nissy-fmc

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

commit c8bb7b7f573f951ff3b80eef80d0d26aa4f88f58
parent 63e4e8d1a1f91304e406017148ee8f22a58b3299
Author: Sebastiano Tronto <sebastiano@tronto.net>
Date:   Fri, 21 Apr 2023 20:47:34 +0200

New file split

Diffstat:
Msrc/main.c | 4++--
Msrc/nissy.c | 751++-----------------------------------------------------------------------------
Msrc/nissy.h | 4++--
Asrc/solve.c | 242+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/solve.h | 26++++++++++++++++++++++++++
Asrc/steps.c | 488+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/steps.h | 2++
7 files changed, 773 insertions(+), 744 deletions(-)

diff --git a/src/main.c b/src/main.c @@ -10,7 +10,7 @@ main(int argc, char *argv[]) { char sols[99999]; - init_nissy(); + nissy_init(); if (argc != 6) { fprintf(stderr, "Not enough arguments given\n"); @@ -23,7 +23,7 @@ main(int argc, char *argv[]) char *type = argv[4]; char *scramble = argv[5]; - switch (solve(step, trans, d, type, scramble, sols)) { + switch (nissy_solve(step, trans, d, type, scramble, sols)) { case 1: fprintf(stderr, "Error parsing step: %s\n", step); return -1; diff --git a/src/nissy.c b/src/nissy.c @@ -3,716 +3,8 @@ #include "cube.h" #include "coord.h" - -#define MAX_N_COORD 3 - -typedef enum { NORMAL, INVERSE, NISS } SolutionType; -typedef struct { uint64_t val; Trans t; } CubeState; -typedef struct { - char * shortname; - Moveset * moveset; - Coordinate * coord[MAX_N_COORD]; -} Step; -typedef struct { - Cube * cube; - CubeState state[MAX_N_COORD]; - Step * s; - Trans t; - SolutionType st; - char ** sol; - int d; - int bound; - bool niss; - bool has_nissed; - Move last[2]; - Move lastinv[2]; - Alg * current_alg; -} DfsArg; - -static void append_sol(DfsArg *arg); -static bool allowed_next(Move move, Move l0, Move l1); -static void get_state(Coordinate *coord[], Cube *cube, CubeState *state); -static void copy_dfsarg(DfsArg *src, DfsArg *dst); -static int lower_bound(Coordinate *coord[], CubeState *state); -static void dfs(DfsArg *arg); -static void dfs_niss(DfsArg *arg); -static bool dfs_move_checkstop(DfsArg *arg); -static bool niss_makes_sense(DfsArg *arg); - -static bool moveset_HTM(Move m); -static bool moveset_eofb(Move m); -static bool moveset_drud(Move m); -static bool moveset_htr(Move m); - -static uint64_t index_eofb(Cube *cube); -static void invindex_eofb(uint64_t ind, Cube *ret); -Indexer i_eofb = { - .n = POW2TO11, - .index = index_eofb, - .to_cube = invindex_eofb, -}; - -static uint64_t index_coud(Cube *cube); -static void invindex_coud(uint64_t ind, Cube *ret); -Indexer i_coud = { - .n = POW3TO7, - .index = index_coud, - .to_cube = invindex_coud, -}; - -static uint64_t index_cp(Cube *cube); -static void invindex_cp(uint64_t ind, Cube *ret); -Indexer i_cp = { - .n = FACTORIAL8, - .index = index_cp, - .to_cube = invindex_cp, -}; - -static uint64_t index_epos(Cube *cube); -static void invindex_epos(uint64_t ind, Cube *ret); -Indexer i_epos = { - .n = BINOM12ON4, - .index = index_epos, - .to_cube = invindex_epos, -}; - -static uint64_t index_epe(Cube *cube); -static void invindex_epe(uint64_t ind, Cube *ret); -Indexer i_epe = { - .n = FACTORIAL4, - .index = index_epe, - .to_cube = invindex_epe, -}; - -static uint64_t index_eposepe(Cube *cube); -static void invindex_eposepe(uint64_t ind, Cube *ret); -Indexer i_eposepe = { - .n = BINOM12ON4 * FACTORIAL4, - .index = index_eposepe, - .to_cube = invindex_eposepe, -}; - -static uint64_t index_epud(Cube *cube); -static void invindex_epud(uint64_t ind, Cube *ret); -Indexer i_epud = { - .n = FACTORIAL8, - .index = index_epud, - .to_cube = invindex_epud, -}; - -Coordinate coord_eofb = { - .name = "eofb", - .type = COMP_COORD, - .i = {&i_eofb, NULL}, - .moveset = moveset_HTM, -}; - -Coordinate coord_coud = { - .name = "coud", - .type = COMP_COORD, - .i = {&i_coud, NULL}, - .moveset = moveset_HTM, -}; - -Coordinate coord_cp = { - .name = "cp", - .type = COMP_COORD, - .i = {&i_cp, NULL}, - .moveset = moveset_HTM, -}; - -Coordinate coord_epos = { - .name = "epos", - .type = COMP_COORD, - .i = {&i_epos, NULL}, - .moveset = moveset_HTM, -}; - -Coordinate coord_epe = { - .name = "epe", - .type = COMP_COORD, - .i = {&i_epe, NULL}, - .moveset = moveset_HTM, -}; - -Coordinate coord_eposepe = { - .name = "eposepe", - .type = COMP_COORD, - .i = {&i_eposepe, NULL}, - .moveset = moveset_HTM, -}; - -Coordinate coord_epud = { - .name = "epud", - .type = COMP_COORD, - .i = {&i_epud, NULL}, - .moveset = moveset_drud, -}; - -Coordinate coord_eofbepos = { - .name = "eofbepos", - .type = COMP_COORD, - .i = {&i_epos, &i_eofb, NULL}, - .moveset = moveset_HTM, -}; - -Coordinate coord_eofbepos_sym16 = { - .name = "eofbepos_sym16", - .type = SYM_COORD, - .base = {&coord_eofbepos, NULL}, - .tgrp = &tgrp_udfix, - .moveset = moveset_HTM, -}; - -Coordinate coord_cp_sym16 = { - .name = "cp_sym16", - .type = SYM_COORD, - .base = {&coord_cp, NULL}, - .tgrp = &tgrp_udfix, - .moveset = moveset_HTM, -}; - -Coordinate coord_drud_sym16 = { - .name = "drud_sym16", - .type = SYMCOMP_COORD, - .base = {&coord_eofbepos_sym16, &coord_coud}, - .moveset = moveset_HTM, -}; - -Coordinate coord_drudfin_noE_sym16 = { - .name = "drudfin_noE_sym16", - .type = SYMCOMP_COORD, - .base = {&coord_cp_sym16, &coord_epud}, - .moveset = moveset_drud, -}; - -Coordinate *coordinates[] = { - &coord_eofb, &coord_coud, &coord_cp, &coord_epos, &coord_epe, - &coord_eposepe, &coord_epud, &coord_eofbepos, &coord_eofbepos_sym16, - &coord_drud_sym16, &coord_cp_sym16, &coord_drudfin_noE_sym16, - NULL -}; - -Step eofb_HTM = { - .shortname = "eofb", - .moveset = moveset_HTM, - .coord = {&coord_eofb, NULL}, -}; - -Step drud_HTM = { - .shortname = "drud", - .moveset = moveset_HTM, - .coord = {&coord_drud_sym16, NULL}, -}; - -Step drfin_drud = { - .shortname = "drudfin", - .moveset = moveset_drud, - .coord = {&coord_drudfin_noE_sym16, &coord_epe, NULL}, -}; - -Step *steps[] = {&eofb_HTM, &drud_HTM, &drfin_drud, NULL}; - -static bool -moveset_HTM(Move m) -{ - return m >= U && m <= B3; -} - -static 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); -} - -static 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); -} - -static bool -moveset_htr(Move m) -{ - return moveset_HTM(m) && m == base_move(m) + 1; -} - -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 int -perm_to_index(int *a, int n) -{ - int i, j, c, ret = 0; - - 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 void -index_to_perm(int p, int n, int *r) -{ - int a[n]; - 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); - } -} - -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 int -subset_to_index(int *a, int n, int k) -{ - int i, ret = 0; - - 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 -index_to_subset(int s, int n, int k, int *r) -{ - int i, j, v; - - 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 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 void -int_to_digit_array(int a, int b, int n, int *r) -{ - int i; - - 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; - - 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 -perm_sign(int *a, int n) -{ - int i, j, ret = 0; - - for (i = 0; i < n; i++) - for (j = i+1; j < n; j++) - ret += (a[i] > a[j]) ? 1 : 0; - - return ret % 2; -} - -static uint64_t -index_eofb(Cube *cube) -{ - return (uint64_t)digit_array_to_int(cube->eo, 11, 2); -} - -static uint64_t -index_coud(Cube *cube) -{ - return (uint64_t)digit_array_to_int(cube->co, 7, 3); -} - -static uint64_t -index_cp(Cube *cube) -{ - return (uint64_t)perm_to_index(cube->cp, 8); -} - -static uint64_t -index_epe(Cube *cube) -{ - int i, e[4]; - - for (i = 0; i < 4; i++) - e[i] = cube->ep[i+8] - 8; - - return (uint64_t)perm_to_index(e, 4); -} - -static uint64_t -index_epud(Cube *cube) -{ - return (uint64_t)perm_to_index(cube->ep, 8); -} - -static uint64_t -index_epos(Cube *cube) -{ - int i, a[12]; - - for (i = 0; i < 12; i++) - a[i] = (cube->ep[i] < 8) ? 0 : 1; - - return (uint64_t)subset_to_index(a, 12, 4); -} - -static uint64_t -index_eposepe(Cube *cube) -{ - int i, j, e[4]; - uint64_t epos, epe; - - epos = (uint64_t)index_epos(cube); - for (i = 0, j = 0; i < 12; i++) - if (cube->ep[i] >= 8) - e[j++] = cube->ep[i] - 8; - epe = (uint64_t)perm_to_index(e, 4); - - return epos * FACTORIAL4 + epe; -} - -static void -invindex_eofb(uint64_t ind, Cube *cube) -{ - int_to_sum_zero_array(ind, 2, 12, cube->eo); -} - -static void -invindex_coud(uint64_t ind, Cube *cube) -{ - int_to_sum_zero_array(ind, 3, 8, cube->co); -} - -static void -invindex_cp(uint64_t ind, Cube *cube) -{ - index_to_perm(ind, 8, cube->cp); -} - -static void -invindex_epe(uint64_t ind, Cube *cube) -{ - int i; - - index_to_perm(ind, 4, &cube->ep[8]); - for (i = 0; i < 4; i++) - cube->ep[i+8] += 8; -} - -static void -invindex_epud(uint64_t ind, Cube *cube) -{ - index_to_perm(ind, 8, cube->ep); -} - -static void -invindex_epos(uint64_t ind, Cube *cube) -{ - int i, j, k; - - index_to_subset(ind, 12, 4, cube->ep); - for (i = 0, j = 0, k = 8; i < 12; i++) - if (cube->ep[i] == 0) - cube->ep[i] = j++; - else - cube->ep[i] = k++; -} - -static void -invindex_eposepe(uint64_t ind, Cube *cube) -{ - int i, j, k, e[4]; - uint64_t epos, epe; - - epos = ind / FACTORIAL4; - epe = ind % FACTORIAL4; - - index_to_subset(epos, 12, 4, cube->ep); - index_to_perm(epe, 4, e); - - for (i = 0, j = 0, k = 0; i < 12; i++) - if (cube->ep[i] == 0) - cube->ep[i] = j++; - else - cube->ep[i] = e[k++] + 8; -} - -static void -append_sol(DfsArg *arg) -{ - Alg alg; - int i, n; - - copy_alg(arg->current_alg, &alg); - transform_alg(inverse_trans(arg->t), &alg); - - if (arg->st == INVERSE) - for (i = 0; i < alg.len; i++) - alg.inv[i] = true; - - n = alg_string(&alg, *arg->sol); - (*arg->sol)[n] = '\n'; - (*arg->sol)[n+1] = 0; - *arg->sol += (n+1); -} - -static bool -allowed_next(Move m, Move l0, Move l1) -{ - bool p, q, allowed, order; - - p = l0 != NULLMOVE && base_move(l0) == base_move(m); - q = l1 != NULLMOVE && base_move(l1) == base_move(m); - allowed = !(p || (commute(l0, l1) && q)); - order = !commute(l0, m) || l0 < m; - - return allowed && order; -} - -void -get_state(Coordinate *coord[], Cube *cube, CubeState *state) -{ - int i; - - for (i = 0; coord[i] != NULL; i++) - state[i].val = index_coord(coord[i], cube, &state[i].t); -} - -static void -copy_dfsarg(DfsArg *src, DfsArg *dst) -{ - int i; - - dst->cube = src->cube; - dst->s = src->s; - dst->t = src->t; - dst->st = src->st; - dst->d = src->d; - dst->bound = src->bound; /* In theory not needed */ - dst->niss = src->niss; - dst->has_nissed = src->has_nissed; - dst->sol = src->sol; - dst->current_alg = src->current_alg; - - for (i = 0; i < 2; i++) { - dst->last[i] = src->last[i]; - dst->lastinv[i] = src->lastinv[i]; - } - - for (i = 0; src->s->coord[i] != NULL; i++) { - dst->state[i].val = src->state[i].val; - dst->state[i].t = src->state[i].t; - } -} - -static int -lower_bound(Coordinate *coord[], CubeState *state) -{ - int i, ret; - - ret = -1; - for (i = 0; coord[i] != NULL; i++) - ret = MAX(ret, ptableval(coord[i], state[i].val)); - - return ret; -} - -static void -dfs(DfsArg *arg) -{ - Move m; - DfsArg newarg; - bool len, niss; - - if (dfs_move_checkstop(arg)) - return; - - if (arg->bound == 0) { - len = arg->current_alg->len == arg->d; - niss = !(arg->st == NISS) || arg->has_nissed; - if (len && niss) - append_sol(arg); - return; - } - - for (m = U; m <= B3; m++) { - if (!arg->s->moveset(m)) - continue; - if (allowed_next(m, arg->last[0], arg->last[1])) { - copy_dfsarg(arg, &newarg); - newarg.last[1] = arg->last[0]; - newarg.last[0] = m; - append_move(arg->current_alg, m, newarg.niss); - dfs(&newarg); - arg->current_alg->len--; - } - } - - if (niss_makes_sense(arg)) - dfs_niss(arg); -} - -static void -dfs_niss(DfsArg *arg) -{ - int i; - DfsArg newarg; - Cube c, newcube; - Move aux; - - copy_dfsarg(arg, &newarg); - - /* Invert current alg and scramble */ - newarg.cube = &newcube; - - make_solved(newarg.cube); - apply_alg(arg->current_alg, newarg.cube); - invert_cube(newarg.cube); - - copy_cube(arg->cube, &c); - invert_cube(&c); - compose(&c, newarg.cube); - - /* New indexes */ - get_state(newarg.s->coord, newarg.cube, newarg.state); - - /* Swap last moves */ - for (i = 0; i < 2; i++) { - aux = newarg.last[i]; - newarg.last[i] = newarg.lastinv[i]; - newarg.lastinv[i] = aux; - } - - newarg.niss = !(arg->niss); - newarg.has_nissed = true; - - dfs(&newarg); -} - -static bool -dfs_move_checkstop(DfsArg *arg) -{ - int i; - Move mm; - Trans tt = uf; /* Avoid uninitialized warning */ - - /* Moving */ - if (arg->last[0] != NULLMOVE) { - for (i = 0; arg->s->coord[i] != NULL; i++) { - mm = transform_move(arg->state[i].t, arg->last[0]); - arg->state[i].val = move_coord(arg->s->coord[i], - mm, arg->state[i].val, &tt); - arg->state[i].t = transform_trans(tt, arg->state[i].t); - } - } - - /* Computing bound for coordinates */ - arg->bound = lower_bound(arg->s->coord, arg->state); - if (arg->st == NISS && !arg->niss) - arg->bound = MIN(1, arg->bound); - - return arg->bound + arg->current_alg->len > arg->d ; -} - -static bool -niss_makes_sense(DfsArg *arg) -{ - Cube testcube; - CubeState state[MAX_N_COORD]; - - if (arg->niss || !(arg->st == NISS) || arg->current_alg->len == 0) - return false; - - make_solved(&testcube); - apply_move(inverse_move(arg->last[0]), &testcube); - get_state(arg->s->coord, &testcube, state); - - return lower_bound(arg->s->coord, state) > 0; -} +#include "solve.h" +#include "steps.h" static bool set_step(char *str, Step **step) @@ -768,45 +60,24 @@ set_trans(char *str, Trans *t) } int -solve(char *step, char *trans, int d, char *type, char *scramble, char *sol) +nissy_solve(char *step, char *trans, int d, char *type, char *scramble, char *sol) { - Alg alg; Cube c; - DfsArg arg; - - arg.niss = false; - arg.has_nissed = false; - arg.last[0] = NULLMOVE; - arg.last[1] = NULLMOVE; - arg.lastinv[0] = NULLMOVE; - arg.lastinv[1] = NULLMOVE; - - alg.len = 0; - arg.current_alg = &alg; - - arg.d = d; - arg.sol = &sol; - - if (!set_step(step, &arg.s)) return 1; - if (!set_trans(trans, &arg.t)) return 2; - if (!set_solutiontype(type, &arg.st)) return 4; + Step *s; + Trans t; + SolutionType st; make_solved(&c); - + if (!set_step(step, &s)) return 1; + if (!set_trans(trans, &t)) return 2; + if (!set_solutiontype(type, &st)) return 4; if (!apply_scramble(scramble, &c)) return 5; - if (arg.st == INVERSE) - invert_cube(&c); - apply_trans(arg.t, &c); - arg.cube = &c; - get_state(arg.s->coord, arg.cube, arg.state); - - dfs(&arg); - return 0; + return solve(s, t, d, st, &c, sol); } void -init_nissy() +nissy_init() { int i; diff --git a/src/nissy.h b/src/nissy.h @@ -1,5 +1,5 @@ /* TODO: this should take a char *buffer as parameter, not read files */ -void init_nissy(); +void nissy_init(); /* Returns 0 on success, 1-based index of bad arg on failure */ -int solve(char *step, char *trans, int d, char *type, char *scr, char *sol); +int nissy_solve(char *s, char *trans, int d, char *type, char *scr, char *sol); diff --git a/src/solve.c b/src/solve.c @@ -0,0 +1,242 @@ +#include <string.h> +#include <inttypes.h> + +#include "cube.h" +#include "coord.h" +#include "solve.h" + +static void append_sol(DfsArg *arg); +static bool allowed_next(Move move, Move l0, Move l1); +static void get_state(Coordinate *coord[], Cube *cube, CubeState *state); +static void copy_dfsarg(DfsArg *src, DfsArg *dst); +static int lower_bound(Coordinate *coord[], CubeState *state); +static void dfs(DfsArg *arg); +static void dfs_niss(DfsArg *arg); +static bool dfs_move_checkstop(DfsArg *arg); +static bool niss_makes_sense(DfsArg *arg); + +static void +append_sol(DfsArg *arg) +{ + Alg alg; + int i, n; + + copy_alg(arg->current_alg, &alg); + transform_alg(inverse_trans(arg->t), &alg); + + if (arg->st == INVERSE) + for (i = 0; i < alg.len; i++) + alg.inv[i] = true; + + n = alg_string(&alg, *arg->sol); + (*arg->sol)[n] = '\n'; + (*arg->sol)[n+1] = 0; + *arg->sol += (n+1); +} + +static bool +allowed_next(Move m, Move l0, Move l1) +{ + bool p, q, allowed, order; + + p = l0 != NULLMOVE && base_move(l0) == base_move(m); + q = l1 != NULLMOVE && base_move(l1) == base_move(m); + allowed = !(p || (commute(l0, l1) && q)); + order = !commute(l0, m) || l0 < m; + + return allowed && order; +} + +void +get_state(Coordinate *coord[], Cube *cube, CubeState *state) +{ + int i; + + for (i = 0; coord[i] != NULL; i++) + state[i].val = index_coord(coord[i], cube, &state[i].t); +} + +static void +copy_dfsarg(DfsArg *src, DfsArg *dst) +{ + int i; + + dst->cube = src->cube; + dst->s = src->s; + dst->t = src->t; + dst->st = src->st; + dst->d = src->d; + dst->bound = src->bound; /* In theory not needed */ + dst->niss = src->niss; + dst->has_nissed = src->has_nissed; + dst->sol = src->sol; + dst->current_alg = src->current_alg; + + for (i = 0; i < 2; i++) { + dst->last[i] = src->last[i]; + dst->lastinv[i] = src->lastinv[i]; + } + + for (i = 0; src->s->coord[i] != NULL; i++) { + dst->state[i].val = src->state[i].val; + dst->state[i].t = src->state[i].t; + } +} + +static int +lower_bound(Coordinate *coord[], CubeState *state) +{ + int i, ret; + + ret = -1; + for (i = 0; coord[i] != NULL; i++) + ret = MAX(ret, ptableval(coord[i], state[i].val)); + + return ret; +} + +static void +dfs(DfsArg *arg) +{ + Move m; + DfsArg newarg; + bool len, niss; + + if (dfs_move_checkstop(arg)) + return; + + if (arg->bound == 0) { + len = arg->current_alg->len == arg->d; + niss = !(arg->st == NISS) || arg->has_nissed; + if (len && niss) + append_sol(arg); + return; + } + + for (m = U; m <= B3; m++) { + if (!arg->s->moveset(m)) + continue; + if (allowed_next(m, arg->last[0], arg->last[1])) { + copy_dfsarg(arg, &newarg); + newarg.last[1] = arg->last[0]; + newarg.last[0] = m; + append_move(arg->current_alg, m, newarg.niss); + dfs(&newarg); + arg->current_alg->len--; + } + } + + if (niss_makes_sense(arg)) + dfs_niss(arg); +} + +static void +dfs_niss(DfsArg *arg) +{ + int i; + DfsArg newarg; + Cube c, newcube; + Move aux; + + copy_dfsarg(arg, &newarg); + + /* Invert current alg and scramble */ + newarg.cube = &newcube; + + make_solved(newarg.cube); + apply_alg(arg->current_alg, newarg.cube); + invert_cube(newarg.cube); + + copy_cube(arg->cube, &c); + invert_cube(&c); + compose(&c, newarg.cube); + + /* New indexes */ + get_state(newarg.s->coord, newarg.cube, newarg.state); + + /* Swap last moves */ + for (i = 0; i < 2; i++) { + aux = newarg.last[i]; + newarg.last[i] = newarg.lastinv[i]; + newarg.lastinv[i] = aux; + } + + newarg.niss = !(arg->niss); + newarg.has_nissed = true; + + dfs(&newarg); +} + +static bool +dfs_move_checkstop(DfsArg *arg) +{ + int i; + Move mm; + Trans tt = uf; /* Avoid uninitialized warning */ + + /* Moving */ + if (arg->last[0] != NULLMOVE) { + for (i = 0; arg->s->coord[i] != NULL; i++) { + mm = transform_move(arg->state[i].t, arg->last[0]); + arg->state[i].val = move_coord(arg->s->coord[i], + mm, arg->state[i].val, &tt); + arg->state[i].t = transform_trans(tt, arg->state[i].t); + } + } + + /* Computing bound for coordinates */ + arg->bound = lower_bound(arg->s->coord, arg->state); + if (arg->st == NISS && !arg->niss) + arg->bound = MIN(1, arg->bound); + + return arg->bound + arg->current_alg->len > arg->d ; +} + +static bool +niss_makes_sense(DfsArg *arg) +{ + Cube testcube; + CubeState state[MAX_N_COORD]; + + if (arg->niss || !(arg->st == NISS) || arg->current_alg->len == 0) + return false; + + make_solved(&testcube); + apply_move(inverse_move(arg->last[0]), &testcube); + get_state(arg->s->coord, &testcube, state); + + return lower_bound(arg->s->coord, state) > 0; +} + +int +solve(Step *s, Trans t, int d, SolutionType st, Cube *c, char *sol) +{ + Alg alg; + DfsArg arg; + + arg.niss = false; + arg.has_nissed = false; + arg.last[0] = NULLMOVE; + arg.last[1] = NULLMOVE; + arg.lastinv[0] = NULLMOVE; + arg.lastinv[1] = NULLMOVE; + + alg.len = 0; + arg.current_alg = &alg; + + arg.cube = c; + arg.s = s; + arg.t = t; + arg.st = st; + + arg.d = d; + arg.sol = &sol; + + if (arg.st == INVERSE) + invert_cube(c); + apply_trans(arg.t, c); + get_state(arg.s->coord, arg.cube, arg.state); + + dfs(&arg); + return 0; +} diff --git a/src/solve.h b/src/solve.h @@ -0,0 +1,26 @@ +#define MAX_N_COORD 3 + +typedef enum { NORMAL, INVERSE, NISS } SolutionType; +typedef struct { uint64_t val; Trans t; } CubeState; +typedef struct { + char * shortname; + Moveset * moveset; + Coordinate * coord[MAX_N_COORD]; +} Step; +typedef struct { + Cube * cube; + CubeState state[MAX_N_COORD]; + Step * s; + Trans t; + SolutionType st; + char ** sol; + int d; + int bound; + bool niss; + bool has_nissed; + Move last[2]; + Move lastinv[2]; + Alg * current_alg; +} DfsArg; + +int solve(Step *, Trans, int, SolutionType, Cube *, char *); diff --git a/src/steps.c b/src/steps.c @@ -0,0 +1,488 @@ +#include <string.h> +#include <inttypes.h> + +#include "cube.h" +#include "coord.h" +#include "solve.h" + +static bool moveset_HTM(Move m); +static bool moveset_eofb(Move m); +static bool moveset_drud(Move m); +static bool moveset_htr(Move m); + +static uint64_t index_eofb(Cube *cube); +static void invindex_eofb(uint64_t ind, Cube *ret); +Indexer i_eofb = { + .n = POW2TO11, + .index = index_eofb, + .to_cube = invindex_eofb, +}; + +static uint64_t index_coud(Cube *cube); +static void invindex_coud(uint64_t ind, Cube *ret); +Indexer i_coud = { + .n = POW3TO7, + .index = index_coud, + .to_cube = invindex_coud, +}; + +static uint64_t index_cp(Cube *cube); +static void invindex_cp(uint64_t ind, Cube *ret); +Indexer i_cp = { + .n = FACTORIAL8, + .index = index_cp, + .to_cube = invindex_cp, +}; + +static uint64_t index_epos(Cube *cube); +static void invindex_epos(uint64_t ind, Cube *ret); +Indexer i_epos = { + .n = BINOM12ON4, + .index = index_epos, + .to_cube = invindex_epos, +}; + +static uint64_t index_epe(Cube *cube); +static void invindex_epe(uint64_t ind, Cube *ret); +Indexer i_epe = { + .n = FACTORIAL4, + .index = index_epe, + .to_cube = invindex_epe, +}; + +static uint64_t index_eposepe(Cube *cube); +static void invindex_eposepe(uint64_t ind, Cube *ret); +Indexer i_eposepe = { + .n = BINOM12ON4 * FACTORIAL4, + .index = index_eposepe, + .to_cube = invindex_eposepe, +}; + +static uint64_t index_epud(Cube *cube); +static void invindex_epud(uint64_t ind, Cube *ret); +Indexer i_epud = { + .n = FACTORIAL8, + .index = index_epud, + .to_cube = invindex_epud, +}; + +Coordinate coord_eofb = { + .name = "eofb", + .type = COMP_COORD, + .i = {&i_eofb, NULL}, + .moveset = moveset_HTM, +}; + +Coordinate coord_coud = { + .name = "coud", + .type = COMP_COORD, + .i = {&i_coud, NULL}, + .moveset = moveset_HTM, +}; + +Coordinate coord_cp = { + .name = "cp", + .type = COMP_COORD, + .i = {&i_cp, NULL}, + .moveset = moveset_HTM, +}; + +Coordinate coord_epos = { + .name = "epos", + .type = COMP_COORD, + .i = {&i_epos, NULL}, + .moveset = moveset_HTM, +}; + +Coordinate coord_epe = { + .name = "epe", + .type = COMP_COORD, + .i = {&i_epe, NULL}, + .moveset = moveset_HTM, +}; + +Coordinate coord_eposepe = { + .name = "eposepe", + .type = COMP_COORD, + .i = {&i_eposepe, NULL}, + .moveset = moveset_HTM, +}; + +Coordinate coord_epud = { + .name = "epud", + .type = COMP_COORD, + .i = {&i_epud, NULL}, + .moveset = moveset_drud, +}; + +Coordinate coord_eofbepos = { + .name = "eofbepos", + .type = COMP_COORD, + .i = {&i_epos, &i_eofb, NULL}, + .moveset = moveset_HTM, +}; + +Coordinate coord_eofbepos_sym16 = { + .name = "eofbepos_sym16", + .type = SYM_COORD, + .base = {&coord_eofbepos, NULL}, + .tgrp = &tgrp_udfix, + .moveset = moveset_HTM, +}; + +Coordinate coord_cp_sym16 = { + .name = "cp_sym16", + .type = SYM_COORD, + .base = {&coord_cp, NULL}, + .tgrp = &tgrp_udfix, + .moveset = moveset_HTM, +}; + +Coordinate coord_drud_sym16 = { + .name = "drud_sym16", + .type = SYMCOMP_COORD, + .base = {&coord_eofbepos_sym16, &coord_coud}, + .moveset = moveset_HTM, +}; + +Coordinate coord_drudfin_noE_sym16 = { + .name = "drudfin_noE_sym16", + .type = SYMCOMP_COORD, + .base = {&coord_cp_sym16, &coord_epud}, + .moveset = moveset_drud, +}; + +Coordinate *coordinates[] = { + &coord_eofb, &coord_coud, &coord_cp, &coord_epos, &coord_epe, + &coord_eposepe, &coord_epud, &coord_eofbepos, &coord_eofbepos_sym16, + &coord_drud_sym16, &coord_cp_sym16, &coord_drudfin_noE_sym16, + NULL +}; + +Step eofb_HTM = { + .shortname = "eofb", + .moveset = moveset_HTM, + .coord = {&coord_eofb, NULL}, +}; + +Step drud_HTM = { + .shortname = "drud", + .moveset = moveset_HTM, + .coord = {&coord_drud_sym16, NULL}, +}; + +Step drfin_drud = { + .shortname = "drudfin", + .moveset = moveset_drud, + .coord = {&coord_drudfin_noE_sym16, &coord_epe, NULL}, +}; + +Step *steps[] = {&eofb_HTM, &drud_HTM, &drfin_drud, NULL}; + +static bool +moveset_HTM(Move m) +{ + return m >= U && m <= B3; +} + +static 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); +} + +static 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); +} + +static bool +moveset_htr(Move m) +{ + return moveset_HTM(m) && m == base_move(m) + 1; +} + +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 int +perm_to_index(int *a, int n) +{ + int i, j, c, ret = 0; + + 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 void +index_to_perm(int p, int n, int *r) +{ + int a[n]; + 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); + } +} + +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 int +subset_to_index(int *a, int n, int k) +{ + int i, ret = 0; + + 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 +index_to_subset(int s, int n, int k, int *r) +{ + int i, j, v; + + 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 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 void +int_to_digit_array(int a, int b, int n, int *r) +{ + int i; + + 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; + + 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 +perm_sign(int *a, int n) +{ + int i, j, ret = 0; + + for (i = 0; i < n; i++) + for (j = i+1; j < n; j++) + ret += (a[i] > a[j]) ? 1 : 0; + + return ret % 2; +} + +static uint64_t +index_eofb(Cube *cube) +{ + return (uint64_t)digit_array_to_int(cube->eo, 11, 2); +} + +static uint64_t +index_coud(Cube *cube) +{ + return (uint64_t)digit_array_to_int(cube->co, 7, 3); +} + +static uint64_t +index_cp(Cube *cube) +{ + return (uint64_t)perm_to_index(cube->cp, 8); +} + +static uint64_t +index_epe(Cube *cube) +{ + int i, e[4]; + + for (i = 0; i < 4; i++) + e[i] = cube->ep[i+8] - 8; + + return (uint64_t)perm_to_index(e, 4); +} + +static uint64_t +index_epud(Cube *cube) +{ + return (uint64_t)perm_to_index(cube->ep, 8); +} + +static uint64_t +index_epos(Cube *cube) +{ + int i, a[12]; + + for (i = 0; i < 12; i++) + a[i] = (cube->ep[i] < 8) ? 0 : 1; + + return (uint64_t)subset_to_index(a, 12, 4); +} + +static uint64_t +index_eposepe(Cube *cube) +{ + int i, j, e[4]; + uint64_t epos, epe; + + epos = (uint64_t)index_epos(cube); + for (i = 0, j = 0; i < 12; i++) + if (cube->ep[i] >= 8) + e[j++] = cube->ep[i] - 8; + epe = (uint64_t)perm_to_index(e, 4); + + return epos * FACTORIAL4 + epe; +} + +static void +invindex_eofb(uint64_t ind, Cube *cube) +{ + int_to_sum_zero_array(ind, 2, 12, cube->eo); +} + +static void +invindex_coud(uint64_t ind, Cube *cube) +{ + int_to_sum_zero_array(ind, 3, 8, cube->co); +} + +static void +invindex_cp(uint64_t ind, Cube *cube) +{ + index_to_perm(ind, 8, cube->cp); +} + +static void +invindex_epe(uint64_t ind, Cube *cube) +{ + int i; + + index_to_perm(ind, 4, &cube->ep[8]); + for (i = 0; i < 4; i++) + cube->ep[i+8] += 8; +} + +static void +invindex_epud(uint64_t ind, Cube *cube) +{ + index_to_perm(ind, 8, cube->ep); +} + +static void +invindex_epos(uint64_t ind, Cube *cube) +{ + int i, j, k; + + index_to_subset(ind, 12, 4, cube->ep); + for (i = 0, j = 0, k = 8; i < 12; i++) + if (cube->ep[i] == 0) + cube->ep[i] = j++; + else + cube->ep[i] = k++; +} + +static void +invindex_eposepe(uint64_t ind, Cube *cube) +{ + int i, j, k, e[4]; + uint64_t epos, epe; + + epos = ind / FACTORIAL4; + epe = ind % FACTORIAL4; + + index_to_subset(epos, 12, 4, cube->ep); + index_to_perm(epe, 4, e); + + for (i = 0, j = 0, k = 0; i < 12; i++) + if (cube->ep[i] == 0) + cube->ep[i] = j++; + else + cube->ep[i] = e[k++] + 8; +} diff --git a/src/steps.h b/src/steps.h @@ -0,0 +1,2 @@ +extern Coordinate *coordinates[]; +extern Step *steps[];