Make Bracket Squares

33

1

Every programmer knows that brackets []{}()<> are really fun. To exacerbate this fun, groups of interwoven brackets can be transformed into cute and fuzzy diagrams.

Let's say that you have a string that contains balanced brackets, like [{][<(]})>(()). Step one is to rotate the string 45 degrees clockwise. (In Mathematica, this can be almost done with Rotate[ur_string,-pi/4]). Here is the result of the first step:

[
 {
  ]
   [
    <
     (
      ]
       }
        )
         >
          (
           (
            )
             )

Next add a diagonal space between each character.

[

  {

    ]

      [

        <

          (

            ]

              }

                )

                  >

                    (

                      (

                        )

                          )

Next, start with the left-most bracket and draw a square between it and its partner in crime.

+---+
|   |
| { |
|   |
+---+

      [

        <

          (

            ]

              }

                )

                  >

                    (

                      (

                        )

                          )

Repeat this process with each pair of brackets, overwriting previous characters with +s if need be.

+---+
|   |
| +-+---------+
| | |         |
+-+-+         |
  |           |
  |   [       |
  |           |
  |     <     |
  |           |
  |       (   |
  |           |
  |         ] |
  |           |
  +-----------+

                )

                  >

                    (

                      (

                        )

                          )

Continue until you have made everything nice and square.

+---+
|   |
| +-+---------+
| | |         |
+-+-+         |
  |           |
  |   +-----+ |
  |   |     | |
  |   | +---+-+---+
  |   | |   | |   |
  |   | | +-+-+-+ |
  |   | | | | | | |
  |   +-+-+-+ | | |
  |     | |   | | |
  +-----+-+---+ | |
        | |     | |
        | +-----+ |
        |         |
        +---------+

                    +-----+
                    |     |
                    | +-+ |
                    | | | |
                    | +-+ |
                    |     |
                    +-----+

Input

Input will be a single line of balanced brackets and no other characters, with each bracket being one of []{}()<>. Each type of bracket is balanced individually, though different types may overlap (this is what makes the squares look interesting). A trailing newline is optional.

Output

Output will be the interlocking square pattern generated from the bracket string. Trailing spaces and trailing newline are optional, but there mustn't be leading whitespace.

Goal

This is code-golf, fewest bytes wins.

PhiNotPi

Posted 2016-01-08T02:42:10.050

Reputation: 26 739

1Do we have to deal with nesting of the same type of bracket? e.g. for [[]] can we output two squares overlapping or do we have to output one square inside the other? – Volatility – 2016-01-08T02:49:49.413

2One square is inside of the other. I will adjust my example. Edit: done. – PhiNotPi – 2016-01-08T02:53:10.673

Answers

7

JavaScript (ES6), 269 274 278 296 261 bytes

Edit Saved 4 bytes thx @Neil

x=>[...x].map(c=>{g.push([],[]),z='<{[(>}])'.indexOf(c);if(z>3)for(j=a=o[z-4].pop();j<=b;j++)S(j,a,'|'),S(j,b,'|'),S(a),S(b);else o[z].push(b);b+=2},S=(y,x=j,c='-')=>g[y][x]=g[y][x]?'+':c,o=[[],[],[],[]],g=[],b=0)&&g.map(r=>[...r].map(c=>c||' ').join``).join`
`

TEST

F=x=>[...x].map(c=>{g.push([],[]),z='<{[(>}])'.indexOf(c);if(z>3)for(j=a=o[z-4].pop();j<=b;j++)S(j,a,'|'),S(j,b,'|'),S(a),S(b);else o[z].push(b);b+=2},S=(y,x=j,c='-')=>g[y][x]=g[y][x]?'+':c,o=[[],[],[],[]],g=[],b=0)&&g.map(r=>[...r].map(c=>c||' ').join``).join`
`

// Less golfed
U=x=>(
  S = (y,x=j,c='-')=>g[y][x]=g[y][x]?'+':c,
  o = [[],[],[],[]],
  g = [],
  b = 0,
  [...x].map(c=>
  {
    g.push([],[]),
    z='<{[(>}])'.indexOf(c);
    if(z>3)
      for(j = a =o[z-4].pop(); j <= b; j++)
        S(j,a,'|'),
        S(j,b,'|'),
        S(a),
        S(b)
    else
      o[z].push(b);
    b += 2
  }),
  g.map(r=>
    [...r].map(c=>c||' ').join``
  ).join`\n`
)

function test() {
  O.textContent=F(I.value)
}

