# The ASCII Architect

You don't want to pay money for the expensive architectural program, so you decide to roll your own. You decide to use ASCII to design your buildings. Your program will take in a single string formatted in a specific way, and the program will output the building.

## Input

Input consists of a single line of characters. It can be assumed to only contain the letters a-j, the numbers 1-9, and the symbols - and +.

## Output Description

For each letter a-j, the program will output a vertical line as follows. We will call this a column.

         .
..
...
****
*****
******
-------
--------
+++++++++
++++++++++
abcdefghij


For instance, the input abcdefgfedefghgfedc would output:

             .
*     ***
***   *****
***** *******
---------------
-----------------
++++++++++++++++++
+++++++++++++++++++


A letter may be prefixed with a positive integer n, which will add n whitespace characters below the column. We will call this an offset. For instance, using S to notate a whitespace, the input 3b2b3b would output:

+ +
+++
S+S
SSS
SSS


A letter may also be prefixed with a negative integer -m, which will remove the bottom m non-whitespace characters of the column (not replace them with whitespace, remove them entirely). We will call this a slice. For instance, the input -1j-2j-3j-4j-5j-6j-7j-8j would output:

.
..
...
*...
**...
***...
-***...
--***...
+--***..


An offset and a slice can be applied to the same line, but the offset must go first. In other words, the letter may be prefixed with n-m, where n is the size of the offset, and m is the size of the slice. For instance, using S to notate a whitespace, the input '2-4j' would output:

.
.
.
*
*
*
S
S


Lastly, the + operator used between two columns indicates that they should be stacked on top of each other in the same column instead of in seperate columns. For instance, the input 2-4ja' outputs:

.
.
.
*
*
*
S
S+


Whereas the input 2-4j+a outputs:

+
.
.
.
*
*
*
S
S


Here is a sample input:

abiehef+ehfhabc


And the resultant output:

      *
-
.   -
. . +. .
* * +* *
* * ****
********
--------
--------  -
+++++++++ ++
+++++++++++++


Looks like an old destroyed castle tower of some sort.

Here is another sample input:

6b5b+a6b1-2d+3-4f1-2d+-2c+2-4f+1-2d+-2c2-2d+1-4g+1-2c+b+-2c+-4e2-7j+-4g+d+-2c+-4f2-7j+-5h+b+-2c+a+-3f2-7j+-7i+-4e+b+b+a+-4f2-7i+a+-7h+-4f+b+b+a+-4f2-7j+-7h+-4f+a+-7h+a+-7i+-4f2-7j+-7i+-6h+a+-7i+b+-4e3-7i+a+-7h+-4e+a+-7h+b+1-7h3-7j+1-4f+-7h+b+-4f+a3-7j+2-4f+a+-4f+b3-2d+-2d+3-4g+b3-2d+-2d+-2c


And the resultant output:

      ****** +++
******+.*++
---++.+ ***
-+-+++..++**
-+--+++.+++*
--++++.+..*
+++++.+**
+++****.******  -
+++*****.**..  --
+   ***....+..--
...+.....--
--.........--
---......
--


(It was supposed to be Mario but didn't turn out very good...)

If the specification still isn't clear, I have a non-golfed implementation written in Python 2.7. You can run it and experiment to get a feel for how the specification works. You may also choose to laugh at my programming skills.

This is code-golf, so shortest entry wins. Ask questions in comments if unclear.

• Stacking of more than two towers is valid? I see "2c+b+-2c" in one of your examples, but I can't make out if that's how you stacked them. – AndoDaan Aug 20 '14 at 21:17
• @AndoDaan Towers can be infinitely stacked using +. For instance a+a+a+a+a would output five plus signs on top of each other. – absinthe Aug 20 '14 at 21:26
• Isn't this a duplicate of codegolf.stackexchange.com/questions/18967/landscapes? – Howard Aug 20 '14 at 22:00
• @Howard Huh, you're right, these are surprisingly similar (the only additions being to be able to cut off the tower and to stack towers). – Martin Ender Aug 20 '14 at 22:03
• ​​​​​​​​​​​​​​@Howard Huh. It didn't show up on the similiar questions thingo that pops up when you type in your title. The implementation of the whitespace is a little different though. I'll flag my post as a duplicate and see what the mods think. – absinthe Aug 20 '14 at 22:11

## Ruby, 223 214 bytes

g=$*[0].split(/(?<=[a-j])(?!\+)/).map{|r|r.scan(/(\d*)(-\d+)?([a-j])/).map{|a,b,c|' '*a.to_i+'++--***...'[-b.to_i..c.ord-97]}*''} puts g.map{|s|s.ljust(g.map(&:size).max).chars.reverse}.transpose.map(&:join).join$/


That was fun. :)

