12
\$\begingroup\$

This came to me in a dream somehow. I've seen similar questions around, but hope this is novel.

The premise is straightforward:

Input: one positive integer.

Output is a pretty square squared using these fancy characters.

Examples:

n = 1

╔═══╗
║   ║
╚═══╝

n = 2

╔═══╦═══╗
║   ║   ║
╠═══╬═══╣
║   ║   ║
╚═══╩═══╝

...

n = 10

╔═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╦═══╗
║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╠═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╬═══╣
║   ║   ║   ║   ║   ║   ║   ║   ║   ║   ║
╚═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╩═══╝

Note that it's three across and one high (plus corners) so that it appears more squarely.

     -3-   
    ╔═══╗
  1 ║   ║
    ╚═══╝

Take your input and output as desired, trailing spaces and lines are fine.

It's , go for the fewest bytes in your preferred lang!

\$\endgroup\$
4
  • \$\begingroup\$ Possible duplicate, but I'll not swing my hammer. \$\endgroup\$ Commented Aug 28 at 7:05
  • 4
    \$\begingroup\$ Is it just me or does it look not pretty at all? On my phone the right side seems to be shifted to either the left or right \$\endgroup\$ Commented Aug 28 at 15:06
  • \$\begingroup\$ @infinitezero Looks fine to me, but I'm on desktop. \$\endgroup\$ Commented Aug 28 at 18:56
  • \$\begingroup\$ @DLosc can confirm on Desktop it's fine. \$\endgroup\$ Commented Aug 29 at 5:29

11 Answers 11

5
\$\begingroup\$

R, 294 bytes

p=paste;r=rep;q=\(...)cat(...,sep="");f=\(n)for(i in 0:(2*n))"if"(i%%2==0,"if"(i==0,q("╔",p(r("═══",n),collapse="╦"),"╗\n"),"if"(i==2*n,q("╚",p(r("═══",n),collapse="╩"),"╝\n"),q("╠",p(r("═══",n),collapse="╬"),"╣\n"))),q(p(r("║   ",n),collapse=""),"║\n"))

Attempt This Online!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ 260 bytes with a bit more golfing. \$\endgroup\$ Commented Aug 28 at 14:08
  • 1
    \$\begingroup\$ @SamR thank you, I started with ~500 bytes but soon grew tired of adding custom definitions. That looks great. \$\endgroup\$ Commented Aug 28 at 14:34
5
\$\begingroup\$

x86_64 machine code: 97 bytes

0:  57                      push   rdi
1:  48 b8 66 25 50 25 50    movabs rax,0x2550255025502566
8:  25 50 25
b:  89 f1                   mov    ecx,esi
d:  f3 48 ab                rep stos QWORD PTR es:[rdi],rax
10: b8 57 25 0a 00          mov    eax,0xa2557
15: ab                      stos   DWORD PTR es:[rdi],eax
16: 5a                      pop    rdx
17: 80 2a 12                sub    BYTE PTR [rdx],0x12
1a: 89 f1                   mov    ecx,esi
000000000000001c <writelines>:
1c: 51                      push   rcx
1d: 48 b8 51 25 20 00 20    movabs rax,0x20002000202551
24: 00 20 00
27: 89 f1                   mov    ecx,esi
29: f3 48 ab                rep stos QWORD PTR es:[rdi],rax
2c: b8 51 25 0a 00          mov    eax,0xa2551
31: ab                      stos   DWORD PTR es:[rdi],eax
32: 57                      push   rdi
33: 5a                      pop    rdx
34: 48 b8 6c 25 50 25 50    movabs rax,0x255025502550256c
3b: 25 50 25
3e: 89 f1                   mov    ecx,esi
40: f3 48 ab                rep stos QWORD PTR es:[rdi],rax
43: b8 63 25 0a 00          mov    eax,0xa2563
48: ab                      stos   DWORD PTR es:[rdi],eax
49: 80 2a 0c                sub    BYTE PTR [rdx],0xc
4c: 59                      pop    rcx
4d: e2 cd                   loop   1c <writelines>
4f: 80 2a 06                sub    BYTE PTR [rdx],0x6
0000000000000052 <correct_last>:
52: ff ce                   dec    esi
54: 74 06                   je     5c <end>
56: 80 2c f2 03             sub    BYTE PTR [rdx+rsi*8],0x3
5a: eb f6                   jmp    52 <correct_last>
000000000000005c <end>:
5c: 80 6f fc 06             sub    BYTE PTR [rdi-0x4],0x6
60: c3                      ret

