| Bytes | Lang | Time | Link |
|---|---|---|---|
| 242 | Lua | 250922T002856Z | Someone |
| 154 | Ruby | 250901T113529Z | Nelson |
| 046 | Jelly | 250831T134601Z | Jonathan |
| 129 | JavaScript ES6 | 250828T202423Z | Arnauld |
| 179 | Python 3 | 250828T031933Z | Ted |
| 097 | x86_64 machine code | 250829T114015Z | user1290 |
| 6363 | Uiua | 250829T112339Z | YufangIG |
| 059 | 05AB1E | 250828T082701Z | Kevin Cr |
| 046 | Charcoal | 250827T235352Z | Neil |
| 7793 | Uiua | 250827T233446Z | janMakos |
| 294 | R | 250827T222504Z | M-- |
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
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}═══╣"}
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.
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.
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)
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 =
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)]
- 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.
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
Uiua, 63 characters (63 bytes SBCS)
˜⊏˜≡⌞⊏⍜⊢⍜⊢⋅@ +9520⬚@![""" -*9"" '$6"" 30<"]∩⌟/⊂₃⊸˙⊟₃0+×₂⊸⇌⊂0˜↯1
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.
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.
Uiua, 77 characters (93 bytes SBCS)
≡⌞▽1_3⊂˜⊂/⊂₃¤⊃($"╠_╣"/⊂₃@╬|↯⟜(/⊂₃@ ˜↯@║+₁)⧻|⊓$"╔_╗"$"╚_╝"∩⌟/⊂₃@╦@╩)˜↯@═
Takes the integer as input, and outputs a matrix of characters.
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"))