```"""
By K. Urner, Oregon Curriculum Network

coords, povray, functions (plus some other modules) are all
http://www.inetarena.com/~pdx4d/ocn/numeracy0.html

"""

from __future__ import nested_scopes
from coords import Qvector
import povray, functions, ciphers
from ciphers import P,mkdict
from random import choice

# vertices needed for our shapes (using quadray coordinates)

v0,v1,v2,v3 = map(Qvector,[(1,0,0,0),(0,1,0,0),
(0,0,1,0),(0,0,0,1)])
v4,v5,v6,v7 = -v0,-v1,-v2,-v3

ciphers._domain = ['A','B','C','D','E','F','G','H']

colors  = {'A':'Red','B':'Blue','C':'Orange','D':'Yellow',
'E':'Magenta','F':'Pink','G':'Violet','H':'Green'}

class Polyhedron:

def getedges(self):
# Extract edges from faces list

output = []
for face in self.faces:
for i in range(len(face)):
edge = [face[i],face[i-1]]
edge.sort()
if (tuple(edge) not in output):
output.append(tuple(edge))
return output

def listp(self):
"""
List the permutations in pgroup
"""
for i in self.pgroup:
print i

def mkperm(self,n):
"""
Multiply randomly selected permutations from
pgroup together, starting with the identity
permutation.  Randomly choose and multiply n times
"""
result = self.pgroup[-1]
for i in range(n):
result *= choice(self.pgroup)
return result

def rotate(self,perm):
"""
Apply permutation to corners of a polyhedron -- an
operation analogous to rotation about an axis by a
fixed increment
"""
for i in range(len(self.corners)):
corner = self.corners[i]
self.corners[i] = perm.dict[corner]

def randroll(self,n):
"""
Like rolling a die:  make a permutation as a
product of randomly chosen permutations, and
apply it to self (tetrahedron object)
"""
p = self.mkperm(n)
self.rotate(p)

def display(self,filename):
"""
Output polyhedron, with color-coded vertices,
to a povray file (extension .pov)
"""
myfile = povray.Povray(filename+".pov")
myfile.sphradius = 0.1  # spheres relatively fatter than edges

# edges will be black

myfile.cylcolor = "Black"
# include some axes in the picture

functions.xyzaxes(myfile,2)
for a,b in self.edges:
myfile.edge(a,b)
i=0
for corner in self.corners:
# associate colors with spheres, so we can

# tell them apart

myfile.sphcolor = colors[corner]
myfile.point(eval('v'+str(i)))
i += 1
myfile.close()

class Tetrahedron(Polyhedron):

# create a list of the 12 rotational permutations

# for the tetrahedron, including the identity permutation

pgroup = [ P([('A','B','C')]),  # 120 degree face rotations

P([('A','B','D')]),
P([('A','C','D')]),
P([('B','C','D')]),
P([('A','B'),('C','D')]),  # opposite mid-edge axes

P([('A','C'),('B','D')]),
P([('A','D'),('B','C')]),
P([])]

for i in range(4):    #  add 240 degree face rotations

pgroup.append(pgroup[i]**2)

# and here is a list of the faces

faces = [(v0,v1,v2),(v0,v2,v3),(v0,v3,v1),(v1,v2,v3)]

def __init__(self):
# this ordering will change as permutations

# are applied

self.corners = ['A','B','C','D']
self.edges = self.getedges()

class Cube(Polyhedron):

# create a list of the 24 rotational permutations

# for the cube, including the identity permutation

pgroup = [ P([('A','H','C','F'),('G','B','E','D')]), # face axes

P([('A','H','B','G'),('F','C','E','D')]),
P([('D','G','A','F'),('E','B','H','C')]),
P([('H','E','F'),('B','D','A')]),  # axis C-G

P([('B','D','C'),('H','G','F')]),  # axis E-A

P([('E','H','G'),('C','A','D')]),  # axis B-F

P([('B','C','A'),('E','F','G')]),  # axis H-D

P([('E','C'),('A','G'),('D','H'),('B','F')]), # vertex axes

P([('D','F'),('H','B'),('C','G'),('A','E')]),
P([('C','F'),('B','G'),('A','E'),('D','H')]),
P([('E','D'),('H','A'),('F','B'),('G','C')]),
P([('E','B'),('A','F'),('G','C'),('H','D')]),
P([('H','C'),('D','G'),('A','E'),('B','F')]),
P([])]

for i in range(3):    #  add 180 and 270 degree face rotations

pgroup.append(pgroup[i]**2)
pgroup.append(pgroup[i]**3)

for i in range(3,7):  # add 240 degree opposite corner rotations

pgroup.append(pgroup[i]**2)

# A  B  C  D  E  F  G  H     <-- starting positions

# v0 v1 v2 v3 v4 v5 v6 v7

# and here is a list of the faces

faces = ((v0,v7,v2,v5),(v0,v7,v1,v6),(v1,v4,v2,v7),
(v1,v4,v3,v6),(v3,v6,v0,v5),(v2,v4,v3,v5))

def __init__(self):
# this ordering will change as permutations

# are applied

self.corners = ['A','B','C','D','E','F','G','H']
self.edges = self.getedges()

def genpix(n, shape):
"""
Generate n pictures of the tetrahedron, each
time randomly permuted by one of the 12 in
pgroup
"""
for i in range(n):
shape.randroll(5)
shape.display(shape.__class__.__name__+str(i))
```
`# code highlighted using py2html.py version 0.8`