From 6f4313bc1ed5be794146e6ca2fd73f48c7906061 Mon Sep 17 00:00:00 2001 From: Sebastiano Tronto Date: Mon, 1 May 2023 12:48:55 +0200 Subject: Reverted to 2.0.3 --- src/alg.c | 301 ++++++---- src/alg.h | 16 +- src/commands.c | 358 +++++++++--- src/commands.h | 199 +------ src/coord.c | 977 ++++++++++++++++---------------- src/coord.h | 271 +-------- src/cube.c | 932 +++++++++++++++++++++++++----- src/cube.h | 59 +- src/cubetypes.h | 240 ++++---- src/env.c | 2 - src/env.h | 4 +- src/fst.c | 401 ------------- src/fst.h | 13 - src/moves.c | 419 +++++++++++--- src/moves.h | 23 +- src/movesets.c | 194 ------- src/movesets.h | 15 - src/pf.c | 95 ++++ src/pf.h | 20 + src/pruning.c | 371 ++++++++---- src/pruning.h | 22 +- src/shell.c | 10 +- src/solve.c | 548 +++++++++++++++--- src/solve.h | 51 +- src/solver_step.c | 306 ---------- src/solver_step.h | 12 - src/steps.c | 1494 +++++++++++++++++++++++++++++++++++++++++++++---- src/steps.h | 243 +------- src/symcoord.c | 687 +++++++++++++++++++++++ src/symcoord.h | 17 + src/threader_eager.c | 163 ------ src/threader_eager.h | 8 - src/threader_single.c | 35 -- src/threader_single.h | 8 - src/trans.c | 383 +++++++++---- src/trans.h | 36 +- src/utils.c | 14 +- 37 files changed, 5525 insertions(+), 3422 deletions(-) delete mode 100644 src/fst.c delete mode 100644 src/fst.h delete mode 100644 src/movesets.c delete mode 100644 src/movesets.h create mode 100644 src/pf.c create mode 100644 src/pf.h delete mode 100644 src/solver_step.c delete mode 100644 src/solver_step.h create mode 100644 src/symcoord.c create mode 100644 src/symcoord.h delete mode 100644 src/threader_eager.c delete mode 100644 src/threader_eager.h delete mode 100644 src/threader_single.c delete mode 100644 src/threader_single.h (limited to 'src') 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 @@ -#define ALG_C - #include "alg.h" +/* Local functions ***********************************************************/ + +static bool allowed_HTM(Move m); +static bool allowed_URF(Move m); +static bool allowed_eofb(Move m); +static bool allowed_drud(Move m); +static bool allowed_htr(Move m); +static bool allowed_next_HTM(Move l2, Move l1, Move m); static int axis(Move m); + static void free_alglistnode(AlgListNode *aln); static void realloc_alg(Alg *alg, int n); +/* Movesets ******************************************************************/ + +Moveset +moveset_HTM = { + .allowed = allowed_HTM, + .allowed_next = allowed_next_HTM, +}; + +Moveset +moveset_URF = { + .allowed = allowed_URF, + .allowed_next = allowed_next_HTM, +}; + +Moveset +moveset_eofb = { + .allowed = allowed_eofb, + .allowed_next = allowed_next_HTM, +}; + +Moveset +moveset_drud = { + .allowed = allowed_drud, + .allowed_next = allowed_next_HTM, +}; + +Moveset +moveset_htr = { + .allowed = allowed_htr, + .allowed_next = allowed_next_HTM, +}; + +static int nmoveset = 5; +static Moveset * all_ms[] = { + &moveset_HTM, + &moveset_URF, + &moveset_eofb, + &moveset_drud, + &moveset_htr, +}; + +/* Functions *****************************************************************/ + +static bool +allowed_HTM(Move m) +{ + return m >= U && m <= B3; +} + +static bool +allowed_URF(Move m) +{ + Move b = base_move(m); + + return b == U || b == R || b == F; +} + +static bool +allowed_eofb(Move m) +{ + Move b = base_move(m); + + return b == U || b == D || b == R || b == L || + ((b == F || b == B) && m == b+1); +} + +static bool +allowed_drud(Move m) +{ + Move b = base_move(m); + + return b == U || b == D || + ((b == R || b == L || b == F || b == B) && m == b + 1); +} + +static bool +allowed_htr(Move m) +{ + Move b = base_move(m); + + return moveset_HTM.allowed(m) && m == b + 1; +} + +static bool +allowed_next_HTM(Move l2, Move l1, Move m) +{ + bool p, q; + + p = l1 != NULLMOVE && base_move(l1) == base_move(m); + q = l2 != NULLMOVE && base_move(l2) == base_move(m); + + return !(p || (commute(l1, l2) && q)); +} + void append_alg(AlgList *l, Alg *alg) { @@ -33,42 +134,30 @@ append_move(Alg *alg, Move m, bool inverse) alg->move[alg->len] = m; alg->inv [alg->len] = inverse; alg->len++; - - if (inverse) - alg->move_inverse[alg->len_inverse++] = m; - else - alg->move_normal[alg->len_normal++] = m; } static int axis(Move m) { - static int aux[] = { - [NULLMOVE] = 0, - - [U] = 1, [U2] = 1, [U3] = 1, - [D] = 1, [D2] = 1, [D3] = 1, - [Uw] = 1, [Uw2] = 1, [Uw3] = 1, - [Dw] = 1, [Dw2] = 1, [Dw3] = 1, - [E] = 1, [E2] = 1, [E3] = 1, - [y] = 1, [y2] = 1, [y3] = 1, - - [R] = 2, [R2] = 2, [R3] = 2, - [L] = 2, [L2] = 2, [L3] = 2, - [Rw] = 2, [Rw2] = 2, [Rw3] = 2, - [Lw] = 2, [Lw2] = 2, [Lw3] = 2, - [M] = 2, [M2] = 2, [M3] = 2, - [x] = 2, [x2] = 2, [x3] = 2, - - [F] = 3, [F2] = 3, [F3] = 3, - [B] = 3, [B2] = 3, [B3] = 3, - [Fw] = 3, [Fw2] = 3, [Fw3] = 3, - [Bw] = 3, [Bw2] = 3, [Bw3] = 3, - [S] = 3, [S2] = 3, [S3] = 3, - [z] = 3, [z2] = 3, [z3] = 3, - }; + if (m == NULLMOVE) + return 0; + + if (m >= U && m <= B3) + return (m-1)/6 + 1; + + if (m >= Uw && m <= Bw3) + return (m-1)/6 - 2; + + if (base_move(m) == E || base_move(m) == y) + return 1; + + if (base_move(m) == M || base_move(m) == x) + return 2; - return aux[m]; + if (base_move(m) == S || base_move(m) == z) + return 3; + + return -1; } Move @@ -86,32 +175,6 @@ commute(Move m1, Move m2) return axis(m1) == axis(m2); } -int -compare(Move m1, Move m2) -{ - if (!commute(m1, m2)) - return 0; - - return m1 < m2 ? 1 : -1; -} - -int -compare_last(Alg *alg, Move m, bool inverse) -{ - Move last; - int n; - - if (inverse) { - n = alg->len_inverse; - last = n > 0 ? alg->move_inverse[n-1] : NULLMOVE; - } else { - n = alg->len_normal; - last = n > 0 ? alg->move_normal[n-1] : NULLMOVE; - } - - return compare(last, m); -} - void compose_alg(Alg *alg1, Alg *alg2) { @@ -124,7 +187,7 @@ compose_alg(Alg *alg1, Alg *alg2) void copy_alg(Alg *src, Alg *dst) { - dst->len = dst->len_normal = dst->len_inverse = 0; + dst->len = 0; /* Overwrites */ compose_alg(dst, src); } @@ -156,6 +219,16 @@ free_alglistnode(AlgListNode *aln) free(aln); } +void +inplace(Alg * (*f)(Alg *), Alg *alg) +{ + Alg *aux; + + aux = f(alg); + copy_alg(aux, alg); + free(aux); +} + Alg * inverse_alg(Alg *alg) { @@ -211,14 +284,10 @@ new_alg(char *str) Move j, m; alg = malloc(sizeof(Alg)); - alg->allocated = 30; - alg->move = malloc(alg->allocated * sizeof(Move)); - alg->inv = malloc(alg->allocated * sizeof(bool)); - alg->move_normal = malloc(alg->allocated * sizeof(Move)); - alg->move_inverse = malloc(alg->allocated * sizeof(Move)); - alg->len = 0; - alg->len_normal = 0; - alg->len_inverse = 0; + alg->move = malloc(30 * sizeof(Move)); + alg->inv = malloc(30 * sizeof(bool)); + alg->allocated = 30; + alg->len = 0; niss = false; for (i = 0; str[i]; i++) { @@ -227,13 +296,13 @@ new_alg(char *str) if (str[i] == '(' && niss) { fprintf(stderr, "Error reading moves: nested ( )\n"); - alg->len = alg->len_normal = alg->len_inverse = 0; + alg->len = 0; return alg; } if (str[i] == ')' && !niss) { fprintf(stderr, "Error reading moves: unmatched )\n"); - alg->len = alg->len_normal = alg->len_inverse = 0; + alg->len = 0; return alg; } @@ -300,7 +369,7 @@ new_alg(char *str) if (niss) { fprintf(stderr, "Error reading moves: unmatched (\n"); - alg->len = alg->len_normal = alg->len_inverse = 0; + alg->len = 0; } return alg; @@ -385,24 +454,11 @@ realloc_alg(Alg *alg, int n) fprintf(stderr, "something might go wrong.\n"); } - alg->move = realloc(alg->move, n * sizeof(int)); - alg->inv = realloc(alg->inv, n * sizeof(int)); - alg->move_normal = realloc(alg->move_normal, n * sizeof(int)); - alg->move_inverse = realloc(alg->move_inverse, n * sizeof(int)); + alg->move = realloc(alg->move, n * sizeof(int)); + alg->inv = realloc(alg->inv, n * sizeof(int)); alg->allocated = n; } -void -remove_last_move(Alg *a) -{ - a->len--; - - if (a->inv[a->len]) - a->len_inverse--; - else - a->len_normal--; -} - void swapmove(Move *m1, Move *m2) { @@ -413,34 +469,6 @@ swapmove(Move *m1, Move *m2) *m2 = aux; } -char * -trans_string(Trans t) -{ - static char trans_string_aux[NTRANS][20] = { - [uf] = "uf", [ur] = "ur", [ub] = "ub", [ul] = "ul", - [df] = "df", [dr] = "dr", [db] = "db", [dl] = "dl", - [rf] = "rf", [rd] = "rd", [rb] = "rb", [ru] = "ru", - [lf] = "lf", [ld] = "ld", [lb] = "lb", [lu] = "lu", - [fu] = "fu", [fr] = "fr", [fd] = "fd", [fl] = "fl", - [bu] = "bu", [br] = "br", [bd] = "bd", [bl] = "bl", - - [uf_mirror] = "uf*", [ur_mirror] = "ur*", - [ub_mirror] = "ub*", [ul_mirror] = "ul*", - [df_mirror] = "df*", [dr_mirror] = "dr*", - [db_mirror] = "db*", [dl_mirror] = "dl*", - [rf_mirror] = "rf*", [rd_mirror] = "rd*", - [rb_mirror] = "rb*", [ru_mirror] = "ru*", - [lf_mirror] = "lf*", [ld_mirror] = "ld*", - [lb_mirror] = "lb*", [lu_mirror] = "lu*", - [fu_mirror] = "fu*", [fr_mirror] = "fr*", - [fd_mirror] = "fd*", [fl_mirror] = "fl*", - [bu_mirror] = "bu*", [br_mirror] = "br*", - [bd_mirror] = "bd*", [bl_mirror] = "bl*", - }; - - return trans_string_aux[t]; -} - Alg * unniss(Alg *alg) { @@ -449,11 +477,48 @@ unniss(Alg *alg) ret = new_alg(""); - for (i = 0; i < alg->len_normal; i++) - append_move(ret, alg->move_normal[i], false); + for (i = 0; i < alg->len; i++) + if (!alg->inv[i]) + append_move(ret, alg->move[i], false); + + for (i = alg->len-1; i >= 0; i--) + if (alg->inv[i]) + append_move(ret, inverse_move(alg->move[i]), false); + + return ret; +} - for (i = 0; i < alg->len_inverse; i++) - append_move(ret, inverse_move(alg->move_inverse[i]), false); +void +init_moveset(Moveset *ms) +{ + int j; + uint64_t l, one; + Move m, l2, l1; + + one = 1; + + for (j = 0, m = U; m < NMOVES; m++) + if (ms->allowed(m)) + ms->sorted_moves[j++] = m; + ms->sorted_moves[j] = NULLMOVE; + + for (l1 = 0; l1 < NMOVES; l1++) { + for (l2 = 0; l2 < NMOVES; l2++) { + ms->mask[l2][l1] = 0; + for (l=0; ms->sorted_moves[l]!=NULLMOVE; l++) { + m = ms->sorted_moves[l]; + if (ms->allowed_next(l2, l1, m)) + ms->mask[l2][l1] |= (one<m2) */ -int compare_last(Alg *alg, Move m, bool inverse); void compose_alg(Alg *alg1, Alg *alg2); bool commute(Move m1, Move m2); void copy_alg(Alg *src, Alg *dst); void free_alg(Alg *alg); void free_alglist(AlgList *l); +void inplace(Alg * (*f)(Alg *), Alg *alg); Alg * inverse_alg(Alg *alg); Move inverse_move(Move m); char * move_string(Move m); +void movelist_to_position(Move *ml, int *pos); +void moveset_to_list(Moveset ms, Move *lst); Alg * new_alg(char *str); AlgList * new_alglist(); Alg * on_inverse(Alg *alg); void print_alg(Alg *alg, bool l); void print_alglist(AlgList *al, bool l); -void remove_last_move(Alg *alg); void swapmove(Move *m1, Move *m2); -char * trans_string(Trans t); /* Here because similar to move_string, move? */ Alg * unniss(Alg *alg); +void init_moveset(Moveset *ms); +void init_all_movesets(); + #endif 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 @@ -#define COMMANDS_C - #include "commands.h" -static bool read_cs(CommandArgs *args, char *str); +/* Arg parsing functions *****************************************************/ + +CommandArgs * gen_parse_args(int c, char **v); +CommandArgs * help_parse_args(int c, char **v); +CommandArgs * parse_only_scramble(int c, char **v); +CommandArgs * parse_no_arg(int c, char **v); +CommandArgs * solve_parse_args(int c, char **v); +CommandArgs * scramble_parse_args(int c, char **v); + +/* Exec functions ************************************************************/ + +static void gen_exec(CommandArgs *args); +static void cleanup_exec(CommandArgs *args); +static void invert_exec(CommandArgs *args); +static void solve_exec(CommandArgs *args); +static void scramble_exec(CommandArgs *args); +static void steps_exec(CommandArgs *args); +static void commands_exec(CommandArgs *args); +static void freemem_exec(CommandArgs *args); +static void print_exec(CommandArgs *args); +static void twophase_exec(CommandArgs *args); +static void help_exec(CommandArgs *args); +static void quit_exec(CommandArgs *args); +static void unniss_exec(CommandArgs *args); +static void version_exec(CommandArgs *args); + +/* Local functions ***********************************************************/ + +static bool read_step(CommandArgs *args, char *str); static bool read_scrtype(CommandArgs *args, char *str); static bool read_scramble(int c, char **v, CommandArgs *args); +/* Commands ******************************************************************/ + +Command +solve_cmd = { + .name = "solve", + .usage = "solve STEP [OPTIONS] SCRAMBLE", + .description = "Solve a step; see command steps for a list of steps", + .parse_args = solve_parse_args, + .exec = solve_exec +}; + +Command +scramble_cmd = { + .name = "scramble", + .usage = "scramble [TYPE] [-n N]", + .description = "Get a random-position scramble", + .parse_args = scramble_parse_args, + .exec = scramble_exec, +}; + +Command +gen_cmd = { + .name = "gen", + .usage = "gen [-t N]", + .description = "Generate all tables [using N threads]", + .parse_args = gen_parse_args, + .exec = gen_exec +}; + +Command +invert_cmd = { + .name = "invert", + .usage = "invert SCRAMBLE]", + .description = "Invert a scramble", + .parse_args = parse_only_scramble, + .exec = invert_exec, +}; + +Command +steps_cmd = { + .name = "steps", + .usage = "steps", + .description = "List available steps", + .parse_args = parse_no_arg, + .exec = steps_exec +}; + +Command +commands_cmd = { + .name = "commands", + .usage = "commands", + .description = "List available commands", + .parse_args = parse_no_arg, + .exec = commands_exec +}; + +Command +freemem_cmd = { + .name = "freemem", + .usage = "freemem", + .description = "free large tables from RAM", + .parse_args = parse_no_arg, + .exec = freemem_exec, +}; + +Command +print_cmd = { + .name = "print", + .usage = "print SCRAMBLE", + .description = "Print written description of the cube", + .parse_args = parse_only_scramble, + .exec = print_exec, +}; + +Command +help_cmd = { + .name = "help", + .usage = "help [COMMAND]", + .description = "Display nissy manual page or help on specific command", + .parse_args = help_parse_args, + .exec = help_exec, +}; + +Command +twophase_cmd = { + .name = "twophase", + .usage = "twophase", + .description = "Find a solution quickly using a 2-phase method", + .parse_args = parse_only_scramble, + .exec = twophase_exec, +}; + +Command +quit_cmd = { + .name = "quit", + .usage = "quit", + .description = "Quit nissy", + .parse_args = parse_no_arg, + .exec = quit_exec, +}; + +Command +cleanup_cmd = { + .name = "cleanup", + .usage = "cleanup SCRAMBLE", + .description = "Rewrite a scramble using only standard moves (HTM)", + .parse_args = parse_only_scramble, + .exec = cleanup_exec, +}; + +Command +unniss_cmd = { + .name = "unniss", + .usage = "unniss SCRAMBLE", + .description = "Rewrite a scramble without NISS", + .parse_args = parse_only_scramble, + .exec = unniss_exec, +}; + +Command +version_cmd = { + .name = "version", + .usage = "version", + .description = "print nissy version", + .parse_args = parse_no_arg, + .exec = version_exec, +}; + +Command *commands[] = { + &commands_cmd, + &freemem_cmd, + &gen_cmd, + &help_cmd, + &invert_cmd, + &print_cmd, + &quit_cmd, + &solve_cmd, + &scramble_cmd, + &steps_cmd, + &twophase_cmd, + &cleanup_cmd, + &unniss_cmd, + &version_cmd, + NULL +}; + +/* Other constants ***********************************************************/ + +char *scrtypes[20] = { "eo", "corners", "edges", "fmc", "dr", "htr", NULL }; + /* Arg parsing functions implementation **************************************/ CommandArgs * @@ -95,7 +271,7 @@ solve_parse_args(int c, char **v) a->opts->print_number = false; } else if (!strcmp(v[i], "-c")) { a->opts->count_only = true; - } else if (!read_cs(a, v[i])) { + } else if (!read_step(a, v[i])) { break; } } @@ -210,26 +386,17 @@ parse_no_arg(int c, char **v) /* Exec functions implementation *********************************************/ -void +static void solve_exec(CommandArgs *args) { Cube c; AlgList *sols; - Solver *solver[99]; - Threader *threader; - make_solved(&c); - apply_alg(args->scramble, &c); -/* TODO: adjust */ -/* threader = &threader_single;*/ - threader = &threader_eager; + init_all_movesets(); + init_symcoord(); -/* TODO: adjust */ - int i; - for (i = 0; args->cs->step[i] != NULL; i++) - solver[i] = new_stepsolver_lazy(args->cs->step[i]); - solver[i] = NULL; - sols = solve(&c, args->opts, solver, threader); + c = apply_alg(args->scramble, (Cube){0}); + sols = solve(c, args->step, args->opts); if (args->opts->count_only) printf("%d\n", sols->len); @@ -239,67 +406,85 @@ solve_exec(CommandArgs *args) free_alglist(sols); } -void +static void scramble_exec(CommandArgs *args) { Cube cube; + CubeArray *arr; Alg *scr, *ruf, *aux; - int i, j, eo, ep, co, cp; + int i, j, eo, ep, co, cp, a[12]; + int eparr[12] = { [8] = 8, [9] = 9, [10] = 10, [11] = 11 }; uint64_t ui, uj, uk; + init_all_movesets(); + init_symcoord(); + srand(time(NULL)); for (i = 0; i < args->n; i++) { if (!strcmp(args->scrtype, "dr")) { - ui = rand() % FACTORIAL8; - uj = rand() % FACTORIAL8; - uk = rand() % FACTORIAL4; - - make_solved(&cube); - index_to_perm(ui, 8, cube.cp); - index_to_perm(uj, 8, cube.ep); - index_to_perm(uk, 4, cube.ep + 8); - for (j = 8; j < 12; j++) - cube.ep[j] += 8; + /* Warning: cube is inconsistent because of side CO * + * and EO on U/D. But solve_2phase only solves drfin * + * in this case, so it should be ok. * + * TODO: check this properly * + * Moreover we again need to fix parity after * + * generating epose manually */ + do { + ui = rand() % FACTORIAL8; + uj = rand() % FACTORIAL8; + uk = rand() % FACTORIAL4; + + index_to_perm(ui, 8, eparr); + arr = malloc(sizeof(CubeArray)); + arr->ep = eparr; + cube = arrays_to_cube(arr, pf_ep); + free(arr); + + cube.cp = uj; + cube.epose = uk; + } while (!is_admissible(cube)); } else if (!strcmp(args->scrtype, "htr")) { - make_solved(&cube); - /* TODO */ + /* antindex_htrfin() returns a consistent * + * cube, except possibly for parity */ + do { + ui = rand() % (24*24/6); + cube = (Cube){0}; + cube.cp = cornershtrfin_ant[ui]; + cube.epose = rand() % 24; + cube.eposs = rand() % 24; + cube.eposm = rand() % 24; + } while (!is_admissible(cube)); } else { - ep = rand() % FACTORIAL12; - cp = rand() % FACTORIAL8; eo = rand() % POW2TO11; + ep = rand() % FACTORIAL12; co = rand() % POW3TO7; + cp = rand() % FACTORIAL8; if (!strcmp(args->scrtype, "eo")) { eo = 0; } else if (!strcmp(args->scrtype, "corners")) { eo = 0; ep = 0; + index_to_perm(cp, 8, a); + if (perm_sign(a, 8) == 1) { + swap(&a[0], &a[1]); + cp = perm_to_index(a, 8); + } } else if (!strcmp(args->scrtype, "edges")) { co = 0; cp = 0; + index_to_perm(ep, 12, a); + if (perm_sign(a, 12) == 1) { + swap(&a[0], &a[1]); + ep = perm_to_index(a, 12); + } } - - make_solved(&cube); - index_to_perm(ep, 12, cube.ep); - index_to_perm(cp, 8, cube.cp); - int_to_sum_zero_array(eo, 2, 12, cube.eo); - int_to_sum_zero_array(co, 3, 8, cube.co); - } - - if (!is_admissible(&cube)) { - if (!strcmp(args->scrtype, "corners")) - swap(&cube.cp[UFR], &cube.cp[UFL]); - else - swap(&cube.ep[UF], &cube.ep[UB]); + cube = fourval_to_cube(eo, ep, co, cp); } /* TODO: can be optimized for htr and dr using htrfin, drfin */ - /* - TODO: solve_2phase was removed - scr = solve_2phase(&cube, 1); - */ + scr = solve_2phase(cube, 1); if (!strcmp(args->scrtype, "fmc")) { aux = new_alg(""); @@ -328,22 +513,23 @@ scramble_exec(CommandArgs *args) } } -void +static void gen_exec(CommandArgs *args) { -/* TODO: int i; fprintf(stderr, "Generating coordinates...\n"); + init_all_movesets(); + init_symcoord(); + fprintf(stderr, "Generating pruning tables...\n"); for (i = 0; all_pd[i] != NULL; i++) genptable(all_pd[i], args->opts->nthreads); -*/ fprintf(stderr, "Done!\n"); } -void +static void invert_exec(CommandArgs *args) { Alg *inv; @@ -354,16 +540,16 @@ invert_exec(CommandArgs *args) free_alg(inv); } -void +static void steps_exec(CommandArgs *args) { int i; - for (i = 0; csteps[i] != NULL; i++) - printf("%-15s %s\n", csteps[i]->shortname, csteps[i]->name); + for (i = 0; steps[i] != NULL; i++) + printf("%-15s %s\n", steps[i]->shortname, steps[i]->name); } -void +static void commands_exec(CommandArgs *args) { int i; @@ -373,10 +559,9 @@ commands_exec(CommandArgs *args) } -void +static void freemem_exec(CommandArgs *args) { -/* TODO: int i; for (i = 0; all_pd[i] != NULL; i++) @@ -384,36 +569,35 @@ freemem_exec(CommandArgs *args) for (i = 0; all_sd[i] != NULL; i++) free_sd(all_sd[i]); -*/ + + /* TODO: invtables are also large, but for now they are * + * statically allocated. Consider releasing those too. */ } -void +static void print_exec(CommandArgs *args) { - Cube c; - - make_solved(&c); - apply_alg(args->scramble, &c); - print_cube(&c); + init_moves(); + print_cube(apply_alg(args->scramble, (Cube){0})); } -/* -void +static void twophase_exec(CommandArgs *args) { Cube c; Alg *sol; - make_solved(&c); - apply_alg(args->scramble, &c); - sol = solve_2phase(&c, 1); + init_all_movesets(); + init_symcoord(); + + c = apply_alg(args->scramble, (Cube){0}); + sol = solve_2phase(c, 1); print_alg(sol, false); free_alg(sol); } -*/ -void +static void help_exec(CommandArgs *args) { if (args->command == NULL) { @@ -427,7 +611,7 @@ help_exec(CommandArgs *args) " system (such as Linux or MacOS) or in pdf and html" " format in the docs folder.\n" "Nissy is available for free at " - "https://nissy.tronto.net\n" + "https://github.com/sebastianotronto/nissy\n" ); } else { printf("Command %s: %s\nusage: %s\n", args->command->name, @@ -435,24 +619,26 @@ help_exec(CommandArgs *args) } } -void +static void quit_exec(CommandArgs *args) { exit(0); } -void +static void cleanup_exec(CommandArgs *args) { Alg *alg; + init_moves(); + alg = cleanup(args->scramble); print_alg(alg, false); free_alg(alg); } -void +static void unniss_exec(CommandArgs *args) { Alg *aux; @@ -462,7 +648,7 @@ unniss_exec(CommandArgs *args) free(aux); } -void +static void version_exec(CommandArgs *args) { printf(VERSION"\n"); @@ -505,8 +691,6 @@ static bool read_scrtype(CommandArgs *args, char *str) { int i; - static char *scrtypes[20] = - { "eo", "corners", "edges", "fmc", "dr", "htr", NULL }; for (i = 0; scrtypes[i] != NULL; i++) { if (!strcmp(scrtypes[i], str)) { @@ -519,13 +703,13 @@ read_scrtype(CommandArgs *args, char *str) } static bool -read_cs(CommandArgs *args, char *str) +read_step(CommandArgs *args, char *str) { int i; - for (i = 0; csteps[i] != NULL; i++) { - if (!strcmp(csteps[i]->shortname, str)) { - args->cs = csteps[i]; + for (i = 0; steps[i] != NULL; i++) { + if (!strcmp(steps[i]->shortname, str)) { + args->step = steps[i]; return true; } } @@ -562,7 +746,7 @@ new_args() args->opts = malloc(sizeof(SolveOptions)); /* step and command are static */ - args->cs = csteps[0]; /* default: first step in list */ + args->step = steps[0]; /* default: first step in list */ args->command = NULL; 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 @@ #include "solve.h" #include "steps.h" -#include "solver_step.h" -#include "threader_single.h" -#include "threader_eager.h" void free_args(CommandArgs *args); CommandArgs * new_args(); -/* Arg parsing functions *****************************************************/ - -CommandArgs * gen_parse_args(int c, char **v); -CommandArgs * help_parse_args(int c, char **v); -CommandArgs * parse_only_scramble(int c, char **v); -CommandArgs * parse_no_arg(int c, char **v); -CommandArgs * solve_parse_args(int c, char **v); -CommandArgs * scramble_parse_args(int c, char **v); - -/* Exec functions ************************************************************/ - -void gen_exec(CommandArgs *args); -void cleanup_exec(CommandArgs *args); -void invert_exec(CommandArgs *args); -void solve_exec(CommandArgs *args); -void scramble_exec(CommandArgs *args); -void steps_exec(CommandArgs *args); -void commands_exec(CommandArgs *args); -void freemem_exec(CommandArgs *args); -void print_exec(CommandArgs *args); -/*void twophase_exec(CommandArgs *args);*/ -void help_exec(CommandArgs *args); -void quit_exec(CommandArgs *args); -void unniss_exec(CommandArgs *args); -void version_exec(CommandArgs *args); - -/* Commands ******************************************************************/ - -#ifndef COMMANDS_C - -extern Command cleanup_cmd; -extern Command commands_cmd; -extern Command freemem_cmd; -extern Command gen_cmd; -extern Command help_cmd; -extern Command invert_cmd; -extern Command print_cmd; -extern Command quit_cmd; -extern Command scramble_cmd; -extern Command solve_cmd; -extern Command steps_cmd; -extern Command unniss_cmd; -extern Command version_cmd; - -extern Command *commands[]; - -#else - -Command -solve_cmd = { - .name = "solve", - .usage = "solve STEP [OPTIONS] SCRAMBLE", - .description = "Solve a step; see command steps for a list of steps", - .parse_args = solve_parse_args, - .exec = solve_exec -}; - -Command -scramble_cmd = { - .name = "scramble", - .usage = "scramble [TYPE] [-n N]", - .description = "Get a random-position scramble", - .parse_args = scramble_parse_args, - .exec = scramble_exec, -}; - -Command -gen_cmd = { - .name = "gen", - .usage = "gen [-t N]", - .description = "Generate all tables [using N threads]", - .parse_args = gen_parse_args, - .exec = gen_exec -}; - -Command -invert_cmd = { - .name = "invert", - .usage = "invert SCRAMBLE]", - .description = "Invert a scramble", - .parse_args = parse_only_scramble, - .exec = invert_exec, -}; - -Command -steps_cmd = { - .name = "steps", - .usage = "steps", - .description = "List available steps", - .parse_args = parse_no_arg, - .exec = steps_exec -}; - -Command -commands_cmd = { - .name = "commands", - .usage = "commands", - .description = "List available commands", - .parse_args = parse_no_arg, - .exec = commands_exec -}; - -Command -freemem_cmd = { - .name = "freemem", - .usage = "freemem", - .description = "free large tables from RAM", - .parse_args = parse_no_arg, - .exec = freemem_exec, -}; - -Command -print_cmd = { - .name = "print", - .usage = "print SCRAMBLE", - .description = "Print written description of the cube", - .parse_args = parse_only_scramble, - .exec = print_exec, -}; - -Command -help_cmd = { - .name = "help", - .usage = "help [COMMAND]", - .description = "Display nissy manual page or help on specific command", - .parse_args = help_parse_args, - .exec = help_exec, -}; - -/* -Command -twophase_cmd = { - .name = "twophase", - .usage = "twophase", - .description = "Find a solution quickly using a 2-phase method", - .parse_args = parse_only_scramble, - .exec = twophase_exec, -}; -*/ - -Command -quit_cmd = { - .name = "quit", - .usage = "quit", - .description = "Quit nissy", - .parse_args = parse_no_arg, - .exec = quit_exec, -}; - -Command -cleanup_cmd = { - .name = "cleanup", - .usage = "cleanup SCRAMBLE", - .description = "Rewrite a scramble using only standard moves (HTM)", - .parse_args = parse_only_scramble, - .exec = cleanup_exec, -}; - -Command -unniss_cmd = { - .name = "unniss", - .usage = "unniss SCRAMBLE", - .description = "Rewrite a scramble without NISS", - .parse_args = parse_only_scramble, - .exec = unniss_exec, -}; - -Command -version_cmd = { - .name = "version", - .usage = "version", - .description = "print nissy version", - .parse_args = parse_no_arg, - .exec = version_exec, -}; - -Command *commands[] = { - &commands_cmd, - &freemem_cmd, - &gen_cmd, - &help_cmd, - &invert_cmd, - &print_cmd, - &quit_cmd, - &solve_cmd, - &scramble_cmd, - &steps_cmd, -/* &twophase_cmd,*/ - &cleanup_cmd, - &unniss_cmd, - &version_cmd, - NULL -}; - -#endif +extern Command * commands[]; #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 @@ -#define COORD_C - #include "coord.h" -static void gen_coord_comp(Coordinate *coord); -static void gen_coord_sym(Coordinate *coord); -static bool read_coord_mtable(Coordinate *coord); -static bool read_coord_sd(Coordinate *coord); -static bool read_coord_ttable(Coordinate *coord); -static bool write_coord_mtable(Coordinate *coord); -static bool write_coord_sd(Coordinate *coord); -static bool write_coord_ttable(Coordinate *coord); +static uint64_t index_eofb(Cube cube); +static uint64_t index_eofbepos(Cube cube); +static uint64_t index_epud(Cube cube); +static uint64_t index_coud(Cube cube); +static uint64_t index_corners(Cube cube); +static uint64_t index_cp(Cube cube); +static uint64_t index_cphtr(Cube cube); +static uint64_t index_cornershtr(Cube cube); +static uint64_t index_cornershtrfin(Cube cube); +static uint64_t index_drud(Cube cube); +static uint64_t index_drud_eofb(Cube cube); +static uint64_t index_htr_drud(Cube cube); +static uint64_t index_htrfin(Cube cube); +static uint64_t index_cpud_separate(Cube cube); + +static uint64_t move_eofb(Move m, uint64_t ind); +static uint64_t move_eofbepos(Move m, uint64_t ind); +static uint64_t move_epud(Move m, uint64_t ind); +static uint64_t move_coud(Move m, uint64_t ind); +static uint64_t move_corners(Move m, uint64_t ind); +static uint64_t move_cp(Move m, uint64_t ind); +static uint64_t move_cphtr(Move m, uint64_t ind); +static uint64_t move_cornershtr(Move m, uint64_t ind); +static uint64_t move_cornershtrfin(Move m, uint64_t ind); +static uint64_t move_drud(Move m, uint64_t ind); +static uint64_t move_drud_eofb(Move m, uint64_t ind); +static uint64_t move_htr_drud(Move m, uint64_t ind); +static uint64_t move_htrfin(Move m, uint64_t ind); +static uint64_t move_cpud_separate(Move m, uint64_t ind); + +static void init_cphtr_cosets(); +static void init_cphtr_left_cosets_bfs(int i, int c); +static void init_cphtr_right_cosets_color(int i, int c); +static void init_cpud_separate(); +static void init_cornershtrfin(); +static void init_htr_eposs(); + + +/* All sorts of useful costants and tables **********************************/ + +static int cphtr_left_cosets[FACTORIAL8]; +static int cphtr_right_cosets[FACTORIAL8]; +static int cphtr_right_rep[BINOM8ON4*6]; +int cpud_separate_ind[FACTORIAL8]; +int cpud_separate_ant[BINOM8ON4]; +static int cornershtrfin_ind[FACTORIAL8]; +int cornershtrfin_ant[24*24/6]; +static int htr_eposs_ind[BINOM12ON4]; +static int htr_eposs_ant[BINOM8ON4]; + +/* Coordinates and their implementation **************************************/ + +Coordinate +coord_eofb = { + .index = index_eofb, + .max = POW2TO11, + .move = move_eofb, +}; + +Coordinate +coord_eofbepos = { + .index = index_eofbepos, + .max = POW2TO11 * BINOM12ON4, + .move = move_eofbepos, +}; + +Coordinate +coord_coud = { + .index = index_coud, + .max = POW3TO7, + .move = move_coud, +}; + +Coordinate +coord_corners = { + .index = index_corners, + .max = POW3TO7 * FACTORIAL8, + .move = move_corners, +}; + +Coordinate +coord_cp = { + .index = index_cp, + .max = FACTORIAL8, + .move = move_cp, +}; + +Coordinate +coord_cphtr = { + .index = index_cphtr, + .max = BINOM8ON4 * 6, + .move = move_cphtr, +}; + +Coordinate +coord_cornershtr = { + .index = index_cornershtr, + .max = POW3TO7 * BINOM8ON4 * 6, + .move = move_cornershtr, +}; + +Coordinate +coord_cornershtrfin = { + .index = index_cornershtrfin, + .max = 24*24/6, + .move = move_cornershtrfin, +}; + +Coordinate +coord_epud = { + .index = index_epud, + .max = FACTORIAL8, + .move = move_epud, +}; + +Coordinate +coord_drud = { + .index = index_drud, + .max = POW2TO11 * POW3TO7 * BINOM12ON4, + .move = move_drud, +}; + +Coordinate +coord_htr_drud = { + .index = index_htr_drud, + .max = BINOM8ON4 * 6 * BINOM8ON4, + .move = move_htr_drud, +}; + +Coordinate +coord_htrfin = { + .index = index_htrfin, + .max = 24 * 24 * 24 *24 * 24 / 6, /* should be /12 but it's ok */ + .move = move_htrfin, +}; + +Coordinate +coord_drud_eofb = { + .index = index_drud_eofb, + .max = POW3TO7 * BINOM12ON4, + .move = move_drud_eofb, +}; + +Coordinate +coord_cpud_separate = { + .index = index_cpud_separate, + .max = BINOM8ON4, + .move = move_cpud_separate, +}; /* Indexers ******************************************************************/ -uint64_t -index_eofb(Cube *cube) -{ - return (uint64_t)digit_array_to_int(cube->eo, 11, 2); -} - -uint64_t -index_coud(Cube *cube) +static uint64_t +index_eofb(Cube cube) { - return (uint64_t)digit_array_to_int(cube->co, 7, 3); + return cube.eofb; } -uint64_t -index_cp(Cube *cube) +static uint64_t +index_eofbepos(Cube cube) { - return (uint64_t)perm_to_index(cube->cp, 8); + return (cube.epose / FACTORIAL4) * POW2TO11 + cube.eofb; } -uint64_t -index_cpudsep(Cube *cube) +static uint64_t +index_epud(Cube cube) { - int i, c[8]; + uint64_t ret; + CubeArray *arr = new_cubearray(cube, pf_ep); - for (i = 0; i < 8; i++) - c[i] = cube->cp[i] < 4 ? 0 : 1; + ret = perm_to_index(arr->ep, 8); + free_cubearray(arr, pf_ep); - return (uint64_t)subset_to_index(c, 8, 4); + return ret; } -uint64_t -index_epe(Cube *cube) +static uint64_t +index_coud(Cube cube) { - int i, e[4]; - - for (i = 0; i < 4; i++) - e[i] = cube->ep[i+8] - 8; - - return (uint64_t)perm_to_index(e, 4); + return cube.coud; } -uint64_t -index_epud(Cube *cube) +static uint64_t +index_corners(Cube cube) { - return (uint64_t)perm_to_index(cube->ep, 8); + return cube.coud * FACTORIAL8 + cube.cp; } -uint64_t -index_epos(Cube *cube) +static uint64_t +index_cp(Cube cube) { - int i, a[12]; - - for (i = 0; i < 12; i++) - a[i] = (cube->ep[i] < 8) ? 0 : 1; - - return (uint64_t)subset_to_index(a, 12, 4); + return cube.cp; } -uint64_t -index_eposepe(Cube *cube) +static uint64_t +index_cphtr(Cube cube) { - int i, j, e[4]; - uint64_t epos, epe; - - epos = (uint64_t)index_epos(cube); - for (i = 0, j = 0; i < 12; i++) - if (cube->ep[i] >= 8) - e[j++] = cube->ep[i] - 8; - epe = (uint64_t)perm_to_index(e, 4); - - return epos * FACTORIAL4 + epe; + return cphtr_right_cosets[cube.cp]; } -/* Inverse indexers **********************************************************/ - -void -invindex_eofb(uint64_t ind, Cube *cube) +static uint64_t +index_cornershtr(Cube cube) { - int_to_sum_zero_array(ind, 2, 12, cube->eo); + return cube.coud * BINOM8ON4 * 6 + index_cphtr(cube); } -void -invindex_coud(uint64_t ind, Cube *cube) +static uint64_t +index_cornershtrfin(Cube cube) { - int_to_sum_zero_array(ind, 3, 8, cube->co); + return cornershtrfin_ind[cube.cp]; } -void -invindex_cp(uint64_t ind, Cube *cube) +static uint64_t +index_drud(Cube cube) { - index_to_perm(ind, 8, cube->cp); -} - -void -invindex_cpudsep(uint64_t ind, Cube *cube) -{ - int i, j, k, c[8]; - - index_to_subset(ind, 8, 4, c); - for (i = 0, j = 0, k = 4; i < 8; i++) - cube->cp[i] = c[i] == 0 ? j++ : k++; -} + uint64_t a, b, c; + a = cube.eofb; + b = cube.coud; + c = cube.epose / FACTORIAL4; -void -invindex_epe(uint64_t ind, Cube *cube) -{ - int i; + b *= POW2TO11; + c *= POW2TO11 * POW3TO7; - index_to_perm(ind, 4, &cube->ep[8]); - for (i = 0; i < 4; i++) - cube->ep[i+8] += 8; + return a + b + c; } -void -invindex_epud(uint64_t ind, Cube *cube) +static uint64_t +index_drud_eofb(Cube cube) { - index_to_perm(ind, 8, cube->ep); + return index_drud(cube) / POW2TO11; } -void -invindex_epos(uint64_t ind, Cube *cube) +static uint64_t +index_htr_drud(Cube cube) { - int i, j, k; + uint64_t a, b; - index_to_subset(ind, 12, 4, cube->ep); - for (i = 0, j = 0, k = 8; i < 12; i++) - if (cube->ep[i] == 0) - cube->ep[i] = j++; - else - cube->ep[i] = k++; -} - -void -invindex_eposepe(uint64_t ind, Cube *cube) -{ - int i, j, k, e[4]; - uint64_t epos, epe; + a = index_cphtr(cube); + b = htr_eposs_ind[cube.eposs/24]; - epos = ind / FACTORIAL4; - epe = ind % FACTORIAL4; - - index_to_subset(epos, 12, 4, cube->ep); - index_to_perm(epe, 4, e); - - for (i = 0, j = 0, k = 0; i < 12; i++) - if (cube->ep[i] == 0) - cube->ep[i] = j++; - else - cube->ep[i] = e[k++] + 8; + return a * BINOM8ON4 + b; } -/* Other local functions *****************************************************/ - -uint64_t -indexers_getmax(Indexer **is) +static uint64_t +index_htrfin(Cube cube) { - int i; - uint64_t max = 1; + uint64_t epe, eps, epm, cp, ep; - for (i = 0; is[i] != NULL; i++) - max *= is[i]->n; + epe = cube.epose % 24; + eps = cube.eposs % 24; + epm = cube.eposm % 24; + ep = (epe * 24 + eps) *24 + epm; + cp = index_cornershtrfin(cube); - return max; + return cp * 24 * 24 * 24 + ep; } -uint64_t -indexers_getind(Indexer **is, Cube *c) +static uint64_t +index_cpud_separate(Cube cube) { - int i; - uint64_t max = 0; + return cpud_separate_ind[cube.cp]; +} - for (i = 0; is[i] != NULL; i++) { - max *= is[i]->n; - max += is[i]->index(c); - } +/* Coordinate movers *********************************************************/ - return max; +static uint64_t +move_eofb(Move m, uint64_t ind) +{ + return eofb_mtable[m][ind]; } -void -indexers_makecube(Indexer **is, uint64_t ind, Cube *c) +static uint64_t +move_eofbepos(Move m, uint64_t ind) { - /* Warning: anti-indexers are applied in the same order as indexers. */ - /* We assume order does not matter, but it would make more sense to */ - /* apply them in reverse. */ + uint64_t a, b; - int i; - uint64_t m; + a = epose_mtable[m][(ind / POW2TO11)*24]; + b = eofb_mtable[m][ind % POW2TO11]; - make_solved(c); - m = indexers_getmax(is); - for (i = 0; is[i] != NULL; i++) { - m /= is[i]->n; - is[i]->to_cube(ind / m, c); - ind %= m; - } + return (a/24) * POW2TO11 + b; } -static void -gen_coord_comp(Coordinate *coord) +static uint64_t +move_epud(Move m, uint64_t ind) { + /* TODO: save to file? */ + static bool initialized = false; + static int a[12] = { [8] = 8, [9] = 9, [10] = 10, [11] = 11 }; + static int shortlist[NMOVES] = { + [U] = 0, [U2] = 1, [U3] = 2, [D] = 3, [D2] = 4, [D3] = 5, + [R2] = 6, [L2] = 7, [F2] = 8, [B2] = 9 + }; + static uint64_t aux[10][FACTORIAL8]; uint64_t ui; - Cube c, mvd; - Move m; - Trans t; - - coord->max = indexers_getmax(coord->i); - - for (m = 0; m < NMOVES; m++) - coord->mtable[m] = malloc(coord->max * sizeof(uint64_t)); - - for (t = 0; t < NTRANS; t++) - coord->ttable[t] = malloc(coord->max * sizeof(uint64_t)); - - if (!read_coord_mtable(coord)) { - fprintf(stderr, "%s: generating mtable\n", coord->name); - - for (ui = 0; ui < coord->max; ui++) { - indexers_makecube(coord->i, ui, &c); - for (m = 0; m < NMOVES; m++) { - copy_cube(&c, &mvd); - apply_move(m, &mvd); - coord->mtable[m][ui] = - indexers_getind(coord->i, &mvd); - } - } - if (!write_coord_mtable(coord)) - fprintf(stderr, "%s: error writing mtable\n", - coord->name); - - fprintf(stderr, "%s: mtable generated\n", coord->name); + int j; + Move mj; + Cube c; + CubeArray *arr, *auxarr; + + if (!moveset_drud.allowed(m)) { + fprintf(stderr, "Move not allowed for epud\n" + "This is a bug, please report\n"); + return coord_epud.max; } - if (!read_coord_ttable(coord)) { - fprintf(stderr, "%s: generating ttable\n", coord->name); - - for (ui = 0; ui < coord->max; ui++) { - indexers_makecube(coord->i, ui, &c); - for (t = 0; t < NTRANS; t++) { - copy_cube(&c, &mvd); - apply_trans(t, &mvd); - coord->ttable[t][ui] = - indexers_getind(coord->i, &mvd); + if (!initialized) { + auxarr = malloc(sizeof(CubeArray)); + auxarr->ep = a; + for (ui = 0; ui < coord_epud.max; ui++) { + index_to_perm(ui, 8, a); + c = arrays_to_cube(auxarr, pf_ep); + for (j = 0; moveset_drud.sorted_moves[j] != NULLMOVE; + j++) { + mj = moveset_drud.sorted_moves[j]; + arr = new_cubearray(apply_move(mj, c), pf_ep); + aux[shortlist[mj]][ui] = + perm_to_index(arr->ep, 8); + free_cubearray(arr, pf_ep); } } - if (!write_coord_ttable(coord)) - fprintf(stderr, "%s: error writing ttable\n", - coord->name); + free(auxarr); + + initialized = true; } + + return aux[shortlist[m]][ind]; } -static void -gen_coord_sym(Coordinate *coord) +static uint64_t +move_coud(Move m, uint64_t ind) { - uint64_t i, in, ui, uj, uu, M, nr; - int j; - Move m; - Trans t; - - M = coord->base[0]->max; - coord->selfsim = malloc(M * sizeof(uint64_t)); - coord->symclass = malloc(M * sizeof(uint64_t)); - coord->symrep = malloc(M * sizeof(uint64_t)); - coord->transtorep = malloc(M * sizeof(Trans)); - - if (!read_coord_sd(coord)) { - fprintf(stderr, "%s: generating syms\n", coord->name); + return coud_mtable[m][ind]; +} - for (i = 0; i < M; i++) - coord->symclass[i] = M+1; +static uint64_t +move_corners(Move m, uint64_t ind) +{ + uint64_t a, b; - for (i = 0, nr = 0; i < M; i++) { - if (coord->symclass[i] != M+1) - continue; + a = coud_mtable[m][ind / FACTORIAL8]; + b = cp_mtable[m][ind % FACTORIAL8]; - coord->symrep[nr] = i; - coord->transtorep[i] = uf; - coord->selfsim[nr] = (uint64_t)0; - for (j = 0; j < coord->tgrp->n; j++) { - t = coord->tgrp->t[j]; - in = trans_coord(coord->base[0], t, i); - coord->symclass[in] = nr; - if (in == i) - coord->selfsim[nr] |= ((uint64_t)1<transtorep[in] = - inverse_trans(t); - } - nr++; - } + return a * FACTORIAL8 + b; +} - coord->max = nr; +static uint64_t +move_cp(Move m, uint64_t ind) +{ + return cp_mtable[m][ind]; +} - fprintf(stderr, "%s: found %" PRIu64 " classes\n", - coord->name, nr); - if (!write_coord_sd(coord)) - fprintf(stderr, "%s: error writing symdata\n", - coord->name); - } +static uint64_t +move_cphtr(Move m, uint64_t ind) +{ + static bool initialized = false; + static uint64_t aux[NMOVES][BINOM8ON4*6]; + uint64_t ui; + Move j; - coord->symrep = realloc(coord->symrep, coord->max*sizeof(uint64_t)); - coord->selfsim = realloc(coord->selfsim, coord->max*sizeof(uint64_t)); + if (!initialized) { + for (ui = 0; ui < BINOM8ON4*6; ui++) + for (j = U; j < NMOVES; j++) + aux[j][ui] = cphtr_right_cosets[ + cp_mtable[j][cphtr_right_rep[ui]]]; - for (m = 0; m < NMOVES; m++) { - coord->mtable[m] = malloc(coord->max*sizeof(uint64_t)); - coord->ttrep_move[m] = malloc(coord->max*sizeof(Trans)); + initialized = true; } - if (!read_coord_mtable(coord)) { - for (ui = 0; ui < coord->max; ui++) { - uu = coord->symrep[ui]; - for (m = 0; m < NMOVES; m++) { - uj = move_coord(coord->base[0], m, uu, NULL); - coord->mtable[m][ui] = coord->symclass[uj]; - coord->ttrep_move[m][ui] = - coord->transtorep[uj]; - } - } - if (!write_coord_mtable(coord)) - fprintf(stderr, "%s: error writing mtable\n", - coord->name); - } + return aux[m][ind]; } -static bool -read_coord_mtable(Coordinate *coord) +static uint64_t +move_cornershtr(Move m, uint64_t ind) { - FILE *f; - char fname[strlen(tabledir)+256]; - Move m; - uint64_t M; - bool r; + uint64_t a, b; - strcpy(fname, tabledir); - strcat(fname, "/mt_"); - strcat(fname, coord->name); + a = coud_mtable[m][ind/(BINOM8ON4 * 6)]; + b = move_cphtr(m, ind % (BINOM8ON4 * 6)); - if ((f = fopen(fname, "rb")) == NULL) - return false; - - M = coord->max; - r = true; - for (m = 0; m < NMOVES; m++) - r = r && fread(coord->mtable[m], sizeof(uint64_t), M, f) == M; - - if (coord->type == SYM_COORD) - for (m = 0; m < NMOVES; m++) - r = r && fread(coord->ttrep_move[m], - sizeof(Trans), M, f) == M; - - fclose(f); - return r; + return a * BINOM8ON4 * 6 + b; } -static bool -read_coord_sd(Coordinate *coord) +static uint64_t +move_cornershtrfin(Move m, uint64_t ind) { - FILE *f; - char fname[strlen(tabledir)+256]; - uint64_t M, N; - bool r; - - strcpy(fname, tabledir); - strcat(fname, "/sd_"); - strcat(fname, coord->name); + int a; - if ((f = fopen(fname, "rb")) == NULL) - return false; + a = cp_mtable[m][cornershtrfin_ant[ind]]; - r = true; - r = r && fread(&coord->max, sizeof(uint64_t), 1, f) == 1; - M = coord->max; - N = coord->base[0]->max; - r = r && fread(coord->symrep, sizeof(uint64_t), M, f) == M; - r = r && fread(coord->selfsim, sizeof(uint64_t), M, f) == M; - r = r && fread(coord->symclass, sizeof(uint64_t), N, f) == N; - r = r && fread(coord->transtorep, sizeof(Trans), N, f) == N; - - fclose(f); - return r; + return cornershtrfin_ind[a]; } -static bool -read_coord_ttable(Coordinate *coord) +static uint64_t +move_drud(Move m, uint64_t ind) { - FILE *f; - char fname[strlen(tabledir)+256]; - Trans t; - uint64_t M; - bool r; - - strcpy(fname, tabledir); - strcat(fname, "/tt_"); - strcat(fname, coord->name); - - if ((f = fopen(fname, "rb")) == NULL) - return false; + uint64_t a, b, c; - M = coord->max; - r = true; - for (t = 0; t < NTRANS; t++) - r = r && fread(coord->ttable[t], sizeof(uint64_t), M, f) == M; + a = eofb_mtable[m][ind % POW2TO11]; + b = coud_mtable[m][(ind / POW2TO11) % POW3TO7]; + c = epose_mtable[m][ind / (POW2TO11 * POW3TO7)]; - fclose(f); - return r; + return a + (b + c * POW3TO7) * POW2TO11; } -static bool -write_coord_mtable(Coordinate *coord) +static uint64_t +move_drud_eofb(Move m, uint64_t ind) { - FILE *f; - char fname[strlen(tabledir)+256]; - Move m; - uint64_t M; - bool r; - - strcpy(fname, tabledir); - strcat(fname, "/mt_"); - strcat(fname, coord->name); - - if ((f = fopen(fname, "wb")) == NULL) - return false; - - M = coord->max; - r = true; - for (m = 0; m < NMOVES; m++) - r = r && fwrite(coord->mtable[m], sizeof(uint64_t), M, f) == M; + uint64_t a, b; - if (coord->type == SYM_COORD) - for (m = 0; m < NMOVES; m++) - r = r && fwrite(coord->ttrep_move[m], - sizeof(Trans), M, f) == M; + a = coud_mtable[m][ind % POW3TO7]; + b = epose_mtable[m][(ind / POW3TO7) * 24] / 24; - fclose(f); - return r; + return a + b * POW3TO7; } -static bool -write_coord_sd(Coordinate *coord) +static uint64_t +move_htr_drud(Move m, uint64_t ind) { - FILE *f; - char fname[strlen(tabledir)+256]; - uint64_t M, N; - bool r; + uint64_t a, b; - strcpy(fname, tabledir); - strcat(fname, "/sd_"); - strcat(fname, coord->name); + a = move_cphtr(m, ind/BINOM8ON4); + b = eposs_mtable[m][htr_eposs_ant[ind%BINOM8ON4]]; - if ((f = fopen(fname, "wb")) == NULL) - return false; - - r = true; - M = coord->max; - N = coord->base[0]->max; - r = r && fwrite(&coord->max, sizeof(uint64_t), 1, f) == 1; - r = r && fwrite(coord->symrep, sizeof(uint64_t), M, f) == M; - r = r && fwrite(coord->selfsim, sizeof(uint64_t), M, f) == M; - r = r && fwrite(coord->symclass, sizeof(uint64_t), N, f) == N; - r = r && fwrite(coord->transtorep, sizeof(Trans), N, f) == N; - - fclose(f); - return r; + return a*BINOM8ON4 + htr_eposs_ind[b/24]; } -static bool -write_coord_ttable(Coordinate *coord) +static uint64_t +move_htrfin(Move m, uint64_t ind) { - FILE *f; - char fname[strlen(tabledir)+256]; - Trans t; - uint64_t M; - bool r; - - strcpy(fname, tabledir); - strcat(fname, "/tt_"); - strcat(fname, coord->name); - - if ((f = fopen(fname, "wb")) == NULL) - return false; + uint64_t a, b, bm, bs, be; - M = coord->max; - r = true; - for (t = 0; t < NTRANS; t++) - r = r && fwrite(coord->ttable[t], sizeof(uint64_t), M, f) == M; + a = move_cornershtrfin(m, ind / (24*24*24)); + bm = eposm_mtable[m][ind%24] % 24; + bs = eposs_mtable[m][(ind/24)%24] % 24; + be = epose_mtable[m][(ind/(24*24))%24] % 24; + b = (be * 24 + bs) * 24 + bm; - fclose(f); - return r; + return a * (24*24*24) + b; } -/* Public functions **********************************************************/ - -void -gen_coord(Coordinate *coord) +static uint64_t +move_cpud_separate(Move m, uint64_t ind) { - int i; + return cpud_separate_ind[cp_mtable[m][cpud_separate_ant[ind]]]; +} - if (coord == NULL || coord->generated) - return; +/* Init functions implementation *********************************************/ + +/* + * There is certainly a better way to do this, but for now I just use + * a "graph coloring" algorithm to compute the left cosets, and I compose + * with every possible cp to get the right cosets (it is possible that I am + * mixing up left and right). + * + * For doing it better "Mathematically", we need 3 things: + * - Checking that cp separates the orbits (UFR,UBL,DFL,DBR) and the other + * This is easy and it is done in the commented function cphtr_cp(). + * - Check that there is no ep/cp parity + * - Check that we are not in the "3c" case; this is the part I don't + * know how to do. + */ +static void +init_cphtr_cosets() +{ + unsigned int i; + int c = 0, d = 0; - for (i = 0; i < 2; i++) - gen_coord(coord->base[i]); - - switch (coord->type) { - case COMP_COORD: - if (coord->i[0] == NULL) - goto error_gc; - gen_coord_comp(coord); - break; - case SYM_COORD: - if (coord->base[0] == NULL || coord->tgrp == NULL) - goto error_gc; - gen_coord_sym(coord); - break; - case SYMCOMP_COORD: - if (coord->base[0] == NULL || coord->base[1] == NULL) - goto error_gc; - coord->max = coord->base[0]->max * coord->base[1]->max; - break; - default: - break; + for (i = 0; i < FACTORIAL8; i++) { + cphtr_left_cosets[i] = -1; + cphtr_right_cosets[i] = -1; } - coord->generated = true; - return; + /* First we compute left cosets with a bfs */ + for (i = 0; i < FACTORIAL8; i++) + if (cphtr_left_cosets[i] == -1) + init_cphtr_left_cosets_bfs(i, c++); -error_gc: - fprintf(stderr, "Error generating coordinates.\n" - "This is a bug, pleae report.\n"); - exit(1); + /* Then we compute right cosets using compose() */ + for (i = 0; i < FACTORIAL8; i++) + if (cphtr_right_cosets[i] == -1) + init_cphtr_right_cosets_color(i, d++); } -uint64_t -index_coord(Coordinate *coord, Cube *cube, Trans *offtrans) +static void +init_cphtr_left_cosets_bfs(int i, int c) { - uint64_t c[2], cnosym; - Trans ttr; + int j, jj, next[FACTORIAL8], next2[FACTORIAL8], n, n2; - switch (coord->type) { - case COMP_COORD: - if (offtrans != NULL) - *offtrans = uf; + Move k; - return indexers_getind(coord->i, cube); - case SYM_COORD: - cnosym = index_coord(coord->base[0], cube, NULL); - ttr = coord->transtorep[cnosym]; + n = 1; + next[0] = i; + cphtr_left_cosets[i] = c; - if (offtrans != NULL) - *offtrans = ttr; + while (n != 0) { + for (j = 0, n2 = 0; j < n; j++) { + for (k = U2; k < B3; k++) { + if (!moveset_htr.allowed(k)) + continue; + jj = apply_move(k, (Cube){ .cp = next[j] }).cp; - return coord->symclass[cnosym]; - case SYMCOMP_COORD: - c[0] = index_coord(coord->base[0], cube, NULL); - cnosym = index_coord(coord->base[0]->base[0], cube, NULL); - ttr = coord->base[0]->transtorep[cnosym]; - c[1] = index_coord(coord->base[1], cube, NULL); - c[1] = trans_coord(coord->base[1], ttr, c[1]); - - if (offtrans != NULL) - *offtrans = ttr; + if (cphtr_left_cosets[jj] == -1) { + cphtr_left_cosets[jj] = c; + next2[n2++] = jj; + } + } + } - return c[0] * coord->base[1]->max + c[1]; - default: - break; + for (j = 0; j < n2; j++) + next[j] = next2[j]; + n = n2; } - - return coord->max; /* Only reached in case of error */ } -uint64_t -move_coord(Coordinate *coord, Move m, uint64_t ind, Trans *offtrans) +static void +init_cphtr_right_cosets_color(int i, int d) { - uint64_t i[2], M; - Trans ttr; - - /* Some safety checks should be done here, but for performance * - * reasons we'd rather do them before calling this function. * - * We should check if coord is generated. */ - - switch (coord->type) { - case COMP_COORD: - if (offtrans != NULL) - *offtrans = uf; - - return coord->mtable[m][ind]; - case SYM_COORD: - ttr = coord->ttrep_move[m][ind]; + int cp; + unsigned int j; + + cphtr_right_rep[d] = i; + for (j = 0; j < FACTORIAL8; j++) { + if (cphtr_left_cosets[j] == 0) { + cp = compose((Cube){.cp = i}, (Cube){.cp = j}).cp; + cphtr_right_cosets[cp] = d; + } + } +} - if (offtrans != NULL) - *offtrans = ttr; +static void +init_cpud_separate() +{ + unsigned int ui; + int i, co[8]; + + for (ui = 0; ui < FACTORIAL8; ui++) { + for (i = 0; i < 8; i++) + co[i] = what_corner_at((Cube){.cp=ui},i)>UBR ? 1 : 0; + cpud_separate_ind[ui] = subset_to_index(co, 8, 4); + cpud_separate_ant[cpud_separate_ind[ui]] = ui; + } +} - return coord->mtable[m][ind]; - case SYMCOMP_COORD: - M = coord->base[1]->max; - i[0] = ind / M; - i[1] = ind % M; - ttr = coord->base[0]->ttrep_move[m][i[0]]; - i[0] = coord->base[0]->mtable[m][i[0]]; - i[1] = coord->base[1]->mtable[m][i[1]]; - i[1] = coord->base[1]->ttable[ttr][i[1]]; +static void +init_cornershtrfin() +{ + unsigned int i, j; + int n, c; + Move m; - if (offtrans != NULL) - *offtrans = ttr; + for (i = 0; i < FACTORIAL8; i++) + cornershtrfin_ind[i] = -1; + cornershtrfin_ind[0] = 0; - return i[0] * M + i[1]; - default: - break; + /* 10-pass, I think 5 is enough, but just in case */ + n = 1; + for (i = 0; i < 10; i++) { + for (j = 0; j < FACTORIAL8; j++) { + if (cornershtrfin_ind[j] == -1) + continue; + for (m = U; m < NMOVES; m++) { + if (moveset_htr.allowed(m)) { + c = cp_mtable[m][j]; + if (cornershtrfin_ind[c] == -1) { + cornershtrfin_ind[c] = n; + cornershtrfin_ant[n] = c; + n++; + } + } + } + } } - - return coord->max; /* Only reached in case of error */ } -uint64_t -trans_coord(Coordinate *coord, Trans t, uint64_t ind) +void +init_htr_eposs() { - uint64_t i[2], M; + int ep[12], ep2[12]; + int eps_solved[4] = {UL, UR, DL, DR}; + unsigned int i, j; + + for (i = 0; i < BINOM12ON4; i++) { + for (j = 0; j < 12; j++) + ep[j] = ep2[j] = 0; + epos_to_partial_ep(i*24, ep, eps_solved); + for (j = 0; j < 8; j++) + ep2[j/2 + 4*(j%2)] = ep[j] ? 1 : 0; + htr_eposs_ind[i] = subset_to_index(ep2, 8, 4); + htr_eposs_ant[htr_eposs_ind[i]] = i*24; + } +} - /* Some safety checks should be done here, but for performance * - * reasons we'd rather do them before calling this function. * - * We should check if coord is generated. */ +void +init_coord() +{ + static bool initialized = false; + if (initialized) + return; + initialized = true; - switch (coord->type) { - case COMP_COORD: - return coord->ttable[t][ind]; - case SYM_COORD: - return ind; - case SYMCOMP_COORD: - M = coord->base[1]->max; - i[0] = ind / M; /* Always fixed */ - i[1] = ind % M; - i[1] = coord->base[1]->ttable[t][i[1]]; - return i[0] * M + i[1]; - default: - break; - } + init_trans(); - return coord->max; /* Only reached in case of error */ + init_cphtr_cosets(); + init_cornershtrfin(); + init_htr_eposs(); + init_cpud_separate(); } + 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 @@ #include "trans.h" -void gen_coord(Coordinate *coord); -uint64_t index_coord(Coordinate *coord, Cube *cube, - Trans *offtrans); -uint64_t indexers_getind(Indexer **is, Cube *c); -void indexers_makecube(Indexer **is, uint64_t ind, Cube *c); -uint64_t move_coord(Coordinate *coord, Move m, - uint64_t ind, Trans *offtrans); -uint64_t trans_coord(Coordinate *coord, Trans t, uint64_t ind); - -/* Base coordinates and their index functions ********************************/ - -#ifndef COORD_C - -extern Coordinate coord_eofb; -extern Coordinate coord_coud; -extern Coordinate coord_cp; -extern Coordinate coord_cpudsep; -extern Coordinate coord_epos; -extern Coordinate coord_epe; -extern Coordinate coord_eposepe; -extern Coordinate coord_epud; -extern Coordinate coord_eofbepos; -extern Coordinate coord_coud_cpudsep; -extern Coordinate coord_eofbepos_sym16; -extern Coordinate coord_cp_sym16; -extern Coordinate coord_corners_sym16; -extern Coordinate coord_drud_sym16; -extern Coordinate coord_drudfin_noE_sym16; -extern Coordinate coord_nxopt31; - -extern Coordinate *all_coordinates[]; - -#else - -/* Indexers ******************************************************************/ - -uint64_t index_eofb(Cube *cube); -void invindex_eofb(uint64_t ind, Cube *ret); -Indexer -i_eofb = { - .n = POW2TO11, - .index = index_eofb, - .to_cube = invindex_eofb, -}; - -uint64_t index_coud(Cube *cube); -void invindex_coud(uint64_t ind, Cube *ret); -Indexer -i_coud = { - .n = POW3TO7, - .index = index_coud, - .to_cube = invindex_coud, -}; - -uint64_t index_cp(Cube *cube); -void invindex_cp(uint64_t ind, Cube *ret); -Indexer -i_cp = { - .n = FACTORIAL8, - .index = index_cp, - .to_cube = invindex_cp, -}; - -uint64_t index_cpudsep(Cube *cube); -void invindex_cpudsep(uint64_t ind, Cube *ret); -Indexer -i_cpudsep = { - .n = BINOM8ON4, - .index = index_cpudsep, - .to_cube = invindex_cpudsep, -}; - -uint64_t index_epos(Cube *cube); -void invindex_epos(uint64_t ind, Cube *ret); -Indexer -i_epos = { - .n = BINOM12ON4, - .index = index_epos, - .to_cube = invindex_epos, -}; - -uint64_t index_epe(Cube *cube); -void invindex_epe(uint64_t ind, Cube *ret); -Indexer -i_epe = { - .n = FACTORIAL4, - .index = index_epe, - .to_cube = invindex_epe, -}; - -uint64_t index_eposepe(Cube *cube); -void invindex_eposepe(uint64_t ind, Cube *ret); -Indexer -i_eposepe = { - .n = BINOM12ON4 * FACTORIAL4, - .index = index_eposepe, - .to_cube = invindex_eposepe, -}; - -uint64_t index_epud(Cube *cube); -void invindex_epud(uint64_t ind, Cube *ret); -Indexer -i_epud = { - .n = FACTORIAL8, - .index = index_epud, - .to_cube = invindex_epud, -}; - -/* Composite coordinates *****************************************************/ - -Coordinate -coord_eofb = { - .name = "eofb", - .type = COMP_COORD, - .i = {&i_eofb, NULL}, -}; - -Coordinate -coord_coud = { - .name = "coud", - .type = COMP_COORD, - .i = {&i_coud, NULL}, -}; - -Coordinate -coord_cp = { - .name = "cp", - .type = COMP_COORD, - .i = {&i_cp, NULL}, -}; - -Coordinate -coord_cpudsep = { - .name = "cpudsep", - .type = COMP_COORD, - .i = {&i_cpudsep, NULL}, -}; - -Coordinate -coord_epos = { - .name = "epos", - .type = COMP_COORD, - .i = {&i_epos, NULL}, -}; - -Coordinate -coord_epe = { - .name = "epe", - .type = COMP_COORD, - .i = {&i_epe, NULL}, -}; - -Coordinate -coord_eposepe = { /* Has to be done by hand, hard compose epos + epe */ - .name = "eposepe", - .type = COMP_COORD, - .i = {&i_eposepe, NULL}, -}; - -Coordinate -coord_epud = { - .name = "epud", - .type = COMP_COORD, - .i = {&i_epud, NULL}, -}; - -Coordinate -coord_eofbepos = { - .name = "eofbepos", - .type = COMP_COORD, - .i = {&i_epos, &i_eofb, NULL}, -}; - -Coordinate -coord_coud_cpudsep = { - .name = "coud_cpudsep", - .type = COMP_COORD, - .i = {&i_coud, &i_cpudsep, NULL}, -}; - -/* Symcoordinates ************************************************************/ - -Coordinate -coord_eofbepos_sym16 = { - .name = "eofbepos_sym16", - .type = SYM_COORD, - .base = {&coord_eofbepos, NULL}, - .tgrp = &tgrp_udfix, -}; - -Coordinate -coord_cp_sym16 = { - .name = "cp_sym16", - .type = SYM_COORD, - .base = {&coord_cp, NULL}, - .tgrp = &tgrp_udfix, -}; - -/* "Symcomp" coordinates *****************************************************/ - -Coordinate -coord_corners_sym16 = { - .name = "corners_sym16", - .type = SYMCOMP_COORD, - .base = {&coord_cp_sym16, &coord_coud}, -}; - -Coordinate -coord_drud_sym16 = { - .name = "drud_sym16", - .type = SYMCOMP_COORD, - .base = {&coord_eofbepos_sym16, &coord_coud}, -}; - -Coordinate -coord_drudfin_noE_sym16 = { - .name = "drudfin_noE_sym16", - .type = SYMCOMP_COORD, - .base = {&coord_cp_sym16, &coord_epud}, -}; - -Coordinate -coord_nxopt31 = { - .name = "nxopt31", - .type = SYMCOMP_COORD, - .base = {&coord_eofbepos_sym16, &coord_coud_cpudsep}, -}; - -/* All coordinates ***********************************************************/ - -Coordinate *all_coordinates[] = { - &coord_eofb, - &coord_coud, - &coord_cp, - &coord_cpudsep, - &coord_epos, - &coord_epe, - &coord_eposepe, - &coord_epud, - &coord_eofbepos, - &coord_coud_cpudsep, - &coord_eofbepos_sym16, - &coord_cp_sym16, - &coord_corners_sym16, - &coord_drud_sym16, - &coord_drudfin_noE_sym16, - &coord_nxopt31, - NULL -}; - -#endif +extern Coordinate coord_eofb; +extern Coordinate coord_eofbepos; +extern Coordinate coord_coud; +extern Coordinate coord_cp; +extern Coordinate coord_cphtr; +extern Coordinate coord_corners; +extern Coordinate coord_cornershtr; +extern Coordinate coord_cornershtrfin; +extern Coordinate coord_epud; +extern Coordinate coord_drud; +extern Coordinate coord_drud_eofb; +extern Coordinate coord_htr_drud; +extern Coordinate coord_htrfin; +extern Coordinate coord_cpud_separate; + +extern int cpud_separate_ant[BINOM8ON4]; +extern int cpud_separate_ind[FACTORIAL8]; +extern int cornershtrfin_ant[24*24/6]; + +void init_coord(); #endif 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 @@ -#define CUBE_C - #include "cube.h" -static int where_is_piece(int piece, int *arr, int n); +/* Local functions ***********************************************************/ -void -compose_centers(Cube *c2, Cube *c1) +static void init_inverse(); +static bool read_invtables_file(); +static bool write_invtables_file(); + +/* Tables ********************************************************************/ + +static uint16_t eo_invtable_e[POW2TO11][BINOM12ON4*FACTORIAL4]; +static uint16_t eo_invtable_s[POW2TO11][BINOM12ON4*FACTORIAL4]; +static uint16_t eo_invtable_m[POW2TO11][BINOM12ON4*FACTORIAL4]; +static uint16_t co_invtable[POW3TO7][FACTORIAL8]; +static uint16_t cp_invtable[FACTORIAL8]; +static uint16_t cpos_invtable[FACTORIAL6]; + +/* Functions implementation **************************************************/ + +int +array_ep_to_epos(int *ep, int *ss) { - apply_permutation(c2->xp, c1->xp, 6); + int epos[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + int eps[4]; + int i, j, is; + + for (i = 0, is = 0; i < 12; i++) { + for (j = 0; j < 4; j++) { + if (ep[i] == ss[j]) { + eps[is++] = j; + epos[i] = 1; + } + } + } + + for (i = 0; i < 4; i++) + swap(&epos[ss[i]], &epos[i+8]); + + return 24 * subset_to_index(epos, 12, 4) + perm_to_index(eps, 4); } -void -compose_corners(Cube *c2, Cube *c1) +Cube +arrays_to_cube(CubeArray *arr, PieceFilter f) { - apply_permutation(c2->cp, c1->cp, 8); - apply_permutation(c2->cp, c1->co, 8); - sum_arrays_mod(c2->co, c1->co, 8, 3); + Cube ret = {0}; + + static int epe_solved[4] = {FR, FL, BL, BR}; + static int eps_solved[4] = {UL, UR, DL, DR}; + static int epm_solved[4] = {UF, UB, DF, DB}; + + if (f.epose) + ret.epose = array_ep_to_epos(arr->ep, epe_solved); + if (f.eposs) + ret.eposs = array_ep_to_epos(arr->ep, eps_solved); + if (f.eposm) + ret.eposm = array_ep_to_epos(arr->ep, epm_solved); + if (f.eofb) + ret.eofb = digit_array_to_int(arr->eofb, 11, 2); + if (f.eorl) + ret.eorl = digit_array_to_int(arr->eorl, 11, 2); + if (f.eoud) + ret.eoud = digit_array_to_int(arr->eoud, 11, 2); + if (f.cp) + ret.cp = perm_to_index(arr->cp, 8); + if (f.coud) + ret.coud = digit_array_to_int(arr->coud, 7, 3); + if (f.corl) + ret.corl = digit_array_to_int(arr->corl, 7, 3); + if (f.cofb) + ret.cofb = digit_array_to_int(arr->cofb, 7, 3); + if (f.cpos) + ret.cpos = perm_to_index(arr->cpos, 6); + + return ret; } -void -compose_edges(Cube *c2, Cube *c1) +Cube +compose_filtered(Cube c2, Cube c1, PieceFilter f) { - apply_permutation(c2->ep, c1->ep, 12); - apply_permutation(c2->ep, c1->eo, 12); - sum_arrays_mod(c2->eo, c1->eo, 12, 2); + CubeArray *arr = new_cubearray(c2, f); + Cube ret; + + ret = move_via_arrays(arr, c1, f); + free_cubearray(arr, f); + + return ret; } void -compose(Cube *c2, Cube *c1) +cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f) { - compose_centers(c2, c1); - compose_corners(c2, c1); - compose_edges(c2, c1); + int i; + + static int epe_solved[4] = {FR, FL, BL, BR}; + static int eps_solved[4] = {UL, UR, DL, DR}; + static int epm_solved[4] = {UF, UB, DF, DB}; + + if (f.epose || f.eposs || f.eposm) + for (i = 0; i < 12; i++) + arr->ep[i] = -1; + + if (f.epose) + epos_to_partial_ep(cube.epose, arr->ep, epe_solved); + if (f.eposs) + epos_to_partial_ep(cube.eposs, arr->ep, eps_solved); + if (f.eposm) + epos_to_partial_ep(cube.eposm, arr->ep, epm_solved); + if (f.eofb) + int_to_sum_zero_array(cube.eofb, 2, 12, arr->eofb); + if (f.eorl) + int_to_sum_zero_array(cube.eorl, 2, 12, arr->eorl); + if (f.eoud) + int_to_sum_zero_array(cube.eoud, 2, 12, arr->eoud); + if (f.cp) + index_to_perm(cube.cp, 8, arr->cp); + if (f.coud) + int_to_sum_zero_array(cube.coud, 3, 8, arr->coud); + if (f.corl) + int_to_sum_zero_array(cube.corl, 3, 8, arr->corl); + if (f.cofb) + int_to_sum_zero_array(cube.cofb, 3, 8, arr->cofb); + if (f.cpos) + index_to_perm(cube.cpos, 6, arr->cpos); } void -copy_cube_centers(Cube *src, Cube *dst) +epos_to_compatible_ep(int epos, int *ep, int *ss) { - memcpy(dst->xp, src->xp, 6 * sizeof(int)); + int i, j, k, other[8]; + bool flag; + + for (i = 0; i < 12; i++) + ep[i] = -1; + + epos_to_partial_ep(epos, ep, ss); + + for (i = 0, j = 0; i < 12; i++) { + flag = false; + for (k = 0; k < 4; k++) + flag = flag || (i == ss[k]); + if (!flag) + other[j++] = i; + } + + for (i = 0, j = 0; i < 12; i++) + if (ep[i] == -1) + ep[i] = other[j++]; } void -copy_cube_corners(Cube *src, Cube *dst) +epos_to_partial_ep(int epos, int *ep, int *ss) { - memcpy(dst->cp, src->cp, 8 * sizeof(int)); - memcpy(dst->co, src->co, 8 * sizeof(int)); + int i, is, eposs[12], eps[4]; + + index_to_perm(epos % FACTORIAL4, 4, eps); + index_to_subset(epos / FACTORIAL4, 12, 4, eposs); + + for (i = 0; i < 4; i++) + swap(&eposs[ss[i]], &eposs[i+8]); + + for (i = 0, is = 0; i < 12; i++) + if (eposs[i]) + ep[i] = ss[eps[is++]]; } void -copy_cube_edges(Cube *src, Cube *dst) +fix_eorleoud(CubeArray *arr) { - memcpy(dst->ep, src->ep, 12 * sizeof(int)); - memcpy(dst->eo, src->eo, 12 * sizeof(int)); + int i; + + for (i = 0; i < 12; i++) { + if ((edge_slice(i) == 0 && edge_slice(arr->ep[i]) != 0) || + (edge_slice(i) != 0 && edge_slice(arr->ep[i]) == 0)) { + arr->eorl[i] = 1 - arr->eofb[i]; + } else { + arr->eorl[i] = arr->eofb[i]; + } + + if ((edge_slice(i) == 2 && edge_slice(arr->ep[i]) != 2) || + (edge_slice(i) != 2 && edge_slice(arr->ep[i]) == 2)) { + arr->eoud[i] = 1 - arr->eofb[i]; + } else { + arr->eoud[i] = arr->eofb[i]; + } + } } void -copy_cube(Cube *src, Cube *dst) +fix_cofbcorl(CubeArray *arr) { - copy_cube_centers(src, dst); - copy_cube_corners(src, dst); - copy_cube_edges(src, dst); + int i; + + for (i = 0; i < 8; i++) { + if (i % 2 == arr->cp[i] % 2) { + arr->cofb[i] = arr->coud[i]; + arr->corl[i] = arr->coud[i]; + } else { + if (arr->cp[i] % 2 == 0) { + arr->cofb[i] = (arr->coud[i]+1)%3; + arr->corl[i] = (arr->coud[i]+2)%3; + } else { + arr->cofb[i] = (arr->coud[i]+2)%3; + arr->corl[i] = (arr->coud[i]+1)%3; + } + } + } } -bool -equal(Cube *c1, Cube *c2) +Cube +fourval_to_cube(int eofb, int ep, int coud, int cp) { - int i; + CubeArray *arr; - for (i = 0; i < 12; i++) - if (c1->ep[i] != c2->ep[i] || c1->eo[i] != c2->eo[i]) - return false; + arr = new_cubearray((Cube){0}, pf_all); - for (i = 0; i < 8; i++) - if (c1->cp[i] != c2->cp[i] || c1->co[i] != c2->co[i]) - return false; + index_to_perm(ep, 12, arr->ep); + index_to_perm(cp, 8, arr->cp); + int_to_sum_zero_array(eofb, 2, 12, arr->eofb); + int_to_sum_zero_array(coud, 3, 8, arr->coud); - for (i = 0; i < 6; i++) - if (c1->xp[i] != c2->xp[i]) - return false; + /* fix parity */ + if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8)) + swap(&(arr->ep[0]), &(arr->ep[1])); - return true; + fix_eorleoud(arr); + fix_cofbcorl(arr); + + return arrays_to_cube(arr, pf_all); } void -invert_cube_centers(Cube *cube) +free_cubearray(CubeArray *arr, PieceFilter f) { - int i; - Cube aux; + if (f.epose || f.eposs || f.eposm) + free(arr->ep); + if (f.eofb) + free(arr->eofb); + if (f.eorl) + free(arr->eorl); + if (f.eoud) + free(arr->eoud); + if (f.cp) + free(arr->cp); + if (f.coud) + free(arr->coud); + if (f.corl) + free(arr->corl); + if (f.cofb) + free(arr->cofb); + if (f.cpos) + free(arr->cpos); + + free(arr); +} - copy_cube_centers(cube, &aux); +Cube +move_via_arrays(CubeArray *arr, Cube c, PieceFilter f) +{ + CubeArray *arrc = new_cubearray(c, f); + Cube ret; - for (i = 0; i < 6; i++) - cube->xp[aux.xp[i]] = i; + if (f.epose || f.eposs || f.eposm) + apply_permutation(arr->ep, arrc->ep, 12); + + if (f.eofb) { + apply_permutation(arr->ep, arrc->eofb, 12); + sum_arrays_mod(arr->eofb, arrc->eofb, 12, 2); + } + + if (f.eorl) { + apply_permutation(arr->ep, arrc->eorl, 12); + sum_arrays_mod(arr->eorl, arrc->eorl, 12, 2); + } + + if (f.eoud) { + apply_permutation(arr->ep, arrc->eoud, 12); + sum_arrays_mod(arr->eoud, arrc->eoud, 12, 2); + } + + if (f.cp) + apply_permutation(arr->cp, arrc->cp, 8); + + if (f.coud) { + apply_permutation(arr->cp, arrc->coud, 8); + sum_arrays_mod(arr->coud, arrc->coud, 8, 3); + } + + if (f.corl) { + apply_permutation(arr->cp, arrc->corl, 8); + sum_arrays_mod(arr->corl, arrc->corl, 8, 3); + } + + if (f.cofb) { + apply_permutation(arr->cp, arrc->cofb, 8); + sum_arrays_mod(arr->cofb, arrc->cofb, 8, 3); + } + + if (f.cpos) + apply_permutation(arr->cpos, arrc->cpos, 6); + + ret = arrays_to_cube(arrc, f); + free_cubearray(arrc, f); + + return ret; } -void -invert_cube_corners(Cube *cube) +CubeArray * +new_cubearray(Cube cube, PieceFilter f) { - int i; - Cube aux; + CubeArray *arr = malloc(sizeof(CubeArray)); + + if (f.epose || f.eposs || f.eposm) + arr->ep = malloc(12 * sizeof(int)); + if (f.eofb) + arr->eofb = malloc(12 * sizeof(int)); + if (f.eorl) + arr->eorl = malloc(12 * sizeof(int)); + if (f.eoud) + arr->eoud = malloc(12 * sizeof(int)); + if (f.cp) + arr->cp = malloc(8 * sizeof(int)); + if (f.coud) + arr->coud = malloc(8 * sizeof(int)); + if (f.corl) + arr->corl = malloc(8 * sizeof(int)); + if (f.cofb) + arr->cofb = malloc(8 * sizeof(int)); + if (f.cpos) + arr->cpos = malloc(6 * sizeof(int)); + + cube_to_arrays(cube, arr, f); + + return arr; +} - copy_cube_corners(cube, &aux); +Cube +admissible_ep(Cube cube, PieceFilter f) +{ + CubeArray *arr = new_cubearray(cube, f); + Cube ret; + bool used[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + int i, j; - for (i = 0; i < 8; i++) { - cube->cp[aux.cp[i]] = i; - cube->co[aux.cp[i]] = (3 - aux.co[i]) % 3; + for (i = 0; i < 12; i++) + if (arr->ep[i] != -1) + used[arr->ep[i]] = true; + + for (i = 0, j = 0; i < 12; i++) { + for ( ; j < 11 && used[j]; j++); + if (arr->ep[i] == -1) + arr->ep[i] = j++; } + + ret = arrays_to_cube(arr, pf_ep); + free_cubearray(arr, f); + + return ret; } -void -invert_cube_edges(Cube *cube) +Cube +compose(Cube c2, Cube c1) { - int i; - Cube aux; + return compose_filtered(c2, c1, pf_all); +} - copy_cube_edges(cube, &aux); +int +edge_slice(Edge e) { + if (e < 0 || e > 11) + return -1; - for (i = 0; i < 12; i++) { - cube->ep[aux.ep[i]] = i; - cube->eo[aux.ep[i]] = aux.eo[i]; - } + if (e == FR || e == FL || e == BL || e == BR) + return 0; + if (e == UR || e == UL || e == DR || e == DL) + return 1; + + return 2; } -void -invert_cube(Cube *cube) +bool +equal(Cube c1, Cube c2) { - invert_cube_centers(cube); - invert_cube_corners(cube); - invert_cube_edges(cube); + return c1.eofb == c2.eofb && + c1.epose == c2.epose && + c1.eposs == c2.eposs && + c1.eposm == c2.eposm && + c1.coud == c2.coud && + c1.cp == c2.cp && + c1.cpos == c2.cpos; +} + +Cube +inverse_cube(Cube cube) +{ + CubeArray inv; + Cube ret; + int i, ep[12]; + + for (i = 0; i < 12; i++) + ep[i] = where_is_edge(cube, i); + inv = (CubeArray){.ep = ep}; + ret = arrays_to_cube(&inv, pf_ep); + + ret.eofb = ((int)eo_invtable_e[cube.eofb][cube.epose]) | + ((int)eo_invtable_m[cube.eofb][cube.eposm]) | + ((int)eo_invtable_s[cube.eofb][cube.eposs]); + ret.eorl = ((int)eo_invtable_e[cube.eorl][cube.epose]) | + ((int)eo_invtable_m[cube.eorl][cube.eposm]) | + ((int)eo_invtable_s[cube.eorl][cube.eposs]); + ret.eoud = ((int)eo_invtable_e[cube.eoud][cube.epose]) | + ((int)eo_invtable_m[cube.eoud][cube.eposm]) | + ((int)eo_invtable_s[cube.eoud][cube.eposs]); + ret.cp = cp_invtable[cube.cp]; + ret.cpos = cpos_invtable[cube.cpos]; + ret.coud = co_invtable[cube.coud][cube.cp]; + ret.corl = co_invtable[cube.corl][cube.cp]; + ret.cofb = co_invtable[cube.cofb][cube.cp]; + + return ret; } bool -is_admissible(Cube *c) { - bool perm; - int sign, i; - int sum_e, sum_c; +is_admissible(Cube cube) { - perm = is_perm(c->ep, 12) && is_perm(c->cp, 8) && is_perm(c->xp, 6); + /* TODO: this should check consistency of different orientations */ + /* check also that centers are opposite and admissible */ - sign = perm_sign(c->ep,12) + perm_sign(c->cp,8) + perm_sign(c->xp,6); + CubeArray *a = new_cubearray(cube, pf_all); + int parity; + bool perm; - for (i = 0, sum_e = 0; i < 12; i++) - if (c->eo[i] > 1) - return false; - else - sum_e += c->eo[i]; + perm = is_perm(a->ep, 12) && + is_perm(a->cp, 8) && + is_perm(a->cpos, 6); + parity = perm_sign(a->ep, 12) + + perm_sign(a->cp, 8) + + perm_sign(a->cpos, 6); - for (i = 0, sum_c = 0; i < 8; i++) - if (c->co[i] > 2) - return false; - else - sum_c += c->co[i]; + free_cubearray(a, pf_all); - return (perm && sign % 2 == 0 && sum_e % 2 == 0 && sum_c % 2 == 0); + return perm && parity % 2 == 0; } bool -is_solved(Cube *cube) +is_solved(Cube cube) { - Cube solved_cube; - make_solved(&solved_cube); - - return equal(cube, &solved_cube); + return equal(cube, (Cube){0}); } -void -make_solved_centers(Cube *cube) +bool +is_block_solved(Cube cube, Block block) { - static int sorted[6] = {0, 1, 2, 3, 4, 5}; + int i; + + for (i = 0; i < 12; i++) + if (block.edge[i] && !is_solved_edge(cube, i)) + return false; + for (i = 0; i < 8; i++) + if (block.corner[i] && !is_solved_corner(cube, i)) + return false; + for (i = 0; i < 6; i++) + if (block.center[i] && !is_solved_center(cube, i)) + return false; - memcpy(cube->xp, sorted, 6 * sizeof(int)); + return true; } -void -make_solved_corners(Cube *cube) +bool +is_solved_center(Cube cube, Center c) { - static int sorted[8] = {0, 1, 2, 3, 4, 5, 6, 7}; - - memcpy(cube->cp, sorted, 8 * sizeof(int)); - memset(cube->co, 0, 8 * sizeof(int)); + return what_center_at(cube, c) == c; } -void -make_solved_edges(Cube *cube) +bool +is_solved_corner(Cube cube, Corner c) { - static int sorted[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + return what_corner_at(cube, c) == c && + what_orientation_corner(cube.coud, c); +} - memcpy(cube->ep, sorted, 12 * sizeof(int)); - memset(cube->eo, 0, 12 * sizeof(int)); +bool +is_solved_edge(Cube cube, Edge e) +{ + return what_edge_at(cube, e) == e && + what_orientation_edge(cube.eofb, e); } -void -make_solved(Cube *cube) +int +piece_orientation(Cube cube, int piece, char *orientation) { - make_solved_centers(cube); - make_solved_corners(cube); - make_solved_edges(cube); + int arr[12], n, b, x; + + if (!strcmp(orientation, "eofb")) { + x = cube.eofb; + n = 12; + b = 2; + } else if (!strcmp(orientation, "eorl")) { + x = cube.eorl; + n = 12; + b = 2; + } else if (!strcmp(orientation, "eoud")) { + x = cube.eoud; + n = 12; + b = 2; + } else if (!strcmp(orientation, "coud")) { + x = cube.coud; + n = 8; + b = 3; + } else if (!strcmp(orientation, "corl")) { + x = cube.corl; + n = 8; + b = 3; + } else if (!strcmp(orientation, "cofb")) { + x = cube.cofb; + n = 8; + b = 3; + } else { + return -1; + } + + int_to_sum_zero_array(x, b, n, arr); + if (piece < n) + return arr[piece]; + + return -1; } void -print_cube(Cube *cube) +print_cube(Cube cube) { static char edge_string[12][7] = { [UF] = "UF", [UL] = "UL", [UB] = "UB", [UR] = "UR", @@ -219,52 +545,388 @@ print_cube(Cube *cube) }; for (int i = 0; i < 12; i++) - printf(" %s ", edge_string[cube->ep[i]]); + printf(" %s ", edge_string[what_edge_at(cube, i)]); printf("\n"); for (int i = 0; i < 12; i++) - printf(" %" PRIu8 " ", cube->eo[i]); + printf(" %d ", what_orientation_edge(cube.eofb, i)); printf("\n"); for (int i = 0; i < 8; i++) - printf("%s ", corner_string[cube->cp[i]]); + printf("%s ", corner_string[what_corner_at(cube, i)]); printf("\n"); for (int i = 0; i < 8; i++) - printf(" %" PRIu8 " ", cube->co[i]); + printf(" %d ", what_orientation_corner(cube.coud, i)); printf("\n"); for (int i = 0; i < 6; i++) - printf(" %s ", center_string[cube->xp[i]]); + printf(" %s ", center_string[what_center_at(cube, i)]); printf("\n"); } -int -where_is_center(Center x, Cube *c) +Center +what_center_at(Cube cube, Center c) +{ + static bool initialized = false; + static Center aux[FACTORIAL6][6]; + static int i; + static unsigned int ui; + static CubeArray *arr; + + if (!initialized) { + for (ui = 0; ui < FACTORIAL6; ui++) { + arr = new_cubearray((Cube){.cpos = ui}, pf_cpos); + for (i = 0; i < 6; i++) + aux[ui][i] = arr->cpos[i]; + free_cubearray(arr, pf_cpos); + } + + initialized = true; + } + + return aux[cube.cpos][c]; +} + +Corner +what_corner_at(Cube cube, Corner c) +{ + int i; + unsigned int ui; + CubeArray *arr; + + static bool initialized = false; + static Corner aux[FACTORIAL8][8]; + + if (!initialized) { + for (ui = 0; ui < FACTORIAL8; ui++) { + arr = new_cubearray((Cube){.cp = ui}, pf_cp); + for (i = 0; i < 8; i++) + aux[ui][i] = arr->cp[i]; + free_cubearray(arr, pf_cp); + } + + initialized = true; + } + + return aux[cube.cp][c]; +} + +Edge +what_edge_at(Cube cube, Edge e) { - return where_is_piece(x, c->xp, 6); + Edge ret; + CubeArray *arr = new_cubearray(cube, pf_ep); + + ret = arr->ep[e]; + + free_cubearray(arr, pf_ep); + return ret; } int -where_is_corner(Corner k, Cube *c) +what_orientation_corner(int co, Corner c) { - return where_is_piece(k, c->cp, 8); + static bool initialized = false; + static int auxlast[POW3TO7]; + static int auxarr[8]; + static unsigned int ui; + + if (!initialized) { + for (ui = 0; ui < POW3TO7; ui++) { + int_to_sum_zero_array(ui, 3, 8, auxarr); + auxlast[ui] = auxarr[7]; + } + + initialized = true; + } + + if (c < 7) + return (co / powint(3, c)) % 3; + else + return auxlast[co]; } int -where_is_edge(Edge e, Cube *c) +what_orientation_edge(int eo, Edge e) { - return where_is_piece(e, c->ep, 12); + static bool initialized = false; + static int auxlast[POW2TO11]; + static int auxarr[12]; + static unsigned int ui; + + if (!initialized) { + for (ui = 0; ui < POW2TO11; ui++) { + int_to_sum_zero_array(ui, 2, 12, auxarr); + auxlast[ui] = auxarr[11]; + } + + initialized = true; + } + + if (e < 11) + return (eo & (1 << e)) ? 1 : 0; + else + return auxlast[eo]; } -static int -where_is_piece(int piece, int *arr, int n) +Center +where_is_center(Cube cube, Center c) { - int i; + static bool initialized = false; + static Center aux[FACTORIAL6][6]; + static int i; + static unsigned int ui; + static CubeArray *arr; + + if (!initialized) { + for (ui = 0; ui < FACTORIAL6; ui++) { + arr = new_cubearray((Cube){.cpos = ui}, pf_cpos); + for (i = 0; i < 6; i++) + aux[ui][arr->cpos[i]] = i; + free_cubearray(arr, pf_cpos); + } + + initialized = true; + } - for (i = 0; i < n; i++) - if (arr[i] == piece) - return i; + return aux[cube.cpos][c]; +} - return -1; +Corner +where_is_corner(Cube cube, Corner c) +{ + static bool initialized = false; + static Corner aux[FACTORIAL8][8]; + static int i; + static unsigned int ui; + static CubeArray *arr; + + if (!initialized) { + for (ui = 0; ui < FACTORIAL8; ui++) { + arr = new_cubearray((Cube){.cp = ui}, pf_cp); + for (i = 0; i < 8; i++) + aux[ui][arr->cp[i]] = i; + free_cubearray(arr, pf_cp); + } + + initialized = true; + } + return aux[cube.cp][c]; +} + +Edge +where_is_edge(Cube c, Edge e) +{ + int r0, r1, r2; + + static bool initialized = false; + static int aux[3][BINOM12ON4*FACTORIAL4][12]; + static int i, j; + static unsigned int ui; + static CubeArray *arr; + + if (!initialized) { + for (ui = 0; ui < BINOM12ON4*FACTORIAL4; ui++) { + for (i = 0; i < 3; i++) + for (j = 0; j < 12; j++) + aux[i][ui][j] = -1; + + arr = new_cubearray((Cube){.epose = ui}, pf_e); + for (i = 0; i < 12; i++) + if (edge_slice(arr->ep[i]) == 0) + aux[0][ui][arr->ep[i]] = i; + free_cubearray(arr, pf_e); + + arr = new_cubearray((Cube){.eposs = ui}, pf_s); + for (i = 0; i < 12; i++) + if (edge_slice(arr->ep[i]) == 1) + aux[1][ui][arr->ep[i]] = i; + free_cubearray(arr, pf_s); + + arr = new_cubearray((Cube){.eposm = ui}, pf_m); + for (i = 0; i < 12; i++) + if (edge_slice(arr->ep[i]) == 2) + aux[2][ui][arr->ep[i]] = i; + free_cubearray(arr, pf_m); + } + + initialized = true; + } + + r0 = aux[0][c.epose][e]; + r1 = aux[1][c.eposs][e]; + r2 = aux[2][c.eposm][e]; + return MAX(r0, MAX(r1, r2)); +} + +static bool +read_invtables_file() +{ + init_env(); + + FILE *f; + char fname[strlen(tabledir)+20]; + int b; + unsigned int ui, meeo, meco, mecp, mecpos; + bool r; + + strcpy(fname, tabledir); + strcat(fname, "/invtables"); + + if ((f = fopen(fname, "rb")) == NULL) + return false; + + b = sizeof(uint16_t); + r = true; + meeo = BINOM12ON4*FACTORIAL4; + meco = FACTORIAL8; + mecp = FACTORIAL8; + mecpos = FACTORIAL6; + + for (ui = 0; ui < POW2TO11; ui++) { + r = r && fread(eo_invtable_e[ui], b, meeo, f) == meeo; + r = r && fread(eo_invtable_m[ui], b, meeo, f) == meeo; + r = r && fread(eo_invtable_s[ui], b, meeo, f) == meeo; + } + + for (ui = 0; ui < POW3TO7; ui++) { + r = r && fread(co_invtable[ui], b, meco, f) == meco; + } + + r = r && fread(cp_invtable, b, mecp, f) == mecp; + r = r && fread(cpos_invtable, b, mecpos, f) == mecpos; + + fclose(f); + return r; +} + +static bool +write_invtables_file() +{ + init_env(); + + FILE *f; + char fname[strlen(tabledir)+20]; + unsigned int ui, meeo, meco, mecp, mecpos; + int b; + bool r; + + strcpy(fname, tabledir); + strcat(fname, "/invtables"); + + if ((f = fopen(fname, "wb")) == NULL) + return false; + + b = sizeof(uint16_t); + r = true; + meeo = BINOM12ON4*FACTORIAL4; + meco = FACTORIAL8; + mecp = FACTORIAL8; + mecpos = FACTORIAL6; + + for (ui = 0; ui < POW2TO11; ui++) { + r = r && fwrite(eo_invtable_e[ui], b, meeo, f) == meeo; + r = r && fwrite(eo_invtable_m[ui], b, meeo, f) == meeo; + r = r && fwrite(eo_invtable_s[ui], b, meeo, f) == meeo; + } + + for (ui = 0; ui < POW3TO7; ui++) { + r = r && fwrite(co_invtable[ui], b, meco, f) == meco; + } + + r = r && fwrite(cp_invtable, b, mecp, f) == mecp; + r = r && fwrite(cpos_invtable, b, mecpos, f) == mecpos; + + fclose(f); + return r; +} + +void +init_inverse() +{ + static bool initialized = false; + if (initialized) + return; + initialized = true; + + if (read_invtables_file()) + return; + + fprintf(stderr, "Cannot load invtables, generating it\n"); + + CubeArray *aux, *inv; + Cube c; + int i, j, eoaux[12], eoinv[12]; + unsigned int ui, uj; + + aux = new_cubearray((Cube){0}, pf_all); + inv = new_cubearray((Cube){0}, pf_all); + + for (ui = 0; ui < POW2TO11; ui++) { + int_to_sum_zero_array(ui, 2, 12, eoaux); + for (uj = 0; uj < BINOM12ON4*FACTORIAL4; uj++) { + for (j = 0; j < 12; j++) + eoinv[j] = 0; + c = (Cube){.epose = uj, .eposm = 0, .eposs = 0}; + eoinv[FR] = eoaux[where_is_edge(c, FR)]; + eoinv[FL] = eoaux[where_is_edge(c, FL)]; + eoinv[BL] = eoaux[where_is_edge(c, BL)]; + eoinv[BR] = eoaux[where_is_edge(c, BR)]; + eo_invtable_e[ui][uj] = digit_array_to_int(eoinv,11,2); + + for (j = 0; j < 12; j++) + eoinv[j] = 0; + c = (Cube){.epose = 0, .eposm = uj, .eposs = 0}; + eoinv[UF] = eoaux[where_is_edge(c, UF)]; + eoinv[UB] = eoaux[where_is_edge(c, UB)]; + eoinv[DF] = eoaux[where_is_edge(c, DF)]; + eoinv[DB] = eoaux[where_is_edge(c, DB)]; + eo_invtable_m[ui][uj] = digit_array_to_int(eoinv,11,2); + + for (j = 0; j < 12; j++) + eoinv[j] = 0; + c = (Cube){.epose = 0, .eposm = 0, .eposs = uj}; + eoinv[UL] = eoaux[where_is_edge(c, UL)]; + eoinv[UR] = eoaux[where_is_edge(c, UR)]; + eoinv[DL] = eoaux[where_is_edge(c, DL)]; + eoinv[DR] = eoaux[where_is_edge(c, DR)]; + eo_invtable_s[ui][uj] = digit_array_to_int(eoinv,11,2); + } + } + + for (ui = 0; ui < FACTORIAL8; ui++) { + cube_to_arrays((Cube){.cp = ui}, aux, pf_cp); + for (i = 0; i < 8; i++) + inv->cp[aux->cp[i]] = i; + cp_invtable[ui] = (uint16_t)arrays_to_cube(inv, pf_cp).cp; + + for (uj = 0; uj < POW3TO7; uj++) { + cube_to_arrays((Cube){.coud = uj}, aux, pf_coud); + for (i = 0; i < 8; i++) + inv->coud[aux->cp[i]] = (3-aux->coud[i])%3; + co_invtable[uj][ui] = + (uint16_t)arrays_to_cube(inv, pf_coud).coud; + } + } + + for (ui = 0; ui < FACTORIAL6; ui++) { + cube_to_arrays((Cube){.cpos = ui}, aux, pf_cpos); + for (i = 0; i < 6; i++) + inv->cpos[aux->cpos[i]] = i; + cpos_invtable[ui] = + (uint16_t)arrays_to_cube(inv, pf_cpos).cpos; + } + + free_cubearray(aux, pf_all); + free_cubearray(inv, pf_all); + + if (!write_invtables_file()) + fprintf(stderr, "Error writing invtables\n"); +} + +void +init_cube() +{ + init_inverse(); } 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 @@ #include -#include "cubetypes.h" #include "env.h" +#include "pf.h" #include "utils.h" -void compose(Cube *c2, Cube *c1); /* Use c2 as an alg on c1 */ -void compose_centers(Cube *c2, Cube *c1); -void compose_corners(Cube *c2, Cube *c1); -void compose_edges(Cube *c2, Cube *c1); -void copy_cube(Cube *src, Cube *dst); -void copy_cube_centers(Cube *src, Cube *dst); -void copy_cube_corners(Cube *src, Cube *dst); -void copy_cube_edges(Cube *src, Cube *dst); -bool equal(Cube *c1, Cube *c2); -void invert_cube(Cube *cube); -void invert_cube_centers(Cube *cube); -void invert_cube_corners(Cube *cube); -void invert_cube_edges(Cube *cube); -bool is_admissible(Cube *cube); -bool is_solved(Cube *cube); -void make_solved(Cube *cube); -void make_solved_centers(Cube *cube); -void make_solved_corners(Cube *cube); -void make_solved_edges(Cube *cube); -void print_cube(Cube *cube); -int where_is_center(Center x, Cube *c); -int where_is_corner(Corner k, Cube *c); -int where_is_edge(Edge e, Cube *c); +Cube admissible_ep(Cube cube, PieceFilter f); +int array_ep_to_epos(int *ep, int *eps_solved); +Cube arrays_to_cube(CubeArray *arr, PieceFilter f); +Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */ +Cube compose_filtered(Cube c2, Cube c1, PieceFilter f); +void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f); +int edge_slice(Edge e); /* E=0, S=1, M=2 */ +bool equal(Cube c1, Cube c2); +Cube inverse_cube(Cube cube); +bool is_admissible(Cube cube); +bool is_solved(Cube cube); +bool is_block_solved(Cube cube, Block); +bool is_solved_center(Cube cube, Center c); +bool is_solved_corner(Cube cube, Corner c); +bool is_solved_edge(Cube cube, Edge e); +void epos_to_partial_ep(int epos, int *ep, int *ss); +void epos_to_compatible_ep(int epos, int *ep, int *ss); +void fix_eorleoud(CubeArray *arr); +void fix_cofbcorl(CubeArray *arr); +Cube fourval_to_cube(int eofb, int ep, int coud, int cp); +void free_cubearray(CubeArray *arr, PieceFilter f); +Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf); +CubeArray * new_cubearray(Cube cube, PieceFilter f); +void print_cube(Cube cube); +Center what_center_at(Cube cube, Center c); +Corner what_corner_at(Cube cube, Corner c); +Edge what_edge_at(Cube cube, Edge e); +int what_orientation_corner(int co, Corner c); +int what_orientation_edge(int eo, Edge e); +Center where_is_center(Cube cube, Center c); +Corner where_is_corner(Cube cube, Corner c); +Edge where_is_edge(Cube cube, Edge e); + +void init_cube(); #endif 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 @@ #define NROTATIONS 24 #define entry_group_t uint8_t /* For pruning tables */ -#define MAX_N_COORD 6 - /* Enums *********************************************************************/ typedef enum @@ -29,12 +27,6 @@ corner DFR, DFL, DBL, DBR } Corner; -typedef enum -coordtype -{ - COMP_COORD, SYM_COORD, SYMCOMP_COORD -} CoordType; - typedef enum edge { @@ -84,32 +76,33 @@ trans typedef struct alg Alg; typedef struct alglist AlgList; typedef struct alglistnode AlgListNode; -typedef struct choicestep ChoiceStep; +typedef struct block Block; typedef struct command Command; typedef struct commandargs CommandArgs; typedef struct coordinate Coordinate; typedef struct cube Cube; -/*typedef struct dfsarg DfsArg;*/ -typedef struct fstcube FstCube; -typedef struct indexer Indexer; -typedef struct movable Movable; +typedef struct cubearray CubeArray; +typedef struct dfsarg DfsArg; +typedef struct estimatedata EstimateData; typedef struct moveset Moveset; +typedef struct piecefilter PieceFilter; typedef struct prunedata PruneData; typedef struct solveoptions SolveOptions; typedef struct step Step; typedef struct symdata SymData; typedef struct threaddatasolve ThreadDataSolve; typedef struct threaddatagenpt ThreadDataGenpt; -typedef struct transgroup TransGroup; -typedef bool (*Checker) (Cube *); -typedef bool (*CubeTester) (Cube *, Alg *); -/*typedef bool (*DfsMover) (DfsArg *);*/ -typedef void (*DfsExtraCopier) (void *, void *); -typedef Alg * (*Validator) (Alg *); +typedef Cube (*AntiIndexer) (uint64_t); +typedef bool (*Checker) (Cube); +typedef uint64_t (*CoordMover) (Move, uint64_t); +typedef uint64_t (*CoordTransformer) (Trans, uint64_t); +typedef int (*Estimator) (DfsArg *); +typedef bool (*Validator) (Alg *); typedef void (*Exec) (CommandArgs *); +typedef uint64_t (*Indexer) (Cube); typedef CommandArgs * (*ArgParser) (int, char **); -typedef bool (*Tester) (void); +typedef int (*TransDetector) (Cube, Trans *); typedef int (*TransFinder) (uint64_t, Trans *); @@ -122,10 +115,6 @@ alg bool * inv; int len; int allocated; - Move * move_normal; - int len_normal; - Move * move_inverse; - int len_inverse; }; struct @@ -144,13 +133,11 @@ alglistnode }; struct -choicestep +block { - char * shortname; - char * name; - Step * step[99]; - Trans t[99]; - char * ready_msg; + bool edge[12]; + bool corner[8]; + bool center[6]; }; struct @@ -169,7 +156,7 @@ commandargs bool success; Alg * scramble; SolveOptions * opts; - ChoiceStep * cs; + Step * step; Command * command; /* For help */ int n; char scrtype[20]; @@ -180,119 +167,119 @@ commandargs struct coordinate { - char * name; - CoordType type; - bool generated; - Indexer * i[99]; + Indexer index; uint64_t max; - uint64_t * mtable[NMOVES]; - uint64_t * ttable[NTRANS]; - TransGroup * tgrp; - Coordinate * base[2]; - uint64_t * symclass; - uint64_t * symrep; - Trans * transtorep; - Trans * ttrep_move[NMOVES]; - uint64_t * selfsim; + CoordMover move; + CoordTransformer transform; + SymData * sd; + TransFinder tfind; /* TODO: should be easy to remove */ + Coordinate * base; /* TODO: part of refactor */ }; struct cube { - int ep[12]; - int eo[12]; - int cp[8]; - int co[8]; - int xp[6]; + int epose; + int eposs; + int eposm; + int eofb; + int eorl; + int eoud; + int cp; + int coud; + int cofb; + int corl; + int cpos; }; -/* struct -movable +cubearray { - uint64_t val; - Trans t; + int * ep; + int * eofb; + int * eorl; + int * eoud; + int * cp; + int * coud; + int * corl; + int * cofb; + int * cpos; }; -*/ -/* struct dfsarg { - Cube * cube; - Movable ind[MAX_N_COORD]; - Trans t; - Step * s; + Step * step; SolveOptions * opts; + Trans t; + Cube cube; + Cube inverse; int d; - int bound; + uint64_t badmoves; + uint64_t badmovesinv; bool niss; + Move last1; + Move last2; + Move last1inv; + Move last2inv; + EstimateData * ed; AlgList * sols; pthread_mutex_t * sols_mutex; Alg * current_alg; - void * extra; }; -*/ -/* struct -dfsarg +estimatedata { - void * cube_data; - SolveOptions * opts; - int d; - int bound; - bool niss; - AlgList * sols; - Alg * current_alg; - Solver * solver; - Threader * threader; + int corners; + int normal_ud; + int normal_fb; + int normal_rl; + int inverse_ud; + int inverse_fb; + int inverse_rl; + int oldret; }; -*/ struct -fstcube +moveset { - uint16_t uf_eofb; - uint16_t uf_eposepe; - uint16_t uf_coud; - uint16_t uf_cp; - uint16_t fr_eofb; - uint16_t fr_eposepe; - uint16_t fr_coud; - uint16_t rd_eofb; - uint16_t rd_eposepe; - uint16_t rd_coud; + bool (*allowed)(Move); + bool (*allowed_next)(Move, Move, Move); + Move sorted_moves[NMOVES+1]; + uint64_t mask[NMOVES][NMOVES]; }; struct -indexer +piecefilter { - int n; - uint64_t (*index)(Cube *); - void (*to_cube)(uint64_t, Cube *); -}; - -struct -moveset -{ - char * name; - bool (*allowed)(Move); - bool (*can_append)(Alg *, Move, bool); - bool (*cancel_niss)(Alg *); - Move sorted_moves[NMOVES+1]; + bool epose; + bool eposs; + bool eposm; + bool eofb; + bool eorl; + bool eoud; + bool cp; + bool coud; + bool cofb; + bool corl; + bool cpos; }; struct prunedata { + char * filename; entry_group_t * ptable; + bool generated; uint64_t n; Coordinate * coord; Moveset * moveset; - uint64_t count[16]; bool compact; int base; + uint64_t count[16]; + PruneData * fallback; + uint64_t fbmod; }; struct @@ -313,30 +300,52 @@ solveoptions struct step { - Checker ready; + char * shortname; + char * name; bool final; - Moveset * moveset; - int n_coord; - Coordinate * coord[MAX_N_COORD]; - Trans coord_trans[MAX_N_COORD]; - PruneData * pd[MAX_N_COORD]; - bool pd_compact[MAX_N_COORD]; + Checker is_done; + Estimator estimate; + Checker ready; + char * ready_msg; Validator is_valid; - /*DfsMover custom_move_checkstop;*/ - DfsExtraCopier copy_extra; + Moveset * moveset; + Trans pre_trans; + TransDetector detect; + int ntables; + PruneData * tables[10]; +}; + +struct +symdata +{ + char * filename; + bool generated; + Coordinate * coord; + Coordinate * sym_coord; + int ntrans; + Trans * trans; + uint64_t * class; + uint64_t * unsym; + Trans * transtorep; + uint64_t * selfsim; + CoordTransformer transform; /* TODO: remove, use that of base coord */ }; -/* struct threaddatasolve { - DfsArg arg; int thid; + Trans t; + Cube cube; + Step * step; + int depth; + SolveOptions * opts; AlgList * start; AlgListNode ** node; + AlgList * sols; pthread_mutex_t * start_mutex; + pthread_mutex_t * sols_mutex; }; -*/ struct threaddatagenpt @@ -350,11 +359,4 @@ threaddatagenpt pthread_mutex_t * upmutex; }; -struct -transgroup -{ - int n; - Trans t[NTRANS]; -}; - #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 @@ -#define ENV_C - #include "env.h" bool 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 @@ #include #include -void init_env(); - extern char *tabledir; +void init_env(); + #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 @@ -#define FST_C - -#include "fst.h" - -static FstCube ep_to_fst_epos(int *ep); -static void init_fst_corner_invtables(); -static void init_fst_eo_invtables(); -static void init_fst_eo_update(uint64_t, uint64_t, int, Cube *); -static void init_fst_where_is_edge(); -static bool read_fst_tables_file(); -static bool write_fst_tables_file(); - -static int edge_slice[12] = {[FR] = 0, [FL] = 0, [BL] = 0, [BR] = 0, - [UL] = 1, [UR] = 1, [DR] = 1, [DL] = 1, - [UF] = 2, [UB] = 2, [DF] = 2, [DB] = 2}; - -static uint16_t inv_coud[FACTORIAL8][POW3TO7]; -static uint16_t inv_cp[FACTORIAL8]; -static uint16_t uf_cp_to_fr_cp[FACTORIAL8]; -static uint16_t uf_cp_to_rd_cp[FACTORIAL8]; -static uint16_t eo_invtable[3][POW2TO11][BINOM12ON4*FACTORIAL4]; -static uint16_t fst_where_is_edge_arr[3][12][BINOM12ON4*FACTORIAL4]; - -FstCube -cube_to_fst(Cube *cube) -{ - Cube c; - FstCube ret; - - copy_cube(cube, &c); - ret.uf_eofb = coord_eofb.i[0]->index(&c); - ret.uf_eposepe = coord_eposepe.i[0]->index(&c); - ret.uf_coud = coord_coud.i[0]->index(&c); - ret.uf_cp = coord_cp.i[0]->index(&c); - copy_cube(cube, &c); - apply_trans(fr, &c); - ret.fr_eofb = coord_eofb.i[0]->index(&c); - ret.fr_eposepe = coord_eposepe.i[0]->index(&c); - ret.fr_coud = coord_coud.i[0]->index(&c); - copy_cube(cube, &c); - apply_trans(rd, &c); - ret.rd_eofb = coord_eofb.i[0]->index(&c); - ret.rd_eposepe = coord_eposepe.i[0]->index(&c); - ret.rd_coud = coord_coud.i[0]->index(&c); - - return ret; -} - -static FstCube -ep_to_fst_epos(int *ep) -{ - static int eind[12] = { - [FR] = 0, [FL] = 1, [BL] = 2, [BR] = 3, - [UR] = 0, [DR] = 1, [DL] = 2, [UL] = 3, - [DB] = 0, [DF] = 1, [UF] = 2, [UB] = 3 - }; - static int eptrans_fr[12] = { - [FR] = UF, [DF] = UL, [FL] = UB, [UF] = UR, - [BR] = DF, [DB] = DL, [BL] = DB, [UB] = DR, - [UR] = FR, [DR] = FL, [DL] = BL, [UL] = BR - }; - static int eptrans_rd[12] = { - [DR] = UF, [FR] = UL, [UR] = UB, [BR] = UR, - [DL] = DF, [FL] = DL, [UL] = DB, [BL] = DR, - [DB] = FR, [DF] = FL, [UF] = BL, [UB] = BR - }; - - FstCube ret; - int i, ce, cs, cm; - int epe[4], eps[4], epm[4], epose[12], eposs[12], eposm[12]; - - memset(epose, 0, 12*sizeof(int)); - memset(eposs, 0, 12*sizeof(int)); - memset(eposm, 0, 12*sizeof(int)); - - for (i = 0, ce = 0; i < 12; i++) { - switch (edge_slice[ep[i]]) { - case 0: - epose[i] = 1; - epe[ce++] = eind[ep[i]]; - break; - case 1: - eposs[eptrans_fr[i]] = eind[ep[i]] + 1; - break; - default: - eposm[eptrans_rd[i]] = eind[ep[i]] + 1; - break; - } - } - - for (i = 0, cs = 0, cm = 0; i < 12; i++) { - if (eposs[i]) { - eps[cs++] = eposs[i] - 1; - eposs[i] = 1; - } - if (eposm[i]) { - epm[cm++] = eposm[i] - 1; - eposm[i] = 1; - } - } - - ret.uf_eposepe = subset_to_index(epose, 12, 4) * FACTORIAL4 + - perm_to_index(epe, 4); - ret.fr_eposepe = subset_to_index(eposs, 12, 4) * FACTORIAL4 + - perm_to_index(eps, 4); - ret.rd_eposepe = subset_to_index(eposm, 12, 4) * FACTORIAL4 + - perm_to_index(epm, 4); - - return ret; -} - -FstCube -fst_inverse(FstCube fst) -{ - FstCube ret; - int ep_inv[12]; - - ep_inv[FR] = fst_where_is_edge_arr[0][FR][fst.uf_eposepe]; - ep_inv[FL] = fst_where_is_edge_arr[0][FL][fst.uf_eposepe]; - ep_inv[BL] = fst_where_is_edge_arr[0][BL][fst.uf_eposepe]; - ep_inv[BR] = fst_where_is_edge_arr[0][BR][fst.uf_eposepe]; - - ep_inv[UR] = fst_where_is_edge_arr[1][UR][fst.fr_eposepe]; - ep_inv[UL] = fst_where_is_edge_arr[1][UL][fst.fr_eposepe]; - ep_inv[DR] = fst_where_is_edge_arr[1][DR][fst.fr_eposepe]; - ep_inv[DL] = fst_where_is_edge_arr[1][DL][fst.fr_eposepe]; - - ep_inv[UF] = fst_where_is_edge_arr[2][UF][fst.rd_eposepe]; - ep_inv[UB] = fst_where_is_edge_arr[2][UB][fst.rd_eposepe]; - ep_inv[DF] = fst_where_is_edge_arr[2][DF][fst.rd_eposepe]; - ep_inv[DB] = fst_where_is_edge_arr[2][DB][fst.rd_eposepe]; - - ret = ep_to_fst_epos(ep_inv); - - ret.uf_eofb = ((uint16_t)eo_invtable[0][fst.uf_eofb][fst.uf_eposepe]) | - ((uint16_t)eo_invtable[1][fst.uf_eofb][fst.fr_eposepe]) | - ((uint16_t)eo_invtable[2][fst.uf_eofb][fst.rd_eposepe]); - ret.fr_eofb = ((uint16_t)eo_invtable[0][fst.fr_eofb][fst.uf_eposepe]) | - ((uint16_t)eo_invtable[1][fst.fr_eofb][fst.fr_eposepe]) | - ((uint16_t)eo_invtable[2][fst.fr_eofb][fst.rd_eposepe]); - ret.rd_eofb = ((uint16_t)eo_invtable[0][fst.rd_eofb][fst.uf_eposepe]) | - ((uint16_t)eo_invtable[1][fst.rd_eofb][fst.fr_eposepe]) | - ((uint16_t)eo_invtable[2][fst.rd_eofb][fst.rd_eposepe]); - - ret.uf_cp = inv_cp[fst.uf_cp]; - - ret.uf_coud = inv_coud[fst.uf_cp][fst.uf_coud]; - ret.fr_coud = inv_coud[uf_cp_to_fr_cp[fst.uf_cp]][fst.fr_coud]; - ret.rd_coud = inv_coud[uf_cp_to_rd_cp[fst.uf_cp]][fst.rd_coud]; - - return ret; -} - -FstCube -fst_move(Move m, FstCube fst) -{ - FstCube ret; - Move m_fr, m_rd; - - m_fr = transform_move(fr, m); - m_rd = transform_move(rd, m); - - ret.uf_eofb = coord_eofb.mtable[m][fst.uf_eofb]; - ret.uf_eposepe = coord_eposepe.mtable[m][fst.uf_eposepe]; - ret.uf_coud = coord_coud.mtable[m][fst.uf_coud]; - ret.uf_cp = coord_cp.mtable[m][fst.uf_cp]; - - ret.fr_eofb = coord_eofb.mtable[m_fr][fst.fr_eofb]; - ret.fr_eposepe = coord_eposepe.mtable[m_fr][fst.fr_eposepe]; - ret.fr_coud = coord_coud.mtable[m_fr][fst.fr_coud]; - - ret.rd_eofb = coord_eofb.mtable[m_rd][fst.rd_eofb]; - ret.rd_eposepe = coord_eposepe.mtable[m_rd][fst.rd_eposepe]; - ret.rd_coud = coord_coud.mtable[m_rd][fst.rd_coud]; - - return ret; -} - -void -fst_to_cube(FstCube fst, Cube *cube) -{ - Cube e, s, m; - int i; - - coord_eposepe.i[0]->to_cube(fst.uf_eposepe, &e); - coord_eposepe.i[0]->to_cube(fst.fr_eposepe, &s); - apply_trans(inverse_trans(fr), &s); - coord_eposepe.i[0]->to_cube(fst.rd_eposepe, &m); - apply_trans(inverse_trans(rd), &m); - - for (i = 0; i < 12; i++) { - if (edge_slice[e.ep[i]] == 0) - cube->ep[i] = e.ep[i]; - if (edge_slice[s.ep[i]] == 1) - cube->ep[i] = s.ep[i]; - if (edge_slice[m.ep[i]] == 2) - cube->ep[i] = m.ep[i]; - } - - coord_eofb.i[0]->to_cube((uint64_t)fst.uf_eofb, cube); - coord_coud.i[0]->to_cube((uint64_t)fst.uf_coud, cube); - coord_cp.i[0]->to_cube((uint64_t)fst.uf_cp, cube); - - for (i = 0; i < 6; i++) - cube->xp[i] = i; -} - -void -init_fst() -{ - init_trans(); - gen_coord(&coord_eofb); - gen_coord(&coord_eposepe); - gen_coord(&coord_coud); - gen_coord(&coord_cp); - - if (!read_fst_tables_file()) { - fprintf(stderr, - "Could not load fst_tables, generating them\n"); - init_fst_corner_invtables(); - init_fst_eo_invtables(); - init_fst_where_is_edge(); - if (!write_fst_tables_file()) - fprintf(stderr, "fst_tables could not be written\b"); - } -} - -static void -init_fst_corner_invtables() -{ - Cube c, d; - uint64_t cp, coud; - - for (cp = 0; cp < FACTORIAL8; cp++) { - make_solved_corners(&c); - coord_cp.i[0]->to_cube(cp, &c); - - copy_cube_corners(&c, &d); - invert_cube_corners(&d); - inv_cp[cp] = coord_cp.i[0]->index(&d); - - for (coud = 0; coud < POW3TO7; coud++) { - copy_cube_corners(&c, &d); - coord_coud.i[0]->to_cube(coud, &d); - invert_cube_corners(&d); - inv_coud[cp][coud] = coord_coud.i[0]->index(&d); - } - - copy_cube_corners(&c, &d); - apply_trans(fr, &d); - uf_cp_to_fr_cp[cp] = coord_cp.i[0]->index(&d); - - copy_cube_corners(&c, &d); - apply_trans(rd, &d); - uf_cp_to_rd_cp[cp] = coord_cp.i[0]->index(&d); - } -} - -static void -init_fst_eo_invtables() -{ - uint64_t ep, eo; - Cube c, d; - - for (ep = 0; ep < BINOM12ON4 * FACTORIAL4; ep++) { - make_solved(&c); - coord_eposepe.i[0]->to_cube(ep, &c); - for (eo = 0; eo < POW2TO11; eo++) { - copy_cube_edges(&c, &d); - coord_eofb.i[0]->to_cube(eo, &d); - init_fst_eo_update(eo, ep, 0, &d); - - apply_trans(inverse_trans(fr), &d); - coord_eofb.i[0]->to_cube(eo, &d); - init_fst_eo_update(eo, ep, 1, &d); - - copy_cube_edges(&c, &d); - apply_trans(inverse_trans(rd), &d); - coord_eofb.i[0]->to_cube(eo, &d); - init_fst_eo_update(eo, ep, 2, &d); - } - } -} - -static void -init_fst_eo_update(uint64_t eo, uint64_t ep, int s, Cube *d) -{ - int i; - - for (i = 0; i < 12; i++) { - if (edge_slice[d->ep[i]] == s && d->eo[i] && d->ep[i] != 11) - eo_invtable[s][eo][ep] |= - ((uint16_t)1) << ((uint16_t)d->ep[i]); - } -} - -static void -init_fst_where_is_edge() -{ - Cube c, d; - uint64_t e; - - make_solved(&c); - for (e = 0; e < BINOM12ON4 * FACTORIAL4; e++) { - coord_eposepe.i[0]->to_cube(e, &c); - - copy_cube_edges(&c, &d); - fst_where_is_edge_arr[0][FR][e] = where_is_edge(FR, &d); - fst_where_is_edge_arr[0][FL][e] = where_is_edge(FL, &d); - fst_where_is_edge_arr[0][BL][e] = where_is_edge(BL, &d); - fst_where_is_edge_arr[0][BR][e] = where_is_edge(BR, &d); - - copy_cube_edges(&c, &d); - apply_trans(inverse_trans(fr), &d); - fst_where_is_edge_arr[1][UL][e] = where_is_edge(UL, &d); - fst_where_is_edge_arr[1][UR][e] = where_is_edge(UR, &d); - fst_where_is_edge_arr[1][DL][e] = where_is_edge(DL, &d); - fst_where_is_edge_arr[1][DR][e] = where_is_edge(DR, &d); - - copy_cube_edges(&c, &d); - apply_trans(inverse_trans(rd), &d); - fst_where_is_edge_arr[2][UF][e] = where_is_edge(UF, &d); - fst_where_is_edge_arr[2][UB][e] = where_is_edge(UB, &d); - fst_where_is_edge_arr[2][DF][e] = where_is_edge(DF, &d); - fst_where_is_edge_arr[2][DB][e] = where_is_edge(DB, &d); - } -} - -static bool -read_fst_tables_file() -{ - init_env(); - - FILE *f; - char fname[strlen(tabledir)+256]; - uint64_t i, j, r, total; - - strcpy(fname, tabledir); - strcat(fname, "/fst_tables"); - - if ((f = fopen(fname, "rb")) == NULL) - return false; - - r = 0; - total = FACTORIAL8*(POW3TO7+3) + 3*BINOM12ON4*FACTORIAL4*(12+POW2TO11); - - for (i = 0; i < FACTORIAL8; i++) - r += fread(inv_coud[i], sizeof(uint16_t), POW3TO7, f); - r += fread(inv_cp, sizeof(uint16_t), FACTORIAL8, f); - r += fread(uf_cp_to_fr_cp, sizeof(uint16_t), FACTORIAL8, f); - r += fread(uf_cp_to_rd_cp, sizeof(uint16_t), FACTORIAL8, f); - for (i = 0; i < 3; i++) - for (j = 0; j < POW2TO11; j++) - r += fread(eo_invtable[i][j], - sizeof(uint16_t), BINOM12ON4*FACTORIAL4, f); - for (i = 0; i < 3; i++) - for (j = 0; j < 12; j++) - r += fread(fst_where_is_edge_arr[i][j], - sizeof(uint16_t), BINOM12ON4*FACTORIAL4, f); - - fclose(f); - - return r == total; -} - -static bool -write_fst_tables_file() -{ - init_env(); - - FILE *f; - char fname[strlen(tabledir)+256]; - uint64_t i, j, w, total; - - strcpy(fname, tabledir); - strcat(fname, "/fst_tables"); - - if ((f = fopen(fname, "wb")) == NULL) - return false; - - w = 0; - total = FACTORIAL8*(POW3TO7+3) + 3*BINOM12ON4*FACTORIAL4*(12+POW2TO11); - - for (i = 0; i < FACTORIAL8; i++) - w += fwrite(inv_coud[i], sizeof(uint16_t), POW3TO7, f); - w += fwrite(inv_cp, sizeof(uint16_t), FACTORIAL8, f); - w += fwrite(uf_cp_to_fr_cp, sizeof(uint16_t), FACTORIAL8, f); - w += fwrite(uf_cp_to_rd_cp, sizeof(uint16_t), FACTORIAL8, f); - for (i = 0; i < 3; i++) - for (j = 0; j < POW2TO11; j++) - w += fwrite(eo_invtable[i][j], - sizeof(uint16_t), BINOM12ON4*FACTORIAL4, f); - for (i = 0; i < 3; i++) - for (j = 0; j < 12; j++) - w += fwrite(fst_where_is_edge_arr[i][j], - sizeof(uint16_t), BINOM12ON4*FACTORIAL4, f); - - fclose(f); - - return w == total; -} 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 @@ -#ifndef FST_H -#define FST_H - -#include "coord.h" - -FstCube cube_to_fst(Cube *cube); -FstCube fst_inverse(FstCube fst); -FstCube fst_move(Move m, FstCube fst); -void fst_to_cube(FstCube fst, Cube *cube); -void init_fst(); - -#endif - 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 @@ -#define MOVES_C - #include "moves.h" /* Local functions ***********************************************************/ +static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f); static void cleanup_aux(Alg *alg, Alg *ret, bool inv); +static bool read_mtables_file(); +static bool write_mtables_file(); /* Tables and other data *****************************************************/ -/* Moves are represented as cubes and applied using compose(). Every move is * - * translated to a an alg before filling the transition tables. * - * See init_moves(). */ +/* Every move is translated to a an alg before filling the + transition tables, see init_moves() */ + +static int edge_cycle[NMOVES][12] = +{ + [U] = { UR, UF, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR }, + [x] = { DF, FL, UF, FR, DB, BL, UB, BR, DR, DL, UL, UR }, + [y] = { UR, UF, UL, UB, DR, DF, DL, DB, BR, FR, FL, BL } +}; + +static int corner_cycle[NMOVES][8] = +{ + [U] = { UBR, UFR, UFL, UBL, DFR, DFL, DBL, DBR }, + [x] = { DFR, DFL, UFL, UFR, DBR, DBL, UBL, UBR }, + [y] = { UBR, UFR, UFL, UBL, DBR, DFR, DFL, DBL } +}; + +static int center_cycle[NMOVES][6] = +{ + [x] = { F_center, B_center, R_center, L_center, D_center, U_center }, + [y] = { U_center, D_center, B_center, F_center, R_center, L_center } +}; + +static int eofb_flipped[NMOVES][12] = { + [x] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 }, + [y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 } +}; + +static int eorl_flipped[NMOVES][12] = { + [x] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, + [y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 } +}; + +static int eoud_flipped[NMOVES][12] = { + [U] = { [UF] = 1, [UL] = 1, [UB] = 1, [UR] = 1 }, + [x] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 }, + [y] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } +}; + +static int coud_flipped[NMOVES][8] = { + [x] = { + [UFR] = 2, [UBR] = 1, [UFL] = 1, [UBL] = 2, + [DBR] = 2, [DFR] = 1, [DBL] = 1, [DFL] = 2 + } +}; + +static int corl_flipped[NMOVES][8] = { + [U] = { [UFR] = 1, [UBR] = 2, [UBL] = 1, [UFL] = 2 }, + [y] = { + [UFR] = 1, [UBR] = 2, [UBL] = 1, [UFL] = 2, + [DFR] = 2, [DBR] = 1, [DBL] = 2, [DFL] = 1 + } +}; -static Cube move_array[NMOVES]; +static int cofb_flipped[NMOVES][8] = { + [U] = { [UFR] = 2, [UBR] = 1, [UBL] = 2, [UFL] = 1 }, + [x] = { + [UFR] = 1, [UBR] = 2, [UBL] = 1, [UFL] = 2, + [DFR] = 2, [DBR] = 1, [DBL] = 2, [DFL] = 1 + }, + [y] = { + [UFR] = 2, [UBR] = 1, [UBL] = 2, [UFL] = 1, + [DFR] = 1, [DBR] = 2, [DBL] = 1, [DFL] = 2 + } +}; static char equiv_alg_string[100][NMOVES] = { [NULLMOVE] = "", @@ -76,52 +137,89 @@ static char equiv_alg_string[100][NMOVES] = { [z3] = " y x yyy " }; +/* Transition tables, to be loaded up at the beginning */ +int epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +int eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +int eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +int eofb_mtable[NMOVES][POW2TO11]; +int eorl_mtable[NMOVES][POW2TO11]; +int eoud_mtable[NMOVES][POW2TO11]; +int cp_mtable[NMOVES][FACTORIAL8]; +int coud_mtable[NMOVES][POW3TO7]; +int cofb_mtable[NMOVES][POW3TO7]; +int corl_mtable[NMOVES][POW3TO7]; +int cpos_mtable[NMOVES][FACTORIAL6]; + + +/* Local functions implementation ********************************************/ + +static Cube +apply_move_cubearray(Move m, Cube cube, PieceFilter f) +{ + /*init_moves();*/ + + CubeArray m_arr = { + edge_cycle[m], + eofb_flipped[m], + eorl_flipped[m], + eoud_flipped[m], + corner_cycle[m], + coud_flipped[m], + corl_flipped[m], + cofb_flipped[m], + center_cycle[m] + }; + + return move_via_arrays(&m_arr, cube, f); +} /* Public functions **********************************************************/ -void -apply_alg(Alg *alg, Cube *cube) +Cube +apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a) { - Cube aux; + Cube ret = {0}; int i; - copy_cube(cube, &aux); - make_solved(cube); - for (i = 0; i < alg->len; i++) if (alg->inv[i]) - apply_move(alg->move[i], cube); + ret = a ? apply_move(alg->move[i], ret) : + apply_move_cubearray(alg->move[i], ret, f); - invert_cube(cube); - compose(&aux, cube); + ret = compose_filtered(c, inverse_cube(ret), f); for (i = 0; i < alg->len; i++) if (!alg->inv[i]) - apply_move(alg->move[i], cube); -} + ret = a ? apply_move(alg->move[i], ret) : + apply_move_cubearray(alg->move[i], ret, f); -void -apply_move(Move m, Cube *cube) -{ - compose(&move_array[m], cube); + return ret; } -void -apply_move_centers(Move m, Cube *cube) +Cube +apply_alg(Alg *alg, Cube cube) { - compose_centers(&move_array[m], cube); + return apply_alg_generic(alg, cube, pf_all, true); } -void -apply_move_corners(Move m, Cube *cube) +Cube +apply_move(Move m, Cube cube) { - compose_corners(&move_array[m], cube); -} - -void -apply_move_edges(Move m, Cube *cube) -{ - compose_edges(&move_array[m], cube); + /*init_moves();*/ + + return (Cube) { + .epose = epose_mtable[m][cube.epose], + .eposs = eposs_mtable[m][cube.eposs], + .eposm = eposm_mtable[m][cube.eposm], + .eofb = eofb_mtable[m][cube.eofb], + .eorl = eorl_mtable[m][cube.eorl], + .eoud = eoud_mtable[m][cube.eoud], + .coud = coud_mtable[m][cube.coud], + .cofb = cofb_mtable[m][cube.cofb], + .corl = corl_mtable[m][cube.corl], + .cp = cp_mtable[m][cube.cp], + .cpos = cpos_mtable[m][cube.cpos] + }; } Alg * @@ -181,27 +279,31 @@ cleanup_aux(Alg *alg, Alg *ret, bool inv) { int i, j; Cube c, d; - Move m; + Move m, mm; Alg *equiv_alg; - make_solved(&c); + c = (Cube){0}; for (i = 0; i < alg->len; i++) { if (alg->inv[i] != inv) continue; equiv_alg = new_alg(equiv_alg_string[alg->move[i]]); - for (j = 0; j < equiv_alg->len; j++) - if (equiv_alg->move[j] == U) - append_move(ret, 3 * c.xp[U_center] + 1, inv); - else - apply_move(equiv_alg->move[j], &c); + for (j = 0; j < equiv_alg->len; j++) { + m = equiv_alg->move[j]; + if (m == U) { + mm = 3*what_center_at(c, U_center) + 1; + append_move(ret, mm, inv); + } else { + c = apply_move(m, c); + } + } free_alg(equiv_alg); } m = NULLMOVE; - switch (c.xp[F_center]) { + switch (what_center_at(c, F_center)) { case U_center: m = x3; break; @@ -215,7 +317,7 @@ cleanup_aux(Alg *alg, Alg *ret, bool inv) m = y3; break; case B_center: - if (c.xp[U_center] == U_center) + if (what_center_at(c, U_center) == U_center) m = y2; else m = x2; @@ -223,24 +325,120 @@ cleanup_aux(Alg *alg, Alg *ret, bool inv) default: break; } - - make_solved(&d); - apply_move(m, &d); + d = apply_move(m, (Cube){0}); if (m != NULLMOVE) append_move(ret, m, inv); m = NULLMOVE; - if (c.xp[U_center] == d.xp[D_center]) { + if (what_center_at(c, U_center) == what_center_at(d, D_center)) { m = z2; - } else if (c.xp[U_center] == d.xp[R_center]) { + } else if (what_center_at(c, U_center) == what_center_at(d, R_center)) { m = z3; - } else if (c.xp[U_center] == d.xp[L_center]) { + } else if (what_center_at(c, U_center) == what_center_at(d, L_center)) { m = z; } if (m != NULLMOVE) append_move(ret, m, inv); } +static bool +read_mtables_file() +{ + init_env(); + + FILE *f; + char fname[strlen(tabledir)+20]; + int m, b = sizeof(int); + bool r = true; + + /* Table sizes, used for reading and writing files */ + uint64_t me[11] = { + [0] = FACTORIAL12/FACTORIAL8, + [1] = FACTORIAL12/FACTORIAL8, + [2] = FACTORIAL12/FACTORIAL8, + [3] = POW2TO11, + [4] = POW2TO11, + [5] = POW2TO11, + [6] = FACTORIAL8, + [7] = POW3TO7, + [8] = POW3TO7, + [9] = POW3TO7, + [10] = FACTORIAL6 + }; + + strcpy(fname, tabledir); + strcat(fname, "/mtables"); + + if ((f = fopen(fname, "rb")) == NULL) + return false; + + for (m = 0; m < NMOVES; m++) { + r = r && fread(epose_mtable[m], b, me[0], f) == me[0]; + r = r && fread(eposs_mtable[m], b, me[1], f) == me[1]; + r = r && fread(eposm_mtable[m], b, me[2], f) == me[2]; + r = r && fread(eofb_mtable[m], b, me[3], f) == me[3]; + r = r && fread(eorl_mtable[m], b, me[4], f) == me[4]; + r = r && fread(eoud_mtable[m], b, me[5], f) == me[5]; + r = r && fread(cp_mtable[m], b, me[6], f) == me[6]; + r = r && fread(coud_mtable[m], b, me[7], f) == me[7]; + r = r && fread(corl_mtable[m], b, me[8], f) == me[8]; + r = r && fread(cofb_mtable[m], b, me[9], f) == me[9]; + r = r && fread(cpos_mtable[m], b, me[10], f) == me[10]; + } + + fclose(f); + return r; +} + +static bool +write_mtables_file() +{ + init_env(); + + FILE *f; + char fname[strlen(tabledir)+20]; + int m, b = sizeof(int); + bool r = true; + + /* Table sizes, used for reading and writing files */ + uint64_t me[11] = { + [0] = FACTORIAL12/FACTORIAL8, + [1] = FACTORIAL12/FACTORIAL8, + [2] = FACTORIAL12/FACTORIAL8, + [3] = POW2TO11, + [4] = POW2TO11, + [5] = POW2TO11, + [6] = FACTORIAL8, + [7] = POW3TO7, + [8] = POW3TO7, + [9] = POW3TO7, + [10] = FACTORIAL6 + }; + + strcpy(fname, tabledir); + strcat(fname, "/mtables"); + + if ((f = fopen(fname, "wb")) == NULL) + return false; + + for (m = 0; m < NMOVES; m++) { + r = r && fwrite(epose_mtable[m], b, me[0], f) == me[0]; + r = r && fwrite(eposs_mtable[m], b, me[1], f) == me[1]; + r = r && fwrite(eposm_mtable[m], b, me[2], f) == me[2]; + r = r && fwrite(eofb_mtable[m], b, me[3], f) == me[3]; + r = r && fwrite(eorl_mtable[m], b, me[4], f) == me[4]; + r = r && fwrite(eoud_mtable[m], b, me[5], f) == me[5]; + r = r && fwrite(cp_mtable[m], b, me[6], f) == me[6]; + r = r && fwrite(coud_mtable[m], b, me[7], f) == me[7]; + r = r && fwrite(corl_mtable[m], b, me[8], f) == me[8]; + r = r && fwrite(cofb_mtable[m], b, me[9], f) == me[9]; + r = r && fwrite(cpos_mtable[m], b, me[10], f) == me[10]; + } + + fclose(f); + return r; +} + void init_moves() { static bool initialized = false; @@ -248,54 +446,101 @@ init_moves() { return; initialized = true; + Cube c; + CubeArray arrs; + int i; + unsigned int ui; Move m; Alg *equiv_alg[NMOVES]; - static const Cube mcu = { - .ep = { UR, UF, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR }, - .cp = { UBR, UFR, UFL, UBL, DFR, DFL, DBL, DBR }, - }; - static const Cube mcx = { - .ep = { DF, FL, UF, FR, DB, BL, UB, BR, DR, DL, UL, UR }, - .eo = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 }, - .cp = { DFR, DFL, UFL, UFR, DBR, DBL, UBL, UBR }, - .co = { [UFR] = 2, [UBR] = 1, [UFL] = 1, [UBL] = 2, - [DBR] = 2, [DFR] = 1, [DBL] = 1, [DFL] = 2 }, - .xp = { F_center, B_center, R_center, - L_center, D_center, U_center }, - }; - static const Cube mcy = { - .ep = { UR, UF, UL, UB, DR, DF, DL, DB, BR, FR, FL, BL }, - .eo = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 }, - .cp = { UBR, UFR, UFL, UBL, DBR, DFR, DFL, DBL }, - .xp = { U_center, D_center, B_center, - F_center, R_center, L_center }, - }; + init_cube(); + + for (i = 0; i < NMOVES; i++) + equiv_alg[i] = new_alg(equiv_alg_string[i]); - move_array[U] = mcu; - move_array[x] = mcx; - move_array[y] = mcy; + /* Generate all move cycles and flips; I do this regardless */ + for (i = 0; i < NMOVES; i++) { + if (i == U || i == x || i == y) + continue; + + c = apply_alg_generic(equiv_alg[i], (Cube){0}, pf_all, false); + + arrs = (CubeArray) { + edge_cycle[i], + eofb_flipped[i], + eorl_flipped[i], + eoud_flipped[i], + corner_cycle[i], + coud_flipped[i], + corl_flipped[i], + cofb_flipped[i], + center_cycle[i] + }; + cube_to_arrays(c, &arrs, pf_all); + } + + if (read_mtables_file()) + return; - for (m = 0; m < NMOVES; m++) - equiv_alg[m] = new_alg(equiv_alg_string[m]); + fprintf(stderr, "Cannot load %s, generating it\n", "mtables"); + /* Initialize transition tables */ for (m = 0; m < NMOVES; m++) { - switch (m) { - case NULLMOVE: - make_solved(&move_array[m]); - break; - case U: - case x: - case y: - break; - default: - make_solved(&move_array[m]); - apply_alg(equiv_alg[m], &move_array[m]); - break; + for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) { + c = (Cube){ .epose = ui }; + c = apply_move_cubearray(m, c, pf_e); + epose_mtable[m][ui] = c.epose; + + c = (Cube){ .eposs = ui }; + c = apply_move_cubearray(m, c, pf_s); + eposs_mtable[m][ui] = c.eposs; + + c = (Cube){ .eposm = ui }; + c = apply_move_cubearray(m, c, pf_m); + eposm_mtable[m][ui] = c.eposm; + } + for (ui = 0; ui < POW2TO11; ui++ ) { + c = (Cube){ .eofb = ui }; + c = apply_move_cubearray(m, c, pf_eo); + eofb_mtable[m][ui] = c.eofb; + + c = (Cube){ .eorl = ui }; + c = apply_move_cubearray(m, c, pf_eo); + eorl_mtable[m][ui] = c.eorl; + + c = (Cube){ .eoud = ui }; + c = apply_move_cubearray(m, c, pf_eo); + eoud_mtable[m][ui] = c.eoud; + } + for (ui = 0; ui < POW3TO7; ui++) { + c = (Cube){ .coud = ui }; + c = apply_move_cubearray(m, c, pf_co); + coud_mtable[m][ui] = c.coud; + + c = (Cube){ .corl = ui }; + c = apply_move_cubearray(m, c, pf_co); + corl_mtable[m][ui] = c.corl; + + c = (Cube){ .cofb = ui }; + c = apply_move_cubearray(m, c, pf_co); + cofb_mtable[m][ui] = c.cofb; + } + for (ui = 0; ui < FACTORIAL8; ui++) { + c = (Cube){ .cp = ui }; + c = apply_move_cubearray(m, c, pf_cp); + cp_mtable[m][ui] = c.cp; + } + for (ui = 0; ui < FACTORIAL6; ui++) { + c = (Cube){ .cpos = ui }; + c = apply_move_cubearray(m, c, pf_cpos); + cpos_mtable[m][ui] = c.cpos; } } - for (m = 0; m < NMOVES; m++) - free_alg(equiv_alg[m]); + if (!write_mtables_file()) + fprintf(stderr, "Error writing mtables\n"); + + for (i = 0; i < NMOVES; i++) + free_alg(equiv_alg[i]); } 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 @@ #include "cube.h" #include "env.h" -void apply_alg(Alg *alg, Cube *cube); -void apply_move(Move m, Cube *cube); -void apply_move_centers(Move m, Cube *cube); -void apply_move_corners(Move m, Cube *cube); -void apply_move_edges(Move m, Cube *cube); +/* + * Tables are exposed to allow for faster moves in some cases. + */ +extern int epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +extern int eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +extern int eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +extern int eofb_mtable[NMOVES][POW2TO11]; +extern int eorl_mtable[NMOVES][POW2TO11]; +extern int eoud_mtable[NMOVES][POW2TO11]; +extern int cp_mtable[NMOVES][FACTORIAL8]; +extern int coud_mtable[NMOVES][POW3TO7]; +extern int cofb_mtable[NMOVES][POW3TO7]; +extern int corl_mtable[NMOVES][POW3TO7]; +extern int cpos_mtable[NMOVES][FACTORIAL6]; + +Cube apply_alg(Alg *alg, Cube cube); +Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a); +Cube apply_move(Move m, Cube cube); Alg * cleanup(Alg *alg); void 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 @@ -#define MOVESETS_C - -#include "movesets.h" - -static bool allowed_HTM(Move m); -static bool allowed_URF(Move m); -static bool allowed_eofb(Move m); -static bool allowed_drud(Move m); -static bool allowed_htr(Move m); -static bool can_append_HTM(Move l2, Move l1, Move m); -static bool can_append_HTM_cached(Alg *alg, Move m, bool inverse); -static bool cancel_niss_HTM_cached(Alg *alg); -static void init_can_append_HTM(); - -Moveset -moveset_HTM = { - .name = "HTM", - .allowed = allowed_HTM, - .can_append = can_append_HTM_cached, - .cancel_niss = cancel_niss_HTM_cached, -}; - -Moveset -moveset_URF = { - .name = "URF", - .allowed = allowed_URF, - .can_append = can_append_HTM_cached, - .cancel_niss = cancel_niss_HTM_cached, -}; - -Moveset -moveset_eofb = { - .name = "eofb", - .allowed = allowed_eofb, - .can_append = can_append_HTM_cached, - .cancel_niss = cancel_niss_HTM_cached, -}; - -Moveset -moveset_drud = { - .name = "drud", - .allowed = allowed_drud, - .can_append = can_append_HTM_cached, - .cancel_niss = cancel_niss_HTM_cached, -}; - -Moveset -moveset_htr = { - .name = "htr", - .allowed = allowed_htr, - .can_append = can_append_HTM_cached, - .cancel_niss = cancel_niss_HTM_cached, -}; - -Moveset * -all_movesets[] = { - &moveset_HTM, - &moveset_URF, - &moveset_eofb, - &moveset_drud, - &moveset_htr, - NULL -}; - -static uint64_t can_append_HTM_mask[NMOVES][NMOVES]; - -static bool -allowed_HTM(Move m) -{ - return m >= U && m <= B3; -} - -static bool -allowed_URF(Move m) -{ - Move b = base_move(m); - - return b == U || b == R || b == F; -} - -static bool -allowed_eofb(Move m) -{ - Move b = base_move(m); - - return b == U || b == D || b == R || b == L || - ((b == F || b == B) && m == b+1); -} - -static bool -allowed_drud(Move m) -{ - Move b = base_move(m); - - return b == U || b == D || - ((b == R || b == L || b == F || b == B) && m == b + 1); -} - -static bool -allowed_htr(Move m) -{ - Move b = base_move(m); - - return moveset_HTM.allowed(m) && m == b + 1; -} - -static bool -can_append_HTM(Move l2, Move l1, Move m) -{ - bool cancel, cancel_last, cancel_swap; - - cancel_last = l1 != NULLMOVE && base_move(l1) == base_move(m); - cancel_swap = l2 != NULLMOVE && base_move(l2) == base_move(m); - cancel = cancel_last || (commute(l1, l2) && cancel_swap); - - return !cancel; -} - -static bool -can_append_HTM_cached(Alg *alg, Move m, bool inverse) -{ - Move *moves, l1, l2; - uint64_t mbit; - int n; - - if (inverse) { - moves = alg->move_inverse; - n = alg->len_inverse; - } else { - moves = alg->move_normal; - n = alg->len_normal; - } - - l1 = n > 0 ? moves[n-1] : NULLMOVE; - l2 = n > 1 ? moves[n-2] : NULLMOVE; - - mbit = ((uint64_t)1) << m; - - return can_append_HTM_mask[l2][l1] & mbit; -} - -static bool -cancel_niss_HTM_cached(Alg *alg) -{ - Move i1, i2; - int n; - bool can_first, can_swap; - - n = alg->len_inverse; - i1 = n > 0 ? alg->move_inverse[n-1] : NULLMOVE; - i2 = n > 1 ? alg->move_inverse[n-2] : NULLMOVE; - - can_first = can_append_HTM_cached(alg, inverse_move(i1), false); - can_swap = can_append_HTM_cached(alg, inverse_move(i2), false); - - return can_first && (!commute(i1, i2) || can_swap); -} - -static void -init_can_append_HTM() -{ - Move l2, l1, m; - - for (l1 = 0; l1 < NMOVES; l1++) - for (l2 = 0; l2 < NMOVES; l2++) - for (m = 0; m < NMOVES; m++) - if (can_append_HTM(l2, l1, m)) - can_append_HTM_mask[l2][l1] - |= (((uint64_t)1) << m); -} - -void -init_moveset(Moveset *ms) -{ - int j; - Move m; - - for (j = 0, m = U; m < NMOVES; m++) - if (ms->allowed(m)) - ms->sorted_moves[j++] = m; - ms->sorted_moves[j] = NULLMOVE; - -/* TODO: should be here? maybe just init all movesets together anyway... */ - init_can_append_HTM(); -} - -void -init_movesets() -{ - int i; - - for (i = 0; all_movesets[i] != NULL; i++) - init_moveset(all_movesets[i]); -} 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 @@ -#ifndef MOVESETS_H -#define MOVESETS_H - -#include "alg.h" - -void init_moveset(Moveset *); -void init_movesets(); - -extern Moveset moveset_HTM; -extern Moveset moveset_URF; -extern Moveset moveset_eofb; -extern Moveset moveset_drud; -extern Moveset moveset_htr; - -#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 @@ +#include "pf.h" + +PieceFilter +pf_all = { + .epose = true, + .eposs = true, + .eposm = true, + .eofb = true, + .eorl = true, + .eoud = true, + .cp = true, + .cofb = true, + .corl = true, + .coud = true, + .cpos = true +}; + +PieceFilter +pf_4val = { + .epose = true, + .eposs = true, + .eposm = true, + .eofb = true, + .coud = true, + .cp = true +}; + +PieceFilter +pf_epcp = { + .epose = true, + .eposs = true, + .eposm = true, + .cp = true +}; + +PieceFilter +pf_cpos = { + .cpos = true +}; + +PieceFilter +pf_cp = { + .cp = true +}; + +PieceFilter +pf_ep = { + .epose = true, + .eposs = true, + .eposm = true +}; + +PieceFilter +pf_e = { + .epose = true +}; + +PieceFilter +pf_s = { + .eposs = true +}; + +PieceFilter +pf_m = { + .eposm = true +}; + +PieceFilter +pf_eo = { + .eofb = true, + .eorl = true, + .eoud = true +}; + +PieceFilter +pf_co = { + .cofb = true, + .corl = true, + .coud = true +}; + +PieceFilter +pf_coud = { + .coud = true +}; + +PieceFilter +pf_edges = { + .epose = true, + .eposs = true, + .eposm = true, + .eofb = true, + .eorl = true, + .eoud = true +}; 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 @@ +#ifndef PF_H +#define PF_H + +#include "cubetypes.h" + +extern PieceFilter pf_all; +extern PieceFilter pf_4val; +extern PieceFilter pf_epcp; +extern PieceFilter pf_cpos; +extern PieceFilter pf_cp; +extern PieceFilter pf_ep; +extern PieceFilter pf_e; +extern PieceFilter pf_s; +extern PieceFilter pf_m; +extern PieceFilter pf_eo; +extern PieceFilter pf_co; +extern PieceFilter pf_coud; +extern PieceFilter pf_edges; + +#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 @@ -#define PRUNING_C - #include "pruning.h" #define ENTRIES_PER_GROUP (2*sizeof(entry_group_t)) @@ -7,14 +5,106 @@ static int findchunk(PruneData *pd, int nchunks, uint64_t i); static void genptable_bfs(PruneData *pd, int d, int nt, int nc); +static void genptable_compress(PruneData *pd); static void genptable_fixnasty(PruneData *pd, int d, int nthreads); +static void genptable_setbase(PruneData *pd); static void * instance_bfs(void *arg); static void * instance_fixnasty(void *arg); -static void ptable_update(PruneData *pd, uint64_t ind, int m); +static void ptable_update(PruneData *pd, Cube cube, int m); +static void ptable_update_index(PruneData *pd, uint64_t ind, int m); +static int ptableval_index(PruneData *pd, uint64_t ind); static bool read_ptable_file(PruneData *pd); static bool write_ptable_file(PruneData *pd); -PruneData *active_pd[256]; +PruneData +pd_eofb_HTM = { + .filename = "pt_eofb_HTM", + .coord = &coord_eofb, + .moveset = &moveset_HTM, +}; + +PruneData +pd_coud_HTM = { + .filename = "pt_coud_HTM", + .coord = &coord_coud, + .moveset = &moveset_HTM, +}; + +PruneData +pd_cornershtr_HTM = { + .filename = "pt_cornershtr_HTM", + .coord = &coord_cornershtr, + .moveset = &moveset_HTM, +}; + +PruneData +pd_corners_HTM = { + .filename = "pt_corners_HTM", + .coord = &coord_corners, + .moveset = &moveset_HTM, +}; + +PruneData +pd_drud_sym16_HTM = { + .filename = "pt_drud_sym16_HTM", + .coord = &coord_drud_sym16, + .moveset = &moveset_HTM, +}; + +PruneData +pd_drud_eofb = { + .filename = "pt_drud_eofb", + .coord = &coord_drud_eofb, + .moveset = &moveset_eofb, +}; + +PruneData +pd_drudfin_noE_sym16_drud = { + .filename = "pt_drudfin_noE_sym16_drud", + .coord = &coord_drudfin_noE_sym16, + .moveset = &moveset_drud, +}; + +PruneData +pd_htr_drud = { + .filename = "pt_htr_drud", + .coord = &coord_htr_drud, + .moveset = &moveset_drud, +}; + +PruneData +pd_htrfin_htr = { + .filename = "pt_htrfin_htr", + .coord = &coord_htrfin, + .moveset = &moveset_htr, +}; + +PruneData +pd_nxopt31_HTM = { + .filename = "pt_nxopt31_HTM", + .coord = &coord_nxopt31, + .moveset = &moveset_HTM, + + .compact = true, + .fallback = &pd_drud_sym16_HTM, + .fbmod = BINOM8ON4, +}; + +PruneData * all_pd[] = { + &pd_eofb_HTM, + &pd_coud_HTM, + &pd_cornershtr_HTM, + &pd_corners_HTM, + &pd_drud_sym16_HTM, + &pd_drud_eofb, + &pd_drudfin_noE_sym16_drud, + &pd_htr_drud, + &pd_htrfin_htr, + &pd_nxopt31_HTM, + NULL +}; + +/* Functions *****************************************************************/ int findchunk(PruneData *pd, int nchunks, uint64_t i) @@ -27,47 +117,59 @@ findchunk(PruneData *pd, int nchunks, uint64_t i) return MIN(nchunks-1, (int)(i / chunksize)); } -PruneData * +void +free_pd(PruneData *pd) +{ + if (pd->generated) + free(pd->ptable); + + pd->generated = false; +} + +void genptable(PruneData *pd, int nthreads) { - int d, nchunks, i, maxv; - uint64_t oldn; - - for (i = 0; active_pd[i] != NULL; i++) { - if (active_pd[i]->coord == pd->coord && - active_pd[i]->moveset == pd->moveset && - active_pd[i]->compact == pd->compact) - return active_pd[i]; - } + bool compact; + int d, nchunks; + uint64_t oldn, sz; - init_moveset(pd->moveset); - gen_coord(pd->coord); + if (pd->generated) + return; - pd->ptable = malloc(ptablesize(pd) * sizeof(entry_group_t)); + /* TODO: check if memory is enough, otherwise maybe exit gracefully? */ + sz = ptablesize(pd) * (pd->compact ? 2 : 1); + pd->ptable = malloc(sz * sizeof(entry_group_t)); - if (read_ptable_file(pd)) - goto genptable_done; + if (read_ptable_file(pd)) { + pd->generated = true; + return; + } if (nthreads < 4) { fprintf(stderr, "--- Warning ---\n" "You are using only %d threads to generate the pruning" - "tables. This can take a while.\n" + "tables. This can take a while." "Unless you did this intentionally, you should re-run" "this command with `-t 4' or more.\n" "---------------\n\n", nthreads ); } + + /* For the first steps we proceed the same way for compact and not */ + compact = pd->compact; + pd->compact = false; + pd->generated = true; + nchunks = MIN(ptablesize(pd), 100000); - fprintf(stderr, "Generating pt_%s_%s with %d threads\n", - pd->coord->name, pd->moveset->name, nthreads); + fprintf(stderr, "Cannot load %s, generating it with %d threads\n", + pd->filename, nthreads); + memset(pd->ptable, ~(uint8_t)0, ptablesize(pd)*sizeof(entry_group_t)); - for (i = 0; i < 16; i++) - pd->count[i] = 0; - ptable_update(pd, 0, 0); + ptable_update(pd, (Cube){0}, 0); pd->n = 1; oldn = 0; genptable_fixnasty(pd, 0, nthreads); @@ -76,9 +178,7 @@ genptable(PruneData *pd, int nthreads) 0, pd->n - oldn, pd->n, pd->coord->max); oldn = pd->n; pd->count[0] = pd->n; - - maxv = pd->compact ? MIN(15, pd->base + 4) : 15; - for (d = 0; d < maxv && pd->n < pd->coord->max; d++) { + for (d = 0; d < 15 && pd->n < pd->coord->max; d++) { genptable_bfs(pd, d, nthreads, nchunks); genptable_fixnasty(pd, d+1, nthreads); fprintf(stderr, "Depth %d done, generated %" @@ -87,17 +187,14 @@ genptable(PruneData *pd, int nthreads) pd->count[d+1] = pd->n - oldn; oldn = pd->n; } - if (pd->compact) - fprintf(stderr, "Compact table, values above " - "%d are inaccurate.\n", maxv-1); fprintf(stderr, "Pruning table generated!\n"); - + + genptable_setbase(pd); + if (compact) + genptable_compress(pd); + if (!write_ptable_file(pd)) fprintf(stderr, "Error writing ptable file\n"); - -genptable_done: - for (i = 0; active_pd[i] != NULL; i++); - return active_pd[i] = pd; } static void @@ -134,6 +231,31 @@ genptable_bfs(PruneData *pd, int d, int nthreads, int nchunks) free(mtx[i]); } +static void +genptable_compress(PruneData *pd) +{ + int val; + uint64_t i, j; + entry_group_t mask, v; + + fprintf(stderr, "Compressing table to 2 bits per entry\n"); + + for (i = 0; i < pd->coord->max; i += ENTRIES_PER_GROUP_COMPACT) { + mask = (entry_group_t)0; + for (j = 0; j < ENTRIES_PER_GROUP_COMPACT; j++) { + if (i+j >= pd->coord->max) + break; + val = ptableval_index(pd, i+j) - pd->base; + v = (entry_group_t)MIN(3, MAX(0, val)); + mask |= v << (2*j); + } + pd->ptable[i/ENTRIES_PER_GROUP_COMPACT] = mask; + } + + pd->compact = true; + pd->ptable = realloc(pd->ptable, sizeof(entry_group_t)*ptablesize(pd)); +} + static void genptable_fixnasty(PruneData *pd, int d, int nthreads) { @@ -142,7 +264,7 @@ genptable_fixnasty(PruneData *pd, int d, int nthreads) ThreadDataGenpt td[nthreads]; pthread_mutex_t *upmtx; - if (pd->coord->type != SYMCOMP_COORD) + if (pd->coord->tfind == NULL) return; upmtx = malloc(sizeof(pthread_mutex_t)); @@ -162,12 +284,28 @@ genptable_fixnasty(PruneData *pd, int d, int nthreads) free(upmtx); } +static void +genptable_setbase(PruneData *pd) +{ + int i; + uint64_t sum, newsum; + + pd->base = 0; + sum = pd->count[0] + pd->count[1] + pd->count[2]; + for (i = 3; i < 16; i++) { + newsum = sum + pd->count[i] - pd->count[i-3]; + if (newsum > sum) + pd->base = i-3; + sum = newsum; + } +} + static void * instance_bfs(void *arg) { ThreadDataGenpt *td; uint64_t i, ii, blocksize, rmin, rmax, updated; - int j, pval, ichunk, oldc, newc; + int j, pval, ichunk; Move *ms; td = (ThreadDataGenpt *)arg; @@ -178,43 +316,25 @@ instance_bfs(void *arg) td->pd->coord->max : ((uint64_t)td->thid + 1) * blocksize; - if (td->pd->compact) { - if (td->d <= td->pd->base) { - oldc = 1; - newc = 1; - } else { - oldc = td->d - td->pd->base; - newc = td->d - td->pd->base; - } - } else { - oldc = td->d; - newc = td->d + 1; - } - updated = 0; for (i = rmin; i < rmax; i++) { ichunk = findchunk(td->pd, td->nchunks, i); pthread_mutex_lock(td->mutex[ichunk]); - pval = ptableval(td->pd, i); + pval = ptableval_index(td->pd, i); pthread_mutex_unlock(td->mutex[ichunk]); - if (pval == oldc) { + if (pval == td->d) { for (j = 0; ms[j] != NULLMOVE; j++) { - ii = move_coord(td->pd->coord, ms[j], i, NULL); + ii = td->pd->coord->move(ms[j], i); ichunk = findchunk(td->pd, td->nchunks, ii); pthread_mutex_lock(td->mutex[ichunk]); - pval = ptableval(td->pd, ii); - if (pval > newc) { - ptable_update(td->pd, ii, newc); + pval = ptableval_index(td->pd, ii); + if (pval > td->d+1) { + ptable_update_index(td->pd, + ii, td->d+1); updated++; } pthread_mutex_unlock(td->mutex[ichunk]); } - if (td->pd->compact && td->d <= td->pd->base) { - ichunk = findchunk(td->pd, td->nchunks, i); - pthread_mutex_lock(td->mutex[ichunk]); - ptable_update(td->pd, i, 0); - pthread_mutex_unlock(td->mutex[ichunk]); - } } } @@ -229,40 +349,30 @@ static void * instance_fixnasty(void *arg) { ThreadDataGenpt *td; - uint64_t i, ii, blocksize, rmin, rmax, updated, ss, M; - int j, oldc; - Trans t; + uint64_t i, ii, nb, blocksize, rmin, rmax, updated; + int j, n; + Trans t, aux[NTRANS]; td = (ThreadDataGenpt *)arg; - - /* We know type = SYMCOMP_COORD */ - M = td->pd->coord->base[1]->max; - blocksize = (td->pd->coord->base[0]->max / td->nthreads) * M; + nb = td->pd->coord->max / td->pd->coord->base->max; + blocksize = (td->pd->coord->base->max / td->nthreads) * nb; rmin = ((uint64_t)td->thid) * blocksize; rmax = td->thid == td->nthreads - 1 ? td->pd->coord->max : ((uint64_t)td->thid + 1) * blocksize; - if (td->pd->compact) { - if (td->d <= td->pd->base) - oldc = 1; - else - oldc = td->d - td->pd->base; - } else { - oldc = td->d; - } - updated = 0; for (i = rmin; i < rmax; i++) { - if (ptableval(td->pd, i) == oldc) { - ss = td->pd->coord->base[0]->selfsim[i/M]; - for (j = 0; j < td->pd->coord->base[0]->tgrp->n; j++) { - t = td->pd->coord->base[0]->tgrp->t[j]; - if (t == uf || !(ss & ((uint64_t)1<pd, i) == td->d) { + if ((n = td->pd->coord->tfind(i, aux)) == 1) + continue; + + for (j = 0; j < n; j++) { + if ((t = aux[j]) == uf) continue; - ii = trans_coord(td->pd->coord, t, i); - if (ptableval(td->pd, ii) > oldc) { - ptable_update(td->pd, ii, oldc); + ii = td->pd->coord->transform(t, i); + if (ptableval_index(td->pd, ii) > td->d) { + ptable_update_index(td->pd, ii, td->d); updated++; } } @@ -281,13 +391,11 @@ print_ptable(PruneData *pd) { uint64_t i; - printf("Table %s_%s\n", pd->coord->name, pd->moveset->name); - - if (pd->compact) { - printf("Compract table with base value: %d\n", pd->base); - printf("Values above %d are inaccurate.\n", pd->base + 3); - } - + if (!pd->generated) + genptable(pd, 1); /* TODO: set default nthreads somewhere */ + + printf("Table %s\n", pd->filename); + printf("Base value: %d\n", pd->base); for (i = 0; i < 16; i++) printf("%2" PRIu64 "\t%10" PRIu64 "\n", i, pd->count[i]); } @@ -303,31 +411,48 @@ ptablesize(PruneData *pd) } static void -ptable_update(PruneData *pd, uint64_t ind, int n) +ptable_update(PruneData *pd, Cube cube, int n) { - int sh; - entry_group_t f, mask; - uint64_t i, e, b; + ptable_update_index(pd, pd->coord->index(cube), n); +} - e = pd->compact ? ENTRIES_PER_GROUP_COMPACT : ENTRIES_PER_GROUP; - b = pd->compact ? 2 : 4; - f = pd->compact ? 3 : 15; +static void +ptable_update_index(PruneData *pd, uint64_t ind, int n) +{ + int sh; + entry_group_t mask; + uint64_t i; - sh = b * (ind % e); - mask = f << sh; - i = ind / e; + sh = 4 * (ind % ENTRIES_PER_GROUP); + mask = ((entry_group_t)15) << sh; + i = ind/ENTRIES_PER_GROUP; pd->ptable[i] &= ~mask; - pd->ptable[i] |= (((entry_group_t)n) & f) << sh; + pd->ptable[i] |= (((entry_group_t)n)&15) << sh; } int -ptableval(PruneData *pd, uint64_t ind) +ptableval(PruneData *pd, Cube cube) { - int sh; - uint64_t e; + return ptableval_index(pd, pd->coord->index(cube)); +} + +static int +ptableval_index(PruneData *pd, uint64_t ind) +{ + int sh, ret; + entry_group_t mask; + uint64_t i, e; entry_group_t m; + if (!pd->generated) { + fprintf(stderr, "Warning: request pruning table value" + " for uninitialized table %s.\n It's fine, but it" + " should not happen. Please report bug.\n", + pd->filename); + genptable(pd, 1); /* TODO: set default or remove this case */ + } + if (pd->compact) { e = ENTRIES_PER_GROUP_COMPACT; m = 3; @@ -338,7 +463,19 @@ ptableval(PruneData *pd, uint64_t ind) sh = (ind % e) * 4; } - return (pd->ptable[ind/e] & (m << sh)) >> sh; + mask = m << sh; + i = ind/e; + + ret = (pd->ptable[i] & mask) >> sh; + + if (pd->compact) { + if (ret) + ret += pd->base; + else + ret = ptableval_index(pd->fallback, ind / pd->fbmod); + } + + return ret; } static bool @@ -347,15 +484,13 @@ read_ptable_file(PruneData *pd) init_env(); FILE *f; - char fname[strlen(tabledir)+256]; + char fname[strlen(tabledir)+100]; int i; uint64_t r; strcpy(fname, tabledir); - strcat(fname, "/pt_"); - strcat(fname, pd->coord->name); - strcat(fname, "_"); - strcat(fname, pd->moveset->name); + strcat(fname, "/"); + strcat(fname, pd->filename); if ((f = fopen(fname, "rb")) == NULL) return false; @@ -376,15 +511,13 @@ write_ptable_file(PruneData *pd) init_env(); FILE *f; - char fname[strlen(tabledir)+256]; + char fname[strlen(tabledir)+100]; int i; uint64_t w; strcpy(fname, tabledir); - strcat(fname, "/pt_"); - strcat(fname, pd->coord->name); - strcat(fname, "_"); - strcat(fname, pd->moveset->name); + strcat(fname, "/"); + strcat(fname, pd->filename); if ((f = fopen(fname, "wb")) == NULL) 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 @@ #ifndef PRUNING_H #define PRUNING_H -#include "coord.h" -#include "movesets.h" +#include "symcoord.h" + +extern PruneData pd_eofb_HTM; +extern PruneData pd_coud_HTM; +extern PruneData pd_corners_HTM; +extern PruneData pd_cornershtr_HTM; +extern PruneData pd_drud_sym16_HTM; +extern PruneData pd_drud_eofb; +extern PruneData pd_drudfin_noE_sym16_drud; +extern PruneData pd_htr_drud; +extern PruneData pd_htrfin_htr; +extern PruneData pd_nxopt31_HTM; + +extern PruneData * all_pd[]; void free_pd(PruneData *pd); -PruneData * genptable(PruneData *data, int nthreads); +void genptable(PruneData *pd, int nthreads); void print_ptable(PruneData *pd); uint64_t ptablesize(PruneData *pd); -int ptableval(PruneData *pd, uint64_t ind); - -extern PruneData *active_pd[256]; +int ptableval(PruneData *pd, Cube cube); #endif 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 @@ -#define SHELL_C - #include "shell.h" static void cleanwhitespaces(char *line); @@ -9,9 +7,7 @@ bool checkfiles() { /* TODO: add more checks (other files, use checksum...) */ - /* How to check for pruning tables with new method? */ - /* Solution: use list of steps */ - /* + FILE *f; char fname[strlen(tabledir)+100]; int i; @@ -24,7 +20,6 @@ checkfiles() else fclose(f); } - */ return true; } @@ -142,14 +137,12 @@ launch(bool batchmode) free(shell_argv); } -#ifndef TEST int main(int argc, char *argv[]) { char *closing_cmd[1] = { "freemem" }; init_env(); - init_trans(); if (!checkfiles()) { fprintf(stderr, @@ -174,4 +167,3 @@ main(int argc, char *argv[]) return 0; } -#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 @@ -#define SOLVE_C - #include "solve.h" -void -dfs(DfsArg *arg, Solver *solver, Threader *threader) +/* Local functions ***********************************************************/ + +static bool allowed_next(Move move, DfsArg *arg); +static bool cancel_niss(DfsArg *arg); +static void copy_dfsarg(DfsArg *src, DfsArg *dst); +static void dfs(DfsArg *arg); +static void dfs_branch(DfsArg *arg); +static bool dfs_check_solved(DfsArg *arg); +static bool dfs_switch(DfsArg *arg); +static void dfs_niss(DfsArg *arg); +static bool dfs_stop(DfsArg *arg); +static void * instance_thread(void *arg); +static void invert_branch(DfsArg *arg); +static void multidfs(Cube c, Trans t, Step *s, SolveOptions *opts, + AlgList *sols, int d); +static bool niss_makes_sense(DfsArg *arg); +static bool solvestop(int d, int op, SolveOptions *opts, AlgList *sols); + +/* Local functions ***********************************************************/ + +static bool +allowed_next(Move m, DfsArg *arg) +{ + bool bad, allowed, order; + uint64_t mbit; + + mbit = ((uint64_t)1) << m; + bad = mbit & arg->badmoves; + allowed = mbit & arg->step->moveset->mask[arg->last2][arg->last1]; + order = !commute(arg->last1, m) || arg->last1 < m; + + return allowed && !bad && order; +} + +static bool +cancel_niss(DfsArg *arg) +{ + Moveset *ms; + Move i1, i2; + bool p, p1, p2, q, q1, q2; + + if (arg->last1inv == NULLMOVE) + return false; + + ms = arg->step->moveset; + i1 = inverse_move(arg->last1inv); + i2 = inverse_move(arg->last2inv); + + p1 = !ms->allowed_next(arg->last2, arg->last1, i1); + p2 = !ms->allowed_next(arg->last2, i1, arg->last1); + p = p1 || (commute(i1, arg->last1) && p2); + + q1 = !ms->allowed_next(arg->last2, arg->last1, i2); + q2 = !ms->allowed_next(arg->last2, i2, arg->last1); + q = q1 || (commute(i2, arg->last1) && q2); + + return p || (commute(i1, i2) && q); +} + +static void +copy_dfsarg(DfsArg *src, DfsArg *dst) +{ + dst->step = src->step; + dst->opts = src->opts; + dst->t = src->t; + dst->cube = src->cube; + dst->inverse = src->inverse; + dst->d = src->d; + dst->badmoves = src->badmoves; + dst->badmovesinv = src->badmovesinv; + dst->niss = src->niss; + dst->last1 = src->last1; + dst->last2 = src->last2; + dst->last1inv = src->last1inv; + dst->last2inv = src->last2inv; + dst->sols = src->sols; + dst->sols_mutex = src->sols_mutex; + dst->current_alg = src->current_alg; + + copy_estimatedata(src->ed, dst->ed); +} + +static void +dfs(DfsArg *arg) +{ + bool sw = false; + + if (dfs_stop(arg)) + return; + + if (dfs_check_solved(arg)) + return; + + if (arg->step->final && (sw = dfs_switch(arg))) + invert_branch(arg); + dfs_branch(arg); + + if (arg->opts->can_niss && !arg->niss && niss_makes_sense(arg)) + dfs_niss(arg); + + if (sw) + invert_branch(arg); +} + +static void +dfs_branch(DfsArg *arg) { int i; - DfsArg newarg; - Alg *sol; Move m; + DfsArg *newarg; - if (arg->current_alg->len > arg->d) - return; + newarg = malloc(sizeof(DfsArg)); + newarg->ed = malloc(sizeof(EstimateData)); + + for (i = 0; arg->step->moveset->sorted_moves[i] != NULLMOVE; i++) { + m = arg->step->moveset->sorted_moves[i]; + if (allowed_next(m, arg)) { + copy_dfsarg(arg, newarg); + newarg->last2 = arg->last1; + newarg->last1 = m; + newarg->cube = apply_move(m, arg->cube); + append_move(arg->current_alg, m, newarg->niss); - if (solver->is_solved(solver->param, arg->cubedata)) { -/* TODO: the "all" option should be re-implemented as setting -validate to null */ - -/* TODO: we also have to check if cancel with NISS; -we can't because we have no access to the s->final field -this should be done by the step's validator? */ - sol = solver->validate_solution(solver->param,arg->current_alg); - bool accepted = sol != NULL; - bool too_short = arg->current_alg->len != arg->d; - - if (accepted && !too_short) { -/* TODO: arg->t got lost in refactoring */ -/* transform_alg(inverse_trans(arg->t), sol);*/ - if (arg->opts->verbose) - print_alg(sol, false); - threader->append_sol(sol, arg->threaddata); + dfs(newarg); + + arg->current_alg->len--; } - return; } - if (arg->current_alg->len == arg->d) - return; + free(newarg->ed); + free(newarg); +} + +static bool +dfs_check_solved(DfsArg *arg) +{ + if (!arg->step->is_done(arg->cube)) + return false; -/* TODO: do not alloc */ - newarg.cubedata = solver->alloc_cubedata(solver->param); - for (i = 0; solver->moveset->sorted_moves[i] != NULLMOVE; i++) { - m = solver->moveset->sorted_moves[i]; - if (solver->moveset->can_append(arg->current_alg, m, arg->niss) - && compare_last(arg->current_alg, m, arg->niss) >= 0) { - append_move(arg->current_alg, m, arg->niss); - - solver->copy_cubedata( - solver->param, arg->cubedata, newarg.cubedata); - newarg.threaddata = arg->threaddata; - newarg.opts = arg->opts; - newarg.d = arg->d; - newarg.niss = arg->niss; - newarg.current_alg = arg->current_alg; - if (!solver->move_check_stop( - solver->param, &newarg, threader)) - dfs(&newarg, solver, threader); - - remove_last_move(arg->current_alg); + if (arg->current_alg->len == arg->d) { + if ((arg->step->is_valid(arg->current_alg) || arg->opts->all) + && (!arg->step->final || !cancel_niss(arg))) { + + pthread_mutex_lock(arg->sols_mutex); + + if (arg->sols->len < arg->opts->max_solutions) { + append_alg(arg->sols, arg->current_alg); + + transform_alg( + inverse_trans(arg->t), + arg->sols->last->alg + ); + if (arg->step->final) + inplace(unniss, arg->sols->last->alg); + + if (arg->opts->verbose) + print_alg(arg->sols->last->alg, false); + } + + pthread_mutex_unlock(arg->sols_mutex); } } - solver->free_cubedata(solver->param, newarg.cubedata); - - if (arg->opts->can_niss && !arg->niss && - solver->niss_makes_sense( - solver->param, arg->cubedata, arg->current_alg)) { - solver->invert_cube(solver->param, arg->cubedata); - arg->niss = true; - dfs(arg, solver, threader); + + return true; +} + +static void +dfs_niss(DfsArg *arg) +{ + DfsArg *newarg; + + newarg = malloc(sizeof(DfsArg)); + newarg->ed = malloc(sizeof(EstimateData)); + + copy_dfsarg(arg, newarg); + swapmove(&(newarg->last1), &(newarg->last1inv)); + swapmove(&(newarg->last2), &(newarg->last2inv)); + newarg->niss = !(arg->niss); + newarg->cube = inverse_cube(arg->cube); + + dfs(newarg); + + free(newarg->ed); + free(newarg); +} + +static bool +dfs_stop(DfsArg *arg) +{ + int lowerbound; + bool b; + + lowerbound = arg->step->estimate(arg); + if (arg->opts->can_niss && !arg->niss) + lowerbound = MIN(1, lowerbound); + + if (arg->current_alg->len + lowerbound > arg->d) { + b = true; + } else { + pthread_mutex_lock(arg->sols_mutex); + b = arg->sols->len >= arg->opts->max_solutions; + pthread_mutex_unlock(arg->sols_mutex); } + + return b; } +static bool +dfs_switch(DfsArg *arg) +{ + int i, bn, bi; + + bn = 0; + for (i = 0; arg->step->moveset->sorted_moves[i] != NULLMOVE; i++) + if (allowed_next(arg->step->moveset->sorted_moves[i], arg)) + bn++; + + swapmove(&(arg->last1), &(arg->last1inv)); + swapmove(&(arg->last2), &(arg->last2inv)); + swapu64(&(arg->badmoves), &(arg->badmovesinv)); + + bi = 0; + for (i = 0; arg->step->moveset->sorted_moves[i] != NULLMOVE; i++) + if (allowed_next(arg->step->moveset->sorted_moves[i], arg)) + bi++; + + swapmove(&(arg->last1), &(arg->last1inv)); + swapmove(&(arg->last2), &(arg->last2inv)); + swapu64(&(arg->badmoves), &(arg->badmovesinv)); + + return bi < bn; +} + +static void * +instance_thread(void *arg) +{ + bool b; + Cube c; + ThreadDataSolve *td; + AlgListNode *node; + DfsArg darg; + + td = (ThreadDataSolve *)arg; + + while (1) { + b = false; + + pthread_mutex_lock(td->start_mutex); + if ((node = *(td->node)) == NULL) + b = true; + else + *(td->node) = (*(td->node))->next; + pthread_mutex_unlock(td->start_mutex); + + if (b) + break; + + c = node->alg->inv[0] ? + apply_move(node->alg->move[0], inverse_cube(td->cube)) : + apply_move(node->alg->move[0], td->cube); + + darg.step = td->step; + darg.opts = td->opts; + darg.t = td->t; + darg.cube = c; + darg.d = td->depth; + darg.niss = node->alg->inv[0]; + darg.last1 = node->alg->move[0]; + darg.last2 = NULLMOVE; + darg.last1inv = NULLMOVE; + darg.last2inv = NULLMOVE; + darg.sols = td->sols; + darg.sols_mutex = td->sols_mutex; + darg.current_alg = new_alg(""); + append_move(darg.current_alg, node->alg->move[0], + node->alg->inv[0]); + darg.ed = malloc(sizeof(EstimateData)); + reset_estimatedata(darg.ed); + darg.badmoves = 0; + darg.badmovesinv = 0; + + dfs(&darg); + + free_alg(darg.current_alg); + free(darg.ed); + } + + return NULL; +} + +static void +invert_branch(DfsArg *arg) +{ + Cube aux; + + aux = arg->cube; + arg->cube = is_solved(arg->inverse) ? + inverse_cube(arg->cube) : arg->inverse; + arg->inverse = aux; + + swapu64(&(arg->badmoves), &(arg->badmovesinv)); + arg->niss = !(arg->niss); + swapmove(&(arg->last1), &(arg->last1inv)); + swapmove(&(arg->last2), &(arg->last2inv)); + invert_estimatedata(arg->ed); +} + +static void +multidfs(Cube c, Trans tr, Step *s, SolveOptions *opts, AlgList *sols, int d) +{ + int i; + Alg *alg; + AlgList *start; + AlgListNode **node; + pthread_t t[opts->nthreads]; + ThreadDataSolve td[opts->nthreads]; + pthread_mutex_t *start_mutex, *sols_mutex; + + node = malloc(sizeof(AlgListNode *)); + start_mutex = malloc(sizeof(pthread_mutex_t)); + sols_mutex = malloc(sizeof(pthread_mutex_t)); + + start = new_alglist(); + pthread_mutex_init(start_mutex, NULL); + pthread_mutex_init(sols_mutex, NULL); + + for (i = 0; s->moveset->sorted_moves[i] != NULLMOVE; i++) { + alg = new_alg(""); + append_move(alg, s->moveset->sorted_moves[i], false); + append_alg(start, alg); + if (opts->can_niss) { + alg->inv[0] = true; + append_alg(start, alg); + } + free_alg(alg); + } + *node = start->first; + + for (i = 0; i < opts->nthreads; i++) { + td[i].thid = i; + td[i].t = tr; + td[i].cube = c; + td[i].step = s; + td[i].depth = d; + td[i].opts = opts; + td[i].start = start; + td[i].node = node; + td[i].sols = sols; + td[i].start_mutex = start_mutex; + td[i].sols_mutex = sols_mutex; + pthread_create(&t[i], NULL, instance_thread, &td[i]); + } + + for (i = 0; i < opts->nthreads; i++) + pthread_join(t[i], NULL); + + free_alglist(start); + free(node); + free(start_mutex); + free(sols_mutex); +} + +static bool +niss_makes_sense(DfsArg *arg) +{ + Cube testcube; + + testcube = apply_move(inverse_move(arg->last1), (Cube){0}); + return arg->current_alg->len == 0 || !arg->step->is_done(testcube); +} + +static bool +solvestop(int d, int op, SolveOptions *opts, AlgList *sols) +{ + bool opt_done, max_moves_exceeded, max_sols_exceeded; + + opt_done = opts->optimal != -1 && op != -1 && d > opts->optimal + op; + max_moves_exceeded = d > opts->max_moves; + max_sols_exceeded = sols->len >= opts->max_solutions; + + return opt_done || max_moves_exceeded || max_sols_exceeded; +} + +/* Public functions **********************************************************/ + AlgList * -solve(Cube *cube, SolveOptions *opts, Solver **solver, Threader *threader) +solve(Cube cube, Step *step, SolveOptions *opts) { - int i, d, optimal; - bool ready[MAX_SOLVERS], stop, one_ready; - DfsArg arg[MAX_SOLVERS]; + bool ready; + int i, d, op, nt; AlgList *sols; + Cube c; + Trans tt[NTRANS]; + + prepare_step(step, opts); - one_ready = false; - for (i = 0; solver[i] != NULL; i++) { - arg[i].cubedata = - solver[i]->prepare_cube(solver[i]->param, cube); - arg[i].opts = opts; - ready[i] = arg[i].cubedata != NULL; - one_ready = one_ready || ready[i]; + if (step->detect != NULL) { + nt = step->detect(cube, tt); + } else { + tt[0] = step->pre_trans; + ready = step->ready == NULL || + step->ready(apply_trans(tt[0], cube)); + nt = ready ? 1 : 0; } sols = new_alglist(); - if (!one_ready) { - fprintf(stderr, "Cube not ready for solving\n"); + + if (nt == 0) { + fprintf(stderr, "Cube not ready for solving step: "); + fprintf(stderr, "%s\n", step->ready_msg); return sols; } - optimal = opts->max_moves; - stop = false; - for (d = opts->min_moves; d <= opts->max_moves && !stop; d++) { + if (opts->min_moves == 0) { + for (i = 0; i < nt; i++) { + c = apply_trans(tt[i], cube); + if (step->is_done(c)) { + append_alg(sols, new_alg("")); + return sols; + } + } + } + + op = -1; + for (d = opts->min_moves; !solvestop(d, op, opts, sols); d++) { if (opts->verbose) fprintf(stderr, "Searching depth %d\n", d); - for (i = 0; solver[i] != NULL && !stop; i++) { - if (!ready[i]) - continue; + for (i = 0; i < nt && !solvestop(d, op, opts, sols); i++) { + c = apply_trans(tt[i], cube); + multidfs(c, tt[i], step, opts, sols, d); + if (sols->len > 0 && op == -1) + op = d; + } + } - arg[i].d = d; - threader->dispatch(&arg[i], sols, solver[i], threader); + return sols; +} - if (sols->len > 0) - optimal = MIN(optimal, d); +/* TODO: make more general! */ +Alg * +solve_2phase(Cube cube, int nthreads) +{ + int bestlen, newb; + Alg *bestalg, *ret; + AlgList *sols1, *sols2; + AlgListNode *i; + Cube c; + SolveOptions opts1, opts2; + + opts1.min_moves = 0; + opts1.max_moves = 13; + opts1.max_solutions = 20; + opts1.nthreads = nthreads; + opts1.optimal = 3; + opts1.can_niss = false; + opts1.verbose = false; + opts1.all = true; - stop = sols->len >= opts->max_solutions; + opts2.min_moves = 0; + opts2.max_moves = 19; + opts2.max_solutions = 1; + opts2.nthreads = nthreads; + opts2.can_niss = false; + opts2.verbose = false; + + /* We skip step1 if it is solved on any axis */ + if (drany_HTM.is_done(cube)) { + sols1 = new_alglist(); + append_alg(sols1, new_alg("")); + } else { + sols1 = solve(cube, &drany_HTM, &opts1); + } + bestalg = new_alg(""); + bestlen = 999; + for (i = sols1->first; i != NULL; i = i->next) { + c = apply_alg(i->alg, cube); + sols2 = solve(c, &dranyfin_DR, &opts2); + + if (sols2->len > 0) { + newb = i->alg->len + sols2->first->alg->len; + if (newb < bestlen) { + bestlen = newb; + copy_alg(i->alg, bestalg); + compose_alg(bestalg, sols2->first->alg); + } } - stop = stop || - (opts->optimal != -1 && d >= opts->optimal + optimal); + + free_alglist(sols2); } -/* TODO: some cleanup (free cubedata) */ -/* TODO: actually, preparation should be done somewhere else */ + free_alglist(sols1); - return sols; + ret = cleanup(bestalg); + free_alg(bestalg); + + return ret; } 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 @@ #define SOLVE_H #include "moves.h" +#include "steps.h" +#include "trans.h" -#define MAX_SOLVERS 99 - -typedef struct dfsarg DfsArg; -typedef struct threader Threader; -typedef struct solver Solver; - -/* TODO: add solver and threader in DfsData, remove from dispatch args and similar */ - -struct dfsarg { - void * cubedata; - void * threaddata; - SolveOptions * opts; - int d; - bool niss; - Alg * current_alg; -}; - -struct threader { - void (*append_sol)(Alg *, void *); - void (*dispatch)(DfsArg *, AlgList *, Solver *, Threader *); - int (*get_nsol)(void *); -/* TODO: threader should have param, like solver? */ -}; - -struct solver { - Moveset * moveset; - bool (*move_check_stop)(void *, DfsArg *, Threader *); - Alg * (*validate_solution)(void *, Alg *); - bool (*niss_makes_sense)(void *, void *, Alg *); -/* TODO: move param to somewhere where it makes more sense */ - void * param; -/* TODO: the following should be part of a generic cube description */ -/* TODO: remove alloc? */ -/* TODO: revisit apply_move, maybe apply_alg? or both? */ - void * (*alloc_cubedata)(void *); - void (*copy_cubedata)(void *, void *, void *); - void (*free_cubedata)(void *, void *); - void (*invert_cube)(void *, void *); - bool (*is_solved)(void *, void *); - void (*apply_move)(void *, void *, Move); -/* TODO: remove dependence on Cube, preparation should be done before */ - void * (*prepare_cube)(void *, Cube *); -}; - -void dfs(DfsArg *, Solver *, Threader *); -/* TODO: remove dependence on Cube, preparation should be done before */ -AlgList * solve(Cube *, SolveOptions *, Solver **, Threader *); +AlgList * solve(Cube cube, Step *step, SolveOptions *opts); +Alg * solve_2phase(Cube cube, int nthreads); #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 @@ -#include "solver_step.h" - -typedef struct { - Cube * cube; - uint64_t * val; - Trans * t; -} CubeData; - -static void apply_move_cubedata(void *, void *, Move); -static void init_indexes(Step *, CubeData *); -static void * prepare_cube(void *, Cube *); -static bool move_check_stop_eager(void *, DfsArg *, Threader *); -static bool move_check_stop_lazy(void *, DfsArg *, Threader *); -static bool move_check_stop_nonsol(void *, DfsArg *, Threader *); -static bool is_solved_step(void *, void *); -static Alg * validate_solution(void *, Alg *); -static void * alloc_cubedata(void *); -static void copy_cubedata(void *, void *, void *); -static void free_cubedata(void *, void *); -static void invert_cubedata(void *, void *); -static bool niss_makes_sense(void *, void *, Alg *); -static Solver * new_stepsolver_nocheckstop(Step *step); - -static void -apply_move_cubedata(void *param, void *cubedata, Move m) -{ - Step *s = (Step *)param; - CubeData *data = (CubeData *)cubedata; - - Trans tt; - for (int i = 0; i < s->n_coord; i++) { - Move mm = transform_move(data->t[i], m); - data->val[i] = move_coord(s->coord[i], mm, data->val[i], &tt); - data->t[i] = transform_trans(tt, data->t[i]); - } -} - -static void -init_indexes(Step *step, CubeData *data) -{ - int i; - Cube moved; - Trans t, tt; - - for (i = 0; i < step->n_coord; i++) { - t = step->coord_trans[i]; - copy_cube(data->cube, &moved); - apply_trans(t, &moved); - data->val[i] = index_coord(step->coord[i], &moved, &tt); - data->t[i] = transform_trans(tt, t); - } -} - -static void * -prepare_cube(void *param, Cube *cube) -{ - int i; - Step *s; - CubeData *data; - - s = (Step *)param; - - for (i = 0; i < s->n_coord; i++) { - s->pd[i] = malloc(sizeof(PruneData)); - s->pd[i]->moveset = s->moveset; -/* TODO: check if moveset initialization works fine, - e.g. if there is a variable to save the initialized status - or if it gets initialized multiple times */ - init_moveset(s->moveset); - s->pd[i]->coord = s->coord[i]; - gen_coord(s->coord[i]); - s->pd[i]->compact = s->pd_compact[i]; - s->pd[i] = genptable(s->pd[i], 4); /* TODO: threads */ - } - - data = alloc_cubedata(param); - data->cube = malloc(sizeof(Cube)); - copy_cube(cube, data->cube); - init_indexes(s, data); - - return data; -} - -static bool -move_check_stop_eager(void *param, DfsArg *arg, Threader *threader) -{ - int nsol; - - if (move_check_stop_nonsol(param, arg, threader)) - return true; - - nsol = threader->get_nsol(arg->threaddata); - return nsol >= arg->opts->max_solutions; -} - -static bool -move_check_stop_lazy(void *param, DfsArg *arg, Threader *threader) -{ - int nsol; - - nsol = threader->get_nsol(arg->threaddata); - if (nsol >= arg->opts->max_solutions) - return true; - - return move_check_stop_nonsol(param, arg, threader); -} - -/* TODO: split in 2 (nissable / non-nissable) and only move cube - when nissable */ -static bool -move_check_stop_nonsol(void *param, DfsArg *arg, Threader *threader) -{ - int i, goal, bound; - Move mm, lastmove; - Trans tt = uf; - CubeData *data; - Step *s; - - s = (Step *)param; - data = (CubeData *)arg->cubedata; - - - bound = 0; - goal = arg->d - arg->current_alg->len; -/* TODO: check if len is 0 */ - lastmove = arg->current_alg->move[arg->current_alg->len-1]; - for (i = 0; i < s->n_coord; i++) { - mm = transform_move(data->t[i], lastmove); - data->val[i] = move_coord(s->coord[i], mm, data->val[i], &tt); - data->t[i] = transform_trans(tt, data->t[i]); - - bound = MAX(bound, ptableval(s->pd[i], data->val[i])); - if (arg->opts->can_niss && !arg->niss) - bound = MIN(1, bound); - - if (bound > goal) { - return true; - } - } - if (arg->opts->can_niss && !arg->niss) - apply_move(lastmove, data->cube); - - return false; -} - -static bool -is_solved_step(void *param, void *cubedata) -{ - int i; - Step *s; - CubeData *data; - - s = (Step *)param; - data = (CubeData *)cubedata; - - for (i = 0; i < s->n_coord; i++) - if (data->val[i] != 0) - return false; - - return true; -} - -static Alg * -validate_solution(void *param, Alg *alg) -{ - return ((Step *)param)->is_valid(alg); -} - -static void * -alloc_cubedata(void *param) -{ - Step *s; - CubeData *data; - - s = (Step *)param; - - data = malloc(sizeof(CubeData)); - /* We do not need to allocate a cube */ - data->val = malloc(s->n_coord * sizeof(uint64_t)); - data->t = malloc(s->n_coord * sizeof(Trans)); - - return data; -} - -static void -copy_cubedata(void *param, void *src, void *dst) -{ - int i; - Step *s; - CubeData *newdata, *olddata; - - s = (Step *)param; - olddata = (CubeData *)src; - newdata = (CubeData *)dst; - -/* TODO: do not copy if not nissable */ - newdata->cube = malloc(sizeof(Cube)); - copy_cube(olddata->cube, newdata->cube); - for (i = 0; i < s->n_coord; i++) { - newdata->val[i] = olddata->val[i]; - newdata->t[i] = olddata->t[i]; - } -} - -static void -free_cubedata(void *param, void *cubedata) -{ - CubeData *data; - - data = (CubeData *)cubedata; - - free(data->t); - free(data->val); - free(data->cube); - free(data); -} - -static void -invert_cubedata(void *param, void *cubedata) -{ - Step *s; - CubeData *data; - - s = (Step *)param; - data = (CubeData *)cubedata; - - invert_cube(data->cube); - init_indexes(s, data); -} - -static bool -niss_makes_sense(void *param, void *cubedata, Alg *alg) -{ - Step *s; - CubeData *data; - - s = (Step *)param; - data = (CubeData *)cubedata; - - if (s->final) - return false; - - if (alg->len_normal == 0) - return true; - - Move m = inverse_move(alg->move_normal[alg->len_normal-1]); - for (int i = 0; i < s->n_coord; i++) { - Move mm = transform_move(data->t[i], m); - uint64_t u = move_coord(s->coord[i], mm, 0, NULL); - if (ptableval(s->pd[i], u) > 0) - return true; - } - - return false; -} - -static Solver * -new_stepsolver_nocheckstop(Step *step) -{ - Solver *solver; - - solver = malloc(sizeof(Solver)); - - solver->moveset = step->moveset; - solver->param = step; - - solver->apply_move = apply_move_cubedata; - solver->prepare_cube = prepare_cube; - solver->is_solved = is_solved_step; - solver->validate_solution = validate_solution; - solver->alloc_cubedata = alloc_cubedata; - solver->copy_cubedata = copy_cubedata; - solver->free_cubedata = free_cubedata; - solver->invert_cube = invert_cubedata; - solver->niss_makes_sense = niss_makes_sense; - - return solver; -} - -Solver * -new_stepsolver_eager(Step *step) -{ - Solver *solver; - - solver = new_stepsolver_nocheckstop(step); - solver->move_check_stop = move_check_stop_eager; - - return solver; -} - -Solver * -new_stepsolver_lazy(Step *step) -{ - Solver *solver; - - solver = new_stepsolver_nocheckstop(step); - solver->move_check_stop = move_check_stop_lazy; - - return solver; -} - -void -free_stepsolver(Solver *solver) -{ - free(solver); -} 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 @@ -#ifndef SOLVER_STEP_H -#define SOLVER_STEP_H - -#include "cube.h" -#include "solve.h" -#include "steps.h" - -Solver *new_stepsolver_eager(Step *); -Solver *new_stepsolver_lazy(Step *); -void free_stepsolver(Solver *); - -#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 @@ -#define STEPS_C - #include "steps.h" -/* TODO: change all checkers to use coordinates! */ +#define UPDATECHECKSTOP(a, b, c) if ((a=(MAX((a),(b))))>(c)) return (a); + +/* Checkers, estimators and validators ***************************************/ + +static bool check_centers(Cube cube); +static bool check_coud_HTM(Cube cube); +static bool check_coud_URF(Cube cube); +static bool check_corners_HTM(Cube cube); +static bool check_corners_URF(Cube cube); +static bool check_cornershtr(Cube cube); +static bool check_eofb(Cube cube); +static bool check_drud(Cube cube); +static bool check_htr(Cube cube); + +static int estimate_eofb_HTM(DfsArg *arg); +static int estimate_coud_HTM(DfsArg *arg); +static int estimate_coud_URF(DfsArg *arg); +static int estimate_corners_HTM(DfsArg *arg); +static int estimate_cornershtr_HTM(DfsArg *arg); +static int estimate_corners_URF(DfsArg *arg); +static int estimate_cornershtr_URF(DfsArg *arg); +static int estimate_drud_HTM(DfsArg *arg); +static int estimate_drud_eofb(DfsArg *arg); +static int estimate_dr_eofb(DfsArg *arg); +static int estimate_drudfin_drud(DfsArg *arg); +static int estimate_htr_drud(DfsArg *arg); +static int estimate_htrfin_htr(DfsArg *arg); +static int estimate_nxopt31_HTM(DfsArg *arg); +static int estimate_light_HTM(DfsArg *arg); + +static int estimate_nxoptlike(DfsArg *arg, PruneData *pd); + +static bool always_valid(Alg *alg); +static bool validate_singlecw_ending(Alg *alg); + +/* Pre-transformation detectors **********************************************/ + +static int detect_pretrans_eofb(Cube cube, Trans *ret); +static int detect_pretrans_drud(Cube cube, Trans *ret); +static int detect_pretrans_void_3axis(Cube cube, Trans *ret); + +/* Messages for when cube is not ready ***************************************/ + +static char check_centers_msg[100] = "cube must be oriented (centers solved)"; +static char check_eo_msg[100] = "EO must be solved on given axis"; +static char check_dr_msg[100] = "DR must be solved on given axis"; +static char check_htr_msg[100] = "HTR must be solved"; +static char check_drany_msg[100] = "DR must be solved on at least one axis"; + +/* Steps *********************************************************************/ + +/* Optimal solvers *******************/ + +Step +optimal_HTM = { + .shortname = "optimal", + .name = "Optimal solve (in HTM)", + + .final = true, + .is_done = is_solved, + .estimate = estimate_nxopt31_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = always_valid, + .moveset = &moveset_HTM, + + .pre_trans = uf, + + .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, + .ntables = 2, +}; + +Step +optimal_light_HTM = { + .shortname = "light", + .name = "Optimal solve (in HTM), small table (500Mb RAM total)", + + .final = true, + .is_done = is_solved, + .estimate = estimate_light_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = always_valid, + .moveset = &moveset_HTM, + + .pre_trans = uf, + + .tables = {&pd_drud_sym16_HTM, &pd_corners_HTM}, + .ntables = 2, +}; + +/* Optimal after EO ******************/ + +Step +eofin_eo = { + .shortname = "eofin", + .name = "Optimal solve after EO without breaking EO (detected)", + + .final = true, + .is_done = is_solved, + .estimate = estimate_nxopt31_HTM, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = always_valid, + .moveset = &moveset_eofb, + + .detect = detect_pretrans_eofb, + + .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, + .ntables = 2, +}; + +Step +eofbfin_eofb = { + .shortname = "eofbfin", + .name = "Optimal after EO on F/B without breaking EO", + + .final = true, + .is_done = is_solved, + .estimate = estimate_nxopt31_HTM, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = always_valid, + .moveset = &moveset_eofb, + + .pre_trans = uf, + + .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, + .ntables = 2, +}; + +Step +eorlfin_eorl = { + .shortname = "eorlfin", + .name = "Optimal after EO on R/L without breaking EO", + + .final = true, + .is_done = is_solved, + .estimate = estimate_nxopt31_HTM, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = always_valid, + .moveset = &moveset_eofb, + + .pre_trans = ur, + + .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, + .ntables = 2, +}; + +Step +eoudfin_eoud = { + .shortname = "eoudfin", + .name = "Optimal after EO on U/D without breaking EO", + + .final = true, + .is_done = is_solved, + .estimate = estimate_nxopt31_HTM, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = always_valid, + .moveset = &moveset_eofb, + + .pre_trans = fd, + + .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, + .ntables = 2, +}; + +/* EO steps **************************/ +Step +eoany_HTM = { + .shortname = "eo", + .name = "EO on any axis", + + .final = false, + .is_done = check_eofb, + .estimate = estimate_eofb_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_HTM, + + .detect = detect_pretrans_void_3axis, + + .tables = {&pd_eofb_HTM}, + .ntables = 1, +}; + +Step +eofb_HTM = { + .shortname = "eofb", + .name = "EO on F/B", + + .final = false, + .is_done = check_eofb, + .estimate = estimate_eofb_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_HTM, + + .pre_trans = uf, + + .tables = {&pd_eofb_HTM}, + .ntables = 1, +}; + +Step +eorl_HTM = { + .shortname = "eorl", + .name = "EO on R/L", + + .final = false, + .is_done = check_eofb, + .estimate = estimate_eofb_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_HTM, + + .pre_trans = ur, + + .tables = {&pd_eofb_HTM}, + .ntables = 1, +}; + +Step +eoud_HTM = { + .shortname = "eoud", + .name = "EO on U/D", + + .final = false, + .is_done = check_eofb, + .estimate = estimate_eofb_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_HTM, + + .pre_trans = fd, + + .tables = {&pd_eofb_HTM}, + .ntables = 1, +}; + +/* CO steps **************************/ +Step +coany_HTM = { + .shortname = "co", + .name = "CO on any axis", + + .final = false, + .is_done = check_coud_HTM, + .estimate = estimate_coud_HTM, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_HTM, + + .detect = detect_pretrans_void_3axis, + + .tables = {&pd_coud_HTM}, + .ntables = 1, +}; + +Step +coud_HTM = { + .shortname = "coud", + .name = "CO on U/D", + + .final = false, + .is_done = check_coud_HTM, + .estimate = estimate_coud_HTM, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_HTM, + + .pre_trans = uf, + + .tables = {&pd_coud_HTM}, + .ntables = 1, +}; + +Step +corl_HTM = { + .shortname = "corl", + .name = "CO on R/L", + + .final = false, + .is_done = check_coud_HTM, + .estimate = estimate_coud_HTM, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_HTM, + + .pre_trans = rf, + + .tables = {&pd_coud_HTM}, + .ntables = 1, +}; + +Step +cofb_HTM = { + .shortname = "cofb", + .name = "CO on F/B", + + .final = false, + .is_done = check_coud_HTM, + .estimate = estimate_coud_HTM, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_HTM, + + .pre_trans = fd, + + .tables = {&pd_coud_HTM}, + .ntables = 1, +}; + +Step +coany_URF = { + .shortname = "co-URF", + .name = "CO any axis (URF moveset)", + + .final = false, + .is_done = check_coud_URF, + .estimate = estimate_coud_URF, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_URF, + + .detect = detect_pretrans_void_3axis, + + .tables = {&pd_coud_HTM}, + .ntables = 1, +}; + +Step +coud_URF = { + .shortname = "coud-URF", + .name = "CO on U/D (URF moveset)", + + .final = false, + .is_done = check_coud_URF, + .estimate = estimate_coud_URF, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_URF, + + .pre_trans = uf, + + .tables = {&pd_coud_HTM}, + .ntables = 1, +}; + +Step +corl_URF = { + .shortname = "corl-URF", + .name = "CO on R/L (URF moveset)", + + .final = false, + .is_done = check_coud_URF, + .estimate = estimate_coud_URF, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_URF, + + .pre_trans = rf, + + .tables = {&pd_coud_HTM}, + .ntables = 1, +}; + +Step +cofb_URF = { + .shortname = "cofb-URF", + .name = "CO on F/B (URF moveset)", + + .final = false, + .is_done = check_coud_URF, + .estimate = estimate_coud_URF, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_URF, + + .pre_trans = fd, + + .tables = {&pd_coud_HTM}, + .ntables = 1, +}; + +/* Misc corner steps *****************/ +Step +cornershtr_HTM = { + .shortname = "chtr", + .name = "Solve corners to HTR state", + + .final = false, + .is_done = check_cornershtr, + .estimate = estimate_cornershtr_HTM, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_HTM, + + .pre_trans = uf, + + .tables = {&pd_cornershtr_HTM}, + .ntables = 1, +}; + +Step +cornershtr_URF = { + .shortname = "chtr-URF", + .name = "Solve corners to HTR state (URF moveset)", + + .final = false, + .is_done = check_cornershtr, + .estimate = estimate_cornershtr_URF, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_URF, + + .pre_trans = uf, + + .tables = {&pd_cornershtr_HTM}, + .ntables = 1, +}; + +Step +corners_HTM = { + .shortname = "corners", + .name = "Solve corners", + + .final = true, + .is_done = check_corners_HTM, + .estimate = estimate_corners_HTM, + .ready = NULL, + .is_valid = always_valid, + .moveset = &moveset_HTM, + + .pre_trans = uf, + + .tables = {&pd_corners_HTM}, + .ntables = 1, +}; + +Step +corners_URF = { + .shortname = "corners-URF", + .name = "Solve corners (URF moveset)", + + .final = true, /* TODO: check if this works with reorient */ + .is_done = check_corners_URF, + .estimate = estimate_corners_URF, + .ready = NULL, + .is_valid = always_valid, + .moveset = &moveset_URF, + + .pre_trans = uf, + + .tables = {&pd_corners_HTM}, + .ntables = 1, +}; + +/* DR steps **************************/ +Step +drany_HTM = { + .shortname = "dr", + .name = "DR on any axis", + + .final = false, + .is_done = check_drud, + .estimate = estimate_drud_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_HTM, + + .detect = detect_pretrans_void_3axis, + + .tables = {&pd_drud_sym16_HTM}, + .ntables = 1, +}; + +Step +drud_HTM = { + .shortname = "drud", + .name = "DR on U/D", + + .final = false, + .is_done = check_drud, + .estimate = estimate_drud_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_HTM, + + .pre_trans = uf, + + .tables = {&pd_drud_sym16_HTM}, + .ntables = 1, +}; + +Step +drrl_HTM = { + .shortname = "drrl", + .name = "DR on R/L", + + .final = false, + .is_done = check_drud, + .estimate = estimate_drud_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_HTM, + + .pre_trans = rf, + + .tables = {&pd_drud_sym16_HTM}, + .ntables = 1, +}; + +Step +drfb_HTM = { + .shortname = "drfb", + .name = "DR on F/B", + + .final = false, + .is_done = check_drud, + .estimate = estimate_drud_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_HTM, + + .pre_trans = fd, + + .tables = {&pd_drud_sym16_HTM}, + .ntables = 1, +}; + +/* DR from EO */ +Step +dr_eo = { + .shortname = "dr-eo", + .name = "DR without breaking EO (automatically detected)", + + .final = false, + .is_done = check_drud, + .estimate = estimate_dr_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_eofb, + + .detect = detect_pretrans_eofb, + + .tables = {&pd_drud_eofb}, + .ntables = 1, +}; + +Step +dr_eofb = { + .shortname = "dr-eofb", + .name = "DR on U/D or R/L without breaking EO on F/B", + + .final = false, + .is_done = check_drud, + .estimate = estimate_dr_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_eofb, + + .pre_trans = uf, + + .tables = {&pd_drud_eofb}, + .ntables = 1, +}; + +Step +dr_eorl = { + .shortname = "dr-eorl", + .name = "DR on U/D or F/B without breaking EO on R/L", + + .final = false, + .is_done = check_drud, + .estimate = estimate_dr_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_eofb, + + .pre_trans = ur, + + .tables = {&pd_drud_eofb}, + .ntables = 1, +}; + +Step +dr_eoud = { + .shortname = "dr-eoud", + .name = "DR on R/L or F/B without breaking EO on U/D", + + .final = false, + .is_done = check_drud, + .estimate = estimate_dr_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_eofb, + + .pre_trans = fd, + + .tables = {&pd_drud_eofb}, + .ntables = 1, +}; + +Step +drud_eofb = { + .shortname = "drud-eofb", + .name = "DR on U/D without breaking EO on F/B", + + .final = false, + .is_done = check_drud, + .estimate = estimate_drud_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_eofb, + + .pre_trans = uf, + + .tables = {&pd_drud_eofb}, + .ntables = 1, +}; + +Step +drrl_eofb = { + .shortname = "drrl-eofb", + .name = "DR on R/L without breaking EO on F/B", + + .final = false, + .is_done = check_drud, + .estimate = estimate_drud_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_eofb, + + .pre_trans = rf, + + .tables = {&pd_drud_eofb}, + .ntables = 1, +}; + +Step +drud_eorl = { + .shortname = "drud-eorl", + .name = "DR on U/D without breaking EO on R/L", + + .final = false, + .is_done = check_drud, + .estimate = estimate_drud_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_eofb, + + .pre_trans = ur, + + .tables = {&pd_drud_eofb}, + .ntables = 1, +}; + +Step +drfb_eorl = { + .shortname = "drfb-eorl", + .name = "DR on F/B without breaking EO on R/L", + + .final = false, + .is_done = check_drud, + .estimate = estimate_drud_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_eofb, + + .pre_trans = fr, + + .tables = {&pd_drud_eofb}, + .ntables = 1, +}; + +Step +drfb_eoud = { + .shortname = "drfb-eoud", + .name = "DR on F/B without breaking EO on U/D", + + .final = false, + .is_done = check_drud, + .estimate = estimate_drud_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_eofb, + + .pre_trans = fd, + + .tables = {&pd_drud_eofb}, + .ntables = 1, +}; + +Step +drrl_eoud = { + .shortname = "drrl-eoud", + .name = "DR on R/L without breaking EO on U/D", + + .final = false, + .is_done = check_drud, + .estimate = estimate_drud_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_eofb, + + .pre_trans = rd, + + .tables = {&pd_drud_eofb}, + .ntables = 1, +}; + +/* DR finish steps */ +Step +dranyfin_DR = { + .shortname = "drfin", + .name = "DR finish on any axis without breaking DR", + + .final = true, + .is_done = is_solved, + .estimate = estimate_drudfin_drud, + .ready = check_drud, + .ready_msg = check_drany_msg, + .is_valid = always_valid, + .moveset = &moveset_drud, + + .detect = detect_pretrans_drud, + + .tables = {&pd_drudfin_noE_sym16_drud}, + .ntables = 1, +}; + +Step +drudfin_drud = { + .shortname = "drudfin", + .name = "DR finish on U/D without breaking DR", + + .final = true, + .is_done = is_solved, + .estimate = estimate_drudfin_drud, + .ready = check_drud, + .ready_msg = check_dr_msg, + .is_valid = always_valid, + .moveset = &moveset_drud, + + .pre_trans = uf, + + .tables = {&pd_drudfin_noE_sym16_drud}, + .ntables = 1, +}; + +Step +drrlfin_drrl = { + .shortname = "drrlfin", + .name = "DR finish on R/L without breaking DR", + + .final = true, + .is_done = is_solved, + .estimate = estimate_drudfin_drud, + .ready = check_drud, + .ready_msg = check_dr_msg, + .is_valid = always_valid, + .moveset = &moveset_drud, + + .pre_trans = rf, + + .tables = {&pd_drudfin_noE_sym16_drud}, + .ntables = 1, +}; + +Step +drfbfin_drfb = { + .shortname = "drfbfin", + .name = "DR finish on F/B without breaking DR", + + .final = true, + .is_done = is_solved, + .estimate = estimate_drudfin_drud, + .ready = check_drud, + .ready_msg = check_dr_msg, + .is_valid = always_valid, + .moveset = &moveset_drud, + + .pre_trans = fd, + + .tables = {&pd_drudfin_noE_sym16_drud}, + .ntables = 1, +}; + +/* HTR from DR */ +Step +htr_any = { + .shortname = "htr", + .name = "HTR from DR", + + .final = false, + .is_done = check_htr, + .estimate = estimate_htr_drud, + .ready = check_drud, + .ready_msg = check_drany_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_drud, + + .detect = detect_pretrans_drud, + + .tables = {&pd_htr_drud}, + .ntables = 1, +}; + +Step +htr_drud = { + .shortname = "htr-drud", + .name = "HTR from DR on U/D", + + .final = false, + .is_done = check_htr, + .estimate = estimate_htr_drud, + .ready = check_drud, + .ready_msg = check_dr_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_drud, -bool -check_centers(Cube *cube) + .pre_trans = uf, + + .tables = {&pd_htr_drud}, + .ntables = 1, +}; + +Step +htr_drrl = { + .shortname = "htr-drrl", + .name = "HTR from DR on R/L", + + .final = false, + .is_done = check_htr, + .estimate = estimate_htr_drud, + .ready = check_drud, + .ready_msg = check_dr_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_drud, + + .pre_trans = rf, + + .tables = {&pd_htr_drud}, + .ntables = 1, +}; + +Step +htr_drfb = { + .shortname = "htr-drfb", + .name = "HTR from DR on F/B", + + .final = false, + .is_done = check_htr, + .estimate = estimate_htr_drud, + .ready = check_drud, + .ready_msg = check_dr_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_drud, + + .pre_trans = fd, + + .tables = {&pd_htr_drud}, + .ntables = 1, +}; + +/* HTR finish */ +Step +htrfin_htr = { + .shortname = "htrfin", + .name = "HTR finish without breaking HTR", + + .final = true, + .is_done = is_solved, + .estimate = estimate_htrfin_htr, + .ready = check_htr, + .ready_msg = check_htr_msg, + .is_valid = always_valid, + .moveset = &moveset_htr, + + .pre_trans = uf, + + .tables = {&pd_htrfin_htr}, + .ntables = 1, +}; + +Step *steps[] = { + &optimal_HTM, /* first is default */ + &optimal_light_HTM, + + &eofin_eo, + &eofbfin_eofb, + &eorlfin_eorl, + &eoudfin_eoud, + + &eoany_HTM, + &eofb_HTM, + &eorl_HTM, + &eoud_HTM, + + &coany_HTM, + &coud_HTM, + &corl_HTM, + &cofb_HTM, + + &coany_URF, + &coud_URF, + &corl_URF, + &cofb_URF, + + &drany_HTM, + &drud_HTM, + &drrl_HTM, + &drfb_HTM, + + &dr_eo, + &dr_eofb, + &dr_eorl, + &dr_eoud, + &drud_eofb, + &drrl_eofb, + &drud_eorl, + &drfb_eorl, + &drfb_eoud, + &drrl_eoud, + + &dranyfin_DR, + &drudfin_drud, + &drrlfin_drrl, + &drfbfin_drfb, + + &htr_any, + &htr_drud, + &htr_drrl, + &htr_drfb, + + &htrfin_htr, + + &cornershtr_HTM, + &cornershtr_URF, + &corners_HTM, + &corners_URF, + + NULL +}; + +/* Checkers, estimators and validators ***************************************/ + +static bool +check_centers(Cube cube) { - int i; + return cube.cpos == 0; +} - for (i = 0; i < 6; i++) - if (cube->xp[i] != i) - return false; +static bool +check_coud_HTM(Cube cube) +{ + return cube.coud == 0; +} - return true; +static bool +check_coud_URF(Cube cube) +{ + Cube c2, c3; + + c2 = apply_move(z, cube); + c3 = apply_move(x, cube); + + return cube.coud == 0 || c2.coud == 0 || c3.coud == 0; } -bool -check_coud_HTM(Cube *cube) +static bool +check_corners_URF(Cube cube) { - int i; + Cube c; + Trans i; - for (i = 0; i < 8; i++) - if (cube->co[i] != 0) - return false; + for (i = 0; i < NROTATIONS; i++) { + c = apply_alg(rotation_alg(i), cube); + if (c.cp && c.coud) + return true; + } - return true; + return false; } -bool -check_coud_URF(Cube *cube) +static bool +check_corners_HTM(Cube cube) { - Cube c2, c3; + return cube.cp == 0 && cube.coud == 0; +} - copy_cube(cube, &c2); - copy_cube(cube, &c3); +static bool +check_cornershtr(Cube cube) +{ + return coord_cornershtr.index(cube) == 0; +} - apply_move(z, &c2); - apply_move(x, &c3); +static bool +check_eofb(Cube cube) +{ + return cube.eofb == 0; +} - return check_coud_HTM(cube) || - check_coud_HTM(&c2) || - check_coud_HTM(&c3); +static bool +check_drud(Cube cube) +{ + return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0; } -bool -check_cp_HTM(Cube *cube) +static bool +check_htr(Cube cube) { - int i; + return check_drud(cube) && coord_htr_drud.index(cube) == 0; +} - for (i = 0; i < 8; i++) - if (cube->cp[i] != i) - return false; +static int +estimate_eofb_HTM(DfsArg *arg) +{ + return ptableval(&pd_eofb_HTM, arg->cube); +} - return true; +static int +estimate_coud_HTM(DfsArg *arg) +{ + return ptableval(&pd_coud_HTM, arg->cube); } -bool -check_corners_HTM(Cube *cube) +static int +estimate_coud_URF(DfsArg *arg) { - return check_coud_HTM(cube) && check_cp_HTM(cube); + /* TODO: I can improve this by checking first the orientation of + * the corner in DBL and use that as a reference */ + + Cube c; + + c = arg->cube; + + int ud = estimate_coud_HTM(arg); + arg->cube = apply_move(z, c); + int rl = estimate_coud_HTM(arg); + arg->cube = apply_move(x, c); + int fb = estimate_coud_HTM(arg); + + arg->cube = c; + + return MIN(ud, MIN(rl, fb)); } -bool -check_corners_URF(Cube *cube) +static int +estimate_corners_HTM(DfsArg *arg) { + return ptableval(&pd_corners_HTM, arg->cube); +} + +static int +estimate_cornershtr_HTM(DfsArg *arg) +{ + return ptableval(&pd_cornershtr_HTM, arg->cube); +} + +static int +estimate_cornershtr_URF(DfsArg *arg) +{ + /* TODO: I can improve this by checking first the corner in DBL + * and use that as a reference */ + + int ret; Cube c; Trans i; + c = arg->cube; + ret = 15; + for (i = 0; i < NROTATIONS; i++) { - copy_cube(cube, &c); - apply_alg(rotation_alg(i), &c); - if (check_corners_HTM(&c)) - return true; + arg->cube = apply_alg(rotation_alg(i), c); + ret = MIN(ret, estimate_cornershtr_HTM(arg)); } - return false; + arg->cube = c; + + return ret; } -bool -check_cornershtr(Cube *cube) +static int +estimate_corners_URF(DfsArg *arg) { - /* TODO (use coord) */ - return true; + /* TODO: I can improve this by checking first the corner in DBL + * and use that as a reference */ + + int ret; + Cube c; + Trans i; + + c = arg->cube; + ret = 15; + + for (i = 0; i < NROTATIONS; i++) { + arg->cube = apply_alg(rotation_alg(i), c); + ret = MIN(ret, estimate_corners_HTM(arg)); + } + + arg->cube = c; + + return ret; } -bool -check_eofb(Cube *cube) +static int +estimate_drud_HTM(DfsArg *arg) { - /* TODO (use coord) */ - return true; + return ptableval(&pd_drud_sym16_HTM, arg->cube); } -bool -check_drud(Cube *cube) +static int +estimate_drud_eofb(DfsArg *arg) { - /* TODO (use coord) */ - return true; + return ptableval(&pd_drud_eofb, arg->cube); } -bool -check_htr(Cube *cube) +static int +estimate_dr_eofb(DfsArg *arg) +{ + int r1, r2; + + r1 = ptableval(&pd_drud_eofb, arg->cube); + r2 = ptableval(&pd_drud_eofb, apply_trans(rf, arg->cube)); + + return MIN(r1, r2); +} + +static int +estimate_drudfin_drud(DfsArg *arg) +{ + int val = ptableval(&pd_drudfin_noE_sym16_drud, arg->cube); + + if (val != 0) + return val; + + return arg->cube.epose % 24 == 0 ? 0 : 1; +} + +static int +estimate_htr_drud(DfsArg *arg) +{ + return ptableval(&pd_htr_drud, arg->cube); +} + +static int +estimate_htrfin_htr(DfsArg *arg) +{ + return ptableval(&pd_htrfin_htr, arg->cube); +} + +static int +estimate_nxopt31_HTM(DfsArg *arg) +{ + return estimate_nxoptlike(arg, &pd_nxopt31_HTM); +} + +/* TODO: also use generic procedure for this */ +static int +estimate_light_HTM(DfsArg *arg) +{ + int target, ret; + Cube aux; + + static const uint64_t udmask = (1<d - arg->current_alg->len; + arg->inverse = (Cube){0}; + arg->badmovesinv = 0; + arg->badmoves = 0; + + /* Corners */ + arg->ed->corners = ptableval(&pd_corners_HTM, arg->cube); + UPDATECHECKSTOP(ret, arg->ed->corners, target); + + /* Normal probing */ + arg->ed->normal_ud = ptableval(&pd_drud_sym16_HTM, arg->cube); + UPDATECHECKSTOP(ret, arg->ed->normal_ud, target); + aux = apply_trans(fd, arg->cube); + arg->ed->normal_fb = ptableval(&pd_drud_sym16_HTM, aux); + UPDATECHECKSTOP(ret, arg->ed->normal_fb, target); + aux = apply_trans(rf, arg->cube); + arg->ed->normal_rl = ptableval(&pd_drud_sym16_HTM, aux); + UPDATECHECKSTOP(ret, arg->ed->normal_rl, target); + + /* If ret == 0, it's solved (corners + triple slice solved) */ + if (ret == 0) + return is_solved(arg->cube) ? 0 : 1; + + /* Michel de Bondt's trick*/ + if (arg->ed->normal_ud == arg->ed->normal_fb && + arg->ed->normal_fb == arg->ed->normal_rl) { + UPDATECHECKSTOP(ret, arg->ed->normal_ud + 1, target); + } + + /* Inverse probing */ + if (!((1<last1) & htmask)) { + aux = arg->inverse = inverse_cube(arg->cube); + if (!((1<last1) & udmask) || (arg->ed->inverse_ud==-1)) { + arg->ed->inverse_ud = + ptableval(&pd_drud_sym16_HTM, aux); + } + UPDATECHECKSTOP(ret, arg->ed->inverse_ud, target); + if (!((1<last1) & fbmask) || (arg->ed->inverse_fb==-1)) { + aux = apply_trans(fd, arg->inverse); + arg->ed->inverse_fb = + ptableval(&pd_drud_sym16_HTM, aux); + } + UPDATECHECKSTOP(ret, arg->ed->inverse_fb, target); + if (!((1<last1) & rlmask) || (arg->ed->inverse_rl==-1)) { + aux = apply_trans(rf, arg->inverse); + arg->ed->inverse_rl = + ptableval(&pd_drud_sym16_HTM, aux); + } + UPDATECHECKSTOP(ret, arg->ed->inverse_rl, target); + } else { + UPDATECHECKSTOP(ret, arg->ed->inverse_ud, target); + UPDATECHECKSTOP(ret, arg->ed->inverse_fb, target); + UPDATECHECKSTOP(ret, arg->ed->inverse_rl, target); + } + + /* Michel de Bondt's trick*/ + if (arg->ed->inverse_ud == arg->ed->inverse_fb && + arg->ed->inverse_fb == arg->ed->inverse_rl) { + UPDATECHECKSTOP(ret, arg->ed->inverse_ud + 1, target); + } + + /* nxopt trick + half turn trick */ + if (arg->ed->normal_ud == target) + arg->badmovesinv |= udmask | htmask; + if (arg->ed->normal_fb == target) + arg->badmovesinv |= fbmask | htmask; + if (arg->ed->normal_rl == target) + arg->badmovesinv |= rlmask | htmask; + + if (arg->ed->inverse_ud == target) + arg->badmoves |= udmask | htmask; + if (arg->ed->inverse_fb == target) + arg->badmoves |= fbmask | htmask; + if (arg->ed->inverse_rl == target) + arg->badmoves |= rlmask | htmask; + + return arg->ed->oldret = ret; +} + +static int +estimate_nxoptlike(DfsArg *arg, PruneData *pd) +{ + int target, ret; + Cube aux; + + static const uint64_t udmask = (1<d - arg->current_alg->len; + arg->inverse = (Cube){0}; + arg->badmovesinv = 0; + arg->badmoves = 0; + + /* Corners */ + arg->ed->corners = ptableval(&pd_corners_HTM, arg->cube); + UPDATECHECKSTOP(ret, arg->ed->corners, target); + + /* Normal probing */ + arg->ed->normal_ud = ptableval(pd, arg->cube); + UPDATECHECKSTOP(ret, arg->ed->normal_ud, target); + aux = apply_trans(fd, arg->cube); + arg->ed->normal_fb = ptableval(pd, aux); + UPDATECHECKSTOP(ret, arg->ed->normal_fb, target); + aux = apply_trans(rf, arg->cube); + arg->ed->normal_rl = ptableval(pd, aux); + UPDATECHECKSTOP(ret, arg->ed->normal_rl, target); + + if (ret == 0) + return arg->step->is_done(arg->cube) ? 0 : 1; + + /* Michel de Bondt's trick*/ + if (arg->ed->normal_ud == arg->ed->normal_fb && + arg->ed->normal_fb == arg->ed->normal_rl) { + UPDATECHECKSTOP(ret, arg->ed->normal_ud + 1, target); + } + + /* Inverse probing */ + aux = arg->inverse = inverse_cube(arg->cube); + if (!((1<last1) & udmask) || (arg->ed->inverse_ud == -1)) { + arg->ed->inverse_ud = ptableval(pd, aux); + } + UPDATECHECKSTOP(ret, arg->ed->inverse_ud, target); + if (!((1<last1) & fbmask) || (arg->ed->inverse_fb == -1)) { + aux = apply_trans(fd, arg->inverse); + arg->ed->inverse_fb = ptableval(pd, aux); + } + UPDATECHECKSTOP(ret, arg->ed->inverse_fb, target); + if (!((1<last1) & rlmask) || (arg->ed->inverse_rl == -1)) { + aux = apply_trans(rf, arg->inverse); + arg->ed->inverse_rl = ptableval(pd, aux); + } + UPDATECHECKSTOP(ret, arg->ed->inverse_rl, target); + + /* Michel de Bondt's trick*/ + if (arg->ed->inverse_ud == arg->ed->inverse_fb && + arg->ed->inverse_fb == arg->ed->inverse_rl) { + UPDATECHECKSTOP(ret, arg->ed->inverse_ud + 1, target); + } + + /* nxopt trick */ + if (arg->ed->normal_ud == target) + arg->badmovesinv |= udmask; + if (arg->ed->normal_fb == target) + arg->badmovesinv |= fbmask; + if (arg->ed->normal_rl == target) + arg->badmovesinv |= rlmask; + + if (arg->ed->inverse_ud == target) + arg->badmoves |= udmask; + if (arg->ed->inverse_fb == target) + arg->badmoves |= fbmask; + if (arg->ed->inverse_rl == target) + arg->badmoves |= rlmask; + + return arg->ed->oldret = ret; +} + + +static bool +always_valid(Alg *alg) { - /* TODO (check_drud(cube) and coord_htr_drud == 0) */ return true; } -Alg * +static bool validate_singlecw_ending(Alg *alg) { int i; bool nor, inv; - Alg *ret; Move l2 = NULLMOVE, l1 = NULLMOVE, l2i = NULLMOVE, l1i = NULLMOVE; for (i = 0; i < alg->len; i++) { @@ -127,51 +1386,96 @@ validate_singlecw_ending(Alg *alg) nor = l1 ==base_move(l1) && (!commute(l1, l2) ||l2 ==base_move(l2)); inv = l1i==base_move(l1i) && (!commute(l1i,l2i)||l2i==base_move(l2i)); - if (nor && inv) { - ret = new_alg(""); - copy_alg(alg, ret); - } else { - ret = NULL; - } + return nor && inv; +} - return ret; +/* Pre-transformation detectors **********************************************/ + +static int +detect_pretrans_eofb(Cube cube, Trans *ret) +{ + int i, n; + static Trans tt[3] = {uf, ur, fd}; + + for (i = 0, n = 0; i < 3; i++) + if (check_eofb(apply_trans(tt[i], cube))) + ret[n++] = tt[i]; + + return n; +} + +static int +detect_pretrans_drud(Cube cube, Trans *ret) +{ + int i, n; + static Trans tt[3] = {uf, fr, rd}; + + for (i = 0, n = 0; i < 3; i++) + if (check_drud(apply_trans(tt[i], cube))) + ret[n++] = tt[i]; + + return n; +} + +static int +detect_pretrans_void_3axis(Cube cube, Trans *ret) +{ + ret[0] = uf; + ret[1] = fr; + ret[2] = rd; + + return 3; } /* Public functions **********************************************************/ -/* void -compute_ind(Step *s, Cube *cube, Movable *ind) +copy_estimatedata(EstimateData *src, EstimateData *dst) { - int i; - Cube mvd; - Trans t, tt; + dst->corners = src->corners; + dst->normal_ud = src->normal_ud; + dst->normal_fb = src->normal_fb; + dst->normal_rl = src->normal_rl; + dst->inverse_ud = src->inverse_ud; + dst->inverse_fb = src->inverse_fb; + dst->inverse_rl = src->inverse_rl; + dst->oldret = src->oldret; +} - for (i = 0; i < s->n_coord; i++) { - t = s->coord_trans[i]; - copy_cube(cube, &mvd); - apply_trans(t, &mvd); +void +invert_estimatedata(EstimateData *ed) +{ + swap(&(ed->normal_ud), &(ed->inverse_ud)); + swap(&(ed->normal_fb), &(ed->inverse_fb)); + swap(&(ed->normal_rl), &(ed->inverse_rl)); +} - ind[i].val = index_coord(s->coord[i], &mvd, &tt); - ind[i].t = transform_trans(tt, t); - } +void +reset_estimatedata(EstimateData *ed) +{ + ed->corners = -1; + ed->normal_ud = -1; + ed->normal_fb = -1; + ed->normal_rl = -1; + ed->inverse_ud = -1; + ed->inverse_fb = -1; + ed->inverse_rl = -1; + ed->oldret = -1; } -*/ void -prepare_cs(ChoiceStep *cs, SolveOptions *opts) -{ - int i, j; - Step *s; - - for (i = 0; cs->step[i] != NULL; i++) { - s = cs->step[i]; - for (j = 0; j < s->n_coord; j++) { - s->pd[j] = malloc(sizeof(PruneData)); - s->pd[j]->moveset = s->moveset; - s->pd[j]->coord = s->coord[j]; - s->pd[j]->compact = s->pd_compact[j]; - s->pd[j] = genptable(s->pd[j], opts->nthreads); - } +prepare_step(Step *step, SolveOptions *opts) +{ + int i; + + if (step->final && opts->can_niss) { + opts->can_niss = false; + fprintf(stderr, "Step is final, NISS not used (-n ignored)\n"); + } + + for (i = 0; i < step->ntables; i++) { + genptable(step->tables[i], opts->nthreads); + if (step->tables[i]->compact) + genptable(step->tables[i]->fallback, opts->nthreads); } } 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 @@ #define STEPS_H #include "pruning.h" -#include "movesets.h" -bool check_centers(Cube *cube); -bool check_coud_HTM(Cube *cube); -bool check_coud_URF(Cube *cube); -bool check_cp_HTM(Cube *cube); -bool check_corners_HTM(Cube *cube); -bool check_corners_URF(Cube *cube); -bool check_cornershtr(Cube *cube); -bool check_eofb(Cube *cube); -bool check_drud(Cube *cube); -bool check_htr(Cube *cube); -/*void compute_ind(Step *a, Cube *cube, Movable *ind);*/ -void prepare_cs(ChoiceStep *cs, SolveOptions *opts); -bool always_valid(Alg *alg); -Alg * validate_singlecw_ending(Alg *alg); +extern Step * steps[]; -#ifndef STEPS_C +/* Two steps used directly by two-phase solver */ +extern Step drany_HTM; +extern Step dranyfin_DR; -extern char check_centers_msg[100]; -extern char check_eo_msg[100]; -extern char check_dr_msg[100]; -extern char check_htr_msg[100]; -extern char check_drany_msg[100]; - -extern Step step_eofb_HTM; -extern Step step_drud_HTM; -extern Step step_drfin_drud; - -extern ChoiceStep optimal_HTM; -extern ChoiceStep eoany_HTM; -extern ChoiceStep eofb_HTM; -extern ChoiceStep eorl_HTM; -extern ChoiceStep eoud_HTM; -extern ChoiceStep drany_HTM; -extern ChoiceStep drud_HTM; -extern ChoiceStep drrl_HTM; -extern ChoiceStep drfb_HTM; -extern ChoiceStep dranyfin_DR; -extern ChoiceStep drudfin_drud; -extern ChoiceStep drrlfin_drrl; -extern ChoiceStep drfbfin_drfb; - -extern ChoiceStep *csteps[]; - -#else - -char check_centers_msg[100] = "cube must be oriented (centers solved)"; -char check_eo_msg[100] = "EO must be solved on given axis"; -char check_dr_msg[100] = "DR must be solved on given axis"; -char check_htr_msg[100] = "HTR must be solved"; -char check_drany_msg[100] = "DR must be solved on at least one axis"; - -/* Optimal after EO ******************/ -/* TODO: eofin_eo (generic), eofbfin_eofb, eorlfin_eorl, eoudfin_eoud */ - -/* EO steps **************************/ -/* TODO: eoany_HTM (generic), eofb_HTM, eorl_HTM, eoud_HTM */ - -Step -step_eofb_HTM = { - .ready = check_centers, - .final = false, - .moveset = &moveset_HTM, - .n_coord = 1, - .coord = {&coord_eofb}, - .coord_trans = {uf}, - .is_valid = validate_singlecw_ending, -}; -ChoiceStep -eoany_HTM = { - .shortname = "eo", - .name = "EO on any axis", - .step = {&step_eofb_HTM, &step_eofb_HTM, &step_eofb_HTM, NULL}, - .t = {uf, ur, fd}, - .ready_msg = check_centers_msg, -}; -ChoiceStep -eofb_HTM = { - .shortname = "eofb", - .name = "EO on F/B", - .step = {&step_eofb_HTM, NULL}, - .t = {uf}, - .ready_msg = check_centers_msg, -}; -ChoiceStep -eorl_HTM = { - .shortname = "eorl", - .name = "EO on R/L", - .step = {&step_eofb_HTM, NULL}, - .t = {ur}, - .ready_msg = check_centers_msg, -}; -ChoiceStep -eoud_HTM = { - .shortname = "eoud", - .name = "EO on U/D", - .step = {&step_eofb_HTM, NULL}, - .t = {fd}, - .ready_msg = check_centers_msg, -}; - -/* CO steps **************************/ -/* TODO: coany_HTM (generic), cofb_HTM, corl_HTM, coud_HTM */ -/* TODO: coany_URF (generic), cofb_URF, corl_URF, coud_URF */ - -/* Misc corner steps *****************/ -/* TODO: cornershtr_HTM, cornershtr_URF, corners_HTM, corners_URF */ -/* TODO (new): corners_drud */ - -/* DR steps **************************/ -/* TODO: dr_eo (generic) */ -/* TODO: dr_eofb (generic), dr_eorl (generic), dr_eoud (generic) */ -/* TODO: drud_eofb, drrl_eofb, drud_eorl, drfb_eorl, drrl_eoud, drfb_eoud */ - -Step -step_drud_HTM = { - .ready = check_centers, - .final = false, - .moveset = &moveset_HTM, - .n_coord = 1, - .coord = {&coord_drud_sym16}, - .coord_trans = {uf}, - .is_valid = validate_singlecw_ending, -}; -ChoiceStep -drany_HTM = { - .shortname = "dr", - .name = "DR on any axis", - .step = {&step_drud_HTM, &step_drud_HTM, &step_drud_HTM, NULL}, - .t = {uf, rf, fd}, - .ready_msg = check_centers_msg, -}; -ChoiceStep -drud_HTM = { - .shortname = "drud", - .name = "DR on U/D", - .step = {&step_drud_HTM, NULL}, - .t = {uf}, - .ready_msg = check_centers_msg, -}; -ChoiceStep -drrl_HTM = { - .shortname = "drrl", - .name = "DR on R/L", - .step = {&step_drud_HTM, NULL}, - .t = {rf}, - .ready_msg = check_centers_msg, -}; -ChoiceStep -drfb_HTM = { - .shortname = "drfb", - .name = "DR on F/B", - .step = {&step_drud_HTM, NULL}, - .t = {fd}, - .ready_msg = check_centers_msg, -}; - -/* DR finish steps */ -Step -step_drfin_drud = { - .ready = check_drud, - .final = true, - .moveset = &moveset_drud, - .n_coord = 1, - .coord = {&coord_drudfin_noE_sym16}, /* TODO: maybe no noE */ - .coord_trans = {uf}, - .is_valid = NULL, -}; -ChoiceStep -dranyfin_DR = { - .shortname = "drfin", - .name = "DR finish on any axis without breaking DR", - .step = {&step_drfin_drud, &step_drfin_drud, - &step_drfin_drud, NULL}, - .t = {uf, rf, fd}, - .ready_msg = check_dr_msg, -}; -ChoiceStep -drudfin_drud = { - .shortname = "drudfin", - .name = "DR finis on U/D without breaking DR", - .step = {&step_drfin_drud, NULL}, - .t = {uf}, - .ready_msg = check_dr_msg, -}; -ChoiceStep -drrlfin_drrl = { - .shortname = "drrlfin", - .name = "DR finish on R/L without breaking DR", - .step = {&step_drfin_drud, NULL}, - .t = {rf}, - .ready_msg = check_dr_msg, -}; -ChoiceStep -drfbfin_drfb = { - .shortname = "drfbfin", - .name = "DR finish on F/B without breaking DR", - .step = {&step_drfin_drud, NULL}, - .t = {fd}, - .ready_msg = check_dr_msg, -}; - -/* HTR from DR */ -/* TODO: htr_any (generic), htr_drud, htr_drrl, htr_drfb */ - -/* HTR finish */ -/* TODO: htrfin_htr */ - -ChoiceStep *csteps[] = { -/* TODO: re-implement optimal - &optimal_HTM, -*/ - - &eoany_HTM, &eofb_HTM, &eorl_HTM, &eoud_HTM, - &drany_HTM, &drud_HTM, &drrl_HTM, &drfb_HTM, - &dranyfin_DR, &drudfin_drud, &drrlfin_drrl, &drfbfin_drfb, - -NULL -/* TODO: - &optimal_light_HTM, - - &eofin_eo, &eofbfin_eofb, &eorlfin_eorl, &eoudfin_eoud, - &coany_HTM, &coud_HTM, &corl_HTM, &cofb_HTM, - &coany_URF, &coud_URF, &corl_URF, &cofb_URF, - &dr_eo, &dr_eofb, &dr_eorl, &dr_eoud, - &drud_eofb, &drrl_eofb, - &drud_eorl, &drfb_eorl, - &drfb_eoud, &drrl_eoud, - &htr_any, &htr_drud, &htr_drrl, &htr_drfb, - &htrfin_htr, - &cornershtr_HTM, &cornershtr_URF, &corners_HTM, &corners_URF, - NULL -*/ - -}; - -#endif +void copy_estimatedata(EstimateData *s, EstimateData *d); +void invert_estimatedata(EstimateData *ed); +void reset_estimatedata(EstimateData *ed); +void prepare_step(Step *step, SolveOptions *opts); #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 @@ +#include "symcoord.h" + +/* These constants have been computed generating the respective SymData */ +#define CLASSES_CP_16 2768 +#define CLASSES_EOFBEPOS_16 64430 + +static uint64_t index_cp_sym16(Cube cube); +static uint64_t index_eofbepos_sym16(Cube cube); +static uint64_t index_drud_sym16(Cube cube); +static uint64_t index_drudfin_noE_sym16(Cube cube); +static uint64_t index_nxopt31(Cube cube); + +static uint64_t move_cp_sym16(Move m, uint64_t ind); +static uint64_t move_eofbepos_sym16(Move m, uint64_t ind); +static uint64_t move_drud_sym16(Move m, uint64_t ind); +static uint64_t move_drudfin_noE_sym16(Move m, uint64_t ind); +static uint64_t move_nxopt31(Move m, uint64_t ind); + +static int tfind_from_mask(uint64_t mask, Trans *ret); +static int tfind_drud_sym16(uint64_t ind, Trans *ret); +static int tfind_drudfin_noE_sym16(uint64_t ind, Trans *ret); +static int tfind_nxopt31(uint64_t ind, Trans *ret); + +static uint64_t transform_cp(Trans t, uint64_t ind); +static uint64_t transform_eofbepos(Trans t, uint64_t ind); +static uint64_t transform_drud_sym16(Trans t, uint64_t ind); +static uint64_t transform_drudfin_noE_sym16(Trans t, uint64_t ind); +static uint64_t transform_nxopt31(Trans t, uint64_t ind); + +static void gensym(SymData *sd); +static void init_symc_moves(); +static void init_symc_trans(); +static bool read_symdata_file(SymData *sd); +static bool read_symc_moves_file(); +static bool read_symc_trans_file(); +static bool write_symdata_file(SymData *sd); +static bool write_symc_moves_file(); +static bool write_symc_trans_file(); + +/* Some tables ***************************************************************/ + +static uint64_t move_cp_16[NMOVES][CLASSES_CP_16]; +static uint64_t move_eofbepos_16[NMOVES][CLASSES_EOFBEPOS_16]; + +static int trans_eofbepos[NTRANS][POW2TO11*BINOM12ON4]; +static int trans_epud[NTRANS][FACTORIAL8]; +static int trans_cpud_separate[NTRANS][BINOM8ON4]; + +static Trans ttrep_move_cp_16[NMOVES][CLASSES_CP_16]; +static Trans ttrep_move_eofbepos_16[NMOVES][CLASSES_EOFBEPOS_16]; + + +/* Transformation groups and symmetry data ***********************************/ + +static Trans +trans_group_udfix[16] = { + uf, ur, ub, ul, + df, dr, db, dl, + uf_mirror, ur_mirror, ub_mirror, ul_mirror, + df_mirror, dr_mirror, db_mirror, dl_mirror, +}; + +static SymData +sd_cp_16 = { + .filename = "sd_cp_16_new", + .coord = &coord_cp, + .sym_coord = &coord_cp_sym16, + .ntrans = 16, + .trans = trans_group_udfix, + .transform = transform_cp, +}; + +static SymData +sd_eofbepos_16 = { + .filename = "sd_eofbepos_16_new", + .coord = &coord_eofbepos, + .sym_coord = &coord_eofbepos_sym16, + .ntrans = 16, + .trans = trans_group_udfix, + .transform = transform_eofbepos, +}; + +SymData * all_sd[] = { + &sd_cp_16, + &sd_eofbepos_16, + NULL +}; + + +/* Coordinates and their implementation **************************************/ + +Coordinate +coord_eofbepos_sym16 = { + .index = index_eofbepos_sym16, + .move = move_eofbepos_sym16, +}; + +Coordinate +coord_cp_sym16 = { + .index = index_cp_sym16, + .move = move_cp_sym16, +}; + +Coordinate +coord_drud_sym16 = { + .index = index_drud_sym16, + .move = move_drud_sym16, + .max = POW3TO7 * CLASSES_EOFBEPOS_16, + .base = &coord_eofbepos_sym16, + .transform = transform_drud_sym16, + .tfind = tfind_drud_sym16, +}; + +Coordinate +coord_drudfin_noE_sym16 = { + .index = index_drudfin_noE_sym16, + .move = move_drudfin_noE_sym16, + .max = FACTORIAL8 * CLASSES_CP_16, + .base = &coord_cp_sym16, + .transform = transform_drudfin_noE_sym16, + .tfind = tfind_drudfin_noE_sym16, +}; + +Coordinate +coord_nxopt31 = { + .index = index_nxopt31, + .move = move_nxopt31, + .max = POW3TO7 * BINOM8ON4 * CLASSES_EOFBEPOS_16, + .base = &coord_eofbepos_sym16, + .transform = transform_nxopt31, + .tfind = tfind_nxopt31, +}; + +/* Functions *****************************************************************/ + +static uint64_t +index_cp_sym16(Cube cube) +{ + return sd_cp_16.class[coord_cp.index(cube)]; +} + +static uint64_t +index_drud_sym16(Cube cube) +{ + Trans t; + + t = sd_eofbepos_16.transtorep[coord_eofbepos.index(cube)]; + + return index_eofbepos_sym16(cube) * POW3TO7 + co_ttable[t][cube.coud]; +} + +static uint64_t +index_drudfin_noE_sym16(Cube cube) +{ + Trans t; + Cube c; + + t = sd_cp_16.transtorep[coord_cp.index(cube)]; + c = apply_trans(t, cube); + + /* TODO: add transform to coord_epud to make this faster */ + return index_cp_sym16(c) * FACTORIAL8 + coord_epud.index(c); +} + +static uint64_t +index_eofbepos_sym16(Cube cube) +{ + return sd_eofbepos_16.class[coord_eofbepos.index(cube)]; +} + +static uint64_t +index_nxopt31(Cube cube) +{ + Trans t; + uint64_t a; + int coud, cp; + + t = sd_eofbepos_16.transtorep[coord_eofbepos.index(cube)]; + coud = co_ttable[t][cube.coud]; + cp = cp_ttable[t][cube.cp]; + a = (index_eofbepos_sym16(cube)*POW3TO7) + coud; + + return a * BINOM8ON4 + coord_cpud_separate.index((Cube){.cp = cp}); +} + +static uint64_t +move_cp_sym16(Move m, uint64_t ind) +{ + return move_cp_16[m][ind]; +} + +static uint64_t +move_eofbepos_sym16(Move m, uint64_t ind) +{ + return move_eofbepos_16[m][ind]; +} + +static uint64_t +move_drud_sym16(Move m, uint64_t ind) +{ + uint64_t coud, eofbepos; + Trans ttr; + + eofbepos = move_eofbepos_16[m][ind / POW3TO7]; + ttr = ttrep_move_eofbepos_16[m][ind / POW3TO7]; + coud = coud_mtable[m][ind % POW3TO7]; + coud = co_ttable[ttr][coud]; /* Source is always coud */ + + return eofbepos * POW3TO7 + coud; +} + +static uint64_t +move_drudfin_noE_sym16(Move m, uint64_t ind) +{ + uint64_t cp, epud; + Trans ttr; + + cp = move_cp_16[m][ind / FACTORIAL8]; + ttr = ttrep_move_cp_16[m][ind / FACTORIAL8]; + epud = coord_epud.move(m, ind % FACTORIAL8); + epud = trans_epud[ttr][epud]; + + return cp * FACTORIAL8 + epud; +} + +static uint64_t +move_nxopt31(Move m, uint64_t ind) +{ + uint64_t eofbepos, cpsep, coud; + Trans ttr; + + eofbepos = ind / (POW3TO7 * BINOM8ON4); + coud = (ind / BINOM8ON4) % POW3TO7; + cpsep = ind % BINOM8ON4; + + ttr = ttrep_move_eofbepos_16[m][eofbepos]; + eofbepos = move_eofbepos_16[m][eofbepos]; + coud = coud_mtable[m][coud]; + coud = co_ttable[ttr][coud]; /* Source is always coud */ + cpsep = coord_cpud_separate.move(m, cpsep); + cpsep = trans_cpud_separate[ttr][cpsep]; + + return (eofbepos * POW3TO7 + coud) * BINOM8ON4 + cpsep; +} + +static uint64_t +transform_cp(Trans t, uint64_t ind) +{ + return cp_ttable[t][ind]; +} + +static uint64_t +transform_eofbepos(Trans t, uint64_t ind) +{ + return trans_eofbepos[t][ind]; +} + +static uint64_t +transform_drud_sym16(Trans t, uint64_t ind) +{ + uint64_t coud, eofbepos; + + eofbepos = ind / POW3TO7; /* Assum trans fixes eofbepos */ + coud = co_ttable[t][ind % POW3TO7]; /* Source is always coud */ + + return eofbepos * POW3TO7 + coud; +} + +static uint64_t +transform_drudfin_noE_sym16(Trans t, uint64_t ind) +{ + uint64_t cp, epud; + + cp = ind / FACTORIAL8; /* Assume trans fixes cp */ + epud = trans_epud[t][ind % FACTORIAL8]; + + return cp * FACTORIAL8 + epud; +} + +static uint64_t +transform_nxopt31(Trans t, uint64_t ind) +{ + uint64_t eofbepos, cpsep, coud; + + eofbepos = ind / (POW3TO7 * BINOM8ON4); + coud = (ind / BINOM8ON4) % POW3TO7; + cpsep = ind % BINOM8ON4; + + coud = co_ttable[t][coud]; /* Source is always coud */ + cpsep = trans_cpud_separate[t][cpsep]; + + return (eofbepos * POW3TO7 + coud) * BINOM8ON4 + cpsep; +} + +static int +tfind_from_mask(uint64_t mask, Trans *ret) +{ + Trans t; + int i = 0; + + for (t = uf; t < NTRANS; t++) + if (((uint64_t)1 << t) & mask) + ret[i++] = t; + + return i; +} + +static int +tfind_drud_sym16(uint64_t ind, Trans *ret) +{ + uint64_t mask = sd_eofbepos_16.selfsim[ind / POW3TO7]; + + return tfind_from_mask(mask, ret); +} + +static int +tfind_drudfin_noE_sym16(uint64_t ind, Trans *ret) +{ + uint64_t mask = sd_cp_16.selfsim[ind / FACTORIAL8]; + + return tfind_from_mask(mask, ret); +} + +static int +tfind_nxopt31(uint64_t ind, Trans *ret) +{ + uint64_t mask = sd_eofbepos_16.selfsim[ind / (POW3TO7 * BINOM8ON4)]; + + return tfind_from_mask(mask, ret); +} + +/* Other functions ***********************************************************/ + +void +free_sd(SymData *sd) +{ + if (sd->generated) { + free(sd->class); + free(sd->unsym); + free(sd->transtorep); + } + + sd->generated = false; +} + +static void +gensym(SymData *sd) +{ + uint64_t i, in, nreps = 0; + Trans t; + int j; + + if (sd->generated) + return; + + sd->class = malloc(sd->coord->max * sizeof(uint64_t)); + sd->unsym = malloc(sd->coord->max * sizeof(uint64_t)); + sd->transtorep = malloc(sd->coord->max * sizeof(Trans)); + sd->selfsim = malloc(sd->coord->max * sizeof(uint64_t)); + + if (read_symdata_file(sd)) { + sd->generated = true; + return; + } + + fprintf(stderr, "Cannot load %s, generating it\n", sd->filename); + + for (i = 0; i < sd->coord->max; i++) + sd->class[i] = sd->coord->max + 1; + + for (i = 0; i < sd->coord->max; i++) { + if (sd->class[i] == sd->coord->max + 1) { + sd->unsym[nreps] = i; + sd->transtorep[i] = uf; + sd->selfsim[nreps] = (uint64_t)0; + for (j = 0; j < sd->ntrans; j++) { + t = sd->trans[j]; + in = sd->transform(t, i); + sd->class[in] = nreps; + if (in == i) + sd->selfsim[nreps] |= + ((uint64_t)1 << t); + else + sd->transtorep[in] = inverse_trans(t); + } + nreps++; + } + } + + sd->sym_coord->max = nreps; + sd->unsym = realloc(sd->unsym, nreps * sizeof(uint64_t)); + sd->selfsim = realloc(sd->selfsim, nreps * sizeof(uint64_t)); + sd->generated = true; + + fprintf(stderr, "Found %" PRIu64 " classes\n", nreps); + + if (!write_symdata_file(sd)) + fprintf(stderr, "Error writing SymData file\n"); + + return; +} + +static bool +read_symdata_file(SymData *sd) +{ + init_env(); + + FILE *f; + char fname[strlen(tabledir)+100]; + uint64_t n = sd->coord->max, *sn = &sd->sym_coord->max; + bool r = true; + + strcpy(fname, tabledir); + strcat(fname, "/"); + strcat(fname, sd->filename); + + if ((f = fopen(fname, "rb")) == NULL) + return false; + + r = r && fread(&sd->sym_coord->max, sizeof(uint64_t), 1, f) == 1; + r = r && fread(sd->unsym, sizeof(uint64_t), *sn, f) == *sn; + r = r && fread(sd->selfsim, sizeof(uint64_t), *sn, f) == *sn; + r = r && fread(sd->class, sizeof(uint64_t), n, f) == n; + r = r && fread(sd->transtorep, sizeof(Trans), n, f) == n; + + fclose(f); + return r; +} + +static bool +read_symc_moves_file() +{ + init_env(); + + Move m; + bool r = true; + FILE *f; + char fname[strlen(tabledir)+100]; + + strcpy(fname, tabledir); + strcat(fname, "/symc_moves"); + + if ((f = fopen(fname, "rb")) == NULL) + return false; + + for (m = 0; m < NMOVES; m++) { + r = r && fread(move_cp_16[m], sizeof(uint64_t), + CLASSES_CP_16, f) == CLASSES_CP_16; + r = r && fread(move_eofbepos_16[m], sizeof(uint64_t), + CLASSES_EOFBEPOS_16, f) == CLASSES_EOFBEPOS_16; + + r = r && fread(ttrep_move_cp_16[m], sizeof(Trans), + CLASSES_CP_16, f) == CLASSES_CP_16; + r = r && fread(ttrep_move_eofbepos_16[m], sizeof(Trans), + CLASSES_EOFBEPOS_16, f) == CLASSES_EOFBEPOS_16; + } + + fclose(f); + return r; +} + +static bool +read_symc_trans_file() +{ + init_env(); + + Trans t; + bool r = true; + FILE *f; + char fname[strlen(tabledir)+100]; + + strcpy(fname, tabledir); + strcat(fname, "/symc_trans"); + + if ((f = fopen(fname, "rb")) == NULL) + return false; + + for (t = 0; t < NTRANS; t++) { + r = r && fread(trans_eofbepos[t], sizeof(int), + POW2TO11*BINOM12ON4, f) == POW2TO11*BINOM12ON4; + r = r && fread(trans_epud[t], sizeof(int), + FACTORIAL8, f) == FACTORIAL8; + r = r && fread(trans_cpud_separate[t], sizeof(int), + BINOM8ON4, f) == BINOM8ON4; + } + + fclose(f); + return r; +} + +static bool +write_symdata_file(SymData *sd) +{ + init_env(); + + FILE *f; + char fname[strlen(tabledir)+100]; + uint64_t n = sd->coord->max, *sn = &sd->sym_coord->max; + bool r = true; + + strcpy(fname, tabledir); + strcat(fname, "/"); + strcat(fname, sd->filename); + + if ((f = fopen(fname, "wb")) == NULL) + return false; + + r = r && fwrite(&sd->sym_coord->max, sizeof(uint64_t), 1, f) == 1; + r = r && fwrite(sd->unsym, sizeof(uint64_t), *sn, f) == *sn; + r = r && fwrite(sd->selfsim, sizeof(uint64_t), *sn, f) == *sn; + r = r && fwrite(sd->class, sizeof(uint64_t), n, f) == n; + r = r && fwrite(sd->transtorep, sizeof(Trans), n, f) == n; + + fclose(f); + return r; +} + +static bool +write_symc_moves_file() +{ + init_env(); + + Move m; + bool r = true; + FILE *f; + char fname[strlen(tabledir)+100]; + + strcpy(fname, tabledir); + strcat(fname, "/symc_moves"); + + if ((f = fopen(fname, "wb")) == NULL) + return false; + + for (m = 0; m < NMOVES; m++) { + r = r && fwrite(move_cp_16[m], sizeof(uint64_t), + CLASSES_CP_16, f) == CLASSES_CP_16; + r = r && fwrite(move_eofbepos_16[m], sizeof(uint64_t), + CLASSES_EOFBEPOS_16, f) == CLASSES_EOFBEPOS_16; + + r = r && fwrite(ttrep_move_cp_16[m], sizeof(Trans), + CLASSES_CP_16, f) == CLASSES_CP_16; + r = r && fwrite(ttrep_move_eofbepos_16[m], sizeof(Trans), + CLASSES_EOFBEPOS_16, f) == CLASSES_EOFBEPOS_16; + } + + fclose(f); + return r; +} + +static bool +write_symc_trans_file() +{ + init_env(); + + Trans t; + bool r = true; + FILE *f; + char fname[strlen(tabledir)+100]; + + strcpy(fname, tabledir); + strcat(fname, "/symc_trans"); + + if ((f = fopen(fname, "wb")) == NULL) + return false; + + for (t = 0; t < NTRANS; t++) { + r = r && fwrite(trans_eofbepos[t], sizeof(int), + POW2TO11*BINOM12ON4, f) == POW2TO11*BINOM12ON4; + r = r && fwrite(trans_epud[t], sizeof(int), + FACTORIAL8, f) == FACTORIAL8; + r = r && fwrite(trans_cpud_separate[t], sizeof(int), + BINOM8ON4, f) == BINOM8ON4; + } + + fclose(f); + return r; +} + +static void +init_symc_moves() +{ + uint64_t i, ii, coo; + Move j; + + if (read_symc_moves_file()) + return; + + for (i = 0; i < CLASSES_CP_16; i++) { + ii = sd_cp_16.unsym[i]; + for (j = 0; j < NMOVES; j++) { + coo = sd_cp_16.coord->move(j, ii); + move_cp_16[j][i] = sd_cp_16.class[coo]; + ttrep_move_cp_16[j][i] = sd_cp_16.transtorep[coo]; + } + } + + for (i = 0; i < CLASSES_EOFBEPOS_16; i++) { + ii = sd_eofbepos_16.unsym[i]; + for (j = 0; j < NMOVES; j++) { + coo = sd_eofbepos_16.coord->move(j, ii); + move_eofbepos_16[j][i] = sd_eofbepos_16.class[coo]; + ttrep_move_eofbepos_16[j][i] = + sd_eofbepos_16.transtorep[coo]; + } + } + + if (!write_symc_moves_file()) + fprintf(stderr, "Error writing SymMoves file\n"); +} + +void +init_symc_trans() +{ + uint64_t i; + int j, cp; + int epe[4] = {FR, FL, BL, BR}; + int a[12] = { [8] = 8, [9] = 9, [10] = 10, [11] = 11 }; + Cube c; + CubeArray *arr, *aux; + Trans t; + + if (read_symc_trans_file()) + return; + + for (i = 0; i < POW2TO11*BINOM12ON4; i++) { + for (j = 0; j < 16; j++) { + t = trans_group_udfix[j]; + + arr = new_cubearray((Cube){0}, pf_edges); + int_to_sum_zero_array(i % POW2TO11, 2, 12, arr->eofb); + epos_to_compatible_ep((i / POW2TO11)*24, arr->ep, epe); + fix_eorleoud(arr); + c = arrays_to_cube(arr, pf_edges); + free_cubearray(arr, pf_edges); + + c = apply_trans(t, c); + trans_eofbepos[t][i] = (c.epose/24)*POW2TO11 + c.eofb; + } + } + + aux = malloc(sizeof(CubeArray)); + aux->ep = a; + for (i = 0; i < FACTORIAL8; i++) { + index_to_perm(i, 8, a); + c = arrays_to_cube(aux, pf_ep); + for (j = 0; j < 16; j++) { + t = trans_group_udfix[j]; + arr = new_cubearray(apply_trans(t, c), pf_ep); + trans_epud[t][i] = perm_to_index(arr->ep, 8); + free_cubearray(arr, pf_ep); + } + } + free(aux); + + for (i = 0; i < BINOM8ON4; i++) { + cp = cpud_separate_ant[i]; + for (j = 0; j < 16; j++) { + t = trans_group_udfix[j]; + trans_cpud_separate[t][i] = + cpud_separate_ind[cp_ttable[t][cp]]; + } + } + + if (!write_symc_trans_file()) + fprintf(stderr, "Error writing SymTrans file\n"); +} + +void +init_symcoord() +{ + int i; + + static bool initialized = false; + if (initialized) + return; + initialized = true; + + init_coord(); + + init_symc_trans(); + + for (i = 0; all_sd[i] != NULL; i++) + gensym(all_sd[i]); + + init_symc_moves(); +} + 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 @@ +#ifndef SYMCOORD_H +#define SYMCOORD_H + +#include "coord.h" + +extern Coordinate coord_cp_sym16; +extern Coordinate coord_eofbepos_sym16; +extern Coordinate coord_drud_sym16; +extern Coordinate coord_drudfin_noE_sym16; +extern Coordinate coord_nxopt31; + +extern SymData *all_sd[]; + +void free_sd(SymData *sd); +void init_symcoord(); + +#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 @@ -#include -#include "threader_eager.h" - -typedef struct { - AlgList * sols; - pthread_mutex_t * sols_mutex; -} ThreadData; - -typedef struct { - DfsArg * arg; - Solver * solver; - Threader * threader; - AlgList * starts; - AlgListNode ** node; - pthread_mutex_t * start_mutex; -} ThreadInitData; - -static void append_sol(Alg *, void *); -static void * instance_thread(void *); -static void dispatch(DfsArg *, AlgList *, Solver *, Threader *); -static AlgList * possible_starts(DfsArg *, Solver *); -static int get_nsol(void *); - -Threader threader_eager = { - .append_sol = append_sol, - .dispatch = dispatch, - .get_nsol = get_nsol, -}; - -static void -append_sol(Alg *alg, void *threaddata) -{ - ThreadData *td = (ThreadData *)threaddata; - - pthread_mutex_lock(td->sols_mutex); - append_alg(td->sols, alg); - pthread_mutex_unlock(td->sols_mutex); -} - -static AlgList * -possible_starts(DfsArg *arg, Solver *solver) -{ - AlgList *ret = new_alglist(); - - if (solver->is_solved(solver->param, arg->cubedata)) { - if (arg->opts->min_moves == 0 && arg->d == 0) - append_sol(new_alg(""), arg->threaddata); - return ret; - } - - for (int i = 0; solver->moveset->sorted_moves[i] != NULLMOVE; i++) { - Move m = solver->moveset->sorted_moves[i]; - Alg *alg = new_alg(""); - append_move(alg, m, false); - append_alg(ret, alg); - free_alg(alg); - -/* TODO: check if step not final */ - if (arg->opts->can_niss) { - alg = new_alg(""); - append_move(alg, m, true); - append_alg(ret, alg); - free_alg(alg); - } - } - - return ret; -} - -static void * -instance_thread(void *arg) -{ - ThreadInitData *tid = (ThreadInitData *)arg; - - while (true) { - pthread_mutex_lock(tid->start_mutex); - AlgListNode *node = *(tid->node); - if (node == NULL) { - pthread_mutex_unlock(tid->start_mutex); - break; - } - *(tid->node) = (*(tid->node))->next; - pthread_mutex_unlock(tid->start_mutex); - -/* TODO: adjust for longer (arbitrarily long?) starting sequences */ - void *data = tid->solver->alloc_cubedata(tid->solver->param); - tid->solver->copy_cubedata( - tid->solver->param, tid->arg->cubedata, data); - bool inv = node->alg->inv[node->alg->len-1]; - if (inv) - tid->solver->invert_cube( - tid->solver->param, data); - tid->solver->apply_move( - tid->solver->param, data, node->alg->move[0]); - - DfsArg newarg; - newarg.cubedata = data; - newarg.threaddata = tid->arg->threaddata; - newarg.opts = tid->arg->opts; - newarg.d = tid->arg->d; - newarg.niss = inv; - newarg.current_alg = new_alg(""); - copy_alg(node->alg, newarg.current_alg); - - dfs(&newarg, tid->solver, tid->threader); - - tid->solver->free_cubedata(tid->solver->param, data); - free_alg(newarg.current_alg); - } - - return NULL; -} - -static void -dispatch(DfsArg *arg, AlgList *sols, Solver *solver, Threader *threader) -{ - int nthreads = arg->opts->nthreads; - ThreadInitData tid[nthreads]; - pthread_t t[nthreads]; - - pthread_mutex_t *sols_mutex = malloc(sizeof(pthread_mutex_t)); - pthread_mutex_init(sols_mutex, NULL); - - arg->threaddata = malloc(sizeof(ThreadData)); - ThreadData *td = (ThreadData *)arg->threaddata; - td->sols = sols; - td->sols_mutex = sols_mutex; - - AlgList *starts = possible_starts(arg, solver); - AlgListNode *node = starts->first; - pthread_mutex_t *start_mutex = malloc(sizeof(pthread_mutex_t)); - pthread_mutex_init(start_mutex, NULL); - for (int i = 0; i < nthreads; i++) { - tid[i].arg = arg; - tid[i].solver = solver; - tid[i].threader = threader; - tid[i].starts = starts; - tid[i].node = &node; - tid[i].start_mutex = start_mutex; - - pthread_create(&t[i], NULL, instance_thread, &tid[i]); - } - - for (int i = 0; i < nthreads; i++) - pthread_join(t[i], NULL); - - free(td); - free(sols_mutex); - free_alglist(starts); - free(start_mutex); -} - -static int -get_nsol(void *threaddata) -{ - ThreadData *td = (ThreadData *)threaddata; - - pthread_mutex_lock(td->sols_mutex); - int n = td->sols->len; - pthread_mutex_unlock(td->sols_mutex); - - return n; -} 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 @@ -#ifndef THREADER_EAGER_H -#define THREADER_EAGER_H - -#include "solve.h" - -extern Threader threader_eager; - -#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 @@ -#include "threader_single.h" - -static void append_sol(Alg *, void *); -static void dispatch(DfsArg *, AlgList *, Solver *, Threader *); -static int get_nsol(void *); - -Threader threader_single = { - .append_sol = append_sol, - .dispatch = dispatch, - .get_nsol = get_nsol, -}; - -static void -append_sol(Alg *alg, void *threaddata) -{ - append_alg((AlgList *)threaddata, alg); -} - -static void -dispatch(DfsArg *arg, AlgList *sols, Solver *solver, Threader *threader) -{ - arg->threaddata = sols; - arg->niss = false; - arg->current_alg = new_alg(""); - - dfs(arg, solver, threader); - - free_alg(arg->current_alg); -} - -static int -get_nsol(void *threaddata) -{ - return ((AlgList *)threaddata)->len; -} 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 @@ -#ifndef THREADER_SINGLE_H -#define THREADER_SINGLE_H - -#include "solve.h" - -extern Threader threader_single; - -#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 @@ -#define TRANS_C - #include "trans.h" /* Local functions ***********************************************************/ +static bool read_ttables_file(); +static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f); +static bool write_ttables_file(); + /* Tables and other data *****************************************************/ -static Cube mirror_cube = { -.ep = { [UF] = UF, [UL] = UR, [UB] = UB, [UR] = UL, +static int ep_mirror[12] = { + [UF] = UF, [UL] = UR, [UB] = UB, [UR] = UL, [DF] = DF, [DL] = DR, [DB] = DB, [DR] = DL, - [FR] = FL, [FL] = FR, [BL] = BR, [BR] = BL }, -.cp = { [UFR] = UFL, [UFL] = UFR, [UBL] = UBR, [UBR] = UBL, - [DFR] = DFL, [DFL] = DFR, [DBL] = DBR, [DBR] = DBL }, -.xp = { [U_center] = U_center, [D_center] = D_center, + [FR] = FL, [FL] = FR, [BL] = BR, [BR] = BL +}; + +static int cp_mirror[8] = { + [UFR] = UFL, [UFL] = UFR, [UBL] = UBR, [UBR] = UBL, + [DFR] = DFL, [DFL] = DFR, [DBL] = DBR, [DBR] = DBL +}; + +static int cpos_mirror[6] = { + [U_center] = U_center, [D_center] = D_center, [R_center] = L_center, [L_center] = R_center, - [F_center] = F_center, [B_center] = B_center } + [F_center] = F_center, [B_center] = B_center }; -static char rotation_alg_string[100][NROTATIONS] = { +static char rotation_alg_string[100][NROTATIONS] = { [uf] = "", [ur] = "y", [ub] = "y2", [ul] = "y3", [df] = "z2", [dr] = "y z2", [db] = "x2", [dl] = "y3 z2", [rf] = "z3", [rd] = "z3 y", [rb] = "z3 y2", [ru] = "z3 y3", @@ -26,39 +34,176 @@ static char rotation_alg_string[100][NROTATIONS] = { [bu] = "x3", [br] = "x3 y", [bd] = "x3 y2", [bl] = "x3 y3", }; -Alg *rotation_alg_arr[NROTATIONS]; -Move moves_ttable[NTRANS][NMOVES]; -Trans trans_ttable[NTRANS][NTRANS]; -Trans trans_itable[NTRANS]; +static int epose_source[NTRANS]; /* 0=epose, 1=eposs, 2=eposm */ +static int eposs_source[NTRANS]; +static int eposm_source[NTRANS]; +static int eofb_source[NTRANS]; /* 0=eoud, 1=eorl, 2=eofb */ +static int eorl_source[NTRANS]; +static int eoud_source[NTRANS]; +static int coud_source[NTRANS]; /* 0=coud, 1=corl, 2=cofb */ +static int cofb_source[NTRANS]; +static int corl_source[NTRANS]; -/* Public functions **********************************************************/ +int epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +int eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +int eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +int eo_ttable[NTRANS][POW2TO11]; +int cp_ttable[NTRANS][FACTORIAL8]; +int co_ttable[NTRANS][POW3TO7]; +int cpos_ttable[NTRANS][FACTORIAL6]; +Move moves_ttable[NTRANS][NMOVES]; -void -apply_trans(Trans t, Cube *cube) +/* Local functions implementation ********************************************/ + +static bool +read_ttables_file() { - Cube aux; - Alg *inv; - int i; + init_env(); + + FILE *f; + char fname[strlen(tabledir)+20]; + int b = sizeof(int); + bool r = true; + Move m; - inv = inverse_alg(rotation_alg(t % NROTATIONS)); - copy_cube(cube, &aux); - make_solved(cube); - - if (t >= NROTATIONS) - compose(&mirror_cube, cube); - apply_alg(inv, cube); - compose(&aux, cube); - apply_alg(rotation_alg(t % NROTATIONS), cube); - if (t >= NROTATIONS) { - compose(&mirror_cube, cube); - for (i = 0; i < 8; i++) - cube->co[i] = (3 - cube->co[i]) % 3; + /* Table sizes, used for reading and writing files */ + uint64_t me[11] = { + [0] = FACTORIAL12/FACTORIAL8, + [1] = FACTORIAL12/FACTORIAL8, + [2] = FACTORIAL12/FACTORIAL8, + [3] = POW2TO11, + [4] = FACTORIAL8, + [5] = POW3TO7, + [6] = FACTORIAL6, + [7] = NMOVES + }; + + strcpy(fname, tabledir); + strcat(fname, "/"); + strcat(fname, "ttables"); + + if ((f = fopen(fname, "rb")) == NULL) + return false; + + for (m = 0; m < NTRANS; m++) { + r = r && fread(epose_ttable[m], b, me[0], f) == me[0]; + r = r && fread(eposs_ttable[m], b, me[1], f) == me[1]; + r = r && fread(eposm_ttable[m], b, me[2], f) == me[2]; + r = r && fread(eo_ttable[m], b, me[3], f) == me[3]; + r = r && fread(cp_ttable[m], b, me[4], f) == me[4]; + r = r && fread(co_ttable[m], b, me[5], f) == me[5]; + r = r && fread(cpos_ttable[m], b, me[6], f) == me[6]; + r = r && fread(moves_ttable[m], b, me[7], f) == me[7]; } + fclose(f); + return r; +} + +static Cube +rotate_via_compose(Trans r, Cube c, PieceFilter f) +{ + static int zero12[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + static int zero8[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + static CubeArray ma = { + .ep = ep_mirror, + .eofb = zero12, + .eorl = zero12, + .eoud = zero12, + .cp = cp_mirror, + .coud = zero8, + .corl = zero8, + .cofb = zero8, + .cpos = cpos_mirror + }; + + Alg *inv = inverse_alg(rotation_alg(r)); + Cube ret = {0}; + + if (r >= NROTATIONS) + ret = move_via_arrays(&ma, ret, f); + ret = apply_alg_generic(inv, ret, f, true); + + ret = compose_filtered(c, ret, f); + + ret = apply_alg_generic(rotation_alg(r), ret, f, true); + if (r >= NROTATIONS) + ret = move_via_arrays(&ma, ret, f); + free_alg(inv); + return ret; +} + +static bool +write_ttables_file() +{ + init_env(); + + FILE *f; + char fname[strlen(tabledir)+20]; + bool r = true; + int b = sizeof(int); + Move m; + + /* Table sizes, used for reading and writing files */ + uint64_t me[11] = { + [0] = FACTORIAL12/FACTORIAL8, + [1] = FACTORIAL12/FACTORIAL8, + [2] = FACTORIAL12/FACTORIAL8, + [3] = POW2TO11, + [4] = FACTORIAL8, + [5] = POW3TO7, + [6] = FACTORIAL6, + [7] = NMOVES + }; + + strcpy(fname, tabledir); + strcat(fname, "/ttables"); + + if ((f = fopen(fname, "wb")) == NULL) + return false; + + for (m = 0; m < NTRANS; m++) { + r = r && fwrite(epose_ttable[m], b, me[0], f) == me[0]; + r = r && fwrite(eposs_ttable[m], b, me[1], f) == me[1]; + r = r && fwrite(eposm_ttable[m], b, me[2], f) == me[2]; + r = r && fwrite(eo_ttable[m], b, me[3], f) == me[3]; + r = r && fwrite(cp_ttable[m], b, me[4], f) == me[4]; + r = r && fwrite(co_ttable[m], b, me[5], f) == me[5]; + r = r && fwrite(cpos_ttable[m], b, me[6], f) == me[6]; + r = r && fwrite(moves_ttable[m], b, me[7], f) == me[7]; + } + + fclose(f); + return r; +} + +/* Public functions **********************************************************/ + +Cube +apply_trans(Trans t, Cube cube) +{ + /*init_trans();*/ + + int aux_epos[3] = { cube.epose, cube.eposs, cube.eposm }; + int aux_eo[3] = { cube.eoud, cube.eorl, cube.eofb }; + int aux_co[3] = { cube.coud, cube.corl, cube.cofb }; + + return (Cube) { + .epose = epose_ttable[t][aux_epos[epose_source[t]]], + .eposs = eposs_ttable[t][aux_epos[eposs_source[t]]], + .eposm = eposm_ttable[t][aux_epos[eposm_source[t]]], + .eofb = eo_ttable[t][aux_eo[eofb_source[t]]], + .eorl = eo_ttable[t][aux_eo[eorl_source[t]]], + .eoud = eo_ttable[t][aux_eo[eoud_source[t]]], + .coud = co_ttable[t][aux_co[coud_source[t]]], + .corl = co_ttable[t][aux_co[corl_source[t]]], + .cofb = co_ttable[t][aux_co[cofb_source[t]]], + .cp = cp_ttable[t][cube.cp], + .cpos = cpos_ttable[t][cube.cpos] + }; } -/* Trans inverse_trans(Trans t) { @@ -86,18 +231,23 @@ inverse_trans(Trans t) return inverse_trans_aux[t]; } -*/ - -Trans -inverse_trans(Trans t) -{ - return trans_itable[t]; -} Alg * -rotation_alg(Trans i) +rotation_alg(Trans t) { - return rotation_alg_arr[i % NROTATIONS]; + int i; + + static Alg *rotation_alg_arr[NROTATIONS]; + static bool initialized = false; + + if (!initialized) { + for (i = 0; i < NROTATIONS; i++) + rotation_alg_arr[i] = new_alg(rotation_alg_string[i]); + + initialized = true; + } + + return rotation_alg_arr[t % NROTATIONS]; } void @@ -105,20 +255,10 @@ transform_alg(Trans t, Alg *alg) { int i; + /*init_trans();*/ + for (i = 0; i < alg->len; i++) - alg->move[i] = transform_move(t, alg->move[i]); -} - -Move -transform_move(Trans t, Move m) -{ - return moves_ttable[t][m]; -} - -Trans -transform_trans(Trans t, Trans m) -{ - return trans_ttable[t][m]; + alg->move[i] = moves_ttable[t][alg->move[i]]; } void @@ -128,63 +268,106 @@ init_trans() { return; initialized = true; - int i; - Alg *nonsym_alg, *nonsym_inv; - Cube aux, cube; + init_moves(); + + Cube aux, cube, c[3]; + CubeArray epcp; + int i, eparr[12], eoarr[12], cparr[8], coarr[8]; + unsigned int ui; Move mi, move; - Trans t, u, v; + Trans m; - init_moves(); + /* Compute sources */ + for (i = 0; i < NTRANS; i++) { + cube = apply_alg(rotation_alg(i), (Cube){0}); + + epose_source[i] = edge_slice(what_edge_at(cube, FR)); + eposs_source[i] = edge_slice(what_edge_at(cube, UR)); + eposm_source[i] = edge_slice(what_edge_at(cube, UF)); + eofb_source[i] = what_center_at(cube, F_center)/2; + eorl_source[i] = what_center_at(cube, R_center)/2; + eoud_source[i] = what_center_at(cube, U_center)/2; + coud_source[i] = what_center_at(cube, U_center)/2; + cofb_source[i] = what_center_at(cube, F_center)/2; + corl_source[i] = what_center_at(cube, R_center)/2; + } - for (i = 0; i < NROTATIONS; i++) - rotation_alg_arr[i] = new_alg(rotation_alg_string[i]); + if (read_ttables_file()) + return; + + fprintf(stderr, "Cannot load %s, generating it\n", "ttables"); - for (t = 0; t < NTRANS; t++) { + /* Initialize tables */ + for (m = 0; m < NTRANS; m++) { + epcp = (CubeArray){ .ep = eparr, .cp = cparr }; + cube = apply_alg(rotation_alg(m), (Cube){0}); + cube_to_arrays(cube, &epcp, pf_epcp); + if (m >= NROTATIONS) { + apply_permutation(ep_mirror, eparr, 12); + apply_permutation(cp_mirror, cparr, 8); + } + + for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) { + c[0] = admissible_ep((Cube){ .epose = ui }, pf_e); + c[1] = admissible_ep((Cube){ .eposs = ui }, pf_s); + c[2] = admissible_ep((Cube){ .eposm = ui }, pf_m); + + cube = rotate_via_compose(m,c[epose_source[m]],pf_ep); + epose_ttable[m][ui] = cube.epose; + + cube = rotate_via_compose(m,c[eposs_source[m]],pf_ep); + eposs_ttable[m][ui] = cube.eposs; + + cube = rotate_via_compose(m,c[eposm_source[m]],pf_ep); + eposm_ttable[m][ui] = cube.eposm; + } + for (ui = 0; ui < POW2TO11; ui++ ) { + int_to_sum_zero_array(ui, 2, 12, eoarr); + apply_permutation(eparr, eoarr, 12); + eo_ttable[m][ui] = digit_array_to_int(eoarr, 11, 2); + } + for (ui = 0; ui < POW3TO7; ui++) { + int_to_sum_zero_array(ui, 3, 8, coarr); + apply_permutation(cparr, coarr, 8); + co_ttable[m][ui] = digit_array_to_int(coarr, 7, 3); + if (m >= NROTATIONS) + co_ttable[m][ui] = + invert_digits(co_ttable[m][ui], 3, 7); + } + for (ui = 0; ui < FACTORIAL8; ui++) { + cube = (Cube){ .cp = ui }; + cube = rotate_via_compose(m, cube, pf_cp); + cp_ttable[m][ui] = cube.cp; + } + for (ui = 0; ui < FACTORIAL6; ui++) { + cube = (Cube){ .cpos = ui }; + cube = rotate_via_compose(m, cube, pf_cpos); + cpos_ttable[m][ui] = cube.cpos; + } for (mi = 0; mi < NMOVES; mi++) { - make_solved(&aux); - apply_move(mi, &aux); - apply_trans(t, &aux); + /* Old version: + * + aux = apply_trans(m, apply_move(mi, (Cube){0})); for (move = 0; move < NMOVES; move++) { - copy_cube(&aux, &cube); - apply_move(inverse_move(move), &cube); - if (is_solved(&cube)) { - moves_ttable[t][mi] = move; - break; - } + cube = apply_move(inverse_move(move), aux); + mirr = apply_trans(uf_mirror, cube); + if (is_solved(cube) || is_solved(mirr)) + moves_ttable[m][mi] = move; } - } - } + */ - nonsym_alg = new_alg("R' U' F"); - nonsym_inv = inverse_alg(nonsym_alg); - - for (t = 0; t < NTRANS; t++) { - for (u = 0; u < NTRANS; u++) { - make_solved(&aux); - apply_alg(nonsym_alg, &aux); - apply_trans(u, &aux); - apply_trans(t, &aux); - for (v = 0; v < NTRANS; v++) { - copy_cube(&aux, &cube); - apply_trans(v, &cube); - apply_alg(nonsym_inv, &cube); - if (is_solved(&cube)) { - /* This is the inverse of the correct - value, it will be inverted later */ - trans_ttable[t][u] = v; - if (v == uf) - trans_itable[t] = u; + aux = apply_trans(m, apply_move(mi, (Cube){0})); + for (move = 0; move < NMOVES; move++) { + cube = apply_move(inverse_move(move), aux); + if (is_solved(cube)) { + moves_ttable[m][mi] = move; break; } } } } - for (t = 0; t < NTRANS; t++) - for (u = 0; u < NTRANS; u++) - trans_ttable[t][u] = trans_itable[trans_ttable[t][u]]; - - free_alg(nonsym_alg); - free_alg(nonsym_inv); + if (!write_ttables_file()) + fprintf(stderr, "Error writing ttables\n"); } 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 @@ #include "moves.h" -void apply_trans(Trans t, Cube *cube); +/* + * Tables are exposed to allow faster partial transformations in some + * specific cases (in symcoord) + */ +extern int epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +extern int eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +extern int eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +extern int eo_ttable[NTRANS][POW2TO11]; +extern int cp_ttable[NTRANS][FACTORIAL8]; +extern int co_ttable[NTRANS][POW3TO7]; +extern int cpos_ttable[NTRANS][FACTORIAL6]; +extern Move moves_ttable[NTRANS][NMOVES]; + +Cube apply_trans(Trans t, Cube cube); Trans inverse_trans(Trans t); Alg * rotation_alg(Trans i); -void transform_alg(Trans t, Alg *alg); -Move transform_move(Trans t, Move m); -Trans transform_trans(Trans t, Trans m); +void transform_alg(Trans i, Alg *alg); void init_trans(); -#ifndef TRANS_C - -extern TransGroup tgrp_udfix; - -#else - -TransGroup -tgrp_udfix = { - .n = 16, - .t = { uf, ur, ub, ul, - df, dr, db, dl, - uf_mirror, ur_mirror, ub_mirror, ul_mirror, - df_mirror, dr_mirror, db_mirror, dl_mirror }, -}; - -#endif - #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 @@ -#define UTILS_C - #include "utils.h" void @@ -161,24 +159,24 @@ is_perm(int *a, int n) { int *aux = malloc(n * sizeof(int)); int i; - bool ret = true; for (i = 0; i < n; i++) aux[i] = 0; for (i = 0; i < n; i++) { if (a[i] < 0 || a[i] >= n) - ret = false; + return false; else aux[a[i]] = 1; } for (i = 0; i < n; i++) if (!aux[i]) - ret = false; + return false; free(aux); - return ret; + + return true; } bool @@ -197,7 +195,7 @@ perm_sign(int *a, int n) { int i, j, ret = 0; - if (!is_perm(a, n)) + if (!is_perm(a,n)) return -1; for (i = 0; i < n; i++) @@ -213,7 +211,7 @@ perm_to_index(int *a, int n) int i, j, c, ret = 0; if (!is_perm(a, n)) - return factorial(n); + return -1; for (i = 0; i < n; i++) { c = 0; -- cgit v1.3