Code Golf: Playing Cubes
Asked Answered
B

13

61

The challenge

The shortest code by character count, that will output playing bricks tower series according to user input.

The input will be a series of numbers (positive, negative and zero) that represents the height of the current cube tower following their index. A height of 0 means no tower and is spaced.

A cube tower is composed of stacked cubes. If the input number on the current index is positive, the cubes go up, if the input number is negative, the cubes go down. A single cube is drawn using the 4 following lines:

   __
 /__ /|
|   | |
|___|/

Cubes are 3D - this means they hide each other when two towers are placed next to each other, generating fake perspective.

All input can be assumed to be valid and without errors - Each number is separated with a white space on a single line, with at least one number.

Test cases

Input:
    2 -3 -2 1 2 -1
Output:
       __              __
     /__ /|          /__ /|
    |   | |        _|   | |
    |___|/|      /__|___|/|
    |   | |__  _|   |   | |__
    |___|/__ /__|___|___|/__ /|
        |   |   | |     |   | |
        |___|___|/|     |___|/
        |   |   | |
        |___|___|/
        |   | |
        |___|/

Input:
    1 2 3 4 -2 4 3 2 1
Output:
                   __      __ 
                 /__ /|  /__ /|
               _|   | | |   | |__
             /__|___|/| |___|/__ /|
           _|   |   | | |   |   | |__
         /__|___|___|/| |___|___|/__ /|
       _|   |   |   | | |   |   |   | |__
     /__|___|___|___|/| |___|___|___|/__ /|
    |   |   |   |   | |_|   |   |   |   | |
    |___|___|___|___|/__|___|___|___|___|/
                    |   | |
                    |___|/|
                    |   | |
                    |___|/

Input:
    1 3 3 7 0 -2 -2
Output:
                   __
                 /__ /|
                |   | |
                |___|/| 
                |   | | 
                |___|/| 
                |   | | 
                |___|/| 
           __  _|   | | 
         /__ /__|___|/| 
        |   |   |   | | 
        |___|___|___|/| 
       _|   |   |   | | 
     /__|___|___|___|/| 
    |   |   |   |   | |    __  __
    |___|___|___|___|/   /__ /__ /|
                        |   |   | |
                        |___|___|/|
                        |   |   | |
                        |___|___|/

Code count includes input/output (i.e full program).

Beaverette answered 22/10, 2009 at 20:15 Comment(19)
The -3 cube seemed to have lost during formatting. I am sorry for that. My draft clearly has this one. Thanks to LFSR for fixing :)Beaverette
So... very... tempted... to add an example for 1 3 7 3 3Alburnum
I've noticed a few more tiny space-related issues on the spec. Apparently SO doesn't like ASCII art :(Beaverette
@Lira: use a <pre> blockLubet
I also forgot to mention - to all of my weekly code golf fans: Next week will be a special Halloween edition code-golf!Beaverette
Is this challenge to hard? why are there no answers?Beaverette
@LiraNuna, I don't believe it's hard, just too elaborate. The whole negative thing adds a lot of code (for my solutions at least). I don't want to optimize a 600-character solution, really.Epifocal
Aww, put the negative cubes back!Bulahbulawayo
Negative cubes are back. Though bring answers so it won't look dull!Beaverette
I think your 0 example is a space off.Kadner
@Chris: Thank you! Another SO formatting issue...Beaverette
@Epifocal You have a 600 char solution to optimize? Lucky bastard. I'm starting at about 1400.Satirize
@mobrule, Surely not in perl??Gide
@gnibbler - Maybe mobrule applies good coding practices and is currently trying to shorten codeGolfCubingFunction before applying the name-shortening. :PKadner
@UK Jon Skeet is busy doing something else probably. ;-)Interpret
@mobrule, i see you managed to shave off 1214 bytes :pGide
I'm not gonna enter this one. Too stringy for a C lover.Epifocal
@strager, I thought you must be working on the golfscriptGide
@gnibbler, This is beyond my Golfscript ability. However, I have been convinced to work on a solution and will post it soon.Epifocal
S
40

