aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSebastiano Tronto <sebastiano@tronto.net>2023-05-01 12:48:55 +0200
committerSebastiano Tronto <sebastiano@tronto.net>2023-05-01 12:48:55 +0200
commit6f4313bc1ed5be794146e6ca2fd73f48c7906061 (patch)
treea79c8be8613e8b4256d609477f98f440bfd7168c /src
parent1a5bfe9b08707b0aef748d7921a419ba4a046fba (diff)
downloadnissy-classic-6f4313bc1ed5be794146e6ca2fd73f48c7906061.tar.gz
nissy-classic-6f4313bc1ed5be794146e6ca2fd73f48c7906061.zip
Reverted to 2.0.3
Diffstat (limited to 'src')
-rw-r--r--src/alg.c295
-rw-r--r--src/alg.h16
-rw-r--r--src/commands.c356
-rw-r--r--src/commands.h199
-rw-r--r--src/coord.c959
-rw-r--r--src/coord.h267
-rw-r--r--src/cube.c932
-rw-r--r--src/cube.h59
-rw-r--r--src/cubetypes.h240
-rw-r--r--src/env.c2
-rw-r--r--src/env.h4
-rw-r--r--src/fst.c401
-rw-r--r--src/fst.h13
-rw-r--r--src/moves.c417
-rw-r--r--src/moves.h23
-rw-r--r--src/movesets.c194
-rw-r--r--src/movesets.h15
-rw-r--r--src/pf.c95
-rw-r--r--src/pf.h20
-rw-r--r--src/pruning.c371
-rw-r--r--src/pruning.h22
-rw-r--r--src/shell.c10
-rw-r--r--src/solve.c538
-rw-r--r--src/solve.h51
-rw-r--r--src/solver_step.c306
-rw-r--r--src/solver_step.h12
-rw-r--r--src/steps.c1490
-rw-r--r--src/steps.h243
-rw-r--r--src/symcoord.c687
-rw-r--r--src/symcoord.h17
-rw-r--r--src/threader_eager.c163
-rw-r--r--src/threader_eager.h8
-rw-r--r--src/threader_single.c35
-rw-r--r--src/threader_single.h8
-rw-r--r--src/trans.c381
-rw-r--r--src/trans.h36
-rw-r--r--src/utils.c14
37 files changed, 5501 insertions, 3398 deletions
diff --git a/src/alg.c b/src/alg.c
index d806178..52bebc0 100644
--- a/src/alg.c
+++ b/src/alg.c
@@ -1,11 +1,112 @@
1#define ALG_C
2
3#include "alg.h" 1#include "alg.h"
4 2
3/* Local functions ***********************************************************/
4
5static bool allowed_HTM(Move m);
6static bool allowed_URF(Move m);
7static bool allowed_eofb(Move m);
8static bool allowed_drud(Move m);
9static bool allowed_htr(Move m);
10static bool allowed_next_HTM(Move l2, Move l1, Move m);
5static int axis(Move m); 11static int axis(Move m);
12
6static void free_alglistnode(AlgListNode *aln); 13static void free_alglistnode(AlgListNode *aln);
7static void realloc_alg(Alg *alg, int n); 14static void realloc_alg(Alg *alg, int n);
8 15
16/* Movesets ******************************************************************/
17
18Moveset
19moveset_HTM = {
20 .allowed = allowed_HTM,
21 .allowed_next = allowed_next_HTM,
22};
23
24Moveset
25moveset_URF = {
26 .allowed = allowed_URF,
27 .allowed_next = allowed_next_HTM,
28};
29
30Moveset
31moveset_eofb = {
32 .allowed = allowed_eofb,
33 .allowed_next = allowed_next_HTM,
34};
35
36Moveset
37moveset_drud = {
38 .allowed = allowed_drud,
39 .allowed_next = allowed_next_HTM,
40};
41
42Moveset
43moveset_htr = {
44 .allowed = allowed_htr,
45 .allowed_next = allowed_next_HTM,
46};
47
48static int nmoveset = 5;
49static Moveset * all_ms[] = {
50 &moveset_HTM,
51 &moveset_URF,
52 &moveset_eofb,
53 &moveset_drud,
54 &moveset_htr,
55};
56
57/* Functions *****************************************************************/
58
59static bool
60allowed_HTM(Move m)
61{
62 return m >= U && m <= B3;
63}
64
65static bool
66allowed_URF(Move m)
67{
68 Move b = base_move(m);
69
70 return b == U || b == R || b == F;
71}
72
73static bool
74allowed_eofb(Move m)
75{
76 Move b = base_move(m);
77
78 return b == U || b == D || b == R || b == L ||
79 ((b == F || b == B) && m == b+1);
80}
81
82static bool
83allowed_drud(Move m)
84{
85 Move b = base_move(m);
86
87 return b == U || b == D ||
88 ((b == R || b == L || b == F || b == B) && m == b + 1);
89}
90
91static bool
92allowed_htr(Move m)
93{
94 Move b = base_move(m);
95
96 return moveset_HTM.allowed(m) && m == b + 1;
97}
98
99static bool
100allowed_next_HTM(Move l2, Move l1, Move m)
101{
102 bool p, q;
103
104 p = l1 != NULLMOVE && base_move(l1) == base_move(m);
105 q = l2 != NULLMOVE && base_move(l2) == base_move(m);
106
107 return !(p || (commute(l1, l2) && q));
108}
109
9void 110void
10append_alg(AlgList *l, Alg *alg) 111append_alg(AlgList *l, Alg *alg)
11{ 112{
@@ -33,42 +134,30 @@ append_move(Alg *alg, Move m, bool inverse)
33 alg->move[alg->len] = m; 134 alg->move[alg->len] = m;
34 alg->inv [alg->len] = inverse; 135 alg->inv [alg->len] = inverse;
35 alg->len++; 136 alg->len++;
36
37 if (inverse)
38 alg->move_inverse[alg->len_inverse++] = m;
39 else
40 alg->move_normal[alg->len_normal++] = m;
41} 137}
42 138
43static int 139static int
44axis(Move m) 140axis(Move m)
45{ 141{
46 static int aux[] = { 142 if (m == NULLMOVE)
47 [NULLMOVE] = 0, 143 return 0;
48 144
49 [U] = 1, [U2] = 1, [U3] = 1, 145 if (m >= U && m <= B3)
50 [D] = 1, [D2] = 1, [D3] = 1, 146 return (m-1)/6 + 1;
51 [Uw] = 1, [Uw2] = 1, [Uw3] = 1, 147
52 [Dw] = 1, [Dw2] = 1, [Dw3] = 1, 148 if (m >= Uw && m <= Bw3)
53 [E] = 1, [E2] = 1, [E3] = 1, 149 return (m-1)/6 - 2;
54 [y] = 1, [y2] = 1, [y3] = 1,
55 150
56 [R] = 2, [R2] = 2, [R3] = 2, 151 if (base_move(m) == E || base_move(m) == y)
57 [L] = 2, [L2] = 2, [L3] = 2, 152 return 1;
58 [Rw] = 2, [Rw2] = 2, [Rw3] = 2,
59 [Lw] = 2, [Lw2] = 2, [Lw3] = 2,
60 [M] = 2, [M2] = 2, [M3] = 2,
61 [x] = 2, [x2] = 2, [x3] = 2,
62 153
63 [F] = 3, [F2] = 3, [F3] = 3, 154 if (base_move(m) == M || base_move(m) == x)
64 [B] = 3, [B2] = 3, [B3] = 3, 155 return 2;
65 [Fw] = 3, [Fw2] = 3, [Fw3] = 3, 156
66 [Bw] = 3, [Bw2] = 3, [Bw3] = 3, 157 if (base_move(m) == S || base_move(m) == z)
67 [S] = 3, [S2] = 3, [S3] = 3, 158 return 3;
68 [z] = 3, [z2] = 3, [z3] = 3,
69 };
70 159
71 return aux[m]; 160 return -1;
72} 161}
73 162
74Move 163Move
@@ -86,32 +175,6 @@ commute(Move m1, Move m2)
86 return axis(m1) == axis(m2); 175 return axis(m1) == axis(m2);
87} 176}
88 177
89int
90compare(Move m1, Move m2)
91{
92 if (!commute(m1, m2))
93 return 0;
94
95 return m1 < m2 ? 1 : -1;
96}
97
98int
99compare_last(Alg *alg, Move m, bool inverse)
100{
101 Move last;
102 int n;
103
104 if (inverse) {
105 n = alg->len_inverse;
106 last = n > 0 ? alg->move_inverse[n-1] : NULLMOVE;
107 } else {
108 n = alg->len_normal;
109 last = n > 0 ? alg->move_normal[n-1] : NULLMOVE;
110 }
111
112 return compare(last, m);
113}
114
115void 178void
116compose_alg(Alg *alg1, Alg *alg2) 179compose_alg(Alg *alg1, Alg *alg2)
117{ 180{
@@ -124,7 +187,7 @@ compose_alg(Alg *alg1, Alg *alg2)
124void 187void
125copy_alg(Alg *src, Alg *dst) 188copy_alg(Alg *src, Alg *dst)
126{ 189{
127 dst->len = dst->len_normal = dst->len_inverse = 0; 190 dst->len = 0; /* Overwrites */
128 compose_alg(dst, src); 191 compose_alg(dst, src);
129} 192}
130 193
@@ -156,6 +219,16 @@ free_alglistnode(AlgListNode *aln)
156 free(aln); 219 free(aln);
157} 220}
158 221
222void
223inplace(Alg * (*f)(Alg *), Alg *alg)
224{
225 Alg *aux;
226
227 aux = f(alg);
228 copy_alg(aux, alg);
229 free(aux);
230}
231
159Alg * 232Alg *
160inverse_alg(Alg *alg) 233inverse_alg(Alg *alg)
161{ 234{
@@ -211,14 +284,10 @@ new_alg(char *str)
211 Move j, m; 284 Move j, m;
212 285
213 alg = malloc(sizeof(Alg)); 286 alg = malloc(sizeof(Alg));
214 alg->allocated = 30; 287 alg->move = malloc(30 * sizeof(Move));
215 alg->move = malloc(alg->allocated * sizeof(Move)); 288 alg->inv = malloc(30 * sizeof(bool));
216 alg->inv = malloc(alg->allocated * sizeof(bool)); 289 alg->allocated = 30;
217 alg->move_normal = malloc(alg->allocated * sizeof(Move)); 290 alg->len = 0;
218 alg->move_inverse = malloc(alg->allocated * sizeof(Move));
219 alg->len = 0;
220 alg->len_normal = 0;
221 alg->len_inverse = 0;
222 291
223 niss = false; 292 niss = false;
224 for (i = 0; str[i]; i++) { 293 for (i = 0; str[i]; i++) {
@@ -227,13 +296,13 @@ new_alg(char *str)
227 296
228 if (str[i] == '(' && niss) { 297 if (str[i] == '(' && niss) {
229 fprintf(stderr, "Error reading moves: nested ( )\n"); 298 fprintf(stderr, "Error reading moves: nested ( )\n");
230 alg->len = alg->len_normal = alg->len_inverse = 0; 299 alg->len = 0;
231 return alg; 300 return alg;
232 } 301 }
233 302
234 if (str[i] == ')' && !niss) { 303 if (str[i] == ')' && !niss) {
235 fprintf(stderr, "Error reading moves: unmatched )\n"); 304 fprintf(stderr, "Error reading moves: unmatched )\n");
236 alg->len = alg->len_normal = alg->len_inverse = 0; 305 alg->len = 0;
237 return alg; 306 return alg;
238 } 307 }
239 308
@@ -300,7 +369,7 @@ new_alg(char *str)
300 369
301 if (niss) { 370 if (niss) {
302 fprintf(stderr, "Error reading moves: unmatched (\n"); 371 fprintf(stderr, "Error reading moves: unmatched (\n");
303 alg->len = alg->len_normal = alg->len_inverse = 0; 372 alg->len = 0;
304 } 373 }
305 374
306 return alg; 375 return alg;
@@ -385,25 +454,12 @@ realloc_alg(Alg *alg, int n)
385 fprintf(stderr, "something might go wrong.\n"); 454 fprintf(stderr, "something might go wrong.\n");
386 } 455 }
387 456
388 alg->move = realloc(alg->move, n * sizeof(int)); 457 alg->move = realloc(alg->move, n * sizeof(int));
389 alg->inv = realloc(alg->inv, n * sizeof(int)); 458 alg->inv = realloc(alg->inv, n * sizeof(int));
390 alg->move_normal = realloc(alg->move_normal, n * sizeof(int));
391 alg->move_inverse = realloc(alg->move_inverse, n * sizeof(int));
392 alg->allocated = n; 459 alg->allocated = n;
393} 460}
394 461
395void 462void
396remove_last_move(Alg *a)
397{
398 a->len--;
399
400 if (a->inv[a->len])
401 a->len_inverse--;
402 else
403 a->len_normal--;
404}
405
406void
407swapmove(Move *m1, Move *m2) 463swapmove(Move *m1, Move *m2)
408{ 464{
409 Move aux; 465 Move aux;
@@ -413,34 +469,6 @@ swapmove(Move *m1, Move *m2)
413 *m2 = aux; 469 *m2 = aux;
414} 470}
415 471
416char *
417trans_string(Trans t)
418{
419 static char trans_string_aux[NTRANS][20] = {
420 [uf] = "uf", [ur] = "ur", [ub] = "ub", [ul] = "ul",
421 [df] = "df", [dr] = "dr", [db] = "db", [dl] = "dl",
422 [rf] = "rf", [rd] = "rd", [rb] = "rb", [ru] = "ru",
423 [lf] = "lf", [ld] = "ld", [lb] = "lb", [lu] = "lu",
424 [fu] = "fu", [fr] = "fr", [fd] = "fd", [fl] = "fl",
425 [bu] = "bu", [br] = "br", [bd] = "bd", [bl] = "bl",
426
427 [uf_mirror] = "uf*", [ur_mirror] = "ur*",
428 [ub_mirror] = "ub*", [ul_mirror] = "ul*",
429 [df_mirror] = "df*", [dr_mirror] = "dr*",
430 [db_mirror] = "db*", [dl_mirror] = "dl*",
431 [rf_mirror] = "rf*", [rd_mirror] = "rd*",
432 [rb_mirror] = "rb*", [ru_mirror] = "ru*",
433 [lf_mirror] = "lf*", [ld_mirror] = "ld*",
434 [lb_mirror] = "lb*", [lu_mirror] = "lu*",
435 [fu_mirror] = "fu*", [fr_mirror] = "fr*",
436 [fd_mirror] = "fd*", [fl_mirror] = "fl*",
437 [bu_mirror] = "bu*", [br_mirror] = "br*",
438 [bd_mirror] = "bd*", [bl_mirror] = "bl*",
439 };
440
441 return trans_string_aux[t];
442}
443
444Alg * 472Alg *
445unniss(Alg *alg) 473unniss(Alg *alg)
446{ 474{
@@ -449,11 +477,48 @@ unniss(Alg *alg)
449 477
450 ret = new_alg(""); 478 ret = new_alg("");
451 479
452 for (i = 0; i < alg->len_normal; i++) 480 for (i = 0; i < alg->len; i++)
453 append_move(ret, alg->move_normal[i], false); 481 if (!alg->inv[i])
482 append_move(ret, alg->move[i], false);
483
484 for (i = alg->len-1; i >= 0; i--)
485 if (alg->inv[i])
486 append_move(ret, inverse_move(alg->move[i]), false);
487
488 return ret;
489}
454 490
455 for (i = 0; i < alg->len_inverse; i++) 491void
456 append_move(ret, inverse_move(alg->move_inverse[i]), false); 492init_moveset(Moveset *ms)
493{
494 int j;
495 uint64_t l, one;
496 Move m, l2, l1;
457 497
458 return ret; 498 one = 1;
499
500 for (j = 0, m = U; m < NMOVES; m++)
501 if (ms->allowed(m))
502 ms->sorted_moves[j++] = m;
503 ms->sorted_moves[j] = NULLMOVE;
504
505 for (l1 = 0; l1 < NMOVES; l1++) {
506 for (l2 = 0; l2 < NMOVES; l2++) {
507 ms->mask[l2][l1] = 0;
508 for (l=0; ms->sorted_moves[l]!=NULLMOVE; l++) {
509 m = ms->sorted_moves[l];
510 if (ms->allowed_next(l2, l1, m))
511 ms->mask[l2][l1] |= (one<<m);
512 }
513 }
514 }
515}
516
517void
518init_all_movesets()
519{
520 int i;
521
522 for (i = 0; i < nmoveset; i++)
523 init_moveset(all_ms[i]);
459} 524}
diff --git a/src/alg.h b/src/alg.h
index 967cd92..6bee26b 100644
--- a/src/alg.h
+++ b/src/alg.h
@@ -8,28 +8,36 @@
8#include "cubetypes.h" 8#include "cubetypes.h"
9#include "utils.h" 9#include "utils.h"
10 10
11extern Moveset moveset_HTM;
12extern Moveset moveset_URF;
13extern Moveset moveset_eofb;
14extern Moveset moveset_drud;
15extern Moveset moveset_htr;
16
11void append_alg(AlgList *l, Alg *alg); 17void append_alg(AlgList *l, Alg *alg);
12void append_move(Alg *alg, Move m, bool inverse); 18void append_move(Alg *alg, Move m, bool inverse);
13Move base_move(Move m); 19Move base_move(Move m);
14int compare(Move m1, Move m2); /* Return 1 (m1<m2), 0 or -1 (m1>m2) */
15int compare_last(Alg *alg, Move m, bool inverse);
16void compose_alg(Alg *alg1, Alg *alg2); 20void compose_alg(Alg *alg1, Alg *alg2);
17bool commute(Move m1, Move m2); 21bool commute(Move m1, Move m2);
18void copy_alg(Alg *src, Alg *dst); 22void copy_alg(Alg *src, Alg *dst);
19void free_alg(Alg *alg); 23void free_alg(Alg *alg);
20void free_alglist(AlgList *l); 24void free_alglist(AlgList *l);
25void inplace(Alg * (*f)(Alg *), Alg *alg);
21Alg * inverse_alg(Alg *alg); 26Alg * inverse_alg(Alg *alg);
22Move inverse_move(Move m); 27Move inverse_move(Move m);
23char * move_string(Move m); 28char * move_string(Move m);
29void movelist_to_position(Move *ml, int *pos);
30void moveset_to_list(Moveset ms, Move *lst);
24Alg * new_alg(char *str); 31Alg * new_alg(char *str);
25AlgList * new_alglist(); 32AlgList * new_alglist();
26Alg * on_inverse(Alg *alg); 33Alg * on_inverse(Alg *alg);
27void print_alg(Alg *alg, bool l); 34void print_alg(Alg *alg, bool l);
28void print_alglist(AlgList *al, bool l); 35void print_alglist(AlgList *al, bool l);
29void remove_last_move(Alg *alg);
30void swapmove(Move *m1, Move *m2); 36void swapmove(Move *m1, Move *m2);
31char * trans_string(Trans t); /* Here because similar to move_string, move? */
32Alg * unniss(Alg *alg); 37Alg * unniss(Alg *alg);
33 38
39void init_moveset(Moveset *ms);
40void init_all_movesets();
41
34#endif 42#endif
35 43
diff --git a/src/commands.c b/src/commands.c
index a9e8fc9..4d3ad50 100644
--- a/src/commands.c
+++ b/src/commands.c
@@ -1,11 +1,187 @@
1#define COMMANDS_C
2
3#include "commands.h" 1#include "commands.h"
4 2
5static bool read_cs(CommandArgs *args, char *str); 3/* Arg parsing functions *****************************************************/
4
5CommandArgs * gen_parse_args(int c, char **v);
6CommandArgs * help_parse_args(int c, char **v);
7CommandArgs * parse_only_scramble(int c, char **v);
8CommandArgs * parse_no_arg(int c, char **v);
9CommandArgs * solve_parse_args(int c, char **v);
10CommandArgs * scramble_parse_args(int c, char **v);
11
12/* Exec functions ************************************************************/
13
14static void gen_exec(CommandArgs *args);
15static void cleanup_exec(CommandArgs *args);
16static void invert_exec(CommandArgs *args);
17static void solve_exec(CommandArgs *args);
18static void scramble_exec(CommandArgs *args);
19static void steps_exec(CommandArgs *args);
20static void commands_exec(CommandArgs *args);
21static void freemem_exec(CommandArgs *args);
22static void print_exec(CommandArgs *args);
23static void twophase_exec(CommandArgs *args);
24static void help_exec(CommandArgs *args);
25static void quit_exec(CommandArgs *args);
26static void unniss_exec(CommandArgs *args);
27static void version_exec(CommandArgs *args);
28
29/* Local functions ***********************************************************/
30
31static bool read_step(CommandArgs *args, char *str);
6static bool read_scrtype(CommandArgs *args, char *str); 32static bool read_scrtype(CommandArgs *args, char *str);
7static bool read_scramble(int c, char **v, CommandArgs *args); 33static bool read_scramble(int c, char **v, CommandArgs *args);
8 34
35/* Commands ******************************************************************/
36
37Command
38solve_cmd = {
39 .name = "solve",
40 .usage = "solve STEP [OPTIONS] SCRAMBLE",
41 .description = "Solve a step; see command steps for a list of steps",
42 .parse_args = solve_parse_args,
43 .exec = solve_exec
44};
45
46Command
47scramble_cmd = {
48 .name = "scramble",
49 .usage = "scramble [TYPE] [-n N]",
50 .description = "Get a random-position scramble",
51 .parse_args = scramble_parse_args,
52 .exec = scramble_exec,
53};
54
55Command
56gen_cmd = {
57 .name = "gen",
58 .usage = "gen [-t N]",
59 .description = "Generate all tables [using N threads]",
60 .parse_args = gen_parse_args,
61 .exec = gen_exec
62};
63
64Command
65invert_cmd = {
66 .name = "invert",
67 .usage = "invert SCRAMBLE]",
68 .description = "Invert a scramble",
69 .parse_args = parse_only_scramble,
70 .exec = invert_exec,
71};
72
73Command
74steps_cmd = {
75 .name = "steps",
76 .usage = "steps",
77 .description = "List available steps",
78 .parse_args = parse_no_arg,
79 .exec = steps_exec
80};
81
82Command
83commands_cmd = {
84 .name = "commands",
85 .usage = "commands",
86 .description = "List available commands",
87 .parse_args = parse_no_arg,
88 .exec = commands_exec
89};
90
91Command
92freemem_cmd = {
93 .name = "freemem",
94 .usage = "freemem",
95 .description = "free large tables from RAM",
96 .parse_args = parse_no_arg,
97 .exec = freemem_exec,
98};
99
100Command
101print_cmd = {
102 .name = "print",
103 .usage = "print SCRAMBLE",
104 .description = "Print written description of the cube",
105 .parse_args = parse_only_scramble,
106 .exec = print_exec,
107};
108
109Command
110help_cmd = {
111 .name = "help",
112 .usage = "help [COMMAND]",
113 .description = "Display nissy manual page or help on specific command",
114 .parse_args = help_parse_args,
115 .exec = help_exec,
116};
117
118Command
119twophase_cmd = {
120 .name = "twophase",
121 .usage = "twophase",
122 .description = "Find a solution quickly using a 2-phase method",
123 .parse_args = parse_only_scramble,
124 .exec = twophase_exec,
125};
126
127Command
128quit_cmd = {
129 .name = "quit",
130 .usage = "quit",
131 .description = "Quit nissy",
132 .parse_args = parse_no_arg,
133 .exec = quit_exec,
134};
135
136Command
137cleanup_cmd = {
138 .name = "cleanup",
139 .usage = "cleanup SCRAMBLE",
140 .description = "Rewrite a scramble using only standard moves (HTM)",
141 .parse_args = parse_only_scramble,
142 .exec = cleanup_exec,
143};
144
145Command
146unniss_cmd = {
147 .name = "unniss",
148 .usage = "unniss SCRAMBLE",
149 .description = "Rewrite a scramble without NISS",
150 .parse_args = parse_only_scramble,
151 .exec = unniss_exec,
152};
153
154Command
155version_cmd = {
156 .name = "version",
157 .usage = "version",
158 .description = "print nissy version",
159 .parse_args = parse_no_arg,
160 .exec = version_exec,
161};
162
163Command *commands[] = {
164 &commands_cmd,
165 &freemem_cmd,
166 &gen_cmd,
167 &help_cmd,
168 &invert_cmd,
169 &print_cmd,
170 &quit_cmd,
171 &solve_cmd,
172 &scramble_cmd,
173 &steps_cmd,
174 &twophase_cmd,
175 &cleanup_cmd,
176 &unniss_cmd,
177 &version_cmd,
178 NULL
179};
180
181/* Other constants ***********************************************************/
182
183char *scrtypes[20] = { "eo", "corners", "edges", "fmc", "dr", "htr", NULL };
184
9/* Arg parsing functions implementation **************************************/ 185/* Arg parsing functions implementation **************************************/
10 186
11CommandArgs * 187CommandArgs *
@@ -95,7 +271,7 @@ solve_parse_args(int c, char **v)
95 a->opts->print_number = false; 271 a->opts->print_number = false;
96 } else if (!strcmp(v[i], "-c")) { 272 } else if (!strcmp(v[i], "-c")) {
97 a->opts->count_only = true; 273 a->opts->count_only = true;
98 } else if (!read_cs(a, v[i])) { 274 } else if (!read_step(a, v[i])) {
99 break; 275 break;
100 } 276 }
101 } 277 }
@@ -210,26 +386,17 @@ parse_no_arg(int c, char **v)
210 386
211/* Exec functions implementation *********************************************/ 387/* Exec functions implementation *********************************************/
212 388
213void 389static void
214solve_exec(CommandArgs *args) 390solve_exec(CommandArgs *args)
215{ 391{
216 Cube c; 392 Cube c;
217 AlgList *sols; 393 AlgList *sols;
218 Solver *solver[99];
219 Threader *threader;
220 394
221 make_solved(&c); 395 init_all_movesets();
222 apply_alg(args->scramble, &c); 396 init_symcoord();
223/* TODO: adjust */
224/* threader = &threader_single;*/
225 threader = &threader_eager;
226 397
227/* TODO: adjust */ 398 c = apply_alg(args->scramble, (Cube){0});
228 int i; 399 sols = solve(c, args->step, args->opts);
229 for (i = 0; args->cs->step[i] != NULL; i++)
230 solver[i] = new_stepsolver_lazy(args->cs->step[i]);
231 solver[i] = NULL;
232 sols = solve(&c, args->opts, solver, threader);
233 400
234 if (args->opts->count_only) 401 if (args->opts->count_only)
235 printf("%d\n", sols->len); 402 printf("%d\n", sols->len);
@@ -239,67 +406,85 @@ solve_exec(CommandArgs *args)
239 free_alglist(sols); 406 free_alglist(sols);
240} 407}
241 408
242void 409static void
243scramble_exec(CommandArgs *args) 410scramble_exec(CommandArgs *args)
244{ 411{
245 Cube cube; 412 Cube cube;
413 CubeArray *arr;
246 Alg *scr, *ruf, *aux; 414 Alg *scr, *ruf, *aux;
247 int i, j, eo, ep, co, cp; 415 int i, j, eo, ep, co, cp, a[12];
416 int eparr[12] = { [8] = 8, [9] = 9, [10] = 10, [11] = 11 };
248 uint64_t ui, uj, uk; 417 uint64_t ui, uj, uk;
249 418
419 init_all_movesets();
420 init_symcoord();
421
250 srand(time(NULL)); 422 srand(time(NULL));
251 423
252 for (i = 0; i < args->n; i++) { 424 for (i = 0; i < args->n; i++) {
253 425
254 if (!strcmp(args->scrtype, "dr")) { 426 if (!strcmp(args->scrtype, "dr")) {
255 ui = rand() % FACTORIAL8; 427 /* Warning: cube is inconsistent because of side CO *
256 uj = rand() % FACTORIAL8; 428 * and EO on U/D. But solve_2phase only solves drfin *
257 uk = rand() % FACTORIAL4; 429 * in this case, so it should be ok. *
430 * TODO: check this properly *
431 * Moreover we again need to fix parity after *
432 * generating epose manually */
433 do {
434 ui = rand() % FACTORIAL8;
435 uj = rand() % FACTORIAL8;
436 uk = rand() % FACTORIAL4;
437
438 index_to_perm(ui, 8, eparr);
439 arr = malloc(sizeof(CubeArray));
440 arr->ep = eparr;
441 cube = arrays_to_cube(arr, pf_ep);
442 free(arr);
258 443
259 make_solved(&cube); 444 cube.cp = uj;
260 index_to_perm(ui, 8, cube.cp); 445 cube.epose = uk;
261 index_to_perm(uj, 8, cube.ep); 446 } while (!is_admissible(cube));
262 index_to_perm(uk, 4, cube.ep + 8);
263 for (j = 8; j < 12; j++)
264 cube.ep[j] += 8;
265 } else if (!strcmp(args->scrtype, "htr")) { 447 } else if (!strcmp(args->scrtype, "htr")) {
266 make_solved(&cube); 448 /* antindex_htrfin() returns a consistent *
267 /* TODO */ 449 * cube, except possibly for parity */
450 do {
451 ui = rand() % (24*24/6);
452 cube = (Cube){0};
453 cube.cp = cornershtrfin_ant[ui];
454 cube.epose = rand() % 24;
455 cube.eposs = rand() % 24;
456 cube.eposm = rand() % 24;
457 } while (!is_admissible(cube));
268 } else { 458 } else {
269 ep = rand() % FACTORIAL12;
270 cp = rand() % FACTORIAL8;
271 eo = rand() % POW2TO11; 459 eo = rand() % POW2TO11;
460 ep = rand() % FACTORIAL12;
272 co = rand() % POW3TO7; 461 co = rand() % POW3TO7;
462 cp = rand() % FACTORIAL8;
273 463
274 if (!strcmp(args->scrtype, "eo")) { 464 if (!strcmp(args->scrtype, "eo")) {
275 eo = 0; 465 eo = 0;
276 } else if (!strcmp(args->scrtype, "corners")) { 466 } else if (!strcmp(args->scrtype, "corners")) {
277 eo = 0; 467 eo = 0;
278 ep = 0; 468 ep = 0;
469 index_to_perm(cp, 8, a);
470 if (perm_sign(a, 8) == 1) {
471 swap(&a[0], &a[1]);
472 cp = perm_to_index(a, 8);
473 }
279 } else if (!strcmp(args->scrtype, "edges")) { 474 } else if (!strcmp(args->scrtype, "edges")) {
280 co = 0; 475 co = 0;
281 cp = 0; 476 cp = 0;
477 index_to_perm(ep, 12, a);
478 if (perm_sign(a, 12) == 1) {
479 swap(&a[0], &a[1]);
480 ep = perm_to_index(a, 12);
481 }
282 } 482 }
283 483 cube = fourval_to_cube(eo, ep, co, cp);
284 make_solved(&cube);
285 index_to_perm(ep, 12, cube.ep);
286 index_to_perm(cp, 8, cube.cp);
287 int_to_sum_zero_array(eo, 2, 12, cube.eo);
288 int_to_sum_zero_array(co, 3, 8, cube.co);
289 }
290
291 if (!is_admissible(&cube)) {
292 if (!strcmp(args->scrtype, "corners"))
293 swap(&cube.cp[UFR], &cube.cp[UFL]);
294 else
295 swap(&cube.ep[UF], &cube.ep[UB]);
296 } 484 }
297 485
298 /* TODO: can be optimized for htr and dr using htrfin, drfin */ 486 /* TODO: can be optimized for htr and dr using htrfin, drfin */
299 /* 487 scr = solve_2phase(cube, 1);
300 TODO: solve_2phase was removed
301 scr = solve_2phase(&cube, 1);
302 */
303 488
304 if (!strcmp(args->scrtype, "fmc")) { 489 if (!strcmp(args->scrtype, "fmc")) {
305 aux = new_alg(""); 490 aux = new_alg("");
@@ -328,22 +513,23 @@ scramble_exec(CommandArgs *args)
328 } 513 }
329} 514}
330 515
331void 516static void
332gen_exec(CommandArgs *args) 517gen_exec(CommandArgs *args)
333{ 518{
334/* TODO:
335 int i; 519 int i;
336 520
337 fprintf(stderr, "Generating coordinates...\n"); 521 fprintf(stderr, "Generating coordinates...\n");
522 init_all_movesets();
523 init_symcoord();
524
338 fprintf(stderr, "Generating pruning tables...\n"); 525 fprintf(stderr, "Generating pruning tables...\n");
339 for (i = 0; all_pd[i] != NULL; i++) 526 for (i = 0; all_pd[i] != NULL; i++)
340 genptable(all_pd[i], args->opts->nthreads); 527 genptable(all_pd[i], args->opts->nthreads);
341*/
342 528
343 fprintf(stderr, "Done!\n"); 529 fprintf(stderr, "Done!\n");
344} 530}
345 531
346void 532static void
347invert_exec(CommandArgs *args) 533invert_exec(CommandArgs *args)
348{ 534{
349 Alg *inv; 535 Alg *inv;
@@ -354,16 +540,16 @@ invert_exec(CommandArgs *args)
354 free_alg(inv); 540 free_alg(inv);
355} 541}
356 542
357void 543static void
358steps_exec(CommandArgs *args) 544steps_exec(CommandArgs *args)
359{ 545{
360 int i; 546 int i;
361 547
362 for (i = 0; csteps[i] != NULL; i++) 548 for (i = 0; steps[i] != NULL; i++)
363 printf("%-15s %s\n", csteps[i]->shortname, csteps[i]->name); 549 printf("%-15s %s\n", steps[i]->shortname, steps[i]->name);
364} 550}
365 551
366void 552static void
367commands_exec(CommandArgs *args) 553commands_exec(CommandArgs *args)
368{ 554{
369 int i; 555 int i;
@@ -373,10 +559,9 @@ commands_exec(CommandArgs *args)
373 559
374} 560}
375 561
376void 562static void
377freemem_exec(CommandArgs *args) 563freemem_exec(CommandArgs *args)
378{ 564{
379/* TODO:
380 int i; 565 int i;
381 566
382 for (i = 0; all_pd[i] != NULL; i++) 567 for (i = 0; all_pd[i] != NULL; i++)
@@ -384,36 +569,35 @@ freemem_exec(CommandArgs *args)
384 569
385 for (i = 0; all_sd[i] != NULL; i++) 570 for (i = 0; all_sd[i] != NULL; i++)
386 free_sd(all_sd[i]); 571 free_sd(all_sd[i]);
387*/ 572
573 /* TODO: invtables are also large, but for now they are *
574 * statically allocated. Consider releasing those too. */
388} 575}
389 576
390void 577static void
391print_exec(CommandArgs *args) 578print_exec(CommandArgs *args)
392{ 579{
393 Cube c; 580 init_moves();
394 581 print_cube(apply_alg(args->scramble, (Cube){0}));
395 make_solved(&c);
396 apply_alg(args->scramble, &c);
397 print_cube(&c);
398} 582}
399 583
400/* 584static void
401void
402twophase_exec(CommandArgs *args) 585twophase_exec(CommandArgs *args)
403{ 586{
404 Cube c; 587 Cube c;
405 Alg *sol; 588 Alg *sol;
406 589
407 make_solved(&c); 590 init_all_movesets();
408 apply_alg(args->scramble, &c); 591 init_symcoord();
409 sol = solve_2phase(&c, 1); 592
593 c = apply_alg(args->scramble, (Cube){0});
594 sol = solve_2phase(c, 1);
410 595
411 print_alg(sol, false); 596 print_alg(sol, false);
412 free_alg(sol); 597 free_alg(sol);
413} 598}
414*/
415 599
416void 600static void
417help_exec(CommandArgs *args) 601help_exec(CommandArgs *args)
418{ 602{
419 if (args->command == NULL) { 603 if (args->command == NULL) {
@@ -427,7 +611,7 @@ help_exec(CommandArgs *args)
427 " system (such as Linux or MacOS) or in pdf and html" 611 " system (such as Linux or MacOS) or in pdf and html"
428 " format in the docs folder.\n" 612 " format in the docs folder.\n"
429 "Nissy is available for free at " 613 "Nissy is available for free at "
430 "https://nissy.tronto.net\n" 614 "https://github.com/sebastianotronto/nissy\n"
431 ); 615 );
432 } else { 616 } else {
433 printf("Command %s: %s\nusage: %s\n", args->command->name, 617 printf("Command %s: %s\nusage: %s\n", args->command->name,
@@ -435,24 +619,26 @@ help_exec(CommandArgs *args)
435 } 619 }
436} 620}
437 621
438void 622static void
439quit_exec(CommandArgs *args) 623quit_exec(CommandArgs *args)
440{ 624{
441 exit(0); 625 exit(0);
442} 626}
443 627
444void 628static void
445cleanup_exec(CommandArgs *args) 629cleanup_exec(CommandArgs *args)
446{ 630{
447 Alg *alg; 631 Alg *alg;
448 632
633 init_moves();
634
449 alg = cleanup(args->scramble); 635 alg = cleanup(args->scramble);
450 print_alg(alg, false); 636 print_alg(alg, false);
451 637
452 free_alg(alg); 638 free_alg(alg);
453} 639}
454 640
455void 641static void
456unniss_exec(CommandArgs *args) 642unniss_exec(CommandArgs *args)
457{ 643{
458 Alg *aux; 644 Alg *aux;
@@ -462,7 +648,7 @@ unniss_exec(CommandArgs *args)
462 free(aux); 648 free(aux);
463} 649}
464 650
465void 651static void
466version_exec(CommandArgs *args) 652version_exec(CommandArgs *args)
467{ 653{
468 printf(VERSION"\n"); 654 printf(VERSION"\n");
@@ -505,8 +691,6 @@ static bool
505read_scrtype(CommandArgs *args, char *str) 691read_scrtype(CommandArgs *args, char *str)
506{ 692{
507 int i; 693 int i;
508 static char *scrtypes[20] =
509 { "eo", "corners", "edges", "fmc", "dr", "htr", NULL };
510 694
511 for (i = 0; scrtypes[i] != NULL; i++) { 695 for (i = 0; scrtypes[i] != NULL; i++) {
512 if (!strcmp(scrtypes[i], str)) { 696 if (!strcmp(scrtypes[i], str)) {
@@ -519,13 +703,13 @@ read_scrtype(CommandArgs *args, char *str)
519} 703}
520 704
521static bool 705static bool
522read_cs(CommandArgs *args, char *str) 706read_step(CommandArgs *args, char *str)
523{ 707{
524 int i; 708 int i;
525 709
526 for (i = 0; csteps[i] != NULL; i++) { 710 for (i = 0; steps[i] != NULL; i++) {
527 if (!strcmp(csteps[i]->shortname, str)) { 711 if (!strcmp(steps[i]->shortname, str)) {
528 args->cs = csteps[i]; 712 args->step = steps[i];
529 return true; 713 return true;
530 } 714 }
531 } 715 }
@@ -562,7 +746,7 @@ new_args()
562 args->opts = malloc(sizeof(SolveOptions)); 746 args->opts = malloc(sizeof(SolveOptions));
563 747
564 /* step and command are static */ 748 /* step and command are static */
565 args->cs = csteps[0]; /* default: first step in list */ 749 args->step = steps[0]; /* default: first step in list */
566 args->command = NULL; 750 args->command = NULL;
567 751
568 return args; 752 return args;
diff --git a/src/commands.h b/src/commands.h
index 65708e0..b7a4c36 100644
--- a/src/commands.h
+++ b/src/commands.h
@@ -5,207 +5,10 @@
5 5
6#include "solve.h" 6#include "solve.h"
7#include "steps.h" 7#include "steps.h"
8#include "solver_step.h"
9#include "threader_single.h"
10#include "threader_eager.h"
11 8
12void free_args(CommandArgs *args); 9void free_args(CommandArgs *args);
13CommandArgs * new_args(); 10CommandArgs * new_args();
14 11
15/* Arg parsing functions *****************************************************/ 12extern Command * commands[];
16
17CommandArgs * gen_parse_args(int c, char **v);
18CommandArgs * help_parse_args(int c, char **v);
19CommandArgs * parse_only_scramble(int c, char **v);
20CommandArgs * parse_no_arg(int c, char **v);
21CommandArgs * solve_parse_args(int c, char **v);
22CommandArgs * scramble_parse_args(int c, char **v);
23
24/* Exec functions ************************************************************/
25
26void gen_exec(CommandArgs *args);
27void cleanup_exec(CommandArgs *args);
28void invert_exec(CommandArgs *args);
29void solve_exec(CommandArgs *args);
30void scramble_exec(CommandArgs *args);
31void steps_exec(CommandArgs *args);
32void commands_exec(CommandArgs *args);
33void freemem_exec(CommandArgs *args);
34void print_exec(CommandArgs *args);
35/*void twophase_exec(CommandArgs *args);*/
36void help_exec(CommandArgs *args);
37void quit_exec(CommandArgs *args);
38void unniss_exec(CommandArgs *args);
39void version_exec(CommandArgs *args);
40
41/* Commands ******************************************************************/
42
43#ifndef COMMANDS_C
44
45extern Command cleanup_cmd;
46extern Command commands_cmd;
47extern Command freemem_cmd;
48extern Command gen_cmd;
49extern Command help_cmd;
50extern Command invert_cmd;
51extern Command print_cmd;
52extern Command quit_cmd;
53extern Command scramble_cmd;
54extern Command solve_cmd;
55extern Command steps_cmd;
56extern Command unniss_cmd;
57extern Command version_cmd;
58
59extern Command *commands[];
60
61#else
62
63Command
64solve_cmd = {
65 .name = "solve",
66 .usage = "solve STEP [OPTIONS] SCRAMBLE",
67 .description = "Solve a step; see command steps for a list of steps",
68 .parse_args = solve_parse_args,
69 .exec = solve_exec
70};
71
72Command
73scramble_cmd = {
74 .name = "scramble",
75 .usage = "scramble [TYPE] [-n N]",
76 .description = "Get a random-position scramble",
77 .parse_args = scramble_parse_args,
78 .exec = scramble_exec,
79};
80
81Command
82gen_cmd = {
83 .name = "gen",
84 .usage = "gen [-t N]",
85 .description = "Generate all tables [using N threads]",
86 .parse_args = gen_parse_args,
87 .exec = gen_exec
88};
89
90Command
91invert_cmd = {
92 .name = "invert",
93 .usage = "invert SCRAMBLE]",
94 .description = "Invert a scramble",
95 .parse_args = parse_only_scramble,
96 .exec = invert_exec,
97};
98
99Command
100steps_cmd = {
101 .name = "steps",
102 .usage = "steps",
103 .description = "List available steps",
104 .parse_args = parse_no_arg,
105 .exec = steps_exec
106};
107
108Command
109commands_cmd = {
110 .name = "commands",
111 .usage = "commands",
112 .description = "List available commands",
113 .parse_args = parse_no_arg,
114 .exec = commands_exec
115};
116
117Command
118freemem_cmd = {
119 .name = "freemem",
120 .usage = "freemem",
121 .description = "free large tables from RAM",
122 .parse_args = parse_no_arg,
123 .exec = freemem_exec,
124};
125
126Command
127print_cmd = {
128 .name = "print",
129 .usage = "print SCRAMBLE",
130 .description = "Print written description of the cube",
131 .parse_args = parse_only_scramble,
132 .exec = print_exec,
133};
134
135Command
136help_cmd = {
137 .name = "help",
138 .usage = "help [COMMAND]",
139 .description = "Display nissy manual page or help on specific command",
140 .parse_args = help_parse_args,
141 .exec = help_exec,
142};
143
144/*
145Command
146twophase_cmd = {
147 .name = "twophase",
148 .usage = "twophase",
149 .description = "Find a solution quickly using a 2-phase method",
150 .parse_args = parse_only_scramble,
151 .exec = twophase_exec,
152};
153*/
154
155Command
156quit_cmd = {
157 .name = "quit",
158 .usage = "quit",
159 .description = "Quit nissy",
160 .parse_args = parse_no_arg,
161 .exec = quit_exec,
162};
163
164Command
165cleanup_cmd = {
166 .name = "cleanup",
167 .usage = "cleanup SCRAMBLE",
168 .description = "Rewrite a scramble using only standard moves (HTM)",
169 .parse_args = parse_only_scramble,
170 .exec = cleanup_exec,
171};
172
173Command
174unniss_cmd = {
175 .name = "unniss",
176 .usage = "unniss SCRAMBLE",
177 .description = "Rewrite a scramble without NISS",
178 .parse_args = parse_only_scramble,
179 .exec = unniss_exec,
180};
181
182Command
183version_cmd = {
184 .name = "version",
185 .usage = "version",
186 .description = "print nissy version",
187 .parse_args = parse_no_arg,
188 .exec = version_exec,
189};
190
191Command *commands[] = {
192 &commands_cmd,
193 &freemem_cmd,
194 &gen_cmd,
195 &help_cmd,
196 &invert_cmd,
197 &print_cmd,
198 &quit_cmd,
199 &solve_cmd,
200 &scramble_cmd,
201 &steps_cmd,
202/* &twophase_cmd,*/
203 &cleanup_cmd,
204 &unniss_cmd,
205 &version_cmd,
206 NULL
207};
208
209#endif
210 13
211#endif 14#endif
diff --git a/src/coord.c b/src/coord.c
index 673434f..a9df9fd 100644
--- a/src/coord.c
+++ b/src/coord.c
@@ -1,654 +1,611 @@
1#define COORD_C
2
3#include "coord.h" 1#include "coord.h"
4 2
5static void gen_coord_comp(Coordinate *coord); 3static uint64_t index_eofb(Cube cube);
6static void gen_coord_sym(Coordinate *coord); 4static uint64_t index_eofbepos(Cube cube);
7static bool read_coord_mtable(Coordinate *coord); 5static uint64_t index_epud(Cube cube);
8static bool read_coord_sd(Coordinate *coord); 6static uint64_t index_coud(Cube cube);
9static bool read_coord_ttable(Coordinate *coord); 7static uint64_t index_corners(Cube cube);
10static bool write_coord_mtable(Coordinate *coord); 8static uint64_t index_cp(Cube cube);
11static bool write_coord_sd(Coordinate *coord); 9static uint64_t index_cphtr(Cube cube);
12static bool write_coord_ttable(Coordinate *coord); 10static uint64_t index_cornershtr(Cube cube);
11static uint64_t index_cornershtrfin(Cube cube);
12static uint64_t index_drud(Cube cube);
13static uint64_t index_drud_eofb(Cube cube);
14static uint64_t index_htr_drud(Cube cube);
15static uint64_t index_htrfin(Cube cube);
16static uint64_t index_cpud_separate(Cube cube);
13 17
14/* Indexers ******************************************************************/ 18static uint64_t move_eofb(Move m, uint64_t ind);
19static uint64_t move_eofbepos(Move m, uint64_t ind);
20static uint64_t move_epud(Move m, uint64_t ind);
21static uint64_t move_coud(Move m, uint64_t ind);
22static uint64_t move_corners(Move m, uint64_t ind);
23static uint64_t move_cp(Move m, uint64_t ind);
24static uint64_t move_cphtr(Move m, uint64_t ind);
25static uint64_t move_cornershtr(Move m, uint64_t ind);
26static uint64_t move_cornershtrfin(Move m, uint64_t ind);
27static uint64_t move_drud(Move m, uint64_t ind);
28static uint64_t move_drud_eofb(Move m, uint64_t ind);
29static uint64_t move_htr_drud(Move m, uint64_t ind);
30static uint64_t move_htrfin(Move m, uint64_t ind);
31static uint64_t move_cpud_separate(Move m, uint64_t ind);
15 32
16uint64_t 33static void init_cphtr_cosets();
17index_eofb(Cube *cube) 34static void init_cphtr_left_cosets_bfs(int i, int c);
18{ 35static void init_cphtr_right_cosets_color(int i, int c);
19 return (uint64_t)digit_array_to_int(cube->eo, 11, 2); 36static void init_cpud_separate();
20} 37static void init_cornershtrfin();
38static void init_htr_eposs();
21 39
22uint64_t
23index_coud(Cube *cube)
24{
25 return (uint64_t)digit_array_to_int(cube->co, 7, 3);
26}
27 40
28uint64_t 41/* All sorts of useful costants and tables **********************************/
29index_cp(Cube *cube)
30{
31 return (uint64_t)perm_to_index(cube->cp, 8);
32}
33 42
34uint64_t 43static int cphtr_left_cosets[FACTORIAL8];
35index_cpudsep(Cube *cube) 44static int cphtr_right_cosets[FACTORIAL8];
36{ 45static int cphtr_right_rep[BINOM8ON4*6];
37 int i, c[8]; 46int cpud_separate_ind[FACTORIAL8];
47int cpud_separate_ant[BINOM8ON4];
48static int cornershtrfin_ind[FACTORIAL8];
49int cornershtrfin_ant[24*24/6];
50static int htr_eposs_ind[BINOM12ON4];
51static int htr_eposs_ant[BINOM8ON4];
38 52
39 for (i = 0; i < 8; i++) 53/* Coordinates and their implementation **************************************/
40 c[i] = cube->cp[i] < 4 ? 0 : 1;
41 54
42 return (uint64_t)subset_to_index(c, 8, 4); 55Coordinate
43} 56coord_eofb = {
57 .index = index_eofb,
58 .max = POW2TO11,
59 .move = move_eofb,
60};
44 61
45uint64_t 62Coordinate
46index_epe(Cube *cube) 63coord_eofbepos = {
47{ 64 .index = index_eofbepos,
48 int i, e[4]; 65 .max = POW2TO11 * BINOM12ON4,
66 .move = move_eofbepos,
67};
49 68
50 for (i = 0; i < 4; i++) 69Coordinate
51 e[i] = cube->ep[i+8] - 8; 70coord_coud = {
71 .index = index_coud,
72 .max = POW3TO7,
73 .move = move_coud,
74};
52 75
53 return (uint64_t)perm_to_index(e, 4); 76Coordinate
54} 77coord_corners = {
78 .index = index_corners,
79 .max = POW3TO7 * FACTORIAL8,
80 .move = move_corners,
81};
55 82
56uint64_t 83Coordinate
57index_epud(Cube *cube) 84coord_cp = {
58{ 85 .index = index_cp,
59 return (uint64_t)perm_to_index(cube->ep, 8); 86 .max = FACTORIAL8,
60} 87 .move = move_cp,
88};
61 89
62uint64_t 90Coordinate
63index_epos(Cube *cube) 91coord_cphtr = {
64{ 92 .index = index_cphtr,
65 int i, a[12]; 93 .max = BINOM8ON4 * 6,
94 .move = move_cphtr,
95};
66 96
67 for (i = 0; i < 12; i++) 97Coordinate
68 a[i] = (cube->ep[i] < 8) ? 0 : 1; 98coord_cornershtr = {
99 .index = index_cornershtr,
100 .max = POW3TO7 * BINOM8ON4 * 6,
101 .move = move_cornershtr,
102};
69 103
70 return (uint64_t)subset_to_index(a, 12, 4); 104Coordinate
71} 105coord_cornershtrfin = {
106 .index = index_cornershtrfin,
107 .max = 24*24/6,
108 .move = move_cornershtrfin,
109};
72 110
73uint64_t 111Coordinate
74index_eposepe(Cube *cube) 112coord_epud = {
75{ 113 .index = index_epud,
76 int i, j, e[4]; 114 .max = FACTORIAL8,
77 uint64_t epos, epe; 115 .move = move_epud,
116};
78 117
79 epos = (uint64_t)index_epos(cube); 118Coordinate
80 for (i = 0, j = 0; i < 12; i++) 119coord_drud = {
81 if (cube->ep[i] >= 8) 120 .index = index_drud,
82 e[j++] = cube->ep[i] - 8; 121 .max = POW2TO11 * POW3TO7 * BINOM12ON4,
83 epe = (uint64_t)perm_to_index(e, 4); 122 .move = move_drud,
123};
84 124
85 return epos * FACTORIAL4 + epe; 125Coordinate
86} 126coord_htr_drud = {
127 .index = index_htr_drud,
128 .max = BINOM8ON4 * 6 * BINOM8ON4,
129 .move = move_htr_drud,
130};
87 131
88/* Inverse indexers **********************************************************/ 132Coordinate
133coord_htrfin = {
134 .index = index_htrfin,
135 .max = 24 * 24 * 24 *24 * 24 / 6, /* should be /12 but it's ok */
136 .move = move_htrfin,
137};
89 138
90void 139Coordinate
91invindex_eofb(uint64_t ind, Cube *cube) 140coord_drud_eofb = {
92{ 141 .index = index_drud_eofb,
93 int_to_sum_zero_array(ind, 2, 12, cube->eo); 142 .max = POW3TO7 * BINOM12ON4,
94} 143 .move = move_drud_eofb,
144};
95 145
96void 146Coordinate
97invindex_coud(uint64_t ind, Cube *cube) 147coord_cpud_separate = {
148 .index = index_cpud_separate,
149 .max = BINOM8ON4,
150 .move = move_cpud_separate,
151};
152
153/* Indexers ******************************************************************/
154
155static uint64_t
156index_eofb(Cube cube)
98{ 157{
99 int_to_sum_zero_array(ind, 3, 8, cube->co); 158 return cube.eofb;
100} 159}
101 160
102void 161static uint64_t
103invindex_cp(uint64_t ind, Cube *cube) 162index_eofbepos(Cube cube)
104{ 163{
105 index_to_perm(ind, 8, cube->cp); 164 return (cube.epose / FACTORIAL4) * POW2TO11 + cube.eofb;
106} 165}
107 166
108void 167static uint64_t
109invindex_cpudsep(uint64_t ind, Cube *cube) 168index_epud(Cube cube)
110{ 169{
111 int i, j, k, c[8]; 170 uint64_t ret;
171 CubeArray *arr = new_cubearray(cube, pf_ep);
112 172
113 index_to_subset(ind, 8, 4, c); 173 ret = perm_to_index(arr->ep, 8);
114 for (i = 0, j = 0, k = 4; i < 8; i++) 174 free_cubearray(arr, pf_ep);
115 cube->cp[i] = c[i] == 0 ? j++ : k++; 175
176 return ret;
116} 177}
117 178
179static uint64_t
180index_coud(Cube cube)
181{
182 return cube.coud;
183}
118 184
119void 185static uint64_t
120invindex_epe(uint64_t ind, Cube *cube) 186index_corners(Cube cube)
121{ 187{
122 int i; 188 return cube.coud * FACTORIAL8 + cube.cp;
189}
123 190
124 index_to_perm(ind, 4, &cube->ep[8]); 191static uint64_t
125 for (i = 0; i < 4; i++) 192index_cp(Cube cube)
126 cube->ep[i+8] += 8; 193{
194 return cube.cp;
127} 195}
128 196
129void 197static uint64_t
130invindex_epud(uint64_t ind, Cube *cube) 198index_cphtr(Cube cube)
131{ 199{
132 index_to_perm(ind, 8, cube->ep); 200 return cphtr_right_cosets[cube.cp];
133} 201}
134 202
135void 203static uint64_t
136invindex_epos(uint64_t ind, Cube *cube) 204index_cornershtr(Cube cube)
137{ 205{
138 int i, j, k; 206 return cube.coud * BINOM8ON4 * 6 + index_cphtr(cube);
207}
139 208
140 index_to_subset(ind, 12, 4, cube->ep); 209static uint64_t
141 for (i = 0, j = 0, k = 8; i < 12; i++) 210index_cornershtrfin(Cube cube)
142 if (cube->ep[i] == 0) 211{
143 cube->ep[i] = j++; 212 return cornershtrfin_ind[cube.cp];
144 else
145 cube->ep[i] = k++;
146} 213}
147 214
148void 215static uint64_t
149invindex_eposepe(uint64_t ind, Cube *cube) 216index_drud(Cube cube)
150{ 217{
151 int i, j, k, e[4]; 218 uint64_t a, b, c;
152 uint64_t epos, epe;
153 219
154 epos = ind / FACTORIAL4; 220 a = cube.eofb;
155 epe = ind % FACTORIAL4; 221 b = cube.coud;
222 c = cube.epose / FACTORIAL4;
156 223
157 index_to_subset(epos, 12, 4, cube->ep); 224 b *= POW2TO11;
158 index_to_perm(epe, 4, e); 225 c *= POW2TO11 * POW3TO7;
159 226
160 for (i = 0, j = 0, k = 0; i < 12; i++) 227 return a + b + c;
161 if (cube->ep[i] == 0)
162 cube->ep[i] = j++;
163 else
164 cube->ep[i] = e[k++] + 8;
165} 228}
166 229
167/* Other local functions *****************************************************/ 230static uint64_t
168 231index_drud_eofb(Cube cube)
169uint64_t
170indexers_getmax(Indexer **is)
171{ 232{
172 int i; 233 return index_drud(cube) / POW2TO11;
173 uint64_t max = 1;
174
175 for (i = 0; is[i] != NULL; i++)
176 max *= is[i]->n;
177
178 return max;
179} 234}
180 235
181uint64_t 236static uint64_t
182indexers_getind(Indexer **is, Cube *c) 237index_htr_drud(Cube cube)
183{ 238{
184 int i; 239 uint64_t a, b;
185 uint64_t max = 0;
186 240
187 for (i = 0; is[i] != NULL; i++) { 241 a = index_cphtr(cube);
188 max *= is[i]->n; 242 b = htr_eposs_ind[cube.eposs/24];
189 max += is[i]->index(c);
190 }
191 243
192 return max; 244 return a * BINOM8ON4 + b;
193} 245}
194 246
195void 247static uint64_t
196indexers_makecube(Indexer **is, uint64_t ind, Cube *c) 248index_htrfin(Cube cube)
197{ 249{
198 /* Warning: anti-indexers are applied in the same order as indexers. */ 250 uint64_t epe, eps, epm, cp, ep;
199 /* We assume order does not matter, but it would make more sense to */
200 /* apply them in reverse. */
201 251
202 int i; 252 epe = cube.epose % 24;
203 uint64_t m; 253 eps = cube.eposs % 24;
254 epm = cube.eposm % 24;
255 ep = (epe * 24 + eps) *24 + epm;
256 cp = index_cornershtrfin(cube);
204 257
205 make_solved(c); 258 return cp * 24 * 24 * 24 + ep;
206 m = indexers_getmax(is);
207 for (i = 0; is[i] != NULL; i++) {
208 m /= is[i]->n;
209 is[i]->to_cube(ind / m, c);
210 ind %= m;
211 }
212} 259}
213 260
214static void 261static uint64_t
215gen_coord_comp(Coordinate *coord) 262index_cpud_separate(Cube cube)
216{ 263{
217 uint64_t ui; 264 return cpud_separate_ind[cube.cp];
218 Cube c, mvd; 265}
219 Move m;
220 Trans t;
221
222 coord->max = indexers_getmax(coord->i);
223
224 for (m = 0; m < NMOVES; m++)
225 coord->mtable[m] = malloc(coord->max * sizeof(uint64_t));
226 266
227 for (t = 0; t < NTRANS; t++) 267/* Coordinate movers *********************************************************/
228 coord->ttable[t] = malloc(coord->max * sizeof(uint64_t));
229 268
230 if (!read_coord_mtable(coord)) { 269static uint64_t
231 fprintf(stderr, "%s: generating mtable\n", coord->name); 270move_eofb(Move m, uint64_t ind)
271{
272 return eofb_mtable[m][ind];
273}
232 274
233 for (ui = 0; ui < coord->max; ui++) { 275static uint64_t
234 indexers_makecube(coord->i, ui, &c); 276move_eofbepos(Move m, uint64_t ind)
235 for (m = 0; m < NMOVES; m++) { 277{
236 copy_cube(&c, &mvd); 278 uint64_t a, b;
237 apply_move(m, &mvd);
238 coord->mtable[m][ui] =
239 indexers_getind(coord->i, &mvd);
240 }
241 }
242 if (!write_coord_mtable(coord))
243 fprintf(stderr, "%s: error writing mtable\n",
244 coord->name);
245
246 fprintf(stderr, "%s: mtable generated\n", coord->name);
247 }
248 279
249 if (!read_coord_ttable(coord)) { 280 a = epose_mtable[m][(ind / POW2TO11)*24];
250 fprintf(stderr, "%s: generating ttable\n", coord->name); 281 b = eofb_mtable[m][ind % POW2TO11];
251 282
252 for (ui = 0; ui < coord->max; ui++) { 283 return (a/24) * POW2TO11 + b;
253 indexers_makecube(coord->i, ui, &c);
254 for (t = 0; t < NTRANS; t++) {
255 copy_cube(&c, &mvd);
256 apply_trans(t, &mvd);
257 coord->ttable[t][ui] =
258 indexers_getind(coord->i, &mvd);
259 }
260 }
261 if (!write_coord_ttable(coord))
262 fprintf(stderr, "%s: error writing ttable\n",
263 coord->name);
264 }
265} 284}
266 285
267static void 286static uint64_t
268gen_coord_sym(Coordinate *coord) 287move_epud(Move m, uint64_t ind)
269{ 288{
270 uint64_t i, in, ui, uj, uu, M, nr; 289 /* TODO: save to file? */
290 static bool initialized = false;
291 static int a[12] = { [8] = 8, [9] = 9, [10] = 10, [11] = 11 };
292 static int shortlist[NMOVES] = {
293 [U] = 0, [U2] = 1, [U3] = 2, [D] = 3, [D2] = 4, [D3] = 5,
294 [R2] = 6, [L2] = 7, [F2] = 8, [B2] = 9
295 };
296 static uint64_t aux[10][FACTORIAL8];
297 uint64_t ui;
271 int j; 298 int j;
272 Move m; 299 Move mj;
273 Trans t; 300 Cube c;
274 301 CubeArray *arr, *auxarr;
275 M = coord->base[0]->max;
276 coord->selfsim = malloc(M * sizeof(uint64_t));
277 coord->symclass = malloc(M * sizeof(uint64_t));
278 coord->symrep = malloc(M * sizeof(uint64_t));
279 coord->transtorep = malloc(M * sizeof(Trans));
280
281 if (!read_coord_sd(coord)) {
282 fprintf(stderr, "%s: generating syms\n", coord->name);
283
284 for (i = 0; i < M; i++)
285 coord->symclass[i] = M+1;
286 302
287 for (i = 0, nr = 0; i < M; i++) { 303 if (!moveset_drud.allowed(m)) {
288 if (coord->symclass[i] != M+1) 304 fprintf(stderr, "Move not allowed for epud\n"
289 continue; 305 "This is a bug, please report\n");
306 return coord_epud.max;
307 }
290 308
291 coord->symrep[nr] = i; 309 if (!initialized) {
292 coord->transtorep[i] = uf; 310 auxarr = malloc(sizeof(CubeArray));
293 coord->selfsim[nr] = (uint64_t)0; 311 auxarr->ep = a;
294 for (j = 0; j < coord->tgrp->n; j++) { 312 for (ui = 0; ui < coord_epud.max; ui++) {
295 t = coord->tgrp->t[j]; 313 index_to_perm(ui, 8, a);
296 in = trans_coord(coord->base[0], t, i); 314 c = arrays_to_cube(auxarr, pf_ep);
297 coord->symclass[in] = nr; 315 for (j = 0; moveset_drud.sorted_moves[j] != NULLMOVE;
298 if (in == i) 316 j++) {
299 coord->selfsim[nr] |= ((uint64_t)1<<t); 317 mj = moveset_drud.sorted_moves[j];
300 else 318 arr = new_cubearray(apply_move(mj, c), pf_ep);
301 coord->transtorep[in] = 319 aux[shortlist[mj]][ui] =
302 inverse_trans(t); 320 perm_to_index(arr->ep, 8);
321 free_cubearray(arr, pf_ep);
303 } 322 }
304 nr++;
305 } 323 }
324 free(auxarr);
306 325
307 coord->max = nr; 326 initialized = true;
308
309 fprintf(stderr, "%s: found %" PRIu64 " classes\n",
310 coord->name, nr);
311 if (!write_coord_sd(coord))
312 fprintf(stderr, "%s: error writing symdata\n",
313 coord->name);
314 }
315
316 coord->symrep = realloc(coord->symrep, coord->max*sizeof(uint64_t));
317 coord->selfsim = realloc(coord->selfsim, coord->max*sizeof(uint64_t));
318
319 for (m = 0; m < NMOVES; m++) {
320 coord->mtable[m] = malloc(coord->max*sizeof(uint64_t));
321 coord->ttrep_move[m] = malloc(coord->max*sizeof(Trans));
322 } 327 }
323 328
324 if (!read_coord_mtable(coord)) { 329 return aux[shortlist[m]][ind];
325 for (ui = 0; ui < coord->max; ui++) {
326 uu = coord->symrep[ui];
327 for (m = 0; m < NMOVES; m++) {
328 uj = move_coord(coord->base[0], m, uu, NULL);
329 coord->mtable[m][ui] = coord->symclass[uj];
330 coord->ttrep_move[m][ui] =
331 coord->transtorep[uj];
332 }
333 }
334 if (!write_coord_mtable(coord))
335 fprintf(stderr, "%s: error writing mtable\n",
336 coord->name);
337 }
338} 330}
339 331
340static bool 332static uint64_t
341read_coord_mtable(Coordinate *coord) 333move_coud(Move m, uint64_t ind)
342{ 334{
343 FILE *f; 335 return coud_mtable[m][ind];
344 char fname[strlen(tabledir)+256]; 336}
345 Move m;
346 uint64_t M;
347 bool r;
348
349 strcpy(fname, tabledir);
350 strcat(fname, "/mt_");
351 strcat(fname, coord->name);
352
353 if ((f = fopen(fname, "rb")) == NULL)
354 return false;
355 337
356 M = coord->max; 338static uint64_t
357 r = true; 339move_corners(Move m, uint64_t ind)
358 for (m = 0; m < NMOVES; m++) 340{
359 r = r && fread(coord->mtable[m], sizeof(uint64_t), M, f) == M; 341 uint64_t a, b;
360 342
361 if (coord->type == SYM_COORD) 343 a = coud_mtable[m][ind / FACTORIAL8];
362 for (m = 0; m < NMOVES; m++) 344 b = cp_mtable[m][ind % FACTORIAL8];
363 r = r && fread(coord->ttrep_move[m],
364 sizeof(Trans), M, f) == M;
365 345
366 fclose(f); 346 return a * FACTORIAL8 + b;
367 return r;
368} 347}
369 348
370static bool 349static uint64_t
371read_coord_sd(Coordinate *coord) 350move_cp(Move m, uint64_t ind)
372{ 351{
373 FILE *f; 352 return cp_mtable[m][ind];
374 char fname[strlen(tabledir)+256]; 353}
375 uint64_t M, N;
376 bool r;
377 354
378 strcpy(fname, tabledir); 355static uint64_t
379 strcat(fname, "/sd_"); 356move_cphtr(Move m, uint64_t ind)
380 strcat(fname, coord->name); 357{
358 static bool initialized = false;
359 static uint64_t aux[NMOVES][BINOM8ON4*6];
360 uint64_t ui;
361 Move j;
381 362
382 if ((f = fopen(fname, "rb")) == NULL) 363 if (!initialized) {
383 return false; 364 for (ui = 0; ui < BINOM8ON4*6; ui++)
365 for (j = U; j < NMOVES; j++)
366 aux[j][ui] = cphtr_right_cosets[
367 cp_mtable[j][cphtr_right_rep[ui]]];
384 368
385 r = true; 369 initialized = true;
386 r = r && fread(&coord->max, sizeof(uint64_t), 1, f) == 1; 370 }
387 M = coord->max;
388 N = coord->base[0]->max;
389 r = r && fread(coord->symrep, sizeof(uint64_t), M, f) == M;
390 r = r && fread(coord->selfsim, sizeof(uint64_t), M, f) == M;
391 r = r && fread(coord->symclass, sizeof(uint64_t), N, f) == N;
392 r = r && fread(coord->transtorep, sizeof(Trans), N, f) == N;
393 371
394 fclose(f); 372 return aux[m][ind];
395 return r;
396} 373}
397 374
398static bool 375static uint64_t
399read_coord_ttable(Coordinate *coord) 376move_cornershtr(Move m, uint64_t ind)
400{ 377{
401 FILE *f; 378 uint64_t a, b;
402 char fname[strlen(tabledir)+256];
403 Trans t;
404 uint64_t M;
405 bool r;
406
407 strcpy(fname, tabledir);
408 strcat(fname, "/tt_");
409 strcat(fname, coord->name);
410
411 if ((f = fopen(fname, "rb")) == NULL)
412 return false;
413 379
414 M = coord->max; 380 a = coud_mtable[m][ind/(BINOM8ON4 * 6)];
415 r = true; 381 b = move_cphtr(m, ind % (BINOM8ON4 * 6));
416 for (t = 0; t < NTRANS; t++)
417 r = r && fread(coord->ttable[t], sizeof(uint64_t), M, f) == M;
418 382
419 fclose(f); 383 return a * BINOM8ON4 * 6 + b;
420 return r;
421} 384}
422 385
423static bool 386static uint64_t
424write_coord_mtable(Coordinate *coord) 387move_cornershtrfin(Move m, uint64_t ind)
425{ 388{
426 FILE *f; 389 int a;
427 char fname[strlen(tabledir)+256];
428 Move m;
429 uint64_t M;
430 bool r;
431 390
432 strcpy(fname, tabledir); 391 a = cp_mtable[m][cornershtrfin_ant[ind]];
433 strcat(fname, "/mt_");
434 strcat(fname, coord->name);
435 392
436 if ((f = fopen(fname, "wb")) == NULL) 393 return cornershtrfin_ind[a];
437 return false; 394}
438 395
439 M = coord->max; 396static uint64_t
440 r = true; 397move_drud(Move m, uint64_t ind)
441 for (m = 0; m < NMOVES; m++) 398{
442 r = r && fwrite(coord->mtable[m], sizeof(uint64_t), M, f) == M; 399 uint64_t a, b, c;
443 400
444 if (coord->type == SYM_COORD) 401 a = eofb_mtable[m][ind % POW2TO11];
445 for (m = 0; m < NMOVES; m++) 402 b = coud_mtable[m][(ind / POW2TO11) % POW3TO7];
446 r = r && fwrite(coord->ttrep_move[m], 403 c = epose_mtable[m][ind / (POW2TO11 * POW3TO7)];
447 sizeof(Trans), M, f) == M;
448 404
449 fclose(f); 405 return a + (b + c * POW3TO7) * POW2TO11;
450 return r;
451} 406}
452 407
453static bool 408static uint64_t
454write_coord_sd(Coordinate *coord) 409move_drud_eofb(Move m, uint64_t ind)
455{ 410{
456 FILE *f; 411 uint64_t a, b;
457 char fname[strlen(tabledir)+256];
458 uint64_t M, N;
459 bool r;
460
461 strcpy(fname, tabledir);
462 strcat(fname, "/sd_");
463 strcat(fname, coord->name);
464 412
465 if ((f = fopen(fname, "wb")) == NULL) 413 a = coud_mtable[m][ind % POW3TO7];
466 return false; 414 b = epose_mtable[m][(ind / POW3TO7) * 24] / 24;
467 415
468 r = true; 416 return a + b * POW3TO7;
469 M = coord->max;
470 N = coord->base[0]->max;
471 r = r && fwrite(&coord->max, sizeof(uint64_t), 1, f) == 1;
472 r = r && fwrite(coord->symrep, sizeof(uint64_t), M, f) == M;
473 r = r && fwrite(coord->selfsim, sizeof(uint64_t), M, f) == M;
474 r = r && fwrite(coord->symclass, sizeof(uint64_t), N, f) == N;
475 r = r && fwrite(coord->transtorep, sizeof(Trans), N, f) == N;
476
477 fclose(f);
478 return r;
479} 417}
480 418
481static bool 419static uint64_t
482write_coord_ttable(Coordinate *coord) 420move_htr_drud(Move m, uint64_t ind)
483{ 421{
484 FILE *f; 422 uint64_t a, b;
485 char fname[strlen(tabledir)+256];
486 Trans t;
487 uint64_t M;
488 bool r;
489 423
490 strcpy(fname, tabledir); 424 a = move_cphtr(m, ind/BINOM8ON4);
491 strcat(fname, "/tt_"); 425 b = eposs_mtable[m][htr_eposs_ant[ind%BINOM8ON4]];
492 strcat(fname, coord->name);
493 426
494 if ((f = fopen(fname, "wb")) == NULL) 427 return a*BINOM8ON4 + htr_eposs_ind[b/24];
495 return false; 428}
496 429
497 M = coord->max; 430static uint64_t
498 r = true; 431move_htrfin(Move m, uint64_t ind)
499 for (t = 0; t < NTRANS; t++) 432{
500 r = r && fwrite(coord->ttable[t], sizeof(uint64_t), M, f) == M; 433 uint64_t a, b, bm, bs, be;
501 434
502 fclose(f); 435 a = move_cornershtrfin(m, ind / (24*24*24));
503 return r; 436 bm = eposm_mtable[m][ind%24] % 24;
504} 437 bs = eposs_mtable[m][(ind/24)%24] % 24;
438 be = epose_mtable[m][(ind/(24*24))%24] % 24;
439 b = (be * 24 + bs) * 24 + bm;
505 440
506/* Public functions **********************************************************/ 441 return a * (24*24*24) + b;
442}
507 443
508void 444static uint64_t
509gen_coord(Coordinate *coord) 445move_cpud_separate(Move m, uint64_t ind)
510{ 446{
511 int i; 447 return cpud_separate_ind[cp_mtable[m][cpud_separate_ant[ind]]];
448}
512 449
513 if (coord == NULL || coord->generated) 450/* Init functions implementation *********************************************/
514 return;
515 451
516 for (i = 0; i < 2; i++) 452/*
517 gen_coord(coord->base[i]); 453 * There is certainly a better way to do this, but for now I just use
454 * a "graph coloring" algorithm to compute the left cosets, and I compose
455 * with every possible cp to get the right cosets (it is possible that I am
456 * mixing up left and right).
457 *
458 * For doing it better "Mathematically", we need 3 things:
459 * - Checking that cp separates the orbits (UFR,UBL,DFL,DBR) and the other
460 * This is easy and it is done in the commented function cphtr_cp().
461 * - Check that there is no ep/cp parity
462 * - Check that we are not in the "3c" case; this is the part I don't
463 * know how to do.
464 */
465static void
466init_cphtr_cosets()
467{
468 unsigned int i;
469 int c = 0, d = 0;
518 470
519 switch (coord->type) { 471 for (i = 0; i < FACTORIAL8; i++) {
520 case COMP_COORD: 472 cphtr_left_cosets[i] = -1;
521 if (coord->i[0] == NULL) 473 cphtr_right_cosets[i] = -1;
522 goto error_gc;
523 gen_coord_comp(coord);
524 break;
525 case SYM_COORD:
526 if (coord->base[0] == NULL || coord->tgrp == NULL)
527 goto error_gc;
528 gen_coord_sym(coord);
529 break;
530 case SYMCOMP_COORD:
531 if (coord->base[0] == NULL || coord->base[1] == NULL)
532 goto error_gc;
533 coord->max = coord->base[0]->max * coord->base[1]->max;
534 break;
535 default:
536 break;
537 } 474 }
538 475
539 coord->generated = true; 476 /* First we compute left cosets with a bfs */
540 return; 477 for (i = 0; i < FACTORIAL8; i++)
478 if (cphtr_left_cosets[i] == -1)
479 init_cphtr_left_cosets_bfs(i, c++);
541 480
542error_gc: 481 /* Then we compute right cosets using compose() */
543 fprintf(stderr, "Error generating coordinates.\n" 482 for (i = 0; i < FACTORIAL8; i++)
544 "This is a bug, pleae report.\n"); 483 if (cphtr_right_cosets[i] == -1)
545 exit(1); 484 init_cphtr_right_cosets_color(i, d++);
546} 485}
547 486
548uint64_t 487static void
549index_coord(Coordinate *coord, Cube *cube, Trans *offtrans) 488init_cphtr_left_cosets_bfs(int i, int c)
550{ 489{
551 uint64_t c[2], cnosym; 490 int j, jj, next[FACTORIAL8], next2[FACTORIAL8], n, n2;
552 Trans ttr;
553
554 switch (coord->type) {
555 case COMP_COORD:
556 if (offtrans != NULL)
557 *offtrans = uf;
558 491
559 return indexers_getind(coord->i, cube); 492 Move k;
560 case SYM_COORD:
561 cnosym = index_coord(coord->base[0], cube, NULL);
562 ttr = coord->transtorep[cnosym];
563 493
564 if (offtrans != NULL) 494 n = 1;
565 *offtrans = ttr; 495 next[0] = i;
496 cphtr_left_cosets[i] = c;
566 497
567 return coord->symclass[cnosym]; 498 while (n != 0) {
568 case SYMCOMP_COORD: 499 for (j = 0, n2 = 0; j < n; j++) {
569 c[0] = index_coord(coord->base[0], cube, NULL); 500 for (k = U2; k < B3; k++) {
570 cnosym = index_coord(coord->base[0]->base[0], cube, NULL); 501 if (!moveset_htr.allowed(k))
571 ttr = coord->base[0]->transtorep[cnosym]; 502 continue;
572 c[1] = index_coord(coord->base[1], cube, NULL); 503 jj = apply_move(k, (Cube){ .cp = next[j] }).cp;
573 c[1] = trans_coord(coord->base[1], ttr, c[1]);
574 504
575 if (offtrans != NULL) 505 if (cphtr_left_cosets[jj] == -1) {
576 *offtrans = ttr; 506 cphtr_left_cosets[jj] = c;
507 next2[n2++] = jj;
508 }
509 }
510 }
577 511
578 return c[0] * coord->base[1]->max + c[1]; 512 for (j = 0; j < n2; j++)
579 default: 513 next[j] = next2[j];
580 break; 514 n = n2;
581 } 515 }
582
583 return coord->max; /* Only reached in case of error */
584} 516}
585 517
586uint64_t 518static void
587move_coord(Coordinate *coord, Move m, uint64_t ind, Trans *offtrans) 519init_cphtr_right_cosets_color(int i, int d)
588{ 520{
589 uint64_t i[2], M; 521 int cp;
590 Trans ttr; 522 unsigned int j;
591 523
592 /* Some safety checks should be done here, but for performance * 524 cphtr_right_rep[d] = i;
593 * reasons we'd rather do them before calling this function. * 525 for (j = 0; j < FACTORIAL8; j++) {
594 * We should check if coord is generated. */ 526 if (cphtr_left_cosets[j] == 0) {
595 527 cp = compose((Cube){.cp = i}, (Cube){.cp = j}).cp;
596 switch (coord->type) { 528 cphtr_right_cosets[cp] = d;
597 case COMP_COORD: 529 }
598 if (offtrans != NULL) 530 }
599 *offtrans = uf; 531}
600 532
601 return coord->mtable[m][ind]; 533static void
602 case SYM_COORD: 534init_cpud_separate()
603 ttr = coord->ttrep_move[m][ind]; 535{
536 unsigned int ui;
537 int i, co[8];
604 538
605 if (offtrans != NULL) 539 for (ui = 0; ui < FACTORIAL8; ui++) {
606 *offtrans = ttr; 540 for (i = 0; i < 8; i++)
541 co[i] = what_corner_at((Cube){.cp=ui},i)>UBR ? 1 : 0;
542 cpud_separate_ind[ui] = subset_to_index(co, 8, 4);
543 cpud_separate_ant[cpud_separate_ind[ui]] = ui;
544 }
545}
607 546
608 return coord->mtable[m][ind]; 547static void
609 case SYMCOMP_COORD: 548init_cornershtrfin()
610 M = coord->base[1]->max; 549{
611 i[0] = ind / M; 550 unsigned int i, j;
612 i[1] = ind % M; 551 int n, c;
613 ttr = coord->base[0]->ttrep_move[m][i[0]]; 552 Move m;
614 i[0] = coord->base[0]->mtable[m][i[0]];
615 i[1] = coord->base[1]->mtable[m][i[1]];
616 i[1] = coord->base[1]->ttable[ttr][i[1]];
617 553
618 if (offtrans != NULL) 554 for (i = 0; i < FACTORIAL8; i++)
619 *offtrans = ttr; 555 cornershtrfin_ind[i] = -1;
556 cornershtrfin_ind[0] = 0;
620 557
621 return i[0] * M + i[1]; 558 /* 10-pass, I think 5 is enough, but just in case */
622 default: 559 n = 1;
623 break; 560 for (i = 0; i < 10; i++) {
561 for (j = 0; j < FACTORIAL8; j++) {
562 if (cornershtrfin_ind[j] == -1)
563 continue;
564 for (m = U; m < NMOVES; m++) {
565 if (moveset_htr.allowed(m)) {
566 c = cp_mtable[m][j];
567 if (cornershtrfin_ind[c] == -1) {
568 cornershtrfin_ind[c] = n;
569 cornershtrfin_ant[n] = c;
570 n++;
571 }
572 }
573 }
574 }
624 } 575 }
625
626 return coord->max; /* Only reached in case of error */
627} 576}
628 577
629uint64_t 578void
630trans_coord(Coordinate *coord, Trans t, uint64_t ind) 579init_htr_eposs()
631{ 580{
632 uint64_t i[2], M; 581 int ep[12], ep2[12];
582 int eps_solved[4] = {UL, UR, DL, DR};
583 unsigned int i, j;
633 584
634 /* Some safety checks should be done here, but for performance * 585 for (i = 0; i < BINOM12ON4; i++) {
635 * reasons we'd rather do them before calling this function. * 586 for (j = 0; j < 12; j++)
636 * We should check if coord is generated. */ 587 ep[j] = ep2[j] = 0;
637 588 epos_to_partial_ep(i*24, ep, eps_solved);
638 switch (coord->type) { 589 for (j = 0; j < 8; j++)
639 case COMP_COORD: 590 ep2[j/2 + 4*(j%2)] = ep[j] ? 1 : 0;
640 return coord->ttable[t][ind]; 591 htr_eposs_ind[i] = subset_to_index(ep2, 8, 4);
641 case SYM_COORD: 592 htr_eposs_ant[htr_eposs_ind[i]] = i*24;
642 return ind;
643 case SYMCOMP_COORD:
644 M = coord->base[1]->max;
645 i[0] = ind / M; /* Always fixed */
646 i[1] = ind % M;
647 i[1] = coord->base[1]->ttable[t][i[1]];
648 return i[0] * M + i[1];
649 default:
650 break;
651 } 593 }
594}
595
596void
597init_coord()
598{
599 static bool initialized = false;
600 if (initialized)
601 return;
602 initialized = true;
652 603
653 return coord->max; /* Only reached in case of error */ 604 init_trans();
605
606 init_cphtr_cosets();
607 init_cornershtrfin();
608 init_htr_eposs();
609 init_cpud_separate();
654} 610}
611
diff --git a/src/coord.h b/src/coord.h
index 4cd7e47..61398a4 100644
--- a/src/coord.h
+++ b/src/coord.h
@@ -3,257 +3,26 @@
3 3
4#include "trans.h" 4#include "trans.h"
5 5
6void gen_coord(Coordinate *coord); 6extern Coordinate coord_eofb;
7uint64_t index_coord(Coordinate *coord, Cube *cube, 7extern Coordinate coord_eofbepos;
8 Trans *offtrans); 8extern Coordinate coord_coud;
9uint64_t indexers_getind(Indexer **is, Cube *c); 9extern Coordinate coord_cp;
10void indexers_makecube(Indexer **is, uint64_t ind, Cube *c); 10extern Coordinate coord_cphtr;
11uint64_t move_coord(Coordinate *coord, Move m, 11extern Coordinate coord_corners;
12 uint64_t ind, Trans *offtrans); 12extern Coordinate coord_cornershtr;
13uint64_t trans_coord(Coordinate *coord, Trans t, uint64_t ind); 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;
19extern Coordinate coord_cpud_separate;
14 20
15/* Base coordinates and their index functions ********************************/ 21extern int cpud_separate_ant[BINOM8ON4];
22extern int cpud_separate_ind[FACTORIAL8];
23extern int cornershtrfin_ant[24*24/6];
16 24
17#ifndef COORD_C 25void init_coord();
18
19extern Coordinate coord_eofb;
20extern Coordinate coord_coud;
21extern Coordinate coord_cp;
22extern Coordinate coord_cpudsep;
23extern Coordinate coord_epos;
24extern Coordinate coord_epe;
25extern Coordinate coord_eposepe;
26extern Coordinate coord_epud;
27extern Coordinate coord_eofbepos;
28extern Coordinate coord_coud_cpudsep;
29extern Coordinate coord_eofbepos_sym16;
30extern Coordinate coord_cp_sym16;
31extern Coordinate coord_corners_sym16;
32extern Coordinate coord_drud_sym16;
33extern Coordinate coord_drudfin_noE_sym16;
34extern Coordinate coord_nxopt31;
35
36extern Coordinate *all_coordinates[];
37
38#else
39
40/* Indexers ******************************************************************/
41
42uint64_t index_eofb(Cube *cube);
43void invindex_eofb(uint64_t ind, Cube *ret);
44Indexer
45i_eofb = {
46 .n = POW2TO11,
47 .index = index_eofb,
48 .to_cube = invindex_eofb,
49};
50
51uint64_t index_coud(Cube *cube);
52void invindex_coud(uint64_t ind, Cube *ret);
53Indexer
54i_coud = {
55 .n = POW3TO7,
56 .index = index_coud,
57 .to_cube = invindex_coud,
58};
59
60uint64_t index_cp(Cube *cube);
61void invindex_cp(uint64_t ind, Cube *ret);
62Indexer
63i_cp = {
64 .n = FACTORIAL8,
65 .index = index_cp,
66 .to_cube = invindex_cp,
67};
68
69uint64_t index_cpudsep(Cube *cube);
70void invindex_cpudsep(uint64_t ind, Cube *ret);
71Indexer
72i_cpudsep = {
73 .n = BINOM8ON4,
74 .index = index_cpudsep,
75 .to_cube = invindex_cpudsep,
76};
77
78uint64_t index_epos(Cube *cube);
79void invindex_epos(uint64_t ind, Cube *ret);
80Indexer
81i_epos = {
82 .n = BINOM12ON4,
83 .index = index_epos,
84 .to_cube = invindex_epos,
85};
86
87uint64_t index_epe(Cube *cube);
88void invindex_epe(uint64_t ind, Cube *ret);
89Indexer
90i_epe = {
91 .n = FACTORIAL4,
92 .index = index_epe,
93 .to_cube = invindex_epe,
94};
95
96uint64_t index_eposepe(Cube *cube);
97void invindex_eposepe(uint64_t ind, Cube *ret);
98Indexer
99i_eposepe = {
100 .n = BINOM12ON4 * FACTORIAL4,
101 .index = index_eposepe,
102 .to_cube = invindex_eposepe,
103};
104
105uint64_t index_epud(Cube *cube);
106void invindex_epud(uint64_t ind, Cube *ret);
107Indexer
108i_epud = {
109 .n = FACTORIAL8,
110 .index = index_epud,
111 .to_cube = invindex_epud,
112};
113
114/* Composite coordinates *****************************************************/
115
116Coordinate
117coord_eofb = {
118 .name = "eofb",
119 .type = COMP_COORD,
120 .i = {&i_eofb, NULL},
121};
122
123Coordinate
124coord_coud = {
125 .name = "coud",
126 .type = COMP_COORD,
127 .i = {&i_coud, NULL},
128};
129
130Coordinate
131coord_cp = {
132 .name = "cp",
133 .type = COMP_COORD,
134 .i = {&i_cp, NULL},
135};
136
137Coordinate
138coord_cpudsep = {
139 .name = "cpudsep",
140 .type = COMP_COORD,
141 .i = {&i_cpudsep, NULL},
142};
143
144Coordinate
145coord_epos = {
146 .name = "epos",
147 .type = COMP_COORD,
148 .i = {&i_epos, NULL},
149};
150
151Coordinate
152coord_epe = {
153 .name = "epe",
154 .type = COMP_COORD,
155 .i = {&i_epe, NULL},
156};
157
158Coordinate
159coord_eposepe = { /* Has to be done by hand, hard compose epos + epe */
160 .name = "eposepe",
161 .type = COMP_COORD,
162 .i = {&i_eposepe, NULL},
163};
164
165Coordinate
166coord_epud = {
167 .name = "epud",
168 .type = COMP_COORD,
169 .i = {&i_epud, NULL},
170};
171
172Coordinate
173coord_eofbepos = {
174 .name = "eofbepos",
175 .type = COMP_COORD,
176 .i = {&i_epos, &i_eofb, NULL},
177};
178
179Coordinate
180coord_coud_cpudsep = {
181 .name = "coud_cpudsep",
182 .type = COMP_COORD,
183 .i = {&i_coud, &i_cpudsep, NULL},
184};
185
186/* Symcoordinates ************************************************************/
187
188Coordinate
189coord_eofbepos_sym16 = {
190 .name = "eofbepos_sym16",
191 .type = SYM_COORD,
192 .base = {&coord_eofbepos, NULL},
193 .tgrp = &tgrp_udfix,
194};
195
196Coordinate
197coord_cp_sym16 = {
198 .name = "cp_sym16",
199 .type = SYM_COORD,
200 .base = {&coord_cp, NULL},
201 .tgrp = &tgrp_udfix,
202};
203
204/* "Symcomp" coordinates *****************************************************/
205
206Coordinate
207coord_corners_sym16 = {
208 .name = "corners_sym16",
209 .type = SYMCOMP_COORD,
210 .base = {&coord_cp_sym16, &coord_coud},
211};
212
213Coordinate
214coord_drud_sym16 = {
215 .name = "drud_sym16",
216 .type = SYMCOMP_COORD,
217 .base = {&coord_eofbepos_sym16, &coord_coud},
218};
219
220Coordinate
221coord_drudfin_noE_sym16 = {
222 .name = "drudfin_noE_sym16",
223 .type = SYMCOMP_COORD,
224 .base = {&coord_cp_sym16, &coord_epud},
225};
226
227Coordinate
228coord_nxopt31 = {
229 .name = "nxopt31",
230 .type = SYMCOMP_COORD,
231 .base = {&coord_eofbepos_sym16, &coord_coud_cpudsep},
232};
233
234/* All coordinates ***********************************************************/
235
236Coordinate *all_coordinates[] = {
237 &coord_eofb,
238 &coord_coud,
239 &coord_cp,
240 &coord_cpudsep,
241 &coord_epos,
242 &coord_epe,
243 &coord_eposepe,
244 &coord_epud,
245 &coord_eofbepos,
246 &coord_coud_cpudsep,
247 &coord_eofbepos_sym16,
248 &coord_cp_sym16,
249 &coord_corners_sym16,
250 &coord_drud_sym16,
251 &coord_drudfin_noE_sym16,
252 &coord_nxopt31,
253 NULL
254};
255
256#endif
257 26
258#endif 27#endif
259 28
diff --git a/src/cube.c b/src/cube.c
index 92c6713..aae3a6e 100644
--- a/src/cube.c
+++ b/src/cube.c
@@ -1,205 +1,531 @@
1#define CUBE_C
2
3#include "cube.h" 1#include "cube.h"
4 2
5static int where_is_piece(int piece, int *arr, int n); 3/* Local functions ***********************************************************/
6 4
7void 5static void init_inverse();
8compose_centers(Cube *c2, Cube *c1) 6static bool read_invtables_file();
7static bool write_invtables_file();
8
9/* Tables ********************************************************************/
10
11static uint16_t eo_invtable_e[POW2TO11][BINOM12ON4*FACTORIAL4];
12static uint16_t eo_invtable_s[POW2TO11][BINOM12ON4*FACTORIAL4];
13static uint16_t eo_invtable_m[POW2TO11][BINOM12ON4*FACTORIAL4];
14static uint16_t co_invtable[POW3TO7][FACTORIAL8];
15static uint16_t cp_invtable[FACTORIAL8];
16static uint16_t cpos_invtable[FACTORIAL6];
17
18/* Functions implementation **************************************************/
19
20int
21array_ep_to_epos(int *ep, int *ss)
9{ 22{
10 apply_permutation(c2->xp, c1->xp, 6); 23 int epos[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
24 int eps[4];
25 int i, j, is;
26
27 for (i = 0, is = 0; i < 12; i++) {
28 for (j = 0; j < 4; j++) {
29 if (ep[i] == ss[j]) {
30 eps[is++] = j;
31 epos[i] = 1;
32 }
33 }
34 }
35
36 for (i = 0; i < 4; i++)
37 swap(&epos[ss[i]], &epos[i+8]);
38
39 return 24 * subset_to_index(epos, 12, 4) + perm_to_index(eps, 4);
11} 40}
12 41
13void 42Cube
14compose_corners(Cube *c2, Cube *c1) 43arrays_to_cube(CubeArray *arr, PieceFilter f)
15{ 44{
16 apply_permutation(c2->cp, c1->cp, 8); 45 Cube ret = {0};
17 apply_permutation(c2->cp, c1->co, 8); 46
18 sum_arrays_mod(c2->co, c1->co, 8, 3); 47 static int epe_solved[4] = {FR, FL, BL, BR};
48 static int eps_solved[4] = {UL, UR, DL, DR};
49 static int epm_solved[4] = {UF, UB, DF, DB};
50
51 if (f.epose)
52 ret.epose = array_ep_to_epos(arr->ep, epe_solved);
53 if (f.eposs)
54 ret.eposs = array_ep_to_epos(arr->ep, eps_solved);
55 if (f.eposm)
56 ret.eposm = array_ep_to_epos(arr->ep, epm_solved);
57 if (f.eofb)
58 ret.eofb = digit_array_to_int(arr->eofb, 11, 2);
59 if (f.eorl)
60 ret.eorl = digit_array_to_int(arr->eorl, 11, 2);
61 if (f.eoud)
62 ret.eoud = digit_array_to_int(arr->eoud, 11, 2);
63 if (f.cp)
64 ret.cp = perm_to_index(arr->cp, 8);
65 if (f.coud)
66 ret.coud = digit_array_to_int(arr->coud, 7, 3);
67 if (f.corl)
68 ret.corl = digit_array_to_int(arr->corl, 7, 3);
69 if (f.cofb)
70 ret.cofb = digit_array_to_int(arr->cofb, 7, 3);
71 if (f.cpos)
72 ret.cpos = perm_to_index(arr->cpos, 6);
73
74 return ret;
19} 75}
20 76
21void 77Cube
22compose_edges(Cube *c2, Cube *c1) 78compose_filtered(Cube c2, Cube c1, PieceFilter f)
23{ 79{
24 apply_permutation(c2->ep, c1->ep, 12); 80 CubeArray *arr = new_cubearray(c2, f);
25 apply_permutation(c2->ep, c1->eo, 12); 81 Cube ret;
26 sum_arrays_mod(c2->eo, c1->eo, 12, 2); 82
83 ret = move_via_arrays(arr, c1, f);
84 free_cubearray(arr, f);
85
86 return ret;
27} 87}
28 88
29void 89void
30compose(Cube *c2, Cube *c1) 90cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f)
31{ 91{
32 compose_centers(c2, c1); 92 int i;
33 compose_corners(c2, c1); 93
34 compose_edges(c2, c1); 94 static int epe_solved[4] = {FR, FL, BL, BR};
95 static int eps_solved[4] = {UL, UR, DL, DR};
96 static int epm_solved[4] = {UF, UB, DF, DB};
97
98 if (f.epose || f.eposs || f.eposm)
99 for (i = 0; i < 12; i++)
100 arr->ep[i] = -1;
101
102 if (f.epose)
103 epos_to_partial_ep(cube.epose, arr->ep, epe_solved);
104 if (f.eposs)
105 epos_to_partial_ep(cube.eposs, arr->ep, eps_solved);
106 if (f.eposm)
107 epos_to_partial_ep(cube.eposm, arr->ep, epm_solved);
108 if (f.eofb)
109 int_to_sum_zero_array(cube.eofb, 2, 12, arr->eofb);
110 if (f.eorl)
111 int_to_sum_zero_array(cube.eorl, 2, 12, arr->eorl);
112 if (f.eoud)
113 int_to_sum_zero_array(cube.eoud, 2, 12, arr->eoud);
114 if (f.cp)
115 index_to_perm(cube.cp, 8, arr->cp);
116 if (f.coud)
117 int_to_sum_zero_array(cube.coud, 3, 8, arr->coud);
118 if (f.corl)
119 int_to_sum_zero_array(cube.corl, 3, 8, arr->corl);
120 if (f.cofb)
121 int_to_sum_zero_array(cube.cofb, 3, 8, arr->cofb);
122 if (f.cpos)
123 index_to_perm(cube.cpos, 6, arr->cpos);
35} 124}
36 125
37void 126void
38copy_cube_centers(Cube *src, Cube *dst) 127epos_to_compatible_ep(int epos, int *ep, int *ss)
39{ 128{
40 memcpy(dst->xp, src->xp, 6 * sizeof(int)); 129 int i, j, k, other[8];
130 bool flag;
131
132 for (i = 0; i < 12; i++)
133 ep[i] = -1;
134
135 epos_to_partial_ep(epos, ep, ss);
136
137 for (i = 0, j = 0; i < 12; i++) {
138 flag = false;
139 for (k = 0; k < 4; k++)
140 flag = flag || (i == ss[k]);
141 if (!flag)
142 other[j++] = i;
143 }
144
145 for (i = 0, j = 0; i < 12; i++)
146 if (ep[i] == -1)
147 ep[i] = other[j++];
41} 148}
42 149
43void 150void
44copy_cube_corners(Cube *src, Cube *dst) 151epos_to_partial_ep(int epos, int *ep, int *ss)
45{ 152{
46 memcpy(dst->cp, src->cp, 8 * sizeof(int)); 153 int i, is, eposs[12], eps[4];
47 memcpy(dst->co, src->co, 8 * sizeof(int)); 154
155 index_to_perm(epos % FACTORIAL4, 4, eps);
156 index_to_subset(epos / FACTORIAL4, 12, 4, eposs);
157
158 for (i = 0; i < 4; i++)
159 swap(&eposs[ss[i]], &eposs[i+8]);
160
161 for (i = 0, is = 0; i < 12; i++)
162 if (eposs[i])
163 ep[i] = ss[eps[is++]];
48} 164}
49 165
50void 166void
51copy_cube_edges(Cube *src, Cube *dst) 167fix_eorleoud(CubeArray *arr)
52{ 168{
53 memcpy(dst->ep, src->ep, 12 * sizeof(int)); 169 int i;
54 memcpy(dst->eo, src->eo, 12 * sizeof(int)); 170
171 for (i = 0; i < 12; i++) {
172 if ((edge_slice(i) == 0 && edge_slice(arr->ep[i]) != 0) ||
173 (edge_slice(i) != 0 && edge_slice(arr->ep[i]) == 0)) {
174 arr->eorl[i] = 1 - arr->eofb[i];
175 } else {
176 arr->eorl[i] = arr->eofb[i];
177 }
178
179 if ((edge_slice(i) == 2 && edge_slice(arr->ep[i]) != 2) ||
180 (edge_slice(i) != 2 && edge_slice(arr->ep[i]) == 2)) {
181 arr->eoud[i] = 1 - arr->eofb[i];
182 } else {
183 arr->eoud[i] = arr->eofb[i];
184 }
185 }
55} 186}
56 187
57void 188void
58copy_cube(Cube *src, Cube *dst) 189fix_cofbcorl(CubeArray *arr)
59{ 190{
60 copy_cube_centers(src, dst); 191 int i;
61 copy_cube_corners(src, dst); 192
62 copy_cube_edges(src, dst); 193 for (i = 0; i < 8; i++) {
194 if (i % 2 == arr->cp[i] % 2) {
195 arr->cofb[i] = arr->coud[i];
196 arr->corl[i] = arr->coud[i];
197 } else {
198 if (arr->cp[i] % 2 == 0) {
199 arr->cofb[i] = (arr->coud[i]+1)%3;
200 arr->corl[i] = (arr->coud[i]+2)%3;
201 } else {
202 arr->cofb[i] = (arr->coud[i]+2)%3;
203 arr->corl[i] = (arr->coud[i]+1)%3;
204 }
205 }
206 }
63} 207}
64 208
65bool 209Cube
66equal(Cube *c1, Cube *c2) 210fourval_to_cube(int eofb, int ep, int coud, int cp)
67{ 211{
68 int i; 212 CubeArray *arr;
69 213
70 for (i = 0; i < 12; i++) 214 arr = new_cubearray((Cube){0}, pf_all);
71 if (c1->ep[i] != c2->ep[i] || c1->eo[i] != c2->eo[i])
72 return false;
73 215
74 for (i = 0; i < 8; i++) 216 index_to_perm(ep, 12, arr->ep);
75 if (c1->cp[i] != c2->cp[i] || c1->co[i] != c2->co[i]) 217 index_to_perm(cp, 8, arr->cp);
76 return false; 218 int_to_sum_zero_array(eofb, 2, 12, arr->eofb);
219 int_to_sum_zero_array(coud, 3, 8, arr->coud);
77 220
78 for (i = 0; i < 6; i++) 221 /* fix parity */
79 if (c1->xp[i] != c2->xp[i]) 222 if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8))
80 return false; 223 swap(&(arr->ep[0]), &(arr->ep[1]));
81 224
82 return true; 225 fix_eorleoud(arr);
226 fix_cofbcorl(arr);
227
228 return arrays_to_cube(arr, pf_all);
83} 229}
84 230
85void 231void
86invert_cube_centers(Cube *cube) 232free_cubearray(CubeArray *arr, PieceFilter f)
87{ 233{
88 int i; 234 if (f.epose || f.eposs || f.eposm)
89 Cube aux; 235 free(arr->ep);
90 236 if (f.eofb)
91 copy_cube_centers(cube, &aux); 237 free(arr->eofb);
238 if (f.eorl)
239 free(arr->eorl);
240 if (f.eoud)
241 free(arr->eoud);
242 if (f.cp)
243 free(arr->cp);
244 if (f.coud)
245 free(arr->coud);
246 if (f.corl)
247 free(arr->corl);
248 if (f.cofb)
249 free(arr->cofb);
250 if (f.cpos)
251 free(arr->cpos);
92 252
93 for (i = 0; i < 6; i++) 253 free(arr);
94 cube->xp[aux.xp[i]] = i;
95} 254}
96 255
97void 256Cube
98invert_cube_corners(Cube *cube) 257move_via_arrays(CubeArray *arr, Cube c, PieceFilter f)
99{ 258{
100 int i; 259 CubeArray *arrc = new_cubearray(c, f);
101 Cube aux; 260 Cube ret;
102 261
103 copy_cube_corners(cube, &aux); 262 if (f.epose || f.eposs || f.eposm)
263 apply_permutation(arr->ep, arrc->ep, 12);
104 264
105 for (i = 0; i < 8; i++) { 265 if (f.eofb) {
106 cube->cp[aux.cp[i]] = i; 266 apply_permutation(arr->ep, arrc->eofb, 12);
107 cube->co[aux.cp[i]] = (3 - aux.co[i]) % 3; 267 sum_arrays_mod(arr->eofb, arrc->eofb, 12, 2);
108 } 268 }
269
270 if (f.eorl) {
271 apply_permutation(arr->ep, arrc->eorl, 12);
272 sum_arrays_mod(arr->eorl, arrc->eorl, 12, 2);
273 }
274
275 if (f.eoud) {
276 apply_permutation(arr->ep, arrc->eoud, 12);
277 sum_arrays_mod(arr->eoud, arrc->eoud, 12, 2);
278 }
279
280 if (f.cp)
281 apply_permutation(arr->cp, arrc->cp, 8);
282
283 if (f.coud) {
284 apply_permutation(arr->cp, arrc->coud, 8);
285 sum_arrays_mod(arr->coud, arrc->coud, 8, 3);
286 }
287
288 if (f.corl) {
289 apply_permutation(arr->cp, arrc->corl, 8);
290 sum_arrays_mod(arr->corl, arrc->corl, 8, 3);
291 }
292
293 if (f.cofb) {
294 apply_permutation(arr->cp, arrc->cofb, 8);
295 sum_arrays_mod(arr->cofb, arrc->cofb, 8, 3);
296 }
297
298 if (f.cpos)
299 apply_permutation(arr->cpos, arrc->cpos, 6);
300
301 ret = arrays_to_cube(arrc, f);
302 free_cubearray(arrc, f);
303
304 return ret;
109} 305}
110 306
111void 307CubeArray *
112invert_cube_edges(Cube *cube) 308new_cubearray(Cube cube, PieceFilter f)
113{ 309{
114 int i; 310 CubeArray *arr = malloc(sizeof(CubeArray));
115 Cube aux;
116 311
117 copy_cube_edges(cube, &aux); 312 if (f.epose || f.eposs || f.eposm)
313 arr->ep = malloc(12 * sizeof(int));
314 if (f.eofb)
315 arr->eofb = malloc(12 * sizeof(int));
316 if (f.eorl)
317 arr->eorl = malloc(12 * sizeof(int));
318 if (f.eoud)
319 arr->eoud = malloc(12 * sizeof(int));
320 if (f.cp)
321 arr->cp = malloc(8 * sizeof(int));
322 if (f.coud)
323 arr->coud = malloc(8 * sizeof(int));
324 if (f.corl)
325 arr->corl = malloc(8 * sizeof(int));
326 if (f.cofb)
327 arr->cofb = malloc(8 * sizeof(int));
328 if (f.cpos)
329 arr->cpos = malloc(6 * sizeof(int));
118 330
119 for (i = 0; i < 12; i++) { 331 cube_to_arrays(cube, arr, f);
120 cube->ep[aux.ep[i]] = i; 332
121 cube->eo[aux.ep[i]] = aux.eo[i]; 333 return arr;
334}
335
336Cube
337admissible_ep(Cube cube, PieceFilter f)
338{
339 CubeArray *arr = new_cubearray(cube, f);
340 Cube ret;
341 bool used[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
342 int i, j;
343
344 for (i = 0; i < 12; i++)
345 if (arr->ep[i] != -1)
346 used[arr->ep[i]] = true;
347
348 for (i = 0, j = 0; i < 12; i++) {
349 for ( ; j < 11 && used[j]; j++);
350 if (arr->ep[i] == -1)
351 arr->ep[i] = j++;
122 } 352 }
353
354 ret = arrays_to_cube(arr, pf_ep);
355 free_cubearray(arr, f);
356
357 return ret;
123} 358}
124 359
125void 360Cube
126invert_cube(Cube *cube) 361compose(Cube c2, Cube c1)
127{ 362{
128 invert_cube_centers(cube); 363 return compose_filtered(c2, c1, pf_all);
129 invert_cube_corners(cube); 364}
130 invert_cube_edges(cube); 365
366int
367edge_slice(Edge e) {
368 if (e < 0 || e > 11)
369 return -1;
370
371 if (e == FR || e == FL || e == BL || e == BR)
372 return 0;
373 if (e == UR || e == UL || e == DR || e == DL)
374 return 1;
375
376 return 2;
131} 377}
132 378
133bool 379bool
134is_admissible(Cube *c) { 380equal(Cube c1, Cube c2)
135 bool perm; 381{
136 int sign, i; 382 return c1.eofb == c2.eofb &&
137 int sum_e, sum_c; 383 c1.epose == c2.epose &&
384 c1.eposs == c2.eposs &&
385 c1.eposm == c2.eposm &&
386 c1.coud == c2.coud &&
387 c1.cp == c2.cp &&
388 c1.cpos == c2.cpos;
389}
390
391Cube
392inverse_cube(Cube cube)
393{
394 CubeArray inv;
395 Cube ret;
396 int i, ep[12];
138 397
139 perm = is_perm(c->ep, 12) && is_perm(c->cp, 8) && is_perm(c->xp, 6); 398 for (i = 0; i < 12; i++)
399 ep[i] = where_is_edge(cube, i);
400 inv = (CubeArray){.ep = ep};
401 ret = arrays_to_cube(&inv, pf_ep);
140 402
141 sign = perm_sign(c->ep,12) + perm_sign(c->cp,8) + perm_sign(c->xp,6); 403 ret.eofb = ((int)eo_invtable_e[cube.eofb][cube.epose]) |
404 ((int)eo_invtable_m[cube.eofb][cube.eposm]) |
405 ((int)eo_invtable_s[cube.eofb][cube.eposs]);
406 ret.eorl = ((int)eo_invtable_e[cube.eorl][cube.epose]) |
407 ((int)eo_invtable_m[cube.eorl][cube.eposm]) |
408 ((int)eo_invtable_s[cube.eorl][cube.eposs]);
409 ret.eoud = ((int)eo_invtable_e[cube.eoud][cube.epose]) |
410 ((int)eo_invtable_m[cube.eoud][cube.eposm]) |
411 ((int)eo_invtable_s[cube.eoud][cube.eposs]);
412 ret.cp = cp_invtable[cube.cp];
413 ret.cpos = cpos_invtable[cube.cpos];
414 ret.coud = co_invtable[cube.coud][cube.cp];
415 ret.corl = co_invtable[cube.corl][cube.cp];
416 ret.cofb = co_invtable[cube.cofb][cube.cp];
142 417
143 for (i = 0, sum_e = 0; i < 12; i++) 418 return ret;
144 if (c->eo[i] > 1) 419}
145 return false;
146 else
147 sum_e += c->eo[i];
148 420
149 for (i = 0, sum_c = 0; i < 8; i++) 421bool
150 if (c->co[i] > 2) 422is_admissible(Cube cube) {
151 return false; 423
152 else 424 /* TODO: this should check consistency of different orientations */
153 sum_c += c->co[i]; 425 /* check also that centers are opposite and admissible */
154 426
155 return (perm && sign % 2 == 0 && sum_e % 2 == 0 && sum_c % 2 == 0); 427 CubeArray *a = new_cubearray(cube, pf_all);
428 int parity;
429 bool perm;
430
431 perm = is_perm(a->ep, 12) &&
432 is_perm(a->cp, 8) &&
433 is_perm(a->cpos, 6);
434 parity = perm_sign(a->ep, 12) +
435 perm_sign(a->cp, 8) +
436 perm_sign(a->cpos, 6);
437
438 free_cubearray(a, pf_all);
439
440 return perm && parity % 2 == 0;
156} 441}
157 442
158bool 443bool
159is_solved(Cube *cube) 444is_solved(Cube cube)
160{ 445{
161 Cube solved_cube; 446 return equal(cube, (Cube){0});
162 make_solved(&solved_cube);
163
164 return equal(cube, &solved_cube);
165} 447}
166 448
167void 449bool
168make_solved_centers(Cube *cube) 450is_block_solved(Cube cube, Block block)
169{ 451{
170 static int sorted[6] = {0, 1, 2, 3, 4, 5}; 452 int i;
453
454 for (i = 0; i < 12; i++)
455 if (block.edge[i] && !is_solved_edge(cube, i))
456 return false;
457 for (i = 0; i < 8; i++)
458 if (block.corner[i] && !is_solved_corner(cube, i))
459 return false;
460 for (i = 0; i < 6; i++)
461 if (block.center[i] && !is_solved_center(cube, i))
462 return false;
171 463
172 memcpy(cube->xp, sorted, 6 * sizeof(int)); 464 return true;
173} 465}
174 466
175void 467bool
176make_solved_corners(Cube *cube) 468is_solved_center(Cube cube, Center c)
177{ 469{
178 static int sorted[8] = {0, 1, 2, 3, 4, 5, 6, 7}; 470 return what_center_at(cube, c) == c;
179
180 memcpy(cube->cp, sorted, 8 * sizeof(int));
181 memset(cube->co, 0, 8 * sizeof(int));
182} 471}
183 472
184void 473bool
185make_solved_edges(Cube *cube) 474is_solved_corner(Cube cube, Corner c)
186{ 475{
187 static int sorted[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; 476 return what_corner_at(cube, c) == c &&
477 what_orientation_corner(cube.coud, c);
478}
188 479
189 memcpy(cube->ep, sorted, 12 * sizeof(int)); 480bool
190 memset(cube->eo, 0, 12 * sizeof(int)); 481is_solved_edge(Cube cube, Edge e)
482{
483 return what_edge_at(cube, e) == e &&
484 what_orientation_edge(cube.eofb, e);
191} 485}
192 486
193void 487int
194make_solved(Cube *cube) 488piece_orientation(Cube cube, int piece, char *orientation)
195{ 489{
196 make_solved_centers(cube); 490 int arr[12], n, b, x;
197 make_solved_corners(cube); 491
198 make_solved_edges(cube); 492 if (!strcmp(orientation, "eofb")) {
493 x = cube.eofb;
494 n = 12;
495 b = 2;
496 } else if (!strcmp(orientation, "eorl")) {
497 x = cube.eorl;
498 n = 12;
499 b = 2;
500 } else if (!strcmp(orientation, "eoud")) {
501 x = cube.eoud;
502 n = 12;
503 b = 2;
504 } else if (!strcmp(orientation, "coud")) {
505 x = cube.coud;
506 n = 8;
507 b = 3;
508 } else if (!strcmp(orientation, "corl")) {
509 x = cube.corl;
510 n = 8;
511 b = 3;
512 } else if (!strcmp(orientation, "cofb")) {
513 x = cube.cofb;
514 n = 8;
515 b = 3;
516 } else {
517 return -1;
518 }
519
520 int_to_sum_zero_array(x, b, n, arr);
521 if (piece < n)
522 return arr[piece];
523
524 return -1;
199} 525}
200 526
201void 527void
202print_cube(Cube *cube) 528print_cube(Cube cube)
203{ 529{
204 static char edge_string[12][7] = { 530 static char edge_string[12][7] = {
205 [UF] = "UF", [UL] = "UL", [UB] = "UB", [UR] = "UR", 531 [UF] = "UF", [UL] = "UL", [UB] = "UB", [UR] = "UR",
@@ -219,52 +545,388 @@ print_cube(Cube *cube)
219 }; 545 };
220 546
221 for (int i = 0; i < 12; i++) 547 for (int i = 0; i < 12; i++)
222 printf(" %s ", edge_string[cube->ep[i]]); 548 printf(" %s ", edge_string[what_edge_at(cube, i)]);
223 printf("\n"); 549 printf("\n");
224 550
225 for (int i = 0; i < 12; i++) 551 for (int i = 0; i < 12; i++)
226 printf(" %" PRIu8 " ", cube->eo[i]); 552 printf(" %d ", what_orientation_edge(cube.eofb, i));
227 printf("\n"); 553 printf("\n");
228 554
229 for (int i = 0; i < 8; i++) 555 for (int i = 0; i < 8; i++)
230 printf("%s ", corner_string[cube->cp[i]]); 556 printf("%s ", corner_string[what_corner_at(cube, i)]);
231 printf("\n"); 557 printf("\n");
232 558
233 for (int i = 0; i < 8; i++) 559 for (int i = 0; i < 8; i++)
234 printf(" %" PRIu8 " ", cube->co[i]); 560 printf(" %d ", what_orientation_corner(cube.coud, i));
235 printf("\n"); 561 printf("\n");
236 562
237 for (int i = 0; i < 6; i++) 563 for (int i = 0; i < 6; i++)
238 printf(" %s ", center_string[cube->xp[i]]); 564 printf(" %s ", center_string[what_center_at(cube, i)]);
239 printf("\n"); 565 printf("\n");
240} 566}
241 567
242int 568Center
243where_is_center(Center x, Cube *c) 569what_center_at(Cube cube, Center c)
570{
571 static bool initialized = false;
572 static Center aux[FACTORIAL6][6];
573 static int i;
574 static unsigned int ui;
575 static CubeArray *arr;
576
577 if (!initialized) {
578 for (ui = 0; ui < FACTORIAL6; ui++) {
579 arr = new_cubearray((Cube){.cpos = ui}, pf_cpos);
580 for (i = 0; i < 6; i++)
581 aux[ui][i] = arr->cpos[i];
582 free_cubearray(arr, pf_cpos);
583 }
584
585 initialized = true;
586 }
587
588 return aux[cube.cpos][c];
589}
590
591Corner
592what_corner_at(Cube cube, Corner c)
593{
594 int i;
595 unsigned int ui;
596 CubeArray *arr;
597
598 static bool initialized = false;
599 static Corner aux[FACTORIAL8][8];
600
601 if (!initialized) {
602 for (ui = 0; ui < FACTORIAL8; ui++) {
603 arr = new_cubearray((Cube){.cp = ui}, pf_cp);
604 for (i = 0; i < 8; i++)
605 aux[ui][i] = arr->cp[i];
606 free_cubearray(arr, pf_cp);
607 }
608
609 initialized = true;
610 }
611
612 return aux[cube.cp][c];
613}
614
615Edge
616what_edge_at(Cube cube, Edge e)
244{ 617{
245 return where_is_piece(x, c->xp, 6); 618 Edge ret;
619 CubeArray *arr = new_cubearray(cube, pf_ep);
620
621 ret = arr->ep[e];
622
623 free_cubearray(arr, pf_ep);
624 return ret;
246} 625}
247 626
248int 627int
249where_is_corner(Corner k, Cube *c) 628what_orientation_corner(int co, Corner c)
250{ 629{
251 return where_is_piece(k, c->cp, 8); 630 static bool initialized = false;
631 static int auxlast[POW3TO7];
632 static int auxarr[8];
633 static unsigned int ui;
634
635 if (!initialized) {
636 for (ui = 0; ui < POW3TO7; ui++) {
637 int_to_sum_zero_array(ui, 3, 8, auxarr);
638 auxlast[ui] = auxarr[7];
639 }
640
641 initialized = true;
642 }
643
644 if (c < 7)
645 return (co / powint(3, c)) % 3;
646 else
647 return auxlast[co];
252} 648}
253 649
254int 650int
255where_is_edge(Edge e, Cube *c) 651what_orientation_edge(int eo, Edge e)
652{
653 static bool initialized = false;
654 static int auxlast[POW2TO11];
655 static int auxarr[12];
656 static unsigned int ui;
657
658 if (!initialized) {
659 for (ui = 0; ui < POW2TO11; ui++) {
660 int_to_sum_zero_array(ui, 2, 12, auxarr);
661 auxlast[ui] = auxarr[11];
662 }
663
664 initialized = true;
665 }
666
667 if (e < 11)
668 return (eo & (1 << e)) ? 1 : 0;
669 else
670 return auxlast[eo];
671}
672
673Center
674where_is_center(Cube cube, Center c)
256{ 675{
257 return where_is_piece(e, c->ep, 12); 676 static bool initialized = false;
677 static Center aux[FACTORIAL6][6];
678 static int i;
679 static unsigned int ui;
680 static CubeArray *arr;
681
682 if (!initialized) {
683 for (ui = 0; ui < FACTORIAL6; ui++) {
684 arr = new_cubearray((Cube){.cpos = ui}, pf_cpos);
685 for (i = 0; i < 6; i++)
686 aux[ui][arr->cpos[i]] = i;
687 free_cubearray(arr, pf_cpos);
688 }
689
690 initialized = true;
691 }
692
693 return aux[cube.cpos][c];
258} 694}
259 695
260static int 696Corner
261where_is_piece(int piece, int *arr, int n) 697where_is_corner(Cube cube, Corner c)
262{ 698{
263 int i; 699 static bool initialized = false;
700 static Corner aux[FACTORIAL8][8];
701 static int i;
702 static unsigned int ui;
703 static CubeArray *arr;
264 704
265 for (i = 0; i < n; i++) 705 if (!initialized) {
266 if (arr[i] == piece) 706 for (ui = 0; ui < FACTORIAL8; ui++) {
267 return i; 707 arr = new_cubearray((Cube){.cp = ui}, pf_cp);
708 for (i = 0; i < 8; i++)
709 aux[ui][arr->cp[i]] = i;
710 free_cubearray(arr, pf_cp);
711 }
268 712
269 return -1; 713 initialized = true;
714 }
715 return aux[cube.cp][c];
716}
717
718Edge
719where_is_edge(Cube c, Edge e)
720{
721 int r0, r1, r2;
722
723 static bool initialized = false;
724 static int aux[3][BINOM12ON4*FACTORIAL4][12];
725 static int i, j;
726 static unsigned int ui;
727 static CubeArray *arr;
728
729 if (!initialized) {
730 for (ui = 0; ui < BINOM12ON4*FACTORIAL4; ui++) {
731 for (i = 0; i < 3; i++)
732 for (j = 0; j < 12; j++)
733 aux[i][ui][j] = -1;
734
735 arr = new_cubearray((Cube){.epose = ui}, pf_e);
736 for (i = 0; i < 12; i++)
737 if (edge_slice(arr->ep[i]) == 0)
738 aux[0][ui][arr->ep[i]] = i;
739 free_cubearray(arr, pf_e);
740
741 arr = new_cubearray((Cube){.eposs = ui}, pf_s);
742 for (i = 0; i < 12; i++)
743 if (edge_slice(arr->ep[i]) == 1)
744 aux[1][ui][arr->ep[i]] = i;
745 free_cubearray(arr, pf_s);
746
747 arr = new_cubearray((Cube){.eposm = ui}, pf_m);
748 for (i = 0; i < 12; i++)
749 if (edge_slice(arr->ep[i]) == 2)
750 aux[2][ui][arr->ep[i]] = i;
751 free_cubearray(arr, pf_m);
752 }
753
754 initialized = true;
755 }
756
757 r0 = aux[0][c.epose][e];
758 r1 = aux[1][c.eposs][e];
759 r2 = aux[2][c.eposm][e];
760 return MAX(r0, MAX(r1, r2));
761}
762
763static bool
764read_invtables_file()
765{
766 init_env();
767
768 FILE *f;
769 char fname[strlen(tabledir)+20];
770 int b;
771 unsigned int ui, meeo, meco, mecp, mecpos;
772 bool r;
773
774 strcpy(fname, tabledir);
775 strcat(fname, "/invtables");
776
777 if ((f = fopen(fname, "rb")) == NULL)
778 return false;
779
780 b = sizeof(uint16_t);
781 r = true;
782 meeo = BINOM12ON4*FACTORIAL4;
783 meco = FACTORIAL8;
784 mecp = FACTORIAL8;
785 mecpos = FACTORIAL6;
786
787 for (ui = 0; ui < POW2TO11; ui++) {
788 r = r && fread(eo_invtable_e[ui], b, meeo, f) == meeo;
789 r = r && fread(eo_invtable_m[ui], b, meeo, f) == meeo;
790 r = r && fread(eo_invtable_s[ui], b, meeo, f) == meeo;
791 }
792
793 for (ui = 0; ui < POW3TO7; ui++) {
794 r = r && fread(co_invtable[ui], b, meco, f) == meco;
795 }
796
797 r = r && fread(cp_invtable, b, mecp, f) == mecp;
798 r = r && fread(cpos_invtable, b, mecpos, f) == mecpos;
799
800 fclose(f);
801 return r;
802}
803
804static bool
805write_invtables_file()
806{
807 init_env();
808
809 FILE *f;
810 char fname[strlen(tabledir)+20];
811 unsigned int ui, meeo, meco, mecp, mecpos;
812 int b;
813 bool r;
814
815 strcpy(fname, tabledir);
816 strcat(fname, "/invtables");
817
818 if ((f = fopen(fname, "wb")) == NULL)
819 return false;
820
821 b = sizeof(uint16_t);
822 r = true;
823 meeo = BINOM12ON4*FACTORIAL4;
824 meco = FACTORIAL8;
825 mecp = FACTORIAL8;
826 mecpos = FACTORIAL6;
827
828 for (ui = 0; ui < POW2TO11; ui++) {
829 r = r && fwrite(eo_invtable_e[ui], b, meeo, f) == meeo;
830 r = r && fwrite(eo_invtable_m[ui], b, meeo, f) == meeo;
831 r = r && fwrite(eo_invtable_s[ui], b, meeo, f) == meeo;
832 }
833
834 for (ui = 0; ui < POW3TO7; ui++) {
835 r = r && fwrite(co_invtable[ui], b, meco, f) == meco;
836 }
837
838 r = r && fwrite(cp_invtable, b, mecp, f) == mecp;
839 r = r && fwrite(cpos_invtable, b, mecpos, f) == mecpos;
840
841 fclose(f);
842 return r;
843}
844
845void
846init_inverse()
847{
848 static bool initialized = false;
849 if (initialized)
850 return;
851 initialized = true;
852
853 if (read_invtables_file())
854 return;
855
856 fprintf(stderr, "Cannot load invtables, generating it\n");
857
858 CubeArray *aux, *inv;
859 Cube c;
860 int i, j, eoaux[12], eoinv[12];
861 unsigned int ui, uj;
862
863 aux = new_cubearray((Cube){0}, pf_all);
864 inv = new_cubearray((Cube){0}, pf_all);
865
866 for (ui = 0; ui < POW2TO11; ui++) {
867 int_to_sum_zero_array(ui, 2, 12, eoaux);
868 for (uj = 0; uj < BINOM12ON4*FACTORIAL4; uj++) {
869 for (j = 0; j < 12; j++)
870 eoinv[j] = 0;
871 c = (Cube){.epose = uj, .eposm = 0, .eposs = 0};
872 eoinv[FR] = eoaux[where_is_edge(c, FR)];
873 eoinv[FL] = eoaux[where_is_edge(c, FL)];
874 eoinv[BL] = eoaux[where_is_edge(c, BL)];
875 eoinv[BR] = eoaux[where_is_edge(c, BR)];
876 eo_invtable_e[ui][uj] = digit_array_to_int(eoinv,11,2);
877
878 for (j = 0; j < 12; j++)
879 eoinv[j] = 0;
880 c = (Cube){.epose = 0, .eposm = uj, .eposs = 0};
881 eoinv[UF] = eoaux[where_is_edge(c, UF)];
882 eoinv[UB] = eoaux[where_is_edge(c, UB)];
883 eoinv[DF] = eoaux[where_is_edge(c, DF)];
884 eoinv[DB] = eoaux[where_is_edge(c, DB)];
885 eo_invtable_m[ui][uj] = digit_array_to_int(eoinv,11,2);
886
887 for (j = 0; j < 12; j++)
888 eoinv[j] = 0;
889 c = (Cube){.epose = 0, .eposm = 0, .eposs = uj};
890 eoinv[UL] = eoaux[where_is_edge(c, UL)];
891 eoinv[UR] = eoaux[where_is_edge(c, UR)];
892 eoinv[DL] = eoaux[where_is_edge(c, DL)];
893 eoinv[DR] = eoaux[where_is_edge(c, DR)];
894 eo_invtable_s[ui][uj] = digit_array_to_int(eoinv,11,2);
895 }
896 }
897
898 for (ui = 0; ui < FACTORIAL8; ui++) {
899 cube_to_arrays((Cube){.cp = ui}, aux, pf_cp);
900 for (i = 0; i < 8; i++)
901 inv->cp[aux->cp[i]] = i;
902 cp_invtable[ui] = (uint16_t)arrays_to_cube(inv, pf_cp).cp;
903
904 for (uj = 0; uj < POW3TO7; uj++) {
905 cube_to_arrays((Cube){.coud = uj}, aux, pf_coud);
906 for (i = 0; i < 8; i++)
907 inv->coud[aux->cp[i]] = (3-aux->coud[i])%3;
908 co_invtable[uj][ui] =
909 (uint16_t)arrays_to_cube(inv, pf_coud).coud;
910 }
911 }
912
913 for (ui = 0; ui < FACTORIAL6; ui++) {
914 cube_to_arrays((Cube){.cpos = ui}, aux, pf_cpos);
915 for (i = 0; i < 6; i++)
916 inv->cpos[aux->cpos[i]] = i;
917 cpos_invtable[ui] =
918 (uint16_t)arrays_to_cube(inv, pf_cpos).cpos;
919 }
920
921 free_cubearray(aux, pf_all);
922 free_cubearray(inv, pf_all);
923
924 if (!write_invtables_file())
925 fprintf(stderr, "Error writing invtables\n");
926}
927
928void
929init_cube()
930{
931 init_inverse();
270} 932}
diff --git a/src/cube.h b/src/cube.h
index f182b27..483a89a 100644
--- a/src/cube.h
+++ b/src/cube.h
@@ -3,33 +3,44 @@
3 3
4#include <stdio.h> 4#include <stdio.h>
5 5
6#include "cubetypes.h"
7#include "env.h" 6#include "env.h"
7#include "pf.h"
8#include "utils.h" 8#include "utils.h"
9 9
10void compose(Cube *c2, Cube *c1); /* Use c2 as an alg on c1 */ 10Cube admissible_ep(Cube cube, PieceFilter f);
11void compose_centers(Cube *c2, Cube *c1); 11int array_ep_to_epos(int *ep, int *eps_solved);
12void compose_corners(Cube *c2, Cube *c1); 12Cube arrays_to_cube(CubeArray *arr, PieceFilter f);
13void compose_edges(Cube *c2, Cube *c1); 13Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */
14void copy_cube(Cube *src, Cube *dst); 14Cube compose_filtered(Cube c2, Cube c1, PieceFilter f);
15void copy_cube_centers(Cube *src, Cube *dst); 15void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f);
16void copy_cube_corners(Cube *src, Cube *dst); 16int edge_slice(Edge e); /* E=0, S=1, M=2 */
17void copy_cube_edges(Cube *src, Cube *dst); 17bool equal(Cube c1, Cube c2);
18bool equal(Cube *c1, Cube *c2); 18Cube inverse_cube(Cube cube);
19void invert_cube(Cube *cube); 19bool is_admissible(Cube cube);
20void invert_cube_centers(Cube *cube); 20bool is_solved(Cube cube);
21void invert_cube_corners(Cube *cube); 21bool is_block_solved(Cube cube, Block);
22void invert_cube_edges(Cube *cube); 22bool is_solved_center(Cube cube, Center c);
23bool is_admissible(Cube *cube); 23bool is_solved_corner(Cube cube, Corner c);
24bool is_solved(Cube *cube); 24bool is_solved_edge(Cube cube, Edge e);
25void make_solved(Cube *cube); 25void epos_to_partial_ep(int epos, int *ep, int *ss);
26void make_solved_centers(Cube *cube); 26void epos_to_compatible_ep(int epos, int *ep, int *ss);
27void make_solved_corners(Cube *cube); 27void fix_eorleoud(CubeArray *arr);
28void make_solved_edges(Cube *cube); 28void fix_cofbcorl(CubeArray *arr);
29void print_cube(Cube *cube); 29Cube fourval_to_cube(int eofb, int ep, int coud, int cp);
30int where_is_center(Center x, Cube *c); 30void free_cubearray(CubeArray *arr, PieceFilter f);
31int where_is_corner(Corner k, Cube *c); 31Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf);
32int where_is_edge(Edge e, Cube *c); 32CubeArray * new_cubearray(Cube cube, PieceFilter f);
33void print_cube(Cube cube);
34Center what_center_at(Cube cube, Center c);
35Corner what_corner_at(Cube cube, Corner c);
36Edge what_edge_at(Cube cube, Edge e);
37int what_orientation_corner(int co, Corner c);
38int what_orientation_edge(int eo, Edge e);
39Center where_is_center(Cube cube, Center c);
40Corner where_is_corner(Cube cube, Corner c);
41Edge where_is_edge(Cube cube, Edge e);
42
43void init_cube();
33 44
34#endif 45#endif
35 46
diff --git a/src/cubetypes.h b/src/cubetypes.h
index 3752019..ad9c627 100644
--- a/src/cubetypes.h
+++ b/src/cubetypes.h
@@ -10,8 +10,6 @@
10#define NROTATIONS 24 10#define NROTATIONS 24
11#define entry_group_t uint8_t /* For pruning tables */ 11#define entry_group_t uint8_t /* For pruning tables */
12 12
13#define MAX_N_COORD 6
14
15/* Enums *********************************************************************/ 13/* Enums *********************************************************************/
16 14
17typedef enum 15typedef enum
@@ -30,12 +28,6 @@ corner
30} Corner; 28} Corner;
31 29
32typedef enum 30typedef enum
33coordtype
34{
35 COMP_COORD, SYM_COORD, SYMCOMP_COORD
36} CoordType;
37
38typedef enum
39edge 31edge
40{ 32{
41 UF, UL, UB, UR, 33 UF, UL, UB, UR,
@@ -84,32 +76,33 @@ trans
84typedef struct alg Alg; 76typedef struct alg Alg;
85typedef struct alglist AlgList; 77typedef struct alglist AlgList;
86typedef struct alglistnode AlgListNode; 78typedef struct alglistnode AlgListNode;
87typedef struct choicestep ChoiceStep; 79typedef struct block Block;
88typedef struct command Command; 80typedef struct command Command;
89typedef struct commandargs CommandArgs; 81typedef struct commandargs CommandArgs;
90typedef struct coordinate Coordinate; 82typedef struct coordinate Coordinate;
91typedef struct cube Cube; 83typedef struct cube Cube;
92/*typedef struct dfsarg DfsArg;*/ 84typedef struct cubearray CubeArray;
93typedef struct fstcube FstCube; 85typedef struct dfsarg DfsArg;
94typedef struct indexer Indexer; 86typedef struct estimatedata EstimateData;
95typedef struct movable Movable;
96typedef struct moveset Moveset; 87typedef struct moveset Moveset;
88typedef struct piecefilter PieceFilter;
97typedef struct prunedata PruneData; 89typedef struct prunedata PruneData;
98typedef struct solveoptions SolveOptions; 90typedef struct solveoptions SolveOptions;
99typedef struct step Step; 91typedef struct step Step;
100typedef struct symdata SymData; 92typedef struct symdata SymData;
101typedef struct threaddatasolve ThreadDataSolve; 93typedef struct threaddatasolve ThreadDataSolve;
102typedef struct threaddatagenpt ThreadDataGenpt; 94typedef struct threaddatagenpt ThreadDataGenpt;
103typedef struct transgroup TransGroup;
104 95
105typedef bool (*Checker) (Cube *); 96typedef Cube (*AntiIndexer) (uint64_t);
106typedef bool (*CubeTester) (Cube *, Alg *); 97typedef bool (*Checker) (Cube);
107/*typedef bool (*DfsMover) (DfsArg *);*/ 98typedef uint64_t (*CoordMover) (Move, uint64_t);
108typedef void (*DfsExtraCopier) (void *, void *); 99typedef uint64_t (*CoordTransformer) (Trans, uint64_t);
109typedef Alg * (*Validator) (Alg *); 100typedef int (*Estimator) (DfsArg *);
101typedef bool (*Validator) (Alg *);
110typedef void (*Exec) (CommandArgs *); 102typedef void (*Exec) (CommandArgs *);
103typedef uint64_t (*Indexer) (Cube);
111typedef CommandArgs * (*ArgParser) (int, char **); 104typedef CommandArgs * (*ArgParser) (int, char **);
112typedef bool (*Tester) (void); 105typedef int (*TransDetector) (Cube, Trans *);
113typedef int (*TransFinder) (uint64_t, Trans *); 106typedef int (*TransFinder) (uint64_t, Trans *);
114 107
115 108
@@ -122,10 +115,6 @@ alg
122 bool * inv; 115 bool * inv;
123 int len; 116 int len;
124 int allocated; 117 int allocated;
125 Move * move_normal;
126 int len_normal;
127 Move * move_inverse;
128 int len_inverse;
129}; 118};
130 119
131struct 120struct
@@ -144,13 +133,11 @@ alglistnode
144}; 133};
145 134
146struct 135struct
147choicestep 136block
148{ 137{
149 char * shortname; 138 bool edge[12];
150 char * name; 139 bool corner[8];
151 Step * step[99]; 140 bool center[6];
152 Trans t[99];
153 char * ready_msg;
154}; 141};
155 142
156struct 143struct
@@ -169,7 +156,7 @@ commandargs
169 bool success; 156 bool success;
170 Alg * scramble; 157 Alg * scramble;
171 SolveOptions * opts; 158 SolveOptions * opts;
172 ChoiceStep * cs; 159 Step * step;
173 Command * command; /* For help */ 160 Command * command; /* For help */
174 int n; 161 int n;
175 char scrtype[20]; 162 char scrtype[20];
@@ -180,119 +167,119 @@ commandargs
180struct 167struct
181coordinate 168coordinate
182{ 169{
183 char * name; 170 Indexer index;
184 CoordType type;
185 bool generated;
186 Indexer * i[99];
187 uint64_t max; 171 uint64_t max;
188 uint64_t * mtable[NMOVES]; 172 CoordMover move;
189 uint64_t * ttable[NTRANS]; 173 CoordTransformer transform;
190 TransGroup * tgrp; 174 SymData * sd;
191 Coordinate * base[2]; 175 TransFinder tfind; /* TODO: should be easy to remove */
192 uint64_t * symclass; 176 Coordinate * base; /* TODO: part of refactor */
193 uint64_t * symrep;
194 Trans * transtorep;
195 Trans * ttrep_move[NMOVES];
196 uint64_t * selfsim;
197}; 177};
198 178
199struct 179struct
200cube 180cube
201{ 181{
202 int ep[12]; 182 int epose;
203 int eo[12]; 183 int eposs;
204 int cp[8]; 184 int eposm;
205 int co[8]; 185 int eofb;
206 int xp[6]; 186 int eorl;
187 int eoud;
188 int cp;
189 int coud;
190 int cofb;
191 int corl;
192 int cpos;
207}; 193};
208 194
209/*
210struct 195struct
211movable 196cubearray
212{ 197{
213 uint64_t val; 198 int * ep;
214 Trans t; 199 int * eofb;
200 int * eorl;
201 int * eoud;
202 int * cp;
203 int * coud;
204 int * corl;
205 int * cofb;
206 int * cpos;
215}; 207};
216*/
217 208
218/*
219struct 209struct
220dfsarg 210dfsarg
221{ 211{
222 Cube * cube; 212 Step * step;
223 Movable ind[MAX_N_COORD];
224 Trans t;
225 Step * s;
226 SolveOptions * opts; 213 SolveOptions * opts;
214 Trans t;
215 Cube cube;
216 Cube inverse;
227 int d; 217 int d;
228 int bound; 218 uint64_t badmoves;
219 uint64_t badmovesinv;
229 bool niss; 220 bool niss;
221 Move last1;
222 Move last2;
223 Move last1inv;
224 Move last2inv;
225 EstimateData * ed;
230 AlgList * sols; 226 AlgList * sols;
231 pthread_mutex_t * sols_mutex; 227 pthread_mutex_t * sols_mutex;
232 Alg * current_alg; 228 Alg * current_alg;
233 void * extra;
234}; 229};
235*/
236 230
237/*
238struct 231struct
239dfsarg 232estimatedata
240{ 233{
241 void * cube_data; 234 int corners;
242 SolveOptions * opts; 235 int normal_ud;
243 int d; 236 int normal_fb;
244 int bound; 237 int normal_rl;
245 bool niss; 238 int inverse_ud;
246 AlgList * sols; 239 int inverse_fb;
247 Alg * current_alg; 240 int inverse_rl;
248 Solver * solver; 241 int oldret;
249 Threader * threader;
250}; 242};
251*/
252 243
253struct 244struct
254fstcube 245moveset
255{ 246{
256 uint16_t uf_eofb; 247 bool (*allowed)(Move);
257 uint16_t uf_eposepe; 248 bool (*allowed_next)(Move, Move, Move);
258 uint16_t uf_coud; 249 Move sorted_moves[NMOVES+1];
259 uint16_t uf_cp; 250 uint64_t mask[NMOVES][NMOVES];
260 uint16_t fr_eofb;
261 uint16_t fr_eposepe;
262 uint16_t fr_coud;
263 uint16_t rd_eofb;
264 uint16_t rd_eposepe;
265 uint16_t rd_coud;
266}; 251};
267 252
268struct 253struct
269indexer 254piecefilter
270{ 255{
271 int n; 256 bool epose;
272 uint64_t (*index)(Cube *); 257 bool eposs;
273 void (*to_cube)(uint64_t, Cube *); 258 bool eposm;
274}; 259 bool eofb;
275 260 bool eorl;
276struct 261 bool eoud;
277moveset 262 bool cp;
278{ 263 bool coud;
279 char * name; 264 bool cofb;
280 bool (*allowed)(Move); 265 bool corl;
281 bool (*can_append)(Alg *, Move, bool); 266 bool cpos;
282 bool (*cancel_niss)(Alg *);
283 Move sorted_moves[NMOVES+1];
284}; 267};
285 268
286struct 269struct
287prunedata 270prunedata
288{ 271{
272 char * filename;
289 entry_group_t * ptable; 273 entry_group_t * ptable;
274 bool generated;
290 uint64_t n; 275 uint64_t n;
291 Coordinate * coord; 276 Coordinate * coord;
292 Moveset * moveset; 277 Moveset * moveset;
293 uint64_t count[16];
294 bool compact; 278 bool compact;
295 int base; 279 int base;
280 uint64_t count[16];
281 PruneData * fallback;
282 uint64_t fbmod;
296}; 283};
297 284
298struct 285struct
@@ -313,30 +300,52 @@ solveoptions
313struct 300struct
314step 301step
315{ 302{
316 Checker ready; 303 char * shortname;
304 char * name;
317 bool final; 305 bool final;
318 Moveset * moveset; 306 Checker is_done;
319 int n_coord; 307 Estimator estimate;
320 Coordinate * coord[MAX_N_COORD]; 308 Checker ready;
321 Trans coord_trans[MAX_N_COORD]; 309 char * ready_msg;
322 PruneData * pd[MAX_N_COORD];
323 bool pd_compact[MAX_N_COORD];
324 Validator is_valid; 310 Validator is_valid;
325 /*DfsMover custom_move_checkstop;*/ 311 Moveset * moveset;
326 DfsExtraCopier copy_extra; 312 Trans pre_trans;
313 TransDetector detect;
314 int ntables;
315 PruneData * tables[10];
316};
317
318struct
319symdata
320{
321 char * filename;
322 bool generated;
323 Coordinate * coord;
324 Coordinate * sym_coord;
325 int ntrans;
326 Trans * trans;
327 uint64_t * class;
328 uint64_t * unsym;
329 Trans * transtorep;
330 uint64_t * selfsim;
331 CoordTransformer transform; /* TODO: remove, use that of base coord */
327}; 332};
328 333
329/*
330struct 334struct
331threaddatasolve 335threaddatasolve
332{ 336{
333 DfsArg arg;
334 int thid; 337 int thid;
338 Trans t;
339 Cube cube;
340 Step * step;
341 int depth;
342 SolveOptions * opts;
335 AlgList * start; 343 AlgList * start;
336 AlgListNode ** node; 344 AlgListNode ** node;
345 AlgList * sols;
337 pthread_mutex_t * start_mutex; 346 pthread_mutex_t * start_mutex;
347 pthread_mutex_t * sols_mutex;
338}; 348};
339*/
340 349
341struct 350struct
342threaddatagenpt 351threaddatagenpt
@@ -350,11 +359,4 @@ threaddatagenpt
350 pthread_mutex_t * upmutex; 359 pthread_mutex_t * upmutex;
351}; 360};
352 361
353struct
354transgroup
355{
356 int n;
357 Trans t[NTRANS];
358};
359
360#endif 362#endif
diff --git a/src/env.c b/src/env.c
index 375bfa8..282bc8f 100644
--- a/src/env.c
+++ b/src/env.c
@@ -1,5 +1,3 @@
1#define ENV_C
2
3#include "env.h" 1#include "env.h"
4 2
5bool initialized_env = false; 3bool initialized_env = false;
diff --git a/src/env.h b/src/env.h
index a49d643..871a9c1 100644
--- a/src/env.h
+++ b/src/env.h
@@ -8,8 +8,8 @@
8#include <unistd.h> 8#include <unistd.h>
9#include <sys/stat.h> 9#include <sys/stat.h>
10 10
11void init_env();
12
13extern char *tabledir; 11extern char *tabledir;
14 12
13void init_env();
14
15#endif 15#endif
diff --git a/src/fst.c b/src/fst.c
deleted file mode 100644
index b51e2d4..0000000
--- a/src/fst.c
+++ /dev/null
@@ -1,401 +0,0 @@
1#define FST_C
2
3#include "fst.h"
4
5static FstCube ep_to_fst_epos(int *ep);
6static void init_fst_corner_invtables();
7static void init_fst_eo_invtables();
8static void init_fst_eo_update(uint64_t, uint64_t, int, Cube *);
9static void init_fst_where_is_edge();
10static bool read_fst_tables_file();
11static bool write_fst_tables_file();
12
13static int edge_slice[12] = {[FR] = 0, [FL] = 0, [BL] = 0, [BR] = 0,
14 [UL] = 1, [UR] = 1, [DR] = 1, [DL] = 1,
15 [UF] = 2, [UB] = 2, [DF] = 2, [DB] = 2};
16
17static uint16_t inv_coud[FACTORIAL8][POW3TO7];
18static uint16_t inv_cp[FACTORIAL8];
19static uint16_t uf_cp_to_fr_cp[FACTORIAL8];
20static uint16_t uf_cp_to_rd_cp[FACTORIAL8];
21static uint16_t eo_invtable[3][POW2TO11][BINOM12ON4*FACTORIAL4];
22static uint16_t fst_where_is_edge_arr[3][12][BINOM12ON4*FACTORIAL4];
23
24FstCube
25cube_to_fst(Cube *cube)
26{
27 Cube c;
28 FstCube ret;
29
30 copy_cube(cube, &c);
31 ret.uf_eofb = coord_eofb.i[0]->index(&c);
32 ret.uf_eposepe = coord_eposepe.i[0]->index(&c);
33 ret.uf_coud = coord_coud.i[0]->index(&c);
34 ret.uf_cp = coord_cp.i[0]->index(&c);
35 copy_cube(cube, &c);
36 apply_trans(fr, &c);
37 ret.fr_eofb = coord_eofb.i[0]->index(&c);
38 ret.fr_eposepe = coord_eposepe.i[0]->index(&c);
39 ret.fr_coud = coord_coud.i[0]->index(&c);
40 copy_cube(cube, &c);
41 apply_trans(rd, &c);
42 ret.rd_eofb = coord_eofb.i[0]->index(&c);
43 ret.rd_eposepe = coord_eposepe.i[0]->index(&c);
44 ret.rd_coud = coord_coud.i[0]->index(&c);
45
46 return ret;
47}
48
49static FstCube
50ep_to_fst_epos(int *ep)
51{
52 static int eind[12] = {
53 [FR] = 0, [FL] = 1, [BL] = 2, [BR] = 3,
54 [UR] = 0, [DR] = 1, [DL] = 2, [UL] = 3,
55 [DB] = 0, [DF] = 1, [UF] = 2, [UB] = 3
56 };
57 static int eptrans_fr[12] = {
58 [FR] = UF, [DF] = UL, [FL] = UB, [UF] = UR,
59 [BR] = DF, [DB] = DL, [BL] = DB, [UB] = DR,
60 [UR] = FR, [DR] = FL, [DL] = BL, [UL] = BR
61 };
62 static int eptrans_rd[12] = {
63 [DR] = UF, [FR] = UL, [UR] = UB, [BR] = UR,
64 [DL] = DF, [FL] = DL, [UL] = DB, [BL] = DR,
65 [DB] = FR, [DF] = FL, [UF] = BL, [UB] = BR
66 };
67
68 FstCube ret;
69 int i, ce, cs, cm;
70 int epe[4], eps[4], epm[4], epose[12], eposs[12], eposm[12];
71
72 memset(epose, 0, 12*sizeof(int));
73 memset(eposs, 0, 12*sizeof(int));
74 memset(eposm, 0, 12*sizeof(int));
75
76 for (i = 0, ce = 0; i < 12; i++) {
77 switch (edge_slice[ep[i]]) {
78 case 0:
79 epose[i] = 1;
80 epe[ce++] = eind[ep[i]];
81 break;
82 case 1:
83 eposs[eptrans_fr[i]] = eind[ep[i]] + 1;
84 break;
85 default:
86 eposm[eptrans_rd[i]] = eind[ep[i]] + 1;
87 break;
88 }
89 }
90
91 for (i = 0, cs = 0, cm = 0; i < 12; i++) {
92 if (eposs[i]) {
93 eps[cs++] = eposs[i] - 1;
94 eposs[i] = 1;
95 }
96 if (eposm[i]) {
97 epm[cm++] = eposm[i] - 1;
98 eposm[i] = 1;
99 }
100 }
101
102 ret.uf_eposepe = subset_to_index(epose, 12, 4) * FACTORIAL4 +
103 perm_to_index(epe, 4);
104 ret.fr_eposepe = subset_to_index(eposs, 12, 4) * FACTORIAL4 +
105 perm_to_index(eps, 4);
106 ret.rd_eposepe = subset_to_index(eposm, 12, 4) * FACTORIAL4 +
107 perm_to_index(epm, 4);
108
109 return ret;
110}
111
112FstCube
113fst_inverse(FstCube fst)
114{
115 FstCube ret;
116 int ep_inv[12];
117
118 ep_inv[FR] = fst_where_is_edge_arr[0][FR][fst.uf_eposepe];
119 ep_inv[FL] = fst_where_is_edge_arr[0][FL][fst.uf_eposepe];
120 ep_inv[BL] = fst_where_is_edge_arr[0][BL][fst.uf_eposepe];
121 ep_inv[BR] = fst_where_is_edge_arr[0][BR][fst.uf_eposepe];
122
123 ep_inv[UR] = fst_where_is_edge_arr[1][UR][fst.fr_eposepe];
124 ep_inv[UL] = fst_where_is_edge_arr[1][UL][fst.fr_eposepe];
125 ep_inv[DR] = fst_where_is_edge_arr[1][DR][fst.fr_eposepe];
126 ep_inv[DL] = fst_where_is_edge_arr[1][DL][fst.fr_eposepe];
127
128 ep_inv[UF] = fst_where_is_edge_arr[2][UF][fst.rd_eposepe];
129 ep_inv[UB] = fst_where_is_edge_arr[2][UB][fst.rd_eposepe];
130 ep_inv[DF] = fst_where_is_edge_arr[2][DF][fst.rd_eposepe];
131 ep_inv[DB] = fst_where_is_edge_arr[2][DB][fst.rd_eposepe];
132
133 ret = ep_to_fst_epos(ep_inv);
134
135 ret.uf_eofb = ((uint16_t)eo_invtable[0][fst.uf_eofb][fst.uf_eposepe]) |
136 ((uint16_t)eo_invtable[1][fst.uf_eofb][fst.fr_eposepe]) |
137 ((uint16_t)eo_invtable[2][fst.uf_eofb][fst.rd_eposepe]);
138 ret.fr_eofb = ((uint16_t)eo_invtable[0][fst.fr_eofb][fst.uf_eposepe]) |
139 ((uint16_t)eo_invtable[1][fst.fr_eofb][fst.fr_eposepe]) |
140 ((uint16_t)eo_invtable[2][fst.fr_eofb][fst.rd_eposepe]);
141 ret.rd_eofb = ((uint16_t)eo_invtable[0][fst.rd_eofb][fst.uf_eposepe]) |
142 ((uint16_t)eo_invtable[1][fst.rd_eofb][fst.fr_eposepe]) |
143 ((uint16_t)eo_invtable[2][fst.rd_eofb][fst.rd_eposepe]);
144
145 ret.uf_cp = inv_cp[fst.uf_cp];
146
147 ret.uf_coud = inv_coud[fst.uf_cp][fst.uf_coud];
148 ret.fr_coud = inv_coud[uf_cp_to_fr_cp[fst.uf_cp]][fst.fr_coud];
149 ret.rd_coud = inv_coud[uf_cp_to_rd_cp[fst.uf_cp]][fst.rd_coud];
150
151 return ret;
152}
153
154FstCube
155fst_move(Move m, FstCube fst)
156{
157 FstCube ret;
158 Move m_fr, m_rd;
159
160 m_fr = transform_move(fr, m);
161 m_rd = transform_move(rd, m);
162
163 ret.uf_eofb = coord_eofb.mtable[m][fst.uf_eofb];
164 ret.uf_eposepe = coord_eposepe.mtable[m][fst.uf_eposepe];
165 ret.uf_coud = coord_coud.mtable[m][fst.uf_coud];
166 ret.uf_cp = coord_cp.mtable[m][fst.uf_cp];
167
168 ret.fr_eofb = coord_eofb.mtable[m_fr][fst.fr_eofb];
169 ret.fr_eposepe = coord_eposepe.mtable[m_fr][fst.fr_eposepe];
170 ret.fr_coud = coord_coud.mtable[m_fr][fst.fr_coud];
171
172 ret.rd_eofb = coord_eofb.mtable[m_rd][fst.rd_eofb];
173 ret.rd_eposepe = coord_eposepe.mtable[m_rd][fst.rd_eposepe];
174 ret.rd_coud = coord_coud.mtable[m_rd][fst.rd_coud];
175
176 return ret;
177}
178
179void
180fst_to_cube(FstCube fst, Cube *cube)
181{
182 Cube e, s, m;
183 int i;
184
185 coord_eposepe.i[0]->to_cube(fst.uf_eposepe, &e);
186 coord_eposepe.i[0]->to_cube(fst.fr_eposepe, &s);
187 apply_trans(inverse_trans(fr), &s);
188 coord_eposepe.i[0]->to_cube(fst.rd_eposepe, &m);
189 apply_trans(inverse_trans(rd), &m);
190
191 for (i = 0; i < 12; i++) {
192 if (edge_slice[e.ep[i]] == 0)
193 cube->ep[i] = e.ep[i];
194 if (edge_slice[s.ep[i]] == 1)
195 cube->ep[i] = s.ep[i];
196 if (edge_slice[m.ep[i]] == 2)
197 cube->ep[i] = m.ep[i];
198 }
199
200 coord_eofb.i[0]->to_cube((uint64_t)fst.uf_eofb, cube);
201 coord_coud.i[0]->to_cube((uint64_t)fst.uf_coud, cube);
202 coord_cp.i[0]->to_cube((uint64_t)fst.uf_cp, cube);
203
204 for (i = 0; i < 6; i++)
205 cube->xp[i] = i;
206}
207
208void
209init_fst()
210{
211 init_trans();
212 gen_coord(&coord_eofb);
213 gen_coord(&coord_eposepe);
214 gen_coord(&coord_coud);
215 gen_coord(&coord_cp);
216
217 if (!read_fst_tables_file()) {
218 fprintf(stderr,
219 "Could not load fst_tables, generating them\n");
220 init_fst_corner_invtables();
221 init_fst_eo_invtables();
222 init_fst_where_is_edge();
223 if (!write_fst_tables_file())
224 fprintf(stderr, "fst_tables could not be written\b");
225 }
226}
227
228static void
229init_fst_corner_invtables()
230{
231 Cube c, d;
232 uint64_t cp, coud;
233
234 for (cp = 0; cp < FACTORIAL8; cp++) {
235 make_solved_corners(&c);
236 coord_cp.i[0]->to_cube(cp, &c);
237
238 copy_cube_corners(&c, &d);
239 invert_cube_corners(&d);
240 inv_cp[cp] = coord_cp.i[0]->index(&d);
241
242 for (coud = 0; coud < POW3TO7; coud++) {
243 copy_cube_corners(&c, &d);
244 coord_coud.i[0]->to_cube(coud, &d);
245 invert_cube_corners(&d);
246 inv_coud[cp][coud] = coord_coud.i[0]->index(&d);
247 }
248
249 copy_cube_corners(&c, &d);
250 apply_trans(fr, &d);
251 uf_cp_to_fr_cp[cp] = coord_cp.i[0]->index(&d);
252
253 copy_cube_corners(&c, &d);
254 apply_trans(rd, &d);
255 uf_cp_to_rd_cp[cp] = coord_cp.i[0]->index(&d);
256 }
257}
258
259static void
260init_fst_eo_invtables()
261{
262 uint64_t ep, eo;
263 Cube c, d;
264
265 for (ep = 0; ep < BINOM12ON4 * FACTORIAL4; ep++) {
266 make_solved(&c);
267 coord_eposepe.i[0]->to_cube(ep, &c);
268 for (eo = 0; eo < POW2TO11; eo++) {
269 copy_cube_edges(&c, &d);
270 coord_eofb.i[0]->to_cube(eo, &d);
271 init_fst_eo_update(eo, ep, 0, &d);
272
273 apply_trans(inverse_trans(fr), &d);
274 coord_eofb.i[0]->to_cube(eo, &d);
275 init_fst_eo_update(eo, ep, 1, &d);
276
277 copy_cube_edges(&c, &d);
278 apply_trans(inverse_trans(rd), &d);
279 coord_eofb.i[0]->to_cube(eo, &d);
280 init_fst_eo_update(eo, ep, 2, &d);
281 }
282 }
283}
284
285static void
286init_fst_eo_update(uint64_t eo, uint64_t ep, int s, Cube *d)
287{
288 int i;
289
290 for (i = 0; i < 12; i++) {
291 if (edge_slice[d->ep[i]] == s && d->eo[i] && d->ep[i] != 11)
292 eo_invtable[s][eo][ep] |=
293 ((uint16_t)1) << ((uint16_t)d->ep[i]);
294 }
295}
296
297static void
298init_fst_where_is_edge()
299{
300 Cube c, d;
301 uint64_t e;
302
303 make_solved(&c);
304 for (e = 0; e < BINOM12ON4 * FACTORIAL4; e++) {
305 coord_eposepe.i[0]->to_cube(e, &c);
306
307 copy_cube_edges(&c, &d);
308 fst_where_is_edge_arr[0][FR][e] = where_is_edge(FR, &d);
309 fst_where_is_edge_arr[0][FL][e] = where_is_edge(FL, &d);
310 fst_where_is_edge_arr[0][BL][e] = where_is_edge(BL, &d);
311 fst_where_is_edge_arr[0][BR][e] = where_is_edge(BR, &d);
312
313 copy_cube_edges(&c, &d);
314 apply_trans(inverse_trans(fr), &d);
315 fst_where_is_edge_arr[1][UL][e] = where_is_edge(UL, &d);
316 fst_where_is_edge_arr[1][UR][e] = where_is_edge(UR, &d);
317 fst_where_is_edge_arr[1][DL][e] = where_is_edge(DL, &d);
318 fst_where_is_edge_arr[1][DR][e] = where_is_edge(DR, &d);
319
320 copy_cube_edges(&c, &d);
321 apply_trans(inverse_trans(rd), &d);
322 fst_where_is_edge_arr[2][UF][e] = where_is_edge(UF, &d);
323 fst_where_is_edge_arr[2][UB][e] = where_is_edge(UB, &d);
324 fst_where_is_edge_arr[2][DF][e] = where_is_edge(DF, &d);
325 fst_where_is_edge_arr[2][DB][e] = where_is_edge(DB, &d);
326 }
327}
328
329static bool
330read_fst_tables_file()
331{
332 init_env();
333
334 FILE *f;
335 char fname[strlen(tabledir)+256];
336 uint64_t i, j, r, total;
337
338 strcpy(fname, tabledir);
339 strcat(fname, "/fst_tables");
340
341 if ((f = fopen(fname, "rb")) == NULL)
342 return false;
343
344 r = 0;
345 total = FACTORIAL8*(POW3TO7+3) + 3*BINOM12ON4*FACTORIAL4*(12+POW2TO11);
346
347 for (i = 0; i < FACTORIAL8; i++)
348 r += fread(inv_coud[i], sizeof(uint16_t), POW3TO7, f);
349 r += fread(inv_cp, sizeof(uint16_t), FACTORIAL8, f);
350 r += fread(uf_cp_to_fr_cp, sizeof(uint16_t), FACTORIAL8, f);
351 r += fread(uf_cp_to_rd_cp, sizeof(uint16_t), FACTORIAL8, f);
352 for (i = 0; i < 3; i++)
353 for (j = 0; j < POW2TO11; j++)
354 r += fread(eo_invtable[i][j],
355 sizeof(uint16_t), BINOM12ON4*FACTORIAL4, f);
356 for (i = 0; i < 3; i++)
357 for (j = 0; j < 12; j++)
358 r += fread(fst_where_is_edge_arr[i][j],
359 sizeof(uint16_t), BINOM12ON4*FACTORIAL4, f);
360
361 fclose(f);
362
363 return r == total;
364}
365
366static bool
367write_fst_tables_file()
368{
369 init_env();
370
371 FILE *f;
372 char fname[strlen(tabledir)+256];
373 uint64_t i, j, w, total;
374
375 strcpy(fname, tabledir);
376 strcat(fname, "/fst_tables");
377
378 if ((f = fopen(fname, "wb")) == NULL)
379 return false;
380
381 w = 0;
382 total = FACTORIAL8*(POW3TO7+3) + 3*BINOM12ON4*FACTORIAL4*(12+POW2TO11);
383
384 for (i = 0; i < FACTORIAL8; i++)
385 w += fwrite(inv_coud[i], sizeof(uint16_t), POW3TO7, f);
386 w += fwrite(inv_cp, sizeof(uint16_t), FACTORIAL8, f);
387 w += fwrite(uf_cp_to_fr_cp, sizeof(uint16_t), FACTORIAL8, f);
388 w += fwrite(uf_cp_to_rd_cp, sizeof(uint16_t), FACTORIAL8, f);
389 for (i = 0; i < 3; i++)
390 for (j = 0; j < POW2TO11; j++)
391 w += fwrite(eo_invtable[i][j],
392 sizeof(uint16_t), BINOM12ON4*FACTORIAL4, f);
393 for (i = 0; i < 3; i++)
394 for (j = 0; j < 12; j++)
395 w += fwrite(fst_where_is_edge_arr[i][j],
396 sizeof(uint16_t), BINOM12ON4*FACTORIAL4, f);
397
398 fclose(f);
399
400 return w == total;
401}
diff --git a/src/fst.h b/src/fst.h
deleted file mode 100644
index c3b226c..0000000
--- a/src/fst.h
+++ /dev/null
@@ -1,13 +0,0 @@
1#ifndef FST_H
2#define FST_H
3
4#include "coord.h"
5
6FstCube cube_to_fst(Cube *cube);
7FstCube fst_inverse(FstCube fst);
8FstCube fst_move(Move m, FstCube fst);
9void fst_to_cube(FstCube fst, Cube *cube);
10void init_fst();
11
12#endif
13
diff --git a/src/moves.c b/src/moves.c
index a9dfdc0..02880ca 100644
--- a/src/moves.c
+++ b/src/moves.c
@@ -1,18 +1,79 @@
1#define MOVES_C
2
3#include "moves.h" 1#include "moves.h"
4 2
5/* Local functions ***********************************************************/ 3/* Local functions ***********************************************************/
6 4
5static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f);
7static void cleanup_aux(Alg *alg, Alg *ret, bool inv); 6static void cleanup_aux(Alg *alg, Alg *ret, bool inv);
7static bool read_mtables_file();
8static bool write_mtables_file();
8 9
9/* Tables and other data *****************************************************/ 10/* Tables and other data *****************************************************/
10 11
11/* Moves are represented as cubes and applied using compose(). Every move is * 12/* Every move is translated to a an <U, x, y> alg before filling the
12 * translated to a an <U, x, y> alg before filling the transition tables. * 13 transition tables, see init_moves() */
13 * See init_moves(). */ 14
15static int edge_cycle[NMOVES][12] =
16{
17 [U] = { UR, UF, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR },
18 [x] = { DF, FL, UF, FR, DB, BL, UB, BR, DR, DL, UL, UR },
19 [y] = { UR, UF, UL, UB, DR, DF, DL, DB, BR, FR, FL, BL }
20};
21
22static int corner_cycle[NMOVES][8] =
23{
24 [U] = { UBR, UFR, UFL, UBL, DFR, DFL, DBL, DBR },
25 [x] = { DFR, DFL, UFL, UFR, DBR, DBL, UBL, UBR },
26 [y] = { UBR, UFR, UFL, UBL, DBR, DFR, DFL, DBL }
27};
28
29static int center_cycle[NMOVES][6] =
30{
31 [x] = { F_center, B_center, R_center, L_center, D_center, U_center },
32 [y] = { U_center, D_center, B_center, F_center, R_center, L_center }
33};
34
35static int eofb_flipped[NMOVES][12] = {
36 [x] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 },
37 [y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 }
38};
39
40static int eorl_flipped[NMOVES][12] = {
41 [x] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
42 [y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 }
43};
44
45static int eoud_flipped[NMOVES][12] = {
46 [U] = { [UF] = 1, [UL] = 1, [UB] = 1, [UR] = 1 },
47 [x] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 },
48 [y] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
49};
50
51static int coud_flipped[NMOVES][8] = {
52 [x] = {
53 [UFR] = 2, [UBR] = 1, [UFL] = 1, [UBL] = 2,
54 [DBR] = 2, [DFR] = 1, [DBL] = 1, [DFL] = 2
55 }
56};
57
58static int corl_flipped[NMOVES][8] = {
59 [U] = { [UFR] = 1, [UBR] = 2, [UBL] = 1, [UFL] = 2 },
60 [y] = {
61 [UFR] = 1, [UBR] = 2, [UBL] = 1, [UFL] = 2,
62 [DFR] = 2, [DBR] = 1, [DBL] = 2, [DFL] = 1
63 }
64};
14 65
15static Cube move_array[NMOVES]; 66static int cofb_flipped[NMOVES][8] = {
67 [U] = { [UFR] = 2, [UBR] = 1, [UBL] = 2, [UFL] = 1 },
68 [x] = {
69 [UFR] = 1, [UBR] = 2, [UBL] = 1, [UFL] = 2,
70 [DFR] = 2, [DBR] = 1, [DBL] = 2, [DFL] = 1
71 },
72 [y] = {
73 [UFR] = 2, [UBR] = 1, [UBL] = 2, [UFL] = 1,
74 [DFR] = 1, [DBR] = 2, [DBL] = 1, [DFL] = 2
75 }
76};
16 77
17static char equiv_alg_string[100][NMOVES] = { 78static char equiv_alg_string[100][NMOVES] = {
18 [NULLMOVE] = "", 79 [NULLMOVE] = "",
@@ -76,52 +137,89 @@ static char equiv_alg_string[100][NMOVES] = {
76 [z3] = " y x yyy " 137 [z3] = " y x yyy "
77}; 138};
78 139
140/* Transition tables, to be loaded up at the beginning */
141int epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
142int eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
143int eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
144int eofb_mtable[NMOVES][POW2TO11];
145int eorl_mtable[NMOVES][POW2TO11];
146int eoud_mtable[NMOVES][POW2TO11];
147int cp_mtable[NMOVES][FACTORIAL8];
148int coud_mtable[NMOVES][POW3TO7];
149int cofb_mtable[NMOVES][POW3TO7];
150int corl_mtable[NMOVES][POW3TO7];
151int cpos_mtable[NMOVES][FACTORIAL6];
152
153
154/* Local functions implementation ********************************************/
155
156static Cube
157apply_move_cubearray(Move m, Cube cube, PieceFilter f)
158{
159 /*init_moves();*/
160
161 CubeArray m_arr = {
162 edge_cycle[m],
163 eofb_flipped[m],
164 eorl_flipped[m],
165 eoud_flipped[m],
166 corner_cycle[m],
167 coud_flipped[m],
168 corl_flipped[m],
169 cofb_flipped[m],
170 center_cycle[m]
171 };
172
173 return move_via_arrays(&m_arr, cube, f);
174}
79 175
80/* Public functions **********************************************************/ 176/* Public functions **********************************************************/
81 177
82void 178Cube
83apply_alg(Alg *alg, Cube *cube) 179apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a)
84{ 180{
85 Cube aux; 181 Cube ret = {0};
86 int i; 182 int i;
87 183
88 copy_cube(cube, &aux);
89 make_solved(cube);
90
91 for (i = 0; i < alg->len; i++) 184 for (i = 0; i < alg->len; i++)
92 if (alg->inv[i]) 185 if (alg->inv[i])
93 apply_move(alg->move[i], cube); 186 ret = a ? apply_move(alg->move[i], ret) :
187 apply_move_cubearray(alg->move[i], ret, f);
94 188
95 invert_cube(cube); 189 ret = compose_filtered(c, inverse_cube(ret), f);
96 compose(&aux, cube);
97 190
98 for (i = 0; i < alg->len; i++) 191 for (i = 0; i < alg->len; i++)
99 if (!alg->inv[i]) 192 if (!alg->inv[i])
100 apply_move(alg->move[i], cube); 193 ret = a ? apply_move(alg->move[i], ret) :
101} 194 apply_move_cubearray(alg->move[i], ret, f);
102 195
103void 196 return ret;
104apply_move(Move m, Cube *cube)
105{
106 compose(&move_array[m], cube);
107} 197}
108 198
109void 199Cube
110apply_move_centers(Move m, Cube *cube) 200apply_alg(Alg *alg, Cube cube)
111{ 201{
112 compose_centers(&move_array[m], cube); 202 return apply_alg_generic(alg, cube, pf_all, true);
113} 203}
114 204
115void 205Cube
116apply_move_corners(Move m, Cube *cube) 206apply_move(Move m, Cube cube)
117{ 207{
118 compose_corners(&move_array[m], cube); 208 /*init_moves();*/
119}
120 209
121void 210 return (Cube) {
122apply_move_edges(Move m, Cube *cube) 211 .epose = epose_mtable[m][cube.epose],
123{ 212 .eposs = eposs_mtable[m][cube.eposs],
124 compose_edges(&move_array[m], cube); 213 .eposm = eposm_mtable[m][cube.eposm],
214 .eofb = eofb_mtable[m][cube.eofb],
215 .eorl = eorl_mtable[m][cube.eorl],
216 .eoud = eoud_mtable[m][cube.eoud],
217 .coud = coud_mtable[m][cube.coud],
218 .cofb = cofb_mtable[m][cube.cofb],
219 .corl = corl_mtable[m][cube.corl],
220 .cp = cp_mtable[m][cube.cp],
221 .cpos = cpos_mtable[m][cube.cpos]
222 };
125} 223}
126 224
127Alg * 225Alg *
@@ -181,27 +279,31 @@ cleanup_aux(Alg *alg, Alg *ret, bool inv)
181{ 279{
182 int i, j; 280 int i, j;
183 Cube c, d; 281 Cube c, d;
184 Move m; 282 Move m, mm;
185 Alg *equiv_alg; 283 Alg *equiv_alg;
186 284
187 make_solved(&c); 285 c = (Cube){0};
188 for (i = 0; i < alg->len; i++) { 286 for (i = 0; i < alg->len; i++) {
189 if (alg->inv[i] != inv) 287 if (alg->inv[i] != inv)
190 continue; 288 continue;
191 289
192 equiv_alg = new_alg(equiv_alg_string[alg->move[i]]); 290 equiv_alg = new_alg(equiv_alg_string[alg->move[i]]);
193 291
194 for (j = 0; j < equiv_alg->len; j++) 292 for (j = 0; j < equiv_alg->len; j++) {
195 if (equiv_alg->move[j] == U) 293 m = equiv_alg->move[j];
196 append_move(ret, 3 * c.xp[U_center] + 1, inv); 294 if (m == U) {
197 else 295 mm = 3*what_center_at(c, U_center) + 1;
198 apply_move(equiv_alg->move[j], &c); 296 append_move(ret, mm, inv);
297 } else {
298 c = apply_move(m, c);
299 }
300 }
199 301
200 free_alg(equiv_alg); 302 free_alg(equiv_alg);
201 } 303 }
202 304
203 m = NULLMOVE; 305 m = NULLMOVE;
204 switch (c.xp[F_center]) { 306 switch (what_center_at(c, F_center)) {
205 case U_center: 307 case U_center:
206 m = x3; 308 m = x3;
207 break; 309 break;
@@ -215,7 +317,7 @@ cleanup_aux(Alg *alg, Alg *ret, bool inv)
215 m = y3; 317 m = y3;
216 break; 318 break;
217 case B_center: 319 case B_center:
218 if (c.xp[U_center] == U_center) 320 if (what_center_at(c, U_center) == U_center)
219 m = y2; 321 m = y2;
220 else 322 else
221 m = x2; 323 m = x2;
@@ -223,24 +325,120 @@ cleanup_aux(Alg *alg, Alg *ret, bool inv)
223 default: 325 default:
224 break; 326 break;
225 } 327 }
226 328 d = apply_move(m, (Cube){0});
227 make_solved(&d);
228 apply_move(m, &d);
229 if (m != NULLMOVE) 329 if (m != NULLMOVE)
230 append_move(ret, m, inv); 330 append_move(ret, m, inv);
231 331
232 m = NULLMOVE; 332 m = NULLMOVE;
233 if (c.xp[U_center] == d.xp[D_center]) { 333 if (what_center_at(c, U_center) == what_center_at(d, D_center)) {
234 m = z2; 334 m = z2;
235 } else if (c.xp[U_center] == d.xp[R_center]) { 335 } else if (what_center_at(c, U_center) == what_center_at(d, R_center)) {
236 m = z3; 336 m = z3;
237 } else if (c.xp[U_center] == d.xp[L_center]) { 337 } else if (what_center_at(c, U_center) == what_center_at(d, L_center)) {
238 m = z; 338 m = z;
239 } 339 }
240 if (m != NULLMOVE) 340 if (m != NULLMOVE)
241 append_move(ret, m, inv); 341 append_move(ret, m, inv);
242} 342}
243 343
344static bool
345read_mtables_file()
346{
347 init_env();
348
349 FILE *f;
350 char fname[strlen(tabledir)+20];
351 int m, b = sizeof(int);
352 bool r = true;
353
354 /* Table sizes, used for reading and writing files */
355 uint64_t me[11] = {
356 [0] = FACTORIAL12/FACTORIAL8,
357 [1] = FACTORIAL12/FACTORIAL8,
358 [2] = FACTORIAL12/FACTORIAL8,
359 [3] = POW2TO11,
360 [4] = POW2TO11,
361 [5] = POW2TO11,
362 [6] = FACTORIAL8,
363 [7] = POW3TO7,
364 [8] = POW3TO7,
365 [9] = POW3TO7,
366 [10] = FACTORIAL6
367 };
368
369 strcpy(fname, tabledir);
370 strcat(fname, "/mtables");
371
372 if ((f = fopen(fname, "rb")) == NULL)
373 return false;
374
375 for (m = 0; m < NMOVES; m++) {
376 r = r && fread(epose_mtable[m], b, me[0], f) == me[0];
377 r = r && fread(eposs_mtable[m], b, me[1], f) == me[1];
378 r = r && fread(eposm_mtable[m], b, me[2], f) == me[2];
379 r = r && fread(eofb_mtable[m], b, me[3], f) == me[3];
380 r = r && fread(eorl_mtable[m], b, me[4], f) == me[4];
381 r = r && fread(eoud_mtable[m], b, me[5], f) == me[5];
382 r = r && fread(cp_mtable[m], b, me[6], f) == me[6];
383 r = r && fread(coud_mtable[m], b, me[7], f) == me[7];
384 r = r && fread(corl_mtable[m], b, me[8], f) == me[8];
385 r = r && fread(cofb_mtable[m], b, me[9], f) == me[9];
386 r = r && fread(cpos_mtable[m], b, me[10], f) == me[10];
387 }
388
389 fclose(f);
390 return r;
391}
392
393static bool
394write_mtables_file()
395{
396 init_env();
397
398 FILE *f;
399 char fname[strlen(tabledir)+20];
400 int m, b = sizeof(int);
401 bool r = true;
402
403 /* Table sizes, used for reading and writing files */
404 uint64_t me[11] = {
405 [0] = FACTORIAL12/FACTORIAL8,
406 [1] = FACTORIAL12/FACTORIAL8,
407 [2] = FACTORIAL12/FACTORIAL8,
408 [3] = POW2TO11,
409 [4] = POW2TO11,
410 [5] = POW2TO11,
411 [6] = FACTORIAL8,
412 [7] = POW3TO7,
413 [8] = POW3TO7,
414 [9] = POW3TO7,
415 [10] = FACTORIAL6
416 };
417
418 strcpy(fname, tabledir);
419 strcat(fname, "/mtables");
420
421 if ((f = fopen(fname, "wb")) == NULL)
422 return false;
423
424 for (m = 0; m < NMOVES; m++) {
425 r = r && fwrite(epose_mtable[m], b, me[0], f) == me[0];
426 r = r && fwrite(eposs_mtable[m], b, me[1], f) == me[1];
427 r = r && fwrite(eposm_mtable[m], b, me[2], f) == me[2];
428 r = r && fwrite(eofb_mtable[m], b, me[3], f) == me[3];
429 r = r && fwrite(eorl_mtable[m], b, me[4], f) == me[4];
430 r = r && fwrite(eoud_mtable[m], b, me[5], f) == me[5];
431 r = r && fwrite(cp_mtable[m], b, me[6], f) == me[6];
432 r = r && fwrite(coud_mtable[m], b, me[7], f) == me[7];
433 r = r && fwrite(corl_mtable[m], b, me[8], f) == me[8];
434 r = r && fwrite(cofb_mtable[m], b, me[9], f) == me[9];
435 r = r && fwrite(cpos_mtable[m], b, me[10], f) == me[10];
436 }
437
438 fclose(f);
439 return r;
440}
441
244void 442void
245init_moves() { 443init_moves() {
246 static bool initialized = false; 444 static bool initialized = false;
@@ -248,54 +446,101 @@ init_moves() {
248 return; 446 return;
249 initialized = true; 447 initialized = true;
250 448
449 Cube c;
450 CubeArray arrs;
451 int i;
452 unsigned int ui;
251 Move m; 453 Move m;
252 Alg *equiv_alg[NMOVES]; 454 Alg *equiv_alg[NMOVES];
253 455
254 static const Cube mcu = { 456 init_cube();
255 .ep = { UR, UF, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR }, 457
256 .cp = { UBR, UFR, UFL, UBL, DFR, DFL, DBL, DBR }, 458 for (i = 0; i < NMOVES; i++)
257 }; 459 equiv_alg[i] = new_alg(equiv_alg_string[i]);
258 static const Cube mcx = {
259 .ep = { DF, FL, UF, FR, DB, BL, UB, BR, DR, DL, UL, UR },
260 .eo = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 },
261 .cp = { DFR, DFL, UFL, UFR, DBR, DBL, UBL, UBR },
262 .co = { [UFR] = 2, [UBR] = 1, [UFL] = 1, [UBL] = 2,
263 [DBR] = 2, [DFR] = 1, [DBL] = 1, [DFL] = 2 },
264 .xp = { F_center, B_center, R_center,
265 L_center, D_center, U_center },
266 };
267 static const Cube mcy = {
268 .ep = { UR, UF, UL, UB, DR, DF, DL, DB, BR, FR, FL, BL },
269 .eo = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 },
270 .cp = { UBR, UFR, UFL, UBL, DBR, DFR, DFL, DBL },
271 .xp = { U_center, D_center, B_center,
272 F_center, R_center, L_center },
273 };
274 460
275 move_array[U] = mcu; 461 /* Generate all move cycles and flips; I do this regardless */
276 move_array[x] = mcx; 462 for (i = 0; i < NMOVES; i++) {
277 move_array[y] = mcy; 463 if (i == U || i == x || i == y)
464 continue;
465
466 c = apply_alg_generic(equiv_alg[i], (Cube){0}, pf_all, false);
467
468 arrs = (CubeArray) {
469 edge_cycle[i],
470 eofb_flipped[i],
471 eorl_flipped[i],
472 eoud_flipped[i],
473 corner_cycle[i],
474 coud_flipped[i],
475 corl_flipped[i],
476 cofb_flipped[i],
477 center_cycle[i]
478 };
479 cube_to_arrays(c, &arrs, pf_all);
480 }
481
482 if (read_mtables_file())
483 return;
278 484
279 for (m = 0; m < NMOVES; m++) 485 fprintf(stderr, "Cannot load %s, generating it\n", "mtables");
280 equiv_alg[m] = new_alg(equiv_alg_string[m]);
281 486
487 /* Initialize transition tables */
282 for (m = 0; m < NMOVES; m++) { 488 for (m = 0; m < NMOVES; m++) {
283 switch (m) { 489 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
284 case NULLMOVE: 490 c = (Cube){ .epose = ui };
285 make_solved(&move_array[m]); 491 c = apply_move_cubearray(m, c, pf_e);
286 break; 492 epose_mtable[m][ui] = c.epose;
287 case U: 493
288 case x: 494 c = (Cube){ .eposs = ui };
289 case y: 495 c = apply_move_cubearray(m, c, pf_s);
290 break; 496 eposs_mtable[m][ui] = c.eposs;
291 default: 497
292 make_solved(&move_array[m]); 498 c = (Cube){ .eposm = ui };
293 apply_alg(equiv_alg[m], &move_array[m]); 499 c = apply_move_cubearray(m, c, pf_m);
294 break; 500 eposm_mtable[m][ui] = c.eposm;
501 }
502 for (ui = 0; ui < POW2TO11; ui++ ) {
503 c = (Cube){ .eofb = ui };
504 c = apply_move_cubearray(m, c, pf_eo);
505 eofb_mtable[m][ui] = c.eofb;
506
507 c = (Cube){ .eorl = ui };
508 c = apply_move_cubearray(m, c, pf_eo);
509 eorl_mtable[m][ui] = c.eorl;
510
511 c = (Cube){ .eoud = ui };
512 c = apply_move_cubearray(m, c, pf_eo);
513 eoud_mtable[m][ui] = c.eoud;
514 }
515 for (ui = 0; ui < POW3TO7; ui++) {
516 c = (Cube){ .coud = ui };
517 c = apply_move_cubearray(m, c, pf_co);
518 coud_mtable[m][ui] = c.coud;
519
520 c = (Cube){ .corl = ui };
521 c = apply_move_cubearray(m, c, pf_co);
522 corl_mtable[m][ui] = c.corl;
523
524 c = (Cube){ .cofb = ui };
525 c = apply_move_cubearray(m, c, pf_co);
526 cofb_mtable[m][ui] = c.cofb;
527 }
528 for (ui = 0; ui < FACTORIAL8; ui++) {
529 c = (Cube){ .cp = ui };
530 c = apply_move_cubearray(m, c, pf_cp);
531 cp_mtable[m][ui] = c.cp;
532 }
533 for (ui = 0; ui < FACTORIAL6; ui++) {
534 c = (Cube){ .cpos = ui };
535 c = apply_move_cubearray(m, c, pf_cpos);
536 cpos_mtable[m][ui] = c.cpos;
295 } 537 }
296 } 538 }
297 539
298 for (m = 0; m < NMOVES; m++) 540 if (!write_mtables_file())
299 free_alg(equiv_alg[m]); 541 fprintf(stderr, "Error writing mtables\n");
542
543 for (i = 0; i < NMOVES; i++)
544 free_alg(equiv_alg[i]);
300} 545}
301 546
diff --git a/src/moves.h b/src/moves.h
index 4e8be7f..14ae087 100644
--- a/src/moves.h
+++ b/src/moves.h
@@ -5,11 +5,24 @@
5#include "cube.h" 5#include "cube.h"
6#include "env.h" 6#include "env.h"
7 7
8void apply_alg(Alg *alg, Cube *cube); 8/*
9void apply_move(Move m, Cube *cube); 9 * Tables are exposed to allow for faster moves in some cases.
10void apply_move_centers(Move m, Cube *cube); 10 */
11void apply_move_corners(Move m, Cube *cube); 11extern int epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
12void apply_move_edges(Move m, Cube *cube); 12extern int eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
13extern int eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
14extern int eofb_mtable[NMOVES][POW2TO11];
15extern int eorl_mtable[NMOVES][POW2TO11];
16extern int eoud_mtable[NMOVES][POW2TO11];
17extern int cp_mtable[NMOVES][FACTORIAL8];
18extern int coud_mtable[NMOVES][POW3TO7];
19extern int cofb_mtable[NMOVES][POW3TO7];
20extern int corl_mtable[NMOVES][POW3TO7];
21extern int cpos_mtable[NMOVES][FACTORIAL6];
22
23Cube apply_alg(Alg *alg, Cube cube);
24Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a);
25Cube apply_move(Move m, Cube cube);
13Alg * cleanup(Alg *alg); 26Alg * cleanup(Alg *alg);
14 27
15void init_moves(); 28void init_moves();
diff --git a/src/movesets.c b/src/movesets.c
deleted file mode 100644
index d8f5bc1..0000000
--- a/src/movesets.c
+++ /dev/null
@@ -1,194 +0,0 @@
1#define MOVESETS_C
2
3#include "movesets.h"
4
5static bool allowed_HTM(Move m);
6static bool allowed_URF(Move m);
7static bool allowed_eofb(Move m);
8static bool allowed_drud(Move m);
9static bool allowed_htr(Move m);
10static bool can_append_HTM(Move l2, Move l1, Move m);
11static bool can_append_HTM_cached(Alg *alg, Move m, bool inverse);
12static bool cancel_niss_HTM_cached(Alg *alg);
13static void init_can_append_HTM();
14
15Moveset
16moveset_HTM = {
17 .name = "HTM",
18 .allowed = allowed_HTM,
19 .can_append = can_append_HTM_cached,
20 .cancel_niss = cancel_niss_HTM_cached,
21};
22
23Moveset
24moveset_URF = {
25 .name = "URF",
26 .allowed = allowed_URF,
27 .can_append = can_append_HTM_cached,
28 .cancel_niss = cancel_niss_HTM_cached,
29};
30
31Moveset
32moveset_eofb = {
33 .name = "eofb",
34 .allowed = allowed_eofb,
35 .can_append = can_append_HTM_cached,
36 .cancel_niss = cancel_niss_HTM_cached,
37};
38
39Moveset
40moveset_drud = {
41 .name = "drud",
42 .allowed = allowed_drud,
43 .can_append = can_append_HTM_cached,
44 .cancel_niss = cancel_niss_HTM_cached,
45};
46
47Moveset
48moveset_htr = {
49 .name = "htr",
50 .allowed = allowed_htr,
51 .can_append = can_append_HTM_cached,
52 .cancel_niss = cancel_niss_HTM_cached,
53};
54
55Moveset *
56all_movesets[] = {
57 &moveset_HTM,
58 &moveset_URF,
59 &moveset_eofb,
60 &moveset_drud,
61 &moveset_htr,
62 NULL
63};
64
65static uint64_t can_append_HTM_mask[NMOVES][NMOVES];
66
67static bool
68allowed_HTM(Move m)
69{
70 return m >= U && m <= B3;
71}
72
73static bool
74allowed_URF(Move m)
75{
76 Move b = base_move(m);
77
78 return b == U || b == R || b == F;
79}
80
81static bool
82allowed_eofb(Move m)
83{
84 Move b = base_move(m);
85
86 return b == U || b == D || b == R || b == L ||
87 ((b == F || b == B) && m == b+1);
88}
89
90static bool
91allowed_drud(Move m)
92{
93 Move b = base_move(m);
94
95 return b == U || b == D ||
96 ((b == R || b == L || b == F || b == B) && m == b + 1);
97}
98
99static bool
100allowed_htr(Move m)
101{
102 Move b = base_move(m);
103
104 return moveset_HTM.allowed(m) && m == b + 1;
105}
106
107static bool
108can_append_HTM(Move l2, Move l1, Move m)
109{
110 bool cancel, cancel_last, cancel_swap;
111
112 cancel_last = l1 != NULLMOVE && base_move(l1) == base_move(m);
113 cancel_swap = l2 != NULLMOVE && base_move(l2) == base_move(m);
114 cancel = cancel_last || (commute(l1, l2) && cancel_swap);
115
116 return !cancel;
117}
118
119static bool
120can_append_HTM_cached(Alg *alg, Move m, bool inverse)
121{
122 Move *moves, l1, l2;
123 uint64_t mbit;
124 int n;
125
126 if (inverse) {
127 moves = alg->move_inverse;
128 n = alg->len_inverse;
129 } else {
130 moves = alg->move_normal;
131 n = alg->len_normal;
132 }
133
134 l1 = n > 0 ? moves[n-1] : NULLMOVE;
135 l2 = n > 1 ? moves[n-2] : NULLMOVE;
136
137 mbit = ((uint64_t)1) << m;
138
139 return can_append_HTM_mask[l2][l1] & mbit;
140}
141
142static bool
143cancel_niss_HTM_cached(Alg *alg)
144{
145 Move i1, i2;
146 int n;
147 bool can_first, can_swap;
148
149 n = alg->len_inverse;
150 i1 = n > 0 ? alg->move_inverse[n-1] : NULLMOVE;
151 i2 = n > 1 ? alg->move_inverse[n-2] : NULLMOVE;
152
153 can_first = can_append_HTM_cached(alg, inverse_move(i1), false);
154 can_swap = can_append_HTM_cached(alg, inverse_move(i2), false);
155
156 return can_first && (!commute(i1, i2) || can_swap);
157}
158
159static void
160init_can_append_HTM()
161{
162 Move l2, l1, m;
163
164 for (l1 = 0; l1 < NMOVES; l1++)
165 for (l2 = 0; l2 < NMOVES; l2++)
166 for (m = 0; m < NMOVES; m++)
167 if (can_append_HTM(l2, l1, m))
168 can_append_HTM_mask[l2][l1]
169 |= (((uint64_t)1) << m);
170}
171
172void
173init_moveset(Moveset *ms)
174{
175 int j;
176 Move m;
177
178 for (j = 0, m = U; m < NMOVES; m++)
179 if (ms->allowed(m))
180 ms->sorted_moves[j++] = m;
181 ms->sorted_moves[j] = NULLMOVE;
182
183/* TODO: should be here? maybe just init all movesets together anyway... */
184 init_can_append_HTM();
185}
186
187void
188init_movesets()
189{
190 int i;
191
192 for (i = 0; all_movesets[i] != NULL; i++)
193 init_moveset(all_movesets[i]);
194}
diff --git a/src/movesets.h b/src/movesets.h
deleted file mode 100644
index a02d171..0000000
--- a/src/movesets.h
+++ /dev/null
@@ -1,15 +0,0 @@
1#ifndef MOVESETS_H
2#define MOVESETS_H
3
4#include "alg.h"
5
6void init_moveset(Moveset *);
7void init_movesets();
8
9extern Moveset moveset_HTM;
10extern Moveset moveset_URF;
11extern Moveset moveset_eofb;
12extern Moveset moveset_drud;
13extern Moveset moveset_htr;
14
15#endif
diff --git a/src/pf.c b/src/pf.c
new file mode 100644
index 0000000..7d86e4e
--- /dev/null
+++ b/src/pf.c
@@ -0,0 +1,95 @@
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};
81
82PieceFilter
83pf_coud = {
84 .coud = true
85};
86
87PieceFilter
88pf_edges = {
89 .epose = true,
90 .eposs = true,
91 .eposm = true,
92 .eofb = true,
93 .eorl = true,
94 .eoud = true
95};
diff --git a/src/pf.h b/src/pf.h
new file mode 100644
index 0000000..0b552dc
--- /dev/null
+++ b/src/pf.h
@@ -0,0 +1,20 @@
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;
17extern PieceFilter pf_coud;
18extern PieceFilter pf_edges;
19
20#endif
diff --git a/src/pruning.c b/src/pruning.c
index 3cc9152..1dba949 100644
--- a/src/pruning.c
+++ b/src/pruning.c
@@ -1,5 +1,3 @@
1#define PRUNING_C
2
3#include "pruning.h" 1#include "pruning.h"
4 2
5#define ENTRIES_PER_GROUP (2*sizeof(entry_group_t)) 3#define ENTRIES_PER_GROUP (2*sizeof(entry_group_t))
@@ -7,14 +5,106 @@
7 5
8static int findchunk(PruneData *pd, int nchunks, uint64_t i); 6static int findchunk(PruneData *pd, int nchunks, uint64_t i);
9static void genptable_bfs(PruneData *pd, int d, int nt, int nc); 7static void genptable_bfs(PruneData *pd, int d, int nt, int nc);
8static void genptable_compress(PruneData *pd);
10static void genptable_fixnasty(PruneData *pd, int d, int nthreads); 9static void genptable_fixnasty(PruneData *pd, int d, int nthreads);
10static void genptable_setbase(PruneData *pd);
11static void * instance_bfs(void *arg); 11static void * instance_bfs(void *arg);
12static void * instance_fixnasty(void *arg); 12static void * instance_fixnasty(void *arg);
13static void ptable_update(PruneData *pd, uint64_t ind, int m); 13static void ptable_update(PruneData *pd, Cube cube, int m);
14static void ptable_update_index(PruneData *pd, uint64_t ind, int m);
15static int ptableval_index(PruneData *pd, uint64_t ind);
14static bool read_ptable_file(PruneData *pd); 16static bool read_ptable_file(PruneData *pd);
15static bool write_ptable_file(PruneData *pd); 17static bool write_ptable_file(PruneData *pd);
16 18
17PruneData *active_pd[256]; 19PruneData
20pd_eofb_HTM = {
21 .filename = "pt_eofb_HTM",
22 .coord = &coord_eofb,
23 .moveset = &moveset_HTM,
24};
25
26PruneData
27pd_coud_HTM = {
28 .filename = "pt_coud_HTM",
29 .coord = &coord_coud,
30 .moveset = &moveset_HTM,
31};
32
33PruneData
34pd_cornershtr_HTM = {
35 .filename = "pt_cornershtr_HTM",
36 .coord = &coord_cornershtr,
37 .moveset = &moveset_HTM,
38};
39
40PruneData
41pd_corners_HTM = {
42 .filename = "pt_corners_HTM",
43 .coord = &coord_corners,
44 .moveset = &moveset_HTM,
45};
46
47PruneData
48pd_drud_sym16_HTM = {
49 .filename = "pt_drud_sym16_HTM",
50 .coord = &coord_drud_sym16,
51 .moveset = &moveset_HTM,
52};
53
54PruneData
55pd_drud_eofb = {
56 .filename = "pt_drud_eofb",
57 .coord = &coord_drud_eofb,
58 .moveset = &moveset_eofb,
59};
60
61PruneData
62pd_drudfin_noE_sym16_drud = {
63 .filename = "pt_drudfin_noE_sym16_drud",
64 .coord = &coord_drudfin_noE_sym16,
65 .moveset = &moveset_drud,
66};
67
68PruneData
69pd_htr_drud = {
70 .filename = "pt_htr_drud",
71 .coord = &coord_htr_drud,
72 .moveset = &moveset_drud,
73};
74
75PruneData
76pd_htrfin_htr = {
77 .filename = "pt_htrfin_htr",
78 .coord = &coord_htrfin,
79 .moveset = &moveset_htr,
80};
81
82PruneData
83pd_nxopt31_HTM = {
84 .filename = "pt_nxopt31_HTM",
85 .coord = &coord_nxopt31,
86 .moveset = &moveset_HTM,
87
88 .compact = true,
89 .fallback = &pd_drud_sym16_HTM,
90 .fbmod = BINOM8ON4,
91};
92
93PruneData * all_pd[] = {
94 &pd_eofb_HTM,
95 &pd_coud_HTM,
96 &pd_cornershtr_HTM,
97 &pd_corners_HTM,
98 &pd_drud_sym16_HTM,
99 &pd_drud_eofb,
100 &pd_drudfin_noE_sym16_drud,
101 &pd_htr_drud,
102 &pd_htrfin_htr,
103 &pd_nxopt31_HTM,
104 NULL
105};
106
107/* Functions *****************************************************************/
18 108
19int 109int
20findchunk(PruneData *pd, int nchunks, uint64_t i) 110findchunk(PruneData *pd, int nchunks, uint64_t i)
@@ -27,47 +117,59 @@ findchunk(PruneData *pd, int nchunks, uint64_t i)
27 return MIN(nchunks-1, (int)(i / chunksize)); 117 return MIN(nchunks-1, (int)(i / chunksize));
28} 118}
29 119
30PruneData * 120void
31genptable(PruneData *pd, int nthreads) 121free_pd(PruneData *pd)
32{ 122{
33 int d, nchunks, i, maxv; 123 if (pd->generated)
34 uint64_t oldn; 124 free(pd->ptable);
35 125
36 for (i = 0; active_pd[i] != NULL; i++) { 126 pd->generated = false;
37 if (active_pd[i]->coord == pd->coord && 127}
38 active_pd[i]->moveset == pd->moveset && 128
39 active_pd[i]->compact == pd->compact) 129void
40 return active_pd[i]; 130genptable(PruneData *pd, int nthreads)
41 } 131{
132 bool compact;
133 int d, nchunks;
134 uint64_t oldn, sz;
42 135
43 init_moveset(pd->moveset); 136 if (pd->generated)
44 gen_coord(pd->coord); 137 return;
45 138
46 pd->ptable = malloc(ptablesize(pd) * sizeof(entry_group_t)); 139 /* TODO: check if memory is enough, otherwise maybe exit gracefully? */
140 sz = ptablesize(pd) * (pd->compact ? 2 : 1);
141 pd->ptable = malloc(sz * sizeof(entry_group_t));
47 142
48 if (read_ptable_file(pd)) 143 if (read_ptable_file(pd)) {
49 goto genptable_done; 144 pd->generated = true;
145 return;
146 }
50 147
51 if (nthreads < 4) { 148 if (nthreads < 4) {
52 fprintf(stderr, 149 fprintf(stderr,
53 "--- Warning ---\n" 150 "--- Warning ---\n"
54 "You are using only %d threads to generate the pruning" 151 "You are using only %d threads to generate the pruning"
55 "tables. This can take a while.\n" 152 "tables. This can take a while."
56 "Unless you did this intentionally, you should re-run" 153 "Unless you did this intentionally, you should re-run"
57 "this command with `-t 4' or more.\n" 154 "this command with `-t 4' or more.\n"
58 "---------------\n\n", nthreads 155 "---------------\n\n", nthreads
59 ); 156 );
60 } 157 }
61 158
159
160 /* For the first steps we proceed the same way for compact and not */
161 compact = pd->compact;
162 pd->compact = false;
163 pd->generated = true;
164
62 nchunks = MIN(ptablesize(pd), 100000); 165 nchunks = MIN(ptablesize(pd), 100000);
63 fprintf(stderr, "Generating pt_%s_%s with %d threads\n", 166 fprintf(stderr, "Cannot load %s, generating it with %d threads\n",
64 pd->coord->name, pd->moveset->name, nthreads); 167 pd->filename, nthreads);
168
65 169
66 memset(pd->ptable, ~(uint8_t)0, ptablesize(pd)*sizeof(entry_group_t)); 170 memset(pd->ptable, ~(uint8_t)0, ptablesize(pd)*sizeof(entry_group_t));
67 for (i = 0; i < 16; i++)
68 pd->count[i] = 0;
69 171
70 ptable_update(pd, 0, 0); 172 ptable_update(pd, (Cube){0}, 0);
71 pd->n = 1; 173 pd->n = 1;
72 oldn = 0; 174 oldn = 0;
73 genptable_fixnasty(pd, 0, nthreads); 175 genptable_fixnasty(pd, 0, nthreads);
@@ -76,9 +178,7 @@ genptable(PruneData *pd, int nthreads)
76 0, pd->n - oldn, pd->n, pd->coord->max); 178 0, pd->n - oldn, pd->n, pd->coord->max);
77 oldn = pd->n; 179 oldn = pd->n;
78 pd->count[0] = pd->n; 180 pd->count[0] = pd->n;
79 181 for (d = 0; d < 15 && pd->n < pd->coord->max; d++) {
80 maxv = pd->compact ? MIN(15, pd->base + 4) : 15;
81 for (d = 0; d < maxv && pd->n < pd->coord->max; d++) {
82 genptable_bfs(pd, d, nthreads, nchunks); 182 genptable_bfs(pd, d, nthreads, nchunks);
83 genptable_fixnasty(pd, d+1, nthreads); 183 genptable_fixnasty(pd, d+1, nthreads);
84 fprintf(stderr, "Depth %d done, generated %" 184 fprintf(stderr, "Depth %d done, generated %"
@@ -87,17 +187,14 @@ genptable(PruneData *pd, int nthreads)
87 pd->count[d+1] = pd->n - oldn; 187 pd->count[d+1] = pd->n - oldn;
88 oldn = pd->n; 188 oldn = pd->n;
89 } 189 }
90 if (pd->compact)
91 fprintf(stderr, "Compact table, values above "
92 "%d are inaccurate.\n", maxv-1);
93 fprintf(stderr, "Pruning table generated!\n"); 190 fprintf(stderr, "Pruning table generated!\n");
94 191
192 genptable_setbase(pd);
193 if (compact)
194 genptable_compress(pd);
195
95 if (!write_ptable_file(pd)) 196 if (!write_ptable_file(pd))
96 fprintf(stderr, "Error writing ptable file\n"); 197 fprintf(stderr, "Error writing ptable file\n");
97
98genptable_done:
99 for (i = 0; active_pd[i] != NULL; i++);
100 return active_pd[i] = pd;
101} 198}
102 199
103static void 200static void
@@ -135,6 +232,31 @@ genptable_bfs(PruneData *pd, int d, int nthreads, int nchunks)
135} 232}
136 233
137static void 234static void
235genptable_compress(PruneData *pd)
236{
237 int val;
238 uint64_t i, j;
239 entry_group_t mask, v;
240
241 fprintf(stderr, "Compressing table to 2 bits per entry\n");
242
243 for (i = 0; i < pd->coord->max; i += ENTRIES_PER_GROUP_COMPACT) {
244 mask = (entry_group_t)0;
245 for (j = 0; j < ENTRIES_PER_GROUP_COMPACT; j++) {
246 if (i+j >= pd->coord->max)
247 break;
248 val = ptableval_index(pd, i+j) - pd->base;
249 v = (entry_group_t)MIN(3, MAX(0, val));
250 mask |= v << (2*j);
251 }
252 pd->ptable[i/ENTRIES_PER_GROUP_COMPACT] = mask;
253 }
254
255 pd->compact = true;
256 pd->ptable = realloc(pd->ptable, sizeof(entry_group_t)*ptablesize(pd));
257}
258
259static void
138genptable_fixnasty(PruneData *pd, int d, int nthreads) 260genptable_fixnasty(PruneData *pd, int d, int nthreads)
139{ 261{
140 int i; 262 int i;
@@ -142,7 +264,7 @@ genptable_fixnasty(PruneData *pd, int d, int nthreads)
142 ThreadDataGenpt td[nthreads]; 264 ThreadDataGenpt td[nthreads];
143 pthread_mutex_t *upmtx; 265 pthread_mutex_t *upmtx;
144 266
145 if (pd->coord->type != SYMCOMP_COORD) 267 if (pd->coord->tfind == NULL)
146 return; 268 return;
147 269
148 upmtx = malloc(sizeof(pthread_mutex_t)); 270 upmtx = malloc(sizeof(pthread_mutex_t));
@@ -162,12 +284,28 @@ genptable_fixnasty(PruneData *pd, int d, int nthreads)
162 free(upmtx); 284 free(upmtx);
163} 285}
164 286
287static void
288genptable_setbase(PruneData *pd)
289{
290 int i;
291 uint64_t sum, newsum;
292
293 pd->base = 0;
294 sum = pd->count[0] + pd->count[1] + pd->count[2];
295 for (i = 3; i < 16; i++) {
296 newsum = sum + pd->count[i] - pd->count[i-3];
297 if (newsum > sum)
298 pd->base = i-3;
299 sum = newsum;
300 }
301}
302
165static void * 303static void *
166instance_bfs(void *arg) 304instance_bfs(void *arg)
167{ 305{
168 ThreadDataGenpt *td; 306 ThreadDataGenpt *td;
169 uint64_t i, ii, blocksize, rmin, rmax, updated; 307 uint64_t i, ii, blocksize, rmin, rmax, updated;
170 int j, pval, ichunk, oldc, newc; 308 int j, pval, ichunk;
171 Move *ms; 309 Move *ms;
172 310
173 td = (ThreadDataGenpt *)arg; 311 td = (ThreadDataGenpt *)arg;
@@ -178,43 +316,25 @@ instance_bfs(void *arg)
178 td->pd->coord->max : 316 td->pd->coord->max :
179 ((uint64_t)td->thid + 1) * blocksize; 317 ((uint64_t)td->thid + 1) * blocksize;
180 318
181 if (td->pd->compact) {
182 if (td->d <= td->pd->base) {
183 oldc = 1;
184 newc = 1;
185 } else {
186 oldc = td->d - td->pd->base;
187 newc = td->d - td->pd->base;
188 }
189 } else {
190 oldc = td->d;
191 newc = td->d + 1;
192 }
193
194 updated = 0; 319 updated = 0;
195 for (i = rmin; i < rmax; i++) { 320 for (i = rmin; i < rmax; i++) {
196 ichunk = findchunk(td->pd, td->nchunks, i); 321 ichunk = findchunk(td->pd, td->nchunks, i);
197 pthread_mutex_lock(td->mutex[ichunk]); 322 pthread_mutex_lock(td->mutex[ichunk]);
198 pval = ptableval(td->pd, i); 323 pval = ptableval_index(td->pd, i);
199 pthread_mutex_unlock(td->mutex[ichunk]); 324 pthread_mutex_unlock(td->mutex[ichunk]);
200 if (pval == oldc) { 325 if (pval == td->d) {
201 for (j = 0; ms[j] != NULLMOVE; j++) { 326 for (j = 0; ms[j] != NULLMOVE; j++) {
202 ii = move_coord(td->pd->coord, ms[j], i, NULL); 327 ii = td->pd->coord->move(ms[j], i);
203 ichunk = findchunk(td->pd, td->nchunks, ii); 328 ichunk = findchunk(td->pd, td->nchunks, ii);
204 pthread_mutex_lock(td->mutex[ichunk]); 329 pthread_mutex_lock(td->mutex[ichunk]);
205 pval = ptableval(td->pd, ii); 330 pval = ptableval_index(td->pd, ii);
206 if (pval > newc) { 331 if (pval > td->d+1) {
207 ptable_update(td->pd, ii, newc); 332 ptable_update_index(td->pd,
333 ii, td->d+1);
208 updated++; 334 updated++;
209 } 335 }
210 pthread_mutex_unlock(td->mutex[ichunk]); 336 pthread_mutex_unlock(td->mutex[ichunk]);
211 } 337 }
212 if (td->pd->compact && td->d <= td->pd->base) {
213 ichunk = findchunk(td->pd, td->nchunks, i);
214 pthread_mutex_lock(td->mutex[ichunk]);
215 ptable_update(td->pd, i, 0);
216 pthread_mutex_unlock(td->mutex[ichunk]);
217 }
218 } 338 }
219 } 339 }
220 340
@@ -229,40 +349,30 @@ static void *
229instance_fixnasty(void *arg) 349instance_fixnasty(void *arg)
230{ 350{
231 ThreadDataGenpt *td; 351 ThreadDataGenpt *td;
232 uint64_t i, ii, blocksize, rmin, rmax, updated, ss, M; 352 uint64_t i, ii, nb, blocksize, rmin, rmax, updated;
233 int j, oldc; 353 int j, n;
234 Trans t; 354 Trans t, aux[NTRANS];
235 355
236 td = (ThreadDataGenpt *)arg; 356 td = (ThreadDataGenpt *)arg;
237 357 nb = td->pd->coord->max / td->pd->coord->base->max;
238 /* We know type = SYMCOMP_COORD */ 358 blocksize = (td->pd->coord->base->max / td->nthreads) * nb;
239 M = td->pd->coord->base[1]->max;
240 blocksize = (td->pd->coord->base[0]->max / td->nthreads) * M;
241 rmin = ((uint64_t)td->thid) * blocksize; 359 rmin = ((uint64_t)td->thid) * blocksize;
242 rmax = td->thid == td->nthreads - 1 ? 360 rmax = td->thid == td->nthreads - 1 ?
243 td->pd->coord->max : 361 td->pd->coord->max :
244 ((uint64_t)td->thid + 1) * blocksize; 362 ((uint64_t)td->thid + 1) * blocksize;
245 363
246 if (td->pd->compact) {
247 if (td->d <= td->pd->base)
248 oldc = 1;
249 else
250 oldc = td->d - td->pd->base;
251 } else {
252 oldc = td->d;
253 }
254
255 updated = 0; 364 updated = 0;
256 for (i = rmin; i < rmax; i++) { 365 for (i = rmin; i < rmax; i++) {
257 if (ptableval(td->pd, i) == oldc) { 366 if (ptableval_index(td->pd, i) == td->d) {
258 ss = td->pd->coord->base[0]->selfsim[i/M]; 367 if ((n = td->pd->coord->tfind(i, aux)) == 1)
259 for (j = 0; j < td->pd->coord->base[0]->tgrp->n; j++) { 368 continue;
260 t = td->pd->coord->base[0]->tgrp->t[j]; 369
261 if (t == uf || !(ss & ((uint64_t)1<<t))) 370 for (j = 0; j < n; j++) {
371 if ((t = aux[j]) == uf)
262 continue; 372 continue;
263 ii = trans_coord(td->pd->coord, t, i); 373 ii = td->pd->coord->transform(t, i);
264 if (ptableval(td->pd, ii) > oldc) { 374 if (ptableval_index(td->pd, ii) > td->d) {
265 ptable_update(td->pd, ii, oldc); 375 ptable_update_index(td->pd, ii, td->d);
266 updated++; 376 updated++;
267 } 377 }
268 } 378 }
@@ -281,13 +391,11 @@ print_ptable(PruneData *pd)
281{ 391{
282 uint64_t i; 392 uint64_t i;
283 393
284 printf("Table %s_%s\n", pd->coord->name, pd->moveset->name); 394 if (!pd->generated)
285 395 genptable(pd, 1); /* TODO: set default nthreads somewhere */
286 if (pd->compact) { 396
287 printf("Compract table with base value: %d\n", pd->base); 397 printf("Table %s\n", pd->filename);
288 printf("Values above %d are inaccurate.\n", pd->base + 3); 398 printf("Base value: %d\n", pd->base);
289 }
290
291 for (i = 0; i < 16; i++) 399 for (i = 0; i < 16; i++)
292 printf("%2" PRIu64 "\t%10" PRIu64 "\n", i, pd->count[i]); 400 printf("%2" PRIu64 "\t%10" PRIu64 "\n", i, pd->count[i]);
293} 401}
@@ -303,31 +411,48 @@ ptablesize(PruneData *pd)
303} 411}
304 412
305static void 413static void
306ptable_update(PruneData *pd, uint64_t ind, int n) 414ptable_update(PruneData *pd, Cube cube, int n)
307{ 415{
308 int sh; 416 ptable_update_index(pd, pd->coord->index(cube), n);
309 entry_group_t f, mask; 417}
310 uint64_t i, e, b;
311 418
312 e = pd->compact ? ENTRIES_PER_GROUP_COMPACT : ENTRIES_PER_GROUP; 419static void
313 b = pd->compact ? 2 : 4; 420ptable_update_index(PruneData *pd, uint64_t ind, int n)
314 f = pd->compact ? 3 : 15; 421{
422 int sh;
423 entry_group_t mask;
424 uint64_t i;
315 425
316 sh = b * (ind % e); 426 sh = 4 * (ind % ENTRIES_PER_GROUP);
317 mask = f << sh; 427 mask = ((entry_group_t)15) << sh;
318 i = ind / e; 428 i = ind/ENTRIES_PER_GROUP;
319 429
320 pd->ptable[i] &= ~mask; 430 pd->ptable[i] &= ~mask;
321 pd->ptable[i] |= (((entry_group_t)n) & f) << sh; 431 pd->ptable[i] |= (((entry_group_t)n)&15) << sh;
322} 432}
323 433
324int 434int
325ptableval(PruneData *pd, uint64_t ind) 435ptableval(PruneData *pd, Cube cube)
326{ 436{
327 int sh; 437 return ptableval_index(pd, pd->coord->index(cube));
328 uint64_t e; 438}
439
440static int
441ptableval_index(PruneData *pd, uint64_t ind)
442{
443 int sh, ret;
444 entry_group_t mask;
445 uint64_t i, e;
329 entry_group_t m; 446 entry_group_t m;
330 447
448 if (!pd->generated) {
449 fprintf(stderr, "Warning: request pruning table value"
450 " for uninitialized table %s.\n It's fine, but it"
451 " should not happen. Please report bug.\n",
452 pd->filename);
453 genptable(pd, 1); /* TODO: set default or remove this case */
454 }
455
331 if (pd->compact) { 456 if (pd->compact) {
332 e = ENTRIES_PER_GROUP_COMPACT; 457 e = ENTRIES_PER_GROUP_COMPACT;
333 m = 3; 458 m = 3;
@@ -338,7 +463,19 @@ ptableval(PruneData *pd, uint64_t ind)
338 sh = (ind % e) * 4; 463 sh = (ind % e) * 4;
339 } 464 }
340 465
341 return (pd->ptable[ind/e] & (m << sh)) >> sh; 466 mask = m << sh;
467 i = ind/e;
468
469 ret = (pd->ptable[i] & mask) >> sh;
470
471 if (pd->compact) {
472 if (ret)
473 ret += pd->base;
474 else
475 ret = ptableval_index(pd->fallback, ind / pd->fbmod);
476 }
477
478 return ret;
342} 479}
343 480
344static bool 481static bool
@@ -347,15 +484,13 @@ read_ptable_file(PruneData *pd)
347 init_env(); 484 init_env();
348 485
349 FILE *f; 486 FILE *f;
350 char fname[strlen(tabledir)+256]; 487 char fname[strlen(tabledir)+100];
351 int i; 488 int i;
352 uint64_t r; 489 uint64_t r;
353 490
354 strcpy(fname, tabledir); 491 strcpy(fname, tabledir);
355 strcat(fname, "/pt_"); 492 strcat(fname, "/");
356 strcat(fname, pd->coord->name); 493 strcat(fname, pd->filename);
357 strcat(fname, "_");
358 strcat(fname, pd->moveset->name);
359 494
360 if ((f = fopen(fname, "rb")) == NULL) 495 if ((f = fopen(fname, "rb")) == NULL)
361 return false; 496 return false;
@@ -376,15 +511,13 @@ write_ptable_file(PruneData *pd)
376 init_env(); 511 init_env();
377 512
378 FILE *f; 513 FILE *f;
379 char fname[strlen(tabledir)+256]; 514 char fname[strlen(tabledir)+100];
380 int i; 515 int i;
381 uint64_t w; 516 uint64_t w;
382 517
383 strcpy(fname, tabledir); 518 strcpy(fname, tabledir);
384 strcat(fname, "/pt_"); 519 strcat(fname, "/");
385 strcat(fname, pd->coord->name); 520 strcat(fname, pd->filename);
386 strcat(fname, "_");
387 strcat(fname, pd->moveset->name);
388 521
389 if ((f = fopen(fname, "wb")) == NULL) 522 if ((f = fopen(fname, "wb")) == NULL)
390 return false; 523 return false;
diff --git a/src/pruning.h b/src/pruning.h
index 93ae863..6bdbee1 100644
--- a/src/pruning.h
+++ b/src/pruning.h
@@ -1,16 +1,26 @@
1#ifndef PRUNING_H 1#ifndef PRUNING_H
2#define PRUNING_H 2#define PRUNING_H
3 3
4#include "coord.h" 4#include "symcoord.h"
5#include "movesets.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_nxopt31_HTM;
16
17extern PruneData * all_pd[];
6 18
7void free_pd(PruneData *pd); 19void free_pd(PruneData *pd);
8PruneData * genptable(PruneData *data, int nthreads); 20void genptable(PruneData *pd, int nthreads);
9void print_ptable(PruneData *pd); 21void print_ptable(PruneData *pd);
10uint64_t ptablesize(PruneData *pd); 22uint64_t ptablesize(PruneData *pd);
11int ptableval(PruneData *pd, uint64_t ind); 23int ptableval(PruneData *pd, Cube cube);
12
13extern PruneData *active_pd[256];
14 24
15#endif 25#endif
16 26
diff --git a/src/shell.c b/src/shell.c
index 4faa0a8..0001e0d 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -1,5 +1,3 @@
1#define SHELL_C
2
3#include "shell.h" 1#include "shell.h"
4 2
5static void cleanwhitespaces(char *line); 3static void cleanwhitespaces(char *line);
@@ -9,9 +7,7 @@ bool
9checkfiles() 7checkfiles()
10{ 8{
11 /* TODO: add more checks (other files, use checksum...) */ 9 /* TODO: add more checks (other files, use checksum...) */
12 /* How to check for pruning tables with new method? */ 10 FILE *f;
13 /* Solution: use list of steps */
14 /*
15 char fname[strlen(tabledir)+100]; 11 char fname[strlen(tabledir)+100];
16 int i; 12 int i;
17 13
@@ -24,7 +20,6 @@ checkfiles()
24 else 20 else
25 fclose(f); 21 fclose(f);
26 } 22 }
27 */
28 23
29 return true; 24 return true;
30} 25}
@@ -142,14 +137,12 @@ launch(bool batchmode)
142 free(shell_argv); 137 free(shell_argv);
143} 138}
144 139
145#ifndef TEST
146int 140int
147main(int argc, char *argv[]) 141main(int argc, char *argv[])
148{ 142{
149 char *closing_cmd[1] = { "freemem" }; 143 char *closing_cmd[1] = { "freemem" };
150 144
151 init_env(); 145 init_env();
152 init_trans();
153 146
154 if (!checkfiles()) { 147 if (!checkfiles()) {
155 fprintf(stderr, 148 fprintf(stderr,
@@ -174,4 +167,3 @@ main(int argc, char *argv[])
174 167
175 return 0; 168 return 0;
176} 169}
177#endif
diff --git a/src/solve.c b/src/solve.c
index 2d0c94d..d4c0f18 100644
--- a/src/solve.c
+++ b/src/solve.c
@@ -1,122 +1,500 @@
1#define SOLVE_C
2
3#include "solve.h" 1#include "solve.h"
4 2
5void 3/* Local functions ***********************************************************/
6dfs(DfsArg *arg, Solver *solver, Threader *threader) 4
5static bool allowed_next(Move move, DfsArg *arg);
6static bool cancel_niss(DfsArg *arg);
7static void copy_dfsarg(DfsArg *src, DfsArg *dst);
8static void dfs(DfsArg *arg);
9static void dfs_branch(DfsArg *arg);
10static bool dfs_check_solved(DfsArg *arg);
11static bool dfs_switch(DfsArg *arg);
12static void dfs_niss(DfsArg *arg);
13static bool dfs_stop(DfsArg *arg);
14static void * instance_thread(void *arg);
15static void invert_branch(DfsArg *arg);
16static void multidfs(Cube c, Trans t, Step *s, SolveOptions *opts,
17 AlgList *sols, int d);
18static bool niss_makes_sense(DfsArg *arg);
19static bool solvestop(int d, int op, SolveOptions *opts, AlgList *sols);
20
21/* Local functions ***********************************************************/
22
23static bool
24allowed_next(Move m, DfsArg *arg)
25{
26 bool bad, allowed, order;
27 uint64_t mbit;
28
29 mbit = ((uint64_t)1) << m;
30 bad = mbit & arg->badmoves;
31 allowed = mbit & arg->step->moveset->mask[arg->last2][arg->last1];
32 order = !commute(arg->last1, m) || arg->last1 < m;
33
34 return allowed && !bad && order;
35}
36
37static bool
38cancel_niss(DfsArg *arg)
39{
40 Moveset *ms;
41 Move i1, i2;
42 bool p, p1, p2, q, q1, q2;
43
44 if (arg->last1inv == NULLMOVE)
45 return false;
46
47 ms = arg->step->moveset;
48 i1 = inverse_move(arg->last1inv);
49 i2 = inverse_move(arg->last2inv);
50
51 p1 = !ms->allowed_next(arg->last2, arg->last1, i1);
52 p2 = !ms->allowed_next(arg->last2, i1, arg->last1);
53 p = p1 || (commute(i1, arg->last1) && p2);
54
55 q1 = !ms->allowed_next(arg->last2, arg->last1, i2);
56 q2 = !ms->allowed_next(arg->last2, i2, arg->last1);
57 q = q1 || (commute(i2, arg->last1) && q2);
58
59 return p || (commute(i1, i2) && q);
60}
61
62static void
63copy_dfsarg(DfsArg *src, DfsArg *dst)
64{
65 dst->step = src->step;
66 dst->opts = src->opts;
67 dst->t = src->t;
68 dst->cube = src->cube;
69 dst->inverse = src->inverse;
70 dst->d = src->d;
71 dst->badmoves = src->badmoves;
72 dst->badmovesinv = src->badmovesinv;
73 dst->niss = src->niss;
74 dst->last1 = src->last1;
75 dst->last2 = src->last2;
76 dst->last1inv = src->last1inv;
77 dst->last2inv = src->last2inv;
78 dst->sols = src->sols;
79 dst->sols_mutex = src->sols_mutex;
80 dst->current_alg = src->current_alg;
81
82 copy_estimatedata(src->ed, dst->ed);
83}
84
85static void
86dfs(DfsArg *arg)
87{
88 bool sw = false;
89
90 if (dfs_stop(arg))
91 return;
92
93 if (dfs_check_solved(arg))
94 return;
95
96 if (arg->step->final && (sw = dfs_switch(arg)))
97 invert_branch(arg);
98 dfs_branch(arg);
99
100 if (arg->opts->can_niss && !arg->niss && niss_makes_sense(arg))
101 dfs_niss(arg);
102
103 if (sw)
104 invert_branch(arg);
105}
106
107static void
108dfs_branch(DfsArg *arg)
7{ 109{
8 int i; 110 int i;
9 DfsArg newarg;
10 Alg *sol;
11 Move m; 111 Move m;
112 DfsArg *newarg;
12 113
13 if (arg->current_alg->len > arg->d) 114 newarg = malloc(sizeof(DfsArg));
14 return; 115 newarg->ed = malloc(sizeof(EstimateData));
15 116
16 if (solver->is_solved(solver->param, arg->cubedata)) { 117 for (i = 0; arg->step->moveset->sorted_moves[i] != NULLMOVE; i++) {
17/* TODO: the "all" option should be re-implemented as setting 118 m = arg->step->moveset->sorted_moves[i];
18validate to null */ 119 if (allowed_next(m, arg)) {
120 copy_dfsarg(arg, newarg);
121 newarg->last2 = arg->last1;
122 newarg->last1 = m;
123 newarg->cube = apply_move(m, arg->cube);
124 append_move(arg->current_alg, m, newarg->niss);
19 125
20/* TODO: we also have to check if cancel with NISS; 126 dfs(newarg);
21we can't because we have no access to the s->final field
22this should be done by the step's validator? */
23 sol = solver->validate_solution(solver->param,arg->current_alg);
24 bool accepted = sol != NULL;
25 bool too_short = arg->current_alg->len != arg->d;
26 127
27 if (accepted && !too_short) { 128 arg->current_alg->len--;
28/* TODO: arg->t got lost in refactoring */
29/* transform_alg(inverse_trans(arg->t), sol);*/
30 if (arg->opts->verbose)
31 print_alg(sol, false);
32 threader->append_sol(sol, arg->threaddata);
33 } 129 }
34 return;
35 } 130 }
36 131
37 if (arg->current_alg->len == arg->d) 132 free(newarg->ed);
38 return; 133 free(newarg);
134}
135
136static bool
137dfs_check_solved(DfsArg *arg)
138{
139 if (!arg->step->is_done(arg->cube))
140 return false;
141
142 if (arg->current_alg->len == arg->d) {
143 if ((arg->step->is_valid(arg->current_alg) || arg->opts->all)
144 && (!arg->step->final || !cancel_niss(arg))) {
145
146 pthread_mutex_lock(arg->sols_mutex);
147
148 if (arg->sols->len < arg->opts->max_solutions) {
149 append_alg(arg->sols, arg->current_alg);
150
151 transform_alg(
152 inverse_trans(arg->t),
153 arg->sols->last->alg
154 );
155 if (arg->step->final)
156 inplace(unniss, arg->sols->last->alg);
157
158 if (arg->opts->verbose)
159 print_alg(arg->sols->last->alg, false);
160 }
161
162 pthread_mutex_unlock(arg->sols_mutex);
163 }
164 }
165
166 return true;
167}
168
169static void
170dfs_niss(DfsArg *arg)
171{
172 DfsArg *newarg;
173
174 newarg = malloc(sizeof(DfsArg));
175 newarg->ed = malloc(sizeof(EstimateData));
176
177 copy_dfsarg(arg, newarg);
178 swapmove(&(newarg->last1), &(newarg->last1inv));
179 swapmove(&(newarg->last2), &(newarg->last2inv));
180 newarg->niss = !(arg->niss);
181 newarg->cube = inverse_cube(arg->cube);
182
183 dfs(newarg);
184
185 free(newarg->ed);
186 free(newarg);
187}
188
189static bool
190dfs_stop(DfsArg *arg)
191{
192 int lowerbound;
193 bool b;
194
195 lowerbound = arg->step->estimate(arg);
196 if (arg->opts->can_niss && !arg->niss)
197 lowerbound = MIN(1, lowerbound);
198
199 if (arg->current_alg->len + lowerbound > arg->d) {
200 b = true;
201 } else {
202 pthread_mutex_lock(arg->sols_mutex);
203 b = arg->sols->len >= arg->opts->max_solutions;
204 pthread_mutex_unlock(arg->sols_mutex);
205 }
206
207 return b;
208}
209
210static bool
211dfs_switch(DfsArg *arg)
212{
213 int i, bn, bi;
214
215 bn = 0;
216 for (i = 0; arg->step->moveset->sorted_moves[i] != NULLMOVE; i++)
217 if (allowed_next(arg->step->moveset->sorted_moves[i], arg))
218 bn++;
219
220 swapmove(&(arg->last1), &(arg->last1inv));
221 swapmove(&(arg->last2), &(arg->last2inv));
222 swapu64(&(arg->badmoves), &(arg->badmovesinv));
223
224 bi = 0;
225 for (i = 0; arg->step->moveset->sorted_moves[i] != NULLMOVE; i++)
226 if (allowed_next(arg->step->moveset->sorted_moves[i], arg))
227 bi++;
228
229 swapmove(&(arg->last1), &(arg->last1inv));
230 swapmove(&(arg->last2), &(arg->last2inv));
231 swapu64(&(arg->badmoves), &(arg->badmovesinv));
232
233 return bi < bn;
234}
235
236static void *
237instance_thread(void *arg)
238{
239 bool b;
240 Cube c;
241 ThreadDataSolve *td;
242 AlgListNode *node;
243 DfsArg darg;
244
245 td = (ThreadDataSolve *)arg;
246
247 while (1) {
248 b = false;
249
250 pthread_mutex_lock(td->start_mutex);
251 if ((node = *(td->node)) == NULL)
252 b = true;
253 else
254 *(td->node) = (*(td->node))->next;
255 pthread_mutex_unlock(td->start_mutex);
256
257 if (b)
258 break;
259
260 c = node->alg->inv[0] ?
261 apply_move(node->alg->move[0], inverse_cube(td->cube)) :
262 apply_move(node->alg->move[0], td->cube);
263
264 darg.step = td->step;
265 darg.opts = td->opts;
266 darg.t = td->t;
267 darg.cube = c;
268 darg.d = td->depth;
269 darg.niss = node->alg->inv[0];
270 darg.last1 = node->alg->move[0];
271 darg.last2 = NULLMOVE;
272 darg.last1inv = NULLMOVE;
273 darg.last2inv = NULLMOVE;
274 darg.sols = td->sols;
275 darg.sols_mutex = td->sols_mutex;
276 darg.current_alg = new_alg("");
277 append_move(darg.current_alg, node->alg->move[0],
278 node->alg->inv[0]);
279 darg.ed = malloc(sizeof(EstimateData));
280 reset_estimatedata(darg.ed);
281 darg.badmoves = 0;
282 darg.badmovesinv = 0;
283
284 dfs(&darg);
285
286 free_alg(darg.current_alg);
287 free(darg.ed);
288 }
289
290 return NULL;
291}
292
293static void
294invert_branch(DfsArg *arg)
295{
296 Cube aux;
297
298 aux = arg->cube;
299 arg->cube = is_solved(arg->inverse) ?
300 inverse_cube(arg->cube) : arg->inverse;
301 arg->inverse = aux;
302
303 swapu64(&(arg->badmoves), &(arg->badmovesinv));
304 arg->niss = !(arg->niss);
305 swapmove(&(arg->last1), &(arg->last1inv));
306 swapmove(&(arg->last2), &(arg->last2inv));
307 invert_estimatedata(arg->ed);
308}
309
310static void
311multidfs(Cube c, Trans tr, Step *s, SolveOptions *opts, AlgList *sols, int d)
312{
313 int i;
314 Alg *alg;
315 AlgList *start;
316 AlgListNode **node;
317 pthread_t t[opts->nthreads];
318 ThreadDataSolve td[opts->nthreads];
319 pthread_mutex_t *start_mutex, *sols_mutex;
39 320
40/* TODO: do not alloc */ 321 node = malloc(sizeof(AlgListNode *));
41 newarg.cubedata = solver->alloc_cubedata(solver->param); 322 start_mutex = malloc(sizeof(pthread_mutex_t));
42 for (i = 0; solver->moveset->sorted_moves[i] != NULLMOVE; i++) { 323 sols_mutex = malloc(sizeof(pthread_mutex_t));
43 m = solver->moveset->sorted_moves[i];
44 if (solver->moveset->can_append(arg->current_alg, m, arg->niss)
45 && compare_last(arg->current_alg, m, arg->niss) >= 0) {
46 append_move(arg->current_alg, m, arg->niss);
47 324
48 solver->copy_cubedata( 325 start = new_alglist();
49 solver->param, arg->cubedata, newarg.cubedata); 326 pthread_mutex_init(start_mutex, NULL);
50 newarg.threaddata = arg->threaddata; 327 pthread_mutex_init(sols_mutex, NULL);
51 newarg.opts = arg->opts;
52 newarg.d = arg->d;
53 newarg.niss = arg->niss;
54 newarg.current_alg = arg->current_alg;
55 if (!solver->move_check_stop(
56 solver->param, &newarg, threader))
57 dfs(&newarg, solver, threader);
58 328
59 remove_last_move(arg->current_alg); 329 for (i = 0; s->moveset->sorted_moves[i] != NULLMOVE; i++) {
330 alg = new_alg("");
331 append_move(alg, s->moveset->sorted_moves[i], false);
332 append_alg(start, alg);
333 if (opts->can_niss) {
334 alg->inv[0] = true;
335 append_alg(start, alg);
60 } 336 }
337 free_alg(alg);
61 } 338 }
62 solver->free_cubedata(solver->param, newarg.cubedata); 339 *node = start->first;
63 340
64 if (arg->opts->can_niss && !arg->niss && 341 for (i = 0; i < opts->nthreads; i++) {
65 solver->niss_makes_sense( 342 td[i].thid = i;
66 solver->param, arg->cubedata, arg->current_alg)) { 343 td[i].t = tr;
67 solver->invert_cube(solver->param, arg->cubedata); 344 td[i].cube = c;
68 arg->niss = true; 345 td[i].step = s;
69 dfs(arg, solver, threader); 346 td[i].depth = d;
347 td[i].opts = opts;
348 td[i].start = start;
349 td[i].node = node;
350 td[i].sols = sols;
351 td[i].start_mutex = start_mutex;
352 td[i].sols_mutex = sols_mutex;
353 pthread_create(&t[i], NULL, instance_thread, &td[i]);
70 } 354 }
355
356 for (i = 0; i < opts->nthreads; i++)
357 pthread_join(t[i], NULL);
358
359 free_alglist(start);
360 free(node);
361 free(start_mutex);
362 free(sols_mutex);
363}
364
365static bool
366niss_makes_sense(DfsArg *arg)
367{
368 Cube testcube;
369
370 testcube = apply_move(inverse_move(arg->last1), (Cube){0});
371 return arg->current_alg->len == 0 || !arg->step->is_done(testcube);
71} 372}
72 373
374static bool
375solvestop(int d, int op, SolveOptions *opts, AlgList *sols)
376{
377 bool opt_done, max_moves_exceeded, max_sols_exceeded;
378
379 opt_done = opts->optimal != -1 && op != -1 && d > opts->optimal + op;
380 max_moves_exceeded = d > opts->max_moves;
381 max_sols_exceeded = sols->len >= opts->max_solutions;
382
383 return opt_done || max_moves_exceeded || max_sols_exceeded;
384}
385
386/* Public functions **********************************************************/
387
73AlgList * 388AlgList *
74solve(Cube *cube, SolveOptions *opts, Solver **solver, Threader *threader) 389solve(Cube cube, Step *step, SolveOptions *opts)
75{ 390{
76 int i, d, optimal; 391 bool ready;
77 bool ready[MAX_SOLVERS], stop, one_ready; 392 int i, d, op, nt;
78 DfsArg arg[MAX_SOLVERS];
79 AlgList *sols; 393 AlgList *sols;
394 Cube c;
395 Trans tt[NTRANS];
396
397 prepare_step(step, opts);
80 398
81 one_ready = false; 399 if (step->detect != NULL) {
82 for (i = 0; solver[i] != NULL; i++) { 400 nt = step->detect(cube, tt);
83 arg[i].cubedata = 401 } else {
84 solver[i]->prepare_cube(solver[i]->param, cube); 402 tt[0] = step->pre_trans;
85 arg[i].opts = opts; 403 ready = step->ready == NULL ||
86 ready[i] = arg[i].cubedata != NULL; 404 step->ready(apply_trans(tt[0], cube));
87 one_ready = one_ready || ready[i]; 405 nt = ready ? 1 : 0;
88 } 406 }
89 407
90 sols = new_alglist(); 408 sols = new_alglist();
91 if (!one_ready) { 409
92 fprintf(stderr, "Cube not ready for solving\n"); 410 if (nt == 0) {
411 fprintf(stderr, "Cube not ready for solving step: ");
412 fprintf(stderr, "%s\n", step->ready_msg);
93 return sols; 413 return sols;
94 } 414 }
95 415
96 optimal = opts->max_moves; 416 if (opts->min_moves == 0) {
97 stop = false; 417 for (i = 0; i < nt; i++) {
98 for (d = opts->min_moves; d <= opts->max_moves && !stop; d++) { 418 c = apply_trans(tt[i], cube);
419 if (step->is_done(c)) {
420 append_alg(sols, new_alg(""));
421 return sols;
422 }
423 }
424 }
425
426 op = -1;
427 for (d = opts->min_moves; !solvestop(d, op, opts, sols); d++) {
99 if (opts->verbose) 428 if (opts->verbose)
100 fprintf(stderr, "Searching depth %d\n", d); 429 fprintf(stderr, "Searching depth %d\n", d);
101 430
102 for (i = 0; solver[i] != NULL && !stop; i++) { 431 for (i = 0; i < nt && !solvestop(d, op, opts, sols); i++) {
103 if (!ready[i]) 432 c = apply_trans(tt[i], cube);
104 continue; 433 multidfs(c, tt[i], step, opts, sols, d);
434 if (sols->len > 0 && op == -1)
435 op = d;
436 }
437 }
438
439 return sols;
440}
441
442/* TODO: make more general! */
443Alg *
444solve_2phase(Cube cube, int nthreads)
445{
446 int bestlen, newb;
447 Alg *bestalg, *ret;
448 AlgList *sols1, *sols2;
449 AlgListNode *i;
450 Cube c;
451 SolveOptions opts1, opts2;
105 452
106 arg[i].d = d; 453 opts1.min_moves = 0;
107 threader->dispatch(&arg[i], sols, solver[i], threader); 454 opts1.max_moves = 13;
455 opts1.max_solutions = 20;
456 opts1.nthreads = nthreads;
457 opts1.optimal = 3;
458 opts1.can_niss = false;
459 opts1.verbose = false;
460 opts1.all = true;
108 461
109 if (sols->len > 0) 462 opts2.min_moves = 0;
110 optimal = MIN(optimal, d); 463 opts2.max_moves = 19;
464 opts2.max_solutions = 1;
465 opts2.nthreads = nthreads;
466 opts2.can_niss = false;
467 opts2.verbose = false;
111 468
112 stop = sols->len >= opts->max_solutions; 469 /* We skip step1 if it is solved on any axis */
470 if (drany_HTM.is_done(cube)) {
471 sols1 = new_alglist();
472 append_alg(sols1, new_alg(""));
473 } else {
474 sols1 = solve(cube, &drany_HTM, &opts1);
475 }
476 bestalg = new_alg("");
477 bestlen = 999;
478 for (i = sols1->first; i != NULL; i = i->next) {
479 c = apply_alg(i->alg, cube);
480 sols2 = solve(c, &dranyfin_DR, &opts2);
481
482 if (sols2->len > 0) {
483 newb = i->alg->len + sols2->first->alg->len;
484 if (newb < bestlen) {
485 bestlen = newb;
486 copy_alg(i->alg, bestalg);
487 compose_alg(bestalg, sols2->first->alg);
488 }
113 } 489 }
114 stop = stop || 490
115 (opts->optimal != -1 && d >= opts->optimal + optimal); 491 free_alglist(sols2);
116 } 492 }
117 493
118/* TODO: some cleanup (free cubedata) */ 494 free_alglist(sols1);
119/* TODO: actually, preparation should be done somewhere else */
120 495
121 return sols; 496 ret = cleanup(bestalg);
497 free_alg(bestalg);
498
499 return ret;
122} 500}
diff --git a/src/solve.h b/src/solve.h
index 8182887..6ce6609 100644
--- a/src/solve.h
+++ b/src/solve.h
@@ -2,53 +2,10 @@
2#define SOLVE_H 2#define SOLVE_H
3 3
4#include "moves.h" 4#include "moves.h"
5#include "steps.h"
6#include "trans.h"
5 7
6#define MAX_SOLVERS 99 8AlgList * solve(Cube cube, Step *step, SolveOptions *opts);
7 9Alg * solve_2phase(Cube cube, int nthreads);
8typedef struct dfsarg DfsArg;
9typedef struct threader Threader;
10typedef struct solver Solver;
11
12/* TODO: add solver and threader in DfsData, remove from dispatch args and similar */
13
14struct dfsarg {
15 void * cubedata;
16 void * threaddata;
17 SolveOptions * opts;
18 int d;
19 bool niss;
20 Alg * current_alg;
21};
22
23struct threader {
24 void (*append_sol)(Alg *, void *);
25 void (*dispatch)(DfsArg *, AlgList *, Solver *, Threader *);
26 int (*get_nsol)(void *);
27/* TODO: threader should have param, like solver? */
28};
29
30struct solver {
31 Moveset * moveset;
32 bool (*move_check_stop)(void *, DfsArg *, Threader *);
33 Alg * (*validate_solution)(void *, Alg *);
34 bool (*niss_makes_sense)(void *, void *, Alg *);
35/* TODO: move param to somewhere where it makes more sense */
36 void * param;
37/* TODO: the following should be part of a generic cube description */
38/* TODO: remove alloc? */
39/* TODO: revisit apply_move, maybe apply_alg? or both? */
40 void * (*alloc_cubedata)(void *);
41 void (*copy_cubedata)(void *, void *, void *);
42 void (*free_cubedata)(void *, void *);
43 void (*invert_cube)(void *, void *);
44 bool (*is_solved)(void *, void *);
45 void (*apply_move)(void *, void *, Move);
46/* TODO: remove dependence on Cube, preparation should be done before */
47 void * (*prepare_cube)(void *, Cube *);
48};
49
50void dfs(DfsArg *, Solver *, Threader *);
51/* TODO: remove dependence on Cube, preparation should be done before */
52AlgList * solve(Cube *, SolveOptions *, Solver **, Threader *);
53 10
54#endif 11#endif
diff --git a/src/solver_step.c b/src/solver_step.c
deleted file mode 100644
index 52fa347..0000000
--- a/src/solver_step.c
+++ /dev/null
@@ -1,306 +0,0 @@
1#include "solver_step.h"
2
3typedef struct {
4 Cube * cube;
5 uint64_t * val;
6 Trans * t;
7} CubeData;
8
9static void apply_move_cubedata(void *, void *, Move);
10static void init_indexes(Step *, CubeData *);
11static void * prepare_cube(void *, Cube *);
12static bool move_check_stop_eager(void *, DfsArg *, Threader *);
13static bool move_check_stop_lazy(void *, DfsArg *, Threader *);
14static bool move_check_stop_nonsol(void *, DfsArg *, Threader *);
15static bool is_solved_step(void *, void *);
16static Alg * validate_solution(void *, Alg *);
17static void * alloc_cubedata(void *);
18static void copy_cubedata(void *, void *, void *);
19static void free_cubedata(void *, void *);
20static void invert_cubedata(void *, void *);
21static bool niss_makes_sense(void *, void *, Alg *);
22static Solver * new_stepsolver_nocheckstop(Step *step);
23
24static void
25apply_move_cubedata(void *param, void *cubedata, Move m)
26{
27 Step *s = (Step *)param;
28 CubeData *data = (CubeData *)cubedata;
29
30 Trans tt;
31 for (int i = 0; i < s->n_coord; i++) {
32 Move mm = transform_move(data->t[i], m);
33 data->val[i] = move_coord(s->coord[i], mm, data->val[i], &tt);
34 data->t[i] = transform_trans(tt, data->t[i]);
35 }
36}
37
38static void
39init_indexes(Step *step, CubeData *data)
40{
41 int i;
42 Cube moved;
43 Trans t, tt;
44
45 for (i = 0; i < step->n_coord; i++) {
46 t = step->coord_trans[i];
47 copy_cube(data->cube, &moved);
48 apply_trans(t, &moved);
49 data->val[i] = index_coord(step->coord[i], &moved, &tt);
50 data->t[i] = transform_trans(tt, t);
51 }
52}
53
54static void *
55prepare_cube(void *param, Cube *cube)
56{
57 int i;
58 Step *s;
59 CubeData *data;
60
61 s = (Step *)param;
62
63 for (i = 0; i < s->n_coord; i++) {
64 s->pd[i] = malloc(sizeof(PruneData));
65 s->pd[i]->moveset = s->moveset;
66/* TODO: check if moveset initialization works fine,
67 e.g. if there is a variable to save the initialized status
68 or if it gets initialized multiple times */
69 init_moveset(s->moveset);
70 s->pd[i]->coord = s->coord[i];
71 gen_coord(s->coord[i]);
72 s->pd[i]->compact = s->pd_compact[i];
73 s->pd[i] = genptable(s->pd[i], 4); /* TODO: threads */
74 }
75
76 data = alloc_cubedata(param);
77 data->cube = malloc(sizeof(Cube));
78 copy_cube(cube, data->cube);
79 init_indexes(s, data);
80
81 return data;
82}
83
84static bool
85move_check_stop_eager(void *param, DfsArg *arg, Threader *threader)
86{
87 int nsol;
88
89 if (move_check_stop_nonsol(param, arg, threader))
90 return true;
91
92 nsol = threader->get_nsol(arg->threaddata);
93 return nsol >= arg->opts->max_solutions;
94}
95
96static bool
97move_check_stop_lazy(void *param, DfsArg *arg, Threader *threader)
98{
99 int nsol;
100
101 nsol = threader->get_nsol(arg->threaddata);
102 if (nsol >= arg->opts->max_solutions)
103 return true;
104
105 return move_check_stop_nonsol(param, arg, threader);
106}
107
108/* TODO: split in 2 (nissable / non-nissable) and only move cube
109 when nissable */
110static bool
111move_check_stop_nonsol(void *param, DfsArg *arg, Threader *threader)
112{
113 int i, goal, bound;
114 Move mm, lastmove;
115 Trans tt = uf;
116 CubeData *data;
117 Step *s;
118
119 s = (Step *)param;
120 data = (CubeData *)arg->cubedata;
121
122
123 bound = 0;
124 goal = arg->d - arg->current_alg->len;
125/* TODO: check if len is 0 */
126 lastmove = arg->current_alg->move[arg->current_alg->len-1];
127 for (i = 0; i < s->n_coord; i++) {
128 mm = transform_move(data->t[i], lastmove);
129 data->val[i] = move_coord(s->coord[i], mm, data->val[i], &tt);
130 data->t[i] = transform_trans(tt, data->t[i]);
131
132 bound = MAX(bound, ptableval(s->pd[i], data->val[i]));
133 if (arg->opts->can_niss && !arg->niss)
134 bound = MIN(1, bound);
135
136 if (bound > goal) {
137 return true;
138 }
139 }
140 if (arg->opts->can_niss && !arg->niss)
141 apply_move(lastmove, data->cube);
142
143 return false;
144}
145
146static bool
147is_solved_step(void *param, void *cubedata)
148{
149 int i;
150 Step *s;
151 CubeData *data;
152
153 s = (Step *)param;
154 data = (CubeData *)cubedata;
155
156 for (i = 0; i < s->n_coord; i++)
157 if (data->val[i] != 0)
158 return false;
159
160 return true;
161}
162
163static Alg *
164validate_solution(void *param, Alg *alg)
165{
166 return ((Step *)param)->is_valid(alg);
167}
168
169static void *
170alloc_cubedata(void *param)
171{
172 Step *s;
173 CubeData *data;
174
175 s = (Step *)param;
176
177 data = malloc(sizeof(CubeData));
178 /* We do not need to allocate a cube */
179 data->val = malloc(s->n_coord * sizeof(uint64_t));
180 data->t = malloc(s->n_coord * sizeof(Trans));
181
182 return data;
183}
184
185static void
186copy_cubedata(void *param, void *src, void *dst)
187{
188 int i;
189 Step *s;
190 CubeData *newdata, *olddata;
191
192 s = (Step *)param;
193 olddata = (CubeData *)src;
194 newdata = (CubeData *)dst;
195
196/* TODO: do not copy if not nissable */
197 newdata->cube = malloc(sizeof(Cube));
198 copy_cube(olddata->cube, newdata->cube);
199 for (i = 0; i < s->n_coord; i++) {
200 newdata->val[i] = olddata->val[i];
201 newdata->t[i] = olddata->t[i];
202 }
203}
204
205static void
206free_cubedata(void *param, void *cubedata)
207{
208 CubeData *data;
209
210 data = (CubeData *)cubedata;
211
212 free(data->t);
213 free(data->val);
214 free(data->cube);
215 free(data);
216}
217
218static void
219invert_cubedata(void *param, void *cubedata)
220{
221 Step *s;
222 CubeData *data;
223
224 s = (Step *)param;
225 data = (CubeData *)cubedata;
226
227 invert_cube(data->cube);
228 init_indexes(s, data);
229}
230
231static bool
232niss_makes_sense(void *param, void *cubedata, Alg *alg)
233{
234 Step *s;
235 CubeData *data;
236
237 s = (Step *)param;
238 data = (CubeData *)cubedata;
239
240 if (s->final)
241 return false;
242
243 if (alg->len_normal == 0)
244 return true;
245
246 Move m = inverse_move(alg->move_normal[alg->len_normal-1]);
247 for (int i = 0; i < s->n_coord; i++) {
248 Move mm = transform_move(data->t[i], m);
249 uint64_t u = move_coord(s->coord[i], mm, 0, NULL);
250 if (ptableval(s->pd[i], u) > 0)
251 return true;
252 }
253
254 return false;
255}
256
257static Solver *
258new_stepsolver_nocheckstop(Step *step)
259{
260 Solver *solver;
261
262 solver = malloc(sizeof(Solver));
263
264 solver->moveset = step->moveset;
265 solver->param = step;
266
267 solver->apply_move = apply_move_cubedata;
268 solver->prepare_cube = prepare_cube;
269 solver->is_solved = is_solved_step;
270 solver->validate_solution = validate_solution;
271 solver->alloc_cubedata = alloc_cubedata;
272 solver->copy_cubedata = copy_cubedata;
273 solver->free_cubedata = free_cubedata;
274 solver->invert_cube = invert_cubedata;
275 solver->niss_makes_sense = niss_makes_sense;
276
277 return solver;
278}
279
280Solver *
281new_stepsolver_eager(Step *step)
282{
283 Solver *solver;
284
285 solver = new_stepsolver_nocheckstop(step);
286 solver->move_check_stop = move_check_stop_eager;
287
288 return solver;
289}
290
291Solver *
292new_stepsolver_lazy(Step *step)
293{
294 Solver *solver;
295
296 solver = new_stepsolver_nocheckstop(step);
297 solver->move_check_stop = move_check_stop_lazy;
298
299 return solver;
300}
301
302void
303free_stepsolver(Solver *solver)
304{
305 free(solver);
306}
diff --git a/src/solver_step.h b/src/solver_step.h
deleted file mode 100644
index f68d077..0000000
--- a/src/solver_step.h
+++ /dev/null
@@ -1,12 +0,0 @@
1#ifndef SOLVER_STEP_H
2#define SOLVER_STEP_H
3
4#include "cube.h"
5#include "solve.h"
6#include "steps.h"
7
8Solver *new_stepsolver_eager(Step *);
9Solver *new_stepsolver_lazy(Step *);
10void free_stepsolver(Solver *);
11
12#endif
diff --git a/src/steps.c b/src/steps.c
index cdba763..3189811 100644
--- a/src/steps.c
+++ b/src/steps.c
@@ -1,117 +1,1376 @@
1#define STEPS_C
2
3#include "steps.h" 1#include "steps.h"
4 2
5/* TODO: change all checkers to use coordinates! */ 3#define UPDATECHECKSTOP(a, b, c) if ((a=(MAX((a),(b))))>(c)) return (a);
4
5/* Checkers, estimators and validators ***************************************/
6
7static bool check_centers(Cube cube);
8static bool check_coud_HTM(Cube cube);
9static bool check_coud_URF(Cube cube);
10static bool check_corners_HTM(Cube cube);
11static bool check_corners_URF(Cube cube);
12static bool check_cornershtr(Cube cube);
13static bool check_eofb(Cube cube);
14static bool check_drud(Cube cube);
15static bool check_htr(Cube cube);
16
17static int estimate_eofb_HTM(DfsArg *arg);
18static int estimate_coud_HTM(DfsArg *arg);
19static int estimate_coud_URF(DfsArg *arg);
20static int estimate_corners_HTM(DfsArg *arg);
21static int estimate_cornershtr_HTM(DfsArg *arg);
22static int estimate_corners_URF(DfsArg *arg);
23static int estimate_cornershtr_URF(DfsArg *arg);
24static int estimate_drud_HTM(DfsArg *arg);
25static int estimate_drud_eofb(DfsArg *arg);
26static int estimate_dr_eofb(DfsArg *arg);
27static int estimate_drudfin_drud(DfsArg *arg);
28static int estimate_htr_drud(DfsArg *arg);
29static int estimate_htrfin_htr(DfsArg *arg);
30static int estimate_nxopt31_HTM(DfsArg *arg);
31static int estimate_light_HTM(DfsArg *arg);
32
33static int estimate_nxoptlike(DfsArg *arg, PruneData *pd);
34
35static bool always_valid(Alg *alg);
36static bool validate_singlecw_ending(Alg *alg);
37
38/* Pre-transformation detectors **********************************************/
39
40static int detect_pretrans_eofb(Cube cube, Trans *ret);
41static int detect_pretrans_drud(Cube cube, Trans *ret);
42static int detect_pretrans_void_3axis(Cube cube, Trans *ret);
43
44/* Messages for when cube is not ready ***************************************/
45
46static char check_centers_msg[100] = "cube must be oriented (centers solved)";
47static char check_eo_msg[100] = "EO must be solved on given axis";
48static char check_dr_msg[100] = "DR must be solved on given axis";
49static char check_htr_msg[100] = "HTR must be solved";
50static char check_drany_msg[100] = "DR must be solved on at least one axis";
51
52/* Steps *********************************************************************/
53
54/* Optimal solvers *******************/
55
56Step
57optimal_HTM = {
58 .shortname = "optimal",
59 .name = "Optimal solve (in HTM)",
60
61 .final = true,
62 .is_done = is_solved,
63 .estimate = estimate_nxopt31_HTM,
64 .ready = check_centers,
65 .ready_msg = check_centers_msg,
66 .is_valid = always_valid,
67 .moveset = &moveset_HTM,
68
69 .pre_trans = uf,
70
71 .tables = {&pd_nxopt31_HTM, &pd_corners_HTM},
72 .ntables = 2,
73};
74
75Step
76optimal_light_HTM = {
77 .shortname = "light",
78 .name = "Optimal solve (in HTM), small table (500Mb RAM total)",
79
80 .final = true,
81 .is_done = is_solved,
82 .estimate = estimate_light_HTM,
83 .ready = check_centers,
84 .ready_msg = check_centers_msg,
85 .is_valid = always_valid,
86 .moveset = &moveset_HTM,
87
88 .pre_trans = uf,
89
90 .tables = {&pd_drud_sym16_HTM, &pd_corners_HTM},
91 .ntables = 2,
92};
93
94/* Optimal after EO ******************/
95
96Step
97eofin_eo = {
98 .shortname = "eofin",
99 .name = "Optimal solve after EO without breaking EO (detected)",
100
101 .final = true,
102 .is_done = is_solved,
103 .estimate = estimate_nxopt31_HTM,
104 .ready = check_eofb,
105 .ready_msg = check_eo_msg,
106 .is_valid = always_valid,
107 .moveset = &moveset_eofb,
108
109 .detect = detect_pretrans_eofb,
110
111 .tables = {&pd_nxopt31_HTM, &pd_corners_HTM},
112 .ntables = 2,
113};
114
115Step
116eofbfin_eofb = {
117 .shortname = "eofbfin",
118 .name = "Optimal after EO on F/B without breaking EO",
119
120 .final = true,
121 .is_done = is_solved,
122 .estimate = estimate_nxopt31_HTM,
123 .ready = check_eofb,
124 .ready_msg = check_eo_msg,
125 .is_valid = always_valid,
126 .moveset = &moveset_eofb,
127
128 .pre_trans = uf,
129
130 .tables = {&pd_nxopt31_HTM, &pd_corners_HTM},
131 .ntables = 2,
132};
133
134Step
135eorlfin_eorl = {
136 .shortname = "eorlfin",
137 .name = "Optimal after EO on R/L without breaking EO",
138
139 .final = true,
140 .is_done = is_solved,
141 .estimate = estimate_nxopt31_HTM,
142 .ready = check_eofb,
143 .ready_msg = check_eo_msg,
144 .is_valid = always_valid,
145 .moveset = &moveset_eofb,
146
147 .pre_trans = ur,
148
149 .tables = {&pd_nxopt31_HTM, &pd_corners_HTM},
150 .ntables = 2,
151};
152
153Step
154eoudfin_eoud = {
155 .shortname = "eoudfin",
156 .name = "Optimal after EO on U/D without breaking EO",
157
158 .final = true,
159 .is_done = is_solved,
160 .estimate = estimate_nxopt31_HTM,
161 .ready = check_eofb,
162 .ready_msg = check_eo_msg,
163 .is_valid = always_valid,
164 .moveset = &moveset_eofb,
165
166 .pre_trans = fd,
167
168 .tables = {&pd_nxopt31_HTM, &pd_corners_HTM},
169 .ntables = 2,
170};
171
172/* EO steps **************************/
173Step
174eoany_HTM = {
175 .shortname = "eo",
176 .name = "EO on any axis",
177
178 .final = false,
179 .is_done = check_eofb,
180 .estimate = estimate_eofb_HTM,
181 .ready = check_centers,
182 .ready_msg = check_centers_msg,
183 .is_valid = validate_singlecw_ending,
184 .moveset = &moveset_HTM,
185
186 .detect = detect_pretrans_void_3axis,
187
188 .tables = {&pd_eofb_HTM},
189 .ntables = 1,
190};
191
192Step
193eofb_HTM = {
194 .shortname = "eofb",
195 .name = "EO on F/B",
196
197 .final = false,
198 .is_done = check_eofb,
199 .estimate = estimate_eofb_HTM,
200 .ready = check_centers,
201 .ready_msg = check_centers_msg,
202 .is_valid = validate_singlecw_ending,
203 .moveset = &moveset_HTM,
204
205 .pre_trans = uf,
206
207 .tables = {&pd_eofb_HTM},
208 .ntables = 1,
209};
210
211Step
212eorl_HTM = {
213 .shortname = "eorl",
214 .name = "EO on R/L",
215
216 .final = false,
217 .is_done = check_eofb,
218 .estimate = estimate_eofb_HTM,
219 .ready = check_centers,
220 .ready_msg = check_centers_msg,
221 .is_valid = validate_singlecw_ending,
222 .moveset = &moveset_HTM,
223
224 .pre_trans = ur,
225
226 .tables = {&pd_eofb_HTM},
227 .ntables = 1,
228};
229
230Step
231eoud_HTM = {
232 .shortname = "eoud",
233 .name = "EO on U/D",
234
235 .final = false,
236 .is_done = check_eofb,
237 .estimate = estimate_eofb_HTM,
238 .ready = check_centers,
239 .ready_msg = check_centers_msg,
240 .is_valid = validate_singlecw_ending,
241 .moveset = &moveset_HTM,
242
243 .pre_trans = fd,
244
245 .tables = {&pd_eofb_HTM},
246 .ntables = 1,
247};
248
249/* CO steps **************************/
250Step
251coany_HTM = {
252 .shortname = "co",
253 .name = "CO on any axis",
254
255 .final = false,
256 .is_done = check_coud_HTM,
257 .estimate = estimate_coud_HTM,
258 .ready = NULL,
259 .is_valid = validate_singlecw_ending,
260 .moveset = &moveset_HTM,
261
262 .detect = detect_pretrans_void_3axis,
263
264 .tables = {&pd_coud_HTM},
265 .ntables = 1,
266};
267
268Step
269coud_HTM = {
270 .shortname = "coud",
271 .name = "CO on U/D",
272
273 .final = false,
274 .is_done = check_coud_HTM,
275 .estimate = estimate_coud_HTM,
276 .ready = NULL,
277 .is_valid = validate_singlecw_ending,
278 .moveset = &moveset_HTM,
279
280 .pre_trans = uf,
281
282 .tables = {&pd_coud_HTM},
283 .ntables = 1,
284};
285
286Step
287corl_HTM = {
288 .shortname = "corl",
289 .name = "CO on R/L",
290
291 .final = false,
292 .is_done = check_coud_HTM,
293 .estimate = estimate_coud_HTM,
294 .ready = NULL,
295 .is_valid = validate_singlecw_ending,
296 .moveset = &moveset_HTM,
297
298 .pre_trans = rf,
299
300 .tables = {&pd_coud_HTM},
301 .ntables = 1,
302};
303
304Step
305cofb_HTM = {
306 .shortname = "cofb",
307 .name = "CO on F/B",
308
309 .final = false,
310 .is_done = check_coud_HTM,
311 .estimate = estimate_coud_HTM,
312 .ready = NULL,
313 .is_valid = validate_singlecw_ending,
314 .moveset = &moveset_HTM,
315
316 .pre_trans = fd,
317
318 .tables = {&pd_coud_HTM},
319 .ntables = 1,
320};
321
322Step
323coany_URF = {
324 .shortname = "co-URF",
325 .name = "CO any axis (URF moveset)",
326
327 .final = false,
328 .is_done = check_coud_URF,
329 .estimate = estimate_coud_URF,
330 .ready = NULL,
331 .is_valid = validate_singlecw_ending,
332 .moveset = &moveset_URF,
333
334 .detect = detect_pretrans_void_3axis,
335
336 .tables = {&pd_coud_HTM},
337 .ntables = 1,
338};
339
340Step
341coud_URF = {
342 .shortname = "coud-URF",
343 .name = "CO on U/D (URF moveset)",
344
345 .final = false,
346 .is_done = check_coud_URF,
347 .estimate = estimate_coud_URF,
348 .ready = NULL,
349 .is_valid = validate_singlecw_ending,
350 .moveset = &moveset_URF,
351
352 .pre_trans = uf,
353
354 .tables = {&pd_coud_HTM},
355 .ntables = 1,
356};
357
358Step
359corl_URF = {
360 .shortname = "corl-URF",
361 .name = "CO on R/L (URF moveset)",
362
363 .final = false,
364 .is_done = check_coud_URF,
365 .estimate = estimate_coud_URF,
366 .ready = NULL,
367 .is_valid = validate_singlecw_ending,
368 .moveset = &moveset_URF,
369
370 .pre_trans = rf,
371
372 .tables = {&pd_coud_HTM},
373 .ntables = 1,
374};
375
376Step
377cofb_URF = {
378 .shortname = "cofb-URF",
379 .name = "CO on F/B (URF moveset)",
380
381 .final = false,
382 .is_done = check_coud_URF,
383 .estimate = estimate_coud_URF,
384 .ready = NULL,
385 .is_valid = validate_singlecw_ending,
386 .moveset = &moveset_URF,
387
388 .pre_trans = fd,
389
390 .tables = {&pd_coud_HTM},
391 .ntables = 1,
392};
393
394/* Misc corner steps *****************/
395Step
396cornershtr_HTM = {
397 .shortname = "chtr",
398 .name = "Solve corners to HTR state",
399
400 .final = false,
401 .is_done = check_cornershtr,
402 .estimate = estimate_cornershtr_HTM,
403 .ready = NULL,
404 .is_valid = validate_singlecw_ending,
405 .moveset = &moveset_HTM,
406
407 .pre_trans = uf,
408
409 .tables = {&pd_cornershtr_HTM},
410 .ntables = 1,
411};
412
413Step
414cornershtr_URF = {
415 .shortname = "chtr-URF",
416 .name = "Solve corners to HTR state (URF moveset)",
417
418 .final = false,
419 .is_done = check_cornershtr,
420 .estimate = estimate_cornershtr_URF,
421 .ready = NULL,
422 .is_valid = validate_singlecw_ending,
423 .moveset = &moveset_URF,
424
425 .pre_trans = uf,
426
427 .tables = {&pd_cornershtr_HTM},
428 .ntables = 1,
429};
430
431Step
432corners_HTM = {
433 .shortname = "corners",
434 .name = "Solve corners",
435
436 .final = true,
437 .is_done = check_corners_HTM,
438 .estimate = estimate_corners_HTM,
439 .ready = NULL,
440 .is_valid = always_valid,
441 .moveset = &moveset_HTM,
442
443 .pre_trans = uf,
444
445 .tables = {&pd_corners_HTM},
446 .ntables = 1,
447};
448
449Step
450corners_URF = {
451 .shortname = "corners-URF",
452 .name = "Solve corners (URF moveset)",
453
454 .final = true, /* TODO: check if this works with reorient */
455 .is_done = check_corners_URF,
456 .estimate = estimate_corners_URF,
457 .ready = NULL,
458 .is_valid = always_valid,
459 .moveset = &moveset_URF,
460
461 .pre_trans = uf,
462
463 .tables = {&pd_corners_HTM},
464 .ntables = 1,
465};
466
467/* DR steps **************************/
468Step
469drany_HTM = {
470 .shortname = "dr",
471 .name = "DR on any axis",
472
473 .final = false,
474 .is_done = check_drud,
475 .estimate = estimate_drud_HTM,
476 .ready = check_centers,
477 .ready_msg = check_centers_msg,
478 .is_valid = validate_singlecw_ending,
479 .moveset = &moveset_HTM,
480
481 .detect = detect_pretrans_void_3axis,
482
483 .tables = {&pd_drud_sym16_HTM},
484 .ntables = 1,
485};
486
487Step
488drud_HTM = {
489 .shortname = "drud",
490 .name = "DR on U/D",
491
492 .final = false,
493 .is_done = check_drud,
494 .estimate = estimate_drud_HTM,
495 .ready = check_centers,
496 .ready_msg = check_centers_msg,
497 .is_valid = validate_singlecw_ending,
498 .moveset = &moveset_HTM,
499
500 .pre_trans = uf,
501
502 .tables = {&pd_drud_sym16_HTM},
503 .ntables = 1,
504};
505
506Step
507drrl_HTM = {
508 .shortname = "drrl",
509 .name = "DR on R/L",
510
511 .final = false,
512 .is_done = check_drud,
513 .estimate = estimate_drud_HTM,
514 .ready = check_centers,
515 .ready_msg = check_centers_msg,
516 .is_valid = validate_singlecw_ending,
517 .moveset = &moveset_HTM,
518
519 .pre_trans = rf,
520
521 .tables = {&pd_drud_sym16_HTM},
522 .ntables = 1,
523};
524
525Step
526drfb_HTM = {
527 .shortname = "drfb",
528 .name = "DR on F/B",
529
530 .final = false,
531 .is_done = check_drud,
532 .estimate = estimate_drud_HTM,
533 .ready = check_centers,
534 .ready_msg = check_centers_msg,
535 .is_valid = validate_singlecw_ending,
536 .moveset = &moveset_HTM,
537
538 .pre_trans = fd,
539
540 .tables = {&pd_drud_sym16_HTM},
541 .ntables = 1,
542};
543
544/* DR from EO */
545Step
546dr_eo = {
547 .shortname = "dr-eo",
548 .name = "DR without breaking EO (automatically detected)",
549
550 .final = false,
551 .is_done = check_drud,
552 .estimate = estimate_dr_eofb,
553 .ready = check_eofb,
554 .ready_msg = check_eo_msg,
555 .is_valid = validate_singlecw_ending,
556 .moveset = &moveset_eofb,
557
558 .detect = detect_pretrans_eofb,
559
560 .tables = {&pd_drud_eofb},
561 .ntables = 1,
562};
563
564Step
565dr_eofb = {
566 .shortname = "dr-eofb",
567 .name = "DR on U/D or R/L without breaking EO on F/B",
568
569 .final = false,
570 .is_done = check_drud,
571 .estimate = estimate_dr_eofb,
572 .ready = check_eofb,
573 .ready_msg = check_eo_msg,
574 .is_valid = validate_singlecw_ending,
575 .moveset = &moveset_eofb,
576
577 .pre_trans = uf,
578
579 .tables = {&pd_drud_eofb},
580 .ntables = 1,
581};
582
583Step
584dr_eorl = {
585 .shortname = "dr-eorl",
586 .name = "DR on U/D or F/B without breaking EO on R/L",
587
588 .final = false,
589 .is_done = check_drud,
590 .estimate = estimate_dr_eofb,
591 .ready = check_eofb,
592 .ready_msg = check_eo_msg,
593 .is_valid = validate_singlecw_ending,
594 .moveset = &moveset_eofb,
595
596 .pre_trans = ur,
597
598 .tables = {&pd_drud_eofb},
599 .ntables = 1,
600};
601
602Step
603dr_eoud = {
604 .shortname = "dr-eoud",
605 .name = "DR on R/L or F/B without breaking EO on U/D",
606
607 .final = false,
608 .is_done = check_drud,
609 .estimate = estimate_dr_eofb,
610 .ready = check_eofb,
611 .ready_msg = check_eo_msg,
612 .is_valid = validate_singlecw_ending,
613 .moveset = &moveset_eofb,
614
615 .pre_trans = fd,
616
617 .tables = {&pd_drud_eofb},
618 .ntables = 1,
619};
620
621Step
622drud_eofb = {
623 .shortname = "drud-eofb",
624 .name = "DR on U/D without breaking EO on F/B",
625
626 .final = false,
627 .is_done = check_drud,
628 .estimate = estimate_drud_eofb,
629 .ready = check_eofb,
630 .ready_msg = check_eo_msg,
631 .is_valid = validate_singlecw_ending,
632 .moveset = &moveset_eofb,
633
634 .pre_trans = uf,
635
636 .tables = {&pd_drud_eofb},
637 .ntables = 1,
638};
639
640Step
641drrl_eofb = {
642 .shortname = "drrl-eofb",
643 .name = "DR on R/L without breaking EO on F/B",
644
645 .final = false,
646 .is_done = check_drud,
647 .estimate = estimate_drud_eofb,
648 .ready = check_eofb,
649 .ready_msg = check_eo_msg,
650 .is_valid = validate_singlecw_ending,
651 .moveset = &moveset_eofb,
652
653 .pre_trans = rf,
654
655 .tables = {&pd_drud_eofb},
656 .ntables = 1,
657};
658
659Step
660drud_eorl = {
661 .shortname = "drud-eorl",
662 .name = "DR on U/D without breaking EO on R/L",
663
664 .final = false,
665 .is_done = check_drud,
666 .estimate = estimate_drud_eofb,
667 .ready = check_eofb,
668 .ready_msg = check_eo_msg,
669 .is_valid = validate_singlecw_ending,
670 .moveset = &moveset_eofb,
671
672 .pre_trans = ur,
673
674 .tables = {&pd_drud_eofb},
675 .ntables = 1,
676};
677
678Step
679drfb_eorl = {
680 .shortname = "drfb-eorl",
681 .name = "DR on F/B without breaking EO on R/L",
682
683 .final = false,
684 .is_done = check_drud,
685 .estimate = estimate_drud_eofb,
686 .ready = check_eofb,
687 .ready_msg = check_eo_msg,
688 .is_valid = validate_singlecw_ending,
689 .moveset = &moveset_eofb,
690
691 .pre_trans = fr,
692
693 .tables = {&pd_drud_eofb},
694 .ntables = 1,
695};
696
697Step
698drfb_eoud = {
699 .shortname = "drfb-eoud",
700 .name = "DR on F/B without breaking EO on U/D",
701
702 .final = false,
703 .is_done = check_drud,
704 .estimate = estimate_drud_eofb,
705 .ready = check_eofb,
706 .ready_msg = check_eo_msg,
707 .is_valid = validate_singlecw_ending,
708 .moveset = &moveset_eofb,
709
710 .pre_trans = fd,
711
712 .tables = {&pd_drud_eofb},
713 .ntables = 1,
714};
715
716Step
717drrl_eoud = {
718 .shortname = "drrl-eoud",
719 .name = "DR on R/L without breaking EO on U/D",
720
721 .final = false,
722 .is_done = check_drud,
723 .estimate = estimate_drud_eofb,
724 .ready = check_eofb,
725 .ready_msg = check_eo_msg,
726 .is_valid = validate_singlecw_ending,
727 .moveset = &moveset_eofb,
728
729 .pre_trans = rd,
730
731 .tables = {&pd_drud_eofb},
732 .ntables = 1,
733};
734
735/* DR finish steps */
736Step
737dranyfin_DR = {
738 .shortname = "drfin",
739 .name = "DR finish on any axis without breaking DR",
740
741 .final = true,
742 .is_done = is_solved,
743 .estimate = estimate_drudfin_drud,
744 .ready = check_drud,
745 .ready_msg = check_drany_msg,
746 .is_valid = always_valid,
747 .moveset = &moveset_drud,
748
749 .detect = detect_pretrans_drud,
750
751 .tables = {&pd_drudfin_noE_sym16_drud},
752 .ntables = 1,
753};
754
755Step
756drudfin_drud = {
757 .shortname = "drudfin",
758 .name = "DR finish on U/D without breaking DR",
759
760 .final = true,
761 .is_done = is_solved,
762 .estimate = estimate_drudfin_drud,
763 .ready = check_drud,
764 .ready_msg = check_dr_msg,
765 .is_valid = always_valid,
766 .moveset = &moveset_drud,
767
768 .pre_trans = uf,
769
770 .tables = {&pd_drudfin_noE_sym16_drud},
771 .ntables = 1,
772};
773
774Step
775drrlfin_drrl = {
776 .shortname = "drrlfin",
777 .name = "DR finish on R/L without breaking DR",
778
779 .final = true,
780 .is_done = is_solved,
781 .estimate = estimate_drudfin_drud,
782 .ready = check_drud,
783 .ready_msg = check_dr_msg,
784 .is_valid = always_valid,
785 .moveset = &moveset_drud,
786
787 .pre_trans = rf,
788
789 .tables = {&pd_drudfin_noE_sym16_drud},
790 .ntables = 1,
791};
792
793Step
794drfbfin_drfb = {
795 .shortname = "drfbfin",
796 .name = "DR finish on F/B without breaking DR",
797
798 .final = true,
799 .is_done = is_solved,
800 .estimate = estimate_drudfin_drud,
801 .ready = check_drud,
802 .ready_msg = check_dr_msg,
803 .is_valid = always_valid,
804 .moveset = &moveset_drud,
805
806 .pre_trans = fd,
807
808 .tables = {&pd_drudfin_noE_sym16_drud},
809 .ntables = 1,
810};
811
812/* HTR from DR */
813Step
814htr_any = {
815 .shortname = "htr",
816 .name = "HTR from DR",
817
818 .final = false,
819 .is_done = check_htr,
820 .estimate = estimate_htr_drud,
821 .ready = check_drud,
822 .ready_msg = check_drany_msg,
823 .is_valid = validate_singlecw_ending,
824 .moveset = &moveset_drud,
825
826 .detect = detect_pretrans_drud,
827
828 .tables = {&pd_htr_drud},
829 .ntables = 1,
830};
831
832Step
833htr_drud = {
834 .shortname = "htr-drud",
835 .name = "HTR from DR on U/D",
6 836
7bool 837 .final = false,
8check_centers(Cube *cube) 838 .is_done = check_htr,
839 .estimate = estimate_htr_drud,
840 .ready = check_drud,
841 .ready_msg = check_dr_msg,
842 .is_valid = validate_singlecw_ending,
843 .moveset = &moveset_drud,
844
845 .pre_trans = uf,
846
847 .tables = {&pd_htr_drud},
848 .ntables = 1,
849};
850
851Step
852htr_drrl = {
853 .shortname = "htr-drrl",
854 .name = "HTR from DR on R/L",
855
856 .final = false,
857 .is_done = check_htr,
858 .estimate = estimate_htr_drud,
859 .ready = check_drud,
860 .ready_msg = check_dr_msg,
861 .is_valid = validate_singlecw_ending,
862 .moveset = &moveset_drud,
863
864 .pre_trans = rf,
865
866 .tables = {&pd_htr_drud},
867 .ntables = 1,
868};
869
870Step
871htr_drfb = {
872 .shortname = "htr-drfb",
873 .name = "HTR from DR on F/B",
874
875 .final = false,
876 .is_done = check_htr,
877 .estimate = estimate_htr_drud,
878 .ready = check_drud,
879 .ready_msg = check_dr_msg,
880 .is_valid = validate_singlecw_ending,
881 .moveset = &moveset_drud,
882
883 .pre_trans = fd,
884
885 .tables = {&pd_htr_drud},
886 .ntables = 1,
887};
888
889/* HTR finish */
890Step
891htrfin_htr = {
892 .shortname = "htrfin",
893 .name = "HTR finish without breaking HTR",
894
895 .final = true,
896 .is_done = is_solved,
897 .estimate = estimate_htrfin_htr,
898 .ready = check_htr,
899 .ready_msg = check_htr_msg,
900 .is_valid = always_valid,
901 .moveset = &moveset_htr,
902
903 .pre_trans = uf,
904
905 .tables = {&pd_htrfin_htr},
906 .ntables = 1,
907};
908
909Step *steps[] = {
910 &optimal_HTM, /* first is default */
911 &optimal_light_HTM,
912
913 &eofin_eo,
914 &eofbfin_eofb,
915 &eorlfin_eorl,
916 &eoudfin_eoud,
917
918 &eoany_HTM,
919 &eofb_HTM,
920 &eorl_HTM,
921 &eoud_HTM,
922
923 &coany_HTM,
924 &coud_HTM,
925 &corl_HTM,
926 &cofb_HTM,
927
928 &coany_URF,
929 &coud_URF,
930 &corl_URF,
931 &cofb_URF,
932
933 &drany_HTM,
934 &drud_HTM,
935 &drrl_HTM,
936 &drfb_HTM,
937
938 &dr_eo,
939 &dr_eofb,
940 &dr_eorl,
941 &dr_eoud,
942 &drud_eofb,
943 &drrl_eofb,
944 &drud_eorl,
945 &drfb_eorl,
946 &drfb_eoud,
947 &drrl_eoud,
948
949 &dranyfin_DR,
950 &drudfin_drud,
951 &drrlfin_drrl,
952 &drfbfin_drfb,
953
954 &htr_any,
955 &htr_drud,
956 &htr_drrl,
957 &htr_drfb,
958
959 &htrfin_htr,
960
961 &cornershtr_HTM,
962 &cornershtr_URF,
963 &corners_HTM,
964 &corners_URF,
965
966 NULL
967};
968
969/* Checkers, estimators and validators ***************************************/
970
971static bool
972check_centers(Cube cube)
9{ 973{
10 int i; 974 return cube.cpos == 0;
975}
11 976
12 for (i = 0; i < 6; i++) 977static bool
13 if (cube->xp[i] != i) 978check_coud_HTM(Cube cube)
14 return false; 979{
980 return cube.coud == 0;
981}
15 982
16 return true; 983static bool
984check_coud_URF(Cube cube)
985{
986 Cube c2, c3;
987
988 c2 = apply_move(z, cube);
989 c3 = apply_move(x, cube);
990
991 return cube.coud == 0 || c2.coud == 0 || c3.coud == 0;
17} 992}
18 993
19bool 994static bool
20check_coud_HTM(Cube *cube) 995check_corners_URF(Cube cube)
21{ 996{
22 int i; 997 Cube c;
998 Trans i;
23 999
24 for (i = 0; i < 8; i++) 1000 for (i = 0; i < NROTATIONS; i++) {
25 if (cube->co[i] != 0) 1001 c = apply_alg(rotation_alg(i), cube);
26 return false; 1002 if (c.cp && c.coud)
1003 return true;
1004 }
27 1005
28 return true; 1006 return false;
29} 1007}
30 1008
31bool 1009static bool
32check_coud_URF(Cube *cube) 1010check_corners_HTM(Cube cube)
33{ 1011{
34 Cube c2, c3; 1012 return cube.cp == 0 && cube.coud == 0;
1013}
35 1014
36 copy_cube(cube, &c2); 1015static bool
37 copy_cube(cube, &c3); 1016check_cornershtr(Cube cube)
1017{
1018 return coord_cornershtr.index(cube) == 0;
1019}
38 1020
39 apply_move(z, &c2); 1021static bool
40 apply_move(x, &c3); 1022check_eofb(Cube cube)
1023{
1024 return cube.eofb == 0;
1025}
41 1026
42 return check_coud_HTM(cube) || 1027static bool
43 check_coud_HTM(&c2) || 1028check_drud(Cube cube)
44 check_coud_HTM(&c3); 1029{
1030 return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0;
45} 1031}
46 1032
47bool 1033static bool
48check_cp_HTM(Cube *cube) 1034check_htr(Cube cube)
49{ 1035{
50 int i; 1036 return check_drud(cube) && coord_htr_drud.index(cube) == 0;
1037}
1038
1039static int
1040estimate_eofb_HTM(DfsArg *arg)
1041{
1042 return ptableval(&pd_eofb_HTM, arg->cube);
1043}
1044
1045static int
1046estimate_coud_HTM(DfsArg *arg)
1047{
1048 return ptableval(&pd_coud_HTM, arg->cube);
1049}
51 1050
52 for (i = 0; i < 8; i++) 1051static int
53 if (cube->cp[i] != i) 1052estimate_coud_URF(DfsArg *arg)
54 return false; 1053{
1054 /* TODO: I can improve this by checking first the orientation of
1055 * the corner in DBL and use that as a reference */
55 1056
56 return true; 1057 Cube c;
1058
1059 c = arg->cube;
1060
1061 int ud = estimate_coud_HTM(arg);
1062 arg->cube = apply_move(z, c);
1063 int rl = estimate_coud_HTM(arg);
1064 arg->cube = apply_move(x, c);
1065 int fb = estimate_coud_HTM(arg);
1066
1067 arg->cube = c;
1068
1069 return MIN(ud, MIN(rl, fb));
57} 1070}
58 1071
59bool 1072static int
60check_corners_HTM(Cube *cube) 1073estimate_corners_HTM(DfsArg *arg)
61{ 1074{
62 return check_coud_HTM(cube) && check_cp_HTM(cube); 1075 return ptableval(&pd_corners_HTM, arg->cube);
63} 1076}
64 1077
65bool 1078static int
66check_corners_URF(Cube *cube) 1079estimate_cornershtr_HTM(DfsArg *arg)
67{ 1080{
1081 return ptableval(&pd_cornershtr_HTM, arg->cube);
1082}
1083
1084static int
1085estimate_cornershtr_URF(DfsArg *arg)
1086{
1087 /* TODO: I can improve this by checking first the corner in DBL
1088 * and use that as a reference */
1089
1090 int ret;
68 Cube c; 1091 Cube c;
69 Trans i; 1092 Trans i;
70 1093
1094 c = arg->cube;
1095 ret = 15;
1096
71 for (i = 0; i < NROTATIONS; i++) { 1097 for (i = 0; i < NROTATIONS; i++) {
72 copy_cube(cube, &c); 1098 arg->cube = apply_alg(rotation_alg(i), c);
73 apply_alg(rotation_alg(i), &c); 1099 ret = MIN(ret, estimate_cornershtr_HTM(arg));
74 if (check_corners_HTM(&c))
75 return true;
76 } 1100 }
77 1101
78 return false; 1102 arg->cube = c;
1103
1104 return ret;
79} 1105}
80 1106
81bool 1107static int
82check_cornershtr(Cube *cube) 1108estimate_corners_URF(DfsArg *arg)
83{ 1109{
84 /* TODO (use coord) */ 1110 /* TODO: I can improve this by checking first the corner in DBL
85 return true; 1111 * and use that as a reference */
1112
1113 int ret;
1114 Cube c;
1115 Trans i;
1116
1117 c = arg->cube;
1118 ret = 15;
1119
1120 for (i = 0; i < NROTATIONS; i++) {
1121 arg->cube = apply_alg(rotation_alg(i), c);
1122 ret = MIN(ret, estimate_corners_HTM(arg));
1123 }
1124
1125 arg->cube = c;
1126
1127 return ret;
86} 1128}
87 1129
88bool 1130static int
89check_eofb(Cube *cube) 1131estimate_drud_HTM(DfsArg *arg)
90{ 1132{
91 /* TODO (use coord) */ 1133 return ptableval(&pd_drud_sym16_HTM, arg->cube);
92 return true;
93} 1134}
94 1135
95bool 1136static int
96check_drud(Cube *cube) 1137estimate_drud_eofb(DfsArg *arg)
97{ 1138{
98 /* TODO (use coord) */ 1139 return ptableval(&pd_drud_eofb, arg->cube);
99 return true;
100} 1140}
101 1141
102bool 1142static int
103check_htr(Cube *cube) 1143estimate_dr_eofb(DfsArg *arg)
1144{
1145 int r1, r2;
1146
1147 r1 = ptableval(&pd_drud_eofb, arg->cube);
1148 r2 = ptableval(&pd_drud_eofb, apply_trans(rf, arg->cube));
1149
1150 return MIN(r1, r2);
1151}
1152
1153static int
1154estimate_drudfin_drud(DfsArg *arg)
1155{
1156 int val = ptableval(&pd_drudfin_noE_sym16_drud, arg->cube);
1157
1158 if (val != 0)
1159 return val;
1160
1161 return arg->cube.epose % 24 == 0 ? 0 : 1;
1162}
1163
1164static int
1165estimate_htr_drud(DfsArg *arg)
1166{
1167 return ptableval(&pd_htr_drud, arg->cube);
1168}
1169
1170static int
1171estimate_htrfin_htr(DfsArg *arg)
1172{
1173 return ptableval(&pd_htrfin_htr, arg->cube);
1174}
1175
1176static int
1177estimate_nxopt31_HTM(DfsArg *arg)
1178{
1179 return estimate_nxoptlike(arg, &pd_nxopt31_HTM);
1180}
1181
1182/* TODO: also use generic procedure for this */
1183static int
1184estimate_light_HTM(DfsArg *arg)
1185{
1186 int target, ret;
1187 Cube aux;
1188
1189 static const uint64_t udmask = (1<<U) | (1<<U2) | (1<<U3) |
1190 (1<<D) | (1<<D2) | (1<<D3);
1191 static const uint64_t rlmask = (1<<R) | (1<<R2) | (1<<R3) |
1192 (1<<L) | (1<<L2) | (1<<L3);
1193 static const uint64_t fbmask = (1<<F) | (1<<F2) | (1<<F3) |
1194 (1<<B) | (1<<B2) | (1<<B3);
1195 static const uint64_t htmask = (1<<U2) | (1<<D2) |
1196 (1<<R2) | (1<<L2) |
1197 (1<<F2) | (1<<B2);
1198
1199 ret = -1;
1200 target = arg->d - arg->current_alg->len;
1201 arg->inverse = (Cube){0};
1202 arg->badmovesinv = 0;
1203 arg->badmoves = 0;
1204
1205 /* Corners */
1206 arg->ed->corners = ptableval(&pd_corners_HTM, arg->cube);
1207 UPDATECHECKSTOP(ret, arg->ed->corners, target);
1208
1209 /* Normal probing */
1210 arg->ed->normal_ud = ptableval(&pd_drud_sym16_HTM, arg->cube);
1211 UPDATECHECKSTOP(ret, arg->ed->normal_ud, target);
1212 aux = apply_trans(fd, arg->cube);
1213 arg->ed->normal_fb = ptableval(&pd_drud_sym16_HTM, aux);
1214 UPDATECHECKSTOP(ret, arg->ed->normal_fb, target);
1215 aux = apply_trans(rf, arg->cube);
1216 arg->ed->normal_rl = ptableval(&pd_drud_sym16_HTM, aux);
1217 UPDATECHECKSTOP(ret, arg->ed->normal_rl, target);
1218
1219 /* If ret == 0, it's solved (corners + triple slice solved) */
1220 if (ret == 0)
1221 return is_solved(arg->cube) ? 0 : 1;
1222
1223 /* Michel de Bondt's trick*/
1224 if (arg->ed->normal_ud == arg->ed->normal_fb &&
1225 arg->ed->normal_fb == arg->ed->normal_rl) {
1226 UPDATECHECKSTOP(ret, arg->ed->normal_ud + 1, target);
1227 }
1228
1229 /* Inverse probing */
1230 if (!((1<<arg->last1) & htmask)) {
1231 aux = arg->inverse = inverse_cube(arg->cube);
1232 if (!((1<<arg->last1) & udmask) || (arg->ed->inverse_ud==-1)) {
1233 arg->ed->inverse_ud =
1234 ptableval(&pd_drud_sym16_HTM, aux);
1235 }
1236 UPDATECHECKSTOP(ret, arg->ed->inverse_ud, target);
1237 if (!((1<<arg->last1) & fbmask) || (arg->ed->inverse_fb==-1)) {
1238 aux = apply_trans(fd, arg->inverse);
1239 arg->ed->inverse_fb =
1240 ptableval(&pd_drud_sym16_HTM, aux);
1241 }
1242 UPDATECHECKSTOP(ret, arg->ed->inverse_fb, target);
1243 if (!((1<<arg->last1) & rlmask) || (arg->ed->inverse_rl==-1)) {
1244 aux = apply_trans(rf, arg->inverse);
1245 arg->ed->inverse_rl =
1246 ptableval(&pd_drud_sym16_HTM, aux);
1247 }
1248 UPDATECHECKSTOP(ret, arg->ed->inverse_rl, target);
1249 } else {
1250 UPDATECHECKSTOP(ret, arg->ed->inverse_ud, target);
1251 UPDATECHECKSTOP(ret, arg->ed->inverse_fb, target);
1252 UPDATECHECKSTOP(ret, arg->ed->inverse_rl, target);
1253 }
1254
1255 /* Michel de Bondt's trick*/
1256 if (arg->ed->inverse_ud == arg->ed->inverse_fb &&
1257 arg->ed->inverse_fb == arg->ed->inverse_rl) {
1258 UPDATECHECKSTOP(ret, arg->ed->inverse_ud + 1, target);
1259 }
1260
1261 /* nxopt trick + half turn trick */
1262 if (arg->ed->normal_ud == target)
1263 arg->badmovesinv |= udmask | htmask;
1264 if (arg->ed->normal_fb == target)
1265 arg->badmovesinv |= fbmask | htmask;
1266 if (arg->ed->normal_rl == target)
1267 arg->badmovesinv |= rlmask | htmask;
1268
1269 if (arg->ed->inverse_ud == target)
1270 arg->badmoves |= udmask | htmask;
1271 if (arg->ed->inverse_fb == target)
1272 arg->badmoves |= fbmask | htmask;
1273 if (arg->ed->inverse_rl == target)
1274 arg->badmoves |= rlmask | htmask;
1275
1276 return arg->ed->oldret = ret;
1277}
1278
1279static int
1280estimate_nxoptlike(DfsArg *arg, PruneData *pd)
1281{
1282 int target, ret;
1283 Cube aux;
1284
1285 static const uint64_t udmask = (1<<U) | (1<<U2) | (1<<U3) |
1286 (1<<D) | (1<<D2) | (1<<D3);
1287 static const uint64_t rlmask = (1<<R) | (1<<R2) | (1<<R3) |
1288 (1<<L) | (1<<L2) | (1<<L3);
1289 static const uint64_t fbmask = (1<<F) | (1<<F2) | (1<<F3) |
1290 (1<<B) | (1<<B2) | (1<<B3);
1291
1292 ret = -1;
1293 target = arg->d - arg->current_alg->len;
1294 arg->inverse = (Cube){0};
1295 arg->badmovesinv = 0;
1296 arg->badmoves = 0;
1297
1298 /* Corners */
1299 arg->ed->corners = ptableval(&pd_corners_HTM, arg->cube);
1300 UPDATECHECKSTOP(ret, arg->ed->corners, target);
1301
1302 /* Normal probing */
1303 arg->ed->normal_ud = ptableval(pd, arg->cube);
1304 UPDATECHECKSTOP(ret, arg->ed->normal_ud, target);
1305 aux = apply_trans(fd, arg->cube);
1306 arg->ed->normal_fb = ptableval(pd, aux);
1307 UPDATECHECKSTOP(ret, arg->ed->normal_fb, target);
1308 aux = apply_trans(rf, arg->cube);
1309 arg->ed->normal_rl = ptableval(pd, aux);
1310 UPDATECHECKSTOP(ret, arg->ed->normal_rl, target);
1311
1312 if (ret == 0)
1313 return arg->step->is_done(arg->cube) ? 0 : 1;
1314
1315 /* Michel de Bondt's trick*/
1316 if (arg->ed->normal_ud == arg->ed->normal_fb &&
1317 arg->ed->normal_fb == arg->ed->normal_rl) {
1318 UPDATECHECKSTOP(ret, arg->ed->normal_ud + 1, target);
1319 }
1320
1321 /* Inverse probing */
1322 aux = arg->inverse = inverse_cube(arg->cube);
1323 if (!((1<<arg->last1) & udmask) || (arg->ed->inverse_ud == -1)) {
1324 arg->ed->inverse_ud = ptableval(pd, aux);
1325 }
1326 UPDATECHECKSTOP(ret, arg->ed->inverse_ud, target);
1327 if (!((1<<arg->last1) & fbmask) || (arg->ed->inverse_fb == -1)) {
1328 aux = apply_trans(fd, arg->inverse);
1329 arg->ed->inverse_fb = ptableval(pd, aux);
1330 }
1331 UPDATECHECKSTOP(ret, arg->ed->inverse_fb, target);
1332 if (!((1<<arg->last1) & rlmask) || (arg->ed->inverse_rl == -1)) {
1333 aux = apply_trans(rf, arg->inverse);
1334 arg->ed->inverse_rl = ptableval(pd, aux);
1335 }
1336 UPDATECHECKSTOP(ret, arg->ed->inverse_rl, target);
1337
1338 /* Michel de Bondt's trick*/
1339 if (arg->ed->inverse_ud == arg->ed->inverse_fb &&
1340 arg->ed->inverse_fb == arg->ed->inverse_rl) {
1341 UPDATECHECKSTOP(ret, arg->ed->inverse_ud + 1, target);
1342 }
1343
1344 /* nxopt trick */
1345 if (arg->ed->normal_ud == target)
1346 arg->badmovesinv |= udmask;
1347 if (arg->ed->normal_fb == target)
1348 arg->badmovesinv |= fbmask;
1349 if (arg->ed->normal_rl == target)
1350 arg->badmovesinv |= rlmask;
1351
1352 if (arg->ed->inverse_ud == target)
1353 arg->badmoves |= udmask;
1354 if (arg->ed->inverse_fb == target)
1355 arg->badmoves |= fbmask;
1356 if (arg->ed->inverse_rl == target)
1357 arg->badmoves |= rlmask;
1358
1359 return arg->ed->oldret = ret;
1360}
1361
1362
1363static bool
1364always_valid(Alg *alg)
104{ 1365{
105 /* TODO (check_drud(cube) and coord_htr_drud == 0) */
106 return true; 1366 return true;
107} 1367}
108 1368
109Alg * 1369static bool
110validate_singlecw_ending(Alg *alg) 1370validate_singlecw_ending(Alg *alg)
111{ 1371{
112 int i; 1372 int i;
113 bool nor, inv; 1373 bool nor, inv;
114 Alg *ret;
115 Move l2 = NULLMOVE, l1 = NULLMOVE, l2i = NULLMOVE, l1i = NULLMOVE; 1374 Move l2 = NULLMOVE, l1 = NULLMOVE, l2i = NULLMOVE, l1i = NULLMOVE;
116 1375
117 for (i = 0; i < alg->len; i++) { 1376 for (i = 0; i < alg->len; i++) {
@@ -127,51 +1386,96 @@ validate_singlecw_ending(Alg *alg)
127 nor = l1 ==base_move(l1) && (!commute(l1, l2) ||l2 ==base_move(l2)); 1386 nor = l1 ==base_move(l1) && (!commute(l1, l2) ||l2 ==base_move(l2));
128 inv = l1i==base_move(l1i) && (!commute(l1i,l2i)||l2i==base_move(l2i)); 1387 inv = l1i==base_move(l1i) && (!commute(l1i,l2i)||l2i==base_move(l2i));
129 1388
130 if (nor && inv) { 1389 return nor && inv;
131 ret = new_alg(""); 1390}
132 copy_alg(alg, ret);
133 } else {
134 ret = NULL;
135 }
136 1391
137 return ret; 1392/* Pre-transformation detectors **********************************************/
1393
1394static int
1395detect_pretrans_eofb(Cube cube, Trans *ret)
1396{
1397 int i, n;
1398 static Trans tt[3] = {uf, ur, fd};
1399
1400 for (i = 0, n = 0; i < 3; i++)
1401 if (check_eofb(apply_trans(tt[i], cube)))
1402 ret[n++] = tt[i];
1403
1404 return n;
1405}
1406
1407static int
1408detect_pretrans_drud(Cube cube, Trans *ret)
1409{
1410 int i, n;
1411 static Trans tt[3] = {uf, fr, rd};
1412
1413 for (i = 0, n = 0; i < 3; i++)
1414 if (check_drud(apply_trans(tt[i], cube)))
1415 ret[n++] = tt[i];
1416
1417 return n;
1418}
1419
1420static int
1421detect_pretrans_void_3axis(Cube cube, Trans *ret)
1422{
1423 ret[0] = uf;
1424 ret[1] = fr;
1425 ret[2] = rd;
1426
1427 return 3;
138} 1428}
139 1429
140/* Public functions **********************************************************/ 1430/* Public functions **********************************************************/
141 1431
142/*
143void 1432void
144compute_ind(Step *s, Cube *cube, Movable *ind) 1433copy_estimatedata(EstimateData *src, EstimateData *dst)
145{ 1434{
146 int i; 1435 dst->corners = src->corners;
147 Cube mvd; 1436 dst->normal_ud = src->normal_ud;
148 Trans t, tt; 1437 dst->normal_fb = src->normal_fb;
1438 dst->normal_rl = src->normal_rl;
1439 dst->inverse_ud = src->inverse_ud;
1440 dst->inverse_fb = src->inverse_fb;
1441 dst->inverse_rl = src->inverse_rl;
1442 dst->oldret = src->oldret;
1443}
149 1444
150 for (i = 0; i < s->n_coord; i++) { 1445void
151 t = s->coord_trans[i]; 1446invert_estimatedata(EstimateData *ed)
152 copy_cube(cube, &mvd); 1447{
153 apply_trans(t, &mvd); 1448 swap(&(ed->normal_ud), &(ed->inverse_ud));
1449 swap(&(ed->normal_fb), &(ed->inverse_fb));
1450 swap(&(ed->normal_rl), &(ed->inverse_rl));
1451}
154 1452
155 ind[i].val = index_coord(s->coord[i], &mvd, &tt); 1453void
156 ind[i].t = transform_trans(tt, t); 1454reset_estimatedata(EstimateData *ed)
157 } 1455{
1456 ed->corners = -1;
1457 ed->normal_ud = -1;
1458 ed->normal_fb = -1;
1459 ed->normal_rl = -1;
1460 ed->inverse_ud = -1;
1461 ed->inverse_fb = -1;
1462 ed->inverse_rl = -1;
1463 ed->oldret = -1;
158} 1464}
159*/
160 1465
161void 1466void
162prepare_cs(ChoiceStep *cs, SolveOptions *opts) 1467prepare_step(Step *step, SolveOptions *opts)
163{ 1468{
164 int i, j; 1469 int i;
165 Step *s;
166 1470
167 for (i = 0; cs->step[i] != NULL; i++) { 1471 if (step->final && opts->can_niss) {
168 s = cs->step[i]; 1472 opts->can_niss = false;
169 for (j = 0; j < s->n_coord; j++) { 1473 fprintf(stderr, "Step is final, NISS not used (-n ignored)\n");
170 s->pd[j] = malloc(sizeof(PruneData)); 1474 }
171 s->pd[j]->moveset = s->moveset; 1475
172 s->pd[j]->coord = s->coord[j]; 1476 for (i = 0; i < step->ntables; i++) {
173 s->pd[j]->compact = s->pd_compact[j]; 1477 genptable(step->tables[i], opts->nthreads);
174 s->pd[j] = genptable(s->pd[j], opts->nthreads); 1478 if (step->tables[i]->compact)
175 } 1479 genptable(step->tables[i]->fallback, opts->nthreads);
176 } 1480 }
177} 1481}
diff --git a/src/steps.h b/src/steps.h
index 206f8b4..da5c041 100644
--- a/src/steps.h
+++ b/src/steps.h
@@ -2,243 +2,16 @@
2#define STEPS_H 2#define STEPS_H
3 3
4#include "pruning.h" 4#include "pruning.h"
5#include "movesets.h"
6 5
7bool check_centers(Cube *cube); 6extern Step * steps[];
8bool check_coud_HTM(Cube *cube);
9bool check_coud_URF(Cube *cube);
10bool check_cp_HTM(Cube *cube);
11bool check_corners_HTM(Cube *cube);
12bool check_corners_URF(Cube *cube);
13bool check_cornershtr(Cube *cube);
14bool check_eofb(Cube *cube);
15bool check_drud(Cube *cube);
16bool check_htr(Cube *cube);
17/*void compute_ind(Step *a, Cube *cube, Movable *ind);*/
18void prepare_cs(ChoiceStep *cs, SolveOptions *opts);
19bool always_valid(Alg *alg);
20Alg * validate_singlecw_ending(Alg *alg);
21 7
22#ifndef STEPS_C 8/* Two steps used directly by two-phase solver */
9extern Step drany_HTM;
10extern Step dranyfin_DR;
23 11
24extern char check_centers_msg[100]; 12void copy_estimatedata(EstimateData *s, EstimateData *d);
25extern char check_eo_msg[100]; 13void invert_estimatedata(EstimateData *ed);
26extern char check_dr_msg[100]; 14void reset_estimatedata(EstimateData *ed);
27extern char check_htr_msg[100]; 15void prepare_step(Step *step, SolveOptions *opts);
28extern char check_drany_msg[100];
29
30extern Step step_eofb_HTM;
31extern Step step_drud_HTM;
32extern Step step_drfin_drud;
33
34extern ChoiceStep optimal_HTM;
35extern ChoiceStep eoany_HTM;
36extern ChoiceStep eofb_HTM;
37extern ChoiceStep eorl_HTM;
38extern ChoiceStep eoud_HTM;
39extern ChoiceStep drany_HTM;
40extern ChoiceStep drud_HTM;
41extern ChoiceStep drrl_HTM;
42extern ChoiceStep drfb_HTM;
43extern ChoiceStep dranyfin_DR;
44extern ChoiceStep drudfin_drud;
45extern ChoiceStep drrlfin_drrl;
46extern ChoiceStep drfbfin_drfb;
47
48extern ChoiceStep *csteps[];
49
50#else
51
52char check_centers_msg[100] = "cube must be oriented (centers solved)";
53char check_eo_msg[100] = "EO must be solved on given axis";
54char check_dr_msg[100] = "DR must be solved on given axis";
55char check_htr_msg[100] = "HTR must be solved";
56char check_drany_msg[100] = "DR must be solved on at least one axis";
57
58/* Optimal after EO ******************/
59/* TODO: eofin_eo (generic), eofbfin_eofb, eorlfin_eorl, eoudfin_eoud */
60
61/* EO steps **************************/
62/* TODO: eoany_HTM (generic), eofb_HTM, eorl_HTM, eoud_HTM */
63
64Step
65step_eofb_HTM = {
66 .ready = check_centers,
67 .final = false,
68 .moveset = &moveset_HTM,
69 .n_coord = 1,
70 .coord = {&coord_eofb},
71 .coord_trans = {uf},
72 .is_valid = validate_singlecw_ending,
73};
74ChoiceStep
75eoany_HTM = {
76 .shortname = "eo",
77 .name = "EO on any axis",
78 .step = {&step_eofb_HTM, &step_eofb_HTM, &step_eofb_HTM, NULL},
79 .t = {uf, ur, fd},
80 .ready_msg = check_centers_msg,
81};
82ChoiceStep
83eofb_HTM = {
84 .shortname = "eofb",
85 .name = "EO on F/B",
86 .step = {&step_eofb_HTM, NULL},
87 .t = {uf},
88 .ready_msg = check_centers_msg,
89};
90ChoiceStep
91eorl_HTM = {
92 .shortname = "eorl",
93 .name = "EO on R/L",
94 .step = {&step_eofb_HTM, NULL},
95 .t = {ur},
96 .ready_msg = check_centers_msg,
97};
98ChoiceStep
99eoud_HTM = {
100 .shortname = "eoud",
101 .name = "EO on U/D",
102 .step = {&step_eofb_HTM, NULL},
103 .t = {fd},
104 .ready_msg = check_centers_msg,
105};
106
107/* CO steps **************************/
108/* TODO: coany_HTM (generic), cofb_HTM, corl_HTM, coud_HTM */
109/* TODO: coany_URF (generic), cofb_URF, corl_URF, coud_URF */
110
111/* Misc corner steps *****************/
112/* TODO: cornershtr_HTM, cornershtr_URF, corners_HTM, corners_URF */
113/* TODO (new): corners_drud */
114
115/* DR steps **************************/
116/* TODO: dr_eo (generic) */
117/* TODO: dr_eofb (generic), dr_eorl (generic), dr_eoud (generic) */
118/* TODO: drud_eofb, drrl_eofb, drud_eorl, drfb_eorl, drrl_eoud, drfb_eoud */
119
120Step
121step_drud_HTM = {
122 .ready = check_centers,
123 .final = false,
124 .moveset = &moveset_HTM,
125 .n_coord = 1,
126 .coord = {&coord_drud_sym16},
127 .coord_trans = {uf},
128 .is_valid = validate_singlecw_ending,
129};
130ChoiceStep
131drany_HTM = {
132 .shortname = "dr",
133 .name = "DR on any axis",
134 .step = {&step_drud_HTM, &step_drud_HTM, &step_drud_HTM, NULL},
135 .t = {uf, rf, fd},
136 .ready_msg = check_centers_msg,
137};
138ChoiceStep
139drud_HTM = {
140 .shortname = "drud",
141 .name = "DR on U/D",
142 .step = {&step_drud_HTM, NULL},
143 .t = {uf},
144 .ready_msg = check_centers_msg,
145};
146ChoiceStep
147drrl_HTM = {
148 .shortname = "drrl",
149 .name = "DR on R/L",
150 .step = {&step_drud_HTM, NULL},
151 .t = {rf},
152 .ready_msg = check_centers_msg,
153};
154ChoiceStep
155drfb_HTM = {
156 .shortname = "drfb",
157 .name = "DR on F/B",
158 .step = {&step_drud_HTM, NULL},
159 .t = {fd},
160 .ready_msg = check_centers_msg,
161};
162
163/* DR finish steps */
164Step
165step_drfin_drud = {
166 .ready = check_drud,
167 .final = true,
168 .moveset = &moveset_drud,
169 .n_coord = 1,
170 .coord = {&coord_drudfin_noE_sym16}, /* TODO: maybe no noE */
171 .coord_trans = {uf},
172 .is_valid = NULL,
173};
174ChoiceStep
175dranyfin_DR = {
176 .shortname = "drfin",
177 .name = "DR finish on any axis without breaking DR",
178 .step = {&step_drfin_drud, &step_drfin_drud,
179 &step_drfin_drud, NULL},
180 .t = {uf, rf, fd},
181 .ready_msg = check_dr_msg,
182};
183ChoiceStep
184drudfin_drud = {
185 .shortname = "drudfin",
186 .name = "DR finis on U/D without breaking DR",
187 .step = {&step_drfin_drud, NULL},
188 .t = {uf},
189 .ready_msg = check_dr_msg,
190};
191ChoiceStep
192drrlfin_drrl = {
193 .shortname = "drrlfin",
194 .name = "DR finish on R/L without breaking DR",
195 .step = {&step_drfin_drud, NULL},
196 .t = {rf},
197 .ready_msg = check_dr_msg,
198};
199ChoiceStep
200drfbfin_drfb = {
201 .shortname = "drfbfin",
202 .name = "DR finish on F/B without breaking DR",
203 .step = {&step_drfin_drud, NULL},
204 .t = {fd},
205 .ready_msg = check_dr_msg,
206};
207
208/* HTR from DR */
209/* TODO: htr_any (generic), htr_drud, htr_drrl, htr_drfb */
210
211/* HTR finish */
212/* TODO: htrfin_htr */
213
214ChoiceStep *csteps[] = {
215/* TODO: re-implement optimal
216 &optimal_HTM,
217*/
218
219 &eoany_HTM, &eofb_HTM, &eorl_HTM, &eoud_HTM,
220 &drany_HTM, &drud_HTM, &drrl_HTM, &drfb_HTM,
221 &dranyfin_DR, &drudfin_drud, &drrlfin_drrl, &drfbfin_drfb,
222
223NULL
224/* TODO:
225 &optimal_light_HTM,
226
227 &eofin_eo, &eofbfin_eofb, &eorlfin_eorl, &eoudfin_eoud,
228 &coany_HTM, &coud_HTM, &corl_HTM, &cofb_HTM,
229 &coany_URF, &coud_URF, &corl_URF, &cofb_URF,
230 &dr_eo, &dr_eofb, &dr_eorl, &dr_eoud,
231 &drud_eofb, &drrl_eofb,
232 &drud_eorl, &drfb_eorl,
233 &drfb_eoud, &drrl_eoud,
234 &htr_any, &htr_drud, &htr_drrl, &htr_drfb,
235 &htrfin_htr,
236 &cornershtr_HTM, &cornershtr_URF, &corners_HTM, &corners_URF,
237 NULL
238*/
239
240};
241
242#endif
243 16
244#endif 17#endif
diff --git a/src/symcoord.c b/src/symcoord.c
new file mode 100644
index 0000000..20d7c28
--- /dev/null
+++ b/src/symcoord.c
@@ -0,0 +1,687 @@
1#include "symcoord.h"
2
3/* These constants have been computed generating the respective SymData */
4#define CLASSES_CP_16 2768
5#define CLASSES_EOFBEPOS_16 64430
6
7static uint64_t index_cp_sym16(Cube cube);
8static uint64_t index_eofbepos_sym16(Cube cube);
9static uint64_t index_drud_sym16(Cube cube);
10static uint64_t index_drudfin_noE_sym16(Cube cube);
11static uint64_t index_nxopt31(Cube cube);
12
13static uint64_t move_cp_sym16(Move m, uint64_t ind);
14static uint64_t move_eofbepos_sym16(Move m, uint64_t ind);
15static uint64_t move_drud_sym16(Move m, uint64_t ind);
16static uint64_t move_drudfin_noE_sym16(Move m, uint64_t ind);
17static uint64_t move_nxopt31(Move m, uint64_t ind);
18
19static int tfind_from_mask(uint64_t mask, Trans *ret);
20static int tfind_drud_sym16(uint64_t ind, Trans *ret);
21static int tfind_drudfin_noE_sym16(uint64_t ind, Trans *ret);
22static int tfind_nxopt31(uint64_t ind, Trans *ret);
23
24static uint64_t transform_cp(Trans t, uint64_t ind);
25static uint64_t transform_eofbepos(Trans t, uint64_t ind);
26static uint64_t transform_drud_sym16(Trans t, uint64_t ind);
27static uint64_t transform_drudfin_noE_sym16(Trans t, uint64_t ind);
28static uint64_t transform_nxopt31(Trans t, uint64_t ind);
29
30static void gensym(SymData *sd);
31static void init_symc_moves();
32static void init_symc_trans();
33static bool read_symdata_file(SymData *sd);
34static bool read_symc_moves_file();
35static bool read_symc_trans_file();
36static bool write_symdata_file(SymData *sd);
37static bool write_symc_moves_file();
38static bool write_symc_trans_file();
39
40/* Some tables ***************************************************************/
41
42static uint64_t move_cp_16[NMOVES][CLASSES_CP_16];
43static uint64_t move_eofbepos_16[NMOVES][CLASSES_EOFBEPOS_16];
44
45static int trans_eofbepos[NTRANS][POW2TO11*BINOM12ON4];
46static int trans_epud[NTRANS][FACTORIAL8];
47static int trans_cpud_separate[NTRANS][BINOM8ON4];
48
49static Trans ttrep_move_cp_16[NMOVES][CLASSES_CP_16];
50static Trans ttrep_move_eofbepos_16[NMOVES][CLASSES_EOFBEPOS_16];
51
52
53/* Transformation groups and symmetry data ***********************************/
54
55static Trans
56trans_group_udfix[16] = {
57 uf, ur, ub, ul,
58 df, dr, db, dl,
59 uf_mirror, ur_mirror, ub_mirror, ul_mirror,
60 df_mirror, dr_mirror, db_mirror, dl_mirror,
61};
62
63static SymData
64sd_cp_16 = {
65 .filename = "sd_cp_16_new",
66 .coord = &coord_cp,
67 .sym_coord = &coord_cp_sym16,
68 .ntrans = 16,
69 .trans = trans_group_udfix,
70 .transform = transform_cp,
71};
72
73static SymData
74sd_eofbepos_16 = {
75 .filename = "sd_eofbepos_16_new",
76 .coord = &coord_eofbepos,
77 .sym_coord = &coord_eofbepos_sym16,
78 .ntrans = 16,
79 .trans = trans_group_udfix,
80 .transform = transform_eofbepos,
81};
82
83SymData * all_sd[] = {
84 &sd_cp_16,
85 &sd_eofbepos_16,
86 NULL
87};
88
89
90/* Coordinates and their implementation **************************************/
91
92Coordinate
93coord_eofbepos_sym16 = {
94 .index = index_eofbepos_sym16,
95 .move = move_eofbepos_sym16,
96};
97
98Coordinate
99coord_cp_sym16 = {
100 .index = index_cp_sym16,
101 .move = move_cp_sym16,
102};
103
104Coordinate
105coord_drud_sym16 = {
106 .index = index_drud_sym16,
107 .move = move_drud_sym16,
108 .max = POW3TO7 * CLASSES_EOFBEPOS_16,
109 .base = &coord_eofbepos_sym16,
110 .transform = transform_drud_sym16,
111 .tfind = tfind_drud_sym16,
112};
113
114Coordinate
115coord_drudfin_noE_sym16 = {
116 .index = index_drudfin_noE_sym16,
117 .move = move_drudfin_noE_sym16,
118 .max = FACTORIAL8 * CLASSES_CP_16,
119 .base = &coord_cp_sym16,
120 .transform = transform_drudfin_noE_sym16,
121 .tfind = tfind_drudfin_noE_sym16,
122};
123
124Coordinate
125coord_nxopt31 = {
126 .index = index_nxopt31,
127 .move = move_nxopt31,
128 .max = POW3TO7 * BINOM8ON4 * CLASSES_EOFBEPOS_16,
129 .base = &coord_eofbepos_sym16,
130 .transform = transform_nxopt31,
131 .tfind = tfind_nxopt31,
132};
133
134/* Functions *****************************************************************/
135
136static uint64_t
137index_cp_sym16(Cube cube)
138{
139 return sd_cp_16.class[coord_cp.index(cube)];
140}
141
142static uint64_t
143index_drud_sym16(Cube cube)
144{
145 Trans t;
146
147 t = sd_eofbepos_16.transtorep[coord_eofbepos.index(cube)];
148
149 return index_eofbepos_sym16(cube) * POW3TO7 + co_ttable[t][cube.coud];
150}
151
152static uint64_t
153index_drudfin_noE_sym16(Cube cube)
154{
155 Trans t;
156 Cube c;
157
158 t = sd_cp_16.transtorep[coord_cp.index(cube)];
159 c = apply_trans(t, cube);
160
161 /* TODO: add transform to coord_epud to make this faster */
162 return index_cp_sym16(c) * FACTORIAL8 + coord_epud.index(c);
163}
164
165static uint64_t
166index_eofbepos_sym16(Cube cube)
167{
168 return sd_eofbepos_16.class[coord_eofbepos.index(cube)];
169}
170
171static uint64_t
172index_nxopt31(Cube cube)
173{
174 Trans t;
175 uint64_t a;
176 int coud, cp;
177
178 t = sd_eofbepos_16.transtorep[coord_eofbepos.index(cube)];
179 coud = co_ttable[t][cube.coud];
180 cp = cp_ttable[t][cube.cp];
181 a = (index_eofbepos_sym16(cube)*POW3TO7) + coud;
182
183 return a * BINOM8ON4 + coord_cpud_separate.index((Cube){.cp = cp});
184}
185
186static uint64_t
187move_cp_sym16(Move m, uint64_t ind)
188{
189 return move_cp_16[m][ind];
190}
191
192static uint64_t
193move_eofbepos_sym16(Move m, uint64_t ind)
194{
195 return move_eofbepos_16[m][ind];
196}
197
198static uint64_t
199move_drud_sym16(Move m, uint64_t ind)
200{
201 uint64_t coud, eofbepos;
202 Trans ttr;
203
204 eofbepos = move_eofbepos_16[m][ind / POW3TO7];
205 ttr = ttrep_move_eofbepos_16[m][ind / POW3TO7];
206 coud = coud_mtable[m][ind % POW3TO7];
207 coud = co_ttable[ttr][coud]; /* Source is always coud */
208
209 return eofbepos * POW3TO7 + coud;
210}
211
212static uint64_t
213move_drudfin_noE_sym16(Move m, uint64_t ind)
214{
215 uint64_t cp, epud;
216 Trans ttr;
217
218 cp = move_cp_16[m][ind / FACTORIAL8];
219 ttr = ttrep_move_cp_16[m][ind / FACTORIAL8];
220 epud = coord_epud.move(m, ind % FACTORIAL8);
221 epud = trans_epud[ttr][epud];
222
223 return cp * FACTORIAL8 + epud;
224}
225
226static uint64_t
227move_nxopt31(Move m, uint64_t ind)
228{
229 uint64_t eofbepos, cpsep, coud;
230 Trans ttr;
231
232 eofbepos = ind / (POW3TO7 * BINOM8ON4);
233 coud = (ind / BINOM8ON4) % POW3TO7;
234 cpsep = ind % BINOM8ON4;
235
236 ttr = ttrep_move_eofbepos_16[m][eofbepos];
237 eofbepos = move_eofbepos_16[m][eofbepos];
238 coud = coud_mtable[m][coud];
239 coud = co_ttable[ttr][coud]; /* Source is always coud */
240 cpsep = coord_cpud_separate.move(m, cpsep);
241 cpsep = trans_cpud_separate[ttr][cpsep];
242
243 return (eofbepos * POW3TO7 + coud) * BINOM8ON4 + cpsep;
244}
245
246static uint64_t
247transform_cp(Trans t, uint64_t ind)
248{
249 return cp_ttable[t][ind];
250}
251
252static uint64_t
253transform_eofbepos(Trans t, uint64_t ind)
254{
255 return trans_eofbepos[t][ind];
256}
257
258static uint64_t
259transform_drud_sym16(Trans t, uint64_t ind)
260{
261 uint64_t coud, eofbepos;
262
263 eofbepos = ind / POW3TO7; /* Assum trans fixes eofbepos */
264 coud = co_ttable[t][ind % POW3TO7]; /* Source is always coud */
265
266 return eofbepos * POW3TO7 + coud;
267}
268
269static uint64_t
270transform_drudfin_noE_sym16(Trans t, uint64_t ind)
271{
272 uint64_t cp, epud;
273
274 cp = ind / FACTORIAL8; /* Assume trans fixes cp */
275 epud = trans_epud[t][ind % FACTORIAL8];
276
277 return cp * FACTORIAL8 + epud;
278}
279
280static uint64_t
281transform_nxopt31(Trans t, uint64_t ind)
282{
283 uint64_t eofbepos, cpsep, coud;
284
285 eofbepos = ind / (POW3TO7 * BINOM8ON4);
286 coud = (ind / BINOM8ON4) % POW3TO7;
287 cpsep = ind % BINOM8ON4;
288
289 coud = co_ttable[t][coud]; /* Source is always coud */
290 cpsep = trans_cpud_separate[t][cpsep];
291
292 return (eofbepos * POW3TO7 + coud) * BINOM8ON4 + cpsep;
293}
294
295static int
296tfind_from_mask(uint64_t mask, Trans *ret)
297{
298 Trans t;
299 int i = 0;
300
301 for (t = uf; t < NTRANS; t++)
302 if (((uint64_t)1 << t) & mask)
303 ret[i++] = t;
304
305 return i;
306}
307
308static int
309tfind_drud_sym16(uint64_t ind, Trans *ret)
310{
311 uint64_t mask = sd_eofbepos_16.selfsim[ind / POW3TO7];
312
313 return tfind_from_mask(mask, ret);
314}
315
316static int
317tfind_drudfin_noE_sym16(uint64_t ind, Trans *ret)
318{
319 uint64_t mask = sd_cp_16.selfsim[ind / FACTORIAL8];
320
321 return tfind_from_mask(mask, ret);
322}
323
324static int
325tfind_nxopt31(uint64_t ind, Trans *ret)
326{
327 uint64_t mask = sd_eofbepos_16.selfsim[ind / (POW3TO7 * BINOM8ON4)];
328
329 return tfind_from_mask(mask, ret);
330}
331
332/* Other functions ***********************************************************/
333
334void
335free_sd(SymData *sd)
336{
337 if (sd->generated) {
338 free(sd->class);
339 free(sd->unsym);
340 free(sd->transtorep);
341 }
342
343 sd->generated = false;
344}
345
346static void
347gensym(SymData *sd)
348{
349 uint64_t i, in, nreps = 0;
350 Trans t;
351 int j;
352
353 if (sd->generated)
354 return;
355
356 sd->class = malloc(sd->coord->max * sizeof(uint64_t));
357 sd->unsym = malloc(sd->coord->max * sizeof(uint64_t));
358 sd->transtorep = malloc(sd->coord->max * sizeof(Trans));
359 sd->selfsim = malloc(sd->coord->max * sizeof(uint64_t));
360
361 if (read_symdata_file(sd)) {
362 sd->generated = true;
363 return;
364 }
365
366 fprintf(stderr, "Cannot load %s, generating it\n", sd->filename);
367
368 for (i = 0; i < sd->coord->max; i++)
369 sd->class[i] = sd->coord->max + 1;
370
371 for (i = 0; i < sd->coord->max; i++) {
372 if (sd->class[i] == sd->coord->max + 1) {
373 sd->unsym[nreps] = i;
374 sd->transtorep[i] = uf;
375 sd->selfsim[nreps] = (uint64_t)0;
376 for (j = 0; j < sd->ntrans; j++) {
377 t = sd->trans[j];
378 in = sd->transform(t, i);
379 sd->class[in] = nreps;
380 if (in == i)
381 sd->selfsim[nreps] |=
382 ((uint64_t)1 << t);
383 else
384 sd->transtorep[in] = inverse_trans(t);
385 }
386 nreps++;
387 }
388 }
389
390 sd->sym_coord->max = nreps;
391 sd->unsym = realloc(sd->unsym, nreps * sizeof(uint64_t));
392 sd->selfsim = realloc(sd->selfsim, nreps * sizeof(uint64_t));
393 sd->generated = true;
394
395 fprintf(stderr, "Found %" PRIu64 " classes\n", nreps);
396
397 if (!write_symdata_file(sd))
398 fprintf(stderr, "Error writing SymData file\n");
399
400 return;
401}
402
403static bool
404read_symdata_file(SymData *sd)
405{
406 init_env();
407
408 FILE *f;
409 char fname[strlen(tabledir)+100];
410 uint64_t n = sd->coord->max, *sn = &sd->sym_coord->max;
411 bool r = true;
412
413 strcpy(fname, tabledir);
414 strcat(fname, "/");
415 strcat(fname, sd->filename);
416
417 if ((f = fopen(fname, "rb")) == NULL)
418 return false;
419
420 r = r && fread(&sd->sym_coord->max, sizeof(uint64_t), 1, f) == 1;
421 r = r && fread(sd->unsym, sizeof(uint64_t), *sn, f) == *sn;
422 r = r && fread(sd->selfsim, sizeof(uint64_t), *sn, f) == *sn;
423 r = r && fread(sd->class, sizeof(uint64_t), n, f) == n;
424 r = r && fread(sd->transtorep, sizeof(Trans), n, f) == n;
425
426 fclose(f);
427 return r;
428}
429
430static bool
431read_symc_moves_file()
432{
433 init_env();
434
435 Move m;
436 bool r = true;
437 FILE *f;
438 char fname[strlen(tabledir)+100];
439
440 strcpy(fname, tabledir);
441 strcat(fname, "/symc_moves");
442
443 if ((f = fopen(fname, "rb")) == NULL)
444 return false;
445
446 for (m = 0; m < NMOVES; m++) {
447 r = r && fread(move_cp_16[m], sizeof(uint64_t),
448 CLASSES_CP_16, f) == CLASSES_CP_16;
449 r = r && fread(move_eofbepos_16[m], sizeof(uint64_t),
450 CLASSES_EOFBEPOS_16, f) == CLASSES_EOFBEPOS_16;
451
452 r = r && fread(ttrep_move_cp_16[m], sizeof(Trans),
453 CLASSES_CP_16, f) == CLASSES_CP_16;
454 r = r && fread(ttrep_move_eofbepos_16[m], sizeof(Trans),
455 CLASSES_EOFBEPOS_16, f) == CLASSES_EOFBEPOS_16;
456 }
457
458 fclose(f);
459 return r;
460}
461
462static bool
463read_symc_trans_file()
464{
465 init_env();
466
467 Trans t;
468 bool r = true;
469 FILE *f;
470 char fname[strlen(tabledir)+100];
471
472 strcpy(fname, tabledir);
473 strcat(fname, "/symc_trans");
474
475 if ((f = fopen(fname, "rb")) == NULL)
476 return false;
477
478 for (t = 0; t < NTRANS; t++) {
479 r = r && fread(trans_eofbepos[t], sizeof(int),
480 POW2TO11*BINOM12ON4, f) == POW2TO11*BINOM12ON4;
481 r = r && fread(trans_epud[t], sizeof(int),
482 FACTORIAL8, f) == FACTORIAL8;
483 r = r && fread(trans_cpud_separate[t], sizeof(int),
484 BINOM8ON4, f) == BINOM8ON4;
485 }
486
487 fclose(f);
488 return r;
489}
490
491static bool
492write_symdata_file(SymData *sd)
493{
494 init_env();
495
496 FILE *f;
497 char fname[strlen(tabledir)+100];
498 uint64_t n = sd->coord->max, *sn = &sd->sym_coord->max;
499 bool r = true;
500
501 strcpy(fname, tabledir);
502 strcat(fname, "/");
503 strcat(fname, sd->filename);
504
505 if ((f = fopen(fname, "wb")) == NULL)
506 return false;
507
508 r = r && fwrite(&sd->sym_coord->max, sizeof(uint64_t), 1, f) == 1;
509 r = r && fwrite(sd->unsym, sizeof(uint64_t), *sn, f) == *sn;
510 r = r && fwrite(sd->selfsim, sizeof(uint64_t), *sn, f) == *sn;
511 r = r && fwrite(sd->class, sizeof(uint64_t), n, f) == n;
512 r = r && fwrite(sd->transtorep, sizeof(Trans), n, f) == n;
513
514 fclose(f);
515 return r;
516}
517
518static bool
519write_symc_moves_file()
520{
521 init_env();
522
523 Move m;
524 bool r = true;
525 FILE *f;
526 char fname[strlen(tabledir)+100];
527
528 strcpy(fname, tabledir);
529 strcat(fname, "/symc_moves");
530
531 if ((f = fopen(fname, "wb")) == NULL)
532 return false;
533
534 for (m = 0; m < NMOVES; m++) {
535 r = r && fwrite(move_cp_16[m], sizeof(uint64_t),
536 CLASSES_CP_16, f) == CLASSES_CP_16;
537 r = r && fwrite(move_eofbepos_16[m], sizeof(uint64_t),
538 CLASSES_EOFBEPOS_16, f) == CLASSES_EOFBEPOS_16;
539
540 r = r && fwrite(ttrep_move_cp_16[m], sizeof(Trans),
541 CLASSES_CP_16, f) == CLASSES_CP_16;
542 r = r && fwrite(ttrep_move_eofbepos_16[m], sizeof(Trans),
543 CLASSES_EOFBEPOS_16, f) == CLASSES_EOFBEPOS_16;
544 }
545
546 fclose(f);
547 return r;
548}
549
550static bool
551write_symc_trans_file()
552{
553 init_env();
554
555 Trans t;
556 bool r = true;
557 FILE *f;
558 char fname[strlen(tabledir)+100];
559
560 strcpy(fname, tabledir);
561 strcat(fname, "/symc_trans");
562
563 if ((f = fopen(fname, "wb")) == NULL)
564 return false;
565
566 for (t = 0; t < NTRANS; t++) {
567 r = r && fwrite(trans_eofbepos[t], sizeof(int),
568 POW2TO11*BINOM12ON4, f) == POW2TO11*BINOM12ON4;
569 r = r && fwrite(trans_epud[t], sizeof(int),
570 FACTORIAL8, f) == FACTORIAL8;
571 r = r && fwrite(trans_cpud_separate[t], sizeof(int),
572 BINOM8ON4, f) == BINOM8ON4;
573 }
574
575 fclose(f);
576 return r;
577}
578
579static void
580init_symc_moves()
581{
582 uint64_t i, ii, coo;
583 Move j;
584
585 if (read_symc_moves_file())
586 return;
587
588 for (i = 0; i < CLASSES_CP_16; i++) {
589 ii = sd_cp_16.unsym[i];
590 for (j = 0; j < NMOVES; j++) {
591 coo = sd_cp_16.coord->move(j, ii);
592 move_cp_16[j][i] = sd_cp_16.class[coo];
593 ttrep_move_cp_16[j][i] = sd_cp_16.transtorep[coo];
594 }
595 }
596
597 for (i = 0; i < CLASSES_EOFBEPOS_16; i++) {
598 ii = sd_eofbepos_16.unsym[i];
599 for (j = 0; j < NMOVES; j++) {
600 coo = sd_eofbepos_16.coord->move(j, ii);
601 move_eofbepos_16[j][i] = sd_eofbepos_16.class[coo];
602 ttrep_move_eofbepos_16[j][i] =
603 sd_eofbepos_16.transtorep[coo];
604 }
605 }
606
607 if (!write_symc_moves_file())
608 fprintf(stderr, "Error writing SymMoves file\n");
609}
610
611void
612init_symc_trans()
613{
614 uint64_t i;
615 int j, cp;
616 int epe[4] = {FR, FL, BL, BR};
617 int a[12] = { [8] = 8, [9] = 9, [10] = 10, [11] = 11 };
618 Cube c;
619 CubeArray *arr, *aux;
620 Trans t;
621
622 if (read_symc_trans_file())
623 return;
624
625 for (i = 0; i < POW2TO11*BINOM12ON4; i++) {
626 for (j = 0; j < 16; j++) {
627 t = trans_group_udfix[j];
628
629 arr = new_cubearray((Cube){0}, pf_edges);
630 int_to_sum_zero_array(i % POW2TO11, 2, 12, arr->eofb);
631 epos_to_compatible_ep((i / POW2TO11)*24, arr->ep, epe);
632 fix_eorleoud(arr);
633 c = arrays_to_cube(arr, pf_edges);
634 free_cubearray(arr, pf_edges);
635
636 c = apply_trans(t, c);
637 trans_eofbepos[t][i] = (c.epose/24)*POW2TO11 + c.eofb;
638 }
639 }
640
641 aux = malloc(sizeof(CubeArray));
642 aux->ep = a;
643 for (i = 0; i < FACTORIAL8; i++) {
644 index_to_perm(i, 8, a);
645 c = arrays_to_cube(aux, pf_ep);
646 for (j = 0; j < 16; j++) {
647 t = trans_group_udfix[j];
648 arr = new_cubearray(apply_trans(t, c), pf_ep);
649 trans_epud[t][i] = perm_to_index(arr->ep, 8);
650 free_cubearray(arr, pf_ep);
651 }
652 }
653 free(aux);
654
655 for (i = 0; i < BINOM8ON4; i++) {
656 cp = cpud_separate_ant[i];
657 for (j = 0; j < 16; j++) {
658 t = trans_group_udfix[j];
659 trans_cpud_separate[t][i] =
660 cpud_separate_ind[cp_ttable[t][cp]];
661 }
662 }
663
664 if (!write_symc_trans_file())
665 fprintf(stderr, "Error writing SymTrans file\n");
666}
667
668void
669init_symcoord()
670{
671 int i;
672
673 static bool initialized = false;
674 if (initialized)
675 return;
676 initialized = true;
677
678 init_coord();
679
680 init_symc_trans();
681
682 for (i = 0; all_sd[i] != NULL; i++)
683 gensym(all_sd[i]);
684
685 init_symc_moves();
686}
687
diff --git a/src/symcoord.h b/src/symcoord.h
new file mode 100644
index 0000000..0882bff
--- /dev/null
+++ b/src/symcoord.h
@@ -0,0 +1,17 @@
1#ifndef SYMCOORD_H
2#define SYMCOORD_H
3
4#include "coord.h"
5
6extern Coordinate coord_cp_sym16;
7extern Coordinate coord_eofbepos_sym16;
8extern Coordinate coord_drud_sym16;
9extern Coordinate coord_drudfin_noE_sym16;
10extern Coordinate coord_nxopt31;
11
12extern SymData *all_sd[];
13
14void free_sd(SymData *sd);
15void init_symcoord();
16
17#endif
diff --git a/src/threader_eager.c b/src/threader_eager.c
deleted file mode 100644
index 261b995..0000000
--- a/src/threader_eager.c
+++ /dev/null
@@ -1,163 +0,0 @@
1#include <pthread.h>
2#include "threader_eager.h"
3
4typedef struct {
5 AlgList * sols;
6 pthread_mutex_t * sols_mutex;
7} ThreadData;
8
9typedef struct {
10 DfsArg * arg;
11 Solver * solver;
12 Threader * threader;
13 AlgList * starts;
14 AlgListNode ** node;
15 pthread_mutex_t * start_mutex;
16} ThreadInitData;
17
18static void append_sol(Alg *, void *);
19static void * instance_thread(void *);
20static void dispatch(DfsArg *, AlgList *, Solver *, Threader *);
21static AlgList * possible_starts(DfsArg *, Solver *);
22static int get_nsol(void *);
23
24Threader threader_eager = {
25 .append_sol = append_sol,
26 .dispatch = dispatch,
27 .get_nsol = get_nsol,
28};
29
30static void
31append_sol(Alg *alg, void *threaddata)
32{
33 ThreadData *td = (ThreadData *)threaddata;
34
35 pthread_mutex_lock(td->sols_mutex);
36 append_alg(td->sols, alg);
37 pthread_mutex_unlock(td->sols_mutex);
38}
39
40static AlgList *
41possible_starts(DfsArg *arg, Solver *solver)
42{
43 AlgList *ret = new_alglist();
44
45 if (solver->is_solved(solver->param, arg->cubedata)) {
46 if (arg->opts->min_moves == 0 && arg->d == 0)
47 append_sol(new_alg(""), arg->threaddata);
48 return ret;
49 }
50
51 for (int i = 0; solver->moveset->sorted_moves[i] != NULLMOVE; i++) {
52 Move m = solver->moveset->sorted_moves[i];
53 Alg *alg = new_alg("");
54 append_move(alg, m, false);
55 append_alg(ret, alg);
56 free_alg(alg);
57
58/* TODO: check if step not final */
59 if (arg->opts->can_niss) {
60 alg = new_alg("");
61 append_move(alg, m, true);
62 append_alg(ret, alg);
63 free_alg(alg);
64 }
65 }
66
67 return ret;
68}
69
70static void *
71instance_thread(void *arg)
72{
73 ThreadInitData *tid = (ThreadInitData *)arg;
74
75 while (true) {
76 pthread_mutex_lock(tid->start_mutex);
77 AlgListNode *node = *(tid->node);
78 if (node == NULL) {
79 pthread_mutex_unlock(tid->start_mutex);
80 break;
81 }
82 *(tid->node) = (*(tid->node))->next;
83 pthread_mutex_unlock(tid->start_mutex);
84
85/* TODO: adjust for longer (arbitrarily long?) starting sequences */
86 void *data = tid->solver->alloc_cubedata(tid->solver->param);
87 tid->solver->copy_cubedata(
88 tid->solver->param, tid->arg->cubedata, data);
89 bool inv = node->alg->inv[node->alg->len-1];
90 if (inv)
91 tid->solver->invert_cube(
92 tid->solver->param, data);
93 tid->solver->apply_move(
94 tid->solver->param, data, node->alg->move[0]);
95
96 DfsArg newarg;
97 newarg.cubedata = data;
98 newarg.threaddata = tid->arg->threaddata;
99 newarg.opts = tid->arg->opts;
100 newarg.d = tid->arg->d;
101 newarg.niss = inv;
102 newarg.current_alg = new_alg("");
103 copy_alg(node->alg, newarg.current_alg);
104
105 dfs(&newarg, tid->solver, tid->threader);
106
107 tid->solver->free_cubedata(tid->solver->param, data);
108 free_alg(newarg.current_alg);
109 }
110
111 return NULL;
112}
113
114static void
115dispatch(DfsArg *arg, AlgList *sols, Solver *solver, Threader *threader)
116{
117 int nthreads = arg->opts->nthreads;
118 ThreadInitData tid[nthreads];
119 pthread_t t[nthreads];
120
121 pthread_mutex_t *sols_mutex = malloc(sizeof(pthread_mutex_t));
122 pthread_mutex_init(sols_mutex, NULL);
123
124 arg->threaddata = malloc(sizeof(ThreadData));
125 ThreadData *td = (ThreadData *)arg->threaddata;
126 td->sols = sols;
127 td->sols_mutex = sols_mutex;
128
129 AlgList *starts = possible_starts(arg, solver);
130 AlgListNode *node = starts->first;
131 pthread_mutex_t *start_mutex = malloc(sizeof(pthread_mutex_t));
132 pthread_mutex_init(start_mutex, NULL);
133 for (int i = 0; i < nthreads; i++) {
134 tid[i].arg = arg;
135 tid[i].solver = solver;
136 tid[i].threader = threader;
137 tid[i].starts = starts;
138 tid[i].node = &node;
139 tid[i].start_mutex = start_mutex;
140
141 pthread_create(&t[i], NULL, instance_thread, &tid[i]);
142 }
143
144 for (int i = 0; i < nthreads; i++)
145 pthread_join(t[i], NULL);
146
147 free(td);
148 free(sols_mutex);
149 free_alglist(starts);
150 free(start_mutex);
151}
152
153static int
154get_nsol(void *threaddata)
155{
156 ThreadData *td = (ThreadData *)threaddata;
157
158 pthread_mutex_lock(td->sols_mutex);
159 int n = td->sols->len;
160 pthread_mutex_unlock(td->sols_mutex);
161
162 return n;
163}
diff --git a/src/threader_eager.h b/src/threader_eager.h
deleted file mode 100644
index e39b27f..0000000
--- a/src/threader_eager.h
+++ /dev/null
@@ -1,8 +0,0 @@
1#ifndef THREADER_EAGER_H
2#define THREADER_EAGER_H
3
4#include "solve.h"
5
6extern Threader threader_eager;
7
8#endif
diff --git a/src/threader_single.c b/src/threader_single.c
deleted file mode 100644
index 232835d..0000000
--- a/src/threader_single.c
+++ /dev/null
@@ -1,35 +0,0 @@
1#include "threader_single.h"
2
3static void append_sol(Alg *, void *);
4static void dispatch(DfsArg *, AlgList *, Solver *, Threader *);
5static int get_nsol(void *);
6
7Threader threader_single = {
8 .append_sol = append_sol,
9 .dispatch = dispatch,
10 .get_nsol = get_nsol,
11};
12
13static void
14append_sol(Alg *alg, void *threaddata)
15{
16 append_alg((AlgList *)threaddata, alg);
17}
18
19static void
20dispatch(DfsArg *arg, AlgList *sols, Solver *solver, Threader *threader)
21{
22 arg->threaddata = sols;
23 arg->niss = false;
24 arg->current_alg = new_alg("");
25
26 dfs(arg, solver, threader);
27
28 free_alg(arg->current_alg);
29}
30
31static int
32get_nsol(void *threaddata)
33{
34 return ((AlgList *)threaddata)->len;
35}
diff --git a/src/threader_single.h b/src/threader_single.h
deleted file mode 100644
index 2c0bfab..0000000
--- a/src/threader_single.h
+++ /dev/null
@@ -1,8 +0,0 @@
1#ifndef THREADER_SINGLE_H
2#define THREADER_SINGLE_H
3
4#include "solve.h"
5
6extern Threader threader_single;
7
8#endif
diff --git a/src/trans.c b/src/trans.c
index 898c2be..e267a17 100644
--- a/src/trans.c
+++ b/src/trans.c
@@ -1,23 +1,31 @@
1#define TRANS_C
2
3#include "trans.h" 1#include "trans.h"
4 2
5/* Local functions ***********************************************************/ 3/* Local functions ***********************************************************/
6 4
5static bool read_ttables_file();
6static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f);
7static bool write_ttables_file();
8
7/* Tables and other data *****************************************************/ 9/* Tables and other data *****************************************************/
8 10
9static Cube mirror_cube = { 11static int ep_mirror[12] = {
10.ep = { [UF] = UF, [UL] = UR, [UB] = UB, [UR] = UL, 12 [UF] = UF, [UL] = UR, [UB] = UB, [UR] = UL,
11 [DF] = DF, [DL] = DR, [DB] = DB, [DR] = DL, 13 [DF] = DF, [DL] = DR, [DB] = DB, [DR] = DL,
12 [FR] = FL, [FL] = FR, [BL] = BR, [BR] = BL }, 14 [FR] = FL, [FL] = FR, [BL] = BR, [BR] = BL
13.cp = { [UFR] = UFL, [UFL] = UFR, [UBL] = UBR, [UBR] = UBL, 15};
14 [DFR] = DFL, [DFL] = DFR, [DBL] = DBR, [DBR] = DBL }, 16
15.xp = { [U_center] = U_center, [D_center] = D_center, 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,
16 [R_center] = L_center, [L_center] = R_center, 24 [R_center] = L_center, [L_center] = R_center,
17 [F_center] = F_center, [B_center] = B_center } 25 [F_center] = F_center, [B_center] = B_center
18}; 26};
19 27
20static char rotation_alg_string[100][NROTATIONS] = { 28static char rotation_alg_string[100][NROTATIONS] = {
21 [uf] = "", [ur] = "y", [ub] = "y2", [ul] = "y3", 29 [uf] = "", [ur] = "y", [ub] = "y2", [ul] = "y3",
22 [df] = "z2", [dr] = "y z2", [db] = "x2", [dl] = "y3 z2", 30 [df] = "z2", [dr] = "y z2", [db] = "x2", [dl] = "y3 z2",
23 [rf] = "z3", [rd] = "z3 y", [rb] = "z3 y2", [ru] = "z3 y3", 31 [rf] = "z3", [rd] = "z3 y", [rb] = "z3 y2", [ru] = "z3 y3",
@@ -26,39 +34,176 @@ static char rotation_alg_string[100][NROTATIONS] = {
26 [bu] = "x3", [br] = "x3 y", [bd] = "x3 y2", [bl] = "x3 y3", 34 [bu] = "x3", [br] = "x3 y", [bd] = "x3 y2", [bl] = "x3 y3",
27}; 35};
28 36
29Alg *rotation_alg_arr[NROTATIONS]; 37static int epose_source[NTRANS]; /* 0=epose, 1=eposs, 2=eposm */
30Move moves_ttable[NTRANS][NMOVES]; 38static int eposs_source[NTRANS];
31Trans trans_ttable[NTRANS][NTRANS]; 39static int eposm_source[NTRANS];
32Trans trans_itable[NTRANS]; 40static int eofb_source[NTRANS]; /* 0=eoud, 1=eorl, 2=eofb */
41static int eorl_source[NTRANS];
42static int eoud_source[NTRANS];
43static int coud_source[NTRANS]; /* 0=coud, 1=corl, 2=cofb */
44static int cofb_source[NTRANS];
45static int corl_source[NTRANS];
33 46
34/* Public functions **********************************************************/ 47int epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
48int eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
49int eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
50int eo_ttable[NTRANS][POW2TO11];
51int cp_ttable[NTRANS][FACTORIAL8];
52int co_ttable[NTRANS][POW3TO7];
53int cpos_ttable[NTRANS][FACTORIAL6];
54Move moves_ttable[NTRANS][NMOVES];
35 55
36void 56/* Local functions implementation ********************************************/
37apply_trans(Trans t, Cube *cube) 57
58static bool
59read_ttables_file()
38{ 60{
39 Cube aux; 61 init_env();
40 Alg *inv; 62
41 int i; 63 FILE *f;
64 char fname[strlen(tabledir)+20];
65 int b = sizeof(int);
66 bool r = true;
67 Move m;
42 68
43 inv = inverse_alg(rotation_alg(t % NROTATIONS)); 69 /* Table sizes, used for reading and writing files */
44 copy_cube(cube, &aux); 70 uint64_t me[11] = {
45 make_solved(cube); 71 [0] = FACTORIAL12/FACTORIAL8,
72 [1] = FACTORIAL12/FACTORIAL8,
73 [2] = FACTORIAL12/FACTORIAL8,
74 [3] = POW2TO11,
75 [4] = FACTORIAL8,
76 [5] = POW3TO7,
77 [6] = FACTORIAL6,
78 [7] = NMOVES
79 };
80
81 strcpy(fname, tabledir);
82 strcat(fname, "/");
83 strcat(fname, "ttables");
84
85 if ((f = fopen(fname, "rb")) == NULL)
86 return false;
46 87
47 if (t >= NROTATIONS) 88 for (m = 0; m < NTRANS; m++) {
48 compose(&mirror_cube, cube); 89 r = r && fread(epose_ttable[m], b, me[0], f) == me[0];
49 apply_alg(inv, cube); 90 r = r && fread(eposs_ttable[m], b, me[1], f) == me[1];
50 compose(&aux, cube); 91 r = r && fread(eposm_ttable[m], b, me[2], f) == me[2];
51 apply_alg(rotation_alg(t % NROTATIONS), cube); 92 r = r && fread(eo_ttable[m], b, me[3], f) == me[3];
52 if (t >= NROTATIONS) { 93 r = r && fread(cp_ttable[m], b, me[4], f) == me[4];
53 compose(&mirror_cube, cube); 94 r = r && fread(co_ttable[m], b, me[5], f) == me[5];
54 for (i = 0; i < 8; i++) 95 r = r && fread(cpos_ttable[m], b, me[6], f) == me[6];
55 cube->co[i] = (3 - cube->co[i]) % 3; 96 r = r && fread(moves_ttable[m], b, me[7], f) == me[7];
56 } 97 }
57 98
99 fclose(f);
100 return r;
101}
102
103static Cube
104rotate_via_compose(Trans r, Cube c, PieceFilter f)
105{
106 static int zero12[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
107 static int zero8[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
108 static CubeArray ma = {
109 .ep = ep_mirror,
110 .eofb = zero12,
111 .eorl = zero12,
112 .eoud = zero12,
113 .cp = cp_mirror,
114 .coud = zero8,
115 .corl = zero8,
116 .cofb = zero8,
117 .cpos = cpos_mirror
118 };
119
120 Alg *inv = inverse_alg(rotation_alg(r));
121 Cube ret = {0};
122
123 if (r >= NROTATIONS)
124 ret = move_via_arrays(&ma, ret, f);
125 ret = apply_alg_generic(inv, ret, f, true);
126
127 ret = compose_filtered(c, ret, f);
128
129 ret = apply_alg_generic(rotation_alg(r), ret, f, true);
130 if (r >= NROTATIONS)
131 ret = move_via_arrays(&ma, ret, f);
132
58 free_alg(inv); 133 free_alg(inv);
134 return ret;
135}
136
137static bool
138write_ttables_file()
139{
140 init_env();
141
142 FILE *f;
143 char fname[strlen(tabledir)+20];
144 bool r = true;
145 int b = sizeof(int);
146 Move m;
147
148 /* Table sizes, used for reading and writing files */
149 uint64_t me[11] = {
150 [0] = FACTORIAL12/FACTORIAL8,
151 [1] = FACTORIAL12/FACTORIAL8,
152 [2] = FACTORIAL12/FACTORIAL8,
153 [3] = POW2TO11,
154 [4] = FACTORIAL8,
155 [5] = POW3TO7,
156 [6] = FACTORIAL6,
157 [7] = NMOVES
158 };
159
160 strcpy(fname, tabledir);
161 strcat(fname, "/ttables");
162
163 if ((f = fopen(fname, "wb")) == NULL)
164 return false;
165
166 for (m = 0; m < NTRANS; m++) {
167 r = r && fwrite(epose_ttable[m], b, me[0], f) == me[0];
168 r = r && fwrite(eposs_ttable[m], b, me[1], f) == me[1];
169 r = r && fwrite(eposm_ttable[m], b, me[2], f) == me[2];
170 r = r && fwrite(eo_ttable[m], b, me[3], f) == me[3];
171 r = r && fwrite(cp_ttable[m], b, me[4], f) == me[4];
172 r = r && fwrite(co_ttable[m], b, me[5], f) == me[5];
173 r = r && fwrite(cpos_ttable[m], b, me[6], f) == me[6];
174 r = r && fwrite(moves_ttable[m], b, me[7], f) == me[7];
175 }
176
177 fclose(f);
178 return r;
179}
180
181/* Public functions **********************************************************/
182
183Cube
184apply_trans(Trans t, Cube cube)
185{
186 /*init_trans();*/
187
188 int aux_epos[3] = { cube.epose, cube.eposs, cube.eposm };
189 int aux_eo[3] = { cube.eoud, cube.eorl, cube.eofb };
190 int aux_co[3] = { cube.coud, cube.corl, cube.cofb };
191
192 return (Cube) {
193 .epose = epose_ttable[t][aux_epos[epose_source[t]]],
194 .eposs = eposs_ttable[t][aux_epos[eposs_source[t]]],
195 .eposm = eposm_ttable[t][aux_epos[eposm_source[t]]],
196 .eofb = eo_ttable[t][aux_eo[eofb_source[t]]],
197 .eorl = eo_ttable[t][aux_eo[eorl_source[t]]],
198 .eoud = eo_ttable[t][aux_eo[eoud_source[t]]],
199 .coud = co_ttable[t][aux_co[coud_source[t]]],
200 .corl = co_ttable[t][aux_co[corl_source[t]]],
201 .cofb = co_ttable[t][aux_co[cofb_source[t]]],
202 .cp = cp_ttable[t][cube.cp],
203 .cpos = cpos_ttable[t][cube.cpos]
204 };
59} 205}
60 206
61/*
62Trans 207Trans
63inverse_trans(Trans t) 208inverse_trans(Trans t)
64{ 209{
@@ -86,18 +231,23 @@ inverse_trans(Trans t)
86 231
87 return inverse_trans_aux[t]; 232 return inverse_trans_aux[t];
88} 233}
89*/
90
91Trans
92inverse_trans(Trans t)
93{
94 return trans_itable[t];
95}
96 234
97Alg * 235Alg *
98rotation_alg(Trans i) 236rotation_alg(Trans t)
99{ 237{
100 return rotation_alg_arr[i % NROTATIONS]; 238 int i;
239
240 static Alg *rotation_alg_arr[NROTATIONS];
241 static bool initialized = false;
242
243 if (!initialized) {
244 for (i = 0; i < NROTATIONS; i++)
245 rotation_alg_arr[i] = new_alg(rotation_alg_string[i]);
246
247 initialized = true;
248 }
249
250 return rotation_alg_arr[t % NROTATIONS];
101} 251}
102 252
103void 253void
@@ -105,20 +255,10 @@ transform_alg(Trans t, Alg *alg)
105{ 255{
106 int i; 256 int i;
107 257
258 /*init_trans();*/
259
108 for (i = 0; i < alg->len; i++) 260 for (i = 0; i < alg->len; i++)
109 alg->move[i] = transform_move(t, alg->move[i]); 261 alg->move[i] = moves_ttable[t][alg->move[i]];
110}
111
112Move
113transform_move(Trans t, Move m)
114{
115 return moves_ttable[t][m];
116}
117
118Trans
119transform_trans(Trans t, Trans m)
120{
121 return trans_ttable[t][m];
122} 262}
123 263
124void 264void
@@ -128,63 +268,106 @@ init_trans() {
128 return; 268 return;
129 initialized = true; 269 initialized = true;
130 270
131 int i; 271 init_moves();
132 Alg *nonsym_alg, *nonsym_inv; 272
133 Cube aux, cube; 273 Cube aux, cube, c[3];
274 CubeArray epcp;
275 int i, eparr[12], eoarr[12], cparr[8], coarr[8];
276 unsigned int ui;
134 Move mi, move; 277 Move mi, move;
135 Trans t, u, v; 278 Trans m;
136 279
137 init_moves(); 280 /* Compute sources */
281 for (i = 0; i < NTRANS; i++) {
282 cube = apply_alg(rotation_alg(i), (Cube){0});
283
284 epose_source[i] = edge_slice(what_edge_at(cube, FR));
285 eposs_source[i] = edge_slice(what_edge_at(cube, UR));
286 eposm_source[i] = edge_slice(what_edge_at(cube, UF));
287 eofb_source[i] = what_center_at(cube, F_center)/2;
288 eorl_source[i] = what_center_at(cube, R_center)/2;
289 eoud_source[i] = what_center_at(cube, U_center)/2;
290 coud_source[i] = what_center_at(cube, U_center)/2;
291 cofb_source[i] = what_center_at(cube, F_center)/2;
292 corl_source[i] = what_center_at(cube, R_center)/2;
293 }
138 294
139 for (i = 0; i < NROTATIONS; i++) 295 if (read_ttables_file())
140 rotation_alg_arr[i] = new_alg(rotation_alg_string[i]); 296 return;
297
298 fprintf(stderr, "Cannot load %s, generating it\n", "ttables");
141 299
142 for (t = 0; t < NTRANS; t++) { 300 /* Initialize tables */
301 for (m = 0; m < NTRANS; m++) {
302 epcp = (CubeArray){ .ep = eparr, .cp = cparr };
303 cube = apply_alg(rotation_alg(m), (Cube){0});
304 cube_to_arrays(cube, &epcp, pf_epcp);
305 if (m >= NROTATIONS) {
306 apply_permutation(ep_mirror, eparr, 12);
307 apply_permutation(cp_mirror, cparr, 8);
308 }
309
310 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
311 c[0] = admissible_ep((Cube){ .epose = ui }, pf_e);
312 c[1] = admissible_ep((Cube){ .eposs = ui }, pf_s);
313 c[2] = admissible_ep((Cube){ .eposm = ui }, pf_m);
314
315 cube = rotate_via_compose(m,c[epose_source[m]],pf_ep);
316 epose_ttable[m][ui] = cube.epose;
317
318 cube = rotate_via_compose(m,c[eposs_source[m]],pf_ep);
319 eposs_ttable[m][ui] = cube.eposs;
320
321 cube = rotate_via_compose(m,c[eposm_source[m]],pf_ep);
322 eposm_ttable[m][ui] = cube.eposm;
323 }
324 for (ui = 0; ui < POW2TO11; ui++ ) {
325 int_to_sum_zero_array(ui, 2, 12, eoarr);
326 apply_permutation(eparr, eoarr, 12);
327 eo_ttable[m][ui] = digit_array_to_int(eoarr, 11, 2);
328 }
329 for (ui = 0; ui < POW3TO7; ui++) {
330 int_to_sum_zero_array(ui, 3, 8, coarr);
331 apply_permutation(cparr, coarr, 8);
332 co_ttable[m][ui] = digit_array_to_int(coarr, 7, 3);
333 if (m >= NROTATIONS)
334 co_ttable[m][ui] =
335 invert_digits(co_ttable[m][ui], 3, 7);
336 }
337 for (ui = 0; ui < FACTORIAL8; ui++) {
338 cube = (Cube){ .cp = ui };
339 cube = rotate_via_compose(m, cube, pf_cp);
340 cp_ttable[m][ui] = cube.cp;
341 }
342 for (ui = 0; ui < FACTORIAL6; ui++) {
343 cube = (Cube){ .cpos = ui };
344 cube = rotate_via_compose(m, cube, pf_cpos);
345 cpos_ttable[m][ui] = cube.cpos;
346 }
143 for (mi = 0; mi < NMOVES; mi++) { 347 for (mi = 0; mi < NMOVES; mi++) {
144 make_solved(&aux); 348 /* Old version:
145 apply_move(mi, &aux); 349 *
146 apply_trans(t, &aux); 350 aux = apply_trans(m, apply_move(mi, (Cube){0}));
147 for (move = 0; move < NMOVES; move++) { 351 for (move = 0; move < NMOVES; move++) {
148 copy_cube(&aux, &cube); 352 cube = apply_move(inverse_move(move), aux);
149 apply_move(inverse_move(move), &cube); 353 mirr = apply_trans(uf_mirror, cube);
150 if (is_solved(&cube)) { 354 if (is_solved(cube) || is_solved(mirr))
151 moves_ttable[t][mi] = move; 355 moves_ttable[m][mi] = move;
152 break;
153 }
154 } 356 }
155 } 357 */
156 }
157 358
158 nonsym_alg = new_alg("R' U' F"); 359 aux = apply_trans(m, apply_move(mi, (Cube){0}));
159 nonsym_inv = inverse_alg(nonsym_alg); 360 for (move = 0; move < NMOVES; move++) {
160 361 cube = apply_move(inverse_move(move), aux);
161 for (t = 0; t < NTRANS; t++) { 362 if (is_solved(cube)) {
162 for (u = 0; u < NTRANS; u++) { 363 moves_ttable[m][mi] = move;
163 make_solved(&aux);
164 apply_alg(nonsym_alg, &aux);
165 apply_trans(u, &aux);
166 apply_trans(t, &aux);
167 for (v = 0; v < NTRANS; v++) {
168 copy_cube(&aux, &cube);
169 apply_trans(v, &cube);
170 apply_alg(nonsym_inv, &cube);
171 if (is_solved(&cube)) {
172 /* This is the inverse of the correct
173 value, it will be inverted later */
174 trans_ttable[t][u] = v;
175 if (v == uf)
176 trans_itable[t] = u;
177 break; 364 break;
178 } 365 }
179 } 366 }
180 } 367 }
181 } 368 }
182 for (t = 0; t < NTRANS; t++)
183 for (u = 0; u < NTRANS; u++)
184 trans_ttable[t][u] = trans_itable[trans_ttable[t][u]];
185
186 369
187 free_alg(nonsym_alg); 370 if (!write_ttables_file())
188 free_alg(nonsym_inv); 371 fprintf(stderr, "Error writing ttables\n");
189} 372}
190 373
diff --git a/src/trans.h b/src/trans.h
index 0cc8cef..51df12f 100644
--- a/src/trans.h
+++ b/src/trans.h
@@ -3,30 +3,24 @@
3 3
4#include "moves.h" 4#include "moves.h"
5 5
6void apply_trans(Trans t, Cube *cube); 6/*
7 * Tables are exposed to allow faster partial transformations in some
8 * specific cases (in symcoord)
9 */
10extern int epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
11extern int eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
12extern int eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
13extern int eo_ttable[NTRANS][POW2TO11];
14extern int cp_ttable[NTRANS][FACTORIAL8];
15extern int co_ttable[NTRANS][POW3TO7];
16extern int cpos_ttable[NTRANS][FACTORIAL6];
17extern Move moves_ttable[NTRANS][NMOVES];
18
19Cube apply_trans(Trans t, Cube cube);
7Trans inverse_trans(Trans t); 20Trans inverse_trans(Trans t);
8Alg * rotation_alg(Trans i); 21Alg * rotation_alg(Trans i);
9void transform_alg(Trans t, Alg *alg); 22void transform_alg(Trans i, Alg *alg);
10Move transform_move(Trans t, Move m);
11Trans transform_trans(Trans t, Trans m);
12 23
13void init_trans(); 24void init_trans();
14 25
15#ifndef TRANS_C
16
17extern TransGroup tgrp_udfix;
18
19#else
20
21TransGroup
22tgrp_udfix = {
23 .n = 16,
24 .t = { uf, ur, ub, ul,
25 df, dr, db, dl,
26 uf_mirror, ur_mirror, ub_mirror, ul_mirror,
27 df_mirror, dr_mirror, db_mirror, dl_mirror },
28};
29
30#endif
31
32#endif 26#endif
diff --git a/src/utils.c b/src/utils.c
index cbf951e..e0d3268 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -1,5 +1,3 @@
1#define UTILS_C
2
3#include "utils.h" 1#include "utils.h"
4 2
5void 3void
@@ -161,24 +159,24 @@ is_perm(int *a, int n)
161{ 159{
162 int *aux = malloc(n * sizeof(int)); 160 int *aux = malloc(n * sizeof(int));
163 int i; 161 int i;
164 bool ret = true;
165 162
166 for (i = 0; i < n; i++) 163 for (i = 0; i < n; i++)
167 aux[i] = 0; 164 aux[i] = 0;
168 165
169 for (i = 0; i < n; i++) { 166 for (i = 0; i < n; i++) {
170 if (a[i] < 0 || a[i] >= n) 167 if (a[i] < 0 || a[i] >= n)
171 ret = false; 168 return false;
172 else 169 else
173 aux[a[i]] = 1; 170 aux[a[i]] = 1;
174 } 171 }
175 172
176 for (i = 0; i < n; i++) 173 for (i = 0; i < n; i++)
177 if (!aux[i]) 174 if (!aux[i])
178 ret = false; 175 return false;
179 176
180 free(aux); 177 free(aux);
181 return ret; 178
179 return true;
182} 180}
183 181
184bool 182bool
@@ -197,7 +195,7 @@ perm_sign(int *a, int n)
197{ 195{
198 int i, j, ret = 0; 196 int i, j, ret = 0;
199 197
200 if (!is_perm(a, n)) 198 if (!is_perm(a,n))
201 return -1; 199 return -1;
202 200
203 for (i = 0; i < n; i++) 201 for (i = 0; i < n; i++)
@@ -213,7 +211,7 @@ perm_to_index(int *a, int n)
213 int i, j, c, ret = 0; 211 int i, j, c, ret = 0;
214 212
215 if (!is_perm(a, n)) 213 if (!is_perm(a, n))
216 return factorial(n); 214 return -1;
217 215
218 for (i = 0; i < n; i++) { 216 for (i = 0; i < n; i++) {
219 c = 0; 217 c = 0;

Generated with cgit - Back to sebastiano.tronto.net