test()
Input:<input id=I value='[{][<(]})>(())' oninput='test()'>
<pre id=O></pre>

edc65

Posted 2016-01-08T02:42:10.050

Reputation: 31 086

Why not [...r].map? – Neil – 2016-01-08T13:41:31.287

Better still, [...r].map(c=>c||' '). – Neil – 2016-01-08T13:42:25.543

@Neil I cannot use r.map because r is a sparse array and map skips missing elements. So I now use g, that is filled (and there are as many rows as columns in output) – edc65 – 2016-01-08T14:08:41.470

2

I didn't say r.map, I said [...r].map, and [...r] is NOT a sparse array, as you mentioned yourself in http://codegolf.stackexchange.com/a/61505 comment 5.

– Neil – 2016-01-08T14:35:09.890

@Neil I missed that ... it seems a nice hint, thanks – edc65 – 2016-01-08T14:40:27.737

4

Python 3, 226

n,p,*t=0,[],0,[],[],[],[]
for b in input():
 r=t[ord(b)//30];r+=[n];n+=2
 if b in'])}>':p+=[r[-2:]];del r[-2:]
R=range(n-1)
for y in R:print(''.join(' -|+'[sum((y in q)+2*(x in q)for q in p if x>=q[0]<=y<=q[1]>=x)]for x in R))

Example. Explanation:

n,p,*t=0,[],0,[],[],[],[]   # n -> counter for input
                            # p -> bracket pairs
                            # t -> four stacks [unused, (), <>, [], {}]

for b in input():           # for each bracket b of input
  r=t[ord(b)//30];          # r -> alias for b's stack
  r+=[n];                   # push bracket's index
  n+=2                      # increase counter by 2 (to add diagonal gaps)

  if b in'])}>':            # if b is a closing bracket
    p+=[r[-2:]];            # pair the top 2 brackets on stack
    del r[-2:]              # pop them from stack

R=range(n-1)                # n-1 is now the width/height of output

for y in R:
  print(''.join(' -|+'[
    sum((y in{a,b})+2*(x in{a,b})for a,b in p if x>=a<=y<=b>=x)
  ]for x in R))

# three nested loops:
# 1) for each line y
#   2) for each character x
#     3) for each bracket pair (a, b)

if x>=a<=y<=b>=x
# if x or y isn't in the inclusive range [a, b], we can skip it

(y in{a,b})
# if y is a or b, then the character lies on a horizontal edge of that square
# so we add 1 to the sum

2*(x in{a,b})
# if x is a or b, then the character lies on a vertical edge of that square
# so we add 2 to the sum

' -|+'[sum()]
# if it lies on a single edge, the sum will be 1 or 2 -> '-' or '|'
# if it lies on two edges, the sum will be 1 + 2 == 3 -> '+'

grc

Posted 2016-01-08T02:42:10.050

Reputation: 18 565

You can save 2 bytes by not unpacking the bracket pairs in the last line. – Volatility – 2016-01-08T11:50:17.663

2

pb - 449 bytes

^w[B!0]{w[B=40]{b[39]}t[B]w[B!0]{w[B=T]{^b[1]}w[B=T+1]{^b[1]}w[B=T+2]{^b[2]}^[Y]^>}<[X]^w[B!1]{>}t[1]b[0]w[T!0]{>w[B=1]{t[T+1]b[0]}w[B=2]{t[T-1]b[0]}}b[3]vw[B!0]{>}^w[B!3]{b[0]<}b[0]vb[1]>[X]vv[X]b[43]t[X]^[Y]^<[X]w[B=0]{>}>[X]vv[X]b[43]w[Y!T-1]{vw[B=45]{b[43]}w[B=0]{b[124]}}vb[43]t[1]>w[B!43]{t[T+1]w[B=124]{b[43]}w[B=0]{b[45]}>}w[T!0]{^t[T-1]w[B=45]{b[43]}w[B=0]{b[124]}}w[B!43]{w[B=124]{b[43]}w[B=0]{b[45]}<}<[X]^[Y]^w[B=0]{>}b[0]>w[B=1]{b[0]>}}

I was all excited when I read this because I have a language that prints directly to a position! This challenge about positioning outputs should be easy and short!

Then I remembered pb is longwinded anyway.

With comments:

^w[B!0]{
    w[B=40]{b[39]}                       # change ( to ' to make closing bracket calculation work
    t[B]

    # this used to just find the first matching bracket
    # but then op clarified we had to use depth
    # whoops
    # <fix>

    w[B!0]{
        w[B=T]{^b[1]}                        # put a 1 above opening brackets of this type
        w[B=T+1]{^b[1]}                      # same as before, but ugly hack to make ( work
        w[B=T+2]{^b[2]}                      # put a 2 above closing brackets of this type
        ^[Y]^                                # return to input line
    >}
    <[X]^w[B!1]{>}t[1]b[0]               # set T to 1 above the opening bracket
    w[T!0]{>                             # until T (depth) == 0:
        w[B=1]{t[T+1]b[0]}                   # add 1 to T if 1
        w[B=2]{t[T-1]b[0]}                   # subtract 1 from T if 2
    }
    b[3]                                 # when T is 0, we've found the right one
    vw[B!0]{>}                           # go to the end of the input
    ^w[B!3]{b[0]<}b[0]v                  # clean up the row above
    # </fix>

    b[1]                                 # replace it with 1 so it's not confusing later
    >[X]vv[X]b[43]t[X]                   # put a + at its output position and save coord
    ^[Y]^<[X]w[B=0]{>}>[X]vv[X]b[43]     # put a + at opening bracket's output position
    w[Y!T-1]{v
        w[B=45]{b[43]}                       # replace - with +
        w[B=0]{b[124]}                       # otherwise put |
    }
    vb[43]                               # put a + at lower left corner
    t[1]                                 # count side length + 1
    >w[B!43]{
        t[T+1]
        w[B=124]{b[43]}                      # replace | with +
        w[B=0]{b[45]}                        # otherwise put -
    >}
    w[T!0]{^                             # create right side
        t[T-1]
        w[B=45]{b[43]}
        w[B=0]{b[124]}
    }
    w[B!43]{                             # create top side
        w[B=124]{b[43]}                      # this replacement saves us from putting the last + explicitly
                                             # which is why we counted the side length + 1, to get that 
                                             # extra char to replace
        w[B=0]{b[45]}
    <}
    <[X]^[Y]^w[B=0]{>}b[0]>w[B=1]{b[0]>}# Go to next character (skipping 1s)
}

undergroundmonorail

Posted 2016-01-08T02:42:10.050

Reputation: 5 897

I... Just... Can't... – Cyoce – 2016-02-10T02:11:31.343

2

CJam, 117 bytes

q_,2*:M2#0a*\:iee{1=K/}${~)4%1>{a+aL+:L;}*}/L{2f*__~,>m*5Zb\m*{~W2$#%Mb\}%\2m*Mfb3am*}%e_2/{~2$2$=+3e<t}/" |-+"f=M/N*

Try it here.

Lynn

Posted 2016-01-08T02:42:10.050

Reputation: 55 648

1

Ruby, 268

->z{a=(2..2*t=z.size).map{'  '*t}
g=->y,x{a[y][x]=(a[y][x-1]+a[y][x+1]).sum>64??+:?|}
2.times{|h|s=z*1
t.times{|i|c=s[i]
c>?$&&(j=s.index(c.tr('[]{}()<>','][}{)(><'))
(m=i*2).upto(n=j*2){|k|k%n>m ?g[k,m]+g[k,n]:h<1&&a[k][m..n]=?++?-*(n-m-1)+?+}
s[i]=s[j]=?!)}}
puts a}

ungolfed in test program

f=->z{
  a=(2..2*t=z.size).map{'  '*t}                       #make an array of strings of spaces
  g=->y,x{a[y][x]=(a[y][x-1]+a[y][x+1]).sum>64??+:?|} #function for printing verticals: | if adjacent cells spaces (32+32) otherwise +

  2.times{|h|                                         #run through the array twice
    s=z*1                                             #make a duplicate of the input (*1 is a dummy operation to avoid passing just pointer)
    t.times{|i|                                       #for each index in input
    c=s[i]                                            #take the character
    c>?$&&(                                           #if ascii value higher than for $
      j=s.index(c.tr('[]{}()<>','][}{)(><'))          #it must be a braket so find its match
      (m=i*2).upto(n=j*2){|k|                         #loop through the relevant rows of array
        k%n>m ?g[k,m]+g[k,n]:                         #if k!=n and k!m draw verticals
        h<1&&a[k][m..n]=?++?-*(n-m-1)+?+              #otherwise draw horizontals (but only on 1st pass)
      }
      s[i]=s[j]=?!)                                   #we are done with this set of brackets, replace them with ! so they will be ignored in next call of index  
    }
  }
  puts a
}


z=gets.chop
f[z]

Level River St

Posted 2016-01-08T02:42:10.050

Reputation: 22 049