17
\$\begingroup\$

Here is the 3rd ABACABA city:

  _
A|_|
B|__|
A|_|_
C|___|
A|_|
B|__|
A|_|

It is made out of the ABACABA sequence, which is basically:

  • A (1st iteration)
  • place B - AB
  • repeat A - ABA (2nd iteration)
  • Place C - ABAC
  • Repeat ABA - ABACABA (3rd iteration)

and you get the idea.

The buildings have a height (corresponded by no. of underscores) equal to the letters converted to numbers as A = 1, B = 2 e.t.c.

Input

An iteration number 1<=n<=26.

Output

The ABACABA city of order n, including the letters at the start of the lines.

\$\endgroup\$
11
  • \$\begingroup\$ @DonMuesli Haha yes. Will hyperlink in question. \$\endgroup\$
    – user51533
    Commented Mar 25, 2016 at 21:37
  • 1
    \$\begingroup\$ What do we need to output when the number gets higher than 26? \$\endgroup\$
    – Adnan
    Commented Mar 25, 2016 at 21:42
  • \$\begingroup\$ Yes please :D (it wasn't going to be easy was it?) \$\endgroup\$
    – user51533
    Commented Mar 25, 2016 at 21:42
  • 1
    \$\begingroup\$ That won't count as valid input. \$\endgroup\$
    – user51533
    Commented Mar 25, 2016 at 21:43
  • 2
    \$\begingroup\$ Can the input be zero, and if so, what should the output be? Also, it wouldn't hurt to list the first, say, 4 inputs and expected outputs. \$\endgroup\$
    – Zgarb
    Commented Mar 25, 2016 at 22:03

11 Answers 11

6
\$\begingroup\$

Python 2, 82 bytes

f=lambda n,s=1:n*"'"and"  _"*s+f(n-1,0)+"_"*(n-2)+"\n%c|%s|"%(64+n,"_"*n)+f(n-1,0)

I noticed no one had posted the binary recursion method and decided to give it a shot...and now with a trick borrowed from Sherlock9, it is the shortest python answer! (Also, thanks to xnor for one more shortening.) (And then Dennis who shaved a handful more...)

Ungolfed:

def f(n,s=1):
    if n>0:
        strsofar = "  _" if s==1 else ""        #prepend overhang for top-level call
        strsofar += f(n-1,0)                    #build the city above the current line
        strsofar += "_"*(n-2)                   #add the overhang to reach the current tower
        strsofar += "\n%c|%s|" % (64+n, "_"*n)  #write the current (center) line
        strsofar += f(n-1,0)                    #build the city below the current line
        return strsofar
    else: 
        return ""                               #only this line will be executed when n==0 (base case)

print "  _"+f(input())
\$\endgroup\$
8
  • \$\begingroup\$ I think I understand this and it's quite clever. I had totally missed this nice recursion. You can save some chars by concatenating onto both sides rather than storing s, and by making the second line an anon function: f=lambda n:n*"?"and f(n-1)+"_"*(n-2)+"\n%c|%s|"%(64+n,"_"*n)+f(n-1);lambda n:" _"+f(n) \$\endgroup\$
    – xnor
    Commented Mar 30, 2016 at 4:27
  • \$\begingroup\$ I was thinking about doing that next... \$\endgroup\$
    – quintopia
    Commented Mar 30, 2016 at 4:35
  • \$\begingroup\$ @quintopia f=lambda n,s=1:n*"_"and" _"*s+f(n-1,0)+"_"*(n-2)+"\n%c|%s|"%(64+n,"_"*n)+f(n-1,0) should work. \$\endgroup\$
    – Dennis
    Commented Mar 30, 2016 at 22:47
  • \$\begingroup\$ @Dennis i suggest implementing the above solution in Pyth. I suspect it could be shorter than 59 bytes... I would do it, but at this point, it's only half mine... \$\endgroup\$
    – quintopia
    Commented Mar 31, 2016 at 4:06
  • 1
    \$\begingroup\$ 81 bytes as program, same length as a function. \$\endgroup\$
    – xnor
    Commented Apr 2, 2016 at 6:41
3
\$\begingroup\$

Python 2, 99 bytes

b=1;i=2**input('  _\n')-1
while i:i-=1;a=len(bin(i&-i))-2;print'%c|%s|'%(64+b,'_'*b)+'_'*(a+~b);b=a

To find the ith number of the ABACABA sequence, write i in binary, count the number of trailing zeroes, and add one. We use the classic bit trick i&-i to find the greatest power of 2 that divides i, then compute bit length. Actually, we count i down from 2**n-1 to 0, which is fine because the ABACABA sequence is symmetric.

We track both the current and last number of the sequence with the help of a "previous" variable b. This tells us how many underscores to print as the "overhang". The final building is drawn correctly without overhang because 0 is treated as have bit length 1.

The string format for printing is taken from Sp3000, as is the trick of using the input to print the first line.

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

MATL, 59 bytes

vi:"t@wv]!-1hPXJtPvX>"'|'@Z"63+h6MJ2+X@)(]XhcJ64+!wh!32H:(!   

This uses current release (15.0.0) of the language.

Try it online!


(If the letters didn't have to be included in the output: the following would work, 48 bytes):

vi:"t@wv]!-1hPXJtPvX>"' |'X@1=o)@Z"63+h6MJ2+X@)(

Explanation

v        % vertically concatenate the stack contents: gives an empty array
i:       % input number n. Generate [1,2,...,n]
"        % for each k in [1,2,...n]
  t      %   duplicate
  @      %   push k
  wv     %   swap, vertically concatenate
]        % end. Poduces the numeric ABACABA: [1 2 1 3 1 2 1]: ceiling heights
!        % transpose into a row
-1h      % append -1
PXJ      % reverse array. Copy into clipboard J
tP       % duplicate. Reverse again, so undo the reversing
v        % vertically concatenate reversed and non-reversed row arrays
X>       % max of each column. Gives array of wall heights: [1 2 2 3 3 2 2 1]
"        % for each value in that array
  '|'    %   push "floor" char
  @      %   push height
  Z"     %   create string with that many spaces
  63+    %   transform spaces into "wall" chars, '_'
  h      %   concatenate horizontally
  6M     %   push "floor" char '|' again, to be used as ceiling
  J      %   push array of ceiling heights
  2+X@)  %   index into that to get height of current building
  (      %   at that position, overwrite the string with '|'
]        % end
Xhc      % concatenate all strings into a 2D char array, padding with spaces
J        % push array of ceiling heights (numeric ABACABA sequence)
64+      % add 64 to transform into letters
!        % transpose into column array
wh       % swap, concatenate horizontally. This appends letters below the floor
!        % transpose
32H:(    % overwrite first two positions (in linear order) with spaces
!        % transpose back. Implicitly display
\$\endgroup\$
4
  • \$\begingroup\$ Very nice answer, but you also need to output the letters in front of the buildings :p. \$\endgroup\$
    – Adnan
    Commented Mar 25, 2016 at 22:29
  • \$\begingroup\$ Solved. Waiting for OP clarification anyway \$\endgroup\$
    – Luis Mendo
    Commented Mar 25, 2016 at 22:46
  • 1
    \$\begingroup\$ I actually already asked this, but I deleted my comment. This was the response though :p. \$\endgroup\$
    – Adnan
    Commented Mar 25, 2016 at 22:47
  • \$\begingroup\$ A very elegant solution. \$\endgroup\$
    – user51533
    Commented Mar 26, 2016 at 7:17
2
\$\begingroup\$

CJam, 37 35 bytes

SS'_Lri{[H)'_*_2>N@H'A+'|@'|6$]+}fH

This is an iterative implementation of the recursive algorithm from @quintopia's answer.

Try it online!

How it works

SS'_     e# Push two spaces and an underscore.
L        e# Push "".
ri       e# Read an integer I from STDIN.
{        e# For each H in [0 ... I-1]:
  [      e#   Set an array marker.
    H)   e#     Push Push H+1.
    '_*  e#     Push a string of that many underscores.
    _2>  e#   Push a copy and remove the first two underscores.
    N    e#   Push a linefeed.
    @    e#   Rotate the longer string of underscores on top of it.
    h'A+ e#   Add H to the character 'A', pushing the corresponding letter.
    '|  e#    Push a vertical bar.
    @   e#    Rotate the string of underscores on top of it.
    '|  e#    Push another vertical bar.
    6$  e#    Push a copy of the previous iteration (initially "").
  ]     e#   Wrap everything up to the former marker in an array.
}fH     e#
\$\endgroup\$
1
\$\begingroup\$

