90
\$\begingroup\$

Challenge

Write a program that takes an 11x11 array of integers, and constructs a 3D ASCII block building, where each value in the array represents the height of a column of blocks at the coordinates matching the array position. A negative height is a "floating" column - only the top block is visible.

Example

 __________________
 ___ /\__\__\__\__\__\__\
 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /\__\ /\/\__\__\__\__\__\__\
 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /\/__/ /\/\/__/__/__/__/__/__/
 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /\/\__\ /\/\/\__\ /\/\/__/
 1, 0, 0, 7,-7,-7,-7,-7, 7, 0, 0, \/\/\__\ /\/\/\/__/ /\/\/__/
 0, 0, 0, 7,-7,-7,-7,-7, 7, 0, 0, \/\/__/ /\/\/\/\__\ /\/\/__/
 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, \/\__\ /\/\/\/\/__/ /\/\/__/
 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, \/__/ \/\/\/\/\__\_ \/\/__/
 1, 0, 0, 4, 3, 2, 1, 0, 0, 0, 1, \/\/\/\/__/_\_ \/__/
 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, ___ \/\/\/__/__/_\_ ___
 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /\__\ \/\/__/__/__/_\ /\__\
 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, \/\__\ \/__/__/__/__/ \/\__\
 \/\__\_________ ______\/\__\
 \/\__\__\__\__\ /\__\__\__\__\
 \/__/__/__/__/ \/__/__/__/__/

Input

The input will be a list of 121 integers, either read from stdin (choice of separator is up to you), or passed in as an array (can be 1D or 2D).

Heights will be in the range -11 to 11.

Output

The generated building can be written to stdout, displayed directly on the screen, or returned as a newline-separated string.

Leading and trailing whitespace is allowed.

Building Rules

The shape of an individual 3D block looks like this:

 ___
/\__\
\/__/

And a 2x2x2 cube of blocks looks like this:

 ______
 /\__\__\
/\/\__\__\
\/\/__/__/
 \/__/__/

When blocks overlap, a higher block takes precedence over a lower one, blocks in front take precedence over those further back, and blocks to the left takes precedence over those to the right. The only special case is that the top line of a block should never overwrite any non-space character behind it.

The interpretation of column heights can best be explained by looking at a 2D representation from the side.

HEIGHT: 1 2 3 -3 -2 -1
 __ __
 __ |__| |__| __
 __ |__| |__| |__| __
 |__| |__| |__| |__|

Test Cases

If you want to try out your solution on a few more inputs, I've put together a couple of test cases here.

Winning

This is , so the shortest submission (in bytes) wins.

asked Jan 12, 2018 at 20:10
\$\endgroup\$
8
  • 9
    \$\begingroup\$ Ohh boy, get ready for 300+ byte solutions. Good challenge. +1 \$\endgroup\$ Commented Jan 12, 2018 at 20:11
  • 7
    \$\begingroup\$ @totallyhuman Nah, Dennis is going to have a 9-byte solution for this in 20 minutes. \$\endgroup\$ Commented Jan 12, 2018 at 20:50
  • 3
    \$\begingroup\$ Does the perspective have to be as shown with the bottom left of the input data in the foreground? The fact that this is not the first or last element of data makes it harder. Is it acceptable to either 1. keep the mapping as is and draw output with the bottom right column in the foreground or 2. draw a mirror image or 90 deg rotation of the data? Either of these would make the last data element correspond with the column in the foreground, which would be easier. \$\endgroup\$ Commented Jan 12, 2018 at 21:41
  • 3
    \$\begingroup\$ I feel inclined to use a real game engine (or part of it) to render a photo and convert it to ASCII \$\endgroup\$ Commented Jan 12, 2018 at 22:16
  • \$\begingroup\$ @LevelRiverSt That seems like a reasonable request - you can choose the order of the 121 input elements to be whatever makes the most sense for your solution, as long as your ordering is consistent. It must be possible to produce every kind of layout that can be produced with the default order. \$\endgroup\$ Commented Jan 12, 2018 at 22:24

6 Answers 6