Perl 157 characters

This entry was inspired by gnibbler's Ruby entry, including the part about embedding the cube in the code. Also thanks to Kinopiko for schooling me on the 4 arg version of substr.

@O=($/.$"x99)x99;map{for$n(0..$_-1,$_..-1){map{substr$O[50-2*$n+$_],$W+4/$_,6,
(_,"__"
,"/__ /|",
"|   | |",
"|___|/")[$_]}1..4}$W+=4}@ARGV;print grep/\S/,@O

Explanation:

Line 1: Choose where cubes go
Lines 2-5: Put cubes where cubes go, print

Satirize answered 22/10, 2009 at 20:15 Comment(6)
map{substr$O[-2*$n-$_],$W+$_*$_/3,(6,7,6,2)[$_],("|___|/","| | |","/__ /|","__")[$_]}0..3} gets you two more. /\S/&&print for@O[-49..49] gets you one more.Crissum
map{substr$O[-2*$n-$_],$W+($f=$_*$_)/3,6+$_-$f,("|___|/","| | |","/__ /|","__")[$_]}0..3}Crissum
Have you seen the C entry? :pBulahbulawayo
@Robert P: The C version is just a translation of this algorithm into C.Crissum
My ruby was based on my Python, so we have Python => Ruby => Perl => C :)Gide
Grats for winning this week. You're in for a scare this weekend though. ;PEpifocal
L
39

Ruby - 233

mutable strings ;) No arbitrary "99" limits. pfft :p
Had to lose the picture of the cube in the source though

S=gets.split.map{|x|x.to_i}<<0
S.max.downto(S.min){|y|e=" ";q=e*3;r=e*3
S.map{|x|a=0,x;if(w=a.min)<=y&&x!=0&&y<z=a.max
r[-3,4]="|   | |";q[-3,4]="|___|/"+(y>w ?"|":e)else(z=z!=y)?q+=e*4:q[-2,4]="/__ /|"
r+=z ?e*4:"__  "end}
puts r,q}

Ruby - 243

Delete the extra space I put in there to get the nice picture of the cube

S=gets.split.map{|x|x.to_i}<<0
S.max.downto(S.min){|y|e=" ";q=e*3;r=e*3
S.map{|x|a=0,x;if(w=a.min)<=y&&x!=0&&y<=z=a.max
if z==y;r+="__  "
 q[-2,3]="/__ /|"else
r[-3,4]="|   | |"
q[-3,4]="|___|/"+(y>w ?e:"|")end
else r+=e*4;q+=e*4 end}
puts r,q}
$ echo 1 3 7 3 3 |ruby pc.rb
           __              
         /__ /|            
        |   | |            
        |___|/|            
        |   | |            
        |___|/|            
        |   | |            
        |___|/|            
       _|   | |__  __      
     /__|___|/__ /__ /|    
    |   |   |   |   | |    
    |___|___|___|___|/|    
   _|   |   |   |   | |    
 /__|___|___|___|___|/|    
|   |   |   |   |   | |    
|___|___|___|___|___|/  
Legality answered 22/10, 2009 at 20:15 Comment(3)
I voted for the answer with 253 chars. It looks amazing with the actual cube in the solution.Interpret
OFFENSIVE! OFFENSIVE! OFFENSIVE! j/k.Beaverette
With three more strokes and a co-location facility, I could change that "99" limit to "9E9" ;-)Satirize
E
6

Befunge-93 (too many characters)

Very unoptimized. My first Befunge program. =]

>~:88+`v6 >11p>:!|v                 g13$<       v            $<
 000090#8 + >      >68*31p  v >     1-:!|!:-1g14<p+g11g13+g12g 14<
   __  :* *      5 ^       < > 31pvvp16<>:41p1- 31g1+g :68*-!#^_ ^
 /__ /||\-6      >>1-:       |^8   < $<|       `g16 $<   <