Running on godbolt, but since godbolt doesn't seem to print the characters I've translated them to ascii characters that are kind of similar so there's something to display.

The algorithm is pretty simple, print the first line, then print alternating vertical and horizontal lines N times, correcting characters on the final line afterwards. Main size optimisation is using 1-byte subtracts to adjust the UTF-16 characters to the correct ones, since all the characters used are only distinguished by the low 8 bits.

Version with comments:

#save start position
    push rdi
#generate line - '╦═══'
    movabs rax, 0x2550255025502566
#write it N times
    mov ecx, esi
    rep stosq
#write ending - '╗\n'
    mov eax, 0x000a2557
    stosd
#restore first char
    pop rdx
#change starting char '╦' -> '╔'
    sub byte ptr[rdx], 18
#setup loop counter
    mov ecx, esi
writelines:
#save current loop counter
    push rcx
#generate line - '║   '
    movabs rax, 0x0020002000202551
#write it N times
    mov ecx, esi
    rep stosq
#write ending - '║\n'
    mov eax, 0x000A2551
    stosd
#save start position
    push rdi
    pop rdx
#generate line - '╬═══'
    movabs rax, 0x255025502550256c
#write it N times
    mov ecx, esi
    rep stosq
#write ending - '╣\n'
    mov eax, 0x000A2563
    stosd
#change starting char '╬' -> '╠'
    sub byte ptr[rdx], 12
#restore loop counter and iterate
    pop rcx
    loop writelines
#change starting char '╠' -> '╚'
    sub byte ptr[rdx], 6
#correct chars on last line '╬' -> '╩'
correct_last:
#decrement first so we don't immediately access out of bounds
    dec esi
    je end
    sub byte ptr[rdx + rcx*8], 3
    jmp correct_last
#change last char '╣' -> '╝'
end:
    sub byte ptr[rdi - 4], 6
    ret
\$\endgroup\$
5
\$\begingroup\$

Python 3, 229 179 bytes

def f(n):[print("".join(" ║═╔║║╗╦═╚═╠╝╩╣╬"[sum((n*4!=c,2*(n*2!=r),c and 4,r and 8,c%4and 16,r%2*32))%21]for c in range(n*4+1)))for r in range(n*2+1)]

Try it online!

  • 23 bytes saved @emanresuA

Explanation

In essence, we iterate through all the rows an columns (of the character grid, not of the box grid), denoted by r and c.

We define some checks for each cell:

sum((n*4!=c,2*(n*2!=r),c and 4,r and 8,c%4and 16,r%2*32))

These are designed to each be 1 bit worth of information, so when summed they don't affect eachother. Then we modulo the whole thing by 21, which gives us the smallest resulting domain of numbers without causing collisions between characters (found by exhaustive search).

Then we lookup the resulting value in the string " ║═╔║║╗╦═╚═╠╝╩╣╬"

Here's the code for finding the lookup string.

\$\endgroup\$
5
  • \$\begingroup\$ 185 but also there's got to be a smarter way to do that hash \$\endgroup\$ Commented Aug 28 at 5:08
  • \$\begingroup\$ @emanresuA maybe... there's only 10 different characters so in theory you need 4 conditions I think... \$\endgroup\$ Commented Aug 28 at 5:09
  • \$\begingroup\$ also you have to include the lambda n: in the bytecount \$\endgroup\$ Commented Aug 28 at 5:25
  • \$\begingroup\$ @emanresuA I thought you didn't have to if it's not recursive \$\endgroup\$ Commented Aug 28 at 5:26
  • 2
    \$\begingroup\$ That's for naming the function: If you have a function f that relies on f being bound to that function, then you have to include the f= in the byte count. But in general, solutions should be full programs or (possibly anonymous) functions. So you don't have to count the f=, but you do have to count the lambda n: \$\endgroup\$ Commented Aug 28 at 5:30
4
\$\begingroup\$

Uiua, 77 characters (93 bytes SBCS)

≡⌞▽1_3⊂˜⊂/⊂₃¤⊃($"╠_╣"/⊂₃@╬|↯⟜(/⊂₃@ ˜↯@║+₁)⧻|⊓$"╔_╗"$"╚_╝"∩⌟/⊂₃@╦@╩)˜↯@═

Takes the integer as input, and outputs a matrix of characters.

Try it in the pad!

\$\endgroup\$
4
\$\begingroup\$

Charcoal, 46 bytes

