1 /*
2  * cubex.cpp
3  * Cubex .505 by Eric Dietz (c) 2003 (26 Dec 03, 21 Jan 05) % 0
4  * Cube Puzzle and Universal Solver.
5  * Notes: readme.txt  Email: root@wrongway.org
6  * NOTE: This program is unaffiliated with the Rubik's Cube Trademark.
7  * This program MAY NOT be reproduced or modified outside the licensing terms
8  * set forth in the readme.
9  */
10 
11 #include <cstdio>
12 #include <string>
13 using namespace std;
14 #include "cubex.h"
15 
16 // definition of cube class
17 // Cubex constructor & destructor & count
Cubex()18 Cubex::Cubex()
19 {
20   shorten = true;
21   cenfix = 0;
22   erval = 0;
23   cubeinit = false;
24   solution = "";
25   ResetCube();
26   numcubes++;
27 }
~Cubex()28 Cubex::~Cubex()
29 {
30   numcubes--;
31 }
32 int Cubex::numcubes = 0;
33 // version & author of the solver
34 const char* Cubex::ver = ".505";
35 const char* Cubex::author = "Eric Dietz (root@wrongway.org)";
36 // test the (in)eqaulity of two cubes
operator ==(const Cubex & q)37 const bool Cubex::operator==(const Cubex &q)
38 {
39   if (!(q.cubeinit) || !(this->cubeinit)) return false;
40   bool n = true;
41   for (int i = 1; i <= N; i++) {
42     for (int j = 1; j <= N; j++) {
43       if
44       (q.Cub[i][N+1][j] != this->Cub[i][N+1][j] ||
45        q.Cub[i][j][0]   != this->Cub[i][j][0]   ||
46        q.Cub[0][i][j]   != this->Cub[0][i][j]   ||
47        q.Cub[i][j][N+1] != this->Cub[i][j][N+1] ||
48        q.Cub[N+1][i][j] != this->Cub[N+1][i][j] ||
49        q.Cub[i][0][j]   != this->Cub[i][0][j]  )
50         n = false;
51     }
52   }
53   if (q.cenfix && this->cenfix) {
54     for (int i = 2; i <= N-1; i++) {
55       for (int j = 2; j <= N-1; j++) {
56         if
57         (q.Cub[i][N][j] != this->Cub[i][N][j] ||
58          q.Cub[i][j][1] != this->Cub[i][j][1] ||
59          q.Cub[1][i][j] != this->Cub[1][i][j] ||
60          q.Cub[i][j][N] != this->Cub[i][j][N] ||
61          q.Cub[N][i][j] != this->Cub[N][i][j] ||
62          q.Cub[i][1][j] != this->Cub[i][1][j])
63           n = false;
64       }
65     }
66   }
67   return n;
68 }
operator !=(const Cubex & a)69 const bool Cubex::operator!=(const Cubex &a) { return !(operator==(a)); }
70 // point a pretty cube value to an ugly array value
face(int x,int y,int z)71 int *Cubex::face(int x, int y, int z)
72 {
73   if (x+2 < 0 || x+2 > N+1 || y+2 < 0 || y+2 > N+1 || z+2 < 0 || z+2 > N+1)
74     return NULL;
75   return &Cub[x+2][y+2][z+2];
76 }
77 // show cube on the screen (e.g., for debugging)
RenderScreen()78 const void Cubex::RenderScreen()
79 {
80 /*
81   for (int i = 1; i <= N; i++) {
82     for (int j = 1; j <= N; j++) printf("  ");
83     printf(" ");
84     for (int j = 1; j <= N; j++)
85       printf(" %i", Cub[j][N+1][N+1-i]);
86     printf("\n");
87   }
88   for (int i = 1; i <= N; i++) {
89     for (int j = 1; j <= N; j++)
90       printf(" %i", Cub[0][N+1-i][N+1-j]);
91     printf(" ");
92     for (int j = 1; j <= N; j++)
93       printf(" %i", Cub[j][N+1-i][0]);
94     printf(" ");
95     for (int j = 1; j <= N; j++)
96       printf(" %i", Cub[N+1][N+1-i][j]);
97     printf(" ");
98     for (int j = 1; j <= N; j++)
99       printf(" %i", Cub[N+1-j][N+1-i][N+1]);
100     printf("\n");
101   }
102   for (int i = 1; i <= N; i++) {
103     for (int j = 1; j <= N; j++) printf("  ");
104     printf(" ");
105     for (int j = 1; j <= N; j++)
106       printf(" %i", Cub[j][0][i]);
107     printf("\n");
108   }
109 */
110   printf(
111 "\
112         %i %i %i     %i      %i\n\
113         %i %i %i   %i %i %i %i\n\
114         %i %i %i     %i\n\
115  %i %i %i  %i %i %i  %i %i %i  %i %i %i\n\
116  %i %i %i  %i %i %i  %i %i %i  %i %i %i\n\
117  %i %i %i  %i %i %i  %i %i %i  %i %i %i\n\
118         %i %i %i\n\
119         %i %i %i\n\
120         %i %i %i\n\
121 ",
122 Cub[-1+2][ 2+2][ 1+2], Cub[ 0+2][ 2+2][ 1+2], Cub[ 1+2][ 2+2][ 1+2],
123 Cub[ 0+2][ 1+2][ 0+2], cenfix,
124 Cub[-1+2][ 2+2][ 0+2], Cub[ 0+2][ 2+2][ 0+2], Cub[ 1+2][ 2+2][ 0+2],
125 Cub[-1+2][ 0+2][ 0+2], Cub[ 0+2][ 0+2][-1+2], Cub[ 1+2][ 0+2][ 0+2], Cub[ 0+2][ 0+2][ 1+2],
126 Cub[-1+2][ 2+2][-1+2], Cub[ 0+2][ 2+2][-1+2], Cub[ 1+2][ 2+2][-1+2],
127 Cub[ 0+2][-1+2][ 0+2],
128 Cub[-2+2][ 1+2][ 1+2], Cub[-2+2][ 1+2][ 0+2], Cub[-2+2][ 1+2][-1+2],
129 Cub[-1+2][ 1+2][-2+2], Cub[ 0+2][ 1+2][-2+2], Cub[ 1+2][ 1+2][-2+2],
130 Cub[ 2+2][ 1+2][-1+2], Cub[ 2+2][ 1+2][ 0+2], Cub[ 2+2][ 1+2][ 1+2],
131 Cub[ 1+2][ 1+2][ 2+2], Cub[ 0+2][ 1+2][ 2+2], Cub[-1+2][ 1+2][ 2+2],
132 Cub[-2+2][ 0+2][ 1+2], Cub[-2+2][ 0+2][ 0+2], Cub[-2+2][ 0+2][-1+2],
133 Cub[-1+2][ 0+2][-2+2], Cub[ 0+2][ 0+2][-2+2], Cub[ 1+2][ 0+2][-2+2],
134 Cub[ 2+2][ 0+2][-1+2], Cub[ 2+2][ 0+2][ 0+2], Cub[ 2+2][ 0+2][ 1+2],
135 Cub[ 1+2][ 0+2][ 2+2], Cub[ 0+2][ 0+2][ 2+2], Cub[-1+2][ 0+2][ 2+2],
136 Cub[-2+2][-1+2][ 1+2], Cub[-2+2][-1+2][ 0+2], Cub[-2+2][-1+2][-1+2],
137 Cub[-1+2][-1+2][-2+2], Cub[ 0+2][-1+2][-2+2], Cub[ 1+2][-1+2][-2+2],
138 Cub[ 2+2][-1+2][-1+2], Cub[ 2+2][-1+2][ 0+2], Cub[ 2+2][-1+2][ 1+2],
139 Cub[ 1+2][-1+2][ 2+2], Cub[ 0+2][-1+2][ 2+2], Cub[-1+2][-1+2][ 2+2],
140 Cub[-1+2][-2+2][-1+2], Cub[ 0+2][-2+2][-1+2], Cub[ 1+2][-2+2][-1+2],
141 Cub[-1+2][-2+2][ 0+2], Cub[ 0+2][-2+2][ 0+2], Cub[ 1+2][-2+2][ 0+2],
142 Cub[-1+2][-2+2][ 1+2], Cub[ 0+2][-2+2][ 1+2], Cub[ 1+2][-2+2][ 1+2]
143   );
144 }
145 // return true if cube is solved
IsSolved()146 const bool Cubex::IsSolved()
147 {
148   if (!cubeinit) return false;
149   int c[7], d; bool n = true;
150   c[1] = Cub[2][N+1][2]; c[2] = Cub[2][2][0];
151   c[3] = Cub[0][2][2];   c[4] = Cub[2][2][N+1];
152   c[5] = Cub[N+1][2][2]; c[6] = Cub[2][0][2];
153   for (int i = 1; i <= 6 && n == true; i++) {
154     d = 0;
155     for (int j = 1; j <= 6 && n == true; j++) {
156       if (c[i] == j) d++;
157     }
158     if (d != 1)
159       n = false;
160   }
161   for (int i = 1; i <= N && n == true; i++) {
162     for (int j = 1; j <= N && n == true; j++) {
163       if
164       (Cub[i][N+1][j] != c[1] ||
165        Cub[i][j][0]   != c[2] ||
166        Cub[0][i][j]   != c[3] ||
167        Cub[i][j][N+1] != c[4] ||
168        Cub[N+1][i][j] != c[5] ||
169        Cub[i][0][j]   != c[6])
170         n = false;
171     }
172   }
173   if (cenfix) {
174     for (int i = 2; i <= N-1; i++) {
175       for (int j = 2; j <= N-1; j++) {
176         if
177         (Cub[i][N][j] != 0 ||
178          Cub[i][j][1] != 0 ||
179          Cub[1][i][j] != 0 ||
180          Cub[i][j][N] != 0 ||
181          Cub[N][i][j] != 0 ||
182          Cub[i][1][j] != 0)
183           n = false;
184       }
185     }
186   }
187   return n;
188 }
189 // create default (solved) cube model and put it in Cub[]
ResetCube()190 const void Cubex::ResetCube()
191 {
192   solution = "";
193   for (int i = 0; i <= MOV; i++) mov[i] = 0;
194   for (int i = 0; i <= N+1; i++) {
195     for (int j = 0; j <= N+1; j++) {
196       for (int k = 0; k <= N+1; k++) {
197         if (!(i-2 == 0 && j-2 == 0 && k-2 == 0))
198           Cub[i][j][k] = 0;
199       }
200     }
201   }
202   for (int i = 1; i <= N; i++) {
203     for (int j = 1; j <= N; j++) {
204       Cub[i][N+1][j] = 1;
205       Cub[i][j][0]   = 2;
206       Cub[0][i][j]   = 3;
207       Cub[i][j][N+1] = 4;
208       Cub[N+1][i][j] = 5;
209       Cub[i][0][j]   = 6;
210     }
211   }
212   cubeinit = true;
213   erval = 0;
214 }
215 // this is the series of cube rotation functions
216 // copy cube model so we can change it and remember the original
Ctemp()217 const void Cubex::Ctemp()
218 {
219   for (int i = 0; i <= N+1; i++) {
220     for (int j = 0; j <= N+1; j++) {
221       for (int k = 0; k <= N+1; k++) {
222         Tmp[i][j][k] = Cub[i][j][k];
223       }
224     }
225   }
226 }
227 // rotate given slice left
XML(int a,bool n=true)228 const bool Cubex::XML(int a, bool n = true)
229 {
230   if (a < 1 || a > N) return false;
231   Ctemp();
232   for (int i = 1; i <= N; i++) {
233     if (a == 1)
234       for (int j = 1; j <= N; j++)
235         Cub[i][0][j] = Tmp[N+1-j][0][i];
236     else if (a == N)
237       for (int j = 1; j <= N; j++)
238         Cub[i][N+1][j] = Tmp[N+1-j][N+1][i];
239     Cub[i][a][0]   = Tmp[N+1][a][i];
240     Cub[i][a][N+1] = Tmp[0][a][i];
241     Cub[0][a][i]   = Tmp[N+1-i][a][0];
242     Cub[N+1][a][i] = Tmp[N+1-i][a][N+1];
243   }
244   if (a == 1) {
245     for (int i = 2; i <= N-1; i++) {
246       for (int j = 2; j <= N-1; j++) {
247         Cub[i][1][j] = Tmp[N+1-j][1][i];
248         if (n) {
249           Cub[i][1][j]--;
250           if (Cub[i][1][j] < 0) Cub[i][1][j] += 4;
251         }
252       }
253     }
254   }
255   else if (a == N) {
256     for (int i = 2; i <= N-1; i++) {
257       for (int j = 2; j <= N-1; j++) {
258         Cub[i][N][j] = Tmp[N+1-j][N][i];
259         if (n) {
260           Cub[i][N][j]++;
261           if (Cub[i][N][j] > 3) Cub[i][N][j] -= 4;
262         }
263       }
264     }
265   }
266   else {
267     for (int i = 2; i <= N-1; i++) {
268       Cub[i][a][1] = Tmp[N][a][i];
269       Cub[i][a][N] = Tmp[1][a][i];
270       Cub[1][a][i] = Tmp[N+1-i][a][1];
271       Cub[N][a][i] = Tmp[N+1-i][a][N];
272     }
273   }
274   return true;
275 }
276 // rotate given slice right
XMR(int a,bool n=true)277 const bool Cubex::XMR(int a, bool n = true)
278 {
279   if (a < 1 || a > N) return false;
280   Ctemp();
281   for (int i = 1; i <= N; i++) {
282     if (a == 1)
283       for (int j = 1; j <= N; j++)
284         Cub[i][0][j] = Tmp[j][0][N+1-i];
285     else if (a == N)
286       for (int j = 1; j <= N; j++)
287         Cub[i][N+1][j] = Tmp[j][N+1][N+1-i];
288     Cub[i][a][0]   = Tmp[0][a][N+1-i];
289     Cub[i][a][N+1] = Tmp[N+1][a][N+1-i];
290     Cub[0][a][i]   = Tmp[i][a][N+1];
291     Cub[N+1][a][i] = Tmp[i][a][0];
292   }
293   if (a == 1) {
294     for (int i = 2; i <= N-1; i++) {
295       for (int j = 2; j <= N-1; j++) {
296         Cub[i][1][j] = Tmp[j][1][N+1-i];
297         if (n) {
298           Cub[i][1][j]++;
299           if (Cub[i][1][j] > 3) Cub[i][1][j] -= 4;
300         }
301       }
302     }
303   }
304   else if (a == N) {
305     for (int i = 2; i <= N-1; i++) {
306       for (int j = 2; j <= N-1; j++) {
307         Cub[i][N][j] = Tmp[j][N][N+1-i];
308         if (n) {
309           Cub[i][N][j]--;
310           if (Cub[i][N][j] < 0) Cub[i][N][j] += 4;
311         }
312       }
313     }
314   }
315   else {
316     for (int i = 2; i <= N-1; i++) {
317       Cub[i][a][1] = Tmp[1][a][N+1-i];
318       Cub[i][a][N] = Tmp[N][a][N+1-i];
319       Cub[1][a][i] = Tmp[i][a][N];
320       Cub[N][a][i] = Tmp[i][a][1];
321     }
322   }
323   return true;
324 }
325 // rotate given slice up
XMU(int a,bool n=true)326 const bool Cubex::XMU(int a, bool n = true)
327 {
328   if (a < 1 || a > N) return false;
329   Ctemp();
330   for (int i = 1; i <= N; i++) {
331     if (a == 1)
332       for (int j = 1; j <= N; j++)
333         Cub[0][i][j] = Tmp[0][j][N+1-i];
334     if (a == N)
335       for (int j = 1; j <= N; j++)
336         Cub[N+1][i][j] = Tmp[N+1][j][N+1-i];
337     Cub[a][i][0]   = Tmp[a][0][N+1-i];
338     Cub[a][i][N+1] = Tmp[a][N+1][N+1-i];
339     Cub[a][0][i]   = Tmp[a][i][N+1];
340     Cub[a][N+1][i] = Tmp[a][i][0];
341   }
342   if (a == 1) {
343     for (int i = 2; i <= N-1; i++) {
344       for (int j = 2; j <= N-1; j++) {
345         Cub[1][i][j] = Tmp[1][j][N+1-i];
346         if (n) {
347           Cub[1][i][j]--;
348           if (Cub[1][i][j] < 0) Cub[1][i][j] += 4;
349         }
350       }
351     }
352   }
353   else if (a == N) {
354     for (int i = 2; i <= N-1; i++) {
355       for (int j = 2; j <= N-1; j++) {
356         Cub[N][i][j] = Tmp[N][j][N+1-i];
357         if (n) {
358           Cub[N][i][j]++;
359           if (Cub[N][i][j] > 3) Cub[N][i][j] -= 4;
360         }
361       }
362     }
363   }
364   else {
365     for (int i = 2; i <= N-1; i++) {
366       Cub[a][i][1] = Tmp[a][1][N+1-i];
367       Cub[a][i][N] = Tmp[a][N][N+1-i];
368       Cub[a][1][i] = Tmp[a][i][N];
369       Cub[a][N][i] = Tmp[a][i][1];
370     }
371   }
372   return true;
373 }
374 // rotate given slice down
XMD(int a,bool n=true)375 const bool Cubex::XMD(int a, bool n = true)
376 {
377   if (a < 1 || a > N) return false;
378   Ctemp();
379   for (int i = 1; i <= N; i++) {
380     if (a == 1)
381       for (int j = 1; j <= N; j++)
382         Cub[0][i][j] = Tmp[0][N+1-j][i];
383     if (a == N)
384       for (int j = 1; j <= N; j++)
385         Cub[N+1][i][j] = Tmp[N+1][N+1-j][i];
386     Cub[a][i][0]   = Tmp[a][N+1][i];
387     Cub[a][i][N+1] = Tmp[a][0][i];
388     Cub[a][0][i]   = Tmp[a][N+1-i][0];
389     Cub[a][N+1][i] = Tmp[a][N+1-i][N+1];
390   }
391   if (a == 1) {
392     for (int i = 2; i <= N-1; i++) {
393       for (int j = 2; j <= N-1; j++) {
394         Cub[1][i][j] = Tmp[1][N+1-j][i];
395         if (n) {
396           Cub[1][i][j]++;
397           if (Cub[1][i][j] > 3) Cub[1][i][j] -= 4;
398         }
399       }
400     }
401   }
402   else if (a == N) {
403     for (int i = 2; i <= N-1; i++) {
404       for (int j = 2; j <= N-1; j++) {
405         Cub[N][i][j] = Tmp[N][N+1-j][i];
406         if (n) {
407           Cub[N][i][j]--;
408           if (Cub[N][i][j] < 0) Cub[N][i][j] += 4;
409         }
410       }
411     }
412   }
413   else {
414     for (int i = 2; i <= N-1; i++) {
415       Cub[a][i][1] = Tmp[a][N][i];
416       Cub[a][i][N] = Tmp[a][1][i];
417       Cub[a][1][i] = Tmp[a][N+1-i][1];
418       Cub[a][N][i] = Tmp[a][N+1-i][N];
419     }
420   }
421   return true;
422 }
423 // rotate given slice clockwise
XMC(int a,bool n=true)424 const bool Cubex::XMC(int a, bool n = true)
425 {
426   if (a < 1 || a > N) return false;
427   Ctemp();
428   for (int i = 1; i <= N; i++) {
429     if (a == 1)
430       for (int j = 1; j <= N; j++)
431         Cub[i][j][0] = Tmp[N+1-j][i][0];
432     if (a == N)
433       for (int j = 1; j <= N; j++)
434         Cub[i][j][N+1] = Tmp[N+1-j][i][N+1];
435     Cub[i][0][a]   = Tmp[N+1][i][a];
436     Cub[i][N+1][a] = Tmp[0][i][a];
437     Cub[0][i][a]   = Tmp[N+1-i][0][a];
438     Cub[N+1][i][a] = Tmp[N+1-i][N+1][a];
439   }
440   if (a == 1) {
441     for (int i = 2; i <= N-1; i++) {
442       for (int j = 2; j <= N-1; j++) {
443         Cub[i][j][1] = Tmp[N+1-j][i][1];
444         if (n) {
445           Cub[i][j][1]++;
446           if (Cub[i][j][1] > 3) Cub[i][j][1] -= 4;
447         }
448       }
449     }
450   }
451   else if (a == N) {
452     for (int i = 2; i <= N-1; i++) {
453       for (int j = 2; j <= N-1; j++) {
454         Cub[i][j][N] = Tmp[N+1-j][i][N];
455         if (n) {
456           Cub[i][j][N]--;
457           if (Cub[i][j][N] < 0) Cub[i][j][N] += 4;
458         }
459       }
460     }
461   }
462   else {
463     for (int i = 2; i <= N-1; i++) {
464       Cub[i][1][a] = Tmp[N][i][a];
465       Cub[i][N][a] = Tmp[1][i][a];
466       Cub[1][i][a] = Tmp[N+1-i][1][a];
467       Cub[N][i][a] = Tmp[N+1-i][N][a];
468     }
469   }
470   return true;
471 }
472 // rotate given slice anticlockwise (looking from the front)
XMA(int a,bool n=true)473 const bool Cubex::XMA(int a, bool n = true)
474 {
475   if (a < 1 || a > N) return false;
476   Ctemp();
477   for (int i = 1; i <= N; i++) {
478     if (a == 1)
479       for (int j = 1; j <= N; j++)
480         Cub[i][j][0] = Tmp[j][N+1-i][0];
481     if (a == N)
482       for (int j = 1; j <= N; j++)
483         Cub[i][j][N+1] = Tmp[j][N+1-i][N+1];
484     Cub[i][0][a]   = Tmp[0][N+1-i][a];
485     Cub[i][N+1][a] = Tmp[N+1][N+1-i][a];
486     Cub[0][i][a]   = Tmp[i][N+1][a];
487     Cub[N+1][i][a] = Tmp[i][0][a];
488   }
489   if (a == 1) {
490     for (int i = 2; i <= N-1; i++) {
491       for (int j = 2; j <= N-1; j++) {
492         Cub[i][j][1] = Tmp[j][N+1-i][1];
493         if (n) {
494           Cub[i][j][1]--;
495           if (Cub[i][j][1] < 0) Cub[i][j][1] += 4;
496         }
497       }
498     }
499   }
500   else if (a == N) {
501     for (int i = 2; i <= N-1; i++) {
502       for (int j = 2; j <= N-1; j++) {
503         Cub[i][j][N] = Tmp[j][N+1-i][N];
504         if (n) {
505           Cub[i][j][N]++;
506           if (Cub[i][j][N] > 3) Cub[i][j][N] -= 4;
507         }
508       }
509     }
510   }
511   else {
512     for (int i = 2; i <= N-1; i++) {
513       Cub[i][1][a] = Tmp[1][N+1-i][a];
514       Cub[i][N][a] = Tmp[N][N+1-i][a];
515       Cub[1][i][a] = Tmp[i][N][a];
516       Cub[N][i][a] = Tmp[i][1][a];
517     }
518   }
519   return true;
520 }
521 // the remaining rotation functions are aliases to the above rotators (with nicer names)
UL()522 const void Cubex::UL() { XML(N); } // rotate top left
UR()523 const void Cubex::UR() { XMR(N); } // rotate top right
DL()524 const void Cubex::DL() { XML(1); } // rotate bottom left
DR()525 const void Cubex::DR() { XMR(1); } // rotate bottom right
LU()526 const void Cubex::LU() { XMU(1); } // rotate left up
LD()527 const void Cubex::LD() { XMD(1); } // rotate left down
RU()528 const void Cubex::RU() { XMU(N); } // rotate right up
RD()529 const void Cubex::RD() { XMD(N); } // rotate right down
FC()530 const void Cubex::FC() { XMC(1); } // rotate front clockwise
FA()531 const void Cubex::FA() { XMA(1); } // rotate front anticlockwise
BC()532 const void Cubex::BC() { XMC(N); } // rotate back clockwise (looking from front)
BA()533 const void Cubex::BA() { XMA(N); } // rotate back anticlockwise (looking from front)
ML()534 const void Cubex::ML() { XML(2); } // rotate middle left
MR()535 const void Cubex::MR() { XMR(2); } // rotate middle right
MU()536 const void Cubex::MU() { XMU(2); } // rotate middle up
MD()537 const void Cubex::MD() { XMD(2); } // rotate middle down
MC()538 const void Cubex::MC() { XMC(2); } // rotate middle clockwise
MA()539 const void Cubex::MA() { XMA(2); } // rotate middle anticlockwise
CL()540 const void Cubex::CL() { for (int i = 1; i <= N; i++) XML(i); } // rotate whole cube left
CR()541 const void Cubex::CR() { for (int i = 1; i <= N; i++) XMR(i); } // rotate whole cube right
CU()542 const void Cubex::CU() { for (int i = 1; i <= N; i++) XMU(i); } // rotate whole cube up
CD()543 const void Cubex::CD() { for (int i = 1; i <= N; i++) XMD(i); } // rotate whole cube down
CC()544 const void Cubex::CC() { for (int i = 1; i <= N; i++) XMC(i); } // rotate whole cube clockwise
CA()545 const void Cubex::CA() { for (int i = 1; i <= N; i++) XMA(i); } // rotate whole cube anticlockwise
XCL()546 const void Cubex::XCL() { for (int i = 1; i <= N; i++) XML(i, false); } // rotate whole cube left w/o altering centers
XCR()547 const void Cubex::XCR() { for (int i = 1; i <= N; i++) XMR(i, false); } // rotate whole cube right w/o altering centers
XCU()548 const void Cubex::XCU() { for (int i = 1; i <= N; i++) XMU(i, false); } // rotate whole cube up w/o altering centers
XCD()549 const void Cubex::XCD() { for (int i = 1; i <= N; i++) XMD(i, false); } // rotate whole cube down w/o altering centers
XCC()550 const void Cubex::XCC() { for (int i = 1; i <= N; i++) XMC(i, false); } // rotate whole cube clockwise w/o altering centers
XCA()551 const void Cubex::XCA() { for (int i = 1; i <= N; i++) XMA(i, false); } // rotate whole cube anticlockwise w/o altering centers
552 // scramble up the cube model
ScrambleCube()553 const void Cubex::ScrambleCube()
554 {
555   // come up with a better calculation for a good number of random moves based on cube size later
556   int a = (N-2)*25+10;
557   int n, o; string s = "";
558   a += rand() % a;
559   ResetCube();
560   for (int i = 1; i <= a; i++) {
561     n = rand() % 6 + 1; // which dimension & direction
562     o = rand() % N + 1; // which layer
563     switch (n) {
564       case 1: XML(o); break;
565       case 2: XMR(o); break;
566       case 3: XMU(o); break;
567       case 4: XMD(o); break;
568       case 5: XMC(o); break;
569       case 6: XMA(o); break;
570     }
571   }
572   cubeinit = true;
573 }
574 // execute solution
DoSolution()575 const void Cubex::DoSolution()
576 {
577   if (!cubeinit) return;
578   string a = "";
579   for (int i = 1; i <= mov[0]; i++) {
580     a = solution.substr(i * 3 - 3, 3);
581     if      (a == "UL.") UL();
582     else if (a == "UR.") UR();
583     else if (a == "DL.") DL();
584     else if (a == "DR.") DR();
585     else if (a == "LU.") LU();
586     else if (a == "LD.") LD();
587     else if (a == "RU.") RU();
588     else if (a == "RD.") RD();
589     else if (a == "FC.") FC();
590     else if (a == "FA.") FA();
591     else if (a == "BC.") BC();
592     else if (a == "BA.") BA();
593     else if (a == "ML.") ML();
594     else if (a == "MR.") MR();
595     else if (a == "MU.") MU();
596     else if (a == "MD.") MD();
597     else if (a == "MC.") MC();
598     else if (a == "MA.") MA();
599     else if (a == "CL.") CL();
600     else if (a == "CR.") CR();
601     else if (a == "CU.") CU();
602     else if (a == "CD.") CD();
603     else if (a == "CC.") CC();
604     else if (a == "CA.") CA();
605   }
606 }
607 // return adjacent axis on which given center is found
FindCent(int a)608 const int Cubex::FindCent(int a)
609 {
610   int f = 0, x, y, z; fx = 0; fy = 0; fz = 0;
611   for (int i = -1; i <= 1; i = i + 2) {
612     x = Cub[i*2+2][0+2][0+2];
613     y = Cub[0+2][i*2+2][0+2];
614     z = Cub[0+2][0+2][i*2+2];
615     if      (x == a) {
616       f = i * 1; fx = i * 2; return f;
617     }
618     else if (y == a) {
619       f = i * 2; fy = i * 2; return f;
620     }
621     else if (z == a) {
622       f = i * 3; fz = i * 2; return f;
623     }
624   }
625   return f;
626 }
627 // return adjacent axis on which given edge is found
FindEdge(int a,int b)628 const int Cubex::FindEdge(int a, int b)
629 {
630   int f = 0, x, y, z; fx = 0; fy = 0; fz = 0;
631   for (int i = -1; i <= 1; i = i + 2) {
632     for (int j = -1; j <= 1; j = j + 2) {
633       x = Cub[i*2+2][j+2][0+2];
634       y = Cub[i+2][j*2+2][0+2];
635       if      (x == a && y == b) {
636         f = i * 1; fx = i * 2; fy = j; return f;
637       }
638       else if (y == a && x == b) {
639         f = j * 2; fx = i; fy = j * 2; return f;
640       }
641       x = Cub[i*2+2][0+2][j+2];
642       z = Cub[i+2][0+2][j*2+2];
643       if      (x == a && z == b) {
644         f = i * 1; fx = i * 2; fz = j; return f;
645       }
646       else if (z == a && x == b) {
647         f = j * 3; fx = i; fz = j * 2; return f;
648       }
649       y = Cub[0+2][i*2+2][j+2];
650       z = Cub[0+2][i+2][j*2+2];
651       if      (y == a && z == b) {
652         f = i * 2; fy = i * 2; fz = j; return f;
653       }
654       else if (z == a && y == b) {
655         f = j * 3; fy = i; fz = j * 2; return f;
656       }
657     }
658   }
659   return f;
660 }
661 // return adjacent axis on which given corner is found
FindCorn(int a,int b,int c)662 const int Cubex::FindCorn(int a, int b, int c)
663 {
664   int f = 0, x, y, z; fx = 0; fy = 0; fz = 0;
665   for (int i = -1; i <= 1; i = i + 2) {
666     for (int j = -1; j <= 1; j = j + 2) {
667       for (int k = -1; k <= 1; k = k + 2) {
668         x = Cub[i*2+2][j+2][k+2];
669         y = Cub[i+2][j*2+2][k+2];
670         z = Cub[i+2][j+2][k*2+2];
671         if      (x == a && (y == b || y == c) && (z == b || z == c)) {
672           f = i * 1; fx = i * 2; fy = j; fz = k; return f;
673         }
674         else if (y == a && (x == b || x == c) && (z == b || z == c)) {
675           f = j * 2; fx = i; fy = j * 2; fz = k; return f;
676         }
677         else if (z == a && (x == b || x == c) && (y == b || y == c)) {
678           f = k * 3; fx = i; fy = j; fz = k * 2; return f;
679         }
680       }
681     }
682   }
683   return f;
684 }
685 // routine for condensing redundant redundancies (a joke)
686 // this is undoubtedly the most complex routine in this class
Concise(string a)687 const string Cubex::Concise(string a)
688 {
689   // initialize stuff
690   string s = a; string t = "";
691   string s1 = ""; string s2 = ""; string s3 = "";
692   string t1 = ""; string t2 = ""; string t3 = "";
693   string zz = ""; string yy = ""; string xx = "";
694   string ww = ""; string vv = ""; string uu = "";
695   string mm = ""; string ll = ""; string kk = "";
696   string jj = ""; string ii = ""; string hh = "";
697   int b, c, g, h[2], mvs[MOV+1];
698   if (mov[0] == -1) {
699     mvs[0] = 0;
700     for (int i = 1; i <= MOV; i++) {
701       mvs[i] = 0;
702       for (int j = 1; j <= i; j++) mvs[i] += mov[j];
703     }
704   }
705   // part 1: remove middle, and whole cube moves by interpolating them
706   // part 1a - getting rid of middle slice moves
707   for (int i = 1; i <= s.length() / 3; i++) {
708     s1 = s.substr(i * 3 - 3, 1);
709     s2 = s.substr(i * 3 - 2, 1);
710     if (s1 == "M") {
711       if      (s2 == "U") { t += "CU.LD.RD."; }
712       else if (s2 == "D") { t += "CD.LU.RU."; }
713       else if (s2 == "L") { t += "CL.UR.DR."; }
714       else if (s2 == "R") { t += "CR.UL.DL."; }
715       else if (s2 == "C") { t += "CC.FA.BA."; }
716       else if (s2 == "A") { t += "CA.FC.BC."; }
717     }
718     else {
719       t += s1; t += s2; t += ".";
720     }
721   }
722   s = t;
723   // part 1b - interpolating whole cube moves
724   c = 1;
725   while (c <= s.length() / 3) {
726     s1 = s.substr(c * 3 - 3, 1);
727     s2 = s.substr(c * 3 - 2, 1);
728     if (s1 == "C") {
729       zz = "U"; yy = "D"; xx = "L"; ww = "R"; vv = "F"; uu = "B";
730       mm = "L"; ll = "R"; kk = "U"; jj = "D"; ii = "C"; hh = "A";
731       if      (s2 == "U") {
732         zz = "F"; yy = "B"; vv = "D"; uu = "U";
733         mm = "C"; ll = "A"; ii = "R"; hh = "L";
734       }
735       else if (s2 == "D") {
736         zz = "B"; yy = "F"; vv = "U"; uu = "D";
737         mm = "A"; ll = "C"; ii = "L"; hh = "R";
738       }
739       else if (s2 == "L") {
740         xx = "F"; ww = "B"; vv = "R"; uu = "L";
741         kk = "A"; jj = "C"; ii = "U"; hh = "D";
742       }
743       else if (s2 == "R") {
744         xx = "B"; ww = "F"; vv = "L"; uu = "R";
745         kk = "C"; jj = "A"; ii = "D"; hh = "U";
746       }
747       else if (s2 == "C") {
748         xx = "D"; ww = "U"; zz = "L"; yy = "R";
749         kk = "L"; jj = "R"; mm = "D"; ll = "U";
750       }
751       else if (s2 == "A") {
752         xx = "U"; ww = "D"; zz = "R"; yy = "L";
753         kk = "R"; jj = "L"; mm = "U"; ll = "D";
754       }
755       t = "";
756       for (int i = c + 1; i <= s.length() / 3; i++) {
757         t1 = s.substr(i * 3 - 3, 1);
758         t2 = s.substr(i * 3 - 2, 1);
759         if      (t1 == "U") { t += zz; }
760         else if (t1 == "D") { t += yy; }
761         else if (t1 == "L") { t += xx; }
762         else if (t1 == "R") { t += ww; }
763         else if (t1 == "F") { t += vv; }
764         else if (t1 == "B") { t += uu; }
765         else if (t1 == "C") { t += "C"; }
766         if      (t2 == "L") { t += mm; }
767         else if (t2 == "R") { t += ll; }
768         else if (t2 == "U") { t += kk; }
769         else if (t2 == "D") { t += jj; }
770         else if (t2 == "C") { t += ii; }
771         else if (t2 == "A") { t += hh; }
772         t += ".";
773       }
774       c--;
775       s = s.substr(0, c * 3); s += t;
776     }
777     c++;
778   }
779   // parts 2-4 are nested in this while, so that it will keep stripping out
780   // moves until it goes through an entire cycle without stripping anything.
781   g = 1;
782   while (g > 0) {
783     g = 0;
784     // part 2: unshuffle possible opposite face groups, e.g., "UL.DR.UR.DL." to "UL.UR.DR.DL."
785     // this will make it much easier to identify redundancies like "top left, top right" later on
786     b = 0;
787     while (b <= s.length() / 3 - 1 && s.length() / 3 > 0) {
788       s1 = s.substr(b * 3, 2);
789       t1 = s1.substr(0, 1);
790       if      (t1 == "U") { t3 = "D"; }
791       else if (t1 == "D") { t3 = "U"; }
792       else if (t1 == "L") { t3 = "R"; }
793       else if (t1 == "R") { t3 = "L"; }
794       else if (t1 == "F") { t3 = "B"; }
795       else if (t1 == "B") { t3 = "F"; }
796       c = 0;
797       s2 = s.substr(b * 3 + 3, 2);
798       t2 = s2.substr(0, 1);
799       while ((t2 == t1 || t2 == t3) && c <= s.length() / 3 - b - 2 && s != "") {
800         if (t2 == t1 && c > 0) {
801           t = s.substr(0, b * 3 + 3);
802           t += s.substr(b * 3 + c * 3 + 3, 3);
803           t += s.substr(b * 3 + 3, c * 3);
804           t += s.substr(b * 3 + c * 3 + 6, s.length() - (b * 3 + c * 3 + 6));
805           s = t;
806           c = s.length() / 3;
807         }
808         else if (t2 == t3) {
809           c++;
810         }
811         else {
812           c = s.length() / 3;
813         }
814         if (c < s.length() / 3) {
815           s2 = s.substr(b * 3 + c * 3 + 3, 2);
816           t2 = s2.substr(0, 1);
817         }
818       }
819       b++;
820     }
821     // part 3: change things like "top left, top left, top left" to simply "top right"
822     b = 0;
823     while (b <= s.length() / 3 - 2 && s.length() / 3 >= 3) {
824       s1 = s.substr(b * 3, 2);
825       s2 = s.substr(b * 3 + 3, 2);
826       s3 = s.substr(b * 3 + 6, 2);
827       t1 = s1.substr(0, 1);
828       t2 = s1.substr(1, 1);
829       if (s1 == s2 && s2 == s3) {
830         if      (t2 == "L") { t3 = "R"; }
831         else if (t2 == "R") { t3 = "L"; }
832         else if (t2 == "U") { t3 = "D"; }
833         else if (t2 == "D") { t3 = "U"; }
834         else if (t2 == "C") { t3 = "A"; }
835         else if (t2 == "A") { t3 = "C"; }
836         g = 1;
837         t = s.substr(0, b * 3);
838         t += t1 + t3 + ".";
839         t += s.substr(b * 3 + 9, s.length() - (b * 3 + 9));
840         // change the mov[] array if necessary
841         if (mov[0] == -1) {
842           h[0] = 0; h[1] = 0;
843           for (int i = 1; i <= MOV; i++) {
844             for (int k = 0; k <= 1; k++) {
845               if ((b+k+2) <= mvs[i] && (b+k+2) > mvs[i-1] && h[k] == 0) {
846                 mov[i]--; h[k] = 1;
847                 for (int j = i; j <= MOV; j++) mvs[j]--;
848               }
849             }
850           }
851         }
852         //
853         s = t;
854         b = b - 3; if (b < -1) b = -1;
855       }
856       b++;
857     }
858     // part 4: remove explicit redundancies like "top left, top right"
859     b = 0;
860     while (b <= s.length() / 3 - 2 && s.length() / 3 >= 2) {
861       t1 = s.substr(b * 3, 1);
862       t2 = s.substr(b * 3 + 3, 1);
863       s1 = s.substr(b * 3 + 1, 1);
864       s2 = s.substr(b * 3 + 4, 1);
865       if ((t1 == t2) &&
866        ((s1 == "L" && s2 == "R") ||
867        (s1 == "R" && s2 == "L") ||
868        (s1 == "U" && s2 == "D") ||
869        (s1 == "D" && s2 == "U") ||
870        (s1 == "C" && s2 == "A") ||
871        (s1 == "A" && s2 == "C"))) {
872         g = 1;
873         t = s.substr(0, b * 3);
874         t += s.substr(b * 3 + 6, s.length() - (b * 3 + 6));
875         // change the mov[] array if necessary
876         if (mov[0] == -1) {
877           h[0] = 0; h[1] = 0;
878           for (int i = 1; i <= MOV; i++) {
879             for (int k = 0; k <= 1; k++) {
880               if ((b+k+1) <= mvs[i] && (b+k+1) > mvs[i-1] && h[k] == 0) {
881                 mov[i]--; h[k] = 1;
882                 for (int j = i; j <= MOV; j++) mvs[j]--;
883               }
884             }
885           }
886         }
887         //
888         s = t;
889         b = b - 2; if (b < -1) b = -1;
890       }
891       b++;
892     }
893     // ok now it will run again if necessary, and then return the new concise string.
894   }
895   return s;
896 }
897 // complicated string analysis to shorten solution...
Efficient(string a)898 const string Cubex::Efficient(string a)
899 {
900   string s = a;
901 // to be continued some day..........
902   return s;
903 }
904 // Top Edges (step 1)
TopEdges()905 const string Cubex::TopEdges()
906 {
907   string s = "";
908   if (!cubeinit) return s;
909   string a = ""; int b = 0, e, f, f1, m = 0;
910   while (!(FindEdge(1, 2) == 2 && FindEdge(2, 1) == -3 &&
911    FindEdge(1, 3) == 2 && FindEdge(3, 1) == -1 &&
912    FindEdge(1, 4) == 2 && FindEdge(4, 1) == 3 &&
913    FindEdge(1, 5) == 2 && FindEdge(5, 1) == 1)) {
914     for (int i = 2; i <= b; i++) CR();
915     if (b > 0) { s += "CR."; CR(); }
916     b++; if (b > 4) b = 1;
917     switch (b) {
918       case 1: e = 2; break;
919       case 2: e = 3; break;
920       case 3: e = 4; break;
921       case 4: e = 5; break;
922     }
923     f = FindEdge(1, e); f1 = FindEdge(e, 1);
924     switch (f) {
925       case 2:
926         switch (f1) {
927           case 3:
928             s += "BC.BC.DL.DL.FC.FC.";
929             BC(); BC(); DL(); DL(); FC(); FC(); break;
930           case -1:
931             s += "LD.LD.DR.FC.FC.";
932             LD(); LD(); DR(); FC(); FC(); break;
933           case 1:
934             s += "RD.RD.DL.FC.FC.";
935             RD(); RD(); DL(); FC(); FC(); break;
936         }
937         break;
938       case -2:
939         switch (f1) {
940           case 3:
941             s += "DL.DL.";
942             DL(); DL(); break;
943           case -1:
944             s += "DR.";
945             DR(); break;
946           case 1:
947             s += "DL.";
948             DL(); break;
949         }
950         s += "FC.FC.";
951         FC(); FC();
952         break;
953       case 1:
954         switch (f1) {
955           case -3:
956             s += "FA.";
957             FA(); break;
958           case 3:
959             s += "RU.RU.FA.RD.RD.";
960             RU(); RU(); FA(); RD(); RD(); break;
961           case -2:
962             s += "RU.FA.RD.";
963             RU(); FA(); RD(); break;
964           case 2:
965             s += "RD.FA.";
966             RD(); FA(); break;
967         }
968         break;
969       case -1:
970         switch (f1) {
971           case -3:
972             s += "FC.";
973             FC(); break;
974           case 3:
975             s += "LU.LU.FC.LD.LD.";
976             LU(); LU(); FC(); LD(); LD(); break;
977           case -2:
978             s += "LU.FC.LD.";
979             LU(); FC(); LD(); break;
980           case 2:
981             s += "LD.FC.";
982             LD(); FC(); break;
983         }
984         break;
985       case 3:
986         switch (f1) {
987           case -2:
988             s += "DL.RU.FA.RD.";
989             DL(); RU(); FA(); RD(); break;
990           case 2:
991             s += "BC.BC.DL.RU.FA.RD.";
992             BC(); BC(); DL(); RU(); FA(); RD(); break;
993           case -1:
994             s += "LU.DR.FC.FC.LD.";
995             LU(); DR(); FC(); FC(); LD(); break;
996           case 1:
997             s += "RU.DL.FC.FC.RD.";
998             RU(); DL(); FC(); FC(); RD(); break;
999         }
1000         break;
1001       case -3:
1002         switch (f1) {
1003           case -2:
1004             s += "DR.RU.FA.RD.";
1005             DR(); RU(); FA(); RD(); break;
1006           case 2:
1007             s += "FC.RD.DL.FC.FC.RU.";
1008             FC(); RD(); DL(); FC(); FC(); RU(); break;
1009           case -1:
1010             s += "LD.DR.FC.FC.LU.";
1011             LD(); DR(); FC(); FC(); LU(); break;
1012           case 1:
1013             s += "RD.DL.FC.FC.RU.";
1014             RD(); DL(); FC(); FC(); RU(); break;
1015         }
1016         break;
1017     }
1018     switch (b) {
1019       case 1: a = ""; break;
1020       case 2: a = "CL."; CL(); break;
1021       case 3: a = "CL.CL."; CL(); CL(); break;
1022       case 4: a = "CR."; CR(); break;
1023     }
1024     m++; if (m > 255) { cubeinit = false; s = ""; return s; }
1025   }
1026   s += a;
1027   if (shorten) s = Concise(s);
1028   mov[1] = s.length() / 3;
1029   return s;
1030 }
1031 // Top Corners (step 2)
TopCorners()1032 const string Cubex::TopCorners()
1033 {
1034   string s = "";
1035   if (!cubeinit) return s;
1036   string a = ""; int b = 0, c, c1, f, f1, f2, m = 0;
1037   while (!(FindCorn(1, 2, 5) == 2 && FindCorn(2, 1, 5) == -3 &&
1038    FindCorn(1, 3, 2) == 2 && FindCorn(3, 1, 2) == -1 &&
1039    FindCorn(1, 4, 3) == 2 && FindCorn(4, 1, 3) == 3 &&
1040    FindCorn(1, 5, 4) == 2 && FindCorn(5, 1, 4) == 1)) {
1041     for (int i = 2; i <= b; i++) CR();
1042     if (b > 0) { s += "CR."; CR(); }
1043     b++; if (b > 4) b = 1;
1044     switch (b) {
1045       case 1: c = 2; c1 = 5; break;
1046       case 2: c = 3; c1 = 2; break;
1047       case 3: c = 4; c1 = 3; break;
1048       case 4: c = 5; c1 = 4; break;
1049     }
1050     f = FindCorn(1, c, c1); f1 = FindCorn(c, 1, c1); f2 = FindCorn(c1, 1, c);
1051     switch (f) {
1052       case 2:
1053         switch (f1) {
1054           case 3:
1055             s += "BA.DL.BC.DR.RD.DR.RU.";
1056             BA(); DL(); BC(); DR(); RD(); DR(); RU(); break;
1057           case -1:
1058             s += "LD.DR.LU.RD.DL.RU.";
1059             LD(); DR(); LU(); RD(); DL(); RU(); break;
1060           case 1:
1061             s += "BC.DL.BA.FC.DR.FA.";
1062             BC(); DL(); BA(); FC(); DR(); FA(); break;
1063         }
1064         break;
1065       case -2:
1066         switch (f1) {
1067           case -3:
1068             s += "DR.";
1069             DR(); break;
1070           case 3:
1071             s += "DL.";
1072             DL(); break;
1073           case -1:
1074             s += "DL.DL.";
1075             DL(); DL(); break;
1076         }
1077         s += "FC.DL.FA.DR.RD.DR.RU.";
1078         FC(); DL(); FA(); DR(); RD(); DR(); RU();
1079         break;
1080       case 1:
1081         switch (f1) {
1082           case -3:
1083             s += "RD.DL.RU.";
1084             RD(); DL(); RU(); break;
1085           case 3:
1086             s += "RU.DR.RD.DR.RD.DR.RU.";
1087             RU(); DR(); RD(); DR(); RD(); DR(); RU(); break;
1088           case -2:
1089             s += "DL.FC.DR.FA.";
1090             DL(); FC(); DR(); FA(); break;
1091           case 2:
1092             s += "RD.DL.RU.DR.RD.DL.RU.";
1093             RD(); DL(); RU(); DR(); RD(); DL(); RU(); break;
1094         }
1095         break;
1096       case -1:
1097         switch (f1) {
1098           case -3:
1099             s += "LD.DR.LU.FC.DR.FA.";
1100             LD(); DR(); LU(); FC(); DR(); FA(); break;
1101           case 3:
1102             s += "DL.FC.DL.FA.";
1103             DL(); FC(); DL(); FA(); break;
1104           case -2:
1105             s += "RD.DR.RU.";
1106             RD(); DR(); RU(); break;
1107           case 2:
1108             s += "LU.DL.LD.FC.DL.FA.";
1109             LU(); DL(); LD(); FC(); DL(); FA(); break;
1110         }
1111         break;
1112       case 3:
1113         switch (f1) {
1114           case -2:
1115             s += "DR.RD.DR.RU.";
1116             DR(); RD(); DR(); RU(); break;
1117           case 2:
1118             s += "BC.FC.DL.BA.FA.";
1119             BC(); FC(); DL(); BA(); FA(); break;
1120           case -1:
1121             s += "BA.DR.BC.RD.DR.RU.";
1122             BA(); DR(); BC(); RD(); DR(); RU(); break;
1123           case 1:
1124             s += "FC.DL.FA.";
1125             FC(); DL(); FA(); break;
1126         }
1127         break;
1128       case -3:
1129         switch (f1) {
1130           case -2:
1131             s += "FC.DR.FA.";
1132             FC(); DR(); FA(); break;
1133           case 2:
1134             s += "FA.DL.FC.DL.FC.DL.FA.";
1135             FA(); DL(); FC(); DL(); FC(); DL(); FA(); break;
1136           case -1:
1137             s += "DR.RD.DL.RU.";
1138             DR(); RD(); DL(); RU(); break;
1139           case 1:
1140             s += "FC.DR.FA.DL.FC.DR.FA.";
1141             FC(); DR(); FA(); DL(); FC(); DR(); FA(); break;
1142         }
1143         break;
1144     }
1145     switch (b) {
1146       case 1: a = ""; break;
1147       case 2: a = "CL."; CL(); break;
1148       case 3: a = "CL.CL."; CL(); CL(); break;
1149       case 4: a = "CR."; CR(); break;
1150     }
1151     m++; if (m > 255) { cubeinit = false; s = ""; return s; }
1152   }
1153   s += a;
1154   if (shorten) s = Concise(s);
1155   mov[2] = s.length() / 3;
1156   return s;
1157 }
1158 // Middle Edges (step 3)
MiddleEdges()1159 const string Cubex::MiddleEdges()
1160 {
1161   string s = "";
1162   if (!cubeinit) return s;
1163   string a = ""; int b = 0, e, e1, f, f1, m = 0;
1164   while (!(FindEdge(2, 5) == -3 && FindEdge(5, 2) == 1 &&
1165    FindEdge(3, 2) == -1 && FindEdge(2, 3) == -3 &&
1166    FindEdge(4, 3) == 3 && FindEdge(3, 4) == -1 &&
1167    FindEdge(5, 4) == 1 && FindEdge(4, 5) == 3)) {
1168     for (int i = 2; i <= b; i++) CR();
1169     if (b > 0) { s += "CR."; CR(); }
1170     b++; if (b > 4) b = 1;
1171     switch (b) {
1172       case 1: e = 2; e1 = 5; break;
1173       case 2: e = 3; e1 = 2; break;
1174       case 3: e = 4; e1 = 3; break;
1175       case 4: e = 5; e1 = 4; break;
1176     }
1177     a = "";
1178     f = FindEdge(e, e1); f1 = FindEdge(e1, e);
1179     while (!(f == -2 || f1 == -2)) {
1180       if (f == -1 && f1 == -3) { a = "CR."; CR(); }
1181       if (f == -1 && f1 == 3) { a = "CL.CL."; CL(); CL(); }
1182       if (f == 1 && f1 == 3) { a = "CL."; CL(); }
1183       if (f == -3 && f1 == -1) { a = "CR."; CR(); }
1184       if (f == 3 && f1 == -1) { a = "CL.CL."; CL(); CL(); }
1185       if (f == 3 && f1 == 1) { a = "CL."; CL(); }
1186       s += a; s += "RD.DR.RU.DR.FC.DL.FA.";
1187       RD(); DR(); RU(); DR(); FC(); DL(); FA();
1188       if (a == "CL.") { s += "CR."; CR(); }
1189       if (a == "CL.CL.") { s += "CR.CR."; CR(); CR(); }
1190       if (a == "CR.") { s += "CL."; CL(); }
1191       a = "";
1192       f = FindEdge(e,  e1); f1 = FindEdge(e1, e);
1193     }
1194     if (f == -2) {
1195       switch (f1) {
1196         case -3:
1197           s += "DL.DL."; DL(); DL(); break;
1198         case -1:
1199           s += "DL."; DL(); break;
1200         case 1:
1201           s += "DR."; DR(); break;
1202       }
1203       s += "FC.DL.FA.DL.RD.DR.RU.";
1204       FC(); DL(); FA(); DL(); RD(); DR(); RU();
1205     }
1206     else if (f1 == -2) {
1207       switch (f) {
1208         case -3:
1209           s += "DL."; DL(); break;
1210         case 3:
1211           s += "DR."; DR(); break;
1212         case 1:
1213           s += "DL.DL."; DL(); DL(); break;
1214       }
1215       s += "RD.DR.RU.DR.FC.DL.FA.";
1216       RD(); DR(); RU(); DR(); FC(); DL(); FA();
1217     }
1218     switch (b) {
1219       case 1: a = ""; break;
1220       case 2: a = "CL."; CL(); break;
1221       case 3: a = "CL.CL."; CL(); CL(); break;
1222       case 4: a = "CR."; CR(); break;
1223     }
1224     m++; if (m > 255) { cubeinit = false; s = ""; return s; }
1225   }
1226   s += a;
1227   if (shorten) s = Concise(s);
1228   mov[3] = s.length() / 3;
1229   return s;
1230 }
1231 // Bottom Edges Orient (step 4)
BottomEdgesOrient()1232 const string Cubex::BottomEdgesOrient()
1233 {
1234   string s = "";
1235   if (!cubeinit) return s;
1236   int eo[4], a = 0, b, m = 0, r;
1237   while (a != 4) {
1238     eo[0] = Cub[0+2][-2+2][-1+2];
1239     eo[1] = Cub[-1+2][-2+2][0+2];
1240     eo[2] = Cub[0+2][-2+2][1+2];
1241     eo[3] = Cub[1+2][-2+2][0+2];
1242     a = 0; r = 0;
1243     for (int i = 0; i <= 3; i++) {
1244       b = i + 1; if (b > 3) b = 0;
1245       if (eo[i] == 6) {
1246         a++;
1247         if (eo[b] == 6) r = i;
1248       }
1249     }
1250     if (a == 0) {
1251       s += "RD.BC.DL.BA.DR.RU.";
1252       RD(); BC(); DL(); BA(); DR(); RU();
1253     }
1254     else if (a == 2) {
1255       switch (r) {
1256         case 1:
1257           s += "CR."; CR(); break;
1258         case 2:
1259           s += "CL.CL."; CL(); CL(); break;
1260         case 3:
1261           s += "CL."; CL(); break;
1262       }
1263       s += "RD.DL.BC.DR.BA.RU.";
1264       RD(); DL(); BC(); DR(); BA(); RU();
1265       switch (r) {
1266         case 1:
1267           s += "CL."; CL(); break;
1268         case 2:
1269           s += "CR.CR."; CR(); CR(); break;
1270         case 3:
1271           s += "CR."; CR(); break;
1272       }
1273     }
1274     m++; if (m > 255) { cubeinit = false; s = ""; return s; }
1275   }
1276   if (shorten) s = Concise(s);
1277   mov[4] = s.length() / 3;
1278   return s;
1279 }
1280 // Bottom Edges Position (step 5)
BottomEdgesPosition()1281 const string Cubex::BottomEdgesPosition()
1282 {
1283   string s = "";
1284   if (!cubeinit) return s;
1285   int ep[4][2], a = 0, b, l, m = 0, t = 0;
1286   while (a != 4) {
1287     ep[0][0] = Cub[0+2][0+2][-2+2]; ep[0][1] = Cub[0+2][-1+2][-2+2];
1288     ep[1][0] = Cub[-2+2][0+2][0+2]; ep[1][1] = Cub[-2+2][-1+2][0+2];
1289     ep[2][0] = Cub[0+2][0+2][2+2]; ep[2][1] = Cub[0+2][-1+2][2+2];
1290     ep[3][0] = Cub[2+2][0+2][0+2]; ep[3][1] = Cub[2+2][-1+2][0+2];
1291     a = 0; l = 0;
1292     for (int i = 0; i <= 3; i++) {
1293       b = i - 1; if (b < 0) b = 3;
1294       if (ep[i][0] == ep[i][1]) {
1295         a++;
1296       }
1297       else {
1298         if (ep[b][0] != ep[b][1]) l = i;
1299       }
1300     }
1301     if (a < 2) {
1302       t++; if (t > 3) t = 0;
1303       DL();
1304     }
1305     else {
1306       switch (t) {
1307         case 1:
1308           s += "DL."; break;
1309         case 2:
1310           s += "DL.DL."; break;
1311         case 3:
1312           s += "DR."; break;
1313       }
1314       t = 0;
1315     }
1316     if (a == 2) {
1317       switch (l) {
1318         case 1:
1319           s += "CR."; CR(); break;
1320         case 2:
1321           s += "CL.CL."; CL(); CL(); break;
1322         case 3:
1323           s += "CL."; CL(); break;
1324       }
1325       s += "RD.DL.DL.RU.DR.RD.DR.RU.";
1326       RD(); DL(); DL(); RU(); DR(); RD(); DR(); RU();
1327       switch (l) {
1328         case 1:
1329           s += "CL."; CL(); break;
1330         case 2:
1331           s += "CR.CR."; CR(); CR(); break;
1332         case 3:
1333           s += "CR."; CR(); break;
1334       }
1335     }
1336     m++; if (m > 255) { cubeinit = false; s = ""; return s; }
1337   }
1338   if (shorten) s = Concise(s);
1339   mov[5] = s.length() / 3;
1340   return s;
1341 }
1342 // Bottom Corners Position (step 6)
BottomCornersPosition()1343 const string Cubex::BottomCornersPosition()
1344 {
1345   string s = "";
1346   if (!cubeinit) return s;
1347   int cp[4][2], a = 0, l, m = 0;
1348   while (a != 4) {
1349     cp[0][0] = FindCorn(6, 2, 3); cp[0][1] = (fx < 0 && fy < 0 && fz < 0);
1350     cp[1][0] = FindCorn(6, 3, 4); cp[1][1] = (fx < 0 && fy < 0 && fz > 0);
1351     cp[2][0] = FindCorn(6, 4, 5); cp[2][1] = (fx > 0 && fy < 0 && fz > 0);
1352     cp[3][0] = FindCorn(6, 5, 2); cp[3][1] = (fx > 0 && fy < 0 && fz < 0);
1353     a = 0; l = 0;
1354     for (int i = 0; i <= 3; i++) {
1355       if (cp[i][1] == 1) {
1356         a++; l = i;
1357       }
1358     }
1359     if (a < 4) {
1360       switch (l) {
1361         case 1:
1362           s += "CR."; CR(); break;
1363         case 2:
1364           s += "CL.CL."; CL(); CL(); break;
1365         case 3:
1366           s += "CL."; CL(); break;
1367       }
1368       s += "RD.DR.LD.DL.RU.DR.LU.DL.";
1369       RD(); DR(); LD(); DL(); RU(); DR(); LU(); DL();
1370       switch (l) {
1371         case 1:
1372           s += "CL."; CL(); break;
1373         case 2:
1374           s += "CR.CR."; CR(); CR(); break;
1375         case 3:
1376           s += "CR."; CR(); break;
1377       }
1378       m++; if (m > 255) { cubeinit = false; s = ""; return s; }
1379     }
1380   }
1381   if (shorten) s = Concise(s);
1382   mov[6] = s.length() / 3;
1383   return s;
1384 }
1385 // Bottom Corners Orient (step 7)
BottomCornersOrient()1386 const string Cubex::BottomCornersOrient()
1387 {
1388   string s = "";
1389   if (!cubeinit) return s;
1390   int co[4], a = -1, b, b1, b2, d, m = 0, r;
1391   while (a != 0) {
1392     co[0] = FindCorn(6, 2, 5);
1393     co[1] = FindCorn(6, 3, 2);
1394     co[2] = FindCorn(6, 4, 3);
1395     co[3] = FindCorn(6, 5, 4);
1396     a = 0; r = 0; d = 0;
1397     for (int i = 0; i <= 3; i++) {
1398       if (co[i] != -2) a++;
1399     }
1400     if (a > 0) {
1401       for (int i = 0; i <= 3; i++) {
1402         b = i + 2; if (b > 3) b = b - 4;
1403         b1 = i - 1; if (b1 < 0) b1 = 3;
1404         b2 = i + 1; if (b2 > 3) b2 = 0;
1405         if (co[i] != -2) {
1406           switch (a) {
1407             case 2:
1408               if (co[b1] != -2) r = i;
1409               if (co[b] != -2 && (co[i] == 1 || co[i] == -1)) {
1410                 d = 1; if (i == 0) r = 0; else r = i - 1;
1411               }
1412               break;
1413             case 3:
1414               if (co[b1] != -2 && co[b2] != -2) r = i;
1415               break;
1416             case 4:
1417               if (co[i] == 1 && co[b1] == 1 && i < 2) r = i;
1418               break;
1419           }
1420         }
1421       }
1422       switch (r) {
1423         case 1:
1424           s += "CR."; CR(); break;
1425         case 2:
1426           s += "CL.CL."; CL(); CL(); break;
1427         case 3:
1428           s += "CL."; CL(); break;
1429       }
1430       if (a == 4) {
1431         s += "RD.DL.DL.RU.DR.RD.DR.RU.";
1432         s += "LD.DR.DR.LU.DL.LD.";
1433         s += "DR.LU.DL.LD.DL.LU.";
1434         s += "RD.DL.DL.RU.DR.RD.DR.RU.";
1435         RD(); DL(); DL(); RU(); DR(); RD(); DR(); RU();
1436         LD(); DR(); DR(); LU(); DL(); LD();
1437         DR(); LU(); DL(); LD(); DL(); LU();
1438         RD(); DL(); DL(); RU(); DR(); RD(); DR(); RU();
1439       }
1440       else if (a == 3 && Cub[2+2][-1+2][-1+2] == 6) {
1441         s += "FC.DR.DR.FA.DL.FC.DL.FA.";
1442         s += "BC.DL.DL.BA.DR.BC.DR.BA.";
1443         FC(); DR(); DR(); FA(); DL(); FC(); DL(); FA();
1444         BC(); DL(); DL(); BA(); DR(); BC(); DR(); BA();
1445       }
1446       else if (a == 2 && d == 0 && Cub[1+2][-1+2][-2+2] == 6) {
1447         s += "LD.DR.LU.DR.LD.DL.DL.LU.";
1448         s += "RD.DL.RU.DL.RD.DR.DR.RU.";
1449         LD(); DR(); LU(); DR(); LD(); DL(); DL(); LU();
1450         RD(); DL(); RU(); DL(); RD(); DR(); DR(); RU();
1451       }
1452       else {
1453         s += "RD.DL.DL.RU.DR.RD.DR.RU.";
1454         s += "LD.DR.DR.LU.DL.LD.DL.LU.";
1455         RD(); DL(); DL(); RU(); DR(); RD(); DR(); RU();
1456         LD(); DR(); DR(); LU(); DL(); LD(); DL(); LU();
1457       }
1458       switch (r) {
1459         case 1:
1460           s += "CL."; CL(); break;
1461         case 2:
1462           s += "CR.CR."; CR(); CR(); break;
1463         case 3:
1464           s += "CR."; CR(); break;
1465       }
1466       m++; if (m > 255) { cubeinit = false; s = ""; return s; }
1467     }
1468   }
1469   if (shorten) s = Concise(s);
1470   mov[7] = s.length() / 3;
1471   return s;
1472 }
1473 // Centers Rotation (for bitmapped/picture cubes) (step 8)
CentersRotate()1474 const string Cubex::CentersRotate()
1475 {
1476   string s = "";
1477   if (!cubeinit) return s;
1478   mov[8] = 0;
1479   if (!cenfix) return s;
1480   int a = 0, b, c, d, p;
1481   for (int q = 1; q <= 6; q++) {
1482     a += Cub[0+2][1+2][0+2];
1483     if (q % 2 == 0) XCU(); else XCA();
1484   }
1485   if (a % 2 != 0) { cubeinit = false; s = ""; return s; }
1486   for (int q = 1; q <= 6; q++) {
1487     b = Cub[0+2][1+2][0+2];
1488     switch (b) {
1489       case 2:
1490         // top = 2
1491         s += "UL.RU.LD.UR.UR.RD.LU.";
1492         s += "UL.RU.LD.UR.UR.RD.LU.";
1493         UL(); RU(); LD(); UR(); UR(); RD(); LU();
1494         UL(); RU(); LD(); UR(); UR(); RD(); LU();
1495         break;
1496       case 1:
1497         d = 0;
1498         for (p = 1; p <= 4; p++) {
1499           if (d == 0) {
1500             c = Cub[-1+2][0+2][0+2];
1501             if (c == 3) {
1502               // top = 1, left = 3
1503               s += "MD.MR.MU.UL.MD.ML.MU.UR.";
1504               MD(); MR(); MU(); UL(); MD(); ML(); MU(); UR();
1505               d = 1;
1506             }
1507           }
1508           s += "CL."; XCL();
1509         }
1510         if (d == 0) {
1511           for (p = 1; p <= 4; p++) {
1512             if (d == 0) {
1513               c = Cub[-1+2][0+2][0+2];
1514               if (c == 1) {
1515                 // top = 1, left = 1
1516                 s += "CC.";
1517                 s += "UL.RU.LD.UR.UR.RD.LU.";
1518                 s += "UL.RU.LD.UR.UR.RD.LU.";
1519                 s += "CA.";
1520                 s += "MD.MR.MU.UL.MD.ML.MU.UR.";
1521                 CC();
1522                 UL(); RU(); LD(); UR(); UR(); RD(); LU();
1523                 UL(); RU(); LD(); UR(); UR(); RD(); LU();
1524                 CA();
1525                 MD(); MR(); MU(); UL(); MD(); ML(); MU(); UR();
1526                 d = 1;
1527               }
1528             }
1529             s += "CL."; XCL();
1530           }
1531         }
1532         if (d == 0) {
1533           c = Cub[0+2][-1+2][0+2];
1534           switch (c) {
1535             case 3:
1536               // top = 1, bottom = 3
1537               s += "CC.";
1538               s += "MD.MR.MU.UL.MD.ML.MU.UR.";
1539               s += "CA.";
1540               s += "MD.MR.MU.UL.MD.ML.MU.UR.";
1541               CC();
1542               MD(); MR(); MU(); UL(); MD(); ML(); MU(); UR();
1543               CA();
1544               MD(); MR(); MU(); UL(); MD(); ML(); MU(); UR();
1545               break;
1546             case 1:
1547               // top = 1, bottom = 1
1548               s += "CC.CC.";
1549               s += "UL.RU.LD.UR.UR.RD.LU.";
1550               s += "UL.RU.LD.UR.UR.RD.LU.";
1551               s += "CA.";
1552               s += "MD.MR.MU.UL.MD.ML.MU.UR.";
1553               s += "CA.";
1554               s += "MD.MR.MU.UL.MD.ML.MU.UR.";
1555               CC(); CC();
1556               UL(); RU(); LD(); UR(); UR(); RD(); LU();
1557               UL(); RU(); LD(); UR(); UR(); RD(); LU();
1558               CA();
1559               MD(); MR(); MU(); UL(); MD(); ML(); MU(); UR();
1560               CA();
1561               MD(); MR(); MU(); UL(); MD(); ML(); MU(); UR();
1562               break;
1563           }
1564         }
1565         break;
1566       case 3:
1567         d = 0;
1568         for (p = 1; p <= 4; p++) {
1569           if (d == 0) {
1570             c = Cub[1+2][0+2][0+2];
1571             if (c == 1) {
1572               // top = 3, right = 1
1573               s += "MD.ML.MU.UR.MD.MR.MU.UL.";
1574               MD(); ML(); MU(); UR(); MD(); MR(); MU(); UL();
1575               d = 1;
1576             }
1577           }
1578           s += "CL."; XCL();
1579         }
1580         if (d == 0) {
1581           for (p = 1; p <= 4; p++) {
1582             if (d == 0) {
1583               c = Cub[1+2][0+2][0+2];
1584               if (c == 3) {
1585                 // top = 3, right = 3
1586                 s += "CA.";
1587                 s += "UL.RU.LD.UR.UR.RD.LU.";
1588                 s += "UL.RU.LD.UR.UR.RD.LU.";
1589                 s += "CC.";
1590                 s += "MD.ML.MU.UR.MD.MR.MU.UL.";
1591                 CA();
1592                 UL(); RU(); LD(); UR(); UR(); RD(); LU();
1593                 UL(); RU(); LD(); UR(); UR(); RD(); LU();
1594                 CC();
1595                 MD(); ML(); MU(); UR(); MD(); MR(); MU(); UL();
1596                 d = 1;
1597               }
1598             }
1599             s += "CL."; XCL();
1600           }
1601         }
1602         if (d == 0) {
1603           c = Cub[0+2][-1+2][0+2];
1604           switch (c) {
1605             case 1:
1606               // top = 3, bottom = 1
1607               s += "CA.";
1608               s += "MD.ML.MU.UR.MD.MR.MU.UL.";
1609               s += "CC.";
1610               s += "MD.ML.MU.UR.MD.MR.MU.UL.";
1611               CA();
1612               MD(); ML(); MU(); UR(); MD(); MR(); MU(); UL();
1613               CC();
1614               MD(); ML(); MU(); UR(); MD(); MR(); MU(); UL();
1615               break;
1616             case 3:
1617               // top = 3, bottom = 3
1618               s += "CA.CA.";
1619               s += "UL.RU.LD.UR.UR.RD.LU.";
1620               s += "UL.RU.LD.UR.UR.RD.LU.";
1621               s += "CC.";
1622               s += "MD.ML.MU.UR.MD.MR.MU.UL.";
1623               s += "CC.";
1624               s += "MD.ML.MU.UR.MD.MR.MU.UL.";
1625               CA(); CA();
1626               UL(); RU(); LD(); UR(); UR(); RD(); LU();
1627               UL(); RU(); LD(); UR(); UR(); RD(); LU();
1628               CC();
1629               MD(); ML(); MU(); UR(); MD(); MR(); MU(); UL();
1630               CC();
1631               MD(); ML(); MU(); UR(); MD(); MR(); MU(); UL();
1632               break;
1633           }
1634         }
1635         break;
1636     }
1637     if (q % 2 == 0) {
1638       s += "CU."; XCU();
1639     }
1640     else {
1641       s += "CA."; XCA();
1642     }
1643   }
1644   if (shorten) s = Concise(s);
1645   mov[8] = s.length() / 3;
1646   return s;
1647 }
1648 // solve the cube (uses many other routines also)
1649 // slightly complicated...
SolveCube()1650 const int Cubex::SolveCube()
1651 {
1652   // make sure cube was initialized
1653   if (!cubeinit) return 1;
1654   // set up buffers and counters and such...
1655   int Rub[5][5][5], Fac[7][2], mvs[MOV+1], m = -1, n;
1656   string s = ""; string t = ""; string p = "";
1657   // make sure that the cube has the proper cubelets...
1658   cubeinit = false;
1659   // check that all the centers are present
1660   for (int i = 1; i <= 6; i++) {
1661     if (FindCent(i) == 0) {
1662       erval = 1; return erval;
1663     }
1664   }
1665   // buffer the cube so we can interpolate it to a specific color arrangement to check for edges and corners...
1666   for (int i = -2; i <= 2; i++) {
1667     for (int j = -2; j <= 2; j++) {
1668       for (int k = -2; k <= 2; k++) {
1669         Rub[i+2][j+2][k+2] = Cub[i+2][j+2][k+2];
1670       }
1671     }
1672   }
1673   // interpolate the cube...
1674   Fac[0][0] = 0;
1675   Fac[1][0] = Cub[0+2][2+2][0+2]; Fac[2][0] = Cub[0+2][0+2][-2+2];
1676   Fac[3][0] = Cub[-2+2][0+2][0+2]; Fac[4][0] = Cub[0+2][0+2][2+2];
1677   Fac[5][0] = Cub[2+2][0+2][0+2]; Fac[6][0] = Cub[0+2][-2+2][0+2];
1678   for (int i = 0; i <= 6; i++) {
1679     Fac[Fac[i][0]][1] = i;
1680   }
1681   // apply interpolation
1682   for (int i = -1; i <= 1; i++) {
1683     for (int j = -1; j <= 1; j++) {
1684       Cub[i+2][2+2][j+2] = Fac[Cub[i+2][2+2][j+2]][1];
1685       Cub[i+2][j+2][-2+2] = Fac[Cub[i+2][j+2][-2+2]][1];
1686       Cub[-2+2][i+2][j+2] = Fac[Cub[-2+2][i+2][j+2]][1];
1687       Cub[i+2][j+2][2+2] = Fac[Cub[i+2][j+2][2+2]][1];
1688       Cub[2+2][i+2][j+2] = Fac[Cub[2+2][i+2][j+2]][1];
1689       Cub[i+2][-2+2][j+2] = Fac[Cub[i+2][-2+2][j+2]][1];
1690     }
1691   }
1692   // check that all edges and corners are present
1693   for (int i = 1; i <= 4; i++) {
1694     int j = 1;
1695     if (i < 4) j = i + 1;
1696     if (FindEdge(1, i + 1) == 0 ||
1697      FindEdge(6, i + 1) == 0 ||
1698      FindEdge(i + 1, j + 1) == 0 ||
1699      FindCorn(1, i + 1, j + 1) == 0 ||
1700      FindCorn(6, i + 1, j + 1) == 0) {
1701       m = 0;
1702     }
1703   }
1704   // return cube to pre-interpolated status
1705   for (int i = -2; i <= 2; i++) {
1706     for (int j = -2; j <= 2; j++) {
1707       for (int k = -2; k <= 2; k++) {
1708         Cub[i+2][j+2][k+2] = Rub[i+2][j+2][k+2];
1709       }
1710     }
1711   }
1712   // if any flags went off during checking then return error 1 (improper cubelets)
1713   if (m == 0) { erval = 1; return erval; }
1714   cubeinit = true;
1715   // cube seems to have ok cubelets, so try to solve it...
1716   for (int i = 1; i <= MOV; i++) mvs[i] = 0;
1717   // try to solve the cube from each possible starting orientation (to find the fastest solution)...
1718   for (int q = 1; q <= 24; q++) {
1719     // buffer old cube
1720     for (int i = -2; i <= 2; i++) {
1721       for (int j = -2; j <= 2; j++) {
1722         for (int k = -2; k <= 2; k++) {
1723           Rub[i+2][j+2][k+2] = Cub[i+2][j+2][k+2];
1724         }
1725       }
1726     }
1727     // interpolate so that centers are in order...
1728     Fac[0][0] = 0;
1729     Fac[1][0] = Cub[0+2][2+2][0+2]; Fac[2][0] = Cub[0+2][0+2][-2+2];
1730     Fac[3][0] = Cub[-2+2][0+2][0+2]; Fac[4][0] = Cub[0+2][0+2][2+2];
1731     Fac[5][0] = Cub[2+2][0+2][0+2]; Fac[6][0] = Cub[0+2][-2+2][0+2];
1732     for (int i = 0; i <= 6; i++) {
1733       Fac[Fac[i][0]][1] = i;
1734     }
1735     // apply interpolation
1736     for (int i = -1; i <= 1; i++) {
1737       for (int j = -1; j <= 1; j++) {
1738         Cub[i+2][2+2][j+2] = Fac[Cub[i+2][2+2][j+2]][1];
1739         Cub[i+2][j+2][-2+2] = Fac[Cub[i+2][j+2][-2+2]][1];
1740         Cub[-2+2][i+2][j+2] = Fac[Cub[-2+2][i+2][j+2]][1];
1741         Cub[i+2][j+2][2+2] = Fac[Cub[i+2][j+2][2+2]][1];
1742         Cub[2+2][i+2][j+2] = Fac[Cub[2+2][i+2][j+2]][1];
1743         Cub[i+2][-2+2][j+2] = Fac[Cub[i+2][-2+2][j+2]][1];
1744       }
1745     }
1746     // if we dont care about centers, we can imply their orientation liberally
1747     if (!cenfix) {
1748       Cub[0+2][1+2][0+2] = 0;
1749       Cub[0+2][0+2][-1+2] = 0;
1750       Cub[-1+2][0+2][0+2] = 0;
1751       Cub[0+2][0+2][1+2] = 0;
1752       Cub[1+2][0+2][0+2] = 0;
1753       Cub[0+2][-1+2][0+2] = 0;
1754     }
1755     // solve the cube...
1756     t = TopEdges();
1757     t += TopCorners();
1758     t += MiddleEdges();
1759     if (!cubeinit && erval == 0) { erval = 4; }
1760     t += BottomEdgesOrient();
1761     if (!cubeinit && erval == 0) { erval = 5; }
1762     t += BottomEdgesPosition();
1763     if (!cubeinit && erval == 0) { erval = 2; }
1764     t += BottomCornersPosition();
1765     if (!cubeinit && erval == 0) { erval = 6; }
1766     t += BottomCornersOrient();
1767     if (!cubeinit && erval == 0) { erval = 7; }
1768     t += CentersRotate();
1769     if (!cubeinit && erval == 0) { erval = 3; }
1770     // errors above:
1771     // 2-nondescript parity, 3-center orientation, 4-backward centers or corners,
1772     // 5-edge flip parity, 6-edge swap parity, 7-corner rotation parity
1773     if (shorten) {
1774       mov[0] = -1; t = Concise(p + t); mov[0] = 0;
1775     }
1776     t = Efficient(t);
1777     n = t.length() / 3;
1778     // if this was shortest solution found so far, run with it...
1779     if (n < m || m < 0) {
1780       m = n; s = t;
1781       for (int i = 1; i <= MOV; i++) {
1782         mvs[i] = mov[i];
1783       }
1784       // if we dont care about centers, apply the implied orientations
1785       if (!cenfix) {
1786         Rub[0+2][1+2][0+2] = (4 - Cub[0+2][1+2][0+2]) % 4;
1787         Rub[0+2][0+2][-1+2] = (4 - Cub[0+2][0+2][-1+2]) % 4;
1788         Rub[-1+2][0+2][0+2] = (4 - Cub[-1+2][0+2][0+2]) % 4;
1789         Rub[0+2][0+2][1+2] = (4 - Cub[0+2][0+2][1+2]) % 4;
1790         Rub[1+2][0+2][0+2] = (4 - Cub[1+2][0+2][0+2]) % 4;
1791         Rub[0+2][-1+2][0+2] = (4 - Cub[0+2][-1+2][0+2]) % 4;
1792       }
1793     }
1794     // restore old (pre-interpolated) cube
1795     for (int i = -2; i <= 2; i++) {
1796       for (int j = -2; j <= 2; j++) {
1797         for (int k = -2; k <= 2; k++) {
1798           Cub[i+2][j+2][k+2] = Rub[i+2][j+2][k+2];
1799         }
1800       }
1801     }
1802     // rotate to next orientation and try again to see if we get a shorter solution
1803     if (q % 4 == 0) {
1804       p += "CU."; XCU();
1805     }
1806     else {
1807       p += "CL."; XCL();
1808     }
1809     if (q == 12) {
1810       p = "CU.CU.CR."; XCU(); XCU(); XCR();
1811     }
1812     else if (q == 24) {
1813       XCD(); XCD(); XCR();
1814     }
1815   }
1816   // set mov array...
1817   for (int i = 1; i <= MOV; i++) {
1818     mov[i] = mvs[i];
1819   }
1820   // return error if one was found
1821   if (!cubeinit) return erval;
1822   mov[0] = m;
1823   // set solution and return...
1824   solution = s;
1825   return 0;
1826 }
1827 // end of cube class definitions
1828