Although it should be quite obvious, I discovered a new way to do these challenges where strings have be constructed from columns: just do them in rows, and transpose the array of characters before joining everything.

g=$*[0].split(/(?<=[a-j])(?!\+)/) # Split into columns. .map{|r| # For each column r.scan(/(\d*)(-\d+)?([a-j])/) # Split into components. .map{|a,b,c| # For each component ' '*a.to_i+ # Prepend spaces if any. '++--***...'[-b.to_i..c.ord-97] # Select the appropriate slice of the tower. }*'' # Join all components together. } puts g.map{|s| # For each column s.ljust(g.map(&:size).max) # Pad with spaces on the right such that. # all columns are the same height. .chars.reverse # Turn into character array and reverse. } .transpose # Mirror in the main diagonal. .map(&:join) # Join lines. .join$/                                   # Join columns.

• Was trying out different styles of the final line and came out with: puts (0..z=g.map(&:size).max-1).map{|i|g.map{|y|(v=y[z-i])?v:?\ }*''}. But probably not so fun without the transpose. – Vectorized Aug 22 '14 at 16:27
• @bitpwner Thanks, I'll have a look and test this later. – Martin Ender Aug 26 '14 at 10:07

# Cobra - 473

I don't think Cobra's ever going to win one of these :/

use System.Text.RegularExpressions
class P
def main
r=Regex.matches(Console.readLine,r'(?<=^|[a-j])(([^a-j]*[a-j])+?)(?=[^+]|$)') z,l=0String[](r.count) for m in r.count,for n in'[r[m]]'.split('+'),l[m]+=' '.repeat(int.parse('0[Regex.match(n,r'(?<!-)\d+')]'))+'++--***...'[int.parse('0[Regex.match(n,r'(?<=-)\d+')]'):' abcdefghij'.indexOf(n[-1:])] for y in l,if y.length>z,z=y.length for x in-z+1:1 for y in l,Console.write(if(-x<y.length,y[-x],' ')) print  All nice and commented: EDIT: Just realized this looks suspiciously similar to the Ruby solution. Great minds think alike? use System.Text.RegularExpressions class P def main r=Regex.matches(Console.readLine,r'(?<=^|[a-j])(([^a-j]*[a-j])+?)(?=[^+]|$)')
# Split into columns
z,l=0,String[](r.count)
# Assign the column-array
for m in r.count
# Loop through columns
for n in'[r[m]]'.split('+')
# Loop through individual letter instructions
# - within columns
l[m]+=
# Add characters to the last column
' '.repeat(int.parse('0[Regex.match(n,r'(?<!-)\d+')]'))+
# Any spaces, plus
'++--***...'[:' abcdefghij'.indexOf(n[-1:])]
# The default column string
[int.parse('0[Regex.match(n,r'(?<=-)\d+')]'):]
# Sliced to the right length
for y in l,if y.length>z,z=y.length
# Determine the maximum length of any column
for x in-z+1:1
for y in l
# Loop through columns so that they rotate to the left
Console.write(if(-x<y.length,y[-x],' '))
# Write the character in the current position
print
# Insert newlines


# Lua - 451

a=arg[1]j='++--***...'I=io.write M=string.match U=string.sub T=table.insert n=''y=0 t={}m=0 for i in a:gmatch('[%-%d]*[a-j]%+?')do b=M(i,'-(%d)')b=b or 0 s=M(U(i,1,1),'%d')s=s or 0 n=n..(' '):rep(s)..U(U(j,1,M(U(i,-2),'[a-j]'):byte()-96),1+b,-1)if U(i,-1,-1)~="+"then T(t,n)m=m<#n and #n or m n=""y=y+1 end end T(t,n)n=''for k,v in pairs(t)do n=#v<m and n..v..(' '):rep(m-#v)or n..v end for i=m,1,-1 do for k=0,m*y-1,m do I(U(n,i+k,i+k))end I'\n'end


