# Print a cube's vertices and its covering triangles

Output coordinates of the vertices of a cube. Then, output a list of twelve triangles that will cover the cube, each triangle being a list of three vertex-indexes, consistently oriented. Output must be an ASCII string of distinct decimal numbers. This golf has no input. Winner is the fewest characters, where the character set is Unicode.

For an example, consider a 1x1x1 cube cornered at 0,0,0. The eight vertices of the cube can be described by the following xyz coordinates on a 3d Cartesian grid:

x y z = (0,0,1) (1,0,1) (1,1,1) (0,1,1) (0,0,0) (1,0,0) (1,1,0) (0,1,0)


Each vertex can be given an index: x y z->index: 0 0 1->0, 1 0 1->1, 1 1 1->2, 0 1 1->3, 0 0 0->4, 1 0 0->5, 1 1 0->6, 0 1 0->7

Now consider the top face, vertexes indexed zero to three. The two covering triangles can be described by three indices each:

[0,1,2] [2,3,0]


Here is a picture of this top face, viewed from above the cube:

 3_____2
|    /|
|   / |
|  /  |
| /   |
0_____1


And here is a view from an angle.

    3____2
/ __-/|
0/___1 |
|    | /6
|____|/
4     5


Note the orientation, or 'winding', of both of these triangles is 'counterclockwise' when viewed from 'outside' the cube directly looking at the face in question (imagine visiting each vertex as listed, it goes counterclockwise). Now imagine this done for all six sides of the cube.

vertices: (0,0,1) (1,0,1) (1,1,1) (0,1,1) (0,0,0) (1,0,0) (1,1,0) (0,1,0)
triangles as indices: [0,1,2], [2,3,0], [6,5,4], [4,7,6],
[5,2,1], [2,5,6], [0,3,4], [4,3,7], [2,6,3], [3,6,7], [0,4,1], [1,4,5]


You can output any size of cube located at any coordinates. You can number and order the vertex coordinates however you wish. Indices can be 0 based or 1 based. The triangle's orientation can be either clockwise or counterclockwise when viewed from outside the cube as long as it is consistent for all triangles.

The output can be formatted however you wish, as long as each ASCII decimal number is separated by at least one non-numeric ASCII character. For instance the above example could also be output as follows:

0 0 1 1 0 1 1 1 1 0 1 1 0 0 0 1 0 0 1 1 0 0 1 0
0 1 2 2 3 0 6 5 4 4 7 6 5 2 1 2 5 6 0 3 4 4 3 7 2 6 3 3 6 7 0 4 1 1 4 5


This golf is inspired by various 3d graphics systems and formats, including OpenGL, OBJ, OFF, AMF, CGAL, etc. This golf is similar to the golf by Calvin's Hobbies named Output a Face on a Numbered Cube , the big difference being you need to output the x y z coordinates of the vertices yourself and output triangle indices. Thanks for reading.

Per user inspiration here is a "helper" validation program in python2 (non-golfy) that will print 'ok' or 'not ok' for test output data in variables vertstr and idxstr. It doesn't work perfectly... but it can catch some errors.

Edit: fixed typo in example and bugs in validation code.



#vertstr = '0 0 0 0 0 1 0 1 0 0 1 1 1 0 0 1 0 1 1 1 0 1 1 1'
#idxstr = '1 2 0 2 1 3 7 5 6 4 6 5 2 4 0 4 2 6 7 3 5 1 5 3 4 1 0 1 4 5 7 6 3 2 3 6'
vertstr = '0 0 1 1 0 1 1 1 1 0 1 1 0 0 0 1 0 0 1 1 0 0 1 0'
idxstr = '0 1 2 2 3 0 6 5 4 4 7 6 5 2 1 2 5 6 0 3 4 4 3 7 2 6 3 3 6 7 0 4 1 1 4 5'