JavaScript (ES6), 162 bytes

n=>(a=[...Array(1<<n)]).map((_,i)=>i?(a[i]=String.fromCharCode(64+(n=1+Math.log2(i&-i)))+`|${"_".repeat(n)}|`,a[i-1]+='_'.repeat(--n&&--n)):a[i]='  _')&&a.join`\n`

Where \n is the literal newline character.

\$\endgroup\$
1
  • \$\begingroup\$ \n is at the end, if anyone was wondering. \$\endgroup\$ Commented Mar 26, 2016 at 3:51
1
\$\begingroup\$

Python 2, 123 121 bytes

f=lambda n:n*[n]and f(n-1)+[n]+f(n-1)
L=f(input('  _\n'))
for i,j in zip(L,L[1:]+L):print'%c|%s|'%(64+i,'_'*i)+'_'*(j+~i)

ideone link (-2 bytes thanks to @xsot)

f generates the ABACABA sequence as a list of numbers, e.g. f(3) = [1, 2, 1, 3, 1, 2, 1]. The offset of the input by 1 compared to the ABACABA sequence challenge lets us golf off a byte in f.

The first line is printed separately, after which all other lines are printed using an expression which takes into account the current number and the next number. Just for fun, the first line is printed using input().

\$\endgroup\$
2
  • \$\begingroup\$ You can replace [0] with L. \$\endgroup\$
    – xsot
    Commented Mar 26, 2016 at 12:34
  • \$\begingroup\$ @xsot Ah thanks, that works out pretty well :) (just as xnor posts an answer!) \$\endgroup\$
    – Sp3000
    Commented Mar 26, 2016 at 12:42
