From 3568412f8f230774d0d11d7ed1c897424f95d3ef Mon Sep 17 00:00:00 2001 From: Sebastiano Tronto Date: Thu, 11 Nov 2021 21:37:34 +0100 Subject: Rewritten from scratch. Welocme nissy 2.0! --- old/2020-unknown-date/cube_backup.c | 527 +++ old/2020-unknown-date/cubeutils.c | 100 + old/2020-unknown-date/cubeutils.h | 18 + old/2020-unknown-date/moves.c | 57 + old/2020-unknown-date/moves.h | 9 + old/2020-unknown-date/pieces.c | 208 ++ old/2020-unknown-date/pieces.h | 59 + old/2021-02-06/cube.c | 664 ++++ old/2021-02-06/cube.h | 60 + old/2021-02-06/main.c | 46 + old/2021-02-06/solve.c | 177 + old/2021-02-06/solve.h | 55 + old/2021-02-06/utils.c | 197 ++ old/2021-02-06/utils.h | 70 + old/2021-02-18-piecefilter/compile.sh | 1 + old/2021-02-18-piecefilter/nissy | Bin 0 -> 71872 bytes old/2021-02-18-piecefilter/src/cube.c | 198 ++ old/2021-02-18-piecefilter/src/cube.h | 45 + old/2021-02-18-piecefilter/src/main.c | 47 + old/2021-02-18-piecefilter/src/moves.c | 482 +++ old/2021-02-18-piecefilter/src/moves.h | 46 + old/2021-02-18-piecefilter/src/solve.c | 179 + old/2021-02-18-piecefilter/src/solve.h | 56 + old/2021-02-18-piecefilter/src/transformations.c | 103 + old/2021-02-18-piecefilter/src/transformations.h | 37 + old/2021-02-18-piecefilter/src/utils.c | 197 ++ old/2021-02-18-piecefilter/src/utils.h | 70 + old/2021-02-28-transformcube-works/src/cube.c | 271 ++ old/2021-02-28-transformcube-works/src/cube.h | 55 + old/2021-02-28-transformcube-works/src/main.c | 57 + old/2021-02-28-transformcube-works/src/moves.c | 489 +++ old/2021-02-28-transformcube-works/src/moves.h | 50 + old/2021-02-28-transformcube-works/src/solve.c | 180 ++ old/2021-02-28-transformcube-works/src/solve.h | 56 + .../src/transformations.c | 224 ++ .../src/transformations.h | 34 + old/2021-02-28-transformcube-works/src/utils.c | 197 ++ old/2021-02-28-transformcube-works/src/utils.h | 70 + old/2021-05-26-before-restyle/cube.c | 293 ++ old/2021-05-26-before-restyle/cube.h | 65 + old/2021-05-26-before-restyle/main.c | 24 + old/2021-05-26-before-restyle/moves.c | 412 +++ old/2021-05-26-before-restyle/moves.h | 51 + old/2021-05-26-before-restyle/solve.c | 180 ++ old/2021-05-26-before-restyle/solve.h | 59 + old/2021-05-26-before-restyle/transformations.c | 200 ++ old/2021-05-26-before-restyle/transformations.h | 34 + old/2021-05-26-before-restyle/utils.c | 197 ++ old/2021-05-26-before-restyle/utils.h | 70 + old/2021-06-02-cleanedup/cube.c | 2010 ++++++++++++ old/2021-06-02-cleanedup/cube.h | 179 + old/2021-06-02-cleanedup/main.c | 35 + old/2021-06-02-cleanedup/steps.h | 22 + old/2021-06-14-oldalg/cube.c | 2849 ++++++++++++++++ old/2021-06-14-oldalg/cube.h | 73 + old/2021-06-14-oldalg/cubetypes.h | 210 ++ old/2021-06-14-oldalg/main.c | 56 + old/2021-06-15-before-separating-steps/cube.c | 2836 ++++++++++++++++ old/2021-06-15-before-separating-steps/cube.h | 72 + old/2021-06-15-before-separating-steps/cubetypes.h | 201 ++ old/2021-06-15-before-separating-steps/main.c | 60 + old/2021-06-15-before-separating-steps/steps.h | 20 + old/2021-06-17-cachedata/cube.c | 2738 ++++++++++++++++ old/2021-06-17-cachedata/cube.h | 79 + old/2021-06-17-cachedata/cubetypes.h | 232 ++ old/2021-06-17-cachedata/main.c | 63 + old/2021-06-17-cachedata/steps.c | 327 ++ old/2021-06-17-cachedata/steps.h | 34 + old/2021-06-23-realizing-bad-tables/HERE | 1 + old/2021-06-23-realizing-bad-tables/cube.c | 2844 ++++++++++++++++ old/2021-06-23-realizing-bad-tables/cube.h | 88 + old/2021-06-23-realizing-bad-tables/cubetypes.h | 224 ++ old/2021-06-23-realizing-bad-tables/main.c | 70 + old/2021-06-23-realizing-bad-tables/steps.c | 486 +++ old/2021-06-23-realizing-bad-tables/steps.h | 42 + old/2021-06-23-uint16t/cube.c | 2762 ++++++++++++++++ old/2021-06-23-uint16t/cube.h | 87 + old/2021-06-23-uint16t/cubetypes.h | 224 ++ old/2021-06-30-noreached/cube.c | 3394 +++++++++++++++++++ old/2021-06-30-noreached/cube.h | 90 + old/2021-06-30-noreached/cubetypes.h | 250 ++ old/2021-06-30-noreached/macros.h | 23 + old/2021-06-30-noreached/main.c | 80 + old/2021-06-30-noreached/steps.c | 307 ++ old/2021-06-30-noreached/steps.h | 24 + old/2021-06-30-reached/cube.c | 3419 ++++++++++++++++++++ old/2021-06-30-reached/cube.h | 90 + old/2021-06-30-reached/cubetypes.h | 251 ++ old/2021-06-30-reached/macros.h | 23 + old/2021-06-30-reached/main.c | 80 + old/2021-06-30-reached/steps.c | 307 ++ old/2021-06-30-reached/steps.h | 24 + old/2021-07-02-genptable-dfs/cube.c | 3394 +++++++++++++++++++ old/2021-07-02-genptable-dfs/cube.h | 90 + old/2021-07-02-genptable-dfs/cubetypes.h | 250 ++ old/2021-07-02-genptable-dfs/macros.h | 23 + old/2021-07-02-genptable-dfs/main.c | 80 + old/2021-07-02-genptable-dfs/steps.c | 307 ++ old/2021-07-02-genptable-dfs/steps.h | 24 + old/2021-07-15-almostbeforerefactor/README | 3 + old/2021-07-15-almostbeforerefactor/alg.c | 3388 +++++++++++++++++++ old/2021-07-15-almostbeforerefactor/alg.h | 27 + old/2021-07-15-almostbeforerefactor/cube.c | 3391 +++++++++++++++++++ old/2021-07-15-almostbeforerefactor/cube.h | 79 + old/2021-07-15-almostbeforerefactor/cubetypes.h | 252 ++ old/2021-07-15-almostbeforerefactor/macros.h | 23 + old/2021-07-15-almostbeforerefactor/main.c | 60 + old/2021-07-15-almostbeforerefactor/nissy | Bin 0 -> 92920 bytes old/2021-07-15-almostbeforerefactor/steps.c | 284 ++ old/2021-07-15-almostbeforerefactor/steps.h | 24 + old/2021-11-10-beforeremovingchecker/alg.c | 366 +++ old/2021-11-10-beforeremovingchecker/alg.h | 35 + old/2021-11-10-beforeremovingchecker/commands.c | 329 ++ old/2021-11-10-beforeremovingchecker/commands.h | 13 + old/2021-11-10-beforeremovingchecker/coord.c | 629 ++++ old/2021-11-10-beforeremovingchecker/coord.h | 40 + old/2021-11-10-beforeremovingchecker/cube.c | 716 ++++ old/2021-11-10-beforeremovingchecker/cube.h | 40 + old/2021-11-10-beforeremovingchecker/cubetypes.h | 298 ++ old/2021-11-10-beforeremovingchecker/env.c | 45 + old/2021-11-10-beforeremovingchecker/env.h | 15 + old/2021-11-10-beforeremovingchecker/moves.c | 474 +++ old/2021-11-10-beforeremovingchecker/moves.h | 16 + old/2021-11-10-beforeremovingchecker/pf.c | 80 + old/2021-11-10-beforeremovingchecker/pf.h | 18 + old/2021-11-10-beforeremovingchecker/pruning.c | 272 ++ old/2021-11-10-beforeremovingchecker/pruning.h | 23 + old/2021-11-10-beforeremovingchecker/shell.c | 99 + old/2021-11-10-beforeremovingchecker/shell.h | 13 + old/2021-11-10-beforeremovingchecker/solve.c | 209 ++ old/2021-11-10-beforeremovingchecker/solve.h | 9 + old/2021-11-10-beforeremovingchecker/steps.c | 916 ++++++ old/2021-11-10-beforeremovingchecker/steps.h | 10 + old/2021-11-10-beforeremovingchecker/symcoord.c | 359 ++ old/2021-11-10-beforeremovingchecker/symcoord.h | 15 + old/2021-11-10-beforeremovingchecker/trans.c | 372 +++ old/2021-11-10-beforeremovingchecker/trans.h | 13 + old/2021-11-10-beforeremovingchecker/utils.c | 274 ++ old/2021-11-10-beforeremovingchecker/utils.h | 41 + old/backup-manysteps-pretrans/steps.c | 369 +++ old/backup-manysteps-pretrans/steps.h | 36 + old/coord.c | 1014 ++++++ old/coord.h | 45 + old/utils.c | 294 ++ old/utils.h | 59 + 145 files changed, 53517 insertions(+) create mode 100644 old/2020-unknown-date/cube_backup.c create mode 100644 old/2020-unknown-date/cubeutils.c create mode 100644 old/2020-unknown-date/cubeutils.h create mode 100644 old/2020-unknown-date/moves.c create mode 100644 old/2020-unknown-date/moves.h create mode 100644 old/2020-unknown-date/pieces.c create mode 100644 old/2020-unknown-date/pieces.h create mode 100644 old/2021-02-06/cube.c create mode 100644 old/2021-02-06/cube.h create mode 100644 old/2021-02-06/main.c create mode 100644 old/2021-02-06/solve.c create mode 100644 old/2021-02-06/solve.h create mode 100644 old/2021-02-06/utils.c create mode 100644 old/2021-02-06/utils.h create mode 100755 old/2021-02-18-piecefilter/compile.sh create mode 100755 old/2021-02-18-piecefilter/nissy create mode 100644 old/2021-02-18-piecefilter/src/cube.c create mode 100644 old/2021-02-18-piecefilter/src/cube.h create mode 100644 old/2021-02-18-piecefilter/src/main.c create mode 100644 old/2021-02-18-piecefilter/src/moves.c create mode 100644 old/2021-02-18-piecefilter/src/moves.h create mode 100644 old/2021-02-18-piecefilter/src/solve.c create mode 100644 old/2021-02-18-piecefilter/src/solve.h create mode 100644 old/2021-02-18-piecefilter/src/transformations.c create mode 100644 old/2021-02-18-piecefilter/src/transformations.h create mode 100644 old/2021-02-18-piecefilter/src/utils.c create mode 100644 old/2021-02-18-piecefilter/src/utils.h create mode 100644 old/2021-02-28-transformcube-works/src/cube.c create mode 100644 old/2021-02-28-transformcube-works/src/cube.h create mode 100644 old/2021-02-28-transformcube-works/src/main.c create mode 100644 old/2021-02-28-transformcube-works/src/moves.c create mode 100644 old/2021-02-28-transformcube-works/src/moves.h create mode 100644 old/2021-02-28-transformcube-works/src/solve.c create mode 100644 old/2021-02-28-transformcube-works/src/solve.h create mode 100644 old/2021-02-28-transformcube-works/src/transformations.c create mode 100644 old/2021-02-28-transformcube-works/src/transformations.h create mode 100644 old/2021-02-28-transformcube-works/src/utils.c create mode 100644 old/2021-02-28-transformcube-works/src/utils.h create mode 100644 old/2021-05-26-before-restyle/cube.c create mode 100644 old/2021-05-26-before-restyle/cube.h create mode 100644 old/2021-05-26-before-restyle/main.c create mode 100644 old/2021-05-26-before-restyle/moves.c create mode 100644 old/2021-05-26-before-restyle/moves.h create mode 100644 old/2021-05-26-before-restyle/solve.c create mode 100644 old/2021-05-26-before-restyle/solve.h create mode 100644 old/2021-05-26-before-restyle/transformations.c create mode 100644 old/2021-05-26-before-restyle/transformations.h create mode 100644 old/2021-05-26-before-restyle/utils.c create mode 100644 old/2021-05-26-before-restyle/utils.h create mode 100644 old/2021-06-02-cleanedup/cube.c create mode 100644 old/2021-06-02-cleanedup/cube.h create mode 100644 old/2021-06-02-cleanedup/main.c create mode 100644 old/2021-06-02-cleanedup/steps.h create mode 100644 old/2021-06-14-oldalg/cube.c create mode 100644 old/2021-06-14-oldalg/cube.h create mode 100644 old/2021-06-14-oldalg/cubetypes.h create mode 100644 old/2021-06-14-oldalg/main.c create mode 100644 old/2021-06-15-before-separating-steps/cube.c create mode 100644 old/2021-06-15-before-separating-steps/cube.h create mode 100644 old/2021-06-15-before-separating-steps/cubetypes.h create mode 100644 old/2021-06-15-before-separating-steps/main.c create mode 100644 old/2021-06-15-before-separating-steps/steps.h create mode 100644 old/2021-06-17-cachedata/cube.c create mode 100644 old/2021-06-17-cachedata/cube.h create mode 100644 old/2021-06-17-cachedata/cubetypes.h create mode 100644 old/2021-06-17-cachedata/main.c create mode 100644 old/2021-06-17-cachedata/steps.c create mode 100644 old/2021-06-17-cachedata/steps.h create mode 100644 old/2021-06-23-realizing-bad-tables/HERE create mode 100644 old/2021-06-23-realizing-bad-tables/cube.c create mode 100644 old/2021-06-23-realizing-bad-tables/cube.h create mode 100644 old/2021-06-23-realizing-bad-tables/cubetypes.h create mode 100644 old/2021-06-23-realizing-bad-tables/main.c create mode 100644 old/2021-06-23-realizing-bad-tables/steps.c create mode 100644 old/2021-06-23-realizing-bad-tables/steps.h create mode 100644 old/2021-06-23-uint16t/cube.c create mode 100644 old/2021-06-23-uint16t/cube.h create mode 100644 old/2021-06-23-uint16t/cubetypes.h create mode 100644 old/2021-06-30-noreached/cube.c create mode 100644 old/2021-06-30-noreached/cube.h create mode 100644 old/2021-06-30-noreached/cubetypes.h create mode 100644 old/2021-06-30-noreached/macros.h create mode 100644 old/2021-06-30-noreached/main.c create mode 100644 old/2021-06-30-noreached/steps.c create mode 100644 old/2021-06-30-noreached/steps.h create mode 100644 old/2021-06-30-reached/cube.c create mode 100644 old/2021-06-30-reached/cube.h create mode 100644 old/2021-06-30-reached/cubetypes.h create mode 100644 old/2021-06-30-reached/macros.h create mode 100644 old/2021-06-30-reached/main.c create mode 100644 old/2021-06-30-reached/steps.c create mode 100644 old/2021-06-30-reached/steps.h create mode 100644 old/2021-07-02-genptable-dfs/cube.c create mode 100644 old/2021-07-02-genptable-dfs/cube.h create mode 100644 old/2021-07-02-genptable-dfs/cubetypes.h create mode 100644 old/2021-07-02-genptable-dfs/macros.h create mode 100644 old/2021-07-02-genptable-dfs/main.c create mode 100644 old/2021-07-02-genptable-dfs/steps.c create mode 100644 old/2021-07-02-genptable-dfs/steps.h create mode 100644 old/2021-07-15-almostbeforerefactor/README create mode 100644 old/2021-07-15-almostbeforerefactor/alg.c create mode 100644 old/2021-07-15-almostbeforerefactor/alg.h create mode 100644 old/2021-07-15-almostbeforerefactor/cube.c create mode 100644 old/2021-07-15-almostbeforerefactor/cube.h create mode 100644 old/2021-07-15-almostbeforerefactor/cubetypes.h create mode 100644 old/2021-07-15-almostbeforerefactor/macros.h create mode 100644 old/2021-07-15-almostbeforerefactor/main.c create mode 100755 old/2021-07-15-almostbeforerefactor/nissy create mode 100644 old/2021-07-15-almostbeforerefactor/steps.c create mode 100644 old/2021-07-15-almostbeforerefactor/steps.h create mode 100644 old/2021-11-10-beforeremovingchecker/alg.c create mode 100644 old/2021-11-10-beforeremovingchecker/alg.h create mode 100644 old/2021-11-10-beforeremovingchecker/commands.c create mode 100644 old/2021-11-10-beforeremovingchecker/commands.h create mode 100644 old/2021-11-10-beforeremovingchecker/coord.c create mode 100644 old/2021-11-10-beforeremovingchecker/coord.h create mode 100644 old/2021-11-10-beforeremovingchecker/cube.c create mode 100644 old/2021-11-10-beforeremovingchecker/cube.h create mode 100644 old/2021-11-10-beforeremovingchecker/cubetypes.h create mode 100644 old/2021-11-10-beforeremovingchecker/env.c create mode 100644 old/2021-11-10-beforeremovingchecker/env.h create mode 100644 old/2021-11-10-beforeremovingchecker/moves.c create mode 100644 old/2021-11-10-beforeremovingchecker/moves.h create mode 100644 old/2021-11-10-beforeremovingchecker/pf.c create mode 100644 old/2021-11-10-beforeremovingchecker/pf.h create mode 100644 old/2021-11-10-beforeremovingchecker/pruning.c create mode 100644 old/2021-11-10-beforeremovingchecker/pruning.h create mode 100644 old/2021-11-10-beforeremovingchecker/shell.c create mode 100644 old/2021-11-10-beforeremovingchecker/shell.h create mode 100644 old/2021-11-10-beforeremovingchecker/solve.c create mode 100644 old/2021-11-10-beforeremovingchecker/solve.h create mode 100644 old/2021-11-10-beforeremovingchecker/steps.c create mode 100644 old/2021-11-10-beforeremovingchecker/steps.h create mode 100644 old/2021-11-10-beforeremovingchecker/symcoord.c create mode 100644 old/2021-11-10-beforeremovingchecker/symcoord.h create mode 100644 old/2021-11-10-beforeremovingchecker/trans.c create mode 100644 old/2021-11-10-beforeremovingchecker/trans.h create mode 100644 old/2021-11-10-beforeremovingchecker/utils.c create mode 100644 old/2021-11-10-beforeremovingchecker/utils.h create mode 100644 old/backup-manysteps-pretrans/steps.c create mode 100644 old/backup-manysteps-pretrans/steps.h create mode 100644 old/coord.c create mode 100644 old/coord.h create mode 100644 old/utils.c create mode 100644 old/utils.h (limited to 'old') diff --git a/old/2020-unknown-date/cube_backup.c b/old/2020-unknown-date/cube_backup.c new file mode 100644 index 0000000..e049edd --- /dev/null +++ b/old/2020-unknown-date/cube_backup.c @@ -0,0 +1,527 @@ +#include +#include +#include "cube.h" + +/* The next few functions are used to convert from the Cube structure + * representation to actual arrays of pieces. */ +void cube_to_ep_array(Cube cube, int ep[12]); +void cube_to_eofb_array(Cube cube, int eo[12]); +void cube_to_eorl_array(Cube cube, int eo[12]); +void cube_to_eoud_array(Cube cube, int eo[12]); +void cube_to_cp_array(Cube cube, int cp[8]); +void cube_to_coud_array(Cube cube, int co[8]); +void cube_to_cofb_array(Cube cube, int co[8]); +void cube_to_corl_array(Cube cube, int co[8]); +void cube_to_centerpos_array(Cube cube, int centerpos[6]); +Cube ep_array_to_cube(int ep[12]); +Cube eofb_array_to_cube(int eo[12]); +Cube eorl_array_to_cube(int eo[12]); +Cube eoud_array_to_cube(int eo[12]); +Cube cp_array_to_cube(int cp[8]); +Cube coud_array_to_cube(int co[8]); +Cube cofb_array_to_cube(int co[8]); +Cube corl_array_to_cube(int co[8]); +Cube centerpos_array_to_cube(int centerpos[6]); +Cube move_array(Cube cube, void (cube_to_arr)(Cube, int *), + Cube (*arr_to_cube)(int *), + int *perm, int *orient, int n, int m); + + +/* Transition tables */ +int epose_ttable[NMOVES][factorial12/factorial8]; +int eposs_ttable[NMOVES][factorial12/factorial8]; +int eposm_ttable[NMOVES][factorial12/factorial8]; +int eofb_ttable[NMOVES][pow2to11]; +int eorl_ttable[NMOVES][pow2to11]; +int eoud_ttable[NMOVES][pow2to11]; +int cp_ttable[NMOVES][factorial8]; +int coud_ttable[NMOVES][pow3to7]; +int cofb_ttable[NMOVES][pow3to7]; +int corl_ttable[NMOVES][pow3to7]; +int centerpos_ttable[NMOVES][factorial6]; + +char edge_string[12][5] = { + "UF", "UL", "UB", "UR", "DF", "DL", "DB", "DR", "FR", "FL", "BL", "BR" +}; +char corner_string[8][5] = { "UFR", "UFL", "UBL", "UBR", "DFR", "DFL", "DBL", "DBR" }; +char center_string[6][5] = { "U", "D", "R", "L", "F", "B" }; +char move_string[NMOVES][5] = { + "-", + "U", "U2", "U\'", "D", "D2", "D\'", "R", "R2", "R\'", + "L", "L2", "L\'", "F", "F2", "F\'", "B", "B2", "B\'", + "Uw", "Uw2", "Uw\'", "Dw", "Dw2", "Dw\'", "Rw", "Rw2", "Rw\'", + "Lw", "Lw2", "Lw\'", "Fw", "Fw2", "Fw\'", "Bw", "Bw2", "Bw\'", + "M", "M2", "M\'", "S", "S2", "S\'", "E", "E2", "E\'", + "x", "x2", "x\'", "y", "y2", "y\'", "z", "z2", "z\'", +}; + +int epe_solved[] = {FR, FL, BL, BR}; +int eps_solved[] = {UL, UR, DL, DR}; +int epm_solved[] = {UF, UB, DF, DB}; + +/**************************/ +/* Internal use functions */ +/**************************/ + +int cube_to_ep_array(Cube cube, int ep[12]) { + int epe[4], eps[4], epm[4]; + index_to_perm(cube.epose % factorial(4), 4, epe); + index_to_perm(cube.eposs % factorial(4), 4, eps); + index_to_perm(cube.eposm % factorial(4), 4, epm); + + int epose[12], eposs[12], eposm[12]; + index_to_subset(cube.epose / factorial(4), 12, 4, epose); + index_to_subset(cube.eposs / factorial(4), 12, 4, eposs); + index_to_subset(cube.eposm / factorial(4), 12, 4, eposm); + for (int i = 0; i < 4; i++) { + swap(&eposs[eps_solved[i]], &eposs[i+8]); + swap(&eposm[epm_solved[i]], &eposm[i+8]); + } + + for (int i = 0, ie = 0, is = 0, im = 0; i < 12; i++) { + if (epose[i]) ep[i] = epe_solved[epe[ie++]]; + if (eposs[i]) ep[i] = eps_solved[eps[is++]]; + if (eposm[i]) ep[i] = epm_solved[epm[im++]]; + } +} + +void cube_to_eofb_array(Cube cube, int eo[12]) { + int_to_sum_zero_array(cube.eofb, 2, 12, eo); +} + +void cube_to_eorl_array(Cube cube, int eo[12]) { + int_to_sum_zero_array(cube.eorl, 2, 12, eo); +} + +void cube_to_eoud_array(Cube cube, int eo[12]) { + int_to_sum_zero_array(cube.eoud, 2, 12, eo); +} + +void cube_to_cp_array(Cube cube, int cp[8]) { + index_to_perm(cube.cp, 8, cp); +} + +void cube_to_coud_array(Cube cube, int co[8]) { + int_to_sum_zero_array(cube.coud, 3, 8, co); +} + +void cube_to_cofb_array(Cube cube, int co[8]) { + int_to_sum_zero_array(cube.cofb, 3, 8, co); +} + +void cube_to_corl_array(Cube cube, int co[8]) { + int_to_sum_zero_array(cube.corl, 3, 8, co); +} + +void cube_to_centerpos_array(Cube cube, int centerpos[6]) { + index_to_perm(cube.centerpos, 6, centerpos); +} + +Cube ep_array_to_cube(int ep[12]) { + int epe[4], eps[4], epm[4]; + int epose[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + int eposs[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + int eposm[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + for (int i = 0, ie = 0, is = 0, im = 0; i < 12; i++) { + for (int j = 0; j < 4; j++) { + if (ep[i] == epe_solved[j]) { epe[ie++] = j; epose[i] = 1; } + if (ep[i] == eps_solved[j]) { eps[is++] = j; eposs[i] = 1; } + if (ep[i] == epm_solved[j]) { epm[im++] = j; eposm[i] = 1; } + } + } + for (int i = 0; i < 4; i++) { + swap(&eposs[eps_solved[i]], &eposs[i+8]); + swap(&eposm[epm_solved[i]], &eposm[i+8]); + } + return { .epose = factorial(4) * subset_to_index(epose, 12, 4) + + perm_to_index(epe, 4), + .eposs = factorial(4) * subset_to_index(eposs, 12, 4) + + perm_to_index(eps, 4), + .eposm = factorial(4) * subset_to_index(eposm, 12, 4) + + perm_to_index(epm, 4) }; +} + +Cube eofb_array_to_cube(int eo[12]) { + return { .eofb = digit_array_to_int(eo, 11, 2) }; +} + +Cube eorl_array_to_cube(int eo[12]) { + return { .eorl = digit_array_to_int(eo, 11, 2) }; +} + +Cube eoud_array_to_cube(int eo[12]) { + return { .eoud = digit_array_to_int(eo, 11, 2) }; +} + +Cube cp_array_to_cube(int cp[8]) { + return { .cp = perm_to_index(cp, 8) }; +} + +Cube coud_array_to_cube(int co[8]) { + return { .coud = digit_array_to_int(co, 7, 3) }; +} + +Cube cofb_array_to_cube(int co[8]) { + return { .cofb = digit_array_to_int(co, 7, 3) }; +} + +Cube corl_array_to_cube(int co[8]) { + return { .corl = digit_array_to_int(co, 7, 3) }; +} + +Cube centerpos_array_to_cube(int centerpos[6]) { + return { .centerpos = perm_to_index(centerpos, 6) }; +} + +Cube move_array(Cube cube, void (*cube_to_arr)(Cube, int *), + void (*arr_to_cube)(int *), + int *perm, int *orient, int n, int m) { + int arr[n]; + cube_to_arr(cube, arr); + apply_permutation(perm, arr, n); + sum_arrays_mod(arr, orient, n, m); + return arr_to_cube(arr); +} + +/***********************/ +/* Interface functions */ +/***********************/ + +Move inverse(Move m) { + if (m == NULLMOVE) + return m; + int mod = (m-1)%3; + Move base = m - mod; + return base + 2 - mod; +} + +void copy_alg(NissMove *src, NissMove *dest) { + for (int i = 0; src[i].m != NULLMOVE; i++) + dest[i] = src[i]; +} + +bool commute(Move m1, Move m2) { + return equal(apply_move(m2, apply_move(m1, {0})), + apply_move(m1, apply_move(m2, {0}))); +} + +bool equal(Cube c1, Cube c2) { + 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.centerpos == c2.centerpos; +} + +bool solvable(Cube cube) { + /* Since we memorize orientation truncating the last digit, we only need to + * check that the permutations have the correct sign. */ + /* TODO: add check that every integer is in range */ + int ep[12], cp[12], c[6]; + /* TODO: change to use cube-specific functions */ + cube_to_ep_array(cube, ep); + cube_to_cp_array(cube, 8, cp); + cube_to_centerpos_array(cube, 6, c); + return (perm_sign(ep, 12) ^ perm_sign(c, 6)) == perm_sign(cp, 8); +} + +bool is_solved(Cube cube) { + return (!cube.eofb && !cube.coud && !cube.cp && + !cube.epose && !cube.eposs && !cube.eposm && !cube.centerpos); +} + +char *to_string(Cube cube) { + int eo[12], co[8], ep[12], cp[8], cenpos[6]; + cube_to_eofb_array(cube, eo); + cube_to_coud_array(cube, co); + cube_to_ep_array(cube, ep); + cube_to_cp_array(cube, cp); + cube_to_centerpos_array(cube, cenpos); + + static char ret[1000]; + + for (int i = 0; i < 12; i++) { + strcat(ret, " "); + strcat(ret, edge_string[ep[i]]); + strcat(ret, " "); + } + strcat(ret, "\n"); + for (int i = 0; i < 12; i++) { + strcat(ret, " "); + char num[2] = { [0] = eo[i] + '0', [1] = 0 }; + strcat(ret, num); + strcat(ret, " "); + } + strcat(ret, "\n"); + for (int i = 0; i < 8; i++) { + strcat(ret, corner_string[cp[i]]); + strcat(ret, " "); + } + strcat(ret, "\n"); + for (int i = 0; i < 8; i++) { + strcat(ret, " "); + char num[2] = { [0] = co[i] + '0', [1] = 0 }; + strcat(ret, num); + strcat(ret, " "); + } + strcat(ret, "\n"); + for (int i = 0; i < 6; i++) { + strcat(ret, " "); + strcat(ret, center_string[cenpos[i]]); + strcat(ret, " "); + } + strcat(ret, "\n"); + + return ret; +} + +void init_ttables() { + FILE *ttf; + + if ((ttf = fopen("ttables", "rb")) != NULL) { + for (int m = 0; m < NMOVES; m++) { + fread(epose_ttable[m], sizeof(int), factorial12/factorial8, ttf); + fread(eposs_ttable[m], sizeof(int), factorial12/factorial8, ttf); + fread(eposm_ttable[m], sizeof(int), factorial12/factorial8, ttf); + fread(eofb_ttable[m], sizeof(int), pow2to11, ttf); + fread(eorl_ttable[m], sizeof(int), pow2to11, ttf); + fread(eoud_ttable[m], sizeof(int), pow2to11, ttf); + fread(cp_ttable[m], sizeof(int), factorial8, ttf); + fread(coud_ttable[m], sizeof(int), pow3to7, ttf); + fread(corl_ttable[m], sizeof(int), pow3to7, ttf); + fread(cofb_ttable[m], sizeof(int), pow3to7, ttf); + fread(centerpos_ttable[m], sizeof(int), factorial6, ttf); + } + fclose(ttf); + } else { + ttf = fopen("ttables", "wb"); + int empty[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; + /* For each type of pieces only the effects of U, x and y are described */ + 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}, + }; + int eofb_flipped[NMOVES][12] = { + [X] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 }, + [Y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 }, + }; + 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 }, + }; + 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 }, + }; + 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}, + }; + int coud_flipped[NMOVES][8] = { + [X] = {[UFR]=2,[UBR]=1,[DBR]=2,[DFR]=1,[UFL]=1,[UBL]=2,[DBL]=1,[DFL]=2}, + }; + 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}, + }; + int cofb_flipped[NMOVES][8] = { + [U] = { [UFR] = 2, [UBR] = 1, [UBL] = 2, [UFL] = 1 }, + [X] = {[UFR]=1,[UBR]=2,[DFR]=2,[DBR]=1,[UBL]=2,[UFL]=1,[DBL]=1,[DFL]=2}, + [Y] = {[UFR]=2,[UBR]=1,[UBL]=2,[UFL]=1,[DFR]=1,[DBR]=2,[DBL]=1,[DFL]=2}, + }; + 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}, + }; + + /* Each move is reduced to a combination of U, x and y using this table */ + Move equiv_moves[NMOVES][13] = { + [U] = { U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [U2] = { U, U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [U3] = { U, U, U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [D] = { X, X, U, X, X, 0, 0, 0, 0, 0, 0, 0, 0 }, + [D2] = { X, X, U, U, X, X, 0, 0, 0, 0, 0, 0, 0 }, + [D3] = { X, X, U, U, U, X, X, 0, 0, 0, 0, 0, 0 }, + [R] = { Y, X, U, X, X, X, Y, Y, Y, 0, 0, 0, 0 }, + [R2] = { Y, X, U, U, X, X, X, Y, Y, Y, 0, 0, 0 }, + [R3] = { Y, X, U, U, U, X, X, X, Y, Y, Y, 0, 0 }, + [L] = { Y, Y, Y, X, U, X, X, X, Y, 0, 0, 0, 0 }, + [L2] = { Y, Y, Y, X, U, U, X, X, X, Y, 0, 0, 0 }, + [L3] = { Y, Y, Y, X, U, U, U, X, X, X, Y, 0, 0 }, + [F] = { X, U, X, X, X, 0, 0, 0, 0, 0, 0, 0, 0 }, + [F2] = { X, U, U, X, X, X, 0, 0, 0, 0, 0, 0, 0 }, + [F3] = { X, U, U, U, X, X, X, 0, 0, 0, 0, 0, 0 }, + [B] = { X, X, X, U, X, 0, 0, 0, 0, 0, 0, 0, 0 }, + [B2] = { X, X, X, U, U, X, 0, 0, 0, 0, 0, 0, 0 }, + [B3] = { X, X, X, U, U, U, X, 0, 0, 0, 0, 0, 0 }, + + [Uw] = { X, X, U, X, X, Y, 0, 0, 0, 0, 0, 0, 0 }, + [Uw2] = { X, X, U, U, X, X, Y, Y, 0, 0, 0, 0, 0 }, + [Uw3] = { X, X, U, U, U, X, X, Y, Y, Y, 0, 0, 0 }, + [Dw] = { U, Y, Y, Y, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Dw2] = { U, U, Y, Y, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Dw3] = { U, U, U, Y, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Rw] = { Y, Y, Y, X, U, X, X, X, Y, X, 0, 0, 0 }, + [Rw2] = { Y, Y, Y, X, U, U, X, X, X, Y, X, X, 0 }, + [Rw3] = { Y, Y, Y, X, U, U, U, Y, X, X, X, Y, 0 }, + [Lw] = { Y, X, U, X, X, X, Y, Y, Y, X, X, X, 0 }, + [Lw2] = { Y, X, U, U, X, X, X, Y, Y, Y, X, X, 0 }, + [Lw3] = { Y, X, U, U, U, X, X, X, Y, Y, Y, X, 0 }, + [Fw] = { X, X, X, U, Y, Y, Y, X, 0, 0, 0, 0, 0 }, + [Fw2] = { X, X, X, U, U, Y, Y, X, 0, 0, 0, 0, 0 }, + [Fw3] = { X, X, X, U, U, U, Y, X, 0, 0, 0, 0, 0 }, + [Bw] = { X, U, Y, Y, Y, X, X, X, 0, 0, 0, 0, 0 }, + [Bw2] = { X, U, U, Y, Y, X, X, X, 0, 0, 0, 0, 0 }, + [Bw3] = { X, U, U, U, Y, X, X, X, 0, 0, 0, 0, 0 }, + + [M] = { Y, X, U, X, X, U, U, U, Y, X, Y, Y, Y }, + [M2] = { Y, X, U, U, X, X, U, U, X, X, X, Y, 0 }, + [M3] = { Y, X, U, U, U, X, X, U, Y, X, X, X, Y }, + [S] = { X, U, U, U, X, X, U, Y, Y, Y, X, 0, 0 }, + [S2] = { X, U, U, X, X, U, U, Y, Y, X, 0, 0, 0 }, + [S3] = { X, U, X, X, U, U, U, Y, X, 0, 0, 0, 0 }, + [E] = { U, X, X, U, U, U, X, X, Y, Y, Y, 0, 0 }, + [E2] = { U, U, X, X, U, U, X, X, Y, Y, 0, 0, 0 }, + [E3] = { U, U, U, X, X, U, X, X, Y, 0, 0, 0, 0 }, + + [X] = { X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [X2] = { X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [X3] = { X, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Y] = { Y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Y2] = { Y, Y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Y3] = { Y, Y, Y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Z] = { Y, Y, Y, X, Y, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Z2] = { Y, Y, X, X, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Z3] = { Y, X, Y, Y, Y, 0, 0, 0, 0, 0, 0, 0, 0 }, + }; + + /* Generate all move cycles and flips */ + for (int i = 0; i < NMOVES; i++) { + if (i == U || i == X || i == Y) + continue; + + Cube cube = {0}; + + cube_to_ep_array(&cube, edge_cycle[i]); + cube_to_eofb_array(&cube, eofb_flipped[i]); + cube_to_eorl_array(&cube, eorl_flipped[i]); + cube_to_eoud_array(&cube, eoud_flipped[i]); + cube_to_cp_array(&cube, corner_cycle[i]); + cube_to_coud_array(&cube, coud_flipped[i]); + cube_to_cofb_array(&cube, cofb_flipped[i]); + cube_to_corl_array(&cube, corl_flipped[i]); + cube_to_centerpos_array(&cube, center_cycle[i]); + + for (int j = 0; equiv_moves[i][j]; j++) { + int m = equiv_moves[i][j]; + + apply_permutation(edge_cycle[m], edge_cycle[i], 12); + apply_permutation(edge_cycle[m], eofb_flipped[i], 12); + apply_permutation(edge_cycle[m], eorl_flipped[i], 12); + apply_permutation(edge_cycle[m], eoud_flipped[i], 12); + + sum_arrays_mod(eofb_flipped[i], eofb_flipped[m], 12, 2); + sum_arrays_mod(eorl_flipped[i], eorl_flipped[m], 12, 2); + sum_arrays_mod(eoud_flipped[i], eoud_flipped[m], 12, 2); + + apply_permutation(corner_cycle[m], corner_cycle[i], 8); + apply_permutation(corner_cycle[m], coud_flipped[i], 8); + apply_permutation(corner_cycle[m], cofb_flipped[i], 8); + apply_permutation(corner_cycle[m], corl_flipped[i], 8); + + sum_arrays_mod(coud_flipped[i], coud_flipped[m], 8, 3); + sum_arrays_mod(corl_flipped[i], corl_flipped[m], 8, 3); + sum_arrays_mod(cofb_flipped[i], cofb_flipped[m], 8, 3); + + apply_permutation(center_cycle[m], center_cycle[i], 6); + } + } + + /* Initialize transition tables */ + for (int m = 0; m < NMOVES; m++) { + for (int i = 0; i < factorial12/factorial8; i++) { + Cube cube = { .epose = i }; + move_array(&cube, cube_to_ep_array, ep_array_to_cube, + edge_cycle[m], empty, 12, 1); + epose_ttable[m][i] = cube.epose; + cube.eposs = i; + move_array(&cube, cube_to_ep_array, ep_array_to_cube, + edge_cycle[m], empty, 12, 1); + eposs_ttable[m][i] = cube.eposs; + cube.eposm = i; + move_array(&cube, cube_to_ep_array, ep_array_to_cube, + edge_cycle[m], empty, 12, 1); + eposm_ttable[m][i] = cube.eposm; + } + for (int i = 0; i < pow2to11; i++ ) { + Cube cube = { .eofb = i, .eorl = i, .eoud = i }; + move_array(&cube, cube_to_eofb_array, eofb_array_to_cube, + edge_cycle[m], eofb_flipped[m], 12, 2); + move_array(&cube, cube_to_eorl_array, eorl_array_to_cube, + edge_cycle[m], eorl_flipped[m], 12, 2); + move_array(&cube, cube_to_eoud_array, eoud_array_to_cube, + edge_cycle[m], eoud_flipped[m], 12, 2); + eofb_ttable[m][i] = cube.eofb; + eorl_ttable[m][i] = cube.eorl; + eoud_ttable[m][i] = cube.eoud; + } + for (int i = 0; i < factorial8; i++) { + /* TODO: Maybe do this by hand to optimize? */ + Cube cube = { .cp = i }; + move_array(&cube, cube_to_cp_array, ep_array_to_cube, + corner_cycle[m], empty, 8, 1); + cp_ttable[m][i] = cube.cp; + } + for (int i = 0; i < pow3to7; i++) { + Cube cube = { .coud = i, .corl = i, .cofb = i }; + move_array(&cube, cube_to_coud_array, coud_array_to_cube, + corner_cycle[m], coud_flipped[m], 8, 3); + move_array(&cube, cube_to_corl_array, corl_array_to_cube, + corner_cycle[m], corl_flipped[m], 8, 3); + move_array(&cube, cube_to_cofb_array, cofb_array_to_cube, + corner_cycle[m], cofb_flipped[m], 8, 3); + coud_ttable[m][i] = cube.coud; + corl_ttable[m][i] = cube.corl; + cofb_ttable[m][i] = cube.cofb; + } + for (int i = 0; i < factorial6; i++) { + Cube cube = { .centerpos = i }; + move_array(&cube, cube_to_centerpos_array, centerpos_array_to_cube, + center_cycle[m], empty, 6, 1); + centerpos_ttable[m][i] = cube.centerpos; + } + fwrite(epose_ttable[m], sizeof(int), factorial12/factorial8, ttf); + fwrite(eposs_ttable[m], sizeof(int), factorial12/factorial8, ttf); + fwrite(eposm_ttable[m], sizeof(int), factorial12/factorial8, ttf); + fwrite(eofb_ttable[m], sizeof(int), pow2to11, ttf); + fwrite(eorl_ttable[m], sizeof(int), pow2to11, ttf); + fwrite(eoud_ttable[m], sizeof(int), pow2to11, ttf); + fwrite(cp_ttable[m], sizeof(int), factorial8, ttf); + fwrite(coud_ttable[m], sizeof(int), pow3to7, ttf); + fwrite(corl_ttable[m], sizeof(int), pow3to7, ttf); + fwrite(cofb_ttable[m], sizeof(int), pow3to7, ttf); + fwrite(centerpos_ttable[m], sizeof(int), factorial6, ttf); + } + fclose(ttf); + } +} + +Cube apply_move(Move m, Cube cube) { + Cube moved = cube; + + moved.eofb = eofb_ttable[m][cube.eofb]; + moved.eorl = eorl_ttable[m][cube.eorl]; + moved.eoud = eoud_ttable[m][cube.eoud]; + moved.coud = coud_ttable[m][cube.coud]; + moved.cofb = cofb_ttable[m][cube.cofb]; + moved.corl = corl_ttable[m][cube.corl]; + moved.epose = epose_ttable[m][cube.epose]; + moved.eposs = eposs_ttable[m][cube.eposs]; + moved.eposm = eposm_ttable[m][cube.eposm]; + moved.cp = cp_ttable[m][cube.cp]; + moved.centerpos = centerpos_ttable[m][cube.centerpos]; + + return moved; +} diff --git a/old/2020-unknown-date/cubeutils.c b/old/2020-unknown-date/cubeutils.c new file mode 100644 index 0000000..4f0a060 --- /dev/null +++ b/old/2020-unknown-date/cubeutils.c @@ -0,0 +1,100 @@ +#include +#include "utils.h" +#include "pieces.h" +#include "cubeutils.h" + +int epe_solved[] = {FR, FL, BL, BR}; +int eps_solved[] = {UL, UR, DL, DR}; +int epm_solved[] = {UF, UB, DF, DB}; + +void cube_to_ep_array(Cube *cube, int ep[12]) { + int epe[4], eps[4], epm[4]; + index_to_perm(cube->epose % factorial(4), 4, epe); + index_to_perm(cube->eposs % factorial(4), 4, eps); + index_to_perm(cube->eposm % factorial(4), 4, epm); + + int epose[12], eposs[12], eposm[12]; + index_to_subset(cube->epose / factorial(4), 12, 4, epose); + index_to_subset(cube->eposs / factorial(4), 12, 4, eposs); + index_to_subset(cube->eposm / factorial(4), 12, 4, eposm); + for (int i = 0; i < 4; i++) { + swap(&eposs[eps_solved[i]], &eposs[i+8]); + swap(&eposm[epm_solved[i]], &eposm[i+8]); + } + + for (int i = 0, ie = 0, is = 0, im = 0; i < 12; i++) { + if (epose[i]) ep[i] = epe_solved[epe[ie++]]; + if (eposs[i]) ep[i] = eps_solved[eps[is++]]; + if (eposm[i]) ep[i] = epm_solved[epm[im++]]; + } +} + +void ep_array_to_epos(int ep[12], Cube *cube) { + int epe[4], eps[4], epm[4]; + int epose[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + int eposs[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + int eposm[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + for (int i = 0, ie = 0, is = 0, im = 0; i < 12; i++) { + for (int j = 0; j < 4; j++) { + if (ep[i] == epe_solved[j]) { epe[ie++] = j; epose[i] = 1; } + if (ep[i] == eps_solved[j]) { eps[is++] = j; eposs[i] = 1; } + if (ep[i] == epm_solved[j]) { epm[im++] = j; eposm[i] = 1; } + } + } + for (int i = 0; i < 4; i++) { + swap(&eposs[eps_solved[i]], &eposs[i+8]); + swap(&eposm[epm_solved[i]], &eposm[i+8]); + } + cube->epose = factorial(4) * subset_to_index(epose, 12, 4) + + perm_to_index(epe, 4); + cube->eposs = factorial(4) * subset_to_index(eposs, 12, 4) + + perm_to_index(eps, 4); + cube->eposm = factorial(4) * subset_to_index(eposm, 12, 4) + + perm_to_index(epm, 4); +} + +bool solvable(Cube *cube) { + /* Since we memorize orientation truncating the last digit, we only need to + * check that the permutations have the correct sign. */ + /* TODO: add check that every integer is in range */ + int ep[12], cp[12], c[6]; + cube_to_ep_array(cube, ep); + index_to_perm(cube->cp, 8, cp); + index_to_perm(cube->centerpos, 6, c); + return (perm_sign(ep, 12) ^ perm_sign(c, 6)) == perm_sign(cp, 8); +} + +Cube *solved_cube() { + static Cube cube = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + return &cube; +} + +bool solved(Cube *cube) { + return (cube->eofb == 0 && cube->coud == 0 && cube->cp == 0 && + cube->epose == 0 && cube->eposs == 0 && cube->eposm == 0 && + cube->centerpos == 0); +} + +char *to_string(Cube *cube) { + int eo[12], co[8], ep[12], cp[8], cenpos[6]; + cube_to_eofb_array(cube->eofb, eo); + cube_to_coud_array(cube->coud, co); + cube_to_ep_array(cube, ep); + cube_to_cp_array(cube->cp, cp); + cube_to_centerpos_array(cube->centerpos, cenpos); + + char *ret[1000]; + + for (int i = 0; i < 12; i++) sprintf(ret, " %s ", edge_string[ep[i]]); + sprintf(ret, "\n"); + for (int i = 0; i < 12; i++) sprintf(ret, " %d ", eo[i]); + sprintf(ret, "\n"); + for (int i = 0; i < 8; i++) sprintf(ret, "%s ", corner_string[cp[i]]); + sprintf(ret, "\n"); + for (int i = 0; i < 8; i++) sprintf(ret, " %d ", co[i]); + sprintf(ret, "\n"); + for (int i = 0; i < 6; i++) sprintf(ret, " %s ", center_string[cenpos[i]]); + sprintf(ret, "\n"); + + return ret; +} diff --git a/old/2020-unknown-date/cubeutils.h b/old/2020-unknown-date/cubeutils.h new file mode 100644 index 0000000..b24291c --- /dev/null +++ b/old/2020-unknown-date/cubeutils.h @@ -0,0 +1,18 @@ +/* Cube-specific utility functions */ + +#ifndef CUBEUTILS_H +#define CUBEUTILS_H + +#include +#include "pieces.h" + +void cube_to_ep_array(Cube *cube, int ep[12]); +void ep_array_to_epos(int ep[12], Cube *cube); + +Cube *solved_cube(); +bool solvable(Cube *cube); +bool solved(Cube *cube); + +void print(Cube *cube); + +#endif diff --git a/old/2020-unknown-date/moves.c b/old/2020-unknown-date/moves.c new file mode 100644 index 0000000..de293ed --- /dev/null +++ b/old/2020-unknown-date/moves.c @@ -0,0 +1,57 @@ +#include +#include "pieces.h" +#include "moves.h" +#include "utils.h" + +/* Transition tables */ +int eofb_ttable[pow2to11][NULLMOVE]; +int eorl_ttable[pow2to11][NULLMOVE]; +int eoud_ttable[pow2to11][NULLMOVE]; +int coud_ttable[pow3to7][NULLMOVE]; +int cofb_ttable[pow3to7][NULLMOVE]; +int corl_ttable[pow3to7][NULLMOVE]; +int epose_ttable[factorial12/factorial8][NULLMOVE]; +int eposs_ttable[factorial12/factorial8][NULLMOVE]; +int eposm_ttable[factorial12/factorial8][NULLMOVE]; +int cp_ttable[factorial8][NULLMOVE]; +int centerpos_ttable[factorial6][NULLMOVE]; + +void apply_move_ep(Move m, int a[12]) { + int aux[12]; + intarrcopy(a, aux, 12); + for (int i = 0; i < 12; i++) + a[i] = aux[edge_cycle[m][i]]; +} + +void apply_move_cp(Move m, int a[8]) { + int aux[8]; + intarrcopy(a, aux, 8); + for (int i = 0; i < 8; i++) + a[i] = aux[corner_cycle[m][i]]; +} + +void apply_move_centerpos(Move m, int a[6]) { + int aux[6]; + intarrcopy(a, aux, 6); + for (int i = 0; i < 6; i++) + a[i] = aux[center_cycle[m][i]]; +} + +void init_ttables() { + /* TODO */ +} + +void apply_move(Move m, Cube *cube) { + cube->eofb = eofb_ttable[cube->eofb][m]; + cube->eorl = eorl_ttable[cube->eorl][m]; + cube->eoud = eoud_ttable[cube->eoud][m]; + cube->coud = coud_ttable[cube->coud][m]; + cube->cofb = cofb_ttable[cube->cofb][m]; + cube->corl = corl_ttable[cube->corl][m]; + cube->epose = epose_ttable[cube->epose][m]; + cube->eposs = eposs_ttable[cube->eposs][m]; + cube->eposm = eposm_ttable[cube->eposm][m]; + cube->cp = cp_ttable[cube->cp][m]; + cube->centerpos = centerpos_ttable[cube->centerpos][m]; +} + diff --git a/old/2020-unknown-date/moves.h b/old/2020-unknown-date/moves.h new file mode 100644 index 0000000..605f335 --- /dev/null +++ b/old/2020-unknown-date/moves.h @@ -0,0 +1,9 @@ +/* Moves and transition tables */ + +#ifndef MOVES_H +#define MOVES_H + +void apply_move(Move m, Cube *cube); +void init_ttables(); + +#endif diff --git a/old/2020-unknown-date/pieces.c b/old/2020-unknown-date/pieces.c new file mode 100644 index 0000000..d782c89 --- /dev/null +++ b/old/2020-unknown-date/pieces.c @@ -0,0 +1,208 @@ +#include "pieces.h" + +char edge_string[12][5] = { + "UF", "UL", "UB", "UR", "DF", "DL", "DB", "DR", "FR", "FL", "BL", "BR" +}; + +char corner_string[8][5] = { + "UFR", "UFL", "UBL", "UBR", "DFR", "DFL", "DBL", "DBR" +}; + +char center_string[6][5] = { "U", "D", "R", "L", "F", "B" }; + +char move_string[NULLMOVE+1][5] = { + "U", "U2", "U\'", "D", "D2", "D\'", "R", "R2", "R\'", + "L", "L2", "L\'", "F", "F2", "F\'", "B", "B2", "B\'", + "Uw", "Uw2", "Uw\'", "Dw", "Dw2", "Dw\'", "Rw", "Rw2", "Rw\'", + "Lw", "Lw2", "Lw\'", "Fw", "Fw2", "Fw\'", "Bw", "Bw2", "Bw\'", + "M", "M2", "M\'", "S", "S2", "S\'", "E", "E2", "E\'", + "x", "x2", "x\'", "y", "y2", "y\'", "z", "z2", "z\'", + "-" +}; + +int edge_cycle[NULLMOVE+1][12] = { + [U] = {UR, UF, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR}, + [U2] = {UB, UR, UF, UL, DF, DL, DB, DR, FR, FL, BL, BR}, + [U3] = {UL, UB, UR, UF, DF, DL, DB, DR, FR, FL, BL, BR}, + [D] = {UF, UL, UB, UR, DL, DB, DR, DF, FR, FL, BL, BR}, + [D2] = {UF, UL, UB, UR, DB, DR, DF, DL, FR, FL, BL, BR}, + [D3] = {UF, UL, UB, UR, DR, DF, DL, DB, FR, FL, BL, BR}, + [R] = {UF, UL, UB, FR, DF, DL, DB, BR, DR, FL, BL, UR}, + [R2] = {UF, UL, UB, DR, DF, DL, DB, UR, BR, FL, BL, FR}, + [R3] = {UF, UL, UB, BR, DF, DL, DB, FR, UR, FL, BL, DR}, + [L] = {UF, BL, UB, UR, DF, FL, DB, DR, FR, UL, DL, BR}, + [L2] = {UF, DL, UB, UR, DF, UL, DB, DR, FR, BL, FL, BR}, + [L3] = {UF, FL, UB, UR, DF, BL, DB, DR, FR, DL, UL, BR}, + [F] = {FL, UL, UB, UR, FR, DL, DB, DR, UF, DF, BL, BR}, + [F2] = {DF, UL, UB, UR, UF, DL, DB, DR, FL, FR, BL, BR}, + [F3] = {FR, UL, UB, UR, FL, DL, DB, DR, DF, UF, BL, BR}, + [B] = {UF, UL, BR, UR, DF, DL, BL, DR, FR, FL, UB, DB}, + [B2] = {UF, UL, DB, UR, DF, DL, UB, DR, FR, FL, BR, BL}, + [B3] = {UF, UL, BL, UR, DF, DL, BR, DR, FR, FL, DB, UB}, + + [Uw] = {UR, UF, UL, UB, DF, DL, DB, DR, BR, FR, FL, BL}, + [Uw2] = {UB, UR, UF, UL, DF, DL, DB, DR, BL, BR, FR, FL}, + [Uw3] = {UL, UB, UR, UF, DF, DL, DB, DR, FL, BL, BR, FR}, + [Dw] = {UF, UL, UB, UR, DL, DB, DR, DF, FL, BL, BR, FR}, + [Dw2] = {UF, UL, UB, UR, DB, DR, DF, DL, BL, BR, FR, FL}, + [Dw3] = {UF, UL, UB, UR, DR, DF, DL, DB, BR, FR, FL, BL}, + [Rw] = {DF, UL, UF, FR, DB, DL, UB, BR, DR, FL, BL, UR}, + [Rw2] = {DB, UL, DF, DR, UB, DL, UF, UR, BR, FL, BL, FR}, + [Rw3] = {UB, UL, DB, BR, UF, DL, DF, FR, UR, FL, BL, DR}, + [Lw] = {UB, BL, DB, UR, UF, FL, DF, DR, FR, UL, DL, BR}, + [Lw2] = {DB, DL, DF, UR, UB, UL, UF, DR, FR, BL, FL, BR}, + [Lw3] = {DF, FL, UF, UR, DB, BL, UB, DR, FR, DL, UL, BR}, + [Fw] = {FL, DL, UB, UL, FR, DR, DB, UR, UF, DF, BL, BR}, + [Fw2] = {DF, DR, UB, DL, UF, UR, DB, UL, FL, FR, BL, BR}, + [Fw3] = {FR, UR, UB, DR, FL, UL, DB, DL, DF, UF, BL, BR}, + [Bw] = {UF, UR, BR, DR, DF, UL, BL, DL, FR, FL, UB, DB}, + [Bw2] = {UF, DR, DB, DL, DF, UR, UB, UL, FR, FL, BR, BL}, + [Bw3] = {UF, DL, BL, UL, DF, DR, BR, UR, FR, FL, DB, UB}, + + [M] = {UB, UL, DB, UR, UF, DL, DF, DR, FR, FL, BL, BR}, + [M2] = {DB, UL, DF, UR, UB, DL, UF, DR, FR, FL, BL, BR}, + [M3] = {DF, UL, UF, UR, DB, DL, UB, DR, FR, FL, BL, BR}, + [S] = {UF, DL, UB, UL, DF, DR, DB, UR, FR, FL, BL, BR}, + [S2] = {UF, DR, UB, DL, DF, UR, DB, UL, FR, FL, BL, BR}, + [S3] = {UF, UR, UB, DR, DF, UL, DB, DL, FR, FL, BL, BR}, + [E] = {UF, UL, UB, UR, DF, DL, DB, DR, FL, BL, BR, FR}, + [E2] = {UF, UL, UB, UR, DF, DL, DB, DR, BL, BR, FR, FL}, + [E3] = {UF, UL, UB, UR, DF, DL, DB, DR, BR, FR, FL, BL}, + + [X] = {DF, FL, UF, FR, DB, BL, UB, BR, DR, DL, UL, UR}, + [X2] = {DB, DL, DF, DR, UB, UL, UF, UR, BR, BL, FL, FR}, + [X3] = {UB, BL, DB, BR, UF, FL, DF, FR, UR, UL, DL, DR}, + [Y] = {UR, UF, UL, UB, DR, DF, DL, DB, BR, FR, FL, BL}, + [Y2] = {UB, UR, UF, UL, DB, DR, DF, DL, BL, BR, FR, FL}, + [Y3] = {UL, UB, UR, UF, DL, DB, DR, DF, FL, BL, BR, FR}, + [Z] = {FL, DL, BL, UL, FR, DR, BR, UR, UF, DF, DB, UB}, + [Z2] = {DF, DR, DB, DL, UF, UR, UB, UL, FL, FR, BR, BL}, + [Z3] = {FR, UR, BR, DR, FL, UL, BL, DL, DF, UF, UB, DB}, + + [NULLMOVE] = {UF, UL, UB, UR, DF, DL, DB, DR, FR, FL, BL, BR}, +}; + +int corner_cycle[NULLMOVE+1][8] = { + [U] = {UBR, UFR, UFL, UBL, DFR, DFL, DBL, DBR}, + [U2] = {UBL, UBR, UFR, UFL, DFR, DFL, DBL, DBR}, + [U3] = {UFL, UBL, UBR, UFR, DFR, DFL, DBL, DBR}, + [D] = {UFR, UFL, UBL, UBR, DFL, DBL, DBR, DFR}, + [D2] = {UFR, UFL, UBL, UBR, DBL, DBR, DFR, DFL}, + [D3] = {UFR, UFL, UBL, UBR, DBR, DFR, DFL, DBL}, + [R] = {DFR, UFL, UBL, UFR, DBR, DFL, DBL, UBR}, + [R2] = {DBR, UFL, UBL, DFR, UBR, DFL, DBL, UFR}, + [R3] = {UBR, UFL, UBL, DBR, UFR, DFL, DBL, DFR}, + [L] = {UFR, UBL, DBL, UBR, DFR, UFL, DFL, DBR}, + [L2] = {UFR, DBL, DFL, UBR, DFR, UBL, UFL, DBR}, + [L3] = {UFR, DFL, UFL, UBR, DFR, DBL, UBL, DBR}, + [F] = {UFL, DFL, UBL, UBR, UFR, DFR, DBL, DBR}, + [F2] = {DFL, DFR, UBL, UBR, UFL, UFR, DBL, DBR}, + [F3] = {DFR, UFR, UBL, UBR, DFL, UFL, DBL, DBR}, + [B] = {UFR, UFL, UBR, DBR, DFR, DFL, UBL, DBL}, + [B2] = {UFR, UFL, DBR, DBL, DFR, DFL, UBR, UBL}, + [B3] = {UFR, UFL, DBL, UBL, DFR, DFL, DBR, UBR}, + + [Uw] = {UBR, UFR, UFL, UBL, DFR, DFL, DBL, DBR}, + [Uw2] = {UBL, UBR, UFR, UFL, DFR, DFL, DBL, DBR}, + [Uw3] = {UFL, UBL, UBR, UFR, DFR, DFL, DBL, DBR}, + [Dw] = {UFR, UFL, UBL, UBR, DFL, DBL, DBR, DFR}, + [Dw2] = {UFR, UFL, UBL, UBR, DBL, DBR, DFR, DFL}, + [Dw3] = {UFR, UFL, UBL, UBR, DBR, DFR, DFL, DBL}, + [Rw] = {DFR, UFL, UBL, UFR, DBR, DFL, DBL, UBR}, + [Rw2] = {DBR, UFL, UBL, DFR, UBR, DFL, DBL, UFR}, + [Rw3] = {UBR, UFL, UBL, DBR, UFR, DFL, DBL, DFR}, + [Lw] = {UFR, UBL, DBL, UBR, DFR, UFL, DFL, DBR}, + [Lw2] = {UFR, DBL, DFL, UBR, DFR, UBL, UFL, DBR}, + [Lw3] = {UFR, DFL, UFL, UBR, DFR, DBL, UBL, DBR}, + [Fw] = {UFL, DFL, UBL, UBR, UFR, DFR, DBL, DBR}, + [Fw2] = {DFL, DFR, UBL, UBR, UFL, UFR, DBL, DBR}, + [Fw3] = {DFR, UFR, UBL, UBR, DFL, UFL, DBL, DBR}, + [Bw] = {UFR, UFL, UBR, DBR, DFR, DFL, UBL, DBL}, + [Bw2] = {UFR, UFL, DBR, DBL, DFR, DFL, UBR, UBL}, + [Bw3] = {UFR, UFL, DBL, UBL, DFR, DFL, DBR, UBR}, + + [M] = {UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR}, + [M2] = {UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR}, + [M3] = {UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR}, + [S] = {UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR}, + [S2] = {UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR}, + [S3] = {UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR}, + [E] = {UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR}, + [E2] = {UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR}, + [E3] = {UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR}, + + [X] = {DFR, DFL, UFL, UFR, DBR, DBL, UBL, UBR}, + [X2] = {DBR, DBL, DFL, DFR, UBR, UBL, UFL, UFR}, + [X3] = {UBR, UBL, DBL, DBR, UFR, UFL, DFL, DFR}, + [Y] = {UBR, UFR, UFL, UBL, DBR, DFR, DFL, DBL}, + [Y2] = {UBL, UBR, UFR, UFL, DBL, DBR, DFR, DFL}, + [Y3] = {UFL, UBL, UBR, UFR, DFL, DBL, DBR, DFR}, + [Z] = {UFL, DFL, DBL, UBL, UFR, DFR, DBR, UBR}, + [Z2] = {DFL, DFR, DBR, DBL, UFL, UFR, UBR, UBL}, + [Z3] = {DFR, UFR, UBR, DBR, DFL, UFL, UBL, DBL}, + + [NULLMOVE] = {UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR}, +}; + +int center_cycle[NULLMOVE+1][6] = { + [U] = {U_center, D_center, R_center, L_center, F_center, B_center}, + [U2] = {U_center, D_center, R_center, L_center, F_center, B_center}, + [U3] = {U_center, D_center, R_center, L_center, F_center, B_center}, + [D] = {U_center, D_center, R_center, L_center, F_center, B_center}, + [D2] = {U_center, D_center, R_center, L_center, F_center, B_center}, + [D3] = {U_center, D_center, R_center, L_center, F_center, B_center}, + [R] = {U_center, D_center, R_center, L_center, F_center, B_center}, + [R2] = {U_center, D_center, R_center, L_center, F_center, B_center}, + [R3] = {U_center, D_center, R_center, L_center, F_center, B_center}, + [L] = {U_center, D_center, R_center, L_center, F_center, B_center}, + [L2] = {U_center, D_center, R_center, L_center, F_center, B_center}, + [L3] = {U_center, D_center, R_center, L_center, F_center, B_center}, + [F] = {U_center, D_center, R_center, L_center, F_center, B_center}, + [F2] = {U_center, D_center, R_center, L_center, F_center, B_center}, + [F3] = {U_center, D_center, R_center, L_center, F_center, B_center}, + [B] = {U_center, D_center, R_center, L_center, F_center, B_center}, + [B2] = {U_center, D_center, R_center, L_center, F_center, B_center}, + [B3] = {U_center, D_center, R_center, L_center, F_center, B_center}, + + [Uw] = {U_center, D_center, B_center, F_center, R_center, L_center}, + [Uw2] = {U_center, D_center, L_center, R_center, B_center, F_center}, + [Uw3] = {U_center, D_center, F_center, B_center, L_center, R_center}, + [Dw] = {U_center, D_center, F_center, B_center, L_center, R_center}, + [Dw2] = {U_center, D_center, L_center, R_center, B_center, F_center}, + [Dw3] = {U_center, D_center, B_center, F_center, R_center, L_center}, + [Rw] = {F_center, B_center, R_center, L_center, D_center, U_center}, + [Rw2] = {D_center, U_center, R_center, L_center, B_center, F_center}, + [Rw3] = {B_center, F_center, R_center, L_center, U_center, D_center}, + [Lw] = {B_center, F_center, R_center, L_center, U_center, D_center}, + [Lw2] = {D_center, U_center, R_center, L_center, B_center, F_center}, + [Lw3] = {F_center, B_center, R_center, L_center, D_center, U_center}, + [Fw] = {L_center, R_center, U_center, D_center, F_center, B_center}, + [Fw2] = {D_center, U_center, L_center, R_center, F_center, B_center}, + [Fw3] = {R_center, L_center, D_center, U_center, F_center, B_center}, + [Bw] = {R_center, L_center, D_center, U_center, F_center, B_center}, + [Bw2] = {D_center, U_center, L_center, R_center, F_center, B_center}, + [Bw3] = {L_center, R_center, U_center, D_center, F_center, B_center}, + + [X] = {F_center, B_center, R_center, L_center, D_center, U_center}, + [X2] = {D_center, U_center, R_center, L_center, B_center, F_center}, + [X3] = {B_center, F_center, R_center, L_center, U_center, D_center}, + [Y] = {U_center, D_center, B_center, F_center, R_center, L_center}, + [Y2] = {U_center, D_center, L_center, R_center, B_center, F_center}, + [Y3] = {U_center, D_center, F_center, B_center, L_center, R_center}, + [Z] = {L_center, R_center, U_center, D_center, F_center, B_center}, + [Z2] = {D_center, U_center, L_center, R_center, F_center, B_center}, + [Z3] = {R_center, L_center, D_center, U_center, F_center, B_center}, + + [M] = {B_center, F_center, R_center, L_center, U_center, D_center}, + [M2] = {D_center, U_center, R_center, L_center, B_center, F_center}, + [M3] = {F_center, B_center, R_center, L_center, D_center, U_center}, + [E] = {U_center, D_center, F_center, B_center, L_center, R_center}, + [E2] = {U_center, D_center, L_center, R_center, B_center, F_center}, + [E3] = {U_center, D_center, B_center, F_center, R_center, L_center}, + [S] = {L_center, R_center, U_center, D_center, F_center, B_center}, + [S2] = {D_center, U_center, L_center, R_center, F_center, B_center}, + [S3] = {R_center, L_center, D_center, U_center, F_center, B_center}, + + [NULLMOVE] = {U_center, D_center, R_center, L_center, F_center, B_center}, +}; + diff --git a/old/2020-unknown-date/pieces.h b/old/2020-unknown-date/pieces.h new file mode 100644 index 0000000..dbdd740 --- /dev/null +++ b/old/2020-unknown-date/pieces.h @@ -0,0 +1,59 @@ +/* Moves and other things */ + +#ifndef PIECES_H +#define PIECES_H + +typedef enum { + U, U2, U3, D, D2, D3, R, R2, R3, L, L2, L3, F, F2, F3, B, B2, B3, + Uw, Uw2, Uw3, Dw, Dw2, Dw3, Rw, Rw2, Rw3, + Lw, Lw2, Lw3, Fw, Fw2, Fw3, Bw, Bw2, Bw3, + M, M2, M3, S, S2, S3, E, E2, E3, + X, X2, X3, Y, Y2, Y3, Z, Z2, Z3, + NULLMOVE +} Move; +typedef enum { + U_center, D_center, R_center, L_center, F_center, B_center +} Center; +typedef enum { UF, UL, UB, UR, DF, DL, DB, DR, FR, FL, BL, BR } Edge; +typedef enum { UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR } Corner; + +/* Arrays for strings of pieces and moves */ +extern char edge_string[12][5]; +extern char corner_string[8][5]; +extern char center_string[6][5]; +extern char move_string[NULLMOVE+1][5]; + +/* Three big arrays that determine the movement of edges, corners and + * centers for some of the basic moves. Yes, one can be much more elegant and + * write much fewer lines. But then things get less elegant somewhere else. */ +extern int edge_cycle[NULLMOVE+1][12]; +extern int corner_cycle[NULLMOVE+1][8]; +extern int center_cycle[NULLMOVE+1][6]; + +/* Representation of the cube */ +typedef struct { + /* Edge orientation */ + int eofb; + int eorl; + int eoud; + + /* Corner orientation */ + int coud; + int cofb; + int corl; + + /* Position of M/E/S slice edges */ + /* TODO: keep in mind that the 4! positions with edges in correct slice + * must be the first 4! indeces */ + int epose; + int eposs; + int eposm; + + /* Permutation of corners */ + int cp; + + /* Position of centers */ + int centerpos; +} Cube; + +#endif diff --git a/old/2021-02-06/cube.c b/old/2021-02-06/cube.c new file mode 100644 index 0000000..9185281 --- /dev/null +++ b/old/2021-02-06/cube.c @@ -0,0 +1,664 @@ +#include "cube.h" + +typedef struct { + int ep[12], eofb[12], eorl[12], eoud[12], + cp[8], coud[8], corl[8], cofb[8], cpos[6]; +} CubeArray; + +typedef struct { + bool epose, eposs, eposm, eofb, eorl, eoud, cp, coud, cofb, corl, cpos; +} PieceFilter; + +PieceFilter fAll = {true,true,true,true,true,true,true,true,true,true,true}; +PieceFilter cpos_only = { .cpos = true }; + +void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f); +Cube arrays_to_cube(CubeArray arr, PieceFilter f); +void move_cubearray(Move m, CubeArray *arr, PieceFilter f); +Cube move_via_array(Move m, Cube cube, PieceFilter f); +void sort_cancel_rotate(NissMove *alg, int n, bool inv, int top, int front); +bool read_ttables_file(); +bool write_ttables_file(); + +/* Transition tables */ +uint16_t epose_ttable[NMOVES][factorial12/factorial8]; +uint16_t eposs_ttable[NMOVES][factorial12/factorial8]; +uint16_t eposm_ttable[NMOVES][factorial12/factorial8]; +uint16_t eofb_ttable[NMOVES][pow2to11]; +uint16_t eorl_ttable[NMOVES][pow2to11]; +uint16_t eoud_ttable[NMOVES][pow2to11]; +uint16_t cp_ttable[NMOVES][factorial8]; +uint16_t coud_ttable[NMOVES][pow3to7]; +uint16_t cofb_ttable[NMOVES][pow3to7]; +uint16_t corl_ttable[NMOVES][pow3to7]; +uint16_t cpos_ttable[NMOVES][factorial6]; + +bool commute[NMOVES][NMOVES]; +bool possible_next[NMOVES][NMOVES][NMOVES]; +Move inverse[NMOVES]; + +char edge_string[12][5] = + { "UF", "UL", "UB", "UR", "DF", "DL", "DB", "DR", "FR", "FL", "BL", "BR" }; +char corner_string[8][5] = { "UFR","UFL","UBL","UBR","DFR","DFL","DBL","DBR" }; +char center_string[6][5] = { "U", "D", "R", "L", "F", "B" }; +char move_string[NMOVES][5] = + { "-", + "U", "U2", "U\'", "D", "D2", "D\'", "R", "R2", "R\'", + "L", "L2", "L\'", "F", "F2", "F\'", "B", "B2", "B\'", + "Uw", "Uw2", "Uw\'", "Dw", "Dw2", "Dw\'", "Rw", "Rw2", "Rw\'", + "Lw", "Lw2", "Lw\'", "Fw", "Fw2", "Fw\'", "Bw", "Bw2", "Bw\'", + "M", "M2", "M\'", "S", "S2", "S\'", "E", "E2", "E\'", + "x", "x2", "x\'", "y", "y2", "y\'", "z", "z2", "z\'" }; + +/* For each type of pieces only the effects of U, x and y are described */ +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} }; +int eofb_flipped[NMOVES][12] = + { [x] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 }, + [y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 } }; +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 } }; +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 } }; +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} }; +int coud_flipped[NMOVES][8] = + { [x] = {[UFR]=2,[UBR]=1,[DBR]=2,[DFR]=1,[UFL]=1,[UBL]=2,[DBL]=1,[DFL]=2} }; +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} }; +int cofb_flipped[NMOVES][8] = + { [U] = { [UFR] = 2, [UBR] = 1, [UBL] = 2, [UFL] = 1 }, + [x] = {[UFR]=1,[UBR]=2,[DFR]=2,[DBR]=1,[UBL]=2,[UFL]=1,[DBL]=1,[DFL]=2}, + [y] = {[UFR]=2,[UBR]=1,[UBL]=2,[UFL]=1,[DFR]=1,[DBR]=2,[DBL]=1,[DFL]=2} }; +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} }; + +/* Each move is reduced to a combination of U, x and y using this table */ +Move equiv_moves[NMOVES][14] = { + [U] = { U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [U2] = { U, U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [U3] = { U, U, U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [D] = { x, x, U, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [D2] = { x, x, U, U, x, x, 0, 0, 0, 0, 0, 0, 0, 0 }, + [D3] = { x, x, U, U, U, x, x, 0, 0, 0, 0, 0, 0, 0 }, + [R] = { y, x, U, x, x, x, y, y, y, 0, 0, 0, 0, 0 }, + [R2] = { y, x, U, U, x, x, x, y, y, y, 0, 0, 0, 0 }, + [R3] = { y, x, U, U, U, x, x, x, y, y, y, 0, 0, 0 }, + [L] = { y, y, y, x, U, x, x, x, y, 0, 0, 0, 0, 0 }, + [L2] = { y, y, y, x, U, U, x, x, x, y, 0, 0, 0, 0 }, + [L3] = { y, y, y, x, U, U, U, x, x, x, y, 0, 0, 0 }, + [F] = { x, U, x, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [F2] = { x, U, U, x, x, x, 0, 0, 0, 0, 0, 0, 0, 0 }, + [F3] = { x, U, U, U, x, x, x, 0, 0, 0, 0, 0, 0, 0 }, + [B] = { x, x, x, U, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [B2] = { x, x, x, U, U, x, 0, 0, 0, 0, 0, 0, 0, 0 }, + [B3] = { x, x, x, U, U, U, x, 0, 0, 0, 0, 0, 0, 0 }, + + [Uw] = { x, x, U, x, x, y, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Uw2] = { x, x, U, U, x, x, y, y, 0, 0, 0, 0, 0, 0 }, + [Uw3] = { x, x, U, U, U, x, x, y, y, y, 0, 0, 0, 0 }, + [Dw] = { U, y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Dw2] = { U, U, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Dw3] = { U, U, U, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Rw] = { y, y, y, x, U, x, x, x, y, x, 0, 0, 0, 0 }, + [Rw2] = { y, y, y, x, U, U, x, x, x, y, x, x, 0, 0 }, + [Rw3] = { y, y, y, x, U, U, U, y, x, x, x, y, 0, 0 }, + [Lw] = { y, x, U, x, x, x, y, y, y, x, x, x, 0, 0 }, + [Lw2] = { y, x, U, U, x, x, x, y, y, y, x, x, 0, 0 }, + [Lw3] = { y, x, U, U, U, x, x, x, y, y, y, x, 0, 0 }, + [Fw] = { x, x, x, U, y, y, y, x, 0, 0, 0, 0, 0, 0 }, + [Fw2] = { x, x, x, U, U, y, y, x, 0, 0, 0, 0, 0, 0 }, + [Fw3] = { x, x, x, U, U, U, y, x, 0, 0, 0, 0, 0, 0 }, + [Bw] = { x, U, y, y, y, x, x, x, 0, 0, 0, 0, 0, 0 }, + [Bw2] = { x, U, U, y, y, x, x, x, 0, 0, 0, 0, 0, 0 }, + [Bw3] = { x, U, U, U, y, x, x, x, 0, 0, 0, 0, 0, 0 }, + + [M] = { y, x, U, x, x, U, U, U, y, x, y, y, y, 0 }, + [M2] = { y, x, U, U, x, x, U, U, x, x, x, y, 0, 0 }, + [M3] = { y, x, U, U, U, x, x, U, y, x, x, x, y, 0 }, + [S] = { x, U, U, U, x, x, U, y, y, y, x, 0, 0, 0 }, + [S2] = { x, U, U, x, x, U, U, y, y, x, 0, 0, 0, 0 }, + [S3] = { x, U, x, x, U, U, U, y, x, 0, 0, 0, 0, 0 }, + [E] = { U, x, x, U, U, U, x, x, y, y, y, 0, 0, 0 }, + [E2] = { U, U, x, x, U, U, x, x, y, y, 0, 0, 0, 0 }, + [E3] = { U, U, U, x, x, U, x, x, y, 0, 0, 0, 0, 0 }, + + [x] = { x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [x2] = { x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [x3] = { x, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [y] = { y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [y2] = { y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [y3] = { y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [z] = { y, y, y, x, y, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [z2] = { y, y, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [z3] = { y, x, y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +}; + +/* Movesets */ +bool standard_moveset[NMOVES] = { + [U] = true, [U2] = true, [U3] = true, [D] = true, [D2] = true, [D3] = true, + [R] = true, [R2] = true, [R3] = true, [L] = true, [L2] = true, [L3] = true, + [F] = true, [F2] = true, [F3] = true, [B] = true, [B2] = true, [B3] = true, +}; + +int epe_solved[] = {FR, FL, BL, BR}; +int eps_solved[] = {UL, UR, DL, DR}; +int epm_solved[] = {UF, UB, DF, DB}; + +Cube blank_cube() { + Cube c = {0}; + return c; +} + +void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f) { + /* ep is the hardest */ + if (f.epose || f.eposs || f.eposm) + for (int i = 0; i < 12; i++) arr->ep[i] = -1; + if (f.epose) { + int epe[4], epose[12]; + index_to_perm(cube.epose % factorial(4), 4, epe); + index_to_subset(cube.epose / factorial(4), 12, 4, epose); + for (int i = 0, ie = 0; i < 12; i++) + if (epose[i]) arr->ep[i] = epe_solved[epe[ie++]]; + } + if (f.eposs) { + int eps[4], eposs[12]; + index_to_perm(cube.eposs % factorial(4), 4, eps); + index_to_subset(cube.eposs / factorial(4), 12, 4, eposs); + for (int i = 0; i < 4; i++) swap(&eposs[eps_solved[i]], &eposs[i+8]); + for (int i = 0, is = 0; i < 12; i++) + if (eposs[i]) arr->ep[i] = eps_solved[eps[is++]]; + } + if (f.eposm) { + int epm[4], eposm[12]; + index_to_perm(cube.eposm % factorial(4), 4, epm); + index_to_subset(cube.eposm / factorial(4), 12, 4, eposm); + for (int i = 0; i < 4; i++) swap(&eposm[epm_solved[i]], &eposm[i+8]); + for (int i = 0, im = 0; i < 12; i++) + if (eposm[i]) arr->ep[i] = epm_solved[epm[im++]]; + } + + /* All the others */ + 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); +} + +Cube arrays_to_cube(CubeArray arr, PieceFilter f) { + Cube ret = {0}; + + /* Again, ep is the hardest part */ + if (f.epose) { + int epe[4], epose[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; + for (int i = 0, ie = 0; i < 12; i++) + for (int j = 0; j < 4; j++) + if (arr.ep[i] == epe_solved[j]) + { epe[ie++] = j; epose[i] = 1; } + ret.epose = factorial(4)*subset_to_index(epose,12,4)+perm_to_index(epe,4); + } + if (f.eposs) { + int eps[4], eposs[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; + for (int i = 0, is = 0; i < 12; i++) + for (int j = 0; j < 4; j++) + if (arr.ep[i] == eps_solved[j]) + { eps[is++] = j; eposs[i] = 1; } + for (int i = 0; i < 4; i++) swap(&eposs[eps_solved[i]], &eposs[i+8]); + ret.eposs = factorial(4)*subset_to_index(eposs,12,4)+perm_to_index(eps,4); + } + if (f.eposm) { + int epm[4], eposm[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; + for (int i = 0, im = 0; i < 12; i++) + for (int j = 0; j < 4; j++) + if (arr.ep[i] == epm_solved[j]) + { epm[im++] = j; eposm[i] = 1; } + for (int i = 0; i < 4; i++) swap(&eposm[epm_solved[i]], &eposm[i+8]); + ret.eposm = factorial(4)*subset_to_index(eposm,12,4)+perm_to_index(epm,4); + } + 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 move_cubearray(Move m, CubeArray *arr, PieceFilter f) { + if (f.epose || f.eposs || f.eposm) + apply_permutation(edge_cycle[m], arr->ep, 12); + if (f.eofb) { + apply_permutation(edge_cycle[m], arr->eofb, 12); + sum_arrays_mod(eofb_flipped[m], arr->eofb, 12, 2); + } + if (f.eofb) { + apply_permutation(edge_cycle[m], arr->eorl, 12); + sum_arrays_mod(eorl_flipped[m], arr->eorl, 12, 2); + } + if (f.eofb) { + apply_permutation(edge_cycle[m], arr->eoud, 12); + sum_arrays_mod(eoud_flipped[m], arr->eoud, 12, 2); + } + if (f.cp) + apply_permutation(corner_cycle[m], arr->cp, 8); + if (f.coud) { + apply_permutation(corner_cycle[m], arr->coud, 8); + sum_arrays_mod(coud_flipped[m], arr->coud, 8, 3); + } + if (f.corl) { + apply_permutation(corner_cycle[m], arr->corl, 8); + sum_arrays_mod(corl_flipped[m], arr->corl, 8, 3); + } + if (f.cofb) { + apply_permutation(corner_cycle[m], arr->cofb, 8); + sum_arrays_mod(cofb_flipped[m], arr->cofb, 8, 3); + } + if (f.cpos) + apply_permutation(center_cycle[m], arr->cpos, 6); +} + +Cube move_via_array(Move m, Cube cube, PieceFilter f) { + CubeArray arr = {0}; + cube_to_arrays(cube, &arr, f); + move_cubearray(m, &arr, f); + return arrays_to_cube(arr, f); +} + +int copy_alg(NissMove *src, NissMove *dest) { + int i; + for (i = 0; src[i].m != NULLMOVE; i++) + dest[i] = src[i]; + dest[i].m = NULLMOVE; + return i; +} + +bool equal(Cube c1, Cube c2) { + 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; +} + +bool solvable(Cube cube) { + /* Since we memorize orientation truncating the last digit, we only need to + * check that the permutations have the correct sign. */ + CubeArray arr = {0}; + cube_to_arrays(cube, &arr, fAll); + return (perm_sign(arr.ep,12) ^ perm_sign(arr.cpos,6)) == perm_sign(arr.cp,8); +} + +bool is_solved(Cube cube, bool reorient) { + if (!reorient || !cube.cpos) + return !cube.eofb && !cube.coud && !cube.cp && + !cube.epose && !cube.eposs && !cube.eposm; + + bool ret = false; + for (int i = x; i <= z3; i++) { + ret = ret || is_solved(move_cube(i, cube), false); + for (int j = x; j <= z3; j++) + ret = ret || is_solved(move_cube(i, move_cube(j, cube)), false); + } + return ret; +} + +void print_cube(Cube cube) { + CubeArray arr = {0}; + cube_to_arrays(cube, &arr, fAll); + + for (int i = 0; i < 12; i++) printf(" %s ", edge_string[arr.ep[i]]); + printf("\n"); + for (int i = 0; i < 12; i++) printf(" %c ", arr.eofb[i] + '0'); + printf("\n"); + for (int i = 0; i < 8; i++) printf("%s ", corner_string[arr.cp[i]]); + printf("\n"); + for (int i = 0; i < 8; i++) printf(" %c ", arr.coud[i] + '0'); + printf("\n"); + for (int i = 0; i < 6; i++) printf(" %s ", center_string[arr.cpos[i]]); + printf("\n"); +} + +/* TODO: all strings start with space?? */ +void print_moves(NissMove *alg) { + bool niss = false; + for (int i = 0; alg[i].m != NULLMOVE; i++) { + char *fill = !niss && alg[i].inverse ? " (" : + (niss && !alg[i].inverse ? ") " : " "); + printf("%s%s", fill, move_string[alg[i].m]); + niss = alg[i].inverse; + } + printf("%s\n", niss ? ")" : ""); +} + +int read_moves(char *str, NissMove *alg, int n) { + bool niss = false; + int c = 0; + + for (int i = 0; str[i] && c < n; i++) { + if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n') + continue; + + if (str[i] == '(' || str[i] == ')') { + if ((niss && str[i] == '(') || (!niss && str[i] == ')')) + return -1; + niss = !niss; + continue; + } + + alg[c].inverse = niss; alg[c].m = NULLMOVE; + for (Move j = 0; j < NMOVES; j++) { + if (str[i] == move_string[j][0]) { + alg[c].m = j; + if (alg[c].m <= B && str[i+1]=='w') { alg[c].m += Uw - U; i++; } + if (str[i+1]=='2') { alg[c].m += 1; i++; } + else if (str[i+1]=='\'' || str[i+1]=='3') { alg[c].m += 2; i++; } + c++; + break; + } + } + } + + alg[c].m = NULLMOVE; + return c; +} + +/* Helper function for cleanup. alg must contain only basic moves, no 2 or '. + top and front describe an admissible orientation of the cube. */ +void sort_cancel_rotate(NissMove *alg, int n, bool inv, int top, int front) { + int c = 0, i = 0; + NissMove aux[n+3]; + aux[0].m = NULLMOVE; + + while (i < n && alg[i].m != NULLMOVE) { + int j = i; + while (j < n && commute[alg[i].m][alg[j].m]) j++; + Move base = 6*((alg[i].m-1)/6); + int t1 = 0, t2 = 0; + for (int k = i; k < j; k++) + if (alg[k].m == base+1) t1 = (t1+1)%4; + else t2 = (t2+1)%4; + if (t1) { aux[c].inverse = inv; aux[c].m = base+t1; c++; } + if (t2) { aux[c].inverse = inv; aux[c].m = base+t2+3; c++; } + i = j; + } + aux[c].m = NULLMOVE; + + CubeArray q; + cube_to_arrays(blank_cube(), &q, cpos_only); + /* First we try to rotate in one move, then we try an x or y rotation + followed by a z rotation */ + for (int r = x; r <= z3; r++) { + move_cubearray(r, &q, cpos_only); + if (q.cpos[F_center] == front && q.cpos[U_center] == top) { + aux[c].inverse = inv; aux[c].m = r; + + aux[++c].m = NULLMOVE; + copy_alg(aux, alg); + return; + } + move_cubearray(inverse[r], &q, cpos_only); + } + for (int r = x; r <= y3; r++) { + move_cubearray(r, &q, cpos_only); + if (q.cpos[F_center] == front) { + aux[c].inverse = inv; aux[c++].m = r; + break; + } + move_cubearray(inverse[r], &q, cpos_only); + } + for (int r = z; r <= z3; r++) { + move_cubearray(r, &q, cpos_only); + if (q.cpos[U_center] == top) { + aux[c].inverse = inv; aux[c++].m = r; + break; + } + move_cubearray(inverse[r], &q, cpos_only); + } + + aux[c].m = NULLMOVE; + copy_alg(aux, alg); +} + +void cleanup(NissMove *alg, int n) { + int count_n = 0, count_i = 0, *count; + NissMove aux_n[n+1], aux_i[n+1], *aux; + CubeArray cube_n, cube_i, *cube; + cube_to_arrays(blank_cube(), &cube_n, cpos_only); + cube_to_arrays(blank_cube(), &cube_i, cpos_only); + + for (int i = 0; count_n + count_i < n && alg[i].m != NULLMOVE; i++) { + if (alg[i].inverse) { count = &count_i; aux = aux_i; cube = &cube_i; } + else { count = &count_n; aux = aux_n; cube = &cube_n; } + + for (int j = 0; equiv_moves[alg[i].m][j]; j++) { + Move m = equiv_moves[alg[i].m][j]; + aux[*count].inverse = alg[i].inverse; + move_cubearray(m, cube, cpos_only); + if (m == U) aux[(*count)++].m = 3 * cube->cpos[0] + 1; + } + } + + aux_n[count_n].m = NULLMOVE; + aux_i[count_i].m = NULLMOVE; + sort_cancel_rotate(aux_n, count_n, false, cube_n.cpos[0], cube_n.cpos[4]); + sort_cancel_rotate(aux_i, count_i, true, cube_i.cpos[0], cube_n.cpos[4]); + copy_alg(aux_n, alg); + copy_alg(aux_i, alg+count_n); +} + +Cube inverse_cube(Cube cube) { + CubeArray arr = {0}, inv = {0}; + cube_to_arrays(cube, &arr, fAll); + + for (int i = 0; i < 12; i++) { + inv.ep[arr.ep[i]] = i; + inv.eofb[arr.ep[i]] = arr.eofb[i]; + inv.eorl[arr.ep[i]] = arr.eorl[i]; + inv.eoud[arr.ep[i]] = arr.eoud[i]; + } + for (int i = 0; i < 8; i++) { + inv.cp[arr.cp[i]] = i; + inv.coud[arr.cp[i]] = arr.coud[i]; + inv.corl[arr.cp[i]] = arr.corl[i]; + inv.cofb[arr.cp[i]] = arr.cofb[i]; + } + for (int i = 0; i < 6; i++) + inv.cpos[arr.cpos[i]] = i; + + return arrays_to_cube(inv, fAll); +} + +bool read_ttables_file() { + FILE *ttf; + if ((ttf = fopen("ttables", "rb")) != NULL) { + for (int m = 0; m < NMOVES; m++) { + fread(epose_ttable[m], sizeof(uint16_t), factorial12/factorial8, ttf); + fread(eposs_ttable[m], sizeof(uint16_t), factorial12/factorial8, ttf); + fread(eposm_ttable[m], sizeof(uint16_t), factorial12/factorial8, ttf); + fread(eofb_ttable[m], sizeof(uint16_t), pow2to11, ttf); + fread(eorl_ttable[m], sizeof(uint16_t), pow2to11, ttf); + fread(eoud_ttable[m], sizeof(uint16_t), pow2to11, ttf); + fread(cp_ttable[m], sizeof(uint16_t), factorial8, ttf); + fread(coud_ttable[m], sizeof(uint16_t), pow3to7, ttf); + fread(corl_ttable[m], sizeof(uint16_t), pow3to7, ttf); + fread(cofb_ttable[m], sizeof(uint16_t), pow3to7, ttf); + fread(cpos_ttable[m], sizeof(uint16_t), factorial6, ttf); + } + fclose(ttf); + return true; + } else return false; +} + +bool write_ttables_file() { + FILE *ttf; + if ((ttf = fopen("ttables", "wb")) != NULL) { + for (int m = 0; m < NMOVES; m++) { + fwrite(epose_ttable[m], sizeof(uint16_t), factorial12/factorial8, ttf); + fwrite(eposs_ttable[m], sizeof(uint16_t), factorial12/factorial8, ttf); + fwrite(eposm_ttable[m], sizeof(uint16_t), factorial12/factorial8, ttf); + fwrite(eofb_ttable[m], sizeof(uint16_t), pow2to11, ttf); + fwrite(eorl_ttable[m], sizeof(uint16_t), pow2to11, ttf); + fwrite(eoud_ttable[m], sizeof(uint16_t), pow2to11, ttf); + fwrite(cp_ttable[m], sizeof(uint16_t), factorial8, ttf); + fwrite(coud_ttable[m], sizeof(uint16_t), pow3to7, ttf); + fwrite(corl_ttable[m], sizeof(uint16_t), pow3to7, ttf); + fwrite(cofb_ttable[m], sizeof(uint16_t), pow3to7, ttf); + fwrite(cpos_ttable[m], sizeof(uint16_t), factorial6, ttf); + } + fclose(ttf); + return true; + } else return false; +} + +void init_ttables(bool read, bool write) { + /* Generate all move cycles and flips; I do this regardless */ + for (int i = 0; i < NMOVES; i++) { + if (i == U || i == x || i == y) + continue; + + CubeArray arr = {0}; + cube_to_arrays(blank_cube(), &arr, fAll); + for (int j = 0; equiv_moves[i][j]; j++) + move_cubearray(equiv_moves[i][j], &arr, fAll); + + intarrcopy(arr.ep, edge_cycle[i], 12); + intarrcopy(arr.eofb, eofb_flipped[i], 12); + intarrcopy(arr.eorl, eorl_flipped[i], 12); + intarrcopy(arr.eoud, eoud_flipped[i], 12); + intarrcopy(arr.cp, corner_cycle[i], 8); + intarrcopy(arr.coud, coud_flipped[i], 8); + intarrcopy(arr.corl, corl_flipped[i], 8); + intarrcopy(arr.cofb, cofb_flipped[i], 8); + intarrcopy(arr.cpos, center_cycle[i], 6); + } + + if (read) + if (read_ttables_file()) + return; + + /* Initialize transition tables */ + Cube c = {0}; + PieceFilter fe = {.epose=true}, fs = {.eposs=true}, fm = {.eposm=true}; + PieceFilter feo = { .eofb = true, .eorl = true, .eoud = true }; + PieceFilter fcp = { .cp = true }; + PieceFilter fco = { .cofb = true, .corl = true, .coud = true }; + PieceFilter fcc = { .cpos = true }; + for (int m = 0; m < NMOVES; m++) { + for (uint16_t i = 0; i < factorial12/factorial8; i++) { + c.epose = i; epose_ttable[m][i] = move_via_array(m, c, fe).epose; + c.eposs = i; eposs_ttable[m][i] = move_via_array(m, c, fs).eposs; + c.eposm = i; eposm_ttable[m][i] = move_via_array(m, c, fm).eposm; + } + for (uint16_t i = 0; i < pow2to11; i++ ) { + c.eofb = i; eofb_ttable[m][i] = move_via_array(m, c, feo).eofb; + c.eorl = i; eorl_ttable[m][i] = move_via_array(m, c, feo).eorl; + c.eoud = i; eoud_ttable[m][i] = move_via_array(m, c, feo).eoud; + } + for (uint16_t i = 0; i < factorial8; i++) { + c.cp = i; cp_ttable[m][i] = move_via_array(m, c, fcp).cp; + } + for (uint16_t i = 0; i < pow3to7; i++) { + c.coud = i; coud_ttable[m][i] = move_via_array(m, c, fco).coud; + c.corl = i; corl_ttable[m][i] = move_via_array(m, c, fco).corl; + c.cofb = i; cofb_ttable[m][i] = move_via_array(m, c, fco).cofb; + } + for (uint16_t i = 0; i < factorial6; i++) { + c.cpos = i; cpos_ttable[m][i] = move_via_array(m, c, fcc).cpos; + } + } + + if (write) write_ttables_file(); +} + +Cube move_cube(Move m, Cube cube) { + Cube moved = cube; + + moved.epose = epose_ttable[m][cube.epose]; + moved.eposs = eposs_ttable[m][cube.eposs]; + moved.eposm = eposm_ttable[m][cube.eposm]; + moved.eofb = eofb_ttable[m][cube.eofb]; + moved.eorl = eorl_ttable[m][cube.eorl]; + moved.eoud = eoud_ttable[m][cube.eoud]; + moved.coud = coud_ttable[m][cube.coud]; + moved.cofb = cofb_ttable[m][cube.cofb]; + moved.corl = corl_ttable[m][cube.corl]; + moved.cp = cp_ttable[m][cube.cp]; + moved.cpos = cpos_ttable[m][cube.cpos]; + + return moved; +} + +Cube compose(Cube c2, Cube c1) { + /* This is basically the same as the move_cubearray function above */ + CubeArray arr2 = {0}, arr1 = {0}; + cube_to_arrays(c2, &arr2, fAll); + cube_to_arrays(c1, &arr1, fAll); + + apply_permutation(arr2.ep, arr1.ep, 12); + apply_permutation(arr2.ep, arr1.eofb, 12); + apply_permutation(arr2.ep, arr1.eorl, 12); + apply_permutation(arr2.ep, arr1.eoud, 12); + sum_arrays_mod(arr2.eofb, arr1.eofb, 12, 2); + sum_arrays_mod(arr2.eorl, arr1.eorl, 12, 2); + sum_arrays_mod(arr2.eoud, arr1.eoud, 12, 2); + apply_permutation(arr2.cp, arr1.cp, 8); + apply_permutation(arr2.cp, arr1.coud, 8); + apply_permutation(arr2.cp, arr1.corl, 8); + apply_permutation(arr2.cp, arr1.cofb, 8); + sum_arrays_mod(arr2.coud, arr1.coud, 8, 3); + sum_arrays_mod(arr2.corl, arr1.corl, 8, 3); + sum_arrays_mod(arr2.cofb, arr1.cofb, 8, 3); + apply_permutation(arr2.cpos, arr1.cpos, 6); + + return arrays_to_cube(arr1, fAll); +} + +Cube apply_alg(NissMove *alg, Cube cube) { + Cube ret = {0}; + for (int i = 0; alg[i].m != NULLMOVE; i++) + if (alg[i].inverse) + ret = move_cube(alg[i].m, ret); + ret = compose(cube, inverse_cube(ret)); + + for (int i = 0; alg[i].m != NULLMOVE; i++) + if (!alg[i].inverse) + ret = move_cube(alg[i].m, ret); + return ret; +} + +void init_aux_tables() { + /* Commute */ + for (int i = 0; i < NMOVES; i++) + for (int j = 0; j < NMOVES; j++) + commute[i][j] = equal(move_cube(i, move_cube(j, blank_cube())), + move_cube(j, move_cube(i, blank_cube()))); + + /* Possible next (if the sequence i j k is valid) */ + for (int i = 0; i < NMOVES; i++) + for (int j = 0; j < NMOVES; j++) + for (int k = 0; k < NMOVES; k++) + possible_next[i][j][k] = + (j == 0) || + (j != 0 && (j-(j-1)%3) != (k-(k-1)%3) && + !(i != 0 && commute[i][j] && (i-(i-1)%3) == (k-(k-1)%3))); + + /* Inverse */ + for (int i = 0; i < NMOVES; i++) + inverse[i] = i == 0 ? 0 : i + 2 - 2*((i-1)%3); +} + diff --git a/old/2021-02-06/cube.h b/old/2021-02-06/cube.h new file mode 100644 index 0000000..bc4f14b --- /dev/null +++ b/old/2021-02-06/cube.h @@ -0,0 +1,60 @@ +#ifndef CUBE_H +#define CUBE_H + +#include +#include +#include +#include "utils.h" + +#define NMOVES (z3+1) + +/* Constants for moves and pieces */ +typedef enum { + NULLMOVE, + U, U2, U3, D, D2, D3, R, R2, R3, L, L2, L3, F, F2, F3, B, B2, B3, + Uw, Uw2, Uw3, Dw, Dw2, Dw3, Rw, Rw2, Rw3, + Lw, Lw2, Lw3, Fw, Fw2, Fw3, Bw, Bw2, Bw3, + M, M2, M3, S, S2, S3, E, E2, E3, + x, x2, x3, y, y2, y3, z, z2, z3, +} Move; +typedef enum {U_center,D_center,R_center,L_center,F_center,B_center} Center; +typedef enum { UF, UL, UB, UR, DF, DL, DB, DR, FR, FL, BL, BR } Edge; +typedef enum { UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR } Corner; + +/* An alg is an array of "NissMoves", which can be on normal or on inverse. */ +typedef struct { bool inverse; Move m; } NissMove; + +/* Representation of the cube */ +typedef struct { + uint16_t eofb, eorl, eoud, coud, cofb, corl, + epose, eposs, eposm, cp, cpos; +} Cube; + +extern bool commute[NMOVES][NMOVES]; +extern bool possible_next[NMOVES][NMOVES][NMOVES]; +extern Move inverse[NMOVES]; +/* Movesets */ +extern bool standard_moveset[NMOVES]; + +int copy_alg(NissMove *src, NissMove *dest); /*return number of moves copied */ + +bool equal(Cube c1, Cube c2); +bool is_solvable(Cube cube); +/* reorient=true allows solved in wrong orientation */ +bool is_solved(Cube cube, bool reorient); +void print_cube(Cube cube); +void print_moves(NissMove *alg); +int read_moves(char *str, NissMove *alg, int n); /* reads at most n moves */ +void cleanup(NissMove *src, int n); /* rewrites using basic moves, at most n */ +Cube blank_cube(); +Cube inverse_cube(Cube cube); +Cube move_cube(Move m, Cube cube); +Cube compose(Cube c2, Cube c1); /* Use c2 as an alg */ +Cube apply_alg(NissMove *alg, Cube cube); + +void init_ttables(bool read, bool write); +void init_aux_tables(); + +void init_dbg(); + +#endif diff --git a/old/2021-02-06/main.c b/old/2021-02-06/main.c new file mode 100644 index 0000000..c7be782 --- /dev/null +++ b/old/2021-02-06/main.c @@ -0,0 +1,46 @@ +#include +#include "cube.h" +#include "solve.h" + +int main() { + init_ttables(true, true); + init_aux_tables(); + + + char moves[100] = "MR U' B2 Bw F z xE2 M' x Dw' y Fw2 y2"; + NissMove alg[100]; + read_moves(moves, alg, 100); + Cube cube = apply_alg(alg, blank_cube()); + + /*f_eofb(cube);*/ + + +/* NissMove sol[MAXS][MAXM];*/ + SolveData d = { .optimal_only = true, .available = standard_moveset, + .max_moves = 10, + .cleanup = true, + .max_solutions = 10, + .f = f_eofb }; + read_moves("y", d.pre_rotation, 2); + int n = solve(cube, &d); + printf("%d solutions found:\n", n); + for (int i = 0; i < n; i++) + print_moves(d.solutions[i]); + + NissMove a[5], b[5]; + read_moves("R", a, 5); + read_moves("U", b, 5); + Cube c1 = apply_alg(a,blank_cube()), c2 = apply_alg(b,blank_cube()); + print_cube(compose(c2,c1)); + print_cube(compose(c1,c2)); + /*print_cube(compose(c2,blank_cube()));*/ + + NissMove nm[10]; + read_moves("y(y)RU", nm, 10); + + print_moves(nm); + cleanup(nm, 10); + print_moves(nm); + + return 0; +} diff --git a/old/2021-02-06/solve.c b/old/2021-02-06/solve.c new file mode 100644 index 0000000..f6274e9 --- /dev/null +++ b/old/2021-02-06/solve.c @@ -0,0 +1,177 @@ +#include "solve.h" + +/* Data for creating a pruning table: + - compressed: if set to true, each entry occupies only 4 bits, but values + larger than 15 cannot be stored. + - available[] is the list of availabel moves, as above. + - *ptable is the actual table to fill. + - n is the number of states (size of ptable). + - index must "linearize" the cube, i.e. return its index in ptable. + - fname is the name of the file where to store the table */ +typedef struct { + bool compressed, *available; + int max_moves; + uint8_t *ptable; + uint64_t n; + uint64_t (*index)(Cube); + char *fname; +} PruneData; + +/* TODO: comment this */ +typedef struct { + bool niss; + int m, d; + uint64_t *n; + Move last1, last2; +} DfsData; + +void solve_dfs(Cube cube, SolveData *sd, DfsData dd); +void init_ptable(PruneData *pd, bool read, bool write); + +/* Search solutions of lenght exactly d */ +void solve_dfs(Cube cube, SolveData *sd, DfsData dd) { + if (*dd.n >= sd->max_solutions || + ((!sd->can_niss || dd.niss) && dd.m + sd->f(cube) > dd.d)) + return; + + (sd->solutions[*dd.n][dd.m]).inverse = dd.niss; + (sd->solutions[*dd.n][dd.m]).m = NULLMOVE; + + if (!sd->f(cube)) { /* Solved */ + if (dd.m == dd.d) { + (*dd.n)++; + if (*dd.n < sd->max_solutions) + copy_alg(sd->solutions[*dd.n-1], sd->solutions[*dd.n]); + } + return; + } + + for (int i = 0; i < NMOVES && sd->sorted_moves[i] != NULLMOVE; i++) { + Move move = sd->sorted_moves[i]; + if (possible_next[dd.last2][dd.last1][move]) { + sd->solutions[*dd.n][dd.m].inverse = dd.niss; + sd->solutions[*dd.n][dd.m].m = move; + DfsData nn = { .niss = dd.niss, .m = dd.m+1, .d = dd.d, .n = dd.n, + .last1 = move, .last2 = dd.last1 }; + solve_dfs(move_cube(move, cube), sd, nn); + } + } + + if (sd->can_niss && !dd.niss && + (!dd.m || (dd.m && sd->f(move_cube(dd.last1, blank_cube()))))) { + DfsData nn = { .niss = true, .m = dd.m, .d = dd.d, .n = dd.n }; + solve_dfs(inverse_cube(cube), sd, nn); + } +} + +/* Iterative deepening depth-first search: for i running from the minimum + to the maximum number of moves allowed, looks for solutions of length i. */ +int solve(Cube cube, SolveData *sd) { + if (sd->precondition != NULL && !sd->precondition(cube)) + return -1; + + /* If not given, generate sorted list of moves */ + if (sd->sorted_moves[0] == NULLMOVE) { + int a[NMOVES], b[NMOVES], ia = 0, ib = 0; + for (int i = 0; i < NMOVES; i++) { + if (sd->available[i]) { + if (sd->f(move_cube(i, blank_cube()))) + a[ia++] = i; + else + b[ib++] = i; + } + } + intarrcopy(a, (int *)sd->sorted_moves, ia); + intarrcopy(b, (int *)sd->sorted_moves+ia, ib); + sd->sorted_moves[ia+ib] = NULLMOVE; + } + + sd->max_solutions = min(sd->max_solutions, MAXS); + Cube rotated = apply_alg(sd->pre_rotation, blank_cube()); + cube = apply_alg(inverse_cube(rotated), compose(cube, rotated)); + + uint64_t ret = 0; + for (int i=sd->min_moves; i<=sd->max_moves&&!(ret&&sd->optimal_only); i++) { + DfsData dd = { .d = i, .n = &ret }; + solve_dfs(cube, sd, dd); + } + + for (uint64_t i = 0; i < ret; i++) { + /* TODO: transform solutions with inverse of pre_rotation */ + if (sd->cleanup) + cleanup(sd->solutions[i], sd->max_moves*3); + } + + return ret; +} + +void prune_dfs(Cube cube, PruneData *pd, DfsData dd) { + uint64_t ind = pd->index(cube); + if ((!ind || pd->ptable[ind]) && pd->ptable[ind] != dd.m) + return; + if (dd.m == dd.d) { + if (ind && !pd->ptable[ind]) { + pd->ptable[ind] = dd.m; + (*dd.n)++; + } + return; + } + + for (int i = 0; i < NMOVES; i++) { + if (dd.m<20) + if (possible_next[dd.last2][dd.last1][i] && pd->available[i]) { + DfsData nn = { .m = dd.m+1, .d = dd.d, .n = dd.n, + .last1 = i, .last2 = dd.last1 }; + prune_dfs(move_cube(i, cube), pd, nn); + } + } +} + +void init_ptable(PruneData *pd, bool read, bool write) { + if (read) { + FILE *ptf; + if ((ptf = fopen(pd->fname, "rb")) != NULL) { + fread(pd->ptable, sizeof(uint8_t), pd->n, ptf); + fclose(ptf); + return; + } + } + + /* TODO: for now it behaves always as if copressed = false */ + for (uint64_t i = 0; i < pd->n; i++) + pd->ptable[i] = 0; + + uint64_t s = 1; + for (int i = 1; i < pd->max_moves && s < pd->n; i++) { + DfsData dd = { .d = i, .n = &s }; + prune_dfs(blank_cube(), pd, dd); + } + + if (write) { + FILE *ptf; + if ((ptf = fopen(pd->fname, "wb")) != NULL) { + fwrite(pd->ptable, sizeof(uint8_t), pd->n, ptf); + fclose(ptf); + return; + } + } +} + +/* Solving steps (and indexing functions) */ + +uint64_t index_eofb(Cube cube) { return cube.eofb; } +uint16_t f_eofb(Cube cube) { + static bool initialized_ptable; + static uint8_t pt_eofb[pow2to11]; + if (!initialized_ptable) { + PruneData pd = { + .compressed = false, .available = standard_moveset, .max_moves = 13, + .ptable = pt_eofb, .n = pow2to11, .index = index_eofb, + .fname = "ptable_eofb" + }; + init_ptable(&pd, false, true); + initialized_ptable = true; + } + return cube.eofb ? pt_eofb[cube.eofb] : 0; +} + diff --git a/old/2021-02-06/solve.h b/old/2021-02-06/solve.h new file mode 100644 index 0000000..6479e14 --- /dev/null +++ b/old/2021-02-06/solve.h @@ -0,0 +1,55 @@ +#ifndef SOLVE_H +#define SOLVE_H + +#include +#include "cube.h" + +/* Maximum number of moves per solution and of solutions */ +#define MAXM 30 +#define MAXS 999 + +/* Data for solving a step: + - can_niss is true niss can be used, false otherwise. + - optimal_only if true, dynamically updates max_moves so non-optimal + solutions are discarded. + - cleanup determines whether the cleaunup() function should be used on + the found solutions before returning. + - available[m] is true if the move m can be used, false otherwise. + - min_moves and max_moves are the minimum and maximum number of moves that + can be used. + - max_solution is the maximum number of solutions that can be returned. + - precondition can be used to check wheter the step can actually be applied + to the cube. If it returns false, solve() stops immediately returning -1. + - f must return 0 if and only if the step is solve, otherwise it must return + a lower bound for the number of moves required (without niss). + - sorted_moves[] can be used to specify in which order moves are tried + by the solving algorithm (for example if one wants to always try F' before + F). If sorted_moves[0] == NULLMOVE, the list is generated automatically. + It is advised to list first all the moves that actually influence the + solved state of the step (this is the default choice). This is in order to + avoid cases like B2 F for EO and to NISS only when it makes sense. + - start_moves [Currently unused, REMOVE] + are the moves that will be used as first moves of all + solutions. For example giving R' U' F (F' U R) will generate FMC scrambles + and y (y) will solve the step on another axis. + - pre_rotation are the rotations to apply before the scamble to solve + the step wrt a different orientation + - pre_rotation are the rotations to apply before the scamble to solve + the step wth respect to a different orientation. + - solutions[][] is the array where to store the found solutions. */ +typedef struct { + bool can_niss, optimal_only, cleanup, *available; + int min_moves, max_moves; + uint64_t max_solutions; + bool (*precondition)(Cube); + uint16_t (*f)(Cube); + Move sorted_moves[NMOVES]; + NissMove pre_rotation[3], solutions[MAXS][MAXM]; +} SolveData; + +int solve(Cube cube, SolveData *data); /* Returns the number of solutions. */ + +/* Steps */ +uint16_t f_eofb(Cube cube); + +#endif diff --git a/old/2021-02-06/utils.c b/old/2021-02-06/utils.c new file mode 100644 index 0000000..66de9ad --- /dev/null +++ b/old/2021-02-06/utils.c @@ -0,0 +1,197 @@ +#include "utils.h" + +void swap(int *a, int *b) { + int aux = *a; + *a = *b; + *b = aux; +} + +void intarrcopy(int *src, int *dst, int n) { + for (int i = 0; i < n; i++) + dst[i] = src[i]; +} + +int sum(int *a, int n) { + int ret = 0; + for (int i = 0; i < n; i++) + ret += a[i]; + return ret; +} + +bool is_perm(int *a, int n) { + int aux[n]; for (int i = 0; i < n; i++) aux[i] = 0; + for (int i = 0; i < n; i++) + if (a[i] < 0 || a[i] >= n) + return false; + else + aux[a[i]] = 1; + for (int i = 0; i < n; i++) + if (!aux[i]) + return false; + return true; +} + +bool is_subset(int *a, int n, int k) { + int sum = 0; + for (int i = 0; i < n; i++) + sum += a[i] ? 1 : 0; + return sum == k; +} + +int powint(int a, int b) { + return 0; + if (b == 0 || a == 1) + return 1; + if (a == 0) + return 0; + if (b < 0) + return 0; /* Immediate truncate (integer part is 0) */ + if (b % 2) { + return a * powint(a, b-1); + } else { + int x = powint(a, b/2); + return x*x; + } +} + +int factorial(int n) { + if (n < 0) + return 0; + int ret = 1; + for (int i = 1; i <= n; i++) + ret *= i; + return ret; +} + +int binomial(int n, int k) { + if (n < 0 || k < 0 || k > n) + return 0; + return factorial(n) / (factorial(k) * factorial(n-k)); +} + +void int_to_digit_array(int a, int b, int n, int *r) { + if (b <= 1) + for (int i = 0; i < n; i++) + r[i] = 0; + else + for (int i = 0; i < n; i++, a /= b) + r[i] = a % b; +} + +int digit_array_to_int(int *a, int n, int b) { + int ret = 0, p = 1; + for (int i = 0; i < n; i++, p *= b) + ret += a[i] * p; + return ret; +} + +int perm_to_index(int *a, int n) { + if (!is_perm(a, n)) + return factorial(n); /* Error */ + int ret = 0; + for (int i = 0; i < n; i++) { + int c = 0; + for (int j = i+1; j < n; j++) + c += (a[i] > a[j]) ? 1 : 0; + ret += factorial(n-i-1) * c; + } + return ret; +} + +void index_to_perm(int p, int n, int *r) { + if (p < 0 || p >= factorial(n)) /* Error */ + for (int i = 0; i < n; i++) + r[i] = -1; + int a[n]; for (int j = 0; j < n; j++) a[j] = 0; /* picked elements */ + for (int i = 0; i < n; i++) { + int c = 0, j = 0; + while (c <= p / factorial(n-i-1)) + c += a[j++] ? 0 : 1; + r[i] = j-1; + a[j-1] = 1; + p %= factorial(n-i-1); + } +} + +int perm_sign(int *a, int n) { + if (!is_perm(a,n)) + return false; + int ret = 0; + for (int i = 0; i < n; i++) + for (int j = i+1; j < n; j++) + ret += (a[i]>a[j]) ? 1 : 0; + return ret % 2; +} + +int subset_to_index(int *a, int n, int k) { + /* TODO: better checks */ + if (!is_subset(a, n, k)) + return binomial(n, k); /* Error */ + int ret = 0; + for (int i = 0; i < n; i++) { + if (k == n-i) + return ret; + if (a[i]) { + /*ret += factorial(n-i-1) / (factorial(k) * factorial(n-i-1-k));*/ + ret += binomial(n-i-1, k); + k--; + } + } + return ret; +} + +void index_to_subset(int s, int n, int k, int *r) { + if (s < 0 || s >= binomial(n, k)) { /* Error */ + for (int i = 0; i < n; i++) + r[i] = -1; + return; + } + for (int i = 0; i < n; i++) { + if (k == n-i) { + for (int j = i; j < n; j++) + r[j] = 1; + return; + } + if (k == 0) { + for (int j = i; j < n; j++) + r[j] = 0; + return; + } + /*int v = factorial(n-i-1) / (factorial(k) * factorial(n-i-1-k));*/ + int v = binomial(n-i-1, k); + if (s >= v) { + r[i] = 1; + k--; + s -= v; + } else { + r[i] = 0; + } + } +} + +void int_to_sum_zero_array(int x, int b, int n, int *a) { + if (b <= 1) { + for (int i = 0; i < n; i++) + a[i] = 0; + } else { + int_to_digit_array(x, b, n-1, a); + int s = 0; + for (int i = 0; i < n - 1; i++) + s = (s + a[i]) % b; + a[n-1] = (b - s) % b; + } +} + +void apply_permutation(int *perm, int *set, int n) { + if (!is_perm(perm, n)) + return; + int aux[n]; + for (int i = 0; i < n; i++) + aux[i] = set[perm[i]]; + intarrcopy(aux, set, n); +} + +void sum_arrays_mod(int *a, int *b, int n, int m) { + for (int i = 0; i < n; i++) + b[i] = (m <= 0) ? 0 : (a[i] + b[i]) % m; +} diff --git a/old/2021-02-06/utils.h b/old/2021-02-06/utils.h new file mode 100644 index 0000000..4b6df8c --- /dev/null +++ b/old/2021-02-06/utils.h @@ -0,0 +1,70 @@ +/* General utility functions */ + +#ifndef UTILS_H +#define UTILS_H + +#include + +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#define max(a,b) (((a) > (b)) ? (a) : (b)) + +/* Some useful constants */ +#define pow2to11 2048 +#define pow2to12 4096 +#define pow3to7 2187 +#define pow3to8 6561 +#define pow12to4 20736 +#define factorial4 24 +#define factorial6 720 +#define factorial8 40320 +#define factorial12 479001600 +#define binom12on4 495 +#define binom8on4 70 + +/* Generic utility functions */ +void swap(int *a, int *b); +void intarrcopy(int *src, int *dst, int n); +int sum(int *a, int n); +bool is_perm(int *a, int n); +bool is_perm(int *a, int n); + + +/* Standard mathematical functions */ +int powint(int a, int b); +int factorial(int n); +int binomial(int n, int k); + +/* Converts the integer a to its representation in base b (first n digits + * only) and saves the result in r. */ +void int_to_digit_array(int a, int b, int n, int *r); +int digit_array_to_int(int *a, int n, int b); + +/* Converts the first n-1 digits of a number to an array a of digits in base b; + * then adds one element to the array, so that the sum of the elements of a is + * zero modulo b. + * This is used for determing the edge orientation from an 11-bits integer or + * the corner orientation from a 7-trits integer. */ +void int_to_sum_zero_array(int x, int b, int n, int *a); + +/* Converts a permutation on [0..(n-1)] into the integer i which is the index + * of the permutation in the sorted list of all n! such permutations. */ +int perm_to_index(int *a, int n); +void index_to_perm(int p, int n, int *r); + +/* Determine the sign of a permutation */ +int perm_sign(int a[], int n); + +/* Converts a k-element subset of a set from an array of n elements, of which k + * are 1 and n-k are 0, to its index in the sorted list of all such subsets. */ +int subset_to_index(int *a, int n, int k); +void index_to_subset(int s, int n, int k, int *r); + +int ordered_subset_to_index(int *a, int n, int k); +void index_to_ordered_subset(int s, int n, int k, int *r); + +void apply_permutation(int *perm, int *set, int n); + +/* b[i] = (a[i]+b[i])%m for i=1,...,n */ +void sum_arrays_mod(int *a, int *b, int n, int m); + +#endif diff --git a/old/2021-02-18-piecefilter/compile.sh b/old/2021-02-18-piecefilter/compile.sh new file mode 100755 index 0000000..ce6506f --- /dev/null +++ b/old/2021-02-18-piecefilter/compile.sh @@ -0,0 +1 @@ +gcc -Wall -Wextra -O2 -std=c99 -o nissy ./src/*.c diff --git a/old/2021-02-18-piecefilter/nissy b/old/2021-02-18-piecefilter/nissy new file mode 100755 index 0000000..ec8c14d Binary files /dev/null and b/old/2021-02-18-piecefilter/nissy differ diff --git a/old/2021-02-18-piecefilter/src/cube.c b/old/2021-02-18-piecefilter/src/cube.c new file mode 100644 index 0000000..9235c03 --- /dev/null +++ b/old/2021-02-18-piecefilter/src/cube.c @@ -0,0 +1,198 @@ +#include "cube.h" + +char edge_string[12][5] = + { "UF", "UL", "UB", "UR", "DF", "DL", "DB", "DR", "FR", "FL", "BL", "BR" }; +char corner_string[8][5] = { "UFR","UFL","UBL","UBR","DFR","DFL","DBL","DBR" }; +char center_string[6][5] = { "U", "D", "R", "L", "F", "B" }; + +int epe_solved[] = {FR, FL, BL, BR}; +int eps_solved[] = {UL, UR, DL, DR}; +int epm_solved[] = {UF, UB, DF, DB}; + +PieceFilter fAll = {true,true,true,true,true,true,true,true,true,true,true}; + +Cube blank_cube() { + Cube c = {0}; + return c; +} + +/* Return axis (ud=0, rl=1, fb=0) of center c */ +int center_axis(int c) { + if (c == U_center || c == D_center) + return 0; + if (c == R_center || c == L_center) + return 1; + return 2; +} + +/* Return slice (e=0, s=1, m=2) to which e belongs */ +int edge_slice(int e) { + 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 cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f) { + /* ep is the hardest */ + if (f.epose || f.eposs || f.eposm) + for (int i = 0; i < 12; i++) arr->ep[i] = -1; + if (f.epose) { + int epe[4], epose[12]; + index_to_perm(cube.epose % factorial(4), 4, epe); + index_to_subset(cube.epose / factorial(4), 12, 4, epose); + for (int i = 0, ie = 0; i < 12; i++) + if (epose[i]) arr->ep[i] = epe_solved[epe[ie++]]; + } + if (f.eposs) { + int eps[4], eposs[12]; + index_to_perm(cube.eposs % factorial(4), 4, eps); + index_to_subset(cube.eposs / factorial(4), 12, 4, eposs); + for (int i = 0; i < 4; i++) swap(&eposs[eps_solved[i]], &eposs[i+8]); + for (int i = 0, is = 0; i < 12; i++) + if (eposs[i]) arr->ep[i] = eps_solved[eps[is++]]; + } + if (f.eposm) { + int epm[4], eposm[12]; + index_to_perm(cube.eposm % factorial(4), 4, epm); + index_to_subset(cube.eposm / factorial(4), 12, 4, eposm); + for (int i = 0; i < 4; i++) swap(&eposm[epm_solved[i]], &eposm[i+8]); + for (int i = 0, im = 0; i < 12; i++) + if (eposm[i]) arr->ep[i] = epm_solved[epm[im++]]; + } + + /* All the others */ + 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); +} + +Cube arrays_to_cube(CubeArray arr, PieceFilter f) { + Cube ret = {0}; + + /* Again, ep is the hardest part */ + if (f.epose) { + int epe[4], epose[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; + for (int i = 0, ie = 0; i < 12; i++) + for (int j = 0; j < 4; j++) + if (arr.ep[i] == epe_solved[j]) + { epe[ie++] = j; epose[i] = 1; } + ret.epose = factorial(4)*subset_to_index(epose,12,4)+perm_to_index(epe,4); + } + if (f.eposs) { + int eps[4], eposs[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; + for (int i = 0, is = 0; i < 12; i++) + for (int j = 0; j < 4; j++) + if (arr.ep[i] == eps_solved[j]) + { eps[is++] = j; eposs[i] = 1; } + for (int i = 0; i < 4; i++) swap(&eposs[eps_solved[i]], &eposs[i+8]); + ret.eposs = factorial(4)*subset_to_index(eposs,12,4)+perm_to_index(eps,4); + } + if (f.eposm) { + int epm[4], eposm[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; + for (int i = 0, im = 0; i < 12; i++) + for (int j = 0; j < 4; j++) + if (arr.ep[i] == epm_solved[j]) + { epm[im++] = j; eposm[i] = 1; } + for (int i = 0; i < 4; i++) swap(&eposm[epm_solved[i]], &eposm[i+8]); + ret.eposm = factorial(4)*subset_to_index(eposm,12,4)+perm_to_index(epm,4); + } + 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; +} + +bool equal(Cube c1, Cube c2) { + 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; +} + +bool solvable(Cube cube) { + /* Since we memorize orientation truncating the last digit, we only need to + * check that the permutations have the correct sign. */ + CubeArray arr = {0}; + cube_to_arrays(cube, &arr, fAll); + return (perm_sign(arr.ep,12) ^ perm_sign(arr.cpos,6)) == perm_sign(arr.cp,8); +} + +bool is_solved(Cube cube) { + return !cube.eofb && !cube.coud && !cube.cp && + !cube.epose && !cube.eposs && !cube.eposm && cube.cpos; +} + +void print_cube(Cube cube) { + CubeArray arr = {0}; + cube_to_arrays(cube, &arr, fAll); + + for (int i = 0; i < 12; i++) printf(" %s ", edge_string[arr.ep[i]]); + printf("\n"); + for (int i = 0; i < 12; i++) printf(" %c ", arr.eofb[i] + '0'); + printf("\n"); + for (int i = 0; i < 8; i++) printf("%s ", corner_string[arr.cp[i]]); + printf("\n"); + for (int i = 0; i < 8; i++) printf(" %c ", arr.coud[i] + '0'); + printf("\n"); + for (int i = 0; i < 6; i++) printf(" %s ", center_string[arr.cpos[i]]); + printf("\n"); +} + +Cube inverse_cube(Cube cube) { + CubeArray arr = {0}, inv = {0}; + cube_to_arrays(cube, &arr, fAll); + + for (int i = 0; i < 12; i++) { + inv.ep[arr.ep[i]] = i; + inv.eofb[arr.ep[i]] = arr.eofb[i]; + inv.eorl[arr.ep[i]] = arr.eorl[i]; + inv.eoud[arr.ep[i]] = arr.eoud[i]; + } + for (int i = 0; i < 8; i++) { + inv.cp[arr.cp[i]] = i; + inv.coud[arr.cp[i]] = arr.coud[i]; + inv.corl[arr.cp[i]] = arr.corl[i]; + inv.cofb[arr.cp[i]] = arr.cofb[i]; + } + for (int i = 0; i < 6; i++) + inv.cpos[arr.cpos[i]] = i; + + return arrays_to_cube(inv, fAll); +} + +Cube compose_via_arrays(CubeArray arr2, Cube c1, PieceFilter f) { + /* This is basically the same as the move_cubearray function above */ + CubeArray arr1 = {0}; + cube_to_arrays(c1, &arr1, fAll); + + apply_permutation(arr2.ep, arr1.ep, 12); + apply_permutation(arr2.ep, arr1.eofb, 12); + apply_permutation(arr2.ep, arr1.eorl, 12); + apply_permutation(arr2.ep, arr1.eoud, 12); + sum_arrays_mod(arr2.eofb, arr1.eofb, 12, 2); + sum_arrays_mod(arr2.eorl, arr1.eorl, 12, 2); + sum_arrays_mod(arr2.eoud, arr1.eoud, 12, 2); + apply_permutation(arr2.cp, arr1.cp, 8); + apply_permutation(arr2.cp, arr1.coud, 8); + apply_permutation(arr2.cp, arr1.corl, 8); + apply_permutation(arr2.cp, arr1.cofb, 8); + sum_arrays_mod(arr2.coud, arr1.coud, 8, 3); + sum_arrays_mod(arr2.corl, arr1.corl, 8, 3); + sum_arrays_mod(arr2.cofb, arr1.cofb, 8, 3); + apply_permutation(arr2.cpos, arr1.cpos, 6); + + return arrays_to_cube(arr1, fAll); +} diff --git a/old/2021-02-18-piecefilter/src/cube.h b/old/2021-02-18-piecefilter/src/cube.h new file mode 100644 index 0000000..9b64a0c --- /dev/null +++ b/old/2021-02-18-piecefilter/src/cube.h @@ -0,0 +1,45 @@ +#ifndef CUBE_H +#define CUBE_H + +#include +#include +#include +#include "utils.h" + +typedef enum {U_center,D_center,R_center,L_center,F_center,B_center} Center; +typedef enum { UF, UL, UB, UR, DF, DL, DB, DR, FR, FL, BL, BR } Edge; +typedef enum { UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR } Corner; + +typedef struct { + bool epose, eposs, eposm, eofb, eorl, eoud, cp, coud, cofb, corl, cpos; +} PieceFilter; + +typedef struct { + uint16_t eofb, eorl, eoud, coud, cofb, corl, + epose, eposs, eposm, cp, cpos; +} Cube; + +typedef struct { + int ep[12], eofb[12], eorl[12], eoud[12], + cp[8], coud[8], corl[8], cofb[8], cpos[6]; +} CubeArray; + + +extern PieceFilter fAll; + +Cube blank_cube(); +/* Return axis (ud=0, rl=1, fb=0) of center c */ +int center_axis(int c); +/* Return slice (e=0, s=1, m=2) to which e belongs */ +int edge_slice(int e); +void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f); +Cube arrays_to_cube(CubeArray arr, PieceFilter f); +bool equal(Cube c1, Cube c2); +bool is_solvable(Cube cube); +bool is_solved(Cube cube); +void print_cube(Cube cube); +Cube inverse_cube(Cube cube); +/* Use c2 as an alg on c1 */ +Cube compose_via_arrays(CubeArray c2, Cube c1, PieceFilter f); + +#endif diff --git a/old/2021-02-18-piecefilter/src/main.c b/old/2021-02-18-piecefilter/src/main.c new file mode 100644 index 0000000..0b5de2e --- /dev/null +++ b/old/2021-02-18-piecefilter/src/main.c @@ -0,0 +1,47 @@ +#include +#include "cube.h" +#include "moves.h" +#include "solve.h" + +int main() { + init_ttables(true, true); + init_aux_tables(); + + + char moves[100] = "MR U' B2 Bw F z xE2 M' x Dw' y Fw2 y2"; + NissMove alg[100]; + read_moves(moves, alg, 100); + Cube cube = apply_alg(alg, blank_cube()); + + /*f_eofb(cube);*/ + + +/* NissMove sol[MAXS][MAXM];*/ + SolveData d = { .optimal_only = true, .available = standard_moveset, + .max_moves = 10, + .cleanup = true, + .max_solutions = 10, + .f = f_eofb }; + read_moves("y", d.pre_rotation, 2); + int n = solve(cube, &d); + printf("%d solutions found:\n", n); + for (int i = 0; i < n; i++) + print_moves(d.solutions[i]); + + NissMove a[5], b[5]; + read_moves("R", a, 5); + read_moves("U", b, 5); + Cube c1 = apply_alg(a,blank_cube()), c2 = apply_alg(b,blank_cube()); + print_cube(compose(c2,c1)); + print_cube(compose(c1,c2)); + /*print_cube(compose(c2,blank_cube()));*/ + + NissMove nm[10]; + read_moves("y(y)RU", nm, 10); + + print_moves(nm); + cleanup(nm, 10); + print_moves(nm); + + return 0; +} diff --git a/old/2021-02-18-piecefilter/src/moves.c b/old/2021-02-18-piecefilter/src/moves.c new file mode 100644 index 0000000..7cccbdf --- /dev/null +++ b/old/2021-02-18-piecefilter/src/moves.c @@ -0,0 +1,482 @@ +#include "moves.h" + +void move_cubearray(Move m, CubeArray *arr, PieceFilter f); +Cube move_via_array(Move m, Cube cube, PieceFilter f); +void sort_cancel_rotate(NissMove *alg, int n, bool inv, int top, int front); +bool read_ttables_file(); +bool write_ttables_file(); + +/* Transition tables */ +uint16_t epose_ttable[NMOVES][factorial12/factorial8]; +uint16_t eposs_ttable[NMOVES][factorial12/factorial8]; +uint16_t eposm_ttable[NMOVES][factorial12/factorial8]; +uint16_t eofb_ttable[NMOVES][pow2to11]; +uint16_t eorl_ttable[NMOVES][pow2to11]; +uint16_t eoud_ttable[NMOVES][pow2to11]; +uint16_t cp_ttable[NMOVES][factorial8]; +uint16_t coud_ttable[NMOVES][pow3to7]; +uint16_t cofb_ttable[NMOVES][pow3to7]; +uint16_t corl_ttable[NMOVES][pow3to7]; +uint16_t cpos_ttable[NMOVES][factorial6]; + +bool commute[NMOVES][NMOVES]; +bool possible_next[NMOVES][NMOVES][NMOVES]; +Move inverse[NMOVES]; + +char move_string[NMOVES][5] = + { "-", + "U", "U2", "U\'", "D", "D2", "D\'", "R", "R2", "R\'", + "L", "L2", "L\'", "F", "F2", "F\'", "B", "B2", "B\'", + "Uw", "Uw2", "Uw\'", "Dw", "Dw2", "Dw\'", "Rw", "Rw2", "Rw\'", + "Lw", "Lw2", "Lw\'", "Fw", "Fw2", "Fw\'", "Bw", "Bw2", "Bw\'", + "M", "M2", "M\'", "S", "S2", "S\'", "E", "E2", "E\'", + "x", "x2", "x\'", "y", "y2", "y\'", "z", "z2", "z\'" }; + +/* For each type of pieces only the effects of U, x and y are described */ +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} }; +int eofb_flipped[NMOVES][12] = + { [x] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 }, + [y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 } }; +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 } }; +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 } }; +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} }; +int coud_flipped[NMOVES][8] = + { [x] = {[UFR]=2,[UBR]=1,[DBR]=2,[DFR]=1,[UFL]=1,[UBL]=2,[DBL]=1,[DFL]=2} }; +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} }; +int cofb_flipped[NMOVES][8] = + { [U] = { [UFR] = 2, [UBR] = 1, [UBL] = 2, [UFL] = 1 }, + [x] = {[UFR]=1,[UBR]=2,[DFR]=2,[DBR]=1,[UBL]=2,[UFL]=1,[DBL]=1,[DFL]=2}, + [y] = {[UFR]=2,[UBR]=1,[UBL]=2,[UFL]=1,[DFR]=1,[DBR]=2,[DBL]=1,[DFL]=2} }; +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} }; + +/* Each move is reduced to a combination of U, x and y using this table */ +Move equiv_moves[NMOVES][14] = { + [U] = { U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [U2] = { U, U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [U3] = { U, U, U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [D] = { x, x, U, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [D2] = { x, x, U, U, x, x, 0, 0, 0, 0, 0, 0, 0, 0 }, + [D3] = { x, x, U, U, U, x, x, 0, 0, 0, 0, 0, 0, 0 }, + [R] = { y, x, U, x, x, x, y, y, y, 0, 0, 0, 0, 0 }, + [R2] = { y, x, U, U, x, x, x, y, y, y, 0, 0, 0, 0 }, + [R3] = { y, x, U, U, U, x, x, x, y, y, y, 0, 0, 0 }, + [L] = { y, y, y, x, U, x, x, x, y, 0, 0, 0, 0, 0 }, + [L2] = { y, y, y, x, U, U, x, x, x, y, 0, 0, 0, 0 }, + [L3] = { y, y, y, x, U, U, U, x, x, x, y, 0, 0, 0 }, + [F] = { x, U, x, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [F2] = { x, U, U, x, x, x, 0, 0, 0, 0, 0, 0, 0, 0 }, + [F3] = { x, U, U, U, x, x, x, 0, 0, 0, 0, 0, 0, 0 }, + [B] = { x, x, x, U, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [B2] = { x, x, x, U, U, x, 0, 0, 0, 0, 0, 0, 0, 0 }, + [B3] = { x, x, x, U, U, U, x, 0, 0, 0, 0, 0, 0, 0 }, + + [Uw] = { x, x, U, x, x, y, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Uw2] = { x, x, U, U, x, x, y, y, 0, 0, 0, 0, 0, 0 }, + [Uw3] = { x, x, U, U, U, x, x, y, y, y, 0, 0, 0, 0 }, + [Dw] = { U, y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Dw2] = { U, U, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Dw3] = { U, U, U, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Rw] = { y, y, y, x, U, x, x, x, y, x, 0, 0, 0, 0 }, + [Rw2] = { y, y, y, x, U, U, x, x, x, y, x, x, 0, 0 }, + [Rw3] = { y, y, y, x, U, U, U, y, x, x, x, y, 0, 0 }, + [Lw] = { y, x, U, x, x, x, y, y, y, x, x, x, 0, 0 }, + [Lw2] = { y, x, U, U, x, x, x, y, y, y, x, x, 0, 0 }, + [Lw3] = { y, x, U, U, U, x, x, x, y, y, y, x, 0, 0 }, + [Fw] = { x, x, x, U, y, y, y, x, 0, 0, 0, 0, 0, 0 }, + [Fw2] = { x, x, x, U, U, y, y, x, 0, 0, 0, 0, 0, 0 }, + [Fw3] = { x, x, x, U, U, U, y, x, 0, 0, 0, 0, 0, 0 }, + [Bw] = { x, U, y, y, y, x, x, x, 0, 0, 0, 0, 0, 0 }, + [Bw2] = { x, U, U, y, y, x, x, x, 0, 0, 0, 0, 0, 0 }, + [Bw3] = { x, U, U, U, y, x, x, x, 0, 0, 0, 0, 0, 0 }, + + [M] = { y, x, U, x, x, U, U, U, y, x, y, y, y, 0 }, + [M2] = { y, x, U, U, x, x, U, U, x, x, x, y, 0, 0 }, + [M3] = { y, x, U, U, U, x, x, U, y, x, x, x, y, 0 }, + [S] = { x, U, U, U, x, x, U, y, y, y, x, 0, 0, 0 }, + [S2] = { x, U, U, x, x, U, U, y, y, x, 0, 0, 0, 0 }, + [S3] = { x, U, x, x, U, U, U, y, x, 0, 0, 0, 0, 0 }, + [E] = { U, x, x, U, U, U, x, x, y, y, y, 0, 0, 0 }, + [E2] = { U, U, x, x, U, U, x, x, y, y, 0, 0, 0, 0 }, + [E3] = { U, U, U, x, x, U, x, x, y, 0, 0, 0, 0, 0 }, + + [x] = { x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [x2] = { x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [x3] = { x, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [y] = { y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [y2] = { y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [y3] = { y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [z] = { y, y, y, x, y, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [z2] = { y, y, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [z3] = { y, x, y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +}; + +/* Movesets */ +bool standard_moveset[NMOVES] = { + [U] = true, [U2] = true, [U3] = true, [D] = true, [D2] = true, [D3] = true, + [R] = true, [R2] = true, [R3] = true, [L] = true, [L2] = true, [L3] = true, + [F] = true, [F2] = true, [F3] = true, [B] = true, [B2] = true, [B3] = true, +}; + +bool is_solved_up_to_reorient(Cube cube) { + if (is_solved(cube)) + return true; + + /*TODO: improve this crap */ + + bool ret = false; + for (int i = x; i <= z3; i++) { + ret = ret || is_solved(move_cube(i, cube)); + for (int j = x; j <= z3; j++) + ret = ret || is_solved(move_cube(i, move_cube(j, cube))); + } + return ret; +} + +void move_cubearray(Move m, CubeArray *arr, PieceFilter f) { + if (f.epose || f.eposs || f.eposm) + apply_permutation(edge_cycle[m], arr->ep, 12); + if (f.eofb) { + apply_permutation(edge_cycle[m], arr->eofb, 12); + sum_arrays_mod(eofb_flipped[m], arr->eofb, 12, 2); + } + if (f.eorl) { + apply_permutation(edge_cycle[m], arr->eorl, 12); + sum_arrays_mod(eorl_flipped[m], arr->eorl, 12, 2); + } + if (f.eoud) { + apply_permutation(edge_cycle[m], arr->eoud, 12); + sum_arrays_mod(eoud_flipped[m], arr->eoud, 12, 2); + } + if (f.cp) + apply_permutation(corner_cycle[m], arr->cp, 8); + if (f.coud) { + apply_permutation(corner_cycle[m], arr->coud, 8); + sum_arrays_mod(coud_flipped[m], arr->coud, 8, 3); + } + if (f.corl) { + apply_permutation(corner_cycle[m], arr->corl, 8); + sum_arrays_mod(corl_flipped[m], arr->corl, 8, 3); + } + if (f.cofb) { + apply_permutation(corner_cycle[m], arr->cofb, 8); + sum_arrays_mod(cofb_flipped[m], arr->cofb, 8, 3); + } + if (f.cpos) + apply_permutation(center_cycle[m], arr->cpos, 6); +} + +Cube move_via_array(Move m, Cube cube, PieceFilter f) { + CubeArray arr = {0}; + cube_to_arrays(cube, &arr, f); + move_cubearray(m, &arr, f); + return arrays_to_cube(arr, f); +} + +int copy_alg(NissMove *src, NissMove *dest) { + int i; + for (i = 0; src[i].m != NULLMOVE; i++) + dest[i] = src[i]; + dest[i].m = NULLMOVE; + return i; +} + +/* TODO: all strings start with space?? */ +void print_moves(NissMove *alg) { + bool niss = false; + for (int i = 0; alg[i].m != NULLMOVE; i++) { + char *fill = !niss && alg[i].inverse ? " (" : + (niss && !alg[i].inverse ? ") " : " "); + printf("%s%s", fill, move_string[alg[i].m]); + niss = alg[i].inverse; + } + printf("%s\n", niss ? ")" : ""); +} + +int read_moves(char *str, NissMove *alg, int n) { + bool niss = false; + int c = 0; + + for (int i = 0; str[i] && c < n; i++) { + if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n') + continue; + + if (str[i] == '(' || str[i] == ')') { + if ((niss && str[i] == '(') || (!niss && str[i] == ')')) + return -1; + niss = !niss; + continue; + } + + alg[c].inverse = niss; alg[c].m = NULLMOVE; + for (Move j = 0; j < NMOVES; j++) { + if (str[i] == move_string[j][0]) { + alg[c].m = j; + if (alg[c].m <= B && str[i+1]=='w') { alg[c].m += Uw - U; i++; } + if (str[i+1]=='2') { alg[c].m += 1; i++; } + else if (str[i+1]=='\'' || str[i+1]=='3') { alg[c].m += 2; i++; } + c++; + break; + } + } + } + + alg[c].m = NULLMOVE; + return c; +} + +/* Helper function for cleanup. alg must contain only basic moves, no 2 or '. + top and front describe an admissible orientation of the cube. */ +void sort_cancel_rotate(NissMove *alg, int n, bool inv, int top, int front) { + int c = 0, i = 0; + PieceFilter cpos_only = { .cpos = true }; + NissMove aux[n+3]; + aux[0].m = NULLMOVE; + + while (i < n && alg[i].m != NULLMOVE) { + int j = i; + while (j < n && commute[alg[i].m][alg[j].m]) j++; + Move base = 6*((alg[i].m-1)/6); + int t1 = 0, t2 = 0; + for (int k = i; k < j; k++) + if (alg[k].m == base+1) t1 = (t1+1)%4; + else t2 = (t2+1)%4; + if (t1) { aux[c].inverse = inv; aux[c].m = base+t1; c++; } + if (t2) { aux[c].inverse = inv; aux[c].m = base+t2+3; c++; } + i = j; + } + aux[c].m = NULLMOVE; + + CubeArray q; + cube_to_arrays(blank_cube(), &q, cpos_only); + /* First we try to rotate in one move, then we try an x or y rotation + followed by a z rotation */ + for (int r = x; r <= z3; r++) { + move_cubearray(r, &q, cpos_only); + if (q.cpos[F_center] == front && q.cpos[U_center] == top) { + aux[c].inverse = inv; aux[c].m = r; + + aux[++c].m = NULLMOVE; + copy_alg(aux, alg); + return; + } + move_cubearray(inverse[r], &q, cpos_only); + } + for (int r = x; r <= y3; r++) { + move_cubearray(r, &q, cpos_only); + if (q.cpos[F_center] == front) { + aux[c].inverse = inv; aux[c++].m = r; + break; + } + move_cubearray(inverse[r], &q, cpos_only); + } + for (int r = z; r <= z3; r++) { + move_cubearray(r, &q, cpos_only); + if (q.cpos[U_center] == top) { + aux[c].inverse = inv; aux[c++].m = r; + break; + } + move_cubearray(inverse[r], &q, cpos_only); + } + + aux[c].m = NULLMOVE; + copy_alg(aux, alg); +} + +/* TODO: does not work with niss + rotations */ +void cleanup(NissMove *alg, int n) { + int count_n = 0, count_i = 0, *count; + PieceFilter cpos_only = { .cpos = true }; + NissMove aux_n[n+1], aux_i[n+1], *aux; + CubeArray cube_n, cube_i, *cube; + cube_to_arrays(blank_cube(), &cube_n, cpos_only); + cube_to_arrays(blank_cube(), &cube_i, cpos_only); + + for (int i = 0; count_n + count_i < n && alg[i].m != NULLMOVE; i++) { + if (alg[i].inverse) { count = &count_i; aux = aux_i; cube = &cube_i; } + else { count = &count_n; aux = aux_n; cube = &cube_n; } + + for (int j = 0; equiv_moves[alg[i].m][j]; j++) { + Move m = equiv_moves[alg[i].m][j]; + aux[*count].inverse = alg[i].inverse; + move_cubearray(m, cube, cpos_only); + if (m == U) aux[(*count)++].m = 3 * cube->cpos[0] + 1; + } + } + + aux_n[count_n].m = NULLMOVE; + aux_i[count_i].m = NULLMOVE; + sort_cancel_rotate(aux_n, count_n, false, cube_n.cpos[0], cube_n.cpos[4]); + sort_cancel_rotate(aux_i, count_i, true, cube_i.cpos[0], cube_n.cpos[4]); + copy_alg(aux_n, alg); + copy_alg(aux_i, alg+count_n); +} + +bool read_ttables_file() { + FILE *ttf; + if ((ttf = fopen("ttables", "rb")) != NULL) { + for (int m = 0; m < NMOVES; m++) { + fread(epose_ttable[m], sizeof(uint16_t), factorial12/factorial8, ttf); + fread(eposs_ttable[m], sizeof(uint16_t), factorial12/factorial8, ttf); + fread(eposm_ttable[m], sizeof(uint16_t), factorial12/factorial8, ttf); + fread(eofb_ttable[m], sizeof(uint16_t), pow2to11, ttf); + fread(eorl_ttable[m], sizeof(uint16_t), pow2to11, ttf); + fread(eoud_ttable[m], sizeof(uint16_t), pow2to11, ttf); + fread(cp_ttable[m], sizeof(uint16_t), factorial8, ttf); + fread(coud_ttable[m], sizeof(uint16_t), pow3to7, ttf); + fread(corl_ttable[m], sizeof(uint16_t), pow3to7, ttf); + fread(cofb_ttable[m], sizeof(uint16_t), pow3to7, ttf); + fread(cpos_ttable[m], sizeof(uint16_t), factorial6, ttf); + } + fclose(ttf); + return true; + } else return false; +} + +bool write_ttables_file() { + FILE *ttf; + if ((ttf = fopen("ttables", "wb")) != NULL) { + for (int m = 0; m < NMOVES; m++) { + fwrite(epose_ttable[m], sizeof(uint16_t), factorial12/factorial8, ttf); + fwrite(eposs_ttable[m], sizeof(uint16_t), factorial12/factorial8, ttf); + fwrite(eposm_ttable[m], sizeof(uint16_t), factorial12/factorial8, ttf); + fwrite(eofb_ttable[m], sizeof(uint16_t), pow2to11, ttf); + fwrite(eorl_ttable[m], sizeof(uint16_t), pow2to11, ttf); + fwrite(eoud_ttable[m], sizeof(uint16_t), pow2to11, ttf); + fwrite(cp_ttable[m], sizeof(uint16_t), factorial8, ttf); + fwrite(coud_ttable[m], sizeof(uint16_t), pow3to7, ttf); + fwrite(corl_ttable[m], sizeof(uint16_t), pow3to7, ttf); + fwrite(cofb_ttable[m], sizeof(uint16_t), pow3to7, ttf); + fwrite(cpos_ttable[m], sizeof(uint16_t), factorial6, ttf); + } + fclose(ttf); + return true; + } else return false; +} + +void init_ttables(bool read, bool write) { + /* Generate all move cycles and flips; I do this regardless */ + for (int i = 0; i < NMOVES; i++) { + if (i == U || i == x || i == y) + continue; + + CubeArray arr = {0}; + cube_to_arrays(blank_cube(), &arr, fAll); + for (int j = 0; equiv_moves[i][j]; j++) + move_cubearray(equiv_moves[i][j], &arr, fAll); + + intarrcopy(arr.ep, edge_cycle[i], 12); + intarrcopy(arr.eofb, eofb_flipped[i], 12); + intarrcopy(arr.eorl, eorl_flipped[i], 12); + intarrcopy(arr.eoud, eoud_flipped[i], 12); + intarrcopy(arr.cp, corner_cycle[i], 8); + intarrcopy(arr.coud, coud_flipped[i], 8); + intarrcopy(arr.corl, corl_flipped[i], 8); + intarrcopy(arr.cofb, cofb_flipped[i], 8); + intarrcopy(arr.cpos, center_cycle[i], 6); + } + + if (read) + if (read_ttables_file()) + return; + + /* Initialize transition tables */ + Cube c = {0}; + PieceFilter fe = {.epose=true}, fs = {.eposs=true}, fm = {.eposm=true}; + PieceFilter feo = { .eofb = true, .eorl = true, .eoud = true }; + PieceFilter fcp = { .cp = true }; + PieceFilter fco = { .cofb = true, .corl = true, .coud = true }; + PieceFilter fcc = { .cpos = true }; + for (int m = 0; m < NMOVES; m++) { + for (uint16_t i = 0; i < factorial12/factorial8; i++) { + c.epose = i; epose_ttable[m][i] = move_via_array(m, c, fe).epose; + c.eposs = i; eposs_ttable[m][i] = move_via_array(m, c, fs).eposs; + c.eposm = i; eposm_ttable[m][i] = move_via_array(m, c, fm).eposm; + } + for (uint16_t i = 0; i < pow2to11; i++ ) { + c.eofb = i; eofb_ttable[m][i] = move_via_array(m, c, feo).eofb; + c.eorl = i; eorl_ttable[m][i] = move_via_array(m, c, feo).eorl; + c.eoud = i; eoud_ttable[m][i] = move_via_array(m, c, feo).eoud; + } + for (uint16_t i = 0; i < factorial8; i++) { + c.cp = i; cp_ttable[m][i] = move_via_array(m, c, fcp).cp; + } + for (uint16_t i = 0; i < pow3to7; i++) { + c.coud = i; coud_ttable[m][i] = move_via_array(m, c, fco).coud; + c.corl = i; corl_ttable[m][i] = move_via_array(m, c, fco).corl; + c.cofb = i; cofb_ttable[m][i] = move_via_array(m, c, fco).cofb; + } + for (uint16_t i = 0; i < factorial6; i++) { + c.cpos = i; cpos_ttable[m][i] = move_via_array(m, c, fcc).cpos; + } + } + + if (write) write_ttables_file(); +} + +Cube move_cube(Move m, Cube cube) { + Cube moved = cube; + + moved.epose = epose_ttable[m][cube.epose]; + moved.eposs = eposs_ttable[m][cube.eposs]; + moved.eposm = eposm_ttable[m][cube.eposm]; + moved.eofb = eofb_ttable[m][cube.eofb]; + moved.eorl = eorl_ttable[m][cube.eorl]; + moved.eoud = eoud_ttable[m][cube.eoud]; + moved.coud = coud_ttable[m][cube.coud]; + moved.cofb = cofb_ttable[m][cube.cofb]; + moved.corl = corl_ttable[m][cube.corl]; + moved.cp = cp_ttable[m][cube.cp]; + moved.cpos = cpos_ttable[m][cube.cpos]; + + return moved; +} + +Cube apply_alg(NissMove *alg, Cube cube) { + Cube ret = {0}; + for (int i = 0; alg[i].m != NULLMOVE; i++) + if (alg[i].inverse) + ret = move_cube(alg[i].m, ret); + ret = compose(cube, inverse_cube(ret)); + + for (int i = 0; alg[i].m != NULLMOVE; i++) + if (!alg[i].inverse) + ret = move_cube(alg[i].m, ret); + return ret; +} + +void init_aux_tables() { + /* Commute */ + for (int i = 0; i < NMOVES; i++) + for (int j = 0; j < NMOVES; j++) + commute[i][j] = equal(move_cube(i, move_cube(j, blank_cube())), + move_cube(j, move_cube(i, blank_cube()))); + + /* Possible next (if the sequence i j k is valid) */ + for (int i = 0; i < NMOVES; i++) + for (int j = 0; j < NMOVES; j++) + for (int k = 0; k < NMOVES; k++) + possible_next[i][j][k] = + (j == 0) || + (j != 0 && (j-(j-1)%3) != (k-(k-1)%3) && + !(i != 0 && commute[i][j] && (i-(i-1)%3) == (k-(k-1)%3))); + + /* Inverse */ + for (int i = 0; i < NMOVES; i++) + inverse[i] = i == 0 ? 0 : i + 2 - 2*((i-1)%3); +} + diff --git a/old/2021-02-18-piecefilter/src/moves.h b/old/2021-02-18-piecefilter/src/moves.h new file mode 100644 index 0000000..9ccf6e4 --- /dev/null +++ b/old/2021-02-18-piecefilter/src/moves.h @@ -0,0 +1,46 @@ +#ifndef MOVES_H +#define MOVES_H + +#include +#include +#include +#include "cube.h" +#include "utils.h" + +#define NMOVES (z3+1) + +typedef enum { + NULLMOVE, + U, U2, U3, D, D2, D3, R, R2, R3, L, L2, L3, F, F2, F3, B, B2, B3, + Uw, Uw2, Uw3, Dw, Dw2, Dw3, Rw, Rw2, Rw3, + Lw, Lw2, Lw3, Fw, Fw2, Fw3, Bw, Bw2, Bw3, + M, M2, M3, S, S2, S3, E, E2, E3, + x, x2, x3, y, y2, y3, z, z2, z3, +} Move; + +/* An alg is an array of "NissMoves", which can be on normal or on inverse. */ +typedef struct { bool inverse; Move m; } NissMove; + +/* Movesets */ +extern bool standard_moveset[NMOVES]; + +extern bool commute[NMOVES][NMOVES]; +extern bool possible_next[NMOVES][NMOVES][NMOVES]; +extern Move inverse[NMOVES]; + +bool is_solve_up_to_reorient(Cube cube); +int copy_alg(NissMove *src, NissMove *dest); /*return number of moves copied */ +void print_moves(NissMove *alg); +int read_moves(char *str, NissMove *alg, int n); /* reads at most n moves */ +void cleanup(NissMove *src, int n); /* rewrites using basic moves, at most n */ +Cube move_cube(Move m, Cube cube); +/* I might want to replace this with two versions, one that uses PieceFilter */ +Cube apply_alg(NissMove *alg, Cube cube); + +/* Merge the following two? + always in this order */ +void init_ttables(bool read, bool write); +void init_aux_tables(); + + +#endif diff --git a/old/2021-02-18-piecefilter/src/solve.c b/old/2021-02-18-piecefilter/src/solve.c new file mode 100644 index 0000000..ac19d6f --- /dev/null +++ b/old/2021-02-18-piecefilter/src/solve.c @@ -0,0 +1,179 @@ +#include "solve.h" + +/* Data for creating a pruning table: + - compressed: if set to true, each entry occupies only 4 bits, but values + larger than 15 cannot be stored. + - available[] is the list of availabel moves, as above. + - *ptable is the actual table to fill. + - n is the number of states (size of ptable). + - index must "linearize" the cube, i.e. return its index in ptable. + - fname is the name of the file where to store the table */ +typedef struct { + bool compressed, *available; + int max_moves; + uint8_t *ptable; + uint64_t n; + uint64_t (*index)(Cube); + char *fname; +} PruneData; + +/* TODO: comment this */ +typedef struct { + bool niss; + int m, d; + uint64_t *n; + Move last1, last2; +} DfsData; + +void solve_dfs(Cube cube, SolveData *sd, DfsData dd); +void init_ptable(PruneData *pd, bool read, bool write); + +/* Search solutions of lenght exactly d */ +void solve_dfs(Cube cube, SolveData *sd, DfsData dd) { + if (*dd.n >= sd->max_solutions || + ((!sd->can_niss || dd.niss) && dd.m + sd->f(cube) > dd.d)) + return; + + (sd->solutions[*dd.n][dd.m]).inverse = dd.niss; + (sd->solutions[*dd.n][dd.m]).m = NULLMOVE; + + if (!sd->f(cube)) { /* Solved */ + if (dd.m == dd.d) { + (*dd.n)++; + if (*dd.n < sd->max_solutions) + copy_alg(sd->solutions[*dd.n-1], sd->solutions[*dd.n]); + } + return; + } + + for (int i = 0; i < NMOVES && sd->sorted_moves[i] != NULLMOVE; i++) { + Move move = sd->sorted_moves[i]; + if (possible_next[dd.last2][dd.last1][move]) { + sd->solutions[*dd.n][dd.m].inverse = dd.niss; + sd->solutions[*dd.n][dd.m].m = move; + DfsData nn = { .niss = dd.niss, .m = dd.m+1, .d = dd.d, .n = dd.n, + .last1 = move, .last2 = dd.last1 }; + solve_dfs(move_cube(move, cube), sd, nn); + } + } + + if (sd->can_niss && !dd.niss && + (!dd.m || (dd.m && sd->f(move_cube(dd.last1, blank_cube()))))) { + DfsData nn = { .niss = true, .m = dd.m, .d = dd.d, .n = dd.n }; + solve_dfs(inverse_cube(cube), sd, nn); + } +} + +/* Iterative deepening depth-first search: for i running from the minimum + to the maximum number of moves allowed, looks for solutions of length i. */ +int solve(Cube cube, SolveData *sd) { + if (sd->precondition != NULL && !sd->precondition(cube)) + return -1; + + /* If not given, generate sorted list of moves */ + if (sd->sorted_moves[0] == NULLMOVE) { + int a[NMOVES], b[NMOVES], ia = 0, ib = 0; + for (int i = 0; i < NMOVES; i++) { + if (sd->available[i]) { + if (sd->f(move_cube(i, blank_cube()))) + a[ia++] = i; + else + b[ib++] = i; + } + } + intarrcopy(a, (int *)sd->sorted_moves, ia); + intarrcopy(b, (int *)sd->sorted_moves+ia, ib); + sd->sorted_moves[ia+ib] = NULLMOVE; + } + + sd->max_solutions = min(sd->max_solutions, MAXS); + /*TODO + Cube rotated = apply_alg(sd->pre_rotation, blank_cube()); + cube = apply_alg(inverse_cube(rotated), compose(cube, rotated)); + */ + + uint64_t ret = 0; + for (int i=sd->min_moves; i<=sd->max_moves&&!(ret&&sd->optimal_only); i++) { + DfsData dd = { .d = i, .n = &ret }; + solve_dfs(cube, sd, dd); + } + + for (uint64_t i = 0; i < ret; i++) { + /* TODO: transform solutions with inverse of pre_rotation */ + if (sd->cleanup) + cleanup(sd->solutions[i], sd->max_moves*3); + } + + return ret; +} + +void prune_dfs(Cube cube, PruneData *pd, DfsData dd) { + uint64_t ind = pd->index(cube); + if ((!ind || pd->ptable[ind]) && pd->ptable[ind] != dd.m) + return; + if (dd.m == dd.d) { + if (ind && !pd->ptable[ind]) { + pd->ptable[ind] = dd.m; + (*dd.n)++; + } + return; + } + + for (int i = 0; i < NMOVES; i++) { + if (dd.m<20) + if (possible_next[dd.last2][dd.last1][i] && pd->available[i]) { + DfsData nn = { .m = dd.m+1, .d = dd.d, .n = dd.n, + .last1 = i, .last2 = dd.last1 }; + prune_dfs(move_cube(i, cube), pd, nn); + } + } +} + +void init_ptable(PruneData *pd, bool read, bool write) { + if (read) { + FILE *ptf; + if ((ptf = fopen(pd->fname, "rb")) != NULL) { + fread(pd->ptable, sizeof(uint8_t), pd->n, ptf); + fclose(ptf); + return; + } + } + + /* TODO: for now it behaves always as if copressed = false */ + for (uint64_t i = 0; i < pd->n; i++) + pd->ptable[i] = 0; + + uint64_t s = 1; + for (int i = 1; i < pd->max_moves && s < pd->n; i++) { + DfsData dd = { .d = i, .n = &s }; + prune_dfs(blank_cube(), pd, dd); + } + + if (write) { + FILE *ptf; + if ((ptf = fopen(pd->fname, "wb")) != NULL) { + fwrite(pd->ptable, sizeof(uint8_t), pd->n, ptf); + fclose(ptf); + return; + } + } +} + +/* Solving steps (and indexing functions) */ + +uint64_t index_eofb(Cube cube) { return cube.eofb; } +uint16_t f_eofb(Cube cube) { + static bool initialized_ptable; + static uint8_t pt_eofb[pow2to11]; + if (!initialized_ptable) { + PruneData pd = { + .compressed = false, .available = standard_moveset, .max_moves = 13, + .ptable = pt_eofb, .n = pow2to11, .index = index_eofb, + .fname = "ptable_eofb" + }; + init_ptable(&pd, false, true); + initialized_ptable = true; + } + return cube.eofb ? pt_eofb[cube.eofb] : 0; +} + diff --git a/old/2021-02-18-piecefilter/src/solve.h b/old/2021-02-18-piecefilter/src/solve.h new file mode 100644 index 0000000..d585a8e --- /dev/null +++ b/old/2021-02-18-piecefilter/src/solve.h @@ -0,0 +1,56 @@ +#ifndef SOLVE_H +#define SOLVE_H + +#include +#include "cube.h" +#include "moves.h" + +/* Maximum number of moves per solution and of solutions */ +#define MAXM 30 +#define MAXS 999 + +/* Data for solving a step: + - can_niss is true niss can be used, false otherwise. + - optimal_only if true, dynamically updates max_moves so non-optimal + solutions are discarded. + - cleanup determines whether the cleaunup() function should be used on + the found solutions before returning. + - available[m] is true if the move m can be used, false otherwise. + - min_moves and max_moves are the minimum and maximum number of moves that + can be used. + - max_solution is the maximum number of solutions that can be returned. + - precondition can be used to check wheter the step can actually be applied + to the cube. If it returns false, solve() stops immediately returning -1. + - f must return 0 if and only if the step is solve, otherwise it must return + a lower bound for the number of moves required (without niss). + - sorted_moves[] can be used to specify in which order moves are tried + by the solving algorithm (for example if one wants to always try F' before + F). If sorted_moves[0] == NULLMOVE, the list is generated automatically. + It is advised to list first all the moves that actually influence the + solved state of the step (this is the default choice). This is in order to + avoid cases like B2 F for EO and to NISS only when it makes sense. + - start_moves [Currently unused, REMOVE] + are the moves that will be used as first moves of all + solutions. For example giving R' U' F (F' U R) will generate FMC scrambles + and y (y) will solve the step on another axis. + - pre_rotation are the rotations to apply before the scamble to solve + the step wrt a different orientation + - pre_rotation are the rotations to apply before the scamble to solve + the step wth respect to a different orientation. + - solutions[][] is the array where to store the found solutions. */ +typedef struct { + bool can_niss, optimal_only, cleanup, *available; + int min_moves, max_moves; + uint64_t max_solutions; + bool (*precondition)(Cube); + uint16_t (*f)(Cube); + Move sorted_moves[NMOVES]; + NissMove pre_rotation[3], solutions[MAXS][MAXM]; +} SolveData; + +int solve(Cube cube, SolveData *data); /* Returns the number of solutions. */ + +/* Steps */ +uint16_t f_eofb(Cube cube); + +#endif diff --git a/old/2021-02-18-piecefilter/src/transformations.c b/old/2021-02-18-piecefilter/src/transformations.c new file mode 100644 index 0000000..bcf4115 --- /dev/null +++ b/old/2021-02-18-piecefilter/src/transformations.c @@ -0,0 +1,103 @@ +#include "transformations.h" +/* +Cube apply_rotation_alg(Rotation r, Cube c); +void apply_rotation_cube(NissMove *alg); +Cube apply_mirror_cube(Cube c); +void apply_mirror_alg(NissMove *alg); +*/ + +void compute_sources(); +Cube rotate_via_compose(Rotation r, Cube c); + +/* Values mod 3 to determine from which side to take the state to convert */ +int epose_source[NROTATIONS]; /* 0 = epose, 1 = eposs, 2 = eposm */ +int eposs_source[NROTATIONS]; +int eposm_source[NROTATIONS]; +int eofb_source[NROTATIONS]; /* 0 = eofb, 1 = eorl, 2 = eoud */ +int eorl_source[NROTATIONS]; +int eoud_source[NROTATIONS]; +int coud_source[NROTATIONS]; /* 0 = coud, 1 = cofb, 2 = corl */ +int cofb_source[NROTATIONS]; +int corl_source[NROTATIONS]; + +/* Transition tables for rotations */ +uint16_t epose_rtable[NROTATIONS][factorial12/factorial8]; +uint16_t eposs_rtable[NROTATIONS][factorial12/factorial8]; +uint16_t eposm_rtable[NROTATIONS][factorial12/factorial8]; +uint16_t eofb_rtable[NROTATIONS][pow2to11]; +uint16_t eorl_rtable[NROTATIONS][pow2to11]; +uint16_t eoud_rtable[NROTATIONS][pow2to11]; +uint16_t cp_rtable[NROTATIONS][factorial8]; +uint16_t coud_rtable[NROTATIONS][pow3to7]; +uint16_t cofb_rtable[NROTATIONS][pow3to7]; +uint16_t corl_rtable[NROTATIONS][pow3to7]; + +/* Transition tables for mirror */ +uint16_t epose_mtable[factorial12/factorial8]; +uint16_t eposs_mtable[factorial12/factorial8]; +uint16_t eposm_mtable[factorial12/factorial8]; +uint16_t eofb_mtable[pow2to11]; +uint16_t eorl_mtable[pow2to11]; +uint16_t eoud_mtable[pow2to11]; +uint16_t cp_mtable[factorial8]; +uint16_t coud_mtable[pow3to7]; +uint16_t cofb_mtable[pow3to7]; +uint16_t corl_mtable[pow3to7]; + +/* Same for moves */ +uint16_t move_rtable[NROTATIONS][NMOVES]; +uint16_t move_mtable[NMOVES]; + +/* Applying a rotation to the cube is equivalent to applying m (m) */ +Move equiv_moves[NROTATIONS][3] = { + [uf] = {0,0,0}, [ur] = {y,0,0}, [ub] = {y2,0,0}, [ul] = {y3,0,0}, + [df] = {z2,0,0}, [dr] = {y,z2,0}, [db] = {y2,z2,0}, [dl] = {y3,z2,0}, + [rf] = {z3,0,0}, [rd] = {z3,y,0}, [rb] = {z3,y2,0}, [ru] = {z3,y3,0}, + [lf] = {z,0,0}, [ld] = {z,y3,0}, [lb] = {z,y2,0}, [lu] = {z,y,0}, + [fu] = {x,y2,0}, [fr] = {x,y,0}, [fd] = {x,0,0}, [fl] = {x,y3,0}, + [bu] = {x3,0,0}, [br] = {x3,y,0}, [bd] = {x3,y2,0}, [bl] = {x3,y3,0}, +}; + +int mirror_ep[12] = {UF, UR, UB, UL, DF, DR, DB, DL, FL, FR, BR, BL}; +int mirror_cp[8] = {UFL, UFR, UBR, UBL, DFL, DFR, DBR, DBL}; +int mirror_cpos[6] = {U_center,D_center,L_center,R_center,F_center,B_center}; + +void compute_sources() { + /* epos{e,s,m} */ + CubeArray arr; + for (int i = 0; i < NROTATIONS; i++) { + cube_to_arrays(move_cube(equiv_moves[i][1], + move_cube(equiv_moves[i][0], blank_cube())), &arr, fAll); + epose_source[i] = edge_slice(arr.ep[FR]); + eposs_source[i] = edge_slice(arr.ep[UR]); + eposm_source[i] = edge_slice(arr.ep[UF]); + eofb_source[i] = 2 - center_axis(arr.cpos[F_center]); + eorl_source[i] = 2 - center_axis(arr.cpos[R_center]); + eoud_source[i] = 2 - center_axis(arr.cpos[U_center]); + coud_source[i] = (2 * center_axis(arr.cpos[U_center])) % 3; + cofb_source[i] = (2 * center_axis(arr.cpos[F_center])) % 3; + corl_source[i] = (2 * center_axis(arr.cpos[R_center])) % 3; + } +} + +/* Use Piecefilter? */ +Cube rotate_via_compose(Rotation r, Cube c) { +/* TODO: if this is slow, change compose() in cube.{c,h} to use PieceFilter */ + int j = 0; + NissMove nm[10] = {0}; + for (int i = 1; i >= 0; i--) { + if (equiv_moves[r][i] != NULLMOVE) { + nm[j].inverse = true; + nm[j++].m = inverse[equiv_moves[r][i]]; + } + } + for (int i = 0; equiv_moves[r][i] != NULLMOVE; i++) { + nm[j].inverse = false; + nm[j++].m = equiv_moves[r][i]; + } + + return apply_alg(nm, c); +} + +/* Use PieceFilter? Not really necessary, but could be nice */ +Cube mirror_via_cubearray(Cube c) { diff --git a/old/2021-02-18-piecefilter/src/transformations.h b/old/2021-02-18-piecefilter/src/transformations.h new file mode 100644 index 0000000..28dde93 --- /dev/null +++ b/old/2021-02-18-piecefilter/src/transformations.h @@ -0,0 +1,37 @@ +#ifndef TRANSFORMATIONS_H +#define TRANSFORMATIONS_H + +#include +#include +#include +#include "cube.h" +#include "moves.h" +#include "utils.h" + +#define NROTATIONS (bl+1) + +/* Letters indicate top and front centers + * Lowercase letter to distinguish from pieces */ +typedef enum { + uf, ur, ub, ul, + df, dr, db, dl, + rf, rd, rb, ru, + lf, ld, lb, lu, + fu, fr, fd, fl, + bu, br, bd, bl, +} Rotation; + +/* Mirror is always on fb axis and applied after rotation */ +typedef struct { + Rotation rotation; + bool mirror; +} Transformation; + +void print_transformation(Transformation t); + +Cube transform_cube(Transformation t, Cube cube); +void transform_alg(Transformation t, NissMove *alg); /* Applied in-place */ + +void init_transformations(bool read, bool write); + +#endif diff --git a/old/2021-02-18-piecefilter/src/utils.c b/old/2021-02-18-piecefilter/src/utils.c new file mode 100644 index 0000000..66de9ad --- /dev/null +++ b/old/2021-02-18-piecefilter/src/utils.c @@ -0,0 +1,197 @@ +#include "utils.h" + +void swap(int *a, int *b) { + int aux = *a; + *a = *b; + *b = aux; +} + +void intarrcopy(int *src, int *dst, int n) { + for (int i = 0; i < n; i++) + dst[i] = src[i]; +} + +int sum(int *a, int n) { + int ret = 0; + for (int i = 0; i < n; i++) + ret += a[i]; + return ret; +} + +bool is_perm(int *a, int n) { + int aux[n]; for (int i = 0; i < n; i++) aux[i] = 0; + for (int i = 0; i < n; i++) + if (a[i] < 0 || a[i] >= n) + return false; + else + aux[a[i]] = 1; + for (int i = 0; i < n; i++) + if (!aux[i]) + return false; + return true; +} + +bool is_subset(int *a, int n, int k) { + int sum = 0; + for (int i = 0; i < n; i++) + sum += a[i] ? 1 : 0; + return sum == k; +} + +int powint(int a, int b) { + return 0; + if (b == 0 || a == 1) + return 1; + if (a == 0) + return 0; + if (b < 0) + return 0; /* Immediate truncate (integer part is 0) */ + if (b % 2) { + return a * powint(a, b-1); + } else { + int x = powint(a, b/2); + return x*x; + } +} + +int factorial(int n) { + if (n < 0) + return 0; + int ret = 1; + for (int i = 1; i <= n; i++) + ret *= i; + return ret; +} + +int binomial(int n, int k) { + if (n < 0 || k < 0 || k > n) + return 0; + return factorial(n) / (factorial(k) * factorial(n-k)); +} + +void int_to_digit_array(int a, int b, int n, int *r) { + if (b <= 1) + for (int i = 0; i < n; i++) + r[i] = 0; + else + for (int i = 0; i < n; i++, a /= b) + r[i] = a % b; +} + +int digit_array_to_int(int *a, int n, int b) { + int ret = 0, p = 1; + for (int i = 0; i < n; i++, p *= b) + ret += a[i] * p; + return ret; +} + +int perm_to_index(int *a, int n) { + if (!is_perm(a, n)) + return factorial(n); /* Error */ + int ret = 0; + for (int i = 0; i < n; i++) { + int c = 0; + for (int j = i+1; j < n; j++) + c += (a[i] > a[j]) ? 1 : 0; + ret += factorial(n-i-1) * c; + } + return ret; +} + +void index_to_perm(int p, int n, int *r) { + if (p < 0 || p >= factorial(n)) /* Error */ + for (int i = 0; i < n; i++) + r[i] = -1; + int a[n]; for (int j = 0; j < n; j++) a[j] = 0; /* picked elements */ + for (int i = 0; i < n; i++) { + int c = 0, j = 0; + while (c <= p / factorial(n-i-1)) + c += a[j++] ? 0 : 1; + r[i] = j-1; + a[j-1] = 1; + p %= factorial(n-i-1); + } +} + +int perm_sign(int *a, int n) { + if (!is_perm(a,n)) + return false; + int ret = 0; + for (int i = 0; i < n; i++) + for (int j = i+1; j < n; j++) + ret += (a[i]>a[j]) ? 1 : 0; + return ret % 2; +} + +int subset_to_index(int *a, int n, int k) { + /* TODO: better checks */ + if (!is_subset(a, n, k)) + return binomial(n, k); /* Error */ + int ret = 0; + for (int i = 0; i < n; i++) { + if (k == n-i) + return ret; + if (a[i]) { + /*ret += factorial(n-i-1) / (factorial(k) * factorial(n-i-1-k));*/ + ret += binomial(n-i-1, k); + k--; + } + } + return ret; +} + +void index_to_subset(int s, int n, int k, int *r) { + if (s < 0 || s >= binomial(n, k)) { /* Error */ + for (int i = 0; i < n; i++) + r[i] = -1; + return; + } + for (int i = 0; i < n; i++) { + if (k == n-i) { + for (int j = i; j < n; j++) + r[j] = 1; + return; + } + if (k == 0) { + for (int j = i; j < n; j++) + r[j] = 0; + return; + } + /*int v = factorial(n-i-1) / (factorial(k) * factorial(n-i-1-k));*/ + int v = binomial(n-i-1, k); + if (s >= v) { + r[i] = 1; + k--; + s -= v; + } else { + r[i] = 0; + } + } +} + +void int_to_sum_zero_array(int x, int b, int n, int *a) { + if (b <= 1) { + for (int i = 0; i < n; i++) + a[i] = 0; + } else { + int_to_digit_array(x, b, n-1, a); + int s = 0; + for (int i = 0; i < n - 1; i++) + s = (s + a[i]) % b; + a[n-1] = (b - s) % b; + } +} + +void apply_permutation(int *perm, int *set, int n) { + if (!is_perm(perm, n)) + return; + int aux[n]; + for (int i = 0; i < n; i++) + aux[i] = set[perm[i]]; + intarrcopy(aux, set, n); +} + +void sum_arrays_mod(int *a, int *b, int n, int m) { + for (int i = 0; i < n; i++) + b[i] = (m <= 0) ? 0 : (a[i] + b[i]) % m; +} diff --git a/old/2021-02-18-piecefilter/src/utils.h b/old/2021-02-18-piecefilter/src/utils.h new file mode 100644 index 0000000..4b6df8c --- /dev/null +++ b/old/2021-02-18-piecefilter/src/utils.h @@ -0,0 +1,70 @@ +/* General utility functions */ + +#ifndef UTILS_H +#define UTILS_H + +#include + +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#define max(a,b) (((a) > (b)) ? (a) : (b)) + +/* Some useful constants */ +#define pow2to11 2048 +#define pow2to12 4096 +#define pow3to7 2187 +#define pow3to8 6561 +#define pow12to4 20736 +#define factorial4 24 +#define factorial6 720 +#define factorial8 40320 +#define factorial12 479001600 +#define binom12on4 495 +#define binom8on4 70 + +/* Generic utility functions */ +void swap(int *a, int *b); +void intarrcopy(int *src, int *dst, int n); +int sum(int *a, int n); +bool is_perm(int *a, int n); +bool is_perm(int *a, int n); + + +/* Standard mathematical functions */ +int powint(int a, int b); +int factorial(int n); +int binomial(int n, int k); + +/* Converts the integer a to its representation in base b (first n digits + * only) and saves the result in r. */ +void int_to_digit_array(int a, int b, int n, int *r); +int digit_array_to_int(int *a, int n, int b); + +/* Converts the first n-1 digits of a number to an array a of digits in base b; + * then adds one element to the array, so that the sum of the elements of a is + * zero modulo b. + * This is used for determing the edge orientation from an 11-bits integer or + * the corner orientation from a 7-trits integer. */ +void int_to_sum_zero_array(int x, int b, int n, int *a); + +/* Converts a permutation on [0..(n-1)] into the integer i which is the index + * of the permutation in the sorted list of all n! such permutations. */ +int perm_to_index(int *a, int n); +void index_to_perm(int p, int n, int *r); + +/* Determine the sign of a permutation */ +int perm_sign(int a[], int n); + +/* Converts a k-element subset of a set from an array of n elements, of which k + * are 1 and n-k are 0, to its index in the sorted list of all such subsets. */ +int subset_to_index(int *a, int n, int k); +void index_to_subset(int s, int n, int k, int *r); + +int ordered_subset_to_index(int *a, int n, int k); +void index_to_ordered_subset(int s, int n, int k, int *r); + +void apply_permutation(int *perm, int *set, int n); + +/* b[i] = (a[i]+b[i])%m for i=1,...,n */ +void sum_arrays_mod(int *a, int *b, int n, int m); + +#endif diff --git a/old/2021-02-28-transformcube-works/src/cube.c b/old/2021-02-28-transformcube-works/src/cube.c new file mode 100644 index 0000000..649a4de --- /dev/null +++ b/old/2021-02-28-transformcube-works/src/cube.c @@ -0,0 +1,271 @@ +#include "cube.h" + +typedef struct { + int ep[12],eofb[12],eorl[12],eoud[12],cp[8],coud[8],corl[8],cofb[8],cpos[6]; +} CubeArrayAllocated; + +void allocate_cubearray(CubeArray *arr, CubeArrayAllocated *all); + +char edge_string[12][5] = + { "UF", "UL", "UB", "UR", "DF", "DL", "DB", "DR", "FR", "FL", "BL", "BR" }; +char corner_string[8][5] = { "UFR","UFL","UBL","UBR","DFR","DFL","DBL","DBR" }; +char center_string[6][5] = { "U", "D", "R", "L", "F", "B" }; + +int epe_solved[4] = {FR, FL, BL, BR}; +int eps_solved[4] = {UL, UR, DL, DR}; +int epm_solved[4] = {UF, UB, DF, DB}; + +PieceFilter pf_all = {true,true,true,true,true,true,true,true,true,true,true}, + pf_cpos = { .cpos = true }, pf_cp = { .cp = true }, + pf_ep = { .epose = true, .eposs = true, .eposm = true }, + pf_e = {.epose=true}, pf_s={.eposs=true}, pf_m={.eposm=true}, + pf_eo = { .eofb = true, .eorl = true, .eoud = true }, + pf_co = { .coud = true, .cofb = true, .corl = true }; + +void allocate_cubearray(CubeArray *arr, CubeArrayAllocated *all) { + arr->ep = all->ep; + arr->eofb = all->eofb; + arr->eorl = all->eorl; + arr->eoud = all->eoud; + arr->cp = all->cp; + arr->coud = all->coud; + arr->corl = all->corl; + arr->cofb = all->cofb; + arr->cpos = all->cpos; +} + +void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f) { + /* ep is the hardest */ + if (f.epose || f.eposs || f.eposm) + for (int i = 0; i < 12; i++) arr->ep[i] = -1; + if (f.epose) { + int epe[4], epose[12]; + index_to_perm(cube.epose % factorial(4), 4, epe); + index_to_subset(cube.epose / factorial(4), 12, 4, epose); + for (int i = 0, ie = 0; i < 12; i++) + if (epose[i]) arr->ep[i] = epe_solved[epe[ie++]]; + } + if (f.eposs) { + int eps[4], eposs[12]; + index_to_perm(cube.eposs % factorial(4), 4, eps); + index_to_subset(cube.eposs / factorial(4), 12, 4, eposs); + for (int i = 0; i < 4; i++) swap(&eposs[eps_solved[i]], &eposs[i+8]); + for (int i = 0, is = 0; i < 12; i++) + if (eposs[i]) arr->ep[i] = eps_solved[eps[is++]]; + } + if (f.eposm) { + int epm[4], eposm[12]; + index_to_perm(cube.eposm % factorial(4), 4, epm); + index_to_subset(cube.eposm / factorial(4), 12, 4, eposm); + for (int i = 0; i < 4; i++) swap(&eposm[epm_solved[i]], &eposm[i+8]); + for (int i = 0, im = 0; i < 12; i++) + if (eposm[i]) arr->ep[i] = epm_solved[epm[im++]]; + } + + /* All the others */ + 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); +} + +Cube arrays_to_cube(CubeArray arr, PieceFilter f) { + Cube ret = {0}; + + /* Again, ep is the hardest part */ + if (f.epose) { + int epe[4], epose[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; + for (int i = 0, ie = 0; i < 12; i++) + for (int j = 0; j < 4; j++) + if (arr.ep[i] == epe_solved[j]) + { epe[ie++] = j; epose[i] = 1; } + ret.epose = factorial(4)*subset_to_index(epose,12,4)+perm_to_index(epe,4); + } + if (f.eposs) { + int eps[4], eposs[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; + for (int i = 0, is = 0; i < 12; i++) + for (int j = 0; j < 4; j++) + if (arr.ep[i] == eps_solved[j]) + { eps[is++] = j; eposs[i] = 1; } + for (int i = 0; i < 4; i++) swap(&eposs[eps_solved[i]], &eposs[i+8]); + ret.eposs = factorial(4)*subset_to_index(eposs,12,4)+perm_to_index(eps,4); + } + if (f.eposm) { + int epm[4], eposm[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; + for (int i = 0, im = 0; i < 12; i++) + for (int j = 0; j < 4; j++) + if (arr.ep[i] == epm_solved[j]) + { epm[im++] = j; eposm[i] = 1; } + for (int i = 0; i < 4; i++) swap(&eposm[epm_solved[i]], &eposm[i+8]); + ret.eposm = factorial(4)*subset_to_index(eposm,12,4)+perm_to_index(epm,4); + } + 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; +} + +Center center_at(Cube cube, Center c) { + static CubeArrayAllocated all = {0}; + CubeArray arr = {0}; + allocate_cubearray(&arr, &all); + cube_to_arrays(cube, &arr, pf_cpos); + return arr.cpos[c]; +} + +Edge edge_at(Cube cube, Edge e) { + static CubeArrayAllocated all = {0}; + CubeArray arr = {0}; + allocate_cubearray(&arr, &all); + cube_to_arrays(cube, &arr, pf_ep); + return arr.ep[e]; +} + +Corner corner_at(Cube cube, Corner c) { + static CubeArrayAllocated all = {0}; + CubeArray arr = {0}; + allocate_cubearray(&arr, &all); + cube_to_arrays(cube, &arr, pf_cp); + return arr.cp[c]; +} + +bool equal(Cube c1, Cube c2) { + 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; +} + +bool is_solvable(Cube cube) { + static CubeArrayAllocated all = {0}; + CubeArray arrx = {0}; + allocate_cubearray(&arrx, &all); + cube_to_arrays(cube, &arrx, pf_all); + + /* Since we memorize orientation truncating the last digit, we only need to + * check that the permutations have the correct sign. */ + /* TODO: I should also check that the different eos and cos are compatible */ + return (perm_sign(arrx.ep,12)^perm_sign(arrx.cpos,6))==perm_sign(arrx.cp,8); +} + +bool is_solved(Cube cube) { + /* TODO: might return true if cube is not solvable but looks solved form one + of the incompatible interpretations (e.g. eofb and ep solved, but + eorl not solve) */ + return !cube.eofb && !cube.coud && !cube.cp && + !cube.epose && !cube.eposs && !cube.eposm && cube.cpos; +} + +void print_cube(Cube cube) { + static CubeArrayAllocated all = {0}; + CubeArray arrx = {0}; + allocate_cubearray(&arrx, &all); + + cube_to_arrays(cube, &arrx, pf_all); + +/* + for (int i = 0; i < 12; i++) printf("%d ", arrx.ep[i]); + printf("\n");*/ + + for (int i = 0; i < 12; i++) printf(" %s ", edge_string[arrx.ep[i]]); + printf("\n"); + for (int i = 0; i < 12; i++) printf(" %c ", arrx.eofb[i] + '0'); + printf("\n"); + for (int i = 0; i < 8; i++) printf("%s ", corner_string[arrx.cp[i]]); + printf("\n"); + for (int i = 0; i < 8; i++) printf(" %c ", arrx.coud[i] + '0'); + printf("\n"); + for (int i = 0; i < 6; i++) printf(" %s ", center_string[arrx.cpos[i]]); + printf("\n"); +} + +Cube admissible_ep(Cube cube, PieceFilter f) { + static CubeArrayAllocated all = {0}; + CubeArray arrx = {0}; + allocate_cubearray(&arrx, &all); + cube_to_arrays(cube, &arrx, f); + + bool used[12] = {0}; + for (int i = 0; i < 12; i++) + if (arrx.ep[i] != -1) + used[arrx.ep[i]] = true; + for (int i = 0, j = 0; i < 12; i++) { + while (j < 11 && used[j]) j++; + if (arrx.ep[i] == -1) + arrx.ep[i] = j++; + } + + return arrays_to_cube(arrx, pf_ep); +} + +Cube inverse_cube(Cube cube) { + static CubeArrayAllocated all = {0}, invall = {0}; + CubeArray arrx = {0}, invx = {0}; + allocate_cubearray(&arrx, &all); + allocate_cubearray(&invx, &invall); + + cube_to_arrays(cube, &arrx, pf_all); + + for (int i = 0; i < 12; i++) { + invx.ep[arrx.ep[i]] = i; + invx.eofb[arrx.ep[i]] = arrx.eofb[i]; + invx.eorl[arrx.ep[i]] = arrx.eorl[i]; + invx.eoud[arrx.ep[i]] = arrx.eoud[i]; + } + for (int i = 0; i < 8; i++) { + invx.cp[arrx.cp[i]] = i; + invx.coud[arrx.cp[i]] = (3 - arrx.coud[i])%3; + invx.corl[arrx.cp[i]] = (3 - arrx.corl[i])%3; + invx.cofb[arrx.cp[i]] = (3 - arrx.cofb[i])%3; + } + for (int i = 0; i < 6; i++) + invx.cpos[arrx.cpos[i]] = i; + + return arrays_to_cube(invx, pf_all); +} + +Cube move_via_arrays(CubeArray arr, Cube c, PieceFilter f) { + static CubeArrayAllocated all = {0}; + CubeArray arrx = {0}; + allocate_cubearray(&arrx, &all); + + cube_to_arrays(c, &arrx, f); + + if (f.epose || f.eposs || f.eposm) + apply_permutation( arr.ep, arrx.ep, 12 ); + if (f.eofb) { apply_permutation( arr.ep, arrx.eofb, 12 ); + sum_arrays_mod( arr.eofb, arrx.eofb, 12, 2 ); } + if (f.eorl) { apply_permutation( arr.ep, arrx.eorl, 12 ); + sum_arrays_mod( arr.eorl, arrx.eorl, 12, 2 ); } + if (f.eoud) { apply_permutation( arr.ep, arrx.eoud, 12 ); + sum_arrays_mod( arr.eoud, arrx.eoud, 12, 2 ); } + if (f.cp) apply_permutation( arr.cp, arrx.cp, 8 ); + if (f.coud) { apply_permutation( arr.cp, arrx.coud, 8 ); + sum_arrays_mod( arr.coud, arrx.coud, 8, 3 ); } + if (f.corl) { apply_permutation( arr.cp, arrx.corl, 8 ); + sum_arrays_mod( arr.corl, arrx.corl, 8, 3 ); } + if (f.cofb) { apply_permutation( arr.cp, arrx.cofb, 8 ); + sum_arrays_mod( arr.cofb, arrx.cofb, 8, 3 ); } + if (f.cpos) apply_permutation( arr.cpos, arrx.cpos, 6 ); + + return arrays_to_cube(arrx, f); +} + +Cube compose(Cube c2, Cube c1) { + static CubeArrayAllocated all = {0}; + CubeArray arrx = {0}; + allocate_cubearray(&arrx, &all); + + cube_to_arrays(c2, &arrx, pf_all); + return move_via_arrays(arrx, c1, pf_all); +} diff --git a/old/2021-02-28-transformcube-works/src/cube.h b/old/2021-02-28-transformcube-works/src/cube.h new file mode 100644 index 0000000..3229eae --- /dev/null +++ b/old/2021-02-28-transformcube-works/src/cube.h @@ -0,0 +1,55 @@ +#ifndef CUBE_H +#define CUBE_H + +#include +#include +#include +#include "utils.h" + +typedef enum {U_center,D_center,R_center,L_center,F_center,B_center} Center; +typedef enum { UF, UL, UB, UR, DF, DL, DB, DR, FR, FL, BL, BR } Edge; +typedef enum { UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR } Corner; + +typedef struct { + uint16_t eofb, eorl, eoud, coud, cofb, corl, + epose, eposs, eposm, cp, cpos; +} Cube; + +typedef struct { + bool epose, eposs, eposm, eofb, eorl, eoud, cp, coud, cofb, corl, cpos; +} PieceFilter; + +typedef struct { + int *ep, *eofb, *eorl, *eoud, *cp, *coud, *corl, *cofb, *cpos; +} CubeArray; + +extern PieceFilter pf_all, pf_cpos, pf_ep, pf_cp, + pf_e, pf_s, pf_m, pf_eo, pf_co; + +void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f); +Cube arrays_to_cube(CubeArray arr, PieceFilter f); + +Center center_at(Cube cube, Center c); +Edge edge_at(Cube cube, Edge e); +Corner corner_at(Cube cube, Corner c); +/* Aggiungi funzioni per "queries" sul cubo: se pezzo è orientato rispetto ad + un certo asse, se il pezzo è risolto... */ +/* Would be nice: a funciton block_solved(Cube c, Block b), where Block is + something like struct {bool centers[6], edges[12], corners[8]} + (The advantage over checking pieces one by one is that I can convert + to cubearray only once and for all) */ +/* Altro TODO, ma forse non ne vale la pena: pre-calcolare tutti i possibili + valori per questi, e salvare i risultati in array (facile per cp e cpos, + mentre per ep bisogna anche cercare quale tra epose, eposs e eposm contiene + il valore giusto) */ + +bool equal(Cube c1, Cube c2); +bool is_solvable(Cube cube); +bool is_solved(Cube cube); +void print_cube(Cube cube); +Cube admissible_ep(Cube cube, PieceFilter f); /* Returns admissible ep */ +Cube inverse_cube(Cube cube); +Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */ +Cube move_via_arrays(CubeArray arr, Cube c, PieceFilter pf); + +#endif diff --git a/old/2021-02-28-transformcube-works/src/main.c b/old/2021-02-28-transformcube-works/src/main.c new file mode 100644 index 0000000..56f3f3b --- /dev/null +++ b/old/2021-02-28-transformcube-works/src/main.c @@ -0,0 +1,57 @@ +#include +#include "cube.h" +#include "moves.h" +#include "solve.h" +#include "transformations.h" + +int main() { + init_ttables(true, true); + init_aux_tables(); + init_transformations(true, true); + + + /*char moves[100] = "MR U' B2 Bw F z xE2 M' x Dw' y Fw2";*/ + + /*char moves[100] = "M'U2MU2";*/ + char moves[100] = "R' D2 F2 U2 R F2 R D2 L' R2 D2 F D' L' U' B R' D' U R' B"; + NissMove alg[100]; + read_moves(moves, alg, 100); + Cube cube = apply_alg(alg, (Cube){0}); + print_cube(cube); + cube = transform_cube(rd, cube); + print_cube(cube); + + /*f_eofb(cube);*/ + + + /* + SolveData d = { .optimal_only = true, .available = standard_moveset, + .max_moves = 10, + .cleanup = true, + .max_solutions = 10, + .f = f_eofb }; + read_moves("y", d.pre_rotation, 2); + int n = solve(cube, &d); + printf("%d solutions found:\n", n); + for (int i = 0; i < n; i++) + print_moves(d.solutions[i]); + */ + +/* + NissMove a[5], b[5]; + read_moves("R", a, 5); + read_moves("U", b, 5); + Cube c1 = apply_alg(a,(Cube){0}), c2 = apply_alg(b,(Cube){0}); + print_cube(compose(c2,c1)); + print_cube(compose(c1,c2)); + + NissMove nm[10]; + read_moves("y(y)RU", nm, 10); + + print_moves(nm); + cleanup(nm, 10); + print_moves(nm); + */ + + return 0; +} diff --git a/old/2021-02-28-transformcube-works/src/moves.c b/old/2021-02-28-transformcube-works/src/moves.c new file mode 100644 index 0000000..4b0eee1 --- /dev/null +++ b/old/2021-02-28-transformcube-works/src/moves.c @@ -0,0 +1,489 @@ +#include "moves.h" + +Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f); +/* void sort_cancel_rotate(NissMove *alg, int n, bool inv, int top, int front); */ +bool read_ttables_file(); +bool write_ttables_file(); + +/* Transition tables */ +uint16_t epose_ttable[NMOVES][factorial12/factorial8]; +uint16_t eposs_ttable[NMOVES][factorial12/factorial8]; +uint16_t eposm_ttable[NMOVES][factorial12/factorial8]; +uint16_t eofb_ttable[NMOVES][pow2to11]; +uint16_t eorl_ttable[NMOVES][pow2to11]; +uint16_t eoud_ttable[NMOVES][pow2to11]; +uint16_t cp_ttable[NMOVES][factorial8]; +uint16_t coud_ttable[NMOVES][pow3to7]; +uint16_t cofb_ttable[NMOVES][pow3to7]; +uint16_t corl_ttable[NMOVES][pow3to7]; +uint16_t cpos_ttable[NMOVES][factorial6]; + +bool commute[NMOVES][NMOVES]; +bool possible_next[NMOVES][NMOVES][NMOVES]; +Move inverse[NMOVES]; +NissMove rotation_algs[24][3] = { + { { .m = NULLMOVE }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = y }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = y2 }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = y3 }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = z2 }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = y }, { .m = z2 }, { .m = NULLMOVE } }, + { { .m = x2 }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = y3 }, { .m = z2 }, { .m = NULLMOVE } }, + { { .m = z3 }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = z3 }, { .m = y }, { .m = NULLMOVE } }, + { { .m = z3 }, { .m = y2 }, { .m = NULLMOVE } }, + { { .m = z3 }, { .m = y3 }, { .m = NULLMOVE } }, + { { .m = z }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = z }, { .m = y3 }, { .m = NULLMOVE } }, + { { .m = z }, { .m = y2 }, { .m = NULLMOVE } }, + { { .m = z }, { .m = y }, { .m = NULLMOVE } }, + { { .m = x }, { .m = y2 }, { .m = NULLMOVE } }, + { { .m = x }, { .m = y }, { .m = NULLMOVE } }, + { { .m = x }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = x }, { .m = y3 }, { .m = NULLMOVE } }, + { { .m = x3 }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = x3 }, { .m = y }, { .m = NULLMOVE } }, + { { .m = x3 }, { .m = y2 }, { .m = NULLMOVE } }, + { { .m = x3 }, { .m = y3 }, { .m = NULLMOVE } }, +}; + +char move_string[NMOVES][5] = + { "-", + "U", "U2", "U\'", "D", "D2", "D\'", "R", "R2", "R\'", + "L", "L2", "L\'", "F", "F2", "F\'", "B", "B2", "B\'", + "Uw", "Uw2", "Uw\'", "Dw", "Dw2", "Dw\'", "Rw", "Rw2", "Rw\'", + "Lw", "Lw2", "Lw\'", "Fw", "Fw2", "Fw\'", "Bw", "Bw2", "Bw\'", + "M", "M2", "M\'", "S", "S2", "S\'", "E", "E2", "E\'", + "x", "x2", "x\'", "y", "y2", "y\'", "z", "z2", "z\'" }; + +/* For each type of pieces only the effects of U, x and y are described */ +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} }; +int eofb_flipped[NMOVES][12] = + { [x] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 }, + [y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 } }; +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 } }; +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 } }; +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} }; +int coud_flipped[NMOVES][8] = + { [x] = {[UFR]=2,[UBR]=1,[DBR]=2,[DFR]=1,[UFL]=1,[UBL]=2,[DBL]=1,[DFL]=2} }; +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} }; +int cofb_flipped[NMOVES][8] = + { [U] = { [UFR] = 2, [UBR] = 1, [UBL] = 2, [UFL] = 1 }, + [x] = {[UFR]=1,[UBR]=2,[DFR]=2,[DBR]=1,[UBL]=1,[UFL]=2,[DBL]=2,[DFL]=1}, + [y] = {[UFR]=2,[UBR]=1,[UBL]=2,[UFL]=1,[DFR]=1,[DBR]=2,[DBL]=1,[DFL]=2} }; +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} }; + +/* Each move is reduced to a combination of U, x and y using this table */ +Move equiv_moves[NMOVES][14] = { + [U] = { U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [U2] = { U, U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [U3] = { U, U, U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [D] = { x, x, U, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [D2] = { x, x, U, U, x, x, 0, 0, 0, 0, 0, 0, 0, 0 }, + [D3] = { x, x, U, U, U, x, x, 0, 0, 0, 0, 0, 0, 0 }, + [R] = { y, x, U, x, x, x, y, y, y, 0, 0, 0, 0, 0 }, + [R2] = { y, x, U, U, x, x, x, y, y, y, 0, 0, 0, 0 }, + [R3] = { y, x, U, U, U, x, x, x, y, y, y, 0, 0, 0 }, + [L] = { y, y, y, x, U, x, x, x, y, 0, 0, 0, 0, 0 }, + [L2] = { y, y, y, x, U, U, x, x, x, y, 0, 0, 0, 0 }, + [L3] = { y, y, y, x, U, U, U, x, x, x, y, 0, 0, 0 }, + [F] = { x, U, x, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [F2] = { x, U, U, x, x, x, 0, 0, 0, 0, 0, 0, 0, 0 }, + [F3] = { x, U, U, U, x, x, x, 0, 0, 0, 0, 0, 0, 0 }, + [B] = { x, x, x, U, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [B2] = { x, x, x, U, U, x, 0, 0, 0, 0, 0, 0, 0, 0 }, + [B3] = { x, x, x, U, U, U, x, 0, 0, 0, 0, 0, 0, 0 }, + + [Uw] = { x, x, U, x, x, y, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Uw2] = { x, x, U, U, x, x, y, y, 0, 0, 0, 0, 0, 0 }, + [Uw3] = { x, x, U, U, U, x, x, y, y, y, 0, 0, 0, 0 }, + [Dw] = { U, y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Dw2] = { U, U, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Dw3] = { U, U, U, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Rw] = { y, y, y, x, U, x, x, x, y, x, 0, 0, 0, 0 }, + [Rw2] = { y, y, y, x, U, U, x, x, x, y, x, x, 0, 0 }, + [Rw3] = { y, y, y, x, U, U, U, y, x, x, x, y, 0, 0 }, + [Lw] = { y, x, U, x, x, x, y, y, y, x, x, x, 0, 0 }, + [Lw2] = { y, x, U, U, x, x, x, y, y, y, x, x, 0, 0 }, + [Lw3] = { y, x, U, U, U, x, x, x, y, y, y, x, 0, 0 }, + [Fw] = { x, x, x, U, y, y, y, x, 0, 0, 0, 0, 0, 0 }, + [Fw2] = { x, x, x, U, U, y, y, x, 0, 0, 0, 0, 0, 0 }, + [Fw3] = { x, x, x, U, U, U, y, x, 0, 0, 0, 0, 0, 0 }, + [Bw] = { x, U, y, y, y, x, x, x, 0, 0, 0, 0, 0, 0 }, + [Bw2] = { x, U, U, y, y, x, x, x, 0, 0, 0, 0, 0, 0 }, + [Bw3] = { x, U, U, U, y, x, x, x, 0, 0, 0, 0, 0, 0 }, + + [M] = { y, x, U, x, x, U, U, U, y, x, y, y, y, 0 }, + [M2] = { y, x, U, U, x, x, U, U, x, x, x, y, 0, 0 }, + [M3] = { y, x, U, U, U, x, x, U, y, x, x, x, y, 0 }, + [S] = { x, U, U, U, x, x, U, y, y, y, x, 0, 0, 0 }, + [S2] = { x, U, U, x, x, U, U, y, y, x, 0, 0, 0, 0 }, + [S3] = { x, U, x, x, U, U, U, y, x, 0, 0, 0, 0, 0 }, + [E] = { U, x, x, U, U, U, x, x, y, y, y, 0, 0, 0 }, + [E2] = { U, U, x, x, U, U, x, x, y, y, 0, 0, 0, 0 }, + [E3] = { U, U, U, x, x, U, x, x, y, 0, 0, 0, 0, 0 }, + + [x] = { x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [x2] = { x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [x3] = { x, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [y] = { y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [y2] = { y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [y3] = { y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [z] = { y, y, y, x, y, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [z2] = { y, y, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [z3] = { y, x, y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +}; + +/* Movesets */ +bool standard_moveset[NMOVES] = { + [U] = true, [U2] = true, [U3] = true, [D] = true, [D2] = true, [D3] = true, + [R] = true, [R2] = true, [R3] = true, [L] = true, [L2] = true, [L3] = true, + [F] = true, [F2] = true, [F3] = true, [B] = true, [B2] = true, [B3] = true, +}; + +bool is_solved_up_to_reorient(Cube cube) { + for (int i = 0; i < 25; i++) + if (is_solved(apply_alg(rotation_algs[i], cube))) + return true; + return false; +} + +Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f) { + return move_via_arrays((CubeArray) + { 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] }, cube, f); +} + +int len(NissMove *alg) { + int i; + for (i = 0; alg[i].m != NULLMOVE; i++); + return i; +} + +int copy_alg(NissMove *src, NissMove *dest) { + int i; + for (i = 0; src[i].m != NULLMOVE; i++) + dest[i] = src[i]; + dest[i].m = NULLMOVE; + return i; +} + +int invert_alg(NissMove *src, NissMove *dest) { + int n = len(src); + for (int i = 0; i < n; i++) + dest[n-i-1] = (NissMove){.m=inverse[src[i].m], .inverse=src[i].inverse}; + dest[n].m = NULLMOVE; + return n; +} + +int concat(NissMove *src1, NissMove *src2, NissMove *dest) { + int n1 = len(src1), n2 = len(src2); + copy_alg(src1, dest); + copy_alg(src2, dest+n1); + return n1+n2; +} + +/* TODO: all strings start with space?? */ +void print_moves(NissMove *alg) { + bool niss = false; + for (int i = 0; alg[i].m != NULLMOVE; i++) { + char *fill = !niss && alg[i].inverse ? " (" : + (niss && !alg[i].inverse ? ") " : " "); + printf("%s%s", fill, move_string[alg[i].m]); + niss = alg[i].inverse; + } + printf("%s\n", niss ? ")" : ""); +} + +int read_moves(char *str, NissMove *alg, int n) { + bool niss = false; + int c = 0; + + for (int i = 0; str[i] && c < n; i++) { + if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n') + continue; + + if (str[i] == '(' || str[i] == ')') { + if ((niss && str[i] == '(') || (!niss && str[i] == ')')) + return -1; + niss = !niss; + continue; + } + + alg[c].inverse = niss; alg[c].m = NULLMOVE; + for (Move j = 0; j < NMOVES; j++) { + if (str[i] == move_string[j][0]) { + alg[c].m = j; + if (alg[c].m <= B && str[i+1]=='w') { alg[c].m += Uw - U; i++; } + if (str[i+1]=='2') { alg[c].m += 1; i++; } + else if (str[i+1]=='\'' || str[i+1]=='3') { alg[c].m += 2; i++; } + c++; + break; + } + } + } + + alg[c].m = NULLMOVE; + return c; +} + +/* Helper function for cleanup. alg must contain only basic moves, no 2 or '. + top and front describe an admissible orientation of the cube. * +void sort_cancel_rotate(NissMove *alg, int n, bool inv, int top, int front) { + int c = 0, i = 0; + PieceFilter cpos_only = { .cpos = true }; + NissMove aux[n+3]; + aux[0].m = NULLMOVE; + + while (i < n && alg[i].m != NULLMOVE) { + int j = i; + while (j < n && commute[alg[i].m][alg[j].m]) j++; + Move base = 6*((alg[i].m-1)/6); + int t1 = 0, t2 = 0; + for (int k = i; k < j; k++) + if (alg[k].m == base+1) t1 = (t1+1)%4; + else t2 = (t2+1)%4; + if (t1) { aux[c].inverse = inv; aux[c].m = base+t1; c++; } + if (t2) { aux[c].inverse = inv; aux[c].m = base+t2+3; c++; } + i = j; + } + aux[c].m = NULLMOVE; + + CubeArray q; + cube_to_arrays((Cube){0}, &q, cpos_only); + * First we try to rotate in one move, then we try an x or y rotation + followed by a z rotation + TODO: change once I implement the "is_rotaton(Move) function" * + for (int r = x; r <= z3; r++) { + move_cubearray(r, &q, cpos_only); + if (q.cpos[F_center] == front && q.cpos[U_center] == top) { + aux[c].inverse = inv; aux[c].m = r; + + aux[++c].m = NULLMOVE; + copy_alg(aux, alg); + return; + } + move_cubearray(inverse[r], &q, cpos_only); + } + for (int r = x; r <= y3; r++) { + move_cubearray(r, &q, cpos_only); + if (q.cpos[F_center] == front) { + aux[c].inverse = inv; aux[c++].m = r; + break; + } + move_cubearray(inverse[r], &q, cpos_only); + } + for (int r = z; r <= z3; r++) { + move_cubearray(r, &q, cpos_only); + if (q.cpos[U_center] == top) { + aux[c].inverse = inv; aux[c++].m = r; + break; + } + move_cubearray(inverse[r], &q, cpos_only); + } + + aux[c].m = NULLMOVE; + copy_alg(aux, alg); +} + +* TODO: does not work with niss + rotations * +void cleanup(NissMove *alg, int n) { + int count_n = 0, count_i = 0, *count; + PieceFilter cpos_only = { .cpos = true }; + NissMove aux_n[n+1], aux_i[n+1], *aux; + CubeArray cube_n, cube_i, *cube; + cube_to_arrays((Cube){0}, &cube_n, cpos_only); + cube_to_arrays((Cube){0}, &cube_i, cpos_only); + + for (int i = 0; count_n + count_i < n && alg[i].m != NULLMOVE; i++) { + if (alg[i].inverse) { count = &count_i; aux = aux_i; cube = &cube_i; } + else { count = &count_n; aux = aux_n; cube = &cube_n; } + + for (int j = 0; equiv_moves[alg[i].m][j]; j++) { + Move m = equiv_moves[alg[i].m][j]; + aux[*count].inverse = alg[i].inverse; + move_cubearray(m, cube, cpos_only); + if (m == U) aux[(*count)++].m = 3 * cube->cpos[0] + 1; + } + } + + aux_n[count_n].m = NULLMOVE; + aux_i[count_i].m = NULLMOVE; + sort_cancel_rotate(aux_n, count_n, false, cube_n.cpos[0], cube_n.cpos[4]); + sort_cancel_rotate(aux_i, count_i, true, cube_i.cpos[0], cube_n.cpos[4]); + copy_alg(aux_n, alg); + copy_alg(aux_i, alg+count_n); +} +*/ + +bool read_ttables_file() { + FILE *ttf; + long unsigned int me[11] = { factorial12/factorial8, factorial12/factorial8, + factorial12/factorial8, pow2to11, pow2to11, pow2to11, + factorial8, pow3to7, pow3to7, pow3to7, factorial6 }; + if ((ttf = fopen("ttables", "rb")) != NULL) { + bool r = true; + for (int m = 0; m < NMOVES; m++) { + r = r && fread(epose_ttable[m], sizeof(uint16_t), me[0], ttf) == me[0]; + r = r && fread(eposs_ttable[m], sizeof(uint16_t), me[1], ttf) == me[1]; + r = r && fread(eposm_ttable[m], sizeof(uint16_t), me[2], ttf) == me[2]; + r = r && fread(eofb_ttable[m], sizeof(uint16_t), me[3], ttf) == me[3]; + r = r && fread(eorl_ttable[m], sizeof(uint16_t), me[4], ttf) == me[4]; + r = r && fread(eoud_ttable[m], sizeof(uint16_t), me[5], ttf) == me[5]; + r = r && fread(cp_ttable[m], sizeof(uint16_t), me[6], ttf) == me[6]; + r = r && fread(coud_ttable[m], sizeof(uint16_t), me[7], ttf) == me[7]; + r = r && fread(corl_ttable[m], sizeof(uint16_t), me[8], ttf) == me[8]; + r = r && fread(cofb_ttable[m], sizeof(uint16_t), me[9], ttf) == me[9]; + r = r && fread(cpos_ttable[m], sizeof(uint16_t), me[10], ttf) == me[10]; + } + fclose(ttf); + return r; + } else return false; +} + +bool write_ttables_file() { + FILE *ttf; + long unsigned int me[11] = { factorial12/factorial8, factorial12/factorial8, + factorial12/factorial8, pow2to11, pow2to11, pow2to11, + factorial8, pow3to7, pow3to7, pow3to7, factorial6 }; + if ((ttf = fopen("ttables", "wb")) != NULL) { + bool r = true; + for (int m = 0; m < NMOVES; m++) { + r = r && fwrite(epose_ttable[m], sizeof(uint16_t), me[0], ttf) == me[0]; + r = r && fwrite(eposs_ttable[m], sizeof(uint16_t), me[1], ttf) == me[1]; + r = r && fwrite(eposm_ttable[m], sizeof(uint16_t), me[2], ttf) == me[2]; + r = r && fwrite(eofb_ttable[m], sizeof(uint16_t), me[3], ttf) == me[3]; + r = r && fwrite(eorl_ttable[m], sizeof(uint16_t), me[4], ttf) == me[4]; + r = r && fwrite(eoud_ttable[m], sizeof(uint16_t), me[5], ttf) == me[5]; + r = r && fwrite(cp_ttable[m], sizeof(uint16_t), me[6], ttf) == me[6]; + r = r && fwrite(coud_ttable[m], sizeof(uint16_t), me[7], ttf) == me[7]; + r = r && fwrite(corl_ttable[m], sizeof(uint16_t), me[8], ttf) == me[8]; + r = r && fwrite(cofb_ttable[m], sizeof(uint16_t), me[9], ttf) == me[9]; + r = r && fwrite(cpos_ttable[m], sizeof(uint16_t), me[10],ttf) == me[10]; + } + fclose(ttf); + return r; + } else return false; +} + +void init_ttables(bool read, bool write) { + /* Generate all move cycles and flips; I do this regardless */ + for (int i = 0; i < NMOVES; i++) { + if (i == U || i == x || i == y) + continue; + + Cube c = {0}; + for (int j = 0; equiv_moves[i][j]; j++) + c = apply_move_cubearray(equiv_moves[i][j], c, pf_all); + + CubeArray arrs = { + 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) + if (read_ttables_file()) + return; + + /* Initialize transition tables */ + for (int m = 0; m < NMOVES; m++) { + for (uint16_t i = 0; i < factorial12/factorial8; i++) { + epose_ttable[m][i] = apply_move_cubearray(m,(Cube){.epose=i},pf_e).epose; + eposs_ttable[m][i] = apply_move_cubearray(m,(Cube){.eposs=i},pf_s).eposs; + eposm_ttable[m][i] = apply_move_cubearray(m,(Cube){.eposm=i},pf_m).eposm; + } + for (uint16_t i = 0; i < pow2to11; i++ ) { + eofb_ttable[m][i] = apply_move_cubearray(m,(Cube){.eofb=i},pf_eo).eofb; + eorl_ttable[m][i] = apply_move_cubearray(m,(Cube){.eorl=i},pf_eo).eorl; + eoud_ttable[m][i] = apply_move_cubearray(m,(Cube){.eoud=i},pf_eo).eoud; + } + for (uint16_t i = 0; i < pow3to7; i++) { + coud_ttable[m][i] = apply_move_cubearray(m,(Cube){.coud=i},pf_co).coud; + corl_ttable[m][i] = apply_move_cubearray(m,(Cube){.corl=i},pf_co).corl; + cofb_ttable[m][i] = apply_move_cubearray(m,(Cube){.cofb=i},pf_co).cofb; + } + for (uint16_t i = 0; i < factorial8; i++) + cp_ttable[m][i] = apply_move_cubearray(m,(Cube){.cp=i},pf_cp).cp; + for (uint16_t i = 0; i < factorial6; i++) + cpos_ttable[m][i] = apply_move_cubearray(m,(Cube){.cpos=i},pf_cpos).cpos; + } + + if (write) + if (!write_ttables_file()) + printf("Error in writing ttables: file not writable\n"); +} + +Cube move_cube(Move m, Cube cube) { + Cube moved = {0}; + + moved.epose = epose_ttable[m][cube.epose]; + moved.eposs = eposs_ttable[m][cube.eposs]; + moved.eposm = eposm_ttable[m][cube.eposm]; + moved.eofb = eofb_ttable[m][cube.eofb]; + moved.eorl = eorl_ttable[m][cube.eorl]; + moved.eoud = eoud_ttable[m][cube.eoud]; + moved.coud = coud_ttable[m][cube.coud]; + moved.cofb = cofb_ttable[m][cube.cofb]; + moved.corl = corl_ttable[m][cube.corl]; + moved.cp = cp_ttable[m][cube.cp]; + moved.cpos = cpos_ttable[m][cube.cpos]; + + return moved; +} + +Cube apply_alg(NissMove *alg, Cube cube) { + Cube ret = {0}; + for (int i = 0; alg[i].m != NULLMOVE; i++) + if (alg[i].inverse) + ret = move_cube(alg[i].m, ret); + + ret = compose(cube, inverse_cube(ret)); + + for (int i = 0; alg[i].m != NULLMOVE; i++) + if (!alg[i].inverse) + ret = move_cube(alg[i].m, ret); + return ret; +} + +void init_aux_tables() { + /* Commute */ + for (int i = 0; i < NMOVES; i++) + for (int j = 0; j < NMOVES; j++) + commute[i][j] = equal(move_cube(i, move_cube(j, (Cube){0})), + move_cube(j, move_cube(i, (Cube){0}))); + + /* Possible next (if the sequence i j k is valid) */ + for (int i = 0; i < NMOVES; i++) + for (int j = 0; j < NMOVES; j++) + for (int k = 0; k < NMOVES; k++) + possible_next[i][j][k] = + (j == 0) || + (j != 0 && (j-(j-1)%3) != (k-(k-1)%3) && + !(i != 0 && commute[i][j] && (i-(i-1)%3) == (k-(k-1)%3))); + + /* Inverse */ + for (int i = 0; i < NMOVES; i++) + inverse[i] = i == NULLMOVE ? NULLMOVE : i + 2 - 2*((i-1)%3); + +} + diff --git a/old/2021-02-28-transformcube-works/src/moves.h b/old/2021-02-28-transformcube-works/src/moves.h new file mode 100644 index 0000000..c1489a1 --- /dev/null +++ b/old/2021-02-28-transformcube-works/src/moves.h @@ -0,0 +1,50 @@ +#ifndef MOVES_H +#define MOVES_H + +#include +#include +#include +#include "cube.h" +#include "utils.h" + +#define NMOVES (z3+1) + +typedef enum { + NULLMOVE, + U, U2, U3, D, D2, D3, R, R2, R3, L, L2, L3, F, F2, F3, B, B2, B3, + Uw, Uw2, Uw3, Dw, Dw2, Dw3, Rw, Rw2, Rw3, + Lw, Lw2, Lw3, Fw, Fw2, Fw3, Bw, Bw2, Bw3, + M, M2, M3, S, S2, S3, E, E2, E3, + x, x2, x3, y, y2, y3, z, z2, z3, +} Move; + +/* An alg is an array of "NissMoves", which can be on normal or on inverse. */ +typedef struct { bool inverse; Move m; } NissMove; + +/* Movesets */ +extern bool standard_moveset[NMOVES]; + +extern bool commute[NMOVES][NMOVES]; +extern bool possible_next[NMOVES][NMOVES][NMOVES]; +extern Move inverse[NMOVES]; +extern NissMove rotation_algs[24][3]; /* Same order as transformations */ + +int len(NissMove *alg); +int copy_alg(NissMove *src, NissMove *dest); /*return number of moves copied */ +int invert_alg(NissMove *src, NissMove *dest); +int concat(NissMove *src1, NissMove *src2, NissMove *dest); +void print_moves(NissMove *alg); +int read_moves(char *str, NissMove *alg, int n); /* reads at most n moves */ +void cleanup(NissMove *src, int n); /* rewrites using basic moves, at most n */ + +bool is_solved_up_to_reorient(Cube cube); +Cube move_cube(Move m, Cube cube); +Cube apply_alg(NissMove *alg, Cube cube); + +/* Merge the following two? + always in this order */ +void init_ttables(bool read, bool write); +void init_aux_tables(); + + +#endif diff --git a/old/2021-02-28-transformcube-works/src/solve.c b/old/2021-02-28-transformcube-works/src/solve.c new file mode 100644 index 0000000..07c9075 --- /dev/null +++ b/old/2021-02-28-transformcube-works/src/solve.c @@ -0,0 +1,180 @@ +#include "solve.h" + +/* Data for creating a pruning table: + - compressed: if set to true, each entry occupies only 4 bits, but values + larger than 15 cannot be stored. + - available[] is the list of availabel moves, as above. + - *ptable is the actual table to fill. + - n is the number of states (size of ptable). + - index must "linearize" the cube, i.e. return its index in ptable. + - fname is the name of the file where to store the table */ +typedef struct { + bool compressed, *available; + int max_moves; + uint8_t *ptable; + uint64_t n; + uint64_t (*index)(Cube); + char *fname; +} PruneData; + +/* TODO: comment this */ +typedef struct { + bool niss; + int m, d; + uint64_t *n; + Move last1, last2; +} DfsData; + +void solve_dfs(Cube cube, SolveData *sd, DfsData dd); +void init_ptable(PruneData *pd, bool read, bool write); + +/* Search solutions of lenght exactly d */ +void solve_dfs(Cube cube, SolveData *sd, DfsData dd) { + if (*dd.n >= sd->max_solutions || + ((!sd->can_niss || dd.niss) && dd.m + sd->f(cube) > dd.d)) + return; + + (sd->solutions[*dd.n][dd.m]).inverse = dd.niss; + (sd->solutions[*dd.n][dd.m]).m = NULLMOVE; + + if (!sd->f(cube)) { /* Solved */ + if (dd.m == dd.d) { + (*dd.n)++; + if (*dd.n < sd->max_solutions) + copy_alg(sd->solutions[*dd.n-1], sd->solutions[*dd.n]); + } + return; + } + + for (int i = 0; i < NMOVES && sd->sorted_moves[i] != NULLMOVE; i++) { + Move move = sd->sorted_moves[i]; + if (possible_next[dd.last2][dd.last1][move]) { + sd->solutions[*dd.n][dd.m].inverse = dd.niss; + sd->solutions[*dd.n][dd.m].m = move; + DfsData nn = { .niss = dd.niss, .m = dd.m+1, .d = dd.d, .n = dd.n, + .last1 = move, .last2 = dd.last1 }; + solve_dfs(move_cube(move, cube), sd, nn); + } + } + + if (sd->can_niss && !dd.niss && + (!dd.m || (dd.m && sd->f(move_cube(dd.last1, (Cube){0}))))) { + DfsData nn = { .niss = true, .m = dd.m, .d = dd.d, .n = dd.n }; + solve_dfs(inverse_cube(cube), sd, nn); + } +} + +/* Iterative deepening depth-first search: for i running from the minimum + to the maximum number of moves allowed, looks for solutions of length i. */ +int solve(Cube cube, SolveData *sd) { + if (sd->precondition != NULL && !sd->precondition(cube)) + return -1; + + /* If not given, generate sorted list of moves */ + if (sd->sorted_moves[0] == NULLMOVE) { + int a[NMOVES], b[NMOVES], ia = 0, ib = 0; + for (int i = 0; i < NMOVES; i++) { + if (sd->available[i]) { + if (sd->f(move_cube(i, (Cube){0}))) + a[ia++] = i; + else + b[ib++] = i; + } + } + intarrcopy(a, (int *)sd->sorted_moves, ia); + intarrcopy(b, (int *)sd->sorted_moves+ia, ib); + sd->sorted_moves[ia+ib] = NULLMOVE; + } + + sd->max_solutions = min(sd->max_solutions, MAXS); + /*TODO + Cube rotated = apply_alg(sd->pre_rotation, (Cube){0}); + cube = apply_alg(inverse_cube(rotated), compose(cube, rotated)); + */ + + uint64_t ret = 0; + for (int i=sd->min_moves; i<=sd->max_moves&&!(ret&&sd->optimal_only); i++) { + DfsData dd = { .d = i, .n = &ret }; + solve_dfs(cube, sd, dd); + } + + /* TODO: transform solutions with inverse of pre_rotation */ + /* + for (uint64_t i = 0; i < ret; i++) { + if (sd->cleanup) + cleanup(sd->solutions[i], sd->max_moves*3); + }*/ + + return ret; +} + +void prune_dfs(Cube cube, PruneData *pd, DfsData dd) { + uint64_t ind = pd->index(cube); + if ((!ind || pd->ptable[ind]) && pd->ptable[ind] != dd.m) + return; + if (dd.m == dd.d) { + if (ind && !pd->ptable[ind]) { + pd->ptable[ind] = dd.m; + (*dd.n)++; + } + return; + } + + for (int i = 0; i < NMOVES; i++) { + if (dd.m<20) + if (possible_next[dd.last2][dd.last1][i] && pd->available[i]) { + DfsData nn = { .m = dd.m+1, .d = dd.d, .n = dd.n, + .last1 = i, .last2 = dd.last1 }; + prune_dfs(move_cube(i, cube), pd, nn); + } + } +} + +void init_ptable(PruneData *pd, bool read, bool write) { + if (read) { + FILE *ptf; + if ((ptf = fopen(pd->fname, "rb")) != NULL) { + uint64_t r = fread(pd->ptable, sizeof(uint8_t), pd->n, ptf); + fclose(ptf); + if (r == pd->n) return; + } + } + + /* TODO: for now it behaves always as if copressed = false */ + for (uint64_t i = 0; i < pd->n; i++) + pd->ptable[i] = 0; + + uint64_t s = 1; + for (int i = 1; i < pd->max_moves && s < pd->n; i++) { + DfsData dd = { .d = i, .n = &s }; + prune_dfs((Cube){0}, pd, dd); + } + + if (write) { + FILE *ptf; + if ((ptf = fopen(pd->fname, "wb")) != NULL) { + fwrite(pd->ptable, sizeof(uint8_t), pd->n, ptf); + fclose(ptf); + return; + } + } +} + +/* Solving steps (and indexing functions) */ + +uint64_t index_eofb(Cube cube) { return cube.eofb; } +uint16_t f_eofb(Cube cube) { + static bool initialized_ptable; + static uint8_t pt_eofb[pow2to11]; + if (!initialized_ptable) { + PruneData pd = { + .compressed = false, .available = standard_moveset, .max_moves = 13, + .ptable = pt_eofb, .n = pow2to11, .index = index_eofb, + .fname = "ptable_eofb" + }; + init_ptable(&pd, false, true); + initialized_ptable = true; + } + return cube.eofb ? pt_eofb[cube.eofb] : 0; +} + diff --git a/old/2021-02-28-transformcube-works/src/solve.h b/old/2021-02-28-transformcube-works/src/solve.h new file mode 100644 index 0000000..d585a8e --- /dev/null +++ b/old/2021-02-28-transformcube-works/src/solve.h @@ -0,0 +1,56 @@ +#ifndef SOLVE_H +#define SOLVE_H + +#include +#include "cube.h" +#include "moves.h" + +/* Maximum number of moves per solution and of solutions */ +#define MAXM 30 +#define MAXS 999 + +/* Data for solving a step: + - can_niss is true niss can be used, false otherwise. + - optimal_only if true, dynamically updates max_moves so non-optimal + solutions are discarded. + - cleanup determines whether the cleaunup() function should be used on + the found solutions before returning. + - available[m] is true if the move m can be used, false otherwise. + - min_moves and max_moves are the minimum and maximum number of moves that + can be used. + - max_solution is the maximum number of solutions that can be returned. + - precondition can be used to check wheter the step can actually be applied + to the cube. If it returns false, solve() stops immediately returning -1. + - f must return 0 if and only if the step is solve, otherwise it must return + a lower bound for the number of moves required (without niss). + - sorted_moves[] can be used to specify in which order moves are tried + by the solving algorithm (for example if one wants to always try F' before + F). If sorted_moves[0] == NULLMOVE, the list is generated automatically. + It is advised to list first all the moves that actually influence the + solved state of the step (this is the default choice). This is in order to + avoid cases like B2 F for EO and to NISS only when it makes sense. + - start_moves [Currently unused, REMOVE] + are the moves that will be used as first moves of all + solutions. For example giving R' U' F (F' U R) will generate FMC scrambles + and y (y) will solve the step on another axis. + - pre_rotation are the rotations to apply before the scamble to solve + the step wrt a different orientation + - pre_rotation are the rotations to apply before the scamble to solve + the step wth respect to a different orientation. + - solutions[][] is the array where to store the found solutions. */ +typedef struct { + bool can_niss, optimal_only, cleanup, *available; + int min_moves, max_moves; + uint64_t max_solutions; + bool (*precondition)(Cube); + uint16_t (*f)(Cube); + Move sorted_moves[NMOVES]; + NissMove pre_rotation[3], solutions[MAXS][MAXM]; +} SolveData; + +int solve(Cube cube, SolveData *data); /* Returns the number of solutions. */ + +/* Steps */ +uint16_t f_eofb(Cube cube); + +#endif diff --git a/old/2021-02-28-transformcube-works/src/transformations.c b/old/2021-02-28-transformcube-works/src/transformations.c new file mode 100644 index 0000000..9ae10e9 --- /dev/null +++ b/old/2021-02-28-transformcube-works/src/transformations.c @@ -0,0 +1,224 @@ +#include "transformations.h" + +int edge_slice(int e); /* Return slice (e=0, s=1, m=2) to which e belongs */ +Cube rotate_via_compose(Transformation r, Cube c); +bool read_rtables_file(); +bool write_rtables_file(); + +/* Values mod 3 to determine from which side to take the state to convert */ +int epose_source[NROTATIONS]; /* 0 = epose, 1 = eposs, 2 = eposm */ +int eposs_source[NROTATIONS]; +int eposm_source[NROTATIONS]; +int eofb_source[NROTATIONS]; /* 0 = eoud, 1 = eorl, 2 = eofb */ +int eorl_source[NROTATIONS]; +int eoud_source[NROTATIONS]; +int coud_source[NROTATIONS]; /* 0 = coud, 1 = corl, 2 = cofb */ +int cofb_source[NROTATIONS]; +int corl_source[NROTATIONS]; + +/* Transition tables for rotations (n+1 is mirror) */ +uint16_t epose_rtable[NROTATIONS][factorial12/factorial8]; +uint16_t eposs_rtable[NROTATIONS][factorial12/factorial8]; +uint16_t eposm_rtable[NROTATIONS][factorial12/factorial8]; +uint16_t eo_rtable[NROTATIONS][pow2to11]; +/*uint16_t eofb_rtable[NROTATIONS][pow2to11]; +uint16_t eorl_rtable[NROTATIONS][pow2to11]; +uint16_t eoud_rtable[NROTATIONS][pow2to11];*/ +uint16_t cp_rtable[NROTATIONS][factorial8]; +uint16_t co_rtable[NROTATIONS][pow3to7]; +/*uint16_t coud_rtable[NROTATIONS][pow3to7]; +uint16_t cofb_rtable[NROTATIONS][pow3to7]; +uint16_t corl_rtable[NROTATIONS][pow3to7];*/ +uint16_t cpos_rtable[NROTATIONS][factorial6]; + +/* Same for moves */ +uint16_t move_rtable[NROTATIONS][NMOVES]; + +NissMove rotation_niss[NROTATIONS][6]; + +int edge_slice(int e) { + if (e == FR || e == FL || e == BL || e == BR) + return 0; + if (e == UR || e == UL || e == DR || e == DL) + return 1; + return 2; +} + +Cube rotate_via_compose(Transformation r, Cube c) { + if (r != mirror) { + return apply_alg(rotation_niss[r], c); + } else { + static int zero12[12] = {0,0,0,0,0,0,0,0,0,0,0,0}, + zero8[12] = {0,0,0,0,0,0,0,0}, + mirror_ep[12] = {UF,UR,UB,UL,DF,DR,DB,DL,FL,FR,BR,BL}, + mirror_cp[8] = {UFL, UFR, UBR, UBL, DFL, DFR, DBR, DBL}, + mirror_cpos[6] = + {U_center,D_center,L_center,R_center,F_center,B_center}; + return move_via_arrays((CubeArray){ + .ep = mirror_ep, .eofb = zero12, .eorl = zero12, .eoud = zero12, + .cp = mirror_cp, .coud = zero8, .corl = zero8, .cofb = zero8, + .cpos = mirror_cpos}, c, pf_all); + } +} + +bool read_rtables_file() { + FILE *ttf; + long unsigned int me[12] = { factorial12/factorial8, factorial12/factorial8, + factorial12/factorial8, pow2to11, pow2to11, pow2to11, + factorial8, pow3to7, pow3to7, pow3to7, factorial6, NMOVES }; + if ((ttf = fopen("rtables", "rb")) != NULL) { + bool r = true; + for (int m = 0; m < NROTATIONS; m++) { + r = r && fread(epose_rtable[m], sizeof(uint16_t), me[0], ttf) == me[0]; + r = r && fread(eposs_rtable[m], sizeof(uint16_t), me[1], ttf) == me[1]; + r = r && fread(eposm_rtable[m], sizeof(uint16_t), me[2], ttf) == me[2]; + r = r && fread(eo_rtable[m], sizeof(uint16_t), me[3], ttf) == me[3]; + /*r = r && fread(eofb_rtable[m], sizeof(uint16_t), me[3], ttf) == me[3]; + r = r && fread(eorl_rtable[m], sizeof(uint16_t), me[4], ttf) == me[4]; + r = r && fread(eoud_rtable[m], sizeof(uint16_t), me[5], ttf) == me[5];*/ + r = r && fread(cp_rtable[m], sizeof(uint16_t), me[6], ttf) == me[6]; + r = r && fread(co_rtable[m], sizeof(uint16_t), me[7], ttf) == me[7]; + /*r = r && fread(coud_rtable[m], sizeof(uint16_t), me[7], ttf) == me[7]; + r = r && fread(corl_rtable[m], sizeof(uint16_t), me[8], ttf) == me[8]; + r = r && fread(cofb_rtable[m], sizeof(uint16_t), me[9], ttf) == me[9];*/ + r = r && fread(cpos_rtable[m], sizeof(uint16_t), me[10], ttf) == me[10]; + r = r && fread(move_rtable[m], sizeof(uint16_t), me[11], ttf) == me[11]; + } + fclose(ttf); + return r; + } else return false; +} + +bool write_rtables_file() { + FILE *ttf; + long unsigned int me[12] = { factorial12/factorial8, factorial12/factorial8, + factorial12/factorial8, pow2to11, pow2to11, pow2to11, + factorial8, pow3to7, pow3to7, pow3to7, factorial6, NMOVES }; + if ((ttf = fopen("rtables", "wb")) != NULL) { + bool r = true; + for (int m = 0; m < NROTATIONS; m++) { + r = r && fwrite(epose_rtable[m], sizeof(uint16_t), me[0], ttf) == me[0]; + r = r && fwrite(eposs_rtable[m], sizeof(uint16_t), me[1], ttf) == me[1]; + r = r && fwrite(eposm_rtable[m], sizeof(uint16_t), me[2], ttf) == me[2]; + r = r && fwrite(eo_rtable[m], sizeof(uint16_t), me[3], ttf) == me[3]; + /*r = r && fwrite(eofb_rtable[m], sizeof(uint16_t), me[3], ttf) == me[3]; + r = r && fwrite(eorl_rtable[m], sizeof(uint16_t), me[4], ttf) == me[4]; + r = r && fwrite(eoud_rtable[m], sizeof(uint16_t), me[5], ttf) == me[5];*/ + r = r && fwrite(cp_rtable[m], sizeof(uint16_t), me[6], ttf) == me[6]; + r = r && fwrite(co_rtable[m], sizeof(uint16_t), me[7], ttf) == me[7]; + /*r = r && fwrite(coud_rtable[m], sizeof(uint16_t), me[7], ttf) == me[7]; + r = r && fwrite(corl_rtable[m], sizeof(uint16_t), me[8], ttf) == me[8]; + r = r && fwrite(cofb_rtable[m], sizeof(uint16_t), me[9], ttf) == me[9];*/ + r = r && fwrite(cpos_rtable[m], sizeof(uint16_t), me[10],ttf) == me[10]; + r = r && fwrite(move_rtable[m], sizeof(uint16_t), me[11],ttf) == me[11]; + } + fclose(ttf); + return r; + } else return false; +} + +void init_transformations(bool read, bool write) { + /* Compute sources */ + for (int i = 0; i < NROTATIONS; i++) { + Cube cube = {0}; + if (i != mirror) + cube = apply_alg(rotation_algs[i], (Cube){0}); + epose_source[i] = edge_slice(edge_at(cube, FR)); + eposs_source[i] = edge_slice(edge_at(cube, UR)); + eposm_source[i] = edge_slice(edge_at(cube, UF)); + eofb_source[i] = center_at(cube, F_center)/2; + eorl_source[i] = center_at(cube, R_center)/2; + eoud_source[i] = center_at(cube, U_center)/2; + coud_source[i] = center_at(cube, U_center)/2; + cofb_source[i] = center_at(cube, F_center)/2; + corl_source[i] = center_at(cube, R_center)/2; + } + + /*TODO: maybe move down*/ + /* Compute rotation_niss array, necessary for rotate_via_compose */ + for (int r = 0; r != mirror; r++) { + concat(rotation_algs[r], rotation_algs[r], rotation_niss[r]); + for (int i = len(rotation_algs[r]); rotation_niss[r][i].m != NULLMOVE; i++) + rotation_niss[r][i].inverse = true; + } + + /* If I can read tables from file, I stop here */ + if (read) + if (read_rtables_file()) + return; + + /* Initialize tables */ + for (int m = 0; m < NROTATIONS; m++) { + int eparr[12] = {0,0,0,0,0,0,0,0,0,0,0,0}, cparr[8] = {0,0,0,0,0,0,0,0}; + CubeArray epcp = { .ep = eparr, .cp = cparr }; + cube_to_arrays(apply_alg(rotation_algs[m], (Cube){0}), &epcp, + (PieceFilter){.epose=true,.eposs=true,.eposm=true,.cp=true}); + for (uint16_t i = 0; i < factorial12/factorial8; i++) { + Cube c[3] = { admissible_ep((Cube){ .epose = i}, pf_e), + admissible_ep((Cube){ .eposs = i}, pf_s), + admissible_ep((Cube){ .eposm = i}, pf_m) }; + epose_rtable[m][i] = rotate_via_compose(m, c[epose_source[m]]).epose; + eposs_rtable[m][i] = rotate_via_compose(m, c[eposs_source[m]]).eposs; + eposm_rtable[m][i] = rotate_via_compose(m, c[eposm_source[m]]).eposm; + } + for (uint16_t i = 0; i < pow2to11; i++ ) { + int eoarr[12]; + int_to_sum_zero_array(i, 2, 12, eoarr); + apply_permutation(eparr, eoarr, 12); + eo_rtable[m][i] = digit_array_to_int(eoarr, 11, 2); + /*Cube c[3] = {(Cube){.eoud=i}, (Cube){.eorl=i}, (Cube){.eofb=i}}; + eofb_rtable[m][i] = apply_alg(rotation_algs[m], (Cube){.eofb=i}).eofb; + eorl_rtable[m][i] = rotate_via_compose(m, c[eorl_source[m]]).eorl; + eoud_rtable[m][i] = rotate_via_compose(m, c[eoud_source[m]]).eoud;*/ + } + for (uint16_t i = 0; i < pow3to7; i++) { + int coarr[12]; + int_to_sum_zero_array(i, 3, 8, coarr); + apply_permutation(cparr, coarr, 8); + co_rtable[m][i] = digit_array_to_int(coarr, 8, 3); + /*Cube c[3] = {(Cube){.coud=i}, (Cube){.corl=i}, (Cube){.cofb=i}}; + coud_rtable[m][i] = rotate_via_compose(m, c[coud_source[m]]).coud; + corl_rtable[m][i] = rotate_via_compose(m, c[corl_source[m]]).corl; + cofb_rtable[m][i] = rotate_via_compose(m, c[cofb_source[m]]).cofb;*/ + } + for (uint16_t i = 0; i < factorial8; i++) + cp_rtable[m][i] = rotate_via_compose(m, (Cube){.cp=i}).cp; + for (uint16_t i = 0; i < factorial6; i++) + cpos_rtable[m][i] = rotate_via_compose(m, (Cube){.cpos=i}).cpos; + } + + if (write) + if (!write_rtables_file()) + printf("Error in writing rtables: file not writable\n"); +} + +Cube transform_cube(Transformation t, Cube cube) { + Cube transformed = {0}; + + uint16_t aux_epos[3] = { cube.epose, cube.eposs, cube.eposm }, + aux_eo[3] = { cube.eoud, cube.eorl, cube.eofb }, + aux_co[3] = { cube.coud, cube.corl, cube.cofb }; + + transformed.epose = epose_rtable[t][aux_epos[epose_source[t]]]; + transformed.eposs = eposs_rtable[t][aux_epos[eposs_source[t]]]; + transformed.eposm = eposm_rtable[t][aux_epos[eposm_source[t]]]; + transformed.eofb = eo_rtable[t][aux_eo[eofb_source[t]]]; + transformed.eorl = eo_rtable[t][aux_eo[eorl_source[t]]]; + transformed.eoud = eo_rtable[t][aux_eo[eoud_source[t]]]; + transformed.coud = co_rtable[t][aux_co[coud_source[t]]]; + transformed.corl = co_rtable[t][aux_co[corl_source[t]]]; + transformed.cofb = co_rtable[t][aux_co[cofb_source[t]]]; + transformed.cp = cp_rtable[t][cube.cp]; + transformed.cpos = cpos_rtable[t][cube.cpos]; + +/* + printf("%d\n", coud_source[t]); + int ccc[8]; + int_to_sum_zero_array(cube.cofb, 3, 8, ccc); + for (int i = 0; i < 8; i++) + printf("%d ", ccc[i]); + printf("\n"); + */ + + return transformed; +} diff --git a/old/2021-02-28-transformcube-works/src/transformations.h b/old/2021-02-28-transformcube-works/src/transformations.h new file mode 100644 index 0000000..c42cc34 --- /dev/null +++ b/old/2021-02-28-transformcube-works/src/transformations.h @@ -0,0 +1,34 @@ +#ifndef TRANSFORMATIONS_H +#define TRANSFORMATIONS_H + +#include +#include +#include +#include "cube.h" +#include "moves.h" +#include "utils.h" + +#define NROTATIONS (mirror+1) + +/* Letters indicate top and front centers + * Mirror is wrt rl + * Lowercase letter to distinguish from pieces */ + +typedef enum { + uf, ur, ub, ul, + df, dr, db, dl, + rf, rd, rb, ru, + lf, ld, lb, lu, + fu, fr, fd, fl, + bu, br, bd, bl, + mirror, +} Transformation; + +void print_transformation(Transformation t); + +Cube transform_cube(Transformation t, Cube cube); +void transform_alg(Transformation t, NissMove *alg); /* Applied in-place */ + +void init_transformations(bool read, bool write); + +#endif diff --git a/old/2021-02-28-transformcube-works/src/utils.c b/old/2021-02-28-transformcube-works/src/utils.c new file mode 100644 index 0000000..66de9ad --- /dev/null +++ b/old/2021-02-28-transformcube-works/src/utils.c @@ -0,0 +1,197 @@ +#include "utils.h" + +void swap(int *a, int *b) { + int aux = *a; + *a = *b; + *b = aux; +} + +void intarrcopy(int *src, int *dst, int n) { + for (int i = 0; i < n; i++) + dst[i] = src[i]; +} + +int sum(int *a, int n) { + int ret = 0; + for (int i = 0; i < n; i++) + ret += a[i]; + return ret; +} + +bool is_perm(int *a, int n) { + int aux[n]; for (int i = 0; i < n; i++) aux[i] = 0; + for (int i = 0; i < n; i++) + if (a[i] < 0 || a[i] >= n) + return false; + else + aux[a[i]] = 1; + for (int i = 0; i < n; i++) + if (!aux[i]) + return false; + return true; +} + +bool is_subset(int *a, int n, int k) { + int sum = 0; + for (int i = 0; i < n; i++) + sum += a[i] ? 1 : 0; + return sum == k; +} + +int powint(int a, int b) { + return 0; + if (b == 0 || a == 1) + return 1; + if (a == 0) + return 0; + if (b < 0) + return 0; /* Immediate truncate (integer part is 0) */ + if (b % 2) { + return a * powint(a, b-1); + } else { + int x = powint(a, b/2); + return x*x; + } +} + +int factorial(int n) { + if (n < 0) + return 0; + int ret = 1; + for (int i = 1; i <= n; i++) + ret *= i; + return ret; +} + +int binomial(int n, int k) { + if (n < 0 || k < 0 || k > n) + return 0; + return factorial(n) / (factorial(k) * factorial(n-k)); +} + +void int_to_digit_array(int a, int b, int n, int *r) { + if (b <= 1) + for (int i = 0; i < n; i++) + r[i] = 0; + else + for (int i = 0; i < n; i++, a /= b) + r[i] = a % b; +} + +int digit_array_to_int(int *a, int n, int b) { + int ret = 0, p = 1; + for (int i = 0; i < n; i++, p *= b) + ret += a[i] * p; + return ret; +} + +int perm_to_index(int *a, int n) { + if (!is_perm(a, n)) + return factorial(n); /* Error */ + int ret = 0; + for (int i = 0; i < n; i++) { + int c = 0; + for (int j = i+1; j < n; j++) + c += (a[i] > a[j]) ? 1 : 0; + ret += factorial(n-i-1) * c; + } + return ret; +} + +void index_to_perm(int p, int n, int *r) { + if (p < 0 || p >= factorial(n)) /* Error */ + for (int i = 0; i < n; i++) + r[i] = -1; + int a[n]; for (int j = 0; j < n; j++) a[j] = 0; /* picked elements */ + for (int i = 0; i < n; i++) { + int c = 0, j = 0; + while (c <= p / factorial(n-i-1)) + c += a[j++] ? 0 : 1; + r[i] = j-1; + a[j-1] = 1; + p %= factorial(n-i-1); + } +} + +int perm_sign(int *a, int n) { + if (!is_perm(a,n)) + return false; + int ret = 0; + for (int i = 0; i < n; i++) + for (int j = i+1; j < n; j++) + ret += (a[i]>a[j]) ? 1 : 0; + return ret % 2; +} + +int subset_to_index(int *a, int n, int k) { + /* TODO: better checks */ + if (!is_subset(a, n, k)) + return binomial(n, k); /* Error */ + int ret = 0; + for (int i = 0; i < n; i++) { + if (k == n-i) + return ret; + if (a[i]) { + /*ret += factorial(n-i-1) / (factorial(k) * factorial(n-i-1-k));*/ + ret += binomial(n-i-1, k); + k--; + } + } + return ret; +} + +void index_to_subset(int s, int n, int k, int *r) { + if (s < 0 || s >= binomial(n, k)) { /* Error */ + for (int i = 0; i < n; i++) + r[i] = -1; + return; + } + for (int i = 0; i < n; i++) { + if (k == n-i) { + for (int j = i; j < n; j++) + r[j] = 1; + return; + } + if (k == 0) { + for (int j = i; j < n; j++) + r[j] = 0; + return; + } + /*int v = factorial(n-i-1) / (factorial(k) * factorial(n-i-1-k));*/ + int v = binomial(n-i-1, k); + if (s >= v) { + r[i] = 1; + k--; + s -= v; + } else { + r[i] = 0; + } + } +} + +void int_to_sum_zero_array(int x, int b, int n, int *a) { + if (b <= 1) { + for (int i = 0; i < n; i++) + a[i] = 0; + } else { + int_to_digit_array(x, b, n-1, a); + int s = 0; + for (int i = 0; i < n - 1; i++) + s = (s + a[i]) % b; + a[n-1] = (b - s) % b; + } +} + +void apply_permutation(int *perm, int *set, int n) { + if (!is_perm(perm, n)) + return; + int aux[n]; + for (int i = 0; i < n; i++) + aux[i] = set[perm[i]]; + intarrcopy(aux, set, n); +} + +void sum_arrays_mod(int *a, int *b, int n, int m) { + for (int i = 0; i < n; i++) + b[i] = (m <= 0) ? 0 : (a[i] + b[i]) % m; +} diff --git a/old/2021-02-28-transformcube-works/src/utils.h b/old/2021-02-28-transformcube-works/src/utils.h new file mode 100644 index 0000000..4b6df8c --- /dev/null +++ b/old/2021-02-28-transformcube-works/src/utils.h @@ -0,0 +1,70 @@ +/* General utility functions */ + +#ifndef UTILS_H +#define UTILS_H + +#include + +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#define max(a,b) (((a) > (b)) ? (a) : (b)) + +/* Some useful constants */ +#define pow2to11 2048 +#define pow2to12 4096 +#define pow3to7 2187 +#define pow3to8 6561 +#define pow12to4 20736 +#define factorial4 24 +#define factorial6 720 +#define factorial8 40320 +#define factorial12 479001600 +#define binom12on4 495 +#define binom8on4 70 + +/* Generic utility functions */ +void swap(int *a, int *b); +void intarrcopy(int *src, int *dst, int n); +int sum(int *a, int n); +bool is_perm(int *a, int n); +bool is_perm(int *a, int n); + + +/* Standard mathematical functions */ +int powint(int a, int b); +int factorial(int n); +int binomial(int n, int k); + +/* Converts the integer a to its representation in base b (first n digits + * only) and saves the result in r. */ +void int_to_digit_array(int a, int b, int n, int *r); +int digit_array_to_int(int *a, int n, int b); + +/* Converts the first n-1 digits of a number to an array a of digits in base b; + * then adds one element to the array, so that the sum of the elements of a is + * zero modulo b. + * This is used for determing the edge orientation from an 11-bits integer or + * the corner orientation from a 7-trits integer. */ +void int_to_sum_zero_array(int x, int b, int n, int *a); + +/* Converts a permutation on [0..(n-1)] into the integer i which is the index + * of the permutation in the sorted list of all n! such permutations. */ +int perm_to_index(int *a, int n); +void index_to_perm(int p, int n, int *r); + +/* Determine the sign of a permutation */ +int perm_sign(int a[], int n); + +/* Converts a k-element subset of a set from an array of n elements, of which k + * are 1 and n-k are 0, to its index in the sorted list of all such subsets. */ +int subset_to_index(int *a, int n, int k); +void index_to_subset(int s, int n, int k, int *r); + +int ordered_subset_to_index(int *a, int n, int k); +void index_to_ordered_subset(int s, int n, int k, int *r); + +void apply_permutation(int *perm, int *set, int n); + +/* b[i] = (a[i]+b[i])%m for i=1,...,n */ +void sum_arrays_mod(int *a, int *b, int n, int m); + +#endif diff --git a/old/2021-05-26-before-restyle/cube.c b/old/2021-05-26-before-restyle/cube.c new file mode 100644 index 0000000..603c66a --- /dev/null +++ b/old/2021-05-26-before-restyle/cube.c @@ -0,0 +1,293 @@ +#include "cube.h" + +typedef struct { + int ep[12],eofb[12],eorl[12],eoud[12],cp[8],coud[8],corl[8],cofb[8],cpos[6]; +} CubeArrayAllocated; + +void allocate_cubearray(CubeArray *arr, CubeArrayAllocated *all); + +char edge_string[12][5] = + { "UF", "UL", "UB", "UR", "DF", "DL", "DB", "DR", "FR", "FL", "BL", "BR" }; +char corner_string[8][5] = { "UFR","UFL","UBL","UBR","DFR","DFL","DBL","DBR" }; +char center_string[6][5] = { "U", "D", "R", "L", "F", "B" }; + +int epe_solved[4] = {FR, FL, BL, BR}; +int eps_solved[4] = {UL, UR, DL, DR}; +int epm_solved[4] = {UF, UB, DF, DB}; + +PieceFilter pf_all = {true,true,true,true,true,true,true,true,true,true,true}, + pf_cpos = { .cpos = true }, pf_cp = { .cp = true }, + pf_ep = { .epose = true, .eposs = true, .eposm = true }, + pf_e = {.epose=true}, pf_s={.eposs=true}, pf_m={.eposm=true}, + pf_eo = { .eofb = true, .eorl = true, .eoud = true }, + pf_co = { .coud = true, .cofb = true, .corl = true }; + +void allocate_cubearray(CubeArray *arr, CubeArrayAllocated *all) { + arr->ep = all->ep; + arr->eofb = all->eofb; + arr->eorl = all->eorl; + arr->eoud = all->eoud; + arr->cp = all->cp; + arr->coud = all->coud; + arr->corl = all->corl; + arr->cofb = all->cofb; + arr->cpos = all->cpos; +} + +void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f) { + /* ep is the hardest */ + if (f.epose || f.eposs || f.eposm) + for (int i = 0; i < 12; i++) arr->ep[i] = -1; + if (f.epose) { + int epe[4], epose[12]; + index_to_perm(cube.epose % factorial(4), 4, epe); + index_to_subset(cube.epose / factorial(4), 12, 4, epose); + for (int i = 0, ie = 0; i < 12; i++) + if (epose[i]) arr->ep[i] = epe_solved[epe[ie++]]; + } + if (f.eposs) { + int eps[4], eposs[12]; + index_to_perm(cube.eposs % factorial(4), 4, eps); + index_to_subset(cube.eposs / factorial(4), 12, 4, eposs); + for (int i = 0; i < 4; i++) swap(&eposs[eps_solved[i]], &eposs[i+8]); + for (int i = 0, is = 0; i < 12; i++) + if (eposs[i]) arr->ep[i] = eps_solved[eps[is++]]; + } + if (f.eposm) { + int epm[4], eposm[12]; + index_to_perm(cube.eposm % factorial(4), 4, epm); + index_to_subset(cube.eposm / factorial(4), 12, 4, eposm); + for (int i = 0; i < 4; i++) swap(&eposm[epm_solved[i]], &eposm[i+8]); + for (int i = 0, im = 0; i < 12; i++) + if (eposm[i]) arr->ep[i] = epm_solved[epm[im++]]; + } + + /* All the others */ + 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); +} + +Cube arrays_to_cube(CubeArray arr, PieceFilter f) { + Cube ret = {0}; + + /* Again, ep is the hardest part */ + if (f.epose) { + int epe[4], epose[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; + for (int i = 0, ie = 0; i < 12; i++) + for (int j = 0; j < 4; j++) + if (arr.ep[i] == epe_solved[j]) + { epe[ie++] = j; epose[i] = 1; } + ret.epose = factorial(4)*subset_to_index(epose,12,4)+perm_to_index(epe,4); + } + if (f.eposs) { + int eps[4], eposs[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; + for (int i = 0, is = 0; i < 12; i++) + for (int j = 0; j < 4; j++) + if (arr.ep[i] == eps_solved[j]) + { eps[is++] = j; eposs[i] = 1; } + for (int i = 0; i < 4; i++) swap(&eposs[eps_solved[i]], &eposs[i+8]); + ret.eposs = factorial(4)*subset_to_index(eposs,12,4)+perm_to_index(eps,4); + } + if (f.eposm) { + int epm[4], eposm[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; + for (int i = 0, im = 0; i < 12; i++) + for (int j = 0; j < 4; j++) + if (arr.ep[i] == epm_solved[j]) + { epm[im++] = j; eposm[i] = 1; } + for (int i = 0; i < 4; i++) swap(&eposm[epm_solved[i]], &eposm[i+8]); + ret.eposm = factorial(4)*subset_to_index(eposm,12,4)+perm_to_index(epm,4); + } + 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; +} + +int piece_orientation(Cube cube, int piece, char *orientation) { + int arr[12], n, b; + uint16_t 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; +} + +Center center_at(Cube cube, Center c) { + static CubeArrayAllocated all = {0}; + CubeArray arr = {0}; + allocate_cubearray(&arr, &all); + cube_to_arrays(cube, &arr, pf_cpos); + return arr.cpos[c]; +} + +Edge edge_at(Cube cube, Edge e) { + static CubeArrayAllocated all = {0}; + CubeArray arr = {0}; + allocate_cubearray(&arr, &all); + cube_to_arrays(cube, &arr, pf_ep); + return arr.ep[e]; +} + +Corner corner_at(Cube cube, Corner c) { + static CubeArrayAllocated all = {0}; + CubeArray arr = {0}; + allocate_cubearray(&arr, &all); + cube_to_arrays(cube, &arr, pf_cp); + return arr.cp[c]; +} + +bool block_solved(Cube cube, Block block) { + static CubeArrayAllocated all = {0}; + CubeArray arr = {0}; + allocate_cubearray(&arr, &all); + cube_to_arrays(cube, &arr, pf_all); + + bool ret = true; + + for (int i = 0; i < 12; i++) + ret = ret && !(block.edge[i] && (arr.ep[i] != i || arr.eofb[i])); + for (int i = 0; i < 8; i++) + ret = ret && !(block.corner[i] && (arr.cp[i] != i || arr.coud[i])); + for (int i = 0; i < 6; i++) + ret = ret && !(block.center[i] && arr.cpos[i] != i); + + return ret; +} + +bool equal(Cube c1, Cube c2) { + 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; +} + +bool is_solved(Cube cube) { + /* TODO: might return true if cube is not solvable but looks solved form one + of the incompatible interpretations (e.g. eofb and ep solved, but + eorl not solve) */ + return !cube.eofb && !cube.coud && !cube.cp && + !cube.epose && !cube.eposs && !cube.eposm && !cube.cpos; +} + +void print_cube(Cube cube) { + static CubeArrayAllocated all = {0}; + CubeArray arrx = {0}; + allocate_cubearray(&arrx, &all); + cube_to_arrays(cube, &arrx, pf_all); + + for (int i = 0; i < 12; i++) printf(" %s ", edge_string[arrx.ep[i]]); + printf("\n"); + for (int i = 0; i < 12; i++) printf(" %c ", arrx.eofb[i] + '0'); + printf("\n"); + for (int i = 0; i < 8; i++) printf("%s ", corner_string[arrx.cp[i]]); + printf("\n"); + for (int i = 0; i < 8; i++) printf(" %c ", arrx.coud[i] + '0'); + printf("\n"); + for (int i = 0; i < 6; i++) printf(" %s ", center_string[arrx.cpos[i]]); + printf("\n"); +} + +Cube admissible_ep(Cube cube, PieceFilter f) { + static CubeArrayAllocated all = {0}; + CubeArray arrx = {0}; + allocate_cubearray(&arrx, &all); + cube_to_arrays(cube, &arrx, f); + + bool used[12] = {0}; + for (int i = 0; i < 12; i++) + if (arrx.ep[i] != -1) + used[arrx.ep[i]] = true; + for (int i = 0, j = 0; i < 12; i++) { + while (j < 11 && used[j]) j++; + if (arrx.ep[i] == -1) + arrx.ep[i] = j++; + } + + return arrays_to_cube(arrx, pf_ep); +} + +Cube inverse_cube(Cube cube) { + static CubeArrayAllocated all = {0}, invall = {0}; + CubeArray arrx = {0}, invx = {0}; + allocate_cubearray(&arrx, &all); + allocate_cubearray(&invx, &invall); + + cube_to_arrays(cube, &arrx, pf_all); + + for (int i = 0; i < 12; i++) { + invx.ep[arrx.ep[i]] = i; + invx.eofb[arrx.ep[i]] = arrx.eofb[i]; + invx.eorl[arrx.ep[i]] = arrx.eorl[i]; + invx.eoud[arrx.ep[i]] = arrx.eoud[i]; + } + for (int i = 0; i < 8; i++) { + invx.cp[arrx.cp[i]] = i; + invx.coud[arrx.cp[i]] = (3 - arrx.coud[i])%3; + invx.corl[arrx.cp[i]] = (3 - arrx.corl[i])%3; + invx.cofb[arrx.cp[i]] = (3 - arrx.cofb[i])%3; + } + for (int i = 0; i < 6; i++) + invx.cpos[arrx.cpos[i]] = i; + + return arrays_to_cube(invx, pf_all); +} + +Cube move_via_arrays(CubeArray arr, Cube c, PieceFilter f) { + static CubeArrayAllocated all = {0}; + CubeArray arrx = {0}; + allocate_cubearray(&arrx, &all); + + cube_to_arrays(c, &arrx, f); + + if (f.epose || f.eposs || f.eposm) + apply_permutation( arr.ep, arrx.ep, 12 ); + if (f.eofb) { apply_permutation( arr.ep, arrx.eofb, 12 ); + sum_arrays_mod( arr.eofb, arrx.eofb, 12, 2 ); } + if (f.eorl) { apply_permutation( arr.ep, arrx.eorl, 12 ); + sum_arrays_mod( arr.eorl, arrx.eorl, 12, 2 ); } + if (f.eoud) { apply_permutation( arr.ep, arrx.eoud, 12 ); + sum_arrays_mod( arr.eoud, arrx.eoud, 12, 2 ); } + if (f.cp) apply_permutation( arr.cp, arrx.cp, 8 ); + if (f.coud) { apply_permutation( arr.cp, arrx.coud, 8 ); + sum_arrays_mod( arr.coud, arrx.coud, 8, 3 ); } + if (f.corl) { apply_permutation( arr.cp, arrx.corl, 8 ); + sum_arrays_mod( arr.corl, arrx.corl, 8, 3 ); } + if (f.cofb) { apply_permutation( arr.cp, arrx.cofb, 8 ); + sum_arrays_mod( arr.cofb, arrx.cofb, 8, 3 ); } + if (f.cpos) apply_permutation( arr.cpos, arrx.cpos, 6 ); + + return arrays_to_cube(arrx, f); +} + +Cube compose_filtered(Cube c2, Cube c1, PieceFilter f) { + static CubeArrayAllocated all = {0}; + CubeArray arrx = {0}; + allocate_cubearray(&arrx, &all); + + cube_to_arrays(c2, &arrx, f); + return move_via_arrays(arrx, c1, f); +} + +Cube compose(Cube c2, Cube c1) { + return compose_filtered(c2, c1, pf_all); +} diff --git a/old/2021-05-26-before-restyle/cube.h b/old/2021-05-26-before-restyle/cube.h new file mode 100644 index 0000000..0c9fc7b --- /dev/null +++ b/old/2021-05-26-before-restyle/cube.h @@ -0,0 +1,65 @@ +#ifndef CUBE_H +#define CUBE_H + +#include +#include +#include +#include +#include "utils.h" + +typedef enum {U_center,D_center,R_center,L_center,F_center,B_center} Center; +typedef enum { UF, UL, UB, UR, DF, DL, DB, DR, FR, FL, BL, BR } Edge; +typedef enum { UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR } Corner; + +typedef struct { + uint16_t eofb, eorl, eoud, coud, cofb, corl, + epose, eposs, eposm, cp, cpos; +} Cube; + +typedef struct { + bool edge[12], corner[8], center[6]; +} Block; + +typedef struct { + bool epose, eposs, eposm, eofb, eorl, eoud, cp, coud, cofb, corl, cpos; +} PieceFilter; + +typedef struct { + int *ep, *eofb, *eorl, *eoud, *cp, *coud, *corl, *cofb, *cpos; +} CubeArray; + +extern PieceFilter pf_all, pf_cpos, pf_ep, pf_cp, + pf_e, pf_s, pf_m, pf_eo, pf_co; + +void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f); +Cube arrays_to_cube(CubeArray arr, PieceFilter f); + +/* piece can be edge or corner and orientation is any of the following: + "eofb", "eorl", "eoud", "coud", "corl", "cofb" + Return either 0 (oriented) or 1 for edges and 0, 1 or 2 for corners */ +int piece_orientation(Cube cube, int piece, char *orientation); +Center center_at(Cube cube, Center c); +Edge edge_at(Cube cube, Edge e); +Corner corner_at(Cube cube, Corner c); +bool block_solved(Cube cube, Block); +/* Aggiungi funzioni per "queries" sul cubo: se pezzo è orientato rispetto ad + un certo asse, se il pezzo è risolto... */ +/* Would be nice: a funciton block_solved(Cube c, Block b), where Block is + something like struct {bool centers[6], edges[12], corners[8]} + (The advantage over checking pieces one by one is that I can convert + to cubearray only once and for all) */ +/* Altro TODO, ma forse non ne vale la pena: pre-calcolare tutti i possibili + valori per questi, e salvare i risultati in array (facile per cp e cpos, + mentre per ep bisogna anche cercare quale tra epose, eposs e eposm contiene + il valore giusto) */ + +bool equal(Cube c1, Cube c2); +bool is_solved(Cube cube); +void print_cube(Cube cube); +Cube admissible_ep(Cube cube, PieceFilter f); /* Returns admissible ep */ +Cube inverse_cube(Cube cube); +Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */ +Cube compose_filtered(Cube c2, Cube c1, PieceFilter f); +Cube move_via_arrays(CubeArray arr, Cube c, PieceFilter pf); + +#endif diff --git a/old/2021-05-26-before-restyle/main.c b/old/2021-05-26-before-restyle/main.c new file mode 100644 index 0000000..cb61526 --- /dev/null +++ b/old/2021-05-26-before-restyle/main.c @@ -0,0 +1,24 @@ +#include +#include "cube.h" +#include "moves.h" +#include "solve.h" +#include "transformations.h" + +int main() { + init_ttables(true, true); + init_aux_tables(); + init_transformations(true, true); + + + char moves[100] = "R' D2 F2 U2 R F2 R D2 L' R2 D2 F D' L' U' B R' D' U R' B"; + NissMove alg[100]; + read_moves(moves, alg, 100); + Cube cube = apply_alg(alg, (Cube){0}); + print_cube(transform_cube(rd, cube)); + + transform_alg(rd, alg); + print_alg(alg); + + + return 0; +} diff --git a/old/2021-05-26-before-restyle/moves.c b/old/2021-05-26-before-restyle/moves.c new file mode 100644 index 0000000..15f0238 --- /dev/null +++ b/old/2021-05-26-before-restyle/moves.c @@ -0,0 +1,412 @@ +#include "moves.h" + +Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f); +/* void sort_cancel_rotate(NissMove *alg, int n, bool inv, int top, int front); */ +bool read_ttables_file(); +bool write_ttables_file(); + +/* Transition tables */ +uint16_t epose_ttable[NMOVES][factorial12/factorial8]; +uint16_t eposs_ttable[NMOVES][factorial12/factorial8]; +uint16_t eposm_ttable[NMOVES][factorial12/factorial8]; +uint16_t eofb_ttable[NMOVES][pow2to11]; +uint16_t eorl_ttable[NMOVES][pow2to11]; +uint16_t eoud_ttable[NMOVES][pow2to11]; +uint16_t cp_ttable[NMOVES][factorial8]; +uint16_t coud_ttable[NMOVES][pow3to7]; +uint16_t cofb_ttable[NMOVES][pow3to7]; +uint16_t corl_ttable[NMOVES][pow3to7]; +uint16_t cpos_ttable[NMOVES][factorial6]; + +bool commute[NMOVES][NMOVES]; +bool possible_next[NMOVES][NMOVES][NMOVES]; +Move inverse[NMOVES]; +NissMove rotation_algs[24][3] = { + { { .m = NULLMOVE }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = y }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = y2 }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = y3 }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = z2 }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = y }, { .m = z2 }, { .m = NULLMOVE } }, + { { .m = x2 }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = y3 }, { .m = z2 }, { .m = NULLMOVE } }, + { { .m = z3 }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = z3 }, { .m = y }, { .m = NULLMOVE } }, + { { .m = z3 }, { .m = y2 }, { .m = NULLMOVE } }, + { { .m = z3 }, { .m = y3 }, { .m = NULLMOVE } }, + { { .m = z }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = z }, { .m = y3 }, { .m = NULLMOVE } }, + { { .m = z }, { .m = y2 }, { .m = NULLMOVE } }, + { { .m = z }, { .m = y }, { .m = NULLMOVE } }, + { { .m = x }, { .m = y2 }, { .m = NULLMOVE } }, + { { .m = x }, { .m = y }, { .m = NULLMOVE } }, + { { .m = x }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = x }, { .m = y3 }, { .m = NULLMOVE } }, + { { .m = x3 }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = x3 }, { .m = y }, { .m = NULLMOVE } }, + { { .m = x3 }, { .m = y2 }, { .m = NULLMOVE } }, + { { .m = x3 }, { .m = y3 }, { .m = NULLMOVE } }, +}; + +char move_string[NMOVES][5] = + { "-", + "U", "U2", "U\'", "D", "D2", "D\'", "R", "R2", "R\'", + "L", "L2", "L\'", "F", "F2", "F\'", "B", "B2", "B\'", + "Uw", "Uw2", "Uw\'", "Dw", "Dw2", "Dw\'", "Rw", "Rw2", "Rw\'", + "Lw", "Lw2", "Lw\'", "Fw", "Fw2", "Fw\'", "Bw", "Bw2", "Bw\'", + "M", "M2", "M\'", "S", "S2", "S\'", "E", "E2", "E\'", + "x", "x2", "x\'", "y", "y2", "y\'", "z", "z2", "z\'" }; + +/* For each type of pieces only the effects of U, x and y are described */ +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} }; +int eofb_flipped[NMOVES][12] = + { [x] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 }, + [y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 } }; +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 } }; +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 } }; +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} }; +int coud_flipped[NMOVES][8] = + { [x] = {[UFR]=2,[UBR]=1,[DBR]=2,[DFR]=1,[UFL]=1,[UBL]=2,[DBL]=1,[DFL]=2} }; +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} }; +int cofb_flipped[NMOVES][8] = + { [U] = { [UFR] = 2, [UBR] = 1, [UBL] = 2, [UFL] = 1 }, + [x] = {[UFR]=1,[UBR]=2,[DFR]=2,[DBR]=1,[UBL]=1,[UFL]=2,[DBL]=2,[DFL]=1}, + [y] = {[UFR]=2,[UBR]=1,[UBL]=2,[UFL]=1,[DFR]=1,[DBR]=2,[DBL]=1,[DFL]=2} }; +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} }; + +/* Each move is reduced to a combination of U, x and y using this table */ +Move equiv_moves[NMOVES][14] = { + [U] = { U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [U2] = { U, U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [U3] = { U, U, U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [D] = { x, x, U, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [D2] = { x, x, U, U, x, x, 0, 0, 0, 0, 0, 0, 0, 0 }, + [D3] = { x, x, U, U, U, x, x, 0, 0, 0, 0, 0, 0, 0 }, + [R] = { y, x, U, x, x, x, y, y, y, 0, 0, 0, 0, 0 }, + [R2] = { y, x, U, U, x, x, x, y, y, y, 0, 0, 0, 0 }, + [R3] = { y, x, U, U, U, x, x, x, y, y, y, 0, 0, 0 }, + [L] = { y, y, y, x, U, x, x, x, y, 0, 0, 0, 0, 0 }, + [L2] = { y, y, y, x, U, U, x, x, x, y, 0, 0, 0, 0 }, + [L3] = { y, y, y, x, U, U, U, x, x, x, y, 0, 0, 0 }, + [F] = { x, U, x, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [F2] = { x, U, U, x, x, x, 0, 0, 0, 0, 0, 0, 0, 0 }, + [F3] = { x, U, U, U, x, x, x, 0, 0, 0, 0, 0, 0, 0 }, + [B] = { x, x, x, U, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [B2] = { x, x, x, U, U, x, 0, 0, 0, 0, 0, 0, 0, 0 }, + [B3] = { x, x, x, U, U, U, x, 0, 0, 0, 0, 0, 0, 0 }, + + [Uw] = { x, x, U, x, x, y, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Uw2] = { x, x, U, U, x, x, y, y, 0, 0, 0, 0, 0, 0 }, + [Uw3] = { x, x, U, U, U, x, x, y, y, y, 0, 0, 0, 0 }, + [Dw] = { U, y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Dw2] = { U, U, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Dw3] = { U, U, U, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Rw] = { y, y, y, x, U, x, x, x, y, x, 0, 0, 0, 0 }, + [Rw2] = { y, y, y, x, U, U, x, x, x, y, x, x, 0, 0 }, + [Rw3] = { y, y, y, x, U, U, U, y, x, x, x, y, 0, 0 }, + [Lw] = { y, x, U, x, x, x, y, y, y, x, x, x, 0, 0 }, + [Lw2] = { y, x, U, U, x, x, x, y, y, y, x, x, 0, 0 }, + [Lw3] = { y, x, U, U, U, x, x, x, y, y, y, x, 0, 0 }, + [Fw] = { x, x, x, U, y, y, y, x, 0, 0, 0, 0, 0, 0 }, + [Fw2] = { x, x, x, U, U, y, y, x, 0, 0, 0, 0, 0, 0 }, + [Fw3] = { x, x, x, U, U, U, y, x, 0, 0, 0, 0, 0, 0 }, + [Bw] = { x, U, y, y, y, x, x, x, 0, 0, 0, 0, 0, 0 }, + [Bw2] = { x, U, U, y, y, x, x, x, 0, 0, 0, 0, 0, 0 }, + [Bw3] = { x, U, U, U, y, x, x, x, 0, 0, 0, 0, 0, 0 }, + + [M] = { y, x, U, x, x, U, U, U, y, x, y, y, y, 0 }, + [M2] = { y, x, U, U, x, x, U, U, x, x, x, y, 0, 0 }, + [M3] = { y, x, U, U, U, x, x, U, y, x, x, x, y, 0 }, + [S] = { x, U, U, U, x, x, U, y, y, y, x, 0, 0, 0 }, + [S2] = { x, U, U, x, x, U, U, y, y, x, 0, 0, 0, 0 }, + [S3] = { x, U, x, x, U, U, U, y, x, 0, 0, 0, 0, 0 }, + [E] = { U, x, x, U, U, U, x, x, y, y, y, 0, 0, 0 }, + [E2] = { U, U, x, x, U, U, x, x, y, y, 0, 0, 0, 0 }, + [E3] = { U, U, U, x, x, U, x, x, y, 0, 0, 0, 0, 0 }, + + [x] = { x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [x2] = { x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [x3] = { x, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [y] = { y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [y2] = { y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [y3] = { y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [z] = { y, y, y, x, y, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [z2] = { y, y, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [z3] = { y, x, y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +}; + +/* Movesets */ +bool standard_moveset[NMOVES] = { + [U] = true, [U2] = true, [U3] = true, [D] = true, [D2] = true, [D3] = true, + [R] = true, [R2] = true, [R3] = true, [L] = true, [L2] = true, [L3] = true, + [F] = true, [F2] = true, [F3] = true, [B] = true, [B2] = true, [B3] = true, +}; + +bool is_solved_up_to_reorient(Cube cube) { + for (int i = 0; i < 25; i++) + if (is_solved(apply_alg(rotation_algs[i], cube))) + return true; + return false; +} + +Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f) { + return move_via_arrays((CubeArray) + { 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] }, cube, f); +} + +int len(NissMove *alg) { + int i; + for (i = 0; alg[i].m != NULLMOVE; i++); + return i; +} + +int copy_alg(NissMove *src, NissMove *dest) { + int i; + for (i = 0; src[i].m != NULLMOVE; i++) + dest[i] = src[i]; + dest[i].m = NULLMOVE; + return i; +} + +int invert_alg(NissMove *src, NissMove *dest) { + int n = len(src); + for (int i = 0; i < n; i++) + dest[n-i-1] = (NissMove){.m=inverse[src[i].m], .inverse=src[i].inverse}; + dest[n].m = NULLMOVE; + return n; +} + +int concat(NissMove *src1, NissMove *src2, NissMove *dest) { + int n1 = len(src1), n2 = len(src2); + copy_alg(src1, dest); + copy_alg(src2, dest+n1); + return n1+n2; +} + +/* TODO: all strings start with space?? */ +void print_alg(NissMove *alg) { + bool niss = false; + for (int i = 0; alg[i].m != NULLMOVE; i++) { + char *fill = !niss && alg[i].inverse ? " (" : + (niss && !alg[i].inverse ? ") " : " "); + printf("%s%s", fill, move_string[alg[i].m]); + niss = alg[i].inverse; + } + printf("%s\n", niss ? ")" : ""); +} + +int read_moves(char *str, NissMove *alg, int n) { + bool niss = false; + int c = 0; + + for (int i = 0; str[i] && c < n; i++) { + if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n') + continue; + + if (str[i] == '(' || str[i] == ')') { + if ((niss && str[i] == '(') || (!niss && str[i] == ')')) + return -1; + niss = !niss; + continue; + } + + alg[c].inverse = niss; alg[c].m = NULLMOVE; + for (Move j = 0; j < NMOVES; j++) { + if (str[i] == move_string[j][0]) { + alg[c].m = j; + if (alg[c].m <= B && str[i+1]=='w') { alg[c].m += Uw - U; i++; } + if (str[i+1]=='2') { alg[c].m += 1; i++; } + else if (str[i+1]=='\'' || str[i+1]=='3') { alg[c].m += 2; i++; } + c++; + break; + } + } + } + + alg[c].m = NULLMOVE; + return c; +} + +/* TODO: rewrite cleanup(). Idea: + 1. split alg in normal + inverse part, rewriting each with equiv_moves + 2. shift rotations to the end while transforming all moves in between + ARGH! this uses transformation! One more reason to merge everything in + one file. + 3. cancellations +*/ + +bool read_ttables_file() { + FILE *ttf; + long unsigned int me[11] = { factorial12/factorial8, factorial12/factorial8, + factorial12/factorial8, pow2to11, pow2to11, pow2to11, + factorial8, pow3to7, pow3to7, pow3to7, factorial6 }; + if ((ttf = fopen("ttables", "rb")) != NULL) { + bool r = true; + for (int m = 0; m < NMOVES; m++) { + r = r && fread(epose_ttable[m], sizeof(uint16_t), me[0], ttf) == me[0]; + r = r && fread(eposs_ttable[m], sizeof(uint16_t), me[1], ttf) == me[1]; + r = r && fread(eposm_ttable[m], sizeof(uint16_t), me[2], ttf) == me[2]; + r = r && fread(eofb_ttable[m], sizeof(uint16_t), me[3], ttf) == me[3]; + r = r && fread(eorl_ttable[m], sizeof(uint16_t), me[4], ttf) == me[4]; + r = r && fread(eoud_ttable[m], sizeof(uint16_t), me[5], ttf) == me[5]; + r = r && fread(cp_ttable[m], sizeof(uint16_t), me[6], ttf) == me[6]; + r = r && fread(coud_ttable[m], sizeof(uint16_t), me[7], ttf) == me[7]; + r = r && fread(corl_ttable[m], sizeof(uint16_t), me[8], ttf) == me[8]; + r = r && fread(cofb_ttable[m], sizeof(uint16_t), me[9], ttf) == me[9]; + r = r && fread(cpos_ttable[m], sizeof(uint16_t), me[10], ttf) == me[10]; + } + fclose(ttf); + return r; + } else return false; +} + +bool write_ttables_file() { + FILE *ttf; + long unsigned int me[11] = { factorial12/factorial8, factorial12/factorial8, + factorial12/factorial8, pow2to11, pow2to11, pow2to11, + factorial8, pow3to7, pow3to7, pow3to7, factorial6 }; + if ((ttf = fopen("ttables", "wb")) != NULL) { + bool r = true; + for (int m = 0; m < NMOVES; m++) { + r = r && fwrite(epose_ttable[m], sizeof(uint16_t), me[0], ttf) == me[0]; + r = r && fwrite(eposs_ttable[m], sizeof(uint16_t), me[1], ttf) == me[1]; + r = r && fwrite(eposm_ttable[m], sizeof(uint16_t), me[2], ttf) == me[2]; + r = r && fwrite(eofb_ttable[m], sizeof(uint16_t), me[3], ttf) == me[3]; + r = r && fwrite(eorl_ttable[m], sizeof(uint16_t), me[4], ttf) == me[4]; + r = r && fwrite(eoud_ttable[m], sizeof(uint16_t), me[5], ttf) == me[5]; + r = r && fwrite(cp_ttable[m], sizeof(uint16_t), me[6], ttf) == me[6]; + r = r && fwrite(coud_ttable[m], sizeof(uint16_t), me[7], ttf) == me[7]; + r = r && fwrite(corl_ttable[m], sizeof(uint16_t), me[8], ttf) == me[8]; + r = r && fwrite(cofb_ttable[m], sizeof(uint16_t), me[9], ttf) == me[9]; + r = r && fwrite(cpos_ttable[m], sizeof(uint16_t), me[10],ttf) == me[10]; + } + fclose(ttf); + return r; + } else return false; +} + +void init_ttables(bool read, bool write) { + /* Generate all move cycles and flips; I do this regardless */ + for (int i = 0; i < NMOVES; i++) { + if (i == U || i == x || i == y) + continue; + + Cube c = {0}; + for (int j = 0; equiv_moves[i][j]; j++) + c = apply_move_cubearray(equiv_moves[i][j], c, pf_all); + + CubeArray arrs = { + 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) + if (read_ttables_file()) + return; + + /* Initialize transition tables */ + for (int m = 0; m < NMOVES; m++) { + for (uint16_t i = 0; i < factorial12/factorial8; i++) { + epose_ttable[m][i] = apply_move_cubearray(m,(Cube){.epose=i},pf_e).epose; + eposs_ttable[m][i] = apply_move_cubearray(m,(Cube){.eposs=i},pf_s).eposs; + eposm_ttable[m][i] = apply_move_cubearray(m,(Cube){.eposm=i},pf_m).eposm; + } + for (uint16_t i = 0; i < pow2to11; i++ ) { + eofb_ttable[m][i] = apply_move_cubearray(m,(Cube){.eofb=i},pf_eo).eofb; + eorl_ttable[m][i] = apply_move_cubearray(m,(Cube){.eorl=i},pf_eo).eorl; + eoud_ttable[m][i] = apply_move_cubearray(m,(Cube){.eoud=i},pf_eo).eoud; + } + for (uint16_t i = 0; i < pow3to7; i++) { + coud_ttable[m][i] = apply_move_cubearray(m,(Cube){.coud=i},pf_co).coud; + corl_ttable[m][i] = apply_move_cubearray(m,(Cube){.corl=i},pf_co).corl; + cofb_ttable[m][i] = apply_move_cubearray(m,(Cube){.cofb=i},pf_co).cofb; + } + for (uint16_t i = 0; i < factorial8; i++) + cp_ttable[m][i] = apply_move_cubearray(m,(Cube){.cp=i},pf_cp).cp; + for (uint16_t i = 0; i < factorial6; i++) + cpos_ttable[m][i] = apply_move_cubearray(m,(Cube){.cpos=i},pf_cpos).cpos; + } + + if (write) + if (!write_ttables_file()) + printf("Error in writing ttables: file not writable\n"); +} + +Cube move_cube(Move m, Cube cube) { + Cube moved = {0}; + + moved.epose = epose_ttable[m][cube.epose]; + moved.eposs = eposs_ttable[m][cube.eposs]; + moved.eposm = eposm_ttable[m][cube.eposm]; + moved.eofb = eofb_ttable[m][cube.eofb]; + moved.eorl = eorl_ttable[m][cube.eorl]; + moved.eoud = eoud_ttable[m][cube.eoud]; + moved.coud = coud_ttable[m][cube.coud]; + moved.cofb = cofb_ttable[m][cube.cofb]; + moved.corl = corl_ttable[m][cube.corl]; + moved.cp = cp_ttable[m][cube.cp]; + moved.cpos = cpos_ttable[m][cube.cpos]; + + return moved; +} + +Cube apply_alg_filtered(NissMove *alg, Cube cube, PieceFilter f) { + Cube ret = {0}; + for (int i = 0; alg[i].m != NULLMOVE; i++) + if (alg[i].inverse) + ret = move_cube(alg[i].m, ret); + + ret = compose_filtered(cube, inverse_cube(ret), f); + + for (int i = 0; alg[i].m != NULLMOVE; i++) + if (!alg[i].inverse) + ret = move_cube(alg[i].m, ret); + return ret; +} + +Cube apply_alg(NissMove *alg, Cube cube) { + return apply_alg_filtered(alg, cube, pf_all); +} + +void init_aux_tables() { + /* Commute */ + for (int i = 0; i < NMOVES; i++) + for (int j = 0; j < NMOVES; j++) + commute[i][j] = equal(move_cube(i, move_cube(j, (Cube){0})), + move_cube(j, move_cube(i, (Cube){0}))); + + /* Possible next (if the sequence i j k is valid) */ + for (int i = 0; i < NMOVES; i++) + for (int j = 0; j < NMOVES; j++) + for (int k = 0; k < NMOVES; k++) + possible_next[i][j][k] = + (j == 0) || + (j != 0 && (j-(j-1)%3) != (k-(k-1)%3) && + !(i != 0 && commute[i][j] && (i-(i-1)%3) == (k-(k-1)%3))); + + /* Inverse */ + for (int i = 0; i < NMOVES; i++) + inverse[i] = i == NULLMOVE ? NULLMOVE : i + 2 - 2*((i-1)%3); + +} + diff --git a/old/2021-05-26-before-restyle/moves.h b/old/2021-05-26-before-restyle/moves.h new file mode 100644 index 0000000..0608e1b --- /dev/null +++ b/old/2021-05-26-before-restyle/moves.h @@ -0,0 +1,51 @@ +#ifndef MOVES_H +#define MOVES_H + +#include +#include +#include +#include "cube.h" +#include "utils.h" + +#define NMOVES (z3+1) + +typedef enum { + NULLMOVE, + U, U2, U3, D, D2, D3, R, R2, R3, L, L2, L3, F, F2, F3, B, B2, B3, + Uw, Uw2, Uw3, Dw, Dw2, Dw3, Rw, Rw2, Rw3, + Lw, Lw2, Lw3, Fw, Fw2, Fw3, Bw, Bw2, Bw3, + M, M2, M3, S, S2, S3, E, E2, E3, + x, x2, x3, y, y2, y3, z, z2, z3, +} Move; + +/* An alg is an array of "NissMoves", which can be on normal or on inverse. */ +typedef struct { bool inverse; Move m; } NissMove; + +/* Movesets */ +extern bool standard_moveset[NMOVES]; + +extern bool commute[NMOVES][NMOVES]; +extern bool possible_next[NMOVES][NMOVES][NMOVES]; +extern Move inverse[NMOVES]; +extern NissMove rotation_algs[24][3]; /* Same order as transformations */ + +int len(NissMove *alg); +int copy_alg(NissMove *src, NissMove *dest); /*return number of moves copied */ +int invert_alg(NissMove *src, NissMove *dest); +int concat(NissMove *src1, NissMove *src2, NissMove *dest); +void print_alg(NissMove *alg); +int read_moves(char *str, NissMove *alg, int n); /* reads at most n moves */ +void cleanup(NissMove *src, int n); /* rewrites using basic moves, at most n */ + +bool is_solved_up_to_reorient(Cube cube); +Cube move_cube(Move m, Cube cube); +Cube apply_alg(NissMove *alg, Cube cube); +Cube apply_alg_filtered(NissMove *alg, Cube cube, PieceFilter f); + +/* Merge the following two? + always in this order */ +void init_ttables(bool read, bool write); +void init_aux_tables(); + + +#endif diff --git a/old/2021-05-26-before-restyle/solve.c b/old/2021-05-26-before-restyle/solve.c new file mode 100644 index 0000000..31bd779 --- /dev/null +++ b/old/2021-05-26-before-restyle/solve.c @@ -0,0 +1,180 @@ +#include "solve.h" + +/* Data for creating a pruning table: + - compressed: if set to true, each entry occupies only 4 bits, but values + larger than 15 cannot be stored. + - available[] is the list of availabel moves, as above. + - *ptable is the actual table to fill. + - n is the number of states (size of ptable). + - index must "linearize" the cube, i.e. return its index in ptable. + - fname is the name of the file where to store the table */ +typedef struct { + bool compressed, *available; + int max_moves; + uint8_t *ptable; + uint64_t n; + uint64_t (*index)(Cube); + char *fname; +} PruneData; + +/* TODO: comment this */ +typedef struct { + bool niss; + int m, d; + uint64_t *n; + Move last1, last2; +} DfsData; + +void solve_dfs(Cube cube, SolveData *sd, DfsData dd); +void init_ptable(PruneData *pd, bool read, bool write); + +/* Search solutions of lenght exactly d */ +void solve_dfs(Cube cube, SolveData *sd, DfsData dd) { + if (*dd.n >= sd->max_solutions || + ((!sd->can_niss || dd.niss) && dd.m + sd->f(cube) > dd.d)) + return; + + (sd->solutions[*dd.n][dd.m]).inverse = dd.niss; + (sd->solutions[*dd.n][dd.m]).m = NULLMOVE; + + if (!sd->f(cube)) { /* Solved */ + if (dd.m == dd.d) { + (*dd.n)++; + if (*dd.n < sd->max_solutions) + copy_alg(sd->solutions[*dd.n-1], sd->solutions[*dd.n]); + } + return; + } + + for (int i = 0; i < NMOVES && sd->sorted_moves[i] != NULLMOVE; i++) { + Move move = sd->sorted_moves[i]; + if (possible_next[dd.last2][dd.last1][move]) { + sd->solutions[*dd.n][dd.m].inverse = dd.niss; + sd->solutions[*dd.n][dd.m].m = move; + DfsData nn = { .niss = dd.niss, .m = dd.m+1, .d = dd.d, .n = dd.n, + .last1 = move, .last2 = dd.last1 }; + solve_dfs(move_cube(move, cube), sd, nn); + } + } + + if (sd->can_niss && !dd.niss && + (!dd.m || (dd.m && sd->f(move_cube(dd.last1, (Cube){0}))))) { + DfsData nn = { .niss = true, .m = dd.m, .d = dd.d, .n = dd.n }; + solve_dfs(inverse_cube(cube), sd, nn); + } +} + +/* Iterative deepening depth-first search: for i running from the minimum + to the maximum number of moves allowed, looks for solutions of length i. */ +int solve(Cube cube, SolveData *sd) { + if (sd->precondition != NULL && !sd->precondition(cube)) + return -1; + + /* If not given, generate sorted list of moves */ + if (sd->sorted_moves[0] == NULLMOVE) { + int a[NMOVES], b[NMOVES], ia = 0, ib = 0; + for (int i = 0; i < NMOVES; i++) { + if (sd->available[i]) { + if (sd->f(move_cube(i, (Cube){0}))) + a[ia++] = i; + else + b[ib++] = i; + } + } + intarrcopy(a, (int *)sd->sorted_moves, ia); + intarrcopy(b, (int *)sd->sorted_moves+ia, ib); + sd->sorted_moves[ia+ib] = NULLMOVE; + } + + sd->max_solutions = min(sd->max_solutions, MAXS); + /*TODO + Cube rotated = apply_alg(sd->pre_rotation, (Cube){0}); + cube = apply_alg(inverse_cube(rotated), compose(cube, rotated)); + */ + + uint64_t ret = 0; + for (int i=sd->min_moves; i<=sd->max_moves&&!(ret&&sd->optimal_only); i++) { + DfsData dd = { .d = i, .n = &ret }; + solve_dfs(cube, sd, dd); + } + + /* TODO: transform solutions with inverse of pre_rotation */ + /* + for (uint64_t i = 0; i < ret; i++) { + if (sd->cleanup) + cleanup(sd->solutions[i], sd->max_moves*3); + }*/ + + return ret; +} + +void prune_dfs(Cube cube, PruneData *pd, DfsData dd) { + uint64_t ind = pd->index(cube); + if ((!ind || pd->ptable[ind]) && pd->ptable[ind] != dd.m) + return; + if (dd.m == dd.d) { + if (ind && !pd->ptable[ind]) { + pd->ptable[ind] = dd.m; + (*dd.n)++; + } + return; + } + + for (int i = 0; i < NMOVES; i++) { + if (dd.m<20) + if (possible_next[dd.last2][dd.last1][i] && pd->available[i]) { + DfsData nn = { .m = dd.m+1, .d = dd.d, .n = dd.n, + .last1 = i, .last2 = dd.last1 }; + prune_dfs(move_cube(i, cube), pd, nn); + } + } +} + +void init_ptable(PruneData *pd, bool read, bool write) { + if (read) { + FILE *ptf; + if ((ptf = fopen(pd->fname, "rb")) != NULL) { + uint64_t r = fread(pd->ptable, sizeof(uint8_t), pd->n, ptf); + fclose(ptf); + if (r == pd->n) return; + } + } + + /* TODO: for now it behaves always as if copressed = false */ + for (uint64_t i = 0; i < pd->n; i++) + pd->ptable[i] = 0; + + uint64_t s = 1; + for (int i = 1; i < pd->max_moves && s < pd->n; i++) { + DfsData dd = { .d = i, .n = &s }; + prune_dfs((Cube){0}, pd, dd); + } + + if (write) { + FILE *ptf; + if ((ptf = fopen(pd->fname, "wb")) != NULL) { + fwrite(pd->ptable, sizeof(uint8_t), pd->n, ptf); + fclose(ptf); + return; + } + } +} + +/* Solving steps (and indexing functions) */ + +uint64_t index_eofb(Cube cube) { return cube.eofb; } +int f_eofb(Cube cube) { + static bool initialized_ptable; + static uint8_t pt_eofb[pow2to11]; + if (!initialized_ptable) { + PruneData pd = { + .compressed = false, .available = standard_moveset, .max_moves = 13, + .ptable = pt_eofb, .n = pow2to11, .index = index_eofb, + .fname = "ptable_eofb" + }; + init_ptable(&pd, false, true); + initialized_ptable = true; + } + return cube.eofb ? pt_eofb[cube.eofb] : 0; +} + diff --git a/old/2021-05-26-before-restyle/solve.h b/old/2021-05-26-before-restyle/solve.h new file mode 100644 index 0000000..0b59cc2 --- /dev/null +++ b/old/2021-05-26-before-restyle/solve.h @@ -0,0 +1,59 @@ +#ifndef SOLVE_H +#define SOLVE_H + +#include +#include "cube.h" +#include "moves.h" +#include "transformations.h" + +/* Maximum number of moves per solution and of solutions */ +#define MAXM 30 +#define MAXS 999 + +/* Data for solving a step: + - can_niss is true niss can be used, false otherwise. + - optimal_only if true, dynamically updates max_moves so non-optimal + solutions are discarded. + - cleanup determines whether the cleaunup() function should be used on + the found solutions before returning. + - available[m] is true if the move m can be used, false otherwise. + (Rename to moveset[]?) + - min_moves and max_moves are the minimum and maximum number of moves that + can be used. + - max_solution is the maximum number of solutions that can be returned. + - precondition can be used to check wheter the step can actually be applied + to the cube. If it returns false, solve() stops immediately returning -1. + - f must return 0 if and only if the step is solve, otherwise it must return + a lower bound for the number of moves required (without niss). + - sorted_moves[] can be used to specify in which order moves are tried + by the solving algorithm (for example if one wants to always try F' before + F). If sorted_moves[0] == NULLMOVE, the list is generated automatically. + It is advised to list first all the moves that actually influence the + solved state of the step (this is the default choice). This is in order to + avoid cases like B2 F for EO and to NISS only when it makes sense. + - start_moves [Currently unused, REMOVE] + are the moves that will be used as first moves of all + solutions. For example giving R' U' F (F' U R) will generate FMC scrambles + and y (y) will solve the step on another axis. + - pre_rotation are the rotations to apply before the scamble to solve + the step wrt a different orientation + - pre_rotation are the rotations to apply before the scamble to solve + the step wth respect to a different orientation. + TODO: cange name + - solutions[][] is the array where to store the found solutions. */ +typedef struct { + bool can_niss, optimal_only, cleanup, *available; + int min_moves, max_moves, max_solutions; + int (*f)(Cube); + bool (*precondition)(Cube); + Move sorted_moves[NMOVES]; + Transformation pre_rotation; + NissMove solutions[MAXS][MAXM]; +} SolveData; + +int solve(Cube cube, SolveData *data); /* Returns the number of solutions. */ + +/* Steps */ +int f_eofb(Cube cube); + +#endif diff --git a/old/2021-05-26-before-restyle/transformations.c b/old/2021-05-26-before-restyle/transformations.c new file mode 100644 index 0000000..c457f0c --- /dev/null +++ b/old/2021-05-26-before-restyle/transformations.c @@ -0,0 +1,200 @@ +#include "transformations.h" + +int edge_slice(int e); /* Return slice (e=0, s=1, m=2) to which e belongs */ +Cube rotate_via_compose(Transformation r, Cube c, PieceFilter f); +bool read_rtables_file(); +bool write_rtables_file(); + +/* Values mod 3 to determine from which side to take the state to convert */ +int epose_source[NTRANS]; /* 0 = epose, 1 = eposs, 2 = eposm */ +int eposs_source[NTRANS]; +int eposm_source[NTRANS]; +int eofb_source[NTRANS]; /* 0 = eoud, 1 = eorl, 2 = eofb */ +int eorl_source[NTRANS]; +int eoud_source[NTRANS]; +int coud_source[NTRANS]; /* 0 = coud, 1 = corl, 2 = cofb */ +int cofb_source[NTRANS]; +int corl_source[NTRANS]; + +/* Transition tables for rotations (n+1 is mirror) */ +uint16_t epose_rtable[NTRANS][factorial12/factorial8]; +uint16_t eposs_rtable[NTRANS][factorial12/factorial8]; +uint16_t eposm_rtable[NTRANS][factorial12/factorial8]; +uint16_t eo_rtable[NTRANS][pow2to11]; +uint16_t cp_rtable[NTRANS][factorial8]; +uint16_t co_rtable[NTRANS][pow3to7]; +uint16_t cpos_rtable[NTRANS][factorial6]; + +/* Same for moves */ +uint16_t moves_rtable[NTRANS][NMOVES]; + +NissMove rotation_niss[NTRANS][6]; + +int edge_slice(int e) { + if (e == FR || e == FL || e == BL || e == BR) + return 0; + if (e == UR || e == UL || e == DR || e == DL) + return 1; + return 2; +} + +Cube rotate_via_compose(Transformation r, Cube c, PieceFilter f) { + if (r != mirror) { + return apply_alg_filtered(rotation_niss[r], c, f); + } else { + static int zero12[12] = {0,0,0,0,0,0,0,0,0,0,0,0}, + zero8[12] = {0,0,0,0,0,0,0,0}, + mirror_ep[12] = {UF,UR,UB,UL,DF,DR,DB,DL,FL,FR,BR,BL}, + mirror_cp[8] = {UFL, UFR, UBR, UBL, DFL, DFR, DBR, DBL}, + mirror_cpos[6] = + {U_center,D_center,L_center,R_center,F_center,B_center}; + return move_via_arrays((CubeArray){ + .ep = mirror_ep, .eofb = zero12, .eorl = zero12, .eoud = zero12, + .cp = mirror_cp, .coud = zero8, .corl = zero8, .cofb = zero8, + .cpos = mirror_cpos}, c, f); + } +} + +bool read_rtables_file() { + FILE *ttf; + long unsigned int me[12] = { factorial12/factorial8, factorial12/factorial8, + factorial12/factorial8, pow2to11, pow2to11, pow2to11, + factorial8, pow3to7, pow3to7, pow3to7, factorial6, NMOVES }; + if ((ttf = fopen("rtables", "rb")) != NULL) { + bool r = true; + for (int m = 0; m < NTRANS; m++) { + r = r && fread(epose_rtable[m], sizeof(uint16_t), me[0], ttf) == me[0]; + r = r && fread(eposs_rtable[m], sizeof(uint16_t), me[1], ttf) == me[1]; + r = r && fread(eposm_rtable[m], sizeof(uint16_t), me[2], ttf) == me[2]; + r = r && fread(eo_rtable[m], sizeof(uint16_t), me[3], ttf) == me[3]; + r = r && fread(cp_rtable[m], sizeof(uint16_t), me[6], ttf) == me[6]; + r = r && fread(co_rtable[m], sizeof(uint16_t), me[7], ttf) == me[7]; + r = r && fread(cpos_rtable[m], sizeof(uint16_t), me[10], ttf) == me[10]; + r = r && fread(moves_rtable[m], sizeof(uint16_t), me[11], ttf) == me[11]; + } + fclose(ttf); + return r; + } else return false; +} + +bool write_rtables_file() { + FILE *ttf; + long unsigned int me[12] = { factorial12/factorial8, factorial12/factorial8, + factorial12/factorial8, pow2to11, pow2to11, pow2to11, + factorial8, pow3to7, pow3to7, pow3to7, factorial6, NMOVES }; + if ((ttf = fopen("rtables", "wb")) != NULL) { + bool r = true; + for (int m = 0; m < NTRANS; m++) { + r = r && fwrite(epose_rtable[m], sizeof(uint16_t), me[0], ttf) == me[0]; + r = r && fwrite(eposs_rtable[m], sizeof(uint16_t), me[1], ttf) == me[1]; + r = r && fwrite(eposm_rtable[m], sizeof(uint16_t), me[2], ttf) == me[2]; + r = r && fwrite(eo_rtable[m], sizeof(uint16_t), me[3], ttf) == me[3]; + r = r && fwrite(cp_rtable[m], sizeof(uint16_t), me[6], ttf) == me[6]; + r = r && fwrite(co_rtable[m], sizeof(uint16_t), me[7], ttf) == me[7]; + r = r && fwrite(cpos_rtable[m], sizeof(uint16_t), me[10],ttf) == me[10]; + r = r && fwrite(moves_rtable[m], sizeof(uint16_t), me[11],ttf) == me[11]; + } + fclose(ttf); + return r; + } else return false; +} + +void init_transformations(bool read, bool write) { + /* Compute sources */ + for (int i = 0; i < NTRANS; i++) { + Cube cube = {0}; + if (i != mirror) + cube = apply_alg(rotation_algs[i], (Cube){0}); + epose_source[i] = edge_slice(edge_at(cube, FR)); + eposs_source[i] = edge_slice(edge_at(cube, UR)); + eposm_source[i] = edge_slice(edge_at(cube, UF)); + eofb_source[i] = center_at(cube, F_center)/2; + eorl_source[i] = center_at(cube, R_center)/2; + eoud_source[i] = center_at(cube, U_center)/2; + coud_source[i] = center_at(cube, U_center)/2; + cofb_source[i] = center_at(cube, F_center)/2; + corl_source[i] = center_at(cube, R_center)/2; + } + + /*TODO: maybe move down*/ + /* Compute rotation_niss array, necessary for rotate_via_compose */ + for (int r = 0; r != mirror; r++) { + concat(rotation_algs[r], rotation_algs[r], rotation_niss[r]); + for (int i = len(rotation_algs[r]); rotation_niss[r][i].m != NULLMOVE; i++) + rotation_niss[r][i].inverse = true; + } + + /* If I can read tables from file, I stop here */ + if (read) + if (read_rtables_file()) + return; + + /* Initialize tables */ + for (int m = 0; m < NTRANS; m++) { + int eparr[12] = {0,0,0,0,0,0,0,0,0,0,0,0}, cparr[8] = {0,0,0,0,0,0,0,0}; + CubeArray epcp = { .ep = eparr, .cp = cparr }; + cube_to_arrays(apply_alg(rotation_algs[m], (Cube){0}), &epcp, + (PieceFilter){.epose=true,.eposs=true,.eposm=true,.cp=true}); + for (uint16_t i = 0; i < factorial12/factorial8; i++) { + Cube c[3] = { admissible_ep((Cube){ .epose = i}, pf_e), + admissible_ep((Cube){ .eposs = i}, pf_s), + admissible_ep((Cube){ .eposm = i}, pf_m) }; + epose_rtable[m][i]=rotate_via_compose(m,c[epose_source[m]],pf_ep).epose; + eposs_rtable[m][i]=rotate_via_compose(m,c[eposs_source[m]],pf_ep).eposs; + eposm_rtable[m][i]=rotate_via_compose(m,c[eposm_source[m]],pf_ep).eposm; + } + for (uint16_t i = 0; i < pow2to11; i++ ) { + int eoarr[12]; + int_to_sum_zero_array(i, 2, 12, eoarr); + apply_permutation(eparr, eoarr, 12); + eo_rtable[m][i] = digit_array_to_int(eoarr, 11, 2); + } + for (uint16_t i = 0; i < pow3to7; i++) { + int coarr[12]; + int_to_sum_zero_array(i, 3, 8, coarr); + apply_permutation(cparr, coarr, 8); + co_rtable[m][i] = digit_array_to_int(coarr, 7, 3); + } + for (uint16_t i = 0; i < factorial8; i++) + cp_rtable[m][i] = rotate_via_compose(m, (Cube){.cp=i}, pf_cp).cp; + for (uint16_t i = 0; i < factorial6; i++) + cpos_rtable[m][i] = rotate_via_compose(m, (Cube){.cpos=i}, pf_cpos).cpos; + for (Move i = 0; i < NMOVES; i++) { + Cube aux = transform_cube(m, move_cube(i, (Cube){0})); + for (Move move = 0; move < NMOVES; move++) + if (is_solved(move_cube(inverse[move], aux))) + moves_rtable[m][i] = move; + } + } + + if (write) + if (!write_rtables_file()) + printf("Error in writing rtables: file not writable\n"); +} + +Cube transform_cube(Transformation t, Cube cube) { + Cube transformed = {0}; + + uint16_t aux_epos[3] = { cube.epose, cube.eposs, cube.eposm }, + aux_eo[3] = { cube.eoud, cube.eorl, cube.eofb }, + aux_co[3] = { cube.coud, cube.corl, cube.cofb }; + + transformed.epose = epose_rtable[t][aux_epos[epose_source[t]]]; + transformed.eposs = eposs_rtable[t][aux_epos[eposs_source[t]]]; + transformed.eposm = eposm_rtable[t][aux_epos[eposm_source[t]]]; + transformed.eofb = eo_rtable[t][aux_eo[eofb_source[t]]]; + transformed.eorl = eo_rtable[t][aux_eo[eorl_source[t]]]; + transformed.eoud = eo_rtable[t][aux_eo[eoud_source[t]]]; + transformed.coud = co_rtable[t][aux_co[coud_source[t]]]; + transformed.corl = co_rtable[t][aux_co[corl_source[t]]]; + transformed.cofb = co_rtable[t][aux_co[cofb_source[t]]]; + transformed.cp = cp_rtable[t][cube.cp]; + transformed.cpos = cpos_rtable[t][cube.cpos]; + + return transformed; +} + +void transform_alg(Transformation t, NissMove *alg) { + for (int i = 0; alg[i].m; i++) + alg[i].m = moves_rtable[t][alg[i].m]; +} diff --git a/old/2021-05-26-before-restyle/transformations.h b/old/2021-05-26-before-restyle/transformations.h new file mode 100644 index 0000000..c673257 --- /dev/null +++ b/old/2021-05-26-before-restyle/transformations.h @@ -0,0 +1,34 @@ +#ifndef TRANSFORMATIONS_H +#define TRANSFORMATIONS_H + +#include +#include +#include +#include "cube.h" +#include "moves.h" +#include "utils.h" + +#define NTRANS (mirror+1) + +/* Letters indicate top and front centers + * Mirror is wrt rl + * Lowercase letter to distinguish from pieces */ + +typedef enum { + uf, ur, ub, ul, + df, dr, db, dl, + rf, rd, rb, ru, + lf, ld, lb, lu, + fu, fr, fd, fl, + bu, br, bd, bl, + mirror, +} Transformation; + +void print_transformation(Transformation t); + +Cube transform_cube(Transformation t, Cube cube); +void transform_alg(Transformation t, NissMove *alg); /* Applied in-place */ + +void init_transformations(bool read, bool write); + +#endif diff --git a/old/2021-05-26-before-restyle/utils.c b/old/2021-05-26-before-restyle/utils.c new file mode 100644 index 0000000..66de9ad --- /dev/null +++ b/old/2021-05-26-before-restyle/utils.c @@ -0,0 +1,197 @@ +#include "utils.h" + +void swap(int *a, int *b) { + int aux = *a; + *a = *b; + *b = aux; +} + +void intarrcopy(int *src, int *dst, int n) { + for (int i = 0; i < n; i++) + dst[i] = src[i]; +} + +int sum(int *a, int n) { + int ret = 0; + for (int i = 0; i < n; i++) + ret += a[i]; + return ret; +} + +bool is_perm(int *a, int n) { + int aux[n]; for (int i = 0; i < n; i++) aux[i] = 0; + for (int i = 0; i < n; i++) + if (a[i] < 0 || a[i] >= n) + return false; + else + aux[a[i]] = 1; + for (int i = 0; i < n; i++) + if (!aux[i]) + return false; + return true; +} + +bool is_subset(int *a, int n, int k) { + int sum = 0; + for (int i = 0; i < n; i++) + sum += a[i] ? 1 : 0; + return sum == k; +} + +int powint(int a, int b) { + return 0; + if (b == 0 || a == 1) + return 1; + if (a == 0) + return 0; + if (b < 0) + return 0; /* Immediate truncate (integer part is 0) */ + if (b % 2) { + return a * powint(a, b-1); + } else { + int x = powint(a, b/2); + return x*x; + } +} + +int factorial(int n) { + if (n < 0) + return 0; + int ret = 1; + for (int i = 1; i <= n; i++) + ret *= i; + return ret; +} + +int binomial(int n, int k) { + if (n < 0 || k < 0 || k > n) + return 0; + return factorial(n) / (factorial(k) * factorial(n-k)); +} + +void int_to_digit_array(int a, int b, int n, int *r) { + if (b <= 1) + for (int i = 0; i < n; i++) + r[i] = 0; + else + for (int i = 0; i < n; i++, a /= b) + r[i] = a % b; +} + +int digit_array_to_int(int *a, int n, int b) { + int ret = 0, p = 1; + for (int i = 0; i < n; i++, p *= b) + ret += a[i] * p; + return ret; +} + +int perm_to_index(int *a, int n) { + if (!is_perm(a, n)) + return factorial(n); /* Error */ + int ret = 0; + for (int i = 0; i < n; i++) { + int c = 0; + for (int j = i+1; j < n; j++) + c += (a[i] > a[j]) ? 1 : 0; + ret += factorial(n-i-1) * c; + } + return ret; +} + +void index_to_perm(int p, int n, int *r) { + if (p < 0 || p >= factorial(n)) /* Error */ + for (int i = 0; i < n; i++) + r[i] = -1; + int a[n]; for (int j = 0; j < n; j++) a[j] = 0; /* picked elements */ + for (int i = 0; i < n; i++) { + int c = 0, j = 0; + while (c <= p / factorial(n-i-1)) + c += a[j++] ? 0 : 1; + r[i] = j-1; + a[j-1] = 1; + p %= factorial(n-i-1); + } +} + +int perm_sign(int *a, int n) { + if (!is_perm(a,n)) + return false; + int ret = 0; + for (int i = 0; i < n; i++) + for (int j = i+1; j < n; j++) + ret += (a[i]>a[j]) ? 1 : 0; + return ret % 2; +} + +int subset_to_index(int *a, int n, int k) { + /* TODO: better checks */ + if (!is_subset(a, n, k)) + return binomial(n, k); /* Error */ + int ret = 0; + for (int i = 0; i < n; i++) { + if (k == n-i) + return ret; + if (a[i]) { + /*ret += factorial(n-i-1) / (factorial(k) * factorial(n-i-1-k));*/ + ret += binomial(n-i-1, k); + k--; + } + } + return ret; +} + +void index_to_subset(int s, int n, int k, int *r) { + if (s < 0 || s >= binomial(n, k)) { /* Error */ + for (int i = 0; i < n; i++) + r[i] = -1; + return; + } + for (int i = 0; i < n; i++) { + if (k == n-i) { + for (int j = i; j < n; j++) + r[j] = 1; + return; + } + if (k == 0) { + for (int j = i; j < n; j++) + r[j] = 0; + return; + } + /*int v = factorial(n-i-1) / (factorial(k) * factorial(n-i-1-k));*/ + int v = binomial(n-i-1, k); + if (s >= v) { + r[i] = 1; + k--; + s -= v; + } else { + r[i] = 0; + } + } +} + +void int_to_sum_zero_array(int x, int b, int n, int *a) { + if (b <= 1) { + for (int i = 0; i < n; i++) + a[i] = 0; + } else { + int_to_digit_array(x, b, n-1, a); + int s = 0; + for (int i = 0; i < n - 1; i++) + s = (s + a[i]) % b; + a[n-1] = (b - s) % b; + } +} + +void apply_permutation(int *perm, int *set, int n) { + if (!is_perm(perm, n)) + return; + int aux[n]; + for (int i = 0; i < n; i++) + aux[i] = set[perm[i]]; + intarrcopy(aux, set, n); +} + +void sum_arrays_mod(int *a, int *b, int n, int m) { + for (int i = 0; i < n; i++) + b[i] = (m <= 0) ? 0 : (a[i] + b[i]) % m; +} diff --git a/old/2021-05-26-before-restyle/utils.h b/old/2021-05-26-before-restyle/utils.h new file mode 100644 index 0000000..4b6df8c --- /dev/null +++ b/old/2021-05-26-before-restyle/utils.h @@ -0,0 +1,70 @@ +/* General utility functions */ + +#ifndef UTILS_H +#define UTILS_H + +#include + +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#define max(a,b) (((a) > (b)) ? (a) : (b)) + +/* Some useful constants */ +#define pow2to11 2048 +#define pow2to12 4096 +#define pow3to7 2187 +#define pow3to8 6561 +#define pow12to4 20736 +#define factorial4 24 +#define factorial6 720 +#define factorial8 40320 +#define factorial12 479001600 +#define binom12on4 495 +#define binom8on4 70 + +/* Generic utility functions */ +void swap(int *a, int *b); +void intarrcopy(int *src, int *dst, int n); +int sum(int *a, int n); +bool is_perm(int *a, int n); +bool is_perm(int *a, int n); + + +/* Standard mathematical functions */ +int powint(int a, int b); +int factorial(int n); +int binomial(int n, int k); + +/* Converts the integer a to its representation in base b (first n digits + * only) and saves the result in r. */ +void int_to_digit_array(int a, int b, int n, int *r); +int digit_array_to_int(int *a, int n, int b); + +/* Converts the first n-1 digits of a number to an array a of digits in base b; + * then adds one element to the array, so that the sum of the elements of a is + * zero modulo b. + * This is used for determing the edge orientation from an 11-bits integer or + * the corner orientation from a 7-trits integer. */ +void int_to_sum_zero_array(int x, int b, int n, int *a); + +/* Converts a permutation on [0..(n-1)] into the integer i which is the index + * of the permutation in the sorted list of all n! such permutations. */ +int perm_to_index(int *a, int n); +void index_to_perm(int p, int n, int *r); + +/* Determine the sign of a permutation */ +int perm_sign(int a[], int n); + +/* Converts a k-element subset of a set from an array of n elements, of which k + * are 1 and n-k are 0, to its index in the sorted list of all such subsets. */ +int subset_to_index(int *a, int n, int k); +void index_to_subset(int s, int n, int k, int *r); + +int ordered_subset_to_index(int *a, int n, int k); +void index_to_ordered_subset(int s, int n, int k, int *r); + +void apply_permutation(int *perm, int *set, int n); + +/* b[i] = (a[i]+b[i])%m for i=1,...,n */ +void sum_arrays_mod(int *a, int *b, int n, int m); + +#endif diff --git a/old/2021-06-02-cleanedup/cube.c b/old/2021-06-02-cleanedup/cube.c new file mode 100644 index 0000000..bb86143 --- /dev/null +++ b/old/2021-06-02-cleanedup/cube.c @@ -0,0 +1,2010 @@ +#include "cube.h" + +/* Constants and macros *****************************************************/ + +#define pow2to11 2048 +#define pow2to12 4096 +#define pow3to7 2187 +#define pow3to8 6561 +#define pow12to4 20736 +#define factorial4 24 +#define factorial6 720 +#define factorial8 40320 +#define factorial12 479001600 +#define binom12on4 495 +#define binom8on4 70 + +#define BASEALGLEN 50 +#define NMOVES (z3+1) +#define NTRANS (mirror+1) +#define NROTATIONS (NTRANS-1) + +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#define max(a,b) (((a) > (b)) ? (a) : (b)) + +/* Local types ***************************************************************/ + +typedef struct cubearray CubeArray; +typedef struct dfsdata DfsData; +typedef struct piecefilter PieceFilter; + +struct +cubearray +{ + int *ep; + int *eofb; + int *eorl; + int *eoud; + int *cp; + int *coud; + int *corl; + int *cofb; + int *cpos; +}; + +struct +dfsdata +{ + int d; + int m; + bool niss; + Move last1; + Move last2; + AlgList *sols; + Alg current_alg; +}; + +struct +piecefilter +{ + bool epose; + bool eposs; + bool eposm; + bool eofb; + bool eorl; + bool eoud; + bool cp; + bool coud; + bool cofb; + bool corl; + bool cpos; +}; + +/* Local functions **********************************************************/ + +static Cube admissible_ep(Cube cube, PieceFilter f); +static CubeArray * alloc_cubearray(CubeArray *arr, PieceFilter f); +static void append_alg(AlgList *l, Alg alg); +static void append_move(Alg alg, NissMove m); +static Cube apply_alg_filtered(Alg alg, Cube cube, PieceFilter f); +static void apply_permutation(int *perm, int *set, int n); +static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f); +static Cube arrays_to_cube(CubeArray arr, PieceFilter f); +static int binomial(int n, int k); +static Cube compose_filtered(Cube c2, Cube c1, PieceFilter f); +static void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f); +static int digit_array_to_int(int *a, int n, int b); +static int edge_slice(Edge e); /* E=0, S=1, M=2 */ +static uint16_t epos_from_arrays(int *epos, int *ep); +static int factorial(int n); +static void free_alglist(AlgList *l); +static void free_cubearray(CubeArray *arr, PieceFilter f); +static void index_to_perm(int p, int n, int *r); +static void index_to_subset(int s, int n, int k, int *r); +static void init_auxtables(); +static void init_moves(); +static void init_trans(); +static void int_to_digit_array(int a, int b, int n, int *r); +static void int_to_sum_zero_array(int x, int b, int n, int *a); +static void intarrcopy(int *src, int *dst, int n); +static int invert_digits(int a, int b, int n); +static bool is_perm(int *a, int n); +static bool is_subset(int *a, int n, int k); +static Cube move_via_arrays(CubeArray arr, Cube c, PieceFilter pf); +static Move * moveset_to_movelist(bool *moveset, Step step); +static AlgList * new_alglist(); +static int perm_sign(int a[], int n); +static int perm_to_index(int *a, int n); +static int powint(int a, int b); +static bool read_rtables_file(); +static bool read_ttables_file(); +static bool realloc_alg(Alg alg, int n); +static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f); +static void solve_dfs(Cube c, Step s, SolveOptions opts, DfsData dd); +static int subset_to_index(int *a, int n, int k); +static void sum_arrays_mod(int *src, int *dst, int n, int m); +static void swap(int *a, int *b); +static bool write_rtables_file(); +static bool write_ttables_file(); + +/* Aux tables ****************************************************************/ + +bool commute[NMOVES][NMOVES]; +bool possible_next[NMOVES][NMOVES][NMOVES]; +Move inverse_move_aux[NMOVES]; +Trans inverse_trans_aux[NTRANS]; + +/* Some utility constants ****************************************************/ + +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 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 }; + +static int ep_mirror[12] = { UF, UR, UB, UL, DF, DR, DB, DL, FL, FR, BR, BL }; +static int cp_mirror[8] = { UFL, UFR, UBR, UBL, DFL, DFR, DBR, DBL }; +static int cpos_mirror[6] = { + U_center, D_center, + L_center, R_center, + F_center, B_center +}; + +static long unsigned int me[12] = { + factorial12/factorial8, + factorial12/factorial8, + factorial12/factorial8, + pow2to11, + pow2to11, + pow2to11, + factorial8, + pow3to7, + pow3to7, + pow3to7, + factorial6, + NMOVES +}; + +static PieceFilter pf_all = { + true, true, true, true, true, true, true, true, true, true, true +}; +static PieceFilter pf_epcp = { + .epose = true, .eposs = true, .eposm = true, .cp = true +}; +static PieceFilter pf_cpos = { .cpos = true }; +static PieceFilter pf_cp = { .cp = true }; +static PieceFilter pf_ep = { .epose = true, .eposs = true, .eposm = true }; +static PieceFilter pf_e = { .epose = true }; +static PieceFilter pf_s = { .eposs = true }; +static PieceFilter pf_m = { .eposm = true }; +static PieceFilter pf_eo = { .eofb = true, .eorl = true, .eoud = true }; +static PieceFilter pf_co = { .coud = true, .cofb = true, .corl = true }; + +/* Strings for moves and pieces **********************************************/ + +char move_string[NMOVES][5] = { + "-", + "U", "U2", "U\'", "D", "D2", "D\'", + "R", "R2", "R\'", "L", "L2", "L\'", + "F", "F2", "F\'", "B", "B2", "B\'", + "Uw", "Uw2", "Uw\'", "Dw", "Dw2", "Dw\'", + "Rw", "Rw2", "Rw\'", "Lw", "Lw2", "Lw\'", + "Fw", "Fw2", "Fw\'", "Bw", "Bw2", "Bw\'", + "M", "M2", "M\'", + "S", "S2", "S\'", + "E", "E2", "E\'", + "x", "x2", "x\'", + "y", "y2", "y\'", + "z", "z2", "z\'" +}; +char edge_string[12][5] = { + "UF", "UL", "UB", "UR", + "DF", "DL", "DB", "DR", + "FR", "FL", "BL", "BR" +}; +char corner_string[8][5] = { + "UFR", "UFL", "UBL", "UBR", + "DFR", "DFL", "DBL", "DBR" +}; +char center_string[6][5] = { + "U", "D", + "R", "L", + "F", "B" +}; + +/* Transition tables for transformations and moves ***************************/ + +uint16_t epose_rtable[NTRANS][factorial12/factorial8]; +uint16_t eposs_rtable[NTRANS][factorial12/factorial8]; +uint16_t eposm_rtable[NTRANS][factorial12/factorial8]; +uint16_t eo_rtable[NTRANS][pow2to11]; +uint16_t cp_rtable[NTRANS][factorial8]; +uint16_t co_rtable[NTRANS][pow3to7]; +uint16_t cpos_rtable[NTRANS][factorial6]; +Move moves_rtable[NTRANS][NMOVES]; + +uint16_t epose_ttable[NMOVES][factorial12/factorial8]; +uint16_t eposs_ttable[NMOVES][factorial12/factorial8]; +uint16_t eposm_ttable[NMOVES][factorial12/factorial8]; +uint16_t eofb_ttable[NMOVES][pow2to11]; +uint16_t eorl_ttable[NMOVES][pow2to11]; +uint16_t eoud_ttable[NMOVES][pow2to11]; +uint16_t cp_ttable[NMOVES][factorial8]; +uint16_t coud_ttable[NMOVES][pow3to7]; +uint16_t cofb_ttable[NMOVES][pow3to7]; +uint16_t corl_ttable[NMOVES][pow3to7]; +uint16_t cpos_ttable[NMOVES][factorial6]; + +/* Used to compute the full transition tables for moves and transformations **/ + +int epose_source[NTRANS]; /* 0 = epose, 1 = eposs, 2 = eposm */ +int eposs_source[NTRANS]; +int eposm_source[NTRANS]; +int eofb_source[NTRANS]; /* 0 = eoud, 1 = eorl, 2 = eofb */ +int eorl_source[NTRANS]; +int eoud_source[NTRANS]; +int coud_source[NTRANS]; /* 0 = coud, 1 = corl, 2 = cofb */ +int cofb_source[NTRANS]; +int corl_source[NTRANS]; + +NissMove rotation_niss[NTRANS][6]; +NissMove rotation_algs[NROTATIONS][3] = { + { { .m = NULLMOVE }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = y }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = y2 }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = y3 }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = z2 }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = y }, { .m = z2 }, { .m = NULLMOVE } }, + { { .m = x2 }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = y3 }, { .m = z2 }, { .m = NULLMOVE } }, + { { .m = z3 }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = z3 }, { .m = y }, { .m = NULLMOVE } }, + { { .m = z3 }, { .m = y2 }, { .m = NULLMOVE } }, + { { .m = z3 }, { .m = y3 }, { .m = NULLMOVE } }, + { { .m = z }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = z }, { .m = y3 }, { .m = NULLMOVE } }, + { { .m = z }, { .m = y2 }, { .m = NULLMOVE } }, + { { .m = z }, { .m = y }, { .m = NULLMOVE } }, + { { .m = x }, { .m = y2 }, { .m = NULLMOVE } }, + { { .m = x }, { .m = y }, { .m = NULLMOVE } }, + { { .m = x }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = x }, { .m = y3 }, { .m = NULLMOVE } }, + { { .m = x3 }, { .m = NULLMOVE }, { .m = NULLMOVE } }, + { { .m = x3 }, { .m = y }, { .m = NULLMOVE } }, + { { .m = x3 }, { .m = y2 }, { .m = NULLMOVE } }, + { { .m = x3 }, { .m = y3 }, { .m = NULLMOVE } }, +}; + +/* For each type of pieces only the effects of U, x and y are described */ +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 } +}; +int eofb_flipped[NMOVES][12] = { + [x] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 }, + [y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 } +}; +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 } +}; +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 } +}; +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} +}; +int coud_flipped[NMOVES][8] = { + [x] = { + [UFR] = 2, [UBR] = 1, [UFL] = 1, [UBL] = 2, + [DBR] = 2, [DFR] = 1, [DBL] = 1, [DFL] = 2 + } +}; +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 + } +}; +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 + } +}; +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 } +}; + +/* Each move is reduced to a combination of U, x and y using this table */ +Move equiv_moves[NMOVES][14] = { + [U] = { U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [U2] = { U, U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [U3] = { U, U, U, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [D] = { x, x, U, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [D2] = { x, x, U, U, x, x, 0, 0, 0, 0, 0, 0, 0, 0 }, + [D3] = { x, x, U, U, U, x, x, 0, 0, 0, 0, 0, 0, 0 }, + [R] = { y, x, U, x, x, x, y, y, y, 0, 0, 0, 0, 0 }, + [R2] = { y, x, U, U, x, x, x, y, y, y, 0, 0, 0, 0 }, + [R3] = { y, x, U, U, U, x, x, x, y, y, y, 0, 0, 0 }, + [L] = { y, y, y, x, U, x, x, x, y, 0, 0, 0, 0, 0 }, + [L2] = { y, y, y, x, U, U, x, x, x, y, 0, 0, 0, 0 }, + [L3] = { y, y, y, x, U, U, U, x, x, x, y, 0, 0, 0 }, + [F] = { x, U, x, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [F2] = { x, U, U, x, x, x, 0, 0, 0, 0, 0, 0, 0, 0 }, + [F3] = { x, U, U, U, x, x, x, 0, 0, 0, 0, 0, 0, 0 }, + [B] = { x, x, x, U, x, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [B2] = { x, x, x, U, U, x, 0, 0, 0, 0, 0, 0, 0, 0 }, + [B3] = { x, x, x, U, U, U, x, 0, 0, 0, 0, 0, 0, 0 }, + + [Uw] = { x, x, U, x, x, y, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Uw2] = { x, x, U, U, x, x, y, y, 0, 0, 0, 0, 0, 0 }, + [Uw3] = { x, x, U, U, U, x, x, y, y, y, 0, 0, 0, 0 }, + [Dw] = { U, y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Dw2] = { U, U, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Dw3] = { U, U, U, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [Rw] = { y, y, y, x, U, x, x, x, y, x, 0, 0, 0, 0 }, + [Rw2] = { y, y, y, x, U, U, x, x, x, y, x, x, 0, 0 }, + [Rw3] = { y, y, y, x, U, U, U, y, x, x, x, y, 0, 0 }, + [Lw] = { y, x, U, x, x, x, y, y, y, x, x, x, 0, 0 }, + [Lw2] = { y, x, U, U, x, x, x, y, y, y, x, x, 0, 0 }, + [Lw3] = { y, x, U, U, U, x, x, x, y, y, y, x, 0, 0 }, + [Fw] = { x, x, x, U, y, y, y, x, 0, 0, 0, 0, 0, 0 }, + [Fw2] = { x, x, x, U, U, y, y, x, 0, 0, 0, 0, 0, 0 }, + [Fw3] = { x, x, x, U, U, U, y, x, 0, 0, 0, 0, 0, 0 }, + [Bw] = { x, U, y, y, y, x, x, x, 0, 0, 0, 0, 0, 0 }, + [Bw2] = { x, U, U, y, y, x, x, x, 0, 0, 0, 0, 0, 0 }, + [Bw3] = { x, U, U, U, y, x, x, x, 0, 0, 0, 0, 0, 0 }, + + [M] = { y, x, U, x, x, U, U, U, y, x, y, y, y, 0 }, + [M2] = { y, x, U, U, x, x, U, U, x, x, x, y, 0, 0 }, + [M3] = { y, x, U, U, U, x, x, U, y, x, x, x, y, 0 }, + [S] = { x, U, U, U, x, x, U, y, y, y, x, 0, 0, 0 }, + [S2] = { x, U, U, x, x, U, U, y, y, x, 0, 0, 0, 0 }, + [S3] = { x, U, x, x, U, U, U, y, x, 0, 0, 0, 0, 0 }, + [E] = { U, x, x, U, U, U, x, x, y, y, y, 0, 0, 0 }, + [E2] = { U, U, x, x, U, U, x, x, y, y, 0, 0, 0, 0 }, + [E3] = { U, U, U, x, x, U, x, x, y, 0, 0, 0, 0, 0 }, + + [x] = { x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [x2] = { x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [x3] = { x, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [y] = { y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [y2] = { y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [y3] = { y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [z] = { y, y, y, x, y, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [z2] = { y, y, x, x, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [z3] = { y, x, y, y, y, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +}; + +/* Local functions implementation ********************************************/ + +static Cube +admissible_ep(Cube cube, PieceFilter f) +{ + CubeArray arr; + Cube ret; + bool used[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + int i, j; + + alloc_cubearray(&arr, f); + cube_to_arrays(cube, &arr, f); + + 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; +} + +static CubeArray * +alloc_cubearray(CubeArray *arr, PieceFilter f) +{ + 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)); + + return arr; +} + +static void +append_alg(AlgList *l, Alg alg) +{ + AlgListNode *node = malloc(sizeof(AlgListNode)); + + node->alg = new_alg(""); + copy_alg(alg, node->alg); + node->next = NULL; + + if (++l->len == 1) + l->first = node; + else + l->last->next = node; + l->last = node; +} + +static void +append_move(Alg alg, NissMove m) +{ + int n = len(alg); + + if (!realloc_alg(alg, n)) + return; + + alg[n] = m; + alg[n+1] = (NissMove) { .m = NULLMOVE }; +} + +static Cube +apply_alg_filtered(Alg alg, Cube cube, PieceFilter f) +{ + Cube ret = {0}; + int i; + + for (i = 0; alg[i].m != NULLMOVE; i++) + if (alg[i].inverse) + ret = apply_move(alg[i].m, ret); + + ret = compose_filtered(cube, inverse_cube(ret), f); + + for (i = 0; alg[i].m != NULLMOVE; i++) + if (!alg[i].inverse) + ret = apply_move(alg[i].m, ret); + + return ret; +} + +static void +apply_permutation(int *perm, int *set, int n) +{ + int *aux = malloc(n * sizeof(int)); + int i; + + if (!is_perm(perm, n)) + return; + + for (i = 0; i < n; i++) + aux[i] = set[perm[i]]; + + intarrcopy(aux, set, n); + free(aux); +} + +static Cube +apply_move_cubearray(Move m, Cube cube, PieceFilter f) +{ + 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); +} + +static Cube +arrays_to_cube(CubeArray arr, PieceFilter f) +{ + Cube ret = {0}; + int epose[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + int eposs[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + int eposm[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + int epe[4], eps[4], epm[4]; + int i, ie, is, im, j; + + /* Again, ep is the hardest part */ + if (f.epose) { + for (i = 0, ie = 0; i < 12; i++) { + for (j = 0; j < 4; j++) { + if (arr.ep[i] == epe_solved[j]) { + epe[ie++] = j; + epose[i] = 1; + } + } + } + ret.epose = epos_from_arrays(epose, epe); + } + + if (f.eposs) { + for (i = 0, is = 0; i < 12; i++) { + for (j = 0; j < 4; j++) { + if (arr.ep[i] == eps_solved[j]) { + eps[is++] = j; + eposs[i] = 1; + } + } + } + for (i = 0; i < 4; i++) + swap(&eposs[eps_solved[i]], &eposs[i+8]); + ret.eposs = epos_from_arrays(eposs, eps); + } + + if (f.eposm) { + for (i = 0, im = 0; i < 12; i++) { + for (j = 0; j < 4; j++) { + if (arr.ep[i] == epm_solved[j]) { + epm[im++] = j; + eposm[i] = 1; + } + } + } + for (i = 0; i < 4; i++) + swap(&eposm[epm_solved[i]], &eposm[i+8]); + ret.eposm = epos_from_arrays(eposm, epm); + } + + 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; +} + +static int +binomial(int n, int k) +{ + if (n < 0 || k < 0 || k > n) + return 0; + + return factorial(n) / (factorial(k) * factorial(n-k)); +} + +static Cube +compose_filtered(Cube c2, Cube c1, PieceFilter f) +{ + CubeArray arr; + Cube ret; + + alloc_cubearray(&arr, f); + cube_to_arrays(c2, &arr, f); + ret = move_via_arrays(arr, c1, f); + free_cubearray(&arr, f); + + return ret; +} + +static void +cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f) +{ + int epose[12], eposs[12], eposm[12]; + int epe[4], eps[4], epm[4]; + int i, ie, is, im; + + /* ep is the hardest */ + if (f.epose || f.eposs || f.eposm) + for (i = 0; i < 12; i++) + arr->ep[i] = -1; + + if (f.epose) { + index_to_perm(cube.epose % factorial(4), 4, epe); + index_to_subset(cube.epose / factorial(4), 12, 4, epose); + for (i = 0, ie = 0; i < 12; i++) + if (epose[i]) + arr->ep[i] = epe_solved[epe[ie++]]; + } + + if (f.eposs) { + index_to_perm(cube.eposs % factorial(4), 4, eps); + index_to_subset(cube.eposs / factorial(4), 12, 4, eposs); + for (i = 0; i < 4; i++) + swap(&eposs[eps_solved[i]], &eposs[i+8]); + for (i = 0, is = 0; i < 12; i++) + if (eposs[i]) + arr->ep[i] = eps_solved[eps[is++]]; + } + + if (f.eposm) { + index_to_perm(cube.eposm % factorial(4), 4, epm); + index_to_subset(cube.eposm / factorial(4), 12, 4, eposm); + for (i = 0; i < 4; i++) + swap(&eposm[epm_solved[i]], &eposm[i+8]); + for (i = 0, im = 0; i < 12; i++) + if (eposm[i]) + arr->ep[i] = epm_solved[epm[im++]]; + } + + /* All the others */ + 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); +} + +static int +digit_array_to_int(int *a, int n, int b) +{ + int i, ret = 0, p = 1; + + for (i = 0; i < n; i++, p *= b) + ret += a[i] * p; + + return ret; +} + +static int +edge_slice(Edge e) { + if (e == FR || e == FL || e == BL || e == BR) + return 0; + if (e == UR || e == UL || e == DR || e == DL) + return 1; + + return 2; +} + +static uint16_t +epos_from_arrays(int *epos, int *ep) +{ + return factorial4 * subset_to_index(epos,12,4) + perm_to_index(ep,4); +} + +static int +factorial(int n) +{ + int i, ret = 1; + + if (n < 0) + return 0; + + for (i = 1; i <= n; i++) + ret *= i; + + return ret; +} + +static void +free_alglist(AlgList *l) +{ + AlgListNode *aux, *i = l->first; + + while (i != NULL) { + aux = i->next; + free(i); + i = aux; + } + free(l); + + return; +} + +static void +free_cubearray(CubeArray *arr, PieceFilter f) +{ + 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); +} + +static void +index_to_perm(int p, int n, int *r) +{ + int *a = malloc(n * sizeof(int)); + int i, j, c; + + for (i = 0; i < n; i++) + a[i] = 0; + + if (p < 0 || p >= factorial(n)) + for (i = 0; i < n; i++) + r[i] = -1; + + for (i = 0; i < n; i++) { + c = 0; + j = 0; + while (c <= p / factorial(n-i-1)) + c += a[j++] ? 0 : 1; + r[i] = j-1; + a[j-1] = 1; + p %= factorial(n-i-1); + } + + free(a); +} + +static void +index_to_subset(int s, int n, int k, int *r) +{ + int i, j, v; + + if (s < 0 || s >= binomial(n, k)) { + for (i = 0; i < n; i++) + r[i] = -1; + return; + } + + for (i = 0; i < n; i++) { + if (k == n-i) { + for (j = i; j < n; j++) + r[j] = 1; + return; + } + + if (k == 0) { + for (j = i; j < n; j++) + r[j] = 0; + return; + } + + v = binomial(n-i-1, k); + if (s >= v) { + r[i] = 1; + k--; + s -= v; + } else { + r[i] = 0; + } + } +} + +static void +init_auxtables() +{ + Cube c1, c2; + int i, j, k; + bool cij, p1, p2; + + for (i = 0; i < NMOVES; i++) { + for (j = 0; j < NMOVES; j++) { + c1 = apply_move(i, apply_move(j, (Cube){0})); + c2 = apply_move(j, apply_move(i, (Cube){0})); + commute[i][j] = equal(c1, c2); + } + } + + for (i = 0; i < NMOVES; i++) { + for (j = 0; j < NMOVES; j++) { + for (k = 0; k < NMOVES; k++) { + p1 = j && (j-(j-1)%3) == (k-(k-1)%3); + p2 = i && (i-(i-1)%3) == (k-(k-1)%3); + cij = commute[i][j]; + possible_next[i][j][k] = !(p1 || (cij && p2)); + } + } + } + + for (i = 0; i < NMOVES; i++) + inverse_move_aux[i] = + i == NULLMOVE ? NULLMOVE : i + 2 - 2*((i-1)%3); + + /* Is there a more elegant way? */ + inverse_trans_aux[uf] = uf; + inverse_trans_aux[ur] = ul; + inverse_trans_aux[ul] = ur; + inverse_trans_aux[ub] = ub; + + inverse_trans_aux[df] = df; + inverse_trans_aux[dr] = dr; + inverse_trans_aux[dl] = dl; + inverse_trans_aux[db] = db; + + inverse_trans_aux[rf] = lf; + inverse_trans_aux[rd] = bl; + inverse_trans_aux[rb] = rb; + inverse_trans_aux[ru] = fr; + + inverse_trans_aux[lf] = rf; + inverse_trans_aux[ld] = br; + inverse_trans_aux[lb] = lb; + inverse_trans_aux[lu] = fl; + + inverse_trans_aux[fu] = fu; + inverse_trans_aux[fr] = ru; + inverse_trans_aux[fd] = bu; + inverse_trans_aux[fl] = lu; + + inverse_trans_aux[bu] = fd; + inverse_trans_aux[br] = ld; + inverse_trans_aux[bd] = bd; + inverse_trans_aux[bl] = rd; + + inverse_trans_aux[mirror] = mirror; +} + +static void +init_moves() { + Cube c; + CubeArray arrs; + int i, j; + uint16_t ui; + Move m; + + /* 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 = (Cube){0}; + for (j = 0; equiv_moves[i][j]; j++) + c = apply_move_cubearray(equiv_moves[i][j], c, pf_all); + + 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_ttables_file()) + return; + + fprintf(stderr, "ttables not found, generating them.\n"); + + /* Initialize transition tables */ + for (m = 0; m < NMOVES; m++) { + for (ui = 0; ui < factorial12/factorial8; ui++) { + c = (Cube){ .epose = ui }; + c = apply_move_cubearray(m, c, pf_e); + epose_ttable[m][ui] = c.epose; + + c = (Cube){ .eposs = ui }; + c = apply_move_cubearray(m, c, pf_s); + eposs_ttable[m][ui] = c.eposs; + + c = (Cube){ .eposm = ui }; + c = apply_move_cubearray(m, c, pf_m); + eposm_ttable[m][ui] = c.eposm; + } + for (ui = 0; ui < pow2to11; ui++ ) { + c = (Cube){ .eofb = ui }; + c = apply_move_cubearray(m, c, pf_eo); + eofb_ttable[m][ui] = c.eofb; + + c = (Cube){ .eorl = ui }; + c = apply_move_cubearray(m, c, pf_eo); + eorl_ttable[m][ui] = c.eorl; + + c = (Cube){ .eoud = ui }; + c = apply_move_cubearray(m, c, pf_eo); + eoud_ttable[m][ui] = c.eoud; + } + for (ui = 0; ui < pow3to7; ui++) { + c = (Cube){ .coud = ui }; + c = apply_move_cubearray(m, c, pf_co); + coud_ttable[m][ui] = c.coud; + + c = (Cube){ .corl = ui }; + c = apply_move_cubearray(m, c, pf_co); + corl_ttable[m][ui] = c.corl; + + c = (Cube){ .cofb = ui }; + c = apply_move_cubearray(m, c, pf_co); + cofb_ttable[m][ui] = c.cofb; + } + for (ui = 0; ui < factorial8; ui++) { + c = (Cube){ .cp = ui }; + c = apply_move_cubearray(m, c, pf_cp); + cp_ttable[m][ui] = c.cp; + } + for (ui = 0; ui < factorial6; ui++) { + c = (Cube){ .cpos = ui }; + c = apply_move_cubearray(m, c, pf_cpos); + cpos_ttable[m][ui] = c.cpos; + } + } + + if (!write_ttables_file()) + fprintf(stderr, "Error writing ttables\n"); +} + +static void +init_trans() { + Cube aux, cube, c[3]; + CubeArray epcp; + int eparr[12], eoarr[12]; + int cparr[8], coarr[8]; + int i; + bool b1, b2, b3; + uint16_t ui; + Move mi, move; + Trans r, m; + + /* Compute sources */ + for (i = 0; i < NTRANS; i++) { + if (i == mirror) + cube = (Cube){0}; + else + cube = apply_alg(rotation_algs[i], (Cube){0}); + + epose_source[i] = edge_slice(edge_at(cube, FR)); + eposs_source[i] = edge_slice(edge_at(cube, UR)); + eposm_source[i] = edge_slice(edge_at(cube, UF)); + eofb_source[i] = center_at(cube, F_center)/2; + eorl_source[i] = center_at(cube, R_center)/2; + eoud_source[i] = center_at(cube, U_center)/2; + coud_source[i] = center_at(cube, U_center)/2; + cofb_source[i] = center_at(cube, F_center)/2; + corl_source[i] = center_at(cube, R_center)/2; + } + + /* Compute rotation_niss array, necessary for rotate_via_compose */ + for (r = 0; r != mirror; r++) { + concat(rotation_algs[r], rotation_algs[r], rotation_niss[r]); + for (i = len(rotation_algs[r]); rotation_niss[r][i].m; i++) + rotation_niss[r][i].inverse = true; + } + + if (read_rtables_file()) + return; + + fprintf(stderr, "rtables not found, generating them.\n"); + + /* Initialize tables */ + for (m = 0; m < NTRANS; m++) { + if (m == mirror) { + intarrcopy(ep_mirror, eparr, 12); + intarrcopy(cp_mirror, cparr, 8); + } else { + epcp = (CubeArray){ .ep = eparr, .cp = cparr }; + cube = apply_alg(rotation_algs[m], (Cube){0}); + cube_to_arrays(cube, &epcp, pf_epcp); + } + + 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_rtable[m][ui] = cube.epose; + + cube = rotate_via_compose(m,c[eposs_source[m]],pf_ep); + eposs_rtable[m][ui] = cube.eposs; + + cube = rotate_via_compose(m,c[eposm_source[m]],pf_ep); + eposm_rtable[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_rtable[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_rtable[m][ui] = digit_array_to_int(coarr, 7, 3); + if (m == mirror) + co_rtable[m][ui] = + invert_digits(co_rtable[m][ui], 3, 7); + } + for (ui = 0; ui < factorial8; ui++) { + cube = (Cube){ .cp = ui }; + cube = rotate_via_compose(m, cube, pf_cp); + cp_rtable[m][ui] = cube.cp; + } + for (ui = 0; ui < factorial6; ui++) { + cube = (Cube){ .cpos = ui }; + cube = rotate_via_compose(m, cube, pf_cpos); + cpos_rtable[m][ui] = cube.cpos; + } + for (mi = 0; mi < NMOVES; mi++) { + if (m == mirror) { + b1 = (mi >= U && mi <= Bw3); + b2 = (mi >= S && mi <= E3); + b3 = (mi >= x && mi <= z3); + if (b1 || b2 || b3) + moves_rtable[m][mi] = + inverse_move_aux[mi]; + else + moves_rtable[m][mi] = mi; + + if ((mi-1)/3==(R-1)/3 || (mi-1)/3==(Rw-1)/3) + moves_rtable[m][mi] += 3; + if ((mi-1)/3==(L-1)/3 || (mi-1)/3==(L2-1)/3) + moves_rtable[m][mi] -= 3; + } else { + aux = apply_trans(m, apply_move(mi,(Cube){0})); + for (move = 0; move < NMOVES; move++) { + cube = apply_move( + inverse_move_aux[move], aux); + if (is_solved(cube, false)) + moves_rtable[m][mi] = move; + } + } + } + } + + if (!write_rtables_file()) + fprintf(stderr, "Error writing rtables\n"); +} + +static void +int_to_digit_array(int a, int b, int n, int *r) +{ + int i; + + if (b <= 1) + for (i = 0; i < n; i++) + r[i] = 0; + else + for (i = 0; i < n; i++, a /= b) + r[i] = a % b; +} + +static void +int_to_sum_zero_array(int x, int b, int n, int *a) +{ + int i, s = 0; + + if (b <= 1) { + for (i = 0; i < n; i++) + a[i] = 0; + } else { + int_to_digit_array(x, b, n-1, a); + for (i = 0; i < n - 1; i++) + s = (s + a[i]) % b; + a[n-1] = (b - s) % b; + } +} + +static void +intarrcopy(int *src, int *dst, int n) +{ + int i; + + for (i = 0; i < n; i++) + dst[i] = src[i]; +} + +static int +invert_digits(int a, int b, int n) +{ + int i, *r = malloc(n * sizeof(int)); + + int_to_digit_array(a, b, n, r); + for (i = 0; i < n; i++) + r[i] = (b-r[i]) % b; + + return digit_array_to_int(r, n, b); +} + +static bool +is_perm(int *a, int n) +{ + int *aux = malloc(n * sizeof(int)); + int i; + + for (i = 0; i < n; i++) + if (a[i] < 0 || a[i] >= n) + return false; + else + aux[a[i]] = 1; + + for (i = 0; i < n; i++) + if (!aux[i]) + return false; + + free(aux); + + return true; +} + +static bool +is_subset(int *a, int n, int k) +{ + int i, sum = 0; + + for (i = 0; i < n; i++) + sum += a[i] ? 1 : 0; + + return sum == k; +} + +static Cube +move_via_arrays(CubeArray arr, Cube c, PieceFilter f) +{ + CubeArray arrc; + Cube ret; + + alloc_cubearray(&arrc, f); + cube_to_arrays(c, &arrc, f); + + 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; +} + +static Move * +moveset_to_movelist(bool *moveset, Step step) +{ + Cube c; + int *a = malloc(NMOVES * sizeof(int)), b[NMOVES]; + int na = 0, nb = 0; + Move i; + + if (moveset != NULL) { + for (i = NULLMOVE+1; i < NMOVES; i++) { + if (moveset[i]) { + c = apply_move(i, (Cube){0}); + if (step.f != NULL && step.f(c)) { + a[na++] = i; + } else { + b[nb++] = i; + } + } + } + } + + intarrcopy(b, a+na, nb); + a[na+nb] = NULLMOVE; + + return (Move *)a; +} + +static AlgList * +new_alglist() +{ + AlgList *ret = malloc(sizeof(AlgList)); + + ret->len = 0; + ret->first = NULL; + ret->last = NULL; + + return ret; +} + +static int +perm_sign(int *a, int n) +{ + int i, j, ret = 0; + + if (!is_perm(a,n)) + return -1; + + for (i = 0; i < n; i++) + for (j = i+1; j < n; j++) + ret += (a[i] > a[j]) ? 1 : 0; + + return ret % 2; +} + +static int +perm_to_index(int *a, int n) +{ + int i, j, c, ret = 0; + + if (!is_perm(a, n)) + return -1; + + for (i = 0; i < n; i++) { + c = 0; + for (j = i+1; j < n; j++) + c += (a[i] > a[j]) ? 1 : 0; + ret += factorial(n-i-1) * c; + } + + return ret; +} + +static int +powint(int a, int b) +{ + if (b < 0) + return 0; /* Truncate */ + if (b == 0) + return 1; + + if (b % 2) + return a * powint(a, b-1); + else + return powint(a*a, b/2); +} + +static bool +read_rtables_file() +{ + FILE *ttf; + int b = sizeof(uint16_t); + bool r = true; + Move m; + + if ((ttf = fopen("rtables", "rb")) != NULL) { + for (m = 0; m < NTRANS; m++) { + r = r && fread(epose_rtable[m],b,me[0],ttf) == me[0]; + r = r && fread(eposs_rtable[m],b,me[1],ttf) == me[1]; + r = r && fread(eposm_rtable[m],b,me[2],ttf) == me[2]; + r = r && fread(eo_rtable[m],b,me[3],ttf) == me[3]; + r = r && fread(cp_rtable[m],b,me[6],ttf) == me[6]; + r = r && fread(co_rtable[m],b,me[7],ttf) == me[7]; + r = r && fread(cpos_rtable[m],b,me[10],ttf) == me[10]; + r = r && fread(moves_rtable[m],b,me[11],ttf) == me[11]; + } + fclose(ttf); + return r; + } else { + return false; + } +} + +static bool +read_ttables_file() +{ + FILE *ttf; + int m, b = sizeof(uint16_t); + bool r = true; + + if ((ttf = fopen("ttables", "rb")) != NULL) { + for (m = 0; m < NMOVES; m++) { + r = r && fread(epose_ttable[m],b,me[0],ttf) == me[0]; + r = r && fread(eposs_ttable[m],b,me[1],ttf) == me[1]; + r = r && fread(eposm_ttable[m],b,me[2],ttf) == me[2]; + r = r && fread(eofb_ttable[m],b,me[3],ttf) == me[3]; + r = r && fread(eorl_ttable[m],b,me[4],ttf) == me[4]; + r = r && fread(eoud_ttable[m],b,me[5],ttf) == me[5]; + r = r && fread(cp_ttable[m],b,me[6],ttf) == me[6]; + r = r && fread(coud_ttable[m],b,me[7],ttf) == me[7]; + r = r && fread(corl_ttable[m],b,me[8],ttf) == me[8]; + r = r && fread(cofb_ttable[m],b,me[9],ttf) == me[9]; + r = r && fread(cpos_ttable[m],b,me[10],ttf) == me[10]; + } + fclose(ttf); + return r; + } else { + return false; + } +} + +static bool +realloc_alg(Alg alg, int n) +{ + if (n+1 >= BASEALGLEN) { + if (reallocarray(alg, n+2, sizeof(NissMove)) == NULL) { + fprintf(stderr, "Error reallocating alg\n"); + return false; + } + } + + return true; +} + +static Cube +rotate_via_compose(Trans r, Cube c, PieceFilter f) +{ + Cube ret; + CubeArray ma = { + .ep = ep_mirror, + .eofb = zero12, + .eorl = zero12, + .eoud = zero12, + .cp = cp_mirror, + .coud = zero8, + .corl = zero8, + .cofb = zero8, + .cpos = cpos_mirror + }; + + if (r != mirror) { + ret = apply_alg_filtered(rotation_niss[r], c, f); + } else { + ret = move_via_arrays(ma, (Cube){0}, f); + ret = compose_filtered(c, ret, f); + ret = move_via_arrays(ma, ret, f); + } + + return ret; +} + +static void +solve_dfs(Cube c, Step s, SolveOptions opts, DfsData dd) +{ + DfsData newdd; + Move move; + NissMove nm; + int i; + bool found_many, prune, niss_makes_sense; + + found_many = dd.sols->len >= opts.max_solutions; + prune = (!opts.can_niss || dd.niss) && dd.m + s.f(c) > dd.d; + if (found_many || prune) + return; + + if (!s.f(c)) { + if (dd.m == dd.d) + append_alg(dd.sols, dd.current_alg); + return; + } + + for (i = 0; opts.sorted_moves[i] != NULLMOVE; i++) { + move = opts.sorted_moves[i]; + if (possible_next[dd.last2][dd.last1][move]) { + nm = (NissMove){ .m = move, .inverse = dd.niss }; + newdd = (DfsData) { + .d = dd.d, + .m = dd.m + 1, + .niss = dd.niss, + .last1 = move, + .last2 = dd.last1, + .sols = dd.sols, + .current_alg = dd.current_alg, + }; + + append_move(dd.current_alg, nm); + solve_dfs(apply_move(move, c), s, opts, newdd); + remove_last_moves(dd.current_alg, 1); + } + } + + niss_makes_sense = !dd.m || (s.f(apply_move(dd.last1, (Cube){0}))); + if (opts.can_niss && !dd.niss && niss_makes_sense) { + newdd = (DfsData) { + .d = dd.d, + .m = dd.m, + .niss = true, + .last1 = NULLMOVE, + .last2 = NULLMOVE, + .sols = dd.sols, + .current_alg = dd.current_alg, + }; + solve_dfs(inverse_cube(c), s, opts, newdd); + } +} + +static int +subset_to_index(int *a, int n, int k) +{ + int i, ret = 0; + + if (!is_subset(a, n, k)) + return binomial(n, k); + + for (i = 0; i < n; i++) { + if (k == n-i) + return ret; + if (a[i]) { + ret += binomial(n-i-1, k); + k--; + } + } + + return ret; +} + +static void +sum_arrays_mod(int *src, int *dst, int n, int m) +{ + int i; + + for (i = 0; i < n; i++) + dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m; +} + +static void +swap(int *a, int *b) +{ + int aux; + + aux = *a; + *a = *b; + *b = aux; +} + +static bool +write_rtables_file() +{ + FILE *ttf; + bool r = true; + int b = sizeof(uint16_t); + Move m; + + if ((ttf = fopen("rtables", "wb")) != NULL) { + for (m = 0; m < NTRANS; m++) { + r = r && fwrite(epose_rtable[m],b,me[0], ttf) == me[0]; + r = r && fwrite(eposs_rtable[m],b,me[1], ttf) == me[1]; + r = r && fwrite(eposm_rtable[m],b,me[2], ttf) == me[2]; + r = r && fwrite(eo_rtable[m],b,me[3], ttf) == me[3]; + r = r && fwrite(cp_rtable[m],b,me[6], ttf) == me[6]; + r = r && fwrite(co_rtable[m],b,me[7], ttf) == me[7]; + r = r && fwrite(cpos_rtable[m],b,me[10],ttf) == me[10]; + r = r && fwrite(moves_rtable[m],b,me[11],ttf)== me[11]; + } + fclose(ttf); + return r; + } else { + return false; + } +} + +static bool +write_ttables_file() +{ + FILE *ttf; + int m, b = sizeof(uint16_t);; + bool r = true; + + if ((ttf = fopen("ttables", "wb")) != NULL) { + for (m = 0; m < NMOVES; m++) { + r = r && fwrite(epose_ttable[m],b,me[0],ttf) == me[0]; + r = r && fwrite(eposs_ttable[m],b,me[1],ttf) == me[1]; + r = r && fwrite(eposm_ttable[m],b,me[2],ttf) == me[2]; + r = r && fwrite(eofb_ttable[m],b,me[3],ttf) == me[3]; + r = r && fwrite(eorl_ttable[m],b,me[4],ttf) == me[4]; + r = r && fwrite(eoud_ttable[m],b,me[5],ttf) == me[5]; + r = r && fwrite(cp_ttable[m],b,me[6],ttf) == me[6]; + r = r && fwrite(coud_ttable[m],b,me[7],ttf) == me[7]; + r = r && fwrite(corl_ttable[m],b,me[8],ttf) == me[8]; + r = r && fwrite(cofb_ttable[m],b,me[9],ttf) == me[9]; + r = r && fwrite(cpos_ttable[m],b,me[10],ttf) == me[10]; + } + fclose(ttf); + return r; + } else { + return false; + } +} + +/* Public functions implementation *******************************************/ + +Cube +apply_alg(Alg alg, Cube cube) +{ + return apply_alg_filtered(alg, cube, pf_all); +} + +Cube +apply_move(Move m, Cube cube) +{ + Cube moved = {0}; + + moved.epose = epose_ttable[m][cube.epose]; + moved.eposs = eposs_ttable[m][cube.eposs]; + moved.eposm = eposm_ttable[m][cube.eposm]; + moved.eofb = eofb_ttable[m][cube.eofb]; + moved.eorl = eorl_ttable[m][cube.eorl]; + moved.eoud = eoud_ttable[m][cube.eoud]; + moved.coud = coud_ttable[m][cube.coud]; + moved.cofb = cofb_ttable[m][cube.cofb]; + moved.corl = corl_ttable[m][cube.corl]; + moved.cp = cp_ttable[m][cube.cp]; + moved.cpos = cpos_ttable[m][cube.cpos]; + + return moved; +} + +Cube +apply_trans(Trans t, Cube cube) +{ + Cube transformed = {0}; + uint16_t aux_epos[3] = { cube.epose, cube.eposs, cube.eposm }; + uint16_t aux_eo[3] = { cube.eoud, cube.eorl, cube.eofb }; + uint16_t aux_co[3] = { cube.coud, cube.corl, cube.cofb }; + + transformed.epose = epose_rtable[t][aux_epos[epose_source[t]]]; + transformed.eposs = eposs_rtable[t][aux_epos[eposs_source[t]]]; + transformed.eposm = eposm_rtable[t][aux_epos[eposm_source[t]]]; + transformed.eofb = eo_rtable[t][aux_eo[eofb_source[t]]]; + transformed.eorl = eo_rtable[t][aux_eo[eorl_source[t]]]; + transformed.eoud = eo_rtable[t][aux_eo[eoud_source[t]]]; + transformed.coud = co_rtable[t][aux_co[coud_source[t]]]; + transformed.corl = co_rtable[t][aux_co[corl_source[t]]]; + transformed.cofb = co_rtable[t][aux_co[cofb_source[t]]]; + transformed.cp = cp_rtable[t][cube.cp]; + transformed.cpos = cpos_rtable[t][cube.cpos]; + + return transformed; +} + +/* TODO: this has to be changed using pre-computations */ +bool +block_solved(Cube cube, Block block) +{ + CubeArray arr; + int i; + bool ret = true; + + alloc_cubearray(&arr, pf_all); + cube_to_arrays(cube, &arr, pf_all); + + for (i = 0; i < 12; i++) + ret = ret && !(block.edge[i] && (arr.ep[i] != i || arr.eofb[i])); + for (i = 0; i < 8; i++) + ret = ret && !(block.corner[i] && (arr.cp[i] != i || arr.coud[i])); + for (i = 0; i < 6; i++) + ret = ret && !(block.center[i] && arr.cpos[i] != i); + + free_cubearray(&arr, pf_all); + + return ret; +} + +Center +center_at(Cube cube, Center c) +{ + int ret; + CubeArray arr; + + alloc_cubearray(&arr, pf_cpos); + cube_to_arrays(cube, &arr, pf_cpos); + ret = arr.cpos[c]; + free_cubearray(&arr, pf_cpos); + + return ret; +} + +Cube +compose(Cube c2, Cube c1) +{ + return compose_filtered(c2, c1, pf_all); +} + +Corner +corner_at(Cube cube, Corner c) +{ + int ret; + CubeArray arr; + + alloc_cubearray(&arr, pf_cp); + cube_to_arrays(cube, &arr, pf_cp); + ret = arr.cp[c]; + free_cubearray(&arr, pf_cp); + + return ret; +} + +Edge +edge_at(Cube cube, Edge e) +{ + int ret; + CubeArray arr; + + alloc_cubearray(&arr, pf_ep); + cube_to_arrays(cube, &arr, pf_ep); + ret = arr.ep[e]; + free_cubearray(&arr, pf_ep); + + return ret; +} + +bool +equal(Cube c1, Cube c2) +{ + 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 arr, inv; + Cube ret; + int i; + + alloc_cubearray(&arr, pf_all); + alloc_cubearray(&inv, pf_all); + + cube_to_arrays(cube, &arr, pf_all); + + for (i = 0; i < 12; i++) { + inv.ep[arr.ep[i]] = i; + inv.eofb[arr.ep[i]] = arr.eofb[i]; + inv.eorl[arr.ep[i]] = arr.eorl[i]; + inv.eoud[arr.ep[i]] = arr.eoud[i]; + } + + for (i = 0; i < 8; i++) { + inv.cp[arr.cp[i]] = i; + inv.coud[arr.cp[i]] = (3 - arr.coud[i]) % 3; + inv.corl[arr.cp[i]] = (3 - arr.corl[i]) % 3; + inv.cofb[arr.cp[i]] = (3 - arr.cofb[i]) % 3; + } + + for (int i = 0; i < 6; i++) + inv.cpos[arr.cpos[i]] = i; + + ret = arrays_to_cube(inv, pf_all); + free_cubearray(&arr, pf_all); + free_cubearray(&inv, pf_all); + + return ret; +} + +Move +inverse_move(Move m) +{ + return inverse_move_aux[m]; +} + +Trans +inverse_trans(Trans t) +{ + return inverse_trans_aux[t]; +} + +bool +is_solved(Cube cube, bool reorient) +{ + int i; + + if (reorient) + for (i = 0; i < NROTATIONS; i++) + if (is_solved(apply_alg(rotation_algs[i], cube), false)) + return true; + + return equal(cube, (Cube){0}); +} + +int +piece_orientation(Cube cube, int piece, char *orientation) +{ + int arr[12], n, b; + uint16_t 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) +{ + CubeArray arr; + + alloc_cubearray(&arr, pf_all); + cube_to_arrays(cube, &arr, pf_all); + + for (int i = 0; i < 12; i++) + printf(" %s ", edge_string[arr.ep[i]]); + printf("\n"); + + for (int i = 0; i < 12; i++) + printf(" %c ", arr.eofb[i] + '0'); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf("%s ", corner_string[arr.cp[i]]); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf(" %c ", arr.coud[i] + '0'); + printf("\n"); + + for (int i = 0; i < 6; i++) + printf(" %s ", center_string[arr.cpos[i]]); + printf("\n"); + + free_cubearray(&arr, pf_all); +} + +void +concat(Alg src1, Alg src2, Alg dest) +{ + int n1 = len(src1), n2 = len(src2); + + if (!realloc_alg(dest, n1+n2)) + return; + + copy_alg(src1, dest); + copy_alg(src2, dest + n1); +} + +void +copy_alg(Alg src, Alg dest) +{ + int i, n = len(src); + + if (!realloc_alg(dest, n)) + return; + + for (i = 0; src[i].m != NULLMOVE; i++) + dest[i] = src[i]; + dest[i].m = NULLMOVE; +} + +void +invert_alg(Alg src, Alg dest) +{ + Move m; + int i, n = len(src); + + if (!realloc_alg(dest, n)) + return; + + for (i = 0; i < n; i++) { + m = inverse_move_aux[src[i].m]; + dest[n-i-1] = (NissMove) { .m = m, .inverse = src[i].inverse }; + } + dest[n].m = NULLMOVE; +} + +int +len(Alg alg) +{ + int i; + + for (i = 0; alg[i].m != NULLMOVE; i++); + + return i; +} + +Alg +new_alg(char *str) +{ + Alg alg = malloc(BASEALGLEN * sizeof(NissMove)); + int i; + bool niss = false; + Move j, m; + NissMove nm; + + alg[0] = (NissMove){ .m = NULLMOVE }; + for (i = 0; str[i]; i++) { + if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n') + continue; + + if (str[i] == '(' && niss) { + fprintf(stderr, "Error reading moves: nested ( )\n"); + return alg; + } + + if (str[i] == ')' && !niss) { + fprintf(stderr, "Error reading moves: unmatched )\n"); + return alg; + } + + if (str[i] == '(' || str[i] == ')') { + niss = !niss; + continue; + } + + for (j = 0; j < NMOVES; j++) { + if (str[i] == move_string[j][0]) { + m = j; + if (m <= B && str[i+1]=='w') { + m += Uw - U; + i++; + } + if (str[i+1]=='2') { + m += 1; + i++; + } else if (str[i+1]=='\'' || str[i+1]=='3') { + m += 2; + i++; + } + nm = (NissMove){ .m = m, .inverse = niss }; + append_move(alg, nm); + break; + } + } + } + append_move(alg, (NissMove){ .m = NULLMOVE }); + + return alg; +} + +void +print_alg(Alg alg) +{ + char fill[4]; + int i; + bool niss = false; + + for (i = 0; alg[i].m != NULLMOVE; i++) { + if (!niss && alg[i].inverse) + strcpy(fill, i == 0 ? "(" : " ("); + if (niss && !alg[i].inverse) + strcpy(fill, ") "); + if (niss == alg[i].inverse) + strcpy(fill, i == 0 ? "" : " "); + + printf("%s%s", fill, move_string[alg[i].m]); + niss = alg[i].inverse; + } + printf("%s\n", niss ? ")" : ""); +} + +void +remove_last_moves(Alg alg, int k) +{ + int n = len(alg); + int i = max(0, n-k); + + alg[i].m = NULLMOVE; +} + +AlgList * +solve(Cube cube, Step step, SolveOptions opts) +{ + AlgList *sols = new_alglist(); + AlgListNode *node; + Cube c; + DfsData dd; + int i; + + if (step.ready != NULL && !step.ready(cube)) + return sols; + + if (opts.sorted_moves == NULL) + opts.sorted_moves = moveset_to_movelist(opts.moveset, step); + + for (i = opts.min_moves; i <= opts.max_moves; i++) { + if (sols->len && opts.optimal_only) + break; + + c = apply_trans(opts.pre_trans, cube); + dd = (DfsData) { + .d = i, + .m = 0, + .niss = false, + .last1 = NULLMOVE, + .last2 = NULLMOVE, + .sols = sols, + .current_alg = new_alg("") + }; + + solve_dfs(c, step, opts, dd); + } + + for (node = sols->first; node != NULL; node = node->next) + transform_alg(inverse_trans_aux[opts.pre_trans], node->alg); + + return sols; +} + +void +transform_alg(Trans t, Alg alg) +{ + int i; + + for (i = 0; alg[i].m != NULLMOVE; i++) + alg[i].m = moves_rtable[t][alg[i].m]; +} + + +void +init() +{ + init_moves(); + init_auxtables(); + init_trans(); +} diff --git a/old/2021-06-02-cleanedup/cube.h b/old/2021-06-02-cleanedup/cube.h new file mode 100644 index 0000000..f1559a4 --- /dev/null +++ b/old/2021-06-02-cleanedup/cube.h @@ -0,0 +1,179 @@ +#include +#include +#include +#include +#include + +/* Constants ****************************************************************/ + +#define NMOVES (z3+1) +#define NTRANS (mirror+1) +#define NROTATIONS (NTRANS-1) + +/* Typedefs *****************************************************************/ + +typedef enum center Center; +typedef enum corner Corner; +typedef enum edge Edge; +typedef enum move Move; +typedef enum trans Trans; + +typedef struct nissmove * Alg; +typedef struct alglist AlgList; +typedef struct alglistnode AlgListNode; +typedef struct block Block; +typedef struct cube Cube; +typedef struct nissmove NissMove; +typedef struct solveoptions SolveOptions; +typedef struct step Step; + +/* Type specifications *******************************************************/ + +enum +center +{ + U_center, D_center, + R_center, L_center, + F_center, B_center +}; + +enum +corner +{ + UFR, UFL, UBL, UBR, + DFR, DFL, DBL, DBR +}; + +enum +edge +{ + UF, UL, UB, UR, + DF, DL, DB, DR, + FR, FL, BL, BR +}; + +enum +move +{ + NULLMOVE, + U, U2, U3, D, D2, D3, + R, R2, R3, L, L2, L3, + F, F2, F3, B, B2, B3, + Uw, Uw2, Uw3, Dw, Dw2, Dw3, + Rw, Rw2, Rw3, Lw, Lw2, Lw3, + Fw, Fw2, Fw3, Bw, Bw2, Bw3, + M, M2, M3, + S, S2, S3, + E, E2, E3, + x, x2, x3, + y, y2, y3, + z, z2, z3, +}; + +enum +trans +{ + uf, ur, ub, ul, + df, dr, db, dl, + rf, rd, rb, ru, + lf, ld, lb, lu, + fu, fr, fd, fl, + bu, br, bd, bl, + mirror, /* R|L */ +}; + +struct +alglist +{ + AlgListNode *first; + AlgListNode *last; + int len; +}; + +struct +alglistnode +{ + Alg alg; + AlgListNode *next; +}; + +struct +block +{ + bool edge[12]; + bool corner[8]; + bool center[6]; +}; + +struct +cube +{ + uint16_t epose; + uint16_t eposs; + uint16_t eposm; + uint16_t eofb; + uint16_t eorl; + uint16_t eoud; + uint16_t cp; + uint16_t coud; + uint16_t cofb; + uint16_t corl; + uint16_t cpos; +}; + +struct +nissmove +{ + Move m; + bool inverse; +}; + +struct +solveoptions +{ + int min_moves; + int max_moves; + int max_solutions; + bool optimal_only; + bool can_niss; + bool *moveset; + Move *sorted_moves; + Trans pre_trans; +}; + +struct +step +{ + int (*f)(Cube); + bool (*ready)(Cube); +}; + +/* Public functions **********************************************************/ + +Cube apply_alg(Alg alg, Cube cube); +Cube apply_move(Move m, Cube cube); +Cube apply_trans(Trans t, Cube cube); +bool block_solved(Cube cube, Block); +Center center_at(Cube cube, Center c); +Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */ +Corner corner_at(Cube cube, Corner c); +Edge edge_at(Cube cube, Edge e); +bool equal(Cube c1, Cube c2); +Cube inverse_cube(Cube cube); +Move inverse_move(Move m); +Trans inverse_trans(Trans t); +bool is_solved(Cube cube, bool reorient); +int piece_orientation(Cube cube, int piece, char *orientation); +void print_cube(Cube cube); +AlgList * solve(Cube cube, Step step, SolveOptions opts); + +void concat(Alg src1, Alg src2, Alg dest); +void copy_alg(Alg src, Alg dest); +void invert_alg(Alg src, Alg dest); +int len(Alg alg); +Alg new_alg(char *str); +void print_alg(Alg alg); +void remove_last_moves(Alg alg, int k); +void transform_alg(Trans t, Alg alg); + +void init(); diff --git a/old/2021-06-02-cleanedup/main.c b/old/2021-06-02-cleanedup/main.c new file mode 100644 index 0000000..fca5e3c --- /dev/null +++ b/old/2021-06-02-cleanedup/main.c @@ -0,0 +1,35 @@ +#include +#include "cube.h" +#include "steps.h" + +int main() { + Alg algo; + AlgList *sols; + Cube cube; + SolveOptions opts; + + init(); + + algo = new_alg("R U R' F"); + cube = apply_alg(algo, (Cube){0}); + + print_cube(apply_trans(rd, cube)); + + opts = (SolveOptions) { + .min_moves = 0, + .max_moves = 5, + .optimal_only = true, + .max_solutions = 3, + .can_niss = false, + .moveset = standard_moveset, + .pre_trans = fu + }; + sols = solve(cube, step_eofb, opts); + if (sols->len == 0) + fprintf(stderr, "No solution found\n"); + else + print_alg(sols->first->alg); + + + return 0; +} diff --git a/old/2021-06-02-cleanedup/steps.h b/old/2021-06-02-cleanedup/steps.h new file mode 100644 index 0000000..452b71c --- /dev/null +++ b/old/2021-06-02-cleanedup/steps.h @@ -0,0 +1,22 @@ +/* Pre-conditions, i.e. "ready(cube)" functions ******************************/ + +bool always_ready(Cube cube) { return true; } + +/* Main functions, i.e. "f(cube)" ********************************************/ + +int f_eofb(Cube cube) { return (cube.eofb != 0) ? 1 : 0; } + +/* Steps *********************************************************************/ + +Step step_eofb = { .f = f_eofb, .ready = always_ready }; + +/* Movesets ******************************************************************/ + +bool standard_moveset[NMOVES] = { + [U] = true, [U2] = true, [U3] = true, + [D] = true, [D2] = true, [D3] = true, + [R] = true, [R2] = true, [R3] = true, + [L] = true, [L2] = true, [L3] = true, + [F] = true, [F2] = true, [F3] = true, + [B] = true, [B2] = true, [B3] = true, +}; diff --git a/old/2021-06-14-oldalg/cube.c b/old/2021-06-14-oldalg/cube.c new file mode 100644 index 0000000..5409896 --- /dev/null +++ b/old/2021-06-14-oldalg/cube.c @@ -0,0 +1,2849 @@ +#include "cube.h" + +/* Constants and macros *****************************************************/ + +#define POW2TO11 2048ULL +#define POW2TO12 4096ULL +#define POW3TO7 2187ULL +#define POW3TO8 6561ULL +#define FACTORIAL4 24ULL +#define FACTORIAL6 720ULL +#define FACTORIAL8 40320ULL +#define FACTORIAL12 479001600ULL +#define BINOM12ON4 495ULL +#define BINOM8ON4 70ULL +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +#define BASEALGLEN 50 +#define NMOVES (z3+1) +#define NTRANS (mirror+1) +#define NROTATIONS (NTRANS-1) +#define PTABLESIZE(n) ((n+1) / 2) +#define PTABLEVAL(tab,ind) (((ind)%2) ? (tab[(ind)/2] / 16) : \ + (tab[(ind)/2] % 16)) + + +/* Local functions **********************************************************/ + +static Cube admissible_ep(Cube cube, PieceFilter f); +static void append_alg(AlgList *l, Alg *alg); +static void append_move(Alg *alg, Move m, bool inverse); +static Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a); +static void apply_permutation(int *perm, int *set, int n); +static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f); +static uint16_t array_ep_to_epos(int *ep, int *eps_solved); +static Cube arrays_to_cube(CubeArray *arr, PieceFilter f); +static Move base_move(Move m); +static int binomial(int n, int k); +static Cube compose_filtered(Cube c2, Cube c1, PieceFilter f); +static void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f); +static int digit_array_to_int(int *a, int n, int b); +static int edge_slice(Edge e); /* E=0, S=1, M=2 */ +static int epos_dependent(int pos1, int pos2); +static uint16_t epos_from_arrays(int *epos, int *ep); +static void epos_to_partial_ep(uint16_t epos, int *ep, int *ss); +static int factorial(int n); +static void free_alglistnode(AlgListNode *aln); +static void free_cubearray(CubeArray *arr, PieceFilter f); +static void generate_ptable(PruneData *pd); +static void generate_ptable_dfs(Cube c, PruneData *pd, DfsData *dd); +static void index_to_perm(int p, int n, int *r); +static void index_to_subset(int s, int n, int k, int *r); +static void int_to_digit_array(int a, int b, int n, int *r); +static void int_to_sum_zero_array(int x, int b, int n, int *a); +static int invert_digits(int a, int b, int n); +static bool is_perm(int *a, int n); +static bool is_subset(int *a, int n, int k); +static Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf); +static void moveset_to_list(bool (*ms)(Move), int (*f)(Cube), Move *r); +static AlgList * new_alglist(); +static CubeArray * new_cubearray(Cube cube, PieceFilter f); +static int perm_sign(int *a, int n); +static int perm_to_index(int *a, int n); +static int powint(int a, int b); +static void ptable_set_reached(PruneData *pd, uint64_t ind); +static void ptable_update(PruneData *pd, uint64_t ind, int m); +static bool read_ptable_file(PruneData *pd); +static bool read_ttables_file(); +static bool read_mtables_file(); +static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f); +static void solve_dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static int subset_to_index(int *a, int n, int k); +static void sum_arrays_mod(int *src, int *dst, int n, int m); +static void swap(int *a, int *b); +static bool write_ptable_file(PruneData *pd); +static bool write_ttables_file(); +static bool write_mtables_file(); + +static void init_auxtables(); +static void init_environment(); +static void init_moves(); +static void init_moves_aux(); +static void init_steps(); +static void init_strings(); +static void init_trans(); +static void init_trans_aux(); + +static bool moveset_HTM(Move m); +static bool moveset_URF(Move m); + +/* Steps and related functions and data **************************************/ + +Step eofb_HTM; +Step eorl_HTM; +Step eoud_HTM; +Step coud_HTM; +Step corl_HTM; +Step cofb_HTM; +Step coud_URF; +Step corl_URF; +Step cofb_URF; +Step corners_HTM; +Step corners_URF; +Step edges_HTM; +Step drud_HTM; +Step optimal_HTM; + +PruneData pd_eofb_HTM; +PruneData pd_coud_HTM; +PruneData pd_corners_HTM; +PruneData pd_ep_HTM; +PruneData pd_drud_HTM; + +static uint64_t index_eofb(Cube cube); +static uint64_t index_coud(Cube cube); +static uint64_t index_corners(Cube cube); +static uint64_t index_ep(Cube cube); +static uint64_t index_drud(Cube cube); + +static int check_nothing(Cube cube); +static int check_eofb_HTM(Cube cube); +static int check_coud_HTM(Cube cube); +static int check_coud_URF(Cube cube); +static int check_corners_HTM(Cube cube); +static int check_corners_URF(Cube cube); +static int check_edges_HTM(Cube cube); +static int check_drud_HTM(Cube cube); +static int check_optimal_HTM(Cube cube); + +/* All sorts of useful costants and tables **********************************/ + +static char * tabledir; + +static PieceFilter pf_all; +static PieceFilter pf_4val; +static PieceFilter pf_epcp; +static PieceFilter pf_cpos; +static PieceFilter pf_cp; +static PieceFilter pf_ep; +static PieceFilter pf_e; +static PieceFilter pf_s; +static PieceFilter pf_m; +static PieceFilter pf_eo; +static PieceFilter pf_co; + +static int epe_solved[4]; +static int eps_solved[4]; +static int epm_solved[4]; + +static char move_string[NMOVES][7]; +static char edge_string[12][7]; +static char corner_string[8][7]; +static char center_string[6][7]; + +static bool commute[NMOVES][NMOVES]; +static bool possible_next[NMOVES][NMOVES][NMOVES]; +static Move inverse_move_aux[NMOVES]; +static Trans inverse_trans_aux[NTRANS]; +static int epos_dependent_aux[BINOM12ON4][BINOM12ON4]; + +static uint16_t epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static uint16_t eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static uint16_t eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static uint16_t eo_ttable[NTRANS][POW2TO11]; +static uint16_t cp_ttable[NTRANS][FACTORIAL8]; +static uint16_t co_ttable[NTRANS][POW3TO7]; +static uint16_t cpos_ttable[NTRANS][FACTORIAL6]; +static Move moves_ttable[NTRANS][NMOVES]; + +static uint16_t epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static uint16_t eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static uint16_t eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static uint16_t eofb_mtable[NMOVES][POW2TO11]; +static uint16_t eorl_mtable[NMOVES][POW2TO11]; +static uint16_t eoud_mtable[NMOVES][POW2TO11]; +static uint16_t cp_mtable[NMOVES][FACTORIAL8]; +static uint16_t coud_mtable[NMOVES][POW3TO7]; +static uint16_t cofb_mtable[NMOVES][POW3TO7]; +static uint16_t corl_mtable[NMOVES][POW3TO7]; +static uint16_t cpos_mtable[NMOVES][FACTORIAL6]; + +static uint64_t me[12]; + +static int edge_cycle[NMOVES][12]; +static int corner_cycle[NMOVES][8]; +static int center_cycle[NMOVES][6]; +static int eofb_flipped[NMOVES][12]; +static int eorl_flipped[NMOVES][12]; +static int eoud_flipped[NMOVES][12]; +static int coud_flipped[NMOVES][8]; +static int corl_flipped[NMOVES][8]; +static int cofb_flipped[NMOVES][8]; +static Alg * equiv_alg[NMOVES]; + +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]; +static int ep_mirror[12]; +static int cp_mirror[8]; +static int cpos_mirror[6]; +static Alg * trans_algs[NROTATIONS]; + + +/* Local functions implementation ********************************************/ + +static 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 < 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; +} + +static void +append_alg(AlgList *l, Alg *alg) +{ + AlgListNode *node = malloc(sizeof(AlgListNode)); + AlgNode *i; + + node->alg = new_alg(""); + for (i = alg->first; i != NULL; i = i->next) + append_move(node->alg, i->m, i->inverse); + node->next = NULL; + + if (++l->len == 1) + l->first = node; + else + l->last->next = node; + l->last = node; +} + +static void +append_move(Alg *alg, Move m, bool inverse) +{ + AlgNode *node = malloc(sizeof(AlgNode)); + + node->m = m; + node->inverse = inverse; + node->next = NULL; + node->prev = alg->last; + + if (++alg->len == 1) + alg->first = node; + else + alg->last->next = node; + alg->last = node; +} + +static Cube +apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a) +{ + Cube ret = {0}; + AlgNode *i; + + for (i = alg->first; i != NULL; i = i->next) + if (i->inverse) + ret = a ? apply_move(i->m, ret) : + apply_move_cubearray(i->m, ret, f); + + ret = compose_filtered(c, inverse_cube(ret), f); + + for (i = alg->first; i != NULL; i = i->next) + if (!i->inverse) + ret = a ? apply_move(i->m, ret) : + apply_move_cubearray(i->m, ret, f); + + return ret; +} + +static void +apply_permutation(int *perm, int *set, int n) +{ + int *aux = malloc(n * sizeof(int)); + int i; + + if (!is_perm(perm, n)) + return; + + for (i = 0; i < n; i++) + aux[i] = set[perm[i]]; + + memcpy(set, aux, n * sizeof(int)); + free(aux); +} + +static Cube +apply_move_cubearray(Move m, Cube cube, PieceFilter f) +{ + 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); +} + +static uint16_t +array_ep_to_epos(int *ep, int *ss) +{ + 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 epos_from_arrays(epos, eps); +} + +static Cube +arrays_to_cube(CubeArray *arr, PieceFilter f) +{ + Cube ret = {0}; + + 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; +} + +static Move +base_move(Move m) +{ + if (m == NULLMOVE) + return NULLMOVE; + else + return m - (m-1)%3; +} + +static int +binomial(int n, int k) +{ + if (n < 0 || k < 0 || k > n) + return 0; + + return factorial(n) / (factorial(k) * factorial(n-k)); +} + +static Cube +compose_filtered(Cube c2, Cube c1, PieceFilter f) +{ + CubeArray *arr = new_cubearray(c2, f); + Cube ret; + + ret = move_via_arrays(arr, c1, f); + free_cubearray(arr, f); + + return ret; +} + +static void +cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f) +{ + int i; + + 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); +} + +static int +digit_array_to_int(int *a, int n, int b) +{ + int i, ret = 0, p = 1; + + for (i = 0; i < n; i++, p *= b) + ret += a[i] * p; + + return ret; +} + +static int +edge_slice(Edge e) { + if (e < 0 || e > 11) + return -1; + + if (e == FR || e == FL || e == BL || e == BR) + return 0; + if (e == UR || e == UL || e == DR || e == DL) + return 1; + + return 2; +} + +static int +epos_dependent(int poss, int pose) +{ + int ep[12] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; + int ep8[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + int i, j; + + epos_to_partial_ep(poss*FACTORIAL4, ep, eps_solved); + epos_to_partial_ep(pose*FACTORIAL4, ep, epe_solved); + + for (i = 0, j = 0; i < 12; i++) + if (edge_slice(ep[i]) != 1) + ep8[j++] = (edge_slice(ep[i]) == 0) ? 1 : 0; + + return subset_to_index(ep8, 8, 4); +} + +static uint16_t +epos_from_arrays(int *epos, int *ep) +{ + return FACTORIAL4 * subset_to_index(epos,12,4) + perm_to_index(ep,4); +} + +static void +epos_to_partial_ep(uint16_t epos, int *ep, int *ss) +{ + 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++]]; +} + +static int +factorial(int n) +{ + int i, ret = 1; + + if (n < 0) + return 0; + + for (i = 1; i <= n; i++) + ret *= i; + + return ret; +} + +void +free_alg(Alg *alg) +{ + AlgNode *aux, *i = alg->first; + + while (i != NULL) { + aux = i->next; + free(i); + i = aux; + } + free(alg); +} + +void +free_alglist(AlgList *l) +{ + AlgListNode *aux, *i = l->first; + + while (i != NULL) { + aux = i->next; + free_alglistnode(i); + i = aux; + } + free(l); +} + +void +free_alglistnode(AlgListNode *aln) +{ + free_alg(aln->alg); + free(aln); +} + +static void +free_cubearray(CubeArray *arr, PieceFilter f) +{ + 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); +} + +static void +generate_ptable(PruneData *pd) +{ + uint64_t j; + DfsData dd; + + if (pd->generated) + return; + + pd->ptable = malloc(PTABLESIZE(pd->size) * sizeof(uint8_t)); + + if (read_ptable_file(pd)) { + pd->generated = true; + return; + } + + fprintf(stderr, "Cannot load %s, generating it\n", pd->filename); + + dd.m = 0; + dd.last1 = NULLMOVE; + dd.last2 = NULLMOVE; + + /* We use 4 bits per value, so any distance >= 15 is set to 15 */ + for (j = 0; j < pd->size; j++) + ptable_update(pd, j, 15); + + moveset_to_list(pd->moveset, NULL, dd.sorted_moves); + + pd->reached = malloc(PTABLESIZE(pd->size) * sizeof(uint8_t)); + for (dd.d = 0, pd->n = 0; dd.d < 15 && pd->n < pd->size; dd.d++) { + memset(pd->reached, 0, PTABLESIZE(pd->size)*sizeof(uint8_t)); + generate_ptable_dfs((Cube){0}, pd, &dd); + fprintf(stderr, "Depth %d completed, generated %lu/%lu\n", + dd.d, pd->n, pd->size); + } + + if (!write_ptable_file(pd)) + fprintf(stderr, "Error writing ptable file\n"); + + pd->generated = true; + free(pd->reached); +} + +static void +generate_ptable_dfs(Cube c, PruneData *pd, DfsData *dd) +{ + uint64_t ind = pd->index(c); + int oldval = PTABLEVAL(pd->ptable, ind); + Move i, move, l1 = dd->last1, l2 = dd->last2; + + if (oldval < dd->m || PTABLEVAL(pd->reached, ind) || pd->n == pd->size) + return; + + ptable_set_reached(pd, ind); + + if (dd->m == dd->d) { + if (dd->m < oldval) + ptable_update(pd, ind, dd->m); + return; + } + + dd->m++; + dd->last2 = dd->last1; + + for (i = 0; dd->sorted_moves[i] != NULLMOVE; i++) { + move = dd->sorted_moves[i]; + if (possible_next[l2][l1][move]) { + dd->last1 = move; + generate_ptable_dfs(apply_move(move, c), pd, dd); + } + } + + dd->m--; + dd->last1 = l1; + dd->last2 = l2; +} + +static void +index_to_perm(int p, int n, int *r) +{ + int *a = malloc(n * sizeof(int)); + int i, j, c; + + for (i = 0; i < n; i++) + a[i] = 0; + + if (p < 0 || p >= factorial(n)) + for (i = 0; i < n; i++) + r[i] = -1; + + for (i = 0; i < n; i++) { + c = 0; + j = 0; + while (c <= p / factorial(n-i-1)) + c += a[j++] ? 0 : 1; + r[i] = j-1; + a[j-1] = 1; + p %= factorial(n-i-1); + } + + free(a); +} + +static void +index_to_subset(int s, int n, int k, int *r) +{ + int i, j, v; + + if (s < 0 || s >= binomial(n, k)) { + for (i = 0; i < n; i++) + r[i] = -1; + return; + } + + for (i = 0; i < n; i++) { + if (k == n-i) { + for (j = i; j < n; j++) + r[j] = 1; + return; + } + + if (k == 0) { + for (j = i; j < n; j++) + r[j] = 0; + return; + } + + v = binomial(n-i-1, k); + if (s >= v) { + r[i] = 1; + k--; + s -= v; + } else { + r[i] = 0; + } + } +} + +static void +int_to_digit_array(int a, int b, int n, int *r) +{ + int i; + + if (b <= 1) + for (i = 0; i < n; i++) + r[i] = 0; + else + for (i = 0; i < n; i++, a /= b) + r[i] = a % b; +} + +static void +int_to_sum_zero_array(int x, int b, int n, int *a) +{ + int i, s = 0; + + if (b <= 1) { + for (i = 0; i < n; i++) + a[i] = 0; + } else { + int_to_digit_array(x, b, n-1, a); + for (i = 0; i < n - 1; i++) + s = (s + a[i]) % b; + a[n-1] = (b - s) % b; + } +} + +static int +invert_digits(int a, int b, int n) +{ + int i, ret, *r = malloc(n * sizeof(int)); + + int_to_digit_array(a, b, n, r); + for (i = 0; i < n; i++) + r[i] = (b-r[i]) % b; + + ret = digit_array_to_int(r, n, b); + free(r); + return ret; +} + +static bool +is_perm(int *a, int n) +{ + int *aux = malloc(n * sizeof(int)); + int i; + + for (i = 0; i < n; i++) + if (a[i] < 0 || a[i] >= n) + return false; + else + aux[a[i]] = 1; + + for (i = 0; i < n; i++) + if (!aux[i]) + return false; + + free(aux); + + return true; +} + +static bool +is_subset(int *a, int n, int k) +{ + int i, sum = 0; + + for (i = 0; i < n; i++) + sum += a[i] ? 1 : 0; + + return sum == k; +} + +static Cube +move_via_arrays(CubeArray *arr, Cube c, PieceFilter f) +{ + CubeArray *arrc = new_cubearray(c, f); + Cube ret; + + 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; +} + +static void +moveset_to_list(bool (*ms)(Move m), int (*f)(Cube), Move *r) +{ + Cube c; + int b[NMOVES]; + int na = 0, nb = 0; + Move i; + + if (ms == NULL) { + fprintf(stderr, "Error: no moveset given\n"); + return; + } + + for (i = U; i < NMOVES; i++) { + if (ms(i)) { + c = apply_move(i, (Cube){0}); + if (f != NULL && f(c)) + r[na++] = i; + else + b[nb++] = i; + } + } + + memcpy(r + na, b, nb * sizeof(Move)); + r[na+nb] = NULLMOVE; +} + +static AlgList * +new_alglist() +{ + AlgList *ret = malloc(sizeof(AlgList)); + + ret->len = 0; + ret->first = NULL; + ret->last = NULL; + + return ret; +} + +static CubeArray * +new_cubearray(Cube cube, PieceFilter f) +{ + 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; +} + +static int +perm_sign(int *a, int n) +{ + int i, j, ret = 0; + + if (!is_perm(a,n)) + return -1; + + for (i = 0; i < n; i++) + for (j = i+1; j < n; j++) + ret += (a[i] > a[j]) ? 1 : 0; + + return ret % 2; +} + +static int +perm_to_index(int *a, int n) +{ + int i, j, c, ret = 0; + + if (!is_perm(a, n)) + return -1; + + for (i = 0; i < n; i++) { + c = 0; + for (j = i+1; j < n; j++) + c += (a[i] > a[j]) ? 1 : 0; + ret += factorial(n-i-1) * c; + } + + return ret; +} + +static int +powint(int a, int b) +{ + if (b < 0) + return 0; /* Truncate */ + if (b == 0) + return 1; + + if (b % 2) + return a * powint(a, b-1); + else + return powint(a*a, b/2); +} + +static void +ptable_set_reached(PruneData *pd, uint64_t ind) +{ + uint8_t oldval2 = pd->reached[ind/2]; + int other = ind % 2 ? oldval2 % 16 : oldval2 / 16; + + pd->reached[ind/2] = ind % 2 ? 16 + other : 16*other + 1; +} + +static void +ptable_update(PruneData *pd, uint64_t ind, int n) +{ + uint8_t oldval2 = pd->ptable[ind/2]; + int other = ind % 2 ? oldval2 % 16 : oldval2 / 16; + + pd->ptable[ind/2] = ind % 2 ? 16*n + other : 16*other + n; + pd->n++; +} + +static bool +read_mtables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int m, b = sizeof(uint16_t); + bool r = true; + + 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 +read_ptable_file(PruneData *pd) +{ + FILE *f; + char fname[strlen(tabledir)+100]; + uint64_t r; + + strcpy(fname, tabledir); + strcat(fname, "/"); + strcat(fname, pd->filename); + + if ((f = fopen(fname, "rb")) == NULL) + return false; + + r = fread(pd->ptable, sizeof(uint8_t), PTABLESIZE(pd->size), f); + fclose(f); + + return r == PTABLESIZE(pd->size); +} + +static bool +read_ttables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int b = sizeof(uint16_t); + bool r = true; + Move m; + + 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[6], f) == me[6]; + r = r && fread(co_ttable[m], b, me[7], f) == me[7]; + r = r && fread(cpos_ttable[m], b, me[10], f) == me[10]; + r = r && fread(moves_ttable[m], b, me[11], f) == me[11]; + } + + fclose(f); + return r; +} + +static Cube +rotate_via_compose(Trans r, Cube c, PieceFilter f) +{ + Alg *inv; + 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 + }; + + Cube ret; + + if (r != mirror) { + ret = apply_alg_generic(trans_algs[r], c, f, true); + inv = on_inverse(trans_algs[r]); + ret = apply_alg_generic(inv, ret, f, true); + free_alg(inv); + } else { + ret = move_via_arrays(&ma, (Cube){0}, f); + ret = compose_filtered(c, ret, f); + ret = move_via_arrays(&ma, ret, f); + } + + return ret; +} + +static void +solve_dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + Move move, l1 = dd->last1, l2 = dd->last2; + int i, lower_bound = s.check(c); + bool found_many, prune, niss_make_sense, nissbackup = dd->niss; + + if (opts->can_niss && !dd->niss) + lower_bound = MIN(1, lower_bound); + + found_many = dd->sols->len >= opts->max_solutions; + prune = dd->current_alg->len + lower_bound > dd->d; + if (found_many || prune) + return; + + if (!lower_bound) { /* solved */ + if (dd->current_alg->len == dd->d) + append_alg(dd->sols, dd->current_alg); + return; + } + + dd->last2 = dd->last1; + + for (i = 0; dd->sorted_moves[i] != NULLMOVE; i++) { + move = dd->sorted_moves[i]; + if (possible_next[l2][l1][move]) { + dd->last1 = move; + append_move(dd->current_alg, move, dd->niss); + solve_dfs(apply_move(move, c), s, opts, dd); + remove_last_move(dd->current_alg); + } + } + + niss_make_sense = !dd->current_alg->len || + (s.check(apply_move(l1,(Cube){0}))); + if (opts->can_niss && !dd->niss && niss_make_sense) { + dd->niss = true; + dd->last1 = NULLMOVE; + dd->last2 = NULLMOVE; + solve_dfs(inverse_cube(c), s, opts, dd); + } + + dd->last1 = l1; + dd->last2 = l2; + dd->niss = nissbackup; +} + +static int +subset_to_index(int *a, int n, int k) +{ + int i, ret = 0; + + if (!is_subset(a, n, k)) + return binomial(n, k); + + for (i = 0; i < n; i++) { + if (k == n-i) + return ret; + if (a[i]) { + ret += binomial(n-i-1, k); + k--; + } + } + + return ret; +} + +static void +sum_arrays_mod(int *src, int *dst, int n, int m) +{ + int i; + + for (i = 0; i < n; i++) + dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m; +} + +static void +swap(int *a, int *b) +{ + int aux; + + aux = *a; + *a = *b; + *b = aux; +} + +static bool +write_mtables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int m, b = sizeof(uint16_t); + bool r = true; + + 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; +} + +static bool +write_ptable_file(PruneData *pd) +{ + FILE *f; + char fname[strlen(tabledir)+100]; + uint64_t written; + + strcpy(fname, tabledir); + strcat(fname, "/"); + strcat(fname, pd->filename); + + if ((f = fopen(fname, "wb")) == NULL) + return false; + + written = fwrite(pd->ptable, sizeof(uint8_t), PTABLESIZE(pd->size), f); + fclose(f); + + return written == PTABLESIZE(pd->size); +} + +static bool +write_ttables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + bool r = true; + int b = sizeof(uint16_t); + Move m; + + 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[6], f) == me[6]; + r = r && fwrite(co_ttable[m], b, me[7], f) == me[7]; + r = r && fwrite(cpos_ttable[m], b, me[10], f) == me[10]; + r = r && fwrite(moves_ttable[m], b, me[11], f) == me[11]; + } + + fclose(f); + return r; +} + +/* Init functions implementation *********************************************/ + +static void +init_auxtables() +{ + Cube c1, c2; + uint64_t ui, uj; + int i, j, k; + bool cij, p1, p2; + + for (ui = 0; ui < BINOM12ON4; ui++) + for (uj = 0; uj < BINOM12ON4; uj++) + epos_dependent_aux[ui][uj] = epos_dependent(ui, uj); + + for (i = 0; i < NMOVES; i++) { + for (j = 0; j < NMOVES; j++) { + c1 = apply_move(i, apply_move(j, (Cube){0})); + c2 = apply_move(j, apply_move(i, (Cube){0})); + commute[i][j] = equal(c1, c2); + } + } + + for (i = 0; i < NMOVES; i++) { + for (j = 0; j < NMOVES; j++) { + for (k = 0; k < NMOVES; k++) { + p1 = j && base_move(j) == base_move(k); + p2 = i && base_move(i) == base_move(k); + cij = commute[i][j]; + possible_next[i][j][k] = !(p1 || (cij && p2)); + } + } + } + + for (i = 0; i < NMOVES; i++) + inverse_move_aux[i] = i ? i + 2 - 2*((i-1)%3) : NULLMOVE; + + /* Is there a more elegant way? */ + inverse_trans_aux[uf] = uf; + inverse_trans_aux[ur] = ul; + inverse_trans_aux[ul] = ur; + inverse_trans_aux[ub] = ub; + + inverse_trans_aux[df] = df; + inverse_trans_aux[dr] = dr; + inverse_trans_aux[dl] = dl; + inverse_trans_aux[db] = db; + + inverse_trans_aux[rf] = lf; + inverse_trans_aux[rd] = bl; + inverse_trans_aux[rb] = rb; + inverse_trans_aux[ru] = fr; + + inverse_trans_aux[lf] = rf; + inverse_trans_aux[ld] = br; + inverse_trans_aux[lb] = lb; + inverse_trans_aux[lu] = fl; + + inverse_trans_aux[fu] = fu; + inverse_trans_aux[fr] = ru; + inverse_trans_aux[fd] = bu; + inverse_trans_aux[fl] = lu; + + inverse_trans_aux[bu] = fd; + inverse_trans_aux[br] = ld; + inverse_trans_aux[bd] = bd; + inverse_trans_aux[bl] = rd; + + inverse_trans_aux[mirror] = mirror; +} + +static void +init_environment() +{ + char *nissydata = getenv("NISSYDATA"); + char *localdata = getenv("XDG_DATA_HOME"); + char *home = getenv("HOME"); + bool read, write; + + if (nissydata != NULL) { + tabledir = malloc(strlen(nissydata) * sizeof(char) + 20); + strcpy(tabledir, nissydata); + } else if (localdata != NULL) { + tabledir = malloc(strlen(localdata) * sizeof(char) + 20); + strcpy(tabledir, localdata); + strcat(tabledir, "/nissy"); + } else if (home != NULL) { + tabledir = malloc(strlen(home) * sizeof(char) + 20); + strcpy(tabledir, home); + strcat(tabledir, "/.nissy"); + } + + mkdir(tabledir, 0777); + strcat(tabledir, "/tables"); + mkdir(tabledir, 0777); + + read = !access(tabledir, R_OK); + write = !access(tabledir, W_OK); + + if (!read) { + fprintf(stderr, "Table files cannot be read.\n"); + } else if (!write) { + fprintf(stderr, "Data directory not writable: "); + fprintf(stderr, "tables can be loaded, but not saved.\n"); + } +} + +static void +init_moves() { + Cube c; + CubeArray arrs; + int i; + uint16_t ui; + Move m; + + /* 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; + + fprintf(stderr, "Cannot load %s, generating it\n", "mtables"); + + /* Initialize transition tables */ + for (m = 0; m < NMOVES; m++) { + 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; + } + } + + if (!write_mtables_file()) + fprintf(stderr, "Error writing mtables\n"); +} + +static void +init_moves_aux() +{ + /* Some standard PieceFilters */ + pf_all.epose = true; + pf_all.eposs = true; + pf_all.eposm = true; + pf_all.eofb = true; + pf_all.eorl = true; + pf_all.eoud = true; + pf_all.cp = true; + pf_all.cofb = true; + pf_all.corl = true; + pf_all.coud = true; + pf_all.cpos = true; + + pf_4val.epose = true; + pf_4val.eposs = true; + pf_4val.eposm = true; + pf_4val.eofb = true; + pf_4val.coud = true; + pf_4val.cp = true; + + pf_epcp.epose = true; + pf_epcp.eposs = true; + pf_epcp.eposm = true; + pf_epcp.cp = true; + + pf_cpos.cpos = true; + + pf_cp.cp = true; + + pf_ep.epose = true; + pf_ep.eposs = true; + pf_ep.eposm = true; + + pf_e.epose = true; + pf_s.eposs = true; + pf_m.eposm = true; + + pf_eo.eofb = true; + pf_eo.eorl = true; + pf_eo.eoud = true; + + pf_co.cofb = true; + pf_co.corl = true; + pf_co.coud = true; + + /* Used to convert to and from CubeArray */ + epe_solved[0] = FR; + epe_solved[1] = FL; + epe_solved[2] = BL; + epe_solved[3] = BR; + + eps_solved[0] = UL; + eps_solved[1] = UR; + eps_solved[2] = DL; + eps_solved[3] = DR; + + epm_solved[0] = UF; + epm_solved[1] = UB; + epm_solved[2] = DF; + epm_solved[3] = DB; + + /* Table sizes, used for reading and writing files */ + me[0] = FACTORIAL12/FACTORIAL8; + me[1] = FACTORIAL12/FACTORIAL8; + me[2] = FACTORIAL12/FACTORIAL8; + me[3] = POW2TO11; + me[4] = POW2TO11; + me[5] = POW2TO11; + me[6] = FACTORIAL8; + me[7] = POW3TO7; + me[8] = POW3TO7; + me[9] = POW3TO7; + me[10] = FACTORIAL6; + me[11] = NMOVES; + + /* Cycles *********************/ + edge_cycle[U][UF] = UR; + edge_cycle[U][UL] = UF; + edge_cycle[U][UB] = UL; + edge_cycle[U][UR] = UB; + edge_cycle[U][DF] = DF; + edge_cycle[U][DL] = DL; + edge_cycle[U][DB] = DB; + edge_cycle[U][DR] = DR; + edge_cycle[U][FR] = FR; + edge_cycle[U][FL] = FL; + edge_cycle[U][BL] = BL; + edge_cycle[U][BR] = BR; + + edge_cycle[x][UF] = DF; + edge_cycle[x][UL] = FL; + edge_cycle[x][UB] = UF; + edge_cycle[x][UR] = FR; + edge_cycle[x][DF] = DB; + edge_cycle[x][DL] = BL; + edge_cycle[x][DB] = UB; + edge_cycle[x][DR] = BR; + edge_cycle[x][FR] = DR; + edge_cycle[x][FL] = DL; + edge_cycle[x][BL] = UL; + edge_cycle[x][BR] = UR; + + edge_cycle[y][UF] = UR; + edge_cycle[y][UL] = UF; + edge_cycle[y][UB] = UL; + edge_cycle[y][UR] = UB; + edge_cycle[y][DF] = DR; + edge_cycle[y][DL] = DF; + edge_cycle[y][DB] = DL; + edge_cycle[y][DR] = DB; + edge_cycle[y][FR] = BR; + edge_cycle[y][FL] = FR; + edge_cycle[y][BL] = FL; + edge_cycle[y][BR] = BL; + + corner_cycle[U][UFR] = UBR; + corner_cycle[U][UFL] = UFR; + corner_cycle[U][UBL] = UFL; + corner_cycle[U][UBR] = UBL; + corner_cycle[U][DFR] = DFR; + corner_cycle[U][DFL] = DFL; + corner_cycle[U][DBL] = DBL; + corner_cycle[U][DBR] = DBR; + + corner_cycle[x][UFR] = DFR; + corner_cycle[x][UFL] = DFL; + corner_cycle[x][UBL] = UFL; + corner_cycle[x][UBR] = UFR; + corner_cycle[x][DFR] = DBR; + corner_cycle[x][DFL] = DBL; + corner_cycle[x][DBL] = UBL; + corner_cycle[x][DBR] = UBR; + + corner_cycle[y][UFR] = UBR; + corner_cycle[y][UFL] = UFR; + corner_cycle[y][UBL] = UFL; + corner_cycle[y][UBR] = UBL; + corner_cycle[y][DFR] = DBR; + corner_cycle[y][DFL] = DFR; + corner_cycle[y][DBL] = DFL; + corner_cycle[y][DBR] = DBL; + + center_cycle[U][U_center] = U_center; + center_cycle[U][D_center] = D_center; + center_cycle[U][R_center] = R_center; + center_cycle[U][L_center] = L_center; + center_cycle[U][F_center] = F_center; + center_cycle[U][B_center] = B_center; + + center_cycle[x][U_center] = F_center; + center_cycle[x][D_center] = B_center; + center_cycle[x][R_center] = R_center; + center_cycle[x][L_center] = L_center; + center_cycle[x][F_center] = D_center; + center_cycle[x][B_center] = U_center; + + center_cycle[y][U_center] = U_center; + center_cycle[y][D_center] = D_center; + center_cycle[y][R_center] = B_center; + center_cycle[y][L_center] = F_center; + center_cycle[y][F_center] = R_center; + center_cycle[y][B_center] = L_center; + + /* Flipped pieces *************/ + eofb_flipped[x][UF] = 1; + eofb_flipped[x][UB] = 1; + eofb_flipped[x][DF] = 1; + eofb_flipped[x][DB] = 1; + + eofb_flipped[y][FR] = 1; + eofb_flipped[y][FL] = 1; + eofb_flipped[y][BL] = 1; + eofb_flipped[y][BR] = 1; + + eorl_flipped[x][UF] = 1; + eorl_flipped[x][UL] = 1; + eorl_flipped[x][UB] = 1; + eorl_flipped[x][UR] = 1; + eorl_flipped[x][DF] = 1; + eorl_flipped[x][DL] = 1; + eorl_flipped[x][DB] = 1; + eorl_flipped[x][DR] = 1; + eorl_flipped[x][FR] = 1; + eorl_flipped[x][FL] = 1; + eorl_flipped[x][BL] = 1; + eorl_flipped[x][BR] = 1; + + eorl_flipped[y][FR] = 1; + eorl_flipped[y][FL] = 1; + eorl_flipped[y][BL] = 1; + eorl_flipped[y][BR] = 1; + + eoud_flipped[U][UF] = 1; + eoud_flipped[U][UL] = 1; + eoud_flipped[U][UB] = 1; + eoud_flipped[U][UR] = 1; + + eoud_flipped[x][UF] = 1; + eoud_flipped[x][UB] = 1; + eoud_flipped[x][DF] = 1; + eoud_flipped[x][DB] = 1; + + eoud_flipped[y][UF] = 1; + eoud_flipped[y][UL] = 1; + eoud_flipped[y][UB] = 1; + eoud_flipped[y][UR] = 1; + eoud_flipped[y][DF] = 1; + eoud_flipped[y][DL] = 1; + eoud_flipped[y][DB] = 1; + eoud_flipped[y][DR] = 1; + eoud_flipped[y][FR] = 1; + eoud_flipped[y][FL] = 1; + eoud_flipped[y][BL] = 1; + eoud_flipped[y][BR] = 1; + + coud_flipped[x][UFR] = 2; + coud_flipped[x][UFL] = 1; + coud_flipped[x][UBR] = 1; + coud_flipped[x][UBL] = 2; + coud_flipped[x][DFR] = 1; + coud_flipped[x][DFL] = 2; + coud_flipped[x][DBR] = 2; + coud_flipped[x][DBL] = 1; + + corl_flipped[U][UFR] = 1; + corl_flipped[U][UFL] = 2; + corl_flipped[U][UBL] = 1; + corl_flipped[U][UBR] = 2; + + corl_flipped[y][UFR] = 1; + corl_flipped[y][UFL] = 2; + corl_flipped[y][UBL] = 1; + corl_flipped[y][UBR] = 2; + corl_flipped[y][DFR] = 2; + corl_flipped[y][DFL] = 1; + corl_flipped[y][DBL] = 2; + corl_flipped[y][DBR] = 1; + + cofb_flipped[U][UFR] = 2; + cofb_flipped[U][UFL] = 1; + cofb_flipped[U][UBL] = 2; + cofb_flipped[U][UBR] = 1; + + cofb_flipped[x][UFR] = 1; + cofb_flipped[x][UFL] = 2; + cofb_flipped[x][UBL] = 1; + cofb_flipped[x][UBR] = 2; + cofb_flipped[x][DFR] = 2; + cofb_flipped[x][DFL] = 1; + cofb_flipped[x][DBL] = 2; + cofb_flipped[x][DBR] = 1; + + cofb_flipped[y][UFR] = 2; + cofb_flipped[y][UFL] = 1; + cofb_flipped[y][UBL] = 2; + cofb_flipped[y][UBR] = 1; + cofb_flipped[y][DFR] = 1; + cofb_flipped[y][DFL] = 2; + cofb_flipped[y][DBL] = 1; + cofb_flipped[y][DBR] = 2; + + /* Equivalent moves ***********/ + equiv_alg[NULLMOVE] = new_alg(""); + + equiv_alg[U] = new_alg(" U "); + equiv_alg[U2] = new_alg(" UU "); + equiv_alg[U3] = new_alg(" UUU "); + equiv_alg[D] = new_alg(" xx U xx "); + equiv_alg[D2] = new_alg(" xx UU xx "); + equiv_alg[D3] = new_alg(" xx UUU xx "); + equiv_alg[R] = new_alg(" yx U xxxyyy "); + equiv_alg[R2] = new_alg(" yx UU xxxyyy "); + equiv_alg[R3] = new_alg(" yx UUU xxxyyy "); + equiv_alg[L] = new_alg(" yyyx U xxxy "); + equiv_alg[L2] = new_alg(" yyyx UU xxxy "); + equiv_alg[L3] = new_alg(" yyyx UUU xxxy "); + equiv_alg[F] = new_alg(" x U xxx "); + equiv_alg[F2] = new_alg(" x UU xxx "); + equiv_alg[F3] = new_alg(" x UUU xxx "); + equiv_alg[B] = new_alg(" xxx U x "); + equiv_alg[B2] = new_alg(" xxx UU x "); + equiv_alg[B3] = new_alg(" xxx UUU x "); + + equiv_alg[Uw] = new_alg(" xx U xx y "); + equiv_alg[Uw2] = new_alg(" xx UU xx yy "); + equiv_alg[Uw3] = new_alg(" xx UUU xx yyy "); + equiv_alg[Dw] = new_alg(" U yyy "); + equiv_alg[Dw2] = new_alg(" UU yy "); + equiv_alg[Dw3] = new_alg(" UUU y "); + equiv_alg[Rw] = new_alg(" yyyx U xxxy x "); + equiv_alg[Rw2] = new_alg(" yyyx UU xxxy xx "); + equiv_alg[Rw3] = new_alg(" yyyx UUU xxxy xxx "); + equiv_alg[Lw] = new_alg(" yx U xxxyyy xxx "); + equiv_alg[Lw2] = new_alg(" yx UU xxxyyy xx "); + equiv_alg[Lw3] = new_alg(" yx UUU xxxyyy x "); + equiv_alg[Fw] = new_alg(" xxx U x yxxxyyy "); + equiv_alg[Fw2] = new_alg(" xxx UU x yxxyyy "); + equiv_alg[Fw3] = new_alg(" xxx UUU x yxyyy "); + equiv_alg[Bw] = new_alg(" x U xxx yxyyy "); + equiv_alg[Bw2] = new_alg(" x UU xxx yxxyyy "); + equiv_alg[Bw3] = new_alg(" x UUU xxx yxxxyyy "); + + equiv_alg[M] = new_alg(" yx U xx UUU yxyyy "); + equiv_alg[M2] = new_alg(" yx UU xx UU xxxy "); + equiv_alg[M3] = new_alg(" yx UUU xx U yxxxy "); + equiv_alg[S] = new_alg(" x UUU xx U yyyx "); + equiv_alg[S2] = new_alg(" x UU xx UU yyx "); + equiv_alg[S3] = new_alg(" x U xx UUU yx "); + equiv_alg[E] = new_alg(" U xx UUU xxyyy "); + equiv_alg[E2] = new_alg(" UU xx UU xxyy "); + equiv_alg[E3] = new_alg(" UUU xx U xxy "); + + equiv_alg[x] = new_alg(" x "); + equiv_alg[x2] = new_alg(" xx "); + equiv_alg[x3] = new_alg(" xxx "); + equiv_alg[y] = new_alg(" y "); + equiv_alg[y2] = new_alg(" yy "); + equiv_alg[y3] = new_alg(" yyy "); + equiv_alg[z] = new_alg(" yyy x y "); + equiv_alg[z2] = new_alg(" yy xx "); + equiv_alg[z3] = new_alg(" y x yyy "); +} + +static void +init_steps() +{ + /* PruneData */ + pd_eofb_HTM.filename = "ptable_eofb_HTM"; + pd_eofb_HTM.size = POW2TO11; + pd_eofb_HTM.index = index_eofb; + pd_eofb_HTM.moveset = moveset_HTM; + + pd_coud_HTM.filename = "ptable_coud_HTM"; + pd_coud_HTM.size = POW3TO7; + pd_coud_HTM.index = index_coud; + pd_coud_HTM.moveset = moveset_HTM; + + pd_corners_HTM.filename = "ptable_corners_HTM"; + pd_corners_HTM.size = POW3TO7 * FACTORIAL8; + pd_corners_HTM.index = index_corners; + pd_corners_HTM.moveset = moveset_HTM; + + pd_ep_HTM.filename = "ptable_ep_HTM"; + pd_ep_HTM.size = FACTORIAL12; + pd_ep_HTM.index = index_ep; + pd_ep_HTM.moveset = moveset_HTM; + + pd_drud_HTM.filename = "ptable_drud_HTM"; + pd_drud_HTM.size = POW2TO11 * POW3TO7 * BINOM12ON4; + pd_drud_HTM.index = index_drud; + pd_drud_HTM.moveset = moveset_HTM; + + + /* Actual steps */ + eofb_HTM.check = check_eofb_HTM; + eofb_HTM.ready = check_nothing; + eofb_HTM.pre_trans = uf; + eofb_HTM.moveset = moveset_HTM; + + eorl_HTM.check = check_eofb_HTM; + eorl_HTM.ready = check_nothing; + eorl_HTM.pre_trans = ur; + eorl_HTM.moveset = moveset_HTM; + + eoud_HTM.check = check_eofb_HTM; + eoud_HTM.ready = check_nothing; + eoud_HTM.pre_trans = bu; + eoud_HTM.moveset = moveset_HTM; + + + coud_HTM.check = check_coud_HTM; + coud_HTM.ready = check_nothing; + coud_HTM.pre_trans = uf; + coud_HTM.moveset = moveset_HTM; + + corl_HTM.check = check_coud_HTM; + corl_HTM.ready = check_nothing; + corl_HTM.pre_trans = rf; + corl_HTM.moveset = moveset_HTM; + + cofb_HTM.check = check_coud_HTM; + cofb_HTM.ready = check_nothing; + cofb_HTM.pre_trans = fd; + cofb_HTM.moveset = moveset_HTM; + + coud_URF.check = check_coud_URF; + coud_URF.ready = check_nothing; + coud_URF.pre_trans = uf; + coud_URF.moveset = moveset_URF; + + corl_URF.check = check_coud_URF; + corl_URF.ready = check_nothing; + corl_URF.pre_trans = rf; + corl_URF.moveset = moveset_URF; + + cofb_URF.check = check_coud_URF; + cofb_URF.ready = check_nothing; + cofb_URF.pre_trans = fd; + cofb_URF.moveset = moveset_URF; + + corners_HTM.check = check_corners_HTM; + corners_HTM.ready = check_nothing; + corners_HTM.pre_trans = uf; + corners_HTM.moveset = moveset_HTM; + + corners_URF.check = check_corners_URF; + corners_URF.ready = check_nothing; + corners_URF.pre_trans = uf; + corners_URF.moveset = moveset_URF; + + edges_HTM.check = check_edges_HTM; + edges_HTM.ready = check_nothing; + edges_HTM.pre_trans = uf; + edges_HTM.moveset = moveset_HTM; + + drud_HTM.check = check_drud_HTM; + drud_HTM.ready = check_nothing; + drud_HTM.pre_trans = uf; + drud_HTM.moveset = moveset_HTM; + + optimal_HTM.check = check_optimal_HTM; + optimal_HTM.ready = check_nothing; + optimal_HTM.pre_trans = uf; + optimal_HTM.moveset = moveset_HTM; +} + +static void +init_strings() +{ + strcpy(move_string [NULLMOVE], "-" ); + strcpy(move_string [U], "U" ); + strcpy(move_string [U2], "U2" ); + strcpy(move_string [U3], "U\'" ); + strcpy(move_string [D], "D" ); + strcpy(move_string [D2], "D2" ); + strcpy(move_string [D3], "D\'" ); + strcpy(move_string [R], "R" ); + strcpy(move_string [R2], "R2" ); + strcpy(move_string [R3], "R\'" ); + strcpy(move_string [L], "L" ); + strcpy(move_string [L2], "L2" ); + strcpy(move_string [L3], "L\'" ); + strcpy(move_string [F], "F" ); + strcpy(move_string [F2], "F2" ); + strcpy(move_string [F3], "F\'" ); + strcpy(move_string [B], "B" ); + strcpy(move_string [B2], "B2" ); + strcpy(move_string [B3], "B\'" ); + strcpy(move_string [Uw], "Uw" ); + strcpy(move_string [Uw2], "Uw2" ); + strcpy(move_string [Uw3], "Uw\'" ); + strcpy(move_string [Dw], "Dw" ); + strcpy(move_string [Dw2], "Dw2" ); + strcpy(move_string [Dw3], "Dw\'" ); + strcpy(move_string [Rw], "Rw" ); + strcpy(move_string [Rw2], "Rw2" ); + strcpy(move_string [Rw3], "Rw\'" ); + strcpy(move_string [Lw], "Lw" ); + strcpy(move_string [Lw2], "Lw2" ); + strcpy(move_string [Lw3], "Lw\'" ); + strcpy(move_string [Fw], "Fw" ); + strcpy(move_string [Fw2], "Fw2" ); + strcpy(move_string [Fw3], "Fw\'" ); + strcpy(move_string [Bw], "Bw" ); + strcpy(move_string [Bw2], "Bw2" ); + strcpy(move_string [Bw3], "Bw\'" ); + strcpy(move_string [M], "M" ); + strcpy(move_string [M2], "M2" ); + strcpy(move_string [M3], "M\'" ); + strcpy(move_string [S], "S" ); + strcpy(move_string [S2], "S2" ); + strcpy(move_string [S3], "S\'" ); + strcpy(move_string [E], "E" ); + strcpy(move_string [E2], "E2" ); + strcpy(move_string [E3], "E\'" ); + strcpy(move_string [x], "x" ); + strcpy(move_string [x2], "x2" ); + strcpy(move_string [x3], "x\'" ); + strcpy(move_string [y], "y" ); + strcpy(move_string [y2], "y2" ); + strcpy(move_string [y3], "y\'" ); + strcpy(move_string [z], "z" ); + strcpy(move_string [z2], "z2" ); + strcpy(move_string [z3], "z\'" ); + + strcpy(edge_string [UF], "UF" ); + strcpy(edge_string [UL], "UL" ); + strcpy(edge_string [UB], "UB" ); + strcpy(edge_string [UR], "UR" ); + strcpy(edge_string [DF], "DF" ); + strcpy(edge_string [DL], "DL" ); + strcpy(edge_string [DB], "DB" ); + strcpy(edge_string [DR], "DR" ); + strcpy(edge_string [FR], "FR" ); + strcpy(edge_string [FL], "FL" ); + strcpy(edge_string [BL], "BL" ); + strcpy(edge_string [BR], "BR" ); + + strcpy(corner_string [UFR], "UFR" ); + strcpy(corner_string [UFL], "UFL" ); + strcpy(corner_string [UBL], "UBL" ); + strcpy(corner_string [UBR], "UBR" ); + strcpy(corner_string [DFR], "DFR" ); + strcpy(corner_string [DFL], "DFL" ); + strcpy(corner_string [DBL], "DBL" ); + strcpy(corner_string [DBR], "DBR" ); + + strcpy(center_string [U_center], "U" ); + strcpy(center_string [D_center], "D" ); + strcpy(center_string [R_center], "R" ); + strcpy(center_string [L_center], "L" ); + strcpy(center_string [F_center], "F" ); + strcpy(center_string [B_center], "B" ); +} + +static void +init_trans() { + Cube aux, cube, c[3]; + CubeArray epcp; + int eparr[12], eoarr[12]; + int cparr[8], coarr[8]; + int i; + bool b1, b2, b3; + uint16_t ui; + Move mi, move; + Trans m; + + /* Compute sources */ + for (i = 0; i < NTRANS; i++) { + if (i == mirror) + cube = (Cube){0}; + else + cube = apply_alg(trans_algs[i], (Cube){0}); + + epose_source[i] = edge_slice(edge_at(cube, FR)); + eposs_source[i] = edge_slice(edge_at(cube, UR)); + eposm_source[i] = edge_slice(edge_at(cube, UF)); + eofb_source[i] = center_at(cube, F_center)/2; + eorl_source[i] = center_at(cube, R_center)/2; + eoud_source[i] = center_at(cube, U_center)/2; + coud_source[i] = center_at(cube, U_center)/2; + cofb_source[i] = center_at(cube, F_center)/2; + corl_source[i] = center_at(cube, R_center)/2; + } + + if (read_ttables_file()) + return; + + fprintf(stderr, "Cannot load %s, generating it\n", "ttables"); + + /* Initialize tables */ + for (m = 0; m < NTRANS; m++) { + if (m == mirror) { + memcpy(eparr, ep_mirror, 12 * sizeof(int)); + memcpy(cparr, cp_mirror, 8 * sizeof(int)); + } else { + epcp = (CubeArray){ .ep = eparr, .cp = cparr }; + cube = apply_alg(trans_algs[m], (Cube){0}); + cube_to_arrays(cube, &epcp, pf_epcp); + } + + 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 == mirror) + 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++) { + if (m == mirror) { + b1 = (mi >= U && mi <= Bw3); + b2 = (mi >= S && mi <= E3); + b3 = (mi >= x && mi <= z3); + if (b1 || b2 || b3) + moves_ttable[m][mi] = + inverse_move_aux[mi]; + else + moves_ttable[m][mi] = mi; + + if ((mi-1)/3==(R-1)/3 || (mi-1)/3==(Rw-1)/3) + moves_ttable[m][mi] += 3; + if ((mi-1)/3==(L-1)/3 || (mi-1)/3==(L2-1)/3) + moves_ttable[m][mi] -= 3; + } else { + aux = apply_trans(m, apply_move(mi,(Cube){0})); + for (move = 0; move < NMOVES; move++) { + cube = apply_move( + inverse_move_aux[move], aux); + if (is_solved(cube, false)) + moves_ttable[m][mi] = move; + } + } + } + } + + if (!write_ttables_file()) + fprintf(stderr, "Error writing ttables\n"); +} + +static void +init_trans_aux() +{ + ep_mirror[UF] = UF; + ep_mirror[UL] = UR; + ep_mirror[UB] = UB; + ep_mirror[UR] = UL; + ep_mirror[DF] = DF; + ep_mirror[DL] = DR; + ep_mirror[DB] = DB; + ep_mirror[DR] = DL; + ep_mirror[FR] = FL; + ep_mirror[FL] = FR; + ep_mirror[BR] = BL; + ep_mirror[BL] = BR; + + cp_mirror[UFR] = UFL; + cp_mirror[UFL] = UFR; + cp_mirror[UBL] = UBR; + cp_mirror[UBR] = UBL; + cp_mirror[DFR] = DFL; + cp_mirror[DFL] = DFR; + cp_mirror[DBL] = DBR; + cp_mirror[DBR] = DBL; + + cpos_mirror[U_center] = U_center; + cpos_mirror[D_center] = D_center; + cpos_mirror[R_center] = L_center; + cpos_mirror[L_center] = R_center; + cpos_mirror[F_center] = F_center; + cpos_mirror[B_center] = B_center; + + /* Is there a more elegant way? */ + trans_algs[uf] = new_alg(""); + trans_algs[ur] = new_alg("y"); + trans_algs[ub] = new_alg("y2"); + trans_algs[ul] = new_alg("y3"); + + trans_algs[df] = new_alg("z2"); + trans_algs[dr] = new_alg("y z2"); + trans_algs[db] = new_alg("x2"); + trans_algs[dl] = new_alg("y3 z2"); + + trans_algs[rf] = new_alg("z3"); + trans_algs[rd] = new_alg("z3 y"); + trans_algs[rb] = new_alg("z3 y2"); + trans_algs[ru] = new_alg("z3 y3"); + + trans_algs[lf] = new_alg("z"); + trans_algs[ld] = new_alg("z y3"); + trans_algs[lb] = new_alg("z y2"); + trans_algs[lu] = new_alg("z y"); + + trans_algs[fu] = new_alg("x y2"); + trans_algs[fr] = new_alg("x y"); + trans_algs[fd] = new_alg("x"); + trans_algs[fl] = new_alg("x y3"); + + trans_algs[bu] = new_alg("x3"); + trans_algs[br] = new_alg("x3 y"); + trans_algs[bd] = new_alg("x3 y2"); + trans_algs[bl] = new_alg("x3 y3"); +} + +/* Linearization functions implementation ************************************/ + +static uint64_t +index_eofb(Cube cube) +{ + return cube.eofb; +} + +static uint64_t +index_coud(Cube cube) +{ + return cube.coud; +} + +static uint64_t +index_corners(Cube cube) +{ + return cube.coud * FACTORIAL8 + cube.cp; +} + +static uint64_t +index_ep(Cube cube) +{ + uint64_t a, b, c; + + /* TODO: remove this check */ + if (epos_dependent_aux[cube.eposs/FACTORIAL4][cube.epose/FACTORIAL4] ==BINOM8ON4) + fprintf(stderr, "Impossible\n"); + + a = cube.eposs; + b = (cube.epose % FACTORIAL4) + + epos_dependent_aux[cube.eposs/FACTORIAL4][cube.epose/FACTORIAL4] * + FACTORIAL4; + c = cube.eposm % FACTORIAL4; + + b *= FACTORIAL4 * BINOM12ON4; + c *= FACTORIAL4 * BINOM12ON4 * FACTORIAL4 * BINOM8ON4; + + return a + b + c; +} + +static uint64_t +index_drud(Cube cube) +{ + uint64_t a, b, c; + + a = cube.eofb; + b = cube.coud; + c = cube.epose / FACTORIAL4; + + b *= POW2TO11; + c *= POW2TO11 * POW3TO7; + + return a + b + c; +} + +/* Step checking functions implementation ************************************/ + +static int +check_nothing(Cube cube) +{ + return true; +} + +static int +check_eofb_HTM(Cube cube) +{ + if (!pd_eofb_HTM.generated) + generate_ptable(&pd_eofb_HTM); + + return PTABLEVAL(pd_eofb_HTM.ptable, cube.eofb); +} + +static int +check_coud_HTM(Cube cube) +{ + if (!pd_coud_HTM.generated) + generate_ptable(&pd_coud_HTM); + + return PTABLEVAL(pd_coud_HTM.ptable, cube.coud); +} + +static int +check_coud_URF(Cube cube) +{ + /* TODO: I can improve this by checking first the orientation of + * the corner in DBL and use that as a reference */ + + int ud = check_coud_HTM(cube); + int rl = check_coud_HTM(apply_move(z, cube)); + int fb = check_coud_HTM(apply_move(x, cube)); + + return MIN(ud, MIN(rl, fb)); +} + +static int +check_corners_HTM(Cube cube) +{ + if (!pd_corners_HTM.generated) + generate_ptable(&pd_corners_HTM); + + return PTABLEVAL(pd_corners_HTM.ptable, index_corners(cube)); +} + +static int +check_corners_URF(Cube cube) +{ + /* TODO: I can improve this by checking first the corner in DBL + * and use that as a reference */ + + int ret = 15; + Cube c; + Trans i; + + for (i = 0; i < NROTATIONS; i++) { + c = apply_alg(trans_algs[i], cube); + ret = MIN(ret, check_corners_HTM(c)); + } + + return ret; +} + +static int +check_edges_HTM(Cube cube) +{ + int ret = 0; + + if (!pd_ep_HTM.generated) + generate_ptable(&pd_ep_HTM); + + ret = MAX(ret, PTABLEVAL(pd_ep_HTM.ptable, index_ep(cube))); + ret = MAX(ret, check_eofb_HTM(cube)); + ret = MAX(ret, check_eofb_HTM(apply_trans(ur, cube))); + ret = MAX(ret, check_eofb_HTM(apply_trans(fd, cube))); + + return ret; +} + +static int +check_drud_HTM(Cube cube) +{ + if (!pd_drud_HTM.generated) + generate_ptable(&pd_drud_HTM); + + return PTABLEVAL(pd_drud_HTM.ptable, index_drud(cube)); +} + +static int +check_optimal_HTM(Cube cube) +{ + int dr1, dr2, dr3, drmax, cor; /*ep;*/ + + if (!pd_drud_HTM.generated) + generate_ptable(&pd_drud_HTM); + if (!pd_corners_HTM.generated) + generate_ptable(&pd_corners_HTM); + /* + *if (!pd_ep_HTM.generated) + * generate_ptable(&pd_ep_HTM); + */ + + dr1 = PTABLEVAL(pd_drud_HTM.ptable, index_drud(cube)); + dr2 = PTABLEVAL(pd_drud_HTM.ptable, index_drud(apply_trans(rf, cube))); + dr3 = PTABLEVAL(pd_drud_HTM.ptable, index_drud(apply_trans(fd, cube))); + + drmax = MAX(dr1, MAX(dr2, dr3)); + if (dr1 == dr2 && dr2 == dr3 && dr1 != 0) + drmax++; + + cor = PTABLEVAL(pd_corners_HTM.ptable, index_corners(cube)); + /* ep = PTABLEVAL(pd_ep_HTM.ptable, index_ep(cube)); */ + + /*return MAX(drmax, MAX(ep, cor));*/ + if (drmax == 0 && cor == 0) + return is_solved(cube, false) ? 0 : 1; + return MAX(drmax, cor); +} + + +/* Movesets ******************************************************************/ + +bool +moveset_HTM(Move m) +{ + return m >= U && m <= B3; +} + +bool +moveset_URF(Move m) +{ + Move b = base_move(m); + + return b == U || b == R || b == F; +} + + +/* Public functions implementation *******************************************/ + +Cube +apply_alg(Alg *alg, Cube cube) +{ + return apply_alg_generic(alg, cube, pf_all, true); +} + +Cube +apply_move(Move m, Cube cube) +{ + Cube moved = {0}; + + moved.epose = epose_mtable[m][cube.epose]; + moved.eposs = eposs_mtable[m][cube.eposs]; + moved.eposm = eposm_mtable[m][cube.eposm]; + moved.eofb = eofb_mtable[m][cube.eofb]; + moved.eorl = eorl_mtable[m][cube.eorl]; + moved.eoud = eoud_mtable[m][cube.eoud]; + moved.coud = coud_mtable[m][cube.coud]; + moved.cofb = cofb_mtable[m][cube.cofb]; + moved.corl = corl_mtable[m][cube.corl]; + moved.cp = cp_mtable[m][cube.cp]; + moved.cpos = cpos_mtable[m][cube.cpos]; + + return moved; +} + +Cube +apply_trans(Trans t, Cube cube) +{ + Cube transformed = {0}; + uint16_t aux_epos[3] = { cube.epose, cube.eposs, cube.eposm }; + uint16_t aux_eo[3] = { cube.eoud, cube.eorl, cube.eofb }; + uint16_t aux_co[3] = { cube.coud, cube.corl, cube.cofb }; + + transformed.epose = epose_ttable[t][aux_epos[epose_source[t]]]; + transformed.eposs = eposs_ttable[t][aux_epos[eposs_source[t]]]; + transformed.eposm = eposm_ttable[t][aux_epos[eposm_source[t]]]; + transformed.eofb = eo_ttable[t][aux_eo[eofb_source[t]]]; + transformed.eorl = eo_ttable[t][aux_eo[eorl_source[t]]]; + transformed.eoud = eo_ttable[t][aux_eo[eoud_source[t]]]; + transformed.coud = co_ttable[t][aux_co[coud_source[t]]]; + transformed.corl = co_ttable[t][aux_co[corl_source[t]]]; + transformed.cofb = co_ttable[t][aux_co[cofb_source[t]]]; + transformed.cp = cp_ttable[t][cube.cp]; + transformed.cpos = cpos_ttable[t][cube.cpos]; + + return transformed; +} + +/* TODO: this has to be changed using pre-computations */ +bool +block_solved(Cube cube, Block block) +{ + CubeArray *arr = new_cubearray(cube, pf_all); + int i; + bool ret = true; + + for (i = 0; i < 12; i++) + ret = ret && !(block.edge[i] && (arr->ep[i] != i || arr->eofb[i])); + for (i = 0; i < 8; i++) + ret = ret && !(block.corner[i] && (arr->cp[i] != i || arr->coud[i])); + for (i = 0; i < 6; i++) + ret = ret && !(block.center[i] && arr->cpos[i] != i); + + free_cubearray(arr, pf_all); + + return ret; +} + +Center +center_at(Cube cube, Center c) +{ + int ret; + CubeArray *arr = new_cubearray(cube, pf_cpos); + + ret = arr->cpos[c]; + free_cubearray(arr, pf_cpos); + + return ret; +} + +Cube +compose(Cube c2, Cube c1) +{ + return compose_filtered(c2, c1, pf_all); +} + +Corner +corner_at(Cube cube, Corner c) +{ + int ret; + CubeArray *arr = new_cubearray(cube, pf_cp); + + ret = arr->cp[c]; + free_cubearray(arr, pf_cp); + + return ret; +} + +Edge +edge_at(Cube cube, Edge e) +{ + int ret; + CubeArray *arr = new_cubearray(cube, pf_ep); + + ret = arr->ep[e]; + free_cubearray(arr, pf_ep); + + return ret; +} + +bool +equal(Cube c1, Cube c2) +{ + 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 *arr = new_cubearray(cube, pf_all); + CubeArray *inv = new_cubearray((Cube){0}, pf_all); + Cube ret; + int i; + + for (i = 0; i < 12; i++) { + inv->ep[arr->ep[i]] = i; + inv->eofb[arr->ep[i]] = arr->eofb[i]; + inv->eorl[arr->ep[i]] = arr->eorl[i]; + inv->eoud[arr->ep[i]] = arr->eoud[i]; + } + + for (i = 0; i < 8; i++) { + inv->cp[arr->cp[i]] = i; + inv->coud[arr->cp[i]] = (3 - arr->coud[i]) % 3; + inv->corl[arr->cp[i]] = (3 - arr->corl[i]) % 3; + inv->cofb[arr->cp[i]] = (3 - arr->cofb[i]) % 3; + } + + for (int i = 0; i < 6; i++) + inv->cpos[arr->cpos[i]] = i; + + ret = arrays_to_cube(inv, pf_all); + free_cubearray(arr, pf_all); + free_cubearray(inv, pf_all); + + return ret; +} + +Move +inverse_move(Move m) +{ + return inverse_move_aux[m]; +} + +Trans +inverse_trans(Trans t) +{ + return inverse_trans_aux[t]; +} + +bool +is_admissible(Cube cube) +{ + /* TODO: this should check consistency of different orientations */ + /* TODO: check that centers are opposite and admissible */ + + CubeArray *a = new_cubearray(cube, pf_all); + int parity; + bool perm; + + 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); + + return perm && parity % 2 == 0; +} + +bool +is_solved(Cube cube, bool reorient) +{ + Trans i; + + if (reorient) + for (i = 0; i < NROTATIONS; i++) + if (is_solved(apply_alg(trans_algs[i],cube), false)) + return true; + + return equal(cube, (Cube){0}); +} + +int +piece_orientation(Cube cube, int piece, char *orientation) +{ + int arr[12], n, b; + uint16_t 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) +{ + CubeArray *arr = new_cubearray(cube, pf_all); + + for (int i = 0; i < 12; i++) + printf(" %s ", edge_string[arr->ep[i]]); + printf("\n"); + + for (int i = 0; i < 12; i++) + printf(" %c ", arr->eofb[i] + '0'); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf("%s ", corner_string[arr->cp[i]]); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf(" %c ", arr->coud[i] + '0'); + printf("\n"); + + for (int i = 0; i < 6; i++) + printf(" %s ", center_string[arr->cpos[i]]); + printf("\n"); + + free_cubearray(arr, pf_all); +} + +Cube +random_cube() +{ + CubeArray *arr = new_cubearray((Cube){0}, pf_4val); + Cube ret; + int ep, cp, eo, co; + + ep = rand() % FACTORIAL12; + cp = rand() % FACTORIAL8; + eo = rand() % POW2TO11; + co = rand() % POW3TO7; + + index_to_perm(ep, 12, arr->ep); + index_to_perm(cp, 8, arr->cp); + int_to_sum_zero_array(eo, 2, 12, arr->eofb); + int_to_sum_zero_array(co, 3, 8, arr->coud); + + if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8)) + swap(&(arr->ep[0]), &(arr->ep[1])); + + ret = arrays_to_cube(arr, pf_4val); + free_cubearray(arr, pf_4val); + + return ret; +} + +AlgList * +solve(Cube cube, Step step, SolveOptions *opts) +{ + AlgListNode *node; + AlgList *sols = new_alglist(); + Cube c = apply_trans(step.pre_trans, cube); + DfsData dd = { + .m = 0, + .niss = false, + .last1 = NULLMOVE, + .last2 = NULLMOVE, + .sols = sols, + .current_alg = new_alg("") + }; + + if (step.ready != NULL && !step.ready(c)) + return sols; + + moveset_to_list(step.moveset, step.check, dd.sorted_moves); + + for (dd.d = MAX(opts->min_moves, step.check(c)); + dd.d <= opts->max_moves && !(sols->len && opts->optimal_only); + dd.d++) { + solve_dfs(c, step, opts, &dd); + if (opts->feedback) + fprintf(stderr, + "Depth %d completed, found %d solutions\n", + dd.d, sols->len); + } + + for (node = sols->first; node != NULL; node = node->next) + transform_alg(inverse_trans_aux[step.pre_trans], node->alg); + + return sols; +} + +Alg * +inverse_alg(Alg *alg) +{ + Alg *ret = new_alg(""); + AlgNode *i; + + for (i = alg->last; i != NULL; i = i->prev) + append_move(ret, i->m, i->inverse); + + return ret; +} + +Alg * +new_alg(char *str) +{ + Alg *alg = malloc(sizeof(Alg)); + int i; + bool niss = false; + Move j, m; + + alg->first = NULL; + alg->last = NULL; + alg->len = 0; + + for (i = 0; str[i]; i++) { + if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n') + continue; + + if (str[i] == '(' && niss) { + fprintf(stderr, "Error reading moves: nested ( )\n"); + return alg; + } + + if (str[i] == ')' && !niss) { + fprintf(stderr, "Error reading moves: unmatched )\n"); + return alg; + } + + if (str[i] == '(' || str[i] == ')') { + niss = !niss; + continue; + } + + for (j = 0; j < NMOVES; j++) { + if (str[i] == move_string[j][0]) { + m = j; + if (m <= B && str[i+1]=='w') { + m += Uw - U; + i++; + } + if (str[i+1]=='2') { + m += 1; + i++; + } else if (str[i+1]=='\'' || str[i+1]=='3') { + m += 2; + i++; + } + append_move(alg, m, niss); + break; + } + } + } + + return alg; +} + +Alg * +on_inverse(Alg *alg) +{ + Alg *ret = new_alg(""); + AlgNode *i; + + for (i = alg->first; i != NULL; i = i->next) + append_move(ret, i->m, !i->inverse); + + return ret; +} + +void +print_alg(Alg *alg, bool l) +{ + char fill[4]; + AlgNode *i; + bool niss = false; + + for (i = alg->first; i != NULL; i = i->next) { + if (!niss && i->inverse) + strcpy(fill, i == alg->first ? "(" : " ("); + if (niss && !i->inverse) + strcpy(fill, ") "); + if (niss == i->inverse) + strcpy(fill, i == alg->first ? "" : " "); + + printf("%s%s", fill, move_string[i->m]); + niss = i->inverse; + } + + if (niss) + printf(")"); + if (l) + printf(" (%d)", alg->len); + + printf("\n"); +} + +void +print_ptable(PruneData *pd) +{ + uint64_t i, a[16]; + + memset(a, 0, 16 * sizeof(uint64_t)); + + if (!pd->generated) + generate_ptable(pd); + + for (i = 0; i < pd->size; i++) + a[PTABLEVAL(pd->ptable, i)]++; + + fprintf(stderr, "Values for table %s\n", pd->filename); + for (i = 0; i < 16; i++) + printf("%2lu\t%10lu\n", i, a[i]); +} + +void +print_alglist(AlgList *al, bool l) +{ + AlgListNode *i; + + for (i = al->first; i != NULL; i = i->next) + print_alg(i->alg, l); +} + +void +remove_last_move(Alg *alg) +{ + AlgNode *newlast = alg->last->prev; + free(alg->last); + if (newlast != NULL) + newlast->next = NULL; + alg->last = newlast; + alg->len--; +} + +void +transform_alg(Trans t, Alg *alg) +{ + AlgNode *i; + + for (i = alg->first; i != NULL; i = i->next) + i->m = moves_ttable[t][i->m]; +} + + +void +init() +{ + /* Order is important! */ + init_environment(); + init_strings(); + init_moves_aux(); + init_moves(); + init_auxtables(); + init_trans_aux(); + init_trans(); + init_steps(); +} + + diff --git a/old/2021-06-14-oldalg/cube.h b/old/2021-06-14-oldalg/cube.h new file mode 100644 index 0000000..a17c291 --- /dev/null +++ b/old/2021-06-14-oldalg/cube.h @@ -0,0 +1,73 @@ +#ifndef CUBE_H +#define CUBE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include "cubetypes.h" + +/* Steps *********************************************************************/ + +extern Step eofb_HTM; +extern Step eorl_HTM; +extern Step eoud_HTM; +extern Step coud_HTM; +extern Step corl_HTM; +extern Step cofb_HTM; +extern Step coud_URF; +extern Step corl_URF; +extern Step cofb_URF; +extern Step corners_HTM; +extern Step corners_URF; +extern Step edges_HTM; +extern Step drud_HTM; +extern Step optimal_HTM; + +extern PruneData pd_eofb_HTM; +extern PruneData pd_coud_HTM; +extern PruneData pd_corners_HTM; +extern PruneData pd_ep_HTM; +extern PruneData pd_drud_HTM; + +/* Public functions **********************************************************/ + +Cube apply_alg(Alg *alg, Cube cube); +Cube apply_move(Move m, Cube cube); +Cube apply_trans(Trans t, Cube cube); +bool block_solved(Cube cube, Block); +Center center_at(Cube cube, Center c); +Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */ +Corner corner_at(Cube cube, Corner c); +Edge edge_at(Cube cube, Edge e); +bool equal(Cube c1, Cube c2); +Cube inverse_cube(Cube cube); +Move inverse_move(Move m); +Trans inverse_trans(Trans t); +bool is_admissible(Cube cube); +bool is_solved(Cube cube, bool reorient); +int piece_orientation(Cube cube, int piece, char *orientation); +void print_cube(Cube cube); +Cube random_cube(); +AlgList * solve(Cube cube, Step step, SolveOptions *opts); + +void free_alg(Alg *alg); +void free_alglist(AlgList *l); +Alg * inverse_alg(Alg *alg); +Alg * new_alg(char *str); +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 transform_alg(Trans t, Alg *alg); + +void print_ptable(PruneData *pd); + +void init(); + +#endif + diff --git a/old/2021-06-14-oldalg/cubetypes.h b/old/2021-06-14-oldalg/cubetypes.h new file mode 100644 index 0000000..292fbb7 --- /dev/null +++ b/old/2021-06-14-oldalg/cubetypes.h @@ -0,0 +1,210 @@ +/* Typedefs ******************************************************************/ + +typedef enum center Center; +typedef enum corner Corner; +typedef enum edge Edge; +typedef enum move Move; +typedef enum trans Trans; + +typedef struct alg Alg; +typedef struct algnode AlgNode; +typedef struct alglist AlgList; +typedef struct alglistnode AlgListNode; +typedef struct block Block; +typedef struct cube Cube; +typedef struct cubearray CubeArray; +typedef struct dfsdata DfsData; +typedef struct piecefilter PieceFilter; +typedef struct prunedata PruneData; +typedef struct solveoptions SolveOptions; +typedef struct step Step; + +/* Enums *********************************************************************/ + +enum +center +{ + U_center, D_center, + R_center, L_center, + F_center, B_center +}; + +enum +corner +{ + UFR, UFL, UBL, UBR, + DFR, DFL, DBL, DBR +}; + +enum +edge +{ + UF, UL, UB, UR, + DF, DL, DB, DR, + FR, FL, BL, BR +}; + +enum +move +{ + NULLMOVE, + U, U2, U3, D, D2, D3, + R, R2, R3, L, L2, L3, + F, F2, F3, B, B2, B3, + Uw, Uw2, Uw3, Dw, Dw2, Dw3, + Rw, Rw2, Rw3, Lw, Lw2, Lw3, + Fw, Fw2, Fw3, Bw, Bw2, Bw3, + M, M2, M3, + S, S2, S3, + E, E2, E3, + x, x2, x3, + y, y2, y3, + z, z2, z3, +}; + +enum +trans +{ + uf, ur, ub, ul, + df, dr, db, dl, + rf, rd, rb, ru, + lf, ld, lb, lu, + fu, fr, fd, fl, + bu, br, bd, bl, + mirror, /* R|L */ +}; + + +/* Structs *******************************************************************/ + +struct +alg +{ + AlgNode * first; + AlgNode * last; + int len; +}; + +struct +algnode +{ + Move m; + bool inverse; + AlgNode * next; + AlgNode * prev; +}; + +struct +alglist +{ + AlgListNode * first; + AlgListNode * last; + int len; +}; + +struct +alglistnode +{ + Alg * alg; + AlgListNode * next; +}; + +struct +block +{ + bool edge[12]; + bool corner[8]; + bool center[6]; +}; + +struct +cube +{ + uint16_t epose; + uint16_t eposs; + uint16_t eposm; + uint16_t eofb; + uint16_t eorl; + uint16_t eoud; + uint16_t cp; + uint16_t coud; + uint16_t cofb; + uint16_t corl; + uint16_t cpos; +}; + +struct +cubearray +{ + int * ep; + int * eofb; + int * eorl; + int * eoud; + int * cp; + int * coud; + int * corl; + int * cofb; + int * cpos; +}; + +struct +dfsdata +{ + int d; + int m; + bool niss; + Move last1; + Move last2; + AlgList * sols; + Alg * current_alg; + Move sorted_moves[z3+1]; +}; + +struct +piecefilter +{ + 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; + uint8_t * ptable; + uint8_t * reached; + bool generated; + uint64_t n; + uint64_t size; + uint64_t (*index)(Cube); + bool (*moveset)(Move); +}; + +struct +solveoptions +{ + int min_moves; + int max_moves; + int max_solutions; + bool optimal_only; + bool can_niss; + bool feedback; +}; + +struct +step +{ + int (*check)(Cube); + int (*ready)(Cube); + bool (*moveset)(Move); + Trans pre_trans; +}; diff --git a/old/2021-06-14-oldalg/main.c b/old/2021-06-14-oldalg/main.c new file mode 100644 index 0000000..445eefc --- /dev/null +++ b/old/2021-06-14-oldalg/main.c @@ -0,0 +1,56 @@ +#include +#include "cube.h" + +int main() { + Alg *algo; + AlgList *sols; + Cube cube; + SolveOptions opts; + char line[1000]; + int i, ns = 2, nrand = 100000, sum; + + Step *stps[20] = {&drud_HTM, &optimal_HTM}; + char sss[30][30] = {"DR on U/D", "Optimal solution"}; + + opts = (SolveOptions) { + .min_moves = 0, + .max_moves = 20, + .optimal_only = true, + .max_solutions = 1, + .can_niss = false, + .feedback = true + }; + + init(); + +/* + print_ptable(&pd_drud_HTM); + print_ptable(&pd_ep_HTM); + print_ptable(&pd_corners_HTM); +*/ + + srand(time(NULL)); + sum = 0; + for (i = 0; i < nrand; i++) + sum += optimal_HTM.check(random_cube()); + printf("Average pruning value: %lf\n", ((double)sum) / ((double) nrand)); + + printf("Welcome to nissy 2.0! Insert a scramble:\n"); + + if (fgets(line, 1000, stdin) != NULL) { + algo = new_alg(line); + cube = apply_alg(algo, (Cube){0}); + + for (i = 0; i < ns; i++) { + if (stps[i]->check == NULL) + fprintf(stderr, "Check function for step %d is null\n", i); + sols = solve(cube, *stps[i], &opts); + printf("%s: %d solutions found:\n", sss[i], sols->len); + print_alglist(sols, true); + free_alglist(sols); + } + free(algo); + } + + return 0; +} diff --git a/old/2021-06-15-before-separating-steps/cube.c b/old/2021-06-15-before-separating-steps/cube.c new file mode 100644 index 0000000..06c829b --- /dev/null +++ b/old/2021-06-15-before-separating-steps/cube.c @@ -0,0 +1,2836 @@ +#include "cube.h" + +/* Constants and macros *****************************************************/ + +#define POW2TO11 2048ULL +#define POW2TO12 4096ULL +#define POW3TO7 2187ULL +#define POW3TO8 6561ULL +#define FACTORIAL4 24ULL +#define FACTORIAL6 720ULL +#define FACTORIAL8 40320ULL +#define FACTORIAL12 479001600ULL +#define BINOM12ON4 495ULL +#define BINOM8ON4 70ULL +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +#define BASEALGLEN 50 +#define NMOVES (z3+1) +#define NTRANS (mirror+1) +#define NROTATIONS (NTRANS-1) +#define PTABLESIZE(n) ((n+1) / 2) +#define PTABLEVAL(tab,ind) (((ind)%2) ? (tab[(ind)/2] / 16) : \ + (tab[(ind)/2] % 16)) + + +/* Local functions **********************************************************/ + +static Cube admissible_ep(Cube cube, PieceFilter f); +static void append_alg(AlgList *l, Alg *alg); +static void append_move(Alg *alg, Move m, bool inverse); +static Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a); +static void apply_permutation(int *perm, int *set, int n); +static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f); +static uint16_t array_ep_to_epos(int *ep, int *eps_solved); +static Cube arrays_to_cube(CubeArray *arr, PieceFilter f); +static Move base_move(Move m); +static int binomial(int n, int k); +static Cube compose_filtered(Cube c2, Cube c1, PieceFilter f); +static void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f); +static int digit_array_to_int(int *a, int n, int b); +static int edge_slice(Edge e); /* E=0, S=1, M=2 */ +static int epos_dependent(int pos1, int pos2); +static uint16_t epos_from_arrays(int *epos, int *ep); +static void epos_to_partial_ep(uint16_t epos, int *ep, int *ss); +static int factorial(int n); +static void free_alglistnode(AlgListNode *aln); +static void free_cubearray(CubeArray *arr, PieceFilter f); +static void generate_ptable(PruneData *pd); +static void generate_ptable_dfs(Cube c, PruneData *pd, DfsData *dd); +static void index_to_perm(int p, int n, int *r); +static void index_to_subset(int s, int n, int k, int *r); +static void int_to_digit_array(int a, int b, int n, int *r); +static void int_to_sum_zero_array(int x, int b, int n, int *a); +static int invert_digits(int a, int b, int n); +static bool is_perm(int *a, int n); +static bool is_subset(int *a, int n, int k); +static Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf); +static void moveset_to_list(bool (*ms)(Move), int (*f)(Cube), Move *r); +static AlgList * new_alglist(); +static CubeArray * new_cubearray(Cube cube, PieceFilter f); +static int perm_sign(int *a, int n); +static int perm_to_index(int *a, int n); +static int powint(int a, int b); +static void ptable_set_reached(PruneData *pd, uint64_t ind); +static void ptable_update(PruneData *pd, uint64_t ind, int m); +static bool read_ptable_file(PruneData *pd); +static bool read_ttables_file(); +static bool read_mtables_file(); +static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f); +static void solve_dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static int subset_to_index(int *a, int n, int k); +static void sum_arrays_mod(int *src, int *dst, int n, int m); +static void swap(int *a, int *b); +static bool write_ptable_file(PruneData *pd); +static bool write_ttables_file(); +static bool write_mtables_file(); + +static void init_auxtables(); +static void init_environment(); +static void init_moves(); +static void init_moves_aux(); +static void init_steps(); +static void init_strings(); +static void init_trans(); +static void init_trans_aux(); + +static bool moveset_HTM(Move m); +static bool moveset_URF(Move m); + +/* Steps and related functions and data **************************************/ + +Step eofb_HTM; +Step eorl_HTM; +Step eoud_HTM; +Step coud_HTM; +Step corl_HTM; +Step cofb_HTM; +Step coud_URF; +Step corl_URF; +Step cofb_URF; +Step corners_HTM; +Step corners_URF; +Step edges_HTM; +Step drud_HTM; +Step optimal_HTM; + +PruneData pd_eofb_HTM; +PruneData pd_coud_HTM; +PruneData pd_corners_HTM; +PruneData pd_ep_HTM; +PruneData pd_drud_HTM; + +static uint64_t index_eofb(Cube cube); +static uint64_t index_coud(Cube cube); +static uint64_t index_corners(Cube cube); +static uint64_t index_ep(Cube cube); +static uint64_t index_drud(Cube cube); + +static int check_nothing(Cube cube); +static int check_eofb_HTM(Cube cube); +static int check_coud_HTM(Cube cube); +static int check_coud_URF(Cube cube); +static int check_corners_HTM(Cube cube); +static int check_corners_URF(Cube cube); +static int check_edges_HTM(Cube cube); +static int check_drud_HTM(Cube cube); +static int check_optimal_HTM(Cube cube); + +/* All sorts of useful costants and tables **********************************/ + +static char * tabledir; + +static PieceFilter pf_all; +static PieceFilter pf_4val; +static PieceFilter pf_epcp; +static PieceFilter pf_cpos; +static PieceFilter pf_cp; +static PieceFilter pf_ep; +static PieceFilter pf_e; +static PieceFilter pf_s; +static PieceFilter pf_m; +static PieceFilter pf_eo; +static PieceFilter pf_co; + +static int epe_solved[4]; +static int eps_solved[4]; +static int epm_solved[4]; + +static char move_string[NMOVES][7]; +static char edge_string[12][7]; +static char corner_string[8][7]; +static char center_string[6][7]; + +static bool commute[NMOVES][NMOVES]; +static bool possible_next[NMOVES][NMOVES][NMOVES]; +static Move inverse_move_aux[NMOVES]; +static Trans inverse_trans_aux[NTRANS]; +static int epos_dependent_aux[BINOM12ON4][BINOM12ON4]; + +static uint16_t epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static uint16_t eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static uint16_t eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static uint16_t eo_ttable[NTRANS][POW2TO11]; +static uint16_t cp_ttable[NTRANS][FACTORIAL8]; +static uint16_t co_ttable[NTRANS][POW3TO7]; +static uint16_t cpos_ttable[NTRANS][FACTORIAL6]; +static Move moves_ttable[NTRANS][NMOVES]; + +static uint16_t epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static uint16_t eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static uint16_t eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static uint16_t eofb_mtable[NMOVES][POW2TO11]; +static uint16_t eorl_mtable[NMOVES][POW2TO11]; +static uint16_t eoud_mtable[NMOVES][POW2TO11]; +static uint16_t cp_mtable[NMOVES][FACTORIAL8]; +static uint16_t coud_mtable[NMOVES][POW3TO7]; +static uint16_t cofb_mtable[NMOVES][POW3TO7]; +static uint16_t corl_mtable[NMOVES][POW3TO7]; +static uint16_t cpos_mtable[NMOVES][FACTORIAL6]; + +static uint64_t me[12]; + +static int edge_cycle[NMOVES][12]; +static int corner_cycle[NMOVES][8]; +static int center_cycle[NMOVES][6]; +static int eofb_flipped[NMOVES][12]; +static int eorl_flipped[NMOVES][12]; +static int eoud_flipped[NMOVES][12]; +static int coud_flipped[NMOVES][8]; +static int corl_flipped[NMOVES][8]; +static int cofb_flipped[NMOVES][8]; +static Alg * equiv_alg[NMOVES]; + +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]; +static int ep_mirror[12]; +static int cp_mirror[8]; +static int cpos_mirror[6]; +static Alg * trans_algs[NROTATIONS]; + + +/* Local functions implementation ********************************************/ + +static 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 < 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; +} + +static void +append_alg(AlgList *l, Alg *alg) +{ + AlgListNode *node = malloc(sizeof(AlgListNode)); + int i; + + node->alg = new_alg(""); + for (i = 0; i < alg->len; i++) + append_move(node->alg, alg->move[i], alg->inv[i]); + node->next = NULL; + + if (++l->len == 1) + l->first = node; + else + l->last->next = node; + l->last = node; +} + +static void +append_move(Alg *alg, Move m, bool inverse) +{ + if (alg->len == alg->allocated) { + if (alg->len > 1000000) { + fprintf(stderr, "Warning: very long alg,"); + fprintf(stderr, "something might be wrong.\n"); + } + alg->move = realloc(alg->move, 2 * alg->len * sizeof(Move)); + alg->inv = realloc(alg->inv, 2 * alg->len * sizeof(bool)); + alg->allocated *= 2; + } + + alg->move[alg->len] = m; + alg->inv [alg->len] = inverse; + alg->len++; +} + +static Cube +apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a) +{ + Cube ret = {0}; + int i; + + for (i = 0; i < alg->len; i++) + if (alg->inv[i]) + ret = a ? apply_move(alg->move[i], ret) : + apply_move_cubearray(alg->move[i], ret, f); + + ret = compose_filtered(c, inverse_cube(ret), f); + + for (i = 0; i < alg->len; i++) + if (!alg->inv[i]) + ret = a ? apply_move(alg->move[i], ret) : + apply_move_cubearray(alg->move[i], ret, f); + + return ret; +} + +static void +apply_permutation(int *perm, int *set, int n) +{ + int *aux = malloc(n * sizeof(int)); + int i; + + if (!is_perm(perm, n)) + return; + + for (i = 0; i < n; i++) + aux[i] = set[perm[i]]; + + memcpy(set, aux, n * sizeof(int)); + free(aux); +} + +static Cube +apply_move_cubearray(Move m, Cube cube, PieceFilter f) +{ + 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); +} + +static uint16_t +array_ep_to_epos(int *ep, int *ss) +{ + 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 epos_from_arrays(epos, eps); +} + +static Cube +arrays_to_cube(CubeArray *arr, PieceFilter f) +{ + Cube ret = {0}; + + 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; +} + +static Move +base_move(Move m) +{ + if (m == NULLMOVE) + return NULLMOVE; + else + return m - (m-1)%3; +} + +static int +binomial(int n, int k) +{ + if (n < 0 || k < 0 || k > n) + return 0; + + return factorial(n) / (factorial(k) * factorial(n-k)); +} + +static Cube +compose_filtered(Cube c2, Cube c1, PieceFilter f) +{ + CubeArray *arr = new_cubearray(c2, f); + Cube ret; + + ret = move_via_arrays(arr, c1, f); + free_cubearray(arr, f); + + return ret; +} + +static void +cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f) +{ + int i; + + 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); +} + +static int +digit_array_to_int(int *a, int n, int b) +{ + int i, ret = 0, p = 1; + + for (i = 0; i < n; i++, p *= b) + ret += a[i] * p; + + return ret; +} + +static int +edge_slice(Edge e) { + if (e < 0 || e > 11) + return -1; + + if (e == FR || e == FL || e == BL || e == BR) + return 0; + if (e == UR || e == UL || e == DR || e == DL) + return 1; + + return 2; +} + +static int +epos_dependent(int poss, int pose) +{ + int ep[12] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; + int ep8[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + int i, j; + + epos_to_partial_ep(poss*FACTORIAL4, ep, eps_solved); + epos_to_partial_ep(pose*FACTORIAL4, ep, epe_solved); + + for (i = 0, j = 0; i < 12; i++) + if (edge_slice(ep[i]) != 1) + ep8[j++] = (edge_slice(ep[i]) == 0) ? 1 : 0; + + return subset_to_index(ep8, 8, 4); +} + +static uint16_t +epos_from_arrays(int *epos, int *ep) +{ + return FACTORIAL4 * subset_to_index(epos,12,4) + perm_to_index(ep,4); +} + +static void +epos_to_partial_ep(uint16_t epos, int *ep, int *ss) +{ + 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++]]; +} + +static int +factorial(int n) +{ + int i, ret = 1; + + if (n < 0) + return 0; + + for (i = 1; i <= n; i++) + ret *= i; + + return ret; +} + +void +free_alg(Alg *alg) +{ + free(alg->move); + free(alg->inv); + free(alg); +} + +void +free_alglist(AlgList *l) +{ + AlgListNode *aux, *i = l->first; + + while (i != NULL) { + aux = i->next; + free_alglistnode(i); + i = aux; + } + free(l); +} + +void +free_alglistnode(AlgListNode *aln) +{ + free_alg(aln->alg); + free(aln); +} + +static void +free_cubearray(CubeArray *arr, PieceFilter f) +{ + 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); +} + +static void +generate_ptable(PruneData *pd) +{ + uint64_t j; + DfsData dd; + + if (pd->generated) + return; + + /* TODO: check if memory is enough, otherwise maybe crash gracefully? */ + pd->ptable = malloc(PTABLESIZE(pd->size) * sizeof(uint8_t)); + + if (read_ptable_file(pd)) { + pd->generated = true; + return; + } + + fprintf(stderr, "Cannot load %s, generating it\n", pd->filename); + + dd.m = 0; + dd.last1 = NULLMOVE; + dd.last2 = NULLMOVE; + + /* We use 4 bits per value, so any distance >= 15 is set to 15 */ + for (j = 0; j < pd->size; j++) + ptable_update(pd, j, 15); + + moveset_to_list(pd->moveset, NULL, dd.sorted_moves); + + pd->reached = malloc(PTABLESIZE(pd->size) * sizeof(uint8_t)); + for (dd.d = 0, pd->n = 0; dd.d < 15 && pd->n < pd->size; dd.d++) { + memset(pd->reached, 0, PTABLESIZE(pd->size)*sizeof(uint8_t)); + generate_ptable_dfs((Cube){0}, pd, &dd); + fprintf(stderr, "Depth %d completed, generated %lu/%lu\n", + dd.d, pd->n, pd->size); + } + + if (!write_ptable_file(pd)) + fprintf(stderr, "Error writing ptable file\n"); + + pd->generated = true; + free(pd->reached); +} + +static void +generate_ptable_dfs(Cube c, PruneData *pd, DfsData *dd) +{ + uint64_t ind = pd->index(c); + int oldval = PTABLEVAL(pd->ptable, ind); + Move i, move, l1 = dd->last1, l2 = dd->last2; + + if (oldval < dd->m || PTABLEVAL(pd->reached, ind) || pd->n == pd->size) + return; + + ptable_set_reached(pd, ind); + + if (dd->m == dd->d) { + if (dd->m < oldval) + ptable_update(pd, ind, dd->m); + return; + } + + dd->m++; + dd->last2 = dd->last1; + + for (i = 0; dd->sorted_moves[i] != NULLMOVE; i++) { + move = dd->sorted_moves[i]; + if (possible_next[l2][l1][move]) { + dd->last1 = move; + generate_ptable_dfs(apply_move(move, c), pd, dd); + } + } + + dd->m--; + dd->last1 = l1; + dd->last2 = l2; +} + +static void +index_to_perm(int p, int n, int *r) +{ + int *a = malloc(n * sizeof(int)); + int i, j, c; + + for (i = 0; i < n; i++) + a[i] = 0; + + if (p < 0 || p >= factorial(n)) + for (i = 0; i < n; i++) + r[i] = -1; + + for (i = 0; i < n; i++) { + c = 0; + j = 0; + while (c <= p / factorial(n-i-1)) + c += a[j++] ? 0 : 1; + r[i] = j-1; + a[j-1] = 1; + p %= factorial(n-i-1); + } + + free(a); +} + +static void +index_to_subset(int s, int n, int k, int *r) +{ + int i, j, v; + + if (s < 0 || s >= binomial(n, k)) { + for (i = 0; i < n; i++) + r[i] = -1; + return; + } + + for (i = 0; i < n; i++) { + if (k == n-i) { + for (j = i; j < n; j++) + r[j] = 1; + return; + } + + if (k == 0) { + for (j = i; j < n; j++) + r[j] = 0; + return; + } + + v = binomial(n-i-1, k); + if (s >= v) { + r[i] = 1; + k--; + s -= v; + } else { + r[i] = 0; + } + } +} + +static void +int_to_digit_array(int a, int b, int n, int *r) +{ + int i; + + if (b <= 1) + for (i = 0; i < n; i++) + r[i] = 0; + else + for (i = 0; i < n; i++, a /= b) + r[i] = a % b; +} + +static void +int_to_sum_zero_array(int x, int b, int n, int *a) +{ + int i, s = 0; + + if (b <= 1) { + for (i = 0; i < n; i++) + a[i] = 0; + } else { + int_to_digit_array(x, b, n-1, a); + for (i = 0; i < n - 1; i++) + s = (s + a[i]) % b; + a[n-1] = (b - s) % b; + } +} + +static int +invert_digits(int a, int b, int n) +{ + int i, ret, *r = malloc(n * sizeof(int)); + + int_to_digit_array(a, b, n, r); + for (i = 0; i < n; i++) + r[i] = (b-r[i]) % b; + + ret = digit_array_to_int(r, n, b); + free(r); + return ret; +} + +static bool +is_perm(int *a, int n) +{ + int *aux = malloc(n * sizeof(int)); + int i; + + for (i = 0; i < n; i++) + if (a[i] < 0 || a[i] >= n) + return false; + else + aux[a[i]] = 1; + + for (i = 0; i < n; i++) + if (!aux[i]) + return false; + + free(aux); + + return true; +} + +static bool +is_subset(int *a, int n, int k) +{ + int i, sum = 0; + + for (i = 0; i < n; i++) + sum += a[i] ? 1 : 0; + + return sum == k; +} + +static Cube +move_via_arrays(CubeArray *arr, Cube c, PieceFilter f) +{ + CubeArray *arrc = new_cubearray(c, f); + Cube ret; + + 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; +} + +static void +moveset_to_list(bool (*ms)(Move m), int (*f)(Cube), Move *r) +{ + Cube c; + int b[NMOVES]; + int na = 0, nb = 0; + Move i; + + if (ms == NULL) { + fprintf(stderr, "Error: no moveset given\n"); + return; + } + + for (i = U; i < NMOVES; i++) { + if (ms(i)) { + c = apply_move(i, (Cube){0}); + if (f != NULL && f(c)) + r[na++] = i; + else + b[nb++] = i; + } + } + + memcpy(r + na, b, nb * sizeof(Move)); + r[na+nb] = NULLMOVE; +} + +static AlgList * +new_alglist() +{ + AlgList *ret = malloc(sizeof(AlgList)); + + ret->len = 0; + ret->first = NULL; + ret->last = NULL; + + return ret; +} + +static CubeArray * +new_cubearray(Cube cube, PieceFilter f) +{ + 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; +} + +static int +perm_sign(int *a, int n) +{ + int i, j, ret = 0; + + if (!is_perm(a,n)) + return -1; + + for (i = 0; i < n; i++) + for (j = i+1; j < n; j++) + ret += (a[i] > a[j]) ? 1 : 0; + + return ret % 2; +} + +static int +perm_to_index(int *a, int n) +{ + int i, j, c, ret = 0; + + if (!is_perm(a, n)) + return -1; + + for (i = 0; i < n; i++) { + c = 0; + for (j = i+1; j < n; j++) + c += (a[i] > a[j]) ? 1 : 0; + ret += factorial(n-i-1) * c; + } + + return ret; +} + +static int +powint(int a, int b) +{ + if (b < 0) + return 0; /* Truncate */ + if (b == 0) + return 1; + + if (b % 2) + return a * powint(a, b-1); + else + return powint(a*a, b/2); +} + +static void +ptable_set_reached(PruneData *pd, uint64_t ind) +{ + uint8_t oldval2 = pd->reached[ind/2]; + int other = ind % 2 ? oldval2 % 16 : oldval2 / 16; + + pd->reached[ind/2] = ind % 2 ? 16 + other : 16*other + 1; +} + +static void +ptable_update(PruneData *pd, uint64_t ind, int n) +{ + uint8_t oldval2 = pd->ptable[ind/2]; + int other = ind % 2 ? oldval2 % 16 : oldval2 / 16; + + pd->ptable[ind/2] = ind % 2 ? 16*n + other : 16*other + n; + pd->n++; +} + +static bool +read_mtables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int m, b = sizeof(uint16_t); + bool r = true; + + 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 +read_ptable_file(PruneData *pd) +{ + FILE *f; + char fname[strlen(tabledir)+100]; + uint64_t r; + + strcpy(fname, tabledir); + strcat(fname, "/"); + strcat(fname, pd->filename); + + if ((f = fopen(fname, "rb")) == NULL) + return false; + + r = fread(pd->ptable, sizeof(uint8_t), PTABLESIZE(pd->size), f); + fclose(f); + + return r == PTABLESIZE(pd->size); +} + +static bool +read_ttables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int b = sizeof(uint16_t); + bool r = true; + Move m; + + 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[6], f) == me[6]; + r = r && fread(co_ttable[m], b, me[7], f) == me[7]; + r = r && fread(cpos_ttable[m], b, me[10], f) == me[10]; + r = r && fread(moves_ttable[m], b, me[11], f) == me[11]; + } + + fclose(f); + return r; +} + +static Cube +rotate_via_compose(Trans r, Cube c, PieceFilter f) +{ + Alg *inv; + 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 + }; + + Cube ret; + + if (r != mirror) { + ret = apply_alg_generic(trans_algs[r], c, f, true); + inv = on_inverse(trans_algs[r]); + ret = apply_alg_generic(inv, ret, f, true); + free_alg(inv); + } else { + ret = move_via_arrays(&ma, (Cube){0}, f); + ret = compose_filtered(c, ret, f); + ret = move_via_arrays(&ma, ret, f); + } + + return ret; +} + +static void +solve_dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + Move move, l1 = dd->last1, l2 = dd->last2; + int i, lower_bound = s.check(c); + bool found_many, prune, niss_make_sense, nissbackup = dd->niss; + + if (opts->can_niss && !dd->niss) + lower_bound = MIN(1, lower_bound); + + found_many = dd->sols->len >= opts->max_solutions; + prune = dd->current_alg->len + lower_bound > dd->d; + if (found_many || prune) + return; + + if (lower_bound == 0) { + if (dd->current_alg->len == dd->d) + append_alg(dd->sols, dd->current_alg); + return; + } + + dd->last2 = dd->last1; + + for (i = 0; dd->sorted_moves[i] != NULLMOVE; i++) { + move = dd->sorted_moves[i]; + if (possible_next[l2][l1][move]) { + dd->last1 = move; + append_move(dd->current_alg, move, dd->niss); + solve_dfs(apply_move(move, c), s, opts, dd); + dd->current_alg->len--; + } + } + + niss_make_sense = !dd->current_alg->len || + (s.check(apply_move(l1,(Cube){0}))); + if (opts->can_niss && !dd->niss && niss_make_sense) { + dd->niss = true; + dd->last1 = NULLMOVE; + dd->last2 = NULLMOVE; + solve_dfs(inverse_cube(c), s, opts, dd); + } + + dd->last1 = l1; + dd->last2 = l2; + dd->niss = nissbackup; +} + +static int +subset_to_index(int *a, int n, int k) +{ + int i, ret = 0; + + if (!is_subset(a, n, k)) + return binomial(n, k); + + for (i = 0; i < n; i++) { + if (k == n-i) + return ret; + if (a[i]) { + ret += binomial(n-i-1, k); + k--; + } + } + + return ret; +} + +static void +sum_arrays_mod(int *src, int *dst, int n, int m) +{ + int i; + + for (i = 0; i < n; i++) + dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m; +} + +static void +swap(int *a, int *b) +{ + int aux; + + aux = *a; + *a = *b; + *b = aux; +} + +static bool +write_mtables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int m, b = sizeof(uint16_t); + bool r = true; + + 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; +} + +static bool +write_ptable_file(PruneData *pd) +{ + FILE *f; + char fname[strlen(tabledir)+100]; + uint64_t written; + + strcpy(fname, tabledir); + strcat(fname, "/"); + strcat(fname, pd->filename); + + if ((f = fopen(fname, "wb")) == NULL) + return false; + + written = fwrite(pd->ptable, sizeof(uint8_t), PTABLESIZE(pd->size), f); + fclose(f); + + return written == PTABLESIZE(pd->size); +} + +static bool +write_ttables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + bool r = true; + int b = sizeof(uint16_t); + Move m; + + 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[6], f) == me[6]; + r = r && fwrite(co_ttable[m], b, me[7], f) == me[7]; + r = r && fwrite(cpos_ttable[m], b, me[10], f) == me[10]; + r = r && fwrite(moves_ttable[m], b, me[11], f) == me[11]; + } + + fclose(f); + return r; +} + +/* Init functions implementation *********************************************/ + +static void +init_auxtables() +{ + Cube c1, c2; + uint64_t ui, uj; + int i, j, k; + bool cij, p1, p2; + + for (ui = 0; ui < BINOM12ON4; ui++) + for (uj = 0; uj < BINOM12ON4; uj++) + epos_dependent_aux[ui][uj] = epos_dependent(ui, uj); + + for (i = 0; i < NMOVES; i++) { + for (j = 0; j < NMOVES; j++) { + c1 = apply_move(i, apply_move(j, (Cube){0})); + c2 = apply_move(j, apply_move(i, (Cube){0})); + commute[i][j] = equal(c1, c2); + } + } + + for (i = 0; i < NMOVES; i++) { + for (j = 0; j < NMOVES; j++) { + for (k = 0; k < NMOVES; k++) { + p1 = j && base_move(j) == base_move(k); + p2 = i && base_move(i) == base_move(k); + cij = commute[i][j]; + possible_next[i][j][k] = !(p1 || (cij && p2)); + } + } + } + + for (i = 0; i < NMOVES; i++) + inverse_move_aux[i] = i ? i + 2 - 2*((i-1)%3) : NULLMOVE; + + /* Is there a more elegant way? */ + inverse_trans_aux[uf] = uf; + inverse_trans_aux[ur] = ul; + inverse_trans_aux[ul] = ur; + inverse_trans_aux[ub] = ub; + + inverse_trans_aux[df] = df; + inverse_trans_aux[dr] = dr; + inverse_trans_aux[dl] = dl; + inverse_trans_aux[db] = db; + + inverse_trans_aux[rf] = lf; + inverse_trans_aux[rd] = bl; + inverse_trans_aux[rb] = rb; + inverse_trans_aux[ru] = fr; + + inverse_trans_aux[lf] = rf; + inverse_trans_aux[ld] = br; + inverse_trans_aux[lb] = lb; + inverse_trans_aux[lu] = fl; + + inverse_trans_aux[fu] = fu; + inverse_trans_aux[fr] = ru; + inverse_trans_aux[fd] = bu; + inverse_trans_aux[fl] = lu; + + inverse_trans_aux[bu] = fd; + inverse_trans_aux[br] = ld; + inverse_trans_aux[bd] = bd; + inverse_trans_aux[bl] = rd; + + inverse_trans_aux[mirror] = mirror; +} + +static void +init_environment() +{ + char *nissydata = getenv("NISSYDATA"); + char *localdata = getenv("XDG_DATA_HOME"); + char *home = getenv("HOME"); + bool read, write; + + if (nissydata != NULL) { + tabledir = malloc(strlen(nissydata) * sizeof(char) + 20); + strcpy(tabledir, nissydata); + } else if (localdata != NULL) { + tabledir = malloc(strlen(localdata) * sizeof(char) + 20); + strcpy(tabledir, localdata); + strcat(tabledir, "/nissy"); + } else if (home != NULL) { + tabledir = malloc(strlen(home) * sizeof(char) + 20); + strcpy(tabledir, home); + strcat(tabledir, "/.nissy"); + } + + mkdir(tabledir, 0777); + strcat(tabledir, "/tables"); + mkdir(tabledir, 0777); + + read = !access(tabledir, R_OK); + write = !access(tabledir, W_OK); + + if (!read) { + fprintf(stderr, "Table files cannot be read.\n"); + } else if (!write) { + fprintf(stderr, "Data directory not writable: "); + fprintf(stderr, "tables can be loaded, but not saved.\n"); + } +} + +static void +init_moves() { + Cube c; + CubeArray arrs; + int i; + uint16_t ui; + Move m; + + /* 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; + + fprintf(stderr, "Cannot load %s, generating it\n", "mtables"); + + /* Initialize transition tables */ + for (m = 0; m < NMOVES; m++) { + 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; + } + } + + if (!write_mtables_file()) + fprintf(stderr, "Error writing mtables\n"); +} + +static void +init_moves_aux() +{ + /* Some standard PieceFilters */ + pf_all.epose = true; + pf_all.eposs = true; + pf_all.eposm = true; + pf_all.eofb = true; + pf_all.eorl = true; + pf_all.eoud = true; + pf_all.cp = true; + pf_all.cofb = true; + pf_all.corl = true; + pf_all.coud = true; + pf_all.cpos = true; + + pf_4val.epose = true; + pf_4val.eposs = true; + pf_4val.eposm = true; + pf_4val.eofb = true; + pf_4val.coud = true; + pf_4val.cp = true; + + pf_epcp.epose = true; + pf_epcp.eposs = true; + pf_epcp.eposm = true; + pf_epcp.cp = true; + + pf_cpos.cpos = true; + + pf_cp.cp = true; + + pf_ep.epose = true; + pf_ep.eposs = true; + pf_ep.eposm = true; + + pf_e.epose = true; + pf_s.eposs = true; + pf_m.eposm = true; + + pf_eo.eofb = true; + pf_eo.eorl = true; + pf_eo.eoud = true; + + pf_co.cofb = true; + pf_co.corl = true; + pf_co.coud = true; + + /* Used to convert to and from CubeArray */ + epe_solved[0] = FR; + epe_solved[1] = FL; + epe_solved[2] = BL; + epe_solved[3] = BR; + + eps_solved[0] = UL; + eps_solved[1] = UR; + eps_solved[2] = DL; + eps_solved[3] = DR; + + epm_solved[0] = UF; + epm_solved[1] = UB; + epm_solved[2] = DF; + epm_solved[3] = DB; + + /* Table sizes, used for reading and writing files */ + me[0] = FACTORIAL12/FACTORIAL8; + me[1] = FACTORIAL12/FACTORIAL8; + me[2] = FACTORIAL12/FACTORIAL8; + me[3] = POW2TO11; + me[4] = POW2TO11; + me[5] = POW2TO11; + me[6] = FACTORIAL8; + me[7] = POW3TO7; + me[8] = POW3TO7; + me[9] = POW3TO7; + me[10] = FACTORIAL6; + me[11] = NMOVES; + + /* Cycles *********************/ + edge_cycle[U][UF] = UR; + edge_cycle[U][UL] = UF; + edge_cycle[U][UB] = UL; + edge_cycle[U][UR] = UB; + edge_cycle[U][DF] = DF; + edge_cycle[U][DL] = DL; + edge_cycle[U][DB] = DB; + edge_cycle[U][DR] = DR; + edge_cycle[U][FR] = FR; + edge_cycle[U][FL] = FL; + edge_cycle[U][BL] = BL; + edge_cycle[U][BR] = BR; + + edge_cycle[x][UF] = DF; + edge_cycle[x][UL] = FL; + edge_cycle[x][UB] = UF; + edge_cycle[x][UR] = FR; + edge_cycle[x][DF] = DB; + edge_cycle[x][DL] = BL; + edge_cycle[x][DB] = UB; + edge_cycle[x][DR] = BR; + edge_cycle[x][FR] = DR; + edge_cycle[x][FL] = DL; + edge_cycle[x][BL] = UL; + edge_cycle[x][BR] = UR; + + edge_cycle[y][UF] = UR; + edge_cycle[y][UL] = UF; + edge_cycle[y][UB] = UL; + edge_cycle[y][UR] = UB; + edge_cycle[y][DF] = DR; + edge_cycle[y][DL] = DF; + edge_cycle[y][DB] = DL; + edge_cycle[y][DR] = DB; + edge_cycle[y][FR] = BR; + edge_cycle[y][FL] = FR; + edge_cycle[y][BL] = FL; + edge_cycle[y][BR] = BL; + + corner_cycle[U][UFR] = UBR; + corner_cycle[U][UFL] = UFR; + corner_cycle[U][UBL] = UFL; + corner_cycle[U][UBR] = UBL; + corner_cycle[U][DFR] = DFR; + corner_cycle[U][DFL] = DFL; + corner_cycle[U][DBL] = DBL; + corner_cycle[U][DBR] = DBR; + + corner_cycle[x][UFR] = DFR; + corner_cycle[x][UFL] = DFL; + corner_cycle[x][UBL] = UFL; + corner_cycle[x][UBR] = UFR; + corner_cycle[x][DFR] = DBR; + corner_cycle[x][DFL] = DBL; + corner_cycle[x][DBL] = UBL; + corner_cycle[x][DBR] = UBR; + + corner_cycle[y][UFR] = UBR; + corner_cycle[y][UFL] = UFR; + corner_cycle[y][UBL] = UFL; + corner_cycle[y][UBR] = UBL; + corner_cycle[y][DFR] = DBR; + corner_cycle[y][DFL] = DFR; + corner_cycle[y][DBL] = DFL; + corner_cycle[y][DBR] = DBL; + + center_cycle[U][U_center] = U_center; + center_cycle[U][D_center] = D_center; + center_cycle[U][R_center] = R_center; + center_cycle[U][L_center] = L_center; + center_cycle[U][F_center] = F_center; + center_cycle[U][B_center] = B_center; + + center_cycle[x][U_center] = F_center; + center_cycle[x][D_center] = B_center; + center_cycle[x][R_center] = R_center; + center_cycle[x][L_center] = L_center; + center_cycle[x][F_center] = D_center; + center_cycle[x][B_center] = U_center; + + center_cycle[y][U_center] = U_center; + center_cycle[y][D_center] = D_center; + center_cycle[y][R_center] = B_center; + center_cycle[y][L_center] = F_center; + center_cycle[y][F_center] = R_center; + center_cycle[y][B_center] = L_center; + + /* Flipped pieces *************/ + eofb_flipped[x][UF] = 1; + eofb_flipped[x][UB] = 1; + eofb_flipped[x][DF] = 1; + eofb_flipped[x][DB] = 1; + + eofb_flipped[y][FR] = 1; + eofb_flipped[y][FL] = 1; + eofb_flipped[y][BL] = 1; + eofb_flipped[y][BR] = 1; + + eorl_flipped[x][UF] = 1; + eorl_flipped[x][UL] = 1; + eorl_flipped[x][UB] = 1; + eorl_flipped[x][UR] = 1; + eorl_flipped[x][DF] = 1; + eorl_flipped[x][DL] = 1; + eorl_flipped[x][DB] = 1; + eorl_flipped[x][DR] = 1; + eorl_flipped[x][FR] = 1; + eorl_flipped[x][FL] = 1; + eorl_flipped[x][BL] = 1; + eorl_flipped[x][BR] = 1; + + eorl_flipped[y][FR] = 1; + eorl_flipped[y][FL] = 1; + eorl_flipped[y][BL] = 1; + eorl_flipped[y][BR] = 1; + + eoud_flipped[U][UF] = 1; + eoud_flipped[U][UL] = 1; + eoud_flipped[U][UB] = 1; + eoud_flipped[U][UR] = 1; + + eoud_flipped[x][UF] = 1; + eoud_flipped[x][UB] = 1; + eoud_flipped[x][DF] = 1; + eoud_flipped[x][DB] = 1; + + eoud_flipped[y][UF] = 1; + eoud_flipped[y][UL] = 1; + eoud_flipped[y][UB] = 1; + eoud_flipped[y][UR] = 1; + eoud_flipped[y][DF] = 1; + eoud_flipped[y][DL] = 1; + eoud_flipped[y][DB] = 1; + eoud_flipped[y][DR] = 1; + eoud_flipped[y][FR] = 1; + eoud_flipped[y][FL] = 1; + eoud_flipped[y][BL] = 1; + eoud_flipped[y][BR] = 1; + + coud_flipped[x][UFR] = 2; + coud_flipped[x][UFL] = 1; + coud_flipped[x][UBR] = 1; + coud_flipped[x][UBL] = 2; + coud_flipped[x][DFR] = 1; + coud_flipped[x][DFL] = 2; + coud_flipped[x][DBR] = 2; + coud_flipped[x][DBL] = 1; + + corl_flipped[U][UFR] = 1; + corl_flipped[U][UFL] = 2; + corl_flipped[U][UBL] = 1; + corl_flipped[U][UBR] = 2; + + corl_flipped[y][UFR] = 1; + corl_flipped[y][UFL] = 2; + corl_flipped[y][UBL] = 1; + corl_flipped[y][UBR] = 2; + corl_flipped[y][DFR] = 2; + corl_flipped[y][DFL] = 1; + corl_flipped[y][DBL] = 2; + corl_flipped[y][DBR] = 1; + + cofb_flipped[U][UFR] = 2; + cofb_flipped[U][UFL] = 1; + cofb_flipped[U][UBL] = 2; + cofb_flipped[U][UBR] = 1; + + cofb_flipped[x][UFR] = 1; + cofb_flipped[x][UFL] = 2; + cofb_flipped[x][UBL] = 1; + cofb_flipped[x][UBR] = 2; + cofb_flipped[x][DFR] = 2; + cofb_flipped[x][DFL] = 1; + cofb_flipped[x][DBL] = 2; + cofb_flipped[x][DBR] = 1; + + cofb_flipped[y][UFR] = 2; + cofb_flipped[y][UFL] = 1; + cofb_flipped[y][UBL] = 2; + cofb_flipped[y][UBR] = 1; + cofb_flipped[y][DFR] = 1; + cofb_flipped[y][DFL] = 2; + cofb_flipped[y][DBL] = 1; + cofb_flipped[y][DBR] = 2; + + /* Equivalent moves ***********/ + equiv_alg[NULLMOVE] = new_alg(""); + + equiv_alg[U] = new_alg(" U "); + equiv_alg[U2] = new_alg(" UU "); + equiv_alg[U3] = new_alg(" UUU "); + equiv_alg[D] = new_alg(" xx U xx "); + equiv_alg[D2] = new_alg(" xx UU xx "); + equiv_alg[D3] = new_alg(" xx UUU xx "); + equiv_alg[R] = new_alg(" yx U xxxyyy "); + equiv_alg[R2] = new_alg(" yx UU xxxyyy "); + equiv_alg[R3] = new_alg(" yx UUU xxxyyy "); + equiv_alg[L] = new_alg(" yyyx U xxxy "); + equiv_alg[L2] = new_alg(" yyyx UU xxxy "); + equiv_alg[L3] = new_alg(" yyyx UUU xxxy "); + equiv_alg[F] = new_alg(" x U xxx "); + equiv_alg[F2] = new_alg(" x UU xxx "); + equiv_alg[F3] = new_alg(" x UUU xxx "); + equiv_alg[B] = new_alg(" xxx U x "); + equiv_alg[B2] = new_alg(" xxx UU x "); + equiv_alg[B3] = new_alg(" xxx UUU x "); + + equiv_alg[Uw] = new_alg(" xx U xx y "); + equiv_alg[Uw2] = new_alg(" xx UU xx yy "); + equiv_alg[Uw3] = new_alg(" xx UUU xx yyy "); + equiv_alg[Dw] = new_alg(" U yyy "); + equiv_alg[Dw2] = new_alg(" UU yy "); + equiv_alg[Dw3] = new_alg(" UUU y "); + equiv_alg[Rw] = new_alg(" yyyx U xxxy x "); + equiv_alg[Rw2] = new_alg(" yyyx UU xxxy xx "); + equiv_alg[Rw3] = new_alg(" yyyx UUU xxxy xxx "); + equiv_alg[Lw] = new_alg(" yx U xxxyyy xxx "); + equiv_alg[Lw2] = new_alg(" yx UU xxxyyy xx "); + equiv_alg[Lw3] = new_alg(" yx UUU xxxyyy x "); + equiv_alg[Fw] = new_alg(" xxx U x yxxxyyy "); + equiv_alg[Fw2] = new_alg(" xxx UU x yxxyyy "); + equiv_alg[Fw3] = new_alg(" xxx UUU x yxyyy "); + equiv_alg[Bw] = new_alg(" x U xxx yxyyy "); + equiv_alg[Bw2] = new_alg(" x UU xxx yxxyyy "); + equiv_alg[Bw3] = new_alg(" x UUU xxx yxxxyyy "); + + equiv_alg[M] = new_alg(" yx U xx UUU yxyyy "); + equiv_alg[M2] = new_alg(" yx UU xx UU xxxy "); + equiv_alg[M3] = new_alg(" yx UUU xx U yxxxy "); + equiv_alg[S] = new_alg(" x UUU xx U yyyx "); + equiv_alg[S2] = new_alg(" x UU xx UU yyx "); + equiv_alg[S3] = new_alg(" x U xx UUU yx "); + equiv_alg[E] = new_alg(" U xx UUU xxyyy "); + equiv_alg[E2] = new_alg(" UU xx UU xxyy "); + equiv_alg[E3] = new_alg(" UUU xx U xxy "); + + equiv_alg[x] = new_alg(" x "); + equiv_alg[x2] = new_alg(" xx "); + equiv_alg[x3] = new_alg(" xxx "); + equiv_alg[y] = new_alg(" y "); + equiv_alg[y2] = new_alg(" yy "); + equiv_alg[y3] = new_alg(" yyy "); + equiv_alg[z] = new_alg(" yyy x y "); + equiv_alg[z2] = new_alg(" yy xx "); + equiv_alg[z3] = new_alg(" y x yyy "); +} + +static void +init_steps() +{ + /* PruneData */ + pd_eofb_HTM.filename = "ptable_eofb_HTM"; + pd_eofb_HTM.size = POW2TO11; + pd_eofb_HTM.index = index_eofb; + pd_eofb_HTM.moveset = moveset_HTM; + + pd_coud_HTM.filename = "ptable_coud_HTM"; + pd_coud_HTM.size = POW3TO7; + pd_coud_HTM.index = index_coud; + pd_coud_HTM.moveset = moveset_HTM; + + pd_corners_HTM.filename = "ptable_corners_HTM"; + pd_corners_HTM.size = POW3TO7 * FACTORIAL8; + pd_corners_HTM.index = index_corners; + pd_corners_HTM.moveset = moveset_HTM; + + pd_ep_HTM.filename = "ptable_ep_HTM"; + pd_ep_HTM.size = FACTORIAL12; + pd_ep_HTM.index = index_ep; + pd_ep_HTM.moveset = moveset_HTM; + + pd_drud_HTM.filename = "ptable_drud_HTM"; + pd_drud_HTM.size = POW2TO11 * POW3TO7 * BINOM12ON4; + pd_drud_HTM.index = index_drud; + pd_drud_HTM.moveset = moveset_HTM; + + + /* Actual steps */ + eofb_HTM.check = check_eofb_HTM; + eofb_HTM.ready = check_nothing; + eofb_HTM.pre_trans = uf; + eofb_HTM.moveset = moveset_HTM; + + eorl_HTM.check = check_eofb_HTM; + eorl_HTM.ready = check_nothing; + eorl_HTM.pre_trans = ur; + eorl_HTM.moveset = moveset_HTM; + + eoud_HTM.check = check_eofb_HTM; + eoud_HTM.ready = check_nothing; + eoud_HTM.pre_trans = bu; + eoud_HTM.moveset = moveset_HTM; + + + coud_HTM.check = check_coud_HTM; + coud_HTM.ready = check_nothing; + coud_HTM.pre_trans = uf; + coud_HTM.moveset = moveset_HTM; + + corl_HTM.check = check_coud_HTM; + corl_HTM.ready = check_nothing; + corl_HTM.pre_trans = rf; + corl_HTM.moveset = moveset_HTM; + + cofb_HTM.check = check_coud_HTM; + cofb_HTM.ready = check_nothing; + cofb_HTM.pre_trans = fd; + cofb_HTM.moveset = moveset_HTM; + + coud_URF.check = check_coud_URF; + coud_URF.ready = check_nothing; + coud_URF.pre_trans = uf; + coud_URF.moveset = moveset_URF; + + corl_URF.check = check_coud_URF; + corl_URF.ready = check_nothing; + corl_URF.pre_trans = rf; + corl_URF.moveset = moveset_URF; + + cofb_URF.check = check_coud_URF; + cofb_URF.ready = check_nothing; + cofb_URF.pre_trans = fd; + cofb_URF.moveset = moveset_URF; + + corners_HTM.check = check_corners_HTM; + corners_HTM.ready = check_nothing; + corners_HTM.pre_trans = uf; + corners_HTM.moveset = moveset_HTM; + + corners_URF.check = check_corners_URF; + corners_URF.ready = check_nothing; + corners_URF.pre_trans = uf; + corners_URF.moveset = moveset_URF; + + edges_HTM.check = check_edges_HTM; + edges_HTM.ready = check_nothing; + edges_HTM.pre_trans = uf; + edges_HTM.moveset = moveset_HTM; + + drud_HTM.check = check_drud_HTM; + drud_HTM.ready = check_nothing; + drud_HTM.pre_trans = uf; + drud_HTM.moveset = moveset_HTM; + + optimal_HTM.check = check_optimal_HTM; + optimal_HTM.ready = check_nothing; + optimal_HTM.pre_trans = uf; + optimal_HTM.moveset = moveset_HTM; +} + +static void +init_strings() +{ + strcpy(move_string [NULLMOVE], "-" ); + strcpy(move_string [U], "U" ); + strcpy(move_string [U2], "U2" ); + strcpy(move_string [U3], "U\'" ); + strcpy(move_string [D], "D" ); + strcpy(move_string [D2], "D2" ); + strcpy(move_string [D3], "D\'" ); + strcpy(move_string [R], "R" ); + strcpy(move_string [R2], "R2" ); + strcpy(move_string [R3], "R\'" ); + strcpy(move_string [L], "L" ); + strcpy(move_string [L2], "L2" ); + strcpy(move_string [L3], "L\'" ); + strcpy(move_string [F], "F" ); + strcpy(move_string [F2], "F2" ); + strcpy(move_string [F3], "F\'" ); + strcpy(move_string [B], "B" ); + strcpy(move_string [B2], "B2" ); + strcpy(move_string [B3], "B\'" ); + strcpy(move_string [Uw], "Uw" ); + strcpy(move_string [Uw2], "Uw2" ); + strcpy(move_string [Uw3], "Uw\'" ); + strcpy(move_string [Dw], "Dw" ); + strcpy(move_string [Dw2], "Dw2" ); + strcpy(move_string [Dw3], "Dw\'" ); + strcpy(move_string [Rw], "Rw" ); + strcpy(move_string [Rw2], "Rw2" ); + strcpy(move_string [Rw3], "Rw\'" ); + strcpy(move_string [Lw], "Lw" ); + strcpy(move_string [Lw2], "Lw2" ); + strcpy(move_string [Lw3], "Lw\'" ); + strcpy(move_string [Fw], "Fw" ); + strcpy(move_string [Fw2], "Fw2" ); + strcpy(move_string [Fw3], "Fw\'" ); + strcpy(move_string [Bw], "Bw" ); + strcpy(move_string [Bw2], "Bw2" ); + strcpy(move_string [Bw3], "Bw\'" ); + strcpy(move_string [M], "M" ); + strcpy(move_string [M2], "M2" ); + strcpy(move_string [M3], "M\'" ); + strcpy(move_string [S], "S" ); + strcpy(move_string [S2], "S2" ); + strcpy(move_string [S3], "S\'" ); + strcpy(move_string [E], "E" ); + strcpy(move_string [E2], "E2" ); + strcpy(move_string [E3], "E\'" ); + strcpy(move_string [x], "x" ); + strcpy(move_string [x2], "x2" ); + strcpy(move_string [x3], "x\'" ); + strcpy(move_string [y], "y" ); + strcpy(move_string [y2], "y2" ); + strcpy(move_string [y3], "y\'" ); + strcpy(move_string [z], "z" ); + strcpy(move_string [z2], "z2" ); + strcpy(move_string [z3], "z\'" ); + + strcpy(edge_string [UF], "UF" ); + strcpy(edge_string [UL], "UL" ); + strcpy(edge_string [UB], "UB" ); + strcpy(edge_string [UR], "UR" ); + strcpy(edge_string [DF], "DF" ); + strcpy(edge_string [DL], "DL" ); + strcpy(edge_string [DB], "DB" ); + strcpy(edge_string [DR], "DR" ); + strcpy(edge_string [FR], "FR" ); + strcpy(edge_string [FL], "FL" ); + strcpy(edge_string [BL], "BL" ); + strcpy(edge_string [BR], "BR" ); + + strcpy(corner_string [UFR], "UFR" ); + strcpy(corner_string [UFL], "UFL" ); + strcpy(corner_string [UBL], "UBL" ); + strcpy(corner_string [UBR], "UBR" ); + strcpy(corner_string [DFR], "DFR" ); + strcpy(corner_string [DFL], "DFL" ); + strcpy(corner_string [DBL], "DBL" ); + strcpy(corner_string [DBR], "DBR" ); + + strcpy(center_string [U_center], "U" ); + strcpy(center_string [D_center], "D" ); + strcpy(center_string [R_center], "R" ); + strcpy(center_string [L_center], "L" ); + strcpy(center_string [F_center], "F" ); + strcpy(center_string [B_center], "B" ); +} + +static void +init_trans() { + Cube aux, cube, c[3]; + CubeArray epcp; + int eparr[12], eoarr[12]; + int cparr[8], coarr[8]; + int i; + bool b1, b2, b3; + uint16_t ui; + Move mi, move; + Trans m; + + /* Compute sources */ + for (i = 0; i < NTRANS; i++) { + if (i == mirror) + cube = (Cube){0}; + else + cube = apply_alg(trans_algs[i], (Cube){0}); + + epose_source[i] = edge_slice(edge_at(cube, FR)); + eposs_source[i] = edge_slice(edge_at(cube, UR)); + eposm_source[i] = edge_slice(edge_at(cube, UF)); + eofb_source[i] = center_at(cube, F_center)/2; + eorl_source[i] = center_at(cube, R_center)/2; + eoud_source[i] = center_at(cube, U_center)/2; + coud_source[i] = center_at(cube, U_center)/2; + cofb_source[i] = center_at(cube, F_center)/2; + corl_source[i] = center_at(cube, R_center)/2; + } + + if (read_ttables_file()) + return; + + fprintf(stderr, "Cannot load %s, generating it\n", "ttables"); + + /* Initialize tables */ + for (m = 0; m < NTRANS; m++) { + if (m == mirror) { + memcpy(eparr, ep_mirror, 12 * sizeof(int)); + memcpy(cparr, cp_mirror, 8 * sizeof(int)); + } else { + epcp = (CubeArray){ .ep = eparr, .cp = cparr }; + cube = apply_alg(trans_algs[m], (Cube){0}); + cube_to_arrays(cube, &epcp, pf_epcp); + } + + 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 == mirror) + 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++) { + if (m == mirror) { + b1 = (mi >= U && mi <= Bw3); + b2 = (mi >= S && mi <= E3); + b3 = (mi >= x && mi <= z3); + if (b1 || b2 || b3) + moves_ttable[m][mi] = + inverse_move_aux[mi]; + else + moves_ttable[m][mi] = mi; + + if ((mi-1)/3==(R-1)/3 || (mi-1)/3==(Rw-1)/3) + moves_ttable[m][mi] += 3; + if ((mi-1)/3==(L-1)/3 || (mi-1)/3==(L2-1)/3) + moves_ttable[m][mi] -= 3; + } else { + aux = apply_trans(m, apply_move(mi,(Cube){0})); + for (move = 0; move < NMOVES; move++) { + cube = apply_move( + inverse_move_aux[move], aux); + if (is_solved(cube, false)) + moves_ttable[m][mi] = move; + } + } + } + } + + if (!write_ttables_file()) + fprintf(stderr, "Error writing ttables\n"); +} + +static void +init_trans_aux() +{ + ep_mirror[UF] = UF; + ep_mirror[UL] = UR; + ep_mirror[UB] = UB; + ep_mirror[UR] = UL; + ep_mirror[DF] = DF; + ep_mirror[DL] = DR; + ep_mirror[DB] = DB; + ep_mirror[DR] = DL; + ep_mirror[FR] = FL; + ep_mirror[FL] = FR; + ep_mirror[BR] = BL; + ep_mirror[BL] = BR; + + cp_mirror[UFR] = UFL; + cp_mirror[UFL] = UFR; + cp_mirror[UBL] = UBR; + cp_mirror[UBR] = UBL; + cp_mirror[DFR] = DFL; + cp_mirror[DFL] = DFR; + cp_mirror[DBL] = DBR; + cp_mirror[DBR] = DBL; + + cpos_mirror[U_center] = U_center; + cpos_mirror[D_center] = D_center; + cpos_mirror[R_center] = L_center; + cpos_mirror[L_center] = R_center; + cpos_mirror[F_center] = F_center; + cpos_mirror[B_center] = B_center; + + /* Is there a more elegant way? */ + trans_algs[uf] = new_alg(""); + trans_algs[ur] = new_alg("y"); + trans_algs[ub] = new_alg("y2"); + trans_algs[ul] = new_alg("y3"); + + trans_algs[df] = new_alg("z2"); + trans_algs[dr] = new_alg("y z2"); + trans_algs[db] = new_alg("x2"); + trans_algs[dl] = new_alg("y3 z2"); + + trans_algs[rf] = new_alg("z3"); + trans_algs[rd] = new_alg("z3 y"); + trans_algs[rb] = new_alg("z3 y2"); + trans_algs[ru] = new_alg("z3 y3"); + + trans_algs[lf] = new_alg("z"); + trans_algs[ld] = new_alg("z y3"); + trans_algs[lb] = new_alg("z y2"); + trans_algs[lu] = new_alg("z y"); + + trans_algs[fu] = new_alg("x y2"); + trans_algs[fr] = new_alg("x y"); + trans_algs[fd] = new_alg("x"); + trans_algs[fl] = new_alg("x y3"); + + trans_algs[bu] = new_alg("x3"); + trans_algs[br] = new_alg("x3 y"); + trans_algs[bd] = new_alg("x3 y2"); + trans_algs[bl] = new_alg("x3 y3"); +} + +/* Linearization functions implementation ************************************/ + +static uint64_t +index_eofb(Cube cube) +{ + return cube.eofb; +} + +static uint64_t +index_coud(Cube cube) +{ + return cube.coud; +} + +static uint64_t +index_corners(Cube cube) +{ + return cube.coud * FACTORIAL8 + cube.cp; +} + +static uint64_t +index_ep(Cube cube) +{ + uint64_t a, b, c; + + /* TODO: remove this check */ + if (epos_dependent_aux[cube.eposs/FACTORIAL4][cube.epose/FACTORIAL4] ==BINOM8ON4) + fprintf(stderr, "Impossible\n"); + + a = cube.eposs; + b = (cube.epose % FACTORIAL4) + + epos_dependent_aux[cube.eposs/FACTORIAL4][cube.epose/FACTORIAL4] * + FACTORIAL4; + c = cube.eposm % FACTORIAL4; + + b *= FACTORIAL4 * BINOM12ON4; + c *= FACTORIAL4 * BINOM12ON4 * FACTORIAL4 * BINOM8ON4; + + return a + b + c; +} + +static uint64_t +index_drud(Cube cube) +{ + uint64_t a, b, c; + + a = cube.eofb; + b = cube.coud; + c = cube.epose / FACTORIAL4; + + b *= POW2TO11; + c *= POW2TO11 * POW3TO7; + + return a + b + c; +} + +/* Step checking functions implementation ************************************/ + +static int +check_nothing(Cube cube) +{ + return true; +} + +static int +check_eofb_HTM(Cube cube) +{ + if (!pd_eofb_HTM.generated) + generate_ptable(&pd_eofb_HTM); + + return PTABLEVAL(pd_eofb_HTM.ptable, cube.eofb); +} + +static int +check_coud_HTM(Cube cube) +{ + if (!pd_coud_HTM.generated) + generate_ptable(&pd_coud_HTM); + + return PTABLEVAL(pd_coud_HTM.ptable, cube.coud); +} + +static int +check_coud_URF(Cube cube) +{ + /* TODO: I can improve this by checking first the orientation of + * the corner in DBL and use that as a reference */ + + int ud = check_coud_HTM(cube); + int rl = check_coud_HTM(apply_move(z, cube)); + int fb = check_coud_HTM(apply_move(x, cube)); + + return MIN(ud, MIN(rl, fb)); +} + +static int +check_corners_HTM(Cube cube) +{ + if (!pd_corners_HTM.generated) + generate_ptable(&pd_corners_HTM); + + return PTABLEVAL(pd_corners_HTM.ptable, index_corners(cube)); +} + +static int +check_corners_URF(Cube cube) +{ + /* TODO: I can improve this by checking first the corner in DBL + * and use that as a reference */ + + int ret = 15; + Cube c; + Trans i; + + for (i = 0; i < NROTATIONS; i++) { + c = apply_alg(trans_algs[i], cube); + ret = MIN(ret, check_corners_HTM(c)); + } + + return ret; +} + +static int +check_edges_HTM(Cube cube) +{ + int ret = 0; + + if (!pd_ep_HTM.generated) + generate_ptable(&pd_ep_HTM); + + ret = MAX(ret, PTABLEVAL(pd_ep_HTM.ptable, index_ep(cube))); + ret = MAX(ret, check_eofb_HTM(cube)); + ret = MAX(ret, check_eofb_HTM(apply_trans(ur, cube))); + ret = MAX(ret, check_eofb_HTM(apply_trans(fd, cube))); + + return ret; +} + +static int +check_drud_HTM(Cube cube) +{ + if (!pd_drud_HTM.generated) + generate_ptable(&pd_drud_HTM); + + return PTABLEVAL(pd_drud_HTM.ptable, index_drud(cube)); +} + +static int +check_optimal_HTM(Cube cube) +{ + int dr1, dr2, dr3, drmax, cor; /*ep;*/ + + if (!pd_drud_HTM.generated) + generate_ptable(&pd_drud_HTM); + if (!pd_corners_HTM.generated) + generate_ptable(&pd_corners_HTM); + /* + *if (!pd_ep_HTM.generated) + * generate_ptable(&pd_ep_HTM); + */ + + dr1 = PTABLEVAL(pd_drud_HTM.ptable, index_drud(cube)); + dr2 = PTABLEVAL(pd_drud_HTM.ptable, index_drud(apply_trans(rf, cube))); + dr3 = PTABLEVAL(pd_drud_HTM.ptable, index_drud(apply_trans(fd, cube))); + + drmax = MAX(dr1, MAX(dr2, dr3)); + if (dr1 == dr2 && dr2 == dr3 && dr1 != 0) + drmax++; + + cor = PTABLEVAL(pd_corners_HTM.ptable, index_corners(cube)); + /* ep = PTABLEVAL(pd_ep_HTM.ptable, index_ep(cube)); */ + + /*return MAX(drmax, MAX(ep, cor));*/ + if (drmax == 0 && cor == 0) + return is_solved(cube, false) ? 0 : 1; + return MAX(drmax, cor); +} + + +/* Movesets ******************************************************************/ + +bool +moveset_HTM(Move m) +{ + return m >= U && m <= B3; +} + +bool +moveset_URF(Move m) +{ + Move b = base_move(m); + + return b == U || b == R || b == F; +} + + +/* Public functions implementation *******************************************/ + +Cube +apply_alg(Alg *alg, Cube cube) +{ + return apply_alg_generic(alg, cube, pf_all, true); +} + +Cube +apply_move(Move m, Cube cube) +{ + Cube moved = {0}; + + moved.epose = epose_mtable[m][cube.epose]; + moved.eposs = eposs_mtable[m][cube.eposs]; + moved.eposm = eposm_mtable[m][cube.eposm]; + moved.eofb = eofb_mtable[m][cube.eofb]; + moved.eorl = eorl_mtable[m][cube.eorl]; + moved.eoud = eoud_mtable[m][cube.eoud]; + moved.coud = coud_mtable[m][cube.coud]; + moved.cofb = cofb_mtable[m][cube.cofb]; + moved.corl = corl_mtable[m][cube.corl]; + moved.cp = cp_mtable[m][cube.cp]; + moved.cpos = cpos_mtable[m][cube.cpos]; + + return moved; +} + +Cube +apply_trans(Trans t, Cube cube) +{ + Cube transformed = {0}; + uint16_t aux_epos[3] = { cube.epose, cube.eposs, cube.eposm }; + uint16_t aux_eo[3] = { cube.eoud, cube.eorl, cube.eofb }; + uint16_t aux_co[3] = { cube.coud, cube.corl, cube.cofb }; + + transformed.epose = epose_ttable[t][aux_epos[epose_source[t]]]; + transformed.eposs = eposs_ttable[t][aux_epos[eposs_source[t]]]; + transformed.eposm = eposm_ttable[t][aux_epos[eposm_source[t]]]; + transformed.eofb = eo_ttable[t][aux_eo[eofb_source[t]]]; + transformed.eorl = eo_ttable[t][aux_eo[eorl_source[t]]]; + transformed.eoud = eo_ttable[t][aux_eo[eoud_source[t]]]; + transformed.coud = co_ttable[t][aux_co[coud_source[t]]]; + transformed.corl = co_ttable[t][aux_co[corl_source[t]]]; + transformed.cofb = co_ttable[t][aux_co[cofb_source[t]]]; + transformed.cp = cp_ttable[t][cube.cp]; + transformed.cpos = cpos_ttable[t][cube.cpos]; + + return transformed; +} + +/* TODO: this has to be changed using pre-computations */ +bool +block_solved(Cube cube, Block block) +{ + CubeArray *arr = new_cubearray(cube, pf_all); + int i; + bool ret = true; + + for (i = 0; i < 12; i++) + ret = ret && !(block.edge[i] && (arr->ep[i] != i || arr->eofb[i])); + for (i = 0; i < 8; i++) + ret = ret && !(block.corner[i] && (arr->cp[i] != i || arr->coud[i])); + for (i = 0; i < 6; i++) + ret = ret && !(block.center[i] && arr->cpos[i] != i); + + free_cubearray(arr, pf_all); + + return ret; +} + +Center +center_at(Cube cube, Center c) +{ + int ret; + CubeArray *arr = new_cubearray(cube, pf_cpos); + + ret = arr->cpos[c]; + free_cubearray(arr, pf_cpos); + + return ret; +} + +Cube +compose(Cube c2, Cube c1) +{ + return compose_filtered(c2, c1, pf_all); +} + +Corner +corner_at(Cube cube, Corner c) +{ + int ret; + CubeArray *arr = new_cubearray(cube, pf_cp); + + ret = arr->cp[c]; + free_cubearray(arr, pf_cp); + + return ret; +} + +Edge +edge_at(Cube cube, Edge e) +{ + int ret; + CubeArray *arr = new_cubearray(cube, pf_ep); + + ret = arr->ep[e]; + free_cubearray(arr, pf_ep); + + return ret; +} + +bool +equal(Cube c1, Cube c2) +{ + 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 *arr = new_cubearray(cube, pf_all); + CubeArray *inv = new_cubearray((Cube){0}, pf_all); + Cube ret; + int i; + + for (i = 0; i < 12; i++) { + inv->ep[arr->ep[i]] = i; + inv->eofb[arr->ep[i]] = arr->eofb[i]; + inv->eorl[arr->ep[i]] = arr->eorl[i]; + inv->eoud[arr->ep[i]] = arr->eoud[i]; + } + + for (i = 0; i < 8; i++) { + inv->cp[arr->cp[i]] = i; + inv->coud[arr->cp[i]] = (3 - arr->coud[i]) % 3; + inv->corl[arr->cp[i]] = (3 - arr->corl[i]) % 3; + inv->cofb[arr->cp[i]] = (3 - arr->cofb[i]) % 3; + } + + for (int i = 0; i < 6; i++) + inv->cpos[arr->cpos[i]] = i; + + ret = arrays_to_cube(inv, pf_all); + free_cubearray(arr, pf_all); + free_cubearray(inv, pf_all); + + return ret; +} + +Move +inverse_move(Move m) +{ + return inverse_move_aux[m]; +} + +Trans +inverse_trans(Trans t) +{ + return inverse_trans_aux[t]; +} + +bool +is_admissible(Cube cube) +{ + /* TODO: this should check consistency of different orientations */ + /* TODO: check that centers are opposite and admissible */ + + CubeArray *a = new_cubearray(cube, pf_all); + int parity; + bool perm; + + 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); + + return perm && parity % 2 == 0; +} + +bool +is_solved(Cube cube, bool reorient) +{ + Trans i; + + if (reorient) + for (i = 0; i < NROTATIONS; i++) + if (is_solved(apply_alg(trans_algs[i],cube), false)) + return true; + + return equal(cube, (Cube){0}); +} + +int +piece_orientation(Cube cube, int piece, char *orientation) +{ + int arr[12], n, b; + uint16_t 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) +{ + CubeArray *arr = new_cubearray(cube, pf_all); + + for (int i = 0; i < 12; i++) + printf(" %s ", edge_string[arr->ep[i]]); + printf("\n"); + + for (int i = 0; i < 12; i++) + printf(" %c ", arr->eofb[i] + '0'); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf("%s ", corner_string[arr->cp[i]]); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf(" %c ", arr->coud[i] + '0'); + printf("\n"); + + for (int i = 0; i < 6; i++) + printf(" %s ", center_string[arr->cpos[i]]); + printf("\n"); + + free_cubearray(arr, pf_all); +} + +Cube +random_cube() +{ + CubeArray *arr = new_cubearray((Cube){0}, pf_4val); + Cube ret; + int ep, cp, eo, co; + + ep = rand() % FACTORIAL12; + cp = rand() % FACTORIAL8; + eo = rand() % POW2TO11; + co = rand() % POW3TO7; + + index_to_perm(ep, 12, arr->ep); + index_to_perm(cp, 8, arr->cp); + int_to_sum_zero_array(eo, 2, 12, arr->eofb); + int_to_sum_zero_array(co, 3, 8, arr->coud); + + if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8)) + swap(&(arr->ep[0]), &(arr->ep[1])); + + ret = arrays_to_cube(arr, pf_4val); + free_cubearray(arr, pf_4val); + + return ret; +} + +AlgList * +solve(Cube cube, Step step, SolveOptions *opts) +{ + AlgListNode *node; + AlgList *sols = new_alglist(); + Cube c = apply_trans(step.pre_trans, cube); + DfsData dd = { + .m = 0, + .niss = false, + .last1 = NULLMOVE, + .last2 = NULLMOVE, + .sols = sols, + .current_alg = new_alg("") + }; + + if (step.ready != NULL && !step.ready(c)) + return sols; + + moveset_to_list(step.moveset, step.check, dd.sorted_moves); + + for (dd.d = MAX(opts->min_moves, step.check(c)); + dd.d <= opts->max_moves && !(sols->len && opts->optimal_only); + dd.d++) { + solve_dfs(c, step, opts, &dd); + if (opts->feedback) + fprintf(stderr, + "Depth %d completed, found %d solutions\n", + dd.d, sols->len); + } + + for (node = sols->first; node != NULL; node = node->next) + transform_alg(inverse_trans_aux[step.pre_trans], node->alg); + + return sols; +} + +Alg * +inverse_alg(Alg *alg) +{ + Alg *ret = new_alg(""); + int i; + + for (i = alg->len-1; i >= 0; i--) + append_move(ret, alg->move[i], alg->inv[i]); + + return ret; +} + +Alg * +new_alg(char *str) +{ + Alg *alg = malloc(sizeof(Alg)); + int i; + bool niss = false; + Move j, m; + + alg->move = malloc(30 * sizeof(Move)); + alg->inv = malloc(30 * sizeof(bool)); + alg->allocated = 30; + alg->len = 0; + + for (i = 0; str[i]; i++) { + if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n') + continue; + + if (str[i] == '(' && niss) { + fprintf(stderr, "Error reading moves: nested ( )\n"); + return alg; + } + + if (str[i] == ')' && !niss) { + fprintf(stderr, "Error reading moves: unmatched )\n"); + return alg; + } + + if (str[i] == '(' || str[i] == ')') { + niss = !niss; + continue; + } + + for (j = 0; j < NMOVES; j++) { + if (str[i] == move_string[j][0]) { + m = j; + if (m <= B && str[i+1]=='w') { + m += Uw - U; + i++; + } + if (str[i+1]=='2') { + m += 1; + i++; + } else if (str[i+1]=='\'' || str[i+1]=='3') { + m += 2; + i++; + } + append_move(alg, m, niss); + break; + } + } + } + + return alg; +} + +Alg * +on_inverse(Alg *alg) +{ + Alg *ret = new_alg(""); + int i; + + for (i = 0; i < alg->len; i++) + append_move(ret, alg->move[i], !alg->inv[i]); + + return ret; +} + +void +print_alg(Alg *alg, bool l) +{ + char fill[4]; + int i; + bool niss = false; + + for (i = 0; i < alg->len; i++) { + if (!niss && alg->inv[i]) + strcpy(fill, i == 0 ? "(" : " ("); + if (niss && !alg->inv[i]) + strcpy(fill, ") "); + if (niss == alg->inv[i]) + strcpy(fill, i == 0 ? "" : " "); + + printf("%s%s", fill, move_string[alg->move[i]]); + niss = alg->inv[i]; + } + + if (niss) + printf(")"); + if (l) + printf(" (%d)", alg->len); + + printf("\n"); +} + +void +print_ptable(PruneData *pd) +{ + uint64_t i, a[16]; + + memset(a, 0, 16 * sizeof(uint64_t)); + + if (!pd->generated) + generate_ptable(pd); + + for (i = 0; i < pd->size; i++) + a[PTABLEVAL(pd->ptable, i)]++; + + fprintf(stderr, "Values for table %s\n", pd->filename); + for (i = 0; i < 16; i++) + printf("%2lu\t%10lu\n", i, a[i]); +} + +void +print_alglist(AlgList *al, bool l) +{ + AlgListNode *i; + + for (i = al->first; i != NULL; i = i->next) + print_alg(i->alg, l); +} + +void +transform_alg(Trans t, Alg *alg) +{ + int i; + + for (i = 0; i < alg->len; i++) + alg->move[i] = moves_ttable[t][alg->move[i]]; +} + + +void +init() +{ + /* Order is important! */ + init_environment(); + init_strings(); + init_moves_aux(); + init_moves(); + init_auxtables(); + init_trans_aux(); + init_trans(); + init_steps(); +} + + diff --git a/old/2021-06-15-before-separating-steps/cube.h b/old/2021-06-15-before-separating-steps/cube.h new file mode 100644 index 0000000..c30b53f --- /dev/null +++ b/old/2021-06-15-before-separating-steps/cube.h @@ -0,0 +1,72 @@ +#ifndef CUBE_H +#define CUBE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include "cubetypes.h" + +/* Steps *********************************************************************/ + +extern Step eofb_HTM; +extern Step eorl_HTM; +extern Step eoud_HTM; +extern Step coud_HTM; +extern Step corl_HTM; +extern Step cofb_HTM; +extern Step coud_URF; +extern Step corl_URF; +extern Step cofb_URF; +extern Step corners_HTM; +extern Step corners_URF; +extern Step edges_HTM; +extern Step drud_HTM; +extern Step optimal_HTM; + +extern PruneData pd_eofb_HTM; +extern PruneData pd_coud_HTM; +extern PruneData pd_corners_HTM; +extern PruneData pd_ep_HTM; +extern PruneData pd_drud_HTM; + +/* Public functions **********************************************************/ + +Cube apply_alg(Alg *alg, Cube cube); +Cube apply_move(Move m, Cube cube); +Cube apply_trans(Trans t, Cube cube); +bool block_solved(Cube cube, Block); +Center center_at(Cube cube, Center c); +Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */ +Corner corner_at(Cube cube, Corner c); +Edge edge_at(Cube cube, Edge e); +bool equal(Cube c1, Cube c2); +Cube inverse_cube(Cube cube); +Move inverse_move(Move m); +Trans inverse_trans(Trans t); +bool is_admissible(Cube cube); +bool is_solved(Cube cube, bool reorient); +int piece_orientation(Cube cube, int piece, char *orientation); +void print_cube(Cube cube); +Cube random_cube(); +AlgList * solve(Cube cube, Step step, SolveOptions *opts); + +void free_alg(Alg *alg); +void free_alglist(AlgList *l); +Alg * inverse_alg(Alg *alg); +Alg * new_alg(char *str); +Alg * on_inverse(Alg *alg); +void print_alg(Alg *alg, bool l); +void print_alglist(AlgList *al, bool l); +void transform_alg(Trans t, Alg *alg); + +void print_ptable(PruneData *pd); + +void init(); + +#endif + diff --git a/old/2021-06-15-before-separating-steps/cubetypes.h b/old/2021-06-15-before-separating-steps/cubetypes.h new file mode 100644 index 0000000..6ba3675 --- /dev/null +++ b/old/2021-06-15-before-separating-steps/cubetypes.h @@ -0,0 +1,201 @@ +/* Typedefs ******************************************************************/ + +typedef enum center Center; +typedef enum corner Corner; +typedef enum edge Edge; +typedef enum move Move; +typedef enum trans Trans; + +typedef struct alg Alg; +typedef struct alglist AlgList; +typedef struct alglistnode AlgListNode; +typedef struct block Block; +typedef struct cube Cube; +typedef struct cubearray CubeArray; +typedef struct dfsdata DfsData; +typedef struct piecefilter PieceFilter; +typedef struct prunedata PruneData; +typedef struct solveoptions SolveOptions; +typedef struct step Step; + +/* Enums *********************************************************************/ + +enum +center +{ + U_center, D_center, + R_center, L_center, + F_center, B_center +}; + +enum +corner +{ + UFR, UFL, UBL, UBR, + DFR, DFL, DBL, DBR +}; + +enum +edge +{ + UF, UL, UB, UR, + DF, DL, DB, DR, + FR, FL, BL, BR +}; + +enum +move +{ + NULLMOVE, + U, U2, U3, D, D2, D3, + R, R2, R3, L, L2, L3, + F, F2, F3, B, B2, B3, + Uw, Uw2, Uw3, Dw, Dw2, Dw3, + Rw, Rw2, Rw3, Lw, Lw2, Lw3, + Fw, Fw2, Fw3, Bw, Bw2, Bw3, + M, M2, M3, + S, S2, S3, + E, E2, E3, + x, x2, x3, + y, y2, y3, + z, z2, z3, +}; + +enum +trans +{ + uf, ur, ub, ul, + df, dr, db, dl, + rf, rd, rb, ru, + lf, ld, lb, lu, + fu, fr, fd, fl, + bu, br, bd, bl, + mirror, /* R|L */ +}; + + +/* Structs *******************************************************************/ + +struct +alg +{ + Move * move; + bool * inv; + int len; + int allocated; +}; + +struct +alglist +{ + AlgListNode * first; + AlgListNode * last; + int len; +}; + +struct +alglistnode +{ + Alg * alg; + AlgListNode * next; +}; + +struct +block +{ + bool edge[12]; + bool corner[8]; + bool center[6]; +}; + +struct +cube +{ + uint16_t epose; + uint16_t eposs; + uint16_t eposm; + uint16_t eofb; + uint16_t eorl; + uint16_t eoud; + uint16_t cp; + uint16_t coud; + uint16_t cofb; + uint16_t corl; + uint16_t cpos; +}; + +struct +cubearray +{ + int * ep; + int * eofb; + int * eorl; + int * eoud; + int * cp; + int * coud; + int * corl; + int * cofb; + int * cpos; +}; + +struct +dfsdata +{ + int d; + int m; + bool niss; + Move last1; + Move last2; + AlgList * sols; + Alg * current_alg; + Move sorted_moves[z3+1]; +}; + +struct +piecefilter +{ + 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; + uint8_t * ptable; + uint8_t * reached; + bool generated; + uint64_t n; + uint64_t size; + uint64_t (*index)(Cube); + bool (*moveset)(Move); +}; + +struct +solveoptions +{ + int min_moves; + int max_moves; + int max_solutions; + bool optimal_only; + bool can_niss; + bool feedback; +}; + +struct +step +{ + int (*check)(Cube); + int (*ready)(Cube); + bool (*moveset)(Move); + Trans pre_trans; +}; diff --git a/old/2021-06-15-before-separating-steps/main.c b/old/2021-06-15-before-separating-steps/main.c new file mode 100644 index 0000000..ff726b5 --- /dev/null +++ b/old/2021-06-15-before-separating-steps/main.c @@ -0,0 +1,60 @@ +#include +#include "cube.h" + +int main() { + Alg *algo; + AlgList *sols; + Cube cube; + SolveOptions opts; + char line[1000]; + int i, ns = 2, nrand = 100000, sum1, sum2; + + Step *stps[20] = {&drud_HTM, &optimal_HTM}; + char sss[30][30] = {"DR on U/D", "Optimal solution"}; + + opts = (SolveOptions) { + .min_moves = 0, + .max_moves = 20, + .optimal_only = true, + .max_solutions = 1, + .can_niss = false, + .feedback = true + }; + + init(); + +/* + print_ptable(&pd_drud_HTM); + print_ptable(&pd_ep_HTM); + print_ptable(&pd_corners_HTM); +*/ + + srand(time(NULL)); + sum1 = 0; + sum2 = 0; + for (i = 0; i < nrand; i++) { + sum1 += optimal_HTM.check(random_cube()); + sum2 += corners_HTM.check(random_cube()); + } + printf("Average optimal pruning: %lf\n", ((double)sum1) / ((double) nrand)); + printf("Average corners pruning: %lf\n", ((double)sum2) / ((double) nrand)); + + printf("Welcome to nissy 2.0! Insert a scramble:\n"); + + if (fgets(line, 1000, stdin) != NULL) { + algo = new_alg(line); + cube = apply_alg(algo, (Cube){0}); + + for (i = 0; i < ns; i++) { + if (stps[i]->check == NULL) + fprintf(stderr, "Check function for step %d is null\n", i); + sols = solve(cube, *stps[i], &opts); + printf("%s: %d solutions found:\n", sss[i], sols->len); + print_alglist(sols, true); + free_alglist(sols); + } + free(algo); + } + + return 0; +} diff --git a/old/2021-06-15-before-separating-steps/steps.h b/old/2021-06-15-before-separating-steps/steps.h new file mode 100644 index 0000000..e2b71a0 --- /dev/null +++ b/old/2021-06-15-before-separating-steps/steps.h @@ -0,0 +1,20 @@ +extern Step eofb_HTM; +extern Step eorl_HTM; +extern Step eoud_HTM; +extern Step coud_HTM; +extern Step corl_HTM; +extern Step cofb_HTM; +extern Step coud_URF; +extern Step corl_URF; +extern Step cofb_URF; +extern Step corners_HTM; +extern Step corners_URF; +extern Step edges_HTM; +extern Step drud_HTM; +extern Step optimal_HTM; + +extern PruneData pd_eofb_HTM; +extern PruneData pd_coud_HTM; +extern PruneData pd_corners_HTM; +extern PruneData pd_ep_HTM; +extern PruneData pd_drud_HTM; diff --git a/old/2021-06-17-cachedata/cube.c b/old/2021-06-17-cachedata/cube.c new file mode 100644 index 0000000..58178dc --- /dev/null +++ b/old/2021-06-17-cachedata/cube.c @@ -0,0 +1,2738 @@ +#include "cube.h" + +/* Constants and macros *****************************************************/ + +#define POW2TO11 2048ULL +#define POW2TO12 4096ULL +#define POW3TO7 2187ULL +#define POW3TO8 6561ULL +#define FACTORIAL4 24ULL +#define FACTORIAL6 720ULL +#define FACTORIAL8 40320ULL +#define FACTORIAL12 479001600ULL +#define BINOM12ON4 495ULL +#define BINOM8ON4 70ULL +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +#define NMOVES (z3+1) +#define NTRANS (mirror+1) +#define NROTATIONS (NTRANS-1) +#define PTABLESIZE(n) ((n+1) / 2) + + +/* Local functions **********************************************************/ + +static Cube admissible_ep(Cube cube, PieceFilter f); +static bool allowed_next_move(Move move, DfsData *dd); +static void append_alg(AlgList *l, Alg *alg); +static void append_move(Alg *alg, Move m, bool inverse); +static Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a); +static void apply_permutation(int *perm, int *set, int n); +static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f); +static uint16_t array_ep_to_epos(int *ep, int *eps_solved); +static Cube arrays_to_cube(CubeArray *arr, PieceFilter f); +static int binomial(int n, int k); +static Cube compose_filtered(Cube c2, Cube c1, PieceFilter f); +static void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f); +static int digit_array_to_int(int *a, int n, int b); +static int edge_slice(Edge e); /* E=0, S=1, M=2 */ +static int epos_dependent(int pos1, int pos2); +static uint16_t epos_from_arrays(int *epos, int *ep); +static void epos_to_partial_ep(uint16_t epos, int *ep, int *ss); +static int factorial(int n); +static void free_alglistnode(AlgListNode *aln); +static void free_cubearray(CubeArray *arr, PieceFilter f); +static void generate_ctable_dfs(Cube c, CacheData *cd, DfsData *dd); +static void generate_ptable_dfs(Cube c, PruneData *pd, DfsData *dd); +static void index_to_perm(int p, int n, int *r); +static void index_to_subset(int s, int n, int k, int *r); +static void int_to_digit_array(int a, int b, int n, int *r); +static void int_to_sum_zero_array(int x, int b, int n, int *a); +static int invert_digits(int a, int b, int n); +static bool is_perm(int *a, int n); +static bool is_subset(int *a, int n, int k); +static Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf); +static void movelist_to_position(Move *movelist, int *position); +static void moveset_to_list(Moveset ms, Checker f, Move *r); +static AlgList * new_alglist(); +static CubeArray * new_cubearray(Cube cube, PieceFilter f); +static int perm_sign(int *a, int n); +static int perm_to_index(int *a, int n); +/*static int powint(int a, int b);*/ +static void ptable_set_reached(PruneData *pd, uint64_t ind); +static void ptable_update(PruneData *pd, uint64_t ind, int m); +static void push_cachenode(CacheData *cd, Cube c, Alg *alg); +static void realloc_alg(Alg *alg, int n); +static bool read_ctable_file(CacheData *cd); +static bool read_mtables_file(); +static bool read_ptable_file(PruneData *pd); +static bool read_ttables_file(); +static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f); +static void solve_cd(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static void solve_dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static int subset_to_index(int *a, int n, int k); +static void sum_arrays_mod(int *src, int *dst, int n, int m); +static void swap(int *a, int *b); +static bool write_ctable_file(CacheData *cd); +static bool write_mtables_file(); +static bool write_ptable_file(PruneData *pd); +static bool write_ttables_file(); + +static void init_auxtables(); +static void init_environment(); +static void init_moves(); +static void init_moves_aux(); +static void init_strings(); +static void init_trans(); +static void init_trans_aux(); + +/* All sorts of useful costants and tables **********************************/ + +static char * tabledir; + +static PieceFilter pf_all; +static PieceFilter pf_4val; +static PieceFilter pf_epcp; +static PieceFilter pf_cpos; +static PieceFilter pf_cp; +static PieceFilter pf_ep; +static PieceFilter pf_e; +static PieceFilter pf_s; +static PieceFilter pf_m; +static PieceFilter pf_eo; +static PieceFilter pf_co; + +static int epe_solved[4]; +static int eps_solved[4]; +static int epm_solved[4]; + +static char move_string[NMOVES][7]; +static char edge_string[12][7]; +static char corner_string[8][7]; +static char center_string[6][7]; + +static bool commute[NMOVES][NMOVES]; +static bool possible_next[NMOVES][NMOVES][NMOVES]; +static Move inverse_move_aux[NMOVES]; +static Trans inverse_trans_aux[NTRANS]; +static int epos_dependent_aux[BINOM12ON4][BINOM12ON4]; + +static uint16_t epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static uint16_t eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static uint16_t eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static uint16_t eo_ttable[NTRANS][POW2TO11]; +static uint16_t cp_ttable[NTRANS][FACTORIAL8]; +static uint16_t co_ttable[NTRANS][POW3TO7]; +static uint16_t cpos_ttable[NTRANS][FACTORIAL6]; +static Move moves_ttable[NTRANS][NMOVES]; + +static uint16_t epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static uint16_t eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static uint16_t eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static uint16_t eofb_mtable[NMOVES][POW2TO11]; +static uint16_t eorl_mtable[NMOVES][POW2TO11]; +static uint16_t eoud_mtable[NMOVES][POW2TO11]; +static uint16_t cp_mtable[NMOVES][FACTORIAL8]; +static uint16_t coud_mtable[NMOVES][POW3TO7]; +static uint16_t cofb_mtable[NMOVES][POW3TO7]; +static uint16_t corl_mtable[NMOVES][POW3TO7]; +static uint16_t cpos_mtable[NMOVES][FACTORIAL6]; + +static uint64_t me[12]; + +static int edge_cycle[NMOVES][12]; +static int corner_cycle[NMOVES][8]; +static int center_cycle[NMOVES][6]; +static int eofb_flipped[NMOVES][12]; +static int eorl_flipped[NMOVES][12]; +static int eoud_flipped[NMOVES][12]; +static int coud_flipped[NMOVES][8]; +static int corl_flipped[NMOVES][8]; +static int cofb_flipped[NMOVES][8]; +static Alg * equiv_alg[NMOVES]; + +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]; +static int ep_mirror[12]; +static int cp_mirror[8]; +static int cpos_mirror[6]; +static Alg * trans_algs[NROTATIONS]; + + +/* Local functions implementation ********************************************/ + +static 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 < 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; +} + +static bool +allowed_next_move(Move move, DfsData *dd) +{ + if (!possible_next[dd->last2][dd->last1][move]) + return false; + + if (commute[dd->last1][move]) + return dd->move_position[dd->last1] < dd->move_position[move]; + + return true; +} + +static void +append_alg(AlgList *l, Alg *alg) +{ + AlgListNode *node = malloc(sizeof(AlgListNode)); + int i; + + node->alg = new_alg(""); + for (i = 0; i < alg->len; i++) + append_move(node->alg, alg->move[i], alg->inv[i]); + node->next = NULL; + + if (++l->len == 1) + l->first = node; + else + l->last->next = node; + l->last = node; +} + +static void +append_move(Alg *alg, Move m, bool inverse) +{ + if (alg->len == alg->allocated) + realloc_alg(alg, 2*alg->len); + + alg->move[alg->len] = m; + alg->inv [alg->len] = inverse; + alg->len++; +} + +static Cube +apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a) +{ + Cube ret = {0}; + int i; + + for (i = 0; i < alg->len; i++) + if (alg->inv[i]) + ret = a ? apply_move(alg->move[i], ret) : + apply_move_cubearray(alg->move[i], ret, f); + + ret = compose_filtered(c, inverse_cube(ret), f); + + for (i = 0; i < alg->len; i++) + if (!alg->inv[i]) + ret = a ? apply_move(alg->move[i], ret) : + apply_move_cubearray(alg->move[i], ret, f); + + return ret; +} + +static void +apply_permutation(int *perm, int *set, int n) +{ + int *aux = malloc(n * sizeof(int)); + int i; + + if (!is_perm(perm, n)) + return; + + for (i = 0; i < n; i++) + aux[i] = set[perm[i]]; + + memcpy(set, aux, n * sizeof(int)); + free(aux); +} + +static Cube +apply_move_cubearray(Move m, Cube cube, PieceFilter f) +{ + 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); +} + +static uint16_t +array_ep_to_epos(int *ep, int *ss) +{ + 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 epos_from_arrays(epos, eps); +} + +static Cube +arrays_to_cube(CubeArray *arr, PieceFilter f) +{ + Cube ret = {0}; + + 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; +} + +static int +binomial(int n, int k) +{ + if (n < 0 || k < 0 || k > n) + return 0; + + return factorial(n) / (factorial(k) * factorial(n-k)); +} + +static Cube +compose_filtered(Cube c2, Cube c1, PieceFilter f) +{ + CubeArray *arr = new_cubearray(c2, f); + Cube ret; + + ret = move_via_arrays(arr, c1, f); + free_cubearray(arr, f); + + return ret; +} + +static void +cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f) +{ + int i; + + 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); +} + +static int +digit_array_to_int(int *a, int n, int b) +{ + int i, ret = 0, p = 1; + + for (i = 0; i < n; i++, p *= b) + ret += a[i] * p; + + return ret; +} + +static int +edge_slice(Edge e) { + if (e < 0 || e > 11) + return -1; + + if (e == FR || e == FL || e == BL || e == BR) + return 0; + if (e == UR || e == UL || e == DR || e == DL) + return 1; + + return 2; +} + +static int +epos_dependent(int poss, int pose) +{ + int ep[12] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; + int ep8[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + int i, j; + + epos_to_partial_ep(poss*FACTORIAL4, ep, eps_solved); + epos_to_partial_ep(pose*FACTORIAL4, ep, epe_solved); + + for (i = 0, j = 0; i < 12; i++) + if (edge_slice(ep[i]) != 1) + ep8[j++] = (edge_slice(ep[i]) == 0) ? 1 : 0; + + return subset_to_index(ep8, 8, 4); +} + +static uint16_t +epos_from_arrays(int *epos, int *ep) +{ + return FACTORIAL4 * subset_to_index(epos,12,4) + perm_to_index(ep,4); +} + +static void +epos_to_partial_ep(uint16_t epos, int *ep, int *ss) +{ + 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++]]; +} + +static int +factorial(int n) +{ + int i, ret = 1; + + if (n < 0) + return 0; + + for (i = 1; i <= n; i++) + ret *= i; + + return ret; +} + +void +free_alg(Alg *alg) +{ + free(alg->move); + free(alg->inv); + free(alg); +} + +void +free_alglist(AlgList *l) +{ + AlgListNode *aux, *i = l->first; + + while (i != NULL) { + aux = i->next; + free_alglistnode(i); + i = aux; + } + free(l); +} + +void +free_alglistnode(AlgListNode *aln) +{ + free_alg(aln->alg); + free(aln); +} + +static void +free_cubearray(CubeArray *arr, PieceFilter f) +{ + 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); +} + +static void +generate_ctable_dfs(Cube c, CacheData *cd, DfsData *dd) +{ + int i; + bool flag; + Move move, l1 = dd->last1, l2 = dd->last2; + + if (dd->current_alg->len > 0) { + for (i = 0, flag = true; i < cd->nind; i++) { + if (cd->index[i](c) != cd->index[i]((Cube){0})) { + flag = false; + break; + } + } + if (flag) + return; + } + + if (dd->current_alg->len == dd->d) { + push_cachenode(cd, c, dd->current_alg); + return; + } + + for (i = 0; dd->sorted_moves[i] != NULLMOVE; i++) { + move = dd->sorted_moves[i]; + if (allowed_next_move(move, dd)) { + dd->last2 = dd->last1; + dd->last1 = move; + append_move(dd->current_alg, move, false); + generate_ctable_dfs(apply_move(move, c), cd, dd); + dd->current_alg->len--; + dd->last2 = l2; + dd->last1 = l1; + } + } +} + +static void +generate_ptable_dfs(Cube c, PruneData *pd, DfsData *dd) +{ + uint64_t ind = pd->index(c); + int oldval = PTABLEVAL(pd->ptable, ind); + Move i, move, l1 = dd->last1, l2 = dd->last2; + + if (oldval < dd->m || PTABLEVAL(pd->reached, ind) || pd->n == pd->size) + return; + + ptable_set_reached(pd, ind); + + if (dd->m == dd->d) { + if (dd->m < oldval) + ptable_update(pd, ind, dd->m); + return; + } + + dd->m++; + for (i = 0; dd->sorted_moves[i] != NULLMOVE; i++) { + move = dd->sorted_moves[i]; + if (allowed_next_move(move, dd)) { + dd->last2 = dd->last1; + dd->last1 = move; + generate_ptable_dfs(apply_move(move, c), pd, dd); + dd->last2 = l2; + dd->last1 = l1; + } + } + + dd->m--; + dd->last1 = l1; + dd->last2 = l2; +} + +static void +index_to_perm(int p, int n, int *r) +{ + int *a = malloc(n * sizeof(int)); + int i, j, c; + + for (i = 0; i < n; i++) + a[i] = 0; + + if (p < 0 || p >= factorial(n)) + for (i = 0; i < n; i++) + r[i] = -1; + + for (i = 0; i < n; i++) { + c = 0; + j = 0; + while (c <= p / factorial(n-i-1)) + c += a[j++] ? 0 : 1; + r[i] = j-1; + a[j-1] = 1; + p %= factorial(n-i-1); + } + + free(a); +} + +static void +index_to_subset(int s, int n, int k, int *r) +{ + int i, j, v; + + if (s < 0 || s >= binomial(n, k)) { + for (i = 0; i < n; i++) + r[i] = -1; + return; + } + + for (i = 0; i < n; i++) { + if (k == n-i) { + for (j = i; j < n; j++) + r[j] = 1; + return; + } + + if (k == 0) { + for (j = i; j < n; j++) + r[j] = 0; + return; + } + + v = binomial(n-i-1, k); + if (s >= v) { + r[i] = 1; + k--; + s -= v; + } else { + r[i] = 0; + } + } +} + +static void +int_to_digit_array(int a, int b, int n, int *r) +{ + int i; + + if (b <= 1) + for (i = 0; i < n; i++) + r[i] = 0; + else + for (i = 0; i < n; i++, a /= b) + r[i] = a % b; +} + +static void +int_to_sum_zero_array(int x, int b, int n, int *a) +{ + int i, s = 0; + + if (b <= 1) { + for (i = 0; i < n; i++) + a[i] = 0; + } else { + int_to_digit_array(x, b, n-1, a); + for (i = 0; i < n - 1; i++) + s = (s + a[i]) % b; + a[n-1] = (b - s) % b; + } +} + +static int +invert_digits(int a, int b, int n) +{ + int i, ret, *r = malloc(n * sizeof(int)); + + int_to_digit_array(a, b, n, r); + for (i = 0; i < n; i++) + r[i] = (b-r[i]) % b; + + ret = digit_array_to_int(r, n, b); + free(r); + return ret; +} + +static bool +is_perm(int *a, int n) +{ + int *aux = malloc(n * sizeof(int)); + int i; + + for (i = 0; i < n; i++) + if (a[i] < 0 || a[i] >= n) + return false; + else + aux[a[i]] = 1; + + for (i = 0; i < n; i++) + if (!aux[i]) + return false; + + free(aux); + + return true; +} + +static bool +is_subset(int *a, int n, int k) +{ + int i, sum = 0; + + for (i = 0; i < n; i++) + sum += a[i] ? 1 : 0; + + return sum == k; +} + +static Cube +move_via_arrays(CubeArray *arr, Cube c, PieceFilter f) +{ + CubeArray *arrc = new_cubearray(c, f); + Cube ret; + + 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; +} + +static void +movelist_to_position(Move *movelist, int *position) +{ + Move m; + + for (m = 0; m < NMOVES && movelist[m] != NULLMOVE; m++) + position[movelist[m]] = m; +} + +static void +moveset_to_list(bool (*ms)(Move m), int (*f)(Cube), Move *r) +{ + Cube c; + int b[NMOVES]; + int na = 0, nb = 0; + Move i; + + if (ms == NULL) { + fprintf(stderr, "Error: no moveset given\n"); + return; + } + + for (i = U; i < NMOVES; i++) { + if (ms(i)) { + c = apply_move(i, (Cube){0}); + if (f != NULL && f(c)) + r[na++] = i; + else + b[nb++] = i; + } + } + + memcpy(r + na, b, nb * sizeof(Move)); + r[na+nb] = NULLMOVE; +} + +static AlgList * +new_alglist() +{ + AlgList *ret = malloc(sizeof(AlgList)); + + ret->len = 0; + ret->first = NULL; + ret->last = NULL; + + return ret; +} + +static CubeArray * +new_cubearray(Cube cube, PieceFilter f) +{ + 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; +} + +static int +perm_sign(int *a, int n) +{ + int i, j, ret = 0; + + if (!is_perm(a,n)) + return -1; + + for (i = 0; i < n; i++) + for (j = i+1; j < n; j++) + ret += (a[i] > a[j]) ? 1 : 0; + + return ret % 2; +} + +static int +perm_to_index(int *a, int n) +{ + int i, j, c, ret = 0; + + if (!is_perm(a, n)) + return -1; + + for (i = 0; i < n; i++) { + c = 0; + for (j = i+1; j < n; j++) + c += (a[i] > a[j]) ? 1 : 0; + ret += factorial(n-i-1) * c; + } + + return ret; +} + +/* +static int +powint(int a, int b) +{ + if (b < 0) + return 0; + if (b == 0) + return 1; + + if (b % 2) + return a * powint(a, b-1); + else + return powint(a*a, b/2); +} +*/ + +static void +ptable_set_reached(PruneData *pd, uint64_t ind) +{ + uint8_t oldval2 = pd->reached[ind/2]; + int other = ind % 2 ? oldval2 % 16 : oldval2 / 16; + + pd->reached[ind/2] = ind % 2 ? 16 + other : 16*other + 1; +} + +static void +ptable_update(PruneData *pd, uint64_t ind, int n) +{ + uint8_t oldval2 = pd->ptable[ind/2]; + int other = ind % 2 ? oldval2 % 16 : oldval2 / 16; + + pd->ptable[ind/2] = ind % 2 ? 16*n + other : 16*other + n; + pd->n++; +} + +static void +push_cachenode(CacheData *cd, Cube c, Alg *alg) +{ + CacheNode *node = malloc(sizeof(CacheNode)); + uint64_t ind0 = cd->index[0](c); + int i; + + node->indexval = malloc((cd->nind - 1) * sizeof(uint64_t)); + for (i = 1; i < cd->nind; i++) + node->indexval[i-1] = cd->index[i](c); + + node->sol = inverse_alg(alg); + realloc_alg(node->sol, cd->len); + node->next = cd->ctable[ind0]; + cd->ctable[ind0] = node; +} + +static void +realloc_alg(Alg *alg, int n) +{ + if (alg == NULL) { + fprintf(stderr, "Error: trying to reallocate NULL alg.\n"); + return; + } + + if (n < alg->len) { + fprintf(stderr, "Error: alg too long for reallocation "); + fprintf(stderr, "(%d vs %d)\n", alg->len, n); + return; + } + + if (n > 1000000) { + fprintf(stderr, "Warning: very long alg,"); + fprintf(stderr, "something might go wrong.\n"); + } + + alg->move = realloc(alg->move, n); + alg->inv = realloc(alg->inv, n); + alg->allocated = n; +} + +static bool +read_ctable_file(CacheData *cd) +{ + return false; +} + +static bool +read_mtables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int m, b = sizeof(uint16_t); + bool r = true; + + 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 +read_ptable_file(PruneData *pd) +{ + FILE *f; + char fname[strlen(tabledir)+100]; + uint64_t r; + + strcpy(fname, tabledir); + strcat(fname, "/"); + strcat(fname, pd->filename); + + if ((f = fopen(fname, "rb")) == NULL) + return false; + + r = fread(pd->ptable, sizeof(uint8_t), PTABLESIZE(pd->size), f); + fclose(f); + + return r == PTABLESIZE(pd->size); +} + +static bool +read_ttables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int b = sizeof(uint16_t); + bool r = true; + Move m; + + 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[6], f) == me[6]; + r = r && fread(co_ttable[m], b, me[7], f) == me[7]; + r = r && fread(cpos_ttable[m], b, me[10], f) == me[10]; + r = r && fread(moves_ttable[m], b, me[11], f) == me[11]; + } + + fclose(f); + return r; +} + +static Cube +rotate_via_compose(Trans r, Cube c, PieceFilter f) +{ + Alg *inv; + 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 + }; + + Cube ret; + + if (r != mirror) { + ret = apply_alg_generic(trans_algs[r], c, f, true); + inv = on_inverse(trans_algs[r]); + ret = apply_alg_generic(inv, ret, f, true); + free_alg(inv); + } else { + ret = move_via_arrays(&ma, (Cube){0}, f); + ret = compose_filtered(c, ret, f); + ret = move_via_arrays(&ma, ret, f); + } + + return ret; +} + +static void +solve_cd(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + int j, k; + bool flag; + uint64_t ind0; + CacheNode *i; + + if (!s.cd->generated) + generate_ctable(s.cd); + + ind0 = s.cd->index[0](c); + for (i = s.cd->ctable[ind0]; + i != NULL && dd->sols->len < opts->max_solutions; + i = i->next) { + for (j = 1, flag = true; j < s.cd->nind; j++) { + if (s.cd->index[j](c) != i->indexval[j-1]) { + flag = false; + break; + } + } + if (flag) { + for (k = 0; k < s.cd->len; k++) + append_move(dd->current_alg, + i->sol->move[k], dd->niss); + append_alg(dd->sols, dd->current_alg); + if (opts->feedback) { + printf("[cached] "); + print_alg(dd->current_alg, false); + } + } + } +} + +static void +solve_dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + Move move, l1 = dd->last1, l2 = dd->last2; + int i, lower_bound; + bool nissbackup = dd->niss; + + if (dd->sols->len >= opts->max_solutions) + return; + + lower_bound = s.check(c); + if (opts->can_niss && !dd->niss) + lower_bound = MIN(1, lower_bound); + + if (dd->current_alg->len + lower_bound > dd->d) + return; + + if (lower_bound == 0) { + if (dd->current_alg->len == dd->d) { + append_alg(dd->sols, dd->current_alg); + if (opts->feedback) + print_alg(dd->current_alg, false); + } + return; + } + + if (s.cd != NULL && s.cd->len == dd->d - dd->current_alg->len) { + solve_cd(c, s, opts, dd); + } else { + for (i = 0; + dd->sorted_moves[i] != NULLMOVE && + dd->sols->len < opts->max_solutions; + i++) { + move = dd->sorted_moves[i]; + if (allowed_next_move(move, dd)) { + dd->last2 = dd->last1; + dd->last1 = move; + append_move(dd->current_alg, move, dd->niss); + solve_dfs(apply_move(move, c), s, opts, dd); + dd->current_alg->len--; + dd->last2 = l2; + dd->last1 = l1; + } + } + } + + if (opts->can_niss && !dd->niss) { + if (dd->current_alg->len == 0 || + (s.check(apply_move(inverse_move(l1), (Cube){0})))) { + dd->niss = true; + dd->last1 = NULLMOVE; + dd->last2 = NULLMOVE; + solve_dfs(inverse_cube(c), s, opts, dd); + } + } + + dd->last1 = l1; + dd->last2 = l2; + dd->niss = nissbackup; +} + +static int +subset_to_index(int *a, int n, int k) +{ + int i, ret = 0; + + if (!is_subset(a, n, k)) + return binomial(n, k); + + for (i = 0; i < n; i++) { + if (k == n-i) + return ret; + if (a[i]) { + ret += binomial(n-i-1, k); + k--; + } + } + + return ret; +} + +static void +sum_arrays_mod(int *src, int *dst, int n, int m) +{ + int i; + + for (i = 0; i < n; i++) + dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m; +} + +static void +swap(int *a, int *b) +{ + int aux; + + aux = *a; + *a = *b; + *b = aux; +} + +static bool +write_ctable_file(CacheData *cd) +{ + return false; +} + +static bool +write_mtables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int m, b = sizeof(uint16_t); + bool r = true; + + 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; +} + +static bool +write_ptable_file(PruneData *pd) +{ + FILE *f; + char fname[strlen(tabledir)+100]; + uint64_t written; + + strcpy(fname, tabledir); + strcat(fname, "/"); + strcat(fname, pd->filename); + + if ((f = fopen(fname, "wb")) == NULL) + return false; + + written = fwrite(pd->ptable, sizeof(uint8_t), PTABLESIZE(pd->size), f); + fclose(f); + + return written == PTABLESIZE(pd->size); +} + +static bool +write_ttables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + bool r = true; + int b = sizeof(uint16_t); + Move m; + + 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[6], f) == me[6]; + r = r && fwrite(co_ttable[m], b, me[7], f) == me[7]; + r = r && fwrite(cpos_ttable[m], b, me[10], f) == me[10]; + r = r && fwrite(moves_ttable[m], b, me[11], f) == me[11]; + } + + fclose(f); + return r; +} + +/* Init functions implementation *********************************************/ + +static void +init_auxtables() +{ + Cube c1, c2; + uint64_t ui, uj; + int i, j, k; + bool cij, p1, p2; + + for (ui = 0; ui < BINOM12ON4; ui++) + for (uj = 0; uj < BINOM12ON4; uj++) + epos_dependent_aux[ui][uj] = epos_dependent(ui, uj); + + for (i = 0; i < NMOVES; i++) { + for (j = 0; j < NMOVES; j++) { + c1 = apply_move(i, apply_move(j, (Cube){0})); + c2 = apply_move(j, apply_move(i, (Cube){0})); + commute[i][j] = equal(c1, c2) && i && j; + } + } + + for (i = 0; i < NMOVES; i++) { + for (j = 0; j < NMOVES; j++) { + for (k = 0; k < NMOVES; k++) { + p1 = j && base_move(j) == base_move(k); + p2 = i && base_move(i) == base_move(k); + cij = commute[i][j]; + possible_next[i][j][k] = !(p1 || (cij && p2)); + } + } + } + + for (i = 0; i < NMOVES; i++) + inverse_move_aux[i] = i ? i + 2 - 2*((i-1)%3) : NULLMOVE; + + /* Is there a more elegant way? */ + inverse_trans_aux[uf] = uf; + inverse_trans_aux[ur] = ul; + inverse_trans_aux[ul] = ur; + inverse_trans_aux[ub] = ub; + + inverse_trans_aux[df] = df; + inverse_trans_aux[dr] = dr; + inverse_trans_aux[dl] = dl; + inverse_trans_aux[db] = db; + + inverse_trans_aux[rf] = lf; + inverse_trans_aux[rd] = bl; + inverse_trans_aux[rb] = rb; + inverse_trans_aux[ru] = fr; + + inverse_trans_aux[lf] = rf; + inverse_trans_aux[ld] = br; + inverse_trans_aux[lb] = lb; + inverse_trans_aux[lu] = fl; + + inverse_trans_aux[fu] = fu; + inverse_trans_aux[fr] = ru; + inverse_trans_aux[fd] = bu; + inverse_trans_aux[fl] = lu; + + inverse_trans_aux[bu] = fd; + inverse_trans_aux[br] = ld; + inverse_trans_aux[bd] = bd; + inverse_trans_aux[bl] = rd; + + inverse_trans_aux[mirror] = mirror; +} + +static void +init_environment() +{ + char *nissydata = getenv("NISSYDATA"); + char *localdata = getenv("XDG_DATA_HOME"); + char *home = getenv("HOME"); + bool read, write; + + if (nissydata != NULL) { + tabledir = malloc(strlen(nissydata) * sizeof(char) + 20); + strcpy(tabledir, nissydata); + } else if (localdata != NULL) { + tabledir = malloc(strlen(localdata) * sizeof(char) + 20); + strcpy(tabledir, localdata); + strcat(tabledir, "/nissy"); + } else if (home != NULL) { + tabledir = malloc(strlen(home) * sizeof(char) + 20); + strcpy(tabledir, home); + strcat(tabledir, "/.nissy"); + } + + mkdir(tabledir, 0777); + strcat(tabledir, "/tables"); + mkdir(tabledir, 0777); + + read = !access(tabledir, R_OK); + write = !access(tabledir, W_OK); + + if (!read) { + fprintf(stderr, "Table files cannot be read.\n"); + } else if (!write) { + fprintf(stderr, "Data directory not writable: "); + fprintf(stderr, "tables can be loaded, but not saved.\n"); + } +} + +static void +init_moves() { + Cube c; + CubeArray arrs; + int i; + uint16_t ui; + Move m; + + /* 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; + + fprintf(stderr, "Cannot load %s, generating it\n", "mtables"); + + /* Initialize transition tables */ + for (m = 0; m < NMOVES; m++) { + 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; + } + } + + if (!write_mtables_file()) + fprintf(stderr, "Error writing mtables\n"); +} + +static void +init_moves_aux() +{ + /* Some standard PieceFilters */ + pf_all.epose = true; + pf_all.eposs = true; + pf_all.eposm = true; + pf_all.eofb = true; + pf_all.eorl = true; + pf_all.eoud = true; + pf_all.cp = true; + pf_all.cofb = true; + pf_all.corl = true; + pf_all.coud = true; + pf_all.cpos = true; + + pf_4val.epose = true; + pf_4val.eposs = true; + pf_4val.eposm = true; + pf_4val.eofb = true; + pf_4val.coud = true; + pf_4val.cp = true; + + pf_epcp.epose = true; + pf_epcp.eposs = true; + pf_epcp.eposm = true; + pf_epcp.cp = true; + + pf_cpos.cpos = true; + + pf_cp.cp = true; + + pf_ep.epose = true; + pf_ep.eposs = true; + pf_ep.eposm = true; + + pf_e.epose = true; + pf_s.eposs = true; + pf_m.eposm = true; + + pf_eo.eofb = true; + pf_eo.eorl = true; + pf_eo.eoud = true; + + pf_co.cofb = true; + pf_co.corl = true; + pf_co.coud = true; + + /* Used to convert to and from CubeArray */ + epe_solved[0] = FR; + epe_solved[1] = FL; + epe_solved[2] = BL; + epe_solved[3] = BR; + + eps_solved[0] = UL; + eps_solved[1] = UR; + eps_solved[2] = DL; + eps_solved[3] = DR; + + epm_solved[0] = UF; + epm_solved[1] = UB; + epm_solved[2] = DF; + epm_solved[3] = DB; + + /* Table sizes, used for reading and writing files */ + me[0] = FACTORIAL12/FACTORIAL8; + me[1] = FACTORIAL12/FACTORIAL8; + me[2] = FACTORIAL12/FACTORIAL8; + me[3] = POW2TO11; + me[4] = POW2TO11; + me[5] = POW2TO11; + me[6] = FACTORIAL8; + me[7] = POW3TO7; + me[8] = POW3TO7; + me[9] = POW3TO7; + me[10] = FACTORIAL6; + me[11] = NMOVES; + + /* Cycles *********************/ + edge_cycle[U][UF] = UR; + edge_cycle[U][UL] = UF; + edge_cycle[U][UB] = UL; + edge_cycle[U][UR] = UB; + edge_cycle[U][DF] = DF; + edge_cycle[U][DL] = DL; + edge_cycle[U][DB] = DB; + edge_cycle[U][DR] = DR; + edge_cycle[U][FR] = FR; + edge_cycle[U][FL] = FL; + edge_cycle[U][BL] = BL; + edge_cycle[U][BR] = BR; + + edge_cycle[x][UF] = DF; + edge_cycle[x][UL] = FL; + edge_cycle[x][UB] = UF; + edge_cycle[x][UR] = FR; + edge_cycle[x][DF] = DB; + edge_cycle[x][DL] = BL; + edge_cycle[x][DB] = UB; + edge_cycle[x][DR] = BR; + edge_cycle[x][FR] = DR; + edge_cycle[x][FL] = DL; + edge_cycle[x][BL] = UL; + edge_cycle[x][BR] = UR; + + edge_cycle[y][UF] = UR; + edge_cycle[y][UL] = UF; + edge_cycle[y][UB] = UL; + edge_cycle[y][UR] = UB; + edge_cycle[y][DF] = DR; + edge_cycle[y][DL] = DF; + edge_cycle[y][DB] = DL; + edge_cycle[y][DR] = DB; + edge_cycle[y][FR] = BR; + edge_cycle[y][FL] = FR; + edge_cycle[y][BL] = FL; + edge_cycle[y][BR] = BL; + + corner_cycle[U][UFR] = UBR; + corner_cycle[U][UFL] = UFR; + corner_cycle[U][UBL] = UFL; + corner_cycle[U][UBR] = UBL; + corner_cycle[U][DFR] = DFR; + corner_cycle[U][DFL] = DFL; + corner_cycle[U][DBL] = DBL; + corner_cycle[U][DBR] = DBR; + + corner_cycle[x][UFR] = DFR; + corner_cycle[x][UFL] = DFL; + corner_cycle[x][UBL] = UFL; + corner_cycle[x][UBR] = UFR; + corner_cycle[x][DFR] = DBR; + corner_cycle[x][DFL] = DBL; + corner_cycle[x][DBL] = UBL; + corner_cycle[x][DBR] = UBR; + + corner_cycle[y][UFR] = UBR; + corner_cycle[y][UFL] = UFR; + corner_cycle[y][UBL] = UFL; + corner_cycle[y][UBR] = UBL; + corner_cycle[y][DFR] = DBR; + corner_cycle[y][DFL] = DFR; + corner_cycle[y][DBL] = DFL; + corner_cycle[y][DBR] = DBL; + + center_cycle[U][U_center] = U_center; + center_cycle[U][D_center] = D_center; + center_cycle[U][R_center] = R_center; + center_cycle[U][L_center] = L_center; + center_cycle[U][F_center] = F_center; + center_cycle[U][B_center] = B_center; + + center_cycle[x][U_center] = F_center; + center_cycle[x][D_center] = B_center; + center_cycle[x][R_center] = R_center; + center_cycle[x][L_center] = L_center; + center_cycle[x][F_center] = D_center; + center_cycle[x][B_center] = U_center; + + center_cycle[y][U_center] = U_center; + center_cycle[y][D_center] = D_center; + center_cycle[y][R_center] = B_center; + center_cycle[y][L_center] = F_center; + center_cycle[y][F_center] = R_center; + center_cycle[y][B_center] = L_center; + + /* Flipped pieces *************/ + eofb_flipped[x][UF] = 1; + eofb_flipped[x][UB] = 1; + eofb_flipped[x][DF] = 1; + eofb_flipped[x][DB] = 1; + + eofb_flipped[y][FR] = 1; + eofb_flipped[y][FL] = 1; + eofb_flipped[y][BL] = 1; + eofb_flipped[y][BR] = 1; + + eorl_flipped[x][UF] = 1; + eorl_flipped[x][UL] = 1; + eorl_flipped[x][UB] = 1; + eorl_flipped[x][UR] = 1; + eorl_flipped[x][DF] = 1; + eorl_flipped[x][DL] = 1; + eorl_flipped[x][DB] = 1; + eorl_flipped[x][DR] = 1; + eorl_flipped[x][FR] = 1; + eorl_flipped[x][FL] = 1; + eorl_flipped[x][BL] = 1; + eorl_flipped[x][BR] = 1; + + eorl_flipped[y][FR] = 1; + eorl_flipped[y][FL] = 1; + eorl_flipped[y][BL] = 1; + eorl_flipped[y][BR] = 1; + + eoud_flipped[U][UF] = 1; + eoud_flipped[U][UL] = 1; + eoud_flipped[U][UB] = 1; + eoud_flipped[U][UR] = 1; + + eoud_flipped[x][UF] = 1; + eoud_flipped[x][UB] = 1; + eoud_flipped[x][DF] = 1; + eoud_flipped[x][DB] = 1; + + eoud_flipped[y][UF] = 1; + eoud_flipped[y][UL] = 1; + eoud_flipped[y][UB] = 1; + eoud_flipped[y][UR] = 1; + eoud_flipped[y][DF] = 1; + eoud_flipped[y][DL] = 1; + eoud_flipped[y][DB] = 1; + eoud_flipped[y][DR] = 1; + eoud_flipped[y][FR] = 1; + eoud_flipped[y][FL] = 1; + eoud_flipped[y][BL] = 1; + eoud_flipped[y][BR] = 1; + + coud_flipped[x][UFR] = 2; + coud_flipped[x][UFL] = 1; + coud_flipped[x][UBR] = 1; + coud_flipped[x][UBL] = 2; + coud_flipped[x][DFR] = 1; + coud_flipped[x][DFL] = 2; + coud_flipped[x][DBR] = 2; + coud_flipped[x][DBL] = 1; + + corl_flipped[U][UFR] = 1; + corl_flipped[U][UFL] = 2; + corl_flipped[U][UBL] = 1; + corl_flipped[U][UBR] = 2; + + corl_flipped[y][UFR] = 1; + corl_flipped[y][UFL] = 2; + corl_flipped[y][UBL] = 1; + corl_flipped[y][UBR] = 2; + corl_flipped[y][DFR] = 2; + corl_flipped[y][DFL] = 1; + corl_flipped[y][DBL] = 2; + corl_flipped[y][DBR] = 1; + + cofb_flipped[U][UFR] = 2; + cofb_flipped[U][UFL] = 1; + cofb_flipped[U][UBL] = 2; + cofb_flipped[U][UBR] = 1; + + cofb_flipped[x][UFR] = 1; + cofb_flipped[x][UFL] = 2; + cofb_flipped[x][UBL] = 1; + cofb_flipped[x][UBR] = 2; + cofb_flipped[x][DFR] = 2; + cofb_flipped[x][DFL] = 1; + cofb_flipped[x][DBL] = 2; + cofb_flipped[x][DBR] = 1; + + cofb_flipped[y][UFR] = 2; + cofb_flipped[y][UFL] = 1; + cofb_flipped[y][UBL] = 2; + cofb_flipped[y][UBR] = 1; + cofb_flipped[y][DFR] = 1; + cofb_flipped[y][DFL] = 2; + cofb_flipped[y][DBL] = 1; + cofb_flipped[y][DBR] = 2; + + /* Equivalent moves ***********/ + equiv_alg[NULLMOVE] = new_alg(""); + + equiv_alg[U] = new_alg(" U "); + equiv_alg[U2] = new_alg(" UU "); + equiv_alg[U3] = new_alg(" UUU "); + equiv_alg[D] = new_alg(" xx U xx "); + equiv_alg[D2] = new_alg(" xx UU xx "); + equiv_alg[D3] = new_alg(" xx UUU xx "); + equiv_alg[R] = new_alg(" yx U xxxyyy "); + equiv_alg[R2] = new_alg(" yx UU xxxyyy "); + equiv_alg[R3] = new_alg(" yx UUU xxxyyy "); + equiv_alg[L] = new_alg(" yyyx U xxxy "); + equiv_alg[L2] = new_alg(" yyyx UU xxxy "); + equiv_alg[L3] = new_alg(" yyyx UUU xxxy "); + equiv_alg[F] = new_alg(" x U xxx "); + equiv_alg[F2] = new_alg(" x UU xxx "); + equiv_alg[F3] = new_alg(" x UUU xxx "); + equiv_alg[B] = new_alg(" xxx U x "); + equiv_alg[B2] = new_alg(" xxx UU x "); + equiv_alg[B3] = new_alg(" xxx UUU x "); + + equiv_alg[Uw] = new_alg(" xx U xx y "); + equiv_alg[Uw2] = new_alg(" xx UU xx yy "); + equiv_alg[Uw3] = new_alg(" xx UUU xx yyy "); + equiv_alg[Dw] = new_alg(" U yyy "); + equiv_alg[Dw2] = new_alg(" UU yy "); + equiv_alg[Dw3] = new_alg(" UUU y "); + equiv_alg[Rw] = new_alg(" yyyx U xxxy x "); + equiv_alg[Rw2] = new_alg(" yyyx UU xxxy xx "); + equiv_alg[Rw3] = new_alg(" yyyx UUU xxxy xxx "); + equiv_alg[Lw] = new_alg(" yx U xxxyyy xxx "); + equiv_alg[Lw2] = new_alg(" yx UU xxxyyy xx "); + equiv_alg[Lw3] = new_alg(" yx UUU xxxyyy x "); + equiv_alg[Fw] = new_alg(" xxx U x yxxxyyy "); + equiv_alg[Fw2] = new_alg(" xxx UU x yxxyyy "); + equiv_alg[Fw3] = new_alg(" xxx UUU x yxyyy "); + equiv_alg[Bw] = new_alg(" x U xxx yxyyy "); + equiv_alg[Bw2] = new_alg(" x UU xxx yxxyyy "); + equiv_alg[Bw3] = new_alg(" x UUU xxx yxxxyyy "); + + equiv_alg[M] = new_alg(" yx U xx UUU yxyyy "); + equiv_alg[M2] = new_alg(" yx UU xx UU xxxy "); + equiv_alg[M3] = new_alg(" yx UUU xx U yxxxy "); + equiv_alg[S] = new_alg(" x UUU xx U yyyx "); + equiv_alg[S2] = new_alg(" x UU xx UU yyx "); + equiv_alg[S3] = new_alg(" x U xx UUU yx "); + equiv_alg[E] = new_alg(" U xx UUU xxyyy "); + equiv_alg[E2] = new_alg(" UU xx UU xxyy "); + equiv_alg[E3] = new_alg(" UUU xx U xxy "); + + equiv_alg[x] = new_alg(" x "); + equiv_alg[x2] = new_alg(" xx "); + equiv_alg[x3] = new_alg(" xxx "); + equiv_alg[y] = new_alg(" y "); + equiv_alg[y2] = new_alg(" yy "); + equiv_alg[y3] = new_alg(" yyy "); + equiv_alg[z] = new_alg(" yyy x y "); + equiv_alg[z2] = new_alg(" yy xx "); + equiv_alg[z3] = new_alg(" y x yyy "); +} + +static void +init_strings() +{ + strcpy(move_string [NULLMOVE], "-" ); + strcpy(move_string [U], "U" ); + strcpy(move_string [U2], "U2" ); + strcpy(move_string [U3], "U\'" ); + strcpy(move_string [D], "D" ); + strcpy(move_string [D2], "D2" ); + strcpy(move_string [D3], "D\'" ); + strcpy(move_string [R], "R" ); + strcpy(move_string [R2], "R2" ); + strcpy(move_string [R3], "R\'" ); + strcpy(move_string [L], "L" ); + strcpy(move_string [L2], "L2" ); + strcpy(move_string [L3], "L\'" ); + strcpy(move_string [F], "F" ); + strcpy(move_string [F2], "F2" ); + strcpy(move_string [F3], "F\'" ); + strcpy(move_string [B], "B" ); + strcpy(move_string [B2], "B2" ); + strcpy(move_string [B3], "B\'" ); + strcpy(move_string [Uw], "Uw" ); + strcpy(move_string [Uw2], "Uw2" ); + strcpy(move_string [Uw3], "Uw\'" ); + strcpy(move_string [Dw], "Dw" ); + strcpy(move_string [Dw2], "Dw2" ); + strcpy(move_string [Dw3], "Dw\'" ); + strcpy(move_string [Rw], "Rw" ); + strcpy(move_string [Rw2], "Rw2" ); + strcpy(move_string [Rw3], "Rw\'" ); + strcpy(move_string [Lw], "Lw" ); + strcpy(move_string [Lw2], "Lw2" ); + strcpy(move_string [Lw3], "Lw\'" ); + strcpy(move_string [Fw], "Fw" ); + strcpy(move_string [Fw2], "Fw2" ); + strcpy(move_string [Fw3], "Fw\'" ); + strcpy(move_string [Bw], "Bw" ); + strcpy(move_string [Bw2], "Bw2" ); + strcpy(move_string [Bw3], "Bw\'" ); + strcpy(move_string [M], "M" ); + strcpy(move_string [M2], "M2" ); + strcpy(move_string [M3], "M\'" ); + strcpy(move_string [S], "S" ); + strcpy(move_string [S2], "S2" ); + strcpy(move_string [S3], "S\'" ); + strcpy(move_string [E], "E" ); + strcpy(move_string [E2], "E2" ); + strcpy(move_string [E3], "E\'" ); + strcpy(move_string [x], "x" ); + strcpy(move_string [x2], "x2" ); + strcpy(move_string [x3], "x\'" ); + strcpy(move_string [y], "y" ); + strcpy(move_string [y2], "y2" ); + strcpy(move_string [y3], "y\'" ); + strcpy(move_string [z], "z" ); + strcpy(move_string [z2], "z2" ); + strcpy(move_string [z3], "z\'" ); + + strcpy(edge_string [UF], "UF" ); + strcpy(edge_string [UL], "UL" ); + strcpy(edge_string [UB], "UB" ); + strcpy(edge_string [UR], "UR" ); + strcpy(edge_string [DF], "DF" ); + strcpy(edge_string [DL], "DL" ); + strcpy(edge_string [DB], "DB" ); + strcpy(edge_string [DR], "DR" ); + strcpy(edge_string [FR], "FR" ); + strcpy(edge_string [FL], "FL" ); + strcpy(edge_string [BL], "BL" ); + strcpy(edge_string [BR], "BR" ); + + strcpy(corner_string [UFR], "UFR" ); + strcpy(corner_string [UFL], "UFL" ); + strcpy(corner_string [UBL], "UBL" ); + strcpy(corner_string [UBR], "UBR" ); + strcpy(corner_string [DFR], "DFR" ); + strcpy(corner_string [DFL], "DFL" ); + strcpy(corner_string [DBL], "DBL" ); + strcpy(corner_string [DBR], "DBR" ); + + strcpy(center_string [U_center], "U" ); + strcpy(center_string [D_center], "D" ); + strcpy(center_string [R_center], "R" ); + strcpy(center_string [L_center], "L" ); + strcpy(center_string [F_center], "F" ); + strcpy(center_string [B_center], "B" ); +} + +static void +init_trans() { + Cube aux, cube, c[3]; + CubeArray epcp; + int eparr[12], eoarr[12]; + int cparr[8], coarr[8]; + int i; + bool b1, b2, b3; + uint16_t ui; + Move mi, move; + Trans m; + + /* Compute sources */ + for (i = 0; i < NTRANS; i++) { + if (i == mirror) + cube = (Cube){0}; + else + cube = apply_alg(trans_algs[i], (Cube){0}); + + epose_source[i] = edge_slice(edge_at(cube, FR)); + eposs_source[i] = edge_slice(edge_at(cube, UR)); + eposm_source[i] = edge_slice(edge_at(cube, UF)); + eofb_source[i] = center_at(cube, F_center)/2; + eorl_source[i] = center_at(cube, R_center)/2; + eoud_source[i] = center_at(cube, U_center)/2; + coud_source[i] = center_at(cube, U_center)/2; + cofb_source[i] = center_at(cube, F_center)/2; + corl_source[i] = center_at(cube, R_center)/2; + } + + if (read_ttables_file()) + return; + + fprintf(stderr, "Cannot load %s, generating it\n", "ttables"); + + /* Initialize tables */ + for (m = 0; m < NTRANS; m++) { + if (m == mirror) { + memcpy(eparr, ep_mirror, 12 * sizeof(int)); + memcpy(cparr, cp_mirror, 8 * sizeof(int)); + } else { + epcp = (CubeArray){ .ep = eparr, .cp = cparr }; + cube = apply_alg(trans_algs[m], (Cube){0}); + cube_to_arrays(cube, &epcp, pf_epcp); + } + + 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 == mirror) + 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++) { + if (m == mirror) { + b1 = (mi >= U && mi <= Bw3); + b2 = (mi >= S && mi <= E3); + b3 = (mi >= x && mi <= z3); + if (b1 || b2 || b3) + moves_ttable[m][mi] = + inverse_move_aux[mi]; + else + moves_ttable[m][mi] = mi; + + if ((mi-1)/3==(R-1)/3 || (mi-1)/3==(Rw-1)/3) + moves_ttable[m][mi] += 3; + if ((mi-1)/3==(L-1)/3 || (mi-1)/3==(L2-1)/3) + moves_ttable[m][mi] -= 3; + } else { + aux = apply_trans(m, apply_move(mi,(Cube){0})); + for (move = 0; move < NMOVES; move++) { + cube = apply_move( + inverse_move_aux[move], aux); + if (is_solved(cube, false)) + moves_ttable[m][mi] = move; + } + } + } + } + + if (!write_ttables_file()) + fprintf(stderr, "Error writing ttables\n"); +} + +static void +init_trans_aux() +{ + ep_mirror[UF] = UF; + ep_mirror[UL] = UR; + ep_mirror[UB] = UB; + ep_mirror[UR] = UL; + ep_mirror[DF] = DF; + ep_mirror[DL] = DR; + ep_mirror[DB] = DB; + ep_mirror[DR] = DL; + ep_mirror[FR] = FL; + ep_mirror[FL] = FR; + ep_mirror[BR] = BL; + ep_mirror[BL] = BR; + + cp_mirror[UFR] = UFL; + cp_mirror[UFL] = UFR; + cp_mirror[UBL] = UBR; + cp_mirror[UBR] = UBL; + cp_mirror[DFR] = DFL; + cp_mirror[DFL] = DFR; + cp_mirror[DBL] = DBR; + cp_mirror[DBR] = DBL; + + cpos_mirror[U_center] = U_center; + cpos_mirror[D_center] = D_center; + cpos_mirror[R_center] = L_center; + cpos_mirror[L_center] = R_center; + cpos_mirror[F_center] = F_center; + cpos_mirror[B_center] = B_center; + + /* Is there a more elegant way? */ + trans_algs[uf] = new_alg(""); + trans_algs[ur] = new_alg("y"); + trans_algs[ub] = new_alg("y2"); + trans_algs[ul] = new_alg("y3"); + + trans_algs[df] = new_alg("z2"); + trans_algs[dr] = new_alg("y z2"); + trans_algs[db] = new_alg("x2"); + trans_algs[dl] = new_alg("y3 z2"); + + trans_algs[rf] = new_alg("z3"); + trans_algs[rd] = new_alg("z3 y"); + trans_algs[rb] = new_alg("z3 y2"); + trans_algs[ru] = new_alg("z3 y3"); + + trans_algs[lf] = new_alg("z"); + trans_algs[ld] = new_alg("z y3"); + trans_algs[lb] = new_alg("z y2"); + trans_algs[lu] = new_alg("z y"); + + trans_algs[fu] = new_alg("x y2"); + trans_algs[fr] = new_alg("x y"); + trans_algs[fd] = new_alg("x"); + trans_algs[fl] = new_alg("x y3"); + + trans_algs[bu] = new_alg("x3"); + trans_algs[br] = new_alg("x3 y"); + trans_algs[bd] = new_alg("x3 y2"); + trans_algs[bl] = new_alg("x3 y3"); +} + + +/* Public functions implementation *******************************************/ + +Cube +apply_alg(Alg *alg, Cube cube) +{ + return apply_alg_generic(alg, cube, pf_all, true); +} + +Cube +apply_move(Move m, Cube cube) +{ + 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] + }; +} + +Cube +apply_trans(Trans t, Cube cube) +{ + uint16_t aux_epos[3] = { cube.epose, cube.eposs, cube.eposm }; + uint16_t aux_eo[3] = { cube.eoud, cube.eorl, cube.eofb }; + uint16_t 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] + }; +} + +Move +base_move(Move m) +{ + if (m == NULLMOVE) + return NULLMOVE; + else + return m - (m-1)%3; +} + +/* TODO: this has to be changed using pre-computations */ +bool +block_solved(Cube cube, Block block) +{ + CubeArray *arr = new_cubearray(cube, pf_all); + int i; + bool ret = true; + + for (i = 0; i < 12; i++) + ret = ret && !(block.edge[i] && (arr->ep[i] != i || arr->eofb[i])); + for (i = 0; i < 8; i++) + ret = ret && !(block.corner[i] && (arr->cp[i] != i || arr->coud[i])); + for (i = 0; i < 6; i++) + ret = ret && !(block.center[i] && arr->cpos[i] != i); + + free_cubearray(arr, pf_all); + + return ret; +} + +Center +center_at(Cube cube, Center c) +{ + int ret; + CubeArray *arr = new_cubearray(cube, pf_cpos); + + ret = arr->cpos[c]; + free_cubearray(arr, pf_cpos); + + return ret; +} + +Cube +compose(Cube c2, Cube c1) +{ + return compose_filtered(c2, c1, pf_all); +} + +Corner +corner_at(Cube cube, Corner c) +{ + int ret; + CubeArray *arr = new_cubearray(cube, pf_cp); + + ret = arr->cp[c]; + free_cubearray(arr, pf_cp); + + return ret; +} + +Edge +edge_at(Cube cube, Edge e) +{ + int ret; + CubeArray *arr = new_cubearray(cube, pf_ep); + + ret = arr->ep[e]; + free_cubearray(arr, pf_ep); + + return ret; +} + +uint64_t +epos_dependent_cube(Cube c) +{ + return epos_dependent_aux[c.eposs/FACTORIAL4][c.epose/FACTORIAL4]; +} + +bool +equal(Cube c1, Cube c2) +{ + 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; +} + +void +generate_ctable(CacheData *cd) +{ + uint64_t i; + DfsData dd = { + .d = cd->len, + .last1 = NULLMOVE, + .last2 = NULLMOVE, + .current_alg = new_alg("") + }; + + if (cd->generated) + return; + + /* TODO: check if memory is enough, otherwise maybe crash gracefully? */ + cd->ctable = malloc(cd->maxind0 * sizeof(CacheNode *)); + for (i = 0; i < cd->maxind0; i++) + cd->ctable[i] = NULL; + + if (read_ctable_file(cd)) { + cd->generated = true; + return; + } + + fprintf(stderr, "Cannot load %s, generating it\n", cd->filename); + + moveset_to_list(cd->moveset, NULL, dd.sorted_moves); + movelist_to_position(dd.sorted_moves, dd.move_position); + + generate_ctable_dfs((Cube){0}, cd, &dd); + + if (!write_ctable_file(cd)) + fprintf(stderr, "Error writing ctable file\n"); + + cd->generated = true; +} + +void +generate_ptable(PruneData *pd) +{ + uint64_t j; + DfsData dd = { + .m = 0, + .last1 = NULLMOVE, + .last2 = NULLMOVE + }; + + if (pd->generated) + return; + + /* TODO: check if memory is enough, otherwise maybe crash gracefully? */ + pd->ptable = malloc(PTABLESIZE(pd->size) * sizeof(uint8_t)); + + if (read_ptable_file(pd)) { + pd->generated = true; + return; + } + + fprintf(stderr, "Cannot load %s, generating it\n", pd->filename); + + /* We use 4 bits per value, so any distance >= 15 is set to 15 */ + for (j = 0; j < pd->size; j++) + ptable_update(pd, j, 15); + + moveset_to_list(pd->moveset, NULL, dd.sorted_moves); + movelist_to_position(dd.sorted_moves, dd.move_position); + + pd->reached = malloc(PTABLESIZE(pd->size) * sizeof(uint8_t)); + for (dd.d = 0, pd->n = 0; dd.d < 15 && pd->n < pd->size; dd.d++) { + memset(pd->reached, 0, PTABLESIZE(pd->size)*sizeof(uint8_t)); + generate_ptable_dfs((Cube){0}, pd, &dd); + fprintf(stderr, "Depth %d completed, generated %lu/%lu\n", + dd.d, pd->n, pd->size); + } + + if (!write_ptable_file(pd)) + fprintf(stderr, "Error writing ptable file\n"); + + pd->generated = true; + free(pd->reached); +} + +Cube +inverse_cube(Cube cube) +{ + CubeArray *arr = new_cubearray(cube, pf_all); + CubeArray *inv = new_cubearray((Cube){0}, pf_all); + Cube ret; + int i; + + for (i = 0; i < 12; i++) { + inv->ep[arr->ep[i]] = i; + inv->eofb[arr->ep[i]] = arr->eofb[i]; + inv->eorl[arr->ep[i]] = arr->eorl[i]; + inv->eoud[arr->ep[i]] = arr->eoud[i]; + } + + for (i = 0; i < 8; i++) { + inv->cp[arr->cp[i]] = i; + inv->coud[arr->cp[i]] = (3 - arr->coud[i]) % 3; + inv->corl[arr->cp[i]] = (3 - arr->corl[i]) % 3; + inv->cofb[arr->cp[i]] = (3 - arr->cofb[i]) % 3; + } + + for (int i = 0; i < 6; i++) + inv->cpos[arr->cpos[i]] = i; + + ret = arrays_to_cube(inv, pf_all); + free_cubearray(arr, pf_all); + free_cubearray(inv, pf_all); + + return ret; +} + +Move +inverse_move(Move m) +{ + return inverse_move_aux[m]; +} + +Trans +inverse_trans(Trans t) +{ + return inverse_trans_aux[t]; +} + +bool +is_admissible(Cube cube) +{ + /* TODO: this should check consistency of different orientations */ + /* TODO: check that centers are opposite and admissible */ + + CubeArray *a = new_cubearray(cube, pf_all); + int parity; + bool perm; + + 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); + + return perm && parity % 2 == 0; +} + +bool +is_solved(Cube cube, bool reorient) +{ + Trans i; + + if (reorient) + for (i = 0; i < NROTATIONS; i++) + if (is_solved(apply_alg(trans_algs[i],cube), false)) + return true; + + return equal(cube, (Cube){0}); +} + +int +piece_orientation(Cube cube, int piece, char *orientation) +{ + int arr[12], n, b; + uint16_t 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) +{ + CubeArray *arr = new_cubearray(cube, pf_all); + + for (int i = 0; i < 12; i++) + printf(" %s ", edge_string[arr->ep[i]]); + printf("\n"); + + for (int i = 0; i < 12; i++) + printf(" %c ", arr->eofb[i] + '0'); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf("%s ", corner_string[arr->cp[i]]); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf(" %c ", arr->coud[i] + '0'); + printf("\n"); + + for (int i = 0; i < 6; i++) + printf(" %s ", center_string[arr->cpos[i]]); + printf("\n"); + + free_cubearray(arr, pf_all); +} + +Cube +random_cube() +{ + CubeArray *arr = new_cubearray((Cube){0}, pf_4val); + Cube ret; + int ep, cp, eo, co; + + ep = rand() % FACTORIAL12; + cp = rand() % FACTORIAL8; + eo = rand() % POW2TO11; + co = rand() % POW3TO7; + + index_to_perm(ep, 12, arr->ep); + index_to_perm(cp, 8, arr->cp); + int_to_sum_zero_array(eo, 2, 12, arr->eofb); + int_to_sum_zero_array(co, 3, 8, arr->coud); + + if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8)) + swap(&(arr->ep[0]), &(arr->ep[1])); + + ret = arrays_to_cube(arr, pf_4val); + free_cubearray(arr, pf_4val); + + return ret; +} + +AlgList * +solve(Cube cube, Step step, SolveOptions *opts) +{ + AlgListNode *node; + AlgList *sols = new_alglist(); + Cube c = apply_trans(opts->pre_trans, cube); + DfsData dd = { + .m = 0, + .niss = false, + .last1 = NULLMOVE, + .last2 = NULLMOVE, + .sols = sols, + .current_alg = new_alg("") + }; + + if (step.ready != NULL && !step.ready(c)) { + fprintf(stderr, "Cube not ready for solving step\n"); + return sols; + } + + moveset_to_list(step.moveset, step.check, dd.sorted_moves); + movelist_to_position(dd.sorted_moves, dd.move_position); + + for (dd.d = MAX(opts->min_moves, step.check(c)); + dd.d <= opts->max_moves && !(sols->len && opts->optimal_only); + dd.d++) { + if (opts->feedback) + fprintf(stderr, + "Found %d solutions, searching depth %d...\n", + sols->len, dd.d); + solve_dfs(c, step, opts, &dd); + } + + for (node = sols->first; node != NULL; node = node->next) + transform_alg(inverse_trans_aux[opts->pre_trans], node->alg); + + return sols; +} + +Alg * +inverse_alg(Alg *alg) +{ + Alg *ret = new_alg(""); + int i; + + for (i = alg->len-1; i >= 0; i--) + append_move(ret, alg->move[i], alg->inv[i]); + + return ret; +} + +Alg * +new_alg(char *str) +{ + Alg *alg = malloc(sizeof(Alg)); + int i; + bool niss = false; + Move j, m; + + alg->move = malloc(30 * sizeof(Move)); + alg->inv = malloc(30 * sizeof(bool)); + alg->allocated = 30; + alg->len = 0; + + for (i = 0; str[i]; i++) { + if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n') + continue; + + if (str[i] == '(' && niss) { + fprintf(stderr, "Error reading moves: nested ( )\n"); + return alg; + } + + if (str[i] == ')' && !niss) { + fprintf(stderr, "Error reading moves: unmatched )\n"); + return alg; + } + + if (str[i] == '(' || str[i] == ')') { + niss = !niss; + continue; + } + + for (j = 0; j < NMOVES; j++) { + if (str[i] == move_string[j][0]) { + m = j; + if (m <= B && str[i+1]=='w') { + m += Uw - U; + i++; + } + if (str[i+1]=='2') { + m += 1; + i++; + } else if (str[i+1]=='\'' || str[i+1]=='3') { + m += 2; + i++; + } + append_move(alg, m, niss); + break; + } + } + } + + return alg; +} + +Alg * +on_inverse(Alg *alg) +{ + Alg *ret = new_alg(""); + int i; + + for (i = 0; i < alg->len; i++) + append_move(ret, alg->move[i], !alg->inv[i]); + + return ret; +} + +void +print_alg(Alg *alg, bool l) +{ + /* TODO: make it possible to print to stdout or to string */ + /* Maybe just return a string */ + char fill[4]; + int i; + bool niss = false; + + for (i = 0; i < alg->len; i++) { + if (!niss && alg->inv[i]) + strcpy(fill, i == 0 ? "(" : " ("); + if (niss && !alg->inv[i]) + strcpy(fill, ") "); + if (niss == alg->inv[i]) + strcpy(fill, i == 0 ? "" : " "); + + printf("%s%s", fill, move_string[alg->move[i]]); + niss = alg->inv[i]; + } + + if (niss) + printf(")"); + if (l) + printf(" (%d)", alg->len); + + printf("\n"); +} + +void +print_alglist(AlgList *al, bool l) +{ + AlgListNode *i; + + for (i = al->first; i != NULL; i = i->next) + print_alg(i->alg, l); +} + +void +print_cachedata(CacheData *cd, bool printalgs) +{ + CacheNode *j; + uint64_t i, s, maxa = 0, maxs = 0, n = 0, empty = 0; + + if (!cd->generated) + generate_ctable(cd); + + for (i = 0; i < cd->maxind0; i++) { + if (cd->ctable[i] == NULL) { + empty++; + continue; + } + + for (j = cd->ctable[i], s = 0; + j != NULL; j = j->next, n++, s++) + if (printalgs) + print_alg(j->sol, false); + + if (s > maxs) { + maxs = s; + maxa = i; + } + } + + printf("Cache data %s\n", cd->filename); + printf("Length: %d\n", cd->len); + printf("Main table cells: %lu (of which %lu empty)\n", i, empty); + printf("%lu solutions cached ", n); + printf("(most crowded cell: %lu with %lu)\n", maxa, maxs); +} + +void +print_ptable(PruneData *pd) +{ + uint64_t i, a[16]; + + for (i = 0; i < 16; i++) + a[i] = 0; + + if (!pd->generated) + generate_ptable(pd); + + for (i = 0; i < pd->size; i++) + a[PTABLEVAL(pd->ptable, i)]++; + + fprintf(stderr, "Values for table %s\n", pd->filename); + for (i = 0; i < 16; i++) + printf("%2lu\t%10lu\n", i, a[i]); +} + + +Alg * +trans_alg(Trans i) +{ + return trans_algs[i]; +} + +void +transform_alg(Trans t, Alg *alg) +{ + int i; + + for (i = 0; i < alg->len; i++) + alg->move[i] = moves_ttable[t][alg->move[i]]; +} + + +void +init() +{ + /* Order is important! */ + init_environment(); + init_strings(); + init_moves_aux(); + init_moves(); + init_auxtables(); + init_trans_aux(); + init_trans(); +} + diff --git a/old/2021-06-17-cachedata/cube.h b/old/2021-06-17-cachedata/cube.h new file mode 100644 index 0000000..d233165 --- /dev/null +++ b/old/2021-06-17-cachedata/cube.h @@ -0,0 +1,79 @@ +#ifndef CUBE_H +#define CUBE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Constants and macros *****************************************************/ + +#define POW2TO11 2048ULL +#define POW2TO12 4096ULL +#define POW3TO7 2187ULL +#define POW3TO8 6561ULL +#define FACTORIAL4 24ULL +#define FACTORIAL6 720ULL +#define FACTORIAL8 40320ULL +#define FACTORIAL12 479001600ULL +#define BINOM12ON4 495ULL +#define BINOM8ON4 70ULL +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +#define NMOVES (z3+1) +#define NTRANS (mirror+1) +#define NROTATIONS (NTRANS-1) +#define PTABLESIZE(n) ((n+1) / 2) +#define PTABLEVAL(t,i) (((i)%2) ? (t[(i)/2] / 16) : (t[(i)/2] % 16)) + +/* Type definitions **********************************************************/ + +#include "cubetypes.h" + +/* Public functions **********************************************************/ + +Cube apply_alg(Alg *alg, Cube cube); +Cube apply_move(Move m, Cube cube); +Cube apply_trans(Trans t, Cube cube); +bool block_solved(Cube cube, Block); +Center center_at(Cube cube, Center c); +Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */ +Corner corner_at(Cube cube, Corner c); +Edge edge_at(Cube cube, Edge e); +uint64_t epos_dependent_cube(Cube cube); +bool equal(Cube c1, Cube c2); +Cube inverse_cube(Cube cube); +Move inverse_move(Move m); +Trans inverse_trans(Trans t); +bool is_admissible(Cube cube); +bool is_solved(Cube cube, bool reorient); +int piece_orientation(Cube cube, int piece, char *orientation); +void print_cube(Cube cube); +Cube random_cube(); +AlgList * solve(Cube cube, Step step, SolveOptions *opts); + +Move base_move(Move m); +void free_alg(Alg *alg); +void free_alglist(AlgList *l); +Alg * inverse_alg(Alg *alg); +Alg * new_alg(char *str); +Alg * on_inverse(Alg *alg); +void print_alg(Alg *alg, bool l); +void print_alglist(AlgList *al, bool l); +Alg * trans_alg(Trans i); +void transform_alg(Trans t, Alg *alg); + +void generate_ctable(CacheData *cd); +void generate_ptable(PruneData *pd); +void print_cachedata(CacheData *cd, bool printalgs); +void print_ptable(PruneData *pd); + +void init(); + +#endif + diff --git a/old/2021-06-17-cachedata/cubetypes.h b/old/2021-06-17-cachedata/cubetypes.h new file mode 100644 index 0000000..4369385 --- /dev/null +++ b/old/2021-06-17-cachedata/cubetypes.h @@ -0,0 +1,232 @@ +/* Typedefs ******************************************************************/ + +typedef enum center Center; +typedef enum corner Corner; +typedef enum edge Edge; +typedef enum move Move; +typedef enum trans Trans; + +typedef struct alg Alg; +typedef struct alglist AlgList; +typedef struct alglistnode AlgListNode; +typedef struct block Block; +typedef struct cachedata CacheData; +typedef struct cachenode CacheNode; +typedef struct cube Cube; +typedef struct cubearray CubeArray; +typedef struct dfsdata DfsData; +typedef struct piecefilter PieceFilter; +typedef struct prunedata PruneData; +typedef struct solveoptions SolveOptions; +typedef struct step Step; + +typedef int (*Checker)(Cube); +typedef uint64_t (*Indexer)(Cube); +typedef bool (*Moveset)(Move); + + +/* Enums *********************************************************************/ + +enum +center +{ + U_center, D_center, + R_center, L_center, + F_center, B_center +}; + +enum +corner +{ + UFR, UFL, UBL, UBR, + DFR, DFL, DBL, DBR +}; + +enum +edge +{ + UF, UL, UB, UR, + DF, DL, DB, DR, + FR, FL, BL, BR +}; + +enum +move +{ + NULLMOVE, + U, U2, U3, D, D2, D3, + R, R2, R3, L, L2, L3, + F, F2, F3, B, B2, B3, + Uw, Uw2, Uw3, Dw, Dw2, Dw3, + Rw, Rw2, Rw3, Lw, Lw2, Lw3, + Fw, Fw2, Fw3, Bw, Bw2, Bw3, + M, M2, M3, + S, S2, S3, + E, E2, E3, + x, x2, x3, + y, y2, y3, + z, z2, z3, +}; + +enum +trans +{ + uf, ur, ub, ul, + df, dr, db, dl, + rf, rd, rb, ru, + lf, ld, lb, lu, + fu, fr, fd, fl, + bu, br, bd, bl, + mirror, /* R|L */ +}; + + +/* Structs *******************************************************************/ + +struct +alg +{ + Move * move; + bool * inv; + int len; + int allocated; +}; + +struct +alglist +{ + AlgListNode * first; + AlgListNode * last; + int len; +}; + +struct +alglistnode +{ + Alg * alg; + AlgListNode * next; +}; + +struct +block +{ + bool edge[12]; + bool corner[8]; + bool center[6]; +}; + +struct +cachedata +{ + char * filename; + CacheNode ** ctable; + bool generated; + uint64_t maxind0; + int len; + int nind; + Indexer index[20]; /* Should be enough */ + Checker check; + Moveset moveset; +}; + +struct +cachenode +{ + uint64_t * indexval; + Alg * sol; + CacheNode * next; +}; + +struct +cube +{ + uint16_t epose; + uint16_t eposs; + uint16_t eposm; + uint16_t eofb; + uint16_t eorl; + uint16_t eoud; + uint16_t cp; + uint16_t coud; + uint16_t cofb; + uint16_t corl; + uint16_t cpos; +}; + +struct +cubearray +{ + int * ep; + int * eofb; + int * eorl; + int * eoud; + int * cp; + int * coud; + int * corl; + int * cofb; + int * cpos; +}; + +struct +dfsdata +{ + int d; + int m; + bool niss; + Move last1; + Move last2; + AlgList * sols; + Alg * current_alg; + Move sorted_moves[NMOVES]; + int move_position[NMOVES]; +}; + +struct +piecefilter +{ + 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; + uint8_t * ptable; + uint8_t * reached; + bool generated; + uint64_t n; + uint64_t size; + Indexer index; + Moveset moveset; +}; + +struct +solveoptions +{ + int min_moves; + int max_moves; + int max_solutions; + bool optimal_only; + bool can_niss; + bool feedback; + Trans pre_trans; +}; + +struct +step +{ + Checker check; + Checker ready; + Moveset moveset; + CacheData * cd; +}; diff --git a/old/2021-06-17-cachedata/main.c b/old/2021-06-17-cachedata/main.c new file mode 100644 index 0000000..bd69ac9 --- /dev/null +++ b/old/2021-06-17-cachedata/main.c @@ -0,0 +1,63 @@ +#include +#include "cube.h" +#include "steps.h" + +int main() { + Alg *algo; + AlgList *sols; + Cube cube; + SolveOptions opts; + char line[1000]; + int i, ns = 3; /*, nrand = 100000, sum1, sum2;*/ + + Step *stps[20] = {&eofb_HTM, &corners_URF, &optimal_HTM}; + char sss[30][30] = {"EO on F/B", "Corners URF", "Optimal solution"}; + + opts = (SolveOptions) { + .min_moves = 0, + .max_moves = 20, + .optimal_only = true, + .max_solutions = 1, + .can_niss = false, + .feedback = true, + .pre_trans = uf + }; + + init(); + +/* + print_ptable(&pd_corners_HTM); + + srand(time(NULL)); + sum1 = 0; + sum2 = 0; + for (i = 0; i < nrand; i++) { + sum1 += optimal_HTM.check(random_cube()); + sum2 += corners_HTM.check(random_cube()); + } + printf("Average optimal pruning: %lf\n", ((double)sum1) / ((double) nrand)); + printf("Average corners pruning: %lf\n", ((double)sum2) / ((double) nrand)); +*/ + + print_cachedata(&cd_optimal_HTM_6, false); + + printf("Welcome to nissy 2.0! Insert a scramble:\n"); + + if (fgets(line, 1000, stdin) != NULL) { + algo = new_alg(line); + cube = apply_alg(algo, (Cube){0}); + + for (i = 0; i < ns; i++) { + if (stps[i]->check == NULL) + fprintf(stderr, "Check function for step %d is null\n", i); + sols = solve(cube, *stps[i], &opts); + printf("%s: %d solutions found:\n", sss[i], sols->len); + print_alglist(sols, true); + free_alglist(sols); + } + free(algo); + } + + return 0; +} + diff --git a/old/2021-06-17-cachedata/steps.c b/old/2021-06-17-cachedata/steps.c new file mode 100644 index 0000000..f1001e6 --- /dev/null +++ b/old/2021-06-17-cachedata/steps.c @@ -0,0 +1,327 @@ +#include "steps.h" + +/* Check functions ***********************************************************/ + +static int check_nothing(Cube cube); +static int check_eofb_HTM(Cube cube); +static int check_coud_HTM(Cube cube); +static int check_coud_URF(Cube cube); +static int check_corners_HTM(Cube cube); +static int check_corners_URF(Cube cube); +static int check_edges_HTM(Cube cube); +static int check_drud_HTM(Cube cube); +static int check_optimal_HTM(Cube cube); + + +/* Index functions ***********************************************************/ + +static uint64_t index_eofb(Cube cube); +static uint64_t index_coud(Cube cube); +static uint64_t index_corners(Cube cube); +static uint64_t index_ep(Cube cube); +static uint64_t index_drud(Cube cube); + + +/* Steps *********************************************************************/ + +Step +eofb_HTM = { + .check = check_eofb_HTM, + .ready = check_nothing, + .moveset = moveset_HTM +}; + +Step +coud_HTM = { + .check = check_coud_HTM, + .ready = check_nothing, + .moveset = moveset_HTM +}; + +Step +coud_URF = { + .check = check_coud_URF, + .ready = check_nothing, + .moveset = moveset_URF +}; + +Step +corners_HTM = { + .check = check_corners_HTM, + .ready = check_nothing, + .moveset = moveset_HTM +}; + +Step +corners_URF = { + .check = check_corners_URF, + .ready = check_nothing, + .moveset = moveset_URF +}; + +Step +edges_HTM = { + .check = check_edges_HTM, + .ready = check_nothing, + .moveset = moveset_HTM +}; + +Step +drud_HTM = { + .check = check_drud_HTM, + .ready = check_nothing, + .moveset = moveset_HTM +}; + +Step +optimal_HTM = { + .check = check_optimal_HTM, + .ready = check_nothing, + .moveset = moveset_HTM, + .cd = &cd_optimal_HTM_6 +}; + + +/* Cache solutions ***********************************************************/ + +CacheData +cd_optimal_HTM_6 = { + .filename = "cd_optimal_HTM_6", + .maxind0 = POW3TO7 * FACTORIAL8, + .len = 6, + .nind = 3, + .index = { index_corners, index_eofb, index_ep }, + .moveset = moveset_HTM +}; + + +/* Pruning tables ************************************************************/ + +PruneData +pd_eofb_HTM = { + .filename = "ptable_eofb_HTM", + .size = POW2TO11, + .index = index_eofb, + .moveset = moveset_HTM +}; + +PruneData +pd_coud_HTM = { + .filename = "ptable_coud_HTM", + .size = POW3TO7, + .index = index_coud, + .moveset = moveset_HTM +}; + +PruneData +pd_corners_HTM = { + .filename = "ptable_corners_HTM", + .size = POW3TO7 * FACTORIAL8, + .index = index_corners, + .moveset = moveset_HTM +}; + +PruneData +pd_ep_HTM = { + .filename = "ptable_ep_HTM", + .size = FACTORIAL12, + .index = index_ep, + .moveset = moveset_HTM +}; + +PruneData +pd_drud_HTM = { + .filename = "ptable_drud_HTM", + .size = POW2TO11 * POW3TO7 * BINOM12ON4, + .index = index_drud, + .moveset = moveset_HTM +}; + + +/* Check functions implementation ********************************************/ + +static int +check_nothing(Cube cube) +{ + /* At least we check that it is admissible */ + return is_admissible(cube); +} + +static int +check_eofb_HTM(Cube cube) +{ + if (!pd_eofb_HTM.generated) + generate_ptable(&pd_eofb_HTM); + + return PTABLEVAL(pd_eofb_HTM.ptable, cube.eofb); +} + +static int +check_coud_HTM(Cube cube) +{ + if (!pd_coud_HTM.generated) + generate_ptable(&pd_coud_HTM); + + return PTABLEVAL(pd_coud_HTM.ptable, cube.coud); +} + +static int +check_coud_URF(Cube cube) +{ + /* TODO: I can improve this by checking first the orientation of + * the corner in DBL and use that as a reference */ + + int ud = check_coud_HTM(cube); + int rl = check_coud_HTM(apply_move(z, cube)); + int fb = check_coud_HTM(apply_move(x, cube)); + + return MIN(ud, MIN(rl, fb)); +} + +static int +check_corners_HTM(Cube cube) +{ + if (!pd_corners_HTM.generated) + generate_ptable(&pd_corners_HTM); + + return PTABLEVAL(pd_corners_HTM.ptable, index_corners(cube)); +} + +static int +check_corners_URF(Cube cube) +{ + /* TODO: I can improve this by checking first the corner in DBL + * and use that as a reference */ + + int ret = 15; + Trans i; + + for (i = 0; i < NROTATIONS; i++) + ret = MIN(ret,check_corners_HTM(apply_alg(trans_alg(i),cube))); + + return ret; +} + +static int +check_edges_HTM(Cube cube) +{ + int ret = 0; + + if (!pd_ep_HTM.generated) + generate_ptable(&pd_ep_HTM); + + ret = MAX(ret, PTABLEVAL(pd_ep_HTM.ptable, index_ep(cube))); + ret = MAX(ret, check_eofb_HTM(cube)); + ret = MAX(ret, check_eofb_HTM(apply_trans(ur, cube))); + ret = MAX(ret, check_eofb_HTM(apply_trans(fd, cube))); + + return ret; +} + +static int +check_drud_HTM(Cube cube) +{ + if (!pd_drud_HTM.generated) + generate_ptable(&pd_drud_HTM); + + return PTABLEVAL(pd_drud_HTM.ptable, index_drud(cube)); +} + +static int +check_optimal_HTM(Cube cube) +{ + int dr1, dr2, dr3, drmax, cor; /*ep;*/ + + if (!pd_drud_HTM.generated) + generate_ptable(&pd_drud_HTM); + if (!pd_corners_HTM.generated) + generate_ptable(&pd_corners_HTM); + /* + *if (!pd_ep_HTM.generated) + * generate_ptable(&pd_ep_HTM); + */ + + dr1 = PTABLEVAL(pd_drud_HTM.ptable, index_drud(cube)); + dr2 = PTABLEVAL(pd_drud_HTM.ptable, index_drud(apply_trans(rf, cube))); + dr3 = PTABLEVAL(pd_drud_HTM.ptable, index_drud(apply_trans(fd, cube))); + + drmax = MAX(dr1, MAX(dr2, dr3)); + if (dr1 == dr2 && dr2 == dr3 && dr1 != 0) + drmax++; + + cor = PTABLEVAL(pd_corners_HTM.ptable, index_corners(cube)); + /* ep = PTABLEVAL(pd_ep_HTM.ptable, index_ep(cube)); */ + + /*return MAX(drmax, MAX(ep, cor));*/ + if (drmax == 0 && cor == 0) + return is_solved(cube, false) ? 0 : 1; + return MAX(drmax, cor); +} + + +/* Index functions implementation ********************************************/ + +static uint64_t +index_eofb(Cube cube) +{ + return cube.eofb; +} + +static uint64_t +index_coud(Cube cube) +{ + return cube.coud; +} + +static uint64_t +index_corners(Cube cube) +{ + return cube.coud * FACTORIAL8 + cube.cp; +} + +static uint64_t +index_ep(Cube cube) +{ + uint64_t a, b, c; + + a = cube.eposs; + b = (cube.epose % FACTORIAL4) + epos_dependent_cube(cube)*FACTORIAL4; + c = cube.eposm % FACTORIAL4; + + b *= FACTORIAL4 * BINOM12ON4; + c *= FACTORIAL4 * BINOM12ON4 * FACTORIAL4 * BINOM8ON4; + + return a + b + c; +} + +static uint64_t +index_drud(Cube cube) +{ + uint64_t a, b, c; + + a = cube.eofb; + b = cube.coud; + c = cube.epose / FACTORIAL4; + + b *= POW2TO11; + c *= POW2TO11 * POW3TO7; + + return a + b + c; +} + +/* Movesets ******************************************************************/ + +bool +moveset_HTM(Move m) +{ + return m >= U && m <= B3; +} + +bool +moveset_URF(Move m) +{ + Move b = base_move(m); + + return b == U || b == R || b == F; +} + diff --git a/old/2021-06-17-cachedata/steps.h b/old/2021-06-17-cachedata/steps.h new file mode 100644 index 0000000..66a31a8 --- /dev/null +++ b/old/2021-06-17-cachedata/steps.h @@ -0,0 +1,34 @@ +#ifndef STEPS_H +#define STEPS_H + +#include "cube.h" + +/* Steps *********************************************************************/ + +extern Step eofb_HTM; +extern Step coud_HTM; +extern Step coud_URF; +extern Step corners_HTM; +extern Step corners_URF; +extern Step edges_HTM; +extern Step drud_HTM; +extern Step optimal_HTM; + +/* Cache solutions ***********************************************************/ + +extern CacheData cd_optimal_HTM_6; + +/* Pruning tables ************************************************************/ + +extern PruneData pd_eofb_HTM; +extern PruneData pd_coud_HTM; +extern PruneData pd_corners_HTM; +extern PruneData pd_ep_HTM; +extern PruneData pd_drud_HTM; + +/* Movesets ******************************************************************/ + +bool moveset_HTM(Move m); +bool moveset_URF(Move m); + +#endif diff --git a/old/2021-06-23-realizing-bad-tables/HERE b/old/2021-06-23-realizing-bad-tables/HERE new file mode 100644 index 0000000..487e305 --- /dev/null +++ b/old/2021-06-23-realizing-bad-tables/HERE @@ -0,0 +1 @@ +Here you can also find some tables data that I have removed, like ep and tripleeo diff --git a/old/2021-06-23-realizing-bad-tables/cube.c b/old/2021-06-23-realizing-bad-tables/cube.c new file mode 100644 index 0000000..4e60bb2 --- /dev/null +++ b/old/2021-06-23-realizing-bad-tables/cube.c @@ -0,0 +1,2844 @@ +#include "cube.h" + +/* Local functions **********************************************************/ + +static Cube admissible_ep(Cube cube, PieceFilter f); +static bool allowed_next(Move move, DfsData *dd); +static void append_alg(AlgList *l, Alg *alg); +static void append_move(Alg *alg, Move m, bool inverse); +static Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a); +static void apply_permutation(int *perm, int *set, int n); +static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f); +static int array_ep_to_epos(int *ep, int *eps_solved); +static Cube arrays_to_cube(CubeArray *arr, PieceFilter f); +static int binomial(int n, int k); +static Cube compose_filtered(Cube c2, Cube c1, PieceFilter f); +static void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f); +static void dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static void dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static bool dfs_check_solved(SolveOptions *opts, DfsData *dd); +static void dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static bool dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static int digit_array_to_int(int *a, int n, int b); +static int edge_slice(Edge e); /* E=0, S=1, M=2 */ +static int epos_dependent_pos(int pos1, int pos2); +static int epos_from_arrays(int *epos, int *ep); +static void epos_to_partial_ep(int epos, int *ep, int *ss); +static int factorial(int n); +static void free_alglistnode(AlgListNode *aln); +static void free_cubearray(CubeArray *arr, PieceFilter f); +static void genptable_dfs(Cube c, PruneData *pd, DfsData *dd); +static void genptable_dfs_branch(Cube c, PruneData *pd, DfsData *dd); +static void index_to_perm(int p, int n, int *r); +static void index_to_subset(int s, int n, int k, int *r); +static void int_to_digit_array(int a, int b, int n, int *r); +static void int_to_sum_zero_array(int x, int b, int n, int *a); +static int invert_digits(int a, int b, int n); +static bool is_perm(int *a, int n); +static bool is_subset(int *a, int n, int k); +static Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf); +static void movelist_to_position(Move *movelist, int *position); +static void moveset_to_list(Moveset ms, Checker f, Move *r); +static AlgList * new_alglist(); +static CubeArray * new_cubearray(Cube cube, PieceFilter f); +static int perm_sign(int *a, int n); +static int perm_to_index(int *a, int n); +static int powint(int a, int b); +static bool ptable_has_reached(PruneData *pd, uint64_t ind); +static void ptable_set_reached(PruneData *pd, uint64_t ind); +static void ptable_update(PruneData *pd, uint64_t ind, int m); +static void realloc_alg(Alg *alg, int n); +static bool read_algset_file(AlgSet *as); +static bool read_mtables_file(); +static bool read_ptable_file(PruneData *pd); +static bool read_ttables_file(); +static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f); +static int subset_to_index(int *a, int n, int k); +static void sum_arrays_mod(int *src, int *dst, int n, int m); +static void swap(int *a, int *b); +static bool write_algset_file(AlgSet *as); +static bool write_mtables_file(); +static bool write_ptable_file(PruneData *pd); +static bool write_ttables_file(); + +static void init_auxtables(); +static void init_cphtr_cosets(); +static void init_cphtr_cosets_bfs(int i, int c); +static void init_environment(); +static void init_moves(); +static void init_moves_aux(); +static void init_strings(); +static void init_trans(); +static void init_trans_aux(); + +/* All sorts of useful costants and tables **********************************/ + +static char * tabledir; + +static PieceFilter pf_all; +static PieceFilter pf_4val; +static PieceFilter pf_epcp; +static PieceFilter pf_cpos; +static PieceFilter pf_cp; +static PieceFilter pf_ep; +static PieceFilter pf_e; +static PieceFilter pf_s; +static PieceFilter pf_m; +static PieceFilter pf_eo; +static PieceFilter pf_co; + +static int epe_solved[4]; +static int eps_solved[4]; +static int epm_solved[4]; + +static char move_string[NMOVES][7]; +static char edge_string[12][7]; +static char corner_string[8][7]; +static char center_string[6][7]; + +static bool commute[NMOVES][NMOVES]; +static bool possible_next[NMOVES][NMOVES][NMOVES]; +static Move inverse_move_aux[NMOVES]; +static Trans inverse_trans_aux[NTRANS]; +static int epos_dependent_aux[BINOM12ON4][BINOM12ON4]; +static int cphtr_cosets[FACTORIAL8]; +static Center what_center_at_aux[FACTORIAL6][6]; +static Corner what_corner_at_aux[FACTORIAL8][8]; +static int what_orientation_last_corner_aux[POW3TO7]; +static int what_orientation_last_edge_aux[POW2TO11]; +static Center where_is_center_aux[FACTORIAL6][6]; +static Corner where_is_corner_aux[FACTORIAL8][8]; +static Edge where_is_edge_aux[3][FACTORIAL12/FACTORIAL8][12]; + +static int epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static int eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static int eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static int eo_ttable[NTRANS][POW2TO11]; +static int cp_ttable[NTRANS][FACTORIAL8]; +static int co_ttable[NTRANS][POW3TO7]; +static int cpos_ttable[NTRANS][FACTORIAL6]; +static Move moves_ttable[NTRANS][NMOVES]; + +static int epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static int eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static int eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static int eofb_mtable[NMOVES][POW2TO11]; +static int eorl_mtable[NMOVES][POW2TO11]; +static int eoud_mtable[NMOVES][POW2TO11]; +static int cp_mtable[NMOVES][FACTORIAL8]; +static int coud_mtable[NMOVES][POW3TO7]; +static int cofb_mtable[NMOVES][POW3TO7]; +static int corl_mtable[NMOVES][POW3TO7]; +static int cpos_mtable[NMOVES][FACTORIAL6]; + +static uint64_t me[12]; + +static int edge_cycle[NMOVES][12]; +static int corner_cycle[NMOVES][8]; +static int center_cycle[NMOVES][6]; +static int eofb_flipped[NMOVES][12]; +static int eorl_flipped[NMOVES][12]; +static int eoud_flipped[NMOVES][12]; +static int coud_flipped[NMOVES][8]; +static int corl_flipped[NMOVES][8]; +static int cofb_flipped[NMOVES][8]; +static Alg * equiv_alg[NMOVES]; + +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]; +static int ep_mirror[12]; +static int cp_mirror[8]; +static int cpos_mirror[6]; +static Alg * trans_algs[NROTATIONS]; + + +/* Local functions implementation ********************************************/ + +static 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 < 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; +} + +static bool +allowed_next(Move move, DfsData *dd) +{ + if (!possible_next[dd->last2][dd->last1][move]) + return false; + + if (commute[dd->last1][move]) + return dd->move_position[dd->last1] < dd->move_position[move]; + + return true; +} + +static void +append_alg(AlgList *l, Alg *alg) +{ + AlgListNode *node = malloc(sizeof(AlgListNode)); + int i; + + node->alg = new_alg(""); + for (i = 0; i < alg->len; i++) + append_move(node->alg, alg->move[i], alg->inv[i]); + node->next = NULL; + + if (++l->len == 1) + l->first = node; + else + l->last->next = node; + l->last = node; +} + +static void +append_move(Alg *alg, Move m, bool inverse) +{ + if (alg->len == alg->allocated) + realloc_alg(alg, 2*alg->len); + + alg->move[alg->len] = m; + alg->inv [alg->len] = inverse; + alg->len++; +} + +static Cube +apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a) +{ + Cube ret = {0}; + int i; + + for (i = 0; i < alg->len; i++) + if (alg->inv[i]) + ret = a ? apply_move(alg->move[i], ret) : + apply_move_cubearray(alg->move[i], ret, f); + + ret = compose_filtered(c, inverse_cube(ret), f); + + for (i = 0; i < alg->len; i++) + if (!alg->inv[i]) + ret = a ? apply_move(alg->move[i], ret) : + apply_move_cubearray(alg->move[i], ret, f); + + return ret; +} + +static void +apply_permutation(int *perm, int *set, int n) +{ + int *aux = malloc(n * sizeof(int)); + int i; + + if (!is_perm(perm, n)) + return; + + for (i = 0; i < n; i++) + aux[i] = set[perm[i]]; + + memcpy(set, aux, n * sizeof(int)); + free(aux); +} + +static Cube +apply_move_cubearray(Move m, Cube cube, PieceFilter f) +{ + 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); +} + +static int +array_ep_to_epos(int *ep, int *ss) +{ + 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 epos_from_arrays(epos, eps); +} + +static Cube +arrays_to_cube(CubeArray *arr, PieceFilter f) +{ + Cube ret = {0}; + + 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; +} + +static int +binomial(int n, int k) +{ + if (n < 0 || k < 0 || k > n) + return 0; + + return factorial(n) / (factorial(k) * factorial(n-k)); +} + +static Cube +compose_filtered(Cube c2, Cube c1, PieceFilter f) +{ + CubeArray *arr = new_cubearray(c2, f); + Cube ret; + + ret = move_via_arrays(arr, c1, f); + free_cubearray(arr, f); + + return ret; +} + +static void +cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f) +{ + int i; + + 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); +} + +/* +static int +cphtr_cp(int cp) +{ + int i, a[8]; + + index_to_perm(cp, 8, a); + + for (i = 0; i < 8; i++) + if (a[i] == UFR || a[i] == UBL || a[i] == DFL || a[i] == DBR) + a[i] = 0; + else + a[i] = 1; + + swap(&a[1], &a[5]); + swap(&a[3], &a[7]); + + return subset_to_index(a, 8, 4); +} +*/ + +static void +dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + if (dfs_stop(c, s, opts, dd)) + return; + + if (dfs_check_solved(opts, dd)) + return; + + dfs_branch(c, s, opts, dd); + + if (opts->can_niss && !dd->niss) + dfs_niss(c, s, opts, dd); +} + +static void +dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + Move m, l1 = dd->last1, l2 = dd->last2, *moves = dd->sorted_moves; + + int i, maxnsol = opts->max_solutions; + + for (i = 0; (m=moves[i]) != NULLMOVE && dd->sols->len < maxnsol; i++) { + if (allowed_next(m, dd)) { + dd->last2 = dd->last1; + dd->last1 = m; + append_move(dd->current_alg, m, dd->niss); + + dfs(apply_move(m, c), s, opts, dd); + + dd->current_alg->len--; + dd->last2 = l2; + dd->last1 = l1; + } + } +} + +static bool +dfs_check_solved(SolveOptions *opts, DfsData *dd) +{ + if (dd->lb != 0) + return false; + + if (dd->current_alg->len == dd->d) { + append_alg(dd->sols, dd->current_alg); + + if (opts->feedback) + print_alg(dd->current_alg, false); + } + + return true; +} + +static void +dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + Move l1 = dd->last1, l2 = dd->last2; + + if (dd->current_alg->len == 0 || + (s.check(apply_move(inverse_move(l1), (Cube){0}), 1))) { + dd->niss = true; + dd->last1 = NULLMOVE; + dd->last2 = NULLMOVE; + + dfs(inverse_cube(c), s, opts, dd); + + dd->last1 = l1; + dd->last2 = l2; + dd->niss = false; + } +} + +static bool +dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + if (dd->sols->len >= opts->max_solutions) + return true; + + dd->lb = s.check(c, dd->d - dd->current_alg->len); + if (opts->can_niss && !dd->niss) + dd->lb = MIN(1, dd->lb); + + if (dd->current_alg->len + dd->lb > dd->d) + return true; + + return false; +} + +static int +digit_array_to_int(int *a, int n, int b) +{ + int i, ret = 0, p = 1; + + for (i = 0; i < n; i++, p *= b) + ret += a[i] * p; + + return ret; +} + +static int +edge_slice(Edge e) { + if (e < 0 || e > 11) + return -1; + + if (e == FR || e == FL || e == BL || e == BR) + return 0; + if (e == UR || e == UL || e == DR || e == DL) + return 1; + + return 2; +} + +static int +epos_dependent_pos(int poss, int pose) +{ + int ep[12] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; + int ep8[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + int i, j; + + epos_to_partial_ep(poss*FACTORIAL4, ep, eps_solved); + epos_to_partial_ep(pose*FACTORIAL4, ep, epe_solved); + + for (i = 0, j = 0; i < 12; i++) + if (edge_slice(ep[i]) != 0) + ep8[j++] = (edge_slice(ep[i]) == 1) ? 1 : 0; + + swap(&ep8[1], &ep8[4]); + swap(&ep8[3], &ep8[6]); + + return subset_to_index(ep8, 8, 4); +} + +static int +epos_from_arrays(int *epos, int *ep) +{ + return FACTORIAL4 * subset_to_index(epos,12,4) + perm_to_index(ep,4); +} + +static void +epos_to_partial_ep(int epos, int *ep, int *ss) +{ + 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++]]; +} + +static int +factorial(int n) +{ + int i, ret = 1; + + if (n < 0) + return 0; + + for (i = 1; i <= n; i++) + ret *= i; + + return ret; +} + +void +free_alg(Alg *alg) +{ + free(alg->move); + free(alg->inv); + free(alg); +} + +void +free_alglist(AlgList *l) +{ + AlgListNode *aux, *i = l->first; + + while (i != NULL) { + aux = i->next; + free_alglistnode(i); + i = aux; + } + free(l); +} + +void +free_alglistnode(AlgListNode *aln) +{ + free_alg(aln->alg); + free(aln); +} + +static void +free_cubearray(CubeArray *arr, PieceFilter f) +{ + 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); +} + +static void +genptable_dfs(Cube c, PruneData *pd, DfsData *dd) +{ + uint64_t ind = pd->index(c); + int oldval = ptableval(pd, ind); + + if (oldval < dd->m || ptable_has_reached(pd, ind) || pd->n == pd->size) + return; + + ptable_set_reached(pd, ind); + + if (dd->m == dd->d) { + if (dd->m < oldval) + ptable_update(pd, ind, dd->m); + return; + } + + genptable_dfs_branch(c, pd, dd); +} + +static void +genptable_dfs_branch(Cube c, PruneData *pd, DfsData *dd) +{ + Move i, move, l1 = dd->last1, l2 = dd->last2; + + dd->m++; + + for (i = 0; dd->sorted_moves[i] != NULLMOVE; i++) { + move = dd->sorted_moves[i]; + if (allowed_next(move, dd)) { + dd->last2 = dd->last1; + dd->last1 = move; + + genptable_dfs(apply_move(move, c), pd, dd); + + dd->last2 = l2; + dd->last1 = l1; + } + } + + dd->m--; +} + +static void +index_to_perm(int p, int n, int *r) +{ + int *a = malloc(n * sizeof(int)); + int i, j, c; + + for (i = 0; i < n; i++) + a[i] = 0; + + if (p < 0 || p >= factorial(n)) + for (i = 0; i < n; i++) + r[i] = -1; + + for (i = 0; i < n; i++) { + c = 0; + j = 0; + while (c <= p / factorial(n-i-1)) + c += a[j++] ? 0 : 1; + r[i] = j-1; + a[j-1] = 1; + p %= factorial(n-i-1); + } + + free(a); +} + +static void +index_to_subset(int s, int n, int k, int *r) +{ + int i, j, v; + + if (s < 0 || s >= binomial(n, k)) { + for (i = 0; i < n; i++) + r[i] = -1; + return; + } + + for (i = 0; i < n; i++) { + if (k == n-i) { + for (j = i; j < n; j++) + r[j] = 1; + return; + } + + if (k == 0) { + for (j = i; j < n; j++) + r[j] = 0; + return; + } + + v = binomial(n-i-1, k); + if (s >= v) { + r[i] = 1; + k--; + s -= v; + } else { + r[i] = 0; + } + } +} + +static void +int_to_digit_array(int a, int b, int n, int *r) +{ + int i; + + if (b <= 1) + for (i = 0; i < n; i++) + r[i] = 0; + else + for (i = 0; i < n; i++, a /= b) + r[i] = a % b; +} + +static void +int_to_sum_zero_array(int x, int b, int n, int *a) +{ + int i, s = 0; + + if (b <= 1) { + for (i = 0; i < n; i++) + a[i] = 0; + } else { + int_to_digit_array(x, b, n-1, a); + for (i = 0; i < n - 1; i++) + s = (s + a[i]) % b; + a[n-1] = (b - s) % b; + } +} + +static int +invert_digits(int a, int b, int n) +{ + int i, ret, *r = malloc(n * sizeof(int)); + + int_to_digit_array(a, b, n, r); + for (i = 0; i < n; i++) + r[i] = (b-r[i]) % b; + + ret = digit_array_to_int(r, n, b); + free(r); + return ret; +} + +static bool +is_perm(int *a, int n) +{ + int *aux = malloc(n * sizeof(int)); + int i; + + for (i = 0; i < n; i++) + if (a[i] < 0 || a[i] >= n) + return false; + else + aux[a[i]] = 1; + + for (i = 0; i < n; i++) + if (!aux[i]) + return false; + + free(aux); + + return true; +} + +static bool +is_subset(int *a, int n, int k) +{ + int i, sum = 0; + + for (i = 0; i < n; i++) + sum += a[i] ? 1 : 0; + + return sum == k; +} + +static Cube +move_via_arrays(CubeArray *arr, Cube c, PieceFilter f) +{ + CubeArray *arrc = new_cubearray(c, f); + Cube ret; + + 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; +} + +static void +movelist_to_position(Move *movelist, int *position) +{ + Move m; + + for (m = 0; m < NMOVES && movelist[m] != NULLMOVE; m++) + position[movelist[m]] = m; +} + +static void +moveset_to_list(Moveset ms, Checker f, Move *r) +{ + Cube c; + int b[NMOVES]; + int na = 0, nb = 0; + Move i; + + if (ms == NULL) { + fprintf(stderr, "Error: no moveset given\n"); + return; + } + + for (i = U; i < NMOVES; i++) { + if (ms(i)) { + c = apply_move(i, (Cube){0}); + if (f != NULL && f(c, 1)) + r[na++] = i; + else + b[nb++] = i; + } + } + + memcpy(r + na, b, nb * sizeof(Move)); + r[na+nb] = NULLMOVE; +} + +static AlgList * +new_alglist() +{ + AlgList *ret = malloc(sizeof(AlgList)); + + ret->len = 0; + ret->first = NULL; + ret->last = NULL; + + return ret; +} + +static CubeArray * +new_cubearray(Cube cube, PieceFilter f) +{ + 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; +} + +static int +perm_sign(int *a, int n) +{ + int i, j, ret = 0; + + if (!is_perm(a,n)) + return -1; + + for (i = 0; i < n; i++) + for (j = i+1; j < n; j++) + ret += (a[i] > a[j]) ? 1 : 0; + + return ret % 2; +} + +static int +perm_to_index(int *a, int n) +{ + int i, j, c, ret = 0; + + if (!is_perm(a, n)) + return -1; + + for (i = 0; i < n; i++) { + c = 0; + for (j = i+1; j < n; j++) + c += (a[i] > a[j]) ? 1 : 0; + ret += factorial(n-i-1) * c; + } + + return ret; +} + +static int +powint(int a, int b) +{ + if (b < 0) + return 0; + if (b == 0) + return 1; + + if (b % 2) + return a * powint(a, b-1); + else + return powint(a*a, b/2); +} + +static bool +ptable_has_reached(PruneData *pd, uint64_t ind) +{ + return (ind % 2) ? pd->reached[ind/2] / 16 : pd->reached[ind/2] % 16; +} + +static void +ptable_set_reached(PruneData *pd, uint64_t ind) +{ + uint8_t oldval2 = pd->reached[ind/2]; + int other = (ind % 2) ? oldval2 % 16 : oldval2 / 16; + + pd->reached[ind/2] = (ind % 2) ? 16 + other : 16*other + 1; +} + +static void +ptable_update(PruneData *pd, uint64_t ind, int n) +{ + uint8_t oldval2 = pd->ptable[ind/2]; + int other = (ind % 2) ? oldval2 % 16 : oldval2 / 16; + + pd->ptable[ind/2] = (ind % 2) ? 16*n + other : 16*other + n; + pd->n++; +} + +static void +realloc_alg(Alg *alg, int n) +{ + if (alg == NULL) { + fprintf(stderr, "Error: trying to reallocate NULL alg.\n"); + return; + } + + if (n < alg->len) { + fprintf(stderr, "Error: alg too long for reallocation "); + fprintf(stderr, "(%d vs %d)\n", alg->len, n); + return; + } + + if (n > 1000000) { + fprintf(stderr, "Warning: very long alg,"); + fprintf(stderr, "something might go wrong.\n"); + } + + alg->move = realloc(alg->move, n * sizeof(int)); + alg->inv = realloc(alg->inv, n * sizeof(int)); + alg->allocated = n; +} + +static bool +read_algset_file(AlgSet *as) +{ + return false; +} + +static bool +read_mtables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int m, b = sizeof(int); + bool r = true; + + 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 +read_ptable_file(PruneData *pd) +{ + FILE *f; + char fname[strlen(tabledir)+100]; + uint64_t r; + + strcpy(fname, tabledir); + strcat(fname, "/"); + strcat(fname, pd->filename); + + if ((f = fopen(fname, "rb")) == NULL) + return false; + + r = fread(pd->ptable, sizeof(uint8_t), ptablesize(pd), f); + fclose(f); + + return r == ptablesize(pd); +} + +static bool +read_ttables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int b = sizeof(int); + bool r = true; + Move m; + + 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[6], f) == me[6]; + r = r && fread(co_ttable[m], b, me[7], f) == me[7]; + r = r && fread(cpos_ttable[m], b, me[10], f) == me[10]; + r = r && fread(moves_ttable[m], b, me[11], f) == me[11]; + } + + fclose(f); + return r; +} + +static Cube +rotate_via_compose(Trans r, Cube c, PieceFilter f) +{ + Alg *inv; + 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 + }; + + Cube ret; + + if (r != mirror) { + ret = apply_alg_generic(trans_algs[r], c, f, true); + inv = on_inverse(trans_algs[r]); + ret = apply_alg_generic(inv, ret, f, true); + free_alg(inv); + } else { + ret = move_via_arrays(&ma, (Cube){0}, f); + ret = compose_filtered(c, ret, f); + ret = move_via_arrays(&ma, ret, f); + } + + return ret; +} + +static int +subset_to_index(int *a, int n, int k) +{ + int i, ret = 0; + + if (!is_subset(a, n, k)) + return binomial(n, k); + + for (i = 0; i < n; i++) { + if (k == n-i) + return ret; + if (a[i]) { + ret += binomial(n-i-1, k); + k--; + } + } + + return ret; +} + +static void +sum_arrays_mod(int *src, int *dst, int n, int m) +{ + int i; + + for (i = 0; i < n; i++) + dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m; +} + +static void +swap(int *a, int *b) +{ + int aux; + + aux = *a; + *a = *b; + *b = aux; +} + +static bool +write_algset_file(AlgSet *as) +{ + return false; +} + +static bool +write_mtables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int m, b = sizeof(int); + bool r = true; + + 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; +} + +static bool +write_ptable_file(PruneData *pd) +{ + FILE *f; + char fname[strlen(tabledir)+100]; + uint64_t written; + + strcpy(fname, tabledir); + strcat(fname, "/"); + strcat(fname, pd->filename); + + if ((f = fopen(fname, "wb")) == NULL) + return false; + + written = fwrite(pd->ptable, sizeof(uint8_t), ptablesize(pd), f); + fclose(f); + + return written == ptablesize(pd); +} + +static bool +write_ttables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + bool r = true; + int b = sizeof(int); + Move m; + + 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[6], f) == me[6]; + r = r && fwrite(co_ttable[m], b, me[7], f) == me[7]; + r = r && fwrite(cpos_ttable[m], b, me[10], f) == me[10]; + r = r && fwrite(moves_ttable[m], b, me[11], f) == me[11]; + } + + fclose(f); + return r; +} + +/* Init functions implementation *********************************************/ + +static void +init_auxtables() +{ + Cube c1, c2; + CubeArray *arr; + uint64_t ui, uj; + int i, j, k, auxarr[12]; + bool cij, p1, p2; + + for (ui = 0; ui < FACTORIAL6; ui++) { + arr = new_cubearray((Cube){.cpos = ui}, pf_cpos); + for (i = 0; i < 6; i++) { + what_center_at_aux[ui][i] = arr->cpos[i]; + where_is_center_aux[ui][arr->cpos[i]] = i; + } + free_cubearray(arr, pf_cpos); + } + + for (ui = 0; ui < FACTORIAL8; ui++) { + arr = new_cubearray((Cube){.cp = ui}, pf_cp); + for (i = 0; i < 8; i++) { + what_corner_at_aux[ui][i] = arr->cp[i]; + where_is_corner_aux[ui][arr->cp[i]] = i; + } + free_cubearray(arr, pf_cp); + } + + for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) { + arr = new_cubearray((Cube){.epose = ui}, pf_e); + for (i = 0; i < 12; i++) + if (edge_slice(arr->ep[i]) == 0) + where_is_edge_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) + where_is_edge_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) + where_is_edge_aux[2][ui][arr->ep[i]] = i; + free_cubearray(arr, pf_m); + } + + for (ui = 0; ui < POW3TO7; ui++) { + int_to_sum_zero_array(ui, 3, 8, auxarr); + what_orientation_last_corner_aux[ui] = auxarr[7]; + } + + for (ui = 0; ui < POW2TO11; ui++) { + int_to_sum_zero_array(ui, 2, 12, auxarr); + what_orientation_last_edge_aux[ui] = auxarr[11]; + } + + for (ui = 0; ui < BINOM12ON4; ui++) + for (uj = 0; uj < BINOM12ON4; uj++) + epos_dependent_aux[ui][uj]=epos_dependent_pos(ui, uj); + + for (i = 0; i < NMOVES; i++) { + for (j = 0; j < NMOVES; j++) { + c1 = apply_move(i, apply_move(j, (Cube){0})); + c2 = apply_move(j, apply_move(i, (Cube){0})); + commute[i][j] = equal(c1, c2) && i && j; + } + } + + for (i = 0; i < NMOVES; i++) { + for (j = 0; j < NMOVES; j++) { + for (k = 0; k < NMOVES; k++) { + p1 = j && base_move(j) == base_move(k); + p2 = i && base_move(i) == base_move(k); + cij = commute[i][j]; + possible_next[i][j][k] = !(p1 || (cij && p2)); + } + } + } + + for (i = 0; i < NMOVES; i++) + inverse_move_aux[i] = i ? i + 2 - 2*((i-1)%3) : NULLMOVE; + + /* Is there a more elegant way? */ + inverse_trans_aux[uf] = uf; + inverse_trans_aux[ur] = ul; + inverse_trans_aux[ul] = ur; + inverse_trans_aux[ub] = ub; + + inverse_trans_aux[df] = df; + inverse_trans_aux[dr] = dr; + inverse_trans_aux[dl] = dl; + inverse_trans_aux[db] = db; + + inverse_trans_aux[rf] = lf; + inverse_trans_aux[rd] = bl; + inverse_trans_aux[rb] = rb; + inverse_trans_aux[ru] = fr; + + inverse_trans_aux[lf] = rf; + inverse_trans_aux[ld] = br; + inverse_trans_aux[lb] = lb; + inverse_trans_aux[lu] = fl; + + inverse_trans_aux[fu] = fu; + inverse_trans_aux[fr] = ru; + inverse_trans_aux[fd] = bu; + inverse_trans_aux[fl] = lu; + + inverse_trans_aux[bu] = fd; + inverse_trans_aux[br] = ld; + inverse_trans_aux[bd] = bd; + inverse_trans_aux[bl] = rd; + + inverse_trans_aux[mirror] = mirror; +} + +/* + * There is certainly a bette way to do this, but for now I just use + * a "graph coloring" algorithm to compute the cosets for cphtr. + * + * 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; + + for (i = 0; i < FACTORIAL8; i++) + cphtr_cosets[i] = -1; + + for (i = 0; i < FACTORIAL8; i++) + if (cphtr_cosets[i] == -1) + init_cphtr_cosets_bfs(i, c++); +} + +static void +init_cphtr_cosets_bfs(int i, int c) +{ + int j, jj, k, next[FACTORIAL8], next2[FACTORIAL8], n, n2; + Move moves[6] = {U2, D2, R2, L2, F2, B2}; + + n = 1; + next[0] = i; + cphtr_cosets[i] = c; + + while (n != 0) { + for (j = 0, n2 = 0; j < n; j++) { + for (k = 0; k < 6; k++) { + jj = cp_mtable[moves[k]][next[j]]; + if (cphtr_cosets[jj] == -1) { + cphtr_cosets[jj] = c; + next2[n2++] = jj; + } + } + } + + for (j = 0; j < n2; j++) + next[j] = next2[j]; + n = n2; + } +} + +static void +init_environment() +{ + char *nissydata = getenv("NISSYDATA"); + char *localdata = getenv("XDG_DATA_HOME"); + char *home = getenv("HOME"); + bool read, write; + + if (nissydata != NULL) { + tabledir = malloc(strlen(nissydata) * sizeof(char) + 20); + strcpy(tabledir, nissydata); + } else if (localdata != NULL) { + tabledir = malloc(strlen(localdata) * sizeof(char) + 20); + strcpy(tabledir, localdata); + strcat(tabledir, "/nissy"); + } else if (home != NULL) { + tabledir = malloc(strlen(home) * sizeof(char) + 20); + strcpy(tabledir, home); + strcat(tabledir, "/.nissy"); + } + + mkdir(tabledir, 0777); + strcat(tabledir, "/tables"); + mkdir(tabledir, 0777); + + read = !access(tabledir, R_OK); + write = !access(tabledir, W_OK); + + if (!read) { + fprintf(stderr, "Table files cannot be read.\n"); + } else if (!write) { + fprintf(stderr, "Data directory not writable: "); + fprintf(stderr, "tables can be loaded, but not saved.\n"); + } +} + +static void +init_moves() { + Cube c; + CubeArray arrs; + int i; + unsigned int ui; + Move m; + + /* 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; + + fprintf(stderr, "Cannot load %s, generating it\n", "mtables"); + + /* Initialize transition tables */ + for (m = 0; m < NMOVES; m++) { + 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; + } + } + + if (!write_mtables_file()) + fprintf(stderr, "Error writing mtables\n"); +} + +static void +init_moves_aux() +{ + /* Some standard PieceFilters */ + pf_all.epose = true; + pf_all.eposs = true; + pf_all.eposm = true; + pf_all.eofb = true; + pf_all.eorl = true; + pf_all.eoud = true; + pf_all.cp = true; + pf_all.cofb = true; + pf_all.corl = true; + pf_all.coud = true; + pf_all.cpos = true; + + pf_4val.epose = true; + pf_4val.eposs = true; + pf_4val.eposm = true; + pf_4val.eofb = true; + pf_4val.coud = true; + pf_4val.cp = true; + + pf_epcp.epose = true; + pf_epcp.eposs = true; + pf_epcp.eposm = true; + pf_epcp.cp = true; + + pf_cpos.cpos = true; + + pf_cp.cp = true; + + pf_ep.epose = true; + pf_ep.eposs = true; + pf_ep.eposm = true; + + pf_e.epose = true; + pf_s.eposs = true; + pf_m.eposm = true; + + pf_eo.eofb = true; + pf_eo.eorl = true; + pf_eo.eoud = true; + + pf_co.cofb = true; + pf_co.corl = true; + pf_co.coud = true; + + /* Used to convert to and from CubeArray */ + epe_solved[0] = FR; + epe_solved[1] = FL; + epe_solved[2] = BL; + epe_solved[3] = BR; + + eps_solved[0] = UL; + eps_solved[1] = UR; + eps_solved[2] = DL; + eps_solved[3] = DR; + + epm_solved[0] = UF; + epm_solved[1] = UB; + epm_solved[2] = DF; + epm_solved[3] = DB; + + /* Table sizes, used for reading and writing files */ + me[0] = FACTORIAL12/FACTORIAL8; + me[1] = FACTORIAL12/FACTORIAL8; + me[2] = FACTORIAL12/FACTORIAL8; + me[3] = POW2TO11; + me[4] = POW2TO11; + me[5] = POW2TO11; + me[6] = FACTORIAL8; + me[7] = POW3TO7; + me[8] = POW3TO7; + me[9] = POW3TO7; + me[10] = FACTORIAL6; + me[11] = NMOVES; + + /* Cycles *********************/ + edge_cycle[U][UF] = UR; + edge_cycle[U][UL] = UF; + edge_cycle[U][UB] = UL; + edge_cycle[U][UR] = UB; + edge_cycle[U][DF] = DF; + edge_cycle[U][DL] = DL; + edge_cycle[U][DB] = DB; + edge_cycle[U][DR] = DR; + edge_cycle[U][FR] = FR; + edge_cycle[U][FL] = FL; + edge_cycle[U][BL] = BL; + edge_cycle[U][BR] = BR; + + edge_cycle[x][UF] = DF; + edge_cycle[x][UL] = FL; + edge_cycle[x][UB] = UF; + edge_cycle[x][UR] = FR; + edge_cycle[x][DF] = DB; + edge_cycle[x][DL] = BL; + edge_cycle[x][DB] = UB; + edge_cycle[x][DR] = BR; + edge_cycle[x][FR] = DR; + edge_cycle[x][FL] = DL; + edge_cycle[x][BL] = UL; + edge_cycle[x][BR] = UR; + + edge_cycle[y][UF] = UR; + edge_cycle[y][UL] = UF; + edge_cycle[y][UB] = UL; + edge_cycle[y][UR] = UB; + edge_cycle[y][DF] = DR; + edge_cycle[y][DL] = DF; + edge_cycle[y][DB] = DL; + edge_cycle[y][DR] = DB; + edge_cycle[y][FR] = BR; + edge_cycle[y][FL] = FR; + edge_cycle[y][BL] = FL; + edge_cycle[y][BR] = BL; + + corner_cycle[U][UFR] = UBR; + corner_cycle[U][UFL] = UFR; + corner_cycle[U][UBL] = UFL; + corner_cycle[U][UBR] = UBL; + corner_cycle[U][DFR] = DFR; + corner_cycle[U][DFL] = DFL; + corner_cycle[U][DBL] = DBL; + corner_cycle[U][DBR] = DBR; + + corner_cycle[x][UFR] = DFR; + corner_cycle[x][UFL] = DFL; + corner_cycle[x][UBL] = UFL; + corner_cycle[x][UBR] = UFR; + corner_cycle[x][DFR] = DBR; + corner_cycle[x][DFL] = DBL; + corner_cycle[x][DBL] = UBL; + corner_cycle[x][DBR] = UBR; + + corner_cycle[y][UFR] = UBR; + corner_cycle[y][UFL] = UFR; + corner_cycle[y][UBL] = UFL; + corner_cycle[y][UBR] = UBL; + corner_cycle[y][DFR] = DBR; + corner_cycle[y][DFL] = DFR; + corner_cycle[y][DBL] = DFL; + corner_cycle[y][DBR] = DBL; + + center_cycle[U][U_center] = U_center; + center_cycle[U][D_center] = D_center; + center_cycle[U][R_center] = R_center; + center_cycle[U][L_center] = L_center; + center_cycle[U][F_center] = F_center; + center_cycle[U][B_center] = B_center; + + center_cycle[x][U_center] = F_center; + center_cycle[x][D_center] = B_center; + center_cycle[x][R_center] = R_center; + center_cycle[x][L_center] = L_center; + center_cycle[x][F_center] = D_center; + center_cycle[x][B_center] = U_center; + + center_cycle[y][U_center] = U_center; + center_cycle[y][D_center] = D_center; + center_cycle[y][R_center] = B_center; + center_cycle[y][L_center] = F_center; + center_cycle[y][F_center] = R_center; + center_cycle[y][B_center] = L_center; + + /* Flipped pieces *************/ + eofb_flipped[x][UF] = 1; + eofb_flipped[x][UB] = 1; + eofb_flipped[x][DF] = 1; + eofb_flipped[x][DB] = 1; + + eofb_flipped[y][FR] = 1; + eofb_flipped[y][FL] = 1; + eofb_flipped[y][BL] = 1; + eofb_flipped[y][BR] = 1; + + eorl_flipped[x][UF] = 1; + eorl_flipped[x][UL] = 1; + eorl_flipped[x][UB] = 1; + eorl_flipped[x][UR] = 1; + eorl_flipped[x][DF] = 1; + eorl_flipped[x][DL] = 1; + eorl_flipped[x][DB] = 1; + eorl_flipped[x][DR] = 1; + eorl_flipped[x][FR] = 1; + eorl_flipped[x][FL] = 1; + eorl_flipped[x][BL] = 1; + eorl_flipped[x][BR] = 1; + + eorl_flipped[y][FR] = 1; + eorl_flipped[y][FL] = 1; + eorl_flipped[y][BL] = 1; + eorl_flipped[y][BR] = 1; + + eoud_flipped[U][UF] = 1; + eoud_flipped[U][UL] = 1; + eoud_flipped[U][UB] = 1; + eoud_flipped[U][UR] = 1; + + eoud_flipped[x][UF] = 1; + eoud_flipped[x][UB] = 1; + eoud_flipped[x][DF] = 1; + eoud_flipped[x][DB] = 1; + + eoud_flipped[y][UF] = 1; + eoud_flipped[y][UL] = 1; + eoud_flipped[y][UB] = 1; + eoud_flipped[y][UR] = 1; + eoud_flipped[y][DF] = 1; + eoud_flipped[y][DL] = 1; + eoud_flipped[y][DB] = 1; + eoud_flipped[y][DR] = 1; + eoud_flipped[y][FR] = 1; + eoud_flipped[y][FL] = 1; + eoud_flipped[y][BL] = 1; + eoud_flipped[y][BR] = 1; + + coud_flipped[x][UFR] = 2; + coud_flipped[x][UFL] = 1; + coud_flipped[x][UBR] = 1; + coud_flipped[x][UBL] = 2; + coud_flipped[x][DFR] = 1; + coud_flipped[x][DFL] = 2; + coud_flipped[x][DBR] = 2; + coud_flipped[x][DBL] = 1; + + corl_flipped[U][UFR] = 1; + corl_flipped[U][UFL] = 2; + corl_flipped[U][UBL] = 1; + corl_flipped[U][UBR] = 2; + + corl_flipped[y][UFR] = 1; + corl_flipped[y][UFL] = 2; + corl_flipped[y][UBL] = 1; + corl_flipped[y][UBR] = 2; + corl_flipped[y][DFR] = 2; + corl_flipped[y][DFL] = 1; + corl_flipped[y][DBL] = 2; + corl_flipped[y][DBR] = 1; + + cofb_flipped[U][UFR] = 2; + cofb_flipped[U][UFL] = 1; + cofb_flipped[U][UBL] = 2; + cofb_flipped[U][UBR] = 1; + + cofb_flipped[x][UFR] = 1; + cofb_flipped[x][UFL] = 2; + cofb_flipped[x][UBL] = 1; + cofb_flipped[x][UBR] = 2; + cofb_flipped[x][DFR] = 2; + cofb_flipped[x][DFL] = 1; + cofb_flipped[x][DBL] = 2; + cofb_flipped[x][DBR] = 1; + + cofb_flipped[y][UFR] = 2; + cofb_flipped[y][UFL] = 1; + cofb_flipped[y][UBL] = 2; + cofb_flipped[y][UBR] = 1; + cofb_flipped[y][DFR] = 1; + cofb_flipped[y][DFL] = 2; + cofb_flipped[y][DBL] = 1; + cofb_flipped[y][DBR] = 2; + + /* Equivalent moves ***********/ + equiv_alg[NULLMOVE] = new_alg(""); + + equiv_alg[U] = new_alg(" U "); + equiv_alg[U2] = new_alg(" UU "); + equiv_alg[U3] = new_alg(" UUU "); + equiv_alg[D] = new_alg(" xx U xx "); + equiv_alg[D2] = new_alg(" xx UU xx "); + equiv_alg[D3] = new_alg(" xx UUU xx "); + equiv_alg[R] = new_alg(" yx U xxxyyy "); + equiv_alg[R2] = new_alg(" yx UU xxxyyy "); + equiv_alg[R3] = new_alg(" yx UUU xxxyyy "); + equiv_alg[L] = new_alg(" yyyx U xxxy "); + equiv_alg[L2] = new_alg(" yyyx UU xxxy "); + equiv_alg[L3] = new_alg(" yyyx UUU xxxy "); + equiv_alg[F] = new_alg(" x U xxx "); + equiv_alg[F2] = new_alg(" x UU xxx "); + equiv_alg[F3] = new_alg(" x UUU xxx "); + equiv_alg[B] = new_alg(" xxx U x "); + equiv_alg[B2] = new_alg(" xxx UU x "); + equiv_alg[B3] = new_alg(" xxx UUU x "); + + equiv_alg[Uw] = new_alg(" xx U xx y "); + equiv_alg[Uw2] = new_alg(" xx UU xx yy "); + equiv_alg[Uw3] = new_alg(" xx UUU xx yyy "); + equiv_alg[Dw] = new_alg(" U yyy "); + equiv_alg[Dw2] = new_alg(" UU yy "); + equiv_alg[Dw3] = new_alg(" UUU y "); + equiv_alg[Rw] = new_alg(" yyyx U xxxy x "); + equiv_alg[Rw2] = new_alg(" yyyx UU xxxy xx "); + equiv_alg[Rw3] = new_alg(" yyyx UUU xxxy xxx "); + equiv_alg[Lw] = new_alg(" yx U xxxyyy xxx "); + equiv_alg[Lw2] = new_alg(" yx UU xxxyyy xx "); + equiv_alg[Lw3] = new_alg(" yx UUU xxxyyy x "); + equiv_alg[Fw] = new_alg(" xxx U x yxxxyyy "); + equiv_alg[Fw2] = new_alg(" xxx UU x yxxyyy "); + equiv_alg[Fw3] = new_alg(" xxx UUU x yxyyy "); + equiv_alg[Bw] = new_alg(" x U xxx yxyyy "); + equiv_alg[Bw2] = new_alg(" x UU xxx yxxyyy "); + equiv_alg[Bw3] = new_alg(" x UUU xxx yxxxyyy "); + + equiv_alg[M] = new_alg(" yx U xx UUU yxyyy "); + equiv_alg[M2] = new_alg(" yx UU xx UU xxxy "); + equiv_alg[M3] = new_alg(" yx UUU xx U yxxxy "); + equiv_alg[S] = new_alg(" x UUU xx U yyyx "); + equiv_alg[S2] = new_alg(" x UU xx UU yyx "); + equiv_alg[S3] = new_alg(" x U xx UUU yx "); + equiv_alg[E] = new_alg(" U xx UUU xxyyy "); + equiv_alg[E2] = new_alg(" UU xx UU xxyy "); + equiv_alg[E3] = new_alg(" UUU xx U xxy "); + + equiv_alg[x] = new_alg(" x "); + equiv_alg[x2] = new_alg(" xx "); + equiv_alg[x3] = new_alg(" xxx "); + equiv_alg[y] = new_alg(" y "); + equiv_alg[y2] = new_alg(" yy "); + equiv_alg[y3] = new_alg(" yyy "); + equiv_alg[z] = new_alg(" yyy x y "); + equiv_alg[z2] = new_alg(" yy xx "); + equiv_alg[z3] = new_alg(" y x yyy "); +} + +static void +init_strings() +{ + strcpy(move_string [NULLMOVE], "-" ); + strcpy(move_string [U], "U" ); + strcpy(move_string [U2], "U2" ); + strcpy(move_string [U3], "U\'" ); + strcpy(move_string [D], "D" ); + strcpy(move_string [D2], "D2" ); + strcpy(move_string [D3], "D\'" ); + strcpy(move_string [R], "R" ); + strcpy(move_string [R2], "R2" ); + strcpy(move_string [R3], "R\'" ); + strcpy(move_string [L], "L" ); + strcpy(move_string [L2], "L2" ); + strcpy(move_string [L3], "L\'" ); + strcpy(move_string [F], "F" ); + strcpy(move_string [F2], "F2" ); + strcpy(move_string [F3], "F\'" ); + strcpy(move_string [B], "B" ); + strcpy(move_string [B2], "B2" ); + strcpy(move_string [B3], "B\'" ); + strcpy(move_string [Uw], "Uw" ); + strcpy(move_string [Uw2], "Uw2" ); + strcpy(move_string [Uw3], "Uw\'" ); + strcpy(move_string [Dw], "Dw" ); + strcpy(move_string [Dw2], "Dw2" ); + strcpy(move_string [Dw3], "Dw\'" ); + strcpy(move_string [Rw], "Rw" ); + strcpy(move_string [Rw2], "Rw2" ); + strcpy(move_string [Rw3], "Rw\'" ); + strcpy(move_string [Lw], "Lw" ); + strcpy(move_string [Lw2], "Lw2" ); + strcpy(move_string [Lw3], "Lw\'" ); + strcpy(move_string [Fw], "Fw" ); + strcpy(move_string [Fw2], "Fw2" ); + strcpy(move_string [Fw3], "Fw\'" ); + strcpy(move_string [Bw], "Bw" ); + strcpy(move_string [Bw2], "Bw2" ); + strcpy(move_string [Bw3], "Bw\'" ); + strcpy(move_string [M], "M" ); + strcpy(move_string [M2], "M2" ); + strcpy(move_string [M3], "M\'" ); + strcpy(move_string [S], "S" ); + strcpy(move_string [S2], "S2" ); + strcpy(move_string [S3], "S\'" ); + strcpy(move_string [E], "E" ); + strcpy(move_string [E2], "E2" ); + strcpy(move_string [E3], "E\'" ); + strcpy(move_string [x], "x" ); + strcpy(move_string [x2], "x2" ); + strcpy(move_string [x3], "x\'" ); + strcpy(move_string [y], "y" ); + strcpy(move_string [y2], "y2" ); + strcpy(move_string [y3], "y\'" ); + strcpy(move_string [z], "z" ); + strcpy(move_string [z2], "z2" ); + strcpy(move_string [z3], "z\'" ); + + strcpy(edge_string [UF], "UF" ); + strcpy(edge_string [UL], "UL" ); + strcpy(edge_string [UB], "UB" ); + strcpy(edge_string [UR], "UR" ); + strcpy(edge_string [DF], "DF" ); + strcpy(edge_string [DL], "DL" ); + strcpy(edge_string [DB], "DB" ); + strcpy(edge_string [DR], "DR" ); + strcpy(edge_string [FR], "FR" ); + strcpy(edge_string [FL], "FL" ); + strcpy(edge_string [BL], "BL" ); + strcpy(edge_string [BR], "BR" ); + + strcpy(corner_string [UFR], "UFR" ); + strcpy(corner_string [UFL], "UFL" ); + strcpy(corner_string [UBL], "UBL" ); + strcpy(corner_string [UBR], "UBR" ); + strcpy(corner_string [DFR], "DFR" ); + strcpy(corner_string [DFL], "DFL" ); + strcpy(corner_string [DBL], "DBL" ); + strcpy(corner_string [DBR], "DBR" ); + + strcpy(center_string [U_center], "U" ); + strcpy(center_string [D_center], "D" ); + strcpy(center_string [R_center], "R" ); + strcpy(center_string [L_center], "L" ); + strcpy(center_string [F_center], "F" ); + strcpy(center_string [B_center], "B" ); +} + +static void +init_trans() { + Cube aux, cube, c[3]; + CubeArray epcp; + int eparr[12], eoarr[12]; + int cparr[8], coarr[8]; + int i; + unsigned int ui; + bool b1, b2, b3; + Move mi, move; + Trans m; + + /* Compute sources */ + for (i = 0; i < NTRANS; i++) { + if (i == mirror) + cube = (Cube){0}; + else + cube = apply_alg(trans_algs[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; + } + + if (read_ttables_file()) + return; + + fprintf(stderr, "Cannot load %s, generating it\n", "ttables"); + + /* Initialize tables */ + for (m = 0; m < NTRANS; m++) { + if (m == mirror) { + memcpy(eparr, ep_mirror, 12 * sizeof(int)); + memcpy(cparr, cp_mirror, 8 * sizeof(int)); + } else { + epcp = (CubeArray){ .ep = eparr, .cp = cparr }; + cube = apply_alg(trans_algs[m], (Cube){0}); + cube_to_arrays(cube, &epcp, pf_epcp); + } + + 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 == mirror) + 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++) { + if (m == mirror) { + b1 = (mi >= U && mi <= Bw3); + b2 = (mi >= S && mi <= E3); + b3 = (mi >= x && mi <= z3); + if (b1 || b2 || b3) + moves_ttable[m][mi] = + inverse_move_aux[mi]; + else + moves_ttable[m][mi] = mi; + + if ((mi-1)/3==(R-1)/3 || (mi-1)/3==(Rw-1)/3) + moves_ttable[m][mi] += 3; + if ((mi-1)/3==(L-1)/3 || (mi-1)/3==(L2-1)/3) + moves_ttable[m][mi] -= 3; + } else { + aux = apply_trans(m, apply_move(mi,(Cube){0})); + for (move = 0; move < NMOVES; move++) { + cube = apply_move( + inverse_move_aux[move], aux); + if (is_solved(cube, false)) + moves_ttable[m][mi] = move; + } + } + } + } + + if (!write_ttables_file()) + fprintf(stderr, "Error writing ttables\n"); +} + +static void +init_trans_aux() +{ + ep_mirror[UF] = UF; + ep_mirror[UL] = UR; + ep_mirror[UB] = UB; + ep_mirror[UR] = UL; + ep_mirror[DF] = DF; + ep_mirror[DL] = DR; + ep_mirror[DB] = DB; + ep_mirror[DR] = DL; + ep_mirror[FR] = FL; + ep_mirror[FL] = FR; + ep_mirror[BR] = BL; + ep_mirror[BL] = BR; + + cp_mirror[UFR] = UFL; + cp_mirror[UFL] = UFR; + cp_mirror[UBL] = UBR; + cp_mirror[UBR] = UBL; + cp_mirror[DFR] = DFL; + cp_mirror[DFL] = DFR; + cp_mirror[DBL] = DBR; + cp_mirror[DBR] = DBL; + + cpos_mirror[U_center] = U_center; + cpos_mirror[D_center] = D_center; + cpos_mirror[R_center] = L_center; + cpos_mirror[L_center] = R_center; + cpos_mirror[F_center] = F_center; + cpos_mirror[B_center] = B_center; + + /* Is there a more elegant way? */ + trans_algs[uf] = new_alg(""); + trans_algs[ur] = new_alg("y"); + trans_algs[ub] = new_alg("y2"); + trans_algs[ul] = new_alg("y3"); + + trans_algs[df] = new_alg("z2"); + trans_algs[dr] = new_alg("y z2"); + trans_algs[db] = new_alg("x2"); + trans_algs[dl] = new_alg("y3 z2"); + + trans_algs[rf] = new_alg("z3"); + trans_algs[rd] = new_alg("z3 y"); + trans_algs[rb] = new_alg("z3 y2"); + trans_algs[ru] = new_alg("z3 y3"); + + trans_algs[lf] = new_alg("z"); + trans_algs[ld] = new_alg("z y3"); + trans_algs[lb] = new_alg("z y2"); + trans_algs[lu] = new_alg("z y"); + + trans_algs[fu] = new_alg("x y2"); + trans_algs[fr] = new_alg("x y"); + trans_algs[fd] = new_alg("x"); + trans_algs[fl] = new_alg("x y3"); + + trans_algs[bu] = new_alg("x3"); + trans_algs[br] = new_alg("x3 y"); + trans_algs[bd] = new_alg("x3 y2"); + trans_algs[bl] = new_alg("x3 y3"); +} + + +/* Public functions implementation *******************************************/ + +Cube +apply_alg(Alg *alg, Cube cube) +{ + return apply_alg_generic(alg, cube, pf_all, true); +} + +Cube +apply_move(Move m, Cube cube) +{ + 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] + }; +} + +Cube +apply_trans(Trans t, Cube cube) +{ + 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] + }; +} + +Move +base_move(Move m) +{ + if (m == NULLMOVE) + return NULLMOVE; + else + return m - (m-1)%3; +} + +Cube +compose(Cube c2, Cube c1) +{ + return compose_filtered(c2, c1, pf_all); +} + +uint64_t +cphtr(Cube cube) +{ + return cphtr_cosets[cube.cp]; +} + +uint64_t +epos_dependent(Cube c) +{ + return epos_dependent_aux[c.eposs/FACTORIAL4][c.epose/FACTORIAL4]; +} + +bool +equal(Cube c1, Cube c2) +{ + 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; +} + +void +genalgset(AlgSet *as) +{ + uint64_t i; + + if (as->generated) + return; + + /* TODO: check if memory is enough, otherwise maybe crash gracefully? */ + as->table = malloc(as->size * sizeof(AlgList *)); + + if (read_algset_file(as)) { + as->generated = true; + return; + } + + fprintf(stderr, "Cannot load %s, generating it\n", as->filename); + + for (i = 0; i < as->size; i++) { + as->table[i] = solve(as->antindex(i), as->step, &as->opts); + fprintf(stderr, "Generated %lu / %lu cases\n", i, as->size); + } + + if (!write_algset_file(as)) + fprintf(stderr, "Error writing algset file\n"); + + as->generated = true; +} + +void +genptable(PruneData *pd) +{ + uint64_t j; + DfsData dd = { + .m = 0, + .last1 = NULLMOVE, + .last2 = NULLMOVE + }; + + if (pd->generated) + return; + + /* TODO: check if memory is enough, otherwise maybe crash gracefully? */ + pd->ptable = malloc(ptablesize(pd) * sizeof(uint8_t)); + + if (read_ptable_file(pd)) { + pd->generated = true; + return; + } + + fprintf(stderr, "Cannot load %s, generating it\n", pd->filename); + + /* We use 4 bits per value, so any distance >= 15 is set to 15 */ + for (j = 0; j < pd->size; j++) + ptable_update(pd, j, 15); + + moveset_to_list(pd->moveset, NULL, dd.sorted_moves); + movelist_to_position(dd.sorted_moves, dd.move_position); + + pd->reached = malloc(ptablesize(pd) * sizeof(uint8_t)); + for (dd.d = 0, pd->n = 0; dd.d < 15 && pd->n < pd->size; dd.d++) { + memset(pd->reached, 0, ptablesize(pd)*sizeof(uint8_t)); + genptable_dfs((Cube){0}, pd, &dd); + fprintf(stderr, "Depth %d completed, generated %lu/%lu\n", + dd.d, pd->n, pd->size); + } + + if (!write_ptable_file(pd)) + fprintf(stderr, "Error writing ptable file\n"); + + pd->generated = true; + free(pd->reached); +} + +Cube +inverse_cube(Cube cube) +{ + CubeArray *arr = new_cubearray(cube, pf_all); + CubeArray *inv = new_cubearray((Cube){0}, pf_all); + Cube ret; + int i; + + for (i = 0; i < 12; i++) { + inv->ep[arr->ep[i]] = i; + inv->eofb[arr->ep[i]] = arr->eofb[i]; + inv->eorl[arr->ep[i]] = arr->eorl[i]; + inv->eoud[arr->ep[i]] = arr->eoud[i]; + } + + for (i = 0; i < 8; i++) { + inv->cp[arr->cp[i]] = i; + inv->coud[arr->cp[i]] = (3 - arr->coud[i]) % 3; + inv->corl[arr->cp[i]] = (3 - arr->corl[i]) % 3; + inv->cofb[arr->cp[i]] = (3 - arr->cofb[i]) % 3; + } + + for (int i = 0; i < 6; i++) + inv->cpos[arr->cpos[i]] = i; + + ret = arrays_to_cube(inv, pf_all); + free_cubearray(arr, pf_all); + free_cubearray(inv, pf_all); + + return ret; +} + +Move +inverse_move(Move m) +{ + return inverse_move_aux[m]; +} + +Trans +inverse_trans(Trans t) +{ + return inverse_trans_aux[t]; +} + +bool +is_admissible(Cube cube) +{ + /* TODO: this should check consistency of different orientations */ + /* TODO: check that centers are opposite and admissible */ + + CubeArray *a = new_cubearray(cube, pf_all); + int parity; + bool perm; + + 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); + + return perm && parity % 2 == 0; +} + +bool +is_solved(Cube cube, bool reorient) +{ + Trans i; + + if (reorient) + for (i = 0; i < NROTATIONS; i++) + if (is_solved(apply_alg(trans_algs[i],cube), false)) + return true; + + return equal(cube, (Cube){0}); +} + +bool +is_solved_block(Cube cube, Block block) +{ + 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; + + return true; +} + +bool +is_solved_center(Cube cube, Center c) +{ + return what_center_at(cube, c) == c; +} + +bool +is_solved_corner(Cube cube, Corner c) +{ + return what_corner_at(cube, c) == c && + what_orientation_corner(cube.coud, c); +} + +bool +is_solved_edge(Cube cube, Edge e) +{ + return what_edge_at(cube, e) == e && + what_orientation_edge(cube.eofb, e); +} + +int +piece_orientation(Cube cube, int piece, char *orientation) +{ + 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) +{ +/* + CubeArray *arr = new_cubearray(cube, pf_all); + + for (int i = 0; i < 12; i++) + printf(" %s ", edge_string[arr->ep[i]]); + printf("\n"); + + for (int i = 0; i < 12; i++) + printf(" %c ", arr->eofb[i] + '0'); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf("%s ", corner_string[arr->cp[i]]); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf(" %c ", arr->coud[i] + '0'); + printf("\n"); + + for (int i = 0; i < 6; i++) + printf(" %s ", center_string[arr->cpos[i]]); + printf("\n"); + + free_cubearray(arr, pf_all); +*/ + + for (int i = 0; i < 12; i++) + printf(" %s ", edge_string[what_edge_at(cube, i)]); + printf("\n"); + + for (int i = 0; i < 12; i++) + printf(" %d ", what_orientation_edge(cube.eofb, i)); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf("%s ", corner_string[what_corner_at(cube, i)]); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf(" %d ", what_orientation_corner(cube.coud, i)); + printf("\n"); + + for (int i = 0; i < 6; i++) + printf(" %s ", center_string[what_center_at(cube, i)]); + printf("\n"); + +} + +Cube +random_cube() +{ + CubeArray *arr = new_cubearray((Cube){0}, pf_4val); + Cube ret; + int ep, cp, eo, co; + + ep = rand() % FACTORIAL12; + cp = rand() % FACTORIAL8; + eo = rand() % POW2TO11; + co = rand() % POW3TO7; + + index_to_perm(ep, 12, arr->ep); + index_to_perm(cp, 8, arr->cp); + int_to_sum_zero_array(eo, 2, 12, arr->eofb); + int_to_sum_zero_array(co, 3, 8, arr->coud); + + if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8)) + swap(&(arr->ep[0]), &(arr->ep[1])); + + ret = arrays_to_cube(arr, pf_4val); + free_cubearray(arr, pf_4val); + + return ret; +} + +AlgList * +solve(Cube cube, Step step, SolveOptions *opts) +{ + AlgListNode *node; + AlgList *sols = new_alglist(); + Cube c = apply_trans(opts->pre_trans, cube); + DfsData dd = { + .m = 0, + .niss = false, + .lb = -1, + .last1 = NULLMOVE, + .last2 = NULLMOVE, + .sols = sols, + .current_alg = new_alg("") + }; + + if (step.ready != NULL && step.ready(c, 1) != 0) { + fprintf(stderr, "Cube not ready for solving step\n"); + return sols; + } + + moveset_to_list(step.moveset, step.check, dd.sorted_moves); + movelist_to_position(dd.sorted_moves, dd.move_position); + + for (dd.d = opts->min_moves; + dd.d <= opts->max_moves && !(sols->len && opts->optimal_only); + dd.d++) { + if (opts->feedback) + fprintf(stderr, + "Found %d solutions, searching depth %d...\n", + sols->len, dd.d); + dfs(c, step, opts, &dd); + } + + for (node = sols->first; node != NULL; node = node->next) + transform_alg(inverse_trans_aux[opts->pre_trans], node->alg); + + free_alg(dd.current_alg); + return sols; +} + +Alg * +inverse_alg(Alg *alg) +{ + Alg *ret = new_alg(""); + int i; + + for (i = alg->len-1; i >= 0; i--) + append_move(ret, alg->move[i], alg->inv[i]); + + return ret; +} + +Alg * +new_alg(char *str) +{ + Alg *alg = malloc(sizeof(Alg)); + int i; + bool niss = false; + Move j, m; + + alg->move = malloc(30 * sizeof(Move)); + alg->inv = malloc(30 * sizeof(bool)); + alg->allocated = 30; + alg->len = 0; + + for (i = 0; str[i]; i++) { + if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n') + continue; + + if (str[i] == '(' && niss) { + fprintf(stderr, "Error reading moves: nested ( )\n"); + return alg; + } + + if (str[i] == ')' && !niss) { + fprintf(stderr, "Error reading moves: unmatched )\n"); + return alg; + } + + if (str[i] == '(' || str[i] == ')') { + niss = !niss; + continue; + } + + for (j = 0; j < NMOVES; j++) { + if (str[i] == move_string[j][0]) { + m = j; + if (m <= B && str[i+1]=='w') { + m += Uw - U; + i++; + } + if (str[i+1]=='2') { + m += 1; + i++; + } else if (str[i+1]=='\'' || str[i+1]=='3') { + m += 2; + i++; + } + append_move(alg, m, niss); + break; + } + } + } + + return alg; +} + +Alg * +on_inverse(Alg *alg) +{ + Alg *ret = new_alg(""); + int i; + + for (i = 0; i < alg->len; i++) + append_move(ret, alg->move[i], !alg->inv[i]); + + return ret; +} + +void +print_alg(Alg *alg, bool l) +{ + /* TODO: make it possible to print to stdout or to string */ + /* Maybe just return a string */ + char fill[4]; + int i; + bool niss = false; + + for (i = 0; i < alg->len; i++) { + if (!niss && alg->inv[i]) + strcpy(fill, i == 0 ? "(" : " ("); + if (niss && !alg->inv[i]) + strcpy(fill, ") "); + if (niss == alg->inv[i]) + strcpy(fill, i == 0 ? "" : " "); + + printf("%s%s", fill, move_string[alg->move[i]]); + niss = alg->inv[i]; + } + + if (niss) + printf(")"); + if (l) + printf(" (%d)", alg->len); + + printf("\n"); +} + +void +print_alglist(AlgList *al, bool l) +{ + AlgListNode *i; + + for (i = al->first; i != NULL; i = i->next) + print_alg(i->alg, l); +} + +void +print_ptable(PruneData *pd) +{ + uint64_t i, a[16]; + + for (i = 0; i < 16; i++) + a[i] = 0; + + if (!pd->generated) + genptable(pd); + + for (i = 0; i < pd->size; i++) + a[ptableval(pd, i)]++; + + fprintf(stderr, "Values for table %s\n", pd->filename); + for (i = 0; i < 16; i++) + printf("%2lu\t%10lu\n", i, a[i]); +} + +uint64_t +ptablesize(PruneData *pd) +{ + return (pd->size + 1) / 2; +} + +int +ptableval(PruneData *pd, uint64_t ind) +{ + return (ind % 2) ? pd->ptable[ind/2] / 16 : pd->ptable[ind/2] % 16; +} + + +Alg * +trans_alg(Trans i) +{ + return trans_algs[i]; +} + +void +transform_alg(Trans t, Alg *alg) +{ + int i; + + for (i = 0; i < alg->len; i++) + alg->move[i] = moves_ttable[t][alg->move[i]]; +} + +Center +what_center_at(Cube cube, Center c) +{ + return what_center_at_aux[cube.cpos][c]; +} + +Corner +what_corner_at(Cube cube, Corner c) +{ + return what_corner_at_aux[cube.cp][c]; +} + +Edge +what_edge_at(Cube cube, Edge e) +{ + Edge ret; + CubeArray *arr = new_cubearray(cube, pf_ep); + + ret = arr->ep[e]; + + free_cubearray(arr, pf_ep); + return ret; +} + +int +what_orientation_corner(int co, Corner c) +{ + if (c < 7) + return (co / powint(3, c)) % 3; + else + return what_orientation_last_corner_aux[co]; +} + +int +what_orientation_edge(int eo, Edge e) +{ + if (e < 11) + return (eo & (1 << e)) ? 1 : 0; + else + return what_orientation_last_edge_aux[eo]; +} + +Center +where_is_center(Cube cube, Center c) +{ + return where_is_center_aux[cube.cpos][c]; +} + +Corner +where_is_corner(Cube cube, Corner c) +{ + return where_is_corner_aux[cube.cp][c]; +} + + +void +init() +{ + /* Order is important! */ + init_environment(); + init_strings(); + init_moves_aux(); + init_moves(); + init_auxtables(); + init_cphtr_cosets(); + init_trans_aux(); + init_trans(); +} + diff --git a/old/2021-06-23-realizing-bad-tables/cube.h b/old/2021-06-23-realizing-bad-tables/cube.h new file mode 100644 index 0000000..dcad047 --- /dev/null +++ b/old/2021-06-23-realizing-bad-tables/cube.h @@ -0,0 +1,88 @@ +#ifndef CUBE_H +#define CUBE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Constants and macros *****************************************************/ + +#define POW2TO6 64ULL +#define POW2TO11 2048ULL +#define POW2TO12 4096ULL +#define POW3TO7 2187ULL +#define POW3TO8 6561ULL +#define FACTORIAL4 24ULL +#define FACTORIAL6 720ULL +#define FACTORIAL7 5040ULL +#define FACTORIAL8 40320ULL +#define FACTORIAL12 479001600ULL +#define BINOM12ON4 495ULL +#define BINOM8ON4 70ULL +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +#define NMOVES (z3+1) +#define NTRANS (mirror+1) +#define NROTATIONS (NTRANS-1) + +/* Type definitions **********************************************************/ + +#include "cubetypes.h" + +/* Public functions **********************************************************/ + +Cube apply_alg(Alg *alg, Cube cube); +Cube apply_move(Move m, Cube cube); +Cube apply_trans(Trans t, Cube cube); +bool block_solved(Cube cube, Block); +Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */ +uint64_t cphtr(Cube cube); +uint64_t epos_dependent(Cube cube); +bool equal(Cube c1, Cube c2); +Cube inverse_cube(Cube cube); +Move inverse_move(Move m); +Trans inverse_trans(Trans t); +bool is_admissible(Cube cube); +bool is_solved(Cube cube, bool reorient); +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 print_cube(Cube cube); +Cube random_cube(); +AlgList * solve(Cube cube, Step step, SolveOptions *opts); +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); + +Move base_move(Move m); +void free_alg(Alg *alg); +void free_alglist(AlgList *l); +Alg * inverse_alg(Alg *alg); +Alg * new_alg(char *str); +Alg * on_inverse(Alg *alg); +void print_alg(Alg *alg, bool l); +void print_alglist(AlgList *al, bool l); +Alg * trans_alg(Trans i); +void transform_alg(Trans t, Alg *alg); + +void genalgset(AlgSet *as); +void genptable(PruneData *pd); +void print_ptable(PruneData *pd); +uint64_t ptablesize(PruneData *pd); +int ptableval(PruneData *pd, uint64_t ind); + +void init(); + +#endif + diff --git a/old/2021-06-23-realizing-bad-tables/cubetypes.h b/old/2021-06-23-realizing-bad-tables/cubetypes.h new file mode 100644 index 0000000..886295c --- /dev/null +++ b/old/2021-06-23-realizing-bad-tables/cubetypes.h @@ -0,0 +1,224 @@ +/* Typedefs ******************************************************************/ + +typedef enum center Center; +typedef enum corner Corner; +typedef enum edge Edge; +typedef enum move Move; +typedef enum trans Trans; + +typedef struct alg Alg; +typedef struct alglist AlgList; +typedef struct alglistnode AlgListNode; +typedef struct algset AlgSet; +typedef struct block Block; +typedef struct cube Cube; +typedef struct cubearray CubeArray; +typedef struct dfsdata DfsData; +typedef struct piecefilter PieceFilter; +typedef struct prunedata PruneData; +typedef struct solveoptions SolveOptions; +typedef struct step Step; + +typedef Cube (*AntiIndexer) (uint64_t); +typedef int (*Checker) (Cube, int); +typedef uint64_t (*Indexer) (Cube); +typedef bool (*Moveset) (Move); + + +/* Enums *********************************************************************/ + +enum +center +{ + U_center, D_center, + R_center, L_center, + F_center, B_center +}; + +enum +corner +{ + UFR, UFL, UBL, UBR, + DFR, DFL, DBL, DBR +}; + +enum +edge +{ + UF, UL, UB, UR, + DF, DL, DB, DR, + FR, FL, BL, BR +}; + +enum +move +{ + NULLMOVE, + U, U2, U3, D, D2, D3, + R, R2, R3, L, L2, L3, + F, F2, F3, B, B2, B3, + Uw, Uw2, Uw3, Dw, Dw2, Dw3, + Rw, Rw2, Rw3, Lw, Lw2, Lw3, + Fw, Fw2, Fw3, Bw, Bw2, Bw3, + M, M2, M3, + S, S2, S3, + E, E2, E3, + x, x2, x3, + y, y2, y3, + z, z2, z3, +}; + +enum +trans +{ + uf, ur, ub, ul, + df, dr, db, dl, + rf, rd, rb, ru, + lf, ld, lb, lu, + fu, fr, fd, fl, + bu, br, bd, bl, + mirror, /* R|L */ +}; + + +/* Structs *******************************************************************/ + +struct +alg +{ + Move * move; + bool * inv; + int len; + int allocated; +}; + +struct +alglist +{ + AlgListNode * first; + AlgListNode * last; + int len; +}; + +struct +alglistnode +{ + Alg * alg; + AlgListNode * next; +}; + +struct +block +{ + bool edge[12]; + bool corner[8]; + bool center[6]; +}; + +struct +cube +{ + int epose; + int eposs; + int eposm; + int eofb; + int eorl; + int eoud; + int cp; + int coud; + int cofb; + int corl; + int cpos; +}; + +struct +cubearray +{ + int * ep; + int * eofb; + int * eorl; + int * eoud; + int * cp; + int * coud; + int * corl; + int * cofb; + int * cpos; +}; + +struct +dfsdata +{ + int d; + int m; + int lb; + bool niss; + Move last1; + Move last2; + AlgList * sols; + Alg * current_alg; + Move sorted_moves[NMOVES]; + int move_position[NMOVES]; +}; + +struct +piecefilter +{ + 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; + uint8_t * ptable; + uint8_t * reached; + bool generated; + uint64_t n; + uint64_t size; + Indexer index; + Moveset moveset; +}; + +struct +solveoptions +{ + int min_moves; + int max_moves; + int max_solutions; + bool optimal_only; + bool can_niss; + bool feedback; + Trans pre_trans; +}; + +struct +step +{ + Checker check; + Checker ready; + Moveset moveset; +}; + +/* TODO: I put it here because it needs the definition of Step, sort it out */ +struct +algset +{ + char * filename; + AlgList ** table; + bool generated; + uint64_t size; + Indexer index; + AntiIndexer antindex; + Step step; + SolveOptions opts; +}; diff --git a/old/2021-06-23-realizing-bad-tables/main.c b/old/2021-06-23-realizing-bad-tables/main.c new file mode 100644 index 0000000..e0e049a --- /dev/null +++ b/old/2021-06-23-realizing-bad-tables/main.c @@ -0,0 +1,70 @@ +#include +#include "cube.h" +#include "steps.h" + +int main() { + Alg *algo; + AlgList *sols; + Cube cube; + SolveOptions opts; + char line[1000]; + int i, ns = 3; +/* int nrand = 10000, sum1, sum2, sum3;*/ + + Step *stps[20] = {&corners_HTM, &eofb_HTM, &optimal_HTM}; + char sss[30][30] = {"Corners", "EO on F/B", "Optimal solution"}; + + opts = (SolveOptions) { + .min_moves = 0, + .max_moves = 20, + .optimal_only = true, + .max_solutions = 1, + .can_niss = false, + .feedback = true, + .pre_trans = uf + }; + + init(); + + print_ptable(&pd_corners_HTM); + +/* + srand(time(NULL)); + sum1 = 0; + sum2 = 0; + sum3 = 0; + for (i = 0; i < nrand; i++) { + cube = random_cube(); + sum1 += corners_HTM.check(cube, 20); + sum2 += cornershtr_HTM.check(cube, 20); + sum3 += optimal_HTM.check(cube, 20); + } + printf("Average corners pruning: %lf\n", ((double)sum1) / ((double) nrand)); + printf("Average corners htr pruning: %lf\n", ((double)sum2) / ((double) nrand)); + printf("Average optimal pruning: %lf\n", ((double)sum3) / ((double) nrand)); +*/ + + printf("Welcome to nissy 2.0! Insert a scramble:\n"); + + if (fgets(line, 1000, stdin) != NULL) { + algo = new_alg(line); + cube = apply_alg(algo, (Cube){0}); + + print_cube(cube); + printf("Index: %lu\n", pd_cornershtr_HTM.index(cube)); + + for (i = 0; i < ns; i++) { + if (stps[i]->check == NULL) + fprintf(stderr, "Check function for step %d is null\n", i); + printf("Check: %d\n", stps[i]->check(cube, 20)); + sols = solve(cube, *stps[i], &opts); + printf("%s: %d solutions found:\n", sss[i], sols->len); + print_alglist(sols, true); + free_alglist(sols); + } + free_alg(algo); + } + + return 0; +} + diff --git a/old/2021-06-23-realizing-bad-tables/steps.c b/old/2021-06-23-realizing-bad-tables/steps.c new file mode 100644 index 0000000..2b029b8 --- /dev/null +++ b/old/2021-06-23-realizing-bad-tables/steps.c @@ -0,0 +1,486 @@ +#include "steps.h" + +/* Check functions ***********************************************************/ + +static int check_nothing(Cube cube, int target); +static int check_centers(Cube cube, int target); +static int check_eofb_HTM(Cube cube, int target); +static int check_coud_HTM(Cube cube, int target); +static int check_coud_URF(Cube cube, int target); +static int check_corners_HTM(Cube cube, int target); +static int check_cornershtr_HTM(Cube cube, int target); +static int check_corners_URF(Cube cube, int target); +static int check_cornershtr_URF(Cube cube, int target); +static int check_ep_HTM(Cube cube, int target); +static int check_edges_HTM(Cube cube, int target); +static int check_drud_HTM(Cube cube, int target); +static int check_optimal_HTM(Cube cube, int target); +static int check_corners6eo_HTM(Cube cube, int target); +static int check_tripleeo_HTM(Cube cube, int target); + + +/* Index functions ***********************************************************/ + +static uint64_t index_eofb(Cube cube); +static uint64_t index_coud(Cube cube); +static uint64_t index_corners(Cube cube); +static uint64_t index_cornershtr(Cube cube); +static uint64_t index_ep(Cube cube); +static uint64_t index_drud(Cube cube); +static uint64_t index_corners6eo(Cube cube); +static uint64_t index_tripleeo(Cube cube); + + +/* Steps *********************************************************************/ + +Step +eofb_HTM = { + .check = check_eofb_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + +Step +coud_HTM = { + .check = check_coud_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + +Step +coud_URF = { + .check = check_coud_URF, + .ready = check_nothing, + .moveset = moveset_URF +}; + +Step +corners_HTM = { + .check = check_corners_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + +Step +cornershtr_HTM = { + .check = check_cornershtr_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + +Step +cornershtr_URF = { + .check = check_cornershtr_URF, + .ready = check_nothing, + .moveset = moveset_URF +}; + +Step +corners_URF = { + .check = check_corners_URF, + .ready = check_nothing, + .moveset = moveset_URF +}; + +Step +edges_HTM = { + .check = check_edges_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + +Step +drud_HTM = { + .check = check_drud_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + +Step +optimal_HTM = { + .check = check_optimal_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + +Step +tripleeo_HTM = { + .check = check_tripleeo_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + + +/* Blocks ********************************************************************/ + +Block +block_223dl = { + .edge = { [DF] = 1, [DL] = 1, [DB] = 1, [FL] = 1, [BL] = 1 }, + .corner = { [DFL] = 1, [DBL] = 1 }, + .center = { [D_center] = 1, [L_center] = 1 } +}; + + +/* Pruning tables ************************************************************/ + +PruneData +pd_eofb_HTM = { + .filename = "ptable_eofb_HTM", + .size = POW2TO11, + .index = index_eofb, + .moveset = moveset_HTM +}; + +PruneData +pd_coud_HTM = { + .filename = "ptable_coud_HTM", + .size = POW3TO7, + .index = index_coud, + .moveset = moveset_HTM +}; + +PruneData +pd_cornershtr_HTM = { + .filename = "ptable_cornershtr_HTM", + .size = POW3TO7 * BINOM8ON4 * 6, /*TODO: check */ + .index = index_cornershtr, + .moveset = moveset_HTM +}; + +PruneData +pd_corners_HTM = { + .filename = "ptable_corners_HTM", + .size = POW3TO7 * FACTORIAL8, + .index = index_corners, + .moveset = moveset_HTM +}; + +PruneData +pd_ep_HTM = { + .filename = "ptable_ep_HTM", + .size = FACTORIAL12, + .index = index_ep, + .moveset = moveset_HTM +}; + +PruneData +pd_drud_HTM = { + .filename = "ptable_drud_HTM", + .size = POW2TO11 * POW3TO7 * BINOM12ON4, + .index = index_drud, + .moveset = moveset_HTM +}; + +PruneData +pd_corners6eo_HTM = { + .filename = "ptable_corners6eo_HTM", + .size = POW2TO6 * POW3TO7 * FACTORIAL8, + .index = index_corners6eo, + .moveset = moveset_HTM +}; + +PruneData +pd_tripleeo_HTM = { + .filename = "ptable_tripleeo_HTM", + .size = BINOM12ON4 * BINOM8ON4 * POW2TO11, + .index = index_tripleeo, + .moveset = moveset_HTM +}; + + +/* Alg sets ******************************************************************/ + +/* TODO: remove this (I am only keeping it as an example for future algesets) +AlgSet +as_ephtr_HTM = { + .filename = "algset_ephtr_HTM", + .size = FACTORIAL4 * FACTORIAL4 * FACTORIAL4, + .index = index_ephtr, + .antindex = index_to_cube_ephtr, + .step = (Step) { + .check = check_optimal_HTM, + .ready = check_htr_solved_corners_HTM, + .moveset = moveset_HTM + }, + .opts = (SolveOptions) { + .min_moves = 0, + .max_moves = 20, + .max_solutions = 1, + .optimal_only = true, + .can_niss = false, + .feedback = true, + .pre_trans = uf + } +}; +*/ + + +/* Check functions implementation ********************************************/ + +static int +check_nothing(Cube cube, int target) +{ + return 0; +} + +static int +check_centers(Cube cube, int target) +{ + return (cube.cpos == 0) ? 0 : 1; +} + +static int +check_eofb_HTM(Cube cube, int target) +{ + if (!pd_eofb_HTM.generated) + genptable(&pd_eofb_HTM); + + return ptableval(&pd_eofb_HTM, cube.eofb); +} + +static int +check_coud_HTM(Cube cube, int target) +{ + if (!pd_coud_HTM.generated) + genptable(&pd_coud_HTM); + + return ptableval(&pd_coud_HTM, cube.coud); +} + +static int +check_coud_URF(Cube cube, int target) +{ + /* TODO: I can improve this by checking first the orientation of + * the corner in DBL and use that as a reference */ + + int ud = check_coud_HTM(cube, target); + int rl = check_coud_HTM(apply_move(z, cube), target); + int fb = check_coud_HTM(apply_move(x, cube), target); + + return MIN(ud, MIN(rl, fb)); +} + +static int +check_corners_HTM(Cube cube, int target) +{ + if (!pd_corners_HTM.generated) + genptable(&pd_corners_HTM); + + return ptableval(&pd_corners_HTM, index_corners(cube)); +} + +static int +check_cornershtr_HTM(Cube cube, int target) +{ + if (!pd_cornershtr_HTM.generated) + genptable(&pd_cornershtr_HTM); + + return ptableval(&pd_cornershtr_HTM, index_cornershtr(cube)); +} + +static int +check_cornershtr_URF(Cube cube, int target) +{ + /* TODO: I can improve this by checking first the corner in DBL + * and use that as a reference */ + + int c, ret = 15; + Trans i; + + for (i = 0; i < NROTATIONS; i++) { + c = check_cornershtr_HTM(apply_alg(trans_alg(i),cube), target); + ret = MIN(ret, c); + } + + return ret; +} + +static int +check_corners_URF(Cube cube, int target) +{ + /* TODO: I can improve this by checking first the corner in DBL + * and use that as a reference */ + + int ret = 15; + Trans i; + + for (i = 0; i < NROTATIONS; i++) + ret = MIN(ret, check_corners_HTM( + apply_alg(trans_alg(i), cube), target)); + + return ret; +} + +static int +check_ep_HTM(Cube cube, int target) +{ + if (!pd_ep_HTM.generated) + genptable(&pd_ep_HTM); + + return ptableval(&pd_ep_HTM, index_ep(cube)); +} + +static int +check_edges_HTM(Cube cube, int target) +{ + return MAX(check_ep_HTM(cube, target), + check_tripleeo_HTM(cube, target)); +} + +static int +check_drud_HTM(Cube cube, int target) +{ + if (!pd_drud_HTM.generated) + genptable(&pd_drud_HTM); + + return ptableval(&pd_drud_HTM, index_drud(cube)); +} + +static int +check_optimal_HTM(Cube cube, int target) +{ + int dr1, dr2, dr3, cor, ret; + Cube cube2, cube3; + + dr1 = check_drud_HTM(cube, target); + /*cor = check_corners6eo_HTM(cube, target);*/ + cor = check_corners_HTM(cube, target); + ret = MAX(dr1, cor); + + if (ret > target) + return ret; + + cube2 = apply_trans(rf, cube); + dr2 = check_drud_HTM(cube2, target); + /*cor = check_corners6eo_HTM(cube2, target); + ret = MAX(ret, MAX(dr2, cor));*/ + ret = MAX(ret, dr2); + + if (ret > target) + return ret; + + cube3 = apply_trans(bd, cube); + dr3 = check_drud_HTM(cube3, target); + /*cor = check_corners6eo_HTM(cube3, target);*/ + + if (dr1 == dr2 && dr2 == dr3 && dr1 != 0) + dr3++; + + /*ret = MAX(ret, MAX(dr3, cor));*/ + ret = MAX(ret, dr3); + + if (ret == 0) + return (!cube.epose && !cube.eposs && !cube.eposm) ? 0 : 6; + + return ret; +} + +static int +check_corners6eo_HTM(Cube cube, int target) +{ + if (!pd_corners6eo_HTM.generated) + genptable(&pd_corners6eo_HTM); + + return ptableval(&pd_corners6eo_HTM, index_corners6eo(cube)); +} + +static int +check_tripleeo_HTM(Cube cube, int target) +{ + if (!pd_tripleeo_HTM.generated) + genptable(&pd_tripleeo_HTM); + + return ptableval(&pd_tripleeo_HTM, index_tripleeo(cube)); +} + + +/* Index functions implementation ********************************************/ + +static uint64_t +index_eofb(Cube cube) +{ + return cube.eofb; +} + +static uint64_t +index_coud(Cube cube) +{ + return cube.coud; +} + +static uint64_t +index_cornershtr(Cube cube) +{ + return cube.coud * BINOM8ON4 * 6 + cphtr(cube); +} + +static uint64_t +index_corners(Cube cube) +{ + return cube.coud * FACTORIAL8 + cube.cp; +} + +static uint64_t +index_ep(Cube cube) +{ + uint64_t a, b, c; + + a = cube.epose; + b = (cube.eposs % FACTORIAL4) + epos_dependent(cube)*FACTORIAL4; + c = cube.eposm % FACTORIAL4; + + b *= FACTORIAL4 * BINOM12ON4; + c *= FACTORIAL4 * BINOM12ON4 * FACTORIAL4 * BINOM8ON4; + + return a + b + c; +} + +static uint64_t +index_drud(Cube cube) +{ + uint64_t a, b, c; + + a = cube.eofb; + b = cube.coud; + c = cube.epose / FACTORIAL4; + + b *= POW2TO11; + c *= POW2TO11 * POW3TO7; + + return a + b + c; +} + +static uint64_t +index_corners6eo(Cube cube) +{ + return (cube.coud*FACTORIAL8 + cube.cp)*POW2TO6 + (cube.eofb%POW2TO6); +} + +static uint64_t +index_tripleeo(Cube cube) +{ + uint64_t ee, es; + + ee = cube.epose / FACTORIAL4; + es = epos_dependent(cube); + + return (ee * BINOM8ON4 + es) * POW2TO11 + cube.eofb; +} + + +/* Movesets ******************************************************************/ + +bool +moveset_HTM(Move m) +{ + return m >= U && m <= B3; +} + +bool +moveset_URF(Move m) +{ + Move b = base_move(m); + + return b == U || b == R || b == F; +} + diff --git a/old/2021-06-23-realizing-bad-tables/steps.h b/old/2021-06-23-realizing-bad-tables/steps.h new file mode 100644 index 0000000..9d8bf6a --- /dev/null +++ b/old/2021-06-23-realizing-bad-tables/steps.h @@ -0,0 +1,42 @@ +#ifndef STEPS_H +#define STEPS_H + +#include "cube.h" + +/* Steps *********************************************************************/ + +extern Step eofb_HTM; +extern Step coud_HTM; +extern Step coud_URF; +extern Step corners_HTM; +extern Step cornershtr_HTM; +extern Step corners_URF; +extern Step cornershtr_URF; +extern Step edges_HTM; +extern Step drud_HTM; +extern Step optimal_HTM; +extern Step tripleeo_HTM; + +/* Blocks ********************************************************************/ + +extern Block block_223dl; + +/* Pruning tables ************************************************************/ + +extern PruneData pd_eofb_HTM; +extern PruneData pd_coud_HTM; +extern PruneData pd_corners_HTM; +extern PruneData pd_cornershtr_HTM; +extern PruneData pd_ep_HTM; +extern PruneData pd_drud_HTM; +extern PruneData pd_tripleeo_HTM; + +/* Alg sets ******************************************************************/ + + +/* Movesets ******************************************************************/ + +bool moveset_HTM(Move m); +bool moveset_URF(Move m); + +#endif diff --git a/old/2021-06-23-uint16t/cube.c b/old/2021-06-23-uint16t/cube.c new file mode 100644 index 0000000..0381ba0 --- /dev/null +++ b/old/2021-06-23-uint16t/cube.c @@ -0,0 +1,2762 @@ +#include "cube.h" + +/* Local functions **********************************************************/ + +static Cube admissible_ep(Cube cube, PieceFilter f); +static bool allowed_next(Move move, DfsData *dd); +static void append_alg(AlgList *l, Alg *alg); +static void append_move(Alg *alg, Move m, bool inverse); +static Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a); +static void apply_permutation(int *perm, int *set, int n); +static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f); +static uint16_t array_ep_to_epos(int *ep, int *eps_solved); +static Cube arrays_to_cube(CubeArray *arr, PieceFilter f); +static int binomial(int n, int k); +static Cube compose_filtered(Cube c2, Cube c1, PieceFilter f); +static void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f); +static void dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static void dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static bool dfs_check_solved(SolveOptions *opts, DfsData *dd); +static void dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static bool dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static int digit_array_to_int(int *a, int n, int b); +static int edge_slice(Edge e); /* E=0, S=1, M=2 */ +static int epos_dependent(int pos1, int pos2); +static uint16_t epos_from_arrays(int *epos, int *ep); +static void epos_to_partial_ep(uint16_t epos, int *ep, int *ss); +static int factorial(int n); +static void free_alglistnode(AlgListNode *aln); +static void free_cubearray(CubeArray *arr, PieceFilter f); +static void genptable_dfs(Cube c, PruneData *pd, DfsData *dd); +static void genptable_dfs_branch(Cube c, PruneData *pd, DfsData *dd); +static void index_to_perm(int p, int n, int *r); +static void index_to_subset(int s, int n, int k, int *r); +static void int_to_digit_array(int a, int b, int n, int *r); +static void int_to_sum_zero_array(int x, int b, int n, int *a); +static int invert_digits(int a, int b, int n); +static bool is_perm(int *a, int n); +static bool is_subset(int *a, int n, int k); +static Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf); +static void movelist_to_position(Move *movelist, int *position); +static void moveset_to_list(Moveset ms, Checker f, Move *r); +static AlgList * new_alglist(); +static CubeArray * new_cubearray(Cube cube, PieceFilter f); +static int perm_sign(int *a, int n); +static int perm_to_index(int *a, int n); +static int powint(int a, int b); +static bool ptable_has_reached(PruneData *pd, uint64_t ind); +static void ptable_set_reached(PruneData *pd, uint64_t ind); +static void ptable_update(PruneData *pd, uint64_t ind, int m); +static void realloc_alg(Alg *alg, int n); +static bool read_algset_file(AlgSet *as); +static bool read_mtables_file(); +static bool read_ptable_file(PruneData *pd); +static bool read_ttables_file(); +static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f); +static int subset_to_index(int *a, int n, int k); +static void sum_arrays_mod(int *src, int *dst, int n, int m); +static void swap(int *a, int *b); +static bool write_algset_file(AlgSet *as); +static bool write_mtables_file(); +static bool write_ptable_file(PruneData *pd); +static bool write_ttables_file(); + +static void init_auxtables(); +static void init_environment(); +static void init_moves(); +static void init_moves_aux(); +static void init_strings(); +static void init_trans(); +static void init_trans_aux(); + +/* All sorts of useful costants and tables **********************************/ + +static char * tabledir; + +static PieceFilter pf_all; +static PieceFilter pf_4val; +static PieceFilter pf_epcp; +static PieceFilter pf_cpos; +static PieceFilter pf_cp; +static PieceFilter pf_ep; +static PieceFilter pf_e; +static PieceFilter pf_s; +static PieceFilter pf_m; +static PieceFilter pf_eo; +static PieceFilter pf_co; + +static int epe_solved[4]; +static int eps_solved[4]; +static int epm_solved[4]; + +static char move_string[NMOVES][7]; +static char edge_string[12][7]; +static char corner_string[8][7]; +static char center_string[6][7]; + +static bool commute[NMOVES][NMOVES]; +static bool possible_next[NMOVES][NMOVES][NMOVES]; +static Move inverse_move_aux[NMOVES]; +static Trans inverse_trans_aux[NTRANS]; +static int epos_dependent_aux[BINOM12ON4][BINOM12ON4]; +static Center what_center_at_aux[FACTORIAL6][6]; +static Corner what_corner_at_aux[FACTORIAL8][8]; +static int what_orientation_last_corner_aux[POW3TO7]; +static int what_orientation_last_edge_aux[POW2TO11]; +static Center where_is_center_aux[FACTORIAL6][6]; +static Corner where_is_corner_aux[FACTORIAL8][8]; +static Edge where_is_edge_aux[3][FACTORIAL12/FACTORIAL8][12]; + +static uint16_t epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static uint16_t eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static uint16_t eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static uint16_t eo_ttable[NTRANS][POW2TO11]; +static uint16_t cp_ttable[NTRANS][FACTORIAL8]; +static uint16_t co_ttable[NTRANS][POW3TO7]; +static uint16_t cpos_ttable[NTRANS][FACTORIAL6]; +static Move moves_ttable[NTRANS][NMOVES]; + +static uint16_t epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static uint16_t eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static uint16_t eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static uint16_t eofb_mtable[NMOVES][POW2TO11]; +static uint16_t eorl_mtable[NMOVES][POW2TO11]; +static uint16_t eoud_mtable[NMOVES][POW2TO11]; +static uint16_t cp_mtable[NMOVES][FACTORIAL8]; +static uint16_t coud_mtable[NMOVES][POW3TO7]; +static uint16_t cofb_mtable[NMOVES][POW3TO7]; +static uint16_t corl_mtable[NMOVES][POW3TO7]; +static uint16_t cpos_mtable[NMOVES][FACTORIAL6]; + +static uint64_t me[12]; + +static int edge_cycle[NMOVES][12]; +static int corner_cycle[NMOVES][8]; +static int center_cycle[NMOVES][6]; +static int eofb_flipped[NMOVES][12]; +static int eorl_flipped[NMOVES][12]; +static int eoud_flipped[NMOVES][12]; +static int coud_flipped[NMOVES][8]; +static int corl_flipped[NMOVES][8]; +static int cofb_flipped[NMOVES][8]; +static Alg * equiv_alg[NMOVES]; + +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]; +static int ep_mirror[12]; +static int cp_mirror[8]; +static int cpos_mirror[6]; +static Alg * trans_algs[NROTATIONS]; + + +/* Local functions implementation ********************************************/ + +static 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 < 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; +} + +static bool +allowed_next(Move move, DfsData *dd) +{ + if (!possible_next[dd->last2][dd->last1][move]) + return false; + + if (commute[dd->last1][move]) + return dd->move_position[dd->last1] < dd->move_position[move]; + + return true; +} + +static void +append_alg(AlgList *l, Alg *alg) +{ + AlgListNode *node = malloc(sizeof(AlgListNode)); + int i; + + node->alg = new_alg(""); + for (i = 0; i < alg->len; i++) + append_move(node->alg, alg->move[i], alg->inv[i]); + node->next = NULL; + + if (++l->len == 1) + l->first = node; + else + l->last->next = node; + l->last = node; +} + +static void +append_move(Alg *alg, Move m, bool inverse) +{ + if (alg->len == alg->allocated) + realloc_alg(alg, 2*alg->len); + + alg->move[alg->len] = m; + alg->inv [alg->len] = inverse; + alg->len++; +} + +static Cube +apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a) +{ + Cube ret = {0}; + int i; + + for (i = 0; i < alg->len; i++) + if (alg->inv[i]) + ret = a ? apply_move(alg->move[i], ret) : + apply_move_cubearray(alg->move[i], ret, f); + + ret = compose_filtered(c, inverse_cube(ret), f); + + for (i = 0; i < alg->len; i++) + if (!alg->inv[i]) + ret = a ? apply_move(alg->move[i], ret) : + apply_move_cubearray(alg->move[i], ret, f); + + return ret; +} + +static void +apply_permutation(int *perm, int *set, int n) +{ + int *aux = malloc(n * sizeof(int)); + int i; + + if (!is_perm(perm, n)) + return; + + for (i = 0; i < n; i++) + aux[i] = set[perm[i]]; + + memcpy(set, aux, n * sizeof(int)); + free(aux); +} + +static Cube +apply_move_cubearray(Move m, Cube cube, PieceFilter f) +{ + 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); +} + +static uint16_t +array_ep_to_epos(int *ep, int *ss) +{ + 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 epos_from_arrays(epos, eps); +} + +static Cube +arrays_to_cube(CubeArray *arr, PieceFilter f) +{ + Cube ret = {0}; + + 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; +} + +static int +binomial(int n, int k) +{ + if (n < 0 || k < 0 || k > n) + return 0; + + return factorial(n) / (factorial(k) * factorial(n-k)); +} + +static Cube +compose_filtered(Cube c2, Cube c1, PieceFilter f) +{ + CubeArray *arr = new_cubearray(c2, f); + Cube ret; + + ret = move_via_arrays(arr, c1, f); + free_cubearray(arr, f); + + return ret; +} + +static void +cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f) +{ + int i; + + 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); +} + +static void +dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + if (dfs_stop(c, s, opts, dd)) + return; + + if (dfs_check_solved(opts, dd)) + return; + + dfs_branch(c, s, opts, dd); + + if (opts->can_niss && !dd->niss) + dfs_niss(c, s, opts, dd); +} + +static void +dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + Move m, l1 = dd->last1, l2 = dd->last2, *moves = dd->sorted_moves; + + int i, maxnsol = opts->max_solutions; + + for (i = 0; (m=moves[i]) != NULLMOVE && dd->sols->len < maxnsol; i++) { + if (allowed_next(m, dd)) { + dd->last2 = dd->last1; + dd->last1 = m; + append_move(dd->current_alg, m, dd->niss); + + dfs(apply_move(m, c), s, opts, dd); + + dd->current_alg->len--; + dd->last2 = l2; + dd->last1 = l1; + } + } +} + +static bool +dfs_check_solved(SolveOptions *opts, DfsData *dd) +{ + if (dd->lb != 0) + return false; + + if (dd->current_alg->len == dd->d) { + append_alg(dd->sols, dd->current_alg); + + if (opts->feedback) + print_alg(dd->current_alg, false); + } + + return true; +} + +static void +dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + Move l1 = dd->last1, l2 = dd->last2; + + if (dd->current_alg->len == 0 || + (s.check(apply_move(inverse_move(l1), (Cube){0}), 1))) { + dd->niss = true; + dd->last1 = NULLMOVE; + dd->last2 = NULLMOVE; + + dfs(inverse_cube(c), s, opts, dd); + + dd->last1 = l1; + dd->last2 = l2; + dd->niss = false; + } +} + +static bool +dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + if (dd->sols->len >= opts->max_solutions) + return true; + + dd->lb = s.check(c, dd->d - dd->current_alg->len); + if (opts->can_niss && !dd->niss) + dd->lb = MIN(1, dd->lb); + + if (dd->current_alg->len + dd->lb > dd->d) + return true; + + return false; +} + +static int +digit_array_to_int(int *a, int n, int b) +{ + int i, ret = 0, p = 1; + + for (i = 0; i < n; i++, p *= b) + ret += a[i] * p; + + return ret; +} + +static int +edge_slice(Edge e) { + if (e < 0 || e > 11) + return -1; + + if (e == FR || e == FL || e == BL || e == BR) + return 0; + if (e == UR || e == UL || e == DR || e == DL) + return 1; + + return 2; +} + +static int +epos_dependent(int poss, int pose) +{ + int ep[12] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; + int ep8[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + int i, j; + + epos_to_partial_ep(poss*FACTORIAL4, ep, eps_solved); + epos_to_partial_ep(pose*FACTORIAL4, ep, epe_solved); + + for (i = 0, j = 0; i < 12; i++) + if (edge_slice(ep[i]) != 0) + ep8[j++] = (edge_slice(ep[i]) == 1) ? 1 : 0; + + swap(&ep8[1], &ep8[4]); + swap(&ep8[3], &ep8[6]); + + return subset_to_index(ep8, 8, 4); +} + +static uint16_t +epos_from_arrays(int *epos, int *ep) +{ + return FACTORIAL4 * subset_to_index(epos,12,4) + perm_to_index(ep,4); +} + +static void +epos_to_partial_ep(uint16_t epos, int *ep, int *ss) +{ + 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++]]; +} + +static int +factorial(int n) +{ + int i, ret = 1; + + if (n < 0) + return 0; + + for (i = 1; i <= n; i++) + ret *= i; + + return ret; +} + +void +free_alg(Alg *alg) +{ + free(alg->move); + free(alg->inv); + free(alg); +} + +void +free_alglist(AlgList *l) +{ + AlgListNode *aux, *i = l->first; + + while (i != NULL) { + aux = i->next; + free_alglistnode(i); + i = aux; + } + free(l); +} + +void +free_alglistnode(AlgListNode *aln) +{ + free_alg(aln->alg); + free(aln); +} + +static void +free_cubearray(CubeArray *arr, PieceFilter f) +{ + 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); +} + +static void +genptable_dfs(Cube c, PruneData *pd, DfsData *dd) +{ + uint64_t ind = pd->index(c); + int oldval = ptableval(pd, ind); + + if (oldval < dd->m || ptable_has_reached(pd, ind) || pd->n == pd->size) + return; + + ptable_set_reached(pd, ind); + + if (dd->m == dd->d) { + if (dd->m < oldval) + ptable_update(pd, ind, dd->m); + return; + } + + genptable_dfs_branch(c, pd, dd); +} + +static void +genptable_dfs_branch(Cube c, PruneData *pd, DfsData *dd) +{ + Move i, move, l1 = dd->last1, l2 = dd->last2; + + dd->m++; + + for (i = 0; dd->sorted_moves[i] != NULLMOVE; i++) { + move = dd->sorted_moves[i]; + if (allowed_next(move, dd)) { + dd->last2 = dd->last1; + dd->last1 = move; + + genptable_dfs(apply_move(move, c), pd, dd); + + dd->last2 = l2; + dd->last1 = l1; + } + } + + dd->m--; +} + +static void +index_to_perm(int p, int n, int *r) +{ + int *a = malloc(n * sizeof(int)); + int i, j, c; + + for (i = 0; i < n; i++) + a[i] = 0; + + if (p < 0 || p >= factorial(n)) + for (i = 0; i < n; i++) + r[i] = -1; + + for (i = 0; i < n; i++) { + c = 0; + j = 0; + while (c <= p / factorial(n-i-1)) + c += a[j++] ? 0 : 1; + r[i] = j-1; + a[j-1] = 1; + p %= factorial(n-i-1); + } + + free(a); +} + +static void +index_to_subset(int s, int n, int k, int *r) +{ + int i, j, v; + + if (s < 0 || s >= binomial(n, k)) { + for (i = 0; i < n; i++) + r[i] = -1; + return; + } + + for (i = 0; i < n; i++) { + if (k == n-i) { + for (j = i; j < n; j++) + r[j] = 1; + return; + } + + if (k == 0) { + for (j = i; j < n; j++) + r[j] = 0; + return; + } + + v = binomial(n-i-1, k); + if (s >= v) { + r[i] = 1; + k--; + s -= v; + } else { + r[i] = 0; + } + } +} + +static void +int_to_digit_array(int a, int b, int n, int *r) +{ + int i; + + if (b <= 1) + for (i = 0; i < n; i++) + r[i] = 0; + else + for (i = 0; i < n; i++, a /= b) + r[i] = a % b; +} + +static void +int_to_sum_zero_array(int x, int b, int n, int *a) +{ + int i, s = 0; + + if (b <= 1) { + for (i = 0; i < n; i++) + a[i] = 0; + } else { + int_to_digit_array(x, b, n-1, a); + for (i = 0; i < n - 1; i++) + s = (s + a[i]) % b; + a[n-1] = (b - s) % b; + } +} + +static int +invert_digits(int a, int b, int n) +{ + int i, ret, *r = malloc(n * sizeof(int)); + + int_to_digit_array(a, b, n, r); + for (i = 0; i < n; i++) + r[i] = (b-r[i]) % b; + + ret = digit_array_to_int(r, n, b); + free(r); + return ret; +} + +static bool +is_perm(int *a, int n) +{ + int *aux = malloc(n * sizeof(int)); + int i; + + for (i = 0; i < n; i++) + if (a[i] < 0 || a[i] >= n) + return false; + else + aux[a[i]] = 1; + + for (i = 0; i < n; i++) + if (!aux[i]) + return false; + + free(aux); + + return true; +} + +static bool +is_subset(int *a, int n, int k) +{ + int i, sum = 0; + + for (i = 0; i < n; i++) + sum += a[i] ? 1 : 0; + + return sum == k; +} + +static Cube +move_via_arrays(CubeArray *arr, Cube c, PieceFilter f) +{ + CubeArray *arrc = new_cubearray(c, f); + Cube ret; + + 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; +} + +static void +movelist_to_position(Move *movelist, int *position) +{ + Move m; + + for (m = 0; m < NMOVES && movelist[m] != NULLMOVE; m++) + position[movelist[m]] = m; +} + +static void +moveset_to_list(Moveset ms, Checker f, Move *r) +{ + Cube c; + int b[NMOVES]; + int na = 0, nb = 0; + Move i; + + if (ms == NULL) { + fprintf(stderr, "Error: no moveset given\n"); + return; + } + + for (i = U; i < NMOVES; i++) { + if (ms(i)) { + c = apply_move(i, (Cube){0}); + if (f != NULL && f(c, 1)) + r[na++] = i; + else + b[nb++] = i; + } + } + + memcpy(r + na, b, nb * sizeof(Move)); + r[na+nb] = NULLMOVE; +} + +static AlgList * +new_alglist() +{ + AlgList *ret = malloc(sizeof(AlgList)); + + ret->len = 0; + ret->first = NULL; + ret->last = NULL; + + return ret; +} + +static CubeArray * +new_cubearray(Cube cube, PieceFilter f) +{ + 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; +} + +static int +perm_sign(int *a, int n) +{ + int i, j, ret = 0; + + if (!is_perm(a,n)) + return -1; + + for (i = 0; i < n; i++) + for (j = i+1; j < n; j++) + ret += (a[i] > a[j]) ? 1 : 0; + + return ret % 2; +} + +static int +perm_to_index(int *a, int n) +{ + int i, j, c, ret = 0; + + if (!is_perm(a, n)) + return -1; + + for (i = 0; i < n; i++) { + c = 0; + for (j = i+1; j < n; j++) + c += (a[i] > a[j]) ? 1 : 0; + ret += factorial(n-i-1) * c; + } + + return ret; +} + +static int +powint(int a, int b) +{ + if (b < 0) + return 0; + if (b == 0) + return 1; + + if (b % 2) + return a * powint(a, b-1); + else + return powint(a*a, b/2); +} + +static bool +ptable_has_reached(PruneData *pd, uint64_t ind) +{ + return ind % 2 ? pd->reached[ind/2] / 16 : pd->reached[ind/2] % 16; +} + +static void +ptable_set_reached(PruneData *pd, uint64_t ind) +{ + uint8_t oldval2 = pd->reached[ind/2]; + int other = ind % 2 ? oldval2 % 16 : oldval2 / 16; + + pd->reached[ind/2] = ind % 2 ? 16 + other : 16*other + 1; +} + +static void +ptable_update(PruneData *pd, uint64_t ind, int n) +{ + uint8_t oldval2 = pd->ptable[ind/2]; + int other = ind % 2 ? oldval2 % 16 : oldval2 / 16; + + pd->ptable[ind/2] = ind % 2 ? 16*n + other : 16*other + n; + pd->n++; +} + +static void +realloc_alg(Alg *alg, int n) +{ + if (alg == NULL) { + fprintf(stderr, "Error: trying to reallocate NULL alg.\n"); + return; + } + + if (n < alg->len) { + fprintf(stderr, "Error: alg too long for reallocation "); + fprintf(stderr, "(%d vs %d)\n", alg->len, n); + return; + } + + if (n > 1000000) { + fprintf(stderr, "Warning: very long alg,"); + fprintf(stderr, "something might go wrong.\n"); + } + + alg->move = realloc(alg->move, n * sizeof(int)); + alg->inv = realloc(alg->inv, n * sizeof(int)); + alg->allocated = n; +} + +static bool +read_algset_file(AlgSet *as) +{ + return false; +} + +static bool +read_mtables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int m, b = sizeof(uint16_t); + bool r = true; + + 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 +read_ptable_file(PruneData *pd) +{ + FILE *f; + char fname[strlen(tabledir)+100]; + uint64_t r; + + strcpy(fname, tabledir); + strcat(fname, "/"); + strcat(fname, pd->filename); + + if ((f = fopen(fname, "rb")) == NULL) + return false; + + r = fread(pd->ptable, sizeof(uint8_t), ptablesize(pd), f); + fclose(f); + + return r == ptablesize(pd); +} + +static bool +read_ttables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int b = sizeof(uint16_t); + bool r = true; + Move m; + + 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[6], f) == me[6]; + r = r && fread(co_ttable[m], b, me[7], f) == me[7]; + r = r && fread(cpos_ttable[m], b, me[10], f) == me[10]; + r = r && fread(moves_ttable[m], b, me[11], f) == me[11]; + } + + fclose(f); + return r; +} + +static Cube +rotate_via_compose(Trans r, Cube c, PieceFilter f) +{ + Alg *inv; + 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 + }; + + Cube ret; + + if (r != mirror) { + ret = apply_alg_generic(trans_algs[r], c, f, true); + inv = on_inverse(trans_algs[r]); + ret = apply_alg_generic(inv, ret, f, true); + free_alg(inv); + } else { + ret = move_via_arrays(&ma, (Cube){0}, f); + ret = compose_filtered(c, ret, f); + ret = move_via_arrays(&ma, ret, f); + } + + return ret; +} + +static int +subset_to_index(int *a, int n, int k) +{ + int i, ret = 0; + + if (!is_subset(a, n, k)) + return binomial(n, k); + + for (i = 0; i < n; i++) { + if (k == n-i) + return ret; + if (a[i]) { + ret += binomial(n-i-1, k); + k--; + } + } + + return ret; +} + +static void +sum_arrays_mod(int *src, int *dst, int n, int m) +{ + int i; + + for (i = 0; i < n; i++) + dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m; +} + +static void +swap(int *a, int *b) +{ + int aux; + + aux = *a; + *a = *b; + *b = aux; +} + +static bool +write_algset_file(AlgSet *as) +{ + return false; +} + +static bool +write_mtables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int m, b = sizeof(uint16_t); + bool r = true; + + 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; +} + +static bool +write_ptable_file(PruneData *pd) +{ + FILE *f; + char fname[strlen(tabledir)+100]; + uint64_t written; + + strcpy(fname, tabledir); + strcat(fname, "/"); + strcat(fname, pd->filename); + + if ((f = fopen(fname, "wb")) == NULL) + return false; + + written = fwrite(pd->ptable, sizeof(uint8_t), ptablesize(pd), f); + fclose(f); + + return written == ptablesize(pd); +} + +static bool +write_ttables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + bool r = true; + int b = sizeof(uint16_t); + Move m; + + 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[6], f) == me[6]; + r = r && fwrite(co_ttable[m], b, me[7], f) == me[7]; + r = r && fwrite(cpos_ttable[m], b, me[10], f) == me[10]; + r = r && fwrite(moves_ttable[m], b, me[11], f) == me[11]; + } + + fclose(f); + return r; +} + +/* Init functions implementation *********************************************/ + +static void +init_auxtables() +{ + Cube c1, c2; + CubeArray *arr; + uint64_t ui, uj; + int i, j, k, auxarr[12]; + bool cij, p1, p2; + + for (ui = 0; ui < FACTORIAL6; ui++) { + arr = new_cubearray((Cube){.cpos = ui}, pf_cpos); + for (i = 0; i < 6; i++) { + what_center_at_aux[ui][i] = arr->cpos[i]; + where_is_center_aux[ui][arr->cpos[i]] = i; + } + free_cubearray(arr, pf_cpos); + } + + for (ui = 0; ui < FACTORIAL8; ui++) { + arr = new_cubearray((Cube){.cp = ui}, pf_cp); + for (i = 0; i < 8; i++) { + what_corner_at_aux[ui][i] = arr->cp[i]; + where_is_corner_aux[ui][arr->cp[i]] = i; + } + free_cubearray(arr, pf_cp); + } + + for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) { + arr = new_cubearray((Cube){.epose = ui}, pf_e); + for (i = 0; i < 12; i++) + if (edge_slice(arr->ep[i]) == 0) + where_is_edge_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) + where_is_edge_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) + where_is_edge_aux[2][ui][arr->ep[i]] = i; + free_cubearray(arr, pf_m); + } + + for (ui = 0; ui < POW3TO7; ui++) { + int_to_sum_zero_array(ui, 3, 8, auxarr); + what_orientation_last_corner_aux[ui] = auxarr[7]; + } + + for (ui = 0; ui < POW2TO11; ui++) { + int_to_sum_zero_array(ui, 2, 12, auxarr); + what_orientation_last_edge_aux[ui] = auxarr[11]; + } + + for (ui = 0; ui < BINOM12ON4; ui++) + for (uj = 0; uj < BINOM12ON4; uj++) + epos_dependent_aux[ui][uj] = epos_dependent(ui, uj); + + for (i = 0; i < NMOVES; i++) { + for (j = 0; j < NMOVES; j++) { + c1 = apply_move(i, apply_move(j, (Cube){0})); + c2 = apply_move(j, apply_move(i, (Cube){0})); + commute[i][j] = equal(c1, c2) && i && j; + } + } + + for (i = 0; i < NMOVES; i++) { + for (j = 0; j < NMOVES; j++) { + for (k = 0; k < NMOVES; k++) { + p1 = j && base_move(j) == base_move(k); + p2 = i && base_move(i) == base_move(k); + cij = commute[i][j]; + possible_next[i][j][k] = !(p1 || (cij && p2)); + } + } + } + + for (i = 0; i < NMOVES; i++) + inverse_move_aux[i] = i ? i + 2 - 2*((i-1)%3) : NULLMOVE; + + /* Is there a more elegant way? */ + inverse_trans_aux[uf] = uf; + inverse_trans_aux[ur] = ul; + inverse_trans_aux[ul] = ur; + inverse_trans_aux[ub] = ub; + + inverse_trans_aux[df] = df; + inverse_trans_aux[dr] = dr; + inverse_trans_aux[dl] = dl; + inverse_trans_aux[db] = db; + + inverse_trans_aux[rf] = lf; + inverse_trans_aux[rd] = bl; + inverse_trans_aux[rb] = rb; + inverse_trans_aux[ru] = fr; + + inverse_trans_aux[lf] = rf; + inverse_trans_aux[ld] = br; + inverse_trans_aux[lb] = lb; + inverse_trans_aux[lu] = fl; + + inverse_trans_aux[fu] = fu; + inverse_trans_aux[fr] = ru; + inverse_trans_aux[fd] = bu; + inverse_trans_aux[fl] = lu; + + inverse_trans_aux[bu] = fd; + inverse_trans_aux[br] = ld; + inverse_trans_aux[bd] = bd; + inverse_trans_aux[bl] = rd; + + inverse_trans_aux[mirror] = mirror; +} + +static void +init_environment() +{ + char *nissydata = getenv("NISSYDATA"); + char *localdata = getenv("XDG_DATA_HOME"); + char *home = getenv("HOME"); + bool read, write; + + if (nissydata != NULL) { + tabledir = malloc(strlen(nissydata) * sizeof(char) + 20); + strcpy(tabledir, nissydata); + } else if (localdata != NULL) { + tabledir = malloc(strlen(localdata) * sizeof(char) + 20); + strcpy(tabledir, localdata); + strcat(tabledir, "/nissy"); + } else if (home != NULL) { + tabledir = malloc(strlen(home) * sizeof(char) + 20); + strcpy(tabledir, home); + strcat(tabledir, "/.nissy"); + } + + mkdir(tabledir, 0777); + strcat(tabledir, "/tables"); + mkdir(tabledir, 0777); + + read = !access(tabledir, R_OK); + write = !access(tabledir, W_OK); + + if (!read) { + fprintf(stderr, "Table files cannot be read.\n"); + } else if (!write) { + fprintf(stderr, "Data directory not writable: "); + fprintf(stderr, "tables can be loaded, but not saved.\n"); + } +} + +static void +init_moves() { + Cube c; + CubeArray arrs; + int i; + uint16_t ui; + Move m; + + /* 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; + + fprintf(stderr, "Cannot load %s, generating it\n", "mtables"); + + /* Initialize transition tables */ + for (m = 0; m < NMOVES; m++) { + 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; + } + } + + if (!write_mtables_file()) + fprintf(stderr, "Error writing mtables\n"); +} + +static void +init_moves_aux() +{ + /* Some standard PieceFilters */ + pf_all.epose = true; + pf_all.eposs = true; + pf_all.eposm = true; + pf_all.eofb = true; + pf_all.eorl = true; + pf_all.eoud = true; + pf_all.cp = true; + pf_all.cofb = true; + pf_all.corl = true; + pf_all.coud = true; + pf_all.cpos = true; + + pf_4val.epose = true; + pf_4val.eposs = true; + pf_4val.eposm = true; + pf_4val.eofb = true; + pf_4val.coud = true; + pf_4val.cp = true; + + pf_epcp.epose = true; + pf_epcp.eposs = true; + pf_epcp.eposm = true; + pf_epcp.cp = true; + + pf_cpos.cpos = true; + + pf_cp.cp = true; + + pf_ep.epose = true; + pf_ep.eposs = true; + pf_ep.eposm = true; + + pf_e.epose = true; + pf_s.eposs = true; + pf_m.eposm = true; + + pf_eo.eofb = true; + pf_eo.eorl = true; + pf_eo.eoud = true; + + pf_co.cofb = true; + pf_co.corl = true; + pf_co.coud = true; + + /* Used to convert to and from CubeArray */ + epe_solved[0] = FR; + epe_solved[1] = FL; + epe_solved[2] = BL; + epe_solved[3] = BR; + + eps_solved[0] = UL; + eps_solved[1] = UR; + eps_solved[2] = DL; + eps_solved[3] = DR; + + epm_solved[0] = UF; + epm_solved[1] = UB; + epm_solved[2] = DF; + epm_solved[3] = DB; + + /* Table sizes, used for reading and writing files */ + me[0] = FACTORIAL12/FACTORIAL8; + me[1] = FACTORIAL12/FACTORIAL8; + me[2] = FACTORIAL12/FACTORIAL8; + me[3] = POW2TO11; + me[4] = POW2TO11; + me[5] = POW2TO11; + me[6] = FACTORIAL8; + me[7] = POW3TO7; + me[8] = POW3TO7; + me[9] = POW3TO7; + me[10] = FACTORIAL6; + me[11] = NMOVES; + + /* Cycles *********************/ + edge_cycle[U][UF] = UR; + edge_cycle[U][UL] = UF; + edge_cycle[U][UB] = UL; + edge_cycle[U][UR] = UB; + edge_cycle[U][DF] = DF; + edge_cycle[U][DL] = DL; + edge_cycle[U][DB] = DB; + edge_cycle[U][DR] = DR; + edge_cycle[U][FR] = FR; + edge_cycle[U][FL] = FL; + edge_cycle[U][BL] = BL; + edge_cycle[U][BR] = BR; + + edge_cycle[x][UF] = DF; + edge_cycle[x][UL] = FL; + edge_cycle[x][UB] = UF; + edge_cycle[x][UR] = FR; + edge_cycle[x][DF] = DB; + edge_cycle[x][DL] = BL; + edge_cycle[x][DB] = UB; + edge_cycle[x][DR] = BR; + edge_cycle[x][FR] = DR; + edge_cycle[x][FL] = DL; + edge_cycle[x][BL] = UL; + edge_cycle[x][BR] = UR; + + edge_cycle[y][UF] = UR; + edge_cycle[y][UL] = UF; + edge_cycle[y][UB] = UL; + edge_cycle[y][UR] = UB; + edge_cycle[y][DF] = DR; + edge_cycle[y][DL] = DF; + edge_cycle[y][DB] = DL; + edge_cycle[y][DR] = DB; + edge_cycle[y][FR] = BR; + edge_cycle[y][FL] = FR; + edge_cycle[y][BL] = FL; + edge_cycle[y][BR] = BL; + + corner_cycle[U][UFR] = UBR; + corner_cycle[U][UFL] = UFR; + corner_cycle[U][UBL] = UFL; + corner_cycle[U][UBR] = UBL; + corner_cycle[U][DFR] = DFR; + corner_cycle[U][DFL] = DFL; + corner_cycle[U][DBL] = DBL; + corner_cycle[U][DBR] = DBR; + + corner_cycle[x][UFR] = DFR; + corner_cycle[x][UFL] = DFL; + corner_cycle[x][UBL] = UFL; + corner_cycle[x][UBR] = UFR; + corner_cycle[x][DFR] = DBR; + corner_cycle[x][DFL] = DBL; + corner_cycle[x][DBL] = UBL; + corner_cycle[x][DBR] = UBR; + + corner_cycle[y][UFR] = UBR; + corner_cycle[y][UFL] = UFR; + corner_cycle[y][UBL] = UFL; + corner_cycle[y][UBR] = UBL; + corner_cycle[y][DFR] = DBR; + corner_cycle[y][DFL] = DFR; + corner_cycle[y][DBL] = DFL; + corner_cycle[y][DBR] = DBL; + + center_cycle[U][U_center] = U_center; + center_cycle[U][D_center] = D_center; + center_cycle[U][R_center] = R_center; + center_cycle[U][L_center] = L_center; + center_cycle[U][F_center] = F_center; + center_cycle[U][B_center] = B_center; + + center_cycle[x][U_center] = F_center; + center_cycle[x][D_center] = B_center; + center_cycle[x][R_center] = R_center; + center_cycle[x][L_center] = L_center; + center_cycle[x][F_center] = D_center; + center_cycle[x][B_center] = U_center; + + center_cycle[y][U_center] = U_center; + center_cycle[y][D_center] = D_center; + center_cycle[y][R_center] = B_center; + center_cycle[y][L_center] = F_center; + center_cycle[y][F_center] = R_center; + center_cycle[y][B_center] = L_center; + + /* Flipped pieces *************/ + eofb_flipped[x][UF] = 1; + eofb_flipped[x][UB] = 1; + eofb_flipped[x][DF] = 1; + eofb_flipped[x][DB] = 1; + + eofb_flipped[y][FR] = 1; + eofb_flipped[y][FL] = 1; + eofb_flipped[y][BL] = 1; + eofb_flipped[y][BR] = 1; + + eorl_flipped[x][UF] = 1; + eorl_flipped[x][UL] = 1; + eorl_flipped[x][UB] = 1; + eorl_flipped[x][UR] = 1; + eorl_flipped[x][DF] = 1; + eorl_flipped[x][DL] = 1; + eorl_flipped[x][DB] = 1; + eorl_flipped[x][DR] = 1; + eorl_flipped[x][FR] = 1; + eorl_flipped[x][FL] = 1; + eorl_flipped[x][BL] = 1; + eorl_flipped[x][BR] = 1; + + eorl_flipped[y][FR] = 1; + eorl_flipped[y][FL] = 1; + eorl_flipped[y][BL] = 1; + eorl_flipped[y][BR] = 1; + + eoud_flipped[U][UF] = 1; + eoud_flipped[U][UL] = 1; + eoud_flipped[U][UB] = 1; + eoud_flipped[U][UR] = 1; + + eoud_flipped[x][UF] = 1; + eoud_flipped[x][UB] = 1; + eoud_flipped[x][DF] = 1; + eoud_flipped[x][DB] = 1; + + eoud_flipped[y][UF] = 1; + eoud_flipped[y][UL] = 1; + eoud_flipped[y][UB] = 1; + eoud_flipped[y][UR] = 1; + eoud_flipped[y][DF] = 1; + eoud_flipped[y][DL] = 1; + eoud_flipped[y][DB] = 1; + eoud_flipped[y][DR] = 1; + eoud_flipped[y][FR] = 1; + eoud_flipped[y][FL] = 1; + eoud_flipped[y][BL] = 1; + eoud_flipped[y][BR] = 1; + + coud_flipped[x][UFR] = 2; + coud_flipped[x][UFL] = 1; + coud_flipped[x][UBR] = 1; + coud_flipped[x][UBL] = 2; + coud_flipped[x][DFR] = 1; + coud_flipped[x][DFL] = 2; + coud_flipped[x][DBR] = 2; + coud_flipped[x][DBL] = 1; + + corl_flipped[U][UFR] = 1; + corl_flipped[U][UFL] = 2; + corl_flipped[U][UBL] = 1; + corl_flipped[U][UBR] = 2; + + corl_flipped[y][UFR] = 1; + corl_flipped[y][UFL] = 2; + corl_flipped[y][UBL] = 1; + corl_flipped[y][UBR] = 2; + corl_flipped[y][DFR] = 2; + corl_flipped[y][DFL] = 1; + corl_flipped[y][DBL] = 2; + corl_flipped[y][DBR] = 1; + + cofb_flipped[U][UFR] = 2; + cofb_flipped[U][UFL] = 1; + cofb_flipped[U][UBL] = 2; + cofb_flipped[U][UBR] = 1; + + cofb_flipped[x][UFR] = 1; + cofb_flipped[x][UFL] = 2; + cofb_flipped[x][UBL] = 1; + cofb_flipped[x][UBR] = 2; + cofb_flipped[x][DFR] = 2; + cofb_flipped[x][DFL] = 1; + cofb_flipped[x][DBL] = 2; + cofb_flipped[x][DBR] = 1; + + cofb_flipped[y][UFR] = 2; + cofb_flipped[y][UFL] = 1; + cofb_flipped[y][UBL] = 2; + cofb_flipped[y][UBR] = 1; + cofb_flipped[y][DFR] = 1; + cofb_flipped[y][DFL] = 2; + cofb_flipped[y][DBL] = 1; + cofb_flipped[y][DBR] = 2; + + /* Equivalent moves ***********/ + equiv_alg[NULLMOVE] = new_alg(""); + + equiv_alg[U] = new_alg(" U "); + equiv_alg[U2] = new_alg(" UU "); + equiv_alg[U3] = new_alg(" UUU "); + equiv_alg[D] = new_alg(" xx U xx "); + equiv_alg[D2] = new_alg(" xx UU xx "); + equiv_alg[D3] = new_alg(" xx UUU xx "); + equiv_alg[R] = new_alg(" yx U xxxyyy "); + equiv_alg[R2] = new_alg(" yx UU xxxyyy "); + equiv_alg[R3] = new_alg(" yx UUU xxxyyy "); + equiv_alg[L] = new_alg(" yyyx U xxxy "); + equiv_alg[L2] = new_alg(" yyyx UU xxxy "); + equiv_alg[L3] = new_alg(" yyyx UUU xxxy "); + equiv_alg[F] = new_alg(" x U xxx "); + equiv_alg[F2] = new_alg(" x UU xxx "); + equiv_alg[F3] = new_alg(" x UUU xxx "); + equiv_alg[B] = new_alg(" xxx U x "); + equiv_alg[B2] = new_alg(" xxx UU x "); + equiv_alg[B3] = new_alg(" xxx UUU x "); + + equiv_alg[Uw] = new_alg(" xx U xx y "); + equiv_alg[Uw2] = new_alg(" xx UU xx yy "); + equiv_alg[Uw3] = new_alg(" xx UUU xx yyy "); + equiv_alg[Dw] = new_alg(" U yyy "); + equiv_alg[Dw2] = new_alg(" UU yy "); + equiv_alg[Dw3] = new_alg(" UUU y "); + equiv_alg[Rw] = new_alg(" yyyx U xxxy x "); + equiv_alg[Rw2] = new_alg(" yyyx UU xxxy xx "); + equiv_alg[Rw3] = new_alg(" yyyx UUU xxxy xxx "); + equiv_alg[Lw] = new_alg(" yx U xxxyyy xxx "); + equiv_alg[Lw2] = new_alg(" yx UU xxxyyy xx "); + equiv_alg[Lw3] = new_alg(" yx UUU xxxyyy x "); + equiv_alg[Fw] = new_alg(" xxx U x yxxxyyy "); + equiv_alg[Fw2] = new_alg(" xxx UU x yxxyyy "); + equiv_alg[Fw3] = new_alg(" xxx UUU x yxyyy "); + equiv_alg[Bw] = new_alg(" x U xxx yxyyy "); + equiv_alg[Bw2] = new_alg(" x UU xxx yxxyyy "); + equiv_alg[Bw3] = new_alg(" x UUU xxx yxxxyyy "); + + equiv_alg[M] = new_alg(" yx U xx UUU yxyyy "); + equiv_alg[M2] = new_alg(" yx UU xx UU xxxy "); + equiv_alg[M3] = new_alg(" yx UUU xx U yxxxy "); + equiv_alg[S] = new_alg(" x UUU xx U yyyx "); + equiv_alg[S2] = new_alg(" x UU xx UU yyx "); + equiv_alg[S3] = new_alg(" x U xx UUU yx "); + equiv_alg[E] = new_alg(" U xx UUU xxyyy "); + equiv_alg[E2] = new_alg(" UU xx UU xxyy "); + equiv_alg[E3] = new_alg(" UUU xx U xxy "); + + equiv_alg[x] = new_alg(" x "); + equiv_alg[x2] = new_alg(" xx "); + equiv_alg[x3] = new_alg(" xxx "); + equiv_alg[y] = new_alg(" y "); + equiv_alg[y2] = new_alg(" yy "); + equiv_alg[y3] = new_alg(" yyy "); + equiv_alg[z] = new_alg(" yyy x y "); + equiv_alg[z2] = new_alg(" yy xx "); + equiv_alg[z3] = new_alg(" y x yyy "); +} + +static void +init_strings() +{ + strcpy(move_string [NULLMOVE], "-" ); + strcpy(move_string [U], "U" ); + strcpy(move_string [U2], "U2" ); + strcpy(move_string [U3], "U\'" ); + strcpy(move_string [D], "D" ); + strcpy(move_string [D2], "D2" ); + strcpy(move_string [D3], "D\'" ); + strcpy(move_string [R], "R" ); + strcpy(move_string [R2], "R2" ); + strcpy(move_string [R3], "R\'" ); + strcpy(move_string [L], "L" ); + strcpy(move_string [L2], "L2" ); + strcpy(move_string [L3], "L\'" ); + strcpy(move_string [F], "F" ); + strcpy(move_string [F2], "F2" ); + strcpy(move_string [F3], "F\'" ); + strcpy(move_string [B], "B" ); + strcpy(move_string [B2], "B2" ); + strcpy(move_string [B3], "B\'" ); + strcpy(move_string [Uw], "Uw" ); + strcpy(move_string [Uw2], "Uw2" ); + strcpy(move_string [Uw3], "Uw\'" ); + strcpy(move_string [Dw], "Dw" ); + strcpy(move_string [Dw2], "Dw2" ); + strcpy(move_string [Dw3], "Dw\'" ); + strcpy(move_string [Rw], "Rw" ); + strcpy(move_string [Rw2], "Rw2" ); + strcpy(move_string [Rw3], "Rw\'" ); + strcpy(move_string [Lw], "Lw" ); + strcpy(move_string [Lw2], "Lw2" ); + strcpy(move_string [Lw3], "Lw\'" ); + strcpy(move_string [Fw], "Fw" ); + strcpy(move_string [Fw2], "Fw2" ); + strcpy(move_string [Fw3], "Fw\'" ); + strcpy(move_string [Bw], "Bw" ); + strcpy(move_string [Bw2], "Bw2" ); + strcpy(move_string [Bw3], "Bw\'" ); + strcpy(move_string [M], "M" ); + strcpy(move_string [M2], "M2" ); + strcpy(move_string [M3], "M\'" ); + strcpy(move_string [S], "S" ); + strcpy(move_string [S2], "S2" ); + strcpy(move_string [S3], "S\'" ); + strcpy(move_string [E], "E" ); + strcpy(move_string [E2], "E2" ); + strcpy(move_string [E3], "E\'" ); + strcpy(move_string [x], "x" ); + strcpy(move_string [x2], "x2" ); + strcpy(move_string [x3], "x\'" ); + strcpy(move_string [y], "y" ); + strcpy(move_string [y2], "y2" ); + strcpy(move_string [y3], "y\'" ); + strcpy(move_string [z], "z" ); + strcpy(move_string [z2], "z2" ); + strcpy(move_string [z3], "z\'" ); + + strcpy(edge_string [UF], "UF" ); + strcpy(edge_string [UL], "UL" ); + strcpy(edge_string [UB], "UB" ); + strcpy(edge_string [UR], "UR" ); + strcpy(edge_string [DF], "DF" ); + strcpy(edge_string [DL], "DL" ); + strcpy(edge_string [DB], "DB" ); + strcpy(edge_string [DR], "DR" ); + strcpy(edge_string [FR], "FR" ); + strcpy(edge_string [FL], "FL" ); + strcpy(edge_string [BL], "BL" ); + strcpy(edge_string [BR], "BR" ); + + strcpy(corner_string [UFR], "UFR" ); + strcpy(corner_string [UFL], "UFL" ); + strcpy(corner_string [UBL], "UBL" ); + strcpy(corner_string [UBR], "UBR" ); + strcpy(corner_string [DFR], "DFR" ); + strcpy(corner_string [DFL], "DFL" ); + strcpy(corner_string [DBL], "DBL" ); + strcpy(corner_string [DBR], "DBR" ); + + strcpy(center_string [U_center], "U" ); + strcpy(center_string [D_center], "D" ); + strcpy(center_string [R_center], "R" ); + strcpy(center_string [L_center], "L" ); + strcpy(center_string [F_center], "F" ); + strcpy(center_string [B_center], "B" ); +} + +static void +init_trans() { + Cube aux, cube, c[3]; + CubeArray epcp; + int eparr[12], eoarr[12]; + int cparr[8], coarr[8]; + int i; + bool b1, b2, b3; + uint16_t ui; + Move mi, move; + Trans m; + + /* Compute sources */ + for (i = 0; i < NTRANS; i++) { + if (i == mirror) + cube = (Cube){0}; + else + cube = apply_alg(trans_algs[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; + } + + if (read_ttables_file()) + return; + + fprintf(stderr, "Cannot load %s, generating it\n", "ttables"); + + /* Initialize tables */ + for (m = 0; m < NTRANS; m++) { + if (m == mirror) { + memcpy(eparr, ep_mirror, 12 * sizeof(int)); + memcpy(cparr, cp_mirror, 8 * sizeof(int)); + } else { + epcp = (CubeArray){ .ep = eparr, .cp = cparr }; + cube = apply_alg(trans_algs[m], (Cube){0}); + cube_to_arrays(cube, &epcp, pf_epcp); + } + + 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 == mirror) + 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++) { + if (m == mirror) { + b1 = (mi >= U && mi <= Bw3); + b2 = (mi >= S && mi <= E3); + b3 = (mi >= x && mi <= z3); + if (b1 || b2 || b3) + moves_ttable[m][mi] = + inverse_move_aux[mi]; + else + moves_ttable[m][mi] = mi; + + if ((mi-1)/3==(R-1)/3 || (mi-1)/3==(Rw-1)/3) + moves_ttable[m][mi] += 3; + if ((mi-1)/3==(L-1)/3 || (mi-1)/3==(L2-1)/3) + moves_ttable[m][mi] -= 3; + } else { + aux = apply_trans(m, apply_move(mi,(Cube){0})); + for (move = 0; move < NMOVES; move++) { + cube = apply_move( + inverse_move_aux[move], aux); + if (is_solved(cube, false)) + moves_ttable[m][mi] = move; + } + } + } + } + + if (!write_ttables_file()) + fprintf(stderr, "Error writing ttables\n"); +} + +static void +init_trans_aux() +{ + ep_mirror[UF] = UF; + ep_mirror[UL] = UR; + ep_mirror[UB] = UB; + ep_mirror[UR] = UL; + ep_mirror[DF] = DF; + ep_mirror[DL] = DR; + ep_mirror[DB] = DB; + ep_mirror[DR] = DL; + ep_mirror[FR] = FL; + ep_mirror[FL] = FR; + ep_mirror[BR] = BL; + ep_mirror[BL] = BR; + + cp_mirror[UFR] = UFL; + cp_mirror[UFL] = UFR; + cp_mirror[UBL] = UBR; + cp_mirror[UBR] = UBL; + cp_mirror[DFR] = DFL; + cp_mirror[DFL] = DFR; + cp_mirror[DBL] = DBR; + cp_mirror[DBR] = DBL; + + cpos_mirror[U_center] = U_center; + cpos_mirror[D_center] = D_center; + cpos_mirror[R_center] = L_center; + cpos_mirror[L_center] = R_center; + cpos_mirror[F_center] = F_center; + cpos_mirror[B_center] = B_center; + + /* Is there a more elegant way? */ + trans_algs[uf] = new_alg(""); + trans_algs[ur] = new_alg("y"); + trans_algs[ub] = new_alg("y2"); + trans_algs[ul] = new_alg("y3"); + + trans_algs[df] = new_alg("z2"); + trans_algs[dr] = new_alg("y z2"); + trans_algs[db] = new_alg("x2"); + trans_algs[dl] = new_alg("y3 z2"); + + trans_algs[rf] = new_alg("z3"); + trans_algs[rd] = new_alg("z3 y"); + trans_algs[rb] = new_alg("z3 y2"); + trans_algs[ru] = new_alg("z3 y3"); + + trans_algs[lf] = new_alg("z"); + trans_algs[ld] = new_alg("z y3"); + trans_algs[lb] = new_alg("z y2"); + trans_algs[lu] = new_alg("z y"); + + trans_algs[fu] = new_alg("x y2"); + trans_algs[fr] = new_alg("x y"); + trans_algs[fd] = new_alg("x"); + trans_algs[fl] = new_alg("x y3"); + + trans_algs[bu] = new_alg("x3"); + trans_algs[br] = new_alg("x3 y"); + trans_algs[bd] = new_alg("x3 y2"); + trans_algs[bl] = new_alg("x3 y3"); +} + + +/* Public functions implementation *******************************************/ + +Cube +apply_alg(Alg *alg, Cube cube) +{ + return apply_alg_generic(alg, cube, pf_all, true); +} + +Cube +apply_move(Move m, Cube cube) +{ + 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] + }; +} + +Cube +apply_trans(Trans t, Cube cube) +{ + uint16_t aux_epos[3] = { cube.epose, cube.eposs, cube.eposm }; + uint16_t aux_eo[3] = { cube.eoud, cube.eorl, cube.eofb }; + uint16_t 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] + }; +} + +Move +base_move(Move m) +{ + if (m == NULLMOVE) + return NULLMOVE; + else + return m - (m-1)%3; +} + +Cube +compose(Cube c2, Cube c1) +{ + return compose_filtered(c2, c1, pf_all); +} + +uint64_t +epos_dependent_cube(Cube c) +{ + return epos_dependent_aux[c.eposs/FACTORIAL4][c.epose/FACTORIAL4]; +} + +bool +equal(Cube c1, Cube c2) +{ + 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; +} + +void +genalgset(AlgSet *as) +{ + uint64_t i; + + if (as->generated) + return; + + /* TODO: check if memory is enough, otherwise maybe crash gracefully? */ + as->table = malloc(as->size * sizeof(AlgList *)); + + if (read_algset_file(as)) { + as->generated = true; + return; + } + + fprintf(stderr, "Cannot load %s, generating it\n", as->filename); + + for (i = 0; i < as->size; i++) { + as->table[i] = solve(as->antindex(i), as->step, &as->opts); + fprintf(stderr, "Generated %lu / %lu cases\n", i, as->size); + } + + if (!write_algset_file(as)) + fprintf(stderr, "Error writing algset file\n"); + + as->generated = true; +} + +void +genptable(PruneData *pd) +{ + uint64_t j; + DfsData dd = { + .m = 0, + .last1 = NULLMOVE, + .last2 = NULLMOVE + }; + + if (pd->generated) + return; + + /* TODO: check if memory is enough, otherwise maybe crash gracefully? */ + pd->ptable = malloc(ptablesize(pd) * sizeof(uint8_t)); + + if (read_ptable_file(pd)) { + pd->generated = true; + return; + } + + fprintf(stderr, "Cannot load %s, generating it\n", pd->filename); + + /* We use 4 bits per value, so any distance >= 15 is set to 15 */ + for (j = 0; j < pd->size; j++) + ptable_update(pd, j, 15); + + moveset_to_list(pd->moveset, NULL, dd.sorted_moves); + movelist_to_position(dd.sorted_moves, dd.move_position); + + pd->reached = malloc(ptablesize(pd) * sizeof(uint8_t)); + for (dd.d = 0, pd->n = 0; dd.d < 15 && pd->n < pd->size; dd.d++) { + memset(pd->reached, 0, ptablesize(pd)*sizeof(uint8_t)); + genptable_dfs((Cube){0}, pd, &dd); + fprintf(stderr, "Depth %d completed, generated %lu/%lu\n", + dd.d, pd->n, pd->size); + } + + if (!write_ptable_file(pd)) + fprintf(stderr, "Error writing ptable file\n"); + + pd->generated = true; + free(pd->reached); +} + +Cube +inverse_cube(Cube cube) +{ + CubeArray *arr = new_cubearray(cube, pf_all); + CubeArray *inv = new_cubearray((Cube){0}, pf_all); + Cube ret; + int i; + + for (i = 0; i < 12; i++) { + inv->ep[arr->ep[i]] = i; + inv->eofb[arr->ep[i]] = arr->eofb[i]; + inv->eorl[arr->ep[i]] = arr->eorl[i]; + inv->eoud[arr->ep[i]] = arr->eoud[i]; + } + + for (i = 0; i < 8; i++) { + inv->cp[arr->cp[i]] = i; + inv->coud[arr->cp[i]] = (3 - arr->coud[i]) % 3; + inv->corl[arr->cp[i]] = (3 - arr->corl[i]) % 3; + inv->cofb[arr->cp[i]] = (3 - arr->cofb[i]) % 3; + } + + for (int i = 0; i < 6; i++) + inv->cpos[arr->cpos[i]] = i; + + ret = arrays_to_cube(inv, pf_all); + free_cubearray(arr, pf_all); + free_cubearray(inv, pf_all); + + return ret; +} + +Move +inverse_move(Move m) +{ + return inverse_move_aux[m]; +} + +Trans +inverse_trans(Trans t) +{ + return inverse_trans_aux[t]; +} + +bool +is_admissible(Cube cube) +{ + /* TODO: this should check consistency of different orientations */ + /* TODO: check that centers are opposite and admissible */ + + CubeArray *a = new_cubearray(cube, pf_all); + int parity; + bool perm; + + 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); + + return perm && parity % 2 == 0; +} + +bool +is_solved(Cube cube, bool reorient) +{ + Trans i; + + if (reorient) + for (i = 0; i < NROTATIONS; i++) + if (is_solved(apply_alg(trans_algs[i],cube), false)) + return true; + + return equal(cube, (Cube){0}); +} + +bool +is_solved_block(Cube cube, Block block) +{ + 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; + + return true; +} + +bool +is_solved_center(Cube cube, Center c) +{ + return what_center_at(cube, c) == c; +} + +bool +is_solved_corner(Cube cube, Corner c) +{ + return what_corner_at(cube, c) == c && + what_orientation_corner(cube.coud, c); +} + +bool +is_solved_edge(Cube cube, Edge e) +{ + return what_edge_at(cube, e) == e && + what_orientation_edge(cube.eofb, e); +} + +int +piece_orientation(Cube cube, int piece, char *orientation) +{ + int arr[12], n, b; + uint16_t 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) +{ +/* + CubeArray *arr = new_cubearray(cube, pf_all); + + for (int i = 0; i < 12; i++) + printf(" %s ", edge_string[arr->ep[i]]); + printf("\n"); + + for (int i = 0; i < 12; i++) + printf(" %c ", arr->eofb[i] + '0'); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf("%s ", corner_string[arr->cp[i]]); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf(" %c ", arr->coud[i] + '0'); + printf("\n"); + + for (int i = 0; i < 6; i++) + printf(" %s ", center_string[arr->cpos[i]]); + printf("\n"); + + free_cubearray(arr, pf_all); +*/ + + for (int i = 0; i < 12; i++) + printf(" %s ", edge_string[what_edge_at(cube, i)]); + printf("\n"); + + for (int i = 0; i < 12; i++) + printf(" %d ", what_orientation_edge(cube.eofb, i)); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf("%s ", corner_string[what_corner_at(cube, i)]); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf(" %d ", what_orientation_corner(cube.coud, i)); + printf("\n"); + + for (int i = 0; i < 6; i++) + printf(" %s ", center_string[what_center_at(cube, i)]); + printf("\n"); + +} + +Cube +random_cube() +{ + CubeArray *arr = new_cubearray((Cube){0}, pf_4val); + Cube ret; + int ep, cp, eo, co; + + ep = rand() % FACTORIAL12; + cp = rand() % FACTORIAL8; + eo = rand() % POW2TO11; + co = rand() % POW3TO7; + + index_to_perm(ep, 12, arr->ep); + index_to_perm(cp, 8, arr->cp); + int_to_sum_zero_array(eo, 2, 12, arr->eofb); + int_to_sum_zero_array(co, 3, 8, arr->coud); + + if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8)) + swap(&(arr->ep[0]), &(arr->ep[1])); + + ret = arrays_to_cube(arr, pf_4val); + free_cubearray(arr, pf_4val); + + return ret; +} + +AlgList * +solve(Cube cube, Step step, SolveOptions *opts) +{ + AlgListNode *node; + AlgList *sols = new_alglist(); + Cube c = apply_trans(opts->pre_trans, cube); + DfsData dd = { + .m = 0, + .niss = false, + .lb = -1, + .last1 = NULLMOVE, + .last2 = NULLMOVE, + .sols = sols, + .current_alg = new_alg("") + }; + + if (step.ready != NULL && step.ready(c, 1) != 0) { + fprintf(stderr, "Cube not ready for solving step\n"); + return sols; + } + + moveset_to_list(step.moveset, step.check, dd.sorted_moves); + movelist_to_position(dd.sorted_moves, dd.move_position); + + for (dd.d = opts->min_moves; + dd.d <= opts->max_moves && !(sols->len && opts->optimal_only); + dd.d++) { + if (opts->feedback) + fprintf(stderr, + "Found %d solutions, searching depth %d...\n", + sols->len, dd.d); + dfs(c, step, opts, &dd); + } + + for (node = sols->first; node != NULL; node = node->next) + transform_alg(inverse_trans_aux[opts->pre_trans], node->alg); + + free_alg(dd.current_alg); + return sols; +} + +Alg * +inverse_alg(Alg *alg) +{ + Alg *ret = new_alg(""); + int i; + + for (i = alg->len-1; i >= 0; i--) + append_move(ret, alg->move[i], alg->inv[i]); + + return ret; +} + +Alg * +new_alg(char *str) +{ + Alg *alg = malloc(sizeof(Alg)); + int i; + bool niss = false; + Move j, m; + + alg->move = malloc(30 * sizeof(Move)); + alg->inv = malloc(30 * sizeof(bool)); + alg->allocated = 30; + alg->len = 0; + + for (i = 0; str[i]; i++) { + if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n') + continue; + + if (str[i] == '(' && niss) { + fprintf(stderr, "Error reading moves: nested ( )\n"); + return alg; + } + + if (str[i] == ')' && !niss) { + fprintf(stderr, "Error reading moves: unmatched )\n"); + return alg; + } + + if (str[i] == '(' || str[i] == ')') { + niss = !niss; + continue; + } + + for (j = 0; j < NMOVES; j++) { + if (str[i] == move_string[j][0]) { + m = j; + if (m <= B && str[i+1]=='w') { + m += Uw - U; + i++; + } + if (str[i+1]=='2') { + m += 1; + i++; + } else if (str[i+1]=='\'' || str[i+1]=='3') { + m += 2; + i++; + } + append_move(alg, m, niss); + break; + } + } + } + + return alg; +} + +Alg * +on_inverse(Alg *alg) +{ + Alg *ret = new_alg(""); + int i; + + for (i = 0; i < alg->len; i++) + append_move(ret, alg->move[i], !alg->inv[i]); + + return ret; +} + +void +print_alg(Alg *alg, bool l) +{ + /* TODO: make it possible to print to stdout or to string */ + /* Maybe just return a string */ + char fill[4]; + int i; + bool niss = false; + + for (i = 0; i < alg->len; i++) { + if (!niss && alg->inv[i]) + strcpy(fill, i == 0 ? "(" : " ("); + if (niss && !alg->inv[i]) + strcpy(fill, ") "); + if (niss == alg->inv[i]) + strcpy(fill, i == 0 ? "" : " "); + + printf("%s%s", fill, move_string[alg->move[i]]); + niss = alg->inv[i]; + } + + if (niss) + printf(")"); + if (l) + printf(" (%d)", alg->len); + + printf("\n"); +} + +void +print_alglist(AlgList *al, bool l) +{ + AlgListNode *i; + + for (i = al->first; i != NULL; i = i->next) + print_alg(i->alg, l); +} + +void +print_ptable(PruneData *pd) +{ + uint64_t i, a[16]; + + for (i = 0; i < 16; i++) + a[i] = 0; + + if (!pd->generated) + genptable(pd); + + for (i = 0; i < pd->size; i++) + a[ptableval(pd, i)]++; + + fprintf(stderr, "Values for table %s\n", pd->filename); + for (i = 0; i < 16; i++) + printf("%2lu\t%10lu\n", i, a[i]); +} + +uint64_t +ptablesize(PruneData *pd) +{ + return (pd->size + 1) / 2; +} + +int +ptableval(PruneData *pd, uint64_t ind) +{ + return (ind % 2) ? pd->ptable[ind/2] / 16 : pd->ptable[ind/2] % 16; +} + + +Alg * +trans_alg(Trans i) +{ + return trans_algs[i]; +} + +void +transform_alg(Trans t, Alg *alg) +{ + int i; + + for (i = 0; i < alg->len; i++) + alg->move[i] = moves_ttable[t][alg->move[i]]; +} + +Center +what_center_at(Cube cube, Center c) +{ + return what_center_at_aux[cube.cpos][c]; +} + +Corner +what_corner_at(Cube cube, Corner c) +{ + return what_corner_at_aux[cube.cp][c]; +} + +Edge +what_edge_at(Cube cube, Edge e) +{ + Edge ret; + CubeArray *arr = new_cubearray(cube, pf_ep); + + ret = arr->ep[e]; + + free_cubearray(arr, pf_ep); + return ret; +} + +int +what_orientation_corner(int co, Corner c) +{ + if (c < 7) + return (co / powint(3, c)) % 3; + else + return what_orientation_last_corner_aux[co]; +} + +int +what_orientation_edge(int eo, Edge e) +{ + if (e < 11) + return (eo & (1 << e)) ? 1 : 0; + else + return what_orientation_last_edge_aux[eo]; +} + +Center +where_is_center(Cube cube, Center c) +{ + return where_is_center_aux[cube.cpos][c]; +} + +Corner +where_is_corner(Cube cube, Corner c) +{ + return where_is_corner_aux[cube.cp][c]; +} + + +void +init() +{ + /* Order is important! */ + init_environment(); + init_strings(); + init_moves_aux(); + init_moves(); + init_auxtables(); + init_trans_aux(); + init_trans(); +} + diff --git a/old/2021-06-23-uint16t/cube.h b/old/2021-06-23-uint16t/cube.h new file mode 100644 index 0000000..74d14cc --- /dev/null +++ b/old/2021-06-23-uint16t/cube.h @@ -0,0 +1,87 @@ +#ifndef CUBE_H +#define CUBE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Constants and macros *****************************************************/ + +#define POW2TO6 64ULL +#define POW2TO11 2048ULL +#define POW2TO12 4096ULL +#define POW3TO7 2187ULL +#define POW3TO8 6561ULL +#define FACTORIAL4 24ULL +#define FACTORIAL6 720ULL +#define FACTORIAL7 5040ULL +#define FACTORIAL8 40320ULL +#define FACTORIAL12 479001600ULL +#define BINOM12ON4 495ULL +#define BINOM8ON4 70ULL +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +#define NMOVES (z3+1) +#define NTRANS (mirror+1) +#define NROTATIONS (NTRANS-1) + +/* Type definitions **********************************************************/ + +#include "cubetypes.h" + +/* Public functions **********************************************************/ + +Cube apply_alg(Alg *alg, Cube cube); +Cube apply_move(Move m, Cube cube); +Cube apply_trans(Trans t, Cube cube); +bool block_solved(Cube cube, Block); +Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */ +uint64_t epos_dependent_cube(Cube cube); +bool equal(Cube c1, Cube c2); +Cube inverse_cube(Cube cube); +Move inverse_move(Move m); +Trans inverse_trans(Trans t); +bool is_admissible(Cube cube); +bool is_solved(Cube cube, bool reorient); +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 print_cube(Cube cube); +Cube random_cube(); +AlgList * solve(Cube cube, Step step, SolveOptions *opts); +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); + +Move base_move(Move m); +void free_alg(Alg *alg); +void free_alglist(AlgList *l); +Alg * inverse_alg(Alg *alg); +Alg * new_alg(char *str); +Alg * on_inverse(Alg *alg); +void print_alg(Alg *alg, bool l); +void print_alglist(AlgList *al, bool l); +Alg * trans_alg(Trans i); +void transform_alg(Trans t, Alg *alg); + +void genalgset(AlgSet *as); +void genptable(PruneData *pd); +void print_ptable(PruneData *pd); +uint64_t ptablesize(PruneData *pd); +int ptableval(PruneData *pd, uint64_t ind); + +void init(); + +#endif + diff --git a/old/2021-06-23-uint16t/cubetypes.h b/old/2021-06-23-uint16t/cubetypes.h new file mode 100644 index 0000000..10bfabb --- /dev/null +++ b/old/2021-06-23-uint16t/cubetypes.h @@ -0,0 +1,224 @@ +/* Typedefs ******************************************************************/ + +typedef enum center Center; +typedef enum corner Corner; +typedef enum edge Edge; +typedef enum move Move; +typedef enum trans Trans; + +typedef struct alg Alg; +typedef struct alglist AlgList; +typedef struct alglistnode AlgListNode; +typedef struct algset AlgSet; +typedef struct block Block; +typedef struct cube Cube; +typedef struct cubearray CubeArray; +typedef struct dfsdata DfsData; +typedef struct piecefilter PieceFilter; +typedef struct prunedata PruneData; +typedef struct solveoptions SolveOptions; +typedef struct step Step; + +typedef Cube (*AntiIndexer) (uint64_t); +typedef int (*Checker) (Cube, int); +typedef uint64_t (*Indexer) (Cube); +typedef bool (*Moveset) (Move); + + +/* Enums *********************************************************************/ + +enum +center +{ + U_center, D_center, + R_center, L_center, + F_center, B_center +}; + +enum +corner +{ + UFR, UFL, UBL, UBR, + DFR, DFL, DBL, DBR +}; + +enum +edge +{ + UF, UL, UB, UR, + DF, DL, DB, DR, + FR, FL, BL, BR +}; + +enum +move +{ + NULLMOVE, + U, U2, U3, D, D2, D3, + R, R2, R3, L, L2, L3, + F, F2, F3, B, B2, B3, + Uw, Uw2, Uw3, Dw, Dw2, Dw3, + Rw, Rw2, Rw3, Lw, Lw2, Lw3, + Fw, Fw2, Fw3, Bw, Bw2, Bw3, + M, M2, M3, + S, S2, S3, + E, E2, E3, + x, x2, x3, + y, y2, y3, + z, z2, z3, +}; + +enum +trans +{ + uf, ur, ub, ul, + df, dr, db, dl, + rf, rd, rb, ru, + lf, ld, lb, lu, + fu, fr, fd, fl, + bu, br, bd, bl, + mirror, /* R|L */ +}; + + +/* Structs *******************************************************************/ + +struct +alg +{ + Move * move; + bool * inv; + int len; + int allocated; +}; + +struct +alglist +{ + AlgListNode * first; + AlgListNode * last; + int len; +}; + +struct +alglistnode +{ + Alg * alg; + AlgListNode * next; +}; + +struct +block +{ + bool edge[12]; + bool corner[8]; + bool center[6]; +}; + +struct +cube +{ + uint16_t epose; + uint16_t eposs; + uint16_t eposm; + uint16_t eofb; + uint16_t eorl; + uint16_t eoud; + uint16_t cp; + uint16_t coud; + uint16_t cofb; + uint16_t corl; + uint16_t cpos; +}; + +struct +cubearray +{ + int * ep; + int * eofb; + int * eorl; + int * eoud; + int * cp; + int * coud; + int * corl; + int * cofb; + int * cpos; +}; + +struct +dfsdata +{ + int d; + int m; + int lb; + bool niss; + Move last1; + Move last2; + AlgList * sols; + Alg * current_alg; + Move sorted_moves[NMOVES]; + int move_position[NMOVES]; +}; + +struct +piecefilter +{ + 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; + uint8_t * ptable; + uint8_t * reached; + bool generated; + uint64_t n; + uint64_t size; + Indexer index; + Moveset moveset; +}; + +struct +solveoptions +{ + int min_moves; + int max_moves; + int max_solutions; + bool optimal_only; + bool can_niss; + bool feedback; + Trans pre_trans; +}; + +struct +step +{ + Checker check; + Checker ready; + Moveset moveset; +}; + +/* TODO: I put it here because it needs the definition of Step, sort it out */ +struct +algset +{ + char * filename; + AlgList ** table; + bool generated; + uint64_t size; + Indexer index; + AntiIndexer antindex; + Step step; + SolveOptions opts; +}; diff --git a/old/2021-06-30-noreached/cube.c b/old/2021-06-30-noreached/cube.c new file mode 100644 index 0000000..a7d137c --- /dev/null +++ b/old/2021-06-30-noreached/cube.c @@ -0,0 +1,3394 @@ +#include "cube.h" + +/* Local functions **********************************************************/ + +static Cube admissible_ep(Cube cube, PieceFilter f); +static Cube admissible_eos_from_eofbepos(Cube cube); +static bool allowed_next(Move move, DfsData *dd); +static void append_alg(AlgList *l, Alg *alg); +static void append_move(Alg *alg, Move m, bool inverse); +static Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a); +static void apply_permutation(int *perm, int *set, int n); +static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f); +static int array_ep_to_epos(int *ep, int *eps_solved); +static Cube arrays_to_cube(CubeArray *arr, PieceFilter f); +static int binomial(int n, int k); +static Cube compose_filtered(Cube c2, Cube c1, PieceFilter f); +static void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f); +static void dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static void dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static bool dfs_check_solved(SolveOptions *opts, DfsData *dd); +static void dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static bool dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static int digit_array_to_int(int *a, int n, int b); +static int edge_slice(Edge e); /* E=0, S=1, M=2 */ +static int epos_dependent_pos(int pos1, int pos2); +static int epos_from_arrays(int *epos, int *ep); +static void epos_to_partial_ep(int epos, int *ep, int *ss); +static int factorial(int n); +static void free_alglistnode(AlgListNode *aln); +static void free_cubearray(CubeArray *arr, PieceFilter f); +static void genptable_dfs(Cube c, PruneData *pd, DfsData *dd); +static void genptable_dfs_branch(Cube c, PruneData *pd, DfsData *dd); +static void gensym(SymData *sd); +static void index_to_perm(int p, int n, int *r); +static void index_to_subset(int s, int n, int k, int *r); +static void init_auxtables(); +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_environment(); +static void init_moves(); +static void init_moves_aux(); +static void init_strings(); +static void init_symdata(); +static void init_trans(); +static void init_trans_aux(); +static void int_to_digit_array(int a, int b, int n, int *r); +static void int_to_sum_zero_array(int x, int b, int n, int *a); +static int invert_digits(int a, int b, int n); +static bool is_perm(int *a, int n); +static bool is_subset(int *a, int n, int k); +static Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf); +static void movelist_to_position(Move *movelist, int *position); +static void moveset_to_list(Moveset ms, Estimator f, Move *r); +static AlgList * new_alglist(); +static CubeArray * new_cubearray(Cube cube, PieceFilter f); +static int perm_sign(int *a, int n); +static int perm_to_index(int *a, int n); +static int powint(int a, int b); +static void ptable_update(PruneData *pd, Cube cube, int m); +static void realloc_alg(Alg *alg, int n); +static bool read_mtables_file(); +static bool read_ptable_file(PruneData *pd); +static bool read_symdata_file(SymData *sd); +static bool read_ttables_file(); +static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f); +static int subset_to_index(int *a, int n, int k); +static void sum_arrays_mod(int *src, int *dst, int n, int m); +static void swap(int *a, int *b); +static bool write_mtables_file(); +static bool write_ptable_file(PruneData *pd); +static bool write_symdata_file(SymData *sd); +static bool write_ttables_file(); + + +/* All sorts of useful costants and tables **********************************/ + +static char * tabledir; + +static PieceFilter pf_all; +static PieceFilter pf_4val; +static PieceFilter pf_epcp; +static PieceFilter pf_cpos; +static PieceFilter pf_cp; +static PieceFilter pf_ep; +static PieceFilter pf_e; +static PieceFilter pf_s; +static PieceFilter pf_m; +static PieceFilter pf_eo; +static PieceFilter pf_co; + +static int epe_solved[4]; +static int eps_solved[4]; +static int epm_solved[4]; + +static char move_string[NMOVES][7]; +static char edge_string[12][7]; +static char corner_string[8][7]; +static char center_string[6][7]; + +static Cube admissible_ee_aux[POW2TO11*BINOM12ON4]; +static bool commute[NMOVES][NMOVES]; +static bool possible_next[NMOVES][NMOVES][NMOVES]; +static Move inverse_move_aux[NMOVES]; +static Trans inverse_trans_aux[NTRANS]; +static int epos_dependent_aux[BINOM12ON4][BINOM12ON4]; +static int cphtr_left_cosets[FACTORIAL8]; +static int cphtr_right_cosets[FACTORIAL8]; +static int cphtr_right_rep[BINOM8ON4*6]; +static Center what_center_at_aux[FACTORIAL6][6]; +static Corner what_corner_at_aux[FACTORIAL8][8]; +static int what_orientation_last_corner_aux[POW3TO7]; +static int what_orientation_last_edge_aux[POW2TO11]; +static Center where_is_center_aux[FACTORIAL6][6]; +static Corner where_is_corner_aux[FACTORIAL8][8]; +static Edge where_is_edge_aux[3][FACTORIAL12/FACTORIAL8][12]; + +static int epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static int eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static int eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static int eo_ttable[NTRANS][POW2TO11]; +static int cp_ttable[NTRANS][FACTORIAL8]; +static int co_ttable[NTRANS][POW3TO7]; +static int cpos_ttable[NTRANS][FACTORIAL6]; +static Move moves_ttable[NTRANS][NMOVES]; + +static int epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static int eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static int eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static int eofb_mtable[NMOVES][POW2TO11]; +static int eorl_mtable[NMOVES][POW2TO11]; +static int eoud_mtable[NMOVES][POW2TO11]; +static int cp_mtable[NMOVES][FACTORIAL8]; +static int coud_mtable[NMOVES][POW3TO7]; +static int cofb_mtable[NMOVES][POW3TO7]; +static int corl_mtable[NMOVES][POW3TO7]; +static int cpos_mtable[NMOVES][FACTORIAL6]; + +static uint64_t me[12]; + +static int edge_cycle[NMOVES][12]; +static int corner_cycle[NMOVES][8]; +static int center_cycle[NMOVES][6]; +static int eofb_flipped[NMOVES][12]; +static int eorl_flipped[NMOVES][12]; +static int eoud_flipped[NMOVES][12]; +static int coud_flipped[NMOVES][8]; +static int corl_flipped[NMOVES][8]; +static int cofb_flipped[NMOVES][8]; +static Alg * equiv_alg[NMOVES]; + +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]; +static int ep_mirror[12]; +static int cp_mirror[8]; +static int cpos_mirror[6]; +static Alg * rotation_algs[NROTATIONS]; + + +/* Symmetry data for some coordinates ****************************************/ + +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, +}; + +SymData +sd_coud_16 = { + .filename = "sd_coud_16", + .coord = &coord_coud, + .sym_coord = &coord_coud_sym16, + .ntrans = 16, + .trans = trans_group_udfix +}; + +SymData +sd_eofbepos_16 = { + .filename = "sd_eofbepos_16", + .coord = &coord_eofbepos, + .sym_coord = &coord_eofbepos_sym16, + .ntrans = 16, + .trans = trans_group_udfix +}; + +static int n_all_symdata = 2; +static SymData * all_sd[2] = { &sd_coud_16, &sd_eofbepos_16 }; + +/* Coordinates and their implementation **************************************/ + +static uint64_t index_eofb(Cube cube); +static uint64_t index_eofbepos(Cube cube); +static uint64_t index_coud(Cube cube); +static uint64_t index_corners(Cube cube); +static uint64_t index_cornershtr(Cube cube); +static uint64_t index_drud(Cube cube); +static uint64_t index_coud_sym16(Cube cube); +static uint64_t index_eofbepos_sym16(Cube cube); +static uint64_t index_drud_sym16(Cube cube); +static uint64_t index_khuge(Cube cube); + +static Cube antindex_eofb(uint64_t ind); +static Cube antindex_eofbepos(uint64_t ind); +static Cube antindex_coud(uint64_t ind); +static Cube antindex_corners(uint64_t ind); +static Cube antindex_cornershtr(uint64_t ind); +static Cube antindex_drud(uint64_t ind); +static Cube antindex_coud_sym16(uint64_t ind); +static Cube antindex_eofbepos_sym16(uint64_t ind); +static Cube antindex_drud_sym16(uint64_t ind); +static Cube antindex_khuge(uint64_t ind); + +Coordinate +coord_eofb = { + .index = index_eofb, + .cube = antindex_eofb, + .check = check_eofb, + .max = POW2TO11 +}; + +Coordinate +coord_eofbepos = { + .index = index_eofbepos, + .cube = antindex_eofbepos, + .check = check_eofbepos, + .max = POW2TO11 * BINOM12ON4 +}; + +Coordinate +coord_coud = { + .index = index_coud, + .cube = antindex_coud, + .check = check_coud, + .max = POW3TO7 +}; + +Coordinate +coord_corners = { + .index = index_corners, + .cube = antindex_corners, + .check = check_corners, + .max = POW3TO7 * FACTORIAL8 +}; + +Coordinate +coord_cornershtr = { + .index = index_cornershtr, + .cube = antindex_cornershtr, + .check = check_cornershtr, + .max = POW3TO7 * BINOM8ON4 * 6 +}; + +Coordinate +coord_drud = { + .index = index_drud, + .cube = antindex_drud, + .check = check_drud, + .max = POW2TO11 * POW3TO7 * BINOM12ON4 +}; + +Coordinate +coord_eofbepos_sym16 = { + .index = index_eofbepos_sym16, + .cube = antindex_eofbepos_sym16, + .check = check_eofbepos, +}; + +Coordinate +coord_coud_sym16 = { + .index = index_coud_sym16, + .cube = antindex_coud_sym16, + .check = check_coud, +}; + +Coordinate +coord_drud_sym16 = { + .index = index_drud_sym16, + .cube = antindex_drud_sym16, + .check = check_drud, + .max = POW3TO7 * 64430 +}; + +Coordinate +coord_khuge = { + .index = index_khuge, + .cube = antindex_khuge, + .check = check_khuge, + .max = POW3TO7 * FACTORIAL4 * 64430 +}; + + +static uint64_t +index_eofb(Cube cube) +{ + return cube.eofb; +} + +static uint64_t +index_eofbepos(Cube cube) +{ + return (cube.epose / FACTORIAL4) * POW2TO11 + cube.eofb; +} + +static uint64_t +index_coud(Cube cube) +{ + return cube.coud; +} + +static uint64_t +index_corners(Cube cube) +{ + return cube.coud * FACTORIAL8 + cube.cp; +} + +static uint64_t +index_cornershtr(Cube cube) +{ + return cube.coud * BINOM8ON4 * 6 + cphtr(cube); +} + +static uint64_t +index_drud(Cube cube) +{ + uint64_t a, b, c; + + a = cube.eofb; + b = cube.coud; + c = cube.epose / FACTORIAL4; + + b *= POW2TO11; + c *= POW2TO11 * POW3TO7; + + return a + b + c; +} + +static uint64_t +index_coud_sym16(Cube cube) +{ + return sd_coud_16.class[index_coud(cube)]; +} + +static uint64_t +index_drud_sym16(Cube cube) +{ + Trans t; + Cube c; + + t = sd_eofbepos_16.transtorep[index_eofbepos(cube)]; + c = apply_trans(t, cube); + + return index_eofbepos_sym16(c) * POW3TO7 + c.coud; +} + +static uint64_t +index_eofbepos_sym16(Cube cube) +{ + return sd_eofbepos_16.class[index_eofbepos(cube)]; +} + +static uint64_t +index_khuge(Cube cube) +{ + Trans t; + Cube c; + uint64_t a; + + t = sd_eofbepos_16.transtorep[index_eofbepos(cube)]; + c = apply_trans(t, cube); + a = (index_eofbepos_sym16(c) * 24) + (c.epose % 24); + + return a * POW3TO7 + c.coud; +} + + +/* TODO: rename */ +static Cube +antindex_eofb(uint64_t ind) +{ + return (Cube){ .eofb = ind, .eorl = ind, .eoud = ind }; +} + +static Cube +antindex_eofbepos(uint64_t ind) +{ + return admissible_ee_aux[ind]; +} + +/* TODO: rename */ +static Cube +antindex_coud(uint64_t ind) +{ + return (Cube){ .coud = ind, .corl = ind, .cofb = ind }; +} + +/* TODO: admissible co for other orientations */ +static Cube +antindex_corners(uint64_t ind) +{ + Cube c = {0}; + + c.coud = ind / FACTORIAL8; + c.cp = ind % FACTORIAL8; + + return c; +} + +/* TODO: admissible co for other orientations */ +static Cube +antindex_cornershtr(uint64_t ind) +{ + Cube c = anti_cphtr(ind % (BINOM8ON4 * 6)); + + c.coud = ind / (BINOM8ON4 * 6); + + return c; +} + +/* TODO: admissible eos and cos */ +static Cube +antindex_drud(uint64_t ind) +{ + Cube c = {0}; + + c.eofb = ind % POW2TO11; + c.coud = (ind / POW2TO11) % POW3TO7; + c.epose = (ind % (POW2TO11 * POW3TO7)) * FACTORIAL4; + + return c; +} + +static Cube +antindex_coud_sym16(uint64_t ind) +{ + return sd_coud_16.rep[ind]; +} + +static Cube +antindex_eofbepos_sym16(uint64_t ind) +{ + return sd_eofbepos_16.rep[ind]; +} + +static Cube +antindex_drud_sym16(uint64_t ind) +{ + Cube c; + + c = sd_eofbepos_16.rep[ind/POW3TO7]; + c.coud = ind % POW3TO7; + c.cofb = c.coud; + c.corl = c.coud; + + return c; +} + +static Cube +antindex_khuge(uint64_t ind) +{ + Cube c; + + c = sd_eofbepos_16.rep[ind/(FACTORIAL4*POW3TO7)]; + c.epose = ((c.epose / 24) * 24) + ((ind/POW3TO7) % 24); + c.coud = ind % POW3TO7; + + return c; +} + + +/* Checkers ******************************************************************/ + +bool +check_centers(Cube cube) +{ + return cube.cpos == 0; +} + +bool +check_corners(Cube cube) +{ + return cube.cp == 0 && cube.coud == 0; +} + +bool +check_cornershtr(Cube cube) +{ + return cube.coud == 0 && cphtr(cube) == 0; /* TODO: use array cphtrcosets*/ +} + +bool +check_coud(Cube cube) +{ + return cube.coud == 0; +} + +bool +check_drud(Cube cube) +{ + return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0; +} + +bool +check_eofb(Cube cube) +{ + return cube.eofb == 0; +} + +bool +check_eofbepos(Cube cube) +{ + return cube.eofb == 0 && cube.epose / 24 == 0; +} + +bool +check_epose(Cube cube) +{ + return cube.epose == 0; +} + +bool +check_ep(Cube cube) +{ + return cube.epose == 0 && cube.eposs == 0 && cube.eposm == 0; +} + +bool +check_khuge(Cube cube) +{ + return check_drud(cube) && cube.epose % 24 == 0; +} + +bool +check_nothing(Cube cube) +{ + return is_admissible(cube); /*TODO: maybe change?*/ +} + +/* Movesets ******************************************************************/ + +bool +moveset_HTM(Move m) +{ + return m >= U && m <= B3; +} + +bool +moveset_URF(Move m) +{ + Move b = base_move(m); + + return b == U || b == R || b == F; +} + + +/* Local functions implementation ********************************************/ + +/* TODO: this should be an anti index (maybe?) */ +static 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 < 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; +} + +static Cube +admissible_eos_from_eofbepos(Cube cube) +{ + Edge e; + Cube ret; + CubeArray *arr = new_cubearray(cube, pf_all); + + memcpy(arr->eorl, arr->eofb, 12 * sizeof(int)); + memcpy(arr->eoud, arr->eofb, 12 * sizeof(int)); + + for (e = 0; e < 12; e++) { + if ((edge_slice(e) != 0 && edge_slice(arr->ep[e]) == 0) || + (edge_slice(e) == 0 && edge_slice(arr->ep[e]) != 0)) + arr->eorl[e] = 1 - arr->eorl[e]; + if ((edge_slice(e) != 2 && edge_slice(arr->ep[e]) == 2) || + (edge_slice(e) == 2 && edge_slice(arr->ep[e]) != 2)) + arr->eoud[e] = 1 - arr->eoud[e]; + } + + ret = arrays_to_cube(arr, pf_all); + free_cubearray(arr, pf_all); + + return ret; +} + +static bool +allowed_next(Move move, DfsData *dd) +{ + if (!possible_next[dd->last2][dd->last1][move]) + return false; + + if (commute[dd->last1][move]) + return dd->move_position[dd->last1] < dd->move_position[move]; + + return true; +} + +static void +append_alg(AlgList *l, Alg *alg) +{ + AlgListNode *node = malloc(sizeof(AlgListNode)); + int i; + + node->alg = new_alg(""); + for (i = 0; i < alg->len; i++) + append_move(node->alg, alg->move[i], alg->inv[i]); + node->next = NULL; + + if (++l->len == 1) + l->first = node; + else + l->last->next = node; + l->last = node; +} + +static void +append_move(Alg *alg, Move m, bool inverse) +{ + if (alg->len == alg->allocated) + realloc_alg(alg, 2*alg->len); + + alg->move[alg->len] = m; + alg->inv [alg->len] = inverse; + alg->len++; +} + +static Cube +apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a) +{ + Cube ret = {0}; + int i; + + for (i = 0; i < alg->len; i++) + if (alg->inv[i]) + ret = a ? apply_move(alg->move[i], ret) : + apply_move_cubearray(alg->move[i], ret, f); + + ret = compose_filtered(c, inverse_cube(ret), f); + + for (i = 0; i < alg->len; i++) + if (!alg->inv[i]) + ret = a ? apply_move(alg->move[i], ret) : + apply_move_cubearray(alg->move[i], ret, f); + + return ret; +} + +static void +apply_permutation(int *perm, int *set, int n) +{ + int *aux = malloc(n * sizeof(int)); + int i; + + if (!is_perm(perm, n)) + return; + + for (i = 0; i < n; i++) + aux[i] = set[perm[i]]; + + memcpy(set, aux, n * sizeof(int)); + free(aux); +} + +static Cube +apply_move_cubearray(Move m, Cube cube, PieceFilter f) +{ + 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); +} + +static int +array_ep_to_epos(int *ep, int *ss) +{ + 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 epos_from_arrays(epos, eps); +} + +static Cube +arrays_to_cube(CubeArray *arr, PieceFilter f) +{ + Cube ret = {0}; + + 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; +} + +static int +binomial(int n, int k) +{ + if (n < 0 || k < 0 || k > n) + return 0; + + return factorial(n) / (factorial(k) * factorial(n-k)); +} + +static Cube +compose_filtered(Cube c2, Cube c1, PieceFilter f) +{ + CubeArray *arr = new_cubearray(c2, f); + Cube ret; + + ret = move_via_arrays(arr, c1, f); + free_cubearray(arr, f); + + return ret; +} + +static void +cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f) +{ + int i; + + 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); +} + +/* +static int +cphtr_cp(int cp) +{ + int i, a[8]; + + index_to_perm(cp, 8, a); + + for (i = 0; i < 8; i++) + if (a[i] == UFR || a[i] == UBL || a[i] == DFL || a[i] == DBR) + a[i] = 0; + else + a[i] = 1; + + swap(&a[1], &a[5]); + swap(&a[3], &a[7]); + + return subset_to_index(a, 8, 4); +} +*/ + +static void +dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + if (dfs_stop(c, s, opts, dd)) + return; + + if (dfs_check_solved(opts, dd)) + return; + + dfs_branch(c, s, opts, dd); + + if (opts->can_niss && !dd->niss) + dfs_niss(c, s, opts, dd); +} + +static void +dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + Move m, l1 = dd->last1, l2 = dd->last2, *moves = dd->sorted_moves; + + int i, maxnsol = opts->max_solutions; + + for (i = 0; moves[i] != NULLMOVE && dd->sols->len < maxnsol; i++) { + m = moves[i]; + if (allowed_next(m, dd)) { + dd->last2 = dd->last1; + dd->last1 = m; + append_move(dd->current_alg, m, dd->niss); + + dfs(apply_move(m, c), s, opts, dd); + + dd->current_alg->len--; + dd->last2 = l2; + dd->last1 = l1; + } + } +} + +static bool +dfs_check_solved(SolveOptions *opts, DfsData *dd) +{ + if (dd->lb != 0) + return false; + + if (dd->current_alg->len == dd->d) { + append_alg(dd->sols, dd->current_alg); + + if (opts->feedback) + print_alg(dd->current_alg, false); + } + + return true; +} + +static void +dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + Move l1 = dd->last1, l2 = dd->last2; + CubeTarget ct; + + ct.cube = apply_move(inverse_move(l1), (Cube){0}); + ct.target = 1; + + if (dd->current_alg->len == 0 || s.estimate(ct)) { + dd->niss = true; + dd->last1 = NULLMOVE; + dd->last2 = NULLMOVE; + + dfs(inverse_cube(c), s, opts, dd); + + dd->last1 = l1; + dd->last2 = l2; + dd->niss = false; + } +} + +static bool +dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + CubeTarget ct = { + .cube = c, + .target = dd->d - dd->current_alg->len + }; + + if (dd->sols->len >= opts->max_solutions) + return true; + + dd->lb = s.estimate(ct); + if (opts->can_niss && !dd->niss) + dd->lb = MIN(1, dd->lb); + + if (dd->current_alg->len + dd->lb > dd->d) + return true; + + return false; +} + +static int +digit_array_to_int(int *a, int n, int b) +{ + int i, ret = 0, p = 1; + + for (i = 0; i < n; i++, p *= b) + ret += a[i] * p; + + return ret; +} + +static int +edge_slice(Edge e) { + if (e < 0 || e > 11) + return -1; + + if (e == FR || e == FL || e == BL || e == BR) + return 0; + if (e == UR || e == UL || e == DR || e == DL) + return 1; + + return 2; +} + +static int +epos_dependent_pos(int poss, int pose) +{ + int ep[12] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; + int ep8[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + int i, j; + + epos_to_partial_ep(poss*FACTORIAL4, ep, eps_solved); + epos_to_partial_ep(pose*FACTORIAL4, ep, epe_solved); + + for (i = 0, j = 0; i < 12; i++) + if (edge_slice(ep[i]) != 0) + ep8[j++] = (edge_slice(ep[i]) == 1) ? 1 : 0; + + swap(&ep8[1], &ep8[4]); + swap(&ep8[3], &ep8[6]); + + return subset_to_index(ep8, 8, 4); +} + +static int +epos_from_arrays(int *epos, int *ep) +{ + return FACTORIAL4 * subset_to_index(epos,12,4) + perm_to_index(ep,4); +} + +static void +epos_to_partial_ep(int epos, int *ep, int *ss) +{ + 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++]]; +} + +static int +factorial(int n) +{ + int i, ret = 1; + + if (n < 0) + return 0; + + for (i = 1; i <= n; i++) + ret *= i; + + return ret; +} + +void +free_alg(Alg *alg) +{ + free(alg->move); + free(alg->inv); + free(alg); +} + +void +free_alglist(AlgList *l) +{ + AlgListNode *aux, *i = l->first; + + while (i != NULL) { + aux = i->next; + free_alglistnode(i); + i = aux; + } + free(l); +} + +void +free_alglistnode(AlgListNode *aln) +{ + free_alg(aln->alg); + free(aln); +} + +static void +free_cubearray(CubeArray *arr, PieceFilter f) +{ + 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); +} + +static void +genptable_dfs(Cube c, PruneData *pd, DfsData *dd) +{ + int oldval = ptableval(pd, c); + + if (oldval < dd->m || pd->n == pd->coord->max || + (dd->m != 0 && pd->coord->check(c)) ) + return; + + if (dd->m == dd->d) { + if (dd->m < oldval) + ptable_update(pd, c, dd->m); + return; + } + + genptable_dfs_branch(c, pd, dd); +} + +static void +genptable_dfs_branch(Cube c, PruneData *pd, DfsData *dd) +{ + Move i, move, l1 = dd->last1, l2 = dd->last2; + + dd->m++; + + for (i = 0; dd->sorted_moves[i] != NULLMOVE; i++) { + move = dd->sorted_moves[i]; + if (allowed_next(move, dd)) { + dd->last2 = dd->last1; + dd->last1 = move; + + genptable_dfs(apply_move(move, c), pd, dd); + + dd->last2 = l2; + dd->last1 = l1; + } + } + + dd->m--; +} + +static void +gensym(SymData *sd) +{ + uint64_t i, in, nreps = 0; + int j; + Cube c, d; + + if (sd->generated) + return; + + sd->class = malloc(sd->coord->max * sizeof(uint64_t)); + sd->rep = malloc(sd->coord->max * sizeof(Cube)); + sd->transtorep = malloc(sd->coord->max * sizeof(Trans)); + + 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) { + c = sd->coord->cube(i); + sd->rep[nreps] = c; + for (j = 0; j < sd->ntrans; j++) { + d = apply_trans(sd->trans[j], c); + in = sd->coord->index(d); + + if (sd->class[in] == sd->coord->max + 1) { + sd->class[in] = nreps; + sd->transtorep[in] = + inverse_trans(sd->trans[j]); + } + } + nreps++; + } + } + + sd->sym_coord->max = nreps; + sd->rep = realloc(sd->rep, nreps * sizeof(Cube)); + sd->generated = true; + + fprintf(stderr, "Found %lu classes\n", nreps); + + if (!write_symdata_file(sd)) + fprintf(stderr, "Error writing SymData file\n"); + + return; +} + +static void +index_to_perm(int p, int n, int *r) +{ + int *a = malloc(n * sizeof(int)); + int i, j, c; + + for (i = 0; i < n; i++) + a[i] = 0; + + if (p < 0 || p >= factorial(n)) + for (i = 0; i < n; i++) + r[i] = -1; + + for (i = 0; i < n; i++) { + c = 0; + j = 0; + while (c <= p / factorial(n-i-1)) + c += a[j++] ? 0 : 1; + r[i] = j-1; + a[j-1] = 1; + p %= factorial(n-i-1); + } + + free(a); +} + +static void +index_to_subset(int s, int n, int k, int *r) +{ + int i, j, v; + + if (s < 0 || s >= binomial(n, k)) { + for (i = 0; i < n; i++) + r[i] = -1; + return; + } + + for (i = 0; i < n; i++) { + if (k == n-i) { + for (j = i; j < n; j++) + r[j] = 1; + return; + } + + if (k == 0) { + for (j = i; j < n; j++) + r[j] = 0; + return; + } + + v = binomial(n-i-1, k); + if (s >= v) { + r[i] = 1; + k--; + s -= v; + } else { + r[i] = 0; + } + } +} + +static void +int_to_digit_array(int a, int b, int n, int *r) +{ + int i; + + if (b <= 1) + for (i = 0; i < n; i++) + r[i] = 0; + else + for (i = 0; i < n; i++, a /= b) + r[i] = a % b; +} + +static void +int_to_sum_zero_array(int x, int b, int n, int *a) +{ + int i, s = 0; + + if (b <= 1) { + for (i = 0; i < n; i++) + a[i] = 0; + } else { + int_to_digit_array(x, b, n-1, a); + for (i = 0; i < n - 1; i++) + s = (s + a[i]) % b; + a[n-1] = (b - s) % b; + } +} + +static int +invert_digits(int a, int b, int n) +{ + int i, ret, *r = malloc(n * sizeof(int)); + + int_to_digit_array(a, b, n, r); + for (i = 0; i < n; i++) + r[i] = (b-r[i]) % b; + + ret = digit_array_to_int(r, n, b); + free(r); + return ret; +} + +static bool +is_perm(int *a, int n) +{ + int *aux = malloc(n * sizeof(int)); + int i; + + for (i = 0; i < n; i++) + if (a[i] < 0 || a[i] >= n) + return false; + else + aux[a[i]] = 1; + + for (i = 0; i < n; i++) + if (!aux[i]) + return false; + + free(aux); + + return true; +} + +static bool +is_subset(int *a, int n, int k) +{ + int i, sum = 0; + + for (i = 0; i < n; i++) + sum += a[i] ? 1 : 0; + + return sum == k; +} + +static Cube +move_via_arrays(CubeArray *arr, Cube c, PieceFilter f) +{ + CubeArray *arrc = new_cubearray(c, f); + Cube ret; + + 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; +} + +static void +movelist_to_position(Move *movelist, int *position) +{ + Move m; + + for (m = 0; m < NMOVES && movelist[m] != NULLMOVE; m++) + position[movelist[m]] = m; +} + +static void +moveset_to_list(Moveset ms, Estimator f, Move *r) +{ + CubeTarget ct = { .target = 1 }; + int b[NMOVES]; + int na = 0, nb = 0; + Move i; + + if (ms == NULL) { + fprintf(stderr, "Error: no moveset given\n"); + return; + } + + for (i = U; i < NMOVES; i++) { + if (ms(i)) { + ct.cube = apply_move(i, (Cube){0}); + if (f != NULL && f(ct)) + r[na++] = i; + else + b[nb++] = i; + } + } + + memcpy(r + na, b, nb * sizeof(Move)); + r[na+nb] = NULLMOVE; +} + +static AlgList * +new_alglist() +{ + AlgList *ret = malloc(sizeof(AlgList)); + + ret->len = 0; + ret->first = NULL; + ret->last = NULL; + + return ret; +} + +static CubeArray * +new_cubearray(Cube cube, PieceFilter f) +{ + 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; +} + +static int +perm_sign(int *a, int n) +{ + int i, j, ret = 0; + + if (!is_perm(a,n)) + return -1; + + for (i = 0; i < n; i++) + for (j = i+1; j < n; j++) + ret += (a[i] > a[j]) ? 1 : 0; + + return ret % 2; +} + +static int +perm_to_index(int *a, int n) +{ + int i, j, c, ret = 0; + + if (!is_perm(a, n)) + return -1; + + for (i = 0; i < n; i++) { + c = 0; + for (j = i+1; j < n; j++) + c += (a[i] > a[j]) ? 1 : 0; + ret += factorial(n-i-1) * c; + } + + return ret; +} + +static int +powint(int a, int b) +{ + if (b < 0) + return 0; + if (b == 0) + return 1; + + if (b % 2) + return a * powint(a, b-1); + else + return powint(a*a, b/2); +} + +static void +ptable_update(PruneData *pd, Cube cube, int n) +{ + uint64_t ind = pd->coord->index(cube); + uint8_t oldval2 = pd->ptable[ind/2]; + int other = (ind % 2) ? oldval2 % 16 : oldval2 / 16; + + pd->ptable[ind/2] = (ind % 2) ? 16*n + other : 16*other + n; + pd->n++; +} + +static void +realloc_alg(Alg *alg, int n) +{ + if (alg == NULL) { + fprintf(stderr, "Error: trying to reallocate NULL alg.\n"); + return; + } + + if (n < alg->len) { + fprintf(stderr, "Error: alg too long for reallocation "); + fprintf(stderr, "(%d vs %d)\n", alg->len, n); + return; + } + + if (n > 1000000) { + fprintf(stderr, "Warning: very long alg,"); + fprintf(stderr, "something might go wrong.\n"); + } + + alg->move = realloc(alg->move, n * sizeof(int)); + alg->inv = realloc(alg->inv, n * sizeof(int)); + alg->allocated = n; +} + +static bool +read_mtables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int m, b = sizeof(int); + bool r = true; + + 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 +read_ptable_file(PruneData *pd) +{ + FILE *f; + char fname[strlen(tabledir)+100]; + uint64_t r; + + strcpy(fname, tabledir); + strcat(fname, "/"); + strcat(fname, pd->filename); + + if ((f = fopen(fname, "rb")) == NULL) + return false; + + r = fread(pd->ptable, sizeof(uint8_t), ptablesize(pd), f); + fclose(f); + + return r == ptablesize(pd); +} + +static bool +read_symdata_file(SymData *sd) +{ + 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->rep, sizeof(Cube), *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_ttables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int b = sizeof(int); + bool r = true; + Move m; + + 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[6], f) == me[6]; + r = r && fread(co_ttable[m], b, me[7], f) == me[7]; + r = r && fread(cpos_ttable[m], b, me[10], f) == me[10]; + r = r && fread(moves_ttable[m], b, me[11], f) == me[11]; + } + + 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_algs[r % NROTATIONS]); + 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_algs[r % NROTATIONS], ret, f, true); + if (r >= NROTATIONS) + ret = move_via_arrays(&ma, ret, f); + + free_alg(inv); + return ret; +} + +static int +subset_to_index(int *a, int n, int k) +{ + int i, ret = 0; + + if (!is_subset(a, n, k)) + return binomial(n, k); + + for (i = 0; i < n; i++) { + if (k == n-i) + return ret; + if (a[i]) { + ret += binomial(n-i-1, k); + k--; + } + } + + return ret; +} + +static void +sum_arrays_mod(int *src, int *dst, int n, int m) +{ + int i; + + for (i = 0; i < n; i++) + dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m; +} + +static void +swap(int *a, int *b) +{ + int aux; + + aux = *a; + *a = *b; + *b = aux; +} + +static bool +write_mtables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int m, b = sizeof(int); + bool r = true; + + 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; +} + +static bool +write_ptable_file(PruneData *pd) +{ + FILE *f; + char fname[strlen(tabledir)+100]; + uint64_t written; + + strcpy(fname, tabledir); + strcat(fname, "/"); + strcat(fname, pd->filename); + + if ((f = fopen(fname, "wb")) == NULL) + return false; + + written = fwrite(pd->ptable, sizeof(uint8_t), ptablesize(pd), f); + fclose(f); + + return written == ptablesize(pd); +} + +static bool +write_symdata_file(SymData *sd) +{ + 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->rep, sizeof(Cube), *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_ttables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + bool r = true; + int b = sizeof(int); + Move m; + + 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[6], f) == me[6]; + r = r && fwrite(co_ttable[m], b, me[7], f) == me[7]; + r = r && fwrite(cpos_ttable[m], b, me[10], f) == me[10]; + r = r && fwrite(moves_ttable[m], b, me[11], f) == me[11]; + } + + fclose(f); + return r; +} + +/* Init functions implementation *********************************************/ + +static void +init_auxtables() +{ + Cube c1, c2; + CubeArray *arr; + uint64_t ui, uj; + int i, j, k, auxarr[12]; + bool cij, p1, p2; + + for (ui = 0; ui < POW2TO11*BINOM12ON4; ui++) { + k = (ui / POW2TO11) * 24; + c1 = admissible_ep((Cube){ .epose = k }, pf_e); + c1.eofb = ui % POW2TO11; + c1 = admissible_eos_from_eofbepos(c1); + admissible_ee_aux[ui] = c1; + } + + for (ui = 0; ui < FACTORIAL6; ui++) { + arr = new_cubearray((Cube){.cpos = ui}, pf_cpos); + for (i = 0; i < 6; i++) { + what_center_at_aux[ui][i] = arr->cpos[i]; + where_is_center_aux[ui][arr->cpos[i]] = i; + } + free_cubearray(arr, pf_cpos); + } + + for (ui = 0; ui < FACTORIAL8; ui++) { + arr = new_cubearray((Cube){.cp = ui}, pf_cp); + for (i = 0; i < 8; i++) { + what_corner_at_aux[ui][i] = arr->cp[i]; + where_is_corner_aux[ui][arr->cp[i]] = i; + } + free_cubearray(arr, pf_cp); + } + + for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) { + arr = new_cubearray((Cube){.epose = ui}, pf_e); + for (i = 0; i < 12; i++) + if (edge_slice(arr->ep[i]) == 0) + where_is_edge_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) + where_is_edge_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) + where_is_edge_aux[2][ui][arr->ep[i]] = i; + free_cubearray(arr, pf_m); + } + + for (ui = 0; ui < POW3TO7; ui++) { + int_to_sum_zero_array(ui, 3, 8, auxarr); + what_orientation_last_corner_aux[ui] = auxarr[7]; + } + + for (ui = 0; ui < POW2TO11; ui++) { + int_to_sum_zero_array(ui, 2, 12, auxarr); + what_orientation_last_edge_aux[ui] = auxarr[11]; + } + + for (ui = 0; ui < BINOM12ON4; ui++) + for (uj = 0; uj < BINOM12ON4; uj++) + epos_dependent_aux[ui][uj]=epos_dependent_pos(ui, uj); + + for (i = 0; i < NMOVES; i++) { + for (j = 0; j < NMOVES; j++) { + c1 = apply_move(i, apply_move(j, (Cube){0})); + c2 = apply_move(j, apply_move(i, (Cube){0})); + commute[i][j] = equal(c1, c2) && i && j; + } + } + + for (i = 0; i < NMOVES; i++) { + for (j = 0; j < NMOVES; j++) { + for (k = 0; k < NMOVES; k++) { + p1 = j && base_move(j) == base_move(k); + p2 = i && base_move(i) == base_move(k); + cij = commute[i][j]; + possible_next[i][j][k] = !(p1 || (cij && p2)); + } + } + } + + for (i = 0; i < NMOVES; i++) + inverse_move_aux[i] = i ? i + 2 - 2*((i-1)%3) : NULLMOVE; + + /* Is there a more elegant way? */ + inverse_trans_aux[uf] = uf; + inverse_trans_aux[ur] = ul; + inverse_trans_aux[ul] = ur; + inverse_trans_aux[ub] = ub; + + inverse_trans_aux[df] = df; + inverse_trans_aux[dr] = dr; + inverse_trans_aux[dl] = dl; + inverse_trans_aux[db] = db; + + inverse_trans_aux[rf] = lf; + inverse_trans_aux[rd] = bl; + inverse_trans_aux[rb] = rb; + inverse_trans_aux[ru] = fr; + + inverse_trans_aux[lf] = rf; + inverse_trans_aux[ld] = br; + inverse_trans_aux[lb] = lb; + inverse_trans_aux[lu] = fl; + + inverse_trans_aux[fu] = fu; + inverse_trans_aux[fr] = ru; + inverse_trans_aux[fd] = bu; + inverse_trans_aux[fl] = lu; + + inverse_trans_aux[bu] = fd; + inverse_trans_aux[br] = ld; + inverse_trans_aux[bd] = bd; + inverse_trans_aux[bl] = rd; + + inverse_trans_aux[uf_mirror] = uf_mirror; + inverse_trans_aux[ur_mirror] = ur_mirror; + inverse_trans_aux[ul_mirror] = ul_mirror; + inverse_trans_aux[ub_mirror] = ub_mirror; + + inverse_trans_aux[df_mirror] = df_mirror; + inverse_trans_aux[dr_mirror] = dl_mirror; + inverse_trans_aux[dl_mirror] = dr_mirror; + inverse_trans_aux[db_mirror] = db_mirror; + + inverse_trans_aux[rf_mirror] = rf_mirror; + inverse_trans_aux[rd_mirror] = br_mirror; + inverse_trans_aux[rb_mirror] = lb_mirror; + inverse_trans_aux[ru_mirror] = fl_mirror; + + inverse_trans_aux[lf_mirror] = lf_mirror; + inverse_trans_aux[ld_mirror] = bl_mirror; + inverse_trans_aux[lb_mirror] = rb_mirror; + inverse_trans_aux[lu_mirror] = fr_mirror; + + inverse_trans_aux[fu_mirror] = fu_mirror; + inverse_trans_aux[fr_mirror] = lu_mirror; + inverse_trans_aux[fd_mirror] = bu_mirror; + inverse_trans_aux[fl_mirror] = ru_mirror; + + inverse_trans_aux[bu_mirror] = fd_mirror; + inverse_trans_aux[br_mirror] = rd_mirror; + inverse_trans_aux[bd_mirror] = bd_mirror; + inverse_trans_aux[bl_mirror] = ld_mirror; +} + +/* + * There is certainly a bette 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 < FACTORIAL8; i++) { + cphtr_left_cosets[i] = -1; + cphtr_right_cosets[i] = -1; + } + + /* 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++); + + /* 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++); +} + +static void +init_cphtr_left_cosets_bfs(int i, int c) +{ + int j, jj, k, next[FACTORIAL8], next2[FACTORIAL8], n, n2; + Move moves[6] = {U2, D2, R2, L2, F2, B2}; + + n = 1; + next[0] = i; + cphtr_left_cosets[i] = c; + + while (n != 0) { + for (j = 0, n2 = 0; j < n; j++) { + for (k = 0; k < 6; k++) { + jj = cp_mtable[moves[k]][next[j]]; + if (cphtr_left_cosets[jj] == -1) { + cphtr_left_cosets[jj] = c; + next2[n2++] = jj; + } + } + } + + for (j = 0; j < n2; j++) + next[j] = next2[j]; + n = n2; + } +} + +static void +init_cphtr_right_cosets_color(int i, int d) +{ + int cp; + unsigned int j; + + cphtr_right_rep[d] = i; + for (j = 0; j < FACTORIAL8; j++) { + if (cphtr_left_cosets[j] == 0) { + /* TODO: use antindexer, it's nicer */ + cp = compose((Cube){.cp = i}, (Cube){.cp = j}).cp; + cphtr_right_cosets[cp] = d; + } + } +} + +static void +init_environment() +{ + char *nissydata = getenv("NISSYDATA"); + char *localdata = getenv("XDG_DATA_HOME"); + char *home = getenv("HOME"); + bool read, write; + + if (nissydata != NULL) { + tabledir = malloc(strlen(nissydata) * sizeof(char) + 20); + strcpy(tabledir, nissydata); + } else if (localdata != NULL) { + tabledir = malloc(strlen(localdata) * sizeof(char) + 20); + strcpy(tabledir, localdata); + strcat(tabledir, "/nissy"); + } else if (home != NULL) { + tabledir = malloc(strlen(home) * sizeof(char) + 20); + strcpy(tabledir, home); + strcat(tabledir, "/.nissy"); + } + + mkdir(tabledir, 0777); + strcat(tabledir, "/tables"); + mkdir(tabledir, 0777); + + read = !access(tabledir, R_OK); + write = !access(tabledir, W_OK); + + if (!read) { + fprintf(stderr, "Table files cannot be read.\n"); + } else if (!write) { + fprintf(stderr, "Data directory not writable: "); + fprintf(stderr, "tables can be loaded, but not saved.\n"); + } +} + +static void +init_moves() { + Cube c; + CubeArray arrs; + int i; + unsigned int ui; + Move m; + + /* 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; + + fprintf(stderr, "Cannot load %s, generating it\n", "mtables"); + + /* Initialize transition tables */ + for (m = 0; m < NMOVES; m++) { + 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; + } + } + + if (!write_mtables_file()) + fprintf(stderr, "Error writing mtables\n"); +} + +static void +init_moves_aux() +{ + /* Some standard PieceFilters */ + pf_all.epose = true; + pf_all.eposs = true; + pf_all.eposm = true; + pf_all.eofb = true; + pf_all.eorl = true; + pf_all.eoud = true; + pf_all.cp = true; + pf_all.cofb = true; + pf_all.corl = true; + pf_all.coud = true; + pf_all.cpos = true; + + pf_4val.epose = true; + pf_4val.eposs = true; + pf_4val.eposm = true; + pf_4val.eofb = true; + pf_4val.coud = true; + pf_4val.cp = true; + + pf_epcp.epose = true; + pf_epcp.eposs = true; + pf_epcp.eposm = true; + pf_epcp.cp = true; + + pf_cpos.cpos = true; + + pf_cp.cp = true; + + pf_ep.epose = true; + pf_ep.eposs = true; + pf_ep.eposm = true; + + pf_e.epose = true; + pf_s.eposs = true; + pf_m.eposm = true; + + pf_eo.eofb = true; + pf_eo.eorl = true; + pf_eo.eoud = true; + + pf_co.cofb = true; + pf_co.corl = true; + pf_co.coud = true; + + /* Used to convert to and from CubeArray */ + epe_solved[0] = FR; + epe_solved[1] = FL; + epe_solved[2] = BL; + epe_solved[3] = BR; + + eps_solved[0] = UL; + eps_solved[1] = UR; + eps_solved[2] = DL; + eps_solved[3] = DR; + + epm_solved[0] = UF; + epm_solved[1] = UB; + epm_solved[2] = DF; + epm_solved[3] = DB; + + /* Table sizes, used for reading and writing files */ + me[0] = FACTORIAL12/FACTORIAL8; + me[1] = FACTORIAL12/FACTORIAL8; + me[2] = FACTORIAL12/FACTORIAL8; + me[3] = POW2TO11; + me[4] = POW2TO11; + me[5] = POW2TO11; + me[6] = FACTORIAL8; + me[7] = POW3TO7; + me[8] = POW3TO7; + me[9] = POW3TO7; + me[10] = FACTORIAL6; + me[11] = NMOVES; + + /* Cycles *********************/ + edge_cycle[U][UF] = UR; + edge_cycle[U][UL] = UF; + edge_cycle[U][UB] = UL; + edge_cycle[U][UR] = UB; + edge_cycle[U][DF] = DF; + edge_cycle[U][DL] = DL; + edge_cycle[U][DB] = DB; + edge_cycle[U][DR] = DR; + edge_cycle[U][FR] = FR; + edge_cycle[U][FL] = FL; + edge_cycle[U][BL] = BL; + edge_cycle[U][BR] = BR; + + edge_cycle[x][UF] = DF; + edge_cycle[x][UL] = FL; + edge_cycle[x][UB] = UF; + edge_cycle[x][UR] = FR; + edge_cycle[x][DF] = DB; + edge_cycle[x][DL] = BL; + edge_cycle[x][DB] = UB; + edge_cycle[x][DR] = BR; + edge_cycle[x][FR] = DR; + edge_cycle[x][FL] = DL; + edge_cycle[x][BL] = UL; + edge_cycle[x][BR] = UR; + + edge_cycle[y][UF] = UR; + edge_cycle[y][UL] = UF; + edge_cycle[y][UB] = UL; + edge_cycle[y][UR] = UB; + edge_cycle[y][DF] = DR; + edge_cycle[y][DL] = DF; + edge_cycle[y][DB] = DL; + edge_cycle[y][DR] = DB; + edge_cycle[y][FR] = BR; + edge_cycle[y][FL] = FR; + edge_cycle[y][BL] = FL; + edge_cycle[y][BR] = BL; + + corner_cycle[U][UFR] = UBR; + corner_cycle[U][UFL] = UFR; + corner_cycle[U][UBL] = UFL; + corner_cycle[U][UBR] = UBL; + corner_cycle[U][DFR] = DFR; + corner_cycle[U][DFL] = DFL; + corner_cycle[U][DBL] = DBL; + corner_cycle[U][DBR] = DBR; + + corner_cycle[x][UFR] = DFR; + corner_cycle[x][UFL] = DFL; + corner_cycle[x][UBL] = UFL; + corner_cycle[x][UBR] = UFR; + corner_cycle[x][DFR] = DBR; + corner_cycle[x][DFL] = DBL; + corner_cycle[x][DBL] = UBL; + corner_cycle[x][DBR] = UBR; + + corner_cycle[y][UFR] = UBR; + corner_cycle[y][UFL] = UFR; + corner_cycle[y][UBL] = UFL; + corner_cycle[y][UBR] = UBL; + corner_cycle[y][DFR] = DBR; + corner_cycle[y][DFL] = DFR; + corner_cycle[y][DBL] = DFL; + corner_cycle[y][DBR] = DBL; + + center_cycle[U][U_center] = U_center; + center_cycle[U][D_center] = D_center; + center_cycle[U][R_center] = R_center; + center_cycle[U][L_center] = L_center; + center_cycle[U][F_center] = F_center; + center_cycle[U][B_center] = B_center; + + center_cycle[x][U_center] = F_center; + center_cycle[x][D_center] = B_center; + center_cycle[x][R_center] = R_center; + center_cycle[x][L_center] = L_center; + center_cycle[x][F_center] = D_center; + center_cycle[x][B_center] = U_center; + + center_cycle[y][U_center] = U_center; + center_cycle[y][D_center] = D_center; + center_cycle[y][R_center] = B_center; + center_cycle[y][L_center] = F_center; + center_cycle[y][F_center] = R_center; + center_cycle[y][B_center] = L_center; + + /* Flipped pieces *************/ + eofb_flipped[x][UF] = 1; + eofb_flipped[x][UB] = 1; + eofb_flipped[x][DF] = 1; + eofb_flipped[x][DB] = 1; + + eofb_flipped[y][FR] = 1; + eofb_flipped[y][FL] = 1; + eofb_flipped[y][BL] = 1; + eofb_flipped[y][BR] = 1; + + eorl_flipped[x][UF] = 1; + eorl_flipped[x][UL] = 1; + eorl_flipped[x][UB] = 1; + eorl_flipped[x][UR] = 1; + eorl_flipped[x][DF] = 1; + eorl_flipped[x][DL] = 1; + eorl_flipped[x][DB] = 1; + eorl_flipped[x][DR] = 1; + eorl_flipped[x][FR] = 1; + eorl_flipped[x][FL] = 1; + eorl_flipped[x][BL] = 1; + eorl_flipped[x][BR] = 1; + + eorl_flipped[y][FR] = 1; + eorl_flipped[y][FL] = 1; + eorl_flipped[y][BL] = 1; + eorl_flipped[y][BR] = 1; + + eoud_flipped[U][UF] = 1; + eoud_flipped[U][UL] = 1; + eoud_flipped[U][UB] = 1; + eoud_flipped[U][UR] = 1; + + eoud_flipped[x][UF] = 1; + eoud_flipped[x][UB] = 1; + eoud_flipped[x][DF] = 1; + eoud_flipped[x][DB] = 1; + + eoud_flipped[y][UF] = 1; + eoud_flipped[y][UL] = 1; + eoud_flipped[y][UB] = 1; + eoud_flipped[y][UR] = 1; + eoud_flipped[y][DF] = 1; + eoud_flipped[y][DL] = 1; + eoud_flipped[y][DB] = 1; + eoud_flipped[y][DR] = 1; + eoud_flipped[y][FR] = 1; + eoud_flipped[y][FL] = 1; + eoud_flipped[y][BL] = 1; + eoud_flipped[y][BR] = 1; + + coud_flipped[x][UFR] = 2; + coud_flipped[x][UFL] = 1; + coud_flipped[x][UBR] = 1; + coud_flipped[x][UBL] = 2; + coud_flipped[x][DFR] = 1; + coud_flipped[x][DFL] = 2; + coud_flipped[x][DBR] = 2; + coud_flipped[x][DBL] = 1; + + corl_flipped[U][UFR] = 1; + corl_flipped[U][UFL] = 2; + corl_flipped[U][UBL] = 1; + corl_flipped[U][UBR] = 2; + + corl_flipped[y][UFR] = 1; + corl_flipped[y][UFL] = 2; + corl_flipped[y][UBL] = 1; + corl_flipped[y][UBR] = 2; + corl_flipped[y][DFR] = 2; + corl_flipped[y][DFL] = 1; + corl_flipped[y][DBL] = 2; + corl_flipped[y][DBR] = 1; + + cofb_flipped[U][UFR] = 2; + cofb_flipped[U][UFL] = 1; + cofb_flipped[U][UBL] = 2; + cofb_flipped[U][UBR] = 1; + + cofb_flipped[x][UFR] = 1; + cofb_flipped[x][UFL] = 2; + cofb_flipped[x][UBL] = 1; + cofb_flipped[x][UBR] = 2; + cofb_flipped[x][DFR] = 2; + cofb_flipped[x][DFL] = 1; + cofb_flipped[x][DBL] = 2; + cofb_flipped[x][DBR] = 1; + + cofb_flipped[y][UFR] = 2; + cofb_flipped[y][UFL] = 1; + cofb_flipped[y][UBL] = 2; + cofb_flipped[y][UBR] = 1; + cofb_flipped[y][DFR] = 1; + cofb_flipped[y][DFL] = 2; + cofb_flipped[y][DBL] = 1; + cofb_flipped[y][DBR] = 2; + + /* Equivalent moves ***********/ + equiv_alg[NULLMOVE] = new_alg(""); + + equiv_alg[U] = new_alg(" U "); + equiv_alg[U2] = new_alg(" UU "); + equiv_alg[U3] = new_alg(" UUU "); + equiv_alg[D] = new_alg(" xx U xx "); + equiv_alg[D2] = new_alg(" xx UU xx "); + equiv_alg[D3] = new_alg(" xx UUU xx "); + equiv_alg[R] = new_alg(" yx U xxxyyy "); + equiv_alg[R2] = new_alg(" yx UU xxxyyy "); + equiv_alg[R3] = new_alg(" yx UUU xxxyyy "); + equiv_alg[L] = new_alg(" yyyx U xxxy "); + equiv_alg[L2] = new_alg(" yyyx UU xxxy "); + equiv_alg[L3] = new_alg(" yyyx UUU xxxy "); + equiv_alg[F] = new_alg(" x U xxx "); + equiv_alg[F2] = new_alg(" x UU xxx "); + equiv_alg[F3] = new_alg(" x UUU xxx "); + equiv_alg[B] = new_alg(" xxx U x "); + equiv_alg[B2] = new_alg(" xxx UU x "); + equiv_alg[B3] = new_alg(" xxx UUU x "); + + equiv_alg[Uw] = new_alg(" xx U xx y "); + equiv_alg[Uw2] = new_alg(" xx UU xx yy "); + equiv_alg[Uw3] = new_alg(" xx UUU xx yyy "); + equiv_alg[Dw] = new_alg(" U yyy "); + equiv_alg[Dw2] = new_alg(" UU yy "); + equiv_alg[Dw3] = new_alg(" UUU y "); + equiv_alg[Rw] = new_alg(" yyyx U xxxy x "); + equiv_alg[Rw2] = new_alg(" yyyx UU xxxy xx "); + equiv_alg[Rw3] = new_alg(" yyyx UUU xxxy xxx "); + equiv_alg[Lw] = new_alg(" yx U xxxyyy xxx "); + equiv_alg[Lw2] = new_alg(" yx UU xxxyyy xx "); + equiv_alg[Lw3] = new_alg(" yx UUU xxxyyy x "); + equiv_alg[Fw] = new_alg(" xxx U x yxxxyyy "); + equiv_alg[Fw2] = new_alg(" xxx UU x yxxyyy "); + equiv_alg[Fw3] = new_alg(" xxx UUU x yxyyy "); + equiv_alg[Bw] = new_alg(" x U xxx yxyyy "); + equiv_alg[Bw2] = new_alg(" x UU xxx yxxyyy "); + equiv_alg[Bw3] = new_alg(" x UUU xxx yxxxyyy "); + + equiv_alg[M] = new_alg(" yx U xx UUU yxyyy "); + equiv_alg[M2] = new_alg(" yx UU xx UU xxxy "); + equiv_alg[M3] = new_alg(" yx UUU xx U yxxxy "); + equiv_alg[S] = new_alg(" x UUU xx U yyyx "); + equiv_alg[S2] = new_alg(" x UU xx UU yyx "); + equiv_alg[S3] = new_alg(" x U xx UUU yx "); + equiv_alg[E] = new_alg(" U xx UUU xxyyy "); + equiv_alg[E2] = new_alg(" UU xx UU xxyy "); + equiv_alg[E3] = new_alg(" UUU xx U xxy "); + + equiv_alg[x] = new_alg(" x "); + equiv_alg[x2] = new_alg(" xx "); + equiv_alg[x3] = new_alg(" xxx "); + equiv_alg[y] = new_alg(" y "); + equiv_alg[y2] = new_alg(" yy "); + equiv_alg[y3] = new_alg(" yyy "); + equiv_alg[z] = new_alg(" yyy x y "); + equiv_alg[z2] = new_alg(" yy xx "); + equiv_alg[z3] = new_alg(" y x yyy "); +} + +static void +init_strings() +{ + strcpy(move_string [NULLMOVE], "-" ); + strcpy(move_string [U], "U" ); + strcpy(move_string [U2], "U2" ); + strcpy(move_string [U3], "U\'" ); + strcpy(move_string [D], "D" ); + strcpy(move_string [D2], "D2" ); + strcpy(move_string [D3], "D\'" ); + strcpy(move_string [R], "R" ); + strcpy(move_string [R2], "R2" ); + strcpy(move_string [R3], "R\'" ); + strcpy(move_string [L], "L" ); + strcpy(move_string [L2], "L2" ); + strcpy(move_string [L3], "L\'" ); + strcpy(move_string [F], "F" ); + strcpy(move_string [F2], "F2" ); + strcpy(move_string [F3], "F\'" ); + strcpy(move_string [B], "B" ); + strcpy(move_string [B2], "B2" ); + strcpy(move_string [B3], "B\'" ); + strcpy(move_string [Uw], "Uw" ); + strcpy(move_string [Uw2], "Uw2" ); + strcpy(move_string [Uw3], "Uw\'" ); + strcpy(move_string [Dw], "Dw" ); + strcpy(move_string [Dw2], "Dw2" ); + strcpy(move_string [Dw3], "Dw\'" ); + strcpy(move_string [Rw], "Rw" ); + strcpy(move_string [Rw2], "Rw2" ); + strcpy(move_string [Rw3], "Rw\'" ); + strcpy(move_string [Lw], "Lw" ); + strcpy(move_string [Lw2], "Lw2" ); + strcpy(move_string [Lw3], "Lw\'" ); + strcpy(move_string [Fw], "Fw" ); + strcpy(move_string [Fw2], "Fw2" ); + strcpy(move_string [Fw3], "Fw\'" ); + strcpy(move_string [Bw], "Bw" ); + strcpy(move_string [Bw2], "Bw2" ); + strcpy(move_string [Bw3], "Bw\'" ); + strcpy(move_string [M], "M" ); + strcpy(move_string [M2], "M2" ); + strcpy(move_string [M3], "M\'" ); + strcpy(move_string [S], "S" ); + strcpy(move_string [S2], "S2" ); + strcpy(move_string [S3], "S\'" ); + strcpy(move_string [E], "E" ); + strcpy(move_string [E2], "E2" ); + strcpy(move_string [E3], "E\'" ); + strcpy(move_string [x], "x" ); + strcpy(move_string [x2], "x2" ); + strcpy(move_string [x3], "x\'" ); + strcpy(move_string [y], "y" ); + strcpy(move_string [y2], "y2" ); + strcpy(move_string [y3], "y\'" ); + strcpy(move_string [z], "z" ); + strcpy(move_string [z2], "z2" ); + strcpy(move_string [z3], "z\'" ); + + strcpy(edge_string [UF], "UF" ); + strcpy(edge_string [UL], "UL" ); + strcpy(edge_string [UB], "UB" ); + strcpy(edge_string [UR], "UR" ); + strcpy(edge_string [DF], "DF" ); + strcpy(edge_string [DL], "DL" ); + strcpy(edge_string [DB], "DB" ); + strcpy(edge_string [DR], "DR" ); + strcpy(edge_string [FR], "FR" ); + strcpy(edge_string [FL], "FL" ); + strcpy(edge_string [BL], "BL" ); + strcpy(edge_string [BR], "BR" ); + + strcpy(corner_string [UFR], "UFR" ); + strcpy(corner_string [UFL], "UFL" ); + strcpy(corner_string [UBL], "UBL" ); + strcpy(corner_string [UBR], "UBR" ); + strcpy(corner_string [DFR], "DFR" ); + strcpy(corner_string [DFL], "DFL" ); + strcpy(corner_string [DBL], "DBL" ); + strcpy(corner_string [DBR], "DBR" ); + + strcpy(center_string [U_center], "U" ); + strcpy(center_string [D_center], "D" ); + strcpy(center_string [R_center], "R" ); + strcpy(center_string [L_center], "L" ); + strcpy(center_string [F_center], "F" ); + strcpy(center_string [B_center], "B" ); +} + +static void +init_symdata() +{ + int i; + + for (i = 0; i < n_all_symdata; i++) + gensym(all_sd[i]); +} + +static void +init_trans() { + Cube aux, cube, mirr, c[3]; + CubeArray epcp; + int i, eparr[12], eoarr[12], cparr[8], coarr[8]; + unsigned int ui; + Move mi, move; + Trans m; + + /* Compute sources */ + for (i = 0; i < NTRANS; i++) { + cube = apply_alg(rotation_algs[i % NROTATIONS], (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; + } + + if (read_ttables_file()) + return; + + fprintf(stderr, "Cannot load %s, generating it\n", "ttables"); + + /* Initialize tables */ + for (m = 0; m < NTRANS; m++) { + epcp = (CubeArray){ .ep = eparr, .cp = cparr }; + cube = apply_alg(rotation_algs[m % NROTATIONS], (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++) { + aux = apply_trans(m, apply_move(mi, (Cube){0})); + for (move = 0; move < NMOVES; move++) { + cube = apply_move(inverse_move_aux[move], aux); + mirr = apply_trans(uf_mirror, cube); + if (is_solved(cube, false) || + is_solved(mirr, false)) + moves_ttable[m][mi] = move; + } + } + } + + if (!write_ttables_file()) + fprintf(stderr, "Error writing ttables\n"); +} + +static void +init_trans_aux() +{ + ep_mirror[UF] = UF; + ep_mirror[UL] = UR; + ep_mirror[UB] = UB; + ep_mirror[UR] = UL; + ep_mirror[DF] = DF; + ep_mirror[DL] = DR; + ep_mirror[DB] = DB; + ep_mirror[DR] = DL; + ep_mirror[FR] = FL; + ep_mirror[FL] = FR; + ep_mirror[BR] = BL; + ep_mirror[BL] = BR; + + cp_mirror[UFR] = UFL; + cp_mirror[UFL] = UFR; + cp_mirror[UBL] = UBR; + cp_mirror[UBR] = UBL; + cp_mirror[DFR] = DFL; + cp_mirror[DFL] = DFR; + cp_mirror[DBL] = DBR; + cp_mirror[DBR] = DBL; + + cpos_mirror[U_center] = U_center; + cpos_mirror[D_center] = D_center; + cpos_mirror[R_center] = L_center; + cpos_mirror[L_center] = R_center; + cpos_mirror[F_center] = F_center; + cpos_mirror[B_center] = B_center; + + /* Is there a more elegant way? */ + rotation_algs[uf] = new_alg(""); + rotation_algs[ur] = new_alg("y"); + rotation_algs[ub] = new_alg("y2"); + rotation_algs[ul] = new_alg("y3"); + + rotation_algs[df] = new_alg("z2"); + rotation_algs[dr] = new_alg("y z2"); + rotation_algs[db] = new_alg("x2"); + rotation_algs[dl] = new_alg("y3 z2"); + + rotation_algs[rf] = new_alg("z3"); + rotation_algs[rd] = new_alg("z3 y"); + rotation_algs[rb] = new_alg("z3 y2"); + rotation_algs[ru] = new_alg("z3 y3"); + + rotation_algs[lf] = new_alg("z"); + rotation_algs[ld] = new_alg("z y3"); + rotation_algs[lb] = new_alg("z y2"); + rotation_algs[lu] = new_alg("z y"); + + rotation_algs[fu] = new_alg("x y2"); + rotation_algs[fr] = new_alg("x y"); + rotation_algs[fd] = new_alg("x"); + rotation_algs[fl] = new_alg("x y3"); + + rotation_algs[bu] = new_alg("x3"); + rotation_algs[br] = new_alg("x3 y"); + rotation_algs[bd] = new_alg("x3 y2"); + rotation_algs[bl] = new_alg("x3 y3"); +} + + +/* Public functions implementation *******************************************/ + +Cube +apply_alg(Alg *alg, Cube cube) +{ + return apply_alg_generic(alg, cube, pf_all, true); +} + +Cube +apply_move(Move m, Cube cube) +{ + 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] + }; +} + + +Cube +apply_trans(Trans t, Cube cube) +{ + 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] + }; +} + +Move +base_move(Move m) +{ + if (m == NULLMOVE) + return NULLMOVE; + else + return m - (m-1)%3; +} + +Cube +compose(Cube c2, Cube c1) +{ + return compose_filtered(c2, c1, pf_all); +} + +/*TODO maybe move the next two */ +uint64_t +cphtr(Cube cube) +{ + return cphtr_right_cosets[cube.cp]; +} + +Cube +anti_cphtr(uint64_t ind) +{ + return (Cube) { .cp = cphtr_right_rep[ind] }; +} + +uint64_t +epos_dependent(Cube c) +{ + return epos_dependent_aux[c.eposs/FACTORIAL4][c.epose/FACTORIAL4]; +} + +bool +equal(Cube c1, Cube c2) +{ + 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; +} + +void +genptable(PruneData *pd) +{ + Cube cube; + uint64_t j, oldn = 0; + DfsData dd = { + .m = 0, + .last1 = NULLMOVE, + .last2 = NULLMOVE + }; + + if (pd->generated) + return; + + /* TODO: check if memory is enough, otherwise maybe crash gracefully? */ + pd->ptable = malloc(ptablesize(pd) * sizeof(uint8_t)); + + if (read_ptable_file(pd)) { + pd->generated = true; + return; + } + + fprintf(stderr, "Cannot load %s, generating it\n", pd->filename); + + /* We use 4 bits per value, so any distance >= 15 is set to 15 */ + for (j = 0; j < pd->coord->max; j++) + ptable_update(pd, pd->coord->cube(j), 15); + + moveset_to_list(pd->moveset, NULL, dd.sorted_moves); + movelist_to_position(dd.sorted_moves, dd.move_position); + + for (dd.d = 0, pd->n = 0; dd.d < 15 && pd->n < pd->coord->max; dd.d++) { + for (j = 0; j < pd->coord->max; j++) { + cube = pd->coord->cube(j); + if (pd->coord->check(cube)) + genptable_dfs(cube, pd, &dd); + } + fprintf(stderr, "Depth %d done, generated %lu\t(%lu/%lu)\n", + dd.d, pd->n-oldn, pd->n, pd->coord->max); + oldn = pd->n; + } + + if (!write_ptable_file(pd)) + fprintf(stderr, "Error writing ptable file\n"); + + pd->generated = true; +} + +Cube +inverse_cube(Cube cube) +{ + CubeArray *arr = new_cubearray(cube, pf_all); + CubeArray *inv = new_cubearray((Cube){0}, pf_all); + Cube ret; + int i; + + for (i = 0; i < 12; i++) { + inv->ep[arr->ep[i]] = i; + inv->eofb[arr->ep[i]] = arr->eofb[i]; + inv->eorl[arr->ep[i]] = arr->eorl[i]; + inv->eoud[arr->ep[i]] = arr->eoud[i]; + } + + for (i = 0; i < 8; i++) { + inv->cp[arr->cp[i]] = i; + inv->coud[arr->cp[i]] = (3 - arr->coud[i]) % 3; + inv->corl[arr->cp[i]] = (3 - arr->corl[i]) % 3; + inv->cofb[arr->cp[i]] = (3 - arr->cofb[i]) % 3; + } + + for (int i = 0; i < 6; i++) + inv->cpos[arr->cpos[i]] = i; + + ret = arrays_to_cube(inv, pf_all); + free_cubearray(arr, pf_all); + free_cubearray(inv, pf_all); + + return ret; +} + +Move +inverse_move(Move m) +{ + return inverse_move_aux[m]; +} + +Trans +inverse_trans(Trans t) +{ + return inverse_trans_aux[t]; +} + +bool +is_admissible(Cube cube) +{ + /* TODO: this should check consistency of different orientations */ + /* TODO: check that centers are opposite and admissible */ + + CubeArray *a = new_cubearray(cube, pf_all); + int parity; + bool perm; + + 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); + + return perm && parity % 2 == 0; +} + +bool +is_solved(Cube cube, bool reorient) +{ + int i; + + if (reorient) { + for (i = 0; i < NROTATIONS; i++) + if (is_solved(apply_alg(rotation_algs[i], cube),false)) + return true; + return false; + } else { + return equal(cube, (Cube){0}); + } +} + +bool +is_solved_block(Cube cube, Block block) +{ + 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; + + return true; +} + +bool +is_solved_center(Cube cube, Center c) +{ + return what_center_at(cube, c) == c; +} + +bool +is_solved_corner(Cube cube, Corner c) +{ + return what_corner_at(cube, c) == c && + what_orientation_corner(cube.coud, c); +} + +bool +is_solved_edge(Cube cube, Edge e) +{ + return what_edge_at(cube, e) == e && + what_orientation_edge(cube.eofb, e); +} + +int +piece_orientation(Cube cube, int piece, char *orientation) +{ + 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) +{ +/* + CubeArray *arr = new_cubearray(cube, pf_all); + + for (int i = 0; i < 12; i++) + printf(" %s ", edge_string[arr->ep[i]]); + printf("\n"); + + for (int i = 0; i < 12; i++) + printf(" %c ", arr->eofb[i] + '0'); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf("%s ", corner_string[arr->cp[i]]); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf(" %c ", arr->coud[i] + '0'); + printf("\n"); + + for (int i = 0; i < 6; i++) + printf(" %s ", center_string[arr->cpos[i]]); + printf("\n"); + + free_cubearray(arr, pf_all); +*/ + + for (int i = 0; i < 12; i++) + printf(" %s ", edge_string[what_edge_at(cube, i)]); + printf("\n"); + + for (int i = 0; i < 12; i++) + printf(" %d ", what_orientation_edge(cube.eofb, i)); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf("%s ", corner_string[what_corner_at(cube, i)]); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf(" %d ", what_orientation_corner(cube.coud, i)); + printf("\n"); + + for (int i = 0; i < 6; i++) + printf(" %s ", center_string[what_center_at(cube, i)]); + printf("\n"); + +} + +Cube +random_cube() +{ + CubeArray *arr = new_cubearray((Cube){0}, pf_4val); + Cube ret; + int ep, cp, eo, co; + + ep = rand() % FACTORIAL12; + cp = rand() % FACTORIAL8; + eo = rand() % POW2TO11; + co = rand() % POW3TO7; + + index_to_perm(ep, 12, arr->ep); + index_to_perm(cp, 8, arr->cp); + int_to_sum_zero_array(eo, 2, 12, arr->eofb); + int_to_sum_zero_array(co, 3, 8, arr->coud); + + if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8)) + swap(&(arr->ep[0]), &(arr->ep[1])); + + ret = arrays_to_cube(arr, pf_4val); + free_cubearray(arr, pf_4val); + + return ret; +} + +/* TODO: clean pre_trans or put it back */ +AlgList * +solve(Cube cube, Step step, SolveOptions *opts) +{ + /*AlgListNode *node;*/ + AlgList *sols = new_alglist(); + /*Cube c = apply_trans(opts->pre_trans, cube);*/ + DfsData dd = { + .m = 0, + .niss = false, + .lb = -1, + .last1 = NULLMOVE, + .last2 = NULLMOVE, + .sols = sols, + .current_alg = new_alg("") + }; + + if (step.ready != NULL && !step.ready(cube)) { + fprintf(stderr, "Cube not ready for solving step\n"); + return sols; + } + + moveset_to_list(step.moveset, step.estimate, dd.sorted_moves); + movelist_to_position(dd.sorted_moves, dd.move_position); + + for (dd.d = opts->min_moves; + dd.d <= opts->max_moves && !(sols->len && opts->optimal_only); + dd.d++) { + if (opts->feedback) + fprintf(stderr, + "Found %d solutions, searching depth %d...\n", + sols->len, dd.d); + dfs(cube, step, opts, &dd); + } + +/* + for (node = sols->first; node != NULL; node = node->next) + transform_alg(inverse_trans(opts->pre_trans), node->alg); +*/ + + free_alg(dd.current_alg); + return sols; +} + +Alg * +inverse_alg(Alg *alg) +{ + Alg *ret = new_alg(""); + int i; + + for (i = alg->len-1; i >= 0; i--) + append_move(ret, inverse_move(alg->move[i]), alg->inv[i]); + + return ret; +} + +Alg * +new_alg(char *str) +{ + Alg *alg = malloc(sizeof(Alg)); + int i; + bool niss = false; + Move j, m; + + alg->move = malloc(30 * sizeof(Move)); + alg->inv = malloc(30 * sizeof(bool)); + alg->allocated = 30; + alg->len = 0; + + for (i = 0; str[i]; i++) { + if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n') + continue; + + if (str[i] == '(' && niss) { + fprintf(stderr, "Error reading moves: nested ( )\n"); + return alg; + } + + if (str[i] == ')' && !niss) { + fprintf(stderr, "Error reading moves: unmatched )\n"); + return alg; + } + + if (str[i] == '(' || str[i] == ')') { + niss = !niss; + continue; + } + + for (j = 0; j < NMOVES; j++) { + if (str[i] == move_string[j][0]) { + m = j; + if (m <= B && str[i+1]=='w') { + m += Uw - U; + i++; + } + if (str[i+1]=='2') { + m += 1; + i++; + } else if (str[i+1]=='\'' || str[i+1]=='3') { + m += 2; + i++; + } + append_move(alg, m, niss); + break; + } + } + } + + return alg; +} + +Alg * +on_inverse(Alg *alg) +{ + Alg *ret = new_alg(""); + int i; + + for (i = 0; i < alg->len; i++) + append_move(ret, alg->move[i], !alg->inv[i]); + + return ret; +} + +void +print_alg(Alg *alg, bool l) +{ + /* TODO: make it possible to print to stdout or to string */ + /* Maybe just return a string */ + char fill[4]; + int i; + bool niss = false; + + for (i = 0; i < alg->len; i++) { + if (!niss && alg->inv[i]) + strcpy(fill, i == 0 ? "(" : " ("); + if (niss && !alg->inv[i]) + strcpy(fill, ") "); + if (niss == alg->inv[i]) + strcpy(fill, i == 0 ? "" : " "); + + printf("%s%s", fill, move_string[alg->move[i]]); + niss = alg->inv[i]; + } + + if (niss) + printf(")"); + if (l) + printf(" (%d)", alg->len); + + printf("\n"); +} + +void +print_alglist(AlgList *al, bool l) +{ + AlgListNode *i; + + for (i = al->first; i != NULL; i = i->next) + print_alg(i->alg, l); +} + +void +print_ptable(PruneData *pd) +{ + uint64_t i, a[16]; + + for (i = 0; i < 16; i++) + a[i] = 0; + + if (!pd->generated) + genptable(pd); + + for (i = 0; i < pd->coord->max; i++) + a[ptableval(pd, pd->coord->cube(i))]++; + + fprintf(stderr, "Values for table %s\n", pd->filename); + for (i = 0; i < 16; i++) + printf("%2lu\t%10lu\n", i, a[i]); +} + +uint64_t +ptablesize(PruneData *pd) +{ + return (pd->coord->max + 1) / 2; +} + +int +ptableval(PruneData *pd, Cube cube) +{ + uint64_t ind = pd->coord->index(cube); + + return (ind % 2) ? pd->ptable[ind/2] / 16 : pd->ptable[ind/2] % 16; +} + + +Alg * +rotation_alg(Trans i) +{ + return rotation_algs[i % NROTATIONS]; +} + +void +transform_alg(Trans t, Alg *alg) +{ + int i; + + for (i = 0; i < alg->len; i++) + alg->move[i] = moves_ttable[t][alg->move[i]]; +} + +Center +what_center_at(Cube cube, Center c) +{ + return what_center_at_aux[cube.cpos][c]; +} + +Corner +what_corner_at(Cube cube, Corner c) +{ + return what_corner_at_aux[cube.cp][c]; +} + +Edge +what_edge_at(Cube cube, Edge e) +{ + Edge ret; + CubeArray *arr = new_cubearray(cube, pf_ep); + + ret = arr->ep[e]; + + free_cubearray(arr, pf_ep); + return ret; +} + +int +what_orientation_corner(int co, Corner c) +{ + if (c < 7) + return (co / powint(3, c)) % 3; + else + return what_orientation_last_corner_aux[co]; +} + +int +what_orientation_edge(int eo, Edge e) +{ + if (e < 11) + return (eo & (1 << e)) ? 1 : 0; + else + return what_orientation_last_edge_aux[eo]; +} + +Center +where_is_center(Cube cube, Center c) +{ + return where_is_center_aux[cube.cpos][c]; +} + +Corner +where_is_corner(Cube cube, Corner c) +{ + return where_is_corner_aux[cube.cp][c]; +} + + +void +init() +{ + /* Order is important! */ + init_environment(); + init_strings(); + init_moves_aux(); + init_moves(); + init_auxtables(); + init_cphtr_cosets(); + init_trans_aux(); + init_trans(); + init_symdata(); +} + diff --git a/old/2021-06-30-noreached/cube.h b/old/2021-06-30-noreached/cube.h new file mode 100644 index 0000000..ffbcd86 --- /dev/null +++ b/old/2021-06-30-noreached/cube.h @@ -0,0 +1,90 @@ +#ifndef CUBE_H +#define CUBE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "macros.h" +#include "cubetypes.h" + +extern Coordinate coord_eofb; +extern Coordinate coord_eofbepos; +extern Coordinate coord_coud; +extern Coordinate coord_corners; +extern Coordinate coord_cornershtr; +extern Coordinate coord_drud; +extern Coordinate coord_coud_sym16; +extern Coordinate coord_eofbepos_sym16; +extern Coordinate coord_drud_sym16; +extern Coordinate coord_khuge; + +Cube apply_alg(Alg *alg, Cube cube); +Cube apply_move(Move m, Cube cube); +Cube apply_trans(Trans t, Cube cube); +bool block_solved(Cube cube, Block); +Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */ +uint64_t cphtr(Cube cube); /* TODO: rename (something with cosets) */ +Cube anti_cphtr(uint64_t ind); /*TODO also this */ +uint64_t epos_dependent(Cube cube); /* TODO: rename and turn into an indexer */ +bool equal(Cube c1, Cube c2); +Cube inverse_cube(Cube cube); +Move inverse_move(Move m); +Trans inverse_trans(Trans t); +bool is_admissible(Cube cube); +bool is_solved(Cube cube, bool reorient); +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 print_cube(Cube cube); +Cube random_cube(); +AlgList * solve(Cube cube, Step step, SolveOptions *opts); +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); + +bool check_centers(Cube cube); +bool check_corners(Cube cube); +bool check_cornershtr(Cube cube); +bool check_coud(Cube cube); +bool check_drud(Cube cube); +bool check_eofb(Cube cube); +bool check_eofbepos(Cube cube); +bool check_epose(Cube cube); +bool check_ep(Cube cube); +bool check_khuge(Cube cube); +bool check_nothing(Cube cube); + +bool moveset_HTM(Move m); +bool moveset_URF(Move m); + +Move base_move(Move m); +void free_alg(Alg *alg); +void free_alglist(AlgList *l); +Alg * inverse_alg(Alg *alg); +Alg * new_alg(char *str); +Alg * on_inverse(Alg *alg); +void print_alg(Alg *alg, bool l); +void print_alglist(AlgList *al, bool l); +Alg * rotation_alg(Trans i); +void transform_alg(Trans t, Alg *alg); + +void genptable(PruneData *pd); +void print_ptable(PruneData *pd); +uint64_t ptablesize(PruneData *pd); +int ptableval(PruneData *pd, Cube cube); + +void init(); + +#endif + diff --git a/old/2021-06-30-noreached/cubetypes.h b/old/2021-06-30-noreached/cubetypes.h new file mode 100644 index 0000000..a324985 --- /dev/null +++ b/old/2021-06-30-noreached/cubetypes.h @@ -0,0 +1,250 @@ +#ifndef CUBETYPES_H +#define CUBETYPES_H + +/* Typedefs ******************************************************************/ + +typedef enum center Center; +typedef enum corner Corner; +typedef enum edge Edge; +typedef enum move Move; +typedef enum trans Trans; + +typedef struct alg Alg; +typedef struct alglist AlgList; +typedef struct alglistnode AlgListNode; +typedef struct block Block; +typedef struct coordinate Coordinate; +typedef struct cube Cube; +typedef struct cubearray CubeArray; +typedef struct cubetarget CubeTarget; +typedef struct dfsdata DfsData; +typedef struct piecefilter PieceFilter; +typedef struct prunedata PruneData; +typedef struct solveoptions SolveOptions; +typedef struct step Step; +typedef struct symdata SymData; + +typedef Cube (*AntiIndexer) (uint64_t); +typedef bool (*Checker) (Cube); +typedef int (*Estimator) (CubeTarget); +typedef uint64_t (*Indexer) (Cube); +typedef bool (*Moveset) (Move); + + +/* Enums *********************************************************************/ + +enum +center +{ + U_center, D_center, + R_center, L_center, + F_center, B_center +}; + +enum +corner +{ + UFR, UFL, UBL, UBR, + DFR, DFL, DBL, DBR +}; + +enum +edge +{ + UF, UL, UB, UR, + DF, DL, DB, DR, + FR, FL, BL, BR +}; + +enum +move +{ + NULLMOVE, + U, U2, U3, D, D2, D3, + R, R2, R3, L, L2, L3, + F, F2, F3, B, B2, B3, + Uw, Uw2, Uw3, Dw, Dw2, Dw3, + Rw, Rw2, Rw3, Lw, Lw2, Lw3, + Fw, Fw2, Fw3, Bw, Bw2, Bw3, + M, M2, M3, + S, S2, S3, + E, E2, E3, + x, x2, x3, + y, y2, y3, + z, z2, z3, +}; + +enum +trans +{ + uf, ur, ub, ul, + df, dr, db, dl, + rf, rd, rb, ru, + lf, ld, lb, lu, + fu, fr, fd, fl, + bu, br, bd, bl, + uf_mirror, ur_mirror, ub_mirror, ul_mirror, + df_mirror, dr_mirror, db_mirror, dl_mirror, + rf_mirror, rd_mirror, rb_mirror, ru_mirror, + lf_mirror, ld_mirror, lb_mirror, lu_mirror, + fu_mirror, fr_mirror, fd_mirror, fl_mirror, + bu_mirror, br_mirror, bd_mirror, bl_mirror, +}; + + +/* Structs *******************************************************************/ + +struct +alg +{ + Move * move; + bool * inv; + int len; + int allocated; +}; + +struct +alglist +{ + AlgListNode * first; + AlgListNode * last; + int len; +}; + +struct +alglistnode +{ + Alg * alg; + AlgListNode * next; +}; + +struct +block +{ + bool edge[12]; + bool corner[8]; + bool center[6]; +}; + +struct +coordinate +{ + Indexer index; + AntiIndexer cube; + Checker check; + uint64_t max; +}; + +struct +cube +{ + int epose; + int eposs; + int eposm; + int eofb; + int eorl; + int eoud; + int cp; + int coud; + int cofb; + int corl; + int cpos; +}; + +struct +cubearray +{ + int * ep; + int * eofb; + int * eorl; + int * eoud; + int * cp; + int * coud; + int * corl; + int * cofb; + int * cpos; +}; + +struct +cubetarget +{ + Cube cube; + int target; +}; + +struct +dfsdata +{ + int d; + int m; + int lb; + bool niss; + Move last1; + Move last2; + AlgList * sols; + Alg * current_alg; + Move sorted_moves[NMOVES]; + int move_position[NMOVES]; +}; + +struct +piecefilter +{ + 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; + uint8_t * ptable; + bool generated; + uint64_t n; + Coordinate * coord; + Moveset moveset; +}; + +struct +solveoptions +{ + int min_moves; + int max_moves; + int max_solutions; + bool optimal_only; + bool can_niss; + bool feedback; +}; + +struct +step +{ + Estimator estimate; + Checker ready; + Moveset moveset; +}; + +struct +symdata +{ + char * filename; + bool generated; + Coordinate * coord; + Coordinate * sym_coord; + int ntrans; + Trans * trans; + uint64_t * class; + Cube * rep; + Trans * transtorep; +}; + +#endif diff --git a/old/2021-06-30-noreached/macros.h b/old/2021-06-30-noreached/macros.h new file mode 100644 index 0000000..af3bca1 --- /dev/null +++ b/old/2021-06-30-noreached/macros.h @@ -0,0 +1,23 @@ +#ifndef MACROS_H +#define MACROS_H + +#define POW2TO6 64ULL +#define POW2TO11 2048ULL +#define POW2TO12 4096ULL +#define POW3TO7 2187ULL +#define POW3TO8 6561ULL +#define FACTORIAL4 24ULL +#define FACTORIAL6 720ULL +#define FACTORIAL7 5040ULL +#define FACTORIAL8 40320ULL +#define FACTORIAL12 479001600ULL +#define BINOM12ON4 495ULL +#define BINOM8ON4 70ULL +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +#define NMOVES (z3+1) +#define NTRANS 48 +#define NROTATIONS 24 + +#endif diff --git a/old/2021-06-30-noreached/main.c b/old/2021-06-30-noreached/main.c new file mode 100644 index 0000000..1ebd917 --- /dev/null +++ b/old/2021-06-30-noreached/main.c @@ -0,0 +1,80 @@ +#include +#include "cube.h" +#include "steps.h" + +int main() { + Alg *algo; + AlgList *sols; + Cube cube; + SolveOptions opts; + char line[1000]; + int i, ns = 2; +/* Move m;*/ +/* int nrand = 10000, sum1, sum2, sum3;*/ + + Step *stps[20] = {&drud_HTM, &optimal_HTM}; + char sss[30][30] = {"DR on UD", "Optimal solve"}; + + opts = (SolveOptions) { + .min_moves = 0, + .max_moves = 20, + .optimal_only = true, + .max_solutions = 1, + .can_niss = false, + .feedback = true, + }; + + init(); + +/* + srand(time(NULL)); + sum1 = 0; + sum2 = 0; + sum3 = 0; + for (i = 0; i < nrand; i++) { + cube = random_cube(); + sum1 += drud_HTM.check(cube, 20); + sum2 += optimal_HTM.check(cube, 20); + sum3 += cornershtreofb_HTM.check(cube, 20); + } + printf("Average drud pruning: %lf\n", ((double)sum1) / ((double) nrand)); + printf("Average corners htr pruning: %lf\n", ((double)sum2) / ((double) nrand)); + printf("Average corners htr + eofb pruning: %lf\n", ((double)sum3) / ((double) nrand)); +*/ + +/* + for (m = U; m <= B3; m++) { + printf("Class eofbepos after %d: ", m); + printf("%lu\n", coord_khuge.index(apply_move(m,(Cube){0}))); + } +*/ + + printf("Welcome to nissy 2.0! Insert a scramble:\n"); + + if (fgets(line, 1000, stdin) != NULL) { + algo = new_alg(line); + cube = apply_alg(algo, (Cube){0}); + + print_alg(inverse_alg(algo), false); +/* + printf("After rb_mirror:\n"); + cube = apply_trans(rb_mirror, cube); + print_cube(cube); + printf("Going back:\n"); + cube = apply_trans(inverse_trans(rb_mirror), cube); +*/ + + print_cube(cube); + + for (i = 0; i < ns; i++) { + sols = solve(cube, *stps[i], &opts); + printf("%s: %d solutions found:\n", sss[i], sols->len); + print_alglist(sols, true); + free_alglist(sols); + } + free_alg(algo); + } + + return 0; +} + diff --git a/old/2021-06-30-noreached/steps.c b/old/2021-06-30-noreached/steps.c new file mode 100644 index 0000000..91e7f00 --- /dev/null +++ b/old/2021-06-30-noreached/steps.c @@ -0,0 +1,307 @@ +#include "steps.h" + +/* Standard checkers (return lower bound) ************************************/ + +static int estimate_eofb_HTM(CubeTarget ct); +static int estimate_coud_HTM(CubeTarget ct); +static int estimate_coud_URF(CubeTarget ct); +static int estimate_corners_HTM(CubeTarget ct); +static int estimate_cornershtr_HTM(CubeTarget ct); +static int estimate_corners_URF(CubeTarget ct); +static int estimate_cornershtr_URF(CubeTarget ct); +static int estimate_drud_HTM(CubeTarget ct); +static int estimate_optimal_HTM(CubeTarget ct); + +/* Steps *********************************************************************/ + +Step +eofb_HTM = { + .estimate = estimate_eofb_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + +Step +coud_HTM = { + .estimate = estimate_coud_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + +Step +coud_URF = { + .estimate = estimate_coud_URF, + .ready = check_nothing, + .moveset = moveset_URF +}; + +Step +corners_HTM = { + .estimate = estimate_corners_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + +Step +cornershtr_HTM = { + .estimate = estimate_cornershtr_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + +Step +cornershtr_URF = { + .estimate = estimate_cornershtr_URF, + .ready = check_nothing, + .moveset = moveset_URF +}; + +Step +corners_URF = { + .estimate = estimate_corners_URF, + .ready = check_nothing, + .moveset = moveset_URF +}; + +Step +drud_HTM = { + .estimate = estimate_drud_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + +Step +optimal_HTM = { + .estimate = estimate_optimal_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + + +/* Pruning tables ************************************************************/ + +PruneData +pd_eofb_HTM = { + .filename = "ptable_eofb_HTM", + .coord = &coord_eofb, + .moveset = moveset_HTM +}; + +PruneData +pd_coud_HTM = { + .filename = "ptable_coud_HTM", + .coord = &coord_coud, + .moveset = moveset_HTM +}; + +PruneData +pd_cornershtr_HTM = { + .filename = "ptable_cornershtr_withcosets_HTM", + .coord = &coord_cornershtr, + .moveset = moveset_HTM +}; + +PruneData +pd_corners_HTM = { + .filename = "ptable_corners_HTM", + .coord = &coord_corners, + .moveset = moveset_HTM +}; + +PruneData +pd_drud_HTM = { + .filename = "ptable_drud_HTM", + .coord = &coord_drud, + .moveset = moveset_HTM +}; + +PruneData +pd_drud_sym16_HTM = { + .filename = "ptable_drud_sym16_HTM", + .coord = &coord_drud_sym16, + .moveset = moveset_HTM, +}; + +PruneData +pd_khuge_HTM = { + .filename = "ptable_khuge_HTM", + .coord = &coord_khuge, + .moveset = moveset_HTM +}; + + +/* Standard checkers (return lower bound) ************************************/ + +static int +estimate_eofb_HTM(CubeTarget ct) +{ + if (!pd_eofb_HTM.generated) + genptable(&pd_eofb_HTM); + + return ptableval(&pd_eofb_HTM, ct.cube); +} + +static int +estimate_coud_HTM(CubeTarget ct) +{ + if (!pd_coud_HTM.generated) + genptable(&pd_coud_HTM); + + return ptableval(&pd_coud_HTM, ct.cube); +} + +static int +estimate_coud_URF(CubeTarget ct) +{ + /* TODO: I can improve this by checking first the orientation of + * the corner in DBL and use that as a reference */ + + CubeTarget ct2 = {.cube = apply_move(z, ct.cube), .target = ct.target}; + CubeTarget ct3 = {.cube = apply_move(x, ct.cube), .target = ct.target}; + + int ud = estimate_coud_HTM(ct); + int rl = estimate_coud_HTM(ct2); + int fb = estimate_coud_HTM(ct3); + + return MIN(ud, MIN(rl, fb)); +} + +static int +estimate_corners_HTM(CubeTarget ct) +{ + if (!pd_corners_HTM.generated) + genptable(&pd_corners_HTM); + + return ptableval(&pd_corners_HTM, ct.cube); +} + +static int +estimate_cornershtr_HTM(CubeTarget ct) +{ + if (!pd_cornershtr_HTM.generated) + genptable(&pd_cornershtr_HTM); + + return ptableval(&pd_cornershtr_HTM, ct.cube); +} + +static int +estimate_cornershtr_URF(CubeTarget ct) +{ + /* TODO: I can improve this by checking first the corner in DBL + * and use that as a reference */ + + int c, ret = 15; + Trans i; + + for (i = 0; i < NROTATIONS; i++) { + ct.cube = apply_alg(rotation_alg(i), ct.cube); + c = estimate_cornershtr_HTM(ct); + ret = MIN(ret, c); + } + + return ret; +} + +static int +estimate_corners_URF(CubeTarget ct) +{ + /* TODO: I can improve this by checking first the corner in DBL + * and use that as a reference */ + + int c, ret = 15; + Trans i; + + for (i = 0; i < NROTATIONS; i++) { + ct.cube = apply_alg(rotation_alg(i), ct.cube); + c = estimate_corners_HTM(ct); + ret = MIN(ret, c); + } + + return ret; +} + +static int +estimate_drud_HTM(CubeTarget ct) +{ +/* + if (!pd_drud_HTM.generated) + genptable(&pd_drud_HTM); + + return ptableval(&pd_drud_HTM, ct.cube); +*/ + + if (!pd_drud_sym16_HTM.generated) + genptable(&pd_drud_sym16_HTM); + + return ptableval(&pd_drud_sym16_HTM, ct.cube); +} + +/* TODO: if lucky, remove this */ +/* +static int +estimate_optimal_HTM(CubeTarget ct) +{ + static Trans t1 = { .rot = rf, .mirror = false }; + static Trans t2 = { .rot = bd, .mirror = false }; + int dr1, dr2, dr3, cor, ret; + Cube cube = ct.cube; + + dr1 = estimate_drud_HTM(ct); + cor = estimate_corners_HTM(ct); + ret = MAX(dr1, cor); + + if (ret > ct.target) + return ret; + + ct.cube = apply_trans(t1, cube); + dr2 = estimate_drud_HTM(ct); + ret = MAX(ret, dr2); + + if (ret > ct.target) + return ret; + + ct.cube = apply_trans(t2, cube); + dr3 = estimate_drud_HTM(ct); + + if (dr1 == dr2 && dr2 == dr3 && dr1 != 0) + dr3++; + + ret = MAX(ret, dr3); + + if (ret == 0) + return check_ep(cube) ? 0 : 6; + + return ret; +} +*/ + +static int +estimate_optimal_HTM(CubeTarget ct) +{ + static Trans t2 = rf, t3 = bd; + + int dr1, dr2, dr3, cor, ret; + Cube cube = ct.cube; + + if (!pd_khuge_HTM.generated) + genptable(&pd_khuge_HTM); + + dr1 = ptableval(&pd_khuge_HTM, cube); + cor = estimate_corners_HTM(ct); + ret = MAX(dr1, cor); + + if (ret > ct.target) + return ret; + + cube = apply_trans(t2, ct.cube); + dr2 = ptableval(&pd_khuge_HTM, cube); + ret = MAX(ret, dr2); + + if (ret > ct.target) + return ret; + + cube = apply_trans(t3, ct.cube); + dr3 = ptableval(&pd_khuge_HTM, cube); + + return MAX(ret, dr3); +} diff --git a/old/2021-06-30-noreached/steps.h b/old/2021-06-30-noreached/steps.h new file mode 100644 index 0000000..81ae11c --- /dev/null +++ b/old/2021-06-30-noreached/steps.h @@ -0,0 +1,24 @@ +#ifndef STEPS_H +#define STEPS_H + +#include "cube.h" + +extern Step eofb_HTM; +extern Step coud_HTM; +extern Step coud_URF; +extern Step corners_HTM; +extern Step cornershtr_HTM; +extern Step corners_URF; +extern Step cornershtr_URF; +extern Step drud_HTM; +extern Step optimal_HTM; + +extern PruneData pd_eofb_HTM; +extern PruneData pd_coud_HTM; +extern PruneData pd_corners_HTM; +extern PruneData pd_cornershtr_HTM; +extern PruneData pd_cornershtreofb_HTM; +extern PruneData pd_drud_HTM; +extern PruneData pd_khuge_HTM; + +#endif diff --git a/old/2021-06-30-reached/cube.c b/old/2021-06-30-reached/cube.c new file mode 100644 index 0000000..e490589 --- /dev/null +++ b/old/2021-06-30-reached/cube.c @@ -0,0 +1,3419 @@ +#include "cube.h" + +/* Local functions **********************************************************/ + +static Cube admissible_ep(Cube cube, PieceFilter f); +static Cube admissible_eos_from_eofbepos(Cube cube); +static bool allowed_next(Move move, DfsData *dd); +static void append_alg(AlgList *l, Alg *alg); +static void append_move(Alg *alg, Move m, bool inverse); +static Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a); +static void apply_permutation(int *perm, int *set, int n); +static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f); +static int array_ep_to_epos(int *ep, int *eps_solved); +static Cube arrays_to_cube(CubeArray *arr, PieceFilter f); +static int binomial(int n, int k); +static Cube compose_filtered(Cube c2, Cube c1, PieceFilter f); +static void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f); +static void dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static void dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static bool dfs_check_solved(SolveOptions *opts, DfsData *dd); +static void dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static bool dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static int digit_array_to_int(int *a, int n, int b); +static int edge_slice(Edge e); /* E=0, S=1, M=2 */ +static int epos_dependent_pos(int pos1, int pos2); +static int epos_from_arrays(int *epos, int *ep); +static void epos_to_partial_ep(int epos, int *ep, int *ss); +static int factorial(int n); +static void free_alglistnode(AlgListNode *aln); +static void free_cubearray(CubeArray *arr, PieceFilter f); +static void genptable_dfs(Cube c, PruneData *pd, DfsData *dd); +static void genptable_dfs_branch(Cube c, PruneData *pd, DfsData *dd); +static void gensym(SymData *sd); +static void index_to_perm(int p, int n, int *r); +static void index_to_subset(int s, int n, int k, int *r); +static void init_auxtables(); +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_environment(); +static void init_moves(); +static void init_moves_aux(); +static void init_strings(); +static void init_symdata(); +static void init_trans(); +static void init_trans_aux(); +static void int_to_digit_array(int a, int b, int n, int *r); +static void int_to_sum_zero_array(int x, int b, int n, int *a); +static int invert_digits(int a, int b, int n); +static bool is_perm(int *a, int n); +static bool is_subset(int *a, int n, int k); +static Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf); +static void movelist_to_position(Move *movelist, int *position); +static void moveset_to_list(Moveset ms, Estimator f, Move *r); +static AlgList * new_alglist(); +static CubeArray * new_cubearray(Cube cube, PieceFilter f); +static int perm_sign(int *a, int n); +static int perm_to_index(int *a, int n); +static int powint(int a, int b); +static bool ptable_has_reached(PruneData *pd, Cube cube); +static void ptable_set_reached(PruneData *pd, Cube cube); +static void ptable_update(PruneData *pd, Cube cube, int m); +static void realloc_alg(Alg *alg, int n); +static bool read_mtables_file(); +static bool read_ptable_file(PruneData *pd); +static bool read_symdata_file(SymData *sd); +static bool read_ttables_file(); +static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f); +static int subset_to_index(int *a, int n, int k); +static void sum_arrays_mod(int *src, int *dst, int n, int m); +static void swap(int *a, int *b); +static bool write_mtables_file(); +static bool write_ptable_file(PruneData *pd); +static bool write_symdata_file(SymData *sd); +static bool write_ttables_file(); + + +/* All sorts of useful costants and tables **********************************/ + +static char * tabledir; + +static PieceFilter pf_all; +static PieceFilter pf_4val; +static PieceFilter pf_epcp; +static PieceFilter pf_cpos; +static PieceFilter pf_cp; +static PieceFilter pf_ep; +static PieceFilter pf_e; +static PieceFilter pf_s; +static PieceFilter pf_m; +static PieceFilter pf_eo; +static PieceFilter pf_co; + +static int epe_solved[4]; +static int eps_solved[4]; +static int epm_solved[4]; + +static char move_string[NMOVES][7]; +static char edge_string[12][7]; +static char corner_string[8][7]; +static char center_string[6][7]; + +static Cube admissible_ee_aux[POW2TO11*BINOM12ON4]; +static bool commute[NMOVES][NMOVES]; +static bool possible_next[NMOVES][NMOVES][NMOVES]; +static Move inverse_move_aux[NMOVES]; +static Trans inverse_trans_aux[NTRANS]; +static int epos_dependent_aux[BINOM12ON4][BINOM12ON4]; +static int cphtr_left_cosets[FACTORIAL8]; +static int cphtr_right_cosets[FACTORIAL8]; +static int cphtr_right_rep[BINOM8ON4*6]; +static Center what_center_at_aux[FACTORIAL6][6]; +static Corner what_corner_at_aux[FACTORIAL8][8]; +static int what_orientation_last_corner_aux[POW3TO7]; +static int what_orientation_last_edge_aux[POW2TO11]; +static Center where_is_center_aux[FACTORIAL6][6]; +static Corner where_is_corner_aux[FACTORIAL8][8]; +static Edge where_is_edge_aux[3][FACTORIAL12/FACTORIAL8][12]; + +static int epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static int eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static int eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static int eo_ttable[NTRANS][POW2TO11]; +static int cp_ttable[NTRANS][FACTORIAL8]; +static int co_ttable[NTRANS][POW3TO7]; +static int cpos_ttable[NTRANS][FACTORIAL6]; +static Move moves_ttable[NTRANS][NMOVES]; + +static int epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static int eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static int eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static int eofb_mtable[NMOVES][POW2TO11]; +static int eorl_mtable[NMOVES][POW2TO11]; +static int eoud_mtable[NMOVES][POW2TO11]; +static int cp_mtable[NMOVES][FACTORIAL8]; +static int coud_mtable[NMOVES][POW3TO7]; +static int cofb_mtable[NMOVES][POW3TO7]; +static int corl_mtable[NMOVES][POW3TO7]; +static int cpos_mtable[NMOVES][FACTORIAL6]; + +static uint64_t me[12]; + +static int edge_cycle[NMOVES][12]; +static int corner_cycle[NMOVES][8]; +static int center_cycle[NMOVES][6]; +static int eofb_flipped[NMOVES][12]; +static int eorl_flipped[NMOVES][12]; +static int eoud_flipped[NMOVES][12]; +static int coud_flipped[NMOVES][8]; +static int corl_flipped[NMOVES][8]; +static int cofb_flipped[NMOVES][8]; +static Alg * equiv_alg[NMOVES]; + +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]; +static int ep_mirror[12]; +static int cp_mirror[8]; +static int cpos_mirror[6]; +static Alg * rotation_algs[NROTATIONS]; + + +/* Symmetry data for some coordinates ****************************************/ + +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, +}; + +SymData +sd_coud_16 = { + .filename = "sd_coud_16", + .coord = &coord_coud, + .sym_coord = &coord_coud_sym16, + .ntrans = 16, + .trans = trans_group_udfix +}; + +SymData +sd_eofbepos_16 = { + .filename = "sd_eofbepos_16", + .coord = &coord_eofbepos, + .sym_coord = &coord_eofbepos_sym16, + .ntrans = 16, + .trans = trans_group_udfix +}; + +static int n_all_symdata = 2; +static SymData * all_sd[2] = { &sd_coud_16, &sd_eofbepos_16 }; + +/* Coordinates and their implementation **************************************/ + +static uint64_t index_eofb(Cube cube); +static uint64_t index_eofbepos(Cube cube); +static uint64_t index_coud(Cube cube); +static uint64_t index_corners(Cube cube); +static uint64_t index_cornershtr(Cube cube); +static uint64_t index_drud(Cube cube); +static uint64_t index_coud_sym16(Cube cube); +static uint64_t index_eofbepos_sym16(Cube cube); +static uint64_t index_drud_sym16(Cube cube); +static uint64_t index_khuge(Cube cube); + +static Cube antindex_eofb(uint64_t ind); +static Cube antindex_eofbepos(uint64_t ind); +static Cube antindex_coud(uint64_t ind); +static Cube antindex_corners(uint64_t ind); +static Cube antindex_cornershtr(uint64_t ind); +static Cube antindex_drud(uint64_t ind); +static Cube antindex_coud_sym16(uint64_t ind); +static Cube antindex_eofbepos_sym16(uint64_t ind); +static Cube antindex_drud_sym16(uint64_t ind); +static Cube antindex_khuge(uint64_t ind); + +Coordinate +coord_eofb = { + .index = index_eofb, + .cube = antindex_eofb, + .check = check_eofb, + .max = POW2TO11 +}; + +Coordinate +coord_eofbepos = { + .index = index_eofbepos, + .cube = antindex_eofbepos, + .check = check_eofbepos, + .max = POW2TO11 * BINOM12ON4 +}; + +Coordinate +coord_coud = { + .index = index_coud, + .cube = antindex_coud, + .check = check_coud, + .max = POW3TO7 +}; + +Coordinate +coord_corners = { + .index = index_corners, + .cube = antindex_corners, + .check = check_corners, + .max = POW3TO7 * FACTORIAL8 +}; + +Coordinate +coord_cornershtr = { + .index = index_cornershtr, + .cube = antindex_cornershtr, + .check = check_cornershtr, + .max = POW3TO7 * BINOM8ON4 * 6 +}; + +Coordinate +coord_drud = { + .index = index_drud, + .cube = antindex_drud, + .check = check_drud, + .max = POW2TO11 * POW3TO7 * BINOM12ON4 +}; + +Coordinate +coord_eofbepos_sym16 = { + .index = index_eofbepos_sym16, + .cube = antindex_eofbepos_sym16, + .check = check_eofbepos, +}; + +Coordinate +coord_coud_sym16 = { + .index = index_coud_sym16, + .cube = antindex_coud_sym16, + .check = check_coud, +}; + +Coordinate +coord_drud_sym16 = { + .index = index_drud_sym16, + .cube = antindex_drud_sym16, + .check = check_drud, + .max = POW3TO7 * 64430 +}; + +Coordinate +coord_khuge = { + .index = index_khuge, + .cube = antindex_khuge, + .check = check_khuge, + .max = POW3TO7 * FACTORIAL4 * 64430 +}; + + +static uint64_t +index_eofb(Cube cube) +{ + return cube.eofb; +} + +static uint64_t +index_eofbepos(Cube cube) +{ + return (cube.epose / FACTORIAL4) * POW2TO11 + cube.eofb; +} + +static uint64_t +index_coud(Cube cube) +{ + return cube.coud; +} + +static uint64_t +index_corners(Cube cube) +{ + return cube.coud * FACTORIAL8 + cube.cp; +} + +static uint64_t +index_cornershtr(Cube cube) +{ + return cube.coud * BINOM8ON4 * 6 + cphtr(cube); +} + +static uint64_t +index_drud(Cube cube) +{ + uint64_t a, b, c; + + a = cube.eofb; + b = cube.coud; + c = cube.epose / FACTORIAL4; + + b *= POW2TO11; + c *= POW2TO11 * POW3TO7; + + return a + b + c; +} + +static uint64_t +index_coud_sym16(Cube cube) +{ + return sd_coud_16.class[index_coud(cube)]; +} + +static uint64_t +index_drud_sym16(Cube cube) +{ + Trans t; + Cube c; + + t = sd_eofbepos_16.transtorep[index_eofbepos(cube)]; + c = apply_trans(t, cube); + + return index_eofbepos_sym16(c) * POW3TO7 + c.coud; +} + +static uint64_t +index_eofbepos_sym16(Cube cube) +{ + return sd_eofbepos_16.class[index_eofbepos(cube)]; +} + +static uint64_t +index_khuge(Cube cube) +{ + Trans t; + Cube c; + uint64_t a; + + t = sd_eofbepos_16.transtorep[index_eofbepos(cube)]; + c = apply_trans(t, cube); + a = (index_eofbepos_sym16(c) * 24) + (c.epose % 24); + + return a * POW3TO7 + c.coud; +} + + +/* TODO: rename */ +static Cube +antindex_eofb(uint64_t ind) +{ + return (Cube){ .eofb = ind, .eorl = ind, .eoud = ind }; +} + +static Cube +antindex_eofbepos(uint64_t ind) +{ + return admissible_ee_aux[ind]; +} + +/* TODO: rename */ +static Cube +antindex_coud(uint64_t ind) +{ + return (Cube){ .coud = ind, .corl = ind, .cofb = ind }; +} + +/* TODO: admissible co for other orientations */ +static Cube +antindex_corners(uint64_t ind) +{ + Cube c = {0}; + + c.coud = ind / FACTORIAL8; + c.cp = ind % FACTORIAL8; + + return c; +} + +/* TODO: admissible co for other orientations */ +static Cube +antindex_cornershtr(uint64_t ind) +{ + Cube c = anti_cphtr(ind % (BINOM8ON4 * 6)); + + c.coud = ind / (BINOM8ON4 * 6); + + return c; +} + +/* TODO: admissible eos and cos */ +static Cube +antindex_drud(uint64_t ind) +{ + Cube c = {0}; + + c.eofb = ind % POW2TO11; + c.coud = (ind / POW2TO11) % POW3TO7; + c.epose = (ind % (POW2TO11 * POW3TO7)) * FACTORIAL4; + + return c; +} + +static Cube +antindex_coud_sym16(uint64_t ind) +{ + return sd_coud_16.rep[ind]; +} + +static Cube +antindex_eofbepos_sym16(uint64_t ind) +{ + return sd_eofbepos_16.rep[ind]; +} + +static Cube +antindex_drud_sym16(uint64_t ind) +{ + Cube c; + + c = sd_eofbepos_16.rep[ind/POW3TO7]; + c.coud = ind % POW3TO7; + c.cofb = c.coud; + c.corl = c.coud; + + return c; +} + +static Cube +antindex_khuge(uint64_t ind) +{ + Cube c; + + c = sd_eofbepos_16.rep[ind/(FACTORIAL4*POW3TO7)]; + c.epose = ((c.epose / 24) * 24) + ((ind/POW3TO7) % 24); + c.coud = ind % POW3TO7; + + return c; +} + + +/* Checkers ******************************************************************/ + +bool +check_centers(Cube cube) +{ + return cube.cpos == 0; +} + +bool +check_corners(Cube cube) +{ + return cube.cp == 0 && cube.coud == 0; +} + +bool +check_cornershtr(Cube cube) +{ + return cube.coud == 0 && cphtr(cube) == 0; /* TODO: use array cphtrcosets*/ +} + +bool +check_coud(Cube cube) +{ + return cube.coud == 0; +} + +bool +check_drud(Cube cube) +{ + return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0; +} + +bool +check_eofb(Cube cube) +{ + return cube.eofb == 0; +} + +bool +check_eofbepos(Cube cube) +{ + return cube.eofb == 0 && cube.epose / 24 == 0; +} + +bool +check_epose(Cube cube) +{ + return cube.epose == 0; +} + +bool +check_ep(Cube cube) +{ + return cube.epose == 0 && cube.eposs == 0 && cube.eposm == 0; +} + +bool +check_khuge(Cube cube) +{ + return check_drud(cube) && cube.epose % 24 == 0; +} + +bool +check_nothing(Cube cube) +{ + return is_admissible(cube); /*TODO: maybe change?*/ +} + +/* Movesets ******************************************************************/ + +bool +moveset_HTM(Move m) +{ + return m >= U && m <= B3; +} + +bool +moveset_URF(Move m) +{ + Move b = base_move(m); + + return b == U || b == R || b == F; +} + + +/* Local functions implementation ********************************************/ + +/* TODO: this should be an anti index (maybe?) */ +static 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 < 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; +} + +static Cube +admissible_eos_from_eofbepos(Cube cube) +{ + Edge e; + Cube ret; + CubeArray *arr = new_cubearray(cube, pf_all); + + memcpy(arr->eorl, arr->eofb, 12 * sizeof(int)); + memcpy(arr->eoud, arr->eofb, 12 * sizeof(int)); + + for (e = 0; e < 12; e++) { + if ((edge_slice(e) != 0 && edge_slice(arr->ep[e]) == 0) || + (edge_slice(e) == 0 && edge_slice(arr->ep[e]) != 0)) + arr->eorl[e] = 1 - arr->eorl[e]; + if ((edge_slice(e) != 2 && edge_slice(arr->ep[e]) == 2) || + (edge_slice(e) == 2 && edge_slice(arr->ep[e]) != 2)) + arr->eoud[e] = 1 - arr->eoud[e]; + } + + ret = arrays_to_cube(arr, pf_all); + free_cubearray(arr, pf_all); + + return ret; +} + +static bool +allowed_next(Move move, DfsData *dd) +{ + if (!possible_next[dd->last2][dd->last1][move]) + return false; + + if (commute[dd->last1][move]) + return dd->move_position[dd->last1] < dd->move_position[move]; + + return true; +} + +static void +append_alg(AlgList *l, Alg *alg) +{ + AlgListNode *node = malloc(sizeof(AlgListNode)); + int i; + + node->alg = new_alg(""); + for (i = 0; i < alg->len; i++) + append_move(node->alg, alg->move[i], alg->inv[i]); + node->next = NULL; + + if (++l->len == 1) + l->first = node; + else + l->last->next = node; + l->last = node; +} + +static void +append_move(Alg *alg, Move m, bool inverse) +{ + if (alg->len == alg->allocated) + realloc_alg(alg, 2*alg->len); + + alg->move[alg->len] = m; + alg->inv [alg->len] = inverse; + alg->len++; +} + +static Cube +apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a) +{ + Cube ret = {0}; + int i; + + for (i = 0; i < alg->len; i++) + if (alg->inv[i]) + ret = a ? apply_move(alg->move[i], ret) : + apply_move_cubearray(alg->move[i], ret, f); + + ret = compose_filtered(c, inverse_cube(ret), f); + + for (i = 0; i < alg->len; i++) + if (!alg->inv[i]) + ret = a ? apply_move(alg->move[i], ret) : + apply_move_cubearray(alg->move[i], ret, f); + + return ret; +} + +static void +apply_permutation(int *perm, int *set, int n) +{ + int *aux = malloc(n * sizeof(int)); + int i; + + if (!is_perm(perm, n)) + return; + + for (i = 0; i < n; i++) + aux[i] = set[perm[i]]; + + memcpy(set, aux, n * sizeof(int)); + free(aux); +} + +static Cube +apply_move_cubearray(Move m, Cube cube, PieceFilter f) +{ + 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); +} + +static int +array_ep_to_epos(int *ep, int *ss) +{ + 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 epos_from_arrays(epos, eps); +} + +static Cube +arrays_to_cube(CubeArray *arr, PieceFilter f) +{ + Cube ret = {0}; + + 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; +} + +static int +binomial(int n, int k) +{ + if (n < 0 || k < 0 || k > n) + return 0; + + return factorial(n) / (factorial(k) * factorial(n-k)); +} + +static Cube +compose_filtered(Cube c2, Cube c1, PieceFilter f) +{ + CubeArray *arr = new_cubearray(c2, f); + Cube ret; + + ret = move_via_arrays(arr, c1, f); + free_cubearray(arr, f); + + return ret; +} + +static void +cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f) +{ + int i; + + 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); +} + +/* +static int +cphtr_cp(int cp) +{ + int i, a[8]; + + index_to_perm(cp, 8, a); + + for (i = 0; i < 8; i++) + if (a[i] == UFR || a[i] == UBL || a[i] == DFL || a[i] == DBR) + a[i] = 0; + else + a[i] = 1; + + swap(&a[1], &a[5]); + swap(&a[3], &a[7]); + + return subset_to_index(a, 8, 4); +} +*/ + +static void +dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + if (dfs_stop(c, s, opts, dd)) + return; + + if (dfs_check_solved(opts, dd)) + return; + + dfs_branch(c, s, opts, dd); + + if (opts->can_niss && !dd->niss) + dfs_niss(c, s, opts, dd); +} + +static void +dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + Move m, l1 = dd->last1, l2 = dd->last2, *moves = dd->sorted_moves; + + int i, maxnsol = opts->max_solutions; + + for (i = 0; moves[i] != NULLMOVE && dd->sols->len < maxnsol; i++) { + m = moves[i]; + if (allowed_next(m, dd)) { + dd->last2 = dd->last1; + dd->last1 = m; + append_move(dd->current_alg, m, dd->niss); + + dfs(apply_move(m, c), s, opts, dd); + + dd->current_alg->len--; + dd->last2 = l2; + dd->last1 = l1; + } + } +} + +static bool +dfs_check_solved(SolveOptions *opts, DfsData *dd) +{ + if (dd->lb != 0) + return false; + + if (dd->current_alg->len == dd->d) { + append_alg(dd->sols, dd->current_alg); + + if (opts->feedback) + print_alg(dd->current_alg, false); + } + + return true; +} + +static void +dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + Move l1 = dd->last1, l2 = dd->last2; + CubeTarget ct; + + ct.cube = apply_move(inverse_move(l1), (Cube){0}); + ct.target = 1; + + if (dd->current_alg->len == 0 || s.estimate(ct)) { + dd->niss = true; + dd->last1 = NULLMOVE; + dd->last2 = NULLMOVE; + + dfs(inverse_cube(c), s, opts, dd); + + dd->last1 = l1; + dd->last2 = l2; + dd->niss = false; + } +} + +static bool +dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + CubeTarget ct = { + .cube = c, + .target = dd->d - dd->current_alg->len + }; + + if (dd->sols->len >= opts->max_solutions) + return true; + + dd->lb = s.estimate(ct); + if (opts->can_niss && !dd->niss) + dd->lb = MIN(1, dd->lb); + + if (dd->current_alg->len + dd->lb > dd->d) + return true; + + return false; +} + +static int +digit_array_to_int(int *a, int n, int b) +{ + int i, ret = 0, p = 1; + + for (i = 0; i < n; i++, p *= b) + ret += a[i] * p; + + return ret; +} + +static int +edge_slice(Edge e) { + if (e < 0 || e > 11) + return -1; + + if (e == FR || e == FL || e == BL || e == BR) + return 0; + if (e == UR || e == UL || e == DR || e == DL) + return 1; + + return 2; +} + +static int +epos_dependent_pos(int poss, int pose) +{ + int ep[12] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; + int ep8[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + int i, j; + + epos_to_partial_ep(poss*FACTORIAL4, ep, eps_solved); + epos_to_partial_ep(pose*FACTORIAL4, ep, epe_solved); + + for (i = 0, j = 0; i < 12; i++) + if (edge_slice(ep[i]) != 0) + ep8[j++] = (edge_slice(ep[i]) == 1) ? 1 : 0; + + swap(&ep8[1], &ep8[4]); + swap(&ep8[3], &ep8[6]); + + return subset_to_index(ep8, 8, 4); +} + +static int +epos_from_arrays(int *epos, int *ep) +{ + return FACTORIAL4 * subset_to_index(epos,12,4) + perm_to_index(ep,4); +} + +static void +epos_to_partial_ep(int epos, int *ep, int *ss) +{ + 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++]]; +} + +static int +factorial(int n) +{ + int i, ret = 1; + + if (n < 0) + return 0; + + for (i = 1; i <= n; i++) + ret *= i; + + return ret; +} + +void +free_alg(Alg *alg) +{ + free(alg->move); + free(alg->inv); + free(alg); +} + +void +free_alglist(AlgList *l) +{ + AlgListNode *aux, *i = l->first; + + while (i != NULL) { + aux = i->next; + free_alglistnode(i); + i = aux; + } + free(l); +} + +void +free_alglistnode(AlgListNode *aln) +{ + free_alg(aln->alg); + free(aln); +} + +static void +free_cubearray(CubeArray *arr, PieceFilter f) +{ + 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); +} + +static void +genptable_dfs(Cube c, PruneData *pd, DfsData *dd) +{ + int oldval = ptableval(pd, c); + + if (oldval < dd->m || ptable_has_reached(pd, c) || + pd->n == pd->coord->max || (dd->m != 0 && pd->coord->check(c)) ) + return; + + /*ptable_set_reached(pd, c);*/ + + if (dd->m == dd->d) { + if (dd->m < oldval) + ptable_update(pd, c, dd->m); + return; + } + + genptable_dfs_branch(c, pd, dd); +} + +static void +genptable_dfs_branch(Cube c, PruneData *pd, DfsData *dd) +{ + Move i, move, l1 = dd->last1, l2 = dd->last2; + + dd->m++; + + for (i = 0; dd->sorted_moves[i] != NULLMOVE; i++) { + move = dd->sorted_moves[i]; + if (allowed_next(move, dd)) { + dd->last2 = dd->last1; + dd->last1 = move; + + genptable_dfs(apply_move(move, c), pd, dd); + + dd->last2 = l2; + dd->last1 = l1; + } + } + + dd->m--; +} + +static void +gensym(SymData *sd) +{ + uint64_t i, in, nreps = 0; + int j; + Cube c, d; + + if (sd->generated) + return; + + sd->class = malloc(sd->coord->max * sizeof(uint64_t)); + sd->rep = malloc(sd->coord->max * sizeof(Cube)); + sd->transtorep = malloc(sd->coord->max * sizeof(Trans)); + + 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) { + c = sd->coord->cube(i); + sd->rep[nreps] = c; + for (j = 0; j < sd->ntrans; j++) { + d = apply_trans(sd->trans[j], c); + in = sd->coord->index(d); + + if (sd->class[in] == sd->coord->max + 1) { + sd->class[in] = nreps; + sd->transtorep[in] = + inverse_trans(sd->trans[j]); + } + } + nreps++; + } + } + + sd->sym_coord->max = nreps; + sd->rep = realloc(sd->rep, nreps * sizeof(Cube)); + sd->generated = true; + + fprintf(stderr, "Found %lu classes\n", nreps); + + if (!write_symdata_file(sd)) + fprintf(stderr, "Error writing SymData file\n"); + + return; +} + +static void +index_to_perm(int p, int n, int *r) +{ + int *a = malloc(n * sizeof(int)); + int i, j, c; + + for (i = 0; i < n; i++) + a[i] = 0; + + if (p < 0 || p >= factorial(n)) + for (i = 0; i < n; i++) + r[i] = -1; + + for (i = 0; i < n; i++) { + c = 0; + j = 0; + while (c <= p / factorial(n-i-1)) + c += a[j++] ? 0 : 1; + r[i] = j-1; + a[j-1] = 1; + p %= factorial(n-i-1); + } + + free(a); +} + +static void +index_to_subset(int s, int n, int k, int *r) +{ + int i, j, v; + + if (s < 0 || s >= binomial(n, k)) { + for (i = 0; i < n; i++) + r[i] = -1; + return; + } + + for (i = 0; i < n; i++) { + if (k == n-i) { + for (j = i; j < n; j++) + r[j] = 1; + return; + } + + if (k == 0) { + for (j = i; j < n; j++) + r[j] = 0; + return; + } + + v = binomial(n-i-1, k); + if (s >= v) { + r[i] = 1; + k--; + s -= v; + } else { + r[i] = 0; + } + } +} + +static void +int_to_digit_array(int a, int b, int n, int *r) +{ + int i; + + if (b <= 1) + for (i = 0; i < n; i++) + r[i] = 0; + else + for (i = 0; i < n; i++, a /= b) + r[i] = a % b; +} + +static void +int_to_sum_zero_array(int x, int b, int n, int *a) +{ + int i, s = 0; + + if (b <= 1) { + for (i = 0; i < n; i++) + a[i] = 0; + } else { + int_to_digit_array(x, b, n-1, a); + for (i = 0; i < n - 1; i++) + s = (s + a[i]) % b; + a[n-1] = (b - s) % b; + } +} + +static int +invert_digits(int a, int b, int n) +{ + int i, ret, *r = malloc(n * sizeof(int)); + + int_to_digit_array(a, b, n, r); + for (i = 0; i < n; i++) + r[i] = (b-r[i]) % b; + + ret = digit_array_to_int(r, n, b); + free(r); + return ret; +} + +static bool +is_perm(int *a, int n) +{ + int *aux = malloc(n * sizeof(int)); + int i; + + for (i = 0; i < n; i++) + if (a[i] < 0 || a[i] >= n) + return false; + else + aux[a[i]] = 1; + + for (i = 0; i < n; i++) + if (!aux[i]) + return false; + + free(aux); + + return true; +} + +static bool +is_subset(int *a, int n, int k) +{ + int i, sum = 0; + + for (i = 0; i < n; i++) + sum += a[i] ? 1 : 0; + + return sum == k; +} + +static Cube +move_via_arrays(CubeArray *arr, Cube c, PieceFilter f) +{ + CubeArray *arrc = new_cubearray(c, f); + Cube ret; + + 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; +} + +static void +movelist_to_position(Move *movelist, int *position) +{ + Move m; + + for (m = 0; m < NMOVES && movelist[m] != NULLMOVE; m++) + position[movelist[m]] = m; +} + +static void +moveset_to_list(Moveset ms, Estimator f, Move *r) +{ + CubeTarget ct = { .target = 1 }; + int b[NMOVES]; + int na = 0, nb = 0; + Move i; + + if (ms == NULL) { + fprintf(stderr, "Error: no moveset given\n"); + return; + } + + for (i = U; i < NMOVES; i++) { + if (ms(i)) { + ct.cube = apply_move(i, (Cube){0}); + if (f != NULL && f(ct)) + r[na++] = i; + else + b[nb++] = i; + } + } + + memcpy(r + na, b, nb * sizeof(Move)); + r[na+nb] = NULLMOVE; +} + +static AlgList * +new_alglist() +{ + AlgList *ret = malloc(sizeof(AlgList)); + + ret->len = 0; + ret->first = NULL; + ret->last = NULL; + + return ret; +} + +static CubeArray * +new_cubearray(Cube cube, PieceFilter f) +{ + 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; +} + +static int +perm_sign(int *a, int n) +{ + int i, j, ret = 0; + + if (!is_perm(a,n)) + return -1; + + for (i = 0; i < n; i++) + for (j = i+1; j < n; j++) + ret += (a[i] > a[j]) ? 1 : 0; + + return ret % 2; +} + +static int +perm_to_index(int *a, int n) +{ + int i, j, c, ret = 0; + + if (!is_perm(a, n)) + return -1; + + for (i = 0; i < n; i++) { + c = 0; + for (j = i+1; j < n; j++) + c += (a[i] > a[j]) ? 1 : 0; + ret += factorial(n-i-1) * c; + } + + return ret; +} + +static int +powint(int a, int b) +{ + if (b < 0) + return 0; + if (b == 0) + return 1; + + if (b % 2) + return a * powint(a, b-1); + else + return powint(a*a, b/2); +} + +static bool +ptable_has_reached(PruneData *pd, Cube cube) +{ + uint64_t ind = pd->coord->index(cube); + + return (ind % 2) ? pd->reached[ind/2] / 16 : pd->reached[ind/2] % 16; +} + +static void +ptable_set_reached(PruneData *pd, Cube cube) +{ + uint64_t ind = pd->coord->index(cube); + uint8_t oldval2 = pd->reached[ind/2]; + int other = (ind % 2) ? oldval2 % 16 : oldval2 / 16; + + pd->reached[ind/2] = (ind % 2) ? 16 + other : 16*other + 1; +} + +static void +ptable_update(PruneData *pd, Cube cube, int n) +{ + uint64_t ind = pd->coord->index(cube); + uint8_t oldval2 = pd->ptable[ind/2]; + int other = (ind % 2) ? oldval2 % 16 : oldval2 / 16; + + pd->ptable[ind/2] = (ind % 2) ? 16*n + other : 16*other + n; + pd->n++; +} + +static void +realloc_alg(Alg *alg, int n) +{ + if (alg == NULL) { + fprintf(stderr, "Error: trying to reallocate NULL alg.\n"); + return; + } + + if (n < alg->len) { + fprintf(stderr, "Error: alg too long for reallocation "); + fprintf(stderr, "(%d vs %d)\n", alg->len, n); + return; + } + + if (n > 1000000) { + fprintf(stderr, "Warning: very long alg,"); + fprintf(stderr, "something might go wrong.\n"); + } + + alg->move = realloc(alg->move, n * sizeof(int)); + alg->inv = realloc(alg->inv, n * sizeof(int)); + alg->allocated = n; +} + +static bool +read_mtables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int m, b = sizeof(int); + bool r = true; + + 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 +read_ptable_file(PruneData *pd) +{ + FILE *f; + char fname[strlen(tabledir)+100]; + uint64_t r; + + strcpy(fname, tabledir); + strcat(fname, "/"); + strcat(fname, pd->filename); + + if ((f = fopen(fname, "rb")) == NULL) + return false; + + r = fread(pd->ptable, sizeof(uint8_t), ptablesize(pd), f); + fclose(f); + + return r == ptablesize(pd); +} + +static bool +read_symdata_file(SymData *sd) +{ + 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->rep, sizeof(Cube), *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_ttables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int b = sizeof(int); + bool r = true; + Move m; + + 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[6], f) == me[6]; + r = r && fread(co_ttable[m], b, me[7], f) == me[7]; + r = r && fread(cpos_ttable[m], b, me[10], f) == me[10]; + r = r && fread(moves_ttable[m], b, me[11], f) == me[11]; + } + + 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_algs[r % NROTATIONS]); + 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_algs[r % NROTATIONS], ret, f, true); + if (r >= NROTATIONS) + ret = move_via_arrays(&ma, ret, f); + + free_alg(inv); + return ret; +} + +static int +subset_to_index(int *a, int n, int k) +{ + int i, ret = 0; + + if (!is_subset(a, n, k)) + return binomial(n, k); + + for (i = 0; i < n; i++) { + if (k == n-i) + return ret; + if (a[i]) { + ret += binomial(n-i-1, k); + k--; + } + } + + return ret; +} + +static void +sum_arrays_mod(int *src, int *dst, int n, int m) +{ + int i; + + for (i = 0; i < n; i++) + dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m; +} + +static void +swap(int *a, int *b) +{ + int aux; + + aux = *a; + *a = *b; + *b = aux; +} + +static bool +write_mtables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int m, b = sizeof(int); + bool r = true; + + 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; +} + +static bool +write_ptable_file(PruneData *pd) +{ + FILE *f; + char fname[strlen(tabledir)+100]; + uint64_t written; + + strcpy(fname, tabledir); + strcat(fname, "/"); + strcat(fname, pd->filename); + + if ((f = fopen(fname, "wb")) == NULL) + return false; + + written = fwrite(pd->ptable, sizeof(uint8_t), ptablesize(pd), f); + fclose(f); + + return written == ptablesize(pd); +} + +static bool +write_symdata_file(SymData *sd) +{ + 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->rep, sizeof(Cube), *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_ttables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + bool r = true; + int b = sizeof(int); + Move m; + + 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[6], f) == me[6]; + r = r && fwrite(co_ttable[m], b, me[7], f) == me[7]; + r = r && fwrite(cpos_ttable[m], b, me[10], f) == me[10]; + r = r && fwrite(moves_ttable[m], b, me[11], f) == me[11]; + } + + fclose(f); + return r; +} + +/* Init functions implementation *********************************************/ + +static void +init_auxtables() +{ + Cube c1, c2; + CubeArray *arr; + uint64_t ui, uj; + int i, j, k, auxarr[12]; + bool cij, p1, p2; + + for (ui = 0; ui < POW2TO11*BINOM12ON4; ui++) { + k = (ui / POW2TO11) * 24; + c1 = admissible_ep((Cube){ .epose = k }, pf_e); + c1.eofb = ui % POW2TO11; + c1 = admissible_eos_from_eofbepos(c1); + admissible_ee_aux[ui] = c1; + } + + for (ui = 0; ui < FACTORIAL6; ui++) { + arr = new_cubearray((Cube){.cpos = ui}, pf_cpos); + for (i = 0; i < 6; i++) { + what_center_at_aux[ui][i] = arr->cpos[i]; + where_is_center_aux[ui][arr->cpos[i]] = i; + } + free_cubearray(arr, pf_cpos); + } + + for (ui = 0; ui < FACTORIAL8; ui++) { + arr = new_cubearray((Cube){.cp = ui}, pf_cp); + for (i = 0; i < 8; i++) { + what_corner_at_aux[ui][i] = arr->cp[i]; + where_is_corner_aux[ui][arr->cp[i]] = i; + } + free_cubearray(arr, pf_cp); + } + + for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) { + arr = new_cubearray((Cube){.epose = ui}, pf_e); + for (i = 0; i < 12; i++) + if (edge_slice(arr->ep[i]) == 0) + where_is_edge_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) + where_is_edge_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) + where_is_edge_aux[2][ui][arr->ep[i]] = i; + free_cubearray(arr, pf_m); + } + + for (ui = 0; ui < POW3TO7; ui++) { + int_to_sum_zero_array(ui, 3, 8, auxarr); + what_orientation_last_corner_aux[ui] = auxarr[7]; + } + + for (ui = 0; ui < POW2TO11; ui++) { + int_to_sum_zero_array(ui, 2, 12, auxarr); + what_orientation_last_edge_aux[ui] = auxarr[11]; + } + + for (ui = 0; ui < BINOM12ON4; ui++) + for (uj = 0; uj < BINOM12ON4; uj++) + epos_dependent_aux[ui][uj]=epos_dependent_pos(ui, uj); + + for (i = 0; i < NMOVES; i++) { + for (j = 0; j < NMOVES; j++) { + c1 = apply_move(i, apply_move(j, (Cube){0})); + c2 = apply_move(j, apply_move(i, (Cube){0})); + commute[i][j] = equal(c1, c2) && i && j; + } + } + + for (i = 0; i < NMOVES; i++) { + for (j = 0; j < NMOVES; j++) { + for (k = 0; k < NMOVES; k++) { + p1 = j && base_move(j) == base_move(k); + p2 = i && base_move(i) == base_move(k); + cij = commute[i][j]; + possible_next[i][j][k] = !(p1 || (cij && p2)); + } + } + } + + for (i = 0; i < NMOVES; i++) + inverse_move_aux[i] = i ? i + 2 - 2*((i-1)%3) : NULLMOVE; + + /* Is there a more elegant way? */ + inverse_trans_aux[uf] = uf; + inverse_trans_aux[ur] = ul; + inverse_trans_aux[ul] = ur; + inverse_trans_aux[ub] = ub; + + inverse_trans_aux[df] = df; + inverse_trans_aux[dr] = dr; + inverse_trans_aux[dl] = dl; + inverse_trans_aux[db] = db; + + inverse_trans_aux[rf] = lf; + inverse_trans_aux[rd] = bl; + inverse_trans_aux[rb] = rb; + inverse_trans_aux[ru] = fr; + + inverse_trans_aux[lf] = rf; + inverse_trans_aux[ld] = br; + inverse_trans_aux[lb] = lb; + inverse_trans_aux[lu] = fl; + + inverse_trans_aux[fu] = fu; + inverse_trans_aux[fr] = ru; + inverse_trans_aux[fd] = bu; + inverse_trans_aux[fl] = lu; + + inverse_trans_aux[bu] = fd; + inverse_trans_aux[br] = ld; + inverse_trans_aux[bd] = bd; + inverse_trans_aux[bl] = rd; + + inverse_trans_aux[uf_mirror] = uf_mirror; + inverse_trans_aux[ur_mirror] = ur_mirror; + inverse_trans_aux[ul_mirror] = ul_mirror; + inverse_trans_aux[ub_mirror] = ub_mirror; + + inverse_trans_aux[df_mirror] = df_mirror; + inverse_trans_aux[dr_mirror] = dl_mirror; + inverse_trans_aux[dl_mirror] = dr_mirror; + inverse_trans_aux[db_mirror] = db_mirror; + + inverse_trans_aux[rf_mirror] = rf_mirror; + inverse_trans_aux[rd_mirror] = br_mirror; + inverse_trans_aux[rb_mirror] = lb_mirror; + inverse_trans_aux[ru_mirror] = fl_mirror; + + inverse_trans_aux[lf_mirror] = lf_mirror; + inverse_trans_aux[ld_mirror] = bl_mirror; + inverse_trans_aux[lb_mirror] = rb_mirror; + inverse_trans_aux[lu_mirror] = fr_mirror; + + inverse_trans_aux[fu_mirror] = fu_mirror; + inverse_trans_aux[fr_mirror] = lu_mirror; + inverse_trans_aux[fd_mirror] = bu_mirror; + inverse_trans_aux[fl_mirror] = ru_mirror; + + inverse_trans_aux[bu_mirror] = fd_mirror; + inverse_trans_aux[br_mirror] = rd_mirror; + inverse_trans_aux[bd_mirror] = bd_mirror; + inverse_trans_aux[bl_mirror] = ld_mirror; +} + +/* + * There is certainly a bette 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 < FACTORIAL8; i++) { + cphtr_left_cosets[i] = -1; + cphtr_right_cosets[i] = -1; + } + + /* 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++); + + /* 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++); +} + +static void +init_cphtr_left_cosets_bfs(int i, int c) +{ + int j, jj, k, next[FACTORIAL8], next2[FACTORIAL8], n, n2; + Move moves[6] = {U2, D2, R2, L2, F2, B2}; + + n = 1; + next[0] = i; + cphtr_left_cosets[i] = c; + + while (n != 0) { + for (j = 0, n2 = 0; j < n; j++) { + for (k = 0; k < 6; k++) { + jj = cp_mtable[moves[k]][next[j]]; + if (cphtr_left_cosets[jj] == -1) { + cphtr_left_cosets[jj] = c; + next2[n2++] = jj; + } + } + } + + for (j = 0; j < n2; j++) + next[j] = next2[j]; + n = n2; + } +} + +static void +init_cphtr_right_cosets_color(int i, int d) +{ + int cp; + unsigned int j; + + cphtr_right_rep[d] = i; + for (j = 0; j < FACTORIAL8; j++) { + if (cphtr_left_cosets[j] == 0) { + /* TODO: use antindexer, it's nicer */ + cp = compose((Cube){.cp = i}, (Cube){.cp = j}).cp; + cphtr_right_cosets[cp] = d; + } + } +} + +static void +init_environment() +{ + char *nissydata = getenv("NISSYDATA"); + char *localdata = getenv("XDG_DATA_HOME"); + char *home = getenv("HOME"); + bool read, write; + + if (nissydata != NULL) { + tabledir = malloc(strlen(nissydata) * sizeof(char) + 20); + strcpy(tabledir, nissydata); + } else if (localdata != NULL) { + tabledir = malloc(strlen(localdata) * sizeof(char) + 20); + strcpy(tabledir, localdata); + strcat(tabledir, "/nissy"); + } else if (home != NULL) { + tabledir = malloc(strlen(home) * sizeof(char) + 20); + strcpy(tabledir, home); + strcat(tabledir, "/.nissy"); + } + + mkdir(tabledir, 0777); + strcat(tabledir, "/tables"); + mkdir(tabledir, 0777); + + read = !access(tabledir, R_OK); + write = !access(tabledir, W_OK); + + if (!read) { + fprintf(stderr, "Table files cannot be read.\n"); + } else if (!write) { + fprintf(stderr, "Data directory not writable: "); + fprintf(stderr, "tables can be loaded, but not saved.\n"); + } +} + +static void +init_moves() { + Cube c; + CubeArray arrs; + int i; + unsigned int ui; + Move m; + + /* 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; + + fprintf(stderr, "Cannot load %s, generating it\n", "mtables"); + + /* Initialize transition tables */ + for (m = 0; m < NMOVES; m++) { + 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; + } + } + + if (!write_mtables_file()) + fprintf(stderr, "Error writing mtables\n"); +} + +static void +init_moves_aux() +{ + /* Some standard PieceFilters */ + pf_all.epose = true; + pf_all.eposs = true; + pf_all.eposm = true; + pf_all.eofb = true; + pf_all.eorl = true; + pf_all.eoud = true; + pf_all.cp = true; + pf_all.cofb = true; + pf_all.corl = true; + pf_all.coud = true; + pf_all.cpos = true; + + pf_4val.epose = true; + pf_4val.eposs = true; + pf_4val.eposm = true; + pf_4val.eofb = true; + pf_4val.coud = true; + pf_4val.cp = true; + + pf_epcp.epose = true; + pf_epcp.eposs = true; + pf_epcp.eposm = true; + pf_epcp.cp = true; + + pf_cpos.cpos = true; + + pf_cp.cp = true; + + pf_ep.epose = true; + pf_ep.eposs = true; + pf_ep.eposm = true; + + pf_e.epose = true; + pf_s.eposs = true; + pf_m.eposm = true; + + pf_eo.eofb = true; + pf_eo.eorl = true; + pf_eo.eoud = true; + + pf_co.cofb = true; + pf_co.corl = true; + pf_co.coud = true; + + /* Used to convert to and from CubeArray */ + epe_solved[0] = FR; + epe_solved[1] = FL; + epe_solved[2] = BL; + epe_solved[3] = BR; + + eps_solved[0] = UL; + eps_solved[1] = UR; + eps_solved[2] = DL; + eps_solved[3] = DR; + + epm_solved[0] = UF; + epm_solved[1] = UB; + epm_solved[2] = DF; + epm_solved[3] = DB; + + /* Table sizes, used for reading and writing files */ + me[0] = FACTORIAL12/FACTORIAL8; + me[1] = FACTORIAL12/FACTORIAL8; + me[2] = FACTORIAL12/FACTORIAL8; + me[3] = POW2TO11; + me[4] = POW2TO11; + me[5] = POW2TO11; + me[6] = FACTORIAL8; + me[7] = POW3TO7; + me[8] = POW3TO7; + me[9] = POW3TO7; + me[10] = FACTORIAL6; + me[11] = NMOVES; + + /* Cycles *********************/ + edge_cycle[U][UF] = UR; + edge_cycle[U][UL] = UF; + edge_cycle[U][UB] = UL; + edge_cycle[U][UR] = UB; + edge_cycle[U][DF] = DF; + edge_cycle[U][DL] = DL; + edge_cycle[U][DB] = DB; + edge_cycle[U][DR] = DR; + edge_cycle[U][FR] = FR; + edge_cycle[U][FL] = FL; + edge_cycle[U][BL] = BL; + edge_cycle[U][BR] = BR; + + edge_cycle[x][UF] = DF; + edge_cycle[x][UL] = FL; + edge_cycle[x][UB] = UF; + edge_cycle[x][UR] = FR; + edge_cycle[x][DF] = DB; + edge_cycle[x][DL] = BL; + edge_cycle[x][DB] = UB; + edge_cycle[x][DR] = BR; + edge_cycle[x][FR] = DR; + edge_cycle[x][FL] = DL; + edge_cycle[x][BL] = UL; + edge_cycle[x][BR] = UR; + + edge_cycle[y][UF] = UR; + edge_cycle[y][UL] = UF; + edge_cycle[y][UB] = UL; + edge_cycle[y][UR] = UB; + edge_cycle[y][DF] = DR; + edge_cycle[y][DL] = DF; + edge_cycle[y][DB] = DL; + edge_cycle[y][DR] = DB; + edge_cycle[y][FR] = BR; + edge_cycle[y][FL] = FR; + edge_cycle[y][BL] = FL; + edge_cycle[y][BR] = BL; + + corner_cycle[U][UFR] = UBR; + corner_cycle[U][UFL] = UFR; + corner_cycle[U][UBL] = UFL; + corner_cycle[U][UBR] = UBL; + corner_cycle[U][DFR] = DFR; + corner_cycle[U][DFL] = DFL; + corner_cycle[U][DBL] = DBL; + corner_cycle[U][DBR] = DBR; + + corner_cycle[x][UFR] = DFR; + corner_cycle[x][UFL] = DFL; + corner_cycle[x][UBL] = UFL; + corner_cycle[x][UBR] = UFR; + corner_cycle[x][DFR] = DBR; + corner_cycle[x][DFL] = DBL; + corner_cycle[x][DBL] = UBL; + corner_cycle[x][DBR] = UBR; + + corner_cycle[y][UFR] = UBR; + corner_cycle[y][UFL] = UFR; + corner_cycle[y][UBL] = UFL; + corner_cycle[y][UBR] = UBL; + corner_cycle[y][DFR] = DBR; + corner_cycle[y][DFL] = DFR; + corner_cycle[y][DBL] = DFL; + corner_cycle[y][DBR] = DBL; + + center_cycle[U][U_center] = U_center; + center_cycle[U][D_center] = D_center; + center_cycle[U][R_center] = R_center; + center_cycle[U][L_center] = L_center; + center_cycle[U][F_center] = F_center; + center_cycle[U][B_center] = B_center; + + center_cycle[x][U_center] = F_center; + center_cycle[x][D_center] = B_center; + center_cycle[x][R_center] = R_center; + center_cycle[x][L_center] = L_center; + center_cycle[x][F_center] = D_center; + center_cycle[x][B_center] = U_center; + + center_cycle[y][U_center] = U_center; + center_cycle[y][D_center] = D_center; + center_cycle[y][R_center] = B_center; + center_cycle[y][L_center] = F_center; + center_cycle[y][F_center] = R_center; + center_cycle[y][B_center] = L_center; + + /* Flipped pieces *************/ + eofb_flipped[x][UF] = 1; + eofb_flipped[x][UB] = 1; + eofb_flipped[x][DF] = 1; + eofb_flipped[x][DB] = 1; + + eofb_flipped[y][FR] = 1; + eofb_flipped[y][FL] = 1; + eofb_flipped[y][BL] = 1; + eofb_flipped[y][BR] = 1; + + eorl_flipped[x][UF] = 1; + eorl_flipped[x][UL] = 1; + eorl_flipped[x][UB] = 1; + eorl_flipped[x][UR] = 1; + eorl_flipped[x][DF] = 1; + eorl_flipped[x][DL] = 1; + eorl_flipped[x][DB] = 1; + eorl_flipped[x][DR] = 1; + eorl_flipped[x][FR] = 1; + eorl_flipped[x][FL] = 1; + eorl_flipped[x][BL] = 1; + eorl_flipped[x][BR] = 1; + + eorl_flipped[y][FR] = 1; + eorl_flipped[y][FL] = 1; + eorl_flipped[y][BL] = 1; + eorl_flipped[y][BR] = 1; + + eoud_flipped[U][UF] = 1; + eoud_flipped[U][UL] = 1; + eoud_flipped[U][UB] = 1; + eoud_flipped[U][UR] = 1; + + eoud_flipped[x][UF] = 1; + eoud_flipped[x][UB] = 1; + eoud_flipped[x][DF] = 1; + eoud_flipped[x][DB] = 1; + + eoud_flipped[y][UF] = 1; + eoud_flipped[y][UL] = 1; + eoud_flipped[y][UB] = 1; + eoud_flipped[y][UR] = 1; + eoud_flipped[y][DF] = 1; + eoud_flipped[y][DL] = 1; + eoud_flipped[y][DB] = 1; + eoud_flipped[y][DR] = 1; + eoud_flipped[y][FR] = 1; + eoud_flipped[y][FL] = 1; + eoud_flipped[y][BL] = 1; + eoud_flipped[y][BR] = 1; + + coud_flipped[x][UFR] = 2; + coud_flipped[x][UFL] = 1; + coud_flipped[x][UBR] = 1; + coud_flipped[x][UBL] = 2; + coud_flipped[x][DFR] = 1; + coud_flipped[x][DFL] = 2; + coud_flipped[x][DBR] = 2; + coud_flipped[x][DBL] = 1; + + corl_flipped[U][UFR] = 1; + corl_flipped[U][UFL] = 2; + corl_flipped[U][UBL] = 1; + corl_flipped[U][UBR] = 2; + + corl_flipped[y][UFR] = 1; + corl_flipped[y][UFL] = 2; + corl_flipped[y][UBL] = 1; + corl_flipped[y][UBR] = 2; + corl_flipped[y][DFR] = 2; + corl_flipped[y][DFL] = 1; + corl_flipped[y][DBL] = 2; + corl_flipped[y][DBR] = 1; + + cofb_flipped[U][UFR] = 2; + cofb_flipped[U][UFL] = 1; + cofb_flipped[U][UBL] = 2; + cofb_flipped[U][UBR] = 1; + + cofb_flipped[x][UFR] = 1; + cofb_flipped[x][UFL] = 2; + cofb_flipped[x][UBL] = 1; + cofb_flipped[x][UBR] = 2; + cofb_flipped[x][DFR] = 2; + cofb_flipped[x][DFL] = 1; + cofb_flipped[x][DBL] = 2; + cofb_flipped[x][DBR] = 1; + + cofb_flipped[y][UFR] = 2; + cofb_flipped[y][UFL] = 1; + cofb_flipped[y][UBL] = 2; + cofb_flipped[y][UBR] = 1; + cofb_flipped[y][DFR] = 1; + cofb_flipped[y][DFL] = 2; + cofb_flipped[y][DBL] = 1; + cofb_flipped[y][DBR] = 2; + + /* Equivalent moves ***********/ + equiv_alg[NULLMOVE] = new_alg(""); + + equiv_alg[U] = new_alg(" U "); + equiv_alg[U2] = new_alg(" UU "); + equiv_alg[U3] = new_alg(" UUU "); + equiv_alg[D] = new_alg(" xx U xx "); + equiv_alg[D2] = new_alg(" xx UU xx "); + equiv_alg[D3] = new_alg(" xx UUU xx "); + equiv_alg[R] = new_alg(" yx U xxxyyy "); + equiv_alg[R2] = new_alg(" yx UU xxxyyy "); + equiv_alg[R3] = new_alg(" yx UUU xxxyyy "); + equiv_alg[L] = new_alg(" yyyx U xxxy "); + equiv_alg[L2] = new_alg(" yyyx UU xxxy "); + equiv_alg[L3] = new_alg(" yyyx UUU xxxy "); + equiv_alg[F] = new_alg(" x U xxx "); + equiv_alg[F2] = new_alg(" x UU xxx "); + equiv_alg[F3] = new_alg(" x UUU xxx "); + equiv_alg[B] = new_alg(" xxx U x "); + equiv_alg[B2] = new_alg(" xxx UU x "); + equiv_alg[B3] = new_alg(" xxx UUU x "); + + equiv_alg[Uw] = new_alg(" xx U xx y "); + equiv_alg[Uw2] = new_alg(" xx UU xx yy "); + equiv_alg[Uw3] = new_alg(" xx UUU xx yyy "); + equiv_alg[Dw] = new_alg(" U yyy "); + equiv_alg[Dw2] = new_alg(" UU yy "); + equiv_alg[Dw3] = new_alg(" UUU y "); + equiv_alg[Rw] = new_alg(" yyyx U xxxy x "); + equiv_alg[Rw2] = new_alg(" yyyx UU xxxy xx "); + equiv_alg[Rw3] = new_alg(" yyyx UUU xxxy xxx "); + equiv_alg[Lw] = new_alg(" yx U xxxyyy xxx "); + equiv_alg[Lw2] = new_alg(" yx UU xxxyyy xx "); + equiv_alg[Lw3] = new_alg(" yx UUU xxxyyy x "); + equiv_alg[Fw] = new_alg(" xxx U x yxxxyyy "); + equiv_alg[Fw2] = new_alg(" xxx UU x yxxyyy "); + equiv_alg[Fw3] = new_alg(" xxx UUU x yxyyy "); + equiv_alg[Bw] = new_alg(" x U xxx yxyyy "); + equiv_alg[Bw2] = new_alg(" x UU xxx yxxyyy "); + equiv_alg[Bw3] = new_alg(" x UUU xxx yxxxyyy "); + + equiv_alg[M] = new_alg(" yx U xx UUU yxyyy "); + equiv_alg[M2] = new_alg(" yx UU xx UU xxxy "); + equiv_alg[M3] = new_alg(" yx UUU xx U yxxxy "); + equiv_alg[S] = new_alg(" x UUU xx U yyyx "); + equiv_alg[S2] = new_alg(" x UU xx UU yyx "); + equiv_alg[S3] = new_alg(" x U xx UUU yx "); + equiv_alg[E] = new_alg(" U xx UUU xxyyy "); + equiv_alg[E2] = new_alg(" UU xx UU xxyy "); + equiv_alg[E3] = new_alg(" UUU xx U xxy "); + + equiv_alg[x] = new_alg(" x "); + equiv_alg[x2] = new_alg(" xx "); + equiv_alg[x3] = new_alg(" xxx "); + equiv_alg[y] = new_alg(" y "); + equiv_alg[y2] = new_alg(" yy "); + equiv_alg[y3] = new_alg(" yyy "); + equiv_alg[z] = new_alg(" yyy x y "); + equiv_alg[z2] = new_alg(" yy xx "); + equiv_alg[z3] = new_alg(" y x yyy "); +} + +static void +init_strings() +{ + strcpy(move_string [NULLMOVE], "-" ); + strcpy(move_string [U], "U" ); + strcpy(move_string [U2], "U2" ); + strcpy(move_string [U3], "U\'" ); + strcpy(move_string [D], "D" ); + strcpy(move_string [D2], "D2" ); + strcpy(move_string [D3], "D\'" ); + strcpy(move_string [R], "R" ); + strcpy(move_string [R2], "R2" ); + strcpy(move_string [R3], "R\'" ); + strcpy(move_string [L], "L" ); + strcpy(move_string [L2], "L2" ); + strcpy(move_string [L3], "L\'" ); + strcpy(move_string [F], "F" ); + strcpy(move_string [F2], "F2" ); + strcpy(move_string [F3], "F\'" ); + strcpy(move_string [B], "B" ); + strcpy(move_string [B2], "B2" ); + strcpy(move_string [B3], "B\'" ); + strcpy(move_string [Uw], "Uw" ); + strcpy(move_string [Uw2], "Uw2" ); + strcpy(move_string [Uw3], "Uw\'" ); + strcpy(move_string [Dw], "Dw" ); + strcpy(move_string [Dw2], "Dw2" ); + strcpy(move_string [Dw3], "Dw\'" ); + strcpy(move_string [Rw], "Rw" ); + strcpy(move_string [Rw2], "Rw2" ); + strcpy(move_string [Rw3], "Rw\'" ); + strcpy(move_string [Lw], "Lw" ); + strcpy(move_string [Lw2], "Lw2" ); + strcpy(move_string [Lw3], "Lw\'" ); + strcpy(move_string [Fw], "Fw" ); + strcpy(move_string [Fw2], "Fw2" ); + strcpy(move_string [Fw3], "Fw\'" ); + strcpy(move_string [Bw], "Bw" ); + strcpy(move_string [Bw2], "Bw2" ); + strcpy(move_string [Bw3], "Bw\'" ); + strcpy(move_string [M], "M" ); + strcpy(move_string [M2], "M2" ); + strcpy(move_string [M3], "M\'" ); + strcpy(move_string [S], "S" ); + strcpy(move_string [S2], "S2" ); + strcpy(move_string [S3], "S\'" ); + strcpy(move_string [E], "E" ); + strcpy(move_string [E2], "E2" ); + strcpy(move_string [E3], "E\'" ); + strcpy(move_string [x], "x" ); + strcpy(move_string [x2], "x2" ); + strcpy(move_string [x3], "x\'" ); + strcpy(move_string [y], "y" ); + strcpy(move_string [y2], "y2" ); + strcpy(move_string [y3], "y\'" ); + strcpy(move_string [z], "z" ); + strcpy(move_string [z2], "z2" ); + strcpy(move_string [z3], "z\'" ); + + strcpy(edge_string [UF], "UF" ); + strcpy(edge_string [UL], "UL" ); + strcpy(edge_string [UB], "UB" ); + strcpy(edge_string [UR], "UR" ); + strcpy(edge_string [DF], "DF" ); + strcpy(edge_string [DL], "DL" ); + strcpy(edge_string [DB], "DB" ); + strcpy(edge_string [DR], "DR" ); + strcpy(edge_string [FR], "FR" ); + strcpy(edge_string [FL], "FL" ); + strcpy(edge_string [BL], "BL" ); + strcpy(edge_string [BR], "BR" ); + + strcpy(corner_string [UFR], "UFR" ); + strcpy(corner_string [UFL], "UFL" ); + strcpy(corner_string [UBL], "UBL" ); + strcpy(corner_string [UBR], "UBR" ); + strcpy(corner_string [DFR], "DFR" ); + strcpy(corner_string [DFL], "DFL" ); + strcpy(corner_string [DBL], "DBL" ); + strcpy(corner_string [DBR], "DBR" ); + + strcpy(center_string [U_center], "U" ); + strcpy(center_string [D_center], "D" ); + strcpy(center_string [R_center], "R" ); + strcpy(center_string [L_center], "L" ); + strcpy(center_string [F_center], "F" ); + strcpy(center_string [B_center], "B" ); +} + +static void +init_symdata() +{ + int i; + + for (i = 0; i < n_all_symdata; i++) + gensym(all_sd[i]); +} + +static void +init_trans() { + Cube aux, cube, mirr, c[3]; + CubeArray epcp; + int i, eparr[12], eoarr[12], cparr[8], coarr[8]; + unsigned int ui; + Move mi, move; + Trans m; + + /* Compute sources */ + for (i = 0; i < NTRANS; i++) { + cube = apply_alg(rotation_algs[i % NROTATIONS], (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; + } + + if (read_ttables_file()) + return; + + fprintf(stderr, "Cannot load %s, generating it\n", "ttables"); + + /* Initialize tables */ + for (m = 0; m < NTRANS; m++) { + epcp = (CubeArray){ .ep = eparr, .cp = cparr }; + cube = apply_alg(rotation_algs[m % NROTATIONS], (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++) { + aux = apply_trans(m, apply_move(mi, (Cube){0})); + for (move = 0; move < NMOVES; move++) { + cube = apply_move(inverse_move_aux[move], aux); + mirr = apply_trans(uf_mirror, cube); + if (is_solved(cube, false) || + is_solved(mirr, false)) + moves_ttable[m][mi] = move; + } + } + } + + if (!write_ttables_file()) + fprintf(stderr, "Error writing ttables\n"); +} + +static void +init_trans_aux() +{ + ep_mirror[UF] = UF; + ep_mirror[UL] = UR; + ep_mirror[UB] = UB; + ep_mirror[UR] = UL; + ep_mirror[DF] = DF; + ep_mirror[DL] = DR; + ep_mirror[DB] = DB; + ep_mirror[DR] = DL; + ep_mirror[FR] = FL; + ep_mirror[FL] = FR; + ep_mirror[BR] = BL; + ep_mirror[BL] = BR; + + cp_mirror[UFR] = UFL; + cp_mirror[UFL] = UFR; + cp_mirror[UBL] = UBR; + cp_mirror[UBR] = UBL; + cp_mirror[DFR] = DFL; + cp_mirror[DFL] = DFR; + cp_mirror[DBL] = DBR; + cp_mirror[DBR] = DBL; + + cpos_mirror[U_center] = U_center; + cpos_mirror[D_center] = D_center; + cpos_mirror[R_center] = L_center; + cpos_mirror[L_center] = R_center; + cpos_mirror[F_center] = F_center; + cpos_mirror[B_center] = B_center; + + /* Is there a more elegant way? */ + rotation_algs[uf] = new_alg(""); + rotation_algs[ur] = new_alg("y"); + rotation_algs[ub] = new_alg("y2"); + rotation_algs[ul] = new_alg("y3"); + + rotation_algs[df] = new_alg("z2"); + rotation_algs[dr] = new_alg("y z2"); + rotation_algs[db] = new_alg("x2"); + rotation_algs[dl] = new_alg("y3 z2"); + + rotation_algs[rf] = new_alg("z3"); + rotation_algs[rd] = new_alg("z3 y"); + rotation_algs[rb] = new_alg("z3 y2"); + rotation_algs[ru] = new_alg("z3 y3"); + + rotation_algs[lf] = new_alg("z"); + rotation_algs[ld] = new_alg("z y3"); + rotation_algs[lb] = new_alg("z y2"); + rotation_algs[lu] = new_alg("z y"); + + rotation_algs[fu] = new_alg("x y2"); + rotation_algs[fr] = new_alg("x y"); + rotation_algs[fd] = new_alg("x"); + rotation_algs[fl] = new_alg("x y3"); + + rotation_algs[bu] = new_alg("x3"); + rotation_algs[br] = new_alg("x3 y"); + rotation_algs[bd] = new_alg("x3 y2"); + rotation_algs[bl] = new_alg("x3 y3"); +} + + +/* Public functions implementation *******************************************/ + +Cube +apply_alg(Alg *alg, Cube cube) +{ + return apply_alg_generic(alg, cube, pf_all, true); +} + +Cube +apply_move(Move m, Cube cube) +{ + 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] + }; +} + + +Cube +apply_trans(Trans t, Cube cube) +{ + 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] + }; +} + +Move +base_move(Move m) +{ + if (m == NULLMOVE) + return NULLMOVE; + else + return m - (m-1)%3; +} + +Cube +compose(Cube c2, Cube c1) +{ + return compose_filtered(c2, c1, pf_all); +} + +/*TODO maybe move the next two */ +uint64_t +cphtr(Cube cube) +{ + return cphtr_right_cosets[cube.cp]; +} + +Cube +anti_cphtr(uint64_t ind) +{ + return (Cube) { .cp = cphtr_right_rep[ind] }; +} + +uint64_t +epos_dependent(Cube c) +{ + return epos_dependent_aux[c.eposs/FACTORIAL4][c.epose/FACTORIAL4]; +} + +bool +equal(Cube c1, Cube c2) +{ + 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; +} + +void +genptable(PruneData *pd) +{ + Cube cube; + uint64_t j, oldn = 0; + DfsData dd = { + .m = 0, + .last1 = NULLMOVE, + .last2 = NULLMOVE + }; + + if (pd->generated) + return; + + /* TODO: check if memory is enough, otherwise maybe crash gracefully? */ + pd->ptable = malloc(ptablesize(pd) * sizeof(uint8_t)); + + if (read_ptable_file(pd)) { + pd->generated = true; + return; + } + + fprintf(stderr, "Cannot load %s, generating it\n", pd->filename); + + /* We use 4 bits per value, so any distance >= 15 is set to 15 */ + for (j = 0; j < pd->coord->max; j++) + ptable_update(pd, pd->coord->cube(j), 15); + + moveset_to_list(pd->moveset, NULL, dd.sorted_moves); + movelist_to_position(dd.sorted_moves, dd.move_position); + + pd->reached = malloc(ptablesize(pd) * sizeof(uint8_t)); + for (dd.d = 0, pd->n = 0; dd.d < 15 && pd->n < pd->coord->max; dd.d++) { + memset(pd->reached, 0, ptablesize(pd)*sizeof(uint8_t)); + for (j = 0; j < pd->coord->max; j++) { + cube = pd->coord->cube(j); + if (pd->coord->check(cube)) + genptable_dfs(cube, pd, &dd); + } + fprintf(stderr, "Depth %d done, generated %lu\t(%lu/%lu)\n", + dd.d, pd->n-oldn, pd->n, pd->coord->max); + oldn = pd->n; + } + + if (!write_ptable_file(pd)) + fprintf(stderr, "Error writing ptable file\n"); + + pd->generated = true; + free(pd->reached); +} + +Cube +inverse_cube(Cube cube) +{ + CubeArray *arr = new_cubearray(cube, pf_all); + CubeArray *inv = new_cubearray((Cube){0}, pf_all); + Cube ret; + int i; + + for (i = 0; i < 12; i++) { + inv->ep[arr->ep[i]] = i; + inv->eofb[arr->ep[i]] = arr->eofb[i]; + inv->eorl[arr->ep[i]] = arr->eorl[i]; + inv->eoud[arr->ep[i]] = arr->eoud[i]; + } + + for (i = 0; i < 8; i++) { + inv->cp[arr->cp[i]] = i; + inv->coud[arr->cp[i]] = (3 - arr->coud[i]) % 3; + inv->corl[arr->cp[i]] = (3 - arr->corl[i]) % 3; + inv->cofb[arr->cp[i]] = (3 - arr->cofb[i]) % 3; + } + + for (int i = 0; i < 6; i++) + inv->cpos[arr->cpos[i]] = i; + + ret = arrays_to_cube(inv, pf_all); + free_cubearray(arr, pf_all); + free_cubearray(inv, pf_all); + + return ret; +} + +Move +inverse_move(Move m) +{ + return inverse_move_aux[m]; +} + +Trans +inverse_trans(Trans t) +{ + return inverse_trans_aux[t]; +} + +bool +is_admissible(Cube cube) +{ + /* TODO: this should check consistency of different orientations */ + /* TODO: check that centers are opposite and admissible */ + + CubeArray *a = new_cubearray(cube, pf_all); + int parity; + bool perm; + + 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); + + return perm && parity % 2 == 0; +} + +bool +is_solved(Cube cube, bool reorient) +{ + int i; + + if (reorient) { + for (i = 0; i < NROTATIONS; i++) + if (is_solved(apply_alg(rotation_algs[i], cube),false)) + return true; + return false; + } else { + return equal(cube, (Cube){0}); + } +} + +bool +is_solved_block(Cube cube, Block block) +{ + 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; + + return true; +} + +bool +is_solved_center(Cube cube, Center c) +{ + return what_center_at(cube, c) == c; +} + +bool +is_solved_corner(Cube cube, Corner c) +{ + return what_corner_at(cube, c) == c && + what_orientation_corner(cube.coud, c); +} + +bool +is_solved_edge(Cube cube, Edge e) +{ + return what_edge_at(cube, e) == e && + what_orientation_edge(cube.eofb, e); +} + +int +piece_orientation(Cube cube, int piece, char *orientation) +{ + 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) +{ +/* + CubeArray *arr = new_cubearray(cube, pf_all); + + for (int i = 0; i < 12; i++) + printf(" %s ", edge_string[arr->ep[i]]); + printf("\n"); + + for (int i = 0; i < 12; i++) + printf(" %c ", arr->eofb[i] + '0'); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf("%s ", corner_string[arr->cp[i]]); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf(" %c ", arr->coud[i] + '0'); + printf("\n"); + + for (int i = 0; i < 6; i++) + printf(" %s ", center_string[arr->cpos[i]]); + printf("\n"); + + free_cubearray(arr, pf_all); +*/ + + for (int i = 0; i < 12; i++) + printf(" %s ", edge_string[what_edge_at(cube, i)]); + printf("\n"); + + for (int i = 0; i < 12; i++) + printf(" %d ", what_orientation_edge(cube.eofb, i)); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf("%s ", corner_string[what_corner_at(cube, i)]); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf(" %d ", what_orientation_corner(cube.coud, i)); + printf("\n"); + + for (int i = 0; i < 6; i++) + printf(" %s ", center_string[what_center_at(cube, i)]); + printf("\n"); + +} + +Cube +random_cube() +{ + CubeArray *arr = new_cubearray((Cube){0}, pf_4val); + Cube ret; + int ep, cp, eo, co; + + ep = rand() % FACTORIAL12; + cp = rand() % FACTORIAL8; + eo = rand() % POW2TO11; + co = rand() % POW3TO7; + + index_to_perm(ep, 12, arr->ep); + index_to_perm(cp, 8, arr->cp); + int_to_sum_zero_array(eo, 2, 12, arr->eofb); + int_to_sum_zero_array(co, 3, 8, arr->coud); + + if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8)) + swap(&(arr->ep[0]), &(arr->ep[1])); + + ret = arrays_to_cube(arr, pf_4val); + free_cubearray(arr, pf_4val); + + return ret; +} + +/* TODO: clean pre_trans or put it back */ +AlgList * +solve(Cube cube, Step step, SolveOptions *opts) +{ + /*AlgListNode *node;*/ + AlgList *sols = new_alglist(); + /*Cube c = apply_trans(opts->pre_trans, cube);*/ + DfsData dd = { + .m = 0, + .niss = false, + .lb = -1, + .last1 = NULLMOVE, + .last2 = NULLMOVE, + .sols = sols, + .current_alg = new_alg("") + }; + + if (step.ready != NULL && !step.ready(cube)) { + fprintf(stderr, "Cube not ready for solving step\n"); + return sols; + } + + moveset_to_list(step.moveset, step.estimate, dd.sorted_moves); + movelist_to_position(dd.sorted_moves, dd.move_position); + + for (dd.d = opts->min_moves; + dd.d <= opts->max_moves && !(sols->len && opts->optimal_only); + dd.d++) { + if (opts->feedback) + fprintf(stderr, + "Found %d solutions, searching depth %d...\n", + sols->len, dd.d); + dfs(cube, step, opts, &dd); + } + +/* + for (node = sols->first; node != NULL; node = node->next) + transform_alg(inverse_trans(opts->pre_trans), node->alg); +*/ + + free_alg(dd.current_alg); + return sols; +} + +Alg * +inverse_alg(Alg *alg) +{ + Alg *ret = new_alg(""); + int i; + + for (i = alg->len-1; i >= 0; i--) + append_move(ret, inverse_move(alg->move[i]), alg->inv[i]); + + return ret; +} + +Alg * +new_alg(char *str) +{ + Alg *alg = malloc(sizeof(Alg)); + int i; + bool niss = false; + Move j, m; + + alg->move = malloc(30 * sizeof(Move)); + alg->inv = malloc(30 * sizeof(bool)); + alg->allocated = 30; + alg->len = 0; + + for (i = 0; str[i]; i++) { + if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n') + continue; + + if (str[i] == '(' && niss) { + fprintf(stderr, "Error reading moves: nested ( )\n"); + return alg; + } + + if (str[i] == ')' && !niss) { + fprintf(stderr, "Error reading moves: unmatched )\n"); + return alg; + } + + if (str[i] == '(' || str[i] == ')') { + niss = !niss; + continue; + } + + for (j = 0; j < NMOVES; j++) { + if (str[i] == move_string[j][0]) { + m = j; + if (m <= B && str[i+1]=='w') { + m += Uw - U; + i++; + } + if (str[i+1]=='2') { + m += 1; + i++; + } else if (str[i+1]=='\'' || str[i+1]=='3') { + m += 2; + i++; + } + append_move(alg, m, niss); + break; + } + } + } + + return alg; +} + +Alg * +on_inverse(Alg *alg) +{ + Alg *ret = new_alg(""); + int i; + + for (i = 0; i < alg->len; i++) + append_move(ret, alg->move[i], !alg->inv[i]); + + return ret; +} + +void +print_alg(Alg *alg, bool l) +{ + /* TODO: make it possible to print to stdout or to string */ + /* Maybe just return a string */ + char fill[4]; + int i; + bool niss = false; + + for (i = 0; i < alg->len; i++) { + if (!niss && alg->inv[i]) + strcpy(fill, i == 0 ? "(" : " ("); + if (niss && !alg->inv[i]) + strcpy(fill, ") "); + if (niss == alg->inv[i]) + strcpy(fill, i == 0 ? "" : " "); + + printf("%s%s", fill, move_string[alg->move[i]]); + niss = alg->inv[i]; + } + + if (niss) + printf(")"); + if (l) + printf(" (%d)", alg->len); + + printf("\n"); +} + +void +print_alglist(AlgList *al, bool l) +{ + AlgListNode *i; + + for (i = al->first; i != NULL; i = i->next) + print_alg(i->alg, l); +} + +void +print_ptable(PruneData *pd) +{ + uint64_t i, a[16]; + + for (i = 0; i < 16; i++) + a[i] = 0; + + if (!pd->generated) + genptable(pd); + + for (i = 0; i < pd->coord->max; i++) + a[ptableval(pd, pd->coord->cube(i))]++; + + fprintf(stderr, "Values for table %s\n", pd->filename); + for (i = 0; i < 16; i++) + printf("%2lu\t%10lu\n", i, a[i]); +} + +uint64_t +ptablesize(PruneData *pd) +{ + return (pd->coord->max + 1) / 2; +} + +int +ptableval(PruneData *pd, Cube cube) +{ + uint64_t ind = pd->coord->index(cube); + + return (ind % 2) ? pd->ptable[ind/2] / 16 : pd->ptable[ind/2] % 16; +} + + +Alg * +rotation_alg(Trans i) +{ + return rotation_algs[i % NROTATIONS]; +} + +void +transform_alg(Trans t, Alg *alg) +{ + int i; + + for (i = 0; i < alg->len; i++) + alg->move[i] = moves_ttable[t][alg->move[i]]; +} + +Center +what_center_at(Cube cube, Center c) +{ + return what_center_at_aux[cube.cpos][c]; +} + +Corner +what_corner_at(Cube cube, Corner c) +{ + return what_corner_at_aux[cube.cp][c]; +} + +Edge +what_edge_at(Cube cube, Edge e) +{ + Edge ret; + CubeArray *arr = new_cubearray(cube, pf_ep); + + ret = arr->ep[e]; + + free_cubearray(arr, pf_ep); + return ret; +} + +int +what_orientation_corner(int co, Corner c) +{ + if (c < 7) + return (co / powint(3, c)) % 3; + else + return what_orientation_last_corner_aux[co]; +} + +int +what_orientation_edge(int eo, Edge e) +{ + if (e < 11) + return (eo & (1 << e)) ? 1 : 0; + else + return what_orientation_last_edge_aux[eo]; +} + +Center +where_is_center(Cube cube, Center c) +{ + return where_is_center_aux[cube.cpos][c]; +} + +Corner +where_is_corner(Cube cube, Corner c) +{ + return where_is_corner_aux[cube.cp][c]; +} + + +void +init() +{ + /* Order is important! */ + init_environment(); + init_strings(); + init_moves_aux(); + init_moves(); + init_auxtables(); + init_cphtr_cosets(); + init_trans_aux(); + init_trans(); + init_symdata(); +} + diff --git a/old/2021-06-30-reached/cube.h b/old/2021-06-30-reached/cube.h new file mode 100644 index 0000000..ffbcd86 --- /dev/null +++ b/old/2021-06-30-reached/cube.h @@ -0,0 +1,90 @@ +#ifndef CUBE_H +#define CUBE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "macros.h" +#include "cubetypes.h" + +extern Coordinate coord_eofb; +extern Coordinate coord_eofbepos; +extern Coordinate coord_coud; +extern Coordinate coord_corners; +extern Coordinate coord_cornershtr; +extern Coordinate coord_drud; +extern Coordinate coord_coud_sym16; +extern Coordinate coord_eofbepos_sym16; +extern Coordinate coord_drud_sym16; +extern Coordinate coord_khuge; + +Cube apply_alg(Alg *alg, Cube cube); +Cube apply_move(Move m, Cube cube); +Cube apply_trans(Trans t, Cube cube); +bool block_solved(Cube cube, Block); +Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */ +uint64_t cphtr(Cube cube); /* TODO: rename (something with cosets) */ +Cube anti_cphtr(uint64_t ind); /*TODO also this */ +uint64_t epos_dependent(Cube cube); /* TODO: rename and turn into an indexer */ +bool equal(Cube c1, Cube c2); +Cube inverse_cube(Cube cube); +Move inverse_move(Move m); +Trans inverse_trans(Trans t); +bool is_admissible(Cube cube); +bool is_solved(Cube cube, bool reorient); +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 print_cube(Cube cube); +Cube random_cube(); +AlgList * solve(Cube cube, Step step, SolveOptions *opts); +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); + +bool check_centers(Cube cube); +bool check_corners(Cube cube); +bool check_cornershtr(Cube cube); +bool check_coud(Cube cube); +bool check_drud(Cube cube); +bool check_eofb(Cube cube); +bool check_eofbepos(Cube cube); +bool check_epose(Cube cube); +bool check_ep(Cube cube); +bool check_khuge(Cube cube); +bool check_nothing(Cube cube); + +bool moveset_HTM(Move m); +bool moveset_URF(Move m); + +Move base_move(Move m); +void free_alg(Alg *alg); +void free_alglist(AlgList *l); +Alg * inverse_alg(Alg *alg); +Alg * new_alg(char *str); +Alg * on_inverse(Alg *alg); +void print_alg(Alg *alg, bool l); +void print_alglist(AlgList *al, bool l); +Alg * rotation_alg(Trans i); +void transform_alg(Trans t, Alg *alg); + +void genptable(PruneData *pd); +void print_ptable(PruneData *pd); +uint64_t ptablesize(PruneData *pd); +int ptableval(PruneData *pd, Cube cube); + +void init(); + +#endif + diff --git a/old/2021-06-30-reached/cubetypes.h b/old/2021-06-30-reached/cubetypes.h new file mode 100644 index 0000000..0a7961d --- /dev/null +++ b/old/2021-06-30-reached/cubetypes.h @@ -0,0 +1,251 @@ +#ifndef CUBETYPES_H +#define CUBETYPES_H + +/* Typedefs ******************************************************************/ + +typedef enum center Center; +typedef enum corner Corner; +typedef enum edge Edge; +typedef enum move Move; +typedef enum trans Trans; + +typedef struct alg Alg; +typedef struct alglist AlgList; +typedef struct alglistnode AlgListNode; +typedef struct block Block; +typedef struct coordinate Coordinate; +typedef struct cube Cube; +typedef struct cubearray CubeArray; +typedef struct cubetarget CubeTarget; +typedef struct dfsdata DfsData; +typedef struct piecefilter PieceFilter; +typedef struct prunedata PruneData; +typedef struct solveoptions SolveOptions; +typedef struct step Step; +typedef struct symdata SymData; + +typedef Cube (*AntiIndexer) (uint64_t); +typedef bool (*Checker) (Cube); +typedef int (*Estimator) (CubeTarget); +typedef uint64_t (*Indexer) (Cube); +typedef bool (*Moveset) (Move); + + +/* Enums *********************************************************************/ + +enum +center +{ + U_center, D_center, + R_center, L_center, + F_center, B_center +}; + +enum +corner +{ + UFR, UFL, UBL, UBR, + DFR, DFL, DBL, DBR +}; + +enum +edge +{ + UF, UL, UB, UR, + DF, DL, DB, DR, + FR, FL, BL, BR +}; + +enum +move +{ + NULLMOVE, + U, U2, U3, D, D2, D3, + R, R2, R3, L, L2, L3, + F, F2, F3, B, B2, B3, + Uw, Uw2, Uw3, Dw, Dw2, Dw3, + Rw, Rw2, Rw3, Lw, Lw2, Lw3, + Fw, Fw2, Fw3, Bw, Bw2, Bw3, + M, M2, M3, + S, S2, S3, + E, E2, E3, + x, x2, x3, + y, y2, y3, + z, z2, z3, +}; + +enum +trans +{ + uf, ur, ub, ul, + df, dr, db, dl, + rf, rd, rb, ru, + lf, ld, lb, lu, + fu, fr, fd, fl, + bu, br, bd, bl, + uf_mirror, ur_mirror, ub_mirror, ul_mirror, + df_mirror, dr_mirror, db_mirror, dl_mirror, + rf_mirror, rd_mirror, rb_mirror, ru_mirror, + lf_mirror, ld_mirror, lb_mirror, lu_mirror, + fu_mirror, fr_mirror, fd_mirror, fl_mirror, + bu_mirror, br_mirror, bd_mirror, bl_mirror, +}; + + +/* Structs *******************************************************************/ + +struct +alg +{ + Move * move; + bool * inv; + int len; + int allocated; +}; + +struct +alglist +{ + AlgListNode * first; + AlgListNode * last; + int len; +}; + +struct +alglistnode +{ + Alg * alg; + AlgListNode * next; +}; + +struct +block +{ + bool edge[12]; + bool corner[8]; + bool center[6]; +}; + +struct +coordinate +{ + Indexer index; + AntiIndexer cube; + Checker check; + uint64_t max; +}; + +struct +cube +{ + int epose; + int eposs; + int eposm; + int eofb; + int eorl; + int eoud; + int cp; + int coud; + int cofb; + int corl; + int cpos; +}; + +struct +cubearray +{ + int * ep; + int * eofb; + int * eorl; + int * eoud; + int * cp; + int * coud; + int * corl; + int * cofb; + int * cpos; +}; + +struct +cubetarget +{ + Cube cube; + int target; +}; + +struct +dfsdata +{ + int d; + int m; + int lb; + bool niss; + Move last1; + Move last2; + AlgList * sols; + Alg * current_alg; + Move sorted_moves[NMOVES]; + int move_position[NMOVES]; +}; + +struct +piecefilter +{ + 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; + uint8_t * ptable; + uint8_t * reached; + bool generated; + uint64_t n; + Coordinate * coord; + Moveset moveset; +}; + +struct +solveoptions +{ + int min_moves; + int max_moves; + int max_solutions; + bool optimal_only; + bool can_niss; + bool feedback; +}; + +struct +step +{ + Estimator estimate; + Checker ready; + Moveset moveset; +}; + +struct +symdata +{ + char * filename; + bool generated; + Coordinate * coord; + Coordinate * sym_coord; + int ntrans; + Trans * trans; + uint64_t * class; + Cube * rep; + Trans * transtorep; +}; + +#endif diff --git a/old/2021-06-30-reached/macros.h b/old/2021-06-30-reached/macros.h new file mode 100644 index 0000000..af3bca1 --- /dev/null +++ b/old/2021-06-30-reached/macros.h @@ -0,0 +1,23 @@ +#ifndef MACROS_H +#define MACROS_H + +#define POW2TO6 64ULL +#define POW2TO11 2048ULL +#define POW2TO12 4096ULL +#define POW3TO7 2187ULL +#define POW3TO8 6561ULL +#define FACTORIAL4 24ULL +#define FACTORIAL6 720ULL +#define FACTORIAL7 5040ULL +#define FACTORIAL8 40320ULL +#define FACTORIAL12 479001600ULL +#define BINOM12ON4 495ULL +#define BINOM8ON4 70ULL +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +#define NMOVES (z3+1) +#define NTRANS 48 +#define NROTATIONS 24 + +#endif diff --git a/old/2021-06-30-reached/main.c b/old/2021-06-30-reached/main.c new file mode 100644 index 0000000..1ebd917 --- /dev/null +++ b/old/2021-06-30-reached/main.c @@ -0,0 +1,80 @@ +#include +#include "cube.h" +#include "steps.h" + +int main() { + Alg *algo; + AlgList *sols; + Cube cube; + SolveOptions opts; + char line[1000]; + int i, ns = 2; +/* Move m;*/ +/* int nrand = 10000, sum1, sum2, sum3;*/ + + Step *stps[20] = {&drud_HTM, &optimal_HTM}; + char sss[30][30] = {"DR on UD", "Optimal solve"}; + + opts = (SolveOptions) { + .min_moves = 0, + .max_moves = 20, + .optimal_only = true, + .max_solutions = 1, + .can_niss = false, + .feedback = true, + }; + + init(); + +/* + srand(time(NULL)); + sum1 = 0; + sum2 = 0; + sum3 = 0; + for (i = 0; i < nrand; i++) { + cube = random_cube(); + sum1 += drud_HTM.check(cube, 20); + sum2 += optimal_HTM.check(cube, 20); + sum3 += cornershtreofb_HTM.check(cube, 20); + } + printf("Average drud pruning: %lf\n", ((double)sum1) / ((double) nrand)); + printf("Average corners htr pruning: %lf\n", ((double)sum2) / ((double) nrand)); + printf("Average corners htr + eofb pruning: %lf\n", ((double)sum3) / ((double) nrand)); +*/ + +/* + for (m = U; m <= B3; m++) { + printf("Class eofbepos after %d: ", m); + printf("%lu\n", coord_khuge.index(apply_move(m,(Cube){0}))); + } +*/ + + printf("Welcome to nissy 2.0! Insert a scramble:\n"); + + if (fgets(line, 1000, stdin) != NULL) { + algo = new_alg(line); + cube = apply_alg(algo, (Cube){0}); + + print_alg(inverse_alg(algo), false); +/* + printf("After rb_mirror:\n"); + cube = apply_trans(rb_mirror, cube); + print_cube(cube); + printf("Going back:\n"); + cube = apply_trans(inverse_trans(rb_mirror), cube); +*/ + + print_cube(cube); + + for (i = 0; i < ns; i++) { + sols = solve(cube, *stps[i], &opts); + printf("%s: %d solutions found:\n", sss[i], sols->len); + print_alglist(sols, true); + free_alglist(sols); + } + free_alg(algo); + } + + return 0; +} + diff --git a/old/2021-06-30-reached/steps.c b/old/2021-06-30-reached/steps.c new file mode 100644 index 0000000..bc833cb --- /dev/null +++ b/old/2021-06-30-reached/steps.c @@ -0,0 +1,307 @@ +#include "steps.h" + +/* Standard checkers (return lower bound) ************************************/ + +static int estimate_eofb_HTM(CubeTarget ct); +static int estimate_coud_HTM(CubeTarget ct); +static int estimate_coud_URF(CubeTarget ct); +static int estimate_corners_HTM(CubeTarget ct); +static int estimate_cornershtr_HTM(CubeTarget ct); +static int estimate_corners_URF(CubeTarget ct); +static int estimate_cornershtr_URF(CubeTarget ct); +static int estimate_drud_HTM(CubeTarget ct); +static int estimate_optimal_HTM(CubeTarget ct); + +/* Steps *********************************************************************/ + +Step +eofb_HTM = { + .estimate = estimate_eofb_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + +Step +coud_HTM = { + .estimate = estimate_coud_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + +Step +coud_URF = { + .estimate = estimate_coud_URF, + .ready = check_nothing, + .moveset = moveset_URF +}; + +Step +corners_HTM = { + .estimate = estimate_corners_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + +Step +cornershtr_HTM = { + .estimate = estimate_cornershtr_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + +Step +cornershtr_URF = { + .estimate = estimate_cornershtr_URF, + .ready = check_nothing, + .moveset = moveset_URF +}; + +Step +corners_URF = { + .estimate = estimate_corners_URF, + .ready = check_nothing, + .moveset = moveset_URF +}; + +Step +drud_HTM = { + .estimate = estimate_drud_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + +Step +optimal_HTM = { + .estimate = estimate_optimal_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + + +/* Pruning tables ************************************************************/ + +PruneData +pd_eofb_HTM = { + .filename = "ptable_eofb_HTM", + .coord = &coord_eofb, + .moveset = moveset_HTM +}; + +PruneData +pd_coud_HTM = { + .filename = "ptable_coud_HTM", + .coord = &coord_coud, + .moveset = moveset_HTM +}; + +PruneData +pd_cornershtr_HTM = { + .filename = "ptable_cornershtr_withcosets_HTM", + .coord = &coord_cornershtr, + .moveset = moveset_HTM +}; + +PruneData +pd_corners_HTM = { + .filename = "ptable_corners_HTM", + .coord = &coord_corners, + .moveset = moveset_HTM +}; + +PruneData +pd_drud_HTM = { + .filename = "ptable_drud_HTM", + .coord = &coord_drud, + .moveset = moveset_HTM +}; + +PruneData +pd_drud_sym16_HTM = { + .filename = "pd_drud_sym16_HTM", + .coord = &coord_drud_sym16, + .moveset = moveset_HTM, +}; + +PruneData +pd_khuge_HTM = { + .filename = "pd_khuge_HTM", + .coord = &coord_khuge, + .moveset = moveset_HTM +}; + + +/* Standard checkers (return lower bound) ************************************/ + +static int +estimate_eofb_HTM(CubeTarget ct) +{ + if (!pd_eofb_HTM.generated) + genptable(&pd_eofb_HTM); + + return ptableval(&pd_eofb_HTM, ct.cube); +} + +static int +estimate_coud_HTM(CubeTarget ct) +{ + if (!pd_coud_HTM.generated) + genptable(&pd_coud_HTM); + + return ptableval(&pd_coud_HTM, ct.cube); +} + +static int +estimate_coud_URF(CubeTarget ct) +{ + /* TODO: I can improve this by checking first the orientation of + * the corner in DBL and use that as a reference */ + + CubeTarget ct2 = {.cube = apply_move(z, ct.cube), .target = ct.target}; + CubeTarget ct3 = {.cube = apply_move(x, ct.cube), .target = ct.target}; + + int ud = estimate_coud_HTM(ct); + int rl = estimate_coud_HTM(ct2); + int fb = estimate_coud_HTM(ct3); + + return MIN(ud, MIN(rl, fb)); +} + +static int +estimate_corners_HTM(CubeTarget ct) +{ + if (!pd_corners_HTM.generated) + genptable(&pd_corners_HTM); + + return ptableval(&pd_corners_HTM, ct.cube); +} + +static int +estimate_cornershtr_HTM(CubeTarget ct) +{ + if (!pd_cornershtr_HTM.generated) + genptable(&pd_cornershtr_HTM); + + return ptableval(&pd_cornershtr_HTM, ct.cube); +} + +static int +estimate_cornershtr_URF(CubeTarget ct) +{ + /* TODO: I can improve this by checking first the corner in DBL + * and use that as a reference */ + + int c, ret = 15; + Trans i; + + for (i = 0; i < NROTATIONS; i++) { + ct.cube = apply_alg(rotation_alg(i), ct.cube); + c = estimate_cornershtr_HTM(ct); + ret = MIN(ret, c); + } + + return ret; +} + +static int +estimate_corners_URF(CubeTarget ct) +{ + /* TODO: I can improve this by checking first the corner in DBL + * and use that as a reference */ + + int c, ret = 15; + Trans i; + + for (i = 0; i < NROTATIONS; i++) { + ct.cube = apply_alg(rotation_alg(i), ct.cube); + c = estimate_corners_HTM(ct); + ret = MIN(ret, c); + } + + return ret; +} + +static int +estimate_drud_HTM(CubeTarget ct) +{ +/* + if (!pd_drud_HTM.generated) + genptable(&pd_drud_HTM); + + return ptableval(&pd_drud_HTM, ct.cube); +*/ + + if (!pd_drud_sym16_HTM.generated) + genptable(&pd_drud_sym16_HTM); + + return ptableval(&pd_drud_sym16_HTM, ct.cube); +} + +/* TODO: if lucky, remove this */ +/* +static int +estimate_optimal_HTM(CubeTarget ct) +{ + static Trans t1 = { .rot = rf, .mirror = false }; + static Trans t2 = { .rot = bd, .mirror = false }; + int dr1, dr2, dr3, cor, ret; + Cube cube = ct.cube; + + dr1 = estimate_drud_HTM(ct); + cor = estimate_corners_HTM(ct); + ret = MAX(dr1, cor); + + if (ret > ct.target) + return ret; + + ct.cube = apply_trans(t1, cube); + dr2 = estimate_drud_HTM(ct); + ret = MAX(ret, dr2); + + if (ret > ct.target) + return ret; + + ct.cube = apply_trans(t2, cube); + dr3 = estimate_drud_HTM(ct); + + if (dr1 == dr2 && dr2 == dr3 && dr1 != 0) + dr3++; + + ret = MAX(ret, dr3); + + if (ret == 0) + return check_ep(cube) ? 0 : 6; + + return ret; +} +*/ + +static int +estimate_optimal_HTM(CubeTarget ct) +{ + static Trans t2 = rf, t3 = bd; + + int dr1, dr2, dr3, cor, ret; + Cube cube = ct.cube; + + if (!pd_khuge_HTM.generated) + genptable(&pd_khuge_HTM); + + dr1 = ptableval(&pd_khuge_HTM, cube); + cor = estimate_corners_HTM(ct); + ret = MAX(dr1, cor); + + if (ret > ct.target) + return ret; + + cube = apply_trans(t2, ct.cube); + dr2 = ptableval(&pd_khuge_HTM, cube); + ret = MAX(ret, dr2); + + if (ret > ct.target) + return ret; + + cube = apply_trans(t3, ct.cube); + dr3 = ptableval(&pd_khuge_HTM, cube); + + return MAX(ret, dr3); +} diff --git a/old/2021-06-30-reached/steps.h b/old/2021-06-30-reached/steps.h new file mode 100644 index 0000000..81ae11c --- /dev/null +++ b/old/2021-06-30-reached/steps.h @@ -0,0 +1,24 @@ +#ifndef STEPS_H +#define STEPS_H + +#include "cube.h" + +extern Step eofb_HTM; +extern Step coud_HTM; +extern Step coud_URF; +extern Step corners_HTM; +extern Step cornershtr_HTM; +extern Step corners_URF; +extern Step cornershtr_URF; +extern Step drud_HTM; +extern Step optimal_HTM; + +extern PruneData pd_eofb_HTM; +extern PruneData pd_coud_HTM; +extern PruneData pd_corners_HTM; +extern PruneData pd_cornershtr_HTM; +extern PruneData pd_cornershtreofb_HTM; +extern PruneData pd_drud_HTM; +extern PruneData pd_khuge_HTM; + +#endif diff --git a/old/2021-07-02-genptable-dfs/cube.c b/old/2021-07-02-genptable-dfs/cube.c new file mode 100644 index 0000000..a7d137c --- /dev/null +++ b/old/2021-07-02-genptable-dfs/cube.c @@ -0,0 +1,3394 @@ +#include "cube.h" + +/* Local functions **********************************************************/ + +static Cube admissible_ep(Cube cube, PieceFilter f); +static Cube admissible_eos_from_eofbepos(Cube cube); +static bool allowed_next(Move move, DfsData *dd); +static void append_alg(AlgList *l, Alg *alg); +static void append_move(Alg *alg, Move m, bool inverse); +static Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a); +static void apply_permutation(int *perm, int *set, int n); +static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f); +static int array_ep_to_epos(int *ep, int *eps_solved); +static Cube arrays_to_cube(CubeArray *arr, PieceFilter f); +static int binomial(int n, int k); +static Cube compose_filtered(Cube c2, Cube c1, PieceFilter f); +static void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f); +static void dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static void dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static bool dfs_check_solved(SolveOptions *opts, DfsData *dd); +static void dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static bool dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static int digit_array_to_int(int *a, int n, int b); +static int edge_slice(Edge e); /* E=0, S=1, M=2 */ +static int epos_dependent_pos(int pos1, int pos2); +static int epos_from_arrays(int *epos, int *ep); +static void epos_to_partial_ep(int epos, int *ep, int *ss); +static int factorial(int n); +static void free_alglistnode(AlgListNode *aln); +static void free_cubearray(CubeArray *arr, PieceFilter f); +static void genptable_dfs(Cube c, PruneData *pd, DfsData *dd); +static void genptable_dfs_branch(Cube c, PruneData *pd, DfsData *dd); +static void gensym(SymData *sd); +static void index_to_perm(int p, int n, int *r); +static void index_to_subset(int s, int n, int k, int *r); +static void init_auxtables(); +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_environment(); +static void init_moves(); +static void init_moves_aux(); +static void init_strings(); +static void init_symdata(); +static void init_trans(); +static void init_trans_aux(); +static void int_to_digit_array(int a, int b, int n, int *r); +static void int_to_sum_zero_array(int x, int b, int n, int *a); +static int invert_digits(int a, int b, int n); +static bool is_perm(int *a, int n); +static bool is_subset(int *a, int n, int k); +static Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf); +static void movelist_to_position(Move *movelist, int *position); +static void moveset_to_list(Moveset ms, Estimator f, Move *r); +static AlgList * new_alglist(); +static CubeArray * new_cubearray(Cube cube, PieceFilter f); +static int perm_sign(int *a, int n); +static int perm_to_index(int *a, int n); +static int powint(int a, int b); +static void ptable_update(PruneData *pd, Cube cube, int m); +static void realloc_alg(Alg *alg, int n); +static bool read_mtables_file(); +static bool read_ptable_file(PruneData *pd); +static bool read_symdata_file(SymData *sd); +static bool read_ttables_file(); +static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f); +static int subset_to_index(int *a, int n, int k); +static void sum_arrays_mod(int *src, int *dst, int n, int m); +static void swap(int *a, int *b); +static bool write_mtables_file(); +static bool write_ptable_file(PruneData *pd); +static bool write_symdata_file(SymData *sd); +static bool write_ttables_file(); + + +/* All sorts of useful costants and tables **********************************/ + +static char * tabledir; + +static PieceFilter pf_all; +static PieceFilter pf_4val; +static PieceFilter pf_epcp; +static PieceFilter pf_cpos; +static PieceFilter pf_cp; +static PieceFilter pf_ep; +static PieceFilter pf_e; +static PieceFilter pf_s; +static PieceFilter pf_m; +static PieceFilter pf_eo; +static PieceFilter pf_co; + +static int epe_solved[4]; +static int eps_solved[4]; +static int epm_solved[4]; + +static char move_string[NMOVES][7]; +static char edge_string[12][7]; +static char corner_string[8][7]; +static char center_string[6][7]; + +static Cube admissible_ee_aux[POW2TO11*BINOM12ON4]; +static bool commute[NMOVES][NMOVES]; +static bool possible_next[NMOVES][NMOVES][NMOVES]; +static Move inverse_move_aux[NMOVES]; +static Trans inverse_trans_aux[NTRANS]; +static int epos_dependent_aux[BINOM12ON4][BINOM12ON4]; +static int cphtr_left_cosets[FACTORIAL8]; +static int cphtr_right_cosets[FACTORIAL8]; +static int cphtr_right_rep[BINOM8ON4*6]; +static Center what_center_at_aux[FACTORIAL6][6]; +static Corner what_corner_at_aux[FACTORIAL8][8]; +static int what_orientation_last_corner_aux[POW3TO7]; +static int what_orientation_last_edge_aux[POW2TO11]; +static Center where_is_center_aux[FACTORIAL6][6]; +static Corner where_is_corner_aux[FACTORIAL8][8]; +static Edge where_is_edge_aux[3][FACTORIAL12/FACTORIAL8][12]; + +static int epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static int eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static int eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static int eo_ttable[NTRANS][POW2TO11]; +static int cp_ttable[NTRANS][FACTORIAL8]; +static int co_ttable[NTRANS][POW3TO7]; +static int cpos_ttable[NTRANS][FACTORIAL6]; +static Move moves_ttable[NTRANS][NMOVES]; + +static int epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static int eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static int eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static int eofb_mtable[NMOVES][POW2TO11]; +static int eorl_mtable[NMOVES][POW2TO11]; +static int eoud_mtable[NMOVES][POW2TO11]; +static int cp_mtable[NMOVES][FACTORIAL8]; +static int coud_mtable[NMOVES][POW3TO7]; +static int cofb_mtable[NMOVES][POW3TO7]; +static int corl_mtable[NMOVES][POW3TO7]; +static int cpos_mtable[NMOVES][FACTORIAL6]; + +static uint64_t me[12]; + +static int edge_cycle[NMOVES][12]; +static int corner_cycle[NMOVES][8]; +static int center_cycle[NMOVES][6]; +static int eofb_flipped[NMOVES][12]; +static int eorl_flipped[NMOVES][12]; +static int eoud_flipped[NMOVES][12]; +static int coud_flipped[NMOVES][8]; +static int corl_flipped[NMOVES][8]; +static int cofb_flipped[NMOVES][8]; +static Alg * equiv_alg[NMOVES]; + +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]; +static int ep_mirror[12]; +static int cp_mirror[8]; +static int cpos_mirror[6]; +static Alg * rotation_algs[NROTATIONS]; + + +/* Symmetry data for some coordinates ****************************************/ + +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, +}; + +SymData +sd_coud_16 = { + .filename = "sd_coud_16", + .coord = &coord_coud, + .sym_coord = &coord_coud_sym16, + .ntrans = 16, + .trans = trans_group_udfix +}; + +SymData +sd_eofbepos_16 = { + .filename = "sd_eofbepos_16", + .coord = &coord_eofbepos, + .sym_coord = &coord_eofbepos_sym16, + .ntrans = 16, + .trans = trans_group_udfix +}; + +static int n_all_symdata = 2; +static SymData * all_sd[2] = { &sd_coud_16, &sd_eofbepos_16 }; + +/* Coordinates and their implementation **************************************/ + +static uint64_t index_eofb(Cube cube); +static uint64_t index_eofbepos(Cube cube); +static uint64_t index_coud(Cube cube); +static uint64_t index_corners(Cube cube); +static uint64_t index_cornershtr(Cube cube); +static uint64_t index_drud(Cube cube); +static uint64_t index_coud_sym16(Cube cube); +static uint64_t index_eofbepos_sym16(Cube cube); +static uint64_t index_drud_sym16(Cube cube); +static uint64_t index_khuge(Cube cube); + +static Cube antindex_eofb(uint64_t ind); +static Cube antindex_eofbepos(uint64_t ind); +static Cube antindex_coud(uint64_t ind); +static Cube antindex_corners(uint64_t ind); +static Cube antindex_cornershtr(uint64_t ind); +static Cube antindex_drud(uint64_t ind); +static Cube antindex_coud_sym16(uint64_t ind); +static Cube antindex_eofbepos_sym16(uint64_t ind); +static Cube antindex_drud_sym16(uint64_t ind); +static Cube antindex_khuge(uint64_t ind); + +Coordinate +coord_eofb = { + .index = index_eofb, + .cube = antindex_eofb, + .check = check_eofb, + .max = POW2TO11 +}; + +Coordinate +coord_eofbepos = { + .index = index_eofbepos, + .cube = antindex_eofbepos, + .check = check_eofbepos, + .max = POW2TO11 * BINOM12ON4 +}; + +Coordinate +coord_coud = { + .index = index_coud, + .cube = antindex_coud, + .check = check_coud, + .max = POW3TO7 +}; + +Coordinate +coord_corners = { + .index = index_corners, + .cube = antindex_corners, + .check = check_corners, + .max = POW3TO7 * FACTORIAL8 +}; + +Coordinate +coord_cornershtr = { + .index = index_cornershtr, + .cube = antindex_cornershtr, + .check = check_cornershtr, + .max = POW3TO7 * BINOM8ON4 * 6 +}; + +Coordinate +coord_drud = { + .index = index_drud, + .cube = antindex_drud, + .check = check_drud, + .max = POW2TO11 * POW3TO7 * BINOM12ON4 +}; + +Coordinate +coord_eofbepos_sym16 = { + .index = index_eofbepos_sym16, + .cube = antindex_eofbepos_sym16, + .check = check_eofbepos, +}; + +Coordinate +coord_coud_sym16 = { + .index = index_coud_sym16, + .cube = antindex_coud_sym16, + .check = check_coud, +}; + +Coordinate +coord_drud_sym16 = { + .index = index_drud_sym16, + .cube = antindex_drud_sym16, + .check = check_drud, + .max = POW3TO7 * 64430 +}; + +Coordinate +coord_khuge = { + .index = index_khuge, + .cube = antindex_khuge, + .check = check_khuge, + .max = POW3TO7 * FACTORIAL4 * 64430 +}; + + +static uint64_t +index_eofb(Cube cube) +{ + return cube.eofb; +} + +static uint64_t +index_eofbepos(Cube cube) +{ + return (cube.epose / FACTORIAL4) * POW2TO11 + cube.eofb; +} + +static uint64_t +index_coud(Cube cube) +{ + return cube.coud; +} + +static uint64_t +index_corners(Cube cube) +{ + return cube.coud * FACTORIAL8 + cube.cp; +} + +static uint64_t +index_cornershtr(Cube cube) +{ + return cube.coud * BINOM8ON4 * 6 + cphtr(cube); +} + +static uint64_t +index_drud(Cube cube) +{ + uint64_t a, b, c; + + a = cube.eofb; + b = cube.coud; + c = cube.epose / FACTORIAL4; + + b *= POW2TO11; + c *= POW2TO11 * POW3TO7; + + return a + b + c; +} + +static uint64_t +index_coud_sym16(Cube cube) +{ + return sd_coud_16.class[index_coud(cube)]; +} + +static uint64_t +index_drud_sym16(Cube cube) +{ + Trans t; + Cube c; + + t = sd_eofbepos_16.transtorep[index_eofbepos(cube)]; + c = apply_trans(t, cube); + + return index_eofbepos_sym16(c) * POW3TO7 + c.coud; +} + +static uint64_t +index_eofbepos_sym16(Cube cube) +{ + return sd_eofbepos_16.class[index_eofbepos(cube)]; +} + +static uint64_t +index_khuge(Cube cube) +{ + Trans t; + Cube c; + uint64_t a; + + t = sd_eofbepos_16.transtorep[index_eofbepos(cube)]; + c = apply_trans(t, cube); + a = (index_eofbepos_sym16(c) * 24) + (c.epose % 24); + + return a * POW3TO7 + c.coud; +} + + +/* TODO: rename */ +static Cube +antindex_eofb(uint64_t ind) +{ + return (Cube){ .eofb = ind, .eorl = ind, .eoud = ind }; +} + +static Cube +antindex_eofbepos(uint64_t ind) +{ + return admissible_ee_aux[ind]; +} + +/* TODO: rename */ +static Cube +antindex_coud(uint64_t ind) +{ + return (Cube){ .coud = ind, .corl = ind, .cofb = ind }; +} + +/* TODO: admissible co for other orientations */ +static Cube +antindex_corners(uint64_t ind) +{ + Cube c = {0}; + + c.coud = ind / FACTORIAL8; + c.cp = ind % FACTORIAL8; + + return c; +} + +/* TODO: admissible co for other orientations */ +static Cube +antindex_cornershtr(uint64_t ind) +{ + Cube c = anti_cphtr(ind % (BINOM8ON4 * 6)); + + c.coud = ind / (BINOM8ON4 * 6); + + return c; +} + +/* TODO: admissible eos and cos */ +static Cube +antindex_drud(uint64_t ind) +{ + Cube c = {0}; + + c.eofb = ind % POW2TO11; + c.coud = (ind / POW2TO11) % POW3TO7; + c.epose = (ind % (POW2TO11 * POW3TO7)) * FACTORIAL4; + + return c; +} + +static Cube +antindex_coud_sym16(uint64_t ind) +{ + return sd_coud_16.rep[ind]; +} + +static Cube +antindex_eofbepos_sym16(uint64_t ind) +{ + return sd_eofbepos_16.rep[ind]; +} + +static Cube +antindex_drud_sym16(uint64_t ind) +{ + Cube c; + + c = sd_eofbepos_16.rep[ind/POW3TO7]; + c.coud = ind % POW3TO7; + c.cofb = c.coud; + c.corl = c.coud; + + return c; +} + +static Cube +antindex_khuge(uint64_t ind) +{ + Cube c; + + c = sd_eofbepos_16.rep[ind/(FACTORIAL4*POW3TO7)]; + c.epose = ((c.epose / 24) * 24) + ((ind/POW3TO7) % 24); + c.coud = ind % POW3TO7; + + return c; +} + + +/* Checkers ******************************************************************/ + +bool +check_centers(Cube cube) +{ + return cube.cpos == 0; +} + +bool +check_corners(Cube cube) +{ + return cube.cp == 0 && cube.coud == 0; +} + +bool +check_cornershtr(Cube cube) +{ + return cube.coud == 0 && cphtr(cube) == 0; /* TODO: use array cphtrcosets*/ +} + +bool +check_coud(Cube cube) +{ + return cube.coud == 0; +} + +bool +check_drud(Cube cube) +{ + return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0; +} + +bool +check_eofb(Cube cube) +{ + return cube.eofb == 0; +} + +bool +check_eofbepos(Cube cube) +{ + return cube.eofb == 0 && cube.epose / 24 == 0; +} + +bool +check_epose(Cube cube) +{ + return cube.epose == 0; +} + +bool +check_ep(Cube cube) +{ + return cube.epose == 0 && cube.eposs == 0 && cube.eposm == 0; +} + +bool +check_khuge(Cube cube) +{ + return check_drud(cube) && cube.epose % 24 == 0; +} + +bool +check_nothing(Cube cube) +{ + return is_admissible(cube); /*TODO: maybe change?*/ +} + +/* Movesets ******************************************************************/ + +bool +moveset_HTM(Move m) +{ + return m >= U && m <= B3; +} + +bool +moveset_URF(Move m) +{ + Move b = base_move(m); + + return b == U || b == R || b == F; +} + + +/* Local functions implementation ********************************************/ + +/* TODO: this should be an anti index (maybe?) */ +static 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 < 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; +} + +static Cube +admissible_eos_from_eofbepos(Cube cube) +{ + Edge e; + Cube ret; + CubeArray *arr = new_cubearray(cube, pf_all); + + memcpy(arr->eorl, arr->eofb, 12 * sizeof(int)); + memcpy(arr->eoud, arr->eofb, 12 * sizeof(int)); + + for (e = 0; e < 12; e++) { + if ((edge_slice(e) != 0 && edge_slice(arr->ep[e]) == 0) || + (edge_slice(e) == 0 && edge_slice(arr->ep[e]) != 0)) + arr->eorl[e] = 1 - arr->eorl[e]; + if ((edge_slice(e) != 2 && edge_slice(arr->ep[e]) == 2) || + (edge_slice(e) == 2 && edge_slice(arr->ep[e]) != 2)) + arr->eoud[e] = 1 - arr->eoud[e]; + } + + ret = arrays_to_cube(arr, pf_all); + free_cubearray(arr, pf_all); + + return ret; +} + +static bool +allowed_next(Move move, DfsData *dd) +{ + if (!possible_next[dd->last2][dd->last1][move]) + return false; + + if (commute[dd->last1][move]) + return dd->move_position[dd->last1] < dd->move_position[move]; + + return true; +} + +static void +append_alg(AlgList *l, Alg *alg) +{ + AlgListNode *node = malloc(sizeof(AlgListNode)); + int i; + + node->alg = new_alg(""); + for (i = 0; i < alg->len; i++) + append_move(node->alg, alg->move[i], alg->inv[i]); + node->next = NULL; + + if (++l->len == 1) + l->first = node; + else + l->last->next = node; + l->last = node; +} + +static void +append_move(Alg *alg, Move m, bool inverse) +{ + if (alg->len == alg->allocated) + realloc_alg(alg, 2*alg->len); + + alg->move[alg->len] = m; + alg->inv [alg->len] = inverse; + alg->len++; +} + +static Cube +apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a) +{ + Cube ret = {0}; + int i; + + for (i = 0; i < alg->len; i++) + if (alg->inv[i]) + ret = a ? apply_move(alg->move[i], ret) : + apply_move_cubearray(alg->move[i], ret, f); + + ret = compose_filtered(c, inverse_cube(ret), f); + + for (i = 0; i < alg->len; i++) + if (!alg->inv[i]) + ret = a ? apply_move(alg->move[i], ret) : + apply_move_cubearray(alg->move[i], ret, f); + + return ret; +} + +static void +apply_permutation(int *perm, int *set, int n) +{ + int *aux = malloc(n * sizeof(int)); + int i; + + if (!is_perm(perm, n)) + return; + + for (i = 0; i < n; i++) + aux[i] = set[perm[i]]; + + memcpy(set, aux, n * sizeof(int)); + free(aux); +} + +static Cube +apply_move_cubearray(Move m, Cube cube, PieceFilter f) +{ + 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); +} + +static int +array_ep_to_epos(int *ep, int *ss) +{ + 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 epos_from_arrays(epos, eps); +} + +static Cube +arrays_to_cube(CubeArray *arr, PieceFilter f) +{ + Cube ret = {0}; + + 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; +} + +static int +binomial(int n, int k) +{ + if (n < 0 || k < 0 || k > n) + return 0; + + return factorial(n) / (factorial(k) * factorial(n-k)); +} + +static Cube +compose_filtered(Cube c2, Cube c1, PieceFilter f) +{ + CubeArray *arr = new_cubearray(c2, f); + Cube ret; + + ret = move_via_arrays(arr, c1, f); + free_cubearray(arr, f); + + return ret; +} + +static void +cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f) +{ + int i; + + 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); +} + +/* +static int +cphtr_cp(int cp) +{ + int i, a[8]; + + index_to_perm(cp, 8, a); + + for (i = 0; i < 8; i++) + if (a[i] == UFR || a[i] == UBL || a[i] == DFL || a[i] == DBR) + a[i] = 0; + else + a[i] = 1; + + swap(&a[1], &a[5]); + swap(&a[3], &a[7]); + + return subset_to_index(a, 8, 4); +} +*/ + +static void +dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + if (dfs_stop(c, s, opts, dd)) + return; + + if (dfs_check_solved(opts, dd)) + return; + + dfs_branch(c, s, opts, dd); + + if (opts->can_niss && !dd->niss) + dfs_niss(c, s, opts, dd); +} + +static void +dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + Move m, l1 = dd->last1, l2 = dd->last2, *moves = dd->sorted_moves; + + int i, maxnsol = opts->max_solutions; + + for (i = 0; moves[i] != NULLMOVE && dd->sols->len < maxnsol; i++) { + m = moves[i]; + if (allowed_next(m, dd)) { + dd->last2 = dd->last1; + dd->last1 = m; + append_move(dd->current_alg, m, dd->niss); + + dfs(apply_move(m, c), s, opts, dd); + + dd->current_alg->len--; + dd->last2 = l2; + dd->last1 = l1; + } + } +} + +static bool +dfs_check_solved(SolveOptions *opts, DfsData *dd) +{ + if (dd->lb != 0) + return false; + + if (dd->current_alg->len == dd->d) { + append_alg(dd->sols, dd->current_alg); + + if (opts->feedback) + print_alg(dd->current_alg, false); + } + + return true; +} + +static void +dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + Move l1 = dd->last1, l2 = dd->last2; + CubeTarget ct; + + ct.cube = apply_move(inverse_move(l1), (Cube){0}); + ct.target = 1; + + if (dd->current_alg->len == 0 || s.estimate(ct)) { + dd->niss = true; + dd->last1 = NULLMOVE; + dd->last2 = NULLMOVE; + + dfs(inverse_cube(c), s, opts, dd); + + dd->last1 = l1; + dd->last2 = l2; + dd->niss = false; + } +} + +static bool +dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + CubeTarget ct = { + .cube = c, + .target = dd->d - dd->current_alg->len + }; + + if (dd->sols->len >= opts->max_solutions) + return true; + + dd->lb = s.estimate(ct); + if (opts->can_niss && !dd->niss) + dd->lb = MIN(1, dd->lb); + + if (dd->current_alg->len + dd->lb > dd->d) + return true; + + return false; +} + +static int +digit_array_to_int(int *a, int n, int b) +{ + int i, ret = 0, p = 1; + + for (i = 0; i < n; i++, p *= b) + ret += a[i] * p; + + return ret; +} + +static int +edge_slice(Edge e) { + if (e < 0 || e > 11) + return -1; + + if (e == FR || e == FL || e == BL || e == BR) + return 0; + if (e == UR || e == UL || e == DR || e == DL) + return 1; + + return 2; +} + +static int +epos_dependent_pos(int poss, int pose) +{ + int ep[12] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; + int ep8[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + int i, j; + + epos_to_partial_ep(poss*FACTORIAL4, ep, eps_solved); + epos_to_partial_ep(pose*FACTORIAL4, ep, epe_solved); + + for (i = 0, j = 0; i < 12; i++) + if (edge_slice(ep[i]) != 0) + ep8[j++] = (edge_slice(ep[i]) == 1) ? 1 : 0; + + swap(&ep8[1], &ep8[4]); + swap(&ep8[3], &ep8[6]); + + return subset_to_index(ep8, 8, 4); +} + +static int +epos_from_arrays(int *epos, int *ep) +{ + return FACTORIAL4 * subset_to_index(epos,12,4) + perm_to_index(ep,4); +} + +static void +epos_to_partial_ep(int epos, int *ep, int *ss) +{ + 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++]]; +} + +static int +factorial(int n) +{ + int i, ret = 1; + + if (n < 0) + return 0; + + for (i = 1; i <= n; i++) + ret *= i; + + return ret; +} + +void +free_alg(Alg *alg) +{ + free(alg->move); + free(alg->inv); + free(alg); +} + +void +free_alglist(AlgList *l) +{ + AlgListNode *aux, *i = l->first; + + while (i != NULL) { + aux = i->next; + free_alglistnode(i); + i = aux; + } + free(l); +} + +void +free_alglistnode(AlgListNode *aln) +{ + free_alg(aln->alg); + free(aln); +} + +static void +free_cubearray(CubeArray *arr, PieceFilter f) +{ + 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); +} + +static void +genptable_dfs(Cube c, PruneData *pd, DfsData *dd) +{ + int oldval = ptableval(pd, c); + + if (oldval < dd->m || pd->n == pd->coord->max || + (dd->m != 0 && pd->coord->check(c)) ) + return; + + if (dd->m == dd->d) { + if (dd->m < oldval) + ptable_update(pd, c, dd->m); + return; + } + + genptable_dfs_branch(c, pd, dd); +} + +static void +genptable_dfs_branch(Cube c, PruneData *pd, DfsData *dd) +{ + Move i, move, l1 = dd->last1, l2 = dd->last2; + + dd->m++; + + for (i = 0; dd->sorted_moves[i] != NULLMOVE; i++) { + move = dd->sorted_moves[i]; + if (allowed_next(move, dd)) { + dd->last2 = dd->last1; + dd->last1 = move; + + genptable_dfs(apply_move(move, c), pd, dd); + + dd->last2 = l2; + dd->last1 = l1; + } + } + + dd->m--; +} + +static void +gensym(SymData *sd) +{ + uint64_t i, in, nreps = 0; + int j; + Cube c, d; + + if (sd->generated) + return; + + sd->class = malloc(sd->coord->max * sizeof(uint64_t)); + sd->rep = malloc(sd->coord->max * sizeof(Cube)); + sd->transtorep = malloc(sd->coord->max * sizeof(Trans)); + + 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) { + c = sd->coord->cube(i); + sd->rep[nreps] = c; + for (j = 0; j < sd->ntrans; j++) { + d = apply_trans(sd->trans[j], c); + in = sd->coord->index(d); + + if (sd->class[in] == sd->coord->max + 1) { + sd->class[in] = nreps; + sd->transtorep[in] = + inverse_trans(sd->trans[j]); + } + } + nreps++; + } + } + + sd->sym_coord->max = nreps; + sd->rep = realloc(sd->rep, nreps * sizeof(Cube)); + sd->generated = true; + + fprintf(stderr, "Found %lu classes\n", nreps); + + if (!write_symdata_file(sd)) + fprintf(stderr, "Error writing SymData file\n"); + + return; +} + +static void +index_to_perm(int p, int n, int *r) +{ + int *a = malloc(n * sizeof(int)); + int i, j, c; + + for (i = 0; i < n; i++) + a[i] = 0; + + if (p < 0 || p >= factorial(n)) + for (i = 0; i < n; i++) + r[i] = -1; + + for (i = 0; i < n; i++) { + c = 0; + j = 0; + while (c <= p / factorial(n-i-1)) + c += a[j++] ? 0 : 1; + r[i] = j-1; + a[j-1] = 1; + p %= factorial(n-i-1); + } + + free(a); +} + +static void +index_to_subset(int s, int n, int k, int *r) +{ + int i, j, v; + + if (s < 0 || s >= binomial(n, k)) { + for (i = 0; i < n; i++) + r[i] = -1; + return; + } + + for (i = 0; i < n; i++) { + if (k == n-i) { + for (j = i; j < n; j++) + r[j] = 1; + return; + } + + if (k == 0) { + for (j = i; j < n; j++) + r[j] = 0; + return; + } + + v = binomial(n-i-1, k); + if (s >= v) { + r[i] = 1; + k--; + s -= v; + } else { + r[i] = 0; + } + } +} + +static void +int_to_digit_array(int a, int b, int n, int *r) +{ + int i; + + if (b <= 1) + for (i = 0; i < n; i++) + r[i] = 0; + else + for (i = 0; i < n; i++, a /= b) + r[i] = a % b; +} + +static void +int_to_sum_zero_array(int x, int b, int n, int *a) +{ + int i, s = 0; + + if (b <= 1) { + for (i = 0; i < n; i++) + a[i] = 0; + } else { + int_to_digit_array(x, b, n-1, a); + for (i = 0; i < n - 1; i++) + s = (s + a[i]) % b; + a[n-1] = (b - s) % b; + } +} + +static int +invert_digits(int a, int b, int n) +{ + int i, ret, *r = malloc(n * sizeof(int)); + + int_to_digit_array(a, b, n, r); + for (i = 0; i < n; i++) + r[i] = (b-r[i]) % b; + + ret = digit_array_to_int(r, n, b); + free(r); + return ret; +} + +static bool +is_perm(int *a, int n) +{ + int *aux = malloc(n * sizeof(int)); + int i; + + for (i = 0; i < n; i++) + if (a[i] < 0 || a[i] >= n) + return false; + else + aux[a[i]] = 1; + + for (i = 0; i < n; i++) + if (!aux[i]) + return false; + + free(aux); + + return true; +} + +static bool +is_subset(int *a, int n, int k) +{ + int i, sum = 0; + + for (i = 0; i < n; i++) + sum += a[i] ? 1 : 0; + + return sum == k; +} + +static Cube +move_via_arrays(CubeArray *arr, Cube c, PieceFilter f) +{ + CubeArray *arrc = new_cubearray(c, f); + Cube ret; + + 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; +} + +static void +movelist_to_position(Move *movelist, int *position) +{ + Move m; + + for (m = 0; m < NMOVES && movelist[m] != NULLMOVE; m++) + position[movelist[m]] = m; +} + +static void +moveset_to_list(Moveset ms, Estimator f, Move *r) +{ + CubeTarget ct = { .target = 1 }; + int b[NMOVES]; + int na = 0, nb = 0; + Move i; + + if (ms == NULL) { + fprintf(stderr, "Error: no moveset given\n"); + return; + } + + for (i = U; i < NMOVES; i++) { + if (ms(i)) { + ct.cube = apply_move(i, (Cube){0}); + if (f != NULL && f(ct)) + r[na++] = i; + else + b[nb++] = i; + } + } + + memcpy(r + na, b, nb * sizeof(Move)); + r[na+nb] = NULLMOVE; +} + +static AlgList * +new_alglist() +{ + AlgList *ret = malloc(sizeof(AlgList)); + + ret->len = 0; + ret->first = NULL; + ret->last = NULL; + + return ret; +} + +static CubeArray * +new_cubearray(Cube cube, PieceFilter f) +{ + 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; +} + +static int +perm_sign(int *a, int n) +{ + int i, j, ret = 0; + + if (!is_perm(a,n)) + return -1; + + for (i = 0; i < n; i++) + for (j = i+1; j < n; j++) + ret += (a[i] > a[j]) ? 1 : 0; + + return ret % 2; +} + +static int +perm_to_index(int *a, int n) +{ + int i, j, c, ret = 0; + + if (!is_perm(a, n)) + return -1; + + for (i = 0; i < n; i++) { + c = 0; + for (j = i+1; j < n; j++) + c += (a[i] > a[j]) ? 1 : 0; + ret += factorial(n-i-1) * c; + } + + return ret; +} + +static int +powint(int a, int b) +{ + if (b < 0) + return 0; + if (b == 0) + return 1; + + if (b % 2) + return a * powint(a, b-1); + else + return powint(a*a, b/2); +} + +static void +ptable_update(PruneData *pd, Cube cube, int n) +{ + uint64_t ind = pd->coord->index(cube); + uint8_t oldval2 = pd->ptable[ind/2]; + int other = (ind % 2) ? oldval2 % 16 : oldval2 / 16; + + pd->ptable[ind/2] = (ind % 2) ? 16*n + other : 16*other + n; + pd->n++; +} + +static void +realloc_alg(Alg *alg, int n) +{ + if (alg == NULL) { + fprintf(stderr, "Error: trying to reallocate NULL alg.\n"); + return; + } + + if (n < alg->len) { + fprintf(stderr, "Error: alg too long for reallocation "); + fprintf(stderr, "(%d vs %d)\n", alg->len, n); + return; + } + + if (n > 1000000) { + fprintf(stderr, "Warning: very long alg,"); + fprintf(stderr, "something might go wrong.\n"); + } + + alg->move = realloc(alg->move, n * sizeof(int)); + alg->inv = realloc(alg->inv, n * sizeof(int)); + alg->allocated = n; +} + +static bool +read_mtables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int m, b = sizeof(int); + bool r = true; + + 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 +read_ptable_file(PruneData *pd) +{ + FILE *f; + char fname[strlen(tabledir)+100]; + uint64_t r; + + strcpy(fname, tabledir); + strcat(fname, "/"); + strcat(fname, pd->filename); + + if ((f = fopen(fname, "rb")) == NULL) + return false; + + r = fread(pd->ptable, sizeof(uint8_t), ptablesize(pd), f); + fclose(f); + + return r == ptablesize(pd); +} + +static bool +read_symdata_file(SymData *sd) +{ + 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->rep, sizeof(Cube), *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_ttables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int b = sizeof(int); + bool r = true; + Move m; + + 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[6], f) == me[6]; + r = r && fread(co_ttable[m], b, me[7], f) == me[7]; + r = r && fread(cpos_ttable[m], b, me[10], f) == me[10]; + r = r && fread(moves_ttable[m], b, me[11], f) == me[11]; + } + + 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_algs[r % NROTATIONS]); + 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_algs[r % NROTATIONS], ret, f, true); + if (r >= NROTATIONS) + ret = move_via_arrays(&ma, ret, f); + + free_alg(inv); + return ret; +} + +static int +subset_to_index(int *a, int n, int k) +{ + int i, ret = 0; + + if (!is_subset(a, n, k)) + return binomial(n, k); + + for (i = 0; i < n; i++) { + if (k == n-i) + return ret; + if (a[i]) { + ret += binomial(n-i-1, k); + k--; + } + } + + return ret; +} + +static void +sum_arrays_mod(int *src, int *dst, int n, int m) +{ + int i; + + for (i = 0; i < n; i++) + dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m; +} + +static void +swap(int *a, int *b) +{ + int aux; + + aux = *a; + *a = *b; + *b = aux; +} + +static bool +write_mtables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int m, b = sizeof(int); + bool r = true; + + 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; +} + +static bool +write_ptable_file(PruneData *pd) +{ + FILE *f; + char fname[strlen(tabledir)+100]; + uint64_t written; + + strcpy(fname, tabledir); + strcat(fname, "/"); + strcat(fname, pd->filename); + + if ((f = fopen(fname, "wb")) == NULL) + return false; + + written = fwrite(pd->ptable, sizeof(uint8_t), ptablesize(pd), f); + fclose(f); + + return written == ptablesize(pd); +} + +static bool +write_symdata_file(SymData *sd) +{ + 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->rep, sizeof(Cube), *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_ttables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + bool r = true; + int b = sizeof(int); + Move m; + + 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[6], f) == me[6]; + r = r && fwrite(co_ttable[m], b, me[7], f) == me[7]; + r = r && fwrite(cpos_ttable[m], b, me[10], f) == me[10]; + r = r && fwrite(moves_ttable[m], b, me[11], f) == me[11]; + } + + fclose(f); + return r; +} + +/* Init functions implementation *********************************************/ + +static void +init_auxtables() +{ + Cube c1, c2; + CubeArray *arr; + uint64_t ui, uj; + int i, j, k, auxarr[12]; + bool cij, p1, p2; + + for (ui = 0; ui < POW2TO11*BINOM12ON4; ui++) { + k = (ui / POW2TO11) * 24; + c1 = admissible_ep((Cube){ .epose = k }, pf_e); + c1.eofb = ui % POW2TO11; + c1 = admissible_eos_from_eofbepos(c1); + admissible_ee_aux[ui] = c1; + } + + for (ui = 0; ui < FACTORIAL6; ui++) { + arr = new_cubearray((Cube){.cpos = ui}, pf_cpos); + for (i = 0; i < 6; i++) { + what_center_at_aux[ui][i] = arr->cpos[i]; + where_is_center_aux[ui][arr->cpos[i]] = i; + } + free_cubearray(arr, pf_cpos); + } + + for (ui = 0; ui < FACTORIAL8; ui++) { + arr = new_cubearray((Cube){.cp = ui}, pf_cp); + for (i = 0; i < 8; i++) { + what_corner_at_aux[ui][i] = arr->cp[i]; + where_is_corner_aux[ui][arr->cp[i]] = i; + } + free_cubearray(arr, pf_cp); + } + + for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) { + arr = new_cubearray((Cube){.epose = ui}, pf_e); + for (i = 0; i < 12; i++) + if (edge_slice(arr->ep[i]) == 0) + where_is_edge_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) + where_is_edge_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) + where_is_edge_aux[2][ui][arr->ep[i]] = i; + free_cubearray(arr, pf_m); + } + + for (ui = 0; ui < POW3TO7; ui++) { + int_to_sum_zero_array(ui, 3, 8, auxarr); + what_orientation_last_corner_aux[ui] = auxarr[7]; + } + + for (ui = 0; ui < POW2TO11; ui++) { + int_to_sum_zero_array(ui, 2, 12, auxarr); + what_orientation_last_edge_aux[ui] = auxarr[11]; + } + + for (ui = 0; ui < BINOM12ON4; ui++) + for (uj = 0; uj < BINOM12ON4; uj++) + epos_dependent_aux[ui][uj]=epos_dependent_pos(ui, uj); + + for (i = 0; i < NMOVES; i++) { + for (j = 0; j < NMOVES; j++) { + c1 = apply_move(i, apply_move(j, (Cube){0})); + c2 = apply_move(j, apply_move(i, (Cube){0})); + commute[i][j] = equal(c1, c2) && i && j; + } + } + + for (i = 0; i < NMOVES; i++) { + for (j = 0; j < NMOVES; j++) { + for (k = 0; k < NMOVES; k++) { + p1 = j && base_move(j) == base_move(k); + p2 = i && base_move(i) == base_move(k); + cij = commute[i][j]; + possible_next[i][j][k] = !(p1 || (cij && p2)); + } + } + } + + for (i = 0; i < NMOVES; i++) + inverse_move_aux[i] = i ? i + 2 - 2*((i-1)%3) : NULLMOVE; + + /* Is there a more elegant way? */ + inverse_trans_aux[uf] = uf; + inverse_trans_aux[ur] = ul; + inverse_trans_aux[ul] = ur; + inverse_trans_aux[ub] = ub; + + inverse_trans_aux[df] = df; + inverse_trans_aux[dr] = dr; + inverse_trans_aux[dl] = dl; + inverse_trans_aux[db] = db; + + inverse_trans_aux[rf] = lf; + inverse_trans_aux[rd] = bl; + inverse_trans_aux[rb] = rb; + inverse_trans_aux[ru] = fr; + + inverse_trans_aux[lf] = rf; + inverse_trans_aux[ld] = br; + inverse_trans_aux[lb] = lb; + inverse_trans_aux[lu] = fl; + + inverse_trans_aux[fu] = fu; + inverse_trans_aux[fr] = ru; + inverse_trans_aux[fd] = bu; + inverse_trans_aux[fl] = lu; + + inverse_trans_aux[bu] = fd; + inverse_trans_aux[br] = ld; + inverse_trans_aux[bd] = bd; + inverse_trans_aux[bl] = rd; + + inverse_trans_aux[uf_mirror] = uf_mirror; + inverse_trans_aux[ur_mirror] = ur_mirror; + inverse_trans_aux[ul_mirror] = ul_mirror; + inverse_trans_aux[ub_mirror] = ub_mirror; + + inverse_trans_aux[df_mirror] = df_mirror; + inverse_trans_aux[dr_mirror] = dl_mirror; + inverse_trans_aux[dl_mirror] = dr_mirror; + inverse_trans_aux[db_mirror] = db_mirror; + + inverse_trans_aux[rf_mirror] = rf_mirror; + inverse_trans_aux[rd_mirror] = br_mirror; + inverse_trans_aux[rb_mirror] = lb_mirror; + inverse_trans_aux[ru_mirror] = fl_mirror; + + inverse_trans_aux[lf_mirror] = lf_mirror; + inverse_trans_aux[ld_mirror] = bl_mirror; + inverse_trans_aux[lb_mirror] = rb_mirror; + inverse_trans_aux[lu_mirror] = fr_mirror; + + inverse_trans_aux[fu_mirror] = fu_mirror; + inverse_trans_aux[fr_mirror] = lu_mirror; + inverse_trans_aux[fd_mirror] = bu_mirror; + inverse_trans_aux[fl_mirror] = ru_mirror; + + inverse_trans_aux[bu_mirror] = fd_mirror; + inverse_trans_aux[br_mirror] = rd_mirror; + inverse_trans_aux[bd_mirror] = bd_mirror; + inverse_trans_aux[bl_mirror] = ld_mirror; +} + +/* + * There is certainly a bette 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 < FACTORIAL8; i++) { + cphtr_left_cosets[i] = -1; + cphtr_right_cosets[i] = -1; + } + + /* 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++); + + /* 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++); +} + +static void +init_cphtr_left_cosets_bfs(int i, int c) +{ + int j, jj, k, next[FACTORIAL8], next2[FACTORIAL8], n, n2; + Move moves[6] = {U2, D2, R2, L2, F2, B2}; + + n = 1; + next[0] = i; + cphtr_left_cosets[i] = c; + + while (n != 0) { + for (j = 0, n2 = 0; j < n; j++) { + for (k = 0; k < 6; k++) { + jj = cp_mtable[moves[k]][next[j]]; + if (cphtr_left_cosets[jj] == -1) { + cphtr_left_cosets[jj] = c; + next2[n2++] = jj; + } + } + } + + for (j = 0; j < n2; j++) + next[j] = next2[j]; + n = n2; + } +} + +static void +init_cphtr_right_cosets_color(int i, int d) +{ + int cp; + unsigned int j; + + cphtr_right_rep[d] = i; + for (j = 0; j < FACTORIAL8; j++) { + if (cphtr_left_cosets[j] == 0) { + /* TODO: use antindexer, it's nicer */ + cp = compose((Cube){.cp = i}, (Cube){.cp = j}).cp; + cphtr_right_cosets[cp] = d; + } + } +} + +static void +init_environment() +{ + char *nissydata = getenv("NISSYDATA"); + char *localdata = getenv("XDG_DATA_HOME"); + char *home = getenv("HOME"); + bool read, write; + + if (nissydata != NULL) { + tabledir = malloc(strlen(nissydata) * sizeof(char) + 20); + strcpy(tabledir, nissydata); + } else if (localdata != NULL) { + tabledir = malloc(strlen(localdata) * sizeof(char) + 20); + strcpy(tabledir, localdata); + strcat(tabledir, "/nissy"); + } else if (home != NULL) { + tabledir = malloc(strlen(home) * sizeof(char) + 20); + strcpy(tabledir, home); + strcat(tabledir, "/.nissy"); + } + + mkdir(tabledir, 0777); + strcat(tabledir, "/tables"); + mkdir(tabledir, 0777); + + read = !access(tabledir, R_OK); + write = !access(tabledir, W_OK); + + if (!read) { + fprintf(stderr, "Table files cannot be read.\n"); + } else if (!write) { + fprintf(stderr, "Data directory not writable: "); + fprintf(stderr, "tables can be loaded, but not saved.\n"); + } +} + +static void +init_moves() { + Cube c; + CubeArray arrs; + int i; + unsigned int ui; + Move m; + + /* 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; + + fprintf(stderr, "Cannot load %s, generating it\n", "mtables"); + + /* Initialize transition tables */ + for (m = 0; m < NMOVES; m++) { + 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; + } + } + + if (!write_mtables_file()) + fprintf(stderr, "Error writing mtables\n"); +} + +static void +init_moves_aux() +{ + /* Some standard PieceFilters */ + pf_all.epose = true; + pf_all.eposs = true; + pf_all.eposm = true; + pf_all.eofb = true; + pf_all.eorl = true; + pf_all.eoud = true; + pf_all.cp = true; + pf_all.cofb = true; + pf_all.corl = true; + pf_all.coud = true; + pf_all.cpos = true; + + pf_4val.epose = true; + pf_4val.eposs = true; + pf_4val.eposm = true; + pf_4val.eofb = true; + pf_4val.coud = true; + pf_4val.cp = true; + + pf_epcp.epose = true; + pf_epcp.eposs = true; + pf_epcp.eposm = true; + pf_epcp.cp = true; + + pf_cpos.cpos = true; + + pf_cp.cp = true; + + pf_ep.epose = true; + pf_ep.eposs = true; + pf_ep.eposm = true; + + pf_e.epose = true; + pf_s.eposs = true; + pf_m.eposm = true; + + pf_eo.eofb = true; + pf_eo.eorl = true; + pf_eo.eoud = true; + + pf_co.cofb = true; + pf_co.corl = true; + pf_co.coud = true; + + /* Used to convert to and from CubeArray */ + epe_solved[0] = FR; + epe_solved[1] = FL; + epe_solved[2] = BL; + epe_solved[3] = BR; + + eps_solved[0] = UL; + eps_solved[1] = UR; + eps_solved[2] = DL; + eps_solved[3] = DR; + + epm_solved[0] = UF; + epm_solved[1] = UB; + epm_solved[2] = DF; + epm_solved[3] = DB; + + /* Table sizes, used for reading and writing files */ + me[0] = FACTORIAL12/FACTORIAL8; + me[1] = FACTORIAL12/FACTORIAL8; + me[2] = FACTORIAL12/FACTORIAL8; + me[3] = POW2TO11; + me[4] = POW2TO11; + me[5] = POW2TO11; + me[6] = FACTORIAL8; + me[7] = POW3TO7; + me[8] = POW3TO7; + me[9] = POW3TO7; + me[10] = FACTORIAL6; + me[11] = NMOVES; + + /* Cycles *********************/ + edge_cycle[U][UF] = UR; + edge_cycle[U][UL] = UF; + edge_cycle[U][UB] = UL; + edge_cycle[U][UR] = UB; + edge_cycle[U][DF] = DF; + edge_cycle[U][DL] = DL; + edge_cycle[U][DB] = DB; + edge_cycle[U][DR] = DR; + edge_cycle[U][FR] = FR; + edge_cycle[U][FL] = FL; + edge_cycle[U][BL] = BL; + edge_cycle[U][BR] = BR; + + edge_cycle[x][UF] = DF; + edge_cycle[x][UL] = FL; + edge_cycle[x][UB] = UF; + edge_cycle[x][UR] = FR; + edge_cycle[x][DF] = DB; + edge_cycle[x][DL] = BL; + edge_cycle[x][DB] = UB; + edge_cycle[x][DR] = BR; + edge_cycle[x][FR] = DR; + edge_cycle[x][FL] = DL; + edge_cycle[x][BL] = UL; + edge_cycle[x][BR] = UR; + + edge_cycle[y][UF] = UR; + edge_cycle[y][UL] = UF; + edge_cycle[y][UB] = UL; + edge_cycle[y][UR] = UB; + edge_cycle[y][DF] = DR; + edge_cycle[y][DL] = DF; + edge_cycle[y][DB] = DL; + edge_cycle[y][DR] = DB; + edge_cycle[y][FR] = BR; + edge_cycle[y][FL] = FR; + edge_cycle[y][BL] = FL; + edge_cycle[y][BR] = BL; + + corner_cycle[U][UFR] = UBR; + corner_cycle[U][UFL] = UFR; + corner_cycle[U][UBL] = UFL; + corner_cycle[U][UBR] = UBL; + corner_cycle[U][DFR] = DFR; + corner_cycle[U][DFL] = DFL; + corner_cycle[U][DBL] = DBL; + corner_cycle[U][DBR] = DBR; + + corner_cycle[x][UFR] = DFR; + corner_cycle[x][UFL] = DFL; + corner_cycle[x][UBL] = UFL; + corner_cycle[x][UBR] = UFR; + corner_cycle[x][DFR] = DBR; + corner_cycle[x][DFL] = DBL; + corner_cycle[x][DBL] = UBL; + corner_cycle[x][DBR] = UBR; + + corner_cycle[y][UFR] = UBR; + corner_cycle[y][UFL] = UFR; + corner_cycle[y][UBL] = UFL; + corner_cycle[y][UBR] = UBL; + corner_cycle[y][DFR] = DBR; + corner_cycle[y][DFL] = DFR; + corner_cycle[y][DBL] = DFL; + corner_cycle[y][DBR] = DBL; + + center_cycle[U][U_center] = U_center; + center_cycle[U][D_center] = D_center; + center_cycle[U][R_center] = R_center; + center_cycle[U][L_center] = L_center; + center_cycle[U][F_center] = F_center; + center_cycle[U][B_center] = B_center; + + center_cycle[x][U_center] = F_center; + center_cycle[x][D_center] = B_center; + center_cycle[x][R_center] = R_center; + center_cycle[x][L_center] = L_center; + center_cycle[x][F_center] = D_center; + center_cycle[x][B_center] = U_center; + + center_cycle[y][U_center] = U_center; + center_cycle[y][D_center] = D_center; + center_cycle[y][R_center] = B_center; + center_cycle[y][L_center] = F_center; + center_cycle[y][F_center] = R_center; + center_cycle[y][B_center] = L_center; + + /* Flipped pieces *************/ + eofb_flipped[x][UF] = 1; + eofb_flipped[x][UB] = 1; + eofb_flipped[x][DF] = 1; + eofb_flipped[x][DB] = 1; + + eofb_flipped[y][FR] = 1; + eofb_flipped[y][FL] = 1; + eofb_flipped[y][BL] = 1; + eofb_flipped[y][BR] = 1; + + eorl_flipped[x][UF] = 1; + eorl_flipped[x][UL] = 1; + eorl_flipped[x][UB] = 1; + eorl_flipped[x][UR] = 1; + eorl_flipped[x][DF] = 1; + eorl_flipped[x][DL] = 1; + eorl_flipped[x][DB] = 1; + eorl_flipped[x][DR] = 1; + eorl_flipped[x][FR] = 1; + eorl_flipped[x][FL] = 1; + eorl_flipped[x][BL] = 1; + eorl_flipped[x][BR] = 1; + + eorl_flipped[y][FR] = 1; + eorl_flipped[y][FL] = 1; + eorl_flipped[y][BL] = 1; + eorl_flipped[y][BR] = 1; + + eoud_flipped[U][UF] = 1; + eoud_flipped[U][UL] = 1; + eoud_flipped[U][UB] = 1; + eoud_flipped[U][UR] = 1; + + eoud_flipped[x][UF] = 1; + eoud_flipped[x][UB] = 1; + eoud_flipped[x][DF] = 1; + eoud_flipped[x][DB] = 1; + + eoud_flipped[y][UF] = 1; + eoud_flipped[y][UL] = 1; + eoud_flipped[y][UB] = 1; + eoud_flipped[y][UR] = 1; + eoud_flipped[y][DF] = 1; + eoud_flipped[y][DL] = 1; + eoud_flipped[y][DB] = 1; + eoud_flipped[y][DR] = 1; + eoud_flipped[y][FR] = 1; + eoud_flipped[y][FL] = 1; + eoud_flipped[y][BL] = 1; + eoud_flipped[y][BR] = 1; + + coud_flipped[x][UFR] = 2; + coud_flipped[x][UFL] = 1; + coud_flipped[x][UBR] = 1; + coud_flipped[x][UBL] = 2; + coud_flipped[x][DFR] = 1; + coud_flipped[x][DFL] = 2; + coud_flipped[x][DBR] = 2; + coud_flipped[x][DBL] = 1; + + corl_flipped[U][UFR] = 1; + corl_flipped[U][UFL] = 2; + corl_flipped[U][UBL] = 1; + corl_flipped[U][UBR] = 2; + + corl_flipped[y][UFR] = 1; + corl_flipped[y][UFL] = 2; + corl_flipped[y][UBL] = 1; + corl_flipped[y][UBR] = 2; + corl_flipped[y][DFR] = 2; + corl_flipped[y][DFL] = 1; + corl_flipped[y][DBL] = 2; + corl_flipped[y][DBR] = 1; + + cofb_flipped[U][UFR] = 2; + cofb_flipped[U][UFL] = 1; + cofb_flipped[U][UBL] = 2; + cofb_flipped[U][UBR] = 1; + + cofb_flipped[x][UFR] = 1; + cofb_flipped[x][UFL] = 2; + cofb_flipped[x][UBL] = 1; + cofb_flipped[x][UBR] = 2; + cofb_flipped[x][DFR] = 2; + cofb_flipped[x][DFL] = 1; + cofb_flipped[x][DBL] = 2; + cofb_flipped[x][DBR] = 1; + + cofb_flipped[y][UFR] = 2; + cofb_flipped[y][UFL] = 1; + cofb_flipped[y][UBL] = 2; + cofb_flipped[y][UBR] = 1; + cofb_flipped[y][DFR] = 1; + cofb_flipped[y][DFL] = 2; + cofb_flipped[y][DBL] = 1; + cofb_flipped[y][DBR] = 2; + + /* Equivalent moves ***********/ + equiv_alg[NULLMOVE] = new_alg(""); + + equiv_alg[U] = new_alg(" U "); + equiv_alg[U2] = new_alg(" UU "); + equiv_alg[U3] = new_alg(" UUU "); + equiv_alg[D] = new_alg(" xx U xx "); + equiv_alg[D2] = new_alg(" xx UU xx "); + equiv_alg[D3] = new_alg(" xx UUU xx "); + equiv_alg[R] = new_alg(" yx U xxxyyy "); + equiv_alg[R2] = new_alg(" yx UU xxxyyy "); + equiv_alg[R3] = new_alg(" yx UUU xxxyyy "); + equiv_alg[L] = new_alg(" yyyx U xxxy "); + equiv_alg[L2] = new_alg(" yyyx UU xxxy "); + equiv_alg[L3] = new_alg(" yyyx UUU xxxy "); + equiv_alg[F] = new_alg(" x U xxx "); + equiv_alg[F2] = new_alg(" x UU xxx "); + equiv_alg[F3] = new_alg(" x UUU xxx "); + equiv_alg[B] = new_alg(" xxx U x "); + equiv_alg[B2] = new_alg(" xxx UU x "); + equiv_alg[B3] = new_alg(" xxx UUU x "); + + equiv_alg[Uw] = new_alg(" xx U xx y "); + equiv_alg[Uw2] = new_alg(" xx UU xx yy "); + equiv_alg[Uw3] = new_alg(" xx UUU xx yyy "); + equiv_alg[Dw] = new_alg(" U yyy "); + equiv_alg[Dw2] = new_alg(" UU yy "); + equiv_alg[Dw3] = new_alg(" UUU y "); + equiv_alg[Rw] = new_alg(" yyyx U xxxy x "); + equiv_alg[Rw2] = new_alg(" yyyx UU xxxy xx "); + equiv_alg[Rw3] = new_alg(" yyyx UUU xxxy xxx "); + equiv_alg[Lw] = new_alg(" yx U xxxyyy xxx "); + equiv_alg[Lw2] = new_alg(" yx UU xxxyyy xx "); + equiv_alg[Lw3] = new_alg(" yx UUU xxxyyy x "); + equiv_alg[Fw] = new_alg(" xxx U x yxxxyyy "); + equiv_alg[Fw2] = new_alg(" xxx UU x yxxyyy "); + equiv_alg[Fw3] = new_alg(" xxx UUU x yxyyy "); + equiv_alg[Bw] = new_alg(" x U xxx yxyyy "); + equiv_alg[Bw2] = new_alg(" x UU xxx yxxyyy "); + equiv_alg[Bw3] = new_alg(" x UUU xxx yxxxyyy "); + + equiv_alg[M] = new_alg(" yx U xx UUU yxyyy "); + equiv_alg[M2] = new_alg(" yx UU xx UU xxxy "); + equiv_alg[M3] = new_alg(" yx UUU xx U yxxxy "); + equiv_alg[S] = new_alg(" x UUU xx U yyyx "); + equiv_alg[S2] = new_alg(" x UU xx UU yyx "); + equiv_alg[S3] = new_alg(" x U xx UUU yx "); + equiv_alg[E] = new_alg(" U xx UUU xxyyy "); + equiv_alg[E2] = new_alg(" UU xx UU xxyy "); + equiv_alg[E3] = new_alg(" UUU xx U xxy "); + + equiv_alg[x] = new_alg(" x "); + equiv_alg[x2] = new_alg(" xx "); + equiv_alg[x3] = new_alg(" xxx "); + equiv_alg[y] = new_alg(" y "); + equiv_alg[y2] = new_alg(" yy "); + equiv_alg[y3] = new_alg(" yyy "); + equiv_alg[z] = new_alg(" yyy x y "); + equiv_alg[z2] = new_alg(" yy xx "); + equiv_alg[z3] = new_alg(" y x yyy "); +} + +static void +init_strings() +{ + strcpy(move_string [NULLMOVE], "-" ); + strcpy(move_string [U], "U" ); + strcpy(move_string [U2], "U2" ); + strcpy(move_string [U3], "U\'" ); + strcpy(move_string [D], "D" ); + strcpy(move_string [D2], "D2" ); + strcpy(move_string [D3], "D\'" ); + strcpy(move_string [R], "R" ); + strcpy(move_string [R2], "R2" ); + strcpy(move_string [R3], "R\'" ); + strcpy(move_string [L], "L" ); + strcpy(move_string [L2], "L2" ); + strcpy(move_string [L3], "L\'" ); + strcpy(move_string [F], "F" ); + strcpy(move_string [F2], "F2" ); + strcpy(move_string [F3], "F\'" ); + strcpy(move_string [B], "B" ); + strcpy(move_string [B2], "B2" ); + strcpy(move_string [B3], "B\'" ); + strcpy(move_string [Uw], "Uw" ); + strcpy(move_string [Uw2], "Uw2" ); + strcpy(move_string [Uw3], "Uw\'" ); + strcpy(move_string [Dw], "Dw" ); + strcpy(move_string [Dw2], "Dw2" ); + strcpy(move_string [Dw3], "Dw\'" ); + strcpy(move_string [Rw], "Rw" ); + strcpy(move_string [Rw2], "Rw2" ); + strcpy(move_string [Rw3], "Rw\'" ); + strcpy(move_string [Lw], "Lw" ); + strcpy(move_string [Lw2], "Lw2" ); + strcpy(move_string [Lw3], "Lw\'" ); + strcpy(move_string [Fw], "Fw" ); + strcpy(move_string [Fw2], "Fw2" ); + strcpy(move_string [Fw3], "Fw\'" ); + strcpy(move_string [Bw], "Bw" ); + strcpy(move_string [Bw2], "Bw2" ); + strcpy(move_string [Bw3], "Bw\'" ); + strcpy(move_string [M], "M" ); + strcpy(move_string [M2], "M2" ); + strcpy(move_string [M3], "M\'" ); + strcpy(move_string [S], "S" ); + strcpy(move_string [S2], "S2" ); + strcpy(move_string [S3], "S\'" ); + strcpy(move_string [E], "E" ); + strcpy(move_string [E2], "E2" ); + strcpy(move_string [E3], "E\'" ); + strcpy(move_string [x], "x" ); + strcpy(move_string [x2], "x2" ); + strcpy(move_string [x3], "x\'" ); + strcpy(move_string [y], "y" ); + strcpy(move_string [y2], "y2" ); + strcpy(move_string [y3], "y\'" ); + strcpy(move_string [z], "z" ); + strcpy(move_string [z2], "z2" ); + strcpy(move_string [z3], "z\'" ); + + strcpy(edge_string [UF], "UF" ); + strcpy(edge_string [UL], "UL" ); + strcpy(edge_string [UB], "UB" ); + strcpy(edge_string [UR], "UR" ); + strcpy(edge_string [DF], "DF" ); + strcpy(edge_string [DL], "DL" ); + strcpy(edge_string [DB], "DB" ); + strcpy(edge_string [DR], "DR" ); + strcpy(edge_string [FR], "FR" ); + strcpy(edge_string [FL], "FL" ); + strcpy(edge_string [BL], "BL" ); + strcpy(edge_string [BR], "BR" ); + + strcpy(corner_string [UFR], "UFR" ); + strcpy(corner_string [UFL], "UFL" ); + strcpy(corner_string [UBL], "UBL" ); + strcpy(corner_string [UBR], "UBR" ); + strcpy(corner_string [DFR], "DFR" ); + strcpy(corner_string [DFL], "DFL" ); + strcpy(corner_string [DBL], "DBL" ); + strcpy(corner_string [DBR], "DBR" ); + + strcpy(center_string [U_center], "U" ); + strcpy(center_string [D_center], "D" ); + strcpy(center_string [R_center], "R" ); + strcpy(center_string [L_center], "L" ); + strcpy(center_string [F_center], "F" ); + strcpy(center_string [B_center], "B" ); +} + +static void +init_symdata() +{ + int i; + + for (i = 0; i < n_all_symdata; i++) + gensym(all_sd[i]); +} + +static void +init_trans() { + Cube aux, cube, mirr, c[3]; + CubeArray epcp; + int i, eparr[12], eoarr[12], cparr[8], coarr[8]; + unsigned int ui; + Move mi, move; + Trans m; + + /* Compute sources */ + for (i = 0; i < NTRANS; i++) { + cube = apply_alg(rotation_algs[i % NROTATIONS], (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; + } + + if (read_ttables_file()) + return; + + fprintf(stderr, "Cannot load %s, generating it\n", "ttables"); + + /* Initialize tables */ + for (m = 0; m < NTRANS; m++) { + epcp = (CubeArray){ .ep = eparr, .cp = cparr }; + cube = apply_alg(rotation_algs[m % NROTATIONS], (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++) { + aux = apply_trans(m, apply_move(mi, (Cube){0})); + for (move = 0; move < NMOVES; move++) { + cube = apply_move(inverse_move_aux[move], aux); + mirr = apply_trans(uf_mirror, cube); + if (is_solved(cube, false) || + is_solved(mirr, false)) + moves_ttable[m][mi] = move; + } + } + } + + if (!write_ttables_file()) + fprintf(stderr, "Error writing ttables\n"); +} + +static void +init_trans_aux() +{ + ep_mirror[UF] = UF; + ep_mirror[UL] = UR; + ep_mirror[UB] = UB; + ep_mirror[UR] = UL; + ep_mirror[DF] = DF; + ep_mirror[DL] = DR; + ep_mirror[DB] = DB; + ep_mirror[DR] = DL; + ep_mirror[FR] = FL; + ep_mirror[FL] = FR; + ep_mirror[BR] = BL; + ep_mirror[BL] = BR; + + cp_mirror[UFR] = UFL; + cp_mirror[UFL] = UFR; + cp_mirror[UBL] = UBR; + cp_mirror[UBR] = UBL; + cp_mirror[DFR] = DFL; + cp_mirror[DFL] = DFR; + cp_mirror[DBL] = DBR; + cp_mirror[DBR] = DBL; + + cpos_mirror[U_center] = U_center; + cpos_mirror[D_center] = D_center; + cpos_mirror[R_center] = L_center; + cpos_mirror[L_center] = R_center; + cpos_mirror[F_center] = F_center; + cpos_mirror[B_center] = B_center; + + /* Is there a more elegant way? */ + rotation_algs[uf] = new_alg(""); + rotation_algs[ur] = new_alg("y"); + rotation_algs[ub] = new_alg("y2"); + rotation_algs[ul] = new_alg("y3"); + + rotation_algs[df] = new_alg("z2"); + rotation_algs[dr] = new_alg("y z2"); + rotation_algs[db] = new_alg("x2"); + rotation_algs[dl] = new_alg("y3 z2"); + + rotation_algs[rf] = new_alg("z3"); + rotation_algs[rd] = new_alg("z3 y"); + rotation_algs[rb] = new_alg("z3 y2"); + rotation_algs[ru] = new_alg("z3 y3"); + + rotation_algs[lf] = new_alg("z"); + rotation_algs[ld] = new_alg("z y3"); + rotation_algs[lb] = new_alg("z y2"); + rotation_algs[lu] = new_alg("z y"); + + rotation_algs[fu] = new_alg("x y2"); + rotation_algs[fr] = new_alg("x y"); + rotation_algs[fd] = new_alg("x"); + rotation_algs[fl] = new_alg("x y3"); + + rotation_algs[bu] = new_alg("x3"); + rotation_algs[br] = new_alg("x3 y"); + rotation_algs[bd] = new_alg("x3 y2"); + rotation_algs[bl] = new_alg("x3 y3"); +} + + +/* Public functions implementation *******************************************/ + +Cube +apply_alg(Alg *alg, Cube cube) +{ + return apply_alg_generic(alg, cube, pf_all, true); +} + +Cube +apply_move(Move m, Cube cube) +{ + 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] + }; +} + + +Cube +apply_trans(Trans t, Cube cube) +{ + 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] + }; +} + +Move +base_move(Move m) +{ + if (m == NULLMOVE) + return NULLMOVE; + else + return m - (m-1)%3; +} + +Cube +compose(Cube c2, Cube c1) +{ + return compose_filtered(c2, c1, pf_all); +} + +/*TODO maybe move the next two */ +uint64_t +cphtr(Cube cube) +{ + return cphtr_right_cosets[cube.cp]; +} + +Cube +anti_cphtr(uint64_t ind) +{ + return (Cube) { .cp = cphtr_right_rep[ind] }; +} + +uint64_t +epos_dependent(Cube c) +{ + return epos_dependent_aux[c.eposs/FACTORIAL4][c.epose/FACTORIAL4]; +} + +bool +equal(Cube c1, Cube c2) +{ + 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; +} + +void +genptable(PruneData *pd) +{ + Cube cube; + uint64_t j, oldn = 0; + DfsData dd = { + .m = 0, + .last1 = NULLMOVE, + .last2 = NULLMOVE + }; + + if (pd->generated) + return; + + /* TODO: check if memory is enough, otherwise maybe crash gracefully? */ + pd->ptable = malloc(ptablesize(pd) * sizeof(uint8_t)); + + if (read_ptable_file(pd)) { + pd->generated = true; + return; + } + + fprintf(stderr, "Cannot load %s, generating it\n", pd->filename); + + /* We use 4 bits per value, so any distance >= 15 is set to 15 */ + for (j = 0; j < pd->coord->max; j++) + ptable_update(pd, pd->coord->cube(j), 15); + + moveset_to_list(pd->moveset, NULL, dd.sorted_moves); + movelist_to_position(dd.sorted_moves, dd.move_position); + + for (dd.d = 0, pd->n = 0; dd.d < 15 && pd->n < pd->coord->max; dd.d++) { + for (j = 0; j < pd->coord->max; j++) { + cube = pd->coord->cube(j); + if (pd->coord->check(cube)) + genptable_dfs(cube, pd, &dd); + } + fprintf(stderr, "Depth %d done, generated %lu\t(%lu/%lu)\n", + dd.d, pd->n-oldn, pd->n, pd->coord->max); + oldn = pd->n; + } + + if (!write_ptable_file(pd)) + fprintf(stderr, "Error writing ptable file\n"); + + pd->generated = true; +} + +Cube +inverse_cube(Cube cube) +{ + CubeArray *arr = new_cubearray(cube, pf_all); + CubeArray *inv = new_cubearray((Cube){0}, pf_all); + Cube ret; + int i; + + for (i = 0; i < 12; i++) { + inv->ep[arr->ep[i]] = i; + inv->eofb[arr->ep[i]] = arr->eofb[i]; + inv->eorl[arr->ep[i]] = arr->eorl[i]; + inv->eoud[arr->ep[i]] = arr->eoud[i]; + } + + for (i = 0; i < 8; i++) { + inv->cp[arr->cp[i]] = i; + inv->coud[arr->cp[i]] = (3 - arr->coud[i]) % 3; + inv->corl[arr->cp[i]] = (3 - arr->corl[i]) % 3; + inv->cofb[arr->cp[i]] = (3 - arr->cofb[i]) % 3; + } + + for (int i = 0; i < 6; i++) + inv->cpos[arr->cpos[i]] = i; + + ret = arrays_to_cube(inv, pf_all); + free_cubearray(arr, pf_all); + free_cubearray(inv, pf_all); + + return ret; +} + +Move +inverse_move(Move m) +{ + return inverse_move_aux[m]; +} + +Trans +inverse_trans(Trans t) +{ + return inverse_trans_aux[t]; +} + +bool +is_admissible(Cube cube) +{ + /* TODO: this should check consistency of different orientations */ + /* TODO: check that centers are opposite and admissible */ + + CubeArray *a = new_cubearray(cube, pf_all); + int parity; + bool perm; + + 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); + + return perm && parity % 2 == 0; +} + +bool +is_solved(Cube cube, bool reorient) +{ + int i; + + if (reorient) { + for (i = 0; i < NROTATIONS; i++) + if (is_solved(apply_alg(rotation_algs[i], cube),false)) + return true; + return false; + } else { + return equal(cube, (Cube){0}); + } +} + +bool +is_solved_block(Cube cube, Block block) +{ + 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; + + return true; +} + +bool +is_solved_center(Cube cube, Center c) +{ + return what_center_at(cube, c) == c; +} + +bool +is_solved_corner(Cube cube, Corner c) +{ + return what_corner_at(cube, c) == c && + what_orientation_corner(cube.coud, c); +} + +bool +is_solved_edge(Cube cube, Edge e) +{ + return what_edge_at(cube, e) == e && + what_orientation_edge(cube.eofb, e); +} + +int +piece_orientation(Cube cube, int piece, char *orientation) +{ + 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) +{ +/* + CubeArray *arr = new_cubearray(cube, pf_all); + + for (int i = 0; i < 12; i++) + printf(" %s ", edge_string[arr->ep[i]]); + printf("\n"); + + for (int i = 0; i < 12; i++) + printf(" %c ", arr->eofb[i] + '0'); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf("%s ", corner_string[arr->cp[i]]); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf(" %c ", arr->coud[i] + '0'); + printf("\n"); + + for (int i = 0; i < 6; i++) + printf(" %s ", center_string[arr->cpos[i]]); + printf("\n"); + + free_cubearray(arr, pf_all); +*/ + + for (int i = 0; i < 12; i++) + printf(" %s ", edge_string[what_edge_at(cube, i)]); + printf("\n"); + + for (int i = 0; i < 12; i++) + printf(" %d ", what_orientation_edge(cube.eofb, i)); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf("%s ", corner_string[what_corner_at(cube, i)]); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf(" %d ", what_orientation_corner(cube.coud, i)); + printf("\n"); + + for (int i = 0; i < 6; i++) + printf(" %s ", center_string[what_center_at(cube, i)]); + printf("\n"); + +} + +Cube +random_cube() +{ + CubeArray *arr = new_cubearray((Cube){0}, pf_4val); + Cube ret; + int ep, cp, eo, co; + + ep = rand() % FACTORIAL12; + cp = rand() % FACTORIAL8; + eo = rand() % POW2TO11; + co = rand() % POW3TO7; + + index_to_perm(ep, 12, arr->ep); + index_to_perm(cp, 8, arr->cp); + int_to_sum_zero_array(eo, 2, 12, arr->eofb); + int_to_sum_zero_array(co, 3, 8, arr->coud); + + if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8)) + swap(&(arr->ep[0]), &(arr->ep[1])); + + ret = arrays_to_cube(arr, pf_4val); + free_cubearray(arr, pf_4val); + + return ret; +} + +/* TODO: clean pre_trans or put it back */ +AlgList * +solve(Cube cube, Step step, SolveOptions *opts) +{ + /*AlgListNode *node;*/ + AlgList *sols = new_alglist(); + /*Cube c = apply_trans(opts->pre_trans, cube);*/ + DfsData dd = { + .m = 0, + .niss = false, + .lb = -1, + .last1 = NULLMOVE, + .last2 = NULLMOVE, + .sols = sols, + .current_alg = new_alg("") + }; + + if (step.ready != NULL && !step.ready(cube)) { + fprintf(stderr, "Cube not ready for solving step\n"); + return sols; + } + + moveset_to_list(step.moveset, step.estimate, dd.sorted_moves); + movelist_to_position(dd.sorted_moves, dd.move_position); + + for (dd.d = opts->min_moves; + dd.d <= opts->max_moves && !(sols->len && opts->optimal_only); + dd.d++) { + if (opts->feedback) + fprintf(stderr, + "Found %d solutions, searching depth %d...\n", + sols->len, dd.d); + dfs(cube, step, opts, &dd); + } + +/* + for (node = sols->first; node != NULL; node = node->next) + transform_alg(inverse_trans(opts->pre_trans), node->alg); +*/ + + free_alg(dd.current_alg); + return sols; +} + +Alg * +inverse_alg(Alg *alg) +{ + Alg *ret = new_alg(""); + int i; + + for (i = alg->len-1; i >= 0; i--) + append_move(ret, inverse_move(alg->move[i]), alg->inv[i]); + + return ret; +} + +Alg * +new_alg(char *str) +{ + Alg *alg = malloc(sizeof(Alg)); + int i; + bool niss = false; + Move j, m; + + alg->move = malloc(30 * sizeof(Move)); + alg->inv = malloc(30 * sizeof(bool)); + alg->allocated = 30; + alg->len = 0; + + for (i = 0; str[i]; i++) { + if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n') + continue; + + if (str[i] == '(' && niss) { + fprintf(stderr, "Error reading moves: nested ( )\n"); + return alg; + } + + if (str[i] == ')' && !niss) { + fprintf(stderr, "Error reading moves: unmatched )\n"); + return alg; + } + + if (str[i] == '(' || str[i] == ')') { + niss = !niss; + continue; + } + + for (j = 0; j < NMOVES; j++) { + if (str[i] == move_string[j][0]) { + m = j; + if (m <= B && str[i+1]=='w') { + m += Uw - U; + i++; + } + if (str[i+1]=='2') { + m += 1; + i++; + } else if (str[i+1]=='\'' || str[i+1]=='3') { + m += 2; + i++; + } + append_move(alg, m, niss); + break; + } + } + } + + return alg; +} + +Alg * +on_inverse(Alg *alg) +{ + Alg *ret = new_alg(""); + int i; + + for (i = 0; i < alg->len; i++) + append_move(ret, alg->move[i], !alg->inv[i]); + + return ret; +} + +void +print_alg(Alg *alg, bool l) +{ + /* TODO: make it possible to print to stdout or to string */ + /* Maybe just return a string */ + char fill[4]; + int i; + bool niss = false; + + for (i = 0; i < alg->len; i++) { + if (!niss && alg->inv[i]) + strcpy(fill, i == 0 ? "(" : " ("); + if (niss && !alg->inv[i]) + strcpy(fill, ") "); + if (niss == alg->inv[i]) + strcpy(fill, i == 0 ? "" : " "); + + printf("%s%s", fill, move_string[alg->move[i]]); + niss = alg->inv[i]; + } + + if (niss) + printf(")"); + if (l) + printf(" (%d)", alg->len); + + printf("\n"); +} + +void +print_alglist(AlgList *al, bool l) +{ + AlgListNode *i; + + for (i = al->first; i != NULL; i = i->next) + print_alg(i->alg, l); +} + +void +print_ptable(PruneData *pd) +{ + uint64_t i, a[16]; + + for (i = 0; i < 16; i++) + a[i] = 0; + + if (!pd->generated) + genptable(pd); + + for (i = 0; i < pd->coord->max; i++) + a[ptableval(pd, pd->coord->cube(i))]++; + + fprintf(stderr, "Values for table %s\n", pd->filename); + for (i = 0; i < 16; i++) + printf("%2lu\t%10lu\n", i, a[i]); +} + +uint64_t +ptablesize(PruneData *pd) +{ + return (pd->coord->max + 1) / 2; +} + +int +ptableval(PruneData *pd, Cube cube) +{ + uint64_t ind = pd->coord->index(cube); + + return (ind % 2) ? pd->ptable[ind/2] / 16 : pd->ptable[ind/2] % 16; +} + + +Alg * +rotation_alg(Trans i) +{ + return rotation_algs[i % NROTATIONS]; +} + +void +transform_alg(Trans t, Alg *alg) +{ + int i; + + for (i = 0; i < alg->len; i++) + alg->move[i] = moves_ttable[t][alg->move[i]]; +} + +Center +what_center_at(Cube cube, Center c) +{ + return what_center_at_aux[cube.cpos][c]; +} + +Corner +what_corner_at(Cube cube, Corner c) +{ + return what_corner_at_aux[cube.cp][c]; +} + +Edge +what_edge_at(Cube cube, Edge e) +{ + Edge ret; + CubeArray *arr = new_cubearray(cube, pf_ep); + + ret = arr->ep[e]; + + free_cubearray(arr, pf_ep); + return ret; +} + +int +what_orientation_corner(int co, Corner c) +{ + if (c < 7) + return (co / powint(3, c)) % 3; + else + return what_orientation_last_corner_aux[co]; +} + +int +what_orientation_edge(int eo, Edge e) +{ + if (e < 11) + return (eo & (1 << e)) ? 1 : 0; + else + return what_orientation_last_edge_aux[eo]; +} + +Center +where_is_center(Cube cube, Center c) +{ + return where_is_center_aux[cube.cpos][c]; +} + +Corner +where_is_corner(Cube cube, Corner c) +{ + return where_is_corner_aux[cube.cp][c]; +} + + +void +init() +{ + /* Order is important! */ + init_environment(); + init_strings(); + init_moves_aux(); + init_moves(); + init_auxtables(); + init_cphtr_cosets(); + init_trans_aux(); + init_trans(); + init_symdata(); +} + diff --git a/old/2021-07-02-genptable-dfs/cube.h b/old/2021-07-02-genptable-dfs/cube.h new file mode 100644 index 0000000..ffbcd86 --- /dev/null +++ b/old/2021-07-02-genptable-dfs/cube.h @@ -0,0 +1,90 @@ +#ifndef CUBE_H +#define CUBE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "macros.h" +#include "cubetypes.h" + +extern Coordinate coord_eofb; +extern Coordinate coord_eofbepos; +extern Coordinate coord_coud; +extern Coordinate coord_corners; +extern Coordinate coord_cornershtr; +extern Coordinate coord_drud; +extern Coordinate coord_coud_sym16; +extern Coordinate coord_eofbepos_sym16; +extern Coordinate coord_drud_sym16; +extern Coordinate coord_khuge; + +Cube apply_alg(Alg *alg, Cube cube); +Cube apply_move(Move m, Cube cube); +Cube apply_trans(Trans t, Cube cube); +bool block_solved(Cube cube, Block); +Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */ +uint64_t cphtr(Cube cube); /* TODO: rename (something with cosets) */ +Cube anti_cphtr(uint64_t ind); /*TODO also this */ +uint64_t epos_dependent(Cube cube); /* TODO: rename and turn into an indexer */ +bool equal(Cube c1, Cube c2); +Cube inverse_cube(Cube cube); +Move inverse_move(Move m); +Trans inverse_trans(Trans t); +bool is_admissible(Cube cube); +bool is_solved(Cube cube, bool reorient); +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 print_cube(Cube cube); +Cube random_cube(); +AlgList * solve(Cube cube, Step step, SolveOptions *opts); +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); + +bool check_centers(Cube cube); +bool check_corners(Cube cube); +bool check_cornershtr(Cube cube); +bool check_coud(Cube cube); +bool check_drud(Cube cube); +bool check_eofb(Cube cube); +bool check_eofbepos(Cube cube); +bool check_epose(Cube cube); +bool check_ep(Cube cube); +bool check_khuge(Cube cube); +bool check_nothing(Cube cube); + +bool moveset_HTM(Move m); +bool moveset_URF(Move m); + +Move base_move(Move m); +void free_alg(Alg *alg); +void free_alglist(AlgList *l); +Alg * inverse_alg(Alg *alg); +Alg * new_alg(char *str); +Alg * on_inverse(Alg *alg); +void print_alg(Alg *alg, bool l); +void print_alglist(AlgList *al, bool l); +Alg * rotation_alg(Trans i); +void transform_alg(Trans t, Alg *alg); + +void genptable(PruneData *pd); +void print_ptable(PruneData *pd); +uint64_t ptablesize(PruneData *pd); +int ptableval(PruneData *pd, Cube cube); + +void init(); + +#endif + diff --git a/old/2021-07-02-genptable-dfs/cubetypes.h b/old/2021-07-02-genptable-dfs/cubetypes.h new file mode 100644 index 0000000..a324985 --- /dev/null +++ b/old/2021-07-02-genptable-dfs/cubetypes.h @@ -0,0 +1,250 @@ +#ifndef CUBETYPES_H +#define CUBETYPES_H + +/* Typedefs ******************************************************************/ + +typedef enum center Center; +typedef enum corner Corner; +typedef enum edge Edge; +typedef enum move Move; +typedef enum trans Trans; + +typedef struct alg Alg; +typedef struct alglist AlgList; +typedef struct alglistnode AlgListNode; +typedef struct block Block; +typedef struct coordinate Coordinate; +typedef struct cube Cube; +typedef struct cubearray CubeArray; +typedef struct cubetarget CubeTarget; +typedef struct dfsdata DfsData; +typedef struct piecefilter PieceFilter; +typedef struct prunedata PruneData; +typedef struct solveoptions SolveOptions; +typedef struct step Step; +typedef struct symdata SymData; + +typedef Cube (*AntiIndexer) (uint64_t); +typedef bool (*Checker) (Cube); +typedef int (*Estimator) (CubeTarget); +typedef uint64_t (*Indexer) (Cube); +typedef bool (*Moveset) (Move); + + +/* Enums *********************************************************************/ + +enum +center +{ + U_center, D_center, + R_center, L_center, + F_center, B_center +}; + +enum +corner +{ + UFR, UFL, UBL, UBR, + DFR, DFL, DBL, DBR +}; + +enum +edge +{ + UF, UL, UB, UR, + DF, DL, DB, DR, + FR, FL, BL, BR +}; + +enum +move +{ + NULLMOVE, + U, U2, U3, D, D2, D3, + R, R2, R3, L, L2, L3, + F, F2, F3, B, B2, B3, + Uw, Uw2, Uw3, Dw, Dw2, Dw3, + Rw, Rw2, Rw3, Lw, Lw2, Lw3, + Fw, Fw2, Fw3, Bw, Bw2, Bw3, + M, M2, M3, + S, S2, S3, + E, E2, E3, + x, x2, x3, + y, y2, y3, + z, z2, z3, +}; + +enum +trans +{ + uf, ur, ub, ul, + df, dr, db, dl, + rf, rd, rb, ru, + lf, ld, lb, lu, + fu, fr, fd, fl, + bu, br, bd, bl, + uf_mirror, ur_mirror, ub_mirror, ul_mirror, + df_mirror, dr_mirror, db_mirror, dl_mirror, + rf_mirror, rd_mirror, rb_mirror, ru_mirror, + lf_mirror, ld_mirror, lb_mirror, lu_mirror, + fu_mirror, fr_mirror, fd_mirror, fl_mirror, + bu_mirror, br_mirror, bd_mirror, bl_mirror, +}; + + +/* Structs *******************************************************************/ + +struct +alg +{ + Move * move; + bool * inv; + int len; + int allocated; +}; + +struct +alglist +{ + AlgListNode * first; + AlgListNode * last; + int len; +}; + +struct +alglistnode +{ + Alg * alg; + AlgListNode * next; +}; + +struct +block +{ + bool edge[12]; + bool corner[8]; + bool center[6]; +}; + +struct +coordinate +{ + Indexer index; + AntiIndexer cube; + Checker check; + uint64_t max; +}; + +struct +cube +{ + int epose; + int eposs; + int eposm; + int eofb; + int eorl; + int eoud; + int cp; + int coud; + int cofb; + int corl; + int cpos; +}; + +struct +cubearray +{ + int * ep; + int * eofb; + int * eorl; + int * eoud; + int * cp; + int * coud; + int * corl; + int * cofb; + int * cpos; +}; + +struct +cubetarget +{ + Cube cube; + int target; +}; + +struct +dfsdata +{ + int d; + int m; + int lb; + bool niss; + Move last1; + Move last2; + AlgList * sols; + Alg * current_alg; + Move sorted_moves[NMOVES]; + int move_position[NMOVES]; +}; + +struct +piecefilter +{ + 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; + uint8_t * ptable; + bool generated; + uint64_t n; + Coordinate * coord; + Moveset moveset; +}; + +struct +solveoptions +{ + int min_moves; + int max_moves; + int max_solutions; + bool optimal_only; + bool can_niss; + bool feedback; +}; + +struct +step +{ + Estimator estimate; + Checker ready; + Moveset moveset; +}; + +struct +symdata +{ + char * filename; + bool generated; + Coordinate * coord; + Coordinate * sym_coord; + int ntrans; + Trans * trans; + uint64_t * class; + Cube * rep; + Trans * transtorep; +}; + +#endif diff --git a/old/2021-07-02-genptable-dfs/macros.h b/old/2021-07-02-genptable-dfs/macros.h new file mode 100644 index 0000000..af3bca1 --- /dev/null +++ b/old/2021-07-02-genptable-dfs/macros.h @@ -0,0 +1,23 @@ +#ifndef MACROS_H +#define MACROS_H + +#define POW2TO6 64ULL +#define POW2TO11 2048ULL +#define POW2TO12 4096ULL +#define POW3TO7 2187ULL +#define POW3TO8 6561ULL +#define FACTORIAL4 24ULL +#define FACTORIAL6 720ULL +#define FACTORIAL7 5040ULL +#define FACTORIAL8 40320ULL +#define FACTORIAL12 479001600ULL +#define BINOM12ON4 495ULL +#define BINOM8ON4 70ULL +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +#define NMOVES (z3+1) +#define NTRANS 48 +#define NROTATIONS 24 + +#endif diff --git a/old/2021-07-02-genptable-dfs/main.c b/old/2021-07-02-genptable-dfs/main.c new file mode 100644 index 0000000..1ebd917 --- /dev/null +++ b/old/2021-07-02-genptable-dfs/main.c @@ -0,0 +1,80 @@ +#include +#include "cube.h" +#include "steps.h" + +int main() { + Alg *algo; + AlgList *sols; + Cube cube; + SolveOptions opts; + char line[1000]; + int i, ns = 2; +/* Move m;*/ +/* int nrand = 10000, sum1, sum2, sum3;*/ + + Step *stps[20] = {&drud_HTM, &optimal_HTM}; + char sss[30][30] = {"DR on UD", "Optimal solve"}; + + opts = (SolveOptions) { + .min_moves = 0, + .max_moves = 20, + .optimal_only = true, + .max_solutions = 1, + .can_niss = false, + .feedback = true, + }; + + init(); + +/* + srand(time(NULL)); + sum1 = 0; + sum2 = 0; + sum3 = 0; + for (i = 0; i < nrand; i++) { + cube = random_cube(); + sum1 += drud_HTM.check(cube, 20); + sum2 += optimal_HTM.check(cube, 20); + sum3 += cornershtreofb_HTM.check(cube, 20); + } + printf("Average drud pruning: %lf\n", ((double)sum1) / ((double) nrand)); + printf("Average corners htr pruning: %lf\n", ((double)sum2) / ((double) nrand)); + printf("Average corners htr + eofb pruning: %lf\n", ((double)sum3) / ((double) nrand)); +*/ + +/* + for (m = U; m <= B3; m++) { + printf("Class eofbepos after %d: ", m); + printf("%lu\n", coord_khuge.index(apply_move(m,(Cube){0}))); + } +*/ + + printf("Welcome to nissy 2.0! Insert a scramble:\n"); + + if (fgets(line, 1000, stdin) != NULL) { + algo = new_alg(line); + cube = apply_alg(algo, (Cube){0}); + + print_alg(inverse_alg(algo), false); +/* + printf("After rb_mirror:\n"); + cube = apply_trans(rb_mirror, cube); + print_cube(cube); + printf("Going back:\n"); + cube = apply_trans(inverse_trans(rb_mirror), cube); +*/ + + print_cube(cube); + + for (i = 0; i < ns; i++) { + sols = solve(cube, *stps[i], &opts); + printf("%s: %d solutions found:\n", sss[i], sols->len); + print_alglist(sols, true); + free_alglist(sols); + } + free_alg(algo); + } + + return 0; +} + diff --git a/old/2021-07-02-genptable-dfs/steps.c b/old/2021-07-02-genptable-dfs/steps.c new file mode 100644 index 0000000..91e7f00 --- /dev/null +++ b/old/2021-07-02-genptable-dfs/steps.c @@ -0,0 +1,307 @@ +#include "steps.h" + +/* Standard checkers (return lower bound) ************************************/ + +static int estimate_eofb_HTM(CubeTarget ct); +static int estimate_coud_HTM(CubeTarget ct); +static int estimate_coud_URF(CubeTarget ct); +static int estimate_corners_HTM(CubeTarget ct); +static int estimate_cornershtr_HTM(CubeTarget ct); +static int estimate_corners_URF(CubeTarget ct); +static int estimate_cornershtr_URF(CubeTarget ct); +static int estimate_drud_HTM(CubeTarget ct); +static int estimate_optimal_HTM(CubeTarget ct); + +/* Steps *********************************************************************/ + +Step +eofb_HTM = { + .estimate = estimate_eofb_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + +Step +coud_HTM = { + .estimate = estimate_coud_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + +Step +coud_URF = { + .estimate = estimate_coud_URF, + .ready = check_nothing, + .moveset = moveset_URF +}; + +Step +corners_HTM = { + .estimate = estimate_corners_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + +Step +cornershtr_HTM = { + .estimate = estimate_cornershtr_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + +Step +cornershtr_URF = { + .estimate = estimate_cornershtr_URF, + .ready = check_nothing, + .moveset = moveset_URF +}; + +Step +corners_URF = { + .estimate = estimate_corners_URF, + .ready = check_nothing, + .moveset = moveset_URF +}; + +Step +drud_HTM = { + .estimate = estimate_drud_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + +Step +optimal_HTM = { + .estimate = estimate_optimal_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + + +/* Pruning tables ************************************************************/ + +PruneData +pd_eofb_HTM = { + .filename = "ptable_eofb_HTM", + .coord = &coord_eofb, + .moveset = moveset_HTM +}; + +PruneData +pd_coud_HTM = { + .filename = "ptable_coud_HTM", + .coord = &coord_coud, + .moveset = moveset_HTM +}; + +PruneData +pd_cornershtr_HTM = { + .filename = "ptable_cornershtr_withcosets_HTM", + .coord = &coord_cornershtr, + .moveset = moveset_HTM +}; + +PruneData +pd_corners_HTM = { + .filename = "ptable_corners_HTM", + .coord = &coord_corners, + .moveset = moveset_HTM +}; + +PruneData +pd_drud_HTM = { + .filename = "ptable_drud_HTM", + .coord = &coord_drud, + .moveset = moveset_HTM +}; + +PruneData +pd_drud_sym16_HTM = { + .filename = "ptable_drud_sym16_HTM", + .coord = &coord_drud_sym16, + .moveset = moveset_HTM, +}; + +PruneData +pd_khuge_HTM = { + .filename = "ptable_khuge_HTM", + .coord = &coord_khuge, + .moveset = moveset_HTM +}; + + +/* Standard checkers (return lower bound) ************************************/ + +static int +estimate_eofb_HTM(CubeTarget ct) +{ + if (!pd_eofb_HTM.generated) + genptable(&pd_eofb_HTM); + + return ptableval(&pd_eofb_HTM, ct.cube); +} + +static int +estimate_coud_HTM(CubeTarget ct) +{ + if (!pd_coud_HTM.generated) + genptable(&pd_coud_HTM); + + return ptableval(&pd_coud_HTM, ct.cube); +} + +static int +estimate_coud_URF(CubeTarget ct) +{ + /* TODO: I can improve this by checking first the orientation of + * the corner in DBL and use that as a reference */ + + CubeTarget ct2 = {.cube = apply_move(z, ct.cube), .target = ct.target}; + CubeTarget ct3 = {.cube = apply_move(x, ct.cube), .target = ct.target}; + + int ud = estimate_coud_HTM(ct); + int rl = estimate_coud_HTM(ct2); + int fb = estimate_coud_HTM(ct3); + + return MIN(ud, MIN(rl, fb)); +} + +static int +estimate_corners_HTM(CubeTarget ct) +{ + if (!pd_corners_HTM.generated) + genptable(&pd_corners_HTM); + + return ptableval(&pd_corners_HTM, ct.cube); +} + +static int +estimate_cornershtr_HTM(CubeTarget ct) +{ + if (!pd_cornershtr_HTM.generated) + genptable(&pd_cornershtr_HTM); + + return ptableval(&pd_cornershtr_HTM, ct.cube); +} + +static int +estimate_cornershtr_URF(CubeTarget ct) +{ + /* TODO: I can improve this by checking first the corner in DBL + * and use that as a reference */ + + int c, ret = 15; + Trans i; + + for (i = 0; i < NROTATIONS; i++) { + ct.cube = apply_alg(rotation_alg(i), ct.cube); + c = estimate_cornershtr_HTM(ct); + ret = MIN(ret, c); + } + + return ret; +} + +static int +estimate_corners_URF(CubeTarget ct) +{ + /* TODO: I can improve this by checking first the corner in DBL + * and use that as a reference */ + + int c, ret = 15; + Trans i; + + for (i = 0; i < NROTATIONS; i++) { + ct.cube = apply_alg(rotation_alg(i), ct.cube); + c = estimate_corners_HTM(ct); + ret = MIN(ret, c); + } + + return ret; +} + +static int +estimate_drud_HTM(CubeTarget ct) +{ +/* + if (!pd_drud_HTM.generated) + genptable(&pd_drud_HTM); + + return ptableval(&pd_drud_HTM, ct.cube); +*/ + + if (!pd_drud_sym16_HTM.generated) + genptable(&pd_drud_sym16_HTM); + + return ptableval(&pd_drud_sym16_HTM, ct.cube); +} + +/* TODO: if lucky, remove this */ +/* +static int +estimate_optimal_HTM(CubeTarget ct) +{ + static Trans t1 = { .rot = rf, .mirror = false }; + static Trans t2 = { .rot = bd, .mirror = false }; + int dr1, dr2, dr3, cor, ret; + Cube cube = ct.cube; + + dr1 = estimate_drud_HTM(ct); + cor = estimate_corners_HTM(ct); + ret = MAX(dr1, cor); + + if (ret > ct.target) + return ret; + + ct.cube = apply_trans(t1, cube); + dr2 = estimate_drud_HTM(ct); + ret = MAX(ret, dr2); + + if (ret > ct.target) + return ret; + + ct.cube = apply_trans(t2, cube); + dr3 = estimate_drud_HTM(ct); + + if (dr1 == dr2 && dr2 == dr3 && dr1 != 0) + dr3++; + + ret = MAX(ret, dr3); + + if (ret == 0) + return check_ep(cube) ? 0 : 6; + + return ret; +} +*/ + +static int +estimate_optimal_HTM(CubeTarget ct) +{ + static Trans t2 = rf, t3 = bd; + + int dr1, dr2, dr3, cor, ret; + Cube cube = ct.cube; + + if (!pd_khuge_HTM.generated) + genptable(&pd_khuge_HTM); + + dr1 = ptableval(&pd_khuge_HTM, cube); + cor = estimate_corners_HTM(ct); + ret = MAX(dr1, cor); + + if (ret > ct.target) + return ret; + + cube = apply_trans(t2, ct.cube); + dr2 = ptableval(&pd_khuge_HTM, cube); + ret = MAX(ret, dr2); + + if (ret > ct.target) + return ret; + + cube = apply_trans(t3, ct.cube); + dr3 = ptableval(&pd_khuge_HTM, cube); + + return MAX(ret, dr3); +} diff --git a/old/2021-07-02-genptable-dfs/steps.h b/old/2021-07-02-genptable-dfs/steps.h new file mode 100644 index 0000000..81ae11c --- /dev/null +++ b/old/2021-07-02-genptable-dfs/steps.h @@ -0,0 +1,24 @@ +#ifndef STEPS_H +#define STEPS_H + +#include "cube.h" + +extern Step eofb_HTM; +extern Step coud_HTM; +extern Step coud_URF; +extern Step corners_HTM; +extern Step cornershtr_HTM; +extern Step corners_URF; +extern Step cornershtr_URF; +extern Step drud_HTM; +extern Step optimal_HTM; + +extern PruneData pd_eofb_HTM; +extern PruneData pd_coud_HTM; +extern PruneData pd_corners_HTM; +extern PruneData pd_cornershtr_HTM; +extern PruneData pd_cornershtreofb_HTM; +extern PruneData pd_drud_HTM; +extern PruneData pd_khuge_HTM; + +#endif diff --git a/old/2021-07-15-almostbeforerefactor/README b/old/2021-07-15-almostbeforerefactor/README new file mode 100644 index 0000000..e306a9e --- /dev/null +++ b/old/2021-07-15-almostbeforerefactor/README @@ -0,0 +1,3 @@ +I started refactorig (splitting code into more files) before realizing I had no backup of +the fast version that works. +Take some stuff from alg.h back into cube.h, remove alg.* ad it should be ok. diff --git a/old/2021-07-15-almostbeforerefactor/alg.c b/old/2021-07-15-almostbeforerefactor/alg.c new file mode 100644 index 0000000..a3f8a19 --- /dev/null +++ b/old/2021-07-15-almostbeforerefactor/alg.c @@ -0,0 +1,3388 @@ +#include "alg.h" + +/* Local functions **********************************************************/ + +static Cube admissible_ep(Cube cube, PieceFilter f); +static Cube admissible_eos_from_eofbepos(Cube cube); +static bool allowed_next(Move move, DfsData *dd); +static void append_alg(AlgList *l, Alg *alg); +static void append_move(Alg *alg, Move m, bool inverse); +static Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a); +static void apply_permutation(int *perm, int *set, int n); +static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f); +static int array_ep_to_epos(int *ep, int *eps_solved); +static Cube arrays_to_cube(CubeArray *arr, PieceFilter f); +static int binomial(int n, int k); +static Cube compose_filtered(Cube c2, Cube c1, PieceFilter f); +static void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f); +static void dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static void dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static bool dfs_check_solved(SolveOptions *opts, DfsData *dd); +static void dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static bool dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static int digit_array_to_int(int *a, int n, int b); +static int edge_slice(Edge e); /* E=0, S=1, M=2 */ +static int epos_dependent_pos(int pos1, int pos2); +static int epos_from_arrays(int *epos, int *ep); +static void epos_to_partial_ep(int epos, int *ep, int *ss); +static int factorial(int n); +static void free_alglistnode(AlgListNode *aln); +static void free_cubearray(CubeArray *arr, PieceFilter f); +static void genptable_bfs(PruneData *pd, int d, Move *ms); +static void genptable_branch(PruneData *pd, uint64_t i, int d, Move *m); +static void gensym(SymData *sd); +static void index_to_perm(int p, int n, int *r); +static void index_to_subset(int s, int n, int k, int *r); +static void init_auxtables(); +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_environment(); +static void init_moves(); +static void init_moves_aux(); +static void init_strings(); +static void init_symdata(); +static void init_trans(); +static void init_trans_aux(); +static void int_to_digit_array(int a, int b, int n, int *r); +static void int_to_sum_zero_array(int x, int b, int n, int *a); +static int invert_digits(int a, int b, int n); +static bool is_perm(int *a, int n); +static bool is_subset(int *a, int n, int k); +static Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf); +static void movelist_to_position(Move *movelist, int *position); +static void moveset_to_list(Moveset ms, Estimator f, Move *r); +static AlgList * new_alglist(); +static CubeArray * new_cubearray(Cube cube, PieceFilter f); +static int perm_sign(int *a, int n); +static int perm_to_index(int *a, int n); +static int powint(int a, int b); +static void ptable_update(PruneData *pd, Cube cube, int m); +static int ptableval_index(PruneData *pd, uint64_t ind); +static void realloc_alg(Alg *alg, int n); +static bool read_mtables_file(); +static bool read_ptable_file(PruneData *pd); +static bool read_symdata_file(SymData *sd); +static bool read_ttables_file(); +static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f); +static int subset_to_index(int *a, int n, int k); +static void sum_arrays_mod(int *src, int *dst, int n, int m); +static void swap(int *a, int *b); +static bool write_mtables_file(); +static bool write_ptable_file(PruneData *pd); +static bool write_symdata_file(SymData *sd); +static bool write_ttables_file(); + + +/* All sorts of useful costants and tables **********************************/ + +static char * tabledir; + +static PieceFilter pf_all; +static PieceFilter pf_4val; +static PieceFilter pf_epcp; +static PieceFilter pf_cpos; +static PieceFilter pf_cp; +static PieceFilter pf_ep; +static PieceFilter pf_e; +static PieceFilter pf_s; +static PieceFilter pf_m; +static PieceFilter pf_eo; +static PieceFilter pf_co; + +static int epe_solved[4]; +static int eps_solved[4]; +static int epm_solved[4]; + +static char move_string[NMOVES][7]; +static char edge_string[12][7]; +static char corner_string[8][7]; +static char center_string[6][7]; + +static Cube admissible_ee_aux[POW2TO11*BINOM12ON4]; +static bool commute[NMOVES][NMOVES]; +static bool possible_next[NMOVES][NMOVES][NMOVES]; +static Move inverse_move_aux[NMOVES]; +static Trans inverse_trans_aux[NTRANS]; +static int epos_dependent_aux[BINOM12ON4][BINOM12ON4]; +static int cphtr_left_cosets[FACTORIAL8]; +static int cphtr_right_cosets[FACTORIAL8]; +static int cphtr_right_rep[BINOM8ON4*6]; +static Center what_center_at_aux[FACTORIAL6][6]; +static Corner what_corner_at_aux[FACTORIAL8][8]; +static int what_orientation_last_corner_aux[POW3TO7]; +static int what_orientation_last_edge_aux[POW2TO11]; +static Center where_is_center_aux[FACTORIAL6][6]; +static Corner where_is_corner_aux[FACTORIAL8][8]; +static Edge where_is_edge_aux[3][FACTORIAL12/FACTORIAL8][12]; + +static int epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static int eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static int eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static int eo_ttable[NTRANS][POW2TO11]; +static int cp_ttable[NTRANS][FACTORIAL8]; +static int co_ttable[NTRANS][POW3TO7]; +static int cpos_ttable[NTRANS][FACTORIAL6]; +static Move moves_ttable[NTRANS][NMOVES]; + +static int epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static int eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static int eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static int eofb_mtable[NMOVES][POW2TO11]; +static int eorl_mtable[NMOVES][POW2TO11]; +static int eoud_mtable[NMOVES][POW2TO11]; +static int cp_mtable[NMOVES][FACTORIAL8]; +static int coud_mtable[NMOVES][POW3TO7]; +static int cofb_mtable[NMOVES][POW3TO7]; +static int corl_mtable[NMOVES][POW3TO7]; +static int cpos_mtable[NMOVES][FACTORIAL6]; + +static uint64_t me[12]; + +static int edge_cycle[NMOVES][12]; +static int corner_cycle[NMOVES][8]; +static int center_cycle[NMOVES][6]; +static int eofb_flipped[NMOVES][12]; +static int eorl_flipped[NMOVES][12]; +static int eoud_flipped[NMOVES][12]; +static int coud_flipped[NMOVES][8]; +static int corl_flipped[NMOVES][8]; +static int cofb_flipped[NMOVES][8]; +static Alg * equiv_alg[NMOVES]; + +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]; +static int ep_mirror[12]; +static int cp_mirror[8]; +static int cpos_mirror[6]; +static Alg * rotation_algs[NROTATIONS]; + + +/* Symmetry data for some coordinates ****************************************/ + +Trans +trans_group_trivial[1] = { uf }; + +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, +}; + +SymData +sd_coud_16 = { + .filename = "sd_coud_16", + .coord = &coord_coud, + .sym_coord = &coord_coud_sym16, + .ntrans = 16, + .trans = trans_group_udfix +}; + +SymData +sd_eofbepos_16 = { + .filename = "sd_eofbepos_16", + .coord = &coord_eofbepos, + .sym_coord = &coord_eofbepos_sym16, + .ntrans = 16, + .trans = trans_group_udfix +}; + +static int n_all_symdata = 2; +static SymData * all_sd[2] = { &sd_coud_16, &sd_eofbepos_16 }; + +/* Coordinates and their implementation **************************************/ + +static uint64_t index_eofb(Cube cube); +static uint64_t index_eofbepos(Cube cube); +static uint64_t index_coud(Cube cube); +static uint64_t index_corners(Cube cube); +static uint64_t index_cornershtr(Cube cube); +static uint64_t index_drud(Cube cube); +static uint64_t index_coud_sym16(Cube cube); +static uint64_t index_eofbepos_sym16(Cube cube); +static uint64_t index_drud_sym16(Cube cube); +static uint64_t index_khuge(Cube cube); + +static Cube antindex_eofb(uint64_t ind); +static Cube antindex_eofbepos(uint64_t ind); +static Cube antindex_coud(uint64_t ind); +static Cube antindex_corners(uint64_t ind); +static Cube antindex_cornershtr(uint64_t ind); +static Cube antindex_drud(uint64_t ind); +static Cube antindex_coud_sym16(uint64_t ind); +static Cube antindex_eofbepos_sym16(uint64_t ind); +static Cube antindex_drud_sym16(uint64_t ind); +static Cube antindex_khuge(uint64_t ind); + +Coordinate +coord_eofb = { + .index = index_eofb, + .cube = antindex_eofb, + .check = check_eofb, + .max = POW2TO11 +}; + +Coordinate +coord_eofbepos = { + .index = index_eofbepos, + .cube = antindex_eofbepos, + .check = check_eofbepos, + .max = POW2TO11 * BINOM12ON4 +}; + +Coordinate +coord_coud = { + .index = index_coud, + .cube = antindex_coud, + .check = check_coud, + .max = POW3TO7 +}; + +Coordinate +coord_corners = { + .index = index_corners, + .cube = antindex_corners, + .check = check_corners, + .max = POW3TO7 * FACTORIAL8 +}; + +Coordinate +coord_cornershtr = { + .index = index_cornershtr, + .cube = antindex_cornershtr, + .check = check_cornershtr, + .max = POW3TO7 * BINOM8ON4 * 6 +}; + +Coordinate +coord_drud = { + .index = index_drud, + .cube = antindex_drud, + .check = check_drud, + .max = POW2TO11 * POW3TO7 * BINOM12ON4 +}; + +Coordinate +coord_eofbepos_sym16 = { + .index = index_eofbepos_sym16, + .cube = antindex_eofbepos_sym16, + .check = check_eofbepos, +}; + +Coordinate +coord_coud_sym16 = { + .index = index_coud_sym16, + .cube = antindex_coud_sym16, + .check = check_coud, +}; + +Coordinate +coord_drud_sym16 = { + .index = index_drud_sym16, + .cube = antindex_drud_sym16, + .check = check_drud, + .max = POW3TO7 * 64430 +}; + +Coordinate +coord_khuge = { + .index = index_khuge, + .cube = antindex_khuge, + .check = check_khuge, + .max = POW3TO7 * FACTORIAL4 * 64430 +}; + + +static uint64_t +index_eofb(Cube cube) +{ + return cube.eofb; +} + +static uint64_t +index_eofbepos(Cube cube) +{ + return (cube.epose / FACTORIAL4) * POW2TO11 + cube.eofb; +} + +static uint64_t +index_coud(Cube cube) +{ + return cube.coud; +} + +static uint64_t +index_corners(Cube cube) +{ + return cube.coud * FACTORIAL8 + cube.cp; +} + +static uint64_t +index_cornershtr(Cube cube) +{ + return cube.coud * BINOM8ON4 * 6 + cphtr(cube); +} + +static uint64_t +index_drud(Cube cube) +{ + uint64_t a, b, c; + + a = cube.eofb; + b = cube.coud; + c = cube.epose / FACTORIAL4; + + b *= POW2TO11; + c *= POW2TO11 * POW3TO7; + + return a + b + c; +} + +static uint64_t +index_coud_sym16(Cube cube) +{ + return sd_coud_16.class[index_coud(cube)]; +} + +static uint64_t +index_drud_sym16(Cube cube) +{ + Trans t; + Cube c; + + t = sd_eofbepos_16.transtorep[index_eofbepos(cube)]; + c = apply_trans(t, cube); + + return index_eofbepos_sym16(c) * POW3TO7 + c.coud; +} + +static uint64_t +index_eofbepos_sym16(Cube cube) +{ + return sd_eofbepos_16.class[index_eofbepos(cube)]; +} + +static uint64_t +index_khuge(Cube cube) +{ + Trans t; + Cube c; + uint64_t a; + + t = sd_eofbepos_16.transtorep[index_eofbepos(cube)]; + c = apply_trans(t, cube); + a = (index_eofbepos_sym16(c) * 24) + (c.epose % 24); + + return a * POW3TO7 + c.coud; +} + + +/* TODO: rename */ +static Cube +antindex_eofb(uint64_t ind) +{ + return (Cube){ .eofb = ind, .eorl = ind, .eoud = ind }; +} + +static Cube +antindex_eofbepos(uint64_t ind) +{ + return admissible_ee_aux[ind]; +} + +/* TODO: rename */ +static Cube +antindex_coud(uint64_t ind) +{ + return (Cube){ .coud = ind, .corl = ind, .cofb = ind }; +} + +/* TODO: admissible co for other orientations */ +static Cube +antindex_corners(uint64_t ind) +{ + Cube c = {0}; + + c.coud = ind / FACTORIAL8; + c.cp = ind % FACTORIAL8; + + return c; +} + +/* TODO: admissible co for other orientations */ +static Cube +antindex_cornershtr(uint64_t ind) +{ + Cube c = anti_cphtr(ind % (BINOM8ON4 * 6)); + + c.coud = ind / (BINOM8ON4 * 6); + + return c; +} + +/* TODO: admissible eos and cos */ +/* DONE: temporary fix, make it better */ +static Cube +antindex_drud(uint64_t ind) +{ + uint64_t epos, eofb; + Cube c; + + eofb = ind % POW2TO11; + epos = ind / (POW2TO11 * POW3TO7); + c = admissible_ee_aux[eofb + POW2TO11 * epos]; + + c.coud = (ind / POW2TO11) % POW3TO7; + c.corl = c.coud; + c.cofb = c.coud; + + return c; +} + +static Cube +antindex_coud_sym16(uint64_t ind) +{ + return sd_coud_16.rep[ind]; +} + +static Cube +antindex_eofbepos_sym16(uint64_t ind) +{ + return sd_eofbepos_16.rep[ind]; +} + +static Cube +antindex_drud_sym16(uint64_t ind) +{ + Cube c; + + c = sd_eofbepos_16.rep[ind/POW3TO7]; + c.coud = ind % POW3TO7; + c.cofb = c.coud; + c.corl = c.coud; + + return c; +} + +static Cube +antindex_khuge(uint64_t ind) +{ + Cube c; + + c = sd_eofbepos_16.rep[ind/(FACTORIAL4*POW3TO7)]; + c.epose = ((c.epose / 24) * 24) + ((ind/POW3TO7) % 24); + c.coud = ind % POW3TO7; + + return c; +} + + +/* Checkers ******************************************************************/ + +bool +check_centers(Cube cube) +{ + return cube.cpos == 0; +} + +bool +check_corners(Cube cube) +{ + return cube.cp == 0 && cube.coud == 0; +} + +bool +check_cornershtr(Cube cube) +{ + return cube.coud == 0 && cphtr(cube) == 0; /* TODO: use array cphtrcosets*/ +} + +bool +check_coud(Cube cube) +{ + return cube.coud == 0; +} + +bool +check_drud(Cube cube) +{ + return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0; +} + +bool +check_eofb(Cube cube) +{ + return cube.eofb == 0; +} + +bool +check_eofbepos(Cube cube) +{ + return cube.eofb == 0 && cube.epose / 24 == 0; +} + +bool +check_epose(Cube cube) +{ + return cube.epose == 0; +} + +bool +check_ep(Cube cube) +{ + return cube.epose == 0 && cube.eposs == 0 && cube.eposm == 0; +} + +bool +check_khuge(Cube cube) +{ + return check_drud(cube) && cube.epose % 24 == 0; +} + +bool +check_nothing(Cube cube) +{ + return is_admissible(cube); /*TODO: maybe change?*/ +} + +/* Movesets ******************************************************************/ + +bool +moveset_HTM(Move m) +{ + return m >= U && m <= B3; +} + +bool +moveset_URF(Move m) +{ + Move b = base_move(m); + + return b == U || b == R || b == F; +} + + +/* Local functions implementation ********************************************/ + +/* TODO: this should be an anti index (maybe?) */ +static 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 < 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; +} + +static Cube +admissible_eos_from_eofbepos(Cube cube) +{ + Edge e; + Cube ret; + CubeArray *arr = new_cubearray(cube, pf_all); + + memcpy(arr->eorl, arr->eofb, 12 * sizeof(int)); + memcpy(arr->eoud, arr->eofb, 12 * sizeof(int)); + + for (e = 0; e < 12; e++) { + if ((edge_slice(e) != 0 && edge_slice(arr->ep[e]) == 0) || + (edge_slice(e) == 0 && edge_slice(arr->ep[e]) != 0)) + arr->eorl[e] = 1 - arr->eorl[e]; + if ((edge_slice(e) != 2 && edge_slice(arr->ep[e]) == 2) || + (edge_slice(e) == 2 && edge_slice(arr->ep[e]) != 2)) + arr->eoud[e] = 1 - arr->eoud[e]; + } + + ret = arrays_to_cube(arr, pf_all); + free_cubearray(arr, pf_all); + + return ret; +} + +static bool +allowed_next(Move move, DfsData *dd) +{ + if (!possible_next[dd->last2][dd->last1][move]) + return false; + + if (commute[dd->last1][move]) + return dd->move_position[dd->last1] < dd->move_position[move]; + + return true; +} + +static void +append_alg(AlgList *l, Alg *alg) +{ + AlgListNode *node = malloc(sizeof(AlgListNode)); + int i; + + node->alg = new_alg(""); + for (i = 0; i < alg->len; i++) + append_move(node->alg, alg->move[i], alg->inv[i]); + node->next = NULL; + + if (++l->len == 1) + l->first = node; + else + l->last->next = node; + l->last = node; +} + +static void +append_move(Alg *alg, Move m, bool inverse) +{ + if (alg->len == alg->allocated) + realloc_alg(alg, 2*alg->len); + + alg->move[alg->len] = m; + alg->inv [alg->len] = inverse; + alg->len++; +} + +static Cube +apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a) +{ + Cube ret = {0}; + int i; + + for (i = 0; i < alg->len; i++) + if (alg->inv[i]) + ret = a ? apply_move(alg->move[i], ret) : + apply_move_cubearray(alg->move[i], ret, f); + + ret = compose_filtered(c, inverse_cube(ret), f); + + for (i = 0; i < alg->len; i++) + if (!alg->inv[i]) + ret = a ? apply_move(alg->move[i], ret) : + apply_move_cubearray(alg->move[i], ret, f); + + return ret; +} + +static void +apply_permutation(int *perm, int *set, int n) +{ + int *aux = malloc(n * sizeof(int)); + int i; + + if (!is_perm(perm, n)) + return; + + for (i = 0; i < n; i++) + aux[i] = set[perm[i]]; + + memcpy(set, aux, n * sizeof(int)); + free(aux); +} + +static Cube +apply_move_cubearray(Move m, Cube cube, PieceFilter f) +{ + 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); +} + +static int +array_ep_to_epos(int *ep, int *ss) +{ + 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 epos_from_arrays(epos, eps); +} + +static Cube +arrays_to_cube(CubeArray *arr, PieceFilter f) +{ + Cube ret = {0}; + + 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; +} + +static int +binomial(int n, int k) +{ + if (n < 0 || k < 0 || k > n) + return 0; + + return factorial(n) / (factorial(k) * factorial(n-k)); +} + +static Cube +compose_filtered(Cube c2, Cube c1, PieceFilter f) +{ + CubeArray *arr = new_cubearray(c2, f); + Cube ret; + + ret = move_via_arrays(arr, c1, f); + free_cubearray(arr, f); + + return ret; +} + +static void +cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f) +{ + int i; + + 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); +} + +/* +static int +cphtr_cp(int cp) +{ + int i, a[8]; + + index_to_perm(cp, 8, a); + + for (i = 0; i < 8; i++) + if (a[i] == UFR || a[i] == UBL || a[i] == DFL || a[i] == DBR) + a[i] = 0; + else + a[i] = 1; + + swap(&a[1], &a[5]); + swap(&a[3], &a[7]); + + return subset_to_index(a, 8, 4); +} +*/ + +static void +dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + if (dfs_stop(c, s, opts, dd)) + return; + + if (dfs_check_solved(opts, dd)) + return; + + dfs_branch(c, s, opts, dd); + + if (opts->can_niss && !dd->niss) + dfs_niss(c, s, opts, dd); +} + +static void +dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + Move m, l1 = dd->last1, l2 = dd->last2, *moves = dd->sorted_moves; + + int i, maxnsol = opts->max_solutions; + + for (i = 0; moves[i] != NULLMOVE && dd->sols->len < maxnsol; i++) { + m = moves[i]; + if (allowed_next(m, dd)) { + dd->last2 = dd->last1; + dd->last1 = m; + append_move(dd->current_alg, m, dd->niss); + + dfs(apply_move(m, c), s, opts, dd); + + dd->current_alg->len--; + dd->last2 = l2; + dd->last1 = l1; + } + } +} + +static bool +dfs_check_solved(SolveOptions *opts, DfsData *dd) +{ + if (dd->lb != 0) + return false; + + if (dd->current_alg->len == dd->d) { + append_alg(dd->sols, dd->current_alg); + + if (opts->feedback) + print_alg(dd->current_alg, false); + } + + return true; +} + +static void +dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + Move l1 = dd->last1, l2 = dd->last2; + CubeTarget ct; + + ct.cube = apply_move(inverse_move(l1), (Cube){0}); + ct.target = 1; + + if (dd->current_alg->len == 0 || s.estimate(ct)) { + dd->niss = true; + dd->last1 = NULLMOVE; + dd->last2 = NULLMOVE; + + dfs(inverse_cube(c), s, opts, dd); + + dd->last1 = l1; + dd->last2 = l2; + dd->niss = false; + } +} + +static bool +dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + CubeTarget ct = { + .cube = c, + .target = dd->d - dd->current_alg->len + }; + + if (dd->sols->len >= opts->max_solutions) + return true; + + dd->lb = s.estimate(ct); + if (opts->can_niss && !dd->niss) + dd->lb = MIN(1, dd->lb); + + if (dd->current_alg->len + dd->lb > dd->d) + return true; + + return false; +} + +static int +digit_array_to_int(int *a, int n, int b) +{ + int i, ret = 0, p = 1; + + for (i = 0; i < n; i++, p *= b) + ret += a[i] * p; + + return ret; +} + +static int +edge_slice(Edge e) { + if (e < 0 || e > 11) + return -1; + + if (e == FR || e == FL || e == BL || e == BR) + return 0; + if (e == UR || e == UL || e == DR || e == DL) + return 1; + + return 2; +} + +static int +epos_dependent_pos(int poss, int pose) +{ + int ep[12] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; + int ep8[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + int i, j; + + epos_to_partial_ep(poss*FACTORIAL4, ep, eps_solved); + epos_to_partial_ep(pose*FACTORIAL4, ep, epe_solved); + + for (i = 0, j = 0; i < 12; i++) + if (edge_slice(ep[i]) != 0) + ep8[j++] = (edge_slice(ep[i]) == 1) ? 1 : 0; + + swap(&ep8[1], &ep8[4]); + swap(&ep8[3], &ep8[6]); + + return subset_to_index(ep8, 8, 4); +} + +static int +epos_from_arrays(int *epos, int *ep) +{ + return FACTORIAL4 * subset_to_index(epos,12,4) + perm_to_index(ep,4); +} + +static void +epos_to_partial_ep(int epos, int *ep, int *ss) +{ + 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++]]; +} + +static int +factorial(int n) +{ + int i, ret = 1; + + if (n < 0) + return 0; + + for (i = 1; i <= n; i++) + ret *= i; + + return ret; +} + +void +free_alg(Alg *alg) +{ + free(alg->move); + free(alg->inv); + free(alg); +} + +void +free_alglist(AlgList *l) +{ + AlgListNode *aux, *i = l->first; + + while (i != NULL) { + aux = i->next; + free_alglistnode(i); + i = aux; + } + free(l); +} + +void +free_alglistnode(AlgListNode *aln) +{ + free_alg(aln->alg); + free(aln); +} + +static void +free_cubearray(CubeArray *arr, PieceFilter f) +{ + 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); +} + +static void +genptable_bfs(PruneData *pd, int d, Move *ms) +{ + uint64_t i; + + for (i = 0; i < pd->coord->max; i++) + if (ptableval_index(pd, i) == d) + genptable_branch(pd, i, d, ms); +} + +static void +genptable_branch(PruneData *pd, uint64_t ind, int d, Move *ms) +{ + int i, j; + Cube cc, c; + + + for (i = 0; i < pd->ntrans; i++) { + c = apply_trans(pd->trans[i], pd->coord->cube(ind)); + for (j = 0; ms[j] != NULLMOVE; j++) { + cc = apply_move(ms[j], c); + if (ptableval(pd, cc) > d+1) + ptable_update(pd, cc, d+1); + } + } +} + +static void +gensym(SymData *sd) +{ + uint64_t i, in, nreps = 0; + int j; + Cube c, d; + + if (sd->generated) + return; + + sd->class = malloc(sd->coord->max * sizeof(uint64_t)); + sd->rep = malloc(sd->coord->max * sizeof(Cube)); + sd->transtorep = malloc(sd->coord->max * sizeof(Trans)); + + 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) { + c = sd->coord->cube(i); + sd->rep[nreps] = c; + for (j = 0; j < sd->ntrans; j++) { + d = apply_trans(sd->trans[j], c); + in = sd->coord->index(d); + + if (sd->class[in] == sd->coord->max + 1) { + sd->class[in] = nreps; + sd->transtorep[in] = + inverse_trans(sd->trans[j]); + } + } + nreps++; + } + } + + sd->sym_coord->max = nreps; + sd->rep = realloc(sd->rep, nreps * sizeof(Cube)); + sd->generated = true; + + fprintf(stderr, "Found %lu classes\n", nreps); + + if (!write_symdata_file(sd)) + fprintf(stderr, "Error writing SymData file\n"); + + return; +} + +static void +index_to_perm(int p, int n, int *r) +{ + int *a = malloc(n * sizeof(int)); + int i, j, c; + + for (i = 0; i < n; i++) + a[i] = 0; + + if (p < 0 || p >= factorial(n)) + for (i = 0; i < n; i++) + r[i] = -1; + + for (i = 0; i < n; i++) { + c = 0; + j = 0; + while (c <= p / factorial(n-i-1)) + c += a[j++] ? 0 : 1; + r[i] = j-1; + a[j-1] = 1; + p %= factorial(n-i-1); + } + + free(a); +} + +static void +index_to_subset(int s, int n, int k, int *r) +{ + int i, j, v; + + if (s < 0 || s >= binomial(n, k)) { + for (i = 0; i < n; i++) + r[i] = -1; + return; + } + + for (i = 0; i < n; i++) { + if (k == n-i) { + for (j = i; j < n; j++) + r[j] = 1; + return; + } + + if (k == 0) { + for (j = i; j < n; j++) + r[j] = 0; + return; + } + + v = binomial(n-i-1, k); + if (s >= v) { + r[i] = 1; + k--; + s -= v; + } else { + r[i] = 0; + } + } +} + +static void +int_to_digit_array(int a, int b, int n, int *r) +{ + int i; + + if (b <= 1) + for (i = 0; i < n; i++) + r[i] = 0; + else + for (i = 0; i < n; i++, a /= b) + r[i] = a % b; +} + +static void +int_to_sum_zero_array(int x, int b, int n, int *a) +{ + int i, s = 0; + + if (b <= 1) { + for (i = 0; i < n; i++) + a[i] = 0; + } else { + int_to_digit_array(x, b, n-1, a); + for (i = 0; i < n - 1; i++) + s = (s + a[i]) % b; + a[n-1] = (b - s) % b; + } +} + +static int +invert_digits(int a, int b, int n) +{ + int i, ret, *r = malloc(n * sizeof(int)); + + int_to_digit_array(a, b, n, r); + for (i = 0; i < n; i++) + r[i] = (b-r[i]) % b; + + ret = digit_array_to_int(r, n, b); + free(r); + return ret; +} + +static bool +is_perm(int *a, int n) +{ + int *aux = malloc(n * sizeof(int)); + int i; + + for (i = 0; i < n; i++) + if (a[i] < 0 || a[i] >= n) + return false; + else + aux[a[i]] = 1; + + for (i = 0; i < n; i++) + if (!aux[i]) + return false; + + free(aux); + + return true; +} + +static bool +is_subset(int *a, int n, int k) +{ + int i, sum = 0; + + for (i = 0; i < n; i++) + sum += a[i] ? 1 : 0; + + return sum == k; +} + +static Cube +move_via_arrays(CubeArray *arr, Cube c, PieceFilter f) +{ + CubeArray *arrc = new_cubearray(c, f); + Cube ret; + + 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; +} + +static void +movelist_to_position(Move *movelist, int *position) +{ + Move m; + + for (m = 0; m < NMOVES && movelist[m] != NULLMOVE; m++) + position[movelist[m]] = m; +} + +static void +moveset_to_list(Moveset ms, Estimator f, Move *r) +{ + CubeTarget ct = { .target = 1 }; + int b[NMOVES]; + int na = 0, nb = 0; + Move i; + + if (ms == NULL) { + fprintf(stderr, "Error: no moveset given\n"); + return; + } + + for (i = U; i < NMOVES; i++) { + if (ms(i)) { + ct.cube = apply_move(i, (Cube){0}); + if (f != NULL && f(ct)) + r[na++] = i; + else + b[nb++] = i; + } + } + + memcpy(r + na, b, nb * sizeof(Move)); + r[na+nb] = NULLMOVE; +} + +static AlgList * +new_alglist() +{ + AlgList *ret = malloc(sizeof(AlgList)); + + ret->len = 0; + ret->first = NULL; + ret->last = NULL; + + return ret; +} + +static CubeArray * +new_cubearray(Cube cube, PieceFilter f) +{ + 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; +} + +static int +perm_sign(int *a, int n) +{ + int i, j, ret = 0; + + if (!is_perm(a,n)) + return -1; + + for (i = 0; i < n; i++) + for (j = i+1; j < n; j++) + ret += (a[i] > a[j]) ? 1 : 0; + + return ret % 2; +} + +static int +perm_to_index(int *a, int n) +{ + int i, j, c, ret = 0; + + if (!is_perm(a, n)) + return -1; + + for (i = 0; i < n; i++) { + c = 0; + for (j = i+1; j < n; j++) + c += (a[i] > a[j]) ? 1 : 0; + ret += factorial(n-i-1) * c; + } + + return ret; +} + +static int +powint(int a, int b) +{ + if (b < 0) + return 0; + if (b == 0) + return 1; + + if (b % 2) + return a * powint(a, b-1); + else + return powint(a*a, b/2); +} + +static void +ptable_update(PruneData *pd, Cube cube, int n) +{ + uint64_t ind = pd->coord->index(cube); + uint8_t oldval2 = pd->ptable[ind/2]; + int other = (ind % 2) ? oldval2 % 16 : oldval2 / 16; + + pd->ptable[ind/2] = (ind % 2) ? 16*n + other : 16*other + n; + pd->n++; +} + +static int +ptableval_index(PruneData *pd, uint64_t ind) +{ + return (ind % 2) ? pd->ptable[ind/2] / 16 : pd->ptable[ind/2] % 16; +} + +static void +realloc_alg(Alg *alg, int n) +{ + if (alg == NULL) { + fprintf(stderr, "Error: trying to reallocate NULL alg.\n"); + return; + } + + if (n < alg->len) { + fprintf(stderr, "Error: alg too long for reallocation "); + fprintf(stderr, "(%d vs %d)\n", alg->len, n); + return; + } + + if (n > 1000000) { + fprintf(stderr, "Warning: very long alg,"); + fprintf(stderr, "something might go wrong.\n"); + } + + alg->move = realloc(alg->move, n * sizeof(int)); + alg->inv = realloc(alg->inv, n * sizeof(int)); + alg->allocated = n; +} + +static bool +read_mtables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int m, b = sizeof(int); + bool r = true; + + 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 +read_ptable_file(PruneData *pd) +{ + FILE *f; + char fname[strlen(tabledir)+100]; + uint64_t r; + + strcpy(fname, tabledir); + strcat(fname, "/"); + strcat(fname, pd->filename); + + if ((f = fopen(fname, "rb")) == NULL) + return false; + + r = fread(pd->ptable, sizeof(uint8_t), ptablesize(pd), f); + fclose(f); + + return r == ptablesize(pd); +} + +static bool +read_symdata_file(SymData *sd) +{ + 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->rep, sizeof(Cube), *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_ttables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int b = sizeof(int); + bool r = true; + Move m; + + 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[6], f) == me[6]; + r = r && fread(co_ttable[m], b, me[7], f) == me[7]; + r = r && fread(cpos_ttable[m], b, me[10], f) == me[10]; + r = r && fread(moves_ttable[m], b, me[11], f) == me[11]; + } + + 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_algs[r % NROTATIONS]); + 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_algs[r % NROTATIONS], ret, f, true); + if (r >= NROTATIONS) + ret = move_via_arrays(&ma, ret, f); + + free_alg(inv); + return ret; +} + +static int +subset_to_index(int *a, int n, int k) +{ + int i, ret = 0; + + if (!is_subset(a, n, k)) + return binomial(n, k); + + for (i = 0; i < n; i++) { + if (k == n-i) + return ret; + if (a[i]) { + ret += binomial(n-i-1, k); + k--; + } + } + + return ret; +} + +static void +sum_arrays_mod(int *src, int *dst, int n, int m) +{ + int i; + + for (i = 0; i < n; i++) + dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m; +} + +static void +swap(int *a, int *b) +{ + int aux; + + aux = *a; + *a = *b; + *b = aux; +} + +static bool +write_mtables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int m, b = sizeof(int); + bool r = true; + + 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; +} + +static bool +write_ptable_file(PruneData *pd) +{ + FILE *f; + char fname[strlen(tabledir)+100]; + uint64_t written; + + strcpy(fname, tabledir); + strcat(fname, "/"); + strcat(fname, pd->filename); + + if ((f = fopen(fname, "wb")) == NULL) + return false; + + written = fwrite(pd->ptable, sizeof(uint8_t), ptablesize(pd), f); + fclose(f); + + return written == ptablesize(pd); +} + +static bool +write_symdata_file(SymData *sd) +{ + 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->rep, sizeof(Cube), *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_ttables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + bool r = true; + int b = sizeof(int); + Move m; + + 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[6], f) == me[6]; + r = r && fwrite(co_ttable[m], b, me[7], f) == me[7]; + r = r && fwrite(cpos_ttable[m], b, me[10], f) == me[10]; + r = r && fwrite(moves_ttable[m], b, me[11], f) == me[11]; + } + + fclose(f); + return r; +} + +/* Init functions implementation *********************************************/ + +static void +init_auxtables() +{ + Cube c1, c2; + CubeArray *arr; + uint64_t ui, uj; + int i, j, k, auxarr[12]; + bool cij, p1, p2; + + for (ui = 0; ui < POW2TO11*BINOM12ON4; ui++) { + k = (ui / POW2TO11) * 24; + c1 = admissible_ep((Cube){ .epose = k }, pf_e); + c1.eofb = ui % POW2TO11; + c1 = admissible_eos_from_eofbepos(c1); + admissible_ee_aux[ui] = c1; + } + + for (ui = 0; ui < FACTORIAL6; ui++) { + arr = new_cubearray((Cube){.cpos = ui}, pf_cpos); + for (i = 0; i < 6; i++) { + what_center_at_aux[ui][i] = arr->cpos[i]; + where_is_center_aux[ui][arr->cpos[i]] = i; + } + free_cubearray(arr, pf_cpos); + } + + for (ui = 0; ui < FACTORIAL8; ui++) { + arr = new_cubearray((Cube){.cp = ui}, pf_cp); + for (i = 0; i < 8; i++) { + what_corner_at_aux[ui][i] = arr->cp[i]; + where_is_corner_aux[ui][arr->cp[i]] = i; + } + free_cubearray(arr, pf_cp); + } + + for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) { + arr = new_cubearray((Cube){.epose = ui}, pf_e); + for (i = 0; i < 12; i++) + if (edge_slice(arr->ep[i]) == 0) + where_is_edge_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) + where_is_edge_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) + where_is_edge_aux[2][ui][arr->ep[i]] = i; + free_cubearray(arr, pf_m); + } + + for (ui = 0; ui < POW3TO7; ui++) { + int_to_sum_zero_array(ui, 3, 8, auxarr); + what_orientation_last_corner_aux[ui] = auxarr[7]; + } + + for (ui = 0; ui < POW2TO11; ui++) { + int_to_sum_zero_array(ui, 2, 12, auxarr); + what_orientation_last_edge_aux[ui] = auxarr[11]; + } + + for (ui = 0; ui < BINOM12ON4; ui++) + for (uj = 0; uj < BINOM12ON4; uj++) + epos_dependent_aux[ui][uj]=epos_dependent_pos(ui, uj); + + for (i = 0; i < NMOVES; i++) { + for (j = 0; j < NMOVES; j++) { + c1 = apply_move(i, apply_move(j, (Cube){0})); + c2 = apply_move(j, apply_move(i, (Cube){0})); + commute[i][j] = equal(c1, c2) && i && j; + } + } + + for (i = 0; i < NMOVES; i++) { + for (j = 0; j < NMOVES; j++) { + for (k = 0; k < NMOVES; k++) { + p1 = j && base_move(j) == base_move(k); + p2 = i && base_move(i) == base_move(k); + cij = commute[i][j]; + possible_next[i][j][k] = !(p1 || (cij && p2)); + } + } + } + + for (i = 0; i < NMOVES; i++) + inverse_move_aux[i] = i ? i + 2 - 2*((i-1)%3) : NULLMOVE; + + /* Is there a more elegant way? */ + inverse_trans_aux[uf] = uf; + inverse_trans_aux[ur] = ul; + inverse_trans_aux[ul] = ur; + inverse_trans_aux[ub] = ub; + + inverse_trans_aux[df] = df; + inverse_trans_aux[dr] = dr; + inverse_trans_aux[dl] = dl; + inverse_trans_aux[db] = db; + + inverse_trans_aux[rf] = lf; + inverse_trans_aux[rd] = bl; + inverse_trans_aux[rb] = rb; + inverse_trans_aux[ru] = fr; + + inverse_trans_aux[lf] = rf; + inverse_trans_aux[ld] = br; + inverse_trans_aux[lb] = lb; + inverse_trans_aux[lu] = fl; + + inverse_trans_aux[fu] = fu; + inverse_trans_aux[fr] = ru; + inverse_trans_aux[fd] = bu; + inverse_trans_aux[fl] = lu; + + inverse_trans_aux[bu] = fd; + inverse_trans_aux[br] = ld; + inverse_trans_aux[bd] = bd; + inverse_trans_aux[bl] = rd; + + inverse_trans_aux[uf_mirror] = uf_mirror; + inverse_trans_aux[ur_mirror] = ur_mirror; + inverse_trans_aux[ul_mirror] = ul_mirror; + inverse_trans_aux[ub_mirror] = ub_mirror; + + inverse_trans_aux[df_mirror] = df_mirror; + inverse_trans_aux[dr_mirror] = dl_mirror; + inverse_trans_aux[dl_mirror] = dr_mirror; + inverse_trans_aux[db_mirror] = db_mirror; + + inverse_trans_aux[rf_mirror] = rf_mirror; + inverse_trans_aux[rd_mirror] = br_mirror; + inverse_trans_aux[rb_mirror] = lb_mirror; + inverse_trans_aux[ru_mirror] = fl_mirror; + + inverse_trans_aux[lf_mirror] = lf_mirror; + inverse_trans_aux[ld_mirror] = bl_mirror; + inverse_trans_aux[lb_mirror] = rb_mirror; + inverse_trans_aux[lu_mirror] = fr_mirror; + + inverse_trans_aux[fu_mirror] = fu_mirror; + inverse_trans_aux[fr_mirror] = lu_mirror; + inverse_trans_aux[fd_mirror] = bu_mirror; + inverse_trans_aux[fl_mirror] = ru_mirror; + + inverse_trans_aux[bu_mirror] = fd_mirror; + inverse_trans_aux[br_mirror] = rd_mirror; + inverse_trans_aux[bd_mirror] = bd_mirror; + inverse_trans_aux[bl_mirror] = ld_mirror; +} + +/* + * There is certainly a bette 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 < FACTORIAL8; i++) { + cphtr_left_cosets[i] = -1; + cphtr_right_cosets[i] = -1; + } + + /* 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++); + + /* 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++); +} + +static void +init_cphtr_left_cosets_bfs(int i, int c) +{ + int j, jj, k, next[FACTORIAL8], next2[FACTORIAL8], n, n2; + Move moves[6] = {U2, D2, R2, L2, F2, B2}; + + n = 1; + next[0] = i; + cphtr_left_cosets[i] = c; + + while (n != 0) { + for (j = 0, n2 = 0; j < n; j++) { + for (k = 0; k < 6; k++) { + jj = cp_mtable[moves[k]][next[j]]; + if (cphtr_left_cosets[jj] == -1) { + cphtr_left_cosets[jj] = c; + next2[n2++] = jj; + } + } + } + + for (j = 0; j < n2; j++) + next[j] = next2[j]; + n = n2; + } +} + +static void +init_cphtr_right_cosets_color(int i, int d) +{ + int cp; + unsigned int j; + + cphtr_right_rep[d] = i; + for (j = 0; j < FACTORIAL8; j++) { + if (cphtr_left_cosets[j] == 0) { + /* TODO: use antindexer, it's nicer */ + cp = compose((Cube){.cp = i}, (Cube){.cp = j}).cp; + cphtr_right_cosets[cp] = d; + } + } +} + +static void +init_environment() +{ + char *nissydata = getenv("NISSYDATA"); + char *localdata = getenv("XDG_DATA_HOME"); + char *home = getenv("HOME"); + bool read, write; + + if (nissydata != NULL) { + tabledir = malloc(strlen(nissydata) * sizeof(char) + 20); + strcpy(tabledir, nissydata); + } else if (localdata != NULL) { + tabledir = malloc(strlen(localdata) * sizeof(char) + 20); + strcpy(tabledir, localdata); + strcat(tabledir, "/nissy"); + } else if (home != NULL) { + tabledir = malloc(strlen(home) * sizeof(char) + 20); + strcpy(tabledir, home); + strcat(tabledir, "/.nissy"); + } + + mkdir(tabledir, 0777); + strcat(tabledir, "/tables"); + mkdir(tabledir, 0777); + + read = !access(tabledir, R_OK); + write = !access(tabledir, W_OK); + + if (!read) { + fprintf(stderr, "Table files cannot be read.\n"); + } else if (!write) { + fprintf(stderr, "Data directory not writable: "); + fprintf(stderr, "tables can be loaded, but not saved.\n"); + } +} + +static void +init_moves() { + Cube c; + CubeArray arrs; + int i; + unsigned int ui; + Move m; + + /* 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; + + fprintf(stderr, "Cannot load %s, generating it\n", "mtables"); + + /* Initialize transition tables */ + for (m = 0; m < NMOVES; m++) { + 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; + } + } + + if (!write_mtables_file()) + fprintf(stderr, "Error writing mtables\n"); +} + +static void +init_moves_aux() +{ + /* Some standard PieceFilters */ + pf_all.epose = true; + pf_all.eposs = true; + pf_all.eposm = true; + pf_all.eofb = true; + pf_all.eorl = true; + pf_all.eoud = true; + pf_all.cp = true; + pf_all.cofb = true; + pf_all.corl = true; + pf_all.coud = true; + pf_all.cpos = true; + + pf_4val.epose = true; + pf_4val.eposs = true; + pf_4val.eposm = true; + pf_4val.eofb = true; + pf_4val.coud = true; + pf_4val.cp = true; + + pf_epcp.epose = true; + pf_epcp.eposs = true; + pf_epcp.eposm = true; + pf_epcp.cp = true; + + pf_cpos.cpos = true; + + pf_cp.cp = true; + + pf_ep.epose = true; + pf_ep.eposs = true; + pf_ep.eposm = true; + + pf_e.epose = true; + pf_s.eposs = true; + pf_m.eposm = true; + + pf_eo.eofb = true; + pf_eo.eorl = true; + pf_eo.eoud = true; + + pf_co.cofb = true; + pf_co.corl = true; + pf_co.coud = true; + + /* Used to convert to and from CubeArray */ + epe_solved[0] = FR; + epe_solved[1] = FL; + epe_solved[2] = BL; + epe_solved[3] = BR; + + eps_solved[0] = UL; + eps_solved[1] = UR; + eps_solved[2] = DL; + eps_solved[3] = DR; + + epm_solved[0] = UF; + epm_solved[1] = UB; + epm_solved[2] = DF; + epm_solved[3] = DB; + + /* Table sizes, used for reading and writing files */ + me[0] = FACTORIAL12/FACTORIAL8; + me[1] = FACTORIAL12/FACTORIAL8; + me[2] = FACTORIAL12/FACTORIAL8; + me[3] = POW2TO11; + me[4] = POW2TO11; + me[5] = POW2TO11; + me[6] = FACTORIAL8; + me[7] = POW3TO7; + me[8] = POW3TO7; + me[9] = POW3TO7; + me[10] = FACTORIAL6; + me[11] = NMOVES; + + /* Cycles *********************/ + edge_cycle[U][UF] = UR; + edge_cycle[U][UL] = UF; + edge_cycle[U][UB] = UL; + edge_cycle[U][UR] = UB; + edge_cycle[U][DF] = DF; + edge_cycle[U][DL] = DL; + edge_cycle[U][DB] = DB; + edge_cycle[U][DR] = DR; + edge_cycle[U][FR] = FR; + edge_cycle[U][FL] = FL; + edge_cycle[U][BL] = BL; + edge_cycle[U][BR] = BR; + + edge_cycle[x][UF] = DF; + edge_cycle[x][UL] = FL; + edge_cycle[x][UB] = UF; + edge_cycle[x][UR] = FR; + edge_cycle[x][DF] = DB; + edge_cycle[x][DL] = BL; + edge_cycle[x][DB] = UB; + edge_cycle[x][DR] = BR; + edge_cycle[x][FR] = DR; + edge_cycle[x][FL] = DL; + edge_cycle[x][BL] = UL; + edge_cycle[x][BR] = UR; + + edge_cycle[y][UF] = UR; + edge_cycle[y][UL] = UF; + edge_cycle[y][UB] = UL; + edge_cycle[y][UR] = UB; + edge_cycle[y][DF] = DR; + edge_cycle[y][DL] = DF; + edge_cycle[y][DB] = DL; + edge_cycle[y][DR] = DB; + edge_cycle[y][FR] = BR; + edge_cycle[y][FL] = FR; + edge_cycle[y][BL] = FL; + edge_cycle[y][BR] = BL; + + corner_cycle[U][UFR] = UBR; + corner_cycle[U][UFL] = UFR; + corner_cycle[U][UBL] = UFL; + corner_cycle[U][UBR] = UBL; + corner_cycle[U][DFR] = DFR; + corner_cycle[U][DFL] = DFL; + corner_cycle[U][DBL] = DBL; + corner_cycle[U][DBR] = DBR; + + corner_cycle[x][UFR] = DFR; + corner_cycle[x][UFL] = DFL; + corner_cycle[x][UBL] = UFL; + corner_cycle[x][UBR] = UFR; + corner_cycle[x][DFR] = DBR; + corner_cycle[x][DFL] = DBL; + corner_cycle[x][DBL] = UBL; + corner_cycle[x][DBR] = UBR; + + corner_cycle[y][UFR] = UBR; + corner_cycle[y][UFL] = UFR; + corner_cycle[y][UBL] = UFL; + corner_cycle[y][UBR] = UBL; + corner_cycle[y][DFR] = DBR; + corner_cycle[y][DFL] = DFR; + corner_cycle[y][DBL] = DFL; + corner_cycle[y][DBR] = DBL; + + center_cycle[U][U_center] = U_center; + center_cycle[U][D_center] = D_center; + center_cycle[U][R_center] = R_center; + center_cycle[U][L_center] = L_center; + center_cycle[U][F_center] = F_center; + center_cycle[U][B_center] = B_center; + + center_cycle[x][U_center] = F_center; + center_cycle[x][D_center] = B_center; + center_cycle[x][R_center] = R_center; + center_cycle[x][L_center] = L_center; + center_cycle[x][F_center] = D_center; + center_cycle[x][B_center] = U_center; + + center_cycle[y][U_center] = U_center; + center_cycle[y][D_center] = D_center; + center_cycle[y][R_center] = B_center; + center_cycle[y][L_center] = F_center; + center_cycle[y][F_center] = R_center; + center_cycle[y][B_center] = L_center; + + /* Flipped pieces *************/ + eofb_flipped[x][UF] = 1; + eofb_flipped[x][UB] = 1; + eofb_flipped[x][DF] = 1; + eofb_flipped[x][DB] = 1; + + eofb_flipped[y][FR] = 1; + eofb_flipped[y][FL] = 1; + eofb_flipped[y][BL] = 1; + eofb_flipped[y][BR] = 1; + + eorl_flipped[x][UF] = 1; + eorl_flipped[x][UL] = 1; + eorl_flipped[x][UB] = 1; + eorl_flipped[x][UR] = 1; + eorl_flipped[x][DF] = 1; + eorl_flipped[x][DL] = 1; + eorl_flipped[x][DB] = 1; + eorl_flipped[x][DR] = 1; + eorl_flipped[x][FR] = 1; + eorl_flipped[x][FL] = 1; + eorl_flipped[x][BL] = 1; + eorl_flipped[x][BR] = 1; + + eorl_flipped[y][FR] = 1; + eorl_flipped[y][FL] = 1; + eorl_flipped[y][BL] = 1; + eorl_flipped[y][BR] = 1; + + eoud_flipped[U][UF] = 1; + eoud_flipped[U][UL] = 1; + eoud_flipped[U][UB] = 1; + eoud_flipped[U][UR] = 1; + + eoud_flipped[x][UF] = 1; + eoud_flipped[x][UB] = 1; + eoud_flipped[x][DF] = 1; + eoud_flipped[x][DB] = 1; + + eoud_flipped[y][UF] = 1; + eoud_flipped[y][UL] = 1; + eoud_flipped[y][UB] = 1; + eoud_flipped[y][UR] = 1; + eoud_flipped[y][DF] = 1; + eoud_flipped[y][DL] = 1; + eoud_flipped[y][DB] = 1; + eoud_flipped[y][DR] = 1; + eoud_flipped[y][FR] = 1; + eoud_flipped[y][FL] = 1; + eoud_flipped[y][BL] = 1; + eoud_flipped[y][BR] = 1; + + coud_flipped[x][UFR] = 2; + coud_flipped[x][UFL] = 1; + coud_flipped[x][UBR] = 1; + coud_flipped[x][UBL] = 2; + coud_flipped[x][DFR] = 1; + coud_flipped[x][DFL] = 2; + coud_flipped[x][DBR] = 2; + coud_flipped[x][DBL] = 1; + + corl_flipped[U][UFR] = 1; + corl_flipped[U][UFL] = 2; + corl_flipped[U][UBL] = 1; + corl_flipped[U][UBR] = 2; + + corl_flipped[y][UFR] = 1; + corl_flipped[y][UFL] = 2; + corl_flipped[y][UBL] = 1; + corl_flipped[y][UBR] = 2; + corl_flipped[y][DFR] = 2; + corl_flipped[y][DFL] = 1; + corl_flipped[y][DBL] = 2; + corl_flipped[y][DBR] = 1; + + cofb_flipped[U][UFR] = 2; + cofb_flipped[U][UFL] = 1; + cofb_flipped[U][UBL] = 2; + cofb_flipped[U][UBR] = 1; + + cofb_flipped[x][UFR] = 1; + cofb_flipped[x][UFL] = 2; + cofb_flipped[x][UBL] = 1; + cofb_flipped[x][UBR] = 2; + cofb_flipped[x][DFR] = 2; + cofb_flipped[x][DFL] = 1; + cofb_flipped[x][DBL] = 2; + cofb_flipped[x][DBR] = 1; + + cofb_flipped[y][UFR] = 2; + cofb_flipped[y][UFL] = 1; + cofb_flipped[y][UBL] = 2; + cofb_flipped[y][UBR] = 1; + cofb_flipped[y][DFR] = 1; + cofb_flipped[y][DFL] = 2; + cofb_flipped[y][DBL] = 1; + cofb_flipped[y][DBR] = 2; + + /* Equivalent moves ***********/ + equiv_alg[NULLMOVE] = new_alg(""); + + equiv_alg[U] = new_alg(" U "); + equiv_alg[U2] = new_alg(" UU "); + equiv_alg[U3] = new_alg(" UUU "); + equiv_alg[D] = new_alg(" xx U xx "); + equiv_alg[D2] = new_alg(" xx UU xx "); + equiv_alg[D3] = new_alg(" xx UUU xx "); + equiv_alg[R] = new_alg(" yx U xxxyyy "); + equiv_alg[R2] = new_alg(" yx UU xxxyyy "); + equiv_alg[R3] = new_alg(" yx UUU xxxyyy "); + equiv_alg[L] = new_alg(" yyyx U xxxy "); + equiv_alg[L2] = new_alg(" yyyx UU xxxy "); + equiv_alg[L3] = new_alg(" yyyx UUU xxxy "); + equiv_alg[F] = new_alg(" x U xxx "); + equiv_alg[F2] = new_alg(" x UU xxx "); + equiv_alg[F3] = new_alg(" x UUU xxx "); + equiv_alg[B] = new_alg(" xxx U x "); + equiv_alg[B2] = new_alg(" xxx UU x "); + equiv_alg[B3] = new_alg(" xxx UUU x "); + + equiv_alg[Uw] = new_alg(" xx U xx y "); + equiv_alg[Uw2] = new_alg(" xx UU xx yy "); + equiv_alg[Uw3] = new_alg(" xx UUU xx yyy "); + equiv_alg[Dw] = new_alg(" U yyy "); + equiv_alg[Dw2] = new_alg(" UU yy "); + equiv_alg[Dw3] = new_alg(" UUU y "); + equiv_alg[Rw] = new_alg(" yyyx U xxxy x "); + equiv_alg[Rw2] = new_alg(" yyyx UU xxxy xx "); + equiv_alg[Rw3] = new_alg(" yyyx UUU xxxy xxx "); + equiv_alg[Lw] = new_alg(" yx U xxxyyy xxx "); + equiv_alg[Lw2] = new_alg(" yx UU xxxyyy xx "); + equiv_alg[Lw3] = new_alg(" yx UUU xxxyyy x "); + equiv_alg[Fw] = new_alg(" xxx U x yxxxyyy "); + equiv_alg[Fw2] = new_alg(" xxx UU x yxxyyy "); + equiv_alg[Fw3] = new_alg(" xxx UUU x yxyyy "); + equiv_alg[Bw] = new_alg(" x U xxx yxyyy "); + equiv_alg[Bw2] = new_alg(" x UU xxx yxxyyy "); + equiv_alg[Bw3] = new_alg(" x UUU xxx yxxxyyy "); + + equiv_alg[M] = new_alg(" yx U xx UUU yxyyy "); + equiv_alg[M2] = new_alg(" yx UU xx UU xxxy "); + equiv_alg[M3] = new_alg(" yx UUU xx U yxxxy "); + equiv_alg[S] = new_alg(" x UUU xx U yyyx "); + equiv_alg[S2] = new_alg(" x UU xx UU yyx "); + equiv_alg[S3] = new_alg(" x U xx UUU yx "); + equiv_alg[E] = new_alg(" U xx UUU xxyyy "); + equiv_alg[E2] = new_alg(" UU xx UU xxyy "); + equiv_alg[E3] = new_alg(" UUU xx U xxy "); + + equiv_alg[x] = new_alg(" x "); + equiv_alg[x2] = new_alg(" xx "); + equiv_alg[x3] = new_alg(" xxx "); + equiv_alg[y] = new_alg(" y "); + equiv_alg[y2] = new_alg(" yy "); + equiv_alg[y3] = new_alg(" yyy "); + equiv_alg[z] = new_alg(" yyy x y "); + equiv_alg[z2] = new_alg(" yy xx "); + equiv_alg[z3] = new_alg(" y x yyy "); +} + +static void +init_strings() +{ + strcpy(move_string [NULLMOVE], "-" ); + strcpy(move_string [U], "U" ); + strcpy(move_string [U2], "U2" ); + strcpy(move_string [U3], "U\'" ); + strcpy(move_string [D], "D" ); + strcpy(move_string [D2], "D2" ); + strcpy(move_string [D3], "D\'" ); + strcpy(move_string [R], "R" ); + strcpy(move_string [R2], "R2" ); + strcpy(move_string [R3], "R\'" ); + strcpy(move_string [L], "L" ); + strcpy(move_string [L2], "L2" ); + strcpy(move_string [L3], "L\'" ); + strcpy(move_string [F], "F" ); + strcpy(move_string [F2], "F2" ); + strcpy(move_string [F3], "F\'" ); + strcpy(move_string [B], "B" ); + strcpy(move_string [B2], "B2" ); + strcpy(move_string [B3], "B\'" ); + strcpy(move_string [Uw], "Uw" ); + strcpy(move_string [Uw2], "Uw2" ); + strcpy(move_string [Uw3], "Uw\'" ); + strcpy(move_string [Dw], "Dw" ); + strcpy(move_string [Dw2], "Dw2" ); + strcpy(move_string [Dw3], "Dw\'" ); + strcpy(move_string [Rw], "Rw" ); + strcpy(move_string [Rw2], "Rw2" ); + strcpy(move_string [Rw3], "Rw\'" ); + strcpy(move_string [Lw], "Lw" ); + strcpy(move_string [Lw2], "Lw2" ); + strcpy(move_string [Lw3], "Lw\'" ); + strcpy(move_string [Fw], "Fw" ); + strcpy(move_string [Fw2], "Fw2" ); + strcpy(move_string [Fw3], "Fw\'" ); + strcpy(move_string [Bw], "Bw" ); + strcpy(move_string [Bw2], "Bw2" ); + strcpy(move_string [Bw3], "Bw\'" ); + strcpy(move_string [M], "M" ); + strcpy(move_string [M2], "M2" ); + strcpy(move_string [M3], "M\'" ); + strcpy(move_string [S], "S" ); + strcpy(move_string [S2], "S2" ); + strcpy(move_string [S3], "S\'" ); + strcpy(move_string [E], "E" ); + strcpy(move_string [E2], "E2" ); + strcpy(move_string [E3], "E\'" ); + strcpy(move_string [x], "x" ); + strcpy(move_string [x2], "x2" ); + strcpy(move_string [x3], "x\'" ); + strcpy(move_string [y], "y" ); + strcpy(move_string [y2], "y2" ); + strcpy(move_string [y3], "y\'" ); + strcpy(move_string [z], "z" ); + strcpy(move_string [z2], "z2" ); + strcpy(move_string [z3], "z\'" ); + + strcpy(edge_string [UF], "UF" ); + strcpy(edge_string [UL], "UL" ); + strcpy(edge_string [UB], "UB" ); + strcpy(edge_string [UR], "UR" ); + strcpy(edge_string [DF], "DF" ); + strcpy(edge_string [DL], "DL" ); + strcpy(edge_string [DB], "DB" ); + strcpy(edge_string [DR], "DR" ); + strcpy(edge_string [FR], "FR" ); + strcpy(edge_string [FL], "FL" ); + strcpy(edge_string [BL], "BL" ); + strcpy(edge_string [BR], "BR" ); + + strcpy(corner_string [UFR], "UFR" ); + strcpy(corner_string [UFL], "UFL" ); + strcpy(corner_string [UBL], "UBL" ); + strcpy(corner_string [UBR], "UBR" ); + strcpy(corner_string [DFR], "DFR" ); + strcpy(corner_string [DFL], "DFL" ); + strcpy(corner_string [DBL], "DBL" ); + strcpy(corner_string [DBR], "DBR" ); + + strcpy(center_string [U_center], "U" ); + strcpy(center_string [D_center], "D" ); + strcpy(center_string [R_center], "R" ); + strcpy(center_string [L_center], "L" ); + strcpy(center_string [F_center], "F" ); + strcpy(center_string [B_center], "B" ); +} + +static void +init_symdata() +{ + int i; + + for (i = 0; i < n_all_symdata; i++) + gensym(all_sd[i]); +} + +static void +init_trans() { + Cube aux, cube, mirr, c[3]; + CubeArray epcp; + int i, eparr[12], eoarr[12], cparr[8], coarr[8]; + unsigned int ui; + Move mi, move; + Trans m; + + /* Compute sources */ + for (i = 0; i < NTRANS; i++) { + cube = apply_alg(rotation_algs[i % NROTATIONS], (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; + } + + if (read_ttables_file()) + return; + + fprintf(stderr, "Cannot load %s, generating it\n", "ttables"); + + /* Initialize tables */ + for (m = 0; m < NTRANS; m++) { + epcp = (CubeArray){ .ep = eparr, .cp = cparr }; + cube = apply_alg(rotation_algs[m % NROTATIONS], (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++) { + aux = apply_trans(m, apply_move(mi, (Cube){0})); + for (move = 0; move < NMOVES; move++) { + cube = apply_move(inverse_move_aux[move], aux); + mirr = apply_trans(uf_mirror, cube); + if (is_solved(cube, false) || + is_solved(mirr, false)) + moves_ttable[m][mi] = move; + } + } + } + + if (!write_ttables_file()) + fprintf(stderr, "Error writing ttables\n"); +} + +static void +init_trans_aux() +{ + ep_mirror[UF] = UF; + ep_mirror[UL] = UR; + ep_mirror[UB] = UB; + ep_mirror[UR] = UL; + ep_mirror[DF] = DF; + ep_mirror[DL] = DR; + ep_mirror[DB] = DB; + ep_mirror[DR] = DL; + ep_mirror[FR] = FL; + ep_mirror[FL] = FR; + ep_mirror[BR] = BL; + ep_mirror[BL] = BR; + + cp_mirror[UFR] = UFL; + cp_mirror[UFL] = UFR; + cp_mirror[UBL] = UBR; + cp_mirror[UBR] = UBL; + cp_mirror[DFR] = DFL; + cp_mirror[DFL] = DFR; + cp_mirror[DBL] = DBR; + cp_mirror[DBR] = DBL; + + cpos_mirror[U_center] = U_center; + cpos_mirror[D_center] = D_center; + cpos_mirror[R_center] = L_center; + cpos_mirror[L_center] = R_center; + cpos_mirror[F_center] = F_center; + cpos_mirror[B_center] = B_center; + + /* Is there a more elegant way? */ + rotation_algs[uf] = new_alg(""); + rotation_algs[ur] = new_alg("y"); + rotation_algs[ub] = new_alg("y2"); + rotation_algs[ul] = new_alg("y3"); + + rotation_algs[df] = new_alg("z2"); + rotation_algs[dr] = new_alg("y z2"); + rotation_algs[db] = new_alg("x2"); + rotation_algs[dl] = new_alg("y3 z2"); + + rotation_algs[rf] = new_alg("z3"); + rotation_algs[rd] = new_alg("z3 y"); + rotation_algs[rb] = new_alg("z3 y2"); + rotation_algs[ru] = new_alg("z3 y3"); + + rotation_algs[lf] = new_alg("z"); + rotation_algs[ld] = new_alg("z y3"); + rotation_algs[lb] = new_alg("z y2"); + rotation_algs[lu] = new_alg("z y"); + + rotation_algs[fu] = new_alg("x y2"); + rotation_algs[fr] = new_alg("x y"); + rotation_algs[fd] = new_alg("x"); + rotation_algs[fl] = new_alg("x y3"); + + rotation_algs[bu] = new_alg("x3"); + rotation_algs[br] = new_alg("x3 y"); + rotation_algs[bd] = new_alg("x3 y2"); + rotation_algs[bl] = new_alg("x3 y3"); +} + + +/* Public functions implementation *******************************************/ + +Cube +apply_alg(Alg *alg, Cube cube) +{ + return apply_alg_generic(alg, cube, pf_all, true); +} + +Cube +apply_move(Move m, Cube cube) +{ + 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] + }; +} + + +Cube +apply_trans(Trans t, Cube cube) +{ + 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] + }; +} + +Move +base_move(Move m) +{ + if (m == NULLMOVE) + return NULLMOVE; + else + return m - (m-1)%3; +} + +Cube +compose(Cube c2, Cube c1) +{ + return compose_filtered(c2, c1, pf_all); +} + +/*TODO maybe move the next two */ +uint64_t +cphtr(Cube cube) +{ + return cphtr_right_cosets[cube.cp]; +} + +Cube +anti_cphtr(uint64_t ind) +{ + return (Cube) { .cp = cphtr_right_rep[ind] }; +} + +uint64_t +epos_dependent(Cube c) +{ + return epos_dependent_aux[c.eposs/FACTORIAL4][c.epose/FACTORIAL4]; +} + +bool +equal(Cube c1, Cube c2) +{ + 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; +} + +void +genptable(PruneData *pd) +{ + Move ms[NMOVES]; + int d; + uint64_t j, oldn = 0; + + if (pd->generated) + return; + + /* TODO: check if memory is enough, otherwise maybe crash gracefully? */ + pd->ptable = malloc(ptablesize(pd) * sizeof(uint8_t)); + + if (read_ptable_file(pd)) { + pd->generated = true; + return; + } + + fprintf(stderr, "Cannot load %s, generating it\n", pd->filename); + + moveset_to_list(pd->moveset, NULL, ms); + + /* We use 4 bits per value, so any distance >= 15 is set to 15 */ + for (j = 0; j < pd->coord->max; j++) + ptable_update(pd, pd->coord->cube(j), 15); + + /*TODO: change, set to 0 for every solved state (might be more than 1)*/ + ptable_update(pd, (Cube){0}, 0); + pd->n = 1; + + for (d = 0; d < 15 && pd->n < pd->coord->max; d++) { + genptable_bfs(pd, d, ms); + fprintf(stderr, "Depth %d done, generated %lu\t(%lu/%lu)\n", + d, pd->n - oldn, pd->n, pd->coord->max); + oldn = pd->n; + } + + if (!write_ptable_file(pd)) + fprintf(stderr, "Error writing ptable file\n"); + + pd->generated = true; +} + +Cube +inverse_cube(Cube cube) +{ + CubeArray *arr = new_cubearray(cube, pf_all); + CubeArray *inv = new_cubearray((Cube){0}, pf_all); + Cube ret; + int i; + + for (i = 0; i < 12; i++) { + inv->ep[arr->ep[i]] = i; + inv->eofb[arr->ep[i]] = arr->eofb[i]; + inv->eorl[arr->ep[i]] = arr->eorl[i]; + inv->eoud[arr->ep[i]] = arr->eoud[i]; + } + + for (i = 0; i < 8; i++) { + inv->cp[arr->cp[i]] = i; + inv->coud[arr->cp[i]] = (3 - arr->coud[i]) % 3; + inv->corl[arr->cp[i]] = (3 - arr->corl[i]) % 3; + inv->cofb[arr->cp[i]] = (3 - arr->cofb[i]) % 3; + } + + for (int i = 0; i < 6; i++) + inv->cpos[arr->cpos[i]] = i; + + ret = arrays_to_cube(inv, pf_all); + free_cubearray(arr, pf_all); + free_cubearray(inv, pf_all); + + return ret; +} + +Move +inverse_move(Move m) +{ + return inverse_move_aux[m]; +} + +Trans +inverse_trans(Trans t) +{ + return inverse_trans_aux[t]; +} + +bool +is_admissible(Cube cube) +{ + /* TODO: this should check consistency of different orientations */ + /* TODO: check that centers are opposite and admissible */ + + CubeArray *a = new_cubearray(cube, pf_all); + int parity; + bool perm; + + 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); + + return perm && parity % 2 == 0; +} + +bool +is_solved(Cube cube, bool reorient) +{ + int i; + + if (reorient) { + for (i = 0; i < NROTATIONS; i++) + if (is_solved(apply_alg(rotation_algs[i], cube),false)) + return true; + return false; + } else { + return equal(cube, (Cube){0}); + } +} + +bool +is_solved_block(Cube cube, Block block) +{ + 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; + + return true; +} + +bool +is_solved_center(Cube cube, Center c) +{ + return what_center_at(cube, c) == c; +} + +bool +is_solved_corner(Cube cube, Corner c) +{ + return what_corner_at(cube, c) == c && + what_orientation_corner(cube.coud, c); +} + +bool +is_solved_edge(Cube cube, Edge e) +{ + return what_edge_at(cube, e) == e && + what_orientation_edge(cube.eofb, e); +} + +int +piece_orientation(Cube cube, int piece, char *orientation) +{ + 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) +{ +/* + CubeArray *arr = new_cubearray(cube, pf_all); + + for (int i = 0; i < 12; i++) + printf(" %s ", edge_string[arr->ep[i]]); + printf("\n"); + + for (int i = 0; i < 12; i++) + printf(" %c ", arr->eofb[i] + '0'); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf("%s ", corner_string[arr->cp[i]]); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf(" %c ", arr->coud[i] + '0'); + printf("\n"); + + for (int i = 0; i < 6; i++) + printf(" %s ", center_string[arr->cpos[i]]); + printf("\n"); + + free_cubearray(arr, pf_all); +*/ + + for (int i = 0; i < 12; i++) + printf(" %s ", edge_string[what_edge_at(cube, i)]); + printf("\n"); + + for (int i = 0; i < 12; i++) + printf(" %d ", what_orientation_edge(cube.eofb, i)); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf("%s ", corner_string[what_corner_at(cube, i)]); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf(" %d ", what_orientation_corner(cube.coud, i)); + printf("\n"); + + for (int i = 0; i < 6; i++) + printf(" %s ", center_string[what_center_at(cube, i)]); + printf("\n"); + +} + +Cube +random_cube() +{ + CubeArray *arr = new_cubearray((Cube){0}, pf_4val); + Cube ret; + int ep, cp, eo, co; + + ep = rand() % FACTORIAL12; + cp = rand() % FACTORIAL8; + eo = rand() % POW2TO11; + co = rand() % POW3TO7; + + index_to_perm(ep, 12, arr->ep); + index_to_perm(cp, 8, arr->cp); + int_to_sum_zero_array(eo, 2, 12, arr->eofb); + int_to_sum_zero_array(co, 3, 8, arr->coud); + + if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8)) + swap(&(arr->ep[0]), &(arr->ep[1])); + + ret = arrays_to_cube(arr, pf_4val); + free_cubearray(arr, pf_4val); + + return ret; +} + +/* TODO: clean pre_trans or put it back */ +AlgList * +solve(Cube cube, Step step, SolveOptions *opts) +{ + /*AlgListNode *node;*/ + AlgList *sols = new_alglist(); + /*Cube c = apply_trans(opts->pre_trans, cube);*/ + DfsData dd = { + .m = 0, + .niss = false, + .lb = -1, + .last1 = NULLMOVE, + .last2 = NULLMOVE, + .sols = sols, + .current_alg = new_alg("") + }; + + if (step.ready != NULL && !step.ready(cube)) { + fprintf(stderr, "Cube not ready for solving step\n"); + return sols; + } + + moveset_to_list(step.moveset, step.estimate, dd.sorted_moves); + movelist_to_position(dd.sorted_moves, dd.move_position); + + for (dd.d = opts->min_moves; + dd.d <= opts->max_moves && !(sols->len && opts->optimal_only); + dd.d++) { + if (opts->feedback) + fprintf(stderr, + "Found %d solutions, searching depth %d...\n", + sols->len, dd.d); + dfs(cube, step, opts, &dd); + } + +/* + for (node = sols->first; node != NULL; node = node->next) + transform_alg(inverse_trans(opts->pre_trans), node->alg); +*/ + + free_alg(dd.current_alg); + return sols; +} + +Alg * +inverse_alg(Alg *alg) +{ + Alg *ret = new_alg(""); + int i; + + for (i = alg->len-1; i >= 0; i--) + append_move(ret, inverse_move(alg->move[i]), alg->inv[i]); + + return ret; +} + +Alg * +new_alg(char *str) +{ + Alg *alg = malloc(sizeof(Alg)); + int i; + bool niss = false; + Move j, m; + + alg->move = malloc(30 * sizeof(Move)); + alg->inv = malloc(30 * sizeof(bool)); + alg->allocated = 30; + alg->len = 0; + + for (i = 0; str[i]; i++) { + if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n') + continue; + + if (str[i] == '(' && niss) { + fprintf(stderr, "Error reading moves: nested ( )\n"); + return alg; + } + + if (str[i] == ')' && !niss) { + fprintf(stderr, "Error reading moves: unmatched )\n"); + return alg; + } + + if (str[i] == '(' || str[i] == ')') { + niss = !niss; + continue; + } + + for (j = 0; j < NMOVES; j++) { + if (str[i] == move_string[j][0]) { + m = j; + if (m <= B && str[i+1]=='w') { + m += Uw - U; + i++; + } + if (str[i+1]=='2') { + m += 1; + i++; + } else if (str[i+1]=='\'' || str[i+1]=='3') { + m += 2; + i++; + } + append_move(alg, m, niss); + break; + } + } + } + + return alg; +} + +Alg * +on_inverse(Alg *alg) +{ + Alg *ret = new_alg(""); + int i; + + for (i = 0; i < alg->len; i++) + append_move(ret, alg->move[i], !alg->inv[i]); + + return ret; +} + +void +print_alg(Alg *alg, bool l) +{ + /* TODO: make it possible to print to stdout or to string */ + /* Maybe just return a string */ + char fill[4]; + int i; + bool niss = false; + + for (i = 0; i < alg->len; i++) { + if (!niss && alg->inv[i]) + strcpy(fill, i == 0 ? "(" : " ("); + if (niss && !alg->inv[i]) + strcpy(fill, ") "); + if (niss == alg->inv[i]) + strcpy(fill, i == 0 ? "" : " "); + + printf("%s%s", fill, move_string[alg->move[i]]); + niss = alg->inv[i]; + } + + if (niss) + printf(")"); + if (l) + printf(" (%d)", alg->len); + + printf("\n"); +} + +void +print_alglist(AlgList *al, bool l) +{ + AlgListNode *i; + + for (i = al->first; i != NULL; i = i->next) + print_alg(i->alg, l); +} + +void +print_ptable(PruneData *pd) +{ + uint64_t i, a[16]; + + for (i = 0; i < 16; i++) + a[i] = 0; + + if (!pd->generated) + genptable(pd); + + for (i = 0; i < pd->coord->max; i++) + a[ptableval(pd, pd->coord->cube(i))]++; + + fprintf(stderr, "Values for table %s\n", pd->filename); + for (i = 0; i < 16; i++) + printf("%2lu\t%10lu\n", i, a[i]); +} + +uint64_t +ptablesize(PruneData *pd) +{ + return (pd->coord->max + 1) / 2; +} + +int +ptableval(PruneData *pd, Cube cube) +{ + return ptableval_index(pd, pd->coord->index(cube)); +} + +Alg * +rotation_alg(Trans i) +{ + return rotation_algs[i % NROTATIONS]; +} + +void +transform_alg(Trans t, Alg *alg) +{ + int i; + + for (i = 0; i < alg->len; i++) + alg->move[i] = moves_ttable[t][alg->move[i]]; +} + +Center +what_center_at(Cube cube, Center c) +{ + return what_center_at_aux[cube.cpos][c]; +} + +Corner +what_corner_at(Cube cube, Corner c) +{ + return what_corner_at_aux[cube.cp][c]; +} + +Edge +what_edge_at(Cube cube, Edge e) +{ + Edge ret; + CubeArray *arr = new_cubearray(cube, pf_ep); + + ret = arr->ep[e]; + + free_cubearray(arr, pf_ep); + return ret; +} + +int +what_orientation_corner(int co, Corner c) +{ + if (c < 7) + return (co / powint(3, c)) % 3; + else + return what_orientation_last_corner_aux[co]; +} + +int +what_orientation_edge(int eo, Edge e) +{ + if (e < 11) + return (eo & (1 << e)) ? 1 : 0; + else + return what_orientation_last_edge_aux[eo]; +} + +Center +where_is_center(Cube cube, Center c) +{ + return where_is_center_aux[cube.cpos][c]; +} + +Corner +where_is_corner(Cube cube, Corner c) +{ + return where_is_corner_aux[cube.cp][c]; +} + + +void +init() +{ + /* Order is important! */ + init_environment(); + init_strings(); + init_moves_aux(); + init_moves(); + init_auxtables(); + init_cphtr_cosets(); + init_trans_aux(); + init_trans(); + init_symdata(); +} + diff --git a/old/2021-07-15-almostbeforerefactor/alg.h b/old/2021-07-15-almostbeforerefactor/alg.h new file mode 100644 index 0000000..865c2b3 --- /dev/null +++ b/old/2021-07-15-almostbeforerefactor/alg.h @@ -0,0 +1,27 @@ +#ifndef ALG_H +#define ALG_H + +#include +#include +#include +#include + +#include "macros.h" +#include "cubetypes.h" + +Move base_move(Move m); +void free_alg(Alg *alg); +void free_alglist(AlgList *l); +Alg * inverse_alg(Alg *alg); +Move inverse_move(Move m); +bool moveset_HTM(Move m); +bool moveset_URF(Move m); +Alg * new_alg(char *str); +Alg * on_inverse(Alg *alg); +void print_alg(Alg *alg, bool l); +void print_alglist(AlgList *al, bool l); +Alg * rotation_alg(Trans i); +void transform_alg(Trans t, Alg *alg); + +#endif + diff --git a/old/2021-07-15-almostbeforerefactor/cube.c b/old/2021-07-15-almostbeforerefactor/cube.c new file mode 100644 index 0000000..ef16f9d --- /dev/null +++ b/old/2021-07-15-almostbeforerefactor/cube.c @@ -0,0 +1,3391 @@ +#include "cube.h" + +/* TODO: remove! */ +#include "steps.h" + +/* Local functions **********************************************************/ + +static Cube admissible_ep(Cube cube, PieceFilter f); +static Cube admissible_eos_from_eofbepos(Cube cube); +static bool allowed_next(Move move, DfsData *dd); +static void append_alg(AlgList *l, Alg *alg); +static void append_move(Alg *alg, Move m, bool inverse); +static Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a); +static void apply_permutation(int *perm, int *set, int n); +static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f); +static int array_ep_to_epos(int *ep, int *eps_solved); +static Cube arrays_to_cube(CubeArray *arr, PieceFilter f); +static int binomial(int n, int k); +static Cube compose_filtered(Cube c2, Cube c1, PieceFilter f); +static void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f); +static void dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static void dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static bool dfs_check_solved(SolveOptions *opts, DfsData *dd); +static void dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static bool dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd); +static int digit_array_to_int(int *a, int n, int b); +static int edge_slice(Edge e); /* E=0, S=1, M=2 */ +static int epos_dependent_pos(int pos1, int pos2); +static int epos_from_arrays(int *epos, int *ep); +static void epos_to_partial_ep(int epos, int *ep, int *ss); +static int factorial(int n); +static void free_alglistnode(AlgListNode *aln); +static void free_cubearray(CubeArray *arr, PieceFilter f); +static void genptable_bfs(PruneData *pd, int d, Move *ms); +static void genptable_branch(PruneData *pd, uint64_t i, int d, Move *m); +static void gensym(SymData *sd); +static void index_to_perm(int p, int n, int *r); +static void index_to_subset(int s, int n, int k, int *r); +static void init_auxtables(); +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_environment(); +static void init_moves(); +static void init_moves_aux(); +static void init_strings(); +static void init_symdata(); +static void init_trans(); +static void init_trans_aux(); +static void int_to_digit_array(int a, int b, int n, int *r); +static void int_to_sum_zero_array(int x, int b, int n, int *a); +static int invert_digits(int a, int b, int n); +static bool is_perm(int *a, int n); +static bool is_subset(int *a, int n, int k); +static Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf); +static void movelist_to_position(Move *movelist, int *position); +static void moveset_to_list(Moveset ms, Estimator f, Move *r); +static AlgList * new_alglist(); +static CubeArray * new_cubearray(Cube cube, PieceFilter f); +static int perm_sign(int *a, int n); +static int perm_to_index(int *a, int n); +static int powint(int a, int b); +static void ptable_update(PruneData *pd, Cube cube, int m); +static int ptableval_index(PruneData *pd, uint64_t ind); +static void realloc_alg(Alg *alg, int n); +static bool read_mtables_file(); +static bool read_ptable_file(PruneData *pd); +static bool read_symdata_file(SymData *sd); +static bool read_ttables_file(); +static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f); +static int subset_to_index(int *a, int n, int k); +static void sum_arrays_mod(int *src, int *dst, int n, int m); +static void swap(int *a, int *b); +static bool write_mtables_file(); +static bool write_ptable_file(PruneData *pd); +static bool write_symdata_file(SymData *sd); +static bool write_ttables_file(); + + +/* All sorts of useful costants and tables **********************************/ + +static char * tabledir; + +static PieceFilter pf_all; +static PieceFilter pf_4val; +static PieceFilter pf_epcp; +static PieceFilter pf_cpos; +static PieceFilter pf_cp; +static PieceFilter pf_ep; +static PieceFilter pf_e; +static PieceFilter pf_s; +static PieceFilter pf_m; +static PieceFilter pf_eo; +static PieceFilter pf_co; + +static int epe_solved[4]; +static int eps_solved[4]; +static int epm_solved[4]; + +static char move_string[NMOVES][7]; +static char edge_string[12][7]; +static char corner_string[8][7]; +static char center_string[6][7]; + +static Cube admissible_ee_aux[POW2TO11*BINOM12ON4]; +static bool commute[NMOVES][NMOVES]; +static bool possible_next[NMOVES][NMOVES][NMOVES]; +static Move inverse_move_aux[NMOVES]; +static Trans inverse_trans_aux[NTRANS]; +static int epos_dependent_aux[BINOM12ON4][BINOM12ON4]; +static int cphtr_left_cosets[FACTORIAL8]; +static int cphtr_right_cosets[FACTORIAL8]; +static int cphtr_right_rep[BINOM8ON4*6]; +static Center what_center_at_aux[FACTORIAL6][6]; +static Corner what_corner_at_aux[FACTORIAL8][8]; +static int what_orientation_last_corner_aux[POW3TO7]; +static int what_orientation_last_edge_aux[POW2TO11]; +static Center where_is_center_aux[FACTORIAL6][6]; +static Corner where_is_corner_aux[FACTORIAL8][8]; +static Edge where_is_edge_aux[3][FACTORIAL12/FACTORIAL8][12]; + +static int epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static int eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static int eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static int eo_ttable[NTRANS][POW2TO11]; +static int cp_ttable[NTRANS][FACTORIAL8]; +static int co_ttable[NTRANS][POW3TO7]; +static int cpos_ttable[NTRANS][FACTORIAL6]; +static Move moves_ttable[NTRANS][NMOVES]; + +static int epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static int eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static int eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static int eofb_mtable[NMOVES][POW2TO11]; +static int eorl_mtable[NMOVES][POW2TO11]; +static int eoud_mtable[NMOVES][POW2TO11]; +static int cp_mtable[NMOVES][FACTORIAL8]; +static int coud_mtable[NMOVES][POW3TO7]; +static int cofb_mtable[NMOVES][POW3TO7]; +static int corl_mtable[NMOVES][POW3TO7]; +static int cpos_mtable[NMOVES][FACTORIAL6]; + +static uint64_t me[12]; + +static int edge_cycle[NMOVES][12]; +static int corner_cycle[NMOVES][8]; +static int center_cycle[NMOVES][6]; +static int eofb_flipped[NMOVES][12]; +static int eorl_flipped[NMOVES][12]; +static int eoud_flipped[NMOVES][12]; +static int coud_flipped[NMOVES][8]; +static int corl_flipped[NMOVES][8]; +static int cofb_flipped[NMOVES][8]; +static Alg * equiv_alg[NMOVES]; + +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]; +static int ep_mirror[12]; +static int cp_mirror[8]; +static int cpos_mirror[6]; +static Alg * rotation_algs[NROTATIONS]; + + +/* Symmetry data for some coordinates ****************************************/ + +Trans +trans_group_trivial[1] = { uf }; + +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, +}; + +SymData +sd_coud_16 = { + .filename = "sd_coud_16", + .coord = &coord_coud, + .sym_coord = &coord_coud_sym16, + .ntrans = 16, + .trans = trans_group_udfix +}; + +SymData +sd_eofbepos_16 = { + .filename = "sd_eofbepos_16", + .coord = &coord_eofbepos, + .sym_coord = &coord_eofbepos_sym16, + .ntrans = 16, + .trans = trans_group_udfix +}; + +static int n_all_symdata = 2; +static SymData * all_sd[2] = { &sd_coud_16, &sd_eofbepos_16 }; + +/* Coordinates and their implementation **************************************/ + +static uint64_t index_eofb(Cube cube); +static uint64_t index_eofbepos(Cube cube); +static uint64_t index_coud(Cube cube); +static uint64_t index_corners(Cube cube); +static uint64_t index_cornershtr(Cube cube); +static uint64_t index_drud(Cube cube); +static uint64_t index_coud_sym16(Cube cube); +static uint64_t index_eofbepos_sym16(Cube cube); +static uint64_t index_drud_sym16(Cube cube); +static uint64_t index_khuge(Cube cube); + +static Cube antindex_eofb(uint64_t ind); +static Cube antindex_eofbepos(uint64_t ind); +static Cube antindex_coud(uint64_t ind); +static Cube antindex_corners(uint64_t ind); +static Cube antindex_cornershtr(uint64_t ind); +static Cube antindex_drud(uint64_t ind); +static Cube antindex_coud_sym16(uint64_t ind); +static Cube antindex_eofbepos_sym16(uint64_t ind); +static Cube antindex_drud_sym16(uint64_t ind); +static Cube antindex_khuge(uint64_t ind); + +Coordinate +coord_eofb = { + .index = index_eofb, + .cube = antindex_eofb, + .check = check_eofb, + .max = POW2TO11 +}; + +Coordinate +coord_eofbepos = { + .index = index_eofbepos, + .cube = antindex_eofbepos, + .check = check_eofbepos, + .max = POW2TO11 * BINOM12ON4 +}; + +Coordinate +coord_coud = { + .index = index_coud, + .cube = antindex_coud, + .check = check_coud, + .max = POW3TO7 +}; + +Coordinate +coord_corners = { + .index = index_corners, + .cube = antindex_corners, + .check = check_corners, + .max = POW3TO7 * FACTORIAL8 +}; + +Coordinate +coord_cornershtr = { + .index = index_cornershtr, + .cube = antindex_cornershtr, + .check = check_cornershtr, + .max = POW3TO7 * BINOM8ON4 * 6 +}; + +Coordinate +coord_drud = { + .index = index_drud, + .cube = antindex_drud, + .check = check_drud, + .max = POW2TO11 * POW3TO7 * BINOM12ON4 +}; + +Coordinate +coord_eofbepos_sym16 = { + .index = index_eofbepos_sym16, + .cube = antindex_eofbepos_sym16, + .check = check_eofbepos, +}; + +Coordinate +coord_coud_sym16 = { + .index = index_coud_sym16, + .cube = antindex_coud_sym16, + .check = check_coud, +}; + +Coordinate +coord_drud_sym16 = { + .index = index_drud_sym16, + .cube = antindex_drud_sym16, + .check = check_drud, + .max = POW3TO7 * 64430 +}; + +Coordinate +coord_khuge = { + .index = index_khuge, + .cube = antindex_khuge, + .check = check_khuge, + .max = POW3TO7 * FACTORIAL4 * 64430 +}; + + +static uint64_t +index_eofb(Cube cube) +{ + return cube.eofb; +} + +static uint64_t +index_eofbepos(Cube cube) +{ + return (cube.epose / FACTORIAL4) * POW2TO11 + cube.eofb; +} + +static uint64_t +index_coud(Cube cube) +{ + return cube.coud; +} + +static uint64_t +index_corners(Cube cube) +{ + return cube.coud * FACTORIAL8 + cube.cp; +} + +static uint64_t +index_cornershtr(Cube cube) +{ + return cube.coud * BINOM8ON4 * 6 + cphtr(cube); +} + +static uint64_t +index_drud(Cube cube) +{ + uint64_t a, b, c; + + a = cube.eofb; + b = cube.coud; + c = cube.epose / FACTORIAL4; + + b *= POW2TO11; + c *= POW2TO11 * POW3TO7; + + return a + b + c; +} + +static uint64_t +index_coud_sym16(Cube cube) +{ + return sd_coud_16.class[index_coud(cube)]; +} + +static uint64_t +index_drud_sym16(Cube cube) +{ + Trans t; + Cube c; + + t = sd_eofbepos_16.transtorep[index_eofbepos(cube)]; + c = apply_trans(t, cube); + + return index_eofbepos_sym16(c) * POW3TO7 + c.coud; +} + +static uint64_t +index_eofbepos_sym16(Cube cube) +{ + return sd_eofbepos_16.class[index_eofbepos(cube)]; +} + +static uint64_t +index_khuge(Cube cube) +{ + Trans t; + Cube c; + uint64_t a; + + t = sd_eofbepos_16.transtorep[index_eofbepos(cube)]; + c = apply_trans(t, cube); + a = (index_eofbepos_sym16(c) * 24) + (c.epose % 24); + + return a * POW3TO7 + c.coud; +} + + +/* TODO: rename */ +static Cube +antindex_eofb(uint64_t ind) +{ + return (Cube){ .eofb = ind, .eorl = ind, .eoud = ind }; +} + +static Cube +antindex_eofbepos(uint64_t ind) +{ + return admissible_ee_aux[ind]; +} + +/* TODO: rename */ +static Cube +antindex_coud(uint64_t ind) +{ + return (Cube){ .coud = ind, .corl = ind, .cofb = ind }; +} + +/* TODO: admissible co for other orientations */ +static Cube +antindex_corners(uint64_t ind) +{ + Cube c = {0}; + + c.coud = ind / FACTORIAL8; + c.cp = ind % FACTORIAL8; + + return c; +} + +/* TODO: admissible co for other orientations */ +static Cube +antindex_cornershtr(uint64_t ind) +{ + Cube c = anti_cphtr(ind % (BINOM8ON4 * 6)); + + c.coud = ind / (BINOM8ON4 * 6); + + return c; +} + +/* TODO: admissible eos and cos */ +/* DONE: temporary fix, make it better */ +static Cube +antindex_drud(uint64_t ind) +{ + uint64_t epos, eofb; + Cube c; + + eofb = ind % POW2TO11; + epos = ind / (POW2TO11 * POW3TO7); + c = admissible_ee_aux[eofb + POW2TO11 * epos]; + + c.coud = (ind / POW2TO11) % POW3TO7; + c.corl = c.coud; + c.cofb = c.coud; + + return c; +} + +static Cube +antindex_coud_sym16(uint64_t ind) +{ + return sd_coud_16.rep[ind]; +} + +static Cube +antindex_eofbepos_sym16(uint64_t ind) +{ + return sd_eofbepos_16.rep[ind]; +} + +static Cube +antindex_drud_sym16(uint64_t ind) +{ + Cube c; + + c = sd_eofbepos_16.rep[ind/POW3TO7]; + c.coud = ind % POW3TO7; + c.cofb = c.coud; + c.corl = c.coud; + + return c; +} + +static Cube +antindex_khuge(uint64_t ind) +{ + Cube c; + + c = sd_eofbepos_16.rep[ind/(FACTORIAL4*POW3TO7)]; + c.epose = ((c.epose / 24) * 24) + ((ind/POW3TO7) % 24); + c.coud = ind % POW3TO7; + + return c; +} + + +/* Checkers ******************************************************************/ + +bool +check_centers(Cube cube) +{ + return cube.cpos == 0; +} + +bool +check_corners(Cube cube) +{ + return cube.cp == 0 && cube.coud == 0; +} + +bool +check_cornershtr(Cube cube) +{ + return cube.coud == 0 && cphtr(cube) == 0; /* TODO: use array cphtrcosets*/ +} + +bool +check_coud(Cube cube) +{ + return cube.coud == 0; +} + +bool +check_drud(Cube cube) +{ + return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0; +} + +bool +check_eofb(Cube cube) +{ + return cube.eofb == 0; +} + +bool +check_eofbepos(Cube cube) +{ + return cube.eofb == 0 && cube.epose / 24 == 0; +} + +bool +check_epose(Cube cube) +{ + return cube.epose == 0; +} + +bool +check_ep(Cube cube) +{ + return cube.epose == 0 && cube.eposs == 0 && cube.eposm == 0; +} + +bool +check_khuge(Cube cube) +{ + return check_drud(cube) && cube.epose % 24 == 0; +} + +bool +check_nothing(Cube cube) +{ + return is_admissible(cube); /*TODO: maybe change?*/ +} + +/* Movesets ******************************************************************/ + +bool +moveset_HTM(Move m) +{ + return m >= U && m <= B3; +} + +bool +moveset_URF(Move m) +{ + Move b = base_move(m); + + return b == U || b == R || b == F; +} + + +/* Local functions implementation ********************************************/ + +/* TODO: this should be an anti index (maybe?) */ +static 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 < 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; +} + +static Cube +admissible_eos_from_eofbepos(Cube cube) +{ + Edge e; + Cube ret; + CubeArray *arr = new_cubearray(cube, pf_all); + + memcpy(arr->eorl, arr->eofb, 12 * sizeof(int)); + memcpy(arr->eoud, arr->eofb, 12 * sizeof(int)); + + for (e = 0; e < 12; e++) { + if ((edge_slice(e) != 0 && edge_slice(arr->ep[e]) == 0) || + (edge_slice(e) == 0 && edge_slice(arr->ep[e]) != 0)) + arr->eorl[e] = 1 - arr->eorl[e]; + if ((edge_slice(e) != 2 && edge_slice(arr->ep[e]) == 2) || + (edge_slice(e) == 2 && edge_slice(arr->ep[e]) != 2)) + arr->eoud[e] = 1 - arr->eoud[e]; + } + + ret = arrays_to_cube(arr, pf_all); + free_cubearray(arr, pf_all); + + return ret; +} + +static bool +allowed_next(Move move, DfsData *dd) +{ + if (!possible_next[dd->last2][dd->last1][move]) + return false; + + if (commute[dd->last1][move]) + return dd->move_position[dd->last1] < dd->move_position[move]; + + return true; +} + +static void +append_alg(AlgList *l, Alg *alg) +{ + AlgListNode *node = malloc(sizeof(AlgListNode)); + int i; + + node->alg = new_alg(""); + for (i = 0; i < alg->len; i++) + append_move(node->alg, alg->move[i], alg->inv[i]); + node->next = NULL; + + if (++l->len == 1) + l->first = node; + else + l->last->next = node; + l->last = node; +} + +static void +append_move(Alg *alg, Move m, bool inverse) +{ + if (alg->len == alg->allocated) + realloc_alg(alg, 2*alg->len); + + alg->move[alg->len] = m; + alg->inv [alg->len] = inverse; + alg->len++; +} + +static Cube +apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a) +{ + Cube ret = {0}; + int i; + + for (i = 0; i < alg->len; i++) + if (alg->inv[i]) + ret = a ? apply_move(alg->move[i], ret) : + apply_move_cubearray(alg->move[i], ret, f); + + ret = compose_filtered(c, inverse_cube(ret), f); + + for (i = 0; i < alg->len; i++) + if (!alg->inv[i]) + ret = a ? apply_move(alg->move[i], ret) : + apply_move_cubearray(alg->move[i], ret, f); + + return ret; +} + +static void +apply_permutation(int *perm, int *set, int n) +{ + int *aux = malloc(n * sizeof(int)); + int i; + + if (!is_perm(perm, n)) + return; + + for (i = 0; i < n; i++) + aux[i] = set[perm[i]]; + + memcpy(set, aux, n * sizeof(int)); + free(aux); +} + +static Cube +apply_move_cubearray(Move m, Cube cube, PieceFilter f) +{ + 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); +} + +static int +array_ep_to_epos(int *ep, int *ss) +{ + 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 epos_from_arrays(epos, eps); +} + +static Cube +arrays_to_cube(CubeArray *arr, PieceFilter f) +{ + Cube ret = {0}; + + 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; +} + +static int +binomial(int n, int k) +{ + if (n < 0 || k < 0 || k > n) + return 0; + + return factorial(n) / (factorial(k) * factorial(n-k)); +} + +static Cube +compose_filtered(Cube c2, Cube c1, PieceFilter f) +{ + CubeArray *arr = new_cubearray(c2, f); + Cube ret; + + ret = move_via_arrays(arr, c1, f); + free_cubearray(arr, f); + + return ret; +} + +static void +cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f) +{ + int i; + + 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); +} + +/* +static int +cphtr_cp(int cp) +{ + int i, a[8]; + + index_to_perm(cp, 8, a); + + for (i = 0; i < 8; i++) + if (a[i] == UFR || a[i] == UBL || a[i] == DFL || a[i] == DBR) + a[i] = 0; + else + a[i] = 1; + + swap(&a[1], &a[5]); + swap(&a[3], &a[7]); + + return subset_to_index(a, 8, 4); +} +*/ + +static void +dfs(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + if (dfs_stop(c, s, opts, dd)) + return; + + if (dfs_check_solved(opts, dd)) + return; + + dfs_branch(c, s, opts, dd); + + if (opts->can_niss && !dd->niss) + dfs_niss(c, s, opts, dd); +} + +static void +dfs_branch(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + Move m, l1 = dd->last1, l2 = dd->last2, *moves = dd->sorted_moves; + + int i, maxnsol = opts->max_solutions; + + for (i = 0; moves[i] != NULLMOVE && dd->sols->len < maxnsol; i++) { + m = moves[i]; + if (allowed_next(m, dd)) { + dd->last2 = dd->last1; + dd->last1 = m; + append_move(dd->current_alg, m, dd->niss); + + dfs(apply_move(m, c), s, opts, dd); + + dd->current_alg->len--; + dd->last2 = l2; + dd->last1 = l1; + } + } +} + +static bool +dfs_check_solved(SolveOptions *opts, DfsData *dd) +{ + if (dd->lb != 0) + return false; + + if (dd->current_alg->len == dd->d) { + append_alg(dd->sols, dd->current_alg); + + if (opts->feedback) + print_alg(dd->current_alg, false); + } + + return true; +} + +static void +dfs_niss(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + Move l1 = dd->last1, l2 = dd->last2; + CubeTarget ct; + + ct.cube = apply_move(inverse_move(l1), (Cube){0}); + ct.target = 1; + + if (dd->current_alg->len == 0 || s.estimate(ct)) { + dd->niss = true; + dd->last1 = NULLMOVE; + dd->last2 = NULLMOVE; + + dfs(inverse_cube(c), s, opts, dd); + + dd->last1 = l1; + dd->last2 = l2; + dd->niss = false; + } +} + +static bool +dfs_stop(Cube c, Step s, SolveOptions *opts, DfsData *dd) +{ + CubeTarget ct = { + .cube = c, + .target = dd->d - dd->current_alg->len + }; + + if (dd->sols->len >= opts->max_solutions) + return true; + + dd->lb = s.estimate(ct); + if (opts->can_niss && !dd->niss) + dd->lb = MIN(1, dd->lb); + + if (dd->current_alg->len + dd->lb > dd->d) + return true; + + return false; +} + +static int +digit_array_to_int(int *a, int n, int b) +{ + int i, ret = 0, p = 1; + + for (i = 0; i < n; i++, p *= b) + ret += a[i] * p; + + return ret; +} + +static int +edge_slice(Edge e) { + if (e < 0 || e > 11) + return -1; + + if (e == FR || e == FL || e == BL || e == BR) + return 0; + if (e == UR || e == UL || e == DR || e == DL) + return 1; + + return 2; +} + +static int +epos_dependent_pos(int poss, int pose) +{ + int ep[12] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; + int ep8[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + int i, j; + + epos_to_partial_ep(poss*FACTORIAL4, ep, eps_solved); + epos_to_partial_ep(pose*FACTORIAL4, ep, epe_solved); + + for (i = 0, j = 0; i < 12; i++) + if (edge_slice(ep[i]) != 0) + ep8[j++] = (edge_slice(ep[i]) == 1) ? 1 : 0; + + swap(&ep8[1], &ep8[4]); + swap(&ep8[3], &ep8[6]); + + return subset_to_index(ep8, 8, 4); +} + +static int +epos_from_arrays(int *epos, int *ep) +{ + return FACTORIAL4 * subset_to_index(epos,12,4) + perm_to_index(ep,4); +} + +static void +epos_to_partial_ep(int epos, int *ep, int *ss) +{ + 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++]]; +} + +static int +factorial(int n) +{ + int i, ret = 1; + + if (n < 0) + return 0; + + for (i = 1; i <= n; i++) + ret *= i; + + return ret; +} + +void +free_alg(Alg *alg) +{ + free(alg->move); + free(alg->inv); + free(alg); +} + +void +free_alglist(AlgList *l) +{ + AlgListNode *aux, *i = l->first; + + while (i != NULL) { + aux = i->next; + free_alglistnode(i); + i = aux; + } + free(l); +} + +void +free_alglistnode(AlgListNode *aln) +{ + free_alg(aln->alg); + free(aln); +} + +static void +free_cubearray(CubeArray *arr, PieceFilter f) +{ + 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); +} + +static void +genptable_bfs(PruneData *pd, int d, Move *ms) +{ + uint64_t i; + + for (i = 0; i < pd->coord->max; i++) + if (ptableval_index(pd, i) == d) + genptable_branch(pd, i, d, ms); +} + +static void +genptable_branch(PruneData *pd, uint64_t ind, int d, Move *ms) +{ + int i, j; + Cube cc, c; + + + for (i = 0; i < pd->ntrans; i++) { + c = apply_trans(pd->trans[i], pd->coord->cube(ind)); + for (j = 0; ms[j] != NULLMOVE; j++) { + cc = apply_move(ms[j], c); + if (ptableval(pd, cc) > d+1) + ptable_update(pd, cc, d+1); + } + } +} + +static void +gensym(SymData *sd) +{ + uint64_t i, in, nreps = 0; + int j; + Cube c, d; + + if (sd->generated) + return; + + sd->class = malloc(sd->coord->max * sizeof(uint64_t)); + sd->rep = malloc(sd->coord->max * sizeof(Cube)); + sd->transtorep = malloc(sd->coord->max * sizeof(Trans)); + + 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) { + c = sd->coord->cube(i); + sd->rep[nreps] = c; + for (j = 0; j < sd->ntrans; j++) { + d = apply_trans(sd->trans[j], c); + in = sd->coord->index(d); + + if (sd->class[in] == sd->coord->max + 1) { + sd->class[in] = nreps; + sd->transtorep[in] = + inverse_trans(sd->trans[j]); + } + } + nreps++; + } + } + + sd->sym_coord->max = nreps; + sd->rep = realloc(sd->rep, nreps * sizeof(Cube)); + sd->generated = true; + + fprintf(stderr, "Found %lu classes\n", nreps); + + if (!write_symdata_file(sd)) + fprintf(stderr, "Error writing SymData file\n"); + + return; +} + +static void +index_to_perm(int p, int n, int *r) +{ + int *a = malloc(n * sizeof(int)); + int i, j, c; + + for (i = 0; i < n; i++) + a[i] = 0; + + if (p < 0 || p >= factorial(n)) + for (i = 0; i < n; i++) + r[i] = -1; + + for (i = 0; i < n; i++) { + c = 0; + j = 0; + while (c <= p / factorial(n-i-1)) + c += a[j++] ? 0 : 1; + r[i] = j-1; + a[j-1] = 1; + p %= factorial(n-i-1); + } + + free(a); +} + +static void +index_to_subset(int s, int n, int k, int *r) +{ + int i, j, v; + + if (s < 0 || s >= binomial(n, k)) { + for (i = 0; i < n; i++) + r[i] = -1; + return; + } + + for (i = 0; i < n; i++) { + if (k == n-i) { + for (j = i; j < n; j++) + r[j] = 1; + return; + } + + if (k == 0) { + for (j = i; j < n; j++) + r[j] = 0; + return; + } + + v = binomial(n-i-1, k); + if (s >= v) { + r[i] = 1; + k--; + s -= v; + } else { + r[i] = 0; + } + } +} + +static void +int_to_digit_array(int a, int b, int n, int *r) +{ + int i; + + if (b <= 1) + for (i = 0; i < n; i++) + r[i] = 0; + else + for (i = 0; i < n; i++, a /= b) + r[i] = a % b; +} + +static void +int_to_sum_zero_array(int x, int b, int n, int *a) +{ + int i, s = 0; + + if (b <= 1) { + for (i = 0; i < n; i++) + a[i] = 0; + } else { + int_to_digit_array(x, b, n-1, a); + for (i = 0; i < n - 1; i++) + s = (s + a[i]) % b; + a[n-1] = (b - s) % b; + } +} + +static int +invert_digits(int a, int b, int n) +{ + int i, ret, *r = malloc(n * sizeof(int)); + + int_to_digit_array(a, b, n, r); + for (i = 0; i < n; i++) + r[i] = (b-r[i]) % b; + + ret = digit_array_to_int(r, n, b); + free(r); + return ret; +} + +static bool +is_perm(int *a, int n) +{ + int *aux = malloc(n * sizeof(int)); + int i; + + for (i = 0; i < n; i++) + if (a[i] < 0 || a[i] >= n) + return false; + else + aux[a[i]] = 1; + + for (i = 0; i < n; i++) + if (!aux[i]) + return false; + + free(aux); + + return true; +} + +static bool +is_subset(int *a, int n, int k) +{ + int i, sum = 0; + + for (i = 0; i < n; i++) + sum += a[i] ? 1 : 0; + + return sum == k; +} + +static Cube +move_via_arrays(CubeArray *arr, Cube c, PieceFilter f) +{ + CubeArray *arrc = new_cubearray(c, f); + Cube ret; + + 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; +} + +static void +movelist_to_position(Move *movelist, int *position) +{ + Move m; + + for (m = 0; m < NMOVES && movelist[m] != NULLMOVE; m++) + position[movelist[m]] = m; +} + +static void +moveset_to_list(Moveset ms, Estimator f, Move *r) +{ + CubeTarget ct = { .target = 1 }; + int b[NMOVES]; + int na = 0, nb = 0; + Move i; + + if (ms == NULL) { + fprintf(stderr, "Error: no moveset given\n"); + return; + } + + for (i = U; i < NMOVES; i++) { + if (ms(i)) { + ct.cube = apply_move(i, (Cube){0}); + if (f != NULL && f(ct)) + r[na++] = i; + else + b[nb++] = i; + } + } + + memcpy(r + na, b, nb * sizeof(Move)); + r[na+nb] = NULLMOVE; +} + +static AlgList * +new_alglist() +{ + AlgList *ret = malloc(sizeof(AlgList)); + + ret->len = 0; + ret->first = NULL; + ret->last = NULL; + + return ret; +} + +static CubeArray * +new_cubearray(Cube cube, PieceFilter f) +{ + 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; +} + +static int +perm_sign(int *a, int n) +{ + int i, j, ret = 0; + + if (!is_perm(a,n)) + return -1; + + for (i = 0; i < n; i++) + for (j = i+1; j < n; j++) + ret += (a[i] > a[j]) ? 1 : 0; + + return ret % 2; +} + +static int +perm_to_index(int *a, int n) +{ + int i, j, c, ret = 0; + + if (!is_perm(a, n)) + return -1; + + for (i = 0; i < n; i++) { + c = 0; + for (j = i+1; j < n; j++) + c += (a[i] > a[j]) ? 1 : 0; + ret += factorial(n-i-1) * c; + } + + return ret; +} + +static int +powint(int a, int b) +{ + if (b < 0) + return 0; + if (b == 0) + return 1; + + if (b % 2) + return a * powint(a, b-1); + else + return powint(a*a, b/2); +} + +static void +ptable_update(PruneData *pd, Cube cube, int n) +{ + uint64_t ind = pd->coord->index(cube); + uint8_t oldval2 = pd->ptable[ind/2]; + int other = (ind % 2) ? oldval2 % 16 : oldval2 / 16; + + pd->ptable[ind/2] = (ind % 2) ? 16*n + other : 16*other + n; + pd->n++; +} + +static int +ptableval_index(PruneData *pd, uint64_t ind) +{ + return (ind % 2) ? pd->ptable[ind/2] / 16 : pd->ptable[ind/2] % 16; +} + +static void +realloc_alg(Alg *alg, int n) +{ + if (alg == NULL) { + fprintf(stderr, "Error: trying to reallocate NULL alg.\n"); + return; + } + + if (n < alg->len) { + fprintf(stderr, "Error: alg too long for reallocation "); + fprintf(stderr, "(%d vs %d)\n", alg->len, n); + return; + } + + if (n > 1000000) { + fprintf(stderr, "Warning: very long alg,"); + fprintf(stderr, "something might go wrong.\n"); + } + + alg->move = realloc(alg->move, n * sizeof(int)); + alg->inv = realloc(alg->inv, n * sizeof(int)); + alg->allocated = n; +} + +static bool +read_mtables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int m, b = sizeof(int); + bool r = true; + + 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 +read_ptable_file(PruneData *pd) +{ + FILE *f; + char fname[strlen(tabledir)+100]; + uint64_t r; + + strcpy(fname, tabledir); + strcat(fname, "/"); + strcat(fname, pd->filename); + + if ((f = fopen(fname, "rb")) == NULL) + return false; + + r = fread(pd->ptable, sizeof(uint8_t), ptablesize(pd), f); + fclose(f); + + return r == ptablesize(pd); +} + +static bool +read_symdata_file(SymData *sd) +{ + 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->rep, sizeof(Cube), *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_ttables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int b = sizeof(int); + bool r = true; + Move m; + + 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[6], f) == me[6]; + r = r && fread(co_ttable[m], b, me[7], f) == me[7]; + r = r && fread(cpos_ttable[m], b, me[10], f) == me[10]; + r = r && fread(moves_ttable[m], b, me[11], f) == me[11]; + } + + 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_algs[r % NROTATIONS]); + 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_algs[r % NROTATIONS], ret, f, true); + if (r >= NROTATIONS) + ret = move_via_arrays(&ma, ret, f); + + free_alg(inv); + return ret; +} + +static int +subset_to_index(int *a, int n, int k) +{ + int i, ret = 0; + + if (!is_subset(a, n, k)) + return binomial(n, k); + + for (i = 0; i < n; i++) { + if (k == n-i) + return ret; + if (a[i]) { + ret += binomial(n-i-1, k); + k--; + } + } + + return ret; +} + +static void +sum_arrays_mod(int *src, int *dst, int n, int m) +{ + int i; + + for (i = 0; i < n; i++) + dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m; +} + +static void +swap(int *a, int *b) +{ + int aux; + + aux = *a; + *a = *b; + *b = aux; +} + +static bool +write_mtables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + int m, b = sizeof(int); + bool r = true; + + 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; +} + +static bool +write_ptable_file(PruneData *pd) +{ + FILE *f; + char fname[strlen(tabledir)+100]; + uint64_t written; + + strcpy(fname, tabledir); + strcat(fname, "/"); + strcat(fname, pd->filename); + + if ((f = fopen(fname, "wb")) == NULL) + return false; + + written = fwrite(pd->ptable, sizeof(uint8_t), ptablesize(pd), f); + fclose(f); + + return written == ptablesize(pd); +} + +static bool +write_symdata_file(SymData *sd) +{ + 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->rep, sizeof(Cube), *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_ttables_file() +{ + FILE *f; + char fname[strlen(tabledir)+20]; + bool r = true; + int b = sizeof(int); + Move m; + + 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[6], f) == me[6]; + r = r && fwrite(co_ttable[m], b, me[7], f) == me[7]; + r = r && fwrite(cpos_ttable[m], b, me[10], f) == me[10]; + r = r && fwrite(moves_ttable[m], b, me[11], f) == me[11]; + } + + fclose(f); + return r; +} + +/* Init functions implementation *********************************************/ + +static void +init_auxtables() +{ + Cube c1, c2; + CubeArray *arr; + uint64_t ui, uj; + int i, j, k, auxarr[12]; + bool cij, p1, p2; + + for (ui = 0; ui < POW2TO11*BINOM12ON4; ui++) { + k = (ui / POW2TO11) * 24; + c1 = admissible_ep((Cube){ .epose = k }, pf_e); + c1.eofb = ui % POW2TO11; + c1 = admissible_eos_from_eofbepos(c1); + admissible_ee_aux[ui] = c1; + } + + for (ui = 0; ui < FACTORIAL6; ui++) { + arr = new_cubearray((Cube){.cpos = ui}, pf_cpos); + for (i = 0; i < 6; i++) { + what_center_at_aux[ui][i] = arr->cpos[i]; + where_is_center_aux[ui][arr->cpos[i]] = i; + } + free_cubearray(arr, pf_cpos); + } + + for (ui = 0; ui < FACTORIAL8; ui++) { + arr = new_cubearray((Cube){.cp = ui}, pf_cp); + for (i = 0; i < 8; i++) { + what_corner_at_aux[ui][i] = arr->cp[i]; + where_is_corner_aux[ui][arr->cp[i]] = i; + } + free_cubearray(arr, pf_cp); + } + + for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) { + arr = new_cubearray((Cube){.epose = ui}, pf_e); + for (i = 0; i < 12; i++) + if (edge_slice(arr->ep[i]) == 0) + where_is_edge_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) + where_is_edge_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) + where_is_edge_aux[2][ui][arr->ep[i]] = i; + free_cubearray(arr, pf_m); + } + + for (ui = 0; ui < POW3TO7; ui++) { + int_to_sum_zero_array(ui, 3, 8, auxarr); + what_orientation_last_corner_aux[ui] = auxarr[7]; + } + + for (ui = 0; ui < POW2TO11; ui++) { + int_to_sum_zero_array(ui, 2, 12, auxarr); + what_orientation_last_edge_aux[ui] = auxarr[11]; + } + + for (ui = 0; ui < BINOM12ON4; ui++) + for (uj = 0; uj < BINOM12ON4; uj++) + epos_dependent_aux[ui][uj]=epos_dependent_pos(ui, uj); + + for (i = 0; i < NMOVES; i++) { + for (j = 0; j < NMOVES; j++) { + c1 = apply_move(i, apply_move(j, (Cube){0})); + c2 = apply_move(j, apply_move(i, (Cube){0})); + commute[i][j] = equal(c1, c2) && i && j; + } + } + + for (i = 0; i < NMOVES; i++) { + for (j = 0; j < NMOVES; j++) { + for (k = 0; k < NMOVES; k++) { + p1 = j && base_move(j) == base_move(k); + p2 = i && base_move(i) == base_move(k); + cij = commute[i][j]; + possible_next[i][j][k] = !(p1 || (cij && p2)); + } + } + } + + for (i = 0; i < NMOVES; i++) + inverse_move_aux[i] = i ? i + 2 - 2*((i-1)%3) : NULLMOVE; + + /* Is there a more elegant way? */ + inverse_trans_aux[uf] = uf; + inverse_trans_aux[ur] = ul; + inverse_trans_aux[ul] = ur; + inverse_trans_aux[ub] = ub; + + inverse_trans_aux[df] = df; + inverse_trans_aux[dr] = dr; + inverse_trans_aux[dl] = dl; + inverse_trans_aux[db] = db; + + inverse_trans_aux[rf] = lf; + inverse_trans_aux[rd] = bl; + inverse_trans_aux[rb] = rb; + inverse_trans_aux[ru] = fr; + + inverse_trans_aux[lf] = rf; + inverse_trans_aux[ld] = br; + inverse_trans_aux[lb] = lb; + inverse_trans_aux[lu] = fl; + + inverse_trans_aux[fu] = fu; + inverse_trans_aux[fr] = ru; + inverse_trans_aux[fd] = bu; + inverse_trans_aux[fl] = lu; + + inverse_trans_aux[bu] = fd; + inverse_trans_aux[br] = ld; + inverse_trans_aux[bd] = bd; + inverse_trans_aux[bl] = rd; + + inverse_trans_aux[uf_mirror] = uf_mirror; + inverse_trans_aux[ur_mirror] = ur_mirror; + inverse_trans_aux[ul_mirror] = ul_mirror; + inverse_trans_aux[ub_mirror] = ub_mirror; + + inverse_trans_aux[df_mirror] = df_mirror; + inverse_trans_aux[dr_mirror] = dl_mirror; + inverse_trans_aux[dl_mirror] = dr_mirror; + inverse_trans_aux[db_mirror] = db_mirror; + + inverse_trans_aux[rf_mirror] = rf_mirror; + inverse_trans_aux[rd_mirror] = br_mirror; + inverse_trans_aux[rb_mirror] = lb_mirror; + inverse_trans_aux[ru_mirror] = fl_mirror; + + inverse_trans_aux[lf_mirror] = lf_mirror; + inverse_trans_aux[ld_mirror] = bl_mirror; + inverse_trans_aux[lb_mirror] = rb_mirror; + inverse_trans_aux[lu_mirror] = fr_mirror; + + inverse_trans_aux[fu_mirror] = fu_mirror; + inverse_trans_aux[fr_mirror] = lu_mirror; + inverse_trans_aux[fd_mirror] = bu_mirror; + inverse_trans_aux[fl_mirror] = ru_mirror; + + inverse_trans_aux[bu_mirror] = fd_mirror; + inverse_trans_aux[br_mirror] = rd_mirror; + inverse_trans_aux[bd_mirror] = bd_mirror; + inverse_trans_aux[bl_mirror] = ld_mirror; +} + +/* + * There is certainly a bette 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 < FACTORIAL8; i++) { + cphtr_left_cosets[i] = -1; + cphtr_right_cosets[i] = -1; + } + + /* 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++); + + /* 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++); +} + +static void +init_cphtr_left_cosets_bfs(int i, int c) +{ + int j, jj, k, next[FACTORIAL8], next2[FACTORIAL8], n, n2; + Move moves[6] = {U2, D2, R2, L2, F2, B2}; + + n = 1; + next[0] = i; + cphtr_left_cosets[i] = c; + + while (n != 0) { + for (j = 0, n2 = 0; j < n; j++) { + for (k = 0; k < 6; k++) { + jj = cp_mtable[moves[k]][next[j]]; + if (cphtr_left_cosets[jj] == -1) { + cphtr_left_cosets[jj] = c; + next2[n2++] = jj; + } + } + } + + for (j = 0; j < n2; j++) + next[j] = next2[j]; + n = n2; + } +} + +static void +init_cphtr_right_cosets_color(int i, int d) +{ + int cp; + unsigned int j; + + cphtr_right_rep[d] = i; + for (j = 0; j < FACTORIAL8; j++) { + if (cphtr_left_cosets[j] == 0) { + /* TODO: use antindexer, it's nicer */ + cp = compose((Cube){.cp = i}, (Cube){.cp = j}).cp; + cphtr_right_cosets[cp] = d; + } + } +} + +static void +init_environment() +{ + char *nissydata = getenv("NISSYDATA"); + char *localdata = getenv("XDG_DATA_HOME"); + char *home = getenv("HOME"); + bool read, write; + + if (nissydata != NULL) { + tabledir = malloc(strlen(nissydata) * sizeof(char) + 20); + strcpy(tabledir, nissydata); + } else if (localdata != NULL) { + tabledir = malloc(strlen(localdata) * sizeof(char) + 20); + strcpy(tabledir, localdata); + strcat(tabledir, "/nissy"); + } else if (home != NULL) { + tabledir = malloc(strlen(home) * sizeof(char) + 20); + strcpy(tabledir, home); + strcat(tabledir, "/.nissy"); + } + + mkdir(tabledir, 0777); + strcat(tabledir, "/tables"); + mkdir(tabledir, 0777); + + read = !access(tabledir, R_OK); + write = !access(tabledir, W_OK); + + if (!read) { + fprintf(stderr, "Table files cannot be read.\n"); + } else if (!write) { + fprintf(stderr, "Data directory not writable: "); + fprintf(stderr, "tables can be loaded, but not saved.\n"); + } +} + +static void +init_moves() { + Cube c; + CubeArray arrs; + int i; + unsigned int ui; + Move m; + + /* 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; + + fprintf(stderr, "Cannot load %s, generating it\n", "mtables"); + + /* Initialize transition tables */ + for (m = 0; m < NMOVES; m++) { + 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; + } + } + + if (!write_mtables_file()) + fprintf(stderr, "Error writing mtables\n"); +} + +static void +init_moves_aux() +{ + /* Some standard PieceFilters */ + pf_all.epose = true; + pf_all.eposs = true; + pf_all.eposm = true; + pf_all.eofb = true; + pf_all.eorl = true; + pf_all.eoud = true; + pf_all.cp = true; + pf_all.cofb = true; + pf_all.corl = true; + pf_all.coud = true; + pf_all.cpos = true; + + pf_4val.epose = true; + pf_4val.eposs = true; + pf_4val.eposm = true; + pf_4val.eofb = true; + pf_4val.coud = true; + pf_4val.cp = true; + + pf_epcp.epose = true; + pf_epcp.eposs = true; + pf_epcp.eposm = true; + pf_epcp.cp = true; + + pf_cpos.cpos = true; + + pf_cp.cp = true; + + pf_ep.epose = true; + pf_ep.eposs = true; + pf_ep.eposm = true; + + pf_e.epose = true; + pf_s.eposs = true; + pf_m.eposm = true; + + pf_eo.eofb = true; + pf_eo.eorl = true; + pf_eo.eoud = true; + + pf_co.cofb = true; + pf_co.corl = true; + pf_co.coud = true; + + /* Used to convert to and from CubeArray */ + epe_solved[0] = FR; + epe_solved[1] = FL; + epe_solved[2] = BL; + epe_solved[3] = BR; + + eps_solved[0] = UL; + eps_solved[1] = UR; + eps_solved[2] = DL; + eps_solved[3] = DR; + + epm_solved[0] = UF; + epm_solved[1] = UB; + epm_solved[2] = DF; + epm_solved[3] = DB; + + /* Table sizes, used for reading and writing files */ + me[0] = FACTORIAL12/FACTORIAL8; + me[1] = FACTORIAL12/FACTORIAL8; + me[2] = FACTORIAL12/FACTORIAL8; + me[3] = POW2TO11; + me[4] = POW2TO11; + me[5] = POW2TO11; + me[6] = FACTORIAL8; + me[7] = POW3TO7; + me[8] = POW3TO7; + me[9] = POW3TO7; + me[10] = FACTORIAL6; + me[11] = NMOVES; + + /* Cycles *********************/ + edge_cycle[U][UF] = UR; + edge_cycle[U][UL] = UF; + edge_cycle[U][UB] = UL; + edge_cycle[U][UR] = UB; + edge_cycle[U][DF] = DF; + edge_cycle[U][DL] = DL; + edge_cycle[U][DB] = DB; + edge_cycle[U][DR] = DR; + edge_cycle[U][FR] = FR; + edge_cycle[U][FL] = FL; + edge_cycle[U][BL] = BL; + edge_cycle[U][BR] = BR; + + edge_cycle[x][UF] = DF; + edge_cycle[x][UL] = FL; + edge_cycle[x][UB] = UF; + edge_cycle[x][UR] = FR; + edge_cycle[x][DF] = DB; + edge_cycle[x][DL] = BL; + edge_cycle[x][DB] = UB; + edge_cycle[x][DR] = BR; + edge_cycle[x][FR] = DR; + edge_cycle[x][FL] = DL; + edge_cycle[x][BL] = UL; + edge_cycle[x][BR] = UR; + + edge_cycle[y][UF] = UR; + edge_cycle[y][UL] = UF; + edge_cycle[y][UB] = UL; + edge_cycle[y][UR] = UB; + edge_cycle[y][DF] = DR; + edge_cycle[y][DL] = DF; + edge_cycle[y][DB] = DL; + edge_cycle[y][DR] = DB; + edge_cycle[y][FR] = BR; + edge_cycle[y][FL] = FR; + edge_cycle[y][BL] = FL; + edge_cycle[y][BR] = BL; + + corner_cycle[U][UFR] = UBR; + corner_cycle[U][UFL] = UFR; + corner_cycle[U][UBL] = UFL; + corner_cycle[U][UBR] = UBL; + corner_cycle[U][DFR] = DFR; + corner_cycle[U][DFL] = DFL; + corner_cycle[U][DBL] = DBL; + corner_cycle[U][DBR] = DBR; + + corner_cycle[x][UFR] = DFR; + corner_cycle[x][UFL] = DFL; + corner_cycle[x][UBL] = UFL; + corner_cycle[x][UBR] = UFR; + corner_cycle[x][DFR] = DBR; + corner_cycle[x][DFL] = DBL; + corner_cycle[x][DBL] = UBL; + corner_cycle[x][DBR] = UBR; + + corner_cycle[y][UFR] = UBR; + corner_cycle[y][UFL] = UFR; + corner_cycle[y][UBL] = UFL; + corner_cycle[y][UBR] = UBL; + corner_cycle[y][DFR] = DBR; + corner_cycle[y][DFL] = DFR; + corner_cycle[y][DBL] = DFL; + corner_cycle[y][DBR] = DBL; + + center_cycle[U][U_center] = U_center; + center_cycle[U][D_center] = D_center; + center_cycle[U][R_center] = R_center; + center_cycle[U][L_center] = L_center; + center_cycle[U][F_center] = F_center; + center_cycle[U][B_center] = B_center; + + center_cycle[x][U_center] = F_center; + center_cycle[x][D_center] = B_center; + center_cycle[x][R_center] = R_center; + center_cycle[x][L_center] = L_center; + center_cycle[x][F_center] = D_center; + center_cycle[x][B_center] = U_center; + + center_cycle[y][U_center] = U_center; + center_cycle[y][D_center] = D_center; + center_cycle[y][R_center] = B_center; + center_cycle[y][L_center] = F_center; + center_cycle[y][F_center] = R_center; + center_cycle[y][B_center] = L_center; + + /* Flipped pieces *************/ + eofb_flipped[x][UF] = 1; + eofb_flipped[x][UB] = 1; + eofb_flipped[x][DF] = 1; + eofb_flipped[x][DB] = 1; + + eofb_flipped[y][FR] = 1; + eofb_flipped[y][FL] = 1; + eofb_flipped[y][BL] = 1; + eofb_flipped[y][BR] = 1; + + eorl_flipped[x][UF] = 1; + eorl_flipped[x][UL] = 1; + eorl_flipped[x][UB] = 1; + eorl_flipped[x][UR] = 1; + eorl_flipped[x][DF] = 1; + eorl_flipped[x][DL] = 1; + eorl_flipped[x][DB] = 1; + eorl_flipped[x][DR] = 1; + eorl_flipped[x][FR] = 1; + eorl_flipped[x][FL] = 1; + eorl_flipped[x][BL] = 1; + eorl_flipped[x][BR] = 1; + + eorl_flipped[y][FR] = 1; + eorl_flipped[y][FL] = 1; + eorl_flipped[y][BL] = 1; + eorl_flipped[y][BR] = 1; + + eoud_flipped[U][UF] = 1; + eoud_flipped[U][UL] = 1; + eoud_flipped[U][UB] = 1; + eoud_flipped[U][UR] = 1; + + eoud_flipped[x][UF] = 1; + eoud_flipped[x][UB] = 1; + eoud_flipped[x][DF] = 1; + eoud_flipped[x][DB] = 1; + + eoud_flipped[y][UF] = 1; + eoud_flipped[y][UL] = 1; + eoud_flipped[y][UB] = 1; + eoud_flipped[y][UR] = 1; + eoud_flipped[y][DF] = 1; + eoud_flipped[y][DL] = 1; + eoud_flipped[y][DB] = 1; + eoud_flipped[y][DR] = 1; + eoud_flipped[y][FR] = 1; + eoud_flipped[y][FL] = 1; + eoud_flipped[y][BL] = 1; + eoud_flipped[y][BR] = 1; + + coud_flipped[x][UFR] = 2; + coud_flipped[x][UFL] = 1; + coud_flipped[x][UBR] = 1; + coud_flipped[x][UBL] = 2; + coud_flipped[x][DFR] = 1; + coud_flipped[x][DFL] = 2; + coud_flipped[x][DBR] = 2; + coud_flipped[x][DBL] = 1; + + corl_flipped[U][UFR] = 1; + corl_flipped[U][UFL] = 2; + corl_flipped[U][UBL] = 1; + corl_flipped[U][UBR] = 2; + + corl_flipped[y][UFR] = 1; + corl_flipped[y][UFL] = 2; + corl_flipped[y][UBL] = 1; + corl_flipped[y][UBR] = 2; + corl_flipped[y][DFR] = 2; + corl_flipped[y][DFL] = 1; + corl_flipped[y][DBL] = 2; + corl_flipped[y][DBR] = 1; + + cofb_flipped[U][UFR] = 2; + cofb_flipped[U][UFL] = 1; + cofb_flipped[U][UBL] = 2; + cofb_flipped[U][UBR] = 1; + + cofb_flipped[x][UFR] = 1; + cofb_flipped[x][UFL] = 2; + cofb_flipped[x][UBL] = 1; + cofb_flipped[x][UBR] = 2; + cofb_flipped[x][DFR] = 2; + cofb_flipped[x][DFL] = 1; + cofb_flipped[x][DBL] = 2; + cofb_flipped[x][DBR] = 1; + + cofb_flipped[y][UFR] = 2; + cofb_flipped[y][UFL] = 1; + cofb_flipped[y][UBL] = 2; + cofb_flipped[y][UBR] = 1; + cofb_flipped[y][DFR] = 1; + cofb_flipped[y][DFL] = 2; + cofb_flipped[y][DBL] = 1; + cofb_flipped[y][DBR] = 2; + + /* Equivalent moves ***********/ + equiv_alg[NULLMOVE] = new_alg(""); + + equiv_alg[U] = new_alg(" U "); + equiv_alg[U2] = new_alg(" UU "); + equiv_alg[U3] = new_alg(" UUU "); + equiv_alg[D] = new_alg(" xx U xx "); + equiv_alg[D2] = new_alg(" xx UU xx "); + equiv_alg[D3] = new_alg(" xx UUU xx "); + equiv_alg[R] = new_alg(" yx U xxxyyy "); + equiv_alg[R2] = new_alg(" yx UU xxxyyy "); + equiv_alg[R3] = new_alg(" yx UUU xxxyyy "); + equiv_alg[L] = new_alg(" yyyx U xxxy "); + equiv_alg[L2] = new_alg(" yyyx UU xxxy "); + equiv_alg[L3] = new_alg(" yyyx UUU xxxy "); + equiv_alg[F] = new_alg(" x U xxx "); + equiv_alg[F2] = new_alg(" x UU xxx "); + equiv_alg[F3] = new_alg(" x UUU xxx "); + equiv_alg[B] = new_alg(" xxx U x "); + equiv_alg[B2] = new_alg(" xxx UU x "); + equiv_alg[B3] = new_alg(" xxx UUU x "); + + equiv_alg[Uw] = new_alg(" xx U xx y "); + equiv_alg[Uw2] = new_alg(" xx UU xx yy "); + equiv_alg[Uw3] = new_alg(" xx UUU xx yyy "); + equiv_alg[Dw] = new_alg(" U yyy "); + equiv_alg[Dw2] = new_alg(" UU yy "); + equiv_alg[Dw3] = new_alg(" UUU y "); + equiv_alg[Rw] = new_alg(" yyyx U xxxy x "); + equiv_alg[Rw2] = new_alg(" yyyx UU xxxy xx "); + equiv_alg[Rw3] = new_alg(" yyyx UUU xxxy xxx "); + equiv_alg[Lw] = new_alg(" yx U xxxyyy xxx "); + equiv_alg[Lw2] = new_alg(" yx UU xxxyyy xx "); + equiv_alg[Lw3] = new_alg(" yx UUU xxxyyy x "); + equiv_alg[Fw] = new_alg(" xxx U x yxxxyyy "); + equiv_alg[Fw2] = new_alg(" xxx UU x yxxyyy "); + equiv_alg[Fw3] = new_alg(" xxx UUU x yxyyy "); + equiv_alg[Bw] = new_alg(" x U xxx yxyyy "); + equiv_alg[Bw2] = new_alg(" x UU xxx yxxyyy "); + equiv_alg[Bw3] = new_alg(" x UUU xxx yxxxyyy "); + + equiv_alg[M] = new_alg(" yx U xx UUU yxyyy "); + equiv_alg[M2] = new_alg(" yx UU xx UU xxxy "); + equiv_alg[M3] = new_alg(" yx UUU xx U yxxxy "); + equiv_alg[S] = new_alg(" x UUU xx U yyyx "); + equiv_alg[S2] = new_alg(" x UU xx UU yyx "); + equiv_alg[S3] = new_alg(" x U xx UUU yx "); + equiv_alg[E] = new_alg(" U xx UUU xxyyy "); + equiv_alg[E2] = new_alg(" UU xx UU xxyy "); + equiv_alg[E3] = new_alg(" UUU xx U xxy "); + + equiv_alg[x] = new_alg(" x "); + equiv_alg[x2] = new_alg(" xx "); + equiv_alg[x3] = new_alg(" xxx "); + equiv_alg[y] = new_alg(" y "); + equiv_alg[y2] = new_alg(" yy "); + equiv_alg[y3] = new_alg(" yyy "); + equiv_alg[z] = new_alg(" yyy x y "); + equiv_alg[z2] = new_alg(" yy xx "); + equiv_alg[z3] = new_alg(" y x yyy "); +} + +static void +init_strings() +{ + strcpy(move_string [NULLMOVE], "-" ); + strcpy(move_string [U], "U" ); + strcpy(move_string [U2], "U2" ); + strcpy(move_string [U3], "U\'" ); + strcpy(move_string [D], "D" ); + strcpy(move_string [D2], "D2" ); + strcpy(move_string [D3], "D\'" ); + strcpy(move_string [R], "R" ); + strcpy(move_string [R2], "R2" ); + strcpy(move_string [R3], "R\'" ); + strcpy(move_string [L], "L" ); + strcpy(move_string [L2], "L2" ); + strcpy(move_string [L3], "L\'" ); + strcpy(move_string [F], "F" ); + strcpy(move_string [F2], "F2" ); + strcpy(move_string [F3], "F\'" ); + strcpy(move_string [B], "B" ); + strcpy(move_string [B2], "B2" ); + strcpy(move_string [B3], "B\'" ); + strcpy(move_string [Uw], "Uw" ); + strcpy(move_string [Uw2], "Uw2" ); + strcpy(move_string [Uw3], "Uw\'" ); + strcpy(move_string [Dw], "Dw" ); + strcpy(move_string [Dw2], "Dw2" ); + strcpy(move_string [Dw3], "Dw\'" ); + strcpy(move_string [Rw], "Rw" ); + strcpy(move_string [Rw2], "Rw2" ); + strcpy(move_string [Rw3], "Rw\'" ); + strcpy(move_string [Lw], "Lw" ); + strcpy(move_string [Lw2], "Lw2" ); + strcpy(move_string [Lw3], "Lw\'" ); + strcpy(move_string [Fw], "Fw" ); + strcpy(move_string [Fw2], "Fw2" ); + strcpy(move_string [Fw3], "Fw\'" ); + strcpy(move_string [Bw], "Bw" ); + strcpy(move_string [Bw2], "Bw2" ); + strcpy(move_string [Bw3], "Bw\'" ); + strcpy(move_string [M], "M" ); + strcpy(move_string [M2], "M2" ); + strcpy(move_string [M3], "M\'" ); + strcpy(move_string [S], "S" ); + strcpy(move_string [S2], "S2" ); + strcpy(move_string [S3], "S\'" ); + strcpy(move_string [E], "E" ); + strcpy(move_string [E2], "E2" ); + strcpy(move_string [E3], "E\'" ); + strcpy(move_string [x], "x" ); + strcpy(move_string [x2], "x2" ); + strcpy(move_string [x3], "x\'" ); + strcpy(move_string [y], "y" ); + strcpy(move_string [y2], "y2" ); + strcpy(move_string [y3], "y\'" ); + strcpy(move_string [z], "z" ); + strcpy(move_string [z2], "z2" ); + strcpy(move_string [z3], "z\'" ); + + strcpy(edge_string [UF], "UF" ); + strcpy(edge_string [UL], "UL" ); + strcpy(edge_string [UB], "UB" ); + strcpy(edge_string [UR], "UR" ); + strcpy(edge_string [DF], "DF" ); + strcpy(edge_string [DL], "DL" ); + strcpy(edge_string [DB], "DB" ); + strcpy(edge_string [DR], "DR" ); + strcpy(edge_string [FR], "FR" ); + strcpy(edge_string [FL], "FL" ); + strcpy(edge_string [BL], "BL" ); + strcpy(edge_string [BR], "BR" ); + + strcpy(corner_string [UFR], "UFR" ); + strcpy(corner_string [UFL], "UFL" ); + strcpy(corner_string [UBL], "UBL" ); + strcpy(corner_string [UBR], "UBR" ); + strcpy(corner_string [DFR], "DFR" ); + strcpy(corner_string [DFL], "DFL" ); + strcpy(corner_string [DBL], "DBL" ); + strcpy(corner_string [DBR], "DBR" ); + + strcpy(center_string [U_center], "U" ); + strcpy(center_string [D_center], "D" ); + strcpy(center_string [R_center], "R" ); + strcpy(center_string [L_center], "L" ); + strcpy(center_string [F_center], "F" ); + strcpy(center_string [B_center], "B" ); +} + +static void +init_symdata() +{ + int i; + + for (i = 0; i < n_all_symdata; i++) + gensym(all_sd[i]); +} + +static void +init_trans() { + Cube aux, cube, mirr, c[3]; + CubeArray epcp; + int i, eparr[12], eoarr[12], cparr[8], coarr[8]; + unsigned int ui; + Move mi, move; + Trans m; + + /* Compute sources */ + for (i = 0; i < NTRANS; i++) { + cube = apply_alg(rotation_algs[i % NROTATIONS], (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; + } + + if (read_ttables_file()) + return; + + fprintf(stderr, "Cannot load %s, generating it\n", "ttables"); + + /* Initialize tables */ + for (m = 0; m < NTRANS; m++) { + epcp = (CubeArray){ .ep = eparr, .cp = cparr }; + cube = apply_alg(rotation_algs[m % NROTATIONS], (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++) { + aux = apply_trans(m, apply_move(mi, (Cube){0})); + for (move = 0; move < NMOVES; move++) { + cube = apply_move(inverse_move_aux[move], aux); + mirr = apply_trans(uf_mirror, cube); + if (is_solved(cube, false) || + is_solved(mirr, false)) + moves_ttable[m][mi] = move; + } + } + } + + if (!write_ttables_file()) + fprintf(stderr, "Error writing ttables\n"); +} + +static void +init_trans_aux() +{ + ep_mirror[UF] = UF; + ep_mirror[UL] = UR; + ep_mirror[UB] = UB; + ep_mirror[UR] = UL; + ep_mirror[DF] = DF; + ep_mirror[DL] = DR; + ep_mirror[DB] = DB; + ep_mirror[DR] = DL; + ep_mirror[FR] = FL; + ep_mirror[FL] = FR; + ep_mirror[BR] = BL; + ep_mirror[BL] = BR; + + cp_mirror[UFR] = UFL; + cp_mirror[UFL] = UFR; + cp_mirror[UBL] = UBR; + cp_mirror[UBR] = UBL; + cp_mirror[DFR] = DFL; + cp_mirror[DFL] = DFR; + cp_mirror[DBL] = DBR; + cp_mirror[DBR] = DBL; + + cpos_mirror[U_center] = U_center; + cpos_mirror[D_center] = D_center; + cpos_mirror[R_center] = L_center; + cpos_mirror[L_center] = R_center; + cpos_mirror[F_center] = F_center; + cpos_mirror[B_center] = B_center; + + /* Is there a more elegant way? */ + rotation_algs[uf] = new_alg(""); + rotation_algs[ur] = new_alg("y"); + rotation_algs[ub] = new_alg("y2"); + rotation_algs[ul] = new_alg("y3"); + + rotation_algs[df] = new_alg("z2"); + rotation_algs[dr] = new_alg("y z2"); + rotation_algs[db] = new_alg("x2"); + rotation_algs[dl] = new_alg("y3 z2"); + + rotation_algs[rf] = new_alg("z3"); + rotation_algs[rd] = new_alg("z3 y"); + rotation_algs[rb] = new_alg("z3 y2"); + rotation_algs[ru] = new_alg("z3 y3"); + + rotation_algs[lf] = new_alg("z"); + rotation_algs[ld] = new_alg("z y3"); + rotation_algs[lb] = new_alg("z y2"); + rotation_algs[lu] = new_alg("z y"); + + rotation_algs[fu] = new_alg("x y2"); + rotation_algs[fr] = new_alg("x y"); + rotation_algs[fd] = new_alg("x"); + rotation_algs[fl] = new_alg("x y3"); + + rotation_algs[bu] = new_alg("x3"); + rotation_algs[br] = new_alg("x3 y"); + rotation_algs[bd] = new_alg("x3 y2"); + rotation_algs[bl] = new_alg("x3 y3"); +} + + +/* Public functions implementation *******************************************/ + +Cube +apply_alg(Alg *alg, Cube cube) +{ + return apply_alg_generic(alg, cube, pf_all, true); +} + +Cube +apply_move(Move m, Cube cube) +{ + 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] + }; +} + + +Cube +apply_trans(Trans t, Cube cube) +{ + 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] + }; +} + +Move +base_move(Move m) +{ + if (m == NULLMOVE) + return NULLMOVE; + else + return m - (m-1)%3; +} + +Cube +compose(Cube c2, Cube c1) +{ + return compose_filtered(c2, c1, pf_all); +} + +/*TODO maybe move the next two */ +uint64_t +cphtr(Cube cube) +{ + return cphtr_right_cosets[cube.cp]; +} + +Cube +anti_cphtr(uint64_t ind) +{ + return (Cube) { .cp = cphtr_right_rep[ind] }; +} + +uint64_t +epos_dependent(Cube c) +{ + return epos_dependent_aux[c.eposs/FACTORIAL4][c.epose/FACTORIAL4]; +} + +bool +equal(Cube c1, Cube c2) +{ + 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; +} + +void +genptable(PruneData *pd) +{ + Move ms[NMOVES]; + int d; + uint64_t j, oldn = 0; + + if (pd->generated) + return; + + /* TODO: check if memory is enough, otherwise maybe crash gracefully? */ + pd->ptable = malloc(ptablesize(pd) * sizeof(uint8_t)); + + if (read_ptable_file(pd)) { + pd->generated = true; + return; + } + + fprintf(stderr, "Cannot load %s, generating it\n", pd->filename); + + moveset_to_list(pd->moveset, NULL, ms); + + /* We use 4 bits per value, so any distance >= 15 is set to 15 */ + for (j = 0; j < pd->coord->max; j++) + ptable_update(pd, pd->coord->cube(j), 15); + + /*TODO: change, set to 0 for every solved state (might be more than 1)*/ + ptable_update(pd, (Cube){0}, 0); + pd->n = 1; + + for (d = 0; d < 15 && pd->n < pd->coord->max; d++) { + genptable_bfs(pd, d, ms); + fprintf(stderr, "Depth %d done, generated %lu\t(%lu/%lu)\n", + d, pd->n - oldn, pd->n, pd->coord->max); + oldn = pd->n; + } + + if (!write_ptable_file(pd)) + fprintf(stderr, "Error writing ptable file\n"); + + pd->generated = true; +} + +Cube +inverse_cube(Cube cube) +{ + CubeArray *arr = new_cubearray(cube, pf_all); + CubeArray *inv = new_cubearray((Cube){0}, pf_all); + Cube ret; + int i; + + for (i = 0; i < 12; i++) { + inv->ep[arr->ep[i]] = i; + inv->eofb[arr->ep[i]] = arr->eofb[i]; + inv->eorl[arr->ep[i]] = arr->eorl[i]; + inv->eoud[arr->ep[i]] = arr->eoud[i]; + } + + for (i = 0; i < 8; i++) { + inv->cp[arr->cp[i]] = i; + inv->coud[arr->cp[i]] = (3 - arr->coud[i]) % 3; + inv->corl[arr->cp[i]] = (3 - arr->corl[i]) % 3; + inv->cofb[arr->cp[i]] = (3 - arr->cofb[i]) % 3; + } + + for (int i = 0; i < 6; i++) + inv->cpos[arr->cpos[i]] = i; + + ret = arrays_to_cube(inv, pf_all); + free_cubearray(arr, pf_all); + free_cubearray(inv, pf_all); + + return ret; +} + +Move +inverse_move(Move m) +{ + return inverse_move_aux[m]; +} + +Trans +inverse_trans(Trans t) +{ + return inverse_trans_aux[t]; +} + +bool +is_admissible(Cube cube) +{ + /* TODO: this should check consistency of different orientations */ + /* TODO: check that centers are opposite and admissible */ + + CubeArray *a = new_cubearray(cube, pf_all); + int parity; + bool perm; + + 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); + + return perm && parity % 2 == 0; +} + +bool +is_solved(Cube cube, bool reorient) +{ + int i; + + if (reorient) { + for (i = 0; i < NROTATIONS; i++) + if (is_solved(apply_alg(rotation_algs[i], cube),false)) + return true; + return false; + } else { + return equal(cube, (Cube){0}); + } +} + +bool +is_solved_block(Cube cube, Block block) +{ + 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; + + return true; +} + +bool +is_solved_center(Cube cube, Center c) +{ + return what_center_at(cube, c) == c; +} + +bool +is_solved_corner(Cube cube, Corner c) +{ + return what_corner_at(cube, c) == c && + what_orientation_corner(cube.coud, c); +} + +bool +is_solved_edge(Cube cube, Edge e) +{ + return what_edge_at(cube, e) == e && + what_orientation_edge(cube.eofb, e); +} + +int +piece_orientation(Cube cube, int piece, char *orientation) +{ + 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) +{ +/* + CubeArray *arr = new_cubearray(cube, pf_all); + + for (int i = 0; i < 12; i++) + printf(" %s ", edge_string[arr->ep[i]]); + printf("\n"); + + for (int i = 0; i < 12; i++) + printf(" %c ", arr->eofb[i] + '0'); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf("%s ", corner_string[arr->cp[i]]); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf(" %c ", arr->coud[i] + '0'); + printf("\n"); + + for (int i = 0; i < 6; i++) + printf(" %s ", center_string[arr->cpos[i]]); + printf("\n"); + + free_cubearray(arr, pf_all); +*/ + + for (int i = 0; i < 12; i++) + printf(" %s ", edge_string[what_edge_at(cube, i)]); + printf("\n"); + + for (int i = 0; i < 12; i++) + printf(" %d ", what_orientation_edge(cube.eofb, i)); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf("%s ", corner_string[what_corner_at(cube, i)]); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf(" %d ", what_orientation_corner(cube.coud, i)); + printf("\n"); + + for (int i = 0; i < 6; i++) + printf(" %s ", center_string[what_center_at(cube, i)]); + printf("\n"); + +} + +Cube +random_cube() +{ + CubeArray *arr = new_cubearray((Cube){0}, pf_4val); + Cube ret; + int ep, cp, eo, co; + + ep = rand() % FACTORIAL12; + cp = rand() % FACTORIAL8; + eo = rand() % POW2TO11; + co = rand() % POW3TO7; + + index_to_perm(ep, 12, arr->ep); + index_to_perm(cp, 8, arr->cp); + int_to_sum_zero_array(eo, 2, 12, arr->eofb); + int_to_sum_zero_array(co, 3, 8, arr->coud); + + if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8)) + swap(&(arr->ep[0]), &(arr->ep[1])); + + ret = arrays_to_cube(arr, pf_4val); + free_cubearray(arr, pf_4val); + + return ret; +} + +/* TODO: clean pre_trans or put it back */ +AlgList * +solve(Cube cube, Step step, SolveOptions *opts) +{ + /*AlgListNode *node;*/ + AlgList *sols = new_alglist(); + /*Cube c = apply_trans(opts->pre_trans, cube);*/ + DfsData dd = { + .m = 0, + .niss = false, + .lb = -1, + .last1 = NULLMOVE, + .last2 = NULLMOVE, + .sols = sols, + .current_alg = new_alg("") + }; + + if (step.ready != NULL && !step.ready(cube)) { + fprintf(stderr, "Cube not ready for solving step\n"); + return sols; + } + + moveset_to_list(step.moveset, step.estimate, dd.sorted_moves); + movelist_to_position(dd.sorted_moves, dd.move_position); + + for (dd.d = opts->min_moves; + dd.d <= opts->max_moves && !(sols->len && opts->optimal_only); + dd.d++) { + if (opts->feedback) + fprintf(stderr, + "Found %d solutions, searching depth %d...\n", + sols->len, dd.d); + dfs(cube, step, opts, &dd); + } + +/* + for (node = sols->first; node != NULL; node = node->next) + transform_alg(inverse_trans(opts->pre_trans), node->alg); +*/ + + free_alg(dd.current_alg); + return sols; +} + +Alg * +inverse_alg(Alg *alg) +{ + Alg *ret = new_alg(""); + int i; + + for (i = alg->len-1; i >= 0; i--) + append_move(ret, inverse_move(alg->move[i]), alg->inv[i]); + + return ret; +} + +Alg * +new_alg(char *str) +{ + Alg *alg = malloc(sizeof(Alg)); + int i; + bool niss = false; + Move j, m; + + alg->move = malloc(30 * sizeof(Move)); + alg->inv = malloc(30 * sizeof(bool)); + alg->allocated = 30; + alg->len = 0; + + for (i = 0; str[i]; i++) { + if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n') + continue; + + if (str[i] == '(' && niss) { + fprintf(stderr, "Error reading moves: nested ( )\n"); + return alg; + } + + if (str[i] == ')' && !niss) { + fprintf(stderr, "Error reading moves: unmatched )\n"); + return alg; + } + + if (str[i] == '(' || str[i] == ')') { + niss = !niss; + continue; + } + + for (j = 0; j < NMOVES; j++) { + if (str[i] == move_string[j][0]) { + m = j; + if (m <= B && str[i+1]=='w') { + m += Uw - U; + i++; + } + if (str[i+1]=='2') { + m += 1; + i++; + } else if (str[i+1]=='\'' || str[i+1]=='3') { + m += 2; + i++; + } + append_move(alg, m, niss); + break; + } + } + } + + return alg; +} + +Alg * +on_inverse(Alg *alg) +{ + Alg *ret = new_alg(""); + int i; + + for (i = 0; i < alg->len; i++) + append_move(ret, alg->move[i], !alg->inv[i]); + + return ret; +} + +void +print_alg(Alg *alg, bool l) +{ + /* TODO: make it possible to print to stdout or to string */ + /* Maybe just return a string */ + char fill[4]; + int i; + bool niss = false; + + for (i = 0; i < alg->len; i++) { + if (!niss && alg->inv[i]) + strcpy(fill, i == 0 ? "(" : " ("); + if (niss && !alg->inv[i]) + strcpy(fill, ") "); + if (niss == alg->inv[i]) + strcpy(fill, i == 0 ? "" : " "); + + printf("%s%s", fill, move_string[alg->move[i]]); + niss = alg->inv[i]; + } + + if (niss) + printf(")"); + if (l) + printf(" (%d)", alg->len); + + printf("\n"); +} + +void +print_alglist(AlgList *al, bool l) +{ + AlgListNode *i; + + for (i = al->first; i != NULL; i = i->next) + print_alg(i->alg, l); +} + +void +print_ptable(PruneData *pd) +{ + uint64_t i, a[16]; + + for (i = 0; i < 16; i++) + a[i] = 0; + + if (!pd->generated) + genptable(pd); + + for (i = 0; i < pd->coord->max; i++) + a[ptableval(pd, pd->coord->cube(i))]++; + + fprintf(stderr, "Values for table %s\n", pd->filename); + for (i = 0; i < 16; i++) + printf("%2lu\t%10lu\n", i, a[i]); +} + +uint64_t +ptablesize(PruneData *pd) +{ + return (pd->coord->max + 1) / 2; +} + +int +ptableval(PruneData *pd, Cube cube) +{ + return ptableval_index(pd, pd->coord->index(cube)); +} + +Alg * +rotation_alg(Trans i) +{ + return rotation_algs[i % NROTATIONS]; +} + +void +transform_alg(Trans t, Alg *alg) +{ + int i; + + for (i = 0; i < alg->len; i++) + alg->move[i] = moves_ttable[t][alg->move[i]]; +} + +Center +what_center_at(Cube cube, Center c) +{ + return what_center_at_aux[cube.cpos][c]; +} + +Corner +what_corner_at(Cube cube, Corner c) +{ + return what_corner_at_aux[cube.cp][c]; +} + +Edge +what_edge_at(Cube cube, Edge e) +{ + Edge ret; + CubeArray *arr = new_cubearray(cube, pf_ep); + + ret = arr->ep[e]; + + free_cubearray(arr, pf_ep); + return ret; +} + +int +what_orientation_corner(int co, Corner c) +{ + if (c < 7) + return (co / powint(3, c)) % 3; + else + return what_orientation_last_corner_aux[co]; +} + +int +what_orientation_edge(int eo, Edge e) +{ + if (e < 11) + return (eo & (1 << e)) ? 1 : 0; + else + return what_orientation_last_edge_aux[eo]; +} + +Center +where_is_center(Cube cube, Center c) +{ + return where_is_center_aux[cube.cpos][c]; +} + +Corner +where_is_corner(Cube cube, Corner c) +{ + return where_is_corner_aux[cube.cp][c]; +} + + +void +init() +{ + /* Order is important! */ + init_environment(); + init_strings(); + init_moves_aux(); + init_moves(); + init_auxtables(); + init_cphtr_cosets(); + init_trans_aux(); + init_trans(); + init_symdata(); +} + diff --git a/old/2021-07-15-almostbeforerefactor/cube.h b/old/2021-07-15-almostbeforerefactor/cube.h new file mode 100644 index 0000000..c400d14 --- /dev/null +++ b/old/2021-07-15-almostbeforerefactor/cube.h @@ -0,0 +1,79 @@ +#ifndef CUBE_H +#define CUBE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "macros.h" +#include "cubetypes.h" + +extern Coordinate coord_eofb; +extern Coordinate coord_eofbepos; +extern Coordinate coord_coud; +extern Coordinate coord_corners; +extern Coordinate coord_cornershtr; +extern Coordinate coord_drud; +extern Coordinate coord_coud_sym16; +extern Coordinate coord_eofbepos_sym16; +extern Coordinate coord_drud_sym16; +extern Coordinate coord_khuge; + +extern Trans trans_group_udfix[16]; +extern Trans trans_group_trivial[1]; + +Cube apply_alg(Alg *alg, Cube cube); +Cube apply_move(Move m, Cube cube); +Cube apply_trans(Trans t, Cube cube); +bool block_solved(Cube cube, Block); +Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */ +uint64_t cphtr(Cube cube); /* TODO: rename (something with cosets) */ +Cube anti_cphtr(uint64_t ind); /*TODO also this */ +uint64_t epos_dependent(Cube cube); /* TODO: rename and turn into an indexer */ +bool equal(Cube c1, Cube c2); +Cube inverse_cube(Cube cube); +Move inverse_move(Move m); +Trans inverse_trans(Trans t); +bool is_admissible(Cube cube); +bool is_solved(Cube cube, bool reorient); +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 print_cube(Cube cube); +Cube random_cube(); +AlgList * solve(Cube cube, Step step, SolveOptions *opts); +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); + +bool check_centers(Cube cube); +bool check_corners(Cube cube); +bool check_cornershtr(Cube cube); +bool check_coud(Cube cube); +bool check_drud(Cube cube); +bool check_eofb(Cube cube); +bool check_eofbepos(Cube cube); +bool check_epose(Cube cube); +bool check_ep(Cube cube); +bool check_khuge(Cube cube); +bool check_nothing(Cube cube); + +void genptable(PruneData *pd); +void print_ptable(PruneData *pd); +uint64_t ptablesize(PruneData *pd); +int ptableval(PruneData *pd, Cube cube); + +void init(); + +#endif + diff --git a/old/2021-07-15-almostbeforerefactor/cubetypes.h b/old/2021-07-15-almostbeforerefactor/cubetypes.h new file mode 100644 index 0000000..d51314d --- /dev/null +++ b/old/2021-07-15-almostbeforerefactor/cubetypes.h @@ -0,0 +1,252 @@ +#ifndef CUBETYPES_H +#define CUBETYPES_H + +/* Typedefs ******************************************************************/ + +typedef enum center Center; +typedef enum corner Corner; +typedef enum edge Edge; +typedef enum move Move; +typedef enum trans Trans; + +typedef struct alg Alg; +typedef struct alglist AlgList; +typedef struct alglistnode AlgListNode; +typedef struct block Block; +typedef struct coordinate Coordinate; +typedef struct cube Cube; +typedef struct cubearray CubeArray; +typedef struct cubetarget CubeTarget; +typedef struct dfsdata DfsData; +typedef struct piecefilter PieceFilter; +typedef struct prunedata PruneData; +typedef struct solveoptions SolveOptions; +typedef struct step Step; +typedef struct symdata SymData; + +typedef Cube (*AntiIndexer) (uint64_t); +typedef bool (*Checker) (Cube); +typedef int (*Estimator) (CubeTarget); +typedef uint64_t (*Indexer) (Cube); +typedef bool (*Moveset) (Move); + + +/* Enums *********************************************************************/ + +enum +center +{ + U_center, D_center, + R_center, L_center, + F_center, B_center +}; + +enum +corner +{ + UFR, UFL, UBL, UBR, + DFR, DFL, DBL, DBR +}; + +enum +edge +{ + UF, UL, UB, UR, + DF, DL, DB, DR, + FR, FL, BL, BR +}; + +enum +move +{ + NULLMOVE, + U, U2, U3, D, D2, D3, + R, R2, R3, L, L2, L3, + F, F2, F3, B, B2, B3, + Uw, Uw2, Uw3, Dw, Dw2, Dw3, + Rw, Rw2, Rw3, Lw, Lw2, Lw3, + Fw, Fw2, Fw3, Bw, Bw2, Bw3, + M, M2, M3, + S, S2, S3, + E, E2, E3, + x, x2, x3, + y, y2, y3, + z, z2, z3, +}; + +enum +trans +{ + uf, ur, ub, ul, + df, dr, db, dl, + rf, rd, rb, ru, + lf, ld, lb, lu, + fu, fr, fd, fl, + bu, br, bd, bl, + uf_mirror, ur_mirror, ub_mirror, ul_mirror, + df_mirror, dr_mirror, db_mirror, dl_mirror, + rf_mirror, rd_mirror, rb_mirror, ru_mirror, + lf_mirror, ld_mirror, lb_mirror, lu_mirror, + fu_mirror, fr_mirror, fd_mirror, fl_mirror, + bu_mirror, br_mirror, bd_mirror, bl_mirror, +}; + + +/* Structs *******************************************************************/ + +struct +alg +{ + Move * move; + bool * inv; + int len; + int allocated; +}; + +struct +alglist +{ + AlgListNode * first; + AlgListNode * last; + int len; +}; + +struct +alglistnode +{ + Alg * alg; + AlgListNode * next; +}; + +struct +block +{ + bool edge[12]; + bool corner[8]; + bool center[6]; +}; + +struct +coordinate +{ + Indexer index; + AntiIndexer cube; + Checker check; + uint64_t max; +}; + +struct +cube +{ + int epose; + int eposs; + int eposm; + int eofb; + int eorl; + int eoud; + int cp; + int coud; + int cofb; + int corl; + int cpos; +}; + +struct +cubearray +{ + int * ep; + int * eofb; + int * eorl; + int * eoud; + int * cp; + int * coud; + int * corl; + int * cofb; + int * cpos; +}; + +struct +cubetarget +{ + Cube cube; + int target; +}; + +struct +dfsdata +{ + int d; + int m; + int lb; + bool niss; + Move last1; + Move last2; + AlgList * sols; + Alg * current_alg; + Move sorted_moves[NMOVES]; + int move_position[NMOVES]; +}; + +struct +piecefilter +{ + 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; + uint8_t * ptable; + bool generated; + uint64_t n; + Coordinate * coord; + Moveset moveset; + int ntrans; + Trans * trans; +}; + +struct +solveoptions +{ + int min_moves; + int max_moves; + int max_solutions; + bool optimal_only; + bool can_niss; + bool feedback; +}; + +struct +step +{ + Estimator estimate; + Checker ready; + Moveset moveset; +}; + +struct +symdata +{ + char * filename; + bool generated; + Coordinate * coord; + Coordinate * sym_coord; + int ntrans; + Trans * trans; + uint64_t * class; + Cube * rep; + Trans * transtorep; +}; + +#endif diff --git a/old/2021-07-15-almostbeforerefactor/macros.h b/old/2021-07-15-almostbeforerefactor/macros.h new file mode 100644 index 0000000..af3bca1 --- /dev/null +++ b/old/2021-07-15-almostbeforerefactor/macros.h @@ -0,0 +1,23 @@ +#ifndef MACROS_H +#define MACROS_H + +#define POW2TO6 64ULL +#define POW2TO11 2048ULL +#define POW2TO12 4096ULL +#define POW3TO7 2187ULL +#define POW3TO8 6561ULL +#define FACTORIAL4 24ULL +#define FACTORIAL6 720ULL +#define FACTORIAL7 5040ULL +#define FACTORIAL8 40320ULL +#define FACTORIAL12 479001600ULL +#define BINOM12ON4 495ULL +#define BINOM8ON4 70ULL +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +#define NMOVES (z3+1) +#define NTRANS 48 +#define NROTATIONS 24 + +#endif diff --git a/old/2021-07-15-almostbeforerefactor/main.c b/old/2021-07-15-almostbeforerefactor/main.c new file mode 100644 index 0000000..482e007 --- /dev/null +++ b/old/2021-07-15-almostbeforerefactor/main.c @@ -0,0 +1,60 @@ +#include +#include "cube.h" +#include "steps.h" + +int main() { + Alg *algo; + AlgList *sols; + Cube cube; + SolveOptions opts; + char line[1000]; + int i, ns = 1; +/* Move m;*/ +/* int nrand = 10000, sum1, sum2;*/ + + Step *stps[20] = {&optimal_HTM}; + char sss[30][30] = {"Optimal solve"}; + + opts = (SolveOptions) { + .min_moves = 0, + .max_moves = 20, + .optimal_only = true, + .max_solutions = 1, + .can_niss = false, + .feedback = true, + }; + + init(); + +/* + srand(time(NULL)); + sum1 = 0; + sum2 = 0; + for (i = 0; i < nrand; i++) { + cube = random_cube(); + sum1 += drud_HTM.estimate((CubeTarget){.cube = cube, .target = 20}); + sum2 += optimal_HTM.estimate((CubeTarget){.cube = cube, .target = 20}); + } + printf("Average drud pruning: %lf\n", ((double)sum1) / ((double) nrand)); + printf("Average corners htr pruning: %lf\n", ((double)sum2) / ((double) nrand)); +*/ + + + printf("Welcome to nissy 2.0! Insert a scramble:\n"); + + if (fgets(line, 1000, stdin) != NULL) { + algo = new_alg(line); + cube = apply_alg(algo, (Cube){0}); + + for (i = 0; i < ns; i++) { + sols = solve(cube, *stps[i], &opts); + printf("%s: %d solutions found:\n", sss[i], sols->len); + print_alglist(sols, true); + free_alglist(sols); + } + free_alg(algo); + } + + return 0; +} + diff --git a/old/2021-07-15-almostbeforerefactor/nissy b/old/2021-07-15-almostbeforerefactor/nissy new file mode 100755 index 0000000..63f9c39 Binary files /dev/null and b/old/2021-07-15-almostbeforerefactor/nissy differ diff --git a/old/2021-07-15-almostbeforerefactor/steps.c b/old/2021-07-15-almostbeforerefactor/steps.c new file mode 100644 index 0000000..33dc74d --- /dev/null +++ b/old/2021-07-15-almostbeforerefactor/steps.c @@ -0,0 +1,284 @@ +#include "steps.h" + +/* Standard checkers (return lower bound) ************************************/ + +static int estimate_eofb_HTM(CubeTarget ct); +static int estimate_coud_HTM(CubeTarget ct); +static int estimate_coud_URF(CubeTarget ct); +static int estimate_corners_HTM(CubeTarget ct); +static int estimate_cornershtr_HTM(CubeTarget ct); +static int estimate_corners_URF(CubeTarget ct); +static int estimate_cornershtr_URF(CubeTarget ct); +static int estimate_drud_HTM(CubeTarget ct); +static int estimate_optimal_HTM(CubeTarget ct); + +/* Steps *********************************************************************/ + +Step +eofb_HTM = { + .estimate = estimate_eofb_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + +Step +coud_HTM = { + .estimate = estimate_coud_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + +Step +coud_URF = { + .estimate = estimate_coud_URF, + .ready = check_nothing, + .moveset = moveset_URF +}; + +Step +corners_HTM = { + .estimate = estimate_corners_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + +Step +cornershtr_HTM = { + .estimate = estimate_cornershtr_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + +Step +cornershtr_URF = { + .estimate = estimate_cornershtr_URF, + .ready = check_nothing, + .moveset = moveset_URF +}; + +Step +corners_URF = { + .estimate = estimate_corners_URF, + .ready = check_nothing, + .moveset = moveset_URF +}; + +Step +drud_HTM = { + .estimate = estimate_drud_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + +Step +optimal_HTM = { + .estimate = estimate_optimal_HTM, + .ready = check_centers, + .moveset = moveset_HTM +}; + + +/* Pruning tables ************************************************************/ + +PruneData +pd_eofb_HTM = { + .filename = "ptable_eofb_HTM", + .coord = &coord_eofb, + .moveset = moveset_HTM, + .ntrans = 1, + .trans = trans_group_trivial +}; + +PruneData +pd_coud_HTM = { + .filename = "ptable_coud_HTM", + .coord = &coord_coud, + .moveset = moveset_HTM, + .ntrans = 1, + .trans = trans_group_trivial +}; + +PruneData +pd_cornershtr_HTM = { + .filename = "ptable_cornershtr_withcosets_HTM", + .coord = &coord_cornershtr, + .moveset = moveset_HTM, + .ntrans = 1, + .trans = trans_group_trivial +}; + +PruneData +pd_corners_HTM = { + .filename = "ptable_corners_HTM", + .coord = &coord_corners, + .moveset = moveset_HTM, + .ntrans = 1, + .trans = trans_group_trivial +}; + +PruneData +pd_drud_HTM = { + .filename = "ptable_drud_HTM", + .coord = &coord_drud, + .moveset = moveset_HTM, + .ntrans = 1, + .trans = trans_group_trivial +}; + +PruneData +pd_drud_sym16_HTM = { + .filename = "ptable_drud_sym16_HTM", + .coord = &coord_drud_sym16, + .moveset = moveset_HTM, + .ntrans = 16, + .trans = trans_group_udfix +}; + +PruneData +pd_khuge_HTM = { + .filename = "ptable_khuge_HTM", + .coord = &coord_khuge, + .moveset = moveset_HTM, + .ntrans = 16, + .trans = trans_group_udfix +}; + + +/* Standard checkers (return lower bound) ************************************/ + +static int +estimate_eofb_HTM(CubeTarget ct) +{ + if (!pd_eofb_HTM.generated) + genptable(&pd_eofb_HTM); + + return ptableval(&pd_eofb_HTM, ct.cube); +} + +static int +estimate_coud_HTM(CubeTarget ct) +{ + if (!pd_coud_HTM.generated) + genptable(&pd_coud_HTM); + + return ptableval(&pd_coud_HTM, ct.cube); +} + +static int +estimate_coud_URF(CubeTarget ct) +{ + /* TODO: I can improve this by checking first the orientation of + * the corner in DBL and use that as a reference */ + + CubeTarget ct2 = {.cube = apply_move(z, ct.cube), .target = ct.target}; + CubeTarget ct3 = {.cube = apply_move(x, ct.cube), .target = ct.target}; + + int ud = estimate_coud_HTM(ct); + int rl = estimate_coud_HTM(ct2); + int fb = estimate_coud_HTM(ct3); + + return MIN(ud, MIN(rl, fb)); +} + +static int +estimate_corners_HTM(CubeTarget ct) +{ + if (!pd_corners_HTM.generated) + genptable(&pd_corners_HTM); + + return ptableval(&pd_corners_HTM, ct.cube); +} + +static int +estimate_cornershtr_HTM(CubeTarget ct) +{ + if (!pd_cornershtr_HTM.generated) + genptable(&pd_cornershtr_HTM); + + return ptableval(&pd_cornershtr_HTM, ct.cube); +} + +static int +estimate_cornershtr_URF(CubeTarget ct) +{ + /* TODO: I can improve this by checking first the corner in DBL + * and use that as a reference */ + + int c, ret = 15; + Trans i; + + for (i = 0; i < NROTATIONS; i++) { + ct.cube = apply_alg(rotation_alg(i), ct.cube); + c = estimate_cornershtr_HTM(ct); + ret = MIN(ret, c); + } + + return ret; +} + +static int +estimate_corners_URF(CubeTarget ct) +{ + /* TODO: I can improve this by checking first the corner in DBL + * and use that as a reference */ + + int c, ret = 15; + Trans i; + + for (i = 0; i < NROTATIONS; i++) { + ct.cube = apply_alg(rotation_alg(i), ct.cube); + c = estimate_corners_HTM(ct); + ret = MIN(ret, c); + } + + return ret; +} + +static int +estimate_drud_HTM(CubeTarget ct) +{ +/* + if (!pd_drud_HTM.generated) + genptable(&pd_drud_HTM); + + return ptableval(&pd_drud_HTM, ct.cube); +*/ + + if (!pd_drud_sym16_HTM.generated) + genptable(&pd_drud_sym16_HTM); + + return ptableval(&pd_drud_sym16_HTM, ct.cube); +} + +static int +estimate_optimal_HTM(CubeTarget ct) +{ + int dr1, dr2, dr3, cor, ret; + Cube cube = ct.cube; + + if (!pd_khuge_HTM.generated) + genptable(&pd_khuge_HTM); + + dr1 = ptableval(&pd_khuge_HTM, cube); + cor = estimate_corners_HTM(ct); + ret = MAX(dr1, cor); + + if (ret > ct.target) + return ret; + + cube = apply_trans(rf, ct.cube); + dr2 = ptableval(&pd_khuge_HTM, cube); + ret = MAX(ret, dr2); + + if (ret > ct.target) + return ret; + + cube = apply_trans(fd, ct.cube); + dr3 = ptableval(&pd_khuge_HTM, cube); + + /* Michiel de Bondt's trick */ + if (dr1 == dr2 && dr2 == dr3 && dr1 != 0) + dr3++; + + return MAX(ret, dr3); +} diff --git a/old/2021-07-15-almostbeforerefactor/steps.h b/old/2021-07-15-almostbeforerefactor/steps.h new file mode 100644 index 0000000..81ae11c --- /dev/null +++ b/old/2021-07-15-almostbeforerefactor/steps.h @@ -0,0 +1,24 @@ +#ifndef STEPS_H +#define STEPS_H + +#include "cube.h" + +extern Step eofb_HTM; +extern Step coud_HTM; +extern Step coud_URF; +extern Step corners_HTM; +extern Step cornershtr_HTM; +extern Step corners_URF; +extern Step cornershtr_URF; +extern Step drud_HTM; +extern Step optimal_HTM; + +extern PruneData pd_eofb_HTM; +extern PruneData pd_coud_HTM; +extern PruneData pd_corners_HTM; +extern PruneData pd_cornershtr_HTM; +extern PruneData pd_cornershtreofb_HTM; +extern PruneData pd_drud_HTM; +extern PruneData pd_khuge_HTM; + +#endif diff --git a/old/2021-11-10-beforeremovingchecker/alg.c b/old/2021-11-10-beforeremovingchecker/alg.c new file mode 100644 index 0000000..06c2d7b --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/alg.c @@ -0,0 +1,366 @@ +#include "alg.h" + +/* Local functions ***********************************************************/ + +static void free_alglistnode(AlgListNode *aln); +static void realloc_alg(Alg *alg, int n); + +/* Movesets ******************************************************************/ + +bool +moveset_HTM(Move m) +{ + return m >= U && m <= B3; +} + +bool +moveset_URF(Move m) +{ + Move b = base_move(m); + + return b == U || b == R || b == F; +} + +bool +moveset_eofb(Move m) +{ + Move b = base_move(m); + + return b == U || b == D || b == R || b == L || + ((b == F || b == B) && m == b+1); +} + +bool +moveset_drud(Move m) +{ + Move b = base_move(m); + + return b == U || b == D || + ((b == R || b == L || b == F || b == B) && m == b + 1); +} + +bool +moveset_htr(Move m) +{ + Move b = base_move(m); + + return moveset_HTM(m) && m == b + 1; +} + + +/* Functions *****************************************************************/ + +void +append_alg(AlgList *l, Alg *alg) +{ + AlgListNode *node = malloc(sizeof(AlgListNode)); + int i; + + node->alg = new_alg(""); + for (i = 0; i < alg->len; i++) + append_move(node->alg, alg->move[i], alg->inv[i]); + node->next = NULL; + + if (++l->len == 1) + l->first = node; + else + l->last->next = node; + l->last = node; +} + +void +append_move(Alg *alg, Move m, bool inverse) +{ + if (alg->len == alg->allocated) + realloc_alg(alg, 2*alg->len); + + alg->move[alg->len] = m; + alg->inv [alg->len] = inverse; + alg->len++; +} + +Move +base_move(Move m) +{ + if (m == NULLMOVE) + return NULLMOVE; + else + return m - (m-1)%3; +} + +void +compose_alg(Alg *alg1, Alg *alg2) +{ + int i; + + for (i = 0; i < alg2->len; i++) + append_move(alg1, alg2->move[i], alg2->inv[i]); +} + +void +free_alg(Alg *alg) +{ + free(alg->move); + free(alg->inv); + free(alg); +} + +void +free_alglist(AlgList *l) +{ + AlgListNode *aux, *i = l->first; + + while (i != NULL) { + aux = i->next; + free_alglistnode(i); + i = aux; + } + free(l); +} + +static void +free_alglistnode(AlgListNode *aln) +{ + free_alg(aln->alg); + free(aln); +} + +Alg * +inverse_alg(Alg *alg) +{ + Alg *ret = new_alg(""); + int i; + + for (i = alg->len-1; i >= 0; i--) + append_move(ret, inverse_move(alg->move[i]), alg->inv[i]); + + return ret; +} + +Move +inverse_move(Move m) +{ + return m == NULLMOVE ? NULLMOVE : m + 2 - 2*((m-1) % 3); +} + +char * +move_string(Move m) +{ + static char move_string_aux[NMOVES][7] = { + [NULLMOVE] = "-", + [U] = "U", [U2] = "U2", [U3] = "U\'", + [D] = "D", [D2] = "D2", [D3] = "D\'", + [R] = "R", [R2] = "R2", [R3] = "R\'", + [L] = "L", [L2] = "L2", [L3] = "L\'", + [F] = "F", [F2] = "F2", [F3] = "F\'", + [B] = "B", [B2] = "B2", [B3] = "B\'", + [Uw] = "Uw", [Uw2] = "Uw2", [Uw3] = "Uw\'", + [Dw] = "Dw", [Dw2] = "Dw2", [Dw3] = "Dw\'", + [Rw] = "Rw", [Rw2] = "Rw2", [Rw3] = "Rw\'", + [Lw] = "Lw", [Lw2] = "Lw2", [Lw3] = "Lw\'", + [Fw] = "Fw", [Fw2] = "Fw2", [Fw3] = "Fw\'", + [Bw] = "Bw", [Bw2] = "Bw2", [Bw3] = "Bw\'", + [M] = "M", [M2] = "M2", [M3] = "M\'", + [E] = "E", [E2] = "E2", [E3] = "E\'", + [S] = "S", [S2] = "S2", [S3] = "S\'", + [x] = "x", [x2] = "x2", [x3] = "x\'", + [y] = "y", [y2] = "y2", [y3] = "y\'", + [z] = "z", [z2] = "z2", [z3] = "z\'", + }; + + return move_string_aux[m]; +} + +void +movelist_to_position(Move *movelist, int *position) +{ + Move m; + + for (m = 0; m < NMOVES && movelist[m] != NULLMOVE; m++) + position[movelist[m]] = m; +} + +void +moveset_to_list(Moveset ms, Move *r) +{ + int n = 0; + Move i; + + if (ms == NULL) { + fprintf(stderr, "Error: no moveset given\n"); + return; + } + + for (i = U; i < NMOVES; i++) + if (ms(i)) + r[n++] = i; + + r[n] = NULLMOVE; +} + +Alg * +new_alg(char *str) +{ + Alg *alg = malloc(sizeof(Alg)); + int i; + bool niss = false, move_read; + Move j, m; + + alg->move = malloc(30 * sizeof(Move)); + alg->inv = malloc(30 * sizeof(bool)); + alg->allocated = 30; + alg->len = 0; + + for (i = 0; str[i]; i++) { + if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n') + continue; + + if (str[i] == '(' && niss) { + fprintf(stderr, "Error reading moves: nested ( )\n"); + return alg; + } + + if (str[i] == ')' && !niss) { + fprintf(stderr, "Error reading moves: unmatched )\n"); + return alg; + } + + if (str[i] == '(' || str[i] == ')') { + niss = !niss; + continue; + } + + move_read = false; + for (j = 0; j < NMOVES; j++) { + if (str[i] == move_string(j)[0] || + (str[i] >= 'a' && str[i] <= 'z' && + str[i] == move_string(j)[0]-('A'-'a') && j<=B)) { + m = j; + if (str[i] >= 'a' && str[i] <= 'z' && j<=B) { + m += Uw - U; + } + if (m <= B && str[i+1]=='w') { + m += Uw - U; + i++; + } + if (str[i+1]=='2') { + m += 1; + i++; + } else if (str[i+1] == '\'' || + str[i+1] == '3' || + str[i+1] == '`' ) { + m += 2; + i++; + } else if ((int)str[i+1] == -62 && + (int)str[i+2] == -76) { + /* Weird apostrophe */ + m += 2; + i += 2; + } else if ((int)str[i+1] == -30 && + (int)str[i+2] == -128 && + (int)str[i+3] == -103) { + /* MacOS apostrophe */ + m += 2; + i += 3; + } + append_move(alg, m, niss); + move_read = true; + break; + } + } + + if (!move_read) { + alg = new_alg(""); + return alg; + } + } + + return alg; +} + +AlgList * +new_alglist() +{ + AlgList *ret = malloc(sizeof(AlgList)); + + ret->len = 0; + ret->first = NULL; + ret->last = NULL; + + return ret; +} + +Alg * +on_inverse(Alg *alg) +{ + Alg *ret = new_alg(""); + int i; + + for (i = 0; i < alg->len; i++) + append_move(ret, alg->move[i], !alg->inv[i]); + + return ret; +} + +void +print_alg(Alg *alg, bool l) +{ + /* TODO: make it possible to print to stdout or to string */ + /* Maybe just return a string */ + char fill[4]; + int i; + bool niss = false; + + for (i = 0; i < alg->len; i++) { + if (!niss && alg->inv[i]) + strcpy(fill, i == 0 ? "(" : " ("); + if (niss && !alg->inv[i]) + strcpy(fill, ") "); + if (niss == alg->inv[i]) + strcpy(fill, i == 0 ? "" : " "); + + printf("%s%s", fill, move_string(alg->move[i])); + niss = alg->inv[i]; + } + + if (niss) + printf(")"); + if (l) + printf(" (%d)", alg->len); + + printf("\n"); +} + +void +print_alglist(AlgList *al, bool l) +{ + AlgListNode *i; + + for (i = al->first; i != NULL; i = i->next) + print_alg(i->alg, l); +} + +static void +realloc_alg(Alg *alg, int n) +{ + if (alg == NULL) { + fprintf(stderr, "Error: trying to reallocate NULL alg.\n"); + return; + } + + if (n < alg->len) { + fprintf(stderr, "Error: alg too long for reallocation "); + fprintf(stderr, "(%d vs %d)\n", alg->len, n); + return; + } + + if (n > 1000000) { + fprintf(stderr, "Warning: very long alg,"); + fprintf(stderr, "something might go wrong.\n"); + } + + alg->move = realloc(alg->move, n * sizeof(int)); + alg->inv = realloc(alg->inv, n * sizeof(int)); + alg->allocated = n; +} + diff --git a/old/2021-11-10-beforeremovingchecker/alg.h b/old/2021-11-10-beforeremovingchecker/alg.h new file mode 100644 index 0000000..98900b4 --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/alg.h @@ -0,0 +1,35 @@ +#ifndef ALG_H +#define ALG_H + +#include +#include +#include + +#include "cubetypes.h" +#include "utils.h" + +bool moveset_HTM(Move m); +bool moveset_URF(Move m); +bool moveset_eofb(Move m); +bool moveset_drud(Move m); +bool moveset_htr(Move m); + +void append_alg(AlgList *l, Alg *alg); +void append_move(Alg *alg, Move m, bool inverse); +void compose_alg(Alg *alg1, Alg *alg2); +Move base_move(Move m); +void free_alg(Alg *alg); +void free_alglist(AlgList *l); +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); + +#endif + diff --git a/old/2021-11-10-beforeremovingchecker/commands.c b/old/2021-11-10-beforeremovingchecker/commands.c new file mode 100644 index 0000000..b141229 --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/commands.c @@ -0,0 +1,329 @@ +#include "commands.h" + +/* Arg parsing functions *****************************************************/ + +CommandArgs * solvestep_parse_args(int c, char **v); +CommandArgs * help_parse_args(int c, char **v); +CommandArgs * print_parse_args(int c, char **v); +CommandArgs * parse_no_arg(int c, char **v); + +/* Exec functions ************************************************************/ + +static void solvestep_exec(CommandArgs *args); +static void steps_exec(CommandArgs *args); +static void commands_exec(CommandArgs *args); +static void print_exec(CommandArgs *args); +static void help_exec(CommandArgs *args); +static void quit_exec(CommandArgs *args); + +/* Local functions ***********************************************************/ + +static bool read_step(CommandArgs *args, char *str); +static bool read_scramble(int c, char **v, CommandArgs *args); + +/* Commands ******************************************************************/ + +Command +solvestep_cmd = { + .name = "solve", + .usage = "solve STEP [OPTIONS] SCRAMBLE", + .description = "Solve a step", + .parse_args = solvestep_parse_args, + .exec = solvestep_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 +print_cmd = { + .name = "print", + .usage = "print SCRAMBLE", + .description = "Print written description of the cube", + .parse_args = print_parse_args, + .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 +quit_cmd = { + .name = "quit", + .usage = "quit", + .description = "Quit nissy", + .parse_args = parse_no_arg, + .exec = quit_exec, +}; + +Command *commands[NCOMMANDS] = { + &solvestep_cmd, + &steps_cmd, + &commands_cmd, + &help_cmd, + &print_cmd, + &quit_cmd +}; + +/* Arg parsing functions implementation **************************************/ + +CommandArgs * +solvestep_parse_args(int c, char **v) +{ + int i; + long val; + + CommandArgs *a = malloc(sizeof(CommandArgs)); + + a->success = false; + a->opts = malloc(sizeof(SolveOptions)); + a->step = steps[0]; + a->command = NULL; + a->scramble = NULL; + + a->opts->min_moves = 0; + a->opts->max_moves = 20; + a->opts->max_solutions = 1; + a->opts->optimal_only = false; + a->opts->can_niss = false; + a->opts->feedback = false; + a->opts->all = false; + a->opts->print_number = true; + + for (i = 0; i < c; i++) { + if (!strcmp(v[i], "-m")) { + val = strtol(v[++i], NULL, 10); + if (val < 0 || val > 100) { + fprintf(stderr, + "Invalid min number of moves.\n"); + return a; + } + a->opts->min_moves = val; + } else if (!strcmp(v[i], "-M")) { + val = strtol(v[++i], NULL, 10); + if (val < 0 || val > 100) { + fprintf(stderr, + "Invalid max number of moves.\n"); + return a; + } + a->opts->max_moves = val; + } else if (!strcmp(v[i], "-s")) { + val = strtol(v[++i], NULL, 10); + if (val < 1 || val > 1000000) { + fprintf(stderr, + "Invalid number of solutions.\n"); + return a; + } + a->opts->max_solutions = val; + } else if (!strcmp(v[i], "-o")) { + a->opts->optimal_only = true; + } else if (!strcmp(v[i], "-n")) { + a->opts->can_niss = true; + } else if (!strcmp(v[i], "-v")) { + a->opts->feedback = true; + } else if (!strcmp(v[i], "-a")) { + a->opts->all = true; + } else if (!strcmp(v[i], "-p")) { + a->opts->print_number = false; + } else if (!read_step(a, v[i])) { + break; + } + } + + a->success = read_scramble(c-i, &v[i], a); + return a; +} + +CommandArgs * +help_parse_args(int c, char **v) +{ + int i; + CommandArgs *a = malloc(sizeof(CommandArgs)); + + a->scramble = NULL; + a->opts = NULL; + a->step = NULL; + a->command = NULL; + + if (c == 1) { + for (i = 0; i < NCOMMANDS; i++) + if (commands[i] != NULL && + !strcmp(v[0], commands[i]->name)) + a->command = commands[i]; + if (a->command == NULL) + fprintf(stderr, "%s: command not found\n", v[0]); + } + + a->success = c == 0 || (c == 1 && a->command != NULL); + return a; +} + +CommandArgs * +parse_no_arg(int c, char **v) +{ + CommandArgs *a = malloc(sizeof(CommandArgs)); + + a->scramble = NULL; + a->opts = NULL; + a->step = NULL; + a->command = NULL; + + return a; +} + +CommandArgs * +print_parse_args(int c, char **v) +{ + CommandArgs *a = malloc(sizeof(CommandArgs)); + + a->opts = NULL; + a->step = NULL; + a->command = NULL; + + a->success = read_scramble(c-1, &v[1], a); + return a; +} + +/* Exec functions implementation *********************************************/ + +static void +solvestep_exec(CommandArgs *args) +{ + Cube c = apply_alg(args->scramble, (Cube){0}); + AlgList *sols = solve(c, args->step, args->opts); + print_alglist(sols, args->opts->print_number); + free_alglist(sols); +} + +static void +steps_exec(CommandArgs *args) +{ + int i; + + for (i = 0; i < NSTEPS && steps[i] != NULL; i++) + printf("%-15s %s\n", steps[i]->shortname, steps[i]->name); +} + +static void +commands_exec(CommandArgs *args) +{ + int i; + + for (i = 0; i < NCOMMANDS && commands[i] != NULL; i++) + printf("%s\n", commands[i]->usage); + +} + +static void +print_exec(CommandArgs *args) +{ + print_cube(apply_alg(args->scramble, (Cube){0})); +} + +static void +help_exec(CommandArgs *args) +{ + /* TODO: print full nissy manpage */ + if (args->command == NULL) { + printf("Type help COMMAND for information on a "); + printf("specific command.\n"); + printf("A more complete manual page is work in progress.\n"); + } else { + printf("Command %s: %s\nusage: %s\n", args->command->name, + args->command->description, args->command->usage); + } +} + +static void +quit_exec(CommandArgs *args) +{ + exit(0); +} + +/* Local functions implementation ********************************************/ + +static bool +read_step(CommandArgs *args, char *str) +{ + int i; + + for (i = 0; i < NSTEPS; i++) { + if (steps[i] != NULL && !strcmp(steps[i]->shortname, str)) { + args->step = steps[i]; + return true; + } + } + + return false; +} + +static bool +read_scramble(int c, char **v, CommandArgs *args) +{ + int i, k, n; + unsigned int j; + char *algstr; + + if (new_alg(v[0])->len == 0) { + fprintf(stderr, "%s: moves or option unrecognized\n", v[0]); + return false; + } + + n = 0; + for(i = 0; i < c; i++) + n += strlen(v[i]); + + algstr = malloc((n + 1) * sizeof(char)); + k = 0; + for (i = 0; i < c; i++) + for (j = 0; j < strlen(v[i]); j++) + algstr[k++] = v[i][j]; + algstr[k] = 0; + + args->scramble = new_alg(algstr); + free(algstr); + + if (args->scramble->len == 0) + fprintf(stderr, "Error reading scramble\n"); + + return args->scramble->len > 0; +} + +/* Public functions implementation *******************************************/ + +void +free_args(CommandArgs *args) +{ + if (args == NULL) + return; + + if (args->scramble != NULL) + free_alg(args->scramble); + if (args->opts != NULL) + free(args->opts); + + /* step and command must not be freed, they are static! */ + + free(args); +} diff --git a/old/2021-11-10-beforeremovingchecker/commands.h b/old/2021-11-10-beforeremovingchecker/commands.h new file mode 100644 index 0000000..f2703fa --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/commands.h @@ -0,0 +1,13 @@ +#ifndef COMMANDS_H +#define COMMANDS_H + +#include "solve.h" +#include "steps.h" + +#define NCOMMANDS 10 + +void free_args(CommandArgs *args); + +extern Command * commands[NCOMMANDS]; + +#endif diff --git a/old/2021-11-10-beforeremovingchecker/coord.c b/old/2021-11-10-beforeremovingchecker/coord.c new file mode 100644 index 0000000..343dfb3 --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/coord.c @@ -0,0 +1,629 @@ +#include "coord.h" + +static Cube antindex_eofb(uint64_t ind); +static Cube antindex_eofbepos(uint64_t ind); +static Cube antindex_epud(uint64_t ind); +static Cube antindex_coud(uint64_t ind); +static Cube antindex_corners(uint64_t ind); +static Cube antindex_cp(uint64_t ind); +static Cube antindex_cphtr(uint64_t); +static Cube antindex_cornershtr(uint64_t ind); +static Cube antindex_cornershtrfin(uint64_t ind); +static Cube antindex_drud(uint64_t ind); +static Cube antindex_drud_eofb(uint64_t ind); +static Cube antindex_htr_drud(uint64_t ind); +static Cube antindex_htrfin(uint64_t ind); + +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 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_cornershtrfin(); + + +/* 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]; +static int cornershtrfin_ind[FACTORIAL8]; +static int cornershtrfin_ant[24*24/6]; + +/* Coordinates and their implementation **************************************/ + +Coordinate +coord_eofb = { + .index = index_eofb, + .cube = antindex_eofb, + .check = check_eofb, + .max = POW2TO11, + .ntrans = 1, +}; + +Coordinate +coord_eofbepos = { + .index = index_eofbepos, + .cube = antindex_eofbepos, + .check = check_eofbepos, + .max = POW2TO11 * BINOM12ON4, + .ntrans = 1, +}; + +Coordinate +coord_coud = { + .index = index_coud, + .cube = antindex_coud, + .check = check_coud, + .max = POW3TO7, + .ntrans = 1, +}; + +Coordinate +coord_corners = { + .index = index_corners, + .cube = antindex_corners, + .check = check_corners, + .max = POW3TO7 * FACTORIAL8, + .ntrans = 1, +}; + +Coordinate +coord_cp = { + .index = index_cp, + .cube = antindex_cp, + .check = check_cp, + .max = FACTORIAL8, + .ntrans = 1, +}; + +Coordinate +coord_cphtr = { + .index = index_cphtr, + .cube = antindex_cphtr, + .check = check_cphtr, + .max = BINOM8ON4 * 6, + .ntrans = 1, +}; + +Coordinate +coord_cornershtr = { + .index = index_cornershtr, + .cube = antindex_cornershtr, + .check = check_cornershtr, + .max = POW3TO7 * BINOM8ON4 * 6, + .ntrans = 1, +}; + +Coordinate +coord_cornershtrfin = { + .index = index_cornershtrfin, + .cube = antindex_cornershtrfin, + .check = check_cp, + .max = 24*24/6, + .ntrans = 1, +}; + +Coordinate +coord_epud = { + .index = index_epud, + .cube = antindex_epud, + .check = check_epud, + .max = FACTORIAL8, + .ntrans = 1, +}; + +Coordinate +coord_drud = { + .index = index_drud, + .cube = antindex_drud, + .check = check_drud, + .max = POW2TO11 * POW3TO7 * BINOM12ON4, + .ntrans = 1, +}; + +Coordinate +coord_htr_drud = { + .index = index_htr_drud, + .cube = antindex_htr_drud, + .check = check_drud, + .max = BINOM8ON4 * 6 * BINOM8ON4, + .ntrans = 1, +}; + +Coordinate +coord_htrfin = { + .index = index_htrfin, + .cube = antindex_htrfin, + .check = check_htr, + .max = 24 * 24 * 24 *24 * 24 / 6, /* should be /12 but it's ok */ + .ntrans = 1, +}; + +Coordinate +coord_drud_eofb = { + .index = index_drud_eofb, + .cube = antindex_drud_eofb, + .check = check_drud, + .max = POW3TO7 * BINOM12ON4, + .ntrans = 1, +}; + +/* Functions *****************************************************************/ + +static Cube +antindex_eofb(uint64_t ind) +{ + return (Cube){ .eofb = ind, .eorl = ind, .eoud = ind }; +} + +static Cube +antindex_eofbepos(uint64_t ind) +{ + Cube ret = {0}; + + ret.eofb = ind % POW2TO11; + ret.epose = (ind / POW2TO11) * 24; + + return ret; +} + +static Cube +antindex_epud(uint64_t ind) +{ + static bool initialized = false; + static Cube epud_aux[FACTORIAL8]; + int a[12]; + uint64_t ui; + CubeArray arr; + + if (!initialized) { + a[FR] = FR; + a[FL] = FL; + a[BL] = BL; + a[BR] = BR; + for (ui = 0; ui < FACTORIAL8; ui++) { + index_to_perm(ui, 8, a); + arr.ep = a; + epud_aux[ui] = arrays_to_cube(&arr, pf_ep); + } + + initialized = true; + } + + return epud_aux[ind]; +} + +static Cube +antindex_coud(uint64_t ind) +{ + return (Cube){ .coud = ind, .corl = ind, .cofb = ind }; +} + +static Cube +antindex_corners(uint64_t ind) +{ + Cube c = {0}; + + c.coud = ind / FACTORIAL8; + c.cp = ind % FACTORIAL8; + + return c; +} + +static Cube +antindex_cp(uint64_t ind) +{ + Cube c = {0}; + + c.cp = ind; + + return c; +} + +static Cube +antindex_cphtr(uint64_t ind) +{ + return (Cube) { .cp = cphtr_right_rep[ind] }; +} + +static Cube +antindex_cornershtr(uint64_t ind) +{ + Cube c = antindex_cphtr(ind % (BINOM8ON4 * 6)); + + c.coud = ind / (BINOM8ON4 * 6); + + return c; +} + +static Cube +antindex_cornershtrfin(uint64_t ind) +{ + return (Cube){ .cp = cornershtrfin_ant[ind] }; +} + +static Cube +antindex_drud(uint64_t ind) +{ + uint64_t epos, eofb; + Cube c; + + eofb = ind % POW2TO11; + epos = ind / (POW2TO11 * POW3TO7); + c = antindex_eofbepos(eofb + POW2TO11 * epos); + + c.coud = (ind / POW2TO11) % POW3TO7; + + return c; +} + +static Cube +antindex_drud_eofb(uint64_t ind) +{ + return antindex_drud(ind * POW2TO11); +} + +static Cube +antindex_htr_drud(uint64_t ind) +{ + Cube ret; + + ret = antindex_cphtr(ind / BINOM8ON4); + ret.eposs = (ind % BINOM8ON4) * FACTORIAL4; + + return ret; +} + +static Cube +antindex_htrfin(uint64_t ind) +{ + Cube ret; + + ret = antindex_cornershtrfin(ind/(24*24*24)); + + ret.eposm = ind % 24; + ind /= 24; + ret.eposs = ind % 24; + ind /= 24; + ret.epose = ind % 24; + + return ret; +} + +bool +check_centers(Cube cube) +{ + return cube.cpos == 0; +} + +bool +check_corners(Cube cube) +{ + return cube.cp == 0 && cube.coud == 0; +} + +bool +check_cp(Cube cube) +{ + return cube.cp == 0; +} + +bool +check_cphtr(Cube cube) +{ + return index_cphtr(cube) == 0; +} + +bool +check_cornershtr(Cube cube) +{ + return cube.coud == 0 && index_cphtr(cube) == 0; +} + +bool +check_coud(Cube cube) +{ + return cube.coud == 0; +} + +bool +check_drud(Cube cube) +{ + return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0; +} + +bool +check_htr(Cube cube) +{ + return check_cornershtr(cube) && + cube.eofb == 0 && cube.eorl == 0 && cube.eoud == 0; +} + +bool +check_drudfin_noE(Cube cube) +{ + return cube.eposs == 0 && cube.eposm == 0 && cube.cp == 0; +} + +bool +check_eofb(Cube cube) +{ + return cube.eofb == 0; +} + +bool +check_eofbepos(Cube cube) +{ + return cube.eofb == 0 && cube.epose / 24 == 0; +} + +bool +check_epose(Cube cube) +{ + return cube.epose == 0; +} + +bool +check_epud(Cube cube) +{ + return cube.eposs == 0 && cube.eposm == 0; +} + +bool +check_ep(Cube cube) +{ + return cube.epose == 0 && cube.eposs == 0 && cube.eposm == 0; +} + +bool +check_khuge(Cube cube) +{ + return check_drud(cube) && cube.epose % 24 == 0; +} + +bool +check_nothing(Cube cube) +{ + return is_admissible(cube); /*TODO: maybe change?*/ +} + +static uint64_t +index_eofb(Cube cube) +{ + return cube.eofb; +} + +static uint64_t +index_eofbepos(Cube cube) +{ + return (cube.epose / FACTORIAL4) * POW2TO11 + cube.eofb; +} + +static uint64_t +index_epud(Cube cube) +{ + uint64_t ret; + CubeArray *arr = new_cubearray(cube, pf_ep); + + ret = perm_to_index(arr->ep, 8); + free_cubearray(arr, pf_ep); + + return ret; +} + +static uint64_t +index_coud(Cube cube) +{ + return cube.coud; +} + +static uint64_t +index_corners(Cube cube) +{ + return cube.coud * FACTORIAL8 + cube.cp; +} + +static uint64_t +index_cp(Cube cube) +{ + return cube.cp; +} + +static uint64_t +index_cphtr(Cube cube) +{ + return cphtr_right_cosets[cube.cp]; +} + +static uint64_t +index_cornershtr(Cube cube) +{ + return cube.coud * BINOM8ON4 * 6 + index_cphtr(cube); +} + +static uint64_t +index_cornershtrfin(Cube cube) +{ + return cornershtrfin_ind[cube.cp]; +} + +static uint64_t +index_drud(Cube cube) +{ + uint64_t a, b, c; + + a = cube.eofb; + b = cube.coud; + c = cube.epose / FACTORIAL4; + + b *= POW2TO11; + c *= POW2TO11 * POW3TO7; + + return a + b + c; +} + +static uint64_t +index_drud_eofb(Cube cube) +{ + return index_drud(cube) / POW2TO11; +} + +static uint64_t +index_htr_drud(Cube cube) +{ + return index_cphtr(cube) * BINOM8ON4 + + (cube.eposs / FACTORIAL4) % BINOM8ON4; +} + +static uint64_t +index_htrfin(Cube cube) +{ + uint64_t epe, eps, epm, cp, ep; + + epe = cube.epose % 24; + eps = cube.eposs % 24; + epm = cube.eposm % 24; + ep = (epe * 24 + eps) *24 + epm; + cp = index_cornershtrfin(cube); + + return cp * 24 * 24 * 24 + ep; +} + +/* 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 < FACTORIAL8; i++) { + cphtr_left_cosets[i] = -1; + cphtr_right_cosets[i] = -1; + } + + /* 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++); + + /* 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++); +} + +static void +init_cphtr_left_cosets_bfs(int i, int c) +{ + int j, jj, k, next[FACTORIAL8], next2[FACTORIAL8], n, n2; + Move moves[6] = {U2, D2, R2, L2, F2, B2}; + + n = 1; + next[0] = i; + cphtr_left_cosets[i] = c; + + while (n != 0) { + for (j = 0, n2 = 0; j < n; j++) { + for (k = 0; k < 6; k++) { + /*jj = cp_mtable[moves[k]][next[j]];*/ + /* TODO fix formatting */ + jj = apply_move(moves[k], (Cube){.cp=next[j]}).cp; + if (cphtr_left_cosets[jj] == -1) { + cphtr_left_cosets[jj] = c; + next2[n2++] = jj; + } + } + } + + for (j = 0; j < n2; j++) + next[j] = next2[j]; + n = n2; + } +} + +static void +init_cphtr_right_cosets_color(int i, int d) +{ + int cp; + unsigned int j; + + cphtr_right_rep[d] = i; + for (j = 0; j < FACTORIAL8; j++) { + if (cphtr_left_cosets[j] == 0) { + /* TODO: use antindexer, it's nicer */ + cp = compose((Cube){.cp = i}, (Cube){.cp = j}).cp; + cphtr_right_cosets[cp] = d; + } + } +} + +static void +init_cornershtrfin() +{ + unsigned int i, j; + int n, c; + Move m; + + for (i = 0; i < FACTORIAL8; i++) + cornershtrfin_ind[i] = -1; + cornershtrfin_ind[0] = 0; + + /* 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(m)) { + c = apply_move(m, (Cube){.cp = j}).cp; + if (cornershtrfin_ind[c] == -1) { + cornershtrfin_ind[c] = n; + cornershtrfin_ant[n] = c; + n++; + } + } + } + } + } +} + +void +init_coord() +{ + static bool initialized = false; + if (initialized) + return; + initialized = true; + + init_cphtr_cosets(); + init_cornershtrfin(); +} + diff --git a/old/2021-11-10-beforeremovingchecker/coord.h b/old/2021-11-10-beforeremovingchecker/coord.h new file mode 100644 index 0000000..81c1e9c --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/coord.h @@ -0,0 +1,40 @@ +#ifndef COORD_H +#define COORD_H + +#include "trans.h" + +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; + +bool check_centers(Cube cube); +bool check_corners(Cube cube); +bool check_cp(Cube cube); +bool check_cphtr(Cube cube); +bool check_cornershtr(Cube cube); +bool check_coud(Cube cube); +bool check_drud(Cube cube); +bool check_htr(Cube cube); +bool check_drudfin_noE(Cube cube); +bool check_eofb(Cube cube); +bool check_eofbepos(Cube cube); +bool check_epose(Cube cube); +bool check_ep(Cube cube); +bool check_epud(Cube cube); +bool check_khuge(Cube cube); +bool check_nothing(Cube cube); + +void init_coord(); + +#endif + diff --git a/old/2021-11-10-beforeremovingchecker/cube.c b/old/2021-11-10-beforeremovingchecker/cube.c new file mode 100644 index 0000000..b621d7b --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/cube.c @@ -0,0 +1,716 @@ +#include "cube.h" + +/* Local functions **********************************************************/ + +static int array_ep_to_epos(int *ep, int *eps_solved); +static int epos_from_arrays(int *epos, int *ep); + +/* Local functions implementation ********************************************/ + +static int +array_ep_to_epos(int *ep, int *ss) +{ + 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 epos_from_arrays(epos, eps); +} + +static int +epos_from_arrays(int *epos, int *ep) +{ + return FACTORIAL4 * subset_to_index(epos,12,4) + perm_to_index(ep,4); +} + +/* Public functions implementation *******************************************/ + +Cube +arrays_to_cube(CubeArray *arr, PieceFilter f) +{ + 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; +} + +Cube +compose_filtered(Cube c2, Cube c1, PieceFilter f) +{ + CubeArray *arr = new_cubearray(c2, f); + Cube ret; + + ret = move_via_arrays(arr, c1, f); + free_cubearray(arr, f); + + return ret; +} + +void +cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f) +{ + 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 +epos_to_partial_ep(int epos, int *ep, int *ss) +{ + 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 +free_cubearray(CubeArray *arr, PieceFilter f) +{ + 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); +} + +Cube +move_via_arrays(CubeArray *arr, Cube c, PieceFilter f) +{ + CubeArray *arrc = new_cubearray(c, f); + Cube ret; + + 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; +} + +CubeArray * +new_cubearray(Cube cube, PieceFilter f) +{ + 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; +} + + +/* TODO: consider if this is good here or better in coord.c + in any case it is used in transformation init at the moment */ +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 < 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; +} + +Cube +compose(Cube c2, Cube c1) +{ + return compose_filtered(c2, c1, pf_all); +} + +int +edge_slice(Edge e) { + if (e < 0 || e > 11) + return -1; + + if (e == FR || e == FL || e == BL || e == BR) + return 0; + if (e == UR || e == UL || e == DR || e == DL) + return 1; + + return 2; +} + +bool +equal(Cube c1, Cube c2) +{ + 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 *arr = new_cubearray(cube, pf_all); + CubeArray *inv = new_cubearray((Cube){0}, pf_all); + Cube ret; + int i; + + for (i = 0; i < 12; i++) { + inv->ep[arr->ep[i]] = i; + inv->eofb[arr->ep[i]] = arr->eofb[i]; + inv->eorl[arr->ep[i]] = arr->eorl[i]; + inv->eoud[arr->ep[i]] = arr->eoud[i]; + } + + for (i = 0; i < 8; i++) { + inv->cp[arr->cp[i]] = i; + inv->coud[arr->cp[i]] = (3 - arr->coud[i]) % 3; + inv->corl[arr->cp[i]] = (3 - arr->corl[i]) % 3; + inv->cofb[arr->cp[i]] = (3 - arr->cofb[i]) % 3; + } + + for (int i = 0; i < 6; i++) + inv->cpos[arr->cpos[i]] = i; + + ret = arrays_to_cube(inv, pf_all); + free_cubearray(arr, pf_all); + free_cubearray(inv, pf_all); + + return ret; +} + +bool +is_admissible(Cube cube) +{ + /* TODO: this should check consistency of different orientations */ + /* TODO: check that centers are opposite and admissible */ + + CubeArray *a = new_cubearray(cube, pf_all); + int parity; + bool perm; + + 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); + + return perm && parity % 2 == 0; +} + +bool +is_solved(Cube cube) +{ + /* TODO: move somewhere else, like in solve.c + int i; + if (reorient) { + for (i = 0; i < NROTATIONS; i++) + if (is_solved(apply_alg(rotation_algs[i], cube),false)) + return true; + return false; + } else { + return equal(cube, (Cube){0}); + } + */ + + return equal(cube, (Cube){0}); +} + +bool +is_solved_block(Cube cube, Block block) +{ + 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; + + return true; +} + +bool +is_solved_center(Cube cube, Center c) +{ + return what_center_at(cube, c) == c; +} + +bool +is_solved_corner(Cube cube, Corner c) +{ + return what_corner_at(cube, c) == c && + what_orientation_corner(cube.coud, c); +} + +bool +is_solved_edge(Cube cube, Edge e) +{ + return what_edge_at(cube, e) == e && + what_orientation_edge(cube.eofb, e); +} + +int +piece_orientation(Cube cube, int piece, char *orientation) +{ + 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) +{ + static char edge_string[12][7] = { + [UF] = "UF", [UL] = "UL", [UB] = "UB", [UR] = "UR", + [DF] = "DF", [DL] = "DL", [DB] = "DB", [DR] = "DR", + [FR] = "FR", [FL] = "FL", [BL] = "BL", [BR] = "BR" + }; + + static char corner_string[8][7] = { + [UFR] = "UFR", [UFL] = "UFL", [UBL] = "UBL", [UBR] = "UBR", + [DFR] = "DFR", [DFL] = "DFL", [DBL] = "DBL", [DBR] = "DBR" + }; + + static char center_string[6][7] = { + [U_center] = "U", [D_center] = "D", + [R_center] = "R", [L_center] = "L", + [F_center] = "F", [B_center] = "B" + }; + + for (int i = 0; i < 12; i++) + printf(" %s ", edge_string[what_edge_at(cube, i)]); + printf("\n"); + + for (int i = 0; i < 12; i++) + printf(" %d ", what_orientation_edge(cube.eofb, i)); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf("%s ", corner_string[what_corner_at(cube, i)]); + printf("\n"); + + for (int i = 0; i < 8; i++) + printf(" %d ", what_orientation_corner(cube.coud, i)); + printf("\n"); + + for (int i = 0; i < 6; i++) + printf(" %s ", center_string[what_center_at(cube, i)]); + printf("\n"); +} + +Cube +random_cube() +{ + CubeArray *arr = new_cubearray((Cube){0}, pf_4val); + Cube ret; + int ep, cp, eo, co; + + ep = rand() % FACTORIAL12; + cp = rand() % FACTORIAL8; + eo = rand() % POW2TO11; + co = rand() % POW3TO7; + + index_to_perm(ep, 12, arr->ep); + index_to_perm(cp, 8, arr->cp); + int_to_sum_zero_array(eo, 2, 12, arr->eofb); + int_to_sum_zero_array(co, 3, 8, arr->coud); + + if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8)) + swap(&(arr->ep[0]), &(arr->ep[1])); + + ret = arrays_to_cube(arr, pf_4val); + free_cubearray(arr, pf_4val); + + return ret; +} + +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) +{ + 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][i] = arr->cp[i]; + free_cubearray(arr, pf_cp); + } + + initialized = true; + } + + return aux[cube.cp][c]; +} + +Edge +what_edge_at(Cube cube, Edge e) +{ + Edge ret; + CubeArray *arr = new_cubearray(cube, pf_ep); + + ret = arr->ep[e]; + + free_cubearray(arr, pf_ep); + return ret; +} + +int +what_orientation_corner(int co, Corner c) +{ + 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 +what_orientation_edge(int eo, Edge e) +{ + 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]; +} + +Center +where_is_center(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][arr->cpos[i]] = i; + free_cubearray(arr, pf_cpos); + } + + initialized = true; + } + + return aux[cube.cpos][c]; +} + +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 cube, Edge e) +{ + /* TODO: when I wrote this code I forgot to add the final + part, and now I can't remember how it was supposed to + work (i.e. how to recover the location of the edge + from these tables. I think it is either very easy or + wrong, in any case it is not a priority now. + Future Seba can deal with it. + + static bool initialized = false; + static Edge aux[3][FACTORIAL12/FACTORIAL8][12]; + static int i; + static unsigned int ui; + static CubeArray *arr; + + if (!initialized) { + for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) { + 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; + } + */ + + int i; + CubeArray *arr = new_cubearray(cube, pf_ep); + + for (i = 0; i < 12; i++) + if ((Edge)arr->ep[i] == e) + return i; + + return -1; +} diff --git a/old/2021-11-10-beforeremovingchecker/cube.h b/old/2021-11-10-beforeremovingchecker/cube.h new file mode 100644 index 0000000..98657ab --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/cube.h @@ -0,0 +1,40 @@ +#ifndef CUBE_H +#define CUBE_H + +#include +#include + +#include "pf.h" +#include "utils.h" + +Cube admissible_ep(Cube cube, PieceFilter f); /* TODO: move? */ +Cube arrays_to_cube(CubeArray *arr, PieceFilter f); /* TODO: remove */ +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 block_solved(Cube cube, Block); /*TODO: rename to is_solved_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 free_cubearray(CubeArray *arr, PieceFilter f); /* TODO: remove */ +Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf); +CubeArray * new_cubearray(Cube cube, PieceFilter f); /* TODO: remove */ +void print_cube(Cube cube); +Cube random_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); + +#endif + diff --git a/old/2021-11-10-beforeremovingchecker/cubetypes.h b/old/2021-11-10-beforeremovingchecker/cubetypes.h new file mode 100644 index 0000000..38a6f8d --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/cubetypes.h @@ -0,0 +1,298 @@ +#ifndef CUBETYPES_H +#define CUBETYPES_H + +#include +#include + +#define NMOVES 55 /* Actually 55, but one is NULLMOVE */ +#define NTRANS 48 +#define NROTATIONS 24 + + +/* Typedefs ******************************************************************/ + +typedef enum center Center; +typedef enum corner Corner; +typedef enum edge Edge; +typedef enum move Move; +typedef enum trans Trans; + +typedef struct alg Alg; +typedef struct alglist AlgList; +typedef struct alglistnode AlgListNode; +typedef struct block Block; +typedef struct command Command; +typedef struct commandargs CommandArgs; +typedef struct coordinate Coordinate; +typedef struct cube Cube; +typedef struct cubearray CubeArray; +typedef struct cubetarget CubeTarget; +typedef struct dfsdata DfsData; +typedef struct piecefilter PieceFilter; +typedef struct prunedata PruneData; +typedef struct solveoptions SolveOptions; +typedef struct step Step; +typedef struct symdata SymData; + +typedef Cube (*AntiIndexer) (uint64_t); +typedef bool (*Checker) (Cube); +typedef int (*Estimator) (CubeTarget); +typedef bool (*Validator) (Alg *); +typedef void (*Exec) (CommandArgs *); +typedef uint64_t (*Indexer) (Cube); +typedef bool (*Moveset) (Move); +typedef CommandArgs * (*ArgParser) (int, char **); +typedef Trans (*TransDetector) (Cube); + + +/* Enums *********************************************************************/ + +enum +center +{ + U_center, D_center, + R_center, L_center, + F_center, B_center +}; + +enum +corner +{ + UFR, UFL, UBL, UBR, + DFR, DFL, DBL, DBR +}; + +enum +edge +{ + UF, UL, UB, UR, + DF, DL, DB, DR, + FR, FL, BL, BR +}; + +enum +move +{ + NULLMOVE, + U, U2, U3, D, D2, D3, + R, R2, R3, L, L2, L3, + F, F2, F3, B, B2, B3, + Uw, Uw2, Uw3, Dw, Dw2, Dw3, + Rw, Rw2, Rw3, Lw, Lw2, Lw3, + Fw, Fw2, Fw3, Bw, Bw2, Bw3, + M, M2, M3, + S, S2, S3, + E, E2, E3, + x, x2, x3, + y, y2, y3, + z, z2, z3, +}; + +enum +trans +{ + uf, ur, ub, ul, + df, dr, db, dl, + rf, rd, rb, ru, + lf, ld, lb, lu, + fu, fr, fd, fl, + bu, br, bd, bl, + uf_mirror, ur_mirror, ub_mirror, ul_mirror, + df_mirror, dr_mirror, db_mirror, dl_mirror, + rf_mirror, rd_mirror, rb_mirror, ru_mirror, + lf_mirror, ld_mirror, lb_mirror, lu_mirror, + fu_mirror, fr_mirror, fd_mirror, fl_mirror, + bu_mirror, br_mirror, bd_mirror, bl_mirror, +}; + + +/* Structs *******************************************************************/ + +struct +alg +{ + Move * move; + bool * inv; + int len; + int allocated; +}; + +struct +alglist +{ + AlgListNode * first; + AlgListNode * last; + int len; +}; + +struct +alglistnode +{ + Alg * alg; + AlgListNode * next; +}; + +struct +block +{ + bool edge[12]; + bool corner[8]; + bool center[6]; +}; + +struct +command +{ + /* TODO: more stuff to add? maybe complete help? */ + /* Maybe add list of options */ + char * name; + char * usage; + char * description; + ArgParser parse_args; + Exec exec; +}; + +struct +commandargs +{ + bool success; + Alg * scramble; + SolveOptions * opts; + Step * step; + Command * command; /* For help */ +}; + +struct +coordinate +{ + Indexer index; + AntiIndexer cube; + Checker check; + uint64_t max; + int ntrans; + Trans * trans; +}; + +struct +cube +{ + int epose; + int eposs; + int eposm; + int eofb; + int eorl; + int eoud; + int cp; + int coud; + int cofb; + int corl; + int cpos; +}; + +struct +cubearray +{ + int * ep; + int * eofb; + int * eorl; + int * eoud; + int * cp; + int * coud; + int * corl; + int * cofb; + int * cpos; +}; + +struct +cubetarget +{ + Cube cube; + int target; +}; + +struct +dfsdata +{ + int d; + int m; + int lb; + bool niss; + Move last1; + Move last2; + AlgList * sols; + Alg * current_alg; + Move sorted_moves[NMOVES]; + int move_position[NMOVES]; +}; + +struct +piecefilter +{ + 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; + uint8_t * ptable; + bool generated; + uint64_t n; + Coordinate * coord; + Moveset moveset; +}; + +struct +solveoptions +{ + /* TODO: add option to list *all* solutions satisfying other + constraints (min/max moves and optimality) */ + int min_moves; + int max_moves; + int max_solutions; + bool optimal_only; + bool can_niss; + bool feedback; /* TODO: rename with "verbose" */ + bool all; + bool print_number; +}; + +struct +step +{ + char * shortname; + char * name; + Estimator estimate; + Checker ready; + char * ready_msg; + Validator is_valid; + Moveset moveset; + Trans pre_trans; + TransDetector detect; +}; + +struct +symdata +{ + char * filename; + bool generated; + Coordinate * coord; + Coordinate * sym_coord; + int ntrans; + Trans * trans; + uint64_t * class; + Cube * rep; + Trans * transtorep; +}; + +#endif diff --git a/old/2021-11-10-beforeremovingchecker/env.c b/old/2021-11-10-beforeremovingchecker/env.c new file mode 100644 index 0000000..d13642f --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/env.c @@ -0,0 +1,45 @@ +#include "env.h" + +bool initialized_env = false; +char *tabledir; + +void +init_env() +{ + char *nissydata = getenv("NISSYDATA"); + char *localdata = getenv("XDG_DATA_HOME"); + char *home = getenv("HOME"); + bool read, write; + + if (initialized_env) + return; + + if (nissydata != NULL) { + tabledir = malloc(strlen(nissydata) * sizeof(char) + 20); + strcpy(tabledir, nissydata); + } else if (localdata != NULL) { + tabledir = malloc(strlen(localdata) * sizeof(char) + 20); + strcpy(tabledir, localdata); + strcat(tabledir, "/nissy"); + } else if (home != NULL) { + tabledir = malloc(strlen(home) * sizeof(char) + 20); + strcpy(tabledir, home); + strcat(tabledir, "/.nissy"); + } + + mkdir(tabledir, 0777); + strcat(tabledir, "/tables"); + mkdir(tabledir, 0777); + + read = !access(tabledir, R_OK); + write = !access(tabledir, W_OK); + + if (!read) { + fprintf(stderr, "Table files cannot be read.\n"); + } else if (!write) { + fprintf(stderr, "Data directory not writable: "); + fprintf(stderr, "tables can be loaded, but not saved.\n"); + } + + initialized_env = true; +} diff --git a/old/2021-11-10-beforeremovingchecker/env.h b/old/2021-11-10-beforeremovingchecker/env.h new file mode 100644 index 0000000..871a9c1 --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/env.h @@ -0,0 +1,15 @@ +#ifndef ENV_H +#define ENV_H + +#include +#include +#include +#include +#include +#include + +extern char *tabledir; + +void init_env(); + +#endif diff --git a/old/2021-11-10-beforeremovingchecker/moves.c b/old/2021-11-10-beforeremovingchecker/moves.c new file mode 100644 index 0000000..5ba17ca --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/moves.c @@ -0,0 +1,474 @@ +#include "moves.h" + +/* Local functions ***********************************************************/ + +static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f); +static bool read_mtables_file(); +static bool write_mtables_file(); + +/* Tables and other data *****************************************************/ + +/* 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 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] = "", + + [U] = " U ", + [U2] = " UU ", + [U3] = " UUU ", + [D] = " xx U xx ", + [D2] = " xx UU xx ", + [D3] = " xx UUU xx ", + [R] = " yx U xxxyyy ", + [R2] = " yx UU xxxyyy ", + [R3] = " yx UUU xxxyyy ", + [L] = " yyyx U xxxy ", + [L2] = " yyyx UU xxxy ", + [L3] = " yyyx UUU xxxy ", + [F] = " x U xxx ", + [F2] = " x UU xxx ", + [F3] = " x UUU xxx ", + [B] = " xxx U x ", + [B2] = " xxx UU x ", + [B3] = " xxx UUU x ", + + [Uw] = " xx U xx y ", + [Uw2] = " xx UU xx yy ", + [Uw3] = " xx UUU xx yyy ", + [Dw] = " U yyy ", + [Dw2] = " UU yy ", + [Dw3] = " UUU y ", + [Rw] = " yyyx U xxxy x ", + [Rw2] = " yyyx UU xxxy xx ", + [Rw3] = " yyyx UUU xxxy xxx ", + [Lw] = " yx U xxxyyy xxx ", + [Lw2] = " yx UU xxxyyy xx ", + [Lw3] = " yx UUU xxxyyy x ", + [Fw] = " xxx U x yxxxyyy ", + [Fw2] = " xxx UU x yxxyyy ", + [Fw3] = " xxx UUU x yxyyy ", + [Bw] = " x U xxx yxyyy ", + [Bw2] = " x UU xxx yxxyyy ", + [Bw3] = " x UUU xxx yxxxyyy ", + + [M] = " yx U xx UUU yxyyy ", + [M2] = " yx UU xx UU xxxy ", + [M3] = " yx UUU xx U yxxxy ", + [S] = " x UUU xx U yyyx ", + [S2] = " x UU xx UU yyx ", + [S3] = " x U xx UUU yx ", + [E] = " U xx UUU xxyyy ", + [E2] = " UU xx UU xxyy ", + [E3] = " UUU xx U xxy ", + + [x] = " x ", + [x2] = " xx ", + [x3] = " xxx ", + [y] = " y ", + [y2] = " yy ", + [y3] = " yyy ", + [z] = " yyy x y ", + [z2] = " yy xx ", + [z3] = " y x yyy " +}; + +/* Transition tables, to be loaded up at the beginning */ +static int epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static int eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static int eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; +static int eofb_mtable[NMOVES][POW2TO11]; +static int eorl_mtable[NMOVES][POW2TO11]; +static int eoud_mtable[NMOVES][POW2TO11]; +static int cp_mtable[NMOVES][FACTORIAL8]; +static int coud_mtable[NMOVES][POW3TO7]; +static int cofb_mtable[NMOVES][POW3TO7]; +static int corl_mtable[NMOVES][POW3TO7]; +static 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 **********************************************************/ + +Cube +apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a) +{ + Cube ret = {0}; + int i; + + for (i = 0; i < alg->len; i++) + if (alg->inv[i]) + ret = a ? apply_move(alg->move[i], ret) : + apply_move_cubearray(alg->move[i], ret, f); + + ret = compose_filtered(c, inverse_cube(ret), f); + + for (i = 0; i < alg->len; i++) + if (!alg->inv[i]) + ret = a ? apply_move(alg->move[i], ret) : + apply_move_cubearray(alg->move[i], ret, f); + + return ret; +} + +Cube +apply_alg(Alg *alg, Cube cube) +{ + return apply_alg_generic(alg, cube, pf_all, true); +} + +Cube +apply_move(Move m, Cube 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] + }; +} + +void +init_moves() { + static bool initialized = false; + if (initialized) + return; + initialized = true; + + Cube c; + CubeArray arrs; + int i; + unsigned int ui; + Move m; + Alg *equiv_alg[NMOVES]; + + for (i = 0; i < NMOVES; i++) + equiv_alg[i] = new_alg(equiv_alg_string[i]); + + /* 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; + + fprintf(stderr, "Cannot load %s, generating it\n", "mtables"); + + /* Initialize transition tables */ + for (m = 0; m < NMOVES; m++) { + 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; + } + } + + if (!write_mtables_file()) + fprintf(stderr, "Error writing mtables\n"); + + for (i = 0; i < NMOVES; i++) + free_alg(equiv_alg[i]); +} + +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; +} + +bool +commute(Move m1, Move m2) +{ + static bool initialized = false; + static bool commute_aux[NMOVES][NMOVES]; + + if (!initialized) { + Cube c1, c2; + int i, j; + + for (i = 0; i < NMOVES; i++) { + for (j = 0; j < NMOVES; j++) { + c1 = apply_move(i, apply_move(j, (Cube){0})); + c2 = apply_move(j, apply_move(i, (Cube){0})); + commute_aux[i][j] = equal(c1, c2) && i && j; + } + } + + initialized = true; + } + + return commute_aux[m1][m2]; +} + +bool +possible_next(Move m1, Move m2, Move m3) +{ + static bool initialized = false; + static bool paux[NMOVES][NMOVES][NMOVES]; + + if (!initialized) { + int i, j, k; + bool p, q, c; + + for (i = 0; i < NMOVES; i++) { + for (j = 0; j < NMOVES; j++) { + for (k = 0; k < NMOVES; k++) { + p = j && base_move(j) == base_move(k); + q = i && base_move(i) == base_move(k); + c = commute(i, j); + paux[i][j][k] = !(p || (c && q)); + } + } + } + + initialized = true; + } + + return paux[m1][m2][m3]; +} diff --git a/old/2021-11-10-beforeremovingchecker/moves.h b/old/2021-11-10-beforeremovingchecker/moves.h new file mode 100644 index 0000000..082a080 --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/moves.h @@ -0,0 +1,16 @@ +#ifndef MOVES_H +#define MOVES_H + +#include "alg.h" +#include "cube.h" +#include "env.h" + +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); +bool commute(Move m1, Move m2); +bool possible_next(Move m1, Move m2, Move m3); + +void init_moves(); + +#endif diff --git a/old/2021-11-10-beforeremovingchecker/pf.c b/old/2021-11-10-beforeremovingchecker/pf.c new file mode 100644 index 0000000..34be4fd --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/pf.c @@ -0,0 +1,80 @@ +#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 +}; diff --git a/old/2021-11-10-beforeremovingchecker/pf.h b/old/2021-11-10-beforeremovingchecker/pf.h new file mode 100644 index 0000000..85ee1eb --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/pf.h @@ -0,0 +1,18 @@ +#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; + +#endif diff --git a/old/2021-11-10-beforeremovingchecker/pruning.c b/old/2021-11-10-beforeremovingchecker/pruning.c new file mode 100644 index 0000000..86363f4 --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/pruning.c @@ -0,0 +1,272 @@ +#include "pruning.h" + +static void genptable_bfs(PruneData *pd, int d, Move *ms); +static void genptable_branch(PruneData *pd, uint64_t i, int d, Move *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 +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_withcosets_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_khuge_HTM = { + .filename = "pt_khuge_HTM", + .coord = &coord_khuge, + .moveset = moveset_HTM, +}; + +void +genptable(PruneData *pd) +{ + Move ms[NMOVES]; + int d; + uint64_t j, oldn; + + if (pd->generated) + return; + + /* TODO: check if memory is enough, otherwise maybe exit gracefully? */ + pd->ptable = malloc(ptablesize(pd) * sizeof(uint8_t)); + + if (read_ptable_file(pd)) { + pd->generated = true; + return; + } + pd->generated = true; + + fprintf(stderr, "Cannot load %s, generating it\n", pd->filename); + + moveset_to_list(pd->moveset, ms); + + /* We use 4 bits per value, so any distance >= 15 is set to 15 */ + for (j = 0; j < pd->coord->max; j++) + ptable_update_index(pd, j, 15); + + for (j = 0; j < pd->coord->max; j++) + if (ptableval_index(pd, j) != 15) { + printf("Error, non-max value at index %lu!\n", j); + break; + } + printf("Table set, ready to start\n"); + + /*TODO: change, set to 0 for every solved state (might be more than 1)*/ + ptable_update(pd, (Cube){0}, 0); + pd->n = 1; + oldn = 0; + fprintf(stderr, "Depth %d done, generated %lu\t(%lu/%lu)\n", + 0, pd->n - oldn, pd->n, pd->coord->max); + oldn = 1; + for (d = 0; d < 15 && pd->n < pd->coord->max; d++) { + genptable_bfs(pd, d, ms); + fprintf(stderr, "Depth %d done, generated %lu\t(%lu/%lu)\n", + d+1, pd->n - oldn, pd->n, pd->coord->max); + oldn = pd->n; + } + + if (!write_ptable_file(pd)) + fprintf(stderr, "Error writing ptable file\n"); +} + +static void +genptable_bfs(PruneData *pd, int d, Move *ms) +{ + uint64_t i; + + for (i = 0; i < pd->coord->max; i++) + if (ptableval_index(pd, i) == d) + genptable_branch(pd, i, d, ms); +} + +static void +genptable_branch(PruneData *pd, uint64_t ind, int d, Move *ms) +{ + int i, j; + Cube ci, cc, c; + + /* + * This is the only line of the whole program where we REALLY need an + * anti-indexer function. We could get rid of it if only we could save + * a cube object for each index value as we go, but then we would need + * an incredible amount of memory to generate each ptable: assuming + * fields in struct cube are 32 bit ints that would take 88 times the + * memory of the table to be generated, more than 120Gb for + * ptable_khuge for example! + */ + ci = pd->coord->cube(ind); + + for (i = 0; i < pd->coord->ntrans; i++) { + /* For simplicity trans[] is NULL when ntrans = 1 */ + c = i == 0 ? ci : + apply_trans(pd->coord->trans[i], ci); + for (j = 0; ms[j] != NULLMOVE; j++) { + cc = apply_move(ms[j], c); + if (ptableval(pd, cc) > d+1) + ptable_update(pd, cc, d+1); + } + } +} + +void +print_ptable(PruneData *pd) +{ + uint64_t i, a[16]; + + for (i = 0; i < 16; i++) + a[i] = 0; + + if (!pd->generated) + genptable(pd); + + for (i = 0; i < pd->coord->max; i++) + a[ptableval_index(pd, i)]++; + + fprintf(stderr, "Values for table %s\n", pd->filename); + for (i = 0; i < 16; i++) + printf("%2lu\t%10lu\n", i, a[i]); +} + +uint64_t +ptablesize(PruneData *pd) +{ + return (pd->coord->max + 1) / 2; +} + +static void +ptable_update(PruneData *pd, Cube cube, int n) +{ + uint64_t ind = pd->coord->index(cube); + ptable_update_index(pd, ind, n); +} + +static void +ptable_update_index(PruneData *pd, uint64_t ind, int n) +{ + uint8_t oldval2 = pd->ptable[ind/2]; + int other = (ind % 2) ? oldval2 % 16 : oldval2 / 16; + + pd->ptable[ind/2] = (ind % 2) ? 16*n + other : 16*other + n; + pd->n++; +} + +int +ptableval(PruneData *pd, Cube cube) +{ + return ptableval_index(pd, pd->coord->index(cube)); +} + +static int +ptableval_index(PruneData *pd, uint64_t ind) +{ + if (!pd->generated) + genptable(pd); + + return (ind % 2) ? pd->ptable[ind/2] / 16 : pd->ptable[ind/2] % 16; +} + +static bool +read_ptable_file(PruneData *pd) +{ + init_env(); + + FILE *f; + char fname[strlen(tabledir)+100]; + uint64_t r; + + strcpy(fname, tabledir); + strcat(fname, "/"); + strcat(fname, pd->filename); + + if ((f = fopen(fname, "rb")) == NULL) + return false; + + r = fread(pd->ptable, sizeof(uint8_t), ptablesize(pd), f); + fclose(f); + + return r == ptablesize(pd); +} + +static bool +write_ptable_file(PruneData *pd) +{ + init_env(); + + FILE *f; + char fname[strlen(tabledir)+100]; + uint64_t written; + + strcpy(fname, tabledir); + strcat(fname, "/"); + strcat(fname, pd->filename); + + if ((f = fopen(fname, "wb")) == NULL) + return false; + + written = fwrite(pd->ptable, sizeof(uint8_t), ptablesize(pd), f); + fclose(f); + + return written == ptablesize(pd); +} + diff --git a/old/2021-11-10-beforeremovingchecker/pruning.h b/old/2021-11-10-beforeremovingchecker/pruning.h new file mode 100644 index 0000000..631ee3a --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/pruning.h @@ -0,0 +1,23 @@ +#ifndef PRUNING_H +#define PRUNING_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_khuge_HTM; + +void genptable(PruneData *pd); +void print_ptable(PruneData *pd); +uint64_t ptablesize(PruneData *pd); +int ptableval(PruneData *pd, Cube cube); + +#endif + diff --git a/old/2021-11-10-beforeremovingchecker/shell.c b/old/2021-11-10-beforeremovingchecker/shell.c new file mode 100644 index 0000000..e591faa --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/shell.c @@ -0,0 +1,99 @@ +#include "shell.h" + +static void cleanwhitespaces(char *line); +static int parseline(char *line, char **v); + +static void +cleanwhitespaces(char *line) +{ + char *i; + + for (i = line; *i != 0; i++) + if (*i == '\t' || *i == '\n') + *i = ' '; +} + +/* This function assumes that **v is large enough */ +static int +parseline(char *line, char **v) +{ + char *t; + int n = 0; + + cleanwhitespaces(line); + + for (t = strtok(line, " "); t != NULL; t = strtok(NULL, " ")) + strcpy(v[n++], t); + + return n; +} + +void +exec_args(int c, char **v) +{ + int i; + Command *cmd = NULL; + CommandArgs *args; + + for (i = 0; i < NCOMMANDS; i++) + if (commands[i] != NULL && !strcmp(v[0], commands[i]->name)) + cmd = commands[i]; + + if (cmd == NULL) { + fprintf(stderr, "%s: command not found\n", v[0]); + return; + } + + args = cmd->parse_args(c-1, &v[1]); + if (!args->success) { + fprintf(stderr, "usage: %s\n", cmd->usage); + return; + } + + cmd->exec(args); + free_args(args); +} + +void +launch() +{ + int i, shell_argc; + char line[MAXLINELEN], **shell_argv; + + shell_argv = malloc(MAXNTOKENS * sizeof(char *)); + for (i = 0; i < MAXNTOKENS; i++) + shell_argv[i] = malloc((MAXTOKENLEN+1) * sizeof(char)); + + fprintf(stderr, "Welcome to Nissy 2.0 (demo version).\n"); + fprintf(stderr, "Limited commands available. "); + fprintf(stderr, "Type 'help' for a list.\n"); + + while (true) { + fprintf(stderr, "nissy-# "); + if (fgets(line, MAXLINELEN, stdin) == NULL) + break; + shell_argc = parseline(line, shell_argv); + exec_args(shell_argc, shell_argv); + } + + for (i = 0; i < MAXNTOKENS; i++) + free(shell_argv[i]); + free(shell_argv); +} + +/* We will have our main() here, for now */ +int +main(int argc, char *argv[]) +{ + init_moves(); + init_trans(); + init_coord(); + init_symcoord(); + + if (argc > 1) + exec_args(argc-1, &argv[1]); + else + launch(); + + return 0; +} diff --git a/old/2021-11-10-beforeremovingchecker/shell.h b/old/2021-11-10-beforeremovingchecker/shell.h new file mode 100644 index 0000000..a72d136 --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/shell.h @@ -0,0 +1,13 @@ +#ifndef SHELL_H +#define SHELL_H + +#include "commands.h" + +#define MAXLINELEN 10000 +#define MAXTOKENLEN 255 +#define MAXNTOKENS 255 + +void exec_args(int c, char **v); +void launch(); + +#endif diff --git a/old/2021-11-10-beforeremovingchecker/solve.c b/old/2021-11-10-beforeremovingchecker/solve.c new file mode 100644 index 0000000..af685ec --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/solve.c @@ -0,0 +1,209 @@ +#include "solve.h" + +/* Local functions ***********************************************************/ + +static bool allowed_next(Move move, DfsData *dd); +static void dfs(Cube c, Step *s, SolveOptions *opts, DfsData *dd); +static void dfs_branch(Cube c, Step *s, SolveOptions *os, DfsData *dd); +static bool dfs_check_solved(Step *s, SolveOptions *opts, DfsData *dd); +static void dfs_niss(Cube c, Step *s, SolveOptions *opts, DfsData *dd); +static bool dfs_stop(Cube c, Step *s, SolveOptions *opts, DfsData *dd); + +/* Local functions ***********************************************************/ + +static bool +allowed_next(Move move, DfsData *dd) +{ + +/* TODO: remove the commented part, was added to moves.c + static bool initialized = false; + static bool commute[NMOVES][NMOVES], pnext[NMOVES][NMOVES][NMOVES]; + + if (!initialized) { + Cube c1, c2; + int i, j, k; + bool p1, p2, cij; + + for (i = 0; i < NMOVES; i++) { + for (j = 0; j < NMOVES; j++) { + c1 = apply_move(i, apply_move(j, (Cube){0})); + c2 = apply_move(j, apply_move(i, (Cube){0})); + commute[i][j] = equal(c1, c2) && i && j; + for (k = 0; k < NMOVES; k++) { + p1 = j && base_move(j) == base_move(k); + p2 = i && base_move(i) == base_move(k); + cij = commute[i][j]; + pnext[i][j][k] = !(p1 || (cij && p2)); + } + } + } + + initialized = true; + } + + if (!pnext[dd->last2][dd->last1][move]) + return false; + + if (commute[dd->last1][move]) + return dd->move_position[dd->last1] < dd->move_position[move]; + + return true; +*/ + + if (!possible_next(dd->last2, dd->last1, move)) + return false; + + if (commute(dd->last1, move)) + return dd->move_position[dd->last1] < dd->move_position[move]; + + return true; +} + +static void +dfs(Cube c, Step *s, SolveOptions *opts, DfsData *dd) +{ + if (dfs_stop(c, s, opts, dd)) + return; + + if (dfs_check_solved(s, opts, dd)) + return; + + dfs_branch(c, s, opts, dd); + + if (opts->can_niss && !dd->niss) + dfs_niss(c, s, opts, dd); +} + +static void +dfs_branch(Cube c, Step *s, SolveOptions *opts, DfsData *dd) +{ + Move m, l1 = dd->last1, l2 = dd->last2, *moves = dd->sorted_moves; + + int i, maxnsol = opts->max_solutions; + + for (i = 0; moves[i] != NULLMOVE && dd->sols->len < maxnsol; i++) { + m = moves[i]; + if (allowed_next(m, dd)) { + dd->last2 = dd->last1; + dd->last1 = m; + append_move(dd->current_alg, m, dd->niss); + + dfs(apply_move(m, c), s, opts, dd); + + dd->current_alg->len--; + dd->last2 = l2; + dd->last1 = l1; + } + } +} + +static bool +dfs_check_solved(Step *s, SolveOptions *opts, DfsData *dd) +{ + if (dd->lb != 0) + return false; + + if (dd->current_alg->len == dd->d) { + if (s->is_valid(dd->current_alg) || opts->all) + append_alg(dd->sols, dd->current_alg); + + if (opts->feedback) + print_alg(dd->current_alg, false); + } + + return true; +} + +static void +dfs_niss(Cube c, Step *s, SolveOptions *opts, DfsData *dd) +{ + Move l1 = dd->last1, l2 = dd->last2; + CubeTarget ct; + + ct.cube = apply_move(inverse_move(l1), (Cube){0}); + ct.target = 1; + + if (dd->current_alg->len == 0 || s->estimate(ct)) { + dd->niss = true; + dd->last1 = NULLMOVE; + dd->last2 = NULLMOVE; + + dfs(inverse_cube(c), s, opts, dd); + + dd->last1 = l1; + dd->last2 = l2; + dd->niss = false; + } +} + +static bool +dfs_stop(Cube c, Step *s, SolveOptions *opts, DfsData *dd) +{ + CubeTarget ct = { + .cube = c, + .target = dd->d - dd->current_alg->len + }; + + if (dd->sols->len >= opts->max_solutions) + return true; + + dd->lb = s->estimate(ct); + if (opts->can_niss && !dd->niss) + dd->lb = MIN(1, dd->lb); + + if (dd->current_alg->len + dd->lb > dd->d) + return true; + + return false; +} + +/* Public functions **********************************************************/ + +AlgList * +solve(Cube cube, Step *step, SolveOptions *opts) +{ + AlgListNode *node; + AlgList *sols = new_alglist(); + Cube c; + + if (step->detect != NULL) + step->pre_trans = step->detect(cube); + c = apply_trans(step->pre_trans, cube); + + DfsData dd = { + .m = 0, + .niss = false, + .lb = -1, + .last1 = NULLMOVE, + .last2 = NULLMOVE, + .sols = sols, + .current_alg = new_alg("") + }; + + if (step->ready != NULL && !step->ready(c)) { + fprintf(stderr, "Cube not ready for solving step: "); + fprintf(stderr, "%s\n", step->ready_msg); + return sols; + } + + moveset_to_list(step->moveset, dd.sorted_moves); + movelist_to_position(dd.sorted_moves, dd.move_position); + + for (dd.d = opts->min_moves; + dd.d <= opts->max_moves && + !(sols->len && opts->optimal_only) && + sols->len < opts->max_solutions; + dd.d++) { + if (opts->feedback) + fprintf(stderr, + "Found %d solutions, searching depth %d...\n", + sols->len, dd.d); + dfs(c, step, opts, &dd); + } + + for (node = sols->first; node != NULL; node = node->next) + transform_alg(inverse_trans(step->pre_trans), node->alg); + + free_alg(dd.current_alg); + return sols; +} diff --git a/old/2021-11-10-beforeremovingchecker/solve.h b/old/2021-11-10-beforeremovingchecker/solve.h new file mode 100644 index 0000000..ff84e7e --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/solve.h @@ -0,0 +1,9 @@ +#ifndef SOLVE_H +#define SOLVE_H + +#include "moves.h" +#include "trans.h" + +AlgList * solve(Cube cube, Step *step, SolveOptions *opts); + +#endif diff --git a/old/2021-11-10-beforeremovingchecker/steps.c b/old/2021-11-10-beforeremovingchecker/steps.c new file mode 100644 index 0000000..7213766 --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/steps.c @@ -0,0 +1,916 @@ +#include "steps.h" + +/* Standard checkers (return lower bound) ************************************/ + +static int estimate_eoany_HTM(CubeTarget ct); +static int estimate_eofb_HTM(CubeTarget ct); +static int estimate_coany_HTM(CubeTarget ct); +static int estimate_coud_HTM(CubeTarget ct); +static int estimate_coany_URF(CubeTarget ct); +static int estimate_coud_URF(CubeTarget ct); +static int estimate_corners_HTM(CubeTarget ct); +static int estimate_cornershtr_HTM(CubeTarget ct); +static int estimate_corners_URF(CubeTarget ct); +static int estimate_cornershtr_URF(CubeTarget ct); +static int estimate_drany_HTM(CubeTarget ct); +static int estimate_drud_HTM(CubeTarget ct); +static int estimate_drud_eofb(CubeTarget ct); +static int estimate_dr_eofb(CubeTarget ct); +static int estimate_drudfin_drud(CubeTarget ct); +static int estimate_htr_drud(CubeTarget ct); +static int estimate_htrfin_htr(CubeTarget ct); +static int estimate_optimal_HTM(CubeTarget ct); + +/* Validators ****************************************************************/ + +static bool always_valid(Alg *alg); +static bool validate_singlecw_ending(Alg *alg); + +/* Pre-transformation detectors **********************************************/ + +static Trans detect_pretrans_eofb(Cube cube); +static Trans detect_pretrans_drud(Cube cube); + +/* 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 *********************************************************************/ + +Step +optimal_HTM = { + .shortname = "optimal", + .name = "Optimal solve (in HTM)", + + .estimate = estimate_optimal_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = always_valid, + .moveset = moveset_HTM, + + .pre_trans = uf, +}; + +/* EO steps **************************/ +Step +eoany_HTM = { + .shortname = "eo", + .name = "EO on any axis", + + .estimate = estimate_eoany_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = validate_singlecw_ending, + .moveset = moveset_HTM, + + .pre_trans = uf, +}; + +Step +eofb_HTM = { + .shortname = "eofb", + .name = "EO on F/B", + + .estimate = estimate_eofb_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = validate_singlecw_ending, + .moveset = moveset_HTM, + + .pre_trans = uf, +}; + +Step +eorl_HTM = { + .shortname = "eorl", + .name = "EO on R/L", + + .estimate = estimate_eofb_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = validate_singlecw_ending, + .moveset = moveset_HTM, + + .pre_trans = ur, +}; + +Step +eoud_HTM = { + .shortname = "eoud", + .name = "EO on U/D", + + .estimate = estimate_eofb_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = validate_singlecw_ending, + .moveset = moveset_HTM, + + .pre_trans = fd, +}; + +/* CO steps **************************/ +Step +coany_HTM = { + .shortname = "co", + .name = "CO on any axis", + + .estimate = estimate_coany_HTM, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = moveset_HTM, + + .pre_trans = uf, +}; + +Step +coud_HTM = { + .shortname = "coud", + .name = "CO on U/D", + + .estimate = estimate_coud_HTM, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = moveset_HTM, + + .pre_trans = uf, +}; + +Step +corl_HTM = { + .shortname = "corl", + .name = "CO on R/L", + + .estimate = estimate_coud_HTM, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = moveset_HTM, + + .pre_trans = rf, +}; + +Step +cofb_HTM = { + .shortname = "cofb", + .name = "CO on F/B", + + .estimate = estimate_coud_HTM, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = moveset_HTM, + + .pre_trans = fd, +}; + +Step +coany_URF = { + .shortname = "co-URF", + .name = "CO any axis (URF moveset)", + + .estimate = estimate_coany_URF, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = moveset_URF, + + .pre_trans = uf, +}; + +Step +coud_URF = { + .shortname = "coud-URF", + .name = "CO on U/D (URF moveset)", + + .estimate = estimate_coud_URF, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = moveset_URF, + + .pre_trans = uf, +}; + +Step +corl_URF = { + .shortname = "corl-URF", + .name = "CO on R/L (URF moveset)", + + .estimate = estimate_coud_URF, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = moveset_URF, + + .pre_trans = rf, +}; + +Step +cofb_URF = { + .shortname = "cofb-URF", + .name = "CO on F/B (URF moveset)", + + .estimate = estimate_coud_URF, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = moveset_URF, + + .pre_trans = fd, +}; + +/* Misc corner steps *****************/ +Step +cornershtr_HTM = { + .shortname = "chtr", + .name = "Solve corners to HTR state", + + .estimate = estimate_cornershtr_HTM, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = moveset_HTM, + + .pre_trans = uf, +}; + +Step +cornershtr_URF = { + .shortname = "chtr-URF", + .name = "Solve corners to HTR state (URF moveset)", + + .estimate = estimate_cornershtr_URF, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = moveset_URF, + + .pre_trans = uf, +}; + +Step +corners_HTM = { + .shortname = "corners", + .name = "Solve corners", + + .estimate = estimate_corners_HTM, + .ready = NULL, + .is_valid = always_valid, + .moveset = moveset_HTM, + + .pre_trans = uf, +}; + +Step +corners_URF = { + .shortname = "corners-URF", + .name = "Solve corners (URF moveset)", + + .estimate = estimate_corners_URF, + .ready = NULL, + .is_valid = always_valid, + .moveset = moveset_URF, + + .pre_trans = uf, +}; + +/* DR steps **************************/ +Step +drany_HTM = { + .shortname = "dr", + .name = "DR on any axis", + + .estimate = estimate_drany_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = validate_singlecw_ending, + .moveset = moveset_HTM, + + .pre_trans = uf, +}; + +Step +drud_HTM = { + .shortname = "drud", + .name = "DR on U/D", + + .estimate = estimate_drud_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = validate_singlecw_ending, + .moveset = moveset_HTM, + + .pre_trans = uf, +}; + +Step +drrl_HTM = { + .shortname = "drrl", + .name = "DR on R/L", + + .estimate = estimate_drud_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = validate_singlecw_ending, + .moveset = moveset_HTM, + + .pre_trans = rf, +}; + +Step +drfb_HTM = { + .shortname = "drfb", + .name = "DR on F/B", + + .estimate = estimate_drud_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = validate_singlecw_ending, + .moveset = moveset_HTM, + + .pre_trans = fd, +}; + +/* DR from EO */ +Step +dr_eo = { + .shortname = "dr-eo", + .name = "DR without breaking EO (automatically detected)", + + .estimate = estimate_dr_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = moveset_eofb, + + .detect = detect_pretrans_eofb, +}; + +Step +dr_eofb = { + .shortname = "dr-eofb", + .name = "DR on U/D or R/L without breaking EO on F/B", + + .estimate = estimate_dr_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = moveset_eofb, + + .pre_trans = uf, +}; + +Step +dr_eorl = { + .shortname = "dr-eorl", + .name = "DR on U/D or F/B without breaking EO on R/L", + + .estimate = estimate_dr_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = moveset_eofb, + + .pre_trans = ur, +}; + +Step +dr_eoud = { + .shortname = "dr-eoud", + .name = "DR on R/L or F/B without breaking EO on U/R", + + .estimate = estimate_dr_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = moveset_eofb, + + .pre_trans = fd, +}; + +Step +drud_eofb = { + .shortname = "drud-eofb", + .name = "DR on U/D without breaking EO on F/B", + + .estimate = estimate_drud_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = moveset_eofb, + + .pre_trans = uf, +}; + +Step +drrl_eofb = { + .shortname = "drrl-eofb", + .name = "DR on R/L without breaking EO on F/B", + + .estimate = estimate_drud_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = moveset_eofb, + + .pre_trans = rf, +}; + +Step +drud_eorl = { + .shortname = "drud-eorl", + .name = "DR on U/D without breaking EO on R/L", + + .estimate = estimate_drud_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = moveset_eofb, + + .pre_trans = ur, +}; + +Step +drfb_eorl = { + .shortname = "drfb-eorl", + .name = "DR on F/B without breaking EO on R/L", + + .estimate = estimate_drud_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = moveset_eofb, + + .pre_trans = fr, +}; + +Step +drfb_eoud = { + .shortname = "drfb-eoud", + .name = "DR on F/B without breaking EO on U/D", + + .estimate = estimate_drud_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = moveset_eofb, + + .pre_trans = fd, +}; + +Step +drrl_eoud = { + .shortname = "drrl-eoud", + .name = "DR on R/L without breaking EO on U/D", + + .estimate = estimate_drud_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = moveset_eofb, + + .pre_trans = rd, +}; + +/* DR finish steps */ +Step +dranyfin_DR = { + .shortname = "drfin", + .name = "DR finish on any axis without breaking DR", + + .estimate = estimate_drudfin_drud, + .ready = check_drud, + .ready_msg = check_drany_msg, + .is_valid = always_valid, + .moveset = moveset_drud, + + .detect = detect_pretrans_drud, +}; + +Step +drudfin_drud = { + .shortname = "drudfin", + .name = "DR finish on U/D without breaking DR", + + .estimate = estimate_drudfin_drud, + .ready = check_drud, + .ready_msg = check_dr_msg, + .is_valid = always_valid, + .moveset = moveset_drud, + + .pre_trans = uf, +}; + +Step +drrlfin_drrl = { + .shortname = "drrlfin", + .name = "DR finish on R/L without breaking DR", + + .estimate = estimate_drudfin_drud, + .ready = check_drud, + .ready_msg = check_dr_msg, + .is_valid = always_valid, + .moveset = moveset_drud, + + .pre_trans = rf, +}; + +Step +drfbfin_drfb = { + .shortname = "drfbfin", + .name = "DR finish on F/B without breaking DR", + + .estimate = estimate_drudfin_drud, + .ready = check_drud, + .ready_msg = check_dr_msg, + .is_valid = always_valid, + .moveset = moveset_drud, + + .pre_trans = fd, +}; + +/* HTR from DR */ +Step +htr_any = { + .shortname = "htr", + .name = "HTR from DR", + + .estimate = estimate_htr_drud, + .ready = check_drud, + .ready_msg = check_drany_msg, + .is_valid = validate_singlecw_ending, + .moveset = moveset_drud, + + .detect = detect_pretrans_drud, +}; + +Step +htr_drud = { + .shortname = "htr-drud", + .name = "HTR from DR on U/D", + + .estimate = estimate_htr_drud, + .ready = check_drud, + .ready_msg = check_dr_msg, + .is_valid = validate_singlecw_ending, + .moveset = moveset_drud, + + .pre_trans = uf, +}; + +Step +htr_drrl = { + .shortname = "htr-drrl", + .name = "HTR from DR on R/L", + + .estimate = estimate_htr_drud, + .ready = check_drud, + .ready_msg = check_dr_msg, + .is_valid = validate_singlecw_ending, + .moveset = moveset_drud, + + .pre_trans = rf, +}; + +Step +htr_drfb = { + .shortname = "htr-drfb", + .name = "HTR from DR on F/B", + + .estimate = estimate_htr_drud, + .ready = check_drud, + .ready_msg = check_dr_msg, + .is_valid = validate_singlecw_ending, + .moveset = moveset_drud, + + .pre_trans = fd, +}; + +/* HTR finish */ +Step +htrfin_htr = { + .shortname = "htrfin", + .name = "HTR finish without breaking HTR", + + .estimate = estimate_htrfin_htr, + .ready = check_htr, + .ready_msg = check_htr_msg, + .is_valid = always_valid, + .moveset = moveset_htr, + + .pre_trans = uf, +}; + +Step *steps[NSTEPS] = { + &optimal_HTM, /* first is default */ + + &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, +}; + +/* Standard checkers (return lower bound) ************************************/ + +static int +estimate_eoany_HTM(CubeTarget ct) +{ + int r1, r2, r3; + + r1 = ptableval(&pd_eofb_HTM, ct.cube); + r2 = ptableval(&pd_eofb_HTM, apply_trans(ur, ct.cube)); + r3 = ptableval(&pd_eofb_HTM, apply_trans(fd, ct.cube)); + + return MIN(r1, MIN(r2, r3)); +} + +static int +estimate_eofb_HTM(CubeTarget ct) +{ + return ptableval(&pd_eofb_HTM, ct.cube); +} + +static int +estimate_coany_HTM(CubeTarget ct) +{ + int r1, r2, r3; + + r1 = ptableval(&pd_coud_HTM, ct.cube); + r2 = ptableval(&pd_coud_HTM, apply_trans(rf, ct.cube)); + r3 = ptableval(&pd_coud_HTM, apply_trans(fd, ct.cube)); + + return MIN(r1, MIN(r2, r3)); +} + +static int +estimate_coud_HTM(CubeTarget ct) +{ + return ptableval(&pd_coud_HTM, ct.cube); +} + +static int +estimate_coany_URF(CubeTarget ct) +{ + int r1, r2, r3; + CubeTarget ct2, ct3; + + ct2.cube = apply_trans(rf, ct.cube); + ct2.target = ct.target; + + ct3.cube = apply_trans(fd, ct.cube); + ct3.target = ct.target; + + r1 = estimate_coud_URF(ct); + r2 = estimate_coud_URF(ct2); + r3 = estimate_coud_URF(ct3); + + return MIN(r1, MIN(r2, r3)); +} + +static int +estimate_coud_URF(CubeTarget ct) +{ + /* TODO: I can improve this by checking first the orientation of + * the corner in DBL and use that as a reference */ + + CubeTarget ct2 = {.cube = apply_move(z, ct.cube), .target = ct.target}; + CubeTarget ct3 = {.cube = apply_move(x, ct.cube), .target = ct.target}; + + int ud = estimate_coud_HTM(ct); + int rl = estimate_coud_HTM(ct2); + int fb = estimate_coud_HTM(ct3); + + return MIN(ud, MIN(rl, fb)); +} + +static int +estimate_corners_HTM(CubeTarget ct) +{ + return ptableval(&pd_corners_HTM, ct.cube); +} + +static int +estimate_cornershtr_HTM(CubeTarget ct) +{ + return ptableval(&pd_cornershtr_HTM, ct.cube); +} + +static int +estimate_cornershtr_URF(CubeTarget ct) +{ + /* TODO: I can improve this by checking first the corner in DBL + * and use that as a reference */ + + int c, ret = 15; + Trans i; + + for (i = 0; i < NROTATIONS; i++) { + ct.cube = apply_alg(rotation_alg(i), ct.cube); + c = estimate_cornershtr_HTM(ct); + ret = MIN(ret, c); + } + + return ret; +} + +static int +estimate_corners_URF(CubeTarget ct) +{ + /* TODO: I can improve this by checking first the corner in DBL + * and use that as a reference */ + + int c, ret = 15; + Trans i; + + for (i = 0; i < NROTATIONS; i++) { + ct.cube = apply_alg(rotation_alg(i), ct.cube); + c = estimate_corners_HTM(ct); + ret = MIN(ret, c); + } + + return ret; +} + +static int +estimate_drany_HTM(CubeTarget ct) +{ + int r1, r2, r3; + + r1 = ptableval(&pd_drud_sym16_HTM, ct.cube); + r2 = ptableval(&pd_drud_sym16_HTM, apply_trans(rf, ct.cube)); + r3 = ptableval(&pd_drud_sym16_HTM, apply_trans(fd, ct.cube)); + + return MIN(r1, MIN(r2, r3)); +} + +static int +estimate_drud_HTM(CubeTarget ct) +{ + return ptableval(&pd_drud_sym16_HTM, ct.cube); +} + +static int +estimate_drud_eofb(CubeTarget ct) +{ + return ptableval(&pd_drud_eofb, ct.cube); +} + +static int +estimate_dr_eofb(CubeTarget ct) +{ + int r1, r2; + + r1 = ptableval(&pd_drud_eofb, ct.cube); + r2 = ptableval(&pd_drud_eofb, apply_trans(rf, ct.cube)); + + return MIN(r1, r2); +} + +static int +estimate_drudfin_drud(CubeTarget ct) +{ + int val = ptableval(&pd_drudfin_noE_sym16_drud, ct.cube); + + if (val != 0) + return val; + + return ct.cube.epose % 24 == 0 ? 0 : 1; +} + +static int +estimate_htr_drud(CubeTarget ct) +{ + return ptableval(&pd_htr_drud, ct.cube); +} + +static int +estimate_htrfin_htr(CubeTarget ct) +{ + return ptableval(&pd_htrfin_htr, ct.cube); +} + +static int +estimate_optimal_HTM(CubeTarget ct) +{ + int dr1, dr2, dr3, cor, ret; + Cube cube = ct.cube; + + dr1 = ptableval(&pd_khuge_HTM, cube); + cor = estimate_corners_HTM(ct); + ret = MAX(dr1, cor); + + if (ret > ct.target) + return ret; + + cube = apply_trans(rf, ct.cube); + dr2 = ptableval(&pd_khuge_HTM, cube); + ret = MAX(ret, dr2); + + if (ret > ct.target) + return ret; + + cube = apply_trans(fd, ct.cube); + dr3 = ptableval(&pd_khuge_HTM, cube); + + /* Michiel de Bondt's trick */ + if (dr1 == dr2 && dr2 == dr3 && dr1 != 0) + dr3++; + + return MAX(ret, dr3); +} + +/* Validators ****************************************************************/ + +static bool +always_valid(Alg *alg) +{ + return true; +} + +static bool +validate_singlecw_ending(Alg *alg) +{ + int i; + bool nor, inv; + Move l2 = NULLMOVE, l1 = NULLMOVE, l2i = NULLMOVE, l1i = NULLMOVE; + + for (i = 0; i < alg->len; i++) { + if (alg->inv[i]) { + l2i = l1i; + l1i = alg->move[i]; + } else { + l2 = l1; + l1 = alg->move[i]; + } + } + + nor = l1 ==base_move(l1) && (!commute(l1, l2) ||l2 ==base_move(l2)); + inv = l1i==base_move(l1i) && (!commute(l1i,l2i)||l2i==base_move(l2i)); + + return nor && inv; +} + +/* Pre-transformation detectors **********************************************/ + +static Trans +detect_pretrans_eofb(Cube cube) +{ + Trans i; + + for (i = 0; i < NROTATIONS; i++) + if (check_eofb(apply_trans(i, cube))) + return i; + + return 0; +} + +static Trans +detect_pretrans_drud(Cube cube) +{ + Trans i; + + for (i = 0; i < NROTATIONS; i++) + if (check_drud(apply_trans(i, cube))) + return i; + + return 0; +} diff --git a/old/2021-11-10-beforeremovingchecker/steps.h b/old/2021-11-10-beforeremovingchecker/steps.h new file mode 100644 index 0000000..aa3178c --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/steps.h @@ -0,0 +1,10 @@ +#ifndef STEPS_H +#define STEPS_H + +#include "pruning.h" + +#define NSTEPS 50 + +extern Step * steps[NSTEPS]; + +#endif diff --git a/old/2021-11-10-beforeremovingchecker/symcoord.c b/old/2021-11-10-beforeremovingchecker/symcoord.c new file mode 100644 index 0000000..9a4d49a --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/symcoord.c @@ -0,0 +1,359 @@ +#include "symcoord.h" + +static Cube antindex_coud_sym16(uint64_t ind); +static Cube antindex_cp_sym16(uint64_t ind); +static Cube antindex_eofbepos_sym16(uint64_t ind); +static Cube antindex_drud_sym16(uint64_t ind); +static Cube antindex_drudfin_noE_sym16(uint64_t ind); +static Cube antindex_khuge(uint64_t ind); + +static uint64_t index_coud_sym16(Cube cube); +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_khuge(Cube cube); + +static void gensym(SymData *sd); +static bool read_symdata_file(SymData *sd); +static bool write_symdata_file(SymData *sd); + +/* 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_coud_16 = { + .filename = "sd_coud_16", + .coord = &coord_coud, + .sym_coord = &coord_coud_sym16, + .ntrans = 16, + .trans = trans_group_udfix +}; + +static SymData +sd_cp_16 = { + .filename = "sd_cp_16", + .coord = &coord_cp, + .sym_coord = &coord_cp_sym16, + .ntrans = 16, + .trans = trans_group_udfix +}; + +static SymData +sd_eofbepos_16 = { + .filename = "sd_eofbepos_16", + .coord = &coord_eofbepos, + .sym_coord = &coord_eofbepos_sym16, + .ntrans = 16, + .trans = trans_group_udfix +}; + +static int nsymdata = 3; +static SymData * all_sd[] = { + &sd_coud_16, + &sd_cp_16, + &sd_eofbepos_16, +}; + + +/* Coordinates and their implementation **************************************/ + +Coordinate +coord_eofbepos_sym16 = { + .index = index_eofbepos_sym16, + .cube = antindex_eofbepos_sym16, + .check = check_eofbepos, + .ntrans = 16, + .trans = trans_group_udfix, +}; + +Coordinate +coord_coud_sym16 = { + .index = index_coud_sym16, + .cube = antindex_coud_sym16, + .check = check_coud, + .ntrans = 16, + .trans = trans_group_udfix, +}; + +Coordinate +coord_cp_sym16 = { + .index = index_cp_sym16, + .cube = antindex_cp_sym16, + .check = check_cp, + .ntrans = 16, + .trans = trans_group_udfix, +}; + +Coordinate +coord_drud_sym16 = { + .index = index_drud_sym16, + .cube = antindex_drud_sym16, + .check = check_drud, + .max = POW3TO7 * 64430, + .ntrans = 16, + .trans = trans_group_udfix, +}; + +Coordinate +coord_drudfin_noE_sym16 = { + .index = index_drudfin_noE_sym16, + .cube = antindex_drudfin_noE_sym16, + .check = check_drudfin_noE, + .max = FACTORIAL8 * 2768, + .ntrans = 16, + .trans = trans_group_udfix, +}; + +Coordinate +coord_khuge = { + .index = index_khuge, + .cube = antindex_khuge, + .check = check_khuge, + .max = POW3TO7 * FACTORIAL4 * 64430, + .ntrans = 16, + .trans = trans_group_udfix, +}; + +/* Functions *****************************************************************/ + +static Cube +antindex_coud_sym16(uint64_t ind) +{ + return sd_coud_16.rep[ind]; +} + +static Cube +antindex_cp_sym16(uint64_t ind) +{ + return sd_cp_16.rep[ind]; +} + +static Cube +antindex_eofbepos_sym16(uint64_t ind) +{ + return sd_eofbepos_16.rep[ind]; +} + +static Cube +antindex_drud_sym16(uint64_t ind) +{ + Cube c; + + c = antindex_eofbepos_sym16(ind/POW3TO7); + c.coud = ind % POW3TO7; + c.cofb = c.coud; + c.corl = c.coud; + + return c; +} + +static Cube +antindex_drudfin_noE_sym16(uint64_t ind) +{ + Cube c1, c2; + + c1 = coord_epud.cube(ind % FACTORIAL8); + c2 = antindex_cp_sym16(ind/FACTORIAL8); + c1.cp = c2.cp; + + return c1; +} + +static Cube +antindex_khuge(uint64_t ind) +{ + Cube c; + + c = antindex_eofbepos_sym16(ind/(FACTORIAL4*POW3TO7)); + c.epose = ((c.epose / 24) * 24) + ((ind/POW3TO7) % 24); + c.coud = ind % POW3TO7; + + return c; +} + +static uint64_t +index_coud_sym16(Cube cube) +{ + return sd_coud_16.class[coord_coud.index(cube)]; +} + +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; + Cube c; + + t = sd_eofbepos_16.transtorep[coord_eofbepos.index(cube)]; + c = apply_trans(t, cube); + + return index_eofbepos_sym16(c) * POW3TO7 + c.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); + + 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_khuge(Cube cube) +{ + Trans t; + Cube c; + uint64_t a; + + t = sd_eofbepos_16.transtorep[coord_eofbepos.index(cube)]; + c = apply_trans(t, cube); + a = (index_eofbepos_sym16(c) * 24) + (c.epose % 24); + + return a * POW3TO7 + c.coud; +} + +/* Other functions ***********************************************************/ + +static void +gensym(SymData *sd) +{ + uint64_t i, in, nreps = 0; + int j; + Cube c, d; + + if (sd->generated) + return; + + sd->class = malloc(sd->coord->max * sizeof(uint64_t)); + sd->rep = malloc(sd->coord->max * sizeof(Cube)); + sd->transtorep = malloc(sd->coord->max * sizeof(Trans)); + + 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) { + c = sd->coord->cube(i); + sd->rep[nreps] = c; + for (j = 0; j < sd->ntrans; j++) { + d = apply_trans(sd->trans[j], c); + in = sd->coord->index(d); + + if (sd->class[in] == sd->coord->max + 1) { + sd->class[in] = nreps; + sd->transtorep[in] = + inverse_trans(sd->trans[j]); + } + } + nreps++; + } + } + + sd->sym_coord->max = nreps; + sd->rep = realloc(sd->rep, nreps * sizeof(Cube)); + sd->generated = true; + + fprintf(stderr, "Found %lu 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->rep, sizeof(Cube), *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 +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->rep, sizeof(Cube), *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; +} + +void +init_symcoord() +{ + int i; + + static bool initialized = false; + if (initialized) + return; + initialized = true; + + for (i = 0; i < nsymdata; i++) + gensym(all_sd[i]); +} + diff --git a/old/2021-11-10-beforeremovingchecker/symcoord.h b/old/2021-11-10-beforeremovingchecker/symcoord.h new file mode 100644 index 0000000..f231c92 --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/symcoord.h @@ -0,0 +1,15 @@ +#ifndef SYMCOORD_H +#define SYMCOORD_H + +#include "coord.h" + +extern Coordinate coord_coud_sym16; +extern Coordinate coord_cp_sym16; +extern Coordinate coord_eofbepos_sym16; +extern Coordinate coord_drud_sym16; +extern Coordinate coord_drudfin_noE_sym16; +extern Coordinate coord_khuge; + +void init_symcoord(); + +#endif diff --git a/old/2021-11-10-beforeremovingchecker/trans.c b/old/2021-11-10-beforeremovingchecker/trans.c new file mode 100644 index 0000000..ff3cdbb --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/trans.c @@ -0,0 +1,372 @@ +#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 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 +}; + +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 +}; + +/* TODO Is there a more elegant way? */ +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", + [lf] = "z", [ld] = "z y3", [lb] = "z y2", [lu] = "z y", + [fu] = "x y2", [fr] = "x y", [fd] = "x", [fl] = "x y3", + [bu] = "x3", [br] = "x3 y", [bd] = "x3 y2", [bl] = "x3 y3", +}; + +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]; + +static int epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static int eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static int eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; +static int eo_ttable[NTRANS][POW2TO11]; +static int cp_ttable[NTRANS][FACTORIAL8]; +static int co_ttable[NTRANS][POW3TO7]; +static int cpos_ttable[NTRANS][FACTORIAL6]; +static Move moves_ttable[NTRANS][NMOVES]; + +/* Local functions implementation ********************************************/ + +void +init_trans() { + static bool initialized = false; + if (initialized) + return; + initialized = true; + + Cube aux, cube, c[3]; + CubeArray epcp; + int i, eparr[12], eoarr[12], cparr[8], coarr[8]; + unsigned int ui; + Move mi, move; + Trans m; + + /* 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; + } + + if (read_ttables_file()) + return; + + fprintf(stderr, "Cannot load %s, generating it\n", "ttables"); + + /* 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++) { + /* Old version: + * + aux = apply_trans(m, apply_move(mi, (Cube){0})); + for (move = 0; move < NMOVES; move++) { + 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; + } + */ + + 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; + } + } + } + } + + if (!write_ttables_file()) + fprintf(stderr, "Error writing ttables\n"); +} + +static bool +read_ttables_file() +{ + init_env(); + + FILE *f; + char fname[strlen(tabledir)+20]; + int b = sizeof(int); + bool r = true; + 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, "/"); + 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) +{ + /* TODO is there a more elegant way? */ + static Trans inverse_trans_aux[NTRANS] = { + [uf] = uf, [ur] = ul, [ul] = ur, [ub] = ub, + [df] = df, [dr] = dr, [dl] = dl, [db] = db, + [rf] = lf, [rd] = bl, [rb] = rb, [ru] = fr, + [lf] = rf, [ld] = br, [lb] = lb, [lu] = fl, + [fu] = fu, [fr] = ru, [fd] = bu, [fl] = lu, + [bu] = fd, [br] = ld, [bd] = bd, [bl] = rd, + + [uf_mirror] = uf_mirror, [ur_mirror] = ur_mirror, + [ul_mirror] = ul_mirror, [ub_mirror] = ub_mirror, + [df_mirror] = df_mirror, [dr_mirror] = dl_mirror, + [dl_mirror] = dr_mirror, [db_mirror] = db_mirror, + [rf_mirror] = rf_mirror, [rd_mirror] = br_mirror, + [rb_mirror] = lb_mirror, [ru_mirror] = fl_mirror, + [lf_mirror] = lf_mirror, [ld_mirror] = bl_mirror, + [lb_mirror] = rb_mirror, [lu_mirror] = fr_mirror, + [fu_mirror] = fu_mirror, [fr_mirror] = lu_mirror, + [fd_mirror] = bu_mirror, [fl_mirror] = ru_mirror, + [bu_mirror] = fd_mirror, [br_mirror] = rd_mirror, + [bd_mirror] = bd_mirror, [bl_mirror] = ld_mirror + }; + + return inverse_trans_aux[t]; +} + +Alg * +rotation_alg(Trans t) +{ + 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 +transform_alg(Trans t, Alg *alg) +{ + int i; + + /*init_trans();*/ + + for (i = 0; i < alg->len; i++) + alg->move[i] = moves_ttable[t][alg->move[i]]; +} diff --git a/old/2021-11-10-beforeremovingchecker/trans.h b/old/2021-11-10-beforeremovingchecker/trans.h new file mode 100644 index 0000000..2eda568 --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/trans.h @@ -0,0 +1,13 @@ +#ifndef TRANS_H +#define TRANS_H + +#include "moves.h" + +Cube apply_trans(Trans t, Cube cube); +Trans inverse_trans(Trans t); +Alg * rotation_alg(Trans i); +void transform_alg(Trans i, Alg *alg); + +void init_trans(); + +#endif diff --git a/old/2021-11-10-beforeremovingchecker/utils.c b/old/2021-11-10-beforeremovingchecker/utils.c new file mode 100644 index 0000000..f72a00e --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/utils.c @@ -0,0 +1,274 @@ +#include "utils.h" + +void +apply_permutation(int *perm, int *set, int n) +{ + int *aux = malloc(n * sizeof(int)); + int i; + + if (!is_perm(perm, n)) + return; + + for (i = 0; i < n; i++) + aux[i] = set[perm[i]]; + + memcpy(set, aux, n * sizeof(int)); + free(aux); +} + +int +binomial(int n, int k) +{ + if (n < 0 || k < 0 || k > n) + return 0; + + return factorial(n) / (factorial(k) * factorial(n-k)); +} + +int +digit_array_to_int(int *a, int n, int b) +{ + int i, ret = 0, p = 1; + + for (i = 0; i < n; i++, p *= b) + ret += a[i] * p; + + return ret; +} + +int +factorial(int n) +{ + int i, ret = 1; + + if (n < 0) + return 0; + + for (i = 1; i <= n; i++) + ret *= i; + + return ret; +} + +void +index_to_perm(int p, int n, int *r) +{ + int *a = malloc(n * sizeof(int)); + int i, j, c; + + for (i = 0; i < n; i++) + a[i] = 0; + + if (p < 0 || p >= factorial(n)) + for (i = 0; i < n; i++) + r[i] = -1; + + for (i = 0; i < n; i++) { + c = 0; + j = 0; + while (c <= p / factorial(n-i-1)) + c += a[j++] ? 0 : 1; + r[i] = j-1; + a[j-1] = 1; + p %= factorial(n-i-1); + } + + free(a); +} + +void +index_to_subset(int s, int n, int k, int *r) +{ + int i, j, v; + + if (s < 0 || s >= binomial(n, k)) { + for (i = 0; i < n; i++) + r[i] = -1; + return; + } + + for (i = 0; i < n; i++) { + if (k == n-i) { + for (j = i; j < n; j++) + r[j] = 1; + return; + } + + if (k == 0) { + for (j = i; j < n; j++) + r[j] = 0; + return; + } + + v = binomial(n-i-1, k); + if (s >= v) { + r[i] = 1; + k--; + s -= v; + } else { + r[i] = 0; + } + } +} + +void +int_to_digit_array(int a, int b, int n, int *r) +{ + int i; + + if (b <= 1) + for (i = 0; i < n; i++) + r[i] = 0; + else + for (i = 0; i < n; i++, a /= b) + r[i] = a % b; +} + +void +int_to_sum_zero_array(int x, int b, int n, int *a) +{ + int i, s = 0; + + if (b <= 1) { + for (i = 0; i < n; i++) + a[i] = 0; + } else { + int_to_digit_array(x, b, n-1, a); + for (i = 0; i < n - 1; i++) + s = (s + a[i]) % b; + a[n-1] = (b - s) % b; + } +} + +int +invert_digits(int a, int b, int n) +{ + int i, ret, *r = malloc(n * sizeof(int)); + + int_to_digit_array(a, b, n, r); + for (i = 0; i < n; i++) + r[i] = (b-r[i]) % b; + + ret = digit_array_to_int(r, n, b); + free(r); + return ret; +} + +bool +is_perm(int *a, int n) +{ + int *aux = malloc(n * sizeof(int)); + int i; + + for (i = 0; i < n; i++) + if (a[i] < 0 || a[i] >= n) + return false; + else + aux[a[i]] = 1; + + for (i = 0; i < n; i++) + if (!aux[i]) + return false; + + free(aux); + + return true; +} + +bool +is_subset(int *a, int n, int k) +{ + int i, sum = 0; + + for (i = 0; i < n; i++) + sum += a[i] ? 1 : 0; + + return sum == k; +} + +int +perm_sign(int *a, int n) +{ + int i, j, ret = 0; + + if (!is_perm(a,n)) + return -1; + + for (i = 0; i < n; i++) + for (j = i+1; j < n; j++) + ret += (a[i] > a[j]) ? 1 : 0; + + return ret % 2; +} + +int +perm_to_index(int *a, int n) +{ + int i, j, c, ret = 0; + + if (!is_perm(a, n)) + return -1; + + for (i = 0; i < n; i++) { + c = 0; + for (j = i+1; j < n; j++) + c += (a[i] > a[j]) ? 1 : 0; + ret += factorial(n-i-1) * c; + } + + return ret; +} + +int +powint(int a, int b) +{ + if (b < 0) + return 0; + if (b == 0) + return 1; + + if (b % 2) + return a * powint(a, b-1); + else + return powint(a*a, b/2); +} + +int +subset_to_index(int *a, int n, int k) +{ + int i, ret = 0; + + if (!is_subset(a, n, k)) + return binomial(n, k); + + for (i = 0; i < n; i++) { + if (k == n-i) + return ret; + if (a[i]) { + ret += binomial(n-i-1, k); + k--; + } + } + + return ret; +} + +void +sum_arrays_mod(int *src, int *dst, int n, int m) +{ + int i; + + for (i = 0; i < n; i++) + dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m; +} + +void +swap(int *a, int *b) +{ + int aux; + + aux = *a; + *a = *b; + *b = aux; +} + diff --git a/old/2021-11-10-beforeremovingchecker/utils.h b/old/2021-11-10-beforeremovingchecker/utils.h new file mode 100644 index 0000000..80c33ae --- /dev/null +++ b/old/2021-11-10-beforeremovingchecker/utils.h @@ -0,0 +1,41 @@ +#ifndef UTILS_H +#define UTILS_H + +#include +#include +#include + +#define POW2TO6 64ULL +#define POW2TO11 2048ULL +#define POW2TO12 4096ULL +#define POW3TO7 2187ULL +#define POW3TO8 6561ULL +#define FACTORIAL4 24ULL +#define FACTORIAL6 720ULL +#define FACTORIAL7 5040ULL +#define FACTORIAL8 40320ULL +#define FACTORIAL12 479001600ULL +#define BINOM12ON4 495ULL +#define BINOM8ON4 70ULL +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +void apply_permutation(int *perm, int *set, int n); +int binomial(int n, int k); +int digit_array_to_int(int *a, int n, int b); +int factorial(int n); +void index_to_perm(int p, int n, int *r); +void index_to_subset(int s, int n, int k, int *r); +void int_to_digit_array(int a, int b, int n, int *r); +void int_to_sum_zero_array(int x, int b, int n, int *a); +int invert_digits(int a, int b, int n); +bool is_perm(int *a, int n); +bool is_subset(int *a, int n, int k); +int perm_sign(int *a, int n); +int perm_to_index(int *a, int n); +int powint(int a, int b); +int subset_to_index(int *a, int n, int k); +void sum_arrays_mod(int *src, int *dst, int n, int m); +void swap(int *a, int *b); + +#endif diff --git a/old/backup-manysteps-pretrans/steps.c b/old/backup-manysteps-pretrans/steps.c new file mode 100644 index 0000000..e4d79cd --- /dev/null +++ b/old/backup-manysteps-pretrans/steps.c @@ -0,0 +1,369 @@ +#include "steps.h" + +/* Check functions ***********************************************************/ + +static int check_nothing(Cube cube); +static int check_eofb_HTM(Cube cube); +static int check_coud_HTM(Cube cube); +static int check_coud_URF(Cube cube); +static int check_corners_HTM(Cube cube); +static int check_corners_URF(Cube cube); +static int check_edges_HTM(Cube cube); +static int check_drud_HTM(Cube cube); +static int check_optimal_HTM(Cube cube); + + +/* Index functions ***********************************************************/ + +static uint64_t index_eofb(Cube cube); +static uint64_t index_coud(Cube cube); +static uint64_t index_corners(Cube cube); +static uint64_t index_ep(Cube cube); +static uint64_t index_drud(Cube cube); + + +/* Steps *********************************************************************/ + +Step +eofb_HTM = { + .check = check_eofb_HTM, + .ready = check_nothing, + .pre_trans = uf, + .moveset = moveset_HTM +}; + +Step +eorl_HTM = { + .check = check_eofb_HTM, + .ready = check_nothing, + .pre_trans = ur, + .moveset = moveset_HTM +}; + +Step +eoud_HTM = { + .check = check_eofb_HTM, + .ready = check_nothing, + .pre_trans = bu, + .moveset = moveset_HTM +}; + +Step +coud_HTM = { + .check = check_coud_HTM, + .ready = check_nothing, + .pre_trans = uf, + .moveset = moveset_HTM +}; + +Step +corl_HTM = { + .check = check_coud_HTM, + .ready = check_nothing, + .pre_trans = rf, + .moveset = moveset_HTM +}; + +Step +cofb_HTM = { + .check = check_coud_HTM, + .ready = check_nothing, + .pre_trans = fd, + .moveset = moveset_HTM +}; + +Step +coud_URF = { + .check = check_coud_URF, + .ready = check_nothing, + .pre_trans = uf, + .moveset = moveset_URF +}; + +Step +corl_URF = { + .check = check_coud_URF, + .ready = check_nothing, + .pre_trans = rf, + .moveset = moveset_URF +}; + +Step +cofb_URF = { + .check = check_coud_URF, + .ready = check_nothing, + .pre_trans = fd, + .moveset = moveset_URF +}; + +Step +corners_HTM = { + .check = check_corners_HTM, + .ready = check_nothing, + .pre_trans = uf, + .moveset = moveset_HTM +}; + +Step +corners_URF = { + .check = check_corners_URF, + .ready = check_nothing, + .pre_trans = uf, + .moveset = moveset_URF +}; + +Step +edges_HTM = { + .check = check_edges_HTM, + .ready = check_nothing, + .pre_trans = uf, + .moveset = moveset_HTM +}; + +Step +drud_HTM = { + .check = check_drud_HTM, + .ready = check_nothing, + .pre_trans = uf, + .moveset = moveset_HTM +}; + +Step +optimal_HTM = { + .check = check_optimal_HTM, + .ready = check_nothing, + .pre_trans = uf, + .moveset = moveset_HTM +}; + + +/* Pruning tables ************************************************************/ + +PruneData +pd_eofb_HTM = { + .filename = "ptable_eofb_HTM", + .size = POW2TO11, + .index = index_eofb, + .moveset = moveset_HTM +}; + +PruneData +pd_coud_HTM = { + .filename = "ptable_coud_HTM", + .size = POW3TO7, + .index = index_coud, + .moveset = moveset_HTM +}; + +PruneData +pd_corners_HTM = { + .filename = "ptable_corners_HTM", + .size = POW3TO7 * FACTORIAL8, + .index = index_corners, + .moveset = moveset_HTM +}; + +PruneData +pd_ep_HTM = { + .filename = "ptable_ep_HTM", + .size = FACTORIAL12, + .index = index_ep, + .moveset = moveset_HTM +}; + +PruneData +pd_drud_HTM = { + .filename = "ptable_drud_HTM", + .size = POW2TO11 * POW3TO7 * BINOM12ON4, + .index = index_drud, + .moveset = moveset_HTM +}; + + +/* Check functions implementation ********************************************/ + +static int +check_nothing(Cube cube) +{ + /* At least we check that it is admissible */ + return is_admissible(cube); +} + +static int +check_eofb_HTM(Cube cube) +{ + if (!pd_eofb_HTM.generated) + generate_ptable(&pd_eofb_HTM); + + return PTABLEVAL(pd_eofb_HTM.ptable, cube.eofb); +} + +static int +check_coud_HTM(Cube cube) +{ + if (!pd_coud_HTM.generated) + generate_ptable(&pd_coud_HTM); + + return PTABLEVAL(pd_coud_HTM.ptable, cube.coud); +} + +static int +check_coud_URF(Cube cube) +{ + /* TODO: I can improve this by checking first the orientation of + * the corner in DBL and use that as a reference */ + + int ud = check_coud_HTM(cube); + int rl = check_coud_HTM(apply_move(z, cube)); + int fb = check_coud_HTM(apply_move(x, cube)); + + return MIN(ud, MIN(rl, fb)); +} + +static int +check_corners_HTM(Cube cube) +{ + if (!pd_corners_HTM.generated) + generate_ptable(&pd_corners_HTM); + + return PTABLEVAL(pd_corners_HTM.ptable, index_corners(cube)); +} + +static int +check_corners_URF(Cube cube) +{ + /* TODO: I can improve this by checking first the corner in DBL + * and use that as a reference */ + + int ret = 15; + Trans i; + + for (i = 0; i < NROTATIONS; i++) + ret = MIN(ret,check_corners_HTM(apply_alg(trans_alg(i),cube))); + + return ret; +} + +static int +check_edges_HTM(Cube cube) +{ + int ret = 0; + + if (!pd_ep_HTM.generated) + generate_ptable(&pd_ep_HTM); + + ret = MAX(ret, PTABLEVAL(pd_ep_HTM.ptable, index_ep(cube))); + ret = MAX(ret, check_eofb_HTM(cube)); + ret = MAX(ret, check_eofb_HTM(apply_trans(ur, cube))); + ret = MAX(ret, check_eofb_HTM(apply_trans(fd, cube))); + + return ret; +} + +static int +check_drud_HTM(Cube cube) +{ + if (!pd_drud_HTM.generated) + generate_ptable(&pd_drud_HTM); + + return PTABLEVAL(pd_drud_HTM.ptable, index_drud(cube)); +} + +static int +check_optimal_HTM(Cube cube) +{ + int dr1, dr2, dr3, drmax, cor; /*ep;*/ + + if (!pd_drud_HTM.generated) + generate_ptable(&pd_drud_HTM); + if (!pd_corners_HTM.generated) + generate_ptable(&pd_corners_HTM); + /* + *if (!pd_ep_HTM.generated) + * generate_ptable(&pd_ep_HTM); + */ + + dr1 = PTABLEVAL(pd_drud_HTM.ptable, index_drud(cube)); + dr2 = PTABLEVAL(pd_drud_HTM.ptable, index_drud(apply_trans(rf, cube))); + dr3 = PTABLEVAL(pd_drud_HTM.ptable, index_drud(apply_trans(fd, cube))); + + drmax = MAX(dr1, MAX(dr2, dr3)); + if (dr1 == dr2 && dr2 == dr3 && dr1 != 0) + drmax++; + + cor = PTABLEVAL(pd_corners_HTM.ptable, index_corners(cube)); + /* ep = PTABLEVAL(pd_ep_HTM.ptable, index_ep(cube)); */ + + /*return MAX(drmax, MAX(ep, cor));*/ + if (drmax == 0 && cor == 0) + return is_solved(cube, false) ? 0 : 1; + return MAX(drmax, cor); +} + + +/* Index functions implementation ********************************************/ + +static uint64_t +index_eofb(Cube cube) +{ + return cube.eofb; +} + +static uint64_t +index_coud(Cube cube) +{ + return cube.coud; +} + +static uint64_t +index_corners(Cube cube) +{ + return cube.coud * FACTORIAL8 + cube.cp; +} + +static uint64_t +index_ep(Cube cube) +{ + uint64_t a, b, c; + + a = cube.eposs; + b = (cube.epose % FACTORIAL4) + epos_dependent_cube(cube)*FACTORIAL4; + c = cube.eposm % FACTORIAL4; + + b *= FACTORIAL4 * BINOM12ON4; + c *= FACTORIAL4 * BINOM12ON4 * FACTORIAL4 * BINOM8ON4; + + return a + b + c; +} + +static uint64_t +index_drud(Cube cube) +{ + uint64_t a, b, c; + + a = cube.eofb; + b = cube.coud; + c = cube.epose / FACTORIAL4; + + b *= POW2TO11; + c *= POW2TO11 * POW3TO7; + + return a + b + c; +} + +/* Movesets ******************************************************************/ + +bool +moveset_HTM(Move m) +{ + return m >= U && m <= B3; +} + +bool +moveset_URF(Move m) +{ + Move b = base_move(m); + + return b == U || b == R || b == F; +} + diff --git a/old/backup-manysteps-pretrans/steps.h b/old/backup-manysteps-pretrans/steps.h new file mode 100644 index 0000000..b218e04 --- /dev/null +++ b/old/backup-manysteps-pretrans/steps.h @@ -0,0 +1,36 @@ +#ifndef STEPS_H +#define STEPS_H + +#include "cube.h" + +/* Steps *********************************************************************/ + +extern Step eofb_HTM; +extern Step eorl_HTM; +extern Step eoud_HTM; +extern Step coud_HTM; +extern Step corl_HTM; +extern Step cofb_HTM; +extern Step coud_URF; +extern Step corl_URF; +extern Step cofb_URF; +extern Step corners_HTM; +extern Step corners_URF; +extern Step edges_HTM; +extern Step drud_HTM; +extern Step optimal_HTM; + +/* Pruning tables ************************************************************/ + +extern PruneData pd_eofb_HTM; +extern PruneData pd_coud_HTM; +extern PruneData pd_corners_HTM; +extern PruneData pd_ep_HTM; +extern PruneData pd_drud_HTM; + +/* Movesets ******************************************************************/ + +bool moveset_HTM(Move m); +bool moveset_URF(Move m); + +#endif diff --git a/old/coord.c b/old/coord.c new file mode 100644 index 0000000..cd2da69 --- /dev/null +++ b/old/coord.c @@ -0,0 +1,1014 @@ +#include "coord.h" + +static Cube admissible_eos_from_eofbepos(Cube cube); +static Cube antindex_eofb(uint64_t ind); +static Cube antindex_eofbepos(uint64_t ind); +static Cube antindex_epud(uint64_t ind); +static Cube antindex_coud(uint64_t ind); +static Cube antindex_corners(uint64_t ind); +static Cube antindex_cp(uint64_t ind); +static Cube antindex_cornershtr(uint64_t ind); +static Cube antindex_drud(uint64_t ind); +static Cube antindex_coud_sym16(uint64_t ind); +static Cube antindex_cp_sym16(uint64_t ind); +static Cube antindex_eofbepos_sym16(uint64_t ind); +static Cube antindex_drud_sym16(uint64_t ind); +static Cube antindex_drud_eofb(uint64_t ind); +static Cube antindex_drudfin_noE_sym16(uint64_t ind); +static Cube antindex_htrfin(uint64_t ind); +static Cube antindex_khuge(uint64_t ind); +static int epos_dependent_pos(int pos1, int pos2); +static void gensym(SymData *sd); +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_cornershtr(Cube cube); +static uint64_t index_drud(Cube cube); +static uint64_t index_coud_sym16(Cube cube); +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_drud_eofb(Cube cube); +static uint64_t index_drudfin_noE_sym16(Cube cube); +static uint64_t index_htrfin(Cube cube); +static uint64_t index_khuge(Cube cube); +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_symdata(); +static bool read_symdata_file(SymData *sd); +static bool write_symdata_file(SymData *sd); + +/* All sorts of useful costants and tables **********************************/ + +/* TODO: Can I move inside functions that use them? + Maybe I need to pass them as argument to some + secondary function */ +static int cphtr_left_cosets[FACTORIAL8]; +static int cphtr_right_cosets[FACTORIAL8]; +static int cphtr_right_rep[BINOM8ON4*6]; + + +/* Symmetry data for some coordinates ****************************************/ + +static Trans +trans_group_trivial[1] = { uf }; + +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, +}; + +SymData +sd_coud_16 = { + .filename = "sd_coud_16", + .coord = &coord_coud, + .sym_coord = &coord_coud_sym16, + .ntrans = 16, + .trans = trans_group_udfix +}; + +SymData +sd_cp_16 = { + .filename = "sd_cp_16", + .coord = &coord_cp, + .sym_coord = &coord_cp_sym16, + .ntrans = 16, + .trans = trans_group_udfix +}; + +SymData +sd_eofbepos_16 = { + .filename = "sd_eofbepos_16", + .coord = &coord_eofbepos, + .sym_coord = &coord_eofbepos_sym16, + .ntrans = 16, + .trans = trans_group_udfix +}; + +static int n_all_symdata = 3; +static SymData * all_sd[3] = { + &sd_coud_16, + &sd_cp_16, + &sd_eofbepos_16, +}; + +/* Coordinates and their implementation **************************************/ + +Coordinate +coord_eofb = { + .index = index_eofb, + .cube = antindex_eofb, + .check = check_eofb, + .max = POW2TO11, + .ntrans = 1, + .trans = trans_group_trivial, +}; + +Coordinate +coord_eofbepos = { + .index = index_eofbepos, + .cube = antindex_eofbepos, + .check = check_eofbepos, + .max = POW2TO11 * BINOM12ON4, + .ntrans = 1, + .trans = trans_group_trivial, +}; + +Coordinate +coord_coud = { + .index = index_coud, + .cube = antindex_coud, + .check = check_coud, + .max = POW3TO7, + .ntrans = 1, + .trans = trans_group_trivial, +}; + +Coordinate +coord_corners = { + .index = index_corners, + .cube = antindex_corners, + .check = check_corners, + .max = POW3TO7 * FACTORIAL8, + .ntrans = 1, + .trans = trans_group_trivial, +}; + +Coordinate +coord_cp = { + .index = index_cp, + .cube = antindex_cp, + .check = check_cp, + .max = FACTORIAL8, + .ntrans = 1, + .trans = trans_group_trivial, +}; + +Coordinate +coord_cornershtr = { + .index = index_cornershtr, + .cube = antindex_cornershtr, + .check = check_cornershtr, + .max = POW3TO7 * BINOM8ON4 * 6, + .ntrans = 1, + .trans = trans_group_trivial, +}; + +Coordinate +coord_drud = { + .index = index_drud, + .cube = antindex_drud, + .check = check_drud, + .max = POW2TO11 * POW3TO7 * BINOM12ON4, + .ntrans = 1, + .trans = trans_group_trivial, +}; + +Coordinate +coord_htrfin = { + .index = index_htrfin, + .cube = antindex_htrfin, + .check = check_htrfin, + .max = 24 * 24 * 24 *24 * 24, + .ntrans = 1, + .trans = trans_group_trivial, +}; + +Coordinate +coord_drud_eofb = { + .index = index_drud_eofb, + .cube = antindex_drud_eofb, + .check = check_drud, + .max = POW3TO7 * BINOM12ON4, + .ntrans = 1, + .trans = trans_group_trivial, +}; + +Coordinate +coord_eofbepos_sym16 = { + .index = index_eofbepos_sym16, + .cube = antindex_eofbepos_sym16, + .check = check_eofbepos, + .ntrans = 16, + .trans = trans_group_udfix, +}; + +Coordinate +coord_coud_sym16 = { + .index = index_coud_sym16, + .cube = antindex_coud_sym16, + .check = check_coud, + .ntrans = 16, + .trans = trans_group_udfix, +}; + +Coordinate +coord_cp_sym16 = { + .index = index_cp_sym16, + .cube = antindex_cp_sym16, + .check = check_cp, + .ntrans = 16, + .trans = trans_group_udfix, +}; + +Coordinate +coord_drud_sym16 = { + .index = index_drud_sym16, + .cube = antindex_drud_sym16, + .check = check_drud, + .max = POW3TO7 * 64430, + .ntrans = 16, + .trans = trans_group_udfix, +}; + +Coordinate +coord_drudfin_noE_sym16 = { + .index = index_drudfin_noE_sym16, + .cube = antindex_drudfin_noE_sym16, + .check = check_drudfin_noE, + .max = FACTORIAL8 * 2768, + .ntrans = 16, + .trans = trans_group_udfix, +}; + +Coordinate +coord_khuge = { + .index = index_khuge, + .cube = antindex_khuge, + .check = check_khuge, + .max = POW3TO7 * FACTORIAL4 * 64430, + .ntrans = 16, + .trans = trans_group_udfix, +}; + +/* Functions *****************************************************************/ + +static Cube +admissible_eos_from_eofbepos(Cube cube) +{ + Edge e; + Cube ret; + CubeArray *arr = new_cubearray(cube, pf_all); + + memcpy(arr->eorl, arr->eofb, 12 * sizeof(int)); + memcpy(arr->eoud, arr->eofb, 12 * sizeof(int)); + + for (e = 0; e < 12; e++) { + if ((edge_slice(e) != 0 && edge_slice(arr->ep[e]) == 0) || + (edge_slice(e) == 0 && edge_slice(arr->ep[e]) != 0)) + arr->eorl[e] = 1 - arr->eorl[e]; + if ((edge_slice(e) != 2 && edge_slice(arr->ep[e]) == 2) || + (edge_slice(e) == 2 && edge_slice(arr->ep[e]) != 2)) + arr->eoud[e] = 1 - arr->eoud[e]; + } + + ret = arrays_to_cube(arr, pf_all); + free_cubearray(arr, pf_all); + + return ret; +} + + +static Cube +antindex_eofb(uint64_t ind) +{ + return (Cube){ .eofb = ind, .eorl = ind, .eoud = ind }; +} + +static Cube +antindex_eofbepos(uint64_t ind) +{ + static bool initialized = false; + static Cube admissible_ee_aux[POW2TO11*BINOM12ON4]; + static Cube c1; + static int k; + static uint64_t ui; + + if (!initialized) { + for (ui = 0; ui < POW2TO11*BINOM12ON4; ui++) { + k = (ui / POW2TO11) * 24; + c1 = admissible_ep((Cube){ .epose = k }, pf_e); + c1.eofb = ui % POW2TO11; + c1 = admissible_eos_from_eofbepos(c1); + admissible_ee_aux[ui] = c1; + } + + initialized = true; + } + + return admissible_ee_aux[ind]; +} + +static Cube +antindex_epud(uint64_t ind) +{ + static bool initialized = false; + static Cube epud_aux[FACTORIAL8]; + int a[12]; + uint64_t ui; + CubeArray arr; + + if (!initialized) { + a[FR] = FR; + a[FL] = FL; + a[BL] = BL; + a[BR] = BR; + for (ui = 0; ui < FACTORIAL8; ui++) { + index_to_perm(ui, 8, a); + arr.ep = a; + epud_aux[ui] = arrays_to_cube(&arr, pf_ep); + } + + initialized = true; + } + + return epud_aux[ind]; +} + +static Cube +antindex_coud(uint64_t ind) +{ + return (Cube){ .coud = ind, .corl = ind, .cofb = ind }; +} + +static Cube +antindex_corners(uint64_t ind) +{ + Cube c = {0}; + + c.coud = ind / FACTORIAL8; + c.cp = ind % FACTORIAL8; + + return c; +} + +static Cube +antindex_cp(uint64_t ind) +{ + Cube c = {0}; + + c.cp = ind; + + return c; +} + +static Cube +antindex_cornershtr(uint64_t ind) +{ + Cube c = anti_cphtr(ind % (BINOM8ON4 * 6)); + + c.coud = ind / (BINOM8ON4 * 6); + + return c; +} + +/* TODO: admissible eos and cos */ +/* DONE: temporary fix, make it better */ +/* Or maybe it's ok like this? */ +static Cube +antindex_drud(uint64_t ind) +{ + uint64_t epos, eofb; + Cube c; + + eofb = ind % POW2TO11; + epos = ind / (POW2TO11 * POW3TO7); + c = antindex_eofbepos(eofb + POW2TO11 * epos); + + c.coud = (ind / POW2TO11) % POW3TO7; + c.corl = c.coud; + c.cofb = c.coud; + + return c; +} + +static Cube +antindex_drud_eofb(uint64_t ind) +{ + return antindex_drud(ind * POW2TO11); +} + +static Cube +antindex_coud_sym16(uint64_t ind) +{ + return sd_coud_16.rep[ind]; +} + +static Cube +antindex_cp_sym16(uint64_t ind) +{ + return sd_cp_16.rep[ind]; +} + +static Cube +antindex_eofbepos_sym16(uint64_t ind) +{ + return sd_eofbepos_16.rep[ind]; +} + +static Cube +antindex_drud_sym16(uint64_t ind) +{ + Cube c; + + c = sd_eofbepos_16.rep[ind/POW3TO7]; + c.coud = ind % POW3TO7; + c.cofb = c.coud; + c.corl = c.coud; + + return c; +} + +static Cube +antindex_drudfin_noE_sym16(uint64_t ind) +{ + Cube c1, c2; + + c1 = antindex_epud(ind % FACTORIAL8); + c2 = sd_cp_16.rep[ind/FACTORIAL8]; + c1.cp = c2.cp; + + return c1; +} + +static Cube +antindex_htrfin(uint64_t ind) +{ + Cube ret = {0}; + uint64_t cp1, cp2; + + static bool initialized = false; + static int i, j, k, c[8], c1[4], c2[4], cp[24][24]; + static int c1solved[4] = {UFR, UBL, DFL, DBR}; + static int c2solved[4] = {UFL, UBR, DFR, DBL}; + + if (!initialized) { + for (i = 0; i < 24; i++) { + for (j = 0; j < 24; j++) { + index_to_perm(i, 4, c1); + index_to_perm(j, 4, c2); + for (k = 0; k < 8; k++) + if (k == UFR || k == UBL || + k == DFL || k == DBR) + c[k] = c1[c1solved[k/2]]; + else + c[k] = c2[c2solved[k/2]]; + + cp[i][j] = perm_to_index(c, 8); + } + } + + initialized = true; + } + + cp2 = ind % 24; + ind /= 24; + cp1 = ind % 24; + ret.cp = cp[cp1][cp2]; + + ind /= 24; + ret.eposm = ind % 24; + ind /= 24; + ret.eposs = ind % 24; + ret.epose = ind / 24; + + return ret; +} + +static Cube +antindex_khuge(uint64_t ind) +{ + Cube c; + + c = sd_eofbepos_16.rep[ind/(FACTORIAL4*POW3TO7)]; + c.epose = ((c.epose / 24) * 24) + ((ind/POW3TO7) % 24); + c.coud = ind % POW3TO7; + + return c; +} + +bool +check_centers(Cube cube) +{ + return cube.cpos == 0; +} + +bool +check_corners(Cube cube) +{ + return cube.cp == 0 && cube.coud == 0; +} + +bool +check_cp(Cube cube) +{ + return cube.cp == 0; +} + +bool +check_cornershtr(Cube cube) +{ + return cube.coud == 0 && cphtr(cube) == 0; /* TODO: use array cphtrcosets*/ +} + +bool +check_coud(Cube cube) +{ + return cube.coud == 0; +} + +bool +check_drud(Cube cube) +{ + return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0; +} + +bool +check_htr(Cube cube) +{ + return check_cornershtr(cube) && + cube.eofb == 0 && cube.eorl == 0 && cube.eoud == 0; +} + +bool +check_htrfin(Cube cube) +{ + return cube.cp == 0 && + cube.epose == 0 && cube.eposs == 0 && cube.eposm == 0; +} + +bool +check_drudfin_noE(Cube cube) +{ + return cube.eposs == 0 && cube.eposm == 0 && cube.cp == 0; +} + +bool +check_eofb(Cube cube) +{ + return cube.eofb == 0; +} + +bool +check_eofbepos(Cube cube) +{ + return cube.eofb == 0 && cube.epose / 24 == 0; +} + +bool +check_epose(Cube cube) +{ + return cube.epose == 0; +} + +bool +check_ep(Cube cube) +{ + return cube.epose == 0 && cube.eposs == 0 && cube.eposm == 0; +} + +bool +check_khuge(Cube cube) +{ + return check_drud(cube) && cube.epose % 24 == 0; +} + +bool +check_nothing(Cube cube) +{ + return is_admissible(cube); /*TODO: maybe change?*/ +} + +static int +epos_dependent_pos(int poss, int pose) +{ + static int epe_solved[4] = {FR, FL, BL, BR}; + static int eps_solved[4] = {UL, UR, DL, DR}; + int ep[12] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; + int ep8[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + int i, j; + + epos_to_partial_ep(poss*FACTORIAL4, ep, eps_solved); + epos_to_partial_ep(pose*FACTORIAL4, ep, epe_solved); + + for (i = 0, j = 0; i < 12; i++) + if (edge_slice(ep[i]) != 0) + ep8[j++] = (edge_slice(ep[i]) == 1) ? 1 : 0; + + swap(&ep8[1], &ep8[4]); + swap(&ep8[3], &ep8[6]); + + return subset_to_index(ep8, 8, 4); +} + +static void +gensym(SymData *sd) +{ + uint64_t i, in, nreps = 0; + int j; + Cube c, d; + + if (sd->generated) + return; + + sd->class = malloc(sd->coord->max * sizeof(uint64_t)); + sd->rep = malloc(sd->coord->max * sizeof(Cube)); + sd->transtorep = malloc(sd->coord->max * sizeof(Trans)); + + 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) { + c = sd->coord->cube(i); + sd->rep[nreps] = c; + for (j = 0; j < sd->ntrans; j++) { + d = apply_trans(sd->trans[j], c); + in = sd->coord->index(d); + + if (sd->class[in] == sd->coord->max + 1) { + sd->class[in] = nreps; + sd->transtorep[in] = + inverse_trans(sd->trans[j]); + } + } + nreps++; + } + } + + sd->sym_coord->max = nreps; + sd->rep = realloc(sd->rep, nreps * sizeof(Cube)); + sd->generated = true; + + fprintf(stderr, "Found %lu classes\n", nreps); + + if (!write_symdata_file(sd)) + fprintf(stderr, "Error writing SymData file\n"); + + return; +} + +static uint64_t +index_eofb(Cube cube) +{ + return cube.eofb; +} + +static uint64_t +index_eofbepos(Cube cube) +{ + return (cube.epose / FACTORIAL4) * POW2TO11 + cube.eofb; +} + +static uint64_t +index_epud(Cube cube) +{ + uint64_t ret; + CubeArray *arr = new_cubearray(cube, pf_ep); + + ret = perm_to_index(arr->ep, 8); + free_cubearray(arr, pf_ep); + + return ret; +} + +static uint64_t +index_coud(Cube cube) +{ + return cube.coud; +} + +static uint64_t +index_corners(Cube cube) +{ + return cube.coud * FACTORIAL8 + cube.cp; +} + +static uint64_t +index_cp(Cube cube) +{ + return cube.cp; +} + +static uint64_t +index_cornershtr(Cube cube) +{ + return cube.coud * BINOM8ON4 * 6 + cphtr(cube); +} + +static uint64_t +index_drud(Cube cube) +{ + uint64_t a, b, c; + + a = cube.eofb; + b = cube.coud; + c = cube.epose / FACTORIAL4; + + b *= POW2TO11; + c *= POW2TO11 * POW3TO7; + + return a + b + c; +} + +static uint64_t +index_drud_eofb(Cube cube) +{ + return index_drud(cube) / POW2TO11; +} + +static uint64_t +index_coud_sym16(Cube cube) +{ + return sd_coud_16.class[index_coud(cube)]; +} + +static uint64_t +index_cp_sym16(Cube cube) +{ + return sd_cp_16.class[index_cp(cube)]; +} + +static uint64_t +index_drud_sym16(Cube cube) +{ + Trans t; + Cube c; + + t = sd_eofbepos_16.transtorep[index_eofbepos(cube)]; + c = apply_trans(t, cube); + + return index_eofbepos_sym16(c) * POW3TO7 + c.coud; +} + +static uint64_t +index_drudfin_noE_sym16(Cube cube) +{ + Trans t; + Cube c; + + t = sd_cp_16.transtorep[index_cp(cube)]; + c = apply_trans(t, cube); + + return index_cp_sym16(c) * FACTORIAL8 + index_epud(c); +} + +static uint64_t +index_htrfin(Cube cube) +{ + uint64_t epe, eps, epm, cp, ep; + + static bool initialized = false; + static uint64_t cp1[FACTORIAL8], cp2[FACTORIAL8]; + static unsigned int i; + static int j, n1, n2, c[8], c1[4], c2[4]; + + if (!initialized) { + for (i = 0; i < FACTORIAL8; i++) { + index_to_perm(i, 8, c); + n1 = 0; + n2 = 0; + for (j = 0; j < 8; j++) + if (c[j] == UFR || c[j] == UBL || + c[j] == DFL || c[j] == DBR) + c1[n1++] = c[j] / 2; + else + c2[n2++] = c[j] / 2; + + cp1[i] = perm_to_index(c1, 4); + cp2[i] = perm_to_index(c2, 4); + } + + initialized = true; + } + + epe = cube.epose % 24; + eps = cube.eposs % 24; + epm = cube.eposm % 24; + + cp = cp1[cube.cp] * 24 + cp2[cube.cp]; + ep = (epe * 24 + eps) *24 + epm; + + return ep * 24 * 24 + cp; +} + +static uint64_t +index_eofbepos_sym16(Cube cube) +{ + return sd_eofbepos_16.class[index_eofbepos(cube)]; +} + +static uint64_t +index_khuge(Cube cube) +{ + Trans t; + Cube c; + uint64_t a; + + t = sd_eofbepos_16.transtorep[index_eofbepos(cube)]; + c = apply_trans(t, cube); + a = (index_eofbepos_sym16(c) * 24) + (c.epose % 24); + + return a * POW3TO7 + c.coud; +} + +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->rep, sizeof(Cube), *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 +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->rep, sizeof(Cube), *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; +} + +/* Init functions implementation *********************************************/ + +/* + * There is certainly a bette 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 < FACTORIAL8; i++) { + cphtr_left_cosets[i] = -1; + cphtr_right_cosets[i] = -1; + } + + /* 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++); + + /* 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++); +} + +static void +init_cphtr_left_cosets_bfs(int i, int c) +{ + int j, jj, k, next[FACTORIAL8], next2[FACTORIAL8], n, n2; + Move moves[6] = {U2, D2, R2, L2, F2, B2}; + + n = 1; + next[0] = i; + cphtr_left_cosets[i] = c; + + while (n != 0) { + for (j = 0, n2 = 0; j < n; j++) { + for (k = 0; k < 6; k++) { + /*jj = cp_mtable[moves[k]][next[j]];*/ + /* TODO fix formatting */ + jj = apply_move(moves[k], (Cube){.cp=next[j]}).cp; + if (cphtr_left_cosets[jj] == -1) { + cphtr_left_cosets[jj] = c; + next2[n2++] = jj; + } + } + } + + for (j = 0; j < n2; j++) + next[j] = next2[j]; + n = n2; + } +} + +static void +init_cphtr_right_cosets_color(int i, int d) +{ + int cp; + unsigned int j; + + cphtr_right_rep[d] = i; + for (j = 0; j < FACTORIAL8; j++) { + if (cphtr_left_cosets[j] == 0) { + /* TODO: use antindexer, it's nicer */ + cp = compose((Cube){.cp = i}, (Cube){.cp = j}).cp; + cphtr_right_cosets[cp] = d; + } + } +} + +static void +init_symdata() +{ + int i; + + for (i = 0; i < n_all_symdata; i++) + gensym(all_sd[i]); +} + +/*TODO maybe move the next two */ +uint64_t +cphtr(Cube cube) +{ + return cphtr_right_cosets[cube.cp]; +} + +Cube +anti_cphtr(uint64_t ind) +{ + return (Cube) { .cp = cphtr_right_rep[ind] }; +} + +uint64_t +epos_dependent(Cube c) +{ + static int initialized = false; + static int aux[BINOM12ON4][BINOM12ON4]; + static uint64_t ui, uj; + + if (!initialized) { + for (ui = 0; ui < BINOM12ON4; ui++) + for (uj = 0; uj < BINOM12ON4; uj++) + aux[ui][uj] = epos_dependent_pos(ui, uj); + + initialized = true; + } + + return aux[c.eposs/FACTORIAL4][c.epose/FACTORIAL4]; +} + +void +init_coord() +{ + static bool initialized = false; + if (initialized) + return; + initialized = true; + + init_cphtr_cosets(); + init_symdata(); +} + diff --git a/old/coord.h b/old/coord.h new file mode 100644 index 0000000..3e230a8 --- /dev/null +++ b/old/coord.h @@ -0,0 +1,45 @@ +#ifndef COORD_H +#define COORD_H + +#include "trans.h" + +extern Coordinate coord_eofb; +extern Coordinate coord_eofbepos; +extern Coordinate coord_coud; +extern Coordinate coord_cp; +extern Coordinate coord_corners; +extern Coordinate coord_cornershtr; +extern Coordinate coord_drud; +extern Coordinate coord_coud_sym16; +extern Coordinate coord_drud_eofb; +extern Coordinate coord_cp_sym16; +extern Coordinate coord_eofbepos_sym16; +extern Coordinate coord_drud_sym16; +extern Coordinate coord_drudfin_noE_sym16; +extern Coordinate coord_htrfin; +extern Coordinate coord_khuge; + +uint64_t cphtr(Cube cube); /* TODO: rename (something with cosets) */ +Cube anti_cphtr(uint64_t ind); /*TODO also this */ +uint64_t epos_dependent(Cube cube); /* TODO: rename and turn into an indexer */ + +bool check_centers(Cube cube); +bool check_corners(Cube cube); +bool check_cp(Cube cube); +bool check_cornershtr(Cube cube); +bool check_coud(Cube cube); +bool check_drud(Cube cube); +bool check_htr(Cube cube); +bool check_htrfin(Cube cube); +bool check_drudfin_noE(Cube cube); +bool check_eofb(Cube cube); +bool check_eofbepos(Cube cube); +bool check_epose(Cube cube); +bool check_ep(Cube cube); +bool check_khuge(Cube cube); +bool check_nothing(Cube cube); + +void init_coord(); + +#endif + diff --git a/old/utils.c b/old/utils.c new file mode 100644 index 0000000..3b5388e --- /dev/null +++ b/old/utils.c @@ -0,0 +1,294 @@ +#include "utils.h" + +/* Generic utility functions *************************************************/ + +void +apply_permutation(int *perm, int *set, int n) +{ + int *aux = malloc(n * sizeof(int)); + int i; + + if (!is_perm(perm, n)) + return; + + for (i = 0; i < n; i++) + aux[i] = set[perm[i]]; + + intarrcopy(aux, set, n); + free(aux); +} + +void +intarrcopy(int *src, int *dst, int n) +{ + int i; + for (i = 0; i < n; i++) + dst[i] = src[i]; +} + +bool +is_perm(int *a, int n) +{ + int *aux = malloc(n * sizeof(int)); + int i; + + for (i = 0; i < n; i++) + if (a[i] < 0 || a[i] >= n) + return false; + else + aux[a[i]] = 1; + + for (i = 0; i < n; i++) + if (!aux[i]) + return false; + + free(aux); + + return true; +} + +bool +is_subset(int *a, int n, int k) +{ + int i, sum = 0; + + for (i = 0; i < n; i++) + sum += a[i] ? 1 : 0; + + return sum == k; +} + +int +sum(int *a, int n) +{ + int i, ret = 0; + + for (i = 0; i < n; i++) + ret += a[i]; + + return ret; +} + +void +sum_arrays_mod(int *src, int *dst, int n, int m) +{ + int i; + + for (i = 0; i < n; i++) + dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m; +} + +void +swap(int *a, int *b) +{ + int aux; + + aux = *a; + *a = *b; + *b = aux; +} + +/* Standard mathematical functions *******************************************/ + +int +binomial(int n, int k) +{ + if (n < 0 || k < 0 || k > n) + return 0; + + return factorial(n) / (factorial(k) * factorial(n-k)); +} + +int +factorial(int n) +{ + int i, ret = 1; + + if (n < 0) + return 0; + + for (i = 1; i <= n; i++) + ret *= i; + + return ret; +} + +int +perm_sign(int *a, int n) +{ + int i, j, ret = 0; + if (!is_perm(a,n)) + return -1; + + for (i = 0; i < n; i++) + for (j = i+1; j < n; j++) + ret += (a[i] > a[j]) ? 1 : 0; + + return ret % 2; +} + +int +powint(int a, int b) +{ + if (b < 0) + return 0; /* Truncate */ + if (b == 0) + return 1; + + if (b % 2) + return a * powint(a, b-1); + else + return powint(a*a, b/2); +} + +/* Conversions to and from int (base b digits, permutations...) **************/ + +int +digit_array_to_int(int *a, int n, int b) +{ + int i, ret = 0, p = 1; + + for (i = 0; i < n; i++, p *= b) + ret += a[i] * p; + + return ret; +} + +void +int_to_digit_array(int a, int b, int n, int *r) +{ + int i; + + if (b <= 1) + for (i = 0; i < n; i++) + r[i] = 0; + else + for (i = 0; i < n; i++, a /= b) + r[i] = a % b; +} + +void +int_to_sum_zero_array(int x, int b, int n, int *a) +{ + int i, s = 0; + + if (b <= 1) { + for (i = 0; i < n; i++) + a[i] = 0; + } else { + int_to_digit_array(x, b, n-1, a); + for (i = 0; i < n - 1; i++) + s = (s + a[i]) % b; + a[n-1] = (b - s) % b; + } +} + +int +invert_digits(int a, int b, int n) +{ + int i, *r = malloc(n * sizeof(int)); + + int_to_digit_array(a, b, n, r); + for (i = 0; i < n; i++) + r[i] = (b-r[i]) % b; + + return digit_array_to_int(r, n, b); +} + +void +index_to_perm(int p, int n, int *r) +{ + int *a = malloc(n * sizeof(int)); + int i, j, c; + + for (i = 0; i < n; i++) + a[i] = 0; + + if (p < 0 || p >= factorial(n)) + for (i = 0; i < n; i++) + r[i] = -1; + + for (i = 0; i < n; i++) { + c = 0; + j = 0; + while (c <= p / factorial(n-i-1)) + c += a[j++] ? 0 : 1; + r[i] = j-1; + a[j-1] = 1; + p %= factorial(n-i-1); + } + + free(a); +} + +int +perm_to_index(int *a, int n) +{ + int i, j, c, ret = 0; + + if (!is_perm(a, n)) + return -1; + + for (i = 0; i < n; i++) { + c = 0; + for (j = i+1; j < n; j++) + c += (a[i] > a[j]) ? 1 : 0; + ret += factorial(n-i-1) * c; + } + + return ret; +} + +void +index_to_subset(int s, int n, int k, int *r) +{ + int i, j, v; + + if (s < 0 || s >= binomial(n, k)) { + for (i = 0; i < n; i++) + r[i] = -1; + return; + } + + for (i = 0; i < n; i++) { + if (k == n-i) { + for (j = i; j < n; j++) + r[j] = 1; + return; + } + + if (k == 0) { + for (j = i; j < n; j++) + r[j] = 0; + return; + } + + v = binomial(n-i-1, k); + if (s >= v) { + r[i] = 1; + k--; + s -= v; + } else { + r[i] = 0; + } + } +} + +int subset_to_index(int *a, int n, int k) { + int i, ret = 0; + + /* TODO: better checks */ + if (!is_subset(a, n, k)) + return binomial(n, k); + + for (i = 0; i < n; i++) { + if (k == n-i) + return ret; + if (a[i]) { + ret += binomial(n-i-1, k); + k--; + } + } + + return ret; +} diff --git a/old/utils.h b/old/utils.h new file mode 100644 index 0000000..ee8ac6e --- /dev/null +++ b/old/utils.h @@ -0,0 +1,59 @@ +#ifndef UTILS_H +#define UTILS_H + +#include +#include + +/* Constants and macros *****************************************************/ + +#define pow2to11 2048 +#define pow2to12 4096 +#define pow3to7 2187 +#define pow3to8 6561 +#define pow12to4 20736 +#define factorial4 24 +#define factorial6 720 +#define factorial8 40320 +#define factorial12 479001600 +#define binom12on4 495 +#define binom8on4 70 + +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#define max(a,b) (((a) > (b)) ? (a) : (b)) + +/* Generic utility functions *************************************************/ + +void apply_permutation(int *perm, int *set, int n); +void intarrcopy(int *src, int *dst, int n); +bool is_perm(int *a, int n); +bool is_subset(int *a, int n, int k); +int sum(int *a, int n); +void sum_arrays_mod(int *src, int *dst, int n, int m); +void swap(int *a, int *b); + +/* Standard mathematical functions *******************************************/ + +int binomial(int n, int k); +int factorial(int n); +int perm_sign(int a[], int n); +int powint(int a, int b); + +/* Conversions to and from int (base b digits, permutations...) **************/ + +int digit_array_to_int(int *a, int n, int b); +void int_to_digit_array(int a, int b, int n, int *r); +void int_to_sum_zero_array(int x, int b, int n, int *a); +int invert_digits(int a, int b, int n); + +void index_to_perm(int p, int n, int *r); +int perm_to_index(int *a, int n); + +void index_to_subset(int s, int n, int k, int *r); +int subset_to_index(int *a, int n, int k); + +/* Am I not using these two? +void index_to_ordered_subset(int s, int n, int k, int *r); +int ordered_subset_to_index(int *a, int n, int k); +*/ + +#endif -- cgit v1.3