class Vector:
def __init__(self,v):
self.x,self.y,self.z=v[0],v[1],v[2]
return Vector([self.x+v.x,self.y+v.y,self.z+v.z])
def __sub__(self,v):
return Vector([self.x-v.x,self.y-v.y,self.z-v.z])
def __str__(self):
return str(self.x)+','+str(self.y)+','+str(self.z)

def cross(v1,v2):
x = v1.y*v2.z-v2.y*v1.z
z = v1.x*v2.y-v2.x*v1.y
y = v1.z*v2.x-v2.z*v1.x
return Vector([x,y,z])

# http://mathforum.org/library/drmath/view/55343.html & http://sympy.org
def winding(v1,v2,v3,obs):
x1,y1,z1,x2,y2,z2,x3,y3,z3,x4,y4,z4=v1.x,v1.y,v1.z,v2.x,v2.y,v2.z,v3.x,v3.y,v3.z,obs.x,obs.y,obs.z
d =     x1*(y2*z3 - y2*z4 - y3*z2 + y3*z4 + y4*z2 - y4*z3)
d = d + y1*(-x2*z3 + x2*z4 + x3*z2 - x3*z4 - x4*z2 + x4*z3)
d = d + z1*(x2*y3 - x2*y4 - x3*y2 + x3*y4 + x4*y2 - x4*y3)
d = d - x2*y3*z4 + x2*y4*z3 + x3*y2*z4 - x3*y4*z2 - x4*y2*z3 + x4*y3*z2
return d

def normals(v1,v2,v3):
va = v2-v1
vb = v3-v2
vc = v1-v3
n1 = cross(va,vb)
n2 = cross(vb,vc)
n3 = cross(vc,va)
return [n1,n2,n3]

def triplify(str):
nums,triples=[],[]
for num in str.split(' '): nums+=[int(num)]
for i in range(0,len(nums),3):
triples += [[nums[i],nums[i+1],nums[i+2]]]
return triples

verts = triplify(vertstr)
indices = triplify(idxstr)
nsum = Vector([0,0,0])
windsum = 0
xs,ys,zs=[],[],[]
for v in verts:
xs+=[v[0]]
ys+=[v[1]]
zs+=[v[2]]
#print xs,ys,zs,len(xs)
center=Vector([float(sum(xs))/len(xs),float(sum(ys))/len(ys),float(sum(zs))/len(zs)])
for triangle in indices:
v1 = Vector(verts[triangle[0]])
v2 = Vector(verts[triangle[1]])
v3 = Vector(verts[triangle[2]])
norms = normals(v1,v2,v3)
print v1,v2,v3,norms[0],norms[1],norms[2]
for n in norms:
nsum += n
w = winding(v1,v2,v3,center)
print 'winding',w
if w<0: windsum-=1
elif w>0: windsum+=1
if abs(windsum)==12: print 'winding ok'
else: print 'winding not ok'
if (nsum.x==0 and nsum.y==0 and nsum.z==0): print 'normal sum ok'
else: print 'normal sum not ok'

• It's clear from the example, but just to make it perfectly unambiguous, you may want to mention that the indices are 0-based. This is not a given, since at least one of the formats you list as example (OBJ) uses 1-based indices. Commented Oct 19, 2015 at 16:37
• That will work as well. I think one difficulty with this challenge is that it's moderately painful to verify the correctness of the output. You pretty much have to sketch a cube with the chose vertex ordering on a piece of paper, and manually validate all 12 triangles. Well, you could write a validation program. That might actually be another challenge idea... more difficult than this one, I think. Commented Oct 19, 2015 at 16:54
• i really like that idea of another golf for a validator. i updated the example to give a full dataset. thanks again. Commented Oct 19, 2015 at 17:22
• ok I added a very quick and dirty validation program that takes cross products of each pair of vectors in each triangle, adds them all, and if 0 says 'ok'. Commented Oct 20, 2015 at 0:20

# CJam, 35 bytes