1
\$\begingroup\$

Pyth - 64 62 bytes

Probably could be golfed more, but good enough for now.

Lsl.&Jhb_J"  _"Vtt^2Qpr@G=ZyN1p"|_"p*\_Zp\|W<=hZyhNp\_)d)"A|_|

Try it here!

Explanation:

            |Predefined vars: Q = evaluated input, G = lowercase alphabet
L           |Lambda definition. y(b) = return (following code)
   .&       |bitwise and
     Jhb    |J = b + 1, pass b + 1 to the bitwise and
        _J  |-J
  l         | base 2
 s          |̲c̲o̲n̲v̲e̲r̲t̲ ̲t̲o̲ ̲i̲n̲t̲ ̲ ̲ ̲ ̲ ̲ ̲ ̲ ̲ ̲ ̲ ̲ ̲ ̲ ̲ ̲ ̲ ̲ ̲
          "  _"                              |print "  _" with a trailing newline
               Vtt^2Q                        |For N in 2^Q - 2
                     pr      1               |print in caps
                         =ZyN                |Z = y(N) remember the first lambda?
                       @G                    |G[Z], basically convert 1-26 to A-Z
                              p"|_"          |print "|_", no trailing newline
                                   p*\_Z     |print "_" Z times
                                        p\|  |̲p̲r̲i̲n̲t̲ ̲"̲|̲"̲ ̲ ̲ ̲ ̲ ̲ ̲ ̲ ̲ ̲
                                           W<=hZyhN             |While ++Z<y(N+1)
                                                   p\_          |print "_"
                                                      )k        |end while,
                                                                |print newline
                                                        )"A|_|  |end for,
                                                                |print "A|_|"
\$\endgroup\$
0
\$\begingroup\$

Python 3.5 - 262 236 220 bytes:

-16 bytes thanks to @CatsAreFluffy! My entire function can now finally be in a single line! :)

from collections import*
def a(v):o=OrderedDict;j=[chr(i+97)for i in range(26)];d=o((j[i],('  '+'_'*(i+1)+'\n'+j[i]+'|'+'_'*(i+1)+'|'))for i in range(26));f=lambda w:'a'[w:]or f(w-1)+j[w]+f(w-1);[print(d[g])for g in f(v)]

It may be a bit long, and it may print new lines in between building, but in does what it needs to. You can test it out yourself to confirm it.

EDIT:

My previous golfed code did not print the right pattern whatsoever. However, now the one shown above does, and it does it good in my opinion. You can also run it for yourself to confirm that.

Note: The program prints all lowercase letters behind every "building". I hope that's okay.

Ungolfed version with Explanation:

from collections import*
def a(v):
    o=OrderedDict # Assign the OrderedSict function to "o"
    j=[chr(i+97)for i in range(26)] # Create a list with all 26 lowercase letters of the alphabet
    d=o((j[i],('  '+'_'*(i+1)+'\n'+j[i]+'|'+'_'*(i+1)+'|'))for i in range(26)) # Create a dict assigning each letter it's corresponding building with its corresponding length
    f=lambda w:'a'[w:]or f(w-1)+j[w]+f(w-1) # Return the ABACABA sequence based on the user input
    [print(d[g])for g in f(v)] # Print out the building according to the sequence returned by the above lambda function (thanks to @CatsAreFluffy for this method to print it! :) )

