h48

A prototype for an optimal Rubik's cube solver, work in progress.
git clone https://git.tronto.net/h48
Download | Log | Files | Refs | README | LICENSE

commit 4d8465a3a791ebcf4bc74bdcc21eff7341ebc30f
parent 7defd8041e6050a9adf7927b43fd249d75d6389f
Author: Sebastiano Tronto <sebastiano@tronto.net>
Date:   Fri,  7 Mar 2025 17:08:28 +0100

More progress on coordinate solver

Diffstat:
MTODO_COORDINATES | 4++--
Msrc/solvers/coord/common.h | 28++++++++++++++++++++++++++++
Msrc/solvers/coord/coord_solve.h | 225+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/solvers/coord/coord_types_macros.h | 1+
Msrc/solvers/coord/eo.h | 5+++++
Msrc/solvers/coord/gendata_coord.h | 14++++++++------
Msrc/solvers/h48/solve.h | 2+-
Msrc/utils/constants.h | 4++++
8 files changed, 274 insertions(+), 9 deletions(-)

diff --git a/TODO_COORDINATES b/TODO_COORDINATES @@ -1,6 +1,6 @@ -- solver - - include NISS +- solver (from TODOs in appending solution) - test solver for EO +- add NISS (and add tests for NISS EO) - make solve parallelized - other coordinates - gendata must handle symmetry diff --git a/src/solvers/coord/common.h b/src/solvers/coord/common.h @@ -6,6 +6,8 @@ coord_t *all_coordinates[] = { }; STATIC void append_coord_name(const coord_t *, char *); +STATIC coord_t *parse_coord(const char *, int); +STATIC uint8_t parse_axis(const char *, int); STATIC void append_coord_name(const coord_t *coord, char *str) @@ -18,3 +20,29 @@ append_coord_name(const coord_t *coord, char *str) str[j] = '\0'; } + +STATIC coord_t * +parse_coord(const char *coord, int n) +{ + int i; + + for (i = 0; all_coordinates[i] != NULL; i++) + if (!strncmp(all_coordinates[i]->name, coord, n)) + return all_coordinates[i]; + + return NULL; +} + +STATIC uint8_t +parse_axis(const char *axis, int n) +{ + if (!strncmp(axis, "UD", n) || !strncmp(axis, "DU", n)) { + return AXIS_UD; + } else if (!strncmp(axis, "RL", n) || !strncmp(axis, "LR", n)) { + return AXIS_RL; + } else if (!strncmp(axis, "FB", n) || !strncmp(axis, "BF", n)) { + return AXIS_FB; + } + + return UINT8_ERROR; +} diff --git a/src/solvers/coord/coord_solve.h b/src/solvers/coord/coord_solve.h @@ -1,3 +1,228 @@ #include "coord_types_macros.h" #include "common.h" #include "gendata_coord.h" + +#define MAXLEN_COORDSOL 20 + +typedef struct { + cube_t cube; + uint8_t depth; + uint8_t nmoves; + uint8_t moves[MAXLEN_COORDSOL]; + coord_t *coord; + const void *coord_data; + const uint8_t *ptable; + uint8_t trans; + int64_t *nsols; + int64_t maxsolutions; + int optimal; + uint8_t *shortest_sol; + uint64_t solutions_size; + uint64_t *solutions_used; + char **solutions; +} dfsarg_solve_coord_t; + +STATIC int64_t solve_coord(cube_t, coord_t *, uint8_t, uint8_t, uint8_t, + uint8_t, uint64_t, int, int, uint64_t, const void, uint64_t, char); +STATIC int64_t solve_coord_dispatch(cube_t, const char *, uint8_t, uint8_t, + uint8_t, uint64_t, int, int, uint64_t, const void, uint64_t, char); +STATIC bool solve_coord_appendchar(char *, uint64_t, uint64_t *, char); +STATIC int64_t solve_coord_appendsolution(dfsarg_solve_coord_t *); +STATIC int64_t solve_coord_dfs(dfsarg_solve_coord_t *); + +STATIC int64_t +solve_coord_appendsolution(dfsarg_solve_coord_t *arg) +{ + uint8_t i, t, tmoves[MAXLEN_COORDSOL]; + + if (*arg->nsols >= arg->maxsolutions || + arg->nmoves > *arg->shortest_sol + arg->optimal) + return 0; + + sortparallel(arg->moves, arg->nmoves); + + t = inverse_trans(arg->trans); + for (i = 0; i < arg->nmoves; i++) + tmoves[i] = transform_move(arg->moves[i], t); + + /* TODO append tmoves[] */ + + return 1; +} + +STATIC bool +solve_coord_appendchar(char *s, uint64_t s_size, uint64_t *s_used, char c) +{ + if (s_size == *s_used) + return false; + + s[*s_used] = c; + (*s_used)++; + + return true; +} + +STATIC int64_t +solve_coord_dfs(dfsarg_solve_coord_t *arg) +{ + uint64_t coord; + uint8_t pval; + + coord = arg->coord->coord(arg->cube, arg->coord_data); + + if (coord == 0) { + if (arg->nmoves != arg->depth) + return 0; + return solve_coord_appendsolution(arg); + } + + pval = get_coord_pval(arg->coord, arg->ptable, coord); + if (arg->nmoves + pval > arg->depth) + return 0; + + /* TODO recursive call */ + /* Is allowednextmove available here? */ + + return 0; +} + +STATIC int64_t +solve_coord_dispatch( + cube_t cube, + const char *coord_axis, + uint8_t nissflag, + uint8_t minmoves, + uint8_t maxmoves, + uint64_t maxsolutions, + int optimal, + int threads, + uint64_t data_size, + const void *data, + uint64_t sols_size, + char *sols +) +{ + int i, n; + coord_t *coord; + uint8_t axis; + + n = strlen(coord_axis); + for (i = 0; coord_axis[i] != ' ' && coord_axis[i] != '\0'; i++) ; + + coord = parse_coord(coord_axis, i); + axis = parse_axis(coord_axis + i + 1, n - i - 1); + + if (coord == NULL) { + LOG("Could not parse coordinate '%s'\n", coord_axis); + return NISSY_ERROR_INVALID_SOLVER; + } + + if (axis == UINT8_ERROR) { + LOG("Could not parse axis from '%s'\n", coord_axis); + return NISSY_ERROR_INVALID_SOLVER; + } + + return solve_coord(cube, coord, axis, nissflag, minmoves, maxmoves, + maxsolutions, optimal, threads, data_size, data, sols_size, sols); +} + +STATIC int64_t +solve_coord( + cube_t cube, + coord_t *coord, + uint8_t axis, + uint8_t nissflag, + uint8_t minmoves, + uint8_t maxmoves, + uint64_t maxsolutions, + int optimal, + int threads, + uint64_t data_size, + const void data, + uint64_t sols_size, + char *sols +) +{ + int8_t d; + uint8_t t, shortest_sol; + int64_t nsols; + uint64_t sols_used; + cube_t c; + const void *coord_data; + const uint8_t *ptable; + dfsarg_solve_coord_t arg; + tableinfo_t info; + + if (readtableinfo(data_size, data, &info) != NISSY_OK) + goto solve_coord_error_data; + + if (info.type == TABLETYPE_PRUNING) { + /* Only the pruning table */ + coord_data = NULL; + ptable = (uint8_t *)data + INFOSIZE; + } else { + /* Coordinate has extra data */ + coord_data = data + INFOSIZE; + ptable = (uint8_t *)data + info.next + INFOSIZE; + } + + nsols = 0; + sols_used = 0; + shortest_sol = MAXLEN_COORDSOL + 1; + c = transform(cube, t); + t = coord->axistrans[axis]; + + arg = (dfsarg_solve_coord_t) { + .cube = c, + .coord = coord, + .coord_data = coord_data, + .ptable = ptable, + .trans = t, + .nsols = &nsols, + .maxsolutions = (int64_t)maxsolutions, + .optimal = optimal, + .shortest_sol = &shortest_sol, + .solutions_size = sols_size, + .solutions_used = &sols_used, + .solutions = &sols, + }; + + if (coord->coord(c, coord_data) == 0) { + if (minmoves == 0) { + nsols = 1; + if (!solve_coord_appendchar( + sols, sols_size, &sols_used, '\n')) + goto solve_coord_error_buffer; + } + goto solve_coord_done; + } + + for ( + d = MAX(minmoves, 1); + d <= maxmoves && nsols < (int64_t)maxsolutions + && !(nsols != 0 && d > shortest_sol + optimal); + d++ + ) { + if (d >= 10) + LOG("Found %" PRId64 " solutions, searching at depth %" + PRId8 "\n", nsols, d); + + arg.depth = d; + arg.nmoves = 0; + nsols += solve_coord_dfs(&arg); + } + +solve_coord_done: + if (!solve_coord_appendchar(sols, sols_size, &sols_used, '\0')) + goto solve_coord_error_buffer; + + return nsols; + +solve_coord_error_data: + LOG("solve_coord: error reading table\n"); + return NISSY_ERROR_DATA; + +solve_coord_error_buffer: + LOG("Could not append solution to buffer: size too small\n"); + return NISSY_ERROR_BUFFER_SIZE; +} diff --git a/src/solvers/coord/coord_types_macros.h b/src/solvers/coord/coord_types_macros.h @@ -10,4 +10,5 @@ typedef struct { uint64_t max; uint32_t moves_mask; uint64_t trans_mask; + uint8_t axistrans[3]; } coord_t; diff --git a/src/solvers/coord/eo.h b/src/solvers/coord/eo.h @@ -10,6 +10,11 @@ STATIC coord_t coordinate_eo = { .max = POW_2_11, .trans_mask = TM_ALLTRANS, .moves_mask = MM_ALLMOVES, + .axistrans = { + [AXIS_UD] = TRANS_FDr, + [AXIS_RL] = TRANS_URr, + [AXIS_FB] = TRANS_UFr, + }, }; STATIC uint64_t diff --git a/src/solvers/coord/gendata_coord.h b/src/solvers/coord/gendata_coord.h @@ -7,14 +7,16 @@ STATIC void set_coord_pval(const coord_t *, uint8_t *, uint64_t, uint8_t); STATIC size_t gendata_coordinate_name(const char *name, void *buf) { - int i; + coord_t *coord; - for (i = 0; all_coordinates[i] != NULL; i++) - if (strcmp(all_coordinates[i]->name, name) == 0) - return gendata_coordinate(all_coordinates[i], buf); + coord = parse_coord(name, strlen(name)); + if (coord == NULL) { + LOG("Cannot generate data for coordinate '%s': not found\n", + name); + return 0; + } - LOG("Cannot generate data for coordinate '%s': not found\n", name); - return 0; + return gendata_coordinate(coord, buf); } STATIC size_t diff --git a/src/solvers/h48/solve.h b/src/solvers/h48/solve.h @@ -457,7 +457,7 @@ solve_h48( pthread_t thread[THREADS]; pthread_mutex_t solutions_mutex; - if(readtableinfo_n(data_size, data, 2, &info) != NISSY_OK) + if (readtableinfo_n(data_size, data, 2, &info) != NISSY_OK) goto solve_h48_error_data; cocsepdata = (uint32_t *)((char *)data + INFOSIZE); diff --git a/src/utils/constants.h b/src/utils/constants.h @@ -93,6 +93,10 @@ STATIC int64_t binomial[12][12] = { #define TRANS_BDm UINT8_C(46) #define TRANS_BLm UINT8_C(47) +#define AXIS_UD UINT8_C(0) +#define AXIS_RL UINT8_C(1) +#define AXIS_FB UINT8_C(2) + #define NMOVES (1+MOVE_B3) #define NTRANS (1+TRANS_BLm)