NθUB⁺⁺╬×═³¶║P…⁺╦×ψ³⊕⊗θP↓…⁺╠ψ⊕θ╔‖B⌈

Attempt This Online! Link is to verbose version of code. Explanation:

Nθ

Input n.

UB⁺⁺╬×═³¶║

Set the background to a 2×4 section of the result. This handles all of the horizontal and vertical segments and the interior joins correctly, but the edges are still wrong.

P…⁺╦×ψ³⊕⊗θ

Output the top edges, but the top left corner is still wrong.

P↓…⁺╠ψ⊕θ

Output the left edges, but the top left corner is still wrong.

Output the top left corner.

‖B⌈

The previous code only drew the top left quarter of the result; this reflects it twice to complete the output.

Note that each of the box-drawing characters takes 3 bytes to represent in Charcoal.

\$\endgroup\$
3
\$\begingroup\$

05AB1E, 67 62 59 bytes

4*<U₄RX∍2ì3«©4DjRXÌ∍®āžm‡‚I·<∍`®ā56(‡»žm(•dÃи“·”.•29вŽb[+ç‡

Try it online or verify all test cases.

Explanation:

4*         # Multiply the (implicit) input-integer by 4
  <        # Decrease it by 1
   U       # Pop and store this input*4-1 in variable `X`
₄          # Push 1000
 R         # Reverse it: "0001"
  X∍       # Extend/shorten it to length `X`
    2ì3«   # Prepend a 2 and append a 3
        ©  # Store it in variable `®` (without popping)
4          # Push 4
 D         # Duplicate it
  j        # Pad leading spaces to make it that length: "   4"
   R       # Reverse it: "4   "
    XÌ∍    # Extend/shorten it to length `X+2` (aka input*4+1)
®          # Push string `®`
 ā         # Push a list in the range [1,length] (without popping): [1,2,3,...]
  žm       # Push constant 9876543210
    ‡      # Transliterate 1,2,3 to 9,8,7 in string `®`
           # (the other values that aren't present in `®` are no-ops)
‚          # Pair the top two strings together
 I·<∍      # Extend/shorten this list to length input*2-1
     `     # Pop and push all strings separately to the stack
