18
\$\begingroup\$

The Task

In this challenge, your task is to draw an ASCII art representation of several stacks of boxes of increasing height. You are given as input the number of stacks, which is a positive integer. The first stack contains one box of size 2x2. The second stack contains 2 boxes of size 3x3. In general, the kth stack contains k boxes of size (k+1)x(k+1).

The borders of each box are drawn using the characters -|+, and their interior consists of whitespace. Adjacent boxes share their borders, and corners should always be drawn with +, even when they are part of a border of another box.

Examples

Output for 1:

++
++

Output for 2:

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

Output for 3:

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

Output for 5:

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

Rules and Scoring

The input can be received from STDIN, as a command line argument, or as a function argument. Output must go to STDOUT or closest equivalent. Any finite amount of trailing whitespace is allowed, as are preceding and trailing newlines, but there cannot be any extra preceding spaces.

This is code-golf, so the lowest byte count wins. Standard loopholes are disallowed.

\$\endgroup\$
5
  • 2
    \$\begingroup\$ I think this ascii output is a good illustration for how n and n-1 are relatively prime. Two pluses will never overlap. \$\endgroup\$
    – mbomb007
    Commented Jun 24, 2015 at 18:36
  • 1
    \$\begingroup\$ Is there any maximum limit for the input number? \$\endgroup\$ Commented Jun 24, 2015 at 19:01
  • \$\begingroup\$ @ThomasWeller Only the maximum limit of your language's native integer type. \$\endgroup\$
    – Zgarb
    Commented Jun 24, 2015 at 20:07
  • \$\begingroup\$ It seems that this is quite a limiting factor. Some of the submissions will not work for Integer.MaxValue as input. \$\endgroup\$ Commented Jun 24, 2015 at 22:15
  • 1
    \$\begingroup\$ @ThomasWeller Oh, you're right of course... it was not my intention to invalidate existing answers. Let's overrule that: a solution should work for all inputs for which the total number of required characters in the output does not exceed Integer.MaxValue or equivalent. \$\endgroup\$
    – Zgarb
    Commented Jun 25, 2015 at 6:43

9 Answers 9

10
\$\begingroup\$

CJam, 64 60 58 bytes

]ri:X{'|'}{I))*\I**XX*)Se[s}:L~:M.e>S'-LaI*~M}fI]zN*'}/'+*

Constructing each column at a time.

Try it online here

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

Java (407 349 chars)

A few chars thanks to @Zgarb and @Geobits

Code

void s(int q){int d,h,y,i,j,x,z,t=q*q+1;char b;for(i=0;i<t;i++){z=x=0;d=t-i;for(j=0;j<(q*q+q)/2+1;j++){b=' ';h=x*x+1;if(x==z){y=x+1;if((d<=h&d%(x==0?1:x)==(x==1?0:1))|(y<=q&d<=y*y+1&d%(y==0?1:y)==(y==1?0:1)))b='+';else if(d<=h|y<=q&d<=y*y+1)b='|';x++;z=1;}else{if(d<=h&d%(x==0?1:x)==(x==1?0:1))b='-';z++;}System.out.print(b);}System.out.println();}}

Not sure if this is optimal, but it's my first attempt, I will probably try to put it in a better golfing language later. Any suggestions are welcome!

Expanded

class StackingBlocks{
    public static void main(String[]a){
        int d,h,y,i,j,x,z,t,q=10;
        t=q*q+1;
        char b;
        for(i=0;i<t;i++){
            z=x=0;
            d=t-i;
            for(j=0;j<(q*q+q)/2+1;j++){
                b=' ';
                h=x*x+1;
                if(x==z){
                    y=x+1;
                    if((d<=h&d%(x==0?1:x)==(x==1?0:1))|(y<=q&d<=y*y+1&d%(y==0?1:y)==(y==1?0:1)))
                        b='+';
                    else if(d<=h|y<=q&d<=y*y+1)
                        b='|';
                    x++;
                    z=1;
                }else{
                    if(d<=h&d%(x==0?1:x)==(x==1?0:1))
                        b='-';
                    z++;
                }
                System.out.print(b);
            }
            System.out.println();
        }
    }
}

Check it out here.

