# Print ASCII Voxels

Write a program that reads a $$\n\times n \times n\$$ array of binary values which represent an $$\n\times n \times n\$$ cube, that consists of $$\n^3\$$ smaller cubes. Each value says whether there is a voxel (small cube) present in the given position or not. The program must output the given array as an ASCII graphic (that means output through console or writing to a file).

### Examples

Let us consider the following $$\2\times 2\times 2\$$ arrays:

[
[[0,0],
[1,0]]
[[1,1],
[1,0]],
]

[
[[0,0],
[0,0]]
[[1,1],
[1,1]],
]


In this case the output should look like this (it does not look as good here as it does in code editors/consoles with less vertical space):

  +----+
/    /|-+----+
+----+ |     /|
|    | +----+ |
|    | |    | +
+    + |    |/
|    | +----+
|    |/
+----+

+----+----+
/         /|
+         + |
/         /  +
+----+----+  /
|         | +
|         |/
+----+----+


An example for a $$\12\times 12\times 12\$$ input string can be found here (pastebin). A new example for a $$\7\times 7\times 7\$$ input string can be found here.

### Specifications of the ASCII

Each corner of a voxel is represented by a + as long as there is any edge leading to it. The + are also drawn when there is a straight edge that is more than one unit long. There are three types of edges: The horizontal left to right ----, the horizontal back to front / and the vertical

|
|


Each of those has to end in a + (as long visible). The edges will not be drawn when they subdivide one planar plane into two or more pieces (unlike the + in relation to the edges as stated above). Structures that are hidden behind others must not be drawn.

The 'drawing' is basically a parallel projection so only top, right and front sides are visible - always from the same angle.

### Details

The code must be working for inputs of size $$\n=1,2,\ldots,12\$$. Trailing spaces and unnecessary newlines before/after are allowed (so you could write a code that always basically outputs the $$\12\times 12\times 12\$$ grid even when the actual size of the drawing is only $$\3\times 3\times 3\$$ or so).

Input formatting and method is up to you, you can use csv, JSON or any other stuff, but it has to consist of $$\1\$$ and $$\0\$$ for the state of each voxel. The order must be as in the examples:

• 1st dimension: layer by layer from the uppermost to the lowermost
• 2nd dimension: row by row back (furthest away) to front (nearest)
• 3rd dimension: voxels in each row left to right

Whether you use console or reading files as input and output is up to you. Please tell us about your code / how you approached it.

### Judging

This is codegolf so the fewest number of bytes wins. This includes ONLY the part that actually does the work - when counting bytes you can consider the input already as parsed and saved in a variable and you have to have the output string saved to a variable, ready to be printed. The parsing and the output itself does not count.

(And I will upvote submissions with creative examples=)

This was inspired by Rob's Puzzle page.

# Python ( 444 361 354 bytes)

Edit: I found another bug that would omit a corner cross in very special cases. A straight forward fix added 50 bytes to the code so I tried to golf it down a bit further. Now the bug is fixed and it's even 83 bytes shorter. It's becoming very hacky. I also wanted to get rid of the fivefold for loop but could not yet find a solution. Any ideas?

Edit 2: With a very long import I can save another 7 characters.

Neither very short nor very elegant, but then again it is a complex problem:

#input:
u=[[[1,1,1],[1,0,1],[1,1,1]],
[[1,0,1],[0,0,0],[1,0,1]],
[[1,1,1],[1,0,1],[1,1,1]]]

#actual code that counts:
r=range
n=len(u)
g=r(n)
a=([' ']*9*n+['\n'])*6*n
t='/|-+\n '
d=dict(zip(t+'%!=*',2*t))
for y,z,x,i,j in __import__('itertools').product(g,g,g[::-1],r(6),r(8)):
if abs(i+j-6)<5*u[x][y][z]:a[(9*n+1)*(i+3*x+2*y)+j+5*z-2*y+2*n]+='./    %|+====* ||    ! *|    !/.*----+'[8*i+j-8]
o=''.join((d[x[-1]],' ')[x[-2:]in('%/','!|','=-')or x[-4:]=='*++*']for x in a)

