# ASCII Borromean Rings

The Borromean rings are a curious set of three circles, linked such that the removal of any one of them will unlink the other two:

You can make a set for yourself with a couple rubber bands and a binder ring. With more rubber bands, it's easy to make any Brunnian link.

Write a program or function that outputs (prints or returns) this ascii-art representation of Borromean rings:

    +-----+
|     |
+-----+   |
|   | |   |
| +-|---+ |
| | | | | |
| | +-|---+
| |   | |
+-|---+ |
|     |
+-----+


The lines may have trailing spaces and there may be a trailing newline.

The shortest code in bytes wins.

• I have to say that this is a pretty hard challenge because of how simple the expected output is – Beta Decay Jul 20 '15 at 5:20
• I'm a little disappointed. Thought the challenge would be to take an integer size and output rings of that size. – Blacklight Shining Jul 20 '15 at 13:42
• yeah, I thought so too (program takes int as an input and then draws Brunnian Link with that many components, but that is not unique, maybe a number of crossings?). That kind of program would have to actually do search (or at least trial and error - do these rings interlock and if I remove one, do the go free?) instead of just drawing a fixed picture... – alexey Jul 20 '15 at 23:36

# CJam, 53 51 50 49 bytes

Plain old base conversion...

"FÓîÞ¤ÛY­ËB[¢O²êÍÓ
}²|äG"299b4b"+ -|"f=B/N*


All characters are well in extended ASCII range (ASCII code 1 to 255), so number of characters == number of bytes.

Try it online here and get the original code here

• Just curious, where is the newline in your lookup? – Maltysen Jul 20 '15 at 6:47
• @Maltysen I don't have it. B/N* splits by 11 characters and joins be newline – Optimizer Jul 20 '15 at 6:48
• that's coooool. – Maltysen Jul 20 '15 at 6:48

# Pyth - 51 bytes

I'm sure someone's gonna beat this quick, but just a base compression answer cuz I'm feeling lazy. I'll try to write a serious answer soon.

s@L"
+-|"jC" zB²;¶Ê ¿ïÁ»#-ÌClHõy%|ap"5

s              Reduce on string concatenation
@L            Map second arg to index first arg
"..."        String of all chars (Pyth allows literal newlines)
j            Base conversion to list
C           Base conversion 256 -> 10
"..."      Base 256 string
5           To Base 5


# Pyth, 49 bytes

jbc11s@L"+ -|"jC"Tª]UÊ¨WÕÝ_K¨}ÝÝ÷K¨Ý]Òê]UÕ*¡"4


Demonstration.

This uses base 4 encoding, and chops the string into elevenths, then rejoins them on newlines.

# Ruby, 110

-2.upto(8){|i|s=" "*(i%6)+"+-----+"*(1-i%2)+" "*9
6.times{|j|"@d me?K[RR@"[i+2].ord>>j&1>0&&s[j*2]=?|}
puts s}


Something different from straight base conversion.

Ungolfed:

-2.upto(8){|i|                                           #for each line
s=" "*(i%6)+"+-----+"*(1-i%2)+" "*9                    #load s with "+-----+" (if required!) padded appropriately with leading spaces and with nine trailing spaces.
6.times{|j|"@d me?K[RR@"[i+2].ord>>j&1>0&&s[j*2]=?|}   #replace characters with | as necessary, according to the 6-bit number encoded by each character in the magic string.
puts s}                                                #print the line.


# Ruby, 117 bytes

Not winning, but I thought it was a cute approach:

puts'    --
|     |
--  |
|   | |   |
| -||
| | | | | |
| | -|
| |   | |
-||
|     |
--'.gsub /-./,'+\0---+ '


# BrainFuck, 361 bytes

Here is a little BrainFuck program, only printing char by char.