\$\endgroup\$
11
  • 5
    \$\begingroup\$ Quick tips for 10 bytes: 1) Replace && and || with & and |. 2) Move int declarations into the for (for(int i=0,j,x,z;...). 3) You have one too many braces at the end of your golfed function. \$\endgroup\$
    – Geobits
    Commented Jun 24, 2015 at 17:50
  • 4
    \$\begingroup\$ You have a lot of comparisons of the form a+1<=b+1; they can be replaced by a<=b. \$\endgroup\$
    – Zgarb
    Commented Jun 24, 2015 at 17:51
  • 2
    \$\begingroup\$ q*q+1 should probably just be assigned to another variable. You use it 9 times or so, and you could save a bunch by saying a=q*q+1 once. Also, q*(q+1) is just q*q+q. \$\endgroup\$
    – Geobits
    Commented Jun 24, 2015 at 18:04
  • \$\begingroup\$ I was just doing that Geobits and Zgarb, thanks for the suggestions! \$\endgroup\$
    – cmxu
    Commented Jun 24, 2015 at 18:06
  • \$\begingroup\$ You could look for a recursive solution, maybe? It looks like there should be a nice one. \$\endgroup\$
    – mbomb007
    Commented Jun 24, 2015 at 18:50
5
\$\begingroup\$

Python 2, 144 128 bytes

n=input()
i=n*n
while-~i:j=x=1;l="";exec'y=i%j<1;z=i>j*j;l+=j*z*" "or"|+"[x|y]+" -"[y]*~-j;x=y^z>z;j+=1;'*n;print l+"|+"[x];i-=1

Bit twiddling. Bit twiddling everywhere.

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

Python, 188 bytes

Mathematically calculates the character at each x,y position. It was tricky making the +s print on both sides of each box as well as stopping the rightmost +s of what would be n+1th boxes.

n=input();l=1;c=0
for y in range(n*n,-1,-1):
 s=""
 for x in range((n*n+n)/2+1):k=((8*x+1)**.5+1)/2;i=int(k);b=y<=i**2;s+=" |-+"[((k==i)+2*((y%l+c)*(y%i+(k==n+1))<1))*b];l=i;c=b^1
 print s
\$\endgroup\$
8
  • \$\begingroup\$ what does (8*x+1)**.5+1 do ? \$\endgroup\$
    – Abr001am
    Commented Jun 24, 2015 at 21:32
  • \$\begingroup\$ @Agawa001 Looks like an inverse triangle function. \$\endgroup\$
    – Geobits
    Commented Jun 24, 2015 at 21:36
  • \$\begingroup\$ @Geobits Beat me to answering what my own code does! \$\endgroup\$
    – KSab
    Commented Jun 24, 2015 at 21:37
  • \$\begingroup\$ @Geobits yea i was thinkin of something like floor$sqrt(2*n-sqrt(2*n))$ , \$\endgroup\$
    – Abr001am
    Commented Jun 24, 2015 at 21:39
  • 1
    \$\begingroup\$ @ThomasWeller python will automatically convert that to a long which has no upper limit. \$\endgroup\$
    – KSab
    Commented Jun 24, 2015 at 23:54
1
\$\begingroup\$

C# - 304 bytes (function)

void b(int s){int h=s*s,w=h+s>>1,x,y,j;var c=new int[w+1,h+1];for(;s>0;s--){for(y=s*s-s;y>=0;y-=s){x=s*s-s>>1;for(j=0;j<s;){c[x+j,y]=c[x+j,y+s]=13;c[x,y+j]=c[x+s,y+j++]=92;}c[x,y]=c[x+s,y]=c[x+s,y+s]=c[x,y+s]=11;}}for(y=h;y>=0;y--){for(x=0;x<=w;x++)Console.Write((char)(32+c[x,y]));Console.WriteLine();}}

or 363 bytes (full code)

namespace System{class C{static void Main(string[]a){int s=int.Parse(a[0]),h=s*s,w=h+s>>1,x,y,j;var c=new int[w+1,h+1];for(;s>0;s--){for(y=s*s-s;y>=0;y-=s){x=s*s-s>>1;for(j=0;j<s;){c[x+j,y]=c[x+j,y+s]=13;c[x,y+j]=c[x+s,y+j++]=92;}c[x,y]=c[x+s,y]=c[x+s,y+s]=c[x,y+s]=11;}}for(y=h;y>=0;y--){for(x=0;x<=w;x++)Console.Write((char)(32+c[x,y]));Console.WriteLine();}}}}

I tried to avoid if statements. Ungolfed:

namespace N
{
    public class Explained
    {
        static void boxes(string[] args)
        {
            int size = int.Parse(args[0]);
            int height = size * size + 1;
            int width = size * (size + 1) / 2 + 1;
            var canvas = new int[width, height];
            for (; size > 0; size--)
                drawboxes(size, canvas);

            for (int y = height - 1; y >= 0; y--)
            {
                for (int x = 0; x < width; x++)
                    Console.Write((char)(32 + canvas[x, y]));
                Console.WriteLine();
            }
        }

        static void drawboxes(int size, int[,] canvas)
        {
            int x = size * (size - 1) / 2;
            for (int i = size - 1; i >= 0; i--)
            {
                drawbox(x, i * size, size, canvas);
            }
        }