Nothing special. It was fun to rename a butt-load of functions for once though. I'll edit the ungolfed code in later.

Try it out here. Sample Output:

# PowerShell, 214212209206 200 bytes

-3 bytes thanks @Veskah

switch -r($args-split'(-?.)'){\+{$c=1}\d{sv('ps'[0-gt$_])$_}[a-j]{if(!$c){$t+=,''}$t[-1]+=' '*$p+-join'++--***...'[-$s..($_[0]-97)];$c=$p=$s=0}}($t|% Le*|sort)[-1]..1|%{-join($t|% *ht$_|% ch*($_-1))}  Try it online! Less golfed version: # make table with lines instead columns switch -r($args-split'(-?.)'){
\+ {$c=1} \d {set-variable ('ps'[0-gt$_]) $_} [a-j] { if(!$c){$t+=,''}$t[-1]+=' '*$p+-join'++--***...'[-$s..($_[0]-97)]$c=$p=$s=0
}
}
# transpose
($t|% Length|sort)[-1]..1|%{ -join($t|% padRight $_|% chars($_-1))
}

• Regex of (-?.) should work too – Veskah Jun 12 at 15:55
• awesome! thanks. – mazzy Jun 12 at 16:03

# Python 3, 268 bytes

import re
q,t=[(p,' '*int(o or 0)+'++--***...'[-int(s or 0):ord(l)-96])for p,o,s,l in re.findall('(\+?)(\d?)(-\d)?(.)',input())],[]
while q:p,s=q.pop(0);t+=[t.pop()+s if p else s]
t=[*zip(*[[*c.ljust(max(map(len,t)))]for c in t])][::-1]
for l in t:print(*l,sep='')


Mostly ungolfed:

# import the regex module
import re

# array to store initial input
q = []
# array to store translated output
t = []

# split string from stdin into column groups, like: ('plus or blank', 'offset or blank', 'slice or blank', 'letter')
# ex: 6b1-2d+a would become:
# [('','6','','b'), ('', '1', '-2', 'd'), ('+', '', '', 'a')]
i = re.findall('(\+?)(\d?)(-\d)?(.)',input())

# iterate through the groups returned by the regex
for p,o,s,l in i:
# create offset string
# int() cannot parse '', but empty strings are falsey,
# so (o or 0) is equivalent to 'parse the string as an int, or return 0 if it is empty'
offset = ' ' * int(o or 0)

# get the starting point of the slice
# since the regex returns the minus, it must be negated after converting the string to an int
# as before, (s or 0) ensures that the slice is converted to an int properly
start = -int(s or 0)
# since 'a' is ordinal 97, this ensures that the end position will be 1-9
end = ord(l) - 96
# slice the largest possible column string with the calculated start and end positions
a = '++--***...'[start:end]
a = offset + a
# add the plus sting and the column string to the array
q.append( (p, a) )

# while q is not empty
while q:
# remove the first item from the list and separate it into a plus variable and a column string
p, s = q.pop(0)

# if p is not blank, it is a '+'
# if p is truthy, remove the last item added and add s to it
# otherwise just return s
# append the resulting item to the ongoing list
t += [t.pop()+s if p else s]

temp = []
for c in t:
# call len() on all items in t, then return the maximum length
m = max(map(len, t))
# left justify c by adding spaces to the right, up to m total characters
c = c.ljust(m)
# unpack c into a list
# this is equivalent to list(c), but shorter
c = [*c]
# add the list of characters to the array
temp.append(c)

t = temp

# t is currently a list of rows, and needs to be rotated so that it displays correctly
# input: 'abcdefghij'
# before:
#
# +
# ++
# ++-
# ++--
# ++--*
# ++--**
# ++--***
# ++--***.
# ++--***..
# ++--***...
#
# after:
#
#  ++++++++++
#   +++++++++
#    --------
#     -------
#      ******
#       *****
#        ****
#         ...
#          ..
#           .
#
t = [*zip(*t)]
# t is currently upside down, reverse the list
t = t[::-1]

# for each line (currently a list of characters)
for l in t:
# unpack the list into print as arguments, do not add a space between arguments
print(*l,sep='')
`