#output:
print o


It first draws all the individual voxels with all lines on top of each other. Then it outputs only the topmost characters and gets rid of those lines and crosses on planar planes that should not be drawn according to the specs.

I guess it's possible to golf this down quite some more, but 444 is such a nice number. :)

Example 3x3x3 and 7x7x7 output (with some newlines removed):

        +----+----+----+
/              /|
+    +----+    + |
/    /|   /    /  +
+    +----+    +   |
/              /  + |
+----+----+----+  /| +
|              | + | |
|              | |-+ |
+    +----+    + |/  +
|    | +--|    | +  /
|    |/   |    |   +
+    +----+    +  /
|              | +
|              |/
+----+----+----+

+----+----+----+    +----+----+----+
/              /|   /              /|
+    +----+    + |  +    +----+    + |
/    /|   /    /  + /    /|   /    /  +
+    + |  +    +  / +    + |  +    +  /
/    /  +-/    /  + /    /  +-/    /  +
+----+  /-+----+  /-+----+  /-+----+  /--+
|    | +  |    | +  |    | +  |    | +  /|
+----+ | |+----+ | |+----+ | |+----+ | | + |
/    /| + /    /| + /    /| + /    /| + |/  +
+    + | |+    + | |+    + | |+    + | | +   |
/    /  + /    /  + /    /  + /    /  + |   + |
+    +----+    +   |+    +----+    +   | +  /| +
/              /  + /              /  + | | + | |
+----+----+----+  /|+----+----+----+  /| + |/--+ |
|              | + ||              | + | |-+  /  +
|              |/--+|              |/--+ |   +  /
+----+----+----+  / +----+----+----+  /  +  /  +
+    +  / +    +--- +    +  /-+    +  /--+  /--+
/    /  + /              /  + /    /  +   | +  /|
+----+  / +----+----+----+  /-+----+  /--+ |/  + |
|    | +  |              | +  |    | +  /|-+  /  +
|    | |-+|              |/  +|    | | + |   +  /
+    + |  +----+----+----+  /|+    + |/  +  /  +
|    | +----+----+ | |+    + ||    | +  /--+  /
|    |/         /| + /    /  +|    |   +   | +
+    +----+----+ | |+----+  /-+    +  /--+ |/
|              | + ||    | +  |    | +  /|-+
|              | | +|    | | +|    |/  + |
+----+----+    + | |+    + |/|+----+  /  +
+    +--|    | + ||    | + |  +    +  /
/        |    | |-+|    |   +-/    /  +
+----+----+    + |  +    +  / +----+  /
|              | +  |    | +  |    | +
|              |/   |    |/   |    |/
+----+----+----+    +----+    +----+

• Nice job! Very compact compared to my mess. Check your concave edges though! (missing plus signs) - repl.it/XA9/2 – PiGuy Aug 17 '14 at 21:05
• @PiGuy: Good catch! I think I fixed it. It made my code a bit longer but I also found some things golf further, so I'm magically still at the same byte count. – Emil Aug 17 '14 at 22:14
• It seems there is one '+' too much on the closer '4'. (Can you also try the 7x7x7 one I posted?) – flawr Aug 17 '14 at 22:18
• @flawr: That plus sign belongs to the far 4 (far lower right corner) so it should be right. :) I'll add the 7x7x7 case. I first left it out because I thought it would clutter this page if everybody posts it, but I guess that's fine. – Emil Aug 17 '14 at 22:25
• Ah now I see - I think I was tricked by the big vertical spaces. – flawr Aug 17 '14 at 22:32

# Lua (1442 bytes)

Bonus animations! :)
If you have any cool voxel art in the same format as the examples, link it in the comments and I'll make an animation out of it
7x7x7

12x12x12

This is my first code golf, so its quite messy and I plan on improving it or porting it to a different language.
Here is what i have, right now at just under 2.5kB barely-golfed (just removed indentation whitespace at this point, I will continue more later)

Here is the now ~1.4kB golfed and minified version (note the "a" table on the first line is the placeholder for the voxel matrix):

