# Fractal Cathedral

Given a positive integer n >= 1, output the first n rows of the following structure:

   #
# #
###
#   #
# # #
## ##
#####
#     #
#  #  #
# # # #
# ### #
##   ##
## # ##
### ###
#######


The n-th 1-indexed row is the binary representation of n, mirrored without copying the last character, with # in place of 1 and <space> in place of 0. All rows are centered.

You must output as ASCII-art but you may use any non-whitespace character in place of where I use # in the example. Trailing whitespace is allowed, and a trailing newline is allowed. The output must look like the example, and no extra leading whitespace or leading newlines.

You can view the first 1023 rows of the fractal cathedral here.

To generate larger test cases, here's an ungolfed reference implementation in Python

• Nice idea. I wouldn't have guessed binary numbers to have produced such pretty ascii art. – Jonah Aug 14 '17 at 1:21
• @Jonah Thanks :) Glad you like it – HyperNeutrino Aug 14 '17 at 1:22
• Both links are pointing to the generated cathedral. – Otávio Aug 14 '17 at 10:30
• @Otávio :I will fix, thanks – HyperNeutrino Aug 14 '17 at 15:32

# MATL, 10 bytes

:B2&Zv35*c


Try it online!

### Explanation

:      % Implicitly input n. Push range [1 2 ... n]
B      % Convert to binary. Gives a matrix where each row corresponds to
% a number. Rows have left-padding zeros if needed
2      % Push 2
&Zv    % Symmetrize along sepecified dimension (2nd means horizontally),
% without repeating the last element
35*    % Multiply by 35 (ASCII code for '#')
c      % Convert to char. Char 0 is shown as space. Implicitly display