YZm*3{[XY4]m<)\0+_:+1$f-+_@f+W%}%  Try it online The output is: [[0 0 0] [0 0 1] [0 1 0] [0 1 1] [1 0 0] [1 0 1] [1 1 0] [1 1 1]][[1 2 0 2 1 3] [7 5 6 4 6 5] [2 4 0 4 2 6] [7 3 5 1 5 3] [4 1 0 1 4 5] [7 6 3 2 3 6]] Triangle orientation is clockwise from the outside. I checked this manually, and it looks correct to me. Explanation: YZ Push 2 and 3 on stack. m* Cartesian power, creates the coordinates of the 8 vertices.  Convert to string for output. Done with vertices. 3{ Start loop over 3 coordinate directions. [XY4] Push [1 2 4], which are the vertex index offsets for the 3 directions. m< Rotate by loop counter. So the remaining loop body will be executed once with [1 2 4], once with [2 4 1], once with [4 1 2]. ) Pop off last offset. Will use this as index offset between the two parallel faces. \ Swap pair of remaining two offsets to top. These are the index offsets within the face. 0+ Add a 0 to the list. These 3 indices define the first triangle. _:+ Calculate the sum. This is the vertex index of the opposite corner. 1$      Copy first triangle to the top.
f-      Subtract all indices from the index of the opposite corner, producing
the second triangle of the face.
+       Concatenate the indices of the two triangles, resulting in a list with
the 6 vertex indices for the face.
_       Copy the list.
@       Bring the offset between the two faces to the top.
f+      Add the offset to each index in the copied list.
W%      Revert the order, resulting in the properly oriented list of the 6 vertex
indices for the parallel face.
}%      End of loop over 3 coordinate directions.
       Convert to string for output. Done with triangles.

• this is really cool. . . love the symmetry... Commented Oct 20, 2015 at 15:42
• this is clearly the most fun answer, but i messed up my problem definition to have static description and "no input", so i have to keep the agreement and award the lowest character count, below (which is also a fun answer but in a different way), the Answer checkmark. thanks for participating. Commented Nov 22, 2015 at 22:31

# Pyth, 18 characters

jCM"⭧勛囃勦⾽仵ᶌﻘꚱ쥎➡˻ì