local a={}
local b,c=table,string;local d,e,f,g,h,i=b.concat,#a,c.gsub,c.gmatch,ipairs,b.insert;local function j(k,l,m)return a[k]and a[k][l]and a[k][l][m]==1 end;local n={}for o=1,e*5+1 do n[o]={}for p=1,e*7+1 do n[o][p]=" "end end;local q=[[
__6hhhh7
_g    ij
1aaaa2 j
b    d 5
b    de_
3cccc4__
]]local function r(k,l,m)local s=q;if j(k,l,m)then local t,u,v,w,x,y,z,A=j(k-1,l,m),j(k+1,l,m),j(k,l,m-1),j(k,l,m+1),j(k,l-1,m),j(k+1,l+1,m),j(k+1,l,m+1)," "if t then s=f(s,"[ai]"," ")end;if u and not y then A=A.."c"end;if u and not z then A=A.."e"end;if v then A=A.."bg"end;if w then A=A.."di"end;if x then if not j(k,l-1,m+1)then A=A.."j"end;A=A.."h"end;if t then if w and j(k-1,l,m+1)then A=A.."2"end;if v and j(k-1,l,m-1)then A=A.."1"end end;if u then if w and j(k+1,l,m+1)then A=A.."4"end;if v and j(k+1,l,m-1)then A=A.."3"end end;if x then if w and j(k,l-1,m+1)then A=A.."7"end;if v and j(k,l-1,m-1)then A=A.."6"end;if u and j(k+1,l-1,m)then A=A.."5"end end;s=f(f(f(f(f(s,"["..A.."]"," "),"[ach]","-"),"[bdj]","|"),"[gie]","/"),"[1234567]","+")else s=nil end;return s end;local B,C;local D=e*2-1;local E=1;for k=e,1,-1 do for l=1,e do for m=1,e do B=(l-1)*-2+(m-1)*5+D;C=(l-1)*2+(k-1)*3+E;local s=r(k,l,m)if s then local F={}for G in s:gmatch("[^\n]+")do local H={}for I in G:gmatch(".")do i(H,I)end;i(F,H)end;for J,K in h(F)do for L,I in h(K)do if I~="_"then n[C+J-1][B+L-1]=I end end end end end end end;for o,a in h(n)do print(d(a))end