+++++++++[->>>>++++++++++++++<+++++<+++++<++++<]>----....>--.>.....>-->++++++++++<<<.>>>.<<<<....>>>.<<<.....>>>.>.<<<.>.....<.<...>>>.>.<.<<<...>>>.<<<.>>>.<<<...>>>.>.<.<<<.>.>.>.<...<.<.>>>.>.<.<<<.>>>.<<<.>>>.<<<.>>>.<<<.>>>.<<<.>>>.>.<.<<<.>>>.<<<.>.>.>.<...<.>>>.<.<<<.>>>.<<<...>>>.<<<.>>>.>.<<<.>.>.<...<.<.>>>.>.<<<<..>>>.<<<.....>>>.>.<<<<..>.>.....<.


# brainfuck, 282280 271 bytes

+++++++++++[>++++>+++>+++++++++++>+<<<<-]>->-....<.++.....--.>>>-.<<....>+++.<.....>.>.<<<.++.....--.>...>.>.<.<...>.<.>.<...>.>[.<]>++.>>.<<...--[.>]+++++[<<.<.>>>-]<<.>.<.<.>.<.<.++.>>.<<...--.>>>.<.<.>.<...>.<.>.>.<<<.++.>>.<<...--[.>]<<<..>.<.....>.>.<<..<.++.....--.


Try it online!

# Staq, 109 chars

&iiiqi{1" "}{211}{c"| "}{fcc}{o"+-|"}{p"+--"}{r"---+"}{ec;}22pr;22c22epr21ec2f2ecor1effcefor;f2ceor1e2c22e2pr


output:

Executing D:\codegolf\Staq borromean rings.txt

+-----+
|     |
+-----+   |
|   | |   |
| +-|---+ |
| | | | | |
| | +-|---+
| |   | |
+-|---+ |
|     |
+-----+

Execution complete.
>


# Python 3, 139 bytes

This is the closest I can get to printing it directly (which would be 134 bytes) without actually doing so.... I'm not sure how to shorten it any more.

a='+-----+'
b='+-|---+'
c=' '*4
d='| '
e=c+d
print(c+a,e*2,a+e[1:],"|   | "*2,d+b+" |",d*6,d+d+b,"| |   "*2,b+" |",e[2:]+e,"  "+a,sep='\n')


# Charcoal, 31 bytes

Ｂ⁷¦⁷Ｍ±⁴¦²Ｂ⁷¦⁷Ｍ²¦²Ｂ⁷¦⁷Ｍ²→|Ｍ³¦²¦¹


Try it online!

Link is to verbose version of code.

It's pretty fun to have a box function.

Basically draws three boxes at the required location, and patches the required places.

