# Topographic Strings

Here is some example input, so I can explain what the problem is:
`((1 2)(3 (4 5) moo)) (i (lik(cherries)e (woohoo)))`
Think of this line of text as a topographic map of some mountains. Each set of parentheses illustrates one unit of altitude.

If we "view" this from the side, so that we see the mountains vertically, we will see:

``````          4 5                cherries    woohoo
1 2  3       moo       lik          e
i
``````

Given one of these topographic maps, output the map, but on a vertical scale, like the output above. Seperate the different items in the map with the number of characters to the next item. For example, there are 4 spaces in the output between `moo` and `i`. Likewise, there are 4 characters in the input between `moo` and `i`.

The code which does this in the least amount of characters wins.

-
 Is it safe to assume that heights will always be positive? For example, the input `((1 2))))))))))3` should be invalid if negative heights are forbidden. – w0lf Jul 12 '12 at 13:53 @w0lf: yep, the parentheses will always match up. – beary605 Jul 12 '12 at 13:56

## J, 877972706757 56 characters

``````'( ) 'charsub|.|:(+/\@('('&=-')'&=)(],~' '\$~[)"0])1!:1[1
``````

Takes input from the keyboard. Example:

``````   '( ) 'charsub|.|:(+/\@('('&=-')'&=)(],~' '\$~[)"0])1!:1[1
((1 2)(3 (4 5) moo)) (i (lik(cherries)e (woohoo)))
4 5                cherries    woohoo
1 2  3       moo       lik          e
i
``````

Explanation:

This explanation is based on the first version of my program:

``````|.|:('( ) 'charsub x)((' '\$~{.@]),[{~{:@])"1(('('&([:+/=)-')'&([:+/=))\,.i.@#)x=.1!:1[1
``````

`x=.1!:1[1` take input from keyboard and put it into `x` for later

`(('('&([:+/=)-')'&([:+/=))\,.i.@#)` creates a list of all indeces into the string (`i.@#`) and stitches (`,.`) it together with the result of the `(('('&([:+/=)-')'&([:+/=))\` verb.

`(('('&([:+/=)-')'&([:+/=))\` this verb is applied to all the prefixes of the string (so on input `hello` it would apply to `h`,`he`,`hel`,`hell`, and `hello`. It is a fork, which counts the number of open brackets `('('&([:+/=)` and then subtracts the number of close brackets `')'&([:+/=)`. This gives me list of indeces into the string and the level the character at that index should be at in the output. On simple input this gives me the following:

``````   (('('&([:+/=)-')'&([:+/=))\,.i.@#)x=.1!:1[1
(one(two(three)))
1  0
1  1
1  2
1  3
2  4
2  5
2  6
2  7
3  8
3  9
3 10
3 11
3 12
3 13
2 14
1 15
0 16
``````

`((' '\$~{.@]),[{~{:@])"1` this is a verb which takes the list I just generated and also the output of `('( ) 'charsub x)` (which just does a string replacement to replace all brackets with spaces in `x`). It takes the tail of each item of the list `{:@]` and uses it as an index into the string to get the character `[{~{:@]`. Then it prefixes it `,` with the number of spaces as indicated by the head of each item in the list`(' '\$~{.@])`. On the previous example this gives me:

``````   ('( ) 'charsub x)((' '\$~{.@]),[{~{:@])"1(('('&([:+/=)-')'&([:+/=))\,.i.@#)x=.1!:1[1
(one(two(three)))

o
n
e

t
w
o

t
h
r
e
e
``````

I then transpose the array `|:` and reverse it `|.` to get the desired output.

-

## GolfScript 69

``````0:§;{.'()'?))3%(.§+:§' ':s*\@s\if\n}%n/.{,}%\$)\;:μ;{.,μ\-s*\+}%zip n*
``````

Online demo here.

-
 +1 Nice job. It seems I have some golfing to do... – Gareth Jul 12 '12 at 21:17 @Gareth Yes, we both do :) – w0lf Jul 13 '12 at 6:52

## Python, 161 chars

``````S=raw_input()
R=range(len(S))
H=[S[:i].count('(')-S[:i].count(')')for i in R]+[0]
for h in range(max(H),0,-1):print''.join((' '+S[i])[H[i]==H[i+1]==h]for i in R)
``````
-

## APL (59)

``````⊖↑{⊃,/T\¨⍨⍵×P=0}¨R∘=¨(⍴T)∘⍴¨⍳⌈/R←1++\P←+/¨1 ¯1∘×¨'()'∘=¨T←⍞
``````

I have assumed that the 'base' needs to be usable as well. (i.e. `(a(b))c(d)` is valid). If this is not necessary two characters can be saved.

Explanation:

• `T←⍞`: store a line of input in T
• `'()'∘=¨T`: for each character in T, see if it is an opening or closing parenthesis. This gives a list of lists of booleans.
• `1 ¯1∘×¨`: multiply the second element in each of these lists by -1 (so an opening parenthesis is 1, a closing one is -1 and any other character is 0).
• `+/¨`: take the sum of each inner list. We now have the ∆y value for each character.
• `P←`: store in P.
• `R←1++\P`: take a running total of P, giving the height for each character. Add one to each character so that characters outside of the parentheses are on the first line.
• `(⍴T)∘⍴¨⍳⌈/R`: for each possible y-value, make a list as long as T, consisting of only that value. (i.e. 1111..., 2222...., etc.)
• `R∘=¨`: for each element in this list, see if it is equal to R. (For each level, we now have a list of zeroes and ones corresponding to whether or not a character should appear on that level).
• `⍵×P=0`: for each of these lists, set it to zero if P is not zero at that spot. This gets rid of the characters with a non-zero delta-y, so that gets rid of the parentheses.
• `⊃,/T\¨⍨`: for each depth, select from T the characters that should appear.
• `⊖↑`: create a matrix and put it right-side-up.
-
 Which APL implementation are you using? Is it free? – FUZxxl Jul 23 '12 at 8:35 @FUZxxl I've been using Dyalog APL, the Windows version can be downloaded for free. – marinus Jul 23 '12 at 14:23

# C, 149 chars

``````#define S for(i=0;c=v[1][i++];)h+=a=c-'('?c-')'?0:-1:1,
c,i,h=0,m=0;main(int a,char**v){S m=h>m?h:m;for(;m;m--){S putchar(a||h-m?32:c);putchar(10);}}
``````

run with quoted arg, e.g. a.out "((1 2)(3 (4 5) moo)) (i (lik(cherries)e (woohoo)))"

-

# Python, 130

``````a=[""]*9
l=8
i=0
for c in raw_input():o=l;l+=c==')';l-=c=='(';a[l]=a[l].ljust(i)+c*(o==l);i+=1
print"\n".join(filter(str.strip,a))
``````
-

## Ruby 1.9 (129)

``````l=0
@w0lf ha, you're right. I changed the `//` to `''` which keeps the character count the same and avoids the bug in the highlighter. – chron Jul 12 '12 at 22:25