Edit: Here is the original (over 3kB) ungolfed version, including my edits for making the animation (if you are running it yourself and want the animation, change the false near the bottom of the code to true.

local v = {}
local depth = #v;

function voxel(y,z,x)
return (v[y] and v[y][z] and v[y][z][x]==1)
end

local canvas = {}
print("Constructing canvas of depth",depth)
for i=1,depth*5+1 do
canvas[i] = {}
for j=1,depth*7+1 do
canvas[i][j] = " "
end
end

local voxelProto = [[
__6hhhh7
_g    ij
1aaaa2 j
b    d 5
b    de_
3cccc4__
]]

function renderVoxel(y,z,x)
local vox = voxelProto
if (voxel(y,z,x)) then
local up = voxel(y-1,z,x)
local down = voxel(y+1,z,x)
local left = voxel(y,z,x-1)
local right = voxel(y,z,x+1)
local back = voxel(y,z-1,x)
local downFront = voxel(y+1,z+1,x)
local downRight = voxel(y+1,z,x+1)

if (up) then
vox = vox:gsub("[ai]"," ")
end
if (down and not downFront) then
vox = vox:gsub("[c]"," ")
end
if (down and not downRight) then
vox = vox:gsub("[e]"," ")
end
if (left) then
vox = vox:gsub("[bg]"," ")
end
if (right) then
vox = vox:gsub("[di]"," ")
end
if (back and not voxel(y,z-1,x+1)) then
vox = vox:gsub("[j]"," ")
end
if (back or up) then
vox = vox:gsub("[h]"," ")
end
if (up and right and voxel(y-1,z,x+1)) then
vox = vox:gsub("[2]"," ")
end
if (up and left and voxel(y-1,z,x-1)) then
vox = vox:gsub("[1]"," ")
end
if (down and right and voxel(y+1,z,x+1)) then
vox = vox:gsub("[4]"," ")
end
if (down and left and voxel(y+1,z,x-1)) then
vox = vox:gsub("[3]"," ")
end
if (back and right and voxel(y,z-1,x+1)) then
vox = vox:gsub("[7]"," ")
end
if (back and left and voxel(y,z-1,x-1)) then
vox = vox:gsub("[6]"," ")
end
if (back and down and voxel(y+1,z-1,x)) then
vox = vox:gsub("[5]"," ")
end

vox = vox:gsub("[ach]","-")
vox = vox:gsub("[bdj]","|")
vox = vox:gsub("[gie]","/")
vox = vox:gsub("[1234567]","+")
else
vox = nil
end
return vox
end
local xpos,ypos
local minx = depth*2-1
local miny = 1;

local pic = {}
function drawCanvas()
for k,v in pairs(canvas) do
pic[k] = table.concat(v)
end
return table.concat(pic,"\n")
end

local timeline = {}
print("Compositing voxels")
for y=depth,1,-1 do
for z=1,depth do
for x = 1,depth do
xpos = (z-1)*-2 + (x-1)*5 + minx
ypos = (z-1)*2 + (y-1)*3 + miny
local vox = renderVoxel(y,z,x)
if (vox) then
local vt = {}
for line in vox:gmatch("[^\n]+") do
local vtl = {}
for c in line:gmatch(".") do
table.insert(vtl,c)
end
table.insert(vt,vtl)
end
for ly,chars in ipairs(vt) do
for lx,c in ipairs(chars) do
if (c ~= "_") then
canvas[ypos+ly-1][xpos+lx-1] = c
end
end
end
table.insert(timeline,drawCanvas())
end
end
end
end

if (false) then -- change to true if you want to see the animation!
for i=1,#timeline do
local t = os.clock() + 0.05
io.write(timeline[i],'\n\n')
io.flush()
while (t > os.clock()) do end
end
end
print(timeline[#timeline])


Here is a sample of code that will populate the voxel matrix from a string for a 3x3x3 voxel matrix. (It will take any string in a similar format, but make sure it is a cube or things will probably break.)
To use this, insert this chunk right after the first line local v = {}

local vs = [[
100
000
000

110
100
000

111
110
101
]]
for layer in vs:gmatch("[^a]+") do
local a = {}
for row in layer:gmatch("[^\n]+") do
local b = {}
for _vox in row:gmatch("[01]") do
table.insert(b,(_vox=="1") and 1 or 0)
end
table.insert(a,b)
end
table.insert(v,a)
end


Here is the output from the given 12x12x12 voxel pattern: (and yes it does look better on a normal console/text viewing apparatus, there is a bit too much vertical spacing here)

                                                                          +----+----+
/         /|
+----+----+ |
|         | +
+----+      |         |/
/    /|      +    +----+
+----+ |      |    | +----+
|    | +      |    |/    /|
|    | |      +    +----+ |
+    + |      |         | +
+----+----+                         +----+--|    | +      |         |/
/         /|                        /        |    | |      +    +----+
+----+----+ |                       +----+----+    + |      |    | +----+
|         | +                       |              | +      |    |/    /|
|         |/       +----+----+----+ |              | |      +    +----+ |
+    +----+       /              /| +    +----+    + |      |         | +
|    | +         +----+----+----+ | |    | +--|    | +      |         |/
|    | |         |              | + |    |/   |    | |      +----+----+
+    + |         |              | | +    +----+    + |
|    | +         +    +----+    + | |              | +
|    | |         |    | +--|    | + |              |/
+    + |         |    |/   |    | | +----+----+----+
|    | +----+    +    +----+    + |
|    |/    /|    |              | +
+    +----+ |    |              |/
|         | +    +----+----+----+
|         |/
+----+----+                                       +----+----+
/         /|
+----+    +----+----+ |
/    /|    |         | +
+----+ |    |         |/
|    | +    +    +----+
+----+----+----+  +----+----+----+----+---|    | |---+|    | +----+-+----+----+
/              /| /                        +    + |    |    |/    /|          /|
+----+----+----+ |+                         |    | +    +    +----+ |         + |
|              | +                          |    | |    |         | +        /  +
|              | |      +----+----+----+    +    + |    |         |/        +  /
+    +----+    + |     /              /|    |    | +    +    +----+        /  +
|    | +--|    | +    +----+----+----+ |    |    | |    |    | +          +  /
|    |/   |    | |    |              | +    +    + |    |    | |         /  +
+    +----+    + |    |              | |    |    | +    +    + |        +  /
|              | +    +    +----+    + |    |    | |    |    | +       /  +
|              | |    |    | +--|    | +    +    + |    |    |/       +  /
+----+----+    + |    |    |/   |    | |    |    | +    +----+       /  +
+----+--|    | +    +    +----+    + |    |    |/                 +  /
/        |    | |    |              | +    +----+                 /  +
+----+----+    + |    |              |/                           +  /
|              | +    +----+----+----+                           /  +
|              |/                                               +  /
+----+----+----+                                               /  +
+                                                           +  /
/                                                           /  +
+                                                           +  /
/                                                           /  +
+                                                           +  /
/                                                           /  +
+----+----+----+----+----+----+----+----+----+----+----+----+  /
|                                                           | +
|                                                           |/
+----+----+----+----+----+----+----+----+----+----+----+----+


Here is the output from the 7x7x7 example here

              +----+----+----+    +----+----+----+
/              /|   /              /|
+    +----+    + |  +    +----+    + |
/    /|   /    /  + /    /|   /    /  +
+    + |  +    +  / +    + |  +    +  /
/    /  +-/    /  + /    /  +-/    /  +
+----+  /-+----+  /-+----+  /-+----+  /--+
|    | +  |    | +  |    | +  |    | +  /|
+----+ | |+----+ | |+----+ | |+----+ | | + |
/    /| + /    /| + /    /| + /    /| + |/  +
+    + | |+    + | |+    + | |+    + | | +   |
/    /  + /    /  + /    /  + /    /  + |   + |
+    +----+    +   |+    +----+    +   | +  /| +
/              /  + /              /  + | | + | |
+----+----+----+  /|+----+----+----+  /| + |/--+ |
|              | + ||              | + | |-+  /  +
|              |/--+|              |/--+ |   +  /
+----+----+----+  / +----+----+----+  /  +  /  +
+    +  / +    +----+    +  /-+    +  /--+  /--+
/    /  + /              /  + /    /  +   | +  /|
+----+  / +----+----+----+  /-+----+  /--+ |/  + |
|    | +  |              | +  |    | +  /|-+  /  +
|    | |-+|              |/  +|    | | + |   +  /
+    + |  +----+----+----+  /|+    + |/  +  /  +
|    | +----+----+ | |+    + ||    | +  /--+  /
|    |/         /| + /    /  +|    |   +   | +
+    +----+----+ | |+----+  /-+    +  /--+ |/
|              | + ||    | +  |    | +  /|-+
|              | | +|    | | +|    |/  + |
+----+----+    + | |+    + |/|+----+  /  +
+    +--|    | + ||    | + |  +    +  /
/        |    | |-+|    |   +-/    /  +
+----+----+    + |  +    +  / +----+  /
|              | +  |    | +  |    | +
|              |/   |    |/   |    |/
+----+----+----+    +----+    +----+

• Wow, looks great=) Could you also include the parsing/output code even though it does not count - just so that non-luaners can reproduce your results=) – flawr Aug 17 '14 at 11:09
• I included a new example, would be great if you could include that too=) – flawr Aug 17 '14 at 15:41
• Updated with the new 7x7x7 sample, also added the snippet for generating the table from the pastebin strings. – PiGuy Aug 17 '14 at 16:51
• @7x7x7: It seems your program does not draw concave vertical edges. Like on top of that curve on the back (further) side of the top layer. or similarly on the front (near) right side on the lowest layer. I totally love the animations! – flawr Aug 17 '14 at 22:30
• @flawr Thanks, I fixed it as well as spent some time getting the byte count down and am now below 1.5kB, and I added the full code i used for creating the animations as well. – PiGuy Aug 18 '14 at 0:08