"]O|f]S]S6|g[:[S[VO1g$S)S*)O1f)])61g&S]RZ|x">>=(mapM(:"|\n -")"+++"!!).fromEnum  Try it online! A base-5 decompression technique. Each ASCII value in the string is used as an index into the list of parts ["+++", "++|", "++\n", ..., "---"] created by mapM. ## Approach See this tip for Cartesian product with mapM. At first, I used mapM(\_->"......")"123" to create the decoding list, with some permutation of " +-|\n" in place of the dots. The best permutations (yielding the shortest encoded string literals) gave 83-byte solutions: ">:]P>H>F+]%FpHpFob[FrHrFr:vPr>r\bvRfH>F=][">>=(mapM(\_->"\n+ -|")"123"!!).fromEnum ">;|i>C>A1|%AWCWAVwyAXCXAX;ciX>X\tckMC>A=|y">>=(mapM(\_->"\n+ |-")"123"!!).fromEnum "]R>7]b]_%>+_vbv_tH=_wbw_wRp7w]w\ap:gb]_[>=">>=(mapM(\_->"\n+- |")"123"!!).fromEnum "|k>7|w|s%>1scwcsC=sbwbsbkW7b|b\aW;Ow|sy>=">>=(mapM(\_->"\n+-| ")"123"!!).fromEnum "]T|i]X]U1|+UDXDUBryUCXCUCTJiC]C\tJl5X]U[|y">>=(mapM(\_->"\n+| -")"123"!!).fromEnum "|l]P|r|n+]1nJrJnGX[nHrHnHlDPH|H\bDT6r|ny][">>=(mapM(\_->"\n+|- ")"123"!!).fromEnum  Each contains one low-ASCII byte, \b or \t or \a. Then I realized I could write mapM(\_->"\n+ -|")"123" as mapM(:"+ -|")"\n\n\n" to save two bytes. But maybe I could save even more bytes if I used a permutation not starting with \n, because "\n\n\n" is pretty long. Sadly, the permutations not starting with \n yielded bad values making the string literal longer. The best programs are all still 81 bytes: ">6|g>9>:\24|\f:%9%:#mx:$9$:$61g$>$O1f*9>:<|x">>=(mapM(:"| \n-")"+++"!!).fromEnum
">5]O>9>;\18]\f;%9%;#SZ;$9$;$5+O$>$g+M/9>;<]Z">>=(mapM(:"| -\n")"+++"!!).fromEnum "|f>5|m|l\f>\24l1m1l-9<l.m.l.f%5.|.M%6,m|lx><">>=(mapM(:"|-\n ")"+++"!!).fromEnum "]M>6]S]T\f>\18T+S+T(9<T)S)T)M%6)])f%50S]TZ><">>=(mapM(:"|- \n")"+++"!!).fromEnum  However, I had another trick up my sleeve: the problem statement allows for trailing spaces on each line, and maybe I could insert 3 trailing spaces in such a way that the string literal becomes one "actual character" longer, but ends up not having stuff like \24 and \f in it. So I ran a brute force search for all positions to add such trailing spaces. And indeed, adding a trailing space on lines 2, 4, and 6 lets us write the above 79-byte program, where the encoded string is fully printable ASCII. There are many other permutation-space-placement pairs that tie this one. Here are just a few: "]O|f]S]SU|x]$])]$O1g$S)S*)O1f)])61g&S]RZ|x" (44,"+|\n -",[1,1,5])
"|g]M|m|m5]Oyz1m1k-SZk.m.k.g+M.|.5+O'm|kx]Z" (44,"+|\n- ",[1,2,2])
">6|fW=>=A|x>)>$>)61f&$9$:$61g$>$O1f*9>:<|x" (44,"+| \n-",[0,1,4])
">5]Mp=>=g]M=G>$>.5+M.9$9'$5+O$>\$g+M/9>;<]Z" (44,"+| -\n",[0,2,5])
"|f>5|m|ms><|)|.|)f%60.m.l.f%5.|.M%6,m|lx><" (44,"+|-\n ",[1,1,4])
"]M>5b]+]-><],+S+T(9<T)S)T)M%6)])f%50S]TZ><" (44,"+|- \n",[0,0,2])


## I tried a few other things

I tried a few other things. If you pad each line in the target string to "11 characters followed by a newline", then the newlines will only occur at indices ≡ 3 mod 4. In fact, if you look at each k mod 4 and count the unique characters there, they group themselves quite nicely:

target!!k elem " +-|"   when k ≡ 0 mod 4.
target!!k elem " -"     when k ≡ 1 mod 4.
target!!k elem " +-|"   when k ≡ 2 mod 4.
target!!k elem " -\n"   when k ≡ 3 mod 4.


So a mixed-base approach is tempting.

Of course, something like mapM id[" +-|"," -"," +-|"," -\n"] is too long, but I played with mapM(drop"+|\n- ")[0,3,0,2]. Sadly, the strings just aren't great. The best I could get out of this was 93 bytes.

"³F{³;¥F}¥;/¥1(K//-/={/§9=}9§³9©\130W">>=(mapM(drop"||+\n- ")[0,4,1,3]!!).fromEnum


Alternatively, you could try a base-4 approach with different alphabets for each k mod 4. This is easy to express with mapM. I got this 84 byte solution, which would be 70 bytes if Haskell programs used some ANSI encoding rather than UTF-8.

"ÿJ¤ÿ?ðJ§ð?3ð6*p3303B¤3ó<B§<óÿ<öª|">>=(mapM(:"+- ")"|-|\n"!!).fromEnum
`