        static void drawbox(int x, int y, int size, int[,] canvas)
        {
            for (int i = 0; i < size; i++)
            {
                canvas[x + i, y] = 13; // +32 = '-'
                canvas[x + i, y + size] = 13;
                canvas[x, y + i] = 92; // +32 = '|'
                canvas[x + size, y + i] = 92;
            }
            canvas[x, y] = 11; // +32 = '+'
            canvas[x + size, y] = 11;
            canvas[x + size, y + size] = 11;
            canvas[x, y + size] = 11;
        }
    }
}
\$\endgroup\$
1
  • \$\begingroup\$ My solution does not work for any input of Integer range as defined by OP. I'd need to use long instead. \$\endgroup\$ Commented Jun 24, 2015 at 22:12
1
\$\begingroup\$

Ruby (205 bytes)

Takes the number as a command line arguments. It starts with a fail leading newlines, but that's allowed.

n=$*[0].to_i
m=n+1
f=m.times.inject(:+)+1
c=((" "*f+p=?+)*n*m).split p
y=0
1.upto(n){|b|(b*b+1).times{|x|d=x%b==0;r=c[x]
d&&b.times{|g|r[y+g]=?-}
r[y]=d||r[y]==p ?p:?|
r[y+b]=d ?p:?|}
y+=b}
puts c.reverse
\$\endgroup\$
1
\$\begingroup\$

JavaScript (ES6), 293 bytes

(n,o='',r,f,t,u,b,c,e=n*n+1,i)=>{for(t=0;e>t;t++){for(c=b=0,d=e-t,u=0;(n*n+n)/2+1>u;u++)i=" ",r=b*b+1,b==c?(f=b+1,d<=r&d%(0==b?1:b)==(1==b?0:1)|n>=f&d<=f*f+1&d%(0==f?1:f)==(1==f?0:1)?i="+":d<=r|n>=f&d<=f*f+1&&(i="|"),b++,c=1):(d<=r&d%(0==b?1:b)==(1==b?0:1)&&(i="-"),c++),o+=i;o+="\n"}return o}

I ran this in Firefox. Ignore the " the console adds between the strings. This is mostly ES5 stuff but I'll try to golf this more.

Ungolfed / ES5

function box(n, o, r, f, t, u, b, c, e, i) {
  if (o === undefined) o = "";
  if (e === undefined) e = n * n + 1;
  return (function() {
    for (t = 0; e > t; t++) {
      for (c = b = 0, d = e - t, u = 0;
        (n * n + n) / 2 + 1 > u; u++) i = " ", r = b * b + 1, b == c ? (f = b + 1, d <= r & d % (0 == b ? 1 : b) == (1 == b ? 0 : 1) | n >= f & d <= f * f + 1 & d % (0 == f ? 1 : f) == (1 == f ? 0 : 1) ? i = "+" : d <= r | n >= f & d <= f * f + 1 && (i = "|"), b++, c = 1) : (d <= r & d % (0 == b ? 1 : b) == (1 == b ? 0 : 1) && (i = "-"), c++), o += i;
      o += "\n";
    }
    return o;
  })();
}

document.getElementById('g').onclick = function(){ document.getElementById('o').innerHTML = box(+document.getElementById('v').value) };
<input id="v"><button id="g">Run</button><pre id="o"></pre>

\$\endgroup\$
1
\$\begingroup\$

Python 2, 294 290

I got it working, but I still need to golf it more. I'm so happy, though, that was tough (for me, at least)!

I'll probably add an explanation later, unless it's immediately clear to someone...? I kind of doubt it.

Try it here

n=input()
w=n*n+n+2>>1
a=eval(`[[' ']*w]*-~n**2`)
r=range
j=[i*i+i>>1for i in r(n+1)]
p=0
for i in r(w):
 if i in j:
    p+=p<n
    for k in r(p*p+1):a[~k][i]='+'if k%p<1or' '<a[~k][i-1]<'.'else'|'
 else:
    for k in r(p*p+1):a[~k][i]=' 'if k%p else'-'
print'\n'.join(''.join(i)for i in a)
\$\endgroup\$
0
\$\begingroup\$

Python - 243 bytes

Generates all the columns, replacing the overlaps on columns except the first one. Then it pads with spaces, transposes, and prints.

Q=input()
Y=[]
for i in range(Q):
    f="+"+i*"-"+"+";x=map(list,zip(*([f]+["|"+" "*i+"|"]*i)*(i+1)+[f]))
    if i:y=Y.pop();x[0][-len(y):]=y
    Y+=x
print"\n".join("".join(i)for i in zip(*["".join(j[::-1]).ljust(Q*Q+1," ")for j in Y])[::-1])

I am considering translating to Pyth, but I will need a replacement for the pad function.

\$\endgroup\$

Your Answer

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

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