|   | |>-*8 ^ ^ p11-2g11-1$  <    >31g   11g+:::51g` |   1
|___|/   8^0     >#-#<           v    ^<             >51p^
        <  <         |`0:       p 56 p34:p30:p26:p25:p22:p21:p20:*68<
^  v95:< 6^ *2:*  -10<           >21g4+21p 11
1  >*-   |            >     > 31g51gg,31g21g-3-!#v_v
1   >$ ^v<                 | ,+55-g16p15+1:g15   <
|!-*48 <~> ^                ^           p13+1g13   <
>   ^                      @
Epifocal answered 22/10, 2009 at 20:15 Comment(4)
It might look better if you put it in a <pre> block, instead of a code block.Hilariohilarious
@Gilbert, Heh, true. =] However, SO/Markdown doesn't like the < in my answer, so...Epifocal
I was looking forward to seeing how you were going to beat my C solution with some kind of bizarre trick, and all I get is this? It looks like more a.out.Crissum
@Kinopiko, This isn't really my kind of problem. I'm redoing the Befunge solution and will hopefully have it in before the deadline (as if it mattered).Epifocal
S
6

Ruby, 261 258 250 242

c=[]
n=99
$F.map{|e|e=e.to_i
c<<(e<0?[e,-1]:[0,e-1])}
m=[]
x=0
c.map{|d|x+=4
k,l=d
(k+n..l+n).map{|y|y*=2
[[3,3,2,'__'],[2,1,6,'/__ /|'],[1,0,7,'|   | |'],[0,0,6,'|___|/']].map{|e|a,b,c,s=e
(m[y+a]||=' '*79)[x+b,c]=s}}}
puts m.compact.reverse

Run with ruby -n -a v2.rb

This entry is slightly overdesigned in that it can begin and end stacks at any level, not just at 0. There is no way to specify this in the "competition version", but if you replace the first 4 lines with c=eval $_;n=99 then it drops to 203 bytes and you can do: <

[[-3,3],[-3,-2],[2,3],[-3,-3],[-2,-1],[3,3],[2,2],[1,1],[0,0]]
           __      __          __                                                  
         /__ /|  /__ /|      /__ /|                                                
        |   | | |   | |     |   | |__                                              
        |___|/| |___|/|     |___|/__ /|                                            
        |   | | |   | |         |   | |__                                          
        |___|/| |___|/          |___|/__ /|                                        
        |   | |                     |   | |__                                      
        |___|/|                     |___|/__ /|                                    
        |   | |            __           |   | |                                    
        |___|/|          /__ /|         |___|/                                     
        |   | |__       |   | |                                                    
        |___|/__ /|     |___|/|                                                    
        |   |   | |    _|   | |                                                    
        |___|___|/|  /__|___|/                                                     
        |   |   | | |   | |                                                        
        |___|___|/  |___|/   
Supraorbital answered 22/10, 2009 at 20:15 Comment(3)
Ohh, do me a favor, render [[3,3],[1,2],[0,3],[0,7],[0,3],[0,3]]Remorseful
your version was actually my original idea, but it has a different approach which I'm reserving for another code golf challenge.Beaverette
Put your output in a <pre> block to prevent highlighting.Hilariohilarious
L
6

Python - 249

The second for loop is indented with tab

S=map(int,raw_input().split())+[0]
for y in range(max(S),min(S)-1,-1):
 q=r=e=" "*4
 for x in S:
    w=x*(x<0);z=x*(x>0)
    if w<=y<z:r=r[:-3]+"|   | |";q=q[:-3]+"|___|/"+" |"[y>w]
    elif(y==z)*x:q=q[:-2]+"/__ /|";r+="__  "
    else:q+=e;r+=e
 print r+"\n"+q

