nissy-fmc

A Rubik's cube FMC assistant
git clone https://git.tronto.net/nissy-fmc
Download | Log | Files | Refs | README | LICENSE

commit 25e0d5703367969170f8f47051c7adcf58f5c990
parent a9831ada32f9349b3d8973b07df3171455fbddcd
Author: Sebastiano Tronto <sebastiano.tronto@gmail.com>
Date:   Tue, 14 Dec 2021 17:32:29 +0100

Added light optimal solver -  about 5 times slower but takes only 500Mb of RAM

Diffstat:
MINSTALL | 7++++---
MREADME.md | 11++++++-----
MTODO.md | 3---
Mnissy | 0
Msrc/steps.c | 126++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
5 files changed, 129 insertions(+), 18 deletions(-)

diff --git a/INSTALL b/INSTALL @@ -1,10 +1,11 @@ # Requirements A full installation of nissy requires a little more than 2Gb of space, -of which 1.6Gb are occupied by the huge pruning table for optimal solving, +of which 1.6Gb are occupied by the huge pruning table for fast optimal solving, and running it requires the same amount of RAM. -One can choose to never use the optimal solver and not to install the relative -pruning table. If so, about 500Mb should be enough. +One can choose to never use this function and not to install the relative +pruning table. There is an alternative (about 5 times slower) +optimal solving function that uses about 500Mb of RAM. # Installation diff --git a/README.md b/README.md @@ -20,11 +20,12 @@ solutions for EO/DR/HTR or similar substeps. ## Requirements -A full installation of nissy requires about 1.8Gb of space, of which 1.6Gb are -occupied by the huge pruning table for optimal solving, and running it requires -the same amount of RAM. -One can choose to never use the optimal solver and not to install the relative -pruning table. If so, about 200Mb should be enough. +A full installation of nissy requires a little more than 2Gb of space, +of which 1.6Gb are occupied by the huge pruning table for fast optimal solving, +and running it requires the same amount of RAM. +One can choose to never use this function and not to install the relative +pruning table. There is an alternative (about 5 times slower) +optimal solving function that uses about 500Mb of RAM. ## Installation diff --git a/TODO.md b/TODO.md @@ -14,9 +14,6 @@ It's more of a personal reminder than anything else. * invert an alg ### More steps for `solve` -* "slow" optimal solver, using drud table but all the tricks - of khuge (+ trick to avoid 180° moves when one of the inverse - probes returns exactly the target value) * QTM optimal solving * Block-building steps (cross, roux blocks, ...) * Other common steps (LSE, ...) diff --git a/nissy b/nissy Binary files differ. diff --git a/src/steps.c b/src/steps.c @@ -36,6 +36,7 @@ static int estimate_drudfin_drud(DfsArg *arg); static int estimate_htr_drud(DfsArg *arg); static int estimate_htrfin_htr(DfsArg *arg); static int estimate_optimal_HTM(DfsArg *arg); +static int estimate_light_HTM(DfsArg *arg); static bool always_valid(Alg *alg); static bool validate_singlecw_ending(Alg *alg); @@ -55,6 +56,7 @@ static char check_drany_msg[100] = "DR must be solved on at least one axis"; /* Steps *********************************************************************/ +/* Optimal solvers *******************/ Step optimal_HTM = { .shortname = "optimal", @@ -74,6 +76,25 @@ optimal_HTM = { .ntables = 2, }; +Step +optimal_light_HTM = { + .shortname = "light", + .name = "Optimal solve (in HTM), small table (500Mb RAM total)", + + .final = true, + .is_done = is_solved, + .estimate = estimate_light_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = always_valid, + .moveset = moveset_HTM, + + .pre_trans = uf, + + .tables = {&pd_drud_sym16_HTM, &pd_corners_HTM}, + .ntables = 2, +}; + /* EO steps **************************/ Step eoany_HTM = { @@ -813,6 +834,7 @@ htrfin_htr = { Step *steps[NSTEPS] = { &optimal_HTM, /* first is default */ + &optimal_light_HTM, &eoany_HTM, &eofb_HTM, @@ -1162,7 +1184,6 @@ static int estimate_optimal_HTM(DfsArg *arg) { int target, ret; - Move bl1; Cube aux; static const uint64_t udmask = (1<<U) | (1<<U2) | (1<<U3) | @@ -1174,7 +1195,6 @@ estimate_optimal_HTM(DfsArg *arg) ret = -1; target = arg->d - arg->current_alg->len; - bl1 = base_move(arg->last1); arg->inverse = (Cube){0}; arg->badmovesinv = 0; arg->badmoves = 0; @@ -1204,17 +1224,17 @@ estimate_optimal_HTM(DfsArg *arg) } /* Inverse probing */ - arg->inverse = inverse_cube(arg->cube); - if ((bl1 != U && bl1 != D) || (arg->ed->inverse_ud == -1)) { - arg->ed->inverse_ud = ptableval(&pd_khuge_HTM, arg->inverse); + aux = arg->inverse = inverse_cube(arg->cube); + if (!((1<<arg->last1) & udmask) || (arg->ed->inverse_ud == -1)) { + arg->ed->inverse_ud = ptableval(&pd_khuge_HTM, aux); } UPDATECHECKSTOP(ret, arg->ed->inverse_ud, target); - if ((bl1 != F && bl1 != B) || (arg->ed->inverse_fb == -1)) { + if (!((1<<arg->last1) & fbmask) || (arg->ed->inverse_fb == -1)) { aux = apply_trans(fd, arg->inverse); arg->ed->inverse_fb = ptableval(&pd_khuge_HTM, aux); } UPDATECHECKSTOP(ret, arg->ed->inverse_fb, target); - if ((bl1 != R && bl1 != L) || (arg->ed->inverse_rl == -1)) { + if (!((1<<arg->last1) & rlmask) || (arg->ed->inverse_rl == -1)) { aux = apply_trans(rf, arg->inverse); arg->ed->inverse_rl = ptableval(&pd_khuge_HTM, aux); } @@ -1244,6 +1264,98 @@ estimate_optimal_HTM(DfsArg *arg) return arg->ed->oldret = ret; } +static int +estimate_light_HTM(DfsArg *arg) +{ + int target, ret; + Cube aux; + + static const uint64_t udmask = (1<<U) | (1<<U2) | (1<<U3) | + (1<<D) | (1<<D2) | (1<<D3); + static const uint64_t rlmask = (1<<R) | (1<<R2) | (1<<R3) | + (1<<L) | (1<<L2) | (1<<L3); + static const uint64_t fbmask = (1<<F) | (1<<F2) | (1<<F3) | + (1<<B) | (1<<B2) | (1<<B3); + static const uint64_t htmask = (1<<U2) | (1<<D2) | + (1<<R2) | (1<<L2) | + (1<<F2) | (1<<B2); + + ret = -1; + target = arg->d - arg->current_alg->len; + arg->inverse = (Cube){0}; + arg->badmovesinv = 0; + arg->badmoves = 0; + + /* Corners */ + arg->ed->corners = ptableval(&pd_corners_HTM, arg->cube); + UPDATECHECKSTOP(ret, arg->ed->corners, target); + + /* Normal probing */ + arg->ed->normal_ud = ptableval(&pd_drud_sym16_HTM, arg->cube); + UPDATECHECKSTOP(ret, arg->ed->normal_ud, target); + aux = apply_trans(fd, arg->cube); + arg->ed->normal_fb = ptableval(&pd_drud_sym16_HTM, aux); + UPDATECHECKSTOP(ret, arg->ed->normal_fb, target); + aux = apply_trans(rf, arg->cube); + arg->ed->normal_rl = ptableval(&pd_drud_sym16_HTM, aux); + UPDATECHECKSTOP(ret, arg->ed->normal_rl, target); + + /* If ret == 0, it's solved (corners + triple slice solved) */ + if (ret == 0) + return 0; + + /* Michel de Bondt's trick*/ + if (arg->ed->normal_ud == arg->ed->normal_fb && + arg->ed->normal_fb == arg->ed->normal_rl) { + UPDATECHECKSTOP(ret, arg->ed->normal_ud + 1, target); + } + + /* Inverse probing */ + if (!((1<<arg->last1) & htmask)) { + aux = arg->inverse = inverse_cube(arg->cube); + if (!((1<<arg->last1) & udmask) || (arg->ed->inverse_ud==-1)) { + arg->ed->inverse_ud = + ptableval(&pd_drud_sym16_HTM, aux); + } + UPDATECHECKSTOP(ret, arg->ed->inverse_ud, target); + if (!((1<<arg->last1) & fbmask) || (arg->ed->inverse_fb==-1)) { + aux = apply_trans(fd, arg->inverse); + arg->ed->inverse_fb = + ptableval(&pd_drud_sym16_HTM, aux); + } + UPDATECHECKSTOP(ret, arg->ed->inverse_fb, target); + if (!((1<<arg->last1) & rlmask) || (arg->ed->inverse_rl==-1)) { + aux = apply_trans(rf, arg->inverse); + arg->ed->inverse_rl = + ptableval(&pd_drud_sym16_HTM, aux); + } + UPDATECHECKSTOP(ret, arg->ed->inverse_rl, target); + } + + /* Michel de Bondt's trick*/ + if (arg->ed->inverse_ud == arg->ed->inverse_fb && + arg->ed->inverse_fb == arg->ed->inverse_rl) { + UPDATECHECKSTOP(ret, arg->ed->inverse_ud + 1, target); + } + + /* nxopt trick + half turn trick */ + if (arg->ed->normal_ud == target) + arg->badmovesinv |= udmask | htmask; + if (arg->ed->normal_fb == target) + arg->badmovesinv |= fbmask | htmask; + if (arg->ed->normal_rl == target) + arg->badmovesinv |= rlmask | htmask; + + if (arg->ed->inverse_ud == target) + arg->badmoves |= udmask | htmask; + if (arg->ed->inverse_fb == target) + arg->badmoves |= fbmask | htmask; + if (arg->ed->inverse_rl == target) + arg->badmoves |= rlmask | htmask; + + return arg->ed->oldret = ret; +} + static bool always_valid(Alg *alg) {