sourceextensions/scene/demos/voxels-rubik-solve.xtl
1⍝# Voxels, 13: the Rubik's cube solved. Scramble it, or turn it with the
2⍝# six buttons, then Solve: the cube's turns so far are handed to the
3⍝# Eigencube library (X_eTaL-libraries, at LIBRARIES_COMMIT), which holds
4⍝# the cube as 26 rotation matrices and solves it by search, stage by
5⍝# stage -- the first layer by plain search over the twelve turns, the
6⍝# middle and last layers over known move sequences (slot inserts, an
7⍝# edge flip, Sune, a corner cycle), which is what makes it fast enough
8⍝# (2 to 3 seconds; a hundred and some moves). Then Step through the
9⍝# solution a turn at a time, Back to undo one, or Play it through, every
10⍝# turn animated on the voxel cube. The two models are checked to agree
11⍝# (tests/rubik-eigencube.xtl).
12⍝# Run: just demo scene voxels-rubik-solve
13⍝# the buttons, or keys: u r f turn (Shift for '), Space scramble,
14⍝# Enter solve, n step, b back, p play or pause, 0 solved again, drag
15⍝# to look around, q quit
16
17ʳᵇ⁼u̲se< "Rubik"
18ʳᵖ⁼u̲se< "RubikPlay"
19ᵉᶜ⁼u̲se< "Eigencube"
20ˢᶜ⁼u̲se< "Scene"
21
22w ← "Voxels 13: Rubik's cube, solved -- X_eTaL" ˢᶜo̲pen! 640 600
23k ← w ˢᶜc̲amera! 0.6 0.45 7.5 0.25
24z ← (ʳᵇsolved, 0, 0.0) ʳᵇd̲raw w
25
26⍝## The two models
27
28⍝# Rubik's turns (1 to 12: U U' D D' R R' L L' F F' B B') as
29⍝# Eigencube's (U U' D D' F F' B B' R R' L L'), and back: the same vector
30map ← 1 2 3 4 9 10 11 12 5 6 7 8
31
32⍝## The buttons
33
34⍝# the turns: six buttons, their turns, the keys that press them
35names ← "U U' R R' F F'"
36turns ← 1 2 5 6 9 10
37keys ← "uUrRfF"
38top ← 490.0
39⍝# the controls: a second row, wider buttons
40controls ← "Scramble Solve Back Step Play"
41top2 ← 545.0
42cw ← 100.0
43
44⍝ both rows drawn, the turn under way's button lit
45ᵘb̲uttons ← { i →
46 a ← (w, names, top, 640.0, 100, ʳᵖbw) ʳᵖd̲rawRow turns i̲ndexOf a̲bs i
47 b ← (w, controls, top2, 640.0, 200, cw) ʳᵖd̲rawRow 0
48 o ← w ˢᶜo̲verlay! a c̲at b
49 i
50}
51o ← ᵘb̲uttons 0
52title ← ((f̲loat w) c̲at 1.0 20.0 20.0 14.0 1.0 1.0 1.0) ˢᶜl̲abel! "Turns:"
53
54⍝ the status line (solving, the solution, solved)
55ᵘt̲ell ← { m →
56 said ← ((f̲loat w) c̲at 3.0 20.0 44.0 14.0 0.6 1.0 0.6) ˢᶜl̲abel! m
57 m
58}
59
60"keys: u r f turn (Shift for '), Space scramble, Enter solve, n step, b back, p play or pause, 0 solved, q quit; or click the buttons"
61
62⍝## Playing
63
64⍝# The state is a tuple: (the turning -- RubikPlay's colors, turns made,
65⍝# turns waiting, turn under way and its frame -- the solution, in
66⍝# Rubik's numbers; how many of its turns are made; the mode, 0 still, 1
67⍝# playing, 2 solving next frame; whether it runs).
68
69⍝ the last 12 turns made, shown above the cube
70ᵘs̲ay ← { st z →
71 (_, h, _, _, _) ← st
72 said ← ((f̲loat w) c̲at 2.0 100.0 20.0 14.0 1.0 1.0 0.6) ˢᶜl̲abel! ʳᵖn̲ames (0 − 12 m̲in t̲ally h) t̲ake h
73 st
74}
75
76⍝# u:s_crambled n: n random turns, never the same face twice in a row
77ᵘs̲crambled ← { n →
78 (_, ts) ← (n, 0 r̲eshape 0) ᵘm̲ore 0
79 ts
80}
81ᵘm̲ore ← { (n, ts) z →
82 n = 0 ? (n, ts)
83 t ← r̲oll! 12
84 prev ← f̲irst -1 t̲ake 0 c̲at ts
85 ((t + 1) d̲iv 2) = (prev + 1) d̲iv 2 ? (n, ts) ᵘm̲ore 0
86 (n − 1, ts c̲at t) ᵘm̲ore 0
87}
88
89⍝# u:s_olution st: the turns that solve the cube made so far (Rubik's
90⍝# numbers), found by Eigencube from the same turns
91ᵘs̲olution ← { st →
92 (_, h, _, _, _) ← st
93 (m, _, _) ← 1 ᵉᶜs̲olve (h s̲elect map) ᵉᶜd̲o ᵉᶜsolved
94 m s̲elect map
95}
96
97⍝ the turn or control of event v: a turn 1 to 12 (positive), a control
98⍝ 1 to 5 (negative), else 0
99ᵘp̲ressed ← { v →
100 b ← (v, 6, top, 640.0, ʳᵖbw) ʳᵖh̲it 0
101 b > 0 ? b s̲elect turns
102 c ← (v, 5, top2, 640.0, cw) ʳᵖh̲it 0
103 c > 0 ? 0 − c
104 i ← keys i̲ndexOf f̲irst -1 t̲ake v
105 ((5 = t̲ally v) × i ≤ 6) ? i s̲elect turns
106 ks ← (v m̲atch "key Space") c̲at (v m̲atch "key Enter") c̲at (v m̲atch "key b") c̲at (v m̲atch "key n") c̲at v m̲atch "key p"
107 0 < '+ r̲/ ks ? 0 − f̲irst w̲here ks
108 0
109}
110
111⍝ a turn by hand: queued; any solution is stale
112ᵘt̲urnBy ← { t (st, sol, pos, mode, on) →
113 z ← ᵘt̲ell " "
114 (t ʳᵖq̲ueue st, 0 r̲eshape 0, 0, 0, on)
115}
116
117⍝ the controls: 1 scramble, 2 solve, 3 back, 4 step, 5 play or pause
118ᵘc̲ontrol ← { k all →
119 (st, sol, pos, mode, on) ← all
120 0 = ʳᵖi̲dle st ? all
121 k = 1 ? ᵘs̲cramble all
122 k = 2 ? ᵘs̲olveSoon all
123 k = 3 ? ᵘb̲ack all
124 k = 4 ? ᵘs̲tep all
125 ᵘp̲lay all
126}
127ᵘs̲cramble ← { (st, sol, pos, mode, on) →
128 z ← ᵘt̲ell "Scrambled: 20 turns"
129 ((ᵘs̲crambled 20) ʳᵖq̲ueue st, 0 r̲eshape 0, 0, 0, on)
130}
131ᵘs̲olveSoon ← { (st, sol, pos, mode, on) →
132 (c, _, _, _, _) ← st
133 c m̲atch ʳᵇsolved ? (st, sol, pos, mode, on) ᵘs̲ayIt "Already solved"
134 z ← ᵘt̲ell "Solving..."
135 (st, sol, pos, 2, on)
136}
137ᵘs̲ayIt ← { all m →
138 z ← ᵘt̲ell m
139 all
140}
141ᵘb̲ack ← { (st, sol, pos, mode, on) →
142 pos = 0 ? (st, sol, pos, mode, on)
143 z ← ᵘt̲ell "Solution: " c̲at (f̲ormat pos − 1) c̲at " of " c̲at (f̲ormat t̲ally sol) c̲at " made"
144 (ʳᵖu̲ndo st, sol, pos − 1, 0, on)
145}
146ᵘs̲tep ← { (st, sol, pos, mode, on) →
147 pos ≥ t̲ally sol ? (st, sol, pos, 0, on)
148 z ← ᵘt̲ell "Solution: " c̲at (f̲ormat pos + 1) c̲at " of " c̲at (f̲ormat t̲ally sol) c̲at " made"
149 (((pos + 1) s̲elect sol) ʳᵖq̲ueue st, sol, pos + 1, mode, on)
150}
151ᵘp̲lay ← { (st, sol, pos, mode, on) →
152 pos ≥ t̲ally sol ? (st, sol, pos, 0, on)
153 (st, sol, pos, 1 − mode, on)
154}
155
156⍝ the solve, a frame after "Solving..." was shown
157ᵘs̲olveNow ← { (st, sol, pos, mode, on) →
158 sol ← ᵘs̲olution st
159 (_, h, _, _, _) ← st
160 said ← p̲rint! "solved by " c̲at (f̲ormat t̲ally sol) c̲at " turns; the cube solved by them: " c̲at f̲ormat (ʳᵖa̲pplied h c̲at sol) m̲atch ʳᵇsolved
161 z ← ᵘt̲ell "Solution: " c̲at (f̲ormat t̲ally sol) c̲at " turns -- Step or Play"
162 (st, sol, 0, 0, on)
163}
164
165⍝ playing: the next turn of the solution whenever the cube is still
166ᵘp̲layOn ← { all →
167 (st, sol, pos, mode, on) ← all
168 0 = (mode = 1) × ʳᵖi̲dle st ? all
169 pos ≥ t̲ally sol ? (st, sol, pos, 0, on) ᵘs̲ayIt "Solved in " c̲at (f̲ormat t̲ally sol) c̲at " turns"
170 ᵘs̲tep all
171}
172
173ᵘr̲eset ← { (st, sol, pos, mode, on) →
174 d ← (ʳᵇsolved, 0, 0.0) ʳᵇd̲raw w
175 z ← ᵘt̲ell " "
176 (ʳᵖstart ᵘs̲ay 0, 0 r̲eshape 0, 0, 0, on)
177}
178
179ᵘm̲ade ← { (_, h, _, _, _) → t̲ally h }
180ᵘu̲nder ← { (_, _, _, i, _) → i }
181ᵘs̲ayIf ← { yes st →
182 yes ? st ᵘs̲ay 0
183 st
184}
185
186⍝# one frame: an event (a turn, a control, solved again, quit), the
187⍝# solve if it is due, playing, then a frame of turning: 4 frames a
188⍝# quarter turn while more wait, 5 while playing, else 8
189ᵘf̲rame ← { all →
190 (st, sol, pos, mode, on) ← all
191 0 = on ? all
192 v ← ˢᶜn̲ext! w
193 ((v m̲atch "close") + v m̲atch "key q") > 0 ? (st, sol, pos, mode, 0)
194 (v m̲atch "key 0") ? ᵘr̲eset all
195 all ← (mode = 2) ᵘs̲olveIf all
196 p ← ᵘp̲ressed v
197 all ← (p, all) ᵘa̲ct 0
198 all ← ᵘp̲layOn all
199 (st, sol, pos, mode, on) ← all
200 (_, _, q, _, _) ← st
201 fr ← ((mode = 1) × 5) + (mode ≠ 1) × 8 − 4 × 0 < t̲ally q
202 n ← ᵘm̲ade st
203 was ← ᵘu̲nder st
204 st ← (w, fr) ʳᵖa̲dvance st
205 lit ← (was ≠ ᵘu̲nder st) ᵘl̲ightIf ᵘu̲nder st
206 ((n ≠ ᵘm̲ade st) ᵘs̲ayIf st, sol, pos, mode, on)
207}
208ᵘs̲olveIf ← { yes all →
209 yes ? ᵘs̲olveNow all
210 all
211}
212ᵘa̲ct ← { (p, all) z →
213 p > 0 ? p ᵘt̲urnBy all
214 p < 0 ? (0 − p) ᵘc̲ontrol all
215 all
216}
217ᵘl̲ightIf ← { yes i →
218 yes ? ᵘb̲uttons i
219 i
220}
221
222last ← 100000 'ᵘf̲rame p̲ower (ʳᵖstart, 0 r̲eshape 0, 0, 0, 1)
223z ← ˢᶜc̲lose! w
224⍝ (an accessor, not a top-level tuple pattern: xetal doc would list a
225⍝ hidden %N value for one, ask E10)
226ᵘc̲olorsOf ← { ((c, _, _, _, _), _, _, _, _) → c }
227ᵘt̲urnsOf ← { ((_, h, _, _, _), _, _, _, _) → h }
228ᵘm̲adeOf ← { (_, _, pos, _, _) → pos }
229c ← ᵘc̲olorsOf last
230h ← ᵘt̲urnsOf last
231pos ← ᵘm̲adeOf last
232"turns made in all, and the solution's turns made:"
233(t̲ally h) c̲at pos
234"the cube solved at the end:"
235c m̲atch ʳᵇsolved
236"bye"