Python - 393

S=map(int,raw_input().split())+[0]
for Y in range(max(S),min(S)-1,-1):
 Q=R="";B=s=t=" "*4;N=0
 for y in S:
  if(y>0)*(y==Y)+(Y==0)*(y<0):
   q="_  _";r=" /__";s="_   ";t=" /| "
   if(N<y>0)+(N==0):q="   _"
   if y<N>0:q="| |_";r="|/__"
  elif(y>Y>=0)+(y<=Y<0):q="|   ";r="|___";s="| | ";t="|/"+("| "[(y==Y<0)+(Y==0)])+" "
  else:q=s;r=t;s=t=B
  Q+=q;R+=r;N=y
 print Q.rstrip()+"\n"+R.rstrip()
Legality answered 22/10, 2009 at 20:15 Comment(3)
The problem has changed, which will probably make your code a lot shorter.Epifocal
doh! yeah, a lot shorter and about 1/10 as hardGide
Negative cubes don't display correctly. For example, just try -1 -2Nought
L
5

Golfscript - 154

Newlines are significant. If you fail to strip the trailing newline you will get an extra number printed at the bottom! There is a TAB between - and 0

" "4*:s%{~}%0+: $):
;0=:g;{2,{:r;s {[
-   0
-]$(:b\(:t\;=!t!0t<1b>*2*+*[{s}[{"__  "}{-2<"/__ /|"}]r={-3<["|   | |""|___|/"["| "b!=]+]r=}]\=~+}%n}%
(:
g<!}do

Golfscript - 163

0`+" ":s%{~}%:A$):y;0=1-:g;{2,{:r;3s*A{[y- 0y-]$(:b\(:t\;=!:j;[{4s*}[{"__  "}{-2<"/__ /|"}]r={-3<["|   | |""|___|/"["| "b!=]+]r=}]0t=0t<1b>*2*+j*=~+}%n}%y(:y g>}do

Golfscript - 165

0`+" ":s%{~}%:A$):y;0=1-:g;{2,{:r;3s*A{[y- 0y-]$(:b\(:t\;=!:j;[
{4s*}.{"__  "
}{-2<"/__ /|"}
{-3<"|   | |"}
{-3<"|___|/"["| "b!=]+}]0t=2*0t<1b>*4*+r+j*=~+}%n}%y(:y g>}do
Legality answered 22/10, 2009 at 20:15 Comment(0)
I
5

Haskell, 349 characters:

r=replicate
f=foldl
k=repeat
o n a s=r n a++s++k a
main=do{a<-getLine;let{n=map read$words a;u=f max 0 n;d=f min 0 n;i=r(2*(1+u-d))$r(4*length n+3)' '};putStr$unlines$f(\j(x,n)->f(\i y->[[if a=='x'then b else a|(a,b)<-zip m n]|(m,n)<-zip(o(2*(u-y))(k 'x')$map(o(4*x)'x')["xxx__xx","x/__ /|","|   | |","|___|/x"])i])j[1+min 0 n..max 0 n])i$zip[0..]n}
Idolah answered 22/10, 2009 at 20:15 Comment(0)
S
4

C, 287 characters

#define F(r)for(r=0;r<98;r++)
#define C(y,s)for(k=0;s[k];k++)b[49-i][w+k+y]=s[k];i++;
char k,i,j,w,t,b[98][99];main(c,v)char**v;{F(i)F(j)b[i][j]=32;
for(j=0;j<c;j++){i=2*atoi(v[j]);t=0;if(i>0)t=i,i=0;for(;i<t;i-=2){
C(0,"|___|/")C(0,"|   | |")C(1,"/__ /|")C(3,"__")}w+=4;}F(i)puts(b[i]);}

(this character count excludes two newlines)

This runs as a command line program, like

./cubes 1 2 3 4 5 0 1 3 2 -1 -10

You can try running it here: http://codepad.org/tu4HDqSy (This version is altered because codepad.org doesn't allow command line arguments.)

A handy tip for un-golfing is to run it through cpp and then indent:

char                k        , i, j, w, t, b[98][99];
main(c, v)
    char          **v;
{
    for (i = 0; i < 98; i++)
        for (j = 0; j < 98; j++)
            b[i][j] = 32;
    for (j = 0; j < c; j++) {
        i = 2 * atoi(v[j]);
        t = 0;
        if (i > 0)
            t = i, i = 0;
        for (; i < t; i -= 2) {
            for (k = 0; "|___|/"[k]; k++)
                b[49 - i][w + k + 0] = "|___|/"[k];
            i++;
            for (k = 0; "|   | |"[k]; k++)
                b[49 - i][w + k + 0] = "|   | |"[k];
            i++;
            for (k = 0; "/__ /|"[k]; k++)
                b[49 - i][w + k + 1] = "/__ /|"[k];
            i++;
            for (k = 0; "__"[k]; k++)
                b[49 - i][w + k + 3] = "__"[k];
            i++;
        } w += 4;
    } for (i = 0; i < 98; i++)
        puts(b[i]);
}
Sioux answered 22/10, 2009 at 20:15 Comment(7)
Static-initialized elements are default zero, so ={} is superfluous. Using the pre-ANSI main(c,v)char**v;{} prototype shaves off two characters. Pretty clever, though! I wish I could find more to cut...Joiejoin
I get double spaced output on GCC 4.4.1.Beaverette
Are you sure it isn't just the line wrap? If your terminal is less than 98 characters wide it wraps around. My gcc is gcc version 4.2.1 20070719 [FreeBSD].Crissum
Ah, my terminal is a standard 80x24 in size. I think you need to specify it to whoever's testing :).Beaverette
@Kinopiko: yes, I can resize my terminal, that's not the problem - the entry does not specify that it needs it, so I had no idea that this solutions outputs a static 98x98 buffer.Beaverette
Since I'm not doing a C solution myself I'll help you with yours. =] Replace if(i>0)t=i,i=0;for(; with for(i>0?t=i,i=0:0;. For your C macro, remove "" from use and use #s instead of s. Remove i=2*atoi(v[j]) and char**v; and replace for(j=0;j<c;j++){t=0; with for(;scanf("%d",&i);t=0){i*=2; This will read the numbers from stdin. You can now reuse any parameters to main. (You will probably use i as a parameter to main because it has to be an int.) Your init loop can be written as a single loop with a pointer (not sure if it helps in code size).Epifocal
Thanks for the ideas though. I'll try using them next time.Crissum
P
3

Python (2.6), 1092 905 623 501 478 345 --> 318 characters

All comments welcome!

r=range;p="  __","/__ /|","|   | |","|___|/"
l=map(int,raw_input().split())+[0];d=max(l)
g=[[" "]*(len(l)+1)*4 for i in r(d-min(l)+1)*2]
for i,e in enumerate(l):
 for x,y in sorted([(i*4,(d-e+y-(0,1)[e<0])*2)for y in r(0,e,(1,-1)[e<0])])[::-1]:
  for i in r(4):g[y+i][(x,x+1)[i<2]:x+6]=p[i]
for k in g:print ''.join(k)
Pileup answered 22/10, 2009 at 20:15 Comment(0)
L
2

627 bytes of VB.NET 9 (without counting new lines)

Dim a As New List(Of Int32)
Dim b=InputBox("").Split(" ".ToCharArray)
For Each d In b
a.Add(Int32.Parse(d))
Next
Dim e=New String(){"|___|/","|   | |","/__ /|","__"}
Dim f=a.Min
Dim g=a.Max
Dim h=a.Count
Dim i As New List(Of String)
Dim j=(If(g>0,g,0)+If(f<0,-f,0))*2+1
For d=0To j
i.Add(Space(h*6))
Next
For d=f To g
If (d<>0) Then
For k=0To 3
Dim l=i(j)
Dim m=0
While m<h
If (d<0And a(m)<=d)Or(d>0And a(m)>=d) Then
Dim n=m*4+If(k>1,(k-2)*2+1,0)
l=l.Substring(0,n)&e(k)&l.Substring(n+e(k).Length)
i(j)=l
endif
m+=1
End While
j-=1
Next
j+=2
EndIf
Next
For Each d In i
Console.WriteLine(d)
Next
Lenzi answered 22/10, 2009 at 20:15 Comment(0)
M
1

PHP - 447 398

I Know it's not as short as the others here, but I'm happy with it ;)

<?$g=$argv;unset($g[0]);$c=array('|___|/',' '=>'|   | |','/__ 
/|',3=>'__');$x=max(max($g),0);$m=$i=min(min($g),0);$row=$y=0;
while($x>=$i){$n=$row++*2;foreach ($c as $w=>$p){
$L[]=str_pad('',count($g)*4," ");$t='';$y=0;foreach ($g as $h)
{if((($h>=$i&&$i>0)||($h<$i&&$i<=0)))$L[$n]=substr_replace($L[$n],$p,4*$y+$w,
strlen($p));$y++;}$n++;}$i++;}array_splice($L,$n);krsort($L);
print implode("\n",$L);?>

Input / Output

   C:\development\code-golf>php cubes1.php 1 2 1 -5 -5 4 3 3
                       __
                     /__ /|
                    |   | |__  __
                    |___|/__ /__ /|
       __           |   |   |   | |
     /__ /|         |___|___|___|/|
   _|   | |__       |   |   |   | |
 /__|___|/__ /|     |___|___|___|/|
|   |   |   | |__  _|   |   |   | |
|___|___|___|/__ /__|___|___|___|/
            |   |   | |
            |___|___|/|
            |   |   | |
            |___|___|/|
            |   |   | |
            |___|___|/|
            |   |   | |
            |___|___|/|
            |   |   | |
            |___|___|/
Milli answered 22/10, 2009 at 20:15 Comment(1)
input is separated by spaces, not commas.Beaverette
E
1

313 bytes of Ruby

c=gets.split.map{|n|n.to_i}+[0];l=[" "*(c.length*5)]*((c.max-c.min)*2+2)
c.each_index{|i|h=c[i];h==0&&next
(h<0?(h...0):(0...h)).to_a.each{|b|y=c.max*2+1-b*2;x=i*4;s=(x+7)..-1
4.times{|a|l[y-a]=l[y-a][0,x+[0,0,1,3][a]]+['|___|/','|   | |','/__ /|','__'
][a]+(l[y-a][[(x+6)..-1,s,s,s][a]]||'')}}};l.each{|e|puts e}

(There is one newline that doesn't count, it's only there because otherwise there would be a very long line in there.)

I used the obvious method of making a 2D array of characters and pasting in the cubes one at a time, bottom to top and left to right.

Enjambement answered 22/10, 2009 at 20:15 Comment(0)
C
1

Lua, 453 characters

s=io.read("*l")x={}for v in s:gmatch("-?%d+")do x[#x+1]=tonumber(v)end m=math
u=unpack s=string c={s.byte("   __   /__ /||###|#||___|/ ",1,28)}t=m.max(0,u(x))-1
b=m.min(0,u(x))l=#x*4+3 a={}for n=b,t do for p,v in ipairs(x)do y=n<0 and v<=n
or n>=0 and v>n for i=1,4 do e=(t-n)*2+i a[e]=a[e]or{}for j=1,7 do
d=c[(i-1)*7+j]f=(p-1)*4+j a[e][f]=y and d~=32 and d or a[e][f] or 32 end
end end end for i,v in ipairs(a)do print((s.char(u(v)):gsub("#"," ")))end
Carlist answered 22/10, 2009 at 20:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.