[
1
1
1
1
1
,

2
1
2
1
1
...

• i love that you used the same unicode string in 3 different languages Commented Oct 20, 2015 at 15:15
• What is this unicode magic?
– RK.
Commented Oct 20, 2015 at 20:29

# JavaScript (ES6) 78

alert([...'1010011100101110111:120213756465240426735153410145763236'].join )


Sorry but I really don't understand these challenges with no input.

• sorry, it was my first golf question. i guess it is too late to change it now... Commented Oct 20, 2015 at 15:37
• Better next time. You have my vote anyway. Commented Oct 20, 2015 at 16:11

# Ruby, 98106

Fixed error spotted by Reto Koradi.

s=sprintf'%024b',342391
6.times{|i|t='15462315'[i,3];t+=t.reverse;t[1+i%2*3]='07'[i%2];s+=t}
p s.split(//)


Given that coordinates are required, the only corner numbering scheme that made sense seemed to be the one where each corner is the binary representation of its coordinates. That's quite different from the linked question, where various different numbering schemes were tried. In the end I decided to print the coordinates with a dirty hardcode: s is initialised to the string version of 24-bit number000001010011100101110111 whose decimal representation is 342391. Actually with this method of printing coordinates, the numbering of the vertices is flexible, so I may do another answer.

Going round the equator of the cube, we find the vertices 1,5,4,6,2,3 and we can define one triangle for each face from any 3 consecutive numbers on this list (wrapping back to the beginning at the end.) The other triangle on each face is defined by reversing the digits, and substituting the middle digit with 0 or 7 as appropriate.

This gives all the required output, but without any separating characters. To achieve that, I simply convert to an array of characters and print the array, like this (linebreaks inserted to prevent scrolling):

["0", "0", "0", "0", "0", "1", "0", "1", "0", "0", "1", "1", "1", "0", "0",
"1", "0", "1", "1", "1", "0", "1", "1", "1", "1", "0", "4", "4", "5", "1",
"5", "4", "6", "6", "7", "5", "4", "0", "2", "2", "6", "4", "6", "2", "3",
"3", "7", "6", "2", "0", "1", "1", "3", "2", "3", "1", "5", "5", "7", "3"]

• Are you sure that the winding order is consistent? Based on my sketch, 1, 5, 4 is CCW, 5, 4, 6 is CW. Commented Oct 20, 2015 at 6:26
• @RetoKoradi fixed at a cost of 8 bytes. Thanks. Also, I've realised I may do better with a different numbering scheme. Commented Oct 20, 2015 at 10:20

f=mapM(mapM print.show)"⭧勛囃勦⾽仵ᶌﻘꚱ쥎➡˻ì"


Prints the right numbers, separated by a whole lot of junk:

'\''
'\\'
'1'
'1'
'1'
'1'
'1'
'\''
'\''
'\\'
'2'
'1'
'2'
'1'
'1'
...


The cube's diagonal is from (1, 1, 1) to (2, 2, 2).

# CJam, 20 characters

"⭧勛囃勦⾽仵ᶌﻘꚱ쥎➡˻ì":isS*


1 1 1 1 1 2 1 2 1 1 2 2 2 1 1 2 1 2 2 2 1 2 2 2 1 2 0 2 1 3 7 5 6 4 6 5 2 4 0 4 2 6 7 3 5 1 5 3 4 1 0 1 4 5 7 6 3 2 3 6


# Ruby, Rev 1 62

29.downto(0){|c|p c>5?73888640>>c&1:[c,c^1,c|6,c|6,(c+3)%6,c]}


Got rid of the c-6 by multiplying the magic number by 64.

The assignment of coordinates is below. It's odd that I assigned 100 to number 1. I could have saved a byte in rev 0 by exchanging the axes and assigning 001 to number 1. The reason it was that way was because originally I had up counting in the loop, which would have meant I had to put everything in reverse in the magic string. Anyway, with the change I've made now, there's no additional saving to be made, so i'll leave the coordinates as they are

Cube rotated with 0163 face at back
Top layer from above
01   000 100
74   010 110
Bottom layer from above
36   001 101
25   011 111


# Ruby, Rev 0 63

29.downto(0){|c|p c>5?1154510>>c-6&1:[c,c^1,c|6,c|6,(c+3)%6,c]}


Using hardcoding of the coordinates data to give flexibility in picking the corners. There are 54 digits in the output, meaning that the naive solution would have 63-54=9 bytes available for code. As I can't think of a way to insert spaces in 9 bytes, I believe this is shorter than the naive solution.

4---7
|  /|
| / |
|/  |
1---0---7
|  /|  /|
| / | / |
|/  |/  |
6---3---2---7
|  /|  /|
| / | / |
|/  |/  |
6---5---4
|  /|
| / |
|/  |
6---1


Output

0
0
0
1
0
0
0
1
1
0
0
1
1
1
0
1
1
1
0
0
1
1
1
0
[5, 4, 7, 7, 2, 5]
[4, 5, 6, 6, 1, 4]
[3, 2, 7, 7, 0, 3]
[2, 3, 6, 6, 5, 2]
[1, 0, 7, 7, 4, 1]
[0, 1, 6, 6, 3, 0]

• I really like the incorporation of @Runer112 's method Commented Oct 20, 2015 at 15:35
• @donbright I was the first one to think of putting the first 6 vertices on the equator and the last 2 on the poles in that previous question, which is why my C answer is the most popular answer. I had the 6 vertices in sequential order. Runer112 deserves some credit for his reordering of the 6 vertices on the equator. I had to modify the face order for Ruby on the previous question, but the vertex order is indeed identical to Runer112's. Phinotphi's alternative reordering of the 6 vertices on the equator would have given me equal length on the previous question, but would be longer on this one Commented Oct 20, 2015 at 20:37
• wow awesome... thanks for the detailed explanation... very interesting. i should have allowed input then it would have been a better challenge. Commented Oct 21, 2015 at 1:53