• I wonder if it would be helpful to add some sort of builtin that corresponds to multiplying by 35 then converting to char. It seems to be used often – Conor O'Brien Aug 14 '17 at 17:45
• @ConorO'Brien It is used often, yes. But it would be a two-char built-in, so there would be no gain – Luis Mendo Aug 14 '17 at 17:47
• No gain? 35*c is 4 characters – Conor O'Brien Aug 14 '17 at 18:00
• @ConorO'Brien Ah, you mean with 35 fixed? That seems a little specific. On the other hand, some challenges allow any char, so it may be a good idea. Do you think # is the most common? – Luis Mendo Aug 14 '17 at 18:43
• For reference, this feature has been implemented (function Zc, with character 35, i.e. #). Thanks, @ConorO'Brien! – Luis Mendo Aug 14 '17 at 21:14

# 05AB1E, 9 bytes

### Code:

Lb€û.c0ð:


Uses the 05AB1E encoding. Try it online!

### Explanation:

L              # List [1, .., input]
b             # Convert each to binary
€û           # Palindromize each binary number
.c         # Join the array by newlines and centralize
0ð:      # Replace zeroes by spaces


# Jelly, 12 bytes

RBUz0ZUŒBo⁶Y


Try it online!

• I also have to go, so I will read comments when I get back. Feel free to out-golf me. – Leaky Nun Aug 13 '17 at 23:09
• +1 for "feel free to outgolf me" and for the good answer. – Magic Octopus Urn Aug 14 '17 at 1:07

# Python 2, 92 bytes

n=input()
for x in range(n):s=bin(2**len(bin(n))/4+x+1)[3:].replace(*'0 ');print s+s[-2::-1]


Try it online!

In Python 3, s=f'{x+1:0{len(bin(n))-2}b}'.replace(*'0 ') is shorter, but int(input()) and parens around the print argument push it up to 95 bytes.

• That's a copy of mine :) (but clever use of 2**len(bin(n))/4 anyways) – Erik the Outgolfer Aug 14 '17 at 9:12

# JavaScript (ES6), 106 bytes

Uses 1 as the non-whitespace character.

f=(n,k=0)=>k++<n?[...Array(32-Math.clz32(n))].reduce((s,_,i)=>(c=k>>i&1||' ')+s+(i?c:''),'')+
+f(n,k):''


### Demo

f=(n,k=0)=>k++<n?[...Array(32-Math.clz32(n))].reduce((s,_,i)=>(c=k>>i&1||' ')+s+(i?c:''),'')+
+f(n,k):''

O.innerText = f(15)
<pre id=O>

### Alternate version (same size)

Without Math.clz32():

f=(n,a=[k=i=0])=>n>>i+1?f(n,a,a[++i]=i):k++<n?a.reduce((s,i)=>(c=k>>i&1||' ')+s+(i?c:''),'')+
+f(n,a):''

• Very nice! First time I've seen Math.clz32 - I didn't even know it existed! – Birjolaxew Aug 14 '17 at 11:43
• @Birjolaxew Yup, this is an ES6 addition. It comes handy every once in a while. – Arnauld Aug 14 '17 at 12:47

# Husk, 2120 18 bytes

Thanks @Zgarb for golfing off 2 bytes!

S↑(tfS=↔ΠR" #"←DLḋ


Try it online!

### Ungolfed/Explanation

To avoid lengthy padding, this determines the width of the fractal which is given as 2*len(bin(N))-1 and generates all sequences of that length with the symbols #,_ ('_' denotes a space).

Since the Cartesian power is generated in order and the binary numbers are too, this is fine. All we need to do to get the fractal at this point, is filtering out all palindromes and that's basically it:

                    -- implicit input N
S↑(                 -- take N from the following list
ΠR" #"      --   Cartesian power of [" #"] to
Lḋ  --     number of bits in bin(N)
D    --     2*
←     --     -1
fS=↔            --   filter out palindromes
t                --   drop the first line (all spaces)

• Ṙ; can be just R, and ȯ is unnecessary. Nice answer idea! – Zgarb Aug 14 '17 at 17:26

# Mathematica, 94 bytes

Column[Row/@Table[s=IntegerDigits[i,2];Join[s,Reverse@Most@s]/.{0->" ",1->"#"},{i,#}],Center]&

• I really have to go, too... – J42161217 Aug 13 '17 at 23:15

# Mathematica, 98 bytes

Riffle[Nest[ArrayFlatten@{{0,#,0},{1,0,1},{1,#,1}}&,{1},⌊Log2@#⌋]~Take~#"#"/. 0->" ","
"]<>""&


Try it at the Wolfram sandbox! The ⌊ and ⌋ are three bytes each.

It's a different approach from the other answers so far, using the fractal nature of the pattern. The key step is ArrayFlatten@{{0,#,0},{1,0,1},{1,#,1}}&, which does the fractally stuff, best explained in picture form:

                 [    ]
[grid]
[    ]           [    ]
[grid]   --->   #      #
[    ]          #[    ]#
#[grid]#
#[    ]#


The code repeats this step enough times to get at least n rows, then trims off the extra rows and displays it nicely.

# Gaia, 11 bytes

 #”B¦ₔṫ¦€|ṣ


Try it online!

### Explanation

    ¦ₔ       For each number 1..input:
#”B          Convert it to base 2 and use space as 0 and # as 1
ṫ¦     Palindromize each
€|   Centre the lines
ṣ  Join with newlines


# Python 2, 120118 107 bytes

thanks @luismendo, @officialaimm, @halvard-hummel

def f(l):
for a in range(1,l+1):print(bin(a)[2:]+bin(a)[-2:1:-1]).replace(*'0 ').center(len(bin(l+1))*2-4)


Try it online!

• replace(*'0 ') for 2 bytes – officialaimm Aug 14 '17 at 4:03
• 107 bytes – Halvard Hummel Aug 14 '17 at 6:56

# C# (.NET Core), 192178 bytes 168+23

thank you TheLethalCoder for the help.

x=>new int[x].Select((_,z)=>Convert.ToString(z+1,2).PadLeft((int)Math.Log(x,2)+2).Replace('0',' ')).Aggregate((y,z)=>y+"\n"+z+new string(z.Reverse().Skip(1).ToArray()))


Try it online!

pretty sure this can be reduced by a lot, most likely in the padding and reversing of the string.

• Welcome to PPCG! At the moment this answer is just a code snippet. It can be fixed by adding the x=> into the byte count and note you don't need to include the trailing semi-colon. Enumerable.Range(1,x).Select(z is shorter as new int[x].Select((_,z) (I think that's correct). As you are using Linq you should include using System.Linq; into your byte count. You are also using Math so you should include using System; or fully qualify it. Note that this is then shorter as namespace System.Linq{} – TheLethalCoder Aug 14 '17 at 16:04
• You don't need to include ,' ' in the PadLeft call as a space is the default. – TheLethalCoder Aug 14 '17 at 16:07
• 168 bytes + 23 for namespace System.Linq{} – TheLethalCoder Aug 14 '17 at 16:11
• @TheLethalCoder sorry for the inconvenience, it is now fixed. – Dennis.Verweij Aug 14 '17 at 17:30
• No worries +1 from me it is a nice answer :) – TheLethalCoder Aug 15 '17 at 7:58

# Charcoal, 28 bytes

Ａ…·¹ＮθＷ⌈θ«Ｅθ§ #κ↓⸿ＡＥθ÷κ²θ»‖Ｏ


Try it online! Link is to verbose version of code. Explanation:

Ａ…·¹Ｎθ


Create a list of the first n natural numbers.

Ｗ⌈θ«


Repeat until all elements are zero.

Ｅθ§ #κ


Print the last binary digit of each element of the list as a or #.

↓⸿


Move to the previous column.

ＡＥθ÷κ²θ


Divide all elements of the list by two.

»‖Ｏ


Once the left half has been drawn, reflect it.

• Current versions of Charcoal have MapAssignRight(IntDivide, 2, q); which saves 3 bytes. – Neil Nov 25 '17 at 17:02

# J, 29 bytes

' #'{~(],}.@|.)"1@(#.^:_1)@i.


Try it online!

## explanation

• i. integers up to n, the input
• (#.^:_1) converted to base 2
• (],}.@|.) row by row ("1 does that part), take the binary number (] is the identity fn), and cat it (,) with its reverse (|.), where the reverse is beheaded (}.).
• ' #'{~ converts the 1s and 0s to hashes and spaces.
• You can use #.inv instead of #.^:_1. – Conor O'Brien Aug 14 '17 at 17:46
• @ConorO'Brien, thanks, wasn't aware of that. – Jonah Aug 14 '17 at 17:47
• Isn't this off by one? For n = 1, you print nothing. Anyways, you can shave off a few bytes with a few changes like so ' #'{~(,|.@}:)"1@#:@:>:@i. (if you're allowed to be off by one you can remove 4 more bytes). Basically, use a hook because it performs just like a fork when the left tine is ] and use the built-in #: which AFAIK is about the same as #.inv. EDIT: I figure my answer is similar enough to warrant being a comment, let me know if you think it should be an answer of its own. – cole Aug 14 '17 at 17:58
• @cole, thanks! i'll update it a bit later. i thought i'd tried #: and it didn't work, but i must be remembering wrong because you're right that it does. – Jonah Aug 14 '17 at 18:03
• @Jonah you may have tried 2 #: which will only get the right-most digit. Monadic #: functions just like #.inv (or #.&:_1). This differs from dyadic #:, which only gives as many digits as there are atoms in its left argument. – cole Aug 15 '17 at 0:59

# Proton, 95 bytes

r=>{for i:range(1,r)print(((bin(i)[2to]).rjust(len(bin(r))-2)[to-1,to by-1]).replace('0',' '))}


Try it online!

There are too many bugs to not have too many brackets... I need to fix up the parser...

# Python 2, 89 bytes

n=input()+1
w=' #'
while len(w)<n:w=[s+l+s for s in' #'for l in w]
print'\n'.join(w[1:n])


Try it online!

# SOGL V0.12, 11 bytes

∫2─0@ŗ}¹╬⁴╚


Try it Here!

# PHP, 98 97 95 94+1 bytes

while($r++<$argn)echo$s=strtr(sprintf("%".-~log($argn,2).b,$r),0," "),substr(strrev("$s"),1);


Run as pipe with -nR or try it online. Uses 1 as non-whitespace.

• sorry to spoil it, but something is wrong here. output for $argn=1 and $argn=3 is not correct, and $argn is 0-based (specified was 1-based) – Felix Palmen Aug 14 '17 at 18:17 • @FelixPalmen fixed. The incorrectness was caused by the wrong base. Thanks for noticing. – Titus Aug 14 '17 at 18:39 # K (ngn/k), 19 bytes {" #"@+a,1_|a:!x#2}  Try it online! # Python 2, 93 bytes n=input() for i in range(n):s=bin(2**n.bit_length()+i+1)[3:].replace(*'0 ');print s+s[-2::-1]  Try it online! # C (gcc), 146108 105 bytes #define o putchar(33-!(c&(1<<n))) b;c;p(n){--n?o,p(n),o:o;}f(n){while(n>>++b);while(c++<n)p(b),puts("");}  Try it online! This is a function f(n) called with the number of rows n, using an exclamation mark (!) as non-whitespace character. Explanation: #define o putchar(33-!(c&(1<<n))) b;c; p(n) { // least significant bit not yet reached? --n? // print bit twice with recursive step between o, p(n), o // for least significant, just print this bit :o; } // the main "cathedral function": f(r) { // determine max number of bits to shift while(r>>++b); // iterate over rows while(c++<r) // print row recursively p(b), // newline puts(""); } /** * footer, just calling the function */ main(int argc, char **argv) { f(atoi(argv[1])); }  • Suggest --n&&o+p(n);o; instead of --n?o,p(n),o:o; and for(;c++<n;puts(""))p(b); instead of while(c++<n)p(b),puts(""); – ceilingcat Aug 22 '18 at 0:15 # JavaScript (Node.js), 156 149 bytes -7 bytes by @ConorO'Brien f=(n,w=n.toString(2).length,b=n.toString(2).replace(/0/g," "),s=" ".repeat(w-b.length))=>${--n?f(n,w)+s+b+[...b].reverse().join.substr(1):s+"1"}



Try it online!

Recursive function. Unfortunately JS does not support reversing a string, so 19 bytes are used on turning it into an array and back.

• You can use [...b] instead of b.split(""); you can also use .join.substr(1) instead of .join("").substr(1); finally, I think you can use s+1 instead of s+"1" – Conor O'Brien Aug 14 '17 at 17:47

# Perl 5, 77 + 1 (-n) = 78 bytes

$x=1+(log$_)/log 2;map{$_=sprintf"%0${x}b",$_;y/0/ /;say$_.chop.reverse}1..\$_


Try it online!

Using '1' instead of '#' because it saves a couple bytes.

# Stax, 8 bytes

ç▼┼Ö☺Ç¬É


Run and debug it

Shortest answer so far. Uses CP437 charcode 1 in place of #.

ASCII equivalent:

{:B|pm|Cm


# Japt-R, 10 bytes

õ_s*iS)êÃû


Try it

õ_s*iS)êÃû     :Implicit input of integer U
õ              :Range [1,U]
_             :Map
s            :  Convert to string in base
*i          :    "*" prepended with
S         :    Space
)        :  End base conversion
ê       :  Palindromise
Ã      :End map
û     :Centre pad each element with spaces to the length of the longest
:Implicit output, joined with newlines