®          # Push string `®` again
 ā         # Push a list in the range [1,length] (without popping) again
  56(      # Push -56
     ‡     # Transliterate 1,2,3 to "-",5,6 in string `®`
           # (the other integers that aren't present in `®` are no-ops again)
»          # Join all strings on the stack with newline delimiter
žm         # Push constant 9876543210
  (        # Negate it: -9876543210
•dÃи“·”.•  # Push compressed integer 10932220548783273
  29в      # Convert it to base-29 as list: [25,28,16,19,13,10,1,7,4,22,0]
     Žb[   # Push compressed integer 9552
        +  # Add it to each value in the list:
           #  [9577,9580,9568,9571,9565,9562,9553,9559,9556,9574,9552]
         ç # Convert each to a character with that unicode value:
           #  ["╩","╬","╠","╣","╝","╚","║","╗","╔","╦","═"]
‡          # Transliterate the "-","9","8",... to "╩","╬","╠",...
           # (after which the result is output implicitly)

See this 05AB1E tip of mine (sections How to compress large integers? and How to compress integer lists?) to understand why •dÃи“·”.• is 10932220548783273; •dÃи“·”.•29в is [25,28,16,19,13,10,1,7,4,22,0]; and Žb[ is 9552.

\$\endgroup\$
3
\$\begingroup\$

JavaScript (ES6), 129 bytes

f=(n,y=x=0)=>y>2*n?"":`╬╩╠╚╦║╔
╣╝═ ╗`[x>4*n?(x=-1,7):x%4?10+y%2:y%2?5:y/2/n|!x*2|!y*4|x/4/n<<3]+f(n,y+!++x)

Try it online!

Lookup string

The expression y/2/n|!x*2|!y*4|x/4/n<<3 can address 9 entries in the lookup string:

!x*2 (2 if left border) middle horizontal area (0) x/4/n<<3 (8 if right border)
!y*4 (4 if top border) 6 = 4 = 12 =
middle vertical area (0) 2 = 0 = 8 =
y/2/n (1 if bottom border) 3 = 1 = 9 =

The other entries are:

  • 5 =
  • 7 = \n
  • 10 =
  • 11 =
\$\endgroup\$
2
\$\begingroup\$

Uiua, 63 characters (63 bytes SBCS)

˜⊏˜≡⌞⊏⍜⊢⍜⊢⋅@ +9520⬚@![""" -*9"" '$6"" 30<"]∩⌟/⊂₃⊸˙⊟₃0+×₂⊸⇌⊂0˜↯1

Try it!

\$\endgroup\$
2
\$\begingroup\$

Ruby, 154 Bytes

n=gets.to_i
(2*n+1).times{|i|puts i<1?"╔#{"═══╦"*~-n}═══╗":i>2*n-1?"╚#{"═══╩"*~-n}═══╝":i%2>0?"║#{"   ║"*n}":"╠#{"═══╬"*~-n}═══╣"}
\$\endgroup\$
2
\$\begingroup\$

Lua, 280 252 249 246 242 bytes

I don't even want to…ugh…what is this…
Essentially, I use binary to index through a string of all 16 possible states (beginning, interior, middle edge, and end in terms of both row and column). However, because these are Unicode characters, I have to manually account for the box characters' 3-character girth. My original solution involved using Lua's native utf8.offset function. However, I ended up implementing it manually with a bit more jankomancy (and then doing a bunch more golfing after that), which is how I was able to slash almost thirty bytes. I'm looking for more trivial optimizations while writing this, but I'm sure there are also ways to spruce up the algorithm itself a bit. I certainly won't be trying it.

Addendum 1 (immediately after writing): found another trivial optimization! Now I've saved exactly 30 bytes!

Addendum 2: saved 2 more bytes by removing a useless addition…now the code is even less intuitive :(

Addendum 3: 2 more bytes from…okay, for some reason SOME numbers compress with SOME letters, but sometimes it just gives a "malformed number" error. I hate you.

Addendum 3.5: I found a bug, so time to retcon all the buggy old solutions and count their bytes.

Addendum 4: io moment

function(n)t=" ║║║═╔╗╦═╚╝╩═╠╣╬"for r=0,2*n+2 do s=""for c=0,4*n+4 do v=(c%4==0 and(c>0 and 6or 0)+(c>n*4 and 1or 4)or 1)+(r%2==0 and(r>0 and 24 or 0)+(r>2*n and 0 or 12)or 0)s=s..t:sub(math.max(v-2,1),v)end print(s)end end
\$\endgroup\$
1
\$\begingroup\$

Jelly, 46 bytes

(Or \$44\$, as a monadic Link yielding a list of lists of code-points - remove trailing ỌY)

3“¦ç®£££×øÞ¿ȷÇ‘sḢ,ṪW€ƲjẋṖ¥Zʋ⁺µj⁽ḅP)⁺»Ðo1+⁽"2ỌY

A monadic link that accepts a positive integer and yields a list of characters, or a full-program printing to stdout.

Try it online!

How?

3“...‘sḢ,ṪW€ƲjẋṖ¥Zʋ⁺µj⁽ḅP)⁺»Ðo1+⁽"2ỌY - Link: positive integer, N
 “...‘                                - a list of code-page indices
3     s                               - split into chunks of three
                                        -> [[5,23,8],[2,2,2],[17,29,20],[11,26,14]]
                                            ...9551 less than code-points of:
                                             ╔  ╦ ╗   ║ ║ ║    ╠  ╬  ╣    ╚  ╩  ╝
                   ⁺                  - do this twice:
                  ʋ                   -   last four links as a dyad:
            Ʋ                         -     last four links as a monad:
       Ḣ                              -       remove head and yield it
         Ṫ                            -       remove tail and yield it
        ,                             -       pair these together
          W€                          -       wrap each in a list
                ¥                     -     last two links as a dyad:
              ẋ                       -       repeat (remaining interior part(s)) {N} times
               Ṗ                      -       and remove the last one
             j                        -     join {[[head],[tail]]} with {repeated interior}
                 Z                    -     transpose
                          ⁺           - do this twice:
                    µ    )            -   for each:
                     j⁽ḅP             -     join with -9519 (these would all become spaces)
                            Ðo        - for odd indices (first, third, ...):
                           »  1       -   max with one (so those -9519 will now become ═)
                               +⁽"2   - add 9551
                                   Ọ  - cast from code-points to characters
                                    Y - join with newline characters

Note that for the first, third and fourth triples of initial code-points reduced by 9551 do have a nice pattern:
[L, 10x+y, R] = [5,23,8], [17,29,20], and [11,26,14]
...where x and y are the decimal digits of the central element, conform to \$L = x \times y - 1 = R - 3\$
But it does not help save any bytes, as we need to handle the [2,2,2] row by, for example, using x=y=0 and taking the maximum of the results and 2.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.