aboutsummaryrefslogtreecommitdiff
path: root/old
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--old/2020-unknown-date/cube_backup.c527
-rw-r--r--old/2020-unknown-date/cubeutils.c100
-rw-r--r--old/2020-unknown-date/cubeutils.h18
-rw-r--r--old/2020-unknown-date/moves.c57
-rw-r--r--old/2020-unknown-date/moves.h9
-rw-r--r--old/2020-unknown-date/pieces.c208
-rw-r--r--old/2020-unknown-date/pieces.h59
-rw-r--r--old/2021-02-06/cube.c664
-rw-r--r--old/2021-02-06/cube.h60
-rw-r--r--old/2021-02-06/main.c46
-rw-r--r--old/2021-02-06/solve.c177
-rw-r--r--old/2021-02-06/solve.h55
-rw-r--r--old/2021-02-06/utils.c197
-rw-r--r--old/2021-02-06/utils.h70
-rwxr-xr-xold/2021-02-18-piecefilter/compile.sh1
-rwxr-xr-xold/2021-02-18-piecefilter/nissybin0 -> 71872 bytes
-rw-r--r--old/2021-02-18-piecefilter/src/cube.c198
-rw-r--r--old/2021-02-18-piecefilter/src/cube.h45
-rw-r--r--old/2021-02-18-piecefilter/src/main.c47
-rw-r--r--old/2021-02-18-piecefilter/src/moves.c482
-rw-r--r--old/2021-02-18-piecefilter/src/moves.h46
-rw-r--r--old/2021-02-18-piecefilter/src/solve.c179
-rw-r--r--old/2021-02-18-piecefilter/src/solve.h56
-rw-r--r--old/2021-02-18-piecefilter/src/transformations.c103
-rw-r--r--old/2021-02-18-piecefilter/src/transformations.h37
-rw-r--r--old/2021-02-18-piecefilter/src/utils.c197
-rw-r--r--old/2021-02-18-piecefilter/src/utils.h70
-rw-r--r--old/2021-02-28-transformcube-works/src/cube.c271
-rw-r--r--old/2021-02-28-transformcube-works/src/cube.h55
-rw-r--r--old/2021-02-28-transformcube-works/src/main.c57
-rw-r--r--old/2021-02-28-transformcube-works/src/moves.c489
-rw-r--r--old/2021-02-28-transformcube-works/src/moves.h50
-rw-r--r--old/2021-02-28-transformcube-works/src/solve.c180
-rw-r--r--old/2021-02-28-transformcube-works/src/solve.h56
-rw-r--r--old/2021-02-28-transformcube-works/src/transformations.c224
-rw-r--r--old/2021-02-28-transformcube-works/src/transformations.h34
-rw-r--r--old/2021-02-28-transformcube-works/src/utils.c197
-rw-r--r--old/2021-02-28-transformcube-works/src/utils.h70
-rw-r--r--old/2021-05-26-before-restyle/cube.c293
-rw-r--r--old/2021-05-26-before-restyle/cube.h65
-rw-r--r--old/2021-05-26-before-restyle/main.c24
-rw-r--r--old/2021-05-26-before-restyle/moves.c412
-rw-r--r--old/2021-05-26-before-restyle/moves.h51
-rw-r--r--old/2021-05-26-before-restyle/solve.c180
-rw-r--r--old/2021-05-26-before-restyle/solve.h59
-rw-r--r--old/2021-05-26-before-restyle/transformations.c200
-rw-r--r--old/2021-05-26-before-restyle/transformations.h34
-rw-r--r--old/2021-05-26-before-restyle/utils.c197
-rw-r--r--old/2021-05-26-before-restyle/utils.h70
-rw-r--r--old/2021-06-02-cleanedup/cube.c2010
-rw-r--r--old/2021-06-02-cleanedup/cube.h179
-rw-r--r--old/2021-06-02-cleanedup/main.c35
-rw-r--r--old/2021-06-02-cleanedup/steps.h22
-rw-r--r--old/2021-06-14-oldalg/cube.c2849
-rw-r--r--old/2021-06-14-oldalg/cube.h73
-rw-r--r--old/2021-06-14-oldalg/cubetypes.h210
-rw-r--r--old/2021-06-14-oldalg/main.c56
-rw-r--r--old/2021-06-15-before-separating-steps/cube.c2836
-rw-r--r--old/2021-06-15-before-separating-steps/cube.h72
-rw-r--r--old/2021-06-15-before-separating-steps/cubetypes.h201
-rw-r--r--old/2021-06-15-before-separating-steps/main.c60
-rw-r--r--old/2021-06-15-before-separating-steps/steps.h20
-rw-r--r--old/2021-06-17-cachedata/cube.c2738
-rw-r--r--old/2021-06-17-cachedata/cube.h79
-rw-r--r--old/2021-06-17-cachedata/cubetypes.h232
-rw-r--r--old/2021-06-17-cachedata/main.c63
-rw-r--r--old/2021-06-17-cachedata/steps.c327
-rw-r--r--old/2021-06-17-cachedata/steps.h34
-rw-r--r--old/2021-06-23-realizing-bad-tables/HERE1
-rw-r--r--old/2021-06-23-realizing-bad-tables/cube.c2844
-rw-r--r--old/2021-06-23-realizing-bad-tables/cube.h88
-rw-r--r--old/2021-06-23-realizing-bad-tables/cubetypes.h224
-rw-r--r--old/2021-06-23-realizing-bad-tables/main.c70
-rw-r--r--old/2021-06-23-realizing-bad-tables/steps.c486
-rw-r--r--old/2021-06-23-realizing-bad-tables/steps.h42
-rw-r--r--old/2021-06-23-uint16t/cube.c2762
-rw-r--r--old/2021-06-23-uint16t/cube.h87
-rw-r--r--old/2021-06-23-uint16t/cubetypes.h224
-rw-r--r--old/2021-06-30-noreached/cube.c3394
-rw-r--r--old/2021-06-30-noreached/cube.h90
-rw-r--r--old/2021-06-30-noreached/cubetypes.h250
-rw-r--r--old/2021-06-30-noreached/macros.h23
-rw-r--r--old/2021-06-30-noreached/main.c80
-rw-r--r--old/2021-06-30-noreached/steps.c307
-rw-r--r--old/2021-06-30-noreached/steps.h24
-rw-r--r--old/2021-06-30-reached/cube.c3419
-rw-r--r--old/2021-06-30-reached/cube.h90
-rw-r--r--old/2021-06-30-reached/cubetypes.h251
-rw-r--r--old/2021-06-30-reached/macros.h23
-rw-r--r--old/2021-06-30-reached/main.c80
-rw-r--r--old/2021-06-30-reached/steps.c307
-rw-r--r--old/2021-06-30-reached/steps.h24
-rw-r--r--old/2021-07-02-genptable-dfs/cube.c3394
-rw-r--r--old/2021-07-02-genptable-dfs/cube.h90
-rw-r--r--old/2021-07-02-genptable-dfs/cubetypes.h250
-rw-r--r--old/2021-07-02-genptable-dfs/macros.h23
-rw-r--r--old/2021-07-02-genptable-dfs/main.c80
-rw-r--r--old/2021-07-02-genptable-dfs/steps.c307
-rw-r--r--old/2021-07-02-genptable-dfs/steps.h24
-rw-r--r--old/2021-07-15-almostbeforerefactor/README3
-rw-r--r--old/2021-07-15-almostbeforerefactor/alg.c3388
-rw-r--r--old/2021-07-15-almostbeforerefactor/alg.h27
-rw-r--r--old/2021-07-15-almostbeforerefactor/cube.c3391
-rw-r--r--old/2021-07-15-almostbeforerefactor/cube.h79
-rw-r--r--old/2021-07-15-almostbeforerefactor/cubetypes.h252
-rw-r--r--old/2021-07-15-almostbeforerefactor/macros.h23
-rw-r--r--old/2021-07-15-almostbeforerefactor/main.c60
-rwxr-xr-xold/2021-07-15-almostbeforerefactor/nissybin0 -> 92920 bytes
-rw-r--r--old/2021-07-15-almostbeforerefactor/steps.c284
-rw-r--r--old/2021-07-15-almostbeforerefactor/steps.h24
-rw-r--r--old/2021-11-10-beforeremovingchecker/alg.c366
-rw-r--r--old/2021-11-10-beforeremovingchecker/alg.h35
-rw-r--r--old/2021-11-10-beforeremovingchecker/commands.c329
-rw-r--r--old/2021-11-10-beforeremovingchecker/commands.h13
-rw-r--r--old/2021-11-10-beforeremovingchecker/coord.c629
-rw-r--r--old/2021-11-10-beforeremovingchecker/coord.h40
-rw-r--r--old/2021-11-10-beforeremovingchecker/cube.c716
-rw-r--r--old/2021-11-10-beforeremovingchecker/cube.h40
-rw-r--r--old/2021-11-10-beforeremovingchecker/cubetypes.h298
-rw-r--r--old/2021-11-10-beforeremovingchecker/env.c45
-rw-r--r--old/2021-11-10-beforeremovingchecker/env.h15
-rw-r--r--old/2021-11-10-beforeremovingchecker/moves.c474
-rw-r--r--old/2021-11-10-beforeremovingchecker/moves.h16
-rw-r--r--old/2021-11-10-beforeremovingchecker/pf.c80
-rw-r--r--old/2021-11-10-beforeremovingchecker/pf.h18
-rw-r--r--old/2021-11-10-beforeremovingchecker/pruning.c272
-rw-r--r--old/2021-11-10-beforeremovingchecker/pruning.h23
-rw-r--r--old/2021-11-10-beforeremovingchecker/shell.c99
-rw-r--r--old/2021-11-10-beforeremovingchecker/shell.h13
-rw-r--r--old/2021-11-10-beforeremovingchecker/solve.c209
-rw-r--r--old/2021-11-10-beforeremovingchecker/solve.h9
-rw-r--r--old/2021-11-10-beforeremovingchecker/steps.c916
-rw-r--r--old/2021-11-10-beforeremovingchecker/steps.h10
-rw-r--r--old/2021-11-10-beforeremovingchecker/symcoord.c359
-rw-r--r--old/2021-11-10-beforeremovingchecker/symcoord.h15
-rw-r--r--old/2021-11-10-beforeremovingchecker/trans.c372
-rw-r--r--old/2021-11-10-beforeremovingchecker/trans.h13
-rw-r--r--old/2021-11-10-beforeremovingchecker/utils.c274
-rw-r--r--old/2021-11-10-beforeremovingchecker/utils.h41
-rw-r--r--old/backup-manysteps-pretrans/steps.c369
-rw-r--r--old/backup-manysteps-pretrans/steps.h36
-rw-r--r--old/coord.c1014
-rw-r--r--old/coord.h45
-rw-r--r--old/utils.c294
-rw-r--r--old/utils.h59
145 files changed, 53517 insertions, 0 deletions
diff --git a/old/2020-unknown-date/cube_backup.c b/old/2020-unknown-date/cube_backup.c
new file mode 100644
index 0000000..e049edd
--- /dev/null
+++ b/old/2020-unknown-date/cube_backup.c
@@ -0,0 +1,527 @@
1#include <stdio.h>
2#include <string.h>
3#include "cube.h"
4
5/* The next few functions are used to convert from the Cube structure
6 * representation to actual arrays of pieces. */
7void cube_to_ep_array(Cube cube, int ep[12]);
8void cube_to_eofb_array(Cube cube, int eo[12]);
9void cube_to_eorl_array(Cube cube, int eo[12]);
10void cube_to_eoud_array(Cube cube, int eo[12]);
11void cube_to_cp_array(Cube cube, int cp[8]);
12void cube_to_coud_array(Cube cube, int co[8]);
13void cube_to_cofb_array(Cube cube, int co[8]);
14void cube_to_corl_array(Cube cube, int co[8]);
15void cube_to_centerpos_array(Cube cube, int centerpos[6]);
16Cube ep_array_to_cube(int ep[12]);
17Cube eofb_array_to_cube(int eo[12]);
18Cube eorl_array_to_cube(int eo[12]);
19Cube eoud_array_to_cube(int eo[12]);
20Cube cp_array_to_cube(int cp[8]);
21Cube coud_array_to_cube(int co[8]);
22Cube cofb_array_to_cube(int co[8]);
23Cube corl_array_to_cube(int co[8]);
24Cube centerpos_array_to_cube(int centerpos[6]);
25Cube move_array(Cube cube, void (cube_to_arr)(Cube, int *),
26 Cube (*arr_to_cube)(int *),
27 int *perm, int *orient, int n, int m);
28
29
30/* Transition tables */
31int epose_ttable[NMOVES][factorial12/factorial8];
32int eposs_ttable[NMOVES][factorial12/factorial8];
33int eposm_ttable[NMOVES][factorial12/factorial8];
34int eofb_ttable[NMOVES][pow2to11];
35int eorl_ttable[NMOVES][pow2to11];
36int eoud_ttable[NMOVES][pow2to11];
37int cp_ttable[NMOVES][factorial8];
38int coud_ttable[NMOVES][pow3to7];
39int cofb_ttable[NMOVES][pow3to7];
40int corl_ttable[NMOVES][pow3to7];
41int centerpos_ttable[NMOVES][factorial6];
42
43char edge_string[12][5] = {
44 "UF", "UL", "UB", "UR", "DF", "DL", "DB", "DR", "FR", "FL", "BL", "BR"
45};
46char corner_string[8][5] = { "UFR", "UFL", "UBL", "UBR", "DFR", "DFL", "DBL", "DBR" };
47char center_string[6][5] = { "U", "D", "R", "L", "F", "B" };
48char move_string[NMOVES][5] = {
49 "-",
50 "U", "U2", "U\'", "D", "D2", "D\'", "R", "R2", "R\'",
51 "L", "L2", "L\'", "F", "F2", "F\'", "B", "B2", "B\'",
52 "Uw", "Uw2", "Uw\'", "Dw", "Dw2", "Dw\'", "Rw", "Rw2", "Rw\'",
53 "Lw", "Lw2", "Lw\'", "Fw", "Fw2", "Fw\'", "Bw", "Bw2", "Bw\'",
54 "M", "M2", "M\'", "S", "S2", "S\'", "E", "E2", "E\'",
55 "x", "x2", "x\'", "y", "y2", "y\'", "z", "z2", "z\'",
56};
57
58int epe_solved[] = {FR, FL, BL, BR};
59int eps_solved[] = {UL, UR, DL, DR};
60int epm_solved[] = {UF, UB, DF, DB};
61
62/**************************/
63/* Internal use functions */
64/**************************/
65
66int cube_to_ep_array(Cube cube, int ep[12]) {
67 int epe[4], eps[4], epm[4];
68 index_to_perm(cube.epose % factorial(4), 4, epe);
69 index_to_perm(cube.eposs % factorial(4), 4, eps);
70 index_to_perm(cube.eposm % factorial(4), 4, epm);
71
72 int epose[12], eposs[12], eposm[12];
73 index_to_subset(cube.epose / factorial(4), 12, 4, epose);
74 index_to_subset(cube.eposs / factorial(4), 12, 4, eposs);
75 index_to_subset(cube.eposm / factorial(4), 12, 4, eposm);
76 for (int i = 0; i < 4; i++) {
77 swap(&eposs[eps_solved[i]], &eposs[i+8]);
78 swap(&eposm[epm_solved[i]], &eposm[i+8]);
79 }
80
81 for (int i = 0, ie = 0, is = 0, im = 0; i < 12; i++) {
82 if (epose[i]) ep[i] = epe_solved[epe[ie++]];
83 if (eposs[i]) ep[i] = eps_solved[eps[is++]];
84 if (eposm[i]) ep[i] = epm_solved[epm[im++]];
85 }
86}
87
88void cube_to_eofb_array(Cube cube, int eo[12]) {
89 int_to_sum_zero_array(cube.eofb, 2, 12, eo);
90}
91
92void cube_to_eorl_array(Cube cube, int eo[12]) {
93 int_to_sum_zero_array(cube.eorl, 2, 12, eo);
94}
95
96void cube_to_eoud_array(Cube cube, int eo[12]) {
97 int_to_sum_zero_array(cube.eoud, 2, 12, eo);
98}
99
100void cube_to_cp_array(Cube cube, int cp[8]) {
101 index_to_perm(cube.cp, 8, cp);
102}
103
104void cube_to_coud_array(Cube cube, int co[8]) {
105 int_to_sum_zero_array(cube.coud, 3, 8, co);
106}
107
108void cube_to_cofb_array(Cube cube, int co[8]) {
109 int_to_sum_zero_array(cube.cofb, 3, 8, co);
110}
111
112void cube_to_corl_array(Cube cube, int co[8]) {
113 int_to_sum_zero_array(cube.corl, 3, 8, co);
114}
115
116void cube_to_centerpos_array(Cube cube, int centerpos[6]) {
117 index_to_perm(cube.centerpos, 6, centerpos);
118}
119
120Cube ep_array_to_cube(int ep[12]) {
121 int epe[4], eps[4], epm[4];
122 int epose[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
123 int eposs[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
124 int eposm[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
125 for (int i = 0, ie = 0, is = 0, im = 0; i < 12; i++) {
126 for (int j = 0; j < 4; j++) {
127 if (ep[i] == epe_solved[j]) { epe[ie++] = j; epose[i] = 1; }
128 if (ep[i] == eps_solved[j]) { eps[is++] = j; eposs[i] = 1; }
129 if (ep[i] == epm_solved[j]) { epm[im++] = j; eposm[i] = 1; }
130 }
131 }
132 for (int i = 0; i < 4; i++) {
133 swap(&eposs[eps_solved[i]], &eposs[i+8]);
134 swap(&eposm[epm_solved[i]], &eposm[i+8]);
135 }
136 return { .epose = factorial(4) * subset_to_index(epose, 12, 4)
137 + perm_to_index(epe, 4),
138 .eposs = factorial(4) * subset_to_index(eposs, 12, 4)
139 + perm_to_index(eps, 4),
140 .eposm = factorial(4) * subset_to_index(eposm, 12, 4)
141 + perm_to_index(epm, 4) };
142}
143
144Cube eofb_array_to_cube(int eo[12]) {
145 return { .eofb = digit_array_to_int(eo, 11, 2) };
146}
147
148Cube eorl_array_to_cube(int eo[12]) {
149 return { .eorl = digit_array_to_int(eo, 11, 2) };
150}
151
152Cube eoud_array_to_cube(int eo[12]) {
153 return { .eoud = digit_array_to_int(eo, 11, 2) };
154}
155
156Cube cp_array_to_cube(int cp[8]) {
157 return { .cp = perm_to_index(cp, 8) };
158}
159
160Cube coud_array_to_cube(int co[8]) {
161 return { .coud = digit_array_to_int(co, 7, 3) };
162}
163
164Cube cofb_array_to_cube(int co[8]) {
165 return { .cofb = digit_array_to_int(co, 7, 3) };
166}
167
168Cube corl_array_to_cube(int co[8]) {
169 return { .corl = digit_array_to_int(co, 7, 3) };
170}
171
172Cube centerpos_array_to_cube(int centerpos[6]) {
173 return { .centerpos = perm_to_index(centerpos, 6) };
174}
175
176Cube move_array(Cube cube, void (*cube_to_arr)(Cube, int *),
177 void (*arr_to_cube)(int *),
178 int *perm, int *orient, int n, int m) {
179 int arr[n];
180 cube_to_arr(cube, arr);
181 apply_permutation(perm, arr, n);
182 sum_arrays_mod(arr, orient, n, m);
183 return arr_to_cube(arr);
184}
185
186/***********************/
187/* Interface functions */
188/***********************/
189
190Move inverse(Move m) {
191 if (m == NULLMOVE)
192 return m;
193 int mod = (m-1)%3;
194 Move base = m - mod;
195 return base + 2 - mod;
196}
197
198void copy_alg(NissMove *src, NissMove *dest) {
199 for (int i = 0; src[i].m != NULLMOVE; i++)
200 dest[i] = src[i];
201}
202
203bool commute(Move m1, Move m2) {
204 return equal(apply_move(m2, apply_move(m1, {0})),
205 apply_move(m1, apply_move(m2, {0})));
206}
207
208bool equal(Cube c1, Cube c2) {
209 return c1.eofb == c2.eofb && c1.epose == c2.epose &&
210 c1.eposs == c2.eposs && c1.eposm == c2.eposm &&
211 c1.coud == c2.coud && c1.cp == c2.cp &&
212 c1.centerpos == c2.centerpos;
213}
214
215bool solvable(Cube cube) {
216 /* Since we memorize orientation truncating the last digit, we only need to
217 * check that the permutations have the correct sign. */
218 /* TODO: add check that every integer is in range */
219 int ep[12], cp[12], c[6];
220 /* TODO: change to use cube-specific functions */
221 cube_to_ep_array(cube, ep);
222 cube_to_cp_array(cube, 8, cp);
223 cube_to_centerpos_array(cube, 6, c);
224 return (perm_sign(ep, 12) ^ perm_sign(c, 6)) == perm_sign(cp, 8);
225}
226
227bool is_solved(Cube cube) {
228 return (!cube.eofb && !cube.coud && !cube.cp &&
229 !cube.epose && !cube.eposs && !cube.eposm && !cube.centerpos);
230}
231
232char *to_string(Cube cube) {
233 int eo[12], co[8], ep[12], cp[8], cenpos[6];
234 cube_to_eofb_array(cube, eo);
235 cube_to_coud_array(cube, co);
236 cube_to_ep_array(cube, ep);
237 cube_to_cp_array(cube, cp);
238 cube_to_centerpos_array(cube, cenpos);
239
240 static char ret[1000];
241
242 for (int i = 0; i < 12; i++) {
243 strcat(ret, " ");
244 strcat(ret, edge_string[ep[i]]);
245 strcat(ret, " ");
246 }
247 strcat(ret, "\n");
248 for (int i = 0; i < 12; i++) {
249 strcat(ret, " ");
250 char num[2] = { [0] = eo[i] + '0', [1] = 0 };
251 strcat(ret, num);
252 strcat(ret, " ");
253 }
254 strcat(ret, "\n");
255 for (int i = 0; i < 8; i++) {
256 strcat(ret, corner_string[cp[i]]);
257 strcat(ret, " ");
258 }
259 strcat(ret, "\n");
260 for (int i = 0; i < 8; i++) {
261 strcat(ret, " ");
262 char num[2] = { [0] = co[i] + '0', [1] = 0 };
263 strcat(ret, num);
264 strcat(ret, " ");
265 }
266 strcat(ret, "\n");
267 for (int i = 0; i < 6; i++) {
268 strcat(ret, " ");
269 strcat(ret, center_string[cenpos[i]]);
270 strcat(ret, " ");
271 }
272 strcat(ret, "\n");
273
274 return ret;
275}
276
277void init_ttables() {
278 FILE *ttf;
279
280 if ((ttf = fopen("ttables", "rb")) != NULL) {
281 for (int m = 0; m < NMOVES; m++) {
282 fread(epose_ttable[m], sizeof(int), factorial12/factorial8, ttf);
283 fread(eposs_ttable[m], sizeof(int), factorial12/factorial8, ttf);
284 fread(eposm_ttable[m], sizeof(int), factorial12/factorial8, ttf);
285 fread(eofb_ttable[m], sizeof(int), pow2to11, ttf);
286 fread(eorl_ttable[m], sizeof(int), pow2to11, ttf);
287 fread(eoud_ttable[m], sizeof(int), pow2to11, ttf);
288 fread(cp_ttable[m], sizeof(int), factorial8, ttf);
289 fread(coud_ttable[m], sizeof(int), pow3to7, ttf);
290 fread(corl_ttable[m], sizeof(int), pow3to7, ttf);
291 fread(cofb_ttable[m], sizeof(int), pow3to7, ttf);
292 fread(centerpos_ttable[m], sizeof(int), factorial6, ttf);
293 }
294 fclose(ttf);
295 } else {
296 ttf = fopen("ttables", "wb");
297 int empty[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
298 /* For each type of pieces only the effects of U, x and y are described */
299 int edge_cycle[NMOVES][12] = {
300 [U] = {UR, UF, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR},
301 [X] = {DF, FL, UF, FR, DB, BL, UB, BR, DR, DL, UL, UR},
302 [Y] = {UR, UF, UL, UB, DR, DF, DL, DB, BR, FR, FL, BL},
303 };
304 int eofb_flipped[NMOVES][12] = {
305 [X] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 },
306 [Y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 },
307 };
308 int eorl_flipped[NMOVES][12] = {
309 [X] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
310 [Y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 },
311 };
312 int eoud_flipped[NMOVES][12] = {
313 [U] = { [UF] = 1, [UL] = 1, [UB] = 1, [UR] = 1 },
314 [X] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 },
315 [Y] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
316 };
317 int corner_cycle[NMOVES][8] = {
318 [U] = {UBR, UFR, UFL, UBL, DFR, DFL, DBL, DBR},
319 [X] = {DFR, DFL, UFL, UFR, DBR, DBL, UBL, UBR},
320 [Y] = {UBR, UFR, UFL, UBL, DBR, DFR, DFL, DBL},
321 };
322 int coud_flipped[NMOVES][8] = {
323 [X] = {[UFR]=2,[UBR]=1,[DBR]=2,[DFR]=1,[UFL]=1,[UBL]=2,[DBL]=1,[DFL]=2},
324 };
325 int corl_flipped[NMOVES][8] = {
326 [U] = { [UFR] = 1, [UBR] = 2, [UBL] = 1, [UFL] = 2 },
327 [Y] = {[UFR]=1,[UBR]=2,[UBL]=1,[UFL]=2,[DFR]=2,[DBR]=1,[DBL]=2,[DFL]=1},
328 };
329 int cofb_flipped[NMOVES][8] = {
330 [U] = { [UFR] = 2, [UBR] = 1, [UBL] = 2, [UFL] = 1 },
331 [X] = {[UFR]=1,[UBR]=2,[DFR]=2,[DBR]=1,[UBL]=2,[UFL]=1,[DBL]=1,[DFL]=2},
332 [Y] = {[UFR]=2,[UBR]=1,[UBL]=2,[UFL]=1,[DFR]=1,[DBR]=2,[DBL]=1,[DFL]=2},
333 };
334 int center_cycle[NMOVES][6] = {
335 [X] = {F_center, B_center, R_center, L_center, D_center, U_center},
336 [Y] = {U_center, D_center, B_center, F_center, R_center, L_center},
337 };
338
339 /* Each move is reduced to a combination of U, x and y using this table */
340 Move equiv_moves[NMOVES][13] = {
341 [U] = { U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
342 [U2] = { U, U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
343 [U3] = { U, U, U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
344 [D] = { X, X, U, X, X, 0, 0, 0, 0, 0, 0, 0, 0 },
345 [D2] = { X, X, U, U, X, X, 0, 0, 0, 0, 0, 0, 0 },
346 [D3] = { X, X, U, U, U, X, X, 0, 0, 0, 0, 0, 0 },
347 [R] = { Y, X, U, X, X, X, Y, Y, Y, 0, 0, 0, 0 },
348 [R2] = { Y, X, U, U, X, X, X, Y, Y, Y, 0, 0, 0 },
349 [R3] = { Y, X, U, U, U, X, X, X, Y, Y, Y, 0, 0 },
350 [L] = { Y, Y, Y, X, U, X, X, X, Y, 0, 0, 0, 0 },
351 [L2] = { Y, Y, Y, X, U, U, X, X, X, Y, 0, 0, 0 },
352 [L3] = { Y, Y, Y, X, U, U, U, X, X, X, Y, 0, 0 },
353 [F] = { X, U, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0 },
354 [F2] = { X, U, U, X, X, X, 0, 0, 0, 0, 0, 0, 0 },
355 [F3] = { X, U, U, U, X, X, X, 0, 0, 0, 0, 0, 0 },
356 [B] = { X, X, X, U, X, 0, 0, 0, 0, 0, 0, 0, 0 },
357 [B2] = { X, X, X, U, U, X, 0, 0, 0, 0, 0, 0, 0 },
358 [B3] = { X, X, X, U, U, U, X, 0, 0, 0, 0, 0, 0 },
359
360 [Uw] = { X, X, U, X, X, Y, 0, 0, 0, 0, 0, 0, 0 },
361 [Uw2] = { X, X, U, U, X, X, Y, Y, 0, 0, 0, 0, 0 },
362 [Uw3] = { X, X, U, U, U, X, X, Y, Y, Y, 0, 0, 0 },
363 [Dw] = { U, Y, Y, Y, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
364 [Dw2] = { U, U, Y, Y, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
365 [Dw3] = { U, U, U, Y, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
366 [Rw] = { Y, Y, Y, X, U, X, X, X, Y, X, 0, 0, 0 },
367 [Rw2] = { Y, Y, Y, X, U, U, X, X, X, Y, X, X, 0 },
368 [Rw3] = { Y, Y, Y, X, U, U, U, Y, X, X, X, Y, 0 },
369 [Lw] = { Y, X, U, X, X, X, Y, Y, Y, X, X, X, 0 },
370 [Lw2] = { Y, X, U, U, X, X, X, Y, Y, Y, X, X, 0 },
371 [Lw3] = { Y, X, U, U, U, X, X, X, Y, Y, Y, X, 0 },
372 [Fw] = { X, X, X, U, Y, Y, Y, X, 0, 0, 0, 0, 0 },
373 [Fw2] = { X, X, X, U, U, Y, Y, X, 0, 0, 0, 0, 0 },
374 [Fw3] = { X, X, X, U, U, U, Y, X, 0, 0, 0, 0, 0 },
375 [Bw] = { X, U, Y, Y, Y, X, X, X, 0, 0, 0, 0, 0 },
376 [Bw2] = { X, U, U, Y, Y, X, X, X, 0, 0, 0, 0, 0 },
377 [Bw3] = { X, U, U, U, Y, X, X, X, 0, 0, 0, 0, 0 },
378
379 [M] = { Y, X, U, X, X, U, U, U, Y, X, Y, Y, Y },
380 [M2] = { Y, X, U, U, X, X, U, U, X, X, X, Y, 0 },
381 [M3] = { Y, X, U, U, U, X, X, U, Y, X, X, X, Y },
382 [S] = { X, U, U, U, X, X, U, Y, Y, Y, X, 0, 0 },
383 [S2] = { X, U, U, X, X, U, U, Y, Y, X, 0, 0, 0 },
384 [S3] = { X, U, X, X, U, U, U, Y, X, 0, 0, 0, 0 },
385 [E] = { U, X, X, U, U, U, X, X, Y, Y, Y, 0, 0 },
386 [E2] = { U, U, X, X, U, U, X, X, Y, Y, 0, 0, 0 },
387 [E3] = { U, U, U, X, X, U, X, X, Y, 0, 0, 0, 0 },
388
389 [X] = { X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
390 [X2] = { X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
391 [X3] = { X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
392 [Y] = { Y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
393 [Y2] = { Y, Y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
394 [Y3] = { Y, Y, Y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
395 [Z] = { Y, Y, Y, X, Y, 0, 0, 0, 0, 0, 0, 0, 0 },
396 [Z2] = { Y, Y, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
397 [Z3] = { Y, X, Y, Y, Y, 0, 0, 0, 0, 0, 0, 0, 0 },
398 };
399
400 /* Generate all move cycles and flips */
401 for (int i = 0; i < NMOVES; i++) {
402 if (i == U || i == X || i == Y)
403 continue;
404
405 Cube cube = {0};
406
407 cube_to_ep_array(&cube, edge_cycle[i]);
408 cube_to_eofb_array(&cube, eofb_flipped[i]);
409 cube_to_eorl_array(&cube, eorl_flipped[i]);
410 cube_to_eoud_array(&cube, eoud_flipped[i]);
411 cube_to_cp_array(&cube, corner_cycle[i]);
412 cube_to_coud_array(&cube, coud_flipped[i]);
413 cube_to_cofb_array(&cube, cofb_flipped[i]);
414 cube_to_corl_array(&cube, corl_flipped[i]);
415 cube_to_centerpos_array(&cube, center_cycle[i]);
416
417 for (int j = 0; equiv_moves[i][j]; j++) {
418 int m = equiv_moves[i][j];
419
420 apply_permutation(edge_cycle[m], edge_cycle[i], 12);
421 apply_permutation(edge_cycle[m], eofb_flipped[i], 12);
422 apply_permutation(edge_cycle[m], eorl_flipped[i], 12);
423 apply_permutation(edge_cycle[m], eoud_flipped[i], 12);
424
425 sum_arrays_mod(eofb_flipped[i], eofb_flipped[m], 12, 2);
426 sum_arrays_mod(eorl_flipped[i], eorl_flipped[m], 12, 2);
427 sum_arrays_mod(eoud_flipped[i], eoud_flipped[m], 12, 2);
428
429 apply_permutation(corner_cycle[m], corner_cycle[i], 8);
430 apply_permutation(corner_cycle[m], coud_flipped[i], 8);
431 apply_permutation(corner_cycle[m], cofb_flipped[i], 8);
432 apply_permutation(corner_cycle[m], corl_flipped[i], 8);
433
434 sum_arrays_mod(coud_flipped[i], coud_flipped[m], 8, 3);
435 sum_arrays_mod(corl_flipped[i], corl_flipped[m], 8, 3);
436 sum_arrays_mod(cofb_flipped[i], cofb_flipped[m], 8, 3);
437
438 apply_permutation(center_cycle[m], center_cycle[i], 6);
439 }
440 }
441
442 /* Initialize transition tables */
443 for (int m = 0; m < NMOVES; m++) {
444 for (int i = 0; i < factorial12/factorial8; i++) {
445 Cube cube = { .epose = i };
446 move_array(&cube, cube_to_ep_array, ep_array_to_cube,
447 edge_cycle[m], empty, 12, 1);
448 epose_ttable[m][i] = cube.epose;
449 cube.eposs = i;
450 move_array(&cube, cube_to_ep_array, ep_array_to_cube,
451 edge_cycle[m], empty, 12, 1);
452 eposs_ttable[m][i] = cube.eposs;
453 cube.eposm = i;
454 move_array(&cube, cube_to_ep_array, ep_array_to_cube,
455 edge_cycle[m], empty, 12, 1);
456 eposm_ttable[m][i] = cube.eposm;
457 }
458 for (int i = 0; i < pow2to11; i++ ) {
459 Cube cube = { .eofb = i, .eorl = i, .eoud = i };
460 move_array(&cube, cube_to_eofb_array, eofb_array_to_cube,
461 edge_cycle[m], eofb_flipped[m], 12, 2);
462 move_array(&cube, cube_to_eorl_array, eorl_array_to_cube,
463 edge_cycle[m], eorl_flipped[m], 12, 2);
464 move_array(&cube, cube_to_eoud_array, eoud_array_to_cube,
465 edge_cycle[m], eoud_flipped[m], 12, 2);
466 eofb_ttable[m][i] = cube.eofb;
467 eorl_ttable[m][i] = cube.eorl;
468 eoud_ttable[m][i] = cube.eoud;
469 }
470 for (int i = 0; i < factorial8; i++) {
471 /* TODO: Maybe do this by hand to optimize? */
472 Cube cube = { .cp = i };
473 move_array(&cube, cube_to_cp_array, ep_array_to_cube,
474 corner_cycle[m], empty, 8, 1);
475 cp_ttable[m][i] = cube.cp;
476 }
477 for (int i = 0; i < pow3to7; i++) {
478 Cube cube = { .coud = i, .corl = i, .cofb = i };
479 move_array(&cube, cube_to_coud_array, coud_array_to_cube,
480 corner_cycle[m], coud_flipped[m], 8, 3);
481 move_array(&cube, cube_to_corl_array, corl_array_to_cube,
482 corner_cycle[m], corl_flipped[m], 8, 3);
483 move_array(&cube, cube_to_cofb_array, cofb_array_to_cube,
484 corner_cycle[m], cofb_flipped[m], 8, 3);
485 coud_ttable[m][i] = cube.coud;
486 corl_ttable[m][i] = cube.corl;
487 cofb_ttable[m][i] = cube.cofb;
488 }
489 for (int i = 0; i < factorial6; i++) {
490 Cube cube = { .centerpos = i };
491 move_array(&cube, cube_to_centerpos_array, centerpos_array_to_cube,
492 center_cycle[m], empty, 6, 1);
493 centerpos_ttable[m][i] = cube.centerpos;
494 }
495 fwrite(epose_ttable[m], sizeof(int), factorial12/factorial8, ttf);
496 fwrite(eposs_ttable[m], sizeof(int), factorial12/factorial8, ttf);
497 fwrite(eposm_ttable[m], sizeof(int), factorial12/factorial8, ttf);
498 fwrite(eofb_ttable[m], sizeof(int), pow2to11, ttf);
499 fwrite(eorl_ttable[m], sizeof(int), pow2to11, ttf);
500 fwrite(eoud_ttable[m], sizeof(int), pow2to11, ttf);
501 fwrite(cp_ttable[m], sizeof(int), factorial8, ttf);
502 fwrite(coud_ttable[m], sizeof(int), pow3to7, ttf);
503 fwrite(corl_ttable[m], sizeof(int), pow3to7, ttf);
504 fwrite(cofb_ttable[m], sizeof(int), pow3to7, ttf);
505 fwrite(centerpos_ttable[m], sizeof(int), factorial6, ttf);
506 }
507 fclose(ttf);
508 }
509}
510
511Cube apply_move(Move m, Cube cube) {
512 Cube moved = cube;
513
514 moved.eofb = eofb_ttable[m][cube.eofb];
515 moved.eorl = eorl_ttable[m][cube.eorl];
516 moved.eoud = eoud_ttable[m][cube.eoud];
517 moved.coud = coud_ttable[m][cube.coud];
518 moved.cofb = cofb_ttable[m][cube.cofb];
519 moved.corl = corl_ttable[m][cube.corl];
520 moved.epose = epose_ttable[m][cube.epose];
521 moved.eposs = eposs_ttable[m][cube.eposs];
522 moved.eposm = eposm_ttable[m][cube.eposm];
523 moved.cp = cp_ttable[m][cube.cp];
524 moved.centerpos = centerpos_ttable[m][cube.centerpos];
525
526 return moved;
527}
diff --git a/old/2020-unknown-date/cubeutils.c b/old/2020-unknown-date/cubeutils.c
new file mode 100644
index 0000000..4f0a060
--- /dev/null
+++ b/old/2020-unknown-date/cubeutils.c
@@ -0,0 +1,100 @@
1#include <stdio.h>
2#include "utils.h"
3#include "pieces.h"
4#include "cubeutils.h"
5
6int epe_solved[] = {FR, FL, BL, BR};
7int eps_solved[] = {UL, UR, DL, DR};
8int epm_solved[] = {UF, UB, DF, DB};
9
10void cube_to_ep_array(Cube *cube, int ep[12]) {
11 int epe[4], eps[4], epm[4];
12 index_to_perm(cube->epose % factorial(4), 4, epe);
13 index_to_perm(cube->eposs % factorial(4), 4, eps);
14 index_to_perm(cube->eposm % factorial(4), 4, epm);
15
16 int epose[12], eposs[12], eposm[12];
17 index_to_subset(cube->epose / factorial(4), 12, 4, epose);
18 index_to_subset(cube->eposs / factorial(4), 12, 4, eposs);
19 index_to_subset(cube->eposm / factorial(4), 12, 4, eposm);
20 for (int i = 0; i < 4; i++) {
21 swap(&eposs[eps_solved[i]], &eposs[i+8]);
22 swap(&eposm[epm_solved[i]], &eposm[i+8]);
23 }
24
25 for (int i = 0, ie = 0, is = 0, im = 0; i < 12; i++) {
26 if (epose[i]) ep[i] = epe_solved[epe[ie++]];
27 if (eposs[i]) ep[i] = eps_solved[eps[is++]];
28 if (eposm[i]) ep[i] = epm_solved[epm[im++]];
29 }
30}
31
32void ep_array_to_epos(int ep[12], Cube *cube) {
33 int epe[4], eps[4], epm[4];
34 int epose[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
35 int eposs[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
36 int eposm[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
37 for (int i = 0, ie = 0, is = 0, im = 0; i < 12; i++) {
38 for (int j = 0; j < 4; j++) {
39 if (ep[i] == epe_solved[j]) { epe[ie++] = j; epose[i] = 1; }
40 if (ep[i] == eps_solved[j]) { eps[is++] = j; eposs[i] = 1; }
41 if (ep[i] == epm_solved[j]) { epm[im++] = j; eposm[i] = 1; }
42 }
43 }
44 for (int i = 0; i < 4; i++) {
45 swap(&eposs[eps_solved[i]], &eposs[i+8]);
46 swap(&eposm[epm_solved[i]], &eposm[i+8]);
47 }
48 cube->epose = factorial(4) * subset_to_index(epose, 12, 4)
49 + perm_to_index(epe, 4);
50 cube->eposs = factorial(4) * subset_to_index(eposs, 12, 4)
51 + perm_to_index(eps, 4);
52 cube->eposm = factorial(4) * subset_to_index(eposm, 12, 4)
53 + perm_to_index(epm, 4);
54}
55
56bool solvable(Cube *cube) {
57 /* Since we memorize orientation truncating the last digit, we only need to
58 * check that the permutations have the correct sign. */
59 /* TODO: add check that every integer is in range */
60 int ep[12], cp[12], c[6];
61 cube_to_ep_array(cube, ep);
62 index_to_perm(cube->cp, 8, cp);
63 index_to_perm(cube->centerpos, 6, c);
64 return (perm_sign(ep, 12) ^ perm_sign(c, 6)) == perm_sign(cp, 8);
65}
66
67Cube *solved_cube() {
68 static Cube cube = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
69 return &cube;
70}
71
72bool solved(Cube *cube) {
73 return (cube->eofb == 0 && cube->coud == 0 && cube->cp == 0 &&
74 cube->epose == 0 && cube->eposs == 0 && cube->eposm == 0 &&
75 cube->centerpos == 0);
76}
77
78char *to_string(Cube *cube) {
79 int eo[12], co[8], ep[12], cp[8], cenpos[6];
80 cube_to_eofb_array(cube->eofb, eo);
81 cube_to_coud_array(cube->coud, co);
82 cube_to_ep_array(cube, ep);
83 cube_to_cp_array(cube->cp, cp);
84 cube_to_centerpos_array(cube->centerpos, cenpos);
85
86 char *ret[1000];
87
88 for (int i = 0; i < 12; i++) sprintf(ret, " %s ", edge_string[ep[i]]);
89 sprintf(ret, "\n");
90 for (int i = 0; i < 12; i++) sprintf(ret, " %d ", eo[i]);
91 sprintf(ret, "\n");
92 for (int i = 0; i < 8; i++) sprintf(ret, "%s ", corner_string[cp[i]]);
93 sprintf(ret, "\n");
94 for (int i = 0; i < 8; i++) sprintf(ret, " %d ", co[i]);
95 sprintf(ret, "\n");
96 for (int i = 0; i < 6; i++) sprintf(ret, " %s ", center_string[cenpos[i]]);
97 sprintf(ret, "\n");
98
99 return ret;
100}
diff --git a/old/2020-unknown-date/cubeutils.h b/old/2020-unknown-date/cubeutils.h
new file mode 100644
index 0000000..b24291c
--- /dev/null
+++ b/old/2020-unknown-date/cubeutils.h
@@ -0,0 +1,18 @@
1/* Cube-specific utility functions */
2
3#ifndef CUBEUTILS_H
4#define CUBEUTILS_H
5
6#include <stdbool.h>
7#include "pieces.h"
8
9void cube_to_ep_array(Cube *cube, int ep[12]);
10void ep_array_to_epos(int ep[12], Cube *cube);
11
12Cube *solved_cube();
13bool solvable(Cube *cube);
14bool solved(Cube *cube);
15
16void print(Cube *cube);
17
18#endif
diff --git a/old/2020-unknown-date/moves.c b/old/2020-unknown-date/moves.c
new file mode 100644
index 0000000..de293ed
--- /dev/null
+++ b/old/2020-unknown-date/moves.c
@@ -0,0 +1,57 @@
1#include <stdbool.h>
2#include "pieces.h"
3#include "moves.h"
4#include "utils.h"
5
6/* Transition tables */
7int eofb_ttable[pow2to11][NULLMOVE];
8int eorl_ttable[pow2to11][NULLMOVE];
9int eoud_ttable[pow2to11][NULLMOVE];
10int coud_ttable[pow3to7][NULLMOVE];
11int cofb_ttable[pow3to7][NULLMOVE];
12int corl_ttable[pow3to7][NULLMOVE];
13int epose_ttable[factorial12/factorial8][NULLMOVE];
14int eposs_ttable[factorial12/factorial8][NULLMOVE];
15int eposm_ttable[factorial12/factorial8][NULLMOVE];
16int cp_ttable[factorial8][NULLMOVE];
17int centerpos_ttable[factorial6][NULLMOVE];
18
19void apply_move_ep(Move m, int a[12]) {
20 int aux[12];
21 intarrcopy(a, aux, 12);
22 for (int i = 0; i < 12; i++)
23 a[i] = aux[edge_cycle[m][i]];
24}
25
26void apply_move_cp(Move m, int a[8]) {
27 int aux[8];
28 intarrcopy(a, aux, 8);
29 for (int i = 0; i < 8; i++)
30 a[i] = aux[corner_cycle[m][i]];
31}
32
33void apply_move_centerpos(Move m, int a[6]) {
34 int aux[6];
35 intarrcopy(a, aux, 6);
36 for (int i = 0; i < 6; i++)
37 a[i] = aux[center_cycle[m][i]];
38}
39
40void init_ttables() {
41 /* TODO */
42}
43
44void apply_move(Move m, Cube *cube) {
45 cube->eofb = eofb_ttable[cube->eofb][m];
46 cube->eorl = eorl_ttable[cube->eorl][m];
47 cube->eoud = eoud_ttable[cube->eoud][m];
48 cube->coud = coud_ttable[cube->coud][m];
49 cube->cofb = cofb_ttable[cube->cofb][m];
50 cube->corl = corl_ttable[cube->corl][m];
51 cube->epose = epose_ttable[cube->epose][m];
52 cube->eposs = eposs_ttable[cube->eposs][m];
53 cube->eposm = eposm_ttable[cube->eposm][m];
54 cube->cp = cp_ttable[cube->cp][m];
55 cube->centerpos = centerpos_ttable[cube->centerpos][m];
56}
57
diff --git a/old/2020-unknown-date/moves.h b/old/2020-unknown-date/moves.h
new file mode 100644
index 0000000..605f335
--- /dev/null
+++ b/old/2020-unknown-date/moves.h
@@ -0,0 +1,9 @@
1/* Moves and transition tables */
2
3#ifndef MOVES_H
4#define MOVES_H
5
6void apply_move(Move m, Cube *cube);
7void init_ttables();
8
9#endif
diff --git a/old/2020-unknown-date/pieces.c b/old/2020-unknown-date/pieces.c
new file mode 100644
index 0000000..d782c89
--- /dev/null
+++ b/old/2020-unknown-date/pieces.c
@@ -0,0 +1,208 @@
1#include "pieces.h"
2
3char edge_string[12][5] = {
4 "UF", "UL", "UB", "UR", "DF", "DL", "DB", "DR", "FR", "FL", "BL", "BR"
5};
6
7char corner_string[8][5] = {
8 "UFR", "UFL", "UBL", "UBR", "DFR", "DFL", "DBL", "DBR"
9};
10
11char center_string[6][5] = { "U", "D", "R", "L", "F", "B" };
12
13char move_string[NULLMOVE+1][5] = {
14 "U", "U2", "U\'", "D", "D2", "D\'", "R", "R2", "R\'",
15 "L", "L2", "L\'", "F", "F2", "F\'", "B", "B2", "B\'",
16 "Uw", "Uw2", "Uw\'", "Dw", "Dw2", "Dw\'", "Rw", "Rw2", "Rw\'",
17 "Lw", "Lw2", "Lw\'", "Fw", "Fw2", "Fw\'", "Bw", "Bw2", "Bw\'",
18 "M", "M2", "M\'", "S", "S2", "S\'", "E", "E2", "E\'",
19 "x", "x2", "x\'", "y", "y2", "y\'", "z", "z2", "z\'",
20 "-"
21};
22
23int edge_cycle[NULLMOVE+1][12] = {
24 [U] = {UR, UF, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR},
25 [U2] = {UB, UR, UF, UL, DF, DL, DB, DR, FR, FL, BL, BR},
26 [U3] = {UL, UB, UR, UF, DF, DL, DB, DR, FR, FL, BL, BR},
27 [D] = {UF, UL, UB, UR, DL, DB, DR, DF, FR, FL, BL, BR},
28 [D2] = {UF, UL, UB, UR, DB, DR, DF, DL, FR, FL, BL, BR},
29 [D3] = {UF, UL, UB, UR, DR, DF, DL, DB, FR, FL, BL, BR},
30 [R] = {UF, UL, UB, FR, DF, DL, DB, BR, DR, FL, BL, UR},
31 [R2] = {UF, UL, UB, DR, DF, DL, DB, UR, BR, FL, BL, FR},
32 [R3] = {UF, UL, UB, BR, DF, DL, DB, FR, UR, FL, BL, DR},
33 [L] = {UF, BL, UB, UR, DF, FL, DB, DR, FR, UL, DL, BR},
34 [L2] = {UF, DL, UB, UR, DF, UL, DB, DR, FR, BL, FL, BR},
35 [L3] = {UF, FL, UB, UR, DF, BL, DB, DR, FR, DL, UL, BR},
36 [F] = {FL, UL, UB, UR, FR, DL, DB, DR, UF, DF, BL, BR},
37 [F2] = {DF, UL, UB, UR, UF, DL, DB, DR, FL, FR, BL, BR},
38 [F3] = {FR, UL, UB, UR, FL, DL, DB, DR, DF, UF, BL, BR},
39 [B] = {UF, UL, BR, UR, DF, DL, BL, DR, FR, FL, UB, DB},
40 [B2] = {UF, UL, DB, UR, DF, DL, UB, DR, FR, FL, BR, BL},
41 [B3] = {UF, UL, BL, UR, DF, DL, BR, DR, FR, FL, DB, UB},
42
43 [Uw] = {UR, UF, UL, UB, DF, DL, DB, DR, BR, FR, FL, BL},
44 [Uw2] = {UB, UR, UF, UL, DF, DL, DB, DR, BL, BR, FR, FL},
45 [Uw3] = {UL, UB, UR, UF, DF, DL, DB, DR, FL, BL, BR, FR},
46 [Dw] = {UF, UL, UB, UR, DL, DB, DR, DF, FL, BL, BR, FR},
47 [Dw2] = {UF, UL, UB, UR, DB, DR, DF, DL, BL, BR, FR, FL},
48 [Dw3] = {UF, UL, UB, UR, DR, DF, DL, DB, BR, FR, FL, BL},
49 [Rw] = {DF, UL, UF, FR, DB, DL, UB, BR, DR, FL, BL, UR},
50 [Rw2] = {DB, UL, DF, DR, UB, DL, UF, UR, BR, FL, BL, FR},
51 [Rw3] = {UB, UL, DB, BR, UF, DL, DF, FR, UR, FL, BL, DR},
52 [Lw] = {UB, BL, DB, UR, UF, FL, DF, DR, FR, UL, DL, BR},
53 [Lw2] = {DB, DL, DF, UR, UB, UL, UF, DR, FR, BL, FL, BR},
54 [Lw3] = {DF, FL, UF, UR, DB, BL, UB, DR, FR, DL, UL, BR},
55 [Fw] = {FL, DL, UB, UL, FR, DR, DB, UR, UF, DF, BL, BR},
56 [Fw2] = {DF, DR, UB, DL, UF, UR, DB, UL, FL, FR, BL, BR},
57 [Fw3] = {FR, UR, UB, DR, FL, UL, DB, DL, DF, UF, BL, BR},
58 [Bw] = {UF, UR, BR, DR, DF, UL, BL, DL, FR, FL, UB, DB},
59 [Bw2] = {UF, DR, DB, DL, DF, UR, UB, UL, FR, FL, BR, BL},
60 [Bw3] = {UF, DL, BL, UL, DF, DR, BR, UR, FR, FL, DB, UB},
61
62 [M] = {UB, UL, DB, UR, UF, DL, DF, DR, FR, FL, BL, BR},
63 [M2] = {DB, UL, DF, UR, UB, DL, UF, DR, FR, FL, BL, BR},
64 [M3] = {DF, UL, UF, UR, DB, DL, UB, DR, FR, FL, BL, BR},
65 [S] = {UF, DL, UB, UL, DF, DR, DB, UR, FR, FL, BL, BR},
66 [S2] = {UF, DR, UB, DL, DF, UR, DB, UL, FR, FL, BL, BR},
67 [S3] = {UF, UR, UB, DR, DF, UL, DB, DL, FR, FL, BL, BR},
68 [E] = {UF, UL, UB, UR, DF, DL, DB, DR, FL, BL, BR, FR},
69 [E2] = {UF, UL, UB, UR, DF, DL, DB, DR, BL, BR, FR, FL},
70 [E3] = {UF, UL, UB, UR, DF, DL, DB, DR, BR, FR, FL, BL},
71
72 [X] = {DF, FL, UF, FR, DB, BL, UB, BR, DR, DL, UL, UR},
73 [X2] = {DB, DL, DF, DR, UB, UL, UF, UR, BR, BL, FL, FR},
74 [X3] = {UB, BL, DB, BR, UF, FL, DF, FR, UR, UL, DL, DR},
75 [Y] = {UR, UF, UL, UB, DR, DF, DL, DB, BR, FR, FL, BL},
76 [Y2] = {UB, UR, UF, UL, DB, DR, DF, DL, BL, BR, FR, FL},
77 [Y3] = {UL, UB, UR, UF, DL, DB, DR, DF, FL, BL, BR, FR},
78 [Z] = {FL, DL, BL, UL, FR, DR, BR, UR, UF, DF, DB, UB},
79 [Z2] = {DF, DR, DB, DL, UF, UR, UB, UL, FL, FR, BR, BL},
80 [Z3] = {FR, UR, BR, DR, FL, UL, BL, DL, DF, UF, UB, DB},
81
82 [NULLMOVE] = {UF, UL, UB, UR, DF, DL, DB, DR, FR, FL, BL, BR},
83};
84
85int corner_cycle[NULLMOVE+1][8] = {
86 [U] = {UBR, UFR, UFL, UBL, DFR, DFL, DBL, DBR},
87 [U2] = {UBL, UBR, UFR, UFL, DFR, DFL, DBL, DBR},
88 [U3] = {UFL, UBL, UBR, UFR, DFR, DFL, DBL, DBR},
89 [D] = {UFR, UFL, UBL, UBR, DFL, DBL, DBR, DFR},
90 [D2] = {UFR, UFL, UBL, UBR, DBL, DBR, DFR, DFL},
91 [D3] = {UFR, UFL, UBL, UBR, DBR, DFR, DFL, DBL},
92 [R] = {DFR, UFL, UBL, UFR, DBR, DFL, DBL, UBR},
93 [R2] = {DBR, UFL, UBL, DFR, UBR, DFL, DBL, UFR},
94 [R3] = {UBR, UFL, UBL, DBR, UFR, DFL, DBL, DFR},
95 [L] = {UFR, UBL, DBL, UBR, DFR, UFL, DFL, DBR},
96 [L2] = {UFR, DBL, DFL, UBR, DFR, UBL, UFL, DBR},
97 [L3] = {UFR, DFL, UFL, UBR, DFR, DBL, UBL, DBR},
98 [F] = {UFL, DFL, UBL, UBR, UFR, DFR, DBL, DBR},
99 [F2] = {DFL, DFR, UBL, UBR, UFL, UFR, DBL, DBR},
100 [F3] = {DFR, UFR, UBL, UBR, DFL, UFL, DBL, DBR},
101 [B] = {UFR, UFL, UBR, DBR, DFR, DFL, UBL, DBL},
102 [B2] = {UFR, UFL, DBR, DBL, DFR, DFL, UBR, UBL},
103 [B3] = {UFR, UFL, DBL, UBL, DFR, DFL, DBR, UBR},
104
105 [Uw] = {UBR, UFR, UFL, UBL, DFR, DFL, DBL, DBR},
106 [Uw2] = {UBL, UBR, UFR, UFL, DFR, DFL, DBL, DBR},
107 [Uw3] = {UFL, UBL, UBR, UFR, DFR, DFL, DBL, DBR},
108 [Dw] = {UFR, UFL, UBL, UBR, DFL, DBL, DBR, DFR},
109 [Dw2] = {UFR, UFL, UBL, UBR, DBL, DBR, DFR, DFL},
110 [Dw3] = {UFR, UFL, UBL, UBR, DBR, DFR, DFL, DBL},
111 [Rw] = {DFR, UFL, UBL, UFR, DBR, DFL, DBL, UBR},
112 [Rw2] = {DBR, UFL, UBL, DFR, UBR, DFL, DBL, UFR},
113 [Rw3] = {UBR, UFL, UBL, DBR, UFR, DFL, DBL, DFR},
114 [Lw] = {UFR, UBL, DBL, UBR, DFR, UFL, DFL, DBR},
115 [Lw2] = {UFR, DBL, DFL, UBR, DFR, UBL, UFL, DBR},
116 [Lw3] = {UFR, DFL, UFL, UBR, DFR, DBL, UBL, DBR},
117 [Fw] = {UFL, DFL, UBL, UBR, UFR, DFR, DBL, DBR},
118 [Fw2] = {DFL, DFR, UBL, UBR, UFL, UFR, DBL, DBR},
119 [Fw3] = {DFR, UFR, UBL, UBR, DFL, UFL, DBL, DBR},
120 [Bw] = {UFR, UFL, UBR, DBR, DFR, DFL, UBL, DBL},
121 [Bw2] = {UFR, UFL, DBR, DBL, DFR, DFL, UBR, UBL},
122 [Bw3] = {UFR, UFL, DBL, UBL, DFR, DFL, DBR, UBR},
123
124 [M] = {UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR},
125 [M2] = {UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR},
126 [M3] = {UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR},
127 [S] = {UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR},
128 [S2] = {UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR},
129 [S3] = {UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR},
130 [E] = {UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR},
131 [E2] = {UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR},
132 [E3] = {UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR},
133
134 [X] = {DFR, DFL, UFL, UFR, DBR, DBL, UBL, UBR},
135 [X2] = {DBR, DBL, DFL, DFR, UBR, UBL, UFL, UFR},
136 [X3] = {UBR, UBL, DBL, DBR, UFR, UFL, DFL, DFR},
137 [Y] = {UBR, UFR, UFL, UBL, DBR, DFR, DFL, DBL},
138 [Y2] = {UBL, UBR, UFR, UFL, DBL, DBR, DFR, DFL},
139 [Y3] = {UFL, UBL, UBR, UFR, DFL, DBL, DBR, DFR},
140 [Z] = {UFL, DFL, DBL, UBL, UFR, DFR, DBR, UBR},
141 [Z2] = {DFL, DFR, DBR, DBL, UFL, UFR, UBR, UBL},
142 [Z3] = {DFR, UFR, UBR, DBR, DFL, UFL, UBL, DBL},
143
144 [NULLMOVE] = {UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR},
145};
146
147int center_cycle[NULLMOVE+1][6] = {
148 [U] = {U_center, D_center, R_center, L_center, F_center, B_center},
149 [U2] = {U_center, D_center, R_center, L_center, F_center, B_center},
150 [U3] = {U_center, D_center, R_center, L_center, F_center, B_center},
151 [D] = {U_center, D_center, R_center, L_center, F_center, B_center},
152 [D2] = {U_center, D_center, R_center, L_center, F_center, B_center},
153 [D3] = {U_center, D_center, R_center, L_center, F_center, B_center},
154 [R] = {U_center, D_center, R_center, L_center, F_center, B_center},
155 [R2] = {U_center, D_center, R_center, L_center, F_center, B_center},
156 [R3] = {U_center, D_center, R_center, L_center, F_center, B_center},
157 [L] = {U_center, D_center, R_center, L_center, F_center, B_center},
158 [L2] = {U_center, D_center, R_center, L_center, F_center, B_center},
159 [L3] = {U_center, D_center, R_center, L_center, F_center, B_center},
160 [F] = {U_center, D_center, R_center, L_center, F_center, B_center},
161 [F2] = {U_center, D_center, R_center, L_center, F_center, B_center},
162 [F3] = {U_center, D_center, R_center, L_center, F_center, B_center},
163 [B] = {U_center, D_center, R_center, L_center, F_center, B_center},
164 [B2] = {U_center, D_center, R_center, L_center, F_center, B_center},
165 [B3] = {U_center, D_center, R_center, L_center, F_center, B_center},
166
167 [Uw] = {U_center, D_center, B_center, F_center, R_center, L_center},
168 [Uw2] = {U_center, D_center, L_center, R_center, B_center, F_center},
169 [Uw3] = {U_center, D_center, F_center, B_center, L_center, R_center},
170 [Dw] = {U_center, D_center, F_center, B_center, L_center, R_center},
171 [Dw2] = {U_center, D_center, L_center, R_center, B_center, F_center},
172 [Dw3] = {U_center, D_center, B_center, F_center, R_center, L_center},
173 [Rw] = {F_center, B_center, R_center, L_center, D_center, U_center},
174 [Rw2] = {D_center, U_center, R_center, L_center, B_center, F_center},
175 [Rw3] = {B_center, F_center, R_center, L_center, U_center, D_center},
176 [Lw] = {B_center, F_center, R_center, L_center, U_center, D_center},
177 [Lw2] = {D_center, U_center, R_center, L_center, B_center, F_center},
178 [Lw3] = {F_center, B_center, R_center, L_center, D_center, U_center},
179 [Fw] = {L_center, R_center, U_center, D_center, F_center, B_center},
180 [Fw2] = {D_center, U_center, L_center, R_center, F_center, B_center},
181 [Fw3] = {R_center, L_center, D_center, U_center, F_center, B_center},
182 [Bw] = {R_center, L_center, D_center, U_center, F_center, B_center},
183 [Bw2] = {D_center, U_center, L_center, R_center, F_center, B_center},
184 [Bw3] = {L_center, R_center, U_center, D_center, F_center, B_center},
185
186 [X] = {F_center, B_center, R_center, L_center, D_center, U_center},
187 [X2] = {D_center, U_center, R_center, L_center, B_center, F_center},
188 [X3] = {B_center, F_center, R_center, L_center, U_center, D_center},
189 [Y] = {U_center, D_center, B_center, F_center, R_center, L_center},
190 [Y2] = {U_center, D_center, L_center, R_center, B_center, F_center},
191 [Y3] = {U_center, D_center, F_center, B_center, L_center, R_center},
192 [Z] = {L_center, R_center, U_center, D_center, F_center, B_center},
193 [Z2] = {D_center, U_center, L_center, R_center, F_center, B_center},
194 [Z3] = {R_center, L_center, D_center, U_center, F_center, B_center},
195
196 [M] = {B_center, F_center, R_center, L_center, U_center, D_center},
197 [M2] = {D_center, U_center, R_center, L_center, B_center, F_center},
198 [M3] = {F_center, B_center, R_center, L_center, D_center, U_center},
199 [E] = {U_center, D_center, F_center, B_center, L_center, R_center},
200 [E2] = {U_center, D_center, L_center, R_center, B_center, F_center},
201 [E3] = {U_center, D_center, B_center, F_center, R_center, L_center},
202 [S] = {L_center, R_center, U_center, D_center, F_center, B_center},
203 [S2] = {D_center, U_center, L_center, R_center, F_center, B_center},
204 [S3] = {R_center, L_center, D_center, U_center, F_center, B_center},
205
206 [NULLMOVE] = {U_center, D_center, R_center, L_center, F_center, B_center},
207};
208
diff --git a/old/2020-unknown-date/pieces.h b/old/2020-unknown-date/pieces.h
new file mode 100644
index 0000000..dbdd740
--- /dev/null
+++ b/old/2020-unknown-date/pieces.h
@@ -0,0 +1,59 @@
1/* Moves and other things */
2
3#ifndef PIECES_H
4#define PIECES_H
5
6typedef enum {
7 U, U2, U3, D, D2, D3, R, R2, R3, L, L2, L3, F, F2, F3, B, B2, B3,
8 Uw, Uw2, Uw3, Dw, Dw2, Dw3, Rw, Rw2, Rw3,
9 Lw, Lw2, Lw3, Fw, Fw2, Fw3, Bw, Bw2, Bw3,
10 M, M2, M3, S, S2, S3, E, E2, E3,
11 X, X2, X3, Y, Y2, Y3, Z, Z2, Z3,
12 NULLMOVE
13} Move;
14typedef enum {
15 U_center, D_center, R_center, L_center, F_center, B_center
16} Center;
17typedef enum { UF, UL, UB, UR, DF, DL, DB, DR, FR, FL, BL, BR } Edge;
18typedef enum { UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR } Corner;
19
20/* Arrays for strings of pieces and moves */
21extern char edge_string[12][5];
22extern char corner_string[8][5];
23extern char center_string[6][5];
24extern char move_string[NULLMOVE+1][5];
25
26/* Three big arrays that determine the movement of edges, corners and
27 * centers for some of the basic moves. Yes, one can be much more elegant and
28 * write much fewer lines. But then things get less elegant somewhere else. */
29extern int edge_cycle[NULLMOVE+1][12];
30extern int corner_cycle[NULLMOVE+1][8];
31extern int center_cycle[NULLMOVE+1][6];
32
33/* Representation of the cube */
34typedef struct {
35 /* Edge orientation */
36 int eofb;
37 int eorl;
38 int eoud;
39
40 /* Corner orientation */
41 int coud;
42 int cofb;
43 int corl;
44
45 /* Position of M/E/S slice edges */
46 /* TODO: keep in mind that the 4! positions with edges in correct slice
47 * must be the first 4! indeces */
48 int epose;
49 int eposs;
50 int eposm;
51
52 /* Permutation of corners */
53 int cp;
54
55 /* Position of centers */
56 int centerpos;
57} Cube;
58
59#endif
diff --git a/old/2021-02-06/cube.c b/old/2021-02-06/cube.c
new file mode 100644
index 0000000..9185281
--- /dev/null
+++ b/old/2021-02-06/cube.c
@@ -0,0 +1,664 @@
1#include "cube.h"
2
3typedef struct {
4 int ep[12], eofb[12], eorl[12], eoud[12],
5 cp[8], coud[8], corl[8], cofb[8], cpos[6];
6} CubeArray;
7
8typedef struct {
9 bool epose, eposs, eposm, eofb, eorl, eoud, cp, coud, cofb, corl, cpos;
10} PieceFilter;
11
12PieceFilter fAll = {true,true,true,true,true,true,true,true,true,true,true};
13PieceFilter cpos_only = { .cpos = true };
14
15void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f);
16Cube arrays_to_cube(CubeArray arr, PieceFilter f);
17void move_cubearray(Move m, CubeArray *arr, PieceFilter f);
18Cube move_via_array(Move m, Cube cube, PieceFilter f);
19void sort_cancel_rotate(NissMove *alg, int n, bool inv, int top, int front);
20bool read_ttables_file();
21bool write_ttables_file();
22
23/* Transition tables */
24uint16_t epose_ttable[NMOVES][factorial12/factorial8];
25uint16_t eposs_ttable[NMOVES][factorial12/factorial8];
26uint16_t eposm_ttable[NMOVES][factorial12/factorial8];
27uint16_t eofb_ttable[NMOVES][pow2to11];
28uint16_t eorl_ttable[NMOVES][pow2to11];
29uint16_t eoud_ttable[NMOVES][pow2to11];
30uint16_t cp_ttable[NMOVES][factorial8];
31uint16_t coud_ttable[NMOVES][pow3to7];
32uint16_t cofb_ttable[NMOVES][pow3to7];
33uint16_t corl_ttable[NMOVES][pow3to7];
34uint16_t cpos_ttable[NMOVES][factorial6];
35
36bool commute[NMOVES][NMOVES];
37bool possible_next[NMOVES][NMOVES][NMOVES];
38Move inverse[NMOVES];
39
40char edge_string[12][5] =
41 { "UF", "UL", "UB", "UR", "DF", "DL", "DB", "DR", "FR", "FL", "BL", "BR" };
42char corner_string[8][5] = { "UFR","UFL","UBL","UBR","DFR","DFL","DBL","DBR" };
43char center_string[6][5] = { "U", "D", "R", "L", "F", "B" };
44char move_string[NMOVES][5] =
45 { "-",
46 "U", "U2", "U\'", "D", "D2", "D\'", "R", "R2", "R\'",
47 "L", "L2", "L\'", "F", "F2", "F\'", "B", "B2", "B\'",
48 "Uw", "Uw2", "Uw\'", "Dw", "Dw2", "Dw\'", "Rw", "Rw2", "Rw\'",
49 "Lw", "Lw2", "Lw\'", "Fw", "Fw2", "Fw\'", "Bw", "Bw2", "Bw\'",
50 "M", "M2", "M\'", "S", "S2", "S\'", "E", "E2", "E\'",
51 "x", "x2", "x\'", "y", "y2", "y\'", "z", "z2", "z\'" };
52
53/* For each type of pieces only the effects of U, x and y are described */
54int edge_cycle[NMOVES][12] =
55 { [U] = {UR, UF, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR},
56 [x] = {DF, FL, UF, FR, DB, BL, UB, BR, DR, DL, UL, UR},
57 [y] = {UR, UF, UL, UB, DR, DF, DL, DB, BR, FR, FL, BL} };
58int eofb_flipped[NMOVES][12] =
59 { [x] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 },
60 [y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 } };
61int eorl_flipped[NMOVES][12] =
62 { [x] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
63 [y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 } };
64int eoud_flipped[NMOVES][12] =
65 { [U] = { [UF] = 1, [UL] = 1, [UB] = 1, [UR] = 1 },
66 [x] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 },
67 [y] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } };
68int corner_cycle[NMOVES][8] =
69 { [U] = {UBR, UFR, UFL, UBL, DFR, DFL, DBL, DBR},
70 [x] = {DFR, DFL, UFL, UFR, DBR, DBL, UBL, UBR},
71 [y] = {UBR, UFR, UFL, UBL, DBR, DFR, DFL, DBL} };
72int coud_flipped[NMOVES][8] =
73 { [x] = {[UFR]=2,[UBR]=1,[DBR]=2,[DFR]=1,[UFL]=1,[UBL]=2,[DBL]=1,[DFL]=2} };
74int corl_flipped[NMOVES][8] =
75 { [U] = { [UFR] = 1, [UBR] = 2, [UBL] = 1, [UFL] = 2 },
76 [y] = {[UFR]=1,[UBR]=2,[UBL]=1,[UFL]=2,[DFR]=2,[DBR]=1,[DBL]=2,[DFL]=1} };
77int cofb_flipped[NMOVES][8] =
78 { [U] = { [UFR] = 2, [UBR] = 1, [UBL] = 2, [UFL] = 1 },
79 [x] = {[UFR]=1,[UBR]=2,[DFR]=2,[DBR]=1,[UBL]=2,[UFL]=1,[DBL]=1,[DFL]=2},
80 [y] = {[UFR]=2,[UBR]=1,[UBL]=2,[UFL]=1,[DFR]=1,[DBR]=2,[DBL]=1,[DFL]=2} };
81int center_cycle[NMOVES][6] =
82 { [x] = {F_center, B_center, R_center, L_center, D_center, U_center},
83 [y] = {U_center, D_center, B_center, F_center, R_center, L_center} };
84
85/* Each move is reduced to a combination of U, x and y using this table */
86Move equiv_moves[NMOVES][14] = {
87 [U] = { U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
88 [U2] = { U, U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
89 [U3] = { U, U, U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
90 [D] = { x, x, U, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
91 [D2] = { x, x, U, U, x, x, 0, 0, 0, 0, 0, 0, 0, 0 },
92 [D3] = { x, x, U, U, U, x, x, 0, 0, 0, 0, 0, 0, 0 },
93 [R] = { y, x, U, x, x, x, y, y, y, 0, 0, 0, 0, 0 },
94 [R2] = { y, x, U, U, x, x, x, y, y, y, 0, 0, 0, 0 },
95 [R3] = { y, x, U, U, U, x, x, x, y, y, y, 0, 0, 0 },
96 [L] = { y, y, y, x, U, x, x, x, y, 0, 0, 0, 0, 0 },
97 [L2] = { y, y, y, x, U, U, x, x, x, y, 0, 0, 0, 0 },
98 [L3] = { y, y, y, x, U, U, U, x, x, x, y, 0, 0, 0 },
99 [F] = { x, U, x, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
100 [F2] = { x, U, U, x, x, x, 0, 0, 0, 0, 0, 0, 0, 0 },
101 [F3] = { x, U, U, U, x, x, x, 0, 0, 0, 0, 0, 0, 0 },
102 [B] = { x, x, x, U, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
103 [B2] = { x, x, x, U, U, x, 0, 0, 0, 0, 0, 0, 0, 0 },
104 [B3] = { x, x, x, U, U, U, x, 0, 0, 0, 0, 0, 0, 0 },
105
106 [Uw] = { x, x, U, x, x, y, 0, 0, 0, 0, 0, 0, 0, 0 },
107 [Uw2] = { x, x, U, U, x, x, y, y, 0, 0, 0, 0, 0, 0 },
108 [Uw3] = { x, x, U, U, U, x, x, y, y, y, 0, 0, 0, 0 },
109 [Dw] = { U, y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
110 [Dw2] = { U, U, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
111 [Dw3] = { U, U, U, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
112 [Rw] = { y, y, y, x, U, x, x, x, y, x, 0, 0, 0, 0 },
113 [Rw2] = { y, y, y, x, U, U, x, x, x, y, x, x, 0, 0 },
114 [Rw3] = { y, y, y, x, U, U, U, y, x, x, x, y, 0, 0 },
115 [Lw] = { y, x, U, x, x, x, y, y, y, x, x, x, 0, 0 },
116 [Lw2] = { y, x, U, U, x, x, x, y, y, y, x, x, 0, 0 },
117 [Lw3] = { y, x, U, U, U, x, x, x, y, y, y, x, 0, 0 },
118 [Fw] = { x, x, x, U, y, y, y, x, 0, 0, 0, 0, 0, 0 },
119 [Fw2] = { x, x, x, U, U, y, y, x, 0, 0, 0, 0, 0, 0 },
120 [Fw3] = { x, x, x, U, U, U, y, x, 0, 0, 0, 0, 0, 0 },
121 [Bw] = { x, U, y, y, y, x, x, x, 0, 0, 0, 0, 0, 0 },
122 [Bw2] = { x, U, U, y, y, x, x, x, 0, 0, 0, 0, 0, 0 },
123 [Bw3] = { x, U, U, U, y, x, x, x, 0, 0, 0, 0, 0, 0 },
124
125 [M] = { y, x, U, x, x, U, U, U, y, x, y, y, y, 0 },
126 [M2] = { y, x, U, U, x, x, U, U, x, x, x, y, 0, 0 },
127 [M3] = { y, x, U, U, U, x, x, U, y, x, x, x, y, 0 },
128 [S] = { x, U, U, U, x, x, U, y, y, y, x, 0, 0, 0 },
129 [S2] = { x, U, U, x, x, U, U, y, y, x, 0, 0, 0, 0 },
130 [S3] = { x, U, x, x, U, U, U, y, x, 0, 0, 0, 0, 0 },
131 [E] = { U, x, x, U, U, U, x, x, y, y, y, 0, 0, 0 },
132 [E2] = { U, U, x, x, U, U, x, x, y, y, 0, 0, 0, 0 },
133 [E3] = { U, U, U, x, x, U, x, x, y, 0, 0, 0, 0, 0 },
134
135 [x] = { x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
136 [x2] = { x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
137 [x3] = { x, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
138 [y] = { y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
139 [y2] = { y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
140 [y3] = { y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
141 [z] = { y, y, y, x, y, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
142 [z2] = { y, y, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
143 [z3] = { y, x, y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
144};
145
146/* Movesets */
147bool standard_moveset[NMOVES] = {
148 [U] = true, [U2] = true, [U3] = true, [D] = true, [D2] = true, [D3] = true,
149 [R] = true, [R2] = true, [R3] = true, [L] = true, [L2] = true, [L3] = true,
150 [F] = true, [F2] = true, [F3] = true, [B] = true, [B2] = true, [B3] = true,
151};
152
153int epe_solved[] = {FR, FL, BL, BR};
154int eps_solved[] = {UL, UR, DL, DR};
155int epm_solved[] = {UF, UB, DF, DB};
156
157Cube blank_cube() {
158 Cube c = {0};
159 return c;
160}
161
162void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f) {
163 /* ep is the hardest */
164 if (f.epose || f.eposs || f.eposm)
165 for (int i = 0; i < 12; i++) arr->ep[i] = -1;
166 if (f.epose) {
167 int epe[4], epose[12];
168 index_to_perm(cube.epose % factorial(4), 4, epe);
169 index_to_subset(cube.epose / factorial(4), 12, 4, epose);
170 for (int i = 0, ie = 0; i < 12; i++)
171 if (epose[i]) arr->ep[i] = epe_solved[epe[ie++]];
172 }
173 if (f.eposs) {
174 int eps[4], eposs[12];
175 index_to_perm(cube.eposs % factorial(4), 4, eps);
176 index_to_subset(cube.eposs / factorial(4), 12, 4, eposs);
177 for (int i = 0; i < 4; i++) swap(&eposs[eps_solved[i]], &eposs[i+8]);
178 for (int i = 0, is = 0; i < 12; i++)
179 if (eposs[i]) arr->ep[i] = eps_solved[eps[is++]];
180 }
181 if (f.eposm) {
182 int epm[4], eposm[12];
183 index_to_perm(cube.eposm % factorial(4), 4, epm);
184 index_to_subset(cube.eposm / factorial(4), 12, 4, eposm);
185 for (int i = 0; i < 4; i++) swap(&eposm[epm_solved[i]], &eposm[i+8]);
186 for (int i = 0, im = 0; i < 12; i++)
187 if (eposm[i]) arr->ep[i] = epm_solved[epm[im++]];
188 }
189
190 /* All the others */
191 if (f.eofb) int_to_sum_zero_array(cube.eofb, 2, 12, arr->eofb);
192 if (f.eorl) int_to_sum_zero_array(cube.eorl, 2, 12, arr->eorl);
193 if (f.eoud) int_to_sum_zero_array(cube.eoud, 2, 12, arr->eoud);
194 if (f.cp) index_to_perm( cube.cp, 8, arr->cp);
195 if (f.coud) int_to_sum_zero_array(cube.coud, 3, 8, arr->coud);
196 if (f.corl) int_to_sum_zero_array(cube.corl, 3, 8, arr->corl);
197 if (f.cofb) int_to_sum_zero_array(cube.cofb, 3, 8, arr->cofb);
198 if (f.cpos) index_to_perm( cube.cpos, 6, arr->cpos);
199}
200
201Cube arrays_to_cube(CubeArray arr, PieceFilter f) {
202 Cube ret = {0};
203
204 /* Again, ep is the hardest part */
205 if (f.epose) {
206 int epe[4], epose[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
207 for (int i = 0, ie = 0; i < 12; i++)
208 for (int j = 0; j < 4; j++)
209 if (arr.ep[i] == epe_solved[j])
210 { epe[ie++] = j; epose[i] = 1; }
211 ret.epose = factorial(4)*subset_to_index(epose,12,4)+perm_to_index(epe,4);
212 }
213 if (f.eposs) {
214 int eps[4], eposs[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
215 for (int i = 0, is = 0; i < 12; i++)
216 for (int j = 0; j < 4; j++)
217 if (arr.ep[i] == eps_solved[j])
218 { eps[is++] = j; eposs[i] = 1; }
219 for (int i = 0; i < 4; i++) swap(&eposs[eps_solved[i]], &eposs[i+8]);
220 ret.eposs = factorial(4)*subset_to_index(eposs,12,4)+perm_to_index(eps,4);
221 }
222 if (f.eposm) {
223 int epm[4], eposm[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
224 for (int i = 0, im = 0; i < 12; i++)
225 for (int j = 0; j < 4; j++)
226 if (arr.ep[i] == epm_solved[j])
227 { epm[im++] = j; eposm[i] = 1; }
228 for (int i = 0; i < 4; i++) swap(&eposm[epm_solved[i]], &eposm[i+8]);
229 ret.eposm = factorial(4)*subset_to_index(eposm,12,4)+perm_to_index(epm,4);
230 }
231 if (f.eofb) ret.eofb = digit_array_to_int(arr.eofb, 11, 2);
232 if (f.eorl) ret.eorl = digit_array_to_int(arr.eorl, 11, 2);
233 if (f.eoud) ret.eoud = digit_array_to_int(arr.eoud, 11, 2);
234 if (f.cp) ret.cp = perm_to_index( arr.cp, 8 );
235 if (f.coud) ret.coud = digit_array_to_int(arr.coud, 7, 3);
236 if (f.corl) ret.corl = digit_array_to_int(arr.corl, 7, 3);
237 if (f.cofb) ret.cofb = digit_array_to_int(arr.cofb, 7, 3);
238 if (f.cpos) ret.cpos = perm_to_index( arr.cpos, 6 );
239
240 return ret;
241}
242
243void move_cubearray(Move m, CubeArray *arr, PieceFilter f) {
244 if (f.epose || f.eposs || f.eposm)
245 apply_permutation(edge_cycle[m], arr->ep, 12);
246 if (f.eofb) {
247 apply_permutation(edge_cycle[m], arr->eofb, 12);
248 sum_arrays_mod(eofb_flipped[m], arr->eofb, 12, 2);
249 }
250 if (f.eofb) {
251 apply_permutation(edge_cycle[m], arr->eorl, 12);
252 sum_arrays_mod(eorl_flipped[m], arr->eorl, 12, 2);
253 }
254 if (f.eofb) {
255 apply_permutation(edge_cycle[m], arr->eoud, 12);
256 sum_arrays_mod(eoud_flipped[m], arr->eoud, 12, 2);
257 }
258 if (f.cp)
259 apply_permutation(corner_cycle[m], arr->cp, 8);
260 if (f.coud) {
261 apply_permutation(corner_cycle[m], arr->coud, 8);
262 sum_arrays_mod(coud_flipped[m], arr->coud, 8, 3);
263 }
264 if (f.corl) {
265 apply_permutation(corner_cycle[m], arr->corl, 8);
266 sum_arrays_mod(corl_flipped[m], arr->corl, 8, 3);
267 }
268 if (f.cofb) {
269 apply_permutation(corner_cycle[m], arr->cofb, 8);
270 sum_arrays_mod(cofb_flipped[m], arr->cofb, 8, 3);
271 }
272 if (f.cpos)
273 apply_permutation(center_cycle[m], arr->cpos, 6);
274}
275
276Cube move_via_array(Move m, Cube cube, PieceFilter f) {
277 CubeArray arr = {0};
278 cube_to_arrays(cube, &arr, f);
279 move_cubearray(m, &arr, f);
280 return arrays_to_cube(arr, f);
281}
282
283int copy_alg(NissMove *src, NissMove *dest) {
284 int i;
285 for (i = 0; src[i].m != NULLMOVE; i++)
286 dest[i] = src[i];
287 dest[i].m = NULLMOVE;
288 return i;
289}
290
291bool equal(Cube c1, Cube c2) {
292 return c1.eofb == c2.eofb && c1.epose == c2.epose &&
293 c1.eposs == c2.eposs && c1.eposm == c2.eposm &&
294 c1.coud == c2.coud && c1.cp == c2.cp &&
295 c1.cpos == c2.cpos;
296}
297
298bool solvable(Cube cube) {
299 /* Since we memorize orientation truncating the last digit, we only need to
300 * check that the permutations have the correct sign. */
301 CubeArray arr = {0};
302 cube_to_arrays(cube, &arr, fAll);
303 return (perm_sign(arr.ep,12) ^ perm_sign(arr.cpos,6)) == perm_sign(arr.cp,8);
304}
305
306bool is_solved(Cube cube, bool reorient) {
307 if (!reorient || !cube.cpos)
308 return !cube.eofb && !cube.coud && !cube.cp &&
309 !cube.epose && !cube.eposs && !cube.eposm;
310
311 bool ret = false;
312 for (int i = x; i <= z3; i++) {
313 ret = ret || is_solved(move_cube(i, cube), false);
314 for (int j = x; j <= z3; j++)
315 ret = ret || is_solved(move_cube(i, move_cube(j, cube)), false);
316 }
317 return ret;
318}
319
320void print_cube(Cube cube) {
321 CubeArray arr = {0};
322 cube_to_arrays(cube, &arr, fAll);
323
324 for (int i = 0; i < 12; i++) printf(" %s ", edge_string[arr.ep[i]]);
325 printf("\n");
326 for (int i = 0; i < 12; i++) printf(" %c ", arr.eofb[i] + '0');
327 printf("\n");
328 for (int i = 0; i < 8; i++) printf("%s ", corner_string[arr.cp[i]]);
329 printf("\n");
330 for (int i = 0; i < 8; i++) printf(" %c ", arr.coud[i] + '0');
331 printf("\n");
332 for (int i = 0; i < 6; i++) printf(" %s ", center_string[arr.cpos[i]]);
333 printf("\n");
334}
335
336/* TODO: all strings start with space?? */
337void print_moves(NissMove *alg) {
338 bool niss = false;
339 for (int i = 0; alg[i].m != NULLMOVE; i++) {
340 char *fill = !niss && alg[i].inverse ? " (" :
341 (niss && !alg[i].inverse ? ") " : " ");
342 printf("%s%s", fill, move_string[alg[i].m]);
343 niss = alg[i].inverse;
344 }
345 printf("%s\n", niss ? ")" : "");
346}
347
348int read_moves(char *str, NissMove *alg, int n) {
349 bool niss = false;
350 int c = 0;
351
352 for (int i = 0; str[i] && c < n; i++) {
353 if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n')
354 continue;
355
356 if (str[i] == '(' || str[i] == ')') {
357 if ((niss && str[i] == '(') || (!niss && str[i] == ')'))
358 return -1;
359 niss = !niss;
360 continue;
361 }
362
363 alg[c].inverse = niss; alg[c].m = NULLMOVE;
364 for (Move j = 0; j < NMOVES; j++) {
365 if (str[i] == move_string[j][0]) {
366 alg[c].m = j;
367 if (alg[c].m <= B && str[i+1]=='w') { alg[c].m += Uw - U; i++; }
368 if (str[i+1]=='2') { alg[c].m += 1; i++; }
369 else if (str[i+1]=='\'' || str[i+1]=='3') { alg[c].m += 2; i++; }
370 c++;
371 break;
372 }
373 }
374 }
375
376 alg[c].m = NULLMOVE;
377 return c;
378}
379
380/* Helper function for cleanup. alg must contain only basic moves, no 2 or '.
381 top and front describe an admissible orientation of the cube. */
382void sort_cancel_rotate(NissMove *alg, int n, bool inv, int top, int front) {
383 int c = 0, i = 0;
384 NissMove aux[n+3];
385 aux[0].m = NULLMOVE;
386
387 while (i < n && alg[i].m != NULLMOVE) {
388 int j = i;
389 while (j < n && commute[alg[i].m][alg[j].m]) j++;
390 Move base = 6*((alg[i].m-1)/6);
391 int t1 = 0, t2 = 0;
392 for (int k = i; k < j; k++)
393 if (alg[k].m == base+1) t1 = (t1+1)%4;
394 else t2 = (t2+1)%4;
395 if (t1) { aux[c].inverse = inv; aux[c].m = base+t1; c++; }
396 if (t2) { aux[c].inverse = inv; aux[c].m = base+t2+3; c++; }
397 i = j;
398 }
399 aux[c].m = NULLMOVE;
400
401 CubeArray q;
402 cube_to_arrays(blank_cube(), &q, cpos_only);
403 /* First we try to rotate in one move, then we try an x or y rotation
404 followed by a z rotation */
405 for (int r = x; r <= z3; r++) {
406 move_cubearray(r, &q, cpos_only);
407 if (q.cpos[F_center] == front && q.cpos[U_center] == top) {
408 aux[c].inverse = inv; aux[c].m = r;
409
410 aux[++c].m = NULLMOVE;
411 copy_alg(aux, alg);
412 return;
413 }
414 move_cubearray(inverse[r], &q, cpos_only);
415 }
416 for (int r = x; r <= y3; r++) {
417 move_cubearray(r, &q, cpos_only);
418 if (q.cpos[F_center] == front) {
419 aux[c].inverse = inv; aux[c++].m = r;
420 break;
421 }
422 move_cubearray(inverse[r], &q, cpos_only);
423 }
424 for (int r = z; r <= z3; r++) {
425 move_cubearray(r, &q, cpos_only);
426 if (q.cpos[U_center] == top) {
427 aux[c].inverse = inv; aux[c++].m = r;
428 break;
429 }
430 move_cubearray(inverse[r], &q, cpos_only);
431 }
432
433 aux[c].m = NULLMOVE;
434 copy_alg(aux, alg);
435}
436
437void cleanup(NissMove *alg, int n) {
438 int count_n = 0, count_i = 0, *count;
439 NissMove aux_n[n+1], aux_i[n+1], *aux;
440 CubeArray cube_n, cube_i, *cube;
441 cube_to_arrays(blank_cube(), &cube_n, cpos_only);
442 cube_to_arrays(blank_cube(), &cube_i, cpos_only);
443
444 for (int i = 0; count_n + count_i < n && alg[i].m != NULLMOVE; i++) {
445 if (alg[i].inverse) { count = &count_i; aux = aux_i; cube = &cube_i; }
446 else { count = &count_n; aux = aux_n; cube = &cube_n; }
447
448 for (int j = 0; equiv_moves[alg[i].m][j]; j++) {
449 Move m = equiv_moves[alg[i].m][j];
450 aux[*count].inverse = alg[i].inverse;
451 move_cubearray(m, cube, cpos_only);
452 if (m == U) aux[(*count)++].m = 3 * cube->cpos[0] + 1;
453 }
454 }
455
456 aux_n[count_n].m = NULLMOVE;
457 aux_i[count_i].m = NULLMOVE;
458 sort_cancel_rotate(aux_n, count_n, false, cube_n.cpos[0], cube_n.cpos[4]);
459 sort_cancel_rotate(aux_i, count_i, true, cube_i.cpos[0], cube_n.cpos[4]);
460 copy_alg(aux_n, alg);
461 copy_alg(aux_i, alg+count_n);
462}
463
464Cube inverse_cube(Cube cube) {
465 CubeArray arr = {0}, inv = {0};
466 cube_to_arrays(cube, &arr, fAll);
467
468 for (int i = 0; i < 12; i++) {
469 inv.ep[arr.ep[i]] = i;
470 inv.eofb[arr.ep[i]] = arr.eofb[i];
471 inv.eorl[arr.ep[i]] = arr.eorl[i];
472 inv.eoud[arr.ep[i]] = arr.eoud[i];
473 }
474 for (int i = 0; i < 8; i++) {
475 inv.cp[arr.cp[i]] = i;
476 inv.coud[arr.cp[i]] = arr.coud[i];
477 inv.corl[arr.cp[i]] = arr.corl[i];
478 inv.cofb[arr.cp[i]] = arr.cofb[i];
479 }
480 for (int i = 0; i < 6; i++)
481 inv.cpos[arr.cpos[i]] = i;
482
483 return arrays_to_cube(inv, fAll);
484}
485
486bool read_ttables_file() {
487 FILE *ttf;
488 if ((ttf = fopen("ttables", "rb")) != NULL) {
489 for (int m = 0; m < NMOVES; m++) {
490 fread(epose_ttable[m], sizeof(uint16_t), factorial12/factorial8, ttf);
491 fread(eposs_ttable[m], sizeof(uint16_t), factorial12/factorial8, ttf);
492 fread(eposm_ttable[m], sizeof(uint16_t), factorial12/factorial8, ttf);
493 fread(eofb_ttable[m], sizeof(uint16_t), pow2to11, ttf);
494 fread(eorl_ttable[m], sizeof(uint16_t), pow2to11, ttf);
495 fread(eoud_ttable[m], sizeof(uint16_t), pow2to11, ttf);
496 fread(cp_ttable[m], sizeof(uint16_t), factorial8, ttf);
497 fread(coud_ttable[m], sizeof(uint16_t), pow3to7, ttf);
498 fread(corl_ttable[m], sizeof(uint16_t), pow3to7, ttf);
499 fread(cofb_ttable[m], sizeof(uint16_t), pow3to7, ttf);
500 fread(cpos_ttable[m], sizeof(uint16_t), factorial6, ttf);
501 }
502 fclose(ttf);
503 return true;
504 } else return false;
505}
506
507bool write_ttables_file() {
508 FILE *ttf;
509 if ((ttf = fopen("ttables", "wb")) != NULL) {
510 for (int m = 0; m < NMOVES; m++) {
511 fwrite(epose_ttable[m], sizeof(uint16_t), factorial12/factorial8, ttf);
512 fwrite(eposs_ttable[m], sizeof(uint16_t), factorial12/factorial8, ttf);
513 fwrite(eposm_ttable[m], sizeof(uint16_t), factorial12/factorial8, ttf);
514 fwrite(eofb_ttable[m], sizeof(uint16_t), pow2to11, ttf);
515 fwrite(eorl_ttable[m], sizeof(uint16_t), pow2to11, ttf);
516 fwrite(eoud_ttable[m], sizeof(uint16_t), pow2to11, ttf);
517 fwrite(cp_ttable[m], sizeof(uint16_t), factorial8, ttf);
518 fwrite(coud_ttable[m], sizeof(uint16_t), pow3to7, ttf);
519 fwrite(corl_ttable[m], sizeof(uint16_t), pow3to7, ttf);
520 fwrite(cofb_ttable[m], sizeof(uint16_t), pow3to7, ttf);
521 fwrite(cpos_ttable[m], sizeof(uint16_t), factorial6, ttf);
522 }
523 fclose(ttf);
524 return true;
525 } else return false;
526}
527
528void init_ttables(bool read, bool write) {
529 /* Generate all move cycles and flips; I do this regardless */
530 for (int i = 0; i < NMOVES; i++) {
531 if (i == U || i == x || i == y)
532 continue;
533
534 CubeArray arr = {0};
535 cube_to_arrays(blank_cube(), &arr, fAll);
536 for (int j = 0; equiv_moves[i][j]; j++)
537 move_cubearray(equiv_moves[i][j], &arr, fAll);
538
539 intarrcopy(arr.ep, edge_cycle[i], 12);
540 intarrcopy(arr.eofb, eofb_flipped[i], 12);
541 intarrcopy(arr.eorl, eorl_flipped[i], 12);
542 intarrcopy(arr.eoud, eoud_flipped[i], 12);
543 intarrcopy(arr.cp, corner_cycle[i], 8);
544 intarrcopy(arr.coud, coud_flipped[i], 8);
545 intarrcopy(arr.corl, corl_flipped[i], 8);
546 intarrcopy(arr.cofb, cofb_flipped[i], 8);
547 intarrcopy(arr.cpos, center_cycle[i], 6);
548 }
549
550 if (read)
551 if (read_ttables_file())
552 return;
553
554 /* Initialize transition tables */
555 Cube c = {0};
556 PieceFilter fe = {.epose=true}, fs = {.eposs=true}, fm = {.eposm=true};
557 PieceFilter feo = { .eofb = true, .eorl = true, .eoud = true };
558 PieceFilter fcp = { .cp = true };
559 PieceFilter fco = { .cofb = true, .corl = true, .coud = true };
560 PieceFilter fcc = { .cpos = true };
561 for (int m = 0; m < NMOVES; m++) {
562 for (uint16_t i = 0; i < factorial12/factorial8; i++) {
563 c.epose = i; epose_ttable[m][i] = move_via_array(m, c, fe).epose;
564 c.eposs = i; eposs_ttable[m][i] = move_via_array(m, c, fs).eposs;
565 c.eposm = i; eposm_ttable[m][i] = move_via_array(m, c, fm).eposm;
566 }
567 for (uint16_t i = 0; i < pow2to11; i++ ) {
568 c.eofb = i; eofb_ttable[m][i] = move_via_array(m, c, feo).eofb;
569 c.eorl = i; eorl_ttable[m][i] = move_via_array(m, c, feo).eorl;
570 c.eoud = i; eoud_ttable[m][i] = move_via_array(m, c, feo).eoud;
571 }
572 for (uint16_t i = 0; i < factorial8; i++) {
573 c.cp = i; cp_ttable[m][i] = move_via_array(m, c, fcp).cp;
574 }
575 for (uint16_t i = 0; i < pow3to7; i++) {
576 c.coud = i; coud_ttable[m][i] = move_via_array(m, c, fco).coud;
577 c.corl = i; corl_ttable[m][i] = move_via_array(m, c, fco).corl;
578 c.cofb = i; cofb_ttable[m][i] = move_via_array(m, c, fco).cofb;
579 }
580 for (uint16_t i = 0; i < factorial6; i++) {
581 c.cpos = i; cpos_ttable[m][i] = move_via_array(m, c, fcc).cpos;
582 }
583 }
584
585 if (write) write_ttables_file();
586}
587
588Cube move_cube(Move m, Cube cube) {
589 Cube moved = cube;
590
591 moved.epose = epose_ttable[m][cube.epose];
592 moved.eposs = eposs_ttable[m][cube.eposs];
593 moved.eposm = eposm_ttable[m][cube.eposm];
594 moved.eofb = eofb_ttable[m][cube.eofb];
595 moved.eorl = eorl_ttable[m][cube.eorl];
596 moved.eoud = eoud_ttable[m][cube.eoud];
597 moved.coud = coud_ttable[m][cube.coud];
598 moved.cofb = cofb_ttable[m][cube.cofb];
599 moved.corl = corl_ttable[m][cube.corl];
600 moved.cp = cp_ttable[m][cube.cp];
601 moved.cpos = cpos_ttable[m][cube.cpos];
602
603 return moved;
604}
605
606Cube compose(Cube c2, Cube c1) {
607 /* This is basically the same as the move_cubearray function above */
608 CubeArray arr2 = {0}, arr1 = {0};
609 cube_to_arrays(c2, &arr2, fAll);
610 cube_to_arrays(c1, &arr1, fAll);
611
612 apply_permutation(arr2.ep, arr1.ep, 12);
613 apply_permutation(arr2.ep, arr1.eofb, 12);
614 apply_permutation(arr2.ep, arr1.eorl, 12);
615 apply_permutation(arr2.ep, arr1.eoud, 12);
616 sum_arrays_mod(arr2.eofb, arr1.eofb, 12, 2);
617 sum_arrays_mod(arr2.eorl, arr1.eorl, 12, 2);
618 sum_arrays_mod(arr2.eoud, arr1.eoud, 12, 2);
619 apply_permutation(arr2.cp, arr1.cp, 8);
620 apply_permutation(arr2.cp, arr1.coud, 8);
621 apply_permutation(arr2.cp, arr1.corl, 8);
622 apply_permutation(arr2.cp, arr1.cofb, 8);
623 sum_arrays_mod(arr2.coud, arr1.coud, 8, 3);
624 sum_arrays_mod(arr2.corl, arr1.corl, 8, 3);
625 sum_arrays_mod(arr2.cofb, arr1.cofb, 8, 3);
626 apply_permutation(arr2.cpos, arr1.cpos, 6);
627
628 return arrays_to_cube(arr1, fAll);
629}
630
631Cube apply_alg(NissMove *alg, Cube cube) {
632 Cube ret = {0};
633 for (int i = 0; alg[i].m != NULLMOVE; i++)
634 if (alg[i].inverse)
635 ret = move_cube(alg[i].m, ret);
636 ret = compose(cube, inverse_cube(ret));
637
638 for (int i = 0; alg[i].m != NULLMOVE; i++)
639 if (!alg[i].inverse)
640 ret = move_cube(alg[i].m, ret);
641 return ret;
642}
643
644void init_aux_tables() {
645 /* Commute */
646 for (int i = 0; i < NMOVES; i++)
647 for (int j = 0; j < NMOVES; j++)
648 commute[i][j] = equal(move_cube(i, move_cube(j, blank_cube())),
649 move_cube(j, move_cube(i, blank_cube())));
650
651 /* Possible next (if the sequence i j k is valid) */
652 for (int i = 0; i < NMOVES; i++)
653 for (int j = 0; j < NMOVES; j++)
654 for (int k = 0; k < NMOVES; k++)
655 possible_next[i][j][k] =
656 (j == 0) ||
657 (j != 0 && (j-(j-1)%3) != (k-(k-1)%3) &&
658 !(i != 0 && commute[i][j] && (i-(i-1)%3) == (k-(k-1)%3)));
659
660 /* Inverse */
661 for (int i = 0; i < NMOVES; i++)
662 inverse[i] = i == 0 ? 0 : i + 2 - 2*((i-1)%3);
663}
664
diff --git a/old/2021-02-06/cube.h b/old/2021-02-06/cube.h
new file mode 100644
index 0000000..bc4f14b
--- /dev/null
+++ b/old/2021-02-06/cube.h
@@ -0,0 +1,60 @@
1#ifndef CUBE_H
2#define CUBE_H
3
4#include <stdio.h>
5#include <stdbool.h>
6#include <stdint.h>
7#include "utils.h"
8
9#define NMOVES (z3+1)
10
11/* Constants for moves and pieces */
12typedef enum {
13 NULLMOVE,
14 U, U2, U3, D, D2, D3, R, R2, R3, L, L2, L3, F, F2, F3, B, B2, B3,
15 Uw, Uw2, Uw3, Dw, Dw2, Dw3, Rw, Rw2, Rw3,
16 Lw, Lw2, Lw3, Fw, Fw2, Fw3, Bw, Bw2, Bw3,
17 M, M2, M3, S, S2, S3, E, E2, E3,
18 x, x2, x3, y, y2, y3, z, z2, z3,
19} Move;
20typedef enum {U_center,D_center,R_center,L_center,F_center,B_center} Center;
21typedef enum { UF, UL, UB, UR, DF, DL, DB, DR, FR, FL, BL, BR } Edge;
22typedef enum { UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR } Corner;
23
24/* An alg is an array of "NissMoves", which can be on normal or on inverse. */
25typedef struct { bool inverse; Move m; } NissMove;
26
27/* Representation of the cube */
28typedef struct {
29 uint16_t eofb, eorl, eoud, coud, cofb, corl,
30 epose, eposs, eposm, cp, cpos;
31} Cube;
32
33extern bool commute[NMOVES][NMOVES];
34extern bool possible_next[NMOVES][NMOVES][NMOVES];
35extern Move inverse[NMOVES];
36/* Movesets */
37extern bool standard_moveset[NMOVES];
38
39int copy_alg(NissMove *src, NissMove *dest); /*return number of moves copied */
40
41bool equal(Cube c1, Cube c2);
42bool is_solvable(Cube cube);
43/* reorient=true allows solved in wrong orientation */
44bool is_solved(Cube cube, bool reorient);
45void print_cube(Cube cube);
46void print_moves(NissMove *alg);
47int read_moves(char *str, NissMove *alg, int n); /* reads at most n moves */
48void cleanup(NissMove *src, int n); /* rewrites using basic moves, at most n */
49Cube blank_cube();
50Cube inverse_cube(Cube cube);
51Cube move_cube(Move m, Cube cube);
52Cube compose(Cube c2, Cube c1); /* Use c2 as an alg */
53Cube apply_alg(NissMove *alg, Cube cube);
54
55void init_ttables(bool read, bool write);
56void init_aux_tables();
57
58void init_dbg();
59
60#endif
diff --git a/old/2021-02-06/main.c b/old/2021-02-06/main.c
new file mode 100644
index 0000000..c7be782
--- /dev/null
+++ b/old/2021-02-06/main.c
@@ -0,0 +1,46 @@
1#include <stdio.h>
2#include "cube.h"
3#include "solve.h"
4
5int main() {
6 init_ttables(true, true);
7 init_aux_tables();
8
9
10 char moves[100] = "MR U' B2 Bw F z xE2 M' x Dw' y Fw2 y2";
11 NissMove alg[100];
12 read_moves(moves, alg, 100);
13 Cube cube = apply_alg(alg, blank_cube());
14
15 /*f_eofb(cube);*/
16
17
18/* NissMove sol[MAXS][MAXM];*/
19 SolveData d = { .optimal_only = true, .available = standard_moveset,
20 .max_moves = 10,
21 .cleanup = true,
22 .max_solutions = 10,
23 .f = f_eofb };
24 read_moves("y", d.pre_rotation, 2);
25 int n = solve(cube, &d);
26 printf("%d solutions found:\n", n);
27 for (int i = 0; i < n; i++)
28 print_moves(d.solutions[i]);
29
30 NissMove a[5], b[5];
31 read_moves("R", a, 5);
32 read_moves("U", b, 5);
33 Cube c1 = apply_alg(a,blank_cube()), c2 = apply_alg(b,blank_cube());
34 print_cube(compose(c2,c1));
35 print_cube(compose(c1,c2));
36 /*print_cube(compose(c2,blank_cube()));*/
37
38 NissMove nm[10];
39 read_moves("y(y)RU", nm, 10);
40
41 print_moves(nm);
42 cleanup(nm, 10);
43 print_moves(nm);
44
45 return 0;
46}
diff --git a/old/2021-02-06/solve.c b/old/2021-02-06/solve.c
new file mode 100644
index 0000000..f6274e9
--- /dev/null
+++ b/old/2021-02-06/solve.c
@@ -0,0 +1,177 @@
1#include "solve.h"
2
3/* Data for creating a pruning table:
4 - compressed: if set to true, each entry occupies only 4 bits, but values
5 larger than 15 cannot be stored.
6 - available[] is the list of availabel moves, as above.
7 - *ptable is the actual table to fill.
8 - n is the number of states (size of ptable).
9 - index must "linearize" the cube, i.e. return its index in ptable.
10 - fname is the name of the file where to store the table */
11typedef struct {
12 bool compressed, *available;
13 int max_moves;
14 uint8_t *ptable;
15 uint64_t n;
16 uint64_t (*index)(Cube);
17 char *fname;
18} PruneData;
19
20/* TODO: comment this */
21typedef struct {
22 bool niss;
23 int m, d;
24 uint64_t *n;
25 Move last1, last2;
26} DfsData;
27
28void solve_dfs(Cube cube, SolveData *sd, DfsData dd);
29void init_ptable(PruneData *pd, bool read, bool write);
30
31/* Search solutions of lenght exactly d */
32void solve_dfs(Cube cube, SolveData *sd, DfsData dd) {
33 if (*dd.n >= sd->max_solutions ||
34 ((!sd->can_niss || dd.niss) && dd.m + sd->f(cube) > dd.d))
35 return;
36
37 (sd->solutions[*dd.n][dd.m]).inverse = dd.niss;
38 (sd->solutions[*dd.n][dd.m]).m = NULLMOVE;
39
40 if (!sd->f(cube)) { /* Solved */
41 if (dd.m == dd.d) {
42 (*dd.n)++;
43 if (*dd.n < sd->max_solutions)
44 copy_alg(sd->solutions[*dd.n-1], sd->solutions[*dd.n]);
45 }
46 return;
47 }
48
49 for (int i = 0; i < NMOVES && sd->sorted_moves[i] != NULLMOVE; i++) {
50 Move move = sd->sorted_moves[i];
51 if (possible_next[dd.last2][dd.last1][move]) {
52 sd->solutions[*dd.n][dd.m].inverse = dd.niss;
53 sd->solutions[*dd.n][dd.m].m = move;
54 DfsData nn = { .niss = dd.niss, .m = dd.m+1, .d = dd.d, .n = dd.n,
55 .last1 = move, .last2 = dd.last1 };
56 solve_dfs(move_cube(move, cube), sd, nn);
57 }
58 }
59
60 if (sd->can_niss && !dd.niss &&
61 (!dd.m || (dd.m && sd->f(move_cube(dd.last1, blank_cube()))))) {
62 DfsData nn = { .niss = true, .m = dd.m, .d = dd.d, .n = dd.n };
63 solve_dfs(inverse_cube(cube), sd, nn);
64 }
65}
66
67/* Iterative deepening depth-first search: for i running from the minimum
68 to the maximum number of moves allowed, looks for solutions of length i. */
69int solve(Cube cube, SolveData *sd) {
70 if (sd->precondition != NULL && !sd->precondition(cube))
71 return -1;
72
73 /* If not given, generate sorted list of moves */
74 if (sd->sorted_moves[0] == NULLMOVE) {
75 int a[NMOVES], b[NMOVES], ia = 0, ib = 0;
76 for (int i = 0; i < NMOVES; i++) {
77 if (sd->available[i]) {
78 if (sd->f(move_cube(i, blank_cube())))
79 a[ia++] = i;
80 else
81 b[ib++] = i;
82 }
83 }
84 intarrcopy(a, (int *)sd->sorted_moves, ia);
85 intarrcopy(b, (int *)sd->sorted_moves+ia, ib);
86 sd->sorted_moves[ia+ib] = NULLMOVE;
87 }
88
89 sd->max_solutions = min(sd->max_solutions, MAXS);
90 Cube rotated = apply_alg(sd->pre_rotation, blank_cube());
91 cube = apply_alg(inverse_cube(rotated), compose(cube, rotated));
92
93 uint64_t ret = 0;
94 for (int i=sd->min_moves; i<=sd->max_moves&&!(ret&&sd->optimal_only); i++) {
95 DfsData dd = { .d = i, .n = &ret };
96 solve_dfs(cube, sd, dd);
97 }
98
99 for (uint64_t i = 0; i < ret; i++) {
100 /* TODO: transform solutions with inverse of pre_rotation */
101 if (sd->cleanup)
102 cleanup(sd->solutions[i], sd->max_moves*3);
103 }
104
105 return ret;
106}
107
108void prune_dfs(Cube cube, PruneData *pd, DfsData dd) {
109 uint64_t ind = pd->index(cube);
110 if ((!ind || pd->ptable[ind]) && pd->ptable[ind] != dd.m)
111 return;
112 if (dd.m == dd.d) {
113 if (ind && !pd->ptable[ind]) {
114 pd->ptable[ind] = dd.m;
115 (*dd.n)++;
116 }
117 return;
118 }
119
120 for (int i = 0; i < NMOVES; i++) {
121 if (dd.m<20)
122 if (possible_next[dd.last2][dd.last1][i] && pd->available[i]) {
123 DfsData nn = { .m = dd.m+1, .d = dd.d, .n = dd.n,
124 .last1 = i, .last2 = dd.last1 };
125 prune_dfs(move_cube(i, cube), pd, nn);
126 }
127 }
128}
129
130void init_ptable(PruneData *pd, bool read, bool write) {
131 if (read) {
132 FILE *ptf;
133 if ((ptf = fopen(pd->fname, "rb")) != NULL) {
134 fread(pd->ptable, sizeof(uint8_t), pd->n, ptf);
135 fclose(ptf);
136 return;
137 }
138 }
139
140 /* TODO: for now it behaves always as if copressed = false */
141 for (uint64_t i = 0; i < pd->n; i++)
142 pd->ptable[i] = 0;
143
144 uint64_t s = 1;
145 for (int i = 1; i < pd->max_moves && s < pd->n; i++) {
146 DfsData dd = { .d = i, .n = &s };
147 prune_dfs(blank_cube(), pd, dd);
148 }
149
150 if (write) {
151 FILE *ptf;
152 if ((ptf = fopen(pd->fname, "wb")) != NULL) {
153 fwrite(pd->ptable, sizeof(uint8_t), pd->n, ptf);
154 fclose(ptf);
155 return;
156 }
157 }
158}
159
160/* Solving steps (and indexing functions) */
161
162uint64_t index_eofb(Cube cube) { return cube.eofb; }
163uint16_t f_eofb(Cube cube) {
164 static bool initialized_ptable;
165 static uint8_t pt_eofb[pow2to11];
166 if (!initialized_ptable) {
167 PruneData pd = {
168 .compressed = false, .available = standard_moveset, .max_moves = 13,
169 .ptable = pt_eofb, .n = pow2to11, .index = index_eofb,
170 .fname = "ptable_eofb"
171 };
172 init_ptable(&pd, false, true);
173 initialized_ptable = true;
174 }
175 return cube.eofb ? pt_eofb[cube.eofb] : 0;
176}
177
diff --git a/old/2021-02-06/solve.h b/old/2021-02-06/solve.h
new file mode 100644
index 0000000..6479e14
--- /dev/null
+++ b/old/2021-02-06/solve.h
@@ -0,0 +1,55 @@
1#ifndef SOLVE_H
2#define SOLVE_H
3
4#include <stdlib.h>
5#include "cube.h"
6
7/* Maximum number of moves per solution and of solutions */
8#define MAXM 30
9#define MAXS 999
10
11/* Data for solving a step:
12 - can_niss is true niss can be used, false otherwise.
13 - optimal_only if true, dynamically updates max_moves so non-optimal
14 solutions are discarded.
15 - cleanup determines whether the cleaunup() function should be used on
16 the found solutions before returning.
17 - available[m] is true if the move m can be used, false otherwise.
18 - min_moves and max_moves are the minimum and maximum number of moves that
19 can be used.
20 - max_solution is the maximum number of solutions that can be returned.
21 - precondition can be used to check wheter the step can actually be applied
22 to the cube. If it returns false, solve() stops immediately returning -1.
23 - f must return 0 if and only if the step is solve, otherwise it must return
24 a lower bound for the number of moves required (without niss).
25 - sorted_moves[] can be used to specify in which order moves are tried
26 by the solving algorithm (for example if one wants to always try F' before
27 F). If sorted_moves[0] == NULLMOVE, the list is generated automatically.
28 It is advised to list first all the moves that actually influence the
29 solved state of the step (this is the default choice). This is in order to
30 avoid cases like B2 F for EO and to NISS only when it makes sense.
31 - start_moves [Currently unused, REMOVE]
32 are the moves that will be used as first moves of all
33 solutions. For example giving R' U' F (F' U R) will generate FMC scrambles
34 and y (y) will solve the step on another axis.
35 - pre_rotation are the rotations to apply before the scamble to solve
36 the step wrt a different orientation
37 - pre_rotation are the rotations to apply before the scamble to solve
38 the step wth respect to a different orientation.
39 - solutions[][] is the array where to store the found solutions. */
40typedef struct {
41 bool can_niss, optimal_only, cleanup, *available;
42 int min_moves, max_moves;
43 uint64_t max_solutions;
44 bool (*precondition)(Cube);
45 uint16_t (*f)(Cube);
46 Move sorted_moves[NMOVES];
47 NissMove pre_rotation[3], solutions[MAXS][MAXM];
48} SolveData;
49
50int solve(Cube cube, SolveData *data); /* Returns the number of solutions. */
51
52/* Steps */
53uint16_t f_eofb(Cube cube);
54
55#endif
diff --git a/old/2021-02-06/utils.c b/old/2021-02-06/utils.c
new file mode 100644
index 0000000..66de9ad
--- /dev/null
+++ b/old/2021-02-06/utils.c
@@ -0,0 +1,197 @@
1#include "utils.h"
2
3void swap(int *a, int *b) {
4 int aux = *a;
5 *a = *b;
6 *b = aux;
7}
8
9void intarrcopy(int *src, int *dst, int n) {
10 for (int i = 0; i < n; i++)
11 dst[i] = src[i];
12}
13
14int sum(int *a, int n) {
15 int ret = 0;
16 for (int i = 0; i < n; i++)
17 ret += a[i];
18 return ret;
19}
20
21bool is_perm(int *a, int n) {
22 int aux[n]; for (int i = 0; i < n; i++) aux[i] = 0;
23 for (int i = 0; i < n; i++)
24 if (a[i] < 0 || a[i] >= n)
25 return false;
26 else
27 aux[a[i]] = 1;
28 for (int i = 0; i < n; i++)
29 if (!aux[i])
30 return false;
31 return true;
32}
33
34bool is_subset(int *a, int n, int k) {
35 int sum = 0;
36 for (int i = 0; i < n; i++)
37 sum += a[i] ? 1 : 0;
38 return sum == k;
39}
40
41int powint(int a, int b) {
42 return 0;
43 if (b == 0 || a == 1)
44 return 1;
45 if (a == 0)
46 return 0;
47 if (b < 0)
48 return 0; /* Immediate truncate (integer part is 0) */
49 if (b % 2) {
50 return a * powint(a, b-1);
51 } else {
52 int x = powint(a, b/2);
53 return x*x;
54 }
55}
56
57int factorial(int n) {
58 if (n < 0)
59 return 0;
60 int ret = 1;
61 for (int i = 1; i <= n; i++)
62 ret *= i;
63 return ret;
64}
65
66int binomial(int n, int k) {
67 if (n < 0 || k < 0 || k > n)
68 return 0;
69 return factorial(n) / (factorial(k) * factorial(n-k));
70}
71
72void int_to_digit_array(int a, int b, int n, int *r) {
73 if (b <= 1)
74 for (int i = 0; i < n; i++)
75 r[i] = 0;
76 else
77 for (int i = 0; i < n; i++, a /= b)
78 r[i] = a % b;
79}
80
81int digit_array_to_int(int *a, int n, int b) {
82 int ret = 0, p = 1;
83 for (int i = 0; i < n; i++, p *= b)
84 ret += a[i] * p;
85 return ret;
86}
87
88int perm_to_index(int *a, int n) {
89 if (!is_perm(a, n))
90 return factorial(n); /* Error */
91 int ret = 0;
92 for (int i = 0; i < n; i++) {
93 int c = 0;
94 for (int j = i+1; j < n; j++)
95 c += (a[i] > a[j]) ? 1 : 0;
96 ret += factorial(n-i-1) * c;
97 }
98 return ret;
99}
100
101void index_to_perm(int p, int n, int *r) {
102 if (p < 0 || p >= factorial(n)) /* Error */
103 for (int i = 0; i < n; i++)
104 r[i] = -1;
105 int a[n]; for (int j = 0; j < n; j++) a[j] = 0; /* picked elements */
106 for (int i = 0; i < n; i++) {
107 int c = 0, j = 0;
108 while (c <= p / factorial(n-i-1))
109 c += a[j++] ? 0 : 1;
110 r[i] = j-1;
111 a[j-1] = 1;
112 p %= factorial(n-i-1);
113 }
114}
115
116int perm_sign(int *a, int n) {
117 if (!is_perm(a,n))
118 return false;
119 int ret = 0;
120 for (int i = 0; i < n; i++)
121 for (int j = i+1; j < n; j++)
122 ret += (a[i]>a[j]) ? 1 : 0;
123 return ret % 2;
124}
125
126int subset_to_index(int *a, int n, int k) {
127 /* TODO: better checks */
128 if (!is_subset(a, n, k))
129 return binomial(n, k); /* Error */
130 int ret = 0;
131 for (int i = 0; i < n; i++) {
132 if (k == n-i)
133 return ret;
134 if (a[i]) {
135 /*ret += factorial(n-i-1) / (factorial(k) * factorial(n-i-1-k));*/
136 ret += binomial(n-i-1, k);
137 k--;
138 }
139 }
140 return ret;
141}
142
143void index_to_subset(int s, int n, int k, int *r) {
144 if (s < 0 || s >= binomial(n, k)) { /* Error */
145 for (int i = 0; i < n; i++)
146 r[i] = -1;
147 return;
148 }
149 for (int i = 0; i < n; i++) {
150 if (k == n-i) {
151 for (int j = i; j < n; j++)
152 r[j] = 1;
153 return;
154 }
155 if (k == 0) {
156 for (int j = i; j < n; j++)
157 r[j] = 0;
158 return;
159 }
160 /*int v = factorial(n-i-1) / (factorial(k) * factorial(n-i-1-k));*/
161 int v = binomial(n-i-1, k);
162 if (s >= v) {
163 r[i] = 1;
164 k--;
165 s -= v;
166 } else {
167 r[i] = 0;
168 }
169 }
170}
171
172void int_to_sum_zero_array(int x, int b, int n, int *a) {
173 if (b <= 1) {
174 for (int i = 0; i < n; i++)
175 a[i] = 0;
176 } else {
177 int_to_digit_array(x, b, n-1, a);
178 int s = 0;
179 for (int i = 0; i < n - 1; i++)
180 s = (s + a[i]) % b;
181 a[n-1] = (b - s) % b;
182 }
183}
184
185void apply_permutation(int *perm, int *set, int n) {
186 if (!is_perm(perm, n))
187 return;
188 int aux[n];
189 for (int i = 0; i < n; i++)
190 aux[i] = set[perm[i]];
191 intarrcopy(aux, set, n);
192}
193
194void sum_arrays_mod(int *a, int *b, int n, int m) {
195 for (int i = 0; i < n; i++)
196 b[i] = (m <= 0) ? 0 : (a[i] + b[i]) % m;
197}
diff --git a/old/2021-02-06/utils.h b/old/2021-02-06/utils.h
new file mode 100644
index 0000000..4b6df8c
--- /dev/null
+++ b/old/2021-02-06/utils.h
@@ -0,0 +1,70 @@
1/* General utility functions */
2
3#ifndef UTILS_H
4#define UTILS_H
5
6#include <stdbool.h>
7
8#define min(a,b) (((a) < (b)) ? (a) : (b))
9#define max(a,b) (((a) > (b)) ? (a) : (b))
10
11/* Some useful constants */
12#define pow2to11 2048
13#define pow2to12 4096
14#define pow3to7 2187
15#define pow3to8 6561
16#define pow12to4 20736
17#define factorial4 24
18#define factorial6 720
19#define factorial8 40320
20#define factorial12 479001600
21#define binom12on4 495
22#define binom8on4 70
23
24/* Generic utility functions */
25void swap(int *a, int *b);
26void intarrcopy(int *src, int *dst, int n);
27int sum(int *a, int n);
28bool is_perm(int *a, int n);
29bool is_perm(int *a, int n);
30
31
32/* Standard mathematical functions */
33int powint(int a, int b);
34int factorial(int n);
35int binomial(int n, int k);
36
37/* Converts the integer a to its representation in base b (first n digits
38 * only) and saves the result in r. */
39void int_to_digit_array(int a, int b, int n, int *r);
40int digit_array_to_int(int *a, int n, int b);
41
42/* Converts the first n-1 digits of a number to an array a of digits in base b;
43 * then adds one element to the array, so that the sum of the elements of a is
44 * zero modulo b.
45 * This is used for determing the edge orientation from an 11-bits integer or
46 * the corner orientation from a 7-trits integer. */
47void int_to_sum_zero_array(int x, int b, int n, int *a);
48
49/* Converts a permutation on [0..(n-1)] into the integer i which is the index
50 * of the permutation in the sorted list of all n! such permutations. */
51int perm_to_index(int *a, int n);
52void index_to_perm(int p, int n, int *r);
53
54/* Determine the sign of a permutation */
55int perm_sign(int a[], int n);
56
57/* Converts a k-element subset of a set from an array of n elements, of which k
58 * are 1 and n-k are 0, to its index in the sorted list of all such subsets. */
59int subset_to_index(int *a, int n, int k);
60void index_to_subset(int s, int n, int k, int *r);
61
62int ordered_subset_to_index(int *a, int n, int k);
63void index_to_ordered_subset(int s, int n, int k, int *r);
64
65void apply_permutation(int *perm, int *set, int n);
66
67/* b[i] = (a[i]+b[i])%m for i=1,...,n */
68void sum_arrays_mod(int *a, int *b, int n, int m);
69
70#endif
diff --git a/old/2021-02-18-piecefilter/compile.sh b/old/2021-02-18-piecefilter/compile.sh
new file mode 100755
index 0000000..ce6506f
--- /dev/null
+++ b/old/2021-02-18-piecefilter/compile.sh
@@ -0,0 +1 @@
gcc -Wall -Wextra -O2 -std=c99 -o nissy ./src/*.c
diff --git a/old/2021-02-18-piecefilter/nissy b/old/2021-02-18-piecefilter/nissy
new file mode 100755
index 0000000..ec8c14d
--- /dev/null
+++ b/old/2021-02-18-piecefilter/nissy
Binary files differ
diff --git a/old/2021-02-18-piecefilter/src/cube.c b/old/2021-02-18-piecefilter/src/cube.c
new file mode 100644
index 0000000..9235c03
--- /dev/null
+++ b/old/2021-02-18-piecefilter/src/cube.c
@@ -0,0 +1,198 @@
1#include "cube.h"
2
3char edge_string[12][5] =
4 { "UF", "UL", "UB", "UR", "DF", "DL", "DB", "DR", "FR", "FL", "BL", "BR" };
5char corner_string[8][5] = { "UFR","UFL","UBL","UBR","DFR","DFL","DBL","DBR" };
6char center_string[6][5] = { "U", "D", "R", "L", "F", "B" };
7
8int epe_solved[] = {FR, FL, BL, BR};
9int eps_solved[] = {UL, UR, DL, DR};
10int epm_solved[] = {UF, UB, DF, DB};
11
12PieceFilter fAll = {true,true,true,true,true,true,true,true,true,true,true};
13
14Cube blank_cube() {
15 Cube c = {0};
16 return c;
17}
18
19/* Return axis (ud=0, rl=1, fb=0) of center c */
20int center_axis(int c) {
21 if (c == U_center || c == D_center)
22 return 0;
23 if (c == R_center || c == L_center)
24 return 1;
25 return 2;
26}
27
28/* Return slice (e=0, s=1, m=2) to which e belongs */
29int edge_slice(int e) {
30 if (e == FR || e == FL || e == BL || e == BR)
31 return 0;
32 if (e == UR || e == UL || e == DR || e == DL)
33 return 1;
34 return 2;
35}
36
37void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f) {
38 /* ep is the hardest */
39 if (f.epose || f.eposs || f.eposm)
40 for (int i = 0; i < 12; i++) arr->ep[i] = -1;
41 if (f.epose) {
42 int epe[4], epose[12];
43 index_to_perm(cube.epose % factorial(4), 4, epe);
44 index_to_subset(cube.epose / factorial(4), 12, 4, epose);
45 for (int i = 0, ie = 0; i < 12; i++)
46 if (epose[i]) arr->ep[i] = epe_solved[epe[ie++]];
47 }
48 if (f.eposs) {
49 int eps[4], eposs[12];
50 index_to_perm(cube.eposs % factorial(4), 4, eps);
51 index_to_subset(cube.eposs / factorial(4), 12, 4, eposs);
52 for (int i = 0; i < 4; i++) swap(&eposs[eps_solved[i]], &eposs[i+8]);
53 for (int i = 0, is = 0; i < 12; i++)
54 if (eposs[i]) arr->ep[i] = eps_solved[eps[is++]];
55 }
56 if (f.eposm) {
57 int epm[4], eposm[12];
58 index_to_perm(cube.eposm % factorial(4), 4, epm);
59 index_to_subset(cube.eposm / factorial(4), 12, 4, eposm);
60 for (int i = 0; i < 4; i++) swap(&eposm[epm_solved[i]], &eposm[i+8]);
61 for (int i = 0, im = 0; i < 12; i++)
62 if (eposm[i]) arr->ep[i] = epm_solved[epm[im++]];
63 }
64
65 /* All the others */
66 if (f.eofb) int_to_sum_zero_array(cube.eofb, 2, 12, arr->eofb);
67 if (f.eorl) int_to_sum_zero_array(cube.eorl, 2, 12, arr->eorl);
68 if (f.eoud) int_to_sum_zero_array(cube.eoud, 2, 12, arr->eoud);
69 if (f.cp) index_to_perm( cube.cp, 8, arr->cp);
70 if (f.coud) int_to_sum_zero_array(cube.coud, 3, 8, arr->coud);
71 if (f.corl) int_to_sum_zero_array(cube.corl, 3, 8, arr->corl);
72 if (f.cofb) int_to_sum_zero_array(cube.cofb, 3, 8, arr->cofb);
73 if (f.cpos) index_to_perm( cube.cpos, 6, arr->cpos);
74}
75
76Cube arrays_to_cube(CubeArray arr, PieceFilter f) {
77 Cube ret = {0};
78
79 /* Again, ep is the hardest part */
80 if (f.epose) {
81 int epe[4], epose[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
82 for (int i = 0, ie = 0; i < 12; i++)
83 for (int j = 0; j < 4; j++)
84 if (arr.ep[i] == epe_solved[j])
85 { epe[ie++] = j; epose[i] = 1; }
86 ret.epose = factorial(4)*subset_to_index(epose,12,4)+perm_to_index(epe,4);
87 }
88 if (f.eposs) {
89 int eps[4], eposs[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
90 for (int i = 0, is = 0; i < 12; i++)
91 for (int j = 0; j < 4; j++)
92 if (arr.ep[i] == eps_solved[j])
93 { eps[is++] = j; eposs[i] = 1; }
94 for (int i = 0; i < 4; i++) swap(&eposs[eps_solved[i]], &eposs[i+8]);
95 ret.eposs = factorial(4)*subset_to_index(eposs,12,4)+perm_to_index(eps,4);
96 }
97 if (f.eposm) {
98 int epm[4], eposm[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
99 for (int i = 0, im = 0; i < 12; i++)
100 for (int j = 0; j < 4; j++)
101 if (arr.ep[i] == epm_solved[j])
102 { epm[im++] = j; eposm[i] = 1; }
103 for (int i = 0; i < 4; i++) swap(&eposm[epm_solved[i]], &eposm[i+8]);
104 ret.eposm = factorial(4)*subset_to_index(eposm,12,4)+perm_to_index(epm,4);
105 }
106 if (f.eofb) ret.eofb = digit_array_to_int(arr.eofb, 11, 2);
107 if (f.eorl) ret.eorl = digit_array_to_int(arr.eorl, 11, 2);
108 if (f.eoud) ret.eoud = digit_array_to_int(arr.eoud, 11, 2);
109 if (f.cp) ret.cp = perm_to_index( arr.cp, 8 );
110 if (f.coud) ret.coud = digit_array_to_int(arr.coud, 7, 3);
111 if (f.corl) ret.corl = digit_array_to_int(arr.corl, 7, 3);
112 if (f.cofb) ret.cofb = digit_array_to_int(arr.cofb, 7, 3);
113 if (f.cpos) ret.cpos = perm_to_index( arr.cpos, 6 );
114
115 return ret;
116}
117
118bool equal(Cube c1, Cube c2) {
119 return c1.eofb == c2.eofb && c1.epose == c2.epose &&
120 c1.eposs == c2.eposs && c1.eposm == c2.eposm &&
121 c1.coud == c2.coud && c1.cp == c2.cp &&
122 c1.cpos == c2.cpos;
123}
124
125bool solvable(Cube cube) {
126 /* Since we memorize orientation truncating the last digit, we only need to
127 * check that the permutations have the correct sign. */
128 CubeArray arr = {0};
129 cube_to_arrays(cube, &arr, fAll);
130 return (perm_sign(arr.ep,12) ^ perm_sign(arr.cpos,6)) == perm_sign(arr.cp,8);
131}
132
133bool is_solved(Cube cube) {
134 return !cube.eofb && !cube.coud && !cube.cp &&
135 !cube.epose && !cube.eposs && !cube.eposm && cube.cpos;
136}
137
138void print_cube(Cube cube) {
139 CubeArray arr = {0};
140 cube_to_arrays(cube, &arr, fAll);
141
142 for (int i = 0; i < 12; i++) printf(" %s ", edge_string[arr.ep[i]]);
143 printf("\n");
144 for (int i = 0; i < 12; i++) printf(" %c ", arr.eofb[i] + '0');
145 printf("\n");
146 for (int i = 0; i < 8; i++) printf("%s ", corner_string[arr.cp[i]]);
147 printf("\n");
148 for (int i = 0; i < 8; i++) printf(" %c ", arr.coud[i] + '0');
149 printf("\n");
150 for (int i = 0; i < 6; i++) printf(" %s ", center_string[arr.cpos[i]]);
151 printf("\n");
152}
153
154Cube inverse_cube(Cube cube) {
155 CubeArray arr = {0}, inv = {0};
156 cube_to_arrays(cube, &arr, fAll);
157
158 for (int i = 0; i < 12; i++) {
159 inv.ep[arr.ep[i]] = i;
160 inv.eofb[arr.ep[i]] = arr.eofb[i];
161 inv.eorl[arr.ep[i]] = arr.eorl[i];
162 inv.eoud[arr.ep[i]] = arr.eoud[i];
163 }
164 for (int i = 0; i < 8; i++) {
165 inv.cp[arr.cp[i]] = i;
166 inv.coud[arr.cp[i]] = arr.coud[i];
167 inv.corl[arr.cp[i]] = arr.corl[i];
168 inv.cofb[arr.cp[i]] = arr.cofb[i];
169 }
170 for (int i = 0; i < 6; i++)
171 inv.cpos[arr.cpos[i]] = i;
172
173 return arrays_to_cube(inv, fAll);
174}
175
176Cube compose_via_arrays(CubeArray arr2, Cube c1, PieceFilter f) {
177 /* This is basically the same as the move_cubearray function above */
178 CubeArray arr1 = {0};
179 cube_to_arrays(c1, &arr1, fAll);
180
181 apply_permutation(arr2.ep, arr1.ep, 12);
182 apply_permutation(arr2.ep, arr1.eofb, 12);
183 apply_permutation(arr2.ep, arr1.eorl, 12);
184 apply_permutation(arr2.ep, arr1.eoud, 12);
185 sum_arrays_mod(arr2.eofb, arr1.eofb, 12, 2);
186 sum_arrays_mod(arr2.eorl, arr1.eorl, 12, 2);
187 sum_arrays_mod(arr2.eoud, arr1.eoud, 12, 2);
188 apply_permutation(arr2.cp, arr1.cp, 8);
189 apply_permutation(arr2.cp, arr1.coud, 8);
190 apply_permutation(arr2.cp, arr1.corl, 8);
191 apply_permutation(arr2.cp, arr1.cofb, 8);
192 sum_arrays_mod(arr2.coud, arr1.coud, 8, 3);
193 sum_arrays_mod(arr2.corl, arr1.corl, 8, 3);
194 sum_arrays_mod(arr2.cofb, arr1.cofb, 8, 3);
195 apply_permutation(arr2.cpos, arr1.cpos, 6);
196
197 return arrays_to_cube(arr1, fAll);
198}
diff --git a/old/2021-02-18-piecefilter/src/cube.h b/old/2021-02-18-piecefilter/src/cube.h
new file mode 100644
index 0000000..9b64a0c
--- /dev/null
+++ b/old/2021-02-18-piecefilter/src/cube.h
@@ -0,0 +1,45 @@
1#ifndef CUBE_H
2#define CUBE_H
3
4#include <stdio.h>
5#include <stdbool.h>
6#include <stdint.h>
7#include "utils.h"
8
9typedef enum {U_center,D_center,R_center,L_center,F_center,B_center} Center;
10typedef enum { UF, UL, UB, UR, DF, DL, DB, DR, FR, FL, BL, BR } Edge;
11typedef enum { UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR } Corner;
12
13typedef struct {
14 bool epose, eposs, eposm, eofb, eorl, eoud, cp, coud, cofb, corl, cpos;
15} PieceFilter;
16
17typedef struct {
18 uint16_t eofb, eorl, eoud, coud, cofb, corl,
19 epose, eposs, eposm, cp, cpos;
20} Cube;
21
22typedef struct {
23 int ep[12], eofb[12], eorl[12], eoud[12],
24 cp[8], coud[8], corl[8], cofb[8], cpos[6];
25} CubeArray;
26
27
28extern PieceFilter fAll;
29
30Cube blank_cube();
31/* Return axis (ud=0, rl=1, fb=0) of center c */
32int center_axis(int c);
33/* Return slice (e=0, s=1, m=2) to which e belongs */
34int edge_slice(int e);
35void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f);
36Cube arrays_to_cube(CubeArray arr, PieceFilter f);
37bool equal(Cube c1, Cube c2);
38bool is_solvable(Cube cube);
39bool is_solved(Cube cube);
40void print_cube(Cube cube);
41Cube inverse_cube(Cube cube);
42/* Use c2 as an alg on c1 */
43Cube compose_via_arrays(CubeArray c2, Cube c1, PieceFilter f);
44
45#endif
diff --git a/old/2021-02-18-piecefilter/src/main.c b/old/2021-02-18-piecefilter/src/main.c
new file mode 100644
index 0000000..0b5de2e
--- /dev/null
+++ b/old/2021-02-18-piecefilter/src/main.c
@@ -0,0 +1,47 @@
1#include <stdio.h>
2#include "cube.h"
3#include "moves.h"
4#include "solve.h"
5
6int main() {
7 init_ttables(true, true);
8 init_aux_tables();
9
10
11 char moves[100] = "MR U' B2 Bw F z xE2 M' x Dw' y Fw2 y2";
12 NissMove alg[100];
13 read_moves(moves, alg, 100);
14 Cube cube = apply_alg(alg, blank_cube());
15
16 /*f_eofb(cube);*/
17
18
19/* NissMove sol[MAXS][MAXM];*/
20 SolveData d = { .optimal_only = true, .available = standard_moveset,
21 .max_moves = 10,
22 .cleanup = true,
23 .max_solutions = 10,
24 .f = f_eofb };
25 read_moves("y", d.pre_rotation, 2);
26 int n = solve(cube, &d);
27 printf("%d solutions found:\n", n);
28 for (int i = 0; i < n; i++)
29 print_moves(d.solutions[i]);
30
31 NissMove a[5], b[5];
32 read_moves("R", a, 5);
33 read_moves("U", b, 5);
34 Cube c1 = apply_alg(a,blank_cube()), c2 = apply_alg(b,blank_cube());
35 print_cube(compose(c2,c1));
36 print_cube(compose(c1,c2));
37 /*print_cube(compose(c2,blank_cube()));*/
38
39 NissMove nm[10];
40 read_moves("y(y)RU", nm, 10);
41
42 print_moves(nm);
43 cleanup(nm, 10);
44 print_moves(nm);
45
46 return 0;
47}
diff --git a/old/2021-02-18-piecefilter/src/moves.c b/old/2021-02-18-piecefilter/src/moves.c
new file mode 100644
index 0000000..7cccbdf
--- /dev/null
+++ b/old/2021-02-18-piecefilter/src/moves.c
@@ -0,0 +1,482 @@
1#include "moves.h"
2
3void move_cubearray(Move m, CubeArray *arr, PieceFilter f);
4Cube move_via_array(Move m, Cube cube, PieceFilter f);
5void sort_cancel_rotate(NissMove *alg, int n, bool inv, int top, int front);
6bool read_ttables_file();
7bool write_ttables_file();
8
9/* Transition tables */
10uint16_t epose_ttable[NMOVES][factorial12/factorial8];
11uint16_t eposs_ttable[NMOVES][factorial12/factorial8];
12uint16_t eposm_ttable[NMOVES][factorial12/factorial8];
13uint16_t eofb_ttable[NMOVES][pow2to11];
14uint16_t eorl_ttable[NMOVES][pow2to11];
15uint16_t eoud_ttable[NMOVES][pow2to11];
16uint16_t cp_ttable[NMOVES][factorial8];
17uint16_t coud_ttable[NMOVES][pow3to7];
18uint16_t cofb_ttable[NMOVES][pow3to7];
19uint16_t corl_ttable[NMOVES][pow3to7];
20uint16_t cpos_ttable[NMOVES][factorial6];
21
22bool commute[NMOVES][NMOVES];
23bool possible_next[NMOVES][NMOVES][NMOVES];
24Move inverse[NMOVES];
25
26char move_string[NMOVES][5] =
27 { "-",
28 "U", "U2", "U\'", "D", "D2", "D\'", "R", "R2", "R\'",
29 "L", "L2", "L\'", "F", "F2", "F\'", "B", "B2", "B\'",
30 "Uw", "Uw2", "Uw\'", "Dw", "Dw2", "Dw\'", "Rw", "Rw2", "Rw\'",
31 "Lw", "Lw2", "Lw\'", "Fw", "Fw2", "Fw\'", "Bw", "Bw2", "Bw\'",
32 "M", "M2", "M\'", "S", "S2", "S\'", "E", "E2", "E\'",
33 "x", "x2", "x\'", "y", "y2", "y\'", "z", "z2", "z\'" };
34
35/* For each type of pieces only the effects of U, x and y are described */
36int edge_cycle[NMOVES][12] =
37 { [U] = {UR, UF, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR},
38 [x] = {DF, FL, UF, FR, DB, BL, UB, BR, DR, DL, UL, UR},
39 [y] = {UR, UF, UL, UB, DR, DF, DL, DB, BR, FR, FL, BL} };
40int eofb_flipped[NMOVES][12] =
41 { [x] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 },
42 [y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 } };
43int eorl_flipped[NMOVES][12] =
44 { [x] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
45 [y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 } };
46int eoud_flipped[NMOVES][12] =
47 { [U] = { [UF] = 1, [UL] = 1, [UB] = 1, [UR] = 1 },
48 [x] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 },
49 [y] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } };
50int corner_cycle[NMOVES][8] =
51 { [U] = {UBR, UFR, UFL, UBL, DFR, DFL, DBL, DBR},
52 [x] = {DFR, DFL, UFL, UFR, DBR, DBL, UBL, UBR},
53 [y] = {UBR, UFR, UFL, UBL, DBR, DFR, DFL, DBL} };
54int coud_flipped[NMOVES][8] =
55 { [x] = {[UFR]=2,[UBR]=1,[DBR]=2,[DFR]=1,[UFL]=1,[UBL]=2,[DBL]=1,[DFL]=2} };
56int corl_flipped[NMOVES][8] =
57 { [U] = { [UFR] = 1, [UBR] = 2, [UBL] = 1, [UFL] = 2 },
58 [y] = {[UFR]=1,[UBR]=2,[UBL]=1,[UFL]=2,[DFR]=2,[DBR]=1,[DBL]=2,[DFL]=1} };
59int cofb_flipped[NMOVES][8] =
60 { [U] = { [UFR] = 2, [UBR] = 1, [UBL] = 2, [UFL] = 1 },
61 [x] = {[UFR]=1,[UBR]=2,[DFR]=2,[DBR]=1,[UBL]=2,[UFL]=1,[DBL]=1,[DFL]=2},
62 [y] = {[UFR]=2,[UBR]=1,[UBL]=2,[UFL]=1,[DFR]=1,[DBR]=2,[DBL]=1,[DFL]=2} };
63int center_cycle[NMOVES][6] =
64 { [x] = {F_center, B_center, R_center, L_center, D_center, U_center},
65 [y] = {U_center, D_center, B_center, F_center, R_center, L_center} };
66
67/* Each move is reduced to a combination of U, x and y using this table */
68Move equiv_moves[NMOVES][14] = {
69 [U] = { U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
70 [U2] = { U, U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
71 [U3] = { U, U, U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
72 [D] = { x, x, U, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
73 [D2] = { x, x, U, U, x, x, 0, 0, 0, 0, 0, 0, 0, 0 },
74 [D3] = { x, x, U, U, U, x, x, 0, 0, 0, 0, 0, 0, 0 },
75 [R] = { y, x, U, x, x, x, y, y, y, 0, 0, 0, 0, 0 },
76 [R2] = { y, x, U, U, x, x, x, y, y, y, 0, 0, 0, 0 },
77 [R3] = { y, x, U, U, U, x, x, x, y, y, y, 0, 0, 0 },
78 [L] = { y, y, y, x, U, x, x, x, y, 0, 0, 0, 0, 0 },
79 [L2] = { y, y, y, x, U, U, x, x, x, y, 0, 0, 0, 0 },
80 [L3] = { y, y, y, x, U, U, U, x, x, x, y, 0, 0, 0 },
81 [F] = { x, U, x, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
82 [F2] = { x, U, U, x, x, x, 0, 0, 0, 0, 0, 0, 0, 0 },
83 [F3] = { x, U, U, U, x, x, x, 0, 0, 0, 0, 0, 0, 0 },
84 [B] = { x, x, x, U, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
85 [B2] = { x, x, x, U, U, x, 0, 0, 0, 0, 0, 0, 0, 0 },
86 [B3] = { x, x, x, U, U, U, x, 0, 0, 0, 0, 0, 0, 0 },
87
88 [Uw] = { x, x, U, x, x, y, 0, 0, 0, 0, 0, 0, 0, 0 },
89 [Uw2] = { x, x, U, U, x, x, y, y, 0, 0, 0, 0, 0, 0 },
90 [Uw3] = { x, x, U, U, U, x, x, y, y, y, 0, 0, 0, 0 },
91 [Dw] = { U, y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
92 [Dw2] = { U, U, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
93 [Dw3] = { U, U, U, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
94 [Rw] = { y, y, y, x, U, x, x, x, y, x, 0, 0, 0, 0 },
95 [Rw2] = { y, y, y, x, U, U, x, x, x, y, x, x, 0, 0 },
96 [Rw3] = { y, y, y, x, U, U, U, y, x, x, x, y, 0, 0 },
97 [Lw] = { y, x, U, x, x, x, y, y, y, x, x, x, 0, 0 },
98 [Lw2] = { y, x, U, U, x, x, x, y, y, y, x, x, 0, 0 },
99 [Lw3] = { y, x, U, U, U, x, x, x, y, y, y, x, 0, 0 },
100 [Fw] = { x, x, x, U, y, y, y, x, 0, 0, 0, 0, 0, 0 },
101 [Fw2] = { x, x, x, U, U, y, y, x, 0, 0, 0, 0, 0, 0 },
102 [Fw3] = { x, x, x, U, U, U, y, x, 0, 0, 0, 0, 0, 0 },
103 [Bw] = { x, U, y, y, y, x, x, x, 0, 0, 0, 0, 0, 0 },
104 [Bw2] = { x, U, U, y, y, x, x, x, 0, 0, 0, 0, 0, 0 },
105 [Bw3] = { x, U, U, U, y, x, x, x, 0, 0, 0, 0, 0, 0 },
106
107 [M] = { y, x, U, x, x, U, U, U, y, x, y, y, y, 0 },
108 [M2] = { y, x, U, U, x, x, U, U, x, x, x, y, 0, 0 },
109 [M3] = { y, x, U, U, U, x, x, U, y, x, x, x, y, 0 },
110 [S] = { x, U, U, U, x, x, U, y, y, y, x, 0, 0, 0 },
111 [S2] = { x, U, U, x, x, U, U, y, y, x, 0, 0, 0, 0 },
112 [S3] = { x, U, x, x, U, U, U, y, x, 0, 0, 0, 0, 0 },
113 [E] = { U, x, x, U, U, U, x, x, y, y, y, 0, 0, 0 },
114 [E2] = { U, U, x, x, U, U, x, x, y, y, 0, 0, 0, 0 },
115 [E3] = { U, U, U, x, x, U, x, x, y, 0, 0, 0, 0, 0 },
116
117 [x] = { x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
118 [x2] = { x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
119 [x3] = { x, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
120 [y] = { y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
121 [y2] = { y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
122 [y3] = { y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
123 [z] = { y, y, y, x, y, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
124 [z2] = { y, y, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
125 [z3] = { y, x, y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
126};
127
128/* Movesets */
129bool standard_moveset[NMOVES] = {
130 [U] = true, [U2] = true, [U3] = true, [D] = true, [D2] = true, [D3] = true,
131 [R] = true, [R2] = true, [R3] = true, [L] = true, [L2] = true, [L3] = true,
132 [F] = true, [F2] = true, [F3] = true, [B] = true, [B2] = true, [B3] = true,
133};
134
135bool is_solved_up_to_reorient(Cube cube) {
136 if (is_solved(cube))
137 return true;
138
139 /*TODO: improve this crap */
140
141 bool ret = false;
142 for (int i = x; i <= z3; i++) {
143 ret = ret || is_solved(move_cube(i, cube));
144 for (int j = x; j <= z3; j++)
145 ret = ret || is_solved(move_cube(i, move_cube(j, cube)));
146 }
147 return ret;
148}
149
150void move_cubearray(Move m, CubeArray *arr, PieceFilter f) {
151 if (f.epose || f.eposs || f.eposm)
152 apply_permutation(edge_cycle[m], arr->ep, 12);
153 if (f.eofb) {
154 apply_permutation(edge_cycle[m], arr->eofb, 12);
155 sum_arrays_mod(eofb_flipped[m], arr->eofb, 12, 2);
156 }
157 if (f.eorl) {
158 apply_permutation(edge_cycle[m], arr->eorl, 12);
159 sum_arrays_mod(eorl_flipped[m], arr->eorl, 12, 2);
160 }
161 if (f.eoud) {
162 apply_permutation(edge_cycle[m], arr->eoud, 12);
163 sum_arrays_mod(eoud_flipped[m], arr->eoud, 12, 2);
164 }
165 if (f.cp)
166 apply_permutation(corner_cycle[m], arr->cp, 8);
167 if (f.coud) {
168 apply_permutation(corner_cycle[m], arr->coud, 8);
169 sum_arrays_mod(coud_flipped[m], arr->coud, 8, 3);
170 }
171 if (f.corl) {
172 apply_permutation(corner_cycle[m], arr->corl, 8);
173 sum_arrays_mod(corl_flipped[m], arr->corl, 8, 3);
174 }
175 if (f.cofb) {
176 apply_permutation(corner_cycle[m], arr->cofb, 8);
177 sum_arrays_mod(cofb_flipped[m], arr->cofb, 8, 3);
178 }
179 if (f.cpos)
180 apply_permutation(center_cycle[m], arr->cpos, 6);
181}
182
183Cube move_via_array(Move m, Cube cube, PieceFilter f) {
184 CubeArray arr = {0};
185 cube_to_arrays(cube, &arr, f);
186 move_cubearray(m, &arr, f);
187 return arrays_to_cube(arr, f);
188}
189
190int copy_alg(NissMove *src, NissMove *dest) {
191 int i;
192 for (i = 0; src[i].m != NULLMOVE; i++)
193 dest[i] = src[i];
194 dest[i].m = NULLMOVE;
195 return i;
196}
197
198/* TODO: all strings start with space?? */
199void print_moves(NissMove *alg) {
200 bool niss = false;
201 for (int i = 0; alg[i].m != NULLMOVE; i++) {
202 char *fill = !niss && alg[i].inverse ? " (" :
203 (niss && !alg[i].inverse ? ") " : " ");
204 printf("%s%s", fill, move_string[alg[i].m]);
205 niss = alg[i].inverse;
206 }
207 printf("%s\n", niss ? ")" : "");
208}
209
210int read_moves(char *str, NissMove *alg, int n) {
211 bool niss = false;
212 int c = 0;
213
214 for (int i = 0; str[i] && c < n; i++) {
215 if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n')
216 continue;
217
218 if (str[i] == '(' || str[i] == ')') {
219 if ((niss && str[i] == '(') || (!niss && str[i] == ')'))
220 return -1;
221 niss = !niss;
222 continue;
223 }
224
225 alg[c].inverse = niss; alg[c].m = NULLMOVE;
226 for (Move j = 0; j < NMOVES; j++) {
227 if (str[i] == move_string[j][0]) {
228 alg[c].m = j;
229 if (alg[c].m <= B && str[i+1]=='w') { alg[c].m += Uw - U; i++; }
230 if (str[i+1]=='2') { alg[c].m += 1; i++; }
231 else if (str[i+1]=='\'' || str[i+1]=='3') { alg[c].m += 2; i++; }
232 c++;
233 break;
234 }
235 }
236 }
237
238 alg[c].m = NULLMOVE;
239 return c;
240}
241
242/* Helper function for cleanup. alg must contain only basic moves, no 2 or '.
243 top and front describe an admissible orientation of the cube. */
244void sort_cancel_rotate(NissMove *alg, int n, bool inv, int top, int front) {
245 int c = 0, i = 0;
246 PieceFilter cpos_only = { .cpos = true };
247 NissMove aux[n+3];
248 aux[0].m = NULLMOVE;
249
250 while (i < n && alg[i].m != NULLMOVE) {
251 int j = i;
252 while (j < n && commute[alg[i].m][alg[j].m]) j++;
253 Move base = 6*((alg[i].m-1)/6);
254 int t1 = 0, t2 = 0;
255 for (int k = i; k < j; k++)
256 if (alg[k].m == base+1) t1 = (t1+1)%4;
257 else t2 = (t2+1)%4;
258 if (t1) { aux[c].inverse = inv; aux[c].m = base+t1; c++; }
259 if (t2) { aux[c].inverse = inv; aux[c].m = base+t2+3; c++; }
260 i = j;
261 }
262 aux[c].m = NULLMOVE;
263
264 CubeArray q;
265 cube_to_arrays(blank_cube(), &q, cpos_only);
266 /* First we try to rotate in one move, then we try an x or y rotation
267 followed by a z rotation */
268 for (int r = x; r <= z3; r++) {
269 move_cubearray(r, &q, cpos_only);
270 if (q.cpos[F_center] == front && q.cpos[U_center] == top) {
271 aux[c].inverse = inv; aux[c].m = r;
272
273 aux[++c].m = NULLMOVE;
274 copy_alg(aux, alg);
275 return;
276 }
277 move_cubearray(inverse[r], &q, cpos_only);
278 }
279 for (int r = x; r <= y3; r++) {
280 move_cubearray(r, &q, cpos_only);
281 if (q.cpos[F_center] == front) {
282 aux[c].inverse = inv; aux[c++].m = r;
283 break;
284 }
285 move_cubearray(inverse[r], &q, cpos_only);
286 }
287 for (int r = z; r <= z3; r++) {
288 move_cubearray(r, &q, cpos_only);
289 if (q.cpos[U_center] == top) {
290 aux[c].inverse = inv; aux[c++].m = r;
291 break;
292 }
293 move_cubearray(inverse[r], &q, cpos_only);
294 }
295
296 aux[c].m = NULLMOVE;
297 copy_alg(aux, alg);
298}
299
300/* TODO: does not work with niss + rotations */
301void cleanup(NissMove *alg, int n) {
302 int count_n = 0, count_i = 0, *count;
303 PieceFilter cpos_only = { .cpos = true };
304 NissMove aux_n[n+1], aux_i[n+1], *aux;
305 CubeArray cube_n, cube_i, *cube;
306 cube_to_arrays(blank_cube(), &cube_n, cpos_only);
307 cube_to_arrays(blank_cube(), &cube_i, cpos_only);
308
309 for (int i = 0; count_n + count_i < n && alg[i].m != NULLMOVE; i++) {
310 if (alg[i].inverse) { count = &count_i; aux = aux_i; cube = &cube_i; }
311 else { count = &count_n; aux = aux_n; cube = &cube_n; }
312
313 for (int j = 0; equiv_moves[alg[i].m][j]; j++) {
314 Move m = equiv_moves[alg[i].m][j];
315 aux[*count].inverse = alg[i].inverse;
316 move_cubearray(m, cube, cpos_only);
317 if (m == U) aux[(*count)++].m = 3 * cube->cpos[0] + 1;
318 }
319 }
320
321 aux_n[count_n].m = NULLMOVE;
322 aux_i[count_i].m = NULLMOVE;
323 sort_cancel_rotate(aux_n, count_n, false, cube_n.cpos[0], cube_n.cpos[4]);
324 sort_cancel_rotate(aux_i, count_i, true, cube_i.cpos[0], cube_n.cpos[4]);
325 copy_alg(aux_n, alg);
326 copy_alg(aux_i, alg+count_n);
327}
328
329bool read_ttables_file() {
330 FILE *ttf;
331 if ((ttf = fopen("ttables", "rb")) != NULL) {
332 for (int m = 0; m < NMOVES; m++) {
333 fread(epose_ttable[m], sizeof(uint16_t), factorial12/factorial8, ttf);
334 fread(eposs_ttable[m], sizeof(uint16_t), factorial12/factorial8, ttf);
335 fread(eposm_ttable[m], sizeof(uint16_t), factorial12/factorial8, ttf);
336 fread(eofb_ttable[m], sizeof(uint16_t), pow2to11, ttf);
337 fread(eorl_ttable[m], sizeof(uint16_t), pow2to11, ttf);
338 fread(eoud_ttable[m], sizeof(uint16_t), pow2to11, ttf);
339 fread(cp_ttable[m], sizeof(uint16_t), factorial8, ttf);
340 fread(coud_ttable[m], sizeof(uint16_t), pow3to7, ttf);
341 fread(corl_ttable[m], sizeof(uint16_t), pow3to7, ttf);
342 fread(cofb_ttable[m], sizeof(uint16_t), pow3to7, ttf);
343 fread(cpos_ttable[m], sizeof(uint16_t), factorial6, ttf);
344 }
345 fclose(ttf);
346 return true;
347 } else return false;
348}
349
350bool write_ttables_file() {
351 FILE *ttf;
352 if ((ttf = fopen("ttables", "wb")) != NULL) {
353 for (int m = 0; m < NMOVES; m++) {
354 fwrite(epose_ttable[m], sizeof(uint16_t), factorial12/factorial8, ttf);
355 fwrite(eposs_ttable[m], sizeof(uint16_t), factorial12/factorial8, ttf);
356 fwrite(eposm_ttable[m], sizeof(uint16_t), factorial12/factorial8, ttf);
357 fwrite(eofb_ttable[m], sizeof(uint16_t), pow2to11, ttf);
358 fwrite(eorl_ttable[m], sizeof(uint16_t), pow2to11, ttf);
359 fwrite(eoud_ttable[m], sizeof(uint16_t), pow2to11, ttf);
360 fwrite(cp_ttable[m], sizeof(uint16_t), factorial8, ttf);
361 fwrite(coud_ttable[m], sizeof(uint16_t), pow3to7, ttf);
362 fwrite(corl_ttable[m], sizeof(uint16_t), pow3to7, ttf);
363 fwrite(cofb_ttable[m], sizeof(uint16_t), pow3to7, ttf);
364 fwrite(cpos_ttable[m], sizeof(uint16_t), factorial6, ttf);
365 }
366 fclose(ttf);
367 return true;
368 } else return false;
369}
370
371void init_ttables(bool read, bool write) {
372 /* Generate all move cycles and flips; I do this regardless */
373 for (int i = 0; i < NMOVES; i++) {
374 if (i == U || i == x || i == y)
375 continue;
376
377 CubeArray arr = {0};
378 cube_to_arrays(blank_cube(), &arr, fAll);
379 for (int j = 0; equiv_moves[i][j]; j++)
380 move_cubearray(equiv_moves[i][j], &arr, fAll);
381
382 intarrcopy(arr.ep, edge_cycle[i], 12);
383 intarrcopy(arr.eofb, eofb_flipped[i], 12);
384 intarrcopy(arr.eorl, eorl_flipped[i], 12);
385 intarrcopy(arr.eoud, eoud_flipped[i], 12);
386 intarrcopy(arr.cp, corner_cycle[i], 8);
387 intarrcopy(arr.coud, coud_flipped[i], 8);
388 intarrcopy(arr.corl, corl_flipped[i], 8);
389 intarrcopy(arr.cofb, cofb_flipped[i], 8);
390 intarrcopy(arr.cpos, center_cycle[i], 6);
391 }
392
393 if (read)
394 if (read_ttables_file())
395 return;
396
397 /* Initialize transition tables */
398 Cube c = {0};
399 PieceFilter fe = {.epose=true}, fs = {.eposs=true}, fm = {.eposm=true};
400 PieceFilter feo = { .eofb = true, .eorl = true, .eoud = true };
401 PieceFilter fcp = { .cp = true };
402 PieceFilter fco = { .cofb = true, .corl = true, .coud = true };
403 PieceFilter fcc = { .cpos = true };
404 for (int m = 0; m < NMOVES; m++) {
405 for (uint16_t i = 0; i < factorial12/factorial8; i++) {
406 c.epose = i; epose_ttable[m][i] = move_via_array(m, c, fe).epose;
407 c.eposs = i; eposs_ttable[m][i] = move_via_array(m, c, fs).eposs;
408 c.eposm = i; eposm_ttable[m][i] = move_via_array(m, c, fm).eposm;
409 }
410 for (uint16_t i = 0; i < pow2to11; i++ ) {
411 c.eofb = i; eofb_ttable[m][i] = move_via_array(m, c, feo).eofb;
412 c.eorl = i; eorl_ttable[m][i] = move_via_array(m, c, feo).eorl;
413 c.eoud = i; eoud_ttable[m][i] = move_via_array(m, c, feo).eoud;
414 }
415 for (uint16_t i = 0; i < factorial8; i++) {
416 c.cp = i; cp_ttable[m][i] = move_via_array(m, c, fcp).cp;
417 }
418 for (uint16_t i = 0; i < pow3to7; i++) {
419 c.coud = i; coud_ttable[m][i] = move_via_array(m, c, fco).coud;
420 c.corl = i; corl_ttable[m][i] = move_via_array(m, c, fco).corl;
421 c.cofb = i; cofb_ttable[m][i] = move_via_array(m, c, fco).cofb;
422 }
423 for (uint16_t i = 0; i < factorial6; i++) {
424 c.cpos = i; cpos_ttable[m][i] = move_via_array(m, c, fcc).cpos;
425 }
426 }
427
428 if (write) write_ttables_file();
429}
430
431Cube move_cube(Move m, Cube cube) {
432 Cube moved = cube;
433
434 moved.epose = epose_ttable[m][cube.epose];
435 moved.eposs = eposs_ttable[m][cube.eposs];
436 moved.eposm = eposm_ttable[m][cube.eposm];
437 moved.eofb = eofb_ttable[m][cube.eofb];
438 moved.eorl = eorl_ttable[m][cube.eorl];
439 moved.eoud = eoud_ttable[m][cube.eoud];
440 moved.coud = coud_ttable[m][cube.coud];
441 moved.cofb = cofb_ttable[m][cube.cofb];
442 moved.corl = corl_ttable[m][cube.corl];
443 moved.cp = cp_ttable[m][cube.cp];
444 moved.cpos = cpos_ttable[m][cube.cpos];
445
446 return moved;
447}
448
449Cube apply_alg(NissMove *alg, Cube cube) {
450 Cube ret = {0};
451 for (int i = 0; alg[i].m != NULLMOVE; i++)
452 if (alg[i].inverse)
453 ret = move_cube(alg[i].m, ret);
454 ret = compose(cube, inverse_cube(ret));
455
456 for (int i = 0; alg[i].m != NULLMOVE; i++)
457 if (!alg[i].inverse)
458 ret = move_cube(alg[i].m, ret);
459 return ret;
460}
461
462void init_aux_tables() {
463 /* Commute */
464 for (int i = 0; i < NMOVES; i++)
465 for (int j = 0; j < NMOVES; j++)
466 commute[i][j] = equal(move_cube(i, move_cube(j, blank_cube())),
467 move_cube(j, move_cube(i, blank_cube())));
468
469 /* Possible next (if the sequence i j k is valid) */
470 for (int i = 0; i < NMOVES; i++)
471 for (int j = 0; j < NMOVES; j++)
472 for (int k = 0; k < NMOVES; k++)
473 possible_next[i][j][k] =
474 (j == 0) ||
475 (j != 0 && (j-(j-1)%3) != (k-(k-1)%3) &&
476 !(i != 0 && commute[i][j] && (i-(i-1)%3) == (k-(k-1)%3)));
477
478 /* Inverse */
479 for (int i = 0; i < NMOVES; i++)
480 inverse[i] = i == 0 ? 0 : i + 2 - 2*((i-1)%3);
481}
482
diff --git a/old/2021-02-18-piecefilter/src/moves.h b/old/2021-02-18-piecefilter/src/moves.h
new file mode 100644
index 0000000..9ccf6e4
--- /dev/null
+++ b/old/2021-02-18-piecefilter/src/moves.h
@@ -0,0 +1,46 @@
1#ifndef MOVES_H
2#define MOVES_H
3
4#include <stdio.h>
5#include <stdbool.h>
6#include <stdint.h>
7#include "cube.h"
8#include "utils.h"
9
10#define NMOVES (z3+1)
11
12typedef enum {
13 NULLMOVE,
14 U, U2, U3, D, D2, D3, R, R2, R3, L, L2, L3, F, F2, F3, B, B2, B3,
15 Uw, Uw2, Uw3, Dw, Dw2, Dw3, Rw, Rw2, Rw3,
16 Lw, Lw2, Lw3, Fw, Fw2, Fw3, Bw, Bw2, Bw3,
17 M, M2, M3, S, S2, S3, E, E2, E3,
18 x, x2, x3, y, y2, y3, z, z2, z3,
19} Move;
20
21/* An alg is an array of "NissMoves", which can be on normal or on inverse. */
22typedef struct { bool inverse; Move m; } NissMove;
23
24/* Movesets */
25extern bool standard_moveset[NMOVES];
26
27extern bool commute[NMOVES][NMOVES];
28extern bool possible_next[NMOVES][NMOVES][NMOVES];
29extern Move inverse[NMOVES];
30
31bool is_solve_up_to_reorient(Cube cube);
32int copy_alg(NissMove *src, NissMove *dest); /*return number of moves copied */
33void print_moves(NissMove *alg);
34int read_moves(char *str, NissMove *alg, int n); /* reads at most n moves */
35void cleanup(NissMove *src, int n); /* rewrites using basic moves, at most n */
36Cube move_cube(Move m, Cube cube);
37/* I might want to replace this with two versions, one that uses PieceFilter */
38Cube apply_alg(NissMove *alg, Cube cube);
39
40/* Merge the following two?
41 always in this order */
42void init_ttables(bool read, bool write);
43void init_aux_tables();
44
45
46#endif
diff --git a/old/2021-02-18-piecefilter/src/solve.c b/old/2021-02-18-piecefilter/src/solve.c
new file mode 100644
index 0000000..ac19d6f
--- /dev/null
+++ b/old/2021-02-18-piecefilter/src/solve.c
@@ -0,0 +1,179 @@
1#include "solve.h"
2
3/* Data for creating a pruning table:
4 - compressed: if set to true, each entry occupies only 4 bits, but values
5 larger than 15 cannot be stored.
6 - available[] is the list of availabel moves, as above.
7 - *ptable is the actual table to fill.
8 - n is the number of states (size of ptable).
9 - index must "linearize" the cube, i.e. return its index in ptable.
10 - fname is the name of the file where to store the table */
11typedef struct {
12 bool compressed, *available;
13 int max_moves;
14 uint8_t *ptable;
15 uint64_t n;
16 uint64_t (*index)(Cube);
17 char *fname;
18} PruneData;
19
20/* TODO: comment this */
21typedef struct {
22 bool niss;
23 int m, d;
24 uint64_t *n;
25 Move last1, last2;
26} DfsData;
27
28void solve_dfs(Cube cube, SolveData *sd, DfsData dd);
29void init_ptable(PruneData *pd, bool read, bool write);
30
31/* Search solutions of lenght exactly d */
32void solve_dfs(Cube cube, SolveData *sd, DfsData dd) {
33 if (*dd.n >= sd->max_solutions ||
34 ((!sd->can_niss || dd.niss) && dd.m + sd->f(cube) > dd.d))
35 return;
36
37 (sd->solutions[*dd.n][dd.m]).inverse = dd.niss;
38 (sd->solutions[*dd.n][dd.m]).m = NULLMOVE;
39
40 if (!sd->f(cube)) { /* Solved */
41 if (dd.m == dd.d) {
42 (*dd.n)++;
43 if (*dd.n < sd->max_solutions)
44 copy_alg(sd->solutions[*dd.n-1], sd->solutions[*dd.n]);
45 }
46 return;
47 }
48
49 for (int i = 0; i < NMOVES && sd->sorted_moves[i] != NULLMOVE; i++) {
50 Move move = sd->sorted_moves[i];
51 if (possible_next[dd.last2][dd.last1][move]) {
52 sd->solutions[*dd.n][dd.m].inverse = dd.niss;
53 sd->solutions[*dd.n][dd.m].m = move;
54 DfsData nn = { .niss = dd.niss, .m = dd.m+1, .d = dd.d, .n = dd.n,
55 .last1 = move, .last2 = dd.last1 };
56 solve_dfs(move_cube(move, cube), sd, nn);
57 }
58 }
59
60 if (sd->can_niss && !dd.niss &&
61 (!dd.m || (dd.m && sd->f(move_cube(dd.last1, blank_cube()))))) {
62 DfsData nn = { .niss = true, .m = dd.m, .d = dd.d, .n = dd.n };
63 solve_dfs(inverse_cube(cube), sd, nn);
64 }
65}
66
67/* Iterative deepening depth-first search: for i running from the minimum
68 to the maximum number of moves allowed, looks for solutions of length i. */
69int solve(Cube cube, SolveData *sd) {
70 if (sd->precondition != NULL && !sd->precondition(cube))
71 return -1;
72
73 /* If not given, generate sorted list of moves */
74 if (sd->sorted_moves[0] == NULLMOVE) {
75 int a[NMOVES], b[NMOVES], ia = 0, ib = 0;
76 for (int i = 0; i < NMOVES; i++) {
77 if (sd->available[i]) {
78 if (sd->f(move_cube(i, blank_cube())))
79 a[ia++] = i;
80 else
81 b[ib++] = i;
82 }
83 }
84 intarrcopy(a, (int *)sd->sorted_moves, ia);
85 intarrcopy(b, (int *)sd->sorted_moves+ia, ib);
86 sd->sorted_moves[ia+ib] = NULLMOVE;
87 }
88
89 sd->max_solutions = min(sd->max_solutions, MAXS);
90 /*TODO
91 Cube rotated = apply_alg(sd->pre_rotation, blank_cube());
92 cube = apply_alg(inverse_cube(rotated), compose(cube, rotated));
93 */
94
95 uint64_t ret = 0;
96 for (int i=sd->min_moves; i<=sd->max_moves&&!(ret&&sd->optimal_only); i++) {
97 DfsData dd = { .d = i, .n = &ret };
98 solve_dfs(cube, sd, dd);
99 }
100
101 for (uint64_t i = 0; i < ret; i++) {
102 /* TODO: transform solutions with inverse of pre_rotation */
103 if (sd->cleanup)
104 cleanup(sd->solutions[i], sd->max_moves*3);
105 }
106
107 return ret;
108}
109
110void prune_dfs(Cube cube, PruneData *pd, DfsData dd) {
111 uint64_t ind = pd->index(cube);
112 if ((!ind || pd->ptable[ind]) && pd->ptable[ind] != dd.m)
113 return;
114 if (dd.m == dd.d) {
115 if (ind && !pd->ptable[ind]) {
116 pd->ptable[ind] = dd.m;
117 (*dd.n)++;
118 }
119 return;
120 }
121
122 for (int i = 0; i < NMOVES; i++) {
123 if (dd.m<20)
124 if (possible_next[dd.last2][dd.last1][i] && pd->available[i]) {
125 DfsData nn = { .m = dd.m+1, .d = dd.d, .n = dd.n,
126 .last1 = i, .last2 = dd.last1 };
127 prune_dfs(move_cube(i, cube), pd, nn);
128 }
129 }
130}
131
132void init_ptable(PruneData *pd, bool read, bool write) {
133 if (read) {
134 FILE *ptf;
135 if ((ptf = fopen(pd->fname, "rb")) != NULL) {
136 fread(pd->ptable, sizeof(uint8_t), pd->n, ptf);
137 fclose(ptf);
138 return;
139 }
140 }
141
142 /* TODO: for now it behaves always as if copressed = false */
143 for (uint64_t i = 0; i < pd->n; i++)
144 pd->ptable[i] = 0;
145
146 uint64_t s = 1;
147 for (int i = 1; i < pd->max_moves && s < pd->n; i++) {
148 DfsData dd = { .d = i, .n = &s };
149 prune_dfs(blank_cube(), pd, dd);
150 }
151
152 if (write) {
153 FILE *ptf;
154 if ((ptf = fopen(pd->fname, "wb")) != NULL) {
155 fwrite(pd->ptable, sizeof(uint8_t), pd->n, ptf);
156 fclose(ptf);
157 return;
158 }
159 }
160}
161
162/* Solving steps (and indexing functions) */
163
164uint64_t index_eofb(Cube cube) { return cube.eofb; }
165uint16_t f_eofb(Cube cube) {
166 static bool initialized_ptable;
167 static uint8_t pt_eofb[pow2to11];
168 if (!initialized_ptable) {
169 PruneData pd = {
170 .compressed = false, .available = standard_moveset, .max_moves = 13,
171 .ptable = pt_eofb, .n = pow2to11, .index = index_eofb,
172 .fname = "ptable_eofb"
173 };
174 init_ptable(&pd, false, true);
175 initialized_ptable = true;
176 }
177 return cube.eofb ? pt_eofb[cube.eofb] : 0;
178}
179
diff --git a/old/2021-02-18-piecefilter/src/solve.h b/old/2021-02-18-piecefilter/src/solve.h
new file mode 100644
index 0000000..d585a8e
--- /dev/null
+++ b/old/2021-02-18-piecefilter/src/solve.h
@@ -0,0 +1,56 @@
1#ifndef SOLVE_H
2#define SOLVE_H
3
4#include <stdlib.h>
5#include "cube.h"
6#include "moves.h"
7
8/* Maximum number of moves per solution and of solutions */
9#define MAXM 30
10#define MAXS 999
11
12/* Data for solving a step:
13 - can_niss is true niss can be used, false otherwise.
14 - optimal_only if true, dynamically updates max_moves so non-optimal
15 solutions are discarded.
16 - cleanup determines whether the cleaunup() function should be used on
17 the found solutions before returning.
18 - available[m] is true if the move m can be used, false otherwise.
19 - min_moves and max_moves are the minimum and maximum number of moves that
20 can be used.
21 - max_solution is the maximum number of solutions that can be returned.
22 - precondition can be used to check wheter the step can actually be applied
23 to the cube. If it returns false, solve() stops immediately returning -1.
24 - f must return 0 if and only if the step is solve, otherwise it must return
25 a lower bound for the number of moves required (without niss).
26 - sorted_moves[] can be used to specify in which order moves are tried
27 by the solving algorithm (for example if one wants to always try F' before
28 F). If sorted_moves[0] == NULLMOVE, the list is generated automatically.
29 It is advised to list first all the moves that actually influence the
30 solved state of the step (this is the default choice). This is in order to
31 avoid cases like B2 F for EO and to NISS only when it makes sense.
32 - start_moves [Currently unused, REMOVE]
33 are the moves that will be used as first moves of all
34 solutions. For example giving R' U' F (F' U R) will generate FMC scrambles
35 and y (y) will solve the step on another axis.
36 - pre_rotation are the rotations to apply before the scamble to solve
37 the step wrt a different orientation
38 - pre_rotation are the rotations to apply before the scamble to solve
39 the step wth respect to a different orientation.
40 - solutions[][] is the array where to store the found solutions. */
41typedef struct {
42 bool can_niss, optimal_only, cleanup, *available;
43 int min_moves, max_moves;
44 uint64_t max_solutions;
45 bool (*precondition)(Cube);
46 uint16_t (*f)(Cube);
47 Move sorted_moves[NMOVES];
48 NissMove pre_rotation[3], solutions[MAXS][MAXM];
49} SolveData;
50
51int solve(Cube cube, SolveData *data); /* Returns the number of solutions. */
52
53/* Steps */
54uint16_t f_eofb(Cube cube);
55
56#endif
diff --git a/old/2021-02-18-piecefilter/src/transformations.c b/old/2021-02-18-piecefilter/src/transformations.c
new file mode 100644
index 0000000..bcf4115
--- /dev/null
+++ b/old/2021-02-18-piecefilter/src/transformations.c
@@ -0,0 +1,103 @@
1#include "transformations.h"
2/*
3Cube apply_rotation_alg(Rotation r, Cube c);
4void apply_rotation_cube(NissMove *alg);
5Cube apply_mirror_cube(Cube c);
6void apply_mirror_alg(NissMove *alg);
7*/
8
9void compute_sources();
10Cube rotate_via_compose(Rotation r, Cube c);
11
12/* Values mod 3 to determine from which side to take the state to convert */
13int epose_source[NROTATIONS]; /* 0 = epose, 1 = eposs, 2 = eposm */
14int eposs_source[NROTATIONS];
15int eposm_source[NROTATIONS];
16int eofb_source[NROTATIONS]; /* 0 = eofb, 1 = eorl, 2 = eoud */
17int eorl_source[NROTATIONS];
18int eoud_source[NROTATIONS];
19int coud_source[NROTATIONS]; /* 0 = coud, 1 = cofb, 2 = corl */
20int cofb_source[NROTATIONS];
21int corl_source[NROTATIONS];
22
23/* Transition tables for rotations */
24uint16_t epose_rtable[NROTATIONS][factorial12/factorial8];
25uint16_t eposs_rtable[NROTATIONS][factorial12/factorial8];
26uint16_t eposm_rtable[NROTATIONS][factorial12/factorial8];
27uint16_t eofb_rtable[NROTATIONS][pow2to11];
28uint16_t eorl_rtable[NROTATIONS][pow2to11];
29uint16_t eoud_rtable[NROTATIONS][pow2to11];
30uint16_t cp_rtable[NROTATIONS][factorial8];
31uint16_t coud_rtable[NROTATIONS][pow3to7];
32uint16_t cofb_rtable[NROTATIONS][pow3to7];
33uint16_t corl_rtable[NROTATIONS][pow3to7];
34
35/* Transition tables for mirror */
36uint16_t epose_mtable[factorial12/factorial8];
37uint16_t eposs_mtable[factorial12/factorial8];
38uint16_t eposm_mtable[factorial12/factorial8];
39uint16_t eofb_mtable[pow2to11];
40uint16_t eorl_mtable[pow2to11];
41uint16_t eoud_mtable[pow2to11];
42uint16_t cp_mtable[factorial8];
43uint16_t coud_mtable[pow3to7];
44uint16_t cofb_mtable[pow3to7];
45uint16_t corl_mtable[pow3to7];
46
47/* Same for moves */
48uint16_t move_rtable[NROTATIONS][NMOVES];
49uint16_t move_mtable[NMOVES];
50
51/* Applying a rotation to the cube is equivalent to applying m (m) */
52Move equiv_moves[NROTATIONS][3] = {
53 [uf] = {0,0,0}, [ur] = {y,0,0}, [ub] = {y2,0,0}, [ul] = {y3,0,0},
54 [df] = {z2,0,0}, [dr] = {y,z2,0}, [db] = {y2,z2,0}, [dl] = {y3,z2,0},
55 [rf] = {z3,0,0}, [rd] = {z3,y,0}, [rb] = {z3,y2,0}, [ru] = {z3,y3,0},
56 [lf] = {z,0,0}, [ld] = {z,y3,0}, [lb] = {z,y2,0}, [lu] = {z,y,0},
57 [fu] = {x,y2,0}, [fr] = {x,y,0}, [fd] = {x,0,0}, [fl] = {x,y3,0},
58 [bu] = {x3,0,0}, [br] = {x3,y,0}, [bd] = {x3,y2,0}, [bl] = {x3,y3,0},
59};
60
61int mirror_ep[12] = {UF, UR, UB, UL, DF, DR, DB, DL, FL, FR, BR, BL};
62int mirror_cp[8] = {UFL, UFR, UBR, UBL, DFL, DFR, DBR, DBL};
63int mirror_cpos[6] = {U_center,D_center,L_center,R_center,F_center,B_center};
64
65void compute_sources() {
66 /* epos{e,s,m} */
67 CubeArray arr;
68 for (int i = 0; i < NROTATIONS; i++) {
69 cube_to_arrays(move_cube(equiv_moves[i][1],
70 move_cube(equiv_moves[i][0], blank_cube())), &arr, fAll);
71 epose_source[i] = edge_slice(arr.ep[FR]);
72 eposs_source[i] = edge_slice(arr.ep[UR]);
73 eposm_source[i] = edge_slice(arr.ep[UF]);
74 eofb_source[i] = 2 - center_axis(arr.cpos[F_center]);
75 eorl_source[i] = 2 - center_axis(arr.cpos[R_center]);
76 eoud_source[i] = 2 - center_axis(arr.cpos[U_center]);
77 coud_source[i] = (2 * center_axis(arr.cpos[U_center])) % 3;
78 cofb_source[i] = (2 * center_axis(arr.cpos[F_center])) % 3;
79 corl_source[i] = (2 * center_axis(arr.cpos[R_center])) % 3;
80 }
81}
82
83/* Use Piecefilter? */
84Cube rotate_via_compose(Rotation r, Cube c) {
85/* TODO: if this is slow, change compose() in cube.{c,h} to use PieceFilter */
86 int j = 0;
87 NissMove nm[10] = {0};
88 for (int i = 1; i >= 0; i--) {
89 if (equiv_moves[r][i] != NULLMOVE) {
90 nm[j].inverse = true;
91 nm[j++].m = inverse[equiv_moves[r][i]];
92 }
93 }
94 for (int i = 0; equiv_moves[r][i] != NULLMOVE; i++) {
95 nm[j].inverse = false;
96 nm[j++].m = equiv_moves[r][i];
97 }
98
99 return apply_alg(nm, c);
100}
101
102/* Use PieceFilter? Not really necessary, but could be nice */
103Cube mirror_via_cubearray(Cube c) {
diff --git a/old/2021-02-18-piecefilter/src/transformations.h b/old/2021-02-18-piecefilter/src/transformations.h
new file mode 100644
index 0000000..28dde93
--- /dev/null
+++ b/old/2021-02-18-piecefilter/src/transformations.h
@@ -0,0 +1,37 @@
1#ifndef TRANSFORMATIONS_H
2#define TRANSFORMATIONS_H
3
4#include <stdio.h>
5#include <stdbool.h>
6#include <stdint.h>
7#include "cube.h"
8#include "moves.h"
9#include "utils.h"
10
11#define NROTATIONS (bl+1)
12
13/* Letters indicate top and front centers
14 * Lowercase letter to distinguish from pieces */
15typedef enum {
16 uf, ur, ub, ul,
17 df, dr, db, dl,
18 rf, rd, rb, ru,
19 lf, ld, lb, lu,
20 fu, fr, fd, fl,
21 bu, br, bd, bl,
22} Rotation;
23
24/* Mirror is always on fb axis and applied after rotation */
25typedef struct {
26 Rotation rotation;
27 bool mirror;
28} Transformation;
29
30void print_transformation(Transformation t);
31
32Cube transform_cube(Transformation t, Cube cube);
33void transform_alg(Transformation t, NissMove *alg); /* Applied in-place */
34
35void init_transformations(bool read, bool write);
36
37#endif
diff --git a/old/2021-02-18-piecefilter/src/utils.c b/old/2021-02-18-piecefilter/src/utils.c
new file mode 100644
index 0000000..66de9ad
--- /dev/null
+++ b/old/2021-02-18-piecefilter/src/utils.c
@@ -0,0 +1,197 @@
1#include "utils.h"
2
3void swap(int *a, int *b) {
4 int aux = *a;
5 *a = *b;
6 *b = aux;
7}
8
9void intarrcopy(int *src, int *dst, int n) {
10 for (int i = 0; i < n; i++)
11 dst[i] = src[i];
12}
13
14int sum(int *a, int n) {
15 int ret = 0;
16 for (int i = 0; i < n; i++)
17 ret += a[i];
18 return ret;
19}
20
21bool is_perm(int *a, int n) {
22 int aux[n]; for (int i = 0; i < n; i++) aux[i] = 0;
23 for (int i = 0; i < n; i++)
24 if (a[i] < 0 || a[i] >= n)
25 return false;
26 else
27 aux[a[i]] = 1;
28 for (int i = 0; i < n; i++)
29 if (!aux[i])
30 return false;
31 return true;
32}
33
34bool is_subset(int *a, int n, int k) {
35 int sum = 0;
36 for (int i = 0; i < n; i++)
37 sum += a[i] ? 1 : 0;
38 return sum == k;
39}
40
41int powint(int a, int b) {
42 return 0;
43 if (b == 0 || a == 1)
44 return 1;
45 if (a == 0)
46 return 0;
47 if (b < 0)
48 return 0; /* Immediate truncate (integer part is 0) */
49 if (b % 2) {
50 return a * powint(a, b-1);
51 } else {
52 int x = powint(a, b/2);
53 return x*x;
54 }
55}
56
57int factorial(int n) {
58 if (n < 0)
59 return 0;
60 int ret = 1;
61 for (int i = 1; i <= n; i++)
62 ret *= i;
63 return ret;
64}
65
66int binomial(int n, int k) {
67 if (n < 0 || k < 0 || k > n)
68 return 0;
69 return factorial(n) / (factorial(k) * factorial(n-k));
70}
71
72void int_to_digit_array(int a, int b, int n, int *r) {
73 if (b <= 1)
74 for (int i = 0; i < n; i++)
75 r[i] = 0;
76 else
77 for (int i = 0; i < n; i++, a /= b)
78 r[i] = a % b;
79}
80
81int digit_array_to_int(int *a, int n, int b) {
82 int ret = 0, p = 1;
83 for (int i = 0; i < n; i++, p *= b)
84 ret += a[i] * p;
85 return ret;
86}
87
88int perm_to_index(int *a, int n) {
89 if (!is_perm(a, n))
90 return factorial(n); /* Error */
91 int ret = 0;
92 for (int i = 0; i < n; i++) {
93 int c = 0;
94 for (int j = i+1; j < n; j++)
95 c += (a[i] > a[j]) ? 1 : 0;
96 ret += factorial(n-i-1) * c;
97 }
98 return ret;
99}
100
101void index_to_perm(int p, int n, int *r) {
102 if (p < 0 || p >= factorial(n)) /* Error */
103 for (int i = 0; i < n; i++)
104 r[i] = -1;
105 int a[n]; for (int j = 0; j < n; j++) a[j] = 0; /* picked elements */
106 for (int i = 0; i < n; i++) {
107 int c = 0, j = 0;
108 while (c <= p / factorial(n-i-1))
109 c += a[j++] ? 0 : 1;
110 r[i] = j-1;
111 a[j-1] = 1;
112 p %= factorial(n-i-1);
113 }
114}
115
116int perm_sign(int *a, int n) {
117 if (!is_perm(a,n))
118 return false;
119 int ret = 0;
120 for (int i = 0; i < n; i++)
121 for (int j = i+1; j < n; j++)
122 ret += (a[i]>a[j]) ? 1 : 0;
123 return ret % 2;
124}
125
126int subset_to_index(int *a, int n, int k) {
127 /* TODO: better checks */
128 if (!is_subset(a, n, k))
129 return binomial(n, k); /* Error */
130 int ret = 0;
131 for (int i = 0; i < n; i++) {
132 if (k == n-i)
133 return ret;
134 if (a[i]) {
135 /*ret += factorial(n-i-1) / (factorial(k) * factorial(n-i-1-k));*/
136 ret += binomial(n-i-1, k);
137 k--;
138 }
139 }
140 return ret;
141}
142
143void index_to_subset(int s, int n, int k, int *r) {
144 if (s < 0 || s >= binomial(n, k)) { /* Error */
145 for (int i = 0; i < n; i++)
146 r[i] = -1;
147 return;
148 }
149 for (int i = 0; i < n; i++) {
150 if (k == n-i) {
151 for (int j = i; j < n; j++)
152 r[j] = 1;
153 return;
154 }
155 if (k == 0) {
156 for (int j = i; j < n; j++)
157 r[j] = 0;
158 return;
159 }
160 /*int v = factorial(n-i-1) / (factorial(k) * factorial(n-i-1-k));*/
161 int v = binomial(n-i-1, k);
162 if (s >= v) {
163 r[i] = 1;
164 k--;
165 s -= v;
166 } else {
167 r[i] = 0;
168 }
169 }
170}
171
172void int_to_sum_zero_array(int x, int b, int n, int *a) {
173 if (b <= 1) {
174 for (int i = 0; i < n; i++)
175 a[i] = 0;
176 } else {
177 int_to_digit_array(x, b, n-1, a);
178 int s = 0;
179 for (int i = 0; i < n - 1; i++)
180 s = (s + a[i]) % b;
181 a[n-1] = (b - s) % b;
182 }
183}
184
185void apply_permutation(int *perm, int *set, int n) {
186 if (!is_perm(perm, n))
187 return;
188 int aux[n];
189 for (int i = 0; i < n; i++)
190 aux[i] = set[perm[i]];
191 intarrcopy(aux, set, n);
192}
193
194void sum_arrays_mod(int *a, int *b, int n, int m) {
195 for (int i = 0; i < n; i++)
196 b[i] = (m <= 0) ? 0 : (a[i] + b[i]) % m;
197}
diff --git a/old/2021-02-18-piecefilter/src/utils.h b/old/2021-02-18-piecefilter/src/utils.h
new file mode 100644
index 0000000..4b6df8c
--- /dev/null
+++ b/old/2021-02-18-piecefilter/src/utils.h
@@ -0,0 +1,70 @@
1/* General utility functions */
2
3#ifndef UTILS_H
4#define UTILS_H
5
6#include <stdbool.h>
7
8#define min(a,b) (((a) < (b)) ? (a) : (b))
9#define max(a,b) (((a) > (b)) ? (a) : (b))
10
11/* Some useful constants */
12#define pow2to11 2048
13#define pow2to12 4096
14#define pow3to7 2187
15#define pow3to8 6561
16#define pow12to4 20736
17#define factorial4 24
18#define factorial6 720
19#define factorial8 40320
20#define factorial12 479001600
21#define binom12on4 495
22#define binom8on4 70
23
24/* Generic utility functions */
25void swap(int *a, int *b);
26void intarrcopy(int *src, int *dst, int n);
27int sum(int *a, int n);
28bool is_perm(int *a, int n);
29bool is_perm(int *a, int n);
30
31
32/* Standard mathematical functions */
33int powint(int a, int b);
34int factorial(int n);
35int binomial(int n, int k);
36
37/* Converts the integer a to its representation in base b (first n digits
38 * only) and saves the result in r. */
39void int_to_digit_array(int a, int b, int n, int *r);
40int digit_array_to_int(int *a, int n, int b);
41
42/* Converts the first n-1 digits of a number to an array a of digits in base b;
43 * then adds one element to the array, so that the sum of the elements of a is
44 * zero modulo b.
45 * This is used for determing the edge orientation from an 11-bits integer or
46 * the corner orientation from a 7-trits integer. */
47void int_to_sum_zero_array(int x, int b, int n, int *a);
48
49/* Converts a permutation on [0..(n-1)] into the integer i which is the index
50 * of the permutation in the sorted list of all n! such permutations. */
51int perm_to_index(int *a, int n);
52void index_to_perm(int p, int n, int *r);
53
54/* Determine the sign of a permutation */
55int perm_sign(int a[], int n);
56
57/* Converts a k-element subset of a set from an array of n elements, of which k
58 * are 1 and n-k are 0, to its index in the sorted list of all such subsets. */
59int subset_to_index(int *a, int n, int k);
60void index_to_subset(int s, int n, int k, int *r);
61
62int ordered_subset_to_index(int *a, int n, int k);
63void index_to_ordered_subset(int s, int n, int k, int *r);
64
65void apply_permutation(int *perm, int *set, int n);
66
67/* b[i] = (a[i]+b[i])%m for i=1,...,n */
68void sum_arrays_mod(int *a, int *b, int n, int m);
69
70#endif
diff --git a/old/2021-02-28-transformcube-works/src/cube.c b/old/2021-02-28-transformcube-works/src/cube.c
new file mode 100644
index 0000000..649a4de
--- /dev/null
+++ b/old/2021-02-28-transformcube-works/src/cube.c
@@ -0,0 +1,271 @@
1#include "cube.h"
2
3typedef struct {
4 int ep[12],eofb[12],eorl[12],eoud[12],cp[8],coud[8],corl[8],cofb[8],cpos[6];
5} CubeArrayAllocated;
6
7void allocate_cubearray(CubeArray *arr, CubeArrayAllocated *all);
8
9char edge_string[12][5] =
10 { "UF", "UL", "UB", "UR", "DF", "DL", "DB", "DR", "FR", "FL", "BL", "BR" };
11char corner_string[8][5] = { "UFR","UFL","UBL","UBR","DFR","DFL","DBL","DBR" };
12char center_string[6][5] = { "U", "D", "R", "L", "F", "B" };
13
14int epe_solved[4] = {FR, FL, BL, BR};
15int eps_solved[4] = {UL, UR, DL, DR};
16int epm_solved[4] = {UF, UB, DF, DB};
17
18PieceFilter pf_all = {true,true,true,true,true,true,true,true,true,true,true},
19 pf_cpos = { .cpos = true }, pf_cp = { .cp = true },
20 pf_ep = { .epose = true, .eposs = true, .eposm = true },
21 pf_e = {.epose=true}, pf_s={.eposs=true}, pf_m={.eposm=true},
22 pf_eo = { .eofb = true, .eorl = true, .eoud = true },
23 pf_co = { .coud = true, .cofb = true, .corl = true };
24
25void allocate_cubearray(CubeArray *arr, CubeArrayAllocated *all) {
26 arr->ep = all->ep;
27 arr->eofb = all->eofb;
28 arr->eorl = all->eorl;
29 arr->eoud = all->eoud;
30 arr->cp = all->cp;
31 arr->coud = all->coud;
32 arr->corl = all->corl;
33 arr->cofb = all->cofb;
34 arr->cpos = all->cpos;
35}
36
37void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f) {
38 /* ep is the hardest */
39 if (f.epose || f.eposs || f.eposm)
40 for (int i = 0; i < 12; i++) arr->ep[i] = -1;
41 if (f.epose) {
42 int epe[4], epose[12];
43 index_to_perm(cube.epose % factorial(4), 4, epe);
44 index_to_subset(cube.epose / factorial(4), 12, 4, epose);
45 for (int i = 0, ie = 0; i < 12; i++)
46 if (epose[i]) arr->ep[i] = epe_solved[epe[ie++]];
47 }
48 if (f.eposs) {
49 int eps[4], eposs[12];
50 index_to_perm(cube.eposs % factorial(4), 4, eps);
51 index_to_subset(cube.eposs / factorial(4), 12, 4, eposs);
52 for (int i = 0; i < 4; i++) swap(&eposs[eps_solved[i]], &eposs[i+8]);
53 for (int i = 0, is = 0; i < 12; i++)
54 if (eposs[i]) arr->ep[i] = eps_solved[eps[is++]];
55 }
56 if (f.eposm) {
57 int epm[4], eposm[12];
58 index_to_perm(cube.eposm % factorial(4), 4, epm);
59 index_to_subset(cube.eposm / factorial(4), 12, 4, eposm);
60 for (int i = 0; i < 4; i++) swap(&eposm[epm_solved[i]], &eposm[i+8]);
61 for (int i = 0, im = 0; i < 12; i++)
62 if (eposm[i]) arr->ep[i] = epm_solved[epm[im++]];
63 }
64
65 /* All the others */
66 if (f.eofb) int_to_sum_zero_array(cube.eofb, 2, 12, arr->eofb);
67 if (f.eorl) int_to_sum_zero_array(cube.eorl, 2, 12, arr->eorl);
68 if (f.eoud) int_to_sum_zero_array(cube.eoud, 2, 12, arr->eoud);
69 if (f.cp) index_to_perm( cube.cp, 8, arr->cp);
70 if (f.coud) int_to_sum_zero_array(cube.coud, 3, 8, arr->coud);
71 if (f.corl) int_to_sum_zero_array(cube.corl, 3, 8, arr->corl);
72 if (f.cofb) int_to_sum_zero_array(cube.cofb, 3, 8, arr->cofb);
73 if (f.cpos) index_to_perm( cube.cpos, 6, arr->cpos);
74}
75
76Cube arrays_to_cube(CubeArray arr, PieceFilter f) {
77 Cube ret = {0};
78
79 /* Again, ep is the hardest part */
80 if (f.epose) {
81 int epe[4], epose[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
82 for (int i = 0, ie = 0; i < 12; i++)
83 for (int j = 0; j < 4; j++)
84 if (arr.ep[i] == epe_solved[j])
85 { epe[ie++] = j; epose[i] = 1; }
86 ret.epose = factorial(4)*subset_to_index(epose,12,4)+perm_to_index(epe,4);
87 }
88 if (f.eposs) {
89 int eps[4], eposs[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
90 for (int i = 0, is = 0; i < 12; i++)
91 for (int j = 0; j < 4; j++)
92 if (arr.ep[i] == eps_solved[j])
93 { eps[is++] = j; eposs[i] = 1; }
94 for (int i = 0; i < 4; i++) swap(&eposs[eps_solved[i]], &eposs[i+8]);
95 ret.eposs = factorial(4)*subset_to_index(eposs,12,4)+perm_to_index(eps,4);
96 }
97 if (f.eposm) {
98 int epm[4], eposm[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
99 for (int i = 0, im = 0; i < 12; i++)
100 for (int j = 0; j < 4; j++)
101 if (arr.ep[i] == epm_solved[j])
102 { epm[im++] = j; eposm[i] = 1; }
103 for (int i = 0; i < 4; i++) swap(&eposm[epm_solved[i]], &eposm[i+8]);
104 ret.eposm = factorial(4)*subset_to_index(eposm,12,4)+perm_to_index(epm,4);
105 }
106 if (f.eofb) ret.eofb = digit_array_to_int(arr.eofb, 11, 2);
107 if (f.eorl) ret.eorl = digit_array_to_int(arr.eorl, 11, 2);
108 if (f.eoud) ret.eoud = digit_array_to_int(arr.eoud, 11, 2);
109 if (f.cp) ret.cp = perm_to_index( arr.cp, 8 );
110 if (f.coud) ret.coud = digit_array_to_int(arr.coud, 7, 3);
111 if (f.corl) ret.corl = digit_array_to_int(arr.corl, 7, 3);
112 if (f.cofb) ret.cofb = digit_array_to_int(arr.cofb, 7, 3);
113 if (f.cpos) ret.cpos = perm_to_index( arr.cpos, 6 );
114
115 return ret;
116}
117
118Center center_at(Cube cube, Center c) {
119 static CubeArrayAllocated all = {0};
120 CubeArray arr = {0};
121 allocate_cubearray(&arr, &all);
122 cube_to_arrays(cube, &arr, pf_cpos);
123 return arr.cpos[c];
124}
125
126Edge edge_at(Cube cube, Edge e) {
127 static CubeArrayAllocated all = {0};
128 CubeArray arr = {0};
129 allocate_cubearray(&arr, &all);
130 cube_to_arrays(cube, &arr, pf_ep);
131 return arr.ep[e];
132}
133
134Corner corner_at(Cube cube, Corner c) {
135 static CubeArrayAllocated all = {0};
136 CubeArray arr = {0};
137 allocate_cubearray(&arr, &all);
138 cube_to_arrays(cube, &arr, pf_cp);
139 return arr.cp[c];
140}
141
142bool equal(Cube c1, Cube c2) {
143 return c1.eofb == c2.eofb && c1.epose == c2.epose &&
144 c1.eposs == c2.eposs && c1.eposm == c2.eposm &&
145 c1.coud == c2.coud && c1.cp == c2.cp &&
146 c1.cpos == c2.cpos;
147}
148
149bool is_solvable(Cube cube) {
150 static CubeArrayAllocated all = {0};
151 CubeArray arrx = {0};
152 allocate_cubearray(&arrx, &all);
153 cube_to_arrays(cube, &arrx, pf_all);
154
155 /* Since we memorize orientation truncating the last digit, we only need to
156 * check that the permutations have the correct sign. */
157 /* TODO: I should also check that the different eos and cos are compatible */
158 return (perm_sign(arrx.ep,12)^perm_sign(arrx.cpos,6))==perm_sign(arrx.cp,8);
159}
160
161bool is_solved(Cube cube) {
162 /* TODO: might return true if cube is not solvable but looks solved form one
163 of the incompatible interpretations (e.g. eofb and ep solved, but
164 eorl not solve) */
165 return !cube.eofb && !cube.coud && !cube.cp &&
166 !cube.epose && !cube.eposs && !cube.eposm && cube.cpos;
167}
168
169void print_cube(Cube cube) {
170 static CubeArrayAllocated all = {0};
171 CubeArray arrx = {0};
172 allocate_cubearray(&arrx, &all);
173
174 cube_to_arrays(cube, &arrx, pf_all);
175
176/*
177 for (int i = 0; i < 12; i++) printf("%d ", arrx.ep[i]);
178 printf("\n");*/
179
180 for (int i = 0; i < 12; i++) printf(" %s ", edge_string[arrx.ep[i]]);
181 printf("\n");
182 for (int i = 0; i < 12; i++) printf(" %c ", arrx.eofb[i] + '0');
183 printf("\n");
184 for (int i = 0; i < 8; i++) printf("%s ", corner_string[arrx.cp[i]]);
185 printf("\n");
186 for (int i = 0; i < 8; i++) printf(" %c ", arrx.coud[i] + '0');
187 printf("\n");
188 for (int i = 0; i < 6; i++) printf(" %s ", center_string[arrx.cpos[i]]);
189 printf("\n");
190}
191
192Cube admissible_ep(Cube cube, PieceFilter f) {
193 static CubeArrayAllocated all = {0};
194 CubeArray arrx = {0};
195 allocate_cubearray(&arrx, &all);
196 cube_to_arrays(cube, &arrx, f);
197
198 bool used[12] = {0};
199 for (int i = 0; i < 12; i++)
200 if (arrx.ep[i] != -1)
201 used[arrx.ep[i]] = true;
202 for (int i = 0, j = 0; i < 12; i++) {
203 while (j < 11 && used[j]) j++;
204 if (arrx.ep[i] == -1)
205 arrx.ep[i] = j++;
206 }
207
208 return arrays_to_cube(arrx, pf_ep);
209}
210
211Cube inverse_cube(Cube cube) {
212 static CubeArrayAllocated all = {0}, invall = {0};
213 CubeArray arrx = {0}, invx = {0};
214 allocate_cubearray(&arrx, &all);
215 allocate_cubearray(&invx, &invall);
216
217 cube_to_arrays(cube, &arrx, pf_all);
218
219 for (int i = 0; i < 12; i++) {
220 invx.ep[arrx.ep[i]] = i;
221 invx.eofb[arrx.ep[i]] = arrx.eofb[i];
222 invx.eorl[arrx.ep[i]] = arrx.eorl[i];
223 invx.eoud[arrx.ep[i]] = arrx.eoud[i];
224 }
225 for (int i = 0; i < 8; i++) {
226 invx.cp[arrx.cp[i]] = i;
227 invx.coud[arrx.cp[i]] = (3 - arrx.coud[i])%3;
228 invx.corl[arrx.cp[i]] = (3 - arrx.corl[i])%3;
229 invx.cofb[arrx.cp[i]] = (3 - arrx.cofb[i])%3;
230 }
231 for (int i = 0; i < 6; i++)
232 invx.cpos[arrx.cpos[i]] = i;
233
234 return arrays_to_cube(invx, pf_all);
235}
236
237Cube move_via_arrays(CubeArray arr, Cube c, PieceFilter f) {
238 static CubeArrayAllocated all = {0};
239 CubeArray arrx = {0};
240 allocate_cubearray(&arrx, &all);
241
242 cube_to_arrays(c, &arrx, f);
243
244 if (f.epose || f.eposs || f.eposm)
245 apply_permutation( arr.ep, arrx.ep, 12 );
246 if (f.eofb) { apply_permutation( arr.ep, arrx.eofb, 12 );
247 sum_arrays_mod( arr.eofb, arrx.eofb, 12, 2 ); }
248 if (f.eorl) { apply_permutation( arr.ep, arrx.eorl, 12 );
249 sum_arrays_mod( arr.eorl, arrx.eorl, 12, 2 ); }
250 if (f.eoud) { apply_permutation( arr.ep, arrx.eoud, 12 );
251 sum_arrays_mod( arr.eoud, arrx.eoud, 12, 2 ); }
252 if (f.cp) apply_permutation( arr.cp, arrx.cp, 8 );
253 if (f.coud) { apply_permutation( arr.cp, arrx.coud, 8 );
254 sum_arrays_mod( arr.coud, arrx.coud, 8, 3 ); }
255 if (f.corl) { apply_permutation( arr.cp, arrx.corl, 8 );
256 sum_arrays_mod( arr.corl, arrx.corl, 8, 3 ); }
257 if (f.cofb) { apply_permutation( arr.cp, arrx.cofb, 8 );
258 sum_arrays_mod( arr.cofb, arrx.cofb, 8, 3 ); }
259 if (f.cpos) apply_permutation( arr.cpos, arrx.cpos, 6 );
260
261 return arrays_to_cube(arrx, f);
262}
263
264Cube compose(Cube c2, Cube c1) {
265 static CubeArrayAllocated all = {0};
266 CubeArray arrx = {0};
267 allocate_cubearray(&arrx, &all);
268
269 cube_to_arrays(c2, &arrx, pf_all);
270 return move_via_arrays(arrx, c1, pf_all);
271}
diff --git a/old/2021-02-28-transformcube-works/src/cube.h b/old/2021-02-28-transformcube-works/src/cube.h
new file mode 100644
index 0000000..3229eae
--- /dev/null
+++ b/old/2021-02-28-transformcube-works/src/cube.h
@@ -0,0 +1,55 @@
1#ifndef CUBE_H
2#define CUBE_H
3
4#include <stdio.h>
5#include <stdbool.h>
6#include <stdint.h>
7#include "utils.h"
8
9typedef enum {U_center,D_center,R_center,L_center,F_center,B_center} Center;
10typedef enum { UF, UL, UB, UR, DF, DL, DB, DR, FR, FL, BL, BR } Edge;
11typedef enum { UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR } Corner;
12
13typedef struct {
14 uint16_t eofb, eorl, eoud, coud, cofb, corl,
15 epose, eposs, eposm, cp, cpos;
16} Cube;
17
18typedef struct {
19 bool epose, eposs, eposm, eofb, eorl, eoud, cp, coud, cofb, corl, cpos;
20} PieceFilter;
21
22typedef struct {
23 int *ep, *eofb, *eorl, *eoud, *cp, *coud, *corl, *cofb, *cpos;
24} CubeArray;
25
26extern PieceFilter pf_all, pf_cpos, pf_ep, pf_cp,
27 pf_e, pf_s, pf_m, pf_eo, pf_co;
28
29void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f);
30Cube arrays_to_cube(CubeArray arr, PieceFilter f);
31
32Center center_at(Cube cube, Center c);
33Edge edge_at(Cube cube, Edge e);
34Corner corner_at(Cube cube, Corner c);
35/* Aggiungi funzioni per "queries" sul cubo: se pezzo è orientato rispetto ad
36 un certo asse, se il pezzo è risolto... */
37/* Would be nice: a funciton block_solved(Cube c, Block b), where Block is
38 something like struct {bool centers[6], edges[12], corners[8]}
39 (The advantage over checking pieces one by one is that I can convert
40 to cubearray only once and for all) */
41/* Altro TODO, ma forse non ne vale la pena: pre-calcolare tutti i possibili
42 valori per questi, e salvare i risultati in array (facile per cp e cpos,
43 mentre per ep bisogna anche cercare quale tra epose, eposs e eposm contiene
44 il valore giusto) */
45
46bool equal(Cube c1, Cube c2);
47bool is_solvable(Cube cube);
48bool is_solved(Cube cube);
49void print_cube(Cube cube);
50Cube admissible_ep(Cube cube, PieceFilter f); /* Returns admissible ep */
51Cube inverse_cube(Cube cube);
52Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */
53Cube move_via_arrays(CubeArray arr, Cube c, PieceFilter pf);
54
55#endif
diff --git a/old/2021-02-28-transformcube-works/src/main.c b/old/2021-02-28-transformcube-works/src/main.c
new file mode 100644
index 0000000..56f3f3b
--- /dev/null
+++ b/old/2021-02-28-transformcube-works/src/main.c
@@ -0,0 +1,57 @@
1#include <stdio.h>
2#include "cube.h"
3#include "moves.h"
4#include "solve.h"
5#include "transformations.h"
6
7int main() {
8 init_ttables(true, true);
9 init_aux_tables();
10 init_transformations(true, true);
11
12
13 /*char moves[100] = "MR U' B2 Bw F z xE2 M' x Dw' y Fw2";*/
14
15 /*char moves[100] = "M'U2MU2";*/
16 char moves[100] = "R' D2 F2 U2 R F2 R D2 L' R2 D2 F D' L' U' B R' D' U R' B";
17 NissMove alg[100];
18 read_moves(moves, alg, 100);
19 Cube cube = apply_alg(alg, (Cube){0});
20 print_cube(cube);
21 cube = transform_cube(rd, cube);
22 print_cube(cube);
23
24 /*f_eofb(cube);*/
25
26
27 /*
28 SolveData d = { .optimal_only = true, .available = standard_moveset,
29 .max_moves = 10,
30 .cleanup = true,
31 .max_solutions = 10,
32 .f = f_eofb };
33 read_moves("y", d.pre_rotation, 2);
34 int n = solve(cube, &d);
35 printf("%d solutions found:\n", n);
36 for (int i = 0; i < n; i++)
37 print_moves(d.solutions[i]);
38 */
39
40/*
41 NissMove a[5], b[5];
42 read_moves("R", a, 5);
43 read_moves("U", b, 5);
44 Cube c1 = apply_alg(a,(Cube){0}), c2 = apply_alg(b,(Cube){0});
45 print_cube(compose(c2,c1));
46 print_cube(compose(c1,c2));
47
48 NissMove nm[10];
49 read_moves("y(y)RU", nm, 10);
50
51 print_moves(nm);
52 cleanup(nm, 10);
53 print_moves(nm);
54 */
55
56 return 0;
57}
diff --git a/old/2021-02-28-transformcube-works/src/moves.c b/old/2021-02-28-transformcube-works/src/moves.c
new file mode 100644
index 0000000..4b0eee1
--- /dev/null
+++ b/old/2021-02-28-transformcube-works/src/moves.c
@@ -0,0 +1,489 @@
1#include "moves.h"
2
3Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f);
4/* void sort_cancel_rotate(NissMove *alg, int n, bool inv, int top, int front); */
5bool read_ttables_file();
6bool write_ttables_file();
7
8/* Transition tables */
9uint16_t epose_ttable[NMOVES][factorial12/factorial8];
10uint16_t eposs_ttable[NMOVES][factorial12/factorial8];
11uint16_t eposm_ttable[NMOVES][factorial12/factorial8];
12uint16_t eofb_ttable[NMOVES][pow2to11];
13uint16_t eorl_ttable[NMOVES][pow2to11];
14uint16_t eoud_ttable[NMOVES][pow2to11];
15uint16_t cp_ttable[NMOVES][factorial8];
16uint16_t coud_ttable[NMOVES][pow3to7];
17uint16_t cofb_ttable[NMOVES][pow3to7];
18uint16_t corl_ttable[NMOVES][pow3to7];
19uint16_t cpos_ttable[NMOVES][factorial6];
20
21bool commute[NMOVES][NMOVES];
22bool possible_next[NMOVES][NMOVES][NMOVES];
23Move inverse[NMOVES];
24NissMove rotation_algs[24][3] = {
25 { { .m = NULLMOVE }, { .m = NULLMOVE }, { .m = NULLMOVE } },
26 { { .m = y }, { .m = NULLMOVE }, { .m = NULLMOVE } },
27 { { .m = y2 }, { .m = NULLMOVE }, { .m = NULLMOVE } },
28 { { .m = y3 }, { .m = NULLMOVE }, { .m = NULLMOVE } },
29 { { .m = z2 }, { .m = NULLMOVE }, { .m = NULLMOVE } },
30 { { .m = y }, { .m = z2 }, { .m = NULLMOVE } },
31 { { .m = x2 }, { .m = NULLMOVE }, { .m = NULLMOVE } },
32 { { .m = y3 }, { .m = z2 }, { .m = NULLMOVE } },
33 { { .m = z3 }, { .m = NULLMOVE }, { .m = NULLMOVE } },
34 { { .m = z3 }, { .m = y }, { .m = NULLMOVE } },
35 { { .m = z3 }, { .m = y2 }, { .m = NULLMOVE } },
36 { { .m = z3 }, { .m = y3 }, { .m = NULLMOVE } },
37 { { .m = z }, { .m = NULLMOVE }, { .m = NULLMOVE } },
38 { { .m = z }, { .m = y3 }, { .m = NULLMOVE } },
39 { { .m = z }, { .m = y2 }, { .m = NULLMOVE } },
40 { { .m = z }, { .m = y }, { .m = NULLMOVE } },
41 { { .m = x }, { .m = y2 }, { .m = NULLMOVE } },
42 { { .m = x }, { .m = y }, { .m = NULLMOVE } },
43 { { .m = x }, { .m = NULLMOVE }, { .m = NULLMOVE } },
44 { { .m = x }, { .m = y3 }, { .m = NULLMOVE } },
45 { { .m = x3 }, { .m = NULLMOVE }, { .m = NULLMOVE } },
46 { { .m = x3 }, { .m = y }, { .m = NULLMOVE } },
47 { { .m = x3 }, { .m = y2 }, { .m = NULLMOVE } },
48 { { .m = x3 }, { .m = y3 }, { .m = NULLMOVE } },
49};
50
51char move_string[NMOVES][5] =
52 { "-",
53 "U", "U2", "U\'", "D", "D2", "D\'", "R", "R2", "R\'",
54 "L", "L2", "L\'", "F", "F2", "F\'", "B", "B2", "B\'",
55 "Uw", "Uw2", "Uw\'", "Dw", "Dw2", "Dw\'", "Rw", "Rw2", "Rw\'",
56 "Lw", "Lw2", "Lw\'", "Fw", "Fw2", "Fw\'", "Bw", "Bw2", "Bw\'",
57 "M", "M2", "M\'", "S", "S2", "S\'", "E", "E2", "E\'",
58 "x", "x2", "x\'", "y", "y2", "y\'", "z", "z2", "z\'" };
59
60/* For each type of pieces only the effects of U, x and y are described */
61int edge_cycle[NMOVES][12] =
62 { [U] = {UR, UF, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR},
63 [x] = {DF, FL, UF, FR, DB, BL, UB, BR, DR, DL, UL, UR},
64 [y] = {UR, UF, UL, UB, DR, DF, DL, DB, BR, FR, FL, BL} };
65int eofb_flipped[NMOVES][12] =
66 { [x] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 },
67 [y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 } };
68int eorl_flipped[NMOVES][12] =
69 { [x] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
70 [y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 } };
71int eoud_flipped[NMOVES][12] =
72 { [U] = { [UF] = 1, [UL] = 1, [UB] = 1, [UR] = 1 },
73 [x] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 },
74 [y] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } };
75int corner_cycle[NMOVES][8] =
76 { [U] = {UBR, UFR, UFL, UBL, DFR, DFL, DBL, DBR},
77 [x] = {DFR, DFL, UFL, UFR, DBR, DBL, UBL, UBR},
78 [y] = {UBR, UFR, UFL, UBL, DBR, DFR, DFL, DBL} };
79int coud_flipped[NMOVES][8] =
80 { [x] = {[UFR]=2,[UBR]=1,[DBR]=2,[DFR]=1,[UFL]=1,[UBL]=2,[DBL]=1,[DFL]=2} };
81int corl_flipped[NMOVES][8] =
82 { [U] = { [UFR] = 1, [UBR] = 2, [UBL] = 1, [UFL] = 2 },
83 [y] = {[UFR]=1,[UBR]=2,[UBL]=1,[UFL]=2,[DFR]=2,[DBR]=1,[DBL]=2,[DFL]=1} };
84int cofb_flipped[NMOVES][8] =
85 { [U] = { [UFR] = 2, [UBR] = 1, [UBL] = 2, [UFL] = 1 },
86 [x] = {[UFR]=1,[UBR]=2,[DFR]=2,[DBR]=1,[UBL]=1,[UFL]=2,[DBL]=2,[DFL]=1},
87 [y] = {[UFR]=2,[UBR]=1,[UBL]=2,[UFL]=1,[DFR]=1,[DBR]=2,[DBL]=1,[DFL]=2} };
88int center_cycle[NMOVES][6] =
89 { [x] = {F_center, B_center, R_center, L_center, D_center, U_center},
90 [y] = {U_center, D_center, B_center, F_center, R_center, L_center} };
91
92/* Each move is reduced to a combination of U, x and y using this table */
93Move equiv_moves[NMOVES][14] = {
94 [U] = { U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
95 [U2] = { U, U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
96 [U3] = { U, U, U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
97 [D] = { x, x, U, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
98 [D2] = { x, x, U, U, x, x, 0, 0, 0, 0, 0, 0, 0, 0 },
99 [D3] = { x, x, U, U, U, x, x, 0, 0, 0, 0, 0, 0, 0 },
100 [R] = { y, x, U, x, x, x, y, y, y, 0, 0, 0, 0, 0 },
101 [R2] = { y, x, U, U, x, x, x, y, y, y, 0, 0, 0, 0 },
102 [R3] = { y, x, U, U, U, x, x, x, y, y, y, 0, 0, 0 },
103 [L] = { y, y, y, x, U, x, x, x, y, 0, 0, 0, 0, 0 },
104 [L2] = { y, y, y, x, U, U, x, x, x, y, 0, 0, 0, 0 },
105 [L3] = { y, y, y, x, U, U, U, x, x, x, y, 0, 0, 0 },
106 [F] = { x, U, x, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
107 [F2] = { x, U, U, x, x, x, 0, 0, 0, 0, 0, 0, 0, 0 },
108 [F3] = { x, U, U, U, x, x, x, 0, 0, 0, 0, 0, 0, 0 },
109 [B] = { x, x, x, U, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
110 [B2] = { x, x, x, U, U, x, 0, 0, 0, 0, 0, 0, 0, 0 },
111 [B3] = { x, x, x, U, U, U, x, 0, 0, 0, 0, 0, 0, 0 },
112
113 [Uw] = { x, x, U, x, x, y, 0, 0, 0, 0, 0, 0, 0, 0 },
114 [Uw2] = { x, x, U, U, x, x, y, y, 0, 0, 0, 0, 0, 0 },
115 [Uw3] = { x, x, U, U, U, x, x, y, y, y, 0, 0, 0, 0 },
116 [Dw] = { U, y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
117 [Dw2] = { U, U, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
118 [Dw3] = { U, U, U, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
119 [Rw] = { y, y, y, x, U, x, x, x, y, x, 0, 0, 0, 0 },
120 [Rw2] = { y, y, y, x, U, U, x, x, x, y, x, x, 0, 0 },
121 [Rw3] = { y, y, y, x, U, U, U, y, x, x, x, y, 0, 0 },
122 [Lw] = { y, x, U, x, x, x, y, y, y, x, x, x, 0, 0 },
123 [Lw2] = { y, x, U, U, x, x, x, y, y, y, x, x, 0, 0 },
124 [Lw3] = { y, x, U, U, U, x, x, x, y, y, y, x, 0, 0 },
125 [Fw] = { x, x, x, U, y, y, y, x, 0, 0, 0, 0, 0, 0 },
126 [Fw2] = { x, x, x, U, U, y, y, x, 0, 0, 0, 0, 0, 0 },
127 [Fw3] = { x, x, x, U, U, U, y, x, 0, 0, 0, 0, 0, 0 },
128 [Bw] = { x, U, y, y, y, x, x, x, 0, 0, 0, 0, 0, 0 },
129 [Bw2] = { x, U, U, y, y, x, x, x, 0, 0, 0, 0, 0, 0 },
130 [Bw3] = { x, U, U, U, y, x, x, x, 0, 0, 0, 0, 0, 0 },
131
132 [M] = { y, x, U, x, x, U, U, U, y, x, y, y, y, 0 },
133 [M2] = { y, x, U, U, x, x, U, U, x, x, x, y, 0, 0 },
134 [M3] = { y, x, U, U, U, x, x, U, y, x, x, x, y, 0 },
135 [S] = { x, U, U, U, x, x, U, y, y, y, x, 0, 0, 0 },
136 [S2] = { x, U, U, x, x, U, U, y, y, x, 0, 0, 0, 0 },
137 [S3] = { x, U, x, x, U, U, U, y, x, 0, 0, 0, 0, 0 },
138 [E] = { U, x, x, U, U, U, x, x, y, y, y, 0, 0, 0 },
139 [E2] = { U, U, x, x, U, U, x, x, y, y, 0, 0, 0, 0 },
140 [E3] = { U, U, U, x, x, U, x, x, y, 0, 0, 0, 0, 0 },
141
142 [x] = { x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
143 [x2] = { x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
144 [x3] = { x, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
145 [y] = { y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
146 [y2] = { y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
147 [y3] = { y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
148 [z] = { y, y, y, x, y, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
149 [z2] = { y, y, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
150 [z3] = { y, x, y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
151};
152
153/* Movesets */
154bool standard_moveset[NMOVES] = {
155 [U] = true, [U2] = true, [U3] = true, [D] = true, [D2] = true, [D3] = true,
156 [R] = true, [R2] = true, [R3] = true, [L] = true, [L2] = true, [L3] = true,
157 [F] = true, [F2] = true, [F3] = true, [B] = true, [B2] = true, [B3] = true,
158};
159
160bool is_solved_up_to_reorient(Cube cube) {
161 for (int i = 0; i < 25; i++)
162 if (is_solved(apply_alg(rotation_algs[i], cube)))
163 return true;
164 return false;
165}
166
167Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f) {
168 return move_via_arrays((CubeArray)
169 { edge_cycle[m], eofb_flipped[m], eorl_flipped[m], eoud_flipped[m],
170 corner_cycle[m], coud_flipped[m], corl_flipped[m], cofb_flipped[m],
171 center_cycle[m] }, cube, f);
172}
173
174int len(NissMove *alg) {
175 int i;
176 for (i = 0; alg[i].m != NULLMOVE; i++);
177 return i;
178}
179
180int copy_alg(NissMove *src, NissMove *dest) {
181 int i;
182 for (i = 0; src[i].m != NULLMOVE; i++)
183 dest[i] = src[i];
184 dest[i].m = NULLMOVE;
185 return i;
186}
187
188int invert_alg(NissMove *src, NissMove *dest) {
189 int n = len(src);
190 for (int i = 0; i < n; i++)
191 dest[n-i-1] = (NissMove){.m=inverse[src[i].m], .inverse=src[i].inverse};
192 dest[n].m = NULLMOVE;
193 return n;
194}
195
196int concat(NissMove *src1, NissMove *src2, NissMove *dest) {
197 int n1 = len(src1), n2 = len(src2);
198 copy_alg(src1, dest);
199 copy_alg(src2, dest+n1);
200 return n1+n2;
201}
202
203/* TODO: all strings start with space?? */
204void print_moves(NissMove *alg) {
205 bool niss = false;
206 for (int i = 0; alg[i].m != NULLMOVE; i++) {
207 char *fill = !niss && alg[i].inverse ? " (" :
208 (niss && !alg[i].inverse ? ") " : " ");
209 printf("%s%s", fill, move_string[alg[i].m]);
210 niss = alg[i].inverse;
211 }
212 printf("%s\n", niss ? ")" : "");
213}
214
215int read_moves(char *str, NissMove *alg, int n) {
216 bool niss = false;
217 int c = 0;
218
219 for (int i = 0; str[i] && c < n; i++) {
220 if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n')
221 continue;
222
223 if (str[i] == '(' || str[i] == ')') {
224 if ((niss && str[i] == '(') || (!niss && str[i] == ')'))
225 return -1;
226 niss = !niss;
227 continue;
228 }
229
230 alg[c].inverse = niss; alg[c].m = NULLMOVE;
231 for (Move j = 0; j < NMOVES; j++) {
232 if (str[i] == move_string[j][0]) {
233 alg[c].m = j;
234 if (alg[c].m <= B && str[i+1]=='w') { alg[c].m += Uw - U; i++; }
235 if (str[i+1]=='2') { alg[c].m += 1; i++; }
236 else if (str[i+1]=='\'' || str[i+1]=='3') { alg[c].m += 2; i++; }
237 c++;
238 break;
239 }
240 }
241 }
242
243 alg[c].m = NULLMOVE;
244 return c;
245}
246
247/* Helper function for cleanup. alg must contain only basic moves, no 2 or '.
248 top and front describe an admissible orientation of the cube. *
249void sort_cancel_rotate(NissMove *alg, int n, bool inv, int top, int front) {
250 int c = 0, i = 0;
251 PieceFilter cpos_only = { .cpos = true };
252 NissMove aux[n+3];
253 aux[0].m = NULLMOVE;
254
255 while (i < n && alg[i].m != NULLMOVE) {
256 int j = i;
257 while (j < n && commute[alg[i].m][alg[j].m]) j++;
258 Move base = 6*((alg[i].m-1)/6);
259 int t1 = 0, t2 = 0;
260 for (int k = i; k < j; k++)
261 if (alg[k].m == base+1) t1 = (t1+1)%4;
262 else t2 = (t2+1)%4;
263 if (t1) { aux[c].inverse = inv; aux[c].m = base+t1; c++; }
264 if (t2) { aux[c].inverse = inv; aux[c].m = base+t2+3; c++; }
265 i = j;
266 }
267 aux[c].m = NULLMOVE;
268
269 CubeArray q;
270 cube_to_arrays((Cube){0}, &q, cpos_only);
271 * First we try to rotate in one move, then we try an x or y rotation
272 followed by a z rotation
273 TODO: change once I implement the "is_rotaton(Move) function" *
274 for (int r = x; r <= z3; r++) {
275 move_cubearray(r, &q, cpos_only);
276 if (q.cpos[F_center] == front && q.cpos[U_center] == top) {
277 aux[c].inverse = inv; aux[c].m = r;
278
279 aux[++c].m = NULLMOVE;
280 copy_alg(aux, alg);
281 return;
282 }
283 move_cubearray(inverse[r], &q, cpos_only);
284 }
285 for (int r = x; r <= y3; r++) {
286 move_cubearray(r, &q, cpos_only);
287 if (q.cpos[F_center] == front) {
288 aux[c].inverse = inv; aux[c++].m = r;
289 break;
290 }
291 move_cubearray(inverse[r], &q, cpos_only);
292 }
293 for (int r = z; r <= z3; r++) {
294 move_cubearray(r, &q, cpos_only);
295 if (q.cpos[U_center] == top) {
296 aux[c].inverse = inv; aux[c++].m = r;
297 break;
298 }
299 move_cubearray(inverse[r], &q, cpos_only);
300 }
301
302 aux[c].m = NULLMOVE;
303 copy_alg(aux, alg);
304}
305
306* TODO: does not work with niss + rotations *
307void cleanup(NissMove *alg, int n) {
308 int count_n = 0, count_i = 0, *count;
309 PieceFilter cpos_only = { .cpos = true };
310 NissMove aux_n[n+1], aux_i[n+1], *aux;
311 CubeArray cube_n, cube_i, *cube;
312 cube_to_arrays((Cube){0}, &cube_n, cpos_only);
313 cube_to_arrays((Cube){0}, &cube_i, cpos_only);
314
315 for (int i = 0; count_n + count_i < n && alg[i].m != NULLMOVE; i++) {
316 if (alg[i].inverse) { count = &count_i; aux = aux_i; cube = &cube_i; }
317 else { count = &count_n; aux = aux_n; cube = &cube_n; }
318
319 for (int j = 0; equiv_moves[alg[i].m][j]; j++) {
320 Move m = equiv_moves[alg[i].m][j];
321 aux[*count].inverse = alg[i].inverse;
322 move_cubearray(m, cube, cpos_only);
323 if (m == U) aux[(*count)++].m = 3 * cube->cpos[0] + 1;
324 }
325 }
326
327 aux_n[count_n].m = NULLMOVE;
328 aux_i[count_i].m = NULLMOVE;
329 sort_cancel_rotate(aux_n, count_n, false, cube_n.cpos[0], cube_n.cpos[4]);
330 sort_cancel_rotate(aux_i, count_i, true, cube_i.cpos[0], cube_n.cpos[4]);
331 copy_alg(aux_n, alg);
332 copy_alg(aux_i, alg+count_n);
333}
334*/
335
336bool read_ttables_file() {
337 FILE *ttf;
338 long unsigned int me[11] = { factorial12/factorial8, factorial12/factorial8,
339 factorial12/factorial8, pow2to11, pow2to11, pow2to11,
340 factorial8, pow3to7, pow3to7, pow3to7, factorial6 };
341 if ((ttf = fopen("ttables", "rb")) != NULL) {
342 bool r = true;
343 for (int m = 0; m < NMOVES; m++) {
344 r = r && fread(epose_ttable[m], sizeof(uint16_t), me[0], ttf) == me[0];
345 r = r && fread(eposs_ttable[m], sizeof(uint16_t), me[1], ttf) == me[1];
346 r = r && fread(eposm_ttable[m], sizeof(uint16_t), me[2], ttf) == me[2];
347 r = r && fread(eofb_ttable[m], sizeof(uint16_t), me[3], ttf) == me[3];
348 r = r && fread(eorl_ttable[m], sizeof(uint16_t), me[4], ttf) == me[4];
349 r = r && fread(eoud_ttable[m], sizeof(uint16_t), me[5], ttf) == me[5];
350 r = r && fread(cp_ttable[m], sizeof(uint16_t), me[6], ttf) == me[6];
351 r = r && fread(coud_ttable[m], sizeof(uint16_t), me[7], ttf) == me[7];
352 r = r && fread(corl_ttable[m], sizeof(uint16_t), me[8], ttf) == me[8];
353 r = r && fread(cofb_ttable[m], sizeof(uint16_t), me[9], ttf) == me[9];
354 r = r && fread(cpos_ttable[m], sizeof(uint16_t), me[10], ttf) == me[10];
355 }
356 fclose(ttf);
357 return r;
358 } else return false;
359}
360
361bool write_ttables_file() {
362 FILE *ttf;
363 long unsigned int me[11] = { factorial12/factorial8, factorial12/factorial8,
364 factorial12/factorial8, pow2to11, pow2to11, pow2to11,
365 factorial8, pow3to7, pow3to7, pow3to7, factorial6 };
366 if ((ttf = fopen("ttables", "wb")) != NULL) {
367 bool r = true;
368 for (int m = 0; m < NMOVES; m++) {
369 r = r && fwrite(epose_ttable[m], sizeof(uint16_t), me[0], ttf) == me[0];
370 r = r && fwrite(eposs_ttable[m], sizeof(uint16_t), me[1], ttf) == me[1];
371 r = r && fwrite(eposm_ttable[m], sizeof(uint16_t), me[2], ttf) == me[2];
372 r = r && fwrite(eofb_ttable[m], sizeof(uint16_t), me[3], ttf) == me[3];
373 r = r && fwrite(eorl_ttable[m], sizeof(uint16_t), me[4], ttf) == me[4];
374 r = r && fwrite(eoud_ttable[m], sizeof(uint16_t), me[5], ttf) == me[5];
375 r = r && fwrite(cp_ttable[m], sizeof(uint16_t), me[6], ttf) == me[6];
376 r = r && fwrite(coud_ttable[m], sizeof(uint16_t), me[7], ttf) == me[7];
377 r = r && fwrite(corl_ttable[m], sizeof(uint16_t), me[8], ttf) == me[8];
378 r = r && fwrite(cofb_ttable[m], sizeof(uint16_t), me[9], ttf) == me[9];
379 r = r && fwrite(cpos_ttable[m], sizeof(uint16_t), me[10],ttf) == me[10];
380 }
381 fclose(ttf);
382 return r;
383 } else return false;
384}
385
386void init_ttables(bool read, bool write) {
387 /* Generate all move cycles and flips; I do this regardless */
388 for (int i = 0; i < NMOVES; i++) {
389 if (i == U || i == x || i == y)
390 continue;
391
392 Cube c = {0};
393 for (int j = 0; equiv_moves[i][j]; j++)
394 c = apply_move_cubearray(equiv_moves[i][j], c, pf_all);
395
396 CubeArray arrs = {
397 edge_cycle[i], eofb_flipped[i], eorl_flipped[i], eoud_flipped[i],
398 corner_cycle[i], coud_flipped[i], corl_flipped[i], cofb_flipped[i],
399 center_cycle[i]
400 };
401 cube_to_arrays(c, &arrs, pf_all);
402 }
403
404 if (read)
405 if (read_ttables_file())
406 return;
407
408 /* Initialize transition tables */
409 for (int m = 0; m < NMOVES; m++) {
410 for (uint16_t i = 0; i < factorial12/factorial8; i++) {
411 epose_ttable[m][i] = apply_move_cubearray(m,(Cube){.epose=i},pf_e).epose;
412 eposs_ttable[m][i] = apply_move_cubearray(m,(Cube){.eposs=i},pf_s).eposs;
413 eposm_ttable[m][i] = apply_move_cubearray(m,(Cube){.eposm=i},pf_m).eposm;
414 }
415 for (uint16_t i = 0; i < pow2to11; i++ ) {
416 eofb_ttable[m][i] = apply_move_cubearray(m,(Cube){.eofb=i},pf_eo).eofb;
417 eorl_ttable[m][i] = apply_move_cubearray(m,(Cube){.eorl=i},pf_eo).eorl;
418 eoud_ttable[m][i] = apply_move_cubearray(m,(Cube){.eoud=i},pf_eo).eoud;
419 }
420 for (uint16_t i = 0; i < pow3to7; i++) {
421 coud_ttable[m][i] = apply_move_cubearray(m,(Cube){.coud=i},pf_co).coud;
422 corl_ttable[m][i] = apply_move_cubearray(m,(Cube){.corl=i},pf_co).corl;
423 cofb_ttable[m][i] = apply_move_cubearray(m,(Cube){.cofb=i},pf_co).cofb;
424 }
425 for (uint16_t i = 0; i < factorial8; i++)
426 cp_ttable[m][i] = apply_move_cubearray(m,(Cube){.cp=i},pf_cp).cp;
427 for (uint16_t i = 0; i < factorial6; i++)
428 cpos_ttable[m][i] = apply_move_cubearray(m,(Cube){.cpos=i},pf_cpos).cpos;
429 }
430
431 if (write)
432 if (!write_ttables_file())
433 printf("Error in writing ttables: file not writable\n");
434}
435
436Cube move_cube(Move m, Cube cube) {
437 Cube moved = {0};
438
439 moved.epose = epose_ttable[m][cube.epose];
440 moved.eposs = eposs_ttable[m][cube.eposs];
441 moved.eposm = eposm_ttable[m][cube.eposm];
442 moved.eofb = eofb_ttable[m][cube.eofb];
443 moved.eorl = eorl_ttable[m][cube.eorl];
444 moved.eoud = eoud_ttable[m][cube.eoud];
445 moved.coud = coud_ttable[m][cube.coud];
446 moved.cofb = cofb_ttable[m][cube.cofb];
447 moved.corl = corl_ttable[m][cube.corl];
448 moved.cp = cp_ttable[m][cube.cp];
449 moved.cpos = cpos_ttable[m][cube.cpos];
450
451 return moved;
452}
453
454Cube apply_alg(NissMove *alg, Cube cube) {
455 Cube ret = {0};
456 for (int i = 0; alg[i].m != NULLMOVE; i++)
457 if (alg[i].inverse)
458 ret = move_cube(alg[i].m, ret);
459
460 ret = compose(cube, inverse_cube(ret));
461
462 for (int i = 0; alg[i].m != NULLMOVE; i++)
463 if (!alg[i].inverse)
464 ret = move_cube(alg[i].m, ret);
465 return ret;
466}
467
468void init_aux_tables() {
469 /* Commute */
470 for (int i = 0; i < NMOVES; i++)
471 for (int j = 0; j < NMOVES; j++)
472 commute[i][j] = equal(move_cube(i, move_cube(j, (Cube){0})),
473 move_cube(j, move_cube(i, (Cube){0})));
474
475 /* Possible next (if the sequence i j k is valid) */
476 for (int i = 0; i < NMOVES; i++)
477 for (int j = 0; j < NMOVES; j++)
478 for (int k = 0; k < NMOVES; k++)
479 possible_next[i][j][k] =
480 (j == 0) ||
481 (j != 0 && (j-(j-1)%3) != (k-(k-1)%3) &&
482 !(i != 0 && commute[i][j] && (i-(i-1)%3) == (k-(k-1)%3)));
483
484 /* Inverse */
485 for (int i = 0; i < NMOVES; i++)
486 inverse[i] = i == NULLMOVE ? NULLMOVE : i + 2 - 2*((i-1)%3);
487
488}
489
diff --git a/old/2021-02-28-transformcube-works/src/moves.h b/old/2021-02-28-transformcube-works/src/moves.h
new file mode 100644
index 0000000..c1489a1
--- /dev/null
+++ b/old/2021-02-28-transformcube-works/src/moves.h
@@ -0,0 +1,50 @@
1#ifndef MOVES_H
2#define MOVES_H
3
4#include <stdio.h>
5#include <stdbool.h>
6#include <stdint.h>
7#include "cube.h"
8#include "utils.h"
9
10#define NMOVES (z3+1)
11
12typedef enum {
13 NULLMOVE,
14 U, U2, U3, D, D2, D3, R, R2, R3, L, L2, L3, F, F2, F3, B, B2, B3,
15 Uw, Uw2, Uw3, Dw, Dw2, Dw3, Rw, Rw2, Rw3,
16 Lw, Lw2, Lw3, Fw, Fw2, Fw3, Bw, Bw2, Bw3,
17 M, M2, M3, S, S2, S3, E, E2, E3,
18 x, x2, x3, y, y2, y3, z, z2, z3,
19} Move;
20
21/* An alg is an array of "NissMoves", which can be on normal or on inverse. */
22typedef struct { bool inverse; Move m; } NissMove;
23
24/* Movesets */
25extern bool standard_moveset[NMOVES];
26
27extern bool commute[NMOVES][NMOVES];
28extern bool possible_next[NMOVES][NMOVES][NMOVES];
29extern Move inverse[NMOVES];
30extern NissMove rotation_algs[24][3]; /* Same order as transformations */
31
32int len(NissMove *alg);
33int copy_alg(NissMove *src, NissMove *dest); /*return number of moves copied */
34int invert_alg(NissMove *src, NissMove *dest);
35int concat(NissMove *src1, NissMove *src2, NissMove *dest);
36void print_moves(NissMove *alg);
37int read_moves(char *str, NissMove *alg, int n); /* reads at most n moves */
38void cleanup(NissMove *src, int n); /* rewrites using basic moves, at most n */
39
40bool is_solved_up_to_reorient(Cube cube);
41Cube move_cube(Move m, Cube cube);
42Cube apply_alg(NissMove *alg, Cube cube);
43
44/* Merge the following two?
45 always in this order */
46void init_ttables(bool read, bool write);
47void init_aux_tables();
48
49
50#endif
diff --git a/old/2021-02-28-transformcube-works/src/solve.c b/old/2021-02-28-transformcube-works/src/solve.c
new file mode 100644
index 0000000..07c9075
--- /dev/null
+++ b/old/2021-02-28-transformcube-works/src/solve.c
@@ -0,0 +1,180 @@
1#include "solve.h"
2
3/* Data for creating a pruning table:
4 - compressed: if set to true, each entry occupies only 4 bits, but values
5 larger than 15 cannot be stored.
6 - available[] is the list of availabel moves, as above.
7 - *ptable is the actual table to fill.
8 - n is the number of states (size of ptable).
9 - index must "linearize" the cube, i.e. return its index in ptable.
10 - fname is the name of the file where to store the table */
11typedef struct {
12 bool compressed, *available;
13 int max_moves;
14 uint8_t *ptable;
15 uint64_t n;
16 uint64_t (*index)(Cube);
17 char *fname;
18} PruneData;
19
20/* TODO: comment this */
21typedef struct {
22 bool niss;
23 int m, d;
24 uint64_t *n;
25 Move last1, last2;
26} DfsData;
27
28void solve_dfs(Cube cube, SolveData *sd, DfsData dd);
29void init_ptable(PruneData *pd, bool read, bool write);
30
31/* Search solutions of lenght exactly d */
32void solve_dfs(Cube cube, SolveData *sd, DfsData dd) {
33 if (*dd.n >= sd->max_solutions ||
34 ((!sd->can_niss || dd.niss) && dd.m + sd->f(cube) > dd.d))
35 return;
36
37 (sd->solutions[*dd.n][dd.m]).inverse = dd.niss;
38 (sd->solutions[*dd.n][dd.m]).m = NULLMOVE;
39
40 if (!sd->f(cube)) { /* Solved */
41 if (dd.m == dd.d) {
42 (*dd.n)++;
43 if (*dd.n < sd->max_solutions)
44 copy_alg(sd->solutions[*dd.n-1], sd->solutions[*dd.n]);
45 }
46 return;
47 }
48
49 for (int i = 0; i < NMOVES && sd->sorted_moves[i] != NULLMOVE; i++) {
50 Move move = sd->sorted_moves[i];
51 if (possible_next[dd.last2][dd.last1][move]) {
52 sd->solutions[*dd.n][dd.m].inverse = dd.niss;
53 sd->solutions[*dd.n][dd.m].m = move;
54 DfsData nn = { .niss = dd.niss, .m = dd.m+1, .d = dd.d, .n = dd.n,
55 .last1 = move, .last2 = dd.last1 };
56 solve_dfs(move_cube(move, cube), sd, nn);
57 }
58 }
59
60 if (sd->can_niss && !dd.niss &&
61 (!dd.m || (dd.m && sd->f(move_cube(dd.last1, (Cube){0}))))) {
62 DfsData nn = { .niss = true, .m = dd.m, .d = dd.d, .n = dd.n };
63 solve_dfs(inverse_cube(cube), sd, nn);
64 }
65}
66
67/* Iterative deepening depth-first search: for i running from the minimum
68 to the maximum number of moves allowed, looks for solutions of length i. */
69int solve(Cube cube, SolveData *sd) {
70 if (sd->precondition != NULL && !sd->precondition(cube))
71 return -1;
72
73 /* If not given, generate sorted list of moves */
74 if (sd->sorted_moves[0] == NULLMOVE) {
75 int a[NMOVES], b[NMOVES], ia = 0, ib = 0;
76 for (int i = 0; i < NMOVES; i++) {
77 if (sd->available[i]) {
78 if (sd->f(move_cube(i, (Cube){0})))
79 a[ia++] = i;
80 else
81 b[ib++] = i;
82 }
83 }
84 intarrcopy(a, (int *)sd->sorted_moves, ia);
85 intarrcopy(b, (int *)sd->sorted_moves+ia, ib);
86 sd->sorted_moves[ia+ib] = NULLMOVE;
87 }
88
89 sd->max_solutions = min(sd->max_solutions, MAXS);
90 /*TODO
91 Cube rotated = apply_alg(sd->pre_rotation, (Cube){0});
92 cube = apply_alg(inverse_cube(rotated), compose(cube, rotated));
93 */
94
95 uint64_t ret = 0;
96 for (int i=sd->min_moves; i<=sd->max_moves&&!(ret&&sd->optimal_only); i++) {
97 DfsData dd = { .d = i, .n = &ret };
98 solve_dfs(cube, sd, dd);
99 }
100
101 /* TODO: transform solutions with inverse of pre_rotation */
102 /*
103 for (uint64_t i = 0; i < ret; i++) {
104 if (sd->cleanup)
105 cleanup(sd->solutions[i], sd->max_moves*3);
106 }*/
107
108 return ret;
109}
110
111void prune_dfs(Cube cube, PruneData *pd, DfsData dd) {
112 uint64_t ind = pd->index(cube);
113 if ((!ind || pd->ptable[ind]) && pd->ptable[ind] != dd.m)
114 return;
115 if (dd.m == dd.d) {
116 if (ind && !pd->ptable[ind]) {
117 pd->ptable[ind] = dd.m;
118 (*dd.n)++;
119 }
120 return;
121 }
122
123 for (int i = 0; i < NMOVES; i++) {
124 if (dd.m<20)
125 if (possible_next[dd.last2][dd.last1][i] && pd->available[i]) {
126 DfsData nn = { .m = dd.m+1, .d = dd.d, .n = dd.n,
127 .last1 = i, .last2 = dd.last1 };
128 prune_dfs(move_cube(i, cube), pd, nn);
129 }
130 }
131}
132
133void init_ptable(PruneData *pd, bool read, bool write) {
134 if (read) {
135 FILE *ptf;
136 if ((ptf = fopen(pd->fname, "rb")) != NULL) {
137 uint64_t r = fread(pd->ptable, sizeof(uint8_t), pd->n, ptf);
138 fclose(ptf);
139 if (r == pd->n) return;
140 }
141 }
142
143 /* TODO: for now it behaves always as if copressed = false */
144 for (uint64_t i = 0; i < pd->n; i++)
145 pd->ptable[i] = 0;
146
147 uint64_t s = 1;
148 for (int i = 1; i < pd->max_moves && s < pd->n; i++) {
149 DfsData dd = { .d = i, .n = &s };
150 prune_dfs((Cube){0}, pd, dd);
151 }
152
153 if (write) {
154 FILE *ptf;
155 if ((ptf = fopen(pd->fname, "wb")) != NULL) {
156 fwrite(pd->ptable, sizeof(uint8_t), pd->n, ptf);
157 fclose(ptf);
158 return;
159 }
160 }
161}
162
163/* Solving steps (and indexing functions) */
164
165uint64_t index_eofb(Cube cube) { return cube.eofb; }
166uint16_t f_eofb(Cube cube) {
167 static bool initialized_ptable;
168 static uint8_t pt_eofb[pow2to11];
169 if (!initialized_ptable) {
170 PruneData pd = {
171 .compressed = false, .available = standard_moveset, .max_moves = 13,
172 .ptable = pt_eofb, .n = pow2to11, .index = index_eofb,
173 .fname = "ptable_eofb"
174 };
175 init_ptable(&pd, false, true);
176 initialized_ptable = true;
177 }
178 return cube.eofb ? pt_eofb[cube.eofb] : 0;
179}
180
diff --git a/old/2021-02-28-transformcube-works/src/solve.h b/old/2021-02-28-transformcube-works/src/solve.h
new file mode 100644
index 0000000..d585a8e
--- /dev/null
+++ b/old/2021-02-28-transformcube-works/src/solve.h
@@ -0,0 +1,56 @@
1#ifndef SOLVE_H
2#define SOLVE_H
3
4#include <stdlib.h>
5#include "cube.h"
6#include "moves.h"
7
8/* Maximum number of moves per solution and of solutions */
9#define MAXM 30
10#define MAXS 999
11
12/* Data for solving a step:
13 - can_niss is true niss can be used, false otherwise.
14 - optimal_only if true, dynamically updates max_moves so non-optimal
15 solutions are discarded.
16 - cleanup determines whether the cleaunup() function should be used on
17 the found solutions before returning.
18 - available[m] is true if the move m can be used, false otherwise.
19 - min_moves and max_moves are the minimum and maximum number of moves that
20 can be used.
21 - max_solution is the maximum number of solutions that can be returned.
22 - precondition can be used to check wheter the step can actually be applied
23 to the cube. If it returns false, solve() stops immediately returning -1.
24 - f must return 0 if and only if the step is solve, otherwise it must return
25 a lower bound for the number of moves required (without niss).
26 - sorted_moves[] can be used to specify in which order moves are tried
27 by the solving algorithm (for example if one wants to always try F' before
28 F). If sorted_moves[0] == NULLMOVE, the list is generated automatically.
29 It is advised to list first all the moves that actually influence the
30 solved state of the step (this is the default choice). This is in order to
31 avoid cases like B2 F for EO and to NISS only when it makes sense.
32 - start_moves [Currently unused, REMOVE]
33 are the moves that will be used as first moves of all
34 solutions. For example giving R' U' F (F' U R) will generate FMC scrambles
35 and y (y) will solve the step on another axis.
36 - pre_rotation are the rotations to apply before the scamble to solve
37 the step wrt a different orientation
38 - pre_rotation are the rotations to apply before the scamble to solve
39 the step wth respect to a different orientation.
40 - solutions[][] is the array where to store the found solutions. */
41typedef struct {
42 bool can_niss, optimal_only, cleanup, *available;
43 int min_moves, max_moves;
44 uint64_t max_solutions;
45 bool (*precondition)(Cube);
46 uint16_t (*f)(Cube);
47 Move sorted_moves[NMOVES];
48 NissMove pre_rotation[3], solutions[MAXS][MAXM];
49} SolveData;
50
51int solve(Cube cube, SolveData *data); /* Returns the number of solutions. */
52
53/* Steps */
54uint16_t f_eofb(Cube cube);
55
56#endif
diff --git a/old/2021-02-28-transformcube-works/src/transformations.c b/old/2021-02-28-transformcube-works/src/transformations.c
new file mode 100644
index 0000000..9ae10e9
--- /dev/null
+++ b/old/2021-02-28-transformcube-works/src/transformations.c
@@ -0,0 +1,224 @@
1#include "transformations.h"
2
3int edge_slice(int e); /* Return slice (e=0, s=1, m=2) to which e belongs */
4Cube rotate_via_compose(Transformation r, Cube c);
5bool read_rtables_file();
6bool write_rtables_file();
7
8/* Values mod 3 to determine from which side to take the state to convert */
9int epose_source[NROTATIONS]; /* 0 = epose, 1 = eposs, 2 = eposm */
10int eposs_source[NROTATIONS];
11int eposm_source[NROTATIONS];
12int eofb_source[NROTATIONS]; /* 0 = eoud, 1 = eorl, 2 = eofb */
13int eorl_source[NROTATIONS];
14int eoud_source[NROTATIONS];
15int coud_source[NROTATIONS]; /* 0 = coud, 1 = corl, 2 = cofb */
16int cofb_source[NROTATIONS];
17int corl_source[NROTATIONS];
18
19/* Transition tables for rotations (n+1 is mirror) */
20uint16_t epose_rtable[NROTATIONS][factorial12/factorial8];
21uint16_t eposs_rtable[NROTATIONS][factorial12/factorial8];
22uint16_t eposm_rtable[NROTATIONS][factorial12/factorial8];
23uint16_t eo_rtable[NROTATIONS][pow2to11];
24/*uint16_t eofb_rtable[NROTATIONS][pow2to11];
25uint16_t eorl_rtable[NROTATIONS][pow2to11];
26uint16_t eoud_rtable[NROTATIONS][pow2to11];*/
27uint16_t cp_rtable[NROTATIONS][factorial8];
28uint16_t co_rtable[NROTATIONS][pow3to7];
29/*uint16_t coud_rtable[NROTATIONS][pow3to7];
30uint16_t cofb_rtable[NROTATIONS][pow3to7];
31uint16_t corl_rtable[NROTATIONS][pow3to7];*/
32uint16_t cpos_rtable[NROTATIONS][factorial6];
33
34/* Same for moves */
35uint16_t move_rtable[NROTATIONS][NMOVES];
36
37NissMove rotation_niss[NROTATIONS][6];
38
39int edge_slice(int e) {
40 if (e == FR || e == FL || e == BL || e == BR)
41 return 0;
42 if (e == UR || e == UL || e == DR || e == DL)
43 return 1;
44 return 2;
45}
46
47Cube rotate_via_compose(Transformation r, Cube c) {
48 if (r != mirror) {
49 return apply_alg(rotation_niss[r], c);
50 } else {
51 static int zero12[12] = {0,0,0,0,0,0,0,0,0,0,0,0},
52 zero8[12] = {0,0,0,0,0,0,0,0},
53 mirror_ep[12] = {UF,UR,UB,UL,DF,DR,DB,DL,FL,FR,BR,BL},
54 mirror_cp[8] = {UFL, UFR, UBR, UBL, DFL, DFR, DBR, DBL},
55 mirror_cpos[6] =
56 {U_center,D_center,L_center,R_center,F_center,B_center};
57 return move_via_arrays((CubeArray){
58 .ep = mirror_ep, .eofb = zero12, .eorl = zero12, .eoud = zero12,
59 .cp = mirror_cp, .coud = zero8, .corl = zero8, .cofb = zero8,
60 .cpos = mirror_cpos}, c, pf_all);
61 }
62}
63
64bool read_rtables_file() {
65 FILE *ttf;
66 long unsigned int me[12] = { factorial12/factorial8, factorial12/factorial8,
67 factorial12/factorial8, pow2to11, pow2to11, pow2to11,
68 factorial8, pow3to7, pow3to7, pow3to7, factorial6, NMOVES };
69 if ((ttf = fopen("rtables", "rb")) != NULL) {
70 bool r = true;
71 for (int m = 0; m < NROTATIONS; m++) {
72 r = r && fread(epose_rtable[m], sizeof(uint16_t), me[0], ttf) == me[0];
73 r = r && fread(eposs_rtable[m], sizeof(uint16_t), me[1], ttf) == me[1];
74 r = r && fread(eposm_rtable[m], sizeof(uint16_t), me[2], ttf) == me[2];
75 r = r && fread(eo_rtable[m], sizeof(uint16_t), me[3], ttf) == me[3];
76 /*r = r && fread(eofb_rtable[m], sizeof(uint16_t), me[3], ttf) == me[3];
77 r = r && fread(eorl_rtable[m], sizeof(uint16_t), me[4], ttf) == me[4];
78 r = r && fread(eoud_rtable[m], sizeof(uint16_t), me[5], ttf) == me[5];*/
79 r = r && fread(cp_rtable[m], sizeof(uint16_t), me[6], ttf) == me[6];
80 r = r && fread(co_rtable[m], sizeof(uint16_t), me[7], ttf) == me[7];
81 /*r = r && fread(coud_rtable[m], sizeof(uint16_t), me[7], ttf) == me[7];
82 r = r && fread(corl_rtable[m], sizeof(uint16_t), me[8], ttf) == me[8];
83 r = r && fread(cofb_rtable[m], sizeof(uint16_t), me[9], ttf) == me[9];*/
84 r = r && fread(cpos_rtable[m], sizeof(uint16_t), me[10], ttf) == me[10];
85 r = r && fread(move_rtable[m], sizeof(uint16_t), me[11], ttf) == me[11];
86 }
87 fclose(ttf);
88 return r;
89 } else return false;
90}
91
92bool write_rtables_file() {
93 FILE *ttf;
94 long unsigned int me[12] = { factorial12/factorial8, factorial12/factorial8,
95 factorial12/factorial8, pow2to11, pow2to11, pow2to11,
96 factorial8, pow3to7, pow3to7, pow3to7, factorial6, NMOVES };
97 if ((ttf = fopen("rtables", "wb")) != NULL) {
98 bool r = true;
99 for (int m = 0; m < NROTATIONS; m++) {
100 r = r && fwrite(epose_rtable[m], sizeof(uint16_t), me[0], ttf) == me[0];
101 r = r && fwrite(eposs_rtable[m], sizeof(uint16_t), me[1], ttf) == me[1];
102 r = r && fwrite(eposm_rtable[m], sizeof(uint16_t), me[2], ttf) == me[2];
103 r = r && fwrite(eo_rtable[m], sizeof(uint16_t), me[3], ttf) == me[3];
104 /*r = r && fwrite(eofb_rtable[m], sizeof(uint16_t), me[3], ttf) == me[3];
105 r = r && fwrite(eorl_rtable[m], sizeof(uint16_t), me[4], ttf) == me[4];
106 r = r && fwrite(eoud_rtable[m], sizeof(uint16_t), me[5], ttf) == me[5];*/
107 r = r && fwrite(cp_rtable[m], sizeof(uint16_t), me[6], ttf) == me[6];
108 r = r && fwrite(co_rtable[m], sizeof(uint16_t), me[7], ttf) == me[7];
109 /*r = r && fwrite(coud_rtable[m], sizeof(uint16_t), me[7], ttf) == me[7];
110 r = r && fwrite(corl_rtable[m], sizeof(uint16_t), me[8], ttf) == me[8];
111 r = r && fwrite(cofb_rtable[m], sizeof(uint16_t), me[9], ttf) == me[9];*/
112 r = r && fwrite(cpos_rtable[m], sizeof(uint16_t), me[10],ttf) == me[10];
113 r = r && fwrite(move_rtable[m], sizeof(uint16_t), me[11],ttf) == me[11];
114 }
115 fclose(ttf);
116 return r;
117 } else return false;
118}
119
120void init_transformations(bool read, bool write) {
121 /* Compute sources */
122 for (int i = 0; i < NROTATIONS; i++) {
123 Cube cube = {0};
124 if (i != mirror)
125 cube = apply_alg(rotation_algs[i], (Cube){0});
126 epose_source[i] = edge_slice(edge_at(cube, FR));
127 eposs_source[i] = edge_slice(edge_at(cube, UR));
128 eposm_source[i] = edge_slice(edge_at(cube, UF));
129 eofb_source[i] = center_at(cube, F_center)/2;
130 eorl_source[i] = center_at(cube, R_center)/2;
131 eoud_source[i] = center_at(cube, U_center)/2;
132 coud_source[i] = center_at(cube, U_center)/2;
133 cofb_source[i] = center_at(cube, F_center)/2;
134 corl_source[i] = center_at(cube, R_center)/2;
135 }
136
137 /*TODO: maybe move down*/
138 /* Compute rotation_niss array, necessary for rotate_via_compose */
139 for (int r = 0; r != mirror; r++) {
140 concat(rotation_algs[r], rotation_algs[r], rotation_niss[r]);
141 for (int i = len(rotation_algs[r]); rotation_niss[r][i].m != NULLMOVE; i++)
142 rotation_niss[r][i].inverse = true;
143 }
144
145 /* If I can read tables from file, I stop here */
146 if (read)
147 if (read_rtables_file())
148 return;
149
150 /* Initialize tables */
151 for (int m = 0; m < NROTATIONS; m++) {
152 int eparr[12] = {0,0,0,0,0,0,0,0,0,0,0,0}, cparr[8] = {0,0,0,0,0,0,0,0};
153 CubeArray epcp = { .ep = eparr, .cp = cparr };
154 cube_to_arrays(apply_alg(rotation_algs[m], (Cube){0}), &epcp,
155 (PieceFilter){.epose=true,.eposs=true,.eposm=true,.cp=true});
156 for (uint16_t i = 0; i < factorial12/factorial8; i++) {
157 Cube c[3] = { admissible_ep((Cube){ .epose = i}, pf_e),
158 admissible_ep((Cube){ .eposs = i}, pf_s),
159 admissible_ep((Cube){ .eposm = i}, pf_m) };
160 epose_rtable[m][i] = rotate_via_compose(m, c[epose_source[m]]).epose;
161 eposs_rtable[m][i] = rotate_via_compose(m, c[eposs_source[m]]).eposs;
162 eposm_rtable[m][i] = rotate_via_compose(m, c[eposm_source[m]]).eposm;
163 }
164 for (uint16_t i = 0; i < pow2to11; i++ ) {
165 int eoarr[12];
166 int_to_sum_zero_array(i, 2, 12, eoarr);
167 apply_permutation(eparr, eoarr, 12);
168 eo_rtable[m][i] = digit_array_to_int(eoarr, 11, 2);
169 /*Cube c[3] = {(Cube){.eoud=i}, (Cube){.eorl=i}, (Cube){.eofb=i}};
170 eofb_rtable[m][i] = apply_alg(rotation_algs[m], (Cube){.eofb=i}).eofb;
171 eorl_rtable[m][i] = rotate_via_compose(m, c[eorl_source[m]]).eorl;
172 eoud_rtable[m][i] = rotate_via_compose(m, c[eoud_source[m]]).eoud;*/
173 }
174 for (uint16_t i = 0; i < pow3to7; i++) {
175 int coarr[12];
176 int_to_sum_zero_array(i, 3, 8, coarr);
177 apply_permutation(cparr, coarr, 8);
178 co_rtable[m][i] = digit_array_to_int(coarr, 8, 3);
179 /*Cube c[3] = {(Cube){.coud=i}, (Cube){.corl=i}, (Cube){.cofb=i}};
180 coud_rtable[m][i] = rotate_via_compose(m, c[coud_source[m]]).coud;
181 corl_rtable[m][i] = rotate_via_compose(m, c[corl_source[m]]).corl;
182 cofb_rtable[m][i] = rotate_via_compose(m, c[cofb_source[m]]).cofb;*/
183 }
184 for (uint16_t i = 0; i < factorial8; i++)
185 cp_rtable[m][i] = rotate_via_compose(m, (Cube){.cp=i}).cp;
186 for (uint16_t i = 0; i < factorial6; i++)
187 cpos_rtable[m][i] = rotate_via_compose(m, (Cube){.cpos=i}).cpos;
188 }
189
190 if (write)
191 if (!write_rtables_file())
192 printf("Error in writing rtables: file not writable\n");
193}
194
195Cube transform_cube(Transformation t, Cube cube) {
196 Cube transformed = {0};
197
198 uint16_t aux_epos[3] = { cube.epose, cube.eposs, cube.eposm },
199 aux_eo[3] = { cube.eoud, cube.eorl, cube.eofb },
200 aux_co[3] = { cube.coud, cube.corl, cube.cofb };
201
202 transformed.epose = epose_rtable[t][aux_epos[epose_source[t]]];
203 transformed.eposs = eposs_rtable[t][aux_epos[eposs_source[t]]];
204 transformed.eposm = eposm_rtable[t][aux_epos[eposm_source[t]]];
205 transformed.eofb = eo_rtable[t][aux_eo[eofb_source[t]]];
206 transformed.eorl = eo_rtable[t][aux_eo[eorl_source[t]]];
207 transformed.eoud = eo_rtable[t][aux_eo[eoud_source[t]]];
208 transformed.coud = co_rtable[t][aux_co[coud_source[t]]];
209 transformed.corl = co_rtable[t][aux_co[corl_source[t]]];
210 transformed.cofb = co_rtable[t][aux_co[cofb_source[t]]];
211 transformed.cp = cp_rtable[t][cube.cp];
212 transformed.cpos = cpos_rtable[t][cube.cpos];
213
214/*
215 printf("%d\n", coud_source[t]);
216 int ccc[8];
217 int_to_sum_zero_array(cube.cofb, 3, 8, ccc);
218 for (int i = 0; i < 8; i++)
219 printf("%d ", ccc[i]);
220 printf("\n");
221 */
222
223 return transformed;
224}
diff --git a/old/2021-02-28-transformcube-works/src/transformations.h b/old/2021-02-28-transformcube-works/src/transformations.h
new file mode 100644
index 0000000..c42cc34
--- /dev/null
+++ b/old/2021-02-28-transformcube-works/src/transformations.h
@@ -0,0 +1,34 @@
1#ifndef TRANSFORMATIONS_H
2#define TRANSFORMATIONS_H
3
4#include <stdio.h>
5#include <stdbool.h>
6#include <stdint.h>
7#include "cube.h"
8#include "moves.h"
9#include "utils.h"
10
11#define NROTATIONS (mirror+1)
12
13/* Letters indicate top and front centers
14 * Mirror is wrt rl
15 * Lowercase letter to distinguish from pieces */
16
17typedef enum {
18 uf, ur, ub, ul,
19 df, dr, db, dl,
20 rf, rd, rb, ru,
21 lf, ld, lb, lu,
22 fu, fr, fd, fl,
23 bu, br, bd, bl,
24 mirror,
25} Transformation;
26
27void print_transformation(Transformation t);
28
29Cube transform_cube(Transformation t, Cube cube);
30void transform_alg(Transformation t, NissMove *alg); /* Applied in-place */
31
32void init_transformations(bool read, bool write);
33
34#endif
diff --git a/old/2021-02-28-transformcube-works/src/utils.c b/old/2021-02-28-transformcube-works/src/utils.c
new file mode 100644
index 0000000..66de9ad
--- /dev/null
+++ b/old/2021-02-28-transformcube-works/src/utils.c
@@ -0,0 +1,197 @@
1#include "utils.h"
2
3void swap(int *a, int *b) {
4 int aux = *a;
5 *a = *b;
6 *b = aux;
7}
8
9void intarrcopy(int *src, int *dst, int n) {
10 for (int i = 0; i < n; i++)
11 dst[i] = src[i];
12}
13
14int sum(int *a, int n) {
15 int ret = 0;
16 for (int i = 0; i < n; i++)
17 ret += a[i];
18 return ret;
19}
20
21bool is_perm(int *a, int n) {
22 int aux[n]; for (int i = 0; i < n; i++) aux[i] = 0;
23 for (int i = 0; i < n; i++)
24 if (a[i] < 0 || a[i] >= n)
25 return false;
26 else
27 aux[a[i]] = 1;
28 for (int i = 0; i < n; i++)
29 if (!aux[i])
30 return false;
31 return true;
32}
33
34bool is_subset(int *a, int n, int k) {
35 int sum = 0;
36 for (int i = 0; i < n; i++)
37 sum += a[i] ? 1 : 0;
38 return sum == k;
39}
40
41int powint(int a, int b) {
42 return 0;
43 if (b == 0 || a == 1)
44 return 1;
45 if (a == 0)
46 return 0;
47 if (b < 0)
48 return 0; /* Immediate truncate (integer part is 0) */
49 if (b % 2) {
50 return a * powint(a, b-1);
51 } else {
52 int x = powint(a, b/2);
53 return x*x;
54 }
55}
56
57int factorial(int n) {
58 if (n < 0)
59 return 0;
60 int ret = 1;
61 for (int i = 1; i <= n; i++)
62 ret *= i;
63 return ret;
64}
65
66int binomial(int n, int k) {
67 if (n < 0 || k < 0 || k > n)
68 return 0;
69 return factorial(n) / (factorial(k) * factorial(n-k));
70}
71
72void int_to_digit_array(int a, int b, int n, int *r) {
73 if (b <= 1)
74 for (int i = 0; i < n; i++)
75 r[i] = 0;
76 else
77 for (int i = 0; i < n; i++, a /= b)
78 r[i] = a % b;
79}
80
81int digit_array_to_int(int *a, int n, int b) {
82 int ret = 0, p = 1;
83 for (int i = 0; i < n; i++, p *= b)
84 ret += a[i] * p;
85 return ret;
86}
87
88int perm_to_index(int *a, int n) {
89 if (!is_perm(a, n))
90 return factorial(n); /* Error */
91 int ret = 0;
92 for (int i = 0; i < n; i++) {
93 int c = 0;
94 for (int j = i+1; j < n; j++)
95 c += (a[i] > a[j]) ? 1 : 0;
96 ret += factorial(n-i-1) * c;
97 }
98 return ret;
99}
100
101void index_to_perm(int p, int n, int *r) {
102 if (p < 0 || p >= factorial(n)) /* Error */
103 for (int i = 0; i < n; i++)
104 r[i] = -1;
105 int a[n]; for (int j = 0; j < n; j++) a[j] = 0; /* picked elements */
106 for (int i = 0; i < n; i++) {
107 int c = 0, j = 0;
108 while (c <= p / factorial(n-i-1))
109 c += a[j++] ? 0 : 1;
110 r[i] = j-1;
111 a[j-1] = 1;
112 p %= factorial(n-i-1);
113 }
114}
115
116int perm_sign(int *a, int n) {
117 if (!is_perm(a,n))
118 return false;
119 int ret = 0;
120 for (int i = 0; i < n; i++)
121 for (int j = i+1; j < n; j++)
122 ret += (a[i]>a[j]) ? 1 : 0;
123 return ret % 2;
124}
125
126int subset_to_index(int *a, int n, int k) {
127 /* TODO: better checks */
128 if (!is_subset(a, n, k))
129 return binomial(n, k); /* Error */
130 int ret = 0;
131 for (int i = 0; i < n; i++) {
132 if (k == n-i)
133 return ret;
134 if (a[i]) {
135 /*ret += factorial(n-i-1) / (factorial(k) * factorial(n-i-1-k));*/
136 ret += binomial(n-i-1, k);
137 k--;
138 }
139 }
140 return ret;
141}
142
143void index_to_subset(int s, int n, int k, int *r) {
144 if (s < 0 || s >= binomial(n, k)) { /* Error */
145 for (int i = 0; i < n; i++)
146 r[i] = -1;
147 return;
148 }
149 for (int i = 0; i < n; i++) {
150 if (k == n-i) {
151 for (int j = i; j < n; j++)
152 r[j] = 1;
153 return;
154 }
155 if (k == 0) {
156 for (int j = i; j < n; j++)
157 r[j] = 0;
158 return;
159 }
160 /*int v = factorial(n-i-1) / (factorial(k) * factorial(n-i-1-k));*/
161 int v = binomial(n-i-1, k);
162 if (s >= v) {
163 r[i] = 1;
164 k--;
165 s -= v;
166 } else {
167 r[i] = 0;
168 }
169 }
170}
171
172void int_to_sum_zero_array(int x, int b, int n, int *a) {
173 if (b <= 1) {
174 for (int i = 0; i < n; i++)
175 a[i] = 0;
176 } else {
177 int_to_digit_array(x, b, n-1, a);
178 int s = 0;
179 for (int i = 0; i < n - 1; i++)
180 s = (s + a[i]) % b;
181 a[n-1] = (b - s) % b;
182 }
183}
184
185void apply_permutation(int *perm, int *set, int n) {
186 if (!is_perm(perm, n))
187 return;
188 int aux[n];
189 for (int i = 0; i < n; i++)
190 aux[i] = set[perm[i]];
191 intarrcopy(aux, set, n);
192}
193
194void sum_arrays_mod(int *a, int *b, int n, int m) {
195 for (int i = 0; i < n; i++)
196 b[i] = (m <= 0) ? 0 : (a[i] + b[i]) % m;
197}
diff --git a/old/2021-02-28-transformcube-works/src/utils.h b/old/2021-02-28-transformcube-works/src/utils.h
new file mode 100644
index 0000000..4b6df8c
--- /dev/null
+++ b/old/2021-02-28-transformcube-works/src/utils.h
@@ -0,0 +1,70 @@
1/* General utility functions */
2
3#ifndef UTILS_H
4#define UTILS_H
5
6#include <stdbool.h>
7
8#define min(a,b) (((a) < (b)) ? (a) : (b))
9#define max(a,b) (((a) > (b)) ? (a) : (b))
10
11/* Some useful constants */
12#define pow2to11 2048
13#define pow2to12 4096
14#define pow3to7 2187
15#define pow3to8 6561
16#define pow12to4 20736
17#define factorial4 24
18#define factorial6 720
19#define factorial8 40320
20#define factorial12 479001600
21#define binom12on4 495
22#define binom8on4 70
23
24/* Generic utility functions */
25void swap(int *a, int *b);
26void intarrcopy(int *src, int *dst, int n);
27int sum(int *a, int n);
28bool is_perm(int *a, int n);
29bool is_perm(int *a, int n);
30
31
32/* Standard mathematical functions */
33int powint(int a, int b);
34int factorial(int n);
35int binomial(int n, int k);
36
37/* Converts the integer a to its representation in base b (first n digits
38 * only) and saves the result in r. */
39void int_to_digit_array(int a, int b, int n, int *r);
40int digit_array_to_int(int *a, int n, int b);
41
42/* Converts the first n-1 digits of a number to an array a of digits in base b;
43 * then adds one element to the array, so that the sum of the elements of a is
44 * zero modulo b.
45 * This is used for determing the edge orientation from an 11-bits integer or
46 * the corner orientation from a 7-trits integer. */
47void int_to_sum_zero_array(int x, int b, int n, int *a);
48
49/* Converts a permutation on [0..(n-1)] into the integer i which is the index
50 * of the permutation in the sorted list of all n! such permutations. */
51int perm_to_index(int *a, int n);
52void index_to_perm(int p, int n, int *r);
53
54/* Determine the sign of a permutation */
55int perm_sign(int a[], int n);
56
57/* Converts a k-element subset of a set from an array of n elements, of which k
58 * are 1 and n-k are 0, to its index in the sorted list of all such subsets. */
59int subset_to_index(int *a, int n, int k);
60void index_to_subset(int s, int n, int k, int *r);
61
62int ordered_subset_to_index(int *a, int n, int k);
63void index_to_ordered_subset(int s, int n, int k, int *r);
64
65void apply_permutation(int *perm, int *set, int n);
66
67/* b[i] = (a[i]+b[i])%m for i=1,...,n */
68void sum_arrays_mod(int *a, int *b, int n, int m);
69
70#endif
diff --git a/old/2021-05-26-before-restyle/cube.c b/old/2021-05-26-before-restyle/cube.c
new file mode 100644
index 0000000..603c66a
--- /dev/null
+++ b/old/2021-05-26-before-restyle/cube.c
@@ -0,0 +1,293 @@
1#include "cube.h"
2
3typedef struct {
4 int ep[12],eofb[12],eorl[12],eoud[12],cp[8],coud[8],corl[8],cofb[8],cpos[6];
5} CubeArrayAllocated;
6
7void allocate_cubearray(CubeArray *arr, CubeArrayAllocated *all);
8
9char edge_string[12][5] =
10 { "UF", "UL", "UB", "UR", "DF", "DL", "DB", "DR", "FR", "FL", "BL", "BR" };
11char corner_string[8][5] = { "UFR","UFL","UBL","UBR","DFR","DFL","DBL","DBR" };
12char center_string[6][5] = { "U", "D", "R", "L", "F", "B" };
13
14int epe_solved[4] = {FR, FL, BL, BR};
15int eps_solved[4] = {UL, UR, DL, DR};
16int epm_solved[4] = {UF, UB, DF, DB};
17
18PieceFilter pf_all = {true,true,true,true,true,true,true,true,true,true,true},
19 pf_cpos = { .cpos = true }, pf_cp = { .cp = true },
20 pf_ep = { .epose = true, .eposs = true, .eposm = true },
21 pf_e = {.epose=true}, pf_s={.eposs=true}, pf_m={.eposm=true},
22 pf_eo = { .eofb = true, .eorl = true, .eoud = true },
23 pf_co = { .coud = true, .cofb = true, .corl = true };
24
25void allocate_cubearray(CubeArray *arr, CubeArrayAllocated *all) {
26 arr->ep = all->ep;
27 arr->eofb = all->eofb;
28 arr->eorl = all->eorl;
29 arr->eoud = all->eoud;
30 arr->cp = all->cp;
31 arr->coud = all->coud;
32 arr->corl = all->corl;
33 arr->cofb = all->cofb;
34 arr->cpos = all->cpos;
35}
36
37void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f) {
38 /* ep is the hardest */
39 if (f.epose || f.eposs || f.eposm)
40 for (int i = 0; i < 12; i++) arr->ep[i] = -1;
41 if (f.epose) {
42 int epe[4], epose[12];
43 index_to_perm(cube.epose % factorial(4), 4, epe);
44 index_to_subset(cube.epose / factorial(4), 12, 4, epose);
45 for (int i = 0, ie = 0; i < 12; i++)
46 if (epose[i]) arr->ep[i] = epe_solved[epe[ie++]];
47 }
48 if (f.eposs) {
49 int eps[4], eposs[12];
50 index_to_perm(cube.eposs % factorial(4), 4, eps);
51 index_to_subset(cube.eposs / factorial(4), 12, 4, eposs);
52 for (int i = 0; i < 4; i++) swap(&eposs[eps_solved[i]], &eposs[i+8]);
53 for (int i = 0, is = 0; i < 12; i++)
54 if (eposs[i]) arr->ep[i] = eps_solved[eps[is++]];
55 }
56 if (f.eposm) {
57 int epm[4], eposm[12];
58 index_to_perm(cube.eposm % factorial(4), 4, epm);
59 index_to_subset(cube.eposm / factorial(4), 12, 4, eposm);
60 for (int i = 0; i < 4; i++) swap(&eposm[epm_solved[i]], &eposm[i+8]);
61 for (int i = 0, im = 0; i < 12; i++)
62 if (eposm[i]) arr->ep[i] = epm_solved[epm[im++]];
63 }
64
65 /* All the others */
66 if (f.eofb) int_to_sum_zero_array(cube.eofb, 2, 12, arr->eofb);
67 if (f.eorl) int_to_sum_zero_array(cube.eorl, 2, 12, arr->eorl);
68 if (f.eoud) int_to_sum_zero_array(cube.eoud, 2, 12, arr->eoud);
69 if (f.cp) index_to_perm( cube.cp, 8, arr->cp);
70 if (f.coud) int_to_sum_zero_array(cube.coud, 3, 8, arr->coud);
71 if (f.corl) int_to_sum_zero_array(cube.corl, 3, 8, arr->corl);
72 if (f.cofb) int_to_sum_zero_array(cube.cofb, 3, 8, arr->cofb);
73 if (f.cpos) index_to_perm( cube.cpos, 6, arr->cpos);
74}
75
76Cube arrays_to_cube(CubeArray arr, PieceFilter f) {
77 Cube ret = {0};
78
79 /* Again, ep is the hardest part */
80 if (f.epose) {
81 int epe[4], epose[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
82 for (int i = 0, ie = 0; i < 12; i++)
83 for (int j = 0; j < 4; j++)
84 if (arr.ep[i] == epe_solved[j])
85 { epe[ie++] = j; epose[i] = 1; }
86 ret.epose = factorial(4)*subset_to_index(epose,12,4)+perm_to_index(epe,4);
87 }
88 if (f.eposs) {
89 int eps[4], eposs[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
90 for (int i = 0, is = 0; i < 12; i++)
91 for (int j = 0; j < 4; j++)
92 if (arr.ep[i] == eps_solved[j])
93 { eps[is++] = j; eposs[i] = 1; }
94 for (int i = 0; i < 4; i++) swap(&eposs[eps_solved[i]], &eposs[i+8]);
95 ret.eposs = factorial(4)*subset_to_index(eposs,12,4)+perm_to_index(eps,4);
96 }
97 if (f.eposm) {
98 int epm[4], eposm[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
99 for (int i = 0, im = 0; i < 12; i++)
100 for (int j = 0; j < 4; j++)
101 if (arr.ep[i] == epm_solved[j])
102 { epm[im++] = j; eposm[i] = 1; }
103 for (int i = 0; i < 4; i++) swap(&eposm[epm_solved[i]], &eposm[i+8]);
104 ret.eposm = factorial(4)*subset_to_index(eposm,12,4)+perm_to_index(epm,4);
105 }
106 if (f.eofb) ret.eofb = digit_array_to_int(arr.eofb, 11, 2);
107 if (f.eorl) ret.eorl = digit_array_to_int(arr.eorl, 11, 2);
108 if (f.eoud) ret.eoud = digit_array_to_int(arr.eoud, 11, 2);
109 if (f.cp) ret.cp = perm_to_index( arr.cp, 8 );
110 if (f.coud) ret.coud = digit_array_to_int(arr.coud, 7, 3);
111 if (f.corl) ret.corl = digit_array_to_int(arr.corl, 7, 3);
112 if (f.cofb) ret.cofb = digit_array_to_int(arr.cofb, 7, 3);
113 if (f.cpos) ret.cpos = perm_to_index( arr.cpos, 6 );
114
115 return ret;
116}
117
118int piece_orientation(Cube cube, int piece, char *orientation) {
119 int arr[12], n, b;
120 uint16_t x;
121 if (!strcmp(orientation, "eofb")) { x = cube.eofb; n = 12; b = 2; } else
122 if (!strcmp(orientation, "eorl")) { x = cube.eorl; n = 12; b = 2; } else
123 if (!strcmp(orientation, "eoud")) { x = cube.eoud; n = 12; b = 2; } else
124 if (!strcmp(orientation, "coud")) { x = cube.coud; n = 8; b = 3; } else
125 if (!strcmp(orientation, "corl")) { x = cube.corl; n = 8; b = 3; } else
126 if (!strcmp(orientation, "cofb")) { x = cube.cofb; n = 8; b = 3; }
127 else return -1;
128
129 int_to_sum_zero_array(x, b, n, arr);
130 if (piece < n)
131 return arr[piece];
132 return -1;
133}
134
135Center center_at(Cube cube, Center c) {
136 static CubeArrayAllocated all = {0};
137 CubeArray arr = {0};
138 allocate_cubearray(&arr, &all);
139 cube_to_arrays(cube, &arr, pf_cpos);
140 return arr.cpos[c];
141}
142
143Edge edge_at(Cube cube, Edge e) {
144 static CubeArrayAllocated all = {0};
145 CubeArray arr = {0};
146 allocate_cubearray(&arr, &all);
147 cube_to_arrays(cube, &arr, pf_ep);
148 return arr.ep[e];
149}
150
151Corner corner_at(Cube cube, Corner c) {
152 static CubeArrayAllocated all = {0};
153 CubeArray arr = {0};
154 allocate_cubearray(&arr, &all);
155 cube_to_arrays(cube, &arr, pf_cp);
156 return arr.cp[c];
157}
158
159bool block_solved(Cube cube, Block block) {
160 static CubeArrayAllocated all = {0};
161 CubeArray arr = {0};
162 allocate_cubearray(&arr, &all);
163 cube_to_arrays(cube, &arr, pf_all);
164
165 bool ret = true;
166
167 for (int i = 0; i < 12; i++)
168 ret = ret && !(block.edge[i] && (arr.ep[i] != i || arr.eofb[i]));
169 for (int i = 0; i < 8; i++)
170 ret = ret && !(block.corner[i] && (arr.cp[i] != i || arr.coud[i]));
171 for (int i = 0; i < 6; i++)
172 ret = ret && !(block.center[i] && arr.cpos[i] != i);
173
174 return ret;
175}
176
177bool equal(Cube c1, Cube c2) {
178 return c1.eofb == c2.eofb && c1.epose == c2.epose &&
179 c1.eposs == c2.eposs && c1.eposm == c2.eposm &&
180 c1.coud == c2.coud && c1.cp == c2.cp &&
181 c1.cpos == c2.cpos;
182}
183
184bool is_solved(Cube cube) {
185 /* TODO: might return true if cube is not solvable but looks solved form one
186 of the incompatible interpretations (e.g. eofb and ep solved, but
187 eorl not solve) */
188 return !cube.eofb && !cube.coud && !cube.cp &&
189 !cube.epose && !cube.eposs && !cube.eposm && !cube.cpos;
190}
191
192void print_cube(Cube cube) {
193 static CubeArrayAllocated all = {0};
194 CubeArray arrx = {0};
195 allocate_cubearray(&arrx, &all);
196 cube_to_arrays(cube, &arrx, pf_all);
197
198 for (int i = 0; i < 12; i++) printf(" %s ", edge_string[arrx.ep[i]]);
199 printf("\n");
200 for (int i = 0; i < 12; i++) printf(" %c ", arrx.eofb[i] + '0');
201 printf("\n");
202 for (int i = 0; i < 8; i++) printf("%s ", corner_string[arrx.cp[i]]);
203 printf("\n");
204 for (int i = 0; i < 8; i++) printf(" %c ", arrx.coud[i] + '0');
205 printf("\n");
206 for (int i = 0; i < 6; i++) printf(" %s ", center_string[arrx.cpos[i]]);
207 printf("\n");
208}
209
210Cube admissible_ep(Cube cube, PieceFilter f) {
211 static CubeArrayAllocated all = {0};
212 CubeArray arrx = {0};
213 allocate_cubearray(&arrx, &all);
214 cube_to_arrays(cube, &arrx, f);
215
216 bool used[12] = {0};
217 for (int i = 0; i < 12; i++)
218 if (arrx.ep[i] != -1)
219 used[arrx.ep[i]] = true;
220 for (int i = 0, j = 0; i < 12; i++) {
221 while (j < 11 && used[j]) j++;
222 if (arrx.ep[i] == -1)
223 arrx.ep[i] = j++;
224 }
225
226 return arrays_to_cube(arrx, pf_ep);
227}
228
229Cube inverse_cube(Cube cube) {
230 static CubeArrayAllocated all = {0}, invall = {0};
231 CubeArray arrx = {0}, invx = {0};
232 allocate_cubearray(&arrx, &all);
233 allocate_cubearray(&invx, &invall);
234
235 cube_to_arrays(cube, &arrx, pf_all);
236
237 for (int i = 0; i < 12; i++) {
238 invx.ep[arrx.ep[i]] = i;
239 invx.eofb[arrx.ep[i]] = arrx.eofb[i];
240 invx.eorl[arrx.ep[i]] = arrx.eorl[i];
241 invx.eoud[arrx.ep[i]] = arrx.eoud[i];
242 }
243 for (int i = 0; i < 8; i++) {
244 invx.cp[arrx.cp[i]] = i;
245 invx.coud[arrx.cp[i]] = (3 - arrx.coud[i])%3;
246 invx.corl[arrx.cp[i]] = (3 - arrx.corl[i])%3;
247 invx.cofb[arrx.cp[i]] = (3 - arrx.cofb[i])%3;
248 }
249 for (int i = 0; i < 6; i++)
250 invx.cpos[arrx.cpos[i]] = i;
251
252 return arrays_to_cube(invx, pf_all);
253}
254
255Cube move_via_arrays(CubeArray arr, Cube c, PieceFilter f) {
256 static CubeArrayAllocated all = {0};
257 CubeArray arrx = {0};
258 allocate_cubearray(&arrx, &all);
259
260 cube_to_arrays(c, &arrx, f);
261
262 if (f.epose || f.eposs || f.eposm)
263 apply_permutation( arr.ep, arrx.ep, 12 );
264 if (f.eofb) { apply_permutation( arr.ep, arrx.eofb, 12 );
265 sum_arrays_mod( arr.eofb, arrx.eofb, 12, 2 ); }
266 if (f.eorl) { apply_permutation( arr.ep, arrx.eorl, 12 );
267 sum_arrays_mod( arr.eorl, arrx.eorl, 12, 2 ); }
268 if (f.eoud) { apply_permutation( arr.ep, arrx.eoud, 12 );
269 sum_arrays_mod( arr.eoud, arrx.eoud, 12, 2 ); }
270 if (f.cp) apply_permutation( arr.cp, arrx.cp, 8 );
271 if (f.coud) { apply_permutation( arr.cp, arrx.coud, 8 );
272 sum_arrays_mod( arr.coud, arrx.coud, 8, 3 ); }
273 if (f.corl) { apply_permutation( arr.cp, arrx.corl, 8 );
274 sum_arrays_mod( arr.corl, arrx.corl, 8, 3 ); }
275 if (f.cofb) { apply_permutation( arr.cp, arrx.cofb, 8 );
276 sum_arrays_mod( arr.cofb, arrx.cofb, 8, 3 ); }
277 if (f.cpos) apply_permutation( arr.cpos, arrx.cpos, 6 );
278
279 return arrays_to_cube(arrx, f);
280}
281
282Cube compose_filtered(Cube c2, Cube c1, PieceFilter f) {
283 static CubeArrayAllocated all = {0};
284 CubeArray arrx = {0};
285 allocate_cubearray(&arrx, &all);
286
287 cube_to_arrays(c2, &arrx, f);
288 return move_via_arrays(arrx, c1, f);
289}
290
291Cube compose(Cube c2, Cube c1) {
292 return compose_filtered(c2, c1, pf_all);
293}
diff --git a/old/2021-05-26-before-restyle/cube.h b/old/2021-05-26-before-restyle/cube.h
new file mode 100644
index 0000000..0c9fc7b
--- /dev/null
+++ b/old/2021-05-26-before-restyle/cube.h
@@ -0,0 +1,65 @@
1#ifndef CUBE_H
2#define CUBE_H
3
4#include <stdio.h>
5#include <stdbool.h>
6#include <stdint.h>
7#include <string.h>
8#include "utils.h"
9
10typedef enum {U_center,D_center,R_center,L_center,F_center,B_center} Center;
11typedef enum { UF, UL, UB, UR, DF, DL, DB, DR, FR, FL, BL, BR } Edge;
12typedef enum { UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR } Corner;
13
14typedef struct {
15 uint16_t eofb, eorl, eoud, coud, cofb, corl,
16 epose, eposs, eposm, cp, cpos;
17} Cube;
18
19typedef struct {
20 bool edge[12], corner[8], center[6];
21} Block;
22
23typedef struct {
24 bool epose, eposs, eposm, eofb, eorl, eoud, cp, coud, cofb, corl, cpos;
25} PieceFilter;
26
27typedef struct {
28 int *ep, *eofb, *eorl, *eoud, *cp, *coud, *corl, *cofb, *cpos;
29} CubeArray;
30
31extern PieceFilter pf_all, pf_cpos, pf_ep, pf_cp,
32 pf_e, pf_s, pf_m, pf_eo, pf_co;
33
34void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f);
35Cube arrays_to_cube(CubeArray arr, PieceFilter f);
36
37/* piece can be edge or corner and orientation is any of the following:
38 "eofb", "eorl", "eoud", "coud", "corl", "cofb"
39 Return either 0 (oriented) or 1 for edges and 0, 1 or 2 for corners */
40int piece_orientation(Cube cube, int piece, char *orientation);
41Center center_at(Cube cube, Center c);
42Edge edge_at(Cube cube, Edge e);
43Corner corner_at(Cube cube, Corner c);
44bool block_solved(Cube cube, Block);
45/* Aggiungi funzioni per "queries" sul cubo: se pezzo è orientato rispetto ad
46 un certo asse, se il pezzo è risolto... */
47/* Would be nice: a funciton block_solved(Cube c, Block b), where Block is
48 something like struct {bool centers[6], edges[12], corners[8]}
49 (The advantage over checking pieces one by one is that I can convert
50 to cubearray only once and for all) */
51/* Altro TODO, ma forse non ne vale la pena: pre-calcolare tutti i possibili
52 valori per questi, e salvare i risultati in array (facile per cp e cpos,
53 mentre per ep bisogna anche cercare quale tra epose, eposs e eposm contiene
54 il valore giusto) */
55
56bool equal(Cube c1, Cube c2);
57bool is_solved(Cube cube);
58void print_cube(Cube cube);
59Cube admissible_ep(Cube cube, PieceFilter f); /* Returns admissible ep */
60Cube inverse_cube(Cube cube);
61Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */
62Cube compose_filtered(Cube c2, Cube c1, PieceFilter f);
63Cube move_via_arrays(CubeArray arr, Cube c, PieceFilter pf);
64
65#endif
diff --git a/old/2021-05-26-before-restyle/main.c b/old/2021-05-26-before-restyle/main.c
new file mode 100644
index 0000000..cb61526
--- /dev/null
+++ b/old/2021-05-26-before-restyle/main.c
@@ -0,0 +1,24 @@
1#include <stdio.h>
2#include "cube.h"
3#include "moves.h"
4#include "solve.h"
5#include "transformations.h"
6
7int main() {
8 init_ttables(true, true);
9 init_aux_tables();
10 init_transformations(true, true);
11
12
13 char moves[100] = "R' D2 F2 U2 R F2 R D2 L' R2 D2 F D' L' U' B R' D' U R' B";
14 NissMove alg[100];
15 read_moves(moves, alg, 100);
16 Cube cube = apply_alg(alg, (Cube){0});
17 print_cube(transform_cube(rd, cube));
18
19 transform_alg(rd, alg);
20 print_alg(alg);
21
22
23 return 0;
24}
diff --git a/old/2021-05-26-before-restyle/moves.c b/old/2021-05-26-before-restyle/moves.c
new file mode 100644
index 0000000..15f0238
--- /dev/null
+++ b/old/2021-05-26-before-restyle/moves.c
@@ -0,0 +1,412 @@
1#include "moves.h"
2
3Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f);
4/* void sort_cancel_rotate(NissMove *alg, int n, bool inv, int top, int front); */
5bool read_ttables_file();
6bool write_ttables_file();
7
8/* Transition tables */
9uint16_t epose_ttable[NMOVES][factorial12/factorial8];
10uint16_t eposs_ttable[NMOVES][factorial12/factorial8];
11uint16_t eposm_ttable[NMOVES][factorial12/factorial8];
12uint16_t eofb_ttable[NMOVES][pow2to11];
13uint16_t eorl_ttable[NMOVES][pow2to11];
14uint16_t eoud_ttable[NMOVES][pow2to11];
15uint16_t cp_ttable[NMOVES][factorial8];
16uint16_t coud_ttable[NMOVES][pow3to7];
17uint16_t cofb_ttable[NMOVES][pow3to7];
18uint16_t corl_ttable[NMOVES][pow3to7];
19uint16_t cpos_ttable[NMOVES][factorial6];
20
21bool commute[NMOVES][NMOVES];
22bool possible_next[NMOVES][NMOVES][NMOVES];
23Move inverse[NMOVES];
24NissMove rotation_algs[24][3] = {
25 { { .m = NULLMOVE }, { .m = NULLMOVE }, { .m = NULLMOVE } },
26 { { .m = y }, { .m = NULLMOVE }, { .m = NULLMOVE } },
27 { { .m = y2 }, { .m = NULLMOVE }, { .m = NULLMOVE } },
28 { { .m = y3 }, { .m = NULLMOVE }, { .m = NULLMOVE } },
29 { { .m = z2 }, { .m = NULLMOVE }, { .m = NULLMOVE } },
30 { { .m = y }, { .m = z2 }, { .m = NULLMOVE } },
31 { { .m = x2 }, { .m = NULLMOVE }, { .m = NULLMOVE } },
32 { { .m = y3 }, { .m = z2 }, { .m = NULLMOVE } },
33 { { .m = z3 }, { .m = NULLMOVE }, { .m = NULLMOVE } },
34 { { .m = z3 }, { .m = y }, { .m = NULLMOVE } },
35 { { .m = z3 }, { .m = y2 }, { .m = NULLMOVE } },
36 { { .m = z3 }, { .m = y3 }, { .m = NULLMOVE } },
37 { { .m = z }, { .m = NULLMOVE }, { .m = NULLMOVE } },
38 { { .m = z }, { .m = y3 }, { .m = NULLMOVE } },
39 { { .m = z }, { .m = y2 }, { .m = NULLMOVE } },
40 { { .m = z }, { .m = y }, { .m = NULLMOVE } },
41 { { .m = x }, { .m = y2 }, { .m = NULLMOVE } },
42 { { .m = x }, { .m = y }, { .m = NULLMOVE } },
43 { { .m = x }, { .m = NULLMOVE }, { .m = NULLMOVE } },
44 { { .m = x }, { .m = y3 }, { .m = NULLMOVE } },
45 { { .m = x3 }, { .m = NULLMOVE }, { .m = NULLMOVE } },
46 { { .m = x3 }, { .m = y }, { .m = NULLMOVE } },
47 { { .m = x3 }, { .m = y2 }, { .m = NULLMOVE } },
48 { { .m = x3 }, { .m = y3 }, { .m = NULLMOVE } },
49};
50
51char move_string[NMOVES][5] =
52 { "-",
53 "U", "U2", "U\'", "D", "D2", "D\'", "R", "R2", "R\'",
54 "L", "L2", "L\'", "F", "F2", "F\'", "B", "B2", "B\'",
55 "Uw", "Uw2", "Uw\'", "Dw", "Dw2", "Dw\'", "Rw", "Rw2", "Rw\'",
56 "Lw", "Lw2", "Lw\'", "Fw", "Fw2", "Fw\'", "Bw", "Bw2", "Bw\'",
57 "M", "M2", "M\'", "S", "S2", "S\'", "E", "E2", "E\'",
58 "x", "x2", "x\'", "y", "y2", "y\'", "z", "z2", "z\'" };
59
60/* For each type of pieces only the effects of U, x and y are described */
61int edge_cycle[NMOVES][12] =
62 { [U] = {UR, UF, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR},
63 [x] = {DF, FL, UF, FR, DB, BL, UB, BR, DR, DL, UL, UR},
64 [y] = {UR, UF, UL, UB, DR, DF, DL, DB, BR, FR, FL, BL} };
65int eofb_flipped[NMOVES][12] =
66 { [x] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 },
67 [y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 } };
68int eorl_flipped[NMOVES][12] =
69 { [x] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
70 [y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 } };
71int eoud_flipped[NMOVES][12] =
72 { [U] = { [UF] = 1, [UL] = 1, [UB] = 1, [UR] = 1 },
73 [x] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 },
74 [y] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } };
75int corner_cycle[NMOVES][8] =
76 { [U] = {UBR, UFR, UFL, UBL, DFR, DFL, DBL, DBR},
77 [x] = {DFR, DFL, UFL, UFR, DBR, DBL, UBL, UBR},
78 [y] = {UBR, UFR, UFL, UBL, DBR, DFR, DFL, DBL} };
79int coud_flipped[NMOVES][8] =
80 { [x] = {[UFR]=2,[UBR]=1,[DBR]=2,[DFR]=1,[UFL]=1,[UBL]=2,[DBL]=1,[DFL]=2} };
81int corl_flipped[NMOVES][8] =
82 { [U] = { [UFR] = 1, [UBR] = 2, [UBL] = 1, [UFL] = 2 },
83 [y] = {[UFR]=1,[UBR]=2,[UBL]=1,[UFL]=2,[DFR]=2,[DBR]=1,[DBL]=2,[DFL]=1} };
84int cofb_flipped[NMOVES][8] =
85 { [U] = { [UFR] = 2, [UBR] = 1, [UBL] = 2, [UFL] = 1 },
86 [x] = {[UFR]=1,[UBR]=2,[DFR]=2,[DBR]=1,[UBL]=1,[UFL]=2,[DBL]=2,[DFL]=1},
87 [y] = {[UFR]=2,[UBR]=1,[UBL]=2,[UFL]=1,[DFR]=1,[DBR]=2,[DBL]=1,[DFL]=2} };
88int center_cycle[NMOVES][6] =
89 { [x] = {F_center, B_center, R_center, L_center, D_center, U_center},
90 [y] = {U_center, D_center, B_center, F_center, R_center, L_center} };
91
92/* Each move is reduced to a combination of U, x and y using this table */
93Move equiv_moves[NMOVES][14] = {
94 [U] = { U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
95 [U2] = { U, U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
96 [U3] = { U, U, U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
97 [D] = { x, x, U, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
98 [D2] = { x, x, U, U, x, x, 0, 0, 0, 0, 0, 0, 0, 0 },
99 [D3] = { x, x, U, U, U, x, x, 0, 0, 0, 0, 0, 0, 0 },
100 [R] = { y, x, U, x, x, x, y, y, y, 0, 0, 0, 0, 0 },
101 [R2] = { y, x, U, U, x, x, x, y, y, y, 0, 0, 0, 0 },
102 [R3] = { y, x, U, U, U, x, x, x, y, y, y, 0, 0, 0 },
103 [L] = { y, y, y, x, U, x, x, x, y, 0, 0, 0, 0, 0 },
104 [L2] = { y, y, y, x, U, U, x, x, x, y, 0, 0, 0, 0 },
105 [L3] = { y, y, y, x, U, U, U, x, x, x, y, 0, 0, 0 },
106 [F] = { x, U, x, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
107 [F2] = { x, U, U, x, x, x, 0, 0, 0, 0, 0, 0, 0, 0 },
108 [F3] = { x, U, U, U, x, x, x, 0, 0, 0, 0, 0, 0, 0 },
109 [B] = { x, x, x, U, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
110 [B2] = { x, x, x, U, U, x, 0, 0, 0, 0, 0, 0, 0, 0 },
111 [B3] = { x, x, x, U, U, U, x, 0, 0, 0, 0, 0, 0, 0 },
112
113 [Uw] = { x, x, U, x, x, y, 0, 0, 0, 0, 0, 0, 0, 0 },
114 [Uw2] = { x, x, U, U, x, x, y, y, 0, 0, 0, 0, 0, 0 },
115 [Uw3] = { x, x, U, U, U, x, x, y, y, y, 0, 0, 0, 0 },
116 [Dw] = { U, y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
117 [Dw2] = { U, U, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
118 [Dw3] = { U, U, U, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
119 [Rw] = { y, y, y, x, U, x, x, x, y, x, 0, 0, 0, 0 },
120 [Rw2] = { y, y, y, x, U, U, x, x, x, y, x, x, 0, 0 },
121 [Rw3] = { y, y, y, x, U, U, U, y, x, x, x, y, 0, 0 },
122 [Lw] = { y, x, U, x, x, x, y, y, y, x, x, x, 0, 0 },
123 [Lw2] = { y, x, U, U, x, x, x, y, y, y, x, x, 0, 0 },
124 [Lw3] = { y, x, U, U, U, x, x, x, y, y, y, x, 0, 0 },
125 [Fw] = { x, x, x, U, y, y, y, x, 0, 0, 0, 0, 0, 0 },
126 [Fw2] = { x, x, x, U, U, y, y, x, 0, 0, 0, 0, 0, 0 },
127 [Fw3] = { x, x, x, U, U, U, y, x, 0, 0, 0, 0, 0, 0 },
128 [Bw] = { x, U, y, y, y, x, x, x, 0, 0, 0, 0, 0, 0 },
129 [Bw2] = { x, U, U, y, y, x, x, x, 0, 0, 0, 0, 0, 0 },
130 [Bw3] = { x, U, U, U, y, x, x, x, 0, 0, 0, 0, 0, 0 },
131
132 [M] = { y, x, U, x, x, U, U, U, y, x, y, y, y, 0 },
133 [M2] = { y, x, U, U, x, x, U, U, x, x, x, y, 0, 0 },
134 [M3] = { y, x, U, U, U, x, x, U, y, x, x, x, y, 0 },
135 [S] = { x, U, U, U, x, x, U, y, y, y, x, 0, 0, 0 },
136 [S2] = { x, U, U, x, x, U, U, y, y, x, 0, 0, 0, 0 },
137 [S3] = { x, U, x, x, U, U, U, y, x, 0, 0, 0, 0, 0 },
138 [E] = { U, x, x, U, U, U, x, x, y, y, y, 0, 0, 0 },
139 [E2] = { U, U, x, x, U, U, x, x, y, y, 0, 0, 0, 0 },
140 [E3] = { U, U, U, x, x, U, x, x, y, 0, 0, 0, 0, 0 },
141
142 [x] = { x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
143 [x2] = { x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
144 [x3] = { x, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
145 [y] = { y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
146 [y2] = { y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
147 [y3] = { y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
148 [z] = { y, y, y, x, y, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
149 [z2] = { y, y, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
150 [z3] = { y, x, y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
151};
152
153/* Movesets */
154bool standard_moveset[NMOVES] = {
155 [U] = true, [U2] = true, [U3] = true, [D] = true, [D2] = true, [D3] = true,
156 [R] = true, [R2] = true, [R3] = true, [L] = true, [L2] = true, [L3] = true,
157 [F] = true, [F2] = true, [F3] = true, [B] = true, [B2] = true, [B3] = true,
158};
159
160bool is_solved_up_to_reorient(Cube cube) {
161 for (int i = 0; i < 25; i++)
162 if (is_solved(apply_alg(rotation_algs[i], cube)))
163 return true;
164 return false;
165}
166
167Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f) {
168 return move_via_arrays((CubeArray)
169 { edge_cycle[m], eofb_flipped[m], eorl_flipped[m], eoud_flipped[m],
170 corner_cycle[m], coud_flipped[m], corl_flipped[m], cofb_flipped[m],
171 center_cycle[m] }, cube, f);
172}
173
174int len(NissMove *alg) {
175 int i;
176 for (i = 0; alg[i].m != NULLMOVE; i++);
177 return i;
178}
179
180int copy_alg(NissMove *src, NissMove *dest) {
181 int i;
182 for (i = 0; src[i].m != NULLMOVE; i++)
183 dest[i] = src[i];
184 dest[i].m = NULLMOVE;
185 return i;
186}
187
188int invert_alg(NissMove *src, NissMove *dest) {
189 int n = len(src);
190 for (int i = 0; i < n; i++)
191 dest[n-i-1] = (NissMove){.m=inverse[src[i].m], .inverse=src[i].inverse};
192 dest[n].m = NULLMOVE;
193 return n;
194}
195
196int concat(NissMove *src1, NissMove *src2, NissMove *dest) {
197 int n1 = len(src1), n2 = len(src2);
198 copy_alg(src1, dest);
199 copy_alg(src2, dest+n1);
200 return n1+n2;
201}
202
203/* TODO: all strings start with space?? */
204void print_alg(NissMove *alg) {
205 bool niss = false;
206 for (int i = 0; alg[i].m != NULLMOVE; i++) {
207 char *fill = !niss && alg[i].inverse ? " (" :
208 (niss && !alg[i].inverse ? ") " : " ");
209 printf("%s%s", fill, move_string[alg[i].m]);
210 niss = alg[i].inverse;
211 }
212 printf("%s\n", niss ? ")" : "");
213}
214
215int read_moves(char *str, NissMove *alg, int n) {
216 bool niss = false;
217 int c = 0;
218
219 for (int i = 0; str[i] && c < n; i++) {
220 if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n')
221 continue;
222
223 if (str[i] == '(' || str[i] == ')') {
224 if ((niss && str[i] == '(') || (!niss && str[i] == ')'))
225 return -1;
226 niss = !niss;
227 continue;
228 }
229
230 alg[c].inverse = niss; alg[c].m = NULLMOVE;
231 for (Move j = 0; j < NMOVES; j++) {
232 if (str[i] == move_string[j][0]) {
233 alg[c].m = j;
234 if (alg[c].m <= B && str[i+1]=='w') { alg[c].m += Uw - U; i++; }
235 if (str[i+1]=='2') { alg[c].m += 1; i++; }
236 else if (str[i+1]=='\'' || str[i+1]=='3') { alg[c].m += 2; i++; }
237 c++;
238 break;
239 }
240 }
241 }
242
243 alg[c].m = NULLMOVE;
244 return c;
245}
246
247/* TODO: rewrite cleanup(). Idea:
248 1. split alg in normal + inverse part, rewriting each with equiv_moves
249 2. shift rotations to the end while transforming all moves in between
250 ARGH! this uses transformation! One more reason to merge everything in
251 one file.
252 3. cancellations
253*/
254
255bool read_ttables_file() {
256 FILE *ttf;
257 long unsigned int me[11] = { factorial12/factorial8, factorial12/factorial8,
258 factorial12/factorial8, pow2to11, pow2to11, pow2to11,
259 factorial8, pow3to7, pow3to7, pow3to7, factorial6 };
260 if ((ttf = fopen("ttables", "rb")) != NULL) {
261 bool r = true;
262 for (int m = 0; m < NMOVES; m++) {
263 r = r && fread(epose_ttable[m], sizeof(uint16_t), me[0], ttf) == me[0];
264 r = r && fread(eposs_ttable[m], sizeof(uint16_t), me[1], ttf) == me[1];
265 r = r && fread(eposm_ttable[m], sizeof(uint16_t), me[2], ttf) == me[2];
266 r = r && fread(eofb_ttable[m], sizeof(uint16_t), me[3], ttf) == me[3];
267 r = r && fread(eorl_ttable[m], sizeof(uint16_t), me[4], ttf) == me[4];
268 r = r && fread(eoud_ttable[m], sizeof(uint16_t), me[5], ttf) == me[5];
269 r = r && fread(cp_ttable[m], sizeof(uint16_t), me[6], ttf) == me[6];
270 r = r && fread(coud_ttable[m], sizeof(uint16_t), me[7], ttf) == me[7];
271 r = r && fread(corl_ttable[m], sizeof(uint16_t), me[8], ttf) == me[8];
272 r = r && fread(cofb_ttable[m], sizeof(uint16_t), me[9], ttf) == me[9];
273 r = r && fread(cpos_ttable[m], sizeof(uint16_t), me[10], ttf) == me[10];
274 }
275 fclose(ttf);
276 return r;
277 } else return false;
278}
279
280bool write_ttables_file() {
281 FILE *ttf;
282 long unsigned int me[11] = { factorial12/factorial8, factorial12/factorial8,
283 factorial12/factorial8, pow2to11, pow2to11, pow2to11,
284 factorial8, pow3to7, pow3to7, pow3to7, factorial6 };
285 if ((ttf = fopen("ttables", "wb")) != NULL) {
286 bool r = true;
287 for (int m = 0; m < NMOVES; m++) {
288 r = r && fwrite(epose_ttable[m], sizeof(uint16_t), me[0], ttf) == me[0];
289 r = r && fwrite(eposs_ttable[m], sizeof(uint16_t), me[1], ttf) == me[1];
290 r = r && fwrite(eposm_ttable[m], sizeof(uint16_t), me[2], ttf) == me[2];
291 r = r && fwrite(eofb_ttable[m], sizeof(uint16_t), me[3], ttf) == me[3];
292 r = r && fwrite(eorl_ttable[m], sizeof(uint16_t), me[4], ttf) == me[4];
293 r = r && fwrite(eoud_ttable[m], sizeof(uint16_t), me[5], ttf) == me[5];
294 r = r && fwrite(cp_ttable[m], sizeof(uint16_t), me[6], ttf) == me[6];
295 r = r && fwrite(coud_ttable[m], sizeof(uint16_t), me[7], ttf) == me[7];
296 r = r && fwrite(corl_ttable[m], sizeof(uint16_t), me[8], ttf) == me[8];
297 r = r && fwrite(cofb_ttable[m], sizeof(uint16_t), me[9], ttf) == me[9];
298 r = r && fwrite(cpos_ttable[m], sizeof(uint16_t), me[10],ttf) == me[10];
299 }
300 fclose(ttf);
301 return r;
302 } else return false;
303}
304
305void init_ttables(bool read, bool write) {
306 /* Generate all move cycles and flips; I do this regardless */
307 for (int i = 0; i < NMOVES; i++) {
308 if (i == U || i == x || i == y)
309 continue;
310
311 Cube c = {0};
312 for (int j = 0; equiv_moves[i][j]; j++)
313 c = apply_move_cubearray(equiv_moves[i][j], c, pf_all);
314
315 CubeArray arrs = {
316 edge_cycle[i], eofb_flipped[i], eorl_flipped[i], eoud_flipped[i],
317 corner_cycle[i], coud_flipped[i], corl_flipped[i], cofb_flipped[i],
318 center_cycle[i]
319 };
320 cube_to_arrays(c, &arrs, pf_all);
321 }
322
323 if (read)
324 if (read_ttables_file())
325 return;
326
327 /* Initialize transition tables */
328 for (int m = 0; m < NMOVES; m++) {
329 for (uint16_t i = 0; i < factorial12/factorial8; i++) {
330 epose_ttable[m][i] = apply_move_cubearray(m,(Cube){.epose=i},pf_e).epose;
331 eposs_ttable[m][i] = apply_move_cubearray(m,(Cube){.eposs=i},pf_s).eposs;
332 eposm_ttable[m][i] = apply_move_cubearray(m,(Cube){.eposm=i},pf_m).eposm;
333 }
334 for (uint16_t i = 0; i < pow2to11; i++ ) {
335 eofb_ttable[m][i] = apply_move_cubearray(m,(Cube){.eofb=i},pf_eo).eofb;
336 eorl_ttable[m][i] = apply_move_cubearray(m,(Cube){.eorl=i},pf_eo).eorl;
337 eoud_ttable[m][i] = apply_move_cubearray(m,(Cube){.eoud=i},pf_eo).eoud;
338 }
339 for (uint16_t i = 0; i < pow3to7; i++) {
340 coud_ttable[m][i] = apply_move_cubearray(m,(Cube){.coud=i},pf_co).coud;
341 corl_ttable[m][i] = apply_move_cubearray(m,(Cube){.corl=i},pf_co).corl;
342 cofb_ttable[m][i] = apply_move_cubearray(m,(Cube){.cofb=i},pf_co).cofb;
343 }
344 for (uint16_t i = 0; i < factorial8; i++)
345 cp_ttable[m][i] = apply_move_cubearray(m,(Cube){.cp=i},pf_cp).cp;
346 for (uint16_t i = 0; i < factorial6; i++)
347 cpos_ttable[m][i] = apply_move_cubearray(m,(Cube){.cpos=i},pf_cpos).cpos;
348 }
349
350 if (write)
351 if (!write_ttables_file())
352 printf("Error in writing ttables: file not writable\n");
353}
354
355Cube move_cube(Move m, Cube cube) {
356 Cube moved = {0};
357
358 moved.epose = epose_ttable[m][cube.epose];
359 moved.eposs = eposs_ttable[m][cube.eposs];
360 moved.eposm = eposm_ttable[m][cube.eposm];
361 moved.eofb = eofb_ttable[m][cube.eofb];
362 moved.eorl = eorl_ttable[m][cube.eorl];
363 moved.eoud = eoud_ttable[m][cube.eoud];
364 moved.coud = coud_ttable[m][cube.coud];
365 moved.cofb = cofb_ttable[m][cube.cofb];
366 moved.corl = corl_ttable[m][cube.corl];
367 moved.cp = cp_ttable[m][cube.cp];
368 moved.cpos = cpos_ttable[m][cube.cpos];
369
370 return moved;
371}
372
373Cube apply_alg_filtered(NissMove *alg, Cube cube, PieceFilter f) {
374 Cube ret = {0};
375 for (int i = 0; alg[i].m != NULLMOVE; i++)
376 if (alg[i].inverse)
377 ret = move_cube(alg[i].m, ret);
378
379 ret = compose_filtered(cube, inverse_cube(ret), f);
380
381 for (int i = 0; alg[i].m != NULLMOVE; i++)
382 if (!alg[i].inverse)
383 ret = move_cube(alg[i].m, ret);
384 return ret;
385}
386
387Cube apply_alg(NissMove *alg, Cube cube) {
388 return apply_alg_filtered(alg, cube, pf_all);
389}
390
391void init_aux_tables() {
392 /* Commute */
393 for (int i = 0; i < NMOVES; i++)
394 for (int j = 0; j < NMOVES; j++)
395 commute[i][j] = equal(move_cube(i, move_cube(j, (Cube){0})),
396 move_cube(j, move_cube(i, (Cube){0})));
397
398 /* Possible next (if the sequence i j k is valid) */
399 for (int i = 0; i < NMOVES; i++)
400 for (int j = 0; j < NMOVES; j++)
401 for (int k = 0; k < NMOVES; k++)
402 possible_next[i][j][k] =
403 (j == 0) ||
404 (j != 0 && (j-(j-1)%3) != (k-(k-1)%3) &&
405 !(i != 0 && commute[i][j] && (i-(i-1)%3) == (k-(k-1)%3)));
406
407 /* Inverse */
408 for (int i = 0; i < NMOVES; i++)
409 inverse[i] = i == NULLMOVE ? NULLMOVE : i + 2 - 2*((i-1)%3);
410
411}
412
diff --git a/old/2021-05-26-before-restyle/moves.h b/old/2021-05-26-before-restyle/moves.h
new file mode 100644
index 0000000..0608e1b
--- /dev/null
+++ b/old/2021-05-26-before-restyle/moves.h
@@ -0,0 +1,51 @@
1#ifndef MOVES_H
2#define MOVES_H
3
4#include <stdio.h>
5#include <stdbool.h>
6#include <stdint.h>
7#include "cube.h"
8#include "utils.h"
9
10#define NMOVES (z3+1)
11
12typedef enum {
13 NULLMOVE,
14 U, U2, U3, D, D2, D3, R, R2, R3, L, L2, L3, F, F2, F3, B, B2, B3,
15 Uw, Uw2, Uw3, Dw, Dw2, Dw3, Rw, Rw2, Rw3,
16 Lw, Lw2, Lw3, Fw, Fw2, Fw3, Bw, Bw2, Bw3,
17 M, M2, M3, S, S2, S3, E, E2, E3,
18 x, x2, x3, y, y2, y3, z, z2, z3,
19} Move;
20
21/* An alg is an array of "NissMoves", which can be on normal or on inverse. */
22typedef struct { bool inverse; Move m; } NissMove;
23
24/* Movesets */
25extern bool standard_moveset[NMOVES];
26
27extern bool commute[NMOVES][NMOVES];
28extern bool possible_next[NMOVES][NMOVES][NMOVES];
29extern Move inverse[NMOVES];
30extern NissMove rotation_algs[24][3]; /* Same order as transformations */
31
32int len(NissMove *alg);
33int copy_alg(NissMove *src, NissMove *dest); /*return number of moves copied */
34int invert_alg(NissMove *src, NissMove *dest);
35int concat(NissMove *src1, NissMove *src2, NissMove *dest);
36void print_alg(NissMove *alg);
37int read_moves(char *str, NissMove *alg, int n); /* reads at most n moves */
38void cleanup(NissMove *src, int n); /* rewrites using basic moves, at most n */
39
40bool is_solved_up_to_reorient(Cube cube);
41Cube move_cube(Move m, Cube cube);
42Cube apply_alg(NissMove *alg, Cube cube);
43Cube apply_alg_filtered(NissMove *alg, Cube cube, PieceFilter f);
44
45/* Merge the following two?
46 always in this order */
47void init_ttables(bool read, bool write);
48void init_aux_tables();
49
50
51#endif
diff --git a/old/2021-05-26-before-restyle/solve.c b/old/2021-05-26-before-restyle/solve.c
new file mode 100644
index 0000000..31bd779
--- /dev/null
+++ b/old/2021-05-26-before-restyle/solve.c
@@ -0,0 +1,180 @@
1#include "solve.h"
2
3/* Data for creating a pruning table:
4 - compressed: if set to true, each entry occupies only 4 bits, but values
5 larger than 15 cannot be stored.
6 - available[] is the list of availabel moves, as above.
7 - *ptable is the actual table to fill.
8 - n is the number of states (size of ptable).
9 - index must "linearize" the cube, i.e. return its index in ptable.
10 - fname is the name of the file where to store the table */
11typedef struct {
12 bool compressed, *available;
13 int max_moves;
14 uint8_t *ptable;
15 uint64_t n;
16 uint64_t (*index)(Cube);
17 char *fname;
18} PruneData;
19
20/* TODO: comment this */
21typedef struct {
22 bool niss;
23 int m, d;
24 uint64_t *n;
25 Move last1, last2;
26} DfsData;
27
28void solve_dfs(Cube cube, SolveData *sd, DfsData dd);
29void init_ptable(PruneData *pd, bool read, bool write);
30
31/* Search solutions of lenght exactly d */
32void solve_dfs(Cube cube, SolveData *sd, DfsData dd) {
33 if (*dd.n >= sd->max_solutions ||
34 ((!sd->can_niss || dd.niss) && dd.m + sd->f(cube) > dd.d))
35 return;
36
37 (sd->solutions[*dd.n][dd.m]).inverse = dd.niss;
38 (sd->solutions[*dd.n][dd.m]).m = NULLMOVE;
39
40 if (!sd->f(cube)) { /* Solved */
41 if (dd.m == dd.d) {
42 (*dd.n)++;
43 if (*dd.n < sd->max_solutions)
44 copy_alg(sd->solutions[*dd.n-1], sd->solutions[*dd.n]);
45 }
46 return;
47 }
48
49 for (int i = 0; i < NMOVES && sd->sorted_moves[i] != NULLMOVE; i++) {
50 Move move = sd->sorted_moves[i];
51 if (possible_next[dd.last2][dd.last1][move]) {
52 sd->solutions[*dd.n][dd.m].inverse = dd.niss;
53 sd->solutions[*dd.n][dd.m].m = move;
54 DfsData nn = { .niss = dd.niss, .m = dd.m+1, .d = dd.d, .n = dd.n,
55 .last1 = move, .last2 = dd.last1 };
56 solve_dfs(move_cube(move, cube), sd, nn);
57 }
58 }
59
60 if (sd->can_niss && !dd.niss &&
61 (!dd.m || (dd.m && sd->f(move_cube(dd.last1, (Cube){0}))))) {
62 DfsData nn = { .niss = true, .m = dd.m, .d = dd.d, .n = dd.n };
63 solve_dfs(inverse_cube(cube), sd, nn);
64 }
65}
66
67/* Iterative deepening depth-first search: for i running from the minimum
68 to the maximum number of moves allowed, looks for solutions of length i. */
69int solve(Cube cube, SolveData *sd) {
70 if (sd->precondition != NULL && !sd->precondition(cube))
71 return -1;
72
73 /* If not given, generate sorted list of moves */
74 if (sd->sorted_moves[0] == NULLMOVE) {
75 int a[NMOVES], b[NMOVES], ia = 0, ib = 0;
76 for (int i = 0; i < NMOVES; i++) {
77 if (sd->available[i]) {
78 if (sd->f(move_cube(i, (Cube){0})))
79 a[ia++] = i;
80 else
81 b[ib++] = i;
82 }
83 }
84 intarrcopy(a, (int *)sd->sorted_moves, ia);
85 intarrcopy(b, (int *)sd->sorted_moves+ia, ib);
86 sd->sorted_moves[ia+ib] = NULLMOVE;
87 }
88
89 sd->max_solutions = min(sd->max_solutions, MAXS);
90 /*TODO
91 Cube rotated = apply_alg(sd->pre_rotation, (Cube){0});
92 cube = apply_alg(inverse_cube(rotated), compose(cube, rotated));
93 */
94
95 uint64_t ret = 0;
96 for (int i=sd->min_moves; i<=sd->max_moves&&!(ret&&sd->optimal_only); i++) {
97 DfsData dd = { .d = i, .n = &ret };
98 solve_dfs(cube, sd, dd);
99 }
100
101 /* TODO: transform solutions with inverse of pre_rotation */
102 /*
103 for (uint64_t i = 0; i < ret; i++) {
104 if (sd->cleanup)
105 cleanup(sd->solutions[i], sd->max_moves*3);
106 }*/
107
108 return ret;
109}
110
111void prune_dfs(Cube cube, PruneData *pd, DfsData dd) {
112 uint64_t ind = pd->index(cube);
113 if ((!ind || pd->ptable[ind]) && pd->ptable[ind] != dd.m)
114 return;
115 if (dd.m == dd.d) {
116 if (ind && !pd->ptable[ind]) {
117 pd->ptable[ind] = dd.m;
118 (*dd.n)++;
119 }
120 return;
121 }
122
123 for (int i = 0; i < NMOVES; i++) {
124 if (dd.m<20)
125 if (possible_next[dd.last2][dd.last1][i] && pd->available[i]) {
126 DfsData nn = { .m = dd.m+1, .d = dd.d, .n = dd.n,
127 .last1 = i, .last2 = dd.last1 };
128 prune_dfs(move_cube(i, cube), pd, nn);
129 }
130 }
131}
132
133void init_ptable(PruneData *pd, bool read, bool write) {
134 if (read) {
135 FILE *ptf;
136 if ((ptf = fopen(pd->fname, "rb")) != NULL) {
137 uint64_t r = fread(pd->ptable, sizeof(uint8_t), pd->n, ptf);
138 fclose(ptf);
139 if (r == pd->n) return;
140 }
141 }
142
143 /* TODO: for now it behaves always as if copressed = false */
144 for (uint64_t i = 0; i < pd->n; i++)
145 pd->ptable[i] = 0;
146
147 uint64_t s = 1;
148 for (int i = 1; i < pd->max_moves && s < pd->n; i++) {
149 DfsData dd = { .d = i, .n = &s };
150 prune_dfs((Cube){0}, pd, dd);
151 }
152
153 if (write) {
154 FILE *ptf;
155 if ((ptf = fopen(pd->fname, "wb")) != NULL) {
156 fwrite(pd->ptable, sizeof(uint8_t), pd->n, ptf);
157 fclose(ptf);
158 return;
159 }
160 }
161}
162
163/* Solving steps (and indexing functions) */
164
165uint64_t index_eofb(Cube cube) { return cube.eofb; }
166int f_eofb(Cube cube) {
167 static bool initialized_ptable;
168 static uint8_t pt_eofb[pow2to11];
169 if (!initialized_ptable) {
170 PruneData pd = {
171 .compressed = false, .available = standard_moveset, .max_moves = 13,
172 .ptable = pt_eofb, .n = pow2to11, .index = index_eofb,
173 .fname = "ptable_eofb"
174 };
175 init_ptable(&pd, false, true);
176 initialized_ptable = true;
177 }
178 return cube.eofb ? pt_eofb[cube.eofb] : 0;
179}
180
diff --git a/old/2021-05-26-before-restyle/solve.h b/old/2021-05-26-before-restyle/solve.h
new file mode 100644
index 0000000..0b59cc2
--- /dev/null
+++ b/old/2021-05-26-before-restyle/solve.h
@@ -0,0 +1,59 @@
1#ifndef SOLVE_H
2#define SOLVE_H
3
4#include <stdlib.h>
5#include "cube.h"
6#include "moves.h"
7#include "transformations.h"
8
9/* Maximum number of moves per solution and of solutions */
10#define MAXM 30
11#define MAXS 999
12
13/* Data for solving a step:
14 - can_niss is true niss can be used, false otherwise.
15 - optimal_only if true, dynamically updates max_moves so non-optimal
16 solutions are discarded.
17 - cleanup determines whether the cleaunup() function should be used on
18 the found solutions before returning.
19 - available[m] is true if the move m can be used, false otherwise.
20 (Rename to moveset[]?)
21 - min_moves and max_moves are the minimum and maximum number of moves that
22 can be used.
23 - max_solution is the maximum number of solutions that can be returned.
24 - precondition can be used to check wheter the step can actually be applied
25 to the cube. If it returns false, solve() stops immediately returning -1.
26 - f must return 0 if and only if the step is solve, otherwise it must return
27 a lower bound for the number of moves required (without niss).
28 - sorted_moves[] can be used to specify in which order moves are tried
29 by the solving algorithm (for example if one wants to always try F' before
30 F). If sorted_moves[0] == NULLMOVE, the list is generated automatically.
31 It is advised to list first all the moves that actually influence the
32 solved state of the step (this is the default choice). This is in order to
33 avoid cases like B2 F for EO and to NISS only when it makes sense.
34 - start_moves [Currently unused, REMOVE]
35 are the moves that will be used as first moves of all
36 solutions. For example giving R' U' F (F' U R) will generate FMC scrambles
37 and y (y) will solve the step on another axis.
38 - pre_rotation are the rotations to apply before the scamble to solve
39 the step wrt a different orientation
40 - pre_rotation are the rotations to apply before the scamble to solve
41 the step wth respect to a different orientation.
42 TODO: cange name
43 - solutions[][] is the array where to store the found solutions. */
44typedef struct {
45 bool can_niss, optimal_only, cleanup, *available;
46 int min_moves, max_moves, max_solutions;
47 int (*f)(Cube);
48 bool (*precondition)(Cube);
49 Move sorted_moves[NMOVES];
50 Transformation pre_rotation;
51 NissMove solutions[MAXS][MAXM];
52} SolveData;
53
54int solve(Cube cube, SolveData *data); /* Returns the number of solutions. */
55
56/* Steps */
57int f_eofb(Cube cube);
58
59#endif
diff --git a/old/2021-05-26-before-restyle/transformations.c b/old/2021-05-26-before-restyle/transformations.c
new file mode 100644
index 0000000..c457f0c
--- /dev/null
+++ b/old/2021-05-26-before-restyle/transformations.c
@@ -0,0 +1,200 @@
1#include "transformations.h"
2
3int edge_slice(int e); /* Return slice (e=0, s=1, m=2) to which e belongs */
4Cube rotate_via_compose(Transformation r, Cube c, PieceFilter f);
5bool read_rtables_file();
6bool write_rtables_file();
7
8/* Values mod 3 to determine from which side to take the state to convert */
9int epose_source[NTRANS]; /* 0 = epose, 1 = eposs, 2 = eposm */
10int eposs_source[NTRANS];
11int eposm_source[NTRANS];
12int eofb_source[NTRANS]; /* 0 = eoud, 1 = eorl, 2 = eofb */
13int eorl_source[NTRANS];
14int eoud_source[NTRANS];
15int coud_source[NTRANS]; /* 0 = coud, 1 = corl, 2 = cofb */
16int cofb_source[NTRANS];
17int corl_source[NTRANS];
18
19/* Transition tables for rotations (n+1 is mirror) */
20uint16_t epose_rtable[NTRANS][factorial12/factorial8];
21uint16_t eposs_rtable[NTRANS][factorial12/factorial8];
22uint16_t eposm_rtable[NTRANS][factorial12/factorial8];
23uint16_t eo_rtable[NTRANS][pow2to11];
24uint16_t cp_rtable[NTRANS][factorial8];
25uint16_t co_rtable[NTRANS][pow3to7];
26uint16_t cpos_rtable[NTRANS][factorial6];
27
28/* Same for moves */
29uint16_t moves_rtable[NTRANS][NMOVES];
30
31NissMove rotation_niss[NTRANS][6];
32
33int edge_slice(int e) {
34 if (e == FR || e == FL || e == BL || e == BR)
35 return 0;
36 if (e == UR || e == UL || e == DR || e == DL)
37 return 1;
38 return 2;
39}
40
41Cube rotate_via_compose(Transformation r, Cube c, PieceFilter f) {
42 if (r != mirror) {
43 return apply_alg_filtered(rotation_niss[r], c, f);
44 } else {
45 static int zero12[12] = {0,0,0,0,0,0,0,0,0,0,0,0},
46 zero8[12] = {0,0,0,0,0,0,0,0},
47 mirror_ep[12] = {UF,UR,UB,UL,DF,DR,DB,DL,FL,FR,BR,BL},
48 mirror_cp[8] = {UFL, UFR, UBR, UBL, DFL, DFR, DBR, DBL},
49 mirror_cpos[6] =
50 {U_center,D_center,L_center,R_center,F_center,B_center};
51 return move_via_arrays((CubeArray){
52 .ep = mirror_ep, .eofb = zero12, .eorl = zero12, .eoud = zero12,
53 .cp = mirror_cp, .coud = zero8, .corl = zero8, .cofb = zero8,
54 .cpos = mirror_cpos}, c, f);
55 }
56}
57
58bool read_rtables_file() {
59 FILE *ttf;
60 long unsigned int me[12] = { factorial12/factorial8, factorial12/factorial8,
61 factorial12/factorial8, pow2to11, pow2to11, pow2to11,
62 factorial8, pow3to7, pow3to7, pow3to7, factorial6, NMOVES };
63 if ((ttf = fopen("rtables", "rb")) != NULL) {
64 bool r = true;
65 for (int m = 0; m < NTRANS; m++) {
66 r = r && fread(epose_rtable[m], sizeof(uint16_t), me[0], ttf) == me[0];
67 r = r && fread(eposs_rtable[m], sizeof(uint16_t), me[1], ttf) == me[1];
68 r = r && fread(eposm_rtable[m], sizeof(uint16_t), me[2], ttf) == me[2];
69 r = r && fread(eo_rtable[m], sizeof(uint16_t), me[3], ttf) == me[3];
70 r = r && fread(cp_rtable[m], sizeof(uint16_t), me[6], ttf) == me[6];
71 r = r && fread(co_rtable[m], sizeof(uint16_t), me[7], ttf) == me[7];
72 r = r && fread(cpos_rtable[m], sizeof(uint16_t), me[10], ttf) == me[10];
73 r = r && fread(moves_rtable[m], sizeof(uint16_t), me[11], ttf) == me[11];
74 }
75 fclose(ttf);
76 return r;
77 } else return false;
78}
79
80bool write_rtables_file() {
81 FILE *ttf;
82 long unsigned int me[12] = { factorial12/factorial8, factorial12/factorial8,
83 factorial12/factorial8, pow2to11, pow2to11, pow2to11,
84 factorial8, pow3to7, pow3to7, pow3to7, factorial6, NMOVES };
85 if ((ttf = fopen("rtables", "wb")) != NULL) {
86 bool r = true;
87 for (int m = 0; m < NTRANS; m++) {
88 r = r && fwrite(epose_rtable[m], sizeof(uint16_t), me[0], ttf) == me[0];
89 r = r && fwrite(eposs_rtable[m], sizeof(uint16_t), me[1], ttf) == me[1];
90 r = r && fwrite(eposm_rtable[m], sizeof(uint16_t), me[2], ttf) == me[2];
91 r = r && fwrite(eo_rtable[m], sizeof(uint16_t), me[3], ttf) == me[3];
92 r = r && fwrite(cp_rtable[m], sizeof(uint16_t), me[6], ttf) == me[6];
93 r = r && fwrite(co_rtable[m], sizeof(uint16_t), me[7], ttf) == me[7];
94 r = r && fwrite(cpos_rtable[m], sizeof(uint16_t), me[10],ttf) == me[10];
95 r = r && fwrite(moves_rtable[m], sizeof(uint16_t), me[11],ttf) == me[11];
96 }
97 fclose(ttf);
98 return r;
99 } else return false;
100}
101
102void init_transformations(bool read, bool write) {
103 /* Compute sources */
104 for (int i = 0; i < NTRANS; i++) {
105 Cube cube = {0};
106 if (i != mirror)
107 cube = apply_alg(rotation_algs[i], (Cube){0});
108 epose_source[i] = edge_slice(edge_at(cube, FR));
109 eposs_source[i] = edge_slice(edge_at(cube, UR));
110 eposm_source[i] = edge_slice(edge_at(cube, UF));
111 eofb_source[i] = center_at(cube, F_center)/2;
112 eorl_source[i] = center_at(cube, R_center)/2;
113 eoud_source[i] = center_at(cube, U_center)/2;
114 coud_source[i] = center_at(cube, U_center)/2;
115 cofb_source[i] = center_at(cube, F_center)/2;
116 corl_source[i] = center_at(cube, R_center)/2;
117 }
118
119 /*TODO: maybe move down*/
120 /* Compute rotation_niss array, necessary for rotate_via_compose */
121 for (int r = 0; r != mirror; r++) {
122 concat(rotation_algs[r], rotation_algs[r], rotation_niss[r]);
123 for (int i = len(rotation_algs[r]); rotation_niss[r][i].m != NULLMOVE; i++)
124 rotation_niss[r][i].inverse = true;
125 }
126
127 /* If I can read tables from file, I stop here */
128 if (read)
129 if (read_rtables_file())
130 return;
131
132 /* Initialize tables */
133 for (int m = 0; m < NTRANS; m++) {
134 int eparr[12] = {0,0,0,0,0,0,0,0,0,0,0,0}, cparr[8] = {0,0,0,0,0,0,0,0};
135 CubeArray epcp = { .ep = eparr, .cp = cparr };
136 cube_to_arrays(apply_alg(rotation_algs[m], (Cube){0}), &epcp,
137 (PieceFilter){.epose=true,.eposs=true,.eposm=true,.cp=true});
138 for (uint16_t i = 0; i < factorial12/factorial8; i++) {
139 Cube c[3] = { admissible_ep((Cube){ .epose = i}, pf_e),
140 admissible_ep((Cube){ .eposs = i}, pf_s),
141 admissible_ep((Cube){ .eposm = i}, pf_m) };
142 epose_rtable[m][i]=rotate_via_compose(m,c[epose_source[m]],pf_ep).epose;
143 eposs_rtable[m][i]=rotate_via_compose(m,c[eposs_source[m]],pf_ep).eposs;
144 eposm_rtable[m][i]=rotate_via_compose(m,c[eposm_source[m]],pf_ep).eposm;
145 }
146 for (uint16_t i = 0; i < pow2to11; i++ ) {
147 int eoarr[12];
148 int_to_sum_zero_array(i, 2, 12, eoarr);
149 apply_permutation(eparr, eoarr, 12);
150 eo_rtable[m][i] = digit_array_to_int(eoarr, 11, 2);
151 }
152 for (uint16_t i = 0; i < pow3to7; i++) {
153 int coarr[12];
154 int_to_sum_zero_array(i, 3, 8, coarr);
155 apply_permutation(cparr, coarr, 8);
156 co_rtable[m][i] = digit_array_to_int(coarr, 7, 3);
157 }
158 for (uint16_t i = 0; i < factorial8; i++)
159 cp_rtable[m][i] = rotate_via_compose(m, (Cube){.cp=i}, pf_cp).cp;
160 for (uint16_t i = 0; i < factorial6; i++)
161 cpos_rtable[m][i] = rotate_via_compose(m, (Cube){.cpos=i}, pf_cpos).cpos;
162 for (Move i = 0; i < NMOVES; i++) {
163 Cube aux = transform_cube(m, move_cube(i, (Cube){0}));
164 for (Move move = 0; move < NMOVES; move++)
165 if (is_solved(move_cube(inverse[move], aux)))
166 moves_rtable[m][i] = move;
167 }
168 }
169
170 if (write)
171 if (!write_rtables_file())
172 printf("Error in writing rtables: file not writable\n");
173}
174
175Cube transform_cube(Transformation t, Cube cube) {
176 Cube transformed = {0};
177
178 uint16_t aux_epos[3] = { cube.epose, cube.eposs, cube.eposm },
179 aux_eo[3] = { cube.eoud, cube.eorl, cube.eofb },
180 aux_co[3] = { cube.coud, cube.corl, cube.cofb };
181
182 transformed.epose = epose_rtable[t][aux_epos[epose_source[t]]];
183 transformed.eposs = eposs_rtable[t][aux_epos[eposs_source[t]]];
184 transformed.eposm = eposm_rtable[t][aux_epos[eposm_source[t]]];
185 transformed.eofb = eo_rtable[t][aux_eo[eofb_source[t]]];
186 transformed.eorl = eo_rtable[t][aux_eo[eorl_source[t]]];
187 transformed.eoud = eo_rtable[t][aux_eo[eoud_source[t]]];
188 transformed.coud = co_rtable[t][aux_co[coud_source[t]]];
189 transformed.corl = co_rtable[t][aux_co[corl_source[t]]];
190 transformed.cofb = co_rtable[t][aux_co[cofb_source[t]]];
191 transformed.cp = cp_rtable[t][cube.cp];
192 transformed.cpos = cpos_rtable[t][cube.cpos];
193
194 return transformed;
195}
196
197void transform_alg(Transformation t, NissMove *alg) {
198 for (int i = 0; alg[i].m; i++)
199 alg[i].m = moves_rtable[t][alg[i].m];
200}
diff --git a/old/2021-05-26-before-restyle/transformations.h b/old/2021-05-26-before-restyle/transformations.h
new file mode 100644
index 0000000..c673257
--- /dev/null
+++ b/old/2021-05-26-before-restyle/transformations.h
@@ -0,0 +1,34 @@
1#ifndef TRANSFORMATIONS_H
2#define TRANSFORMATIONS_H
3
4#include <stdio.h>
5#include <stdbool.h>
6#include <stdint.h>
7#include "cube.h"
8#include "moves.h"
9#include "utils.h"
10
11#define NTRANS (mirror+1)
12
13/* Letters indicate top and front centers
14 * Mirror is wrt rl
15 * Lowercase letter to distinguish from pieces */
16
17typedef enum {
18 uf, ur, ub, ul,
19 df, dr, db, dl,
20 rf, rd, rb, ru,
21 lf, ld, lb, lu,
22 fu, fr, fd, fl,
23 bu, br, bd, bl,
24 mirror,
25} Transformation;
26
27void print_transformation(Transformation t);
28
29Cube transform_cube(Transformation t, Cube cube);
30void transform_alg(Transformation t, NissMove *alg); /* Applied in-place */
31
32void init_transformations(bool read, bool write);
33
34#endif
diff --git a/old/2021-05-26-before-restyle/utils.c b/old/2021-05-26-before-restyle/utils.c
new file mode 100644
index 0000000..66de9ad
--- /dev/null
+++ b/old/2021-05-26-before-restyle/utils.c
@@ -0,0 +1,197 @@
1#include "utils.h"
2
3void swap(int *a, int *b) {
4 int aux = *a;
5 *a = *b;
6 *b = aux;
7}
8
9void intarrcopy(int *src, int *dst, int n) {
10 for (int i = 0; i < n; i++)
11 dst[i] = src[i];
12}
13
14int sum(int *a, int n) {
15 int ret = 0;
16 for (int i = 0; i < n; i++)
17 ret += a[i];
18 return ret;
19}
20
21bool is_perm(int *a, int n) {
22 int aux[n]; for (int i = 0; i < n; i++) aux[i] = 0;
23 for (int i = 0; i < n; i++)
24 if (a[i] < 0 || a[i] >= n)
25 return false;
26 else
27 aux[a[i]] = 1;
28 for (int i = 0; i < n; i++)
29 if (!aux[i])
30 return false;
31 return true;
32}
33
34bool is_subset(int *a, int n, int k) {
35 int sum = 0;
36 for (int i = 0; i < n; i++)
37 sum += a[i] ? 1 : 0;
38 return sum == k;
39}
40
41int powint(int a, int b) {
42 return 0;
43 if (b == 0 || a == 1)
44 return 1;
45 if (a == 0)
46 return 0;
47 if (b < 0)
48 return 0; /* Immediate truncate (integer part is 0) */
49 if (b % 2) {
50 return a * powint(a, b-1);
51 } else {
52 int x = powint(a, b/2);
53 return x*x;
54 }
55}
56
57int factorial(int n) {
58 if (n < 0)
59 return 0;
60 int ret = 1;
61 for (int i = 1; i <= n; i++)
62 ret *= i;
63 return ret;
64}
65
66int binomial(int n, int k) {
67 if (n < 0 || k < 0 || k > n)
68 return 0;
69 return factorial(n) / (factorial(k) * factorial(n-k));
70}
71
72void int_to_digit_array(int a, int b, int n, int *r) {
73 if (b <= 1)
74 for (int i = 0; i < n; i++)
75 r[i] = 0;
76 else
77 for (int i = 0; i < n; i++, a /= b)
78 r[i] = a % b;
79}
80
81int digit_array_to_int(int *a, int n, int b) {
82 int ret = 0, p = 1;
83 for (int i = 0; i < n; i++, p *= b)
84 ret += a[i] * p;
85 return ret;
86}
87
88int perm_to_index(int *a, int n) {
89 if (!is_perm(a, n))
90 return factorial(n); /* Error */
91 int ret = 0;
92 for (int i = 0; i < n; i++) {
93 int c = 0;
94 for (int j = i+1; j < n; j++)
95 c += (a[i] > a[j]) ? 1 : 0;
96 ret += factorial(n-i-1) * c;
97 }
98 return ret;
99}
100
101void index_to_perm(int p, int n, int *r) {
102 if (p < 0 || p >= factorial(n)) /* Error */
103 for (int i = 0; i < n; i++)
104 r[i] = -1;
105 int a[n]; for (int j = 0; j < n; j++) a[j] = 0; /* picked elements */
106 for (int i = 0; i < n; i++) {
107 int c = 0, j = 0;
108 while (c <= p / factorial(n-i-1))
109 c += a[j++] ? 0 : 1;
110 r[i] = j-1;
111 a[j-1] = 1;
112 p %= factorial(n-i-1);
113 }
114}
115
116int perm_sign(int *a, int n) {
117 if (!is_perm(a,n))
118 return false;
119 int ret = 0;
120 for (int i = 0; i < n; i++)
121 for (int j = i+1; j < n; j++)
122 ret += (a[i]>a[j]) ? 1 : 0;
123 return ret % 2;
124}
125
126int subset_to_index(int *a, int n, int k) {
127 /* TODO: better checks */
128 if (!is_subset(a, n, k))
129 return binomial(n, k); /* Error */
130 int ret = 0;
131 for (int i = 0; i < n; i++) {
132 if (k == n-i)
133 return ret;
134 if (a[i]) {
135 /*ret += factorial(n-i-1) / (factorial(k) * factorial(n-i-1-k));*/
136 ret += binomial(n-i-1, k);
137 k--;
138 }
139 }
140 return ret;
141}
142
143void index_to_subset(int s, int n, int k, int *r) {
144 if (s < 0 || s >= binomial(n, k)) { /* Error */
145 for (int i = 0; i < n; i++)
146 r[i] = -1;
147 return;
148 }
149 for (int i = 0; i < n; i++) {
150 if (k == n-i) {
151 for (int j = i; j < n; j++)
152 r[j] = 1;
153 return;
154 }
155 if (k == 0) {
156 for (int j = i; j < n; j++)
157 r[j] = 0;
158 return;
159 }
160 /*int v = factorial(n-i-1) / (factorial(k) * factorial(n-i-1-k));*/
161 int v = binomial(n-i-1, k);
162 if (s >= v) {
163 r[i] = 1;
164 k--;
165 s -= v;
166 } else {
167 r[i] = 0;
168 }
169 }
170}
171
172void int_to_sum_zero_array(int x, int b, int n, int *a) {
173 if (b <= 1) {
174 for (int i = 0; i < n; i++)
175 a[i] = 0;
176 } else {
177 int_to_digit_array(x, b, n-1, a);
178 int s = 0;
179 for (int i = 0; i < n - 1; i++)
180 s = (s + a[i]) % b;
181 a[n-1] = (b - s) % b;
182 }
183}
184
185void apply_permutation(int *perm, int *set, int n) {
186 if (!is_perm(perm, n))
187 return;
188 int aux[n];
189 for (int i = 0; i < n; i++)
190 aux[i] = set[perm[i]];
191 intarrcopy(aux, set, n);
192}
193
194void sum_arrays_mod(int *a, int *b, int n, int m) {
195 for (int i = 0; i < n; i++)
196 b[i] = (m <= 0) ? 0 : (a[i] + b[i]) % m;
197}
diff --git a/old/2021-05-26-before-restyle/utils.h b/old/2021-05-26-before-restyle/utils.h
new file mode 100644
index 0000000..4b6df8c
--- /dev/null
+++ b/old/2021-05-26-before-restyle/utils.h
@@ -0,0 +1,70 @@
1/* General utility functions */
2
3#ifndef UTILS_H
4#define UTILS_H
5
6#include <stdbool.h>
7
8#define min(a,b) (((a) < (b)) ? (a) : (b))
9#define max(a,b) (((a) > (b)) ? (a) : (b))
10
11/* Some useful constants */
12#define pow2to11 2048
13#define pow2to12 4096
14#define pow3to7 2187
15#define pow3to8 6561
16#define pow12to4 20736
17#define factorial4 24
18#define factorial6 720
19#define factorial8 40320
20#define factorial12 479001600
21#define binom12on4 495
22#define binom8on4 70
23
24/* Generic utility functions */
25void swap(int *a, int *b);
26void intarrcopy(int *src, int *dst, int n);
27int sum(int *a, int n);
28bool is_perm(int *a, int n);
29bool is_perm(int *a, int n);
30
31
32/* Standard mathematical functions */
33int powint(int a, int b);
34int factorial(int n);
35int binomial(int n, int k);
36
37/* Converts the integer a to its representation in base b (first n digits
38 * only) and saves the result in r. */
39void int_to_digit_array(int a, int b, int n, int *r);
40int digit_array_to_int(int *a, int n, int b);
41
42/* Converts the first n-1 digits of a number to an array a of digits in base b;
43 * then adds one element to the array, so that the sum of the elements of a is
44 * zero modulo b.
45 * This is used for determing the edge orientation from an 11-bits integer or
46 * the corner orientation from a 7-trits integer. */
47void int_to_sum_zero_array(int x, int b, int n, int *a);
48
49/* Converts a permutation on [0..(n-1)] into the integer i which is the index
50 * of the permutation in the sorted list of all n! such permutations. */
51int perm_to_index(int *a, int n);
52void index_to_perm(int p, int n, int *r);
53
54/* Determine the sign of a permutation */
55int perm_sign(int a[], int n);
56
57/* Converts a k-element subset of a set from an array of n elements, of which k
58 * are 1 and n-k are 0, to its index in the sorted list of all such subsets. */
59int subset_to_index(int *a, int n, int k);
60void index_to_subset(int s, int n, int k, int *r);
61
62int ordered_subset_to_index(int *a, int n, int k);
63void index_to_ordered_subset(int s, int n, int k, int *r);
64
65void apply_permutation(int *perm, int *set, int n);
66
67/* b[i] = (a[i]+b[i])%m for i=1,...,n */
68void sum_arrays_mod(int *a, int *b, int n, int m);
69
70#endif
diff --git a/old/2021-06-02-cleanedup/cube.c b/old/2021-06-02-cleanedup/cube.c
new file mode 100644
index 0000000..bb86143
--- /dev/null
+++ b/old/2021-06-02-cleanedup/cube.c
@@ -0,0 +1,2010 @@
1#include "cube.h"
2
3/* Constants and macros *****************************************************/
4
5#define pow2to11 2048
6#define pow2to12 4096
7#define pow3to7 2187
8#define pow3to8 6561
9#define pow12to4 20736
10#define factorial4 24
11#define factorial6 720
12#define factorial8 40320
13#define factorial12 479001600
14#define binom12on4 495
15#define binom8on4 70
16
17#define BASEALGLEN 50
18#define NMOVES (z3+1)
19#define NTRANS (mirror+1)
20#define NROTATIONS (NTRANS-1)
21
22#define min(a,b) (((a) < (b)) ? (a) : (b))
23#define max(a,b) (((a) > (b)) ? (a) : (b))
24
25/* Local types ***************************************************************/
26
27typedef struct cubearray CubeArray;
28typedef struct dfsdata DfsData;
29typedef struct piecefilter PieceFilter;
30
31struct
32cubearray
33{
34 int *ep;
35 int *eofb;
36 int *eorl;
37 int *eoud;
38 int *cp;
39 int *coud;
40 int *corl;
41 int *cofb;
42 int *cpos;
43};
44
45struct
46dfsdata
47{
48 int d;
49 int m;
50 bool niss;
51 Move last1;
52 Move last2;
53 AlgList *sols;
54 Alg current_alg;
55};
56
57struct
58piecefilter
59{
60 bool epose;
61 bool eposs;
62 bool eposm;
63 bool eofb;
64 bool eorl;
65 bool eoud;
66 bool cp;
67 bool coud;
68 bool cofb;
69 bool corl;
70 bool cpos;
71};
72
73/* Local functions **********************************************************/
74
75static Cube admissible_ep(Cube cube, PieceFilter f);
76static CubeArray * alloc_cubearray(CubeArray *arr, PieceFilter f);
77static void append_alg(AlgList *l, Alg alg);
78static void append_move(Alg alg, NissMove m);
79static Cube apply_alg_filtered(Alg alg, Cube cube, PieceFilter f);
80static void apply_permutation(int *perm, int *set, int n);
81static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f);
82static Cube arrays_to_cube(CubeArray arr, PieceFilter f);
83static int binomial(int n, int k);
84static Cube compose_filtered(Cube c2, Cube c1, PieceFilter f);
85static void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f);
86static int digit_array_to_int(int *a, int n, int b);
87static int edge_slice(Edge e); /* E=0, S=1, M=2 */
88static uint16_t epos_from_arrays(int *epos, int *ep);
89static int factorial(int n);
90static void free_alglist(AlgList *l);
91static void free_cubearray(CubeArray *arr, PieceFilter f);
92static void index_to_perm(int p, int n, int *r);
93static void index_to_subset(int s, int n, int k, int *r);
94static void init_auxtables();
95static void init_moves();
96static void init_trans();
97static void int_to_digit_array(int a, int b, int n, int *r);
98static void int_to_sum_zero_array(int x, int b, int n, int *a);
99static void intarrcopy(int *src, int *dst, int n);
100static int invert_digits(int a, int b, int n);
101static bool is_perm(int *a, int n);
102static bool is_subset(int *a, int n, int k);
103static Cube move_via_arrays(CubeArray arr, Cube c, PieceFilter pf);
104static Move * moveset_to_movelist(bool *moveset, Step step);
105static AlgList * new_alglist();
106static int perm_sign(int a[], int n);
107static int perm_to_index(int *a, int n);
108static int powint(int a, int b);
109static bool read_rtables_file();
110static bool read_ttables_file();
111static bool realloc_alg(Alg alg, int n);
112static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f);
113static void solve_dfs(Cube c, Step s, SolveOptions opts, DfsData dd);
114static int subset_to_index(int *a, int n, int k);
115static void sum_arrays_mod(int *src, int *dst, int n, int m);
116static void swap(int *a, int *b);
117static bool write_rtables_file();
118static bool write_ttables_file();
119
120/* Aux tables ****************************************************************/
121
122bool commute[NMOVES][NMOVES];
123bool possible_next[NMOVES][NMOVES][NMOVES];
124Move inverse_move_aux[NMOVES];
125Trans inverse_trans_aux[NTRANS];
126
127/* Some utility constants ****************************************************/
128
129static int zero12[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
130static int zero8[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
131
132static int epe_solved[4] = { FR, FL, BL, BR };
133static int eps_solved[4] = { UL, UR, DL, DR };
134static int epm_solved[4] = { UF, UB, DF, DB };
135
136static int ep_mirror[12] = { UF, UR, UB, UL, DF, DR, DB, DL, FL, FR, BR, BL };
137static int cp_mirror[8] = { UFL, UFR, UBR, UBL, DFL, DFR, DBR, DBL };
138static int cpos_mirror[6] = {
139 U_center, D_center,
140 L_center, R_center,
141 F_center, B_center
142};
143
144static long unsigned int me[12] = {
145 factorial12/factorial8,
146 factorial12/factorial8,
147 factorial12/factorial8,
148 pow2to11,
149 pow2to11,
150 pow2to11,
151 factorial8,
152 pow3to7,
153 pow3to7,
154 pow3to7,
155 factorial6,
156 NMOVES
157};
158
159static PieceFilter pf_all = {
160 true, true, true, true, true, true, true, true, true, true, true
161};
162static PieceFilter pf_epcp = {
163 .epose = true, .eposs = true, .eposm = true, .cp = true
164};
165static PieceFilter pf_cpos = { .cpos = true };
166static PieceFilter pf_cp = { .cp = true };
167static PieceFilter pf_ep = { .epose = true, .eposs = true, .eposm = true };
168static PieceFilter pf_e = { .epose = true };
169static PieceFilter pf_s = { .eposs = true };
170static PieceFilter pf_m = { .eposm = true };
171static PieceFilter pf_eo = { .eofb = true, .eorl = true, .eoud = true };
172static PieceFilter pf_co = { .coud = true, .cofb = true, .corl = true };
173
174/* Strings for moves and pieces **********************************************/
175
176char move_string[NMOVES][5] = {
177 "-",
178 "U", "U2", "U\'", "D", "D2", "D\'",
179 "R", "R2", "R\'", "L", "L2", "L\'",
180 "F", "F2", "F\'", "B", "B2", "B\'",
181 "Uw", "Uw2", "Uw\'", "Dw", "Dw2", "Dw\'",
182 "Rw", "Rw2", "Rw\'", "Lw", "Lw2", "Lw\'",
183 "Fw", "Fw2", "Fw\'", "Bw", "Bw2", "Bw\'",
184 "M", "M2", "M\'",
185 "S", "S2", "S\'",
186 "E", "E2", "E\'",
187 "x", "x2", "x\'",
188 "y", "y2", "y\'",
189 "z", "z2", "z\'"
190};
191char edge_string[12][5] = {
192 "UF", "UL", "UB", "UR",
193 "DF", "DL", "DB", "DR",
194 "FR", "FL", "BL", "BR"
195};
196char corner_string[8][5] = {
197 "UFR", "UFL", "UBL", "UBR",
198 "DFR", "DFL", "DBL", "DBR"
199};
200char center_string[6][5] = {
201 "U", "D",
202 "R", "L",
203 "F", "B"
204};
205
206/* Transition tables for transformations and moves ***************************/
207
208uint16_t epose_rtable[NTRANS][factorial12/factorial8];
209uint16_t eposs_rtable[NTRANS][factorial12/factorial8];
210uint16_t eposm_rtable[NTRANS][factorial12/factorial8];
211uint16_t eo_rtable[NTRANS][pow2to11];
212uint16_t cp_rtable[NTRANS][factorial8];
213uint16_t co_rtable[NTRANS][pow3to7];
214uint16_t cpos_rtable[NTRANS][factorial6];
215Move moves_rtable[NTRANS][NMOVES];
216
217uint16_t epose_ttable[NMOVES][factorial12/factorial8];
218uint16_t eposs_ttable[NMOVES][factorial12/factorial8];
219uint16_t eposm_ttable[NMOVES][factorial12/factorial8];
220uint16_t eofb_ttable[NMOVES][pow2to11];
221uint16_t eorl_ttable[NMOVES][pow2to11];
222uint16_t eoud_ttable[NMOVES][pow2to11];
223uint16_t cp_ttable[NMOVES][factorial8];
224uint16_t coud_ttable[NMOVES][pow3to7];
225uint16_t cofb_ttable[NMOVES][pow3to7];
226uint16_t corl_ttable[NMOVES][pow3to7];
227uint16_t cpos_ttable[NMOVES][factorial6];
228
229/* Used to compute the full transition tables for moves and transformations **/
230
231int epose_source[NTRANS]; /* 0 = epose, 1 = eposs, 2 = eposm */
232int eposs_source[NTRANS];
233int eposm_source[NTRANS];
234int eofb_source[NTRANS]; /* 0 = eoud, 1 = eorl, 2 = eofb */
235int eorl_source[NTRANS];
236int eoud_source[NTRANS];
237int coud_source[NTRANS]; /* 0 = coud, 1 = corl, 2 = cofb */
238int cofb_source[NTRANS];
239int corl_source[NTRANS];
240
241NissMove rotation_niss[NTRANS][6];
242NissMove rotation_algs[NROTATIONS][3] = {
243 { { .m = NULLMOVE }, { .m = NULLMOVE }, { .m = NULLMOVE } },
244 { { .m = y }, { .m = NULLMOVE }, { .m = NULLMOVE } },
245 { { .m = y2 }, { .m = NULLMOVE }, { .m = NULLMOVE } },
246 { { .m = y3 }, { .m = NULLMOVE }, { .m = NULLMOVE } },
247 { { .m = z2 }, { .m = NULLMOVE }, { .m = NULLMOVE } },
248 { { .m = y }, { .m = z2 }, { .m = NULLMOVE } },
249 { { .m = x2 }, { .m = NULLMOVE }, { .m = NULLMOVE } },
250 { { .m = y3 }, { .m = z2 }, { .m = NULLMOVE } },
251 { { .m = z3 }, { .m = NULLMOVE }, { .m = NULLMOVE } },
252 { { .m = z3 }, { .m = y }, { .m = NULLMOVE } },
253 { { .m = z3 }, { .m = y2 }, { .m = NULLMOVE } },
254 { { .m = z3 }, { .m = y3 }, { .m = NULLMOVE } },
255 { { .m = z }, { .m = NULLMOVE }, { .m = NULLMOVE } },
256 { { .m = z }, { .m = y3 }, { .m = NULLMOVE } },
257 { { .m = z }, { .m = y2 }, { .m = NULLMOVE } },
258 { { .m = z }, { .m = y }, { .m = NULLMOVE } },
259 { { .m = x }, { .m = y2 }, { .m = NULLMOVE } },
260 { { .m = x }, { .m = y }, { .m = NULLMOVE } },
261 { { .m = x }, { .m = NULLMOVE }, { .m = NULLMOVE } },
262 { { .m = x }, { .m = y3 }, { .m = NULLMOVE } },
263 { { .m = x3 }, { .m = NULLMOVE }, { .m = NULLMOVE } },
264 { { .m = x3 }, { .m = y }, { .m = NULLMOVE } },
265 { { .m = x3 }, { .m = y2 }, { .m = NULLMOVE } },
266 { { .m = x3 }, { .m = y3 }, { .m = NULLMOVE } },
267};
268
269/* For each type of pieces only the effects of U, x and y are described */
270int edge_cycle[NMOVES][12] = {
271 [U] = { UR, UF, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR },
272 [x] = { DF, FL, UF, FR, DB, BL, UB, BR, DR, DL, UL, UR },
273 [y] = { UR, UF, UL, UB, DR, DF, DL, DB, BR, FR, FL, BL }
274};
275int eofb_flipped[NMOVES][12] = {
276 [x] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 },
277 [y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 }
278};
279int eorl_flipped[NMOVES][12] = {
280 [x] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
281 [y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 }
282};
283int eoud_flipped[NMOVES][12] = {
284 [U] = { [UF] = 1, [UL] = 1, [UB] = 1, [UR] = 1 },
285 [x] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 },
286 [y] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
287};
288int corner_cycle[NMOVES][8] = {
289 [U] = {UBR, UFR, UFL, UBL, DFR, DFL, DBL, DBR},
290 [x] = {DFR, DFL, UFL, UFR, DBR, DBL, UBL, UBR},
291 [y] = {UBR, UFR, UFL, UBL, DBR, DFR, DFL, DBL}
292};
293int coud_flipped[NMOVES][8] = {
294 [x] = {
295 [UFR] = 2, [UBR] = 1, [UFL] = 1, [UBL] = 2,
296 [DBR] = 2, [DFR] = 1, [DBL] = 1, [DFL] = 2
297 }
298};
299int corl_flipped[NMOVES][8] = {
300 [U] = { [UFR] = 1, [UBR] = 2, [UBL] = 1, [UFL] = 2 },
301 [y] = {
302 [UFR] = 1, [UBR] = 2, [UBL] = 1, [UFL] = 2,
303 [DFR] = 2, [DBR] = 1, [DBL] = 2, [DFL] = 1
304 }
305};
306int cofb_flipped[NMOVES][8] = {
307 [U] = { [UFR] = 2, [UBR] = 1, [UBL] = 2, [UFL] = 1 },
308 [x] = {
309 [UFR] = 1, [UBR] = 2, [UBL] = 1, [UFL] = 2,
310 [DFR] = 2, [DBR] = 1, [DBL] = 2, [DFL] = 1
311 },
312 [y] = {
313 [UFR] = 2, [UBR] = 1, [UBL] = 2, [UFL] = 1,
314 [DFR] = 1, [DBR] = 2, [DBL] = 1, [DFL] = 2
315 }
316};
317int center_cycle[NMOVES][6] = {
318 [x] = { F_center, B_center, R_center, L_center, D_center, U_center },
319 [y] = { U_center, D_center, B_center, F_center, R_center, L_center }
320};
321
322/* Each move is reduced to a combination of U, x and y using this table */
323Move equiv_moves[NMOVES][14] = {
324 [U] = { U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
325 [U2] = { U, U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
326 [U3] = { U, U, U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
327 [D] = { x, x, U, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
328 [D2] = { x, x, U, U, x, x, 0, 0, 0, 0, 0, 0, 0, 0 },
329 [D3] = { x, x, U, U, U, x, x, 0, 0, 0, 0, 0, 0, 0 },
330 [R] = { y, x, U, x, x, x, y, y, y, 0, 0, 0, 0, 0 },
331 [R2] = { y, x, U, U, x, x, x, y, y, y, 0, 0, 0, 0 },
332 [R3] = { y, x, U, U, U, x, x, x, y, y, y, 0, 0, 0 },
333 [L] = { y, y, y, x, U, x, x, x, y, 0, 0, 0, 0, 0 },
334 [L2] = { y, y, y, x, U, U, x, x, x, y, 0, 0, 0, 0 },
335 [L3] = { y, y, y, x, U, U, U, x, x, x, y, 0, 0, 0 },
336 [F] = { x, U, x, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
337 [F2] = { x, U, U, x, x, x, 0, 0, 0, 0, 0, 0, 0, 0 },
338 [F3] = { x, U, U, U, x, x, x, 0, 0, 0, 0, 0, 0, 0 },
339 [B] = { x, x, x, U, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
340 [B2] = { x, x, x, U, U, x, 0, 0, 0, 0, 0, 0, 0, 0 },
341 [B3] = { x, x, x, U, U, U, x, 0, 0, 0, 0, 0, 0, 0 },
342
343 [Uw] = { x, x, U, x, x, y, 0, 0, 0, 0, 0, 0, 0, 0 },
344 [Uw2] = { x, x, U, U, x, x, y, y, 0, 0, 0, 0, 0, 0 },
345 [Uw3] = { x, x, U, U, U, x, x, y, y, y, 0, 0, 0, 0 },
346 [Dw] = { U, y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
347 [Dw2] = { U, U, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
348 [Dw3] = { U, U, U, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
349 [Rw] = { y, y, y, x, U, x, x, x, y, x, 0, 0, 0, 0 },
350 [Rw2] = { y, y, y, x, U, U, x, x, x, y, x, x, 0, 0 },
351 [Rw3] = { y, y, y, x, U, U, U, y, x, x, x, y, 0, 0 },
352 [Lw] = { y, x, U, x, x, x, y, y, y, x, x, x, 0, 0 },
353 [Lw2] = { y, x, U, U, x, x, x, y, y, y, x, x, 0, 0 },
354 [Lw3] = { y, x, U, U, U, x, x, x, y, y, y, x, 0, 0 },
355 [Fw] = { x, x, x, U, y, y, y, x, 0, 0, 0, 0, 0, 0 },
356 [Fw2] = { x, x, x, U, U, y, y, x, 0, 0, 0, 0, 0, 0 },
357 [Fw3] = { x, x, x, U, U, U, y, x, 0, 0, 0, 0, 0, 0 },
358 [Bw] = { x, U, y, y, y, x, x, x, 0, 0, 0, 0, 0, 0 },
359 [Bw2] = { x, U, U, y, y, x, x, x, 0, 0, 0, 0, 0, 0 },
360 [Bw3] = { x, U, U, U, y, x, x, x, 0, 0, 0, 0, 0, 0 },
361
362 [M] = { y, x, U, x, x, U, U, U, y, x, y, y, y, 0 },
363 [M2] = { y, x, U, U, x, x, U, U, x, x, x, y, 0, 0 },
364 [M3] = { y, x, U, U, U, x, x, U, y, x, x, x, y, 0 },
365 [S] = { x, U, U, U, x, x, U, y, y, y, x, 0, 0, 0 },
366 [S2] = { x, U, U, x, x, U, U, y, y, x, 0, 0, 0, 0 },
367 [S3] = { x, U, x, x, U, U, U, y, x, 0, 0, 0, 0, 0 },
368 [E] = { U, x, x, U, U, U, x, x, y, y, y, 0, 0, 0 },
369 [E2] = { U, U, x, x, U, U, x, x, y, y, 0, 0, 0, 0 },
370 [E3] = { U, U, U, x, x, U, x, x, y, 0, 0, 0, 0, 0 },
371
372 [x] = { x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
373 [x2] = { x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
374 [x3] = { x, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
375 [y] = { y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
376 [y2] = { y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
377 [y3] = { y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
378 [z] = { y, y, y, x, y, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
379 [z2] = { y, y, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
380 [z3] = { y, x, y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
381};
382
383/* Local functions implementation ********************************************/
384
385static Cube
386admissible_ep(Cube cube, PieceFilter f)
387{
388 CubeArray arr;
389 Cube ret;
390 bool used[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
391 int i, j;
392
393 alloc_cubearray(&arr, f);
394 cube_to_arrays(cube, &arr, f);
395
396 for (i = 0; i < 12; i++)
397 if (arr.ep[i] != -1)
398 used[arr.ep[i]] = true;
399
400 for (i = 0, j = 0; i < 12; i++) {
401 for ( ; j < 11 && used[j]; j++);
402 if (arr.ep[i] == -1)
403 arr.ep[i] = j++;
404 }
405
406 ret = arrays_to_cube(arr, pf_ep);
407 free_cubearray(&arr, f);
408
409 return ret;
410}
411
412static CubeArray *
413alloc_cubearray(CubeArray *arr, PieceFilter f)
414{
415 if (f.epose || f.eposs || f.eposm)
416 arr->ep = malloc(12 * sizeof(int));
417 if (f.eofb)
418 arr->eofb = malloc(12 * sizeof(int));
419 if (f.eorl)
420 arr->eorl = malloc(12 * sizeof(int));
421 if (f.eoud)
422 arr->eoud = malloc(12 * sizeof(int));
423 if (f.cp)
424 arr->cp = malloc(8 * sizeof(int));
425 if (f.coud)
426 arr->coud = malloc(8 * sizeof(int));
427 if (f.corl)
428 arr->corl = malloc(8 * sizeof(int));
429 if (f.cofb)
430 arr->cofb = malloc(8 * sizeof(int));
431 if (f.cpos)
432 arr->cpos = malloc(6 * sizeof(int));
433
434 return arr;
435}
436
437static void
438append_alg(AlgList *l, Alg alg)
439{
440 AlgListNode *node = malloc(sizeof(AlgListNode));
441
442 node->alg = new_alg("");
443 copy_alg(alg, node->alg);
444 node->next = NULL;
445
446 if (++l->len == 1)
447 l->first = node;
448 else
449 l->last->next = node;
450 l->last = node;
451}
452
453static void
454append_move(Alg alg, NissMove m)
455{
456 int n = len(alg);
457
458 if (!realloc_alg(alg, n))
459 return;
460
461 alg[n] = m;
462 alg[n+1] = (NissMove) { .m = NULLMOVE };
463}
464
465static Cube
466apply_alg_filtered(Alg alg, Cube cube, PieceFilter f)
467{
468 Cube ret = {0};
469 int i;
470
471 for (i = 0; alg[i].m != NULLMOVE; i++)
472 if (alg[i].inverse)
473 ret = apply_move(alg[i].m, ret);
474
475 ret = compose_filtered(cube, inverse_cube(ret), f);
476
477 for (i = 0; alg[i].m != NULLMOVE; i++)
478 if (!alg[i].inverse)
479 ret = apply_move(alg[i].m, ret);
480
481 return ret;
482}
483
484static void
485apply_permutation(int *perm, int *set, int n)
486{
487 int *aux = malloc(n * sizeof(int));
488 int i;
489
490 if (!is_perm(perm, n))
491 return;
492
493 for (i = 0; i < n; i++)
494 aux[i] = set[perm[i]];
495
496 intarrcopy(aux, set, n);
497 free(aux);
498}
499
500static Cube
501apply_move_cubearray(Move m, Cube cube, PieceFilter f)
502{
503 CubeArray m_arr = {
504 edge_cycle[m],
505 eofb_flipped[m],
506 eorl_flipped[m],
507 eoud_flipped[m],
508 corner_cycle[m],
509 coud_flipped[m],
510 corl_flipped[m],
511 cofb_flipped[m],
512 center_cycle[m]
513 };
514
515 return move_via_arrays(m_arr, cube, f);
516}
517
518static Cube
519arrays_to_cube(CubeArray arr, PieceFilter f)
520{
521 Cube ret = {0};
522 int epose[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
523 int eposs[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
524 int eposm[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
525 int epe[4], eps[4], epm[4];
526 int i, ie, is, im, j;
527
528 /* Again, ep is the hardest part */
529 if (f.epose) {
530 for (i = 0, ie = 0; i < 12; i++) {
531 for (j = 0; j < 4; j++) {
532 if (arr.ep[i] == epe_solved[j]) {
533 epe[ie++] = j;
534 epose[i] = 1;
535 }
536 }
537 }
538 ret.epose = epos_from_arrays(epose, epe);
539 }
540
541 if (f.eposs) {
542 for (i = 0, is = 0; i < 12; i++) {
543 for (j = 0; j < 4; j++) {
544 if (arr.ep[i] == eps_solved[j]) {
545 eps[is++] = j;
546 eposs[i] = 1;
547 }
548 }
549 }
550 for (i = 0; i < 4; i++)
551 swap(&eposs[eps_solved[i]], &eposs[i+8]);
552 ret.eposs = epos_from_arrays(eposs, eps);
553 }
554
555 if (f.eposm) {
556 for (i = 0, im = 0; i < 12; i++) {
557 for (j = 0; j < 4; j++) {
558 if (arr.ep[i] == epm_solved[j]) {
559 epm[im++] = j;
560 eposm[i] = 1;
561 }
562 }
563 }
564 for (i = 0; i < 4; i++)
565 swap(&eposm[epm_solved[i]], &eposm[i+8]);
566 ret.eposm = epos_from_arrays(eposm, epm);
567 }
568
569 if (f.eofb)
570 ret.eofb = digit_array_to_int(arr.eofb, 11, 2);
571 if (f.eorl)
572 ret.eorl = digit_array_to_int(arr.eorl, 11, 2);
573 if (f.eoud)
574 ret.eoud = digit_array_to_int(arr.eoud, 11, 2);
575 if (f.cp)
576 ret.cp = perm_to_index(arr.cp, 8);
577 if (f.coud)
578 ret.coud = digit_array_to_int(arr.coud, 7, 3);
579 if (f.corl)
580 ret.corl = digit_array_to_int(arr.corl, 7, 3);
581 if (f.cofb)
582 ret.cofb = digit_array_to_int(arr.cofb, 7, 3);
583 if (f.cpos)
584 ret.cpos = perm_to_index(arr.cpos, 6);
585
586 return ret;
587}
588
589static int
590binomial(int n, int k)
591{
592 if (n < 0 || k < 0 || k > n)
593 return 0;
594
595 return factorial(n) / (factorial(k) * factorial(n-k));
596}
597
598static Cube
599compose_filtered(Cube c2, Cube c1, PieceFilter f)
600{
601 CubeArray arr;
602 Cube ret;
603
604 alloc_cubearray(&arr, f);
605 cube_to_arrays(c2, &arr, f);
606 ret = move_via_arrays(arr, c1, f);
607 free_cubearray(&arr, f);
608
609 return ret;
610}
611
612static void
613cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f)
614{
615 int epose[12], eposs[12], eposm[12];
616 int epe[4], eps[4], epm[4];
617 int i, ie, is, im;
618
619 /* ep is the hardest */
620 if (f.epose || f.eposs || f.eposm)
621 for (i = 0; i < 12; i++)
622 arr->ep[i] = -1;
623
624 if (f.epose) {
625 index_to_perm(cube.epose % factorial(4), 4, epe);
626 index_to_subset(cube.epose / factorial(4), 12, 4, epose);
627 for (i = 0, ie = 0; i < 12; i++)
628 if (epose[i])
629 arr->ep[i] = epe_solved[epe[ie++]];
630 }
631
632 if (f.eposs) {
633 index_to_perm(cube.eposs % factorial(4), 4, eps);
634 index_to_subset(cube.eposs / factorial(4), 12, 4, eposs);
635 for (i = 0; i < 4; i++)
636 swap(&eposs[eps_solved[i]], &eposs[i+8]);
637 for (i = 0, is = 0; i < 12; i++)
638 if (eposs[i])
639 arr->ep[i] = eps_solved[eps[is++]];
640 }
641
642 if (f.eposm) {
643 index_to_perm(cube.eposm % factorial(4), 4, epm);
644 index_to_subset(cube.eposm / factorial(4), 12, 4, eposm);
645 for (i = 0; i < 4; i++)
646 swap(&eposm[epm_solved[i]], &eposm[i+8]);
647 for (i = 0, im = 0; i < 12; i++)
648 if (eposm[i])
649 arr->ep[i] = epm_solved[epm[im++]];
650 }
651
652 /* All the others */
653 if (f.eofb)
654 int_to_sum_zero_array(cube.eofb, 2, 12, arr->eofb);
655 if (f.eorl)
656 int_to_sum_zero_array(cube.eorl, 2, 12, arr->eorl);
657 if (f.eoud)
658 int_to_sum_zero_array(cube.eoud, 2, 12, arr->eoud);
659 if (f.cp)
660 index_to_perm(cube.cp, 8, arr->cp);
661 if (f.coud)
662 int_to_sum_zero_array(cube.coud, 3, 8, arr->coud);
663 if (f.corl)
664 int_to_sum_zero_array(cube.corl, 3, 8, arr->corl);
665 if (f.cofb)
666 int_to_sum_zero_array(cube.cofb, 3, 8, arr->cofb);
667 if (f.cpos)
668 index_to_perm(cube.cpos, 6, arr->cpos);
669}
670
671static int
672digit_array_to_int(int *a, int n, int b)
673{
674 int i, ret = 0, p = 1;
675
676 for (i = 0; i < n; i++, p *= b)
677 ret += a[i] * p;
678
679 return ret;
680}
681
682static int
683edge_slice(Edge e) {
684 if (e == FR || e == FL || e == BL || e == BR)
685 return 0;
686 if (e == UR || e == UL || e == DR || e == DL)
687 return 1;
688
689 return 2;
690}
691
692static uint16_t
693epos_from_arrays(int *epos, int *ep)
694{
695 return factorial4 * subset_to_index(epos,12,4) + perm_to_index(ep,4);
696}
697
698static int
699factorial(int n)
700{
701 int i, ret = 1;
702
703 if (n < 0)
704 return 0;
705
706 for (i = 1; i <= n; i++)
707 ret *= i;
708
709 return ret;
710}
711
712static void
713free_alglist(AlgList *l)
714{
715 AlgListNode *aux, *i = l->first;
716
717 while (i != NULL) {
718 aux = i->next;
719 free(i);
720 i = aux;
721 }
722 free(l);
723
724 return;
725}
726
727static void
728free_cubearray(CubeArray *arr, PieceFilter f)
729{
730 if (f.epose || f.eposs || f.eposm)
731 free(arr->ep);
732 if (f.eofb)
733 free(arr->eofb);
734 if (f.eorl)
735 free(arr->eorl);
736 if (f.eoud)
737 free(arr->eoud);
738 if (f.cp)
739 free(arr->cp);
740 if (f.coud)
741 free(arr->coud);
742 if (f.corl)
743 free(arr->corl);
744 if (f.cofb)
745 free(arr->cofb);
746 if (f.cpos)
747 free(arr->cpos);
748}
749
750static void
751index_to_perm(int p, int n, int *r)
752{
753 int *a = malloc(n * sizeof(int));
754 int i, j, c;
755
756 for (i = 0; i < n; i++)
757 a[i] = 0;
758
759 if (p < 0 || p >= factorial(n))
760 for (i = 0; i < n; i++)
761 r[i] = -1;
762
763 for (i = 0; i < n; i++) {
764 c = 0;
765 j = 0;
766 while (c <= p / factorial(n-i-1))
767 c += a[j++] ? 0 : 1;
768 r[i] = j-1;
769 a[j-1] = 1;
770 p %= factorial(n-i-1);
771 }
772
773 free(a);
774}
775
776static void
777index_to_subset(int s, int n, int k, int *r)
778{
779 int i, j, v;
780
781 if (s < 0 || s >= binomial(n, k)) {
782 for (i = 0; i < n; i++)
783 r[i] = -1;
784 return;
785 }
786
787 for (i = 0; i < n; i++) {
788 if (k == n-i) {
789 for (j = i; j < n; j++)
790 r[j] = 1;
791 return;
792 }
793
794 if (k == 0) {
795 for (j = i; j < n; j++)
796 r[j] = 0;
797 return;
798 }
799
800 v = binomial(n-i-1, k);
801 if (s >= v) {
802 r[i] = 1;
803 k--;
804 s -= v;
805 } else {
806 r[i] = 0;
807 }
808 }
809}
810
811static void
812init_auxtables()
813{
814 Cube c1, c2;
815 int i, j, k;
816 bool cij, p1, p2;
817
818 for (i = 0; i < NMOVES; i++) {
819 for (j = 0; j < NMOVES; j++) {
820 c1 = apply_move(i, apply_move(j, (Cube){0}));
821 c2 = apply_move(j, apply_move(i, (Cube){0}));
822 commute[i][j] = equal(c1, c2);
823 }
824 }
825
826 for (i = 0; i < NMOVES; i++) {
827 for (j = 0; j < NMOVES; j++) {
828 for (k = 0; k < NMOVES; k++) {
829 p1 = j && (j-(j-1)%3) == (k-(k-1)%3);
830 p2 = i && (i-(i-1)%3) == (k-(k-1)%3);
831 cij = commute[i][j];
832 possible_next[i][j][k] = !(p1 || (cij && p2));
833 }
834 }
835 }
836
837 for (i = 0; i < NMOVES; i++)
838 inverse_move_aux[i] =
839 i == NULLMOVE ? NULLMOVE : i + 2 - 2*((i-1)%3);
840
841 /* Is there a more elegant way? */
842 inverse_trans_aux[uf] = uf;
843 inverse_trans_aux[ur] = ul;
844 inverse_trans_aux[ul] = ur;
845 inverse_trans_aux[ub] = ub;
846
847 inverse_trans_aux[df] = df;
848 inverse_trans_aux[dr] = dr;
849 inverse_trans_aux[dl] = dl;
850 inverse_trans_aux[db] = db;
851
852 inverse_trans_aux[rf] = lf;
853 inverse_trans_aux[rd] = bl;
854 inverse_trans_aux[rb] = rb;
855 inverse_trans_aux[ru] = fr;
856
857 inverse_trans_aux[lf] = rf;
858 inverse_trans_aux[ld] = br;
859 inverse_trans_aux[lb] = lb;
860 inverse_trans_aux[lu] = fl;
861
862 inverse_trans_aux[fu] = fu;
863 inverse_trans_aux[fr] = ru;
864 inverse_trans_aux[fd] = bu;
865 inverse_trans_aux[fl] = lu;
866
867 inverse_trans_aux[bu] = fd;
868 inverse_trans_aux[br] = ld;
869 inverse_trans_aux[bd] = bd;
870 inverse_trans_aux[bl] = rd;
871
872 inverse_trans_aux[mirror] = mirror;
873}
874
875static void
876init_moves() {
877 Cube c;
878 CubeArray arrs;
879 int i, j;
880 uint16_t ui;
881 Move m;
882
883 /* Generate all move cycles and flips; I do this regardless */
884 for (i = 0; i < NMOVES; i++) {
885 if (i == U || i == x || i == y)
886 continue;
887
888 c = (Cube){0};
889 for (j = 0; equiv_moves[i][j]; j++)
890 c = apply_move_cubearray(equiv_moves[i][j], c, pf_all);
891
892 arrs = (CubeArray){
893 edge_cycle[i],
894 eofb_flipped[i],
895 eorl_flipped[i],
896 eoud_flipped[i],
897 corner_cycle[i],
898 coud_flipped[i],
899 corl_flipped[i],
900 cofb_flipped[i],
901 center_cycle[i]
902 };
903 cube_to_arrays(c, &arrs, pf_all);
904 }
905
906 if (read_ttables_file())
907 return;
908
909 fprintf(stderr, "ttables not found, generating them.\n");
910
911 /* Initialize transition tables */
912 for (m = 0; m < NMOVES; m++) {
913 for (ui = 0; ui < factorial12/factorial8; ui++) {
914 c = (Cube){ .epose = ui };
915 c = apply_move_cubearray(m, c, pf_e);
916 epose_ttable[m][ui] = c.epose;
917
918 c = (Cube){ .eposs = ui };
919 c = apply_move_cubearray(m, c, pf_s);
920 eposs_ttable[m][ui] = c.eposs;
921
922 c = (Cube){ .eposm = ui };
923 c = apply_move_cubearray(m, c, pf_m);
924 eposm_ttable[m][ui] = c.eposm;
925 }
926 for (ui = 0; ui < pow2to11; ui++ ) {
927 c = (Cube){ .eofb = ui };
928 c = apply_move_cubearray(m, c, pf_eo);
929 eofb_ttable[m][ui] = c.eofb;
930
931 c = (Cube){ .eorl = ui };
932 c = apply_move_cubearray(m, c, pf_eo);
933 eorl_ttable[m][ui] = c.eorl;
934
935 c = (Cube){ .eoud = ui };
936 c = apply_move_cubearray(m, c, pf_eo);
937 eoud_ttable[m][ui] = c.eoud;
938 }
939 for (ui = 0; ui < pow3to7; ui++) {
940 c = (Cube){ .coud = ui };
941 c = apply_move_cubearray(m, c, pf_co);
942 coud_ttable[m][ui] = c.coud;
943
944 c = (Cube){ .corl = ui };
945 c = apply_move_cubearray(m, c, pf_co);
946 corl_ttable[m][ui] = c.corl;
947
948 c = (Cube){ .cofb = ui };
949 c = apply_move_cubearray(m, c, pf_co);
950 cofb_ttable[m][ui] = c.cofb;
951 }
952 for (ui = 0; ui < factorial8; ui++) {
953 c = (Cube){ .cp = ui };
954 c = apply_move_cubearray(m, c, pf_cp);
955 cp_ttable[m][ui] = c.cp;
956 }
957 for (ui = 0; ui < factorial6; ui++) {
958 c = (Cube){ .cpos = ui };
959 c = apply_move_cubearray(m, c, pf_cpos);
960 cpos_ttable[m][ui] = c.cpos;
961 }
962 }
963
964 if (!write_ttables_file())
965 fprintf(stderr, "Error writing ttables\n");
966}
967
968static void
969init_trans() {
970 Cube aux, cube, c[3];
971 CubeArray epcp;
972 int eparr[12], eoarr[12];
973 int cparr[8], coarr[8];
974 int i;
975 bool b1, b2, b3;
976 uint16_t ui;
977 Move mi, move;
978 Trans r, m;
979
980 /* Compute sources */
981 for (i = 0; i < NTRANS; i++) {
982 if (i == mirror)
983 cube = (Cube){0};
984 else
985 cube = apply_alg(rotation_algs[i], (Cube){0});
986
987 epose_source[i] = edge_slice(edge_at(cube, FR));
988 eposs_source[i] = edge_slice(edge_at(cube, UR));
989 eposm_source[i] = edge_slice(edge_at(cube, UF));
990 eofb_source[i] = center_at(cube, F_center)/2;
991 eorl_source[i] = center_at(cube, R_center)/2;
992 eoud_source[i] = center_at(cube, U_center)/2;
993 coud_source[i] = center_at(cube, U_center)/2;
994 cofb_source[i] = center_at(cube, F_center)/2;
995 corl_source[i] = center_at(cube, R_center)/2;
996 }
997
998 /* Compute rotation_niss array, necessary for rotate_via_compose */
999 for (r = 0; r != mirror; r++) {
1000 concat(rotation_algs[r], rotation_algs[r], rotation_niss[r]);
1001 for (i = len(rotation_algs[r]); rotation_niss[r][i].m; i++)
1002 rotation_niss[r][i].inverse = true;
1003 }
1004
1005 if (read_rtables_file())
1006 return;
1007
1008 fprintf(stderr, "rtables not found, generating them.\n");
1009
1010 /* Initialize tables */
1011 for (m = 0; m < NTRANS; m++) {
1012 if (m == mirror) {
1013 intarrcopy(ep_mirror, eparr, 12);
1014 intarrcopy(cp_mirror, cparr, 8);
1015 } else {
1016 epcp = (CubeArray){ .ep = eparr, .cp = cparr };
1017 cube = apply_alg(rotation_algs[m], (Cube){0});
1018 cube_to_arrays(cube, &epcp, pf_epcp);
1019 }
1020
1021 for (ui = 0; ui < factorial12/factorial8; ui++) {
1022 c[0] = admissible_ep((Cube){ .epose = ui }, pf_e);
1023 c[1] = admissible_ep((Cube){ .eposs = ui }, pf_s);
1024 c[2] = admissible_ep((Cube){ .eposm = ui }, pf_m);
1025
1026 cube = rotate_via_compose(m,c[epose_source[m]],pf_ep);
1027 epose_rtable[m][ui] = cube.epose;
1028
1029 cube = rotate_via_compose(m,c[eposs_source[m]],pf_ep);
1030 eposs_rtable[m][ui] = cube.eposs;
1031
1032 cube = rotate_via_compose(m,c[eposm_source[m]],pf_ep);
1033 eposm_rtable[m][ui] = cube.eposm;
1034 }
1035 for (ui = 0; ui < pow2to11; ui++ ) {
1036 int_to_sum_zero_array(ui, 2, 12, eoarr);
1037 apply_permutation(eparr, eoarr, 12);
1038 eo_rtable[m][ui] = digit_array_to_int(eoarr, 11, 2);
1039 }
1040 for (ui = 0; ui < pow3to7; ui++) {
1041 int_to_sum_zero_array(ui, 3, 8, coarr);
1042 apply_permutation(cparr, coarr, 8);
1043 co_rtable[m][ui] = digit_array_to_int(coarr, 7, 3);
1044 if (m == mirror)
1045 co_rtable[m][ui] =
1046 invert_digits(co_rtable[m][ui], 3, 7);
1047 }
1048 for (ui = 0; ui < factorial8; ui++) {
1049 cube = (Cube){ .cp = ui };
1050 cube = rotate_via_compose(m, cube, pf_cp);
1051 cp_rtable[m][ui] = cube.cp;
1052 }
1053 for (ui = 0; ui < factorial6; ui++) {
1054 cube = (Cube){ .cpos = ui };
1055 cube = rotate_via_compose(m, cube, pf_cpos);
1056 cpos_rtable[m][ui] = cube.cpos;
1057 }
1058 for (mi = 0; mi < NMOVES; mi++) {
1059 if (m == mirror) {
1060 b1 = (mi >= U && mi <= Bw3);
1061 b2 = (mi >= S && mi <= E3);
1062 b3 = (mi >= x && mi <= z3);
1063 if (b1 || b2 || b3)
1064 moves_rtable[m][mi] =
1065 inverse_move_aux[mi];
1066 else
1067 moves_rtable[m][mi] = mi;
1068
1069 if ((mi-1)/3==(R-1)/3 || (mi-1)/3==(Rw-1)/3)
1070 moves_rtable[m][mi] += 3;
1071 if ((mi-1)/3==(L-1)/3 || (mi-1)/3==(L2-1)/3)
1072 moves_rtable[m][mi] -= 3;
1073 } else {
1074 aux = apply_trans(m, apply_move(mi,(Cube){0}));
1075 for (move = 0; move < NMOVES; move++) {
1076 cube = apply_move(
1077 inverse_move_aux[move], aux);
1078 if (is_solved(cube, false))
1079 moves_rtable[m][mi] = move;
1080 }
1081 }
1082 }
1083 }
1084
1085 if (!write_rtables_file())
1086 fprintf(stderr, "Error writing rtables\n");
1087}
1088
1089static void
1090int_to_digit_array(int a, int b, int n, int *r)
1091{
1092 int i;
1093
1094 if (b <= 1)
1095 for (i = 0; i < n; i++)
1096 r[i] = 0;
1097 else
1098 for (i = 0; i < n; i++, a /= b)
1099 r[i] = a % b;
1100}
1101
1102static void
1103int_to_sum_zero_array(int x, int b, int n, int *a)
1104{
1105 int i, s = 0;
1106
1107 if (b <= 1) {
1108 for (i = 0; i < n; i++)
1109 a[i] = 0;
1110 } else {
1111 int_to_digit_array(x, b, n-1, a);
1112 for (i = 0; i < n - 1; i++)
1113 s = (s + a[i]) % b;
1114 a[n-1] = (b - s) % b;
1115 }
1116}
1117
1118static void
1119intarrcopy(int *src, int *dst, int n)
1120{
1121 int i;
1122
1123 for (i = 0; i < n; i++)
1124 dst[i] = src[i];
1125}
1126
1127static int
1128invert_digits(int a, int b, int n)
1129{
1130 int i, *r = malloc(n * sizeof(int));
1131
1132 int_to_digit_array(a, b, n, r);
1133 for (i = 0; i < n; i++)
1134 r[i] = (b-r[i]) % b;
1135
1136 return digit_array_to_int(r, n, b);
1137}
1138
1139static bool
1140is_perm(int *a, int n)
1141{
1142 int *aux = malloc(n * sizeof(int));
1143 int i;
1144
1145 for (i = 0; i < n; i++)
1146 if (a[i] < 0 || a[i] >= n)
1147 return false;
1148 else
1149 aux[a[i]] = 1;
1150
1151 for (i = 0; i < n; i++)
1152 if (!aux[i])
1153 return false;
1154
1155 free(aux);
1156
1157 return true;
1158}
1159
1160static bool
1161is_subset(int *a, int n, int k)
1162{
1163 int i, sum = 0;
1164
1165 for (i = 0; i < n; i++)
1166 sum += a[i] ? 1 : 0;
1167
1168 return sum == k;
1169}
1170
1171static Cube
1172move_via_arrays(CubeArray arr, Cube c, PieceFilter f)
1173{
1174 CubeArray arrc;
1175 Cube ret;
1176
1177 alloc_cubearray(&arrc, f);
1178 cube_to_arrays(c, &arrc, f);
1179
1180 if (f.epose || f.eposs || f.eposm)
1181 apply_permutation(arr.ep, arrc.ep, 12);
1182
1183 if (f.eofb) {
1184 apply_permutation(arr.ep, arrc.eofb, 12);
1185 sum_arrays_mod(arr.eofb, arrc.eofb, 12, 2);
1186 }
1187
1188 if (f.eorl) {
1189 apply_permutation(arr.ep, arrc.eorl, 12);
1190 sum_arrays_mod(arr.eorl, arrc.eorl, 12, 2);
1191 }
1192
1193 if (f.eoud) {
1194 apply_permutation(arr.ep, arrc.eoud, 12);
1195 sum_arrays_mod(arr.eoud, arrc.eoud, 12, 2);
1196 }
1197
1198 if (f.cp)
1199 apply_permutation(arr.cp, arrc.cp, 8);
1200
1201 if (f.coud) {
1202 apply_permutation(arr.cp, arrc.coud, 8);
1203 sum_arrays_mod(arr.coud, arrc.coud, 8, 3);
1204 }
1205
1206 if (f.corl) {
1207 apply_permutation(arr.cp, arrc.corl, 8);
1208 sum_arrays_mod(arr.corl, arrc.corl, 8, 3);
1209 }
1210
1211 if (f.cofb) {
1212 apply_permutation(arr.cp, arrc.cofb, 8);
1213 sum_arrays_mod(arr.cofb, arrc.cofb, 8, 3);
1214 }
1215
1216 if (f.cpos)
1217 apply_permutation(arr.cpos, arrc.cpos, 6);
1218
1219 ret = arrays_to_cube(arrc, f);
1220 free_cubearray(&arrc, f);
1221
1222 return ret;
1223}
1224
1225static Move *
1226moveset_to_movelist(bool *moveset, Step step)
1227{
1228 Cube c;
1229 int *a = malloc(NMOVES * sizeof(int)), b[NMOVES];
1230 int na = 0, nb = 0;
1231 Move i;
1232
1233 if (moveset != NULL) {
1234 for (i = NULLMOVE+1; i < NMOVES; i++) {
1235 if (moveset[i]) {
1236 c = apply_move(i, (Cube){0});
1237 if (step.f != NULL && step.f(c)) {
1238 a[na++] = i;
1239 } else {
1240 b[nb++] = i;
1241 }
1242 }
1243 }
1244 }
1245
1246 intarrcopy(b, a+na, nb);
1247 a[na+nb] = NULLMOVE;
1248
1249 return (Move *)a;
1250}
1251
1252static AlgList *
1253new_alglist()
1254{
1255 AlgList *ret = malloc(sizeof(AlgList));
1256
1257 ret->len = 0;
1258 ret->first = NULL;
1259 ret->last = NULL;
1260
1261 return ret;
1262}
1263
1264static int
1265perm_sign(int *a, int n)
1266{
1267 int i, j, ret = 0;
1268
1269 if (!is_perm(a,n))
1270 return -1;
1271
1272 for (i = 0; i < n; i++)
1273 for (j = i+1; j < n; j++)
1274 ret += (a[i] > a[j]) ? 1 : 0;
1275
1276 return ret % 2;
1277}
1278
1279static int
1280perm_to_index(int *a, int n)
1281{
1282 int i, j, c, ret = 0;
1283
1284 if (!is_perm(a, n))
1285 return -1;
1286
1287 for (i = 0; i < n; i++) {
1288 c = 0;
1289 for (j = i+1; j < n; j++)
1290 c += (a[i] > a[j]) ? 1 : 0;
1291 ret += factorial(n-i-1) * c;
1292 }
1293
1294 return ret;
1295}
1296
1297static int
1298powint(int a, int b)
1299{
1300 if (b < 0)
1301 return 0; /* Truncate */
1302 if (b == 0)
1303 return 1;
1304
1305 if (b % 2)
1306 return a * powint(a, b-1);
1307 else
1308 return powint(a*a, b/2);
1309}
1310
1311static bool
1312read_rtables_file()
1313{
1314 FILE *ttf;
1315 int b = sizeof(uint16_t);
1316 bool r = true;
1317 Move m;
1318
1319 if ((ttf = fopen("rtables", "rb")) != NULL) {
1320 for (m = 0; m < NTRANS; m++) {
1321 r = r && fread(epose_rtable[m],b,me[0],ttf) == me[0];
1322 r = r && fread(eposs_rtable[m],b,me[1],ttf) == me[1];
1323 r = r && fread(eposm_rtable[m],b,me[2],ttf) == me[2];
1324 r = r && fread(eo_rtable[m],b,me[3],ttf) == me[3];
1325 r = r && fread(cp_rtable[m],b,me[6],ttf) == me[6];
1326 r = r && fread(co_rtable[m],b,me[7],ttf) == me[7];
1327 r = r && fread(cpos_rtable[m],b,me[10],ttf) == me[10];
1328 r = r && fread(moves_rtable[m],b,me[11],ttf) == me[11];
1329 }
1330 fclose(ttf);
1331 return r;
1332 } else {
1333 return false;
1334 }
1335}
1336
1337static bool
1338read_ttables_file()
1339{
1340 FILE *ttf;
1341 int m, b = sizeof(uint16_t);
1342 bool r = true;
1343
1344 if ((ttf = fopen("ttables", "rb")) != NULL) {
1345 for (m = 0; m < NMOVES; m++) {
1346 r = r && fread(epose_ttable[m],b,me[0],ttf) == me[0];
1347 r = r && fread(eposs_ttable[m],b,me[1],ttf) == me[1];
1348 r = r && fread(eposm_ttable[m],b,me[2],ttf) == me[2];
1349 r = r && fread(eofb_ttable[m],b,me[3],ttf) == me[3];
1350 r = r && fread(eorl_ttable[m],b,me[4],ttf) == me[4];
1351 r = r && fread(eoud_ttable[m],b,me[5],ttf) == me[5];
1352 r = r && fread(cp_ttable[m],b,me[6],ttf) == me[6];
1353 r = r && fread(coud_ttable[m],b,me[7],ttf) == me[7];
1354 r = r && fread(corl_ttable[m],b,me[8],ttf) == me[8];
1355 r = r && fread(cofb_ttable[m],b,me[9],ttf) == me[9];
1356 r = r && fread(cpos_ttable[m],b,me[10],ttf) == me[10];
1357 }
1358 fclose(ttf);
1359 return r;
1360 } else {
1361 return false;
1362 }
1363}
1364
1365static bool
1366realloc_alg(Alg alg, int n)
1367{
1368 if (n+1 >= BASEALGLEN) {
1369 if (reallocarray(alg, n+2, sizeof(NissMove)) == NULL) {
1370 fprintf(stderr, "Error reallocating alg\n");
1371 return false;
1372 }
1373 }
1374
1375 return true;
1376}
1377
1378static Cube
1379rotate_via_compose(Trans r, Cube c, PieceFilter f)
1380{
1381 Cube ret;
1382 CubeArray ma = {
1383 .ep = ep_mirror,
1384 .eofb = zero12,
1385 .eorl = zero12,
1386 .eoud = zero12,
1387 .cp = cp_mirror,
1388 .coud = zero8,
1389 .corl = zero8,
1390 .cofb = zero8,
1391 .cpos = cpos_mirror
1392 };
1393
1394 if (r != mirror) {
1395 ret = apply_alg_filtered(rotation_niss[r], c, f);
1396 } else {
1397 ret = move_via_arrays(ma, (Cube){0}, f);
1398 ret = compose_filtered(c, ret, f);
1399 ret = move_via_arrays(ma, ret, f);
1400 }
1401
1402 return ret;
1403}
1404
1405static void
1406solve_dfs(Cube c, Step s, SolveOptions opts, DfsData dd)
1407{
1408 DfsData newdd;
1409 Move move;
1410 NissMove nm;
1411 int i;
1412 bool found_many, prune, niss_makes_sense;
1413
1414 found_many = dd.sols->len >= opts.max_solutions;
1415 prune = (!opts.can_niss || dd.niss) && dd.m + s.f(c) > dd.d;
1416 if (found_many || prune)
1417 return;
1418
1419 if (!s.f(c)) {
1420 if (dd.m == dd.d)
1421 append_alg(dd.sols, dd.current_alg);
1422 return;
1423 }
1424
1425 for (i = 0; opts.sorted_moves[i] != NULLMOVE; i++) {
1426 move = opts.sorted_moves[i];
1427 if (possible_next[dd.last2][dd.last1][move]) {
1428 nm = (NissMove){ .m = move, .inverse = dd.niss };
1429 newdd = (DfsData) {
1430 .d = dd.d,
1431 .m = dd.m + 1,
1432 .niss = dd.niss,
1433 .last1 = move,
1434 .last2 = dd.last1,
1435 .sols = dd.sols,
1436 .current_alg = dd.current_alg,
1437 };
1438
1439 append_move(dd.current_alg, nm);
1440 solve_dfs(apply_move(move, c), s, opts, newdd);
1441 remove_last_moves(dd.current_alg, 1);
1442 }
1443 }
1444
1445 niss_makes_sense = !dd.m || (s.f(apply_move(dd.last1, (Cube){0})));
1446 if (opts.can_niss && !dd.niss && niss_makes_sense) {
1447 newdd = (DfsData) {
1448 .d = dd.d,
1449 .m = dd.m,
1450 .niss = true,
1451 .last1 = NULLMOVE,
1452 .last2 = NULLMOVE,
1453 .sols = dd.sols,
1454 .current_alg = dd.current_alg,
1455 };
1456 solve_dfs(inverse_cube(c), s, opts, newdd);
1457 }
1458}
1459
1460static int
1461subset_to_index(int *a, int n, int k)
1462{
1463 int i, ret = 0;
1464
1465 if (!is_subset(a, n, k))
1466 return binomial(n, k);
1467
1468 for (i = 0; i < n; i++) {
1469 if (k == n-i)
1470 return ret;
1471 if (a[i]) {
1472 ret += binomial(n-i-1, k);
1473 k--;
1474 }
1475 }
1476
1477 return ret;
1478}
1479
1480static void
1481sum_arrays_mod(int *src, int *dst, int n, int m)
1482{
1483 int i;
1484
1485 for (i = 0; i < n; i++)
1486 dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m;
1487}
1488
1489static void
1490swap(int *a, int *b)
1491{
1492 int aux;
1493
1494 aux = *a;
1495 *a = *b;
1496 *b = aux;
1497}
1498
1499static bool
1500write_rtables_file()
1501{
1502 FILE *ttf;
1503 bool r = true;
1504 int b = sizeof(uint16_t);
1505 Move m;
1506
1507 if ((ttf = fopen("rtables", "wb")) != NULL) {
1508 for (m = 0; m < NTRANS; m++) {
1509 r = r && fwrite(epose_rtable[m],b,me[0], ttf) == me[0];
1510 r = r && fwrite(eposs_rtable[m],b,me[1], ttf) == me[1];
1511 r = r && fwrite(eposm_rtable[m],b,me[2], ttf) == me[2];
1512 r = r && fwrite(eo_rtable[m],b,me[3], ttf) == me[3];
1513 r = r && fwrite(cp_rtable[m],b,me[6], ttf) == me[6];
1514 r = r && fwrite(co_rtable[m],b,me[7], ttf) == me[7];
1515 r = r && fwrite(cpos_rtable[m],b,me[10],ttf) == me[10];
1516 r = r && fwrite(moves_rtable[m],b,me[11],ttf)== me[11];
1517 }
1518 fclose(ttf);
1519 return r;
1520 } else {
1521 return false;
1522 }
1523}
1524
1525static bool
1526write_ttables_file()
1527{
1528 FILE *ttf;
1529 int m, b = sizeof(uint16_t);;
1530 bool r = true;
1531
1532 if ((ttf = fopen("ttables", "wb")) != NULL) {
1533 for (m = 0; m < NMOVES; m++) {
1534 r = r && fwrite(epose_ttable[m],b,me[0],ttf) == me[0];
1535 r = r && fwrite(eposs_ttable[m],b,me[1],ttf) == me[1];
1536 r = r && fwrite(eposm_ttable[m],b,me[2],ttf) == me[2];
1537 r = r && fwrite(eofb_ttable[m],b,me[3],ttf) == me[3];
1538 r = r && fwrite(eorl_ttable[m],b,me[4],ttf) == me[4];
1539 r = r && fwrite(eoud_ttable[m],b,me[5],ttf) == me[5];
1540 r = r && fwrite(cp_ttable[m],b,me[6],ttf) == me[6];
1541 r = r && fwrite(coud_ttable[m],b,me[7],ttf) == me[7];
1542 r = r && fwrite(corl_ttable[m],b,me[8],ttf) == me[8];
1543 r = r && fwrite(cofb_ttable[m],b,me[9],ttf) == me[9];
1544 r = r && fwrite(cpos_ttable[m],b,me[10],ttf) == me[10];
1545 }
1546 fclose(ttf);
1547 return r;
1548 } else {
1549 return false;
1550 }
1551}
1552
1553/* Public functions implementation *******************************************/
1554
1555Cube
1556apply_alg(Alg alg, Cube cube)
1557{
1558 return apply_alg_filtered(alg, cube, pf_all);
1559}
1560
1561Cube
1562apply_move(Move m, Cube cube)
1563{
1564 Cube moved = {0};
1565
1566 moved.epose = epose_ttable[m][cube.epose];
1567 moved.eposs = eposs_ttable[m][cube.eposs];
1568 moved.eposm = eposm_ttable[m][cube.eposm];
1569 moved.eofb = eofb_ttable[m][cube.eofb];
1570 moved.eorl = eorl_ttable[m][cube.eorl];
1571 moved.eoud = eoud_ttable[m][cube.eoud];
1572 moved.coud = coud_ttable[m][cube.coud];
1573 moved.cofb = cofb_ttable[m][cube.cofb];
1574 moved.corl = corl_ttable[m][cube.corl];
1575 moved.cp = cp_ttable[m][cube.cp];
1576 moved.cpos = cpos_ttable[m][cube.cpos];
1577
1578 return moved;
1579}
1580
1581Cube
1582apply_trans(Trans t, Cube cube)
1583{
1584 Cube transformed = {0};
1585 uint16_t aux_epos[3] = { cube.epose, cube.eposs, cube.eposm };
1586 uint16_t aux_eo[3] = { cube.eoud, cube.eorl, cube.eofb };
1587 uint16_t aux_co[3] = { cube.coud, cube.corl, cube.cofb };
1588
1589 transformed.epose = epose_rtable[t][aux_epos[epose_source[t]]];
1590 transformed.eposs = eposs_rtable[t][aux_epos[eposs_source[t]]];
1591 transformed.eposm = eposm_rtable[t][aux_epos[eposm_source[t]]];
1592 transformed.eofb = eo_rtable[t][aux_eo[eofb_source[t]]];
1593 transformed.eorl = eo_rtable[t][aux_eo[eorl_source[t]]];
1594 transformed.eoud = eo_rtable[t][aux_eo[eoud_source[t]]];
1595 transformed.coud = co_rtable[t][aux_co[coud_source[t]]];
1596 transformed.corl = co_rtable[t][aux_co[corl_source[t]]];
1597 transformed.cofb = co_rtable[t][aux_co[cofb_source[t]]];
1598 transformed.cp = cp_rtable[t][cube.cp];
1599 transformed.cpos = cpos_rtable[t][cube.cpos];
1600
1601 return transformed;
1602}
1603
1604/* TODO: this has to be changed using pre-computations */
1605bool
1606block_solved(Cube cube, Block block)
1607{
1608 CubeArray arr;
1609 int i;
1610 bool ret = true;
1611
1612 alloc_cubearray(&arr, pf_all);
1613 cube_to_arrays(cube, &arr, pf_all);
1614
1615 for (i = 0; i < 12; i++)
1616 ret = ret && !(block.edge[i] && (arr.ep[i] != i || arr.eofb[i]));
1617 for (i = 0; i < 8; i++)
1618 ret = ret && !(block.corner[i] && (arr.cp[i] != i || arr.coud[i]));
1619 for (i = 0; i < 6; i++)
1620 ret = ret && !(block.center[i] && arr.cpos[i] != i);
1621
1622 free_cubearray(&arr, pf_all);
1623
1624 return ret;
1625}
1626
1627Center
1628center_at(Cube cube, Center c)
1629{
1630 int ret;
1631 CubeArray arr;
1632
1633 alloc_cubearray(&arr, pf_cpos);
1634 cube_to_arrays(cube, &arr, pf_cpos);
1635 ret = arr.cpos[c];
1636 free_cubearray(&arr, pf_cpos);
1637
1638 return ret;
1639}
1640
1641Cube
1642compose(Cube c2, Cube c1)
1643{
1644 return compose_filtered(c2, c1, pf_all);
1645}
1646
1647Corner
1648corner_at(Cube cube, Corner c)
1649{
1650 int ret;
1651 CubeArray arr;
1652
1653 alloc_cubearray(&arr, pf_cp);
1654 cube_to_arrays(cube, &arr, pf_cp);
1655 ret = arr.cp[c];
1656 free_cubearray(&arr, pf_cp);
1657
1658 return ret;
1659}
1660
1661Edge
1662edge_at(Cube cube, Edge e)
1663{
1664 int ret;
1665 CubeArray arr;
1666
1667 alloc_cubearray(&arr, pf_ep);
1668 cube_to_arrays(cube, &arr, pf_ep);
1669 ret = arr.ep[e];
1670 free_cubearray(&arr, pf_ep);
1671
1672 return ret;
1673}
1674
1675bool
1676equal(Cube c1, Cube c2)
1677{
1678 return c1.eofb == c2.eofb &&
1679 c1.epose == c2.epose &&
1680 c1.eposs == c2.eposs &&
1681 c1.eposm == c2.eposm &&
1682 c1.coud == c2.coud &&
1683 c1.cp == c2.cp &&
1684 c1.cpos == c2.cpos;
1685}
1686
1687Cube
1688inverse_cube(Cube cube)
1689{
1690 CubeArray arr, inv;
1691 Cube ret;
1692 int i;
1693
1694 alloc_cubearray(&arr, pf_all);
1695 alloc_cubearray(&inv, pf_all);
1696
1697 cube_to_arrays(cube, &arr, pf_all);
1698
1699 for (i = 0; i < 12; i++) {
1700 inv.ep[arr.ep[i]] = i;
1701 inv.eofb[arr.ep[i]] = arr.eofb[i];
1702 inv.eorl[arr.ep[i]] = arr.eorl[i];
1703 inv.eoud[arr.ep[i]] = arr.eoud[i];
1704 }
1705
1706 for (i = 0; i < 8; i++) {
1707 inv.cp[arr.cp[i]] = i;
1708 inv.coud[arr.cp[i]] = (3 - arr.coud[i]) % 3;
1709 inv.corl[arr.cp[i]] = (3 - arr.corl[i]) % 3;
1710 inv.cofb[arr.cp[i]] = (3 - arr.cofb[i]) % 3;
1711 }
1712
1713 for (int i = 0; i < 6; i++)
1714 inv.cpos[arr.cpos[i]] = i;
1715
1716 ret = arrays_to_cube(inv, pf_all);
1717 free_cubearray(&arr, pf_all);
1718 free_cubearray(&inv, pf_all);
1719
1720 return ret;
1721}
1722
1723Move
1724inverse_move(Move m)
1725{
1726 return inverse_move_aux[m];
1727}
1728
1729Trans
1730inverse_trans(Trans t)
1731{
1732 return inverse_trans_aux[t];
1733}
1734
1735bool
1736is_solved(Cube cube, bool reorient)
1737{
1738 int i;
1739
1740 if (reorient)
1741 for (i = 0; i < NROTATIONS; i++)
1742 if (is_solved(apply_alg(rotation_algs[i], cube), false))
1743 return true;
1744
1745 return equal(cube, (Cube){0});
1746}
1747
1748int
1749piece_orientation(Cube cube, int piece, char *orientation)
1750{
1751 int arr[12], n, b;
1752 uint16_t x;
1753
1754 if (!strcmp(orientation, "eofb")) {
1755 x = cube.eofb;
1756 n = 12;
1757 b = 2;
1758 } else if (!strcmp(orientation, "eorl")) {
1759 x = cube.eorl;
1760 n = 12;
1761 b = 2;
1762 } else if (!strcmp(orientation, "eoud")) {
1763 x = cube.eoud;
1764 n = 12;
1765 b = 2;
1766 } else if (!strcmp(orientation, "coud")) {
1767 x = cube.coud;
1768 n = 8;
1769 b = 3;
1770 } else if (!strcmp(orientation, "corl")) {
1771 x = cube.corl;
1772 n = 8;
1773 b = 3;
1774 } else if (!strcmp(orientation, "cofb")) {
1775 x = cube.cofb;
1776 n = 8;
1777 b = 3;
1778 } else {
1779 return -1;
1780 }
1781
1782 int_to_sum_zero_array(x, b, n, arr);
1783 if (piece < n)
1784 return arr[piece];
1785
1786 return -1;
1787}
1788
1789void
1790print_cube(Cube cube)
1791{
1792 CubeArray arr;
1793
1794 alloc_cubearray(&arr, pf_all);
1795 cube_to_arrays(cube, &arr, pf_all);
1796
1797 for (int i = 0; i < 12; i++)
1798 printf(" %s ", edge_string[arr.ep[i]]);
1799 printf("\n");
1800
1801 for (int i = 0; i < 12; i++)
1802 printf(" %c ", arr.eofb[i] + '0');
1803 printf("\n");
1804
1805 for (int i = 0; i < 8; i++)
1806 printf("%s ", corner_string[arr.cp[i]]);
1807 printf("\n");
1808
1809 for (int i = 0; i < 8; i++)
1810 printf(" %c ", arr.coud[i] + '0');
1811 printf("\n");
1812
1813 for (int i = 0; i < 6; i++)
1814 printf(" %s ", center_string[arr.cpos[i]]);
1815 printf("\n");
1816
1817 free_cubearray(&arr, pf_all);
1818}
1819
1820void
1821concat(Alg src1, Alg src2, Alg dest)
1822{
1823 int n1 = len(src1), n2 = len(src2);
1824
1825 if (!realloc_alg(dest, n1+n2))
1826 return;
1827
1828 copy_alg(src1, dest);
1829 copy_alg(src2, dest + n1);
1830}
1831
1832void
1833copy_alg(Alg src, Alg dest)
1834{
1835 int i, n = len(src);
1836
1837 if (!realloc_alg(dest, n))
1838 return;
1839
1840 for (i = 0; src[i].m != NULLMOVE; i++)
1841 dest[i] = src[i];
1842 dest[i].m = NULLMOVE;
1843}
1844
1845void
1846invert_alg(Alg src, Alg dest)
1847{
1848 Move m;
1849 int i, n = len(src);
1850
1851 if (!realloc_alg(dest, n))
1852 return;
1853
1854 for (i = 0; i < n; i++) {
1855 m = inverse_move_aux[src[i].m];
1856 dest[n-i-1] = (NissMove) { .m = m, .inverse = src[i].inverse };
1857 }
1858 dest[n].m = NULLMOVE;
1859}
1860
1861int
1862len(Alg alg)
1863{
1864 int i;
1865
1866 for (i = 0; alg[i].m != NULLMOVE; i++);
1867
1868 return i;
1869}
1870
1871Alg
1872new_alg(char *str)
1873{
1874 Alg alg = malloc(BASEALGLEN * sizeof(NissMove));
1875 int i;
1876 bool niss = false;
1877 Move j, m;
1878 NissMove nm;
1879
1880 alg[0] = (NissMove){ .m = NULLMOVE };
1881 for (i = 0; str[i]; i++) {
1882 if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n')
1883 continue;
1884
1885 if (str[i] == '(' && niss) {
1886 fprintf(stderr, "Error reading moves: nested ( )\n");
1887 return alg;
1888 }
1889
1890 if (str[i] == ')' && !niss) {
1891 fprintf(stderr, "Error reading moves: unmatched )\n");
1892 return alg;
1893 }
1894
1895 if (str[i] == '(' || str[i] == ')') {
1896 niss = !niss;
1897 continue;
1898 }
1899
1900 for (j = 0; j < NMOVES; j++) {
1901 if (str[i] == move_string[j][0]) {
1902 m = j;
1903 if (m <= B && str[i+1]=='w') {
1904 m += Uw - U;
1905 i++;
1906 }
1907 if (str[i+1]=='2') {
1908 m += 1;
1909 i++;
1910 } else if (str[i+1]=='\'' || str[i+1]=='3') {
1911 m += 2;
1912 i++;
1913 }
1914 nm = (NissMove){ .m = m, .inverse = niss };
1915 append_move(alg, nm);
1916 break;
1917 }
1918 }
1919 }
1920 append_move(alg, (NissMove){ .m = NULLMOVE });
1921
1922 return alg;
1923}
1924
1925void
1926print_alg(Alg alg)
1927{
1928 char fill[4];
1929 int i;
1930 bool niss = false;
1931
1932 for (i = 0; alg[i].m != NULLMOVE; i++) {
1933 if (!niss && alg[i].inverse)
1934 strcpy(fill, i == 0 ? "(" : " (");
1935 if (niss && !alg[i].inverse)
1936 strcpy(fill, ") ");
1937 if (niss == alg[i].inverse)
1938 strcpy(fill, i == 0 ? "" : " ");
1939
1940 printf("%s%s", fill, move_string[alg[i].m]);
1941 niss = alg[i].inverse;
1942 }
1943 printf("%s\n", niss ? ")" : "");
1944}
1945
1946void
1947remove_last_moves(Alg alg, int k)
1948{
1949 int n = len(alg);
1950 int i = max(0, n-k);
1951
1952 alg[i].m = NULLMOVE;
1953}
1954
1955AlgList *
1956solve(Cube cube, Step step, SolveOptions opts)
1957{
1958 AlgList *sols = new_alglist();
1959 AlgListNode *node;
1960 Cube c;
1961 DfsData dd;
1962 int i;
1963
1964 if (step.ready != NULL && !step.ready(cube))
1965 return sols;
1966
1967 if (opts.sorted_moves == NULL)
1968 opts.sorted_moves = moveset_to_movelist(opts.moveset, step);
1969
1970 for (i = opts.min_moves; i <= opts.max_moves; i++) {
1971 if (sols->len && opts.optimal_only)
1972 break;
1973
1974 c = apply_trans(opts.pre_trans, cube);
1975 dd = (DfsData) {
1976 .d = i,
1977 .m = 0,
1978 .niss = false,
1979 .last1 = NULLMOVE,
1980 .last2 = NULLMOVE,
1981 .sols = sols,
1982 .current_alg = new_alg("")
1983 };
1984
1985 solve_dfs(c, step, opts, dd);
1986 }
1987
1988 for (node = sols->first; node != NULL; node = node->next)
1989 transform_alg(inverse_trans_aux[opts.pre_trans], node->alg);
1990
1991 return sols;
1992}
1993
1994void
1995transform_alg(Trans t, Alg alg)
1996{
1997 int i;
1998
1999 for (i = 0; alg[i].m != NULLMOVE; i++)
2000 alg[i].m = moves_rtable[t][alg[i].m];
2001}
2002
2003
2004void
2005init()
2006{
2007 init_moves();
2008 init_auxtables();
2009 init_trans();
2010}
diff --git a/old/2021-06-02-cleanedup/cube.h b/old/2021-06-02-cleanedup/cube.h
new file mode 100644
index 0000000..f1559a4
--- /dev/null
+++ b/old/2021-06-02-cleanedup/cube.h
@@ -0,0 +1,179 @@
1#include <stdio.h>
2#include <stdbool.h>
3#include <stdint.h>
4#include <stdlib.h>
5#include <string.h>
6
7/* Constants ****************************************************************/
8
9#define NMOVES (z3+1)
10#define NTRANS (mirror+1)
11#define NROTATIONS (NTRANS-1)
12
13/* Typedefs *****************************************************************/
14
15typedef enum center Center;
16typedef enum corner Corner;
17typedef enum edge Edge;
18typedef enum move Move;
19typedef enum trans Trans;
20
21typedef struct nissmove * Alg;
22typedef struct alglist AlgList;
23typedef struct alglistnode AlgListNode;
24typedef struct block Block;
25typedef struct cube Cube;
26typedef struct nissmove NissMove;
27typedef struct solveoptions SolveOptions;
28typedef struct step Step;
29
30/* Type specifications *******************************************************/
31
32enum
33center
34{
35 U_center, D_center,
36 R_center, L_center,
37 F_center, B_center
38};
39
40enum
41corner
42{
43 UFR, UFL, UBL, UBR,
44 DFR, DFL, DBL, DBR
45};
46
47enum
48edge
49{
50 UF, UL, UB, UR,
51 DF, DL, DB, DR,
52 FR, FL, BL, BR
53};
54
55enum
56move
57{
58 NULLMOVE,
59 U, U2, U3, D, D2, D3,
60 R, R2, R3, L, L2, L3,
61 F, F2, F3, B, B2, B3,
62 Uw, Uw2, Uw3, Dw, Dw2, Dw3,
63 Rw, Rw2, Rw3, Lw, Lw2, Lw3,
64 Fw, Fw2, Fw3, Bw, Bw2, Bw3,
65 M, M2, M3,
66 S, S2, S3,
67 E, E2, E3,
68 x, x2, x3,
69 y, y2, y3,
70 z, z2, z3,
71};
72
73enum
74trans
75{
76 uf, ur, ub, ul,
77 df, dr, db, dl,
78 rf, rd, rb, ru,
79 lf, ld, lb, lu,
80 fu, fr, fd, fl,
81 bu, br, bd, bl,
82 mirror, /* R|L */
83};
84
85struct
86alglist
87{
88 AlgListNode *first;
89 AlgListNode *last;
90 int len;
91};
92
93struct
94alglistnode
95{
96 Alg alg;
97 AlgListNode *next;
98};
99
100struct
101block
102{
103 bool edge[12];
104 bool corner[8];
105 bool center[6];
106};
107
108struct
109cube
110{
111 uint16_t epose;
112 uint16_t eposs;
113 uint16_t eposm;
114 uint16_t eofb;
115 uint16_t eorl;
116 uint16_t eoud;
117 uint16_t cp;
118 uint16_t coud;
119 uint16_t cofb;
120 uint16_t corl;
121 uint16_t cpos;
122};
123
124struct
125nissmove
126{
127 Move m;
128 bool inverse;
129};
130
131struct
132solveoptions
133{
134 int min_moves;
135 int max_moves;
136 int max_solutions;
137 bool optimal_only;
138 bool can_niss;
139 bool *moveset;
140 Move *sorted_moves;
141 Trans pre_trans;
142};
143
144struct
145step
146{
147 int (*f)(Cube);
148 bool (*ready)(Cube);
149};
150
151/* Public functions **********************************************************/
152
153Cube apply_alg(Alg alg, Cube cube);
154Cube apply_move(Move m, Cube cube);
155Cube apply_trans(Trans t, Cube cube);
156bool block_solved(Cube cube, Block);
157Center center_at(Cube cube, Center c);
158Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */
159Corner corner_at(Cube cube, Corner c);
160Edge edge_at(Cube cube, Edge e);
161bool equal(Cube c1, Cube c2);
162Cube inverse_cube(Cube cube);
163Move inverse_move(Move m);
164Trans inverse_trans(Trans t);
165bool is_solved(Cube cube, bool reorient);
166int piece_orientation(Cube cube, int piece, char *orientation);
167void print_cube(Cube cube);
168AlgList * solve(Cube cube, Step step, SolveOptions opts);
169
170void concat(Alg src1, Alg src2, Alg dest);
171void copy_alg(Alg src, Alg dest);
172void invert_alg(Alg src, Alg dest);
173int len(Alg alg);
174Alg new_alg(char *str);
175void print_alg(Alg alg);
176void remove_last_moves(Alg alg, int k);
177void transform_alg(Trans t, Alg alg);
178
179void init();
diff --git a/old/2021-06-02-cleanedup/main.c b/old/2021-06-02-cleanedup/main.c
new file mode 100644
index 0000000..fca5e3c
--- /dev/null
+++ b/old/2021-06-02-cleanedup/main.c
@@ -0,0 +1,35 @@
1#include <stdio.h>
2#include "cube.h"
3#include "steps.h"
4
5int main() {
6 Alg algo;
7 AlgList *sols;
8 Cube cube;
9 SolveOptions opts;
10
11 init();
12
13 algo = new_alg("R U R' F");
14 cube = apply_alg(algo, (Cube){0});
15
16 print_cube(apply_trans(rd, cube));
17
18 opts = (SolveOptions) {
19 .min_moves = 0,
20 .max_moves = 5,
21 .optimal_only = true,
22 .max_solutions = 3,
23 .can_niss = false,
24 .moveset = standard_moveset,
25 .pre_trans = fu
26 };
27 sols = solve(cube, step_eofb, opts);
28 if (sols->len == 0)
29 fprintf(stderr, "No solution found\n");
30 else
31 print_alg(sols->first->alg);
32
33
34 return 0;
35}
diff --git a/old/2021-06-02-cleanedup/steps.h b/old/2021-06-02-cleanedup/steps.h
new file mode 100644
index 0000000..452b71c
--- /dev/null
+++ b/old/2021-06-02-cleanedup/steps.h
@@ -0,0 +1,22 @@
1/* Pre-conditions, i.e. "ready(cube)" functions ******************************/
2
3bool always_ready(Cube cube) { return true; }
4
5/* Main functions, i.e. "f(cube)" ********************************************/
6
7int f_eofb(Cube cube) { return (cube.eofb != 0) ? 1 : 0; }
8
9/* Steps *********************************************************************/
10
11Step step_eofb = { .f = f_eofb, .ready = always_ready };
12
13/* Movesets ******************************************************************/
14
15bool standard_moveset[NMOVES] = {
16 [U] = true, [U2] = true, [U3] = true,
17 [D] = true, [D2] = true, [D3] = true,
18 [R] = true, [R2] = true, [R3] = true,
19 [L] = true, [L2] = true, [L3] = true,
20 [F] = true, [F2] = true, [F3] = true,
21 [B] = true, [B2] = true, [B3] = true,
22};
diff --git a/old/2021-06-14-oldalg/cube.c b/old/2021-06-14-oldalg/cube.c
new file mode 100644
index 0000000..5409896
--- /dev/null
+++ b/old/2021-06-14-oldalg/cube.c
@@ -0,0 +1,2849 @@
1#include "cube.h"
2
3/* Constants and macros *****************************************************/
4
5#define POW2TO11 2048ULL
6#define POW2TO12 4096ULL
7#define POW3TO7 2187ULL
8#define POW3TO8 6561ULL
9#define FACTORIAL4 24ULL
10#define FACTORIAL6 720ULL
11#define FACTORIAL8 40320ULL
12#define FACTORIAL12 479001600ULL
13#define BINOM12ON4 495ULL
14#define BINOM8ON4 70ULL
15#define MIN(a,b) (((a) < (b)) ? (a) : (b))
16#define MAX(a,b) (((a) > (b)) ? (a) : (b))
17
18#define BASEALGLEN 50
19#define NMOVES (z3+1)
20#define NTRANS (mirror+1)
21#define NROTATIONS (NTRANS-1)
22#define PTABLESIZE(n) ((n+1) / 2)
23#define PTABLEVAL(tab,ind) (((ind)%2) ? (tab[(ind)/2] / 16) : \
24 (tab[(ind)/2] % 16))
25
26
27/* Local functions **********************************************************/
28
29static Cube admissible_ep(Cube cube, PieceFilter f);
30static void append_alg(AlgList *l, Alg *alg);
31static void append_move(Alg *alg, Move m, bool inverse);
32static Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a);
33static void apply_permutation(int *perm, int *set, int n);
34static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f);
35static uint16_t array_ep_to_epos(int *ep, int *eps_solved);
36static Cube arrays_to_cube(CubeArray *arr, PieceFilter f);
37static Move base_move(Move m);
38static int binomial(int n, int k);
39static Cube compose_filtered(Cube c2, Cube c1, PieceFilter f);
40static void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f);
41static int digit_array_to_int(int *a, int n, int b);
42static int edge_slice(Edge e); /* E=0, S=1, M=2 */
43static int epos_dependent(int pos1, int pos2);
44static uint16_t epos_from_arrays(int *epos, int *ep);
45static void epos_to_partial_ep(uint16_t epos, int *ep, int *ss);
46static int factorial(int n);
47static void free_alglistnode(AlgListNode *aln);
48static void free_cubearray(CubeArray *arr, PieceFilter f);
49static void generate_ptable(PruneData *pd);
50static void generate_ptable_dfs(Cube c, PruneData *pd, DfsData *dd);
51static void index_to_perm(int p, int n, int *r);
52static void index_to_subset(int s, int n, int k, int *r);
53static void int_to_digit_array(int a, int b, int n, int *r);
54static void int_to_sum_zero_array(int x, int b, int n, int *a);
55static int invert_digits(int a, int b, int n);
56static bool is_perm(int *a, int n);
57static bool is_subset(int *a, int n, int k);
58static Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf);
59static void moveset_to_list(bool (*ms)(Move), int (*f)(Cube), Move *r);
60static AlgList * new_alglist();
61static CubeArray * new_cubearray(Cube cube, PieceFilter f);
62static int perm_sign(int *a, int n);
63static int perm_to_index(int *a, int n);
64static int powint(int a, int b);
65static void ptable_set_reached(PruneData *pd, uint64_t ind);
66static void ptable_update(PruneData *pd, uint64_t ind, int m);
67static bool read_ptable_file(PruneData *pd);
68static bool read_ttables_file();
69static bool read_mtables_file();
70static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f);
71static void solve_dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd);
72static int subset_to_index(int *a, int n, int k);
73static void sum_arrays_mod(int *src, int *dst, int n, int m);
74static void swap(int *a, int *b);
75static bool write_ptable_file(PruneData *pd);
76static bool write_ttables_file();
77static bool write_mtables_file();
78
79static void init_auxtables();
80static void init_environment();
81static void init_moves();
82static void init_moves_aux();
83static void init_steps();
84static void init_strings();
85static void init_trans();
86static void init_trans_aux();
87
88static bool moveset_HTM(Move m);
89static bool moveset_URF(Move m);
90
91/* Steps and related functions and data **************************************/
92
93Step eofb_HTM;
94Step eorl_HTM;
95Step eoud_HTM;
96Step coud_HTM;
97Step corl_HTM;
98Step cofb_HTM;
99Step coud_URF;
100Step corl_URF;
101Step cofb_URF;
102Step corners_HTM;
103Step corners_URF;
104Step edges_HTM;
105Step drud_HTM;
106Step optimal_HTM;
107
108PruneData pd_eofb_HTM;
109PruneData pd_coud_HTM;
110PruneData pd_corners_HTM;
111PruneData pd_ep_HTM;
112PruneData pd_drud_HTM;
113
114static uint64_t index_eofb(Cube cube);
115static uint64_t index_coud(Cube cube);
116static uint64_t index_corners(Cube cube);
117static uint64_t index_ep(Cube cube);
118static uint64_t index_drud(Cube cube);
119
120static int check_nothing(Cube cube);
121static int check_eofb_HTM(Cube cube);
122static int check_coud_HTM(Cube cube);
123static int check_coud_URF(Cube cube);
124static int check_corners_HTM(Cube cube);
125static int check_corners_URF(Cube cube);
126static int check_edges_HTM(Cube cube);
127static int check_drud_HTM(Cube cube);
128static int check_optimal_HTM(Cube cube);
129
130/* All sorts of useful costants and tables **********************************/
131
132static char * tabledir;
133
134static PieceFilter pf_all;
135static PieceFilter pf_4val;
136static PieceFilter pf_epcp;
137static PieceFilter pf_cpos;
138static PieceFilter pf_cp;
139static PieceFilter pf_ep;
140static PieceFilter pf_e;
141static PieceFilter pf_s;
142static PieceFilter pf_m;
143static PieceFilter pf_eo;
144static PieceFilter pf_co;
145
146static int epe_solved[4];
147static int eps_solved[4];
148static int epm_solved[4];
149
150static char move_string[NMOVES][7];
151static char edge_string[12][7];
152static char corner_string[8][7];
153static char center_string[6][7];
154
155static bool commute[NMOVES][NMOVES];
156static bool possible_next[NMOVES][NMOVES][NMOVES];
157static Move inverse_move_aux[NMOVES];
158static Trans inverse_trans_aux[NTRANS];
159static int epos_dependent_aux[BINOM12ON4][BINOM12ON4];
160
161static uint16_t epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
162static uint16_t eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
163static uint16_t eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
164static uint16_t eo_ttable[NTRANS][POW2TO11];
165static uint16_t cp_ttable[NTRANS][FACTORIAL8];
166static uint16_t co_ttable[NTRANS][POW3TO7];
167static uint16_t cpos_ttable[NTRANS][FACTORIAL6];
168static Move moves_ttable[NTRANS][NMOVES];
169
170static uint16_t epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
171static uint16_t eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
172static uint16_t eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
173static uint16_t eofb_mtable[NMOVES][POW2TO11];
174static uint16_t eorl_mtable[NMOVES][POW2TO11];
175static uint16_t eoud_mtable[NMOVES][POW2TO11];
176static uint16_t cp_mtable[NMOVES][FACTORIAL8];
177static uint16_t coud_mtable[NMOVES][POW3TO7];
178static uint16_t cofb_mtable[NMOVES][POW3TO7];
179static uint16_t corl_mtable[NMOVES][POW3TO7];
180static uint16_t cpos_mtable[NMOVES][FACTORIAL6];
181
182static uint64_t me[12];
183
184static int edge_cycle[NMOVES][12];
185static int corner_cycle[NMOVES][8];
186static int center_cycle[NMOVES][6];
187static int eofb_flipped[NMOVES][12];
188static int eorl_flipped[NMOVES][12];
189static int eoud_flipped[NMOVES][12];
190static int coud_flipped[NMOVES][8];
191static int corl_flipped[NMOVES][8];
192static int cofb_flipped[NMOVES][8];
193static Alg * equiv_alg[NMOVES];
194
195static int epose_source[NTRANS]; /* 0=epose, 1=eposs, 2=eposm */
196static int eposs_source[NTRANS];
197static int eposm_source[NTRANS];
198static int eofb_source[NTRANS]; /* 0=eoud, 1=eorl, 2=eofb */
199static int eorl_source[NTRANS];
200static int eoud_source[NTRANS];
201static int coud_source[NTRANS]; /* 0=coud, 1=corl, 2=cofb */
202static int cofb_source[NTRANS];
203static int corl_source[NTRANS];
204static int ep_mirror[12];
205static int cp_mirror[8];
206static int cpos_mirror[6];
207static Alg * trans_algs[NROTATIONS];
208
209
210/* Local functions implementation ********************************************/
211
212static Cube
213admissible_ep(Cube cube, PieceFilter f)
214{
215 CubeArray *arr = new_cubearray(cube, f);
216 Cube ret;
217 bool used[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
218 int i, j;
219
220 for (i = 0; i < 12; i++)
221 if (arr->ep[i] != -1)
222 used[arr->ep[i]] = true;
223
224 for (i = 0, j = 0; i < 12; i++) {
225 for ( ; j < 11 && used[j]; j++);
226 if (arr->ep[i] == -1)
227 arr->ep[i] = j++;
228 }
229
230 ret = arrays_to_cube(arr, pf_ep);
231 free_cubearray(arr, f);
232
233 return ret;
234}
235
236static void
237append_alg(AlgList *l, Alg *alg)
238{
239 AlgListNode *node = malloc(sizeof(AlgListNode));
240 AlgNode *i;
241
242 node->alg = new_alg("");
243 for (i = alg->first; i != NULL; i = i->next)
244 append_move(node->alg, i->m, i->inverse);
245 node->next = NULL;
246
247 if (++l->len == 1)
248 l->first = node;
249 else
250 l->last->next = node;
251 l->last = node;
252}
253
254static void
255append_move(Alg *alg, Move m, bool inverse)
256{
257 AlgNode *node = malloc(sizeof(AlgNode));
258
259 node->m = m;
260 node->inverse = inverse;
261 node->next = NULL;
262 node->prev = alg->last;
263
264 if (++alg->len == 1)
265 alg->first = node;
266 else
267 alg->last->next = node;
268 alg->last = node;
269}
270
271static Cube
272apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a)
273{
274 Cube ret = {0};
275 AlgNode *i;
276
277 for (i = alg->first; i != NULL; i = i->next)
278 if (i->inverse)
279 ret = a ? apply_move(i->m, ret) :
280 apply_move_cubearray(i->m, ret, f);
281
282 ret = compose_filtered(c, inverse_cube(ret), f);
283
284 for (i = alg->first; i != NULL; i = i->next)
285 if (!i->inverse)
286 ret = a ? apply_move(i->m, ret) :
287 apply_move_cubearray(i->m, ret, f);
288
289 return ret;
290}
291
292static void
293apply_permutation(int *perm, int *set, int n)
294{
295 int *aux = malloc(n * sizeof(int));
296 int i;
297
298 if (!is_perm(perm, n))
299 return;
300
301 for (i = 0; i < n; i++)
302 aux[i] = set[perm[i]];
303
304 memcpy(set, aux, n * sizeof(int));
305 free(aux);
306}
307
308static Cube
309apply_move_cubearray(Move m, Cube cube, PieceFilter f)
310{
311 CubeArray m_arr = {
312 edge_cycle[m],
313 eofb_flipped[m],
314 eorl_flipped[m],
315 eoud_flipped[m],
316 corner_cycle[m],
317 coud_flipped[m],
318 corl_flipped[m],
319 cofb_flipped[m],
320 center_cycle[m]
321 };
322
323 return move_via_arrays(&m_arr, cube, f);
324}
325
326static uint16_t
327array_ep_to_epos(int *ep, int *ss)
328{
329 int epos[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
330 int eps[4];
331 int i, j, is;
332
333 for (i = 0, is = 0; i < 12; i++) {
334 for (j = 0; j < 4; j++) {
335 if (ep[i] == ss[j]) {
336 eps[is++] = j;
337 epos[i] = 1;
338 }
339 }
340 }
341
342 for (i = 0; i < 4; i++)
343 swap(&epos[ss[i]], &epos[i+8]);
344
345 return epos_from_arrays(epos, eps);
346}
347
348static Cube
349arrays_to_cube(CubeArray *arr, PieceFilter f)
350{
351 Cube ret = {0};
352
353 if (f.epose)
354 ret.epose = array_ep_to_epos(arr->ep, epe_solved);
355 if (f.eposs)
356 ret.eposs = array_ep_to_epos(arr->ep, eps_solved);
357 if (f.eposm)
358 ret.eposm = array_ep_to_epos(arr->ep, epm_solved);
359 if (f.eofb)
360 ret.eofb = digit_array_to_int(arr->eofb, 11, 2);
361 if (f.eorl)
362 ret.eorl = digit_array_to_int(arr->eorl, 11, 2);
363 if (f.eoud)
364 ret.eoud = digit_array_to_int(arr->eoud, 11, 2);
365 if (f.cp)
366 ret.cp = perm_to_index(arr->cp, 8);
367 if (f.coud)
368 ret.coud = digit_array_to_int(arr->coud, 7, 3);
369 if (f.corl)
370 ret.corl = digit_array_to_int(arr->corl, 7, 3);
371 if (f.cofb)
372 ret.cofb = digit_array_to_int(arr->cofb, 7, 3);
373 if (f.cpos)
374 ret.cpos = perm_to_index(arr->cpos, 6);
375
376 return ret;
377}
378
379static Move
380base_move(Move m)
381{
382 if (m == NULLMOVE)
383 return NULLMOVE;
384 else
385 return m - (m-1)%3;
386}
387
388static int
389binomial(int n, int k)
390{
391 if (n < 0 || k < 0 || k > n)
392 return 0;
393
394 return factorial(n) / (factorial(k) * factorial(n-k));
395}
396
397static Cube
398compose_filtered(Cube c2, Cube c1, PieceFilter f)
399{
400 CubeArray *arr = new_cubearray(c2, f);
401 Cube ret;
402
403 ret = move_via_arrays(arr, c1, f);
404 free_cubearray(arr, f);
405
406 return ret;
407}
408
409static void
410cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f)
411{
412 int i;
413
414 if (f.epose || f.eposs || f.eposm)
415 for (i = 0; i < 12; i++)
416 arr->ep[i] = -1;
417
418 if (f.epose)
419 epos_to_partial_ep(cube.epose, arr->ep, epe_solved);
420 if (f.eposs)
421 epos_to_partial_ep(cube.eposs, arr->ep, eps_solved);
422 if (f.eposm)
423 epos_to_partial_ep(cube.eposm, arr->ep, epm_solved);
424 if (f.eofb)
425 int_to_sum_zero_array(cube.eofb, 2, 12, arr->eofb);
426 if (f.eorl)
427 int_to_sum_zero_array(cube.eorl, 2, 12, arr->eorl);
428 if (f.eoud)
429 int_to_sum_zero_array(cube.eoud, 2, 12, arr->eoud);
430 if (f.cp)
431 index_to_perm(cube.cp, 8, arr->cp);
432 if (f.coud)
433 int_to_sum_zero_array(cube.coud, 3, 8, arr->coud);
434 if (f.corl)
435 int_to_sum_zero_array(cube.corl, 3, 8, arr->corl);
436 if (f.cofb)
437 int_to_sum_zero_array(cube.cofb, 3, 8, arr->cofb);
438 if (f.cpos)
439 index_to_perm(cube.cpos, 6, arr->cpos);
440}
441
442static int
443digit_array_to_int(int *a, int n, int b)
444{
445 int i, ret = 0, p = 1;
446
447 for (i = 0; i < n; i++, p *= b)
448 ret += a[i] * p;
449
450 return ret;
451}
452
453static int
454edge_slice(Edge e) {
455 if (e < 0 || e > 11)
456 return -1;
457
458 if (e == FR || e == FL || e == BL || e == BR)
459 return 0;
460 if (e == UR || e == UL || e == DR || e == DL)
461 return 1;
462
463 return 2;
464}
465
466static int
467epos_dependent(int poss, int pose)
468{
469 int ep[12] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
470 int ep8[8] = {0, 0, 0, 0, 0, 0, 0, 0};
471 int i, j;
472
473 epos_to_partial_ep(poss*FACTORIAL4, ep, eps_solved);
474 epos_to_partial_ep(pose*FACTORIAL4, ep, epe_solved);
475
476 for (i = 0, j = 0; i < 12; i++)
477 if (edge_slice(ep[i]) != 1)
478 ep8[j++] = (edge_slice(ep[i]) == 0) ? 1 : 0;
479
480 return subset_to_index(ep8, 8, 4);
481}
482
483static uint16_t
484epos_from_arrays(int *epos, int *ep)
485{
486 return FACTORIAL4 * subset_to_index(epos,12,4) + perm_to_index(ep,4);
487}
488
489static void
490epos_to_partial_ep(uint16_t epos, int *ep, int *ss)
491{
492 int i, is, eposs[12], eps[4];
493
494 index_to_perm(epos % FACTORIAL4, 4, eps);
495 index_to_subset(epos / FACTORIAL4, 12, 4, eposs);
496
497 for (i = 0; i < 4; i++)
498 swap(&eposs[ss[i]], &eposs[i+8]);
499
500 for (i = 0, is = 0; i < 12; i++)
501 if (eposs[i])
502 ep[i] = ss[eps[is++]];
503}
504
505static int
506factorial(int n)
507{
508 int i, ret = 1;
509
510 if (n < 0)
511 return 0;
512
513 for (i = 1; i <= n; i++)
514 ret *= i;
515
516 return ret;
517}
518
519void
520free_alg(Alg *alg)
521{
522 AlgNode *aux, *i = alg->first;
523
524 while (i != NULL) {
525 aux = i->next;
526 free(i);
527 i = aux;
528 }
529 free(alg);
530}
531
532void
533free_alglist(AlgList *l)
534{
535 AlgListNode *aux, *i = l->first;
536
537 while (i != NULL) {
538 aux = i->next;
539 free_alglistnode(i);
540 i = aux;
541 }
542 free(l);
543}
544
545void
546free_alglistnode(AlgListNode *aln)
547{
548 free_alg(aln->alg);
549 free(aln);
550}
551
552static void
553free_cubearray(CubeArray *arr, PieceFilter f)
554{
555 if (f.epose || f.eposs || f.eposm)
556 free(arr->ep);
557 if (f.eofb)
558 free(arr->eofb);
559 if (f.eorl)
560 free(arr->eorl);
561 if (f.eoud)
562 free(arr->eoud);
563 if (f.cp)
564 free(arr->cp);
565 if (f.coud)
566 free(arr->coud);
567 if (f.corl)
568 free(arr->corl);
569 if (f.cofb)
570 free(arr->cofb);
571 if (f.cpos)
572 free(arr->cpos);
573
574 free(arr);
575}
576
577static void
578generate_ptable(PruneData *pd)
579{
580 uint64_t j;
581 DfsData dd;
582
583 if (pd->generated)
584 return;
585
586 pd->ptable = malloc(PTABLESIZE(pd->size) * sizeof(uint8_t));
587
588 if (read_ptable_file(pd)) {
589 pd->generated = true;
590 return;
591 }
592
593 fprintf(stderr, "Cannot load %s, generating it\n", pd->filename);
594
595 dd.m = 0;
596 dd.last1 = NULLMOVE;
597 dd.last2 = NULLMOVE;
598
599 /* We use 4 bits per value, so any distance >= 15 is set to 15 */
600 for (j = 0; j < pd->size; j++)
601 ptable_update(pd, j, 15);
602
603 moveset_to_list(pd->moveset, NULL, dd.sorted_moves);
604
605 pd->reached = malloc(PTABLESIZE(pd->size) * sizeof(uint8_t));
606 for (dd.d = 0, pd->n = 0; dd.d < 15 && pd->n < pd->size; dd.d++) {
607 memset(pd->reached, 0, PTABLESIZE(pd->size)*sizeof(uint8_t));
608 generate_ptable_dfs((Cube){0}, pd, &dd);
609 fprintf(stderr, "Depth %d completed, generated %lu/%lu\n",
610 dd.d, pd->n, pd->size);
611 }
612
613 if (!write_ptable_file(pd))
614 fprintf(stderr, "Error writing ptable file\n");
615
616 pd->generated = true;
617 free(pd->reached);
618}
619
620static void
621generate_ptable_dfs(Cube c, PruneData *pd, DfsData *dd)
622{
623 uint64_t ind = pd->index(c);
624 int oldval = PTABLEVAL(pd->ptable, ind);
625 Move i, move, l1 = dd->last1, l2 = dd->last2;
626
627 if (oldval < dd->m || PTABLEVAL(pd->reached, ind) || pd->n == pd->size)
628 return;
629
630 ptable_set_reached(pd, ind);
631
632 if (dd->m == dd->d) {
633 if (dd->m < oldval)
634 ptable_update(pd, ind, dd->m);
635 return;
636 }
637
638 dd->m++;
639 dd->last2 = dd->last1;
640
641 for (i = 0; dd->sorted_moves[i] != NULLMOVE; i++) {
642 move = dd->sorted_moves[i];
643 if (possible_next[l2][l1][move]) {
644 dd->last1 = move;
645 generate_ptable_dfs(apply_move(move, c), pd, dd);
646 }
647 }
648
649 dd->m--;
650 dd->last1 = l1;
651 dd->last2 = l2;
652}
653
654static void
655index_to_perm(int p, int n, int *r)
656{
657 int *a = malloc(n * sizeof(int));
658 int i, j, c;
659
660 for (i = 0; i < n; i++)
661 a[i] = 0;
662
663 if (p < 0 || p >= factorial(n))
664 for (i = 0; i < n; i++)
665 r[i] = -1;
666
667 for (i = 0; i < n; i++) {
668 c = 0;
669 j = 0;
670 while (c <= p / factorial(n-i-1))
671 c += a[j++] ? 0 : 1;
672 r[i] = j-1;
673 a[j-1] = 1;
674 p %= factorial(n-i-1);
675 }
676
677 free(a);
678}
679
680static void
681index_to_subset(int s, int n, int k, int *r)
682{
683 int i, j, v;
684
685 if (s < 0 || s >= binomial(n, k)) {
686 for (i = 0; i < n; i++)
687 r[i] = -1;
688 return;
689 }
690
691 for (i = 0; i < n; i++) {
692 if (k == n-i) {
693 for (j = i; j < n; j++)
694 r[j] = 1;
695 return;
696 }
697
698 if (k == 0) {
699 for (j = i; j < n; j++)
700 r[j] = 0;
701 return;
702 }
703
704 v = binomial(n-i-1, k);
705 if (s >= v) {
706 r[i] = 1;
707 k--;
708 s -= v;
709 } else {
710 r[i] = 0;
711 }
712 }
713}
714
715static void
716int_to_digit_array(int a, int b, int n, int *r)
717{
718 int i;
719
720 if (b <= 1)
721 for (i = 0; i < n; i++)
722 r[i] = 0;
723 else
724 for (i = 0; i < n; i++, a /= b)
725 r[i] = a % b;
726}
727
728static void
729int_to_sum_zero_array(int x, int b, int n, int *a)
730{
731 int i, s = 0;
732
733 if (b <= 1) {
734 for (i = 0; i < n; i++)
735 a[i] = 0;
736 } else {
737 int_to_digit_array(x, b, n-1, a);
738 for (i = 0; i < n - 1; i++)
739 s = (s + a[i]) % b;
740 a[n-1] = (b - s) % b;
741 }
742}
743
744static int
745invert_digits(int a, int b, int n)
746{
747 int i, ret, *r = malloc(n * sizeof(int));
748
749 int_to_digit_array(a, b, n, r);
750 for (i = 0; i < n; i++)
751 r[i] = (b-r[i]) % b;
752
753 ret = digit_array_to_int(r, n, b);
754 free(r);
755 return ret;
756}
757
758static bool
759is_perm(int *a, int n)
760{
761 int *aux = malloc(n * sizeof(int));
762 int i;
763
764 for (i = 0; i < n; i++)
765 if (a[i] < 0 || a[i] >= n)
766 return false;
767 else
768 aux[a[i]] = 1;
769
770 for (i = 0; i < n; i++)
771 if (!aux[i])
772 return false;
773
774 free(aux);
775
776 return true;
777}
778
779static bool
780is_subset(int *a, int n, int k)
781{
782 int i, sum = 0;
783
784 for (i = 0; i < n; i++)
785 sum += a[i] ? 1 : 0;
786
787 return sum == k;
788}
789
790static Cube
791move_via_arrays(CubeArray *arr, Cube c, PieceFilter f)
792{
793 CubeArray *arrc = new_cubearray(c, f);
794 Cube ret;
795
796 if (f.epose || f.eposs || f.eposm)
797 apply_permutation(arr->ep, arrc->ep, 12);
798
799 if (f.eofb) {
800 apply_permutation(arr->ep, arrc->eofb, 12);
801 sum_arrays_mod(arr->eofb, arrc->eofb, 12, 2);
802 }
803
804 if (f.eorl) {
805 apply_permutation(arr->ep, arrc->eorl, 12);
806 sum_arrays_mod(arr->eorl, arrc->eorl, 12, 2);
807 }
808
809 if (f.eoud) {
810 apply_permutation(arr->ep, arrc->eoud, 12);
811 sum_arrays_mod(arr->eoud, arrc->eoud, 12, 2);
812 }
813
814 if (f.cp)
815 apply_permutation(arr->cp, arrc->cp, 8);
816
817 if (f.coud) {
818 apply_permutation(arr->cp, arrc->coud, 8);
819 sum_arrays_mod(arr->coud, arrc->coud, 8, 3);
820 }
821
822 if (f.corl) {
823 apply_permutation(arr->cp, arrc->corl, 8);
824 sum_arrays_mod(arr->corl, arrc->corl, 8, 3);
825 }
826
827 if (f.cofb) {
828 apply_permutation(arr->cp, arrc->cofb, 8);
829 sum_arrays_mod(arr->cofb, arrc->cofb, 8, 3);
830 }
831
832 if (f.cpos)
833 apply_permutation(arr->cpos, arrc->cpos, 6);
834
835 ret = arrays_to_cube(arrc, f);
836 free_cubearray(arrc, f);
837
838 return ret;
839}
840
841static void
842moveset_to_list(bool (*ms)(Move m), int (*f)(Cube), Move *r)
843{
844 Cube c;
845 int b[NMOVES];
846 int na = 0, nb = 0;
847 Move i;
848
849 if (ms == NULL) {
850 fprintf(stderr, "Error: no moveset given\n");
851 return;
852 }
853
854 for (i = U; i < NMOVES; i++) {
855 if (ms(i)) {
856 c = apply_move(i, (Cube){0});
857 if (f != NULL && f(c))
858 r[na++] = i;
859 else
860 b[nb++] = i;
861 }
862 }
863
864 memcpy(r + na, b, nb * sizeof(Move));
865 r[na+nb] = NULLMOVE;
866}
867
868static AlgList *
869new_alglist()
870{
871 AlgList *ret = malloc(sizeof(AlgList));
872
873 ret->len = 0;
874 ret->first = NULL;
875 ret->last = NULL;
876
877 return ret;
878}
879
880static CubeArray *
881new_cubearray(Cube cube, PieceFilter f)
882{
883 CubeArray *arr = malloc(sizeof(CubeArray));
884
885 if (f.epose || f.eposs || f.eposm)
886 arr->ep = malloc(12 * sizeof(int));
887 if (f.eofb)
888 arr->eofb = malloc(12 * sizeof(int));
889 if (f.eorl)
890 arr->eorl = malloc(12 * sizeof(int));
891 if (f.eoud)
892 arr->eoud = malloc(12 * sizeof(int));
893 if (f.cp)
894 arr->cp = malloc(8 * sizeof(int));
895 if (f.coud)
896 arr->coud = malloc(8 * sizeof(int));
897 if (f.corl)
898 arr->corl = malloc(8 * sizeof(int));
899 if (f.cofb)
900 arr->cofb = malloc(8 * sizeof(int));
901 if (f.cpos)
902 arr->cpos = malloc(6 * sizeof(int));
903
904 cube_to_arrays(cube, arr, f);
905
906 return arr;
907}
908
909static int
910perm_sign(int *a, int n)
911{
912 int i, j, ret = 0;
913
914 if (!is_perm(a,n))
915 return -1;
916
917 for (i = 0; i < n; i++)
918 for (j = i+1; j < n; j++)
919 ret += (a[i] > a[j]) ? 1 : 0;
920
921 return ret % 2;
922}
923
924static int
925perm_to_index(int *a, int n)
926{
927 int i, j, c, ret = 0;
928
929 if (!is_perm(a, n))
930 return -1;
931
932 for (i = 0; i < n; i++) {
933 c = 0;
934 for (j = i+1; j < n; j++)
935 c += (a[i] > a[j]) ? 1 : 0;
936 ret += factorial(n-i-1) * c;
937 }
938
939 return ret;
940}
941
942static int
943powint(int a, int b)
944{
945 if (b < 0)
946 return 0; /* Truncate */
947 if (b == 0)
948 return 1;
949
950 if (b % 2)
951 return a * powint(a, b-1);
952 else
953 return powint(a*a, b/2);
954}
955
956static void
957ptable_set_reached(PruneData *pd, uint64_t ind)
958{
959 uint8_t oldval2 = pd->reached[ind/2];
960 int other = ind % 2 ? oldval2 % 16 : oldval2 / 16;
961
962 pd->reached[ind/2] = ind % 2 ? 16 + other : 16*other + 1;
963}
964
965static void
966ptable_update(PruneData *pd, uint64_t ind, int n)
967{
968 uint8_t oldval2 = pd->ptable[ind/2];
969 int other = ind % 2 ? oldval2 % 16 : oldval2 / 16;
970
971 pd->ptable[ind/2] = ind % 2 ? 16*n + other : 16*other + n;
972 pd->n++;
973}
974
975static bool
976read_mtables_file()
977{
978 FILE *f;
979 char fname[strlen(tabledir)+20];
980 int m, b = sizeof(uint16_t);
981 bool r = true;
982
983 strcpy(fname, tabledir);
984 strcat(fname, "/mtables");
985
986 if ((f = fopen(fname, "rb")) == NULL)
987 return false;
988
989 for (m = 0; m < NMOVES; m++) {
990 r = r && fread(epose_mtable[m], b, me[0], f) == me[0];
991 r = r && fread(eposs_mtable[m], b, me[1], f) == me[1];
992 r = r && fread(eposm_mtable[m], b, me[2], f) == me[2];
993 r = r && fread(eofb_mtable[m], b, me[3], f) == me[3];
994 r = r && fread(eorl_mtable[m], b, me[4], f) == me[4];
995 r = r && fread(eoud_mtable[m], b, me[5], f) == me[5];
996 r = r && fread(cp_mtable[m], b, me[6], f) == me[6];
997 r = r && fread(coud_mtable[m], b, me[7], f) == me[7];
998 r = r && fread(corl_mtable[m], b, me[8], f) == me[8];
999 r = r && fread(cofb_mtable[m], b, me[9], f) == me[9];
1000 r = r && fread(cpos_mtable[m], b, me[10], f) == me[10];
1001 }
1002
1003 fclose(f);
1004 return r;
1005}
1006
1007static bool
1008read_ptable_file(PruneData *pd)
1009{
1010 FILE *f;
1011 char fname[strlen(tabledir)+100];
1012 uint64_t r;
1013
1014 strcpy(fname, tabledir);
1015 strcat(fname, "/");
1016 strcat(fname, pd->filename);
1017
1018 if ((f = fopen(fname, "rb")) == NULL)
1019 return false;
1020
1021 r = fread(pd->ptable, sizeof(uint8_t), PTABLESIZE(pd->size), f);
1022 fclose(f);
1023
1024 return r == PTABLESIZE(pd->size);
1025}
1026
1027static bool
1028read_ttables_file()
1029{
1030 FILE *f;
1031 char fname[strlen(tabledir)+20];
1032 int b = sizeof(uint16_t);
1033 bool r = true;
1034 Move m;
1035
1036 strcpy(fname, tabledir);
1037 strcat(fname, "/");
1038 strcat(fname, "ttables");
1039
1040 if ((f = fopen(fname, "rb")) == NULL)
1041 return false;
1042
1043 for (m = 0; m < NTRANS; m++) {
1044 r = r && fread(epose_ttable[m], b, me[0], f) == me[0];
1045 r = r && fread(eposs_ttable[m], b, me[1], f) == me[1];
1046 r = r && fread(eposm_ttable[m], b, me[2], f) == me[2];
1047 r = r && fread(eo_ttable[m], b, me[3], f) == me[3];
1048 r = r && fread(cp_ttable[m], b, me[6], f) == me[6];
1049 r = r && fread(co_ttable[m], b, me[7], f) == me[7];
1050 r = r && fread(cpos_ttable[m], b, me[10], f) == me[10];
1051 r = r && fread(moves_ttable[m], b, me[11], f) == me[11];
1052 }
1053
1054 fclose(f);
1055 return r;
1056}
1057
1058static Cube
1059rotate_via_compose(Trans r, Cube c, PieceFilter f)
1060{
1061 Alg *inv;
1062 static int zero12[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1063 static int zero8[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
1064 static CubeArray ma = {
1065 .ep = ep_mirror,
1066 .eofb = zero12,
1067 .eorl = zero12,
1068 .eoud = zero12,
1069 .cp = cp_mirror,
1070 .coud = zero8,
1071 .corl = zero8,
1072 .cofb = zero8,
1073 .cpos = cpos_mirror
1074 };
1075
1076 Cube ret;
1077
1078 if (r != mirror) {
1079 ret = apply_alg_generic(trans_algs[r], c, f, true);
1080 inv = on_inverse(trans_algs[r]);
1081 ret = apply_alg_generic(inv, ret, f, true);
1082 free_alg(inv);
1083 } else {
1084 ret = move_via_arrays(&ma, (Cube){0}, f);
1085 ret = compose_filtered(c, ret, f);
1086 ret = move_via_arrays(&ma, ret, f);
1087 }
1088
1089 return ret;
1090}
1091
1092static void
1093solve_dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd)
1094{
1095 Move move, l1 = dd->last1, l2 = dd->last2;
1096 int i, lower_bound = s.check(c);
1097 bool found_many, prune, niss_make_sense, nissbackup = dd->niss;
1098
1099 if (opts->can_niss && !dd->niss)
1100 lower_bound = MIN(1, lower_bound);
1101
1102 found_many = dd->sols->len >= opts->max_solutions;
1103 prune = dd->current_alg->len + lower_bound > dd->d;
1104 if (found_many || prune)
1105 return;
1106
1107 if (!lower_bound) { /* solved */
1108 if (dd->current_alg->len == dd->d)
1109 append_alg(dd->sols, dd->current_alg);
1110 return;
1111 }
1112
1113 dd->last2 = dd->last1;
1114
1115 for (i = 0; dd->sorted_moves[i] != NULLMOVE; i++) {
1116 move = dd->sorted_moves[i];
1117 if (possible_next[l2][l1][move]) {
1118 dd->last1 = move;
1119 append_move(dd->current_alg, move, dd->niss);
1120 solve_dfs(apply_move(move, c), s, opts, dd);
1121 remove_last_move(dd->current_alg);
1122 }
1123 }
1124
1125 niss_make_sense = !dd->current_alg->len ||
1126 (s.check(apply_move(l1,(Cube){0})));
1127 if (opts->can_niss && !dd->niss && niss_make_sense) {
1128 dd->niss = true;
1129 dd->last1 = NULLMOVE;
1130 dd->last2 = NULLMOVE;
1131 solve_dfs(inverse_cube(c), s, opts, dd);
1132 }
1133
1134 dd->last1 = l1;
1135 dd->last2 = l2;
1136 dd->niss = nissbackup;
1137}
1138
1139static int
1140subset_to_index(int *a, int n, int k)
1141{
1142 int i, ret = 0;
1143
1144 if (!is_subset(a, n, k))
1145 return binomial(n, k);
1146
1147 for (i = 0; i < n; i++) {
1148 if (k == n-i)
1149 return ret;
1150 if (a[i]) {
1151 ret += binomial(n-i-1, k);
1152 k--;
1153 }
1154 }
1155
1156 return ret;
1157}
1158
1159static void
1160sum_arrays_mod(int *src, int *dst, int n, int m)
1161{
1162 int i;
1163
1164 for (i = 0; i < n; i++)
1165 dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m;
1166}
1167
1168static void
1169swap(int *a, int *b)
1170{
1171 int aux;
1172
1173 aux = *a;
1174 *a = *b;
1175 *b = aux;
1176}
1177
1178static bool
1179write_mtables_file()
1180{
1181 FILE *f;
1182 char fname[strlen(tabledir)+20];
1183 int m, b = sizeof(uint16_t);
1184 bool r = true;
1185
1186 strcpy(fname, tabledir);
1187 strcat(fname, "/mtables");
1188
1189 if ((f = fopen(fname, "wb")) == NULL)
1190 return false;
1191
1192 for (m = 0; m < NMOVES; m++) {
1193 r = r && fwrite(epose_mtable[m], b, me[0], f) == me[0];
1194 r = r && fwrite(eposs_mtable[m], b, me[1], f) == me[1];
1195 r = r && fwrite(eposm_mtable[m], b, me[2], f) == me[2];
1196 r = r && fwrite(eofb_mtable[m], b, me[3], f) == me[3];
1197 r = r && fwrite(eorl_mtable[m], b, me[4], f) == me[4];
1198 r = r && fwrite(eoud_mtable[m], b, me[5], f) == me[5];
1199 r = r && fwrite(cp_mtable[m], b, me[6], f) == me[6];
1200 r = r && fwrite(coud_mtable[m], b, me[7], f) == me[7];
1201 r = r && fwrite(corl_mtable[m], b, me[8], f) == me[8];
1202 r = r && fwrite(cofb_mtable[m], b, me[9], f) == me[9];
1203 r = r && fwrite(cpos_mtable[m], b, me[10], f) == me[10];
1204 }
1205
1206 fclose(f);
1207 return r;
1208}
1209
1210static bool
1211write_ptable_file(PruneData *pd)
1212{
1213 FILE *f;
1214 char fname[strlen(tabledir)+100];
1215 uint64_t written;
1216
1217 strcpy(fname, tabledir);
1218 strcat(fname, "/");
1219 strcat(fname, pd->filename);
1220
1221 if ((f = fopen(fname, "wb")) == NULL)
1222 return false;
1223
1224 written = fwrite(pd->ptable, sizeof(uint8_t), PTABLESIZE(pd->size), f);
1225 fclose(f);
1226
1227 return written == PTABLESIZE(pd->size);
1228}
1229
1230static bool
1231write_ttables_file()
1232{
1233 FILE *f;
1234 char fname[strlen(tabledir)+20];
1235 bool r = true;
1236 int b = sizeof(uint16_t);
1237 Move m;
1238
1239 strcpy(fname, tabledir);
1240 strcat(fname, "/ttables");
1241
1242 if ((f = fopen(fname, "wb")) == NULL)
1243 return false;
1244
1245 for (m = 0; m < NTRANS; m++) {
1246 r = r && fwrite(epose_ttable[m], b, me[0], f) == me[0];
1247 r = r && fwrite(eposs_ttable[m], b, me[1], f) == me[1];
1248 r = r && fwrite(eposm_ttable[m], b, me[2], f) == me[2];
1249 r = r && fwrite(eo_ttable[m], b, me[3], f) == me[3];
1250 r = r && fwrite(cp_ttable[m], b, me[6], f) == me[6];
1251 r = r && fwrite(co_ttable[m], b, me[7], f) == me[7];
1252 r = r && fwrite(cpos_ttable[m], b, me[10], f) == me[10];
1253 r = r && fwrite(moves_ttable[m], b, me[11], f) == me[11];
1254 }
1255
1256 fclose(f);
1257 return r;
1258}
1259
1260/* Init functions implementation *********************************************/
1261
1262static void
1263init_auxtables()
1264{
1265 Cube c1, c2;
1266 uint64_t ui, uj;
1267 int i, j, k;
1268 bool cij, p1, p2;
1269
1270 for (ui = 0; ui < BINOM12ON4; ui++)
1271 for (uj = 0; uj < BINOM12ON4; uj++)
1272 epos_dependent_aux[ui][uj] = epos_dependent(ui, uj);
1273
1274 for (i = 0; i < NMOVES; i++) {
1275 for (j = 0; j < NMOVES; j++) {
1276 c1 = apply_move(i, apply_move(j, (Cube){0}));
1277 c2 = apply_move(j, apply_move(i, (Cube){0}));
1278 commute[i][j] = equal(c1, c2);
1279 }
1280 }
1281
1282 for (i = 0; i < NMOVES; i++) {
1283 for (j = 0; j < NMOVES; j++) {
1284 for (k = 0; k < NMOVES; k++) {
1285 p1 = j && base_move(j) == base_move(k);
1286 p2 = i && base_move(i) == base_move(k);
1287 cij = commute[i][j];
1288 possible_next[i][j][k] = !(p1 || (cij && p2));
1289 }
1290 }
1291 }
1292
1293 for (i = 0; i < NMOVES; i++)
1294 inverse_move_aux[i] = i ? i + 2 - 2*((i-1)%3) : NULLMOVE;
1295
1296 /* Is there a more elegant way? */
1297 inverse_trans_aux[uf] = uf;
1298 inverse_trans_aux[ur] = ul;
1299 inverse_trans_aux[ul] = ur;
1300 inverse_trans_aux[ub] = ub;
1301
1302 inverse_trans_aux[df] = df;
1303 inverse_trans_aux[dr] = dr;
1304 inverse_trans_aux[dl] = dl;
1305 inverse_trans_aux[db] = db;
1306
1307 inverse_trans_aux[rf] = lf;
1308 inverse_trans_aux[rd] = bl;
1309 inverse_trans_aux[rb] = rb;
1310 inverse_trans_aux[ru] = fr;
1311
1312 inverse_trans_aux[lf] = rf;
1313 inverse_trans_aux[ld] = br;
1314 inverse_trans_aux[lb] = lb;
1315 inverse_trans_aux[lu] = fl;
1316
1317 inverse_trans_aux[fu] = fu;
1318 inverse_trans_aux[fr] = ru;
1319 inverse_trans_aux[fd] = bu;
1320 inverse_trans_aux[fl] = lu;
1321
1322 inverse_trans_aux[bu] = fd;
1323 inverse_trans_aux[br] = ld;
1324 inverse_trans_aux[bd] = bd;
1325 inverse_trans_aux[bl] = rd;
1326
1327 inverse_trans_aux[mirror] = mirror;
1328}
1329
1330static void
1331init_environment()
1332{
1333 char *nissydata = getenv("NISSYDATA");
1334 char *localdata = getenv("XDG_DATA_HOME");
1335 char *home = getenv("HOME");
1336 bool read, write;
1337
1338 if (nissydata != NULL) {
1339 tabledir = malloc(strlen(nissydata) * sizeof(char) + 20);
1340 strcpy(tabledir, nissydata);
1341 } else if (localdata != NULL) {
1342 tabledir = malloc(strlen(localdata) * sizeof(char) + 20);
1343 strcpy(tabledir, localdata);
1344 strcat(tabledir, "/nissy");
1345 } else if (home != NULL) {
1346 tabledir = malloc(strlen(home) * sizeof(char) + 20);
1347 strcpy(tabledir, home);
1348 strcat(tabledir, "/.nissy");
1349 }
1350
1351 mkdir(tabledir, 0777);
1352 strcat(tabledir, "/tables");
1353 mkdir(tabledir, 0777);
1354
1355 read = !access(tabledir, R_OK);
1356 write = !access(tabledir, W_OK);
1357
1358 if (!read) {
1359 fprintf(stderr, "Table files cannot be read.\n");
1360 } else if (!write) {
1361 fprintf(stderr, "Data directory not writable: ");
1362 fprintf(stderr, "tables can be loaded, but not saved.\n");
1363 }
1364}
1365
1366static void
1367init_moves() {
1368 Cube c;
1369 CubeArray arrs;
1370 int i;
1371 uint16_t ui;
1372 Move m;
1373
1374 /* Generate all move cycles and flips; I do this regardless */
1375 for (i = 0; i < NMOVES; i++) {
1376 if (i == U || i == x || i == y)
1377 continue;
1378
1379 c = apply_alg_generic(equiv_alg[i], (Cube){0}, pf_all, false);
1380
1381 arrs = (CubeArray){
1382 edge_cycle[i],
1383 eofb_flipped[i],
1384 eorl_flipped[i],
1385 eoud_flipped[i],
1386 corner_cycle[i],
1387 coud_flipped[i],
1388 corl_flipped[i],
1389 cofb_flipped[i],
1390 center_cycle[i]
1391 };
1392 cube_to_arrays(c, &arrs, pf_all);
1393 }
1394
1395 if (read_mtables_file())
1396 return;
1397
1398 fprintf(stderr, "Cannot load %s, generating it\n", "mtables");
1399
1400 /* Initialize transition tables */
1401 for (m = 0; m < NMOVES; m++) {
1402 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
1403 c = (Cube){ .epose = ui };
1404 c = apply_move_cubearray(m, c, pf_e);
1405 epose_mtable[m][ui] = c.epose;
1406
1407 c = (Cube){ .eposs = ui };
1408 c = apply_move_cubearray(m, c, pf_s);
1409 eposs_mtable[m][ui] = c.eposs;
1410
1411 c = (Cube){ .eposm = ui };
1412 c = apply_move_cubearray(m, c, pf_m);
1413 eposm_mtable[m][ui] = c.eposm;
1414 }
1415 for (ui = 0; ui < POW2TO11; ui++ ) {
1416 c = (Cube){ .eofb = ui };
1417 c = apply_move_cubearray(m, c, pf_eo);
1418 eofb_mtable[m][ui] = c.eofb;
1419
1420 c = (Cube){ .eorl = ui };
1421 c = apply_move_cubearray(m, c, pf_eo);
1422 eorl_mtable[m][ui] = c.eorl;
1423
1424 c = (Cube){ .eoud = ui };
1425 c = apply_move_cubearray(m, c, pf_eo);
1426 eoud_mtable[m][ui] = c.eoud;
1427 }
1428 for (ui = 0; ui < POW3TO7; ui++) {
1429 c = (Cube){ .coud = ui };
1430 c = apply_move_cubearray(m, c, pf_co);
1431 coud_mtable[m][ui] = c.coud;
1432
1433 c = (Cube){ .corl = ui };
1434 c = apply_move_cubearray(m, c, pf_co);
1435 corl_mtable[m][ui] = c.corl;
1436
1437 c = (Cube){ .cofb = ui };
1438 c = apply_move_cubearray(m, c, pf_co);
1439 cofb_mtable[m][ui] = c.cofb;
1440 }
1441 for (ui = 0; ui < FACTORIAL8; ui++) {
1442 c = (Cube){ .cp = ui };
1443 c = apply_move_cubearray(m, c, pf_cp);
1444 cp_mtable[m][ui] = c.cp;
1445 }
1446 for (ui = 0; ui < FACTORIAL6; ui++) {
1447 c = (Cube){ .cpos = ui };
1448 c = apply_move_cubearray(m, c, pf_cpos);
1449 cpos_mtable[m][ui] = c.cpos;
1450 }
1451 }
1452
1453 if (!write_mtables_file())
1454 fprintf(stderr, "Error writing mtables\n");
1455}
1456
1457static void
1458init_moves_aux()
1459{
1460 /* Some standard PieceFilters */
1461 pf_all.epose = true;
1462 pf_all.eposs = true;
1463 pf_all.eposm = true;
1464 pf_all.eofb = true;
1465 pf_all.eorl = true;
1466 pf_all.eoud = true;
1467 pf_all.cp = true;
1468 pf_all.cofb = true;
1469 pf_all.corl = true;
1470 pf_all.coud = true;
1471 pf_all.cpos = true;
1472
1473 pf_4val.epose = true;
1474 pf_4val.eposs = true;
1475 pf_4val.eposm = true;
1476 pf_4val.eofb = true;
1477 pf_4val.coud = true;
1478 pf_4val.cp = true;
1479
1480 pf_epcp.epose = true;
1481 pf_epcp.eposs = true;
1482 pf_epcp.eposm = true;
1483 pf_epcp.cp = true;
1484
1485 pf_cpos.cpos = true;
1486
1487 pf_cp.cp = true;
1488
1489 pf_ep.epose = true;
1490 pf_ep.eposs = true;
1491 pf_ep.eposm = true;
1492
1493 pf_e.epose = true;
1494 pf_s.eposs = true;
1495 pf_m.eposm = true;
1496
1497 pf_eo.eofb = true;
1498 pf_eo.eorl = true;
1499 pf_eo.eoud = true;
1500
1501 pf_co.cofb = true;
1502 pf_co.corl = true;
1503 pf_co.coud = true;
1504
1505 /* Used to convert to and from CubeArray */
1506 epe_solved[0] = FR;
1507 epe_solved[1] = FL;
1508 epe_solved[2] = BL;
1509 epe_solved[3] = BR;
1510
1511 eps_solved[0] = UL;
1512 eps_solved[1] = UR;
1513 eps_solved[2] = DL;
1514 eps_solved[3] = DR;
1515
1516 epm_solved[0] = UF;
1517 epm_solved[1] = UB;
1518 epm_solved[2] = DF;
1519 epm_solved[3] = DB;
1520
1521 /* Table sizes, used for reading and writing files */
1522 me[0] = FACTORIAL12/FACTORIAL8;
1523 me[1] = FACTORIAL12/FACTORIAL8;
1524 me[2] = FACTORIAL12/FACTORIAL8;
1525 me[3] = POW2TO11;
1526 me[4] = POW2TO11;
1527 me[5] = POW2TO11;
1528 me[6] = FACTORIAL8;
1529 me[7] = POW3TO7;
1530 me[8] = POW3TO7;
1531 me[9] = POW3TO7;
1532 me[10] = FACTORIAL6;
1533 me[11] = NMOVES;
1534
1535 /* Cycles *********************/
1536 edge_cycle[U][UF] = UR;
1537 edge_cycle[U][UL] = UF;
1538 edge_cycle[U][UB] = UL;
1539 edge_cycle[U][UR] = UB;
1540 edge_cycle[U][DF] = DF;
1541 edge_cycle[U][DL] = DL;
1542 edge_cycle[U][DB] = DB;
1543 edge_cycle[U][DR] = DR;
1544 edge_cycle[U][FR] = FR;
1545 edge_cycle[U][FL] = FL;
1546 edge_cycle[U][BL] = BL;
1547 edge_cycle[U][BR] = BR;
1548
1549 edge_cycle[x][UF] = DF;
1550 edge_cycle[x][UL] = FL;
1551 edge_cycle[x][UB] = UF;
1552 edge_cycle[x][UR] = FR;
1553 edge_cycle[x][DF] = DB;
1554 edge_cycle[x][DL] = BL;
1555 edge_cycle[x][DB] = UB;
1556 edge_cycle[x][DR] = BR;
1557 edge_cycle[x][FR] = DR;
1558 edge_cycle[x][FL] = DL;
1559 edge_cycle[x][BL] = UL;
1560 edge_cycle[x][BR] = UR;
1561
1562 edge_cycle[y][UF] = UR;
1563 edge_cycle[y][UL] = UF;
1564 edge_cycle[y][UB] = UL;
1565 edge_cycle[y][UR] = UB;
1566 edge_cycle[y][DF] = DR;
1567 edge_cycle[y][DL] = DF;
1568 edge_cycle[y][DB] = DL;
1569 edge_cycle[y][DR] = DB;
1570 edge_cycle[y][FR] = BR;
1571 edge_cycle[y][FL] = FR;
1572 edge_cycle[y][BL] = FL;
1573 edge_cycle[y][BR] = BL;
1574
1575 corner_cycle[U][UFR] = UBR;
1576 corner_cycle[U][UFL] = UFR;
1577 corner_cycle[U][UBL] = UFL;
1578 corner_cycle[U][UBR] = UBL;
1579 corner_cycle[U][DFR] = DFR;
1580 corner_cycle[U][DFL] = DFL;
1581 corner_cycle[U][DBL] = DBL;
1582 corner_cycle[U][DBR] = DBR;
1583
1584 corner_cycle[x][UFR] = DFR;
1585 corner_cycle[x][UFL] = DFL;
1586 corner_cycle[x][UBL] = UFL;
1587 corner_cycle[x][UBR] = UFR;
1588 corner_cycle[x][DFR] = DBR;
1589 corner_cycle[x][DFL] = DBL;
1590 corner_cycle[x][DBL] = UBL;
1591 corner_cycle[x][DBR] = UBR;
1592
1593 corner_cycle[y][UFR] = UBR;
1594 corner_cycle[y][UFL] = UFR;
1595 corner_cycle[y][UBL] = UFL;
1596 corner_cycle[y][UBR] = UBL;
1597 corner_cycle[y][DFR] = DBR;
1598 corner_cycle[y][DFL] = DFR;
1599 corner_cycle[y][DBL] = DFL;
1600 corner_cycle[y][DBR] = DBL;
1601
1602 center_cycle[U][U_center] = U_center;
1603 center_cycle[U][D_center] = D_center;
1604 center_cycle[U][R_center] = R_center;
1605 center_cycle[U][L_center] = L_center;
1606 center_cycle[U][F_center] = F_center;
1607 center_cycle[U][B_center] = B_center;
1608
1609 center_cycle[x][U_center] = F_center;
1610 center_cycle[x][D_center] = B_center;
1611 center_cycle[x][R_center] = R_center;
1612 center_cycle[x][L_center] = L_center;
1613 center_cycle[x][F_center] = D_center;
1614 center_cycle[x][B_center] = U_center;
1615
1616 center_cycle[y][U_center] = U_center;
1617 center_cycle[y][D_center] = D_center;
1618 center_cycle[y][R_center] = B_center;
1619 center_cycle[y][L_center] = F_center;
1620 center_cycle[y][F_center] = R_center;
1621 center_cycle[y][B_center] = L_center;
1622
1623 /* Flipped pieces *************/
1624 eofb_flipped[x][UF] = 1;
1625 eofb_flipped[x][UB] = 1;
1626 eofb_flipped[x][DF] = 1;
1627 eofb_flipped[x][DB] = 1;
1628
1629 eofb_flipped[y][FR] = 1;
1630 eofb_flipped[y][FL] = 1;
1631 eofb_flipped[y][BL] = 1;
1632 eofb_flipped[y][BR] = 1;
1633
1634 eorl_flipped[x][UF] = 1;
1635 eorl_flipped[x][UL] = 1;
1636 eorl_flipped[x][UB] = 1;
1637 eorl_flipped[x][UR] = 1;
1638 eorl_flipped[x][DF] = 1;
1639 eorl_flipped[x][DL] = 1;
1640 eorl_flipped[x][DB] = 1;
1641 eorl_flipped[x][DR] = 1;
1642 eorl_flipped[x][FR] = 1;
1643 eorl_flipped[x][FL] = 1;
1644 eorl_flipped[x][BL] = 1;
1645 eorl_flipped[x][BR] = 1;
1646
1647 eorl_flipped[y][FR] = 1;
1648 eorl_flipped[y][FL] = 1;
1649 eorl_flipped[y][BL] = 1;
1650 eorl_flipped[y][BR] = 1;
1651
1652 eoud_flipped[U][UF] = 1;
1653 eoud_flipped[U][UL] = 1;
1654 eoud_flipped[U][UB] = 1;
1655 eoud_flipped[U][UR] = 1;
1656
1657 eoud_flipped[x][UF] = 1;
1658 eoud_flipped[x][UB] = 1;
1659 eoud_flipped[x][DF] = 1;
1660 eoud_flipped[x][DB] = 1;
1661
1662 eoud_flipped[y][UF] = 1;
1663 eoud_flipped[y][UL] = 1;
1664 eoud_flipped[y][UB] = 1;
1665 eoud_flipped[y][UR] = 1;
1666 eoud_flipped[y][DF] = 1;
1667 eoud_flipped[y][DL] = 1;
1668 eoud_flipped[y][DB] = 1;
1669 eoud_flipped[y][DR] = 1;
1670 eoud_flipped[y][FR] = 1;
1671 eoud_flipped[y][FL] = 1;
1672 eoud_flipped[y][BL] = 1;
1673 eoud_flipped[y][BR] = 1;
1674
1675 coud_flipped[x][UFR] = 2;
1676 coud_flipped[x][UFL] = 1;
1677 coud_flipped[x][UBR] = 1;
1678 coud_flipped[x][UBL] = 2;
1679 coud_flipped[x][DFR] = 1;
1680 coud_flipped[x][DFL] = 2;
1681 coud_flipped[x][DBR] = 2;
1682 coud_flipped[x][DBL] = 1;
1683
1684 corl_flipped[U][UFR] = 1;
1685 corl_flipped[U][UFL] = 2;
1686 corl_flipped[U][UBL] = 1;
1687 corl_flipped[U][UBR] = 2;
1688
1689 corl_flipped[y][UFR] = 1;
1690 corl_flipped[y][UFL] = 2;
1691 corl_flipped[y][UBL] = 1;
1692 corl_flipped[y][UBR] = 2;
1693 corl_flipped[y][DFR] = 2;
1694 corl_flipped[y][DFL] = 1;
1695 corl_flipped[y][DBL] = 2;
1696 corl_flipped[y][DBR] = 1;
1697
1698 cofb_flipped[U][UFR] = 2;
1699 cofb_flipped[U][UFL] = 1;
1700 cofb_flipped[U][UBL] = 2;
1701 cofb_flipped[U][UBR] = 1;
1702
1703 cofb_flipped[x][UFR] = 1;
1704 cofb_flipped[x][UFL] = 2;
1705 cofb_flipped[x][UBL] = 1;
1706 cofb_flipped[x][UBR] = 2;
1707 cofb_flipped[x][DFR] = 2;
1708 cofb_flipped[x][DFL] = 1;
1709 cofb_flipped[x][DBL] = 2;
1710 cofb_flipped[x][DBR] = 1;
1711
1712 cofb_flipped[y][UFR] = 2;
1713 cofb_flipped[y][UFL] = 1;
1714 cofb_flipped[y][UBL] = 2;
1715 cofb_flipped[y][UBR] = 1;
1716 cofb_flipped[y][DFR] = 1;
1717 cofb_flipped[y][DFL] = 2;
1718 cofb_flipped[y][DBL] = 1;
1719 cofb_flipped[y][DBR] = 2;
1720
1721 /* Equivalent moves ***********/
1722 equiv_alg[NULLMOVE] = new_alg("");
1723
1724 equiv_alg[U] = new_alg(" U ");
1725 equiv_alg[U2] = new_alg(" UU ");
1726 equiv_alg[U3] = new_alg(" UUU ");
1727 equiv_alg[D] = new_alg(" xx U xx ");
1728 equiv_alg[D2] = new_alg(" xx UU xx ");
1729 equiv_alg[D3] = new_alg(" xx UUU xx ");
1730 equiv_alg[R] = new_alg(" yx U xxxyyy ");
1731 equiv_alg[R2] = new_alg(" yx UU xxxyyy ");
1732 equiv_alg[R3] = new_alg(" yx UUU xxxyyy ");
1733 equiv_alg[L] = new_alg(" yyyx U xxxy ");
1734 equiv_alg[L2] = new_alg(" yyyx UU xxxy ");
1735 equiv_alg[L3] = new_alg(" yyyx UUU xxxy ");
1736 equiv_alg[F] = new_alg(" x U xxx ");
1737 equiv_alg[F2] = new_alg(" x UU xxx ");
1738 equiv_alg[F3] = new_alg(" x UUU xxx ");
1739 equiv_alg[B] = new_alg(" xxx U x ");
1740 equiv_alg[B2] = new_alg(" xxx UU x ");
1741 equiv_alg[B3] = new_alg(" xxx UUU x ");
1742
1743 equiv_alg[Uw] = new_alg(" xx U xx y ");
1744 equiv_alg[Uw2] = new_alg(" xx UU xx yy ");
1745 equiv_alg[Uw3] = new_alg(" xx UUU xx yyy ");
1746 equiv_alg[Dw] = new_alg(" U yyy ");
1747 equiv_alg[Dw2] = new_alg(" UU yy ");
1748 equiv_alg[Dw3] = new_alg(" UUU y ");
1749 equiv_alg[Rw] = new_alg(" yyyx U xxxy x ");
1750 equiv_alg[Rw2] = new_alg(" yyyx UU xxxy xx ");
1751 equiv_alg[Rw3] = new_alg(" yyyx UUU xxxy xxx ");
1752 equiv_alg[Lw] = new_alg(" yx U xxxyyy xxx ");
1753 equiv_alg[Lw2] = new_alg(" yx UU xxxyyy xx ");
1754 equiv_alg[Lw3] = new_alg(" yx UUU xxxyyy x ");
1755 equiv_alg[Fw] = new_alg(" xxx U x yxxxyyy ");
1756 equiv_alg[Fw2] = new_alg(" xxx UU x yxxyyy ");
1757 equiv_alg[Fw3] = new_alg(" xxx UUU x yxyyy ");
1758 equiv_alg[Bw] = new_alg(" x U xxx yxyyy ");
1759 equiv_alg[Bw2] = new_alg(" x UU xxx yxxyyy ");
1760 equiv_alg[Bw3] = new_alg(" x UUU xxx yxxxyyy ");
1761
1762 equiv_alg[M] = new_alg(" yx U xx UUU yxyyy ");
1763 equiv_alg[M2] = new_alg(" yx UU xx UU xxxy ");
1764 equiv_alg[M3] = new_alg(" yx UUU xx U yxxxy ");
1765 equiv_alg[S] = new_alg(" x UUU xx U yyyx ");
1766 equiv_alg[S2] = new_alg(" x UU xx UU yyx ");
1767 equiv_alg[S3] = new_alg(" x U xx UUU yx ");
1768 equiv_alg[E] = new_alg(" U xx UUU xxyyy ");
1769 equiv_alg[E2] = new_alg(" UU xx UU xxyy ");
1770 equiv_alg[E3] = new_alg(" UUU xx U xxy ");
1771
1772 equiv_alg[x] = new_alg(" x ");
1773 equiv_alg[x2] = new_alg(" xx ");
1774 equiv_alg[x3] = new_alg(" xxx ");
1775 equiv_alg[y] = new_alg(" y ");
1776 equiv_alg[y2] = new_alg(" yy ");
1777 equiv_alg[y3] = new_alg(" yyy ");
1778 equiv_alg[z] = new_alg(" yyy x y ");
1779 equiv_alg[z2] = new_alg(" yy xx ");
1780 equiv_alg[z3] = new_alg(" y x yyy ");
1781}
1782
1783static void
1784init_steps()
1785{
1786 /* PruneData */
1787 pd_eofb_HTM.filename = "ptable_eofb_HTM";
1788 pd_eofb_HTM.size = POW2TO11;
1789 pd_eofb_HTM.index = index_eofb;
1790 pd_eofb_HTM.moveset = moveset_HTM;
1791
1792 pd_coud_HTM.filename = "ptable_coud_HTM";
1793 pd_coud_HTM.size = POW3TO7;
1794 pd_coud_HTM.index = index_coud;
1795 pd_coud_HTM.moveset = moveset_HTM;
1796
1797 pd_corners_HTM.filename = "ptable_corners_HTM";
1798 pd_corners_HTM.size = POW3TO7 * FACTORIAL8;
1799 pd_corners_HTM.index = index_corners;
1800 pd_corners_HTM.moveset = moveset_HTM;
1801
1802 pd_ep_HTM.filename = "ptable_ep_HTM";
1803 pd_ep_HTM.size = FACTORIAL12;
1804 pd_ep_HTM.index = index_ep;
1805 pd_ep_HTM.moveset = moveset_HTM;
1806
1807 pd_drud_HTM.filename = "ptable_drud_HTM";
1808 pd_drud_HTM.size = POW2TO11 * POW3TO7 * BINOM12ON4;
1809 pd_drud_HTM.index = index_drud;
1810 pd_drud_HTM.moveset = moveset_HTM;
1811
1812
1813 /* Actual steps */
1814 eofb_HTM.check = check_eofb_HTM;
1815 eofb_HTM.ready = check_nothing;
1816 eofb_HTM.pre_trans = uf;
1817 eofb_HTM.moveset = moveset_HTM;
1818
1819 eorl_HTM.check = check_eofb_HTM;
1820 eorl_HTM.ready = check_nothing;
1821 eorl_HTM.pre_trans = ur;
1822 eorl_HTM.moveset = moveset_HTM;
1823
1824 eoud_HTM.check = check_eofb_HTM;
1825 eoud_HTM.ready = check_nothing;
1826 eoud_HTM.pre_trans = bu;
1827 eoud_HTM.moveset = moveset_HTM;
1828
1829
1830 coud_HTM.check = check_coud_HTM;
1831 coud_HTM.ready = check_nothing;
1832 coud_HTM.pre_trans = uf;
1833 coud_HTM.moveset = moveset_HTM;
1834
1835 corl_HTM.check = check_coud_HTM;
1836 corl_HTM.ready = check_nothing;
1837 corl_HTM.pre_trans = rf;
1838 corl_HTM.moveset = moveset_HTM;
1839
1840 cofb_HTM.check = check_coud_HTM;
1841 cofb_HTM.ready = check_nothing;
1842 cofb_HTM.pre_trans = fd;
1843 cofb_HTM.moveset = moveset_HTM;
1844
1845 coud_URF.check = check_coud_URF;
1846 coud_URF.ready = check_nothing;
1847 coud_URF.pre_trans = uf;
1848 coud_URF.moveset = moveset_URF;
1849
1850 corl_URF.check = check_coud_URF;
1851 corl_URF.ready = check_nothing;
1852 corl_URF.pre_trans = rf;
1853 corl_URF.moveset = moveset_URF;
1854
1855 cofb_URF.check = check_coud_URF;
1856 cofb_URF.ready = check_nothing;
1857 cofb_URF.pre_trans = fd;
1858 cofb_URF.moveset = moveset_URF;
1859
1860 corners_HTM.check = check_corners_HTM;
1861 corners_HTM.ready = check_nothing;
1862 corners_HTM.pre_trans = uf;
1863 corners_HTM.moveset = moveset_HTM;
1864
1865 corners_URF.check = check_corners_URF;
1866 corners_URF.ready = check_nothing;
1867 corners_URF.pre_trans = uf;
1868 corners_URF.moveset = moveset_URF;
1869
1870 edges_HTM.check = check_edges_HTM;
1871 edges_HTM.ready = check_nothing;
1872 edges_HTM.pre_trans = uf;
1873 edges_HTM.moveset = moveset_HTM;
1874
1875 drud_HTM.check = check_drud_HTM;
1876 drud_HTM.ready = check_nothing;
1877 drud_HTM.pre_trans = uf;
1878 drud_HTM.moveset = moveset_HTM;
1879
1880 optimal_HTM.check = check_optimal_HTM;
1881 optimal_HTM.ready = check_nothing;
1882 optimal_HTM.pre_trans = uf;
1883 optimal_HTM.moveset = moveset_HTM;
1884}
1885
1886static void
1887init_strings()
1888{
1889 strcpy(move_string [NULLMOVE], "-" );
1890 strcpy(move_string [U], "U" );
1891 strcpy(move_string [U2], "U2" );
1892 strcpy(move_string [U3], "U\'" );
1893 strcpy(move_string [D], "D" );
1894 strcpy(move_string [D2], "D2" );
1895 strcpy(move_string [D3], "D\'" );
1896 strcpy(move_string [R], "R" );
1897 strcpy(move_string [R2], "R2" );
1898 strcpy(move_string [R3], "R\'" );
1899 strcpy(move_string [L], "L" );
1900 strcpy(move_string [L2], "L2" );
1901 strcpy(move_string [L3], "L\'" );
1902 strcpy(move_string [F], "F" );
1903 strcpy(move_string [F2], "F2" );
1904 strcpy(move_string [F3], "F\'" );
1905 strcpy(move_string [B], "B" );
1906 strcpy(move_string [B2], "B2" );
1907 strcpy(move_string [B3], "B\'" );
1908 strcpy(move_string [Uw], "Uw" );
1909 strcpy(move_string [Uw2], "Uw2" );
1910 strcpy(move_string [Uw3], "Uw\'" );
1911 strcpy(move_string [Dw], "Dw" );
1912 strcpy(move_string [Dw2], "Dw2" );
1913 strcpy(move_string [Dw3], "Dw\'" );
1914 strcpy(move_string [Rw], "Rw" );
1915 strcpy(move_string [Rw2], "Rw2" );
1916 strcpy(move_string [Rw3], "Rw\'" );
1917 strcpy(move_string [Lw], "Lw" );
1918 strcpy(move_string [Lw2], "Lw2" );
1919 strcpy(move_string [Lw3], "Lw\'" );
1920 strcpy(move_string [Fw], "Fw" );
1921 strcpy(move_string [Fw2], "Fw2" );
1922 strcpy(move_string [Fw3], "Fw\'" );
1923 strcpy(move_string [Bw], "Bw" );
1924 strcpy(move_string [Bw2], "Bw2" );
1925 strcpy(move_string [Bw3], "Bw\'" );
1926 strcpy(move_string [M], "M" );
1927 strcpy(move_string [M2], "M2" );
1928 strcpy(move_string [M3], "M\'" );
1929 strcpy(move_string [S], "S" );
1930 strcpy(move_string [S2], "S2" );
1931 strcpy(move_string [S3], "S\'" );
1932 strcpy(move_string [E], "E" );
1933 strcpy(move_string [E2], "E2" );
1934 strcpy(move_string [E3], "E\'" );
1935 strcpy(move_string [x], "x" );
1936 strcpy(move_string [x2], "x2" );
1937 strcpy(move_string [x3], "x\'" );
1938 strcpy(move_string [y], "y" );
1939 strcpy(move_string [y2], "y2" );
1940 strcpy(move_string [y3], "y\'" );
1941 strcpy(move_string [z], "z" );
1942 strcpy(move_string [z2], "z2" );
1943 strcpy(move_string [z3], "z\'" );
1944
1945 strcpy(edge_string [UF], "UF" );
1946 strcpy(edge_string [UL], "UL" );
1947 strcpy(edge_string [UB], "UB" );
1948 strcpy(edge_string [UR], "UR" );
1949 strcpy(edge_string [DF], "DF" );
1950 strcpy(edge_string [DL], "DL" );
1951 strcpy(edge_string [DB], "DB" );
1952 strcpy(edge_string [DR], "DR" );
1953 strcpy(edge_string [FR], "FR" );
1954 strcpy(edge_string [FL], "FL" );
1955 strcpy(edge_string [BL], "BL" );
1956 strcpy(edge_string [BR], "BR" );
1957
1958 strcpy(corner_string [UFR], "UFR" );
1959 strcpy(corner_string [UFL], "UFL" );
1960 strcpy(corner_string [UBL], "UBL" );
1961 strcpy(corner_string [UBR], "UBR" );
1962 strcpy(corner_string [DFR], "DFR" );
1963 strcpy(corner_string [DFL], "DFL" );
1964 strcpy(corner_string [DBL], "DBL" );
1965 strcpy(corner_string [DBR], "DBR" );
1966
1967 strcpy(center_string [U_center], "U" );
1968 strcpy(center_string [D_center], "D" );
1969 strcpy(center_string [R_center], "R" );
1970 strcpy(center_string [L_center], "L" );
1971 strcpy(center_string [F_center], "F" );
1972 strcpy(center_string [B_center], "B" );
1973}
1974
1975static void
1976init_trans() {
1977 Cube aux, cube, c[3];
1978 CubeArray epcp;
1979 int eparr[12], eoarr[12];
1980 int cparr[8], coarr[8];
1981 int i;
1982 bool b1, b2, b3;
1983 uint16_t ui;
1984 Move mi, move;
1985 Trans m;
1986
1987 /* Compute sources */
1988 for (i = 0; i < NTRANS; i++) {
1989 if (i == mirror)
1990 cube = (Cube){0};
1991 else
1992 cube = apply_alg(trans_algs[i], (Cube){0});
1993
1994 epose_source[i] = edge_slice(edge_at(cube, FR));
1995 eposs_source[i] = edge_slice(edge_at(cube, UR));
1996 eposm_source[i] = edge_slice(edge_at(cube, UF));
1997 eofb_source[i] = center_at(cube, F_center)/2;
1998 eorl_source[i] = center_at(cube, R_center)/2;
1999 eoud_source[i] = center_at(cube, U_center)/2;
2000 coud_source[i] = center_at(cube, U_center)/2;
2001 cofb_source[i] = center_at(cube, F_center)/2;
2002 corl_source[i] = center_at(cube, R_center)/2;
2003 }
2004
2005 if (read_ttables_file())
2006 return;
2007
2008 fprintf(stderr, "Cannot load %s, generating it\n", "ttables");
2009
2010 /* Initialize tables */
2011 for (m = 0; m < NTRANS; m++) {
2012 if (m == mirror) {
2013 memcpy(eparr, ep_mirror, 12 * sizeof(int));
2014 memcpy(cparr, cp_mirror, 8 * sizeof(int));
2015 } else {
2016 epcp = (CubeArray){ .ep = eparr, .cp = cparr };
2017 cube = apply_alg(trans_algs[m], (Cube){0});
2018 cube_to_arrays(cube, &epcp, pf_epcp);
2019 }
2020
2021 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
2022 c[0] = admissible_ep((Cube){ .epose = ui }, pf_e);
2023 c[1] = admissible_ep((Cube){ .eposs = ui }, pf_s);
2024 c[2] = admissible_ep((Cube){ .eposm = ui }, pf_m);
2025
2026 cube = rotate_via_compose(m,c[epose_source[m]],pf_ep);
2027 epose_ttable[m][ui] = cube.epose;
2028
2029 cube = rotate_via_compose(m,c[eposs_source[m]],pf_ep);
2030 eposs_ttable[m][ui] = cube.eposs;
2031
2032 cube = rotate_via_compose(m,c[eposm_source[m]],pf_ep);
2033 eposm_ttable[m][ui] = cube.eposm;
2034 }
2035 for (ui = 0; ui < POW2TO11; ui++ ) {
2036 int_to_sum_zero_array(ui, 2, 12, eoarr);
2037 apply_permutation(eparr, eoarr, 12);
2038 eo_ttable[m][ui] = digit_array_to_int(eoarr, 11, 2);
2039 }
2040 for (ui = 0; ui < POW3TO7; ui++) {
2041 int_to_sum_zero_array(ui, 3, 8, coarr);
2042 apply_permutation(cparr, coarr, 8);
2043 co_ttable[m][ui] = digit_array_to_int(coarr, 7, 3);
2044 if (m == mirror)
2045 co_ttable[m][ui] =
2046 invert_digits(co_ttable[m][ui], 3, 7);
2047 }
2048 for (ui = 0; ui < FACTORIAL8; ui++) {
2049 cube = (Cube){ .cp = ui };
2050 cube = rotate_via_compose(m, cube, pf_cp);
2051 cp_ttable[m][ui] = cube.cp;
2052 }
2053 for (ui = 0; ui < FACTORIAL6; ui++) {
2054 cube = (Cube){ .cpos = ui };
2055 cube = rotate_via_compose(m, cube, pf_cpos);
2056 cpos_ttable[m][ui] = cube.cpos;
2057 }
2058 for (mi = 0; mi < NMOVES; mi++) {
2059 if (m == mirror) {
2060 b1 = (mi >= U && mi <= Bw3);
2061 b2 = (mi >= S && mi <= E3);
2062 b3 = (mi >= x && mi <= z3);
2063 if (b1 || b2 || b3)
2064 moves_ttable[m][mi] =
2065 inverse_move_aux[mi];
2066 else
2067 moves_ttable[m][mi] = mi;
2068
2069 if ((mi-1)/3==(R-1)/3 || (mi-1)/3==(Rw-1)/3)
2070 moves_ttable[m][mi] += 3;
2071 if ((mi-1)/3==(L-1)/3 || (mi-1)/3==(L2-1)/3)
2072 moves_ttable[m][mi] -= 3;
2073 } else {
2074 aux = apply_trans(m, apply_move(mi,(Cube){0}));
2075 for (move = 0; move < NMOVES; move++) {
2076 cube = apply_move(
2077 inverse_move_aux[move], aux);
2078 if (is_solved(cube, false))
2079 moves_ttable[m][mi] = move;
2080 }
2081 }
2082 }
2083 }
2084
2085 if (!write_ttables_file())
2086 fprintf(stderr, "Error writing ttables\n");
2087}
2088
2089static void
2090init_trans_aux()
2091{
2092 ep_mirror[UF] = UF;
2093 ep_mirror[UL] = UR;
2094 ep_mirror[UB] = UB;
2095 ep_mirror[UR] = UL;
2096 ep_mirror[DF] = DF;
2097 ep_mirror[DL] = DR;
2098 ep_mirror[DB] = DB;
2099 ep_mirror[DR] = DL;
2100 ep_mirror[FR] = FL;
2101 ep_mirror[FL] = FR;
2102 ep_mirror[BR] = BL;
2103 ep_mirror[BL] = BR;
2104
2105 cp_mirror[UFR] = UFL;
2106 cp_mirror[UFL] = UFR;
2107 cp_mirror[UBL] = UBR;
2108 cp_mirror[UBR] = UBL;
2109 cp_mirror[DFR] = DFL;
2110 cp_mirror[DFL] = DFR;
2111 cp_mirror[DBL] = DBR;
2112 cp_mirror[DBR] = DBL;
2113
2114 cpos_mirror[U_center] = U_center;
2115 cpos_mirror[D_center] = D_center;
2116 cpos_mirror[R_center] = L_center;
2117 cpos_mirror[L_center] = R_center;
2118 cpos_mirror[F_center] = F_center;
2119 cpos_mirror[B_center] = B_center;
2120
2121 /* Is there a more elegant way? */
2122 trans_algs[uf] = new_alg("");
2123 trans_algs[ur] = new_alg("y");
2124 trans_algs[ub] = new_alg("y2");
2125 trans_algs[ul] = new_alg("y3");
2126
2127 trans_algs[df] = new_alg("z2");
2128 trans_algs[dr] = new_alg("y z2");
2129 trans_algs[db] = new_alg("x2");
2130 trans_algs[dl] = new_alg("y3 z2");
2131
2132 trans_algs[rf] = new_alg("z3");
2133 trans_algs[rd] = new_alg("z3 y");
2134 trans_algs[rb] = new_alg("z3 y2");
2135 trans_algs[ru] = new_alg("z3 y3");
2136
2137 trans_algs[lf] = new_alg("z");
2138 trans_algs[ld] = new_alg("z y3");
2139 trans_algs[lb] = new_alg("z y2");
2140 trans_algs[lu] = new_alg("z y");
2141
2142 trans_algs[fu] = new_alg("x y2");
2143 trans_algs[fr] = new_alg("x y");
2144 trans_algs[fd] = new_alg("x");
2145 trans_algs[fl] = new_alg("x y3");
2146
2147 trans_algs[bu] = new_alg("x3");
2148 trans_algs[br] = new_alg("x3 y");
2149 trans_algs[bd] = new_alg("x3 y2");
2150 trans_algs[bl] = new_alg("x3 y3");
2151}
2152
2153/* Linearization functions implementation ************************************/
2154
2155static uint64_t
2156index_eofb(Cube cube)
2157{
2158 return cube.eofb;
2159}
2160
2161static uint64_t
2162index_coud(Cube cube)
2163{
2164 return cube.coud;
2165}
2166
2167static uint64_t
2168index_corners(Cube cube)
2169{
2170 return cube.coud * FACTORIAL8 + cube.cp;
2171}
2172
2173static uint64_t
2174index_ep(Cube cube)
2175{
2176 uint64_t a, b, c;
2177
2178 /* TODO: remove this check */
2179 if (epos_dependent_aux[cube.eposs/FACTORIAL4][cube.epose/FACTORIAL4] ==BINOM8ON4)
2180 fprintf(stderr, "Impossible\n");
2181
2182 a = cube.eposs;
2183 b = (cube.epose % FACTORIAL4) +
2184 epos_dependent_aux[cube.eposs/FACTORIAL4][cube.epose/FACTORIAL4] *
2185 FACTORIAL4;
2186 c = cube.eposm % FACTORIAL4;
2187
2188 b *= FACTORIAL4 * BINOM12ON4;
2189 c *= FACTORIAL4 * BINOM12ON4 * FACTORIAL4 * BINOM8ON4;
2190
2191 return a + b + c;
2192}
2193
2194static uint64_t
2195index_drud(Cube cube)
2196{
2197 uint64_t a, b, c;
2198
2199 a = cube.eofb;
2200 b = cube.coud;
2201 c = cube.epose / FACTORIAL4;
2202
2203 b *= POW2TO11;
2204 c *= POW2TO11 * POW3TO7;
2205
2206 return a + b + c;
2207}
2208
2209/* Step checking functions implementation ************************************/
2210
2211static int
2212check_nothing(Cube cube)
2213{
2214 return true;
2215}
2216
2217static int
2218check_eofb_HTM(Cube cube)
2219{
2220 if (!pd_eofb_HTM.generated)
2221 generate_ptable(&pd_eofb_HTM);
2222
2223 return PTABLEVAL(pd_eofb_HTM.ptable, cube.eofb);
2224}
2225
2226static int
2227check_coud_HTM(Cube cube)
2228{
2229 if (!pd_coud_HTM.generated)
2230 generate_ptable(&pd_coud_HTM);
2231
2232 return PTABLEVAL(pd_coud_HTM.ptable, cube.coud);
2233}
2234
2235static int
2236check_coud_URF(Cube cube)
2237{
2238 /* TODO: I can improve this by checking first the orientation of
2239 * the corner in DBL and use that as a reference */
2240
2241 int ud = check_coud_HTM(cube);
2242 int rl = check_coud_HTM(apply_move(z, cube));
2243 int fb = check_coud_HTM(apply_move(x, cube));
2244
2245 return MIN(ud, MIN(rl, fb));
2246}
2247
2248static int
2249check_corners_HTM(Cube cube)
2250{
2251 if (!pd_corners_HTM.generated)
2252 generate_ptable(&pd_corners_HTM);
2253
2254 return PTABLEVAL(pd_corners_HTM.ptable, index_corners(cube));
2255}
2256
2257static int
2258check_corners_URF(Cube cube)
2259{
2260 /* TODO: I can improve this by checking first the corner in DBL
2261 * and use that as a reference */
2262
2263 int ret = 15;
2264 Cube c;
2265 Trans i;
2266
2267 for (i = 0; i < NROTATIONS; i++) {
2268 c = apply_alg(trans_algs[i], cube);
2269 ret = MIN(ret, check_corners_HTM(c));
2270 }
2271
2272 return ret;
2273}
2274
2275static int
2276check_edges_HTM(Cube cube)
2277{
2278 int ret = 0;
2279
2280 if (!pd_ep_HTM.generated)
2281 generate_ptable(&pd_ep_HTM);
2282
2283 ret = MAX(ret, PTABLEVAL(pd_ep_HTM.ptable, index_ep(cube)));
2284 ret = MAX(ret, check_eofb_HTM(cube));
2285 ret = MAX(ret, check_eofb_HTM(apply_trans(ur, cube)));
2286 ret = MAX(ret, check_eofb_HTM(apply_trans(fd, cube)));
2287
2288 return ret;
2289}
2290
2291static int
2292check_drud_HTM(Cube cube)
2293{
2294 if (!pd_drud_HTM.generated)
2295 generate_ptable(&pd_drud_HTM);
2296
2297 return PTABLEVAL(pd_drud_HTM.ptable, index_drud(cube));
2298}
2299
2300static int
2301check_optimal_HTM(Cube cube)
2302{
2303 int dr1, dr2, dr3, drmax, cor; /*ep;*/
2304
2305 if (!pd_drud_HTM.generated)
2306 generate_ptable(&pd_drud_HTM);
2307 if (!pd_corners_HTM.generated)
2308 generate_ptable(&pd_corners_HTM);
2309 /*
2310 *if (!pd_ep_HTM.generated)
2311 * generate_ptable(&pd_ep_HTM);
2312 */
2313
2314 dr1 = PTABLEVAL(pd_drud_HTM.ptable, index_drud(cube));
2315 dr2 = PTABLEVAL(pd_drud_HTM.ptable, index_drud(apply_trans(rf, cube)));
2316 dr3 = PTABLEVAL(pd_drud_HTM.ptable, index_drud(apply_trans(fd, cube)));
2317
2318 drmax = MAX(dr1, MAX(dr2, dr3));
2319 if (dr1 == dr2 && dr2 == dr3 && dr1 != 0)
2320 drmax++;
2321
2322 cor = PTABLEVAL(pd_corners_HTM.ptable, index_corners(cube));
2323 /* ep = PTABLEVAL(pd_ep_HTM.ptable, index_ep(cube)); */
2324
2325 /*return MAX(drmax, MAX(ep, cor));*/
2326 if (drmax == 0 && cor == 0)
2327 return is_solved(cube, false) ? 0 : 1;
2328 return MAX(drmax, cor);
2329}
2330
2331
2332/* Movesets ******************************************************************/
2333
2334bool
2335moveset_HTM(Move m)
2336{
2337 return m >= U && m <= B3;
2338}
2339
2340bool
2341moveset_URF(Move m)
2342{
2343 Move b = base_move(m);
2344
2345 return b == U || b == R || b == F;
2346}
2347
2348
2349/* Public functions implementation *******************************************/
2350
2351Cube
2352apply_alg(Alg *alg, Cube cube)
2353{
2354 return apply_alg_generic(alg, cube, pf_all, true);
2355}
2356
2357Cube
2358apply_move(Move m, Cube cube)
2359{
2360 Cube moved = {0};
2361
2362 moved.epose = epose_mtable[m][cube.epose];
2363 moved.eposs = eposs_mtable[m][cube.eposs];
2364 moved.eposm = eposm_mtable[m][cube.eposm];
2365 moved.eofb = eofb_mtable[m][cube.eofb];
2366 moved.eorl = eorl_mtable[m][cube.eorl];
2367 moved.eoud = eoud_mtable[m][cube.eoud];
2368 moved.coud = coud_mtable[m][cube.coud];
2369 moved.cofb = cofb_mtable[m][cube.cofb];
2370 moved.corl = corl_mtable[m][cube.corl];
2371 moved.cp = cp_mtable[m][cube.cp];
2372 moved.cpos = cpos_mtable[m][cube.cpos];
2373
2374 return moved;
2375}
2376
2377Cube
2378apply_trans(Trans t, Cube cube)
2379{
2380 Cube transformed = {0};
2381 uint16_t aux_epos[3] = { cube.epose, cube.eposs, cube.eposm };
2382 uint16_t aux_eo[3] = { cube.eoud, cube.eorl, cube.eofb };
2383 uint16_t aux_co[3] = { cube.coud, cube.corl, cube.cofb };
2384
2385 transformed.epose = epose_ttable[t][aux_epos[epose_source[t]]];
2386 transformed.eposs = eposs_ttable[t][aux_epos[eposs_source[t]]];
2387 transformed.eposm = eposm_ttable[t][aux_epos[eposm_source[t]]];
2388 transformed.eofb = eo_ttable[t][aux_eo[eofb_source[t]]];
2389 transformed.eorl = eo_ttable[t][aux_eo[eorl_source[t]]];
2390 transformed.eoud = eo_ttable[t][aux_eo[eoud_source[t]]];
2391 transformed.coud = co_ttable[t][aux_co[coud_source[t]]];
2392 transformed.corl = co_ttable[t][aux_co[corl_source[t]]];
2393 transformed.cofb = co_ttable[t][aux_co[cofb_source[t]]];
2394 transformed.cp = cp_ttable[t][cube.cp];
2395 transformed.cpos = cpos_ttable[t][cube.cpos];
2396
2397 return transformed;
2398}
2399
2400/* TODO: this has to be changed using pre-computations */
2401bool
2402block_solved(Cube cube, Block block)
2403{
2404 CubeArray *arr = new_cubearray(cube, pf_all);
2405 int i;
2406 bool ret = true;
2407
2408 for (i = 0; i < 12; i++)
2409 ret = ret && !(block.edge[i] && (arr->ep[i] != i || arr->eofb[i]));
2410 for (i = 0; i < 8; i++)
2411 ret = ret && !(block.corner[i] && (arr->cp[i] != i || arr->coud[i]));
2412 for (i = 0; i < 6; i++)
2413 ret = ret && !(block.center[i] && arr->cpos[i] != i);
2414
2415 free_cubearray(arr, pf_all);
2416
2417 return ret;
2418}
2419
2420Center
2421center_at(Cube cube, Center c)
2422{
2423 int ret;
2424 CubeArray *arr = new_cubearray(cube, pf_cpos);
2425
2426 ret = arr->cpos[c];
2427 free_cubearray(arr, pf_cpos);
2428
2429 return ret;
2430}
2431
2432Cube
2433compose(Cube c2, Cube c1)
2434{
2435 return compose_filtered(c2, c1, pf_all);
2436}
2437
2438Corner
2439corner_at(Cube cube, Corner c)
2440{
2441 int ret;
2442 CubeArray *arr = new_cubearray(cube, pf_cp);
2443
2444 ret = arr->cp[c];
2445 free_cubearray(arr, pf_cp);
2446
2447 return ret;
2448}
2449
2450Edge
2451edge_at(Cube cube, Edge e)
2452{
2453 int ret;
2454 CubeArray *arr = new_cubearray(cube, pf_ep);
2455
2456 ret = arr->ep[e];
2457 free_cubearray(arr, pf_ep);
2458
2459 return ret;
2460}
2461
2462bool
2463equal(Cube c1, Cube c2)
2464{
2465 return c1.eofb == c2.eofb &&
2466 c1.epose == c2.epose &&
2467 c1.eposs == c2.eposs &&
2468 c1.eposm == c2.eposm &&
2469 c1.coud == c2.coud &&
2470 c1.cp == c2.cp &&
2471 c1.cpos == c2.cpos;
2472}
2473
2474Cube
2475inverse_cube(Cube cube)
2476{
2477 CubeArray *arr = new_cubearray(cube, pf_all);
2478 CubeArray *inv = new_cubearray((Cube){0}, pf_all);
2479 Cube ret;
2480 int i;
2481
2482 for (i = 0; i < 12; i++) {
2483 inv->ep[arr->ep[i]] = i;
2484 inv->eofb[arr->ep[i]] = arr->eofb[i];
2485 inv->eorl[arr->ep[i]] = arr->eorl[i];
2486 inv->eoud[arr->ep[i]] = arr->eoud[i];
2487 }
2488
2489 for (i = 0; i < 8; i++) {
2490 inv->cp[arr->cp[i]] = i;
2491 inv->coud[arr->cp[i]] = (3 - arr->coud[i]) % 3;
2492 inv->corl[arr->cp[i]] = (3 - arr->corl[i]) % 3;
2493 inv->cofb[arr->cp[i]] = (3 - arr->cofb[i]) % 3;
2494 }
2495
2496 for (int i = 0; i < 6; i++)
2497 inv->cpos[arr->cpos[i]] = i;
2498
2499 ret = arrays_to_cube(inv, pf_all);
2500 free_cubearray(arr, pf_all);
2501 free_cubearray(inv, pf_all);
2502
2503 return ret;
2504}
2505
2506Move
2507inverse_move(Move m)
2508{
2509 return inverse_move_aux[m];
2510}
2511
2512Trans
2513inverse_trans(Trans t)
2514{
2515 return inverse_trans_aux[t];
2516}
2517
2518bool
2519is_admissible(Cube cube)
2520{
2521 /* TODO: this should check consistency of different orientations */
2522 /* TODO: check that centers are opposite and admissible */
2523
2524 CubeArray *a = new_cubearray(cube, pf_all);
2525 int parity;
2526 bool perm;
2527
2528 perm = is_perm(a->ep, 12) &&
2529 is_perm(a->cp, 8) &&
2530 is_perm(a->cpos, 6);
2531 parity = perm_sign(a->ep, 12) +
2532 perm_sign(a->cp, 8) +
2533 perm_sign(a->cpos, 6);
2534
2535 return perm && parity % 2 == 0;
2536}
2537
2538bool
2539is_solved(Cube cube, bool reorient)
2540{
2541 Trans i;
2542
2543 if (reorient)
2544 for (i = 0; i < NROTATIONS; i++)
2545 if (is_solved(apply_alg(trans_algs[i],cube), false))
2546 return true;
2547
2548 return equal(cube, (Cube){0});
2549}
2550
2551int
2552piece_orientation(Cube cube, int piece, char *orientation)
2553{
2554 int arr[12], n, b;
2555 uint16_t x;
2556
2557 if (!strcmp(orientation, "eofb")) {
2558 x = cube.eofb;
2559 n = 12;
2560 b = 2;
2561 } else if (!strcmp(orientation, "eorl")) {
2562 x = cube.eorl;
2563 n = 12;
2564 b = 2;
2565 } else if (!strcmp(orientation, "eoud")) {
2566 x = cube.eoud;
2567 n = 12;
2568 b = 2;
2569 } else if (!strcmp(orientation, "coud")) {
2570 x = cube.coud;
2571 n = 8;
2572 b = 3;
2573 } else if (!strcmp(orientation, "corl")) {
2574 x = cube.corl;
2575 n = 8;
2576 b = 3;
2577 } else if (!strcmp(orientation, "cofb")) {
2578 x = cube.cofb;
2579 n = 8;
2580 b = 3;
2581 } else {
2582 return -1;
2583 }
2584
2585 int_to_sum_zero_array(x, b, n, arr);
2586 if (piece < n)
2587 return arr[piece];
2588
2589 return -1;
2590}
2591
2592void
2593print_cube(Cube cube)
2594{
2595 CubeArray *arr = new_cubearray(cube, pf_all);
2596
2597 for (int i = 0; i < 12; i++)
2598 printf(" %s ", edge_string[arr->ep[i]]);
2599 printf("\n");
2600
2601 for (int i = 0; i < 12; i++)
2602 printf(" %c ", arr->eofb[i] + '0');
2603 printf("\n");
2604
2605 for (int i = 0; i < 8; i++)
2606 printf("%s ", corner_string[arr->cp[i]]);
2607 printf("\n");
2608
2609 for (int i = 0; i < 8; i++)
2610 printf(" %c ", arr->coud[i] + '0');
2611 printf("\n");
2612
2613 for (int i = 0; i < 6; i++)
2614 printf(" %s ", center_string[arr->cpos[i]]);
2615 printf("\n");
2616
2617 free_cubearray(arr, pf_all);
2618}
2619
2620Cube
2621random_cube()
2622{
2623 CubeArray *arr = new_cubearray((Cube){0}, pf_4val);
2624 Cube ret;
2625 int ep, cp, eo, co;
2626
2627 ep = rand() % FACTORIAL12;
2628 cp = rand() % FACTORIAL8;
2629 eo = rand() % POW2TO11;
2630 co = rand() % POW3TO7;
2631
2632 index_to_perm(ep, 12, arr->ep);
2633 index_to_perm(cp, 8, arr->cp);
2634 int_to_sum_zero_array(eo, 2, 12, arr->eofb);
2635 int_to_sum_zero_array(co, 3, 8, arr->coud);
2636
2637 if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8))
2638 swap(&(arr->ep[0]), &(arr->ep[1]));
2639
2640 ret = arrays_to_cube(arr, pf_4val);
2641 free_cubearray(arr, pf_4val);
2642
2643 return ret;
2644}
2645
2646AlgList *
2647solve(Cube cube, Step step, SolveOptions *opts)
2648{
2649 AlgListNode *node;
2650 AlgList *sols = new_alglist();
2651 Cube c = apply_trans(step.pre_trans, cube);
2652 DfsData dd = {
2653 .m = 0,
2654 .niss = false,
2655 .last1 = NULLMOVE,
2656 .last2 = NULLMOVE,
2657 .sols = sols,
2658 .current_alg = new_alg("")
2659 };
2660
2661 if (step.ready != NULL && !step.ready(c))
2662 return sols;
2663
2664 moveset_to_list(step.moveset, step.check, dd.sorted_moves);
2665
2666 for (dd.d = MAX(opts->min_moves, step.check(c));
2667 dd.d <= opts->max_moves && !(sols->len && opts->optimal_only);
2668 dd.d++) {
2669 solve_dfs(c, step, opts, &dd);
2670 if (opts->feedback)
2671 fprintf(stderr,
2672 "Depth %d completed, found %d solutions\n",
2673 dd.d, sols->len);
2674 }
2675
2676 for (node = sols->first; node != NULL; node = node->next)
2677 transform_alg(inverse_trans_aux[step.pre_trans], node->alg);
2678
2679 return sols;
2680}
2681
2682Alg *
2683inverse_alg(Alg *alg)
2684{
2685 Alg *ret = new_alg("");
2686 AlgNode *i;
2687
2688 for (i = alg->last; i != NULL; i = i->prev)
2689 append_move(ret, i->m, i->inverse);
2690
2691 return ret;
2692}
2693
2694Alg *
2695new_alg(char *str)
2696{
2697 Alg *alg = malloc(sizeof(Alg));
2698 int i;
2699 bool niss = false;
2700 Move j, m;
2701
2702 alg->first = NULL;
2703 alg->last = NULL;
2704 alg->len = 0;
2705
2706 for (i = 0; str[i]; i++) {
2707 if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n')
2708 continue;
2709
2710 if (str[i] == '(' && niss) {
2711 fprintf(stderr, "Error reading moves: nested ( )\n");
2712 return alg;
2713 }
2714
2715 if (str[i] == ')' && !niss) {
2716 fprintf(stderr, "Error reading moves: unmatched )\n");
2717 return alg;
2718 }
2719
2720 if (str[i] == '(' || str[i] == ')') {
2721 niss = !niss;
2722 continue;
2723 }
2724
2725 for (j = 0; j < NMOVES; j++) {
2726 if (str[i] == move_string[j][0]) {
2727 m = j;
2728 if (m <= B && str[i+1]=='w') {
2729 m += Uw - U;
2730 i++;
2731 }
2732 if (str[i+1]=='2') {
2733 m += 1;
2734 i++;
2735 } else if (str[i+1]=='\'' || str[i+1]=='3') {
2736 m += 2;
2737 i++;
2738 }
2739 append_move(alg, m, niss);
2740 break;
2741 }
2742 }
2743 }
2744
2745 return alg;
2746}
2747
2748Alg *
2749on_inverse(Alg *alg)
2750{
2751 Alg *ret = new_alg("");
2752 AlgNode *i;
2753
2754 for (i = alg->first; i != NULL; i = i->next)
2755 append_move(ret, i->m, !i->inverse);
2756
2757 return ret;
2758}
2759
2760void
2761print_alg(Alg *alg, bool l)
2762{
2763 char fill[4];
2764 AlgNode *i;
2765 bool niss = false;
2766
2767 for (i = alg->first; i != NULL; i = i->next) {
2768 if (!niss && i->inverse)
2769 strcpy(fill, i == alg->first ? "(" : " (");
2770 if (niss && !i->inverse)
2771 strcpy(fill, ") ");
2772 if (niss == i->inverse)
2773 strcpy(fill, i == alg->first ? "" : " ");
2774
2775 printf("%s%s", fill, move_string[i->m]);
2776 niss = i->inverse;
2777 }
2778
2779 if (niss)
2780 printf(")");
2781 if (l)
2782 printf(" (%d)", alg->len);
2783
2784 printf("\n");
2785}
2786
2787void
2788print_ptable(PruneData *pd)
2789{
2790 uint64_t i, a[16];
2791
2792 memset(a, 0, 16 * sizeof(uint64_t));
2793
2794 if (!pd->generated)
2795 generate_ptable(pd);
2796
2797 for (i = 0; i < pd->size; i++)
2798 a[PTABLEVAL(pd->ptable, i)]++;
2799
2800 fprintf(stderr, "Values for table %s\n", pd->filename);
2801 for (i = 0; i < 16; i++)
2802 printf("%2lu\t%10lu\n", i, a[i]);
2803}
2804
2805void
2806print_alglist(AlgList *al, bool l)
2807{
2808 AlgListNode *i;
2809
2810 for (i = al->first; i != NULL; i = i->next)
2811 print_alg(i->alg, l);
2812}
2813
2814void
2815remove_last_move(Alg *alg)
2816{
2817 AlgNode *newlast = alg->last->prev;
2818 free(alg->last);
2819 if (newlast != NULL)
2820 newlast->next = NULL;
2821 alg->last = newlast;
2822 alg->len--;
2823}
2824
2825void
2826transform_alg(Trans t, Alg *alg)
2827{
2828 AlgNode *i;
2829
2830 for (i = alg->first; i != NULL; i = i->next)
2831 i->m = moves_ttable[t][i->m];
2832}
2833
2834
2835void
2836init()
2837{
2838 /* Order is important! */
2839 init_environment();
2840 init_strings();
2841 init_moves_aux();
2842 init_moves();
2843 init_auxtables();
2844 init_trans_aux();
2845 init_trans();
2846 init_steps();
2847}
2848
2849
diff --git a/old/2021-06-14-oldalg/cube.h b/old/2021-06-14-oldalg/cube.h
new file mode 100644
index 0000000..a17c291
--- /dev/null
+++ b/old/2021-06-14-oldalg/cube.h
@@ -0,0 +1,73 @@
1#ifndef CUBE_H
2#define CUBE_H
3
4#include <stdio.h>
5#include <stdbool.h>
6#include <stdint.h>
7#include <stdlib.h>
8#include <string.h>
9#include <time.h>
10#include <unistd.h>
11#include <sys/stat.h>
12#include "cubetypes.h"
13
14/* Steps *********************************************************************/
15
16extern Step eofb_HTM;
17extern Step eorl_HTM;
18extern Step eoud_HTM;
19extern Step coud_HTM;
20extern Step corl_HTM;
21extern Step cofb_HTM;
22extern Step coud_URF;
23extern Step corl_URF;
24extern Step cofb_URF;
25extern Step corners_HTM;
26extern Step corners_URF;
27extern Step edges_HTM;
28extern Step drud_HTM;
29extern Step optimal_HTM;
30
31extern PruneData pd_eofb_HTM;
32extern PruneData pd_coud_HTM;
33extern PruneData pd_corners_HTM;
34extern PruneData pd_ep_HTM;
35extern PruneData pd_drud_HTM;
36
37/* Public functions **********************************************************/
38
39Cube apply_alg(Alg *alg, Cube cube);
40Cube apply_move(Move m, Cube cube);
41Cube apply_trans(Trans t, Cube cube);
42bool block_solved(Cube cube, Block);
43Center center_at(Cube cube, Center c);
44Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */
45Corner corner_at(Cube cube, Corner c);
46Edge edge_at(Cube cube, Edge e);
47bool equal(Cube c1, Cube c2);
48Cube inverse_cube(Cube cube);
49Move inverse_move(Move m);
50Trans inverse_trans(Trans t);
51bool is_admissible(Cube cube);
52bool is_solved(Cube cube, bool reorient);
53int piece_orientation(Cube cube, int piece, char *orientation);
54void print_cube(Cube cube);
55Cube random_cube();
56AlgList * solve(Cube cube, Step step, SolveOptions *opts);
57
58void free_alg(Alg *alg);
59void free_alglist(AlgList *l);
60Alg * inverse_alg(Alg *alg);
61Alg * new_alg(char *str);
62Alg * on_inverse(Alg *alg);
63void print_alg(Alg *alg, bool l);
64void print_alglist(AlgList *al, bool l);
65void remove_last_move(Alg *alg);
66void transform_alg(Trans t, Alg *alg);
67
68void print_ptable(PruneData *pd);
69
70void init();
71
72#endif
73
diff --git a/old/2021-06-14-oldalg/cubetypes.h b/old/2021-06-14-oldalg/cubetypes.h
new file mode 100644
index 0000000..292fbb7
--- /dev/null
+++ b/old/2021-06-14-oldalg/cubetypes.h
@@ -0,0 +1,210 @@
1/* Typedefs ******************************************************************/
2
3typedef enum center Center;
4typedef enum corner Corner;
5typedef enum edge Edge;
6typedef enum move Move;
7typedef enum trans Trans;
8
9typedef struct alg Alg;
10typedef struct algnode AlgNode;
11typedef struct alglist AlgList;
12typedef struct alglistnode AlgListNode;
13typedef struct block Block;
14typedef struct cube Cube;
15typedef struct cubearray CubeArray;
16typedef struct dfsdata DfsData;
17typedef struct piecefilter PieceFilter;
18typedef struct prunedata PruneData;
19typedef struct solveoptions SolveOptions;
20typedef struct step Step;
21
22/* Enums *********************************************************************/
23
24enum
25center
26{
27 U_center, D_center,
28 R_center, L_center,
29 F_center, B_center
30};
31
32enum
33corner
34{
35 UFR, UFL, UBL, UBR,
36 DFR, DFL, DBL, DBR
37};
38
39enum
40edge
41{
42 UF, UL, UB, UR,
43 DF, DL, DB, DR,
44 FR, FL, BL, BR
45};
46
47enum
48move
49{
50 NULLMOVE,
51 U, U2, U3, D, D2, D3,
52 R, R2, R3, L, L2, L3,
53 F, F2, F3, B, B2, B3,
54 Uw, Uw2, Uw3, Dw, Dw2, Dw3,
55 Rw, Rw2, Rw3, Lw, Lw2, Lw3,
56 Fw, Fw2, Fw3, Bw, Bw2, Bw3,
57 M, M2, M3,
58 S, S2, S3,
59 E, E2, E3,
60 x, x2, x3,
61 y, y2, y3,
62 z, z2, z3,
63};
64
65enum
66trans
67{
68 uf, ur, ub, ul,
69 df, dr, db, dl,
70 rf, rd, rb, ru,
71 lf, ld, lb, lu,
72 fu, fr, fd, fl,
73 bu, br, bd, bl,
74 mirror, /* R|L */
75};
76
77
78/* Structs *******************************************************************/
79
80struct
81alg
82{
83 AlgNode * first;
84 AlgNode * last;
85 int len;
86};
87
88struct
89algnode
90{
91 Move m;
92 bool inverse;
93 AlgNode * next;
94 AlgNode * prev;
95};
96
97struct
98alglist
99{
100 AlgListNode * first;
101 AlgListNode * last;
102 int len;
103};
104
105struct
106alglistnode
107{
108 Alg * alg;
109 AlgListNode * next;
110};
111
112struct
113block
114{
115 bool edge[12];
116 bool corner[8];
117 bool center[6];
118};
119
120struct
121cube
122{
123 uint16_t epose;
124 uint16_t eposs;
125 uint16_t eposm;
126 uint16_t eofb;
127 uint16_t eorl;
128 uint16_t eoud;
129 uint16_t cp;
130 uint16_t coud;
131 uint16_t cofb;
132 uint16_t corl;
133 uint16_t cpos;
134};
135
136struct
137cubearray
138{
139 int * ep;
140 int * eofb;
141 int * eorl;
142 int * eoud;
143 int * cp;
144 int * coud;
145 int * corl;
146 int * cofb;
147 int * cpos;
148};
149
150struct
151dfsdata
152{
153 int d;
154 int m;
155 bool niss;
156 Move last1;
157 Move last2;
158 AlgList * sols;
159 Alg * current_alg;
160 Move sorted_moves[z3+1];
161};
162
163struct
164piecefilter
165{
166 bool epose;
167 bool eposs;
168 bool eposm;
169 bool eofb;
170 bool eorl;
171 bool eoud;
172 bool cp;
173 bool coud;
174 bool cofb;
175 bool corl;
176 bool cpos;
177};
178
179struct
180prunedata
181{
182 char * filename;
183 uint8_t * ptable;
184 uint8_t * reached;
185 bool generated;
186 uint64_t n;
187 uint64_t size;
188 uint64_t (*index)(Cube);
189 bool (*moveset)(Move);
190};
191
192struct
193solveoptions
194{
195 int min_moves;
196 int max_moves;
197 int max_solutions;
198 bool optimal_only;
199 bool can_niss;
200 bool feedback;
201};
202
203struct
204step
205{
206 int (*check)(Cube);
207 int (*ready)(Cube);
208 bool (*moveset)(Move);
209 Trans pre_trans;
210};
diff --git a/old/2021-06-14-oldalg/main.c b/old/2021-06-14-oldalg/main.c
new file mode 100644
index 0000000..445eefc
--- /dev/null
+++ b/old/2021-06-14-oldalg/main.c
@@ -0,0 +1,56 @@
1#include <stdio.h>
2#include "cube.h"
3
4int main() {
5 Alg *algo;
6 AlgList *sols;
7 Cube cube;
8 SolveOptions opts;
9 char line[1000];
10 int i, ns = 2, nrand = 100000, sum;
11
12 Step *stps[20] = {&drud_HTM, &optimal_HTM};
13 char sss[30][30] = {"DR on U/D", "Optimal solution"};
14
15 opts = (SolveOptions) {
16 .min_moves = 0,
17 .max_moves = 20,
18 .optimal_only = true,
19 .max_solutions = 1,
20 .can_niss = false,
21 .feedback = true
22 };
23
24 init();
25
26/*
27 print_ptable(&pd_drud_HTM);
28 print_ptable(&pd_ep_HTM);
29 print_ptable(&pd_corners_HTM);
30*/
31
32 srand(time(NULL));
33 sum = 0;
34 for (i = 0; i < nrand; i++)
35 sum += optimal_HTM.check(random_cube());
36 printf("Average pruning value: %lf\n", ((double)sum) / ((double) nrand));
37
38 printf("Welcome to nissy 2.0! Insert a scramble:\n");
39
40 if (fgets(line, 1000, stdin) != NULL) {
41 algo = new_alg(line);
42 cube = apply_alg(algo, (Cube){0});
43
44 for (i = 0; i < ns; i++) {
45 if (stps[i]->check == NULL)
46 fprintf(stderr, "Check function for step %d is null\n", i);
47 sols = solve(cube, *stps[i], &opts);
48 printf("%s: %d solutions found:\n", sss[i], sols->len);
49 print_alglist(sols, true);
50 free_alglist(sols);
51 }
52 free(algo);
53 }
54
55 return 0;
56}
diff --git a/old/2021-06-15-before-separating-steps/cube.c b/old/2021-06-15-before-separating-steps/cube.c
new file mode 100644
index 0000000..06c829b
--- /dev/null
+++ b/old/2021-06-15-before-separating-steps/cube.c
@@ -0,0 +1,2836 @@
1#include "cube.h"
2
3/* Constants and macros *****************************************************/
4
5#define POW2TO11 2048ULL
6#define POW2TO12 4096ULL
7#define POW3TO7 2187ULL
8#define POW3TO8 6561ULL
9#define FACTORIAL4 24ULL
10#define FACTORIAL6 720ULL
11#define FACTORIAL8 40320ULL
12#define FACTORIAL12 479001600ULL
13#define BINOM12ON4 495ULL
14#define BINOM8ON4 70ULL
15#define MIN(a,b) (((a) < (b)) ? (a) : (b))
16#define MAX(a,b) (((a) > (b)) ? (a) : (b))
17
18#define BASEALGLEN 50
19#define NMOVES (z3+1)
20#define NTRANS (mirror+1)
21#define NROTATIONS (NTRANS-1)
22#define PTABLESIZE(n) ((n+1) / 2)
23#define PTABLEVAL(tab,ind) (((ind)%2) ? (tab[(ind)/2] / 16) : \
24 (tab[(ind)/2] % 16))
25
26
27/* Local functions **********************************************************/
28
29static Cube admissible_ep(Cube cube, PieceFilter f);
30static void append_alg(AlgList *l, Alg *alg);
31static void append_move(Alg *alg, Move m, bool inverse);
32static Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a);
33static void apply_permutation(int *perm, int *set, int n);
34static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f);
35static uint16_t array_ep_to_epos(int *ep, int *eps_solved);
36static Cube arrays_to_cube(CubeArray *arr, PieceFilter f);
37static Move base_move(Move m);
38static int binomial(int n, int k);
39static Cube compose_filtered(Cube c2, Cube c1, PieceFilter f);
40static void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f);
41static int digit_array_to_int(int *a, int n, int b);
42static int edge_slice(Edge e); /* E=0, S=1, M=2 */
43static int epos_dependent(int pos1, int pos2);
44static uint16_t epos_from_arrays(int *epos, int *ep);
45static void epos_to_partial_ep(uint16_t epos, int *ep, int *ss);
46static int factorial(int n);
47static void free_alglistnode(AlgListNode *aln);
48static void free_cubearray(CubeArray *arr, PieceFilter f);
49static void generate_ptable(PruneData *pd);
50static void generate_ptable_dfs(Cube c, PruneData *pd, DfsData *dd);
51static void index_to_perm(int p, int n, int *r);
52static void index_to_subset(int s, int n, int k, int *r);
53static void int_to_digit_array(int a, int b, int n, int *r);
54static void int_to_sum_zero_array(int x, int b, int n, int *a);
55static int invert_digits(int a, int b, int n);
56static bool is_perm(int *a, int n);
57static bool is_subset(int *a, int n, int k);
58static Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf);
59static void moveset_to_list(bool (*ms)(Move), int (*f)(Cube), Move *r);
60static AlgList * new_alglist();
61static CubeArray * new_cubearray(Cube cube, PieceFilter f);
62static int perm_sign(int *a, int n);
63static int perm_to_index(int *a, int n);
64static int powint(int a, int b);
65static void ptable_set_reached(PruneData *pd, uint64_t ind);
66static void ptable_update(PruneData *pd, uint64_t ind, int m);
67static bool read_ptable_file(PruneData *pd);
68static bool read_ttables_file();
69static bool read_mtables_file();
70static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f);
71static void solve_dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd);
72static int subset_to_index(int *a, int n, int k);
73static void sum_arrays_mod(int *src, int *dst, int n, int m);
74static void swap(int *a, int *b);
75static bool write_ptable_file(PruneData *pd);
76static bool write_ttables_file();
77static bool write_mtables_file();
78
79static void init_auxtables();
80static void init_environment();
81static void init_moves();
82static void init_moves_aux();
83static void init_steps();
84static void init_strings();
85static void init_trans();
86static void init_trans_aux();
87
88static bool moveset_HTM(Move m);
89static bool moveset_URF(Move m);
90
91/* Steps and related functions and data **************************************/
92
93Step eofb_HTM;
94Step eorl_HTM;
95Step eoud_HTM;
96Step coud_HTM;
97Step corl_HTM;
98Step cofb_HTM;
99Step coud_URF;
100Step corl_URF;
101Step cofb_URF;
102Step corners_HTM;
103Step corners_URF;
104Step edges_HTM;
105Step drud_HTM;
106Step optimal_HTM;
107
108PruneData pd_eofb_HTM;
109PruneData pd_coud_HTM;
110PruneData pd_corners_HTM;
111PruneData pd_ep_HTM;
112PruneData pd_drud_HTM;
113
114static uint64_t index_eofb(Cube cube);
115static uint64_t index_coud(Cube cube);
116static uint64_t index_corners(Cube cube);
117static uint64_t index_ep(Cube cube);
118static uint64_t index_drud(Cube cube);
119
120static int check_nothing(Cube cube);
121static int check_eofb_HTM(Cube cube);
122static int check_coud_HTM(Cube cube);
123static int check_coud_URF(Cube cube);
124static int check_corners_HTM(Cube cube);
125static int check_corners_URF(Cube cube);
126static int check_edges_HTM(Cube cube);
127static int check_drud_HTM(Cube cube);
128static int check_optimal_HTM(Cube cube);
129
130/* All sorts of useful costants and tables **********************************/
131
132static char * tabledir;
133
134static PieceFilter pf_all;
135static PieceFilter pf_4val;
136static PieceFilter pf_epcp;
137static PieceFilter pf_cpos;
138static PieceFilter pf_cp;
139static PieceFilter pf_ep;
140static PieceFilter pf_e;
141static PieceFilter pf_s;
142static PieceFilter pf_m;
143static PieceFilter pf_eo;
144static PieceFilter pf_co;
145
146static int epe_solved[4];
147static int eps_solved[4];
148static int epm_solved[4];
149
150static char move_string[NMOVES][7];
151static char edge_string[12][7];
152static char corner_string[8][7];
153static char center_string[6][7];
154
155static bool commute[NMOVES][NMOVES];
156static bool possible_next[NMOVES][NMOVES][NMOVES];
157static Move inverse_move_aux[NMOVES];
158static Trans inverse_trans_aux[NTRANS];
159static int epos_dependent_aux[BINOM12ON4][BINOM12ON4];
160
161static uint16_t epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
162static uint16_t eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
163static uint16_t eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
164static uint16_t eo_ttable[NTRANS][POW2TO11];
165static uint16_t cp_ttable[NTRANS][FACTORIAL8];
166static uint16_t co_ttable[NTRANS][POW3TO7];
167static uint16_t cpos_ttable[NTRANS][FACTORIAL6];
168static Move moves_ttable[NTRANS][NMOVES];
169
170static uint16_t epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
171static uint16_t eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
172static uint16_t eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
173static uint16_t eofb_mtable[NMOVES][POW2TO11];
174static uint16_t eorl_mtable[NMOVES][POW2TO11];
175static uint16_t eoud_mtable[NMOVES][POW2TO11];
176static uint16_t cp_mtable[NMOVES][FACTORIAL8];
177static uint16_t coud_mtable[NMOVES][POW3TO7];
178static uint16_t cofb_mtable[NMOVES][POW3TO7];
179static uint16_t corl_mtable[NMOVES][POW3TO7];
180static uint16_t cpos_mtable[NMOVES][FACTORIAL6];
181
182static uint64_t me[12];
183
184static int edge_cycle[NMOVES][12];
185static int corner_cycle[NMOVES][8];
186static int center_cycle[NMOVES][6];
187static int eofb_flipped[NMOVES][12];
188static int eorl_flipped[NMOVES][12];
189static int eoud_flipped[NMOVES][12];
190static int coud_flipped[NMOVES][8];
191static int corl_flipped[NMOVES][8];
192static int cofb_flipped[NMOVES][8];
193static Alg * equiv_alg[NMOVES];
194
195static int epose_source[NTRANS]; /* 0=epose, 1=eposs, 2=eposm */
196static int eposs_source[NTRANS];
197static int eposm_source[NTRANS];
198static int eofb_source[NTRANS]; /* 0=eoud, 1=eorl, 2=eofb */
199static int eorl_source[NTRANS];
200static int eoud_source[NTRANS];
201static int coud_source[NTRANS]; /* 0=coud, 1=corl, 2=cofb */
202static int cofb_source[NTRANS];
203static int corl_source[NTRANS];
204static int ep_mirror[12];
205static int cp_mirror[8];
206static int cpos_mirror[6];
207static Alg * trans_algs[NROTATIONS];
208
209
210/* Local functions implementation ********************************************/
211
212static Cube
213admissible_ep(Cube cube, PieceFilter f)
214{
215 CubeArray *arr = new_cubearray(cube, f);
216 Cube ret;
217 bool used[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
218 int i, j;
219
220 for (i = 0; i < 12; i++)
221 if (arr->ep[i] != -1)
222 used[arr->ep[i]] = true;
223
224 for (i = 0, j = 0; i < 12; i++) {
225 for ( ; j < 11 && used[j]; j++);
226 if (arr->ep[i] == -1)
227 arr->ep[i] = j++;
228 }
229
230 ret = arrays_to_cube(arr, pf_ep);
231 free_cubearray(arr, f);
232
233 return ret;
234}
235
236static void
237append_alg(AlgList *l, Alg *alg)
238{
239 AlgListNode *node = malloc(sizeof(AlgListNode));
240 int i;
241
242 node->alg = new_alg("");
243 for (i = 0; i < alg->len; i++)
244 append_move(node->alg, alg->move[i], alg->inv[i]);
245 node->next = NULL;
246
247 if (++l->len == 1)
248 l->first = node;
249 else
250 l->last->next = node;
251 l->last = node;
252}
253
254static void
255append_move(Alg *alg, Move m, bool inverse)
256{
257 if (alg->len == alg->allocated) {
258 if (alg->len > 1000000) {
259 fprintf(stderr, "Warning: very long alg,");
260 fprintf(stderr, "something might be wrong.\n");
261 }
262 alg->move = realloc(alg->move, 2 * alg->len * sizeof(Move));
263 alg->inv = realloc(alg->inv, 2 * alg->len * sizeof(bool));
264 alg->allocated *= 2;
265 }
266
267 alg->move[alg->len] = m;
268 alg->inv [alg->len] = inverse;
269 alg->len++;
270}
271
272static Cube
273apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a)
274{
275 Cube ret = {0};
276 int i;
277
278 for (i = 0; i < alg->len; i++)
279 if (alg->inv[i])
280 ret = a ? apply_move(alg->move[i], ret) :
281 apply_move_cubearray(alg->move[i], ret, f);
282
283 ret = compose_filtered(c, inverse_cube(ret), f);
284
285 for (i = 0; i < alg->len; i++)
286 if (!alg->inv[i])
287 ret = a ? apply_move(alg->move[i], ret) :
288 apply_move_cubearray(alg->move[i], ret, f);
289
290 return ret;
291}
292
293static void
294apply_permutation(int *perm, int *set, int n)
295{
296 int *aux = malloc(n * sizeof(int));
297 int i;
298
299 if (!is_perm(perm, n))
300 return;
301
302 for (i = 0; i < n; i++)
303 aux[i] = set[perm[i]];
304
305 memcpy(set, aux, n * sizeof(int));
306 free(aux);
307}
308
309static Cube
310apply_move_cubearray(Move m, Cube cube, PieceFilter f)
311{
312 CubeArray m_arr = {
313 edge_cycle[m],
314 eofb_flipped[m],
315 eorl_flipped[m],
316 eoud_flipped[m],
317 corner_cycle[m],
318 coud_flipped[m],
319 corl_flipped[m],
320 cofb_flipped[m],
321 center_cycle[m]
322 };
323
324 return move_via_arrays(&m_arr, cube, f);
325}
326
327static uint16_t
328array_ep_to_epos(int *ep, int *ss)
329{
330 int epos[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
331 int eps[4];
332 int i, j, is;
333
334 for (i = 0, is = 0; i < 12; i++) {
335 for (j = 0; j < 4; j++) {
336 if (ep[i] == ss[j]) {
337 eps[is++] = j;
338 epos[i] = 1;
339 }
340 }
341 }
342
343 for (i = 0; i < 4; i++)
344 swap(&epos[ss[i]], &epos[i+8]);
345
346 return epos_from_arrays(epos, eps);
347}
348
349static Cube
350arrays_to_cube(CubeArray *arr, PieceFilter f)
351{
352 Cube ret = {0};
353
354 if (f.epose)
355 ret.epose = array_ep_to_epos(arr->ep, epe_solved);
356 if (f.eposs)
357 ret.eposs = array_ep_to_epos(arr->ep, eps_solved);
358 if (f.eposm)
359 ret.eposm = array_ep_to_epos(arr->ep, epm_solved);
360 if (f.eofb)
361 ret.eofb = digit_array_to_int(arr->eofb, 11, 2);
362 if (f.eorl)
363 ret.eorl = digit_array_to_int(arr->eorl, 11, 2);
364 if (f.eoud)
365 ret.eoud = digit_array_to_int(arr->eoud, 11, 2);
366 if (f.cp)
367 ret.cp = perm_to_index(arr->cp, 8);
368 if (f.coud)
369 ret.coud = digit_array_to_int(arr->coud, 7, 3);
370 if (f.corl)
371 ret.corl = digit_array_to_int(arr->corl, 7, 3);
372 if (f.cofb)
373 ret.cofb = digit_array_to_int(arr->cofb, 7, 3);
374 if (f.cpos)
375 ret.cpos = perm_to_index(arr->cpos, 6);
376
377 return ret;
378}
379
380static Move
381base_move(Move m)
382{
383 if (m == NULLMOVE)
384 return NULLMOVE;
385 else
386 return m - (m-1)%3;
387}
388
389static int
390binomial(int n, int k)
391{
392 if (n < 0 || k < 0 || k > n)
393 return 0;
394
395 return factorial(n) / (factorial(k) * factorial(n-k));
396}
397
398static Cube
399compose_filtered(Cube c2, Cube c1, PieceFilter f)
400{
401 CubeArray *arr = new_cubearray(c2, f);
402 Cube ret;
403
404 ret = move_via_arrays(arr, c1, f);
405 free_cubearray(arr, f);
406
407 return ret;
408}
409
410static void
411cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f)
412{
413 int i;
414
415 if (f.epose || f.eposs || f.eposm)
416 for (i = 0; i < 12; i++)
417 arr->ep[i] = -1;
418
419 if (f.epose)
420 epos_to_partial_ep(cube.epose, arr->ep, epe_solved);
421 if (f.eposs)
422 epos_to_partial_ep(cube.eposs, arr->ep, eps_solved);
423 if (f.eposm)
424 epos_to_partial_ep(cube.eposm, arr->ep, epm_solved);
425 if (f.eofb)
426 int_to_sum_zero_array(cube.eofb, 2, 12, arr->eofb);
427 if (f.eorl)
428 int_to_sum_zero_array(cube.eorl, 2, 12, arr->eorl);
429 if (f.eoud)
430 int_to_sum_zero_array(cube.eoud, 2, 12, arr->eoud);
431 if (f.cp)
432 index_to_perm(cube.cp, 8, arr->cp);
433 if (f.coud)
434 int_to_sum_zero_array(cube.coud, 3, 8, arr->coud);
435 if (f.corl)
436 int_to_sum_zero_array(cube.corl, 3, 8, arr->corl);
437 if (f.cofb)
438 int_to_sum_zero_array(cube.cofb, 3, 8, arr->cofb);
439 if (f.cpos)
440 index_to_perm(cube.cpos, 6, arr->cpos);
441}
442
443static int
444digit_array_to_int(int *a, int n, int b)
445{
446 int i, ret = 0, p = 1;
447
448 for (i = 0; i < n; i++, p *= b)
449 ret += a[i] * p;
450
451 return ret;
452}
453
454static int
455edge_slice(Edge e) {
456 if (e < 0 || e > 11)
457 return -1;
458
459 if (e == FR || e == FL || e == BL || e == BR)
460 return 0;
461 if (e == UR || e == UL || e == DR || e == DL)
462 return 1;
463
464 return 2;
465}
466
467static int
468epos_dependent(int poss, int pose)
469{
470 int ep[12] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
471 int ep8[8] = {0, 0, 0, 0, 0, 0, 0, 0};
472 int i, j;
473
474 epos_to_partial_ep(poss*FACTORIAL4, ep, eps_solved);
475 epos_to_partial_ep(pose*FACTORIAL4, ep, epe_solved);
476
477 for (i = 0, j = 0; i < 12; i++)
478 if (edge_slice(ep[i]) != 1)
479 ep8[j++] = (edge_slice(ep[i]) == 0) ? 1 : 0;
480
481 return subset_to_index(ep8, 8, 4);
482}
483
484static uint16_t
485epos_from_arrays(int *epos, int *ep)
486{
487 return FACTORIAL4 * subset_to_index(epos,12,4) + perm_to_index(ep,4);
488}
489
490static void
491epos_to_partial_ep(uint16_t epos, int *ep, int *ss)
492{
493 int i, is, eposs[12], eps[4];
494
495 index_to_perm(epos % FACTORIAL4, 4, eps);
496 index_to_subset(epos / FACTORIAL4, 12, 4, eposs);
497
498 for (i = 0; i < 4; i++)
499 swap(&eposs[ss[i]], &eposs[i+8]);
500
501 for (i = 0, is = 0; i < 12; i++)
502 if (eposs[i])
503 ep[i] = ss[eps[is++]];
504}
505
506static int
507factorial(int n)
508{
509 int i, ret = 1;
510
511 if (n < 0)
512 return 0;
513
514 for (i = 1; i <= n; i++)
515 ret *= i;
516
517 return ret;
518}
519
520void
521free_alg(Alg *alg)
522{
523 free(alg->move);
524 free(alg->inv);
525 free(alg);
526}
527
528void
529free_alglist(AlgList *l)
530{
531 AlgListNode *aux, *i = l->first;
532
533 while (i != NULL) {
534 aux = i->next;
535 free_alglistnode(i);
536 i = aux;
537 }
538 free(l);
539}
540
541void
542free_alglistnode(AlgListNode *aln)
543{
544 free_alg(aln->alg);
545 free(aln);
546}
547
548static void
549free_cubearray(CubeArray *arr, PieceFilter f)
550{
551 if (f.epose || f.eposs || f.eposm)
552 free(arr->ep);
553 if (f.eofb)
554 free(arr->eofb);
555 if (f.eorl)
556 free(arr->eorl);
557 if (f.eoud)
558 free(arr->eoud);
559 if (f.cp)
560 free(arr->cp);
561 if (f.coud)
562 free(arr->coud);
563 if (f.corl)
564 free(arr->corl);
565 if (f.cofb)
566 free(arr->cofb);
567 if (f.cpos)
568 free(arr->cpos);
569
570 free(arr);
571}
572
573static void
574generate_ptable(PruneData *pd)
575{
576 uint64_t j;
577 DfsData dd;
578
579 if (pd->generated)
580 return;
581
582 /* TODO: check if memory is enough, otherwise maybe crash gracefully? */
583 pd->ptable = malloc(PTABLESIZE(pd->size) * sizeof(uint8_t));
584
585 if (read_ptable_file(pd)) {
586 pd->generated = true;
587 return;
588 }
589
590 fprintf(stderr, "Cannot load %s, generating it\n", pd->filename);
591
592 dd.m = 0;
593 dd.last1 = NULLMOVE;
594 dd.last2 = NULLMOVE;
595
596 /* We use 4 bits per value, so any distance >= 15 is set to 15 */
597 for (j = 0; j < pd->size; j++)
598 ptable_update(pd, j, 15);
599
600 moveset_to_list(pd->moveset, NULL, dd.sorted_moves);
601
602 pd->reached = malloc(PTABLESIZE(pd->size) * sizeof(uint8_t));
603 for (dd.d = 0, pd->n = 0; dd.d < 15 && pd->n < pd->size; dd.d++) {
604 memset(pd->reached, 0, PTABLESIZE(pd->size)*sizeof(uint8_t));
605 generate_ptable_dfs((Cube){0}, pd, &dd);
606 fprintf(stderr, "Depth %d completed, generated %lu/%lu\n",
607 dd.d, pd->n, pd->size);
608 }
609
610 if (!write_ptable_file(pd))
611 fprintf(stderr, "Error writing ptable file\n");
612
613 pd->generated = true;
614 free(pd->reached);
615}
616
617static void
618generate_ptable_dfs(Cube c, PruneData *pd, DfsData *dd)
619{
620 uint64_t ind = pd->index(c);
621 int oldval = PTABLEVAL(pd->ptable, ind);
622 Move i, move, l1 = dd->last1, l2 = dd->last2;
623
624 if (oldval < dd->m || PTABLEVAL(pd->reached, ind) || pd->n == pd->size)
625 return;
626
627 ptable_set_reached(pd, ind);
628
629 if (dd->m == dd->d) {
630 if (dd->m < oldval)
631 ptable_update(pd, ind, dd->m);
632 return;
633 }
634
635 dd->m++;
636 dd->last2 = dd->last1;
637
638 for (i = 0; dd->sorted_moves[i] != NULLMOVE; i++) {
639 move = dd->sorted_moves[i];
640 if (possible_next[l2][l1][move]) {
641 dd->last1 = move;
642 generate_ptable_dfs(apply_move(move, c), pd, dd);
643 }
644 }
645
646 dd->m--;
647 dd->last1 = l1;
648 dd->last2 = l2;
649}
650
651static void
652index_to_perm(int p, int n, int *r)
653{
654 int *a = malloc(n * sizeof(int));
655 int i, j, c;
656
657 for (i = 0; i < n; i++)
658 a[i] = 0;
659
660 if (p < 0 || p >= factorial(n))
661 for (i = 0; i < n; i++)
662 r[i] = -1;
663
664 for (i = 0; i < n; i++) {
665 c = 0;
666 j = 0;
667 while (c <= p / factorial(n-i-1))
668 c += a[j++] ? 0 : 1;
669 r[i] = j-1;
670 a[j-1] = 1;
671 p %= factorial(n-i-1);
672 }
673
674 free(a);
675}
676
677static void
678index_to_subset(int s, int n, int k, int *r)
679{
680 int i, j, v;
681
682 if (s < 0 || s >= binomial(n, k)) {
683 for (i = 0; i < n; i++)
684 r[i] = -1;
685 return;
686 }
687
688 for (i = 0; i < n; i++) {
689 if (k == n-i) {
690 for (j = i; j < n; j++)
691 r[j] = 1;
692 return;
693 }
694
695 if (k == 0) {
696 for (j = i; j < n; j++)
697 r[j] = 0;
698 return;
699 }
700
701 v = binomial(n-i-1, k);
702 if (s >= v) {
703 r[i] = 1;
704 k--;
705 s -= v;
706 } else {
707 r[i] = 0;
708 }
709 }
710}
711
712static void
713int_to_digit_array(int a, int b, int n, int *r)
714{
715 int i;
716
717 if (b <= 1)
718 for (i = 0; i < n; i++)
719 r[i] = 0;
720 else
721 for (i = 0; i < n; i++, a /= b)
722 r[i] = a % b;
723}
724
725static void
726int_to_sum_zero_array(int x, int b, int n, int *a)
727{
728 int i, s = 0;
729
730 if (b <= 1) {
731 for (i = 0; i < n; i++)
732 a[i] = 0;
733 } else {
734 int_to_digit_array(x, b, n-1, a);
735 for (i = 0; i < n - 1; i++)
736 s = (s + a[i]) % b;
737 a[n-1] = (b - s) % b;
738 }
739}
740
741static int
742invert_digits(int a, int b, int n)
743{
744 int i, ret, *r = malloc(n * sizeof(int));
745
746 int_to_digit_array(a, b, n, r);
747 for (i = 0; i < n; i++)
748 r[i] = (b-r[i]) % b;
749
750 ret = digit_array_to_int(r, n, b);
751 free(r);
752 return ret;
753}
754
755static bool
756is_perm(int *a, int n)
757{
758 int *aux = malloc(n * sizeof(int));
759 int i;
760
761 for (i = 0; i < n; i++)
762 if (a[i] < 0 || a[i] >= n)
763 return false;
764 else
765 aux[a[i]] = 1;
766
767 for (i = 0; i < n; i++)
768 if (!aux[i])
769 return false;
770
771 free(aux);
772
773 return true;
774}
775
776static bool
777is_subset(int *a, int n, int k)
778{
779 int i, sum = 0;
780
781 for (i = 0; i < n; i++)
782 sum += a[i] ? 1 : 0;
783
784 return sum == k;
785}
786
787static Cube
788move_via_arrays(CubeArray *arr, Cube c, PieceFilter f)
789{
790 CubeArray *arrc = new_cubearray(c, f);
791 Cube ret;
792
793 if (f.epose || f.eposs || f.eposm)
794 apply_permutation(arr->ep, arrc->ep, 12);
795
796 if (f.eofb) {
797 apply_permutation(arr->ep, arrc->eofb, 12);
798 sum_arrays_mod(arr->eofb, arrc->eofb, 12, 2);
799 }
800
801 if (f.eorl) {
802 apply_permutation(arr->ep, arrc->eorl, 12);
803 sum_arrays_mod(arr->eorl, arrc->eorl, 12, 2);
804 }
805
806 if (f.eoud) {
807 apply_permutation(arr->ep, arrc->eoud, 12);
808 sum_arrays_mod(arr->eoud, arrc->eoud, 12, 2);
809 }
810
811 if (f.cp)
812 apply_permutation(arr->cp, arrc->cp, 8);
813
814 if (f.coud) {
815 apply_permutation(arr->cp, arrc->coud, 8);
816 sum_arrays_mod(arr->coud, arrc->coud, 8, 3);
817 }
818
819 if (f.corl) {
820 apply_permutation(arr->cp, arrc->corl, 8);
821 sum_arrays_mod(arr->corl, arrc->corl, 8, 3);
822 }
823
824 if (f.cofb) {
825 apply_permutation(arr->cp, arrc->cofb, 8);
826 sum_arrays_mod(arr->cofb, arrc->cofb, 8, 3);
827 }
828
829 if (f.cpos)
830 apply_permutation(arr->cpos, arrc->cpos, 6);
831
832 ret = arrays_to_cube(arrc, f);
833 free_cubearray(arrc, f);
834
835 return ret;
836}
837
838static void
839moveset_to_list(bool (*ms)(Move m), int (*f)(Cube), Move *r)
840{
841 Cube c;
842 int b[NMOVES];
843 int na = 0, nb = 0;
844 Move i;
845
846 if (ms == NULL) {
847 fprintf(stderr, "Error: no moveset given\n");
848 return;
849 }
850
851 for (i = U; i < NMOVES; i++) {
852 if (ms(i)) {
853 c = apply_move(i, (Cube){0});
854 if (f != NULL && f(c))
855 r[na++] = i;
856 else
857 b[nb++] = i;
858 }
859 }
860
861 memcpy(r + na, b, nb * sizeof(Move));
862 r[na+nb] = NULLMOVE;
863}
864
865static AlgList *
866new_alglist()
867{
868 AlgList *ret = malloc(sizeof(AlgList));
869
870 ret->len = 0;
871 ret->first = NULL;
872 ret->last = NULL;
873
874 return ret;
875}
876
877static CubeArray *
878new_cubearray(Cube cube, PieceFilter f)
879{
880 CubeArray *arr = malloc(sizeof(CubeArray));
881
882 if (f.epose || f.eposs || f.eposm)
883 arr->ep = malloc(12 * sizeof(int));
884 if (f.eofb)
885 arr->eofb = malloc(12 * sizeof(int));
886 if (f.eorl)
887 arr->eorl = malloc(12 * sizeof(int));
888 if (f.eoud)
889 arr->eoud = malloc(12 * sizeof(int));
890 if (f.cp)
891 arr->cp = malloc(8 * sizeof(int));
892 if (f.coud)
893 arr->coud = malloc(8 * sizeof(int));
894 if (f.corl)
895 arr->corl = malloc(8 * sizeof(int));
896 if (f.cofb)
897 arr->cofb = malloc(8 * sizeof(int));
898 if (f.cpos)
899 arr->cpos = malloc(6 * sizeof(int));
900
901 cube_to_arrays(cube, arr, f);
902
903 return arr;
904}
905
906static int
907perm_sign(int *a, int n)
908{
909 int i, j, ret = 0;
910
911 if (!is_perm(a,n))
912 return -1;
913
914 for (i = 0; i < n; i++)
915 for (j = i+1; j < n; j++)
916 ret += (a[i] > a[j]) ? 1 : 0;
917
918 return ret % 2;
919}
920
921static int
922perm_to_index(int *a, int n)
923{
924 int i, j, c, ret = 0;
925
926 if (!is_perm(a, n))
927 return -1;
928
929 for (i = 0; i < n; i++) {
930 c = 0;
931 for (j = i+1; j < n; j++)
932 c += (a[i] > a[j]) ? 1 : 0;
933 ret += factorial(n-i-1) * c;
934 }
935
936 return ret;
937}
938
939static int
940powint(int a, int b)
941{
942 if (b < 0)
943 return 0; /* Truncate */
944 if (b == 0)
945 return 1;
946
947 if (b % 2)
948 return a * powint(a, b-1);
949 else
950 return powint(a*a, b/2);
951}
952
953static void
954ptable_set_reached(PruneData *pd, uint64_t ind)
955{
956 uint8_t oldval2 = pd->reached[ind/2];
957 int other = ind % 2 ? oldval2 % 16 : oldval2 / 16;
958
959 pd->reached[ind/2] = ind % 2 ? 16 + other : 16*other + 1;
960}
961
962static void
963ptable_update(PruneData *pd, uint64_t ind, int n)
964{
965 uint8_t oldval2 = pd->ptable[ind/2];
966 int other = ind % 2 ? oldval2 % 16 : oldval2 / 16;
967
968 pd->ptable[ind/2] = ind % 2 ? 16*n + other : 16*other + n;
969 pd->n++;
970}
971
972static bool
973read_mtables_file()
974{
975 FILE *f;
976 char fname[strlen(tabledir)+20];
977 int m, b = sizeof(uint16_t);
978 bool r = true;
979
980 strcpy(fname, tabledir);
981 strcat(fname, "/mtables");
982
983 if ((f = fopen(fname, "rb")) == NULL)
984 return false;
985
986 for (m = 0; m < NMOVES; m++) {
987 r = r && fread(epose_mtable[m], b, me[0], f) == me[0];
988 r = r && fread(eposs_mtable[m], b, me[1], f) == me[1];
989 r = r && fread(eposm_mtable[m], b, me[2], f) == me[2];
990 r = r && fread(eofb_mtable[m], b, me[3], f) == me[3];
991 r = r && fread(eorl_mtable[m], b, me[4], f) == me[4];
992 r = r && fread(eoud_mtable[m], b, me[5], f) == me[5];
993 r = r && fread(cp_mtable[m], b, me[6], f) == me[6];
994 r = r && fread(coud_mtable[m], b, me[7], f) == me[7];
995 r = r && fread(corl_mtable[m], b, me[8], f) == me[8];
996 r = r && fread(cofb_mtable[m], b, me[9], f) == me[9];
997 r = r && fread(cpos_mtable[m], b, me[10], f) == me[10];
998 }
999
1000 fclose(f);
1001 return r;
1002}
1003
1004static bool
1005read_ptable_file(PruneData *pd)
1006{
1007 FILE *f;
1008 char fname[strlen(tabledir)+100];
1009 uint64_t r;
1010
1011 strcpy(fname, tabledir);
1012 strcat(fname, "/");
1013 strcat(fname, pd->filename);
1014
1015 if ((f = fopen(fname, "rb")) == NULL)
1016 return false;
1017
1018 r = fread(pd->ptable, sizeof(uint8_t), PTABLESIZE(pd->size), f);
1019 fclose(f);
1020
1021 return r == PTABLESIZE(pd->size);
1022}
1023
1024static bool
1025read_ttables_file()
1026{
1027 FILE *f;
1028 char fname[strlen(tabledir)+20];
1029 int b = sizeof(uint16_t);
1030 bool r = true;
1031 Move m;
1032
1033 strcpy(fname, tabledir);
1034 strcat(fname, "/");
1035 strcat(fname, "ttables");
1036
1037 if ((f = fopen(fname, "rb")) == NULL)
1038 return false;
1039
1040 for (m = 0; m < NTRANS; m++) {
1041 r = r && fread(epose_ttable[m], b, me[0], f) == me[0];
1042 r = r && fread(eposs_ttable[m], b, me[1], f) == me[1];
1043 r = r && fread(eposm_ttable[m], b, me[2], f) == me[2];
1044 r = r && fread(eo_ttable[m], b, me[3], f) == me[3];
1045 r = r && fread(cp_ttable[m], b, me[6], f) == me[6];
1046 r = r && fread(co_ttable[m], b, me[7], f) == me[7];
1047 r = r && fread(cpos_ttable[m], b, me[10], f) == me[10];
1048 r = r && fread(moves_ttable[m], b, me[11], f) == me[11];
1049 }
1050
1051 fclose(f);
1052 return r;
1053}
1054
1055static Cube
1056rotate_via_compose(Trans r, Cube c, PieceFilter f)
1057{
1058 Alg *inv;
1059 static int zero12[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1060 static int zero8[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
1061 static CubeArray ma = {
1062 .ep = ep_mirror,
1063 .eofb = zero12,
1064 .eorl = zero12,
1065 .eoud = zero12,
1066 .cp = cp_mirror,
1067 .coud = zero8,
1068 .corl = zero8,
1069 .cofb = zero8,
1070 .cpos = cpos_mirror
1071 };
1072
1073 Cube ret;
1074
1075 if (r != mirror) {
1076 ret = apply_alg_generic(trans_algs[r], c, f, true);
1077 inv = on_inverse(trans_algs[r]);
1078 ret = apply_alg_generic(inv, ret, f, true);
1079 free_alg(inv);
1080 } else {
1081 ret = move_via_arrays(&ma, (Cube){0}, f);
1082 ret = compose_filtered(c, ret, f);
1083 ret = move_via_arrays(&ma, ret, f);
1084 }
1085
1086 return ret;
1087}
1088
1089static void
1090solve_dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd)
1091{
1092 Move move, l1 = dd->last1, l2 = dd->last2;
1093 int i, lower_bound = s.check(c);
1094 bool found_many, prune, niss_make_sense, nissbackup = dd->niss;
1095
1096 if (opts->can_niss && !dd->niss)
1097 lower_bound = MIN(1, lower_bound);
1098
1099 found_many = dd->sols->len >= opts->max_solutions;
1100 prune = dd->current_alg->len + lower_bound > dd->d;
1101 if (found_many || prune)
1102 return;
1103
1104 if (lower_bound == 0) {
1105 if (dd->current_alg->len == dd->d)
1106 append_alg(dd->sols, dd->current_alg);
1107 return;
1108 }
1109
1110 dd->last2 = dd->last1;
1111
1112 for (i = 0; dd->sorted_moves[i] != NULLMOVE; i++) {
1113 move = dd->sorted_moves[i];
1114 if (possible_next[l2][l1][move]) {
1115 dd->last1 = move;
1116 append_move(dd->current_alg, move, dd->niss);
1117 solve_dfs(apply_move(move, c), s, opts, dd);
1118 dd->current_alg->len--;
1119 }
1120 }
1121
1122 niss_make_sense = !dd->current_alg->len ||
1123 (s.check(apply_move(l1,(Cube){0})));
1124 if (opts->can_niss && !dd->niss && niss_make_sense) {
1125 dd->niss = true;
1126 dd->last1 = NULLMOVE;
1127 dd->last2 = NULLMOVE;
1128 solve_dfs(inverse_cube(c), s, opts, dd);
1129 }
1130
1131 dd->last1 = l1;
1132 dd->last2 = l2;
1133 dd->niss = nissbackup;
1134}
1135
1136static int
1137subset_to_index(int *a, int n, int k)
1138{
1139 int i, ret = 0;
1140
1141 if (!is_subset(a, n, k))
1142 return binomial(n, k);
1143
1144 for (i = 0; i < n; i++) {
1145 if (k == n-i)
1146 return ret;
1147 if (a[i]) {
1148 ret += binomial(n-i-1, k);
1149 k--;
1150 }
1151 }
1152
1153 return ret;
1154}
1155
1156static void
1157sum_arrays_mod(int *src, int *dst, int n, int m)
1158{
1159 int i;
1160
1161 for (i = 0; i < n; i++)
1162 dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m;
1163}
1164
1165static void
1166swap(int *a, int *b)
1167{
1168 int aux;
1169
1170 aux = *a;
1171 *a = *b;
1172 *b = aux;
1173}
1174
1175static bool
1176write_mtables_file()
1177{
1178 FILE *f;
1179 char fname[strlen(tabledir)+20];
1180 int m, b = sizeof(uint16_t);
1181 bool r = true;
1182
1183 strcpy(fname, tabledir);
1184 strcat(fname, "/mtables");
1185
1186 if ((f = fopen(fname, "wb")) == NULL)
1187 return false;
1188
1189 for (m = 0; m < NMOVES; m++) {
1190 r = r && fwrite(epose_mtable[m], b, me[0], f) == me[0];
1191 r = r && fwrite(eposs_mtable[m], b, me[1], f) == me[1];
1192 r = r && fwrite(eposm_mtable[m], b, me[2], f) == me[2];
1193 r = r && fwrite(eofb_mtable[m], b, me[3], f) == me[3];
1194 r = r && fwrite(eorl_mtable[m], b, me[4], f) == me[4];
1195 r = r && fwrite(eoud_mtable[m], b, me[5], f) == me[5];
1196 r = r && fwrite(cp_mtable[m], b, me[6], f) == me[6];
1197 r = r && fwrite(coud_mtable[m], b, me[7], f) == me[7];
1198 r = r && fwrite(corl_mtable[m], b, me[8], f) == me[8];
1199 r = r && fwrite(cofb_mtable[m], b, me[9], f) == me[9];
1200 r = r && fwrite(cpos_mtable[m], b, me[10], f) == me[10];
1201 }
1202
1203 fclose(f);
1204 return r;
1205}
1206
1207static bool
1208write_ptable_file(PruneData *pd)
1209{
1210 FILE *f;
1211 char fname[strlen(tabledir)+100];
1212 uint64_t written;
1213
1214 strcpy(fname, tabledir);
1215 strcat(fname, "/");
1216 strcat(fname, pd->filename);
1217
1218 if ((f = fopen(fname, "wb")) == NULL)
1219 return false;
1220
1221 written = fwrite(pd->ptable, sizeof(uint8_t), PTABLESIZE(pd->size), f);
1222 fclose(f);
1223
1224 return written == PTABLESIZE(pd->size);
1225}
1226
1227static bool
1228write_ttables_file()
1229{
1230 FILE *f;
1231 char fname[strlen(tabledir)+20];
1232 bool r = true;
1233 int b = sizeof(uint16_t);
1234 Move m;
1235
1236 strcpy(fname, tabledir);
1237 strcat(fname, "/ttables");
1238
1239 if ((f = fopen(fname, "wb")) == NULL)
1240 return false;
1241
1242 for (m = 0; m < NTRANS; m++) {
1243 r = r && fwrite(epose_ttable[m], b, me[0], f) == me[0];
1244 r = r && fwrite(eposs_ttable[m], b, me[1], f) == me[1];
1245 r = r && fwrite(eposm_ttable[m], b, me[2], f) == me[2];
1246 r = r && fwrite(eo_ttable[m], b, me[3], f) == me[3];
1247 r = r && fwrite(cp_ttable[m], b, me[6], f) == me[6];
1248 r = r && fwrite(co_ttable[m], b, me[7], f) == me[7];
1249 r = r && fwrite(cpos_ttable[m], b, me[10], f) == me[10];
1250 r = r && fwrite(moves_ttable[m], b, me[11], f) == me[11];
1251 }
1252
1253 fclose(f);
1254 return r;
1255}
1256
1257/* Init functions implementation *********************************************/
1258
1259static void
1260init_auxtables()
1261{
1262 Cube c1, c2;
1263 uint64_t ui, uj;
1264 int i, j, k;
1265 bool cij, p1, p2;
1266
1267 for (ui = 0; ui < BINOM12ON4; ui++)
1268 for (uj = 0; uj < BINOM12ON4; uj++)
1269 epos_dependent_aux[ui][uj] = epos_dependent(ui, uj);
1270
1271 for (i = 0; i < NMOVES; i++) {
1272 for (j = 0; j < NMOVES; j++) {
1273 c1 = apply_move(i, apply_move(j, (Cube){0}));
1274 c2 = apply_move(j, apply_move(i, (Cube){0}));
1275 commute[i][j] = equal(c1, c2);
1276 }
1277 }
1278
1279 for (i = 0; i < NMOVES; i++) {
1280 for (j = 0; j < NMOVES; j++) {
1281 for (k = 0; k < NMOVES; k++) {
1282 p1 = j && base_move(j) == base_move(k);
1283 p2 = i && base_move(i) == base_move(k);
1284 cij = commute[i][j];
1285 possible_next[i][j][k] = !(p1 || (cij && p2));
1286 }
1287 }
1288 }
1289
1290 for (i = 0; i < NMOVES; i++)
1291 inverse_move_aux[i] = i ? i + 2 - 2*((i-1)%3) : NULLMOVE;
1292
1293 /* Is there a more elegant way? */
1294 inverse_trans_aux[uf] = uf;
1295 inverse_trans_aux[ur] = ul;
1296 inverse_trans_aux[ul] = ur;
1297 inverse_trans_aux[ub] = ub;
1298
1299 inverse_trans_aux[df] = df;
1300 inverse_trans_aux[dr] = dr;
1301 inverse_trans_aux[dl] = dl;
1302 inverse_trans_aux[db] = db;
1303
1304 inverse_trans_aux[rf] = lf;
1305 inverse_trans_aux[rd] = bl;
1306 inverse_trans_aux[rb] = rb;
1307 inverse_trans_aux[ru] = fr;
1308
1309 inverse_trans_aux[lf] = rf;
1310 inverse_trans_aux[ld] = br;
1311 inverse_trans_aux[lb] = lb;
1312 inverse_trans_aux[lu] = fl;
1313
1314 inverse_trans_aux[fu] = fu;
1315 inverse_trans_aux[fr] = ru;
1316 inverse_trans_aux[fd] = bu;
1317 inverse_trans_aux[fl] = lu;
1318
1319 inverse_trans_aux[bu] = fd;
1320 inverse_trans_aux[br] = ld;
1321 inverse_trans_aux[bd] = bd;
1322 inverse_trans_aux[bl] = rd;
1323
1324 inverse_trans_aux[mirror] = mirror;
1325}
1326
1327static void
1328init_environment()
1329{
1330 char *nissydata = getenv("NISSYDATA");
1331 char *localdata = getenv("XDG_DATA_HOME");
1332 char *home = getenv("HOME");
1333 bool read, write;
1334
1335 if (nissydata != NULL) {
1336 tabledir = malloc(strlen(nissydata) * sizeof(char) + 20);
1337 strcpy(tabledir, nissydata);
1338 } else if (localdata != NULL) {
1339 tabledir = malloc(strlen(localdata) * sizeof(char) + 20);
1340 strcpy(tabledir, localdata);
1341 strcat(tabledir, "/nissy");
1342 } else if (home != NULL) {
1343 tabledir = malloc(strlen(home) * sizeof(char) + 20);
1344 strcpy(tabledir, home);
1345 strcat(tabledir, "/.nissy");
1346 }
1347
1348 mkdir(tabledir, 0777);
1349 strcat(tabledir, "/tables");
1350 mkdir(tabledir, 0777);
1351
1352 read = !access(tabledir, R_OK);
1353 write = !access(tabledir, W_OK);
1354
1355 if (!read) {
1356 fprintf(stderr, "Table files cannot be read.\n");
1357 } else if (!write) {
1358 fprintf(stderr, "Data directory not writable: ");
1359 fprintf(stderr, "tables can be loaded, but not saved.\n");
1360 }
1361}
1362
1363static void
1364init_moves() {
1365 Cube c;
1366 CubeArray arrs;
1367 int i;
1368 uint16_t ui;
1369 Move m;
1370
1371 /* Generate all move cycles and flips; I do this regardless */
1372 for (i = 0; i < NMOVES; i++) {
1373 if (i == U || i == x || i == y)
1374 continue;
1375
1376 c = apply_alg_generic(equiv_alg[i], (Cube){0}, pf_all, false);
1377
1378 arrs = (CubeArray){
1379 edge_cycle[i],
1380 eofb_flipped[i],
1381 eorl_flipped[i],
1382 eoud_flipped[i],
1383 corner_cycle[i],
1384 coud_flipped[i],
1385 corl_flipped[i],
1386 cofb_flipped[i],
1387 center_cycle[i]
1388 };
1389 cube_to_arrays(c, &arrs, pf_all);
1390 }
1391
1392 if (read_mtables_file())
1393 return;
1394
1395 fprintf(stderr, "Cannot load %s, generating it\n", "mtables");
1396
1397 /* Initialize transition tables */
1398 for (m = 0; m < NMOVES; m++) {
1399 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
1400 c = (Cube){ .epose = ui };
1401 c = apply_move_cubearray(m, c, pf_e);
1402 epose_mtable[m][ui] = c.epose;
1403
1404 c = (Cube){ .eposs = ui };
1405 c = apply_move_cubearray(m, c, pf_s);
1406 eposs_mtable[m][ui] = c.eposs;
1407
1408 c = (Cube){ .eposm = ui };
1409 c = apply_move_cubearray(m, c, pf_m);
1410 eposm_mtable[m][ui] = c.eposm;
1411 }
1412 for (ui = 0; ui < POW2TO11; ui++ ) {
1413 c = (Cube){ .eofb = ui };
1414 c = apply_move_cubearray(m, c, pf_eo);
1415 eofb_mtable[m][ui] = c.eofb;
1416
1417 c = (Cube){ .eorl = ui };
1418 c = apply_move_cubearray(m, c, pf_eo);
1419 eorl_mtable[m][ui] = c.eorl;
1420
1421 c = (Cube){ .eoud = ui };
1422 c = apply_move_cubearray(m, c, pf_eo);
1423 eoud_mtable[m][ui] = c.eoud;
1424 }
1425 for (ui = 0; ui < POW3TO7; ui++) {
1426 c = (Cube){ .coud = ui };
1427 c = apply_move_cubearray(m, c, pf_co);
1428 coud_mtable[m][ui] = c.coud;
1429
1430 c = (Cube){ .corl = ui };
1431 c = apply_move_cubearray(m, c, pf_co);
1432 corl_mtable[m][ui] = c.corl;
1433
1434 c = (Cube){ .cofb = ui };
1435 c = apply_move_cubearray(m, c, pf_co);
1436 cofb_mtable[m][ui] = c.cofb;
1437 }
1438 for (ui = 0; ui < FACTORIAL8; ui++) {
1439 c = (Cube){ .cp = ui };
1440 c = apply_move_cubearray(m, c, pf_cp);
1441 cp_mtable[m][ui] = c.cp;
1442 }
1443 for (ui = 0; ui < FACTORIAL6; ui++) {
1444 c = (Cube){ .cpos = ui };
1445 c = apply_move_cubearray(m, c, pf_cpos);
1446 cpos_mtable[m][ui] = c.cpos;
1447 }
1448 }
1449
1450 if (!write_mtables_file())
1451 fprintf(stderr, "Error writing mtables\n");
1452}
1453
1454static void
1455init_moves_aux()
1456{
1457 /* Some standard PieceFilters */
1458 pf_all.epose = true;
1459 pf_all.eposs = true;
1460 pf_all.eposm = true;
1461 pf_all.eofb = true;
1462 pf_all.eorl = true;
1463 pf_all.eoud = true;
1464 pf_all.cp = true;
1465 pf_all.cofb = true;
1466 pf_all.corl = true;
1467 pf_all.coud = true;
1468 pf_all.cpos = true;
1469
1470 pf_4val.epose = true;
1471 pf_4val.eposs = true;
1472 pf_4val.eposm = true;
1473 pf_4val.eofb = true;
1474 pf_4val.coud = true;
1475 pf_4val.cp = true;
1476
1477 pf_epcp.epose = true;
1478 pf_epcp.eposs = true;
1479 pf_epcp.eposm = true;
1480 pf_epcp.cp = true;
1481
1482 pf_cpos.cpos = true;
1483
1484 pf_cp.cp = true;
1485
1486 pf_ep.epose = true;
1487 pf_ep.eposs = true;
1488 pf_ep.eposm = true;
1489
1490 pf_e.epose = true;
1491 pf_s.eposs = true;
1492 pf_m.eposm = true;
1493
1494 pf_eo.eofb = true;
1495 pf_eo.eorl = true;
1496 pf_eo.eoud = true;
1497
1498 pf_co.cofb = true;
1499 pf_co.corl = true;
1500 pf_co.coud = true;
1501
1502 /* Used to convert to and from CubeArray */
1503 epe_solved[0] = FR;
1504 epe_solved[1] = FL;
1505 epe_solved[2] = BL;
1506 epe_solved[3] = BR;
1507
1508 eps_solved[0] = UL;
1509 eps_solved[1] = UR;
1510 eps_solved[2] = DL;
1511 eps_solved[3] = DR;
1512
1513 epm_solved[0] = UF;
1514 epm_solved[1] = UB;
1515 epm_solved[2] = DF;
1516 epm_solved[3] = DB;
1517
1518 /* Table sizes, used for reading and writing files */
1519 me[0] = FACTORIAL12/FACTORIAL8;
1520 me[1] = FACTORIAL12/FACTORIAL8;
1521 me[2] = FACTORIAL12/FACTORIAL8;
1522 me[3] = POW2TO11;
1523 me[4] = POW2TO11;
1524 me[5] = POW2TO11;
1525 me[6] = FACTORIAL8;
1526 me[7] = POW3TO7;
1527 me[8] = POW3TO7;
1528 me[9] = POW3TO7;
1529 me[10] = FACTORIAL6;
1530 me[11] = NMOVES;
1531
1532 /* Cycles *********************/
1533 edge_cycle[U][UF] = UR;
1534 edge_cycle[U][UL] = UF;
1535 edge_cycle[U][UB] = UL;
1536 edge_cycle[U][UR] = UB;
1537 edge_cycle[U][DF] = DF;
1538 edge_cycle[U][DL] = DL;
1539 edge_cycle[U][DB] = DB;
1540 edge_cycle[U][DR] = DR;
1541 edge_cycle[U][FR] = FR;
1542 edge_cycle[U][FL] = FL;
1543 edge_cycle[U][BL] = BL;
1544 edge_cycle[U][BR] = BR;
1545
1546 edge_cycle[x][UF] = DF;
1547 edge_cycle[x][UL] = FL;
1548 edge_cycle[x][UB] = UF;
1549 edge_cycle[x][UR] = FR;
1550 edge_cycle[x][DF] = DB;
1551 edge_cycle[x][DL] = BL;
1552 edge_cycle[x][DB] = UB;
1553 edge_cycle[x][DR] = BR;
1554 edge_cycle[x][FR] = DR;
1555 edge_cycle[x][FL] = DL;
1556 edge_cycle[x][BL] = UL;
1557 edge_cycle[x][BR] = UR;
1558
1559 edge_cycle[y][UF] = UR;
1560 edge_cycle[y][UL] = UF;
1561 edge_cycle[y][UB] = UL;
1562 edge_cycle[y][UR] = UB;
1563 edge_cycle[y][DF] = DR;
1564 edge_cycle[y][DL] = DF;
1565 edge_cycle[y][DB] = DL;
1566 edge_cycle[y][DR] = DB;
1567 edge_cycle[y][FR] = BR;
1568 edge_cycle[y][FL] = FR;
1569 edge_cycle[y][BL] = FL;
1570 edge_cycle[y][BR] = BL;
1571
1572 corner_cycle[U][UFR] = UBR;
1573 corner_cycle[U][UFL] = UFR;
1574 corner_cycle[U][UBL] = UFL;
1575 corner_cycle[U][UBR] = UBL;
1576 corner_cycle[U][DFR] = DFR;
1577 corner_cycle[U][DFL] = DFL;
1578 corner_cycle[U][DBL] = DBL;
1579 corner_cycle[U][DBR] = DBR;
1580
1581 corner_cycle[x][UFR] = DFR;
1582 corner_cycle[x][UFL] = DFL;
1583 corner_cycle[x][UBL] = UFL;
1584 corner_cycle[x][UBR] = UFR;
1585 corner_cycle[x][DFR] = DBR;
1586 corner_cycle[x][DFL] = DBL;
1587 corner_cycle[x][DBL] = UBL;
1588 corner_cycle[x][DBR] = UBR;
1589
1590 corner_cycle[y][UFR] = UBR;
1591 corner_cycle[y][UFL] = UFR;
1592 corner_cycle[y][UBL] = UFL;
1593 corner_cycle[y][UBR] = UBL;
1594 corner_cycle[y][DFR] = DBR;
1595 corner_cycle[y][DFL] = DFR;
1596 corner_cycle[y][DBL] = DFL;
1597 corner_cycle[y][DBR] = DBL;
1598
1599 center_cycle[U][U_center] = U_center;
1600 center_cycle[U][D_center] = D_center;
1601 center_cycle[U][R_center] = R_center;
1602 center_cycle[U][L_center] = L_center;
1603 center_cycle[U][F_center] = F_center;
1604 center_cycle[U][B_center] = B_center;
1605
1606 center_cycle[x][U_center] = F_center;
1607 center_cycle[x][D_center] = B_center;
1608 center_cycle[x][R_center] = R_center;
1609 center_cycle[x][L_center] = L_center;
1610 center_cycle[x][F_center] = D_center;
1611 center_cycle[x][B_center] = U_center;
1612
1613 center_cycle[y][U_center] = U_center;
1614 center_cycle[y][D_center] = D_center;
1615 center_cycle[y][R_center] = B_center;
1616 center_cycle[y][L_center] = F_center;
1617 center_cycle[y][F_center] = R_center;
1618 center_cycle[y][B_center] = L_center;
1619
1620 /* Flipped pieces *************/
1621 eofb_flipped[x][UF] = 1;
1622 eofb_flipped[x][UB] = 1;
1623 eofb_flipped[x][DF] = 1;
1624 eofb_flipped[x][DB] = 1;
1625
1626 eofb_flipped[y][FR] = 1;
1627 eofb_flipped[y][FL] = 1;
1628 eofb_flipped[y][BL] = 1;
1629 eofb_flipped[y][BR] = 1;
1630
1631 eorl_flipped[x][UF] = 1;
1632 eorl_flipped[x][UL] = 1;
1633 eorl_flipped[x][UB] = 1;
1634 eorl_flipped[x][UR] = 1;
1635 eorl_flipped[x][DF] = 1;
1636 eorl_flipped[x][DL] = 1;
1637 eorl_flipped[x][DB] = 1;
1638 eorl_flipped[x][DR] = 1;
1639 eorl_flipped[x][FR] = 1;
1640 eorl_flipped[x][FL] = 1;
1641 eorl_flipped[x][BL] = 1;
1642 eorl_flipped[x][BR] = 1;
1643
1644 eorl_flipped[y][FR] = 1;
1645 eorl_flipped[y][FL] = 1;
1646 eorl_flipped[y][BL] = 1;
1647 eorl_flipped[y][BR] = 1;
1648
1649 eoud_flipped[U][UF] = 1;
1650 eoud_flipped[U][UL] = 1;
1651 eoud_flipped[U][UB] = 1;
1652 eoud_flipped[U][UR] = 1;
1653
1654 eoud_flipped[x][UF] = 1;
1655 eoud_flipped[x][UB] = 1;
1656 eoud_flipped[x][DF] = 1;
1657 eoud_flipped[x][DB] = 1;
1658
1659 eoud_flipped[y][UF] = 1;
1660 eoud_flipped[y][UL] = 1;
1661 eoud_flipped[y][UB] = 1;
1662 eoud_flipped[y][UR] = 1;
1663 eoud_flipped[y][DF] = 1;
1664 eoud_flipped[y][DL] = 1;
1665 eoud_flipped[y][DB] = 1;
1666 eoud_flipped[y][DR] = 1;
1667 eoud_flipped[y][FR] = 1;
1668 eoud_flipped[y][FL] = 1;
1669 eoud_flipped[y][BL] = 1;
1670 eoud_flipped[y][BR] = 1;
1671
1672 coud_flipped[x][UFR] = 2;
1673 coud_flipped[x][UFL] = 1;
1674 coud_flipped[x][UBR] = 1;
1675 coud_flipped[x][UBL] = 2;
1676 coud_flipped[x][DFR] = 1;
1677 coud_flipped[x][DFL] = 2;
1678 coud_flipped[x][DBR] = 2;
1679 coud_flipped[x][DBL] = 1;
1680
1681 corl_flipped[U][UFR] = 1;
1682 corl_flipped[U][UFL] = 2;
1683 corl_flipped[U][UBL] = 1;
1684 corl_flipped[U][UBR] = 2;
1685
1686 corl_flipped[y][UFR] = 1;
1687 corl_flipped[y][UFL] = 2;
1688 corl_flipped[y][UBL] = 1;
1689 corl_flipped[y][UBR] = 2;
1690 corl_flipped[y][DFR] = 2;
1691 corl_flipped[y][DFL] = 1;
1692 corl_flipped[y][DBL] = 2;
1693 corl_flipped[y][DBR] = 1;
1694
1695 cofb_flipped[U][UFR] = 2;
1696 cofb_flipped[U][UFL] = 1;
1697 cofb_flipped[U][UBL] = 2;
1698 cofb_flipped[U][UBR] = 1;
1699
1700 cofb_flipped[x][UFR] = 1;
1701 cofb_flipped[x][UFL] = 2;
1702 cofb_flipped[x][UBL] = 1;
1703 cofb_flipped[x][UBR] = 2;
1704 cofb_flipped[x][DFR] = 2;
1705 cofb_flipped[x][DFL] = 1;
1706 cofb_flipped[x][DBL] = 2;
1707 cofb_flipped[x][DBR] = 1;
1708
1709 cofb_flipped[y][UFR] = 2;
1710 cofb_flipped[y][UFL] = 1;
1711 cofb_flipped[y][UBL] = 2;
1712 cofb_flipped[y][UBR] = 1;
1713 cofb_flipped[y][DFR] = 1;
1714 cofb_flipped[y][DFL] = 2;
1715 cofb_flipped[y][DBL] = 1;
1716 cofb_flipped[y][DBR] = 2;
1717
1718 /* Equivalent moves ***********/
1719 equiv_alg[NULLMOVE] = new_alg("");
1720
1721 equiv_alg[U] = new_alg(" U ");
1722 equiv_alg[U2] = new_alg(" UU ");
1723 equiv_alg[U3] = new_alg(" UUU ");
1724 equiv_alg[D] = new_alg(" xx U xx ");
1725 equiv_alg[D2] = new_alg(" xx UU xx ");
1726 equiv_alg[D3] = new_alg(" xx UUU xx ");
1727 equiv_alg[R] = new_alg(" yx U xxxyyy ");
1728 equiv_alg[R2] = new_alg(" yx UU xxxyyy ");
1729 equiv_alg[R3] = new_alg(" yx UUU xxxyyy ");
1730 equiv_alg[L] = new_alg(" yyyx U xxxy ");
1731 equiv_alg[L2] = new_alg(" yyyx UU xxxy ");
1732 equiv_alg[L3] = new_alg(" yyyx UUU xxxy ");
1733 equiv_alg[F] = new_alg(" x U xxx ");
1734 equiv_alg[F2] = new_alg(" x UU xxx ");
1735 equiv_alg[F3] = new_alg(" x UUU xxx ");
1736 equiv_alg[B] = new_alg(" xxx U x ");
1737 equiv_alg[B2] = new_alg(" xxx UU x ");
1738 equiv_alg[B3] = new_alg(" xxx UUU x ");
1739
1740 equiv_alg[Uw] = new_alg(" xx U xx y ");
1741 equiv_alg[Uw2] = new_alg(" xx UU xx yy ");
1742 equiv_alg[Uw3] = new_alg(" xx UUU xx yyy ");
1743 equiv_alg[Dw] = new_alg(" U yyy ");
1744 equiv_alg[Dw2] = new_alg(" UU yy ");
1745 equiv_alg[Dw3] = new_alg(" UUU y ");
1746 equiv_alg[Rw] = new_alg(" yyyx U xxxy x ");
1747 equiv_alg[Rw2] = new_alg(" yyyx UU xxxy xx ");
1748 equiv_alg[Rw3] = new_alg(" yyyx UUU xxxy xxx ");
1749 equiv_alg[Lw] = new_alg(" yx U xxxyyy xxx ");
1750 equiv_alg[Lw2] = new_alg(" yx UU xxxyyy xx ");
1751 equiv_alg[Lw3] = new_alg(" yx UUU xxxyyy x ");
1752 equiv_alg[Fw] = new_alg(" xxx U x yxxxyyy ");
1753 equiv_alg[Fw2] = new_alg(" xxx UU x yxxyyy ");
1754 equiv_alg[Fw3] = new_alg(" xxx UUU x yxyyy ");
1755 equiv_alg[Bw] = new_alg(" x U xxx yxyyy ");
1756 equiv_alg[Bw2] = new_alg(" x UU xxx yxxyyy ");
1757 equiv_alg[Bw3] = new_alg(" x UUU xxx yxxxyyy ");
1758
1759 equiv_alg[M] = new_alg(" yx U xx UUU yxyyy ");
1760 equiv_alg[M2] = new_alg(" yx UU xx UU xxxy ");
1761 equiv_alg[M3] = new_alg(" yx UUU xx U yxxxy ");
1762 equiv_alg[S] = new_alg(" x UUU xx U yyyx ");
1763 equiv_alg[S2] = new_alg(" x UU xx UU yyx ");
1764 equiv_alg[S3] = new_alg(" x U xx UUU yx ");
1765 equiv_alg[E] = new_alg(" U xx UUU xxyyy ");
1766 equiv_alg[E2] = new_alg(" UU xx UU xxyy ");
1767 equiv_alg[E3] = new_alg(" UUU xx U xxy ");
1768
1769 equiv_alg[x] = new_alg(" x ");
1770 equiv_alg[x2] = new_alg(" xx ");
1771 equiv_alg[x3] = new_alg(" xxx ");
1772 equiv_alg[y] = new_alg(" y ");
1773 equiv_alg[y2] = new_alg(" yy ");
1774 equiv_alg[y3] = new_alg(" yyy ");
1775 equiv_alg[z] = new_alg(" yyy x y ");
1776 equiv_alg[z2] = new_alg(" yy xx ");
1777 equiv_alg[z3] = new_alg(" y x yyy ");
1778}
1779
1780static void
1781init_steps()
1782{
1783 /* PruneData */
1784 pd_eofb_HTM.filename = "ptable_eofb_HTM";
1785 pd_eofb_HTM.size = POW2TO11;
1786 pd_eofb_HTM.index = index_eofb;
1787 pd_eofb_HTM.moveset = moveset_HTM;
1788
1789 pd_coud_HTM.filename = "ptable_coud_HTM";
1790 pd_coud_HTM.size = POW3TO7;
1791 pd_coud_HTM.index = index_coud;
1792 pd_coud_HTM.moveset = moveset_HTM;
1793
1794 pd_corners_HTM.filename = "ptable_corners_HTM";
1795 pd_corners_HTM.size = POW3TO7 * FACTORIAL8;
1796 pd_corners_HTM.index = index_corners;
1797 pd_corners_HTM.moveset = moveset_HTM;
1798
1799 pd_ep_HTM.filename = "ptable_ep_HTM";
1800 pd_ep_HTM.size = FACTORIAL12;
1801 pd_ep_HTM.index = index_ep;
1802 pd_ep_HTM.moveset = moveset_HTM;
1803
1804 pd_drud_HTM.filename = "ptable_drud_HTM";
1805 pd_drud_HTM.size = POW2TO11 * POW3TO7 * BINOM12ON4;
1806 pd_drud_HTM.index = index_drud;
1807 pd_drud_HTM.moveset = moveset_HTM;
1808
1809
1810 /* Actual steps */
1811 eofb_HTM.check = check_eofb_HTM;
1812 eofb_HTM.ready = check_nothing;
1813 eofb_HTM.pre_trans = uf;
1814 eofb_HTM.moveset = moveset_HTM;
1815
1816 eorl_HTM.check = check_eofb_HTM;
1817 eorl_HTM.ready = check_nothing;
1818 eorl_HTM.pre_trans = ur;
1819 eorl_HTM.moveset = moveset_HTM;
1820
1821 eoud_HTM.check = check_eofb_HTM;
1822 eoud_HTM.ready = check_nothing;
1823 eoud_HTM.pre_trans = bu;
1824 eoud_HTM.moveset = moveset_HTM;
1825
1826
1827 coud_HTM.check = check_coud_HTM;
1828 coud_HTM.ready = check_nothing;
1829 coud_HTM.pre_trans = uf;
1830 coud_HTM.moveset = moveset_HTM;
1831
1832 corl_HTM.check = check_coud_HTM;
1833 corl_HTM.ready = check_nothing;
1834 corl_HTM.pre_trans = rf;
1835 corl_HTM.moveset = moveset_HTM;
1836
1837 cofb_HTM.check = check_coud_HTM;
1838 cofb_HTM.ready = check_nothing;
1839 cofb_HTM.pre_trans = fd;
1840 cofb_HTM.moveset = moveset_HTM;
1841
1842 coud_URF.check = check_coud_URF;
1843 coud_URF.ready = check_nothing;
1844 coud_URF.pre_trans = uf;
1845 coud_URF.moveset = moveset_URF;
1846
1847 corl_URF.check = check_coud_URF;
1848 corl_URF.ready = check_nothing;
1849 corl_URF.pre_trans = rf;
1850 corl_URF.moveset = moveset_URF;
1851
1852 cofb_URF.check = check_coud_URF;
1853 cofb_URF.ready = check_nothing;
1854 cofb_URF.pre_trans = fd;
1855 cofb_URF.moveset = moveset_URF;
1856
1857 corners_HTM.check = check_corners_HTM;
1858 corners_HTM.ready = check_nothing;
1859 corners_HTM.pre_trans = uf;
1860 corners_HTM.moveset = moveset_HTM;
1861
1862 corners_URF.check = check_corners_URF;
1863 corners_URF.ready = check_nothing;
1864 corners_URF.pre_trans = uf;
1865 corners_URF.moveset = moveset_URF;
1866
1867 edges_HTM.check = check_edges_HTM;
1868 edges_HTM.ready = check_nothing;
1869 edges_HTM.pre_trans = uf;
1870 edges_HTM.moveset = moveset_HTM;
1871
1872 drud_HTM.check = check_drud_HTM;
1873 drud_HTM.ready = check_nothing;
1874 drud_HTM.pre_trans = uf;
1875 drud_HTM.moveset = moveset_HTM;
1876
1877 optimal_HTM.check = check_optimal_HTM;
1878 optimal_HTM.ready = check_nothing;
1879 optimal_HTM.pre_trans = uf;
1880 optimal_HTM.moveset = moveset_HTM;
1881}
1882
1883static void
1884init_strings()
1885{
1886 strcpy(move_string [NULLMOVE], "-" );
1887 strcpy(move_string [U], "U" );
1888 strcpy(move_string [U2], "U2" );
1889 strcpy(move_string [U3], "U\'" );
1890 strcpy(move_string [D], "D" );
1891 strcpy(move_string [D2], "D2" );
1892 strcpy(move_string [D3], "D\'" );
1893 strcpy(move_string [R], "R" );
1894 strcpy(move_string [R2], "R2" );
1895 strcpy(move_string [R3], "R\'" );
1896 strcpy(move_string [L], "L" );
1897 strcpy(move_string [L2], "L2" );
1898 strcpy(move_string [L3], "L\'" );
1899 strcpy(move_string [F], "F" );
1900 strcpy(move_string [F2], "F2" );
1901 strcpy(move_string [F3], "F\'" );
1902 strcpy(move_string [B], "B" );
1903 strcpy(move_string [B2], "B2" );
1904 strcpy(move_string [B3], "B\'" );
1905 strcpy(move_string [Uw], "Uw" );
1906 strcpy(move_string [Uw2], "Uw2" );
1907 strcpy(move_string [Uw3], "Uw\'" );
1908 strcpy(move_string [Dw], "Dw" );
1909 strcpy(move_string [Dw2], "Dw2" );
1910 strcpy(move_string [Dw3], "Dw\'" );
1911 strcpy(move_string [Rw], "Rw" );
1912 strcpy(move_string [Rw2], "Rw2" );
1913 strcpy(move_string [Rw3], "Rw\'" );
1914 strcpy(move_string [Lw], "Lw" );
1915 strcpy(move_string [Lw2], "Lw2" );
1916 strcpy(move_string [Lw3], "Lw\'" );
1917 strcpy(move_string [Fw], "Fw" );
1918 strcpy(move_string [Fw2], "Fw2" );
1919 strcpy(move_string [Fw3], "Fw\'" );
1920 strcpy(move_string [Bw], "Bw" );
1921 strcpy(move_string [Bw2], "Bw2" );
1922 strcpy(move_string [Bw3], "Bw\'" );
1923 strcpy(move_string [M], "M" );
1924 strcpy(move_string [M2], "M2" );
1925 strcpy(move_string [M3], "M\'" );
1926 strcpy(move_string [S], "S" );
1927 strcpy(move_string [S2], "S2" );
1928 strcpy(move_string [S3], "S\'" );
1929 strcpy(move_string [E], "E" );
1930 strcpy(move_string [E2], "E2" );
1931 strcpy(move_string [E3], "E\'" );
1932 strcpy(move_string [x], "x" );
1933 strcpy(move_string [x2], "x2" );
1934 strcpy(move_string [x3], "x\'" );
1935 strcpy(move_string [y], "y" );
1936 strcpy(move_string [y2], "y2" );
1937 strcpy(move_string [y3], "y\'" );
1938 strcpy(move_string [z], "z" );
1939 strcpy(move_string [z2], "z2" );
1940 strcpy(move_string [z3], "z\'" );
1941
1942 strcpy(edge_string [UF], "UF" );
1943 strcpy(edge_string [UL], "UL" );
1944 strcpy(edge_string [UB], "UB" );
1945 strcpy(edge_string [UR], "UR" );
1946 strcpy(edge_string [DF], "DF" );
1947 strcpy(edge_string [DL], "DL" );
1948 strcpy(edge_string [DB], "DB" );
1949 strcpy(edge_string [DR], "DR" );
1950 strcpy(edge_string [FR], "FR" );
1951 strcpy(edge_string [FL], "FL" );
1952 strcpy(edge_string [BL], "BL" );
1953 strcpy(edge_string [BR], "BR" );
1954
1955 strcpy(corner_string [UFR], "UFR" );
1956 strcpy(corner_string [UFL], "UFL" );
1957 strcpy(corner_string [UBL], "UBL" );
1958 strcpy(corner_string [UBR], "UBR" );
1959 strcpy(corner_string [DFR], "DFR" );
1960 strcpy(corner_string [DFL], "DFL" );
1961 strcpy(corner_string [DBL], "DBL" );
1962 strcpy(corner_string [DBR], "DBR" );
1963
1964 strcpy(center_string [U_center], "U" );
1965 strcpy(center_string [D_center], "D" );
1966 strcpy(center_string [R_center], "R" );
1967 strcpy(center_string [L_center], "L" );
1968 strcpy(center_string [F_center], "F" );
1969 strcpy(center_string [B_center], "B" );
1970}
1971
1972static void
1973init_trans() {
1974 Cube aux, cube, c[3];
1975 CubeArray epcp;
1976 int eparr[12], eoarr[12];
1977 int cparr[8], coarr[8];
1978 int i;
1979 bool b1, b2, b3;
1980 uint16_t ui;
1981 Move mi, move;
1982 Trans m;
1983
1984 /* Compute sources */
1985 for (i = 0; i < NTRANS; i++) {
1986 if (i == mirror)
1987 cube = (Cube){0};
1988 else
1989 cube = apply_alg(trans_algs[i], (Cube){0});
1990
1991 epose_source[i] = edge_slice(edge_at(cube, FR));
1992 eposs_source[i] = edge_slice(edge_at(cube, UR));
1993 eposm_source[i] = edge_slice(edge_at(cube, UF));
1994 eofb_source[i] = center_at(cube, F_center)/2;
1995 eorl_source[i] = center_at(cube, R_center)/2;
1996 eoud_source[i] = center_at(cube, U_center)/2;
1997 coud_source[i] = center_at(cube, U_center)/2;
1998 cofb_source[i] = center_at(cube, F_center)/2;
1999 corl_source[i] = center_at(cube, R_center)/2;
2000 }
2001
2002 if (read_ttables_file())
2003 return;
2004
2005 fprintf(stderr, "Cannot load %s, generating it\n", "ttables");
2006
2007 /* Initialize tables */
2008 for (m = 0; m < NTRANS; m++) {
2009 if (m == mirror) {
2010 memcpy(eparr, ep_mirror, 12 * sizeof(int));
2011 memcpy(cparr, cp_mirror, 8 * sizeof(int));
2012 } else {
2013 epcp = (CubeArray){ .ep = eparr, .cp = cparr };
2014 cube = apply_alg(trans_algs[m], (Cube){0});
2015 cube_to_arrays(cube, &epcp, pf_epcp);
2016 }
2017
2018 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
2019 c[0] = admissible_ep((Cube){ .epose = ui }, pf_e);
2020 c[1] = admissible_ep((Cube){ .eposs = ui }, pf_s);
2021 c[2] = admissible_ep((Cube){ .eposm = ui }, pf_m);
2022
2023 cube = rotate_via_compose(m,c[epose_source[m]],pf_ep);
2024 epose_ttable[m][ui] = cube.epose;
2025
2026 cube = rotate_via_compose(m,c[eposs_source[m]],pf_ep);
2027 eposs_ttable[m][ui] = cube.eposs;
2028
2029 cube = rotate_via_compose(m,c[eposm_source[m]],pf_ep);
2030 eposm_ttable[m][ui] = cube.eposm;
2031 }
2032 for (ui = 0; ui < POW2TO11; ui++ ) {
2033 int_to_sum_zero_array(ui, 2, 12, eoarr);
2034 apply_permutation(eparr, eoarr, 12);
2035 eo_ttable[m][ui] = digit_array_to_int(eoarr, 11, 2);
2036 }
2037 for (ui = 0; ui < POW3TO7; ui++) {
2038 int_to_sum_zero_array(ui, 3, 8, coarr);
2039 apply_permutation(cparr, coarr, 8);
2040 co_ttable[m][ui] = digit_array_to_int(coarr, 7, 3);
2041 if (m == mirror)
2042 co_ttable[m][ui] =
2043 invert_digits(co_ttable[m][ui], 3, 7);
2044 }
2045 for (ui = 0; ui < FACTORIAL8; ui++) {
2046 cube = (Cube){ .cp = ui };
2047 cube = rotate_via_compose(m, cube, pf_cp);
2048 cp_ttable[m][ui] = cube.cp;
2049 }
2050 for (ui = 0; ui < FACTORIAL6; ui++) {
2051 cube = (Cube){ .cpos = ui };
2052 cube = rotate_via_compose(m, cube, pf_cpos);
2053 cpos_ttable[m][ui] = cube.cpos;
2054 }
2055 for (mi = 0; mi < NMOVES; mi++) {
2056 if (m == mirror) {
2057 b1 = (mi >= U && mi <= Bw3);
2058 b2 = (mi >= S && mi <= E3);
2059 b3 = (mi >= x && mi <= z3);
2060 if (b1 || b2 || b3)
2061 moves_ttable[m][mi] =
2062 inverse_move_aux[mi];
2063 else
2064 moves_ttable[m][mi] = mi;
2065
2066 if ((mi-1)/3==(R-1)/3 || (mi-1)/3==(Rw-1)/3)
2067 moves_ttable[m][mi] += 3;
2068 if ((mi-1)/3==(L-1)/3 || (mi-1)/3==(L2-1)/3)
2069 moves_ttable[m][mi] -= 3;
2070 } else {
2071 aux = apply_trans(m, apply_move(mi,(Cube){0}));
2072 for (move = 0; move < NMOVES; move++) {
2073 cube = apply_move(
2074 inverse_move_aux[move], aux);
2075 if (is_solved(cube, false))
2076 moves_ttable[m][mi] = move;
2077 }
2078 }
2079 }
2080 }
2081
2082 if (!write_ttables_file())
2083 fprintf(stderr, "Error writing ttables\n");
2084}
2085
2086static void
2087init_trans_aux()
2088{
2089 ep_mirror[UF] = UF;
2090 ep_mirror[UL] = UR;
2091 ep_mirror[UB] = UB;
2092 ep_mirror[UR] = UL;
2093 ep_mirror[DF] = DF;
2094 ep_mirror[DL] = DR;
2095 ep_mirror[DB] = DB;
2096 ep_mirror[DR] = DL;
2097 ep_mirror[FR] = FL;
2098 ep_mirror[FL] = FR;
2099 ep_mirror[BR] = BL;
2100 ep_mirror[BL] = BR;
2101
2102 cp_mirror[UFR] = UFL;
2103 cp_mirror[UFL] = UFR;
2104 cp_mirror[UBL] = UBR;
2105 cp_mirror[UBR] = UBL;
2106 cp_mirror[DFR] = DFL;
2107 cp_mirror[DFL] = DFR;
2108 cp_mirror[DBL] = DBR;
2109 cp_mirror[DBR] = DBL;
2110
2111 cpos_mirror[U_center] = U_center;
2112 cpos_mirror[D_center] = D_center;
2113 cpos_mirror[R_center] = L_center;
2114 cpos_mirror[L_center] = R_center;
2115 cpos_mirror[F_center] = F_center;
2116 cpos_mirror[B_center] = B_center;
2117
2118 /* Is there a more elegant way? */
2119 trans_algs[uf] = new_alg("");
2120 trans_algs[ur] = new_alg("y");
2121 trans_algs[ub] = new_alg("y2");
2122 trans_algs[ul] = new_alg("y3");
2123
2124 trans_algs[df] = new_alg("z2");
2125 trans_algs[dr] = new_alg("y z2");
2126 trans_algs[db] = new_alg("x2");
2127 trans_algs[dl] = new_alg("y3 z2");
2128
2129 trans_algs[rf] = new_alg("z3");
2130 trans_algs[rd] = new_alg("z3 y");
2131 trans_algs[rb] = new_alg("z3 y2");
2132 trans_algs[ru] = new_alg("z3 y3");
2133
2134 trans_algs[lf] = new_alg("z");
2135 trans_algs[ld] = new_alg("z y3");
2136 trans_algs[lb] = new_alg("z y2");
2137 trans_algs[lu] = new_alg("z y");
2138
2139 trans_algs[fu] = new_alg("x y2");
2140 trans_algs[fr] = new_alg("x y");
2141 trans_algs[fd] = new_alg("x");
2142 trans_algs[fl] = new_alg("x y3");
2143
2144 trans_algs[bu] = new_alg("x3");
2145 trans_algs[br] = new_alg("x3 y");
2146 trans_algs[bd] = new_alg("x3 y2");
2147 trans_algs[bl] = new_alg("x3 y3");
2148}
2149
2150/* Linearization functions implementation ************************************/
2151
2152static uint64_t
2153index_eofb(Cube cube)
2154{
2155 return cube.eofb;
2156}
2157
2158static uint64_t
2159index_coud(Cube cube)
2160{
2161 return cube.coud;
2162}
2163
2164static uint64_t
2165index_corners(Cube cube)
2166{
2167 return cube.coud * FACTORIAL8 + cube.cp;
2168}
2169
2170static uint64_t
2171index_ep(Cube cube)
2172{
2173 uint64_t a, b, c;
2174
2175 /* TODO: remove this check */
2176 if (epos_dependent_aux[cube.eposs/FACTORIAL4][cube.epose/FACTORIAL4] ==BINOM8ON4)
2177 fprintf(stderr, "Impossible\n");
2178
2179 a = cube.eposs;
2180 b = (cube.epose % FACTORIAL4) +
2181 epos_dependent_aux[cube.eposs/FACTORIAL4][cube.epose/FACTORIAL4] *
2182 FACTORIAL4;
2183 c = cube.eposm % FACTORIAL4;
2184
2185 b *= FACTORIAL4 * BINOM12ON4;
2186 c *= FACTORIAL4 * BINOM12ON4 * FACTORIAL4 * BINOM8ON4;
2187
2188 return a + b + c;
2189}
2190
2191static uint64_t
2192index_drud(Cube cube)
2193{
2194 uint64_t a, b, c;
2195
2196 a = cube.eofb;
2197 b = cube.coud;
2198 c = cube.epose / FACTORIAL4;
2199
2200 b *= POW2TO11;
2201 c *= POW2TO11 * POW3TO7;
2202
2203 return a + b + c;
2204}
2205
2206/* Step checking functions implementation ************************************/
2207
2208static int
2209check_nothing(Cube cube)
2210{
2211 return true;
2212}
2213
2214static int
2215check_eofb_HTM(Cube cube)
2216{
2217 if (!pd_eofb_HTM.generated)
2218 generate_ptable(&pd_eofb_HTM);
2219
2220 return PTABLEVAL(pd_eofb_HTM.ptable, cube.eofb);
2221}
2222
2223static int
2224check_coud_HTM(Cube cube)
2225{
2226 if (!pd_coud_HTM.generated)
2227 generate_ptable(&pd_coud_HTM);
2228
2229 return PTABLEVAL(pd_coud_HTM.ptable, cube.coud);
2230}
2231
2232static int
2233check_coud_URF(Cube cube)
2234{
2235 /* TODO: I can improve this by checking first the orientation of
2236 * the corner in DBL and use that as a reference */
2237
2238 int ud = check_coud_HTM(cube);
2239 int rl = check_coud_HTM(apply_move(z, cube));
2240 int fb = check_coud_HTM(apply_move(x, cube));
2241
2242 return MIN(ud, MIN(rl, fb));
2243}
2244
2245static int
2246check_corners_HTM(Cube cube)
2247{
2248 if (!pd_corners_HTM.generated)
2249 generate_ptable(&pd_corners_HTM);
2250
2251 return PTABLEVAL(pd_corners_HTM.ptable, index_corners(cube));
2252}
2253
2254static int
2255check_corners_URF(Cube cube)
2256{
2257 /* TODO: I can improve this by checking first the corner in DBL
2258 * and use that as a reference */
2259
2260 int ret = 15;
2261 Cube c;
2262 Trans i;
2263
2264 for (i = 0; i < NROTATIONS; i++) {
2265 c = apply_alg(trans_algs[i], cube);
2266 ret = MIN(ret, check_corners_HTM(c));
2267 }
2268
2269 return ret;
2270}
2271
2272static int
2273check_edges_HTM(Cube cube)
2274{
2275 int ret = 0;
2276
2277 if (!pd_ep_HTM.generated)
2278 generate_ptable(&pd_ep_HTM);
2279
2280 ret = MAX(ret, PTABLEVAL(pd_ep_HTM.ptable, index_ep(cube)));
2281 ret = MAX(ret, check_eofb_HTM(cube));
2282 ret = MAX(ret, check_eofb_HTM(apply_trans(ur, cube)));
2283 ret = MAX(ret, check_eofb_HTM(apply_trans(fd, cube)));
2284
2285 return ret;
2286}
2287
2288static int
2289check_drud_HTM(Cube cube)
2290{
2291 if (!pd_drud_HTM.generated)
2292 generate_ptable(&pd_drud_HTM);
2293
2294 return PTABLEVAL(pd_drud_HTM.ptable, index_drud(cube));
2295}
2296
2297static int
2298check_optimal_HTM(Cube cube)
2299{
2300 int dr1, dr2, dr3, drmax, cor; /*ep;*/
2301
2302 if (!pd_drud_HTM.generated)
2303 generate_ptable(&pd_drud_HTM);
2304 if (!pd_corners_HTM.generated)
2305 generate_ptable(&pd_corners_HTM);
2306 /*
2307 *if (!pd_ep_HTM.generated)
2308 * generate_ptable(&pd_ep_HTM);
2309 */
2310
2311 dr1 = PTABLEVAL(pd_drud_HTM.ptable, index_drud(cube));
2312 dr2 = PTABLEVAL(pd_drud_HTM.ptable, index_drud(apply_trans(rf, cube)));
2313 dr3 = PTABLEVAL(pd_drud_HTM.ptable, index_drud(apply_trans(fd, cube)));
2314
2315 drmax = MAX(dr1, MAX(dr2, dr3));
2316 if (dr1 == dr2 && dr2 == dr3 && dr1 != 0)
2317 drmax++;
2318
2319 cor = PTABLEVAL(pd_corners_HTM.ptable, index_corners(cube));
2320 /* ep = PTABLEVAL(pd_ep_HTM.ptable, index_ep(cube)); */
2321
2322 /*return MAX(drmax, MAX(ep, cor));*/
2323 if (drmax == 0 && cor == 0)
2324 return is_solved(cube, false) ? 0 : 1;
2325 return MAX(drmax, cor);
2326}
2327
2328
2329/* Movesets ******************************************************************/
2330
2331bool
2332moveset_HTM(Move m)
2333{
2334 return m >= U && m <= B3;
2335}
2336
2337bool
2338moveset_URF(Move m)
2339{
2340 Move b = base_move(m);
2341
2342 return b == U || b == R || b == F;
2343}
2344
2345
2346/* Public functions implementation *******************************************/
2347
2348Cube
2349apply_alg(Alg *alg, Cube cube)
2350{
2351 return apply_alg_generic(alg, cube, pf_all, true);
2352}
2353
2354Cube
2355apply_move(Move m, Cube cube)
2356{
2357 Cube moved = {0};
2358
2359 moved.epose = epose_mtable[m][cube.epose];
2360 moved.eposs = eposs_mtable[m][cube.eposs];
2361 moved.eposm = eposm_mtable[m][cube.eposm];
2362 moved.eofb = eofb_mtable[m][cube.eofb];
2363 moved.eorl = eorl_mtable[m][cube.eorl];
2364 moved.eoud = eoud_mtable[m][cube.eoud];
2365 moved.coud = coud_mtable[m][cube.coud];
2366 moved.cofb = cofb_mtable[m][cube.cofb];
2367 moved.corl = corl_mtable[m][cube.corl];
2368 moved.cp = cp_mtable[m][cube.cp];
2369 moved.cpos = cpos_mtable[m][cube.cpos];
2370
2371 return moved;
2372}
2373
2374Cube
2375apply_trans(Trans t, Cube cube)
2376{
2377 Cube transformed = {0};
2378 uint16_t aux_epos[3] = { cube.epose, cube.eposs, cube.eposm };
2379 uint16_t aux_eo[3] = { cube.eoud, cube.eorl, cube.eofb };
2380 uint16_t aux_co[3] = { cube.coud, cube.corl, cube.cofb };
2381
2382 transformed.epose = epose_ttable[t][aux_epos[epose_source[t]]];
2383 transformed.eposs = eposs_ttable[t][aux_epos[eposs_source[t]]];
2384 transformed.eposm = eposm_ttable[t][aux_epos[eposm_source[t]]];
2385 transformed.eofb = eo_ttable[t][aux_eo[eofb_source[t]]];
2386 transformed.eorl = eo_ttable[t][aux_eo[eorl_source[t]]];
2387 transformed.eoud = eo_ttable[t][aux_eo[eoud_source[t]]];
2388 transformed.coud = co_ttable[t][aux_co[coud_source[t]]];
2389 transformed.corl = co_ttable[t][aux_co[corl_source[t]]];
2390 transformed.cofb = co_ttable[t][aux_co[cofb_source[t]]];
2391 transformed.cp = cp_ttable[t][cube.cp];
2392 transformed.cpos = cpos_ttable[t][cube.cpos];
2393
2394 return transformed;
2395}
2396
2397/* TODO: this has to be changed using pre-computations */
2398bool
2399block_solved(Cube cube, Block block)
2400{
2401 CubeArray *arr = new_cubearray(cube, pf_all);
2402 int i;
2403 bool ret = true;
2404
2405 for (i = 0; i < 12; i++)
2406 ret = ret && !(block.edge[i] && (arr->ep[i] != i || arr->eofb[i]));
2407 for (i = 0; i < 8; i++)
2408 ret = ret && !(block.corner[i] && (arr->cp[i] != i || arr->coud[i]));
2409 for (i = 0; i < 6; i++)
2410 ret = ret && !(block.center[i] && arr->cpos[i] != i);
2411
2412 free_cubearray(arr, pf_all);
2413
2414 return ret;
2415}
2416
2417Center
2418center_at(Cube cube, Center c)
2419{
2420 int ret;
2421 CubeArray *arr = new_cubearray(cube, pf_cpos);
2422
2423 ret = arr->cpos[c];
2424 free_cubearray(arr, pf_cpos);
2425
2426 return ret;
2427}
2428
2429Cube
2430compose(Cube c2, Cube c1)
2431{
2432 return compose_filtered(c2, c1, pf_all);
2433}
2434
2435Corner
2436corner_at(Cube cube, Corner c)
2437{
2438 int ret;
2439 CubeArray *arr = new_cubearray(cube, pf_cp);
2440
2441 ret = arr->cp[c];
2442 free_cubearray(arr, pf_cp);
2443
2444 return ret;
2445}
2446
2447Edge
2448edge_at(Cube cube, Edge e)
2449{
2450 int ret;
2451 CubeArray *arr = new_cubearray(cube, pf_ep);
2452
2453 ret = arr->ep[e];
2454 free_cubearray(arr, pf_ep);
2455
2456 return ret;
2457}
2458
2459bool
2460equal(Cube c1, Cube c2)
2461{
2462 return c1.eofb == c2.eofb &&
2463 c1.epose == c2.epose &&
2464 c1.eposs == c2.eposs &&
2465 c1.eposm == c2.eposm &&
2466 c1.coud == c2.coud &&
2467 c1.cp == c2.cp &&
2468 c1.cpos == c2.cpos;
2469}
2470
2471Cube
2472inverse_cube(Cube cube)
2473{
2474 CubeArray *arr = new_cubearray(cube, pf_all);
2475 CubeArray *inv = new_cubearray((Cube){0}, pf_all);
2476 Cube ret;
2477 int i;
2478
2479 for (i = 0; i < 12; i++) {
2480 inv->ep[arr->ep[i]] = i;
2481 inv->eofb[arr->ep[i]] = arr->eofb[i];
2482 inv->eorl[arr->ep[i]] = arr->eorl[i];
2483 inv->eoud[arr->ep[i]] = arr->eoud[i];
2484 }
2485
2486 for (i = 0; i < 8; i++) {
2487 inv->cp[arr->cp[i]] = i;
2488 inv->coud[arr->cp[i]] = (3 - arr->coud[i]) % 3;
2489 inv->corl[arr->cp[i]] = (3 - arr->corl[i]) % 3;
2490 inv->cofb[arr->cp[i]] = (3 - arr->cofb[i]) % 3;
2491 }
2492
2493 for (int i = 0; i < 6; i++)
2494 inv->cpos[arr->cpos[i]] = i;
2495
2496 ret = arrays_to_cube(inv, pf_all);
2497 free_cubearray(arr, pf_all);
2498 free_cubearray(inv, pf_all);
2499
2500 return ret;
2501}
2502
2503Move
2504inverse_move(Move m)
2505{
2506 return inverse_move_aux[m];
2507}
2508
2509Trans
2510inverse_trans(Trans t)
2511{
2512 return inverse_trans_aux[t];
2513}
2514
2515bool
2516is_admissible(Cube cube)
2517{
2518 /* TODO: this should check consistency of different orientations */
2519 /* TODO: check that centers are opposite and admissible */
2520
2521 CubeArray *a = new_cubearray(cube, pf_all);
2522 int parity;
2523 bool perm;
2524
2525 perm = is_perm(a->ep, 12) &&
2526 is_perm(a->cp, 8) &&
2527 is_perm(a->cpos, 6);
2528 parity = perm_sign(a->ep, 12) +
2529 perm_sign(a->cp, 8) +
2530 perm_sign(a->cpos, 6);
2531
2532 return perm && parity % 2 == 0;
2533}
2534
2535bool
2536is_solved(Cube cube, bool reorient)
2537{
2538 Trans i;
2539
2540 if (reorient)
2541 for (i = 0; i < NROTATIONS; i++)
2542 if (is_solved(apply_alg(trans_algs[i],cube), false))
2543 return true;
2544
2545 return equal(cube, (Cube){0});
2546}
2547
2548int
2549piece_orientation(Cube cube, int piece, char *orientation)
2550{
2551 int arr[12], n, b;
2552 uint16_t x;
2553
2554 if (!strcmp(orientation, "eofb")) {
2555 x = cube.eofb;
2556 n = 12;
2557 b = 2;
2558 } else if (!strcmp(orientation, "eorl")) {
2559 x = cube.eorl;
2560 n = 12;
2561 b = 2;
2562 } else if (!strcmp(orientation, "eoud")) {
2563 x = cube.eoud;
2564 n = 12;
2565 b = 2;
2566 } else if (!strcmp(orientation, "coud")) {
2567 x = cube.coud;
2568 n = 8;
2569 b = 3;
2570 } else if (!strcmp(orientation, "corl")) {
2571 x = cube.corl;
2572 n = 8;
2573 b = 3;
2574 } else if (!strcmp(orientation, "cofb")) {
2575 x = cube.cofb;
2576 n = 8;
2577 b = 3;
2578 } else {
2579 return -1;
2580 }
2581
2582 int_to_sum_zero_array(x, b, n, arr);
2583 if (piece < n)
2584 return arr[piece];
2585
2586 return -1;
2587}
2588
2589void
2590print_cube(Cube cube)
2591{
2592 CubeArray *arr = new_cubearray(cube, pf_all);
2593
2594 for (int i = 0; i < 12; i++)
2595 printf(" %s ", edge_string[arr->ep[i]]);
2596 printf("\n");
2597
2598 for (int i = 0; i < 12; i++)
2599 printf(" %c ", arr->eofb[i] + '0');
2600 printf("\n");
2601
2602 for (int i = 0; i < 8; i++)
2603 printf("%s ", corner_string[arr->cp[i]]);
2604 printf("\n");
2605
2606 for (int i = 0; i < 8; i++)
2607 printf(" %c ", arr->coud[i] + '0');
2608 printf("\n");
2609
2610 for (int i = 0; i < 6; i++)
2611 printf(" %s ", center_string[arr->cpos[i]]);
2612 printf("\n");
2613
2614 free_cubearray(arr, pf_all);
2615}
2616
2617Cube
2618random_cube()
2619{
2620 CubeArray *arr = new_cubearray((Cube){0}, pf_4val);
2621 Cube ret;
2622 int ep, cp, eo, co;
2623
2624 ep = rand() % FACTORIAL12;
2625 cp = rand() % FACTORIAL8;
2626 eo = rand() % POW2TO11;
2627 co = rand() % POW3TO7;
2628
2629 index_to_perm(ep, 12, arr->ep);
2630 index_to_perm(cp, 8, arr->cp);
2631 int_to_sum_zero_array(eo, 2, 12, arr->eofb);
2632 int_to_sum_zero_array(co, 3, 8, arr->coud);
2633
2634 if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8))
2635 swap(&(arr->ep[0]), &(arr->ep[1]));
2636
2637 ret = arrays_to_cube(arr, pf_4val);
2638 free_cubearray(arr, pf_4val);
2639
2640 return ret;
2641}
2642
2643AlgList *
2644solve(Cube cube, Step step, SolveOptions *opts)
2645{
2646 AlgListNode *node;
2647 AlgList *sols = new_alglist();
2648 Cube c = apply_trans(step.pre_trans, cube);
2649 DfsData dd = {
2650 .m = 0,
2651 .niss = false,
2652 .last1 = NULLMOVE,
2653 .last2 = NULLMOVE,
2654 .sols = sols,
2655 .current_alg = new_alg("")
2656 };
2657
2658 if (step.ready != NULL && !step.ready(c))
2659 return sols;
2660
2661 moveset_to_list(step.moveset, step.check, dd.sorted_moves);
2662
2663 for (dd.d = MAX(opts->min_moves, step.check(c));
2664 dd.d <= opts->max_moves && !(sols->len && opts->optimal_only);
2665 dd.d++) {
2666 solve_dfs(c, step, opts, &dd);
2667 if (opts->feedback)
2668 fprintf(stderr,
2669 "Depth %d completed, found %d solutions\n",
2670 dd.d, sols->len);
2671 }
2672
2673 for (node = sols->first; node != NULL; node = node->next)
2674 transform_alg(inverse_trans_aux[step.pre_trans], node->alg);
2675
2676 return sols;
2677}
2678
2679Alg *
2680inverse_alg(Alg *alg)
2681{
2682 Alg *ret = new_alg("");
2683 int i;
2684
2685 for (i = alg->len-1; i >= 0; i--)
2686 append_move(ret, alg->move[i], alg->inv[i]);
2687
2688 return ret;
2689}
2690
2691Alg *
2692new_alg(char *str)
2693{
2694 Alg *alg = malloc(sizeof(Alg));
2695 int i;
2696 bool niss = false;
2697 Move j, m;
2698
2699 alg->move = malloc(30 * sizeof(Move));
2700 alg->inv = malloc(30 * sizeof(bool));
2701 alg->allocated = 30;
2702 alg->len = 0;
2703
2704 for (i = 0; str[i]; i++) {
2705 if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n')
2706 continue;
2707
2708 if (str[i] == '(' && niss) {
2709 fprintf(stderr, "Error reading moves: nested ( )\n");
2710 return alg;
2711 }
2712
2713 if (str[i] == ')' && !niss) {
2714 fprintf(stderr, "Error reading moves: unmatched )\n");
2715 return alg;
2716 }
2717
2718 if (str[i] == '(' || str[i] == ')') {
2719 niss = !niss;
2720 continue;
2721 }
2722
2723 for (j = 0; j < NMOVES; j++) {
2724 if (str[i] == move_string[j][0]) {
2725 m = j;
2726 if (m <= B && str[i+1]=='w') {
2727 m += Uw - U;
2728 i++;
2729 }
2730 if (str[i+1]=='2') {
2731 m += 1;
2732 i++;
2733 } else if (str[i+1]=='\'' || str[i+1]=='3') {
2734 m += 2;
2735 i++;
2736 }
2737 append_move(alg, m, niss);
2738 break;
2739 }
2740 }
2741 }
2742
2743 return alg;
2744}
2745
2746Alg *
2747on_inverse(Alg *alg)
2748{
2749 Alg *ret = new_alg("");
2750 int i;
2751
2752 for (i = 0; i < alg->len; i++)
2753 append_move(ret, alg->move[i], !alg->inv[i]);
2754
2755 return ret;
2756}
2757
2758void
2759print_alg(Alg *alg, bool l)
2760{
2761 char fill[4];
2762 int i;
2763 bool niss = false;
2764
2765 for (i = 0; i < alg->len; i++) {
2766 if (!niss && alg->inv[i])
2767 strcpy(fill, i == 0 ? "(" : " (");
2768 if (niss && !alg->inv[i])
2769 strcpy(fill, ") ");
2770 if (niss == alg->inv[i])
2771 strcpy(fill, i == 0 ? "" : " ");
2772
2773 printf("%s%s", fill, move_string[alg->move[i]]);
2774 niss = alg->inv[i];
2775 }
2776
2777 if (niss)
2778 printf(")");
2779 if (l)
2780 printf(" (%d)", alg->len);
2781
2782 printf("\n");
2783}
2784
2785void
2786print_ptable(PruneData *pd)
2787{
2788 uint64_t i, a[16];
2789
2790 memset(a, 0, 16 * sizeof(uint64_t));
2791
2792 if (!pd->generated)
2793 generate_ptable(pd);
2794
2795 for (i = 0; i < pd->size; i++)
2796 a[PTABLEVAL(pd->ptable, i)]++;
2797
2798 fprintf(stderr, "Values for table %s\n", pd->filename);
2799 for (i = 0; i < 16; i++)
2800 printf("%2lu\t%10lu\n", i, a[i]);
2801}
2802
2803void
2804print_alglist(AlgList *al, bool l)
2805{
2806 AlgListNode *i;
2807
2808 for (i = al->first; i != NULL; i = i->next)
2809 print_alg(i->alg, l);
2810}
2811
2812void
2813transform_alg(Trans t, Alg *alg)
2814{
2815 int i;
2816
2817 for (i = 0; i < alg->len; i++)
2818 alg->move[i] = moves_ttable[t][alg->move[i]];
2819}
2820
2821
2822void
2823init()
2824{
2825 /* Order is important! */
2826 init_environment();
2827 init_strings();
2828 init_moves_aux();
2829 init_moves();
2830 init_auxtables();
2831 init_trans_aux();
2832 init_trans();
2833 init_steps();
2834}
2835
2836
diff --git a/old/2021-06-15-before-separating-steps/cube.h b/old/2021-06-15-before-separating-steps/cube.h
new file mode 100644
index 0000000..c30b53f
--- /dev/null
+++ b/old/2021-06-15-before-separating-steps/cube.h
@@ -0,0 +1,72 @@
1#ifndef CUBE_H
2#define CUBE_H
3
4#include <stdio.h>
5#include <stdbool.h>
6#include <stdint.h>
7#include <stdlib.h>
8#include <string.h>
9#include <time.h>
10#include <unistd.h>
11#include <sys/stat.h>
12#include "cubetypes.h"
13
14/* Steps *********************************************************************/
15
16extern Step eofb_HTM;
17extern Step eorl_HTM;
18extern Step eoud_HTM;
19extern Step coud_HTM;
20extern Step corl_HTM;
21extern Step cofb_HTM;
22extern Step coud_URF;
23extern Step corl_URF;
24extern Step cofb_URF;
25extern Step corners_HTM;
26extern Step corners_URF;
27extern Step edges_HTM;
28extern Step drud_HTM;
29extern Step optimal_HTM;
30
31extern PruneData pd_eofb_HTM;
32extern PruneData pd_coud_HTM;
33extern PruneData pd_corners_HTM;
34extern PruneData pd_ep_HTM;
35extern PruneData pd_drud_HTM;
36
37/* Public functions **********************************************************/
38
39Cube apply_alg(Alg *alg, Cube cube);
40Cube apply_move(Move m, Cube cube);
41Cube apply_trans(Trans t, Cube cube);
42bool block_solved(Cube cube, Block);
43Center center_at(Cube cube, Center c);
44Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */
45Corner corner_at(Cube cube, Corner c);
46Edge edge_at(Cube cube, Edge e);
47bool equal(Cube c1, Cube c2);
48Cube inverse_cube(Cube cube);
49Move inverse_move(Move m);
50Trans inverse_trans(Trans t);
51bool is_admissible(Cube cube);
52bool is_solved(Cube cube, bool reorient);
53int piece_orientation(Cube cube, int piece, char *orientation);
54void print_cube(Cube cube);
55Cube random_cube();
56AlgList * solve(Cube cube, Step step, SolveOptions *opts);
57
58void free_alg(Alg *alg);
59void free_alglist(AlgList *l);
60Alg * inverse_alg(Alg *alg);
61Alg * new_alg(char *str);
62Alg * on_inverse(Alg *alg);
63void print_alg(Alg *alg, bool l);
64void print_alglist(AlgList *al, bool l);
65void transform_alg(Trans t, Alg *alg);
66
67void print_ptable(PruneData *pd);
68
69void init();
70
71#endif
72
diff --git a/old/2021-06-15-before-separating-steps/cubetypes.h b/old/2021-06-15-before-separating-steps/cubetypes.h
new file mode 100644
index 0000000..6ba3675
--- /dev/null
+++ b/old/2021-06-15-before-separating-steps/cubetypes.h
@@ -0,0 +1,201 @@
1/* Typedefs ******************************************************************/
2
3typedef enum center Center;
4typedef enum corner Corner;
5typedef enum edge Edge;
6typedef enum move Move;
7typedef enum trans Trans;
8
9typedef struct alg Alg;
10typedef struct alglist AlgList;
11typedef struct alglistnode AlgListNode;
12typedef struct block Block;
13typedef struct cube Cube;
14typedef struct cubearray CubeArray;
15typedef struct dfsdata DfsData;
16typedef struct piecefilter PieceFilter;
17typedef struct prunedata PruneData;
18typedef struct solveoptions SolveOptions;
19typedef struct step Step;
20
21/* Enums *********************************************************************/
22
23enum
24center
25{
26 U_center, D_center,
27 R_center, L_center,
28 F_center, B_center
29};
30
31enum
32corner
33{
34 UFR, UFL, UBL, UBR,
35 DFR, DFL, DBL, DBR
36};
37
38enum
39edge
40{
41 UF, UL, UB, UR,
42 DF, DL, DB, DR,
43 FR, FL, BL, BR
44};
45
46enum
47move
48{
49 NULLMOVE,
50 U, U2, U3, D, D2, D3,
51 R, R2, R3, L, L2, L3,
52 F, F2, F3, B, B2, B3,
53 Uw, Uw2, Uw3, Dw, Dw2, Dw3,
54 Rw, Rw2, Rw3, Lw, Lw2, Lw3,
55 Fw, Fw2, Fw3, Bw, Bw2, Bw3,
56 M, M2, M3,
57 S, S2, S3,
58 E, E2, E3,
59 x, x2, x3,
60 y, y2, y3,
61 z, z2, z3,
62};
63
64enum
65trans
66{
67 uf, ur, ub, ul,
68 df, dr, db, dl,
69 rf, rd, rb, ru,
70 lf, ld, lb, lu,
71 fu, fr, fd, fl,
72 bu, br, bd, bl,
73 mirror, /* R|L */
74};
75
76
77/* Structs *******************************************************************/
78
79struct
80alg
81{
82 Move * move;
83 bool * inv;
84 int len;
85 int allocated;
86};
87
88struct
89alglist
90{
91 AlgListNode * first;
92 AlgListNode * last;
93 int len;
94};
95
96struct
97alglistnode
98{
99 Alg * alg;
100 AlgListNode * next;
101};
102
103struct
104block
105{
106 bool edge[12];
107 bool corner[8];
108 bool center[6];
109};
110
111struct
112cube
113{
114 uint16_t epose;
115 uint16_t eposs;
116 uint16_t eposm;
117 uint16_t eofb;
118 uint16_t eorl;
119 uint16_t eoud;
120 uint16_t cp;
121 uint16_t coud;
122 uint16_t cofb;
123 uint16_t corl;
124 uint16_t cpos;
125};
126
127struct
128cubearray
129{
130 int * ep;
131 int * eofb;
132 int * eorl;
133 int * eoud;
134 int * cp;
135 int * coud;
136 int * corl;
137 int * cofb;
138 int * cpos;
139};
140
141struct
142dfsdata
143{
144 int d;
145 int m;
146 bool niss;
147 Move last1;
148 Move last2;
149 AlgList * sols;
150 Alg * current_alg;
151 Move sorted_moves[z3+1];
152};
153
154struct
155piecefilter
156{
157 bool epose;
158 bool eposs;
159 bool eposm;
160 bool eofb;
161 bool eorl;
162 bool eoud;
163 bool cp;
164 bool coud;
165 bool cofb;
166 bool corl;
167 bool cpos;
168};
169
170struct
171prunedata
172{
173 char * filename;
174 uint8_t * ptable;
175 uint8_t * reached;
176 bool generated;
177 uint64_t n;
178 uint64_t size;
179 uint64_t (*index)(Cube);
180 bool (*moveset)(Move);
181};
182
183struct
184solveoptions
185{
186 int min_moves;
187 int max_moves;
188 int max_solutions;
189 bool optimal_only;
190 bool can_niss;
191 bool feedback;
192};
193
194struct
195step
196{
197 int (*check)(Cube);
198 int (*ready)(Cube);
199 bool (*moveset)(Move);
200 Trans pre_trans;
201};
diff --git a/old/2021-06-15-before-separating-steps/main.c b/old/2021-06-15-before-separating-steps/main.c
new file mode 100644
index 0000000..ff726b5
--- /dev/null
+++ b/old/2021-06-15-before-separating-steps/main.c
@@ -0,0 +1,60 @@
1#include <stdio.h>
2#include "cube.h"
3
4int main() {
5 Alg *algo;
6 AlgList *sols;
7 Cube cube;
8 SolveOptions opts;
9 char line[1000];
10 int i, ns = 2, nrand = 100000, sum1, sum2;
11
12 Step *stps[20] = {&drud_HTM, &optimal_HTM};
13 char sss[30][30] = {"DR on U/D", "Optimal solution"};
14
15 opts = (SolveOptions) {
16 .min_moves = 0,
17 .max_moves = 20,
18 .optimal_only = true,
19 .max_solutions = 1,
20 .can_niss = false,
21 .feedback = true
22 };
23
24 init();
25
26/*
27 print_ptable(&pd_drud_HTM);
28 print_ptable(&pd_ep_HTM);
29 print_ptable(&pd_corners_HTM);
30*/
31
32 srand(time(NULL));
33 sum1 = 0;
34 sum2 = 0;
35 for (i = 0; i < nrand; i++) {
36 sum1 += optimal_HTM.check(random_cube());
37 sum2 += corners_HTM.check(random_cube());
38 }
39 printf("Average optimal pruning: %lf\n", ((double)sum1) / ((double) nrand));
40 printf("Average corners pruning: %lf\n", ((double)sum2) / ((double) nrand));
41
42 printf("Welcome to nissy 2.0! Insert a scramble:\n");
43
44 if (fgets(line, 1000, stdin) != NULL) {
45 algo = new_alg(line);
46 cube = apply_alg(algo, (Cube){0});
47
48 for (i = 0; i < ns; i++) {
49 if (stps[i]->check == NULL)
50 fprintf(stderr, "Check function for step %d is null\n", i);
51 sols = solve(cube, *stps[i], &opts);
52 printf("%s: %d solutions found:\n", sss[i], sols->len);
53 print_alglist(sols, true);
54 free_alglist(sols);
55 }
56 free(algo);
57 }
58
59 return 0;
60}
diff --git a/old/2021-06-15-before-separating-steps/steps.h b/old/2021-06-15-before-separating-steps/steps.h
new file mode 100644
index 0000000..e2b71a0
--- /dev/null
+++ b/old/2021-06-15-before-separating-steps/steps.h
@@ -0,0 +1,20 @@
1extern Step eofb_HTM;
2extern Step eorl_HTM;
3extern Step eoud_HTM;
4extern Step coud_HTM;
5extern Step corl_HTM;
6extern Step cofb_HTM;
7extern Step coud_URF;
8extern Step corl_URF;
9extern Step cofb_URF;
10extern Step corners_HTM;
11extern Step corners_URF;
12extern Step edges_HTM;
13extern Step drud_HTM;
14extern Step optimal_HTM;
15
16extern PruneData pd_eofb_HTM;
17extern PruneData pd_coud_HTM;
18extern PruneData pd_corners_HTM;
19extern PruneData pd_ep_HTM;
20extern PruneData pd_drud_HTM;
diff --git a/old/2021-06-17-cachedata/cube.c b/old/2021-06-17-cachedata/cube.c
new file mode 100644
index 0000000..58178dc
--- /dev/null
+++ b/old/2021-06-17-cachedata/cube.c
@@ -0,0 +1,2738 @@
1#include "cube.h"
2
3/* Constants and macros *****************************************************/
4
5#define POW2TO11 2048ULL
6#define POW2TO12 4096ULL
7#define POW3TO7 2187ULL
8#define POW3TO8 6561ULL
9#define FACTORIAL4 24ULL
10#define FACTORIAL6 720ULL
11#define FACTORIAL8 40320ULL
12#define FACTORIAL12 479001600ULL
13#define BINOM12ON4 495ULL
14#define BINOM8ON4 70ULL
15#define MIN(a,b) (((a) < (b)) ? (a) : (b))
16#define MAX(a,b) (((a) > (b)) ? (a) : (b))
17
18#define NMOVES (z3+1)
19#define NTRANS (mirror+1)
20#define NROTATIONS (NTRANS-1)
21#define PTABLESIZE(n) ((n+1) / 2)
22
23
24/* Local functions **********************************************************/
25
26static Cube admissible_ep(Cube cube, PieceFilter f);
27static bool allowed_next_move(Move move, DfsData *dd);
28static void append_alg(AlgList *l, Alg *alg);
29static void append_move(Alg *alg, Move m, bool inverse);
30static Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a);
31static void apply_permutation(int *perm, int *set, int n);
32static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f);
33static uint16_t array_ep_to_epos(int *ep, int *eps_solved);
34static Cube arrays_to_cube(CubeArray *arr, PieceFilter f);
35static int binomial(int n, int k);
36static Cube compose_filtered(Cube c2, Cube c1, PieceFilter f);
37static void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f);
38static int digit_array_to_int(int *a, int n, int b);
39static int edge_slice(Edge e); /* E=0, S=1, M=2 */
40static int epos_dependent(int pos1, int pos2);
41static uint16_t epos_from_arrays(int *epos, int *ep);
42static void epos_to_partial_ep(uint16_t epos, int *ep, int *ss);
43static int factorial(int n);
44static void free_alglistnode(AlgListNode *aln);
45static void free_cubearray(CubeArray *arr, PieceFilter f);
46static void generate_ctable_dfs(Cube c, CacheData *cd, DfsData *dd);
47static void generate_ptable_dfs(Cube c, PruneData *pd, DfsData *dd);
48static void index_to_perm(int p, int n, int *r);
49static void index_to_subset(int s, int n, int k, int *r);
50static void int_to_digit_array(int a, int b, int n, int *r);
51static void int_to_sum_zero_array(int x, int b, int n, int *a);
52static int invert_digits(int a, int b, int n);
53static bool is_perm(int *a, int n);
54static bool is_subset(int *a, int n, int k);
55static Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf);
56static void movelist_to_position(Move *movelist, int *position);
57static void moveset_to_list(Moveset ms, Checker f, Move *r);
58static AlgList * new_alglist();
59static CubeArray * new_cubearray(Cube cube, PieceFilter f);
60static int perm_sign(int *a, int n);
61static int perm_to_index(int *a, int n);
62/*static int powint(int a, int b);*/
63static void ptable_set_reached(PruneData *pd, uint64_t ind);
64static void ptable_update(PruneData *pd, uint64_t ind, int m);
65static void push_cachenode(CacheData *cd, Cube c, Alg *alg);
66static void realloc_alg(Alg *alg, int n);
67static bool read_ctable_file(CacheData *cd);
68static bool read_mtables_file();
69static bool read_ptable_file(PruneData *pd);
70static bool read_ttables_file();
71static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f);
72static void solve_cd(Cube c, Step s, SolveOptions *opts, DfsData *dd);
73static void solve_dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd);
74static int subset_to_index(int *a, int n, int k);
75static void sum_arrays_mod(int *src, int *dst, int n, int m);
76static void swap(int *a, int *b);
77static bool write_ctable_file(CacheData *cd);
78static bool write_mtables_file();
79static bool write_ptable_file(PruneData *pd);
80static bool write_ttables_file();
81
82static void init_auxtables();
83static void init_environment();
84static void init_moves();
85static void init_moves_aux();
86static void init_strings();
87static void init_trans();
88static void init_trans_aux();
89
90/* All sorts of useful costants and tables **********************************/
91
92static char * tabledir;
93
94static PieceFilter pf_all;
95static PieceFilter pf_4val;
96static PieceFilter pf_epcp;
97static PieceFilter pf_cpos;
98static PieceFilter pf_cp;
99static PieceFilter pf_ep;
100static PieceFilter pf_e;
101static PieceFilter pf_s;
102static PieceFilter pf_m;
103static PieceFilter pf_eo;
104static PieceFilter pf_co;
105
106static int epe_solved[4];
107static int eps_solved[4];
108static int epm_solved[4];
109
110static char move_string[NMOVES][7];
111static char edge_string[12][7];
112static char corner_string[8][7];
113static char center_string[6][7];
114
115static bool commute[NMOVES][NMOVES];
116static bool possible_next[NMOVES][NMOVES][NMOVES];
117static Move inverse_move_aux[NMOVES];
118static Trans inverse_trans_aux[NTRANS];
119static int epos_dependent_aux[BINOM12ON4][BINOM12ON4];
120
121static uint16_t epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
122static uint16_t eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
123static uint16_t eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
124static uint16_t eo_ttable[NTRANS][POW2TO11];
125static uint16_t cp_ttable[NTRANS][FACTORIAL8];
126static uint16_t co_ttable[NTRANS][POW3TO7];
127static uint16_t cpos_ttable[NTRANS][FACTORIAL6];
128static Move moves_ttable[NTRANS][NMOVES];
129
130static uint16_t epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
131static uint16_t eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
132static uint16_t eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
133static uint16_t eofb_mtable[NMOVES][POW2TO11];
134static uint16_t eorl_mtable[NMOVES][POW2TO11];
135static uint16_t eoud_mtable[NMOVES][POW2TO11];
136static uint16_t cp_mtable[NMOVES][FACTORIAL8];
137static uint16_t coud_mtable[NMOVES][POW3TO7];
138static uint16_t cofb_mtable[NMOVES][POW3TO7];
139static uint16_t corl_mtable[NMOVES][POW3TO7];
140static uint16_t cpos_mtable[NMOVES][FACTORIAL6];
141
142static uint64_t me[12];
143
144static int edge_cycle[NMOVES][12];
145static int corner_cycle[NMOVES][8];
146static int center_cycle[NMOVES][6];
147static int eofb_flipped[NMOVES][12];
148static int eorl_flipped[NMOVES][12];
149static int eoud_flipped[NMOVES][12];
150static int coud_flipped[NMOVES][8];
151static int corl_flipped[NMOVES][8];
152static int cofb_flipped[NMOVES][8];
153static Alg * equiv_alg[NMOVES];
154
155static int epose_source[NTRANS]; /* 0=epose, 1=eposs, 2=eposm */
156static int eposs_source[NTRANS];
157static int eposm_source[NTRANS];
158static int eofb_source[NTRANS]; /* 0=eoud, 1=eorl, 2=eofb */
159static int eorl_source[NTRANS];
160static int eoud_source[NTRANS];
161static int coud_source[NTRANS]; /* 0=coud, 1=corl, 2=cofb */
162static int cofb_source[NTRANS];
163static int corl_source[NTRANS];
164static int ep_mirror[12];
165static int cp_mirror[8];
166static int cpos_mirror[6];
167static Alg * trans_algs[NROTATIONS];
168
169
170/* Local functions implementation ********************************************/
171
172static Cube
173admissible_ep(Cube cube, PieceFilter f)
174{
175 CubeArray *arr = new_cubearray(cube, f);
176 Cube ret;
177 bool used[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
178 int i, j;
179
180 for (i = 0; i < 12; i++)
181 if (arr->ep[i] != -1)
182 used[arr->ep[i]] = true;
183
184 for (i = 0, j = 0; i < 12; i++) {
185 for ( ; j < 11 && used[j]; j++);
186 if (arr->ep[i] == -1)
187 arr->ep[i] = j++;
188 }
189
190 ret = arrays_to_cube(arr, pf_ep);
191 free_cubearray(arr, f);
192
193 return ret;
194}
195
196static bool
197allowed_next_move(Move move, DfsData *dd)
198{
199 if (!possible_next[dd->last2][dd->last1][move])
200 return false;
201
202 if (commute[dd->last1][move])
203 return dd->move_position[dd->last1] < dd->move_position[move];
204
205 return true;
206}
207
208static void
209append_alg(AlgList *l, Alg *alg)
210{
211 AlgListNode *node = malloc(sizeof(AlgListNode));
212 int i;
213
214 node->alg = new_alg("");
215 for (i = 0; i < alg->len; i++)
216 append_move(node->alg, alg->move[i], alg->inv[i]);
217 node->next = NULL;
218
219 if (++l->len == 1)
220 l->first = node;
221 else
222 l->last->next = node;
223 l->last = node;
224}
225
226static void
227append_move(Alg *alg, Move m, bool inverse)
228{
229 if (alg->len == alg->allocated)
230 realloc_alg(alg, 2*alg->len);
231
232 alg->move[alg->len] = m;
233 alg->inv [alg->len] = inverse;
234 alg->len++;
235}
236
237static Cube
238apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a)
239{
240 Cube ret = {0};
241 int i;
242
243 for (i = 0; i < alg->len; i++)
244 if (alg->inv[i])
245 ret = a ? apply_move(alg->move[i], ret) :
246 apply_move_cubearray(alg->move[i], ret, f);
247
248 ret = compose_filtered(c, inverse_cube(ret), f);
249
250 for (i = 0; i < alg->len; i++)
251 if (!alg->inv[i])
252 ret = a ? apply_move(alg->move[i], ret) :
253 apply_move_cubearray(alg->move[i], ret, f);
254
255 return ret;
256}
257
258static void
259apply_permutation(int *perm, int *set, int n)
260{
261 int *aux = malloc(n * sizeof(int));
262 int i;
263
264 if (!is_perm(perm, n))
265 return;
266
267 for (i = 0; i < n; i++)
268 aux[i] = set[perm[i]];
269
270 memcpy(set, aux, n * sizeof(int));
271 free(aux);
272}
273
274static Cube
275apply_move_cubearray(Move m, Cube cube, PieceFilter f)
276{
277 CubeArray m_arr = {
278 edge_cycle[m],
279 eofb_flipped[m],
280 eorl_flipped[m],
281 eoud_flipped[m],
282 corner_cycle[m],
283 coud_flipped[m],
284 corl_flipped[m],
285 cofb_flipped[m],
286 center_cycle[m]
287 };
288
289 return move_via_arrays(&m_arr, cube, f);
290}
291
292static uint16_t
293array_ep_to_epos(int *ep, int *ss)
294{
295 int epos[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
296 int eps[4];
297 int i, j, is;
298
299 for (i = 0, is = 0; i < 12; i++) {
300 for (j = 0; j < 4; j++) {
301 if (ep[i] == ss[j]) {
302 eps[is++] = j;
303 epos[i] = 1;
304 }
305 }
306 }
307
308 for (i = 0; i < 4; i++)
309 swap(&epos[ss[i]], &epos[i+8]);
310
311 return epos_from_arrays(epos, eps);
312}
313
314static Cube
315arrays_to_cube(CubeArray *arr, PieceFilter f)
316{
317 Cube ret = {0};
318
319 if (f.epose)
320 ret.epose = array_ep_to_epos(arr->ep, epe_solved);
321 if (f.eposs)
322 ret.eposs = array_ep_to_epos(arr->ep, eps_solved);
323 if (f.eposm)
324 ret.eposm = array_ep_to_epos(arr->ep, epm_solved);
325 if (f.eofb)
326 ret.eofb = digit_array_to_int(arr->eofb, 11, 2);
327 if (f.eorl)
328 ret.eorl = digit_array_to_int(arr->eorl, 11, 2);
329 if (f.eoud)
330 ret.eoud = digit_array_to_int(arr->eoud, 11, 2);
331 if (f.cp)
332 ret.cp = perm_to_index(arr->cp, 8);
333 if (f.coud)
334 ret.coud = digit_array_to_int(arr->coud, 7, 3);
335 if (f.corl)
336 ret.corl = digit_array_to_int(arr->corl, 7, 3);
337 if (f.cofb)
338 ret.cofb = digit_array_to_int(arr->cofb, 7, 3);
339 if (f.cpos)
340 ret.cpos = perm_to_index(arr->cpos, 6);
341
342 return ret;
343}
344
345static int
346binomial(int n, int k)
347{
348 if (n < 0 || k < 0 || k > n)
349 return 0;
350
351 return factorial(n) / (factorial(k) * factorial(n-k));
352}
353
354static Cube
355compose_filtered(Cube c2, Cube c1, PieceFilter f)
356{
357 CubeArray *arr = new_cubearray(c2, f);
358 Cube ret;
359
360 ret = move_via_arrays(arr, c1, f);
361 free_cubearray(arr, f);
362
363 return ret;
364}
365
366static void
367cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f)
368{
369 int i;
370
371 if (f.epose || f.eposs || f.eposm)
372 for (i = 0; i < 12; i++)
373 arr->ep[i] = -1;
374
375 if (f.epose)
376 epos_to_partial_ep(cube.epose, arr->ep, epe_solved);
377 if (f.eposs)
378 epos_to_partial_ep(cube.eposs, arr->ep, eps_solved);
379 if (f.eposm)
380 epos_to_partial_ep(cube.eposm, arr->ep, epm_solved);
381 if (f.eofb)
382 int_to_sum_zero_array(cube.eofb, 2, 12, arr->eofb);
383 if (f.eorl)
384 int_to_sum_zero_array(cube.eorl, 2, 12, arr->eorl);
385 if (f.eoud)
386 int_to_sum_zero_array(cube.eoud, 2, 12, arr->eoud);
387 if (f.cp)
388 index_to_perm(cube.cp, 8, arr->cp);
389 if (f.coud)
390 int_to_sum_zero_array(cube.coud, 3, 8, arr->coud);
391 if (f.corl)
392 int_to_sum_zero_array(cube.corl, 3, 8, arr->corl);
393 if (f.cofb)
394 int_to_sum_zero_array(cube.cofb, 3, 8, arr->cofb);
395 if (f.cpos)
396 index_to_perm(cube.cpos, 6, arr->cpos);
397}
398
399static int
400digit_array_to_int(int *a, int n, int b)
401{
402 int i, ret = 0, p = 1;
403
404 for (i = 0; i < n; i++, p *= b)
405 ret += a[i] * p;
406
407 return ret;
408}
409
410static int
411edge_slice(Edge e) {
412 if (e < 0 || e > 11)
413 return -1;
414
415 if (e == FR || e == FL || e == BL || e == BR)
416 return 0;
417 if (e == UR || e == UL || e == DR || e == DL)
418 return 1;
419
420 return 2;
421}
422
423static int
424epos_dependent(int poss, int pose)
425{
426 int ep[12] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
427 int ep8[8] = {0, 0, 0, 0, 0, 0, 0, 0};
428 int i, j;
429
430 epos_to_partial_ep(poss*FACTORIAL4, ep, eps_solved);
431 epos_to_partial_ep(pose*FACTORIAL4, ep, epe_solved);
432
433 for (i = 0, j = 0; i < 12; i++)
434 if (edge_slice(ep[i]) != 1)
435 ep8[j++] = (edge_slice(ep[i]) == 0) ? 1 : 0;
436
437 return subset_to_index(ep8, 8, 4);
438}
439
440static uint16_t
441epos_from_arrays(int *epos, int *ep)
442{
443 return FACTORIAL4 * subset_to_index(epos,12,4) + perm_to_index(ep,4);
444}
445
446static void
447epos_to_partial_ep(uint16_t epos, int *ep, int *ss)
448{
449 int i, is, eposs[12], eps[4];
450
451 index_to_perm(epos % FACTORIAL4, 4, eps);
452 index_to_subset(epos / FACTORIAL4, 12, 4, eposs);
453
454 for (i = 0; i < 4; i++)
455 swap(&eposs[ss[i]], &eposs[i+8]);
456
457 for (i = 0, is = 0; i < 12; i++)
458 if (eposs[i])
459 ep[i] = ss[eps[is++]];
460}
461
462static int
463factorial(int n)
464{
465 int i, ret = 1;
466
467 if (n < 0)
468 return 0;
469
470 for (i = 1; i <= n; i++)
471 ret *= i;
472
473 return ret;
474}
475
476void
477free_alg(Alg *alg)
478{
479 free(alg->move);
480 free(alg->inv);
481 free(alg);
482}
483
484void
485free_alglist(AlgList *l)
486{
487 AlgListNode *aux, *i = l->first;
488
489 while (i != NULL) {
490 aux = i->next;
491 free_alglistnode(i);
492 i = aux;
493 }
494 free(l);
495}
496
497void
498free_alglistnode(AlgListNode *aln)
499{
500 free_alg(aln->alg);
501 free(aln);
502}
503
504static void
505free_cubearray(CubeArray *arr, PieceFilter f)
506{
507 if (f.epose || f.eposs || f.eposm)
508 free(arr->ep);
509 if (f.eofb)
510 free(arr->eofb);
511 if (f.eorl)
512 free(arr->eorl);
513 if (f.eoud)
514 free(arr->eoud);
515 if (f.cp)
516 free(arr->cp);
517 if (f.coud)
518 free(arr->coud);
519 if (f.corl)
520 free(arr->corl);
521 if (f.cofb)
522 free(arr->cofb);
523 if (f.cpos)
524 free(arr->cpos);
525
526 free(arr);
527}
528
529static void
530generate_ctable_dfs(Cube c, CacheData *cd, DfsData *dd)
531{
532 int i;
533 bool flag;
534 Move move, l1 = dd->last1, l2 = dd->last2;
535
536 if (dd->current_alg->len > 0) {
537 for (i = 0, flag = true; i < cd->nind; i++) {
538 if (cd->index[i](c) != cd->index[i]((Cube){0})) {
539 flag = false;
540 break;
541 }
542 }
543 if (flag)
544 return;
545 }
546
547 if (dd->current_alg->len == dd->d) {
548 push_cachenode(cd, c, dd->current_alg);
549 return;
550 }
551
552 for (i = 0; dd->sorted_moves[i] != NULLMOVE; i++) {
553 move = dd->sorted_moves[i];
554 if (allowed_next_move(move, dd)) {
555 dd->last2 = dd->last1;
556 dd->last1 = move;
557 append_move(dd->current_alg, move, false);
558 generate_ctable_dfs(apply_move(move, c), cd, dd);
559 dd->current_alg->len--;
560 dd->last2 = l2;
561 dd->last1 = l1;
562 }
563 }
564}
565
566static void
567generate_ptable_dfs(Cube c, PruneData *pd, DfsData *dd)
568{
569 uint64_t ind = pd->index(c);
570 int oldval = PTABLEVAL(pd->ptable, ind);
571 Move i, move, l1 = dd->last1, l2 = dd->last2;
572
573 if (oldval < dd->m || PTABLEVAL(pd->reached, ind) || pd->n == pd->size)
574 return;
575
576 ptable_set_reached(pd, ind);
577
578 if (dd->m == dd->d) {
579 if (dd->m < oldval)
580 ptable_update(pd, ind, dd->m);
581 return;
582 }
583
584 dd->m++;
585 for (i = 0; dd->sorted_moves[i] != NULLMOVE; i++) {
586 move = dd->sorted_moves[i];
587 if (allowed_next_move(move, dd)) {
588 dd->last2 = dd->last1;
589 dd->last1 = move;
590 generate_ptable_dfs(apply_move(move, c), pd, dd);
591 dd->last2 = l2;
592 dd->last1 = l1;
593 }
594 }
595
596 dd->m--;
597 dd->last1 = l1;
598 dd->last2 = l2;
599}
600
601static void
602index_to_perm(int p, int n, int *r)
603{
604 int *a = malloc(n * sizeof(int));
605 int i, j, c;
606
607 for (i = 0; i < n; i++)
608 a[i] = 0;
609
610 if (p < 0 || p >= factorial(n))
611 for (i = 0; i < n; i++)
612 r[i] = -1;
613
614 for (i = 0; i < n; i++) {
615 c = 0;
616 j = 0;
617 while (c <= p / factorial(n-i-1))
618 c += a[j++] ? 0 : 1;
619 r[i] = j-1;
620 a[j-1] = 1;
621 p %= factorial(n-i-1);
622 }
623
624 free(a);
625}
626
627static void
628index_to_subset(int s, int n, int k, int *r)
629{
630 int i, j, v;
631
632 if (s < 0 || s >= binomial(n, k)) {
633 for (i = 0; i < n; i++)
634 r[i] = -1;
635 return;
636 }
637
638 for (i = 0; i < n; i++) {
639 if (k == n-i) {
640 for (j = i; j < n; j++)
641 r[j] = 1;
642 return;
643 }
644
645 if (k == 0) {
646 for (j = i; j < n; j++)
647 r[j] = 0;
648 return;
649 }
650
651 v = binomial(n-i-1, k);
652 if (s >= v) {
653 r[i] = 1;
654 k--;
655 s -= v;
656 } else {
657 r[i] = 0;
658 }
659 }
660}
661
662static void
663int_to_digit_array(int a, int b, int n, int *r)
664{
665 int i;
666
667 if (b <= 1)
668 for (i = 0; i < n; i++)
669 r[i] = 0;
670 else
671 for (i = 0; i < n; i++, a /= b)
672 r[i] = a % b;
673}
674
675static void
676int_to_sum_zero_array(int x, int b, int n, int *a)
677{
678 int i, s = 0;
679
680 if (b <= 1) {
681 for (i = 0; i < n; i++)
682 a[i] = 0;
683 } else {
684 int_to_digit_array(x, b, n-1, a);
685 for (i = 0; i < n - 1; i++)
686 s = (s + a[i]) % b;
687 a[n-1] = (b - s) % b;
688 }
689}
690
691static int
692invert_digits(int a, int b, int n)
693{
694 int i, ret, *r = malloc(n * sizeof(int));
695
696 int_to_digit_array(a, b, n, r);
697 for (i = 0; i < n; i++)
698 r[i] = (b-r[i]) % b;
699
700 ret = digit_array_to_int(r, n, b);
701 free(r);
702 return ret;
703}
704
705static bool
706is_perm(int *a, int n)
707{
708 int *aux = malloc(n * sizeof(int));
709 int i;
710
711 for (i = 0; i < n; i++)
712 if (a[i] < 0 || a[i] >= n)
713 return false;
714 else
715 aux[a[i]] = 1;
716
717 for (i = 0; i < n; i++)
718 if (!aux[i])
719 return false;
720
721 free(aux);
722
723 return true;
724}
725
726static bool
727is_subset(int *a, int n, int k)
728{
729 int i, sum = 0;
730
731 for (i = 0; i < n; i++)
732 sum += a[i] ? 1 : 0;
733
734 return sum == k;
735}
736
737static Cube
738move_via_arrays(CubeArray *arr, Cube c, PieceFilter f)
739{
740 CubeArray *arrc = new_cubearray(c, f);
741 Cube ret;
742
743 if (f.epose || f.eposs || f.eposm)
744 apply_permutation(arr->ep, arrc->ep, 12);
745
746 if (f.eofb) {
747 apply_permutation(arr->ep, arrc->eofb, 12);
748 sum_arrays_mod(arr->eofb, arrc->eofb, 12, 2);
749 }
750
751 if (f.eorl) {
752 apply_permutation(arr->ep, arrc->eorl, 12);
753 sum_arrays_mod(arr->eorl, arrc->eorl, 12, 2);
754 }
755
756 if (f.eoud) {
757 apply_permutation(arr->ep, arrc->eoud, 12);
758 sum_arrays_mod(arr->eoud, arrc->eoud, 12, 2);
759 }
760
761 if (f.cp)
762 apply_permutation(arr->cp, arrc->cp, 8);
763
764 if (f.coud) {
765 apply_permutation(arr->cp, arrc->coud, 8);
766 sum_arrays_mod(arr->coud, arrc->coud, 8, 3);
767 }
768
769 if (f.corl) {
770 apply_permutation(arr->cp, arrc->corl, 8);
771 sum_arrays_mod(arr->corl, arrc->corl, 8, 3);
772 }
773
774 if (f.cofb) {
775 apply_permutation(arr->cp, arrc->cofb, 8);
776 sum_arrays_mod(arr->cofb, arrc->cofb, 8, 3);
777 }
778
779 if (f.cpos)
780 apply_permutation(arr->cpos, arrc->cpos, 6);
781
782 ret = arrays_to_cube(arrc, f);
783 free_cubearray(arrc, f);
784
785 return ret;
786}
787
788static void
789movelist_to_position(Move *movelist, int *position)
790{
791 Move m;
792
793 for (m = 0; m < NMOVES && movelist[m] != NULLMOVE; m++)
794 position[movelist[m]] = m;
795}
796
797static void
798moveset_to_list(bool (*ms)(Move m), int (*f)(Cube), Move *r)
799{
800 Cube c;
801 int b[NMOVES];
802 int na = 0, nb = 0;
803 Move i;
804
805 if (ms == NULL) {
806 fprintf(stderr, "Error: no moveset given\n");
807 return;
808 }
809
810 for (i = U; i < NMOVES; i++) {
811 if (ms(i)) {
812 c = apply_move(i, (Cube){0});
813 if (f != NULL && f(c))
814 r[na++] = i;
815 else
816 b[nb++] = i;
817 }
818 }
819
820 memcpy(r + na, b, nb * sizeof(Move));
821 r[na+nb] = NULLMOVE;
822}
823
824static AlgList *
825new_alglist()
826{
827 AlgList *ret = malloc(sizeof(AlgList));
828
829 ret->len = 0;
830 ret->first = NULL;
831 ret->last = NULL;
832
833 return ret;
834}
835
836static CubeArray *
837new_cubearray(Cube cube, PieceFilter f)
838{
839 CubeArray *arr = malloc(sizeof(CubeArray));
840
841 if (f.epose || f.eposs || f.eposm)
842 arr->ep = malloc(12 * sizeof(int));
843 if (f.eofb)
844 arr->eofb = malloc(12 * sizeof(int));
845 if (f.eorl)
846 arr->eorl = malloc(12 * sizeof(int));
847 if (f.eoud)
848 arr->eoud = malloc(12 * sizeof(int));
849 if (f.cp)
850 arr->cp = malloc(8 * sizeof(int));
851 if (f.coud)
852 arr->coud = malloc(8 * sizeof(int));
853 if (f.corl)
854 arr->corl = malloc(8 * sizeof(int));
855 if (f.cofb)
856 arr->cofb = malloc(8 * sizeof(int));
857 if (f.cpos)
858 arr->cpos = malloc(6 * sizeof(int));
859
860 cube_to_arrays(cube, arr, f);
861
862 return arr;
863}
864
865static int
866perm_sign(int *a, int n)
867{
868 int i, j, ret = 0;
869
870 if (!is_perm(a,n))
871 return -1;
872
873 for (i = 0; i < n; i++)
874 for (j = i+1; j < n; j++)
875 ret += (a[i] > a[j]) ? 1 : 0;
876
877 return ret % 2;
878}
879
880static int
881perm_to_index(int *a, int n)
882{
883 int i, j, c, ret = 0;
884
885 if (!is_perm(a, n))
886 return -1;
887
888 for (i = 0; i < n; i++) {
889 c = 0;
890 for (j = i+1; j < n; j++)
891 c += (a[i] > a[j]) ? 1 : 0;
892 ret += factorial(n-i-1) * c;
893 }
894
895 return ret;
896}
897
898/*
899static int
900powint(int a, int b)
901{
902 if (b < 0)
903 return 0;
904 if (b == 0)
905 return 1;
906
907 if (b % 2)
908 return a * powint(a, b-1);
909 else
910 return powint(a*a, b/2);
911}
912*/
913
914static void
915ptable_set_reached(PruneData *pd, uint64_t ind)
916{
917 uint8_t oldval2 = pd->reached[ind/2];
918 int other = ind % 2 ? oldval2 % 16 : oldval2 / 16;
919
920 pd->reached[ind/2] = ind % 2 ? 16 + other : 16*other + 1;
921}
922
923static void
924ptable_update(PruneData *pd, uint64_t ind, int n)
925{
926 uint8_t oldval2 = pd->ptable[ind/2];
927 int other = ind % 2 ? oldval2 % 16 : oldval2 / 16;
928
929 pd->ptable[ind/2] = ind % 2 ? 16*n + other : 16*other + n;
930 pd->n++;
931}
932
933static void
934push_cachenode(CacheData *cd, Cube c, Alg *alg)
935{
936 CacheNode *node = malloc(sizeof(CacheNode));
937 uint64_t ind0 = cd->index[0](c);
938 int i;
939
940 node->indexval = malloc((cd->nind - 1) * sizeof(uint64_t));
941 for (i = 1; i < cd->nind; i++)
942 node->indexval[i-1] = cd->index[i](c);
943
944 node->sol = inverse_alg(alg);
945 realloc_alg(node->sol, cd->len);
946 node->next = cd->ctable[ind0];
947 cd->ctable[ind0] = node;
948}
949
950static void
951realloc_alg(Alg *alg, int n)
952{
953 if (alg == NULL) {
954 fprintf(stderr, "Error: trying to reallocate NULL alg.\n");
955 return;
956 }
957
958 if (n < alg->len) {
959 fprintf(stderr, "Error: alg too long for reallocation ");
960 fprintf(stderr, "(%d vs %d)\n", alg->len, n);
961 return;
962 }
963
964 if (n > 1000000) {
965 fprintf(stderr, "Warning: very long alg,");
966 fprintf(stderr, "something might go wrong.\n");
967 }
968
969 alg->move = realloc(alg->move, n);
970 alg->inv = realloc(alg->inv, n);
971 alg->allocated = n;
972}
973
974static bool
975read_ctable_file(CacheData *cd)
976{
977 return false;
978}
979
980static bool
981read_mtables_file()
982{
983 FILE *f;
984 char fname[strlen(tabledir)+20];
985 int m, b = sizeof(uint16_t);
986 bool r = true;
987
988 strcpy(fname, tabledir);
989 strcat(fname, "/mtables");
990
991 if ((f = fopen(fname, "rb")) == NULL)
992 return false;
993
994 for (m = 0; m < NMOVES; m++) {
995 r = r && fread(epose_mtable[m], b, me[0], f) == me[0];
996 r = r && fread(eposs_mtable[m], b, me[1], f) == me[1];
997 r = r && fread(eposm_mtable[m], b, me[2], f) == me[2];
998 r = r && fread(eofb_mtable[m], b, me[3], f) == me[3];
999 r = r && fread(eorl_mtable[m], b, me[4], f) == me[4];
1000 r = r && fread(eoud_mtable[m], b, me[5], f) == me[5];
1001 r = r && fread(cp_mtable[m], b, me[6], f) == me[6];
1002 r = r && fread(coud_mtable[m], b, me[7], f) == me[7];
1003 r = r && fread(corl_mtable[m], b, me[8], f) == me[8];
1004 r = r && fread(cofb_mtable[m], b, me[9], f) == me[9];
1005 r = r && fread(cpos_mtable[m], b, me[10], f) == me[10];
1006 }
1007
1008 fclose(f);
1009 return r;
1010}
1011
1012static bool
1013read_ptable_file(PruneData *pd)
1014{
1015 FILE *f;
1016 char fname[strlen(tabledir)+100];
1017 uint64_t r;
1018
1019 strcpy(fname, tabledir);
1020 strcat(fname, "/");
1021 strcat(fname, pd->filename);
1022
1023 if ((f = fopen(fname, "rb")) == NULL)
1024 return false;
1025
1026 r = fread(pd->ptable, sizeof(uint8_t), PTABLESIZE(pd->size), f);
1027 fclose(f);
1028
1029 return r == PTABLESIZE(pd->size);
1030}
1031
1032static bool
1033read_ttables_file()
1034{
1035 FILE *f;
1036 char fname[strlen(tabledir)+20];
1037 int b = sizeof(uint16_t);
1038 bool r = true;
1039 Move m;
1040
1041 strcpy(fname, tabledir);
1042 strcat(fname, "/");
1043 strcat(fname, "ttables");
1044
1045 if ((f = fopen(fname, "rb")) == NULL)
1046 return false;
1047
1048 for (m = 0; m < NTRANS; m++) {
1049 r = r && fread(epose_ttable[m], b, me[0], f) == me[0];
1050 r = r && fread(eposs_ttable[m], b, me[1], f) == me[1];
1051 r = r && fread(eposm_ttable[m], b, me[2], f) == me[2];
1052 r = r && fread(eo_ttable[m], b, me[3], f) == me[3];
1053 r = r && fread(cp_ttable[m], b, me[6], f) == me[6];
1054 r = r && fread(co_ttable[m], b, me[7], f) == me[7];
1055 r = r && fread(cpos_ttable[m], b, me[10], f) == me[10];
1056 r = r && fread(moves_ttable[m], b, me[11], f) == me[11];
1057 }
1058
1059 fclose(f);
1060 return r;
1061}
1062
1063static Cube
1064rotate_via_compose(Trans r, Cube c, PieceFilter f)
1065{
1066 Alg *inv;
1067 static int zero12[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1068 static int zero8[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
1069 static CubeArray ma = {
1070 .ep = ep_mirror,
1071 .eofb = zero12,
1072 .eorl = zero12,
1073 .eoud = zero12,
1074 .cp = cp_mirror,
1075 .coud = zero8,
1076 .corl = zero8,
1077 .cofb = zero8,
1078 .cpos = cpos_mirror
1079 };
1080
1081 Cube ret;
1082
1083 if (r != mirror) {
1084 ret = apply_alg_generic(trans_algs[r], c, f, true);
1085 inv = on_inverse(trans_algs[r]);
1086 ret = apply_alg_generic(inv, ret, f, true);
1087 free_alg(inv);
1088 } else {
1089 ret = move_via_arrays(&ma, (Cube){0}, f);
1090 ret = compose_filtered(c, ret, f);
1091 ret = move_via_arrays(&ma, ret, f);
1092 }
1093
1094 return ret;
1095}
1096
1097static void
1098solve_cd(Cube c, Step s, SolveOptions *opts, DfsData *dd)
1099{
1100 int j, k;
1101 bool flag;
1102 uint64_t ind0;
1103 CacheNode *i;
1104
1105 if (!s.cd->generated)
1106 generate_ctable(s.cd);
1107
1108 ind0 = s.cd->index[0](c);
1109 for (i = s.cd->ctable[ind0];
1110 i != NULL && dd->sols->len < opts->max_solutions;
1111 i = i->next) {
1112 for (j = 1, flag = true; j < s.cd->nind; j++) {
1113 if (s.cd->index[j](c) != i->indexval[j-1]) {
1114 flag = false;
1115 break;
1116 }
1117 }
1118 if (flag) {
1119 for (k = 0; k < s.cd->len; k++)
1120 append_move(dd->current_alg,
1121 i->sol->move[k], dd->niss);
1122 append_alg(dd->sols, dd->current_alg);
1123 if (opts->feedback) {
1124 printf("[cached] ");
1125 print_alg(dd->current_alg, false);
1126 }
1127 }
1128 }
1129}
1130
1131static void
1132solve_dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd)
1133{
1134 Move move, l1 = dd->last1, l2 = dd->last2;
1135 int i, lower_bound;
1136 bool nissbackup = dd->niss;
1137
1138 if (dd->sols->len >= opts->max_solutions)
1139 return;
1140
1141 lower_bound = s.check(c);
1142 if (opts->can_niss && !dd->niss)
1143 lower_bound = MIN(1, lower_bound);
1144
1145 if (dd->current_alg->len + lower_bound > dd->d)
1146 return;
1147
1148 if (lower_bound == 0) {
1149 if (dd->current_alg->len == dd->d) {
1150 append_alg(dd->sols, dd->current_alg);
1151 if (opts->feedback)
1152 print_alg(dd->current_alg, false);
1153 }
1154 return;
1155 }
1156
1157 if (s.cd != NULL && s.cd->len == dd->d - dd->current_alg->len) {
1158 solve_cd(c, s, opts, dd);
1159 } else {
1160 for (i = 0;
1161 dd->sorted_moves[i] != NULLMOVE &&
1162 dd->sols->len < opts->max_solutions;
1163 i++) {
1164 move = dd->sorted_moves[i];
1165 if (allowed_next_move(move, dd)) {
1166 dd->last2 = dd->last1;
1167 dd->last1 = move;
1168 append_move(dd->current_alg, move, dd->niss);
1169 solve_dfs(apply_move(move, c), s, opts, dd);
1170 dd->current_alg->len--;
1171 dd->last2 = l2;
1172 dd->last1 = l1;
1173 }
1174 }
1175 }
1176
1177 if (opts->can_niss && !dd->niss) {
1178 if (dd->current_alg->len == 0 ||
1179 (s.check(apply_move(inverse_move(l1), (Cube){0})))) {
1180 dd->niss = true;
1181 dd->last1 = NULLMOVE;
1182 dd->last2 = NULLMOVE;
1183 solve_dfs(inverse_cube(c), s, opts, dd);
1184 }
1185 }
1186
1187 dd->last1 = l1;
1188 dd->last2 = l2;
1189 dd->niss = nissbackup;
1190}
1191
1192static int
1193subset_to_index(int *a, int n, int k)
1194{
1195 int i, ret = 0;
1196
1197 if (!is_subset(a, n, k))
1198 return binomial(n, k);
1199
1200 for (i = 0; i < n; i++) {
1201 if (k == n-i)
1202 return ret;
1203 if (a[i]) {
1204 ret += binomial(n-i-1, k);
1205 k--;
1206 }
1207 }
1208
1209 return ret;
1210}
1211
1212static void
1213sum_arrays_mod(int *src, int *dst, int n, int m)
1214{
1215 int i;
1216
1217 for (i = 0; i < n; i++)
1218 dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m;
1219}
1220
1221static void
1222swap(int *a, int *b)
1223{
1224 int aux;
1225
1226 aux = *a;
1227 *a = *b;
1228 *b = aux;
1229}
1230
1231static bool
1232write_ctable_file(CacheData *cd)
1233{
1234 return false;
1235}
1236
1237static bool
1238write_mtables_file()
1239{
1240 FILE *f;
1241 char fname[strlen(tabledir)+20];
1242 int m, b = sizeof(uint16_t);
1243 bool r = true;
1244
1245 strcpy(fname, tabledir);
1246 strcat(fname, "/mtables");
1247
1248 if ((f = fopen(fname, "wb")) == NULL)
1249 return false;
1250
1251 for (m = 0; m < NMOVES; m++) {
1252 r = r && fwrite(epose_mtable[m], b, me[0], f) == me[0];
1253 r = r && fwrite(eposs_mtable[m], b, me[1], f) == me[1];
1254 r = r && fwrite(eposm_mtable[m], b, me[2], f) == me[2];
1255 r = r && fwrite(eofb_mtable[m], b, me[3], f) == me[3];
1256 r = r && fwrite(eorl_mtable[m], b, me[4], f) == me[4];
1257 r = r && fwrite(eoud_mtable[m], b, me[5], f) == me[5];
1258 r = r && fwrite(cp_mtable[m], b, me[6], f) == me[6];
1259 r = r && fwrite(coud_mtable[m], b, me[7], f) == me[7];
1260 r = r && fwrite(corl_mtable[m], b, me[8], f) == me[8];
1261 r = r && fwrite(cofb_mtable[m], b, me[9], f) == me[9];
1262 r = r && fwrite(cpos_mtable[m], b, me[10], f) == me[10];
1263 }
1264
1265 fclose(f);
1266 return r;
1267}
1268
1269static bool
1270write_ptable_file(PruneData *pd)
1271{
1272 FILE *f;
1273 char fname[strlen(tabledir)+100];
1274 uint64_t written;
1275
1276 strcpy(fname, tabledir);
1277 strcat(fname, "/");
1278 strcat(fname, pd->filename);
1279
1280 if ((f = fopen(fname, "wb")) == NULL)
1281 return false;
1282
1283 written = fwrite(pd->ptable, sizeof(uint8_t), PTABLESIZE(pd->size), f);
1284 fclose(f);
1285
1286 return written == PTABLESIZE(pd->size);
1287}
1288
1289static bool
1290write_ttables_file()
1291{
1292 FILE *f;
1293 char fname[strlen(tabledir)+20];
1294 bool r = true;
1295 int b = sizeof(uint16_t);
1296 Move m;
1297
1298 strcpy(fname, tabledir);
1299 strcat(fname, "/ttables");
1300
1301 if ((f = fopen(fname, "wb")) == NULL)
1302 return false;
1303
1304 for (m = 0; m < NTRANS; m++) {
1305 r = r && fwrite(epose_ttable[m], b, me[0], f) == me[0];
1306 r = r && fwrite(eposs_ttable[m], b, me[1], f) == me[1];
1307 r = r && fwrite(eposm_ttable[m], b, me[2], f) == me[2];
1308 r = r && fwrite(eo_ttable[m], b, me[3], f) == me[3];
1309 r = r && fwrite(cp_ttable[m], b, me[6], f) == me[6];
1310 r = r && fwrite(co_ttable[m], b, me[7], f) == me[7];
1311 r = r && fwrite(cpos_ttable[m], b, me[10], f) == me[10];
1312 r = r && fwrite(moves_ttable[m], b, me[11], f) == me[11];
1313 }
1314
1315 fclose(f);
1316 return r;
1317}
1318
1319/* Init functions implementation *********************************************/
1320
1321static void
1322init_auxtables()
1323{
1324 Cube c1, c2;
1325 uint64_t ui, uj;
1326 int i, j, k;
1327 bool cij, p1, p2;
1328
1329 for (ui = 0; ui < BINOM12ON4; ui++)
1330 for (uj = 0; uj < BINOM12ON4; uj++)
1331 epos_dependent_aux[ui][uj] = epos_dependent(ui, uj);
1332
1333 for (i = 0; i < NMOVES; i++) {
1334 for (j = 0; j < NMOVES; j++) {
1335 c1 = apply_move(i, apply_move(j, (Cube){0}));
1336 c2 = apply_move(j, apply_move(i, (Cube){0}));
1337 commute[i][j] = equal(c1, c2) && i && j;
1338 }
1339 }
1340
1341 for (i = 0; i < NMOVES; i++) {
1342 for (j = 0; j < NMOVES; j++) {
1343 for (k = 0; k < NMOVES; k++) {
1344 p1 = j && base_move(j) == base_move(k);
1345 p2 = i && base_move(i) == base_move(k);
1346 cij = commute[i][j];
1347 possible_next[i][j][k] = !(p1 || (cij && p2));
1348 }
1349 }
1350 }
1351
1352 for (i = 0; i < NMOVES; i++)
1353 inverse_move_aux[i] = i ? i + 2 - 2*((i-1)%3) : NULLMOVE;
1354
1355 /* Is there a more elegant way? */
1356 inverse_trans_aux[uf] = uf;
1357 inverse_trans_aux[ur] = ul;
1358 inverse_trans_aux[ul] = ur;
1359 inverse_trans_aux[ub] = ub;
1360
1361 inverse_trans_aux[df] = df;
1362 inverse_trans_aux[dr] = dr;
1363 inverse_trans_aux[dl] = dl;
1364 inverse_trans_aux[db] = db;
1365
1366 inverse_trans_aux[rf] = lf;
1367 inverse_trans_aux[rd] = bl;
1368 inverse_trans_aux[rb] = rb;
1369 inverse_trans_aux[ru] = fr;
1370
1371 inverse_trans_aux[lf] = rf;
1372 inverse_trans_aux[ld] = br;
1373 inverse_trans_aux[lb] = lb;
1374 inverse_trans_aux[lu] = fl;
1375
1376 inverse_trans_aux[fu] = fu;
1377 inverse_trans_aux[fr] = ru;
1378 inverse_trans_aux[fd] = bu;
1379 inverse_trans_aux[fl] = lu;
1380
1381 inverse_trans_aux[bu] = fd;
1382 inverse_trans_aux[br] = ld;
1383 inverse_trans_aux[bd] = bd;
1384 inverse_trans_aux[bl] = rd;
1385
1386 inverse_trans_aux[mirror] = mirror;
1387}
1388
1389static void
1390init_environment()
1391{
1392 char *nissydata = getenv("NISSYDATA");
1393 char *localdata = getenv("XDG_DATA_HOME");
1394 char *home = getenv("HOME");
1395 bool read, write;
1396
1397 if (nissydata != NULL) {
1398 tabledir = malloc(strlen(nissydata) * sizeof(char) + 20);
1399 strcpy(tabledir, nissydata);
1400 } else if (localdata != NULL) {
1401 tabledir = malloc(strlen(localdata) * sizeof(char) + 20);
1402 strcpy(tabledir, localdata);
1403 strcat(tabledir, "/nissy");
1404 } else if (home != NULL) {
1405 tabledir = malloc(strlen(home) * sizeof(char) + 20);
1406 strcpy(tabledir, home);
1407 strcat(tabledir, "/.nissy");
1408 }
1409
1410 mkdir(tabledir, 0777);
1411 strcat(tabledir, "/tables");
1412 mkdir(tabledir, 0777);
1413
1414 read = !access(tabledir, R_OK);
1415 write = !access(tabledir, W_OK);
1416
1417 if (!read) {
1418 fprintf(stderr, "Table files cannot be read.\n");
1419 } else if (!write) {
1420 fprintf(stderr, "Data directory not writable: ");
1421 fprintf(stderr, "tables can be loaded, but not saved.\n");
1422 }
1423}
1424
1425static void
1426init_moves() {
1427 Cube c;
1428 CubeArray arrs;
1429 int i;
1430 uint16_t ui;
1431 Move m;
1432
1433 /* Generate all move cycles and flips; I do this regardless */
1434 for (i = 0; i < NMOVES; i++) {
1435 if (i == U || i == x || i == y)
1436 continue;
1437
1438 c = apply_alg_generic(equiv_alg[i], (Cube){0}, pf_all, false);
1439
1440 arrs = (CubeArray) {
1441 edge_cycle[i],
1442 eofb_flipped[i],
1443 eorl_flipped[i],
1444 eoud_flipped[i],
1445 corner_cycle[i],
1446 coud_flipped[i],
1447 corl_flipped[i],
1448 cofb_flipped[i],
1449 center_cycle[i]
1450 };
1451 cube_to_arrays(c, &arrs, pf_all);
1452 }
1453
1454 if (read_mtables_file())
1455 return;
1456
1457 fprintf(stderr, "Cannot load %s, generating it\n", "mtables");
1458
1459 /* Initialize transition tables */
1460 for (m = 0; m < NMOVES; m++) {
1461 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
1462 c = (Cube){ .epose = ui };
1463 c = apply_move_cubearray(m, c, pf_e);
1464 epose_mtable[m][ui] = c.epose;
1465
1466 c = (Cube){ .eposs = ui };
1467 c = apply_move_cubearray(m, c, pf_s);
1468 eposs_mtable[m][ui] = c.eposs;
1469
1470 c = (Cube){ .eposm = ui };
1471 c = apply_move_cubearray(m, c, pf_m);
1472 eposm_mtable[m][ui] = c.eposm;
1473 }
1474 for (ui = 0; ui < POW2TO11; ui++ ) {
1475 c = (Cube){ .eofb = ui };
1476 c = apply_move_cubearray(m, c, pf_eo);
1477 eofb_mtable[m][ui] = c.eofb;
1478
1479 c = (Cube){ .eorl = ui };
1480 c = apply_move_cubearray(m, c, pf_eo);
1481 eorl_mtable[m][ui] = c.eorl;
1482
1483 c = (Cube){ .eoud = ui };
1484 c = apply_move_cubearray(m, c, pf_eo);
1485 eoud_mtable[m][ui] = c.eoud;
1486 }
1487 for (ui = 0; ui < POW3TO7; ui++) {
1488 c = (Cube){ .coud = ui };
1489 c = apply_move_cubearray(m, c, pf_co);
1490 coud_mtable[m][ui] = c.coud;
1491
1492 c = (Cube){ .corl = ui };
1493 c = apply_move_cubearray(m, c, pf_co);
1494 corl_mtable[m][ui] = c.corl;
1495
1496 c = (Cube){ .cofb = ui };
1497 c = apply_move_cubearray(m, c, pf_co);
1498 cofb_mtable[m][ui] = c.cofb;
1499 }
1500 for (ui = 0; ui < FACTORIAL8; ui++) {
1501 c = (Cube){ .cp = ui };
1502 c = apply_move_cubearray(m, c, pf_cp);
1503 cp_mtable[m][ui] = c.cp;
1504 }
1505 for (ui = 0; ui < FACTORIAL6; ui++) {
1506 c = (Cube){ .cpos = ui };
1507 c = apply_move_cubearray(m, c, pf_cpos);
1508 cpos_mtable[m][ui] = c.cpos;
1509 }
1510 }
1511
1512 if (!write_mtables_file())
1513 fprintf(stderr, "Error writing mtables\n");
1514}
1515
1516static void
1517init_moves_aux()
1518{
1519 /* Some standard PieceFilters */
1520 pf_all.epose = true;
1521 pf_all.eposs = true;
1522 pf_all.eposm = true;
1523 pf_all.eofb = true;
1524 pf_all.eorl = true;
1525 pf_all.eoud = true;
1526 pf_all.cp = true;
1527 pf_all.cofb = true;
1528 pf_all.corl = true;
1529 pf_all.coud = true;
1530 pf_all.cpos = true;
1531
1532 pf_4val.epose = true;
1533 pf_4val.eposs = true;
1534 pf_4val.eposm = true;
1535 pf_4val.eofb = true;
1536 pf_4val.coud = true;
1537 pf_4val.cp = true;
1538
1539 pf_epcp.epose = true;
1540 pf_epcp.eposs = true;
1541 pf_epcp.eposm = true;
1542 pf_epcp.cp = true;
1543
1544 pf_cpos.cpos = true;
1545
1546 pf_cp.cp = true;
1547
1548 pf_ep.epose = true;
1549 pf_ep.eposs = true;
1550 pf_ep.eposm = true;
1551
1552 pf_e.epose = true;
1553 pf_s.eposs = true;
1554 pf_m.eposm = true;
1555
1556 pf_eo.eofb = true;
1557 pf_eo.eorl = true;
1558 pf_eo.eoud = true;
1559
1560 pf_co.cofb = true;
1561 pf_co.corl = true;
1562 pf_co.coud = true;
1563
1564 /* Used to convert to and from CubeArray */
1565 epe_solved[0] = FR;
1566 epe_solved[1] = FL;
1567 epe_solved[2] = BL;
1568 epe_solved[3] = BR;
1569
1570 eps_solved[0] = UL;
1571 eps_solved[1] = UR;
1572 eps_solved[2] = DL;
1573 eps_solved[3] = DR;
1574
1575 epm_solved[0] = UF;
1576 epm_solved[1] = UB;
1577 epm_solved[2] = DF;
1578 epm_solved[3] = DB;
1579
1580 /* Table sizes, used for reading and writing files */
1581 me[0] = FACTORIAL12/FACTORIAL8;
1582 me[1] = FACTORIAL12/FACTORIAL8;
1583 me[2] = FACTORIAL12/FACTORIAL8;
1584 me[3] = POW2TO11;
1585 me[4] = POW2TO11;
1586 me[5] = POW2TO11;
1587 me[6] = FACTORIAL8;
1588 me[7] = POW3TO7;
1589 me[8] = POW3TO7;
1590 me[9] = POW3TO7;
1591 me[10] = FACTORIAL6;
1592 me[11] = NMOVES;
1593
1594 /* Cycles *********************/
1595 edge_cycle[U][UF] = UR;
1596 edge_cycle[U][UL] = UF;
1597 edge_cycle[U][UB] = UL;
1598 edge_cycle[U][UR] = UB;
1599 edge_cycle[U][DF] = DF;
1600 edge_cycle[U][DL] = DL;
1601 edge_cycle[U][DB] = DB;
1602 edge_cycle[U][DR] = DR;
1603 edge_cycle[U][FR] = FR;
1604 edge_cycle[U][FL] = FL;
1605 edge_cycle[U][BL] = BL;
1606 edge_cycle[U][BR] = BR;
1607
1608 edge_cycle[x][UF] = DF;
1609 edge_cycle[x][UL] = FL;
1610 edge_cycle[x][UB] = UF;
1611 edge_cycle[x][UR] = FR;
1612 edge_cycle[x][DF] = DB;
1613 edge_cycle[x][DL] = BL;
1614 edge_cycle[x][DB] = UB;
1615 edge_cycle[x][DR] = BR;
1616 edge_cycle[x][FR] = DR;
1617 edge_cycle[x][FL] = DL;
1618 edge_cycle[x][BL] = UL;
1619 edge_cycle[x][BR] = UR;
1620
1621 edge_cycle[y][UF] = UR;
1622 edge_cycle[y][UL] = UF;
1623 edge_cycle[y][UB] = UL;
1624 edge_cycle[y][UR] = UB;
1625 edge_cycle[y][DF] = DR;
1626 edge_cycle[y][DL] = DF;
1627 edge_cycle[y][DB] = DL;
1628 edge_cycle[y][DR] = DB;
1629 edge_cycle[y][FR] = BR;
1630 edge_cycle[y][FL] = FR;
1631 edge_cycle[y][BL] = FL;
1632 edge_cycle[y][BR] = BL;
1633
1634 corner_cycle[U][UFR] = UBR;
1635 corner_cycle[U][UFL] = UFR;
1636 corner_cycle[U][UBL] = UFL;
1637 corner_cycle[U][UBR] = UBL;
1638 corner_cycle[U][DFR] = DFR;
1639 corner_cycle[U][DFL] = DFL;
1640 corner_cycle[U][DBL] = DBL;
1641 corner_cycle[U][DBR] = DBR;
1642
1643 corner_cycle[x][UFR] = DFR;
1644 corner_cycle[x][UFL] = DFL;
1645 corner_cycle[x][UBL] = UFL;
1646 corner_cycle[x][UBR] = UFR;
1647 corner_cycle[x][DFR] = DBR;
1648 corner_cycle[x][DFL] = DBL;
1649 corner_cycle[x][DBL] = UBL;
1650 corner_cycle[x][DBR] = UBR;
1651
1652 corner_cycle[y][UFR] = UBR;
1653 corner_cycle[y][UFL] = UFR;
1654 corner_cycle[y][UBL] = UFL;
1655 corner_cycle[y][UBR] = UBL;
1656 corner_cycle[y][DFR] = DBR;
1657 corner_cycle[y][DFL] = DFR;
1658 corner_cycle[y][DBL] = DFL;
1659 corner_cycle[y][DBR] = DBL;
1660
1661 center_cycle[U][U_center] = U_center;
1662 center_cycle[U][D_center] = D_center;
1663 center_cycle[U][R_center] = R_center;
1664 center_cycle[U][L_center] = L_center;
1665 center_cycle[U][F_center] = F_center;
1666 center_cycle[U][B_center] = B_center;
1667
1668 center_cycle[x][U_center] = F_center;
1669 center_cycle[x][D_center] = B_center;
1670 center_cycle[x][R_center] = R_center;
1671 center_cycle[x][L_center] = L_center;
1672 center_cycle[x][F_center] = D_center;
1673 center_cycle[x][B_center] = U_center;
1674
1675 center_cycle[y][U_center] = U_center;
1676 center_cycle[y][D_center] = D_center;
1677 center_cycle[y][R_center] = B_center;
1678 center_cycle[y][L_center] = F_center;
1679 center_cycle[y][F_center] = R_center;
1680 center_cycle[y][B_center] = L_center;
1681
1682 /* Flipped pieces *************/
1683 eofb_flipped[x][UF] = 1;
1684 eofb_flipped[x][UB] = 1;
1685 eofb_flipped[x][DF] = 1;
1686 eofb_flipped[x][DB] = 1;
1687
1688 eofb_flipped[y][FR] = 1;
1689 eofb_flipped[y][FL] = 1;
1690 eofb_flipped[y][BL] = 1;
1691 eofb_flipped[y][BR] = 1;
1692
1693 eorl_flipped[x][UF] = 1;
1694 eorl_flipped[x][UL] = 1;
1695 eorl_flipped[x][UB] = 1;
1696 eorl_flipped[x][UR] = 1;
1697 eorl_flipped[x][DF] = 1;
1698 eorl_flipped[x][DL] = 1;
1699 eorl_flipped[x][DB] = 1;
1700 eorl_flipped[x][DR] = 1;
1701 eorl_flipped[x][FR] = 1;
1702 eorl_flipped[x][FL] = 1;
1703 eorl_flipped[x][BL] = 1;
1704 eorl_flipped[x][BR] = 1;
1705
1706 eorl_flipped[y][FR] = 1;
1707 eorl_flipped[y][FL] = 1;
1708 eorl_flipped[y][BL] = 1;
1709 eorl_flipped[y][BR] = 1;
1710
1711 eoud_flipped[U][UF] = 1;
1712 eoud_flipped[U][UL] = 1;
1713 eoud_flipped[U][UB] = 1;
1714 eoud_flipped[U][UR] = 1;
1715
1716 eoud_flipped[x][UF] = 1;
1717 eoud_flipped[x][UB] = 1;
1718 eoud_flipped[x][DF] = 1;
1719 eoud_flipped[x][DB] = 1;
1720
1721 eoud_flipped[y][UF] = 1;
1722 eoud_flipped[y][UL] = 1;
1723 eoud_flipped[y][UB] = 1;
1724 eoud_flipped[y][UR] = 1;
1725 eoud_flipped[y][DF] = 1;
1726 eoud_flipped[y][DL] = 1;
1727 eoud_flipped[y][DB] = 1;
1728 eoud_flipped[y][DR] = 1;
1729 eoud_flipped[y][FR] = 1;
1730 eoud_flipped[y][FL] = 1;
1731 eoud_flipped[y][BL] = 1;
1732 eoud_flipped[y][BR] = 1;
1733
1734 coud_flipped[x][UFR] = 2;
1735 coud_flipped[x][UFL] = 1;
1736 coud_flipped[x][UBR] = 1;
1737 coud_flipped[x][UBL] = 2;
1738 coud_flipped[x][DFR] = 1;
1739 coud_flipped[x][DFL] = 2;
1740 coud_flipped[x][DBR] = 2;
1741 coud_flipped[x][DBL] = 1;
1742
1743 corl_flipped[U][UFR] = 1;
1744 corl_flipped[U][UFL] = 2;
1745 corl_flipped[U][UBL] = 1;
1746 corl_flipped[U][UBR] = 2;
1747
1748 corl_flipped[y][UFR] = 1;
1749 corl_flipped[y][UFL] = 2;
1750 corl_flipped[y][UBL] = 1;
1751 corl_flipped[y][UBR] = 2;
1752 corl_flipped[y][DFR] = 2;
1753 corl_flipped[y][DFL] = 1;
1754 corl_flipped[y][DBL] = 2;
1755 corl_flipped[y][DBR] = 1;
1756
1757 cofb_flipped[U][UFR] = 2;
1758 cofb_flipped[U][UFL] = 1;
1759 cofb_flipped[U][UBL] = 2;
1760 cofb_flipped[U][UBR] = 1;
1761
1762 cofb_flipped[x][UFR] = 1;
1763 cofb_flipped[x][UFL] = 2;
1764 cofb_flipped[x][UBL] = 1;
1765 cofb_flipped[x][UBR] = 2;
1766 cofb_flipped[x][DFR] = 2;
1767 cofb_flipped[x][DFL] = 1;
1768 cofb_flipped[x][DBL] = 2;
1769 cofb_flipped[x][DBR] = 1;
1770
1771 cofb_flipped[y][UFR] = 2;
1772 cofb_flipped[y][UFL] = 1;
1773 cofb_flipped[y][UBL] = 2;
1774 cofb_flipped[y][UBR] = 1;
1775 cofb_flipped[y][DFR] = 1;
1776 cofb_flipped[y][DFL] = 2;
1777 cofb_flipped[y][DBL] = 1;
1778 cofb_flipped[y][DBR] = 2;
1779
1780 /* Equivalent moves ***********/
1781 equiv_alg[NULLMOVE] = new_alg("");
1782
1783 equiv_alg[U] = new_alg(" U ");
1784 equiv_alg[U2] = new_alg(" UU ");
1785 equiv_alg[U3] = new_alg(" UUU ");
1786 equiv_alg[D] = new_alg(" xx U xx ");
1787 equiv_alg[D2] = new_alg(" xx UU xx ");
1788 equiv_alg[D3] = new_alg(" xx UUU xx ");
1789 equiv_alg[R] = new_alg(" yx U xxxyyy ");
1790 equiv_alg[R2] = new_alg(" yx UU xxxyyy ");
1791 equiv_alg[R3] = new_alg(" yx UUU xxxyyy ");
1792 equiv_alg[L] = new_alg(" yyyx U xxxy ");
1793 equiv_alg[L2] = new_alg(" yyyx UU xxxy ");
1794 equiv_alg[L3] = new_alg(" yyyx UUU xxxy ");
1795 equiv_alg[F] = new_alg(" x U xxx ");
1796 equiv_alg[F2] = new_alg(" x UU xxx ");
1797 equiv_alg[F3] = new_alg(" x UUU xxx ");
1798 equiv_alg[B] = new_alg(" xxx U x ");
1799 equiv_alg[B2] = new_alg(" xxx UU x ");
1800 equiv_alg[B3] = new_alg(" xxx UUU x ");
1801
1802 equiv_alg[Uw] = new_alg(" xx U xx y ");
1803 equiv_alg[Uw2] = new_alg(" xx UU xx yy ");
1804 equiv_alg[Uw3] = new_alg(" xx UUU xx yyy ");
1805 equiv_alg[Dw] = new_alg(" U yyy ");
1806 equiv_alg[Dw2] = new_alg(" UU yy ");
1807 equiv_alg[Dw3] = new_alg(" UUU y ");
1808 equiv_alg[Rw] = new_alg(" yyyx U xxxy x ");
1809 equiv_alg[Rw2] = new_alg(" yyyx UU xxxy xx ");
1810 equiv_alg[Rw3] = new_alg(" yyyx UUU xxxy xxx ");
1811 equiv_alg[Lw] = new_alg(" yx U xxxyyy xxx ");
1812 equiv_alg[Lw2] = new_alg(" yx UU xxxyyy xx ");
1813 equiv_alg[Lw3] = new_alg(" yx UUU xxxyyy x ");
1814 equiv_alg[Fw] = new_alg(" xxx U x yxxxyyy ");
1815 equiv_alg[Fw2] = new_alg(" xxx UU x yxxyyy ");
1816 equiv_alg[Fw3] = new_alg(" xxx UUU x yxyyy ");
1817 equiv_alg[Bw] = new_alg(" x U xxx yxyyy ");
1818 equiv_alg[Bw2] = new_alg(" x UU xxx yxxyyy ");
1819 equiv_alg[Bw3] = new_alg(" x UUU xxx yxxxyyy ");
1820
1821 equiv_alg[M] = new_alg(" yx U xx UUU yxyyy ");
1822 equiv_alg[M2] = new_alg(" yx UU xx UU xxxy ");
1823 equiv_alg[M3] = new_alg(" yx UUU xx U yxxxy ");
1824 equiv_alg[S] = new_alg(" x UUU xx U yyyx ");
1825 equiv_alg[S2] = new_alg(" x UU xx UU yyx ");
1826 equiv_alg[S3] = new_alg(" x U xx UUU yx ");
1827 equiv_alg[E] = new_alg(" U xx UUU xxyyy ");
1828 equiv_alg[E2] = new_alg(" UU xx UU xxyy ");
1829 equiv_alg[E3] = new_alg(" UUU xx U xxy ");
1830
1831 equiv_alg[x] = new_alg(" x ");
1832 equiv_alg[x2] = new_alg(" xx ");
1833 equiv_alg[x3] = new_alg(" xxx ");
1834 equiv_alg[y] = new_alg(" y ");
1835 equiv_alg[y2] = new_alg(" yy ");
1836 equiv_alg[y3] = new_alg(" yyy ");
1837 equiv_alg[z] = new_alg(" yyy x y ");
1838 equiv_alg[z2] = new_alg(" yy xx ");
1839 equiv_alg[z3] = new_alg(" y x yyy ");
1840}
1841
1842static void
1843init_strings()
1844{
1845 strcpy(move_string [NULLMOVE], "-" );
1846 strcpy(move_string [U], "U" );
1847 strcpy(move_string [U2], "U2" );
1848 strcpy(move_string [U3], "U\'" );
1849 strcpy(move_string [D], "D" );
1850 strcpy(move_string [D2], "D2" );
1851 strcpy(move_string [D3], "D\'" );
1852 strcpy(move_string [R], "R" );
1853 strcpy(move_string [R2], "R2" );
1854 strcpy(move_string [R3], "R\'" );
1855 strcpy(move_string [L], "L" );
1856 strcpy(move_string [L2], "L2" );
1857 strcpy(move_string [L3], "L\'" );
1858 strcpy(move_string [F], "F" );
1859 strcpy(move_string [F2], "F2" );
1860 strcpy(move_string [F3], "F\'" );
1861 strcpy(move_string [B], "B" );
1862 strcpy(move_string [B2], "B2" );
1863 strcpy(move_string [B3], "B\'" );
1864 strcpy(move_string [Uw], "Uw" );
1865 strcpy(move_string [Uw2], "Uw2" );
1866 strcpy(move_string [Uw3], "Uw\'" );
1867 strcpy(move_string [Dw], "Dw" );
1868 strcpy(move_string [Dw2], "Dw2" );
1869 strcpy(move_string [Dw3], "Dw\'" );
1870 strcpy(move_string [Rw], "Rw" );
1871 strcpy(move_string [Rw2], "Rw2" );
1872 strcpy(move_string [Rw3], "Rw\'" );
1873 strcpy(move_string [Lw], "Lw" );
1874 strcpy(move_string [Lw2], "Lw2" );
1875 strcpy(move_string [Lw3], "Lw\'" );
1876 strcpy(move_string [Fw], "Fw" );
1877 strcpy(move_string [Fw2], "Fw2" );
1878 strcpy(move_string [Fw3], "Fw\'" );
1879 strcpy(move_string [Bw], "Bw" );
1880 strcpy(move_string [Bw2], "Bw2" );
1881 strcpy(move_string [Bw3], "Bw\'" );
1882 strcpy(move_string [M], "M" );
1883 strcpy(move_string [M2], "M2" );
1884 strcpy(move_string [M3], "M\'" );
1885 strcpy(move_string [S], "S" );
1886 strcpy(move_string [S2], "S2" );
1887 strcpy(move_string [S3], "S\'" );
1888 strcpy(move_string [E], "E" );
1889 strcpy(move_string [E2], "E2" );
1890 strcpy(move_string [E3], "E\'" );
1891 strcpy(move_string [x], "x" );
1892 strcpy(move_string [x2], "x2" );
1893 strcpy(move_string [x3], "x\'" );
1894 strcpy(move_string [y], "y" );
1895 strcpy(move_string [y2], "y2" );
1896 strcpy(move_string [y3], "y\'" );
1897 strcpy(move_string [z], "z" );
1898 strcpy(move_string [z2], "z2" );
1899 strcpy(move_string [z3], "z\'" );
1900
1901 strcpy(edge_string [UF], "UF" );
1902 strcpy(edge_string [UL], "UL" );
1903 strcpy(edge_string [UB], "UB" );
1904 strcpy(edge_string [UR], "UR" );
1905 strcpy(edge_string [DF], "DF" );
1906 strcpy(edge_string [DL], "DL" );
1907 strcpy(edge_string [DB], "DB" );
1908 strcpy(edge_string [DR], "DR" );
1909 strcpy(edge_string [FR], "FR" );
1910 strcpy(edge_string [FL], "FL" );
1911 strcpy(edge_string [BL], "BL" );
1912 strcpy(edge_string [BR], "BR" );
1913
1914 strcpy(corner_string [UFR], "UFR" );
1915 strcpy(corner_string [UFL], "UFL" );
1916 strcpy(corner_string [UBL], "UBL" );
1917 strcpy(corner_string [UBR], "UBR" );
1918 strcpy(corner_string [DFR], "DFR" );
1919 strcpy(corner_string [DFL], "DFL" );
1920 strcpy(corner_string [DBL], "DBL" );
1921 strcpy(corner_string [DBR], "DBR" );
1922
1923 strcpy(center_string [U_center], "U" );
1924 strcpy(center_string [D_center], "D" );
1925 strcpy(center_string [R_center], "R" );
1926 strcpy(center_string [L_center], "L" );
1927 strcpy(center_string [F_center], "F" );
1928 strcpy(center_string [B_center], "B" );
1929}
1930
1931static void
1932init_trans() {
1933 Cube aux, cube, c[3];
1934 CubeArray epcp;
1935 int eparr[12], eoarr[12];
1936 int cparr[8], coarr[8];
1937 int i;
1938 bool b1, b2, b3;
1939 uint16_t ui;
1940 Move mi, move;
1941 Trans m;
1942
1943 /* Compute sources */
1944 for (i = 0; i < NTRANS; i++) {
1945 if (i == mirror)
1946 cube = (Cube){0};
1947 else
1948 cube = apply_alg(trans_algs[i], (Cube){0});
1949
1950 epose_source[i] = edge_slice(edge_at(cube, FR));
1951 eposs_source[i] = edge_slice(edge_at(cube, UR));
1952 eposm_source[i] = edge_slice(edge_at(cube, UF));
1953 eofb_source[i] = center_at(cube, F_center)/2;
1954 eorl_source[i] = center_at(cube, R_center)/2;
1955 eoud_source[i] = center_at(cube, U_center)/2;
1956 coud_source[i] = center_at(cube, U_center)/2;
1957 cofb_source[i] = center_at(cube, F_center)/2;
1958 corl_source[i] = center_at(cube, R_center)/2;
1959 }
1960
1961 if (read_ttables_file())
1962 return;
1963
1964 fprintf(stderr, "Cannot load %s, generating it\n", "ttables");
1965
1966 /* Initialize tables */
1967 for (m = 0; m < NTRANS; m++) {
1968 if (m == mirror) {
1969 memcpy(eparr, ep_mirror, 12 * sizeof(int));
1970 memcpy(cparr, cp_mirror, 8 * sizeof(int));
1971 } else {
1972 epcp = (CubeArray){ .ep = eparr, .cp = cparr };
1973 cube = apply_alg(trans_algs[m], (Cube){0});
1974 cube_to_arrays(cube, &epcp, pf_epcp);
1975 }
1976
1977 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
1978 c[0] = admissible_ep((Cube){ .epose = ui }, pf_e);
1979 c[1] = admissible_ep((Cube){ .eposs = ui }, pf_s);
1980 c[2] = admissible_ep((Cube){ .eposm = ui }, pf_m);
1981
1982 cube = rotate_via_compose(m,c[epose_source[m]],pf_ep);
1983 epose_ttable[m][ui] = cube.epose;
1984
1985 cube = rotate_via_compose(m,c[eposs_source[m]],pf_ep);
1986 eposs_ttable[m][ui] = cube.eposs;
1987
1988 cube = rotate_via_compose(m,c[eposm_source[m]],pf_ep);
1989 eposm_ttable[m][ui] = cube.eposm;
1990 }
1991 for (ui = 0; ui < POW2TO11; ui++ ) {
1992 int_to_sum_zero_array(ui, 2, 12, eoarr);
1993 apply_permutation(eparr, eoarr, 12);
1994 eo_ttable[m][ui] = digit_array_to_int(eoarr, 11, 2);
1995 }
1996 for (ui = 0; ui < POW3TO7; ui++) {
1997 int_to_sum_zero_array(ui, 3, 8, coarr);
1998 apply_permutation(cparr, coarr, 8);
1999 co_ttable[m][ui] = digit_array_to_int(coarr, 7, 3);
2000 if (m == mirror)
2001 co_ttable[m][ui] =
2002 invert_digits(co_ttable[m][ui], 3, 7);
2003 }
2004 for (ui = 0; ui < FACTORIAL8; ui++) {
2005 cube = (Cube){ .cp = ui };
2006 cube = rotate_via_compose(m, cube, pf_cp);
2007 cp_ttable[m][ui] = cube.cp;
2008 }
2009 for (ui = 0; ui < FACTORIAL6; ui++) {
2010 cube = (Cube){ .cpos = ui };
2011 cube = rotate_via_compose(m, cube, pf_cpos);
2012 cpos_ttable[m][ui] = cube.cpos;
2013 }
2014 for (mi = 0; mi < NMOVES; mi++) {
2015 if (m == mirror) {
2016 b1 = (mi >= U && mi <= Bw3);
2017 b2 = (mi >= S && mi <= E3);
2018 b3 = (mi >= x && mi <= z3);
2019 if (b1 || b2 || b3)
2020 moves_ttable[m][mi] =
2021 inverse_move_aux[mi];
2022 else
2023 moves_ttable[m][mi] = mi;
2024
2025 if ((mi-1)/3==(R-1)/3 || (mi-1)/3==(Rw-1)/3)
2026 moves_ttable[m][mi] += 3;
2027 if ((mi-1)/3==(L-1)/3 || (mi-1)/3==(L2-1)/3)
2028 moves_ttable[m][mi] -= 3;
2029 } else {
2030 aux = apply_trans(m, apply_move(mi,(Cube){0}));
2031 for (move = 0; move < NMOVES; move++) {
2032 cube = apply_move(
2033 inverse_move_aux[move], aux);
2034 if (is_solved(cube, false))
2035 moves_ttable[m][mi] = move;
2036 }
2037 }
2038 }
2039 }
2040
2041 if (!write_ttables_file())
2042 fprintf(stderr, "Error writing ttables\n");
2043}
2044
2045static void
2046init_trans_aux()
2047{
2048 ep_mirror[UF] = UF;
2049 ep_mirror[UL] = UR;
2050 ep_mirror[UB] = UB;
2051 ep_mirror[UR] = UL;
2052 ep_mirror[DF] = DF;
2053 ep_mirror[DL] = DR;
2054 ep_mirror[DB] = DB;
2055 ep_mirror[DR] = DL;
2056 ep_mirror[FR] = FL;
2057 ep_mirror[FL] = FR;
2058 ep_mirror[BR] = BL;
2059 ep_mirror[BL] = BR;
2060
2061 cp_mirror[UFR] = UFL;
2062 cp_mirror[UFL] = UFR;
2063 cp_mirror[UBL] = UBR;
2064 cp_mirror[UBR] = UBL;
2065 cp_mirror[DFR] = DFL;
2066 cp_mirror[DFL] = DFR;
2067 cp_mirror[DBL] = DBR;
2068 cp_mirror[DBR] = DBL;
2069
2070 cpos_mirror[U_center] = U_center;
2071 cpos_mirror[D_center] = D_center;
2072 cpos_mirror[R_center] = L_center;
2073 cpos_mirror[L_center] = R_center;
2074 cpos_mirror[F_center] = F_center;
2075 cpos_mirror[B_center] = B_center;
2076
2077 /* Is there a more elegant way? */
2078 trans_algs[uf] = new_alg("");
2079 trans_algs[ur] = new_alg("y");
2080 trans_algs[ub] = new_alg("y2");
2081 trans_algs[ul] = new_alg("y3");
2082
2083 trans_algs[df] = new_alg("z2");
2084 trans_algs[dr] = new_alg("y z2");
2085 trans_algs[db] = new_alg("x2");
2086 trans_algs[dl] = new_alg("y3 z2");
2087
2088 trans_algs[rf] = new_alg("z3");
2089 trans_algs[rd] = new_alg("z3 y");
2090 trans_algs[rb] = new_alg("z3 y2");
2091 trans_algs[ru] = new_alg("z3 y3");
2092
2093 trans_algs[lf] = new_alg("z");
2094 trans_algs[ld] = new_alg("z y3");
2095 trans_algs[lb] = new_alg("z y2");
2096 trans_algs[lu] = new_alg("z y");
2097
2098 trans_algs[fu] = new_alg("x y2");
2099 trans_algs[fr] = new_alg("x y");
2100 trans_algs[fd] = new_alg("x");
2101 trans_algs[fl] = new_alg("x y3");
2102
2103 trans_algs[bu] = new_alg("x3");
2104 trans_algs[br] = new_alg("x3 y");
2105 trans_algs[bd] = new_alg("x3 y2");
2106 trans_algs[bl] = new_alg("x3 y3");
2107}
2108
2109
2110/* Public functions implementation *******************************************/
2111
2112Cube
2113apply_alg(Alg *alg, Cube cube)
2114{
2115 return apply_alg_generic(alg, cube, pf_all, true);
2116}
2117
2118Cube
2119apply_move(Move m, Cube cube)
2120{
2121 return (Cube) {
2122 .epose = epose_mtable[m][cube.epose],
2123 .eposs = eposs_mtable[m][cube.eposs],
2124 .eposm = eposm_mtable[m][cube.eposm],
2125 .eofb = eofb_mtable[m][cube.eofb],
2126 .eorl = eorl_mtable[m][cube.eorl],
2127 .eoud = eoud_mtable[m][cube.eoud],
2128 .coud = coud_mtable[m][cube.coud],
2129 .cofb = cofb_mtable[m][cube.cofb],
2130 .corl = corl_mtable[m][cube.corl],
2131 .cp = cp_mtable[m][cube.cp],
2132 .cpos = cpos_mtable[m][cube.cpos]
2133 };
2134}
2135
2136Cube
2137apply_trans(Trans t, Cube cube)
2138{
2139 uint16_t aux_epos[3] = { cube.epose, cube.eposs, cube.eposm };
2140 uint16_t aux_eo[3] = { cube.eoud, cube.eorl, cube.eofb };
2141 uint16_t aux_co[3] = { cube.coud, cube.corl, cube.cofb };
2142
2143 return (Cube) {
2144 .epose = epose_ttable[t][aux_epos[epose_source[t]]],
2145 .eposs = eposs_ttable[t][aux_epos[eposs_source[t]]],
2146 .eposm = eposm_ttable[t][aux_epos[eposm_source[t]]],
2147 .eofb = eo_ttable[t][aux_eo[eofb_source[t]]],
2148 .eorl = eo_ttable[t][aux_eo[eorl_source[t]]],
2149 .eoud = eo_ttable[t][aux_eo[eoud_source[t]]],
2150 .coud = co_ttable[t][aux_co[coud_source[t]]],
2151 .corl = co_ttable[t][aux_co[corl_source[t]]],
2152 .cofb = co_ttable[t][aux_co[cofb_source[t]]],
2153 .cp = cp_ttable[t][cube.cp],
2154 .cpos = cpos_ttable[t][cube.cpos]
2155 };
2156}
2157
2158Move
2159base_move(Move m)
2160{
2161 if (m == NULLMOVE)
2162 return NULLMOVE;
2163 else
2164 return m - (m-1)%3;
2165}
2166
2167/* TODO: this has to be changed using pre-computations */
2168bool
2169block_solved(Cube cube, Block block)
2170{
2171 CubeArray *arr = new_cubearray(cube, pf_all);
2172 int i;
2173 bool ret = true;
2174
2175 for (i = 0; i < 12; i++)
2176 ret = ret && !(block.edge[i] && (arr->ep[i] != i || arr->eofb[i]));
2177 for (i = 0; i < 8; i++)
2178 ret = ret && !(block.corner[i] && (arr->cp[i] != i || arr->coud[i]));
2179 for (i = 0; i < 6; i++)
2180 ret = ret && !(block.center[i] && arr->cpos[i] != i);
2181
2182 free_cubearray(arr, pf_all);
2183
2184 return ret;
2185}
2186
2187Center
2188center_at(Cube cube, Center c)
2189{
2190 int ret;
2191 CubeArray *arr = new_cubearray(cube, pf_cpos);
2192
2193 ret = arr->cpos[c];
2194 free_cubearray(arr, pf_cpos);
2195
2196 return ret;
2197}
2198
2199Cube
2200compose(Cube c2, Cube c1)
2201{
2202 return compose_filtered(c2, c1, pf_all);
2203}
2204
2205Corner
2206corner_at(Cube cube, Corner c)
2207{
2208 int ret;
2209 CubeArray *arr = new_cubearray(cube, pf_cp);
2210
2211 ret = arr->cp[c];
2212 free_cubearray(arr, pf_cp);
2213
2214 return ret;
2215}
2216
2217Edge
2218edge_at(Cube cube, Edge e)
2219{
2220 int ret;
2221 CubeArray *arr = new_cubearray(cube, pf_ep);
2222
2223 ret = arr->ep[e];
2224 free_cubearray(arr, pf_ep);
2225
2226 return ret;
2227}
2228
2229uint64_t
2230epos_dependent_cube(Cube c)
2231{
2232 return epos_dependent_aux[c.eposs/FACTORIAL4][c.epose/FACTORIAL4];
2233}
2234
2235bool
2236equal(Cube c1, Cube c2)
2237{
2238 return c1.eofb == c2.eofb &&
2239 c1.epose == c2.epose &&
2240 c1.eposs == c2.eposs &&
2241 c1.eposm == c2.eposm &&
2242 c1.coud == c2.coud &&
2243 c1.cp == c2.cp &&
2244 c1.cpos == c2.cpos;
2245}
2246
2247void
2248generate_ctable(CacheData *cd)
2249{
2250 uint64_t i;
2251 DfsData dd = {
2252 .d = cd->len,
2253 .last1 = NULLMOVE,
2254 .last2 = NULLMOVE,
2255 .current_alg = new_alg("")
2256 };
2257
2258 if (cd->generated)
2259 return;
2260
2261 /* TODO: check if memory is enough, otherwise maybe crash gracefully? */
2262 cd->ctable = malloc(cd->maxind0 * sizeof(CacheNode *));
2263 for (i = 0; i < cd->maxind0; i++)
2264 cd->ctable[i] = NULL;
2265
2266 if (read_ctable_file(cd)) {
2267 cd->generated = true;
2268 return;
2269 }
2270
2271 fprintf(stderr, "Cannot load %s, generating it\n", cd->filename);
2272
2273 moveset_to_list(cd->moveset, NULL, dd.sorted_moves);
2274 movelist_to_position(dd.sorted_moves, dd.move_position);
2275
2276 generate_ctable_dfs((Cube){0}, cd, &dd);
2277
2278 if (!write_ctable_file(cd))
2279 fprintf(stderr, "Error writing ctable file\n");
2280
2281 cd->generated = true;
2282}
2283
2284void
2285generate_ptable(PruneData *pd)
2286{
2287 uint64_t j;
2288 DfsData dd = {
2289 .m = 0,
2290 .last1 = NULLMOVE,
2291 .last2 = NULLMOVE
2292 };
2293
2294 if (pd->generated)
2295 return;
2296
2297 /* TODO: check if memory is enough, otherwise maybe crash gracefully? */
2298 pd->ptable = malloc(PTABLESIZE(pd->size) * sizeof(uint8_t));
2299
2300 if (read_ptable_file(pd)) {
2301 pd->generated = true;
2302 return;
2303 }
2304
2305 fprintf(stderr, "Cannot load %s, generating it\n", pd->filename);
2306
2307 /* We use 4 bits per value, so any distance >= 15 is set to 15 */
2308 for (j = 0; j < pd->size; j++)
2309 ptable_update(pd, j, 15);
2310
2311 moveset_to_list(pd->moveset, NULL, dd.sorted_moves);
2312 movelist_to_position(dd.sorted_moves, dd.move_position);
2313
2314 pd->reached = malloc(PTABLESIZE(pd->size) * sizeof(uint8_t));
2315 for (dd.d = 0, pd->n = 0; dd.d < 15 && pd->n < pd->size; dd.d++) {
2316 memset(pd->reached, 0, PTABLESIZE(pd->size)*sizeof(uint8_t));
2317 generate_ptable_dfs((Cube){0}, pd, &dd);
2318 fprintf(stderr, "Depth %d completed, generated %lu/%lu\n",
2319 dd.d, pd->n, pd->size);
2320 }
2321
2322 if (!write_ptable_file(pd))
2323 fprintf(stderr, "Error writing ptable file\n");
2324
2325 pd->generated = true;
2326 free(pd->reached);
2327}
2328
2329Cube
2330inverse_cube(Cube cube)
2331{
2332 CubeArray *arr = new_cubearray(cube, pf_all);
2333 CubeArray *inv = new_cubearray((Cube){0}, pf_all);
2334 Cube ret;
2335 int i;
2336
2337 for (i = 0; i < 12; i++) {
2338 inv->ep[arr->ep[i]] = i;
2339 inv->eofb[arr->ep[i]] = arr->eofb[i];
2340 inv->eorl[arr->ep[i]] = arr->eorl[i];
2341 inv->eoud[arr->ep[i]] = arr->eoud[i];
2342 }
2343
2344 for (i = 0; i < 8; i++) {
2345 inv->cp[arr->cp[i]] = i;
2346 inv->coud[arr->cp[i]] = (3 - arr->coud[i]) % 3;
2347 inv->corl[arr->cp[i]] = (3 - arr->corl[i]) % 3;
2348 inv->cofb[arr->cp[i]] = (3 - arr->cofb[i]) % 3;
2349 }
2350
2351 for (int i = 0; i < 6; i++)
2352 inv->cpos[arr->cpos[i]] = i;
2353
2354 ret = arrays_to_cube(inv, pf_all);
2355 free_cubearray(arr, pf_all);
2356 free_cubearray(inv, pf_all);
2357
2358 return ret;
2359}
2360
2361Move
2362inverse_move(Move m)
2363{
2364 return inverse_move_aux[m];
2365}
2366
2367Trans
2368inverse_trans(Trans t)
2369{
2370 return inverse_trans_aux[t];
2371}
2372
2373bool
2374is_admissible(Cube cube)
2375{
2376 /* TODO: this should check consistency of different orientations */
2377 /* TODO: check that centers are opposite and admissible */
2378
2379 CubeArray *a = new_cubearray(cube, pf_all);
2380 int parity;
2381 bool perm;
2382
2383 perm = is_perm(a->ep, 12) &&
2384 is_perm(a->cp, 8) &&
2385 is_perm(a->cpos, 6);
2386 parity = perm_sign(a->ep, 12) +
2387 perm_sign(a->cp, 8) +
2388 perm_sign(a->cpos, 6);
2389
2390 return perm && parity % 2 == 0;
2391}
2392
2393bool
2394is_solved(Cube cube, bool reorient)
2395{
2396 Trans i;
2397
2398 if (reorient)
2399 for (i = 0; i < NROTATIONS; i++)
2400 if (is_solved(apply_alg(trans_algs[i],cube), false))
2401 return true;
2402
2403 return equal(cube, (Cube){0});
2404}
2405
2406int
2407piece_orientation(Cube cube, int piece, char *orientation)
2408{
2409 int arr[12], n, b;
2410 uint16_t x;
2411
2412 if (!strcmp(orientation, "eofb")) {
2413 x = cube.eofb;
2414 n = 12;
2415 b = 2;
2416 } else if (!strcmp(orientation, "eorl")) {
2417 x = cube.eorl;
2418 n = 12;
2419 b = 2;
2420 } else if (!strcmp(orientation, "eoud")) {
2421 x = cube.eoud;
2422 n = 12;
2423 b = 2;
2424 } else if (!strcmp(orientation, "coud")) {
2425 x = cube.coud;
2426 n = 8;
2427 b = 3;
2428 } else if (!strcmp(orientation, "corl")) {
2429 x = cube.corl;
2430 n = 8;
2431 b = 3;
2432 } else if (!strcmp(orientation, "cofb")) {
2433 x = cube.cofb;
2434 n = 8;
2435 b = 3;
2436 } else {
2437 return -1;
2438 }
2439
2440 int_to_sum_zero_array(x, b, n, arr);
2441 if (piece < n)
2442 return arr[piece];
2443
2444 return -1;
2445}
2446
2447void
2448print_cube(Cube cube)
2449{
2450 CubeArray *arr = new_cubearray(cube, pf_all);
2451
2452 for (int i = 0; i < 12; i++)
2453 printf(" %s ", edge_string[arr->ep[i]]);
2454 printf("\n");
2455
2456 for (int i = 0; i < 12; i++)
2457 printf(" %c ", arr->eofb[i] + '0');
2458 printf("\n");
2459
2460 for (int i = 0; i < 8; i++)
2461 printf("%s ", corner_string[arr->cp[i]]);
2462 printf("\n");
2463
2464 for (int i = 0; i < 8; i++)
2465 printf(" %c ", arr->coud[i] + '0');
2466 printf("\n");
2467
2468 for (int i = 0; i < 6; i++)
2469 printf(" %s ", center_string[arr->cpos[i]]);
2470 printf("\n");
2471
2472 free_cubearray(arr, pf_all);
2473}
2474
2475Cube
2476random_cube()
2477{
2478 CubeArray *arr = new_cubearray((Cube){0}, pf_4val);
2479 Cube ret;
2480 int ep, cp, eo, co;
2481
2482 ep = rand() % FACTORIAL12;
2483 cp = rand() % FACTORIAL8;
2484 eo = rand() % POW2TO11;
2485 co = rand() % POW3TO7;
2486
2487 index_to_perm(ep, 12, arr->ep);
2488 index_to_perm(cp, 8, arr->cp);
2489 int_to_sum_zero_array(eo, 2, 12, arr->eofb);
2490 int_to_sum_zero_array(co, 3, 8, arr->coud);
2491
2492 if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8))
2493 swap(&(arr->ep[0]), &(arr->ep[1]));
2494
2495 ret = arrays_to_cube(arr, pf_4val);
2496 free_cubearray(arr, pf_4val);
2497
2498 return ret;
2499}
2500
2501AlgList *
2502solve(Cube cube, Step step, SolveOptions *opts)
2503{
2504 AlgListNode *node;
2505 AlgList *sols = new_alglist();
2506 Cube c = apply_trans(opts->pre_trans, cube);
2507 DfsData dd = {
2508 .m = 0,
2509 .niss = false,
2510 .last1 = NULLMOVE,
2511 .last2 = NULLMOVE,
2512 .sols = sols,
2513 .current_alg = new_alg("")
2514 };
2515
2516 if (step.ready != NULL && !step.ready(c)) {
2517 fprintf(stderr, "Cube not ready for solving step\n");
2518 return sols;
2519 }
2520
2521 moveset_to_list(step.moveset, step.check, dd.sorted_moves);
2522 movelist_to_position(dd.sorted_moves, dd.move_position);
2523
2524 for (dd.d = MAX(opts->min_moves, step.check(c));
2525 dd.d <= opts->max_moves && !(sols->len && opts->optimal_only);
2526 dd.d++) {
2527 if (opts->feedback)
2528 fprintf(stderr,
2529 "Found %d solutions, searching depth %d...\n",
2530 sols->len, dd.d);
2531 solve_dfs(c, step, opts, &dd);
2532 }
2533
2534 for (node = sols->first; node != NULL; node = node->next)
2535 transform_alg(inverse_trans_aux[opts->pre_trans], node->alg);
2536
2537 return sols;
2538}
2539
2540Alg *
2541inverse_alg(Alg *alg)
2542{
2543 Alg *ret = new_alg("");
2544 int i;
2545
2546 for (i = alg->len-1; i >= 0; i--)
2547 append_move(ret, alg->move[i], alg->inv[i]);
2548
2549 return ret;
2550}
2551
2552Alg *
2553new_alg(char *str)
2554{
2555 Alg *alg = malloc(sizeof(Alg));
2556 int i;
2557 bool niss = false;
2558 Move j, m;
2559
2560 alg->move = malloc(30 * sizeof(Move));
2561 alg->inv = malloc(30 * sizeof(bool));
2562 alg->allocated = 30;
2563 alg->len = 0;
2564
2565 for (i = 0; str[i]; i++) {
2566 if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n')
2567 continue;
2568
2569 if (str[i] == '(' && niss) {
2570 fprintf(stderr, "Error reading moves: nested ( )\n");
2571 return alg;
2572 }
2573
2574 if (str[i] == ')' && !niss) {
2575 fprintf(stderr, "Error reading moves: unmatched )\n");
2576 return alg;
2577 }
2578
2579 if (str[i] == '(' || str[i] == ')') {
2580 niss = !niss;
2581 continue;
2582 }
2583
2584 for (j = 0; j < NMOVES; j++) {
2585 if (str[i] == move_string[j][0]) {
2586 m = j;
2587 if (m <= B && str[i+1]=='w') {
2588 m += Uw - U;
2589 i++;
2590 }
2591 if (str[i+1]=='2') {
2592 m += 1;
2593 i++;
2594 } else if (str[i+1]=='\'' || str[i+1]=='3') {
2595 m += 2;
2596 i++;
2597 }
2598 append_move(alg, m, niss);
2599 break;
2600 }
2601 }
2602 }
2603
2604 return alg;
2605}
2606
2607Alg *
2608on_inverse(Alg *alg)
2609{
2610 Alg *ret = new_alg("");
2611 int i;
2612
2613 for (i = 0; i < alg->len; i++)
2614 append_move(ret, alg->move[i], !alg->inv[i]);
2615
2616 return ret;
2617}
2618
2619void
2620print_alg(Alg *alg, bool l)
2621{
2622 /* TODO: make it possible to print to stdout or to string */
2623 /* Maybe just return a string */
2624 char fill[4];
2625 int i;
2626 bool niss = false;
2627
2628 for (i = 0; i < alg->len; i++) {
2629 if (!niss && alg->inv[i])
2630 strcpy(fill, i == 0 ? "(" : " (");
2631 if (niss && !alg->inv[i])
2632 strcpy(fill, ") ");
2633 if (niss == alg->inv[i])
2634 strcpy(fill, i == 0 ? "" : " ");
2635
2636 printf("%s%s", fill, move_string[alg->move[i]]);
2637 niss = alg->inv[i];
2638 }
2639
2640 if (niss)
2641 printf(")");
2642 if (l)
2643 printf(" (%d)", alg->len);
2644
2645 printf("\n");
2646}
2647
2648void
2649print_alglist(AlgList *al, bool l)
2650{
2651 AlgListNode *i;
2652
2653 for (i = al->first; i != NULL; i = i->next)
2654 print_alg(i->alg, l);
2655}
2656
2657void
2658print_cachedata(CacheData *cd, bool printalgs)
2659{
2660 CacheNode *j;
2661 uint64_t i, s, maxa = 0, maxs = 0, n = 0, empty = 0;
2662
2663 if (!cd->generated)
2664 generate_ctable(cd);
2665
2666 for (i = 0; i < cd->maxind0; i++) {
2667 if (cd->ctable[i] == NULL) {
2668 empty++;
2669 continue;
2670 }
2671
2672 for (j = cd->ctable[i], s = 0;
2673 j != NULL; j = j->next, n++, s++)
2674 if (printalgs)
2675 print_alg(j->sol, false);
2676
2677 if (s > maxs) {
2678 maxs = s;
2679 maxa = i;
2680 }
2681 }
2682
2683 printf("Cache data %s\n", cd->filename);
2684 printf("Length: %d\n", cd->len);
2685 printf("Main table cells: %lu (of which %lu empty)\n", i, empty);
2686 printf("%lu solutions cached ", n);
2687 printf("(most crowded cell: %lu with %lu)\n", maxa, maxs);
2688}
2689
2690void
2691print_ptable(PruneData *pd)
2692{
2693 uint64_t i, a[16];
2694
2695 for (i = 0; i < 16; i++)
2696 a[i] = 0;
2697
2698 if (!pd->generated)
2699 generate_ptable(pd);
2700
2701 for (i = 0; i < pd->size; i++)
2702 a[PTABLEVAL(pd->ptable, i)]++;
2703
2704 fprintf(stderr, "Values for table %s\n", pd->filename);
2705 for (i = 0; i < 16; i++)
2706 printf("%2lu\t%10lu\n", i, a[i]);
2707}
2708
2709
2710Alg *
2711trans_alg(Trans i)
2712{
2713 return trans_algs[i];
2714}
2715
2716void
2717transform_alg(Trans t, Alg *alg)
2718{
2719 int i;
2720
2721 for (i = 0; i < alg->len; i++)
2722 alg->move[i] = moves_ttable[t][alg->move[i]];
2723}
2724
2725
2726void
2727init()
2728{
2729 /* Order is important! */
2730 init_environment();
2731 init_strings();
2732 init_moves_aux();
2733 init_moves();
2734 init_auxtables();
2735 init_trans_aux();
2736 init_trans();
2737}
2738
diff --git a/old/2021-06-17-cachedata/cube.h b/old/2021-06-17-cachedata/cube.h
new file mode 100644
index 0000000..d233165
--- /dev/null
+++ b/old/2021-06-17-cachedata/cube.h
@@ -0,0 +1,79 @@
1#ifndef CUBE_H
2#define CUBE_H
3
4#include <stdio.h>
5#include <stdbool.h>
6#include <stdint.h>
7#include <stdlib.h>
8#include <string.h>
9#include <time.h>
10#include <unistd.h>
11#include <sys/stat.h>
12
13/* Constants and macros *****************************************************/
14
15#define POW2TO11 2048ULL
16#define POW2TO12 4096ULL
17#define POW3TO7 2187ULL
18#define POW3TO8 6561ULL
19#define FACTORIAL4 24ULL
20#define FACTORIAL6 720ULL
21#define FACTORIAL8 40320ULL
22#define FACTORIAL12 479001600ULL
23#define BINOM12ON4 495ULL
24#define BINOM8ON4 70ULL
25#define MIN(a,b) (((a) < (b)) ? (a) : (b))
26#define MAX(a,b) (((a) > (b)) ? (a) : (b))
27
28#define NMOVES (z3+1)
29#define NTRANS (mirror+1)
30#define NROTATIONS (NTRANS-1)
31#define PTABLESIZE(n) ((n+1) / 2)
32#define PTABLEVAL(t,i) (((i)%2) ? (t[(i)/2] / 16) : (t[(i)/2] % 16))
33
34/* Type definitions **********************************************************/
35
36#include "cubetypes.h"
37
38/* Public functions **********************************************************/
39
40Cube apply_alg(Alg *alg, Cube cube);
41Cube apply_move(Move m, Cube cube);
42Cube apply_trans(Trans t, Cube cube);
43bool block_solved(Cube cube, Block);
44Center center_at(Cube cube, Center c);
45Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */
46Corner corner_at(Cube cube, Corner c);
47Edge edge_at(Cube cube, Edge e);
48uint64_t epos_dependent_cube(Cube cube);
49bool equal(Cube c1, Cube c2);
50Cube inverse_cube(Cube cube);
51Move inverse_move(Move m);
52Trans inverse_trans(Trans t);
53bool is_admissible(Cube cube);
54bool is_solved(Cube cube, bool reorient);
55int piece_orientation(Cube cube, int piece, char *orientation);
56void print_cube(Cube cube);
57Cube random_cube();
58AlgList * solve(Cube cube, Step step, SolveOptions *opts);
59
60Move base_move(Move m);
61void free_alg(Alg *alg);
62void free_alglist(AlgList *l);
63Alg * inverse_alg(Alg *alg);
64Alg * new_alg(char *str);
65Alg * on_inverse(Alg *alg);
66void print_alg(Alg *alg, bool l);
67void print_alglist(AlgList *al, bool l);
68Alg * trans_alg(Trans i);
69void transform_alg(Trans t, Alg *alg);
70
71void generate_ctable(CacheData *cd);
72void generate_ptable(PruneData *pd);
73void print_cachedata(CacheData *cd, bool printalgs);
74void print_ptable(PruneData *pd);
75
76void init();
77
78#endif
79
diff --git a/old/2021-06-17-cachedata/cubetypes.h b/old/2021-06-17-cachedata/cubetypes.h
new file mode 100644
index 0000000..4369385
--- /dev/null
+++ b/old/2021-06-17-cachedata/cubetypes.h
@@ -0,0 +1,232 @@
1/* Typedefs ******************************************************************/
2
3typedef enum center Center;
4typedef enum corner Corner;
5typedef enum edge Edge;
6typedef enum move Move;
7typedef enum trans Trans;
8
9typedef struct alg Alg;
10typedef struct alglist AlgList;
11typedef struct alglistnode AlgListNode;
12typedef struct block Block;
13typedef struct cachedata CacheData;
14typedef struct cachenode CacheNode;
15typedef struct cube Cube;
16typedef struct cubearray CubeArray;
17typedef struct dfsdata DfsData;
18typedef struct piecefilter PieceFilter;
19typedef struct prunedata PruneData;
20typedef struct solveoptions SolveOptions;
21typedef struct step Step;
22
23typedef int (*Checker)(Cube);
24typedef uint64_t (*Indexer)(Cube);
25typedef bool (*Moveset)(Move);
26
27
28/* Enums *********************************************************************/
29
30enum
31center
32{
33 U_center, D_center,
34 R_center, L_center,
35 F_center, B_center
36};
37
38enum
39corner
40{
41 UFR, UFL, UBL, UBR,
42 DFR, DFL, DBL, DBR
43};
44
45enum
46edge
47{
48 UF, UL, UB, UR,
49 DF, DL, DB, DR,
50 FR, FL, BL, BR
51};
52
53enum
54move
55{
56 NULLMOVE,
57 U, U2, U3, D, D2, D3,
58 R, R2, R3, L, L2, L3,
59 F, F2, F3, B, B2, B3,
60 Uw, Uw2, Uw3, Dw, Dw2, Dw3,
61 Rw, Rw2, Rw3, Lw, Lw2, Lw3,
62 Fw, Fw2, Fw3, Bw, Bw2, Bw3,
63 M, M2, M3,
64 S, S2, S3,
65 E, E2, E3,
66 x, x2, x3,
67 y, y2, y3,
68 z, z2, z3,
69};
70
71enum
72trans
73{
74 uf, ur, ub, ul,
75 df, dr, db, dl,
76 rf, rd, rb, ru,
77 lf, ld, lb, lu,
78 fu, fr, fd, fl,
79 bu, br, bd, bl,
80 mirror, /* R|L */
81};
82
83
84/* Structs *******************************************************************/
85
86struct
87alg
88{
89 Move * move;
90 bool * inv;
91 int len;
92 int allocated;
93};
94
95struct
96alglist
97{
98 AlgListNode * first;
99 AlgListNode * last;
100 int len;
101};
102
103struct
104alglistnode
105{
106 Alg * alg;
107 AlgListNode * next;
108};
109
110struct
111block
112{
113 bool edge[12];
114 bool corner[8];
115 bool center[6];
116};
117
118struct
119cachedata
120{
121 char * filename;
122 CacheNode ** ctable;
123 bool generated;
124 uint64_t maxind0;
125 int len;
126 int nind;
127 Indexer index[20]; /* Should be enough */
128 Checker check;
129 Moveset moveset;
130};
131
132struct
133cachenode
134{
135 uint64_t * indexval;
136 Alg * sol;
137 CacheNode * next;
138};
139
140struct
141cube
142{
143 uint16_t epose;
144 uint16_t eposs;
145 uint16_t eposm;
146 uint16_t eofb;
147 uint16_t eorl;
148 uint16_t eoud;
149 uint16_t cp;
150 uint16_t coud;
151 uint16_t cofb;
152 uint16_t corl;
153 uint16_t cpos;
154};
155
156struct
157cubearray
158{
159 int * ep;
160 int * eofb;
161 int * eorl;
162 int * eoud;
163 int * cp;
164 int * coud;
165 int * corl;
166 int * cofb;
167 int * cpos;
168};
169
170struct
171dfsdata
172{
173 int d;
174 int m;
175 bool niss;
176 Move last1;
177 Move last2;
178 AlgList * sols;
179 Alg * current_alg;
180 Move sorted_moves[NMOVES];
181 int move_position[NMOVES];
182};
183
184struct
185piecefilter
186{
187 bool epose;
188 bool eposs;
189 bool eposm;
190 bool eofb;
191 bool eorl;
192 bool eoud;
193 bool cp;
194 bool coud;
195 bool cofb;
196 bool corl;
197 bool cpos;
198};
199
200struct
201prunedata
202{
203 char * filename;
204 uint8_t * ptable;
205 uint8_t * reached;
206 bool generated;
207 uint64_t n;
208 uint64_t size;
209 Indexer index;
210 Moveset moveset;
211};
212
213struct
214solveoptions
215{
216 int min_moves;
217 int max_moves;
218 int max_solutions;
219 bool optimal_only;
220 bool can_niss;
221 bool feedback;
222 Trans pre_trans;
223};
224
225struct
226step
227{
228 Checker check;
229 Checker ready;
230 Moveset moveset;
231 CacheData * cd;
232};
diff --git a/old/2021-06-17-cachedata/main.c b/old/2021-06-17-cachedata/main.c
new file mode 100644
index 0000000..bd69ac9
--- /dev/null
+++ b/old/2021-06-17-cachedata/main.c
@@ -0,0 +1,63 @@
1#include <stdio.h>
2#include "cube.h"
3#include "steps.h"
4
5int main() {
6 Alg *algo;
7 AlgList *sols;
8 Cube cube;
9 SolveOptions opts;
10 char line[1000];
11 int i, ns = 3; /*, nrand = 100000, sum1, sum2;*/
12
13 Step *stps[20] = {&eofb_HTM, &corners_URF, &optimal_HTM};
14 char sss[30][30] = {"EO on F/B", "Corners URF", "Optimal solution"};
15
16 opts = (SolveOptions) {
17 .min_moves = 0,
18 .max_moves = 20,
19 .optimal_only = true,
20 .max_solutions = 1,
21 .can_niss = false,
22 .feedback = true,
23 .pre_trans = uf
24 };
25
26 init();
27
28/*
29 print_ptable(&pd_corners_HTM);
30
31 srand(time(NULL));
32 sum1 = 0;
33 sum2 = 0;
34 for (i = 0; i < nrand; i++) {
35 sum1 += optimal_HTM.check(random_cube());
36 sum2 += corners_HTM.check(random_cube());
37 }
38 printf("Average optimal pruning: %lf\n", ((double)sum1) / ((double) nrand));
39 printf("Average corners pruning: %lf\n", ((double)sum2) / ((double) nrand));
40*/
41
42 print_cachedata(&cd_optimal_HTM_6, false);
43
44 printf("Welcome to nissy 2.0! Insert a scramble:\n");
45
46 if (fgets(line, 1000, stdin) != NULL) {
47 algo = new_alg(line);
48 cube = apply_alg(algo, (Cube){0});
49
50 for (i = 0; i < ns; i++) {
51 if (stps[i]->check == NULL)
52 fprintf(stderr, "Check function for step %d is null\n", i);
53 sols = solve(cube, *stps[i], &opts);
54 printf("%s: %d solutions found:\n", sss[i], sols->len);
55 print_alglist(sols, true);
56 free_alglist(sols);
57 }
58 free(algo);
59 }
60
61 return 0;
62}
63
diff --git a/old/2021-06-17-cachedata/steps.c b/old/2021-06-17-cachedata/steps.c
new file mode 100644
index 0000000..f1001e6
--- /dev/null
+++ b/old/2021-06-17-cachedata/steps.c
@@ -0,0 +1,327 @@
1#include "steps.h"
2
3/* Check functions ***********************************************************/
4
5static int check_nothing(Cube cube);
6static int check_eofb_HTM(Cube cube);
7static int check_coud_HTM(Cube cube);
8static int check_coud_URF(Cube cube);
9static int check_corners_HTM(Cube cube);
10static int check_corners_URF(Cube cube);
11static int check_edges_HTM(Cube cube);
12static int check_drud_HTM(Cube cube);
13static int check_optimal_HTM(Cube cube);
14
15
16/* Index functions ***********************************************************/
17
18static uint64_t index_eofb(Cube cube);
19static uint64_t index_coud(Cube cube);
20static uint64_t index_corners(Cube cube);
21static uint64_t index_ep(Cube cube);
22static uint64_t index_drud(Cube cube);
23
24
25/* Steps *********************************************************************/
26
27Step
28eofb_HTM = {
29 .check = check_eofb_HTM,
30 .ready = check_nothing,
31 .moveset = moveset_HTM
32};
33
34Step
35coud_HTM = {
36 .check = check_coud_HTM,
37 .ready = check_nothing,
38 .moveset = moveset_HTM
39};
40
41Step
42coud_URF = {
43 .check = check_coud_URF,
44 .ready = check_nothing,
45 .moveset = moveset_URF
46};
47
48Step
49corners_HTM = {
50 .check = check_corners_HTM,
51 .ready = check_nothing,
52 .moveset = moveset_HTM
53};
54
55Step
56corners_URF = {
57 .check = check_corners_URF,
58 .ready = check_nothing,
59 .moveset = moveset_URF
60};
61
62Step
63edges_HTM = {
64 .check = check_edges_HTM,
65 .ready = check_nothing,
66 .moveset = moveset_HTM
67};
68
69Step
70drud_HTM = {
71 .check = check_drud_HTM,
72 .ready = check_nothing,
73 .moveset = moveset_HTM
74};
75
76Step
77optimal_HTM = {
78 .check = check_optimal_HTM,
79 .ready = check_nothing,
80 .moveset = moveset_HTM,
81 .cd = &cd_optimal_HTM_6
82};
83
84
85/* Cache solutions ***********************************************************/
86
87CacheData
88cd_optimal_HTM_6 = {
89 .filename = "cd_optimal_HTM_6",
90 .maxind0 = POW3TO7 * FACTORIAL8,
91 .len = 6,
92 .nind = 3,
93 .index = { index_corners, index_eofb, index_ep },
94 .moveset = moveset_HTM
95};
96
97
98/* Pruning tables ************************************************************/
99
100PruneData
101pd_eofb_HTM = {
102 .filename = "ptable_eofb_HTM",
103 .size = POW2TO11,
104 .index = index_eofb,
105 .moveset = moveset_HTM
106};
107
108PruneData
109pd_coud_HTM = {
110 .filename = "ptable_coud_HTM",
111 .size = POW3TO7,
112 .index = index_coud,
113 .moveset = moveset_HTM
114};
115
116PruneData
117pd_corners_HTM = {
118 .filename = "ptable_corners_HTM",
119 .size = POW3TO7 * FACTORIAL8,
120 .index = index_corners,
121 .moveset = moveset_HTM
122};
123
124PruneData
125pd_ep_HTM = {
126 .filename = "ptable_ep_HTM",
127 .size = FACTORIAL12,
128 .index = index_ep,
129 .moveset = moveset_HTM
130};
131
132PruneData
133pd_drud_HTM = {
134 .filename = "ptable_drud_HTM",
135 .size = POW2TO11 * POW3TO7 * BINOM12ON4,
136 .index = index_drud,
137 .moveset = moveset_HTM
138};
139
140
141/* Check functions implementation ********************************************/
142
143static int
144check_nothing(Cube cube)
145{
146 /* At least we check that it is admissible */
147 return is_admissible(cube);
148}
149
150static int
151check_eofb_HTM(Cube cube)
152{
153 if (!pd_eofb_HTM.generated)
154 generate_ptable(&pd_eofb_HTM);
155
156 return PTABLEVAL(pd_eofb_HTM.ptable, cube.eofb);
157}
158
159static int
160check_coud_HTM(Cube cube)
161{
162 if (!pd_coud_HTM.generated)
163 generate_ptable(&pd_coud_HTM);
164
165 return PTABLEVAL(pd_coud_HTM.ptable, cube.coud);
166}
167
168static int
169check_coud_URF(Cube cube)
170{
171 /* TODO: I can improve this by checking first the orientation of
172 * the corner in DBL and use that as a reference */
173
174 int ud = check_coud_HTM(cube);
175 int rl = check_coud_HTM(apply_move(z, cube));
176 int fb = check_coud_HTM(apply_move(x, cube));
177
178 return MIN(ud, MIN(rl, fb));
179}
180
181static int
182check_corners_HTM(Cube cube)
183{
184 if (!pd_corners_HTM.generated)
185 generate_ptable(&pd_corners_HTM);
186
187 return PTABLEVAL(pd_corners_HTM.ptable, index_corners(cube));
188}
189
190static int
191check_corners_URF(Cube cube)
192{
193 /* TODO: I can improve this by checking first the corner in DBL
194 * and use that as a reference */
195
196 int ret = 15;
197 Trans i;
198
199 for (i = 0; i < NROTATIONS; i++)
200 ret = MIN(ret,check_corners_HTM(apply_alg(trans_alg(i),cube)));
201
202 return ret;
203}
204
205static int
206check_edges_HTM(Cube cube)
207{
208 int ret = 0;
209
210 if (!pd_ep_HTM.generated)
211 generate_ptable(&pd_ep_HTM);
212
213 ret = MAX(ret, PTABLEVAL(pd_ep_HTM.ptable, index_ep(cube)));
214 ret = MAX(ret, check_eofb_HTM(cube));
215 ret = MAX(ret, check_eofb_HTM(apply_trans(ur, cube)));
216 ret = MAX(ret, check_eofb_HTM(apply_trans(fd, cube)));
217
218 return ret;
219}
220
221static int
222check_drud_HTM(Cube cube)
223{
224 if (!pd_drud_HTM.generated)
225 generate_ptable(&pd_drud_HTM);
226
227 return PTABLEVAL(pd_drud_HTM.ptable, index_drud(cube));
228}
229
230static int
231check_optimal_HTM(Cube cube)
232{
233 int dr1, dr2, dr3, drmax, cor; /*ep;*/
234
235 if (!pd_drud_HTM.generated)
236 generate_ptable(&pd_drud_HTM);
237 if (!pd_corners_HTM.generated)
238 generate_ptable(&pd_corners_HTM);
239 /*
240 *if (!pd_ep_HTM.generated)
241 * generate_ptable(&pd_ep_HTM);
242 */
243
244 dr1 = PTABLEVAL(pd_drud_HTM.ptable, index_drud(cube));
245 dr2 = PTABLEVAL(pd_drud_HTM.ptable, index_drud(apply_trans(rf, cube)));
246 dr3 = PTABLEVAL(pd_drud_HTM.ptable, index_drud(apply_trans(fd, cube)));
247
248 drmax = MAX(dr1, MAX(dr2, dr3));
249 if (dr1 == dr2 && dr2 == dr3 && dr1 != 0)
250 drmax++;
251
252 cor = PTABLEVAL(pd_corners_HTM.ptable, index_corners(cube));
253 /* ep = PTABLEVAL(pd_ep_HTM.ptable, index_ep(cube)); */
254
255 /*return MAX(drmax, MAX(ep, cor));*/
256 if (drmax == 0 && cor == 0)
257 return is_solved(cube, false) ? 0 : 1;
258 return MAX(drmax, cor);
259}
260
261
262/* Index functions implementation ********************************************/
263
264static uint64_t
265index_eofb(Cube cube)
266{
267 return cube.eofb;
268}
269
270static uint64_t
271index_coud(Cube cube)
272{
273 return cube.coud;
274}
275
276static uint64_t
277index_corners(Cube cube)
278{
279 return cube.coud * FACTORIAL8 + cube.cp;
280}
281
282static uint64_t
283index_ep(Cube cube)
284{
285 uint64_t a, b, c;
286
287 a = cube.eposs;
288 b = (cube.epose % FACTORIAL4) + epos_dependent_cube(cube)*FACTORIAL4;
289 c = cube.eposm % FACTORIAL4;
290
291 b *= FACTORIAL4 * BINOM12ON4;
292 c *= FACTORIAL4 * BINOM12ON4 * FACTORIAL4 * BINOM8ON4;
293
294 return a + b + c;
295}
296
297static uint64_t
298index_drud(Cube cube)
299{
300 uint64_t a, b, c;
301
302 a = cube.eofb;
303 b = cube.coud;
304 c = cube.epose / FACTORIAL4;
305
306 b *= POW2TO11;
307 c *= POW2TO11 * POW3TO7;
308
309 return a + b + c;
310}
311
312/* Movesets ******************************************************************/
313
314bool
315moveset_HTM(Move m)
316{
317 return m >= U && m <= B3;
318}
319
320bool
321moveset_URF(Move m)
322{
323 Move b = base_move(m);
324
325 return b == U || b == R || b == F;
326}
327
diff --git a/old/2021-06-17-cachedata/steps.h b/old/2021-06-17-cachedata/steps.h
new file mode 100644
index 0000000..66a31a8
--- /dev/null
+++ b/old/2021-06-17-cachedata/steps.h
@@ -0,0 +1,34 @@
1#ifndef STEPS_H
2#define STEPS_H
3
4#include "cube.h"
5
6/* Steps *********************************************************************/
7
8extern Step eofb_HTM;
9extern Step coud_HTM;
10extern Step coud_URF;
11extern Step corners_HTM;
12extern Step corners_URF;
13extern Step edges_HTM;
14extern Step drud_HTM;
15extern Step optimal_HTM;
16
17/* Cache solutions ***********************************************************/
18
19extern CacheData cd_optimal_HTM_6;
20
21/* Pruning tables ************************************************************/
22
23extern PruneData pd_eofb_HTM;
24extern PruneData pd_coud_HTM;
25extern PruneData pd_corners_HTM;
26extern PruneData pd_ep_HTM;
27extern PruneData pd_drud_HTM;
28
29/* Movesets ******************************************************************/
30
31bool moveset_HTM(Move m);
32bool moveset_URF(Move m);
33
34#endif
diff --git a/old/2021-06-23-realizing-bad-tables/HERE b/old/2021-06-23-realizing-bad-tables/HERE
new file mode 100644
index 0000000..487e305
--- /dev/null
+++ b/old/2021-06-23-realizing-bad-tables/HERE
@@ -0,0 +1 @@
Here you can also find some tables data that I have removed, like ep and tripleeo
diff --git a/old/2021-06-23-realizing-bad-tables/cube.c b/old/2021-06-23-realizing-bad-tables/cube.c
new file mode 100644
index 0000000..4e60bb2
--- /dev/null
+++ b/old/2021-06-23-realizing-bad-tables/cube.c
@@ -0,0 +1,2844 @@
1#include "cube.h"
2
3/* Local functions **********************************************************/
4
5static Cube admissible_ep(Cube cube, PieceFilter f);
6static bool allowed_next(Move move, DfsData *dd);
7static void append_alg(AlgList *l, Alg *alg);
8static void append_move(Alg *alg, Move m, bool inverse);
9static Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a);
10static void apply_permutation(int *perm, int *set, int n);
11static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f);
12static int array_ep_to_epos(int *ep, int *eps_solved);
13static Cube arrays_to_cube(CubeArray *arr, PieceFilter f);
14static int binomial(int n, int k);
15static Cube compose_filtered(Cube c2, Cube c1, PieceFilter f);
16static void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f);
17static void dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd);
18static void dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd);
19static bool dfs_check_solved(SolveOptions *opts, DfsData *dd);
20static void dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd);
21static bool dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd);
22static int digit_array_to_int(int *a, int n, int b);
23static int edge_slice(Edge e); /* E=0, S=1, M=2 */
24static int epos_dependent_pos(int pos1, int pos2);
25static int epos_from_arrays(int *epos, int *ep);
26static void epos_to_partial_ep(int epos, int *ep, int *ss);
27static int factorial(int n);
28static void free_alglistnode(AlgListNode *aln);
29static void free_cubearray(CubeArray *arr, PieceFilter f);
30static void genptable_dfs(Cube c, PruneData *pd, DfsData *dd);
31static void genptable_dfs_branch(Cube c, PruneData *pd, DfsData *dd);
32static void index_to_perm(int p, int n, int *r);
33static void index_to_subset(int s, int n, int k, int *r);
34static void int_to_digit_array(int a, int b, int n, int *r);
35static void int_to_sum_zero_array(int x, int b, int n, int *a);
36static int invert_digits(int a, int b, int n);
37static bool is_perm(int *a, int n);
38static bool is_subset(int *a, int n, int k);
39static Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf);
40static void movelist_to_position(Move *movelist, int *position);
41static void moveset_to_list(Moveset ms, Checker f, Move *r);
42static AlgList * new_alglist();
43static CubeArray * new_cubearray(Cube cube, PieceFilter f);
44static int perm_sign(int *a, int n);
45static int perm_to_index(int *a, int n);
46static int powint(int a, int b);
47static bool ptable_has_reached(PruneData *pd, uint64_t ind);
48static void ptable_set_reached(PruneData *pd, uint64_t ind);
49static void ptable_update(PruneData *pd, uint64_t ind, int m);
50static void realloc_alg(Alg *alg, int n);
51static bool read_algset_file(AlgSet *as);
52static bool read_mtables_file();
53static bool read_ptable_file(PruneData *pd);
54static bool read_ttables_file();
55static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f);
56static int subset_to_index(int *a, int n, int k);
57static void sum_arrays_mod(int *src, int *dst, int n, int m);
58static void swap(int *a, int *b);
59static bool write_algset_file(AlgSet *as);
60static bool write_mtables_file();
61static bool write_ptable_file(PruneData *pd);
62static bool write_ttables_file();
63
64static void init_auxtables();
65static void init_cphtr_cosets();
66static void init_cphtr_cosets_bfs(int i, int c);
67static void init_environment();
68static void init_moves();
69static void init_moves_aux();
70static void init_strings();
71static void init_trans();
72static void init_trans_aux();
73
74/* All sorts of useful costants and tables **********************************/
75
76static char * tabledir;
77
78static PieceFilter pf_all;
79static PieceFilter pf_4val;
80static PieceFilter pf_epcp;
81static PieceFilter pf_cpos;
82static PieceFilter pf_cp;
83static PieceFilter pf_ep;
84static PieceFilter pf_e;
85static PieceFilter pf_s;
86static PieceFilter pf_m;
87static PieceFilter pf_eo;
88static PieceFilter pf_co;
89
90static int epe_solved[4];
91static int eps_solved[4];
92static int epm_solved[4];
93
94static char move_string[NMOVES][7];
95static char edge_string[12][7];
96static char corner_string[8][7];
97static char center_string[6][7];
98
99static bool commute[NMOVES][NMOVES];
100static bool possible_next[NMOVES][NMOVES][NMOVES];
101static Move inverse_move_aux[NMOVES];
102static Trans inverse_trans_aux[NTRANS];
103static int epos_dependent_aux[BINOM12ON4][BINOM12ON4];
104static int cphtr_cosets[FACTORIAL8];
105static Center what_center_at_aux[FACTORIAL6][6];
106static Corner what_corner_at_aux[FACTORIAL8][8];
107static int what_orientation_last_corner_aux[POW3TO7];
108static int what_orientation_last_edge_aux[POW2TO11];
109static Center where_is_center_aux[FACTORIAL6][6];
110static Corner where_is_corner_aux[FACTORIAL8][8];
111static Edge where_is_edge_aux[3][FACTORIAL12/FACTORIAL8][12];
112
113static int epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
114static int eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
115static int eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
116static int eo_ttable[NTRANS][POW2TO11];
117static int cp_ttable[NTRANS][FACTORIAL8];
118static int co_ttable[NTRANS][POW3TO7];
119static int cpos_ttable[NTRANS][FACTORIAL6];
120static Move moves_ttable[NTRANS][NMOVES];
121
122static int epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
123static int eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
124static int eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
125static int eofb_mtable[NMOVES][POW2TO11];
126static int eorl_mtable[NMOVES][POW2TO11];
127static int eoud_mtable[NMOVES][POW2TO11];
128static int cp_mtable[NMOVES][FACTORIAL8];
129static int coud_mtable[NMOVES][POW3TO7];
130static int cofb_mtable[NMOVES][POW3TO7];
131static int corl_mtable[NMOVES][POW3TO7];
132static int cpos_mtable[NMOVES][FACTORIAL6];
133
134static uint64_t me[12];
135
136static int edge_cycle[NMOVES][12];
137static int corner_cycle[NMOVES][8];
138static int center_cycle[NMOVES][6];
139static int eofb_flipped[NMOVES][12];
140static int eorl_flipped[NMOVES][12];
141static int eoud_flipped[NMOVES][12];
142static int coud_flipped[NMOVES][8];
143static int corl_flipped[NMOVES][8];
144static int cofb_flipped[NMOVES][8];
145static Alg * equiv_alg[NMOVES];
146
147static int epose_source[NTRANS]; /* 0=epose, 1=eposs, 2=eposm */
148static int eposs_source[NTRANS];
149static int eposm_source[NTRANS];
150static int eofb_source[NTRANS]; /* 0=eoud, 1=eorl, 2=eofb */
151static int eorl_source[NTRANS];
152static int eoud_source[NTRANS];
153static int coud_source[NTRANS]; /* 0=coud, 1=corl, 2=cofb */
154static int cofb_source[NTRANS];
155static int corl_source[NTRANS];
156static int ep_mirror[12];
157static int cp_mirror[8];
158static int cpos_mirror[6];
159static Alg * trans_algs[NROTATIONS];
160
161
162/* Local functions implementation ********************************************/
163
164static Cube
165admissible_ep(Cube cube, PieceFilter f)
166{
167 CubeArray *arr = new_cubearray(cube, f);
168 Cube ret;
169 bool used[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
170 int i, j;
171
172 for (i = 0; i < 12; i++)
173 if (arr->ep[i] != -1)
174 used[arr->ep[i]] = true;
175
176 for (i = 0, j = 0; i < 12; i++) {
177 for ( ; j < 11 && used[j]; j++);
178 if (arr->ep[i] == -1)
179 arr->ep[i] = j++;
180 }
181
182 ret = arrays_to_cube(arr, pf_ep);
183 free_cubearray(arr, f);
184
185 return ret;
186}
187
188static bool
189allowed_next(Move move, DfsData *dd)
190{
191 if (!possible_next[dd->last2][dd->last1][move])
192 return false;
193
194 if (commute[dd->last1][move])
195 return dd->move_position[dd->last1] < dd->move_position[move];
196
197 return true;
198}
199
200static void
201append_alg(AlgList *l, Alg *alg)
202{
203 AlgListNode *node = malloc(sizeof(AlgListNode));
204 int i;
205
206 node->alg = new_alg("");
207 for (i = 0; i < alg->len; i++)
208 append_move(node->alg, alg->move[i], alg->inv[i]);
209 node->next = NULL;
210
211 if (++l->len == 1)
212 l->first = node;
213 else
214 l->last->next = node;
215 l->last = node;
216}
217
218static void
219append_move(Alg *alg, Move m, bool inverse)
220{
221 if (alg->len == alg->allocated)
222 realloc_alg(alg, 2*alg->len);
223
224 alg->move[alg->len] = m;
225 alg->inv [alg->len] = inverse;
226 alg->len++;
227}
228
229static Cube
230apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a)
231{
232 Cube ret = {0};
233 int i;
234
235 for (i = 0; i < alg->len; i++)
236 if (alg->inv[i])
237 ret = a ? apply_move(alg->move[i], ret) :
238 apply_move_cubearray(alg->move[i], ret, f);
239
240 ret = compose_filtered(c, inverse_cube(ret), f);
241
242 for (i = 0; i < alg->len; i++)
243 if (!alg->inv[i])
244 ret = a ? apply_move(alg->move[i], ret) :
245 apply_move_cubearray(alg->move[i], ret, f);
246
247 return ret;
248}
249
250static void
251apply_permutation(int *perm, int *set, int n)
252{
253 int *aux = malloc(n * sizeof(int));
254 int i;
255
256 if (!is_perm(perm, n))
257 return;
258
259 for (i = 0; i < n; i++)
260 aux[i] = set[perm[i]];
261
262 memcpy(set, aux, n * sizeof(int));
263 free(aux);
264}
265
266static Cube
267apply_move_cubearray(Move m, Cube cube, PieceFilter f)
268{
269 CubeArray m_arr = {
270 edge_cycle[m],
271 eofb_flipped[m],
272 eorl_flipped[m],
273 eoud_flipped[m],
274 corner_cycle[m],
275 coud_flipped[m],
276 corl_flipped[m],
277 cofb_flipped[m],
278 center_cycle[m]
279 };
280
281 return move_via_arrays(&m_arr, cube, f);
282}
283
284static int
285array_ep_to_epos(int *ep, int *ss)
286{
287 int epos[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
288 int eps[4];
289 int i, j, is;
290
291 for (i = 0, is = 0; i < 12; i++) {
292 for (j = 0; j < 4; j++) {
293 if (ep[i] == ss[j]) {
294 eps[is++] = j;
295 epos[i] = 1;
296 }
297 }
298 }
299
300 for (i = 0; i < 4; i++)
301 swap(&epos[ss[i]], &epos[i+8]);
302
303 return epos_from_arrays(epos, eps);
304}
305
306static Cube
307arrays_to_cube(CubeArray *arr, PieceFilter f)
308{
309 Cube ret = {0};
310
311 if (f.epose)
312 ret.epose = array_ep_to_epos(arr->ep, epe_solved);
313 if (f.eposs)
314 ret.eposs = array_ep_to_epos(arr->ep, eps_solved);
315 if (f.eposm)
316 ret.eposm = array_ep_to_epos(arr->ep, epm_solved);
317 if (f.eofb)
318 ret.eofb = digit_array_to_int(arr->eofb, 11, 2);
319 if (f.eorl)
320 ret.eorl = digit_array_to_int(arr->eorl, 11, 2);
321 if (f.eoud)
322 ret.eoud = digit_array_to_int(arr->eoud, 11, 2);
323 if (f.cp)
324 ret.cp = perm_to_index(arr->cp, 8);
325 if (f.coud)
326 ret.coud = digit_array_to_int(arr->coud, 7, 3);
327 if (f.corl)
328 ret.corl = digit_array_to_int(arr->corl, 7, 3);
329 if (f.cofb)
330 ret.cofb = digit_array_to_int(arr->cofb, 7, 3);
331 if (f.cpos)
332 ret.cpos = perm_to_index(arr->cpos, 6);
333
334 return ret;
335}
336
337static int
338binomial(int n, int k)
339{
340 if (n < 0 || k < 0 || k > n)
341 return 0;
342
343 return factorial(n) / (factorial(k) * factorial(n-k));
344}
345
346static Cube
347compose_filtered(Cube c2, Cube c1, PieceFilter f)
348{
349 CubeArray *arr = new_cubearray(c2, f);
350 Cube ret;
351
352 ret = move_via_arrays(arr, c1, f);
353 free_cubearray(arr, f);
354
355 return ret;
356}
357
358static void
359cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f)
360{
361 int i;
362
363 if (f.epose || f.eposs || f.eposm)
364 for (i = 0; i < 12; i++)
365 arr->ep[i] = -1;
366
367 if (f.epose)
368 epos_to_partial_ep(cube.epose, arr->ep, epe_solved);
369 if (f.eposs)
370 epos_to_partial_ep(cube.eposs, arr->ep, eps_solved);
371 if (f.eposm)
372 epos_to_partial_ep(cube.eposm, arr->ep, epm_solved);
373 if (f.eofb)
374 int_to_sum_zero_array(cube.eofb, 2, 12, arr->eofb);
375 if (f.eorl)
376 int_to_sum_zero_array(cube.eorl, 2, 12, arr->eorl);
377 if (f.eoud)
378 int_to_sum_zero_array(cube.eoud, 2, 12, arr->eoud);
379 if (f.cp)
380 index_to_perm(cube.cp, 8, arr->cp);
381 if (f.coud)
382 int_to_sum_zero_array(cube.coud, 3, 8, arr->coud);
383 if (f.corl)
384 int_to_sum_zero_array(cube.corl, 3, 8, arr->corl);
385 if (f.cofb)
386 int_to_sum_zero_array(cube.cofb, 3, 8, arr->cofb);
387 if (f.cpos)
388 index_to_perm(cube.cpos, 6, arr->cpos);
389}
390
391/*
392static int
393cphtr_cp(int cp)
394{
395 int i, a[8];
396
397 index_to_perm(cp, 8, a);
398
399 for (i = 0; i < 8; i++)
400 if (a[i] == UFR || a[i] == UBL || a[i] == DFL || a[i] == DBR)
401 a[i] = 0;
402 else
403 a[i] = 1;
404
405 swap(&a[1], &a[5]);
406 swap(&a[3], &a[7]);
407
408 return subset_to_index(a, 8, 4);
409}
410*/
411
412static void
413dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd)
414{
415 if (dfs_stop(c, s, opts, dd))
416 return;
417
418 if (dfs_check_solved(opts, dd))
419 return;
420
421 dfs_branch(c, s, opts, dd);
422
423 if (opts->can_niss && !dd->niss)
424 dfs_niss(c, s, opts, dd);
425}
426
427static void
428dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd)
429{
430 Move m, l1 = dd->last1, l2 = dd->last2, *moves = dd->sorted_moves;
431
432 int i, maxnsol = opts->max_solutions;
433
434 for (i = 0; (m=moves[i]) != NULLMOVE && dd->sols->len < maxnsol; i++) {
435 if (allowed_next(m, dd)) {
436 dd->last2 = dd->last1;
437 dd->last1 = m;
438 append_move(dd->current_alg, m, dd->niss);
439
440 dfs(apply_move(m, c), s, opts, dd);
441
442 dd->current_alg->len--;
443 dd->last2 = l2;
444 dd->last1 = l1;
445 }
446 }
447}
448
449static bool
450dfs_check_solved(SolveOptions *opts, DfsData *dd)
451{
452 if (dd->lb != 0)
453 return false;
454
455 if (dd->current_alg->len == dd->d) {
456 append_alg(dd->sols, dd->current_alg);
457
458 if (opts->feedback)
459 print_alg(dd->current_alg, false);
460 }
461
462 return true;
463}
464
465static void
466dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd)
467{
468 Move l1 = dd->last1, l2 = dd->last2;
469
470 if (dd->current_alg->len == 0 ||
471 (s.check(apply_move(inverse_move(l1), (Cube){0}), 1))) {
472 dd->niss = true;
473 dd->last1 = NULLMOVE;
474 dd->last2 = NULLMOVE;
475
476 dfs(inverse_cube(c), s, opts, dd);
477
478 dd->last1 = l1;
479 dd->last2 = l2;
480 dd->niss = false;
481 }
482}
483
484static bool
485dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd)
486{
487 if (dd->sols->len >= opts->max_solutions)
488 return true;
489
490 dd->lb = s.check(c, dd->d - dd->current_alg->len);
491 if (opts->can_niss && !dd->niss)
492 dd->lb = MIN(1, dd->lb);
493
494 if (dd->current_alg->len + dd->lb > dd->d)
495 return true;
496
497 return false;
498}
499
500static int
501digit_array_to_int(int *a, int n, int b)
502{
503 int i, ret = 0, p = 1;
504
505 for (i = 0; i < n; i++, p *= b)
506 ret += a[i] * p;
507
508 return ret;
509}
510
511static int
512edge_slice(Edge e) {
513 if (e < 0 || e > 11)
514 return -1;
515
516 if (e == FR || e == FL || e == BL || e == BR)
517 return 0;
518 if (e == UR || e == UL || e == DR || e == DL)
519 return 1;
520
521 return 2;
522}
523
524static int
525epos_dependent_pos(int poss, int pose)
526{
527 int ep[12] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
528 int ep8[8] = {0, 0, 0, 0, 0, 0, 0, 0};
529 int i, j;
530
531 epos_to_partial_ep(poss*FACTORIAL4, ep, eps_solved);
532 epos_to_partial_ep(pose*FACTORIAL4, ep, epe_solved);
533
534 for (i = 0, j = 0; i < 12; i++)
535 if (edge_slice(ep[i]) != 0)
536 ep8[j++] = (edge_slice(ep[i]) == 1) ? 1 : 0;
537
538 swap(&ep8[1], &ep8[4]);
539 swap(&ep8[3], &ep8[6]);
540
541 return subset_to_index(ep8, 8, 4);
542}
543
544static int
545epos_from_arrays(int *epos, int *ep)
546{
547 return FACTORIAL4 * subset_to_index(epos,12,4) + perm_to_index(ep,4);
548}
549
550static void
551epos_to_partial_ep(int epos, int *ep, int *ss)
552{
553 int i, is, eposs[12], eps[4];
554
555 index_to_perm(epos % FACTORIAL4, 4, eps);
556 index_to_subset(epos / FACTORIAL4, 12, 4, eposs);
557
558 for (i = 0; i < 4; i++)
559 swap(&eposs[ss[i]], &eposs[i+8]);
560
561 for (i = 0, is = 0; i < 12; i++)
562 if (eposs[i])
563 ep[i] = ss[eps[is++]];
564}
565
566static int
567factorial(int n)
568{
569 int i, ret = 1;
570
571 if (n < 0)
572 return 0;
573
574 for (i = 1; i <= n; i++)
575 ret *= i;
576
577 return ret;
578}
579
580void
581free_alg(Alg *alg)
582{
583 free(alg->move);
584 free(alg->inv);
585 free(alg);
586}
587
588void
589free_alglist(AlgList *l)
590{
591 AlgListNode *aux, *i = l->first;
592
593 while (i != NULL) {
594 aux = i->next;
595 free_alglistnode(i);
596 i = aux;
597 }
598 free(l);
599}
600
601void
602free_alglistnode(AlgListNode *aln)
603{
604 free_alg(aln->alg);
605 free(aln);
606}
607
608static void
609free_cubearray(CubeArray *arr, PieceFilter f)
610{
611 if (f.epose || f.eposs || f.eposm)
612 free(arr->ep);
613 if (f.eofb)
614 free(arr->eofb);
615 if (f.eorl)
616 free(arr->eorl);
617 if (f.eoud)
618 free(arr->eoud);
619 if (f.cp)
620 free(arr->cp);
621 if (f.coud)
622 free(arr->coud);
623 if (f.corl)
624 free(arr->corl);
625 if (f.cofb)
626 free(arr->cofb);
627 if (f.cpos)
628 free(arr->cpos);
629
630 free(arr);
631}
632
633static void
634genptable_dfs(Cube c, PruneData *pd, DfsData *dd)
635{
636 uint64_t ind = pd->index(c);
637 int oldval = ptableval(pd, ind);
638
639 if (oldval < dd->m || ptable_has_reached(pd, ind) || pd->n == pd->size)
640 return;
641
642 ptable_set_reached(pd, ind);
643
644 if (dd->m == dd->d) {
645 if (dd->m < oldval)
646 ptable_update(pd, ind, dd->m);
647 return;
648 }
649
650 genptable_dfs_branch(c, pd, dd);
651}
652
653static void
654genptable_dfs_branch(Cube c, PruneData *pd, DfsData *dd)
655{
656 Move i, move, l1 = dd->last1, l2 = dd->last2;
657
658 dd->m++;
659
660 for (i = 0; dd->sorted_moves[i] != NULLMOVE; i++) {
661 move = dd->sorted_moves[i];
662 if (allowed_next(move, dd)) {
663 dd->last2 = dd->last1;
664 dd->last1 = move;
665
666 genptable_dfs(apply_move(move, c), pd, dd);
667
668 dd->last2 = l2;
669 dd->last1 = l1;
670 }
671 }
672
673 dd->m--;
674}
675
676static void
677index_to_perm(int p, int n, int *r)
678{
679 int *a = malloc(n * sizeof(int));
680 int i, j, c;
681
682 for (i = 0; i < n; i++)
683 a[i] = 0;
684
685 if (p < 0 || p >= factorial(n))
686 for (i = 0; i < n; i++)
687 r[i] = -1;
688
689 for (i = 0; i < n; i++) {
690 c = 0;
691 j = 0;
692 while (c <= p / factorial(n-i-1))
693 c += a[j++] ? 0 : 1;
694 r[i] = j-1;
695 a[j-1] = 1;
696 p %= factorial(n-i-1);
697 }
698
699 free(a);
700}
701
702static void
703index_to_subset(int s, int n, int k, int *r)
704{
705 int i, j, v;
706
707 if (s < 0 || s >= binomial(n, k)) {
708 for (i = 0; i < n; i++)
709 r[i] = -1;
710 return;
711 }
712
713 for (i = 0; i < n; i++) {
714 if (k == n-i) {
715 for (j = i; j < n; j++)
716 r[j] = 1;
717 return;
718 }
719
720 if (k == 0) {
721 for (j = i; j < n; j++)
722 r[j] = 0;
723 return;
724 }
725
726 v = binomial(n-i-1, k);
727 if (s >= v) {
728 r[i] = 1;
729 k--;
730 s -= v;
731 } else {
732 r[i] = 0;
733 }
734 }
735}
736
737static void
738int_to_digit_array(int a, int b, int n, int *r)
739{
740 int i;
741
742 if (b <= 1)
743 for (i = 0; i < n; i++)
744 r[i] = 0;
745 else
746 for (i = 0; i < n; i++, a /= b)
747 r[i] = a % b;
748}
749
750static void
751int_to_sum_zero_array(int x, int b, int n, int *a)
752{
753 int i, s = 0;
754
755 if (b <= 1) {
756 for (i = 0; i < n; i++)
757 a[i] = 0;
758 } else {
759 int_to_digit_array(x, b, n-1, a);
760 for (i = 0; i < n - 1; i++)
761 s = (s + a[i]) % b;
762 a[n-1] = (b - s) % b;
763 }
764}
765
766static int
767invert_digits(int a, int b, int n)
768{
769 int i, ret, *r = malloc(n * sizeof(int));
770
771 int_to_digit_array(a, b, n, r);
772 for (i = 0; i < n; i++)
773 r[i] = (b-r[i]) % b;
774
775 ret = digit_array_to_int(r, n, b);
776 free(r);
777 return ret;
778}
779
780static bool
781is_perm(int *a, int n)
782{
783 int *aux = malloc(n * sizeof(int));
784 int i;
785
786 for (i = 0; i < n; i++)
787 if (a[i] < 0 || a[i] >= n)
788 return false;
789 else
790 aux[a[i]] = 1;
791
792 for (i = 0; i < n; i++)
793 if (!aux[i])
794 return false;
795
796 free(aux);
797
798 return true;
799}
800
801static bool
802is_subset(int *a, int n, int k)
803{
804 int i, sum = 0;
805
806 for (i = 0; i < n; i++)
807 sum += a[i] ? 1 : 0;
808
809 return sum == k;
810}
811
812static Cube
813move_via_arrays(CubeArray *arr, Cube c, PieceFilter f)
814{
815 CubeArray *arrc = new_cubearray(c, f);
816 Cube ret;
817
818 if (f.epose || f.eposs || f.eposm)
819 apply_permutation(arr->ep, arrc->ep, 12);
820
821 if (f.eofb) {
822 apply_permutation(arr->ep, arrc->eofb, 12);
823 sum_arrays_mod(arr->eofb, arrc->eofb, 12, 2);
824 }
825
826 if (f.eorl) {
827 apply_permutation(arr->ep, arrc->eorl, 12);
828 sum_arrays_mod(arr->eorl, arrc->eorl, 12, 2);
829 }
830
831 if (f.eoud) {
832 apply_permutation(arr->ep, arrc->eoud, 12);
833 sum_arrays_mod(arr->eoud, arrc->eoud, 12, 2);
834 }
835
836 if (f.cp)
837 apply_permutation(arr->cp, arrc->cp, 8);
838
839 if (f.coud) {
840 apply_permutation(arr->cp, arrc->coud, 8);
841 sum_arrays_mod(arr->coud, arrc->coud, 8, 3);
842 }
843
844 if (f.corl) {
845 apply_permutation(arr->cp, arrc->corl, 8);
846 sum_arrays_mod(arr->corl, arrc->corl, 8, 3);
847 }
848
849 if (f.cofb) {
850 apply_permutation(arr->cp, arrc->cofb, 8);
851 sum_arrays_mod(arr->cofb, arrc->cofb, 8, 3);
852 }
853
854 if (f.cpos)
855 apply_permutation(arr->cpos, arrc->cpos, 6);
856
857 ret = arrays_to_cube(arrc, f);
858 free_cubearray(arrc, f);
859
860 return ret;
861}
862
863static void
864movelist_to_position(Move *movelist, int *position)
865{
866 Move m;
867
868 for (m = 0; m < NMOVES && movelist[m] != NULLMOVE; m++)
869 position[movelist[m]] = m;
870}
871
872static void
873moveset_to_list(Moveset ms, Checker f, Move *r)
874{
875 Cube c;
876 int b[NMOVES];
877 int na = 0, nb = 0;
878 Move i;
879
880 if (ms == NULL) {
881 fprintf(stderr, "Error: no moveset given\n");
882 return;
883 }
884
885 for (i = U; i < NMOVES; i++) {
886 if (ms(i)) {
887 c = apply_move(i, (Cube){0});
888 if (f != NULL && f(c, 1))
889 r[na++] = i;
890 else
891 b[nb++] = i;
892 }
893 }
894
895 memcpy(r + na, b, nb * sizeof(Move));
896 r[na+nb] = NULLMOVE;
897}
898
899static AlgList *
900new_alglist()
901{
902 AlgList *ret = malloc(sizeof(AlgList));
903
904 ret->len = 0;
905 ret->first = NULL;
906 ret->last = NULL;
907
908 return ret;
909}
910
911static CubeArray *
912new_cubearray(Cube cube, PieceFilter f)
913{
914 CubeArray *arr = malloc(sizeof(CubeArray));
915
916 if (f.epose || f.eposs || f.eposm)
917 arr->ep = malloc(12 * sizeof(int));
918 if (f.eofb)
919 arr->eofb = malloc(12 * sizeof(int));
920 if (f.eorl)
921 arr->eorl = malloc(12 * sizeof(int));
922 if (f.eoud)
923 arr->eoud = malloc(12 * sizeof(int));
924 if (f.cp)
925 arr->cp = malloc(8 * sizeof(int));
926 if (f.coud)
927 arr->coud = malloc(8 * sizeof(int));
928 if (f.corl)
929 arr->corl = malloc(8 * sizeof(int));
930 if (f.cofb)
931 arr->cofb = malloc(8 * sizeof(int));
932 if (f.cpos)
933 arr->cpos = malloc(6 * sizeof(int));
934
935 cube_to_arrays(cube, arr, f);
936
937 return arr;
938}
939
940static int
941perm_sign(int *a, int n)
942{
943 int i, j, ret = 0;
944
945 if (!is_perm(a,n))
946 return -1;
947
948 for (i = 0; i < n; i++)
949 for (j = i+1; j < n; j++)
950 ret += (a[i] > a[j]) ? 1 : 0;
951
952 return ret % 2;
953}
954
955static int
956perm_to_index(int *a, int n)
957{
958 int i, j, c, ret = 0;
959
960 if (!is_perm(a, n))
961 return -1;
962
963 for (i = 0; i < n; i++) {
964 c = 0;
965 for (j = i+1; j < n; j++)
966 c += (a[i] > a[j]) ? 1 : 0;
967 ret += factorial(n-i-1) * c;
968 }
969
970 return ret;
971}
972
973static int
974powint(int a, int b)
975{
976 if (b < 0)
977 return 0;
978 if (b == 0)
979 return 1;
980
981 if (b % 2)
982 return a * powint(a, b-1);
983 else
984 return powint(a*a, b/2);
985}
986
987static bool
988ptable_has_reached(PruneData *pd, uint64_t ind)
989{
990 return (ind % 2) ? pd->reached[ind/2] / 16 : pd->reached[ind/2] % 16;
991}
992
993static void
994ptable_set_reached(PruneData *pd, uint64_t ind)
995{
996 uint8_t oldval2 = pd->reached[ind/2];
997 int other = (ind % 2) ? oldval2 % 16 : oldval2 / 16;
998
999 pd->reached[ind/2] = (ind % 2) ? 16 + other : 16*other + 1;
1000}
1001
1002static void
1003ptable_update(PruneData *pd, uint64_t ind, int n)
1004{
1005 uint8_t oldval2 = pd->ptable[ind/2];
1006 int other = (ind % 2) ? oldval2 % 16 : oldval2 / 16;
1007
1008 pd->ptable[ind/2] = (ind % 2) ? 16*n + other : 16*other + n;
1009 pd->n++;
1010}
1011
1012static void
1013realloc_alg(Alg *alg, int n)
1014{
1015 if (alg == NULL) {
1016 fprintf(stderr, "Error: trying to reallocate NULL alg.\n");
1017 return;
1018 }
1019
1020 if (n < alg->len) {
1021 fprintf(stderr, "Error: alg too long for reallocation ");
1022 fprintf(stderr, "(%d vs %d)\n", alg->len, n);
1023 return;
1024 }
1025
1026 if (n > 1000000) {
1027 fprintf(stderr, "Warning: very long alg,");
1028 fprintf(stderr, "something might go wrong.\n");
1029 }
1030
1031 alg->move = realloc(alg->move, n * sizeof(int));
1032 alg->inv = realloc(alg->inv, n * sizeof(int));
1033 alg->allocated = n;
1034}
1035
1036static bool
1037read_algset_file(AlgSet *as)
1038{
1039 return false;
1040}
1041
1042static bool
1043read_mtables_file()
1044{
1045 FILE *f;
1046 char fname[strlen(tabledir)+20];
1047 int m, b = sizeof(int);
1048 bool r = true;
1049
1050 strcpy(fname, tabledir);
1051 strcat(fname, "/mtables");
1052
1053 if ((f = fopen(fname, "rb")) == NULL)
1054 return false;
1055
1056 for (m = 0; m < NMOVES; m++) {
1057 r = r && fread(epose_mtable[m], b, me[0], f) == me[0];
1058 r = r && fread(eposs_mtable[m], b, me[1], f) == me[1];
1059 r = r && fread(eposm_mtable[m], b, me[2], f) == me[2];
1060 r = r && fread(eofb_mtable[m], b, me[3], f) == me[3];
1061 r = r && fread(eorl_mtable[m], b, me[4], f) == me[4];
1062 r = r && fread(eoud_mtable[m], b, me[5], f) == me[5];
1063 r = r && fread(cp_mtable[m], b, me[6], f) == me[6];
1064 r = r && fread(coud_mtable[m], b, me[7], f) == me[7];
1065 r = r && fread(corl_mtable[m], b, me[8], f) == me[8];
1066 r = r && fread(cofb_mtable[m], b, me[9], f) == me[9];
1067 r = r && fread(cpos_mtable[m], b, me[10], f) == me[10];
1068 }
1069
1070 fclose(f);
1071 return r;
1072}
1073
1074static bool
1075read_ptable_file(PruneData *pd)
1076{
1077 FILE *f;
1078 char fname[strlen(tabledir)+100];
1079 uint64_t r;
1080
1081 strcpy(fname, tabledir);
1082 strcat(fname, "/");
1083 strcat(fname, pd->filename);
1084
1085 if ((f = fopen(fname, "rb")) == NULL)
1086 return false;
1087
1088 r = fread(pd->ptable, sizeof(uint8_t), ptablesize(pd), f);
1089 fclose(f);
1090
1091 return r == ptablesize(pd);
1092}
1093
1094static bool
1095read_ttables_file()
1096{
1097 FILE *f;
1098 char fname[strlen(tabledir)+20];
1099 int b = sizeof(int);
1100 bool r = true;
1101 Move m;
1102
1103 strcpy(fname, tabledir);
1104 strcat(fname, "/");
1105 strcat(fname, "ttables");
1106
1107 if ((f = fopen(fname, "rb")) == NULL)
1108 return false;
1109
1110 for (m = 0; m < NTRANS; m++) {
1111 r = r && fread(epose_ttable[m], b, me[0], f) == me[0];
1112 r = r && fread(eposs_ttable[m], b, me[1], f) == me[1];
1113 r = r && fread(eposm_ttable[m], b, me[2], f) == me[2];
1114 r = r && fread(eo_ttable[m], b, me[3], f) == me[3];
1115 r = r && fread(cp_ttable[m], b, me[6], f) == me[6];
1116 r = r && fread(co_ttable[m], b, me[7], f) == me[7];
1117 r = r && fread(cpos_ttable[m], b, me[10], f) == me[10];
1118 r = r && fread(moves_ttable[m], b, me[11], f) == me[11];
1119 }
1120
1121 fclose(f);
1122 return r;
1123}
1124
1125static Cube
1126rotate_via_compose(Trans r, Cube c, PieceFilter f)
1127{
1128 Alg *inv;
1129 static int zero12[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1130 static int zero8[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
1131 static CubeArray ma = {
1132 .ep = ep_mirror,
1133 .eofb = zero12,
1134 .eorl = zero12,
1135 .eoud = zero12,
1136 .cp = cp_mirror,
1137 .coud = zero8,
1138 .corl = zero8,
1139 .cofb = zero8,
1140 .cpos = cpos_mirror
1141 };
1142
1143 Cube ret;
1144
1145 if (r != mirror) {
1146 ret = apply_alg_generic(trans_algs[r], c, f, true);
1147 inv = on_inverse(trans_algs[r]);
1148 ret = apply_alg_generic(inv, ret, f, true);
1149 free_alg(inv);
1150 } else {
1151 ret = move_via_arrays(&ma, (Cube){0}, f);
1152 ret = compose_filtered(c, ret, f);
1153 ret = move_via_arrays(&ma, ret, f);
1154 }
1155
1156 return ret;
1157}
1158
1159static int
1160subset_to_index(int *a, int n, int k)
1161{
1162 int i, ret = 0;
1163
1164 if (!is_subset(a, n, k))
1165 return binomial(n, k);
1166
1167 for (i = 0; i < n; i++) {
1168 if (k == n-i)
1169 return ret;
1170 if (a[i]) {
1171 ret += binomial(n-i-1, k);
1172 k--;
1173 }
1174 }
1175
1176 return ret;
1177}
1178
1179static void
1180sum_arrays_mod(int *src, int *dst, int n, int m)
1181{
1182 int i;
1183
1184 for (i = 0; i < n; i++)
1185 dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m;
1186}
1187
1188static void
1189swap(int *a, int *b)
1190{
1191 int aux;
1192
1193 aux = *a;
1194 *a = *b;
1195 *b = aux;
1196}
1197
1198static bool
1199write_algset_file(AlgSet *as)
1200{
1201 return false;
1202}
1203
1204static bool
1205write_mtables_file()
1206{
1207 FILE *f;
1208 char fname[strlen(tabledir)+20];
1209 int m, b = sizeof(int);
1210 bool r = true;
1211
1212 strcpy(fname, tabledir);
1213 strcat(fname, "/mtables");
1214
1215 if ((f = fopen(fname, "wb")) == NULL)
1216 return false;
1217
1218 for (m = 0; m < NMOVES; m++) {
1219 r = r && fwrite(epose_mtable[m], b, me[0], f) == me[0];
1220 r = r && fwrite(eposs_mtable[m], b, me[1], f) == me[1];
1221 r = r && fwrite(eposm_mtable[m], b, me[2], f) == me[2];
1222 r = r && fwrite(eofb_mtable[m], b, me[3], f) == me[3];
1223 r = r && fwrite(eorl_mtable[m], b, me[4], f) == me[4];
1224 r = r && fwrite(eoud_mtable[m], b, me[5], f) == me[5];
1225 r = r && fwrite(cp_mtable[m], b, me[6], f) == me[6];
1226 r = r && fwrite(coud_mtable[m], b, me[7], f) == me[7];
1227 r = r && fwrite(corl_mtable[m], b, me[8], f) == me[8];
1228 r = r && fwrite(cofb_mtable[m], b, me[9], f) == me[9];
1229 r = r && fwrite(cpos_mtable[m], b, me[10], f) == me[10];
1230 }
1231
1232 fclose(f);
1233 return r;
1234}
1235
1236static bool
1237write_ptable_file(PruneData *pd)
1238{
1239 FILE *f;
1240 char fname[strlen(tabledir)+100];
1241 uint64_t written;
1242
1243 strcpy(fname, tabledir);
1244 strcat(fname, "/");
1245 strcat(fname, pd->filename);
1246
1247 if ((f = fopen(fname, "wb")) == NULL)
1248 return false;
1249
1250 written = fwrite(pd->ptable, sizeof(uint8_t), ptablesize(pd), f);
1251 fclose(f);
1252
1253 return written == ptablesize(pd);
1254}
1255
1256static bool
1257write_ttables_file()
1258{
1259 FILE *f;
1260 char fname[strlen(tabledir)+20];
1261 bool r = true;
1262 int b = sizeof(int);
1263 Move m;
1264
1265 strcpy(fname, tabledir);
1266 strcat(fname, "/ttables");
1267
1268 if ((f = fopen(fname, "wb")) == NULL)
1269 return false;
1270
1271 for (m = 0; m < NTRANS; m++) {
1272 r = r && fwrite(epose_ttable[m], b, me[0], f) == me[0];
1273 r = r && fwrite(eposs_ttable[m], b, me[1], f) == me[1];
1274 r = r && fwrite(eposm_ttable[m], b, me[2], f) == me[2];
1275 r = r && fwrite(eo_ttable[m], b, me[3], f) == me[3];
1276 r = r && fwrite(cp_ttable[m], b, me[6], f) == me[6];
1277 r = r && fwrite(co_ttable[m], b, me[7], f) == me[7];
1278 r = r && fwrite(cpos_ttable[m], b, me[10], f) == me[10];
1279 r = r && fwrite(moves_ttable[m], b, me[11], f) == me[11];
1280 }
1281
1282 fclose(f);
1283 return r;
1284}
1285
1286/* Init functions implementation *********************************************/
1287
1288static void
1289init_auxtables()
1290{
1291 Cube c1, c2;
1292 CubeArray *arr;
1293 uint64_t ui, uj;
1294 int i, j, k, auxarr[12];
1295 bool cij, p1, p2;
1296
1297 for (ui = 0; ui < FACTORIAL6; ui++) {
1298 arr = new_cubearray((Cube){.cpos = ui}, pf_cpos);
1299 for (i = 0; i < 6; i++) {
1300 what_center_at_aux[ui][i] = arr->cpos[i];
1301 where_is_center_aux[ui][arr->cpos[i]] = i;
1302 }
1303 free_cubearray(arr, pf_cpos);
1304 }
1305
1306 for (ui = 0; ui < FACTORIAL8; ui++) {
1307 arr = new_cubearray((Cube){.cp = ui}, pf_cp);
1308 for (i = 0; i < 8; i++) {
1309 what_corner_at_aux[ui][i] = arr->cp[i];
1310 where_is_corner_aux[ui][arr->cp[i]] = i;
1311 }
1312 free_cubearray(arr, pf_cp);
1313 }
1314
1315 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
1316 arr = new_cubearray((Cube){.epose = ui}, pf_e);
1317 for (i = 0; i < 12; i++)
1318 if (edge_slice(arr->ep[i]) == 0)
1319 where_is_edge_aux[0][ui][arr->ep[i]] = i;
1320 free_cubearray(arr, pf_e);
1321
1322 arr = new_cubearray((Cube){.eposs = ui}, pf_s);
1323 for (i = 0; i < 12; i++)
1324 if (edge_slice(arr->ep[i]) == 1)
1325 where_is_edge_aux[1][ui][arr->ep[i]] = i;
1326 free_cubearray(arr, pf_s);
1327
1328 arr = new_cubearray((Cube){.eposm = ui}, pf_m);
1329 for (i = 0; i < 12; i++)
1330 if (edge_slice(arr->ep[i]) == 2)
1331 where_is_edge_aux[2][ui][arr->ep[i]] = i;
1332 free_cubearray(arr, pf_m);
1333 }
1334
1335 for (ui = 0; ui < POW3TO7; ui++) {
1336 int_to_sum_zero_array(ui, 3, 8, auxarr);
1337 what_orientation_last_corner_aux[ui] = auxarr[7];
1338 }
1339
1340 for (ui = 0; ui < POW2TO11; ui++) {
1341 int_to_sum_zero_array(ui, 2, 12, auxarr);
1342 what_orientation_last_edge_aux[ui] = auxarr[11];
1343 }
1344
1345 for (ui = 0; ui < BINOM12ON4; ui++)
1346 for (uj = 0; uj < BINOM12ON4; uj++)
1347 epos_dependent_aux[ui][uj]=epos_dependent_pos(ui, uj);
1348
1349 for (i = 0; i < NMOVES; i++) {
1350 for (j = 0; j < NMOVES; j++) {
1351 c1 = apply_move(i, apply_move(j, (Cube){0}));
1352 c2 = apply_move(j, apply_move(i, (Cube){0}));
1353 commute[i][j] = equal(c1, c2) && i && j;
1354 }
1355 }
1356
1357 for (i = 0; i < NMOVES; i++) {
1358 for (j = 0; j < NMOVES; j++) {
1359 for (k = 0; k < NMOVES; k++) {
1360 p1 = j && base_move(j) == base_move(k);
1361 p2 = i && base_move(i) == base_move(k);
1362 cij = commute[i][j];
1363 possible_next[i][j][k] = !(p1 || (cij && p2));
1364 }
1365 }
1366 }
1367
1368 for (i = 0; i < NMOVES; i++)
1369 inverse_move_aux[i] = i ? i + 2 - 2*((i-1)%3) : NULLMOVE;
1370
1371 /* Is there a more elegant way? */
1372 inverse_trans_aux[uf] = uf;
1373 inverse_trans_aux[ur] = ul;
1374 inverse_trans_aux[ul] = ur;
1375 inverse_trans_aux[ub] = ub;
1376
1377 inverse_trans_aux[df] = df;
1378 inverse_trans_aux[dr] = dr;
1379 inverse_trans_aux[dl] = dl;
1380 inverse_trans_aux[db] = db;
1381
1382 inverse_trans_aux[rf] = lf;
1383 inverse_trans_aux[rd] = bl;
1384 inverse_trans_aux[rb] = rb;
1385 inverse_trans_aux[ru] = fr;
1386
1387 inverse_trans_aux[lf] = rf;
1388 inverse_trans_aux[ld] = br;
1389 inverse_trans_aux[lb] = lb;
1390 inverse_trans_aux[lu] = fl;
1391
1392 inverse_trans_aux[fu] = fu;
1393 inverse_trans_aux[fr] = ru;
1394 inverse_trans_aux[fd] = bu;
1395 inverse_trans_aux[fl] = lu;
1396
1397 inverse_trans_aux[bu] = fd;
1398 inverse_trans_aux[br] = ld;
1399 inverse_trans_aux[bd] = bd;
1400 inverse_trans_aux[bl] = rd;
1401
1402 inverse_trans_aux[mirror] = mirror;
1403}
1404
1405/*
1406 * There is certainly a bette way to do this, but for now I just use
1407 * a "graph coloring" algorithm to compute the cosets for cphtr.
1408 *
1409 * For doing it better "Mathematically", we need 3 things:
1410 * - Checking that cp separates the orbits (UFR,UBL,DFL,DBR) and the other
1411 * This is easy and it is done in the commented function cphtr_cp().
1412 * - Check that there is no ep/cp parity
1413 * - Check that we are not in the "3c" case; this is the part I don't
1414 * know how to do.
1415 */
1416static void
1417init_cphtr_cosets()
1418{
1419 unsigned int i;
1420 int c = 0;
1421
1422 for (i = 0; i < FACTORIAL8; i++)
1423 cphtr_cosets[i] = -1;
1424
1425 for (i = 0; i < FACTORIAL8; i++)
1426 if (cphtr_cosets[i] == -1)
1427 init_cphtr_cosets_bfs(i, c++);
1428}
1429
1430static void
1431init_cphtr_cosets_bfs(int i, int c)
1432{
1433 int j, jj, k, next[FACTORIAL8], next2[FACTORIAL8], n, n2;
1434 Move moves[6] = {U2, D2, R2, L2, F2, B2};
1435
1436 n = 1;
1437 next[0] = i;
1438 cphtr_cosets[i] = c;
1439
1440 while (n != 0) {
1441 for (j = 0, n2 = 0; j < n; j++) {
1442 for (k = 0; k < 6; k++) {
1443 jj = cp_mtable[moves[k]][next[j]];
1444 if (cphtr_cosets[jj] == -1) {
1445 cphtr_cosets[jj] = c;
1446 next2[n2++] = jj;
1447 }
1448 }
1449 }
1450
1451 for (j = 0; j < n2; j++)
1452 next[j] = next2[j];
1453 n = n2;
1454 }
1455}
1456
1457static void
1458init_environment()
1459{
1460 char *nissydata = getenv("NISSYDATA");
1461 char *localdata = getenv("XDG_DATA_HOME");
1462 char *home = getenv("HOME");
1463 bool read, write;
1464
1465 if (nissydata != NULL) {
1466 tabledir = malloc(strlen(nissydata) * sizeof(char) + 20);
1467 strcpy(tabledir, nissydata);
1468 } else if (localdata != NULL) {
1469 tabledir = malloc(strlen(localdata) * sizeof(char) + 20);
1470 strcpy(tabledir, localdata);
1471 strcat(tabledir, "/nissy");
1472 } else if (home != NULL) {
1473 tabledir = malloc(strlen(home) * sizeof(char) + 20);
1474 strcpy(tabledir, home);
1475 strcat(tabledir, "/.nissy");
1476 }
1477
1478 mkdir(tabledir, 0777);
1479 strcat(tabledir, "/tables");
1480 mkdir(tabledir, 0777);
1481
1482 read = !access(tabledir, R_OK);
1483 write = !access(tabledir, W_OK);
1484
1485 if (!read) {
1486 fprintf(stderr, "Table files cannot be read.\n");
1487 } else if (!write) {
1488 fprintf(stderr, "Data directory not writable: ");
1489 fprintf(stderr, "tables can be loaded, but not saved.\n");
1490 }
1491}
1492
1493static void
1494init_moves() {
1495 Cube c;
1496 CubeArray arrs;
1497 int i;
1498 unsigned int ui;
1499 Move m;
1500
1501 /* Generate all move cycles and flips; I do this regardless */
1502 for (i = 0; i < NMOVES; i++) {
1503 if (i == U || i == x || i == y)
1504 continue;
1505
1506 c = apply_alg_generic(equiv_alg[i], (Cube){0}, pf_all, false);
1507
1508 arrs = (CubeArray) {
1509 edge_cycle[i],
1510 eofb_flipped[i],
1511 eorl_flipped[i],
1512 eoud_flipped[i],
1513 corner_cycle[i],
1514 coud_flipped[i],
1515 corl_flipped[i],
1516 cofb_flipped[i],
1517 center_cycle[i]
1518 };
1519 cube_to_arrays(c, &arrs, pf_all);
1520 }
1521
1522 if (read_mtables_file())
1523 return;
1524
1525 fprintf(stderr, "Cannot load %s, generating it\n", "mtables");
1526
1527 /* Initialize transition tables */
1528 for (m = 0; m < NMOVES; m++) {
1529 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
1530 c = (Cube){ .epose = ui };
1531 c = apply_move_cubearray(m, c, pf_e);
1532 epose_mtable[m][ui] = c.epose;
1533
1534 c = (Cube){ .eposs = ui };
1535 c = apply_move_cubearray(m, c, pf_s);
1536 eposs_mtable[m][ui] = c.eposs;
1537
1538 c = (Cube){ .eposm = ui };
1539 c = apply_move_cubearray(m, c, pf_m);
1540 eposm_mtable[m][ui] = c.eposm;
1541 }
1542 for (ui = 0; ui < POW2TO11; ui++ ) {
1543 c = (Cube){ .eofb = ui };
1544 c = apply_move_cubearray(m, c, pf_eo);
1545 eofb_mtable[m][ui] = c.eofb;
1546
1547 c = (Cube){ .eorl = ui };
1548 c = apply_move_cubearray(m, c, pf_eo);
1549 eorl_mtable[m][ui] = c.eorl;
1550
1551 c = (Cube){ .eoud = ui };
1552 c = apply_move_cubearray(m, c, pf_eo);
1553 eoud_mtable[m][ui] = c.eoud;
1554 }
1555 for (ui = 0; ui < POW3TO7; ui++) {
1556 c = (Cube){ .coud = ui };
1557 c = apply_move_cubearray(m, c, pf_co);
1558 coud_mtable[m][ui] = c.coud;
1559
1560 c = (Cube){ .corl = ui };
1561 c = apply_move_cubearray(m, c, pf_co);
1562 corl_mtable[m][ui] = c.corl;
1563
1564 c = (Cube){ .cofb = ui };
1565 c = apply_move_cubearray(m, c, pf_co);
1566 cofb_mtable[m][ui] = c.cofb;
1567 }
1568 for (ui = 0; ui < FACTORIAL8; ui++) {
1569 c = (Cube){ .cp = ui };
1570 c = apply_move_cubearray(m, c, pf_cp);
1571 cp_mtable[m][ui] = c.cp;
1572 }
1573 for (ui = 0; ui < FACTORIAL6; ui++) {
1574 c = (Cube){ .cpos = ui };
1575 c = apply_move_cubearray(m, c, pf_cpos);
1576 cpos_mtable[m][ui] = c.cpos;
1577 }
1578 }
1579
1580 if (!write_mtables_file())
1581 fprintf(stderr, "Error writing mtables\n");
1582}
1583
1584static void
1585init_moves_aux()
1586{
1587 /* Some standard PieceFilters */
1588 pf_all.epose = true;
1589 pf_all.eposs = true;
1590 pf_all.eposm = true;
1591 pf_all.eofb = true;
1592 pf_all.eorl = true;
1593 pf_all.eoud = true;
1594 pf_all.cp = true;
1595 pf_all.cofb = true;
1596 pf_all.corl = true;
1597 pf_all.coud = true;
1598 pf_all.cpos = true;
1599
1600 pf_4val.epose = true;
1601 pf_4val.eposs = true;
1602 pf_4val.eposm = true;
1603 pf_4val.eofb = true;
1604 pf_4val.coud = true;
1605 pf_4val.cp = true;
1606
1607 pf_epcp.epose = true;
1608 pf_epcp.eposs = true;
1609 pf_epcp.eposm = true;
1610 pf_epcp.cp = true;
1611
1612 pf_cpos.cpos = true;
1613
1614 pf_cp.cp = true;
1615
1616 pf_ep.epose = true;
1617 pf_ep.eposs = true;
1618 pf_ep.eposm = true;
1619
1620 pf_e.epose = true;
1621 pf_s.eposs = true;
1622 pf_m.eposm = true;
1623
1624 pf_eo.eofb = true;
1625 pf_eo.eorl = true;
1626 pf_eo.eoud = true;
1627
1628 pf_co.cofb = true;
1629 pf_co.corl = true;
1630 pf_co.coud = true;
1631
1632 /* Used to convert to and from CubeArray */
1633 epe_solved[0] = FR;
1634 epe_solved[1] = FL;
1635 epe_solved[2] = BL;
1636 epe_solved[3] = BR;
1637
1638 eps_solved[0] = UL;
1639 eps_solved[1] = UR;
1640 eps_solved[2] = DL;
1641 eps_solved[3] = DR;
1642
1643 epm_solved[0] = UF;
1644 epm_solved[1] = UB;
1645 epm_solved[2] = DF;
1646 epm_solved[3] = DB;
1647
1648 /* Table sizes, used for reading and writing files */
1649 me[0] = FACTORIAL12/FACTORIAL8;
1650 me[1] = FACTORIAL12/FACTORIAL8;
1651 me[2] = FACTORIAL12/FACTORIAL8;
1652 me[3] = POW2TO11;
1653 me[4] = POW2TO11;
1654 me[5] = POW2TO11;
1655 me[6] = FACTORIAL8;
1656 me[7] = POW3TO7;
1657 me[8] = POW3TO7;
1658 me[9] = POW3TO7;
1659 me[10] = FACTORIAL6;
1660 me[11] = NMOVES;
1661
1662 /* Cycles *********************/
1663 edge_cycle[U][UF] = UR;
1664 edge_cycle[U][UL] = UF;
1665 edge_cycle[U][UB] = UL;
1666 edge_cycle[U][UR] = UB;
1667 edge_cycle[U][DF] = DF;
1668 edge_cycle[U][DL] = DL;
1669 edge_cycle[U][DB] = DB;
1670 edge_cycle[U][DR] = DR;
1671 edge_cycle[U][FR] = FR;
1672 edge_cycle[U][FL] = FL;
1673 edge_cycle[U][BL] = BL;
1674 edge_cycle[U][BR] = BR;
1675
1676 edge_cycle[x][UF] = DF;
1677 edge_cycle[x][UL] = FL;
1678 edge_cycle[x][UB] = UF;
1679 edge_cycle[x][UR] = FR;
1680 edge_cycle[x][DF] = DB;
1681 edge_cycle[x][DL] = BL;
1682 edge_cycle[x][DB] = UB;
1683 edge_cycle[x][DR] = BR;
1684 edge_cycle[x][FR] = DR;
1685 edge_cycle[x][FL] = DL;
1686 edge_cycle[x][BL] = UL;
1687 edge_cycle[x][BR] = UR;
1688
1689 edge_cycle[y][UF] = UR;
1690 edge_cycle[y][UL] = UF;
1691 edge_cycle[y][UB] = UL;
1692 edge_cycle[y][UR] = UB;
1693 edge_cycle[y][DF] = DR;
1694 edge_cycle[y][DL] = DF;
1695 edge_cycle[y][DB] = DL;
1696 edge_cycle[y][DR] = DB;
1697 edge_cycle[y][FR] = BR;
1698 edge_cycle[y][FL] = FR;
1699 edge_cycle[y][BL] = FL;
1700 edge_cycle[y][BR] = BL;
1701
1702 corner_cycle[U][UFR] = UBR;
1703 corner_cycle[U][UFL] = UFR;
1704 corner_cycle[U][UBL] = UFL;
1705 corner_cycle[U][UBR] = UBL;
1706 corner_cycle[U][DFR] = DFR;
1707 corner_cycle[U][DFL] = DFL;
1708 corner_cycle[U][DBL] = DBL;
1709 corner_cycle[U][DBR] = DBR;
1710
1711 corner_cycle[x][UFR] = DFR;
1712 corner_cycle[x][UFL] = DFL;
1713 corner_cycle[x][UBL] = UFL;
1714 corner_cycle[x][UBR] = UFR;
1715 corner_cycle[x][DFR] = DBR;
1716 corner_cycle[x][DFL] = DBL;
1717 corner_cycle[x][DBL] = UBL;
1718 corner_cycle[x][DBR] = UBR;
1719
1720 corner_cycle[y][UFR] = UBR;
1721 corner_cycle[y][UFL] = UFR;
1722 corner_cycle[y][UBL] = UFL;
1723 corner_cycle[y][UBR] = UBL;
1724 corner_cycle[y][DFR] = DBR;
1725 corner_cycle[y][DFL] = DFR;
1726 corner_cycle[y][DBL] = DFL;
1727 corner_cycle[y][DBR] = DBL;
1728
1729 center_cycle[U][U_center] = U_center;
1730 center_cycle[U][D_center] = D_center;
1731 center_cycle[U][R_center] = R_center;
1732 center_cycle[U][L_center] = L_center;
1733 center_cycle[U][F_center] = F_center;
1734 center_cycle[U][B_center] = B_center;
1735
1736 center_cycle[x][U_center] = F_center;
1737 center_cycle[x][D_center] = B_center;
1738 center_cycle[x][R_center] = R_center;
1739 center_cycle[x][L_center] = L_center;
1740 center_cycle[x][F_center] = D_center;
1741 center_cycle[x][B_center] = U_center;
1742
1743 center_cycle[y][U_center] = U_center;
1744 center_cycle[y][D_center] = D_center;
1745 center_cycle[y][R_center] = B_center;
1746 center_cycle[y][L_center] = F_center;
1747 center_cycle[y][F_center] = R_center;
1748 center_cycle[y][B_center] = L_center;
1749
1750 /* Flipped pieces *************/
1751 eofb_flipped[x][UF] = 1;
1752 eofb_flipped[x][UB] = 1;
1753 eofb_flipped[x][DF] = 1;
1754 eofb_flipped[x][DB] = 1;
1755
1756 eofb_flipped[y][FR] = 1;
1757 eofb_flipped[y][FL] = 1;
1758 eofb_flipped[y][BL] = 1;
1759 eofb_flipped[y][BR] = 1;
1760
1761 eorl_flipped[x][UF] = 1;
1762 eorl_flipped[x][UL] = 1;
1763 eorl_flipped[x][UB] = 1;
1764 eorl_flipped[x][UR] = 1;
1765 eorl_flipped[x][DF] = 1;
1766 eorl_flipped[x][DL] = 1;
1767 eorl_flipped[x][DB] = 1;
1768 eorl_flipped[x][DR] = 1;
1769 eorl_flipped[x][FR] = 1;
1770 eorl_flipped[x][FL] = 1;
1771 eorl_flipped[x][BL] = 1;
1772 eorl_flipped[x][BR] = 1;
1773
1774 eorl_flipped[y][FR] = 1;
1775 eorl_flipped[y][FL] = 1;
1776 eorl_flipped[y][BL] = 1;
1777 eorl_flipped[y][BR] = 1;
1778
1779 eoud_flipped[U][UF] = 1;
1780 eoud_flipped[U][UL] = 1;
1781 eoud_flipped[U][UB] = 1;
1782 eoud_flipped[U][UR] = 1;
1783
1784 eoud_flipped[x][UF] = 1;
1785 eoud_flipped[x][UB] = 1;
1786 eoud_flipped[x][DF] = 1;
1787 eoud_flipped[x][DB] = 1;
1788
1789 eoud_flipped[y][UF] = 1;
1790 eoud_flipped[y][UL] = 1;
1791 eoud_flipped[y][UB] = 1;
1792 eoud_flipped[y][UR] = 1;
1793 eoud_flipped[y][DF] = 1;
1794 eoud_flipped[y][DL] = 1;
1795 eoud_flipped[y][DB] = 1;
1796 eoud_flipped[y][DR] = 1;
1797 eoud_flipped[y][FR] = 1;
1798 eoud_flipped[y][FL] = 1;
1799 eoud_flipped[y][BL] = 1;
1800 eoud_flipped[y][BR] = 1;
1801
1802 coud_flipped[x][UFR] = 2;
1803 coud_flipped[x][UFL] = 1;
1804 coud_flipped[x][UBR] = 1;
1805 coud_flipped[x][UBL] = 2;
1806 coud_flipped[x][DFR] = 1;
1807 coud_flipped[x][DFL] = 2;
1808 coud_flipped[x][DBR] = 2;
1809 coud_flipped[x][DBL] = 1;
1810
1811 corl_flipped[U][UFR] = 1;
1812 corl_flipped[U][UFL] = 2;
1813 corl_flipped[U][UBL] = 1;
1814 corl_flipped[U][UBR] = 2;
1815
1816 corl_flipped[y][UFR] = 1;
1817 corl_flipped[y][UFL] = 2;
1818 corl_flipped[y][UBL] = 1;
1819 corl_flipped[y][UBR] = 2;
1820 corl_flipped[y][DFR] = 2;
1821 corl_flipped[y][DFL] = 1;
1822 corl_flipped[y][DBL] = 2;
1823 corl_flipped[y][DBR] = 1;
1824
1825 cofb_flipped[U][UFR] = 2;
1826 cofb_flipped[U][UFL] = 1;
1827 cofb_flipped[U][UBL] = 2;
1828 cofb_flipped[U][UBR] = 1;
1829
1830 cofb_flipped[x][UFR] = 1;
1831 cofb_flipped[x][UFL] = 2;
1832 cofb_flipped[x][UBL] = 1;
1833 cofb_flipped[x][UBR] = 2;
1834 cofb_flipped[x][DFR] = 2;
1835 cofb_flipped[x][DFL] = 1;
1836 cofb_flipped[x][DBL] = 2;
1837 cofb_flipped[x][DBR] = 1;
1838
1839 cofb_flipped[y][UFR] = 2;
1840 cofb_flipped[y][UFL] = 1;
1841 cofb_flipped[y][UBL] = 2;
1842 cofb_flipped[y][UBR] = 1;
1843 cofb_flipped[y][DFR] = 1;
1844 cofb_flipped[y][DFL] = 2;
1845 cofb_flipped[y][DBL] = 1;
1846 cofb_flipped[y][DBR] = 2;
1847
1848 /* Equivalent moves ***********/
1849 equiv_alg[NULLMOVE] = new_alg("");
1850
1851 equiv_alg[U] = new_alg(" U ");
1852 equiv_alg[U2] = new_alg(" UU ");
1853 equiv_alg[U3] = new_alg(" UUU ");
1854 equiv_alg[D] = new_alg(" xx U xx ");
1855 equiv_alg[D2] = new_alg(" xx UU xx ");
1856 equiv_alg[D3] = new_alg(" xx UUU xx ");
1857 equiv_alg[R] = new_alg(" yx U xxxyyy ");
1858 equiv_alg[R2] = new_alg(" yx UU xxxyyy ");
1859 equiv_alg[R3] = new_alg(" yx UUU xxxyyy ");
1860 equiv_alg[L] = new_alg(" yyyx U xxxy ");
1861 equiv_alg[L2] = new_alg(" yyyx UU xxxy ");
1862 equiv_alg[L3] = new_alg(" yyyx UUU xxxy ");
1863 equiv_alg[F] = new_alg(" x U xxx ");
1864 equiv_alg[F2] = new_alg(" x UU xxx ");
1865 equiv_alg[F3] = new_alg(" x UUU xxx ");
1866 equiv_alg[B] = new_alg(" xxx U x ");
1867 equiv_alg[B2] = new_alg(" xxx UU x ");
1868 equiv_alg[B3] = new_alg(" xxx UUU x ");
1869
1870 equiv_alg[Uw] = new_alg(" xx U xx y ");
1871 equiv_alg[Uw2] = new_alg(" xx UU xx yy ");
1872 equiv_alg[Uw3] = new_alg(" xx UUU xx yyy ");
1873 equiv_alg[Dw] = new_alg(" U yyy ");
1874 equiv_alg[Dw2] = new_alg(" UU yy ");
1875 equiv_alg[Dw3] = new_alg(" UUU y ");
1876 equiv_alg[Rw] = new_alg(" yyyx U xxxy x ");
1877 equiv_alg[Rw2] = new_alg(" yyyx UU xxxy xx ");
1878 equiv_alg[Rw3] = new_alg(" yyyx UUU xxxy xxx ");
1879 equiv_alg[Lw] = new_alg(" yx U xxxyyy xxx ");
1880 equiv_alg[Lw2] = new_alg(" yx UU xxxyyy xx ");
1881 equiv_alg[Lw3] = new_alg(" yx UUU xxxyyy x ");
1882 equiv_alg[Fw] = new_alg(" xxx U x yxxxyyy ");
1883 equiv_alg[Fw2] = new_alg(" xxx UU x yxxyyy ");
1884 equiv_alg[Fw3] = new_alg(" xxx UUU x yxyyy ");
1885 equiv_alg[Bw] = new_alg(" x U xxx yxyyy ");
1886 equiv_alg[Bw2] = new_alg(" x UU xxx yxxyyy ");
1887 equiv_alg[Bw3] = new_alg(" x UUU xxx yxxxyyy ");
1888
1889 equiv_alg[M] = new_alg(" yx U xx UUU yxyyy ");
1890 equiv_alg[M2] = new_alg(" yx UU xx UU xxxy ");
1891 equiv_alg[M3] = new_alg(" yx UUU xx U yxxxy ");
1892 equiv_alg[S] = new_alg(" x UUU xx U yyyx ");
1893 equiv_alg[S2] = new_alg(" x UU xx UU yyx ");
1894 equiv_alg[S3] = new_alg(" x U xx UUU yx ");
1895 equiv_alg[E] = new_alg(" U xx UUU xxyyy ");
1896 equiv_alg[E2] = new_alg(" UU xx UU xxyy ");
1897 equiv_alg[E3] = new_alg(" UUU xx U xxy ");
1898
1899 equiv_alg[x] = new_alg(" x ");
1900 equiv_alg[x2] = new_alg(" xx ");
1901 equiv_alg[x3] = new_alg(" xxx ");
1902 equiv_alg[y] = new_alg(" y ");
1903 equiv_alg[y2] = new_alg(" yy ");
1904 equiv_alg[y3] = new_alg(" yyy ");
1905 equiv_alg[z] = new_alg(" yyy x y ");
1906 equiv_alg[z2] = new_alg(" yy xx ");
1907 equiv_alg[z3] = new_alg(" y x yyy ");
1908}
1909
1910static void
1911init_strings()
1912{
1913 strcpy(move_string [NULLMOVE], "-" );
1914 strcpy(move_string [U], "U" );
1915 strcpy(move_string [U2], "U2" );
1916 strcpy(move_string [U3], "U\'" );
1917 strcpy(move_string [D], "D" );
1918 strcpy(move_string [D2], "D2" );
1919 strcpy(move_string [D3], "D\'" );
1920 strcpy(move_string [R], "R" );
1921 strcpy(move_string [R2], "R2" );
1922 strcpy(move_string [R3], "R\'" );
1923 strcpy(move_string [L], "L" );
1924 strcpy(move_string [L2], "L2" );
1925 strcpy(move_string [L3], "L\'" );
1926 strcpy(move_string [F], "F" );
1927 strcpy(move_string [F2], "F2" );
1928 strcpy(move_string [F3], "F\'" );
1929 strcpy(move_string [B], "B" );
1930 strcpy(move_string [B2], "B2" );
1931 strcpy(move_string [B3], "B\'" );
1932 strcpy(move_string [Uw], "Uw" );
1933 strcpy(move_string [Uw2], "Uw2" );
1934 strcpy(move_string [Uw3], "Uw\'" );
1935 strcpy(move_string [Dw], "Dw" );
1936 strcpy(move_string [Dw2], "Dw2" );
1937 strcpy(move_string [Dw3], "Dw\'" );
1938 strcpy(move_string [Rw], "Rw" );
1939 strcpy(move_string [Rw2], "Rw2" );
1940 strcpy(move_string [Rw3], "Rw\'" );
1941 strcpy(move_string [Lw], "Lw" );
1942 strcpy(move_string [Lw2], "Lw2" );
1943 strcpy(move_string [Lw3], "Lw\'" );
1944 strcpy(move_string [Fw], "Fw" );
1945 strcpy(move_string [Fw2], "Fw2" );
1946 strcpy(move_string [Fw3], "Fw\'" );
1947 strcpy(move_string [Bw], "Bw" );
1948 strcpy(move_string [Bw2], "Bw2" );
1949 strcpy(move_string [Bw3], "Bw\'" );
1950 strcpy(move_string [M], "M" );
1951 strcpy(move_string [M2], "M2" );
1952 strcpy(move_string [M3], "M\'" );
1953 strcpy(move_string [S], "S" );
1954 strcpy(move_string [S2], "S2" );
1955 strcpy(move_string [S3], "S\'" );
1956 strcpy(move_string [E], "E" );
1957 strcpy(move_string [E2], "E2" );
1958 strcpy(move_string [E3], "E\'" );
1959 strcpy(move_string [x], "x" );
1960 strcpy(move_string [x2], "x2" );
1961 strcpy(move_string [x3], "x\'" );
1962 strcpy(move_string [y], "y" );
1963 strcpy(move_string [y2], "y2" );
1964 strcpy(move_string [y3], "y\'" );
1965 strcpy(move_string [z], "z" );
1966 strcpy(move_string [z2], "z2" );
1967 strcpy(move_string [z3], "z\'" );
1968
1969 strcpy(edge_string [UF], "UF" );
1970 strcpy(edge_string [UL], "UL" );
1971 strcpy(edge_string [UB], "UB" );
1972 strcpy(edge_string [UR], "UR" );
1973 strcpy(edge_string [DF], "DF" );
1974 strcpy(edge_string [DL], "DL" );
1975 strcpy(edge_string [DB], "DB" );
1976 strcpy(edge_string [DR], "DR" );
1977 strcpy(edge_string [FR], "FR" );
1978 strcpy(edge_string [FL], "FL" );
1979 strcpy(edge_string [BL], "BL" );
1980 strcpy(edge_string [BR], "BR" );
1981
1982 strcpy(corner_string [UFR], "UFR" );
1983 strcpy(corner_string [UFL], "UFL" );
1984 strcpy(corner_string [UBL], "UBL" );
1985 strcpy(corner_string [UBR], "UBR" );
1986 strcpy(corner_string [DFR], "DFR" );
1987 strcpy(corner_string [DFL], "DFL" );
1988 strcpy(corner_string [DBL], "DBL" );
1989 strcpy(corner_string [DBR], "DBR" );
1990
1991 strcpy(center_string [U_center], "U" );
1992 strcpy(center_string [D_center], "D" );
1993 strcpy(center_string [R_center], "R" );
1994 strcpy(center_string [L_center], "L" );
1995 strcpy(center_string [F_center], "F" );
1996 strcpy(center_string [B_center], "B" );
1997}
1998
1999static void
2000init_trans() {
2001 Cube aux, cube, c[3];
2002 CubeArray epcp;
2003 int eparr[12], eoarr[12];
2004 int cparr[8], coarr[8];
2005 int i;
2006 unsigned int ui;
2007 bool b1, b2, b3;
2008 Move mi, move;
2009 Trans m;
2010
2011 /* Compute sources */
2012 for (i = 0; i < NTRANS; i++) {
2013 if (i == mirror)
2014 cube = (Cube){0};
2015 else
2016 cube = apply_alg(trans_algs[i], (Cube){0});
2017
2018 epose_source[i] = edge_slice(what_edge_at(cube, FR));
2019 eposs_source[i] = edge_slice(what_edge_at(cube, UR));
2020 eposm_source[i] = edge_slice(what_edge_at(cube, UF));
2021 eofb_source[i] = what_center_at(cube, F_center)/2;
2022 eorl_source[i] = what_center_at(cube, R_center)/2;
2023 eoud_source[i] = what_center_at(cube, U_center)/2;
2024 coud_source[i] = what_center_at(cube, U_center)/2;
2025 cofb_source[i] = what_center_at(cube, F_center)/2;
2026 corl_source[i] = what_center_at(cube, R_center)/2;
2027 }
2028
2029 if (read_ttables_file())
2030 return;
2031
2032 fprintf(stderr, "Cannot load %s, generating it\n", "ttables");
2033
2034 /* Initialize tables */
2035 for (m = 0; m < NTRANS; m++) {
2036 if (m == mirror) {
2037 memcpy(eparr, ep_mirror, 12 * sizeof(int));
2038 memcpy(cparr, cp_mirror, 8 * sizeof(int));
2039 } else {
2040 epcp = (CubeArray){ .ep = eparr, .cp = cparr };
2041 cube = apply_alg(trans_algs[m], (Cube){0});
2042 cube_to_arrays(cube, &epcp, pf_epcp);
2043 }
2044
2045 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
2046 c[0] = admissible_ep((Cube){ .epose = ui }, pf_e);
2047 c[1] = admissible_ep((Cube){ .eposs = ui }, pf_s);
2048 c[2] = admissible_ep((Cube){ .eposm = ui }, pf_m);
2049
2050 cube = rotate_via_compose(m,c[epose_source[m]],pf_ep);
2051 epose_ttable[m][ui] = cube.epose;
2052
2053 cube = rotate_via_compose(m,c[eposs_source[m]],pf_ep);
2054 eposs_ttable[m][ui] = cube.eposs;
2055
2056 cube = rotate_via_compose(m,c[eposm_source[m]],pf_ep);
2057 eposm_ttable[m][ui] = cube.eposm;
2058 }
2059 for (ui = 0; ui < POW2TO11; ui++ ) {
2060 int_to_sum_zero_array(ui, 2, 12, eoarr);
2061 apply_permutation(eparr, eoarr, 12);
2062 eo_ttable[m][ui] = digit_array_to_int(eoarr, 11, 2);
2063 }
2064 for (ui = 0; ui < POW3TO7; ui++) {
2065 int_to_sum_zero_array(ui, 3, 8, coarr);
2066 apply_permutation(cparr, coarr, 8);
2067 co_ttable[m][ui] = digit_array_to_int(coarr, 7, 3);
2068 if (m == mirror)
2069 co_ttable[m][ui] =
2070 invert_digits(co_ttable[m][ui], 3, 7);
2071 }
2072 for (ui = 0; ui < FACTORIAL8; ui++) {
2073 cube = (Cube){ .cp = ui };
2074 cube = rotate_via_compose(m, cube, pf_cp);
2075 cp_ttable[m][ui] = cube.cp;
2076 }
2077 for (ui = 0; ui < FACTORIAL6; ui++) {
2078 cube = (Cube){ .cpos = ui };
2079 cube = rotate_via_compose(m, cube, pf_cpos);
2080 cpos_ttable[m][ui] = cube.cpos;
2081 }
2082 for (mi = 0; mi < NMOVES; mi++) {
2083 if (m == mirror) {
2084 b1 = (mi >= U && mi <= Bw3);
2085 b2 = (mi >= S && mi <= E3);
2086 b3 = (mi >= x && mi <= z3);
2087 if (b1 || b2 || b3)
2088 moves_ttable[m][mi] =
2089 inverse_move_aux[mi];
2090 else
2091 moves_ttable[m][mi] = mi;
2092
2093 if ((mi-1)/3==(R-1)/3 || (mi-1)/3==(Rw-1)/3)
2094 moves_ttable[m][mi] += 3;
2095 if ((mi-1)/3==(L-1)/3 || (mi-1)/3==(L2-1)/3)
2096 moves_ttable[m][mi] -= 3;
2097 } else {
2098 aux = apply_trans(m, apply_move(mi,(Cube){0}));
2099 for (move = 0; move < NMOVES; move++) {
2100 cube = apply_move(
2101 inverse_move_aux[move], aux);
2102 if (is_solved(cube, false))
2103 moves_ttable[m][mi] = move;
2104 }
2105 }
2106 }
2107 }
2108
2109 if (!write_ttables_file())
2110 fprintf(stderr, "Error writing ttables\n");
2111}
2112
2113static void
2114init_trans_aux()
2115{
2116 ep_mirror[UF] = UF;
2117 ep_mirror[UL] = UR;
2118 ep_mirror[UB] = UB;
2119 ep_mirror[UR] = UL;
2120 ep_mirror[DF] = DF;
2121 ep_mirror[DL] = DR;
2122 ep_mirror[DB] = DB;
2123 ep_mirror[DR] = DL;
2124 ep_mirror[FR] = FL;
2125 ep_mirror[FL] = FR;
2126 ep_mirror[BR] = BL;
2127 ep_mirror[BL] = BR;
2128
2129 cp_mirror[UFR] = UFL;
2130 cp_mirror[UFL] = UFR;
2131 cp_mirror[UBL] = UBR;
2132 cp_mirror[UBR] = UBL;
2133 cp_mirror[DFR] = DFL;
2134 cp_mirror[DFL] = DFR;
2135 cp_mirror[DBL] = DBR;
2136 cp_mirror[DBR] = DBL;
2137
2138 cpos_mirror[U_center] = U_center;
2139 cpos_mirror[D_center] = D_center;
2140 cpos_mirror[R_center] = L_center;
2141 cpos_mirror[L_center] = R_center;
2142 cpos_mirror[F_center] = F_center;
2143 cpos_mirror[B_center] = B_center;
2144
2145 /* Is there a more elegant way? */
2146 trans_algs[uf] = new_alg("");
2147 trans_algs[ur] = new_alg("y");
2148 trans_algs[ub] = new_alg("y2");
2149 trans_algs[ul] = new_alg("y3");
2150
2151 trans_algs[df] = new_alg("z2");
2152 trans_algs[dr] = new_alg("y z2");
2153 trans_algs[db] = new_alg("x2");
2154 trans_algs[dl] = new_alg("y3 z2");
2155
2156 trans_algs[rf] = new_alg("z3");
2157 trans_algs[rd] = new_alg("z3 y");
2158 trans_algs[rb] = new_alg("z3 y2");
2159 trans_algs[ru] = new_alg("z3 y3");
2160
2161 trans_algs[lf] = new_alg("z");
2162 trans_algs[ld] = new_alg("z y3");
2163 trans_algs[lb] = new_alg("z y2");
2164 trans_algs[lu] = new_alg("z y");
2165
2166 trans_algs[fu] = new_alg("x y2");
2167 trans_algs[fr] = new_alg("x y");
2168 trans_algs[fd] = new_alg("x");
2169 trans_algs[fl] = new_alg("x y3");
2170
2171 trans_algs[bu] = new_alg("x3");
2172 trans_algs[br] = new_alg("x3 y");
2173 trans_algs[bd] = new_alg("x3 y2");
2174 trans_algs[bl] = new_alg("x3 y3");
2175}
2176
2177
2178/* Public functions implementation *******************************************/
2179
2180Cube
2181apply_alg(Alg *alg, Cube cube)
2182{
2183 return apply_alg_generic(alg, cube, pf_all, true);
2184}
2185
2186Cube
2187apply_move(Move m, Cube cube)
2188{
2189 return (Cube) {
2190 .epose = epose_mtable[m][cube.epose],
2191 .eposs = eposs_mtable[m][cube.eposs],
2192 .eposm = eposm_mtable[m][cube.eposm],
2193 .eofb = eofb_mtable[m][cube.eofb],
2194 .eorl = eorl_mtable[m][cube.eorl],
2195 .eoud = eoud_mtable[m][cube.eoud],
2196 .coud = coud_mtable[m][cube.coud],
2197 .cofb = cofb_mtable[m][cube.cofb],
2198 .corl = corl_mtable[m][cube.corl],
2199 .cp = cp_mtable[m][cube.cp],
2200 .cpos = cpos_mtable[m][cube.cpos]
2201 };
2202}
2203
2204Cube
2205apply_trans(Trans t, Cube cube)
2206{
2207 int aux_epos[3] = { cube.epose, cube.eposs, cube.eposm };
2208 int aux_eo[3] = { cube.eoud, cube.eorl, cube.eofb };
2209 int aux_co[3] = { cube.coud, cube.corl, cube.cofb };
2210
2211 return (Cube) {
2212 .epose = epose_ttable[t][aux_epos[epose_source[t]]],
2213 .eposs = eposs_ttable[t][aux_epos[eposs_source[t]]],
2214 .eposm = eposm_ttable[t][aux_epos[eposm_source[t]]],
2215 .eofb = eo_ttable[t][aux_eo[eofb_source[t]]],
2216 .eorl = eo_ttable[t][aux_eo[eorl_source[t]]],
2217 .eoud = eo_ttable[t][aux_eo[eoud_source[t]]],
2218 .coud = co_ttable[t][aux_co[coud_source[t]]],
2219 .corl = co_ttable[t][aux_co[corl_source[t]]],
2220 .cofb = co_ttable[t][aux_co[cofb_source[t]]],
2221 .cp = cp_ttable[t][cube.cp],
2222 .cpos = cpos_ttable[t][cube.cpos]
2223 };
2224}
2225
2226Move
2227base_move(Move m)
2228{
2229 if (m == NULLMOVE)
2230 return NULLMOVE;
2231 else
2232 return m - (m-1)%3;
2233}
2234
2235Cube
2236compose(Cube c2, Cube c1)
2237{
2238 return compose_filtered(c2, c1, pf_all);
2239}
2240
2241uint64_t
2242cphtr(Cube cube)
2243{
2244 return cphtr_cosets[cube.cp];
2245}
2246
2247uint64_t
2248epos_dependent(Cube c)
2249{
2250 return epos_dependent_aux[c.eposs/FACTORIAL4][c.epose/FACTORIAL4];
2251}
2252
2253bool
2254equal(Cube c1, Cube c2)
2255{
2256 return c1.eofb == c2.eofb &&
2257 c1.epose == c2.epose &&
2258 c1.eposs == c2.eposs &&
2259 c1.eposm == c2.eposm &&
2260 c1.coud == c2.coud &&
2261 c1.cp == c2.cp &&
2262 c1.cpos == c2.cpos;
2263}
2264
2265void
2266genalgset(AlgSet *as)
2267{
2268 uint64_t i;
2269
2270 if (as->generated)
2271 return;
2272
2273 /* TODO: check if memory is enough, otherwise maybe crash gracefully? */
2274 as->table = malloc(as->size * sizeof(AlgList *));
2275
2276 if (read_algset_file(as)) {
2277 as->generated = true;
2278 return;
2279 }
2280
2281 fprintf(stderr, "Cannot load %s, generating it\n", as->filename);
2282
2283 for (i = 0; i < as->size; i++) {
2284 as->table[i] = solve(as->antindex(i), as->step, &as->opts);
2285 fprintf(stderr, "Generated %lu / %lu cases\n", i, as->size);
2286 }
2287
2288 if (!write_algset_file(as))
2289 fprintf(stderr, "Error writing algset file\n");
2290
2291 as->generated = true;
2292}
2293
2294void
2295genptable(PruneData *pd)
2296{
2297 uint64_t j;
2298 DfsData dd = {
2299 .m = 0,
2300 .last1 = NULLMOVE,
2301 .last2 = NULLMOVE
2302 };
2303
2304 if (pd->generated)
2305 return;
2306
2307 /* TODO: check if memory is enough, otherwise maybe crash gracefully? */
2308 pd->ptable = malloc(ptablesize(pd) * sizeof(uint8_t));
2309
2310 if (read_ptable_file(pd)) {
2311 pd->generated = true;
2312 return;
2313 }
2314
2315 fprintf(stderr, "Cannot load %s, generating it\n", pd->filename);
2316
2317 /* We use 4 bits per value, so any distance >= 15 is set to 15 */
2318 for (j = 0; j < pd->size; j++)
2319 ptable_update(pd, j, 15);
2320
2321 moveset_to_list(pd->moveset, NULL, dd.sorted_moves);
2322 movelist_to_position(dd.sorted_moves, dd.move_position);
2323
2324 pd->reached = malloc(ptablesize(pd) * sizeof(uint8_t));
2325 for (dd.d = 0, pd->n = 0; dd.d < 15 && pd->n < pd->size; dd.d++) {
2326 memset(pd->reached, 0, ptablesize(pd)*sizeof(uint8_t));
2327 genptable_dfs((Cube){0}, pd, &dd);
2328 fprintf(stderr, "Depth %d completed, generated %lu/%lu\n",
2329 dd.d, pd->n, pd->size);
2330 }
2331
2332 if (!write_ptable_file(pd))
2333 fprintf(stderr, "Error writing ptable file\n");
2334
2335 pd->generated = true;
2336 free(pd->reached);
2337}
2338
2339Cube
2340inverse_cube(Cube cube)
2341{
2342 CubeArray *arr = new_cubearray(cube, pf_all);
2343 CubeArray *inv = new_cubearray((Cube){0}, pf_all);
2344 Cube ret;
2345 int i;
2346
2347 for (i = 0; i < 12; i++) {
2348 inv->ep[arr->ep[i]] = i;
2349 inv->eofb[arr->ep[i]] = arr->eofb[i];
2350 inv->eorl[arr->ep[i]] = arr->eorl[i];
2351 inv->eoud[arr->ep[i]] = arr->eoud[i];
2352 }
2353
2354 for (i = 0; i < 8; i++) {
2355 inv->cp[arr->cp[i]] = i;
2356 inv->coud[arr->cp[i]] = (3 - arr->coud[i]) % 3;
2357 inv->corl[arr->cp[i]] = (3 - arr->corl[i]) % 3;
2358 inv->cofb[arr->cp[i]] = (3 - arr->cofb[i]) % 3;
2359 }
2360
2361 for (int i = 0; i < 6; i++)
2362 inv->cpos[arr->cpos[i]] = i;
2363
2364 ret = arrays_to_cube(inv, pf_all);
2365 free_cubearray(arr, pf_all);
2366 free_cubearray(inv, pf_all);
2367
2368 return ret;
2369}
2370
2371Move
2372inverse_move(Move m)
2373{
2374 return inverse_move_aux[m];
2375}
2376
2377Trans
2378inverse_trans(Trans t)
2379{
2380 return inverse_trans_aux[t];
2381}
2382
2383bool
2384is_admissible(Cube cube)
2385{
2386 /* TODO: this should check consistency of different orientations */
2387 /* TODO: check that centers are opposite and admissible */
2388
2389 CubeArray *a = new_cubearray(cube, pf_all);
2390 int parity;
2391 bool perm;
2392
2393 perm = is_perm(a->ep, 12) &&
2394 is_perm(a->cp, 8) &&
2395 is_perm(a->cpos, 6);
2396 parity = perm_sign(a->ep, 12) +
2397 perm_sign(a->cp, 8) +
2398 perm_sign(a->cpos, 6);
2399
2400 return perm && parity % 2 == 0;
2401}
2402
2403bool
2404is_solved(Cube cube, bool reorient)
2405{
2406 Trans i;
2407
2408 if (reorient)
2409 for (i = 0; i < NROTATIONS; i++)
2410 if (is_solved(apply_alg(trans_algs[i],cube), false))
2411 return true;
2412
2413 return equal(cube, (Cube){0});
2414}
2415
2416bool
2417is_solved_block(Cube cube, Block block)
2418{
2419 int i;
2420
2421 for (i = 0; i < 12; i++)
2422 if (block.edge[i] && !is_solved_edge(cube, i))
2423 return false;
2424 for (i = 0; i < 8; i++)
2425 if (block.corner[i] && !is_solved_corner(cube, i))
2426 return false;
2427 for (i = 0; i < 6; i++)
2428 if (block.center[i] && !is_solved_center(cube, i))
2429 return false;
2430
2431 return true;
2432}
2433
2434bool
2435is_solved_center(Cube cube, Center c)
2436{
2437 return what_center_at(cube, c) == c;
2438}
2439
2440bool
2441is_solved_corner(Cube cube, Corner c)
2442{
2443 return what_corner_at(cube, c) == c &&
2444 what_orientation_corner(cube.coud, c);
2445}
2446
2447bool
2448is_solved_edge(Cube cube, Edge e)
2449{
2450 return what_edge_at(cube, e) == e &&
2451 what_orientation_edge(cube.eofb, e);
2452}
2453
2454int
2455piece_orientation(Cube cube, int piece, char *orientation)
2456{
2457 int arr[12], n, b, x;
2458
2459 if (!strcmp(orientation, "eofb")) {
2460 x = cube.eofb;
2461 n = 12;
2462 b = 2;
2463 } else if (!strcmp(orientation, "eorl")) {
2464 x = cube.eorl;
2465 n = 12;
2466 b = 2;
2467 } else if (!strcmp(orientation, "eoud")) {
2468 x = cube.eoud;
2469 n = 12;
2470 b = 2;
2471 } else if (!strcmp(orientation, "coud")) {
2472 x = cube.coud;
2473 n = 8;
2474 b = 3;
2475 } else if (!strcmp(orientation, "corl")) {
2476 x = cube.corl;
2477 n = 8;
2478 b = 3;
2479 } else if (!strcmp(orientation, "cofb")) {
2480 x = cube.cofb;
2481 n = 8;
2482 b = 3;
2483 } else {
2484 return -1;
2485 }
2486
2487 int_to_sum_zero_array(x, b, n, arr);
2488 if (piece < n)
2489 return arr[piece];
2490
2491 return -1;
2492}
2493
2494void
2495print_cube(Cube cube)
2496{
2497/*
2498 CubeArray *arr = new_cubearray(cube, pf_all);
2499
2500 for (int i = 0; i < 12; i++)
2501 printf(" %s ", edge_string[arr->ep[i]]);
2502 printf("\n");
2503
2504 for (int i = 0; i < 12; i++)
2505 printf(" %c ", arr->eofb[i] + '0');
2506 printf("\n");
2507
2508 for (int i = 0; i < 8; i++)
2509 printf("%s ", corner_string[arr->cp[i]]);
2510 printf("\n");
2511
2512 for (int i = 0; i < 8; i++)
2513 printf(" %c ", arr->coud[i] + '0');
2514 printf("\n");
2515
2516 for (int i = 0; i < 6; i++)
2517 printf(" %s ", center_string[arr->cpos[i]]);
2518 printf("\n");
2519
2520 free_cubearray(arr, pf_all);
2521*/
2522
2523 for (int i = 0; i < 12; i++)
2524 printf(" %s ", edge_string[what_edge_at(cube, i)]);
2525 printf("\n");
2526
2527 for (int i = 0; i < 12; i++)
2528 printf(" %d ", what_orientation_edge(cube.eofb, i));
2529 printf("\n");
2530
2531 for (int i = 0; i < 8; i++)
2532 printf("%s ", corner_string[what_corner_at(cube, i)]);
2533 printf("\n");
2534
2535 for (int i = 0; i < 8; i++)
2536 printf(" %d ", what_orientation_corner(cube.coud, i));
2537 printf("\n");
2538
2539 for (int i = 0; i < 6; i++)
2540 printf(" %s ", center_string[what_center_at(cube, i)]);
2541 printf("\n");
2542
2543}
2544
2545Cube
2546random_cube()
2547{
2548 CubeArray *arr = new_cubearray((Cube){0}, pf_4val);
2549 Cube ret;
2550 int ep, cp, eo, co;
2551
2552 ep = rand() % FACTORIAL12;
2553 cp = rand() % FACTORIAL8;
2554 eo = rand() % POW2TO11;
2555 co = rand() % POW3TO7;
2556
2557 index_to_perm(ep, 12, arr->ep);
2558 index_to_perm(cp, 8, arr->cp);
2559 int_to_sum_zero_array(eo, 2, 12, arr->eofb);
2560 int_to_sum_zero_array(co, 3, 8, arr->coud);
2561
2562 if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8))
2563 swap(&(arr->ep[0]), &(arr->ep[1]));
2564
2565 ret = arrays_to_cube(arr, pf_4val);
2566 free_cubearray(arr, pf_4val);
2567
2568 return ret;
2569}
2570
2571AlgList *
2572solve(Cube cube, Step step, SolveOptions *opts)
2573{
2574 AlgListNode *node;
2575 AlgList *sols = new_alglist();
2576 Cube c = apply_trans(opts->pre_trans, cube);
2577 DfsData dd = {
2578 .m = 0,
2579 .niss = false,
2580 .lb = -1,
2581 .last1 = NULLMOVE,
2582 .last2 = NULLMOVE,
2583 .sols = sols,
2584 .current_alg = new_alg("")
2585 };
2586
2587 if (step.ready != NULL && step.ready(c, 1) != 0) {
2588 fprintf(stderr, "Cube not ready for solving step\n");
2589 return sols;
2590 }
2591
2592 moveset_to_list(step.moveset, step.check, dd.sorted_moves);
2593 movelist_to_position(dd.sorted_moves, dd.move_position);
2594
2595 for (dd.d = opts->min_moves;
2596 dd.d <= opts->max_moves && !(sols->len && opts->optimal_only);
2597 dd.d++) {
2598 if (opts->feedback)
2599 fprintf(stderr,
2600 "Found %d solutions, searching depth %d...\n",
2601 sols->len, dd.d);
2602 dfs(c, step, opts, &dd);
2603 }
2604
2605 for (node = sols->first; node != NULL; node = node->next)
2606 transform_alg(inverse_trans_aux[opts->pre_trans], node->alg);
2607
2608 free_alg(dd.current_alg);
2609 return sols;
2610}
2611
2612Alg *
2613inverse_alg(Alg *alg)
2614{
2615 Alg *ret = new_alg("");
2616 int i;
2617
2618 for (i = alg->len-1; i >= 0; i--)
2619 append_move(ret, alg->move[i], alg->inv[i]);
2620
2621 return ret;
2622}
2623
2624Alg *
2625new_alg(char *str)
2626{
2627 Alg *alg = malloc(sizeof(Alg));
2628 int i;
2629 bool niss = false;
2630 Move j, m;
2631
2632 alg->move = malloc(30 * sizeof(Move));
2633 alg->inv = malloc(30 * sizeof(bool));
2634 alg->allocated = 30;
2635 alg->len = 0;
2636
2637 for (i = 0; str[i]; i++) {
2638 if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n')
2639 continue;
2640
2641 if (str[i] == '(' && niss) {
2642 fprintf(stderr, "Error reading moves: nested ( )\n");
2643 return alg;
2644 }
2645
2646 if (str[i] == ')' && !niss) {
2647 fprintf(stderr, "Error reading moves: unmatched )\n");
2648 return alg;
2649 }
2650
2651 if (str[i] == '(' || str[i] == ')') {
2652 niss = !niss;
2653 continue;
2654 }
2655
2656 for (j = 0; j < NMOVES; j++) {
2657 if (str[i] == move_string[j][0]) {
2658 m = j;
2659 if (m <= B && str[i+1]=='w') {
2660 m += Uw - U;
2661 i++;
2662 }
2663 if (str[i+1]=='2') {
2664 m += 1;
2665 i++;
2666 } else if (str[i+1]=='\'' || str[i+1]=='3') {
2667 m += 2;
2668 i++;
2669 }
2670 append_move(alg, m, niss);
2671 break;
2672 }
2673 }
2674 }
2675
2676 return alg;
2677}
2678
2679Alg *
2680on_inverse(Alg *alg)
2681{
2682 Alg *ret = new_alg("");
2683 int i;
2684
2685 for (i = 0; i < alg->len; i++)
2686 append_move(ret, alg->move[i], !alg->inv[i]);
2687
2688 return ret;
2689}
2690
2691void
2692print_alg(Alg *alg, bool l)
2693{
2694 /* TODO: make it possible to print to stdout or to string */
2695 /* Maybe just return a string */
2696 char fill[4];
2697 int i;
2698 bool niss = false;
2699
2700 for (i = 0; i < alg->len; i++) {
2701 if (!niss && alg->inv[i])
2702 strcpy(fill, i == 0 ? "(" : " (");
2703 if (niss && !alg->inv[i])
2704 strcpy(fill, ") ");
2705 if (niss == alg->inv[i])
2706 strcpy(fill, i == 0 ? "" : " ");
2707
2708 printf("%s%s", fill, move_string[alg->move[i]]);
2709 niss = alg->inv[i];
2710 }
2711
2712 if (niss)
2713 printf(")");
2714 if (l)
2715 printf(" (%d)", alg->len);
2716
2717 printf("\n");
2718}
2719
2720void
2721print_alglist(AlgList *al, bool l)
2722{
2723 AlgListNode *i;
2724
2725 for (i = al->first; i != NULL; i = i->next)
2726 print_alg(i->alg, l);
2727}
2728
2729void
2730print_ptable(PruneData *pd)
2731{
2732 uint64_t i, a[16];
2733
2734 for (i = 0; i < 16; i++)
2735 a[i] = 0;
2736
2737 if (!pd->generated)
2738 genptable(pd);
2739
2740 for (i = 0; i < pd->size; i++)
2741 a[ptableval(pd, i)]++;
2742
2743 fprintf(stderr, "Values for table %s\n", pd->filename);
2744 for (i = 0; i < 16; i++)
2745 printf("%2lu\t%10lu\n", i, a[i]);
2746}
2747
2748uint64_t
2749ptablesize(PruneData *pd)
2750{
2751 return (pd->size + 1) / 2;
2752}
2753
2754int
2755ptableval(PruneData *pd, uint64_t ind)
2756{
2757 return (ind % 2) ? pd->ptable[ind/2] / 16 : pd->ptable[ind/2] % 16;
2758}
2759
2760
2761Alg *
2762trans_alg(Trans i)
2763{
2764 return trans_algs[i];
2765}
2766
2767void
2768transform_alg(Trans t, Alg *alg)
2769{
2770 int i;
2771
2772 for (i = 0; i < alg->len; i++)
2773 alg->move[i] = moves_ttable[t][alg->move[i]];
2774}
2775
2776Center
2777what_center_at(Cube cube, Center c)
2778{
2779 return what_center_at_aux[cube.cpos][c];
2780}
2781
2782Corner
2783what_corner_at(Cube cube, Corner c)
2784{
2785 return what_corner_at_aux[cube.cp][c];
2786}
2787
2788Edge
2789what_edge_at(Cube cube, Edge e)
2790{
2791 Edge ret;
2792 CubeArray *arr = new_cubearray(cube, pf_ep);
2793
2794 ret = arr->ep[e];
2795
2796 free_cubearray(arr, pf_ep);
2797 return ret;
2798}
2799
2800int
2801what_orientation_corner(int co, Corner c)
2802{
2803 if (c < 7)
2804 return (co / powint(3, c)) % 3;
2805 else
2806 return what_orientation_last_corner_aux[co];
2807}
2808
2809int
2810what_orientation_edge(int eo, Edge e)
2811{
2812 if (e < 11)
2813 return (eo & (1 << e)) ? 1 : 0;
2814 else
2815 return what_orientation_last_edge_aux[eo];
2816}
2817
2818Center
2819where_is_center(Cube cube, Center c)
2820{
2821 return where_is_center_aux[cube.cpos][c];
2822}
2823
2824Corner
2825where_is_corner(Cube cube, Corner c)
2826{
2827 return where_is_corner_aux[cube.cp][c];
2828}
2829
2830
2831void
2832init()
2833{
2834 /* Order is important! */
2835 init_environment();
2836 init_strings();
2837 init_moves_aux();
2838 init_moves();
2839 init_auxtables();
2840 init_cphtr_cosets();
2841 init_trans_aux();
2842 init_trans();
2843}
2844
diff --git a/old/2021-06-23-realizing-bad-tables/cube.h b/old/2021-06-23-realizing-bad-tables/cube.h
new file mode 100644
index 0000000..dcad047
--- /dev/null
+++ b/old/2021-06-23-realizing-bad-tables/cube.h
@@ -0,0 +1,88 @@
1#ifndef CUBE_H
2#define CUBE_H
3
4#include <stdio.h>
5#include <stdbool.h>
6#include <stdint.h>
7#include <stdlib.h>
8#include <string.h>
9#include <time.h>
10#include <unistd.h>
11#include <sys/stat.h>
12
13/* Constants and macros *****************************************************/
14
15#define POW2TO6 64ULL
16#define POW2TO11 2048ULL
17#define POW2TO12 4096ULL
18#define POW3TO7 2187ULL
19#define POW3TO8 6561ULL
20#define FACTORIAL4 24ULL
21#define FACTORIAL6 720ULL
22#define FACTORIAL7 5040ULL
23#define FACTORIAL8 40320ULL
24#define FACTORIAL12 479001600ULL
25#define BINOM12ON4 495ULL
26#define BINOM8ON4 70ULL
27#define MIN(a,b) (((a) < (b)) ? (a) : (b))
28#define MAX(a,b) (((a) > (b)) ? (a) : (b))
29
30#define NMOVES (z3+1)
31#define NTRANS (mirror+1)
32#define NROTATIONS (NTRANS-1)
33
34/* Type definitions **********************************************************/
35
36#include "cubetypes.h"
37
38/* Public functions **********************************************************/
39
40Cube apply_alg(Alg *alg, Cube cube);
41Cube apply_move(Move m, Cube cube);
42Cube apply_trans(Trans t, Cube cube);
43bool block_solved(Cube cube, Block);
44Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */
45uint64_t cphtr(Cube cube);
46uint64_t epos_dependent(Cube cube);
47bool equal(Cube c1, Cube c2);
48Cube inverse_cube(Cube cube);
49Move inverse_move(Move m);
50Trans inverse_trans(Trans t);
51bool is_admissible(Cube cube);
52bool is_solved(Cube cube, bool reorient);
53bool is_solved_center(Cube cube, Center c);
54bool is_solved_corner(Cube cube, Corner c);
55bool is_solved_edge(Cube cube, Edge e);
56void print_cube(Cube cube);
57Cube random_cube();
58AlgList * solve(Cube cube, Step step, SolveOptions *opts);
59Center what_center_at(Cube cube, Center c);
60Corner what_corner_at(Cube cube, Corner c);
61Edge what_edge_at(Cube cube, Edge e);
62int what_orientation_corner(int co, Corner c);
63int what_orientation_edge(int eo, Edge e);
64Center where_is_center(Cube cube, Center c);
65Corner where_is_corner(Cube cube, Corner c);
66Edge where_is_edge(Cube cube, Edge e);
67
68Move base_move(Move m);
69void free_alg(Alg *alg);
70void free_alglist(AlgList *l);
71Alg * inverse_alg(Alg *alg);
72Alg * new_alg(char *str);
73Alg * on_inverse(Alg *alg);
74void print_alg(Alg *alg, bool l);
75void print_alglist(AlgList *al, bool l);
76Alg * trans_alg(Trans i);
77void transform_alg(Trans t, Alg *alg);
78
79void genalgset(AlgSet *as);
80void genptable(PruneData *pd);
81void print_ptable(PruneData *pd);
82uint64_t ptablesize(PruneData *pd);
83int ptableval(PruneData *pd, uint64_t ind);
84
85void init();
86
87#endif
88
diff --git a/old/2021-06-23-realizing-bad-tables/cubetypes.h b/old/2021-06-23-realizing-bad-tables/cubetypes.h
new file mode 100644
index 0000000..886295c
--- /dev/null
+++ b/old/2021-06-23-realizing-bad-tables/cubetypes.h
@@ -0,0 +1,224 @@
1/* Typedefs ******************************************************************/
2
3typedef enum center Center;
4typedef enum corner Corner;
5typedef enum edge Edge;
6typedef enum move Move;
7typedef enum trans Trans;
8
9typedef struct alg Alg;
10typedef struct alglist AlgList;
11typedef struct alglistnode AlgListNode;
12typedef struct algset AlgSet;
13typedef struct block Block;
14typedef struct cube Cube;
15typedef struct cubearray CubeArray;
16typedef struct dfsdata DfsData;
17typedef struct piecefilter PieceFilter;
18typedef struct prunedata PruneData;
19typedef struct solveoptions SolveOptions;
20typedef struct step Step;
21
22typedef Cube (*AntiIndexer) (uint64_t);
23typedef int (*Checker) (Cube, int);
24typedef uint64_t (*Indexer) (Cube);
25typedef bool (*Moveset) (Move);
26
27
28/* Enums *********************************************************************/
29
30enum
31center
32{
33 U_center, D_center,
34 R_center, L_center,
35 F_center, B_center
36};
37
38enum
39corner
40{
41 UFR, UFL, UBL, UBR,
42 DFR, DFL, DBL, DBR
43};
44
45enum
46edge
47{
48 UF, UL, UB, UR,
49 DF, DL, DB, DR,
50 FR, FL, BL, BR
51};
52
53enum
54move
55{
56 NULLMOVE,
57 U, U2, U3, D, D2, D3,
58 R, R2, R3, L, L2, L3,
59 F, F2, F3, B, B2, B3,
60 Uw, Uw2, Uw3, Dw, Dw2, Dw3,
61 Rw, Rw2, Rw3, Lw, Lw2, Lw3,
62 Fw, Fw2, Fw3, Bw, Bw2, Bw3,
63 M, M2, M3,
64 S, S2, S3,
65 E, E2, E3,
66 x, x2, x3,
67 y, y2, y3,
68 z, z2, z3,
69};
70
71enum
72trans
73{
74 uf, ur, ub, ul,
75 df, dr, db, dl,
76 rf, rd, rb, ru,
77 lf, ld, lb, lu,
78 fu, fr, fd, fl,
79 bu, br, bd, bl,
80 mirror, /* R|L */
81};
82
83
84/* Structs *******************************************************************/
85
86struct
87alg
88{
89 Move * move;
90 bool * inv;
91 int len;
92 int allocated;
93};
94
95struct
96alglist
97{
98 AlgListNode * first;
99 AlgListNode * last;
100 int len;
101};
102
103struct
104alglistnode
105{
106 Alg * alg;
107 AlgListNode * next;
108};
109
110struct
111block
112{
113 bool edge[12];
114 bool corner[8];
115 bool center[6];
116};
117
118struct
119cube
120{
121 int epose;
122 int eposs;
123 int eposm;
124 int eofb;
125 int eorl;
126 int eoud;
127 int cp;
128 int coud;
129 int cofb;
130 int corl;
131 int cpos;
132};
133
134struct
135cubearray
136{
137 int * ep;
138 int * eofb;
139 int * eorl;
140 int * eoud;
141 int * cp;
142 int * coud;
143 int * corl;
144 int * cofb;
145 int * cpos;
146};
147
148struct
149dfsdata
150{
151 int d;
152 int m;
153 int lb;
154 bool niss;
155 Move last1;
156 Move last2;
157 AlgList * sols;
158 Alg * current_alg;
159 Move sorted_moves[NMOVES];
160 int move_position[NMOVES];
161};
162
163struct
164piecefilter
165{
166 bool epose;
167 bool eposs;
168 bool eposm;
169 bool eofb;
170 bool eorl;
171 bool eoud;
172 bool cp;
173 bool coud;
174 bool cofb;
175 bool corl;
176 bool cpos;
177};
178
179struct
180prunedata
181{
182 char * filename;
183 uint8_t * ptable;
184 uint8_t * reached;
185 bool generated;
186 uint64_t n;
187 uint64_t size;
188 Indexer index;
189 Moveset moveset;
190};
191
192struct
193solveoptions
194{
195 int min_moves;
196 int max_moves;
197 int max_solutions;
198 bool optimal_only;
199 bool can_niss;
200 bool feedback;
201 Trans pre_trans;
202};
203
204struct
205step
206{
207 Checker check;
208 Checker ready;
209 Moveset moveset;
210};
211
212/* TODO: I put it here because it needs the definition of Step, sort it out */
213struct
214algset
215{
216 char * filename;
217 AlgList ** table;
218 bool generated;
219 uint64_t size;
220 Indexer index;
221 AntiIndexer antindex;
222 Step step;
223 SolveOptions opts;
224};
diff --git a/old/2021-06-23-realizing-bad-tables/main.c b/old/2021-06-23-realizing-bad-tables/main.c
new file mode 100644
index 0000000..e0e049a
--- /dev/null
+++ b/old/2021-06-23-realizing-bad-tables/main.c
@@ -0,0 +1,70 @@
1#include <stdio.h>
2#include "cube.h"
3#include "steps.h"
4
5int main() {
6 Alg *algo;
7 AlgList *sols;
8 Cube cube;
9 SolveOptions opts;
10 char line[1000];
11 int i, ns = 3;
12/* int nrand = 10000, sum1, sum2, sum3;*/
13
14 Step *stps[20] = {&corners_HTM, &eofb_HTM, &optimal_HTM};
15 char sss[30][30] = {"Corners", "EO on F/B", "Optimal solution"};
16
17 opts = (SolveOptions) {
18 .min_moves = 0,
19 .max_moves = 20,
20 .optimal_only = true,
21 .max_solutions = 1,
22 .can_niss = false,
23 .feedback = true,
24 .pre_trans = uf
25 };
26
27 init();
28
29 print_ptable(&pd_corners_HTM);
30
31/*
32 srand(time(NULL));
33 sum1 = 0;
34 sum2 = 0;
35 sum3 = 0;
36 for (i = 0; i < nrand; i++) {
37 cube = random_cube();
38 sum1 += corners_HTM.check(cube, 20);
39 sum2 += cornershtr_HTM.check(cube, 20);
40 sum3 += optimal_HTM.check(cube, 20);
41 }
42 printf("Average corners pruning: %lf\n", ((double)sum1) / ((double) nrand));
43 printf("Average corners htr pruning: %lf\n", ((double)sum2) / ((double) nrand));
44 printf("Average optimal pruning: %lf\n", ((double)sum3) / ((double) nrand));
45*/
46
47 printf("Welcome to nissy 2.0! Insert a scramble:\n");
48
49 if (fgets(line, 1000, stdin) != NULL) {
50 algo = new_alg(line);
51 cube = apply_alg(algo, (Cube){0});
52
53 print_cube(cube);
54 printf("Index: %lu\n", pd_cornershtr_HTM.index(cube));
55
56 for (i = 0; i < ns; i++) {
57 if (stps[i]->check == NULL)
58 fprintf(stderr, "Check function for step %d is null\n", i);
59 printf("Check: %d\n", stps[i]->check(cube, 20));
60 sols = solve(cube, *stps[i], &opts);
61 printf("%s: %d solutions found:\n", sss[i], sols->len);
62 print_alglist(sols, true);
63 free_alglist(sols);
64 }
65 free_alg(algo);
66 }
67
68 return 0;
69}
70
diff --git a/old/2021-06-23-realizing-bad-tables/steps.c b/old/2021-06-23-realizing-bad-tables/steps.c
new file mode 100644
index 0000000..2b029b8
--- /dev/null
+++ b/old/2021-06-23-realizing-bad-tables/steps.c
@@ -0,0 +1,486 @@
1#include "steps.h"
2
3/* Check functions ***********************************************************/
4
5static int check_nothing(Cube cube, int target);
6static int check_centers(Cube cube, int target);
7static int check_eofb_HTM(Cube cube, int target);
8static int check_coud_HTM(Cube cube, int target);
9static int check_coud_URF(Cube cube, int target);
10static int check_corners_HTM(Cube cube, int target);
11static int check_cornershtr_HTM(Cube cube, int target);
12static int check_corners_URF(Cube cube, int target);
13static int check_cornershtr_URF(Cube cube, int target);
14static int check_ep_HTM(Cube cube, int target);
15static int check_edges_HTM(Cube cube, int target);
16static int check_drud_HTM(Cube cube, int target);
17static int check_optimal_HTM(Cube cube, int target);
18static int check_corners6eo_HTM(Cube cube, int target);
19static int check_tripleeo_HTM(Cube cube, int target);
20
21
22/* Index functions ***********************************************************/
23
24static uint64_t index_eofb(Cube cube);
25static uint64_t index_coud(Cube cube);
26static uint64_t index_corners(Cube cube);
27static uint64_t index_cornershtr(Cube cube);
28static uint64_t index_ep(Cube cube);
29static uint64_t index_drud(Cube cube);
30static uint64_t index_corners6eo(Cube cube);
31static uint64_t index_tripleeo(Cube cube);
32
33
34/* Steps *********************************************************************/
35
36Step
37eofb_HTM = {
38 .check = check_eofb_HTM,
39 .ready = check_centers,
40 .moveset = moveset_HTM
41};
42
43Step
44coud_HTM = {
45 .check = check_coud_HTM,
46 .ready = check_centers,
47 .moveset = moveset_HTM
48};
49
50Step
51coud_URF = {
52 .check = check_coud_URF,
53 .ready = check_nothing,
54 .moveset = moveset_URF
55};
56
57Step
58corners_HTM = {
59 .check = check_corners_HTM,
60 .ready = check_centers,
61 .moveset = moveset_HTM
62};
63
64Step
65cornershtr_HTM = {
66 .check = check_cornershtr_HTM,
67 .ready = check_centers,
68 .moveset = moveset_HTM
69};
70
71Step
72cornershtr_URF = {
73 .check = check_cornershtr_URF,
74 .ready = check_nothing,
75 .moveset = moveset_URF
76};
77
78Step
79corners_URF = {
80 .check = check_corners_URF,
81 .ready = check_nothing,
82 .moveset = moveset_URF
83};
84
85Step
86edges_HTM = {
87 .check = check_edges_HTM,
88 .ready = check_centers,
89 .moveset = moveset_HTM
90};
91
92Step
93drud_HTM = {
94 .check = check_drud_HTM,
95 .ready = check_centers,
96 .moveset = moveset_HTM
97};
98
99Step
100optimal_HTM = {
101 .check = check_optimal_HTM,
102 .ready = check_centers,
103 .moveset = moveset_HTM
104};
105
106Step
107tripleeo_HTM = {
108 .check = check_tripleeo_HTM,
109 .ready = check_centers,
110 .moveset = moveset_HTM
111};
112
113
114/* Blocks ********************************************************************/
115
116Block
117block_223dl = {
118 .edge = { [DF] = 1, [DL] = 1, [DB] = 1, [FL] = 1, [BL] = 1 },
119 .corner = { [DFL] = 1, [DBL] = 1 },
120 .center = { [D_center] = 1, [L_center] = 1 }
121};
122
123
124/* Pruning tables ************************************************************/
125
126PruneData
127pd_eofb_HTM = {
128 .filename = "ptable_eofb_HTM",
129 .size = POW2TO11,
130 .index = index_eofb,
131 .moveset = moveset_HTM
132};
133
134PruneData
135pd_coud_HTM = {
136 .filename = "ptable_coud_HTM",
137 .size = POW3TO7,
138 .index = index_coud,
139 .moveset = moveset_HTM
140};
141
142PruneData
143pd_cornershtr_HTM = {
144 .filename = "ptable_cornershtr_HTM",
145 .size = POW3TO7 * BINOM8ON4 * 6, /*TODO: check */
146 .index = index_cornershtr,
147 .moveset = moveset_HTM
148};
149
150PruneData
151pd_corners_HTM = {
152 .filename = "ptable_corners_HTM",
153 .size = POW3TO7 * FACTORIAL8,
154 .index = index_corners,
155 .moveset = moveset_HTM
156};
157
158PruneData
159pd_ep_HTM = {
160 .filename = "ptable_ep_HTM",
161 .size = FACTORIAL12,
162 .index = index_ep,
163 .moveset = moveset_HTM
164};
165
166PruneData
167pd_drud_HTM = {
168 .filename = "ptable_drud_HTM",
169 .size = POW2TO11 * POW3TO7 * BINOM12ON4,
170 .index = index_drud,
171 .moveset = moveset_HTM
172};
173
174PruneData
175pd_corners6eo_HTM = {
176 .filename = "ptable_corners6eo_HTM",
177 .size = POW2TO6 * POW3TO7 * FACTORIAL8,
178 .index = index_corners6eo,
179 .moveset = moveset_HTM
180};
181
182PruneData
183pd_tripleeo_HTM = {
184 .filename = "ptable_tripleeo_HTM",
185 .size = BINOM12ON4 * BINOM8ON4 * POW2TO11,
186 .index = index_tripleeo,
187 .moveset = moveset_HTM
188};
189
190
191/* Alg sets ******************************************************************/
192
193/* TODO: remove this (I am only keeping it as an example for future algesets)
194AlgSet
195as_ephtr_HTM = {
196 .filename = "algset_ephtr_HTM",
197 .size = FACTORIAL4 * FACTORIAL4 * FACTORIAL4,
198 .index = index_ephtr,
199 .antindex = index_to_cube_ephtr,
200 .step = (Step) {
201 .check = check_optimal_HTM,
202 .ready = check_htr_solved_corners_HTM,
203 .moveset = moveset_HTM
204 },
205 .opts = (SolveOptions) {
206 .min_moves = 0,
207 .max_moves = 20,
208 .max_solutions = 1,
209 .optimal_only = true,
210 .can_niss = false,
211 .feedback = true,
212 .pre_trans = uf
213 }
214};
215*/
216
217
218/* Check functions implementation ********************************************/
219
220static int
221check_nothing(Cube cube, int target)
222{
223 return 0;
224}
225
226static int
227check_centers(Cube cube, int target)
228{
229 return (cube.cpos == 0) ? 0 : 1;
230}
231
232static int
233check_eofb_HTM(Cube cube, int target)
234{
235 if (!pd_eofb_HTM.generated)
236 genptable(&pd_eofb_HTM);
237
238 return ptableval(&pd_eofb_HTM, cube.eofb);
239}
240
241static int
242check_coud_HTM(Cube cube, int target)
243{
244 if (!pd_coud_HTM.generated)
245 genptable(&pd_coud_HTM);
246
247 return ptableval(&pd_coud_HTM, cube.coud);
248}
249
250static int
251check_coud_URF(Cube cube, int target)
252{
253 /* TODO: I can improve this by checking first the orientation of
254 * the corner in DBL and use that as a reference */
255
256 int ud = check_coud_HTM(cube, target);
257 int rl = check_coud_HTM(apply_move(z, cube), target);
258 int fb = check_coud_HTM(apply_move(x, cube), target);
259
260 return MIN(ud, MIN(rl, fb));
261}
262
263static int
264check_corners_HTM(Cube cube, int target)
265{
266 if (!pd_corners_HTM.generated)
267 genptable(&pd_corners_HTM);
268
269 return ptableval(&pd_corners_HTM, index_corners(cube));
270}
271
272static int
273check_cornershtr_HTM(Cube cube, int target)
274{
275 if (!pd_cornershtr_HTM.generated)
276 genptable(&pd_cornershtr_HTM);
277
278 return ptableval(&pd_cornershtr_HTM, index_cornershtr(cube));
279}
280
281static int
282check_cornershtr_URF(Cube cube, int target)
283{
284 /* TODO: I can improve this by checking first the corner in DBL
285 * and use that as a reference */
286
287 int c, ret = 15;
288 Trans i;
289
290 for (i = 0; i < NROTATIONS; i++) {
291 c = check_cornershtr_HTM(apply_alg(trans_alg(i),cube), target);
292 ret = MIN(ret, c);
293 }
294
295 return ret;
296}
297
298static int
299check_corners_URF(Cube cube, int target)
300{
301 /* TODO: I can improve this by checking first the corner in DBL
302 * and use that as a reference */
303
304 int ret = 15;
305 Trans i;
306
307 for (i = 0; i < NROTATIONS; i++)
308 ret = MIN(ret, check_corners_HTM(
309 apply_alg(trans_alg(i), cube), target));
310
311 return ret;
312}
313
314static int
315check_ep_HTM(Cube cube, int target)
316{
317 if (!pd_ep_HTM.generated)
318 genptable(&pd_ep_HTM);
319
320 return ptableval(&pd_ep_HTM, index_ep(cube));
321}
322
323static int
324check_edges_HTM(Cube cube, int target)
325{
326 return MAX(check_ep_HTM(cube, target),
327 check_tripleeo_HTM(cube, target));
328}
329
330static int
331check_drud_HTM(Cube cube, int target)
332{
333 if (!pd_drud_HTM.generated)
334 genptable(&pd_drud_HTM);
335
336 return ptableval(&pd_drud_HTM, index_drud(cube));
337}
338
339static int
340check_optimal_HTM(Cube cube, int target)
341{
342 int dr1, dr2, dr3, cor, ret;
343 Cube cube2, cube3;
344
345 dr1 = check_drud_HTM(cube, target);
346 /*cor = check_corners6eo_HTM(cube, target);*/
347 cor = check_corners_HTM(cube, target);
348 ret = MAX(dr1, cor);
349
350 if (ret > target)
351 return ret;
352
353 cube2 = apply_trans(rf, cube);
354 dr2 = check_drud_HTM(cube2, target);
355 /*cor = check_corners6eo_HTM(cube2, target);
356 ret = MAX(ret, MAX(dr2, cor));*/
357 ret = MAX(ret, dr2);
358
359 if (ret > target)
360 return ret;
361
362 cube3 = apply_trans(bd, cube);
363 dr3 = check_drud_HTM(cube3, target);
364 /*cor = check_corners6eo_HTM(cube3, target);*/
365
366 if (dr1 == dr2 && dr2 == dr3 && dr1 != 0)
367 dr3++;
368
369 /*ret = MAX(ret, MAX(dr3, cor));*/
370 ret = MAX(ret, dr3);
371
372 if (ret == 0)
373 return (!cube.epose && !cube.eposs && !cube.eposm) ? 0 : 6;
374
375 return ret;
376}
377
378static int
379check_corners6eo_HTM(Cube cube, int target)
380{
381 if (!pd_corners6eo_HTM.generated)
382 genptable(&pd_corners6eo_HTM);
383
384 return ptableval(&pd_corners6eo_HTM, index_corners6eo(cube));
385}
386
387static int
388check_tripleeo_HTM(Cube cube, int target)
389{
390 if (!pd_tripleeo_HTM.generated)
391 genptable(&pd_tripleeo_HTM);
392
393 return ptableval(&pd_tripleeo_HTM, index_tripleeo(cube));
394}
395
396
397/* Index functions implementation ********************************************/
398
399static uint64_t
400index_eofb(Cube cube)
401{
402 return cube.eofb;
403}
404
405static uint64_t
406index_coud(Cube cube)
407{
408 return cube.coud;
409}
410
411static uint64_t
412index_cornershtr(Cube cube)
413{
414 return cube.coud * BINOM8ON4 * 6 + cphtr(cube);
415}
416
417static uint64_t
418index_corners(Cube cube)
419{
420 return cube.coud * FACTORIAL8 + cube.cp;
421}
422
423static uint64_t
424index_ep(Cube cube)
425{
426 uint64_t a, b, c;
427
428 a = cube.epose;
429 b = (cube.eposs % FACTORIAL4) + epos_dependent(cube)*FACTORIAL4;
430 c = cube.eposm % FACTORIAL4;
431
432 b *= FACTORIAL4 * BINOM12ON4;
433 c *= FACTORIAL4 * BINOM12ON4 * FACTORIAL4 * BINOM8ON4;
434
435 return a + b + c;
436}
437
438static uint64_t
439index_drud(Cube cube)
440{
441 uint64_t a, b, c;
442
443 a = cube.eofb;
444 b = cube.coud;
445 c = cube.epose / FACTORIAL4;
446
447 b *= POW2TO11;
448 c *= POW2TO11 * POW3TO7;
449
450 return a + b + c;
451}
452
453static uint64_t
454index_corners6eo(Cube cube)
455{
456 return (cube.coud*FACTORIAL8 + cube.cp)*POW2TO6 + (cube.eofb%POW2TO6);
457}
458
459static uint64_t
460index_tripleeo(Cube cube)
461{
462 uint64_t ee, es;
463
464 ee = cube.epose / FACTORIAL4;
465 es = epos_dependent(cube);
466
467 return (ee * BINOM8ON4 + es) * POW2TO11 + cube.eofb;
468}
469
470
471/* Movesets ******************************************************************/
472
473bool
474moveset_HTM(Move m)
475{
476 return m >= U && m <= B3;
477}
478
479bool
480moveset_URF(Move m)
481{
482 Move b = base_move(m);
483
484 return b == U || b == R || b == F;
485}
486
diff --git a/old/2021-06-23-realizing-bad-tables/steps.h b/old/2021-06-23-realizing-bad-tables/steps.h
new file mode 100644
index 0000000..9d8bf6a
--- /dev/null
+++ b/old/2021-06-23-realizing-bad-tables/steps.h
@@ -0,0 +1,42 @@
1#ifndef STEPS_H
2#define STEPS_H
3
4#include "cube.h"
5
6/* Steps *********************************************************************/
7
8extern Step eofb_HTM;
9extern Step coud_HTM;
10extern Step coud_URF;
11extern Step corners_HTM;
12extern Step cornershtr_HTM;
13extern Step corners_URF;
14extern Step cornershtr_URF;
15extern Step edges_HTM;
16extern Step drud_HTM;
17extern Step optimal_HTM;
18extern Step tripleeo_HTM;
19
20/* Blocks ********************************************************************/
21
22extern Block block_223dl;
23
24/* Pruning tables ************************************************************/
25
26extern PruneData pd_eofb_HTM;
27extern PruneData pd_coud_HTM;
28extern PruneData pd_corners_HTM;
29extern PruneData pd_cornershtr_HTM;
30extern PruneData pd_ep_HTM;
31extern PruneData pd_drud_HTM;
32extern PruneData pd_tripleeo_HTM;
33
34/* Alg sets ******************************************************************/
35
36
37/* Movesets ******************************************************************/
38
39bool moveset_HTM(Move m);
40bool moveset_URF(Move m);
41
42#endif
diff --git a/old/2021-06-23-uint16t/cube.c b/old/2021-06-23-uint16t/cube.c
new file mode 100644
index 0000000..0381ba0
--- /dev/null
+++ b/old/2021-06-23-uint16t/cube.c
@@ -0,0 +1,2762 @@
1#include "cube.h"
2
3/* Local functions **********************************************************/
4
5static Cube admissible_ep(Cube cube, PieceFilter f);
6static bool allowed_next(Move move, DfsData *dd);
7static void append_alg(AlgList *l, Alg *alg);
8static void append_move(Alg *alg, Move m, bool inverse);
9static Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a);
10static void apply_permutation(int *perm, int *set, int n);
11static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f);
12static uint16_t array_ep_to_epos(int *ep, int *eps_solved);
13static Cube arrays_to_cube(CubeArray *arr, PieceFilter f);
14static int binomial(int n, int k);
15static Cube compose_filtered(Cube c2, Cube c1, PieceFilter f);
16static void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f);
17static void dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd);
18static void dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd);
19static bool dfs_check_solved(SolveOptions *opts, DfsData *dd);
20static void dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd);
21static bool dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd);
22static int digit_array_to_int(int *a, int n, int b);
23static int edge_slice(Edge e); /* E=0, S=1, M=2 */
24static int epos_dependent(int pos1, int pos2);
25static uint16_t epos_from_arrays(int *epos, int *ep);
26static void epos_to_partial_ep(uint16_t epos, int *ep, int *ss);
27static int factorial(int n);
28static void free_alglistnode(AlgListNode *aln);
29static void free_cubearray(CubeArray *arr, PieceFilter f);
30static void genptable_dfs(Cube c, PruneData *pd, DfsData *dd);
31static void genptable_dfs_branch(Cube c, PruneData *pd, DfsData *dd);
32static void index_to_perm(int p, int n, int *r);
33static void index_to_subset(int s, int n, int k, int *r);
34static void int_to_digit_array(int a, int b, int n, int *r);
35static void int_to_sum_zero_array(int x, int b, int n, int *a);
36static int invert_digits(int a, int b, int n);
37static bool is_perm(int *a, int n);
38static bool is_subset(int *a, int n, int k);
39static Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf);
40static void movelist_to_position(Move *movelist, int *position);
41static void moveset_to_list(Moveset ms, Checker f, Move *r);
42static AlgList * new_alglist();
43static CubeArray * new_cubearray(Cube cube, PieceFilter f);
44static int perm_sign(int *a, int n);
45static int perm_to_index(int *a, int n);
46static int powint(int a, int b);
47static bool ptable_has_reached(PruneData *pd, uint64_t ind);
48static void ptable_set_reached(PruneData *pd, uint64_t ind);
49static void ptable_update(PruneData *pd, uint64_t ind, int m);
50static void realloc_alg(Alg *alg, int n);
51static bool read_algset_file(AlgSet *as);
52static bool read_mtables_file();
53static bool read_ptable_file(PruneData *pd);
54static bool read_ttables_file();
55static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f);
56static int subset_to_index(int *a, int n, int k);
57static void sum_arrays_mod(int *src, int *dst, int n, int m);
58static void swap(int *a, int *b);
59static bool write_algset_file(AlgSet *as);
60static bool write_mtables_file();
61static bool write_ptable_file(PruneData *pd);
62static bool write_ttables_file();
63
64static void init_auxtables();
65static void init_environment();
66static void init_moves();
67static void init_moves_aux();
68static void init_strings();
69static void init_trans();
70static void init_trans_aux();
71
72/* All sorts of useful costants and tables **********************************/
73
74static char * tabledir;
75
76static PieceFilter pf_all;
77static PieceFilter pf_4val;
78static PieceFilter pf_epcp;
79static PieceFilter pf_cpos;
80static PieceFilter pf_cp;
81static PieceFilter pf_ep;
82static PieceFilter pf_e;
83static PieceFilter pf_s;
84static PieceFilter pf_m;
85static PieceFilter pf_eo;
86static PieceFilter pf_co;
87
88static int epe_solved[4];
89static int eps_solved[4];
90static int epm_solved[4];
91
92static char move_string[NMOVES][7];
93static char edge_string[12][7];
94static char corner_string[8][7];
95static char center_string[6][7];
96
97static bool commute[NMOVES][NMOVES];
98static bool possible_next[NMOVES][NMOVES][NMOVES];
99static Move inverse_move_aux[NMOVES];
100static Trans inverse_trans_aux[NTRANS];
101static int epos_dependent_aux[BINOM12ON4][BINOM12ON4];
102static Center what_center_at_aux[FACTORIAL6][6];
103static Corner what_corner_at_aux[FACTORIAL8][8];
104static int what_orientation_last_corner_aux[POW3TO7];
105static int what_orientation_last_edge_aux[POW2TO11];
106static Center where_is_center_aux[FACTORIAL6][6];
107static Corner where_is_corner_aux[FACTORIAL8][8];
108static Edge where_is_edge_aux[3][FACTORIAL12/FACTORIAL8][12];
109
110static uint16_t epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
111static uint16_t eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
112static uint16_t eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
113static uint16_t eo_ttable[NTRANS][POW2TO11];
114static uint16_t cp_ttable[NTRANS][FACTORIAL8];
115static uint16_t co_ttable[NTRANS][POW3TO7];
116static uint16_t cpos_ttable[NTRANS][FACTORIAL6];
117static Move moves_ttable[NTRANS][NMOVES];
118
119static uint16_t epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
120static uint16_t eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
121static uint16_t eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
122static uint16_t eofb_mtable[NMOVES][POW2TO11];
123static uint16_t eorl_mtable[NMOVES][POW2TO11];
124static uint16_t eoud_mtable[NMOVES][POW2TO11];
125static uint16_t cp_mtable[NMOVES][FACTORIAL8];
126static uint16_t coud_mtable[NMOVES][POW3TO7];
127static uint16_t cofb_mtable[NMOVES][POW3TO7];
128static uint16_t corl_mtable[NMOVES][POW3TO7];
129static uint16_t cpos_mtable[NMOVES][FACTORIAL6];
130
131static uint64_t me[12];
132
133static int edge_cycle[NMOVES][12];
134static int corner_cycle[NMOVES][8];
135static int center_cycle[NMOVES][6];
136static int eofb_flipped[NMOVES][12];
137static int eorl_flipped[NMOVES][12];
138static int eoud_flipped[NMOVES][12];
139static int coud_flipped[NMOVES][8];
140static int corl_flipped[NMOVES][8];
141static int cofb_flipped[NMOVES][8];
142static Alg * equiv_alg[NMOVES];
143
144static int epose_source[NTRANS]; /* 0=epose, 1=eposs, 2=eposm */
145static int eposs_source[NTRANS];
146static int eposm_source[NTRANS];
147static int eofb_source[NTRANS]; /* 0=eoud, 1=eorl, 2=eofb */
148static int eorl_source[NTRANS];
149static int eoud_source[NTRANS];
150static int coud_source[NTRANS]; /* 0=coud, 1=corl, 2=cofb */
151static int cofb_source[NTRANS];
152static int corl_source[NTRANS];
153static int ep_mirror[12];
154static int cp_mirror[8];
155static int cpos_mirror[6];
156static Alg * trans_algs[NROTATIONS];
157
158
159/* Local functions implementation ********************************************/
160
161static Cube
162admissible_ep(Cube cube, PieceFilter f)
163{
164 CubeArray *arr = new_cubearray(cube, f);
165 Cube ret;
166 bool used[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
167 int i, j;
168
169 for (i = 0; i < 12; i++)
170 if (arr->ep[i] != -1)
171 used[arr->ep[i]] = true;
172
173 for (i = 0, j = 0; i < 12; i++) {
174 for ( ; j < 11 && used[j]; j++);
175 if (arr->ep[i] == -1)
176 arr->ep[i] = j++;
177 }
178
179 ret = arrays_to_cube(arr, pf_ep);
180 free_cubearray(arr, f);
181
182 return ret;
183}
184
185static bool
186allowed_next(Move move, DfsData *dd)
187{
188 if (!possible_next[dd->last2][dd->last1][move])
189 return false;
190
191 if (commute[dd->last1][move])
192 return dd->move_position[dd->last1] < dd->move_position[move];
193
194 return true;
195}
196
197static void
198append_alg(AlgList *l, Alg *alg)
199{
200 AlgListNode *node = malloc(sizeof(AlgListNode));
201 int i;
202
203 node->alg = new_alg("");
204 for (i = 0; i < alg->len; i++)
205 append_move(node->alg, alg->move[i], alg->inv[i]);
206 node->next = NULL;
207
208 if (++l->len == 1)
209 l->first = node;
210 else
211 l->last->next = node;
212 l->last = node;
213}
214
215static void
216append_move(Alg *alg, Move m, bool inverse)
217{
218 if (alg->len == alg->allocated)
219 realloc_alg(alg, 2*alg->len);
220
221 alg->move[alg->len] = m;
222 alg->inv [alg->len] = inverse;
223 alg->len++;
224}
225
226static Cube
227apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a)
228{
229 Cube ret = {0};
230 int i;
231
232 for (i = 0; i < alg->len; i++)
233 if (alg->inv[i])
234 ret = a ? apply_move(alg->move[i], ret) :
235 apply_move_cubearray(alg->move[i], ret, f);
236
237 ret = compose_filtered(c, inverse_cube(ret), f);
238
239 for (i = 0; i < alg->len; i++)
240 if (!alg->inv[i])
241 ret = a ? apply_move(alg->move[i], ret) :
242 apply_move_cubearray(alg->move[i], ret, f);
243
244 return ret;
245}
246
247static void
248apply_permutation(int *perm, int *set, int n)
249{
250 int *aux = malloc(n * sizeof(int));
251 int i;
252
253 if (!is_perm(perm, n))
254 return;
255
256 for (i = 0; i < n; i++)
257 aux[i] = set[perm[i]];
258
259 memcpy(set, aux, n * sizeof(int));
260 free(aux);
261}
262
263static Cube
264apply_move_cubearray(Move m, Cube cube, PieceFilter f)
265{
266 CubeArray m_arr = {
267 edge_cycle[m],
268 eofb_flipped[m],
269 eorl_flipped[m],
270 eoud_flipped[m],
271 corner_cycle[m],
272 coud_flipped[m],
273 corl_flipped[m],
274 cofb_flipped[m],
275 center_cycle[m]
276 };
277
278 return move_via_arrays(&m_arr, cube, f);
279}
280
281static uint16_t
282array_ep_to_epos(int *ep, int *ss)
283{
284 int epos[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
285 int eps[4];
286 int i, j, is;
287
288 for (i = 0, is = 0; i < 12; i++) {
289 for (j = 0; j < 4; j++) {
290 if (ep[i] == ss[j]) {
291 eps[is++] = j;
292 epos[i] = 1;
293 }
294 }
295 }
296
297 for (i = 0; i < 4; i++)
298 swap(&epos[ss[i]], &epos[i+8]);
299
300 return epos_from_arrays(epos, eps);
301}
302
303static Cube
304arrays_to_cube(CubeArray *arr, PieceFilter f)
305{
306 Cube ret = {0};
307
308 if (f.epose)
309 ret.epose = array_ep_to_epos(arr->ep, epe_solved);
310 if (f.eposs)
311 ret.eposs = array_ep_to_epos(arr->ep, eps_solved);
312 if (f.eposm)
313 ret.eposm = array_ep_to_epos(arr->ep, epm_solved);
314 if (f.eofb)
315 ret.eofb = digit_array_to_int(arr->eofb, 11, 2);
316 if (f.eorl)
317 ret.eorl = digit_array_to_int(arr->eorl, 11, 2);
318 if (f.eoud)
319 ret.eoud = digit_array_to_int(arr->eoud, 11, 2);
320 if (f.cp)
321 ret.cp = perm_to_index(arr->cp, 8);
322 if (f.coud)
323 ret.coud = digit_array_to_int(arr->coud, 7, 3);
324 if (f.corl)
325 ret.corl = digit_array_to_int(arr->corl, 7, 3);
326 if (f.cofb)
327 ret.cofb = digit_array_to_int(arr->cofb, 7, 3);
328 if (f.cpos)
329 ret.cpos = perm_to_index(arr->cpos, 6);
330
331 return ret;
332}
333
334static int
335binomial(int n, int k)
336{
337 if (n < 0 || k < 0 || k > n)
338 return 0;
339
340 return factorial(n) / (factorial(k) * factorial(n-k));
341}
342
343static Cube
344compose_filtered(Cube c2, Cube c1, PieceFilter f)
345{
346 CubeArray *arr = new_cubearray(c2, f);
347 Cube ret;
348
349 ret = move_via_arrays(arr, c1, f);
350 free_cubearray(arr, f);
351
352 return ret;
353}
354
355static void
356cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f)
357{
358 int i;
359
360 if (f.epose || f.eposs || f.eposm)
361 for (i = 0; i < 12; i++)
362 arr->ep[i] = -1;
363
364 if (f.epose)
365 epos_to_partial_ep(cube.epose, arr->ep, epe_solved);
366 if (f.eposs)
367 epos_to_partial_ep(cube.eposs, arr->ep, eps_solved);
368 if (f.eposm)
369 epos_to_partial_ep(cube.eposm, arr->ep, epm_solved);
370 if (f.eofb)
371 int_to_sum_zero_array(cube.eofb, 2, 12, arr->eofb);
372 if (f.eorl)
373 int_to_sum_zero_array(cube.eorl, 2, 12, arr->eorl);
374 if (f.eoud)
375 int_to_sum_zero_array(cube.eoud, 2, 12, arr->eoud);
376 if (f.cp)
377 index_to_perm(cube.cp, 8, arr->cp);
378 if (f.coud)
379 int_to_sum_zero_array(cube.coud, 3, 8, arr->coud);
380 if (f.corl)
381 int_to_sum_zero_array(cube.corl, 3, 8, arr->corl);
382 if (f.cofb)
383 int_to_sum_zero_array(cube.cofb, 3, 8, arr->cofb);
384 if (f.cpos)
385 index_to_perm(cube.cpos, 6, arr->cpos);
386}
387
388static void
389dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd)
390{
391 if (dfs_stop(c, s, opts, dd))
392 return;
393
394 if (dfs_check_solved(opts, dd))
395 return;
396
397 dfs_branch(c, s, opts, dd);
398
399 if (opts->can_niss && !dd->niss)
400 dfs_niss(c, s, opts, dd);
401}
402
403static void
404dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd)
405{
406 Move m, l1 = dd->last1, l2 = dd->last2, *moves = dd->sorted_moves;
407
408 int i, maxnsol = opts->max_solutions;
409
410 for (i = 0; (m=moves[i]) != NULLMOVE && dd->sols->len < maxnsol; i++) {
411 if (allowed_next(m, dd)) {
412 dd->last2 = dd->last1;
413 dd->last1 = m;
414 append_move(dd->current_alg, m, dd->niss);
415
416 dfs(apply_move(m, c), s, opts, dd);
417
418 dd->current_alg->len--;
419 dd->last2 = l2;
420 dd->last1 = l1;
421 }
422 }
423}
424
425static bool
426dfs_check_solved(SolveOptions *opts, DfsData *dd)
427{
428 if (dd->lb != 0)
429 return false;
430
431 if (dd->current_alg->len == dd->d) {
432 append_alg(dd->sols, dd->current_alg);
433
434 if (opts->feedback)
435 print_alg(dd->current_alg, false);
436 }
437
438 return true;
439}
440
441static void
442dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd)
443{
444 Move l1 = dd->last1, l2 = dd->last2;
445
446 if (dd->current_alg->len == 0 ||
447 (s.check(apply_move(inverse_move(l1), (Cube){0}), 1))) {
448 dd->niss = true;
449 dd->last1 = NULLMOVE;
450 dd->last2 = NULLMOVE;
451
452 dfs(inverse_cube(c), s, opts, dd);
453
454 dd->last1 = l1;
455 dd->last2 = l2;
456 dd->niss = false;
457 }
458}
459
460static bool
461dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd)
462{
463 if (dd->sols->len >= opts->max_solutions)
464 return true;
465
466 dd->lb = s.check(c, dd->d - dd->current_alg->len);
467 if (opts->can_niss && !dd->niss)
468 dd->lb = MIN(1, dd->lb);
469
470 if (dd->current_alg->len + dd->lb > dd->d)
471 return true;
472
473 return false;
474}
475
476static int
477digit_array_to_int(int *a, int n, int b)
478{
479 int i, ret = 0, p = 1;
480
481 for (i = 0; i < n; i++, p *= b)
482 ret += a[i] * p;
483
484 return ret;
485}
486
487static int
488edge_slice(Edge e) {
489 if (e < 0 || e > 11)
490 return -1;
491
492 if (e == FR || e == FL || e == BL || e == BR)
493 return 0;
494 if (e == UR || e == UL || e == DR || e == DL)
495 return 1;
496
497 return 2;
498}
499
500static int
501epos_dependent(int poss, int pose)
502{
503 int ep[12] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
504 int ep8[8] = {0, 0, 0, 0, 0, 0, 0, 0};
505 int i, j;
506
507 epos_to_partial_ep(poss*FACTORIAL4, ep, eps_solved);
508 epos_to_partial_ep(pose*FACTORIAL4, ep, epe_solved);
509
510 for (i = 0, j = 0; i < 12; i++)
511 if (edge_slice(ep[i]) != 0)
512 ep8[j++] = (edge_slice(ep[i]) == 1) ? 1 : 0;
513
514 swap(&ep8[1], &ep8[4]);
515 swap(&ep8[3], &ep8[6]);
516
517 return subset_to_index(ep8, 8, 4);
518}
519
520static uint16_t
521epos_from_arrays(int *epos, int *ep)
522{
523 return FACTORIAL4 * subset_to_index(epos,12,4) + perm_to_index(ep,4);
524}
525
526static void
527epos_to_partial_ep(uint16_t epos, int *ep, int *ss)
528{
529 int i, is, eposs[12], eps[4];
530
531 index_to_perm(epos % FACTORIAL4, 4, eps);
532 index_to_subset(epos / FACTORIAL4, 12, 4, eposs);
533
534 for (i = 0; i < 4; i++)
535 swap(&eposs[ss[i]], &eposs[i+8]);
536
537 for (i = 0, is = 0; i < 12; i++)
538 if (eposs[i])
539 ep[i] = ss[eps[is++]];
540}
541
542static int
543factorial(int n)
544{
545 int i, ret = 1;
546
547 if (n < 0)
548 return 0;
549
550 for (i = 1; i <= n; i++)
551 ret *= i;
552
553 return ret;
554}
555
556void
557free_alg(Alg *alg)
558{
559 free(alg->move);
560 free(alg->inv);
561 free(alg);
562}
563
564void
565free_alglist(AlgList *l)
566{
567 AlgListNode *aux, *i = l->first;
568
569 while (i != NULL) {
570 aux = i->next;
571 free_alglistnode(i);
572 i = aux;
573 }
574 free(l);
575}
576
577void
578free_alglistnode(AlgListNode *aln)
579{
580 free_alg(aln->alg);
581 free(aln);
582}
583
584static void
585free_cubearray(CubeArray *arr, PieceFilter f)
586{
587 if (f.epose || f.eposs || f.eposm)
588 free(arr->ep);
589 if (f.eofb)
590 free(arr->eofb);
591 if (f.eorl)
592 free(arr->eorl);
593 if (f.eoud)
594 free(arr->eoud);
595 if (f.cp)
596 free(arr->cp);
597 if (f.coud)
598 free(arr->coud);
599 if (f.corl)
600 free(arr->corl);
601 if (f.cofb)
602 free(arr->cofb);
603 if (f.cpos)
604 free(arr->cpos);
605
606 free(arr);
607}
608
609static void
610genptable_dfs(Cube c, PruneData *pd, DfsData *dd)
611{
612 uint64_t ind = pd->index(c);
613 int oldval = ptableval(pd, ind);
614
615 if (oldval < dd->m || ptable_has_reached(pd, ind) || pd->n == pd->size)
616 return;
617
618 ptable_set_reached(pd, ind);
619
620 if (dd->m == dd->d) {
621 if (dd->m < oldval)
622 ptable_update(pd, ind, dd->m);
623 return;
624 }
625
626 genptable_dfs_branch(c, pd, dd);
627}
628
629static void
630genptable_dfs_branch(Cube c, PruneData *pd, DfsData *dd)
631{
632 Move i, move, l1 = dd->last1, l2 = dd->last2;
633
634 dd->m++;
635
636 for (i = 0; dd->sorted_moves[i] != NULLMOVE; i++) {
637 move = dd->sorted_moves[i];
638 if (allowed_next(move, dd)) {
639 dd->last2 = dd->last1;
640 dd->last1 = move;
641
642 genptable_dfs(apply_move(move, c), pd, dd);
643
644 dd->last2 = l2;
645 dd->last1 = l1;
646 }
647 }
648
649 dd->m--;
650}
651
652static void
653index_to_perm(int p, int n, int *r)
654{
655 int *a = malloc(n * sizeof(int));
656 int i, j, c;
657
658 for (i = 0; i < n; i++)
659 a[i] = 0;
660
661 if (p < 0 || p >= factorial(n))
662 for (i = 0; i < n; i++)
663 r[i] = -1;
664
665 for (i = 0; i < n; i++) {
666 c = 0;
667 j = 0;
668 while (c <= p / factorial(n-i-1))
669 c += a[j++] ? 0 : 1;
670 r[i] = j-1;
671 a[j-1] = 1;
672 p %= factorial(n-i-1);
673 }
674
675 free(a);
676}
677
678static void
679index_to_subset(int s, int n, int k, int *r)
680{
681 int i, j, v;
682
683 if (s < 0 || s >= binomial(n, k)) {
684 for (i = 0; i < n; i++)
685 r[i] = -1;
686 return;
687 }
688
689 for (i = 0; i < n; i++) {
690 if (k == n-i) {
691 for (j = i; j < n; j++)
692 r[j] = 1;
693 return;
694 }
695
696 if (k == 0) {
697 for (j = i; j < n; j++)
698 r[j] = 0;
699 return;
700 }
701
702 v = binomial(n-i-1, k);
703 if (s >= v) {
704 r[i] = 1;
705 k--;
706 s -= v;
707 } else {
708 r[i] = 0;
709 }
710 }
711}
712
713static void
714int_to_digit_array(int a, int b, int n, int *r)
715{
716 int i;
717
718 if (b <= 1)
719 for (i = 0; i < n; i++)
720 r[i] = 0;
721 else
722 for (i = 0; i < n; i++, a /= b)
723 r[i] = a % b;
724}
725
726static void
727int_to_sum_zero_array(int x, int b, int n, int *a)
728{
729 int i, s = 0;
730
731 if (b <= 1) {
732 for (i = 0; i < n; i++)
733 a[i] = 0;
734 } else {
735 int_to_digit_array(x, b, n-1, a);
736 for (i = 0; i < n - 1; i++)
737 s = (s + a[i]) % b;
738 a[n-1] = (b - s) % b;
739 }
740}
741
742static int
743invert_digits(int a, int b, int n)
744{
745 int i, ret, *r = malloc(n * sizeof(int));
746
747 int_to_digit_array(a, b, n, r);
748 for (i = 0; i < n; i++)
749 r[i] = (b-r[i]) % b;
750
751 ret = digit_array_to_int(r, n, b);
752 free(r);
753 return ret;
754}
755
756static bool
757is_perm(int *a, int n)
758{
759 int *aux = malloc(n * sizeof(int));
760 int i;
761
762 for (i = 0; i < n; i++)
763 if (a[i] < 0 || a[i] >= n)
764 return false;
765 else
766 aux[a[i]] = 1;
767
768 for (i = 0; i < n; i++)
769 if (!aux[i])
770 return false;
771
772 free(aux);
773
774 return true;
775}
776
777static bool
778is_subset(int *a, int n, int k)
779{
780 int i, sum = 0;
781
782 for (i = 0; i < n; i++)
783 sum += a[i] ? 1 : 0;
784
785 return sum == k;
786}
787
788static Cube
789move_via_arrays(CubeArray *arr, Cube c, PieceFilter f)
790{
791 CubeArray *arrc = new_cubearray(c, f);
792 Cube ret;
793
794 if (f.epose || f.eposs || f.eposm)
795 apply_permutation(arr->ep, arrc->ep, 12);
796
797 if (f.eofb) {
798 apply_permutation(arr->ep, arrc->eofb, 12);
799 sum_arrays_mod(arr->eofb, arrc->eofb, 12, 2);
800 }
801
802 if (f.eorl) {
803 apply_permutation(arr->ep, arrc->eorl, 12);
804 sum_arrays_mod(arr->eorl, arrc->eorl, 12, 2);
805 }
806
807 if (f.eoud) {
808 apply_permutation(arr->ep, arrc->eoud, 12);
809 sum_arrays_mod(arr->eoud, arrc->eoud, 12, 2);
810 }
811
812 if (f.cp)
813 apply_permutation(arr->cp, arrc->cp, 8);
814
815 if (f.coud) {
816 apply_permutation(arr->cp, arrc->coud, 8);
817 sum_arrays_mod(arr->coud, arrc->coud, 8, 3);
818 }
819
820 if (f.corl) {
821 apply_permutation(arr->cp, arrc->corl, 8);
822 sum_arrays_mod(arr->corl, arrc->corl, 8, 3);
823 }
824
825 if (f.cofb) {
826 apply_permutation(arr->cp, arrc->cofb, 8);
827 sum_arrays_mod(arr->cofb, arrc->cofb, 8, 3);
828 }
829
830 if (f.cpos)
831 apply_permutation(arr->cpos, arrc->cpos, 6);
832
833 ret = arrays_to_cube(arrc, f);
834 free_cubearray(arrc, f);
835
836 return ret;
837}
838
839static void
840movelist_to_position(Move *movelist, int *position)
841{
842 Move m;
843
844 for (m = 0; m < NMOVES && movelist[m] != NULLMOVE; m++)
845 position[movelist[m]] = m;
846}
847
848static void
849moveset_to_list(Moveset ms, Checker f, Move *r)
850{
851 Cube c;
852 int b[NMOVES];
853 int na = 0, nb = 0;
854 Move i;
855
856 if (ms == NULL) {
857 fprintf(stderr, "Error: no moveset given\n");
858 return;
859 }
860
861 for (i = U; i < NMOVES; i++) {
862 if (ms(i)) {
863 c = apply_move(i, (Cube){0});
864 if (f != NULL && f(c, 1))
865 r[na++] = i;
866 else
867 b[nb++] = i;
868 }
869 }
870
871 memcpy(r + na, b, nb * sizeof(Move));
872 r[na+nb] = NULLMOVE;
873}
874
875static AlgList *
876new_alglist()
877{
878 AlgList *ret = malloc(sizeof(AlgList));
879
880 ret->len = 0;
881 ret->first = NULL;
882 ret->last = NULL;
883
884 return ret;
885}
886
887static CubeArray *
888new_cubearray(Cube cube, PieceFilter f)
889{
890 CubeArray *arr = malloc(sizeof(CubeArray));
891
892 if (f.epose || f.eposs || f.eposm)
893 arr->ep = malloc(12 * sizeof(int));
894 if (f.eofb)
895 arr->eofb = malloc(12 * sizeof(int));
896 if (f.eorl)
897 arr->eorl = malloc(12 * sizeof(int));
898 if (f.eoud)
899 arr->eoud = malloc(12 * sizeof(int));
900 if (f.cp)
901 arr->cp = malloc(8 * sizeof(int));
902 if (f.coud)
903 arr->coud = malloc(8 * sizeof(int));
904 if (f.corl)
905 arr->corl = malloc(8 * sizeof(int));
906 if (f.cofb)
907 arr->cofb = malloc(8 * sizeof(int));
908 if (f.cpos)
909 arr->cpos = malloc(6 * sizeof(int));
910
911 cube_to_arrays(cube, arr, f);
912
913 return arr;
914}
915
916static int
917perm_sign(int *a, int n)
918{
919 int i, j, ret = 0;
920
921 if (!is_perm(a,n))
922 return -1;
923
924 for (i = 0; i < n; i++)
925 for (j = i+1; j < n; j++)
926 ret += (a[i] > a[j]) ? 1 : 0;
927
928 return ret % 2;
929}
930
931static int
932perm_to_index(int *a, int n)
933{
934 int i, j, c, ret = 0;
935
936 if (!is_perm(a, n))
937 return -1;
938
939 for (i = 0; i < n; i++) {
940 c = 0;
941 for (j = i+1; j < n; j++)
942 c += (a[i] > a[j]) ? 1 : 0;
943 ret += factorial(n-i-1) * c;
944 }
945
946 return ret;
947}
948
949static int
950powint(int a, int b)
951{
952 if (b < 0)
953 return 0;
954 if (b == 0)
955 return 1;
956
957 if (b % 2)
958 return a * powint(a, b-1);
959 else
960 return powint(a*a, b/2);
961}
962
963static bool
964ptable_has_reached(PruneData *pd, uint64_t ind)
965{
966 return ind % 2 ? pd->reached[ind/2] / 16 : pd->reached[ind/2] % 16;
967}
968
969static void
970ptable_set_reached(PruneData *pd, uint64_t ind)
971{
972 uint8_t oldval2 = pd->reached[ind/2];
973 int other = ind % 2 ? oldval2 % 16 : oldval2 / 16;
974
975 pd->reached[ind/2] = ind % 2 ? 16 + other : 16*other + 1;
976}
977
978static void
979ptable_update(PruneData *pd, uint64_t ind, int n)
980{
981 uint8_t oldval2 = pd->ptable[ind/2];
982 int other = ind % 2 ? oldval2 % 16 : oldval2 / 16;
983
984 pd->ptable[ind/2] = ind % 2 ? 16*n + other : 16*other + n;
985 pd->n++;
986}
987
988static void
989realloc_alg(Alg *alg, int n)
990{
991 if (alg == NULL) {
992 fprintf(stderr, "Error: trying to reallocate NULL alg.\n");
993 return;
994 }
995
996 if (n < alg->len) {
997 fprintf(stderr, "Error: alg too long for reallocation ");
998 fprintf(stderr, "(%d vs %d)\n", alg->len, n);
999 return;
1000 }
1001
1002 if (n > 1000000) {
1003 fprintf(stderr, "Warning: very long alg,");
1004 fprintf(stderr, "something might go wrong.\n");
1005 }
1006
1007 alg->move = realloc(alg->move, n * sizeof(int));
1008 alg->inv = realloc(alg->inv, n * sizeof(int));
1009 alg->allocated = n;
1010}
1011
1012static bool
1013read_algset_file(AlgSet *as)
1014{
1015 return false;
1016}
1017
1018static bool
1019read_mtables_file()
1020{
1021 FILE *f;
1022 char fname[strlen(tabledir)+20];
1023 int m, b = sizeof(uint16_t);
1024 bool r = true;
1025
1026 strcpy(fname, tabledir);
1027 strcat(fname, "/mtables");
1028
1029 if ((f = fopen(fname, "rb")) == NULL)
1030 return false;
1031
1032 for (m = 0; m < NMOVES; m++) {
1033 r = r && fread(epose_mtable[m], b, me[0], f) == me[0];
1034 r = r && fread(eposs_mtable[m], b, me[1], f) == me[1];
1035 r = r && fread(eposm_mtable[m], b, me[2], f) == me[2];
1036 r = r && fread(eofb_mtable[m], b, me[3], f) == me[3];
1037 r = r && fread(eorl_mtable[m], b, me[4], f) == me[4];
1038 r = r && fread(eoud_mtable[m], b, me[5], f) == me[5];
1039 r = r && fread(cp_mtable[m], b, me[6], f) == me[6];
1040 r = r && fread(coud_mtable[m], b, me[7], f) == me[7];
1041 r = r && fread(corl_mtable[m], b, me[8], f) == me[8];
1042 r = r && fread(cofb_mtable[m], b, me[9], f) == me[9];
1043 r = r && fread(cpos_mtable[m], b, me[10], f) == me[10];
1044 }
1045
1046 fclose(f);
1047 return r;
1048}
1049
1050static bool
1051read_ptable_file(PruneData *pd)
1052{
1053 FILE *f;
1054 char fname[strlen(tabledir)+100];
1055 uint64_t r;
1056
1057 strcpy(fname, tabledir);
1058 strcat(fname, "/");
1059 strcat(fname, pd->filename);
1060
1061 if ((f = fopen(fname, "rb")) == NULL)
1062 return false;
1063
1064 r = fread(pd->ptable, sizeof(uint8_t), ptablesize(pd), f);
1065 fclose(f);
1066
1067 return r == ptablesize(pd);
1068}
1069
1070static bool
1071read_ttables_file()
1072{
1073 FILE *f;
1074 char fname[strlen(tabledir)+20];
1075 int b = sizeof(uint16_t);
1076 bool r = true;
1077 Move m;
1078
1079 strcpy(fname, tabledir);
1080 strcat(fname, "/");
1081 strcat(fname, "ttables");
1082
1083 if ((f = fopen(fname, "rb")) == NULL)
1084 return false;
1085
1086 for (m = 0; m < NTRANS; m++) {
1087 r = r && fread(epose_ttable[m], b, me[0], f) == me[0];
1088 r = r && fread(eposs_ttable[m], b, me[1], f) == me[1];
1089 r = r && fread(eposm_ttable[m], b, me[2], f) == me[2];
1090 r = r && fread(eo_ttable[m], b, me[3], f) == me[3];
1091 r = r && fread(cp_ttable[m], b, me[6], f) == me[6];
1092 r = r && fread(co_ttable[m], b, me[7], f) == me[7];
1093 r = r && fread(cpos_ttable[m], b, me[10], f) == me[10];
1094 r = r && fread(moves_ttable[m], b, me[11], f) == me[11];
1095 }
1096
1097 fclose(f);
1098 return r;
1099}
1100
1101static Cube
1102rotate_via_compose(Trans r, Cube c, PieceFilter f)
1103{
1104 Alg *inv;
1105 static int zero12[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1106 static int zero8[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
1107 static CubeArray ma = {
1108 .ep = ep_mirror,
1109 .eofb = zero12,
1110 .eorl = zero12,
1111 .eoud = zero12,
1112 .cp = cp_mirror,
1113 .coud = zero8,
1114 .corl = zero8,
1115 .cofb = zero8,
1116 .cpos = cpos_mirror
1117 };
1118
1119 Cube ret;
1120
1121 if (r != mirror) {
1122 ret = apply_alg_generic(trans_algs[r], c, f, true);
1123 inv = on_inverse(trans_algs[r]);
1124 ret = apply_alg_generic(inv, ret, f, true);
1125 free_alg(inv);
1126 } else {
1127 ret = move_via_arrays(&ma, (Cube){0}, f);
1128 ret = compose_filtered(c, ret, f);
1129 ret = move_via_arrays(&ma, ret, f);
1130 }
1131
1132 return ret;
1133}
1134
1135static int
1136subset_to_index(int *a, int n, int k)
1137{
1138 int i, ret = 0;
1139
1140 if (!is_subset(a, n, k))
1141 return binomial(n, k);
1142
1143 for (i = 0; i < n; i++) {
1144 if (k == n-i)
1145 return ret;
1146 if (a[i]) {
1147 ret += binomial(n-i-1, k);
1148 k--;
1149 }
1150 }
1151
1152 return ret;
1153}
1154
1155static void
1156sum_arrays_mod(int *src, int *dst, int n, int m)
1157{
1158 int i;
1159
1160 for (i = 0; i < n; i++)
1161 dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m;
1162}
1163
1164static void
1165swap(int *a, int *b)
1166{
1167 int aux;
1168
1169 aux = *a;
1170 *a = *b;
1171 *b = aux;
1172}
1173
1174static bool
1175write_algset_file(AlgSet *as)
1176{
1177 return false;
1178}
1179
1180static bool
1181write_mtables_file()
1182{
1183 FILE *f;
1184 char fname[strlen(tabledir)+20];
1185 int m, b = sizeof(uint16_t);
1186 bool r = true;
1187
1188 strcpy(fname, tabledir);
1189 strcat(fname, "/mtables");
1190
1191 if ((f = fopen(fname, "wb")) == NULL)
1192 return false;
1193
1194 for (m = 0; m < NMOVES; m++) {
1195 r = r && fwrite(epose_mtable[m], b, me[0], f) == me[0];
1196 r = r && fwrite(eposs_mtable[m], b, me[1], f) == me[1];
1197 r = r && fwrite(eposm_mtable[m], b, me[2], f) == me[2];
1198 r = r && fwrite(eofb_mtable[m], b, me[3], f) == me[3];
1199 r = r && fwrite(eorl_mtable[m], b, me[4], f) == me[4];
1200 r = r && fwrite(eoud_mtable[m], b, me[5], f) == me[5];
1201 r = r && fwrite(cp_mtable[m], b, me[6], f) == me[6];
1202 r = r && fwrite(coud_mtable[m], b, me[7], f) == me[7];
1203 r = r && fwrite(corl_mtable[m], b, me[8], f) == me[8];
1204 r = r && fwrite(cofb_mtable[m], b, me[9], f) == me[9];
1205 r = r && fwrite(cpos_mtable[m], b, me[10], f) == me[10];
1206 }
1207
1208 fclose(f);
1209 return r;
1210}
1211
1212static bool
1213write_ptable_file(PruneData *pd)
1214{
1215 FILE *f;
1216 char fname[strlen(tabledir)+100];
1217 uint64_t written;
1218
1219 strcpy(fname, tabledir);
1220 strcat(fname, "/");
1221 strcat(fname, pd->filename);
1222
1223 if ((f = fopen(fname, "wb")) == NULL)
1224 return false;
1225
1226 written = fwrite(pd->ptable, sizeof(uint8_t), ptablesize(pd), f);
1227 fclose(f);
1228
1229 return written == ptablesize(pd);
1230}
1231
1232static bool
1233write_ttables_file()
1234{
1235 FILE *f;
1236 char fname[strlen(tabledir)+20];
1237 bool r = true;
1238 int b = sizeof(uint16_t);
1239 Move m;
1240
1241 strcpy(fname, tabledir);
1242 strcat(fname, "/ttables");
1243
1244 if ((f = fopen(fname, "wb")) == NULL)
1245 return false;
1246
1247 for (m = 0; m < NTRANS; m++) {
1248 r = r && fwrite(epose_ttable[m], b, me[0], f) == me[0];
1249 r = r && fwrite(eposs_ttable[m], b, me[1], f) == me[1];
1250 r = r && fwrite(eposm_ttable[m], b, me[2], f) == me[2];
1251 r = r && fwrite(eo_ttable[m], b, me[3], f) == me[3];
1252 r = r && fwrite(cp_ttable[m], b, me[6], f) == me[6];
1253 r = r && fwrite(co_ttable[m], b, me[7], f) == me[7];
1254 r = r && fwrite(cpos_ttable[m], b, me[10], f) == me[10];
1255 r = r && fwrite(moves_ttable[m], b, me[11], f) == me[11];
1256 }
1257
1258 fclose(f);
1259 return r;
1260}
1261
1262/* Init functions implementation *********************************************/
1263
1264static void
1265init_auxtables()
1266{
1267 Cube c1, c2;
1268 CubeArray *arr;
1269 uint64_t ui, uj;
1270 int i, j, k, auxarr[12];
1271 bool cij, p1, p2;
1272
1273 for (ui = 0; ui < FACTORIAL6; ui++) {
1274 arr = new_cubearray((Cube){.cpos = ui}, pf_cpos);
1275 for (i = 0; i < 6; i++) {
1276 what_center_at_aux[ui][i] = arr->cpos[i];
1277 where_is_center_aux[ui][arr->cpos[i]] = i;
1278 }
1279 free_cubearray(arr, pf_cpos);
1280 }
1281
1282 for (ui = 0; ui < FACTORIAL8; ui++) {
1283 arr = new_cubearray((Cube){.cp = ui}, pf_cp);
1284 for (i = 0; i < 8; i++) {
1285 what_corner_at_aux[ui][i] = arr->cp[i];
1286 where_is_corner_aux[ui][arr->cp[i]] = i;
1287 }
1288 free_cubearray(arr, pf_cp);
1289 }
1290
1291 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
1292 arr = new_cubearray((Cube){.epose = ui}, pf_e);
1293 for (i = 0; i < 12; i++)
1294 if (edge_slice(arr->ep[i]) == 0)
1295 where_is_edge_aux[0][ui][arr->ep[i]] = i;
1296 free_cubearray(arr, pf_e);
1297
1298 arr = new_cubearray((Cube){.eposs = ui}, pf_s);
1299 for (i = 0; i < 12; i++)
1300 if (edge_slice(arr->ep[i]) == 1)
1301 where_is_edge_aux[1][ui][arr->ep[i]] = i;
1302 free_cubearray(arr, pf_s);
1303
1304 arr = new_cubearray((Cube){.eposm = ui}, pf_m);
1305 for (i = 0; i < 12; i++)
1306 if (edge_slice(arr->ep[i]) == 2)
1307 where_is_edge_aux[2][ui][arr->ep[i]] = i;
1308 free_cubearray(arr, pf_m);
1309 }
1310
1311 for (ui = 0; ui < POW3TO7; ui++) {
1312 int_to_sum_zero_array(ui, 3, 8, auxarr);
1313 what_orientation_last_corner_aux[ui] = auxarr[7];
1314 }
1315
1316 for (ui = 0; ui < POW2TO11; ui++) {
1317 int_to_sum_zero_array(ui, 2, 12, auxarr);
1318 what_orientation_last_edge_aux[ui] = auxarr[11];
1319 }
1320
1321 for (ui = 0; ui < BINOM12ON4; ui++)
1322 for (uj = 0; uj < BINOM12ON4; uj++)
1323 epos_dependent_aux[ui][uj] = epos_dependent(ui, uj);
1324
1325 for (i = 0; i < NMOVES; i++) {
1326 for (j = 0; j < NMOVES; j++) {
1327 c1 = apply_move(i, apply_move(j, (Cube){0}));
1328 c2 = apply_move(j, apply_move(i, (Cube){0}));
1329 commute[i][j] = equal(c1, c2) && i && j;
1330 }
1331 }
1332
1333 for (i = 0; i < NMOVES; i++) {
1334 for (j = 0; j < NMOVES; j++) {
1335 for (k = 0; k < NMOVES; k++) {
1336 p1 = j && base_move(j) == base_move(k);
1337 p2 = i && base_move(i) == base_move(k);
1338 cij = commute[i][j];
1339 possible_next[i][j][k] = !(p1 || (cij && p2));
1340 }
1341 }
1342 }
1343
1344 for (i = 0; i < NMOVES; i++)
1345 inverse_move_aux[i] = i ? i + 2 - 2*((i-1)%3) : NULLMOVE;
1346
1347 /* Is there a more elegant way? */
1348 inverse_trans_aux[uf] = uf;
1349 inverse_trans_aux[ur] = ul;
1350 inverse_trans_aux[ul] = ur;
1351 inverse_trans_aux[ub] = ub;
1352
1353 inverse_trans_aux[df] = df;
1354 inverse_trans_aux[dr] = dr;
1355 inverse_trans_aux[dl] = dl;
1356 inverse_trans_aux[db] = db;
1357
1358 inverse_trans_aux[rf] = lf;
1359 inverse_trans_aux[rd] = bl;
1360 inverse_trans_aux[rb] = rb;
1361 inverse_trans_aux[ru] = fr;
1362
1363 inverse_trans_aux[lf] = rf;
1364 inverse_trans_aux[ld] = br;
1365 inverse_trans_aux[lb] = lb;
1366 inverse_trans_aux[lu] = fl;
1367
1368 inverse_trans_aux[fu] = fu;
1369 inverse_trans_aux[fr] = ru;
1370 inverse_trans_aux[fd] = bu;
1371 inverse_trans_aux[fl] = lu;
1372
1373 inverse_trans_aux[bu] = fd;
1374 inverse_trans_aux[br] = ld;
1375 inverse_trans_aux[bd] = bd;
1376 inverse_trans_aux[bl] = rd;
1377
1378 inverse_trans_aux[mirror] = mirror;
1379}
1380
1381static void
1382init_environment()
1383{
1384 char *nissydata = getenv("NISSYDATA");
1385 char *localdata = getenv("XDG_DATA_HOME");
1386 char *home = getenv("HOME");
1387 bool read, write;
1388
1389 if (nissydata != NULL) {
1390 tabledir = malloc(strlen(nissydata) * sizeof(char) + 20);
1391 strcpy(tabledir, nissydata);
1392 } else if (localdata != NULL) {
1393 tabledir = malloc(strlen(localdata) * sizeof(char) + 20);
1394 strcpy(tabledir, localdata);
1395 strcat(tabledir, "/nissy");
1396 } else if (home != NULL) {
1397 tabledir = malloc(strlen(home) * sizeof(char) + 20);
1398 strcpy(tabledir, home);
1399 strcat(tabledir, "/.nissy");
1400 }
1401
1402 mkdir(tabledir, 0777);
1403 strcat(tabledir, "/tables");
1404 mkdir(tabledir, 0777);
1405
1406 read = !access(tabledir, R_OK);
1407 write = !access(tabledir, W_OK);
1408
1409 if (!read) {
1410 fprintf(stderr, "Table files cannot be read.\n");
1411 } else if (!write) {
1412 fprintf(stderr, "Data directory not writable: ");
1413 fprintf(stderr, "tables can be loaded, but not saved.\n");
1414 }
1415}
1416
1417static void
1418init_moves() {
1419 Cube c;
1420 CubeArray arrs;
1421 int i;
1422 uint16_t ui;
1423 Move m;
1424
1425 /* Generate all move cycles and flips; I do this regardless */
1426 for (i = 0; i < NMOVES; i++) {
1427 if (i == U || i == x || i == y)
1428 continue;
1429
1430 c = apply_alg_generic(equiv_alg[i], (Cube){0}, pf_all, false);
1431
1432 arrs = (CubeArray) {
1433 edge_cycle[i],
1434 eofb_flipped[i],
1435 eorl_flipped[i],
1436 eoud_flipped[i],
1437 corner_cycle[i],
1438 coud_flipped[i],
1439 corl_flipped[i],
1440 cofb_flipped[i],
1441 center_cycle[i]
1442 };
1443 cube_to_arrays(c, &arrs, pf_all);
1444 }
1445
1446 if (read_mtables_file())
1447 return;
1448
1449 fprintf(stderr, "Cannot load %s, generating it\n", "mtables");
1450
1451 /* Initialize transition tables */
1452 for (m = 0; m < NMOVES; m++) {
1453 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
1454 c = (Cube){ .epose = ui };
1455 c = apply_move_cubearray(m, c, pf_e);
1456 epose_mtable[m][ui] = c.epose;
1457
1458 c = (Cube){ .eposs = ui };
1459 c = apply_move_cubearray(m, c, pf_s);
1460 eposs_mtable[m][ui] = c.eposs;
1461
1462 c = (Cube){ .eposm = ui };
1463 c = apply_move_cubearray(m, c, pf_m);
1464 eposm_mtable[m][ui] = c.eposm;
1465 }
1466 for (ui = 0; ui < POW2TO11; ui++ ) {
1467 c = (Cube){ .eofb = ui };
1468 c = apply_move_cubearray(m, c, pf_eo);
1469 eofb_mtable[m][ui] = c.eofb;
1470
1471 c = (Cube){ .eorl = ui };
1472 c = apply_move_cubearray(m, c, pf_eo);
1473 eorl_mtable[m][ui] = c.eorl;
1474
1475 c = (Cube){ .eoud = ui };
1476 c = apply_move_cubearray(m, c, pf_eo);
1477 eoud_mtable[m][ui] = c.eoud;
1478 }
1479 for (ui = 0; ui < POW3TO7; ui++) {
1480 c = (Cube){ .coud = ui };
1481 c = apply_move_cubearray(m, c, pf_co);
1482 coud_mtable[m][ui] = c.coud;
1483
1484 c = (Cube){ .corl = ui };
1485 c = apply_move_cubearray(m, c, pf_co);
1486 corl_mtable[m][ui] = c.corl;
1487
1488 c = (Cube){ .cofb = ui };
1489 c = apply_move_cubearray(m, c, pf_co);
1490 cofb_mtable[m][ui] = c.cofb;
1491 }
1492 for (ui = 0; ui < FACTORIAL8; ui++) {
1493 c = (Cube){ .cp = ui };
1494 c = apply_move_cubearray(m, c, pf_cp);
1495 cp_mtable[m][ui] = c.cp;
1496 }
1497 for (ui = 0; ui < FACTORIAL6; ui++) {
1498 c = (Cube){ .cpos = ui };
1499 c = apply_move_cubearray(m, c, pf_cpos);
1500 cpos_mtable[m][ui] = c.cpos;
1501 }
1502 }
1503
1504 if (!write_mtables_file())
1505 fprintf(stderr, "Error writing mtables\n");
1506}
1507
1508static void
1509init_moves_aux()
1510{
1511 /* Some standard PieceFilters */
1512 pf_all.epose = true;
1513 pf_all.eposs = true;
1514 pf_all.eposm = true;
1515 pf_all.eofb = true;
1516 pf_all.eorl = true;
1517 pf_all.eoud = true;
1518 pf_all.cp = true;
1519 pf_all.cofb = true;
1520 pf_all.corl = true;
1521 pf_all.coud = true;
1522 pf_all.cpos = true;
1523
1524 pf_4val.epose = true;
1525 pf_4val.eposs = true;
1526 pf_4val.eposm = true;
1527 pf_4val.eofb = true;
1528 pf_4val.coud = true;
1529 pf_4val.cp = true;
1530
1531 pf_epcp.epose = true;
1532 pf_epcp.eposs = true;
1533 pf_epcp.eposm = true;
1534 pf_epcp.cp = true;
1535
1536 pf_cpos.cpos = true;
1537
1538 pf_cp.cp = true;
1539
1540 pf_ep.epose = true;
1541 pf_ep.eposs = true;
1542 pf_ep.eposm = true;
1543
1544 pf_e.epose = true;
1545 pf_s.eposs = true;
1546 pf_m.eposm = true;
1547
1548 pf_eo.eofb = true;
1549 pf_eo.eorl = true;
1550 pf_eo.eoud = true;
1551
1552 pf_co.cofb = true;
1553 pf_co.corl = true;
1554 pf_co.coud = true;
1555
1556 /* Used to convert to and from CubeArray */
1557 epe_solved[0] = FR;
1558 epe_solved[1] = FL;
1559 epe_solved[2] = BL;
1560 epe_solved[3] = BR;
1561
1562 eps_solved[0] = UL;
1563 eps_solved[1] = UR;
1564 eps_solved[2] = DL;
1565 eps_solved[3] = DR;
1566
1567 epm_solved[0] = UF;
1568 epm_solved[1] = UB;
1569 epm_solved[2] = DF;
1570 epm_solved[3] = DB;
1571
1572 /* Table sizes, used for reading and writing files */
1573 me[0] = FACTORIAL12/FACTORIAL8;
1574 me[1] = FACTORIAL12/FACTORIAL8;
1575 me[2] = FACTORIAL12/FACTORIAL8;
1576 me[3] = POW2TO11;
1577 me[4] = POW2TO11;
1578 me[5] = POW2TO11;
1579 me[6] = FACTORIAL8;
1580 me[7] = POW3TO7;
1581 me[8] = POW3TO7;
1582 me[9] = POW3TO7;
1583 me[10] = FACTORIAL6;
1584 me[11] = NMOVES;
1585
1586 /* Cycles *********************/
1587 edge_cycle[U][UF] = UR;
1588 edge_cycle[U][UL] = UF;
1589 edge_cycle[U][UB] = UL;
1590 edge_cycle[U][UR] = UB;
1591 edge_cycle[U][DF] = DF;
1592 edge_cycle[U][DL] = DL;
1593 edge_cycle[U][DB] = DB;
1594 edge_cycle[U][DR] = DR;
1595 edge_cycle[U][FR] = FR;
1596 edge_cycle[U][FL] = FL;
1597 edge_cycle[U][BL] = BL;
1598 edge_cycle[U][BR] = BR;
1599
1600 edge_cycle[x][UF] = DF;
1601 edge_cycle[x][UL] = FL;
1602 edge_cycle[x][UB] = UF;
1603 edge_cycle[x][UR] = FR;
1604 edge_cycle[x][DF] = DB;
1605 edge_cycle[x][DL] = BL;
1606 edge_cycle[x][DB] = UB;
1607 edge_cycle[x][DR] = BR;
1608 edge_cycle[x][FR] = DR;
1609 edge_cycle[x][FL] = DL;
1610 edge_cycle[x][BL] = UL;
1611 edge_cycle[x][BR] = UR;
1612
1613 edge_cycle[y][UF] = UR;
1614 edge_cycle[y][UL] = UF;
1615 edge_cycle[y][UB] = UL;
1616 edge_cycle[y][UR] = UB;
1617 edge_cycle[y][DF] = DR;
1618 edge_cycle[y][DL] = DF;
1619 edge_cycle[y][DB] = DL;
1620 edge_cycle[y][DR] = DB;
1621 edge_cycle[y][FR] = BR;
1622 edge_cycle[y][FL] = FR;
1623 edge_cycle[y][BL] = FL;
1624 edge_cycle[y][BR] = BL;
1625
1626 corner_cycle[U][UFR] = UBR;
1627 corner_cycle[U][UFL] = UFR;
1628 corner_cycle[U][UBL] = UFL;
1629 corner_cycle[U][UBR] = UBL;
1630 corner_cycle[U][DFR] = DFR;
1631 corner_cycle[U][DFL] = DFL;
1632 corner_cycle[U][DBL] = DBL;
1633 corner_cycle[U][DBR] = DBR;
1634
1635 corner_cycle[x][UFR] = DFR;
1636 corner_cycle[x][UFL] = DFL;
1637 corner_cycle[x][UBL] = UFL;
1638 corner_cycle[x][UBR] = UFR;
1639 corner_cycle[x][DFR] = DBR;
1640 corner_cycle[x][DFL] = DBL;
1641 corner_cycle[x][DBL] = UBL;
1642 corner_cycle[x][DBR] = UBR;
1643
1644 corner_cycle[y][UFR] = UBR;
1645 corner_cycle[y][UFL] = UFR;
1646 corner_cycle[y][UBL] = UFL;
1647 corner_cycle[y][UBR] = UBL;
1648 corner_cycle[y][DFR] = DBR;
1649 corner_cycle[y][DFL] = DFR;
1650 corner_cycle[y][DBL] = DFL;
1651 corner_cycle[y][DBR] = DBL;
1652
1653 center_cycle[U][U_center] = U_center;
1654 center_cycle[U][D_center] = D_center;
1655 center_cycle[U][R_center] = R_center;
1656 center_cycle[U][L_center] = L_center;
1657 center_cycle[U][F_center] = F_center;
1658 center_cycle[U][B_center] = B_center;
1659
1660 center_cycle[x][U_center] = F_center;
1661 center_cycle[x][D_center] = B_center;
1662 center_cycle[x][R_center] = R_center;
1663 center_cycle[x][L_center] = L_center;
1664 center_cycle[x][F_center] = D_center;
1665 center_cycle[x][B_center] = U_center;
1666
1667 center_cycle[y][U_center] = U_center;
1668 center_cycle[y][D_center] = D_center;
1669 center_cycle[y][R_center] = B_center;
1670 center_cycle[y][L_center] = F_center;
1671 center_cycle[y][F_center] = R_center;
1672 center_cycle[y][B_center] = L_center;
1673
1674 /* Flipped pieces *************/
1675 eofb_flipped[x][UF] = 1;
1676 eofb_flipped[x][UB] = 1;
1677 eofb_flipped[x][DF] = 1;
1678 eofb_flipped[x][DB] = 1;
1679
1680 eofb_flipped[y][FR] = 1;
1681 eofb_flipped[y][FL] = 1;
1682 eofb_flipped[y][BL] = 1;
1683 eofb_flipped[y][BR] = 1;
1684
1685 eorl_flipped[x][UF] = 1;
1686 eorl_flipped[x][UL] = 1;
1687 eorl_flipped[x][UB] = 1;
1688 eorl_flipped[x][UR] = 1;
1689 eorl_flipped[x][DF] = 1;
1690 eorl_flipped[x][DL] = 1;
1691 eorl_flipped[x][DB] = 1;
1692 eorl_flipped[x][DR] = 1;
1693 eorl_flipped[x][FR] = 1;
1694 eorl_flipped[x][FL] = 1;
1695 eorl_flipped[x][BL] = 1;
1696 eorl_flipped[x][BR] = 1;
1697
1698 eorl_flipped[y][FR] = 1;
1699 eorl_flipped[y][FL] = 1;
1700 eorl_flipped[y][BL] = 1;
1701 eorl_flipped[y][BR] = 1;
1702
1703 eoud_flipped[U][UF] = 1;
1704 eoud_flipped[U][UL] = 1;
1705 eoud_flipped[U][UB] = 1;
1706 eoud_flipped[U][UR] = 1;
1707
1708 eoud_flipped[x][UF] = 1;
1709 eoud_flipped[x][UB] = 1;
1710 eoud_flipped[x][DF] = 1;
1711 eoud_flipped[x][DB] = 1;
1712
1713 eoud_flipped[y][UF] = 1;
1714 eoud_flipped[y][UL] = 1;
1715 eoud_flipped[y][UB] = 1;
1716 eoud_flipped[y][UR] = 1;
1717 eoud_flipped[y][DF] = 1;
1718 eoud_flipped[y][DL] = 1;
1719 eoud_flipped[y][DB] = 1;
1720 eoud_flipped[y][DR] = 1;
1721 eoud_flipped[y][FR] = 1;
1722 eoud_flipped[y][FL] = 1;
1723 eoud_flipped[y][BL] = 1;
1724 eoud_flipped[y][BR] = 1;
1725
1726 coud_flipped[x][UFR] = 2;
1727 coud_flipped[x][UFL] = 1;
1728 coud_flipped[x][UBR] = 1;
1729 coud_flipped[x][UBL] = 2;
1730 coud_flipped[x][DFR] = 1;
1731 coud_flipped[x][DFL] = 2;
1732 coud_flipped[x][DBR] = 2;
1733 coud_flipped[x][DBL] = 1;
1734
1735 corl_flipped[U][UFR] = 1;
1736 corl_flipped[U][UFL] = 2;
1737 corl_flipped[U][UBL] = 1;
1738 corl_flipped[U][UBR] = 2;
1739
1740 corl_flipped[y][UFR] = 1;
1741 corl_flipped[y][UFL] = 2;
1742 corl_flipped[y][UBL] = 1;
1743 corl_flipped[y][UBR] = 2;
1744 corl_flipped[y][DFR] = 2;
1745 corl_flipped[y][DFL] = 1;
1746 corl_flipped[y][DBL] = 2;
1747 corl_flipped[y][DBR] = 1;
1748
1749 cofb_flipped[U][UFR] = 2;
1750 cofb_flipped[U][UFL] = 1;
1751 cofb_flipped[U][UBL] = 2;
1752 cofb_flipped[U][UBR] = 1;
1753
1754 cofb_flipped[x][UFR] = 1;
1755 cofb_flipped[x][UFL] = 2;
1756 cofb_flipped[x][UBL] = 1;
1757 cofb_flipped[x][UBR] = 2;
1758 cofb_flipped[x][DFR] = 2;
1759 cofb_flipped[x][DFL] = 1;
1760 cofb_flipped[x][DBL] = 2;
1761 cofb_flipped[x][DBR] = 1;
1762
1763 cofb_flipped[y][UFR] = 2;
1764 cofb_flipped[y][UFL] = 1;
1765 cofb_flipped[y][UBL] = 2;
1766 cofb_flipped[y][UBR] = 1;
1767 cofb_flipped[y][DFR] = 1;
1768 cofb_flipped[y][DFL] = 2;
1769 cofb_flipped[y][DBL] = 1;
1770 cofb_flipped[y][DBR] = 2;
1771
1772 /* Equivalent moves ***********/
1773 equiv_alg[NULLMOVE] = new_alg("");
1774
1775 equiv_alg[U] = new_alg(" U ");
1776 equiv_alg[U2] = new_alg(" UU ");
1777 equiv_alg[U3] = new_alg(" UUU ");
1778 equiv_alg[D] = new_alg(" xx U xx ");
1779 equiv_alg[D2] = new_alg(" xx UU xx ");
1780 equiv_alg[D3] = new_alg(" xx UUU xx ");
1781 equiv_alg[R] = new_alg(" yx U xxxyyy ");
1782 equiv_alg[R2] = new_alg(" yx UU xxxyyy ");
1783 equiv_alg[R3] = new_alg(" yx UUU xxxyyy ");
1784 equiv_alg[L] = new_alg(" yyyx U xxxy ");
1785 equiv_alg[L2] = new_alg(" yyyx UU xxxy ");
1786 equiv_alg[L3] = new_alg(" yyyx UUU xxxy ");
1787 equiv_alg[F] = new_alg(" x U xxx ");
1788 equiv_alg[F2] = new_alg(" x UU xxx ");
1789 equiv_alg[F3] = new_alg(" x UUU xxx ");
1790 equiv_alg[B] = new_alg(" xxx U x ");
1791 equiv_alg[B2] = new_alg(" xxx UU x ");
1792 equiv_alg[B3] = new_alg(" xxx UUU x ");
1793
1794 equiv_alg[Uw] = new_alg(" xx U xx y ");
1795 equiv_alg[Uw2] = new_alg(" xx UU xx yy ");
1796 equiv_alg[Uw3] = new_alg(" xx UUU xx yyy ");
1797 equiv_alg[Dw] = new_alg(" U yyy ");
1798 equiv_alg[Dw2] = new_alg(" UU yy ");
1799 equiv_alg[Dw3] = new_alg(" UUU y ");
1800 equiv_alg[Rw] = new_alg(" yyyx U xxxy x ");
1801 equiv_alg[Rw2] = new_alg(" yyyx UU xxxy xx ");
1802 equiv_alg[Rw3] = new_alg(" yyyx UUU xxxy xxx ");
1803 equiv_alg[Lw] = new_alg(" yx U xxxyyy xxx ");
1804 equiv_alg[Lw2] = new_alg(" yx UU xxxyyy xx ");
1805 equiv_alg[Lw3] = new_alg(" yx UUU xxxyyy x ");
1806 equiv_alg[Fw] = new_alg(" xxx U x yxxxyyy ");
1807 equiv_alg[Fw2] = new_alg(" xxx UU x yxxyyy ");
1808 equiv_alg[Fw3] = new_alg(" xxx UUU x yxyyy ");
1809 equiv_alg[Bw] = new_alg(" x U xxx yxyyy ");
1810 equiv_alg[Bw2] = new_alg(" x UU xxx yxxyyy ");
1811 equiv_alg[Bw3] = new_alg(" x UUU xxx yxxxyyy ");
1812
1813 equiv_alg[M] = new_alg(" yx U xx UUU yxyyy ");
1814 equiv_alg[M2] = new_alg(" yx UU xx UU xxxy ");
1815 equiv_alg[M3] = new_alg(" yx UUU xx U yxxxy ");
1816 equiv_alg[S] = new_alg(" x UUU xx U yyyx ");
1817 equiv_alg[S2] = new_alg(" x UU xx UU yyx ");
1818 equiv_alg[S3] = new_alg(" x U xx UUU yx ");
1819 equiv_alg[E] = new_alg(" U xx UUU xxyyy ");
1820 equiv_alg[E2] = new_alg(" UU xx UU xxyy ");
1821 equiv_alg[E3] = new_alg(" UUU xx U xxy ");
1822
1823 equiv_alg[x] = new_alg(" x ");
1824 equiv_alg[x2] = new_alg(" xx ");
1825 equiv_alg[x3] = new_alg(" xxx ");
1826 equiv_alg[y] = new_alg(" y ");
1827 equiv_alg[y2] = new_alg(" yy ");
1828 equiv_alg[y3] = new_alg(" yyy ");
1829 equiv_alg[z] = new_alg(" yyy x y ");
1830 equiv_alg[z2] = new_alg(" yy xx ");
1831 equiv_alg[z3] = new_alg(" y x yyy ");
1832}
1833
1834static void
1835init_strings()
1836{
1837 strcpy(move_string [NULLMOVE], "-" );
1838 strcpy(move_string [U], "U" );
1839 strcpy(move_string [U2], "U2" );
1840 strcpy(move_string [U3], "U\'" );
1841 strcpy(move_string [D], "D" );
1842 strcpy(move_string [D2], "D2" );
1843 strcpy(move_string [D3], "D\'" );
1844 strcpy(move_string [R], "R" );
1845 strcpy(move_string [R2], "R2" );
1846 strcpy(move_string [R3], "R\'" );
1847 strcpy(move_string [L], "L" );
1848 strcpy(move_string [L2], "L2" );
1849 strcpy(move_string [L3], "L\'" );
1850 strcpy(move_string [F], "F" );
1851 strcpy(move_string [F2], "F2" );
1852 strcpy(move_string [F3], "F\'" );
1853 strcpy(move_string [B], "B" );
1854 strcpy(move_string [B2], "B2" );
1855 strcpy(move_string [B3], "B\'" );
1856 strcpy(move_string [Uw], "Uw" );
1857 strcpy(move_string [Uw2], "Uw2" );
1858 strcpy(move_string [Uw3], "Uw\'" );
1859 strcpy(move_string [Dw], "Dw" );
1860 strcpy(move_string [Dw2], "Dw2" );
1861 strcpy(move_string [Dw3], "Dw\'" );
1862 strcpy(move_string [Rw], "Rw" );
1863 strcpy(move_string [Rw2], "Rw2" );
1864 strcpy(move_string [Rw3], "Rw\'" );
1865 strcpy(move_string [Lw], "Lw" );
1866 strcpy(move_string [Lw2], "Lw2" );
1867 strcpy(move_string [Lw3], "Lw\'" );
1868 strcpy(move_string [Fw], "Fw" );
1869 strcpy(move_string [Fw2], "Fw2" );
1870 strcpy(move_string [Fw3], "Fw\'" );
1871 strcpy(move_string [Bw], "Bw" );
1872 strcpy(move_string [Bw2], "Bw2" );
1873 strcpy(move_string [Bw3], "Bw\'" );
1874 strcpy(move_string [M], "M" );
1875 strcpy(move_string [M2], "M2" );
1876 strcpy(move_string [M3], "M\'" );
1877 strcpy(move_string [S], "S" );
1878 strcpy(move_string [S2], "S2" );
1879 strcpy(move_string [S3], "S\'" );
1880 strcpy(move_string [E], "E" );
1881 strcpy(move_string [E2], "E2" );
1882 strcpy(move_string [E3], "E\'" );
1883 strcpy(move_string [x], "x" );
1884 strcpy(move_string [x2], "x2" );
1885 strcpy(move_string [x3], "x\'" );
1886 strcpy(move_string [y], "y" );
1887 strcpy(move_string [y2], "y2" );
1888 strcpy(move_string [y3], "y\'" );
1889 strcpy(move_string [z], "z" );
1890 strcpy(move_string [z2], "z2" );
1891 strcpy(move_string [z3], "z\'" );
1892
1893 strcpy(edge_string [UF], "UF" );
1894 strcpy(edge_string [UL], "UL" );
1895 strcpy(edge_string [UB], "UB" );
1896 strcpy(edge_string [UR], "UR" );
1897 strcpy(edge_string [DF], "DF" );
1898 strcpy(edge_string [DL], "DL" );
1899 strcpy(edge_string [DB], "DB" );
1900 strcpy(edge_string [DR], "DR" );
1901 strcpy(edge_string [FR], "FR" );
1902 strcpy(edge_string [FL], "FL" );
1903 strcpy(edge_string [BL], "BL" );
1904 strcpy(edge_string [BR], "BR" );
1905
1906 strcpy(corner_string [UFR], "UFR" );
1907 strcpy(corner_string [UFL], "UFL" );
1908 strcpy(corner_string [UBL], "UBL" );
1909 strcpy(corner_string [UBR], "UBR" );
1910 strcpy(corner_string [DFR], "DFR" );
1911 strcpy(corner_string [DFL], "DFL" );
1912 strcpy(corner_string [DBL], "DBL" );
1913 strcpy(corner_string [DBR], "DBR" );
1914
1915 strcpy(center_string [U_center], "U" );
1916 strcpy(center_string [D_center], "D" );
1917 strcpy(center_string [R_center], "R" );
1918 strcpy(center_string [L_center], "L" );
1919 strcpy(center_string [F_center], "F" );
1920 strcpy(center_string [B_center], "B" );
1921}
1922
1923static void
1924init_trans() {
1925 Cube aux, cube, c[3];
1926 CubeArray epcp;
1927 int eparr[12], eoarr[12];
1928 int cparr[8], coarr[8];
1929 int i;
1930 bool b1, b2, b3;
1931 uint16_t ui;
1932 Move mi, move;
1933 Trans m;
1934
1935 /* Compute sources */
1936 for (i = 0; i < NTRANS; i++) {
1937 if (i == mirror)
1938 cube = (Cube){0};
1939 else
1940 cube = apply_alg(trans_algs[i], (Cube){0});
1941
1942 epose_source[i] = edge_slice(what_edge_at(cube, FR));
1943 eposs_source[i] = edge_slice(what_edge_at(cube, UR));
1944 eposm_source[i] = edge_slice(what_edge_at(cube, UF));
1945 eofb_source[i] = what_center_at(cube, F_center)/2;
1946 eorl_source[i] = what_center_at(cube, R_center)/2;
1947 eoud_source[i] = what_center_at(cube, U_center)/2;
1948 coud_source[i] = what_center_at(cube, U_center)/2;
1949 cofb_source[i] = what_center_at(cube, F_center)/2;
1950 corl_source[i] = what_center_at(cube, R_center)/2;
1951 }
1952
1953 if (read_ttables_file())
1954 return;
1955
1956 fprintf(stderr, "Cannot load %s, generating it\n", "ttables");
1957
1958 /* Initialize tables */
1959 for (m = 0; m < NTRANS; m++) {
1960 if (m == mirror) {
1961 memcpy(eparr, ep_mirror, 12 * sizeof(int));
1962 memcpy(cparr, cp_mirror, 8 * sizeof(int));
1963 } else {
1964 epcp = (CubeArray){ .ep = eparr, .cp = cparr };
1965 cube = apply_alg(trans_algs[m], (Cube){0});
1966 cube_to_arrays(cube, &epcp, pf_epcp);
1967 }
1968
1969 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
1970 c[0] = admissible_ep((Cube){ .epose = ui }, pf_e);
1971 c[1] = admissible_ep((Cube){ .eposs = ui }, pf_s);
1972 c[2] = admissible_ep((Cube){ .eposm = ui }, pf_m);
1973
1974 cube = rotate_via_compose(m,c[epose_source[m]],pf_ep);
1975 epose_ttable[m][ui] = cube.epose;
1976
1977 cube = rotate_via_compose(m,c[eposs_source[m]],pf_ep);
1978 eposs_ttable[m][ui] = cube.eposs;
1979
1980 cube = rotate_via_compose(m,c[eposm_source[m]],pf_ep);
1981 eposm_ttable[m][ui] = cube.eposm;
1982 }
1983 for (ui = 0; ui < POW2TO11; ui++ ) {
1984 int_to_sum_zero_array(ui, 2, 12, eoarr);
1985 apply_permutation(eparr, eoarr, 12);
1986 eo_ttable[m][ui] = digit_array_to_int(eoarr, 11, 2);
1987 }
1988 for (ui = 0; ui < POW3TO7; ui++) {
1989 int_to_sum_zero_array(ui, 3, 8, coarr);
1990 apply_permutation(cparr, coarr, 8);
1991 co_ttable[m][ui] = digit_array_to_int(coarr, 7, 3);
1992 if (m == mirror)
1993 co_ttable[m][ui] =
1994 invert_digits(co_ttable[m][ui], 3, 7);
1995 }
1996 for (ui = 0; ui < FACTORIAL8; ui++) {
1997 cube = (Cube){ .cp = ui };
1998 cube = rotate_via_compose(m, cube, pf_cp);
1999 cp_ttable[m][ui] = cube.cp;
2000 }
2001 for (ui = 0; ui < FACTORIAL6; ui++) {
2002 cube = (Cube){ .cpos = ui };
2003 cube = rotate_via_compose(m, cube, pf_cpos);
2004 cpos_ttable[m][ui] = cube.cpos;
2005 }
2006 for (mi = 0; mi < NMOVES; mi++) {
2007 if (m == mirror) {
2008 b1 = (mi >= U && mi <= Bw3);
2009 b2 = (mi >= S && mi <= E3);
2010 b3 = (mi >= x && mi <= z3);
2011 if (b1 || b2 || b3)
2012 moves_ttable[m][mi] =
2013 inverse_move_aux[mi];
2014 else
2015 moves_ttable[m][mi] = mi;
2016
2017 if ((mi-1)/3==(R-1)/3 || (mi-1)/3==(Rw-1)/3)
2018 moves_ttable[m][mi] += 3;
2019 if ((mi-1)/3==(L-1)/3 || (mi-1)/3==(L2-1)/3)
2020 moves_ttable[m][mi] -= 3;
2021 } else {
2022 aux = apply_trans(m, apply_move(mi,(Cube){0}));
2023 for (move = 0; move < NMOVES; move++) {
2024 cube = apply_move(
2025 inverse_move_aux[move], aux);
2026 if (is_solved(cube, false))
2027 moves_ttable[m][mi] = move;
2028 }
2029 }
2030 }
2031 }
2032
2033 if (!write_ttables_file())
2034 fprintf(stderr, "Error writing ttables\n");
2035}
2036
2037static void
2038init_trans_aux()
2039{
2040 ep_mirror[UF] = UF;
2041 ep_mirror[UL] = UR;
2042 ep_mirror[UB] = UB;
2043 ep_mirror[UR] = UL;
2044 ep_mirror[DF] = DF;
2045 ep_mirror[DL] = DR;
2046 ep_mirror[DB] = DB;
2047 ep_mirror[DR] = DL;
2048 ep_mirror[FR] = FL;
2049 ep_mirror[FL] = FR;
2050 ep_mirror[BR] = BL;
2051 ep_mirror[BL] = BR;
2052
2053 cp_mirror[UFR] = UFL;
2054 cp_mirror[UFL] = UFR;
2055 cp_mirror[UBL] = UBR;
2056 cp_mirror[UBR] = UBL;
2057 cp_mirror[DFR] = DFL;
2058 cp_mirror[DFL] = DFR;
2059 cp_mirror[DBL] = DBR;
2060 cp_mirror[DBR] = DBL;
2061
2062 cpos_mirror[U_center] = U_center;
2063 cpos_mirror[D_center] = D_center;
2064 cpos_mirror[R_center] = L_center;
2065 cpos_mirror[L_center] = R_center;
2066 cpos_mirror[F_center] = F_center;
2067 cpos_mirror[B_center] = B_center;
2068
2069 /* Is there a more elegant way? */
2070 trans_algs[uf] = new_alg("");
2071 trans_algs[ur] = new_alg("y");
2072 trans_algs[ub] = new_alg("y2");
2073 trans_algs[ul] = new_alg("y3");
2074
2075 trans_algs[df] = new_alg("z2");
2076 trans_algs[dr] = new_alg("y z2");
2077 trans_algs[db] = new_alg("x2");
2078 trans_algs[dl] = new_alg("y3 z2");
2079
2080 trans_algs[rf] = new_alg("z3");
2081 trans_algs[rd] = new_alg("z3 y");
2082 trans_algs[rb] = new_alg("z3 y2");
2083 trans_algs[ru] = new_alg("z3 y3");
2084
2085 trans_algs[lf] = new_alg("z");
2086 trans_algs[ld] = new_alg("z y3");
2087 trans_algs[lb] = new_alg("z y2");
2088 trans_algs[lu] = new_alg("z y");
2089
2090 trans_algs[fu] = new_alg("x y2");
2091 trans_algs[fr] = new_alg("x y");
2092 trans_algs[fd] = new_alg("x");
2093 trans_algs[fl] = new_alg("x y3");
2094
2095 trans_algs[bu] = new_alg("x3");
2096 trans_algs[br] = new_alg("x3 y");
2097 trans_algs[bd] = new_alg("x3 y2");
2098 trans_algs[bl] = new_alg("x3 y3");
2099}
2100
2101
2102/* Public functions implementation *******************************************/
2103
2104Cube
2105apply_alg(Alg *alg, Cube cube)
2106{
2107 return apply_alg_generic(alg, cube, pf_all, true);
2108}
2109
2110Cube
2111apply_move(Move m, Cube cube)
2112{
2113 return (Cube) {
2114 .epose = epose_mtable[m][cube.epose],
2115 .eposs = eposs_mtable[m][cube.eposs],
2116 .eposm = eposm_mtable[m][cube.eposm],
2117 .eofb = eofb_mtable[m][cube.eofb],
2118 .eorl = eorl_mtable[m][cube.eorl],
2119 .eoud = eoud_mtable[m][cube.eoud],
2120 .coud = coud_mtable[m][cube.coud],
2121 .cofb = cofb_mtable[m][cube.cofb],
2122 .corl = corl_mtable[m][cube.corl],
2123 .cp = cp_mtable[m][cube.cp],
2124 .cpos = cpos_mtable[m][cube.cpos]
2125 };
2126}
2127
2128Cube
2129apply_trans(Trans t, Cube cube)
2130{
2131 uint16_t aux_epos[3] = { cube.epose, cube.eposs, cube.eposm };
2132 uint16_t aux_eo[3] = { cube.eoud, cube.eorl, cube.eofb };
2133 uint16_t aux_co[3] = { cube.coud, cube.corl, cube.cofb };
2134
2135 return (Cube) {
2136 .epose = epose_ttable[t][aux_epos[epose_source[t]]],
2137 .eposs = eposs_ttable[t][aux_epos[eposs_source[t]]],
2138 .eposm = eposm_ttable[t][aux_epos[eposm_source[t]]],
2139 .eofb = eo_ttable[t][aux_eo[eofb_source[t]]],
2140 .eorl = eo_ttable[t][aux_eo[eorl_source[t]]],
2141 .eoud = eo_ttable[t][aux_eo[eoud_source[t]]],
2142 .coud = co_ttable[t][aux_co[coud_source[t]]],
2143 .corl = co_ttable[t][aux_co[corl_source[t]]],
2144 .cofb = co_ttable[t][aux_co[cofb_source[t]]],
2145 .cp = cp_ttable[t][cube.cp],
2146 .cpos = cpos_ttable[t][cube.cpos]
2147 };
2148}
2149
2150Move
2151base_move(Move m)
2152{
2153 if (m == NULLMOVE)
2154 return NULLMOVE;
2155 else
2156 return m - (m-1)%3;
2157}
2158
2159Cube
2160compose(Cube c2, Cube c1)
2161{
2162 return compose_filtered(c2, c1, pf_all);
2163}
2164
2165uint64_t
2166epos_dependent_cube(Cube c)
2167{
2168 return epos_dependent_aux[c.eposs/FACTORIAL4][c.epose/FACTORIAL4];
2169}
2170
2171bool
2172equal(Cube c1, Cube c2)
2173{
2174 return c1.eofb == c2.eofb &&
2175 c1.epose == c2.epose &&
2176 c1.eposs == c2.eposs &&
2177 c1.eposm == c2.eposm &&
2178 c1.coud == c2.coud &&
2179 c1.cp == c2.cp &&
2180 c1.cpos == c2.cpos;
2181}
2182
2183void
2184genalgset(AlgSet *as)
2185{
2186 uint64_t i;
2187
2188 if (as->generated)
2189 return;
2190
2191 /* TODO: check if memory is enough, otherwise maybe crash gracefully? */
2192 as->table = malloc(as->size * sizeof(AlgList *));
2193
2194 if (read_algset_file(as)) {
2195 as->generated = true;
2196 return;
2197 }
2198
2199 fprintf(stderr, "Cannot load %s, generating it\n", as->filename);
2200
2201 for (i = 0; i < as->size; i++) {
2202 as->table[i] = solve(as->antindex(i), as->step, &as->opts);
2203 fprintf(stderr, "Generated %lu / %lu cases\n", i, as->size);
2204 }
2205
2206 if (!write_algset_file(as))
2207 fprintf(stderr, "Error writing algset file\n");
2208
2209 as->generated = true;
2210}
2211
2212void
2213genptable(PruneData *pd)
2214{
2215 uint64_t j;
2216 DfsData dd = {
2217 .m = 0,
2218 .last1 = NULLMOVE,
2219 .last2 = NULLMOVE
2220 };
2221
2222 if (pd->generated)
2223 return;
2224
2225 /* TODO: check if memory is enough, otherwise maybe crash gracefully? */
2226 pd->ptable = malloc(ptablesize(pd) * sizeof(uint8_t));
2227
2228 if (read_ptable_file(pd)) {
2229 pd->generated = true;
2230 return;
2231 }
2232
2233 fprintf(stderr, "Cannot load %s, generating it\n", pd->filename);
2234
2235 /* We use 4 bits per value, so any distance >= 15 is set to 15 */
2236 for (j = 0; j < pd->size; j++)
2237 ptable_update(pd, j, 15);
2238
2239 moveset_to_list(pd->moveset, NULL, dd.sorted_moves);
2240 movelist_to_position(dd.sorted_moves, dd.move_position);
2241
2242 pd->reached = malloc(ptablesize(pd) * sizeof(uint8_t));
2243 for (dd.d = 0, pd->n = 0; dd.d < 15 && pd->n < pd->size; dd.d++) {
2244 memset(pd->reached, 0, ptablesize(pd)*sizeof(uint8_t));
2245 genptable_dfs((Cube){0}, pd, &dd);
2246 fprintf(stderr, "Depth %d completed, generated %lu/%lu\n",
2247 dd.d, pd->n, pd->size);
2248 }
2249
2250 if (!write_ptable_file(pd))
2251 fprintf(stderr, "Error writing ptable file\n");
2252
2253 pd->generated = true;
2254 free(pd->reached);
2255}
2256
2257Cube
2258inverse_cube(Cube cube)
2259{
2260 CubeArray *arr = new_cubearray(cube, pf_all);
2261 CubeArray *inv = new_cubearray((Cube){0}, pf_all);
2262 Cube ret;
2263 int i;
2264
2265 for (i = 0; i < 12; i++) {
2266 inv->ep[arr->ep[i]] = i;
2267 inv->eofb[arr->ep[i]] = arr->eofb[i];
2268 inv->eorl[arr->ep[i]] = arr->eorl[i];
2269 inv->eoud[arr->ep[i]] = arr->eoud[i];
2270 }
2271
2272 for (i = 0; i < 8; i++) {
2273 inv->cp[arr->cp[i]] = i;
2274 inv->coud[arr->cp[i]] = (3 - arr->coud[i]) % 3;
2275 inv->corl[arr->cp[i]] = (3 - arr->corl[i]) % 3;
2276 inv->cofb[arr->cp[i]] = (3 - arr->cofb[i]) % 3;
2277 }
2278
2279 for (int i = 0; i < 6; i++)
2280 inv->cpos[arr->cpos[i]] = i;
2281
2282 ret = arrays_to_cube(inv, pf_all);
2283 free_cubearray(arr, pf_all);
2284 free_cubearray(inv, pf_all);
2285
2286 return ret;
2287}
2288
2289Move
2290inverse_move(Move m)
2291{
2292 return inverse_move_aux[m];
2293}
2294
2295Trans
2296inverse_trans(Trans t)
2297{
2298 return inverse_trans_aux[t];
2299}
2300
2301bool
2302is_admissible(Cube cube)
2303{
2304 /* TODO: this should check consistency of different orientations */
2305 /* TODO: check that centers are opposite and admissible */
2306
2307 CubeArray *a = new_cubearray(cube, pf_all);
2308 int parity;
2309 bool perm;
2310
2311 perm = is_perm(a->ep, 12) &&
2312 is_perm(a->cp, 8) &&
2313 is_perm(a->cpos, 6);
2314 parity = perm_sign(a->ep, 12) +
2315 perm_sign(a->cp, 8) +
2316 perm_sign(a->cpos, 6);
2317
2318 return perm && parity % 2 == 0;
2319}
2320
2321bool
2322is_solved(Cube cube, bool reorient)
2323{
2324 Trans i;
2325
2326 if (reorient)
2327 for (i = 0; i < NROTATIONS; i++)
2328 if (is_solved(apply_alg(trans_algs[i],cube), false))
2329 return true;
2330
2331 return equal(cube, (Cube){0});
2332}
2333
2334bool
2335is_solved_block(Cube cube, Block block)
2336{
2337 int i;
2338
2339 for (i = 0; i < 12; i++)
2340 if (block.edge[i] && !is_solved_edge(cube, i))
2341 return false;
2342 for (i = 0; i < 8; i++)
2343 if (block.corner[i] && !is_solved_corner(cube, i))
2344 return false;
2345 for (i = 0; i < 6; i++)
2346 if (block.center[i] && !is_solved_center(cube, i))
2347 return false;
2348
2349 return true;
2350}
2351
2352bool
2353is_solved_center(Cube cube, Center c)
2354{
2355 return what_center_at(cube, c) == c;
2356}
2357
2358bool
2359is_solved_corner(Cube cube, Corner c)
2360{
2361 return what_corner_at(cube, c) == c &&
2362 what_orientation_corner(cube.coud, c);
2363}
2364
2365bool
2366is_solved_edge(Cube cube, Edge e)
2367{
2368 return what_edge_at(cube, e) == e &&
2369 what_orientation_edge(cube.eofb, e);
2370}
2371
2372int
2373piece_orientation(Cube cube, int piece, char *orientation)
2374{
2375 int arr[12], n, b;
2376 uint16_t x;
2377
2378 if (!strcmp(orientation, "eofb")) {
2379 x = cube.eofb;
2380 n = 12;
2381 b = 2;
2382 } else if (!strcmp(orientation, "eorl")) {
2383 x = cube.eorl;
2384 n = 12;
2385 b = 2;
2386 } else if (!strcmp(orientation, "eoud")) {
2387 x = cube.eoud;
2388 n = 12;
2389 b = 2;
2390 } else if (!strcmp(orientation, "coud")) {
2391 x = cube.coud;
2392 n = 8;
2393 b = 3;
2394 } else if (!strcmp(orientation, "corl")) {
2395 x = cube.corl;
2396 n = 8;
2397 b = 3;
2398 } else if (!strcmp(orientation, "cofb")) {
2399 x = cube.cofb;
2400 n = 8;
2401 b = 3;
2402 } else {
2403 return -1;
2404 }
2405
2406 int_to_sum_zero_array(x, b, n, arr);
2407 if (piece < n)
2408 return arr[piece];
2409
2410 return -1;
2411}
2412
2413void
2414print_cube(Cube cube)
2415{
2416/*
2417 CubeArray *arr = new_cubearray(cube, pf_all);
2418
2419 for (int i = 0; i < 12; i++)
2420 printf(" %s ", edge_string[arr->ep[i]]);
2421 printf("\n");
2422
2423 for (int i = 0; i < 12; i++)
2424 printf(" %c ", arr->eofb[i] + '0');
2425 printf("\n");
2426
2427 for (int i = 0; i < 8; i++)
2428 printf("%s ", corner_string[arr->cp[i]]);
2429 printf("\n");
2430
2431 for (int i = 0; i < 8; i++)
2432 printf(" %c ", arr->coud[i] + '0');
2433 printf("\n");
2434
2435 for (int i = 0; i < 6; i++)
2436 printf(" %s ", center_string[arr->cpos[i]]);
2437 printf("\n");
2438
2439 free_cubearray(arr, pf_all);
2440*/
2441
2442 for (int i = 0; i < 12; i++)
2443 printf(" %s ", edge_string[what_edge_at(cube, i)]);
2444 printf("\n");
2445
2446 for (int i = 0; i < 12; i++)
2447 printf(" %d ", what_orientation_edge(cube.eofb, i));
2448 printf("\n");
2449
2450 for (int i = 0; i < 8; i++)
2451 printf("%s ", corner_string[what_corner_at(cube, i)]);
2452 printf("\n");
2453
2454 for (int i = 0; i < 8; i++)
2455 printf(" %d ", what_orientation_corner(cube.coud, i));
2456 printf("\n");
2457
2458 for (int i = 0; i < 6; i++)
2459 printf(" %s ", center_string[what_center_at(cube, i)]);
2460 printf("\n");
2461
2462}
2463
2464Cube
2465random_cube()
2466{
2467 CubeArray *arr = new_cubearray((Cube){0}, pf_4val);
2468 Cube ret;
2469 int ep, cp, eo, co;
2470
2471 ep = rand() % FACTORIAL12;
2472 cp = rand() % FACTORIAL8;
2473 eo = rand() % POW2TO11;
2474 co = rand() % POW3TO7;
2475
2476 index_to_perm(ep, 12, arr->ep);
2477 index_to_perm(cp, 8, arr->cp);
2478 int_to_sum_zero_array(eo, 2, 12, arr->eofb);
2479 int_to_sum_zero_array(co, 3, 8, arr->coud);
2480
2481 if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8))
2482 swap(&(arr->ep[0]), &(arr->ep[1]));
2483
2484 ret = arrays_to_cube(arr, pf_4val);
2485 free_cubearray(arr, pf_4val);
2486
2487 return ret;
2488}
2489
2490AlgList *
2491solve(Cube cube, Step step, SolveOptions *opts)
2492{
2493 AlgListNode *node;
2494 AlgList *sols = new_alglist();
2495 Cube c = apply_trans(opts->pre_trans, cube);
2496 DfsData dd = {
2497 .m = 0,
2498 .niss = false,
2499 .lb = -1,
2500 .last1 = NULLMOVE,
2501 .last2 = NULLMOVE,
2502 .sols = sols,
2503 .current_alg = new_alg("")
2504 };
2505
2506 if (step.ready != NULL && step.ready(c, 1) != 0) {
2507 fprintf(stderr, "Cube not ready for solving step\n");
2508 return sols;
2509 }
2510
2511 moveset_to_list(step.moveset, step.check, dd.sorted_moves);
2512 movelist_to_position(dd.sorted_moves, dd.move_position);
2513
2514 for (dd.d = opts->min_moves;
2515 dd.d <= opts->max_moves && !(sols->len && opts->optimal_only);
2516 dd.d++) {
2517 if (opts->feedback)
2518 fprintf(stderr,
2519 "Found %d solutions, searching depth %d...\n",
2520 sols->len, dd.d);
2521 dfs(c, step, opts, &dd);
2522 }
2523
2524 for (node = sols->first; node != NULL; node = node->next)
2525 transform_alg(inverse_trans_aux[opts->pre_trans], node->alg);
2526
2527 free_alg(dd.current_alg);
2528 return sols;
2529}
2530
2531Alg *
2532inverse_alg(Alg *alg)
2533{
2534 Alg *ret = new_alg("");
2535 int i;
2536
2537 for (i = alg->len-1; i >= 0; i--)
2538 append_move(ret, alg->move[i], alg->inv[i]);
2539
2540 return ret;
2541}
2542
2543Alg *
2544new_alg(char *str)
2545{
2546 Alg *alg = malloc(sizeof(Alg));
2547 int i;
2548 bool niss = false;
2549 Move j, m;
2550
2551 alg->move = malloc(30 * sizeof(Move));
2552 alg->inv = malloc(30 * sizeof(bool));
2553 alg->allocated = 30;
2554 alg->len = 0;
2555
2556 for (i = 0; str[i]; i++) {
2557 if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n')
2558 continue;
2559
2560 if (str[i] == '(' && niss) {
2561 fprintf(stderr, "Error reading moves: nested ( )\n");
2562 return alg;
2563 }
2564
2565 if (str[i] == ')' && !niss) {
2566 fprintf(stderr, "Error reading moves: unmatched )\n");
2567 return alg;
2568 }
2569
2570 if (str[i] == '(' || str[i] == ')') {
2571 niss = !niss;
2572 continue;
2573 }
2574
2575 for (j = 0; j < NMOVES; j++) {
2576 if (str[i] == move_string[j][0]) {
2577 m = j;
2578 if (m <= B && str[i+1]=='w') {
2579 m += Uw - U;
2580 i++;
2581 }
2582 if (str[i+1]=='2') {
2583 m += 1;
2584 i++;
2585 } else if (str[i+1]=='\'' || str[i+1]=='3') {
2586 m += 2;
2587 i++;
2588 }
2589 append_move(alg, m, niss);
2590 break;
2591 }
2592 }
2593 }
2594
2595 return alg;
2596}
2597
2598Alg *
2599on_inverse(Alg *alg)
2600{
2601 Alg *ret = new_alg("");
2602 int i;
2603
2604 for (i = 0; i < alg->len; i++)
2605 append_move(ret, alg->move[i], !alg->inv[i]);
2606
2607 return ret;
2608}
2609
2610void
2611print_alg(Alg *alg, bool l)
2612{
2613 /* TODO: make it possible to print to stdout or to string */
2614 /* Maybe just return a string */
2615 char fill[4];
2616 int i;
2617 bool niss = false;
2618
2619 for (i = 0; i < alg->len; i++) {
2620 if (!niss && alg->inv[i])
2621 strcpy(fill, i == 0 ? "(" : " (");
2622 if (niss && !alg->inv[i])
2623 strcpy(fill, ") ");
2624 if (niss == alg->inv[i])
2625 strcpy(fill, i == 0 ? "" : " ");
2626
2627 printf("%s%s", fill, move_string[alg->move[i]]);
2628 niss = alg->inv[i];
2629 }
2630
2631 if (niss)
2632 printf(")");
2633 if (l)
2634 printf(" (%d)", alg->len);
2635
2636 printf("\n");
2637}
2638
2639void
2640print_alglist(AlgList *al, bool l)
2641{
2642 AlgListNode *i;
2643
2644 for (i = al->first; i != NULL; i = i->next)
2645 print_alg(i->alg, l);
2646}
2647
2648void
2649print_ptable(PruneData *pd)
2650{
2651 uint64_t i, a[16];
2652
2653 for (i = 0; i < 16; i++)
2654 a[i] = 0;
2655
2656 if (!pd->generated)
2657 genptable(pd);
2658
2659 for (i = 0; i < pd->size; i++)
2660 a[ptableval(pd, i)]++;
2661
2662 fprintf(stderr, "Values for table %s\n", pd->filename);
2663 for (i = 0; i < 16; i++)
2664 printf("%2lu\t%10lu\n", i, a[i]);
2665}
2666
2667uint64_t
2668ptablesize(PruneData *pd)
2669{
2670 return (pd->size + 1) / 2;
2671}
2672
2673int
2674ptableval(PruneData *pd, uint64_t ind)
2675{
2676 return (ind % 2) ? pd->ptable[ind/2] / 16 : pd->ptable[ind/2] % 16;
2677}
2678
2679
2680Alg *
2681trans_alg(Trans i)
2682{
2683 return trans_algs[i];
2684}
2685
2686void
2687transform_alg(Trans t, Alg *alg)
2688{
2689 int i;
2690
2691 for (i = 0; i < alg->len; i++)
2692 alg->move[i] = moves_ttable[t][alg->move[i]];
2693}
2694
2695Center
2696what_center_at(Cube cube, Center c)
2697{
2698 return what_center_at_aux[cube.cpos][c];
2699}
2700
2701Corner
2702what_corner_at(Cube cube, Corner c)
2703{
2704 return what_corner_at_aux[cube.cp][c];
2705}
2706
2707Edge
2708what_edge_at(Cube cube, Edge e)
2709{
2710 Edge ret;
2711 CubeArray *arr = new_cubearray(cube, pf_ep);
2712
2713 ret = arr->ep[e];
2714
2715 free_cubearray(arr, pf_ep);
2716 return ret;
2717}
2718
2719int
2720what_orientation_corner(int co, Corner c)
2721{
2722 if (c < 7)
2723 return (co / powint(3, c)) % 3;
2724 else
2725 return what_orientation_last_corner_aux[co];
2726}
2727
2728int
2729what_orientation_edge(int eo, Edge e)
2730{
2731 if (e < 11)
2732 return (eo & (1 << e)) ? 1 : 0;
2733 else
2734 return what_orientation_last_edge_aux[eo];
2735}
2736
2737Center
2738where_is_center(Cube cube, Center c)
2739{
2740 return where_is_center_aux[cube.cpos][c];
2741}
2742
2743Corner
2744where_is_corner(Cube cube, Corner c)
2745{
2746 return where_is_corner_aux[cube.cp][c];
2747}
2748
2749
2750void
2751init()
2752{
2753 /* Order is important! */
2754 init_environment();
2755 init_strings();
2756 init_moves_aux();
2757 init_moves();
2758 init_auxtables();
2759 init_trans_aux();
2760 init_trans();
2761}
2762
diff --git a/old/2021-06-23-uint16t/cube.h b/old/2021-06-23-uint16t/cube.h
new file mode 100644
index 0000000..74d14cc
--- /dev/null
+++ b/old/2021-06-23-uint16t/cube.h
@@ -0,0 +1,87 @@
1#ifndef CUBE_H
2#define CUBE_H
3
4#include <stdio.h>
5#include <stdbool.h>
6#include <stdint.h>
7#include <stdlib.h>
8#include <string.h>
9#include <time.h>
10#include <unistd.h>
11#include <sys/stat.h>
12
13/* Constants and macros *****************************************************/
14
15#define POW2TO6 64ULL
16#define POW2TO11 2048ULL
17#define POW2TO12 4096ULL
18#define POW3TO7 2187ULL
19#define POW3TO8 6561ULL
20#define FACTORIAL4 24ULL
21#define FACTORIAL6 720ULL
22#define FACTORIAL7 5040ULL
23#define FACTORIAL8 40320ULL
24#define FACTORIAL12 479001600ULL
25#define BINOM12ON4 495ULL
26#define BINOM8ON4 70ULL
27#define MIN(a,b) (((a) < (b)) ? (a) : (b))
28#define MAX(a,b) (((a) > (b)) ? (a) : (b))
29
30#define NMOVES (z3+1)
31#define NTRANS (mirror+1)
32#define NROTATIONS (NTRANS-1)
33
34/* Type definitions **********************************************************/
35
36#include "cubetypes.h"
37
38/* Public functions **********************************************************/
39
40Cube apply_alg(Alg *alg, Cube cube);
41Cube apply_move(Move m, Cube cube);
42Cube apply_trans(Trans t, Cube cube);
43bool block_solved(Cube cube, Block);
44Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */
45uint64_t epos_dependent_cube(Cube cube);
46bool equal(Cube c1, Cube c2);
47Cube inverse_cube(Cube cube);
48Move inverse_move(Move m);
49Trans inverse_trans(Trans t);
50bool is_admissible(Cube cube);
51bool is_solved(Cube cube, bool reorient);
52bool is_solved_center(Cube cube, Center c);
53bool is_solved_corner(Cube cube, Corner c);
54bool is_solved_edge(Cube cube, Edge e);
55void print_cube(Cube cube);
56Cube random_cube();
57AlgList * solve(Cube cube, Step step, SolveOptions *opts);
58Center what_center_at(Cube cube, Center c);
59Corner what_corner_at(Cube cube, Corner c);
60Edge what_edge_at(Cube cube, Edge e);
61int what_orientation_corner(int co, Corner c);
62int what_orientation_edge(int eo, Edge e);
63Center where_is_center(Cube cube, Center c);
64Corner where_is_corner(Cube cube, Corner c);
65Edge where_is_edge(Cube cube, Edge e);
66
67Move base_move(Move m);
68void free_alg(Alg *alg);
69void free_alglist(AlgList *l);
70Alg * inverse_alg(Alg *alg);
71Alg * new_alg(char *str);
72Alg * on_inverse(Alg *alg);
73void print_alg(Alg *alg, bool l);
74void print_alglist(AlgList *al, bool l);
75Alg * trans_alg(Trans i);
76void transform_alg(Trans t, Alg *alg);
77
78void genalgset(AlgSet *as);
79void genptable(PruneData *pd);
80void print_ptable(PruneData *pd);
81uint64_t ptablesize(PruneData *pd);
82int ptableval(PruneData *pd, uint64_t ind);
83
84void init();
85
86#endif
87
diff --git a/old/2021-06-23-uint16t/cubetypes.h b/old/2021-06-23-uint16t/cubetypes.h
new file mode 100644
index 0000000..10bfabb
--- /dev/null
+++ b/old/2021-06-23-uint16t/cubetypes.h
@@ -0,0 +1,224 @@
1/* Typedefs ******************************************************************/
2
3typedef enum center Center;
4typedef enum corner Corner;
5typedef enum edge Edge;
6typedef enum move Move;
7typedef enum trans Trans;
8
9typedef struct alg Alg;
10typedef struct alglist AlgList;
11typedef struct alglistnode AlgListNode;
12typedef struct algset AlgSet;
13typedef struct block Block;
14typedef struct cube Cube;
15typedef struct cubearray CubeArray;
16typedef struct dfsdata DfsData;
17typedef struct piecefilter PieceFilter;
18typedef struct prunedata PruneData;
19typedef struct solveoptions SolveOptions;
20typedef struct step Step;
21
22typedef Cube (*AntiIndexer) (uint64_t);
23typedef int (*Checker) (Cube, int);
24typedef uint64_t (*Indexer) (Cube);
25typedef bool (*Moveset) (Move);
26
27
28/* Enums *********************************************************************/
29
30enum
31center
32{
33 U_center, D_center,
34 R_center, L_center,
35 F_center, B_center
36};
37
38enum
39corner
40{
41 UFR, UFL, UBL, UBR,
42 DFR, DFL, DBL, DBR
43};
44
45enum
46edge
47{
48 UF, UL, UB, UR,
49 DF, DL, DB, DR,
50 FR, FL, BL, BR
51};
52
53enum
54move
55{
56 NULLMOVE,
57 U, U2, U3, D, D2, D3,
58 R, R2, R3, L, L2, L3,
59 F, F2, F3, B, B2, B3,
60 Uw, Uw2, Uw3, Dw, Dw2, Dw3,
61 Rw, Rw2, Rw3, Lw, Lw2, Lw3,
62 Fw, Fw2, Fw3, Bw, Bw2, Bw3,
63 M, M2, M3,
64 S, S2, S3,
65 E, E2, E3,
66 x, x2, x3,
67 y, y2, y3,
68 z, z2, z3,
69};
70
71enum
72trans
73{
74 uf, ur, ub, ul,
75 df, dr, db, dl,
76 rf, rd, rb, ru,
77 lf, ld, lb, lu,
78 fu, fr, fd, fl,
79 bu, br, bd, bl,
80 mirror, /* R|L */
81};
82
83
84/* Structs *******************************************************************/
85
86struct
87alg
88{
89 Move * move;
90 bool * inv;
91 int len;
92 int allocated;
93};
94
95struct
96alglist
97{
98 AlgListNode * first;
99 AlgListNode * last;
100 int len;
101};
102
103struct
104alglistnode
105{
106 Alg * alg;
107 AlgListNode * next;
108};
109
110struct
111block
112{
113 bool edge[12];
114 bool corner[8];
115 bool center[6];
116};
117
118struct
119cube
120{
121 uint16_t epose;
122 uint16_t eposs;
123 uint16_t eposm;
124 uint16_t eofb;
125 uint16_t eorl;
126 uint16_t eoud;
127 uint16_t cp;
128 uint16_t coud;
129 uint16_t cofb;
130 uint16_t corl;
131 uint16_t cpos;
132};
133
134struct
135cubearray
136{
137 int * ep;
138 int * eofb;
139 int * eorl;
140 int * eoud;
141 int * cp;
142 int * coud;
143 int * corl;
144 int * cofb;
145 int * cpos;
146};
147
148struct
149dfsdata
150{
151 int d;
152 int m;
153 int lb;
154 bool niss;
155 Move last1;
156 Move last2;
157 AlgList * sols;
158 Alg * current_alg;
159 Move sorted_moves[NMOVES];
160 int move_position[NMOVES];
161};
162
163struct
164piecefilter
165{
166 bool epose;
167 bool eposs;
168 bool eposm;
169 bool eofb;
170 bool eorl;
171 bool eoud;
172 bool cp;
173 bool coud;
174 bool cofb;
175 bool corl;
176 bool cpos;
177};
178
179struct
180prunedata
181{
182 char * filename;
183 uint8_t * ptable;
184 uint8_t * reached;
185 bool generated;
186 uint64_t n;
187 uint64_t size;
188 Indexer index;
189 Moveset moveset;
190};
191
192struct
193solveoptions
194{
195 int min_moves;
196 int max_moves;
197 int max_solutions;
198 bool optimal_only;
199 bool can_niss;
200 bool feedback;
201 Trans pre_trans;
202};
203
204struct
205step
206{
207 Checker check;
208 Checker ready;
209 Moveset moveset;
210};
211
212/* TODO: I put it here because it needs the definition of Step, sort it out */
213struct
214algset
215{
216 char * filename;
217 AlgList ** table;
218 bool generated;
219 uint64_t size;
220 Indexer index;
221 AntiIndexer antindex;
222 Step step;
223 SolveOptions opts;
224};
diff --git a/old/2021-06-30-noreached/cube.c b/old/2021-06-30-noreached/cube.c
new file mode 100644
index 0000000..a7d137c
--- /dev/null
+++ b/old/2021-06-30-noreached/cube.c
@@ -0,0 +1,3394 @@
1#include "cube.h"
2
3/* Local functions **********************************************************/
4
5static Cube admissible_ep(Cube cube, PieceFilter f);
6static Cube admissible_eos_from_eofbepos(Cube cube);
7static bool allowed_next(Move move, DfsData *dd);
8static void append_alg(AlgList *l, Alg *alg);
9static void append_move(Alg *alg, Move m, bool inverse);
10static Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a);
11static void apply_permutation(int *perm, int *set, int n);
12static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f);
13static int array_ep_to_epos(int *ep, int *eps_solved);
14static Cube arrays_to_cube(CubeArray *arr, PieceFilter f);
15static int binomial(int n, int k);
16static Cube compose_filtered(Cube c2, Cube c1, PieceFilter f);
17static void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f);
18static void dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd);
19static void dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd);
20static bool dfs_check_solved(SolveOptions *opts, DfsData *dd);
21static void dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd);
22static bool dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd);
23static int digit_array_to_int(int *a, int n, int b);
24static int edge_slice(Edge e); /* E=0, S=1, M=2 */
25static int epos_dependent_pos(int pos1, int pos2);
26static int epos_from_arrays(int *epos, int *ep);
27static void epos_to_partial_ep(int epos, int *ep, int *ss);
28static int factorial(int n);
29static void free_alglistnode(AlgListNode *aln);
30static void free_cubearray(CubeArray *arr, PieceFilter f);
31static void genptable_dfs(Cube c, PruneData *pd, DfsData *dd);
32static void genptable_dfs_branch(Cube c, PruneData *pd, DfsData *dd);
33static void gensym(SymData *sd);
34static void index_to_perm(int p, int n, int *r);
35static void index_to_subset(int s, int n, int k, int *r);
36static void init_auxtables();
37static void init_cphtr_cosets();
38static void init_cphtr_left_cosets_bfs(int i, int c);
39static void init_cphtr_right_cosets_color(int i, int c);
40static void init_environment();
41static void init_moves();
42static void init_moves_aux();
43static void init_strings();
44static void init_symdata();
45static void init_trans();
46static void init_trans_aux();
47static void int_to_digit_array(int a, int b, int n, int *r);
48static void int_to_sum_zero_array(int x, int b, int n, int *a);
49static int invert_digits(int a, int b, int n);
50static bool is_perm(int *a, int n);
51static bool is_subset(int *a, int n, int k);
52static Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf);
53static void movelist_to_position(Move *movelist, int *position);
54static void moveset_to_list(Moveset ms, Estimator f, Move *r);
55static AlgList * new_alglist();
56static CubeArray * new_cubearray(Cube cube, PieceFilter f);
57static int perm_sign(int *a, int n);
58static int perm_to_index(int *a, int n);
59static int powint(int a, int b);
60static void ptable_update(PruneData *pd, Cube cube, int m);
61static void realloc_alg(Alg *alg, int n);
62static bool read_mtables_file();
63static bool read_ptable_file(PruneData *pd);
64static bool read_symdata_file(SymData *sd);
65static bool read_ttables_file();
66static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f);
67static int subset_to_index(int *a, int n, int k);
68static void sum_arrays_mod(int *src, int *dst, int n, int m);
69static void swap(int *a, int *b);
70static bool write_mtables_file();
71static bool write_ptable_file(PruneData *pd);
72static bool write_symdata_file(SymData *sd);
73static bool write_ttables_file();
74
75
76/* All sorts of useful costants and tables **********************************/
77
78static char * tabledir;
79
80static PieceFilter pf_all;
81static PieceFilter pf_4val;
82static PieceFilter pf_epcp;
83static PieceFilter pf_cpos;
84static PieceFilter pf_cp;
85static PieceFilter pf_ep;
86static PieceFilter pf_e;
87static PieceFilter pf_s;
88static PieceFilter pf_m;
89static PieceFilter pf_eo;
90static PieceFilter pf_co;
91
92static int epe_solved[4];
93static int eps_solved[4];
94static int epm_solved[4];
95
96static char move_string[NMOVES][7];
97static char edge_string[12][7];
98static char corner_string[8][7];
99static char center_string[6][7];
100
101static Cube admissible_ee_aux[POW2TO11*BINOM12ON4];
102static bool commute[NMOVES][NMOVES];
103static bool possible_next[NMOVES][NMOVES][NMOVES];
104static Move inverse_move_aux[NMOVES];
105static Trans inverse_trans_aux[NTRANS];
106static int epos_dependent_aux[BINOM12ON4][BINOM12ON4];
107static int cphtr_left_cosets[FACTORIAL8];
108static int cphtr_right_cosets[FACTORIAL8];
109static int cphtr_right_rep[BINOM8ON4*6];
110static Center what_center_at_aux[FACTORIAL6][6];
111static Corner what_corner_at_aux[FACTORIAL8][8];
112static int what_orientation_last_corner_aux[POW3TO7];
113static int what_orientation_last_edge_aux[POW2TO11];
114static Center where_is_center_aux[FACTORIAL6][6];
115static Corner where_is_corner_aux[FACTORIAL8][8];
116static Edge where_is_edge_aux[3][FACTORIAL12/FACTORIAL8][12];
117
118static int epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
119static int eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
120static int eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
121static int eo_ttable[NTRANS][POW2TO11];
122static int cp_ttable[NTRANS][FACTORIAL8];
123static int co_ttable[NTRANS][POW3TO7];
124static int cpos_ttable[NTRANS][FACTORIAL6];
125static Move moves_ttable[NTRANS][NMOVES];
126
127static int epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
128static int eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
129static int eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
130static int eofb_mtable[NMOVES][POW2TO11];
131static int eorl_mtable[NMOVES][POW2TO11];
132static int eoud_mtable[NMOVES][POW2TO11];
133static int cp_mtable[NMOVES][FACTORIAL8];
134static int coud_mtable[NMOVES][POW3TO7];
135static int cofb_mtable[NMOVES][POW3TO7];
136static int corl_mtable[NMOVES][POW3TO7];
137static int cpos_mtable[NMOVES][FACTORIAL6];
138
139static uint64_t me[12];
140
141static int edge_cycle[NMOVES][12];
142static int corner_cycle[NMOVES][8];
143static int center_cycle[NMOVES][6];
144static int eofb_flipped[NMOVES][12];
145static int eorl_flipped[NMOVES][12];
146static int eoud_flipped[NMOVES][12];
147static int coud_flipped[NMOVES][8];
148static int corl_flipped[NMOVES][8];
149static int cofb_flipped[NMOVES][8];
150static Alg * equiv_alg[NMOVES];
151
152static int epose_source[NTRANS]; /* 0=epose, 1=eposs, 2=eposm */
153static int eposs_source[NTRANS];
154static int eposm_source[NTRANS];
155static int eofb_source[NTRANS]; /* 0=eoud, 1=eorl, 2=eofb */
156static int eorl_source[NTRANS];
157static int eoud_source[NTRANS];
158static int coud_source[NTRANS]; /* 0=coud, 1=corl, 2=cofb */
159static int cofb_source[NTRANS];
160static int corl_source[NTRANS];
161static int ep_mirror[12];
162static int cp_mirror[8];
163static int cpos_mirror[6];
164static Alg * rotation_algs[NROTATIONS];
165
166
167/* Symmetry data for some coordinates ****************************************/
168
169static Trans
170trans_group_udfix[16] = {
171 uf, ur, ub, ul,
172 df, dr, db, dl,
173 uf_mirror, ur_mirror, ub_mirror, ul_mirror,
174 df_mirror, dr_mirror, db_mirror, dl_mirror,
175};
176
177SymData
178sd_coud_16 = {
179 .filename = "sd_coud_16",
180 .coord = &coord_coud,
181 .sym_coord = &coord_coud_sym16,
182 .ntrans = 16,
183 .trans = trans_group_udfix
184};
185
186SymData
187sd_eofbepos_16 = {
188 .filename = "sd_eofbepos_16",
189 .coord = &coord_eofbepos,
190 .sym_coord = &coord_eofbepos_sym16,
191 .ntrans = 16,
192 .trans = trans_group_udfix
193};
194
195static int n_all_symdata = 2;
196static SymData * all_sd[2] = { &sd_coud_16, &sd_eofbepos_16 };
197
198/* Coordinates and their implementation **************************************/
199
200static uint64_t index_eofb(Cube cube);
201static uint64_t index_eofbepos(Cube cube);
202static uint64_t index_coud(Cube cube);
203static uint64_t index_corners(Cube cube);
204static uint64_t index_cornershtr(Cube cube);
205static uint64_t index_drud(Cube cube);
206static uint64_t index_coud_sym16(Cube cube);
207static uint64_t index_eofbepos_sym16(Cube cube);
208static uint64_t index_drud_sym16(Cube cube);
209static uint64_t index_khuge(Cube cube);
210
211static Cube antindex_eofb(uint64_t ind);
212static Cube antindex_eofbepos(uint64_t ind);
213static Cube antindex_coud(uint64_t ind);
214static Cube antindex_corners(uint64_t ind);
215static Cube antindex_cornershtr(uint64_t ind);
216static Cube antindex_drud(uint64_t ind);
217static Cube antindex_coud_sym16(uint64_t ind);
218static Cube antindex_eofbepos_sym16(uint64_t ind);
219static Cube antindex_drud_sym16(uint64_t ind);
220static Cube antindex_khuge(uint64_t ind);
221
222Coordinate
223coord_eofb = {
224 .index = index_eofb,
225 .cube = antindex_eofb,
226 .check = check_eofb,
227 .max = POW2TO11
228};
229
230Coordinate
231coord_eofbepos = {
232 .index = index_eofbepos,
233 .cube = antindex_eofbepos,
234 .check = check_eofbepos,
235 .max = POW2TO11 * BINOM12ON4
236};
237
238Coordinate
239coord_coud = {
240 .index = index_coud,
241 .cube = antindex_coud,
242 .check = check_coud,
243 .max = POW3TO7
244};
245
246Coordinate
247coord_corners = {
248 .index = index_corners,
249 .cube = antindex_corners,
250 .check = check_corners,
251 .max = POW3TO7 * FACTORIAL8
252};
253
254Coordinate
255coord_cornershtr = {
256 .index = index_cornershtr,
257 .cube = antindex_cornershtr,
258 .check = check_cornershtr,
259 .max = POW3TO7 * BINOM8ON4 * 6
260};
261
262Coordinate
263coord_drud = {
264 .index = index_drud,
265 .cube = antindex_drud,
266 .check = check_drud,
267 .max = POW2TO11 * POW3TO7 * BINOM12ON4
268};
269
270Coordinate
271coord_eofbepos_sym16 = {
272 .index = index_eofbepos_sym16,
273 .cube = antindex_eofbepos_sym16,
274 .check = check_eofbepos,
275};
276
277Coordinate
278coord_coud_sym16 = {
279 .index = index_coud_sym16,
280 .cube = antindex_coud_sym16,
281 .check = check_coud,
282};
283
284Coordinate
285coord_drud_sym16 = {
286 .index = index_drud_sym16,
287 .cube = antindex_drud_sym16,
288 .check = check_drud,
289 .max = POW3TO7 * 64430
290};
291
292Coordinate
293coord_khuge = {
294 .index = index_khuge,
295 .cube = antindex_khuge,
296 .check = check_khuge,
297 .max = POW3TO7 * FACTORIAL4 * 64430
298};
299
300
301static uint64_t
302index_eofb(Cube cube)
303{
304 return cube.eofb;
305}
306
307static uint64_t
308index_eofbepos(Cube cube)
309{
310 return (cube.epose / FACTORIAL4) * POW2TO11 + cube.eofb;
311}
312
313static uint64_t
314index_coud(Cube cube)
315{
316 return cube.coud;
317}
318
319static uint64_t
320index_corners(Cube cube)
321{
322 return cube.coud * FACTORIAL8 + cube.cp;
323}
324
325static uint64_t
326index_cornershtr(Cube cube)
327{
328 return cube.coud * BINOM8ON4 * 6 + cphtr(cube);
329}
330
331static uint64_t
332index_drud(Cube cube)
333{
334 uint64_t a, b, c;
335
336 a = cube.eofb;
337 b = cube.coud;
338 c = cube.epose / FACTORIAL4;
339
340 b *= POW2TO11;
341 c *= POW2TO11 * POW3TO7;
342
343 return a + b + c;
344}
345
346static uint64_t
347index_coud_sym16(Cube cube)
348{
349 return sd_coud_16.class[index_coud(cube)];
350}
351
352static uint64_t
353index_drud_sym16(Cube cube)
354{
355 Trans t;
356 Cube c;
357
358 t = sd_eofbepos_16.transtorep[index_eofbepos(cube)];
359 c = apply_trans(t, cube);
360
361 return index_eofbepos_sym16(c) * POW3TO7 + c.coud;
362}
363
364static uint64_t
365index_eofbepos_sym16(Cube cube)
366{
367 return sd_eofbepos_16.class[index_eofbepos(cube)];
368}
369
370static uint64_t
371index_khuge(Cube cube)
372{
373 Trans t;
374 Cube c;
375 uint64_t a;
376
377 t = sd_eofbepos_16.transtorep[index_eofbepos(cube)];
378 c = apply_trans(t, cube);
379 a = (index_eofbepos_sym16(c) * 24) + (c.epose % 24);
380
381 return a * POW3TO7 + c.coud;
382}
383
384
385/* TODO: rename */
386static Cube
387antindex_eofb(uint64_t ind)
388{
389 return (Cube){ .eofb = ind, .eorl = ind, .eoud = ind };
390}
391
392static Cube
393antindex_eofbepos(uint64_t ind)
394{
395 return admissible_ee_aux[ind];
396}
397
398/* TODO: rename */
399static Cube
400antindex_coud(uint64_t ind)
401{
402 return (Cube){ .coud = ind, .corl = ind, .cofb = ind };
403}
404
405/* TODO: admissible co for other orientations */
406static Cube
407antindex_corners(uint64_t ind)
408{
409 Cube c = {0};
410
411 c.coud = ind / FACTORIAL8;
412 c.cp = ind % FACTORIAL8;
413
414 return c;
415}
416
417/* TODO: admissible co for other orientations */
418static Cube
419antindex_cornershtr(uint64_t ind)
420{
421 Cube c = anti_cphtr(ind % (BINOM8ON4 * 6));
422
423 c.coud = ind / (BINOM8ON4 * 6);
424
425 return c;
426}
427
428/* TODO: admissible eos and cos */
429static Cube
430antindex_drud(uint64_t ind)
431{
432 Cube c = {0};
433
434 c.eofb = ind % POW2TO11;
435 c.coud = (ind / POW2TO11) % POW3TO7;
436 c.epose = (ind % (POW2TO11 * POW3TO7)) * FACTORIAL4;
437
438 return c;
439}
440
441static Cube
442antindex_coud_sym16(uint64_t ind)
443{
444 return sd_coud_16.rep[ind];
445}
446
447static Cube
448antindex_eofbepos_sym16(uint64_t ind)
449{
450 return sd_eofbepos_16.rep[ind];
451}
452
453static Cube
454antindex_drud_sym16(uint64_t ind)
455{
456 Cube c;
457
458 c = sd_eofbepos_16.rep[ind/POW3TO7];
459 c.coud = ind % POW3TO7;
460 c.cofb = c.coud;
461 c.corl = c.coud;
462
463 return c;
464}
465
466static Cube
467antindex_khuge(uint64_t ind)
468{
469 Cube c;
470
471 c = sd_eofbepos_16.rep[ind/(FACTORIAL4*POW3TO7)];
472 c.epose = ((c.epose / 24) * 24) + ((ind/POW3TO7) % 24);
473 c.coud = ind % POW3TO7;
474
475 return c;
476}
477
478
479/* Checkers ******************************************************************/
480
481bool
482check_centers(Cube cube)
483{
484 return cube.cpos == 0;
485}
486
487bool
488check_corners(Cube cube)
489{
490 return cube.cp == 0 && cube.coud == 0;
491}
492
493bool
494check_cornershtr(Cube cube)
495{
496 return cube.coud == 0 && cphtr(cube) == 0; /* TODO: use array cphtrcosets*/
497}
498
499bool
500check_coud(Cube cube)
501{
502 return cube.coud == 0;
503}
504
505bool
506check_drud(Cube cube)
507{
508 return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0;
509}
510
511bool
512check_eofb(Cube cube)
513{
514 return cube.eofb == 0;
515}
516
517bool
518check_eofbepos(Cube cube)
519{
520 return cube.eofb == 0 && cube.epose / 24 == 0;
521}
522
523bool
524check_epose(Cube cube)
525{
526 return cube.epose == 0;
527}
528
529bool
530check_ep(Cube cube)
531{
532 return cube.epose == 0 && cube.eposs == 0 && cube.eposm == 0;
533}
534
535bool
536check_khuge(Cube cube)
537{
538 return check_drud(cube) && cube.epose % 24 == 0;
539}
540
541bool
542check_nothing(Cube cube)
543{
544 return is_admissible(cube); /*TODO: maybe change?*/
545}
546
547/* Movesets ******************************************************************/
548
549bool
550moveset_HTM(Move m)
551{
552 return m >= U && m <= B3;
553}
554
555bool
556moveset_URF(Move m)
557{
558 Move b = base_move(m);
559
560 return b == U || b == R || b == F;
561}
562
563
564/* Local functions implementation ********************************************/
565
566/* TODO: this should be an anti index (maybe?) */
567static Cube
568admissible_ep(Cube cube, PieceFilter f)
569{
570 CubeArray *arr = new_cubearray(cube, f);
571 Cube ret;
572 bool used[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
573 int i, j;
574
575 for (i = 0; i < 12; i++)
576 if (arr->ep[i] != -1)
577 used[arr->ep[i]] = true;
578
579 for (i = 0, j = 0; i < 12; i++) {
580 for ( ; j < 11 && used[j]; j++);
581 if (arr->ep[i] == -1)
582 arr->ep[i] = j++;
583 }
584
585 ret = arrays_to_cube(arr, pf_ep);
586 free_cubearray(arr, f);
587
588 return ret;
589}
590
591static Cube
592admissible_eos_from_eofbepos(Cube cube)
593{
594 Edge e;
595 Cube ret;
596 CubeArray *arr = new_cubearray(cube, pf_all);
597
598 memcpy(arr->eorl, arr->eofb, 12 * sizeof(int));
599 memcpy(arr->eoud, arr->eofb, 12 * sizeof(int));
600
601 for (e = 0; e < 12; e++) {
602 if ((edge_slice(e) != 0 && edge_slice(arr->ep[e]) == 0) ||
603 (edge_slice(e) == 0 && edge_slice(arr->ep[e]) != 0))
604 arr->eorl[e] = 1 - arr->eorl[e];
605 if ((edge_slice(e) != 2 && edge_slice(arr->ep[e]) == 2) ||
606 (edge_slice(e) == 2 && edge_slice(arr->ep[e]) != 2))
607 arr->eoud[e] = 1 - arr->eoud[e];
608 }
609
610 ret = arrays_to_cube(arr, pf_all);
611 free_cubearray(arr, pf_all);
612
613 return ret;
614}
615
616static bool
617allowed_next(Move move, DfsData *dd)
618{
619 if (!possible_next[dd->last2][dd->last1][move])
620 return false;
621
622 if (commute[dd->last1][move])
623 return dd->move_position[dd->last1] < dd->move_position[move];
624
625 return true;
626}
627
628static void
629append_alg(AlgList *l, Alg *alg)
630{
631 AlgListNode *node = malloc(sizeof(AlgListNode));
632 int i;
633
634 node->alg = new_alg("");
635 for (i = 0; i < alg->len; i++)
636 append_move(node->alg, alg->move[i], alg->inv[i]);
637 node->next = NULL;
638
639 if (++l->len == 1)
640 l->first = node;
641 else
642 l->last->next = node;
643 l->last = node;
644}
645
646static void
647append_move(Alg *alg, Move m, bool inverse)
648{
649 if (alg->len == alg->allocated)
650 realloc_alg(alg, 2*alg->len);
651
652 alg->move[alg->len] = m;
653 alg->inv [alg->len] = inverse;
654 alg->len++;
655}
656
657static Cube
658apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a)
659{
660 Cube ret = {0};
661 int i;
662
663 for (i = 0; i < alg->len; i++)
664 if (alg->inv[i])
665 ret = a ? apply_move(alg->move[i], ret) :
666 apply_move_cubearray(alg->move[i], ret, f);
667
668 ret = compose_filtered(c, inverse_cube(ret), f);
669
670 for (i = 0; i < alg->len; i++)
671 if (!alg->inv[i])
672 ret = a ? apply_move(alg->move[i], ret) :
673 apply_move_cubearray(alg->move[i], ret, f);
674
675 return ret;
676}
677
678static void
679apply_permutation(int *perm, int *set, int n)
680{
681 int *aux = malloc(n * sizeof(int));
682 int i;
683
684 if (!is_perm(perm, n))
685 return;
686
687 for (i = 0; i < n; i++)
688 aux[i] = set[perm[i]];
689
690 memcpy(set, aux, n * sizeof(int));
691 free(aux);
692}
693
694static Cube
695apply_move_cubearray(Move m, Cube cube, PieceFilter f)
696{
697 CubeArray m_arr = {
698 edge_cycle[m],
699 eofb_flipped[m],
700 eorl_flipped[m],
701 eoud_flipped[m],
702 corner_cycle[m],
703 coud_flipped[m],
704 corl_flipped[m],
705 cofb_flipped[m],
706 center_cycle[m]
707 };
708
709 return move_via_arrays(&m_arr, cube, f);
710}
711
712static int
713array_ep_to_epos(int *ep, int *ss)
714{
715 int epos[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
716 int eps[4];
717 int i, j, is;
718
719 for (i = 0, is = 0; i < 12; i++) {
720 for (j = 0; j < 4; j++) {
721 if (ep[i] == ss[j]) {
722 eps[is++] = j;
723 epos[i] = 1;
724 }
725 }
726 }
727
728 for (i = 0; i < 4; i++)
729 swap(&epos[ss[i]], &epos[i+8]);
730
731 return epos_from_arrays(epos, eps);
732}
733
734static Cube
735arrays_to_cube(CubeArray *arr, PieceFilter f)
736{
737 Cube ret = {0};
738
739 if (f.epose)
740 ret.epose = array_ep_to_epos(arr->ep, epe_solved);
741 if (f.eposs)
742 ret.eposs = array_ep_to_epos(arr->ep, eps_solved);
743 if (f.eposm)
744 ret.eposm = array_ep_to_epos(arr->ep, epm_solved);
745 if (f.eofb)
746 ret.eofb = digit_array_to_int(arr->eofb, 11, 2);
747 if (f.eorl)
748 ret.eorl = digit_array_to_int(arr->eorl, 11, 2);
749 if (f.eoud)
750 ret.eoud = digit_array_to_int(arr->eoud, 11, 2);
751 if (f.cp)
752 ret.cp = perm_to_index(arr->cp, 8);
753 if (f.coud)
754 ret.coud = digit_array_to_int(arr->coud, 7, 3);
755 if (f.corl)
756 ret.corl = digit_array_to_int(arr->corl, 7, 3);
757 if (f.cofb)
758 ret.cofb = digit_array_to_int(arr->cofb, 7, 3);
759 if (f.cpos)
760 ret.cpos = perm_to_index(arr->cpos, 6);
761
762 return ret;
763}
764
765static int
766binomial(int n, int k)
767{
768 if (n < 0 || k < 0 || k > n)
769 return 0;
770
771 return factorial(n) / (factorial(k) * factorial(n-k));
772}
773
774static Cube
775compose_filtered(Cube c2, Cube c1, PieceFilter f)
776{
777 CubeArray *arr = new_cubearray(c2, f);
778 Cube ret;
779
780 ret = move_via_arrays(arr, c1, f);
781 free_cubearray(arr, f);
782
783 return ret;
784}
785
786static void
787cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f)
788{
789 int i;
790
791 if (f.epose || f.eposs || f.eposm)
792 for (i = 0; i < 12; i++)
793 arr->ep[i] = -1;
794
795 if (f.epose)
796 epos_to_partial_ep(cube.epose, arr->ep, epe_solved);
797 if (f.eposs)
798 epos_to_partial_ep(cube.eposs, arr->ep, eps_solved);
799 if (f.eposm)
800 epos_to_partial_ep(cube.eposm, arr->ep, epm_solved);
801 if (f.eofb)
802 int_to_sum_zero_array(cube.eofb, 2, 12, arr->eofb);
803 if (f.eorl)
804 int_to_sum_zero_array(cube.eorl, 2, 12, arr->eorl);
805 if (f.eoud)
806 int_to_sum_zero_array(cube.eoud, 2, 12, arr->eoud);
807 if (f.cp)
808 index_to_perm(cube.cp, 8, arr->cp);
809 if (f.coud)
810 int_to_sum_zero_array(cube.coud, 3, 8, arr->coud);
811 if (f.corl)
812 int_to_sum_zero_array(cube.corl, 3, 8, arr->corl);
813 if (f.cofb)
814 int_to_sum_zero_array(cube.cofb, 3, 8, arr->cofb);
815 if (f.cpos)
816 index_to_perm(cube.cpos, 6, arr->cpos);
817}
818
819/*
820static int
821cphtr_cp(int cp)
822{
823 int i, a[8];
824
825 index_to_perm(cp, 8, a);
826
827 for (i = 0; i < 8; i++)
828 if (a[i] == UFR || a[i] == UBL || a[i] == DFL || a[i] == DBR)
829 a[i] = 0;
830 else
831 a[i] = 1;
832
833 swap(&a[1], &a[5]);
834 swap(&a[3], &a[7]);
835
836 return subset_to_index(a, 8, 4);
837}
838*/
839
840static void
841dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd)
842{
843 if (dfs_stop(c, s, opts, dd))
844 return;
845
846 if (dfs_check_solved(opts, dd))
847 return;
848
849 dfs_branch(c, s, opts, dd);
850
851 if (opts->can_niss && !dd->niss)
852 dfs_niss(c, s, opts, dd);
853}
854
855static void
856dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd)
857{
858 Move m, l1 = dd->last1, l2 = dd->last2, *moves = dd->sorted_moves;
859
860 int i, maxnsol = opts->max_solutions;
861
862 for (i = 0; moves[i] != NULLMOVE && dd->sols->len < maxnsol; i++) {
863 m = moves[i];
864 if (allowed_next(m, dd)) {
865 dd->last2 = dd->last1;
866 dd->last1 = m;
867 append_move(dd->current_alg, m, dd->niss);
868
869 dfs(apply_move(m, c), s, opts, dd);
870
871 dd->current_alg->len--;
872 dd->last2 = l2;
873 dd->last1 = l1;
874 }
875 }
876}
877
878static bool
879dfs_check_solved(SolveOptions *opts, DfsData *dd)
880{
881 if (dd->lb != 0)
882 return false;
883
884 if (dd->current_alg->len == dd->d) {
885 append_alg(dd->sols, dd->current_alg);
886
887 if (opts->feedback)
888 print_alg(dd->current_alg, false);
889 }
890
891 return true;
892}
893
894static void
895dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd)
896{
897 Move l1 = dd->last1, l2 = dd->last2;
898 CubeTarget ct;
899
900 ct.cube = apply_move(inverse_move(l1), (Cube){0});
901 ct.target = 1;
902
903 if (dd->current_alg->len == 0 || s.estimate(ct)) {
904 dd->niss = true;
905 dd->last1 = NULLMOVE;
906 dd->last2 = NULLMOVE;
907
908 dfs(inverse_cube(c), s, opts, dd);
909
910 dd->last1 = l1;
911 dd->last2 = l2;
912 dd->niss = false;
913 }
914}
915
916static bool
917dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd)
918{
919 CubeTarget ct = {
920 .cube = c,
921 .target = dd->d - dd->current_alg->len
922 };
923
924 if (dd->sols->len >= opts->max_solutions)
925 return true;
926
927 dd->lb = s.estimate(ct);
928 if (opts->can_niss && !dd->niss)
929 dd->lb = MIN(1, dd->lb);
930
931 if (dd->current_alg->len + dd->lb > dd->d)
932 return true;
933
934 return false;
935}
936
937static int
938digit_array_to_int(int *a, int n, int b)
939{
940 int i, ret = 0, p = 1;
941
942 for (i = 0; i < n; i++, p *= b)
943 ret += a[i] * p;
944
945 return ret;
946}
947
948static int
949edge_slice(Edge e) {
950 if (e < 0 || e > 11)
951 return -1;
952
953 if (e == FR || e == FL || e == BL || e == BR)
954 return 0;
955 if (e == UR || e == UL || e == DR || e == DL)
956 return 1;
957
958 return 2;
959}
960
961static int
962epos_dependent_pos(int poss, int pose)
963{
964 int ep[12] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
965 int ep8[8] = {0, 0, 0, 0, 0, 0, 0, 0};
966 int i, j;
967
968 epos_to_partial_ep(poss*FACTORIAL4, ep, eps_solved);
969 epos_to_partial_ep(pose*FACTORIAL4, ep, epe_solved);
970
971 for (i = 0, j = 0; i < 12; i++)
972 if (edge_slice(ep[i]) != 0)
973 ep8[j++] = (edge_slice(ep[i]) == 1) ? 1 : 0;
974
975 swap(&ep8[1], &ep8[4]);
976 swap(&ep8[3], &ep8[6]);
977
978 return subset_to_index(ep8, 8, 4);
979}
980
981static int
982epos_from_arrays(int *epos, int *ep)
983{
984 return FACTORIAL4 * subset_to_index(epos,12,4) + perm_to_index(ep,4);
985}
986
987static void
988epos_to_partial_ep(int epos, int *ep, int *ss)
989{
990 int i, is, eposs[12], eps[4];
991
992 index_to_perm(epos % FACTORIAL4, 4, eps);
993 index_to_subset(epos / FACTORIAL4, 12, 4, eposs);
994
995 for (i = 0; i < 4; i++)
996 swap(&eposs[ss[i]], &eposs[i+8]);
997
998 for (i = 0, is = 0; i < 12; i++)
999 if (eposs[i])
1000 ep[i] = ss[eps[is++]];
1001}
1002
1003static int
1004factorial(int n)
1005{
1006 int i, ret = 1;
1007
1008 if (n < 0)
1009 return 0;
1010
1011 for (i = 1; i <= n; i++)
1012 ret *= i;
1013
1014 return ret;
1015}
1016
1017void
1018free_alg(Alg *alg)
1019{
1020 free(alg->move);
1021 free(alg->inv);
1022 free(alg);
1023}
1024
1025void
1026free_alglist(AlgList *l)
1027{
1028 AlgListNode *aux, *i = l->first;
1029
1030 while (i != NULL) {
1031 aux = i->next;
1032 free_alglistnode(i);
1033 i = aux;
1034 }
1035 free(l);
1036}
1037
1038void
1039free_alglistnode(AlgListNode *aln)
1040{
1041 free_alg(aln->alg);
1042 free(aln);
1043}
1044
1045static void
1046free_cubearray(CubeArray *arr, PieceFilter f)
1047{
1048 if (f.epose || f.eposs || f.eposm)
1049 free(arr->ep);
1050 if (f.eofb)
1051 free(arr->eofb);
1052 if (f.eorl)
1053 free(arr->eorl);
1054 if (f.eoud)
1055 free(arr->eoud);
1056 if (f.cp)
1057 free(arr->cp);
1058 if (f.coud)
1059 free(arr->coud);
1060 if (f.corl)
1061 free(arr->corl);
1062 if (f.cofb)
1063 free(arr->cofb);
1064 if (f.cpos)
1065 free(arr->cpos);
1066
1067 free(arr);
1068}
1069
1070static void
1071genptable_dfs(Cube c, PruneData *pd, DfsData *dd)
1072{
1073 int oldval = ptableval(pd, c);
1074
1075 if (oldval < dd->m || pd->n == pd->coord->max ||
1076 (dd->m != 0 && pd->coord->check(c)) )
1077 return;
1078
1079 if (dd->m == dd->d) {
1080 if (dd->m < oldval)
1081 ptable_update(pd, c, dd->m);
1082 return;
1083 }
1084
1085 genptable_dfs_branch(c, pd, dd);
1086}
1087
1088static void
1089genptable_dfs_branch(Cube c, PruneData *pd, DfsData *dd)
1090{
1091 Move i, move, l1 = dd->last1, l2 = dd->last2;
1092
1093 dd->m++;
1094
1095 for (i = 0; dd->sorted_moves[i] != NULLMOVE; i++) {
1096 move = dd->sorted_moves[i];
1097 if (allowed_next(move, dd)) {
1098 dd->last2 = dd->last1;
1099 dd->last1 = move;
1100
1101 genptable_dfs(apply_move(move, c), pd, dd);
1102
1103 dd->last2 = l2;
1104 dd->last1 = l1;
1105 }
1106 }
1107
1108 dd->m--;
1109}
1110
1111static void
1112gensym(SymData *sd)
1113{
1114 uint64_t i, in, nreps = 0;
1115 int j;
1116 Cube c, d;
1117
1118 if (sd->generated)
1119 return;
1120
1121 sd->class = malloc(sd->coord->max * sizeof(uint64_t));
1122 sd->rep = malloc(sd->coord->max * sizeof(Cube));
1123 sd->transtorep = malloc(sd->coord->max * sizeof(Trans));
1124
1125 if (read_symdata_file(sd)) {
1126 sd->generated = true;
1127 return;
1128 }
1129
1130 fprintf(stderr, "Cannot load %s, generating it\n", sd->filename);
1131
1132 for (i = 0; i < sd->coord->max; i++)
1133 sd->class[i] = sd->coord->max + 1;
1134
1135 for (i = 0; i < sd->coord->max; i++) {
1136 if (sd->class[i] == sd->coord->max + 1) {
1137 c = sd->coord->cube(i);
1138 sd->rep[nreps] = c;
1139 for (j = 0; j < sd->ntrans; j++) {
1140 d = apply_trans(sd->trans[j], c);
1141 in = sd->coord->index(d);
1142
1143 if (sd->class[in] == sd->coord->max + 1) {
1144 sd->class[in] = nreps;
1145 sd->transtorep[in] =
1146 inverse_trans(sd->trans[j]);
1147 }
1148 }
1149 nreps++;
1150 }
1151 }
1152
1153 sd->sym_coord->max = nreps;
1154 sd->rep = realloc(sd->rep, nreps * sizeof(Cube));
1155 sd->generated = true;
1156
1157 fprintf(stderr, "Found %lu classes\n", nreps);
1158
1159 if (!write_symdata_file(sd))
1160 fprintf(stderr, "Error writing SymData file\n");
1161
1162 return;
1163}
1164
1165static void
1166index_to_perm(int p, int n, int *r)
1167{
1168 int *a = malloc(n * sizeof(int));
1169 int i, j, c;
1170
1171 for (i = 0; i < n; i++)
1172 a[i] = 0;
1173
1174 if (p < 0 || p >= factorial(n))
1175 for (i = 0; i < n; i++)
1176 r[i] = -1;
1177
1178 for (i = 0; i < n; i++) {
1179 c = 0;
1180 j = 0;
1181 while (c <= p / factorial(n-i-1))
1182 c += a[j++] ? 0 : 1;
1183 r[i] = j-1;
1184 a[j-1] = 1;
1185 p %= factorial(n-i-1);
1186 }
1187
1188 free(a);
1189}
1190
1191static void
1192index_to_subset(int s, int n, int k, int *r)
1193{
1194 int i, j, v;
1195
1196 if (s < 0 || s >= binomial(n, k)) {
1197 for (i = 0; i < n; i++)
1198 r[i] = -1;
1199 return;
1200 }
1201
1202 for (i = 0; i < n; i++) {
1203 if (k == n-i) {
1204 for (j = i; j < n; j++)
1205 r[j] = 1;
1206 return;
1207 }
1208
1209 if (k == 0) {
1210 for (j = i; j < n; j++)
1211 r[j] = 0;
1212 return;
1213 }
1214
1215 v = binomial(n-i-1, k);
1216 if (s >= v) {
1217 r[i] = 1;
1218 k--;
1219 s -= v;
1220 } else {
1221 r[i] = 0;
1222 }
1223 }
1224}
1225
1226static void
1227int_to_digit_array(int a, int b, int n, int *r)
1228{
1229 int i;
1230
1231 if (b <= 1)
1232 for (i = 0; i < n; i++)
1233 r[i] = 0;
1234 else
1235 for (i = 0; i < n; i++, a /= b)
1236 r[i] = a % b;
1237}
1238
1239static void
1240int_to_sum_zero_array(int x, int b, int n, int *a)
1241{
1242 int i, s = 0;
1243
1244 if (b <= 1) {
1245 for (i = 0; i < n; i++)
1246 a[i] = 0;
1247 } else {
1248 int_to_digit_array(x, b, n-1, a);
1249 for (i = 0; i < n - 1; i++)
1250 s = (s + a[i]) % b;
1251 a[n-1] = (b - s) % b;
1252 }
1253}
1254
1255static int
1256invert_digits(int a, int b, int n)
1257{
1258 int i, ret, *r = malloc(n * sizeof(int));
1259
1260 int_to_digit_array(a, b, n, r);
1261 for (i = 0; i < n; i++)
1262 r[i] = (b-r[i]) % b;
1263
1264 ret = digit_array_to_int(r, n, b);
1265 free(r);
1266 return ret;
1267}
1268
1269static bool
1270is_perm(int *a, int n)
1271{
1272 int *aux = malloc(n * sizeof(int));
1273 int i;
1274
1275 for (i = 0; i < n; i++)
1276 if (a[i] < 0 || a[i] >= n)
1277 return false;
1278 else
1279 aux[a[i]] = 1;
1280
1281 for (i = 0; i < n; i++)
1282 if (!aux[i])
1283 return false;
1284
1285 free(aux);
1286
1287 return true;
1288}
1289
1290static bool
1291is_subset(int *a, int n, int k)
1292{
1293 int i, sum = 0;
1294
1295 for (i = 0; i < n; i++)
1296 sum += a[i] ? 1 : 0;
1297
1298 return sum == k;
1299}
1300
1301static Cube
1302move_via_arrays(CubeArray *arr, Cube c, PieceFilter f)
1303{
1304 CubeArray *arrc = new_cubearray(c, f);
1305 Cube ret;
1306
1307 if (f.epose || f.eposs || f.eposm)
1308 apply_permutation(arr->ep, arrc->ep, 12);
1309
1310 if (f.eofb) {
1311 apply_permutation(arr->ep, arrc->eofb, 12);
1312 sum_arrays_mod(arr->eofb, arrc->eofb, 12, 2);
1313 }
1314
1315 if (f.eorl) {
1316 apply_permutation(arr->ep, arrc->eorl, 12);
1317 sum_arrays_mod(arr->eorl, arrc->eorl, 12, 2);
1318 }
1319
1320 if (f.eoud) {
1321 apply_permutation(arr->ep, arrc->eoud, 12);
1322 sum_arrays_mod(arr->eoud, arrc->eoud, 12, 2);
1323 }
1324
1325 if (f.cp)
1326 apply_permutation(arr->cp, arrc->cp, 8);
1327
1328 if (f.coud) {
1329 apply_permutation(arr->cp, arrc->coud, 8);
1330 sum_arrays_mod(arr->coud, arrc->coud, 8, 3);
1331 }
1332
1333 if (f.corl) {
1334 apply_permutation(arr->cp, arrc->corl, 8);
1335 sum_arrays_mod(arr->corl, arrc->corl, 8, 3);
1336 }
1337
1338 if (f.cofb) {
1339 apply_permutation(arr->cp, arrc->cofb, 8);
1340 sum_arrays_mod(arr->cofb, arrc->cofb, 8, 3);
1341 }
1342
1343 if (f.cpos)
1344 apply_permutation(arr->cpos, arrc->cpos, 6);
1345
1346 ret = arrays_to_cube(arrc, f);
1347 free_cubearray(arrc, f);
1348
1349 return ret;
1350}
1351
1352static void
1353movelist_to_position(Move *movelist, int *position)
1354{
1355 Move m;
1356
1357 for (m = 0; m < NMOVES && movelist[m] != NULLMOVE; m++)
1358 position[movelist[m]] = m;
1359}
1360
1361static void
1362moveset_to_list(Moveset ms, Estimator f, Move *r)
1363{
1364 CubeTarget ct = { .target = 1 };
1365 int b[NMOVES];
1366 int na = 0, nb = 0;
1367 Move i;
1368
1369 if (ms == NULL) {
1370 fprintf(stderr, "Error: no moveset given\n");
1371 return;
1372 }
1373
1374 for (i = U; i < NMOVES; i++) {
1375 if (ms(i)) {
1376 ct.cube = apply_move(i, (Cube){0});
1377 if (f != NULL && f(ct))
1378 r[na++] = i;
1379 else
1380 b[nb++] = i;
1381 }
1382 }
1383
1384 memcpy(r + na, b, nb * sizeof(Move));
1385 r[na+nb] = NULLMOVE;
1386}
1387
1388static AlgList *
1389new_alglist()
1390{
1391 AlgList *ret = malloc(sizeof(AlgList));
1392
1393 ret->len = 0;
1394 ret->first = NULL;
1395 ret->last = NULL;
1396
1397 return ret;
1398}
1399
1400static CubeArray *
1401new_cubearray(Cube cube, PieceFilter f)
1402{
1403 CubeArray *arr = malloc(sizeof(CubeArray));
1404
1405 if (f.epose || f.eposs || f.eposm)
1406 arr->ep = malloc(12 * sizeof(int));
1407 if (f.eofb)
1408 arr->eofb = malloc(12 * sizeof(int));
1409 if (f.eorl)
1410 arr->eorl = malloc(12 * sizeof(int));
1411 if (f.eoud)
1412 arr->eoud = malloc(12 * sizeof(int));
1413 if (f.cp)
1414 arr->cp = malloc(8 * sizeof(int));
1415 if (f.coud)
1416 arr->coud = malloc(8 * sizeof(int));
1417 if (f.corl)
1418 arr->corl = malloc(8 * sizeof(int));
1419 if (f.cofb)
1420 arr->cofb = malloc(8 * sizeof(int));
1421 if (f.cpos)
1422 arr->cpos = malloc(6 * sizeof(int));
1423
1424 cube_to_arrays(cube, arr, f);
1425
1426 return arr;
1427}
1428
1429static int
1430perm_sign(int *a, int n)
1431{
1432 int i, j, ret = 0;
1433
1434 if (!is_perm(a,n))
1435 return -1;
1436
1437 for (i = 0; i < n; i++)
1438 for (j = i+1; j < n; j++)
1439 ret += (a[i] > a[j]) ? 1 : 0;
1440
1441 return ret % 2;
1442}
1443
1444static int
1445perm_to_index(int *a, int n)
1446{
1447 int i, j, c, ret = 0;
1448
1449 if (!is_perm(a, n))
1450 return -1;
1451
1452 for (i = 0; i < n; i++) {
1453 c = 0;
1454 for (j = i+1; j < n; j++)
1455 c += (a[i] > a[j]) ? 1 : 0;
1456 ret += factorial(n-i-1) * c;
1457 }
1458
1459 return ret;
1460}
1461
1462static int
1463powint(int a, int b)
1464{
1465 if (b < 0)
1466 return 0;
1467 if (b == 0)
1468 return 1;
1469
1470 if (b % 2)
1471 return a * powint(a, b-1);
1472 else
1473 return powint(a*a, b/2);
1474}
1475
1476static void
1477ptable_update(PruneData *pd, Cube cube, int n)
1478{
1479 uint64_t ind = pd->coord->index(cube);
1480 uint8_t oldval2 = pd->ptable[ind/2];
1481 int other = (ind % 2) ? oldval2 % 16 : oldval2 / 16;
1482
1483 pd->ptable[ind/2] = (ind % 2) ? 16*n + other : 16*other + n;
1484 pd->n++;
1485}
1486
1487static void
1488realloc_alg(Alg *alg, int n)
1489{
1490 if (alg == NULL) {
1491 fprintf(stderr, "Error: trying to reallocate NULL alg.\n");
1492 return;
1493 }
1494
1495 if (n < alg->len) {
1496 fprintf(stderr, "Error: alg too long for reallocation ");
1497 fprintf(stderr, "(%d vs %d)\n", alg->len, n);
1498 return;
1499 }
1500
1501 if (n > 1000000) {
1502 fprintf(stderr, "Warning: very long alg,");
1503 fprintf(stderr, "something might go wrong.\n");
1504 }
1505
1506 alg->move = realloc(alg->move, n * sizeof(int));
1507 alg->inv = realloc(alg->inv, n * sizeof(int));
1508 alg->allocated = n;
1509}
1510
1511static bool
1512read_mtables_file()
1513{
1514 FILE *f;
1515 char fname[strlen(tabledir)+20];
1516 int m, b = sizeof(int);
1517 bool r = true;
1518
1519 strcpy(fname, tabledir);
1520 strcat(fname, "/mtables");
1521
1522 if ((f = fopen(fname, "rb")) == NULL)
1523 return false;
1524
1525 for (m = 0; m < NMOVES; m++) {
1526 r = r && fread(epose_mtable[m], b, me[0], f) == me[0];
1527 r = r && fread(eposs_mtable[m], b, me[1], f) == me[1];
1528 r = r && fread(eposm_mtable[m], b, me[2], f) == me[2];
1529 r = r && fread(eofb_mtable[m], b, me[3], f) == me[3];
1530 r = r && fread(eorl_mtable[m], b, me[4], f) == me[4];
1531 r = r && fread(eoud_mtable[m], b, me[5], f) == me[5];
1532 r = r && fread(cp_mtable[m], b, me[6], f) == me[6];
1533 r = r && fread(coud_mtable[m], b, me[7], f) == me[7];
1534 r = r && fread(corl_mtable[m], b, me[8], f) == me[8];
1535 r = r && fread(cofb_mtable[m], b, me[9], f) == me[9];
1536 r = r && fread(cpos_mtable[m], b, me[10], f) == me[10];
1537 }
1538
1539 fclose(f);
1540 return r;
1541}
1542
1543static bool
1544read_ptable_file(PruneData *pd)
1545{
1546 FILE *f;
1547 char fname[strlen(tabledir)+100];
1548 uint64_t r;
1549
1550 strcpy(fname, tabledir);
1551 strcat(fname, "/");
1552 strcat(fname, pd->filename);
1553
1554 if ((f = fopen(fname, "rb")) == NULL)
1555 return false;
1556
1557 r = fread(pd->ptable, sizeof(uint8_t), ptablesize(pd), f);
1558 fclose(f);
1559
1560 return r == ptablesize(pd);
1561}
1562
1563static bool
1564read_symdata_file(SymData *sd)
1565{
1566 FILE *f;
1567 char fname[strlen(tabledir)+100];
1568 uint64_t n = sd->coord->max, *sn = &sd->sym_coord->max;
1569 bool r = true;
1570
1571 strcpy(fname, tabledir);
1572 strcat(fname, "/");
1573 strcat(fname, sd->filename);
1574
1575 if ((f = fopen(fname, "rb")) == NULL)
1576 return false;
1577
1578 r = r && fread(&sd->sym_coord->max, sizeof(uint64_t), 1, f) == 1;
1579 r = r && fread(sd->rep, sizeof(Cube), *sn, f) == *sn;
1580 r = r && fread(sd->class, sizeof(uint64_t), n, f) == n;
1581 r = r && fread(sd->transtorep, sizeof(Trans), n, f) == n;
1582
1583 fclose(f);
1584 return r;
1585}
1586
1587static bool
1588read_ttables_file()
1589{
1590 FILE *f;
1591 char fname[strlen(tabledir)+20];
1592 int b = sizeof(int);
1593 bool r = true;
1594 Move m;
1595
1596 strcpy(fname, tabledir);
1597 strcat(fname, "/");
1598 strcat(fname, "ttables");
1599
1600 if ((f = fopen(fname, "rb")) == NULL)
1601 return false;
1602
1603 for (m = 0; m < NTRANS; m++) {
1604 r = r && fread(epose_ttable[m], b, me[0], f) == me[0];
1605 r = r && fread(eposs_ttable[m], b, me[1], f) == me[1];
1606 r = r && fread(eposm_ttable[m], b, me[2], f) == me[2];
1607 r = r && fread(eo_ttable[m], b, me[3], f) == me[3];
1608 r = r && fread(cp_ttable[m], b, me[6], f) == me[6];
1609 r = r && fread(co_ttable[m], b, me[7], f) == me[7];
1610 r = r && fread(cpos_ttable[m], b, me[10], f) == me[10];
1611 r = r && fread(moves_ttable[m], b, me[11], f) == me[11];
1612 }
1613
1614 fclose(f);
1615 return r;
1616}
1617
1618static Cube
1619rotate_via_compose(Trans r, Cube c, PieceFilter f)
1620{
1621 static int zero12[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1622 static int zero8[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
1623 static CubeArray ma = {
1624 .ep = ep_mirror,
1625 .eofb = zero12,
1626 .eorl = zero12,
1627 .eoud = zero12,
1628 .cp = cp_mirror,
1629 .coud = zero8,
1630 .corl = zero8,
1631 .cofb = zero8,
1632 .cpos = cpos_mirror
1633 };
1634
1635 Alg *inv = inverse_alg(rotation_algs[r % NROTATIONS]);
1636 Cube ret = {0};
1637
1638 if (r >= NROTATIONS)
1639 ret = move_via_arrays(&ma, ret, f);
1640 ret = apply_alg_generic(inv, ret, f, true);
1641
1642 ret = compose_filtered(c, ret, f);
1643
1644 ret = apply_alg_generic(rotation_algs[r % NROTATIONS], ret, f, true);
1645 if (r >= NROTATIONS)
1646 ret = move_via_arrays(&ma, ret, f);
1647
1648 free_alg(inv);
1649 return ret;
1650}
1651
1652static int
1653subset_to_index(int *a, int n, int k)
1654{
1655 int i, ret = 0;
1656
1657 if (!is_subset(a, n, k))
1658 return binomial(n, k);
1659
1660 for (i = 0; i < n; i++) {
1661 if (k == n-i)
1662 return ret;
1663 if (a[i]) {
1664 ret += binomial(n-i-1, k);
1665 k--;
1666 }
1667 }
1668
1669 return ret;
1670}
1671
1672static void
1673sum_arrays_mod(int *src, int *dst, int n, int m)
1674{
1675 int i;
1676
1677 for (i = 0; i < n; i++)
1678 dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m;
1679}
1680
1681static void
1682swap(int *a, int *b)
1683{
1684 int aux;
1685
1686 aux = *a;
1687 *a = *b;
1688 *b = aux;
1689}
1690
1691static bool
1692write_mtables_file()
1693{
1694 FILE *f;
1695 char fname[strlen(tabledir)+20];
1696 int m, b = sizeof(int);
1697 bool r = true;
1698
1699 strcpy(fname, tabledir);
1700 strcat(fname, "/mtables");
1701
1702 if ((f = fopen(fname, "wb")) == NULL)
1703 return false;
1704
1705 for (m = 0; m < NMOVES; m++) {
1706 r = r && fwrite(epose_mtable[m], b, me[0], f) == me[0];
1707 r = r && fwrite(eposs_mtable[m], b, me[1], f) == me[1];
1708 r = r && fwrite(eposm_mtable[m], b, me[2], f) == me[2];
1709 r = r && fwrite(eofb_mtable[m], b, me[3], f) == me[3];
1710 r = r && fwrite(eorl_mtable[m], b, me[4], f) == me[4];
1711 r = r && fwrite(eoud_mtable[m], b, me[5], f) == me[5];
1712 r = r && fwrite(cp_mtable[m], b, me[6], f) == me[6];
1713 r = r && fwrite(coud_mtable[m], b, me[7], f) == me[7];
1714 r = r && fwrite(corl_mtable[m], b, me[8], f) == me[8];
1715 r = r && fwrite(cofb_mtable[m], b, me[9], f) == me[9];
1716 r = r && fwrite(cpos_mtable[m], b, me[10], f) == me[10];
1717 }
1718
1719 fclose(f);
1720 return r;
1721}
1722
1723static bool
1724write_ptable_file(PruneData *pd)
1725{
1726 FILE *f;
1727 char fname[strlen(tabledir)+100];
1728 uint64_t written;
1729
1730 strcpy(fname, tabledir);
1731 strcat(fname, "/");
1732 strcat(fname, pd->filename);
1733
1734 if ((f = fopen(fname, "wb")) == NULL)
1735 return false;
1736
1737 written = fwrite(pd->ptable, sizeof(uint8_t), ptablesize(pd), f);
1738 fclose(f);
1739
1740 return written == ptablesize(pd);
1741}
1742
1743static bool
1744write_symdata_file(SymData *sd)
1745{
1746 FILE *f;
1747 char fname[strlen(tabledir)+100];
1748 uint64_t n = sd->coord->max, *sn = &sd->sym_coord->max;
1749 bool r = true;
1750
1751 strcpy(fname, tabledir);
1752 strcat(fname, "/");
1753 strcat(fname, sd->filename);
1754
1755 if ((f = fopen(fname, "wb")) == NULL)
1756 return false;
1757
1758 r = r && fwrite(&sd->sym_coord->max, sizeof(uint64_t), 1, f) == 1;
1759 r = r && fwrite(sd->rep, sizeof(Cube), *sn, f) == *sn;
1760 r = r && fwrite(sd->class, sizeof(uint64_t), n, f) == n;
1761 r = r && fwrite(sd->transtorep, sizeof(Trans), n, f) == n;
1762
1763 fclose(f);
1764 return r;
1765}
1766
1767static bool
1768write_ttables_file()
1769{
1770 FILE *f;
1771 char fname[strlen(tabledir)+20];
1772 bool r = true;
1773 int b = sizeof(int);
1774 Move m;
1775
1776 strcpy(fname, tabledir);
1777 strcat(fname, "/ttables");
1778
1779 if ((f = fopen(fname, "wb")) == NULL)
1780 return false;
1781
1782 for (m = 0; m < NTRANS; m++) {
1783 r = r && fwrite(epose_ttable[m], b, me[0], f) == me[0];
1784 r = r && fwrite(eposs_ttable[m], b, me[1], f) == me[1];
1785 r = r && fwrite(eposm_ttable[m], b, me[2], f) == me[2];
1786 r = r && fwrite(eo_ttable[m], b, me[3], f) == me[3];
1787 r = r && fwrite(cp_ttable[m], b, me[6], f) == me[6];
1788 r = r && fwrite(co_ttable[m], b, me[7], f) == me[7];
1789 r = r && fwrite(cpos_ttable[m], b, me[10], f) == me[10];
1790 r = r && fwrite(moves_ttable[m], b, me[11], f) == me[11];
1791 }
1792
1793 fclose(f);
1794 return r;
1795}
1796
1797/* Init functions implementation *********************************************/
1798
1799static void
1800init_auxtables()
1801{
1802 Cube c1, c2;
1803 CubeArray *arr;
1804 uint64_t ui, uj;
1805 int i, j, k, auxarr[12];
1806 bool cij, p1, p2;
1807
1808 for (ui = 0; ui < POW2TO11*BINOM12ON4; ui++) {
1809 k = (ui / POW2TO11) * 24;
1810 c1 = admissible_ep((Cube){ .epose = k }, pf_e);
1811 c1.eofb = ui % POW2TO11;
1812 c1 = admissible_eos_from_eofbepos(c1);
1813 admissible_ee_aux[ui] = c1;
1814 }
1815
1816 for (ui = 0; ui < FACTORIAL6; ui++) {
1817 arr = new_cubearray((Cube){.cpos = ui}, pf_cpos);
1818 for (i = 0; i < 6; i++) {
1819 what_center_at_aux[ui][i] = arr->cpos[i];
1820 where_is_center_aux[ui][arr->cpos[i]] = i;
1821 }
1822 free_cubearray(arr, pf_cpos);
1823 }
1824
1825 for (ui = 0; ui < FACTORIAL8; ui++) {
1826 arr = new_cubearray((Cube){.cp = ui}, pf_cp);
1827 for (i = 0; i < 8; i++) {
1828 what_corner_at_aux[ui][i] = arr->cp[i];
1829 where_is_corner_aux[ui][arr->cp[i]] = i;
1830 }
1831 free_cubearray(arr, pf_cp);
1832 }
1833
1834 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
1835 arr = new_cubearray((Cube){.epose = ui}, pf_e);
1836 for (i = 0; i < 12; i++)
1837 if (edge_slice(arr->ep[i]) == 0)
1838 where_is_edge_aux[0][ui][arr->ep[i]] = i;
1839 free_cubearray(arr, pf_e);
1840
1841 arr = new_cubearray((Cube){.eposs = ui}, pf_s);
1842 for (i = 0; i < 12; i++)
1843 if (edge_slice(arr->ep[i]) == 1)
1844 where_is_edge_aux[1][ui][arr->ep[i]] = i;
1845 free_cubearray(arr, pf_s);
1846
1847 arr = new_cubearray((Cube){.eposm = ui}, pf_m);
1848 for (i = 0; i < 12; i++)
1849 if (edge_slice(arr->ep[i]) == 2)
1850 where_is_edge_aux[2][ui][arr->ep[i]] = i;
1851 free_cubearray(arr, pf_m);
1852 }
1853
1854 for (ui = 0; ui < POW3TO7; ui++) {
1855 int_to_sum_zero_array(ui, 3, 8, auxarr);
1856 what_orientation_last_corner_aux[ui] = auxarr[7];
1857 }
1858
1859 for (ui = 0; ui < POW2TO11; ui++) {
1860 int_to_sum_zero_array(ui, 2, 12, auxarr);
1861 what_orientation_last_edge_aux[ui] = auxarr[11];
1862 }
1863
1864 for (ui = 0; ui < BINOM12ON4; ui++)
1865 for (uj = 0; uj < BINOM12ON4; uj++)
1866 epos_dependent_aux[ui][uj]=epos_dependent_pos(ui, uj);
1867
1868 for (i = 0; i < NMOVES; i++) {
1869 for (j = 0; j < NMOVES; j++) {
1870 c1 = apply_move(i, apply_move(j, (Cube){0}));
1871 c2 = apply_move(j, apply_move(i, (Cube){0}));
1872 commute[i][j] = equal(c1, c2) && i && j;
1873 }
1874 }
1875
1876 for (i = 0; i < NMOVES; i++) {
1877 for (j = 0; j < NMOVES; j++) {
1878 for (k = 0; k < NMOVES; k++) {
1879 p1 = j && base_move(j) == base_move(k);
1880 p2 = i && base_move(i) == base_move(k);
1881 cij = commute[i][j];
1882 possible_next[i][j][k] = !(p1 || (cij && p2));
1883 }
1884 }
1885 }
1886
1887 for (i = 0; i < NMOVES; i++)
1888 inverse_move_aux[i] = i ? i + 2 - 2*((i-1)%3) : NULLMOVE;
1889
1890 /* Is there a more elegant way? */
1891 inverse_trans_aux[uf] = uf;
1892 inverse_trans_aux[ur] = ul;
1893 inverse_trans_aux[ul] = ur;
1894 inverse_trans_aux[ub] = ub;
1895
1896 inverse_trans_aux[df] = df;
1897 inverse_trans_aux[dr] = dr;
1898 inverse_trans_aux[dl] = dl;
1899 inverse_trans_aux[db] = db;
1900
1901 inverse_trans_aux[rf] = lf;
1902 inverse_trans_aux[rd] = bl;
1903 inverse_trans_aux[rb] = rb;
1904 inverse_trans_aux[ru] = fr;
1905
1906 inverse_trans_aux[lf] = rf;
1907 inverse_trans_aux[ld] = br;
1908 inverse_trans_aux[lb] = lb;
1909 inverse_trans_aux[lu] = fl;
1910
1911 inverse_trans_aux[fu] = fu;
1912 inverse_trans_aux[fr] = ru;
1913 inverse_trans_aux[fd] = bu;
1914 inverse_trans_aux[fl] = lu;
1915
1916 inverse_trans_aux[bu] = fd;
1917 inverse_trans_aux[br] = ld;
1918 inverse_trans_aux[bd] = bd;
1919 inverse_trans_aux[bl] = rd;
1920
1921 inverse_trans_aux[uf_mirror] = uf_mirror;
1922 inverse_trans_aux[ur_mirror] = ur_mirror;
1923 inverse_trans_aux[ul_mirror] = ul_mirror;
1924 inverse_trans_aux[ub_mirror] = ub_mirror;
1925
1926 inverse_trans_aux[df_mirror] = df_mirror;
1927 inverse_trans_aux[dr_mirror] = dl_mirror;
1928 inverse_trans_aux[dl_mirror] = dr_mirror;
1929 inverse_trans_aux[db_mirror] = db_mirror;
1930
1931 inverse_trans_aux[rf_mirror] = rf_mirror;
1932 inverse_trans_aux[rd_mirror] = br_mirror;
1933 inverse_trans_aux[rb_mirror] = lb_mirror;
1934 inverse_trans_aux[ru_mirror] = fl_mirror;
1935
1936 inverse_trans_aux[lf_mirror] = lf_mirror;
1937 inverse_trans_aux[ld_mirror] = bl_mirror;
1938 inverse_trans_aux[lb_mirror] = rb_mirror;
1939 inverse_trans_aux[lu_mirror] = fr_mirror;
1940
1941 inverse_trans_aux[fu_mirror] = fu_mirror;
1942 inverse_trans_aux[fr_mirror] = lu_mirror;
1943 inverse_trans_aux[fd_mirror] = bu_mirror;
1944 inverse_trans_aux[fl_mirror] = ru_mirror;
1945
1946 inverse_trans_aux[bu_mirror] = fd_mirror;
1947 inverse_trans_aux[br_mirror] = rd_mirror;
1948 inverse_trans_aux[bd_mirror] = bd_mirror;
1949 inverse_trans_aux[bl_mirror] = ld_mirror;
1950}
1951
1952/*
1953 * There is certainly a bette way to do this, but for now I just use
1954 * a "graph coloring" algorithm to compute the left cosets, and I compose
1955 * with every possible cp to get the right cosets (it is possible that I am
1956 * mixing up left and right).
1957 *
1958 * For doing it better "Mathematically", we need 3 things:
1959 * - Checking that cp separates the orbits (UFR,UBL,DFL,DBR) and the other
1960 * This is easy and it is done in the commented function cphtr_cp().
1961 * - Check that there is no ep/cp parity
1962 * - Check that we are not in the "3c" case; this is the part I don't
1963 * know how to do.
1964 */
1965static void
1966init_cphtr_cosets()
1967{
1968 unsigned int i;
1969 int c = 0, d = 0;
1970
1971 for (i = 0; i < FACTORIAL8; i++) {
1972 cphtr_left_cosets[i] = -1;
1973 cphtr_right_cosets[i] = -1;
1974 }
1975
1976 /* First we compute left cosets with a bfs */
1977 for (i = 0; i < FACTORIAL8; i++)
1978 if (cphtr_left_cosets[i] == -1)
1979 init_cphtr_left_cosets_bfs(i, c++);
1980
1981 /* Then we compute right cosets using compose() */
1982 for (i = 0; i < FACTORIAL8; i++)
1983 if (cphtr_right_cosets[i] == -1)
1984 init_cphtr_right_cosets_color(i, d++);
1985}
1986
1987static void
1988init_cphtr_left_cosets_bfs(int i, int c)
1989{
1990 int j, jj, k, next[FACTORIAL8], next2[FACTORIAL8], n, n2;
1991 Move moves[6] = {U2, D2, R2, L2, F2, B2};
1992
1993 n = 1;
1994 next[0] = i;
1995 cphtr_left_cosets[i] = c;
1996
1997 while (n != 0) {
1998 for (j = 0, n2 = 0; j < n; j++) {
1999 for (k = 0; k < 6; k++) {
2000 jj = cp_mtable[moves[k]][next[j]];
2001 if (cphtr_left_cosets[jj] == -1) {
2002 cphtr_left_cosets[jj] = c;
2003 next2[n2++] = jj;
2004 }
2005 }
2006 }
2007
2008 for (j = 0; j < n2; j++)
2009 next[j] = next2[j];
2010 n = n2;
2011 }
2012}
2013
2014static void
2015init_cphtr_right_cosets_color(int i, int d)
2016{
2017 int cp;
2018 unsigned int j;
2019
2020 cphtr_right_rep[d] = i;
2021 for (j = 0; j < FACTORIAL8; j++) {
2022 if (cphtr_left_cosets[j] == 0) {
2023 /* TODO: use antindexer, it's nicer */
2024 cp = compose((Cube){.cp = i}, (Cube){.cp = j}).cp;
2025 cphtr_right_cosets[cp] = d;
2026 }
2027 }
2028}
2029
2030static void
2031init_environment()
2032{
2033 char *nissydata = getenv("NISSYDATA");
2034 char *localdata = getenv("XDG_DATA_HOME");
2035 char *home = getenv("HOME");
2036 bool read, write;
2037
2038 if (nissydata != NULL) {
2039 tabledir = malloc(strlen(nissydata) * sizeof(char) + 20);
2040 strcpy(tabledir, nissydata);
2041 } else if (localdata != NULL) {
2042 tabledir = malloc(strlen(localdata) * sizeof(char) + 20);
2043 strcpy(tabledir, localdata);
2044 strcat(tabledir, "/nissy");
2045 } else if (home != NULL) {
2046 tabledir = malloc(strlen(home) * sizeof(char) + 20);
2047 strcpy(tabledir, home);
2048 strcat(tabledir, "/.nissy");
2049 }
2050
2051 mkdir(tabledir, 0777);
2052 strcat(tabledir, "/tables");
2053 mkdir(tabledir, 0777);
2054
2055 read = !access(tabledir, R_OK);
2056 write = !access(tabledir, W_OK);
2057
2058 if (!read) {
2059 fprintf(stderr, "Table files cannot be read.\n");
2060 } else if (!write) {
2061 fprintf(stderr, "Data directory not writable: ");
2062 fprintf(stderr, "tables can be loaded, but not saved.\n");
2063 }
2064}
2065
2066static void
2067init_moves() {
2068 Cube c;
2069 CubeArray arrs;
2070 int i;
2071 unsigned int ui;
2072 Move m;
2073
2074 /* Generate all move cycles and flips; I do this regardless */
2075 for (i = 0; i < NMOVES; i++) {
2076 if (i == U || i == x || i == y)
2077 continue;
2078
2079 c = apply_alg_generic(equiv_alg[i], (Cube){0}, pf_all, false);
2080
2081 arrs = (CubeArray) {
2082 edge_cycle[i],
2083 eofb_flipped[i],
2084 eorl_flipped[i],
2085 eoud_flipped[i],
2086 corner_cycle[i],
2087 coud_flipped[i],
2088 corl_flipped[i],
2089 cofb_flipped[i],
2090 center_cycle[i]
2091 };
2092 cube_to_arrays(c, &arrs, pf_all);
2093 }
2094
2095 if (read_mtables_file())
2096 return;
2097
2098 fprintf(stderr, "Cannot load %s, generating it\n", "mtables");
2099
2100 /* Initialize transition tables */
2101 for (m = 0; m < NMOVES; m++) {
2102 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
2103 c = (Cube){ .epose = ui };
2104 c = apply_move_cubearray(m, c, pf_e);
2105 epose_mtable[m][ui] = c.epose;
2106
2107 c = (Cube){ .eposs = ui };
2108 c = apply_move_cubearray(m, c, pf_s);
2109 eposs_mtable[m][ui] = c.eposs;
2110
2111 c = (Cube){ .eposm = ui };
2112 c = apply_move_cubearray(m, c, pf_m);
2113 eposm_mtable[m][ui] = c.eposm;
2114 }
2115 for (ui = 0; ui < POW2TO11; ui++ ) {
2116 c = (Cube){ .eofb = ui };
2117 c = apply_move_cubearray(m, c, pf_eo);
2118 eofb_mtable[m][ui] = c.eofb;
2119
2120 c = (Cube){ .eorl = ui };
2121 c = apply_move_cubearray(m, c, pf_eo);
2122 eorl_mtable[m][ui] = c.eorl;
2123
2124 c = (Cube){ .eoud = ui };
2125 c = apply_move_cubearray(m, c, pf_eo);
2126 eoud_mtable[m][ui] = c.eoud;
2127 }
2128 for (ui = 0; ui < POW3TO7; ui++) {
2129 c = (Cube){ .coud = ui };
2130 c = apply_move_cubearray(m, c, pf_co);
2131 coud_mtable[m][ui] = c.coud;
2132
2133 c = (Cube){ .corl = ui };
2134 c = apply_move_cubearray(m, c, pf_co);
2135 corl_mtable[m][ui] = c.corl;
2136
2137 c = (Cube){ .cofb = ui };
2138 c = apply_move_cubearray(m, c, pf_co);
2139 cofb_mtable[m][ui] = c.cofb;
2140 }
2141 for (ui = 0; ui < FACTORIAL8; ui++) {
2142 c = (Cube){ .cp = ui };
2143 c = apply_move_cubearray(m, c, pf_cp);
2144 cp_mtable[m][ui] = c.cp;
2145 }
2146 for (ui = 0; ui < FACTORIAL6; ui++) {
2147 c = (Cube){ .cpos = ui };
2148 c = apply_move_cubearray(m, c, pf_cpos);
2149 cpos_mtable[m][ui] = c.cpos;
2150 }
2151 }
2152
2153 if (!write_mtables_file())
2154 fprintf(stderr, "Error writing mtables\n");
2155}
2156
2157static void
2158init_moves_aux()
2159{
2160 /* Some standard PieceFilters */
2161 pf_all.epose = true;
2162 pf_all.eposs = true;
2163 pf_all.eposm = true;
2164 pf_all.eofb = true;
2165 pf_all.eorl = true;
2166 pf_all.eoud = true;
2167 pf_all.cp = true;
2168 pf_all.cofb = true;
2169 pf_all.corl = true;
2170 pf_all.coud = true;
2171 pf_all.cpos = true;
2172
2173 pf_4val.epose = true;
2174 pf_4val.eposs = true;
2175 pf_4val.eposm = true;
2176 pf_4val.eofb = true;
2177 pf_4val.coud = true;
2178 pf_4val.cp = true;
2179
2180 pf_epcp.epose = true;
2181 pf_epcp.eposs = true;
2182 pf_epcp.eposm = true;
2183 pf_epcp.cp = true;
2184
2185 pf_cpos.cpos = true;
2186
2187 pf_cp.cp = true;
2188
2189 pf_ep.epose = true;
2190 pf_ep.eposs = true;
2191 pf_ep.eposm = true;
2192
2193 pf_e.epose = true;
2194 pf_s.eposs = true;
2195 pf_m.eposm = true;
2196
2197 pf_eo.eofb = true;
2198 pf_eo.eorl = true;
2199 pf_eo.eoud = true;
2200
2201 pf_co.cofb = true;
2202 pf_co.corl = true;
2203 pf_co.coud = true;
2204
2205 /* Used to convert to and from CubeArray */
2206 epe_solved[0] = FR;
2207 epe_solved[1] = FL;
2208 epe_solved[2] = BL;
2209 epe_solved[3] = BR;
2210
2211 eps_solved[0] = UL;
2212 eps_solved[1] = UR;
2213 eps_solved[2] = DL;
2214 eps_solved[3] = DR;
2215
2216 epm_solved[0] = UF;
2217 epm_solved[1] = UB;
2218 epm_solved[2] = DF;
2219 epm_solved[3] = DB;
2220
2221 /* Table sizes, used for reading and writing files */
2222 me[0] = FACTORIAL12/FACTORIAL8;
2223 me[1] = FACTORIAL12/FACTORIAL8;
2224 me[2] = FACTORIAL12/FACTORIAL8;
2225 me[3] = POW2TO11;
2226 me[4] = POW2TO11;
2227 me[5] = POW2TO11;
2228 me[6] = FACTORIAL8;
2229 me[7] = POW3TO7;
2230 me[8] = POW3TO7;
2231 me[9] = POW3TO7;
2232 me[10] = FACTORIAL6;
2233 me[11] = NMOVES;
2234
2235 /* Cycles *********************/
2236 edge_cycle[U][UF] = UR;
2237 edge_cycle[U][UL] = UF;
2238 edge_cycle[U][UB] = UL;
2239 edge_cycle[U][UR] = UB;
2240 edge_cycle[U][DF] = DF;
2241 edge_cycle[U][DL] = DL;
2242 edge_cycle[U][DB] = DB;
2243 edge_cycle[U][DR] = DR;
2244 edge_cycle[U][FR] = FR;
2245 edge_cycle[U][FL] = FL;
2246 edge_cycle[U][BL] = BL;
2247 edge_cycle[U][BR] = BR;
2248
2249 edge_cycle[x][UF] = DF;
2250 edge_cycle[x][UL] = FL;
2251 edge_cycle[x][UB] = UF;
2252 edge_cycle[x][UR] = FR;
2253 edge_cycle[x][DF] = DB;
2254 edge_cycle[x][DL] = BL;
2255 edge_cycle[x][DB] = UB;
2256 edge_cycle[x][DR] = BR;
2257 edge_cycle[x][FR] = DR;
2258 edge_cycle[x][FL] = DL;
2259 edge_cycle[x][BL] = UL;
2260 edge_cycle[x][BR] = UR;
2261
2262 edge_cycle[y][UF] = UR;
2263 edge_cycle[y][UL] = UF;
2264 edge_cycle[y][UB] = UL;
2265 edge_cycle[y][UR] = UB;
2266 edge_cycle[y][DF] = DR;
2267 edge_cycle[y][DL] = DF;
2268 edge_cycle[y][DB] = DL;
2269 edge_cycle[y][DR] = DB;
2270 edge_cycle[y][FR] = BR;
2271 edge_cycle[y][FL] = FR;
2272 edge_cycle[y][BL] = FL;
2273 edge_cycle[y][BR] = BL;
2274
2275 corner_cycle[U][UFR] = UBR;
2276 corner_cycle[U][UFL] = UFR;
2277 corner_cycle[U][UBL] = UFL;
2278 corner_cycle[U][UBR] = UBL;
2279 corner_cycle[U][DFR] = DFR;
2280 corner_cycle[U][DFL] = DFL;
2281 corner_cycle[U][DBL] = DBL;
2282 corner_cycle[U][DBR] = DBR;
2283
2284 corner_cycle[x][UFR] = DFR;
2285 corner_cycle[x][UFL] = DFL;
2286 corner_cycle[x][UBL] = UFL;
2287 corner_cycle[x][UBR] = UFR;
2288 corner_cycle[x][DFR] = DBR;
2289 corner_cycle[x][DFL] = DBL;
2290 corner_cycle[x][DBL] = UBL;
2291 corner_cycle[x][DBR] = UBR;
2292
2293 corner_cycle[y][UFR] = UBR;
2294 corner_cycle[y][UFL] = UFR;
2295 corner_cycle[y][UBL] = UFL;
2296 corner_cycle[y][UBR] = UBL;
2297 corner_cycle[y][DFR] = DBR;
2298 corner_cycle[y][DFL] = DFR;
2299 corner_cycle[y][DBL] = DFL;
2300 corner_cycle[y][DBR] = DBL;
2301
2302 center_cycle[U][U_center] = U_center;
2303 center_cycle[U][D_center] = D_center;
2304 center_cycle[U][R_center] = R_center;
2305 center_cycle[U][L_center] = L_center;
2306 center_cycle[U][F_center] = F_center;
2307 center_cycle[U][B_center] = B_center;
2308
2309 center_cycle[x][U_center] = F_center;
2310 center_cycle[x][D_center] = B_center;
2311 center_cycle[x][R_center] = R_center;
2312 center_cycle[x][L_center] = L_center;
2313 center_cycle[x][F_center] = D_center;
2314 center_cycle[x][B_center] = U_center;
2315
2316 center_cycle[y][U_center] = U_center;
2317 center_cycle[y][D_center] = D_center;
2318 center_cycle[y][R_center] = B_center;
2319 center_cycle[y][L_center] = F_center;
2320 center_cycle[y][F_center] = R_center;
2321 center_cycle[y][B_center] = L_center;
2322
2323 /* Flipped pieces *************/
2324 eofb_flipped[x][UF] = 1;
2325 eofb_flipped[x][UB] = 1;
2326 eofb_flipped[x][DF] = 1;
2327 eofb_flipped[x][DB] = 1;
2328
2329 eofb_flipped[y][FR] = 1;
2330 eofb_flipped[y][FL] = 1;
2331 eofb_flipped[y][BL] = 1;
2332 eofb_flipped[y][BR] = 1;
2333
2334 eorl_flipped[x][UF] = 1;
2335 eorl_flipped[x][UL] = 1;
2336 eorl_flipped[x][UB] = 1;
2337 eorl_flipped[x][UR] = 1;
2338 eorl_flipped[x][DF] = 1;
2339 eorl_flipped[x][DL] = 1;
2340 eorl_flipped[x][DB] = 1;
2341 eorl_flipped[x][DR] = 1;
2342 eorl_flipped[x][FR] = 1;
2343 eorl_flipped[x][FL] = 1;
2344 eorl_flipped[x][BL] = 1;
2345 eorl_flipped[x][BR] = 1;
2346
2347 eorl_flipped[y][FR] = 1;
2348 eorl_flipped[y][FL] = 1;
2349 eorl_flipped[y][BL] = 1;
2350 eorl_flipped[y][BR] = 1;
2351
2352 eoud_flipped[U][UF] = 1;
2353 eoud_flipped[U][UL] = 1;
2354 eoud_flipped[U][UB] = 1;
2355 eoud_flipped[U][UR] = 1;
2356
2357 eoud_flipped[x][UF] = 1;
2358 eoud_flipped[x][UB] = 1;
2359 eoud_flipped[x][DF] = 1;
2360 eoud_flipped[x][DB] = 1;
2361
2362 eoud_flipped[y][UF] = 1;
2363 eoud_flipped[y][UL] = 1;
2364 eoud_flipped[y][UB] = 1;
2365 eoud_flipped[y][UR] = 1;
2366 eoud_flipped[y][DF] = 1;
2367 eoud_flipped[y][DL] = 1;
2368 eoud_flipped[y][DB] = 1;
2369 eoud_flipped[y][DR] = 1;
2370 eoud_flipped[y][FR] = 1;
2371 eoud_flipped[y][FL] = 1;
2372 eoud_flipped[y][BL] = 1;
2373 eoud_flipped[y][BR] = 1;
2374
2375 coud_flipped[x][UFR] = 2;
2376 coud_flipped[x][UFL] = 1;
2377 coud_flipped[x][UBR] = 1;
2378 coud_flipped[x][UBL] = 2;
2379 coud_flipped[x][DFR] = 1;
2380 coud_flipped[x][DFL] = 2;
2381 coud_flipped[x][DBR] = 2;
2382 coud_flipped[x][DBL] = 1;
2383
2384 corl_flipped[U][UFR] = 1;
2385 corl_flipped[U][UFL] = 2;
2386 corl_flipped[U][UBL] = 1;
2387 corl_flipped[U][UBR] = 2;
2388
2389 corl_flipped[y][UFR] = 1;
2390 corl_flipped[y][UFL] = 2;
2391 corl_flipped[y][UBL] = 1;
2392 corl_flipped[y][UBR] = 2;
2393 corl_flipped[y][DFR] = 2;
2394 corl_flipped[y][DFL] = 1;
2395 corl_flipped[y][DBL] = 2;
2396 corl_flipped[y][DBR] = 1;
2397
2398 cofb_flipped[U][UFR] = 2;
2399 cofb_flipped[U][UFL] = 1;
2400 cofb_flipped[U][UBL] = 2;
2401 cofb_flipped[U][UBR] = 1;
2402
2403 cofb_flipped[x][UFR] = 1;
2404 cofb_flipped[x][UFL] = 2;
2405 cofb_flipped[x][UBL] = 1;
2406 cofb_flipped[x][UBR] = 2;
2407 cofb_flipped[x][DFR] = 2;
2408 cofb_flipped[x][DFL] = 1;
2409 cofb_flipped[x][DBL] = 2;
2410 cofb_flipped[x][DBR] = 1;
2411
2412 cofb_flipped[y][UFR] = 2;
2413 cofb_flipped[y][UFL] = 1;
2414 cofb_flipped[y][UBL] = 2;
2415 cofb_flipped[y][UBR] = 1;
2416 cofb_flipped[y][DFR] = 1;
2417 cofb_flipped[y][DFL] = 2;
2418 cofb_flipped[y][DBL] = 1;
2419 cofb_flipped[y][DBR] = 2;
2420
2421 /* Equivalent moves ***********/
2422 equiv_alg[NULLMOVE] = new_alg("");
2423
2424 equiv_alg[U] = new_alg(" U ");
2425 equiv_alg[U2] = new_alg(" UU ");
2426 equiv_alg[U3] = new_alg(" UUU ");
2427 equiv_alg[D] = new_alg(" xx U xx ");
2428 equiv_alg[D2] = new_alg(" xx UU xx ");
2429 equiv_alg[D3] = new_alg(" xx UUU xx ");
2430 equiv_alg[R] = new_alg(" yx U xxxyyy ");
2431 equiv_alg[R2] = new_alg(" yx UU xxxyyy ");
2432 equiv_alg[R3] = new_alg(" yx UUU xxxyyy ");
2433 equiv_alg[L] = new_alg(" yyyx U xxxy ");
2434 equiv_alg[L2] = new_alg(" yyyx UU xxxy ");
2435 equiv_alg[L3] = new_alg(" yyyx UUU xxxy ");
2436 equiv_alg[F] = new_alg(" x U xxx ");
2437 equiv_alg[F2] = new_alg(" x UU xxx ");
2438 equiv_alg[F3] = new_alg(" x UUU xxx ");
2439 equiv_alg[B] = new_alg(" xxx U x ");
2440 equiv_alg[B2] = new_alg(" xxx UU x ");
2441 equiv_alg[B3] = new_alg(" xxx UUU x ");
2442
2443 equiv_alg[Uw] = new_alg(" xx U xx y ");
2444 equiv_alg[Uw2] = new_alg(" xx UU xx yy ");
2445 equiv_alg[Uw3] = new_alg(" xx UUU xx yyy ");
2446 equiv_alg[Dw] = new_alg(" U yyy ");
2447 equiv_alg[Dw2] = new_alg(" UU yy ");
2448 equiv_alg[Dw3] = new_alg(" UUU y ");
2449 equiv_alg[Rw] = new_alg(" yyyx U xxxy x ");
2450 equiv_alg[Rw2] = new_alg(" yyyx UU xxxy xx ");
2451 equiv_alg[Rw3] = new_alg(" yyyx UUU xxxy xxx ");
2452 equiv_alg[Lw] = new_alg(" yx U xxxyyy xxx ");
2453 equiv_alg[Lw2] = new_alg(" yx UU xxxyyy xx ");
2454 equiv_alg[Lw3] = new_alg(" yx UUU xxxyyy x ");
2455 equiv_alg[Fw] = new_alg(" xxx U x yxxxyyy ");
2456 equiv_alg[Fw2] = new_alg(" xxx UU x yxxyyy ");
2457 equiv_alg[Fw3] = new_alg(" xxx UUU x yxyyy ");
2458 equiv_alg[Bw] = new_alg(" x U xxx yxyyy ");
2459 equiv_alg[Bw2] = new_alg(" x UU xxx yxxyyy ");
2460 equiv_alg[Bw3] = new_alg(" x UUU xxx yxxxyyy ");
2461
2462 equiv_alg[M] = new_alg(" yx U xx UUU yxyyy ");
2463 equiv_alg[M2] = new_alg(" yx UU xx UU xxxy ");
2464 equiv_alg[M3] = new_alg(" yx UUU xx U yxxxy ");
2465 equiv_alg[S] = new_alg(" x UUU xx U yyyx ");
2466 equiv_alg[S2] = new_alg(" x UU xx UU yyx ");
2467 equiv_alg[S3] = new_alg(" x U xx UUU yx ");
2468 equiv_alg[E] = new_alg(" U xx UUU xxyyy ");
2469 equiv_alg[E2] = new_alg(" UU xx UU xxyy ");
2470 equiv_alg[E3] = new_alg(" UUU xx U xxy ");
2471
2472 equiv_alg[x] = new_alg(" x ");
2473 equiv_alg[x2] = new_alg(" xx ");
2474 equiv_alg[x3] = new_alg(" xxx ");
2475 equiv_alg[y] = new_alg(" y ");
2476 equiv_alg[y2] = new_alg(" yy ");
2477 equiv_alg[y3] = new_alg(" yyy ");
2478 equiv_alg[z] = new_alg(" yyy x y ");
2479 equiv_alg[z2] = new_alg(" yy xx ");
2480 equiv_alg[z3] = new_alg(" y x yyy ");
2481}
2482
2483static void
2484init_strings()
2485{
2486 strcpy(move_string [NULLMOVE], "-" );
2487 strcpy(move_string [U], "U" );
2488 strcpy(move_string [U2], "U2" );
2489 strcpy(move_string [U3], "U\'" );
2490 strcpy(move_string [D], "D" );
2491 strcpy(move_string [D2], "D2" );
2492 strcpy(move_string [D3], "D\'" );
2493 strcpy(move_string [R], "R" );
2494 strcpy(move_string [R2], "R2" );
2495 strcpy(move_string [R3], "R\'" );
2496 strcpy(move_string [L], "L" );
2497 strcpy(move_string [L2], "L2" );
2498 strcpy(move_string [L3], "L\'" );
2499 strcpy(move_string [F], "F" );
2500 strcpy(move_string [F2], "F2" );
2501 strcpy(move_string [F3], "F\'" );
2502 strcpy(move_string [B], "B" );
2503 strcpy(move_string [B2], "B2" );
2504 strcpy(move_string [B3], "B\'" );
2505 strcpy(move_string [Uw], "Uw" );
2506 strcpy(move_string [Uw2], "Uw2" );
2507 strcpy(move_string [Uw3], "Uw\'" );
2508 strcpy(move_string [Dw], "Dw" );
2509 strcpy(move_string [Dw2], "Dw2" );
2510 strcpy(move_string [Dw3], "Dw\'" );
2511 strcpy(move_string [Rw], "Rw" );
2512 strcpy(move_string [Rw2], "Rw2" );
2513 strcpy(move_string [Rw3], "Rw\'" );
2514 strcpy(move_string [Lw], "Lw" );
2515 strcpy(move_string [Lw2], "Lw2" );
2516 strcpy(move_string [Lw3], "Lw\'" );
2517 strcpy(move_string [Fw], "Fw" );
2518 strcpy(move_string [Fw2], "Fw2" );
2519 strcpy(move_string [Fw3], "Fw\'" );
2520 strcpy(move_string [Bw], "Bw" );
2521 strcpy(move_string [Bw2], "Bw2" );
2522 strcpy(move_string [Bw3], "Bw\'" );
2523 strcpy(move_string [M], "M" );
2524 strcpy(move_string [M2], "M2" );
2525 strcpy(move_string [M3], "M\'" );
2526 strcpy(move_string [S], "S" );
2527 strcpy(move_string [S2], "S2" );
2528 strcpy(move_string [S3], "S\'" );
2529 strcpy(move_string [E], "E" );
2530 strcpy(move_string [E2], "E2" );
2531 strcpy(move_string [E3], "E\'" );
2532 strcpy(move_string [x], "x" );
2533 strcpy(move_string [x2], "x2" );
2534 strcpy(move_string [x3], "x\'" );
2535 strcpy(move_string [y], "y" );
2536 strcpy(move_string [y2], "y2" );
2537 strcpy(move_string [y3], "y\'" );
2538 strcpy(move_string [z], "z" );
2539 strcpy(move_string [z2], "z2" );
2540 strcpy(move_string [z3], "z\'" );
2541
2542 strcpy(edge_string [UF], "UF" );
2543 strcpy(edge_string [UL], "UL" );
2544 strcpy(edge_string [UB], "UB" );
2545 strcpy(edge_string [UR], "UR" );
2546 strcpy(edge_string [DF], "DF" );
2547 strcpy(edge_string [DL], "DL" );
2548 strcpy(edge_string [DB], "DB" );
2549 strcpy(edge_string [DR], "DR" );
2550 strcpy(edge_string [FR], "FR" );
2551 strcpy(edge_string [FL], "FL" );
2552 strcpy(edge_string [BL], "BL" );
2553 strcpy(edge_string [BR], "BR" );
2554
2555 strcpy(corner_string [UFR], "UFR" );
2556 strcpy(corner_string [UFL], "UFL" );
2557 strcpy(corner_string [UBL], "UBL" );
2558 strcpy(corner_string [UBR], "UBR" );
2559 strcpy(corner_string [DFR], "DFR" );
2560 strcpy(corner_string [DFL], "DFL" );
2561 strcpy(corner_string [DBL], "DBL" );
2562 strcpy(corner_string [DBR], "DBR" );
2563
2564 strcpy(center_string [U_center], "U" );
2565 strcpy(center_string [D_center], "D" );
2566 strcpy(center_string [R_center], "R" );
2567 strcpy(center_string [L_center], "L" );
2568 strcpy(center_string [F_center], "F" );
2569 strcpy(center_string [B_center], "B" );
2570}
2571
2572static void
2573init_symdata()
2574{
2575 int i;
2576
2577 for (i = 0; i < n_all_symdata; i++)
2578 gensym(all_sd[i]);
2579}
2580
2581static void
2582init_trans() {
2583 Cube aux, cube, mirr, c[3];
2584 CubeArray epcp;
2585 int i, eparr[12], eoarr[12], cparr[8], coarr[8];
2586 unsigned int ui;
2587 Move mi, move;
2588 Trans m;
2589
2590 /* Compute sources */
2591 for (i = 0; i < NTRANS; i++) {
2592 cube = apply_alg(rotation_algs[i % NROTATIONS], (Cube){0});
2593
2594 epose_source[i] = edge_slice(what_edge_at(cube, FR));
2595 eposs_source[i] = edge_slice(what_edge_at(cube, UR));
2596 eposm_source[i] = edge_slice(what_edge_at(cube, UF));
2597 eofb_source[i] = what_center_at(cube, F_center)/2;
2598 eorl_source[i] = what_center_at(cube, R_center)/2;
2599 eoud_source[i] = what_center_at(cube, U_center)/2;
2600 coud_source[i] = what_center_at(cube, U_center)/2;
2601 cofb_source[i] = what_center_at(cube, F_center)/2;
2602 corl_source[i] = what_center_at(cube, R_center)/2;
2603 }
2604
2605 if (read_ttables_file())
2606 return;
2607
2608 fprintf(stderr, "Cannot load %s, generating it\n", "ttables");
2609
2610 /* Initialize tables */
2611 for (m = 0; m < NTRANS; m++) {
2612 epcp = (CubeArray){ .ep = eparr, .cp = cparr };
2613 cube = apply_alg(rotation_algs[m % NROTATIONS], (Cube){0});
2614 cube_to_arrays(cube, &epcp, pf_epcp);
2615 if (m >= NROTATIONS) {
2616 apply_permutation(ep_mirror, eparr, 12);
2617 apply_permutation(cp_mirror, cparr, 8);
2618 }
2619
2620 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
2621 c[0] = admissible_ep((Cube){ .epose = ui }, pf_e);
2622 c[1] = admissible_ep((Cube){ .eposs = ui }, pf_s);
2623 c[2] = admissible_ep((Cube){ .eposm = ui }, pf_m);
2624
2625 cube = rotate_via_compose(m,c[epose_source[m]],pf_ep);
2626 epose_ttable[m][ui] = cube.epose;
2627
2628 cube = rotate_via_compose(m,c[eposs_source[m]],pf_ep);
2629 eposs_ttable[m][ui] = cube.eposs;
2630
2631 cube = rotate_via_compose(m,c[eposm_source[m]],pf_ep);
2632 eposm_ttable[m][ui] = cube.eposm;
2633 }
2634 for (ui = 0; ui < POW2TO11; ui++ ) {
2635 int_to_sum_zero_array(ui, 2, 12, eoarr);
2636 apply_permutation(eparr, eoarr, 12);
2637 eo_ttable[m][ui] = digit_array_to_int(eoarr, 11, 2);
2638 }
2639 for (ui = 0; ui < POW3TO7; ui++) {
2640 int_to_sum_zero_array(ui, 3, 8, coarr);
2641 apply_permutation(cparr, coarr, 8);
2642 co_ttable[m][ui] = digit_array_to_int(coarr, 7, 3);
2643 if (m >= NROTATIONS)
2644 co_ttable[m][ui] =
2645 invert_digits(co_ttable[m][ui], 3, 7);
2646 }
2647 for (ui = 0; ui < FACTORIAL8; ui++) {
2648 cube = (Cube){ .cp = ui };
2649 cube = rotate_via_compose(m, cube, pf_cp);
2650 cp_ttable[m][ui] = cube.cp;
2651 }
2652 for (ui = 0; ui < FACTORIAL6; ui++) {
2653 cube = (Cube){ .cpos = ui };
2654 cube = rotate_via_compose(m, cube, pf_cpos);
2655 cpos_ttable[m][ui] = cube.cpos;
2656 }
2657 for (mi = 0; mi < NMOVES; mi++) {
2658 aux = apply_trans(m, apply_move(mi, (Cube){0}));
2659 for (move = 0; move < NMOVES; move++) {
2660 cube = apply_move(inverse_move_aux[move], aux);
2661 mirr = apply_trans(uf_mirror, cube);
2662 if (is_solved(cube, false) ||
2663 is_solved(mirr, false))
2664 moves_ttable[m][mi] = move;
2665 }
2666 }
2667 }
2668
2669 if (!write_ttables_file())
2670 fprintf(stderr, "Error writing ttables\n");
2671}
2672
2673static void
2674init_trans_aux()
2675{
2676 ep_mirror[UF] = UF;
2677 ep_mirror[UL] = UR;
2678 ep_mirror[UB] = UB;
2679 ep_mirror[UR] = UL;
2680 ep_mirror[DF] = DF;
2681 ep_mirror[DL] = DR;
2682 ep_mirror[DB] = DB;
2683 ep_mirror[DR] = DL;
2684 ep_mirror[FR] = FL;
2685 ep_mirror[FL] = FR;
2686 ep_mirror[BR] = BL;
2687 ep_mirror[BL] = BR;
2688
2689 cp_mirror[UFR] = UFL;
2690 cp_mirror[UFL] = UFR;
2691 cp_mirror[UBL] = UBR;
2692 cp_mirror[UBR] = UBL;
2693 cp_mirror[DFR] = DFL;
2694 cp_mirror[DFL] = DFR;
2695 cp_mirror[DBL] = DBR;
2696 cp_mirror[DBR] = DBL;
2697
2698 cpos_mirror[U_center] = U_center;
2699 cpos_mirror[D_center] = D_center;
2700 cpos_mirror[R_center] = L_center;
2701 cpos_mirror[L_center] = R_center;
2702 cpos_mirror[F_center] = F_center;
2703 cpos_mirror[B_center] = B_center;
2704
2705 /* Is there a more elegant way? */
2706 rotation_algs[uf] = new_alg("");
2707 rotation_algs[ur] = new_alg("y");
2708 rotation_algs[ub] = new_alg("y2");
2709 rotation_algs[ul] = new_alg("y3");
2710
2711 rotation_algs[df] = new_alg("z2");
2712 rotation_algs[dr] = new_alg("y z2");
2713 rotation_algs[db] = new_alg("x2");
2714 rotation_algs[dl] = new_alg("y3 z2");
2715
2716 rotation_algs[rf] = new_alg("z3");
2717 rotation_algs[rd] = new_alg("z3 y");
2718 rotation_algs[rb] = new_alg("z3 y2");
2719 rotation_algs[ru] = new_alg("z3 y3");
2720
2721 rotation_algs[lf] = new_alg("z");
2722 rotation_algs[ld] = new_alg("z y3");
2723 rotation_algs[lb] = new_alg("z y2");
2724 rotation_algs[lu] = new_alg("z y");
2725
2726 rotation_algs[fu] = new_alg("x y2");
2727 rotation_algs[fr] = new_alg("x y");
2728 rotation_algs[fd] = new_alg("x");
2729 rotation_algs[fl] = new_alg("x y3");
2730
2731 rotation_algs[bu] = new_alg("x3");
2732 rotation_algs[br] = new_alg("x3 y");
2733 rotation_algs[bd] = new_alg("x3 y2");
2734 rotation_algs[bl] = new_alg("x3 y3");
2735}
2736
2737
2738/* Public functions implementation *******************************************/
2739
2740Cube
2741apply_alg(Alg *alg, Cube cube)
2742{
2743 return apply_alg_generic(alg, cube, pf_all, true);
2744}
2745
2746Cube
2747apply_move(Move m, Cube cube)
2748{
2749 return (Cube) {
2750 .epose = epose_mtable[m][cube.epose],
2751 .eposs = eposs_mtable[m][cube.eposs],
2752 .eposm = eposm_mtable[m][cube.eposm],
2753 .eofb = eofb_mtable[m][cube.eofb],
2754 .eorl = eorl_mtable[m][cube.eorl],
2755 .eoud = eoud_mtable[m][cube.eoud],
2756 .coud = coud_mtable[m][cube.coud],
2757 .cofb = cofb_mtable[m][cube.cofb],
2758 .corl = corl_mtable[m][cube.corl],
2759 .cp = cp_mtable[m][cube.cp],
2760 .cpos = cpos_mtable[m][cube.cpos]
2761 };
2762}
2763
2764
2765Cube
2766apply_trans(Trans t, Cube cube)
2767{
2768 int aux_epos[3] = { cube.epose, cube.eposs, cube.eposm };
2769 int aux_eo[3] = { cube.eoud, cube.eorl, cube.eofb };
2770 int aux_co[3] = { cube.coud, cube.corl, cube.cofb };
2771
2772 return (Cube) {
2773 .epose = epose_ttable[t][aux_epos[epose_source[t]]],
2774 .eposs = eposs_ttable[t][aux_epos[eposs_source[t]]],
2775 .eposm = eposm_ttable[t][aux_epos[eposm_source[t]]],
2776 .eofb = eo_ttable[t][aux_eo[eofb_source[t]]],
2777 .eorl = eo_ttable[t][aux_eo[eorl_source[t]]],
2778 .eoud = eo_ttable[t][aux_eo[eoud_source[t]]],
2779 .coud = co_ttable[t][aux_co[coud_source[t]]],
2780 .corl = co_ttable[t][aux_co[corl_source[t]]],
2781 .cofb = co_ttable[t][aux_co[cofb_source[t]]],
2782 .cp = cp_ttable[t][cube.cp],
2783 .cpos = cpos_ttable[t][cube.cpos]
2784 };
2785}
2786
2787Move
2788base_move(Move m)
2789{
2790 if (m == NULLMOVE)
2791 return NULLMOVE;
2792 else
2793 return m - (m-1)%3;
2794}
2795
2796Cube
2797compose(Cube c2, Cube c1)
2798{
2799 return compose_filtered(c2, c1, pf_all);
2800}
2801
2802/*TODO maybe move the next two */
2803uint64_t
2804cphtr(Cube cube)
2805{
2806 return cphtr_right_cosets[cube.cp];
2807}
2808
2809Cube
2810anti_cphtr(uint64_t ind)
2811{
2812 return (Cube) { .cp = cphtr_right_rep[ind] };
2813}
2814
2815uint64_t
2816epos_dependent(Cube c)
2817{
2818 return epos_dependent_aux[c.eposs/FACTORIAL4][c.epose/FACTORIAL4];
2819}
2820
2821bool
2822equal(Cube c1, Cube c2)
2823{
2824 return c1.eofb == c2.eofb &&
2825 c1.epose == c2.epose &&
2826 c1.eposs == c2.eposs &&
2827 c1.eposm == c2.eposm &&
2828 c1.coud == c2.coud &&
2829 c1.cp == c2.cp &&
2830 c1.cpos == c2.cpos;
2831}
2832
2833void
2834genptable(PruneData *pd)
2835{
2836 Cube cube;
2837 uint64_t j, oldn = 0;
2838 DfsData dd = {
2839 .m = 0,
2840 .last1 = NULLMOVE,
2841 .last2 = NULLMOVE
2842 };
2843
2844 if (pd->generated)
2845 return;
2846
2847 /* TODO: check if memory is enough, otherwise maybe crash gracefully? */
2848 pd->ptable = malloc(ptablesize(pd) * sizeof(uint8_t));
2849
2850 if (read_ptable_file(pd)) {
2851 pd->generated = true;
2852 return;
2853 }
2854
2855 fprintf(stderr, "Cannot load %s, generating it\n", pd->filename);
2856
2857 /* We use 4 bits per value, so any distance >= 15 is set to 15 */
2858 for (j = 0; j < pd->coord->max; j++)
2859 ptable_update(pd, pd->coord->cube(j), 15);
2860
2861 moveset_to_list(pd->moveset, NULL, dd.sorted_moves);
2862 movelist_to_position(dd.sorted_moves, dd.move_position);
2863
2864 for (dd.d = 0, pd->n = 0; dd.d < 15 && pd->n < pd->coord->max; dd.d++) {
2865 for (j = 0; j < pd->coord->max; j++) {
2866 cube = pd->coord->cube(j);
2867 if (pd->coord->check(cube))
2868 genptable_dfs(cube, pd, &dd);
2869 }
2870 fprintf(stderr, "Depth %d done, generated %lu\t(%lu/%lu)\n",
2871 dd.d, pd->n-oldn, pd->n, pd->coord->max);
2872 oldn = pd->n;
2873 }
2874
2875 if (!write_ptable_file(pd))
2876 fprintf(stderr, "Error writing ptable file\n");
2877
2878 pd->generated = true;
2879}
2880
2881Cube
2882inverse_cube(Cube cube)
2883{
2884 CubeArray *arr = new_cubearray(cube, pf_all);
2885 CubeArray *inv = new_cubearray((Cube){0}, pf_all);
2886 Cube ret;
2887 int i;
2888
2889 for (i = 0; i < 12; i++) {
2890 inv->ep[arr->ep[i]] = i;
2891 inv->eofb[arr->ep[i]] = arr->eofb[i];
2892 inv->eorl[arr->ep[i]] = arr->eorl[i];
2893 inv->eoud[arr->ep[i]] = arr->eoud[i];
2894 }
2895
2896 for (i = 0; i < 8; i++) {
2897 inv->cp[arr->cp[i]] = i;
2898 inv->coud[arr->cp[i]] = (3 - arr->coud[i]) % 3;
2899 inv->corl[arr->cp[i]] = (3 - arr->corl[i]) % 3;
2900 inv->cofb[arr->cp[i]] = (3 - arr->cofb[i]) % 3;
2901 }
2902
2903 for (int i = 0; i < 6; i++)
2904 inv->cpos[arr->cpos[i]] = i;
2905
2906 ret = arrays_to_cube(inv, pf_all);
2907 free_cubearray(arr, pf_all);
2908 free_cubearray(inv, pf_all);
2909
2910 return ret;
2911}
2912
2913Move
2914inverse_move(Move m)
2915{
2916 return inverse_move_aux[m];
2917}
2918
2919Trans
2920inverse_trans(Trans t)
2921{
2922 return inverse_trans_aux[t];
2923}
2924
2925bool
2926is_admissible(Cube cube)
2927{
2928 /* TODO: this should check consistency of different orientations */
2929 /* TODO: check that centers are opposite and admissible */
2930
2931 CubeArray *a = new_cubearray(cube, pf_all);
2932 int parity;
2933 bool perm;
2934
2935 perm = is_perm(a->ep, 12) &&
2936 is_perm(a->cp, 8) &&
2937 is_perm(a->cpos, 6);
2938 parity = perm_sign(a->ep, 12) +
2939 perm_sign(a->cp, 8) +
2940 perm_sign(a->cpos, 6);
2941
2942 return perm && parity % 2 == 0;
2943}
2944
2945bool
2946is_solved(Cube cube, bool reorient)
2947{
2948 int i;
2949
2950 if (reorient) {
2951 for (i = 0; i < NROTATIONS; i++)
2952 if (is_solved(apply_alg(rotation_algs[i], cube),false))
2953 return true;
2954 return false;
2955 } else {
2956 return equal(cube, (Cube){0});
2957 }
2958}
2959
2960bool
2961is_solved_block(Cube cube, Block block)
2962{
2963 int i;
2964
2965 for (i = 0; i < 12; i++)
2966 if (block.edge[i] && !is_solved_edge(cube, i))
2967 return false;
2968 for (i = 0; i < 8; i++)
2969 if (block.corner[i] && !is_solved_corner(cube, i))
2970 return false;
2971 for (i = 0; i < 6; i++)
2972 if (block.center[i] && !is_solved_center(cube, i))
2973 return false;
2974
2975 return true;
2976}
2977
2978bool
2979is_solved_center(Cube cube, Center c)
2980{
2981 return what_center_at(cube, c) == c;
2982}
2983
2984bool
2985is_solved_corner(Cube cube, Corner c)
2986{
2987 return what_corner_at(cube, c) == c &&
2988 what_orientation_corner(cube.coud, c);
2989}
2990
2991bool
2992is_solved_edge(Cube cube, Edge e)
2993{
2994 return what_edge_at(cube, e) == e &&
2995 what_orientation_edge(cube.eofb, e);
2996}
2997
2998int
2999piece_orientation(Cube cube, int piece, char *orientation)
3000{
3001 int arr[12], n, b, x;
3002
3003 if (!strcmp(orientation, "eofb")) {
3004 x = cube.eofb;
3005 n = 12;
3006 b = 2;
3007 } else if (!strcmp(orientation, "eorl")) {
3008 x = cube.eorl;
3009 n = 12;
3010 b = 2;
3011 } else if (!strcmp(orientation, "eoud")) {
3012 x = cube.eoud;
3013 n = 12;
3014 b = 2;
3015 } else if (!strcmp(orientation, "coud")) {
3016 x = cube.coud;
3017 n = 8;
3018 b = 3;
3019 } else if (!strcmp(orientation, "corl")) {
3020 x = cube.corl;
3021 n = 8;
3022 b = 3;
3023 } else if (!strcmp(orientation, "cofb")) {
3024 x = cube.cofb;
3025 n = 8;
3026 b = 3;
3027 } else {
3028 return -1;
3029 }
3030
3031 int_to_sum_zero_array(x, b, n, arr);
3032 if (piece < n)
3033 return arr[piece];
3034
3035 return -1;
3036}
3037
3038void
3039print_cube(Cube cube)
3040{
3041/*
3042 CubeArray *arr = new_cubearray(cube, pf_all);
3043
3044 for (int i = 0; i < 12; i++)
3045 printf(" %s ", edge_string[arr->ep[i]]);
3046 printf("\n");
3047
3048 for (int i = 0; i < 12; i++)
3049 printf(" %c ", arr->eofb[i] + '0');
3050 printf("\n");
3051
3052 for (int i = 0; i < 8; i++)
3053 printf("%s ", corner_string[arr->cp[i]]);
3054 printf("\n");
3055
3056 for (int i = 0; i < 8; i++)
3057 printf(" %c ", arr->coud[i] + '0');
3058 printf("\n");
3059
3060 for (int i = 0; i < 6; i++)
3061 printf(" %s ", center_string[arr->cpos[i]]);
3062 printf("\n");
3063
3064 free_cubearray(arr, pf_all);
3065*/
3066
3067 for (int i = 0; i < 12; i++)
3068 printf(" %s ", edge_string[what_edge_at(cube, i)]);
3069 printf("\n");
3070
3071 for (int i = 0; i < 12; i++)
3072 printf(" %d ", what_orientation_edge(cube.eofb, i));
3073 printf("\n");
3074
3075 for (int i = 0; i < 8; i++)
3076 printf("%s ", corner_string[what_corner_at(cube, i)]);
3077 printf("\n");
3078
3079 for (int i = 0; i < 8; i++)
3080 printf(" %d ", what_orientation_corner(cube.coud, i));
3081 printf("\n");
3082
3083 for (int i = 0; i < 6; i++)
3084 printf(" %s ", center_string[what_center_at(cube, i)]);
3085 printf("\n");
3086
3087}
3088
3089Cube
3090random_cube()
3091{
3092 CubeArray *arr = new_cubearray((Cube){0}, pf_4val);
3093 Cube ret;
3094 int ep, cp, eo, co;
3095
3096 ep = rand() % FACTORIAL12;
3097 cp = rand() % FACTORIAL8;
3098 eo = rand() % POW2TO11;
3099 co = rand() % POW3TO7;
3100
3101 index_to_perm(ep, 12, arr->ep);
3102 index_to_perm(cp, 8, arr->cp);
3103 int_to_sum_zero_array(eo, 2, 12, arr->eofb);
3104 int_to_sum_zero_array(co, 3, 8, arr->coud);
3105
3106 if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8))
3107 swap(&(arr->ep[0]), &(arr->ep[1]));
3108
3109 ret = arrays_to_cube(arr, pf_4val);
3110 free_cubearray(arr, pf_4val);
3111
3112 return ret;
3113}
3114
3115/* TODO: clean pre_trans or put it back */
3116AlgList *
3117solve(Cube cube, Step step, SolveOptions *opts)
3118{
3119 /*AlgListNode *node;*/
3120 AlgList *sols = new_alglist();
3121 /*Cube c = apply_trans(opts->pre_trans, cube);*/
3122 DfsData dd = {
3123 .m = 0,
3124 .niss = false,
3125 .lb = -1,
3126 .last1 = NULLMOVE,
3127 .last2 = NULLMOVE,
3128 .sols = sols,
3129 .current_alg = new_alg("")
3130 };
3131
3132 if (step.ready != NULL && !step.ready(cube)) {
3133 fprintf(stderr, "Cube not ready for solving step\n");
3134 return sols;
3135 }
3136
3137 moveset_to_list(step.moveset, step.estimate, dd.sorted_moves);
3138 movelist_to_position(dd.sorted_moves, dd.move_position);
3139
3140 for (dd.d = opts->min_moves;
3141 dd.d <= opts->max_moves && !(sols->len && opts->optimal_only);
3142 dd.d++) {
3143 if (opts->feedback)
3144 fprintf(stderr,
3145 "Found %d solutions, searching depth %d...\n",
3146 sols->len, dd.d);
3147 dfs(cube, step, opts, &dd);
3148 }
3149
3150/*
3151 for (node = sols->first; node != NULL; node = node->next)
3152 transform_alg(inverse_trans(opts->pre_trans), node->alg);
3153*/
3154
3155 free_alg(dd.current_alg);
3156 return sols;
3157}
3158
3159Alg *
3160inverse_alg(Alg *alg)
3161{
3162 Alg *ret = new_alg("");
3163 int i;
3164
3165 for (i = alg->len-1; i >= 0; i--)
3166 append_move(ret, inverse_move(alg->move[i]), alg->inv[i]);
3167
3168 return ret;
3169}
3170
3171Alg *
3172new_alg(char *str)
3173{
3174 Alg *alg = malloc(sizeof(Alg));
3175 int i;
3176 bool niss = false;
3177 Move j, m;
3178
3179 alg->move = malloc(30 * sizeof(Move));
3180 alg->inv = malloc(30 * sizeof(bool));
3181 alg->allocated = 30;
3182 alg->len = 0;
3183
3184 for (i = 0; str[i]; i++) {
3185 if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n')
3186 continue;
3187
3188 if (str[i] == '(' && niss) {
3189 fprintf(stderr, "Error reading moves: nested ( )\n");
3190 return alg;
3191 }
3192
3193 if (str[i] == ')' && !niss) {
3194 fprintf(stderr, "Error reading moves: unmatched )\n");
3195 return alg;
3196 }
3197
3198 if (str[i] == '(' || str[i] == ')') {
3199 niss = !niss;
3200 continue;
3201 }
3202
3203 for (j = 0; j < NMOVES; j++) {
3204 if (str[i] == move_string[j][0]) {
3205 m = j;
3206 if (m <= B && str[i+1]=='w') {
3207 m += Uw - U;
3208 i++;
3209 }
3210 if (str[i+1]=='2') {
3211 m += 1;
3212 i++;
3213 } else if (str[i+1]=='\'' || str[i+1]=='3') {
3214 m += 2;
3215 i++;
3216 }
3217 append_move(alg, m, niss);
3218 break;
3219 }
3220 }
3221 }
3222
3223 return alg;
3224}
3225
3226Alg *
3227on_inverse(Alg *alg)
3228{
3229 Alg *ret = new_alg("");
3230 int i;
3231
3232 for (i = 0; i < alg->len; i++)
3233 append_move(ret, alg->move[i], !alg->inv[i]);
3234
3235 return ret;
3236}
3237
3238void
3239print_alg(Alg *alg, bool l)
3240{
3241 /* TODO: make it possible to print to stdout or to string */
3242 /* Maybe just return a string */
3243 char fill[4];
3244 int i;
3245 bool niss = false;
3246
3247 for (i = 0; i < alg->len; i++) {
3248 if (!niss && alg->inv[i])
3249 strcpy(fill, i == 0 ? "(" : " (");
3250 if (niss && !alg->inv[i])
3251 strcpy(fill, ") ");
3252 if (niss == alg->inv[i])
3253 strcpy(fill, i == 0 ? "" : " ");
3254
3255 printf("%s%s", fill, move_string[alg->move[i]]);
3256 niss = alg->inv[i];
3257 }
3258
3259 if (niss)
3260 printf(")");
3261 if (l)
3262 printf(" (%d)", alg->len);
3263
3264 printf("\n");
3265}
3266
3267void
3268print_alglist(AlgList *al, bool l)
3269{
3270 AlgListNode *i;
3271
3272 for (i = al->first; i != NULL; i = i->next)
3273 print_alg(i->alg, l);
3274}
3275
3276void
3277print_ptable(PruneData *pd)
3278{
3279 uint64_t i, a[16];
3280
3281 for (i = 0; i < 16; i++)
3282 a[i] = 0;
3283
3284 if (!pd->generated)
3285 genptable(pd);
3286
3287 for (i = 0; i < pd->coord->max; i++)
3288 a[ptableval(pd, pd->coord->cube(i))]++;
3289
3290 fprintf(stderr, "Values for table %s\n", pd->filename);
3291 for (i = 0; i < 16; i++)
3292 printf("%2lu\t%10lu\n", i, a[i]);
3293}
3294
3295uint64_t
3296ptablesize(PruneData *pd)
3297{
3298 return (pd->coord->max + 1) / 2;
3299}
3300
3301int
3302ptableval(PruneData *pd, Cube cube)
3303{
3304 uint64_t ind = pd->coord->index(cube);
3305
3306 return (ind % 2) ? pd->ptable[ind/2] / 16 : pd->ptable[ind/2] % 16;
3307}
3308
3309
3310Alg *
3311rotation_alg(Trans i)
3312{
3313 return rotation_algs[i % NROTATIONS];
3314}
3315
3316void
3317transform_alg(Trans t, Alg *alg)
3318{
3319 int i;
3320
3321 for (i = 0; i < alg->len; i++)
3322 alg->move[i] = moves_ttable[t][alg->move[i]];
3323}
3324
3325Center
3326what_center_at(Cube cube, Center c)
3327{
3328 return what_center_at_aux[cube.cpos][c];
3329}
3330
3331Corner
3332what_corner_at(Cube cube, Corner c)
3333{
3334 return what_corner_at_aux[cube.cp][c];
3335}
3336
3337Edge
3338what_edge_at(Cube cube, Edge e)
3339{
3340 Edge ret;
3341 CubeArray *arr = new_cubearray(cube, pf_ep);
3342
3343 ret = arr->ep[e];
3344
3345 free_cubearray(arr, pf_ep);
3346 return ret;
3347}
3348
3349int
3350what_orientation_corner(int co, Corner c)
3351{
3352 if (c < 7)
3353 return (co / powint(3, c)) % 3;
3354 else
3355 return what_orientation_last_corner_aux[co];
3356}
3357
3358int
3359what_orientation_edge(int eo, Edge e)
3360{
3361 if (e < 11)
3362 return (eo & (1 << e)) ? 1 : 0;
3363 else
3364 return what_orientation_last_edge_aux[eo];
3365}
3366
3367Center
3368where_is_center(Cube cube, Center c)
3369{
3370 return where_is_center_aux[cube.cpos][c];
3371}
3372
3373Corner
3374where_is_corner(Cube cube, Corner c)
3375{
3376 return where_is_corner_aux[cube.cp][c];
3377}
3378
3379
3380void
3381init()
3382{
3383 /* Order is important! */
3384 init_environment();
3385 init_strings();
3386 init_moves_aux();
3387 init_moves();
3388 init_auxtables();
3389 init_cphtr_cosets();
3390 init_trans_aux();
3391 init_trans();
3392 init_symdata();
3393}
3394
diff --git a/old/2021-06-30-noreached/cube.h b/old/2021-06-30-noreached/cube.h
new file mode 100644
index 0000000..ffbcd86
--- /dev/null
+++ b/old/2021-06-30-noreached/cube.h
@@ -0,0 +1,90 @@
1#ifndef CUBE_H
2#define CUBE_H
3
4#include <stdio.h>
5#include <stdbool.h>
6#include <stdint.h>
7#include <stdlib.h>
8#include <string.h>
9#include <time.h>
10#include <unistd.h>
11#include <sys/stat.h>
12
13#include "macros.h"
14#include "cubetypes.h"
15
16extern Coordinate coord_eofb;
17extern Coordinate coord_eofbepos;
18extern Coordinate coord_coud;
19extern Coordinate coord_corners;
20extern Coordinate coord_cornershtr;
21extern Coordinate coord_drud;
22extern Coordinate coord_coud_sym16;
23extern Coordinate coord_eofbepos_sym16;
24extern Coordinate coord_drud_sym16;
25extern Coordinate coord_khuge;
26
27Cube apply_alg(Alg *alg, Cube cube);
28Cube apply_move(Move m, Cube cube);
29Cube apply_trans(Trans t, Cube cube);
30bool block_solved(Cube cube, Block);
31Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */
32uint64_t cphtr(Cube cube); /* TODO: rename (something with cosets) */
33Cube anti_cphtr(uint64_t ind); /*TODO also this */
34uint64_t epos_dependent(Cube cube); /* TODO: rename and turn into an indexer */
35bool equal(Cube c1, Cube c2);
36Cube inverse_cube(Cube cube);
37Move inverse_move(Move m);
38Trans inverse_trans(Trans t);
39bool is_admissible(Cube cube);
40bool is_solved(Cube cube, bool reorient);
41bool is_solved_center(Cube cube, Center c);
42bool is_solved_corner(Cube cube, Corner c);
43bool is_solved_edge(Cube cube, Edge e);
44void print_cube(Cube cube);
45Cube random_cube();
46AlgList * solve(Cube cube, Step step, SolveOptions *opts);
47Center what_center_at(Cube cube, Center c);
48Corner what_corner_at(Cube cube, Corner c);
49Edge what_edge_at(Cube cube, Edge e);
50int what_orientation_corner(int co, Corner c);
51int what_orientation_edge(int eo, Edge e);
52Center where_is_center(Cube cube, Center c);
53Corner where_is_corner(Cube cube, Corner c);
54Edge where_is_edge(Cube cube, Edge e);
55
56bool check_centers(Cube cube);
57bool check_corners(Cube cube);
58bool check_cornershtr(Cube cube);
59bool check_coud(Cube cube);
60bool check_drud(Cube cube);
61bool check_eofb(Cube cube);
62bool check_eofbepos(Cube cube);
63bool check_epose(Cube cube);
64bool check_ep(Cube cube);
65bool check_khuge(Cube cube);
66bool check_nothing(Cube cube);
67
68bool moveset_HTM(Move m);
69bool moveset_URF(Move m);
70
71Move base_move(Move m);
72void free_alg(Alg *alg);
73void free_alglist(AlgList *l);
74Alg * inverse_alg(Alg *alg);
75Alg * new_alg(char *str);
76Alg * on_inverse(Alg *alg);
77void print_alg(Alg *alg, bool l);
78void print_alglist(AlgList *al, bool l);
79Alg * rotation_alg(Trans i);
80void transform_alg(Trans t, Alg *alg);
81
82void genptable(PruneData *pd);
83void print_ptable(PruneData *pd);
84uint64_t ptablesize(PruneData *pd);
85int ptableval(PruneData *pd, Cube cube);
86
87void init();
88
89#endif
90
diff --git a/old/2021-06-30-noreached/cubetypes.h b/old/2021-06-30-noreached/cubetypes.h
new file mode 100644
index 0000000..a324985
--- /dev/null
+++ b/old/2021-06-30-noreached/cubetypes.h
@@ -0,0 +1,250 @@
1#ifndef CUBETYPES_H
2#define CUBETYPES_H
3
4/* Typedefs ******************************************************************/
5
6typedef enum center Center;
7typedef enum corner Corner;
8typedef enum edge Edge;
9typedef enum move Move;
10typedef enum trans Trans;
11
12typedef struct alg Alg;
13typedef struct alglist AlgList;
14typedef struct alglistnode AlgListNode;
15typedef struct block Block;
16typedef struct coordinate Coordinate;
17typedef struct cube Cube;
18typedef struct cubearray CubeArray;
19typedef struct cubetarget CubeTarget;
20typedef struct dfsdata DfsData;
21typedef struct piecefilter PieceFilter;
22typedef struct prunedata PruneData;
23typedef struct solveoptions SolveOptions;
24typedef struct step Step;
25typedef struct symdata SymData;
26
27typedef Cube (*AntiIndexer) (uint64_t);
28typedef bool (*Checker) (Cube);
29typedef int (*Estimator) (CubeTarget);
30typedef uint64_t (*Indexer) (Cube);
31typedef bool (*Moveset) (Move);
32
33
34/* Enums *********************************************************************/
35
36enum
37center
38{
39 U_center, D_center,
40 R_center, L_center,
41 F_center, B_center
42};
43
44enum
45corner
46{
47 UFR, UFL, UBL, UBR,
48 DFR, DFL, DBL, DBR
49};
50
51enum
52edge
53{
54 UF, UL, UB, UR,
55 DF, DL, DB, DR,
56 FR, FL, BL, BR
57};
58
59enum
60move
61{
62 NULLMOVE,
63 U, U2, U3, D, D2, D3,
64 R, R2, R3, L, L2, L3,
65 F, F2, F3, B, B2, B3,
66 Uw, Uw2, Uw3, Dw, Dw2, Dw3,
67 Rw, Rw2, Rw3, Lw, Lw2, Lw3,
68 Fw, Fw2, Fw3, Bw, Bw2, Bw3,
69 M, M2, M3,
70 S, S2, S3,
71 E, E2, E3,
72 x, x2, x3,
73 y, y2, y3,
74 z, z2, z3,
75};
76
77enum
78trans
79{
80 uf, ur, ub, ul,
81 df, dr, db, dl,
82 rf, rd, rb, ru,
83 lf, ld, lb, lu,
84 fu, fr, fd, fl,
85 bu, br, bd, bl,
86 uf_mirror, ur_mirror, ub_mirror, ul_mirror,
87 df_mirror, dr_mirror, db_mirror, dl_mirror,
88 rf_mirror, rd_mirror, rb_mirror, ru_mirror,
89 lf_mirror, ld_mirror, lb_mirror, lu_mirror,
90 fu_mirror, fr_mirror, fd_mirror, fl_mirror,
91 bu_mirror, br_mirror, bd_mirror, bl_mirror,
92};
93
94
95/* Structs *******************************************************************/
96
97struct
98alg
99{
100 Move * move;
101 bool * inv;
102 int len;
103 int allocated;
104};
105
106struct
107alglist
108{
109 AlgListNode * first;
110 AlgListNode * last;
111 int len;
112};
113
114struct
115alglistnode
116{
117 Alg * alg;
118 AlgListNode * next;
119};
120
121struct
122block
123{
124 bool edge[12];
125 bool corner[8];
126 bool center[6];
127};
128
129struct
130coordinate
131{
132 Indexer index;
133 AntiIndexer cube;
134 Checker check;
135 uint64_t max;
136};
137
138struct
139cube
140{
141 int epose;
142 int eposs;
143 int eposm;
144 int eofb;
145 int eorl;
146 int eoud;
147 int cp;
148 int coud;
149 int cofb;
150 int corl;
151 int cpos;
152};
153
154struct
155cubearray
156{
157 int * ep;
158 int * eofb;
159 int * eorl;
160 int * eoud;
161 int * cp;
162 int * coud;
163 int * corl;
164 int * cofb;
165 int * cpos;
166};
167
168struct
169cubetarget
170{
171 Cube cube;
172 int target;
173};
174
175struct
176dfsdata
177{
178 int d;
179 int m;
180 int lb;
181 bool niss;
182 Move last1;
183 Move last2;
184 AlgList * sols;
185 Alg * current_alg;
186 Move sorted_moves[NMOVES];
187 int move_position[NMOVES];
188};
189
190struct
191piecefilter
192{
193 bool epose;
194 bool eposs;
195 bool eposm;
196 bool eofb;
197 bool eorl;
198 bool eoud;
199 bool cp;
200 bool coud;
201 bool cofb;
202 bool corl;
203 bool cpos;
204};
205
206struct
207prunedata
208{
209 char * filename;
210 uint8_t * ptable;
211 bool generated;
212 uint64_t n;
213 Coordinate * coord;
214 Moveset moveset;
215};
216
217struct
218solveoptions
219{
220 int min_moves;
221 int max_moves;
222 int max_solutions;
223 bool optimal_only;
224 bool can_niss;
225 bool feedback;
226};
227
228struct
229step
230{
231 Estimator estimate;
232 Checker ready;
233 Moveset moveset;
234};
235
236struct
237symdata
238{
239 char * filename;
240 bool generated;
241 Coordinate * coord;
242 Coordinate * sym_coord;
243 int ntrans;
244 Trans * trans;
245 uint64_t * class;
246 Cube * rep;
247 Trans * transtorep;
248};
249
250#endif
diff --git a/old/2021-06-30-noreached/macros.h b/old/2021-06-30-noreached/macros.h
new file mode 100644
index 0000000..af3bca1
--- /dev/null
+++ b/old/2021-06-30-noreached/macros.h
@@ -0,0 +1,23 @@
1#ifndef MACROS_H
2#define MACROS_H
3
4#define POW2TO6 64ULL
5#define POW2TO11 2048ULL
6#define POW2TO12 4096ULL
7#define POW3TO7 2187ULL
8#define POW3TO8 6561ULL
9#define FACTORIAL4 24ULL
10#define FACTORIAL6 720ULL
11#define FACTORIAL7 5040ULL
12#define FACTORIAL8 40320ULL
13#define FACTORIAL12 479001600ULL
14#define BINOM12ON4 495ULL
15#define BINOM8ON4 70ULL
16#define MIN(a,b) (((a) < (b)) ? (a) : (b))
17#define MAX(a,b) (((a) > (b)) ? (a) : (b))
18
19#define NMOVES (z3+1)
20#define NTRANS 48
21#define NROTATIONS 24
22
23#endif
diff --git a/old/2021-06-30-noreached/main.c b/old/2021-06-30-noreached/main.c
new file mode 100644
index 0000000..1ebd917
--- /dev/null
+++ b/old/2021-06-30-noreached/main.c
@@ -0,0 +1,80 @@
1#include <stdio.h>
2#include "cube.h"
3#include "steps.h"
4
5int main() {
6 Alg *algo;
7 AlgList *sols;
8 Cube cube;
9 SolveOptions opts;
10 char line[1000];
11 int i, ns = 2;
12/* Move m;*/
13/* int nrand = 10000, sum1, sum2, sum3;*/
14
15 Step *stps[20] = {&drud_HTM, &optimal_HTM};
16 char sss[30][30] = {"DR on UD", "Optimal solve"};
17
18 opts = (SolveOptions) {
19 .min_moves = 0,
20 .max_moves = 20,
21 .optimal_only = true,
22 .max_solutions = 1,
23 .can_niss = false,
24 .feedback = true,
25 };
26
27 init();
28
29/*
30 srand(time(NULL));
31 sum1 = 0;
32 sum2 = 0;
33 sum3 = 0;
34 for (i = 0; i < nrand; i++) {
35 cube = random_cube();
36 sum1 += drud_HTM.check(cube, 20);
37 sum2 += optimal_HTM.check(cube, 20);
38 sum3 += cornershtreofb_HTM.check(cube, 20);
39 }
40 printf("Average drud pruning: %lf\n", ((double)sum1) / ((double) nrand));
41 printf("Average corners htr pruning: %lf\n", ((double)sum2) / ((double) nrand));
42 printf("Average corners htr + eofb pruning: %lf\n", ((double)sum3) / ((double) nrand));
43*/
44
45/*
46 for (m = U; m <= B3; m++) {
47 printf("Class eofbepos after %d: ", m);
48 printf("%lu\n", coord_khuge.index(apply_move(m,(Cube){0})));
49 }
50*/
51
52 printf("Welcome to nissy 2.0! Insert a scramble:\n");
53
54 if (fgets(line, 1000, stdin) != NULL) {
55 algo = new_alg(line);
56 cube = apply_alg(algo, (Cube){0});
57
58 print_alg(inverse_alg(algo), false);
59/*
60 printf("After rb_mirror:\n");
61 cube = apply_trans(rb_mirror, cube);
62 print_cube(cube);
63 printf("Going back:\n");
64 cube = apply_trans(inverse_trans(rb_mirror), cube);
65*/
66
67 print_cube(cube);
68
69 for (i = 0; i < ns; i++) {
70 sols = solve(cube, *stps[i], &opts);
71 printf("%s: %d solutions found:\n", sss[i], sols->len);
72 print_alglist(sols, true);
73 free_alglist(sols);
74 }
75 free_alg(algo);
76 }
77
78 return 0;
79}
80
diff --git a/old/2021-06-30-noreached/steps.c b/old/2021-06-30-noreached/steps.c
new file mode 100644
index 0000000..91e7f00
--- /dev/null
+++ b/old/2021-06-30-noreached/steps.c
@@ -0,0 +1,307 @@
1#include "steps.h"
2
3/* Standard checkers (return lower bound) ************************************/
4
5static int estimate_eofb_HTM(CubeTarget ct);
6static int estimate_coud_HTM(CubeTarget ct);
7static int estimate_coud_URF(CubeTarget ct);
8static int estimate_corners_HTM(CubeTarget ct);
9static int estimate_cornershtr_HTM(CubeTarget ct);
10static int estimate_corners_URF(CubeTarget ct);
11static int estimate_cornershtr_URF(CubeTarget ct);
12static int estimate_drud_HTM(CubeTarget ct);
13static int estimate_optimal_HTM(CubeTarget ct);
14
15/* Steps *********************************************************************/
16
17Step
18eofb_HTM = {
19 .estimate = estimate_eofb_HTM,
20 .ready = check_centers,
21 .moveset = moveset_HTM
22};
23
24Step
25coud_HTM = {
26 .estimate = estimate_coud_HTM,
27 .ready = check_centers,
28 .moveset = moveset_HTM
29};
30
31Step
32coud_URF = {
33 .estimate = estimate_coud_URF,
34 .ready = check_nothing,
35 .moveset = moveset_URF
36};
37
38Step
39corners_HTM = {
40 .estimate = estimate_corners_HTM,
41 .ready = check_centers,
42 .moveset = moveset_HTM
43};
44
45Step
46cornershtr_HTM = {
47 .estimate = estimate_cornershtr_HTM,
48 .ready = check_centers,
49 .moveset = moveset_HTM
50};
51
52Step
53cornershtr_URF = {
54 .estimate = estimate_cornershtr_URF,
55 .ready = check_nothing,
56 .moveset = moveset_URF
57};
58
59Step
60corners_URF = {
61 .estimate = estimate_corners_URF,
62 .ready = check_nothing,
63 .moveset = moveset_URF
64};
65
66Step
67drud_HTM = {
68 .estimate = estimate_drud_HTM,
69 .ready = check_centers,
70 .moveset = moveset_HTM
71};
72
73Step
74optimal_HTM = {
75 .estimate = estimate_optimal_HTM,
76 .ready = check_centers,
77 .moveset = moveset_HTM
78};
79
80
81/* Pruning tables ************************************************************/
82
83PruneData
84pd_eofb_HTM = {
85 .filename = "ptable_eofb_HTM",
86 .coord = &coord_eofb,
87 .moveset = moveset_HTM
88};
89
90PruneData
91pd_coud_HTM = {
92 .filename = "ptable_coud_HTM",
93 .coord = &coord_coud,
94 .moveset = moveset_HTM
95};
96
97PruneData
98pd_cornershtr_HTM = {
99 .filename = "ptable_cornershtr_withcosets_HTM",
100 .coord = &coord_cornershtr,
101 .moveset = moveset_HTM
102};
103
104PruneData
105pd_corners_HTM = {
106 .filename = "ptable_corners_HTM",
107 .coord = &coord_corners,
108 .moveset = moveset_HTM
109};
110
111PruneData
112pd_drud_HTM = {
113 .filename = "ptable_drud_HTM",
114 .coord = &coord_drud,
115 .moveset = moveset_HTM
116};
117
118PruneData
119pd_drud_sym16_HTM = {
120 .filename = "ptable_drud_sym16_HTM",
121 .coord = &coord_drud_sym16,
122 .moveset = moveset_HTM,
123};
124
125PruneData
126pd_khuge_HTM = {
127 .filename = "ptable_khuge_HTM",
128 .coord = &coord_khuge,
129 .moveset = moveset_HTM
130};
131
132
133/* Standard checkers (return lower bound) ************************************/
134
135static int
136estimate_eofb_HTM(CubeTarget ct)
137{
138 if (!pd_eofb_HTM.generated)
139 genptable(&pd_eofb_HTM);
140
141 return ptableval(&pd_eofb_HTM, ct.cube);
142}
143
144static int
145estimate_coud_HTM(CubeTarget ct)
146{
147 if (!pd_coud_HTM.generated)
148 genptable(&pd_coud_HTM);
149
150 return ptableval(&pd_coud_HTM, ct.cube);
151}
152
153static int
154estimate_coud_URF(CubeTarget ct)
155{
156 /* TODO: I can improve this by checking first the orientation of
157 * the corner in DBL and use that as a reference */
158
159 CubeTarget ct2 = {.cube = apply_move(z, ct.cube), .target = ct.target};
160 CubeTarget ct3 = {.cube = apply_move(x, ct.cube), .target = ct.target};
161
162 int ud = estimate_coud_HTM(ct);
163 int rl = estimate_coud_HTM(ct2);
164 int fb = estimate_coud_HTM(ct3);
165
166 return MIN(ud, MIN(rl, fb));
167}
168
169static int
170estimate_corners_HTM(CubeTarget ct)
171{
172 if (!pd_corners_HTM.generated)
173 genptable(&pd_corners_HTM);
174
175 return ptableval(&pd_corners_HTM, ct.cube);
176}
177
178static int
179estimate_cornershtr_HTM(CubeTarget ct)
180{
181 if (!pd_cornershtr_HTM.generated)
182 genptable(&pd_cornershtr_HTM);
183
184 return ptableval(&pd_cornershtr_HTM, ct.cube);
185}
186
187static int
188estimate_cornershtr_URF(CubeTarget ct)
189{
190 /* TODO: I can improve this by checking first the corner in DBL
191 * and use that as a reference */
192
193 int c, ret = 15;
194 Trans i;
195
196 for (i = 0; i < NROTATIONS; i++) {
197 ct.cube = apply_alg(rotation_alg(i), ct.cube);
198 c = estimate_cornershtr_HTM(ct);
199 ret = MIN(ret, c);
200 }
201
202 return ret;
203}
204
205static int
206estimate_corners_URF(CubeTarget ct)
207{
208 /* TODO: I can improve this by checking first the corner in DBL
209 * and use that as a reference */
210
211 int c, ret = 15;
212 Trans i;
213
214 for (i = 0; i < NROTATIONS; i++) {
215 ct.cube = apply_alg(rotation_alg(i), ct.cube);
216 c = estimate_corners_HTM(ct);
217 ret = MIN(ret, c);
218 }
219
220 return ret;
221}
222
223static int
224estimate_drud_HTM(CubeTarget ct)
225{
226/*
227 if (!pd_drud_HTM.generated)
228 genptable(&pd_drud_HTM);
229
230 return ptableval(&pd_drud_HTM, ct.cube);
231*/
232
233 if (!pd_drud_sym16_HTM.generated)
234 genptable(&pd_drud_sym16_HTM);
235
236 return ptableval(&pd_drud_sym16_HTM, ct.cube);
237}
238
239/* TODO: if lucky, remove this */
240/*
241static int
242estimate_optimal_HTM(CubeTarget ct)
243{
244 static Trans t1 = { .rot = rf, .mirror = false };
245 static Trans t2 = { .rot = bd, .mirror = false };
246 int dr1, dr2, dr3, cor, ret;
247 Cube cube = ct.cube;
248
249 dr1 = estimate_drud_HTM(ct);
250 cor = estimate_corners_HTM(ct);
251 ret = MAX(dr1, cor);
252
253 if (ret > ct.target)
254 return ret;
255
256 ct.cube = apply_trans(t1, cube);
257 dr2 = estimate_drud_HTM(ct);
258 ret = MAX(ret, dr2);
259
260 if (ret > ct.target)
261 return ret;
262
263 ct.cube = apply_trans(t2, cube);
264 dr3 = estimate_drud_HTM(ct);
265
266 if (dr1 == dr2 && dr2 == dr3 && dr1 != 0)
267 dr3++;
268
269 ret = MAX(ret, dr3);
270
271 if (ret == 0)
272 return check_ep(cube) ? 0 : 6;
273
274 return ret;
275}
276*/
277
278static int
279estimate_optimal_HTM(CubeTarget ct)
280{
281 static Trans t2 = rf, t3 = bd;
282
283 int dr1, dr2, dr3, cor, ret;
284 Cube cube = ct.cube;
285
286 if (!pd_khuge_HTM.generated)
287 genptable(&pd_khuge_HTM);
288
289 dr1 = ptableval(&pd_khuge_HTM, cube);
290 cor = estimate_corners_HTM(ct);
291 ret = MAX(dr1, cor);
292
293 if (ret > ct.target)
294 return ret;
295
296 cube = apply_trans(t2, ct.cube);
297 dr2 = ptableval(&pd_khuge_HTM, cube);
298 ret = MAX(ret, dr2);
299
300 if (ret > ct.target)
301 return ret;
302
303 cube = apply_trans(t3, ct.cube);
304 dr3 = ptableval(&pd_khuge_HTM, cube);
305
306 return MAX(ret, dr3);
307}
diff --git a/old/2021-06-30-noreached/steps.h b/old/2021-06-30-noreached/steps.h
new file mode 100644
index 0000000..81ae11c
--- /dev/null
+++ b/old/2021-06-30-noreached/steps.h
@@ -0,0 +1,24 @@
1#ifndef STEPS_H
2#define STEPS_H
3
4#include "cube.h"
5
6extern Step eofb_HTM;
7extern Step coud_HTM;
8extern Step coud_URF;
9extern Step corners_HTM;
10extern Step cornershtr_HTM;
11extern Step corners_URF;
12extern Step cornershtr_URF;
13extern Step drud_HTM;
14extern Step optimal_HTM;
15
16extern PruneData pd_eofb_HTM;
17extern PruneData pd_coud_HTM;
18extern PruneData pd_corners_HTM;
19extern PruneData pd_cornershtr_HTM;
20extern PruneData pd_cornershtreofb_HTM;
21extern PruneData pd_drud_HTM;
22extern PruneData pd_khuge_HTM;
23
24#endif
diff --git a/old/2021-06-30-reached/cube.c b/old/2021-06-30-reached/cube.c
new file mode 100644
index 0000000..e490589
--- /dev/null
+++ b/old/2021-06-30-reached/cube.c
@@ -0,0 +1,3419 @@
1#include "cube.h"
2
3/* Local functions **********************************************************/
4
5static Cube admissible_ep(Cube cube, PieceFilter f);
6static Cube admissible_eos_from_eofbepos(Cube cube);
7static bool allowed_next(Move move, DfsData *dd);
8static void append_alg(AlgList *l, Alg *alg);
9static void append_move(Alg *alg, Move m, bool inverse);
10static Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a);
11static void apply_permutation(int *perm, int *set, int n);
12static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f);
13static int array_ep_to_epos(int *ep, int *eps_solved);
14static Cube arrays_to_cube(CubeArray *arr, PieceFilter f);
15static int binomial(int n, int k);
16static Cube compose_filtered(Cube c2, Cube c1, PieceFilter f);
17static void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f);
18static void dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd);
19static void dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd);
20static bool dfs_check_solved(SolveOptions *opts, DfsData *dd);
21static void dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd);
22static bool dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd);
23static int digit_array_to_int(int *a, int n, int b);
24static int edge_slice(Edge e); /* E=0, S=1, M=2 */
25static int epos_dependent_pos(int pos1, int pos2);
26static int epos_from_arrays(int *epos, int *ep);
27static void epos_to_partial_ep(int epos, int *ep, int *ss);
28static int factorial(int n);
29static void free_alglistnode(AlgListNode *aln);
30static void free_cubearray(CubeArray *arr, PieceFilter f);
31static void genptable_dfs(Cube c, PruneData *pd, DfsData *dd);
32static void genptable_dfs_branch(Cube c, PruneData *pd, DfsData *dd);
33static void gensym(SymData *sd);
34static void index_to_perm(int p, int n, int *r);
35static void index_to_subset(int s, int n, int k, int *r);
36static void init_auxtables();
37static void init_cphtr_cosets();
38static void init_cphtr_left_cosets_bfs(int i, int c);
39static void init_cphtr_right_cosets_color(int i, int c);
40static void init_environment();
41static void init_moves();
42static void init_moves_aux();
43static void init_strings();
44static void init_symdata();
45static void init_trans();
46static void init_trans_aux();
47static void int_to_digit_array(int a, int b, int n, int *r);
48static void int_to_sum_zero_array(int x, int b, int n, int *a);
49static int invert_digits(int a, int b, int n);
50static bool is_perm(int *a, int n);
51static bool is_subset(int *a, int n, int k);
52static Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf);
53static void movelist_to_position(Move *movelist, int *position);
54static void moveset_to_list(Moveset ms, Estimator f, Move *r);
55static AlgList * new_alglist();
56static CubeArray * new_cubearray(Cube cube, PieceFilter f);
57static int perm_sign(int *a, int n);
58static int perm_to_index(int *a, int n);
59static int powint(int a, int b);
60static bool ptable_has_reached(PruneData *pd, Cube cube);
61static void ptable_set_reached(PruneData *pd, Cube cube);
62static void ptable_update(PruneData *pd, Cube cube, int m);
63static void realloc_alg(Alg *alg, int n);
64static bool read_mtables_file();
65static bool read_ptable_file(PruneData *pd);
66static bool read_symdata_file(SymData *sd);
67static bool read_ttables_file();
68static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f);
69static int subset_to_index(int *a, int n, int k);
70static void sum_arrays_mod(int *src, int *dst, int n, int m);
71static void swap(int *a, int *b);
72static bool write_mtables_file();
73static bool write_ptable_file(PruneData *pd);
74static bool write_symdata_file(SymData *sd);
75static bool write_ttables_file();
76
77
78/* All sorts of useful costants and tables **********************************/
79
80static char * tabledir;
81
82static PieceFilter pf_all;
83static PieceFilter pf_4val;
84static PieceFilter pf_epcp;
85static PieceFilter pf_cpos;
86static PieceFilter pf_cp;
87static PieceFilter pf_ep;
88static PieceFilter pf_e;
89static PieceFilter pf_s;
90static PieceFilter pf_m;
91static PieceFilter pf_eo;
92static PieceFilter pf_co;
93
94static int epe_solved[4];
95static int eps_solved[4];
96static int epm_solved[4];
97
98static char move_string[NMOVES][7];
99static char edge_string[12][7];
100static char corner_string[8][7];
101static char center_string[6][7];
102
103static Cube admissible_ee_aux[POW2TO11*BINOM12ON4];
104static bool commute[NMOVES][NMOVES];
105static bool possible_next[NMOVES][NMOVES][NMOVES];
106static Move inverse_move_aux[NMOVES];
107static Trans inverse_trans_aux[NTRANS];
108static int epos_dependent_aux[BINOM12ON4][BINOM12ON4];
109static int cphtr_left_cosets[FACTORIAL8];
110static int cphtr_right_cosets[FACTORIAL8];
111static int cphtr_right_rep[BINOM8ON4*6];
112static Center what_center_at_aux[FACTORIAL6][6];
113static Corner what_corner_at_aux[FACTORIAL8][8];
114static int what_orientation_last_corner_aux[POW3TO7];
115static int what_orientation_last_edge_aux[POW2TO11];
116static Center where_is_center_aux[FACTORIAL6][6];
117static Corner where_is_corner_aux[FACTORIAL8][8];
118static Edge where_is_edge_aux[3][FACTORIAL12/FACTORIAL8][12];
119
120static int epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
121static int eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
122static int eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
123static int eo_ttable[NTRANS][POW2TO11];
124static int cp_ttable[NTRANS][FACTORIAL8];
125static int co_ttable[NTRANS][POW3TO7];
126static int cpos_ttable[NTRANS][FACTORIAL6];
127static Move moves_ttable[NTRANS][NMOVES];
128
129static int epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
130static int eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
131static int eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
132static int eofb_mtable[NMOVES][POW2TO11];
133static int eorl_mtable[NMOVES][POW2TO11];
134static int eoud_mtable[NMOVES][POW2TO11];
135static int cp_mtable[NMOVES][FACTORIAL8];
136static int coud_mtable[NMOVES][POW3TO7];
137static int cofb_mtable[NMOVES][POW3TO7];
138static int corl_mtable[NMOVES][POW3TO7];
139static int cpos_mtable[NMOVES][FACTORIAL6];
140
141static uint64_t me[12];
142
143static int edge_cycle[NMOVES][12];
144static int corner_cycle[NMOVES][8];
145static int center_cycle[NMOVES][6];
146static int eofb_flipped[NMOVES][12];
147static int eorl_flipped[NMOVES][12];
148static int eoud_flipped[NMOVES][12];
149static int coud_flipped[NMOVES][8];
150static int corl_flipped[NMOVES][8];
151static int cofb_flipped[NMOVES][8];
152static Alg * equiv_alg[NMOVES];
153
154static int epose_source[NTRANS]; /* 0=epose, 1=eposs, 2=eposm */
155static int eposs_source[NTRANS];
156static int eposm_source[NTRANS];
157static int eofb_source[NTRANS]; /* 0=eoud, 1=eorl, 2=eofb */
158static int eorl_source[NTRANS];
159static int eoud_source[NTRANS];
160static int coud_source[NTRANS]; /* 0=coud, 1=corl, 2=cofb */
161static int cofb_source[NTRANS];
162static int corl_source[NTRANS];
163static int ep_mirror[12];
164static int cp_mirror[8];
165static int cpos_mirror[6];
166static Alg * rotation_algs[NROTATIONS];
167
168
169/* Symmetry data for some coordinates ****************************************/
170
171static Trans
172trans_group_udfix[16] = {
173 uf, ur, ub, ul,
174 df, dr, db, dl,
175 uf_mirror, ur_mirror, ub_mirror, ul_mirror,
176 df_mirror, dr_mirror, db_mirror, dl_mirror,
177};
178
179SymData
180sd_coud_16 = {
181 .filename = "sd_coud_16",
182 .coord = &coord_coud,
183 .sym_coord = &coord_coud_sym16,
184 .ntrans = 16,
185 .trans = trans_group_udfix
186};
187
188SymData
189sd_eofbepos_16 = {
190 .filename = "sd_eofbepos_16",
191 .coord = &coord_eofbepos,
192 .sym_coord = &coord_eofbepos_sym16,
193 .ntrans = 16,
194 .trans = trans_group_udfix
195};
196
197static int n_all_symdata = 2;
198static SymData * all_sd[2] = { &sd_coud_16, &sd_eofbepos_16 };
199
200/* Coordinates and their implementation **************************************/
201
202static uint64_t index_eofb(Cube cube);
203static uint64_t index_eofbepos(Cube cube);
204static uint64_t index_coud(Cube cube);
205static uint64_t index_corners(Cube cube);
206static uint64_t index_cornershtr(Cube cube);
207static uint64_t index_drud(Cube cube);
208static uint64_t index_coud_sym16(Cube cube);
209static uint64_t index_eofbepos_sym16(Cube cube);
210static uint64_t index_drud_sym16(Cube cube);
211static uint64_t index_khuge(Cube cube);
212
213static Cube antindex_eofb(uint64_t ind);
214static Cube antindex_eofbepos(uint64_t ind);
215static Cube antindex_coud(uint64_t ind);
216static Cube antindex_corners(uint64_t ind);
217static Cube antindex_cornershtr(uint64_t ind);
218static Cube antindex_drud(uint64_t ind);
219static Cube antindex_coud_sym16(uint64_t ind);
220static Cube antindex_eofbepos_sym16(uint64_t ind);
221static Cube antindex_drud_sym16(uint64_t ind);
222static Cube antindex_khuge(uint64_t ind);
223
224Coordinate
225coord_eofb = {
226 .index = index_eofb,
227 .cube = antindex_eofb,
228 .check = check_eofb,
229 .max = POW2TO11
230};
231
232Coordinate
233coord_eofbepos = {
234 .index = index_eofbepos,
235 .cube = antindex_eofbepos,
236 .check = check_eofbepos,
237 .max = POW2TO11 * BINOM12ON4
238};
239
240Coordinate
241coord_coud = {
242 .index = index_coud,
243 .cube = antindex_coud,
244 .check = check_coud,
245 .max = POW3TO7
246};
247
248Coordinate
249coord_corners = {
250 .index = index_corners,
251 .cube = antindex_corners,
252 .check = check_corners,
253 .max = POW3TO7 * FACTORIAL8
254};
255
256Coordinate
257coord_cornershtr = {
258 .index = index_cornershtr,
259 .cube = antindex_cornershtr,
260 .check = check_cornershtr,
261 .max = POW3TO7 * BINOM8ON4 * 6
262};
263
264Coordinate
265coord_drud = {
266 .index = index_drud,
267 .cube = antindex_drud,
268 .check = check_drud,
269 .max = POW2TO11 * POW3TO7 * BINOM12ON4
270};
271
272Coordinate
273coord_eofbepos_sym16 = {
274 .index = index_eofbepos_sym16,
275 .cube = antindex_eofbepos_sym16,
276 .check = check_eofbepos,
277};
278
279Coordinate
280coord_coud_sym16 = {
281 .index = index_coud_sym16,
282 .cube = antindex_coud_sym16,
283 .check = check_coud,
284};
285
286Coordinate
287coord_drud_sym16 = {
288 .index = index_drud_sym16,
289 .cube = antindex_drud_sym16,
290 .check = check_drud,
291 .max = POW3TO7 * 64430
292};
293
294Coordinate
295coord_khuge = {
296 .index = index_khuge,
297 .cube = antindex_khuge,
298 .check = check_khuge,
299 .max = POW3TO7 * FACTORIAL4 * 64430
300};
301
302
303static uint64_t
304index_eofb(Cube cube)
305{
306 return cube.eofb;
307}
308
309static uint64_t
310index_eofbepos(Cube cube)
311{
312 return (cube.epose / FACTORIAL4) * POW2TO11 + cube.eofb;
313}
314
315static uint64_t
316index_coud(Cube cube)
317{
318 return cube.coud;
319}
320
321static uint64_t
322index_corners(Cube cube)
323{
324 return cube.coud * FACTORIAL8 + cube.cp;
325}
326
327static uint64_t
328index_cornershtr(Cube cube)
329{
330 return cube.coud * BINOM8ON4 * 6 + cphtr(cube);
331}
332
333static uint64_t
334index_drud(Cube cube)
335{
336 uint64_t a, b, c;
337
338 a = cube.eofb;
339 b = cube.coud;
340 c = cube.epose / FACTORIAL4;
341
342 b *= POW2TO11;
343 c *= POW2TO11 * POW3TO7;
344
345 return a + b + c;
346}
347
348static uint64_t
349index_coud_sym16(Cube cube)
350{
351 return sd_coud_16.class[index_coud(cube)];
352}
353
354static uint64_t
355index_drud_sym16(Cube cube)
356{
357 Trans t;
358 Cube c;
359
360 t = sd_eofbepos_16.transtorep[index_eofbepos(cube)];
361 c = apply_trans(t, cube);
362
363 return index_eofbepos_sym16(c) * POW3TO7 + c.coud;
364}
365
366static uint64_t
367index_eofbepos_sym16(Cube cube)
368{
369 return sd_eofbepos_16.class[index_eofbepos(cube)];
370}
371
372static uint64_t
373index_khuge(Cube cube)
374{
375 Trans t;
376 Cube c;
377 uint64_t a;
378
379 t = sd_eofbepos_16.transtorep[index_eofbepos(cube)];
380 c = apply_trans(t, cube);
381 a = (index_eofbepos_sym16(c) * 24) + (c.epose % 24);
382
383 return a * POW3TO7 + c.coud;
384}
385
386
387/* TODO: rename */
388static Cube
389antindex_eofb(uint64_t ind)
390{
391 return (Cube){ .eofb = ind, .eorl = ind, .eoud = ind };
392}
393
394static Cube
395antindex_eofbepos(uint64_t ind)
396{
397 return admissible_ee_aux[ind];
398}
399
400/* TODO: rename */
401static Cube
402antindex_coud(uint64_t ind)
403{
404 return (Cube){ .coud = ind, .corl = ind, .cofb = ind };
405}
406
407/* TODO: admissible co for other orientations */
408static Cube
409antindex_corners(uint64_t ind)
410{
411 Cube c = {0};
412
413 c.coud = ind / FACTORIAL8;
414 c.cp = ind % FACTORIAL8;
415
416 return c;
417}
418
419/* TODO: admissible co for other orientations */
420static Cube
421antindex_cornershtr(uint64_t ind)
422{
423 Cube c = anti_cphtr(ind % (BINOM8ON4 * 6));
424
425 c.coud = ind / (BINOM8ON4 * 6);
426
427 return c;
428}
429
430/* TODO: admissible eos and cos */
431static Cube
432antindex_drud(uint64_t ind)
433{
434 Cube c = {0};
435
436 c.eofb = ind % POW2TO11;
437 c.coud = (ind / POW2TO11) % POW3TO7;
438 c.epose = (ind % (POW2TO11 * POW3TO7)) * FACTORIAL4;
439
440 return c;
441}
442
443static Cube
444antindex_coud_sym16(uint64_t ind)
445{
446 return sd_coud_16.rep[ind];
447}
448
449static Cube
450antindex_eofbepos_sym16(uint64_t ind)
451{
452 return sd_eofbepos_16.rep[ind];
453}
454
455static Cube
456antindex_drud_sym16(uint64_t ind)
457{
458 Cube c;
459
460 c = sd_eofbepos_16.rep[ind/POW3TO7];
461 c.coud = ind % POW3TO7;
462 c.cofb = c.coud;
463 c.corl = c.coud;
464
465 return c;
466}
467
468static Cube
469antindex_khuge(uint64_t ind)
470{
471 Cube c;
472
473 c = sd_eofbepos_16.rep[ind/(FACTORIAL4*POW3TO7)];
474 c.epose = ((c.epose / 24) * 24) + ((ind/POW3TO7) % 24);
475 c.coud = ind % POW3TO7;
476
477 return c;
478}
479
480
481/* Checkers ******************************************************************/
482
483bool
484check_centers(Cube cube)
485{
486 return cube.cpos == 0;
487}
488
489bool
490check_corners(Cube cube)
491{
492 return cube.cp == 0 && cube.coud == 0;
493}
494
495bool
496check_cornershtr(Cube cube)
497{
498 return cube.coud == 0 && cphtr(cube) == 0; /* TODO: use array cphtrcosets*/
499}
500
501bool
502check_coud(Cube cube)
503{
504 return cube.coud == 0;
505}
506
507bool
508check_drud(Cube cube)
509{
510 return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0;
511}
512
513bool
514check_eofb(Cube cube)
515{
516 return cube.eofb == 0;
517}
518
519bool
520check_eofbepos(Cube cube)
521{
522 return cube.eofb == 0 && cube.epose / 24 == 0;
523}
524
525bool
526check_epose(Cube cube)
527{
528 return cube.epose == 0;
529}
530
531bool
532check_ep(Cube cube)
533{
534 return cube.epose == 0 && cube.eposs == 0 && cube.eposm == 0;
535}
536
537bool
538check_khuge(Cube cube)
539{
540 return check_drud(cube) && cube.epose % 24 == 0;
541}
542
543bool
544check_nothing(Cube cube)
545{
546 return is_admissible(cube); /*TODO: maybe change?*/
547}
548
549/* Movesets ******************************************************************/
550
551bool
552moveset_HTM(Move m)
553{
554 return m >= U && m <= B3;
555}
556
557bool
558moveset_URF(Move m)
559{
560 Move b = base_move(m);
561
562 return b == U || b == R || b == F;
563}
564
565
566/* Local functions implementation ********************************************/
567
568/* TODO: this should be an anti index (maybe?) */
569static Cube
570admissible_ep(Cube cube, PieceFilter f)
571{
572 CubeArray *arr = new_cubearray(cube, f);
573 Cube ret;
574 bool used[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
575 int i, j;
576
577 for (i = 0; i < 12; i++)
578 if (arr->ep[i] != -1)
579 used[arr->ep[i]] = true;
580
581 for (i = 0, j = 0; i < 12; i++) {
582 for ( ; j < 11 && used[j]; j++);
583 if (arr->ep[i] == -1)
584 arr->ep[i] = j++;
585 }
586
587 ret = arrays_to_cube(arr, pf_ep);
588 free_cubearray(arr, f);
589
590 return ret;
591}
592
593static Cube
594admissible_eos_from_eofbepos(Cube cube)
595{
596 Edge e;
597 Cube ret;
598 CubeArray *arr = new_cubearray(cube, pf_all);
599
600 memcpy(arr->eorl, arr->eofb, 12 * sizeof(int));
601 memcpy(arr->eoud, arr->eofb, 12 * sizeof(int));
602
603 for (e = 0; e < 12; e++) {
604 if ((edge_slice(e) != 0 && edge_slice(arr->ep[e]) == 0) ||
605 (edge_slice(e) == 0 && edge_slice(arr->ep[e]) != 0))
606 arr->eorl[e] = 1 - arr->eorl[e];
607 if ((edge_slice(e) != 2 && edge_slice(arr->ep[e]) == 2) ||
608 (edge_slice(e) == 2 && edge_slice(arr->ep[e]) != 2))
609 arr->eoud[e] = 1 - arr->eoud[e];
610 }
611
612 ret = arrays_to_cube(arr, pf_all);
613 free_cubearray(arr, pf_all);
614
615 return ret;
616}
617
618static bool
619allowed_next(Move move, DfsData *dd)
620{
621 if (!possible_next[dd->last2][dd->last1][move])
622 return false;
623
624 if (commute[dd->last1][move])
625 return dd->move_position[dd->last1] < dd->move_position[move];
626
627 return true;
628}
629
630static void
631append_alg(AlgList *l, Alg *alg)
632{
633 AlgListNode *node = malloc(sizeof(AlgListNode));
634 int i;
635
636 node->alg = new_alg("");
637 for (i = 0; i < alg->len; i++)
638 append_move(node->alg, alg->move[i], alg->inv[i]);
639 node->next = NULL;
640
641 if (++l->len == 1)
642 l->first = node;
643 else
644 l->last->next = node;
645 l->last = node;
646}
647
648static void
649append_move(Alg *alg, Move m, bool inverse)
650{
651 if (alg->len == alg->allocated)
652 realloc_alg(alg, 2*alg->len);
653
654 alg->move[alg->len] = m;
655 alg->inv [alg->len] = inverse;
656 alg->len++;
657}
658
659static Cube
660apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a)
661{
662 Cube ret = {0};
663 int i;
664
665 for (i = 0; i < alg->len; i++)
666 if (alg->inv[i])
667 ret = a ? apply_move(alg->move[i], ret) :
668 apply_move_cubearray(alg->move[i], ret, f);
669
670 ret = compose_filtered(c, inverse_cube(ret), f);
671
672 for (i = 0; i < alg->len; i++)
673 if (!alg->inv[i])
674 ret = a ? apply_move(alg->move[i], ret) :
675 apply_move_cubearray(alg->move[i], ret, f);
676
677 return ret;
678}
679
680static void
681apply_permutation(int *perm, int *set, int n)
682{
683 int *aux = malloc(n * sizeof(int));
684 int i;
685
686 if (!is_perm(perm, n))
687 return;
688
689 for (i = 0; i < n; i++)
690 aux[i] = set[perm[i]];
691
692 memcpy(set, aux, n * sizeof(int));
693 free(aux);
694}
695
696static Cube
697apply_move_cubearray(Move m, Cube cube, PieceFilter f)
698{
699 CubeArray m_arr = {
700 edge_cycle[m],
701 eofb_flipped[m],
702 eorl_flipped[m],
703 eoud_flipped[m],
704 corner_cycle[m],
705 coud_flipped[m],
706 corl_flipped[m],
707 cofb_flipped[m],
708 center_cycle[m]
709 };
710
711 return move_via_arrays(&m_arr, cube, f);
712}
713
714static int
715array_ep_to_epos(int *ep, int *ss)
716{
717 int epos[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
718 int eps[4];
719 int i, j, is;
720
721 for (i = 0, is = 0; i < 12; i++) {
722 for (j = 0; j < 4; j++) {
723 if (ep[i] == ss[j]) {
724 eps[is++] = j;
725 epos[i] = 1;
726 }
727 }
728 }
729
730 for (i = 0; i < 4; i++)
731 swap(&epos[ss[i]], &epos[i+8]);
732
733 return epos_from_arrays(epos, eps);
734}
735
736static Cube
737arrays_to_cube(CubeArray *arr, PieceFilter f)
738{
739 Cube ret = {0};
740
741 if (f.epose)
742 ret.epose = array_ep_to_epos(arr->ep, epe_solved);
743 if (f.eposs)
744 ret.eposs = array_ep_to_epos(arr->ep, eps_solved);
745 if (f.eposm)
746 ret.eposm = array_ep_to_epos(arr->ep, epm_solved);
747 if (f.eofb)
748 ret.eofb = digit_array_to_int(arr->eofb, 11, 2);
749 if (f.eorl)
750 ret.eorl = digit_array_to_int(arr->eorl, 11, 2);
751 if (f.eoud)
752 ret.eoud = digit_array_to_int(arr->eoud, 11, 2);
753 if (f.cp)
754 ret.cp = perm_to_index(arr->cp, 8);
755 if (f.coud)
756 ret.coud = digit_array_to_int(arr->coud, 7, 3);
757 if (f.corl)
758 ret.corl = digit_array_to_int(arr->corl, 7, 3);
759 if (f.cofb)
760 ret.cofb = digit_array_to_int(arr->cofb, 7, 3);
761 if (f.cpos)
762 ret.cpos = perm_to_index(arr->cpos, 6);
763
764 return ret;
765}
766
767static int
768binomial(int n, int k)
769{
770 if (n < 0 || k < 0 || k > n)
771 return 0;
772
773 return factorial(n) / (factorial(k) * factorial(n-k));
774}
775
776static Cube
777compose_filtered(Cube c2, Cube c1, PieceFilter f)
778{
779 CubeArray *arr = new_cubearray(c2, f);
780 Cube ret;
781
782 ret = move_via_arrays(arr, c1, f);
783 free_cubearray(arr, f);
784
785 return ret;
786}
787
788static void
789cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f)
790{
791 int i;
792
793 if (f.epose || f.eposs || f.eposm)
794 for (i = 0; i < 12; i++)
795 arr->ep[i] = -1;
796
797 if (f.epose)
798 epos_to_partial_ep(cube.epose, arr->ep, epe_solved);
799 if (f.eposs)
800 epos_to_partial_ep(cube.eposs, arr->ep, eps_solved);
801 if (f.eposm)
802 epos_to_partial_ep(cube.eposm, arr->ep, epm_solved);
803 if (f.eofb)
804 int_to_sum_zero_array(cube.eofb, 2, 12, arr->eofb);
805 if (f.eorl)
806 int_to_sum_zero_array(cube.eorl, 2, 12, arr->eorl);
807 if (f.eoud)
808 int_to_sum_zero_array(cube.eoud, 2, 12, arr->eoud);
809 if (f.cp)
810 index_to_perm(cube.cp, 8, arr->cp);
811 if (f.coud)
812 int_to_sum_zero_array(cube.coud, 3, 8, arr->coud);
813 if (f.corl)
814 int_to_sum_zero_array(cube.corl, 3, 8, arr->corl);
815 if (f.cofb)
816 int_to_sum_zero_array(cube.cofb, 3, 8, arr->cofb);
817 if (f.cpos)
818 index_to_perm(cube.cpos, 6, arr->cpos);
819}
820
821/*
822static int
823cphtr_cp(int cp)
824{
825 int i, a[8];
826
827 index_to_perm(cp, 8, a);
828
829 for (i = 0; i < 8; i++)
830 if (a[i] == UFR || a[i] == UBL || a[i] == DFL || a[i] == DBR)
831 a[i] = 0;
832 else
833 a[i] = 1;
834
835 swap(&a[1], &a[5]);
836 swap(&a[3], &a[7]);
837
838 return subset_to_index(a, 8, 4);
839}
840*/
841
842static void
843dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd)
844{
845 if (dfs_stop(c, s, opts, dd))
846 return;
847
848 if (dfs_check_solved(opts, dd))
849 return;
850
851 dfs_branch(c, s, opts, dd);
852
853 if (opts->can_niss && !dd->niss)
854 dfs_niss(c, s, opts, dd);
855}
856
857static void
858dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd)
859{
860 Move m, l1 = dd->last1, l2 = dd->last2, *moves = dd->sorted_moves;
861
862 int i, maxnsol = opts->max_solutions;
863
864 for (i = 0; moves[i] != NULLMOVE && dd->sols->len < maxnsol; i++) {
865 m = moves[i];
866 if (allowed_next(m, dd)) {
867 dd->last2 = dd->last1;
868 dd->last1 = m;
869 append_move(dd->current_alg, m, dd->niss);
870
871 dfs(apply_move(m, c), s, opts, dd);
872
873 dd->current_alg->len--;
874 dd->last2 = l2;
875 dd->last1 = l1;
876 }
877 }
878}
879
880static bool
881dfs_check_solved(SolveOptions *opts, DfsData *dd)
882{
883 if (dd->lb != 0)
884 return false;
885
886 if (dd->current_alg->len == dd->d) {
887 append_alg(dd->sols, dd->current_alg);
888
889 if (opts->feedback)
890 print_alg(dd->current_alg, false);
891 }
892
893 return true;
894}
895
896static void
897dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd)
898{
899 Move l1 = dd->last1, l2 = dd->last2;
900 CubeTarget ct;
901
902 ct.cube = apply_move(inverse_move(l1), (Cube){0});
903 ct.target = 1;
904
905 if (dd->current_alg->len == 0 || s.estimate(ct)) {
906 dd->niss = true;
907 dd->last1 = NULLMOVE;
908 dd->last2 = NULLMOVE;
909
910 dfs(inverse_cube(c), s, opts, dd);
911
912 dd->last1 = l1;
913 dd->last2 = l2;
914 dd->niss = false;
915 }
916}
917
918static bool
919dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd)
920{
921 CubeTarget ct = {
922 .cube = c,
923 .target = dd->d - dd->current_alg->len
924 };
925
926 if (dd->sols->len >= opts->max_solutions)
927 return true;
928
929 dd->lb = s.estimate(ct);
930 if (opts->can_niss && !dd->niss)
931 dd->lb = MIN(1, dd->lb);
932
933 if (dd->current_alg->len + dd->lb > dd->d)
934 return true;
935
936 return false;
937}
938
939static int
940digit_array_to_int(int *a, int n, int b)
941{
942 int i, ret = 0, p = 1;
943
944 for (i = 0; i < n; i++, p *= b)
945 ret += a[i] * p;
946
947 return ret;
948}
949
950static int
951edge_slice(Edge e) {
952 if (e < 0 || e > 11)
953 return -1;
954
955 if (e == FR || e == FL || e == BL || e == BR)
956 return 0;
957 if (e == UR || e == UL || e == DR || e == DL)
958 return 1;
959
960 return 2;
961}
962
963static int
964epos_dependent_pos(int poss, int pose)
965{
966 int ep[12] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
967 int ep8[8] = {0, 0, 0, 0, 0, 0, 0, 0};
968 int i, j;
969
970 epos_to_partial_ep(poss*FACTORIAL4, ep, eps_solved);
971 epos_to_partial_ep(pose*FACTORIAL4, ep, epe_solved);
972
973 for (i = 0, j = 0; i < 12; i++)
974 if (edge_slice(ep[i]) != 0)
975 ep8[j++] = (edge_slice(ep[i]) == 1) ? 1 : 0;
976
977 swap(&ep8[1], &ep8[4]);
978 swap(&ep8[3], &ep8[6]);
979
980 return subset_to_index(ep8, 8, 4);
981}
982
983static int
984epos_from_arrays(int *epos, int *ep)
985{
986 return FACTORIAL4 * subset_to_index(epos,12,4) + perm_to_index(ep,4);
987}
988
989static void
990epos_to_partial_ep(int epos, int *ep, int *ss)
991{
992 int i, is, eposs[12], eps[4];
993
994 index_to_perm(epos % FACTORIAL4, 4, eps);
995 index_to_subset(epos / FACTORIAL4, 12, 4, eposs);
996
997 for (i = 0; i < 4; i++)
998 swap(&eposs[ss[i]], &eposs[i+8]);
999
1000 for (i = 0, is = 0; i < 12; i++)
1001 if (eposs[i])
1002 ep[i] = ss[eps[is++]];
1003}
1004
1005static int
1006factorial(int n)
1007{
1008 int i, ret = 1;
1009
1010 if (n < 0)
1011 return 0;
1012
1013 for (i = 1; i <= n; i++)
1014 ret *= i;
1015
1016 return ret;
1017}
1018
1019void
1020free_alg(Alg *alg)
1021{
1022 free(alg->move);
1023 free(alg->inv);
1024 free(alg);
1025}
1026
1027void
1028free_alglist(AlgList *l)
1029{
1030 AlgListNode *aux, *i = l->first;
1031
1032 while (i != NULL) {
1033 aux = i->next;
1034 free_alglistnode(i);
1035 i = aux;
1036 }
1037 free(l);
1038}
1039
1040void
1041free_alglistnode(AlgListNode *aln)
1042{
1043 free_alg(aln->alg);
1044 free(aln);
1045}
1046
1047static void
1048free_cubearray(CubeArray *arr, PieceFilter f)
1049{
1050 if (f.epose || f.eposs || f.eposm)
1051 free(arr->ep);
1052 if (f.eofb)
1053 free(arr->eofb);
1054 if (f.eorl)
1055 free(arr->eorl);
1056 if (f.eoud)
1057 free(arr->eoud);
1058 if (f.cp)
1059 free(arr->cp);
1060 if (f.coud)
1061 free(arr->coud);
1062 if (f.corl)
1063 free(arr->corl);
1064 if (f.cofb)
1065 free(arr->cofb);
1066 if (f.cpos)
1067 free(arr->cpos);
1068
1069 free(arr);
1070}
1071
1072static void
1073genptable_dfs(Cube c, PruneData *pd, DfsData *dd)
1074{
1075 int oldval = ptableval(pd, c);
1076
1077 if (oldval < dd->m || ptable_has_reached(pd, c) ||
1078 pd->n == pd->coord->max || (dd->m != 0 && pd->coord->check(c)) )
1079 return;
1080
1081 /*ptable_set_reached(pd, c);*/
1082
1083 if (dd->m == dd->d) {
1084 if (dd->m < oldval)
1085 ptable_update(pd, c, dd->m);
1086 return;
1087 }
1088
1089 genptable_dfs_branch(c, pd, dd);
1090}
1091
1092static void
1093genptable_dfs_branch(Cube c, PruneData *pd, DfsData *dd)
1094{
1095 Move i, move, l1 = dd->last1, l2 = dd->last2;
1096
1097 dd->m++;
1098
1099 for (i = 0; dd->sorted_moves[i] != NULLMOVE; i++) {
1100 move = dd->sorted_moves[i];
1101 if (allowed_next(move, dd)) {
1102 dd->last2 = dd->last1;
1103 dd->last1 = move;
1104
1105 genptable_dfs(apply_move(move, c), pd, dd);
1106
1107 dd->last2 = l2;
1108 dd->last1 = l1;
1109 }
1110 }
1111
1112 dd->m--;
1113}
1114
1115static void
1116gensym(SymData *sd)
1117{
1118 uint64_t i, in, nreps = 0;
1119 int j;
1120 Cube c, d;
1121
1122 if (sd->generated)
1123 return;
1124
1125 sd->class = malloc(sd->coord->max * sizeof(uint64_t));
1126 sd->rep = malloc(sd->coord->max * sizeof(Cube));
1127 sd->transtorep = malloc(sd->coord->max * sizeof(Trans));
1128
1129 if (read_symdata_file(sd)) {
1130 sd->generated = true;
1131 return;
1132 }
1133
1134 fprintf(stderr, "Cannot load %s, generating it\n", sd->filename);
1135
1136 for (i = 0; i < sd->coord->max; i++)
1137 sd->class[i] = sd->coord->max + 1;
1138
1139 for (i = 0; i < sd->coord->max; i++) {
1140 if (sd->class[i] == sd->coord->max + 1) {
1141 c = sd->coord->cube(i);
1142 sd->rep[nreps] = c;
1143 for (j = 0; j < sd->ntrans; j++) {
1144 d = apply_trans(sd->trans[j], c);
1145 in = sd->coord->index(d);
1146
1147 if (sd->class[in] == sd->coord->max + 1) {
1148 sd->class[in] = nreps;
1149 sd->transtorep[in] =
1150 inverse_trans(sd->trans[j]);
1151 }
1152 }
1153 nreps++;
1154 }
1155 }
1156
1157 sd->sym_coord->max = nreps;
1158 sd->rep = realloc(sd->rep, nreps * sizeof(Cube));
1159 sd->generated = true;
1160
1161 fprintf(stderr, "Found %lu classes\n", nreps);
1162
1163 if (!write_symdata_file(sd))
1164 fprintf(stderr, "Error writing SymData file\n");
1165
1166 return;
1167}
1168
1169static void
1170index_to_perm(int p, int n, int *r)
1171{
1172 int *a = malloc(n * sizeof(int));
1173 int i, j, c;
1174
1175 for (i = 0; i < n; i++)
1176 a[i] = 0;
1177
1178 if (p < 0 || p >= factorial(n))
1179 for (i = 0; i < n; i++)
1180 r[i] = -1;
1181
1182 for (i = 0; i < n; i++) {
1183 c = 0;
1184 j = 0;
1185 while (c <= p / factorial(n-i-1))
1186 c += a[j++] ? 0 : 1;
1187 r[i] = j-1;
1188 a[j-1] = 1;
1189 p %= factorial(n-i-1);
1190 }
1191
1192 free(a);
1193}
1194
1195static void
1196index_to_subset(int s, int n, int k, int *r)
1197{
1198 int i, j, v;
1199
1200 if (s < 0 || s >= binomial(n, k)) {
1201 for (i = 0; i < n; i++)
1202 r[i] = -1;
1203 return;
1204 }
1205
1206 for (i = 0; i < n; i++) {
1207 if (k == n-i) {
1208 for (j = i; j < n; j++)
1209 r[j] = 1;
1210 return;
1211 }
1212
1213 if (k == 0) {
1214 for (j = i; j < n; j++)
1215 r[j] = 0;
1216 return;
1217 }
1218
1219 v = binomial(n-i-1, k);
1220 if (s >= v) {
1221 r[i] = 1;
1222 k--;
1223 s -= v;
1224 } else {
1225 r[i] = 0;
1226 }
1227 }
1228}
1229
1230static void
1231int_to_digit_array(int a, int b, int n, int *r)
1232{
1233 int i;
1234
1235 if (b <= 1)
1236 for (i = 0; i < n; i++)
1237 r[i] = 0;
1238 else
1239 for (i = 0; i < n; i++, a /= b)
1240 r[i] = a % b;
1241}
1242
1243static void
1244int_to_sum_zero_array(int x, int b, int n, int *a)
1245{
1246 int i, s = 0;
1247
1248 if (b <= 1) {
1249 for (i = 0; i < n; i++)
1250 a[i] = 0;
1251 } else {
1252 int_to_digit_array(x, b, n-1, a);
1253 for (i = 0; i < n - 1; i++)
1254 s = (s + a[i]) % b;
1255 a[n-1] = (b - s) % b;
1256 }
1257}
1258
1259static int
1260invert_digits(int a, int b, int n)
1261{
1262 int i, ret, *r = malloc(n * sizeof(int));
1263
1264 int_to_digit_array(a, b, n, r);
1265 for (i = 0; i < n; i++)
1266 r[i] = (b-r[i]) % b;
1267
1268 ret = digit_array_to_int(r, n, b);
1269 free(r);
1270 return ret;
1271}
1272
1273static bool
1274is_perm(int *a, int n)
1275{
1276 int *aux = malloc(n * sizeof(int));
1277 int i;
1278
1279 for (i = 0; i < n; i++)
1280 if (a[i] < 0 || a[i] >= n)
1281 return false;
1282 else
1283 aux[a[i]] = 1;
1284
1285 for (i = 0; i < n; i++)
1286 if (!aux[i])
1287 return false;
1288
1289 free(aux);
1290
1291 return true;
1292}
1293
1294static bool
1295is_subset(int *a, int n, int k)
1296{
1297 int i, sum = 0;
1298
1299 for (i = 0; i < n; i++)
1300 sum += a[i] ? 1 : 0;
1301
1302 return sum == k;
1303}
1304
1305static Cube
1306move_via_arrays(CubeArray *arr, Cube c, PieceFilter f)
1307{
1308 CubeArray *arrc = new_cubearray(c, f);
1309 Cube ret;
1310
1311 if (f.epose || f.eposs || f.eposm)
1312 apply_permutation(arr->ep, arrc->ep, 12);
1313
1314 if (f.eofb) {
1315 apply_permutation(arr->ep, arrc->eofb, 12);
1316 sum_arrays_mod(arr->eofb, arrc->eofb, 12, 2);
1317 }
1318
1319 if (f.eorl) {
1320 apply_permutation(arr->ep, arrc->eorl, 12);
1321 sum_arrays_mod(arr->eorl, arrc->eorl, 12, 2);
1322 }
1323
1324 if (f.eoud) {
1325 apply_permutation(arr->ep, arrc->eoud, 12);
1326 sum_arrays_mod(arr->eoud, arrc->eoud, 12, 2);
1327 }
1328
1329 if (f.cp)
1330 apply_permutation(arr->cp, arrc->cp, 8);
1331
1332 if (f.coud) {
1333 apply_permutation(arr->cp, arrc->coud, 8);
1334 sum_arrays_mod(arr->coud, arrc->coud, 8, 3);
1335 }
1336
1337 if (f.corl) {
1338 apply_permutation(arr->cp, arrc->corl, 8);
1339 sum_arrays_mod(arr->corl, arrc->corl, 8, 3);
1340 }
1341
1342 if (f.cofb) {
1343 apply_permutation(arr->cp, arrc->cofb, 8);
1344 sum_arrays_mod(arr->cofb, arrc->cofb, 8, 3);
1345 }
1346
1347 if (f.cpos)
1348 apply_permutation(arr->cpos, arrc->cpos, 6);
1349
1350 ret = arrays_to_cube(arrc, f);
1351 free_cubearray(arrc, f);
1352
1353 return ret;
1354}
1355
1356static void
1357movelist_to_position(Move *movelist, int *position)
1358{
1359 Move m;
1360
1361 for (m = 0; m < NMOVES && movelist[m] != NULLMOVE; m++)
1362 position[movelist[m]] = m;
1363}
1364
1365static void
1366moveset_to_list(Moveset ms, Estimator f, Move *r)
1367{
1368 CubeTarget ct = { .target = 1 };
1369 int b[NMOVES];
1370 int na = 0, nb = 0;
1371 Move i;
1372
1373 if (ms == NULL) {
1374 fprintf(stderr, "Error: no moveset given\n");
1375 return;
1376 }
1377
1378 for (i = U; i < NMOVES; i++) {
1379 if (ms(i)) {
1380 ct.cube = apply_move(i, (Cube){0});
1381 if (f != NULL && f(ct))
1382 r[na++] = i;
1383 else
1384 b[nb++] = i;
1385 }
1386 }
1387
1388 memcpy(r + na, b, nb * sizeof(Move));
1389 r[na+nb] = NULLMOVE;
1390}
1391
1392static AlgList *
1393new_alglist()
1394{
1395 AlgList *ret = malloc(sizeof(AlgList));
1396
1397 ret->len = 0;
1398 ret->first = NULL;
1399 ret->last = NULL;
1400
1401 return ret;
1402}
1403
1404static CubeArray *
1405new_cubearray(Cube cube, PieceFilter f)
1406{
1407 CubeArray *arr = malloc(sizeof(CubeArray));
1408
1409 if (f.epose || f.eposs || f.eposm)
1410 arr->ep = malloc(12 * sizeof(int));
1411 if (f.eofb)
1412 arr->eofb = malloc(12 * sizeof(int));
1413 if (f.eorl)
1414 arr->eorl = malloc(12 * sizeof(int));
1415 if (f.eoud)
1416 arr->eoud = malloc(12 * sizeof(int));
1417 if (f.cp)
1418 arr->cp = malloc(8 * sizeof(int));
1419 if (f.coud)
1420 arr->coud = malloc(8 * sizeof(int));
1421 if (f.corl)
1422 arr->corl = malloc(8 * sizeof(int));
1423 if (f.cofb)
1424 arr->cofb = malloc(8 * sizeof(int));
1425 if (f.cpos)
1426 arr->cpos = malloc(6 * sizeof(int));
1427
1428 cube_to_arrays(cube, arr, f);
1429
1430 return arr;
1431}
1432
1433static int
1434perm_sign(int *a, int n)
1435{
1436 int i, j, ret = 0;
1437
1438 if (!is_perm(a,n))
1439 return -1;
1440
1441 for (i = 0; i < n; i++)
1442 for (j = i+1; j < n; j++)
1443 ret += (a[i] > a[j]) ? 1 : 0;
1444
1445 return ret % 2;
1446}
1447
1448static int
1449perm_to_index(int *a, int n)
1450{
1451 int i, j, c, ret = 0;
1452
1453 if (!is_perm(a, n))
1454 return -1;
1455
1456 for (i = 0; i < n; i++) {
1457 c = 0;
1458 for (j = i+1; j < n; j++)
1459 c += (a[i] > a[j]) ? 1 : 0;
1460 ret += factorial(n-i-1) * c;
1461 }
1462
1463 return ret;
1464}
1465
1466static int
1467powint(int a, int b)
1468{
1469 if (b < 0)
1470 return 0;
1471 if (b == 0)
1472 return 1;
1473
1474 if (b % 2)
1475 return a * powint(a, b-1);
1476 else
1477 return powint(a*a, b/2);
1478}
1479
1480static bool
1481ptable_has_reached(PruneData *pd, Cube cube)
1482{
1483 uint64_t ind = pd->coord->index(cube);
1484
1485 return (ind % 2) ? pd->reached[ind/2] / 16 : pd->reached[ind/2] % 16;
1486}
1487
1488static void
1489ptable_set_reached(PruneData *pd, Cube cube)
1490{
1491 uint64_t ind = pd->coord->index(cube);
1492 uint8_t oldval2 = pd->reached[ind/2];
1493 int other = (ind % 2) ? oldval2 % 16 : oldval2 / 16;
1494
1495 pd->reached[ind/2] = (ind % 2) ? 16 + other : 16*other + 1;
1496}
1497
1498static void
1499ptable_update(PruneData *pd, Cube cube, int n)
1500{
1501 uint64_t ind = pd->coord->index(cube);
1502 uint8_t oldval2 = pd->ptable[ind/2];
1503 int other = (ind % 2) ? oldval2 % 16 : oldval2 / 16;
1504
1505 pd->ptable[ind/2] = (ind % 2) ? 16*n + other : 16*other + n;
1506 pd->n++;
1507}
1508
1509static void
1510realloc_alg(Alg *alg, int n)
1511{
1512 if (alg == NULL) {
1513 fprintf(stderr, "Error: trying to reallocate NULL alg.\n");
1514 return;
1515 }
1516
1517 if (n < alg->len) {
1518 fprintf(stderr, "Error: alg too long for reallocation ");
1519 fprintf(stderr, "(%d vs %d)\n", alg->len, n);
1520 return;
1521 }
1522
1523 if (n > 1000000) {
1524 fprintf(stderr, "Warning: very long alg,");
1525 fprintf(stderr, "something might go wrong.\n");
1526 }
1527
1528 alg->move = realloc(alg->move, n * sizeof(int));
1529 alg->inv = realloc(alg->inv, n * sizeof(int));
1530 alg->allocated = n;
1531}
1532
1533static bool
1534read_mtables_file()
1535{
1536 FILE *f;
1537 char fname[strlen(tabledir)+20];
1538 int m, b = sizeof(int);
1539 bool r = true;
1540
1541 strcpy(fname, tabledir);
1542 strcat(fname, "/mtables");
1543
1544 if ((f = fopen(fname, "rb")) == NULL)
1545 return false;
1546
1547 for (m = 0; m < NMOVES; m++) {
1548 r = r && fread(epose_mtable[m], b, me[0], f) == me[0];
1549 r = r && fread(eposs_mtable[m], b, me[1], f) == me[1];
1550 r = r && fread(eposm_mtable[m], b, me[2], f) == me[2];
1551 r = r && fread(eofb_mtable[m], b, me[3], f) == me[3];
1552 r = r && fread(eorl_mtable[m], b, me[4], f) == me[4];
1553 r = r && fread(eoud_mtable[m], b, me[5], f) == me[5];
1554 r = r && fread(cp_mtable[m], b, me[6], f) == me[6];
1555 r = r && fread(coud_mtable[m], b, me[7], f) == me[7];
1556 r = r && fread(corl_mtable[m], b, me[8], f) == me[8];
1557 r = r && fread(cofb_mtable[m], b, me[9], f) == me[9];
1558 r = r && fread(cpos_mtable[m], b, me[10], f) == me[10];
1559 }
1560
1561 fclose(f);
1562 return r;
1563}
1564
1565static bool
1566read_ptable_file(PruneData *pd)
1567{
1568 FILE *f;
1569 char fname[strlen(tabledir)+100];
1570 uint64_t r;
1571
1572 strcpy(fname, tabledir);
1573 strcat(fname, "/");
1574 strcat(fname, pd->filename);
1575
1576 if ((f = fopen(fname, "rb")) == NULL)
1577 return false;
1578
1579 r = fread(pd->ptable, sizeof(uint8_t), ptablesize(pd), f);
1580 fclose(f);
1581
1582 return r == ptablesize(pd);
1583}
1584
1585static bool
1586read_symdata_file(SymData *sd)
1587{
1588 FILE *f;
1589 char fname[strlen(tabledir)+100];
1590 uint64_t n = sd->coord->max, *sn = &sd->sym_coord->max;
1591 bool r = true;
1592
1593 strcpy(fname, tabledir);
1594 strcat(fname, "/");
1595 strcat(fname, sd->filename);
1596
1597 if ((f = fopen(fname, "rb")) == NULL)
1598 return false;
1599
1600 r = r && fread(&sd->sym_coord->max, sizeof(uint64_t), 1, f) == 1;
1601 r = r && fread(sd->rep, sizeof(Cube), *sn, f) == *sn;
1602 r = r && fread(sd->class, sizeof(uint64_t), n, f) == n;
1603 r = r && fread(sd->transtorep, sizeof(Trans), n, f) == n;
1604
1605 fclose(f);
1606 return r;
1607}
1608
1609static bool
1610read_ttables_file()
1611{
1612 FILE *f;
1613 char fname[strlen(tabledir)+20];
1614 int b = sizeof(int);
1615 bool r = true;
1616 Move m;
1617
1618 strcpy(fname, tabledir);
1619 strcat(fname, "/");
1620 strcat(fname, "ttables");
1621
1622 if ((f = fopen(fname, "rb")) == NULL)
1623 return false;
1624
1625 for (m = 0; m < NTRANS; m++) {
1626 r = r && fread(epose_ttable[m], b, me[0], f) == me[0];
1627 r = r && fread(eposs_ttable[m], b, me[1], f) == me[1];
1628 r = r && fread(eposm_ttable[m], b, me[2], f) == me[2];
1629 r = r && fread(eo_ttable[m], b, me[3], f) == me[3];
1630 r = r && fread(cp_ttable[m], b, me[6], f) == me[6];
1631 r = r && fread(co_ttable[m], b, me[7], f) == me[7];
1632 r = r && fread(cpos_ttable[m], b, me[10], f) == me[10];
1633 r = r && fread(moves_ttable[m], b, me[11], f) == me[11];
1634 }
1635
1636 fclose(f);
1637 return r;
1638}
1639
1640static Cube
1641rotate_via_compose(Trans r, Cube c, PieceFilter f)
1642{
1643 static int zero12[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1644 static int zero8[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
1645 static CubeArray ma = {
1646 .ep = ep_mirror,
1647 .eofb = zero12,
1648 .eorl = zero12,
1649 .eoud = zero12,
1650 .cp = cp_mirror,
1651 .coud = zero8,
1652 .corl = zero8,
1653 .cofb = zero8,
1654 .cpos = cpos_mirror
1655 };
1656
1657 Alg *inv = inverse_alg(rotation_algs[r % NROTATIONS]);
1658 Cube ret = {0};
1659
1660 if (r >= NROTATIONS)
1661 ret = move_via_arrays(&ma, ret, f);
1662 ret = apply_alg_generic(inv, ret, f, true);
1663
1664 ret = compose_filtered(c, ret, f);
1665
1666 ret = apply_alg_generic(rotation_algs[r % NROTATIONS], ret, f, true);
1667 if (r >= NROTATIONS)
1668 ret = move_via_arrays(&ma, ret, f);
1669
1670 free_alg(inv);
1671 return ret;
1672}
1673
1674static int
1675subset_to_index(int *a, int n, int k)
1676{
1677 int i, ret = 0;
1678
1679 if (!is_subset(a, n, k))
1680 return binomial(n, k);
1681
1682 for (i = 0; i < n; i++) {
1683 if (k == n-i)
1684 return ret;
1685 if (a[i]) {
1686 ret += binomial(n-i-1, k);
1687 k--;
1688 }
1689 }
1690
1691 return ret;
1692}
1693
1694static void
1695sum_arrays_mod(int *src, int *dst, int n, int m)
1696{
1697 int i;
1698
1699 for (i = 0; i < n; i++)
1700 dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m;
1701}
1702
1703static void
1704swap(int *a, int *b)
1705{
1706 int aux;
1707
1708 aux = *a;
1709 *a = *b;
1710 *b = aux;
1711}
1712
1713static bool
1714write_mtables_file()
1715{
1716 FILE *f;
1717 char fname[strlen(tabledir)+20];
1718 int m, b = sizeof(int);
1719 bool r = true;
1720
1721 strcpy(fname, tabledir);
1722 strcat(fname, "/mtables");
1723
1724 if ((f = fopen(fname, "wb")) == NULL)
1725 return false;
1726
1727 for (m = 0; m < NMOVES; m++) {
1728 r = r && fwrite(epose_mtable[m], b, me[0], f) == me[0];
1729 r = r && fwrite(eposs_mtable[m], b, me[1], f) == me[1];
1730 r = r && fwrite(eposm_mtable[m], b, me[2], f) == me[2];
1731 r = r && fwrite(eofb_mtable[m], b, me[3], f) == me[3];
1732 r = r && fwrite(eorl_mtable[m], b, me[4], f) == me[4];
1733 r = r && fwrite(eoud_mtable[m], b, me[5], f) == me[5];
1734 r = r && fwrite(cp_mtable[m], b, me[6], f) == me[6];
1735 r = r && fwrite(coud_mtable[m], b, me[7], f) == me[7];
1736 r = r && fwrite(corl_mtable[m], b, me[8], f) == me[8];
1737 r = r && fwrite(cofb_mtable[m], b, me[9], f) == me[9];
1738 r = r && fwrite(cpos_mtable[m], b, me[10], f) == me[10];
1739 }
1740
1741 fclose(f);
1742 return r;
1743}
1744
1745static bool
1746write_ptable_file(PruneData *pd)
1747{
1748 FILE *f;
1749 char fname[strlen(tabledir)+100];
1750 uint64_t written;
1751
1752 strcpy(fname, tabledir);
1753 strcat(fname, "/");
1754 strcat(fname, pd->filename);
1755
1756 if ((f = fopen(fname, "wb")) == NULL)
1757 return false;
1758
1759 written = fwrite(pd->ptable, sizeof(uint8_t), ptablesize(pd), f);
1760 fclose(f);
1761
1762 return written == ptablesize(pd);
1763}
1764
1765static bool
1766write_symdata_file(SymData *sd)
1767{
1768 FILE *f;
1769 char fname[strlen(tabledir)+100];
1770 uint64_t n = sd->coord->max, *sn = &sd->sym_coord->max;
1771 bool r = true;
1772
1773 strcpy(fname, tabledir);
1774 strcat(fname, "/");
1775 strcat(fname, sd->filename);
1776
1777 if ((f = fopen(fname, "wb")) == NULL)
1778 return false;
1779
1780 r = r && fwrite(&sd->sym_coord->max, sizeof(uint64_t), 1, f) == 1;
1781 r = r && fwrite(sd->rep, sizeof(Cube), *sn, f) == *sn;
1782 r = r && fwrite(sd->class, sizeof(uint64_t), n, f) == n;
1783 r = r && fwrite(sd->transtorep, sizeof(Trans), n, f) == n;
1784
1785 fclose(f);
1786 return r;
1787}
1788
1789static bool
1790write_ttables_file()
1791{
1792 FILE *f;
1793 char fname[strlen(tabledir)+20];
1794 bool r = true;
1795 int b = sizeof(int);
1796 Move m;
1797
1798 strcpy(fname, tabledir);
1799 strcat(fname, "/ttables");
1800
1801 if ((f = fopen(fname, "wb")) == NULL)
1802 return false;
1803
1804 for (m = 0; m < NTRANS; m++) {
1805 r = r && fwrite(epose_ttable[m], b, me[0], f) == me[0];
1806 r = r && fwrite(eposs_ttable[m], b, me[1], f) == me[1];
1807 r = r && fwrite(eposm_ttable[m], b, me[2], f) == me[2];
1808 r = r && fwrite(eo_ttable[m], b, me[3], f) == me[3];
1809 r = r && fwrite(cp_ttable[m], b, me[6], f) == me[6];
1810 r = r && fwrite(co_ttable[m], b, me[7], f) == me[7];
1811 r = r && fwrite(cpos_ttable[m], b, me[10], f) == me[10];
1812 r = r && fwrite(moves_ttable[m], b, me[11], f) == me[11];
1813 }
1814
1815 fclose(f);
1816 return r;
1817}
1818
1819/* Init functions implementation *********************************************/
1820
1821static void
1822init_auxtables()
1823{
1824 Cube c1, c2;
1825 CubeArray *arr;
1826 uint64_t ui, uj;
1827 int i, j, k, auxarr[12];
1828 bool cij, p1, p2;
1829
1830 for (ui = 0; ui < POW2TO11*BINOM12ON4; ui++) {
1831 k = (ui / POW2TO11) * 24;
1832 c1 = admissible_ep((Cube){ .epose = k }, pf_e);
1833 c1.eofb = ui % POW2TO11;
1834 c1 = admissible_eos_from_eofbepos(c1);
1835 admissible_ee_aux[ui] = c1;
1836 }
1837
1838 for (ui = 0; ui < FACTORIAL6; ui++) {
1839 arr = new_cubearray((Cube){.cpos = ui}, pf_cpos);
1840 for (i = 0; i < 6; i++) {
1841 what_center_at_aux[ui][i] = arr->cpos[i];
1842 where_is_center_aux[ui][arr->cpos[i]] = i;
1843 }
1844 free_cubearray(arr, pf_cpos);
1845 }
1846
1847 for (ui = 0; ui < FACTORIAL8; ui++) {
1848 arr = new_cubearray((Cube){.cp = ui}, pf_cp);
1849 for (i = 0; i < 8; i++) {
1850 what_corner_at_aux[ui][i] = arr->cp[i];
1851 where_is_corner_aux[ui][arr->cp[i]] = i;
1852 }
1853 free_cubearray(arr, pf_cp);
1854 }
1855
1856 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
1857 arr = new_cubearray((Cube){.epose = ui}, pf_e);
1858 for (i = 0; i < 12; i++)
1859 if (edge_slice(arr->ep[i]) == 0)
1860 where_is_edge_aux[0][ui][arr->ep[i]] = i;
1861 free_cubearray(arr, pf_e);
1862
1863 arr = new_cubearray((Cube){.eposs = ui}, pf_s);
1864 for (i = 0; i < 12; i++)
1865 if (edge_slice(arr->ep[i]) == 1)
1866 where_is_edge_aux[1][ui][arr->ep[i]] = i;
1867 free_cubearray(arr, pf_s);
1868
1869 arr = new_cubearray((Cube){.eposm = ui}, pf_m);
1870 for (i = 0; i < 12; i++)
1871 if (edge_slice(arr->ep[i]) == 2)
1872 where_is_edge_aux[2][ui][arr->ep[i]] = i;
1873 free_cubearray(arr, pf_m);
1874 }
1875
1876 for (ui = 0; ui < POW3TO7; ui++) {
1877 int_to_sum_zero_array(ui, 3, 8, auxarr);
1878 what_orientation_last_corner_aux[ui] = auxarr[7];
1879 }
1880
1881 for (ui = 0; ui < POW2TO11; ui++) {
1882 int_to_sum_zero_array(ui, 2, 12, auxarr);
1883 what_orientation_last_edge_aux[ui] = auxarr[11];
1884 }
1885
1886 for (ui = 0; ui < BINOM12ON4; ui++)
1887 for (uj = 0; uj < BINOM12ON4; uj++)
1888 epos_dependent_aux[ui][uj]=epos_dependent_pos(ui, uj);
1889
1890 for (i = 0; i < NMOVES; i++) {
1891 for (j = 0; j < NMOVES; j++) {
1892 c1 = apply_move(i, apply_move(j, (Cube){0}));
1893 c2 = apply_move(j, apply_move(i, (Cube){0}));
1894 commute[i][j] = equal(c1, c2) && i && j;
1895 }
1896 }
1897
1898 for (i = 0; i < NMOVES; i++) {
1899 for (j = 0; j < NMOVES; j++) {
1900 for (k = 0; k < NMOVES; k++) {
1901 p1 = j && base_move(j) == base_move(k);
1902 p2 = i && base_move(i) == base_move(k);
1903 cij = commute[i][j];
1904 possible_next[i][j][k] = !(p1 || (cij && p2));
1905 }
1906 }
1907 }
1908
1909 for (i = 0; i < NMOVES; i++)
1910 inverse_move_aux[i] = i ? i + 2 - 2*((i-1)%3) : NULLMOVE;
1911
1912 /* Is there a more elegant way? */
1913 inverse_trans_aux[uf] = uf;
1914 inverse_trans_aux[ur] = ul;
1915 inverse_trans_aux[ul] = ur;
1916 inverse_trans_aux[ub] = ub;
1917
1918 inverse_trans_aux[df] = df;
1919 inverse_trans_aux[dr] = dr;
1920 inverse_trans_aux[dl] = dl;
1921 inverse_trans_aux[db] = db;
1922
1923 inverse_trans_aux[rf] = lf;
1924 inverse_trans_aux[rd] = bl;
1925 inverse_trans_aux[rb] = rb;
1926 inverse_trans_aux[ru] = fr;
1927
1928 inverse_trans_aux[lf] = rf;
1929 inverse_trans_aux[ld] = br;
1930 inverse_trans_aux[lb] = lb;
1931 inverse_trans_aux[lu] = fl;
1932
1933 inverse_trans_aux[fu] = fu;
1934 inverse_trans_aux[fr] = ru;
1935 inverse_trans_aux[fd] = bu;
1936 inverse_trans_aux[fl] = lu;
1937
1938 inverse_trans_aux[bu] = fd;
1939 inverse_trans_aux[br] = ld;
1940 inverse_trans_aux[bd] = bd;
1941 inverse_trans_aux[bl] = rd;
1942
1943 inverse_trans_aux[uf_mirror] = uf_mirror;
1944 inverse_trans_aux[ur_mirror] = ur_mirror;
1945 inverse_trans_aux[ul_mirror] = ul_mirror;
1946 inverse_trans_aux[ub_mirror] = ub_mirror;
1947
1948 inverse_trans_aux[df_mirror] = df_mirror;
1949 inverse_trans_aux[dr_mirror] = dl_mirror;
1950 inverse_trans_aux[dl_mirror] = dr_mirror;
1951 inverse_trans_aux[db_mirror] = db_mirror;
1952
1953 inverse_trans_aux[rf_mirror] = rf_mirror;
1954 inverse_trans_aux[rd_mirror] = br_mirror;
1955 inverse_trans_aux[rb_mirror] = lb_mirror;
1956 inverse_trans_aux[ru_mirror] = fl_mirror;
1957
1958 inverse_trans_aux[lf_mirror] = lf_mirror;
1959 inverse_trans_aux[ld_mirror] = bl_mirror;
1960 inverse_trans_aux[lb_mirror] = rb_mirror;
1961 inverse_trans_aux[lu_mirror] = fr_mirror;
1962
1963 inverse_trans_aux[fu_mirror] = fu_mirror;
1964 inverse_trans_aux[fr_mirror] = lu_mirror;
1965 inverse_trans_aux[fd_mirror] = bu_mirror;
1966 inverse_trans_aux[fl_mirror] = ru_mirror;
1967
1968 inverse_trans_aux[bu_mirror] = fd_mirror;
1969 inverse_trans_aux[br_mirror] = rd_mirror;
1970 inverse_trans_aux[bd_mirror] = bd_mirror;
1971 inverse_trans_aux[bl_mirror] = ld_mirror;
1972}
1973
1974/*
1975 * There is certainly a bette way to do this, but for now I just use
1976 * a "graph coloring" algorithm to compute the left cosets, and I compose
1977 * with every possible cp to get the right cosets (it is possible that I am
1978 * mixing up left and right).
1979 *
1980 * For doing it better "Mathematically", we need 3 things:
1981 * - Checking that cp separates the orbits (UFR,UBL,DFL,DBR) and the other
1982 * This is easy and it is done in the commented function cphtr_cp().
1983 * - Check that there is no ep/cp parity
1984 * - Check that we are not in the "3c" case; this is the part I don't
1985 * know how to do.
1986 */
1987static void
1988init_cphtr_cosets()
1989{
1990 unsigned int i;
1991 int c = 0, d = 0;
1992
1993 for (i = 0; i < FACTORIAL8; i++) {
1994 cphtr_left_cosets[i] = -1;
1995 cphtr_right_cosets[i] = -1;
1996 }
1997
1998 /* First we compute left cosets with a bfs */
1999 for (i = 0; i < FACTORIAL8; i++)
2000 if (cphtr_left_cosets[i] == -1)
2001 init_cphtr_left_cosets_bfs(i, c++);
2002
2003 /* Then we compute right cosets using compose() */
2004 for (i = 0; i < FACTORIAL8; i++)
2005 if (cphtr_right_cosets[i] == -1)
2006 init_cphtr_right_cosets_color(i, d++);
2007}
2008
2009static void
2010init_cphtr_left_cosets_bfs(int i, int c)
2011{
2012 int j, jj, k, next[FACTORIAL8], next2[FACTORIAL8], n, n2;
2013 Move moves[6] = {U2, D2, R2, L2, F2, B2};
2014
2015 n = 1;
2016 next[0] = i;
2017 cphtr_left_cosets[i] = c;
2018
2019 while (n != 0) {
2020 for (j = 0, n2 = 0; j < n; j++) {
2021 for (k = 0; k < 6; k++) {
2022 jj = cp_mtable[moves[k]][next[j]];
2023 if (cphtr_left_cosets[jj] == -1) {
2024 cphtr_left_cosets[jj] = c;
2025 next2[n2++] = jj;
2026 }
2027 }
2028 }
2029
2030 for (j = 0; j < n2; j++)
2031 next[j] = next2[j];
2032 n = n2;
2033 }
2034}
2035
2036static void
2037init_cphtr_right_cosets_color(int i, int d)
2038{
2039 int cp;
2040 unsigned int j;
2041
2042 cphtr_right_rep[d] = i;
2043 for (j = 0; j < FACTORIAL8; j++) {
2044 if (cphtr_left_cosets[j] == 0) {
2045 /* TODO: use antindexer, it's nicer */
2046 cp = compose((Cube){.cp = i}, (Cube){.cp = j}).cp;
2047 cphtr_right_cosets[cp] = d;
2048 }
2049 }
2050}
2051
2052static void
2053init_environment()
2054{
2055 char *nissydata = getenv("NISSYDATA");
2056 char *localdata = getenv("XDG_DATA_HOME");
2057 char *home = getenv("HOME");
2058 bool read, write;
2059
2060 if (nissydata != NULL) {
2061 tabledir = malloc(strlen(nissydata) * sizeof(char) + 20);
2062 strcpy(tabledir, nissydata);
2063 } else if (localdata != NULL) {
2064 tabledir = malloc(strlen(localdata) * sizeof(char) + 20);
2065 strcpy(tabledir, localdata);
2066 strcat(tabledir, "/nissy");
2067 } else if (home != NULL) {
2068 tabledir = malloc(strlen(home) * sizeof(char) + 20);
2069 strcpy(tabledir, home);
2070 strcat(tabledir, "/.nissy");
2071 }
2072
2073 mkdir(tabledir, 0777);
2074 strcat(tabledir, "/tables");
2075 mkdir(tabledir, 0777);
2076
2077 read = !access(tabledir, R_OK);
2078 write = !access(tabledir, W_OK);
2079
2080 if (!read) {
2081 fprintf(stderr, "Table files cannot be read.\n");
2082 } else if (!write) {
2083 fprintf(stderr, "Data directory not writable: ");
2084 fprintf(stderr, "tables can be loaded, but not saved.\n");
2085 }
2086}
2087
2088static void
2089init_moves() {
2090 Cube c;
2091 CubeArray arrs;
2092 int i;
2093 unsigned int ui;
2094 Move m;
2095
2096 /* Generate all move cycles and flips; I do this regardless */
2097 for (i = 0; i < NMOVES; i++) {
2098 if (i == U || i == x || i == y)
2099 continue;
2100
2101 c = apply_alg_generic(equiv_alg[i], (Cube){0}, pf_all, false);
2102
2103 arrs = (CubeArray) {
2104 edge_cycle[i],
2105 eofb_flipped[i],
2106 eorl_flipped[i],
2107 eoud_flipped[i],
2108 corner_cycle[i],
2109 coud_flipped[i],
2110 corl_flipped[i],
2111 cofb_flipped[i],
2112 center_cycle[i]
2113 };
2114 cube_to_arrays(c, &arrs, pf_all);
2115 }
2116
2117 if (read_mtables_file())
2118 return;
2119
2120 fprintf(stderr, "Cannot load %s, generating it\n", "mtables");
2121
2122 /* Initialize transition tables */
2123 for (m = 0; m < NMOVES; m++) {
2124 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
2125 c = (Cube){ .epose = ui };
2126 c = apply_move_cubearray(m, c, pf_e);
2127 epose_mtable[m][ui] = c.epose;
2128
2129 c = (Cube){ .eposs = ui };
2130 c = apply_move_cubearray(m, c, pf_s);
2131 eposs_mtable[m][ui] = c.eposs;
2132
2133 c = (Cube){ .eposm = ui };
2134 c = apply_move_cubearray(m, c, pf_m);
2135 eposm_mtable[m][ui] = c.eposm;
2136 }
2137 for (ui = 0; ui < POW2TO11; ui++ ) {
2138 c = (Cube){ .eofb = ui };
2139 c = apply_move_cubearray(m, c, pf_eo);
2140 eofb_mtable[m][ui] = c.eofb;
2141
2142 c = (Cube){ .eorl = ui };
2143 c = apply_move_cubearray(m, c, pf_eo);
2144 eorl_mtable[m][ui] = c.eorl;
2145
2146 c = (Cube){ .eoud = ui };
2147 c = apply_move_cubearray(m, c, pf_eo);
2148 eoud_mtable[m][ui] = c.eoud;
2149 }
2150 for (ui = 0; ui < POW3TO7; ui++) {
2151 c = (Cube){ .coud = ui };
2152 c = apply_move_cubearray(m, c, pf_co);
2153 coud_mtable[m][ui] = c.coud;
2154
2155 c = (Cube){ .corl = ui };
2156 c = apply_move_cubearray(m, c, pf_co);
2157 corl_mtable[m][ui] = c.corl;
2158
2159 c = (Cube){ .cofb = ui };
2160 c = apply_move_cubearray(m, c, pf_co);
2161 cofb_mtable[m][ui] = c.cofb;
2162 }
2163 for (ui = 0; ui < FACTORIAL8; ui++) {
2164 c = (Cube){ .cp = ui };
2165 c = apply_move_cubearray(m, c, pf_cp);
2166 cp_mtable[m][ui] = c.cp;
2167 }
2168 for (ui = 0; ui < FACTORIAL6; ui++) {
2169 c = (Cube){ .cpos = ui };
2170 c = apply_move_cubearray(m, c, pf_cpos);
2171 cpos_mtable[m][ui] = c.cpos;
2172 }
2173 }
2174
2175 if (!write_mtables_file())
2176 fprintf(stderr, "Error writing mtables\n");
2177}
2178
2179static void
2180init_moves_aux()
2181{
2182 /* Some standard PieceFilters */
2183 pf_all.epose = true;
2184 pf_all.eposs = true;
2185 pf_all.eposm = true;
2186 pf_all.eofb = true;
2187 pf_all.eorl = true;
2188 pf_all.eoud = true;
2189 pf_all.cp = true;
2190 pf_all.cofb = true;
2191 pf_all.corl = true;
2192 pf_all.coud = true;
2193 pf_all.cpos = true;
2194
2195 pf_4val.epose = true;
2196 pf_4val.eposs = true;
2197 pf_4val.eposm = true;
2198 pf_4val.eofb = true;
2199 pf_4val.coud = true;
2200 pf_4val.cp = true;
2201
2202 pf_epcp.epose = true;
2203 pf_epcp.eposs = true;
2204 pf_epcp.eposm = true;
2205 pf_epcp.cp = true;
2206
2207 pf_cpos.cpos = true;
2208
2209 pf_cp.cp = true;
2210
2211 pf_ep.epose = true;
2212 pf_ep.eposs = true;
2213 pf_ep.eposm = true;
2214
2215 pf_e.epose = true;
2216 pf_s.eposs = true;
2217 pf_m.eposm = true;
2218
2219 pf_eo.eofb = true;
2220 pf_eo.eorl = true;
2221 pf_eo.eoud = true;
2222
2223 pf_co.cofb = true;
2224 pf_co.corl = true;
2225 pf_co.coud = true;
2226
2227 /* Used to convert to and from CubeArray */
2228 epe_solved[0] = FR;
2229 epe_solved[1] = FL;
2230 epe_solved[2] = BL;
2231 epe_solved[3] = BR;
2232
2233 eps_solved[0] = UL;
2234 eps_solved[1] = UR;
2235 eps_solved[2] = DL;
2236 eps_solved[3] = DR;
2237
2238 epm_solved[0] = UF;
2239 epm_solved[1] = UB;
2240 epm_solved[2] = DF;
2241 epm_solved[3] = DB;
2242
2243 /* Table sizes, used for reading and writing files */
2244 me[0] = FACTORIAL12/FACTORIAL8;
2245 me[1] = FACTORIAL12/FACTORIAL8;
2246 me[2] = FACTORIAL12/FACTORIAL8;
2247 me[3] = POW2TO11;
2248 me[4] = POW2TO11;
2249 me[5] = POW2TO11;
2250 me[6] = FACTORIAL8;
2251 me[7] = POW3TO7;
2252 me[8] = POW3TO7;
2253 me[9] = POW3TO7;
2254 me[10] = FACTORIAL6;
2255 me[11] = NMOVES;
2256
2257 /* Cycles *********************/
2258 edge_cycle[U][UF] = UR;
2259 edge_cycle[U][UL] = UF;
2260 edge_cycle[U][UB] = UL;
2261 edge_cycle[U][UR] = UB;
2262 edge_cycle[U][DF] = DF;
2263 edge_cycle[U][DL] = DL;
2264 edge_cycle[U][DB] = DB;
2265 edge_cycle[U][DR] = DR;
2266 edge_cycle[U][FR] = FR;
2267 edge_cycle[U][FL] = FL;
2268 edge_cycle[U][BL] = BL;
2269 edge_cycle[U][BR] = BR;
2270
2271 edge_cycle[x][UF] = DF;
2272 edge_cycle[x][UL] = FL;
2273 edge_cycle[x][UB] = UF;
2274 edge_cycle[x][UR] = FR;
2275 edge_cycle[x][DF] = DB;
2276 edge_cycle[x][DL] = BL;
2277 edge_cycle[x][DB] = UB;
2278 edge_cycle[x][DR] = BR;
2279 edge_cycle[x][FR] = DR;
2280 edge_cycle[x][FL] = DL;
2281 edge_cycle[x][BL] = UL;
2282 edge_cycle[x][BR] = UR;
2283
2284 edge_cycle[y][UF] = UR;
2285 edge_cycle[y][UL] = UF;
2286 edge_cycle[y][UB] = UL;
2287 edge_cycle[y][UR] = UB;
2288 edge_cycle[y][DF] = DR;
2289 edge_cycle[y][DL] = DF;
2290 edge_cycle[y][DB] = DL;
2291 edge_cycle[y][DR] = DB;
2292 edge_cycle[y][FR] = BR;
2293 edge_cycle[y][FL] = FR;
2294 edge_cycle[y][BL] = FL;
2295 edge_cycle[y][BR] = BL;
2296
2297 corner_cycle[U][UFR] = UBR;
2298 corner_cycle[U][UFL] = UFR;
2299 corner_cycle[U][UBL] = UFL;
2300 corner_cycle[U][UBR] = UBL;
2301 corner_cycle[U][DFR] = DFR;
2302 corner_cycle[U][DFL] = DFL;
2303 corner_cycle[U][DBL] = DBL;
2304 corner_cycle[U][DBR] = DBR;
2305
2306 corner_cycle[x][UFR] = DFR;
2307 corner_cycle[x][UFL] = DFL;
2308 corner_cycle[x][UBL] = UFL;
2309 corner_cycle[x][UBR] = UFR;
2310 corner_cycle[x][DFR] = DBR;
2311 corner_cycle[x][DFL] = DBL;
2312 corner_cycle[x][DBL] = UBL;
2313 corner_cycle[x][DBR] = UBR;
2314
2315 corner_cycle[y][UFR] = UBR;
2316 corner_cycle[y][UFL] = UFR;
2317 corner_cycle[y][UBL] = UFL;
2318 corner_cycle[y][UBR] = UBL;
2319 corner_cycle[y][DFR] = DBR;
2320 corner_cycle[y][DFL] = DFR;
2321 corner_cycle[y][DBL] = DFL;
2322 corner_cycle[y][DBR] = DBL;
2323
2324 center_cycle[U][U_center] = U_center;
2325 center_cycle[U][D_center] = D_center;
2326 center_cycle[U][R_center] = R_center;
2327 center_cycle[U][L_center] = L_center;
2328 center_cycle[U][F_center] = F_center;
2329 center_cycle[U][B_center] = B_center;
2330
2331 center_cycle[x][U_center] = F_center;
2332 center_cycle[x][D_center] = B_center;
2333 center_cycle[x][R_center] = R_center;
2334 center_cycle[x][L_center] = L_center;
2335 center_cycle[x][F_center] = D_center;
2336 center_cycle[x][B_center] = U_center;
2337
2338 center_cycle[y][U_center] = U_center;
2339 center_cycle[y][D_center] = D_center;
2340 center_cycle[y][R_center] = B_center;
2341 center_cycle[y][L_center] = F_center;
2342 center_cycle[y][F_center] = R_center;
2343 center_cycle[y][B_center] = L_center;
2344
2345 /* Flipped pieces *************/
2346 eofb_flipped[x][UF] = 1;
2347 eofb_flipped[x][UB] = 1;
2348 eofb_flipped[x][DF] = 1;
2349 eofb_flipped[x][DB] = 1;
2350
2351 eofb_flipped[y][FR] = 1;
2352 eofb_flipped[y][FL] = 1;
2353 eofb_flipped[y][BL] = 1;
2354 eofb_flipped[y][BR] = 1;
2355
2356 eorl_flipped[x][UF] = 1;
2357 eorl_flipped[x][UL] = 1;
2358 eorl_flipped[x][UB] = 1;
2359 eorl_flipped[x][UR] = 1;
2360 eorl_flipped[x][DF] = 1;
2361 eorl_flipped[x][DL] = 1;
2362 eorl_flipped[x][DB] = 1;
2363 eorl_flipped[x][DR] = 1;
2364 eorl_flipped[x][FR] = 1;
2365 eorl_flipped[x][FL] = 1;
2366 eorl_flipped[x][BL] = 1;
2367 eorl_flipped[x][BR] = 1;
2368
2369 eorl_flipped[y][FR] = 1;
2370 eorl_flipped[y][FL] = 1;
2371 eorl_flipped[y][BL] = 1;
2372 eorl_flipped[y][BR] = 1;
2373
2374 eoud_flipped[U][UF] = 1;
2375 eoud_flipped[U][UL] = 1;
2376 eoud_flipped[U][UB] = 1;
2377 eoud_flipped[U][UR] = 1;
2378
2379 eoud_flipped[x][UF] = 1;
2380 eoud_flipped[x][UB] = 1;
2381 eoud_flipped[x][DF] = 1;
2382 eoud_flipped[x][DB] = 1;
2383
2384 eoud_flipped[y][UF] = 1;
2385 eoud_flipped[y][UL] = 1;
2386 eoud_flipped[y][UB] = 1;
2387 eoud_flipped[y][UR] = 1;
2388 eoud_flipped[y][DF] = 1;
2389 eoud_flipped[y][DL] = 1;
2390 eoud_flipped[y][DB] = 1;
2391 eoud_flipped[y][DR] = 1;
2392 eoud_flipped[y][FR] = 1;
2393 eoud_flipped[y][FL] = 1;
2394 eoud_flipped[y][BL] = 1;
2395 eoud_flipped[y][BR] = 1;
2396
2397 coud_flipped[x][UFR] = 2;
2398 coud_flipped[x][UFL] = 1;
2399 coud_flipped[x][UBR] = 1;
2400 coud_flipped[x][UBL] = 2;
2401 coud_flipped[x][DFR] = 1;
2402 coud_flipped[x][DFL] = 2;
2403 coud_flipped[x][DBR] = 2;
2404 coud_flipped[x][DBL] = 1;
2405
2406 corl_flipped[U][UFR] = 1;
2407 corl_flipped[U][UFL] = 2;
2408 corl_flipped[U][UBL] = 1;
2409 corl_flipped[U][UBR] = 2;
2410
2411 corl_flipped[y][UFR] = 1;
2412 corl_flipped[y][UFL] = 2;
2413 corl_flipped[y][UBL] = 1;
2414 corl_flipped[y][UBR] = 2;
2415 corl_flipped[y][DFR] = 2;
2416 corl_flipped[y][DFL] = 1;
2417 corl_flipped[y][DBL] = 2;
2418 corl_flipped[y][DBR] = 1;
2419
2420 cofb_flipped[U][UFR] = 2;
2421 cofb_flipped[U][UFL] = 1;
2422 cofb_flipped[U][UBL] = 2;
2423 cofb_flipped[U][UBR] = 1;
2424
2425 cofb_flipped[x][UFR] = 1;
2426 cofb_flipped[x][UFL] = 2;
2427 cofb_flipped[x][UBL] = 1;
2428 cofb_flipped[x][UBR] = 2;
2429 cofb_flipped[x][DFR] = 2;
2430 cofb_flipped[x][DFL] = 1;
2431 cofb_flipped[x][DBL] = 2;
2432 cofb_flipped[x][DBR] = 1;
2433
2434 cofb_flipped[y][UFR] = 2;
2435 cofb_flipped[y][UFL] = 1;
2436 cofb_flipped[y][UBL] = 2;
2437 cofb_flipped[y][UBR] = 1;
2438 cofb_flipped[y][DFR] = 1;
2439 cofb_flipped[y][DFL] = 2;
2440 cofb_flipped[y][DBL] = 1;
2441 cofb_flipped[y][DBR] = 2;
2442
2443 /* Equivalent moves ***********/
2444 equiv_alg[NULLMOVE] = new_alg("");
2445
2446 equiv_alg[U] = new_alg(" U ");
2447 equiv_alg[U2] = new_alg(" UU ");
2448 equiv_alg[U3] = new_alg(" UUU ");
2449 equiv_alg[D] = new_alg(" xx U xx ");
2450 equiv_alg[D2] = new_alg(" xx UU xx ");
2451 equiv_alg[D3] = new_alg(" xx UUU xx ");
2452 equiv_alg[R] = new_alg(" yx U xxxyyy ");
2453 equiv_alg[R2] = new_alg(" yx UU xxxyyy ");
2454 equiv_alg[R3] = new_alg(" yx UUU xxxyyy ");
2455 equiv_alg[L] = new_alg(" yyyx U xxxy ");
2456 equiv_alg[L2] = new_alg(" yyyx UU xxxy ");
2457 equiv_alg[L3] = new_alg(" yyyx UUU xxxy ");
2458 equiv_alg[F] = new_alg(" x U xxx ");
2459 equiv_alg[F2] = new_alg(" x UU xxx ");
2460 equiv_alg[F3] = new_alg(" x UUU xxx ");
2461 equiv_alg[B] = new_alg(" xxx U x ");
2462 equiv_alg[B2] = new_alg(" xxx UU x ");
2463 equiv_alg[B3] = new_alg(" xxx UUU x ");
2464
2465 equiv_alg[Uw] = new_alg(" xx U xx y ");
2466 equiv_alg[Uw2] = new_alg(" xx UU xx yy ");
2467 equiv_alg[Uw3] = new_alg(" xx UUU xx yyy ");
2468 equiv_alg[Dw] = new_alg(" U yyy ");
2469 equiv_alg[Dw2] = new_alg(" UU yy ");
2470 equiv_alg[Dw3] = new_alg(" UUU y ");
2471 equiv_alg[Rw] = new_alg(" yyyx U xxxy x ");
2472 equiv_alg[Rw2] = new_alg(" yyyx UU xxxy xx ");
2473 equiv_alg[Rw3] = new_alg(" yyyx UUU xxxy xxx ");
2474 equiv_alg[Lw] = new_alg(" yx U xxxyyy xxx ");
2475 equiv_alg[Lw2] = new_alg(" yx UU xxxyyy xx ");
2476 equiv_alg[Lw3] = new_alg(" yx UUU xxxyyy x ");
2477 equiv_alg[Fw] = new_alg(" xxx U x yxxxyyy ");
2478 equiv_alg[Fw2] = new_alg(" xxx UU x yxxyyy ");
2479 equiv_alg[Fw3] = new_alg(" xxx UUU x yxyyy ");
2480 equiv_alg[Bw] = new_alg(" x U xxx yxyyy ");
2481 equiv_alg[Bw2] = new_alg(" x UU xxx yxxyyy ");
2482 equiv_alg[Bw3] = new_alg(" x UUU xxx yxxxyyy ");
2483
2484 equiv_alg[M] = new_alg(" yx U xx UUU yxyyy ");
2485 equiv_alg[M2] = new_alg(" yx UU xx UU xxxy ");
2486 equiv_alg[M3] = new_alg(" yx UUU xx U yxxxy ");
2487 equiv_alg[S] = new_alg(" x UUU xx U yyyx ");
2488 equiv_alg[S2] = new_alg(" x UU xx UU yyx ");
2489 equiv_alg[S3] = new_alg(" x U xx UUU yx ");
2490 equiv_alg[E] = new_alg(" U xx UUU xxyyy ");
2491 equiv_alg[E2] = new_alg(" UU xx UU xxyy ");
2492 equiv_alg[E3] = new_alg(" UUU xx U xxy ");
2493
2494 equiv_alg[x] = new_alg(" x ");
2495 equiv_alg[x2] = new_alg(" xx ");
2496 equiv_alg[x3] = new_alg(" xxx ");
2497 equiv_alg[y] = new_alg(" y ");
2498 equiv_alg[y2] = new_alg(" yy ");
2499 equiv_alg[y3] = new_alg(" yyy ");
2500 equiv_alg[z] = new_alg(" yyy x y ");
2501 equiv_alg[z2] = new_alg(" yy xx ");
2502 equiv_alg[z3] = new_alg(" y x yyy ");
2503}
2504
2505static void
2506init_strings()
2507{
2508 strcpy(move_string [NULLMOVE], "-" );
2509 strcpy(move_string [U], "U" );
2510 strcpy(move_string [U2], "U2" );
2511 strcpy(move_string [U3], "U\'" );
2512 strcpy(move_string [D], "D" );
2513 strcpy(move_string [D2], "D2" );
2514 strcpy(move_string [D3], "D\'" );
2515 strcpy(move_string [R], "R" );
2516 strcpy(move_string [R2], "R2" );
2517 strcpy(move_string [R3], "R\'" );
2518 strcpy(move_string [L], "L" );
2519 strcpy(move_string [L2], "L2" );
2520 strcpy(move_string [L3], "L\'" );
2521 strcpy(move_string [F], "F" );
2522 strcpy(move_string [F2], "F2" );
2523 strcpy(move_string [F3], "F\'" );
2524 strcpy(move_string [B], "B" );
2525 strcpy(move_string [B2], "B2" );
2526 strcpy(move_string [B3], "B\'" );
2527 strcpy(move_string [Uw], "Uw" );
2528 strcpy(move_string [Uw2], "Uw2" );
2529 strcpy(move_string [Uw3], "Uw\'" );
2530 strcpy(move_string [Dw], "Dw" );
2531 strcpy(move_string [Dw2], "Dw2" );
2532 strcpy(move_string [Dw3], "Dw\'" );
2533 strcpy(move_string [Rw], "Rw" );
2534 strcpy(move_string [Rw2], "Rw2" );
2535 strcpy(move_string [Rw3], "Rw\'" );
2536 strcpy(move_string [Lw], "Lw" );
2537 strcpy(move_string [Lw2], "Lw2" );
2538 strcpy(move_string [Lw3], "Lw\'" );
2539 strcpy(move_string [Fw], "Fw" );
2540 strcpy(move_string [Fw2], "Fw2" );
2541 strcpy(move_string [Fw3], "Fw\'" );
2542 strcpy(move_string [Bw], "Bw" );
2543 strcpy(move_string [Bw2], "Bw2" );
2544 strcpy(move_string [Bw3], "Bw\'" );
2545 strcpy(move_string [M], "M" );
2546 strcpy(move_string [M2], "M2" );
2547 strcpy(move_string [M3], "M\'" );
2548 strcpy(move_string [S], "S" );
2549 strcpy(move_string [S2], "S2" );
2550 strcpy(move_string [S3], "S\'" );
2551 strcpy(move_string [E], "E" );
2552 strcpy(move_string [E2], "E2" );
2553 strcpy(move_string [E3], "E\'" );
2554 strcpy(move_string [x], "x" );
2555 strcpy(move_string [x2], "x2" );
2556 strcpy(move_string [x3], "x\'" );
2557 strcpy(move_string [y], "y" );
2558 strcpy(move_string [y2], "y2" );
2559 strcpy(move_string [y3], "y\'" );
2560 strcpy(move_string [z], "z" );
2561 strcpy(move_string [z2], "z2" );
2562 strcpy(move_string [z3], "z\'" );
2563
2564 strcpy(edge_string [UF], "UF" );
2565 strcpy(edge_string [UL], "UL" );
2566 strcpy(edge_string [UB], "UB" );
2567 strcpy(edge_string [UR], "UR" );
2568 strcpy(edge_string [DF], "DF" );
2569 strcpy(edge_string [DL], "DL" );
2570 strcpy(edge_string [DB], "DB" );
2571 strcpy(edge_string [DR], "DR" );
2572 strcpy(edge_string [FR], "FR" );
2573 strcpy(edge_string [FL], "FL" );
2574 strcpy(edge_string [BL], "BL" );
2575 strcpy(edge_string [BR], "BR" );
2576
2577 strcpy(corner_string [UFR], "UFR" );
2578 strcpy(corner_string [UFL], "UFL" );
2579 strcpy(corner_string [UBL], "UBL" );
2580 strcpy(corner_string [UBR], "UBR" );
2581 strcpy(corner_string [DFR], "DFR" );
2582 strcpy(corner_string [DFL], "DFL" );
2583 strcpy(corner_string [DBL], "DBL" );
2584 strcpy(corner_string [DBR], "DBR" );
2585
2586 strcpy(center_string [U_center], "U" );
2587 strcpy(center_string [D_center], "D" );
2588 strcpy(center_string [R_center], "R" );
2589 strcpy(center_string [L_center], "L" );
2590 strcpy(center_string [F_center], "F" );
2591 strcpy(center_string [B_center], "B" );
2592}
2593
2594static void
2595init_symdata()
2596{
2597 int i;
2598
2599 for (i = 0; i < n_all_symdata; i++)
2600 gensym(all_sd[i]);
2601}
2602
2603static void
2604init_trans() {
2605 Cube aux, cube, mirr, c[3];
2606 CubeArray epcp;
2607 int i, eparr[12], eoarr[12], cparr[8], coarr[8];
2608 unsigned int ui;
2609 Move mi, move;
2610 Trans m;
2611
2612 /* Compute sources */
2613 for (i = 0; i < NTRANS; i++) {
2614 cube = apply_alg(rotation_algs[i % NROTATIONS], (Cube){0});
2615
2616 epose_source[i] = edge_slice(what_edge_at(cube, FR));
2617 eposs_source[i] = edge_slice(what_edge_at(cube, UR));
2618 eposm_source[i] = edge_slice(what_edge_at(cube, UF));
2619 eofb_source[i] = what_center_at(cube, F_center)/2;
2620 eorl_source[i] = what_center_at(cube, R_center)/2;
2621 eoud_source[i] = what_center_at(cube, U_center)/2;
2622 coud_source[i] = what_center_at(cube, U_center)/2;
2623 cofb_source[i] = what_center_at(cube, F_center)/2;
2624 corl_source[i] = what_center_at(cube, R_center)/2;
2625 }
2626
2627 if (read_ttables_file())
2628 return;
2629
2630 fprintf(stderr, "Cannot load %s, generating it\n", "ttables");
2631
2632 /* Initialize tables */
2633 for (m = 0; m < NTRANS; m++) {
2634 epcp = (CubeArray){ .ep = eparr, .cp = cparr };
2635 cube = apply_alg(rotation_algs[m % NROTATIONS], (Cube){0});
2636 cube_to_arrays(cube, &epcp, pf_epcp);
2637 if (m >= NROTATIONS) {
2638 apply_permutation(ep_mirror, eparr, 12);
2639 apply_permutation(cp_mirror, cparr, 8);
2640 }
2641
2642 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
2643 c[0] = admissible_ep((Cube){ .epose = ui }, pf_e);
2644 c[1] = admissible_ep((Cube){ .eposs = ui }, pf_s);
2645 c[2] = admissible_ep((Cube){ .eposm = ui }, pf_m);
2646
2647 cube = rotate_via_compose(m,c[epose_source[m]],pf_ep);
2648 epose_ttable[m][ui] = cube.epose;
2649
2650 cube = rotate_via_compose(m,c[eposs_source[m]],pf_ep);
2651 eposs_ttable[m][ui] = cube.eposs;
2652
2653 cube = rotate_via_compose(m,c[eposm_source[m]],pf_ep);
2654 eposm_ttable[m][ui] = cube.eposm;
2655 }
2656 for (ui = 0; ui < POW2TO11; ui++ ) {
2657 int_to_sum_zero_array(ui, 2, 12, eoarr);
2658 apply_permutation(eparr, eoarr, 12);
2659 eo_ttable[m][ui] = digit_array_to_int(eoarr, 11, 2);
2660 }
2661 for (ui = 0; ui < POW3TO7; ui++) {
2662 int_to_sum_zero_array(ui, 3, 8, coarr);
2663 apply_permutation(cparr, coarr, 8);
2664 co_ttable[m][ui] = digit_array_to_int(coarr, 7, 3);
2665 if (m >= NROTATIONS)
2666 co_ttable[m][ui] =
2667 invert_digits(co_ttable[m][ui], 3, 7);
2668 }
2669 for (ui = 0; ui < FACTORIAL8; ui++) {
2670 cube = (Cube){ .cp = ui };
2671 cube = rotate_via_compose(m, cube, pf_cp);
2672 cp_ttable[m][ui] = cube.cp;
2673 }
2674 for (ui = 0; ui < FACTORIAL6; ui++) {
2675 cube = (Cube){ .cpos = ui };
2676 cube = rotate_via_compose(m, cube, pf_cpos);
2677 cpos_ttable[m][ui] = cube.cpos;
2678 }
2679 for (mi = 0; mi < NMOVES; mi++) {
2680 aux = apply_trans(m, apply_move(mi, (Cube){0}));
2681 for (move = 0; move < NMOVES; move++) {
2682 cube = apply_move(inverse_move_aux[move], aux);
2683 mirr = apply_trans(uf_mirror, cube);
2684 if (is_solved(cube, false) ||
2685 is_solved(mirr, false))
2686 moves_ttable[m][mi] = move;
2687 }
2688 }
2689 }
2690
2691 if (!write_ttables_file())
2692 fprintf(stderr, "Error writing ttables\n");
2693}
2694
2695static void
2696init_trans_aux()
2697{
2698 ep_mirror[UF] = UF;
2699 ep_mirror[UL] = UR;
2700 ep_mirror[UB] = UB;
2701 ep_mirror[UR] = UL;
2702 ep_mirror[DF] = DF;
2703 ep_mirror[DL] = DR;
2704 ep_mirror[DB] = DB;
2705 ep_mirror[DR] = DL;
2706 ep_mirror[FR] = FL;
2707 ep_mirror[FL] = FR;
2708 ep_mirror[BR] = BL;
2709 ep_mirror[BL] = BR;
2710
2711 cp_mirror[UFR] = UFL;
2712 cp_mirror[UFL] = UFR;
2713 cp_mirror[UBL] = UBR;
2714 cp_mirror[UBR] = UBL;
2715 cp_mirror[DFR] = DFL;
2716 cp_mirror[DFL] = DFR;
2717 cp_mirror[DBL] = DBR;
2718 cp_mirror[DBR] = DBL;
2719
2720 cpos_mirror[U_center] = U_center;
2721 cpos_mirror[D_center] = D_center;
2722 cpos_mirror[R_center] = L_center;
2723 cpos_mirror[L_center] = R_center;
2724 cpos_mirror[F_center] = F_center;
2725 cpos_mirror[B_center] = B_center;
2726
2727 /* Is there a more elegant way? */
2728 rotation_algs[uf] = new_alg("");
2729 rotation_algs[ur] = new_alg("y");
2730 rotation_algs[ub] = new_alg("y2");
2731 rotation_algs[ul] = new_alg("y3");
2732
2733 rotation_algs[df] = new_alg("z2");
2734 rotation_algs[dr] = new_alg("y z2");
2735 rotation_algs[db] = new_alg("x2");
2736 rotation_algs[dl] = new_alg("y3 z2");
2737
2738 rotation_algs[rf] = new_alg("z3");
2739 rotation_algs[rd] = new_alg("z3 y");
2740 rotation_algs[rb] = new_alg("z3 y2");
2741 rotation_algs[ru] = new_alg("z3 y3");
2742
2743 rotation_algs[lf] = new_alg("z");
2744 rotation_algs[ld] = new_alg("z y3");
2745 rotation_algs[lb] = new_alg("z y2");
2746 rotation_algs[lu] = new_alg("z y");
2747
2748 rotation_algs[fu] = new_alg("x y2");
2749 rotation_algs[fr] = new_alg("x y");
2750 rotation_algs[fd] = new_alg("x");
2751 rotation_algs[fl] = new_alg("x y3");
2752
2753 rotation_algs[bu] = new_alg("x3");
2754 rotation_algs[br] = new_alg("x3 y");
2755 rotation_algs[bd] = new_alg("x3 y2");
2756 rotation_algs[bl] = new_alg("x3 y3");
2757}
2758
2759
2760/* Public functions implementation *******************************************/
2761
2762Cube
2763apply_alg(Alg *alg, Cube cube)
2764{
2765 return apply_alg_generic(alg, cube, pf_all, true);
2766}
2767
2768Cube
2769apply_move(Move m, Cube cube)
2770{
2771 return (Cube) {
2772 .epose = epose_mtable[m][cube.epose],
2773 .eposs = eposs_mtable[m][cube.eposs],
2774 .eposm = eposm_mtable[m][cube.eposm],
2775 .eofb = eofb_mtable[m][cube.eofb],
2776 .eorl = eorl_mtable[m][cube.eorl],
2777 .eoud = eoud_mtable[m][cube.eoud],
2778 .coud = coud_mtable[m][cube.coud],
2779 .cofb = cofb_mtable[m][cube.cofb],
2780 .corl = corl_mtable[m][cube.corl],
2781 .cp = cp_mtable[m][cube.cp],
2782 .cpos = cpos_mtable[m][cube.cpos]
2783 };
2784}
2785
2786
2787Cube
2788apply_trans(Trans t, Cube cube)
2789{
2790 int aux_epos[3] = { cube.epose, cube.eposs, cube.eposm };
2791 int aux_eo[3] = { cube.eoud, cube.eorl, cube.eofb };
2792 int aux_co[3] = { cube.coud, cube.corl, cube.cofb };
2793
2794 return (Cube) {
2795 .epose = epose_ttable[t][aux_epos[epose_source[t]]],
2796 .eposs = eposs_ttable[t][aux_epos[eposs_source[t]]],
2797 .eposm = eposm_ttable[t][aux_epos[eposm_source[t]]],
2798 .eofb = eo_ttable[t][aux_eo[eofb_source[t]]],
2799 .eorl = eo_ttable[t][aux_eo[eorl_source[t]]],
2800 .eoud = eo_ttable[t][aux_eo[eoud_source[t]]],
2801 .coud = co_ttable[t][aux_co[coud_source[t]]],
2802 .corl = co_ttable[t][aux_co[corl_source[t]]],
2803 .cofb = co_ttable[t][aux_co[cofb_source[t]]],
2804 .cp = cp_ttable[t][cube.cp],
2805 .cpos = cpos_ttable[t][cube.cpos]
2806 };
2807}
2808
2809Move
2810base_move(Move m)
2811{
2812 if (m == NULLMOVE)
2813 return NULLMOVE;
2814 else
2815 return m - (m-1)%3;
2816}
2817
2818Cube
2819compose(Cube c2, Cube c1)
2820{
2821 return compose_filtered(c2, c1, pf_all);
2822}
2823
2824/*TODO maybe move the next two */
2825uint64_t
2826cphtr(Cube cube)
2827{
2828 return cphtr_right_cosets[cube.cp];
2829}
2830
2831Cube
2832anti_cphtr(uint64_t ind)
2833{
2834 return (Cube) { .cp = cphtr_right_rep[ind] };
2835}
2836
2837uint64_t
2838epos_dependent(Cube c)
2839{
2840 return epos_dependent_aux[c.eposs/FACTORIAL4][c.epose/FACTORIAL4];
2841}
2842
2843bool
2844equal(Cube c1, Cube c2)
2845{
2846 return c1.eofb == c2.eofb &&
2847 c1.epose == c2.epose &&
2848 c1.eposs == c2.eposs &&
2849 c1.eposm == c2.eposm &&
2850 c1.coud == c2.coud &&
2851 c1.cp == c2.cp &&
2852 c1.cpos == c2.cpos;
2853}
2854
2855void
2856genptable(PruneData *pd)
2857{
2858 Cube cube;
2859 uint64_t j, oldn = 0;
2860 DfsData dd = {
2861 .m = 0,
2862 .last1 = NULLMOVE,
2863 .last2 = NULLMOVE
2864 };
2865
2866 if (pd->generated)
2867 return;
2868
2869 /* TODO: check if memory is enough, otherwise maybe crash gracefully? */
2870 pd->ptable = malloc(ptablesize(pd) * sizeof(uint8_t));
2871
2872 if (read_ptable_file(pd)) {
2873 pd->generated = true;
2874 return;
2875 }
2876
2877 fprintf(stderr, "Cannot load %s, generating it\n", pd->filename);
2878
2879 /* We use 4 bits per value, so any distance >= 15 is set to 15 */
2880 for (j = 0; j < pd->coord->max; j++)
2881 ptable_update(pd, pd->coord->cube(j), 15);
2882
2883 moveset_to_list(pd->moveset, NULL, dd.sorted_moves);
2884 movelist_to_position(dd.sorted_moves, dd.move_position);
2885
2886 pd->reached = malloc(ptablesize(pd) * sizeof(uint8_t));
2887 for (dd.d = 0, pd->n = 0; dd.d < 15 && pd->n < pd->coord->max; dd.d++) {
2888 memset(pd->reached, 0, ptablesize(pd)*sizeof(uint8_t));
2889 for (j = 0; j < pd->coord->max; j++) {
2890 cube = pd->coord->cube(j);
2891 if (pd->coord->check(cube))
2892 genptable_dfs(cube, pd, &dd);
2893 }
2894 fprintf(stderr, "Depth %d done, generated %lu\t(%lu/%lu)\n",
2895 dd.d, pd->n-oldn, pd->n, pd->coord->max);
2896 oldn = pd->n;
2897 }
2898
2899 if (!write_ptable_file(pd))
2900 fprintf(stderr, "Error writing ptable file\n");
2901
2902 pd->generated = true;
2903 free(pd->reached);
2904}
2905
2906Cube
2907inverse_cube(Cube cube)
2908{
2909 CubeArray *arr = new_cubearray(cube, pf_all);
2910 CubeArray *inv = new_cubearray((Cube){0}, pf_all);
2911 Cube ret;
2912 int i;
2913
2914 for (i = 0; i < 12; i++) {
2915 inv->ep[arr->ep[i]] = i;
2916 inv->eofb[arr->ep[i]] = arr->eofb[i];
2917 inv->eorl[arr->ep[i]] = arr->eorl[i];
2918 inv->eoud[arr->ep[i]] = arr->eoud[i];
2919 }
2920
2921 for (i = 0; i < 8; i++) {
2922 inv->cp[arr->cp[i]] = i;
2923 inv->coud[arr->cp[i]] = (3 - arr->coud[i]) % 3;
2924 inv->corl[arr->cp[i]] = (3 - arr->corl[i]) % 3;
2925 inv->cofb[arr->cp[i]] = (3 - arr->cofb[i]) % 3;
2926 }
2927
2928 for (int i = 0; i < 6; i++)
2929 inv->cpos[arr->cpos[i]] = i;
2930
2931 ret = arrays_to_cube(inv, pf_all);
2932 free_cubearray(arr, pf_all);
2933 free_cubearray(inv, pf_all);
2934
2935 return ret;
2936}
2937
2938Move
2939inverse_move(Move m)
2940{
2941 return inverse_move_aux[m];
2942}
2943
2944Trans
2945inverse_trans(Trans t)
2946{
2947 return inverse_trans_aux[t];
2948}
2949
2950bool
2951is_admissible(Cube cube)
2952{
2953 /* TODO: this should check consistency of different orientations */
2954 /* TODO: check that centers are opposite and admissible */
2955
2956 CubeArray *a = new_cubearray(cube, pf_all);
2957 int parity;
2958 bool perm;
2959
2960 perm = is_perm(a->ep, 12) &&
2961 is_perm(a->cp, 8) &&
2962 is_perm(a->cpos, 6);
2963 parity = perm_sign(a->ep, 12) +
2964 perm_sign(a->cp, 8) +
2965 perm_sign(a->cpos, 6);
2966
2967 return perm && parity % 2 == 0;
2968}
2969
2970bool
2971is_solved(Cube cube, bool reorient)
2972{
2973 int i;
2974
2975 if (reorient) {
2976 for (i = 0; i < NROTATIONS; i++)
2977 if (is_solved(apply_alg(rotation_algs[i], cube),false))
2978 return true;
2979 return false;
2980 } else {
2981 return equal(cube, (Cube){0});
2982 }
2983}
2984
2985bool
2986is_solved_block(Cube cube, Block block)
2987{
2988 int i;
2989
2990 for (i = 0; i < 12; i++)
2991 if (block.edge[i] && !is_solved_edge(cube, i))
2992 return false;
2993 for (i = 0; i < 8; i++)
2994 if (block.corner[i] && !is_solved_corner(cube, i))
2995 return false;
2996 for (i = 0; i < 6; i++)
2997 if (block.center[i] && !is_solved_center(cube, i))
2998 return false;
2999
3000 return true;
3001}
3002
3003bool
3004is_solved_center(Cube cube, Center c)
3005{
3006 return what_center_at(cube, c) == c;
3007}
3008
3009bool
3010is_solved_corner(Cube cube, Corner c)
3011{
3012 return what_corner_at(cube, c) == c &&
3013 what_orientation_corner(cube.coud, c);
3014}
3015
3016bool
3017is_solved_edge(Cube cube, Edge e)
3018{
3019 return what_edge_at(cube, e) == e &&
3020 what_orientation_edge(cube.eofb, e);
3021}
3022
3023int
3024piece_orientation(Cube cube, int piece, char *orientation)
3025{
3026 int arr[12], n, b, x;
3027
3028 if (!strcmp(orientation, "eofb")) {
3029 x = cube.eofb;
3030 n = 12;
3031 b = 2;
3032 } else if (!strcmp(orientation, "eorl")) {
3033 x = cube.eorl;
3034 n = 12;
3035 b = 2;
3036 } else if (!strcmp(orientation, "eoud")) {
3037 x = cube.eoud;
3038 n = 12;
3039 b = 2;
3040 } else if (!strcmp(orientation, "coud")) {
3041 x = cube.coud;
3042 n = 8;
3043 b = 3;
3044 } else if (!strcmp(orientation, "corl")) {
3045 x = cube.corl;
3046 n = 8;
3047 b = 3;
3048 } else if (!strcmp(orientation, "cofb")) {
3049 x = cube.cofb;
3050 n = 8;
3051 b = 3;
3052 } else {
3053 return -1;
3054 }
3055
3056 int_to_sum_zero_array(x, b, n, arr);
3057 if (piece < n)
3058 return arr[piece];
3059
3060 return -1;
3061}
3062
3063void
3064print_cube(Cube cube)
3065{
3066/*
3067 CubeArray *arr = new_cubearray(cube, pf_all);
3068
3069 for (int i = 0; i < 12; i++)
3070 printf(" %s ", edge_string[arr->ep[i]]);
3071 printf("\n");
3072
3073 for (int i = 0; i < 12; i++)
3074 printf(" %c ", arr->eofb[i] + '0');
3075 printf("\n");
3076
3077 for (int i = 0; i < 8; i++)
3078 printf("%s ", corner_string[arr->cp[i]]);
3079 printf("\n");
3080
3081 for (int i = 0; i < 8; i++)
3082 printf(" %c ", arr->coud[i] + '0');
3083 printf("\n");
3084
3085 for (int i = 0; i < 6; i++)
3086 printf(" %s ", center_string[arr->cpos[i]]);
3087 printf("\n");
3088
3089 free_cubearray(arr, pf_all);
3090*/
3091
3092 for (int i = 0; i < 12; i++)
3093 printf(" %s ", edge_string[what_edge_at(cube, i)]);
3094 printf("\n");
3095
3096 for (int i = 0; i < 12; i++)
3097 printf(" %d ", what_orientation_edge(cube.eofb, i));
3098 printf("\n");
3099
3100 for (int i = 0; i < 8; i++)
3101 printf("%s ", corner_string[what_corner_at(cube, i)]);
3102 printf("\n");
3103
3104 for (int i = 0; i < 8; i++)
3105 printf(" %d ", what_orientation_corner(cube.coud, i));
3106 printf("\n");
3107
3108 for (int i = 0; i < 6; i++)
3109 printf(" %s ", center_string[what_center_at(cube, i)]);
3110 printf("\n");
3111
3112}
3113
3114Cube
3115random_cube()
3116{
3117 CubeArray *arr = new_cubearray((Cube){0}, pf_4val);
3118 Cube ret;
3119 int ep, cp, eo, co;
3120
3121 ep = rand() % FACTORIAL12;
3122 cp = rand() % FACTORIAL8;
3123 eo = rand() % POW2TO11;
3124 co = rand() % POW3TO7;
3125
3126 index_to_perm(ep, 12, arr->ep);
3127 index_to_perm(cp, 8, arr->cp);
3128 int_to_sum_zero_array(eo, 2, 12, arr->eofb);
3129 int_to_sum_zero_array(co, 3, 8, arr->coud);
3130
3131 if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8))
3132 swap(&(arr->ep[0]), &(arr->ep[1]));
3133
3134 ret = arrays_to_cube(arr, pf_4val);
3135 free_cubearray(arr, pf_4val);
3136
3137 return ret;
3138}
3139
3140/* TODO: clean pre_trans or put it back */
3141AlgList *
3142solve(Cube cube, Step step, SolveOptions *opts)
3143{
3144 /*AlgListNode *node;*/
3145 AlgList *sols = new_alglist();
3146 /*Cube c = apply_trans(opts->pre_trans, cube);*/
3147 DfsData dd = {
3148 .m = 0,
3149 .niss = false,
3150 .lb = -1,
3151 .last1 = NULLMOVE,
3152 .last2 = NULLMOVE,
3153 .sols = sols,
3154 .current_alg = new_alg("")
3155 };
3156
3157 if (step.ready != NULL && !step.ready(cube)) {
3158 fprintf(stderr, "Cube not ready for solving step\n");
3159 return sols;
3160 }
3161
3162 moveset_to_list(step.moveset, step.estimate, dd.sorted_moves);
3163 movelist_to_position(dd.sorted_moves, dd.move_position);
3164
3165 for (dd.d = opts->min_moves;
3166 dd.d <= opts->max_moves && !(sols->len && opts->optimal_only);
3167 dd.d++) {
3168 if (opts->feedback)
3169 fprintf(stderr,
3170 "Found %d solutions, searching depth %d...\n",
3171 sols->len, dd.d);
3172 dfs(cube, step, opts, &dd);
3173 }
3174
3175/*
3176 for (node = sols->first; node != NULL; node = node->next)
3177 transform_alg(inverse_trans(opts->pre_trans), node->alg);
3178*/
3179
3180 free_alg(dd.current_alg);
3181 return sols;
3182}
3183
3184Alg *
3185inverse_alg(Alg *alg)
3186{
3187 Alg *ret = new_alg("");
3188 int i;
3189
3190 for (i = alg->len-1; i >= 0; i--)
3191 append_move(ret, inverse_move(alg->move[i]), alg->inv[i]);
3192
3193 return ret;
3194}
3195
3196Alg *
3197new_alg(char *str)
3198{
3199 Alg *alg = malloc(sizeof(Alg));
3200 int i;
3201 bool niss = false;
3202 Move j, m;
3203
3204 alg->move = malloc(30 * sizeof(Move));
3205 alg->inv = malloc(30 * sizeof(bool));
3206 alg->allocated = 30;
3207 alg->len = 0;
3208
3209 for (i = 0; str[i]; i++) {
3210 if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n')
3211 continue;
3212
3213 if (str[i] == '(' && niss) {
3214 fprintf(stderr, "Error reading moves: nested ( )\n");
3215 return alg;
3216 }
3217
3218 if (str[i] == ')' && !niss) {
3219 fprintf(stderr, "Error reading moves: unmatched )\n");
3220 return alg;
3221 }
3222
3223 if (str[i] == '(' || str[i] == ')') {
3224 niss = !niss;
3225 continue;
3226 }
3227
3228 for (j = 0; j < NMOVES; j++) {
3229 if (str[i] == move_string[j][0]) {
3230 m = j;
3231 if (m <= B && str[i+1]=='w') {
3232 m += Uw - U;
3233 i++;
3234 }
3235 if (str[i+1]=='2') {
3236 m += 1;
3237 i++;
3238 } else if (str[i+1]=='\'' || str[i+1]=='3') {
3239 m += 2;
3240 i++;
3241 }
3242 append_move(alg, m, niss);
3243 break;
3244 }
3245 }
3246 }
3247
3248 return alg;
3249}
3250
3251Alg *
3252on_inverse(Alg *alg)
3253{
3254 Alg *ret = new_alg("");
3255 int i;
3256
3257 for (i = 0; i < alg->len; i++)
3258 append_move(ret, alg->move[i], !alg->inv[i]);
3259
3260 return ret;
3261}
3262
3263void
3264print_alg(Alg *alg, bool l)
3265{
3266 /* TODO: make it possible to print to stdout or to string */
3267 /* Maybe just return a string */
3268 char fill[4];
3269 int i;
3270 bool niss = false;
3271
3272 for (i = 0; i < alg->len; i++) {
3273 if (!niss && alg->inv[i])
3274 strcpy(fill, i == 0 ? "(" : " (");
3275 if (niss && !alg->inv[i])
3276 strcpy(fill, ") ");
3277 if (niss == alg->inv[i])
3278 strcpy(fill, i == 0 ? "" : " ");
3279
3280 printf("%s%s", fill, move_string[alg->move[i]]);
3281 niss = alg->inv[i];
3282 }
3283
3284 if (niss)
3285 printf(")");
3286 if (l)
3287 printf(" (%d)", alg->len);
3288
3289 printf("\n");
3290}
3291
3292void
3293print_alglist(AlgList *al, bool l)
3294{
3295 AlgListNode *i;
3296
3297 for (i = al->first; i != NULL; i = i->next)
3298 print_alg(i->alg, l);
3299}
3300
3301void
3302print_ptable(PruneData *pd)
3303{
3304 uint64_t i, a[16];
3305
3306 for (i = 0; i < 16; i++)
3307 a[i] = 0;
3308
3309 if (!pd->generated)
3310 genptable(pd);
3311
3312 for (i = 0; i < pd->coord->max; i++)
3313 a[ptableval(pd, pd->coord->cube(i))]++;
3314
3315 fprintf(stderr, "Values for table %s\n", pd->filename);
3316 for (i = 0; i < 16; i++)
3317 printf("%2lu\t%10lu\n", i, a[i]);
3318}
3319
3320uint64_t
3321ptablesize(PruneData *pd)
3322{
3323 return (pd->coord->max + 1) / 2;
3324}
3325
3326int
3327ptableval(PruneData *pd, Cube cube)
3328{
3329 uint64_t ind = pd->coord->index(cube);
3330
3331 return (ind % 2) ? pd->ptable[ind/2] / 16 : pd->ptable[ind/2] % 16;
3332}
3333
3334
3335Alg *
3336rotation_alg(Trans i)
3337{
3338 return rotation_algs[i % NROTATIONS];
3339}
3340
3341void
3342transform_alg(Trans t, Alg *alg)
3343{
3344 int i;
3345
3346 for (i = 0; i < alg->len; i++)
3347 alg->move[i] = moves_ttable[t][alg->move[i]];
3348}
3349
3350Center
3351what_center_at(Cube cube, Center c)
3352{
3353 return what_center_at_aux[cube.cpos][c];
3354}
3355
3356Corner
3357what_corner_at(Cube cube, Corner c)
3358{
3359 return what_corner_at_aux[cube.cp][c];
3360}
3361
3362Edge
3363what_edge_at(Cube cube, Edge e)
3364{
3365 Edge ret;
3366 CubeArray *arr = new_cubearray(cube, pf_ep);
3367
3368 ret = arr->ep[e];
3369
3370 free_cubearray(arr, pf_ep);
3371 return ret;
3372}
3373
3374int
3375what_orientation_corner(int co, Corner c)
3376{
3377 if (c < 7)
3378 return (co / powint(3, c)) % 3;
3379 else
3380 return what_orientation_last_corner_aux[co];
3381}
3382
3383int
3384what_orientation_edge(int eo, Edge e)
3385{
3386 if (e < 11)
3387 return (eo & (1 << e)) ? 1 : 0;
3388 else
3389 return what_orientation_last_edge_aux[eo];
3390}
3391
3392Center
3393where_is_center(Cube cube, Center c)
3394{
3395 return where_is_center_aux[cube.cpos][c];
3396}
3397
3398Corner
3399where_is_corner(Cube cube, Corner c)
3400{
3401 return where_is_corner_aux[cube.cp][c];
3402}
3403
3404
3405void
3406init()
3407{
3408 /* Order is important! */
3409 init_environment();
3410 init_strings();
3411 init_moves_aux();
3412 init_moves();
3413 init_auxtables();
3414 init_cphtr_cosets();
3415 init_trans_aux();
3416 init_trans();
3417 init_symdata();
3418}
3419
diff --git a/old/2021-06-30-reached/cube.h b/old/2021-06-30-reached/cube.h
new file mode 100644
index 0000000..ffbcd86
--- /dev/null
+++ b/old/2021-06-30-reached/cube.h
@@ -0,0 +1,90 @@
1#ifndef CUBE_H
2#define CUBE_H
3
4#include <stdio.h>
5#include <stdbool.h>
6#include <stdint.h>
7#include <stdlib.h>
8#include <string.h>
9#include <time.h>
10#include <unistd.h>
11#include <sys/stat.h>
12
13#include "macros.h"
14#include "cubetypes.h"
15
16extern Coordinate coord_eofb;
17extern Coordinate coord_eofbepos;
18extern Coordinate coord_coud;
19extern Coordinate coord_corners;
20extern Coordinate coord_cornershtr;
21extern Coordinate coord_drud;
22extern Coordinate coord_coud_sym16;
23extern Coordinate coord_eofbepos_sym16;
24extern Coordinate coord_drud_sym16;
25extern Coordinate coord_khuge;
26
27Cube apply_alg(Alg *alg, Cube cube);
28Cube apply_move(Move m, Cube cube);
29Cube apply_trans(Trans t, Cube cube);
30bool block_solved(Cube cube, Block);
31Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */
32uint64_t cphtr(Cube cube); /* TODO: rename (something with cosets) */
33Cube anti_cphtr(uint64_t ind); /*TODO also this */
34uint64_t epos_dependent(Cube cube); /* TODO: rename and turn into an indexer */
35bool equal(Cube c1, Cube c2);
36Cube inverse_cube(Cube cube);
37Move inverse_move(Move m);
38Trans inverse_trans(Trans t);
39bool is_admissible(Cube cube);
40bool is_solved(Cube cube, bool reorient);
41bool is_solved_center(Cube cube, Center c);
42bool is_solved_corner(Cube cube, Corner c);
43bool is_solved_edge(Cube cube, Edge e);
44void print_cube(Cube cube);
45Cube random_cube();
46AlgList * solve(Cube cube, Step step, SolveOptions *opts);
47Center what_center_at(Cube cube, Center c);
48Corner what_corner_at(Cube cube, Corner c);
49Edge what_edge_at(Cube cube, Edge e);
50int what_orientation_corner(int co, Corner c);
51int what_orientation_edge(int eo, Edge e);
52Center where_is_center(Cube cube, Center c);
53Corner where_is_corner(Cube cube, Corner c);
54Edge where_is_edge(Cube cube, Edge e);
55
56bool check_centers(Cube cube);
57bool check_corners(Cube cube);
58bool check_cornershtr(Cube cube);
59bool check_coud(Cube cube);
60bool check_drud(Cube cube);
61bool check_eofb(Cube cube);
62bool check_eofbepos(Cube cube);
63bool check_epose(Cube cube);
64bool check_ep(Cube cube);
65bool check_khuge(Cube cube);
66bool check_nothing(Cube cube);
67
68bool moveset_HTM(Move m);
69bool moveset_URF(Move m);
70
71Move base_move(Move m);
72void free_alg(Alg *alg);
73void free_alglist(AlgList *l);
74Alg * inverse_alg(Alg *alg);
75Alg * new_alg(char *str);
76Alg * on_inverse(Alg *alg);
77void print_alg(Alg *alg, bool l);
78void print_alglist(AlgList *al, bool l);
79Alg * rotation_alg(Trans i);
80void transform_alg(Trans t, Alg *alg);
81
82void genptable(PruneData *pd);
83void print_ptable(PruneData *pd);
84uint64_t ptablesize(PruneData *pd);
85int ptableval(PruneData *pd, Cube cube);
86
87void init();
88
89#endif
90
diff --git a/old/2021-06-30-reached/cubetypes.h b/old/2021-06-30-reached/cubetypes.h
new file mode 100644
index 0000000..0a7961d
--- /dev/null
+++ b/old/2021-06-30-reached/cubetypes.h
@@ -0,0 +1,251 @@
1#ifndef CUBETYPES_H
2#define CUBETYPES_H
3
4/* Typedefs ******************************************************************/
5
6typedef enum center Center;
7typedef enum corner Corner;
8typedef enum edge Edge;
9typedef enum move Move;
10typedef enum trans Trans;
11
12typedef struct alg Alg;
13typedef struct alglist AlgList;
14typedef struct alglistnode AlgListNode;
15typedef struct block Block;
16typedef struct coordinate Coordinate;
17typedef struct cube Cube;
18typedef struct cubearray CubeArray;
19typedef struct cubetarget CubeTarget;
20typedef struct dfsdata DfsData;
21typedef struct piecefilter PieceFilter;
22typedef struct prunedata PruneData;
23typedef struct solveoptions SolveOptions;
24typedef struct step Step;
25typedef struct symdata SymData;
26
27typedef Cube (*AntiIndexer) (uint64_t);
28typedef bool (*Checker) (Cube);
29typedef int (*Estimator) (CubeTarget);
30typedef uint64_t (*Indexer) (Cube);
31typedef bool (*Moveset) (Move);
32
33
34/* Enums *********************************************************************/
35
36enum
37center
38{
39 U_center, D_center,
40 R_center, L_center,
41 F_center, B_center
42};
43
44enum
45corner
46{
47 UFR, UFL, UBL, UBR,
48 DFR, DFL, DBL, DBR
49};
50
51enum
52edge
53{
54 UF, UL, UB, UR,
55 DF, DL, DB, DR,
56 FR, FL, BL, BR
57};
58
59enum
60move
61{
62 NULLMOVE,
63 U, U2, U3, D, D2, D3,
64 R, R2, R3, L, L2, L3,
65 F, F2, F3, B, B2, B3,
66 Uw, Uw2, Uw3, Dw, Dw2, Dw3,
67 Rw, Rw2, Rw3, Lw, Lw2, Lw3,
68 Fw, Fw2, Fw3, Bw, Bw2, Bw3,
69 M, M2, M3,
70 S, S2, S3,
71 E, E2, E3,
72 x, x2, x3,
73 y, y2, y3,
74 z, z2, z3,
75};
76
77enum
78trans
79{
80 uf, ur, ub, ul,
81 df, dr, db, dl,
82 rf, rd, rb, ru,
83 lf, ld, lb, lu,
84 fu, fr, fd, fl,
85 bu, br, bd, bl,
86 uf_mirror, ur_mirror, ub_mirror, ul_mirror,
87 df_mirror, dr_mirror, db_mirror, dl_mirror,
88 rf_mirror, rd_mirror, rb_mirror, ru_mirror,
89 lf_mirror, ld_mirror, lb_mirror, lu_mirror,
90 fu_mirror, fr_mirror, fd_mirror, fl_mirror,
91 bu_mirror, br_mirror, bd_mirror, bl_mirror,
92};
93
94
95/* Structs *******************************************************************/
96
97struct
98alg
99{
100 Move * move;
101 bool * inv;
102 int len;
103 int allocated;
104};
105
106struct
107alglist
108{
109 AlgListNode * first;
110 AlgListNode * last;
111 int len;
112};
113
114struct
115alglistnode
116{
117 Alg * alg;
118 AlgListNode * next;
119};
120
121struct
122block
123{
124 bool edge[12];
125 bool corner[8];
126 bool center[6];
127};
128
129struct
130coordinate
131{
132 Indexer index;
133 AntiIndexer cube;
134 Checker check;
135 uint64_t max;
136};
137
138struct
139cube
140{
141 int epose;
142 int eposs;
143 int eposm;
144 int eofb;
145 int eorl;
146 int eoud;
147 int cp;
148 int coud;
149 int cofb;
150 int corl;
151 int cpos;
152};
153
154struct
155cubearray
156{
157 int * ep;
158 int * eofb;
159 int * eorl;
160 int * eoud;
161 int * cp;
162 int * coud;
163 int * corl;
164 int * cofb;
165 int * cpos;
166};
167
168struct
169cubetarget
170{
171 Cube cube;
172 int target;
173};
174
175struct
176dfsdata
177{
178 int d;
179 int m;
180 int lb;
181 bool niss;
182 Move last1;
183 Move last2;
184 AlgList * sols;
185 Alg * current_alg;
186 Move sorted_moves[NMOVES];
187 int move_position[NMOVES];
188};
189
190struct
191piecefilter
192{
193 bool epose;
194 bool eposs;
195 bool eposm;
196 bool eofb;
197 bool eorl;
198 bool eoud;
199 bool cp;
200 bool coud;
201 bool cofb;
202 bool corl;
203 bool cpos;
204};
205
206struct
207prunedata
208{
209 char * filename;
210 uint8_t * ptable;
211 uint8_t * reached;
212 bool generated;
213 uint64_t n;
214 Coordinate * coord;
215 Moveset moveset;
216};
217
218struct
219solveoptions
220{
221 int min_moves;
222 int max_moves;
223 int max_solutions;
224 bool optimal_only;
225 bool can_niss;
226 bool feedback;
227};
228
229struct
230step
231{
232 Estimator estimate;
233 Checker ready;
234 Moveset moveset;
235};
236
237struct
238symdata
239{
240 char * filename;
241 bool generated;
242 Coordinate * coord;
243 Coordinate * sym_coord;
244 int ntrans;
245 Trans * trans;
246 uint64_t * class;
247 Cube * rep;
248 Trans * transtorep;
249};
250
251#endif
diff --git a/old/2021-06-30-reached/macros.h b/old/2021-06-30-reached/macros.h
new file mode 100644
index 0000000..af3bca1
--- /dev/null
+++ b/old/2021-06-30-reached/macros.h
@@ -0,0 +1,23 @@
1#ifndef MACROS_H
2#define MACROS_H
3
4#define POW2TO6 64ULL
5#define POW2TO11 2048ULL
6#define POW2TO12 4096ULL
7#define POW3TO7 2187ULL
8#define POW3TO8 6561ULL
9#define FACTORIAL4 24ULL
10#define FACTORIAL6 720ULL
11#define FACTORIAL7 5040ULL
12#define FACTORIAL8 40320ULL
13#define FACTORIAL12 479001600ULL
14#define BINOM12ON4 495ULL
15#define BINOM8ON4 70ULL
16#define MIN(a,b) (((a) < (b)) ? (a) : (b))
17#define MAX(a,b) (((a) > (b)) ? (a) : (b))
18
19#define NMOVES (z3+1)
20#define NTRANS 48
21#define NROTATIONS 24
22
23#endif
diff --git a/old/2021-06-30-reached/main.c b/old/2021-06-30-reached/main.c
new file mode 100644
index 0000000..1ebd917
--- /dev/null
+++ b/old/2021-06-30-reached/main.c
@@ -0,0 +1,80 @@
1#include <stdio.h>
2#include "cube.h"
3#include "steps.h"
4
5int main() {
6 Alg *algo;
7 AlgList *sols;
8 Cube cube;
9 SolveOptions opts;
10 char line[1000];
11 int i, ns = 2;
12/* Move m;*/
13/* int nrand = 10000, sum1, sum2, sum3;*/
14
15 Step *stps[20] = {&drud_HTM, &optimal_HTM};
16 char sss[30][30] = {"DR on UD", "Optimal solve"};
17
18 opts = (SolveOptions) {
19 .min_moves = 0,
20 .max_moves = 20,
21 .optimal_only = true,
22 .max_solutions = 1,
23 .can_niss = false,
24 .feedback = true,
25 };
26
27 init();
28
29/*
30 srand(time(NULL));
31 sum1 = 0;
32 sum2 = 0;
33 sum3 = 0;
34 for (i = 0; i < nrand; i++) {
35 cube = random_cube();
36 sum1 += drud_HTM.check(cube, 20);
37 sum2 += optimal_HTM.check(cube, 20);
38 sum3 += cornershtreofb_HTM.check(cube, 20);
39 }
40 printf("Average drud pruning: %lf\n", ((double)sum1) / ((double) nrand));
41 printf("Average corners htr pruning: %lf\n", ((double)sum2) / ((double) nrand));
42 printf("Average corners htr + eofb pruning: %lf\n", ((double)sum3) / ((double) nrand));
43*/
44
45/*
46 for (m = U; m <= B3; m++) {
47 printf("Class eofbepos after %d: ", m);
48 printf("%lu\n", coord_khuge.index(apply_move(m,(Cube){0})));
49 }
50*/
51
52 printf("Welcome to nissy 2.0! Insert a scramble:\n");
53
54 if (fgets(line, 1000, stdin) != NULL) {
55 algo = new_alg(line);
56 cube = apply_alg(algo, (Cube){0});
57
58 print_alg(inverse_alg(algo), false);
59/*
60 printf("After rb_mirror:\n");
61 cube = apply_trans(rb_mirror, cube);
62 print_cube(cube);
63 printf("Going back:\n");
64 cube = apply_trans(inverse_trans(rb_mirror), cube);
65*/
66
67 print_cube(cube);
68
69 for (i = 0; i < ns; i++) {
70 sols = solve(cube, *stps[i], &opts);
71 printf("%s: %d solutions found:\n", sss[i], sols->len);
72 print_alglist(sols, true);
73 free_alglist(sols);
74 }
75 free_alg(algo);
76 }
77
78 return 0;
79}
80
diff --git a/old/2021-06-30-reached/steps.c b/old/2021-06-30-reached/steps.c
new file mode 100644
index 0000000..bc833cb
--- /dev/null
+++ b/old/2021-06-30-reached/steps.c
@@ -0,0 +1,307 @@
1#include "steps.h"
2
3/* Standard checkers (return lower bound) ************************************/
4
5static int estimate_eofb_HTM(CubeTarget ct);
6static int estimate_coud_HTM(CubeTarget ct);
7static int estimate_coud_URF(CubeTarget ct);
8static int estimate_corners_HTM(CubeTarget ct);
9static int estimate_cornershtr_HTM(CubeTarget ct);
10static int estimate_corners_URF(CubeTarget ct);
11static int estimate_cornershtr_URF(CubeTarget ct);
12static int estimate_drud_HTM(CubeTarget ct);
13static int estimate_optimal_HTM(CubeTarget ct);
14
15/* Steps *********************************************************************/
16
17Step
18eofb_HTM = {
19 .estimate = estimate_eofb_HTM,
20 .ready = check_centers,
21 .moveset = moveset_HTM
22};
23
24Step
25coud_HTM = {
26 .estimate = estimate_coud_HTM,
27 .ready = check_centers,
28 .moveset = moveset_HTM
29};
30
31Step
32coud_URF = {
33 .estimate = estimate_coud_URF,
34 .ready = check_nothing,
35 .moveset = moveset_URF
36};
37
38Step
39corners_HTM = {
40 .estimate = estimate_corners_HTM,
41 .ready = check_centers,
42 .moveset = moveset_HTM
43};
44
45Step
46cornershtr_HTM = {
47 .estimate = estimate_cornershtr_HTM,
48 .ready = check_centers,
49 .moveset = moveset_HTM
50};
51
52Step
53cornershtr_URF = {
54 .estimate = estimate_cornershtr_URF,
55 .ready = check_nothing,
56 .moveset = moveset_URF
57};
58
59Step
60corners_URF = {
61 .estimate = estimate_corners_URF,
62 .ready = check_nothing,
63 .moveset = moveset_URF
64};
65
66Step
67drud_HTM = {
68 .estimate = estimate_drud_HTM,
69 .ready = check_centers,
70 .moveset = moveset_HTM
71};
72
73Step
74optimal_HTM = {
75 .estimate = estimate_optimal_HTM,
76 .ready = check_centers,
77 .moveset = moveset_HTM
78};
79
80
81/* Pruning tables ************************************************************/
82
83PruneData
84pd_eofb_HTM = {
85 .filename = "ptable_eofb_HTM",
86 .coord = &coord_eofb,
87 .moveset = moveset_HTM
88};
89
90PruneData
91pd_coud_HTM = {
92 .filename = "ptable_coud_HTM",
93 .coord = &coord_coud,
94 .moveset = moveset_HTM
95};
96
97PruneData
98pd_cornershtr_HTM = {
99 .filename = "ptable_cornershtr_withcosets_HTM",
100 .coord = &coord_cornershtr,
101 .moveset = moveset_HTM
102};
103
104PruneData
105pd_corners_HTM = {
106 .filename = "ptable_corners_HTM",
107 .coord = &coord_corners,
108 .moveset = moveset_HTM
109};
110
111PruneData
112pd_drud_HTM = {
113 .filename = "ptable_drud_HTM",
114 .coord = &coord_drud,
115 .moveset = moveset_HTM
116};
117
118PruneData
119pd_drud_sym16_HTM = {
120 .filename = "pd_drud_sym16_HTM",
121 .coord = &coord_drud_sym16,
122 .moveset = moveset_HTM,
123};
124
125PruneData
126pd_khuge_HTM = {
127 .filename = "pd_khuge_HTM",
128 .coord = &coord_khuge,
129 .moveset = moveset_HTM
130};
131
132
133/* Standard checkers (return lower bound) ************************************/
134
135static int
136estimate_eofb_HTM(CubeTarget ct)
137{
138 if (!pd_eofb_HTM.generated)
139 genptable(&pd_eofb_HTM);
140
141 return ptableval(&pd_eofb_HTM, ct.cube);
142}
143
144static int
145estimate_coud_HTM(CubeTarget ct)
146{
147 if (!pd_coud_HTM.generated)
148 genptable(&pd_coud_HTM);
149
150 return ptableval(&pd_coud_HTM, ct.cube);
151}
152
153static int
154estimate_coud_URF(CubeTarget ct)
155{
156 /* TODO: I can improve this by checking first the orientation of
157 * the corner in DBL and use that as a reference */
158
159 CubeTarget ct2 = {.cube = apply_move(z, ct.cube), .target = ct.target};
160 CubeTarget ct3 = {.cube = apply_move(x, ct.cube), .target = ct.target};
161
162 int ud = estimate_coud_HTM(ct);
163 int rl = estimate_coud_HTM(ct2);
164 int fb = estimate_coud_HTM(ct3);
165
166 return MIN(ud, MIN(rl, fb));
167}
168
169static int
170estimate_corners_HTM(CubeTarget ct)
171{
172 if (!pd_corners_HTM.generated)
173 genptable(&pd_corners_HTM);
174
175 return ptableval(&pd_corners_HTM, ct.cube);
176}
177
178static int
179estimate_cornershtr_HTM(CubeTarget ct)
180{
181 if (!pd_cornershtr_HTM.generated)
182 genptable(&pd_cornershtr_HTM);
183
184 return ptableval(&pd_cornershtr_HTM, ct.cube);
185}
186
187static int
188estimate_cornershtr_URF(CubeTarget ct)
189{
190 /* TODO: I can improve this by checking first the corner in DBL
191 * and use that as a reference */
192
193 int c, ret = 15;
194 Trans i;
195
196 for (i = 0; i < NROTATIONS; i++) {
197 ct.cube = apply_alg(rotation_alg(i), ct.cube);
198 c = estimate_cornershtr_HTM(ct);
199 ret = MIN(ret, c);
200 }
201
202 return ret;
203}
204
205static int
206estimate_corners_URF(CubeTarget ct)
207{
208 /* TODO: I can improve this by checking first the corner in DBL
209 * and use that as a reference */
210
211 int c, ret = 15;
212 Trans i;
213
214 for (i = 0; i < NROTATIONS; i++) {
215 ct.cube = apply_alg(rotation_alg(i), ct.cube);
216 c = estimate_corners_HTM(ct);
217 ret = MIN(ret, c);
218 }
219
220 return ret;
221}
222
223static int
224estimate_drud_HTM(CubeTarget ct)
225{
226/*
227 if (!pd_drud_HTM.generated)
228 genptable(&pd_drud_HTM);
229
230 return ptableval(&pd_drud_HTM, ct.cube);
231*/
232
233 if (!pd_drud_sym16_HTM.generated)
234 genptable(&pd_drud_sym16_HTM);
235
236 return ptableval(&pd_drud_sym16_HTM, ct.cube);
237}
238
239/* TODO: if lucky, remove this */
240/*
241static int
242estimate_optimal_HTM(CubeTarget ct)
243{
244 static Trans t1 = { .rot = rf, .mirror = false };
245 static Trans t2 = { .rot = bd, .mirror = false };
246 int dr1, dr2, dr3, cor, ret;
247 Cube cube = ct.cube;
248
249 dr1 = estimate_drud_HTM(ct);
250 cor = estimate_corners_HTM(ct);
251 ret = MAX(dr1, cor);
252
253 if (ret > ct.target)
254 return ret;
255
256 ct.cube = apply_trans(t1, cube);
257 dr2 = estimate_drud_HTM(ct);
258 ret = MAX(ret, dr2);
259
260 if (ret > ct.target)
261 return ret;
262
263 ct.cube = apply_trans(t2, cube);
264 dr3 = estimate_drud_HTM(ct);
265
266 if (dr1 == dr2 && dr2 == dr3 && dr1 != 0)
267 dr3++;
268
269 ret = MAX(ret, dr3);
270
271 if (ret == 0)
272 return check_ep(cube) ? 0 : 6;
273
274 return ret;
275}
276*/
277
278static int
279estimate_optimal_HTM(CubeTarget ct)
280{
281 static Trans t2 = rf, t3 = bd;
282
283 int dr1, dr2, dr3, cor, ret;
284 Cube cube = ct.cube;
285
286 if (!pd_khuge_HTM.generated)
287 genptable(&pd_khuge_HTM);
288
289 dr1 = ptableval(&pd_khuge_HTM, cube);
290 cor = estimate_corners_HTM(ct);
291 ret = MAX(dr1, cor);
292
293 if (ret > ct.target)
294 return ret;
295
296 cube = apply_trans(t2, ct.cube);
297 dr2 = ptableval(&pd_khuge_HTM, cube);
298 ret = MAX(ret, dr2);
299
300 if (ret > ct.target)
301 return ret;
302
303 cube = apply_trans(t3, ct.cube);
304 dr3 = ptableval(&pd_khuge_HTM, cube);
305
306 return MAX(ret, dr3);
307}
diff --git a/old/2021-06-30-reached/steps.h b/old/2021-06-30-reached/steps.h
new file mode 100644
index 0000000..81ae11c
--- /dev/null
+++ b/old/2021-06-30-reached/steps.h
@@ -0,0 +1,24 @@
1#ifndef STEPS_H
2#define STEPS_H
3
4#include "cube.h"
5
6extern Step eofb_HTM;
7extern Step coud_HTM;
8extern Step coud_URF;
9extern Step corners_HTM;
10extern Step cornershtr_HTM;
11extern Step corners_URF;
12extern Step cornershtr_URF;
13extern Step drud_HTM;
14extern Step optimal_HTM;
15
16extern PruneData pd_eofb_HTM;
17extern PruneData pd_coud_HTM;
18extern PruneData pd_corners_HTM;
19extern PruneData pd_cornershtr_HTM;
20extern PruneData pd_cornershtreofb_HTM;
21extern PruneData pd_drud_HTM;
22extern PruneData pd_khuge_HTM;
23
24#endif
diff --git a/old/2021-07-02-genptable-dfs/cube.c b/old/2021-07-02-genptable-dfs/cube.c
new file mode 100644
index 0000000..a7d137c
--- /dev/null
+++ b/old/2021-07-02-genptable-dfs/cube.c
@@ -0,0 +1,3394 @@
1#include "cube.h"
2
3/* Local functions **********************************************************/
4
5static Cube admissible_ep(Cube cube, PieceFilter f);
6static Cube admissible_eos_from_eofbepos(Cube cube);
7static bool allowed_next(Move move, DfsData *dd);
8static void append_alg(AlgList *l, Alg *alg);
9static void append_move(Alg *alg, Move m, bool inverse);
10static Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a);
11static void apply_permutation(int *perm, int *set, int n);
12static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f);
13static int array_ep_to_epos(int *ep, int *eps_solved);
14static Cube arrays_to_cube(CubeArray *arr, PieceFilter f);
15static int binomial(int n, int k);
16static Cube compose_filtered(Cube c2, Cube c1, PieceFilter f);
17static void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f);
18static void dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd);
19static void dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd);
20static bool dfs_check_solved(SolveOptions *opts, DfsData *dd);
21static void dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd);
22static bool dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd);
23static int digit_array_to_int(int *a, int n, int b);
24static int edge_slice(Edge e); /* E=0, S=1, M=2 */
25static int epos_dependent_pos(int pos1, int pos2);
26static int epos_from_arrays(int *epos, int *ep);
27static void epos_to_partial_ep(int epos, int *ep, int *ss);
28static int factorial(int n);
29static void free_alglistnode(AlgListNode *aln);
30static void free_cubearray(CubeArray *arr, PieceFilter f);
31static void genptable_dfs(Cube c, PruneData *pd, DfsData *dd);
32static void genptable_dfs_branch(Cube c, PruneData *pd, DfsData *dd);
33static void gensym(SymData *sd);
34static void index_to_perm(int p, int n, int *r);
35static void index_to_subset(int s, int n, int k, int *r);
36static void init_auxtables();
37static void init_cphtr_cosets();
38static void init_cphtr_left_cosets_bfs(int i, int c);
39static void init_cphtr_right_cosets_color(int i, int c);
40static void init_environment();
41static void init_moves();
42static void init_moves_aux();
43static void init_strings();
44static void init_symdata();
45static void init_trans();
46static void init_trans_aux();
47static void int_to_digit_array(int a, int b, int n, int *r);
48static void int_to_sum_zero_array(int x, int b, int n, int *a);
49static int invert_digits(int a, int b, int n);
50static bool is_perm(int *a, int n);
51static bool is_subset(int *a, int n, int k);
52static Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf);
53static void movelist_to_position(Move *movelist, int *position);
54static void moveset_to_list(Moveset ms, Estimator f, Move *r);
55static AlgList * new_alglist();
56static CubeArray * new_cubearray(Cube cube, PieceFilter f);
57static int perm_sign(int *a, int n);
58static int perm_to_index(int *a, int n);
59static int powint(int a, int b);
60static void ptable_update(PruneData *pd, Cube cube, int m);
61static void realloc_alg(Alg *alg, int n);
62static bool read_mtables_file();
63static bool read_ptable_file(PruneData *pd);
64static bool read_symdata_file(SymData *sd);
65static bool read_ttables_file();
66static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f);
67static int subset_to_index(int *a, int n, int k);
68static void sum_arrays_mod(int *src, int *dst, int n, int m);
69static void swap(int *a, int *b);
70static bool write_mtables_file();
71static bool write_ptable_file(PruneData *pd);
72static bool write_symdata_file(SymData *sd);
73static bool write_ttables_file();
74
75
76/* All sorts of useful costants and tables **********************************/
77
78static char * tabledir;
79
80static PieceFilter pf_all;
81static PieceFilter pf_4val;
82static PieceFilter pf_epcp;
83static PieceFilter pf_cpos;
84static PieceFilter pf_cp;
85static PieceFilter pf_ep;
86static PieceFilter pf_e;
87static PieceFilter pf_s;
88static PieceFilter pf_m;
89static PieceFilter pf_eo;
90static PieceFilter pf_co;
91
92static int epe_solved[4];
93static int eps_solved[4];
94static int epm_solved[4];
95
96static char move_string[NMOVES][7];
97static char edge_string[12][7];
98static char corner_string[8][7];
99static char center_string[6][7];
100
101static Cube admissible_ee_aux[POW2TO11*BINOM12ON4];
102static bool commute[NMOVES][NMOVES];
103static bool possible_next[NMOVES][NMOVES][NMOVES];
104static Move inverse_move_aux[NMOVES];
105static Trans inverse_trans_aux[NTRANS];
106static int epos_dependent_aux[BINOM12ON4][BINOM12ON4];
107static int cphtr_left_cosets[FACTORIAL8];
108static int cphtr_right_cosets[FACTORIAL8];
109static int cphtr_right_rep[BINOM8ON4*6];
110static Center what_center_at_aux[FACTORIAL6][6];
111static Corner what_corner_at_aux[FACTORIAL8][8];
112static int what_orientation_last_corner_aux[POW3TO7];
113static int what_orientation_last_edge_aux[POW2TO11];
114static Center where_is_center_aux[FACTORIAL6][6];
115static Corner where_is_corner_aux[FACTORIAL8][8];
116static Edge where_is_edge_aux[3][FACTORIAL12/FACTORIAL8][12];
117
118static int epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
119static int eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
120static int eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
121static int eo_ttable[NTRANS][POW2TO11];
122static int cp_ttable[NTRANS][FACTORIAL8];
123static int co_ttable[NTRANS][POW3TO7];
124static int cpos_ttable[NTRANS][FACTORIAL6];
125static Move moves_ttable[NTRANS][NMOVES];
126
127static int epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
128static int eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
129static int eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
130static int eofb_mtable[NMOVES][POW2TO11];
131static int eorl_mtable[NMOVES][POW2TO11];
132static int eoud_mtable[NMOVES][POW2TO11];
133static int cp_mtable[NMOVES][FACTORIAL8];
134static int coud_mtable[NMOVES][POW3TO7];
135static int cofb_mtable[NMOVES][POW3TO7];
136static int corl_mtable[NMOVES][POW3TO7];
137static int cpos_mtable[NMOVES][FACTORIAL6];
138
139static uint64_t me[12];
140
141static int edge_cycle[NMOVES][12];
142static int corner_cycle[NMOVES][8];
143static int center_cycle[NMOVES][6];
144static int eofb_flipped[NMOVES][12];
145static int eorl_flipped[NMOVES][12];
146static int eoud_flipped[NMOVES][12];
147static int coud_flipped[NMOVES][8];
148static int corl_flipped[NMOVES][8];
149static int cofb_flipped[NMOVES][8];
150static Alg * equiv_alg[NMOVES];
151
152static int epose_source[NTRANS]; /* 0=epose, 1=eposs, 2=eposm */
153static int eposs_source[NTRANS];
154static int eposm_source[NTRANS];
155static int eofb_source[NTRANS]; /* 0=eoud, 1=eorl, 2=eofb */
156static int eorl_source[NTRANS];
157static int eoud_source[NTRANS];
158static int coud_source[NTRANS]; /* 0=coud, 1=corl, 2=cofb */
159static int cofb_source[NTRANS];
160static int corl_source[NTRANS];
161static int ep_mirror[12];
162static int cp_mirror[8];
163static int cpos_mirror[6];
164static Alg * rotation_algs[NROTATIONS];
165
166
167/* Symmetry data for some coordinates ****************************************/
168
169static Trans
170trans_group_udfix[16] = {
171 uf, ur, ub, ul,
172 df, dr, db, dl,
173 uf_mirror, ur_mirror, ub_mirror, ul_mirror,
174 df_mirror, dr_mirror, db_mirror, dl_mirror,
175};
176
177SymData
178sd_coud_16 = {
179 .filename = "sd_coud_16",
180 .coord = &coord_coud,
181 .sym_coord = &coord_coud_sym16,
182 .ntrans = 16,
183 .trans = trans_group_udfix
184};
185
186SymData
187sd_eofbepos_16 = {
188 .filename = "sd_eofbepos_16",
189 .coord = &coord_eofbepos,
190 .sym_coord = &coord_eofbepos_sym16,
191 .ntrans = 16,
192 .trans = trans_group_udfix
193};
194
195static int n_all_symdata = 2;
196static SymData * all_sd[2] = { &sd_coud_16, &sd_eofbepos_16 };
197
198/* Coordinates and their implementation **************************************/
199
200static uint64_t index_eofb(Cube cube);
201static uint64_t index_eofbepos(Cube cube);
202static uint64_t index_coud(Cube cube);
203static uint64_t index_corners(Cube cube);
204static uint64_t index_cornershtr(Cube cube);
205static uint64_t index_drud(Cube cube);
206static uint64_t index_coud_sym16(Cube cube);
207static uint64_t index_eofbepos_sym16(Cube cube);
208static uint64_t index_drud_sym16(Cube cube);
209static uint64_t index_khuge(Cube cube);
210
211static Cube antindex_eofb(uint64_t ind);
212static Cube antindex_eofbepos(uint64_t ind);
213static Cube antindex_coud(uint64_t ind);
214static Cube antindex_corners(uint64_t ind);
215static Cube antindex_cornershtr(uint64_t ind);
216static Cube antindex_drud(uint64_t ind);
217static Cube antindex_coud_sym16(uint64_t ind);
218static Cube antindex_eofbepos_sym16(uint64_t ind);
219static Cube antindex_drud_sym16(uint64_t ind);
220static Cube antindex_khuge(uint64_t ind);
221
222Coordinate
223coord_eofb = {
224 .index = index_eofb,
225 .cube = antindex_eofb,
226 .check = check_eofb,
227 .max = POW2TO11
228};
229
230Coordinate
231coord_eofbepos = {
232 .index = index_eofbepos,
233 .cube = antindex_eofbepos,
234 .check = check_eofbepos,
235 .max = POW2TO11 * BINOM12ON4
236};
237
238Coordinate
239coord_coud = {
240 .index = index_coud,
241 .cube = antindex_coud,
242 .check = check_coud,
243 .max = POW3TO7
244};
245
246Coordinate
247coord_corners = {
248 .index = index_corners,
249 .cube = antindex_corners,
250 .check = check_corners,
251 .max = POW3TO7 * FACTORIAL8
252};
253
254Coordinate
255coord_cornershtr = {
256 .index = index_cornershtr,
257 .cube = antindex_cornershtr,
258 .check = check_cornershtr,
259 .max = POW3TO7 * BINOM8ON4 * 6
260};
261
262Coordinate
263coord_drud = {
264 .index = index_drud,
265 .cube = antindex_drud,
266 .check = check_drud,
267 .max = POW2TO11 * POW3TO7 * BINOM12ON4
268};
269
270Coordinate
271coord_eofbepos_sym16 = {
272 .index = index_eofbepos_sym16,
273 .cube = antindex_eofbepos_sym16,
274 .check = check_eofbepos,
275};
276
277Coordinate
278coord_coud_sym16 = {
279 .index = index_coud_sym16,
280 .cube = antindex_coud_sym16,
281 .check = check_coud,
282};
283
284Coordinate
285coord_drud_sym16 = {
286 .index = index_drud_sym16,
287 .cube = antindex_drud_sym16,
288 .check = check_drud,
289 .max = POW3TO7 * 64430
290};
291
292Coordinate
293coord_khuge = {
294 .index = index_khuge,
295 .cube = antindex_khuge,
296 .check = check_khuge,
297 .max = POW3TO7 * FACTORIAL4 * 64430
298};
299
300
301static uint64_t
302index_eofb(Cube cube)
303{
304 return cube.eofb;
305}
306
307static uint64_t
308index_eofbepos(Cube cube)
309{
310 return (cube.epose / FACTORIAL4) * POW2TO11 + cube.eofb;
311}
312
313static uint64_t
314index_coud(Cube cube)
315{
316 return cube.coud;
317}
318
319static uint64_t
320index_corners(Cube cube)
321{
322 return cube.coud * FACTORIAL8 + cube.cp;
323}
324
325static uint64_t
326index_cornershtr(Cube cube)
327{
328 return cube.coud * BINOM8ON4 * 6 + cphtr(cube);
329}
330
331static uint64_t
332index_drud(Cube cube)
333{
334 uint64_t a, b, c;
335
336 a = cube.eofb;
337 b = cube.coud;
338 c = cube.epose / FACTORIAL4;
339
340 b *= POW2TO11;
341 c *= POW2TO11 * POW3TO7;
342
343 return a + b + c;
344}
345
346static uint64_t
347index_coud_sym16(Cube cube)
348{
349 return sd_coud_16.class[index_coud(cube)];
350}
351
352static uint64_t
353index_drud_sym16(Cube cube)
354{
355 Trans t;
356 Cube c;
357
358 t = sd_eofbepos_16.transtorep[index_eofbepos(cube)];
359 c = apply_trans(t, cube);
360
361 return index_eofbepos_sym16(c) * POW3TO7 + c.coud;
362}
363
364static uint64_t
365index_eofbepos_sym16(Cube cube)
366{
367 return sd_eofbepos_16.class[index_eofbepos(cube)];
368}
369
370static uint64_t
371index_khuge(Cube cube)
372{
373 Trans t;
374 Cube c;
375 uint64_t a;
376
377 t = sd_eofbepos_16.transtorep[index_eofbepos(cube)];
378 c = apply_trans(t, cube);
379 a = (index_eofbepos_sym16(c) * 24) + (c.epose % 24);
380
381 return a * POW3TO7 + c.coud;
382}
383
384
385/* TODO: rename */
386static Cube
387antindex_eofb(uint64_t ind)
388{
389 return (Cube){ .eofb = ind, .eorl = ind, .eoud = ind };
390}
391
392static Cube
393antindex_eofbepos(uint64_t ind)
394{
395 return admissible_ee_aux[ind];
396}
397
398/* TODO: rename */
399static Cube
400antindex_coud(uint64_t ind)
401{
402 return (Cube){ .coud = ind, .corl = ind, .cofb = ind };
403}
404
405/* TODO: admissible co for other orientations */
406static Cube
407antindex_corners(uint64_t ind)
408{
409 Cube c = {0};
410
411 c.coud = ind / FACTORIAL8;
412 c.cp = ind % FACTORIAL8;
413
414 return c;
415}
416
417/* TODO: admissible co for other orientations */
418static Cube
419antindex_cornershtr(uint64_t ind)
420{
421 Cube c = anti_cphtr(ind % (BINOM8ON4 * 6));
422
423 c.coud = ind / (BINOM8ON4 * 6);
424
425 return c;
426}
427
428/* TODO: admissible eos and cos */
429static Cube
430antindex_drud(uint64_t ind)
431{
432 Cube c = {0};
433
434 c.eofb = ind % POW2TO11;
435 c.coud = (ind / POW2TO11) % POW3TO7;
436 c.epose = (ind % (POW2TO11 * POW3TO7)) * FACTORIAL4;
437
438 return c;
439}
440
441static Cube
442antindex_coud_sym16(uint64_t ind)
443{
444 return sd_coud_16.rep[ind];
445}
446
447static Cube
448antindex_eofbepos_sym16(uint64_t ind)
449{
450 return sd_eofbepos_16.rep[ind];
451}
452
453static Cube
454antindex_drud_sym16(uint64_t ind)
455{
456 Cube c;
457
458 c = sd_eofbepos_16.rep[ind/POW3TO7];
459 c.coud = ind % POW3TO7;
460 c.cofb = c.coud;
461 c.corl = c.coud;
462
463 return c;
464}
465
466static Cube
467antindex_khuge(uint64_t ind)
468{
469 Cube c;
470
471 c = sd_eofbepos_16.rep[ind/(FACTORIAL4*POW3TO7)];
472 c.epose = ((c.epose / 24) * 24) + ((ind/POW3TO7) % 24);
473 c.coud = ind % POW3TO7;
474
475 return c;
476}
477
478
479/* Checkers ******************************************************************/
480
481bool
482check_centers(Cube cube)
483{
484 return cube.cpos == 0;
485}
486
487bool
488check_corners(Cube cube)
489{
490 return cube.cp == 0 && cube.coud == 0;
491}
492
493bool
494check_cornershtr(Cube cube)
495{
496 return cube.coud == 0 && cphtr(cube) == 0; /* TODO: use array cphtrcosets*/
497}
498
499bool
500check_coud(Cube cube)
501{
502 return cube.coud == 0;
503}
504
505bool
506check_drud(Cube cube)
507{
508 return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0;
509}
510
511bool
512check_eofb(Cube cube)
513{
514 return cube.eofb == 0;
515}
516
517bool
518check_eofbepos(Cube cube)
519{
520 return cube.eofb == 0 && cube.epose / 24 == 0;
521}
522
523bool
524check_epose(Cube cube)
525{
526 return cube.epose == 0;
527}
528
529bool
530check_ep(Cube cube)
531{
532 return cube.epose == 0 && cube.eposs == 0 && cube.eposm == 0;
533}
534
535bool
536check_khuge(Cube cube)
537{
538 return check_drud(cube) && cube.epose % 24 == 0;
539}
540
541bool
542check_nothing(Cube cube)
543{
544 return is_admissible(cube); /*TODO: maybe change?*/
545}
546
547/* Movesets ******************************************************************/
548
549bool
550moveset_HTM(Move m)
551{
552 return m >= U && m <= B3;
553}
554
555bool
556moveset_URF(Move m)
557{
558 Move b = base_move(m);
559
560 return b == U || b == R || b == F;
561}
562
563
564/* Local functions implementation ********************************************/
565
566/* TODO: this should be an anti index (maybe?) */
567static Cube
568admissible_ep(Cube cube, PieceFilter f)
569{
570 CubeArray *arr = new_cubearray(cube, f);
571 Cube ret;
572 bool used[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
573 int i, j;
574
575 for (i = 0; i < 12; i++)
576 if (arr->ep[i] != -1)
577 used[arr->ep[i]] = true;
578
579 for (i = 0, j = 0; i < 12; i++) {
580 for ( ; j < 11 && used[j]; j++);
581 if (arr->ep[i] == -1)
582 arr->ep[i] = j++;
583 }
584
585 ret = arrays_to_cube(arr, pf_ep);
586 free_cubearray(arr, f);
587
588 return ret;
589}
590
591static Cube
592admissible_eos_from_eofbepos(Cube cube)
593{
594 Edge e;
595 Cube ret;
596 CubeArray *arr = new_cubearray(cube, pf_all);
597
598 memcpy(arr->eorl, arr->eofb, 12 * sizeof(int));
599 memcpy(arr->eoud, arr->eofb, 12 * sizeof(int));
600
601 for (e = 0; e < 12; e++) {
602 if ((edge_slice(e) != 0 && edge_slice(arr->ep[e]) == 0) ||
603 (edge_slice(e) == 0 && edge_slice(arr->ep[e]) != 0))
604 arr->eorl[e] = 1 - arr->eorl[e];
605 if ((edge_slice(e) != 2 && edge_slice(arr->ep[e]) == 2) ||
606 (edge_slice(e) == 2 && edge_slice(arr->ep[e]) != 2))
607 arr->eoud[e] = 1 - arr->eoud[e];
608 }
609
610 ret = arrays_to_cube(arr, pf_all);
611 free_cubearray(arr, pf_all);
612
613 return ret;
614}
615
616static bool
617allowed_next(Move move, DfsData *dd)
618{
619 if (!possible_next[dd->last2][dd->last1][move])
620 return false;
621
622 if (commute[dd->last1][move])
623 return dd->move_position[dd->last1] < dd->move_position[move];
624
625 return true;
626}
627
628static void
629append_alg(AlgList *l, Alg *alg)
630{
631 AlgListNode *node = malloc(sizeof(AlgListNode));
632 int i;
633
634 node->alg = new_alg("");
635 for (i = 0; i < alg->len; i++)
636 append_move(node->alg, alg->move[i], alg->inv[i]);
637 node->next = NULL;
638
639 if (++l->len == 1)
640 l->first = node;
641 else
642 l->last->next = node;
643 l->last = node;
644}
645
646static void
647append_move(Alg *alg, Move m, bool inverse)
648{
649 if (alg->len == alg->allocated)
650 realloc_alg(alg, 2*alg->len);
651
652 alg->move[alg->len] = m;
653 alg->inv [alg->len] = inverse;
654 alg->len++;
655}
656
657static Cube
658apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a)
659{
660 Cube ret = {0};
661 int i;
662
663 for (i = 0; i < alg->len; i++)
664 if (alg->inv[i])
665 ret = a ? apply_move(alg->move[i], ret) :
666 apply_move_cubearray(alg->move[i], ret, f);
667
668 ret = compose_filtered(c, inverse_cube(ret), f);
669
670 for (i = 0; i < alg->len; i++)
671 if (!alg->inv[i])
672 ret = a ? apply_move(alg->move[i], ret) :
673 apply_move_cubearray(alg->move[i], ret, f);
674
675 return ret;
676}
677
678static void
679apply_permutation(int *perm, int *set, int n)
680{
681 int *aux = malloc(n * sizeof(int));
682 int i;
683
684 if (!is_perm(perm, n))
685 return;
686
687 for (i = 0; i < n; i++)
688 aux[i] = set[perm[i]];
689
690 memcpy(set, aux, n * sizeof(int));
691 free(aux);
692}
693
694static Cube
695apply_move_cubearray(Move m, Cube cube, PieceFilter f)
696{
697 CubeArray m_arr = {
698 edge_cycle[m],
699 eofb_flipped[m],
700 eorl_flipped[m],
701 eoud_flipped[m],
702 corner_cycle[m],
703 coud_flipped[m],
704 corl_flipped[m],
705 cofb_flipped[m],
706 center_cycle[m]
707 };
708
709 return move_via_arrays(&m_arr, cube, f);
710}
711
712static int
713array_ep_to_epos(int *ep, int *ss)
714{
715 int epos[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
716 int eps[4];
717 int i, j, is;
718
719 for (i = 0, is = 0; i < 12; i++) {
720 for (j = 0; j < 4; j++) {
721 if (ep[i] == ss[j]) {
722 eps[is++] = j;
723 epos[i] = 1;
724 }
725 }
726 }
727
728 for (i = 0; i < 4; i++)
729 swap(&epos[ss[i]], &epos[i+8]);
730
731 return epos_from_arrays(epos, eps);
732}
733
734static Cube
735arrays_to_cube(CubeArray *arr, PieceFilter f)
736{
737 Cube ret = {0};
738
739 if (f.epose)
740 ret.epose = array_ep_to_epos(arr->ep, epe_solved);
741 if (f.eposs)
742 ret.eposs = array_ep_to_epos(arr->ep, eps_solved);
743 if (f.eposm)
744 ret.eposm = array_ep_to_epos(arr->ep, epm_solved);
745 if (f.eofb)
746 ret.eofb = digit_array_to_int(arr->eofb, 11, 2);
747 if (f.eorl)
748 ret.eorl = digit_array_to_int(arr->eorl, 11, 2);
749 if (f.eoud)
750 ret.eoud = digit_array_to_int(arr->eoud, 11, 2);
751 if (f.cp)
752 ret.cp = perm_to_index(arr->cp, 8);
753 if (f.coud)
754 ret.coud = digit_array_to_int(arr->coud, 7, 3);
755 if (f.corl)
756 ret.corl = digit_array_to_int(arr->corl, 7, 3);
757 if (f.cofb)
758 ret.cofb = digit_array_to_int(arr->cofb, 7, 3);
759 if (f.cpos)
760 ret.cpos = perm_to_index(arr->cpos, 6);
761
762 return ret;
763}
764
765static int
766binomial(int n, int k)
767{
768 if (n < 0 || k < 0 || k > n)
769 return 0;
770
771 return factorial(n) / (factorial(k) * factorial(n-k));
772}
773
774static Cube
775compose_filtered(Cube c2, Cube c1, PieceFilter f)
776{
777 CubeArray *arr = new_cubearray(c2, f);
778 Cube ret;
779
780 ret = move_via_arrays(arr, c1, f);
781 free_cubearray(arr, f);
782
783 return ret;
784}
785
786static void
787cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f)
788{
789 int i;
790
791 if (f.epose || f.eposs || f.eposm)
792 for (i = 0; i < 12; i++)
793 arr->ep[i] = -1;
794
795 if (f.epose)
796 epos_to_partial_ep(cube.epose, arr->ep, epe_solved);
797 if (f.eposs)
798 epos_to_partial_ep(cube.eposs, arr->ep, eps_solved);
799 if (f.eposm)
800 epos_to_partial_ep(cube.eposm, arr->ep, epm_solved);
801 if (f.eofb)
802 int_to_sum_zero_array(cube.eofb, 2, 12, arr->eofb);
803 if (f.eorl)
804 int_to_sum_zero_array(cube.eorl, 2, 12, arr->eorl);
805 if (f.eoud)
806 int_to_sum_zero_array(cube.eoud, 2, 12, arr->eoud);
807 if (f.cp)
808 index_to_perm(cube.cp, 8, arr->cp);
809 if (f.coud)
810 int_to_sum_zero_array(cube.coud, 3, 8, arr->coud);
811 if (f.corl)
812 int_to_sum_zero_array(cube.corl, 3, 8, arr->corl);
813 if (f.cofb)
814 int_to_sum_zero_array(cube.cofb, 3, 8, arr->cofb);
815 if (f.cpos)
816 index_to_perm(cube.cpos, 6, arr->cpos);
817}
818
819/*
820static int
821cphtr_cp(int cp)
822{
823 int i, a[8];
824
825 index_to_perm(cp, 8, a);
826
827 for (i = 0; i < 8; i++)
828 if (a[i] == UFR || a[i] == UBL || a[i] == DFL || a[i] == DBR)
829 a[i] = 0;
830 else
831 a[i] = 1;
832
833 swap(&a[1], &a[5]);
834 swap(&a[3], &a[7]);
835
836 return subset_to_index(a, 8, 4);
837}
838*/
839
840static void
841dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd)
842{
843 if (dfs_stop(c, s, opts, dd))
844 return;
845
846 if (dfs_check_solved(opts, dd))
847 return;
848
849 dfs_branch(c, s, opts, dd);
850
851 if (opts->can_niss && !dd->niss)
852 dfs_niss(c, s, opts, dd);
853}
854
855static void
856dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd)
857{
858 Move m, l1 = dd->last1, l2 = dd->last2, *moves = dd->sorted_moves;
859
860 int i, maxnsol = opts->max_solutions;
861
862 for (i = 0; moves[i] != NULLMOVE && dd->sols->len < maxnsol; i++) {
863 m = moves[i];
864 if (allowed_next(m, dd)) {
865 dd->last2 = dd->last1;
866 dd->last1 = m;
867 append_move(dd->current_alg, m, dd->niss);
868
869 dfs(apply_move(m, c), s, opts, dd);
870
871 dd->current_alg->len--;
872 dd->last2 = l2;
873 dd->last1 = l1;
874 }
875 }
876}
877
878static bool
879dfs_check_solved(SolveOptions *opts, DfsData *dd)
880{
881 if (dd->lb != 0)
882 return false;
883
884 if (dd->current_alg->len == dd->d) {
885 append_alg(dd->sols, dd->current_alg);
886
887 if (opts->feedback)
888 print_alg(dd->current_alg, false);
889 }
890
891 return true;
892}
893
894static void
895dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd)
896{
897 Move l1 = dd->last1, l2 = dd->last2;
898 CubeTarget ct;
899
900 ct.cube = apply_move(inverse_move(l1), (Cube){0});
901 ct.target = 1;
902
903 if (dd->current_alg->len == 0 || s.estimate(ct)) {
904 dd->niss = true;
905 dd->last1 = NULLMOVE;
906 dd->last2 = NULLMOVE;
907
908 dfs(inverse_cube(c), s, opts, dd);
909
910 dd->last1 = l1;
911 dd->last2 = l2;
912 dd->niss = false;
913 }
914}
915
916static bool
917dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd)
918{
919 CubeTarget ct = {
920 .cube = c,
921 .target = dd->d - dd->current_alg->len
922 };
923
924 if (dd->sols->len >= opts->max_solutions)
925 return true;
926
927 dd->lb = s.estimate(ct);
928 if (opts->can_niss && !dd->niss)
929 dd->lb = MIN(1, dd->lb);
930
931 if (dd->current_alg->len + dd->lb > dd->d)
932 return true;
933
934 return false;
935}
936
937static int
938digit_array_to_int(int *a, int n, int b)
939{
940 int i, ret = 0, p = 1;
941
942 for (i = 0; i < n; i++, p *= b)
943 ret += a[i] * p;
944
945 return ret;
946}
947
948static int
949edge_slice(Edge e) {
950 if (e < 0 || e > 11)
951 return -1;
952
953 if (e == FR || e == FL || e == BL || e == BR)
954 return 0;
955 if (e == UR || e == UL || e == DR || e == DL)
956 return 1;
957
958 return 2;
959}
960
961static int
962epos_dependent_pos(int poss, int pose)
963{
964 int ep[12] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
965 int ep8[8] = {0, 0, 0, 0, 0, 0, 0, 0};
966 int i, j;
967
968 epos_to_partial_ep(poss*FACTORIAL4, ep, eps_solved);
969 epos_to_partial_ep(pose*FACTORIAL4, ep, epe_solved);
970
971 for (i = 0, j = 0; i < 12; i++)
972 if (edge_slice(ep[i]) != 0)
973 ep8[j++] = (edge_slice(ep[i]) == 1) ? 1 : 0;
974
975 swap(&ep8[1], &ep8[4]);
976 swap(&ep8[3], &ep8[6]);
977
978 return subset_to_index(ep8, 8, 4);
979}
980
981static int
982epos_from_arrays(int *epos, int *ep)
983{
984 return FACTORIAL4 * subset_to_index(epos,12,4) + perm_to_index(ep,4);
985}
986
987static void
988epos_to_partial_ep(int epos, int *ep, int *ss)
989{
990 int i, is, eposs[12], eps[4];
991
992 index_to_perm(epos % FACTORIAL4, 4, eps);
993 index_to_subset(epos / FACTORIAL4, 12, 4, eposs);
994
995 for (i = 0; i < 4; i++)
996 swap(&eposs[ss[i]], &eposs[i+8]);
997
998 for (i = 0, is = 0; i < 12; i++)
999 if (eposs[i])
1000 ep[i] = ss[eps[is++]];
1001}
1002
1003static int
1004factorial(int n)
1005{
1006 int i, ret = 1;
1007
1008 if (n < 0)
1009 return 0;
1010
1011 for (i = 1; i <= n; i++)
1012 ret *= i;
1013
1014 return ret;
1015}
1016
1017void
1018free_alg(Alg *alg)
1019{
1020 free(alg->move);
1021 free(alg->inv);
1022 free(alg);
1023}
1024
1025void
1026free_alglist(AlgList *l)
1027{
1028 AlgListNode *aux, *i = l->first;
1029
1030 while (i != NULL) {
1031 aux = i->next;
1032 free_alglistnode(i);
1033 i = aux;
1034 }
1035 free(l);
1036}
1037
1038void
1039free_alglistnode(AlgListNode *aln)
1040{
1041 free_alg(aln->alg);
1042 free(aln);
1043}
1044
1045static void
1046free_cubearray(CubeArray *arr, PieceFilter f)
1047{
1048 if (f.epose || f.eposs || f.eposm)
1049 free(arr->ep);
1050 if (f.eofb)
1051 free(arr->eofb);
1052 if (f.eorl)
1053 free(arr->eorl);
1054 if (f.eoud)
1055 free(arr->eoud);
1056 if (f.cp)
1057 free(arr->cp);
1058 if (f.coud)
1059 free(arr->coud);
1060 if (f.corl)
1061 free(arr->corl);
1062 if (f.cofb)
1063 free(arr->cofb);
1064 if (f.cpos)
1065 free(arr->cpos);
1066
1067 free(arr);
1068}
1069
1070static void
1071genptable_dfs(Cube c, PruneData *pd, DfsData *dd)
1072{
1073 int oldval = ptableval(pd, c);
1074
1075 if (oldval < dd->m || pd->n == pd->coord->max ||
1076 (dd->m != 0 && pd->coord->check(c)) )
1077 return;
1078
1079 if (dd->m == dd->d) {
1080 if (dd->m < oldval)
1081 ptable_update(pd, c, dd->m);
1082 return;
1083 }
1084
1085 genptable_dfs_branch(c, pd, dd);
1086}
1087
1088static void
1089genptable_dfs_branch(Cube c, PruneData *pd, DfsData *dd)
1090{
1091 Move i, move, l1 = dd->last1, l2 = dd->last2;
1092
1093 dd->m++;
1094
1095 for (i = 0; dd->sorted_moves[i] != NULLMOVE; i++) {
1096 move = dd->sorted_moves[i];
1097 if (allowed_next(move, dd)) {
1098 dd->last2 = dd->last1;
1099 dd->last1 = move;
1100
1101 genptable_dfs(apply_move(move, c), pd, dd);
1102
1103 dd->last2 = l2;
1104 dd->last1 = l1;
1105 }
1106 }
1107
1108 dd->m--;
1109}
1110
1111static void
1112gensym(SymData *sd)
1113{
1114 uint64_t i, in, nreps = 0;
1115 int j;
1116 Cube c, d;
1117
1118 if (sd->generated)
1119 return;
1120
1121 sd->class = malloc(sd->coord->max * sizeof(uint64_t));
1122 sd->rep = malloc(sd->coord->max * sizeof(Cube));
1123 sd->transtorep = malloc(sd->coord->max * sizeof(Trans));
1124
1125 if (read_symdata_file(sd)) {
1126 sd->generated = true;
1127 return;
1128 }
1129
1130 fprintf(stderr, "Cannot load %s, generating it\n", sd->filename);
1131
1132 for (i = 0; i < sd->coord->max; i++)
1133 sd->class[i] = sd->coord->max + 1;
1134
1135 for (i = 0; i < sd->coord->max; i++) {
1136 if (sd->class[i] == sd->coord->max + 1) {
1137 c = sd->coord->cube(i);
1138 sd->rep[nreps] = c;
1139 for (j = 0; j < sd->ntrans; j++) {
1140 d = apply_trans(sd->trans[j], c);
1141 in = sd->coord->index(d);
1142
1143 if (sd->class[in] == sd->coord->max + 1) {
1144 sd->class[in] = nreps;
1145 sd->transtorep[in] =
1146 inverse_trans(sd->trans[j]);
1147 }
1148 }
1149 nreps++;
1150 }
1151 }
1152
1153 sd->sym_coord->max = nreps;
1154 sd->rep = realloc(sd->rep, nreps * sizeof(Cube));
1155 sd->generated = true;
1156
1157 fprintf(stderr, "Found %lu classes\n", nreps);
1158
1159 if (!write_symdata_file(sd))
1160 fprintf(stderr, "Error writing SymData file\n");
1161
1162 return;
1163}
1164
1165static void
1166index_to_perm(int p, int n, int *r)
1167{
1168 int *a = malloc(n * sizeof(int));
1169 int i, j, c;
1170
1171 for (i = 0; i < n; i++)
1172 a[i] = 0;
1173
1174 if (p < 0 || p >= factorial(n))
1175 for (i = 0; i < n; i++)
1176 r[i] = -1;
1177
1178 for (i = 0; i < n; i++) {
1179 c = 0;
1180 j = 0;
1181 while (c <= p / factorial(n-i-1))
1182 c += a[j++] ? 0 : 1;
1183 r[i] = j-1;
1184 a[j-1] = 1;
1185 p %= factorial(n-i-1);
1186 }
1187
1188 free(a);
1189}
1190
1191static void
1192index_to_subset(int s, int n, int k, int *r)
1193{
1194 int i, j, v;
1195
1196 if (s < 0 || s >= binomial(n, k)) {
1197 for (i = 0; i < n; i++)
1198 r[i] = -1;
1199 return;
1200 }
1201
1202 for (i = 0; i < n; i++) {
1203 if (k == n-i) {
1204 for (j = i; j < n; j++)
1205 r[j] = 1;
1206 return;
1207 }
1208
1209 if (k == 0) {
1210 for (j = i; j < n; j++)
1211 r[j] = 0;
1212 return;
1213 }
1214
1215 v = binomial(n-i-1, k);
1216 if (s >= v) {
1217 r[i] = 1;
1218 k--;
1219 s -= v;
1220 } else {
1221 r[i] = 0;
1222 }
1223 }
1224}
1225
1226static void
1227int_to_digit_array(int a, int b, int n, int *r)
1228{
1229 int i;
1230
1231 if (b <= 1)
1232 for (i = 0; i < n; i++)
1233 r[i] = 0;
1234 else
1235 for (i = 0; i < n; i++, a /= b)
1236 r[i] = a % b;
1237}
1238
1239static void
1240int_to_sum_zero_array(int x, int b, int n, int *a)
1241{
1242 int i, s = 0;
1243
1244 if (b <= 1) {
1245 for (i = 0; i < n; i++)
1246 a[i] = 0;
1247 } else {
1248 int_to_digit_array(x, b, n-1, a);
1249 for (i = 0; i < n - 1; i++)
1250 s = (s + a[i]) % b;
1251 a[n-1] = (b - s) % b;
1252 }
1253}
1254
1255static int
1256invert_digits(int a, int b, int n)
1257{
1258 int i, ret, *r = malloc(n * sizeof(int));
1259
1260 int_to_digit_array(a, b, n, r);
1261 for (i = 0; i < n; i++)
1262 r[i] = (b-r[i]) % b;
1263
1264 ret = digit_array_to_int(r, n, b);
1265 free(r);
1266 return ret;
1267}
1268
1269static bool
1270is_perm(int *a, int n)
1271{
1272 int *aux = malloc(n * sizeof(int));
1273 int i;
1274
1275 for (i = 0; i < n; i++)
1276 if (a[i] < 0 || a[i] >= n)
1277 return false;
1278 else
1279 aux[a[i]] = 1;
1280
1281 for (i = 0; i < n; i++)
1282 if (!aux[i])
1283 return false;
1284
1285 free(aux);
1286
1287 return true;
1288}
1289
1290static bool
1291is_subset(int *a, int n, int k)
1292{
1293 int i, sum = 0;
1294
1295 for (i = 0; i < n; i++)
1296 sum += a[i] ? 1 : 0;
1297
1298 return sum == k;
1299}
1300
1301static Cube
1302move_via_arrays(CubeArray *arr, Cube c, PieceFilter f)
1303{
1304 CubeArray *arrc = new_cubearray(c, f);
1305 Cube ret;
1306
1307 if (f.epose || f.eposs || f.eposm)
1308 apply_permutation(arr->ep, arrc->ep, 12);
1309
1310 if (f.eofb) {
1311 apply_permutation(arr->ep, arrc->eofb, 12);
1312 sum_arrays_mod(arr->eofb, arrc->eofb, 12, 2);
1313 }
1314
1315 if (f.eorl) {
1316 apply_permutation(arr->ep, arrc->eorl, 12);
1317 sum_arrays_mod(arr->eorl, arrc->eorl, 12, 2);
1318 }
1319
1320 if (f.eoud) {
1321 apply_permutation(arr->ep, arrc->eoud, 12);
1322 sum_arrays_mod(arr->eoud, arrc->eoud, 12, 2);
1323 }
1324
1325 if (f.cp)
1326 apply_permutation(arr->cp, arrc->cp, 8);
1327
1328 if (f.coud) {
1329 apply_permutation(arr->cp, arrc->coud, 8);
1330 sum_arrays_mod(arr->coud, arrc->coud, 8, 3);
1331 }
1332
1333 if (f.corl) {
1334 apply_permutation(arr->cp, arrc->corl, 8);
1335 sum_arrays_mod(arr->corl, arrc->corl, 8, 3);
1336 }
1337
1338 if (f.cofb) {
1339 apply_permutation(arr->cp, arrc->cofb, 8);
1340 sum_arrays_mod(arr->cofb, arrc->cofb, 8, 3);
1341 }
1342
1343 if (f.cpos)
1344 apply_permutation(arr->cpos, arrc->cpos, 6);
1345
1346 ret = arrays_to_cube(arrc, f);
1347 free_cubearray(arrc, f);
1348
1349 return ret;
1350}
1351
1352static void
1353movelist_to_position(Move *movelist, int *position)
1354{
1355 Move m;
1356
1357 for (m = 0; m < NMOVES && movelist[m] != NULLMOVE; m++)
1358 position[movelist[m]] = m;
1359}
1360
1361static void
1362moveset_to_list(Moveset ms, Estimator f, Move *r)
1363{
1364 CubeTarget ct = { .target = 1 };
1365 int b[NMOVES];
1366 int na = 0, nb = 0;
1367 Move i;
1368
1369 if (ms == NULL) {
1370 fprintf(stderr, "Error: no moveset given\n");
1371 return;
1372 }
1373
1374 for (i = U; i < NMOVES; i++) {
1375 if (ms(i)) {
1376 ct.cube = apply_move(i, (Cube){0});
1377 if (f != NULL && f(ct))
1378 r[na++] = i;
1379 else
1380 b[nb++] = i;
1381 }
1382 }
1383
1384 memcpy(r + na, b, nb * sizeof(Move));
1385 r[na+nb] = NULLMOVE;
1386}
1387
1388static AlgList *
1389new_alglist()
1390{
1391 AlgList *ret = malloc(sizeof(AlgList));
1392
1393 ret->len = 0;
1394 ret->first = NULL;
1395 ret->last = NULL;
1396
1397 return ret;
1398}
1399
1400static CubeArray *
1401new_cubearray(Cube cube, PieceFilter f)
1402{
1403 CubeArray *arr = malloc(sizeof(CubeArray));
1404
1405 if (f.epose || f.eposs || f.eposm)
1406 arr->ep = malloc(12 * sizeof(int));
1407 if (f.eofb)
1408 arr->eofb = malloc(12 * sizeof(int));
1409 if (f.eorl)
1410 arr->eorl = malloc(12 * sizeof(int));
1411 if (f.eoud)
1412 arr->eoud = malloc(12 * sizeof(int));
1413 if (f.cp)
1414 arr->cp = malloc(8 * sizeof(int));
1415 if (f.coud)
1416 arr->coud = malloc(8 * sizeof(int));
1417 if (f.corl)
1418 arr->corl = malloc(8 * sizeof(int));
1419 if (f.cofb)
1420 arr->cofb = malloc(8 * sizeof(int));
1421 if (f.cpos)
1422 arr->cpos = malloc(6 * sizeof(int));
1423
1424 cube_to_arrays(cube, arr, f);
1425
1426 return arr;
1427}
1428
1429static int
1430perm_sign(int *a, int n)
1431{
1432 int i, j, ret = 0;
1433
1434 if (!is_perm(a,n))
1435 return -1;
1436
1437 for (i = 0; i < n; i++)
1438 for (j = i+1; j < n; j++)
1439 ret += (a[i] > a[j]) ? 1 : 0;
1440
1441 return ret % 2;
1442}
1443
1444static int
1445perm_to_index(int *a, int n)
1446{
1447 int i, j, c, ret = 0;
1448
1449 if (!is_perm(a, n))
1450 return -1;
1451
1452 for (i = 0; i < n; i++) {
1453 c = 0;
1454 for (j = i+1; j < n; j++)
1455 c += (a[i] > a[j]) ? 1 : 0;
1456 ret += factorial(n-i-1) * c;
1457 }
1458
1459 return ret;
1460}
1461
1462static int
1463powint(int a, int b)
1464{
1465 if (b < 0)
1466 return 0;
1467 if (b == 0)
1468 return 1;
1469
1470 if (b % 2)
1471 return a * powint(a, b-1);
1472 else
1473 return powint(a*a, b/2);
1474}
1475
1476static void
1477ptable_update(PruneData *pd, Cube cube, int n)
1478{
1479 uint64_t ind = pd->coord->index(cube);
1480 uint8_t oldval2 = pd->ptable[ind/2];
1481 int other = (ind % 2) ? oldval2 % 16 : oldval2 / 16;
1482
1483 pd->ptable[ind/2] = (ind % 2) ? 16*n + other : 16*other + n;
1484 pd->n++;
1485}
1486
1487static void
1488realloc_alg(Alg *alg, int n)
1489{
1490 if (alg == NULL) {
1491 fprintf(stderr, "Error: trying to reallocate NULL alg.\n");
1492 return;
1493 }
1494
1495 if (n < alg->len) {
1496 fprintf(stderr, "Error: alg too long for reallocation ");
1497 fprintf(stderr, "(%d vs %d)\n", alg->len, n);
1498 return;
1499 }
1500
1501 if (n > 1000000) {
1502 fprintf(stderr, "Warning: very long alg,");
1503 fprintf(stderr, "something might go wrong.\n");
1504 }
1505
1506 alg->move = realloc(alg->move, n * sizeof(int));
1507 alg->inv = realloc(alg->inv, n * sizeof(int));
1508 alg->allocated = n;
1509}
1510
1511static bool
1512read_mtables_file()
1513{
1514 FILE *f;
1515 char fname[strlen(tabledir)+20];
1516 int m, b = sizeof(int);
1517 bool r = true;
1518
1519 strcpy(fname, tabledir);
1520 strcat(fname, "/mtables");
1521
1522 if ((f = fopen(fname, "rb")) == NULL)
1523 return false;
1524
1525 for (m = 0; m < NMOVES; m++) {
1526 r = r && fread(epose_mtable[m], b, me[0], f) == me[0];
1527 r = r && fread(eposs_mtable[m], b, me[1], f) == me[1];
1528 r = r && fread(eposm_mtable[m], b, me[2], f) == me[2];
1529 r = r && fread(eofb_mtable[m], b, me[3], f) == me[3];
1530 r = r && fread(eorl_mtable[m], b, me[4], f) == me[4];
1531 r = r && fread(eoud_mtable[m], b, me[5], f) == me[5];
1532 r = r && fread(cp_mtable[m], b, me[6], f) == me[6];
1533 r = r && fread(coud_mtable[m], b, me[7], f) == me[7];
1534 r = r && fread(corl_mtable[m], b, me[8], f) == me[8];
1535 r = r && fread(cofb_mtable[m], b, me[9], f) == me[9];
1536 r = r && fread(cpos_mtable[m], b, me[10], f) == me[10];
1537 }
1538
1539 fclose(f);
1540 return r;
1541}
1542
1543static bool
1544read_ptable_file(PruneData *pd)
1545{
1546 FILE *f;
1547 char fname[strlen(tabledir)+100];
1548 uint64_t r;
1549
1550 strcpy(fname, tabledir);
1551 strcat(fname, "/");
1552 strcat(fname, pd->filename);
1553
1554 if ((f = fopen(fname, "rb")) == NULL)
1555 return false;
1556
1557 r = fread(pd->ptable, sizeof(uint8_t), ptablesize(pd), f);
1558 fclose(f);
1559
1560 return r == ptablesize(pd);
1561}
1562
1563static bool
1564read_symdata_file(SymData *sd)
1565{
1566 FILE *f;
1567 char fname[strlen(tabledir)+100];
1568 uint64_t n = sd->coord->max, *sn = &sd->sym_coord->max;
1569 bool r = true;
1570
1571 strcpy(fname, tabledir);
1572 strcat(fname, "/");
1573 strcat(fname, sd->filename);
1574
1575 if ((f = fopen(fname, "rb")) == NULL)
1576 return false;
1577
1578 r = r && fread(&sd->sym_coord->max, sizeof(uint64_t), 1, f) == 1;
1579 r = r && fread(sd->rep, sizeof(Cube), *sn, f) == *sn;
1580 r = r && fread(sd->class, sizeof(uint64_t), n, f) == n;
1581 r = r && fread(sd->transtorep, sizeof(Trans), n, f) == n;
1582
1583 fclose(f);
1584 return r;
1585}
1586
1587static bool
1588read_ttables_file()
1589{
1590 FILE *f;
1591 char fname[strlen(tabledir)+20];
1592 int b = sizeof(int);
1593 bool r = true;
1594 Move m;
1595
1596 strcpy(fname, tabledir);
1597 strcat(fname, "/");
1598 strcat(fname, "ttables");
1599
1600 if ((f = fopen(fname, "rb")) == NULL)
1601 return false;
1602
1603 for (m = 0; m < NTRANS; m++) {
1604 r = r && fread(epose_ttable[m], b, me[0], f) == me[0];
1605 r = r && fread(eposs_ttable[m], b, me[1], f) == me[1];
1606 r = r && fread(eposm_ttable[m], b, me[2], f) == me[2];
1607 r = r && fread(eo_ttable[m], b, me[3], f) == me[3];
1608 r = r && fread(cp_ttable[m], b, me[6], f) == me[6];
1609 r = r && fread(co_ttable[m], b, me[7], f) == me[7];
1610 r = r && fread(cpos_ttable[m], b, me[10], f) == me[10];
1611 r = r && fread(moves_ttable[m], b, me[11], f) == me[11];
1612 }
1613
1614 fclose(f);
1615 return r;
1616}
1617
1618static Cube
1619rotate_via_compose(Trans r, Cube c, PieceFilter f)
1620{
1621 static int zero12[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1622 static int zero8[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
1623 static CubeArray ma = {
1624 .ep = ep_mirror,
1625 .eofb = zero12,
1626 .eorl = zero12,
1627 .eoud = zero12,
1628 .cp = cp_mirror,
1629 .coud = zero8,
1630 .corl = zero8,
1631 .cofb = zero8,
1632 .cpos = cpos_mirror
1633 };
1634
1635 Alg *inv = inverse_alg(rotation_algs[r % NROTATIONS]);
1636 Cube ret = {0};
1637
1638 if (r >= NROTATIONS)
1639 ret = move_via_arrays(&ma, ret, f);
1640 ret = apply_alg_generic(inv, ret, f, true);
1641
1642 ret = compose_filtered(c, ret, f);
1643
1644 ret = apply_alg_generic(rotation_algs[r % NROTATIONS], ret, f, true);
1645 if (r >= NROTATIONS)
1646 ret = move_via_arrays(&ma, ret, f);
1647
1648 free_alg(inv);
1649 return ret;
1650}
1651
1652static int
1653subset_to_index(int *a, int n, int k)
1654{
1655 int i, ret = 0;
1656
1657 if (!is_subset(a, n, k))
1658 return binomial(n, k);
1659
1660 for (i = 0; i < n; i++) {
1661 if (k == n-i)
1662 return ret;
1663 if (a[i]) {
1664 ret += binomial(n-i-1, k);
1665 k--;
1666 }
1667 }
1668
1669 return ret;
1670}
1671
1672static void
1673sum_arrays_mod(int *src, int *dst, int n, int m)
1674{
1675 int i;
1676
1677 for (i = 0; i < n; i++)
1678 dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m;
1679}
1680
1681static void
1682swap(int *a, int *b)
1683{
1684 int aux;
1685
1686 aux = *a;
1687 *a = *b;
1688 *b = aux;
1689}
1690
1691static bool
1692write_mtables_file()
1693{
1694 FILE *f;
1695 char fname[strlen(tabledir)+20];
1696 int m, b = sizeof(int);
1697 bool r = true;
1698
1699 strcpy(fname, tabledir);
1700 strcat(fname, "/mtables");
1701
1702 if ((f = fopen(fname, "wb")) == NULL)
1703 return false;
1704
1705 for (m = 0; m < NMOVES; m++) {
1706 r = r && fwrite(epose_mtable[m], b, me[0], f) == me[0];
1707 r = r && fwrite(eposs_mtable[m], b, me[1], f) == me[1];
1708 r = r && fwrite(eposm_mtable[m], b, me[2], f) == me[2];
1709 r = r && fwrite(eofb_mtable[m], b, me[3], f) == me[3];
1710 r = r && fwrite(eorl_mtable[m], b, me[4], f) == me[4];
1711 r = r && fwrite(eoud_mtable[m], b, me[5], f) == me[5];
1712 r = r && fwrite(cp_mtable[m], b, me[6], f) == me[6];
1713 r = r && fwrite(coud_mtable[m], b, me[7], f) == me[7];
1714 r = r && fwrite(corl_mtable[m], b, me[8], f) == me[8];
1715 r = r && fwrite(cofb_mtable[m], b, me[9], f) == me[9];
1716 r = r && fwrite(cpos_mtable[m], b, me[10], f) == me[10];
1717 }
1718
1719 fclose(f);
1720 return r;
1721}
1722
1723static bool
1724write_ptable_file(PruneData *pd)
1725{
1726 FILE *f;
1727 char fname[strlen(tabledir)+100];
1728 uint64_t written;
1729
1730 strcpy(fname, tabledir);
1731 strcat(fname, "/");
1732 strcat(fname, pd->filename);
1733
1734 if ((f = fopen(fname, "wb")) == NULL)
1735 return false;
1736
1737 written = fwrite(pd->ptable, sizeof(uint8_t), ptablesize(pd), f);
1738 fclose(f);
1739
1740 return written == ptablesize(pd);
1741}
1742
1743static bool
1744write_symdata_file(SymData *sd)
1745{
1746 FILE *f;
1747 char fname[strlen(tabledir)+100];
1748 uint64_t n = sd->coord->max, *sn = &sd->sym_coord->max;
1749 bool r = true;
1750
1751 strcpy(fname, tabledir);
1752 strcat(fname, "/");
1753 strcat(fname, sd->filename);
1754
1755 if ((f = fopen(fname, "wb")) == NULL)
1756 return false;
1757
1758 r = r && fwrite(&sd->sym_coord->max, sizeof(uint64_t), 1, f) == 1;
1759 r = r && fwrite(sd->rep, sizeof(Cube), *sn, f) == *sn;
1760 r = r && fwrite(sd->class, sizeof(uint64_t), n, f) == n;
1761 r = r && fwrite(sd->transtorep, sizeof(Trans), n, f) == n;
1762
1763 fclose(f);
1764 return r;
1765}
1766
1767static bool
1768write_ttables_file()
1769{
1770 FILE *f;
1771 char fname[strlen(tabledir)+20];
1772 bool r = true;
1773 int b = sizeof(int);
1774 Move m;
1775
1776 strcpy(fname, tabledir);
1777 strcat(fname, "/ttables");
1778
1779 if ((f = fopen(fname, "wb")) == NULL)
1780 return false;
1781
1782 for (m = 0; m < NTRANS; m++) {
1783 r = r && fwrite(epose_ttable[m], b, me[0], f) == me[0];
1784 r = r && fwrite(eposs_ttable[m], b, me[1], f) == me[1];
1785 r = r && fwrite(eposm_ttable[m], b, me[2], f) == me[2];
1786 r = r && fwrite(eo_ttable[m], b, me[3], f) == me[3];
1787 r = r && fwrite(cp_ttable[m], b, me[6], f) == me[6];
1788 r = r && fwrite(co_ttable[m], b, me[7], f) == me[7];
1789 r = r && fwrite(cpos_ttable[m], b, me[10], f) == me[10];
1790 r = r && fwrite(moves_ttable[m], b, me[11], f) == me[11];
1791 }
1792
1793 fclose(f);
1794 return r;
1795}
1796
1797/* Init functions implementation *********************************************/
1798
1799static void
1800init_auxtables()
1801{
1802 Cube c1, c2;
1803 CubeArray *arr;
1804 uint64_t ui, uj;
1805 int i, j, k, auxarr[12];
1806 bool cij, p1, p2;
1807
1808 for (ui = 0; ui < POW2TO11*BINOM12ON4; ui++) {
1809 k = (ui / POW2TO11) * 24;
1810 c1 = admissible_ep((Cube){ .epose = k }, pf_e);
1811 c1.eofb = ui % POW2TO11;
1812 c1 = admissible_eos_from_eofbepos(c1);
1813 admissible_ee_aux[ui] = c1;
1814 }
1815
1816 for (ui = 0; ui < FACTORIAL6; ui++) {
1817 arr = new_cubearray((Cube){.cpos = ui}, pf_cpos);
1818 for (i = 0; i < 6; i++) {
1819 what_center_at_aux[ui][i] = arr->cpos[i];
1820 where_is_center_aux[ui][arr->cpos[i]] = i;
1821 }
1822 free_cubearray(arr, pf_cpos);
1823 }
1824
1825 for (ui = 0; ui < FACTORIAL8; ui++) {
1826 arr = new_cubearray((Cube){.cp = ui}, pf_cp);
1827 for (i = 0; i < 8; i++) {
1828 what_corner_at_aux[ui][i] = arr->cp[i];
1829 where_is_corner_aux[ui][arr->cp[i]] = i;
1830 }
1831 free_cubearray(arr, pf_cp);
1832 }
1833
1834 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
1835 arr = new_cubearray((Cube){.epose = ui}, pf_e);
1836 for (i = 0; i < 12; i++)
1837 if (edge_slice(arr->ep[i]) == 0)
1838 where_is_edge_aux[0][ui][arr->ep[i]] = i;
1839 free_cubearray(arr, pf_e);
1840
1841 arr = new_cubearray((Cube){.eposs = ui}, pf_s);
1842 for (i = 0; i < 12; i++)
1843 if (edge_slice(arr->ep[i]) == 1)
1844 where_is_edge_aux[1][ui][arr->ep[i]] = i;
1845 free_cubearray(arr, pf_s);
1846
1847 arr = new_cubearray((Cube){.eposm = ui}, pf_m);
1848 for (i = 0; i < 12; i++)
1849 if (edge_slice(arr->ep[i]) == 2)
1850 where_is_edge_aux[2][ui][arr->ep[i]] = i;
1851 free_cubearray(arr, pf_m);
1852 }
1853
1854 for (ui = 0; ui < POW3TO7; ui++) {
1855 int_to_sum_zero_array(ui, 3, 8, auxarr);
1856 what_orientation_last_corner_aux[ui] = auxarr[7];
1857 }
1858
1859 for (ui = 0; ui < POW2TO11; ui++) {
1860 int_to_sum_zero_array(ui, 2, 12, auxarr);
1861 what_orientation_last_edge_aux[ui] = auxarr[11];
1862 }
1863
1864 for (ui = 0; ui < BINOM12ON4; ui++)
1865 for (uj = 0; uj < BINOM12ON4; uj++)
1866 epos_dependent_aux[ui][uj]=epos_dependent_pos(ui, uj);
1867
1868 for (i = 0; i < NMOVES; i++) {
1869 for (j = 0; j < NMOVES; j++) {
1870 c1 = apply_move(i, apply_move(j, (Cube){0}));
1871 c2 = apply_move(j, apply_move(i, (Cube){0}));
1872 commute[i][j] = equal(c1, c2) && i && j;
1873 }
1874 }
1875
1876 for (i = 0; i < NMOVES; i++) {
1877 for (j = 0; j < NMOVES; j++) {
1878 for (k = 0; k < NMOVES; k++) {
1879 p1 = j && base_move(j) == base_move(k);
1880 p2 = i && base_move(i) == base_move(k);
1881 cij = commute[i][j];
1882 possible_next[i][j][k] = !(p1 || (cij && p2));
1883 }
1884 }
1885 }
1886
1887 for (i = 0; i < NMOVES; i++)
1888 inverse_move_aux[i] = i ? i + 2 - 2*((i-1)%3) : NULLMOVE;
1889
1890 /* Is there a more elegant way? */
1891 inverse_trans_aux[uf] = uf;
1892 inverse_trans_aux[ur] = ul;
1893 inverse_trans_aux[ul] = ur;
1894 inverse_trans_aux[ub] = ub;
1895
1896 inverse_trans_aux[df] = df;
1897 inverse_trans_aux[dr] = dr;
1898 inverse_trans_aux[dl] = dl;
1899 inverse_trans_aux[db] = db;
1900
1901 inverse_trans_aux[rf] = lf;
1902 inverse_trans_aux[rd] = bl;
1903 inverse_trans_aux[rb] = rb;
1904 inverse_trans_aux[ru] = fr;
1905
1906 inverse_trans_aux[lf] = rf;
1907 inverse_trans_aux[ld] = br;
1908 inverse_trans_aux[lb] = lb;
1909 inverse_trans_aux[lu] = fl;
1910
1911 inverse_trans_aux[fu] = fu;
1912 inverse_trans_aux[fr] = ru;
1913 inverse_trans_aux[fd] = bu;
1914 inverse_trans_aux[fl] = lu;
1915
1916 inverse_trans_aux[bu] = fd;
1917 inverse_trans_aux[br] = ld;
1918 inverse_trans_aux[bd] = bd;
1919 inverse_trans_aux[bl] = rd;
1920
1921 inverse_trans_aux[uf_mirror] = uf_mirror;
1922 inverse_trans_aux[ur_mirror] = ur_mirror;
1923 inverse_trans_aux[ul_mirror] = ul_mirror;
1924 inverse_trans_aux[ub_mirror] = ub_mirror;
1925
1926 inverse_trans_aux[df_mirror] = df_mirror;
1927 inverse_trans_aux[dr_mirror] = dl_mirror;
1928 inverse_trans_aux[dl_mirror] = dr_mirror;
1929 inverse_trans_aux[db_mirror] = db_mirror;
1930
1931 inverse_trans_aux[rf_mirror] = rf_mirror;
1932 inverse_trans_aux[rd_mirror] = br_mirror;
1933 inverse_trans_aux[rb_mirror] = lb_mirror;
1934 inverse_trans_aux[ru_mirror] = fl_mirror;
1935
1936 inverse_trans_aux[lf_mirror] = lf_mirror;
1937 inverse_trans_aux[ld_mirror] = bl_mirror;
1938 inverse_trans_aux[lb_mirror] = rb_mirror;
1939 inverse_trans_aux[lu_mirror] = fr_mirror;
1940
1941 inverse_trans_aux[fu_mirror] = fu_mirror;
1942 inverse_trans_aux[fr_mirror] = lu_mirror;
1943 inverse_trans_aux[fd_mirror] = bu_mirror;
1944 inverse_trans_aux[fl_mirror] = ru_mirror;
1945
1946 inverse_trans_aux[bu_mirror] = fd_mirror;
1947 inverse_trans_aux[br_mirror] = rd_mirror;
1948 inverse_trans_aux[bd_mirror] = bd_mirror;
1949 inverse_trans_aux[bl_mirror] = ld_mirror;
1950}
1951
1952/*
1953 * There is certainly a bette way to do this, but for now I just use
1954 * a "graph coloring" algorithm to compute the left cosets, and I compose
1955 * with every possible cp to get the right cosets (it is possible that I am
1956 * mixing up left and right).
1957 *
1958 * For doing it better "Mathematically", we need 3 things:
1959 * - Checking that cp separates the orbits (UFR,UBL,DFL,DBR) and the other
1960 * This is easy and it is done in the commented function cphtr_cp().
1961 * - Check that there is no ep/cp parity
1962 * - Check that we are not in the "3c" case; this is the part I don't
1963 * know how to do.
1964 */
1965static void
1966init_cphtr_cosets()
1967{
1968 unsigned int i;
1969 int c = 0, d = 0;
1970
1971 for (i = 0; i < FACTORIAL8; i++) {
1972 cphtr_left_cosets[i] = -1;
1973 cphtr_right_cosets[i] = -1;
1974 }
1975
1976 /* First we compute left cosets with a bfs */
1977 for (i = 0; i < FACTORIAL8; i++)
1978 if (cphtr_left_cosets[i] == -1)
1979 init_cphtr_left_cosets_bfs(i, c++);
1980
1981 /* Then we compute right cosets using compose() */
1982 for (i = 0; i < FACTORIAL8; i++)
1983 if (cphtr_right_cosets[i] == -1)
1984 init_cphtr_right_cosets_color(i, d++);
1985}
1986
1987static void
1988init_cphtr_left_cosets_bfs(int i, int c)
1989{
1990 int j, jj, k, next[FACTORIAL8], next2[FACTORIAL8], n, n2;
1991 Move moves[6] = {U2, D2, R2, L2, F2, B2};
1992
1993 n = 1;
1994 next[0] = i;
1995 cphtr_left_cosets[i] = c;
1996
1997 while (n != 0) {
1998 for (j = 0, n2 = 0; j < n; j++) {
1999 for (k = 0; k < 6; k++) {
2000 jj = cp_mtable[moves[k]][next[j]];
2001 if (cphtr_left_cosets[jj] == -1) {
2002 cphtr_left_cosets[jj] = c;
2003 next2[n2++] = jj;
2004 }
2005 }
2006 }
2007
2008 for (j = 0; j < n2; j++)
2009 next[j] = next2[j];
2010 n = n2;
2011 }
2012}
2013
2014static void
2015init_cphtr_right_cosets_color(int i, int d)
2016{
2017 int cp;
2018 unsigned int j;
2019
2020 cphtr_right_rep[d] = i;
2021 for (j = 0; j < FACTORIAL8; j++) {
2022 if (cphtr_left_cosets[j] == 0) {
2023 /* TODO: use antindexer, it's nicer */
2024 cp = compose((Cube){.cp = i}, (Cube){.cp = j}).cp;
2025 cphtr_right_cosets[cp] = d;
2026 }
2027 }
2028}
2029
2030static void
2031init_environment()
2032{
2033 char *nissydata = getenv("NISSYDATA");
2034 char *localdata = getenv("XDG_DATA_HOME");
2035 char *home = getenv("HOME");
2036 bool read, write;
2037
2038 if (nissydata != NULL) {
2039 tabledir = malloc(strlen(nissydata) * sizeof(char) + 20);
2040 strcpy(tabledir, nissydata);
2041 } else if (localdata != NULL) {
2042 tabledir = malloc(strlen(localdata) * sizeof(char) + 20);
2043 strcpy(tabledir, localdata);
2044 strcat(tabledir, "/nissy");
2045 } else if (home != NULL) {
2046 tabledir = malloc(strlen(home) * sizeof(char) + 20);
2047 strcpy(tabledir, home);
2048 strcat(tabledir, "/.nissy");
2049 }
2050
2051 mkdir(tabledir, 0777);
2052 strcat(tabledir, "/tables");
2053 mkdir(tabledir, 0777);
2054
2055 read = !access(tabledir, R_OK);
2056 write = !access(tabledir, W_OK);
2057
2058 if (!read) {
2059 fprintf(stderr, "Table files cannot be read.\n");
2060 } else if (!write) {
2061 fprintf(stderr, "Data directory not writable: ");
2062 fprintf(stderr, "tables can be loaded, but not saved.\n");
2063 }
2064}
2065
2066static void
2067init_moves() {
2068 Cube c;
2069 CubeArray arrs;
2070 int i;
2071 unsigned int ui;
2072 Move m;
2073
2074 /* Generate all move cycles and flips; I do this regardless */
2075 for (i = 0; i < NMOVES; i++) {
2076 if (i == U || i == x || i == y)
2077 continue;
2078
2079 c = apply_alg_generic(equiv_alg[i], (Cube){0}, pf_all, false);
2080
2081 arrs = (CubeArray) {
2082 edge_cycle[i],
2083 eofb_flipped[i],
2084 eorl_flipped[i],
2085 eoud_flipped[i],
2086 corner_cycle[i],
2087 coud_flipped[i],
2088 corl_flipped[i],
2089 cofb_flipped[i],
2090 center_cycle[i]
2091 };
2092 cube_to_arrays(c, &arrs, pf_all);
2093 }
2094
2095 if (read_mtables_file())
2096 return;
2097
2098 fprintf(stderr, "Cannot load %s, generating it\n", "mtables");
2099
2100 /* Initialize transition tables */
2101 for (m = 0; m < NMOVES; m++) {
2102 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
2103 c = (Cube){ .epose = ui };
2104 c = apply_move_cubearray(m, c, pf_e);
2105 epose_mtable[m][ui] = c.epose;
2106
2107 c = (Cube){ .eposs = ui };
2108 c = apply_move_cubearray(m, c, pf_s);
2109 eposs_mtable[m][ui] = c.eposs;
2110
2111 c = (Cube){ .eposm = ui };
2112 c = apply_move_cubearray(m, c, pf_m);
2113 eposm_mtable[m][ui] = c.eposm;
2114 }
2115 for (ui = 0; ui < POW2TO11; ui++ ) {
2116 c = (Cube){ .eofb = ui };
2117 c = apply_move_cubearray(m, c, pf_eo);
2118 eofb_mtable[m][ui] = c.eofb;
2119
2120 c = (Cube){ .eorl = ui };
2121 c = apply_move_cubearray(m, c, pf_eo);
2122 eorl_mtable[m][ui] = c.eorl;
2123
2124 c = (Cube){ .eoud = ui };
2125 c = apply_move_cubearray(m, c, pf_eo);
2126 eoud_mtable[m][ui] = c.eoud;
2127 }
2128 for (ui = 0; ui < POW3TO7; ui++) {
2129 c = (Cube){ .coud = ui };
2130 c = apply_move_cubearray(m, c, pf_co);
2131 coud_mtable[m][ui] = c.coud;
2132
2133 c = (Cube){ .corl = ui };
2134 c = apply_move_cubearray(m, c, pf_co);
2135 corl_mtable[m][ui] = c.corl;
2136
2137 c = (Cube){ .cofb = ui };
2138 c = apply_move_cubearray(m, c, pf_co);
2139 cofb_mtable[m][ui] = c.cofb;
2140 }
2141 for (ui = 0; ui < FACTORIAL8; ui++) {
2142 c = (Cube){ .cp = ui };
2143 c = apply_move_cubearray(m, c, pf_cp);
2144 cp_mtable[m][ui] = c.cp;
2145 }
2146 for (ui = 0; ui < FACTORIAL6; ui++) {
2147 c = (Cube){ .cpos = ui };
2148 c = apply_move_cubearray(m, c, pf_cpos);
2149 cpos_mtable[m][ui] = c.cpos;
2150 }
2151 }
2152
2153 if (!write_mtables_file())
2154 fprintf(stderr, "Error writing mtables\n");
2155}
2156
2157static void
2158init_moves_aux()
2159{
2160 /* Some standard PieceFilters */
2161 pf_all.epose = true;
2162 pf_all.eposs = true;
2163 pf_all.eposm = true;
2164 pf_all.eofb = true;
2165 pf_all.eorl = true;
2166 pf_all.eoud = true;
2167 pf_all.cp = true;
2168 pf_all.cofb = true;
2169 pf_all.corl = true;
2170 pf_all.coud = true;
2171 pf_all.cpos = true;
2172
2173 pf_4val.epose = true;
2174 pf_4val.eposs = true;
2175 pf_4val.eposm = true;
2176 pf_4val.eofb = true;
2177 pf_4val.coud = true;
2178 pf_4val.cp = true;
2179
2180 pf_epcp.epose = true;
2181 pf_epcp.eposs = true;
2182 pf_epcp.eposm = true;
2183 pf_epcp.cp = true;
2184
2185 pf_cpos.cpos = true;
2186
2187 pf_cp.cp = true;
2188
2189 pf_ep.epose = true;
2190 pf_ep.eposs = true;
2191 pf_ep.eposm = true;
2192
2193 pf_e.epose = true;
2194 pf_s.eposs = true;
2195 pf_m.eposm = true;
2196
2197 pf_eo.eofb = true;
2198 pf_eo.eorl = true;
2199 pf_eo.eoud = true;
2200
2201 pf_co.cofb = true;
2202 pf_co.corl = true;
2203 pf_co.coud = true;
2204
2205 /* Used to convert to and from CubeArray */
2206 epe_solved[0] = FR;
2207 epe_solved[1] = FL;
2208 epe_solved[2] = BL;
2209 epe_solved[3] = BR;
2210
2211 eps_solved[0] = UL;
2212 eps_solved[1] = UR;
2213 eps_solved[2] = DL;
2214 eps_solved[3] = DR;
2215
2216 epm_solved[0] = UF;
2217 epm_solved[1] = UB;
2218 epm_solved[2] = DF;
2219 epm_solved[3] = DB;
2220
2221 /* Table sizes, used for reading and writing files */
2222 me[0] = FACTORIAL12/FACTORIAL8;
2223 me[1] = FACTORIAL12/FACTORIAL8;
2224 me[2] = FACTORIAL12/FACTORIAL8;
2225 me[3] = POW2TO11;
2226 me[4] = POW2TO11;
2227 me[5] = POW2TO11;
2228 me[6] = FACTORIAL8;
2229 me[7] = POW3TO7;
2230 me[8] = POW3TO7;
2231 me[9] = POW3TO7;
2232 me[10] = FACTORIAL6;
2233 me[11] = NMOVES;
2234
2235 /* Cycles *********************/
2236 edge_cycle[U][UF] = UR;
2237 edge_cycle[U][UL] = UF;
2238 edge_cycle[U][UB] = UL;
2239 edge_cycle[U][UR] = UB;
2240 edge_cycle[U][DF] = DF;
2241 edge_cycle[U][DL] = DL;
2242 edge_cycle[U][DB] = DB;
2243 edge_cycle[U][DR] = DR;
2244 edge_cycle[U][FR] = FR;
2245 edge_cycle[U][FL] = FL;
2246 edge_cycle[U][BL] = BL;
2247 edge_cycle[U][BR] = BR;
2248
2249 edge_cycle[x][UF] = DF;
2250 edge_cycle[x][UL] = FL;
2251 edge_cycle[x][UB] = UF;
2252 edge_cycle[x][UR] = FR;
2253 edge_cycle[x][DF] = DB;
2254 edge_cycle[x][DL] = BL;
2255 edge_cycle[x][DB] = UB;
2256 edge_cycle[x][DR] = BR;
2257 edge_cycle[x][FR] = DR;
2258 edge_cycle[x][FL] = DL;
2259 edge_cycle[x][BL] = UL;
2260 edge_cycle[x][BR] = UR;
2261
2262 edge_cycle[y][UF] = UR;
2263 edge_cycle[y][UL] = UF;
2264 edge_cycle[y][UB] = UL;
2265 edge_cycle[y][UR] = UB;
2266 edge_cycle[y][DF] = DR;
2267 edge_cycle[y][DL] = DF;
2268 edge_cycle[y][DB] = DL;
2269 edge_cycle[y][DR] = DB;
2270 edge_cycle[y][FR] = BR;
2271 edge_cycle[y][FL] = FR;
2272 edge_cycle[y][BL] = FL;
2273 edge_cycle[y][BR] = BL;
2274
2275 corner_cycle[U][UFR] = UBR;
2276 corner_cycle[U][UFL] = UFR;
2277 corner_cycle[U][UBL] = UFL;
2278 corner_cycle[U][UBR] = UBL;
2279 corner_cycle[U][DFR] = DFR;
2280 corner_cycle[U][DFL] = DFL;
2281 corner_cycle[U][DBL] = DBL;
2282 corner_cycle[U][DBR] = DBR;
2283
2284 corner_cycle[x][UFR] = DFR;
2285 corner_cycle[x][UFL] = DFL;
2286 corner_cycle[x][UBL] = UFL;
2287 corner_cycle[x][UBR] = UFR;
2288 corner_cycle[x][DFR] = DBR;
2289 corner_cycle[x][DFL] = DBL;
2290 corner_cycle[x][DBL] = UBL;
2291 corner_cycle[x][DBR] = UBR;
2292
2293 corner_cycle[y][UFR] = UBR;
2294 corner_cycle[y][UFL] = UFR;
2295 corner_cycle[y][UBL] = UFL;
2296 corner_cycle[y][UBR] = UBL;
2297 corner_cycle[y][DFR] = DBR;
2298 corner_cycle[y][DFL] = DFR;
2299 corner_cycle[y][DBL] = DFL;
2300 corner_cycle[y][DBR] = DBL;
2301
2302 center_cycle[U][U_center] = U_center;
2303 center_cycle[U][D_center] = D_center;
2304 center_cycle[U][R_center] = R_center;
2305 center_cycle[U][L_center] = L_center;
2306 center_cycle[U][F_center] = F_center;
2307 center_cycle[U][B_center] = B_center;
2308
2309 center_cycle[x][U_center] = F_center;
2310 center_cycle[x][D_center] = B_center;
2311 center_cycle[x][R_center] = R_center;
2312 center_cycle[x][L_center] = L_center;
2313 center_cycle[x][F_center] = D_center;
2314 center_cycle[x][B_center] = U_center;
2315
2316 center_cycle[y][U_center] = U_center;
2317 center_cycle[y][D_center] = D_center;
2318 center_cycle[y][R_center] = B_center;
2319 center_cycle[y][L_center] = F_center;
2320 center_cycle[y][F_center] = R_center;
2321 center_cycle[y][B_center] = L_center;
2322
2323 /* Flipped pieces *************/
2324 eofb_flipped[x][UF] = 1;
2325 eofb_flipped[x][UB] = 1;
2326 eofb_flipped[x][DF] = 1;
2327 eofb_flipped[x][DB] = 1;
2328
2329 eofb_flipped[y][FR] = 1;
2330 eofb_flipped[y][FL] = 1;
2331 eofb_flipped[y][BL] = 1;
2332 eofb_flipped[y][BR] = 1;
2333
2334 eorl_flipped[x][UF] = 1;
2335 eorl_flipped[x][UL] = 1;
2336 eorl_flipped[x][UB] = 1;
2337 eorl_flipped[x][UR] = 1;
2338 eorl_flipped[x][DF] = 1;
2339 eorl_flipped[x][DL] = 1;
2340 eorl_flipped[x][DB] = 1;
2341 eorl_flipped[x][DR] = 1;
2342 eorl_flipped[x][FR] = 1;
2343 eorl_flipped[x][FL] = 1;
2344 eorl_flipped[x][BL] = 1;
2345 eorl_flipped[x][BR] = 1;
2346
2347 eorl_flipped[y][FR] = 1;
2348 eorl_flipped[y][FL] = 1;
2349 eorl_flipped[y][BL] = 1;
2350 eorl_flipped[y][BR] = 1;
2351
2352 eoud_flipped[U][UF] = 1;
2353 eoud_flipped[U][UL] = 1;
2354 eoud_flipped[U][UB] = 1;
2355 eoud_flipped[U][UR] = 1;
2356
2357 eoud_flipped[x][UF] = 1;
2358 eoud_flipped[x][UB] = 1;
2359 eoud_flipped[x][DF] = 1;
2360 eoud_flipped[x][DB] = 1;
2361
2362 eoud_flipped[y][UF] = 1;
2363 eoud_flipped[y][UL] = 1;
2364 eoud_flipped[y][UB] = 1;
2365 eoud_flipped[y][UR] = 1;
2366 eoud_flipped[y][DF] = 1;
2367 eoud_flipped[y][DL] = 1;
2368 eoud_flipped[y][DB] = 1;
2369 eoud_flipped[y][DR] = 1;
2370 eoud_flipped[y][FR] = 1;
2371 eoud_flipped[y][FL] = 1;
2372 eoud_flipped[y][BL] = 1;
2373 eoud_flipped[y][BR] = 1;
2374
2375 coud_flipped[x][UFR] = 2;
2376 coud_flipped[x][UFL] = 1;
2377 coud_flipped[x][UBR] = 1;
2378 coud_flipped[x][UBL] = 2;
2379 coud_flipped[x][DFR] = 1;
2380 coud_flipped[x][DFL] = 2;
2381 coud_flipped[x][DBR] = 2;
2382 coud_flipped[x][DBL] = 1;
2383
2384 corl_flipped[U][UFR] = 1;
2385 corl_flipped[U][UFL] = 2;
2386 corl_flipped[U][UBL] = 1;
2387 corl_flipped[U][UBR] = 2;
2388
2389 corl_flipped[y][UFR] = 1;
2390 corl_flipped[y][UFL] = 2;
2391 corl_flipped[y][UBL] = 1;
2392 corl_flipped[y][UBR] = 2;
2393 corl_flipped[y][DFR] = 2;
2394 corl_flipped[y][DFL] = 1;
2395 corl_flipped[y][DBL] = 2;
2396 corl_flipped[y][DBR] = 1;
2397
2398 cofb_flipped[U][UFR] = 2;
2399 cofb_flipped[U][UFL] = 1;
2400 cofb_flipped[U][UBL] = 2;
2401 cofb_flipped[U][UBR] = 1;
2402
2403 cofb_flipped[x][UFR] = 1;
2404 cofb_flipped[x][UFL] = 2;
2405 cofb_flipped[x][UBL] = 1;
2406 cofb_flipped[x][UBR] = 2;
2407 cofb_flipped[x][DFR] = 2;
2408 cofb_flipped[x][DFL] = 1;
2409 cofb_flipped[x][DBL] = 2;
2410 cofb_flipped[x][DBR] = 1;
2411
2412 cofb_flipped[y][UFR] = 2;
2413 cofb_flipped[y][UFL] = 1;
2414 cofb_flipped[y][UBL] = 2;
2415 cofb_flipped[y][UBR] = 1;
2416 cofb_flipped[y][DFR] = 1;
2417 cofb_flipped[y][DFL] = 2;
2418 cofb_flipped[y][DBL] = 1;
2419 cofb_flipped[y][DBR] = 2;
2420
2421 /* Equivalent moves ***********/
2422 equiv_alg[NULLMOVE] = new_alg("");
2423
2424 equiv_alg[U] = new_alg(" U ");
2425 equiv_alg[U2] = new_alg(" UU ");
2426 equiv_alg[U3] = new_alg(" UUU ");
2427 equiv_alg[D] = new_alg(" xx U xx ");
2428 equiv_alg[D2] = new_alg(" xx UU xx ");
2429 equiv_alg[D3] = new_alg(" xx UUU xx ");
2430 equiv_alg[R] = new_alg(" yx U xxxyyy ");
2431 equiv_alg[R2] = new_alg(" yx UU xxxyyy ");
2432 equiv_alg[R3] = new_alg(" yx UUU xxxyyy ");
2433 equiv_alg[L] = new_alg(" yyyx U xxxy ");
2434 equiv_alg[L2] = new_alg(" yyyx UU xxxy ");
2435 equiv_alg[L3] = new_alg(" yyyx UUU xxxy ");
2436 equiv_alg[F] = new_alg(" x U xxx ");
2437 equiv_alg[F2] = new_alg(" x UU xxx ");
2438 equiv_alg[F3] = new_alg(" x UUU xxx ");
2439 equiv_alg[B] = new_alg(" xxx U x ");
2440 equiv_alg[B2] = new_alg(" xxx UU x ");
2441 equiv_alg[B3] = new_alg(" xxx UUU x ");
2442
2443 equiv_alg[Uw] = new_alg(" xx U xx y ");
2444 equiv_alg[Uw2] = new_alg(" xx UU xx yy ");
2445 equiv_alg[Uw3] = new_alg(" xx UUU xx yyy ");
2446 equiv_alg[Dw] = new_alg(" U yyy ");
2447 equiv_alg[Dw2] = new_alg(" UU yy ");
2448 equiv_alg[Dw3] = new_alg(" UUU y ");
2449 equiv_alg[Rw] = new_alg(" yyyx U xxxy x ");
2450 equiv_alg[Rw2] = new_alg(" yyyx UU xxxy xx ");
2451 equiv_alg[Rw3] = new_alg(" yyyx UUU xxxy xxx ");
2452 equiv_alg[Lw] = new_alg(" yx U xxxyyy xxx ");
2453 equiv_alg[Lw2] = new_alg(" yx UU xxxyyy xx ");
2454 equiv_alg[Lw3] = new_alg(" yx UUU xxxyyy x ");
2455 equiv_alg[Fw] = new_alg(" xxx U x yxxxyyy ");
2456 equiv_alg[Fw2] = new_alg(" xxx UU x yxxyyy ");
2457 equiv_alg[Fw3] = new_alg(" xxx UUU x yxyyy ");
2458 equiv_alg[Bw] = new_alg(" x U xxx yxyyy ");
2459 equiv_alg[Bw2] = new_alg(" x UU xxx yxxyyy ");
2460 equiv_alg[Bw3] = new_alg(" x UUU xxx yxxxyyy ");
2461
2462 equiv_alg[M] = new_alg(" yx U xx UUU yxyyy ");
2463 equiv_alg[M2] = new_alg(" yx UU xx UU xxxy ");
2464 equiv_alg[M3] = new_alg(" yx UUU xx U yxxxy ");
2465 equiv_alg[S] = new_alg(" x UUU xx U yyyx ");
2466 equiv_alg[S2] = new_alg(" x UU xx UU yyx ");
2467 equiv_alg[S3] = new_alg(" x U xx UUU yx ");
2468 equiv_alg[E] = new_alg(" U xx UUU xxyyy ");
2469 equiv_alg[E2] = new_alg(" UU xx UU xxyy ");
2470 equiv_alg[E3] = new_alg(" UUU xx U xxy ");
2471
2472 equiv_alg[x] = new_alg(" x ");
2473 equiv_alg[x2] = new_alg(" xx ");
2474 equiv_alg[x3] = new_alg(" xxx ");
2475 equiv_alg[y] = new_alg(" y ");
2476 equiv_alg[y2] = new_alg(" yy ");
2477 equiv_alg[y3] = new_alg(" yyy ");
2478 equiv_alg[z] = new_alg(" yyy x y ");
2479 equiv_alg[z2] = new_alg(" yy xx ");
2480 equiv_alg[z3] = new_alg(" y x yyy ");
2481}
2482
2483static void
2484init_strings()
2485{
2486 strcpy(move_string [NULLMOVE], "-" );
2487 strcpy(move_string [U], "U" );
2488 strcpy(move_string [U2], "U2" );
2489 strcpy(move_string [U3], "U\'" );
2490 strcpy(move_string [D], "D" );
2491 strcpy(move_string [D2], "D2" );
2492 strcpy(move_string [D3], "D\'" );
2493 strcpy(move_string [R], "R" );
2494 strcpy(move_string [R2], "R2" );
2495 strcpy(move_string [R3], "R\'" );
2496 strcpy(move_string [L], "L" );
2497 strcpy(move_string [L2], "L2" );
2498 strcpy(move_string [L3], "L\'" );
2499 strcpy(move_string [F], "F" );
2500 strcpy(move_string [F2], "F2" );
2501 strcpy(move_string [F3], "F\'" );
2502 strcpy(move_string [B], "B" );
2503 strcpy(move_string [B2], "B2" );
2504 strcpy(move_string [B3], "B\'" );
2505 strcpy(move_string [Uw], "Uw" );
2506 strcpy(move_string [Uw2], "Uw2" );
2507 strcpy(move_string [Uw3], "Uw\'" );
2508 strcpy(move_string [Dw], "Dw" );
2509 strcpy(move_string [Dw2], "Dw2" );
2510 strcpy(move_string [Dw3], "Dw\'" );
2511 strcpy(move_string [Rw], "Rw" );
2512 strcpy(move_string [Rw2], "Rw2" );
2513 strcpy(move_string [Rw3], "Rw\'" );
2514 strcpy(move_string [Lw], "Lw" );
2515 strcpy(move_string [Lw2], "Lw2" );
2516 strcpy(move_string [Lw3], "Lw\'" );
2517 strcpy(move_string [Fw], "Fw" );
2518 strcpy(move_string [Fw2], "Fw2" );
2519 strcpy(move_string [Fw3], "Fw\'" );
2520 strcpy(move_string [Bw], "Bw" );
2521 strcpy(move_string [Bw2], "Bw2" );
2522 strcpy(move_string [Bw3], "Bw\'" );
2523 strcpy(move_string [M], "M" );
2524 strcpy(move_string [M2], "M2" );
2525 strcpy(move_string [M3], "M\'" );
2526 strcpy(move_string [S], "S" );
2527 strcpy(move_string [S2], "S2" );
2528 strcpy(move_string [S3], "S\'" );
2529 strcpy(move_string [E], "E" );
2530 strcpy(move_string [E2], "E2" );
2531 strcpy(move_string [E3], "E\'" );
2532 strcpy(move_string [x], "x" );
2533 strcpy(move_string [x2], "x2" );
2534 strcpy(move_string [x3], "x\'" );
2535 strcpy(move_string [y], "y" );
2536 strcpy(move_string [y2], "y2" );
2537 strcpy(move_string [y3], "y\'" );
2538 strcpy(move_string [z], "z" );
2539 strcpy(move_string [z2], "z2" );
2540 strcpy(move_string [z3], "z\'" );
2541
2542 strcpy(edge_string [UF], "UF" );
2543 strcpy(edge_string [UL], "UL" );
2544 strcpy(edge_string [UB], "UB" );
2545 strcpy(edge_string [UR], "UR" );
2546 strcpy(edge_string [DF], "DF" );
2547 strcpy(edge_string [DL], "DL" );
2548 strcpy(edge_string [DB], "DB" );
2549 strcpy(edge_string [DR], "DR" );
2550 strcpy(edge_string [FR], "FR" );
2551 strcpy(edge_string [FL], "FL" );
2552 strcpy(edge_string [BL], "BL" );
2553 strcpy(edge_string [BR], "BR" );
2554
2555 strcpy(corner_string [UFR], "UFR" );
2556 strcpy(corner_string [UFL], "UFL" );
2557 strcpy(corner_string [UBL], "UBL" );
2558 strcpy(corner_string [UBR], "UBR" );
2559 strcpy(corner_string [DFR], "DFR" );
2560 strcpy(corner_string [DFL], "DFL" );
2561 strcpy(corner_string [DBL], "DBL" );
2562 strcpy(corner_string [DBR], "DBR" );
2563
2564 strcpy(center_string [U_center], "U" );
2565 strcpy(center_string [D_center], "D" );
2566 strcpy(center_string [R_center], "R" );
2567 strcpy(center_string [L_center], "L" );
2568 strcpy(center_string [F_center], "F" );
2569 strcpy(center_string [B_center], "B" );
2570}
2571
2572static void
2573init_symdata()
2574{
2575 int i;
2576
2577 for (i = 0; i < n_all_symdata; i++)
2578 gensym(all_sd[i]);
2579}
2580
2581static void
2582init_trans() {
2583 Cube aux, cube, mirr, c[3];
2584 CubeArray epcp;
2585 int i, eparr[12], eoarr[12], cparr[8], coarr[8];
2586 unsigned int ui;
2587 Move mi, move;
2588 Trans m;
2589
2590 /* Compute sources */
2591 for (i = 0; i < NTRANS; i++) {
2592 cube = apply_alg(rotation_algs[i % NROTATIONS], (Cube){0});
2593
2594 epose_source[i] = edge_slice(what_edge_at(cube, FR));
2595 eposs_source[i] = edge_slice(what_edge_at(cube, UR));
2596 eposm_source[i] = edge_slice(what_edge_at(cube, UF));
2597 eofb_source[i] = what_center_at(cube, F_center)/2;
2598 eorl_source[i] = what_center_at(cube, R_center)/2;
2599 eoud_source[i] = what_center_at(cube, U_center)/2;
2600 coud_source[i] = what_center_at(cube, U_center)/2;
2601 cofb_source[i] = what_center_at(cube, F_center)/2;
2602 corl_source[i] = what_center_at(cube, R_center)/2;
2603 }
2604
2605 if (read_ttables_file())
2606 return;
2607
2608 fprintf(stderr, "Cannot load %s, generating it\n", "ttables");
2609
2610 /* Initialize tables */
2611 for (m = 0; m < NTRANS; m++) {
2612 epcp = (CubeArray){ .ep = eparr, .cp = cparr };
2613 cube = apply_alg(rotation_algs[m % NROTATIONS], (Cube){0});
2614 cube_to_arrays(cube, &epcp, pf_epcp);
2615 if (m >= NROTATIONS) {
2616 apply_permutation(ep_mirror, eparr, 12);
2617 apply_permutation(cp_mirror, cparr, 8);
2618 }
2619
2620 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
2621 c[0] = admissible_ep((Cube){ .epose = ui }, pf_e);
2622 c[1] = admissible_ep((Cube){ .eposs = ui }, pf_s);
2623 c[2] = admissible_ep((Cube){ .eposm = ui }, pf_m);
2624
2625 cube = rotate_via_compose(m,c[epose_source[m]],pf_ep);
2626 epose_ttable[m][ui] = cube.epose;
2627
2628 cube = rotate_via_compose(m,c[eposs_source[m]],pf_ep);
2629 eposs_ttable[m][ui] = cube.eposs;
2630
2631 cube = rotate_via_compose(m,c[eposm_source[m]],pf_ep);
2632 eposm_ttable[m][ui] = cube.eposm;
2633 }
2634 for (ui = 0; ui < POW2TO11; ui++ ) {
2635 int_to_sum_zero_array(ui, 2, 12, eoarr);
2636 apply_permutation(eparr, eoarr, 12);
2637 eo_ttable[m][ui] = digit_array_to_int(eoarr, 11, 2);
2638 }
2639 for (ui = 0; ui < POW3TO7; ui++) {
2640 int_to_sum_zero_array(ui, 3, 8, coarr);
2641 apply_permutation(cparr, coarr, 8);
2642 co_ttable[m][ui] = digit_array_to_int(coarr, 7, 3);
2643 if (m >= NROTATIONS)
2644 co_ttable[m][ui] =
2645 invert_digits(co_ttable[m][ui], 3, 7);
2646 }
2647 for (ui = 0; ui < FACTORIAL8; ui++) {
2648 cube = (Cube){ .cp = ui };
2649 cube = rotate_via_compose(m, cube, pf_cp);
2650 cp_ttable[m][ui] = cube.cp;
2651 }
2652 for (ui = 0; ui < FACTORIAL6; ui++) {
2653 cube = (Cube){ .cpos = ui };
2654 cube = rotate_via_compose(m, cube, pf_cpos);
2655 cpos_ttable[m][ui] = cube.cpos;
2656 }
2657 for (mi = 0; mi < NMOVES; mi++) {
2658 aux = apply_trans(m, apply_move(mi, (Cube){0}));
2659 for (move = 0; move < NMOVES; move++) {
2660 cube = apply_move(inverse_move_aux[move], aux);
2661 mirr = apply_trans(uf_mirror, cube);
2662 if (is_solved(cube, false) ||
2663 is_solved(mirr, false))
2664 moves_ttable[m][mi] = move;
2665 }
2666 }
2667 }
2668
2669 if (!write_ttables_file())
2670 fprintf(stderr, "Error writing ttables\n");
2671}
2672
2673static void
2674init_trans_aux()
2675{
2676 ep_mirror[UF] = UF;
2677 ep_mirror[UL] = UR;
2678 ep_mirror[UB] = UB;
2679 ep_mirror[UR] = UL;
2680 ep_mirror[DF] = DF;
2681 ep_mirror[DL] = DR;
2682 ep_mirror[DB] = DB;
2683 ep_mirror[DR] = DL;
2684 ep_mirror[FR] = FL;
2685 ep_mirror[FL] = FR;
2686 ep_mirror[BR] = BL;
2687 ep_mirror[BL] = BR;
2688
2689 cp_mirror[UFR] = UFL;
2690 cp_mirror[UFL] = UFR;
2691 cp_mirror[UBL] = UBR;
2692 cp_mirror[UBR] = UBL;
2693 cp_mirror[DFR] = DFL;
2694 cp_mirror[DFL] = DFR;
2695 cp_mirror[DBL] = DBR;
2696 cp_mirror[DBR] = DBL;
2697
2698 cpos_mirror[U_center] = U_center;
2699 cpos_mirror[D_center] = D_center;
2700 cpos_mirror[R_center] = L_center;
2701 cpos_mirror[L_center] = R_center;
2702 cpos_mirror[F_center] = F_center;
2703 cpos_mirror[B_center] = B_center;
2704
2705 /* Is there a more elegant way? */
2706 rotation_algs[uf] = new_alg("");
2707 rotation_algs[ur] = new_alg("y");
2708 rotation_algs[ub] = new_alg("y2");
2709 rotation_algs[ul] = new_alg("y3");
2710
2711 rotation_algs[df] = new_alg("z2");
2712 rotation_algs[dr] = new_alg("y z2");
2713 rotation_algs[db] = new_alg("x2");
2714 rotation_algs[dl] = new_alg("y3 z2");
2715
2716 rotation_algs[rf] = new_alg("z3");
2717 rotation_algs[rd] = new_alg("z3 y");
2718 rotation_algs[rb] = new_alg("z3 y2");
2719 rotation_algs[ru] = new_alg("z3 y3");
2720
2721 rotation_algs[lf] = new_alg("z");
2722 rotation_algs[ld] = new_alg("z y3");
2723 rotation_algs[lb] = new_alg("z y2");
2724 rotation_algs[lu] = new_alg("z y");
2725
2726 rotation_algs[fu] = new_alg("x y2");
2727 rotation_algs[fr] = new_alg("x y");
2728 rotation_algs[fd] = new_alg("x");
2729 rotation_algs[fl] = new_alg("x y3");
2730
2731 rotation_algs[bu] = new_alg("x3");
2732 rotation_algs[br] = new_alg("x3 y");
2733 rotation_algs[bd] = new_alg("x3 y2");
2734 rotation_algs[bl] = new_alg("x3 y3");
2735}
2736
2737
2738/* Public functions implementation *******************************************/
2739
2740Cube
2741apply_alg(Alg *alg, Cube cube)
2742{
2743 return apply_alg_generic(alg, cube, pf_all, true);
2744}
2745
2746Cube
2747apply_move(Move m, Cube cube)
2748{
2749 return (Cube) {
2750 .epose = epose_mtable[m][cube.epose],
2751 .eposs = eposs_mtable[m][cube.eposs],
2752 .eposm = eposm_mtable[m][cube.eposm],
2753 .eofb = eofb_mtable[m][cube.eofb],
2754 .eorl = eorl_mtable[m][cube.eorl],
2755 .eoud = eoud_mtable[m][cube.eoud],
2756 .coud = coud_mtable[m][cube.coud],
2757 .cofb = cofb_mtable[m][cube.cofb],
2758 .corl = corl_mtable[m][cube.corl],
2759 .cp = cp_mtable[m][cube.cp],
2760 .cpos = cpos_mtable[m][cube.cpos]
2761 };
2762}
2763
2764
2765Cube
2766apply_trans(Trans t, Cube cube)
2767{
2768 int aux_epos[3] = { cube.epose, cube.eposs, cube.eposm };
2769 int aux_eo[3] = { cube.eoud, cube.eorl, cube.eofb };
2770 int aux_co[3] = { cube.coud, cube.corl, cube.cofb };
2771
2772 return (Cube) {
2773 .epose = epose_ttable[t][aux_epos[epose_source[t]]],
2774 .eposs = eposs_ttable[t][aux_epos[eposs_source[t]]],
2775 .eposm = eposm_ttable[t][aux_epos[eposm_source[t]]],
2776 .eofb = eo_ttable[t][aux_eo[eofb_source[t]]],
2777 .eorl = eo_ttable[t][aux_eo[eorl_source[t]]],
2778 .eoud = eo_ttable[t][aux_eo[eoud_source[t]]],
2779 .coud = co_ttable[t][aux_co[coud_source[t]]],
2780 .corl = co_ttable[t][aux_co[corl_source[t]]],
2781 .cofb = co_ttable[t][aux_co[cofb_source[t]]],
2782 .cp = cp_ttable[t][cube.cp],
2783 .cpos = cpos_ttable[t][cube.cpos]
2784 };
2785}
2786
2787Move
2788base_move(Move m)
2789{
2790 if (m == NULLMOVE)
2791 return NULLMOVE;
2792 else
2793 return m - (m-1)%3;
2794}
2795
2796Cube
2797compose(Cube c2, Cube c1)
2798{
2799 return compose_filtered(c2, c1, pf_all);
2800}
2801
2802/*TODO maybe move the next two */
2803uint64_t
2804cphtr(Cube cube)
2805{
2806 return cphtr_right_cosets[cube.cp];
2807}
2808
2809Cube
2810anti_cphtr(uint64_t ind)
2811{
2812 return (Cube) { .cp = cphtr_right_rep[ind] };
2813}
2814
2815uint64_t
2816epos_dependent(Cube c)
2817{
2818 return epos_dependent_aux[c.eposs/FACTORIAL4][c.epose/FACTORIAL4];
2819}
2820
2821bool
2822equal(Cube c1, Cube c2)
2823{
2824 return c1.eofb == c2.eofb &&
2825 c1.epose == c2.epose &&
2826 c1.eposs == c2.eposs &&
2827 c1.eposm == c2.eposm &&
2828 c1.coud == c2.coud &&
2829 c1.cp == c2.cp &&
2830 c1.cpos == c2.cpos;
2831}
2832
2833void
2834genptable(PruneData *pd)
2835{
2836 Cube cube;
2837 uint64_t j, oldn = 0;
2838 DfsData dd = {
2839 .m = 0,
2840 .last1 = NULLMOVE,
2841 .last2 = NULLMOVE
2842 };
2843
2844 if (pd->generated)
2845 return;
2846
2847 /* TODO: check if memory is enough, otherwise maybe crash gracefully? */
2848 pd->ptable = malloc(ptablesize(pd) * sizeof(uint8_t));
2849
2850 if (read_ptable_file(pd)) {
2851 pd->generated = true;
2852 return;
2853 }
2854
2855 fprintf(stderr, "Cannot load %s, generating it\n", pd->filename);
2856
2857 /* We use 4 bits per value, so any distance >= 15 is set to 15 */
2858 for (j = 0; j < pd->coord->max; j++)
2859 ptable_update(pd, pd->coord->cube(j), 15);
2860
2861 moveset_to_list(pd->moveset, NULL, dd.sorted_moves);
2862 movelist_to_position(dd.sorted_moves, dd.move_position);
2863
2864 for (dd.d = 0, pd->n = 0; dd.d < 15 && pd->n < pd->coord->max; dd.d++) {
2865 for (j = 0; j < pd->coord->max; j++) {
2866 cube = pd->coord->cube(j);
2867 if (pd->coord->check(cube))
2868 genptable_dfs(cube, pd, &dd);
2869 }
2870 fprintf(stderr, "Depth %d done, generated %lu\t(%lu/%lu)\n",
2871 dd.d, pd->n-oldn, pd->n, pd->coord->max);
2872 oldn = pd->n;
2873 }
2874
2875 if (!write_ptable_file(pd))
2876 fprintf(stderr, "Error writing ptable file\n");
2877
2878 pd->generated = true;
2879}
2880
2881Cube
2882inverse_cube(Cube cube)
2883{
2884 CubeArray *arr = new_cubearray(cube, pf_all);
2885 CubeArray *inv = new_cubearray((Cube){0}, pf_all);
2886 Cube ret;
2887 int i;
2888
2889 for (i = 0; i < 12; i++) {
2890 inv->ep[arr->ep[i]] = i;
2891 inv->eofb[arr->ep[i]] = arr->eofb[i];
2892 inv->eorl[arr->ep[i]] = arr->eorl[i];
2893 inv->eoud[arr->ep[i]] = arr->eoud[i];
2894 }
2895
2896 for (i = 0; i < 8; i++) {
2897 inv->cp[arr->cp[i]] = i;
2898 inv->coud[arr->cp[i]] = (3 - arr->coud[i]) % 3;
2899 inv->corl[arr->cp[i]] = (3 - arr->corl[i]) % 3;
2900 inv->cofb[arr->cp[i]] = (3 - arr->cofb[i]) % 3;
2901 }
2902
2903 for (int i = 0; i < 6; i++)
2904 inv->cpos[arr->cpos[i]] = i;
2905
2906 ret = arrays_to_cube(inv, pf_all);
2907 free_cubearray(arr, pf_all);
2908 free_cubearray(inv, pf_all);
2909
2910 return ret;
2911}
2912
2913Move
2914inverse_move(Move m)
2915{
2916 return inverse_move_aux[m];
2917}
2918
2919Trans
2920inverse_trans(Trans t)
2921{
2922 return inverse_trans_aux[t];
2923}
2924
2925bool
2926is_admissible(Cube cube)
2927{
2928 /* TODO: this should check consistency of different orientations */
2929 /* TODO: check that centers are opposite and admissible */
2930
2931 CubeArray *a = new_cubearray(cube, pf_all);
2932 int parity;
2933 bool perm;
2934
2935 perm = is_perm(a->ep, 12) &&
2936 is_perm(a->cp, 8) &&
2937 is_perm(a->cpos, 6);
2938 parity = perm_sign(a->ep, 12) +
2939 perm_sign(a->cp, 8) +
2940 perm_sign(a->cpos, 6);
2941
2942 return perm && parity % 2 == 0;
2943}
2944
2945bool
2946is_solved(Cube cube, bool reorient)
2947{
2948 int i;
2949
2950 if (reorient) {
2951 for (i = 0; i < NROTATIONS; i++)
2952 if (is_solved(apply_alg(rotation_algs[i], cube),false))
2953 return true;
2954 return false;
2955 } else {
2956 return equal(cube, (Cube){0});
2957 }
2958}
2959
2960bool
2961is_solved_block(Cube cube, Block block)
2962{
2963 int i;
2964
2965 for (i = 0; i < 12; i++)
2966 if (block.edge[i] && !is_solved_edge(cube, i))
2967 return false;
2968 for (i = 0; i < 8; i++)
2969 if (block.corner[i] && !is_solved_corner(cube, i))
2970 return false;
2971 for (i = 0; i < 6; i++)
2972 if (block.center[i] && !is_solved_center(cube, i))
2973 return false;
2974
2975 return true;
2976}
2977
2978bool
2979is_solved_center(Cube cube, Center c)
2980{
2981 return what_center_at(cube, c) == c;
2982}
2983
2984bool
2985is_solved_corner(Cube cube, Corner c)
2986{
2987 return what_corner_at(cube, c) == c &&
2988 what_orientation_corner(cube.coud, c);
2989}
2990
2991bool
2992is_solved_edge(Cube cube, Edge e)
2993{
2994 return what_edge_at(cube, e) == e &&
2995 what_orientation_edge(cube.eofb, e);
2996}
2997
2998int
2999piece_orientation(Cube cube, int piece, char *orientation)
3000{
3001 int arr[12], n, b, x;
3002
3003 if (!strcmp(orientation, "eofb")) {
3004 x = cube.eofb;
3005 n = 12;
3006 b = 2;
3007 } else if (!strcmp(orientation, "eorl")) {
3008 x = cube.eorl;
3009 n = 12;
3010 b = 2;
3011 } else if (!strcmp(orientation, "eoud")) {
3012 x = cube.eoud;
3013 n = 12;
3014 b = 2;
3015 } else if (!strcmp(orientation, "coud")) {
3016 x = cube.coud;
3017 n = 8;
3018 b = 3;
3019 } else if (!strcmp(orientation, "corl")) {
3020 x = cube.corl;
3021 n = 8;
3022 b = 3;
3023 } else if (!strcmp(orientation, "cofb")) {
3024 x = cube.cofb;
3025 n = 8;
3026 b = 3;
3027 } else {
3028 return -1;
3029 }
3030
3031 int_to_sum_zero_array(x, b, n, arr);
3032 if (piece < n)
3033 return arr[piece];
3034
3035 return -1;
3036}
3037
3038void
3039print_cube(Cube cube)
3040{
3041/*
3042 CubeArray *arr = new_cubearray(cube, pf_all);
3043
3044 for (int i = 0; i < 12; i++)
3045 printf(" %s ", edge_string[arr->ep[i]]);
3046 printf("\n");
3047
3048 for (int i = 0; i < 12; i++)
3049 printf(" %c ", arr->eofb[i] + '0');
3050 printf("\n");
3051
3052 for (int i = 0; i < 8; i++)
3053 printf("%s ", corner_string[arr->cp[i]]);
3054 printf("\n");
3055
3056 for (int i = 0; i < 8; i++)
3057 printf(" %c ", arr->coud[i] + '0');
3058 printf("\n");
3059
3060 for (int i = 0; i < 6; i++)
3061 printf(" %s ", center_string[arr->cpos[i]]);
3062 printf("\n");
3063
3064 free_cubearray(arr, pf_all);
3065*/
3066
3067 for (int i = 0; i < 12; i++)
3068 printf(" %s ", edge_string[what_edge_at(cube, i)]);
3069 printf("\n");
3070
3071 for (int i = 0; i < 12; i++)
3072 printf(" %d ", what_orientation_edge(cube.eofb, i));
3073 printf("\n");
3074
3075 for (int i = 0; i < 8; i++)
3076 printf("%s ", corner_string[what_corner_at(cube, i)]);
3077 printf("\n");
3078
3079 for (int i = 0; i < 8; i++)
3080 printf(" %d ", what_orientation_corner(cube.coud, i));
3081 printf("\n");
3082
3083 for (int i = 0; i < 6; i++)
3084 printf(" %s ", center_string[what_center_at(cube, i)]);
3085 printf("\n");
3086
3087}
3088
3089Cube
3090random_cube()
3091{
3092 CubeArray *arr = new_cubearray((Cube){0}, pf_4val);
3093 Cube ret;
3094 int ep, cp, eo, co;
3095
3096 ep = rand() % FACTORIAL12;
3097 cp = rand() % FACTORIAL8;
3098 eo = rand() % POW2TO11;
3099 co = rand() % POW3TO7;
3100
3101 index_to_perm(ep, 12, arr->ep);
3102 index_to_perm(cp, 8, arr->cp);
3103 int_to_sum_zero_array(eo, 2, 12, arr->eofb);
3104 int_to_sum_zero_array(co, 3, 8, arr->coud);
3105
3106 if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8))
3107 swap(&(arr->ep[0]), &(arr->ep[1]));
3108
3109 ret = arrays_to_cube(arr, pf_4val);
3110 free_cubearray(arr, pf_4val);
3111
3112 return ret;
3113}
3114
3115/* TODO: clean pre_trans or put it back */
3116AlgList *
3117solve(Cube cube, Step step, SolveOptions *opts)
3118{
3119 /*AlgListNode *node;*/
3120 AlgList *sols = new_alglist();
3121 /*Cube c = apply_trans(opts->pre_trans, cube);*/
3122 DfsData dd = {
3123 .m = 0,
3124 .niss = false,
3125 .lb = -1,
3126 .last1 = NULLMOVE,
3127 .last2 = NULLMOVE,
3128 .sols = sols,
3129 .current_alg = new_alg("")
3130 };
3131
3132 if (step.ready != NULL && !step.ready(cube)) {
3133 fprintf(stderr, "Cube not ready for solving step\n");
3134 return sols;
3135 }
3136
3137 moveset_to_list(step.moveset, step.estimate, dd.sorted_moves);
3138 movelist_to_position(dd.sorted_moves, dd.move_position);
3139
3140 for (dd.d = opts->min_moves;
3141 dd.d <= opts->max_moves && !(sols->len && opts->optimal_only);
3142 dd.d++) {
3143 if (opts->feedback)
3144 fprintf(stderr,
3145 "Found %d solutions, searching depth %d...\n",
3146 sols->len, dd.d);
3147 dfs(cube, step, opts, &dd);
3148 }
3149
3150/*
3151 for (node = sols->first; node != NULL; node = node->next)
3152 transform_alg(inverse_trans(opts->pre_trans), node->alg);
3153*/
3154
3155 free_alg(dd.current_alg);
3156 return sols;
3157}
3158
3159Alg *
3160inverse_alg(Alg *alg)
3161{
3162 Alg *ret = new_alg("");
3163 int i;
3164
3165 for (i = alg->len-1; i >= 0; i--)
3166 append_move(ret, inverse_move(alg->move[i]), alg->inv[i]);
3167
3168 return ret;
3169}
3170
3171Alg *
3172new_alg(char *str)
3173{
3174 Alg *alg = malloc(sizeof(Alg));
3175 int i;
3176 bool niss = false;
3177 Move j, m;
3178
3179 alg->move = malloc(30 * sizeof(Move));
3180 alg->inv = malloc(30 * sizeof(bool));
3181 alg->allocated = 30;
3182 alg->len = 0;
3183
3184 for (i = 0; str[i]; i++) {
3185 if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n')
3186 continue;
3187
3188 if (str[i] == '(' && niss) {
3189 fprintf(stderr, "Error reading moves: nested ( )\n");
3190 return alg;
3191 }
3192
3193 if (str[i] == ')' && !niss) {
3194 fprintf(stderr, "Error reading moves: unmatched )\n");
3195 return alg;
3196 }
3197
3198 if (str[i] == '(' || str[i] == ')') {
3199 niss = !niss;
3200 continue;
3201 }
3202
3203 for (j = 0; j < NMOVES; j++) {
3204 if (str[i] == move_string[j][0]) {
3205 m = j;
3206 if (m <= B && str[i+1]=='w') {
3207 m += Uw - U;
3208 i++;
3209 }
3210 if (str[i+1]=='2') {
3211 m += 1;
3212 i++;
3213 } else if (str[i+1]=='\'' || str[i+1]=='3') {
3214 m += 2;
3215 i++;
3216 }
3217 append_move(alg, m, niss);
3218 break;
3219 }
3220 }
3221 }
3222
3223 return alg;
3224}
3225
3226Alg *
3227on_inverse(Alg *alg)
3228{
3229 Alg *ret = new_alg("");
3230 int i;
3231
3232 for (i = 0; i < alg->len; i++)
3233 append_move(ret, alg->move[i], !alg->inv[i]);
3234
3235 return ret;
3236}
3237
3238void
3239print_alg(Alg *alg, bool l)
3240{
3241 /* TODO: make it possible to print to stdout or to string */
3242 /* Maybe just return a string */
3243 char fill[4];
3244 int i;
3245 bool niss = false;
3246
3247 for (i = 0; i < alg->len; i++) {
3248 if (!niss && alg->inv[i])
3249 strcpy(fill, i == 0 ? "(" : " (");
3250 if (niss && !alg->inv[i])
3251 strcpy(fill, ") ");
3252 if (niss == alg->inv[i])
3253 strcpy(fill, i == 0 ? "" : " ");
3254
3255 printf("%s%s", fill, move_string[alg->move[i]]);
3256 niss = alg->inv[i];
3257 }
3258
3259 if (niss)
3260 printf(")");
3261 if (l)
3262 printf(" (%d)", alg->len);
3263
3264 printf("\n");
3265}
3266
3267void
3268print_alglist(AlgList *al, bool l)
3269{
3270 AlgListNode *i;
3271
3272 for (i = al->first; i != NULL; i = i->next)
3273 print_alg(i->alg, l);
3274}
3275
3276void
3277print_ptable(PruneData *pd)
3278{
3279 uint64_t i, a[16];
3280
3281 for (i = 0; i < 16; i++)
3282 a[i] = 0;
3283
3284 if (!pd->generated)
3285 genptable(pd);
3286
3287 for (i = 0; i < pd->coord->max; i++)
3288 a[ptableval(pd, pd->coord->cube(i))]++;
3289
3290 fprintf(stderr, "Values for table %s\n", pd->filename);
3291 for (i = 0; i < 16; i++)
3292 printf("%2lu\t%10lu\n", i, a[i]);
3293}
3294
3295uint64_t
3296ptablesize(PruneData *pd)
3297{
3298 return (pd->coord->max + 1) / 2;
3299}
3300
3301int
3302ptableval(PruneData *pd, Cube cube)
3303{
3304 uint64_t ind = pd->coord->index(cube);
3305
3306 return (ind % 2) ? pd->ptable[ind/2] / 16 : pd->ptable[ind/2] % 16;
3307}
3308
3309
3310Alg *
3311rotation_alg(Trans i)
3312{
3313 return rotation_algs[i % NROTATIONS];
3314}
3315
3316void
3317transform_alg(Trans t, Alg *alg)
3318{
3319 int i;
3320
3321 for (i = 0; i < alg->len; i++)
3322 alg->move[i] = moves_ttable[t][alg->move[i]];
3323}
3324
3325Center
3326what_center_at(Cube cube, Center c)
3327{
3328 return what_center_at_aux[cube.cpos][c];
3329}
3330
3331Corner
3332what_corner_at(Cube cube, Corner c)
3333{
3334 return what_corner_at_aux[cube.cp][c];
3335}
3336
3337Edge
3338what_edge_at(Cube cube, Edge e)
3339{
3340 Edge ret;
3341 CubeArray *arr = new_cubearray(cube, pf_ep);
3342
3343 ret = arr->ep[e];
3344
3345 free_cubearray(arr, pf_ep);
3346 return ret;
3347}
3348
3349int
3350what_orientation_corner(int co, Corner c)
3351{
3352 if (c < 7)
3353 return (co / powint(3, c)) % 3;
3354 else
3355 return what_orientation_last_corner_aux[co];
3356}
3357
3358int
3359what_orientation_edge(int eo, Edge e)
3360{
3361 if (e < 11)
3362 return (eo & (1 << e)) ? 1 : 0;
3363 else
3364 return what_orientation_last_edge_aux[eo];
3365}
3366
3367Center
3368where_is_center(Cube cube, Center c)
3369{
3370 return where_is_center_aux[cube.cpos][c];
3371}
3372
3373Corner
3374where_is_corner(Cube cube, Corner c)
3375{
3376 return where_is_corner_aux[cube.cp][c];
3377}
3378
3379
3380void
3381init()
3382{
3383 /* Order is important! */
3384 init_environment();
3385 init_strings();
3386 init_moves_aux();
3387 init_moves();
3388 init_auxtables();
3389 init_cphtr_cosets();
3390 init_trans_aux();
3391 init_trans();
3392 init_symdata();
3393}
3394
diff --git a/old/2021-07-02-genptable-dfs/cube.h b/old/2021-07-02-genptable-dfs/cube.h
new file mode 100644
index 0000000..ffbcd86
--- /dev/null
+++ b/old/2021-07-02-genptable-dfs/cube.h
@@ -0,0 +1,90 @@
1#ifndef CUBE_H
2#define CUBE_H
3
4#include <stdio.h>
5#include <stdbool.h>
6#include <stdint.h>
7#include <stdlib.h>
8#include <string.h>
9#include <time.h>
10#include <unistd.h>
11#include <sys/stat.h>
12
13#include "macros.h"
14#include "cubetypes.h"
15
16extern Coordinate coord_eofb;
17extern Coordinate coord_eofbepos;
18extern Coordinate coord_coud;
19extern Coordinate coord_corners;
20extern Coordinate coord_cornershtr;
21extern Coordinate coord_drud;
22extern Coordinate coord_coud_sym16;
23extern Coordinate coord_eofbepos_sym16;
24extern Coordinate coord_drud_sym16;
25extern Coordinate coord_khuge;
26
27Cube apply_alg(Alg *alg, Cube cube);
28Cube apply_move(Move m, Cube cube);
29Cube apply_trans(Trans t, Cube cube);
30bool block_solved(Cube cube, Block);
31Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */
32uint64_t cphtr(Cube cube); /* TODO: rename (something with cosets) */
33Cube anti_cphtr(uint64_t ind); /*TODO also this */
34uint64_t epos_dependent(Cube cube); /* TODO: rename and turn into an indexer */
35bool equal(Cube c1, Cube c2);
36Cube inverse_cube(Cube cube);
37Move inverse_move(Move m);
38Trans inverse_trans(Trans t);
39bool is_admissible(Cube cube);
40bool is_solved(Cube cube, bool reorient);
41bool is_solved_center(Cube cube, Center c);
42bool is_solved_corner(Cube cube, Corner c);
43bool is_solved_edge(Cube cube, Edge e);
44void print_cube(Cube cube);
45Cube random_cube();
46AlgList * solve(Cube cube, Step step, SolveOptions *opts);
47Center what_center_at(Cube cube, Center c);
48Corner what_corner_at(Cube cube, Corner c);
49Edge what_edge_at(Cube cube, Edge e);
50int what_orientation_corner(int co, Corner c);
51int what_orientation_edge(int eo, Edge e);
52Center where_is_center(Cube cube, Center c);
53Corner where_is_corner(Cube cube, Corner c);
54Edge where_is_edge(Cube cube, Edge e);
55
56bool check_centers(Cube cube);
57bool check_corners(Cube cube);
58bool check_cornershtr(Cube cube);
59bool check_coud(Cube cube);
60bool check_drud(Cube cube);
61bool check_eofb(Cube cube);
62bool check_eofbepos(Cube cube);
63bool check_epose(Cube cube);
64bool check_ep(Cube cube);
65bool check_khuge(Cube cube);
66bool check_nothing(Cube cube);
67
68bool moveset_HTM(Move m);
69bool moveset_URF(Move m);
70
71Move base_move(Move m);
72void free_alg(Alg *alg);
73void free_alglist(AlgList *l);
74Alg * inverse_alg(Alg *alg);
75Alg * new_alg(char *str);
76Alg * on_inverse(Alg *alg);
77void print_alg(Alg *alg, bool l);
78void print_alglist(AlgList *al, bool l);
79Alg * rotation_alg(Trans i);
80void transform_alg(Trans t, Alg *alg);
81
82void genptable(PruneData *pd);
83void print_ptable(PruneData *pd);
84uint64_t ptablesize(PruneData *pd);
85int ptableval(PruneData *pd, Cube cube);
86
87void init();
88
89#endif
90
diff --git a/old/2021-07-02-genptable-dfs/cubetypes.h b/old/2021-07-02-genptable-dfs/cubetypes.h
new file mode 100644
index 0000000..a324985
--- /dev/null
+++ b/old/2021-07-02-genptable-dfs/cubetypes.h
@@ -0,0 +1,250 @@
1#ifndef CUBETYPES_H
2#define CUBETYPES_H
3
4/* Typedefs ******************************************************************/
5
6typedef enum center Center;
7typedef enum corner Corner;
8typedef enum edge Edge;
9typedef enum move Move;
10typedef enum trans Trans;
11
12typedef struct alg Alg;
13typedef struct alglist AlgList;
14typedef struct alglistnode AlgListNode;
15typedef struct block Block;
16typedef struct coordinate Coordinate;
17typedef struct cube Cube;
18typedef struct cubearray CubeArray;
19typedef struct cubetarget CubeTarget;
20typedef struct dfsdata DfsData;
21typedef struct piecefilter PieceFilter;
22typedef struct prunedata PruneData;
23typedef struct solveoptions SolveOptions;
24typedef struct step Step;
25typedef struct symdata SymData;
26
27typedef Cube (*AntiIndexer) (uint64_t);
28typedef bool (*Checker) (Cube);
29typedef int (*Estimator) (CubeTarget);
30typedef uint64_t (*Indexer) (Cube);
31typedef bool (*Moveset) (Move);
32
33
34/* Enums *********************************************************************/
35
36enum
37center
38{
39 U_center, D_center,
40 R_center, L_center,
41 F_center, B_center
42};
43
44enum
45corner
46{
47 UFR, UFL, UBL, UBR,
48 DFR, DFL, DBL, DBR
49};
50
51enum
52edge
53{
54 UF, UL, UB, UR,
55 DF, DL, DB, DR,
56 FR, FL, BL, BR
57};
58
59enum
60move
61{
62 NULLMOVE,
63 U, U2, U3, D, D2, D3,
64 R, R2, R3, L, L2, L3,
65 F, F2, F3, B, B2, B3,
66 Uw, Uw2, Uw3, Dw, Dw2, Dw3,
67 Rw, Rw2, Rw3, Lw, Lw2, Lw3,
68 Fw, Fw2, Fw3, Bw, Bw2, Bw3,
69 M, M2, M3,
70 S, S2, S3,
71 E, E2, E3,
72 x, x2, x3,
73 y, y2, y3,
74 z, z2, z3,
75};
76
77enum
78trans
79{
80 uf, ur, ub, ul,
81 df, dr, db, dl,
82 rf, rd, rb, ru,
83 lf, ld, lb, lu,
84 fu, fr, fd, fl,
85 bu, br, bd, bl,
86 uf_mirror, ur_mirror, ub_mirror, ul_mirror,
87 df_mirror, dr_mirror, db_mirror, dl_mirror,
88 rf_mirror, rd_mirror, rb_mirror, ru_mirror,
89 lf_mirror, ld_mirror, lb_mirror, lu_mirror,
90 fu_mirror, fr_mirror, fd_mirror, fl_mirror,
91 bu_mirror, br_mirror, bd_mirror, bl_mirror,
92};
93
94
95/* Structs *******************************************************************/
96
97struct
98alg
99{
100 Move * move;
101 bool * inv;
102 int len;
103 int allocated;
104};
105
106struct
107alglist
108{
109 AlgListNode * first;
110 AlgListNode * last;
111 int len;
112};
113
114struct
115alglistnode
116{
117 Alg * alg;
118 AlgListNode * next;
119};
120
121struct
122block
123{
124 bool edge[12];
125 bool corner[8];
126 bool center[6];
127};
128
129struct
130coordinate
131{
132 Indexer index;
133 AntiIndexer cube;
134 Checker check;
135 uint64_t max;
136};
137
138struct
139cube
140{
141 int epose;
142 int eposs;
143 int eposm;
144 int eofb;
145 int eorl;
146 int eoud;
147 int cp;
148 int coud;
149 int cofb;
150 int corl;
151 int cpos;
152};
153
154struct
155cubearray
156{
157 int * ep;
158 int * eofb;
159 int * eorl;
160 int * eoud;
161 int * cp;
162 int * coud;
163 int * corl;
164 int * cofb;
165 int * cpos;
166};
167
168struct
169cubetarget
170{
171 Cube cube;
172 int target;
173};
174
175struct
176dfsdata
177{
178 int d;
179 int m;
180 int lb;
181 bool niss;
182 Move last1;
183 Move last2;
184 AlgList * sols;
185 Alg * current_alg;
186 Move sorted_moves[NMOVES];
187 int move_position[NMOVES];
188};
189
190struct
191piecefilter
192{
193 bool epose;
194 bool eposs;
195 bool eposm;
196 bool eofb;
197 bool eorl;
198 bool eoud;
199 bool cp;
200 bool coud;
201 bool cofb;
202 bool corl;
203 bool cpos;
204};
205
206struct
207prunedata
208{
209 char * filename;
210 uint8_t * ptable;
211 bool generated;
212 uint64_t n;
213 Coordinate * coord;
214 Moveset moveset;
215};
216
217struct
218solveoptions
219{
220 int min_moves;
221 int max_moves;
222 int max_solutions;
223 bool optimal_only;
224 bool can_niss;
225 bool feedback;
226};
227
228struct
229step
230{
231 Estimator estimate;
232 Checker ready;
233 Moveset moveset;
234};
235
236struct
237symdata
238{
239 char * filename;
240 bool generated;
241 Coordinate * coord;
242 Coordinate * sym_coord;
243 int ntrans;
244 Trans * trans;
245 uint64_t * class;
246 Cube * rep;
247 Trans * transtorep;
248};
249
250#endif
diff --git a/old/2021-07-02-genptable-dfs/macros.h b/old/2021-07-02-genptable-dfs/macros.h
new file mode 100644
index 0000000..af3bca1
--- /dev/null
+++ b/old/2021-07-02-genptable-dfs/macros.h
@@ -0,0 +1,23 @@
1#ifndef MACROS_H
2#define MACROS_H
3
4#define POW2TO6 64ULL
5#define POW2TO11 2048ULL
6#define POW2TO12 4096ULL
7#define POW3TO7 2187ULL
8#define POW3TO8 6561ULL
9#define FACTORIAL4 24ULL
10#define FACTORIAL6 720ULL
11#define FACTORIAL7 5040ULL
12#define FACTORIAL8 40320ULL
13#define FACTORIAL12 479001600ULL
14#define BINOM12ON4 495ULL
15#define BINOM8ON4 70ULL
16#define MIN(a,b) (((a) < (b)) ? (a) : (b))
17#define MAX(a,b) (((a) > (b)) ? (a) : (b))
18
19#define NMOVES (z3+1)
20#define NTRANS 48
21#define NROTATIONS 24
22
23#endif
diff --git a/old/2021-07-02-genptable-dfs/main.c b/old/2021-07-02-genptable-dfs/main.c
new file mode 100644
index 0000000..1ebd917
--- /dev/null
+++ b/old/2021-07-02-genptable-dfs/main.c
@@ -0,0 +1,80 @@
1#include <stdio.h>
2#include "cube.h"
3#include "steps.h"
4
5int main() {
6 Alg *algo;
7 AlgList *sols;
8 Cube cube;
9 SolveOptions opts;
10 char line[1000];
11 int i, ns = 2;
12/* Move m;*/
13/* int nrand = 10000, sum1, sum2, sum3;*/
14
15 Step *stps[20] = {&drud_HTM, &optimal_HTM};
16 char sss[30][30] = {"DR on UD", "Optimal solve"};
17
18 opts = (SolveOptions) {
19 .min_moves = 0,
20 .max_moves = 20,
21 .optimal_only = true,
22 .max_solutions = 1,
23 .can_niss = false,
24 .feedback = true,
25 };
26
27 init();
28
29/*
30 srand(time(NULL));
31 sum1 = 0;
32 sum2 = 0;
33 sum3 = 0;
34 for (i = 0; i < nrand; i++) {
35 cube = random_cube();
36 sum1 += drud_HTM.check(cube, 20);
37 sum2 += optimal_HTM.check(cube, 20);
38 sum3 += cornershtreofb_HTM.check(cube, 20);
39 }
40 printf("Average drud pruning: %lf\n", ((double)sum1) / ((double) nrand));
41 printf("Average corners htr pruning: %lf\n", ((double)sum2) / ((double) nrand));
42 printf("Average corners htr + eofb pruning: %lf\n", ((double)sum3) / ((double) nrand));
43*/
44
45/*
46 for (m = U; m <= B3; m++) {
47 printf("Class eofbepos after %d: ", m);
48 printf("%lu\n", coord_khuge.index(apply_move(m,(Cube){0})));
49 }
50*/
51
52 printf("Welcome to nissy 2.0! Insert a scramble:\n");
53
54 if (fgets(line, 1000, stdin) != NULL) {
55 algo = new_alg(line);
56 cube = apply_alg(algo, (Cube){0});
57
58 print_alg(inverse_alg(algo), false);
59/*
60 printf("After rb_mirror:\n");
61 cube = apply_trans(rb_mirror, cube);
62 print_cube(cube);
63 printf("Going back:\n");
64 cube = apply_trans(inverse_trans(rb_mirror), cube);
65*/
66
67 print_cube(cube);
68
69 for (i = 0; i < ns; i++) {
70 sols = solve(cube, *stps[i], &opts);
71 printf("%s: %d solutions found:\n", sss[i], sols->len);
72 print_alglist(sols, true);
73 free_alglist(sols);
74 }
75 free_alg(algo);
76 }
77
78 return 0;
79}
80
diff --git a/old/2021-07-02-genptable-dfs/steps.c b/old/2021-07-02-genptable-dfs/steps.c
new file mode 100644
index 0000000..91e7f00
--- /dev/null
+++ b/old/2021-07-02-genptable-dfs/steps.c
@@ -0,0 +1,307 @@
1#include "steps.h"
2
3/* Standard checkers (return lower bound) ************************************/
4
5static int estimate_eofb_HTM(CubeTarget ct);
6static int estimate_coud_HTM(CubeTarget ct);
7static int estimate_coud_URF(CubeTarget ct);
8static int estimate_corners_HTM(CubeTarget ct);
9static int estimate_cornershtr_HTM(CubeTarget ct);
10static int estimate_corners_URF(CubeTarget ct);
11static int estimate_cornershtr_URF(CubeTarget ct);
12static int estimate_drud_HTM(CubeTarget ct);
13static int estimate_optimal_HTM(CubeTarget ct);
14
15/* Steps *********************************************************************/
16
17Step
18eofb_HTM = {
19 .estimate = estimate_eofb_HTM,
20 .ready = check_centers,
21 .moveset = moveset_HTM
22};
23
24Step
25coud_HTM = {
26 .estimate = estimate_coud_HTM,
27 .ready = check_centers,
28 .moveset = moveset_HTM
29};
30
31Step
32coud_URF = {
33 .estimate = estimate_coud_URF,
34 .ready = check_nothing,
35 .moveset = moveset_URF
36};
37
38Step
39corners_HTM = {
40 .estimate = estimate_corners_HTM,
41 .ready = check_centers,
42 .moveset = moveset_HTM
43};
44
45Step
46cornershtr_HTM = {
47 .estimate = estimate_cornershtr_HTM,
48 .ready = check_centers,
49 .moveset = moveset_HTM
50};
51
52Step
53cornershtr_URF = {
54 .estimate = estimate_cornershtr_URF,
55 .ready = check_nothing,
56 .moveset = moveset_URF
57};
58
59Step
60corners_URF = {
61 .estimate = estimate_corners_URF,
62 .ready = check_nothing,
63 .moveset = moveset_URF
64};
65
66Step
67drud_HTM = {
68 .estimate = estimate_drud_HTM,
69 .ready = check_centers,
70 .moveset = moveset_HTM
71};
72
73Step
74optimal_HTM = {
75 .estimate = estimate_optimal_HTM,
76 .ready = check_centers,
77 .moveset = moveset_HTM
78};
79
80
81/* Pruning tables ************************************************************/
82
83PruneData
84pd_eofb_HTM = {
85 .filename = "ptable_eofb_HTM",
86 .coord = &coord_eofb,
87 .moveset = moveset_HTM
88};
89
90PruneData
91pd_coud_HTM = {
92 .filename = "ptable_coud_HTM",
93 .coord = &coord_coud,
94 .moveset = moveset_HTM
95};
96
97PruneData
98pd_cornershtr_HTM = {
99 .filename = "ptable_cornershtr_withcosets_HTM",
100 .coord = &coord_cornershtr,
101 .moveset = moveset_HTM
102};
103
104PruneData
105pd_corners_HTM = {
106 .filename = "ptable_corners_HTM",
107 .coord = &coord_corners,
108 .moveset = moveset_HTM
109};
110
111PruneData
112pd_drud_HTM = {
113 .filename = "ptable_drud_HTM",
114 .coord = &coord_drud,
115 .moveset = moveset_HTM
116};
117
118PruneData
119pd_drud_sym16_HTM = {
120 .filename = "ptable_drud_sym16_HTM",
121 .coord = &coord_drud_sym16,
122 .moveset = moveset_HTM,
123};
124
125PruneData
126pd_khuge_HTM = {
127 .filename = "ptable_khuge_HTM",
128 .coord = &coord_khuge,
129 .moveset = moveset_HTM
130};
131
132
133/* Standard checkers (return lower bound) ************************************/
134
135static int
136estimate_eofb_HTM(CubeTarget ct)
137{
138 if (!pd_eofb_HTM.generated)
139 genptable(&pd_eofb_HTM);
140
141 return ptableval(&pd_eofb_HTM, ct.cube);
142}
143
144static int
145estimate_coud_HTM(CubeTarget ct)
146{
147 if (!pd_coud_HTM.generated)
148 genptable(&pd_coud_HTM);
149
150 return ptableval(&pd_coud_HTM, ct.cube);
151}
152
153static int
154estimate_coud_URF(CubeTarget ct)
155{
156 /* TODO: I can improve this by checking first the orientation of
157 * the corner in DBL and use that as a reference */
158
159 CubeTarget ct2 = {.cube = apply_move(z, ct.cube), .target = ct.target};
160 CubeTarget ct3 = {.cube = apply_move(x, ct.cube), .target = ct.target};
161
162 int ud = estimate_coud_HTM(ct);
163 int rl = estimate_coud_HTM(ct2);
164 int fb = estimate_coud_HTM(ct3);
165
166 return MIN(ud, MIN(rl, fb));
167}
168
169static int
170estimate_corners_HTM(CubeTarget ct)
171{
172 if (!pd_corners_HTM.generated)
173 genptable(&pd_corners_HTM);
174
175 return ptableval(&pd_corners_HTM, ct.cube);
176}
177
178static int
179estimate_cornershtr_HTM(CubeTarget ct)
180{
181 if (!pd_cornershtr_HTM.generated)
182 genptable(&pd_cornershtr_HTM);
183
184 return ptableval(&pd_cornershtr_HTM, ct.cube);
185}
186
187static int
188estimate_cornershtr_URF(CubeTarget ct)
189{
190 /* TODO: I can improve this by checking first the corner in DBL
191 * and use that as a reference */
192
193 int c, ret = 15;
194 Trans i;
195
196 for (i = 0; i < NROTATIONS; i++) {
197 ct.cube = apply_alg(rotation_alg(i), ct.cube);
198 c = estimate_cornershtr_HTM(ct);
199 ret = MIN(ret, c);
200 }
201
202 return ret;
203}
204
205static int
206estimate_corners_URF(CubeTarget ct)
207{
208 /* TODO: I can improve this by checking first the corner in DBL
209 * and use that as a reference */
210
211 int c, ret = 15;
212 Trans i;
213
214 for (i = 0; i < NROTATIONS; i++) {
215 ct.cube = apply_alg(rotation_alg(i), ct.cube);
216 c = estimate_corners_HTM(ct);
217 ret = MIN(ret, c);
218 }
219
220 return ret;
221}
222
223static int
224estimate_drud_HTM(CubeTarget ct)
225{
226/*
227 if (!pd_drud_HTM.generated)
228 genptable(&pd_drud_HTM);
229
230 return ptableval(&pd_drud_HTM, ct.cube);
231*/
232
233 if (!pd_drud_sym16_HTM.generated)
234 genptable(&pd_drud_sym16_HTM);
235
236 return ptableval(&pd_drud_sym16_HTM, ct.cube);
237}
238
239/* TODO: if lucky, remove this */
240/*
241static int
242estimate_optimal_HTM(CubeTarget ct)
243{
244 static Trans t1 = { .rot = rf, .mirror = false };
245 static Trans t2 = { .rot = bd, .mirror = false };
246 int dr1, dr2, dr3, cor, ret;
247 Cube cube = ct.cube;
248
249 dr1 = estimate_drud_HTM(ct);
250 cor = estimate_corners_HTM(ct);
251 ret = MAX(dr1, cor);
252
253 if (ret > ct.target)
254 return ret;
255
256 ct.cube = apply_trans(t1, cube);
257 dr2 = estimate_drud_HTM(ct);
258 ret = MAX(ret, dr2);
259
260 if (ret > ct.target)
261 return ret;
262
263 ct.cube = apply_trans(t2, cube);
264 dr3 = estimate_drud_HTM(ct);
265
266 if (dr1 == dr2 && dr2 == dr3 && dr1 != 0)
267 dr3++;
268
269 ret = MAX(ret, dr3);
270
271 if (ret == 0)
272 return check_ep(cube) ? 0 : 6;
273
274 return ret;
275}
276*/
277
278static int
279estimate_optimal_HTM(CubeTarget ct)
280{
281 static Trans t2 = rf, t3 = bd;
282
283 int dr1, dr2, dr3, cor, ret;
284 Cube cube = ct.cube;
285
286 if (!pd_khuge_HTM.generated)
287 genptable(&pd_khuge_HTM);
288
289 dr1 = ptableval(&pd_khuge_HTM, cube);
290 cor = estimate_corners_HTM(ct);
291 ret = MAX(dr1, cor);
292
293 if (ret > ct.target)
294 return ret;
295
296 cube = apply_trans(t2, ct.cube);
297 dr2 = ptableval(&pd_khuge_HTM, cube);
298 ret = MAX(ret, dr2);
299
300 if (ret > ct.target)
301 return ret;
302
303 cube = apply_trans(t3, ct.cube);
304 dr3 = ptableval(&pd_khuge_HTM, cube);
305
306 return MAX(ret, dr3);
307}
diff --git a/old/2021-07-02-genptable-dfs/steps.h b/old/2021-07-02-genptable-dfs/steps.h
new file mode 100644
index 0000000..81ae11c
--- /dev/null
+++ b/old/2021-07-02-genptable-dfs/steps.h
@@ -0,0 +1,24 @@
1#ifndef STEPS_H
2#define STEPS_H
3
4#include "cube.h"
5
6extern Step eofb_HTM;
7extern Step coud_HTM;
8extern Step coud_URF;
9extern Step corners_HTM;
10extern Step cornershtr_HTM;
11extern Step corners_URF;
12extern Step cornershtr_URF;
13extern Step drud_HTM;
14extern Step optimal_HTM;
15
16extern PruneData pd_eofb_HTM;
17extern PruneData pd_coud_HTM;
18extern PruneData pd_corners_HTM;
19extern PruneData pd_cornershtr_HTM;
20extern PruneData pd_cornershtreofb_HTM;
21extern PruneData pd_drud_HTM;
22extern PruneData pd_khuge_HTM;
23
24#endif
diff --git a/old/2021-07-15-almostbeforerefactor/README b/old/2021-07-15-almostbeforerefactor/README
new file mode 100644
index 0000000..e306a9e
--- /dev/null
+++ b/old/2021-07-15-almostbeforerefactor/README
@@ -0,0 +1,3 @@
1I started refactorig (splitting code into more files) before realizing I had no backup of
2the fast version that works.
3Take some stuff from alg.h back into cube.h, remove alg.* ad it should be ok.
diff --git a/old/2021-07-15-almostbeforerefactor/alg.c b/old/2021-07-15-almostbeforerefactor/alg.c
new file mode 100644
index 0000000..a3f8a19
--- /dev/null
+++ b/old/2021-07-15-almostbeforerefactor/alg.c
@@ -0,0 +1,3388 @@
1#include "alg.h"
2
3/* Local functions **********************************************************/
4
5static Cube admissible_ep(Cube cube, PieceFilter f);
6static Cube admissible_eos_from_eofbepos(Cube cube);
7static bool allowed_next(Move move, DfsData *dd);
8static void append_alg(AlgList *l, Alg *alg);
9static void append_move(Alg *alg, Move m, bool inverse);
10static Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a);
11static void apply_permutation(int *perm, int *set, int n);
12static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f);
13static int array_ep_to_epos(int *ep, int *eps_solved);
14static Cube arrays_to_cube(CubeArray *arr, PieceFilter f);
15static int binomial(int n, int k);
16static Cube compose_filtered(Cube c2, Cube c1, PieceFilter f);
17static void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f);
18static void dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd);
19static void dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd);
20static bool dfs_check_solved(SolveOptions *opts, DfsData *dd);
21static void dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd);
22static bool dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd);
23static int digit_array_to_int(int *a, int n, int b);
24static int edge_slice(Edge e); /* E=0, S=1, M=2 */
25static int epos_dependent_pos(int pos1, int pos2);
26static int epos_from_arrays(int *epos, int *ep);
27static void epos_to_partial_ep(int epos, int *ep, int *ss);
28static int factorial(int n);
29static void free_alglistnode(AlgListNode *aln);
30static void free_cubearray(CubeArray *arr, PieceFilter f);
31static void genptable_bfs(PruneData *pd, int d, Move *ms);
32static void genptable_branch(PruneData *pd, uint64_t i, int d, Move *m);
33static void gensym(SymData *sd);
34static void index_to_perm(int p, int n, int *r);
35static void index_to_subset(int s, int n, int k, int *r);
36static void init_auxtables();
37static void init_cphtr_cosets();
38static void init_cphtr_left_cosets_bfs(int i, int c);
39static void init_cphtr_right_cosets_color(int i, int c);
40static void init_environment();
41static void init_moves();
42static void init_moves_aux();
43static void init_strings();
44static void init_symdata();
45static void init_trans();
46static void init_trans_aux();
47static void int_to_digit_array(int a, int b, int n, int *r);
48static void int_to_sum_zero_array(int x, int b, int n, int *a);
49static int invert_digits(int a, int b, int n);
50static bool is_perm(int *a, int n);
51static bool is_subset(int *a, int n, int k);
52static Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf);
53static void movelist_to_position(Move *movelist, int *position);
54static void moveset_to_list(Moveset ms, Estimator f, Move *r);
55static AlgList * new_alglist();
56static CubeArray * new_cubearray(Cube cube, PieceFilter f);
57static int perm_sign(int *a, int n);
58static int perm_to_index(int *a, int n);
59static int powint(int a, int b);
60static void ptable_update(PruneData *pd, Cube cube, int m);
61static int ptableval_index(PruneData *pd, uint64_t ind);
62static void realloc_alg(Alg *alg, int n);
63static bool read_mtables_file();
64static bool read_ptable_file(PruneData *pd);
65static bool read_symdata_file(SymData *sd);
66static bool read_ttables_file();
67static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f);
68static int subset_to_index(int *a, int n, int k);
69static void sum_arrays_mod(int *src, int *dst, int n, int m);
70static void swap(int *a, int *b);
71static bool write_mtables_file();
72static bool write_ptable_file(PruneData *pd);
73static bool write_symdata_file(SymData *sd);
74static bool write_ttables_file();
75
76
77/* All sorts of useful costants and tables **********************************/
78
79static char * tabledir;
80
81static PieceFilter pf_all;
82static PieceFilter pf_4val;
83static PieceFilter pf_epcp;
84static PieceFilter pf_cpos;
85static PieceFilter pf_cp;
86static PieceFilter pf_ep;
87static PieceFilter pf_e;
88static PieceFilter pf_s;
89static PieceFilter pf_m;
90static PieceFilter pf_eo;
91static PieceFilter pf_co;
92
93static int epe_solved[4];
94static int eps_solved[4];
95static int epm_solved[4];
96
97static char move_string[NMOVES][7];
98static char edge_string[12][7];
99static char corner_string[8][7];
100static char center_string[6][7];
101
102static Cube admissible_ee_aux[POW2TO11*BINOM12ON4];
103static bool commute[NMOVES][NMOVES];
104static bool possible_next[NMOVES][NMOVES][NMOVES];
105static Move inverse_move_aux[NMOVES];
106static Trans inverse_trans_aux[NTRANS];
107static int epos_dependent_aux[BINOM12ON4][BINOM12ON4];
108static int cphtr_left_cosets[FACTORIAL8];
109static int cphtr_right_cosets[FACTORIAL8];
110static int cphtr_right_rep[BINOM8ON4*6];
111static Center what_center_at_aux[FACTORIAL6][6];
112static Corner what_corner_at_aux[FACTORIAL8][8];
113static int what_orientation_last_corner_aux[POW3TO7];
114static int what_orientation_last_edge_aux[POW2TO11];
115static Center where_is_center_aux[FACTORIAL6][6];
116static Corner where_is_corner_aux[FACTORIAL8][8];
117static Edge where_is_edge_aux[3][FACTORIAL12/FACTORIAL8][12];
118
119static int epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
120static int eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
121static int eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
122static int eo_ttable[NTRANS][POW2TO11];
123static int cp_ttable[NTRANS][FACTORIAL8];
124static int co_ttable[NTRANS][POW3TO7];
125static int cpos_ttable[NTRANS][FACTORIAL6];
126static Move moves_ttable[NTRANS][NMOVES];
127
128static int epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
129static int eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
130static int eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
131static int eofb_mtable[NMOVES][POW2TO11];
132static int eorl_mtable[NMOVES][POW2TO11];
133static int eoud_mtable[NMOVES][POW2TO11];
134static int cp_mtable[NMOVES][FACTORIAL8];
135static int coud_mtable[NMOVES][POW3TO7];
136static int cofb_mtable[NMOVES][POW3TO7];
137static int corl_mtable[NMOVES][POW3TO7];
138static int cpos_mtable[NMOVES][FACTORIAL6];
139
140static uint64_t me[12];
141
142static int edge_cycle[NMOVES][12];
143static int corner_cycle[NMOVES][8];
144static int center_cycle[NMOVES][6];
145static int eofb_flipped[NMOVES][12];
146static int eorl_flipped[NMOVES][12];
147static int eoud_flipped[NMOVES][12];
148static int coud_flipped[NMOVES][8];
149static int corl_flipped[NMOVES][8];
150static int cofb_flipped[NMOVES][8];
151static Alg * equiv_alg[NMOVES];
152
153static int epose_source[NTRANS]; /* 0=epose, 1=eposs, 2=eposm */
154static int eposs_source[NTRANS];
155static int eposm_source[NTRANS];
156static int eofb_source[NTRANS]; /* 0=eoud, 1=eorl, 2=eofb */
157static int eorl_source[NTRANS];
158static int eoud_source[NTRANS];
159static int coud_source[NTRANS]; /* 0=coud, 1=corl, 2=cofb */
160static int cofb_source[NTRANS];
161static int corl_source[NTRANS];
162static int ep_mirror[12];
163static int cp_mirror[8];
164static int cpos_mirror[6];
165static Alg * rotation_algs[NROTATIONS];
166
167
168/* Symmetry data for some coordinates ****************************************/
169
170Trans
171trans_group_trivial[1] = { uf };
172
173Trans
174trans_group_udfix[16] = {
175 uf, ur, ub, ul,
176 df, dr, db, dl,
177 uf_mirror, ur_mirror, ub_mirror, ul_mirror,
178 df_mirror, dr_mirror, db_mirror, dl_mirror,
179};
180
181SymData
182sd_coud_16 = {
183 .filename = "sd_coud_16",
184 .coord = &coord_coud,
185 .sym_coord = &coord_coud_sym16,
186 .ntrans = 16,
187 .trans = trans_group_udfix
188};
189
190SymData
191sd_eofbepos_16 = {
192 .filename = "sd_eofbepos_16",
193 .coord = &coord_eofbepos,
194 .sym_coord = &coord_eofbepos_sym16,
195 .ntrans = 16,
196 .trans = trans_group_udfix
197};
198
199static int n_all_symdata = 2;
200static SymData * all_sd[2] = { &sd_coud_16, &sd_eofbepos_16 };
201
202/* Coordinates and their implementation **************************************/
203
204static uint64_t index_eofb(Cube cube);
205static uint64_t index_eofbepos(Cube cube);
206static uint64_t index_coud(Cube cube);
207static uint64_t index_corners(Cube cube);
208static uint64_t index_cornershtr(Cube cube);
209static uint64_t index_drud(Cube cube);
210static uint64_t index_coud_sym16(Cube cube);
211static uint64_t index_eofbepos_sym16(Cube cube);
212static uint64_t index_drud_sym16(Cube cube);
213static uint64_t index_khuge(Cube cube);
214
215static Cube antindex_eofb(uint64_t ind);
216static Cube antindex_eofbepos(uint64_t ind);
217static Cube antindex_coud(uint64_t ind);
218static Cube antindex_corners(uint64_t ind);
219static Cube antindex_cornershtr(uint64_t ind);
220static Cube antindex_drud(uint64_t ind);
221static Cube antindex_coud_sym16(uint64_t ind);
222static Cube antindex_eofbepos_sym16(uint64_t ind);
223static Cube antindex_drud_sym16(uint64_t ind);
224static Cube antindex_khuge(uint64_t ind);
225
226Coordinate
227coord_eofb = {
228 .index = index_eofb,
229 .cube = antindex_eofb,
230 .check = check_eofb,
231 .max = POW2TO11
232};
233
234Coordinate
235coord_eofbepos = {
236 .index = index_eofbepos,
237 .cube = antindex_eofbepos,
238 .check = check_eofbepos,
239 .max = POW2TO11 * BINOM12ON4
240};
241
242Coordinate
243coord_coud = {
244 .index = index_coud,
245 .cube = antindex_coud,
246 .check = check_coud,
247 .max = POW3TO7
248};
249
250Coordinate
251coord_corners = {
252 .index = index_corners,
253 .cube = antindex_corners,
254 .check = check_corners,
255 .max = POW3TO7 * FACTORIAL8
256};
257
258Coordinate
259coord_cornershtr = {
260 .index = index_cornershtr,
261 .cube = antindex_cornershtr,
262 .check = check_cornershtr,
263 .max = POW3TO7 * BINOM8ON4 * 6
264};
265
266Coordinate
267coord_drud = {
268 .index = index_drud,
269 .cube = antindex_drud,
270 .check = check_drud,
271 .max = POW2TO11 * POW3TO7 * BINOM12ON4
272};
273
274Coordinate
275coord_eofbepos_sym16 = {
276 .index = index_eofbepos_sym16,
277 .cube = antindex_eofbepos_sym16,
278 .check = check_eofbepos,
279};
280
281Coordinate
282coord_coud_sym16 = {
283 .index = index_coud_sym16,
284 .cube = antindex_coud_sym16,
285 .check = check_coud,
286};
287
288Coordinate
289coord_drud_sym16 = {
290 .index = index_drud_sym16,
291 .cube = antindex_drud_sym16,
292 .check = check_drud,
293 .max = POW3TO7 * 64430
294};
295
296Coordinate
297coord_khuge = {
298 .index = index_khuge,
299 .cube = antindex_khuge,
300 .check = check_khuge,
301 .max = POW3TO7 * FACTORIAL4 * 64430
302};
303
304
305static uint64_t
306index_eofb(Cube cube)
307{
308 return cube.eofb;
309}
310
311static uint64_t
312index_eofbepos(Cube cube)
313{
314 return (cube.epose / FACTORIAL4) * POW2TO11 + cube.eofb;
315}
316
317static uint64_t
318index_coud(Cube cube)
319{
320 return cube.coud;
321}
322
323static uint64_t
324index_corners(Cube cube)
325{
326 return cube.coud * FACTORIAL8 + cube.cp;
327}
328
329static uint64_t
330index_cornershtr(Cube cube)
331{
332 return cube.coud * BINOM8ON4 * 6 + cphtr(cube);
333}
334
335static uint64_t
336index_drud(Cube cube)
337{
338 uint64_t a, b, c;
339
340 a = cube.eofb;
341 b = cube.coud;
342 c = cube.epose / FACTORIAL4;
343
344 b *= POW2TO11;
345 c *= POW2TO11 * POW3TO7;
346
347 return a + b + c;
348}
349
350static uint64_t
351index_coud_sym16(Cube cube)
352{
353 return sd_coud_16.class[index_coud(cube)];
354}
355
356static uint64_t
357index_drud_sym16(Cube cube)
358{
359 Trans t;
360 Cube c;
361
362 t = sd_eofbepos_16.transtorep[index_eofbepos(cube)];
363 c = apply_trans(t, cube);
364
365 return index_eofbepos_sym16(c) * POW3TO7 + c.coud;
366}
367
368static uint64_t
369index_eofbepos_sym16(Cube cube)
370{
371 return sd_eofbepos_16.class[index_eofbepos(cube)];
372}
373
374static uint64_t
375index_khuge(Cube cube)
376{
377 Trans t;
378 Cube c;
379 uint64_t a;
380
381 t = sd_eofbepos_16.transtorep[index_eofbepos(cube)];
382 c = apply_trans(t, cube);
383 a = (index_eofbepos_sym16(c) * 24) + (c.epose % 24);
384
385 return a * POW3TO7 + c.coud;
386}
387
388
389/* TODO: rename */
390static Cube
391antindex_eofb(uint64_t ind)
392{
393 return (Cube){ .eofb = ind, .eorl = ind, .eoud = ind };
394}
395
396static Cube
397antindex_eofbepos(uint64_t ind)
398{
399 return admissible_ee_aux[ind];
400}
401
402/* TODO: rename */
403static Cube
404antindex_coud(uint64_t ind)
405{
406 return (Cube){ .coud = ind, .corl = ind, .cofb = ind };
407}
408
409/* TODO: admissible co for other orientations */
410static Cube
411antindex_corners(uint64_t ind)
412{
413 Cube c = {0};
414
415 c.coud = ind / FACTORIAL8;
416 c.cp = ind % FACTORIAL8;
417
418 return c;
419}
420
421/* TODO: admissible co for other orientations */
422static Cube
423antindex_cornershtr(uint64_t ind)
424{
425 Cube c = anti_cphtr(ind % (BINOM8ON4 * 6));
426
427 c.coud = ind / (BINOM8ON4 * 6);
428
429 return c;
430}
431
432/* TODO: admissible eos and cos */
433/* DONE: temporary fix, make it better */
434static Cube
435antindex_drud(uint64_t ind)
436{
437 uint64_t epos, eofb;
438 Cube c;
439
440 eofb = ind % POW2TO11;
441 epos = ind / (POW2TO11 * POW3TO7);
442 c = admissible_ee_aux[eofb + POW2TO11 * epos];
443
444 c.coud = (ind / POW2TO11) % POW3TO7;
445 c.corl = c.coud;
446 c.cofb = c.coud;
447
448 return c;
449}
450
451static Cube
452antindex_coud_sym16(uint64_t ind)
453{
454 return sd_coud_16.rep[ind];
455}
456
457static Cube
458antindex_eofbepos_sym16(uint64_t ind)
459{
460 return sd_eofbepos_16.rep[ind];
461}
462
463static Cube
464antindex_drud_sym16(uint64_t ind)
465{
466 Cube c;
467
468 c = sd_eofbepos_16.rep[ind/POW3TO7];
469 c.coud = ind % POW3TO7;
470 c.cofb = c.coud;
471 c.corl = c.coud;
472
473 return c;
474}
475
476static Cube
477antindex_khuge(uint64_t ind)
478{
479 Cube c;
480
481 c = sd_eofbepos_16.rep[ind/(FACTORIAL4*POW3TO7)];
482 c.epose = ((c.epose / 24) * 24) + ((ind/POW3TO7) % 24);
483 c.coud = ind % POW3TO7;
484
485 return c;
486}
487
488
489/* Checkers ******************************************************************/
490
491bool
492check_centers(Cube cube)
493{
494 return cube.cpos == 0;
495}
496
497bool
498check_corners(Cube cube)
499{
500 return cube.cp == 0 && cube.coud == 0;
501}
502
503bool
504check_cornershtr(Cube cube)
505{
506 return cube.coud == 0 && cphtr(cube) == 0; /* TODO: use array cphtrcosets*/
507}
508
509bool
510check_coud(Cube cube)
511{
512 return cube.coud == 0;
513}
514
515bool
516check_drud(Cube cube)
517{
518 return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0;
519}
520
521bool
522check_eofb(Cube cube)
523{
524 return cube.eofb == 0;
525}
526
527bool
528check_eofbepos(Cube cube)
529{
530 return cube.eofb == 0 && cube.epose / 24 == 0;
531}
532
533bool
534check_epose(Cube cube)
535{
536 return cube.epose == 0;
537}
538
539bool
540check_ep(Cube cube)
541{
542 return cube.epose == 0 && cube.eposs == 0 && cube.eposm == 0;
543}
544
545bool
546check_khuge(Cube cube)
547{
548 return check_drud(cube) && cube.epose % 24 == 0;
549}
550
551bool
552check_nothing(Cube cube)
553{
554 return is_admissible(cube); /*TODO: maybe change?*/
555}
556
557/* Movesets ******************************************************************/
558
559bool
560moveset_HTM(Move m)
561{
562 return m >= U && m <= B3;
563}
564
565bool
566moveset_URF(Move m)
567{
568 Move b = base_move(m);
569
570 return b == U || b == R || b == F;
571}
572
573
574/* Local functions implementation ********************************************/
575
576/* TODO: this should be an anti index (maybe?) */
577static Cube
578admissible_ep(Cube cube, PieceFilter f)
579{
580 CubeArray *arr = new_cubearray(cube, f);
581 Cube ret;
582 bool used[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
583 int i, j;
584
585 for (i = 0; i < 12; i++)
586 if (arr->ep[i] != -1)
587 used[arr->ep[i]] = true;
588
589 for (i = 0, j = 0; i < 12; i++) {
590 for ( ; j < 11 && used[j]; j++);
591 if (arr->ep[i] == -1)
592 arr->ep[i] = j++;
593 }
594
595 ret = arrays_to_cube(arr, pf_ep);
596 free_cubearray(arr, f);
597
598 return ret;
599}
600
601static Cube
602admissible_eos_from_eofbepos(Cube cube)
603{
604 Edge e;
605 Cube ret;
606 CubeArray *arr = new_cubearray(cube, pf_all);
607
608 memcpy(arr->eorl, arr->eofb, 12 * sizeof(int));
609 memcpy(arr->eoud, arr->eofb, 12 * sizeof(int));
610
611 for (e = 0; e < 12; e++) {
612 if ((edge_slice(e) != 0 && edge_slice(arr->ep[e]) == 0) ||
613 (edge_slice(e) == 0 && edge_slice(arr->ep[e]) != 0))
614 arr->eorl[e] = 1 - arr->eorl[e];
615 if ((edge_slice(e) != 2 && edge_slice(arr->ep[e]) == 2) ||
616 (edge_slice(e) == 2 && edge_slice(arr->ep[e]) != 2))
617 arr->eoud[e] = 1 - arr->eoud[e];
618 }
619
620 ret = arrays_to_cube(arr, pf_all);
621 free_cubearray(arr, pf_all);
622
623 return ret;
624}
625
626static bool
627allowed_next(Move move, DfsData *dd)
628{
629 if (!possible_next[dd->last2][dd->last1][move])
630 return false;
631
632 if (commute[dd->last1][move])
633 return dd->move_position[dd->last1] < dd->move_position[move];
634
635 return true;
636}
637
638static void
639append_alg(AlgList *l, Alg *alg)
640{
641 AlgListNode *node = malloc(sizeof(AlgListNode));
642 int i;
643
644 node->alg = new_alg("");
645 for (i = 0; i < alg->len; i++)
646 append_move(node->alg, alg->move[i], alg->inv[i]);
647 node->next = NULL;
648
649 if (++l->len == 1)
650 l->first = node;
651 else
652 l->last->next = node;
653 l->last = node;
654}
655
656static void
657append_move(Alg *alg, Move m, bool inverse)
658{
659 if (alg->len == alg->allocated)
660 realloc_alg(alg, 2*alg->len);
661
662 alg->move[alg->len] = m;
663 alg->inv [alg->len] = inverse;
664 alg->len++;
665}
666
667static Cube
668apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a)
669{
670 Cube ret = {0};
671 int i;
672
673 for (i = 0; i < alg->len; i++)
674 if (alg->inv[i])
675 ret = a ? apply_move(alg->move[i], ret) :
676 apply_move_cubearray(alg->move[i], ret, f);
677
678 ret = compose_filtered(c, inverse_cube(ret), f);
679
680 for (i = 0; i < alg->len; i++)
681 if (!alg->inv[i])
682 ret = a ? apply_move(alg->move[i], ret) :
683 apply_move_cubearray(alg->move[i], ret, f);
684
685 return ret;
686}
687
688static void
689apply_permutation(int *perm, int *set, int n)
690{
691 int *aux = malloc(n * sizeof(int));
692 int i;
693
694 if (!is_perm(perm, n))
695 return;
696
697 for (i = 0; i < n; i++)
698 aux[i] = set[perm[i]];
699
700 memcpy(set, aux, n * sizeof(int));
701 free(aux);
702}
703
704static Cube
705apply_move_cubearray(Move m, Cube cube, PieceFilter f)
706{
707 CubeArray m_arr = {
708 edge_cycle[m],
709 eofb_flipped[m],
710 eorl_flipped[m],
711 eoud_flipped[m],
712 corner_cycle[m],
713 coud_flipped[m],
714 corl_flipped[m],
715 cofb_flipped[m],
716 center_cycle[m]
717 };
718
719 return move_via_arrays(&m_arr, cube, f);
720}
721
722static int
723array_ep_to_epos(int *ep, int *ss)
724{
725 int epos[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
726 int eps[4];
727 int i, j, is;
728
729 for (i = 0, is = 0; i < 12; i++) {
730 for (j = 0; j < 4; j++) {
731 if (ep[i] == ss[j]) {
732 eps[is++] = j;
733 epos[i] = 1;
734 }
735 }
736 }
737
738 for (i = 0; i < 4; i++)
739 swap(&epos[ss[i]], &epos[i+8]);
740
741 return epos_from_arrays(epos, eps);
742}
743
744static Cube
745arrays_to_cube(CubeArray *arr, PieceFilter f)
746{
747 Cube ret = {0};
748
749 if (f.epose)
750 ret.epose = array_ep_to_epos(arr->ep, epe_solved);
751 if (f.eposs)
752 ret.eposs = array_ep_to_epos(arr->ep, eps_solved);
753 if (f.eposm)
754 ret.eposm = array_ep_to_epos(arr->ep, epm_solved);
755 if (f.eofb)
756 ret.eofb = digit_array_to_int(arr->eofb, 11, 2);
757 if (f.eorl)
758 ret.eorl = digit_array_to_int(arr->eorl, 11, 2);
759 if (f.eoud)
760 ret.eoud = digit_array_to_int(arr->eoud, 11, 2);
761 if (f.cp)
762 ret.cp = perm_to_index(arr->cp, 8);
763 if (f.coud)
764 ret.coud = digit_array_to_int(arr->coud, 7, 3);
765 if (f.corl)
766 ret.corl = digit_array_to_int(arr->corl, 7, 3);
767 if (f.cofb)
768 ret.cofb = digit_array_to_int(arr->cofb, 7, 3);
769 if (f.cpos)
770 ret.cpos = perm_to_index(arr->cpos, 6);
771
772 return ret;
773}
774
775static int
776binomial(int n, int k)
777{
778 if (n < 0 || k < 0 || k > n)
779 return 0;
780
781 return factorial(n) / (factorial(k) * factorial(n-k));
782}
783
784static Cube
785compose_filtered(Cube c2, Cube c1, PieceFilter f)
786{
787 CubeArray *arr = new_cubearray(c2, f);
788 Cube ret;
789
790 ret = move_via_arrays(arr, c1, f);
791 free_cubearray(arr, f);
792
793 return ret;
794}
795
796static void
797cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f)
798{
799 int i;
800
801 if (f.epose || f.eposs || f.eposm)
802 for (i = 0; i < 12; i++)
803 arr->ep[i] = -1;
804
805 if (f.epose)
806 epos_to_partial_ep(cube.epose, arr->ep, epe_solved);
807 if (f.eposs)
808 epos_to_partial_ep(cube.eposs, arr->ep, eps_solved);
809 if (f.eposm)
810 epos_to_partial_ep(cube.eposm, arr->ep, epm_solved);
811 if (f.eofb)
812 int_to_sum_zero_array(cube.eofb, 2, 12, arr->eofb);
813 if (f.eorl)
814 int_to_sum_zero_array(cube.eorl, 2, 12, arr->eorl);
815 if (f.eoud)
816 int_to_sum_zero_array(cube.eoud, 2, 12, arr->eoud);
817 if (f.cp)
818 index_to_perm(cube.cp, 8, arr->cp);
819 if (f.coud)
820 int_to_sum_zero_array(cube.coud, 3, 8, arr->coud);
821 if (f.corl)
822 int_to_sum_zero_array(cube.corl, 3, 8, arr->corl);
823 if (f.cofb)
824 int_to_sum_zero_array(cube.cofb, 3, 8, arr->cofb);
825 if (f.cpos)
826 index_to_perm(cube.cpos, 6, arr->cpos);
827}
828
829/*
830static int
831cphtr_cp(int cp)
832{
833 int i, a[8];
834
835 index_to_perm(cp, 8, a);
836
837 for (i = 0; i < 8; i++)
838 if (a[i] == UFR || a[i] == UBL || a[i] == DFL || a[i] == DBR)
839 a[i] = 0;
840 else
841 a[i] = 1;
842
843 swap(&a[1], &a[5]);
844 swap(&a[3], &a[7]);
845
846 return subset_to_index(a, 8, 4);
847}
848*/
849
850static void
851dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd)
852{
853 if (dfs_stop(c, s, opts, dd))
854 return;
855
856 if (dfs_check_solved(opts, dd))
857 return;
858
859 dfs_branch(c, s, opts, dd);
860
861 if (opts->can_niss && !dd->niss)
862 dfs_niss(c, s, opts, dd);
863}
864
865static void
866dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd)
867{
868 Move m, l1 = dd->last1, l2 = dd->last2, *moves = dd->sorted_moves;
869
870 int i, maxnsol = opts->max_solutions;
871
872 for (i = 0; moves[i] != NULLMOVE && dd->sols->len < maxnsol; i++) {
873 m = moves[i];
874 if (allowed_next(m, dd)) {
875 dd->last2 = dd->last1;
876 dd->last1 = m;
877 append_move(dd->current_alg, m, dd->niss);
878
879 dfs(apply_move(m, c), s, opts, dd);
880
881 dd->current_alg->len--;
882 dd->last2 = l2;
883 dd->last1 = l1;
884 }
885 }
886}
887
888static bool
889dfs_check_solved(SolveOptions *opts, DfsData *dd)
890{
891 if (dd->lb != 0)
892 return false;
893
894 if (dd->current_alg->len == dd->d) {
895 append_alg(dd->sols, dd->current_alg);
896
897 if (opts->feedback)
898 print_alg(dd->current_alg, false);
899 }
900
901 return true;
902}
903
904static void
905dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd)
906{
907 Move l1 = dd->last1, l2 = dd->last2;
908 CubeTarget ct;
909
910 ct.cube = apply_move(inverse_move(l1), (Cube){0});
911 ct.target = 1;
912
913 if (dd->current_alg->len == 0 || s.estimate(ct)) {
914 dd->niss = true;
915 dd->last1 = NULLMOVE;
916 dd->last2 = NULLMOVE;
917
918 dfs(inverse_cube(c), s, opts, dd);
919
920 dd->last1 = l1;
921 dd->last2 = l2;
922 dd->niss = false;
923 }
924}
925
926static bool
927dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd)
928{
929 CubeTarget ct = {
930 .cube = c,
931 .target = dd->d - dd->current_alg->len
932 };
933
934 if (dd->sols->len >= opts->max_solutions)
935 return true;
936
937 dd->lb = s.estimate(ct);
938 if (opts->can_niss && !dd->niss)
939 dd->lb = MIN(1, dd->lb);
940
941 if (dd->current_alg->len + dd->lb > dd->d)
942 return true;
943
944 return false;
945}
946
947static int
948digit_array_to_int(int *a, int n, int b)
949{
950 int i, ret = 0, p = 1;
951
952 for (i = 0; i < n; i++, p *= b)
953 ret += a[i] * p;
954
955 return ret;
956}
957
958static int
959edge_slice(Edge e) {
960 if (e < 0 || e > 11)
961 return -1;
962
963 if (e == FR || e == FL || e == BL || e == BR)
964 return 0;
965 if (e == UR || e == UL || e == DR || e == DL)
966 return 1;
967
968 return 2;
969}
970
971static int
972epos_dependent_pos(int poss, int pose)
973{
974 int ep[12] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
975 int ep8[8] = {0, 0, 0, 0, 0, 0, 0, 0};
976 int i, j;
977
978 epos_to_partial_ep(poss*FACTORIAL4, ep, eps_solved);
979 epos_to_partial_ep(pose*FACTORIAL4, ep, epe_solved);
980
981 for (i = 0, j = 0; i < 12; i++)
982 if (edge_slice(ep[i]) != 0)
983 ep8[j++] = (edge_slice(ep[i]) == 1) ? 1 : 0;
984
985 swap(&ep8[1], &ep8[4]);
986 swap(&ep8[3], &ep8[6]);
987
988 return subset_to_index(ep8, 8, 4);
989}
990
991static int
992epos_from_arrays(int *epos, int *ep)
993{
994 return FACTORIAL4 * subset_to_index(epos,12,4) + perm_to_index(ep,4);
995}
996
997static void
998epos_to_partial_ep(int epos, int *ep, int *ss)
999{
1000 int i, is, eposs[12], eps[4];
1001
1002 index_to_perm(epos % FACTORIAL4, 4, eps);
1003 index_to_subset(epos / FACTORIAL4, 12, 4, eposs);
1004
1005 for (i = 0; i < 4; i++)
1006 swap(&eposs[ss[i]], &eposs[i+8]);
1007
1008 for (i = 0, is = 0; i < 12; i++)
1009 if (eposs[i])
1010 ep[i] = ss[eps[is++]];
1011}
1012
1013static int
1014factorial(int n)
1015{
1016 int i, ret = 1;
1017
1018 if (n < 0)
1019 return 0;
1020
1021 for (i = 1; i <= n; i++)
1022 ret *= i;
1023
1024 return ret;
1025}
1026
1027void
1028free_alg(Alg *alg)
1029{
1030 free(alg->move);
1031 free(alg->inv);
1032 free(alg);
1033}
1034
1035void
1036free_alglist(AlgList *l)
1037{
1038 AlgListNode *aux, *i = l->first;
1039
1040 while (i != NULL) {
1041 aux = i->next;
1042 free_alglistnode(i);
1043 i = aux;
1044 }
1045 free(l);
1046}
1047
1048void
1049free_alglistnode(AlgListNode *aln)
1050{
1051 free_alg(aln->alg);
1052 free(aln);
1053}
1054
1055static void
1056free_cubearray(CubeArray *arr, PieceFilter f)
1057{
1058 if (f.epose || f.eposs || f.eposm)
1059 free(arr->ep);
1060 if (f.eofb)
1061 free(arr->eofb);
1062 if (f.eorl)
1063 free(arr->eorl);
1064 if (f.eoud)
1065 free(arr->eoud);
1066 if (f.cp)
1067 free(arr->cp);
1068 if (f.coud)
1069 free(arr->coud);
1070 if (f.corl)
1071 free(arr->corl);
1072 if (f.cofb)
1073 free(arr->cofb);
1074 if (f.cpos)
1075 free(arr->cpos);
1076
1077 free(arr);
1078}
1079
1080static void
1081genptable_bfs(PruneData *pd, int d, Move *ms)
1082{
1083 uint64_t i;
1084
1085 for (i = 0; i < pd->coord->max; i++)
1086 if (ptableval_index(pd, i) == d)
1087 genptable_branch(pd, i, d, ms);
1088}
1089
1090static void
1091genptable_branch(PruneData *pd, uint64_t ind, int d, Move *ms)
1092{
1093 int i, j;
1094 Cube cc, c;
1095
1096
1097 for (i = 0; i < pd->ntrans; i++) {
1098 c = apply_trans(pd->trans[i], pd->coord->cube(ind));
1099 for (j = 0; ms[j] != NULLMOVE; j++) {
1100 cc = apply_move(ms[j], c);
1101 if (ptableval(pd, cc) > d+1)
1102 ptable_update(pd, cc, d+1);
1103 }
1104 }
1105}
1106
1107static void
1108gensym(SymData *sd)
1109{
1110 uint64_t i, in, nreps = 0;
1111 int j;
1112 Cube c, d;
1113
1114 if (sd->generated)
1115 return;
1116
1117 sd->class = malloc(sd->coord->max * sizeof(uint64_t));
1118 sd->rep = malloc(sd->coord->max * sizeof(Cube));
1119 sd->transtorep = malloc(sd->coord->max * sizeof(Trans));
1120
1121 if (read_symdata_file(sd)) {
1122 sd->generated = true;
1123 return;
1124 }
1125
1126 fprintf(stderr, "Cannot load %s, generating it\n", sd->filename);
1127
1128 for (i = 0; i < sd->coord->max; i++)
1129 sd->class[i] = sd->coord->max + 1;
1130
1131 for (i = 0; i < sd->coord->max; i++) {
1132 if (sd->class[i] == sd->coord->max + 1) {
1133 c = sd->coord->cube(i);
1134 sd->rep[nreps] = c;
1135 for (j = 0; j < sd->ntrans; j++) {
1136 d = apply_trans(sd->trans[j], c);
1137 in = sd->coord->index(d);
1138
1139 if (sd->class[in] == sd->coord->max + 1) {
1140 sd->class[in] = nreps;
1141 sd->transtorep[in] =
1142 inverse_trans(sd->trans[j]);
1143 }
1144 }
1145 nreps++;
1146 }
1147 }
1148
1149 sd->sym_coord->max = nreps;
1150 sd->rep = realloc(sd->rep, nreps * sizeof(Cube));
1151 sd->generated = true;
1152
1153 fprintf(stderr, "Found %lu classes\n", nreps);
1154
1155 if (!write_symdata_file(sd))
1156 fprintf(stderr, "Error writing SymData file\n");
1157
1158 return;
1159}
1160
1161static void
1162index_to_perm(int p, int n, int *r)
1163{
1164 int *a = malloc(n * sizeof(int));
1165 int i, j, c;
1166
1167 for (i = 0; i < n; i++)
1168 a[i] = 0;
1169
1170 if (p < 0 || p >= factorial(n))
1171 for (i = 0; i < n; i++)
1172 r[i] = -1;
1173
1174 for (i = 0; i < n; i++) {
1175 c = 0;
1176 j = 0;
1177 while (c <= p / factorial(n-i-1))
1178 c += a[j++] ? 0 : 1;
1179 r[i] = j-1;
1180 a[j-1] = 1;
1181 p %= factorial(n-i-1);
1182 }
1183
1184 free(a);
1185}
1186
1187static void
1188index_to_subset(int s, int n, int k, int *r)
1189{
1190 int i, j, v;
1191
1192 if (s < 0 || s >= binomial(n, k)) {
1193 for (i = 0; i < n; i++)
1194 r[i] = -1;
1195 return;
1196 }
1197
1198 for (i = 0; i < n; i++) {
1199 if (k == n-i) {
1200 for (j = i; j < n; j++)
1201 r[j] = 1;
1202 return;
1203 }
1204
1205 if (k == 0) {
1206 for (j = i; j < n; j++)
1207 r[j] = 0;
1208 return;
1209 }
1210
1211 v = binomial(n-i-1, k);
1212 if (s >= v) {
1213 r[i] = 1;
1214 k--;
1215 s -= v;
1216 } else {
1217 r[i] = 0;
1218 }
1219 }
1220}
1221
1222static void
1223int_to_digit_array(int a, int b, int n, int *r)
1224{
1225 int i;
1226
1227 if (b <= 1)
1228 for (i = 0; i < n; i++)
1229 r[i] = 0;
1230 else
1231 for (i = 0; i < n; i++, a /= b)
1232 r[i] = a % b;
1233}
1234
1235static void
1236int_to_sum_zero_array(int x, int b, int n, int *a)
1237{
1238 int i, s = 0;
1239
1240 if (b <= 1) {
1241 for (i = 0; i < n; i++)
1242 a[i] = 0;
1243 } else {
1244 int_to_digit_array(x, b, n-1, a);
1245 for (i = 0; i < n - 1; i++)
1246 s = (s + a[i]) % b;
1247 a[n-1] = (b - s) % b;
1248 }
1249}
1250
1251static int
1252invert_digits(int a, int b, int n)
1253{
1254 int i, ret, *r = malloc(n * sizeof(int));
1255
1256 int_to_digit_array(a, b, n, r);
1257 for (i = 0; i < n; i++)
1258 r[i] = (b-r[i]) % b;
1259
1260 ret = digit_array_to_int(r, n, b);
1261 free(r);
1262 return ret;
1263}
1264
1265static bool
1266is_perm(int *a, int n)
1267{
1268 int *aux = malloc(n * sizeof(int));
1269 int i;
1270
1271 for (i = 0; i < n; i++)
1272 if (a[i] < 0 || a[i] >= n)
1273 return false;
1274 else
1275 aux[a[i]] = 1;
1276
1277 for (i = 0; i < n; i++)
1278 if (!aux[i])
1279 return false;
1280
1281 free(aux);
1282
1283 return true;
1284}
1285
1286static bool
1287is_subset(int *a, int n, int k)
1288{
1289 int i, sum = 0;
1290
1291 for (i = 0; i < n; i++)
1292 sum += a[i] ? 1 : 0;
1293
1294 return sum == k;
1295}
1296
1297static Cube
1298move_via_arrays(CubeArray *arr, Cube c, PieceFilter f)
1299{
1300 CubeArray *arrc = new_cubearray(c, f);
1301 Cube ret;
1302
1303 if (f.epose || f.eposs || f.eposm)
1304 apply_permutation(arr->ep, arrc->ep, 12);
1305
1306 if (f.eofb) {
1307 apply_permutation(arr->ep, arrc->eofb, 12);
1308 sum_arrays_mod(arr->eofb, arrc->eofb, 12, 2);
1309 }
1310
1311 if (f.eorl) {
1312 apply_permutation(arr->ep, arrc->eorl, 12);
1313 sum_arrays_mod(arr->eorl, arrc->eorl, 12, 2);
1314 }
1315
1316 if (f.eoud) {
1317 apply_permutation(arr->ep, arrc->eoud, 12);
1318 sum_arrays_mod(arr->eoud, arrc->eoud, 12, 2);
1319 }
1320
1321 if (f.cp)
1322 apply_permutation(arr->cp, arrc->cp, 8);
1323
1324 if (f.coud) {
1325 apply_permutation(arr->cp, arrc->coud, 8);
1326 sum_arrays_mod(arr->coud, arrc->coud, 8, 3);
1327 }
1328
1329 if (f.corl) {
1330 apply_permutation(arr->cp, arrc->corl, 8);
1331 sum_arrays_mod(arr->corl, arrc->corl, 8, 3);
1332 }
1333
1334 if (f.cofb) {
1335 apply_permutation(arr->cp, arrc->cofb, 8);
1336 sum_arrays_mod(arr->cofb, arrc->cofb, 8, 3);
1337 }
1338
1339 if (f.cpos)
1340 apply_permutation(arr->cpos, arrc->cpos, 6);
1341
1342 ret = arrays_to_cube(arrc, f);
1343 free_cubearray(arrc, f);
1344
1345 return ret;
1346}
1347
1348static void
1349movelist_to_position(Move *movelist, int *position)
1350{
1351 Move m;
1352
1353 for (m = 0; m < NMOVES && movelist[m] != NULLMOVE; m++)
1354 position[movelist[m]] = m;
1355}
1356
1357static void
1358moveset_to_list(Moveset ms, Estimator f, Move *r)
1359{
1360 CubeTarget ct = { .target = 1 };
1361 int b[NMOVES];
1362 int na = 0, nb = 0;
1363 Move i;
1364
1365 if (ms == NULL) {
1366 fprintf(stderr, "Error: no moveset given\n");
1367 return;
1368 }
1369
1370 for (i = U; i < NMOVES; i++) {
1371 if (ms(i)) {
1372 ct.cube = apply_move(i, (Cube){0});
1373 if (f != NULL && f(ct))
1374 r[na++] = i;
1375 else
1376 b[nb++] = i;
1377 }
1378 }
1379
1380 memcpy(r + na, b, nb * sizeof(Move));
1381 r[na+nb] = NULLMOVE;
1382}
1383
1384static AlgList *
1385new_alglist()
1386{
1387 AlgList *ret = malloc(sizeof(AlgList));
1388
1389 ret->len = 0;
1390 ret->first = NULL;
1391 ret->last = NULL;
1392
1393 return ret;
1394}
1395
1396static CubeArray *
1397new_cubearray(Cube cube, PieceFilter f)
1398{
1399 CubeArray *arr = malloc(sizeof(CubeArray));
1400
1401 if (f.epose || f.eposs || f.eposm)
1402 arr->ep = malloc(12 * sizeof(int));
1403 if (f.eofb)
1404 arr->eofb = malloc(12 * sizeof(int));
1405 if (f.eorl)
1406 arr->eorl = malloc(12 * sizeof(int));
1407 if (f.eoud)
1408 arr->eoud = malloc(12 * sizeof(int));
1409 if (f.cp)
1410 arr->cp = malloc(8 * sizeof(int));
1411 if (f.coud)
1412 arr->coud = malloc(8 * sizeof(int));
1413 if (f.corl)
1414 arr->corl = malloc(8 * sizeof(int));
1415 if (f.cofb)
1416 arr->cofb = malloc(8 * sizeof(int));
1417 if (f.cpos)
1418 arr->cpos = malloc(6 * sizeof(int));
1419
1420 cube_to_arrays(cube, arr, f);
1421
1422 return arr;
1423}
1424
1425static int
1426perm_sign(int *a, int n)
1427{
1428 int i, j, ret = 0;
1429
1430 if (!is_perm(a,n))
1431 return -1;
1432
1433 for (i = 0; i < n; i++)
1434 for (j = i+1; j < n; j++)
1435 ret += (a[i] > a[j]) ? 1 : 0;
1436
1437 return ret % 2;
1438}
1439
1440static int
1441perm_to_index(int *a, int n)
1442{
1443 int i, j, c, ret = 0;
1444
1445 if (!is_perm(a, n))
1446 return -1;
1447
1448 for (i = 0; i < n; i++) {
1449 c = 0;
1450 for (j = i+1; j < n; j++)
1451 c += (a[i] > a[j]) ? 1 : 0;
1452 ret += factorial(n-i-1) * c;
1453 }
1454
1455 return ret;
1456}
1457
1458static int
1459powint(int a, int b)
1460{
1461 if (b < 0)
1462 return 0;
1463 if (b == 0)
1464 return 1;
1465
1466 if (b % 2)
1467 return a * powint(a, b-1);
1468 else
1469 return powint(a*a, b/2);
1470}
1471
1472static void
1473ptable_update(PruneData *pd, Cube cube, int n)
1474{
1475 uint64_t ind = pd->coord->index(cube);
1476 uint8_t oldval2 = pd->ptable[ind/2];
1477 int other = (ind % 2) ? oldval2 % 16 : oldval2 / 16;
1478
1479 pd->ptable[ind/2] = (ind % 2) ? 16*n + other : 16*other + n;
1480 pd->n++;
1481}
1482
1483static int
1484ptableval_index(PruneData *pd, uint64_t ind)
1485{
1486 return (ind % 2) ? pd->ptable[ind/2] / 16 : pd->ptable[ind/2] % 16;
1487}
1488
1489static void
1490realloc_alg(Alg *alg, int n)
1491{
1492 if (alg == NULL) {
1493 fprintf(stderr, "Error: trying to reallocate NULL alg.\n");
1494 return;
1495 }
1496
1497 if (n < alg->len) {
1498 fprintf(stderr, "Error: alg too long for reallocation ");
1499 fprintf(stderr, "(%d vs %d)\n", alg->len, n);
1500 return;
1501 }
1502
1503 if (n > 1000000) {
1504 fprintf(stderr, "Warning: very long alg,");
1505 fprintf(stderr, "something might go wrong.\n");
1506 }
1507
1508 alg->move = realloc(alg->move, n * sizeof(int));
1509 alg->inv = realloc(alg->inv, n * sizeof(int));
1510 alg->allocated = n;
1511}
1512
1513static bool
1514read_mtables_file()
1515{
1516 FILE *f;
1517 char fname[strlen(tabledir)+20];
1518 int m, b = sizeof(int);
1519 bool r = true;
1520
1521 strcpy(fname, tabledir);
1522 strcat(fname, "/mtables");
1523
1524 if ((f = fopen(fname, "rb")) == NULL)
1525 return false;
1526
1527 for (m = 0; m < NMOVES; m++) {
1528 r = r && fread(epose_mtable[m], b, me[0], f) == me[0];
1529 r = r && fread(eposs_mtable[m], b, me[1], f) == me[1];
1530 r = r && fread(eposm_mtable[m], b, me[2], f) == me[2];
1531 r = r && fread(eofb_mtable[m], b, me[3], f) == me[3];
1532 r = r && fread(eorl_mtable[m], b, me[4], f) == me[4];
1533 r = r && fread(eoud_mtable[m], b, me[5], f) == me[5];
1534 r = r && fread(cp_mtable[m], b, me[6], f) == me[6];
1535 r = r && fread(coud_mtable[m], b, me[7], f) == me[7];
1536 r = r && fread(corl_mtable[m], b, me[8], f) == me[8];
1537 r = r && fread(cofb_mtable[m], b, me[9], f) == me[9];
1538 r = r && fread(cpos_mtable[m], b, me[10], f) == me[10];
1539 }
1540
1541 fclose(f);
1542 return r;
1543}
1544
1545static bool
1546read_ptable_file(PruneData *pd)
1547{
1548 FILE *f;
1549 char fname[strlen(tabledir)+100];
1550 uint64_t r;
1551
1552 strcpy(fname, tabledir);
1553 strcat(fname, "/");
1554 strcat(fname, pd->filename);
1555
1556 if ((f = fopen(fname, "rb")) == NULL)
1557 return false;
1558
1559 r = fread(pd->ptable, sizeof(uint8_t), ptablesize(pd), f);
1560 fclose(f);
1561
1562 return r == ptablesize(pd);
1563}
1564
1565static bool
1566read_symdata_file(SymData *sd)
1567{
1568 FILE *f;
1569 char fname[strlen(tabledir)+100];
1570 uint64_t n = sd->coord->max, *sn = &sd->sym_coord->max;
1571 bool r = true;
1572
1573 strcpy(fname, tabledir);
1574 strcat(fname, "/");
1575 strcat(fname, sd->filename);
1576
1577 if ((f = fopen(fname, "rb")) == NULL)
1578 return false;
1579
1580 r = r && fread(&sd->sym_coord->max, sizeof(uint64_t), 1, f) == 1;
1581 r = r && fread(sd->rep, sizeof(Cube), *sn, f) == *sn;
1582 r = r && fread(sd->class, sizeof(uint64_t), n, f) == n;
1583 r = r && fread(sd->transtorep, sizeof(Trans), n, f) == n;
1584
1585 fclose(f);
1586 return r;
1587}
1588
1589static bool
1590read_ttables_file()
1591{
1592 FILE *f;
1593 char fname[strlen(tabledir)+20];
1594 int b = sizeof(int);
1595 bool r = true;
1596 Move m;
1597
1598 strcpy(fname, tabledir);
1599 strcat(fname, "/");
1600 strcat(fname, "ttables");
1601
1602 if ((f = fopen(fname, "rb")) == NULL)
1603 return false;
1604
1605 for (m = 0; m < NTRANS; m++) {
1606 r = r && fread(epose_ttable[m], b, me[0], f) == me[0];
1607 r = r && fread(eposs_ttable[m], b, me[1], f) == me[1];
1608 r = r && fread(eposm_ttable[m], b, me[2], f) == me[2];
1609 r = r && fread(eo_ttable[m], b, me[3], f) == me[3];
1610 r = r && fread(cp_ttable[m], b, me[6], f) == me[6];
1611 r = r && fread(co_ttable[m], b, me[7], f) == me[7];
1612 r = r && fread(cpos_ttable[m], b, me[10], f) == me[10];
1613 r = r && fread(moves_ttable[m], b, me[11], f) == me[11];
1614 }
1615
1616 fclose(f);
1617 return r;
1618}
1619
1620static Cube
1621rotate_via_compose(Trans r, Cube c, PieceFilter f)
1622{
1623 static int zero12[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1624 static int zero8[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
1625 static CubeArray ma = {
1626 .ep = ep_mirror,
1627 .eofb = zero12,
1628 .eorl = zero12,
1629 .eoud = zero12,
1630 .cp = cp_mirror,
1631 .coud = zero8,
1632 .corl = zero8,
1633 .cofb = zero8,
1634 .cpos = cpos_mirror
1635 };
1636
1637 Alg *inv = inverse_alg(rotation_algs[r % NROTATIONS]);
1638 Cube ret = {0};
1639
1640 if (r >= NROTATIONS)
1641 ret = move_via_arrays(&ma, ret, f);
1642 ret = apply_alg_generic(inv, ret, f, true);
1643
1644 ret = compose_filtered(c, ret, f);
1645
1646 ret = apply_alg_generic(rotation_algs[r % NROTATIONS], ret, f, true);
1647 if (r >= NROTATIONS)
1648 ret = move_via_arrays(&ma, ret, f);
1649
1650 free_alg(inv);
1651 return ret;
1652}
1653
1654static int
1655subset_to_index(int *a, int n, int k)
1656{
1657 int i, ret = 0;
1658
1659 if (!is_subset(a, n, k))
1660 return binomial(n, k);
1661
1662 for (i = 0; i < n; i++) {
1663 if (k == n-i)
1664 return ret;
1665 if (a[i]) {
1666 ret += binomial(n-i-1, k);
1667 k--;
1668 }
1669 }
1670
1671 return ret;
1672}
1673
1674static void
1675sum_arrays_mod(int *src, int *dst, int n, int m)
1676{
1677 int i;
1678
1679 for (i = 0; i < n; i++)
1680 dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m;
1681}
1682
1683static void
1684swap(int *a, int *b)
1685{
1686 int aux;
1687
1688 aux = *a;
1689 *a = *b;
1690 *b = aux;
1691}
1692
1693static bool
1694write_mtables_file()
1695{
1696 FILE *f;
1697 char fname[strlen(tabledir)+20];
1698 int m, b = sizeof(int);
1699 bool r = true;
1700
1701 strcpy(fname, tabledir);
1702 strcat(fname, "/mtables");
1703
1704 if ((f = fopen(fname, "wb")) == NULL)
1705 return false;
1706
1707 for (m = 0; m < NMOVES; m++) {
1708 r = r && fwrite(epose_mtable[m], b, me[0], f) == me[0];
1709 r = r && fwrite(eposs_mtable[m], b, me[1], f) == me[1];
1710 r = r && fwrite(eposm_mtable[m], b, me[2], f) == me[2];
1711 r = r && fwrite(eofb_mtable[m], b, me[3], f) == me[3];
1712 r = r && fwrite(eorl_mtable[m], b, me[4], f) == me[4];
1713 r = r && fwrite(eoud_mtable[m], b, me[5], f) == me[5];
1714 r = r && fwrite(cp_mtable[m], b, me[6], f) == me[6];
1715 r = r && fwrite(coud_mtable[m], b, me[7], f) == me[7];
1716 r = r && fwrite(corl_mtable[m], b, me[8], f) == me[8];
1717 r = r && fwrite(cofb_mtable[m], b, me[9], f) == me[9];
1718 r = r && fwrite(cpos_mtable[m], b, me[10], f) == me[10];
1719 }
1720
1721 fclose(f);
1722 return r;
1723}
1724
1725static bool
1726write_ptable_file(PruneData *pd)
1727{
1728 FILE *f;
1729 char fname[strlen(tabledir)+100];
1730 uint64_t written;
1731
1732 strcpy(fname, tabledir);
1733 strcat(fname, "/");
1734 strcat(fname, pd->filename);
1735
1736 if ((f = fopen(fname, "wb")) == NULL)
1737 return false;
1738
1739 written = fwrite(pd->ptable, sizeof(uint8_t), ptablesize(pd), f);
1740 fclose(f);
1741
1742 return written == ptablesize(pd);
1743}
1744
1745static bool
1746write_symdata_file(SymData *sd)
1747{
1748 FILE *f;
1749 char fname[strlen(tabledir)+100];
1750 uint64_t n = sd->coord->max, *sn = &sd->sym_coord->max;
1751 bool r = true;
1752
1753 strcpy(fname, tabledir);
1754 strcat(fname, "/");
1755 strcat(fname, sd->filename);
1756
1757 if ((f = fopen(fname, "wb")) == NULL)
1758 return false;
1759
1760 r = r && fwrite(&sd->sym_coord->max, sizeof(uint64_t), 1, f) == 1;
1761 r = r && fwrite(sd->rep, sizeof(Cube), *sn, f) == *sn;
1762 r = r && fwrite(sd->class, sizeof(uint64_t), n, f) == n;
1763 r = r && fwrite(sd->transtorep, sizeof(Trans), n, f) == n;
1764
1765 fclose(f);
1766 return r;
1767}
1768
1769static bool
1770write_ttables_file()
1771{
1772 FILE *f;
1773 char fname[strlen(tabledir)+20];
1774 bool r = true;
1775 int b = sizeof(int);
1776 Move m;
1777
1778 strcpy(fname, tabledir);
1779 strcat(fname, "/ttables");
1780
1781 if ((f = fopen(fname, "wb")) == NULL)
1782 return false;
1783
1784 for (m = 0; m < NTRANS; m++) {
1785 r = r && fwrite(epose_ttable[m], b, me[0], f) == me[0];
1786 r = r && fwrite(eposs_ttable[m], b, me[1], f) == me[1];
1787 r = r && fwrite(eposm_ttable[m], b, me[2], f) == me[2];
1788 r = r && fwrite(eo_ttable[m], b, me[3], f) == me[3];
1789 r = r && fwrite(cp_ttable[m], b, me[6], f) == me[6];
1790 r = r && fwrite(co_ttable[m], b, me[7], f) == me[7];
1791 r = r && fwrite(cpos_ttable[m], b, me[10], f) == me[10];
1792 r = r && fwrite(moves_ttable[m], b, me[11], f) == me[11];
1793 }
1794
1795 fclose(f);
1796 return r;
1797}
1798
1799/* Init functions implementation *********************************************/
1800
1801static void
1802init_auxtables()
1803{
1804 Cube c1, c2;
1805 CubeArray *arr;
1806 uint64_t ui, uj;
1807 int i, j, k, auxarr[12];
1808 bool cij, p1, p2;
1809
1810 for (ui = 0; ui < POW2TO11*BINOM12ON4; ui++) {
1811 k = (ui / POW2TO11) * 24;
1812 c1 = admissible_ep((Cube){ .epose = k }, pf_e);
1813 c1.eofb = ui % POW2TO11;
1814 c1 = admissible_eos_from_eofbepos(c1);
1815 admissible_ee_aux[ui] = c1;
1816 }
1817
1818 for (ui = 0; ui < FACTORIAL6; ui++) {
1819 arr = new_cubearray((Cube){.cpos = ui}, pf_cpos);
1820 for (i = 0; i < 6; i++) {
1821 what_center_at_aux[ui][i] = arr->cpos[i];
1822 where_is_center_aux[ui][arr->cpos[i]] = i;
1823 }
1824 free_cubearray(arr, pf_cpos);
1825 }
1826
1827 for (ui = 0; ui < FACTORIAL8; ui++) {
1828 arr = new_cubearray((Cube){.cp = ui}, pf_cp);
1829 for (i = 0; i < 8; i++) {
1830 what_corner_at_aux[ui][i] = arr->cp[i];
1831 where_is_corner_aux[ui][arr->cp[i]] = i;
1832 }
1833 free_cubearray(arr, pf_cp);
1834 }
1835
1836 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
1837 arr = new_cubearray((Cube){.epose = ui}, pf_e);
1838 for (i = 0; i < 12; i++)
1839 if (edge_slice(arr->ep[i]) == 0)
1840 where_is_edge_aux[0][ui][arr->ep[i]] = i;
1841 free_cubearray(arr, pf_e);
1842
1843 arr = new_cubearray((Cube){.eposs = ui}, pf_s);
1844 for (i = 0; i < 12; i++)
1845 if (edge_slice(arr->ep[i]) == 1)
1846 where_is_edge_aux[1][ui][arr->ep[i]] = i;
1847 free_cubearray(arr, pf_s);
1848
1849 arr = new_cubearray((Cube){.eposm = ui}, pf_m);
1850 for (i = 0; i < 12; i++)
1851 if (edge_slice(arr->ep[i]) == 2)
1852 where_is_edge_aux[2][ui][arr->ep[i]] = i;
1853 free_cubearray(arr, pf_m);
1854 }
1855
1856 for (ui = 0; ui < POW3TO7; ui++) {
1857 int_to_sum_zero_array(ui, 3, 8, auxarr);
1858 what_orientation_last_corner_aux[ui] = auxarr[7];
1859 }
1860
1861 for (ui = 0; ui < POW2TO11; ui++) {
1862 int_to_sum_zero_array(ui, 2, 12, auxarr);
1863 what_orientation_last_edge_aux[ui] = auxarr[11];
1864 }
1865
1866 for (ui = 0; ui < BINOM12ON4; ui++)
1867 for (uj = 0; uj < BINOM12ON4; uj++)
1868 epos_dependent_aux[ui][uj]=epos_dependent_pos(ui, uj);
1869
1870 for (i = 0; i < NMOVES; i++) {
1871 for (j = 0; j < NMOVES; j++) {
1872 c1 = apply_move(i, apply_move(j, (Cube){0}));
1873 c2 = apply_move(j, apply_move(i, (Cube){0}));
1874 commute[i][j] = equal(c1, c2) && i && j;
1875 }
1876 }
1877
1878 for (i = 0; i < NMOVES; i++) {
1879 for (j = 0; j < NMOVES; j++) {
1880 for (k = 0; k < NMOVES; k++) {
1881 p1 = j && base_move(j) == base_move(k);
1882 p2 = i && base_move(i) == base_move(k);
1883 cij = commute[i][j];
1884 possible_next[i][j][k] = !(p1 || (cij && p2));
1885 }
1886 }
1887 }
1888
1889 for (i = 0; i < NMOVES; i++)
1890 inverse_move_aux[i] = i ? i + 2 - 2*((i-1)%3) : NULLMOVE;
1891
1892 /* Is there a more elegant way? */
1893 inverse_trans_aux[uf] = uf;
1894 inverse_trans_aux[ur] = ul;
1895 inverse_trans_aux[ul] = ur;
1896 inverse_trans_aux[ub] = ub;
1897
1898 inverse_trans_aux[df] = df;
1899 inverse_trans_aux[dr] = dr;
1900 inverse_trans_aux[dl] = dl;
1901 inverse_trans_aux[db] = db;
1902
1903 inverse_trans_aux[rf] = lf;
1904 inverse_trans_aux[rd] = bl;
1905 inverse_trans_aux[rb] = rb;
1906 inverse_trans_aux[ru] = fr;
1907
1908 inverse_trans_aux[lf] = rf;
1909 inverse_trans_aux[ld] = br;
1910 inverse_trans_aux[lb] = lb;
1911 inverse_trans_aux[lu] = fl;
1912
1913 inverse_trans_aux[fu] = fu;
1914 inverse_trans_aux[fr] = ru;
1915 inverse_trans_aux[fd] = bu;
1916 inverse_trans_aux[fl] = lu;
1917
1918 inverse_trans_aux[bu] = fd;
1919 inverse_trans_aux[br] = ld;
1920 inverse_trans_aux[bd] = bd;
1921 inverse_trans_aux[bl] = rd;
1922
1923 inverse_trans_aux[uf_mirror] = uf_mirror;
1924 inverse_trans_aux[ur_mirror] = ur_mirror;
1925 inverse_trans_aux[ul_mirror] = ul_mirror;
1926 inverse_trans_aux[ub_mirror] = ub_mirror;
1927
1928 inverse_trans_aux[df_mirror] = df_mirror;
1929 inverse_trans_aux[dr_mirror] = dl_mirror;
1930 inverse_trans_aux[dl_mirror] = dr_mirror;
1931 inverse_trans_aux[db_mirror] = db_mirror;
1932
1933 inverse_trans_aux[rf_mirror] = rf_mirror;
1934 inverse_trans_aux[rd_mirror] = br_mirror;
1935 inverse_trans_aux[rb_mirror] = lb_mirror;
1936 inverse_trans_aux[ru_mirror] = fl_mirror;
1937
1938 inverse_trans_aux[lf_mirror] = lf_mirror;
1939 inverse_trans_aux[ld_mirror] = bl_mirror;
1940 inverse_trans_aux[lb_mirror] = rb_mirror;
1941 inverse_trans_aux[lu_mirror] = fr_mirror;
1942
1943 inverse_trans_aux[fu_mirror] = fu_mirror;
1944 inverse_trans_aux[fr_mirror] = lu_mirror;
1945 inverse_trans_aux[fd_mirror] = bu_mirror;
1946 inverse_trans_aux[fl_mirror] = ru_mirror;
1947
1948 inverse_trans_aux[bu_mirror] = fd_mirror;
1949 inverse_trans_aux[br_mirror] = rd_mirror;
1950 inverse_trans_aux[bd_mirror] = bd_mirror;
1951 inverse_trans_aux[bl_mirror] = ld_mirror;
1952}
1953
1954/*
1955 * There is certainly a bette way to do this, but for now I just use
1956 * a "graph coloring" algorithm to compute the left cosets, and I compose
1957 * with every possible cp to get the right cosets (it is possible that I am
1958 * mixing up left and right).
1959 *
1960 * For doing it better "Mathematically", we need 3 things:
1961 * - Checking that cp separates the orbits (UFR,UBL,DFL,DBR) and the other
1962 * This is easy and it is done in the commented function cphtr_cp().
1963 * - Check that there is no ep/cp parity
1964 * - Check that we are not in the "3c" case; this is the part I don't
1965 * know how to do.
1966 */
1967static void
1968init_cphtr_cosets()
1969{
1970 unsigned int i;
1971 int c = 0, d = 0;
1972
1973 for (i = 0; i < FACTORIAL8; i++) {
1974 cphtr_left_cosets[i] = -1;
1975 cphtr_right_cosets[i] = -1;
1976 }
1977
1978 /* First we compute left cosets with a bfs */
1979 for (i = 0; i < FACTORIAL8; i++)
1980 if (cphtr_left_cosets[i] == -1)
1981 init_cphtr_left_cosets_bfs(i, c++);
1982
1983 /* Then we compute right cosets using compose() */
1984 for (i = 0; i < FACTORIAL8; i++)
1985 if (cphtr_right_cosets[i] == -1)
1986 init_cphtr_right_cosets_color(i, d++);
1987}
1988
1989static void
1990init_cphtr_left_cosets_bfs(int i, int c)
1991{
1992 int j, jj, k, next[FACTORIAL8], next2[FACTORIAL8], n, n2;
1993 Move moves[6] = {U2, D2, R2, L2, F2, B2};
1994
1995 n = 1;
1996 next[0] = i;
1997 cphtr_left_cosets[i] = c;
1998
1999 while (n != 0) {
2000 for (j = 0, n2 = 0; j < n; j++) {
2001 for (k = 0; k < 6; k++) {
2002 jj = cp_mtable[moves[k]][next[j]];
2003 if (cphtr_left_cosets[jj] == -1) {
2004 cphtr_left_cosets[jj] = c;
2005 next2[n2++] = jj;
2006 }
2007 }
2008 }
2009
2010 for (j = 0; j < n2; j++)
2011 next[j] = next2[j];
2012 n = n2;
2013 }
2014}
2015
2016static void
2017init_cphtr_right_cosets_color(int i, int d)
2018{
2019 int cp;
2020 unsigned int j;
2021
2022 cphtr_right_rep[d] = i;
2023 for (j = 0; j < FACTORIAL8; j++) {
2024 if (cphtr_left_cosets[j] == 0) {
2025 /* TODO: use antindexer, it's nicer */
2026 cp = compose((Cube){.cp = i}, (Cube){.cp = j}).cp;
2027 cphtr_right_cosets[cp] = d;
2028 }
2029 }
2030}
2031
2032static void
2033init_environment()
2034{
2035 char *nissydata = getenv("NISSYDATA");
2036 char *localdata = getenv("XDG_DATA_HOME");
2037 char *home = getenv("HOME");
2038 bool read, write;
2039
2040 if (nissydata != NULL) {
2041 tabledir = malloc(strlen(nissydata) * sizeof(char) + 20);
2042 strcpy(tabledir, nissydata);
2043 } else if (localdata != NULL) {
2044 tabledir = malloc(strlen(localdata) * sizeof(char) + 20);
2045 strcpy(tabledir, localdata);
2046 strcat(tabledir, "/nissy");
2047 } else if (home != NULL) {
2048 tabledir = malloc(strlen(home) * sizeof(char) + 20);
2049 strcpy(tabledir, home);
2050 strcat(tabledir, "/.nissy");
2051 }
2052
2053 mkdir(tabledir, 0777);
2054 strcat(tabledir, "/tables");
2055 mkdir(tabledir, 0777);
2056
2057 read = !access(tabledir, R_OK);
2058 write = !access(tabledir, W_OK);
2059
2060 if (!read) {
2061 fprintf(stderr, "Table files cannot be read.\n");
2062 } else if (!write) {
2063 fprintf(stderr, "Data directory not writable: ");
2064 fprintf(stderr, "tables can be loaded, but not saved.\n");
2065 }
2066}
2067
2068static void
2069init_moves() {
2070 Cube c;
2071 CubeArray arrs;
2072 int i;
2073 unsigned int ui;
2074 Move m;
2075
2076 /* Generate all move cycles and flips; I do this regardless */
2077 for (i = 0; i < NMOVES; i++) {
2078 if (i == U || i == x || i == y)
2079 continue;
2080
2081 c = apply_alg_generic(equiv_alg[i], (Cube){0}, pf_all, false);
2082
2083 arrs = (CubeArray) {
2084 edge_cycle[i],
2085 eofb_flipped[i],
2086 eorl_flipped[i],
2087 eoud_flipped[i],
2088 corner_cycle[i],
2089 coud_flipped[i],
2090 corl_flipped[i],
2091 cofb_flipped[i],
2092 center_cycle[i]
2093 };
2094 cube_to_arrays(c, &arrs, pf_all);
2095 }
2096
2097 if (read_mtables_file())
2098 return;
2099
2100 fprintf(stderr, "Cannot load %s, generating it\n", "mtables");
2101
2102 /* Initialize transition tables */
2103 for (m = 0; m < NMOVES; m++) {
2104 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
2105 c = (Cube){ .epose = ui };
2106 c = apply_move_cubearray(m, c, pf_e);
2107 epose_mtable[m][ui] = c.epose;
2108
2109 c = (Cube){ .eposs = ui };
2110 c = apply_move_cubearray(m, c, pf_s);
2111 eposs_mtable[m][ui] = c.eposs;
2112
2113 c = (Cube){ .eposm = ui };
2114 c = apply_move_cubearray(m, c, pf_m);
2115 eposm_mtable[m][ui] = c.eposm;
2116 }
2117 for (ui = 0; ui < POW2TO11; ui++ ) {
2118 c = (Cube){ .eofb = ui };
2119 c = apply_move_cubearray(m, c, pf_eo);
2120 eofb_mtable[m][ui] = c.eofb;
2121
2122 c = (Cube){ .eorl = ui };
2123 c = apply_move_cubearray(m, c, pf_eo);
2124 eorl_mtable[m][ui] = c.eorl;
2125
2126 c = (Cube){ .eoud = ui };
2127 c = apply_move_cubearray(m, c, pf_eo);
2128 eoud_mtable[m][ui] = c.eoud;
2129 }
2130 for (ui = 0; ui < POW3TO7; ui++) {
2131 c = (Cube){ .coud = ui };
2132 c = apply_move_cubearray(m, c, pf_co);
2133 coud_mtable[m][ui] = c.coud;
2134
2135 c = (Cube){ .corl = ui };
2136 c = apply_move_cubearray(m, c, pf_co);
2137 corl_mtable[m][ui] = c.corl;
2138
2139 c = (Cube){ .cofb = ui };
2140 c = apply_move_cubearray(m, c, pf_co);
2141 cofb_mtable[m][ui] = c.cofb;
2142 }
2143 for (ui = 0; ui < FACTORIAL8; ui++) {
2144 c = (Cube){ .cp = ui };
2145 c = apply_move_cubearray(m, c, pf_cp);
2146 cp_mtable[m][ui] = c.cp;
2147 }
2148 for (ui = 0; ui < FACTORIAL6; ui++) {
2149 c = (Cube){ .cpos = ui };
2150 c = apply_move_cubearray(m, c, pf_cpos);
2151 cpos_mtable[m][ui] = c.cpos;
2152 }
2153 }
2154
2155 if (!write_mtables_file())
2156 fprintf(stderr, "Error writing mtables\n");
2157}
2158
2159static void
2160init_moves_aux()
2161{
2162 /* Some standard PieceFilters */
2163 pf_all.epose = true;
2164 pf_all.eposs = true;
2165 pf_all.eposm = true;
2166 pf_all.eofb = true;
2167 pf_all.eorl = true;
2168 pf_all.eoud = true;
2169 pf_all.cp = true;
2170 pf_all.cofb = true;
2171 pf_all.corl = true;
2172 pf_all.coud = true;
2173 pf_all.cpos = true;
2174
2175 pf_4val.epose = true;
2176 pf_4val.eposs = true;
2177 pf_4val.eposm = true;
2178 pf_4val.eofb = true;
2179 pf_4val.coud = true;
2180 pf_4val.cp = true;
2181
2182 pf_epcp.epose = true;
2183 pf_epcp.eposs = true;
2184 pf_epcp.eposm = true;
2185 pf_epcp.cp = true;
2186
2187 pf_cpos.cpos = true;
2188
2189 pf_cp.cp = true;
2190
2191 pf_ep.epose = true;
2192 pf_ep.eposs = true;
2193 pf_ep.eposm = true;
2194
2195 pf_e.epose = true;
2196 pf_s.eposs = true;
2197 pf_m.eposm = true;
2198
2199 pf_eo.eofb = true;
2200 pf_eo.eorl = true;
2201 pf_eo.eoud = true;
2202
2203 pf_co.cofb = true;
2204 pf_co.corl = true;
2205 pf_co.coud = true;
2206
2207 /* Used to convert to and from CubeArray */
2208 epe_solved[0] = FR;
2209 epe_solved[1] = FL;
2210 epe_solved[2] = BL;
2211 epe_solved[3] = BR;
2212
2213 eps_solved[0] = UL;
2214 eps_solved[1] = UR;
2215 eps_solved[2] = DL;
2216 eps_solved[3] = DR;
2217
2218 epm_solved[0] = UF;
2219 epm_solved[1] = UB;
2220 epm_solved[2] = DF;
2221 epm_solved[3] = DB;
2222
2223 /* Table sizes, used for reading and writing files */
2224 me[0] = FACTORIAL12/FACTORIAL8;
2225 me[1] = FACTORIAL12/FACTORIAL8;
2226 me[2] = FACTORIAL12/FACTORIAL8;
2227 me[3] = POW2TO11;
2228 me[4] = POW2TO11;
2229 me[5] = POW2TO11;
2230 me[6] = FACTORIAL8;
2231 me[7] = POW3TO7;
2232 me[8] = POW3TO7;
2233 me[9] = POW3TO7;
2234 me[10] = FACTORIAL6;
2235 me[11] = NMOVES;
2236
2237 /* Cycles *********************/
2238 edge_cycle[U][UF] = UR;
2239 edge_cycle[U][UL] = UF;
2240 edge_cycle[U][UB] = UL;
2241 edge_cycle[U][UR] = UB;
2242 edge_cycle[U][DF] = DF;
2243 edge_cycle[U][DL] = DL;
2244 edge_cycle[U][DB] = DB;
2245 edge_cycle[U][DR] = DR;
2246 edge_cycle[U][FR] = FR;
2247 edge_cycle[U][FL] = FL;
2248 edge_cycle[U][BL] = BL;
2249 edge_cycle[U][BR] = BR;
2250
2251 edge_cycle[x][UF] = DF;
2252 edge_cycle[x][UL] = FL;
2253 edge_cycle[x][UB] = UF;
2254 edge_cycle[x][UR] = FR;
2255 edge_cycle[x][DF] = DB;
2256 edge_cycle[x][DL] = BL;
2257 edge_cycle[x][DB] = UB;
2258 edge_cycle[x][DR] = BR;
2259 edge_cycle[x][FR] = DR;
2260 edge_cycle[x][FL] = DL;
2261 edge_cycle[x][BL] = UL;
2262 edge_cycle[x][BR] = UR;
2263
2264 edge_cycle[y][UF] = UR;
2265 edge_cycle[y][UL] = UF;
2266 edge_cycle[y][UB] = UL;
2267 edge_cycle[y][UR] = UB;
2268 edge_cycle[y][DF] = DR;
2269 edge_cycle[y][DL] = DF;
2270 edge_cycle[y][DB] = DL;
2271 edge_cycle[y][DR] = DB;
2272 edge_cycle[y][FR] = BR;
2273 edge_cycle[y][FL] = FR;
2274 edge_cycle[y][BL] = FL;
2275 edge_cycle[y][BR] = BL;
2276
2277 corner_cycle[U][UFR] = UBR;
2278 corner_cycle[U][UFL] = UFR;
2279 corner_cycle[U][UBL] = UFL;
2280 corner_cycle[U][UBR] = UBL;
2281 corner_cycle[U][DFR] = DFR;
2282 corner_cycle[U][DFL] = DFL;
2283 corner_cycle[U][DBL] = DBL;
2284 corner_cycle[U][DBR] = DBR;
2285
2286 corner_cycle[x][UFR] = DFR;
2287 corner_cycle[x][UFL] = DFL;
2288 corner_cycle[x][UBL] = UFL;
2289 corner_cycle[x][UBR] = UFR;
2290 corner_cycle[x][DFR] = DBR;
2291 corner_cycle[x][DFL] = DBL;
2292 corner_cycle[x][DBL] = UBL;
2293 corner_cycle[x][DBR] = UBR;
2294
2295 corner_cycle[y][UFR] = UBR;
2296 corner_cycle[y][UFL] = UFR;
2297 corner_cycle[y][UBL] = UFL;
2298 corner_cycle[y][UBR] = UBL;
2299 corner_cycle[y][DFR] = DBR;
2300 corner_cycle[y][DFL] = DFR;
2301 corner_cycle[y][DBL] = DFL;
2302 corner_cycle[y][DBR] = DBL;
2303
2304 center_cycle[U][U_center] = U_center;
2305 center_cycle[U][D_center] = D_center;
2306 center_cycle[U][R_center] = R_center;
2307 center_cycle[U][L_center] = L_center;
2308 center_cycle[U][F_center] = F_center;
2309 center_cycle[U][B_center] = B_center;
2310
2311 center_cycle[x][U_center] = F_center;
2312 center_cycle[x][D_center] = B_center;
2313 center_cycle[x][R_center] = R_center;
2314 center_cycle[x][L_center] = L_center;
2315 center_cycle[x][F_center] = D_center;
2316 center_cycle[x][B_center] = U_center;
2317
2318 center_cycle[y][U_center] = U_center;
2319 center_cycle[y][D_center] = D_center;
2320 center_cycle[y][R_center] = B_center;
2321 center_cycle[y][L_center] = F_center;
2322 center_cycle[y][F_center] = R_center;
2323 center_cycle[y][B_center] = L_center;
2324
2325 /* Flipped pieces *************/
2326 eofb_flipped[x][UF] = 1;
2327 eofb_flipped[x][UB] = 1;
2328 eofb_flipped[x][DF] = 1;
2329 eofb_flipped[x][DB] = 1;
2330
2331 eofb_flipped[y][FR] = 1;
2332 eofb_flipped[y][FL] = 1;
2333 eofb_flipped[y][BL] = 1;
2334 eofb_flipped[y][BR] = 1;
2335
2336 eorl_flipped[x][UF] = 1;
2337 eorl_flipped[x][UL] = 1;
2338 eorl_flipped[x][UB] = 1;
2339 eorl_flipped[x][UR] = 1;
2340 eorl_flipped[x][DF] = 1;
2341 eorl_flipped[x][DL] = 1;
2342 eorl_flipped[x][DB] = 1;
2343 eorl_flipped[x][DR] = 1;
2344 eorl_flipped[x][FR] = 1;
2345 eorl_flipped[x][FL] = 1;
2346 eorl_flipped[x][BL] = 1;
2347 eorl_flipped[x][BR] = 1;
2348
2349 eorl_flipped[y][FR] = 1;
2350 eorl_flipped[y][FL] = 1;
2351 eorl_flipped[y][BL] = 1;
2352 eorl_flipped[y][BR] = 1;
2353
2354 eoud_flipped[U][UF] = 1;
2355 eoud_flipped[U][UL] = 1;
2356 eoud_flipped[U][UB] = 1;
2357 eoud_flipped[U][UR] = 1;
2358
2359 eoud_flipped[x][UF] = 1;
2360 eoud_flipped[x][UB] = 1;
2361 eoud_flipped[x][DF] = 1;
2362 eoud_flipped[x][DB] = 1;
2363
2364 eoud_flipped[y][UF] = 1;
2365 eoud_flipped[y][UL] = 1;
2366 eoud_flipped[y][UB] = 1;
2367 eoud_flipped[y][UR] = 1;
2368 eoud_flipped[y][DF] = 1;
2369 eoud_flipped[y][DL] = 1;
2370 eoud_flipped[y][DB] = 1;
2371 eoud_flipped[y][DR] = 1;
2372 eoud_flipped[y][FR] = 1;
2373 eoud_flipped[y][FL] = 1;
2374 eoud_flipped[y][BL] = 1;
2375 eoud_flipped[y][BR] = 1;
2376
2377 coud_flipped[x][UFR] = 2;
2378 coud_flipped[x][UFL] = 1;
2379 coud_flipped[x][UBR] = 1;
2380 coud_flipped[x][UBL] = 2;
2381 coud_flipped[x][DFR] = 1;
2382 coud_flipped[x][DFL] = 2;
2383 coud_flipped[x][DBR] = 2;
2384 coud_flipped[x][DBL] = 1;
2385
2386 corl_flipped[U][UFR] = 1;
2387 corl_flipped[U][UFL] = 2;
2388 corl_flipped[U][UBL] = 1;
2389 corl_flipped[U][UBR] = 2;
2390
2391 corl_flipped[y][UFR] = 1;
2392 corl_flipped[y][UFL] = 2;
2393 corl_flipped[y][UBL] = 1;
2394 corl_flipped[y][UBR] = 2;
2395 corl_flipped[y][DFR] = 2;
2396 corl_flipped[y][DFL] = 1;
2397 corl_flipped[y][DBL] = 2;
2398 corl_flipped[y][DBR] = 1;
2399
2400 cofb_flipped[U][UFR] = 2;
2401 cofb_flipped[U][UFL] = 1;
2402 cofb_flipped[U][UBL] = 2;
2403 cofb_flipped[U][UBR] = 1;
2404
2405 cofb_flipped[x][UFR] = 1;
2406 cofb_flipped[x][UFL] = 2;
2407 cofb_flipped[x][UBL] = 1;
2408 cofb_flipped[x][UBR] = 2;
2409 cofb_flipped[x][DFR] = 2;
2410 cofb_flipped[x][DFL] = 1;
2411 cofb_flipped[x][DBL] = 2;
2412 cofb_flipped[x][DBR] = 1;
2413
2414 cofb_flipped[y][UFR] = 2;
2415 cofb_flipped[y][UFL] = 1;
2416 cofb_flipped[y][UBL] = 2;
2417 cofb_flipped[y][UBR] = 1;
2418 cofb_flipped[y][DFR] = 1;
2419 cofb_flipped[y][DFL] = 2;
2420 cofb_flipped[y][DBL] = 1;
2421 cofb_flipped[y][DBR] = 2;
2422
2423 /* Equivalent moves ***********/
2424 equiv_alg[NULLMOVE] = new_alg("");
2425
2426 equiv_alg[U] = new_alg(" U ");
2427 equiv_alg[U2] = new_alg(" UU ");
2428 equiv_alg[U3] = new_alg(" UUU ");
2429 equiv_alg[D] = new_alg(" xx U xx ");
2430 equiv_alg[D2] = new_alg(" xx UU xx ");
2431 equiv_alg[D3] = new_alg(" xx UUU xx ");
2432 equiv_alg[R] = new_alg(" yx U xxxyyy ");
2433 equiv_alg[R2] = new_alg(" yx UU xxxyyy ");
2434 equiv_alg[R3] = new_alg(" yx UUU xxxyyy ");
2435 equiv_alg[L] = new_alg(" yyyx U xxxy ");
2436 equiv_alg[L2] = new_alg(" yyyx UU xxxy ");
2437 equiv_alg[L3] = new_alg(" yyyx UUU xxxy ");
2438 equiv_alg[F] = new_alg(" x U xxx ");
2439 equiv_alg[F2] = new_alg(" x UU xxx ");
2440 equiv_alg[F3] = new_alg(" x UUU xxx ");
2441 equiv_alg[B] = new_alg(" xxx U x ");
2442 equiv_alg[B2] = new_alg(" xxx UU x ");
2443 equiv_alg[B3] = new_alg(" xxx UUU x ");
2444
2445 equiv_alg[Uw] = new_alg(" xx U xx y ");
2446 equiv_alg[Uw2] = new_alg(" xx UU xx yy ");
2447 equiv_alg[Uw3] = new_alg(" xx UUU xx yyy ");
2448 equiv_alg[Dw] = new_alg(" U yyy ");
2449 equiv_alg[Dw2] = new_alg(" UU yy ");
2450 equiv_alg[Dw3] = new_alg(" UUU y ");
2451 equiv_alg[Rw] = new_alg(" yyyx U xxxy x ");
2452 equiv_alg[Rw2] = new_alg(" yyyx UU xxxy xx ");
2453 equiv_alg[Rw3] = new_alg(" yyyx UUU xxxy xxx ");
2454 equiv_alg[Lw] = new_alg(" yx U xxxyyy xxx ");
2455 equiv_alg[Lw2] = new_alg(" yx UU xxxyyy xx ");
2456 equiv_alg[Lw3] = new_alg(" yx UUU xxxyyy x ");
2457 equiv_alg[Fw] = new_alg(" xxx U x yxxxyyy ");
2458 equiv_alg[Fw2] = new_alg(" xxx UU x yxxyyy ");
2459 equiv_alg[Fw3] = new_alg(" xxx UUU x yxyyy ");
2460 equiv_alg[Bw] = new_alg(" x U xxx yxyyy ");
2461 equiv_alg[Bw2] = new_alg(" x UU xxx yxxyyy ");
2462 equiv_alg[Bw3] = new_alg(" x UUU xxx yxxxyyy ");
2463
2464 equiv_alg[M] = new_alg(" yx U xx UUU yxyyy ");
2465 equiv_alg[M2] = new_alg(" yx UU xx UU xxxy ");
2466 equiv_alg[M3] = new_alg(" yx UUU xx U yxxxy ");
2467 equiv_alg[S] = new_alg(" x UUU xx U yyyx ");
2468 equiv_alg[S2] = new_alg(" x UU xx UU yyx ");
2469 equiv_alg[S3] = new_alg(" x U xx UUU yx ");
2470 equiv_alg[E] = new_alg(" U xx UUU xxyyy ");
2471 equiv_alg[E2] = new_alg(" UU xx UU xxyy ");
2472 equiv_alg[E3] = new_alg(" UUU xx U xxy ");
2473
2474 equiv_alg[x] = new_alg(" x ");
2475 equiv_alg[x2] = new_alg(" xx ");
2476 equiv_alg[x3] = new_alg(" xxx ");
2477 equiv_alg[y] = new_alg(" y ");
2478 equiv_alg[y2] = new_alg(" yy ");
2479 equiv_alg[y3] = new_alg(" yyy ");
2480 equiv_alg[z] = new_alg(" yyy x y ");
2481 equiv_alg[z2] = new_alg(" yy xx ");
2482 equiv_alg[z3] = new_alg(" y x yyy ");
2483}
2484
2485static void
2486init_strings()
2487{
2488 strcpy(move_string [NULLMOVE], "-" );
2489 strcpy(move_string [U], "U" );
2490 strcpy(move_string [U2], "U2" );
2491 strcpy(move_string [U3], "U\'" );
2492 strcpy(move_string [D], "D" );
2493 strcpy(move_string [D2], "D2" );
2494 strcpy(move_string [D3], "D\'" );
2495 strcpy(move_string [R], "R" );
2496 strcpy(move_string [R2], "R2" );
2497 strcpy(move_string [R3], "R\'" );
2498 strcpy(move_string [L], "L" );
2499 strcpy(move_string [L2], "L2" );
2500 strcpy(move_string [L3], "L\'" );
2501 strcpy(move_string [F], "F" );
2502 strcpy(move_string [F2], "F2" );
2503 strcpy(move_string [F3], "F\'" );
2504 strcpy(move_string [B], "B" );
2505 strcpy(move_string [B2], "B2" );
2506 strcpy(move_string [B3], "B\'" );
2507 strcpy(move_string [Uw], "Uw" );
2508 strcpy(move_string [Uw2], "Uw2" );
2509 strcpy(move_string [Uw3], "Uw\'" );
2510 strcpy(move_string [Dw], "Dw" );
2511 strcpy(move_string [Dw2], "Dw2" );
2512 strcpy(move_string [Dw3], "Dw\'" );
2513 strcpy(move_string [Rw], "Rw" );
2514 strcpy(move_string [Rw2], "Rw2" );
2515 strcpy(move_string [Rw3], "Rw\'" );
2516 strcpy(move_string [Lw], "Lw" );
2517 strcpy(move_string [Lw2], "Lw2" );
2518 strcpy(move_string [Lw3], "Lw\'" );
2519 strcpy(move_string [Fw], "Fw" );
2520 strcpy(move_string [Fw2], "Fw2" );
2521 strcpy(move_string [Fw3], "Fw\'" );
2522 strcpy(move_string [Bw], "Bw" );
2523 strcpy(move_string [Bw2], "Bw2" );
2524 strcpy(move_string [Bw3], "Bw\'" );
2525 strcpy(move_string [M], "M" );
2526 strcpy(move_string [M2], "M2" );
2527 strcpy(move_string [M3], "M\'" );
2528 strcpy(move_string [S], "S" );
2529 strcpy(move_string [S2], "S2" );
2530 strcpy(move_string [S3], "S\'" );
2531 strcpy(move_string [E], "E" );
2532 strcpy(move_string [E2], "E2" );
2533 strcpy(move_string [E3], "E\'" );
2534 strcpy(move_string [x], "x" );
2535 strcpy(move_string [x2], "x2" );
2536 strcpy(move_string [x3], "x\'" );
2537 strcpy(move_string [y], "y" );
2538 strcpy(move_string [y2], "y2" );
2539 strcpy(move_string [y3], "y\'" );
2540 strcpy(move_string [z], "z" );
2541 strcpy(move_string [z2], "z2" );
2542 strcpy(move_string [z3], "z\'" );
2543
2544 strcpy(edge_string [UF], "UF" );
2545 strcpy(edge_string [UL], "UL" );
2546 strcpy(edge_string [UB], "UB" );
2547 strcpy(edge_string [UR], "UR" );
2548 strcpy(edge_string [DF], "DF" );
2549 strcpy(edge_string [DL], "DL" );
2550 strcpy(edge_string [DB], "DB" );
2551 strcpy(edge_string [DR], "DR" );
2552 strcpy(edge_string [FR], "FR" );
2553 strcpy(edge_string [FL], "FL" );
2554 strcpy(edge_string [BL], "BL" );
2555 strcpy(edge_string [BR], "BR" );
2556
2557 strcpy(corner_string [UFR], "UFR" );
2558 strcpy(corner_string [UFL], "UFL" );
2559 strcpy(corner_string [UBL], "UBL" );
2560 strcpy(corner_string [UBR], "UBR" );
2561 strcpy(corner_string [DFR], "DFR" );
2562 strcpy(corner_string [DFL], "DFL" );
2563 strcpy(corner_string [DBL], "DBL" );
2564 strcpy(corner_string [DBR], "DBR" );
2565
2566 strcpy(center_string [U_center], "U" );
2567 strcpy(center_string [D_center], "D" );
2568 strcpy(center_string [R_center], "R" );
2569 strcpy(center_string [L_center], "L" );
2570 strcpy(center_string [F_center], "F" );
2571 strcpy(center_string [B_center], "B" );
2572}
2573
2574static void
2575init_symdata()
2576{
2577 int i;
2578
2579 for (i = 0; i < n_all_symdata; i++)
2580 gensym(all_sd[i]);
2581}
2582
2583static void
2584init_trans() {
2585 Cube aux, cube, mirr, c[3];
2586 CubeArray epcp;
2587 int i, eparr[12], eoarr[12], cparr[8], coarr[8];
2588 unsigned int ui;
2589 Move mi, move;
2590 Trans m;
2591
2592 /* Compute sources */
2593 for (i = 0; i < NTRANS; i++) {
2594 cube = apply_alg(rotation_algs[i % NROTATIONS], (Cube){0});
2595
2596 epose_source[i] = edge_slice(what_edge_at(cube, FR));
2597 eposs_source[i] = edge_slice(what_edge_at(cube, UR));
2598 eposm_source[i] = edge_slice(what_edge_at(cube, UF));
2599 eofb_source[i] = what_center_at(cube, F_center)/2;
2600 eorl_source[i] = what_center_at(cube, R_center)/2;
2601 eoud_source[i] = what_center_at(cube, U_center)/2;
2602 coud_source[i] = what_center_at(cube, U_center)/2;
2603 cofb_source[i] = what_center_at(cube, F_center)/2;
2604 corl_source[i] = what_center_at(cube, R_center)/2;
2605 }
2606
2607 if (read_ttables_file())
2608 return;
2609
2610 fprintf(stderr, "Cannot load %s, generating it\n", "ttables");
2611
2612 /* Initialize tables */
2613 for (m = 0; m < NTRANS; m++) {
2614 epcp = (CubeArray){ .ep = eparr, .cp = cparr };
2615 cube = apply_alg(rotation_algs[m % NROTATIONS], (Cube){0});
2616 cube_to_arrays(cube, &epcp, pf_epcp);
2617 if (m >= NROTATIONS) {
2618 apply_permutation(ep_mirror, eparr, 12);
2619 apply_permutation(cp_mirror, cparr, 8);
2620 }
2621
2622 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
2623 c[0] = admissible_ep((Cube){ .epose = ui }, pf_e);
2624 c[1] = admissible_ep((Cube){ .eposs = ui }, pf_s);
2625 c[2] = admissible_ep((Cube){ .eposm = ui }, pf_m);
2626
2627 cube = rotate_via_compose(m,c[epose_source[m]],pf_ep);
2628 epose_ttable[m][ui] = cube.epose;
2629
2630 cube = rotate_via_compose(m,c[eposs_source[m]],pf_ep);
2631 eposs_ttable[m][ui] = cube.eposs;
2632
2633 cube = rotate_via_compose(m,c[eposm_source[m]],pf_ep);
2634 eposm_ttable[m][ui] = cube.eposm;
2635 }
2636 for (ui = 0; ui < POW2TO11; ui++ ) {
2637 int_to_sum_zero_array(ui, 2, 12, eoarr);
2638 apply_permutation(eparr, eoarr, 12);
2639 eo_ttable[m][ui] = digit_array_to_int(eoarr, 11, 2);
2640 }
2641 for (ui = 0; ui < POW3TO7; ui++) {
2642 int_to_sum_zero_array(ui, 3, 8, coarr);
2643 apply_permutation(cparr, coarr, 8);
2644 co_ttable[m][ui] = digit_array_to_int(coarr, 7, 3);
2645 if (m >= NROTATIONS)
2646 co_ttable[m][ui] =
2647 invert_digits(co_ttable[m][ui], 3, 7);
2648 }
2649 for (ui = 0; ui < FACTORIAL8; ui++) {
2650 cube = (Cube){ .cp = ui };
2651 cube = rotate_via_compose(m, cube, pf_cp);
2652 cp_ttable[m][ui] = cube.cp;
2653 }
2654 for (ui = 0; ui < FACTORIAL6; ui++) {
2655 cube = (Cube){ .cpos = ui };
2656 cube = rotate_via_compose(m, cube, pf_cpos);
2657 cpos_ttable[m][ui] = cube.cpos;
2658 }
2659 for (mi = 0; mi < NMOVES; mi++) {
2660 aux = apply_trans(m, apply_move(mi, (Cube){0}));
2661 for (move = 0; move < NMOVES; move++) {
2662 cube = apply_move(inverse_move_aux[move], aux);
2663 mirr = apply_trans(uf_mirror, cube);
2664 if (is_solved(cube, false) ||
2665 is_solved(mirr, false))
2666 moves_ttable[m][mi] = move;
2667 }
2668 }
2669 }
2670
2671 if (!write_ttables_file())
2672 fprintf(stderr, "Error writing ttables\n");
2673}
2674
2675static void
2676init_trans_aux()
2677{
2678 ep_mirror[UF] = UF;
2679 ep_mirror[UL] = UR;
2680 ep_mirror[UB] = UB;
2681 ep_mirror[UR] = UL;
2682 ep_mirror[DF] = DF;
2683 ep_mirror[DL] = DR;
2684 ep_mirror[DB] = DB;
2685 ep_mirror[DR] = DL;
2686 ep_mirror[FR] = FL;
2687 ep_mirror[FL] = FR;
2688 ep_mirror[BR] = BL;
2689 ep_mirror[BL] = BR;
2690
2691 cp_mirror[UFR] = UFL;
2692 cp_mirror[UFL] = UFR;
2693 cp_mirror[UBL] = UBR;
2694 cp_mirror[UBR] = UBL;
2695 cp_mirror[DFR] = DFL;
2696 cp_mirror[DFL] = DFR;
2697 cp_mirror[DBL] = DBR;
2698 cp_mirror[DBR] = DBL;
2699
2700 cpos_mirror[U_center] = U_center;
2701 cpos_mirror[D_center] = D_center;
2702 cpos_mirror[R_center] = L_center;
2703 cpos_mirror[L_center] = R_center;
2704 cpos_mirror[F_center] = F_center;
2705 cpos_mirror[B_center] = B_center;
2706
2707 /* Is there a more elegant way? */
2708 rotation_algs[uf] = new_alg("");
2709 rotation_algs[ur] = new_alg("y");
2710 rotation_algs[ub] = new_alg("y2");
2711 rotation_algs[ul] = new_alg("y3");
2712
2713 rotation_algs[df] = new_alg("z2");
2714 rotation_algs[dr] = new_alg("y z2");
2715 rotation_algs[db] = new_alg("x2");
2716 rotation_algs[dl] = new_alg("y3 z2");
2717
2718 rotation_algs[rf] = new_alg("z3");
2719 rotation_algs[rd] = new_alg("z3 y");
2720 rotation_algs[rb] = new_alg("z3 y2");
2721 rotation_algs[ru] = new_alg("z3 y3");
2722
2723 rotation_algs[lf] = new_alg("z");
2724 rotation_algs[ld] = new_alg("z y3");
2725 rotation_algs[lb] = new_alg("z y2");
2726 rotation_algs[lu] = new_alg("z y");
2727
2728 rotation_algs[fu] = new_alg("x y2");
2729 rotation_algs[fr] = new_alg("x y");
2730 rotation_algs[fd] = new_alg("x");
2731 rotation_algs[fl] = new_alg("x y3");
2732
2733 rotation_algs[bu] = new_alg("x3");
2734 rotation_algs[br] = new_alg("x3 y");
2735 rotation_algs[bd] = new_alg("x3 y2");
2736 rotation_algs[bl] = new_alg("x3 y3");
2737}
2738
2739
2740/* Public functions implementation *******************************************/
2741
2742Cube
2743apply_alg(Alg *alg, Cube cube)
2744{
2745 return apply_alg_generic(alg, cube, pf_all, true);
2746}
2747
2748Cube
2749apply_move(Move m, Cube cube)
2750{
2751 return (Cube) {
2752 .epose = epose_mtable[m][cube.epose],
2753 .eposs = eposs_mtable[m][cube.eposs],
2754 .eposm = eposm_mtable[m][cube.eposm],
2755 .eofb = eofb_mtable[m][cube.eofb],
2756 .eorl = eorl_mtable[m][cube.eorl],
2757 .eoud = eoud_mtable[m][cube.eoud],
2758 .coud = coud_mtable[m][cube.coud],
2759 .cofb = cofb_mtable[m][cube.cofb],
2760 .corl = corl_mtable[m][cube.corl],
2761 .cp = cp_mtable[m][cube.cp],
2762 .cpos = cpos_mtable[m][cube.cpos]
2763 };
2764}
2765
2766
2767Cube
2768apply_trans(Trans t, Cube cube)
2769{
2770 int aux_epos[3] = { cube.epose, cube.eposs, cube.eposm };
2771 int aux_eo[3] = { cube.eoud, cube.eorl, cube.eofb };
2772 int aux_co[3] = { cube.coud, cube.corl, cube.cofb };
2773
2774 return (Cube) {
2775 .epose = epose_ttable[t][aux_epos[epose_source[t]]],
2776 .eposs = eposs_ttable[t][aux_epos[eposs_source[t]]],
2777 .eposm = eposm_ttable[t][aux_epos[eposm_source[t]]],
2778 .eofb = eo_ttable[t][aux_eo[eofb_source[t]]],
2779 .eorl = eo_ttable[t][aux_eo[eorl_source[t]]],
2780 .eoud = eo_ttable[t][aux_eo[eoud_source[t]]],
2781 .coud = co_ttable[t][aux_co[coud_source[t]]],
2782 .corl = co_ttable[t][aux_co[corl_source[t]]],
2783 .cofb = co_ttable[t][aux_co[cofb_source[t]]],
2784 .cp = cp_ttable[t][cube.cp],
2785 .cpos = cpos_ttable[t][cube.cpos]
2786 };
2787}
2788
2789Move
2790base_move(Move m)
2791{
2792 if (m == NULLMOVE)
2793 return NULLMOVE;
2794 else
2795 return m - (m-1)%3;
2796}
2797
2798Cube
2799compose(Cube c2, Cube c1)
2800{
2801 return compose_filtered(c2, c1, pf_all);
2802}
2803
2804/*TODO maybe move the next two */
2805uint64_t
2806cphtr(Cube cube)
2807{
2808 return cphtr_right_cosets[cube.cp];
2809}
2810
2811Cube
2812anti_cphtr(uint64_t ind)
2813{
2814 return (Cube) { .cp = cphtr_right_rep[ind] };
2815}
2816
2817uint64_t
2818epos_dependent(Cube c)
2819{
2820 return epos_dependent_aux[c.eposs/FACTORIAL4][c.epose/FACTORIAL4];
2821}
2822
2823bool
2824equal(Cube c1, Cube c2)
2825{
2826 return c1.eofb == c2.eofb &&
2827 c1.epose == c2.epose &&
2828 c1.eposs == c2.eposs &&
2829 c1.eposm == c2.eposm &&
2830 c1.coud == c2.coud &&
2831 c1.cp == c2.cp &&
2832 c1.cpos == c2.cpos;
2833}
2834
2835void
2836genptable(PruneData *pd)
2837{
2838 Move ms[NMOVES];
2839 int d;
2840 uint64_t j, oldn = 0;
2841
2842 if (pd->generated)
2843 return;
2844
2845 /* TODO: check if memory is enough, otherwise maybe crash gracefully? */
2846 pd->ptable = malloc(ptablesize(pd) * sizeof(uint8_t));
2847
2848 if (read_ptable_file(pd)) {
2849 pd->generated = true;
2850 return;
2851 }
2852
2853 fprintf(stderr, "Cannot load %s, generating it\n", pd->filename);
2854
2855 moveset_to_list(pd->moveset, NULL, ms);
2856
2857 /* We use 4 bits per value, so any distance >= 15 is set to 15 */
2858 for (j = 0; j < pd->coord->max; j++)
2859 ptable_update(pd, pd->coord->cube(j), 15);
2860
2861 /*TODO: change, set to 0 for every solved state (might be more than 1)*/
2862 ptable_update(pd, (Cube){0}, 0);
2863 pd->n = 1;
2864
2865 for (d = 0; d < 15 && pd->n < pd->coord->max; d++) {
2866 genptable_bfs(pd, d, ms);
2867 fprintf(stderr, "Depth %d done, generated %lu\t(%lu/%lu)\n",
2868 d, pd->n - oldn, pd->n, pd->coord->max);
2869 oldn = pd->n;
2870 }
2871
2872 if (!write_ptable_file(pd))
2873 fprintf(stderr, "Error writing ptable file\n");
2874
2875 pd->generated = true;
2876}
2877
2878Cube
2879inverse_cube(Cube cube)
2880{
2881 CubeArray *arr = new_cubearray(cube, pf_all);
2882 CubeArray *inv = new_cubearray((Cube){0}, pf_all);
2883 Cube ret;
2884 int i;
2885
2886 for (i = 0; i < 12; i++) {
2887 inv->ep[arr->ep[i]] = i;
2888 inv->eofb[arr->ep[i]] = arr->eofb[i];
2889 inv->eorl[arr->ep[i]] = arr->eorl[i];
2890 inv->eoud[arr->ep[i]] = arr->eoud[i];
2891 }
2892
2893 for (i = 0; i < 8; i++) {
2894 inv->cp[arr->cp[i]] = i;
2895 inv->coud[arr->cp[i]] = (3 - arr->coud[i]) % 3;
2896 inv->corl[arr->cp[i]] = (3 - arr->corl[i]) % 3;
2897 inv->cofb[arr->cp[i]] = (3 - arr->cofb[i]) % 3;
2898 }
2899
2900 for (int i = 0; i < 6; i++)
2901 inv->cpos[arr->cpos[i]] = i;
2902
2903 ret = arrays_to_cube(inv, pf_all);
2904 free_cubearray(arr, pf_all);
2905 free_cubearray(inv, pf_all);
2906
2907 return ret;
2908}
2909
2910Move
2911inverse_move(Move m)
2912{
2913 return inverse_move_aux[m];
2914}
2915
2916Trans
2917inverse_trans(Trans t)
2918{
2919 return inverse_trans_aux[t];
2920}
2921
2922bool
2923is_admissible(Cube cube)
2924{
2925 /* TODO: this should check consistency of different orientations */
2926 /* TODO: check that centers are opposite and admissible */
2927
2928 CubeArray *a = new_cubearray(cube, pf_all);
2929 int parity;
2930 bool perm;
2931
2932 perm = is_perm(a->ep, 12) &&
2933 is_perm(a->cp, 8) &&
2934 is_perm(a->cpos, 6);
2935 parity = perm_sign(a->ep, 12) +
2936 perm_sign(a->cp, 8) +
2937 perm_sign(a->cpos, 6);
2938
2939 return perm && parity % 2 == 0;
2940}
2941
2942bool
2943is_solved(Cube cube, bool reorient)
2944{
2945 int i;
2946
2947 if (reorient) {
2948 for (i = 0; i < NROTATIONS; i++)
2949 if (is_solved(apply_alg(rotation_algs[i], cube),false))
2950 return true;
2951 return false;
2952 } else {
2953 return equal(cube, (Cube){0});
2954 }
2955}
2956
2957bool
2958is_solved_block(Cube cube, Block block)
2959{
2960 int i;
2961
2962 for (i = 0; i < 12; i++)
2963 if (block.edge[i] && !is_solved_edge(cube, i))
2964 return false;
2965 for (i = 0; i < 8; i++)
2966 if (block.corner[i] && !is_solved_corner(cube, i))
2967 return false;
2968 for (i = 0; i < 6; i++)
2969 if (block.center[i] && !is_solved_center(cube, i))
2970 return false;
2971
2972 return true;
2973}
2974
2975bool
2976is_solved_center(Cube cube, Center c)
2977{
2978 return what_center_at(cube, c) == c;
2979}
2980
2981bool
2982is_solved_corner(Cube cube, Corner c)
2983{
2984 return what_corner_at(cube, c) == c &&
2985 what_orientation_corner(cube.coud, c);
2986}
2987
2988bool
2989is_solved_edge(Cube cube, Edge e)
2990{
2991 return what_edge_at(cube, e) == e &&
2992 what_orientation_edge(cube.eofb, e);
2993}
2994
2995int
2996piece_orientation(Cube cube, int piece, char *orientation)
2997{
2998 int arr[12], n, b, x;
2999
3000 if (!strcmp(orientation, "eofb")) {
3001 x = cube.eofb;
3002 n = 12;
3003 b = 2;
3004 } else if (!strcmp(orientation, "eorl")) {
3005 x = cube.eorl;
3006 n = 12;
3007 b = 2;
3008 } else if (!strcmp(orientation, "eoud")) {
3009 x = cube.eoud;
3010 n = 12;
3011 b = 2;
3012 } else if (!strcmp(orientation, "coud")) {
3013 x = cube.coud;
3014 n = 8;
3015 b = 3;
3016 } else if (!strcmp(orientation, "corl")) {
3017 x = cube.corl;
3018 n = 8;
3019 b = 3;
3020 } else if (!strcmp(orientation, "cofb")) {
3021 x = cube.cofb;
3022 n = 8;
3023 b = 3;
3024 } else {
3025 return -1;
3026 }
3027
3028 int_to_sum_zero_array(x, b, n, arr);
3029 if (piece < n)
3030 return arr[piece];
3031
3032 return -1;
3033}
3034
3035void
3036print_cube(Cube cube)
3037{
3038/*
3039 CubeArray *arr = new_cubearray(cube, pf_all);
3040
3041 for (int i = 0; i < 12; i++)
3042 printf(" %s ", edge_string[arr->ep[i]]);
3043 printf("\n");
3044
3045 for (int i = 0; i < 12; i++)
3046 printf(" %c ", arr->eofb[i] + '0');
3047 printf("\n");
3048
3049 for (int i = 0; i < 8; i++)
3050 printf("%s ", corner_string[arr->cp[i]]);
3051 printf("\n");
3052
3053 for (int i = 0; i < 8; i++)
3054 printf(" %c ", arr->coud[i] + '0');
3055 printf("\n");
3056
3057 for (int i = 0; i < 6; i++)
3058 printf(" %s ", center_string[arr->cpos[i]]);
3059 printf("\n");
3060
3061 free_cubearray(arr, pf_all);
3062*/
3063
3064 for (int i = 0; i < 12; i++)
3065 printf(" %s ", edge_string[what_edge_at(cube, i)]);
3066 printf("\n");
3067
3068 for (int i = 0; i < 12; i++)
3069 printf(" %d ", what_orientation_edge(cube.eofb, i));
3070 printf("\n");
3071
3072 for (int i = 0; i < 8; i++)
3073 printf("%s ", corner_string[what_corner_at(cube, i)]);
3074 printf("\n");
3075
3076 for (int i = 0; i < 8; i++)
3077 printf(" %d ", what_orientation_corner(cube.coud, i));
3078 printf("\n");
3079
3080 for (int i = 0; i < 6; i++)
3081 printf(" %s ", center_string[what_center_at(cube, i)]);
3082 printf("\n");
3083
3084}
3085
3086Cube
3087random_cube()
3088{
3089 CubeArray *arr = new_cubearray((Cube){0}, pf_4val);
3090 Cube ret;
3091 int ep, cp, eo, co;
3092
3093 ep = rand() % FACTORIAL12;
3094 cp = rand() % FACTORIAL8;
3095 eo = rand() % POW2TO11;
3096 co = rand() % POW3TO7;
3097
3098 index_to_perm(ep, 12, arr->ep);
3099 index_to_perm(cp, 8, arr->cp);
3100 int_to_sum_zero_array(eo, 2, 12, arr->eofb);
3101 int_to_sum_zero_array(co, 3, 8, arr->coud);
3102
3103 if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8))
3104 swap(&(arr->ep[0]), &(arr->ep[1]));
3105
3106 ret = arrays_to_cube(arr, pf_4val);
3107 free_cubearray(arr, pf_4val);
3108
3109 return ret;
3110}
3111
3112/* TODO: clean pre_trans or put it back */
3113AlgList *
3114solve(Cube cube, Step step, SolveOptions *opts)
3115{
3116 /*AlgListNode *node;*/
3117 AlgList *sols = new_alglist();
3118 /*Cube c = apply_trans(opts->pre_trans, cube);*/
3119 DfsData dd = {
3120 .m = 0,
3121 .niss = false,
3122 .lb = -1,
3123 .last1 = NULLMOVE,
3124 .last2 = NULLMOVE,
3125 .sols = sols,
3126 .current_alg = new_alg("")
3127 };
3128
3129 if (step.ready != NULL && !step.ready(cube)) {
3130 fprintf(stderr, "Cube not ready for solving step\n");
3131 return sols;
3132 }
3133
3134 moveset_to_list(step.moveset, step.estimate, dd.sorted_moves);
3135 movelist_to_position(dd.sorted_moves, dd.move_position);
3136
3137 for (dd.d = opts->min_moves;
3138 dd.d <= opts->max_moves && !(sols->len && opts->optimal_only);
3139 dd.d++) {
3140 if (opts->feedback)
3141 fprintf(stderr,
3142 "Found %d solutions, searching depth %d...\n",
3143 sols->len, dd.d);
3144 dfs(cube, step, opts, &dd);
3145 }
3146
3147/*
3148 for (node = sols->first; node != NULL; node = node->next)
3149 transform_alg(inverse_trans(opts->pre_trans), node->alg);
3150*/
3151
3152 free_alg(dd.current_alg);
3153 return sols;
3154}
3155
3156Alg *
3157inverse_alg(Alg *alg)
3158{
3159 Alg *ret = new_alg("");
3160 int i;
3161
3162 for (i = alg->len-1; i >= 0; i--)
3163 append_move(ret, inverse_move(alg->move[i]), alg->inv[i]);
3164
3165 return ret;
3166}
3167
3168Alg *
3169new_alg(char *str)
3170{
3171 Alg *alg = malloc(sizeof(Alg));
3172 int i;
3173 bool niss = false;
3174 Move j, m;
3175
3176 alg->move = malloc(30 * sizeof(Move));
3177 alg->inv = malloc(30 * sizeof(bool));
3178 alg->allocated = 30;
3179 alg->len = 0;
3180
3181 for (i = 0; str[i]; i++) {
3182 if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n')
3183 continue;
3184
3185 if (str[i] == '(' && niss) {
3186 fprintf(stderr, "Error reading moves: nested ( )\n");
3187 return alg;
3188 }
3189
3190 if (str[i] == ')' && !niss) {
3191 fprintf(stderr, "Error reading moves: unmatched )\n");
3192 return alg;
3193 }
3194
3195 if (str[i] == '(' || str[i] == ')') {
3196 niss = !niss;
3197 continue;
3198 }
3199
3200 for (j = 0; j < NMOVES; j++) {
3201 if (str[i] == move_string[j][0]) {
3202 m = j;
3203 if (m <= B && str[i+1]=='w') {
3204 m += Uw - U;
3205 i++;
3206 }
3207 if (str[i+1]=='2') {
3208 m += 1;
3209 i++;
3210 } else if (str[i+1]=='\'' || str[i+1]=='3') {
3211 m += 2;
3212 i++;
3213 }
3214 append_move(alg, m, niss);
3215 break;
3216 }
3217 }
3218 }
3219
3220 return alg;
3221}
3222
3223Alg *
3224on_inverse(Alg *alg)
3225{
3226 Alg *ret = new_alg("");
3227 int i;
3228
3229 for (i = 0; i < alg->len; i++)
3230 append_move(ret, alg->move[i], !alg->inv[i]);
3231
3232 return ret;
3233}
3234
3235void
3236print_alg(Alg *alg, bool l)
3237{
3238 /* TODO: make it possible to print to stdout or to string */
3239 /* Maybe just return a string */
3240 char fill[4];
3241 int i;
3242 bool niss = false;
3243
3244 for (i = 0; i < alg->len; i++) {
3245 if (!niss && alg->inv[i])
3246 strcpy(fill, i == 0 ? "(" : " (");
3247 if (niss && !alg->inv[i])
3248 strcpy(fill, ") ");
3249 if (niss == alg->inv[i])
3250 strcpy(fill, i == 0 ? "" : " ");
3251
3252 printf("%s%s", fill, move_string[alg->move[i]]);
3253 niss = alg->inv[i];
3254 }
3255
3256 if (niss)
3257 printf(")");
3258 if (l)
3259 printf(" (%d)", alg->len);
3260
3261 printf("\n");
3262}
3263
3264void
3265print_alglist(AlgList *al, bool l)
3266{
3267 AlgListNode *i;
3268
3269 for (i = al->first; i != NULL; i = i->next)
3270 print_alg(i->alg, l);
3271}
3272
3273void
3274print_ptable(PruneData *pd)
3275{
3276 uint64_t i, a[16];
3277
3278 for (i = 0; i < 16; i++)
3279 a[i] = 0;
3280
3281 if (!pd->generated)
3282 genptable(pd);
3283
3284 for (i = 0; i < pd->coord->max; i++)
3285 a[ptableval(pd, pd->coord->cube(i))]++;
3286
3287 fprintf(stderr, "Values for table %s\n", pd->filename);
3288 for (i = 0; i < 16; i++)
3289 printf("%2lu\t%10lu\n", i, a[i]);
3290}
3291
3292uint64_t
3293ptablesize(PruneData *pd)
3294{
3295 return (pd->coord->max + 1) / 2;
3296}
3297
3298int
3299ptableval(PruneData *pd, Cube cube)
3300{
3301 return ptableval_index(pd, pd->coord->index(cube));
3302}
3303
3304Alg *
3305rotation_alg(Trans i)
3306{
3307 return rotation_algs[i % NROTATIONS];
3308}
3309
3310void
3311transform_alg(Trans t, Alg *alg)
3312{
3313 int i;
3314
3315 for (i = 0; i < alg->len; i++)
3316 alg->move[i] = moves_ttable[t][alg->move[i]];
3317}
3318
3319Center
3320what_center_at(Cube cube, Center c)
3321{
3322 return what_center_at_aux[cube.cpos][c];
3323}
3324
3325Corner
3326what_corner_at(Cube cube, Corner c)
3327{
3328 return what_corner_at_aux[cube.cp][c];
3329}
3330
3331Edge
3332what_edge_at(Cube cube, Edge e)
3333{
3334 Edge ret;
3335 CubeArray *arr = new_cubearray(cube, pf_ep);
3336
3337 ret = arr->ep[e];
3338
3339 free_cubearray(arr, pf_ep);
3340 return ret;
3341}
3342
3343int
3344what_orientation_corner(int co, Corner c)
3345{
3346 if (c < 7)
3347 return (co / powint(3, c)) % 3;
3348 else
3349 return what_orientation_last_corner_aux[co];
3350}
3351
3352int
3353what_orientation_edge(int eo, Edge e)
3354{
3355 if (e < 11)
3356 return (eo & (1 << e)) ? 1 : 0;
3357 else
3358 return what_orientation_last_edge_aux[eo];
3359}
3360
3361Center
3362where_is_center(Cube cube, Center c)
3363{
3364 return where_is_center_aux[cube.cpos][c];
3365}
3366
3367Corner
3368where_is_corner(Cube cube, Corner c)
3369{
3370 return where_is_corner_aux[cube.cp][c];
3371}
3372
3373
3374void
3375init()
3376{
3377 /* Order is important! */
3378 init_environment();
3379 init_strings();
3380 init_moves_aux();
3381 init_moves();
3382 init_auxtables();
3383 init_cphtr_cosets();
3384 init_trans_aux();
3385 init_trans();
3386 init_symdata();
3387}
3388
diff --git a/old/2021-07-15-almostbeforerefactor/alg.h b/old/2021-07-15-almostbeforerefactor/alg.h
new file mode 100644
index 0000000..865c2b3
--- /dev/null
+++ b/old/2021-07-15-almostbeforerefactor/alg.h
@@ -0,0 +1,27 @@
1#ifndef ALG_H
2#define ALG_H
3
4#include <stdio.h>
5#include <stdbool.h>
6#include <stdlib.h>
7#include <string.h>
8
9#include "macros.h"
10#include "cubetypes.h"
11
12Move base_move(Move m);
13void free_alg(Alg *alg);
14void free_alglist(AlgList *l);
15Alg * inverse_alg(Alg *alg);
16Move inverse_move(Move m);
17bool moveset_HTM(Move m);
18bool moveset_URF(Move m);
19Alg * new_alg(char *str);
20Alg * on_inverse(Alg *alg);
21void print_alg(Alg *alg, bool l);
22void print_alglist(AlgList *al, bool l);
23Alg * rotation_alg(Trans i);
24void transform_alg(Trans t, Alg *alg);
25
26#endif
27
diff --git a/old/2021-07-15-almostbeforerefactor/cube.c b/old/2021-07-15-almostbeforerefactor/cube.c
new file mode 100644
index 0000000..ef16f9d
--- /dev/null
+++ b/old/2021-07-15-almostbeforerefactor/cube.c
@@ -0,0 +1,3391 @@
1#include "cube.h"
2
3/* TODO: remove! */
4#include "steps.h"
5
6/* Local functions **********************************************************/
7
8static Cube admissible_ep(Cube cube, PieceFilter f);
9static Cube admissible_eos_from_eofbepos(Cube cube);
10static bool allowed_next(Move move, DfsData *dd);
11static void append_alg(AlgList *l, Alg *alg);
12static void append_move(Alg *alg, Move m, bool inverse);
13static Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a);
14static void apply_permutation(int *perm, int *set, int n);
15static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f);
16static int array_ep_to_epos(int *ep, int *eps_solved);
17static Cube arrays_to_cube(CubeArray *arr, PieceFilter f);
18static int binomial(int n, int k);
19static Cube compose_filtered(Cube c2, Cube c1, PieceFilter f);
20static void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f);
21static void dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd);
22static void dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd);
23static bool dfs_check_solved(SolveOptions *opts, DfsData *dd);
24static void dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd);
25static bool dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd);
26static int digit_array_to_int(int *a, int n, int b);
27static int edge_slice(Edge e); /* E=0, S=1, M=2 */
28static int epos_dependent_pos(int pos1, int pos2);
29static int epos_from_arrays(int *epos, int *ep);
30static void epos_to_partial_ep(int epos, int *ep, int *ss);
31static int factorial(int n);
32static void free_alglistnode(AlgListNode *aln);
33static void free_cubearray(CubeArray *arr, PieceFilter f);
34static void genptable_bfs(PruneData *pd, int d, Move *ms);
35static void genptable_branch(PruneData *pd, uint64_t i, int d, Move *m);
36static void gensym(SymData *sd);
37static void index_to_perm(int p, int n, int *r);
38static void index_to_subset(int s, int n, int k, int *r);
39static void init_auxtables();
40static void init_cphtr_cosets();
41static void init_cphtr_left_cosets_bfs(int i, int c);
42static void init_cphtr_right_cosets_color(int i, int c);
43static void init_environment();
44static void init_moves();
45static void init_moves_aux();
46static void init_strings();
47static void init_symdata();
48static void init_trans();
49static void init_trans_aux();
50static void int_to_digit_array(int a, int b, int n, int *r);
51static void int_to_sum_zero_array(int x, int b, int n, int *a);
52static int invert_digits(int a, int b, int n);
53static bool is_perm(int *a, int n);
54static bool is_subset(int *a, int n, int k);
55static Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf);
56static void movelist_to_position(Move *movelist, int *position);
57static void moveset_to_list(Moveset ms, Estimator f, Move *r);
58static AlgList * new_alglist();
59static CubeArray * new_cubearray(Cube cube, PieceFilter f);
60static int perm_sign(int *a, int n);
61static int perm_to_index(int *a, int n);
62static int powint(int a, int b);
63static void ptable_update(PruneData *pd, Cube cube, int m);
64static int ptableval_index(PruneData *pd, uint64_t ind);
65static void realloc_alg(Alg *alg, int n);
66static bool read_mtables_file();
67static bool read_ptable_file(PruneData *pd);
68static bool read_symdata_file(SymData *sd);
69static bool read_ttables_file();
70static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f);
71static int subset_to_index(int *a, int n, int k);
72static void sum_arrays_mod(int *src, int *dst, int n, int m);
73static void swap(int *a, int *b);
74static bool write_mtables_file();
75static bool write_ptable_file(PruneData *pd);
76static bool write_symdata_file(SymData *sd);
77static bool write_ttables_file();
78
79
80/* All sorts of useful costants and tables **********************************/
81
82static char * tabledir;
83
84static PieceFilter pf_all;
85static PieceFilter pf_4val;
86static PieceFilter pf_epcp;
87static PieceFilter pf_cpos;
88static PieceFilter pf_cp;
89static PieceFilter pf_ep;
90static PieceFilter pf_e;
91static PieceFilter pf_s;
92static PieceFilter pf_m;
93static PieceFilter pf_eo;
94static PieceFilter pf_co;
95
96static int epe_solved[4];
97static int eps_solved[4];
98static int epm_solved[4];
99
100static char move_string[NMOVES][7];
101static char edge_string[12][7];
102static char corner_string[8][7];
103static char center_string[6][7];
104
105static Cube admissible_ee_aux[POW2TO11*BINOM12ON4];
106static bool commute[NMOVES][NMOVES];
107static bool possible_next[NMOVES][NMOVES][NMOVES];
108static Move inverse_move_aux[NMOVES];
109static Trans inverse_trans_aux[NTRANS];
110static int epos_dependent_aux[BINOM12ON4][BINOM12ON4];
111static int cphtr_left_cosets[FACTORIAL8];
112static int cphtr_right_cosets[FACTORIAL8];
113static int cphtr_right_rep[BINOM8ON4*6];
114static Center what_center_at_aux[FACTORIAL6][6];
115static Corner what_corner_at_aux[FACTORIAL8][8];
116static int what_orientation_last_corner_aux[POW3TO7];
117static int what_orientation_last_edge_aux[POW2TO11];
118static Center where_is_center_aux[FACTORIAL6][6];
119static Corner where_is_corner_aux[FACTORIAL8][8];
120static Edge where_is_edge_aux[3][FACTORIAL12/FACTORIAL8][12];
121
122static int epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
123static int eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
124static int eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
125static int eo_ttable[NTRANS][POW2TO11];
126static int cp_ttable[NTRANS][FACTORIAL8];
127static int co_ttable[NTRANS][POW3TO7];
128static int cpos_ttable[NTRANS][FACTORIAL6];
129static Move moves_ttable[NTRANS][NMOVES];
130
131static int epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
132static int eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
133static int eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
134static int eofb_mtable[NMOVES][POW2TO11];
135static int eorl_mtable[NMOVES][POW2TO11];
136static int eoud_mtable[NMOVES][POW2TO11];
137static int cp_mtable[NMOVES][FACTORIAL8];
138static int coud_mtable[NMOVES][POW3TO7];
139static int cofb_mtable[NMOVES][POW3TO7];
140static int corl_mtable[NMOVES][POW3TO7];
141static int cpos_mtable[NMOVES][FACTORIAL6];
142
143static uint64_t me[12];
144
145static int edge_cycle[NMOVES][12];
146static int corner_cycle[NMOVES][8];
147static int center_cycle[NMOVES][6];
148static int eofb_flipped[NMOVES][12];
149static int eorl_flipped[NMOVES][12];
150static int eoud_flipped[NMOVES][12];
151static int coud_flipped[NMOVES][8];
152static int corl_flipped[NMOVES][8];
153static int cofb_flipped[NMOVES][8];
154static Alg * equiv_alg[NMOVES];
155
156static int epose_source[NTRANS]; /* 0=epose, 1=eposs, 2=eposm */
157static int eposs_source[NTRANS];
158static int eposm_source[NTRANS];
159static int eofb_source[NTRANS]; /* 0=eoud, 1=eorl, 2=eofb */
160static int eorl_source[NTRANS];
161static int eoud_source[NTRANS];
162static int coud_source[NTRANS]; /* 0=coud, 1=corl, 2=cofb */
163static int cofb_source[NTRANS];
164static int corl_source[NTRANS];
165static int ep_mirror[12];
166static int cp_mirror[8];
167static int cpos_mirror[6];
168static Alg * rotation_algs[NROTATIONS];
169
170
171/* Symmetry data for some coordinates ****************************************/
172
173Trans
174trans_group_trivial[1] = { uf };
175
176Trans
177trans_group_udfix[16] = {
178 uf, ur, ub, ul,
179 df, dr, db, dl,
180 uf_mirror, ur_mirror, ub_mirror, ul_mirror,
181 df_mirror, dr_mirror, db_mirror, dl_mirror,
182};
183
184SymData
185sd_coud_16 = {
186 .filename = "sd_coud_16",
187 .coord = &coord_coud,
188 .sym_coord = &coord_coud_sym16,
189 .ntrans = 16,
190 .trans = trans_group_udfix
191};
192
193SymData
194sd_eofbepos_16 = {
195 .filename = "sd_eofbepos_16",
196 .coord = &coord_eofbepos,
197 .sym_coord = &coord_eofbepos_sym16,
198 .ntrans = 16,
199 .trans = trans_group_udfix
200};
201
202static int n_all_symdata = 2;
203static SymData * all_sd[2] = { &sd_coud_16, &sd_eofbepos_16 };
204
205/* Coordinates and their implementation **************************************/
206
207static uint64_t index_eofb(Cube cube);
208static uint64_t index_eofbepos(Cube cube);
209static uint64_t index_coud(Cube cube);
210static uint64_t index_corners(Cube cube);
211static uint64_t index_cornershtr(Cube cube);
212static uint64_t index_drud(Cube cube);
213static uint64_t index_coud_sym16(Cube cube);
214static uint64_t index_eofbepos_sym16(Cube cube);
215static uint64_t index_drud_sym16(Cube cube);
216static uint64_t index_khuge(Cube cube);
217
218static Cube antindex_eofb(uint64_t ind);
219static Cube antindex_eofbepos(uint64_t ind);
220static Cube antindex_coud(uint64_t ind);
221static Cube antindex_corners(uint64_t ind);
222static Cube antindex_cornershtr(uint64_t ind);
223static Cube antindex_drud(uint64_t ind);
224static Cube antindex_coud_sym16(uint64_t ind);
225static Cube antindex_eofbepos_sym16(uint64_t ind);
226static Cube antindex_drud_sym16(uint64_t ind);
227static Cube antindex_khuge(uint64_t ind);
228
229Coordinate
230coord_eofb = {
231 .index = index_eofb,
232 .cube = antindex_eofb,
233 .check = check_eofb,
234 .max = POW2TO11
235};
236
237Coordinate
238coord_eofbepos = {
239 .index = index_eofbepos,
240 .cube = antindex_eofbepos,
241 .check = check_eofbepos,
242 .max = POW2TO11 * BINOM12ON4
243};
244
245Coordinate
246coord_coud = {
247 .index = index_coud,
248 .cube = antindex_coud,
249 .check = check_coud,
250 .max = POW3TO7
251};
252
253Coordinate
254coord_corners = {
255 .index = index_corners,
256 .cube = antindex_corners,
257 .check = check_corners,
258 .max = POW3TO7 * FACTORIAL8
259};
260
261Coordinate
262coord_cornershtr = {
263 .index = index_cornershtr,
264 .cube = antindex_cornershtr,
265 .check = check_cornershtr,
266 .max = POW3TO7 * BINOM8ON4 * 6
267};
268
269Coordinate
270coord_drud = {
271 .index = index_drud,
272 .cube = antindex_drud,
273 .check = check_drud,
274 .max = POW2TO11 * POW3TO7 * BINOM12ON4
275};
276
277Coordinate
278coord_eofbepos_sym16 = {
279 .index = index_eofbepos_sym16,
280 .cube = antindex_eofbepos_sym16,
281 .check = check_eofbepos,
282};
283
284Coordinate
285coord_coud_sym16 = {
286 .index = index_coud_sym16,
287 .cube = antindex_coud_sym16,
288 .check = check_coud,
289};
290
291Coordinate
292coord_drud_sym16 = {
293 .index = index_drud_sym16,
294 .cube = antindex_drud_sym16,
295 .check = check_drud,
296 .max = POW3TO7 * 64430
297};
298
299Coordinate
300coord_khuge = {
301 .index = index_khuge,
302 .cube = antindex_khuge,
303 .check = check_khuge,
304 .max = POW3TO7 * FACTORIAL4 * 64430
305};
306
307
308static uint64_t
309index_eofb(Cube cube)
310{
311 return cube.eofb;
312}
313
314static uint64_t
315index_eofbepos(Cube cube)
316{
317 return (cube.epose / FACTORIAL4) * POW2TO11 + cube.eofb;
318}
319
320static uint64_t
321index_coud(Cube cube)
322{
323 return cube.coud;
324}
325
326static uint64_t
327index_corners(Cube cube)
328{
329 return cube.coud * FACTORIAL8 + cube.cp;
330}
331
332static uint64_t
333index_cornershtr(Cube cube)
334{
335 return cube.coud * BINOM8ON4 * 6 + cphtr(cube);
336}
337
338static uint64_t
339index_drud(Cube cube)
340{
341 uint64_t a, b, c;
342
343 a = cube.eofb;
344 b = cube.coud;
345 c = cube.epose / FACTORIAL4;
346
347 b *= POW2TO11;
348 c *= POW2TO11 * POW3TO7;
349
350 return a + b + c;
351}
352
353static uint64_t
354index_coud_sym16(Cube cube)
355{
356 return sd_coud_16.class[index_coud(cube)];
357}
358
359static uint64_t
360index_drud_sym16(Cube cube)
361{
362 Trans t;
363 Cube c;
364
365 t = sd_eofbepos_16.transtorep[index_eofbepos(cube)];
366 c = apply_trans(t, cube);
367
368 return index_eofbepos_sym16(c) * POW3TO7 + c.coud;
369}
370
371static uint64_t
372index_eofbepos_sym16(Cube cube)
373{
374 return sd_eofbepos_16.class[index_eofbepos(cube)];
375}
376
377static uint64_t
378index_khuge(Cube cube)
379{
380 Trans t;
381 Cube c;
382 uint64_t a;
383
384 t = sd_eofbepos_16.transtorep[index_eofbepos(cube)];
385 c = apply_trans(t, cube);
386 a = (index_eofbepos_sym16(c) * 24) + (c.epose % 24);
387
388 return a * POW3TO7 + c.coud;
389}
390
391
392/* TODO: rename */
393static Cube
394antindex_eofb(uint64_t ind)
395{
396 return (Cube){ .eofb = ind, .eorl = ind, .eoud = ind };
397}
398
399static Cube
400antindex_eofbepos(uint64_t ind)
401{
402 return admissible_ee_aux[ind];
403}
404
405/* TODO: rename */
406static Cube
407antindex_coud(uint64_t ind)
408{
409 return (Cube){ .coud = ind, .corl = ind, .cofb = ind };
410}
411
412/* TODO: admissible co for other orientations */
413static Cube
414antindex_corners(uint64_t ind)
415{
416 Cube c = {0};
417
418 c.coud = ind / FACTORIAL8;
419 c.cp = ind % FACTORIAL8;
420
421 return c;
422}
423
424/* TODO: admissible co for other orientations */
425static Cube
426antindex_cornershtr(uint64_t ind)
427{
428 Cube c = anti_cphtr(ind % (BINOM8ON4 * 6));
429
430 c.coud = ind / (BINOM8ON4 * 6);
431
432 return c;
433}
434
435/* TODO: admissible eos and cos */
436/* DONE: temporary fix, make it better */
437static Cube
438antindex_drud(uint64_t ind)
439{
440 uint64_t epos, eofb;
441 Cube c;
442
443 eofb = ind % POW2TO11;
444 epos = ind / (POW2TO11 * POW3TO7);
445 c = admissible_ee_aux[eofb + POW2TO11 * epos];
446
447 c.coud = (ind / POW2TO11) % POW3TO7;
448 c.corl = c.coud;
449 c.cofb = c.coud;
450
451 return c;
452}
453
454static Cube
455antindex_coud_sym16(uint64_t ind)
456{
457 return sd_coud_16.rep[ind];
458}
459
460static Cube
461antindex_eofbepos_sym16(uint64_t ind)
462{
463 return sd_eofbepos_16.rep[ind];
464}
465
466static Cube
467antindex_drud_sym16(uint64_t ind)
468{
469 Cube c;
470
471 c = sd_eofbepos_16.rep[ind/POW3TO7];
472 c.coud = ind % POW3TO7;
473 c.cofb = c.coud;
474 c.corl = c.coud;
475
476 return c;
477}
478
479static Cube
480antindex_khuge(uint64_t ind)
481{
482 Cube c;
483
484 c = sd_eofbepos_16.rep[ind/(FACTORIAL4*POW3TO7)];
485 c.epose = ((c.epose / 24) * 24) + ((ind/POW3TO7) % 24);
486 c.coud = ind % POW3TO7;
487
488 return c;
489}
490
491
492/* Checkers ******************************************************************/
493
494bool
495check_centers(Cube cube)
496{
497 return cube.cpos == 0;
498}
499
500bool
501check_corners(Cube cube)
502{
503 return cube.cp == 0 && cube.coud == 0;
504}
505
506bool
507check_cornershtr(Cube cube)
508{
509 return cube.coud == 0 && cphtr(cube) == 0; /* TODO: use array cphtrcosets*/
510}
511
512bool
513check_coud(Cube cube)
514{
515 return cube.coud == 0;
516}
517
518bool
519check_drud(Cube cube)
520{
521 return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0;
522}
523
524bool
525check_eofb(Cube cube)
526{
527 return cube.eofb == 0;
528}
529
530bool
531check_eofbepos(Cube cube)
532{
533 return cube.eofb == 0 && cube.epose / 24 == 0;
534}
535
536bool
537check_epose(Cube cube)
538{
539 return cube.epose == 0;
540}
541
542bool
543check_ep(Cube cube)
544{
545 return cube.epose == 0 && cube.eposs == 0 && cube.eposm == 0;
546}
547
548bool
549check_khuge(Cube cube)
550{
551 return check_drud(cube) && cube.epose % 24 == 0;
552}
553
554bool
555check_nothing(Cube cube)
556{
557 return is_admissible(cube); /*TODO: maybe change?*/
558}
559
560/* Movesets ******************************************************************/
561
562bool
563moveset_HTM(Move m)
564{
565 return m >= U && m <= B3;
566}
567
568bool
569moveset_URF(Move m)
570{
571 Move b = base_move(m);
572
573 return b == U || b == R || b == F;
574}
575
576
577/* Local functions implementation ********************************************/
578
579/* TODO: this should be an anti index (maybe?) */
580static Cube
581admissible_ep(Cube cube, PieceFilter f)
582{
583 CubeArray *arr = new_cubearray(cube, f);
584 Cube ret;
585 bool used[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
586 int i, j;
587
588 for (i = 0; i < 12; i++)
589 if (arr->ep[i] != -1)
590 used[arr->ep[i]] = true;
591
592 for (i = 0, j = 0; i < 12; i++) {
593 for ( ; j < 11 && used[j]; j++);
594 if (arr->ep[i] == -1)
595 arr->ep[i] = j++;
596 }
597
598 ret = arrays_to_cube(arr, pf_ep);
599 free_cubearray(arr, f);
600
601 return ret;
602}
603
604static Cube
605admissible_eos_from_eofbepos(Cube cube)
606{
607 Edge e;
608 Cube ret;
609 CubeArray *arr = new_cubearray(cube, pf_all);
610
611 memcpy(arr->eorl, arr->eofb, 12 * sizeof(int));
612 memcpy(arr->eoud, arr->eofb, 12 * sizeof(int));
613
614 for (e = 0; e < 12; e++) {
615 if ((edge_slice(e) != 0 && edge_slice(arr->ep[e]) == 0) ||
616 (edge_slice(e) == 0 && edge_slice(arr->ep[e]) != 0))
617 arr->eorl[e] = 1 - arr->eorl[e];
618 if ((edge_slice(e) != 2 && edge_slice(arr->ep[e]) == 2) ||
619 (edge_slice(e) == 2 && edge_slice(arr->ep[e]) != 2))
620 arr->eoud[e] = 1 - arr->eoud[e];
621 }
622
623 ret = arrays_to_cube(arr, pf_all);
624 free_cubearray(arr, pf_all);
625
626 return ret;
627}
628
629static bool
630allowed_next(Move move, DfsData *dd)
631{
632 if (!possible_next[dd->last2][dd->last1][move])
633 return false;
634
635 if (commute[dd->last1][move])
636 return dd->move_position[dd->last1] < dd->move_position[move];
637
638 return true;
639}
640
641static void
642append_alg(AlgList *l, Alg *alg)
643{
644 AlgListNode *node = malloc(sizeof(AlgListNode));
645 int i;
646
647 node->alg = new_alg("");
648 for (i = 0; i < alg->len; i++)
649 append_move(node->alg, alg->move[i], alg->inv[i]);
650 node->next = NULL;
651
652 if (++l->len == 1)
653 l->first = node;
654 else
655 l->last->next = node;
656 l->last = node;
657}
658
659static void
660append_move(Alg *alg, Move m, bool inverse)
661{
662 if (alg->len == alg->allocated)
663 realloc_alg(alg, 2*alg->len);
664
665 alg->move[alg->len] = m;
666 alg->inv [alg->len] = inverse;
667 alg->len++;
668}
669
670static Cube
671apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a)
672{
673 Cube ret = {0};
674 int i;
675
676 for (i = 0; i < alg->len; i++)
677 if (alg->inv[i])
678 ret = a ? apply_move(alg->move[i], ret) :
679 apply_move_cubearray(alg->move[i], ret, f);
680
681 ret = compose_filtered(c, inverse_cube(ret), f);
682
683 for (i = 0; i < alg->len; i++)
684 if (!alg->inv[i])
685 ret = a ? apply_move(alg->move[i], ret) :
686 apply_move_cubearray(alg->move[i], ret, f);
687
688 return ret;
689}
690
691static void
692apply_permutation(int *perm, int *set, int n)
693{
694 int *aux = malloc(n * sizeof(int));
695 int i;
696
697 if (!is_perm(perm, n))
698 return;
699
700 for (i = 0; i < n; i++)
701 aux[i] = set[perm[i]];
702
703 memcpy(set, aux, n * sizeof(int));
704 free(aux);
705}
706
707static Cube
708apply_move_cubearray(Move m, Cube cube, PieceFilter f)
709{
710 CubeArray m_arr = {
711 edge_cycle[m],
712 eofb_flipped[m],
713 eorl_flipped[m],
714 eoud_flipped[m],
715 corner_cycle[m],
716 coud_flipped[m],
717 corl_flipped[m],
718 cofb_flipped[m],
719 center_cycle[m]
720 };
721
722 return move_via_arrays(&m_arr, cube, f);
723}
724
725static int
726array_ep_to_epos(int *ep, int *ss)
727{
728 int epos[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
729 int eps[4];
730 int i, j, is;
731
732 for (i = 0, is = 0; i < 12; i++) {
733 for (j = 0; j < 4; j++) {
734 if (ep[i] == ss[j]) {
735 eps[is++] = j;
736 epos[i] = 1;
737 }
738 }
739 }
740
741 for (i = 0; i < 4; i++)
742 swap(&epos[ss[i]], &epos[i+8]);
743
744 return epos_from_arrays(epos, eps);
745}
746
747static Cube
748arrays_to_cube(CubeArray *arr, PieceFilter f)
749{
750 Cube ret = {0};
751
752 if (f.epose)
753 ret.epose = array_ep_to_epos(arr->ep, epe_solved);
754 if (f.eposs)
755 ret.eposs = array_ep_to_epos(arr->ep, eps_solved);
756 if (f.eposm)
757 ret.eposm = array_ep_to_epos(arr->ep, epm_solved);
758 if (f.eofb)
759 ret.eofb = digit_array_to_int(arr->eofb, 11, 2);
760 if (f.eorl)
761 ret.eorl = digit_array_to_int(arr->eorl, 11, 2);
762 if (f.eoud)
763 ret.eoud = digit_array_to_int(arr->eoud, 11, 2);
764 if (f.cp)
765 ret.cp = perm_to_index(arr->cp, 8);
766 if (f.coud)
767 ret.coud = digit_array_to_int(arr->coud, 7, 3);
768 if (f.corl)
769 ret.corl = digit_array_to_int(arr->corl, 7, 3);
770 if (f.cofb)
771 ret.cofb = digit_array_to_int(arr->cofb, 7, 3);
772 if (f.cpos)
773 ret.cpos = perm_to_index(arr->cpos, 6);
774
775 return ret;
776}
777
778static int
779binomial(int n, int k)
780{
781 if (n < 0 || k < 0 || k > n)
782 return 0;
783
784 return factorial(n) / (factorial(k) * factorial(n-k));
785}
786
787static Cube
788compose_filtered(Cube c2, Cube c1, PieceFilter f)
789{
790 CubeArray *arr = new_cubearray(c2, f);
791 Cube ret;
792
793 ret = move_via_arrays(arr, c1, f);
794 free_cubearray(arr, f);
795
796 return ret;
797}
798
799static void
800cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f)
801{
802 int i;
803
804 if (f.epose || f.eposs || f.eposm)
805 for (i = 0; i < 12; i++)
806 arr->ep[i] = -1;
807
808 if (f.epose)
809 epos_to_partial_ep(cube.epose, arr->ep, epe_solved);
810 if (f.eposs)
811 epos_to_partial_ep(cube.eposs, arr->ep, eps_solved);
812 if (f.eposm)
813 epos_to_partial_ep(cube.eposm, arr->ep, epm_solved);
814 if (f.eofb)
815 int_to_sum_zero_array(cube.eofb, 2, 12, arr->eofb);
816 if (f.eorl)
817 int_to_sum_zero_array(cube.eorl, 2, 12, arr->eorl);
818 if (f.eoud)
819 int_to_sum_zero_array(cube.eoud, 2, 12, arr->eoud);
820 if (f.cp)
821 index_to_perm(cube.cp, 8, arr->cp);
822 if (f.coud)
823 int_to_sum_zero_array(cube.coud, 3, 8, arr->coud);
824 if (f.corl)
825 int_to_sum_zero_array(cube.corl, 3, 8, arr->corl);
826 if (f.cofb)
827 int_to_sum_zero_array(cube.cofb, 3, 8, arr->cofb);
828 if (f.cpos)
829 index_to_perm(cube.cpos, 6, arr->cpos);
830}
831
832/*
833static int
834cphtr_cp(int cp)
835{
836 int i, a[8];
837
838 index_to_perm(cp, 8, a);
839
840 for (i = 0; i < 8; i++)
841 if (a[i] == UFR || a[i] == UBL || a[i] == DFL || a[i] == DBR)
842 a[i] = 0;
843 else
844 a[i] = 1;
845
846 swap(&a[1], &a[5]);
847 swap(&a[3], &a[7]);
848
849 return subset_to_index(a, 8, 4);
850}
851*/
852
853static void
854dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd)
855{
856 if (dfs_stop(c, s, opts, dd))
857 return;
858
859 if (dfs_check_solved(opts, dd))
860 return;
861
862 dfs_branch(c, s, opts, dd);
863
864 if (opts->can_niss && !dd->niss)
865 dfs_niss(c, s, opts, dd);
866}
867
868static void
869dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd)
870{
871 Move m, l1 = dd->last1, l2 = dd->last2, *moves = dd->sorted_moves;
872
873 int i, maxnsol = opts->max_solutions;
874
875 for (i = 0; moves[i] != NULLMOVE && dd->sols->len < maxnsol; i++) {
876 m = moves[i];
877 if (allowed_next(m, dd)) {
878 dd->last2 = dd->last1;
879 dd->last1 = m;
880 append_move(dd->current_alg, m, dd->niss);
881
882 dfs(apply_move(m, c), s, opts, dd);
883
884 dd->current_alg->len--;
885 dd->last2 = l2;
886 dd->last1 = l1;
887 }
888 }
889}
890
891static bool
892dfs_check_solved(SolveOptions *opts, DfsData *dd)
893{
894 if (dd->lb != 0)
895 return false;
896
897 if (dd->current_alg->len == dd->d) {
898 append_alg(dd->sols, dd->current_alg);
899
900 if (opts->feedback)
901 print_alg(dd->current_alg, false);
902 }
903
904 return true;
905}
906
907static void
908dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd)
909{
910 Move l1 = dd->last1, l2 = dd->last2;
911 CubeTarget ct;
912
913 ct.cube = apply_move(inverse_move(l1), (Cube){0});
914 ct.target = 1;
915
916 if (dd->current_alg->len == 0 || s.estimate(ct)) {
917 dd->niss = true;
918 dd->last1 = NULLMOVE;
919 dd->last2 = NULLMOVE;
920
921 dfs(inverse_cube(c), s, opts, dd);
922
923 dd->last1 = l1;
924 dd->last2 = l2;
925 dd->niss = false;
926 }
927}
928
929static bool
930dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd)
931{
932 CubeTarget ct = {
933 .cube = c,
934 .target = dd->d - dd->current_alg->len
935 };
936
937 if (dd->sols->len >= opts->max_solutions)
938 return true;
939
940 dd->lb = s.estimate(ct);
941 if (opts->can_niss && !dd->niss)
942 dd->lb = MIN(1, dd->lb);
943
944 if (dd->current_alg->len + dd->lb > dd->d)
945 return true;
946
947 return false;
948}
949
950static int
951digit_array_to_int(int *a, int n, int b)
952{
953 int i, ret = 0, p = 1;
954
955 for (i = 0; i < n; i++, p *= b)
956 ret += a[i] * p;
957
958 return ret;
959}
960
961static int
962edge_slice(Edge e) {
963 if (e < 0 || e > 11)
964 return -1;
965
966 if (e == FR || e == FL || e == BL || e == BR)
967 return 0;
968 if (e == UR || e == UL || e == DR || e == DL)
969 return 1;
970
971 return 2;
972}
973
974static int
975epos_dependent_pos(int poss, int pose)
976{
977 int ep[12] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
978 int ep8[8] = {0, 0, 0, 0, 0, 0, 0, 0};
979 int i, j;
980
981 epos_to_partial_ep(poss*FACTORIAL4, ep, eps_solved);
982 epos_to_partial_ep(pose*FACTORIAL4, ep, epe_solved);
983
984 for (i = 0, j = 0; i < 12; i++)
985 if (edge_slice(ep[i]) != 0)
986 ep8[j++] = (edge_slice(ep[i]) == 1) ? 1 : 0;
987
988 swap(&ep8[1], &ep8[4]);
989 swap(&ep8[3], &ep8[6]);
990
991 return subset_to_index(ep8, 8, 4);
992}
993
994static int
995epos_from_arrays(int *epos, int *ep)
996{
997 return FACTORIAL4 * subset_to_index(epos,12,4) + perm_to_index(ep,4);
998}
999
1000static void
1001epos_to_partial_ep(int epos, int *ep, int *ss)
1002{
1003 int i, is, eposs[12], eps[4];
1004
1005 index_to_perm(epos % FACTORIAL4, 4, eps);
1006 index_to_subset(epos / FACTORIAL4, 12, 4, eposs);
1007
1008 for (i = 0; i < 4; i++)
1009 swap(&eposs[ss[i]], &eposs[i+8]);
1010
1011 for (i = 0, is = 0; i < 12; i++)
1012 if (eposs[i])
1013 ep[i] = ss[eps[is++]];
1014}
1015
1016static int
1017factorial(int n)
1018{
1019 int i, ret = 1;
1020
1021 if (n < 0)
1022 return 0;
1023
1024 for (i = 1; i <= n; i++)
1025 ret *= i;
1026
1027 return ret;
1028}
1029
1030void
1031free_alg(Alg *alg)
1032{
1033 free(alg->move);
1034 free(alg->inv);
1035 free(alg);
1036}
1037
1038void
1039free_alglist(AlgList *l)
1040{
1041 AlgListNode *aux, *i = l->first;
1042
1043 while (i != NULL) {
1044 aux = i->next;
1045 free_alglistnode(i);
1046 i = aux;
1047 }
1048 free(l);
1049}
1050
1051void
1052free_alglistnode(AlgListNode *aln)
1053{
1054 free_alg(aln->alg);
1055 free(aln);
1056}
1057
1058static void
1059free_cubearray(CubeArray *arr, PieceFilter f)
1060{
1061 if (f.epose || f.eposs || f.eposm)
1062 free(arr->ep);
1063 if (f.eofb)
1064 free(arr->eofb);
1065 if (f.eorl)
1066 free(arr->eorl);
1067 if (f.eoud)
1068 free(arr->eoud);
1069 if (f.cp)
1070 free(arr->cp);
1071 if (f.coud)
1072 free(arr->coud);
1073 if (f.corl)
1074 free(arr->corl);
1075 if (f.cofb)
1076 free(arr->cofb);
1077 if (f.cpos)
1078 free(arr->cpos);
1079
1080 free(arr);
1081}
1082
1083static void
1084genptable_bfs(PruneData *pd, int d, Move *ms)
1085{
1086 uint64_t i;
1087
1088 for (i = 0; i < pd->coord->max; i++)
1089 if (ptableval_index(pd, i) == d)
1090 genptable_branch(pd, i, d, ms);
1091}
1092
1093static void
1094genptable_branch(PruneData *pd, uint64_t ind, int d, Move *ms)
1095{
1096 int i, j;
1097 Cube cc, c;
1098
1099
1100 for (i = 0; i < pd->ntrans; i++) {
1101 c = apply_trans(pd->trans[i], pd->coord->cube(ind));
1102 for (j = 0; ms[j] != NULLMOVE; j++) {
1103 cc = apply_move(ms[j], c);
1104 if (ptableval(pd, cc) > d+1)
1105 ptable_update(pd, cc, d+1);
1106 }
1107 }
1108}
1109
1110static void
1111gensym(SymData *sd)
1112{
1113 uint64_t i, in, nreps = 0;
1114 int j;
1115 Cube c, d;
1116
1117 if (sd->generated)
1118 return;
1119
1120 sd->class = malloc(sd->coord->max * sizeof(uint64_t));
1121 sd->rep = malloc(sd->coord->max * sizeof(Cube));
1122 sd->transtorep = malloc(sd->coord->max * sizeof(Trans));
1123
1124 if (read_symdata_file(sd)) {
1125 sd->generated = true;
1126 return;
1127 }
1128
1129 fprintf(stderr, "Cannot load %s, generating it\n", sd->filename);
1130
1131 for (i = 0; i < sd->coord->max; i++)
1132 sd->class[i] = sd->coord->max + 1;
1133
1134 for (i = 0; i < sd->coord->max; i++) {
1135 if (sd->class[i] == sd->coord->max + 1) {
1136 c = sd->coord->cube(i);
1137 sd->rep[nreps] = c;
1138 for (j = 0; j < sd->ntrans; j++) {
1139 d = apply_trans(sd->trans[j], c);
1140 in = sd->coord->index(d);
1141
1142 if (sd->class[in] == sd->coord->max + 1) {
1143 sd->class[in] = nreps;
1144 sd->transtorep[in] =
1145 inverse_trans(sd->trans[j]);
1146 }
1147 }
1148 nreps++;
1149 }
1150 }
1151
1152 sd->sym_coord->max = nreps;
1153 sd->rep = realloc(sd->rep, nreps * sizeof(Cube));
1154 sd->generated = true;
1155
1156 fprintf(stderr, "Found %lu classes\n", nreps);
1157
1158 if (!write_symdata_file(sd))
1159 fprintf(stderr, "Error writing SymData file\n");
1160
1161 return;
1162}
1163
1164static void
1165index_to_perm(int p, int n, int *r)
1166{
1167 int *a = malloc(n * sizeof(int));
1168 int i, j, c;
1169
1170 for (i = 0; i < n; i++)
1171 a[i] = 0;
1172
1173 if (p < 0 || p >= factorial(n))
1174 for (i = 0; i < n; i++)
1175 r[i] = -1;
1176
1177 for (i = 0; i < n; i++) {
1178 c = 0;
1179 j = 0;
1180 while (c <= p / factorial(n-i-1))
1181 c += a[j++] ? 0 : 1;
1182 r[i] = j-1;
1183 a[j-1] = 1;
1184 p %= factorial(n-i-1);
1185 }
1186
1187 free(a);
1188}
1189
1190static void
1191index_to_subset(int s, int n, int k, int *r)
1192{
1193 int i, j, v;
1194
1195 if (s < 0 || s >= binomial(n, k)) {
1196 for (i = 0; i < n; i++)
1197 r[i] = -1;
1198 return;
1199 }
1200
1201 for (i = 0; i < n; i++) {
1202 if (k == n-i) {
1203 for (j = i; j < n; j++)
1204 r[j] = 1;
1205 return;
1206 }
1207
1208 if (k == 0) {
1209 for (j = i; j < n; j++)
1210 r[j] = 0;
1211 return;
1212 }
1213
1214 v = binomial(n-i-1, k);
1215 if (s >= v) {
1216 r[i] = 1;
1217 k--;
1218 s -= v;
1219 } else {
1220 r[i] = 0;
1221 }
1222 }
1223}
1224
1225static void
1226int_to_digit_array(int a, int b, int n, int *r)
1227{
1228 int i;
1229
1230 if (b <= 1)
1231 for (i = 0; i < n; i++)
1232 r[i] = 0;
1233 else
1234 for (i = 0; i < n; i++, a /= b)
1235 r[i] = a % b;
1236}
1237
1238static void
1239int_to_sum_zero_array(int x, int b, int n, int *a)
1240{
1241 int i, s = 0;
1242
1243 if (b <= 1) {
1244 for (i = 0; i < n; i++)
1245 a[i] = 0;
1246 } else {
1247 int_to_digit_array(x, b, n-1, a);
1248 for (i = 0; i < n - 1; i++)
1249 s = (s + a[i]) % b;
1250 a[n-1] = (b - s) % b;
1251 }
1252}
1253
1254static int
1255invert_digits(int a, int b, int n)
1256{
1257 int i, ret, *r = malloc(n * sizeof(int));
1258
1259 int_to_digit_array(a, b, n, r);
1260 for (i = 0; i < n; i++)
1261 r[i] = (b-r[i]) % b;
1262
1263 ret = digit_array_to_int(r, n, b);
1264 free(r);
1265 return ret;
1266}
1267
1268static bool
1269is_perm(int *a, int n)
1270{
1271 int *aux = malloc(n * sizeof(int));
1272 int i;
1273
1274 for (i = 0; i < n; i++)
1275 if (a[i] < 0 || a[i] >= n)
1276 return false;
1277 else
1278 aux[a[i]] = 1;
1279
1280 for (i = 0; i < n; i++)
1281 if (!aux[i])
1282 return false;
1283
1284 free(aux);
1285
1286 return true;
1287}
1288
1289static bool
1290is_subset(int *a, int n, int k)
1291{
1292 int i, sum = 0;
1293
1294 for (i = 0; i < n; i++)
1295 sum += a[i] ? 1 : 0;
1296
1297 return sum == k;
1298}
1299
1300static Cube
1301move_via_arrays(CubeArray *arr, Cube c, PieceFilter f)
1302{
1303 CubeArray *arrc = new_cubearray(c, f);
1304 Cube ret;
1305
1306 if (f.epose || f.eposs || f.eposm)
1307 apply_permutation(arr->ep, arrc->ep, 12);
1308
1309 if (f.eofb) {
1310 apply_permutation(arr->ep, arrc->eofb, 12);
1311 sum_arrays_mod(arr->eofb, arrc->eofb, 12, 2);
1312 }
1313
1314 if (f.eorl) {
1315 apply_permutation(arr->ep, arrc->eorl, 12);
1316 sum_arrays_mod(arr->eorl, arrc->eorl, 12, 2);
1317 }
1318
1319 if (f.eoud) {
1320 apply_permutation(arr->ep, arrc->eoud, 12);
1321 sum_arrays_mod(arr->eoud, arrc->eoud, 12, 2);
1322 }
1323
1324 if (f.cp)
1325 apply_permutation(arr->cp, arrc->cp, 8);
1326
1327 if (f.coud) {
1328 apply_permutation(arr->cp, arrc->coud, 8);
1329 sum_arrays_mod(arr->coud, arrc->coud, 8, 3);
1330 }
1331
1332 if (f.corl) {
1333 apply_permutation(arr->cp, arrc->corl, 8);
1334 sum_arrays_mod(arr->corl, arrc->corl, 8, 3);
1335 }
1336
1337 if (f.cofb) {
1338 apply_permutation(arr->cp, arrc->cofb, 8);
1339 sum_arrays_mod(arr->cofb, arrc->cofb, 8, 3);
1340 }
1341
1342 if (f.cpos)
1343 apply_permutation(arr->cpos, arrc->cpos, 6);
1344
1345 ret = arrays_to_cube(arrc, f);
1346 free_cubearray(arrc, f);
1347
1348 return ret;
1349}
1350
1351static void
1352movelist_to_position(Move *movelist, int *position)
1353{
1354 Move m;
1355
1356 for (m = 0; m < NMOVES && movelist[m] != NULLMOVE; m++)
1357 position[movelist[m]] = m;
1358}
1359
1360static void
1361moveset_to_list(Moveset ms, Estimator f, Move *r)
1362{
1363 CubeTarget ct = { .target = 1 };
1364 int b[NMOVES];
1365 int na = 0, nb = 0;
1366 Move i;
1367
1368 if (ms == NULL) {
1369 fprintf(stderr, "Error: no moveset given\n");
1370 return;
1371 }
1372
1373 for (i = U; i < NMOVES; i++) {
1374 if (ms(i)) {
1375 ct.cube = apply_move(i, (Cube){0});
1376 if (f != NULL && f(ct))
1377 r[na++] = i;
1378 else
1379 b[nb++] = i;
1380 }
1381 }
1382
1383 memcpy(r + na, b, nb * sizeof(Move));
1384 r[na+nb] = NULLMOVE;
1385}
1386
1387static AlgList *
1388new_alglist()
1389{
1390 AlgList *ret = malloc(sizeof(AlgList));
1391
1392 ret->len = 0;
1393 ret->first = NULL;
1394 ret->last = NULL;
1395
1396 return ret;
1397}
1398
1399static CubeArray *
1400new_cubearray(Cube cube, PieceFilter f)
1401{
1402 CubeArray *arr = malloc(sizeof(CubeArray));
1403
1404 if (f.epose || f.eposs || f.eposm)
1405 arr->ep = malloc(12 * sizeof(int));
1406 if (f.eofb)
1407 arr->eofb = malloc(12 * sizeof(int));
1408 if (f.eorl)
1409 arr->eorl = malloc(12 * sizeof(int));
1410 if (f.eoud)
1411 arr->eoud = malloc(12 * sizeof(int));
1412 if (f.cp)
1413 arr->cp = malloc(8 * sizeof(int));
1414 if (f.coud)
1415 arr->coud = malloc(8 * sizeof(int));
1416 if (f.corl)
1417 arr->corl = malloc(8 * sizeof(int));
1418 if (f.cofb)
1419 arr->cofb = malloc(8 * sizeof(int));
1420 if (f.cpos)
1421 arr->cpos = malloc(6 * sizeof(int));
1422
1423 cube_to_arrays(cube, arr, f);
1424
1425 return arr;
1426}
1427
1428static int
1429perm_sign(int *a, int n)
1430{
1431 int i, j, ret = 0;
1432
1433 if (!is_perm(a,n))
1434 return -1;
1435
1436 for (i = 0; i < n; i++)
1437 for (j = i+1; j < n; j++)
1438 ret += (a[i] > a[j]) ? 1 : 0;
1439
1440 return ret % 2;
1441}
1442
1443static int
1444perm_to_index(int *a, int n)
1445{
1446 int i, j, c, ret = 0;
1447
1448 if (!is_perm(a, n))
1449 return -1;
1450
1451 for (i = 0; i < n; i++) {
1452 c = 0;
1453 for (j = i+1; j < n; j++)
1454 c += (a[i] > a[j]) ? 1 : 0;
1455 ret += factorial(n-i-1) * c;
1456 }
1457
1458 return ret;
1459}
1460
1461static int
1462powint(int a, int b)
1463{
1464 if (b < 0)
1465 return 0;
1466 if (b == 0)
1467 return 1;
1468
1469 if (b % 2)
1470 return a * powint(a, b-1);
1471 else
1472 return powint(a*a, b/2);
1473}
1474
1475static void
1476ptable_update(PruneData *pd, Cube cube, int n)
1477{
1478 uint64_t ind = pd->coord->index(cube);
1479 uint8_t oldval2 = pd->ptable[ind/2];
1480 int other = (ind % 2) ? oldval2 % 16 : oldval2 / 16;
1481
1482 pd->ptable[ind/2] = (ind % 2) ? 16*n + other : 16*other + n;
1483 pd->n++;
1484}
1485
1486static int
1487ptableval_index(PruneData *pd, uint64_t ind)
1488{
1489 return (ind % 2) ? pd->ptable[ind/2] / 16 : pd->ptable[ind/2] % 16;
1490}
1491
1492static void
1493realloc_alg(Alg *alg, int n)
1494{
1495 if (alg == NULL) {
1496 fprintf(stderr, "Error: trying to reallocate NULL alg.\n");
1497 return;
1498 }
1499
1500 if (n < alg->len) {
1501 fprintf(stderr, "Error: alg too long for reallocation ");
1502 fprintf(stderr, "(%d vs %d)\n", alg->len, n);
1503 return;
1504 }
1505
1506 if (n > 1000000) {
1507 fprintf(stderr, "Warning: very long alg,");
1508 fprintf(stderr, "something might go wrong.\n");
1509 }
1510
1511 alg->move = realloc(alg->move, n * sizeof(int));
1512 alg->inv = realloc(alg->inv, n * sizeof(int));
1513 alg->allocated = n;
1514}
1515
1516static bool
1517read_mtables_file()
1518{
1519 FILE *f;
1520 char fname[strlen(tabledir)+20];
1521 int m, b = sizeof(int);
1522 bool r = true;
1523
1524 strcpy(fname, tabledir);
1525 strcat(fname, "/mtables");
1526
1527 if ((f = fopen(fname, "rb")) == NULL)
1528 return false;
1529
1530 for (m = 0; m < NMOVES; m++) {
1531 r = r && fread(epose_mtable[m], b, me[0], f) == me[0];
1532 r = r && fread(eposs_mtable[m], b, me[1], f) == me[1];
1533 r = r && fread(eposm_mtable[m], b, me[2], f) == me[2];
1534 r = r && fread(eofb_mtable[m], b, me[3], f) == me[3];
1535 r = r && fread(eorl_mtable[m], b, me[4], f) == me[4];
1536 r = r && fread(eoud_mtable[m], b, me[5], f) == me[5];
1537 r = r && fread(cp_mtable[m], b, me[6], f) == me[6];
1538 r = r && fread(coud_mtable[m], b, me[7], f) == me[7];
1539 r = r && fread(corl_mtable[m], b, me[8], f) == me[8];
1540 r = r && fread(cofb_mtable[m], b, me[9], f) == me[9];
1541 r = r && fread(cpos_mtable[m], b, me[10], f) == me[10];
1542 }
1543
1544 fclose(f);
1545 return r;
1546}
1547
1548static bool
1549read_ptable_file(PruneData *pd)
1550{
1551 FILE *f;
1552 char fname[strlen(tabledir)+100];
1553 uint64_t r;
1554
1555 strcpy(fname, tabledir);
1556 strcat(fname, "/");
1557 strcat(fname, pd->filename);
1558
1559 if ((f = fopen(fname, "rb")) == NULL)
1560 return false;
1561
1562 r = fread(pd->ptable, sizeof(uint8_t), ptablesize(pd), f);
1563 fclose(f);
1564
1565 return r == ptablesize(pd);
1566}
1567
1568static bool
1569read_symdata_file(SymData *sd)
1570{
1571 FILE *f;
1572 char fname[strlen(tabledir)+100];
1573 uint64_t n = sd->coord->max, *sn = &sd->sym_coord->max;
1574 bool r = true;
1575
1576 strcpy(fname, tabledir);
1577 strcat(fname, "/");
1578 strcat(fname, sd->filename);
1579
1580 if ((f = fopen(fname, "rb")) == NULL)
1581 return false;
1582
1583 r = r && fread(&sd->sym_coord->max, sizeof(uint64_t), 1, f) == 1;
1584 r = r && fread(sd->rep, sizeof(Cube), *sn, f) == *sn;
1585 r = r && fread(sd->class, sizeof(uint64_t), n, f) == n;
1586 r = r && fread(sd->transtorep, sizeof(Trans), n, f) == n;
1587
1588 fclose(f);
1589 return r;
1590}
1591
1592static bool
1593read_ttables_file()
1594{
1595 FILE *f;
1596 char fname[strlen(tabledir)+20];
1597 int b = sizeof(int);
1598 bool r = true;
1599 Move m;
1600
1601 strcpy(fname, tabledir);
1602 strcat(fname, "/");
1603 strcat(fname, "ttables");
1604
1605 if ((f = fopen(fname, "rb")) == NULL)
1606 return false;
1607
1608 for (m = 0; m < NTRANS; m++) {
1609 r = r && fread(epose_ttable[m], b, me[0], f) == me[0];
1610 r = r && fread(eposs_ttable[m], b, me[1], f) == me[1];
1611 r = r && fread(eposm_ttable[m], b, me[2], f) == me[2];
1612 r = r && fread(eo_ttable[m], b, me[3], f) == me[3];
1613 r = r && fread(cp_ttable[m], b, me[6], f) == me[6];
1614 r = r && fread(co_ttable[m], b, me[7], f) == me[7];
1615 r = r && fread(cpos_ttable[m], b, me[10], f) == me[10];
1616 r = r && fread(moves_ttable[m], b, me[11], f) == me[11];
1617 }
1618
1619 fclose(f);
1620 return r;
1621}
1622
1623static Cube
1624rotate_via_compose(Trans r, Cube c, PieceFilter f)
1625{
1626 static int zero12[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1627 static int zero8[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
1628 static CubeArray ma = {
1629 .ep = ep_mirror,
1630 .eofb = zero12,
1631 .eorl = zero12,
1632 .eoud = zero12,
1633 .cp = cp_mirror,
1634 .coud = zero8,
1635 .corl = zero8,
1636 .cofb = zero8,
1637 .cpos = cpos_mirror
1638 };
1639
1640 Alg *inv = inverse_alg(rotation_algs[r % NROTATIONS]);
1641 Cube ret = {0};
1642
1643 if (r >= NROTATIONS)
1644 ret = move_via_arrays(&ma, ret, f);
1645 ret = apply_alg_generic(inv, ret, f, true);
1646
1647 ret = compose_filtered(c, ret, f);
1648
1649 ret = apply_alg_generic(rotation_algs[r % NROTATIONS], ret, f, true);
1650 if (r >= NROTATIONS)
1651 ret = move_via_arrays(&ma, ret, f);
1652
1653 free_alg(inv);
1654 return ret;
1655}
1656
1657static int
1658subset_to_index(int *a, int n, int k)
1659{
1660 int i, ret = 0;
1661
1662 if (!is_subset(a, n, k))
1663 return binomial(n, k);
1664
1665 for (i = 0; i < n; i++) {
1666 if (k == n-i)
1667 return ret;
1668 if (a[i]) {
1669 ret += binomial(n-i-1, k);
1670 k--;
1671 }
1672 }
1673
1674 return ret;
1675}
1676
1677static void
1678sum_arrays_mod(int *src, int *dst, int n, int m)
1679{
1680 int i;
1681
1682 for (i = 0; i < n; i++)
1683 dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m;
1684}
1685
1686static void
1687swap(int *a, int *b)
1688{
1689 int aux;
1690
1691 aux = *a;
1692 *a = *b;
1693 *b = aux;
1694}
1695
1696static bool
1697write_mtables_file()
1698{
1699 FILE *f;
1700 char fname[strlen(tabledir)+20];
1701 int m, b = sizeof(int);
1702 bool r = true;
1703
1704 strcpy(fname, tabledir);
1705 strcat(fname, "/mtables");
1706
1707 if ((f = fopen(fname, "wb")) == NULL)
1708 return false;
1709
1710 for (m = 0; m < NMOVES; m++) {
1711 r = r && fwrite(epose_mtable[m], b, me[0], f) == me[0];
1712 r = r && fwrite(eposs_mtable[m], b, me[1], f) == me[1];
1713 r = r && fwrite(eposm_mtable[m], b, me[2], f) == me[2];
1714 r = r && fwrite(eofb_mtable[m], b, me[3], f) == me[3];
1715 r = r && fwrite(eorl_mtable[m], b, me[4], f) == me[4];
1716 r = r && fwrite(eoud_mtable[m], b, me[5], f) == me[5];
1717 r = r && fwrite(cp_mtable[m], b, me[6], f) == me[6];
1718 r = r && fwrite(coud_mtable[m], b, me[7], f) == me[7];
1719 r = r && fwrite(corl_mtable[m], b, me[8], f) == me[8];
1720 r = r && fwrite(cofb_mtable[m], b, me[9], f) == me[9];
1721 r = r && fwrite(cpos_mtable[m], b, me[10], f) == me[10];
1722 }
1723
1724 fclose(f);
1725 return r;
1726}
1727
1728static bool
1729write_ptable_file(PruneData *pd)
1730{
1731 FILE *f;
1732 char fname[strlen(tabledir)+100];
1733 uint64_t written;
1734
1735 strcpy(fname, tabledir);
1736 strcat(fname, "/");
1737 strcat(fname, pd->filename);
1738
1739 if ((f = fopen(fname, "wb")) == NULL)
1740 return false;
1741
1742 written = fwrite(pd->ptable, sizeof(uint8_t), ptablesize(pd), f);
1743 fclose(f);
1744
1745 return written == ptablesize(pd);
1746}
1747
1748static bool
1749write_symdata_file(SymData *sd)
1750{
1751 FILE *f;
1752 char fname[strlen(tabledir)+100];
1753 uint64_t n = sd->coord->max, *sn = &sd->sym_coord->max;
1754 bool r = true;
1755
1756 strcpy(fname, tabledir);
1757 strcat(fname, "/");
1758 strcat(fname, sd->filename);
1759
1760 if ((f = fopen(fname, "wb")) == NULL)
1761 return false;
1762
1763 r = r && fwrite(&sd->sym_coord->max, sizeof(uint64_t), 1, f) == 1;
1764 r = r && fwrite(sd->rep, sizeof(Cube), *sn, f) == *sn;
1765 r = r && fwrite(sd->class, sizeof(uint64_t), n, f) == n;
1766 r = r && fwrite(sd->transtorep, sizeof(Trans), n, f) == n;
1767
1768 fclose(f);
1769 return r;
1770}
1771
1772static bool
1773write_ttables_file()
1774{
1775 FILE *f;
1776 char fname[strlen(tabledir)+20];
1777 bool r = true;
1778 int b = sizeof(int);
1779 Move m;
1780
1781 strcpy(fname, tabledir);
1782 strcat(fname, "/ttables");
1783
1784 if ((f = fopen(fname, "wb")) == NULL)
1785 return false;
1786
1787 for (m = 0; m < NTRANS; m++) {
1788 r = r && fwrite(epose_ttable[m], b, me[0], f) == me[0];
1789 r = r && fwrite(eposs_ttable[m], b, me[1], f) == me[1];
1790 r = r && fwrite(eposm_ttable[m], b, me[2], f) == me[2];
1791 r = r && fwrite(eo_ttable[m], b, me[3], f) == me[3];
1792 r = r && fwrite(cp_ttable[m], b, me[6], f) == me[6];
1793 r = r && fwrite(co_ttable[m], b, me[7], f) == me[7];
1794 r = r && fwrite(cpos_ttable[m], b, me[10], f) == me[10];
1795 r = r && fwrite(moves_ttable[m], b, me[11], f) == me[11];
1796 }
1797
1798 fclose(f);
1799 return r;
1800}
1801
1802/* Init functions implementation *********************************************/
1803
1804static void
1805init_auxtables()
1806{
1807 Cube c1, c2;
1808 CubeArray *arr;
1809 uint64_t ui, uj;
1810 int i, j, k, auxarr[12];
1811 bool cij, p1, p2;
1812
1813 for (ui = 0; ui < POW2TO11*BINOM12ON4; ui++) {
1814 k = (ui / POW2TO11) * 24;
1815 c1 = admissible_ep((Cube){ .epose = k }, pf_e);
1816 c1.eofb = ui % POW2TO11;
1817 c1 = admissible_eos_from_eofbepos(c1);
1818 admissible_ee_aux[ui] = c1;
1819 }
1820
1821 for (ui = 0; ui < FACTORIAL6; ui++) {
1822 arr = new_cubearray((Cube){.cpos = ui}, pf_cpos);
1823 for (i = 0; i < 6; i++) {
1824 what_center_at_aux[ui][i] = arr->cpos[i];
1825 where_is_center_aux[ui][arr->cpos[i]] = i;
1826 }
1827 free_cubearray(arr, pf_cpos);
1828 }
1829
1830 for (ui = 0; ui < FACTORIAL8; ui++) {
1831 arr = new_cubearray((Cube){.cp = ui}, pf_cp);
1832 for (i = 0; i < 8; i++) {
1833 what_corner_at_aux[ui][i] = arr->cp[i];
1834 where_is_corner_aux[ui][arr->cp[i]] = i;
1835 }
1836 free_cubearray(arr, pf_cp);
1837 }
1838
1839 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
1840 arr = new_cubearray((Cube){.epose = ui}, pf_e);
1841 for (i = 0; i < 12; i++)
1842 if (edge_slice(arr->ep[i]) == 0)
1843 where_is_edge_aux[0][ui][arr->ep[i]] = i;
1844 free_cubearray(arr, pf_e);
1845
1846 arr = new_cubearray((Cube){.eposs = ui}, pf_s);
1847 for (i = 0; i < 12; i++)
1848 if (edge_slice(arr->ep[i]) == 1)
1849 where_is_edge_aux[1][ui][arr->ep[i]] = i;
1850 free_cubearray(arr, pf_s);
1851
1852 arr = new_cubearray((Cube){.eposm = ui}, pf_m);
1853 for (i = 0; i < 12; i++)
1854 if (edge_slice(arr->ep[i]) == 2)
1855 where_is_edge_aux[2][ui][arr->ep[i]] = i;
1856 free_cubearray(arr, pf_m);
1857 }
1858
1859 for (ui = 0; ui < POW3TO7; ui++) {
1860 int_to_sum_zero_array(ui, 3, 8, auxarr);
1861 what_orientation_last_corner_aux[ui] = auxarr[7];
1862 }
1863
1864 for (ui = 0; ui < POW2TO11; ui++) {
1865 int_to_sum_zero_array(ui, 2, 12, auxarr);
1866 what_orientation_last_edge_aux[ui] = auxarr[11];
1867 }
1868
1869 for (ui = 0; ui < BINOM12ON4; ui++)
1870 for (uj = 0; uj < BINOM12ON4; uj++)
1871 epos_dependent_aux[ui][uj]=epos_dependent_pos(ui, uj);
1872
1873 for (i = 0; i < NMOVES; i++) {
1874 for (j = 0; j < NMOVES; j++) {
1875 c1 = apply_move(i, apply_move(j, (Cube){0}));
1876 c2 = apply_move(j, apply_move(i, (Cube){0}));
1877 commute[i][j] = equal(c1, c2) && i && j;
1878 }
1879 }
1880
1881 for (i = 0; i < NMOVES; i++) {
1882 for (j = 0; j < NMOVES; j++) {
1883 for (k = 0; k < NMOVES; k++) {
1884 p1 = j && base_move(j) == base_move(k);
1885 p2 = i && base_move(i) == base_move(k);
1886 cij = commute[i][j];
1887 possible_next[i][j][k] = !(p1 || (cij && p2));
1888 }
1889 }
1890 }
1891
1892 for (i = 0; i < NMOVES; i++)
1893 inverse_move_aux[i] = i ? i + 2 - 2*((i-1)%3) : NULLMOVE;
1894
1895 /* Is there a more elegant way? */
1896 inverse_trans_aux[uf] = uf;
1897 inverse_trans_aux[ur] = ul;
1898 inverse_trans_aux[ul] = ur;
1899 inverse_trans_aux[ub] = ub;
1900
1901 inverse_trans_aux[df] = df;
1902 inverse_trans_aux[dr] = dr;
1903 inverse_trans_aux[dl] = dl;
1904 inverse_trans_aux[db] = db;
1905
1906 inverse_trans_aux[rf] = lf;
1907 inverse_trans_aux[rd] = bl;
1908 inverse_trans_aux[rb] = rb;
1909 inverse_trans_aux[ru] = fr;
1910
1911 inverse_trans_aux[lf] = rf;
1912 inverse_trans_aux[ld] = br;
1913 inverse_trans_aux[lb] = lb;
1914 inverse_trans_aux[lu] = fl;
1915
1916 inverse_trans_aux[fu] = fu;
1917 inverse_trans_aux[fr] = ru;
1918 inverse_trans_aux[fd] = bu;
1919 inverse_trans_aux[fl] = lu;
1920
1921 inverse_trans_aux[bu] = fd;
1922 inverse_trans_aux[br] = ld;
1923 inverse_trans_aux[bd] = bd;
1924 inverse_trans_aux[bl] = rd;
1925
1926 inverse_trans_aux[uf_mirror] = uf_mirror;
1927 inverse_trans_aux[ur_mirror] = ur_mirror;
1928 inverse_trans_aux[ul_mirror] = ul_mirror;
1929 inverse_trans_aux[ub_mirror] = ub_mirror;
1930
1931 inverse_trans_aux[df_mirror] = df_mirror;
1932 inverse_trans_aux[dr_mirror] = dl_mirror;
1933 inverse_trans_aux[dl_mirror] = dr_mirror;
1934 inverse_trans_aux[db_mirror] = db_mirror;
1935
1936 inverse_trans_aux[rf_mirror] = rf_mirror;
1937 inverse_trans_aux[rd_mirror] = br_mirror;
1938 inverse_trans_aux[rb_mirror] = lb_mirror;
1939 inverse_trans_aux[ru_mirror] = fl_mirror;
1940
1941 inverse_trans_aux[lf_mirror] = lf_mirror;
1942 inverse_trans_aux[ld_mirror] = bl_mirror;
1943 inverse_trans_aux[lb_mirror] = rb_mirror;
1944 inverse_trans_aux[lu_mirror] = fr_mirror;
1945
1946 inverse_trans_aux[fu_mirror] = fu_mirror;
1947 inverse_trans_aux[fr_mirror] = lu_mirror;
1948 inverse_trans_aux[fd_mirror] = bu_mirror;
1949 inverse_trans_aux[fl_mirror] = ru_mirror;
1950
1951 inverse_trans_aux[bu_mirror] = fd_mirror;
1952 inverse_trans_aux[br_mirror] = rd_mirror;
1953 inverse_trans_aux[bd_mirror] = bd_mirror;
1954 inverse_trans_aux[bl_mirror] = ld_mirror;
1955}
1956
1957/*
1958 * There is certainly a bette way to do this, but for now I just use
1959 * a "graph coloring" algorithm to compute the left cosets, and I compose
1960 * with every possible cp to get the right cosets (it is possible that I am
1961 * mixing up left and right).
1962 *
1963 * For doing it better "Mathematically", we need 3 things:
1964 * - Checking that cp separates the orbits (UFR,UBL,DFL,DBR) and the other
1965 * This is easy and it is done in the commented function cphtr_cp().
1966 * - Check that there is no ep/cp parity
1967 * - Check that we are not in the "3c" case; this is the part I don't
1968 * know how to do.
1969 */
1970static void
1971init_cphtr_cosets()
1972{
1973 unsigned int i;
1974 int c = 0, d = 0;
1975
1976 for (i = 0; i < FACTORIAL8; i++) {
1977 cphtr_left_cosets[i] = -1;
1978 cphtr_right_cosets[i] = -1;
1979 }
1980
1981 /* First we compute left cosets with a bfs */
1982 for (i = 0; i < FACTORIAL8; i++)
1983 if (cphtr_left_cosets[i] == -1)
1984 init_cphtr_left_cosets_bfs(i, c++);
1985
1986 /* Then we compute right cosets using compose() */
1987 for (i = 0; i < FACTORIAL8; i++)
1988 if (cphtr_right_cosets[i] == -1)
1989 init_cphtr_right_cosets_color(i, d++);
1990}
1991
1992static void
1993init_cphtr_left_cosets_bfs(int i, int c)
1994{
1995 int j, jj, k, next[FACTORIAL8], next2[FACTORIAL8], n, n2;
1996 Move moves[6] = {U2, D2, R2, L2, F2, B2};
1997
1998 n = 1;
1999 next[0] = i;
2000 cphtr_left_cosets[i] = c;
2001
2002 while (n != 0) {
2003 for (j = 0, n2 = 0; j < n; j++) {
2004 for (k = 0; k < 6; k++) {
2005 jj = cp_mtable[moves[k]][next[j]];
2006 if (cphtr_left_cosets[jj] == -1) {
2007 cphtr_left_cosets[jj] = c;
2008 next2[n2++] = jj;
2009 }
2010 }
2011 }
2012
2013 for (j = 0; j < n2; j++)
2014 next[j] = next2[j];
2015 n = n2;
2016 }
2017}
2018
2019static void
2020init_cphtr_right_cosets_color(int i, int d)
2021{
2022 int cp;
2023 unsigned int j;
2024
2025 cphtr_right_rep[d] = i;
2026 for (j = 0; j < FACTORIAL8; j++) {
2027 if (cphtr_left_cosets[j] == 0) {
2028 /* TODO: use antindexer, it's nicer */
2029 cp = compose((Cube){.cp = i}, (Cube){.cp = j}).cp;
2030 cphtr_right_cosets[cp] = d;
2031 }
2032 }
2033}
2034
2035static void
2036init_environment()
2037{
2038 char *nissydata = getenv("NISSYDATA");
2039 char *localdata = getenv("XDG_DATA_HOME");
2040 char *home = getenv("HOME");
2041 bool read, write;
2042
2043 if (nissydata != NULL) {
2044 tabledir = malloc(strlen(nissydata) * sizeof(char) + 20);
2045 strcpy(tabledir, nissydata);
2046 } else if (localdata != NULL) {
2047 tabledir = malloc(strlen(localdata) * sizeof(char) + 20);
2048 strcpy(tabledir, localdata);
2049 strcat(tabledir, "/nissy");
2050 } else if (home != NULL) {
2051 tabledir = malloc(strlen(home) * sizeof(char) + 20);
2052 strcpy(tabledir, home);
2053 strcat(tabledir, "/.nissy");
2054 }
2055
2056 mkdir(tabledir, 0777);
2057 strcat(tabledir, "/tables");
2058 mkdir(tabledir, 0777);
2059
2060 read = !access(tabledir, R_OK);
2061 write = !access(tabledir, W_OK);
2062
2063 if (!read) {
2064 fprintf(stderr, "Table files cannot be read.\n");
2065 } else if (!write) {
2066 fprintf(stderr, "Data directory not writable: ");
2067 fprintf(stderr, "tables can be loaded, but not saved.\n");
2068 }
2069}
2070
2071static void
2072init_moves() {
2073 Cube c;
2074 CubeArray arrs;
2075 int i;
2076 unsigned int ui;
2077 Move m;
2078
2079 /* Generate all move cycles and flips; I do this regardless */
2080 for (i = 0; i < NMOVES; i++) {
2081 if (i == U || i == x || i == y)
2082 continue;
2083
2084 c = apply_alg_generic(equiv_alg[i], (Cube){0}, pf_all, false);
2085
2086 arrs = (CubeArray) {
2087 edge_cycle[i],
2088 eofb_flipped[i],
2089 eorl_flipped[i],
2090 eoud_flipped[i],
2091 corner_cycle[i],
2092 coud_flipped[i],
2093 corl_flipped[i],
2094 cofb_flipped[i],
2095 center_cycle[i]
2096 };
2097 cube_to_arrays(c, &arrs, pf_all);
2098 }
2099
2100 if (read_mtables_file())
2101 return;
2102
2103 fprintf(stderr, "Cannot load %s, generating it\n", "mtables");
2104
2105 /* Initialize transition tables */
2106 for (m = 0; m < NMOVES; m++) {
2107 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
2108 c = (Cube){ .epose = ui };
2109 c = apply_move_cubearray(m, c, pf_e);
2110 epose_mtable[m][ui] = c.epose;
2111
2112 c = (Cube){ .eposs = ui };
2113 c = apply_move_cubearray(m, c, pf_s);
2114 eposs_mtable[m][ui] = c.eposs;
2115
2116 c = (Cube){ .eposm = ui };
2117 c = apply_move_cubearray(m, c, pf_m);
2118 eposm_mtable[m][ui] = c.eposm;
2119 }
2120 for (ui = 0; ui < POW2TO11; ui++ ) {
2121 c = (Cube){ .eofb = ui };
2122 c = apply_move_cubearray(m, c, pf_eo);
2123 eofb_mtable[m][ui] = c.eofb;
2124
2125 c = (Cube){ .eorl = ui };
2126 c = apply_move_cubearray(m, c, pf_eo);
2127 eorl_mtable[m][ui] = c.eorl;
2128
2129 c = (Cube){ .eoud = ui };
2130 c = apply_move_cubearray(m, c, pf_eo);
2131 eoud_mtable[m][ui] = c.eoud;
2132 }
2133 for (ui = 0; ui < POW3TO7; ui++) {
2134 c = (Cube){ .coud = ui };
2135 c = apply_move_cubearray(m, c, pf_co);
2136 coud_mtable[m][ui] = c.coud;
2137
2138 c = (Cube){ .corl = ui };
2139 c = apply_move_cubearray(m, c, pf_co);
2140 corl_mtable[m][ui] = c.corl;
2141
2142 c = (Cube){ .cofb = ui };
2143 c = apply_move_cubearray(m, c, pf_co);
2144 cofb_mtable[m][ui] = c.cofb;
2145 }
2146 for (ui = 0; ui < FACTORIAL8; ui++) {
2147 c = (Cube){ .cp = ui };
2148 c = apply_move_cubearray(m, c, pf_cp);
2149 cp_mtable[m][ui] = c.cp;
2150 }
2151 for (ui = 0; ui < FACTORIAL6; ui++) {
2152 c = (Cube){ .cpos = ui };
2153 c = apply_move_cubearray(m, c, pf_cpos);
2154 cpos_mtable[m][ui] = c.cpos;
2155 }
2156 }
2157
2158 if (!write_mtables_file())
2159 fprintf(stderr, "Error writing mtables\n");
2160}
2161
2162static void
2163init_moves_aux()
2164{
2165 /* Some standard PieceFilters */
2166 pf_all.epose = true;
2167 pf_all.eposs = true;
2168 pf_all.eposm = true;
2169 pf_all.eofb = true;
2170 pf_all.eorl = true;
2171 pf_all.eoud = true;
2172 pf_all.cp = true;
2173 pf_all.cofb = true;
2174 pf_all.corl = true;
2175 pf_all.coud = true;
2176 pf_all.cpos = true;
2177
2178 pf_4val.epose = true;
2179 pf_4val.eposs = true;
2180 pf_4val.eposm = true;
2181 pf_4val.eofb = true;
2182 pf_4val.coud = true;
2183 pf_4val.cp = true;
2184
2185 pf_epcp.epose = true;
2186 pf_epcp.eposs = true;
2187 pf_epcp.eposm = true;
2188 pf_epcp.cp = true;
2189
2190 pf_cpos.cpos = true;
2191
2192 pf_cp.cp = true;
2193
2194 pf_ep.epose = true;
2195 pf_ep.eposs = true;
2196 pf_ep.eposm = true;
2197
2198 pf_e.epose = true;
2199 pf_s.eposs = true;
2200 pf_m.eposm = true;
2201
2202 pf_eo.eofb = true;
2203 pf_eo.eorl = true;
2204 pf_eo.eoud = true;
2205
2206 pf_co.cofb = true;
2207 pf_co.corl = true;
2208 pf_co.coud = true;
2209
2210 /* Used to convert to and from CubeArray */
2211 epe_solved[0] = FR;
2212 epe_solved[1] = FL;
2213 epe_solved[2] = BL;
2214 epe_solved[3] = BR;
2215
2216 eps_solved[0] = UL;
2217 eps_solved[1] = UR;
2218 eps_solved[2] = DL;
2219 eps_solved[3] = DR;
2220
2221 epm_solved[0] = UF;
2222 epm_solved[1] = UB;
2223 epm_solved[2] = DF;
2224 epm_solved[3] = DB;
2225
2226 /* Table sizes, used for reading and writing files */
2227 me[0] = FACTORIAL12/FACTORIAL8;
2228 me[1] = FACTORIAL12/FACTORIAL8;
2229 me[2] = FACTORIAL12/FACTORIAL8;
2230 me[3] = POW2TO11;
2231 me[4] = POW2TO11;
2232 me[5] = POW2TO11;
2233 me[6] = FACTORIAL8;
2234 me[7] = POW3TO7;
2235 me[8] = POW3TO7;
2236 me[9] = POW3TO7;
2237 me[10] = FACTORIAL6;
2238 me[11] = NMOVES;
2239
2240 /* Cycles *********************/
2241 edge_cycle[U][UF] = UR;
2242 edge_cycle[U][UL] = UF;
2243 edge_cycle[U][UB] = UL;
2244 edge_cycle[U][UR] = UB;
2245 edge_cycle[U][DF] = DF;
2246 edge_cycle[U][DL] = DL;
2247 edge_cycle[U][DB] = DB;
2248 edge_cycle[U][DR] = DR;
2249 edge_cycle[U][FR] = FR;
2250 edge_cycle[U][FL] = FL;
2251 edge_cycle[U][BL] = BL;
2252 edge_cycle[U][BR] = BR;
2253
2254 edge_cycle[x][UF] = DF;
2255 edge_cycle[x][UL] = FL;
2256 edge_cycle[x][UB] = UF;
2257 edge_cycle[x][UR] = FR;
2258 edge_cycle[x][DF] = DB;
2259 edge_cycle[x][DL] = BL;
2260 edge_cycle[x][DB] = UB;
2261 edge_cycle[x][DR] = BR;
2262 edge_cycle[x][FR] = DR;
2263 edge_cycle[x][FL] = DL;
2264 edge_cycle[x][BL] = UL;
2265 edge_cycle[x][BR] = UR;
2266
2267 edge_cycle[y][UF] = UR;
2268 edge_cycle[y][UL] = UF;
2269 edge_cycle[y][UB] = UL;
2270 edge_cycle[y][UR] = UB;
2271 edge_cycle[y][DF] = DR;
2272 edge_cycle[y][DL] = DF;
2273 edge_cycle[y][DB] = DL;
2274 edge_cycle[y][DR] = DB;
2275 edge_cycle[y][FR] = BR;
2276 edge_cycle[y][FL] = FR;
2277 edge_cycle[y][BL] = FL;
2278 edge_cycle[y][BR] = BL;
2279
2280 corner_cycle[U][UFR] = UBR;
2281 corner_cycle[U][UFL] = UFR;
2282 corner_cycle[U][UBL] = UFL;
2283 corner_cycle[U][UBR] = UBL;
2284 corner_cycle[U][DFR] = DFR;
2285 corner_cycle[U][DFL] = DFL;
2286 corner_cycle[U][DBL] = DBL;
2287 corner_cycle[U][DBR] = DBR;
2288
2289 corner_cycle[x][UFR] = DFR;
2290 corner_cycle[x][UFL] = DFL;
2291 corner_cycle[x][UBL] = UFL;
2292 corner_cycle[x][UBR] = UFR;
2293 corner_cycle[x][DFR] = DBR;
2294 corner_cycle[x][DFL] = DBL;
2295 corner_cycle[x][DBL] = UBL;
2296 corner_cycle[x][DBR] = UBR;
2297
2298 corner_cycle[y][UFR] = UBR;
2299 corner_cycle[y][UFL] = UFR;
2300 corner_cycle[y][UBL] = UFL;
2301 corner_cycle[y][UBR] = UBL;
2302 corner_cycle[y][DFR] = DBR;
2303 corner_cycle[y][DFL] = DFR;
2304 corner_cycle[y][DBL] = DFL;
2305 corner_cycle[y][DBR] = DBL;
2306
2307 center_cycle[U][U_center] = U_center;
2308 center_cycle[U][D_center] = D_center;
2309 center_cycle[U][R_center] = R_center;
2310 center_cycle[U][L_center] = L_center;
2311 center_cycle[U][F_center] = F_center;
2312 center_cycle[U][B_center] = B_center;
2313
2314 center_cycle[x][U_center] = F_center;
2315 center_cycle[x][D_center] = B_center;
2316 center_cycle[x][R_center] = R_center;
2317 center_cycle[x][L_center] = L_center;
2318 center_cycle[x][F_center] = D_center;
2319 center_cycle[x][B_center] = U_center;
2320
2321 center_cycle[y][U_center] = U_center;
2322 center_cycle[y][D_center] = D_center;
2323 center_cycle[y][R_center] = B_center;
2324 center_cycle[y][L_center] = F_center;
2325 center_cycle[y][F_center] = R_center;
2326 center_cycle[y][B_center] = L_center;
2327
2328 /* Flipped pieces *************/
2329 eofb_flipped[x][UF] = 1;
2330 eofb_flipped[x][UB] = 1;
2331 eofb_flipped[x][DF] = 1;
2332 eofb_flipped[x][DB] = 1;
2333
2334 eofb_flipped[y][FR] = 1;
2335 eofb_flipped[y][FL] = 1;
2336 eofb_flipped[y][BL] = 1;
2337 eofb_flipped[y][BR] = 1;
2338
2339 eorl_flipped[x][UF] = 1;
2340 eorl_flipped[x][UL] = 1;
2341 eorl_flipped[x][UB] = 1;
2342 eorl_flipped[x][UR] = 1;
2343 eorl_flipped[x][DF] = 1;
2344 eorl_flipped[x][DL] = 1;
2345 eorl_flipped[x][DB] = 1;
2346 eorl_flipped[x][DR] = 1;
2347 eorl_flipped[x][FR] = 1;
2348 eorl_flipped[x][FL] = 1;
2349 eorl_flipped[x][BL] = 1;
2350 eorl_flipped[x][BR] = 1;
2351
2352 eorl_flipped[y][FR] = 1;
2353 eorl_flipped[y][FL] = 1;
2354 eorl_flipped[y][BL] = 1;
2355 eorl_flipped[y][BR] = 1;
2356
2357 eoud_flipped[U][UF] = 1;
2358 eoud_flipped[U][UL] = 1;
2359 eoud_flipped[U][UB] = 1;
2360 eoud_flipped[U][UR] = 1;
2361
2362 eoud_flipped[x][UF] = 1;
2363 eoud_flipped[x][UB] = 1;
2364 eoud_flipped[x][DF] = 1;
2365 eoud_flipped[x][DB] = 1;
2366
2367 eoud_flipped[y][UF] = 1;
2368 eoud_flipped[y][UL] = 1;
2369 eoud_flipped[y][UB] = 1;
2370 eoud_flipped[y][UR] = 1;
2371 eoud_flipped[y][DF] = 1;
2372 eoud_flipped[y][DL] = 1;
2373 eoud_flipped[y][DB] = 1;
2374 eoud_flipped[y][DR] = 1;
2375 eoud_flipped[y][FR] = 1;
2376 eoud_flipped[y][FL] = 1;
2377 eoud_flipped[y][BL] = 1;
2378 eoud_flipped[y][BR] = 1;
2379
2380 coud_flipped[x][UFR] = 2;
2381 coud_flipped[x][UFL] = 1;
2382 coud_flipped[x][UBR] = 1;
2383 coud_flipped[x][UBL] = 2;
2384 coud_flipped[x][DFR] = 1;
2385 coud_flipped[x][DFL] = 2;
2386 coud_flipped[x][DBR] = 2;
2387 coud_flipped[x][DBL] = 1;
2388
2389 corl_flipped[U][UFR] = 1;
2390 corl_flipped[U][UFL] = 2;
2391 corl_flipped[U][UBL] = 1;
2392 corl_flipped[U][UBR] = 2;
2393
2394 corl_flipped[y][UFR] = 1;
2395 corl_flipped[y][UFL] = 2;
2396 corl_flipped[y][UBL] = 1;
2397 corl_flipped[y][UBR] = 2;
2398 corl_flipped[y][DFR] = 2;
2399 corl_flipped[y][DFL] = 1;
2400 corl_flipped[y][DBL] = 2;
2401 corl_flipped[y][DBR] = 1;
2402
2403 cofb_flipped[U][UFR] = 2;
2404 cofb_flipped[U][UFL] = 1;
2405 cofb_flipped[U][UBL] = 2;
2406 cofb_flipped[U][UBR] = 1;
2407
2408 cofb_flipped[x][UFR] = 1;
2409 cofb_flipped[x][UFL] = 2;
2410 cofb_flipped[x][UBL] = 1;
2411 cofb_flipped[x][UBR] = 2;
2412 cofb_flipped[x][DFR] = 2;
2413 cofb_flipped[x][DFL] = 1;
2414 cofb_flipped[x][DBL] = 2;
2415 cofb_flipped[x][DBR] = 1;
2416
2417 cofb_flipped[y][UFR] = 2;
2418 cofb_flipped[y][UFL] = 1;
2419 cofb_flipped[y][UBL] = 2;
2420 cofb_flipped[y][UBR] = 1;
2421 cofb_flipped[y][DFR] = 1;
2422 cofb_flipped[y][DFL] = 2;
2423 cofb_flipped[y][DBL] = 1;
2424 cofb_flipped[y][DBR] = 2;
2425
2426 /* Equivalent moves ***********/
2427 equiv_alg[NULLMOVE] = new_alg("");
2428
2429 equiv_alg[U] = new_alg(" U ");
2430 equiv_alg[U2] = new_alg(" UU ");
2431 equiv_alg[U3] = new_alg(" UUU ");
2432 equiv_alg[D] = new_alg(" xx U xx ");
2433 equiv_alg[D2] = new_alg(" xx UU xx ");
2434 equiv_alg[D3] = new_alg(" xx UUU xx ");
2435 equiv_alg[R] = new_alg(" yx U xxxyyy ");
2436 equiv_alg[R2] = new_alg(" yx UU xxxyyy ");
2437 equiv_alg[R3] = new_alg(" yx UUU xxxyyy ");
2438 equiv_alg[L] = new_alg(" yyyx U xxxy ");
2439 equiv_alg[L2] = new_alg(" yyyx UU xxxy ");
2440 equiv_alg[L3] = new_alg(" yyyx UUU xxxy ");
2441 equiv_alg[F] = new_alg(" x U xxx ");
2442 equiv_alg[F2] = new_alg(" x UU xxx ");
2443 equiv_alg[F3] = new_alg(" x UUU xxx ");
2444 equiv_alg[B] = new_alg(" xxx U x ");
2445 equiv_alg[B2] = new_alg(" xxx UU x ");
2446 equiv_alg[B3] = new_alg(" xxx UUU x ");
2447
2448 equiv_alg[Uw] = new_alg(" xx U xx y ");
2449 equiv_alg[Uw2] = new_alg(" xx UU xx yy ");
2450 equiv_alg[Uw3] = new_alg(" xx UUU xx yyy ");
2451 equiv_alg[Dw] = new_alg(" U yyy ");
2452 equiv_alg[Dw2] = new_alg(" UU yy ");
2453 equiv_alg[Dw3] = new_alg(" UUU y ");
2454 equiv_alg[Rw] = new_alg(" yyyx U xxxy x ");
2455 equiv_alg[Rw2] = new_alg(" yyyx UU xxxy xx ");
2456 equiv_alg[Rw3] = new_alg(" yyyx UUU xxxy xxx ");
2457 equiv_alg[Lw] = new_alg(" yx U xxxyyy xxx ");
2458 equiv_alg[Lw2] = new_alg(" yx UU xxxyyy xx ");
2459 equiv_alg[Lw3] = new_alg(" yx UUU xxxyyy x ");
2460 equiv_alg[Fw] = new_alg(" xxx U x yxxxyyy ");
2461 equiv_alg[Fw2] = new_alg(" xxx UU x yxxyyy ");
2462 equiv_alg[Fw3] = new_alg(" xxx UUU x yxyyy ");
2463 equiv_alg[Bw] = new_alg(" x U xxx yxyyy ");
2464 equiv_alg[Bw2] = new_alg(" x UU xxx yxxyyy ");
2465 equiv_alg[Bw3] = new_alg(" x UUU xxx yxxxyyy ");
2466
2467 equiv_alg[M] = new_alg(" yx U xx UUU yxyyy ");
2468 equiv_alg[M2] = new_alg(" yx UU xx UU xxxy ");
2469 equiv_alg[M3] = new_alg(" yx UUU xx U yxxxy ");
2470 equiv_alg[S] = new_alg(" x UUU xx U yyyx ");
2471 equiv_alg[S2] = new_alg(" x UU xx UU yyx ");
2472 equiv_alg[S3] = new_alg(" x U xx UUU yx ");
2473 equiv_alg[E] = new_alg(" U xx UUU xxyyy ");
2474 equiv_alg[E2] = new_alg(" UU xx UU xxyy ");
2475 equiv_alg[E3] = new_alg(" UUU xx U xxy ");
2476
2477 equiv_alg[x] = new_alg(" x ");
2478 equiv_alg[x2] = new_alg(" xx ");
2479 equiv_alg[x3] = new_alg(" xxx ");
2480 equiv_alg[y] = new_alg(" y ");
2481 equiv_alg[y2] = new_alg(" yy ");
2482 equiv_alg[y3] = new_alg(" yyy ");
2483 equiv_alg[z] = new_alg(" yyy x y ");
2484 equiv_alg[z2] = new_alg(" yy xx ");
2485 equiv_alg[z3] = new_alg(" y x yyy ");
2486}
2487
2488static void
2489init_strings()
2490{
2491 strcpy(move_string [NULLMOVE], "-" );
2492 strcpy(move_string [U], "U" );
2493 strcpy(move_string [U2], "U2" );
2494 strcpy(move_string [U3], "U\'" );
2495 strcpy(move_string [D], "D" );
2496 strcpy(move_string [D2], "D2" );
2497 strcpy(move_string [D3], "D\'" );
2498 strcpy(move_string [R], "R" );
2499 strcpy(move_string [R2], "R2" );
2500 strcpy(move_string [R3], "R\'" );
2501 strcpy(move_string [L], "L" );
2502 strcpy(move_string [L2], "L2" );
2503 strcpy(move_string [L3], "L\'" );
2504 strcpy(move_string [F], "F" );
2505 strcpy(move_string [F2], "F2" );
2506 strcpy(move_string [F3], "F\'" );
2507 strcpy(move_string [B], "B" );
2508 strcpy(move_string [B2], "B2" );
2509 strcpy(move_string [B3], "B\'" );
2510 strcpy(move_string [Uw], "Uw" );
2511 strcpy(move_string [Uw2], "Uw2" );
2512 strcpy(move_string [Uw3], "Uw\'" );
2513 strcpy(move_string [Dw], "Dw" );
2514 strcpy(move_string [Dw2], "Dw2" );
2515 strcpy(move_string [Dw3], "Dw\'" );
2516 strcpy(move_string [Rw], "Rw" );
2517 strcpy(move_string [Rw2], "Rw2" );
2518 strcpy(move_string [Rw3], "Rw\'" );
2519 strcpy(move_string [Lw], "Lw" );
2520 strcpy(move_string [Lw2], "Lw2" );
2521 strcpy(move_string [Lw3], "Lw\'" );
2522 strcpy(move_string [Fw], "Fw" );
2523 strcpy(move_string [Fw2], "Fw2" );
2524 strcpy(move_string [Fw3], "Fw\'" );
2525 strcpy(move_string [Bw], "Bw" );
2526 strcpy(move_string [Bw2], "Bw2" );
2527 strcpy(move_string [Bw3], "Bw\'" );
2528 strcpy(move_string [M], "M" );
2529 strcpy(move_string [M2], "M2" );
2530 strcpy(move_string [M3], "M\'" );
2531 strcpy(move_string [S], "S" );
2532 strcpy(move_string [S2], "S2" );
2533 strcpy(move_string [S3], "S\'" );
2534 strcpy(move_string [E], "E" );
2535 strcpy(move_string [E2], "E2" );
2536 strcpy(move_string [E3], "E\'" );
2537 strcpy(move_string [x], "x" );
2538 strcpy(move_string [x2], "x2" );
2539 strcpy(move_string [x3], "x\'" );
2540 strcpy(move_string [y], "y" );
2541 strcpy(move_string [y2], "y2" );
2542 strcpy(move_string [y3], "y\'" );
2543 strcpy(move_string [z], "z" );
2544 strcpy(move_string [z2], "z2" );
2545 strcpy(move_string [z3], "z\'" );
2546
2547 strcpy(edge_string [UF], "UF" );
2548 strcpy(edge_string [UL], "UL" );
2549 strcpy(edge_string [UB], "UB" );
2550 strcpy(edge_string [UR], "UR" );
2551 strcpy(edge_string [DF], "DF" );
2552 strcpy(edge_string [DL], "DL" );
2553 strcpy(edge_string [DB], "DB" );
2554 strcpy(edge_string [DR], "DR" );
2555 strcpy(edge_string [FR], "FR" );
2556 strcpy(edge_string [FL], "FL" );
2557 strcpy(edge_string [BL], "BL" );
2558 strcpy(edge_string [BR], "BR" );
2559
2560 strcpy(corner_string [UFR], "UFR" );
2561 strcpy(corner_string [UFL], "UFL" );
2562 strcpy(corner_string [UBL], "UBL" );
2563 strcpy(corner_string [UBR], "UBR" );
2564 strcpy(corner_string [DFR], "DFR" );
2565 strcpy(corner_string [DFL], "DFL" );
2566 strcpy(corner_string [DBL], "DBL" );
2567 strcpy(corner_string [DBR], "DBR" );
2568
2569 strcpy(center_string [U_center], "U" );
2570 strcpy(center_string [D_center], "D" );
2571 strcpy(center_string [R_center], "R" );
2572 strcpy(center_string [L_center], "L" );
2573 strcpy(center_string [F_center], "F" );
2574 strcpy(center_string [B_center], "B" );
2575}
2576
2577static void
2578init_symdata()
2579{
2580 int i;
2581
2582 for (i = 0; i < n_all_symdata; i++)
2583 gensym(all_sd[i]);
2584}
2585
2586static void
2587init_trans() {
2588 Cube aux, cube, mirr, c[3];
2589 CubeArray epcp;
2590 int i, eparr[12], eoarr[12], cparr[8], coarr[8];
2591 unsigned int ui;
2592 Move mi, move;
2593 Trans m;
2594
2595 /* Compute sources */
2596 for (i = 0; i < NTRANS; i++) {
2597 cube = apply_alg(rotation_algs[i % NROTATIONS], (Cube){0});
2598
2599 epose_source[i] = edge_slice(what_edge_at(cube, FR));
2600 eposs_source[i] = edge_slice(what_edge_at(cube, UR));
2601 eposm_source[i] = edge_slice(what_edge_at(cube, UF));
2602 eofb_source[i] = what_center_at(cube, F_center)/2;
2603 eorl_source[i] = what_center_at(cube, R_center)/2;
2604 eoud_source[i] = what_center_at(cube, U_center)/2;
2605 coud_source[i] = what_center_at(cube, U_center)/2;
2606 cofb_source[i] = what_center_at(cube, F_center)/2;
2607 corl_source[i] = what_center_at(cube, R_center)/2;
2608 }
2609
2610 if (read_ttables_file())
2611 return;
2612
2613 fprintf(stderr, "Cannot load %s, generating it\n", "ttables");
2614
2615 /* Initialize tables */
2616 for (m = 0; m < NTRANS; m++) {
2617 epcp = (CubeArray){ .ep = eparr, .cp = cparr };
2618 cube = apply_alg(rotation_algs[m % NROTATIONS], (Cube){0});
2619 cube_to_arrays(cube, &epcp, pf_epcp);
2620 if (m >= NROTATIONS) {
2621 apply_permutation(ep_mirror, eparr, 12);
2622 apply_permutation(cp_mirror, cparr, 8);
2623 }
2624
2625 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
2626 c[0] = admissible_ep((Cube){ .epose = ui }, pf_e);
2627 c[1] = admissible_ep((Cube){ .eposs = ui }, pf_s);
2628 c[2] = admissible_ep((Cube){ .eposm = ui }, pf_m);
2629
2630 cube = rotate_via_compose(m,c[epose_source[m]],pf_ep);
2631 epose_ttable[m][ui] = cube.epose;
2632
2633 cube = rotate_via_compose(m,c[eposs_source[m]],pf_ep);
2634 eposs_ttable[m][ui] = cube.eposs;
2635
2636 cube = rotate_via_compose(m,c[eposm_source[m]],pf_ep);
2637 eposm_ttable[m][ui] = cube.eposm;
2638 }
2639 for (ui = 0; ui < POW2TO11; ui++ ) {
2640 int_to_sum_zero_array(ui, 2, 12, eoarr);
2641 apply_permutation(eparr, eoarr, 12);
2642 eo_ttable[m][ui] = digit_array_to_int(eoarr, 11, 2);
2643 }
2644 for (ui = 0; ui < POW3TO7; ui++) {
2645 int_to_sum_zero_array(ui, 3, 8, coarr);
2646 apply_permutation(cparr, coarr, 8);
2647 co_ttable[m][ui] = digit_array_to_int(coarr, 7, 3);
2648 if (m >= NROTATIONS)
2649 co_ttable[m][ui] =
2650 invert_digits(co_ttable[m][ui], 3, 7);
2651 }
2652 for (ui = 0; ui < FACTORIAL8; ui++) {
2653 cube = (Cube){ .cp = ui };
2654 cube = rotate_via_compose(m, cube, pf_cp);
2655 cp_ttable[m][ui] = cube.cp;
2656 }
2657 for (ui = 0; ui < FACTORIAL6; ui++) {
2658 cube = (Cube){ .cpos = ui };
2659 cube = rotate_via_compose(m, cube, pf_cpos);
2660 cpos_ttable[m][ui] = cube.cpos;
2661 }
2662 for (mi = 0; mi < NMOVES; mi++) {
2663 aux = apply_trans(m, apply_move(mi, (Cube){0}));
2664 for (move = 0; move < NMOVES; move++) {
2665 cube = apply_move(inverse_move_aux[move], aux);
2666 mirr = apply_trans(uf_mirror, cube);
2667 if (is_solved(cube, false) ||
2668 is_solved(mirr, false))
2669 moves_ttable[m][mi] = move;
2670 }
2671 }
2672 }
2673
2674 if (!write_ttables_file())
2675 fprintf(stderr, "Error writing ttables\n");
2676}
2677
2678static void
2679init_trans_aux()
2680{
2681 ep_mirror[UF] = UF;
2682 ep_mirror[UL] = UR;
2683 ep_mirror[UB] = UB;
2684 ep_mirror[UR] = UL;
2685 ep_mirror[DF] = DF;
2686 ep_mirror[DL] = DR;
2687 ep_mirror[DB] = DB;
2688 ep_mirror[DR] = DL;
2689 ep_mirror[FR] = FL;
2690 ep_mirror[FL] = FR;
2691 ep_mirror[BR] = BL;
2692 ep_mirror[BL] = BR;
2693
2694 cp_mirror[UFR] = UFL;
2695 cp_mirror[UFL] = UFR;
2696 cp_mirror[UBL] = UBR;
2697 cp_mirror[UBR] = UBL;
2698 cp_mirror[DFR] = DFL;
2699 cp_mirror[DFL] = DFR;
2700 cp_mirror[DBL] = DBR;
2701 cp_mirror[DBR] = DBL;
2702
2703 cpos_mirror[U_center] = U_center;
2704 cpos_mirror[D_center] = D_center;
2705 cpos_mirror[R_center] = L_center;
2706 cpos_mirror[L_center] = R_center;
2707 cpos_mirror[F_center] = F_center;
2708 cpos_mirror[B_center] = B_center;
2709
2710 /* Is there a more elegant way? */
2711 rotation_algs[uf] = new_alg("");
2712 rotation_algs[ur] = new_alg("y");
2713 rotation_algs[ub] = new_alg("y2");
2714 rotation_algs[ul] = new_alg("y3");
2715
2716 rotation_algs[df] = new_alg("z2");
2717 rotation_algs[dr] = new_alg("y z2");
2718 rotation_algs[db] = new_alg("x2");
2719 rotation_algs[dl] = new_alg("y3 z2");
2720
2721 rotation_algs[rf] = new_alg("z3");
2722 rotation_algs[rd] = new_alg("z3 y");
2723 rotation_algs[rb] = new_alg("z3 y2");
2724 rotation_algs[ru] = new_alg("z3 y3");
2725
2726 rotation_algs[lf] = new_alg("z");
2727 rotation_algs[ld] = new_alg("z y3");
2728 rotation_algs[lb] = new_alg("z y2");
2729 rotation_algs[lu] = new_alg("z y");
2730
2731 rotation_algs[fu] = new_alg("x y2");
2732 rotation_algs[fr] = new_alg("x y");
2733 rotation_algs[fd] = new_alg("x");
2734 rotation_algs[fl] = new_alg("x y3");
2735
2736 rotation_algs[bu] = new_alg("x3");
2737 rotation_algs[br] = new_alg("x3 y");
2738 rotation_algs[bd] = new_alg("x3 y2");
2739 rotation_algs[bl] = new_alg("x3 y3");
2740}
2741
2742
2743/* Public functions implementation *******************************************/
2744
2745Cube
2746apply_alg(Alg *alg, Cube cube)
2747{
2748 return apply_alg_generic(alg, cube, pf_all, true);
2749}
2750
2751Cube
2752apply_move(Move m, Cube cube)
2753{
2754 return (Cube) {
2755 .epose = epose_mtable[m][cube.epose],
2756 .eposs = eposs_mtable[m][cube.eposs],
2757 .eposm = eposm_mtable[m][cube.eposm],
2758 .eofb = eofb_mtable[m][cube.eofb],
2759 .eorl = eorl_mtable[m][cube.eorl],
2760 .eoud = eoud_mtable[m][cube.eoud],
2761 .coud = coud_mtable[m][cube.coud],
2762 .cofb = cofb_mtable[m][cube.cofb],
2763 .corl = corl_mtable[m][cube.corl],
2764 .cp = cp_mtable[m][cube.cp],
2765 .cpos = cpos_mtable[m][cube.cpos]
2766 };
2767}
2768
2769
2770Cube
2771apply_trans(Trans t, Cube cube)
2772{
2773 int aux_epos[3] = { cube.epose, cube.eposs, cube.eposm };
2774 int aux_eo[3] = { cube.eoud, cube.eorl, cube.eofb };
2775 int aux_co[3] = { cube.coud, cube.corl, cube.cofb };
2776
2777 return (Cube) {
2778 .epose = epose_ttable[t][aux_epos[epose_source[t]]],
2779 .eposs = eposs_ttable[t][aux_epos[eposs_source[t]]],
2780 .eposm = eposm_ttable[t][aux_epos[eposm_source[t]]],
2781 .eofb = eo_ttable[t][aux_eo[eofb_source[t]]],
2782 .eorl = eo_ttable[t][aux_eo[eorl_source[t]]],
2783 .eoud = eo_ttable[t][aux_eo[eoud_source[t]]],
2784 .coud = co_ttable[t][aux_co[coud_source[t]]],
2785 .corl = co_ttable[t][aux_co[corl_source[t]]],
2786 .cofb = co_ttable[t][aux_co[cofb_source[t]]],
2787 .cp = cp_ttable[t][cube.cp],
2788 .cpos = cpos_ttable[t][cube.cpos]
2789 };
2790}
2791
2792Move
2793base_move(Move m)
2794{
2795 if (m == NULLMOVE)
2796 return NULLMOVE;
2797 else
2798 return m - (m-1)%3;
2799}
2800
2801Cube
2802compose(Cube c2, Cube c1)
2803{
2804 return compose_filtered(c2, c1, pf_all);
2805}
2806
2807/*TODO maybe move the next two */
2808uint64_t
2809cphtr(Cube cube)
2810{
2811 return cphtr_right_cosets[cube.cp];
2812}
2813
2814Cube
2815anti_cphtr(uint64_t ind)
2816{
2817 return (Cube) { .cp = cphtr_right_rep[ind] };
2818}
2819
2820uint64_t
2821epos_dependent(Cube c)
2822{
2823 return epos_dependent_aux[c.eposs/FACTORIAL4][c.epose/FACTORIAL4];
2824}
2825
2826bool
2827equal(Cube c1, Cube c2)
2828{
2829 return c1.eofb == c2.eofb &&
2830 c1.epose == c2.epose &&
2831 c1.eposs == c2.eposs &&
2832 c1.eposm == c2.eposm &&
2833 c1.coud == c2.coud &&
2834 c1.cp == c2.cp &&
2835 c1.cpos == c2.cpos;
2836}
2837
2838void
2839genptable(PruneData *pd)
2840{
2841 Move ms[NMOVES];
2842 int d;
2843 uint64_t j, oldn = 0;
2844
2845 if (pd->generated)
2846 return;
2847
2848 /* TODO: check if memory is enough, otherwise maybe crash gracefully? */
2849 pd->ptable = malloc(ptablesize(pd) * sizeof(uint8_t));
2850
2851 if (read_ptable_file(pd)) {
2852 pd->generated = true;
2853 return;
2854 }
2855
2856 fprintf(stderr, "Cannot load %s, generating it\n", pd->filename);
2857
2858 moveset_to_list(pd->moveset, NULL, ms);
2859
2860 /* We use 4 bits per value, so any distance >= 15 is set to 15 */
2861 for (j = 0; j < pd->coord->max; j++)
2862 ptable_update(pd, pd->coord->cube(j), 15);
2863
2864 /*TODO: change, set to 0 for every solved state (might be more than 1)*/
2865 ptable_update(pd, (Cube){0}, 0);
2866 pd->n = 1;
2867
2868 for (d = 0; d < 15 && pd->n < pd->coord->max; d++) {
2869 genptable_bfs(pd, d, ms);
2870 fprintf(stderr, "Depth %d done, generated %lu\t(%lu/%lu)\n",
2871 d, pd->n - oldn, pd->n, pd->coord->max);
2872 oldn = pd->n;
2873 }
2874
2875 if (!write_ptable_file(pd))
2876 fprintf(stderr, "Error writing ptable file\n");
2877
2878 pd->generated = true;
2879}
2880
2881Cube
2882inverse_cube(Cube cube)
2883{
2884 CubeArray *arr = new_cubearray(cube, pf_all);
2885 CubeArray *inv = new_cubearray((Cube){0}, pf_all);
2886 Cube ret;
2887 int i;
2888
2889 for (i = 0; i < 12; i++) {
2890 inv->ep[arr->ep[i]] = i;
2891 inv->eofb[arr->ep[i]] = arr->eofb[i];
2892 inv->eorl[arr->ep[i]] = arr->eorl[i];
2893 inv->eoud[arr->ep[i]] = arr->eoud[i];
2894 }
2895
2896 for (i = 0; i < 8; i++) {
2897 inv->cp[arr->cp[i]] = i;
2898 inv->coud[arr->cp[i]] = (3 - arr->coud[i]) % 3;
2899 inv->corl[arr->cp[i]] = (3 - arr->corl[i]) % 3;
2900 inv->cofb[arr->cp[i]] = (3 - arr->cofb[i]) % 3;
2901 }
2902
2903 for (int i = 0; i < 6; i++)
2904 inv->cpos[arr->cpos[i]] = i;
2905
2906 ret = arrays_to_cube(inv, pf_all);
2907 free_cubearray(arr, pf_all);
2908 free_cubearray(inv, pf_all);
2909
2910 return ret;
2911}
2912
2913Move
2914inverse_move(Move m)
2915{
2916 return inverse_move_aux[m];
2917}
2918
2919Trans
2920inverse_trans(Trans t)
2921{
2922 return inverse_trans_aux[t];
2923}
2924
2925bool
2926is_admissible(Cube cube)
2927{
2928 /* TODO: this should check consistency of different orientations */
2929 /* TODO: check that centers are opposite and admissible */
2930
2931 CubeArray *a = new_cubearray(cube, pf_all);
2932 int parity;
2933 bool perm;
2934
2935 perm = is_perm(a->ep, 12) &&
2936 is_perm(a->cp, 8) &&
2937 is_perm(a->cpos, 6);
2938 parity = perm_sign(a->ep, 12) +
2939 perm_sign(a->cp, 8) +
2940 perm_sign(a->cpos, 6);
2941
2942 return perm && parity % 2 == 0;
2943}
2944
2945bool
2946is_solved(Cube cube, bool reorient)
2947{
2948 int i;
2949
2950 if (reorient) {
2951 for (i = 0; i < NROTATIONS; i++)
2952 if (is_solved(apply_alg(rotation_algs[i], cube),false))
2953 return true;
2954 return false;
2955 } else {
2956 return equal(cube, (Cube){0});
2957 }
2958}
2959
2960bool
2961is_solved_block(Cube cube, Block block)
2962{
2963 int i;
2964
2965 for (i = 0; i < 12; i++)
2966 if (block.edge[i] && !is_solved_edge(cube, i))
2967 return false;
2968 for (i = 0; i < 8; i++)
2969 if (block.corner[i] && !is_solved_corner(cube, i))
2970 return false;
2971 for (i = 0; i < 6; i++)
2972 if (block.center[i] && !is_solved_center(cube, i))
2973 return false;
2974
2975 return true;
2976}
2977
2978bool
2979is_solved_center(Cube cube, Center c)
2980{
2981 return what_center_at(cube, c) == c;
2982}
2983
2984bool
2985is_solved_corner(Cube cube, Corner c)
2986{
2987 return what_corner_at(cube, c) == c &&
2988 what_orientation_corner(cube.coud, c);
2989}
2990
2991bool
2992is_solved_edge(Cube cube, Edge e)
2993{
2994 return what_edge_at(cube, e) == e &&
2995 what_orientation_edge(cube.eofb, e);
2996}
2997
2998int
2999piece_orientation(Cube cube, int piece, char *orientation)
3000{
3001 int arr[12], n, b, x;
3002
3003 if (!strcmp(orientation, "eofb")) {
3004 x = cube.eofb;
3005 n = 12;
3006 b = 2;
3007 } else if (!strcmp(orientation, "eorl")) {
3008 x = cube.eorl;
3009 n = 12;
3010 b = 2;
3011 } else if (!strcmp(orientation, "eoud")) {
3012 x = cube.eoud;
3013 n = 12;
3014 b = 2;
3015 } else if (!strcmp(orientation, "coud")) {
3016 x = cube.coud;
3017 n = 8;
3018 b = 3;
3019 } else if (!strcmp(orientation, "corl")) {
3020 x = cube.corl;
3021 n = 8;
3022 b = 3;
3023 } else if (!strcmp(orientation, "cofb")) {
3024 x = cube.cofb;
3025 n = 8;
3026 b = 3;
3027 } else {
3028 return -1;
3029 }
3030
3031 int_to_sum_zero_array(x, b, n, arr);
3032 if (piece < n)
3033 return arr[piece];
3034
3035 return -1;
3036}
3037
3038void
3039print_cube(Cube cube)
3040{
3041/*
3042 CubeArray *arr = new_cubearray(cube, pf_all);
3043
3044 for (int i = 0; i < 12; i++)
3045 printf(" %s ", edge_string[arr->ep[i]]);
3046 printf("\n");
3047
3048 for (int i = 0; i < 12; i++)
3049 printf(" %c ", arr->eofb[i] + '0');
3050 printf("\n");
3051
3052 for (int i = 0; i < 8; i++)
3053 printf("%s ", corner_string[arr->cp[i]]);
3054 printf("\n");
3055
3056 for (int i = 0; i < 8; i++)
3057 printf(" %c ", arr->coud[i] + '0');
3058 printf("\n");
3059
3060 for (int i = 0; i < 6; i++)
3061 printf(" %s ", center_string[arr->cpos[i]]);
3062 printf("\n");
3063
3064 free_cubearray(arr, pf_all);
3065*/
3066
3067 for (int i = 0; i < 12; i++)
3068 printf(" %s ", edge_string[what_edge_at(cube, i)]);
3069 printf("\n");
3070
3071 for (int i = 0; i < 12; i++)
3072 printf(" %d ", what_orientation_edge(cube.eofb, i));
3073 printf("\n");
3074
3075 for (int i = 0; i < 8; i++)
3076 printf("%s ", corner_string[what_corner_at(cube, i)]);
3077 printf("\n");
3078
3079 for (int i = 0; i < 8; i++)
3080 printf(" %d ", what_orientation_corner(cube.coud, i));
3081 printf("\n");
3082
3083 for (int i = 0; i < 6; i++)
3084 printf(" %s ", center_string[what_center_at(cube, i)]);
3085 printf("\n");
3086
3087}
3088
3089Cube
3090random_cube()
3091{
3092 CubeArray *arr = new_cubearray((Cube){0}, pf_4val);
3093 Cube ret;
3094 int ep, cp, eo, co;
3095
3096 ep = rand() % FACTORIAL12;
3097 cp = rand() % FACTORIAL8;
3098 eo = rand() % POW2TO11;
3099 co = rand() % POW3TO7;
3100
3101 index_to_perm(ep, 12, arr->ep);
3102 index_to_perm(cp, 8, arr->cp);
3103 int_to_sum_zero_array(eo, 2, 12, arr->eofb);
3104 int_to_sum_zero_array(co, 3, 8, arr->coud);
3105
3106 if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8))
3107 swap(&(arr->ep[0]), &(arr->ep[1]));
3108
3109 ret = arrays_to_cube(arr, pf_4val);
3110 free_cubearray(arr, pf_4val);
3111
3112 return ret;
3113}
3114
3115/* TODO: clean pre_trans or put it back */
3116AlgList *
3117solve(Cube cube, Step step, SolveOptions *opts)
3118{
3119 /*AlgListNode *node;*/
3120 AlgList *sols = new_alglist();
3121 /*Cube c = apply_trans(opts->pre_trans, cube);*/
3122 DfsData dd = {
3123 .m = 0,
3124 .niss = false,
3125 .lb = -1,
3126 .last1 = NULLMOVE,
3127 .last2 = NULLMOVE,
3128 .sols = sols,
3129 .current_alg = new_alg("")
3130 };
3131
3132 if (step.ready != NULL && !step.ready(cube)) {
3133 fprintf(stderr, "Cube not ready for solving step\n");
3134 return sols;
3135 }
3136
3137 moveset_to_list(step.moveset, step.estimate, dd.sorted_moves);
3138 movelist_to_position(dd.sorted_moves, dd.move_position);
3139
3140 for (dd.d = opts->min_moves;
3141 dd.d <= opts->max_moves && !(sols->len && opts->optimal_only);
3142 dd.d++) {
3143 if (opts->feedback)
3144 fprintf(stderr,
3145 "Found %d solutions, searching depth %d...\n",
3146 sols->len, dd.d);
3147 dfs(cube, step, opts, &dd);
3148 }
3149
3150/*
3151 for (node = sols->first; node != NULL; node = node->next)
3152 transform_alg(inverse_trans(opts->pre_trans), node->alg);
3153*/
3154
3155 free_alg(dd.current_alg);
3156 return sols;
3157}
3158
3159Alg *
3160inverse_alg(Alg *alg)
3161{
3162 Alg *ret = new_alg("");
3163 int i;
3164
3165 for (i = alg->len-1; i >= 0; i--)
3166 append_move(ret, inverse_move(alg->move[i]), alg->inv[i]);
3167
3168 return ret;
3169}
3170
3171Alg *
3172new_alg(char *str)
3173{
3174 Alg *alg = malloc(sizeof(Alg));
3175 int i;
3176 bool niss = false;
3177 Move j, m;
3178
3179 alg->move = malloc(30 * sizeof(Move));
3180 alg->inv = malloc(30 * sizeof(bool));
3181 alg->allocated = 30;
3182 alg->len = 0;
3183
3184 for (i = 0; str[i]; i++) {
3185 if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n')
3186 continue;
3187
3188 if (str[i] == '(' && niss) {
3189 fprintf(stderr, "Error reading moves: nested ( )\n");
3190 return alg;
3191 }
3192
3193 if (str[i] == ')' && !niss) {
3194 fprintf(stderr, "Error reading moves: unmatched )\n");
3195 return alg;
3196 }
3197
3198 if (str[i] == '(' || str[i] == ')') {
3199 niss = !niss;
3200 continue;
3201 }
3202
3203 for (j = 0; j < NMOVES; j++) {
3204 if (str[i] == move_string[j][0]) {
3205 m = j;
3206 if (m <= B && str[i+1]=='w') {
3207 m += Uw - U;
3208 i++;
3209 }
3210 if (str[i+1]=='2') {
3211 m += 1;
3212 i++;
3213 } else if (str[i+1]=='\'' || str[i+1]=='3') {
3214 m += 2;
3215 i++;
3216 }
3217 append_move(alg, m, niss);
3218 break;
3219 }
3220 }
3221 }
3222
3223 return alg;
3224}
3225
3226Alg *
3227on_inverse(Alg *alg)
3228{
3229 Alg *ret = new_alg("");
3230 int i;
3231
3232 for (i = 0; i < alg->len; i++)
3233 append_move(ret, alg->move[i], !alg->inv[i]);
3234
3235 return ret;
3236}
3237
3238void
3239print_alg(Alg *alg, bool l)
3240{
3241 /* TODO: make it possible to print to stdout or to string */
3242 /* Maybe just return a string */
3243 char fill[4];
3244 int i;
3245 bool niss = false;
3246
3247 for (i = 0; i < alg->len; i++) {
3248 if (!niss && alg->inv[i])
3249 strcpy(fill, i == 0 ? "(" : " (");
3250 if (niss && !alg->inv[i])
3251 strcpy(fill, ") ");
3252 if (niss == alg->inv[i])
3253 strcpy(fill, i == 0 ? "" : " ");
3254
3255 printf("%s%s", fill, move_string[alg->move[i]]);
3256 niss = alg->inv[i];
3257 }
3258
3259 if (niss)
3260 printf(")");
3261 if (l)
3262 printf(" (%d)", alg->len);
3263
3264 printf("\n");
3265}
3266
3267void
3268print_alglist(AlgList *al, bool l)
3269{
3270 AlgListNode *i;
3271
3272 for (i = al->first; i != NULL; i = i->next)
3273 print_alg(i->alg, l);
3274}
3275
3276void
3277print_ptable(PruneData *pd)
3278{
3279 uint64_t i, a[16];
3280
3281 for (i = 0; i < 16; i++)
3282 a[i] = 0;
3283
3284 if (!pd->generated)
3285 genptable(pd);
3286
3287 for (i = 0; i < pd->coord->max; i++)
3288 a[ptableval(pd, pd->coord->cube(i))]++;
3289
3290 fprintf(stderr, "Values for table %s\n", pd->filename);
3291 for (i = 0; i < 16; i++)
3292 printf("%2lu\t%10lu\n", i, a[i]);
3293}
3294
3295uint64_t
3296ptablesize(PruneData *pd)
3297{
3298 return (pd->coord->max + 1) / 2;
3299}
3300
3301int
3302ptableval(PruneData *pd, Cube cube)
3303{
3304 return ptableval_index(pd, pd->coord->index(cube));
3305}
3306
3307Alg *
3308rotation_alg(Trans i)
3309{
3310 return rotation_algs[i % NROTATIONS];
3311}
3312
3313void
3314transform_alg(Trans t, Alg *alg)
3315{
3316 int i;
3317
3318 for (i = 0; i < alg->len; i++)
3319 alg->move[i] = moves_ttable[t][alg->move[i]];
3320}
3321
3322Center
3323what_center_at(Cube cube, Center c)
3324{
3325 return what_center_at_aux[cube.cpos][c];
3326}
3327
3328Corner
3329what_corner_at(Cube cube, Corner c)
3330{
3331 return what_corner_at_aux[cube.cp][c];
3332}
3333
3334Edge
3335what_edge_at(Cube cube, Edge e)
3336{
3337 Edge ret;
3338 CubeArray *arr = new_cubearray(cube, pf_ep);
3339
3340 ret = arr->ep[e];
3341
3342 free_cubearray(arr, pf_ep);
3343 return ret;
3344}
3345
3346int
3347what_orientation_corner(int co, Corner c)
3348{
3349 if (c < 7)
3350 return (co / powint(3, c)) % 3;
3351 else
3352 return what_orientation_last_corner_aux[co];
3353}
3354
3355int
3356what_orientation_edge(int eo, Edge e)
3357{
3358 if (e < 11)
3359 return (eo & (1 << e)) ? 1 : 0;
3360 else
3361 return what_orientation_last_edge_aux[eo];
3362}
3363
3364Center
3365where_is_center(Cube cube, Center c)
3366{
3367 return where_is_center_aux[cube.cpos][c];
3368}
3369
3370Corner
3371where_is_corner(Cube cube, Corner c)
3372{
3373 return where_is_corner_aux[cube.cp][c];
3374}
3375
3376
3377void
3378init()
3379{
3380 /* Order is important! */
3381 init_environment();
3382 init_strings();
3383 init_moves_aux();
3384 init_moves();
3385 init_auxtables();
3386 init_cphtr_cosets();
3387 init_trans_aux();
3388 init_trans();
3389 init_symdata();
3390}
3391
diff --git a/old/2021-07-15-almostbeforerefactor/cube.h b/old/2021-07-15-almostbeforerefactor/cube.h
new file mode 100644
index 0000000..c400d14
--- /dev/null
+++ b/old/2021-07-15-almostbeforerefactor/cube.h
@@ -0,0 +1,79 @@
1#ifndef CUBE_H
2#define CUBE_H
3
4#include <stdio.h>
5#include <stdbool.h>
6#include <stdint.h>
7#include <stdlib.h>
8#include <string.h>
9#include <time.h>
10#include <unistd.h>
11#include <sys/stat.h>
12
13#include "macros.h"
14#include "cubetypes.h"
15
16extern Coordinate coord_eofb;
17extern Coordinate coord_eofbepos;
18extern Coordinate coord_coud;
19extern Coordinate coord_corners;
20extern Coordinate coord_cornershtr;
21extern Coordinate coord_drud;
22extern Coordinate coord_coud_sym16;
23extern Coordinate coord_eofbepos_sym16;
24extern Coordinate coord_drud_sym16;
25extern Coordinate coord_khuge;
26
27extern Trans trans_group_udfix[16];
28extern Trans trans_group_trivial[1];
29
30Cube apply_alg(Alg *alg, Cube cube);
31Cube apply_move(Move m, Cube cube);
32Cube apply_trans(Trans t, Cube cube);
33bool block_solved(Cube cube, Block);
34Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */
35uint64_t cphtr(Cube cube); /* TODO: rename (something with cosets) */
36Cube anti_cphtr(uint64_t ind); /*TODO also this */
37uint64_t epos_dependent(Cube cube); /* TODO: rename and turn into an indexer */
38bool equal(Cube c1, Cube c2);
39Cube inverse_cube(Cube cube);
40Move inverse_move(Move m);
41Trans inverse_trans(Trans t);
42bool is_admissible(Cube cube);
43bool is_solved(Cube cube, bool reorient);
44bool is_solved_center(Cube cube, Center c);
45bool is_solved_corner(Cube cube, Corner c);
46bool is_solved_edge(Cube cube, Edge e);
47void print_cube(Cube cube);
48Cube random_cube();
49AlgList * solve(Cube cube, Step step, SolveOptions *opts);
50Center what_center_at(Cube cube, Center c);
51Corner what_corner_at(Cube cube, Corner c);
52Edge what_edge_at(Cube cube, Edge e);
53int what_orientation_corner(int co, Corner c);
54int what_orientation_edge(int eo, Edge e);
55Center where_is_center(Cube cube, Center c);
56Corner where_is_corner(Cube cube, Corner c);
57Edge where_is_edge(Cube cube, Edge e);
58
59bool check_centers(Cube cube);
60bool check_corners(Cube cube);
61bool check_cornershtr(Cube cube);
62bool check_coud(Cube cube);
63bool check_drud(Cube cube);
64bool check_eofb(Cube cube);
65bool check_eofbepos(Cube cube);
66bool check_epose(Cube cube);
67bool check_ep(Cube cube);
68bool check_khuge(Cube cube);
69bool check_nothing(Cube cube);
70
71void genptable(PruneData *pd);
72void print_ptable(PruneData *pd);
73uint64_t ptablesize(PruneData *pd);
74int ptableval(PruneData *pd, Cube cube);
75
76void init();
77
78#endif
79
diff --git a/old/2021-07-15-almostbeforerefactor/cubetypes.h b/old/2021-07-15-almostbeforerefactor/cubetypes.h
new file mode 100644
index 0000000..d51314d
--- /dev/null
+++ b/old/2021-07-15-almostbeforerefactor/cubetypes.h
@@ -0,0 +1,252 @@
1#ifndef CUBETYPES_H
2#define CUBETYPES_H
3
4/* Typedefs ******************************************************************/
5
6typedef enum center Center;
7typedef enum corner Corner;
8typedef enum edge Edge;
9typedef enum move Move;
10typedef enum trans Trans;
11
12typedef struct alg Alg;
13typedef struct alglist AlgList;
14typedef struct alglistnode AlgListNode;
15typedef struct block Block;
16typedef struct coordinate Coordinate;
17typedef struct cube Cube;
18typedef struct cubearray CubeArray;
19typedef struct cubetarget CubeTarget;
20typedef struct dfsdata DfsData;
21typedef struct piecefilter PieceFilter;
22typedef struct prunedata PruneData;
23typedef struct solveoptions SolveOptions;
24typedef struct step Step;
25typedef struct symdata SymData;
26
27typedef Cube (*AntiIndexer) (uint64_t);
28typedef bool (*Checker) (Cube);
29typedef int (*Estimator) (CubeTarget);
30typedef uint64_t (*Indexer) (Cube);
31typedef bool (*Moveset) (Move);
32
33
34/* Enums *********************************************************************/
35
36enum
37center
38{
39 U_center, D_center,
40 R_center, L_center,
41 F_center, B_center
42};
43
44enum
45corner
46{
47 UFR, UFL, UBL, UBR,
48 DFR, DFL, DBL, DBR
49};
50
51enum
52edge
53{
54 UF, UL, UB, UR,
55 DF, DL, DB, DR,
56 FR, FL, BL, BR
57};
58
59enum
60move
61{
62 NULLMOVE,
63 U, U2, U3, D, D2, D3,
64 R, R2, R3, L, L2, L3,
65 F, F2, F3, B, B2, B3,
66 Uw, Uw2, Uw3, Dw, Dw2, Dw3,
67 Rw, Rw2, Rw3, Lw, Lw2, Lw3,
68 Fw, Fw2, Fw3, Bw, Bw2, Bw3,
69 M, M2, M3,
70 S, S2, S3,
71 E, E2, E3,
72 x, x2, x3,
73 y, y2, y3,
74 z, z2, z3,
75};
76
77enum
78trans
79{
80 uf, ur, ub, ul,
81 df, dr, db, dl,
82 rf, rd, rb, ru,
83 lf, ld, lb, lu,
84 fu, fr, fd, fl,
85 bu, br, bd, bl,
86 uf_mirror, ur_mirror, ub_mirror, ul_mirror,
87 df_mirror, dr_mirror, db_mirror, dl_mirror,
88 rf_mirror, rd_mirror, rb_mirror, ru_mirror,
89 lf_mirror, ld_mirror, lb_mirror, lu_mirror,
90 fu_mirror, fr_mirror, fd_mirror, fl_mirror,
91 bu_mirror, br_mirror, bd_mirror, bl_mirror,
92};
93
94
95/* Structs *******************************************************************/
96
97struct
98alg
99{
100 Move * move;
101 bool * inv;
102 int len;
103 int allocated;
104};
105
106struct
107alglist
108{
109 AlgListNode * first;
110 AlgListNode * last;
111 int len;
112};
113
114struct
115alglistnode
116{
117 Alg * alg;
118 AlgListNode * next;
119};
120
121struct
122block
123{
124 bool edge[12];
125 bool corner[8];
126 bool center[6];
127};
128
129struct
130coordinate
131{
132 Indexer index;
133 AntiIndexer cube;
134 Checker check;
135 uint64_t max;
136};
137
138struct
139cube
140{
141 int epose;
142 int eposs;
143 int eposm;
144 int eofb;
145 int eorl;
146 int eoud;
147 int cp;
148 int coud;
149 int cofb;
150 int corl;
151 int cpos;
152};
153
154struct
155cubearray
156{
157 int * ep;
158 int * eofb;
159 int * eorl;
160 int * eoud;
161 int * cp;
162 int * coud;
163 int * corl;
164 int * cofb;
165 int * cpos;
166};
167
168struct
169cubetarget
170{
171 Cube cube;
172 int target;
173};
174
175struct
176dfsdata
177{
178 int d;
179 int m;
180 int lb;
181 bool niss;
182 Move last1;
183 Move last2;
184 AlgList * sols;
185 Alg * current_alg;
186 Move sorted_moves[NMOVES];
187 int move_position[NMOVES];
188};
189
190struct
191piecefilter
192{
193 bool epose;
194 bool eposs;
195 bool eposm;
196 bool eofb;
197 bool eorl;
198 bool eoud;
199 bool cp;
200 bool coud;
201 bool cofb;
202 bool corl;
203 bool cpos;
204};
205
206struct
207prunedata
208{
209 char * filename;
210 uint8_t * ptable;
211 bool generated;
212 uint64_t n;
213 Coordinate * coord;
214 Moveset moveset;
215 int ntrans;
216 Trans * trans;
217};
218
219struct
220solveoptions
221{
222 int min_moves;
223 int max_moves;
224 int max_solutions;
225 bool optimal_only;
226 bool can_niss;
227 bool feedback;
228};
229
230struct
231step
232{
233 Estimator estimate;
234 Checker ready;
235 Moveset moveset;
236};
237
238struct
239symdata
240{
241 char * filename;
242 bool generated;
243 Coordinate * coord;
244 Coordinate * sym_coord;
245 int ntrans;
246 Trans * trans;
247 uint64_t * class;
248 Cube * rep;
249 Trans * transtorep;
250};
251
252#endif
diff --git a/old/2021-07-15-almostbeforerefactor/macros.h b/old/2021-07-15-almostbeforerefactor/macros.h
new file mode 100644
index 0000000..af3bca1
--- /dev/null
+++ b/old/2021-07-15-almostbeforerefactor/macros.h
@@ -0,0 +1,23 @@
1#ifndef MACROS_H
2#define MACROS_H
3
4#define POW2TO6 64ULL
5#define POW2TO11 2048ULL
6#define POW2TO12 4096ULL
7#define POW3TO7 2187ULL
8#define POW3TO8 6561ULL
9#define FACTORIAL4 24ULL
10#define FACTORIAL6 720ULL
11#define FACTORIAL7 5040ULL
12#define FACTORIAL8 40320ULL
13#define FACTORIAL12 479001600ULL
14#define BINOM12ON4 495ULL
15#define BINOM8ON4 70ULL
16#define MIN(a,b) (((a) < (b)) ? (a) : (b))
17#define MAX(a,b) (((a) > (b)) ? (a) : (b))
18
19#define NMOVES (z3+1)
20#define NTRANS 48
21#define NROTATIONS 24
22
23#endif
diff --git a/old/2021-07-15-almostbeforerefactor/main.c b/old/2021-07-15-almostbeforerefactor/main.c
new file mode 100644
index 0000000..482e007
--- /dev/null
+++ b/old/2021-07-15-almostbeforerefactor/main.c
@@ -0,0 +1,60 @@
1#include <stdio.h>
2#include "cube.h"
3#include "steps.h"
4
5int main() {
6 Alg *algo;
7 AlgList *sols;
8 Cube cube;
9 SolveOptions opts;
10 char line[1000];
11 int i, ns = 1;
12/* Move m;*/
13/* int nrand = 10000, sum1, sum2;*/
14
15 Step *stps[20] = {&optimal_HTM};
16 char sss[30][30] = {"Optimal solve"};
17
18 opts = (SolveOptions) {
19 .min_moves = 0,
20 .max_moves = 20,
21 .optimal_only = true,
22 .max_solutions = 1,
23 .can_niss = false,
24 .feedback = true,
25 };
26
27 init();
28
29/*
30 srand(time(NULL));
31 sum1 = 0;
32 sum2 = 0;
33 for (i = 0; i < nrand; i++) {
34 cube = random_cube();
35 sum1 += drud_HTM.estimate((CubeTarget){.cube = cube, .target = 20});
36 sum2 += optimal_HTM.estimate((CubeTarget){.cube = cube, .target = 20});
37 }
38 printf("Average drud pruning: %lf\n", ((double)sum1) / ((double) nrand));
39 printf("Average corners htr pruning: %lf\n", ((double)sum2) / ((double) nrand));
40*/
41
42
43 printf("Welcome to nissy 2.0! Insert a scramble:\n");
44
45 if (fgets(line, 1000, stdin) != NULL) {
46 algo = new_alg(line);
47 cube = apply_alg(algo, (Cube){0});
48
49 for (i = 0; i < ns; i++) {
50 sols = solve(cube, *stps[i], &opts);
51 printf("%s: %d solutions found:\n", sss[i], sols->len);
52 print_alglist(sols, true);
53 free_alglist(sols);
54 }
55 free_alg(algo);
56 }
57
58 return 0;
59}
60
diff --git a/old/2021-07-15-almostbeforerefactor/nissy b/old/2021-07-15-almostbeforerefactor/nissy
new file mode 100755
index 0000000..63f9c39
--- /dev/null
+++ b/old/2021-07-15-almostbeforerefactor/nissy
Binary files differ
diff --git a/old/2021-07-15-almostbeforerefactor/steps.c b/old/2021-07-15-almostbeforerefactor/steps.c
new file mode 100644
index 0000000..33dc74d
--- /dev/null
+++ b/old/2021-07-15-almostbeforerefactor/steps.c
@@ -0,0 +1,284 @@
1#include "steps.h"
2
3/* Standard checkers (return lower bound) ************************************/
4
5static int estimate_eofb_HTM(CubeTarget ct);
6static int estimate_coud_HTM(CubeTarget ct);
7static int estimate_coud_URF(CubeTarget ct);
8static int estimate_corners_HTM(CubeTarget ct);
9static int estimate_cornershtr_HTM(CubeTarget ct);
10static int estimate_corners_URF(CubeTarget ct);
11static int estimate_cornershtr_URF(CubeTarget ct);
12static int estimate_drud_HTM(CubeTarget ct);
13static int estimate_optimal_HTM(CubeTarget ct);
14
15/* Steps *********************************************************************/
16
17Step
18eofb_HTM = {
19 .estimate = estimate_eofb_HTM,
20 .ready = check_centers,
21 .moveset = moveset_HTM
22};
23
24Step
25coud_HTM = {
26 .estimate = estimate_coud_HTM,
27 .ready = check_centers,
28 .moveset = moveset_HTM
29};
30
31Step
32coud_URF = {
33 .estimate = estimate_coud_URF,
34 .ready = check_nothing,
35 .moveset = moveset_URF
36};
37
38Step
39corners_HTM = {
40 .estimate = estimate_corners_HTM,
41 .ready = check_centers,
42 .moveset = moveset_HTM
43};
44
45Step
46cornershtr_HTM = {
47 .estimate = estimate_cornershtr_HTM,
48 .ready = check_centers,
49 .moveset = moveset_HTM
50};
51
52Step
53cornershtr_URF = {
54 .estimate = estimate_cornershtr_URF,
55 .ready = check_nothing,
56 .moveset = moveset_URF
57};
58
59Step
60corners_URF = {
61 .estimate = estimate_corners_URF,
62 .ready = check_nothing,
63 .moveset = moveset_URF
64};
65
66Step
67drud_HTM = {
68 .estimate = estimate_drud_HTM,
69 .ready = check_centers,
70 .moveset = moveset_HTM
71};
72
73Step
74optimal_HTM = {
75 .estimate = estimate_optimal_HTM,
76 .ready = check_centers,
77 .moveset = moveset_HTM
78};
79
80
81/* Pruning tables ************************************************************/
82
83PruneData
84pd_eofb_HTM = {
85 .filename = "ptable_eofb_HTM",
86 .coord = &coord_eofb,
87 .moveset = moveset_HTM,
88 .ntrans = 1,
89 .trans = trans_group_trivial
90};
91
92PruneData
93pd_coud_HTM = {
94 .filename = "ptable_coud_HTM",
95 .coord = &coord_coud,
96 .moveset = moveset_HTM,
97 .ntrans = 1,
98 .trans = trans_group_trivial
99};
100
101PruneData
102pd_cornershtr_HTM = {
103 .filename = "ptable_cornershtr_withcosets_HTM",
104 .coord = &coord_cornershtr,
105 .moveset = moveset_HTM,
106 .ntrans = 1,
107 .trans = trans_group_trivial
108};
109
110PruneData
111pd_corners_HTM = {
112 .filename = "ptable_corners_HTM",
113 .coord = &coord_corners,
114 .moveset = moveset_HTM,
115 .ntrans = 1,
116 .trans = trans_group_trivial
117};
118
119PruneData
120pd_drud_HTM = {
121 .filename = "ptable_drud_HTM",
122 .coord = &coord_drud,
123 .moveset = moveset_HTM,
124 .ntrans = 1,
125 .trans = trans_group_trivial
126};
127
128PruneData
129pd_drud_sym16_HTM = {
130 .filename = "ptable_drud_sym16_HTM",
131 .coord = &coord_drud_sym16,
132 .moveset = moveset_HTM,
133 .ntrans = 16,
134 .trans = trans_group_udfix
135};
136
137PruneData
138pd_khuge_HTM = {
139 .filename = "ptable_khuge_HTM",
140 .coord = &coord_khuge,
141 .moveset = moveset_HTM,
142 .ntrans = 16,
143 .trans = trans_group_udfix
144};
145
146
147/* Standard checkers (return lower bound) ************************************/
148
149static int
150estimate_eofb_HTM(CubeTarget ct)
151{
152 if (!pd_eofb_HTM.generated)
153 genptable(&pd_eofb_HTM);
154
155 return ptableval(&pd_eofb_HTM, ct.cube);
156}
157
158static int
159estimate_coud_HTM(CubeTarget ct)
160{
161 if (!pd_coud_HTM.generated)
162 genptable(&pd_coud_HTM);
163
164 return ptableval(&pd_coud_HTM, ct.cube);
165}
166
167static int
168estimate_coud_URF(CubeTarget ct)
169{
170 /* TODO: I can improve this by checking first the orientation of
171 * the corner in DBL and use that as a reference */
172
173 CubeTarget ct2 = {.cube = apply_move(z, ct.cube), .target = ct.target};
174 CubeTarget ct3 = {.cube = apply_move(x, ct.cube), .target = ct.target};
175
176 int ud = estimate_coud_HTM(ct);
177 int rl = estimate_coud_HTM(ct2);
178 int fb = estimate_coud_HTM(ct3);
179
180 return MIN(ud, MIN(rl, fb));
181}
182
183static int
184estimate_corners_HTM(CubeTarget ct)
185{
186 if (!pd_corners_HTM.generated)
187 genptable(&pd_corners_HTM);
188
189 return ptableval(&pd_corners_HTM, ct.cube);
190}
191
192static int
193estimate_cornershtr_HTM(CubeTarget ct)
194{
195 if (!pd_cornershtr_HTM.generated)
196 genptable(&pd_cornershtr_HTM);
197
198 return ptableval(&pd_cornershtr_HTM, ct.cube);
199}
200
201static int
202estimate_cornershtr_URF(CubeTarget ct)
203{
204 /* TODO: I can improve this by checking first the corner in DBL
205 * and use that as a reference */
206
207 int c, ret = 15;
208 Trans i;
209
210 for (i = 0; i < NROTATIONS; i++) {
211 ct.cube = apply_alg(rotation_alg(i), ct.cube);
212 c = estimate_cornershtr_HTM(ct);
213 ret = MIN(ret, c);
214 }
215
216 return ret;
217}
218
219static int
220estimate_corners_URF(CubeTarget ct)
221{
222 /* TODO: I can improve this by checking first the corner in DBL
223 * and use that as a reference */
224
225 int c, ret = 15;
226 Trans i;
227
228 for (i = 0; i < NROTATIONS; i++) {
229 ct.cube = apply_alg(rotation_alg(i), ct.cube);
230 c = estimate_corners_HTM(ct);
231 ret = MIN(ret, c);
232 }
233
234 return ret;
235}
236
237static int
238estimate_drud_HTM(CubeTarget ct)
239{
240/*
241 if (!pd_drud_HTM.generated)
242 genptable(&pd_drud_HTM);
243
244 return ptableval(&pd_drud_HTM, ct.cube);
245*/
246
247 if (!pd_drud_sym16_HTM.generated)
248 genptable(&pd_drud_sym16_HTM);
249
250 return ptableval(&pd_drud_sym16_HTM, ct.cube);
251}
252
253static int
254estimate_optimal_HTM(CubeTarget ct)
255{
256 int dr1, dr2, dr3, cor, ret;
257 Cube cube = ct.cube;
258
259 if (!pd_khuge_HTM.generated)
260 genptable(&pd_khuge_HTM);
261
262 dr1 = ptableval(&pd_khuge_HTM, cube);
263 cor = estimate_corners_HTM(ct);
264 ret = MAX(dr1, cor);
265
266 if (ret > ct.target)
267 return ret;
268
269 cube = apply_trans(rf, ct.cube);
270 dr2 = ptableval(&pd_khuge_HTM, cube);
271 ret = MAX(ret, dr2);
272
273 if (ret > ct.target)
274 return ret;
275
276 cube = apply_trans(fd, ct.cube);
277 dr3 = ptableval(&pd_khuge_HTM, cube);
278
279 /* Michiel de Bondt's trick */
280 if (dr1 == dr2 && dr2 == dr3 && dr1 != 0)
281 dr3++;
282
283 return MAX(ret, dr3);
284}
diff --git a/old/2021-07-15-almostbeforerefactor/steps.h b/old/2021-07-15-almostbeforerefactor/steps.h
new file mode 100644
index 0000000..81ae11c
--- /dev/null
+++ b/old/2021-07-15-almostbeforerefactor/steps.h
@@ -0,0 +1,24 @@
1#ifndef STEPS_H
2#define STEPS_H
3
4#include "cube.h"
5
6extern Step eofb_HTM;
7extern Step coud_HTM;
8extern Step coud_URF;
9extern Step corners_HTM;
10extern Step cornershtr_HTM;
11extern Step corners_URF;
12extern Step cornershtr_URF;
13extern Step drud_HTM;
14extern Step optimal_HTM;
15
16extern PruneData pd_eofb_HTM;
17extern PruneData pd_coud_HTM;
18extern PruneData pd_corners_HTM;
19extern PruneData pd_cornershtr_HTM;
20extern PruneData pd_cornershtreofb_HTM;
21extern PruneData pd_drud_HTM;
22extern PruneData pd_khuge_HTM;
23
24#endif
diff --git a/old/2021-11-10-beforeremovingchecker/alg.c b/old/2021-11-10-beforeremovingchecker/alg.c
new file mode 100644
index 0000000..06c2d7b
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/alg.c
@@ -0,0 +1,366 @@
1#include "alg.h"
2
3/* Local functions ***********************************************************/
4
5static void free_alglistnode(AlgListNode *aln);
6static void realloc_alg(Alg *alg, int n);
7
8/* Movesets ******************************************************************/
9
10bool
11moveset_HTM(Move m)
12{
13 return m >= U && m <= B3;
14}
15
16bool
17moveset_URF(Move m)
18{
19 Move b = base_move(m);
20
21 return b == U || b == R || b == F;
22}
23
24bool
25moveset_eofb(Move m)
26{
27 Move b = base_move(m);
28
29 return b == U || b == D || b == R || b == L ||
30 ((b == F || b == B) && m == b+1);
31}
32
33bool
34moveset_drud(Move m)
35{
36 Move b = base_move(m);
37
38 return b == U || b == D ||
39 ((b == R || b == L || b == F || b == B) && m == b + 1);
40}
41
42bool
43moveset_htr(Move m)
44{
45 Move b = base_move(m);
46
47 return moveset_HTM(m) && m == b + 1;
48}
49
50
51/* Functions *****************************************************************/
52
53void
54append_alg(AlgList *l, Alg *alg)
55{
56 AlgListNode *node = malloc(sizeof(AlgListNode));
57 int i;
58
59 node->alg = new_alg("");
60 for (i = 0; i < alg->len; i++)
61 append_move(node->alg, alg->move[i], alg->inv[i]);
62 node->next = NULL;
63
64 if (++l->len == 1)
65 l->first = node;
66 else
67 l->last->next = node;
68 l->last = node;
69}
70
71void
72append_move(Alg *alg, Move m, bool inverse)
73{
74 if (alg->len == alg->allocated)
75 realloc_alg(alg, 2*alg->len);
76
77 alg->move[alg->len] = m;
78 alg->inv [alg->len] = inverse;
79 alg->len++;
80}
81
82Move
83base_move(Move m)
84{
85 if (m == NULLMOVE)
86 return NULLMOVE;
87 else
88 return m - (m-1)%3;
89}
90
91void
92compose_alg(Alg *alg1, Alg *alg2)
93{
94 int i;
95
96 for (i = 0; i < alg2->len; i++)
97 append_move(alg1, alg2->move[i], alg2->inv[i]);
98}
99
100void
101free_alg(Alg *alg)
102{
103 free(alg->move);
104 free(alg->inv);
105 free(alg);
106}
107
108void
109free_alglist(AlgList *l)
110{
111 AlgListNode *aux, *i = l->first;
112
113 while (i != NULL) {
114 aux = i->next;
115 free_alglistnode(i);
116 i = aux;
117 }
118 free(l);
119}
120
121static void
122free_alglistnode(AlgListNode *aln)
123{
124 free_alg(aln->alg);
125 free(aln);
126}
127
128Alg *
129inverse_alg(Alg *alg)
130{
131 Alg *ret = new_alg("");
132 int i;
133
134 for (i = alg->len-1; i >= 0; i--)
135 append_move(ret, inverse_move(alg->move[i]), alg->inv[i]);
136
137 return ret;
138}
139
140Move
141inverse_move(Move m)
142{
143 return m == NULLMOVE ? NULLMOVE : m + 2 - 2*((m-1) % 3);
144}
145
146char *
147move_string(Move m)
148{
149 static char move_string_aux[NMOVES][7] = {
150 [NULLMOVE] = "-",
151 [U] = "U", [U2] = "U2", [U3] = "U\'",
152 [D] = "D", [D2] = "D2", [D3] = "D\'",
153 [R] = "R", [R2] = "R2", [R3] = "R\'",
154 [L] = "L", [L2] = "L2", [L3] = "L\'",
155 [F] = "F", [F2] = "F2", [F3] = "F\'",
156 [B] = "B", [B2] = "B2", [B3] = "B\'",
157 [Uw] = "Uw", [Uw2] = "Uw2", [Uw3] = "Uw\'",
158 [Dw] = "Dw", [Dw2] = "Dw2", [Dw3] = "Dw\'",
159 [Rw] = "Rw", [Rw2] = "Rw2", [Rw3] = "Rw\'",
160 [Lw] = "Lw", [Lw2] = "Lw2", [Lw3] = "Lw\'",
161 [Fw] = "Fw", [Fw2] = "Fw2", [Fw3] = "Fw\'",
162 [Bw] = "Bw", [Bw2] = "Bw2", [Bw3] = "Bw\'",
163 [M] = "M", [M2] = "M2", [M3] = "M\'",
164 [E] = "E", [E2] = "E2", [E3] = "E\'",
165 [S] = "S", [S2] = "S2", [S3] = "S\'",
166 [x] = "x", [x2] = "x2", [x3] = "x\'",
167 [y] = "y", [y2] = "y2", [y3] = "y\'",
168 [z] = "z", [z2] = "z2", [z3] = "z\'",
169 };
170
171 return move_string_aux[m];
172}
173
174void
175movelist_to_position(Move *movelist, int *position)
176{
177 Move m;
178
179 for (m = 0; m < NMOVES && movelist[m] != NULLMOVE; m++)
180 position[movelist[m]] = m;
181}
182
183void
184moveset_to_list(Moveset ms, Move *r)
185{
186 int n = 0;
187 Move i;
188
189 if (ms == NULL) {
190 fprintf(stderr, "Error: no moveset given\n");
191 return;
192 }
193
194 for (i = U; i < NMOVES; i++)
195 if (ms(i))
196 r[n++] = i;
197
198 r[n] = NULLMOVE;
199}
200
201Alg *
202new_alg(char *str)
203{
204 Alg *alg = malloc(sizeof(Alg));
205 int i;
206 bool niss = false, move_read;
207 Move j, m;
208
209 alg->move = malloc(30 * sizeof(Move));
210 alg->inv = malloc(30 * sizeof(bool));
211 alg->allocated = 30;
212 alg->len = 0;
213
214 for (i = 0; str[i]; i++) {
215 if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n')
216 continue;
217
218 if (str[i] == '(' && niss) {
219 fprintf(stderr, "Error reading moves: nested ( )\n");
220 return alg;
221 }
222
223 if (str[i] == ')' && !niss) {
224 fprintf(stderr, "Error reading moves: unmatched )\n");
225 return alg;
226 }
227
228 if (str[i] == '(' || str[i] == ')') {
229 niss = !niss;
230 continue;
231 }
232
233 move_read = false;
234 for (j = 0; j < NMOVES; j++) {
235 if (str[i] == move_string(j)[0] ||
236 (str[i] >= 'a' && str[i] <= 'z' &&
237 str[i] == move_string(j)[0]-('A'-'a') && j<=B)) {
238 m = j;
239 if (str[i] >= 'a' && str[i] <= 'z' && j<=B) {
240 m += Uw - U;
241 }
242 if (m <= B && str[i+1]=='w') {
243 m += Uw - U;
244 i++;
245 }
246 if (str[i+1]=='2') {
247 m += 1;
248 i++;
249 } else if (str[i+1] == '\'' ||
250 str[i+1] == '3' ||
251 str[i+1] == '`' ) {
252 m += 2;
253 i++;
254 } else if ((int)str[i+1] == -62 &&
255 (int)str[i+2] == -76) {
256 /* Weird apostrophe */
257 m += 2;
258 i += 2;
259 } else if ((int)str[i+1] == -30 &&
260 (int)str[i+2] == -128 &&
261 (int)str[i+3] == -103) {
262 /* MacOS apostrophe */
263 m += 2;
264 i += 3;
265 }
266 append_move(alg, m, niss);
267 move_read = true;
268 break;
269 }
270 }
271
272 if (!move_read) {
273 alg = new_alg("");
274 return alg;
275 }
276 }
277
278 return alg;
279}
280
281AlgList *
282new_alglist()
283{
284 AlgList *ret = malloc(sizeof(AlgList));
285
286 ret->len = 0;
287 ret->first = NULL;
288 ret->last = NULL;
289
290 return ret;
291}
292
293Alg *
294on_inverse(Alg *alg)
295{
296 Alg *ret = new_alg("");
297 int i;
298
299 for (i = 0; i < alg->len; i++)
300 append_move(ret, alg->move[i], !alg->inv[i]);
301
302 return ret;
303}
304
305void
306print_alg(Alg *alg, bool l)
307{
308 /* TODO: make it possible to print to stdout or to string */
309 /* Maybe just return a string */
310 char fill[4];
311 int i;
312 bool niss = false;
313
314 for (i = 0; i < alg->len; i++) {
315 if (!niss && alg->inv[i])
316 strcpy(fill, i == 0 ? "(" : " (");
317 if (niss && !alg->inv[i])
318 strcpy(fill, ") ");
319 if (niss == alg->inv[i])
320 strcpy(fill, i == 0 ? "" : " ");
321
322 printf("%s%s", fill, move_string(alg->move[i]));
323 niss = alg->inv[i];
324 }
325
326 if (niss)
327 printf(")");
328 if (l)
329 printf(" (%d)", alg->len);
330
331 printf("\n");
332}
333
334void
335print_alglist(AlgList *al, bool l)
336{
337 AlgListNode *i;
338
339 for (i = al->first; i != NULL; i = i->next)
340 print_alg(i->alg, l);
341}
342
343static void
344realloc_alg(Alg *alg, int n)
345{
346 if (alg == NULL) {
347 fprintf(stderr, "Error: trying to reallocate NULL alg.\n");
348 return;
349 }
350
351 if (n < alg->len) {
352 fprintf(stderr, "Error: alg too long for reallocation ");
353 fprintf(stderr, "(%d vs %d)\n", alg->len, n);
354 return;
355 }
356
357 if (n > 1000000) {
358 fprintf(stderr, "Warning: very long alg,");
359 fprintf(stderr, "something might go wrong.\n");
360 }
361
362 alg->move = realloc(alg->move, n * sizeof(int));
363 alg->inv = realloc(alg->inv, n * sizeof(int));
364 alg->allocated = n;
365}
366
diff --git a/old/2021-11-10-beforeremovingchecker/alg.h b/old/2021-11-10-beforeremovingchecker/alg.h
new file mode 100644
index 0000000..98900b4
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/alg.h
@@ -0,0 +1,35 @@
1#ifndef ALG_H
2#define ALG_H
3
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7
8#include "cubetypes.h"
9#include "utils.h"
10
11bool moveset_HTM(Move m);
12bool moveset_URF(Move m);
13bool moveset_eofb(Move m);
14bool moveset_drud(Move m);
15bool moveset_htr(Move m);
16
17void append_alg(AlgList *l, Alg *alg);
18void append_move(Alg *alg, Move m, bool inverse);
19void compose_alg(Alg *alg1, Alg *alg2);
20Move base_move(Move m);
21void free_alg(Alg *alg);
22void free_alglist(AlgList *l);
23Alg * inverse_alg(Alg *alg);
24Move inverse_move(Move m);
25char * move_string(Move m);
26void movelist_to_position(Move *ml, int *pos);
27void moveset_to_list(Moveset ms, Move *lst);
28Alg * new_alg(char *str);
29AlgList * new_alglist();
30Alg * on_inverse(Alg *alg);
31void print_alg(Alg *alg, bool l);
32void print_alglist(AlgList *al, bool l);
33
34#endif
35
diff --git a/old/2021-11-10-beforeremovingchecker/commands.c b/old/2021-11-10-beforeremovingchecker/commands.c
new file mode 100644
index 0000000..b141229
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/commands.c
@@ -0,0 +1,329 @@
1#include "commands.h"
2
3/* Arg parsing functions *****************************************************/
4
5CommandArgs * solvestep_parse_args(int c, char **v);
6CommandArgs * help_parse_args(int c, char **v);
7CommandArgs * print_parse_args(int c, char **v);
8CommandArgs * parse_no_arg(int c, char **v);
9
10/* Exec functions ************************************************************/
11
12static void solvestep_exec(CommandArgs *args);
13static void steps_exec(CommandArgs *args);
14static void commands_exec(CommandArgs *args);
15static void print_exec(CommandArgs *args);
16static void help_exec(CommandArgs *args);
17static void quit_exec(CommandArgs *args);
18
19/* Local functions ***********************************************************/
20
21static bool read_step(CommandArgs *args, char *str);
22static bool read_scramble(int c, char **v, CommandArgs *args);
23
24/* Commands ******************************************************************/
25
26Command
27solvestep_cmd = {
28 .name = "solve",
29 .usage = "solve STEP [OPTIONS] SCRAMBLE",
30 .description = "Solve a step",
31 .parse_args = solvestep_parse_args,
32 .exec = solvestep_exec
33};
34
35Command
36steps_cmd = {
37 .name = "steps",
38 .usage = "steps",
39 .description = "List available steps",
40 .parse_args = parse_no_arg,
41 .exec = steps_exec
42};
43
44Command
45commands_cmd = {
46 .name = "commands",
47 .usage = "commands",
48 .description = "List available commands",
49 .parse_args = parse_no_arg,
50 .exec = commands_exec
51};
52
53Command
54print_cmd = {
55 .name = "print",
56 .usage = "print SCRAMBLE",
57 .description = "Print written description of the cube",
58 .parse_args = print_parse_args,
59 .exec = print_exec,
60};
61
62Command
63help_cmd = {
64 .name = "help",
65 .usage = "help [COMMAND]",
66 .description = "Display nissy manual page or help on specific command",
67 .parse_args = help_parse_args,
68 .exec = help_exec,
69};
70
71Command
72quit_cmd = {
73 .name = "quit",
74 .usage = "quit",
75 .description = "Quit nissy",
76 .parse_args = parse_no_arg,
77 .exec = quit_exec,
78};
79
80Command *commands[NCOMMANDS] = {
81 &solvestep_cmd,
82 &steps_cmd,
83 &commands_cmd,
84 &help_cmd,
85 &print_cmd,
86 &quit_cmd
87};
88
89/* Arg parsing functions implementation **************************************/
90
91CommandArgs *
92solvestep_parse_args(int c, char **v)
93{
94 int i;
95 long val;
96
97 CommandArgs *a = malloc(sizeof(CommandArgs));
98
99 a->success = false;
100 a->opts = malloc(sizeof(SolveOptions));
101 a->step = steps[0];
102 a->command = NULL;
103 a->scramble = NULL;
104
105 a->opts->min_moves = 0;
106 a->opts->max_moves = 20;
107 a->opts->max_solutions = 1;
108 a->opts->optimal_only = false;
109 a->opts->can_niss = false;
110 a->opts->feedback = false;
111 a->opts->all = false;
112 a->opts->print_number = true;
113
114 for (i = 0; i < c; i++) {
115 if (!strcmp(v[i], "-m")) {
116 val = strtol(v[++i], NULL, 10);
117 if (val < 0 || val > 100) {
118 fprintf(stderr,
119 "Invalid min number of moves.\n");
120 return a;
121 }
122 a->opts->min_moves = val;
123 } else if (!strcmp(v[i], "-M")) {
124 val = strtol(v[++i], NULL, 10);
125 if (val < 0 || val > 100) {
126 fprintf(stderr,
127 "Invalid max number of moves.\n");
128 return a;
129 }
130 a->opts->max_moves = val;
131 } else if (!strcmp(v[i], "-s")) {
132 val = strtol(v[++i], NULL, 10);
133 if (val < 1 || val > 1000000) {
134 fprintf(stderr,
135 "Invalid number of solutions.\n");
136 return a;
137 }
138 a->opts->max_solutions = val;
139 } else if (!strcmp(v[i], "-o")) {
140 a->opts->optimal_only = true;
141 } else if (!strcmp(v[i], "-n")) {
142 a->opts->can_niss = true;
143 } else if (!strcmp(v[i], "-v")) {
144 a->opts->feedback = true;
145 } else if (!strcmp(v[i], "-a")) {
146 a->opts->all = true;
147 } else if (!strcmp(v[i], "-p")) {
148 a->opts->print_number = false;
149 } else if (!read_step(a, v[i])) {
150 break;
151 }
152 }
153
154 a->success = read_scramble(c-i, &v[i], a);
155 return a;
156}
157
158CommandArgs *
159help_parse_args(int c, char **v)
160{
161 int i;
162 CommandArgs *a = malloc(sizeof(CommandArgs));
163
164 a->scramble = NULL;
165 a->opts = NULL;
166 a->step = NULL;
167 a->command = NULL;
168
169 if (c == 1) {
170 for (i = 0; i < NCOMMANDS; i++)
171 if (commands[i] != NULL &&
172 !strcmp(v[0], commands[i]->name))
173 a->command = commands[i];
174 if (a->command == NULL)
175 fprintf(stderr, "%s: command not found\n", v[0]);
176 }
177
178 a->success = c == 0 || (c == 1 && a->command != NULL);
179 return a;
180}
181
182CommandArgs *
183parse_no_arg(int c, char **v)
184{
185 CommandArgs *a = malloc(sizeof(CommandArgs));
186
187 a->scramble = NULL;
188 a->opts = NULL;
189 a->step = NULL;
190 a->command = NULL;
191
192 return a;
193}
194
195CommandArgs *
196print_parse_args(int c, char **v)
197{
198 CommandArgs *a = malloc(sizeof(CommandArgs));
199
200 a->opts = NULL;
201 a->step = NULL;
202 a->command = NULL;
203
204 a->success = read_scramble(c-1, &v[1], a);
205 return a;
206}
207
208/* Exec functions implementation *********************************************/
209
210static void
211solvestep_exec(CommandArgs *args)
212{
213 Cube c = apply_alg(args->scramble, (Cube){0});
214 AlgList *sols = solve(c, args->step, args->opts);
215 print_alglist(sols, args->opts->print_number);
216 free_alglist(sols);
217}
218
219static void
220steps_exec(CommandArgs *args)
221{
222 int i;
223
224 for (i = 0; i < NSTEPS && steps[i] != NULL; i++)
225 printf("%-15s %s\n", steps[i]->shortname, steps[i]->name);
226}
227
228static void
229commands_exec(CommandArgs *args)
230{
231 int i;
232
233 for (i = 0; i < NCOMMANDS && commands[i] != NULL; i++)
234 printf("%s\n", commands[i]->usage);
235
236}
237
238static void
239print_exec(CommandArgs *args)
240{
241 print_cube(apply_alg(args->scramble, (Cube){0}));
242}
243
244static void
245help_exec(CommandArgs *args)
246{
247 /* TODO: print full nissy manpage */
248 if (args->command == NULL) {
249 printf("Type help COMMAND for information on a ");
250 printf("specific command.\n");
251 printf("A more complete manual page is work in progress.\n");
252 } else {
253 printf("Command %s: %s\nusage: %s\n", args->command->name,
254 args->command->description, args->command->usage);
255 }
256}
257
258static void
259quit_exec(CommandArgs *args)
260{
261 exit(0);
262}
263
264/* Local functions implementation ********************************************/
265
266static bool
267read_step(CommandArgs *args, char *str)
268{
269 int i;
270
271 for (i = 0; i < NSTEPS; i++) {
272 if (steps[i] != NULL && !strcmp(steps[i]->shortname, str)) {
273 args->step = steps[i];
274 return true;
275 }
276 }
277
278 return false;
279}
280
281static bool
282read_scramble(int c, char **v, CommandArgs *args)
283{
284 int i, k, n;
285 unsigned int j;
286 char *algstr;
287
288 if (new_alg(v[0])->len == 0) {
289 fprintf(stderr, "%s: moves or option unrecognized\n", v[0]);
290 return false;
291 }
292
293 n = 0;
294 for(i = 0; i < c; i++)
295 n += strlen(v[i]);
296
297 algstr = malloc((n + 1) * sizeof(char));
298 k = 0;
299 for (i = 0; i < c; i++)
300 for (j = 0; j < strlen(v[i]); j++)
301 algstr[k++] = v[i][j];
302 algstr[k] = 0;
303
304 args->scramble = new_alg(algstr);
305 free(algstr);
306
307 if (args->scramble->len == 0)
308 fprintf(stderr, "Error reading scramble\n");
309
310 return args->scramble->len > 0;
311}
312
313/* Public functions implementation *******************************************/
314
315void
316free_args(CommandArgs *args)
317{
318 if (args == NULL)
319 return;
320
321 if (args->scramble != NULL)
322 free_alg(args->scramble);
323 if (args->opts != NULL)
324 free(args->opts);
325
326 /* step and command must not be freed, they are static! */
327
328 free(args);
329}
diff --git a/old/2021-11-10-beforeremovingchecker/commands.h b/old/2021-11-10-beforeremovingchecker/commands.h
new file mode 100644
index 0000000..f2703fa
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/commands.h
@@ -0,0 +1,13 @@
1#ifndef COMMANDS_H
2#define COMMANDS_H
3
4#include "solve.h"
5#include "steps.h"
6
7#define NCOMMANDS 10
8
9void free_args(CommandArgs *args);
10
11extern Command * commands[NCOMMANDS];
12
13#endif
diff --git a/old/2021-11-10-beforeremovingchecker/coord.c b/old/2021-11-10-beforeremovingchecker/coord.c
new file mode 100644
index 0000000..343dfb3
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/coord.c
@@ -0,0 +1,629 @@
1#include "coord.h"
2
3static Cube antindex_eofb(uint64_t ind);
4static Cube antindex_eofbepos(uint64_t ind);
5static Cube antindex_epud(uint64_t ind);
6static Cube antindex_coud(uint64_t ind);
7static Cube antindex_corners(uint64_t ind);
8static Cube antindex_cp(uint64_t ind);
9static Cube antindex_cphtr(uint64_t);
10static Cube antindex_cornershtr(uint64_t ind);
11static Cube antindex_cornershtrfin(uint64_t ind);
12static Cube antindex_drud(uint64_t ind);
13static Cube antindex_drud_eofb(uint64_t ind);
14static Cube antindex_htr_drud(uint64_t ind);
15static Cube antindex_htrfin(uint64_t ind);
16
17static uint64_t index_eofb(Cube cube);
18static uint64_t index_eofbepos(Cube cube);
19static uint64_t index_epud(Cube cube);
20static uint64_t index_coud(Cube cube);
21static uint64_t index_corners(Cube cube);
22static uint64_t index_cp(Cube cube);
23static uint64_t index_cphtr(Cube cube);
24static uint64_t index_cornershtr(Cube cube);
25static uint64_t index_cornershtrfin(Cube cube);
26static uint64_t index_drud(Cube cube);
27static uint64_t index_drud_eofb(Cube cube);
28static uint64_t index_htr_drud(Cube cube);
29static uint64_t index_htrfin(Cube cube);
30
31static void init_cphtr_cosets();
32static void init_cphtr_left_cosets_bfs(int i, int c);
33static void init_cphtr_right_cosets_color(int i, int c);
34static void init_cornershtrfin();
35
36
37/* All sorts of useful costants and tables **********************************/
38
39static int cphtr_left_cosets[FACTORIAL8];
40static int cphtr_right_cosets[FACTORIAL8];
41static int cphtr_right_rep[BINOM8ON4*6];
42static int cornershtrfin_ind[FACTORIAL8];
43static int cornershtrfin_ant[24*24/6];
44
45/* Coordinates and their implementation **************************************/
46
47Coordinate
48coord_eofb = {
49 .index = index_eofb,
50 .cube = antindex_eofb,
51 .check = check_eofb,
52 .max = POW2TO11,
53 .ntrans = 1,
54};
55
56Coordinate
57coord_eofbepos = {
58 .index = index_eofbepos,
59 .cube = antindex_eofbepos,
60 .check = check_eofbepos,
61 .max = POW2TO11 * BINOM12ON4,
62 .ntrans = 1,
63};
64
65Coordinate
66coord_coud = {
67 .index = index_coud,
68 .cube = antindex_coud,
69 .check = check_coud,
70 .max = POW3TO7,
71 .ntrans = 1,
72};
73
74Coordinate
75coord_corners = {
76 .index = index_corners,
77 .cube = antindex_corners,
78 .check = check_corners,
79 .max = POW3TO7 * FACTORIAL8,
80 .ntrans = 1,
81};
82
83Coordinate
84coord_cp = {
85 .index = index_cp,
86 .cube = antindex_cp,
87 .check = check_cp,
88 .max = FACTORIAL8,
89 .ntrans = 1,
90};
91
92Coordinate
93coord_cphtr = {
94 .index = index_cphtr,
95 .cube = antindex_cphtr,
96 .check = check_cphtr,
97 .max = BINOM8ON4 * 6,
98 .ntrans = 1,
99};
100
101Coordinate
102coord_cornershtr = {
103 .index = index_cornershtr,
104 .cube = antindex_cornershtr,
105 .check = check_cornershtr,
106 .max = POW3TO7 * BINOM8ON4 * 6,
107 .ntrans = 1,
108};
109
110Coordinate
111coord_cornershtrfin = {
112 .index = index_cornershtrfin,
113 .cube = antindex_cornershtrfin,
114 .check = check_cp,
115 .max = 24*24/6,
116 .ntrans = 1,
117};
118
119Coordinate
120coord_epud = {
121 .index = index_epud,
122 .cube = antindex_epud,
123 .check = check_epud,
124 .max = FACTORIAL8,
125 .ntrans = 1,
126};
127
128Coordinate
129coord_drud = {
130 .index = index_drud,
131 .cube = antindex_drud,
132 .check = check_drud,
133 .max = POW2TO11 * POW3TO7 * BINOM12ON4,
134 .ntrans = 1,
135};
136
137Coordinate
138coord_htr_drud = {
139 .index = index_htr_drud,
140 .cube = antindex_htr_drud,
141 .check = check_drud,
142 .max = BINOM8ON4 * 6 * BINOM8ON4,
143 .ntrans = 1,
144};
145
146Coordinate
147coord_htrfin = {
148 .index = index_htrfin,
149 .cube = antindex_htrfin,
150 .check = check_htr,
151 .max = 24 * 24 * 24 *24 * 24 / 6, /* should be /12 but it's ok */
152 .ntrans = 1,
153};
154
155Coordinate
156coord_drud_eofb = {
157 .index = index_drud_eofb,
158 .cube = antindex_drud_eofb,
159 .check = check_drud,
160 .max = POW3TO7 * BINOM12ON4,
161 .ntrans = 1,
162};
163
164/* Functions *****************************************************************/
165
166static Cube
167antindex_eofb(uint64_t ind)
168{
169 return (Cube){ .eofb = ind, .eorl = ind, .eoud = ind };
170}
171
172static Cube
173antindex_eofbepos(uint64_t ind)
174{
175 Cube ret = {0};
176
177 ret.eofb = ind % POW2TO11;
178 ret.epose = (ind / POW2TO11) * 24;
179
180 return ret;
181}
182
183static Cube
184antindex_epud(uint64_t ind)
185{
186 static bool initialized = false;
187 static Cube epud_aux[FACTORIAL8];
188 int a[12];
189 uint64_t ui;
190 CubeArray arr;
191
192 if (!initialized) {
193 a[FR] = FR;
194 a[FL] = FL;
195 a[BL] = BL;
196 a[BR] = BR;
197 for (ui = 0; ui < FACTORIAL8; ui++) {
198 index_to_perm(ui, 8, a);
199 arr.ep = a;
200 epud_aux[ui] = arrays_to_cube(&arr, pf_ep);
201 }
202
203 initialized = true;
204 }
205
206 return epud_aux[ind];
207}
208
209static Cube
210antindex_coud(uint64_t ind)
211{
212 return (Cube){ .coud = ind, .corl = ind, .cofb = ind };
213}
214
215static Cube
216antindex_corners(uint64_t ind)
217{
218 Cube c = {0};
219
220 c.coud = ind / FACTORIAL8;
221 c.cp = ind % FACTORIAL8;
222
223 return c;
224}
225
226static Cube
227antindex_cp(uint64_t ind)
228{
229 Cube c = {0};
230
231 c.cp = ind;
232
233 return c;
234}
235
236static Cube
237antindex_cphtr(uint64_t ind)
238{
239 return (Cube) { .cp = cphtr_right_rep[ind] };
240}
241
242static Cube
243antindex_cornershtr(uint64_t ind)
244{
245 Cube c = antindex_cphtr(ind % (BINOM8ON4 * 6));
246
247 c.coud = ind / (BINOM8ON4 * 6);
248
249 return c;
250}
251
252static Cube
253antindex_cornershtrfin(uint64_t ind)
254{
255 return (Cube){ .cp = cornershtrfin_ant[ind] };
256}
257
258static Cube
259antindex_drud(uint64_t ind)
260{
261 uint64_t epos, eofb;
262 Cube c;
263
264 eofb = ind % POW2TO11;
265 epos = ind / (POW2TO11 * POW3TO7);
266 c = antindex_eofbepos(eofb + POW2TO11 * epos);
267
268 c.coud = (ind / POW2TO11) % POW3TO7;
269
270 return c;
271}
272
273static Cube
274antindex_drud_eofb(uint64_t ind)
275{
276 return antindex_drud(ind * POW2TO11);
277}
278
279static Cube
280antindex_htr_drud(uint64_t ind)
281{
282 Cube ret;
283
284 ret = antindex_cphtr(ind / BINOM8ON4);
285 ret.eposs = (ind % BINOM8ON4) * FACTORIAL4;
286
287 return ret;
288}
289
290static Cube
291antindex_htrfin(uint64_t ind)
292{
293 Cube ret;
294
295 ret = antindex_cornershtrfin(ind/(24*24*24));
296
297 ret.eposm = ind % 24;
298 ind /= 24;
299 ret.eposs = ind % 24;
300 ind /= 24;
301 ret.epose = ind % 24;
302
303 return ret;
304}
305
306bool
307check_centers(Cube cube)
308{
309 return cube.cpos == 0;
310}
311
312bool
313check_corners(Cube cube)
314{
315 return cube.cp == 0 && cube.coud == 0;
316}
317
318bool
319check_cp(Cube cube)
320{
321 return cube.cp == 0;
322}
323
324bool
325check_cphtr(Cube cube)
326{
327 return index_cphtr(cube) == 0;
328}
329
330bool
331check_cornershtr(Cube cube)
332{
333 return cube.coud == 0 && index_cphtr(cube) == 0;
334}
335
336bool
337check_coud(Cube cube)
338{
339 return cube.coud == 0;
340}
341
342bool
343check_drud(Cube cube)
344{
345 return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0;
346}
347
348bool
349check_htr(Cube cube)
350{
351 return check_cornershtr(cube) &&
352 cube.eofb == 0 && cube.eorl == 0 && cube.eoud == 0;
353}
354
355bool
356check_drudfin_noE(Cube cube)
357{
358 return cube.eposs == 0 && cube.eposm == 0 && cube.cp == 0;
359}
360
361bool
362check_eofb(Cube cube)
363{
364 return cube.eofb == 0;
365}
366
367bool
368check_eofbepos(Cube cube)
369{
370 return cube.eofb == 0 && cube.epose / 24 == 0;
371}
372
373bool
374check_epose(Cube cube)
375{
376 return cube.epose == 0;
377}
378
379bool
380check_epud(Cube cube)
381{
382 return cube.eposs == 0 && cube.eposm == 0;
383}
384
385bool
386check_ep(Cube cube)
387{
388 return cube.epose == 0 && cube.eposs == 0 && cube.eposm == 0;
389}
390
391bool
392check_khuge(Cube cube)
393{
394 return check_drud(cube) && cube.epose % 24 == 0;
395}
396
397bool
398check_nothing(Cube cube)
399{
400 return is_admissible(cube); /*TODO: maybe change?*/
401}
402
403static uint64_t
404index_eofb(Cube cube)
405{
406 return cube.eofb;
407}
408
409static uint64_t
410index_eofbepos(Cube cube)
411{
412 return (cube.epose / FACTORIAL4) * POW2TO11 + cube.eofb;
413}
414
415static uint64_t
416index_epud(Cube cube)
417{
418 uint64_t ret;
419 CubeArray *arr = new_cubearray(cube, pf_ep);
420
421 ret = perm_to_index(arr->ep, 8);
422 free_cubearray(arr, pf_ep);
423
424 return ret;
425}
426
427static uint64_t
428index_coud(Cube cube)
429{
430 return cube.coud;
431}
432
433static uint64_t
434index_corners(Cube cube)
435{
436 return cube.coud * FACTORIAL8 + cube.cp;
437}
438
439static uint64_t
440index_cp(Cube cube)
441{
442 return cube.cp;
443}
444
445static uint64_t
446index_cphtr(Cube cube)
447{
448 return cphtr_right_cosets[cube.cp];
449}
450
451static uint64_t
452index_cornershtr(Cube cube)
453{
454 return cube.coud * BINOM8ON4 * 6 + index_cphtr(cube);
455}
456
457static uint64_t
458index_cornershtrfin(Cube cube)
459{
460 return cornershtrfin_ind[cube.cp];
461}
462
463static uint64_t
464index_drud(Cube cube)
465{
466 uint64_t a, b, c;
467
468 a = cube.eofb;
469 b = cube.coud;
470 c = cube.epose / FACTORIAL4;
471
472 b *= POW2TO11;
473 c *= POW2TO11 * POW3TO7;
474
475 return a + b + c;
476}
477
478static uint64_t
479index_drud_eofb(Cube cube)
480{
481 return index_drud(cube) / POW2TO11;
482}
483
484static uint64_t
485index_htr_drud(Cube cube)
486{
487 return index_cphtr(cube) * BINOM8ON4 +
488 (cube.eposs / FACTORIAL4) % BINOM8ON4;
489}
490
491static uint64_t
492index_htrfin(Cube cube)
493{
494 uint64_t epe, eps, epm, cp, ep;
495
496 epe = cube.epose % 24;
497 eps = cube.eposs % 24;
498 epm = cube.eposm % 24;
499 ep = (epe * 24 + eps) *24 + epm;
500 cp = index_cornershtrfin(cube);
501
502 return cp * 24 * 24 * 24 + ep;
503}
504
505/* Init functions implementation *********************************************/
506
507/*
508 * There is certainly a better way to do this, but for now I just use
509 * a "graph coloring" algorithm to compute the left cosets, and I compose
510 * with every possible cp to get the right cosets (it is possible that I am
511 * mixing up left and right).
512 *
513 * For doing it better "Mathematically", we need 3 things:
514 * - Checking that cp separates the orbits (UFR,UBL,DFL,DBR) and the other
515 * This is easy and it is done in the commented function cphtr_cp().
516 * - Check that there is no ep/cp parity
517 * - Check that we are not in the "3c" case; this is the part I don't
518 * know how to do.
519 */
520static void
521init_cphtr_cosets()
522{
523 unsigned int i;
524 int c = 0, d = 0;
525
526 for (i = 0; i < FACTORIAL8; i++) {
527 cphtr_left_cosets[i] = -1;
528 cphtr_right_cosets[i] = -1;
529 }
530
531 /* First we compute left cosets with a bfs */
532 for (i = 0; i < FACTORIAL8; i++)
533 if (cphtr_left_cosets[i] == -1)
534 init_cphtr_left_cosets_bfs(i, c++);
535
536 /* Then we compute right cosets using compose() */
537 for (i = 0; i < FACTORIAL8; i++)
538 if (cphtr_right_cosets[i] == -1)
539 init_cphtr_right_cosets_color(i, d++);
540}
541
542static void
543init_cphtr_left_cosets_bfs(int i, int c)
544{
545 int j, jj, k, next[FACTORIAL8], next2[FACTORIAL8], n, n2;
546 Move moves[6] = {U2, D2, R2, L2, F2, B2};
547
548 n = 1;
549 next[0] = i;
550 cphtr_left_cosets[i] = c;
551
552 while (n != 0) {
553 for (j = 0, n2 = 0; j < n; j++) {
554 for (k = 0; k < 6; k++) {
555 /*jj = cp_mtable[moves[k]][next[j]];*/
556 /* TODO fix formatting */
557 jj = apply_move(moves[k], (Cube){.cp=next[j]}).cp;
558 if (cphtr_left_cosets[jj] == -1) {
559 cphtr_left_cosets[jj] = c;
560 next2[n2++] = jj;
561 }
562 }
563 }
564
565 for (j = 0; j < n2; j++)
566 next[j] = next2[j];
567 n = n2;
568 }
569}
570
571static void
572init_cphtr_right_cosets_color(int i, int d)
573{
574 int cp;
575 unsigned int j;
576
577 cphtr_right_rep[d] = i;
578 for (j = 0; j < FACTORIAL8; j++) {
579 if (cphtr_left_cosets[j] == 0) {
580 /* TODO: use antindexer, it's nicer */
581 cp = compose((Cube){.cp = i}, (Cube){.cp = j}).cp;
582 cphtr_right_cosets[cp] = d;
583 }
584 }
585}
586
587static void
588init_cornershtrfin()
589{
590 unsigned int i, j;
591 int n, c;
592 Move m;
593
594 for (i = 0; i < FACTORIAL8; i++)
595 cornershtrfin_ind[i] = -1;
596 cornershtrfin_ind[0] = 0;
597
598 /* 10-pass, I think 5 is enough, but just in case */
599 n = 1;
600 for (i = 0; i < 10; i++) {
601 for (j = 0; j < FACTORIAL8; j++) {
602 if (cornershtrfin_ind[j] == -1)
603 continue;
604 for (m = U; m < NMOVES; m++) {
605 if (moveset_htr(m)) {
606 c = apply_move(m, (Cube){.cp = j}).cp;
607 if (cornershtrfin_ind[c] == -1) {
608 cornershtrfin_ind[c] = n;
609 cornershtrfin_ant[n] = c;
610 n++;
611 }
612 }
613 }
614 }
615 }
616}
617
618void
619init_coord()
620{
621 static bool initialized = false;
622 if (initialized)
623 return;
624 initialized = true;
625
626 init_cphtr_cosets();
627 init_cornershtrfin();
628}
629
diff --git a/old/2021-11-10-beforeremovingchecker/coord.h b/old/2021-11-10-beforeremovingchecker/coord.h
new file mode 100644
index 0000000..81c1e9c
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/coord.h
@@ -0,0 +1,40 @@
1#ifndef COORD_H
2#define COORD_H
3
4#include "trans.h"
5
6extern Coordinate coord_eofb;
7extern Coordinate coord_eofbepos;
8extern Coordinate coord_coud;
9extern Coordinate coord_cp;
10extern Coordinate coord_cphtr;
11extern Coordinate coord_corners;
12extern Coordinate coord_cornershtr;
13extern Coordinate coord_cornershtrfin;
14extern Coordinate coord_epud;
15extern Coordinate coord_drud;
16extern Coordinate coord_drud_eofb;
17extern Coordinate coord_htr_drud;
18extern Coordinate coord_htrfin;
19
20bool check_centers(Cube cube);
21bool check_corners(Cube cube);
22bool check_cp(Cube cube);
23bool check_cphtr(Cube cube);
24bool check_cornershtr(Cube cube);
25bool check_coud(Cube cube);
26bool check_drud(Cube cube);
27bool check_htr(Cube cube);
28bool check_drudfin_noE(Cube cube);
29bool check_eofb(Cube cube);
30bool check_eofbepos(Cube cube);
31bool check_epose(Cube cube);
32bool check_ep(Cube cube);
33bool check_epud(Cube cube);
34bool check_khuge(Cube cube);
35bool check_nothing(Cube cube);
36
37void init_coord();
38
39#endif
40
diff --git a/old/2021-11-10-beforeremovingchecker/cube.c b/old/2021-11-10-beforeremovingchecker/cube.c
new file mode 100644
index 0000000..b621d7b
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/cube.c
@@ -0,0 +1,716 @@
1#include "cube.h"
2
3/* Local functions **********************************************************/
4
5static int array_ep_to_epos(int *ep, int *eps_solved);
6static int epos_from_arrays(int *epos, int *ep);
7
8/* Local functions implementation ********************************************/
9
10static int
11array_ep_to_epos(int *ep, int *ss)
12{
13 int epos[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
14 int eps[4];
15 int i, j, is;
16
17 for (i = 0, is = 0; i < 12; i++) {
18 for (j = 0; j < 4; j++) {
19 if (ep[i] == ss[j]) {
20 eps[is++] = j;
21 epos[i] = 1;
22 }
23 }
24 }
25
26 for (i = 0; i < 4; i++)
27 swap(&epos[ss[i]], &epos[i+8]);
28
29 return epos_from_arrays(epos, eps);
30}
31
32static int
33epos_from_arrays(int *epos, int *ep)
34{
35 return FACTORIAL4 * subset_to_index(epos,12,4) + perm_to_index(ep,4);
36}
37
38/* Public functions implementation *******************************************/
39
40Cube
41arrays_to_cube(CubeArray *arr, PieceFilter f)
42{
43 Cube ret = {0};
44
45 static int epe_solved[4] = {FR, FL, BL, BR};
46 static int eps_solved[4] = {UL, UR, DL, DR};
47 static int epm_solved[4] = {UF, UB, DF, DB};
48
49 if (f.epose)
50 ret.epose = array_ep_to_epos(arr->ep, epe_solved);
51 if (f.eposs)
52 ret.eposs = array_ep_to_epos(arr->ep, eps_solved);
53 if (f.eposm)
54 ret.eposm = array_ep_to_epos(arr->ep, epm_solved);
55 if (f.eofb)
56 ret.eofb = digit_array_to_int(arr->eofb, 11, 2);
57 if (f.eorl)
58 ret.eorl = digit_array_to_int(arr->eorl, 11, 2);
59 if (f.eoud)
60 ret.eoud = digit_array_to_int(arr->eoud, 11, 2);
61 if (f.cp)
62 ret.cp = perm_to_index(arr->cp, 8);
63 if (f.coud)
64 ret.coud = digit_array_to_int(arr->coud, 7, 3);
65 if (f.corl)
66 ret.corl = digit_array_to_int(arr->corl, 7, 3);
67 if (f.cofb)
68 ret.cofb = digit_array_to_int(arr->cofb, 7, 3);
69 if (f.cpos)
70 ret.cpos = perm_to_index(arr->cpos, 6);
71
72 return ret;
73}
74
75Cube
76compose_filtered(Cube c2, Cube c1, PieceFilter f)
77{
78 CubeArray *arr = new_cubearray(c2, f);
79 Cube ret;
80
81 ret = move_via_arrays(arr, c1, f);
82 free_cubearray(arr, f);
83
84 return ret;
85}
86
87void
88cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f)
89{
90 int i;
91
92 static int epe_solved[4] = {FR, FL, BL, BR};
93 static int eps_solved[4] = {UL, UR, DL, DR};
94 static int epm_solved[4] = {UF, UB, DF, DB};
95
96 if (f.epose || f.eposs || f.eposm)
97 for (i = 0; i < 12; i++)
98 arr->ep[i] = -1;
99
100 if (f.epose)
101 epos_to_partial_ep(cube.epose, arr->ep, epe_solved);
102 if (f.eposs)
103 epos_to_partial_ep(cube.eposs, arr->ep, eps_solved);
104 if (f.eposm)
105 epos_to_partial_ep(cube.eposm, arr->ep, epm_solved);
106 if (f.eofb)
107 int_to_sum_zero_array(cube.eofb, 2, 12, arr->eofb);
108 if (f.eorl)
109 int_to_sum_zero_array(cube.eorl, 2, 12, arr->eorl);
110 if (f.eoud)
111 int_to_sum_zero_array(cube.eoud, 2, 12, arr->eoud);
112 if (f.cp)
113 index_to_perm(cube.cp, 8, arr->cp);
114 if (f.coud)
115 int_to_sum_zero_array(cube.coud, 3, 8, arr->coud);
116 if (f.corl)
117 int_to_sum_zero_array(cube.corl, 3, 8, arr->corl);
118 if (f.cofb)
119 int_to_sum_zero_array(cube.cofb, 3, 8, arr->cofb);
120 if (f.cpos)
121 index_to_perm(cube.cpos, 6, arr->cpos);
122}
123
124void
125epos_to_partial_ep(int epos, int *ep, int *ss)
126{
127 int i, is, eposs[12], eps[4];
128
129 index_to_perm(epos % FACTORIAL4, 4, eps);
130 index_to_subset(epos / FACTORIAL4, 12, 4, eposs);
131
132 for (i = 0; i < 4; i++)
133 swap(&eposs[ss[i]], &eposs[i+8]);
134
135 for (i = 0, is = 0; i < 12; i++)
136 if (eposs[i])
137 ep[i] = ss[eps[is++]];
138}
139
140void
141free_cubearray(CubeArray *arr, PieceFilter f)
142{
143 if (f.epose || f.eposs || f.eposm)
144 free(arr->ep);
145 if (f.eofb)
146 free(arr->eofb);
147 if (f.eorl)
148 free(arr->eorl);
149 if (f.eoud)
150 free(arr->eoud);
151 if (f.cp)
152 free(arr->cp);
153 if (f.coud)
154 free(arr->coud);
155 if (f.corl)
156 free(arr->corl);
157 if (f.cofb)
158 free(arr->cofb);
159 if (f.cpos)
160 free(arr->cpos);
161
162 free(arr);
163}
164
165Cube
166move_via_arrays(CubeArray *arr, Cube c, PieceFilter f)
167{
168 CubeArray *arrc = new_cubearray(c, f);
169 Cube ret;
170
171 if (f.epose || f.eposs || f.eposm)
172 apply_permutation(arr->ep, arrc->ep, 12);
173
174 if (f.eofb) {
175 apply_permutation(arr->ep, arrc->eofb, 12);
176 sum_arrays_mod(arr->eofb, arrc->eofb, 12, 2);
177 }
178
179 if (f.eorl) {
180 apply_permutation(arr->ep, arrc->eorl, 12);
181 sum_arrays_mod(arr->eorl, arrc->eorl, 12, 2);
182 }
183
184 if (f.eoud) {
185 apply_permutation(arr->ep, arrc->eoud, 12);
186 sum_arrays_mod(arr->eoud, arrc->eoud, 12, 2);
187 }
188
189 if (f.cp)
190 apply_permutation(arr->cp, arrc->cp, 8);
191
192 if (f.coud) {
193 apply_permutation(arr->cp, arrc->coud, 8);
194 sum_arrays_mod(arr->coud, arrc->coud, 8, 3);
195 }
196
197 if (f.corl) {
198 apply_permutation(arr->cp, arrc->corl, 8);
199 sum_arrays_mod(arr->corl, arrc->corl, 8, 3);
200 }
201
202 if (f.cofb) {
203 apply_permutation(arr->cp, arrc->cofb, 8);
204 sum_arrays_mod(arr->cofb, arrc->cofb, 8, 3);
205 }
206
207 if (f.cpos)
208 apply_permutation(arr->cpos, arrc->cpos, 6);
209
210 ret = arrays_to_cube(arrc, f);
211 free_cubearray(arrc, f);
212
213 return ret;
214}
215
216CubeArray *
217new_cubearray(Cube cube, PieceFilter f)
218{
219 CubeArray *arr = malloc(sizeof(CubeArray));
220
221 if (f.epose || f.eposs || f.eposm)
222 arr->ep = malloc(12 * sizeof(int));
223 if (f.eofb)
224 arr->eofb = malloc(12 * sizeof(int));
225 if (f.eorl)
226 arr->eorl = malloc(12 * sizeof(int));
227 if (f.eoud)
228 arr->eoud = malloc(12 * sizeof(int));
229 if (f.cp)
230 arr->cp = malloc(8 * sizeof(int));
231 if (f.coud)
232 arr->coud = malloc(8 * sizeof(int));
233 if (f.corl)
234 arr->corl = malloc(8 * sizeof(int));
235 if (f.cofb)
236 arr->cofb = malloc(8 * sizeof(int));
237 if (f.cpos)
238 arr->cpos = malloc(6 * sizeof(int));
239
240 cube_to_arrays(cube, arr, f);
241
242 return arr;
243}
244
245
246/* TODO: consider if this is good here or better in coord.c
247 in any case it is used in transformation init at the moment */
248Cube
249admissible_ep(Cube cube, PieceFilter f)
250{
251 CubeArray *arr = new_cubearray(cube, f);
252 Cube ret;
253 bool used[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
254 int i, j;
255
256 for (i = 0; i < 12; i++)
257 if (arr->ep[i] != -1)
258 used[arr->ep[i]] = true;
259
260 for (i = 0, j = 0; i < 12; i++) {
261 for ( ; j < 11 && used[j]; j++);
262 if (arr->ep[i] == -1)
263 arr->ep[i] = j++;
264 }
265
266 ret = arrays_to_cube(arr, pf_ep);
267 free_cubearray(arr, f);
268
269 return ret;
270}
271
272Cube
273compose(Cube c2, Cube c1)
274{
275 return compose_filtered(c2, c1, pf_all);
276}
277
278int
279edge_slice(Edge e) {
280 if (e < 0 || e > 11)
281 return -1;
282
283 if (e == FR || e == FL || e == BL || e == BR)
284 return 0;
285 if (e == UR || e == UL || e == DR || e == DL)
286 return 1;
287
288 return 2;
289}
290
291bool
292equal(Cube c1, Cube c2)
293{
294 return c1.eofb == c2.eofb &&
295 c1.epose == c2.epose &&
296 c1.eposs == c2.eposs &&
297 c1.eposm == c2.eposm &&
298 c1.coud == c2.coud &&
299 c1.cp == c2.cp &&
300 c1.cpos == c2.cpos;
301}
302
303Cube
304inverse_cube(Cube cube)
305{
306 CubeArray *arr = new_cubearray(cube, pf_all);
307 CubeArray *inv = new_cubearray((Cube){0}, pf_all);
308 Cube ret;
309 int i;
310
311 for (i = 0; i < 12; i++) {
312 inv->ep[arr->ep[i]] = i;
313 inv->eofb[arr->ep[i]] = arr->eofb[i];
314 inv->eorl[arr->ep[i]] = arr->eorl[i];
315 inv->eoud[arr->ep[i]] = arr->eoud[i];
316 }
317
318 for (i = 0; i < 8; i++) {
319 inv->cp[arr->cp[i]] = i;
320 inv->coud[arr->cp[i]] = (3 - arr->coud[i]) % 3;
321 inv->corl[arr->cp[i]] = (3 - arr->corl[i]) % 3;
322 inv->cofb[arr->cp[i]] = (3 - arr->cofb[i]) % 3;
323 }
324
325 for (int i = 0; i < 6; i++)
326 inv->cpos[arr->cpos[i]] = i;
327
328 ret = arrays_to_cube(inv, pf_all);
329 free_cubearray(arr, pf_all);
330 free_cubearray(inv, pf_all);
331
332 return ret;
333}
334
335bool
336is_admissible(Cube cube)
337{
338 /* TODO: this should check consistency of different orientations */
339 /* TODO: check that centers are opposite and admissible */
340
341 CubeArray *a = new_cubearray(cube, pf_all);
342 int parity;
343 bool perm;
344
345 perm = is_perm(a->ep, 12) &&
346 is_perm(a->cp, 8) &&
347 is_perm(a->cpos, 6);
348 parity = perm_sign(a->ep, 12) +
349 perm_sign(a->cp, 8) +
350 perm_sign(a->cpos, 6);
351
352 return perm && parity % 2 == 0;
353}
354
355bool
356is_solved(Cube cube)
357{
358 /* TODO: move somewhere else, like in solve.c
359 int i;
360 if (reorient) {
361 for (i = 0; i < NROTATIONS; i++)
362 if (is_solved(apply_alg(rotation_algs[i], cube),false))
363 return true;
364 return false;
365 } else {
366 return equal(cube, (Cube){0});
367 }
368 */
369
370 return equal(cube, (Cube){0});
371}
372
373bool
374is_solved_block(Cube cube, Block block)
375{
376 int i;
377
378 for (i = 0; i < 12; i++)
379 if (block.edge[i] && !is_solved_edge(cube, i))
380 return false;
381 for (i = 0; i < 8; i++)
382 if (block.corner[i] && !is_solved_corner(cube, i))
383 return false;
384 for (i = 0; i < 6; i++)
385 if (block.center[i] && !is_solved_center(cube, i))
386 return false;
387
388 return true;
389}
390
391bool
392is_solved_center(Cube cube, Center c)
393{
394 return what_center_at(cube, c) == c;
395}
396
397bool
398is_solved_corner(Cube cube, Corner c)
399{
400 return what_corner_at(cube, c) == c &&
401 what_orientation_corner(cube.coud, c);
402}
403
404bool
405is_solved_edge(Cube cube, Edge e)
406{
407 return what_edge_at(cube, e) == e &&
408 what_orientation_edge(cube.eofb, e);
409}
410
411int
412piece_orientation(Cube cube, int piece, char *orientation)
413{
414 int arr[12], n, b, x;
415
416 if (!strcmp(orientation, "eofb")) {
417 x = cube.eofb;
418 n = 12;
419 b = 2;
420 } else if (!strcmp(orientation, "eorl")) {
421 x = cube.eorl;
422 n = 12;
423 b = 2;
424 } else if (!strcmp(orientation, "eoud")) {
425 x = cube.eoud;
426 n = 12;
427 b = 2;
428 } else if (!strcmp(orientation, "coud")) {
429 x = cube.coud;
430 n = 8;
431 b = 3;
432 } else if (!strcmp(orientation, "corl")) {
433 x = cube.corl;
434 n = 8;
435 b = 3;
436 } else if (!strcmp(orientation, "cofb")) {
437 x = cube.cofb;
438 n = 8;
439 b = 3;
440 } else {
441 return -1;
442 }
443
444 int_to_sum_zero_array(x, b, n, arr);
445 if (piece < n)
446 return arr[piece];
447
448 return -1;
449}
450
451void
452print_cube(Cube cube)
453{
454 static char edge_string[12][7] = {
455 [UF] = "UF", [UL] = "UL", [UB] = "UB", [UR] = "UR",
456 [DF] = "DF", [DL] = "DL", [DB] = "DB", [DR] = "DR",
457 [FR] = "FR", [FL] = "FL", [BL] = "BL", [BR] = "BR"
458 };
459
460 static char corner_string[8][7] = {
461 [UFR] = "UFR", [UFL] = "UFL", [UBL] = "UBL", [UBR] = "UBR",
462 [DFR] = "DFR", [DFL] = "DFL", [DBL] = "DBL", [DBR] = "DBR"
463 };
464
465 static char center_string[6][7] = {
466 [U_center] = "U", [D_center] = "D",
467 [R_center] = "R", [L_center] = "L",
468 [F_center] = "F", [B_center] = "B"
469 };
470
471 for (int i = 0; i < 12; i++)
472 printf(" %s ", edge_string[what_edge_at(cube, i)]);
473 printf("\n");
474
475 for (int i = 0; i < 12; i++)
476 printf(" %d ", what_orientation_edge(cube.eofb, i));
477 printf("\n");
478
479 for (int i = 0; i < 8; i++)
480 printf("%s ", corner_string[what_corner_at(cube, i)]);
481 printf("\n");
482
483 for (int i = 0; i < 8; i++)
484 printf(" %d ", what_orientation_corner(cube.coud, i));
485 printf("\n");
486
487 for (int i = 0; i < 6; i++)
488 printf(" %s ", center_string[what_center_at(cube, i)]);
489 printf("\n");
490}
491
492Cube
493random_cube()
494{
495 CubeArray *arr = new_cubearray((Cube){0}, pf_4val);
496 Cube ret;
497 int ep, cp, eo, co;
498
499 ep = rand() % FACTORIAL12;
500 cp = rand() % FACTORIAL8;
501 eo = rand() % POW2TO11;
502 co = rand() % POW3TO7;
503
504 index_to_perm(ep, 12, arr->ep);
505 index_to_perm(cp, 8, arr->cp);
506 int_to_sum_zero_array(eo, 2, 12, arr->eofb);
507 int_to_sum_zero_array(co, 3, 8, arr->coud);
508
509 if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8))
510 swap(&(arr->ep[0]), &(arr->ep[1]));
511
512 ret = arrays_to_cube(arr, pf_4val);
513 free_cubearray(arr, pf_4val);
514
515 return ret;
516}
517
518Center
519what_center_at(Cube cube, Center c)
520{
521 static bool initialized = false;
522 static Center aux[FACTORIAL6][6];
523 static int i;
524 static unsigned int ui;
525 static CubeArray *arr;
526
527 if (!initialized) {
528 for (ui = 0; ui < FACTORIAL6; ui++) {
529 arr = new_cubearray((Cube){.cpos = ui}, pf_cpos);
530 for (i = 0; i < 6; i++)
531 aux[ui][i] = arr->cpos[i];
532 free_cubearray(arr, pf_cpos);
533 }
534
535 initialized = true;
536 }
537
538 return aux[cube.cpos][c];
539}
540
541Corner
542what_corner_at(Cube cube, Corner c)
543{
544 static bool initialized = false;
545 static Corner aux[FACTORIAL8][8];
546 static int i;
547 static unsigned int ui;
548 static CubeArray *arr;
549
550 if (!initialized) {
551 for (ui = 0; ui < FACTORIAL8; ui++) {
552 arr = new_cubearray((Cube){.cp = ui}, pf_cp);
553 for (i = 0; i < 8; i++)
554 aux[ui][i] = arr->cp[i];
555 free_cubearray(arr, pf_cp);
556 }
557
558 initialized = true;
559 }
560
561 return aux[cube.cp][c];
562}
563
564Edge
565what_edge_at(Cube cube, Edge e)
566{
567 Edge ret;
568 CubeArray *arr = new_cubearray(cube, pf_ep);
569
570 ret = arr->ep[e];
571
572 free_cubearray(arr, pf_ep);
573 return ret;
574}
575
576int
577what_orientation_corner(int co, Corner c)
578{
579 static bool initialized = false;
580 static int auxlast[POW3TO7];
581 static int auxarr[8];
582 static unsigned int ui;
583
584 if (!initialized) {
585 for (ui = 0; ui < POW3TO7; ui++) {
586 int_to_sum_zero_array(ui, 3, 8, auxarr);
587 auxlast[ui] = auxarr[7];
588 }
589
590 initialized = true;
591 }
592
593 if (c < 7)
594 return (co / powint(3, c)) % 3;
595 else
596 return auxlast[co];
597}
598
599int
600what_orientation_edge(int eo, Edge e)
601{
602 static bool initialized = false;
603 static int auxlast[POW2TO11];
604 static int auxarr[12];
605 static unsigned int ui;
606
607 if (!initialized) {
608 for (ui = 0; ui < POW2TO11; ui++) {
609 int_to_sum_zero_array(ui, 2, 12, auxarr);
610 auxlast[ui] = auxarr[11];
611 }
612
613 initialized = true;
614 }
615
616 if (e < 11)
617 return (eo & (1 << e)) ? 1 : 0;
618 else
619 return auxlast[eo];
620}
621
622Center
623where_is_center(Cube cube, Center c)
624{
625 static bool initialized = false;
626 static Center aux[FACTORIAL6][6];
627 static int i;
628 static unsigned int ui;
629 static CubeArray *arr;
630
631 if (!initialized) {
632 for (ui = 0; ui < FACTORIAL6; ui++) {
633 arr = new_cubearray((Cube){.cpos = ui}, pf_cpos);
634 for (i = 0; i < 6; i++)
635 aux[ui][arr->cpos[i]] = i;
636 free_cubearray(arr, pf_cpos);
637 }
638
639 initialized = true;
640 }
641
642 return aux[cube.cpos][c];
643}
644
645Corner
646where_is_corner(Cube cube, Corner c)
647{
648 static bool initialized = false;
649 static Corner aux[FACTORIAL8][8];
650 static int i;
651 static unsigned int ui;
652 static CubeArray *arr;
653
654 if (!initialized) {
655 for (ui = 0; ui < FACTORIAL8; ui++) {
656 arr = new_cubearray((Cube){.cp = ui}, pf_cp);
657 for (i = 0; i < 8; i++)
658 aux[ui][arr->cp[i]] = i;
659 free_cubearray(arr, pf_cp);
660 }
661
662 initialized = true;
663 }
664 return aux[cube.cp][c];
665}
666
667Edge
668where_is_edge(Cube cube, Edge e)
669{
670 /* TODO: when I wrote this code I forgot to add the final
671 part, and now I can't remember how it was supposed to
672 work (i.e. how to recover the location of the edge
673 from these tables. I think it is either very easy or
674 wrong, in any case it is not a priority now.
675 Future Seba can deal with it.
676
677 static bool initialized = false;
678 static Edge aux[3][FACTORIAL12/FACTORIAL8][12];
679 static int i;
680 static unsigned int ui;
681 static CubeArray *arr;
682
683 if (!initialized) {
684 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
685 arr = new_cubearray((Cube){.epose = ui}, pf_e);
686 for (i = 0; i < 12; i++)
687 if (edge_slice(arr->ep[i]) == 0)
688 aux[0][ui][arr->ep[i]] = i;
689 free_cubearray(arr, pf_e);
690
691 arr = new_cubearray((Cube){.eposs = ui}, pf_s);
692 for (i = 0; i < 12; i++)
693 if (edge_slice(arr->ep[i]) == 1)
694 aux[1][ui][arr->ep[i]] = i;
695 free_cubearray(arr, pf_s);
696
697 arr = new_cubearray((Cube){.eposm = ui}, pf_m);
698 for (i = 0; i < 12; i++)
699 if (edge_slice(arr->ep[i]) == 2)
700 aux[2][ui][arr->ep[i]] = i;
701 free_cubearray(arr, pf_m);
702 }
703
704 initialized = true;
705 }
706 */
707
708 int i;
709 CubeArray *arr = new_cubearray(cube, pf_ep);
710
711 for (i = 0; i < 12; i++)
712 if ((Edge)arr->ep[i] == e)
713 return i;
714
715 return -1;
716}
diff --git a/old/2021-11-10-beforeremovingchecker/cube.h b/old/2021-11-10-beforeremovingchecker/cube.h
new file mode 100644
index 0000000..98657ab
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/cube.h
@@ -0,0 +1,40 @@
1#ifndef CUBE_H
2#define CUBE_H
3
4#include <stdio.h>
5#include <time.h>
6
7#include "pf.h"
8#include "utils.h"
9
10Cube admissible_ep(Cube cube, PieceFilter f); /* TODO: move? */
11Cube arrays_to_cube(CubeArray *arr, PieceFilter f); /* TODO: remove */
12Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */
13Cube compose_filtered(Cube c2, Cube c1, PieceFilter f);
14void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f);
15int edge_slice(Edge e); /* E=0, S=1, M=2 */
16bool equal(Cube c1, Cube c2);
17Cube inverse_cube(Cube cube);
18bool is_admissible(Cube cube);
19bool is_solved(Cube cube);
20bool block_solved(Cube cube, Block); /*TODO: rename to is_solved_block()*/
21bool is_solved_center(Cube cube, Center c);
22bool is_solved_corner(Cube cube, Corner c);
23bool is_solved_edge(Cube cube, Edge e);
24void epos_to_partial_ep(int epos, int *ep, int *ss);
25void free_cubearray(CubeArray *arr, PieceFilter f); /* TODO: remove */
26Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf);
27CubeArray * new_cubearray(Cube cube, PieceFilter f); /* TODO: remove */
28void print_cube(Cube cube);
29Cube random_cube();
30Center what_center_at(Cube cube, Center c);
31Corner what_corner_at(Cube cube, Corner c);
32Edge what_edge_at(Cube cube, Edge e);
33int what_orientation_corner(int co, Corner c);
34int what_orientation_edge(int eo, Edge e);
35Center where_is_center(Cube cube, Center c);
36Corner where_is_corner(Cube cube, Corner c);
37Edge where_is_edge(Cube cube, Edge e);
38
39#endif
40
diff --git a/old/2021-11-10-beforeremovingchecker/cubetypes.h b/old/2021-11-10-beforeremovingchecker/cubetypes.h
new file mode 100644
index 0000000..38a6f8d
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/cubetypes.h
@@ -0,0 +1,298 @@
1#ifndef CUBETYPES_H
2#define CUBETYPES_H
3
4#include <stdbool.h>
5#include <stdint.h>
6
7#define NMOVES 55 /* Actually 55, but one is NULLMOVE */
8#define NTRANS 48
9#define NROTATIONS 24
10
11
12/* Typedefs ******************************************************************/
13
14typedef enum center Center;
15typedef enum corner Corner;
16typedef enum edge Edge;
17typedef enum move Move;
18typedef enum trans Trans;
19
20typedef struct alg Alg;
21typedef struct alglist AlgList;
22typedef struct alglistnode AlgListNode;
23typedef struct block Block;
24typedef struct command Command;
25typedef struct commandargs CommandArgs;
26typedef struct coordinate Coordinate;
27typedef struct cube Cube;
28typedef struct cubearray CubeArray;
29typedef struct cubetarget CubeTarget;
30typedef struct dfsdata DfsData;
31typedef struct piecefilter PieceFilter;
32typedef struct prunedata PruneData;
33typedef struct solveoptions SolveOptions;
34typedef struct step Step;
35typedef struct symdata SymData;
36
37typedef Cube (*AntiIndexer) (uint64_t);
38typedef bool (*Checker) (Cube);
39typedef int (*Estimator) (CubeTarget);
40typedef bool (*Validator) (Alg *);
41typedef void (*Exec) (CommandArgs *);
42typedef uint64_t (*Indexer) (Cube);
43typedef bool (*Moveset) (Move);
44typedef CommandArgs * (*ArgParser) (int, char **);
45typedef Trans (*TransDetector) (Cube);
46
47
48/* Enums *********************************************************************/
49
50enum
51center
52{
53 U_center, D_center,
54 R_center, L_center,
55 F_center, B_center
56};
57
58enum
59corner
60{
61 UFR, UFL, UBL, UBR,
62 DFR, DFL, DBL, DBR
63};
64
65enum
66edge
67{
68 UF, UL, UB, UR,
69 DF, DL, DB, DR,
70 FR, FL, BL, BR
71};
72
73enum
74move
75{
76 NULLMOVE,
77 U, U2, U3, D, D2, D3,
78 R, R2, R3, L, L2, L3,
79 F, F2, F3, B, B2, B3,
80 Uw, Uw2, Uw3, Dw, Dw2, Dw3,
81 Rw, Rw2, Rw3, Lw, Lw2, Lw3,
82 Fw, Fw2, Fw3, Bw, Bw2, Bw3,
83 M, M2, M3,
84 S, S2, S3,
85 E, E2, E3,
86 x, x2, x3,
87 y, y2, y3,
88 z, z2, z3,
89};
90
91enum
92trans
93{
94 uf, ur, ub, ul,
95 df, dr, db, dl,
96 rf, rd, rb, ru,
97 lf, ld, lb, lu,
98 fu, fr, fd, fl,
99 bu, br, bd, bl,
100 uf_mirror, ur_mirror, ub_mirror, ul_mirror,
101 df_mirror, dr_mirror, db_mirror, dl_mirror,
102 rf_mirror, rd_mirror, rb_mirror, ru_mirror,
103 lf_mirror, ld_mirror, lb_mirror, lu_mirror,
104 fu_mirror, fr_mirror, fd_mirror, fl_mirror,
105 bu_mirror, br_mirror, bd_mirror, bl_mirror,
106};
107
108
109/* Structs *******************************************************************/
110
111struct
112alg
113{
114 Move * move;
115 bool * inv;
116 int len;
117 int allocated;
118};
119
120struct
121alglist
122{
123 AlgListNode * first;
124 AlgListNode * last;
125 int len;
126};
127
128struct
129alglistnode
130{
131 Alg * alg;
132 AlgListNode * next;
133};
134
135struct
136block
137{
138 bool edge[12];
139 bool corner[8];
140 bool center[6];
141};
142
143struct
144command
145{
146 /* TODO: more stuff to add? maybe complete help? */
147 /* Maybe add list of options */
148 char * name;
149 char * usage;
150 char * description;
151 ArgParser parse_args;
152 Exec exec;
153};
154
155struct
156commandargs
157{
158 bool success;
159 Alg * scramble;
160 SolveOptions * opts;
161 Step * step;
162 Command * command; /* For help */
163};
164
165struct
166coordinate
167{
168 Indexer index;
169 AntiIndexer cube;
170 Checker check;
171 uint64_t max;
172 int ntrans;
173 Trans * trans;
174};
175
176struct
177cube
178{
179 int epose;
180 int eposs;
181 int eposm;
182 int eofb;
183 int eorl;
184 int eoud;
185 int cp;
186 int coud;
187 int cofb;
188 int corl;
189 int cpos;
190};
191
192struct
193cubearray
194{
195 int * ep;
196 int * eofb;
197 int * eorl;
198 int * eoud;
199 int * cp;
200 int * coud;
201 int * corl;
202 int * cofb;
203 int * cpos;
204};
205
206struct
207cubetarget
208{
209 Cube cube;
210 int target;
211};
212
213struct
214dfsdata
215{
216 int d;
217 int m;
218 int lb;
219 bool niss;
220 Move last1;
221 Move last2;
222 AlgList * sols;
223 Alg * current_alg;
224 Move sorted_moves[NMOVES];
225 int move_position[NMOVES];
226};
227
228struct
229piecefilter
230{
231 bool epose;
232 bool eposs;
233 bool eposm;
234 bool eofb;
235 bool eorl;
236 bool eoud;
237 bool cp;
238 bool coud;
239 bool cofb;
240 bool corl;
241 bool cpos;
242};
243
244struct
245prunedata
246{
247 char * filename;
248 uint8_t * ptable;
249 bool generated;
250 uint64_t n;
251 Coordinate * coord;
252 Moveset moveset;
253};
254
255struct
256solveoptions
257{
258 /* TODO: add option to list *all* solutions satisfying other
259 constraints (min/max moves and optimality) */
260 int min_moves;
261 int max_moves;
262 int max_solutions;
263 bool optimal_only;
264 bool can_niss;
265 bool feedback; /* TODO: rename with "verbose" */
266 bool all;
267 bool print_number;
268};
269
270struct
271step
272{
273 char * shortname;
274 char * name;
275 Estimator estimate;
276 Checker ready;
277 char * ready_msg;
278 Validator is_valid;
279 Moveset moveset;
280 Trans pre_trans;
281 TransDetector detect;
282};
283
284struct
285symdata
286{
287 char * filename;
288 bool generated;
289 Coordinate * coord;
290 Coordinate * sym_coord;
291 int ntrans;
292 Trans * trans;
293 uint64_t * class;
294 Cube * rep;
295 Trans * transtorep;
296};
297
298#endif
diff --git a/old/2021-11-10-beforeremovingchecker/env.c b/old/2021-11-10-beforeremovingchecker/env.c
new file mode 100644
index 0000000..d13642f
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/env.c
@@ -0,0 +1,45 @@
1#include "env.h"
2
3bool initialized_env = false;
4char *tabledir;
5
6void
7init_env()
8{
9 char *nissydata = getenv("NISSYDATA");
10 char *localdata = getenv("XDG_DATA_HOME");
11 char *home = getenv("HOME");
12 bool read, write;
13
14 if (initialized_env)
15 return;
16
17 if (nissydata != NULL) {
18 tabledir = malloc(strlen(nissydata) * sizeof(char) + 20);
19 strcpy(tabledir, nissydata);
20 } else if (localdata != NULL) {
21 tabledir = malloc(strlen(localdata) * sizeof(char) + 20);
22 strcpy(tabledir, localdata);
23 strcat(tabledir, "/nissy");
24 } else if (home != NULL) {
25 tabledir = malloc(strlen(home) * sizeof(char) + 20);
26 strcpy(tabledir, home);
27 strcat(tabledir, "/.nissy");
28 }
29
30 mkdir(tabledir, 0777);
31 strcat(tabledir, "/tables");
32 mkdir(tabledir, 0777);
33
34 read = !access(tabledir, R_OK);
35 write = !access(tabledir, W_OK);
36
37 if (!read) {
38 fprintf(stderr, "Table files cannot be read.\n");
39 } else if (!write) {
40 fprintf(stderr, "Data directory not writable: ");
41 fprintf(stderr, "tables can be loaded, but not saved.\n");
42 }
43
44 initialized_env = true;
45}
diff --git a/old/2021-11-10-beforeremovingchecker/env.h b/old/2021-11-10-beforeremovingchecker/env.h
new file mode 100644
index 0000000..871a9c1
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/env.h
@@ -0,0 +1,15 @@
1#ifndef ENV_H
2#define ENV_H
3
4#include <stdbool.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8#include <unistd.h>
9#include <sys/stat.h>
10
11extern char *tabledir;
12
13void init_env();
14
15#endif
diff --git a/old/2021-11-10-beforeremovingchecker/moves.c b/old/2021-11-10-beforeremovingchecker/moves.c
new file mode 100644
index 0000000..5ba17ca
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/moves.c
@@ -0,0 +1,474 @@
1#include "moves.h"
2
3/* Local functions ***********************************************************/
4
5static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f);
6static bool read_mtables_file();
7static bool write_mtables_file();
8
9/* Tables and other data *****************************************************/
10
11/* Every move is translated to a an <U, x, y> alg before filling the
12 transition tables, see init_moves() */
13
14static int edge_cycle[NMOVES][12] =
15{
16 [U] = { UR, UF, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR },
17 [x] = { DF, FL, UF, FR, DB, BL, UB, BR, DR, DL, UL, UR },
18 [y] = { UR, UF, UL, UB, DR, DF, DL, DB, BR, FR, FL, BL }
19};
20
21static int corner_cycle[NMOVES][8] =
22{
23 [U] = { UBR, UFR, UFL, UBL, DFR, DFL, DBL, DBR },
24 [x] = { DFR, DFL, UFL, UFR, DBR, DBL, UBL, UBR },
25 [y] = { UBR, UFR, UFL, UBL, DBR, DFR, DFL, DBL }
26};
27
28static int center_cycle[NMOVES][6] =
29{
30 [x] = { F_center, B_center, R_center, L_center, D_center, U_center },
31 [y] = { U_center, D_center, B_center, F_center, R_center, L_center }
32};
33
34static int eofb_flipped[NMOVES][12] = {
35 [x] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 },
36 [y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 }
37};
38
39static int eorl_flipped[NMOVES][12] = {
40 [x] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
41 [y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 }
42};
43
44static int eoud_flipped[NMOVES][12] = {
45 [U] = { [UF] = 1, [UL] = 1, [UB] = 1, [UR] = 1 },
46 [x] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 },
47 [y] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
48};
49
50static int coud_flipped[NMOVES][8] = {
51 [x] = {
52 [UFR] = 2, [UBR] = 1, [UFL] = 1, [UBL] = 2,
53 [DBR] = 2, [DFR] = 1, [DBL] = 1, [DFL] = 2
54 }
55};
56
57static int corl_flipped[NMOVES][8] = {
58 [U] = { [UFR] = 1, [UBR] = 2, [UBL] = 1, [UFL] = 2 },
59 [y] = {
60 [UFR] = 1, [UBR] = 2, [UBL] = 1, [UFL] = 2,
61 [DFR] = 2, [DBR] = 1, [DBL] = 2, [DFL] = 1
62 }
63};
64
65static int cofb_flipped[NMOVES][8] = {
66 [U] = { [UFR] = 2, [UBR] = 1, [UBL] = 2, [UFL] = 1 },
67 [x] = {
68 [UFR] = 1, [UBR] = 2, [UBL] = 1, [UFL] = 2,
69 [DFR] = 2, [DBR] = 1, [DBL] = 2, [DFL] = 1
70 },
71 [y] = {
72 [UFR] = 2, [UBR] = 1, [UBL] = 2, [UFL] = 1,
73 [DFR] = 1, [DBR] = 2, [DBL] = 1, [DFL] = 2
74 }
75};
76
77static char equiv_alg_string[100][NMOVES] = {
78 [NULLMOVE] = "",
79
80 [U] = " U ",
81 [U2] = " UU ",
82 [U3] = " UUU ",
83 [D] = " xx U xx ",
84 [D2] = " xx UU xx ",
85 [D3] = " xx UUU xx ",
86 [R] = " yx U xxxyyy ",
87 [R2] = " yx UU xxxyyy ",
88 [R3] = " yx UUU xxxyyy ",
89 [L] = " yyyx U xxxy ",
90 [L2] = " yyyx UU xxxy ",
91 [L3] = " yyyx UUU xxxy ",
92 [F] = " x U xxx ",
93 [F2] = " x UU xxx ",
94 [F3] = " x UUU xxx ",
95 [B] = " xxx U x ",
96 [B2] = " xxx UU x ",
97 [B3] = " xxx UUU x ",
98
99 [Uw] = " xx U xx y ",
100 [Uw2] = " xx UU xx yy ",
101 [Uw3] = " xx UUU xx yyy ",
102 [Dw] = " U yyy ",
103 [Dw2] = " UU yy ",
104 [Dw3] = " UUU y ",
105 [Rw] = " yyyx U xxxy x ",
106 [Rw2] = " yyyx UU xxxy xx ",
107 [Rw3] = " yyyx UUU xxxy xxx ",
108 [Lw] = " yx U xxxyyy xxx ",
109 [Lw2] = " yx UU xxxyyy xx ",
110 [Lw3] = " yx UUU xxxyyy x ",
111 [Fw] = " xxx U x yxxxyyy ",
112 [Fw2] = " xxx UU x yxxyyy ",
113 [Fw3] = " xxx UUU x yxyyy ",
114 [Bw] = " x U xxx yxyyy ",
115 [Bw2] = " x UU xxx yxxyyy ",
116 [Bw3] = " x UUU xxx yxxxyyy ",
117
118 [M] = " yx U xx UUU yxyyy ",
119 [M2] = " yx UU xx UU xxxy ",
120 [M3] = " yx UUU xx U yxxxy ",
121 [S] = " x UUU xx U yyyx ",
122 [S2] = " x UU xx UU yyx ",
123 [S3] = " x U xx UUU yx ",
124 [E] = " U xx UUU xxyyy ",
125 [E2] = " UU xx UU xxyy ",
126 [E3] = " UUU xx U xxy ",
127
128 [x] = " x ",
129 [x2] = " xx ",
130 [x3] = " xxx ",
131 [y] = " y ",
132 [y2] = " yy ",
133 [y3] = " yyy ",
134 [z] = " yyy x y ",
135 [z2] = " yy xx ",
136 [z3] = " y x yyy "
137};
138
139/* Transition tables, to be loaded up at the beginning */
140static int epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
141static int eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
142static int eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
143static int eofb_mtable[NMOVES][POW2TO11];
144static int eorl_mtable[NMOVES][POW2TO11];
145static int eoud_mtable[NMOVES][POW2TO11];
146static int cp_mtable[NMOVES][FACTORIAL8];
147static int coud_mtable[NMOVES][POW3TO7];
148static int cofb_mtable[NMOVES][POW3TO7];
149static int corl_mtable[NMOVES][POW3TO7];
150static int cpos_mtable[NMOVES][FACTORIAL6];
151
152
153/* Local functions implementation ********************************************/
154
155static Cube
156apply_move_cubearray(Move m, Cube cube, PieceFilter f)
157{
158 /*init_moves();*/
159
160 CubeArray m_arr = {
161 edge_cycle[m],
162 eofb_flipped[m],
163 eorl_flipped[m],
164 eoud_flipped[m],
165 corner_cycle[m],
166 coud_flipped[m],
167 corl_flipped[m],
168 cofb_flipped[m],
169 center_cycle[m]
170 };
171
172 return move_via_arrays(&m_arr, cube, f);
173}
174
175/* Public functions **********************************************************/
176
177Cube
178apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a)
179{
180 Cube ret = {0};
181 int i;
182
183 for (i = 0; i < alg->len; i++)
184 if (alg->inv[i])
185 ret = a ? apply_move(alg->move[i], ret) :
186 apply_move_cubearray(alg->move[i], ret, f);
187
188 ret = compose_filtered(c, inverse_cube(ret), f);
189
190 for (i = 0; i < alg->len; i++)
191 if (!alg->inv[i])
192 ret = a ? apply_move(alg->move[i], ret) :
193 apply_move_cubearray(alg->move[i], ret, f);
194
195 return ret;
196}
197
198Cube
199apply_alg(Alg *alg, Cube cube)
200{
201 return apply_alg_generic(alg, cube, pf_all, true);
202}
203
204Cube
205apply_move(Move m, Cube cube)
206{
207 /*init_moves();*/
208
209 return (Cube) {
210 .epose = epose_mtable[m][cube.epose],
211 .eposs = eposs_mtable[m][cube.eposs],
212 .eposm = eposm_mtable[m][cube.eposm],
213 .eofb = eofb_mtable[m][cube.eofb],
214 .eorl = eorl_mtable[m][cube.eorl],
215 .eoud = eoud_mtable[m][cube.eoud],
216 .coud = coud_mtable[m][cube.coud],
217 .cofb = cofb_mtable[m][cube.cofb],
218 .corl = corl_mtable[m][cube.corl],
219 .cp = cp_mtable[m][cube.cp],
220 .cpos = cpos_mtable[m][cube.cpos]
221 };
222}
223
224void
225init_moves() {
226 static bool initialized = false;
227 if (initialized)
228 return;
229 initialized = true;
230
231 Cube c;
232 CubeArray arrs;
233 int i;
234 unsigned int ui;
235 Move m;
236 Alg *equiv_alg[NMOVES];
237
238 for (i = 0; i < NMOVES; i++)
239 equiv_alg[i] = new_alg(equiv_alg_string[i]);
240
241 /* Generate all move cycles and flips; I do this regardless */
242 for (i = 0; i < NMOVES; i++) {
243 if (i == U || i == x || i == y)
244 continue;
245
246 c = apply_alg_generic(equiv_alg[i], (Cube){0}, pf_all, false);
247
248 arrs = (CubeArray) {
249 edge_cycle[i],
250 eofb_flipped[i],
251 eorl_flipped[i],
252 eoud_flipped[i],
253 corner_cycle[i],
254 coud_flipped[i],
255 corl_flipped[i],
256 cofb_flipped[i],
257 center_cycle[i]
258 };
259 cube_to_arrays(c, &arrs, pf_all);
260 }
261
262 if (read_mtables_file())
263 return;
264
265 fprintf(stderr, "Cannot load %s, generating it\n", "mtables");
266
267 /* Initialize transition tables */
268 for (m = 0; m < NMOVES; m++) {
269 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
270 c = (Cube){ .epose = ui };
271 c = apply_move_cubearray(m, c, pf_e);
272 epose_mtable[m][ui] = c.epose;
273
274 c = (Cube){ .eposs = ui };
275 c = apply_move_cubearray(m, c, pf_s);
276 eposs_mtable[m][ui] = c.eposs;
277
278 c = (Cube){ .eposm = ui };
279 c = apply_move_cubearray(m, c, pf_m);
280 eposm_mtable[m][ui] = c.eposm;
281 }
282 for (ui = 0; ui < POW2TO11; ui++ ) {
283 c = (Cube){ .eofb = ui };
284 c = apply_move_cubearray(m, c, pf_eo);
285 eofb_mtable[m][ui] = c.eofb;
286
287 c = (Cube){ .eorl = ui };
288 c = apply_move_cubearray(m, c, pf_eo);
289 eorl_mtable[m][ui] = c.eorl;
290
291 c = (Cube){ .eoud = ui };
292 c = apply_move_cubearray(m, c, pf_eo);
293 eoud_mtable[m][ui] = c.eoud;
294 }
295 for (ui = 0; ui < POW3TO7; ui++) {
296 c = (Cube){ .coud = ui };
297 c = apply_move_cubearray(m, c, pf_co);
298 coud_mtable[m][ui] = c.coud;
299
300 c = (Cube){ .corl = ui };
301 c = apply_move_cubearray(m, c, pf_co);
302 corl_mtable[m][ui] = c.corl;
303
304 c = (Cube){ .cofb = ui };
305 c = apply_move_cubearray(m, c, pf_co);
306 cofb_mtable[m][ui] = c.cofb;
307 }
308 for (ui = 0; ui < FACTORIAL8; ui++) {
309 c = (Cube){ .cp = ui };
310 c = apply_move_cubearray(m, c, pf_cp);
311 cp_mtable[m][ui] = c.cp;
312 }
313 for (ui = 0; ui < FACTORIAL6; ui++) {
314 c = (Cube){ .cpos = ui };
315 c = apply_move_cubearray(m, c, pf_cpos);
316 cpos_mtable[m][ui] = c.cpos;
317 }
318 }
319
320 if (!write_mtables_file())
321 fprintf(stderr, "Error writing mtables\n");
322
323 for (i = 0; i < NMOVES; i++)
324 free_alg(equiv_alg[i]);
325}
326
327static bool
328read_mtables_file()
329{
330 init_env();
331
332 FILE *f;
333 char fname[strlen(tabledir)+20];
334 int m, b = sizeof(int);
335 bool r = true;
336
337 /* Table sizes, used for reading and writing files */
338 uint64_t me[11] = {
339 [0] = FACTORIAL12/FACTORIAL8,
340 [1] = FACTORIAL12/FACTORIAL8,
341 [2] = FACTORIAL12/FACTORIAL8,
342 [3] = POW2TO11,
343 [4] = POW2TO11,
344 [5] = POW2TO11,
345 [6] = FACTORIAL8,
346 [7] = POW3TO7,
347 [8] = POW3TO7,
348 [9] = POW3TO7,
349 [10] = FACTORIAL6
350 };
351
352 strcpy(fname, tabledir);
353 strcat(fname, "/mtables");
354
355 if ((f = fopen(fname, "rb")) == NULL)
356 return false;
357
358 for (m = 0; m < NMOVES; m++) {
359 r = r && fread(epose_mtable[m], b, me[0], f) == me[0];
360 r = r && fread(eposs_mtable[m], b, me[1], f) == me[1];
361 r = r && fread(eposm_mtable[m], b, me[2], f) == me[2];
362 r = r && fread(eofb_mtable[m], b, me[3], f) == me[3];
363 r = r && fread(eorl_mtable[m], b, me[4], f) == me[4];
364 r = r && fread(eoud_mtable[m], b, me[5], f) == me[5];
365 r = r && fread(cp_mtable[m], b, me[6], f) == me[6];
366 r = r && fread(coud_mtable[m], b, me[7], f) == me[7];
367 r = r && fread(corl_mtable[m], b, me[8], f) == me[8];
368 r = r && fread(cofb_mtable[m], b, me[9], f) == me[9];
369 r = r && fread(cpos_mtable[m], b, me[10], f) == me[10];
370 }
371
372 fclose(f);
373 return r;
374}
375
376static bool
377write_mtables_file()
378{
379 init_env();
380
381 FILE *f;
382 char fname[strlen(tabledir)+20];
383 int m, b = sizeof(int);
384 bool r = true;
385
386 /* Table sizes, used for reading and writing files */
387 uint64_t me[11] = {
388 [0] = FACTORIAL12/FACTORIAL8,
389 [1] = FACTORIAL12/FACTORIAL8,
390 [2] = FACTORIAL12/FACTORIAL8,
391 [3] = POW2TO11,
392 [4] = POW2TO11,
393 [5] = POW2TO11,
394 [6] = FACTORIAL8,
395 [7] = POW3TO7,
396 [8] = POW3TO7,
397 [9] = POW3TO7,
398 [10] = FACTORIAL6
399 };
400
401 strcpy(fname, tabledir);
402 strcat(fname, "/mtables");
403
404 if ((f = fopen(fname, "wb")) == NULL)
405 return false;
406
407 for (m = 0; m < NMOVES; m++) {
408 r = r && fwrite(epose_mtable[m], b, me[0], f) == me[0];
409 r = r && fwrite(eposs_mtable[m], b, me[1], f) == me[1];
410 r = r && fwrite(eposm_mtable[m], b, me[2], f) == me[2];
411 r = r && fwrite(eofb_mtable[m], b, me[3], f) == me[3];
412 r = r && fwrite(eorl_mtable[m], b, me[4], f) == me[4];
413 r = r && fwrite(eoud_mtable[m], b, me[5], f) == me[5];
414 r = r && fwrite(cp_mtable[m], b, me[6], f) == me[6];
415 r = r && fwrite(coud_mtable[m], b, me[7], f) == me[7];
416 r = r && fwrite(corl_mtable[m], b, me[8], f) == me[8];
417 r = r && fwrite(cofb_mtable[m], b, me[9], f) == me[9];
418 r = r && fwrite(cpos_mtable[m], b, me[10], f) == me[10];
419 }
420
421 fclose(f);
422 return r;
423}
424
425bool
426commute(Move m1, Move m2)
427{
428 static bool initialized = false;
429 static bool commute_aux[NMOVES][NMOVES];
430
431 if (!initialized) {
432 Cube c1, c2;
433 int i, j;
434
435 for (i = 0; i < NMOVES; i++) {
436 for (j = 0; j < NMOVES; j++) {
437 c1 = apply_move(i, apply_move(j, (Cube){0}));
438 c2 = apply_move(j, apply_move(i, (Cube){0}));
439 commute_aux[i][j] = equal(c1, c2) && i && j;
440 }
441 }
442
443 initialized = true;
444 }
445
446 return commute_aux[m1][m2];
447}
448
449bool
450possible_next(Move m1, Move m2, Move m3)
451{
452 static bool initialized = false;
453 static bool paux[NMOVES][NMOVES][NMOVES];
454
455 if (!initialized) {
456 int i, j, k;
457 bool p, q, c;
458
459 for (i = 0; i < NMOVES; i++) {
460 for (j = 0; j < NMOVES; j++) {
461 for (k = 0; k < NMOVES; k++) {
462 p = j && base_move(j) == base_move(k);
463 q = i && base_move(i) == base_move(k);
464 c = commute(i, j);
465 paux[i][j][k] = !(p || (c && q));
466 }
467 }
468 }
469
470 initialized = true;
471 }
472
473 return paux[m1][m2][m3];
474}
diff --git a/old/2021-11-10-beforeremovingchecker/moves.h b/old/2021-11-10-beforeremovingchecker/moves.h
new file mode 100644
index 0000000..082a080
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/moves.h
@@ -0,0 +1,16 @@
1#ifndef MOVES_H
2#define MOVES_H
3
4#include "alg.h"
5#include "cube.h"
6#include "env.h"
7
8Cube apply_alg(Alg *alg, Cube cube);
9Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a);
10Cube apply_move(Move m, Cube cube);
11bool commute(Move m1, Move m2);
12bool possible_next(Move m1, Move m2, Move m3);
13
14void init_moves();
15
16#endif
diff --git a/old/2021-11-10-beforeremovingchecker/pf.c b/old/2021-11-10-beforeremovingchecker/pf.c
new file mode 100644
index 0000000..34be4fd
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/pf.c
@@ -0,0 +1,80 @@
1#include "pf.h"
2
3PieceFilter
4pf_all = {
5 .epose = true,
6 .eposs = true,
7 .eposm = true,
8 .eofb = true,
9 .eorl = true,
10 .eoud = true,
11 .cp = true,
12 .cofb = true,
13 .corl = true,
14 .coud = true,
15 .cpos = true
16};
17
18PieceFilter
19pf_4val = {
20 .epose = true,
21 .eposs = true,
22 .eposm = true,
23 .eofb = true,
24 .coud = true,
25 .cp = true
26};
27
28PieceFilter
29pf_epcp = {
30 .epose = true,
31 .eposs = true,
32 .eposm = true,
33 .cp = true
34};
35
36PieceFilter
37pf_cpos = {
38 .cpos = true
39};
40
41PieceFilter
42pf_cp = {
43 .cp = true
44};
45
46PieceFilter
47pf_ep = {
48 .epose = true,
49 .eposs = true,
50 .eposm = true
51};
52
53PieceFilter
54pf_e = {
55 .epose = true
56};
57
58PieceFilter
59pf_s = {
60 .eposs = true
61};
62
63PieceFilter
64pf_m = {
65 .eposm = true
66};
67
68PieceFilter
69pf_eo = {
70 .eofb = true,
71 .eorl = true,
72 .eoud = true
73};
74
75PieceFilter
76pf_co = {
77 .cofb = true,
78 .corl = true,
79 .coud = true
80};
diff --git a/old/2021-11-10-beforeremovingchecker/pf.h b/old/2021-11-10-beforeremovingchecker/pf.h
new file mode 100644
index 0000000..85ee1eb
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/pf.h
@@ -0,0 +1,18 @@
1#ifndef PF_H
2#define PF_H
3
4#include "cubetypes.h"
5
6extern PieceFilter pf_all;
7extern PieceFilter pf_4val;
8extern PieceFilter pf_epcp;
9extern PieceFilter pf_cpos;
10extern PieceFilter pf_cp;
11extern PieceFilter pf_ep;
12extern PieceFilter pf_e;
13extern PieceFilter pf_s;
14extern PieceFilter pf_m;
15extern PieceFilter pf_eo;
16extern PieceFilter pf_co;
17
18#endif
diff --git a/old/2021-11-10-beforeremovingchecker/pruning.c b/old/2021-11-10-beforeremovingchecker/pruning.c
new file mode 100644
index 0000000..86363f4
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/pruning.c
@@ -0,0 +1,272 @@
1#include "pruning.h"
2
3static void genptable_bfs(PruneData *pd, int d, Move *ms);
4static void genptable_branch(PruneData *pd, uint64_t i, int d, Move *m);
5static void ptable_update(PruneData *pd, Cube cube, int m);
6static void ptable_update_index(PruneData *pd, uint64_t ind, int m);
7static int ptableval_index(PruneData *pd, uint64_t ind);
8static bool read_ptable_file(PruneData *pd);
9static bool write_ptable_file(PruneData *pd);
10
11PruneData
12pd_eofb_HTM = {
13 .filename = "pt_eofb_HTM",
14 .coord = &coord_eofb,
15 .moveset = moveset_HTM,
16};
17
18PruneData
19pd_coud_HTM = {
20 .filename = "pt_coud_HTM",
21 .coord = &coord_coud,
22 .moveset = moveset_HTM,
23};
24
25PruneData
26pd_cornershtr_HTM = {
27 .filename = "pt_cornershtr_withcosets_HTM",
28 .coord = &coord_cornershtr,
29 .moveset = moveset_HTM,
30};
31
32PruneData
33pd_corners_HTM = {
34 .filename = "pt_corners_HTM",
35 .coord = &coord_corners,
36 .moveset = moveset_HTM,
37};
38
39PruneData
40pd_drud_sym16_HTM = {
41 .filename = "pt_drud_sym16_HTM",
42 .coord = &coord_drud_sym16,
43 .moveset = moveset_HTM,
44};
45
46PruneData
47pd_drud_eofb = {
48 .filename = "pt_drud_eofb",
49 .coord = &coord_drud_eofb,
50 .moveset = moveset_eofb,
51};
52
53PruneData
54pd_drudfin_noE_sym16_drud = {
55 .filename = "pt_drudfin_noE_sym16_drud",
56 .coord = &coord_drudfin_noE_sym16,
57 .moveset = moveset_drud,
58};
59
60PruneData
61pd_htr_drud = {
62 .filename = "pt_htr_drud",
63 .coord = &coord_htr_drud,
64 .moveset = moveset_drud,
65};
66
67PruneData
68pd_htrfin_htr = {
69 .filename = "pt_htrfin_htr",
70 .coord = &coord_htrfin,
71 .moveset = moveset_htr,
72};
73
74PruneData
75pd_khuge_HTM = {
76 .filename = "pt_khuge_HTM",
77 .coord = &coord_khuge,
78 .moveset = moveset_HTM,
79};
80
81void
82genptable(PruneData *pd)
83{
84 Move ms[NMOVES];
85 int d;
86 uint64_t j, oldn;
87
88 if (pd->generated)
89 return;
90
91 /* TODO: check if memory is enough, otherwise maybe exit gracefully? */
92 pd->ptable = malloc(ptablesize(pd) * sizeof(uint8_t));
93
94 if (read_ptable_file(pd)) {
95 pd->generated = true;
96 return;
97 }
98 pd->generated = true;
99
100 fprintf(stderr, "Cannot load %s, generating it\n", pd->filename);
101
102 moveset_to_list(pd->moveset, ms);
103
104 /* We use 4 bits per value, so any distance >= 15 is set to 15 */
105 for (j = 0; j < pd->coord->max; j++)
106 ptable_update_index(pd, j, 15);
107
108 for (j = 0; j < pd->coord->max; j++)
109 if (ptableval_index(pd, j) != 15) {
110 printf("Error, non-max value at index %lu!\n", j);
111 break;
112 }
113 printf("Table set, ready to start\n");
114
115 /*TODO: change, set to 0 for every solved state (might be more than 1)*/
116 ptable_update(pd, (Cube){0}, 0);
117 pd->n = 1;
118 oldn = 0;
119 fprintf(stderr, "Depth %d done, generated %lu\t(%lu/%lu)\n",
120 0, pd->n - oldn, pd->n, pd->coord->max);
121 oldn = 1;
122 for (d = 0; d < 15 && pd->n < pd->coord->max; d++) {
123 genptable_bfs(pd, d, ms);
124 fprintf(stderr, "Depth %d done, generated %lu\t(%lu/%lu)\n",
125 d+1, pd->n - oldn, pd->n, pd->coord->max);
126 oldn = pd->n;
127 }
128
129 if (!write_ptable_file(pd))
130 fprintf(stderr, "Error writing ptable file\n");
131}
132
133static void
134genptable_bfs(PruneData *pd, int d, Move *ms)
135{
136 uint64_t i;
137
138 for (i = 0; i < pd->coord->max; i++)
139 if (ptableval_index(pd, i) == d)
140 genptable_branch(pd, i, d, ms);
141}
142
143static void
144genptable_branch(PruneData *pd, uint64_t ind, int d, Move *ms)
145{
146 int i, j;
147 Cube ci, cc, c;
148
149 /*
150 * This is the only line of the whole program where we REALLY need an
151 * anti-indexer function. We could get rid of it if only we could save
152 * a cube object for each index value as we go, but then we would need
153 * an incredible amount of memory to generate each ptable: assuming
154 * fields in struct cube are 32 bit ints that would take 88 times the
155 * memory of the table to be generated, more than 120Gb for
156 * ptable_khuge for example!
157 */
158 ci = pd->coord->cube(ind);
159
160 for (i = 0; i < pd->coord->ntrans; i++) {
161 /* For simplicity trans[] is NULL when ntrans = 1 */
162 c = i == 0 ? ci :
163 apply_trans(pd->coord->trans[i], ci);
164 for (j = 0; ms[j] != NULLMOVE; j++) {
165 cc = apply_move(ms[j], c);
166 if (ptableval(pd, cc) > d+1)
167 ptable_update(pd, cc, d+1);
168 }
169 }
170}
171
172void
173print_ptable(PruneData *pd)
174{
175 uint64_t i, a[16];
176
177 for (i = 0; i < 16; i++)
178 a[i] = 0;
179
180 if (!pd->generated)
181 genptable(pd);
182
183 for (i = 0; i < pd->coord->max; i++)
184 a[ptableval_index(pd, i)]++;
185
186 fprintf(stderr, "Values for table %s\n", pd->filename);
187 for (i = 0; i < 16; i++)
188 printf("%2lu\t%10lu\n", i, a[i]);
189}
190
191uint64_t
192ptablesize(PruneData *pd)
193{
194 return (pd->coord->max + 1) / 2;
195}
196
197static void
198ptable_update(PruneData *pd, Cube cube, int n)
199{
200 uint64_t ind = pd->coord->index(cube);
201 ptable_update_index(pd, ind, n);
202}
203
204static void
205ptable_update_index(PruneData *pd, uint64_t ind, int n)
206{
207 uint8_t oldval2 = pd->ptable[ind/2];
208 int other = (ind % 2) ? oldval2 % 16 : oldval2 / 16;
209
210 pd->ptable[ind/2] = (ind % 2) ? 16*n + other : 16*other + n;
211 pd->n++;
212}
213
214int
215ptableval(PruneData *pd, Cube cube)
216{
217 return ptableval_index(pd, pd->coord->index(cube));
218}
219
220static int
221ptableval_index(PruneData *pd, uint64_t ind)
222{
223 if (!pd->generated)
224 genptable(pd);
225
226 return (ind % 2) ? pd->ptable[ind/2] / 16 : pd->ptable[ind/2] % 16;
227}
228
229static bool
230read_ptable_file(PruneData *pd)
231{
232 init_env();
233
234 FILE *f;
235 char fname[strlen(tabledir)+100];
236 uint64_t r;
237
238 strcpy(fname, tabledir);
239 strcat(fname, "/");
240 strcat(fname, pd->filename);
241
242 if ((f = fopen(fname, "rb")) == NULL)
243 return false;
244
245 r = fread(pd->ptable, sizeof(uint8_t), ptablesize(pd), f);
246 fclose(f);
247
248 return r == ptablesize(pd);
249}
250
251static bool
252write_ptable_file(PruneData *pd)
253{
254 init_env();
255
256 FILE *f;
257 char fname[strlen(tabledir)+100];
258 uint64_t written;
259
260 strcpy(fname, tabledir);
261 strcat(fname, "/");
262 strcat(fname, pd->filename);
263
264 if ((f = fopen(fname, "wb")) == NULL)
265 return false;
266
267 written = fwrite(pd->ptable, sizeof(uint8_t), ptablesize(pd), f);
268 fclose(f);
269
270 return written == ptablesize(pd);
271}
272
diff --git a/old/2021-11-10-beforeremovingchecker/pruning.h b/old/2021-11-10-beforeremovingchecker/pruning.h
new file mode 100644
index 0000000..631ee3a
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/pruning.h
@@ -0,0 +1,23 @@
1#ifndef PRUNING_H
2#define PRUNING_H
3
4#include "symcoord.h"
5
6extern PruneData pd_eofb_HTM;
7extern PruneData pd_coud_HTM;
8extern PruneData pd_corners_HTM;
9extern PruneData pd_cornershtr_HTM;
10extern PruneData pd_drud_sym16_HTM;
11extern PruneData pd_drud_eofb;
12extern PruneData pd_drudfin_noE_sym16_drud;
13extern PruneData pd_htr_drud;
14extern PruneData pd_htrfin_htr;
15extern PruneData pd_khuge_HTM;
16
17void genptable(PruneData *pd);
18void print_ptable(PruneData *pd);
19uint64_t ptablesize(PruneData *pd);
20int ptableval(PruneData *pd, Cube cube);
21
22#endif
23
diff --git a/old/2021-11-10-beforeremovingchecker/shell.c b/old/2021-11-10-beforeremovingchecker/shell.c
new file mode 100644
index 0000000..e591faa
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/shell.c
@@ -0,0 +1,99 @@
1#include "shell.h"
2
3static void cleanwhitespaces(char *line);
4static int parseline(char *line, char **v);
5
6static void
7cleanwhitespaces(char *line)
8{
9 char *i;
10
11 for (i = line; *i != 0; i++)
12 if (*i == '\t' || *i == '\n')
13 *i = ' ';
14}
15
16/* This function assumes that **v is large enough */
17static int
18parseline(char *line, char **v)
19{
20 char *t;
21 int n = 0;
22
23 cleanwhitespaces(line);
24
25 for (t = strtok(line, " "); t != NULL; t = strtok(NULL, " "))
26 strcpy(v[n++], t);
27
28 return n;
29}
30
31void
32exec_args(int c, char **v)
33{
34 int i;
35 Command *cmd = NULL;
36 CommandArgs *args;
37
38 for (i = 0; i < NCOMMANDS; i++)
39 if (commands[i] != NULL && !strcmp(v[0], commands[i]->name))
40 cmd = commands[i];
41
42 if (cmd == NULL) {
43 fprintf(stderr, "%s: command not found\n", v[0]);
44 return;
45 }
46
47 args = cmd->parse_args(c-1, &v[1]);
48 if (!args->success) {
49 fprintf(stderr, "usage: %s\n", cmd->usage);
50 return;
51 }
52
53 cmd->exec(args);
54 free_args(args);
55}
56
57void
58launch()
59{
60 int i, shell_argc;
61 char line[MAXLINELEN], **shell_argv;
62
63 shell_argv = malloc(MAXNTOKENS * sizeof(char *));
64 for (i = 0; i < MAXNTOKENS; i++)
65 shell_argv[i] = malloc((MAXTOKENLEN+1) * sizeof(char));
66
67 fprintf(stderr, "Welcome to Nissy 2.0 (demo version).\n");
68 fprintf(stderr, "Limited commands available. ");
69 fprintf(stderr, "Type 'help' for a list.\n");
70
71 while (true) {
72 fprintf(stderr, "nissy-# ");
73 if (fgets(line, MAXLINELEN, stdin) == NULL)
74 break;
75 shell_argc = parseline(line, shell_argv);
76 exec_args(shell_argc, shell_argv);
77 }
78
79 for (i = 0; i < MAXNTOKENS; i++)
80 free(shell_argv[i]);
81 free(shell_argv);
82}
83
84/* We will have our main() here, for now */
85int
86main(int argc, char *argv[])
87{
88 init_moves();
89 init_trans();
90 init_coord();
91 init_symcoord();
92
93 if (argc > 1)
94 exec_args(argc-1, &argv[1]);
95 else
96 launch();
97
98 return 0;
99}
diff --git a/old/2021-11-10-beforeremovingchecker/shell.h b/old/2021-11-10-beforeremovingchecker/shell.h
new file mode 100644
index 0000000..a72d136
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/shell.h
@@ -0,0 +1,13 @@
1#ifndef SHELL_H
2#define SHELL_H
3
4#include "commands.h"
5
6#define MAXLINELEN 10000
7#define MAXTOKENLEN 255
8#define MAXNTOKENS 255
9
10void exec_args(int c, char **v);
11void launch();
12
13#endif
diff --git a/old/2021-11-10-beforeremovingchecker/solve.c b/old/2021-11-10-beforeremovingchecker/solve.c
new file mode 100644
index 0000000..af685ec
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/solve.c
@@ -0,0 +1,209 @@
1#include "solve.h"
2
3/* Local functions ***********************************************************/
4
5static bool allowed_next(Move move, DfsData *dd);
6static void dfs(Cube c, Step *s, SolveOptions *opts, DfsData *dd);
7static void dfs_branch(Cube c, Step *s, SolveOptions *os, DfsData *dd);
8static bool dfs_check_solved(Step *s, SolveOptions *opts, DfsData *dd);
9static void dfs_niss(Cube c, Step *s, SolveOptions *opts, DfsData *dd);
10static bool dfs_stop(Cube c, Step *s, SolveOptions *opts, DfsData *dd);
11
12/* Local functions ***********************************************************/
13
14static bool
15allowed_next(Move move, DfsData *dd)
16{
17
18/* TODO: remove the commented part, was added to moves.c
19 static bool initialized = false;
20 static bool commute[NMOVES][NMOVES], pnext[NMOVES][NMOVES][NMOVES];
21
22 if (!initialized) {
23 Cube c1, c2;
24 int i, j, k;
25 bool p1, p2, cij;
26
27 for (i = 0; i < NMOVES; i++) {
28 for (j = 0; j < NMOVES; j++) {
29 c1 = apply_move(i, apply_move(j, (Cube){0}));
30 c2 = apply_move(j, apply_move(i, (Cube){0}));
31 commute[i][j] = equal(c1, c2) && i && j;
32 for (k = 0; k < NMOVES; k++) {
33 p1 = j && base_move(j) == base_move(k);
34 p2 = i && base_move(i) == base_move(k);
35 cij = commute[i][j];
36 pnext[i][j][k] = !(p1 || (cij && p2));
37 }
38 }
39 }
40
41 initialized = true;
42 }
43
44 if (!pnext[dd->last2][dd->last1][move])
45 return false;
46
47 if (commute[dd->last1][move])
48 return dd->move_position[dd->last1] < dd->move_position[move];
49
50 return true;
51*/
52
53 if (!possible_next(dd->last2, dd->last1, move))
54 return false;
55
56 if (commute(dd->last1, move))
57 return dd->move_position[dd->last1] < dd->move_position[move];
58
59 return true;
60}
61
62static void
63dfs(Cube c, Step *s, SolveOptions *opts, DfsData *dd)
64{
65 if (dfs_stop(c, s, opts, dd))
66 return;
67
68 if (dfs_check_solved(s, opts, dd))
69 return;
70
71 dfs_branch(c, s, opts, dd);
72
73 if (opts->can_niss && !dd->niss)
74 dfs_niss(c, s, opts, dd);
75}
76
77static void
78dfs_branch(Cube c, Step *s, SolveOptions *opts, DfsData *dd)
79{
80 Move m, l1 = dd->last1, l2 = dd->last2, *moves = dd->sorted_moves;
81
82 int i, maxnsol = opts->max_solutions;
83
84 for (i = 0; moves[i] != NULLMOVE && dd->sols->len < maxnsol; i++) {
85 m = moves[i];
86 if (allowed_next(m, dd)) {
87 dd->last2 = dd->last1;
88 dd->last1 = m;
89 append_move(dd->current_alg, m, dd->niss);
90
91 dfs(apply_move(m, c), s, opts, dd);
92
93 dd->current_alg->len--;
94 dd->last2 = l2;
95 dd->last1 = l1;
96 }
97 }
98}
99
100static bool
101dfs_check_solved(Step *s, SolveOptions *opts, DfsData *dd)
102{
103 if (dd->lb != 0)
104 return false;
105
106 if (dd->current_alg->len == dd->d) {
107 if (s->is_valid(dd->current_alg) || opts->all)
108 append_alg(dd->sols, dd->current_alg);
109
110 if (opts->feedback)
111 print_alg(dd->current_alg, false);
112 }
113
114 return true;
115}
116
117static void
118dfs_niss(Cube c, Step *s, SolveOptions *opts, DfsData *dd)
119{
120 Move l1 = dd->last1, l2 = dd->last2;
121 CubeTarget ct;
122
123 ct.cube = apply_move(inverse_move(l1), (Cube){0});
124 ct.target = 1;
125
126 if (dd->current_alg->len == 0 || s->estimate(ct)) {
127 dd->niss = true;
128 dd->last1 = NULLMOVE;
129 dd->last2 = NULLMOVE;
130
131 dfs(inverse_cube(c), s, opts, dd);
132
133 dd->last1 = l1;
134 dd->last2 = l2;
135 dd->niss = false;
136 }
137}
138
139static bool
140dfs_stop(Cube c, Step *s, SolveOptions *opts, DfsData *dd)
141{
142 CubeTarget ct = {
143 .cube = c,
144 .target = dd->d - dd->current_alg->len
145 };
146
147 if (dd->sols->len >= opts->max_solutions)
148 return true;
149
150 dd->lb = s->estimate(ct);
151 if (opts->can_niss && !dd->niss)
152 dd->lb = MIN(1, dd->lb);
153
154 if (dd->current_alg->len + dd->lb > dd->d)
155 return true;
156
157 return false;
158}
159
160/* Public functions **********************************************************/
161
162AlgList *
163solve(Cube cube, Step *step, SolveOptions *opts)
164{
165 AlgListNode *node;
166 AlgList *sols = new_alglist();
167 Cube c;
168
169 if (step->detect != NULL)
170 step->pre_trans = step->detect(cube);
171 c = apply_trans(step->pre_trans, cube);
172
173 DfsData dd = {
174 .m = 0,
175 .niss = false,
176 .lb = -1,
177 .last1 = NULLMOVE,
178 .last2 = NULLMOVE,
179 .sols = sols,
180 .current_alg = new_alg("")
181 };
182
183 if (step->ready != NULL && !step->ready(c)) {
184 fprintf(stderr, "Cube not ready for solving step: ");
185 fprintf(stderr, "%s\n", step->ready_msg);
186 return sols;
187 }
188
189 moveset_to_list(step->moveset, dd.sorted_moves);
190 movelist_to_position(dd.sorted_moves, dd.move_position);
191
192 for (dd.d = opts->min_moves;
193 dd.d <= opts->max_moves &&
194 !(sols->len && opts->optimal_only) &&
195 sols->len < opts->max_solutions;
196 dd.d++) {
197 if (opts->feedback)
198 fprintf(stderr,
199 "Found %d solutions, searching depth %d...\n",
200 sols->len, dd.d);
201 dfs(c, step, opts, &dd);
202 }
203
204 for (node = sols->first; node != NULL; node = node->next)
205 transform_alg(inverse_trans(step->pre_trans), node->alg);
206
207 free_alg(dd.current_alg);
208 return sols;
209}
diff --git a/old/2021-11-10-beforeremovingchecker/solve.h b/old/2021-11-10-beforeremovingchecker/solve.h
new file mode 100644
index 0000000..ff84e7e
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/solve.h
@@ -0,0 +1,9 @@
1#ifndef SOLVE_H
2#define SOLVE_H
3
4#include "moves.h"
5#include "trans.h"
6
7AlgList * solve(Cube cube, Step *step, SolveOptions *opts);
8
9#endif
diff --git a/old/2021-11-10-beforeremovingchecker/steps.c b/old/2021-11-10-beforeremovingchecker/steps.c
new file mode 100644
index 0000000..7213766
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/steps.c
@@ -0,0 +1,916 @@
1#include "steps.h"
2
3/* Standard checkers (return lower bound) ************************************/
4
5static int estimate_eoany_HTM(CubeTarget ct);
6static int estimate_eofb_HTM(CubeTarget ct);
7static int estimate_coany_HTM(CubeTarget ct);
8static int estimate_coud_HTM(CubeTarget ct);
9static int estimate_coany_URF(CubeTarget ct);
10static int estimate_coud_URF(CubeTarget ct);
11static int estimate_corners_HTM(CubeTarget ct);
12static int estimate_cornershtr_HTM(CubeTarget ct);
13static int estimate_corners_URF(CubeTarget ct);
14static int estimate_cornershtr_URF(CubeTarget ct);
15static int estimate_drany_HTM(CubeTarget ct);
16static int estimate_drud_HTM(CubeTarget ct);
17static int estimate_drud_eofb(CubeTarget ct);
18static int estimate_dr_eofb(CubeTarget ct);
19static int estimate_drudfin_drud(CubeTarget ct);
20static int estimate_htr_drud(CubeTarget ct);
21static int estimate_htrfin_htr(CubeTarget ct);
22static int estimate_optimal_HTM(CubeTarget ct);
23
24/* Validators ****************************************************************/
25
26static bool always_valid(Alg *alg);
27static bool validate_singlecw_ending(Alg *alg);
28
29/* Pre-transformation detectors **********************************************/
30
31static Trans detect_pretrans_eofb(Cube cube);
32static Trans detect_pretrans_drud(Cube cube);
33
34/* Messages for when cube is not ready ***************************************/
35
36static char check_centers_msg[100] = "cube must be oriented (centers solved)";
37static char check_eo_msg[100] = "EO must be solved on given axis";
38static char check_dr_msg[100] = "DR must be solved on given axis";
39static char check_htr_msg[100] = "HTR must be solved";
40static char check_drany_msg[100] = "DR must be solved on at least one axis";
41
42/* Steps *********************************************************************/
43
44Step
45optimal_HTM = {
46 .shortname = "optimal",
47 .name = "Optimal solve (in HTM)",
48
49 .estimate = estimate_optimal_HTM,
50 .ready = check_centers,
51 .ready_msg = check_centers_msg,
52 .is_valid = always_valid,
53 .moveset = moveset_HTM,
54
55 .pre_trans = uf,
56};
57
58/* EO steps **************************/
59Step
60eoany_HTM = {
61 .shortname = "eo",
62 .name = "EO on any axis",
63
64 .estimate = estimate_eoany_HTM,
65 .ready = check_centers,
66 .ready_msg = check_centers_msg,
67 .is_valid = validate_singlecw_ending,
68 .moveset = moveset_HTM,
69
70 .pre_trans = uf,
71};
72
73Step
74eofb_HTM = {
75 .shortname = "eofb",
76 .name = "EO on F/B",
77
78 .estimate = estimate_eofb_HTM,
79 .ready = check_centers,
80 .ready_msg = check_centers_msg,
81 .is_valid = validate_singlecw_ending,
82 .moveset = moveset_HTM,
83
84 .pre_trans = uf,
85};
86
87Step
88eorl_HTM = {
89 .shortname = "eorl",
90 .name = "EO on R/L",
91
92 .estimate = estimate_eofb_HTM,
93 .ready = check_centers,
94 .ready_msg = check_centers_msg,
95 .is_valid = validate_singlecw_ending,
96 .moveset = moveset_HTM,
97
98 .pre_trans = ur,
99};
100
101Step
102eoud_HTM = {
103 .shortname = "eoud",
104 .name = "EO on U/D",
105
106 .estimate = estimate_eofb_HTM,
107 .ready = check_centers,
108 .ready_msg = check_centers_msg,
109 .is_valid = validate_singlecw_ending,
110 .moveset = moveset_HTM,
111
112 .pre_trans = fd,
113};
114
115/* CO steps **************************/
116Step
117coany_HTM = {
118 .shortname = "co",
119 .name = "CO on any axis",
120
121 .estimate = estimate_coany_HTM,
122 .ready = NULL,
123 .is_valid = validate_singlecw_ending,
124 .moveset = moveset_HTM,
125
126 .pre_trans = uf,
127};
128
129Step
130coud_HTM = {
131 .shortname = "coud",
132 .name = "CO on U/D",
133
134 .estimate = estimate_coud_HTM,
135 .ready = NULL,
136 .is_valid = validate_singlecw_ending,
137 .moveset = moveset_HTM,
138
139 .pre_trans = uf,
140};
141
142Step
143corl_HTM = {
144 .shortname = "corl",
145 .name = "CO on R/L",
146
147 .estimate = estimate_coud_HTM,
148 .ready = NULL,
149 .is_valid = validate_singlecw_ending,
150 .moveset = moveset_HTM,
151
152 .pre_trans = rf,
153};
154
155Step
156cofb_HTM = {
157 .shortname = "cofb",
158 .name = "CO on F/B",
159
160 .estimate = estimate_coud_HTM,
161 .ready = NULL,
162 .is_valid = validate_singlecw_ending,
163 .moveset = moveset_HTM,
164
165 .pre_trans = fd,
166};
167
168Step
169coany_URF = {
170 .shortname = "co-URF",
171 .name = "CO any axis (URF moveset)",
172
173 .estimate = estimate_coany_URF,
174 .ready = NULL,
175 .is_valid = validate_singlecw_ending,
176 .moveset = moveset_URF,
177
178 .pre_trans = uf,
179};
180
181Step
182coud_URF = {
183 .shortname = "coud-URF",
184 .name = "CO on U/D (URF moveset)",
185
186 .estimate = estimate_coud_URF,
187 .ready = NULL,
188 .is_valid = validate_singlecw_ending,
189 .moveset = moveset_URF,
190
191 .pre_trans = uf,
192};
193
194Step
195corl_URF = {
196 .shortname = "corl-URF",
197 .name = "CO on R/L (URF moveset)",
198
199 .estimate = estimate_coud_URF,
200 .ready = NULL,
201 .is_valid = validate_singlecw_ending,
202 .moveset = moveset_URF,
203
204 .pre_trans = rf,
205};
206
207Step
208cofb_URF = {
209 .shortname = "cofb-URF",
210 .name = "CO on F/B (URF moveset)",
211
212 .estimate = estimate_coud_URF,
213 .ready = NULL,
214 .is_valid = validate_singlecw_ending,
215 .moveset = moveset_URF,
216
217 .pre_trans = fd,
218};
219
220/* Misc corner steps *****************/
221Step
222cornershtr_HTM = {
223 .shortname = "chtr",
224 .name = "Solve corners to HTR state",
225
226 .estimate = estimate_cornershtr_HTM,
227 .ready = NULL,
228 .is_valid = validate_singlecw_ending,
229 .moveset = moveset_HTM,
230
231 .pre_trans = uf,
232};
233
234Step
235cornershtr_URF = {
236 .shortname = "chtr-URF",
237 .name = "Solve corners to HTR state (URF moveset)",
238
239 .estimate = estimate_cornershtr_URF,
240 .ready = NULL,
241 .is_valid = validate_singlecw_ending,
242 .moveset = moveset_URF,
243
244 .pre_trans = uf,
245};
246
247Step
248corners_HTM = {
249 .shortname = "corners",
250 .name = "Solve corners",
251
252 .estimate = estimate_corners_HTM,
253 .ready = NULL,
254 .is_valid = always_valid,
255 .moveset = moveset_HTM,
256
257 .pre_trans = uf,
258};
259
260Step
261corners_URF = {
262 .shortname = "corners-URF",
263 .name = "Solve corners (URF moveset)",
264
265 .estimate = estimate_corners_URF,
266 .ready = NULL,
267 .is_valid = always_valid,
268 .moveset = moveset_URF,
269
270 .pre_trans = uf,
271};
272
273/* DR steps **************************/
274Step
275drany_HTM = {
276 .shortname = "dr",
277 .name = "DR on any axis",
278
279 .estimate = estimate_drany_HTM,
280 .ready = check_centers,
281 .ready_msg = check_centers_msg,
282 .is_valid = validate_singlecw_ending,
283 .moveset = moveset_HTM,
284
285 .pre_trans = uf,
286};
287
288Step
289drud_HTM = {
290 .shortname = "drud",
291 .name = "DR on U/D",
292
293 .estimate = estimate_drud_HTM,
294 .ready = check_centers,
295 .ready_msg = check_centers_msg,
296 .is_valid = validate_singlecw_ending,
297 .moveset = moveset_HTM,
298
299 .pre_trans = uf,
300};
301
302Step
303drrl_HTM = {
304 .shortname = "drrl",
305 .name = "DR on R/L",
306
307 .estimate = estimate_drud_HTM,
308 .ready = check_centers,
309 .ready_msg = check_centers_msg,
310 .is_valid = validate_singlecw_ending,
311 .moveset = moveset_HTM,
312
313 .pre_trans = rf,
314};
315
316Step
317drfb_HTM = {
318 .shortname = "drfb",
319 .name = "DR on F/B",
320
321 .estimate = estimate_drud_HTM,
322 .ready = check_centers,
323 .ready_msg = check_centers_msg,
324 .is_valid = validate_singlecw_ending,
325 .moveset = moveset_HTM,
326
327 .pre_trans = fd,
328};
329
330/* DR from EO */
331Step
332dr_eo = {
333 .shortname = "dr-eo",
334 .name = "DR without breaking EO (automatically detected)",
335
336 .estimate = estimate_dr_eofb,
337 .ready = check_eofb,
338 .ready_msg = check_eo_msg,
339 .is_valid = validate_singlecw_ending,
340 .moveset = moveset_eofb,
341
342 .detect = detect_pretrans_eofb,
343};
344
345Step
346dr_eofb = {
347 .shortname = "dr-eofb",
348 .name = "DR on U/D or R/L without breaking EO on F/B",
349
350 .estimate = estimate_dr_eofb,
351 .ready = check_eofb,
352 .ready_msg = check_eo_msg,
353 .is_valid = validate_singlecw_ending,
354 .moveset = moveset_eofb,
355
356 .pre_trans = uf,
357};
358
359Step
360dr_eorl = {
361 .shortname = "dr-eorl",
362 .name = "DR on U/D or F/B without breaking EO on R/L",
363
364 .estimate = estimate_dr_eofb,
365 .ready = check_eofb,
366 .ready_msg = check_eo_msg,
367 .is_valid = validate_singlecw_ending,
368 .moveset = moveset_eofb,
369
370 .pre_trans = ur,
371};
372
373Step
374dr_eoud = {
375 .shortname = "dr-eoud",
376 .name = "DR on R/L or F/B without breaking EO on U/R",
377
378 .estimate = estimate_dr_eofb,
379 .ready = check_eofb,
380 .ready_msg = check_eo_msg,
381 .is_valid = validate_singlecw_ending,
382 .moveset = moveset_eofb,
383
384 .pre_trans = fd,
385};
386
387Step
388drud_eofb = {
389 .shortname = "drud-eofb",
390 .name = "DR on U/D without breaking EO on F/B",
391
392 .estimate = estimate_drud_eofb,
393 .ready = check_eofb,
394 .ready_msg = check_eo_msg,
395 .is_valid = validate_singlecw_ending,
396 .moveset = moveset_eofb,
397
398 .pre_trans = uf,
399};
400
401Step
402drrl_eofb = {
403 .shortname = "drrl-eofb",
404 .name = "DR on R/L without breaking EO on F/B",
405
406 .estimate = estimate_drud_eofb,
407 .ready = check_eofb,
408 .ready_msg = check_eo_msg,
409 .is_valid = validate_singlecw_ending,
410 .moveset = moveset_eofb,
411
412 .pre_trans = rf,
413};
414
415Step
416drud_eorl = {
417 .shortname = "drud-eorl",
418 .name = "DR on U/D without breaking EO on R/L",
419
420 .estimate = estimate_drud_eofb,
421 .ready = check_eofb,
422 .ready_msg = check_eo_msg,
423 .is_valid = validate_singlecw_ending,
424 .moveset = moveset_eofb,
425
426 .pre_trans = ur,
427};
428
429Step
430drfb_eorl = {
431 .shortname = "drfb-eorl",
432 .name = "DR on F/B without breaking EO on R/L",
433
434 .estimate = estimate_drud_eofb,
435 .ready = check_eofb,
436 .ready_msg = check_eo_msg,
437 .is_valid = validate_singlecw_ending,
438 .moveset = moveset_eofb,
439
440 .pre_trans = fr,
441};
442
443Step
444drfb_eoud = {
445 .shortname = "drfb-eoud",
446 .name = "DR on F/B without breaking EO on U/D",
447
448 .estimate = estimate_drud_eofb,
449 .ready = check_eofb,
450 .ready_msg = check_eo_msg,
451 .is_valid = validate_singlecw_ending,
452 .moveset = moveset_eofb,
453
454 .pre_trans = fd,
455};
456
457Step
458drrl_eoud = {
459 .shortname = "drrl-eoud",
460 .name = "DR on R/L without breaking EO on U/D",
461
462 .estimate = estimate_drud_eofb,
463 .ready = check_eofb,
464 .ready_msg = check_eo_msg,
465 .is_valid = validate_singlecw_ending,
466 .moveset = moveset_eofb,
467
468 .pre_trans = rd,
469};
470
471/* DR finish steps */
472Step
473dranyfin_DR = {
474 .shortname = "drfin",
475 .name = "DR finish on any axis without breaking DR",
476
477 .estimate = estimate_drudfin_drud,
478 .ready = check_drud,
479 .ready_msg = check_drany_msg,
480 .is_valid = always_valid,
481 .moveset = moveset_drud,
482
483 .detect = detect_pretrans_drud,
484};
485
486Step
487drudfin_drud = {
488 .shortname = "drudfin",
489 .name = "DR finish on U/D without breaking DR",
490
491 .estimate = estimate_drudfin_drud,
492 .ready = check_drud,
493 .ready_msg = check_dr_msg,
494 .is_valid = always_valid,
495 .moveset = moveset_drud,
496
497 .pre_trans = uf,
498};
499
500Step
501drrlfin_drrl = {
502 .shortname = "drrlfin",
503 .name = "DR finish on R/L without breaking DR",
504
505 .estimate = estimate_drudfin_drud,
506 .ready = check_drud,
507 .ready_msg = check_dr_msg,
508 .is_valid = always_valid,
509 .moveset = moveset_drud,
510
511 .pre_trans = rf,
512};
513
514Step
515drfbfin_drfb = {
516 .shortname = "drfbfin",
517 .name = "DR finish on F/B without breaking DR",
518
519 .estimate = estimate_drudfin_drud,
520 .ready = check_drud,
521 .ready_msg = check_dr_msg,
522 .is_valid = always_valid,
523 .moveset = moveset_drud,
524
525 .pre_trans = fd,
526};
527
528/* HTR from DR */
529Step
530htr_any = {
531 .shortname = "htr",
532 .name = "HTR from DR",
533
534 .estimate = estimate_htr_drud,
535 .ready = check_drud,
536 .ready_msg = check_drany_msg,
537 .is_valid = validate_singlecw_ending,
538 .moveset = moveset_drud,
539
540 .detect = detect_pretrans_drud,
541};
542
543Step
544htr_drud = {
545 .shortname = "htr-drud",
546 .name = "HTR from DR on U/D",
547
548 .estimate = estimate_htr_drud,
549 .ready = check_drud,
550 .ready_msg = check_dr_msg,
551 .is_valid = validate_singlecw_ending,
552 .moveset = moveset_drud,
553
554 .pre_trans = uf,
555};
556
557Step
558htr_drrl = {
559 .shortname = "htr-drrl",
560 .name = "HTR from DR on R/L",
561
562 .estimate = estimate_htr_drud,
563 .ready = check_drud,
564 .ready_msg = check_dr_msg,
565 .is_valid = validate_singlecw_ending,
566 .moveset = moveset_drud,
567
568 .pre_trans = rf,
569};
570
571Step
572htr_drfb = {
573 .shortname = "htr-drfb",
574 .name = "HTR from DR on F/B",
575
576 .estimate = estimate_htr_drud,
577 .ready = check_drud,
578 .ready_msg = check_dr_msg,
579 .is_valid = validate_singlecw_ending,
580 .moveset = moveset_drud,
581
582 .pre_trans = fd,
583};
584
585/* HTR finish */
586Step
587htrfin_htr = {
588 .shortname = "htrfin",
589 .name = "HTR finish without breaking HTR",
590
591 .estimate = estimate_htrfin_htr,
592 .ready = check_htr,
593 .ready_msg = check_htr_msg,
594 .is_valid = always_valid,
595 .moveset = moveset_htr,
596
597 .pre_trans = uf,
598};
599
600Step *steps[NSTEPS] = {
601 &optimal_HTM, /* first is default */
602
603 &eoany_HTM,
604 &eofb_HTM,
605 &eorl_HTM,
606 &eoud_HTM,
607
608 &coany_HTM,
609 &coud_HTM,
610 &corl_HTM,
611 &cofb_HTM,
612
613 &coany_URF,
614 &coud_URF,
615 &corl_URF,
616 &cofb_URF,
617
618 &drany_HTM,
619 &drud_HTM,
620 &drrl_HTM,
621 &drfb_HTM,
622
623 &dr_eo,
624 &dr_eofb,
625 &dr_eorl,
626 &dr_eoud,
627 &drud_eofb,
628 &drrl_eofb,
629 &drud_eorl,
630 &drfb_eorl,
631 &drfb_eoud,
632 &drrl_eoud,
633
634 &dranyfin_DR,
635 &drudfin_drud,
636 &drrlfin_drrl,
637 &drfbfin_drfb,
638
639 &htr_any,
640 &htr_drud,
641 &htr_drrl,
642 &htr_drfb,
643
644 &htrfin_htr,
645
646 &cornershtr_HTM,
647 &cornershtr_URF,
648 &corners_HTM,
649 &corners_URF,
650};
651
652/* Standard checkers (return lower bound) ************************************/
653
654static int
655estimate_eoany_HTM(CubeTarget ct)
656{
657 int r1, r2, r3;
658
659 r1 = ptableval(&pd_eofb_HTM, ct.cube);
660 r2 = ptableval(&pd_eofb_HTM, apply_trans(ur, ct.cube));
661 r3 = ptableval(&pd_eofb_HTM, apply_trans(fd, ct.cube));
662
663 return MIN(r1, MIN(r2, r3));
664}
665
666static int
667estimate_eofb_HTM(CubeTarget ct)
668{
669 return ptableval(&pd_eofb_HTM, ct.cube);
670}
671
672static int
673estimate_coany_HTM(CubeTarget ct)
674{
675 int r1, r2, r3;
676
677 r1 = ptableval(&pd_coud_HTM, ct.cube);
678 r2 = ptableval(&pd_coud_HTM, apply_trans(rf, ct.cube));
679 r3 = ptableval(&pd_coud_HTM, apply_trans(fd, ct.cube));
680
681 return MIN(r1, MIN(r2, r3));
682}
683
684static int
685estimate_coud_HTM(CubeTarget ct)
686{
687 return ptableval(&pd_coud_HTM, ct.cube);
688}
689
690static int
691estimate_coany_URF(CubeTarget ct)
692{
693 int r1, r2, r3;
694 CubeTarget ct2, ct3;
695
696 ct2.cube = apply_trans(rf, ct.cube);
697 ct2.target = ct.target;
698
699 ct3.cube = apply_trans(fd, ct.cube);
700 ct3.target = ct.target;
701
702 r1 = estimate_coud_URF(ct);
703 r2 = estimate_coud_URF(ct2);
704 r3 = estimate_coud_URF(ct3);
705
706 return MIN(r1, MIN(r2, r3));
707}
708
709static int
710estimate_coud_URF(CubeTarget ct)
711{
712 /* TODO: I can improve this by checking first the orientation of
713 * the corner in DBL and use that as a reference */
714
715 CubeTarget ct2 = {.cube = apply_move(z, ct.cube), .target = ct.target};
716 CubeTarget ct3 = {.cube = apply_move(x, ct.cube), .target = ct.target};
717
718 int ud = estimate_coud_HTM(ct);
719 int rl = estimate_coud_HTM(ct2);
720 int fb = estimate_coud_HTM(ct3);
721
722 return MIN(ud, MIN(rl, fb));
723}
724
725static int
726estimate_corners_HTM(CubeTarget ct)
727{
728 return ptableval(&pd_corners_HTM, ct.cube);
729}
730
731static int
732estimate_cornershtr_HTM(CubeTarget ct)
733{
734 return ptableval(&pd_cornershtr_HTM, ct.cube);
735}
736
737static int
738estimate_cornershtr_URF(CubeTarget ct)
739{
740 /* TODO: I can improve this by checking first the corner in DBL
741 * and use that as a reference */
742
743 int c, ret = 15;
744 Trans i;
745
746 for (i = 0; i < NROTATIONS; i++) {
747 ct.cube = apply_alg(rotation_alg(i), ct.cube);
748 c = estimate_cornershtr_HTM(ct);
749 ret = MIN(ret, c);
750 }
751
752 return ret;
753}
754
755static int
756estimate_corners_URF(CubeTarget ct)
757{
758 /* TODO: I can improve this by checking first the corner in DBL
759 * and use that as a reference */
760
761 int c, ret = 15;
762 Trans i;
763
764 for (i = 0; i < NROTATIONS; i++) {
765 ct.cube = apply_alg(rotation_alg(i), ct.cube);
766 c = estimate_corners_HTM(ct);
767 ret = MIN(ret, c);
768 }
769
770 return ret;
771}
772
773static int
774estimate_drany_HTM(CubeTarget ct)
775{
776 int r1, r2, r3;
777
778 r1 = ptableval(&pd_drud_sym16_HTM, ct.cube);
779 r2 = ptableval(&pd_drud_sym16_HTM, apply_trans(rf, ct.cube));
780 r3 = ptableval(&pd_drud_sym16_HTM, apply_trans(fd, ct.cube));
781
782 return MIN(r1, MIN(r2, r3));
783}
784
785static int
786estimate_drud_HTM(CubeTarget ct)
787{
788 return ptableval(&pd_drud_sym16_HTM, ct.cube);
789}
790
791static int
792estimate_drud_eofb(CubeTarget ct)
793{
794 return ptableval(&pd_drud_eofb, ct.cube);
795}
796
797static int
798estimate_dr_eofb(CubeTarget ct)
799{
800 int r1, r2;
801
802 r1 = ptableval(&pd_drud_eofb, ct.cube);
803 r2 = ptableval(&pd_drud_eofb, apply_trans(rf, ct.cube));
804
805 return MIN(r1, r2);
806}
807
808static int
809estimate_drudfin_drud(CubeTarget ct)
810{
811 int val = ptableval(&pd_drudfin_noE_sym16_drud, ct.cube);
812
813 if (val != 0)
814 return val;
815
816 return ct.cube.epose % 24 == 0 ? 0 : 1;
817}
818
819static int
820estimate_htr_drud(CubeTarget ct)
821{
822 return ptableval(&pd_htr_drud, ct.cube);
823}
824
825static int
826estimate_htrfin_htr(CubeTarget ct)
827{
828 return ptableval(&pd_htrfin_htr, ct.cube);
829}
830
831static int
832estimate_optimal_HTM(CubeTarget ct)
833{
834 int dr1, dr2, dr3, cor, ret;
835 Cube cube = ct.cube;
836
837 dr1 = ptableval(&pd_khuge_HTM, cube);
838 cor = estimate_corners_HTM(ct);
839 ret = MAX(dr1, cor);
840
841 if (ret > ct.target)
842 return ret;
843
844 cube = apply_trans(rf, ct.cube);
845 dr2 = ptableval(&pd_khuge_HTM, cube);
846 ret = MAX(ret, dr2);
847
848 if (ret > ct.target)
849 return ret;
850
851 cube = apply_trans(fd, ct.cube);
852 dr3 = ptableval(&pd_khuge_HTM, cube);
853
854 /* Michiel de Bondt's trick */
855 if (dr1 == dr2 && dr2 == dr3 && dr1 != 0)
856 dr3++;
857
858 return MAX(ret, dr3);
859}
860
861/* Validators ****************************************************************/
862
863static bool
864always_valid(Alg *alg)
865{
866 return true;
867}
868
869static bool
870validate_singlecw_ending(Alg *alg)
871{
872 int i;
873 bool nor, inv;
874 Move l2 = NULLMOVE, l1 = NULLMOVE, l2i = NULLMOVE, l1i = NULLMOVE;
875
876 for (i = 0; i < alg->len; i++) {
877 if (alg->inv[i]) {
878 l2i = l1i;
879 l1i = alg->move[i];
880 } else {
881 l2 = l1;
882 l1 = alg->move[i];
883 }
884 }
885
886 nor = l1 ==base_move(l1) && (!commute(l1, l2) ||l2 ==base_move(l2));
887 inv = l1i==base_move(l1i) && (!commute(l1i,l2i)||l2i==base_move(l2i));
888
889 return nor && inv;
890}
891
892/* Pre-transformation detectors **********************************************/
893
894static Trans
895detect_pretrans_eofb(Cube cube)
896{
897 Trans i;
898
899 for (i = 0; i < NROTATIONS; i++)
900 if (check_eofb(apply_trans(i, cube)))
901 return i;
902
903 return 0;
904}
905
906static Trans
907detect_pretrans_drud(Cube cube)
908{
909 Trans i;
910
911 for (i = 0; i < NROTATIONS; i++)
912 if (check_drud(apply_trans(i, cube)))
913 return i;
914
915 return 0;
916}
diff --git a/old/2021-11-10-beforeremovingchecker/steps.h b/old/2021-11-10-beforeremovingchecker/steps.h
new file mode 100644
index 0000000..aa3178c
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/steps.h
@@ -0,0 +1,10 @@
1#ifndef STEPS_H
2#define STEPS_H
3
4#include "pruning.h"
5
6#define NSTEPS 50
7
8extern Step * steps[NSTEPS];
9
10#endif
diff --git a/old/2021-11-10-beforeremovingchecker/symcoord.c b/old/2021-11-10-beforeremovingchecker/symcoord.c
new file mode 100644
index 0000000..9a4d49a
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/symcoord.c
@@ -0,0 +1,359 @@
1#include "symcoord.h"
2
3static Cube antindex_coud_sym16(uint64_t ind);
4static Cube antindex_cp_sym16(uint64_t ind);
5static Cube antindex_eofbepos_sym16(uint64_t ind);
6static Cube antindex_drud_sym16(uint64_t ind);
7static Cube antindex_drudfin_noE_sym16(uint64_t ind);
8static Cube antindex_khuge(uint64_t ind);
9
10static uint64_t index_coud_sym16(Cube cube);
11static uint64_t index_cp_sym16(Cube cube);
12static uint64_t index_eofbepos_sym16(Cube cube);
13static uint64_t index_drud_sym16(Cube cube);
14static uint64_t index_drudfin_noE_sym16(Cube cube);
15static uint64_t index_khuge(Cube cube);
16
17static void gensym(SymData *sd);
18static bool read_symdata_file(SymData *sd);
19static bool write_symdata_file(SymData *sd);
20
21/* Transformation groups and symmetry data ***********************************/
22
23static Trans
24trans_group_udfix[16] = {
25 uf, ur, ub, ul,
26 df, dr, db, dl,
27 uf_mirror, ur_mirror, ub_mirror, ul_mirror,
28 df_mirror, dr_mirror, db_mirror, dl_mirror,
29};
30
31static SymData
32sd_coud_16 = {
33 .filename = "sd_coud_16",
34 .coord = &coord_coud,
35 .sym_coord = &coord_coud_sym16,
36 .ntrans = 16,
37 .trans = trans_group_udfix
38};
39
40static SymData
41sd_cp_16 = {
42 .filename = "sd_cp_16",
43 .coord = &coord_cp,
44 .sym_coord = &coord_cp_sym16,
45 .ntrans = 16,
46 .trans = trans_group_udfix
47};
48
49static SymData
50sd_eofbepos_16 = {
51 .filename = "sd_eofbepos_16",
52 .coord = &coord_eofbepos,
53 .sym_coord = &coord_eofbepos_sym16,
54 .ntrans = 16,
55 .trans = trans_group_udfix
56};
57
58static int nsymdata = 3;
59static SymData * all_sd[] = {
60 &sd_coud_16,
61 &sd_cp_16,
62 &sd_eofbepos_16,
63};
64
65
66/* Coordinates and their implementation **************************************/
67
68Coordinate
69coord_eofbepos_sym16 = {
70 .index = index_eofbepos_sym16,
71 .cube = antindex_eofbepos_sym16,
72 .check = check_eofbepos,
73 .ntrans = 16,
74 .trans = trans_group_udfix,
75};
76
77Coordinate
78coord_coud_sym16 = {
79 .index = index_coud_sym16,
80 .cube = antindex_coud_sym16,
81 .check = check_coud,
82 .ntrans = 16,
83 .trans = trans_group_udfix,
84};
85
86Coordinate
87coord_cp_sym16 = {
88 .index = index_cp_sym16,
89 .cube = antindex_cp_sym16,
90 .check = check_cp,
91 .ntrans = 16,
92 .trans = trans_group_udfix,
93};
94
95Coordinate
96coord_drud_sym16 = {
97 .index = index_drud_sym16,
98 .cube = antindex_drud_sym16,
99 .check = check_drud,
100 .max = POW3TO7 * 64430,
101 .ntrans = 16,
102 .trans = trans_group_udfix,
103};
104
105Coordinate
106coord_drudfin_noE_sym16 = {
107 .index = index_drudfin_noE_sym16,
108 .cube = antindex_drudfin_noE_sym16,
109 .check = check_drudfin_noE,
110 .max = FACTORIAL8 * 2768,
111 .ntrans = 16,
112 .trans = trans_group_udfix,
113};
114
115Coordinate
116coord_khuge = {
117 .index = index_khuge,
118 .cube = antindex_khuge,
119 .check = check_khuge,
120 .max = POW3TO7 * FACTORIAL4 * 64430,
121 .ntrans = 16,
122 .trans = trans_group_udfix,
123};
124
125/* Functions *****************************************************************/
126
127static Cube
128antindex_coud_sym16(uint64_t ind)
129{
130 return sd_coud_16.rep[ind];
131}
132
133static Cube
134antindex_cp_sym16(uint64_t ind)
135{
136 return sd_cp_16.rep[ind];
137}
138
139static Cube
140antindex_eofbepos_sym16(uint64_t ind)
141{
142 return sd_eofbepos_16.rep[ind];
143}
144
145static Cube
146antindex_drud_sym16(uint64_t ind)
147{
148 Cube c;
149
150 c = antindex_eofbepos_sym16(ind/POW3TO7);
151 c.coud = ind % POW3TO7;
152 c.cofb = c.coud;
153 c.corl = c.coud;
154
155 return c;
156}
157
158static Cube
159antindex_drudfin_noE_sym16(uint64_t ind)
160{
161 Cube c1, c2;
162
163 c1 = coord_epud.cube(ind % FACTORIAL8);
164 c2 = antindex_cp_sym16(ind/FACTORIAL8);
165 c1.cp = c2.cp;
166
167 return c1;
168}
169
170static Cube
171antindex_khuge(uint64_t ind)
172{
173 Cube c;
174
175 c = antindex_eofbepos_sym16(ind/(FACTORIAL4*POW3TO7));
176 c.epose = ((c.epose / 24) * 24) + ((ind/POW3TO7) % 24);
177 c.coud = ind % POW3TO7;
178
179 return c;
180}
181
182static uint64_t
183index_coud_sym16(Cube cube)
184{
185 return sd_coud_16.class[coord_coud.index(cube)];
186}
187
188static uint64_t
189index_cp_sym16(Cube cube)
190{
191 return sd_cp_16.class[coord_cp.index(cube)];
192}
193
194static uint64_t
195index_drud_sym16(Cube cube)
196{
197 Trans t;
198 Cube c;
199
200 t = sd_eofbepos_16.transtorep[coord_eofbepos.index(cube)];
201 c = apply_trans(t, cube);
202
203 return index_eofbepos_sym16(c) * POW3TO7 + c.coud;
204}
205
206static uint64_t
207index_drudfin_noE_sym16(Cube cube)
208{
209 Trans t;
210 Cube c;
211
212 t = sd_cp_16.transtorep[coord_cp.index(cube)];
213 c = apply_trans(t, cube);
214
215 return index_cp_sym16(c) * FACTORIAL8 + coord_epud.index(c);
216}
217
218static uint64_t
219index_eofbepos_sym16(Cube cube)
220{
221 return sd_eofbepos_16.class[coord_eofbepos.index(cube)];
222}
223
224static uint64_t
225index_khuge(Cube cube)
226{
227 Trans t;
228 Cube c;
229 uint64_t a;
230
231 t = sd_eofbepos_16.transtorep[coord_eofbepos.index(cube)];
232 c = apply_trans(t, cube);
233 a = (index_eofbepos_sym16(c) * 24) + (c.epose % 24);
234
235 return a * POW3TO7 + c.coud;
236}
237
238/* Other functions ***********************************************************/
239
240static void
241gensym(SymData *sd)
242{
243 uint64_t i, in, nreps = 0;
244 int j;
245 Cube c, d;
246
247 if (sd->generated)
248 return;
249
250 sd->class = malloc(sd->coord->max * sizeof(uint64_t));
251 sd->rep = malloc(sd->coord->max * sizeof(Cube));
252 sd->transtorep = malloc(sd->coord->max * sizeof(Trans));
253
254 if (read_symdata_file(sd)) {
255 sd->generated = true;
256 return;
257 }
258
259 fprintf(stderr, "Cannot load %s, generating it\n", sd->filename);
260
261 for (i = 0; i < sd->coord->max; i++)
262 sd->class[i] = sd->coord->max + 1;
263
264 for (i = 0; i < sd->coord->max; i++) {
265 if (sd->class[i] == sd->coord->max + 1) {
266 c = sd->coord->cube(i);
267 sd->rep[nreps] = c;
268 for (j = 0; j < sd->ntrans; j++) {
269 d = apply_trans(sd->trans[j], c);
270 in = sd->coord->index(d);
271
272 if (sd->class[in] == sd->coord->max + 1) {
273 sd->class[in] = nreps;
274 sd->transtorep[in] =
275 inverse_trans(sd->trans[j]);
276 }
277 }
278 nreps++;
279 }
280 }
281
282 sd->sym_coord->max = nreps;
283 sd->rep = realloc(sd->rep, nreps * sizeof(Cube));
284 sd->generated = true;
285
286 fprintf(stderr, "Found %lu classes\n", nreps);
287
288 if (!write_symdata_file(sd))
289 fprintf(stderr, "Error writing SymData file\n");
290
291 return;
292}
293
294static bool
295read_symdata_file(SymData *sd)
296{
297 init_env();
298
299 FILE *f;
300 char fname[strlen(tabledir)+100];
301 uint64_t n = sd->coord->max, *sn = &sd->sym_coord->max;
302 bool r = true;
303
304 strcpy(fname, tabledir);
305 strcat(fname, "/");
306 strcat(fname, sd->filename);
307
308 if ((f = fopen(fname, "rb")) == NULL)
309 return false;
310
311 r = r && fread(&sd->sym_coord->max, sizeof(uint64_t), 1, f) == 1;
312 r = r && fread(sd->rep, sizeof(Cube), *sn, f) == *sn;
313 r = r && fread(sd->class, sizeof(uint64_t), n, f) == n;
314 r = r && fread(sd->transtorep, sizeof(Trans), n, f) == n;
315
316 fclose(f);
317 return r;
318}
319
320static bool
321write_symdata_file(SymData *sd)
322{
323 init_env();
324
325 FILE *f;
326 char fname[strlen(tabledir)+100];
327 uint64_t n = sd->coord->max, *sn = &sd->sym_coord->max;
328 bool r = true;
329
330 strcpy(fname, tabledir);
331 strcat(fname, "/");
332 strcat(fname, sd->filename);
333
334 if ((f = fopen(fname, "wb")) == NULL)
335 return false;
336
337 r = r && fwrite(&sd->sym_coord->max, sizeof(uint64_t), 1, f) == 1;
338 r = r && fwrite(sd->rep, sizeof(Cube), *sn, f) == *sn;
339 r = r && fwrite(sd->class, sizeof(uint64_t), n, f) == n;
340 r = r && fwrite(sd->transtorep, sizeof(Trans), n, f) == n;
341
342 fclose(f);
343 return r;
344}
345
346void
347init_symcoord()
348{
349 int i;
350
351 static bool initialized = false;
352 if (initialized)
353 return;
354 initialized = true;
355
356 for (i = 0; i < nsymdata; i++)
357 gensym(all_sd[i]);
358}
359
diff --git a/old/2021-11-10-beforeremovingchecker/symcoord.h b/old/2021-11-10-beforeremovingchecker/symcoord.h
new file mode 100644
index 0000000..f231c92
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/symcoord.h
@@ -0,0 +1,15 @@
1#ifndef SYMCOORD_H
2#define SYMCOORD_H
3
4#include "coord.h"
5
6extern Coordinate coord_coud_sym16;
7extern Coordinate coord_cp_sym16;
8extern Coordinate coord_eofbepos_sym16;
9extern Coordinate coord_drud_sym16;
10extern Coordinate coord_drudfin_noE_sym16;
11extern Coordinate coord_khuge;
12
13void init_symcoord();
14
15#endif
diff --git a/old/2021-11-10-beforeremovingchecker/trans.c b/old/2021-11-10-beforeremovingchecker/trans.c
new file mode 100644
index 0000000..ff3cdbb
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/trans.c
@@ -0,0 +1,372 @@
1#include "trans.h"
2
3/* Local functions ***********************************************************/
4
5static bool read_ttables_file();
6static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f);
7static bool write_ttables_file();
8
9/* Tables and other data *****************************************************/
10
11static int ep_mirror[12] = {
12 [UF] = UF, [UL] = UR, [UB] = UB, [UR] = UL,
13 [DF] = DF, [DL] = DR, [DB] = DB, [DR] = DL,
14 [FR] = FL, [FL] = FR, [BL] = BR, [BR] = BL
15};
16
17static int cp_mirror[8] = {
18 [UFR] = UFL, [UFL] = UFR, [UBL] = UBR, [UBR] = UBL,
19 [DFR] = DFL, [DFL] = DFR, [DBL] = DBR, [DBR] = DBL
20};
21
22static int cpos_mirror[6] = {
23 [U_center] = U_center, [D_center] = D_center,
24 [R_center] = L_center, [L_center] = R_center,
25 [F_center] = F_center, [B_center] = B_center
26};
27
28/* TODO Is there a more elegant way? */
29static char rotation_alg_string[100][NROTATIONS] = {
30 [uf] = "", [ur] = "y", [ub] = "y2", [ul] = "y3",
31 [df] = "z2", [dr] = "y z2", [db] = "x2", [dl] = "y3 z2",
32 [rf] = "z3", [rd] = "z3 y", [rb] = "z3 y2", [ru] = "z3 y3",
33 [lf] = "z", [ld] = "z y3", [lb] = "z y2", [lu] = "z y",
34 [fu] = "x y2", [fr] = "x y", [fd] = "x", [fl] = "x y3",
35 [bu] = "x3", [br] = "x3 y", [bd] = "x3 y2", [bl] = "x3 y3",
36};
37
38static int epose_source[NTRANS]; /* 0=epose, 1=eposs, 2=eposm */
39static int eposs_source[NTRANS];
40static int eposm_source[NTRANS];
41static int eofb_source[NTRANS]; /* 0=eoud, 1=eorl, 2=eofb */
42static int eorl_source[NTRANS];
43static int eoud_source[NTRANS];
44static int coud_source[NTRANS]; /* 0=coud, 1=corl, 2=cofb */
45static int cofb_source[NTRANS];
46static int corl_source[NTRANS];
47
48static int epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
49static int eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
50static int eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
51static int eo_ttable[NTRANS][POW2TO11];
52static int cp_ttable[NTRANS][FACTORIAL8];
53static int co_ttable[NTRANS][POW3TO7];
54static int cpos_ttable[NTRANS][FACTORIAL6];
55static Move moves_ttable[NTRANS][NMOVES];
56
57/* Local functions implementation ********************************************/
58
59void
60init_trans() {
61 static bool initialized = false;
62 if (initialized)
63 return;
64 initialized = true;
65
66 Cube aux, cube, c[3];
67 CubeArray epcp;
68 int i, eparr[12], eoarr[12], cparr[8], coarr[8];
69 unsigned int ui;
70 Move mi, move;
71 Trans m;
72
73 /* Compute sources */
74 for (i = 0; i < NTRANS; i++) {
75 cube = apply_alg(rotation_alg(i), (Cube){0});
76
77 epose_source[i] = edge_slice(what_edge_at(cube, FR));
78 eposs_source[i] = edge_slice(what_edge_at(cube, UR));
79 eposm_source[i] = edge_slice(what_edge_at(cube, UF));
80 eofb_source[i] = what_center_at(cube, F_center)/2;
81 eorl_source[i] = what_center_at(cube, R_center)/2;
82 eoud_source[i] = what_center_at(cube, U_center)/2;
83 coud_source[i] = what_center_at(cube, U_center)/2;
84 cofb_source[i] = what_center_at(cube, F_center)/2;
85 corl_source[i] = what_center_at(cube, R_center)/2;
86 }
87
88 if (read_ttables_file())
89 return;
90
91 fprintf(stderr, "Cannot load %s, generating it\n", "ttables");
92
93 /* Initialize tables */
94 for (m = 0; m < NTRANS; m++) {
95 epcp = (CubeArray){ .ep = eparr, .cp = cparr };
96 cube = apply_alg(rotation_alg(m), (Cube){0});
97 cube_to_arrays(cube, &epcp, pf_epcp);
98 if (m >= NROTATIONS) {
99 apply_permutation(ep_mirror, eparr, 12);
100 apply_permutation(cp_mirror, cparr, 8);
101 }
102
103 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
104 c[0] = admissible_ep((Cube){ .epose = ui }, pf_e);
105 c[1] = admissible_ep((Cube){ .eposs = ui }, pf_s);
106 c[2] = admissible_ep((Cube){ .eposm = ui }, pf_m);
107
108 cube = rotate_via_compose(m,c[epose_source[m]],pf_ep);
109 epose_ttable[m][ui] = cube.epose;
110
111 cube = rotate_via_compose(m,c[eposs_source[m]],pf_ep);
112 eposs_ttable[m][ui] = cube.eposs;
113
114 cube = rotate_via_compose(m,c[eposm_source[m]],pf_ep);
115 eposm_ttable[m][ui] = cube.eposm;
116 }
117 for (ui = 0; ui < POW2TO11; ui++ ) {
118 int_to_sum_zero_array(ui, 2, 12, eoarr);
119 apply_permutation(eparr, eoarr, 12);
120 eo_ttable[m][ui] = digit_array_to_int(eoarr, 11, 2);
121 }
122 for (ui = 0; ui < POW3TO7; ui++) {
123 int_to_sum_zero_array(ui, 3, 8, coarr);
124 apply_permutation(cparr, coarr, 8);
125 co_ttable[m][ui] = digit_array_to_int(coarr, 7, 3);
126 if (m >= NROTATIONS)
127 co_ttable[m][ui] =
128 invert_digits(co_ttable[m][ui], 3, 7);
129 }
130 for (ui = 0; ui < FACTORIAL8; ui++) {
131 cube = (Cube){ .cp = ui };
132 cube = rotate_via_compose(m, cube, pf_cp);
133 cp_ttable[m][ui] = cube.cp;
134 }
135 for (ui = 0; ui < FACTORIAL6; ui++) {
136 cube = (Cube){ .cpos = ui };
137 cube = rotate_via_compose(m, cube, pf_cpos);
138 cpos_ttable[m][ui] = cube.cpos;
139 }
140 for (mi = 0; mi < NMOVES; mi++) {
141 /* Old version:
142 *
143 aux = apply_trans(m, apply_move(mi, (Cube){0}));
144 for (move = 0; move < NMOVES; move++) {
145 cube = apply_move(inverse_move(move), aux);
146 mirr = apply_trans(uf_mirror, cube);
147 if (is_solved(cube) || is_solved(mirr))
148 moves_ttable[m][mi] = move;
149 }
150 */
151
152 aux = apply_trans(m, apply_move(mi, (Cube){0}));
153 for (move = 0; move < NMOVES; move++) {
154 cube = apply_move(inverse_move(move), aux);
155 if (is_solved(cube)) {
156 moves_ttable[m][mi] = move;
157 break;
158 }
159 }
160 }
161 }
162
163 if (!write_ttables_file())
164 fprintf(stderr, "Error writing ttables\n");
165}
166
167static bool
168read_ttables_file()
169{
170 init_env();
171
172 FILE *f;
173 char fname[strlen(tabledir)+20];
174 int b = sizeof(int);
175 bool r = true;
176 Move m;
177
178 /* Table sizes, used for reading and writing files */
179 uint64_t me[11] = {
180 [0] = FACTORIAL12/FACTORIAL8,
181 [1] = FACTORIAL12/FACTORIAL8,
182 [2] = FACTORIAL12/FACTORIAL8,
183 [3] = POW2TO11,
184 [4] = FACTORIAL8,
185 [5] = POW3TO7,
186 [6] = FACTORIAL6,
187 [7] = NMOVES
188 };
189
190 strcpy(fname, tabledir);
191 strcat(fname, "/");
192 strcat(fname, "ttables");
193
194 if ((f = fopen(fname, "rb")) == NULL)
195 return false;
196
197 for (m = 0; m < NTRANS; m++) {
198 r = r && fread(epose_ttable[m], b, me[0], f) == me[0];
199 r = r && fread(eposs_ttable[m], b, me[1], f) == me[1];
200 r = r && fread(eposm_ttable[m], b, me[2], f) == me[2];
201 r = r && fread(eo_ttable[m], b, me[3], f) == me[3];
202 r = r && fread(cp_ttable[m], b, me[4], f) == me[4];
203 r = r && fread(co_ttable[m], b, me[5], f) == me[5];
204 r = r && fread(cpos_ttable[m], b, me[6], f) == me[6];
205 r = r && fread(moves_ttable[m], b, me[7], f) == me[7];
206 }
207
208 fclose(f);
209 return r;
210}
211
212static Cube
213rotate_via_compose(Trans r, Cube c, PieceFilter f)
214{
215 static int zero12[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
216 static int zero8[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
217 static CubeArray ma = {
218 .ep = ep_mirror,
219 .eofb = zero12,
220 .eorl = zero12,
221 .eoud = zero12,
222 .cp = cp_mirror,
223 .coud = zero8,
224 .corl = zero8,
225 .cofb = zero8,
226 .cpos = cpos_mirror
227 };
228
229 Alg *inv = inverse_alg(rotation_alg(r));
230 Cube ret = {0};
231
232 if (r >= NROTATIONS)
233 ret = move_via_arrays(&ma, ret, f);
234 ret = apply_alg_generic(inv, ret, f, true);
235
236 ret = compose_filtered(c, ret, f);
237
238 ret = apply_alg_generic(rotation_alg(r), ret, f, true);
239 if (r >= NROTATIONS)
240 ret = move_via_arrays(&ma, ret, f);
241
242 free_alg(inv);
243 return ret;
244}
245
246static bool
247write_ttables_file()
248{
249 init_env();
250
251 FILE *f;
252 char fname[strlen(tabledir)+20];
253 bool r = true;
254 int b = sizeof(int);
255 Move m;
256
257 /* Table sizes, used for reading and writing files */
258 uint64_t me[11] = {
259 [0] = FACTORIAL12/FACTORIAL8,
260 [1] = FACTORIAL12/FACTORIAL8,
261 [2] = FACTORIAL12/FACTORIAL8,
262 [3] = POW2TO11,
263 [4] = FACTORIAL8,
264 [5] = POW3TO7,
265 [6] = FACTORIAL6,
266 [7] = NMOVES
267 };
268
269 strcpy(fname, tabledir);
270 strcat(fname, "/ttables");
271
272 if ((f = fopen(fname, "wb")) == NULL)
273 return false;
274
275 for (m = 0; m < NTRANS; m++) {
276 r = r && fwrite(epose_ttable[m], b, me[0], f) == me[0];
277 r = r && fwrite(eposs_ttable[m], b, me[1], f) == me[1];
278 r = r && fwrite(eposm_ttable[m], b, me[2], f) == me[2];
279 r = r && fwrite(eo_ttable[m], b, me[3], f) == me[3];
280 r = r && fwrite(cp_ttable[m], b, me[4], f) == me[4];
281 r = r && fwrite(co_ttable[m], b, me[5], f) == me[5];
282 r = r && fwrite(cpos_ttable[m], b, me[6], f) == me[6];
283 r = r && fwrite(moves_ttable[m], b, me[7], f) == me[7];
284 }
285
286 fclose(f);
287 return r;
288}
289
290/* Public functions **********************************************************/
291
292Cube
293apply_trans(Trans t, Cube cube)
294{
295 /*init_trans();*/
296
297 int aux_epos[3] = { cube.epose, cube.eposs, cube.eposm };
298 int aux_eo[3] = { cube.eoud, cube.eorl, cube.eofb };
299 int aux_co[3] = { cube.coud, cube.corl, cube.cofb };
300
301 return (Cube) {
302 .epose = epose_ttable[t][aux_epos[epose_source[t]]],
303 .eposs = eposs_ttable[t][aux_epos[eposs_source[t]]],
304 .eposm = eposm_ttable[t][aux_epos[eposm_source[t]]],
305 .eofb = eo_ttable[t][aux_eo[eofb_source[t]]],
306 .eorl = eo_ttable[t][aux_eo[eorl_source[t]]],
307 .eoud = eo_ttable[t][aux_eo[eoud_source[t]]],
308 .coud = co_ttable[t][aux_co[coud_source[t]]],
309 .corl = co_ttable[t][aux_co[corl_source[t]]],
310 .cofb = co_ttable[t][aux_co[cofb_source[t]]],
311 .cp = cp_ttable[t][cube.cp],
312 .cpos = cpos_ttable[t][cube.cpos]
313 };
314}
315
316Trans
317inverse_trans(Trans t)
318{
319 /* TODO is there a more elegant way? */
320 static Trans inverse_trans_aux[NTRANS] = {
321 [uf] = uf, [ur] = ul, [ul] = ur, [ub] = ub,
322 [df] = df, [dr] = dr, [dl] = dl, [db] = db,
323 [rf] = lf, [rd] = bl, [rb] = rb, [ru] = fr,
324 [lf] = rf, [ld] = br, [lb] = lb, [lu] = fl,
325 [fu] = fu, [fr] = ru, [fd] = bu, [fl] = lu,
326 [bu] = fd, [br] = ld, [bd] = bd, [bl] = rd,
327
328 [uf_mirror] = uf_mirror, [ur_mirror] = ur_mirror,
329 [ul_mirror] = ul_mirror, [ub_mirror] = ub_mirror,
330 [df_mirror] = df_mirror, [dr_mirror] = dl_mirror,
331 [dl_mirror] = dr_mirror, [db_mirror] = db_mirror,
332 [rf_mirror] = rf_mirror, [rd_mirror] = br_mirror,
333 [rb_mirror] = lb_mirror, [ru_mirror] = fl_mirror,
334 [lf_mirror] = lf_mirror, [ld_mirror] = bl_mirror,
335 [lb_mirror] = rb_mirror, [lu_mirror] = fr_mirror,
336 [fu_mirror] = fu_mirror, [fr_mirror] = lu_mirror,
337 [fd_mirror] = bu_mirror, [fl_mirror] = ru_mirror,
338 [bu_mirror] = fd_mirror, [br_mirror] = rd_mirror,
339 [bd_mirror] = bd_mirror, [bl_mirror] = ld_mirror
340 };
341
342 return inverse_trans_aux[t];
343}
344
345Alg *
346rotation_alg(Trans t)
347{
348 int i;
349
350 static Alg *rotation_alg_arr[NROTATIONS];
351 static bool initialized = false;
352
353 if (!initialized) {
354 for (i = 0; i < NROTATIONS; i++)
355 rotation_alg_arr[i] = new_alg(rotation_alg_string[i]);
356
357 initialized = true;
358 }
359
360 return rotation_alg_arr[t % NROTATIONS];
361}
362
363void
364transform_alg(Trans t, Alg *alg)
365{
366 int i;
367
368 /*init_trans();*/
369
370 for (i = 0; i < alg->len; i++)
371 alg->move[i] = moves_ttable[t][alg->move[i]];
372}
diff --git a/old/2021-11-10-beforeremovingchecker/trans.h b/old/2021-11-10-beforeremovingchecker/trans.h
new file mode 100644
index 0000000..2eda568
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/trans.h
@@ -0,0 +1,13 @@
1#ifndef TRANS_H
2#define TRANS_H
3
4#include "moves.h"
5
6Cube apply_trans(Trans t, Cube cube);
7Trans inverse_trans(Trans t);
8Alg * rotation_alg(Trans i);
9void transform_alg(Trans i, Alg *alg);
10
11void init_trans();
12
13#endif
diff --git a/old/2021-11-10-beforeremovingchecker/utils.c b/old/2021-11-10-beforeremovingchecker/utils.c
new file mode 100644
index 0000000..f72a00e
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/utils.c
@@ -0,0 +1,274 @@
1#include "utils.h"
2
3void
4apply_permutation(int *perm, int *set, int n)
5{
6 int *aux = malloc(n * sizeof(int));
7 int i;
8
9 if (!is_perm(perm, n))
10 return;
11
12 for (i = 0; i < n; i++)
13 aux[i] = set[perm[i]];
14
15 memcpy(set, aux, n * sizeof(int));
16 free(aux);
17}
18
19int
20binomial(int n, int k)
21{
22 if (n < 0 || k < 0 || k > n)
23 return 0;
24
25 return factorial(n) / (factorial(k) * factorial(n-k));
26}
27
28int
29digit_array_to_int(int *a, int n, int b)
30{
31 int i, ret = 0, p = 1;
32
33 for (i = 0; i < n; i++, p *= b)
34 ret += a[i] * p;
35
36 return ret;
37}
38
39int
40factorial(int n)
41{
42 int i, ret = 1;
43
44 if (n < 0)
45 return 0;
46
47 for (i = 1; i <= n; i++)
48 ret *= i;
49
50 return ret;
51}
52
53void
54index_to_perm(int p, int n, int *r)
55{
56 int *a = malloc(n * sizeof(int));
57 int i, j, c;
58
59 for (i = 0; i < n; i++)
60 a[i] = 0;
61
62 if (p < 0 || p >= factorial(n))
63 for (i = 0; i < n; i++)
64 r[i] = -1;
65
66 for (i = 0; i < n; i++) {
67 c = 0;
68 j = 0;
69 while (c <= p / factorial(n-i-1))
70 c += a[j++] ? 0 : 1;
71 r[i] = j-1;
72 a[j-1] = 1;
73 p %= factorial(n-i-1);
74 }
75
76 free(a);
77}
78
79void
80index_to_subset(int s, int n, int k, int *r)
81{
82 int i, j, v;
83
84 if (s < 0 || s >= binomial(n, k)) {
85 for (i = 0; i < n; i++)
86 r[i] = -1;
87 return;
88 }
89
90 for (i = 0; i < n; i++) {
91 if (k == n-i) {
92 for (j = i; j < n; j++)
93 r[j] = 1;
94 return;
95 }
96
97 if (k == 0) {
98 for (j = i; j < n; j++)
99 r[j] = 0;
100 return;
101 }
102
103 v = binomial(n-i-1, k);
104 if (s >= v) {
105 r[i] = 1;
106 k--;
107 s -= v;
108 } else {
109 r[i] = 0;
110 }
111 }
112}
113
114void
115int_to_digit_array(int a, int b, int n, int *r)
116{
117 int i;
118
119 if (b <= 1)
120 for (i = 0; i < n; i++)
121 r[i] = 0;
122 else
123 for (i = 0; i < n; i++, a /= b)
124 r[i] = a % b;
125}
126
127void
128int_to_sum_zero_array(int x, int b, int n, int *a)
129{
130 int i, s = 0;
131
132 if (b <= 1) {
133 for (i = 0; i < n; i++)
134 a[i] = 0;
135 } else {
136 int_to_digit_array(x, b, n-1, a);
137 for (i = 0; i < n - 1; i++)
138 s = (s + a[i]) % b;
139 a[n-1] = (b - s) % b;
140 }
141}
142
143int
144invert_digits(int a, int b, int n)
145{
146 int i, ret, *r = malloc(n * sizeof(int));
147
148 int_to_digit_array(a, b, n, r);
149 for (i = 0; i < n; i++)
150 r[i] = (b-r[i]) % b;
151
152 ret = digit_array_to_int(r, n, b);
153 free(r);
154 return ret;
155}
156
157bool
158is_perm(int *a, int n)
159{
160 int *aux = malloc(n * sizeof(int));
161 int i;
162
163 for (i = 0; i < n; i++)
164 if (a[i] < 0 || a[i] >= n)
165 return false;
166 else
167 aux[a[i]] = 1;
168
169 for (i = 0; i < n; i++)
170 if (!aux[i])
171 return false;
172
173 free(aux);
174
175 return true;
176}
177
178bool
179is_subset(int *a, int n, int k)
180{
181 int i, sum = 0;
182
183 for (i = 0; i < n; i++)
184 sum += a[i] ? 1 : 0;
185
186 return sum == k;
187}
188
189int
190perm_sign(int *a, int n)
191{
192 int i, j, ret = 0;
193
194 if (!is_perm(a,n))
195 return -1;
196
197 for (i = 0; i < n; i++)
198 for (j = i+1; j < n; j++)
199 ret += (a[i] > a[j]) ? 1 : 0;
200
201 return ret % 2;
202}
203
204int
205perm_to_index(int *a, int n)
206{
207 int i, j, c, ret = 0;
208
209 if (!is_perm(a, n))
210 return -1;
211
212 for (i = 0; i < n; i++) {
213 c = 0;
214 for (j = i+1; j < n; j++)
215 c += (a[i] > a[j]) ? 1 : 0;
216 ret += factorial(n-i-1) * c;
217 }
218
219 return ret;
220}
221
222int
223powint(int a, int b)
224{
225 if (b < 0)
226 return 0;
227 if (b == 0)
228 return 1;
229
230 if (b % 2)
231 return a * powint(a, b-1);
232 else
233 return powint(a*a, b/2);
234}
235
236int
237subset_to_index(int *a, int n, int k)
238{
239 int i, ret = 0;
240
241 if (!is_subset(a, n, k))
242 return binomial(n, k);
243
244 for (i = 0; i < n; i++) {
245 if (k == n-i)
246 return ret;
247 if (a[i]) {
248 ret += binomial(n-i-1, k);
249 k--;
250 }
251 }
252
253 return ret;
254}
255
256void
257sum_arrays_mod(int *src, int *dst, int n, int m)
258{
259 int i;
260
261 for (i = 0; i < n; i++)
262 dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m;
263}
264
265void
266swap(int *a, int *b)
267{
268 int aux;
269
270 aux = *a;
271 *a = *b;
272 *b = aux;
273}
274
diff --git a/old/2021-11-10-beforeremovingchecker/utils.h b/old/2021-11-10-beforeremovingchecker/utils.h
new file mode 100644
index 0000000..80c33ae
--- /dev/null
+++ b/old/2021-11-10-beforeremovingchecker/utils.h
@@ -0,0 +1,41 @@
1#ifndef UTILS_H
2#define UTILS_H
3
4#include <stdbool.h>
5#include <stdlib.h>
6#include <string.h>
7
8#define POW2TO6 64ULL
9#define POW2TO11 2048ULL
10#define POW2TO12 4096ULL
11#define POW3TO7 2187ULL
12#define POW3TO8 6561ULL
13#define FACTORIAL4 24ULL
14#define FACTORIAL6 720ULL
15#define FACTORIAL7 5040ULL
16#define FACTORIAL8 40320ULL
17#define FACTORIAL12 479001600ULL
18#define BINOM12ON4 495ULL
19#define BINOM8ON4 70ULL
20#define MIN(a,b) (((a) < (b)) ? (a) : (b))
21#define MAX(a,b) (((a) > (b)) ? (a) : (b))
22
23void apply_permutation(int *perm, int *set, int n);
24int binomial(int n, int k);
25int digit_array_to_int(int *a, int n, int b);
26int factorial(int n);
27void index_to_perm(int p, int n, int *r);
28void index_to_subset(int s, int n, int k, int *r);
29void int_to_digit_array(int a, int b, int n, int *r);
30void int_to_sum_zero_array(int x, int b, int n, int *a);
31int invert_digits(int a, int b, int n);
32bool is_perm(int *a, int n);
33bool is_subset(int *a, int n, int k);
34int perm_sign(int *a, int n);
35int perm_to_index(int *a, int n);
36int powint(int a, int b);
37int subset_to_index(int *a, int n, int k);
38void sum_arrays_mod(int *src, int *dst, int n, int m);
39void swap(int *a, int *b);
40
41#endif
diff --git a/old/backup-manysteps-pretrans/steps.c b/old/backup-manysteps-pretrans/steps.c
new file mode 100644
index 0000000..e4d79cd
--- /dev/null
+++ b/old/backup-manysteps-pretrans/steps.c
@@ -0,0 +1,369 @@
1#include "steps.h"
2
3/* Check functions ***********************************************************/
4
5static int check_nothing(Cube cube);
6static int check_eofb_HTM(Cube cube);
7static int check_coud_HTM(Cube cube);
8static int check_coud_URF(Cube cube);
9static int check_corners_HTM(Cube cube);
10static int check_corners_URF(Cube cube);
11static int check_edges_HTM(Cube cube);
12static int check_drud_HTM(Cube cube);
13static int check_optimal_HTM(Cube cube);
14
15
16/* Index functions ***********************************************************/
17
18static uint64_t index_eofb(Cube cube);
19static uint64_t index_coud(Cube cube);
20static uint64_t index_corners(Cube cube);
21static uint64_t index_ep(Cube cube);
22static uint64_t index_drud(Cube cube);
23
24
25/* Steps *********************************************************************/
26
27Step
28eofb_HTM = {
29 .check = check_eofb_HTM,
30 .ready = check_nothing,
31 .pre_trans = uf,
32 .moveset = moveset_HTM
33};
34
35Step
36eorl_HTM = {
37 .check = check_eofb_HTM,
38 .ready = check_nothing,
39 .pre_trans = ur,
40 .moveset = moveset_HTM
41};
42
43Step
44eoud_HTM = {
45 .check = check_eofb_HTM,
46 .ready = check_nothing,
47 .pre_trans = bu,
48 .moveset = moveset_HTM
49};
50
51Step
52coud_HTM = {
53 .check = check_coud_HTM,
54 .ready = check_nothing,
55 .pre_trans = uf,
56 .moveset = moveset_HTM
57};
58
59Step
60corl_HTM = {
61 .check = check_coud_HTM,
62 .ready = check_nothing,
63 .pre_trans = rf,
64 .moveset = moveset_HTM
65};
66
67Step
68cofb_HTM = {
69 .check = check_coud_HTM,
70 .ready = check_nothing,
71 .pre_trans = fd,
72 .moveset = moveset_HTM
73};
74
75Step
76coud_URF = {
77 .check = check_coud_URF,
78 .ready = check_nothing,
79 .pre_trans = uf,
80 .moveset = moveset_URF
81};
82
83Step
84corl_URF = {
85 .check = check_coud_URF,
86 .ready = check_nothing,
87 .pre_trans = rf,
88 .moveset = moveset_URF
89};
90
91Step
92cofb_URF = {
93 .check = check_coud_URF,
94 .ready = check_nothing,
95 .pre_trans = fd,
96 .moveset = moveset_URF
97};
98
99Step
100corners_HTM = {
101 .check = check_corners_HTM,
102 .ready = check_nothing,
103 .pre_trans = uf,
104 .moveset = moveset_HTM
105};
106
107Step
108corners_URF = {
109 .check = check_corners_URF,
110 .ready = check_nothing,
111 .pre_trans = uf,
112 .moveset = moveset_URF
113};
114
115Step
116edges_HTM = {
117 .check = check_edges_HTM,
118 .ready = check_nothing,
119 .pre_trans = uf,
120 .moveset = moveset_HTM
121};
122
123Step
124drud_HTM = {
125 .check = check_drud_HTM,
126 .ready = check_nothing,
127 .pre_trans = uf,
128 .moveset = moveset_HTM
129};
130
131Step
132optimal_HTM = {
133 .check = check_optimal_HTM,
134 .ready = check_nothing,
135 .pre_trans = uf,
136 .moveset = moveset_HTM
137};
138
139
140/* Pruning tables ************************************************************/
141
142PruneData
143pd_eofb_HTM = {
144 .filename = "ptable_eofb_HTM",
145 .size = POW2TO11,
146 .index = index_eofb,
147 .moveset = moveset_HTM
148};
149
150PruneData
151pd_coud_HTM = {
152 .filename = "ptable_coud_HTM",
153 .size = POW3TO7,
154 .index = index_coud,
155 .moveset = moveset_HTM
156};
157
158PruneData
159pd_corners_HTM = {
160 .filename = "ptable_corners_HTM",
161 .size = POW3TO7 * FACTORIAL8,
162 .index = index_corners,
163 .moveset = moveset_HTM
164};
165
166PruneData
167pd_ep_HTM = {
168 .filename = "ptable_ep_HTM",
169 .size = FACTORIAL12,
170 .index = index_ep,
171 .moveset = moveset_HTM
172};
173
174PruneData
175pd_drud_HTM = {
176 .filename = "ptable_drud_HTM",
177 .size = POW2TO11 * POW3TO7 * BINOM12ON4,
178 .index = index_drud,
179 .moveset = moveset_HTM
180};
181
182
183/* Check functions implementation ********************************************/
184
185static int
186check_nothing(Cube cube)
187{
188 /* At least we check that it is admissible */
189 return is_admissible(cube);
190}
191
192static int
193check_eofb_HTM(Cube cube)
194{
195 if (!pd_eofb_HTM.generated)
196 generate_ptable(&pd_eofb_HTM);
197
198 return PTABLEVAL(pd_eofb_HTM.ptable, cube.eofb);
199}
200
201static int
202check_coud_HTM(Cube cube)
203{
204 if (!pd_coud_HTM.generated)
205 generate_ptable(&pd_coud_HTM);
206
207 return PTABLEVAL(pd_coud_HTM.ptable, cube.coud);
208}
209
210static int
211check_coud_URF(Cube cube)
212{
213 /* TODO: I can improve this by checking first the orientation of
214 * the corner in DBL and use that as a reference */
215
216 int ud = check_coud_HTM(cube);
217 int rl = check_coud_HTM(apply_move(z, cube));
218 int fb = check_coud_HTM(apply_move(x, cube));
219
220 return MIN(ud, MIN(rl, fb));
221}
222
223static int
224check_corners_HTM(Cube cube)
225{
226 if (!pd_corners_HTM.generated)
227 generate_ptable(&pd_corners_HTM);
228
229 return PTABLEVAL(pd_corners_HTM.ptable, index_corners(cube));
230}
231
232static int
233check_corners_URF(Cube cube)
234{
235 /* TODO: I can improve this by checking first the corner in DBL
236 * and use that as a reference */
237
238 int ret = 15;
239 Trans i;
240
241 for (i = 0; i < NROTATIONS; i++)
242 ret = MIN(ret,check_corners_HTM(apply_alg(trans_alg(i),cube)));
243
244 return ret;
245}
246
247static int
248check_edges_HTM(Cube cube)
249{
250 int ret = 0;
251
252 if (!pd_ep_HTM.generated)
253 generate_ptable(&pd_ep_HTM);
254
255 ret = MAX(ret, PTABLEVAL(pd_ep_HTM.ptable, index_ep(cube)));
256 ret = MAX(ret, check_eofb_HTM(cube));
257 ret = MAX(ret, check_eofb_HTM(apply_trans(ur, cube)));
258 ret = MAX(ret, check_eofb_HTM(apply_trans(fd, cube)));
259
260 return ret;
261}
262
263static int
264check_drud_HTM(Cube cube)
265{
266 if (!pd_drud_HTM.generated)
267 generate_ptable(&pd_drud_HTM);
268
269 return PTABLEVAL(pd_drud_HTM.ptable, index_drud(cube));
270}
271
272static int
273check_optimal_HTM(Cube cube)
274{
275 int dr1, dr2, dr3, drmax, cor; /*ep;*/
276
277 if (!pd_drud_HTM.generated)
278 generate_ptable(&pd_drud_HTM);
279 if (!pd_corners_HTM.generated)
280 generate_ptable(&pd_corners_HTM);
281 /*
282 *if (!pd_ep_HTM.generated)
283 * generate_ptable(&pd_ep_HTM);
284 */
285
286 dr1 = PTABLEVAL(pd_drud_HTM.ptable, index_drud(cube));
287 dr2 = PTABLEVAL(pd_drud_HTM.ptable, index_drud(apply_trans(rf, cube)));
288 dr3 = PTABLEVAL(pd_drud_HTM.ptable, index_drud(apply_trans(fd, cube)));
289
290 drmax = MAX(dr1, MAX(dr2, dr3));
291 if (dr1 == dr2 && dr2 == dr3 && dr1 != 0)
292 drmax++;
293
294 cor = PTABLEVAL(pd_corners_HTM.ptable, index_corners(cube));
295 /* ep = PTABLEVAL(pd_ep_HTM.ptable, index_ep(cube)); */
296
297 /*return MAX(drmax, MAX(ep, cor));*/
298 if (drmax == 0 && cor == 0)
299 return is_solved(cube, false) ? 0 : 1;
300 return MAX(drmax, cor);
301}
302
303
304/* Index functions implementation ********************************************/
305
306static uint64_t
307index_eofb(Cube cube)
308{
309 return cube.eofb;
310}
311
312static uint64_t
313index_coud(Cube cube)
314{
315 return cube.coud;
316}
317
318static uint64_t
319index_corners(Cube cube)
320{
321 return cube.coud * FACTORIAL8 + cube.cp;
322}
323
324static uint64_t
325index_ep(Cube cube)
326{
327 uint64_t a, b, c;
328
329 a = cube.eposs;
330 b = (cube.epose % FACTORIAL4) + epos_dependent_cube(cube)*FACTORIAL4;
331 c = cube.eposm % FACTORIAL4;
332
333 b *= FACTORIAL4 * BINOM12ON4;
334 c *= FACTORIAL4 * BINOM12ON4 * FACTORIAL4 * BINOM8ON4;
335
336 return a + b + c;
337}
338
339static uint64_t
340index_drud(Cube cube)
341{
342 uint64_t a, b, c;
343
344 a = cube.eofb;
345 b = cube.coud;
346 c = cube.epose / FACTORIAL4;
347
348 b *= POW2TO11;
349 c *= POW2TO11 * POW3TO7;
350
351 return a + b + c;
352}
353
354/* Movesets ******************************************************************/
355
356bool
357moveset_HTM(Move m)
358{
359 return m >= U && m <= B3;
360}
361
362bool
363moveset_URF(Move m)
364{
365 Move b = base_move(m);
366
367 return b == U || b == R || b == F;
368}
369
diff --git a/old/backup-manysteps-pretrans/steps.h b/old/backup-manysteps-pretrans/steps.h
new file mode 100644
index 0000000..b218e04
--- /dev/null
+++ b/old/backup-manysteps-pretrans/steps.h
@@ -0,0 +1,36 @@
1#ifndef STEPS_H
2#define STEPS_H
3
4#include "cube.h"
5
6/* Steps *********************************************************************/
7
8extern Step eofb_HTM;
9extern Step eorl_HTM;
10extern Step eoud_HTM;
11extern Step coud_HTM;
12extern Step corl_HTM;
13extern Step cofb_HTM;
14extern Step coud_URF;
15extern Step corl_URF;
16extern Step cofb_URF;
17extern Step corners_HTM;
18extern Step corners_URF;
19extern Step edges_HTM;
20extern Step drud_HTM;
21extern Step optimal_HTM;
22
23/* Pruning tables ************************************************************/
24
25extern PruneData pd_eofb_HTM;
26extern PruneData pd_coud_HTM;
27extern PruneData pd_corners_HTM;
28extern PruneData pd_ep_HTM;
29extern PruneData pd_drud_HTM;
30
31/* Movesets ******************************************************************/
32
33bool moveset_HTM(Move m);
34bool moveset_URF(Move m);
35
36#endif
diff --git a/old/coord.c b/old/coord.c
new file mode 100644
index 0000000..cd2da69
--- /dev/null
+++ b/old/coord.c
@@ -0,0 +1,1014 @@
1#include "coord.h"
2
3static Cube admissible_eos_from_eofbepos(Cube cube);
4static Cube antindex_eofb(uint64_t ind);
5static Cube antindex_eofbepos(uint64_t ind);
6static Cube antindex_epud(uint64_t ind);
7static Cube antindex_coud(uint64_t ind);
8static Cube antindex_corners(uint64_t ind);
9static Cube antindex_cp(uint64_t ind);
10static Cube antindex_cornershtr(uint64_t ind);
11static Cube antindex_drud(uint64_t ind);
12static Cube antindex_coud_sym16(uint64_t ind);
13static Cube antindex_cp_sym16(uint64_t ind);
14static Cube antindex_eofbepos_sym16(uint64_t ind);
15static Cube antindex_drud_sym16(uint64_t ind);
16static Cube antindex_drud_eofb(uint64_t ind);
17static Cube antindex_drudfin_noE_sym16(uint64_t ind);
18static Cube antindex_htrfin(uint64_t ind);
19static Cube antindex_khuge(uint64_t ind);
20static int epos_dependent_pos(int pos1, int pos2);
21static void gensym(SymData *sd);
22static uint64_t index_eofb(Cube cube);
23static uint64_t index_eofbepos(Cube cube);
24static uint64_t index_epud(Cube cube);
25static uint64_t index_coud(Cube cube);
26static uint64_t index_corners(Cube cube);
27static uint64_t index_cp(Cube cube);
28static uint64_t index_cornershtr(Cube cube);
29static uint64_t index_drud(Cube cube);
30static uint64_t index_coud_sym16(Cube cube);
31static uint64_t index_cp_sym16(Cube cube);
32static uint64_t index_eofbepos_sym16(Cube cube);
33static uint64_t index_drud_sym16(Cube cube);
34static uint64_t index_drud_eofb(Cube cube);
35static uint64_t index_drudfin_noE_sym16(Cube cube);
36static uint64_t index_htrfin(Cube cube);
37static uint64_t index_khuge(Cube cube);
38static void init_cphtr_cosets();
39static void init_cphtr_left_cosets_bfs(int i, int c);
40static void init_cphtr_right_cosets_color(int i, int c);
41static void init_symdata();
42static bool read_symdata_file(SymData *sd);
43static bool write_symdata_file(SymData *sd);
44
45/* All sorts of useful costants and tables **********************************/
46
47/* TODO: Can I move inside functions that use them?
48 Maybe I need to pass them as argument to some
49 secondary function */
50static int cphtr_left_cosets[FACTORIAL8];
51static int cphtr_right_cosets[FACTORIAL8];
52static int cphtr_right_rep[BINOM8ON4*6];
53
54
55/* Symmetry data for some coordinates ****************************************/
56
57static Trans
58trans_group_trivial[1] = { uf };
59
60static Trans
61trans_group_udfix[16] = {
62 uf, ur, ub, ul,
63 df, dr, db, dl,
64 uf_mirror, ur_mirror, ub_mirror, ul_mirror,
65 df_mirror, dr_mirror, db_mirror, dl_mirror,
66};
67
68SymData
69sd_coud_16 = {
70 .filename = "sd_coud_16",
71 .coord = &coord_coud,
72 .sym_coord = &coord_coud_sym16,
73 .ntrans = 16,
74 .trans = trans_group_udfix
75};
76
77SymData
78sd_cp_16 = {
79 .filename = "sd_cp_16",
80 .coord = &coord_cp,
81 .sym_coord = &coord_cp_sym16,
82 .ntrans = 16,
83 .trans = trans_group_udfix
84};
85
86SymData
87sd_eofbepos_16 = {
88 .filename = "sd_eofbepos_16",
89 .coord = &coord_eofbepos,
90 .sym_coord = &coord_eofbepos_sym16,
91 .ntrans = 16,
92 .trans = trans_group_udfix
93};
94
95static int n_all_symdata = 3;
96static SymData * all_sd[3] = {
97 &sd_coud_16,
98 &sd_cp_16,
99 &sd_eofbepos_16,
100};
101
102/* Coordinates and their implementation **************************************/
103
104Coordinate
105coord_eofb = {
106 .index = index_eofb,
107 .cube = antindex_eofb,
108 .check = check_eofb,
109 .max = POW2TO11,
110 .ntrans = 1,
111 .trans = trans_group_trivial,
112};
113
114Coordinate
115coord_eofbepos = {
116 .index = index_eofbepos,
117 .cube = antindex_eofbepos,
118 .check = check_eofbepos,
119 .max = POW2TO11 * BINOM12ON4,
120 .ntrans = 1,
121 .trans = trans_group_trivial,
122};
123
124Coordinate
125coord_coud = {
126 .index = index_coud,
127 .cube = antindex_coud,
128 .check = check_coud,
129 .max = POW3TO7,
130 .ntrans = 1,
131 .trans = trans_group_trivial,
132};
133
134Coordinate
135coord_corners = {
136 .index = index_corners,
137 .cube = antindex_corners,
138 .check = check_corners,
139 .max = POW3TO7 * FACTORIAL8,
140 .ntrans = 1,
141 .trans = trans_group_trivial,
142};
143
144Coordinate
145coord_cp = {
146 .index = index_cp,
147 .cube = antindex_cp,
148 .check = check_cp,
149 .max = FACTORIAL8,
150 .ntrans = 1,
151 .trans = trans_group_trivial,
152};
153
154Coordinate
155coord_cornershtr = {
156 .index = index_cornershtr,
157 .cube = antindex_cornershtr,
158 .check = check_cornershtr,
159 .max = POW3TO7 * BINOM8ON4 * 6,
160 .ntrans = 1,
161 .trans = trans_group_trivial,
162};
163
164Coordinate
165coord_drud = {
166 .index = index_drud,
167 .cube = antindex_drud,
168 .check = check_drud,
169 .max = POW2TO11 * POW3TO7 * BINOM12ON4,
170 .ntrans = 1,
171 .trans = trans_group_trivial,
172};
173
174Coordinate
175coord_htrfin = {
176 .index = index_htrfin,
177 .cube = antindex_htrfin,
178 .check = check_htrfin,
179 .max = 24 * 24 * 24 *24 * 24,
180 .ntrans = 1,
181 .trans = trans_group_trivial,
182};
183
184Coordinate
185coord_drud_eofb = {
186 .index = index_drud_eofb,
187 .cube = antindex_drud_eofb,
188 .check = check_drud,
189 .max = POW3TO7 * BINOM12ON4,
190 .ntrans = 1,
191 .trans = trans_group_trivial,
192};
193
194Coordinate
195coord_eofbepos_sym16 = {
196 .index = index_eofbepos_sym16,
197 .cube = antindex_eofbepos_sym16,
198 .check = check_eofbepos,
199 .ntrans = 16,
200 .trans = trans_group_udfix,
201};
202
203Coordinate
204coord_coud_sym16 = {
205 .index = index_coud_sym16,
206 .cube = antindex_coud_sym16,
207 .check = check_coud,
208 .ntrans = 16,
209 .trans = trans_group_udfix,
210};
211
212Coordinate
213coord_cp_sym16 = {
214 .index = index_cp_sym16,
215 .cube = antindex_cp_sym16,
216 .check = check_cp,
217 .ntrans = 16,
218 .trans = trans_group_udfix,
219};
220
221Coordinate
222coord_drud_sym16 = {
223 .index = index_drud_sym16,
224 .cube = antindex_drud_sym16,
225 .check = check_drud,
226 .max = POW3TO7 * 64430,
227 .ntrans = 16,
228 .trans = trans_group_udfix,
229};
230
231Coordinate
232coord_drudfin_noE_sym16 = {
233 .index = index_drudfin_noE_sym16,
234 .cube = antindex_drudfin_noE_sym16,
235 .check = check_drudfin_noE,
236 .max = FACTORIAL8 * 2768,
237 .ntrans = 16,
238 .trans = trans_group_udfix,
239};
240
241Coordinate
242coord_khuge = {
243 .index = index_khuge,
244 .cube = antindex_khuge,
245 .check = check_khuge,
246 .max = POW3TO7 * FACTORIAL4 * 64430,
247 .ntrans = 16,
248 .trans = trans_group_udfix,
249};
250
251/* Functions *****************************************************************/
252
253static Cube
254admissible_eos_from_eofbepos(Cube cube)
255{
256 Edge e;
257 Cube ret;
258 CubeArray *arr = new_cubearray(cube, pf_all);
259
260 memcpy(arr->eorl, arr->eofb, 12 * sizeof(int));
261 memcpy(arr->eoud, arr->eofb, 12 * sizeof(int));
262
263 for (e = 0; e < 12; e++) {
264 if ((edge_slice(e) != 0 && edge_slice(arr->ep[e]) == 0) ||
265 (edge_slice(e) == 0 && edge_slice(arr->ep[e]) != 0))
266 arr->eorl[e] = 1 - arr->eorl[e];
267 if ((edge_slice(e) != 2 && edge_slice(arr->ep[e]) == 2) ||
268 (edge_slice(e) == 2 && edge_slice(arr->ep[e]) != 2))
269 arr->eoud[e] = 1 - arr->eoud[e];
270 }
271
272 ret = arrays_to_cube(arr, pf_all);
273 free_cubearray(arr, pf_all);
274
275 return ret;
276}
277
278
279static Cube
280antindex_eofb(uint64_t ind)
281{
282 return (Cube){ .eofb = ind, .eorl = ind, .eoud = ind };
283}
284
285static Cube
286antindex_eofbepos(uint64_t ind)
287{
288 static bool initialized = false;
289 static Cube admissible_ee_aux[POW2TO11*BINOM12ON4];
290 static Cube c1;
291 static int k;
292 static uint64_t ui;
293
294 if (!initialized) {
295 for (ui = 0; ui < POW2TO11*BINOM12ON4; ui++) {
296 k = (ui / POW2TO11) * 24;
297 c1 = admissible_ep((Cube){ .epose = k }, pf_e);
298 c1.eofb = ui % POW2TO11;
299 c1 = admissible_eos_from_eofbepos(c1);
300 admissible_ee_aux[ui] = c1;
301 }
302
303 initialized = true;
304 }
305
306 return admissible_ee_aux[ind];
307}
308
309static Cube
310antindex_epud(uint64_t ind)
311{
312 static bool initialized = false;
313 static Cube epud_aux[FACTORIAL8];
314 int a[12];
315 uint64_t ui;
316 CubeArray arr;
317
318 if (!initialized) {
319 a[FR] = FR;
320 a[FL] = FL;
321 a[BL] = BL;
322 a[BR] = BR;
323 for (ui = 0; ui < FACTORIAL8; ui++) {
324 index_to_perm(ui, 8, a);
325 arr.ep = a;
326 epud_aux[ui] = arrays_to_cube(&arr, pf_ep);
327 }
328
329 initialized = true;
330 }
331
332 return epud_aux[ind];
333}
334
335static Cube
336antindex_coud(uint64_t ind)
337{
338 return (Cube){ .coud = ind, .corl = ind, .cofb = ind };
339}
340
341static Cube
342antindex_corners(uint64_t ind)
343{
344 Cube c = {0};
345
346 c.coud = ind / FACTORIAL8;
347 c.cp = ind % FACTORIAL8;
348
349 return c;
350}
351
352static Cube
353antindex_cp(uint64_t ind)
354{
355 Cube c = {0};
356
357 c.cp = ind;
358
359 return c;
360}
361
362static Cube
363antindex_cornershtr(uint64_t ind)
364{
365 Cube c = anti_cphtr(ind % (BINOM8ON4 * 6));
366
367 c.coud = ind / (BINOM8ON4 * 6);
368
369 return c;
370}
371
372/* TODO: admissible eos and cos */
373/* DONE: temporary fix, make it better */
374/* Or maybe it's ok like this? */
375static Cube
376antindex_drud(uint64_t ind)
377{
378 uint64_t epos, eofb;
379 Cube c;
380
381 eofb = ind % POW2TO11;
382 epos = ind / (POW2TO11 * POW3TO7);
383 c = antindex_eofbepos(eofb + POW2TO11 * epos);
384
385 c.coud = (ind / POW2TO11) % POW3TO7;
386 c.corl = c.coud;
387 c.cofb = c.coud;
388
389 return c;
390}
391
392static Cube
393antindex_drud_eofb(uint64_t ind)
394{
395 return antindex_drud(ind * POW2TO11);
396}
397
398static Cube
399antindex_coud_sym16(uint64_t ind)
400{
401 return sd_coud_16.rep[ind];
402}
403
404static Cube
405antindex_cp_sym16(uint64_t ind)
406{
407 return sd_cp_16.rep[ind];
408}
409
410static Cube
411antindex_eofbepos_sym16(uint64_t ind)
412{
413 return sd_eofbepos_16.rep[ind];
414}
415
416static Cube
417antindex_drud_sym16(uint64_t ind)
418{
419 Cube c;
420
421 c = sd_eofbepos_16.rep[ind/POW3TO7];
422 c.coud = ind % POW3TO7;
423 c.cofb = c.coud;
424 c.corl = c.coud;
425
426 return c;
427}
428
429static Cube
430antindex_drudfin_noE_sym16(uint64_t ind)
431{
432 Cube c1, c2;
433
434 c1 = antindex_epud(ind % FACTORIAL8);
435 c2 = sd_cp_16.rep[ind/FACTORIAL8];
436 c1.cp = c2.cp;
437
438 return c1;
439}
440
441static Cube
442antindex_htrfin(uint64_t ind)
443{
444 Cube ret = {0};
445 uint64_t cp1, cp2;
446
447 static bool initialized = false;
448 static int i, j, k, c[8], c1[4], c2[4], cp[24][24];
449 static int c1solved[4] = {UFR, UBL, DFL, DBR};
450 static int c2solved[4] = {UFL, UBR, DFR, DBL};
451
452 if (!initialized) {
453 for (i = 0; i < 24; i++) {
454 for (j = 0; j < 24; j++) {
455 index_to_perm(i, 4, c1);
456 index_to_perm(j, 4, c2);
457 for (k = 0; k < 8; k++)
458 if (k == UFR || k == UBL ||
459 k == DFL || k == DBR)
460 c[k] = c1[c1solved[k/2]];
461 else
462 c[k] = c2[c2solved[k/2]];
463
464 cp[i][j] = perm_to_index(c, 8);
465 }
466 }
467
468 initialized = true;
469 }
470
471 cp2 = ind % 24;
472 ind /= 24;
473 cp1 = ind % 24;
474 ret.cp = cp[cp1][cp2];
475
476 ind /= 24;
477 ret.eposm = ind % 24;
478 ind /= 24;
479 ret.eposs = ind % 24;
480 ret.epose = ind / 24;
481
482 return ret;
483}
484
485static Cube
486antindex_khuge(uint64_t ind)
487{
488 Cube c;
489
490 c = sd_eofbepos_16.rep[ind/(FACTORIAL4*POW3TO7)];
491 c.epose = ((c.epose / 24) * 24) + ((ind/POW3TO7) % 24);
492 c.coud = ind % POW3TO7;
493
494 return c;
495}
496
497bool
498check_centers(Cube cube)
499{
500 return cube.cpos == 0;
501}
502
503bool
504check_corners(Cube cube)
505{
506 return cube.cp == 0 && cube.coud == 0;
507}
508
509bool
510check_cp(Cube cube)
511{
512 return cube.cp == 0;
513}
514
515bool
516check_cornershtr(Cube cube)
517{
518 return cube.coud == 0 && cphtr(cube) == 0; /* TODO: use array cphtrcosets*/
519}
520
521bool
522check_coud(Cube cube)
523{
524 return cube.coud == 0;
525}
526
527bool
528check_drud(Cube cube)
529{
530 return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0;
531}
532
533bool
534check_htr(Cube cube)
535{
536 return check_cornershtr(cube) &&
537 cube.eofb == 0 && cube.eorl == 0 && cube.eoud == 0;
538}
539
540bool
541check_htrfin(Cube cube)
542{
543 return cube.cp == 0 &&
544 cube.epose == 0 && cube.eposs == 0 && cube.eposm == 0;
545}
546
547bool
548check_drudfin_noE(Cube cube)
549{
550 return cube.eposs == 0 && cube.eposm == 0 && cube.cp == 0;
551}
552
553bool
554check_eofb(Cube cube)
555{
556 return cube.eofb == 0;
557}
558
559bool
560check_eofbepos(Cube cube)
561{
562 return cube.eofb == 0 && cube.epose / 24 == 0;
563}
564
565bool
566check_epose(Cube cube)
567{
568 return cube.epose == 0;
569}
570
571bool
572check_ep(Cube cube)
573{
574 return cube.epose == 0 && cube.eposs == 0 && cube.eposm == 0;
575}
576
577bool
578check_khuge(Cube cube)
579{
580 return check_drud(cube) && cube.epose % 24 == 0;
581}
582
583bool
584check_nothing(Cube cube)
585{
586 return is_admissible(cube); /*TODO: maybe change?*/
587}
588
589static int
590epos_dependent_pos(int poss, int pose)
591{
592 static int epe_solved[4] = {FR, FL, BL, BR};
593 static int eps_solved[4] = {UL, UR, DL, DR};
594 int ep[12] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
595 int ep8[8] = {0, 0, 0, 0, 0, 0, 0, 0};
596 int i, j;
597
598 epos_to_partial_ep(poss*FACTORIAL4, ep, eps_solved);
599 epos_to_partial_ep(pose*FACTORIAL4, ep, epe_solved);
600
601 for (i = 0, j = 0; i < 12; i++)
602 if (edge_slice(ep[i]) != 0)
603 ep8[j++] = (edge_slice(ep[i]) == 1) ? 1 : 0;
604
605 swap(&ep8[1], &ep8[4]);
606 swap(&ep8[3], &ep8[6]);
607
608 return subset_to_index(ep8, 8, 4);
609}
610
611static void
612gensym(SymData *sd)
613{
614 uint64_t i, in, nreps = 0;
615 int j;
616 Cube c, d;
617
618 if (sd->generated)
619 return;
620
621 sd->class = malloc(sd->coord->max * sizeof(uint64_t));
622 sd->rep = malloc(sd->coord->max * sizeof(Cube));
623 sd->transtorep = malloc(sd->coord->max * sizeof(Trans));
624
625 if (read_symdata_file(sd)) {
626 sd->generated = true;
627 return;
628 }
629
630 fprintf(stderr, "Cannot load %s, generating it\n", sd->filename);
631
632 for (i = 0; i < sd->coord->max; i++)
633 sd->class[i] = sd->coord->max + 1;
634
635 for (i = 0; i < sd->coord->max; i++) {
636 if (sd->class[i] == sd->coord->max + 1) {
637 c = sd->coord->cube(i);
638 sd->rep[nreps] = c;
639 for (j = 0; j < sd->ntrans; j++) {
640 d = apply_trans(sd->trans[j], c);
641 in = sd->coord->index(d);
642
643 if (sd->class[in] == sd->coord->max + 1) {
644 sd->class[in] = nreps;
645 sd->transtorep[in] =
646 inverse_trans(sd->trans[j]);
647 }
648 }
649 nreps++;
650 }
651 }
652
653 sd->sym_coord->max = nreps;
654 sd->rep = realloc(sd->rep, nreps * sizeof(Cube));
655 sd->generated = true;
656
657 fprintf(stderr, "Found %lu classes\n", nreps);
658
659 if (!write_symdata_file(sd))
660 fprintf(stderr, "Error writing SymData file\n");
661
662 return;
663}
664
665static uint64_t
666index_eofb(Cube cube)
667{
668 return cube.eofb;
669}
670
671static uint64_t
672index_eofbepos(Cube cube)
673{
674 return (cube.epose / FACTORIAL4) * POW2TO11 + cube.eofb;
675}
676
677static uint64_t
678index_epud(Cube cube)
679{
680 uint64_t ret;
681 CubeArray *arr = new_cubearray(cube, pf_ep);
682
683 ret = perm_to_index(arr->ep, 8);
684 free_cubearray(arr, pf_ep);
685
686 return ret;
687}
688
689static uint64_t
690index_coud(Cube cube)
691{
692 return cube.coud;
693}
694
695static uint64_t
696index_corners(Cube cube)
697{
698 return cube.coud * FACTORIAL8 + cube.cp;
699}
700
701static uint64_t
702index_cp(Cube cube)
703{
704 return cube.cp;
705}
706
707static uint64_t
708index_cornershtr(Cube cube)
709{
710 return cube.coud * BINOM8ON4 * 6 + cphtr(cube);
711}
712
713static uint64_t
714index_drud(Cube cube)
715{
716 uint64_t a, b, c;
717
718 a = cube.eofb;
719 b = cube.coud;
720 c = cube.epose / FACTORIAL4;
721
722 b *= POW2TO11;
723 c *= POW2TO11 * POW3TO7;
724
725 return a + b + c;
726}
727
728static uint64_t
729index_drud_eofb(Cube cube)
730{
731 return index_drud(cube) / POW2TO11;
732}
733
734static uint64_t
735index_coud_sym16(Cube cube)
736{
737 return sd_coud_16.class[index_coud(cube)];
738}
739
740static uint64_t
741index_cp_sym16(Cube cube)
742{
743 return sd_cp_16.class[index_cp(cube)];
744}
745
746static uint64_t
747index_drud_sym16(Cube cube)
748{
749 Trans t;
750 Cube c;
751
752 t = sd_eofbepos_16.transtorep[index_eofbepos(cube)];
753 c = apply_trans(t, cube);
754
755 return index_eofbepos_sym16(c) * POW3TO7 + c.coud;
756}
757
758static uint64_t
759index_drudfin_noE_sym16(Cube cube)
760{
761 Trans t;
762 Cube c;
763
764 t = sd_cp_16.transtorep[index_cp(cube)];
765 c = apply_trans(t, cube);
766
767 return index_cp_sym16(c) * FACTORIAL8 + index_epud(c);
768}
769
770static uint64_t
771index_htrfin(Cube cube)
772{
773 uint64_t epe, eps, epm, cp, ep;
774
775 static bool initialized = false;
776 static uint64_t cp1[FACTORIAL8], cp2[FACTORIAL8];
777 static unsigned int i;
778 static int j, n1, n2, c[8], c1[4], c2[4];
779
780 if (!initialized) {
781 for (i = 0; i < FACTORIAL8; i++) {
782 index_to_perm(i, 8, c);
783 n1 = 0;
784 n2 = 0;
785 for (j = 0; j < 8; j++)
786 if (c[j] == UFR || c[j] == UBL ||
787 c[j] == DFL || c[j] == DBR)
788 c1[n1++] = c[j] / 2;
789 else
790 c2[n2++] = c[j] / 2;
791
792 cp1[i] = perm_to_index(c1, 4);
793 cp2[i] = perm_to_index(c2, 4);
794 }
795
796 initialized = true;
797 }
798
799 epe = cube.epose % 24;
800 eps = cube.eposs % 24;
801 epm = cube.eposm % 24;
802
803 cp = cp1[cube.cp] * 24 + cp2[cube.cp];
804 ep = (epe * 24 + eps) *24 + epm;
805
806 return ep * 24 * 24 + cp;
807}
808
809static uint64_t
810index_eofbepos_sym16(Cube cube)
811{
812 return sd_eofbepos_16.class[index_eofbepos(cube)];
813}
814
815static uint64_t
816index_khuge(Cube cube)
817{
818 Trans t;
819 Cube c;
820 uint64_t a;
821
822 t = sd_eofbepos_16.transtorep[index_eofbepos(cube)];
823 c = apply_trans(t, cube);
824 a = (index_eofbepos_sym16(c) * 24) + (c.epose % 24);
825
826 return a * POW3TO7 + c.coud;
827}
828
829static bool
830read_symdata_file(SymData *sd)
831{
832 init_env();
833
834 FILE *f;
835 char fname[strlen(tabledir)+100];
836 uint64_t n = sd->coord->max, *sn = &sd->sym_coord->max;
837 bool r = true;
838
839 strcpy(fname, tabledir);
840 strcat(fname, "/");
841 strcat(fname, sd->filename);
842
843 if ((f = fopen(fname, "rb")) == NULL)
844 return false;
845
846 r = r && fread(&sd->sym_coord->max, sizeof(uint64_t), 1, f) == 1;
847 r = r && fread(sd->rep, sizeof(Cube), *sn, f) == *sn;
848 r = r && fread(sd->class, sizeof(uint64_t), n, f) == n;
849 r = r && fread(sd->transtorep, sizeof(Trans), n, f) == n;
850
851 fclose(f);
852 return r;
853}
854
855static bool
856write_symdata_file(SymData *sd)
857{
858 init_env();
859
860 FILE *f;
861 char fname[strlen(tabledir)+100];
862 uint64_t n = sd->coord->max, *sn = &sd->sym_coord->max;
863 bool r = true;
864
865 strcpy(fname, tabledir);
866 strcat(fname, "/");
867 strcat(fname, sd->filename);
868
869 if ((f = fopen(fname, "wb")) == NULL)
870 return false;
871
872 r = r && fwrite(&sd->sym_coord->max, sizeof(uint64_t), 1, f) == 1;
873 r = r && fwrite(sd->rep, sizeof(Cube), *sn, f) == *sn;
874 r = r && fwrite(sd->class, sizeof(uint64_t), n, f) == n;
875 r = r && fwrite(sd->transtorep, sizeof(Trans), n, f) == n;
876
877 fclose(f);
878 return r;
879}
880
881/* Init functions implementation *********************************************/
882
883/*
884 * There is certainly a bette way to do this, but for now I just use
885 * a "graph coloring" algorithm to compute the left cosets, and I compose
886 * with every possible cp to get the right cosets (it is possible that I am
887 * mixing up left and right).
888 *
889 * For doing it better "Mathematically", we need 3 things:
890 * - Checking that cp separates the orbits (UFR,UBL,DFL,DBR) and the other
891 * This is easy and it is done in the commented function cphtr_cp().
892 * - Check that there is no ep/cp parity
893 * - Check that we are not in the "3c" case; this is the part I don't
894 * know how to do.
895 */
896static void
897init_cphtr_cosets()
898{
899 unsigned int i;
900 int c = 0, d = 0;
901
902 for (i = 0; i < FACTORIAL8; i++) {
903 cphtr_left_cosets[i] = -1;
904 cphtr_right_cosets[i] = -1;
905 }
906
907 /* First we compute left cosets with a bfs */
908 for (i = 0; i < FACTORIAL8; i++)
909 if (cphtr_left_cosets[i] == -1)
910 init_cphtr_left_cosets_bfs(i, c++);
911
912 /* Then we compute right cosets using compose() */
913 for (i = 0; i < FACTORIAL8; i++)
914 if (cphtr_right_cosets[i] == -1)
915 init_cphtr_right_cosets_color(i, d++);
916}
917
918static void
919init_cphtr_left_cosets_bfs(int i, int c)
920{
921 int j, jj, k, next[FACTORIAL8], next2[FACTORIAL8], n, n2;
922 Move moves[6] = {U2, D2, R2, L2, F2, B2};
923
924 n = 1;
925 next[0] = i;
926 cphtr_left_cosets[i] = c;
927
928 while (n != 0) {
929 for (j = 0, n2 = 0; j < n; j++) {
930 for (k = 0; k < 6; k++) {
931 /*jj = cp_mtable[moves[k]][next[j]];*/
932 /* TODO fix formatting */
933 jj = apply_move(moves[k], (Cube){.cp=next[j]}).cp;
934 if (cphtr_left_cosets[jj] == -1) {
935 cphtr_left_cosets[jj] = c;
936 next2[n2++] = jj;
937 }
938 }
939 }
940
941 for (j = 0; j < n2; j++)
942 next[j] = next2[j];
943 n = n2;
944 }
945}
946
947static void
948init_cphtr_right_cosets_color(int i, int d)
949{
950 int cp;
951 unsigned int j;
952
953 cphtr_right_rep[d] = i;
954 for (j = 0; j < FACTORIAL8; j++) {
955 if (cphtr_left_cosets[j] == 0) {
956 /* TODO: use antindexer, it's nicer */
957 cp = compose((Cube){.cp = i}, (Cube){.cp = j}).cp;
958 cphtr_right_cosets[cp] = d;
959 }
960 }
961}
962
963static void
964init_symdata()
965{
966 int i;
967
968 for (i = 0; i < n_all_symdata; i++)
969 gensym(all_sd[i]);
970}
971
972/*TODO maybe move the next two */
973uint64_t
974cphtr(Cube cube)
975{
976 return cphtr_right_cosets[cube.cp];
977}
978
979Cube
980anti_cphtr(uint64_t ind)
981{
982 return (Cube) { .cp = cphtr_right_rep[ind] };
983}
984
985uint64_t
986epos_dependent(Cube c)
987{
988 static int initialized = false;
989 static int aux[BINOM12ON4][BINOM12ON4];
990 static uint64_t ui, uj;
991
992 if (!initialized) {
993 for (ui = 0; ui < BINOM12ON4; ui++)
994 for (uj = 0; uj < BINOM12ON4; uj++)
995 aux[ui][uj] = epos_dependent_pos(ui, uj);
996
997 initialized = true;
998 }
999
1000 return aux[c.eposs/FACTORIAL4][c.epose/FACTORIAL4];
1001}
1002
1003void
1004init_coord()
1005{
1006 static bool initialized = false;
1007 if (initialized)
1008 return;
1009 initialized = true;
1010
1011 init_cphtr_cosets();
1012 init_symdata();
1013}
1014
diff --git a/old/coord.h b/old/coord.h
new file mode 100644
index 0000000..3e230a8
--- /dev/null
+++ b/old/coord.h
@@ -0,0 +1,45 @@
1#ifndef COORD_H
2#define COORD_H
3
4#include "trans.h"
5
6extern Coordinate coord_eofb;
7extern Coordinate coord_eofbepos;
8extern Coordinate coord_coud;
9extern Coordinate coord_cp;
10extern Coordinate coord_corners;
11extern Coordinate coord_cornershtr;
12extern Coordinate coord_drud;
13extern Coordinate coord_coud_sym16;
14extern Coordinate coord_drud_eofb;
15extern Coordinate coord_cp_sym16;
16extern Coordinate coord_eofbepos_sym16;
17extern Coordinate coord_drud_sym16;
18extern Coordinate coord_drudfin_noE_sym16;
19extern Coordinate coord_htrfin;
20extern Coordinate coord_khuge;
21
22uint64_t cphtr(Cube cube); /* TODO: rename (something with cosets) */
23Cube anti_cphtr(uint64_t ind); /*TODO also this */
24uint64_t epos_dependent(Cube cube); /* TODO: rename and turn into an indexer */
25
26bool check_centers(Cube cube);
27bool check_corners(Cube cube);
28bool check_cp(Cube cube);
29bool check_cornershtr(Cube cube);
30bool check_coud(Cube cube);
31bool check_drud(Cube cube);
32bool check_htr(Cube cube);
33bool check_htrfin(Cube cube);
34bool check_drudfin_noE(Cube cube);
35bool check_eofb(Cube cube);
36bool check_eofbepos(Cube cube);
37bool check_epose(Cube cube);
38bool check_ep(Cube cube);
39bool check_khuge(Cube cube);
40bool check_nothing(Cube cube);
41
42void init_coord();
43
44#endif
45
diff --git a/old/utils.c b/old/utils.c
new file mode 100644
index 0000000..3b5388e
--- /dev/null
+++ b/old/utils.c
@@ -0,0 +1,294 @@
1#include "utils.h"
2
3/* Generic utility functions *************************************************/
4
5void
6apply_permutation(int *perm, int *set, int n)
7{
8 int *aux = malloc(n * sizeof(int));
9 int i;
10
11 if (!is_perm(perm, n))
12 return;
13
14 for (i = 0; i < n; i++)
15 aux[i] = set[perm[i]];
16
17 intarrcopy(aux, set, n);
18 free(aux);
19}
20
21void
22intarrcopy(int *src, int *dst, int n)
23{
24 int i;
25 for (i = 0; i < n; i++)
26 dst[i] = src[i];
27}
28
29bool
30is_perm(int *a, int n)
31{
32 int *aux = malloc(n * sizeof(int));
33 int i;
34
35 for (i = 0; i < n; i++)
36 if (a[i] < 0 || a[i] >= n)
37 return false;
38 else
39 aux[a[i]] = 1;
40
41 for (i = 0; i < n; i++)
42 if (!aux[i])
43 return false;
44
45 free(aux);
46
47 return true;
48}
49
50bool
51is_subset(int *a, int n, int k)
52{
53 int i, sum = 0;
54
55 for (i = 0; i < n; i++)
56 sum += a[i] ? 1 : 0;
57
58 return sum == k;
59}
60
61int
62sum(int *a, int n)
63{
64 int i, ret = 0;
65
66 for (i = 0; i < n; i++)
67 ret += a[i];
68
69 return ret;
70}
71
72void
73sum_arrays_mod(int *src, int *dst, int n, int m)
74{
75 int i;
76
77 for (i = 0; i < n; i++)
78 dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m;
79}
80
81void
82swap(int *a, int *b)
83{
84 int aux;
85
86 aux = *a;
87 *a = *b;
88 *b = aux;
89}
90
91/* Standard mathematical functions *******************************************/
92
93int
94binomial(int n, int k)
95{
96 if (n < 0 || k < 0 || k > n)
97 return 0;
98
99 return factorial(n) / (factorial(k) * factorial(n-k));
100}
101
102int
103factorial(int n)
104{
105 int i, ret = 1;
106
107 if (n < 0)
108 return 0;
109
110 for (i = 1; i <= n; i++)
111 ret *= i;
112
113 return ret;
114}
115
116int
117perm_sign(int *a, int n)
118{
119 int i, j, ret = 0;
120 if (!is_perm(a,n))
121 return -1;
122
123 for (i = 0; i < n; i++)
124 for (j = i+1; j < n; j++)
125 ret += (a[i] > a[j]) ? 1 : 0;
126
127 return ret % 2;
128}
129
130int
131powint(int a, int b)
132{
133 if (b < 0)
134 return 0; /* Truncate */
135 if (b == 0)
136 return 1;
137
138 if (b % 2)
139 return a * powint(a, b-1);
140 else
141 return powint(a*a, b/2);
142}
143
144/* Conversions to and from int (base b digits, permutations...) **************/
145
146int
147digit_array_to_int(int *a, int n, int b)
148{
149 int i, ret = 0, p = 1;
150
151 for (i = 0; i < n; i++, p *= b)
152 ret += a[i] * p;
153
154 return ret;
155}
156
157void
158int_to_digit_array(int a, int b, int n, int *r)
159{
160 int i;
161
162 if (b <= 1)
163 for (i = 0; i < n; i++)
164 r[i] = 0;
165 else
166 for (i = 0; i < n; i++, a /= b)
167 r[i] = a % b;
168}
169
170void
171int_to_sum_zero_array(int x, int b, int n, int *a)
172{
173 int i, s = 0;
174
175 if (b <= 1) {
176 for (i = 0; i < n; i++)
177 a[i] = 0;
178 } else {
179 int_to_digit_array(x, b, n-1, a);
180 for (i = 0; i < n - 1; i++)
181 s = (s + a[i]) % b;
182 a[n-1] = (b - s) % b;
183 }
184}
185
186int
187invert_digits(int a, int b, int n)
188{
189 int i, *r = malloc(n * sizeof(int));
190
191 int_to_digit_array(a, b, n, r);
192 for (i = 0; i < n; i++)
193 r[i] = (b-r[i]) % b;
194
195 return digit_array_to_int(r, n, b);
196}
197
198void
199index_to_perm(int p, int n, int *r)
200{
201 int *a = malloc(n * sizeof(int));
202 int i, j, c;
203
204 for (i = 0; i < n; i++)
205 a[i] = 0;
206
207 if (p < 0 || p >= factorial(n))
208 for (i = 0; i < n; i++)
209 r[i] = -1;
210
211 for (i = 0; i < n; i++) {
212 c = 0;
213 j = 0;
214 while (c <= p / factorial(n-i-1))
215 c += a[j++] ? 0 : 1;
216 r[i] = j-1;
217 a[j-1] = 1;
218 p %= factorial(n-i-1);
219 }
220
221 free(a);
222}
223
224int
225perm_to_index(int *a, int n)
226{
227 int i, j, c, ret = 0;
228
229 if (!is_perm(a, n))
230 return -1;
231
232 for (i = 0; i < n; i++) {
233 c = 0;
234 for (j = i+1; j < n; j++)
235 c += (a[i] > a[j]) ? 1 : 0;
236 ret += factorial(n-i-1) * c;
237 }
238
239 return ret;
240}
241
242void
243index_to_subset(int s, int n, int k, int *r)
244{
245 int i, j, v;
246
247 if (s < 0 || s >= binomial(n, k)) {
248 for (i = 0; i < n; i++)
249 r[i] = -1;
250 return;
251 }
252
253 for (i = 0; i < n; i++) {
254 if (k == n-i) {
255 for (j = i; j < n; j++)
256 r[j] = 1;
257 return;
258 }
259
260 if (k == 0) {
261 for (j = i; j < n; j++)
262 r[j] = 0;
263 return;
264 }
265
266 v = binomial(n-i-1, k);
267 if (s >= v) {
268 r[i] = 1;
269 k--;
270 s -= v;
271 } else {
272 r[i] = 0;
273 }
274 }
275}
276
277int subset_to_index(int *a, int n, int k) {
278 int i, ret = 0;
279
280 /* TODO: better checks */
281 if (!is_subset(a, n, k))
282 return binomial(n, k);
283
284 for (i = 0; i < n; i++) {
285 if (k == n-i)
286 return ret;
287 if (a[i]) {
288 ret += binomial(n-i-1, k);
289 k--;
290 }
291 }
292
293 return ret;
294}
diff --git a/old/utils.h b/old/utils.h
new file mode 100644
index 0000000..ee8ac6e
--- /dev/null
+++ b/old/utils.h
@@ -0,0 +1,59 @@
1#ifndef UTILS_H
2#define UTILS_H
3
4#include <stdbool.h>
5#include <stdlib.h>
6
7/* Constants and macros *****************************************************/
8
9#define pow2to11 2048
10#define pow2to12 4096
11#define pow3to7 2187
12#define pow3to8 6561
13#define pow12to4 20736
14#define factorial4 24
15#define factorial6 720
16#define factorial8 40320
17#define factorial12 479001600
18#define binom12on4 495
19#define binom8on4 70
20
21#define min(a,b) (((a) < (b)) ? (a) : (b))
22#define max(a,b) (((a) > (b)) ? (a) : (b))
23
24/* Generic utility functions *************************************************/
25
26void apply_permutation(int *perm, int *set, int n);
27void intarrcopy(int *src, int *dst, int n);
28bool is_perm(int *a, int n);
29bool is_subset(int *a, int n, int k);
30int sum(int *a, int n);
31void sum_arrays_mod(int *src, int *dst, int n, int m);
32void swap(int *a, int *b);
33
34/* Standard mathematical functions *******************************************/
35
36int binomial(int n, int k);
37int factorial(int n);
38int perm_sign(int a[], int n);
39int powint(int a, int b);
40
41/* Conversions to and from int (base b digits, permutations...) **************/
42
43int digit_array_to_int(int *a, int n, int b);
44void int_to_digit_array(int a, int b, int n, int *r);
45void int_to_sum_zero_array(int x, int b, int n, int *a);
46int invert_digits(int a, int b, int n);
47
48void index_to_perm(int p, int n, int *r);
49int perm_to_index(int *a, int n);
50
51void index_to_subset(int s, int n, int k, int *r);
52int subset_to_index(int *a, int n, int k);
53
54/* Am I not using these two?
55void index_to_ordered_subset(int s, int n, int k, int *r);
56int ordered_subset_to_index(int *a, int n, int k);
57*/
58
59#endif

Generated with cgit - Back to sebastiano.tronto.net