Basically what I am doing is first importing the collections module's Ordered Dictionary function, and then creating an ordered dictionary, with each lower case letter in the list "j" being assigned to its corresponding building, with its corresponding length in underscores. Then I compute the sequence, based on the user's input, using the f=lambda w:"a"[w:]or f(w-1)+j[w]+f(w-1) function, and then based on the sequence returned by that, the buildings, with each's corresponding letter behind it, are printed out.

\$\endgroup\$
12
  • \$\begingroup\$ Can you import OrderedDict as o instead? And changing op to p and item to j also works. \$\endgroup\$
    – Riker
    Commented Mar 26, 2016 at 1:20
  • \$\begingroup\$ You can drop the if (all inputs are 1≤v≤26), change range(26) to range(v), and use return"\n".join(f(v)) instead of the for. \$\endgroup\$ Commented Mar 26, 2016 at 3:33
  • \$\begingroup\$ -2bytes: use from collections import* and o=OrderedDict instead of from collections import OrderedDict as o \$\endgroup\$ Commented Mar 26, 2016 at 3:35
  • \$\begingroup\$ @CatsAreFluffy Actually, changing range(26) to range(v) results in an Index Error. Also, doing return"\n".join(f(v)) will ONLY returns the sequence, but not the buildings themselves. Other than those, your tips were pretty good. Thanks! :) \$\endgroup\$
    – R. Kap
    Commented Mar 26, 2016 at 3:41
  • \$\begingroup\$ Well, I don't quite have Python 3.5 (I've got 3.4.1), maybe it's time to upgrade... \$\endgroup\$ Commented Mar 26, 2016 at 3:44
0
\$\begingroup\$

Ruby, 129 bytes

Anonymous function, returns a multiline string.

->x{a=->n{n<1?[]:(b=a[n-1];b+[n]+b)}
r="  _
"
a[x].zip(a[x][1,9**x]<<0).map{|n,m|r+=(64+n).chr+"|#{?_*n}|#{?_*(m+~n)if m>n}
"}
r}
\$\endgroup\$
0
\$\begingroup\$

JavaScript (ES6), 143

There are 2 newline inside the backticks that are significant and counted.

n=>`  _
`+(r=n=>n?[...r(n-1),n,...r(n-1)]:[])(n).map((x,i,t,u=n=>'|'+'_'.repeat(n>0&&n))=>String.fromCharCode(x+64)+u(x)+u(t[i+1]-x-1)).join`
`

... or 138 if the letters can be lowercase.

n=>`  _
`+(r=n=>n?[...r(n-1),n,...r(n-1)]:[])(n).map((x,i,t,u=n=>'|'+'_'.repeat(n>0&&n))=>(x+9).toString(36)+u(x)+u(t[i+1]-x-1)).join`

Less golfed

n=>{
  // recursive function for ABACABA returning an array of integers
  var r=n=>n?[...r(n-1),n,...r(n-1)]:[]
  // function to build "|__..."
  // if argument <=0 just returns the vertical bar
  var u=n=>'|'+'_'.repeat(n>0&&n)
  var t = r(n)
  t = t.map((x,i)=>
    // current building + extension to the len of next building if needed
    String.fromCharCode(x+64)+u(x)+u(t[i+1]-x-1)
  )
  return ' _\n' // the top line is fixed
    + t.join('\n')
}

Test

solution=
n=>`  _
`+(r=n=>n?[...r(n-1),n,...r(n-1)]:[])(n).map((x,i,t,u=n=>'|'+'_'.repeat(n>0&&n))=>String.fromCharCode(x+64)+u(x)+u(t[i+1]-x-1)).join`
`

function update() {
  var n=+N.value
  if (n>=0 && n<=26) O.textContent=solution(n)
}

update()
#N { width: 2em }
N:<input id=N value=4 oninput='update()'><pre id=O></pre>

\$\endgroup\$
0
\$\begingroup\$

Powershell, 67 Bytes

1..(Read-Host)|%{'  _'}{$x+=@([char]($_+96)+'|'+'_'*$_+'|')+$x}{$x}
\$\endgroup\$

Your Answer

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