78
\$\begingroup\$

Consider a non-empty string of correctly balanced parentheses:

(()(()())()((())))(())

We can imagine that each pair of parentheses represents a ring in a collapsed telescopic construction. So let's extend the telescope:

(                )(  )
 ()(    )()(    )  ()
    ()()    (  )
             ()

Another way to look at it is that the parentheses at depth n are moved to line n, while keeping their horizontal position.

Your task is to take such a string of balanced parentheses and produce the extended version.

You may write a program or function, taking input via STDIN (or closest equivalent), command-line argument or function parameter, and producing output via STDOUT (or closest equivalent), return value or function (out) parameter.

You may assume that the input string is valid, i.e. consists only parentheses, which are correctly balanced.

You may print trailing spaces on each line, but not any more leading spaces than necessary. In total the lines must not be longer than twice the length of the input string. You may optionally print a single trailing newline.

Examples

In addition to the above example, here are a few more test cases (input and output are separated by an empty line).

()

()
(((())))

(      )
 (    )
  (  )
   ()
()(())((()))(())()

()(  )(    )(  )()
   ()  (  )  ()
        ()
((()())()(()(())()))

(                  )
 (    )()(        )
  ()()    ()(  )()
             ()

Related Challenges:

  • Topographic Strings, which asks you to produce what is essentially the complement of the output in this challenge.
  • Code Explanation Formatter, a broad generalisation of the ideas in this challenge, posted recently by PhiNotPi. (In fact, PhiNotPi's original description of his idea was what inspired this challenge.)

Leaderboards

Huh, this got quite a lot of participation, so here is a Stack Snippet to generate both a regular leaderboard and an overview of winners by language.

To make sure that your answer shows up, please start your answer with a headline, using the following Markdown template:

# Language Name, N bytes

where N is the size of your submission. If you improve your score, you can keep old scores in the headline, by striking them through. For instance:

# Ruby, <s>104</s> <s>101</s> 96 bytes

function answersUrl(e){return"http://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function getAnswers(){$.ajax({url:answersUrl(page++),method:"get",dataType:"jsonp",crossDomain:true,success:function(e){answers.push.apply(answers,e.items);if(e.has_more)getAnswers();else process()}})}function shouldHaveHeading(e){var t=false;var n=e.body_markdown.split("\n");try{t|=/^#/.test(e.body_markdown);t|=["-","="].indexOf(n[1][0])>-1;t&=LANGUAGE_REG.test(e.body_markdown)}catch(r){}return t}function shouldHaveScore(e){var t=false;try{t|=SIZE_REG.test(e.body_markdown.split("\n")[0])}catch(n){}return t}function getAuthorName(e){return e.owner.display_name}function process(){answers=answers.filter(shouldHaveScore).filter(shouldHaveHeading);answers.sort(function(e,t){var n=+(e.body_markdown.split("\n")[0].match(SIZE_REG)||[Infinity])[0],r=+(t.body_markdown.split("\n")[0].match(SIZE_REG)||[Infinity])[0];return n-r});var e={};var t=0,c=0,p=-1;answers.forEach(function(n){var r=n.body_markdown.split("\n")[0];var i=$("#answer-template").html();var s=r.match(NUMBER_REG)[0];var o=(r.match(SIZE_REG)||[0])[0];var u=r.match(LANGUAGE_REG)[1];var a=getAuthorName(n);t++;c=p==o?c:t;i=i.replace("{{PLACE}}",c+".").replace("{{NAME}}",a).replace("{{LANGUAGE}}",u).replace("{{SIZE}}",o).replace("{{LINK}}",n.share_link);i=$(i);p=o;$("#answers").append(i);e[u]=e[u]||{lang:u,user:a,size:o,link:n.share_link}});var n=[];for(var r in e)if(e.hasOwnProperty(r))n.push(e[r]);n.sort(function(e,t){if(e.lang>t.lang)return 1;if(e.lang<t.lang)return-1;return 0});for(var i=0;i<n.length;++i){var s=$("#language-template").html();var r=n[i];s=s.replace("{{LANGUAGE}}",r.lang).replace("{{NAME}}",r.user).replace("{{SIZE}}",r.size).replace("{{LINK}}",r.link);s=$(s);$("#languages").append(s)}}var QUESTION_ID=49042;var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe";var answers=[],page=1;getAnswers();var SIZE_REG=/\d+(?=[^\d&]*(?:&lt;(?:s&gt;[^&]*&lt;\/s&gt;|[^&]+&gt;)[^\d&]*)*$)/;var NUMBER_REG=/\d+/;var LANGUAGE_REG=/^#*\s*([^,]+)/
body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
<script src=https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js></script><link rel=stylesheet type=text/css href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"><div id=answer-list><h2>Leaderboard</h2><table class=answer-list><thead><tr><td></td><td>Author<td>Language<td>Size<tbody id=answers></table></div><div id=language-list><h2>Winners by Language</h2><table class=language-list><thead><tr><td>Language<td>User<td>Score<tbody id=languages></table></div><table style=display:none><tbody id=answer-template><tr><td>{{PLACE}}</td><td>{{NAME}}<td>{{LANGUAGE}}<td>{{SIZE}}<td><a href={{LINK}}>Link</a></table><table style=display:none><tbody id=language-template><tr><td>{{LANGUAGE}}<td>{{NAME}}<td>{{SIZE}}<td><a href={{LINK}}>Link</a></table>

\$\endgroup\$
  • 17
    \$\begingroup\$ Alternative title: De-Lisp-ify a string. :P \$\endgroup\$ – Alex A. Apr 20 '15 at 20:25
  • 1
    \$\begingroup\$ Are there any restrictions on the color of the output? \$\endgroup\$ – Matteo Italia Apr 21 '15 at 20:20
  • 1
    \$\begingroup\$ @MartinBüttner: nevermind, I found a cleaner way; let's just say that my previous idea would have shaved a byte leaving all the closed parentheses blinking blue over cyan... :-) \$\endgroup\$ – Matteo Italia Apr 21 '15 at 21:00
  • 8
    \$\begingroup\$ @MatteoItalia oh god, I'm glad that didn't happen. ;) \$\endgroup\$ – Martin Ender Apr 21 '15 at 21:00
  • 12
    \$\begingroup\$ @MatteoItalia: Post that version! It's worth seeing. \$\endgroup\$ – user2357112 Apr 22 '15 at 4:28

44 Answers 44

8
\$\begingroup\$

CJam, 17 16 15 bytes

0000000: 72 3a 69 22 28 0b 20 9b 41 29 22 53 2f 66 3d     r:i"(. .A)"S/f=

The above is a reversible xxd dump, since the source code contains the unprintable characters VT (0x0b) and CSI (0x9b).

Like this answer, it uses ANSI escape sequences, but it also uses vertical tabs and it prints the control characters directly to avoid using printf.

This requires a supporting video text terminal, which includes most non-Windows terminal emulators.

Test run

We have to set the shell variable LANG and the terminal emulator's encoding to ISO 8859-1. The former is achieved by executing

$ LANGsave="$LANG"
$ LANG=en_US

Also, before executing the actual code, we'll disable the prompt and clear the screen.

$ PS1save="$PS1"
$ unset PS1
$ clear

This makes sure the output is shown properly.

echo -n '()(())((()))(())()' | cjam <(base64 -d <<< cjppIigLIJtBKSJTL2Y9)
()(  )(    )(  )()
   ()  (  )  ()
        ()

To restore LANG and the prompt, execute this:

$ LANG="$LANGsave"
$ PS1="$PS1save"

How it works

We insert a vertical tab after each ( to move the cursor down and the byte sequence 9b 41 ("\x9bA") before each ) to move the cursor up.

r         e# Read a whitespace-separated token from STDIN.
:i        e# Replace each character by its code point.
          e#   '(' -> 40, ')' -> 41
"(. .A)"  e# Push the string "(\v \x9bA)".
S/        e# Split at spaces into ["(\v" "\x9bA)"].
f=        e# Select the corresponding chunks.
          e# Since arrays wrap around in CJam, ["(\v" "\x9bA)"]40= and 
          e# ["(\v" "\x9bA)"]41= select the first and second chunk, respectively.
\$\endgroup\$
49
\$\begingroup\$

x86 machine code, 39 34 33 30 29 bytes

00000000  68 c3 b8 07 31 ff be 82  00 b3 a0 ad 4e 3c 28 7c  |h...1.......N<(||
00000010  f0 77 05 ab 01 df eb f3  29 df ab eb ee           |.w......)....|
0000001d

x86 assembly for DOS, with some tricks:

    org 100h

section .text

start:
    ; point the segment ES to video memory
    ; (c3 is chosen so that it doubles as a "ret")
    push 0b8c3h
    pop es
    ; di: output pointer to video memory
    xor di,di
    ; si: input pointer from the command line
    mov si,82h
    ; one row=160 bytes (assume bh=0, as should be)
    mov bl,160
lop:
    ; read & increment si (assume direction flag clean)
    ; we read a whole word, so that later we have something nonzero to
    ; put into character attributes
    lodsw
    ; we read 2 bytes, go back 1
    dec si
    ; check what we read
    cmp al,'('
    ; less than `(`: we got the final `\n` - quit
    ; (we jump mid-instruction to get a c3 i.e. a ret)
    jl start+1
    ; more than `(`: assume we got a `)`
    ja closed
    ; write a whole word (char+attrs), so we end
    ; one position on the right
    stosw
    ; move down
    add di,bx
    ; rinse & repeat
    jmp lop
closed:
    ; move up
    sub di,bx
    ; as above
    stosw
    jmp lop

Limitations:

  • it always prints starting at the bottom of the screen, without erasing first; a cls before running is almost mandatory;
  • the colors are ugly; that's the consequence of recycling the next character as color attributes to save two bytes here and there;
  • the code assumes bh=0 and the direction flag clear on start, both undocumented; OTOH, bx is explicitly set to zero in all DOS variants I saw (DosBox, MS-DOS 2, FreeDOS), and everywhere I tested the flags were already OK.

enter image description here

\$\endgroup\$
  • \$\begingroup\$ Just verified this. Yes, it works. Are you sure you need to do cld? \$\endgroup\$ – FUZxxl Apr 21 '15 at 13:28
  • \$\begingroup\$ @FUZxxl: on DosBox it works fine even without it, but looking at its sources it says that the flags are preserved from whatever happened in DOS and in TRSs before, so probably it would be required to play it safe. Anyhow, that would be just one byte, the real payoff would be to kill at least one of those big (=4 byte each) add/sub. \$\endgroup\$ – Matteo Italia Apr 21 '15 at 13:49
  • \$\begingroup\$ Hm... no idea, really. \$\endgroup\$ – FUZxxl Apr 21 '15 at 14:07
  • \$\begingroup\$ Can you change lop to loop? \$\endgroup\$ – mbomb007 Apr 22 '15 at 16:03
  • \$\begingroup\$ @mbomb007: maybe? I'm not sure if nasm disambiguates between loop as a label and loop the assembly instruction, so I just write lop as everybody else does. \$\endgroup\$ – Matteo Italia Apr 22 '15 at 16:27
28
\$\begingroup\$

J, 32 28 bytes

This was a fun one.

0|:')(('&(i.-<:@+/\@i:){."0]

Explanation

This is how this solution works, including an explanation of how it has been golfed.

   NB. Let a be a test case
   a =. '((()())()(()(())()))'

   NB. level alterations
   _1 + ').(' i. a
1 1 1 _1 1 _1 _1 1 _1 1 1 _1 1 1 _1 _1 1 _1 _1 _1

   NB. absolute levels
   +/\ _1 + ').(' i. a
1 2 3 2 3 2 1 2 1 2 3 2 3 4 3 2 3 2 1 0

   NB. adjusted levels
   (+/\ _1 + ').(' i. a) - ')(' i. a
0 1 2 2 2 2 1 1 1 1 2 2 2 3 3 2 2 2 1 0

   NB. take level from end of each item of a and transpose
   |: a {."0~ _1 - (+/\ _1 + ').(' i. a) - ')(' i. a
(                  )
 (    )()(        ) 
  ()()    ()(  )()  
             ()     

   NB. code as a tacit verb
   [: |: ] {."0~ _1 - ([: +/\ _1 + ').(' i. ]) - ')(' i. ]

   NB. subtractions pulled into the prefix insert
   [: |: ] {."0~ (')(' i. ]) - [: <:@+/\ ').(' i. ]

   NB. i: instead of i. so we can use the same string constant
   [: |: ] {."0~ (')((' i. ]) - [: <:@+/\ ')((' i: ]

   NB. get rid of the caps
   0 |: ] {."0~ (')((' i. ]) - ')((' <:@+/\@i: ]

   NB. join the two usages of ')((' into a single dyadic phrase
   0 |: ] {."0~ ')((' (i. - <:@+/\@i:) ]

   NB. bond ')((' and flip arguments to {."0
   0 |: ')(('&(i. - <:@+/\@i:) {."0 ]
\$\endgroup\$
  • 1
    \$\begingroup\$ Very nice! The solution is full of great parts! \$\endgroup\$ – randomra Apr 21 '15 at 0:58
  • 1
    \$\begingroup\$ (I usually add an example invocation of the function so non-experienced users could try it out too.) \$\endgroup\$ – randomra Apr 21 '15 at 0:58
  • \$\begingroup\$ This solution makes my head hurt :') \$\endgroup\$ – Nic Hartley May 20 '16 at 22:26
  • \$\begingroup\$ @QPaysTaxes I take this as a compliment. \$\endgroup\$ – FUZxxl May 20 '16 at 23:11
  • \$\begingroup\$ @FUZxxl It is. It's also a pun based on a sequence of characters that appears in your answer. \$\endgroup\$ – Nic Hartley May 21 '16 at 0:27
15
\$\begingroup\$

C, 150 bytes

t;f(char*c){char l=strlen(c)+1,o[l*l],*A=o,m=0;for(t=1;t<l*l;t++)o[t-1]=t%l?32:10;for(t=-1;*c;c++)A++[l*(*c-41?++t>m?m=t:t:t--)]=*c;A[m*l]=0;puts(o);}

This was crazy fun to golf. I'm still not convinced I'm done with it.

We define a single function, f, that takes the string as input and outputs to stdout.

Let's go through the code, line by line:

/* t will represent the current depth of a parentheses. It must be an int. */
t;
f(char*c){
    //Our variables:
    char l=strlen(c)+1,    //The length of each row of output, including newlines
         o[l*l],           //The output string. It's way larger than it needs to be.
         *A=o,             //We need another pointer to keep track of things.
         m=0;              //The maximum depth recorded thus far.

    for(t=1;t<l*l;t++)     //For each character in our output...
        o[t-1]=t%l?32:10;  //If it's at the end of a line, make it '\n'. Else, ' '.
    for(t=-1;*c;c++)       //While we have an input string...
        //Perhaps a personal record for ugliest warning-less line...
        A++[l*(*c-41?++t>m?m=t:t:t--)]=*c;
    /* 
        A breakdown:
        A++        --> Go to the next *column* of output, after writing. 
                   --> There will only ever be one parentheses per output column.
        [l*(...)]  --> A[l*X] is the character in the current column at depth X.
        (*c-41?    --> If the character is a '('...    
        ++t>m?     --> Increment t *before* we write it. If this is a new highest depth
        m=t:       --> Set m to t, and set the whole expression to t.
        t:         --> If it's not a new highest depth, don't set m.
        t--)       --> If the character was a ')', decrement t *after* we write it.
        =*c        --> Write our output character to whatever the input read.
    */    

    A[m*l]=0; //The last character of the maximum-depth line should be null terminated.
    puts(o);  //Output!
}

I'll answer any questions you may have!

Try a test program online!

\$\endgroup\$
  • \$\begingroup\$ I want to remember that "char l=strlen(c)+1, o[l*l]" isn't valid because you can't define a variable sized array like that, but it's been 15 years since I tried anything of that sort in C. \$\endgroup\$ – Sparr Apr 20 '15 at 15:19
  • \$\begingroup\$ @Sparr My compiler doesn't even throw a warning. I believe this was "officially" standard in C99. I will try to find a reference for this. \$\endgroup\$ – BrainSteel Apr 20 '15 at 15:20
  • 1
    \$\begingroup\$ @Sparr Here is a reference. \$\endgroup\$ – BrainSteel Apr 20 '15 at 15:29
  • \$\begingroup\$ Thanks. It does seem things changed around 15 (give or take a couple) years ago in this regard :) \$\endgroup\$ – Sparr Apr 20 '15 at 17:32
  • 1
    \$\begingroup\$ @CoolGuy It would, but on subsequent calls of f, m would not reset to 0. This counts as "breaking your environment," outlawed here. \$\endgroup\$ – BrainSteel Jul 2 '15 at 2:28
15
\$\begingroup\$

Retina + Bash, 27 bytes (14 + 10 + 3 = 27)

This makes use of ANSI Escapes:

\(
(\e[B
\)
\e[A)

Equivalent to sed -e "s/(/(\\\e[B/g;s/)/\\\e[A)/g". The \e[B escape code means move cursor down one row, and the \e[A means move cursor up one row, so this solution simply inserts those codes after and before the start and end of each nested pair of parentheses. Input is passed through STDIN.

You'll have to call it as printf $(Retina ...) to see the output correctly.

Output

(((())))
(\e[B(\e[B(\e[B(\e[B\e[A)\e[A)\e[A)\e[A)
^C
amans:~ a$ printf "(\e[B(\e[B(\e[B(\e[B\e[A)\e[A)\e[A)\e[A)"
(      )amans:~ a$ 
 (    )
  (  )
   ()

((()())()(()(())()))
(\e[B(\e[B(\e[B\e[A)(\e[B\e[A)\e[A)(\e[B\e[A)(\e[B(\e[B\e[A)(\e[B(\e[B\e[A)\e[A)(\e[B\e[A)\e[A)\e[A)
^C
amans:~ a$ printf "(\e[B(\e[B(\e[B\e[A)(\e[B\e[A)\e[A)(\e[B\e[A)(\e[B(\e[B\e[A)(\e[B(\e[B\e[A)\e[A)(\e[B\e[A)\e[A)\e[A)"
(                  )amans:~ a$ 
 (    )()(        )
  ()()    ()(  )()
             ()
\$\endgroup\$
  • 1
    \$\begingroup\$ Well, not bad! If you could point to a specific terminal that doesn't need printf that would be great. Otherwise, I think it would only be fair to add | printf to the byte count. \$\endgroup\$ – Martin Ender Apr 22 '15 at 2:43
  • \$\begingroup\$ @MartinBüttner It should be printf $() or printf $(Retina ). \$\endgroup\$ – jimmy23013 Apr 22 '15 at 3:02
  • 1
    \$\begingroup\$ What's that Retina thingy? \$\endgroup\$ – FUZxxl Apr 22 '15 at 7:36
  • 2
    \$\begingroup\$ @FUZxxl It's my own regex-based programming language. See GitHub. \$\endgroup\$ – Martin Ender Apr 22 '15 at 13:16
  • 2
    \$\begingroup\$ Why \e plus printf? You can simply put the control characters in the replacement pattern. \$\endgroup\$ – Dennis Jul 1 '15 at 5:48
14
\$\begingroup\$

TI-BASIC, 69 60 56 55 bytes

This is for the TI-83+/84+ family of calculators, although it was written on an 84+ C Silver Edition.

The program shows up as larger on-calc due to VAT+size info being included. Also, there are more than 56 characters here; the reason it's 56 bytes is because all commands that are more than one character are compressed down to tokens that are either one or two bytes in size.

Input Str1
1→B
For(A,1,length(Str1
sub(Str1,A,1→Str2
Ans="(
Output(B+Ans,A,Str2
B-1+2Ans→B
End

Shaved off another byte thanks to thomas-kwa! (also from him was the jump from 60 to 56.)

\$\endgroup\$
  • 4
    \$\begingroup\$ Ahhh, my first programming language. Thanks for the nostalgia, haha. \$\endgroup\$ – Alex Pritchard Apr 21 '15 at 14:55
  • 1
    \$\begingroup\$ Still programing TI for highschool math class, very useful to have formulas built in that will calculate for you on tests and assignments. \$\endgroup\$ – Elias Benevedes Apr 23 '15 at 20:31
  • 1
    \$\begingroup\$ If you shift things around you can use the cos(piAns trick to save another byte. \$\endgroup\$ – lirtosiast May 25 '15 at 0:57
9
\$\begingroup\$

Python 2, 115 bytes

def f(L,n=0,O=()):
 for c in L:n-=c>"(";O+=" "*n+c,;n+=c<")"
 for r in map(None,*O):print"".join(c or" "for c in r)

Call like f("((()())()(()(())()))"), and output is to STDOUT.

Explanation

We start with n = 0. For each char in the input line:

  • If the char is (, we prepend n spaces then increment n
  • If the char is ), we decrement n then prepend n spaces

The result is then zipped and printed. Note that Python's zip zips to match the length of the shortest element, e.g.

>>> zip([1, 2], [3, 4], [5, 6, 7])
[(1, 3, 5), (2, 4, 6)]

Usually one would use itertools.zip_longest (izip_longest) if they wanted zip to pad to the length of the longest element.

>>> import itertools
>>> list(itertools.izip_longest([1, 2], [3, 4], [5, 6, 7]))
[(1, 3, 5), (2, 4, 6), (None, None, 7)]

But in Python 2, this behaviour can be simulated by mapping None:

>>> map(None, [1, 2], [3, 4], [5, 6, 7])
[(1, 3, 5), (2, 4, 6), (None, None, 7)]

Python 3, 115 bytes

L,d,*O=input(),0
for i,c in enumerate(L):b=c>"(";O+="",;O[d-b]=O[d-b].ljust(i)+c;d-=b*2-1
for l in O:l and print(l)

No zipping, just padding appropriately with ljust. This one seems to have some golfing potential.

\$\endgroup\$
8
\$\begingroup\$

R, 151 127 characters

S=strsplit(scan(,""),"")[[1]];C=cumsum;D=c(C(S=="("),0)-c(0,C(S==")"));for(j in 1:max(D)){X=S;X[D!=j]=' ';cat(X,sep='',fill=T)}

With indents and newlines:

S=strsplit(scan(,""),"")[[1]]
C=cumsum
D=c(C(S=="("),0)-c(0,C(S==")"))
for(j in 1:max(D)){
    X=S
    X[D!=j]=' '
    cat(X,sep='',fill=T)
    }

Usage:

> S=strsplit(scan(,""),"")[[1]];C=cumsum;D=c(C(S=="("),0)-c(0,C(S==")"));for(j in 1:max(D)){X=S;X[D!=j]=' ';cat(X,sep='',fill=T)}
1: ()(())((()))(())()
2: 
Read 1 item
()(  )(    )(  )()
   ()  (  )  ()   
        ()        
> S=strsplit(scan(,""),"")[[1]];C=cumsum;D=c(C(S=="("),0)-c(0,C(S==")"));for(j in 1:max(D)){X=S;X[D!=j]=' ';cat(X,sep='',fill=T)}
1: ((()())()(()(())()))
2: 
Read 1 item
(                  )
 (    )()(        ) 
  ()()    ()(  )()  
             ()     

It reads the string as stdin, splits it as a vector of single characters, computes the cumulative sum of ( and ), substracts the former with the latter (with a lag) thus computing the "level" of each parentheses. It then prints to stdout, for each level, either the corresponding parentheses or a space.

Thanks to @MickyT for helping me shortening it considerably!

\$\endgroup\$
  • 2
    \$\begingroup\$ +1 Nice and elegant solution. You can save 6 by replacing for(i in n)cat(ifelse(D[i]-j," ",S[i]));cat("\n") with X=S;X[which(D!=j)]=' ';cat(X,sep='',fill=T). Then n isn't really required, but you would need change the cumsum part a bit. D=c(C(S=="("),0)-c(0,C(S==")")); bringing it down to 135. \$\endgroup\$ – MickyT Apr 20 '15 at 20:14
  • \$\begingroup\$ @MickyT wow thanks! didn't thought of that. which is not really necessary here though (D!=j being already a vector of booleans allowing indexing). I didn't know argument fill for cat, that's a nifty trick! Thanks for making me shorten it by an astounding 24 characters!! \$\endgroup\$ – plannapus Apr 21 '15 at 6:16
8
\$\begingroup\$

C, 58 53 52 51 49 bytes

Makes use of ANSI escape sequences to move the cursor position.

f(char*s){while(*s)printf(*s++&1?"\e[A)":"(\v");}

If not using gcc or another compiler that supports \e then it can be replaced with \x1B for a total of 2 extra bytes. \e[A moves the cursor up one row and \e[B moves the cursor down one row. It's not necessary to use \e[B to move down one row as it's two bytes shorter to use the ASCII vertical tab character 0xB or \v.

The input string is assumed, from the question, to consist of only (balanced) parentheses, so checking the parity of the character, with &1, is enough to distinguish between ( and ).

\$\endgroup\$
7
\$\begingroup\$

Pip, 53 bytes

Pip is a code-golf language of my invention. The first version was published on Saturday, so I can officially take it for a spin! The solution below isn't terribly competitive as golfing languages go, but that's partly because I haven't implemented things like zip and max yet.

z:{aEQ'(?++v--v+1}MaW(o:{z@++v=i?as}Ma)RMs{Pov:-1++i}

Expects the string of parentheses as a command-line argument.

"Ungolfed" version:

z:{
   a EQ '( ?
    ++v
    --v+1
  } M a
W (o:{
      z @ ++v = i ?
       a
       s
     } M a
  ) RM s
{
 P o
 v:-1
 ++i
}

Explanation:

Unlike most golfing languages, Pip is imperative with infix operators, so the syntax is somewhat closer to C and its derivatives. It also borrows ideas from functional and array-based programming. See the repository for further documentation.

The program first generates a list of depths (storing it in z) by mapping a function to the input string a. The global variable v tracks the current level. (Variables a-g in Pip are function-local variables, but h-z are global. v is handy because it's preinitialized to -1.)

Next, we use a While loop to generate and print each line, until the line generated would consist of all spaces. v is now used for columns, and i for rows. The {z@++v=i?as} function, repeatedly mapped to the original input string, tests whether the current line i matches the line the current parenthesis is supposed to be on (as stored in the z list). If so, use the parenthesis (a); if not, use s (preinitialized to space). The end result is that on each iteration, o gets assigned a list of characters equivalent to the next line of the output.

To test whether we should continue looping, we check if o with all the spaces RM'd is empty. If not, print it (which by default concatenates everything together as in CJam), reset the column number to -1, and increment the row number.

(Fun fact: I had a 51-byte solution at first... which didn't work because it turned up a bug in the interpreter.)

\$\endgroup\$
7
\$\begingroup\$

Pyth, 31 bytes

VzJs.e?YqN-/<zk\(/<zhk\)dzI-JdJ

Try it online.

-/<zk\(/<zhk\): Finds the appropriate level for the current character position.

?YqN-/<zk\(/<zhk\)d: A space if the appropriate level is not the current level, current character otherwise.

Js.e?YqN-/<zk\(/<zhk\)dz: Generate the string, save it to J.

I-JdJ: If J is not all spaces, print it out.

Vz: Loop z times.

\$\endgroup\$
6
\$\begingroup\$

GNU Bash + coreutils + indent, 135

eval paste "`tr '()' {}|indent -nut -i1 -nbap|sed 's/.*/<(fold -1<<<"&")/'|tr '
' \ `"|expand -t2|sed 'y/{}/()/;s/\(.\) /\1/g;s/ \+$//'

Input/output via STDIN/STDOUT:

$ ./telescopic.sh <<< "(()(()())()((())))(())"
(                )(  )
 ()(    )()(    )  ()
    ()()    (  )
             ()
$ 

indent does most of the heavy lifting, but needs to work with braces instead of parens. The rest is modification of this answer to transpose the output of indent.

\$\endgroup\$
5
\$\begingroup\$

Java, 232 226 224 222 bytes

Golfed version:

int i,j,k,l,m,a[];void f(String s){a=new int[s.length()];j=a.length;for(k=0;k<j;){a[k]=s.charAt(k++)<41?i++:--i;m=m<i?i:m;}for(k=0;k<m;k++)for(l=0;l<j;)System.out.print(k==a[l++]?i++%2<1?'(':l==j?")\n":')':l==j?'\n':' ');}

Long version:

int i, j, k, l, m, a[];
void f(String s) {
    a = new int[s.length()];
    j = a.length;
    for (k = 0; k < j;) {
        a[k] = s.charAt(k++) < 41 ? i++ : --i;
        m = m < i ? i : m;
    }
    for (k = 0; k < m; k++)
        for (l = 0; l < j;)
            System.out.print(k == a[l++] ? (i++ % 2 < 1 ? '(' : (l == j ? ")\n" : ')')) : (l == j ? '\n':' '));
}

The input string is analyzed first, looking for "(" and ")" to add/subtract a counter and store its value determining how far down the parentheses should go in an array while also keeping track of how deep the deepest one goes. Then the array is analyzed; the parentheses with lesser values are printed first, and will continue printing line by line until the maximum is reached.

I'll probably find ways to golf this further later.

\$\endgroup\$
5
\$\begingroup\$

Javascript/ES6, 97 chars

f=s=>{for(n in s){m=o=d='';for(c of s)o+=n==(c<')'?d++:--d)?c:' ',m=m<d?d:m;n<m&&console.log(o)}}

Usage

f("(()(()())()((())))(())")

Explanation

fn=str=>{                          // accepts string of parenthesis
  for(line in str){                // repeat process n times where n = str.length
    max=output=depth='';           // max: max depth, output: what to print, depth: current depth
    for(char of str)               // iterate over chars of str
      output+=
        line==(char<')'?depth++:--depth)? // update depth, if line is equal to current depth
        char:' ',                  // append either '(', ')', or ' '
        max=max<depth?depth:max;   // update max depth
    line<max&&console.log(output)  // print if current line is less than max depth
  }
}
\$\endgroup\$
  • \$\begingroup\$ Instead of n<m?console.log(o):0, you can use n<m&&console.log(o) which saves 1 byte. \$\endgroup\$ – Ismael Miguel Apr 22 '15 at 8:16
4
\$\begingroup\$

CJam, 43 41 36 bytes

Not too golfed (I think), but here goes my first attempt:

l:L,{)L<)_')=@~zS*\+}%_$0=,f{Se]}zN*

How it works

I am using the very handy fact that ) and ( in CJam mean increment and decrement respectively. Thus, I simply evaluate the brackets to get the depth.

l:L,{)L<)_')=@~zS*\+}%_$0=,f{Se]}zN*
l:L,{                    }%                "Store input line in L and iterate over [0,L)";
     )L<                                   "substr(L, 0, iterator + 1)";
        )                                  "Slice off the last character to stack";
         _')=                              "Put 0 on stack if the sliced character is (,
                                            else 1 if sliced character is )";
             @~                            "bring forth the remaining
                                            brackets after slicing and evaluate them";
               zS*                         "Stack has negative depth number, take absolute
                                            value and get that many spaces";
                  \+                       "Prepend to the sliced character";
                      _$0=,                "Get the maximum depth of brackets";
                           f{Se]}          "Pad enough spaces after each string to match
                                            the length of each part";
                                 zN*       "Transpose and join with new lines";

Try it online here

\$\endgroup\$
4
\$\begingroup\$

Octave, 85 chars

function r=p(s)i=j=0;for b=s k=b==40;k&&++j;t(j,++i)=9-k;k||--j;r=char(t+32);end;end

It's an optimization of the naïve approach, which is actually pretty natural for Matlab and Octave:

function r=p(s)
i=j=1;
for b=s
 if b=='(' t(++j,i++)='(' else t(j--,i++)=')' end; end; t(~t)=' '; r=char(t);
end;

The table t may even not yet exist, and we may assign to any element right away, and it reshapes to the smallest dimension that is required for this element to exist which is quite convenient.

\$\endgroup\$
4
\$\begingroup\$

Python 2, 92

def f(s,i=0,z=''):
 for x in s:b=x>'(';z+=[' ',x][i==b];i-=2*b-1
 if'('in z:print z;f(s,i-1)

Prints line by line. For a given line number i (actually, its negation), goes through the input string s, and makes a new string z that only contains the characters of s at depth i. This is done by incrementing or decrementing i to track the current depth, and adding the current characters when i is 0 adjusted for paren type, and otherwise adding a space.

Then, prints and recurses to the next i unless the current line was all spaces. Note that since the parens are balanced, the i after a loop is the same as at the start.

Python 3 would be same except for a character for print(z).

\$\endgroup\$
4
\$\begingroup\$

Perl, 91 89 88 84 80 79 bytes

$t=<>;{$_=$t;s/\((?{$l++})|.(?{--$l})/$^R==$c?$&:$"/ge;print,++$c,redo if/\S/}
  • $t is the input string.
  • $c is the depth we want to print on the current line.
  • $l is the depth we are at after encountering a paren.
  • $l is updated in regex embedded code blocks.
  • $^R is the result of the most recent code block.
\$\endgroup\$
4
\$\begingroup\$

cheating :( Retina + TeX, N bytes cheating :(

This only works if you render(?) the output using MathJax or some other TeX, which is currently disabled for this SE :(

\(
({
\)
})
\{\(
_{(

Each line should be in a different file, but you can test it by using Retina -e "\(" -e "({" -e "\)" -e "})" -e "\{\(" -e "_{(" (or the equivalent sed command sed -e "s/(/({/g;s/)/})/g;s/{(/_{(/g"). Input is passed through STDIN.

This works by enclosing the contents of each pair of parentheses in braces, and then subscripting all the items inside them.

Output

(((())))
(_{(_{(_{({})})})})

()(())((()))(())()
({})(_{({})})(_{(_{({})})})(_{({})})({})

((()())()(()(())()))
(_{(_{({})({})})({})(_{({})(_{({})})({})})})

TeX Output

\$\endgroup\$
  • 1
    \$\begingroup\$ I'm flattered that you've used Retina, and this is nice thinking-outside-the-box but that's not quite what the output is supposed to look like. ;) In particular this violates the alternative formulation "Another way to look at it is that the parentheses at depth n are moved to line n, while keeping their horizontal position." I'd be very impressed by a pure, rule-compliant Retina solution though and might hand out a bounty for it. ;) \$\endgroup\$ – Martin Ender Apr 21 '15 at 23:55
  • \$\begingroup\$ In total the lines must not be longer than twice the length of the input string. Changing line 2 to (\,{ and line 4 to }\,) means that the output fits this (although the vertical depth is still wrong : ( ) \$\endgroup\$ – user22723 Apr 22 '15 at 0:14
  • \$\begingroup\$ Well, I managed to make rule-compliant solution : ) \$\endgroup\$ – user22723 Apr 22 '15 at 1:07
  • 1
    \$\begingroup\$ Nice job. I guess that means you can delete the cheaty answer now. ;) \$\endgroup\$ – Martin Ender Apr 22 '15 at 2:44
4
\$\begingroup\$

Haskell, 154 bytes

f h('(':s)=h:f(h+1)s;f h(')':s)=(h-1):f(h-1)s;f _ _=[]
main=interact$ \s->unlines[[if i==h then c else ' '|(c,i)<-zip s l]|let l=f 0 s,h<-[0..maximum l]]

same idea as the other Haskell solution, but somewhat shorter. - Usage:

echo  '(((())())(()))' | runghc Golf.hs
\$\endgroup\$
3
\$\begingroup\$

J, 46

Not as great as the other 'golfing languages', but in my defence: J is terrible with strings.

[:|:(((,~(' '#~]))"0)(0,2%~[:+/\2+/\1-'(('i.]))~

Takes the string as input for a function. There's also probably a better way to do it in J.

Usage:

   f=:[:|:(((,~(' '#~]))"0)(0,2%~[:+/\2+/\1-'(('i.]))~
   f '(()(()())()((())))(())'
(                )(  )
 ()(    )()(    )  () 
    ()()    (  )      
             ()       
\$\endgroup\$
  • \$\begingroup\$ See my answer for another way of doing this in J. \$\endgroup\$ – FUZxxl Apr 20 '15 at 19:40
  • 3
    \$\begingroup\$ Personally, I think that J is perfectly well-suited for strings. You just need to think with arrays. \$\endgroup\$ – FUZxxl Apr 20 '15 at 21:02
3
\$\begingroup\$

Ruby, 119 115 114

->s{r=[""]*s.size
d=0
s.chars.map{|l|r.map!{|s|s+" "}
b=l>"("?1:0
d-=b
r[d][-1]=l
d+=1-b}.max.times{|i|puts r[i]}}

Explanation:

->s{r=[""]*s.size  # Take an array of strings big enough
d=0                # This will contain the current depth
s.chars.map{|l|r.map!{|s|s+" "}  # Add a new space to every array
b=l>"("?1:0       # Inc/Dec value of the depth
d-=b               # Decrement depth if we are at a closing paren
r[d][-1]=l         # Set the corresponding space to the actual open/close paren
d+=1-b             # Increment the depth if we are at a opening paren
}.max.times{|i|puts r[i]}}  # Print only the lines up to the max depth
\$\endgroup\$
3
\$\begingroup\$

Java, 233 214 bytes

void f(String s){int p,x,d,l=s.length();char c,m[]=new char[l*l];java.util.Arrays.fill(m,' ');p=x=0;while(x<l){d=(c=s.charAt(x))==40?p++:--p;m[d*l+x++]=c;}for(x=0;x<l*l;x++)System.out.print((x%l==0?"\n":"")+m[x]);}

Indented:

void f(String s){
    int p, x, d, l = s.length();
    char c, m[] = new char[l * l];
    java.util.Arrays.fill(m, ' ');
    p = x = 0;
    while (x < l){
        d = (c = s.charAt(x)) == 40
                ? p++
                : --p;
        m[d * l + x++] = c;
    }
    for (x = 0; x < l * l; x++)
        System.out.print((x % l == 0 ? "\n" : "") + m[x]);
}

I guess the final loop could be shortened, but I'll leave it as an exercise to the reader. ;-)


Old, 233 bytes answer:

void f(String s){int y=s.length(),x=0;char[][]m=new char[y][y];for(char[]q:m)java.util.Arrays.fill(q,' ');y=0;for(char c:s.toCharArray())if(c=='(')m[y++][x++]=c;else m[--y][x++]=c;for(char[]q:m)System.out.println(String.valueOf(q));}

Indented:

static void f(String s) {
    int y = s.length(), x = 0;
    char[][] m = new char[y][y];
    for(char[] q : m)
        java.util.Arrays.fill(q, ' ');
    y = 0;
    for(char c : s.toCharArray())
        if(c == '(')
            m[y++][x++] = c;
        else
            m[--y][x++] = c;
    for(char[] q : m)
        System.out.println(String.valueOf(q));
}
\$\endgroup\$
  • \$\begingroup\$ I know it's been more than a year, but "I guess the final loop could be shortened, but I'll leave it as an exercise to the reader. ;-)"; you're indeed right. It can be changed from for(x=0;x<l*l;x++)System.out.print((x%l==0?"\n":"")+m[x]); to for(x=0;x<l*l;)System.out.print((x%l==0?"\n":"")+m[x++]); for -1 byte. Also, you can save 2 more bytes by removing p=x=0 and just use int p=0,x=0, at initialization of the fields instead. In total it becomes 211 bytes. \$\endgroup\$ – Kevin Cruijssen Aug 3 '16 at 7:37
3
\$\begingroup\$

C#, 195 bytes

First try at golf - yell if I did something wrong.

Alternative C# version using SetCursorPosition and working left to right taking the input as a commandline arg.

using System;class P{static void Main(string[] a){Action<int,int>p=Console.SetCursorPosition;int r=0,c=0;foreach(var x in a[0]){r+=x==')'?-1:0;p(c,r);Console.Write(x);r+=x=='('?1:0;p(c,r);c++;}}}

I thought it would be fun to adjust the write position based on the open/close paren and not full lines. Close paren moves the position up before writing; open paren moves it down after writing. Actioning SetCursorPosition saves five bytes. Moving the cursor to the next line after the output would take quite a bit extra.

using System;
class P
{
    static void Main(string[] a)
    {
        Action<int, int> p = Console.SetCursorPosition;
        int r = 0, c = 0;
        foreach (var x in a[0])
        {            
            r += x == ')' ? -1 : 0;
            p(c, r);
            Console.Write(x);
            r += x == '(' ? 1 : 0;
            p(c, r);
            c++;
        }
    }
}
\$\endgroup\$
3
\$\begingroup\$

Batch, 356 335 bytes

I know that there already exists a Batch solution for this challenge, but this one is golfed significantly more and seems to take a different approach. Most importantly, the other batch solution contains at least one powershell command; this solution does not.

@echo off
setlocal enabledelayedexpansion
set p=%1
set p=%p:(="(",%
set p=%p:)=")",%
set c=0
for %%a in (%p%)do (if ")"==%%a set/ac-=1
set d=!d!,!c!%%~a
if "("==%%a set/ac+=1&if !c! GTR !m! set m=!c!)
set/am-=1
for /l %%a in (0,1,!m!)do (for %%b in (!d!)do (set t=%%b
if "%%a"=="!t:~0,-1!" (cd|set/p=!t:~-1!)else (cd|set/p=. ))
echo.)

There is a backspace character (U+0008) on the second to last line following the dot (line 12, column 57). This isn't visible in the code posted here but is included in the byte count.

\$\endgroup\$
  • \$\begingroup\$ Somebody else actually submitting an answer in Batch - Nice one +1. \$\endgroup\$ – unclemeat Apr 27 '15 at 0:33
3
\$\begingroup\$

Batch, 424 bytes

@echo off
setLocal enableDelayedExpansion
set s=%1
set a=1
:c
if defined s (set/ac+=1
set "z="
if "%s:~0,1%"=="(" (set "1=(")else (set/aa-=1
set "1=)")
for %%a in (!a!)do for /f usebackq %%b in (`powershell "'!l%%a!'".Length`)do (set/ay=!c!-%%b
for /l %%a in (1,1,!y!)do set z= !z!
set "l%%a=!l%%a!!z!!1!")
if "%s:~0,1%"=="(" set/aa+=1
if !a! GTR !l! set/al=!a!-1
set "s=%s:~1%"
goto c)
for /l %%a in (1,1,!l!)do echo !l%%a!

Un-golfed:

@echo off
setLocal enableDelayedExpansion

set s=%1
set a=1
set c=0
set l=0

:c
if defined s (
    set /a c+=1
    set "z="
    if "%s:~0,1%"=="(" (
        set "1=("
    ) else (
        set /a a-=1
        set "1=)"
    )
    for %%a in (!a!) do for /f usebackq %%b in (`powershell "'!l%%a!'".Length`) do (
        set /a y=!c!-%%b
        for /l %%a in (1,1,!y!) do set z= !z!
        set "l%%a=!l%%a!!z!!1!"
    )
    if "%s:~0,1%"=="(" set /a a+=1
    if !a! GTR !l! set /a l=!a!-1
    set "s=%s:~1%"
    goto c
)

for /l %%a in (1,1,!l!) do echo !l%%a!

Example:

h:\>par.bat (((())())(()))
 (            )
  (      )(  )
   (  )()  ()
    ()
\$\endgroup\$
3
\$\begingroup\$

C, 118 117 Bytes

Another answer in C, but mine is shorter.

c;d;main(m,v)int**v;{while(d++<m){char*p=v[1];while(*p)c+=*p==40,putchar(c-d?*p:32),m=c>m?c:m,c-=*p++==41;puts("");}}

Ungolfed version:

c; /* current depth */
d; /* depth to print in current row */
main(m,v)int**v;{
    while(d++<m) {
        char*p=v[1];
        while(*p){
            c+=*p==40;           /* 40 = '(' */
            putchar(c-d?*p:32); /* 32 = ' ' (space) */
            m=c>m?c:m;           /* search maximum depth */
            c-=*p++==41;         /* 41 = ')' */
        }
        puts("");
    }
}

And it works!

% ./telescope '()(())((()))(())()'
()(  )(    )(  )()
   ()  (  )  ()
        ()
% ./telescope '((()())()(()(())()))'
(                  )
 (    )()(        )
  ()()    ()(  )()
             ()
\$\endgroup\$
  • 1
    \$\begingroup\$ Quite an elegant solution, however putchar(c-d?32:*p) is one character shorter than putchar(c==d?*p:32) . \$\endgroup\$ – pawel.boczarski Apr 25 '15 at 16:53
2
\$\begingroup\$

Haskell, 227 bytes

n _ []=[]
n h ('(':r)=('(',h):n(h+1)r
n d (')':r)=let h=d-1 in(')',h):n h r
m n []=n
m n ((_,h):r)=m(max h n)r
p s=let v=n 0 s;h=m 0 v;in map(\d->map(\(b,l)->if l==d then b else ' ')v)[0..h]
main=fmap p getLine>>=mapM_ putStrLn
\$\endgroup\$
  • 1
    \$\begingroup\$ You can save a few spaces with operators: e.g. n#[] instead of m n []. \$\endgroup\$ – Franky Apr 25 '15 at 17:02
2
\$\begingroup\$

Perl, 76 bytes

$a[/\(/?$l++:--$l][$i++]=$_ for split//,<>;print map{$_||' '}@$_,"\n"for@a

No use strict here :)

\$\endgroup\$
2
\$\begingroup\$

Lex, 94 bytes

Depends on Linux console codes. With gcc, you can cut out four bytes by replacing both instances of \33 with an actual escape character.

%%
 int p[2]={0};
\( printf("(\33D");++p[!*p];
\) printf("\33M)");--*p;
\n while(p[1]--)ECHO;

To compile and run:

$ flex -o telescopic.c telescopic.l
$ gcc -o telecopic telescopic.c -lfl
$ ./telescopic
(()(()())()((())))(())
(                )(  )
 ()(    )()(    )  ()
    ()()    (  )
             ()
--- type ctrl-D ---
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.