sourceextensions/scene/demos/Rubik.xtl
1⍝# Rubik.xtl -- a Rubik's cube as arrays, for the voxel cube demos
2⍝# (voxels-rubik and after). The cube is its 54 stickers; each sticker is
3⍝# where it is -- its cubie's position x y z, each -1 0 or 1 -- and which
4⍝# way it faces, a unit normal. A turn rotates the stickers of one layer
5⍝# by a quarter turn; matching the rotated stickers against the stickers
6⍝# gives where each one goes, a permutation of 54, and turning the cube
7⍝# is selecting its colors by that permutation. Every position reached
8⍝# by turns is a real cube's.
9⍝# Import: "rb:" u_se< "Rubik"
10
11⍝## Stickers
12
13⍝ the six faces' normals, in the order of the colors: up (+y), down,
14⍝ right (+x), left, front (+z, toward the viewer), back
15normals ← 6 3 r̲eshape 0 1 0 0 -1 0 1 0 0 -1 0 0 0 0 1 0 0 -1
16
17⍝ the 27 cubies' positions, x slowest
18q ← (r̲ange 27) − 1
19cubies ← 2 1 t̲ranspose 3 27 r̲eshape ((q d̲iv 9) − 1) c̲at (((q d̲iv 3) m̲od 3) − 1) c̲at (q m̲od 3) − 1
20
21⍝# h:m_akeStickers 0: the stickers, face by face: the cubies whose
22⍝# coordinate along the face's normal is the normal's sign
23ʰm̲akeStickers ← { z →
24 pick ← cubies '+ '× i̲nner 2 1 t̲ranspose normals
25 on ← pick = 1
26 rows ← '{ (⍵ s̲elect₂ on) r̲eplicate cubies } m̲ap r̲ange 6
27 ns ← '{ 9 3 r̲eshape ⍵ s̲elect normals } m̲ap r̲ange 6
28 pos ← d̲isclose '{ e̲nclose (d̲isclose ⍺) c̲at d̲isclose ⍵ } r̲/ rows
29 nrm ← d̲isclose '{ e̲nclose (d̲isclose ⍺) c̲at d̲isclose ⍵ } r̲/ ns
30 pos c̲at₂ nrm
31}
32
33⍝# a sticker for each face and each of its 9 cubies, 54 by 6: x y z of
34⍝# the cubie, then the normal; the faces in the order up down right left
35⍝# front back, 9 stickers each
36⍝# >> "rb:" u_se< "Rubik"
37⍝# >> s_hape rb:stickers
38⍝# 54 6
39ˡstickers ← ʰm̲akeStickers 0
40
41⍝# the solved cube's colors: each sticker its face's number, 0 to 5
42⍝# (up down right left front back)
43⍝# >> "rb:" u_se< "Rubik"
44⍝# >> 10 t_ake rb:solved
45⍝# 0 0 0 0 0 0 0 0 0 1
46ˡsolved ← 9 r̲eplicate (r̲ange 6) − 1
47
48⍝## Turns
49
50⍝# h:k_ey m: one number for each sticker row (x y z nx ny nz), the same
51⍝# for the same place and facing
52ʰk̲ey ← { m → (3 3 3 3 3 3 d̲ecode 2 1 t̲ranspose m + 1) }
53
54⍝# k h:r_otate m: the rows (x y z, and the normal) turned a quarter turn
55⍝# counterclockwise about the axis k (1 x, 2 y, 3 z), seen from its
56⍝# positive end -- x y z goes to x -z y about x, z y -x about y, -y x z
57⍝# about z
58ʰr̲otate ← { k m →
59 x ← 1 s̲elect₂ m
60 y ← 2 s̲elect₂ m
61 z ← 3 s̲elect₂ m
62 a ← 4 s̲elect₂ m
63 b ← 5 s̲elect₂ m
64 c ← 6 s̲elect₂ m
65 k = 1 ? 2 1 t̲ranspose 6 54 r̲eshape x c̲at (0 − z) c̲at y c̲at a c̲at (0 − c) c̲at b
66 k = 2 ? 2 1 t̲ranspose 6 54 r̲eshape z c̲at y c̲at (0 − x) c̲at c c̲at b c̲at 0 − a
67 2 1 t̲ranspose 6 54 r̲eshape (0 − y) c̲at x c̲at z c̲at (0 − b) c̲at a c̲at c
68}
69
70⍝# (axis layer quarters) rb:p_ermutation 0: the permutation of the 54
71⍝# stickers for turning the layer (the cubies whose coordinate on the
72⍝# axis is the layer, -1 or 1) by that many counterclockwise quarter
73⍝# turns about the axis: the colors after the turn are this selection of
74⍝# the colors before
75ˡp̲ermutation ← { t z →
76 k ← 1 s̲elect t
77 v ← 2 s̲elect t
78 n ← 3 s̲elect t
79 m ← ˡstickers
80 turned ← n '{ k ʰr̲otate ⍵ } p̲ower m
81 inlayer ← v = k s̲elect₂ m
82 moved ← (2 1 t̲ranspose 6 54 r̲eshape inlayer) + 0
83 after ← (moved × turned) + (1 − moved) × m
84 g̲rade (ʰk̲ey m) i̲ndexOf ʰk̲ey after
85}
86
87⍝# the twelve turns' names: a face turned clockwise as you look at it,
88⍝# and with ' counterclockwise
89ˡnames ← "U U' D D' R R' L L' F F' B B'"
90
91⍝ each turn as axis (1 x, 2 y, 3 z), layer, counterclockwise quarters:
92⍝ a face turned clockwise as seen from outside it is a quarter turn
93⍝ clockwise about its outward normal -- three counterclockwise quarters
94⍝ about the axis for up, right and front, one for down, left and back
95specs ← 12 3 r̲eshape 2 1 3 2 1 1 2 -1 1 2 -1 3 1 1 3 1 1 1 1 -1 1 1 -1 3 3 1 3 3 1 1 3 -1 1 3 -1 3
96⍝# the twelve turns' permutations, 12 by 54, in the order of rb:names
97ˡmoves ← 12 54 r̲eshape r̲avel d̲isclose '{ e̲nclose (d̲isclose ⍺) c̲at d̲isclose ⍵ } r̲/ '{ (⍵ s̲elect specs) ˡp̲ermutation 0 } m̲ap r̲ange 12
98
99⍝# i rb:t_urn c: the colors c after turn i (1 to 12, in the order of
100⍝# rb:names)
101⍝# >> "rb:" u_se< "Rubik"
102⍝# >> (4 '{ 1 rb:t_urn _r } p_ower rb:solved) m_atch rb:solved
103⍝# 1
104ˡt̲urn ← { i c → (i s̲elect ˡmoves) s̲elect c }
105
106⍝# rb:u_ndo i: the turn that undoes turn i (U and U', and so on)
107⍝# >> "rb:" u_se< "Rubik"
108⍝# >> rb:u_ndo 1 2 5
109⍝# 2 1 6
110ˡu̲ndo ← { i → i + 1 − 2 × 0 = i m̲od 2 }
111
112⍝## Drawing
113
114⍝# (offset half) h:s_quaresAt rows: a square for each row (x y z of a
115⍝# cubie, then a normal), its center offset along the normal, its half
116⍝# side half, its 4 corners in order round it; 4n by 3, row by row
117ʰs̲quaresAt ← { oh pn →
118 p ← f̲loat 1 2 3 s̲elect₂ pn
119 n ← f̲loat 4 5 6 s̲elect₂ pn
120 ax ← (a̲bs 4 s̲elect₂ pn) + (2 × a̲bs 5 s̲elect₂ pn) + 3 × a̲bs 6 s̲elect₂ pn
121 u ← ax s̲elect 3 3 r̲eshape 0.0 1.0 0.0 1.0 0.0 0.0 1.0 0.0 0.0
122 w ← ax s̲elect 3 3 r̲eshape 0.0 0.0 1.0 0.0 0.0 1.0 0.0 1.0 0.0
123 c ← p + (1 s̲elect oh) × n
124 h ← 2 s̲elect oh
125 k1 ← c + h × (0.0 − u) − w
126 k2 ← c + h × u − w
127 k3 ← c + h × u + w
128 k4 ← c + h × w − u
129 m ← t̲ally pn
130 ((4 × m) c̲at 3) r̲eshape 2 1 3 t̲ranspose (4 c̲at m c̲at 3) r̲eshape k1 c̲at k2 c̲at k3 c̲at k4
131}
132
133⍝# the stickers as squares for scene, 4 corners each in order round
134⍝# them (216 by 3), in the stickers' order, just outside the cubies'
135⍝# dark bodies
136ˡsquares ← 0.485 0.42 ʰs̲quaresAt ˡstickers
137
138⍝ the 26 cubies one can see (all but the middle), with each normal
139shell ← (0 < '+ r̲/₂ a̲bs cubies) r̲eplicate cubies
140bodyrows ← d̲isclose '{ e̲nclose (d̲isclose ⍺) c̲at d̲isclose ⍵ } r̲/ '{ shell c̲at₂ 26 3 r̲eshape ⍵ s̲elect normals } m̲ap r̲ange 6
141
142⍝# the cubies' dark bodies as squares for scene (624 by 3): six faces
143⍝# each, 0.96 wide
144ˡbodies ← 0.48 0.48 ʰs̲quaresAt bodyrows
145
146⍝# k rb:c_olorSquares c: the squares of the stickers that are color k
147⍝# in the colors c (k 0 to 5), for one object of quads
148⍝# >> "rb:" u_se< "Rubik"
149⍝# >> s_hape 0 rb:c_olorSquares rb:solved
150⍝# 36 3
151ˡc̲olorSquares ← { k c →
152 i ← w̲here c = k
153 (r̲avel (4 × i − 1) '+ t̲able 1 2 3 4) s̲elect ˡsquares
154}
155
156⍝# each color, red green blue: white (up), yellow (down), red (right),
157⍝# orange (left), green (front), blue (back)
158ˡrgb ← 6 3 r̲eshape 0.95 0.95 0.95 1.0 0.84 0.1 0.82 0.12 0.12 1.0 0.5 0.08 0.1 0.62 0.25 0.12 0.32 0.85