34
\$\begingroup\$

C, (削除) 376 (削除ここまで) (削除) 350 (削除ここまで) (削除) 313 (削除ここまで) (削除) 309 (削除ここまで) 285 bytes

Thanks to @Jonathan Frech for saving four bytes!

#define F for(
char*t,G[26][67],*s;i,j,e,k,v,x,y;b(){F s="\\/__//\\__\\ ___ ";*s;--y,s+=5)F e=5;e--;*t=*s<33&*t>32?*t:s[e])t=G[y]+x+e;}f(int*M){F;e<1716;++e)G[e/66][e%66]=32;F k=0;++k<12;)F i=0;i<11;++i)F j=11;j--;v+k||b())x=i+j*3+k,y=14+i-k,(v=M[i*11+j])>=k&&b();F;++e<26;)puts(G+e);}

Try it online!

Unrolled:

#define F for(
char *t, G[26][67], *s;
i, j, e, k, v, x, y;
b()
{
 F s="\\/__//\\__\\ ___ "; *s; --y, s+=5)
 F e=5; e--; *t=*s<33&*t>32?*t:s[e])
 t = G[y]+x+e;
}
f(int*M)
{
 F; e<1716; ++e)
 G[e/66][e%66] = 32;
 F k=0; ++k<12;)
 F i=0; i<11; ++i)
 F j=11; j--; v+k||b())
 x = i+j*3+k,
 y = 14+i-k,
 (v=M[i*11+j])>=k && b();
 F; ++e<26;)
 puts(G+e);
}
answered Jan 12, 2018 at 23:01
\$\endgroup\$
12
  • \$\begingroup\$ Can 26*66 not be 1716? \$\endgroup\$ Commented Jan 12, 2018 at 23:44
  • \$\begingroup\$ @JonathanFrech Sure, I forgot about that. \$\endgroup\$ Commented Jan 12, 2018 at 23:44
  • \$\begingroup\$ *s==32 -> *s<33. \$\endgroup\$ Commented Jan 12, 2018 at 23:47
  • \$\begingroup\$ for(e=k=1;e;++k)for(e= -> for(k=1;e;++k)for(e=. \$\endgroup\$ Commented Jan 12, 2018 at 23:48
  • 1
    \$\begingroup\$ 262 bytes, I couldn't fit all test cases on the link due to the character limit, just copy them from the answer \$\endgroup\$ Commented May 29, 2023 at 18:32
25
\$\begingroup\$

Charcoal, (削除) 70 (削除ここまで) (削除) 69 (削除ここまで) 68 bytes

×ばつμ3ι−λκ≔§§θλμη¿∨=±η⊕κ‹κη¿ι"↗⊟&9κUhnI"___

Try it online! Link is to verbose version of code. Explanation:

≔E11⮌I⪪S,θ

Read the array, split each line on commas and cast to integer, but also reverse each line, since we want to draw right-to-left so that left columns overwrite right columns. (Other dimensions already have desired overwriting behaviour.)

F2F11F11F11«

Loop through i) top lines and bodies k) height l) rows m) columns. (Looping through first top lines and then bodies avoids overwriting bodies with top lines.)

×ばつμ3ι−λκ

Jump to the position of the cube.

≔§§θλμη

Fetch the height at the current row and column.

¿∨=±η⊕κ‹κη

Test whether a cube should be drawn at this height for this row and column.

¿ι"↗⊟&9κUhnI"___

Draw the body or top of the cube.

answered Jan 13, 2018 at 0:09
\$\endgroup\$
3
  • \$\begingroup\$ When I change the first 3 to a 33, I only get 11 blocks in the tower. In general towers seem to be capped at 11. How does that happen? \$\endgroup\$ Commented Jan 15, 2018 at 13:09
  • \$\begingroup\$ @Fabian I'm slightly confused that F¹¹F¹¹F¹¹ wasn't a clue... \$\endgroup\$ Commented Jan 15, 2018 at 16:06
  • \$\begingroup\$ I don't know this programming language, I just played around a bit with the TIO link. \$\endgroup\$ Commented Jan 15, 2018 at 20:30
9
\$\begingroup\$

JavaScript (ES6), (削除) 277 (削除ここまで) 251 bytes

a=>(n=55,$=f=>[...Array(n)].map((_,i)=>f(i)),S=$(_=>$(_=>' ')),n=11,$(l=>$(z=>$(y=>$(x=>(x=10-x,X=x*3+y+z,Y=y-z+n,Z=a[y][x])<=z&&Z+z+1?0:l?['/\\__\\','\\/__/'].map(s=>S[++Y].splice(X,5,...s)):S[Y].splice(X+1,3,...'___'))))),S.map(r=>r.join``).join`
`)

f=
a=>(n=55,$=f=>[...Array(n)].map((_,i)=>f(i)),S=$(_=>$(_=>' ')),n=11,$(l=>$(z=>$(y=>$(x=>(x=10-x,X=x*3+y+z,Y=y-z+n,Z=a[y][x])<=z&&Z+z+1?0:l?['/\\__\\','\\/__/'].map(s=>S[++Y].splice(X,5,...s)):S[Y].splice(X+1,3,...'___'))))),S.map(r=>r.join``).join`
`)
console.log(f([
	[3, 0, 0, 0, 0, 0, 0, 0, 0, 0, -11],
	[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
	[1, 0, 0, 7,-7,-7,-7,-7, 7, 0, 0],
	[0, 0, 0, 7,-7,-7,-7,-7, 7, 0, 0],
	[0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0],
	[0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0],
	[1, 0, 0, 4, 3, 2, 1, 0, 0, 0, 1],
	[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
	[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
	[1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 11]
]))

Saved 26 bytes from @Neil's suggestion.

Ungolfed

a=>(
 n=55,
 $=f=>[...Array(n)].map((_,i)=>f(i)),
 S=$(_=>$(_=>' ')),
 n=11,
 $(l=>
 $(z=>$(y=>$(x=>(
 x=10-x,
 X=x*3+y+z,
 Y=y-z+n,
 Z=a[y][x],
 Z<=z && Z+z+1 || (
 l
 ? ['/\\__\\','\\/__/'].map(s=>S[++Y].splice(X,5,...s))
 : S[Y].splice(X+1,3,...'___')
 )
 ))))
 ),
 S.map(r=>r.join``).join`\n`
)
answered Jan 13, 2018 at 8:59
\$\endgroup\$
2
  • 2
    \$\begingroup\$ ,$(w=>$(z=>$(y=>$(x=>(Z=a[y][x=10-x,X=x*3+y+z,Y=y-z+n,x])<=z&&Z+z+1?0:w?['/\\__\\','\\/__/'].map(s=>S[++Y].splice(X,5,...s)):S[Y].splice(X+1,3,...'___'))))), seems to save 26 bytes. \$\endgroup\$ Commented Jan 13, 2018 at 11:26
  • \$\begingroup\$ @Neil Brilliant! Drawing all the top lines first saves me the trouble of checking for non-spaces. \$\endgroup\$ Commented Jan 13, 2018 at 16:14
6
\$\begingroup\$

Python 2, 243 bytes

a=input()
s=eval(`[[' ']*55]*23`)
for h in range(7986):
 k=h%3;x=h/3%11;y=h/33%11;z=h/363%11;i=h/3993;u=y+z-x*3+30;v=y-z+10
 if~-(z>=a[y][10-x]!=~z):
	if i*k:s[v+k][u:u+5]='\//\____/\\'[k%2::2]
	if~-i:s[v][u+1+k]='_'
for l in s:print''.join(l)

Try it online!

A Python translation of Neil’s Charcoal approach.

answered Jan 13, 2018 at 14:10
\$\endgroup\$
2
  • \$\begingroup\$ Nice to see a golfed Python solution for this. My Python proof-of-concept was more than 900 bytes! \$\endgroup\$ Commented Jan 13, 2018 at 14:34
  • 3
    \$\begingroup\$ +1+k -> -~k. \$\endgroup\$ Commented Jan 13, 2018 at 16:42
5
\$\begingroup\$

APL (Dyalog Unicode), (削除) 117 (削除ここまで) (削除) 116 (削除ここまで) 112 bytesSBCS

a←23 55⍴0⋄{i←11 ×ばつ3 2⍴3-7897⊤⍨6⍴5⋄(,2 5↑i↓a)←745366⊤⍨10⍴4⋄(3⍴i↓1⌽ ̄1⊖a)⌈←1} ̈j[⍋-/↑j←⍸↑⎕↑ ̈⊂⌽1,11/⍳2]⋄' _/\'[a]

Try it online!

answered Jan 13, 2018 at 22:26
\$\endgroup\$
5
\$\begingroup\$

Tcl, 380 (削除) 409 (削除ここまで) bytes

User sergiol has been busy crunching this down very nicely:

set X [read stdin]
proc L {a b c d e s} {time {incr z
set y -1
time {incr y
set x -1
time {if {abs([set Z [lindex $::X [expr ($y+1)*11-[incr x]-1]]])==$z|$z<$Z} {set s [string repl [string repl $s [set i [expr -3*$x+57*$y-55*abs($z)+701]] $i+$b $a] [incr i $c] $i+$e $d]}} 11} 11} 12
set s}
puts [L /\\__\\ 4 56 \\/__/ 4 [L "" -1 -55 ___ 2 [string repe [string repe \ 55]\n 23]]]

Try it online!

Original Content

set xs [read stdin]
proc L {a b c d e s} {set z 0
while {[incr z]<12} {set y -1
while {[incr y]<11} {set x -1
while {[incr x]<11} {set Z [lindex $::xs [expr ($y+1)*11-$x-1]]
if {abs($Z)==$z||$z<$Z} {set i [expr -3*$x+57*$y-55*abs($z)+701]
set s [string repl [string repl $s $i $i+$b $a] [incr i $c] $i+$e $d]}}}}
set s}
puts [L /\\__\\ 4 56 \\/__/ 4 [L "" -1 -55 ___ 2 [string repe [string repe \ 55]\n 23]]]

Try it online!

Alas, it is what it is. It’s only a tad easier on the eyes when "ungolfed"

set s [string repeat [string repeat " " 55]\n 23]
proc loops {s0 i0 io s1 i1} {
 set z 0; while {[incr z] < 12} {
 set y -1; while {[incr y] < 11} {
 set x -1; while {[incr x] < 11} {
 set Z [lindex $::xs [expr {($y+1) * 11 - $x - 1}]]
 if {abs($Z) == $z || $z < $Z} {
 set i [expr {-3*$x + 57*$y - 55*abs($z) + 701}]
 set ::s [string replace $::s $i $i+$i0 $s0]
 incr i $io
 set ::s [string replace $::s $i $i+$i1 $s1]
 }
 } } }
}
loops "" -1 -55 \
 ___ 2
loops /\\__\\ 4 56 \
 \\/__/ 4
puts $s

Builds a string, as per requirements. Takes the array from stdin. Goes from bottom to top, front to back, right to left over the string data. Does it in two passes, once for the top edge and again for the rest of the body of each cube.

I tried to make it smaller using some sweet functional lambda mojo, but alas, that made it larger.

sergiol
3,8441 gold badge16 silver badges36 bronze badges
answered Jan 13, 2018 at 14:20
\$\endgroup\$
9
  • \$\begingroup\$ You can golf: tio.run/… \$\endgroup\$ Commented Mar 28, 2018 at 21:55
  • \$\begingroup\$ More golfing: tio.run/… \$\endgroup\$ Commented Mar 28, 2018 at 22:03
  • \$\begingroup\$ More: tio.run/… \$\endgroup\$ Commented Mar 28, 2018 at 22:11
  • \$\begingroup\$ Yet more: tio.run/… \$\endgroup\$ Commented Mar 28, 2018 at 22:56
  • \$\begingroup\$ More yet: tio.run/##lVHtboJAEPx/… \$\endgroup\$ Commented Mar 28, 2018 at 23:00

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.