nissy-fmc

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

commit a125e69c8ce0a2764b1e50b2dad0a4fa9d141ef4
parent 072c52f9a54144bc9a58cf2855d5b582f8ba7a1a
Author: Sebastiano Tronto <sebastiano@tronto.net>
Date:   Tue,  6 Sep 2022 18:00:40 +0200

Symcoord version of nissy. Interesting idea, but performance are
actually slower. AT THIS STAGE NISSY IS NOT USABLE.

Diffstat:
MMakefile | 5++---
MTODO.md | 111++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Ddoc/nissy.1 | 271-------------------------------------------------------------------------------
Aold/maybe-useful-coord.c | 181+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aold/maybe-useful-steps.c | 1111+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/alg.c | 105++++++++++++++++++++++++++++---------------------------------------------------
Msrc/alg.h | 76+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Msrc/commands.c | 324+++++++++++++++----------------------------------------------------------------
Msrc/commands.h | 194++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/coord.c | 992++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Msrc/coord.h | 246++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Msrc/cube.c | 920+++++++------------------------------------------------------------------------
Msrc/cube.h | 44+++++++++-----------------------------------
Msrc/cubetypes.h | 176+++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/env.c | 2++
Msrc/env.h | 4++--
Msrc/moves.c | 409++++++++++++++-----------------------------------------------------------------
Msrc/moves.h | 20++------------------
Dsrc/pf.c | 95-------------------------------------------------------------------------------
Dsrc/pf.h | 20--------------------
Msrc/pruning.c | 265++++++++++++++++++++++++-------------------------------------------------------
Msrc/pruning.h | 21+++++----------------
Msrc/shell.c | 22+++++++++++++++++++++-
Msrc/solve.c | 485++++++++++++++++++++++++++++++++++++++-----------------------------------------
Msrc/solve.h | 4++--
Msrc/steps.c | 1514+++++++------------------------------------------------------------------------
Msrc/steps.h | 276++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Dsrc/symcoord.c | 687-------------------------------------------------------------------------------
Dsrc/symcoord.h | 17-----------------
Msrc/trans.c | 383+++++++++++++++++++++----------------------------------------------------------
Msrc/trans.h | 36+++++++++++++++++++++---------------
Msrc/utils.c | 14++++++++------
Mwww/download/index.html | 2+-
Mwww/examples/index.html | 2+-
Mwww/index.html | 2+-
Awww/style-2.css | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dwww/style.css | 99-------------------------------------------------------------------------------
37 files changed, 3704 insertions(+), 5536 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,6 +1,6 @@ # See LICENSE file for copyright and license details. -VERSION = 2.0.2 +VERSION = post-2.0.2 PREFIX = /usr/local MANPREFIX = ${PREFIX}/share/man @@ -26,8 +26,7 @@ debug: ${CC} ${DBGFLAGS} -o nissy src/*.c clean: - rm -rf nissy nissy*.exe nissy*.tar.gz - rm doc/nissy.html doc/nissy.pdf + rm -rf nissy nissy*.exe nissy*.tar.gz doc/nissy.html doc/nissy.pdf dist: clean nissy.exe mkdir -p nissy-${VERSION} diff --git a/TODO.md b/TODO.md @@ -3,50 +3,48 @@ This is a list of things that I would like to add or change at some point. It's more of a personal reminder than anything else. -## Version 2.0.2 -### Website -* now gen takes 40 minutes -### Changelog -* Only improved table generation speed, but this required huge changes in - coordinates.c and symcoord.c (+ some minor changes in other parts). - ## For version 2.1 -### Coordinates -* Text (README.md) description of coordinate system with 3 (or 4) types of - coordinates: basic (+ fundamental), sym, composite (consisting of at most - one sym + one or more basic) -* Use this to restructure the coordinate part; maybe fundamental coordinates - do not need to exist??? -* Add also "transform" for every coordinate. For example, for EO and similar - only allow transformations that fix the EO axis. -* Also: "basic" symcoord do not allow trans, composite coordinates assume - the transformation fixes the basic sumcoord -* For each coordinate, manually disallow "bad" moves, or just ignore the error - (probably better to check: low performance cost, detect problems that I might - be overlooking) +### Slow: it is slower than the old nissy 2.0.2 :( +* nxopt's trick (switching to reduce branching) actually saves about 50%! +* Another factor is estimating *while* moving (i.e. do not move all + coordinates if the first one already gives a high value!) +* simplify solve, remove everything that is used only by optimal solvers +* Good compromise: each stepalt offers one of two alternatives: either solve + by simply using pruning tables and moving coordinates, or using a custom + estimator and moving a cube (or fast_cube) and computing coordinates + in the estimator +* is there really no way to use inverse branching trick with current system? +* new file optimal.c with the old solve logic; try first with the simple + cube implementation and the new indexers, if it is still slow change + to fast_cube (intermediate nissy v2.0.2 implementation) ### Changes to Step and Solve -* Revolutionize: do everything based on coordinates, replace Cube with - CubeArray (or just 4 values, so consistency check is super easy); - remove tables for fast inverse. -* No need for most of step data: just solve a list of coordinates - (+ associated pruning tables) -* For steps that accept multiple solved states (e.g. drany): - just find a way to "merge" multiple steps as alternatives; or - offer multiple lists of coordinates as alternatives -* De Bondt's trick: list of 3 coords (as indexes in coord array of the step) - that if evaluated to the same pruning value allow for de bondt's trick. -* NISS: compute inverse based on current use moves just before switching, - using CubeArray; it is not too slow. -### Loading at startup vs dynamically -* Consider moving more things to the initial loading phase (i.e. remove - many of the "initialized" parts) +* remove cube from dfsarg? (i still need to save the scramble somewhere, + but I really only use it in dfs_niss) +* coord.c: all old coordinates (WIP...) +* steps.c: checkers (use coordinates), all stepalt and steps (WIP...) +* commands gen and freemem +* commands.c: twophase, ...? +* Coordinate should have a moveset field? No, at worst there are some garbage + values in mtable, but no risk for errors +### Rotate, not transform, before solving +* solve should re-orient first if needed and not just give up if centers are off ### Documentation +* Document how coordinates and pruning tables work now * Write an examples.md file * More screenshots! ### Tables management -* Check files in tables directory, add command to remove old / extraneous files +* Check files in tables directory automatically remove old / extraneous files * Add checksum to check that tables are generated / downloaded correctly -* Edit download page update instructions to tell what to do when changing tables +### Conditional compiling +* Option to avoid large tables at compile time +* option to avoid multithreading (write a simpler solve for t=1, and also + check if found enough solutions before checking pruning values) +### Technical +* generic option parser +* testing? Maybe just hardcode some examples generated with old nissy +### Commands +* Easy: add option -I (inverse) and -L (linear, like inverse + normal) + to do only linear NISS ## Commands @@ -62,16 +60,21 @@ including e.g. solutions that were not shown because -c) * 5-side solve (for robots) * Block-building steps (cross, roux blocks, ...) * Other common steps (LSE, ...) +* Larger table for drudfin (include epe)? About 1Gb uncompressed, + 500Mb compressed (fallback to noE), 250 compressed + parity trick + (is it doable?) ### Improvements to currently implemented commands -* solve should re-orient first if needed and not just give up if centers are off +* solve multidfs: do multithread by step, not by alternative (this way + if there are multiple alternatives it can make use of more threads) * solve should try up to a small bound without loading the large pruning table + (maybe this is not necessary if loading the table is fast enough) * silent batch mode without >>> ### New features +* EO analysis (and also DR and HTR analysis): group similar EOs together + and such (suggested by Jay) * configurability: add an `alias` command, run config file at startup -* configure max ram to be used (via config file and/or command line option) -* transform alg, rufify etc... * command notation to list available moves * make multi-step solve much more general and create command * input directly cube status instead of moves @@ -105,7 +108,35 @@ including e.g. solutions that were not shown because -c) ### Cleanup * sort again functions alphabetically in their files +* change some function and variable names to make everything consistent * more stuff to load at start (or when suitable command is called) rather than when called directly, to avoid nasty problems with threading * parse command args: one function per arg type, then each command has a list of options that it accepts (as a string) + +### Style +* do not declare all variables at the beginning of a function +* remove var names from prototypes +* various stuff from style(9) + +### Random +Collect random info like this somewhere: + +Table pt_nxopt31_HTM +Base value: 9 +0 1 +1 6 +2 29 +3 164 +4 1433 +5 16772 +6 205033 +7 2513871 +8 30329976 +9 342440769 +10 2815191126 +11 6147967200 +12 524918774 +13 3546 +14 0 +15 0 diff --git a/doc/nissy.1 b/doc/nissy.1 @@ -1,271 +0,0 @@ -.Dd November 2021 -.Dt NISSY 1 -.Os -.Sh NAME -.Nm nissy -.Nd a Rubik's cube solver and FMC assistant -. -.Sh SYNOPSIS -.Nm -.Op Fl b -.Nm -.Ar command -.Op options... -. -.Sh DESCRIPTION -.Nm -is a Rubik's Cube solver. -It uses techniques from Herbert Kociemba's Cube Explorer and -Tomas Rokicki's nxopt. With 4 cores at 2.5GHz and using about 3Gb -of RAM, Nissy can find the optimal solution for a random Rubik's cube position -in about a minute on average. -Nissy can also solve different substeps of the Thistlethwaite's algorithm and more. -.Pp -When run without any argument an interactive shell is launched, otherwise -the provided -.Ar command -is executed and nissy terminates. If the option -.Fl b -is given, every argument after it is ignored and the shell is launched without -any prompt or welcome message. This can be used to run nissy in batch mode, -for example writing a list of commands in a -.Ar file -(one per line) and running -.Ar nissy -b < file -.Pp -The commands that can be run in the interactive shell are the same that can -be run non-interactively and are provided below. -. -.Sh COMMANDS -The available -.Ar commands -are the following: -. -.Bl -tag -width Ds -. -.It Nm cleanup Ar scramble -Rewrites the given scramble using only the 18 base (HTM) moves and at most two -rotations at the end. If -Ar scramble -uses NISS, all moves done on normal scramble are written first, followed by -all moves done on inverse. -. -.It Nm commands -List all available commands. -. -.It Nm freemem -Release some large tables from memory. You can use this command in case -you want to keep nissy open without using too much RAM. -. -.It Nm gen Op Fl t Ar N -Generate all tables used by nissy. Run this to complete your installation. -If -.Ar N -is specified, -.Ar N -CPU threads will be used (defaults to 64, use less only if you don't want -nissy to use all of your CPU resources). -. -.It Nm help Op Ar command -Display help. If no -.Ar command -is given, a generic help message is printed, otherwise a specific help -relative to -.Ar command -is returned. -. -.It Nm invert Ar scramble -Invert the given scramble. -. -.It Nm print Ar scramble -Display a text-only description of the cube obtained after applying -.Ar scramble . -. -.It Nm quit -Quit nissy. -. -.It Nm scramble Oo Fl n Ar N Oc Oo Ar type Oc -Print a randomly-generated (random position) scramble -. -If -.Ar N -is given, it produces -.Ar N -scrambles. -.Ar type -can be specified to be one of the following: -.Bl -tag -width Ds -.It Ar corners -Scramble with solved edges (only cornes are scrambled). -.It Ar dr -Scramble with solved DR on U/D. -.It Ar edges -Scramble with solved corners (only edges are scrambled). -.It Ar eo -Scramble with solved EO on F/B axis. -.It Ar fmc -Scramble the full cube and the resulting scramble starts and ends with -the moves R\(aq U\(aq F. -.It Ar htr -Scramble with HTR solved. -.El -. -.It Nm solve Ar step Oo Ar options Oc Ar scramble -Solve the given -.Ar step -on the given -.Ar scramble. -By default it finds only one (shortest) solution, without using niss, and it -displays the number of moves at the end of the line. -. -The options for the -.Ar solve -command are the following: -. -.Bl -tag -width Ds -. -.It Fl a -Print all solutions: some solutions are filtered out by default for some -steps, for examples EOs that finish with F\(aq, with this options they are not. -. -.It Fl c -Display only the number of solutions found, not the solutions themselves. -. -.It Fl m Ar min -Only look for solution that are at least -.Ar min -moves long. -. -.It Fl M Ar MAX -Only look for solution that are at most -.Ar MAX -moves long. -. -.It Fl n Ar N -Try to find -.Ar N -solutions. By default and unless the -.Fl M -or -.Fl o -options are used, at most one solution is returned. -If at least one of -.Fl M -and -.Fl o -is used, all the solutions found within the given bounds are returned. -The option -.Fl s -overwrites these default behaviors and at most -.Ar N -solutions are returned, still satisfiyng the other constraints. -. -.It Fl N -Allow use of NISS. -. -.It Fl o -Only find solutions that require the minimum number of moves. -. -.It Fl O Ar N -Only find solutions that require at most -.Ar N -moves more than the optimal solution. If -.Ar N -is 0, this is equivalent to -.Fl o -. -.It Fl p -Plain style: do not print the number of moves. -. -.It Fl t Ar N -Use -.Ar N -CPU threads. By default nissy uses only 1 thread. Using more than one -thread will improve performance, but the optimal number depends on your -machine and operating system. Generally, using one less than the number -of threads of your CPU works quite well. -. -.It Fl v -Verbose mode: print some information during the search and print each solution -as it is found instead of only printing them all together at the end. -. -. -.El -. -.It Nm steps -List all available -.Ar steps -for the -.Ar solve -command. -. -.It Nm twophase Ar scramble -Find a solution using a two-phase method. This does not guarantee -to return an optimal solution (and in fact most often it does not), -but it is very fast. -. -.It Nm unniss Ar scramble -Rewrite the scramble without using NISS. -. -.It Nm version -Display version information. -. -.El -. -.Sh SCRAMBLES -All the commands above that accept a scramble also accept a -.Fl Nm i -option with no arguments. -If this option is given, multiple scrambles are read from standard -input (one per line) until and EOF is found, at which point stdin is cleared. -. -.Sh ENVIRONMENT -Data is stored in the folder pointed to by -.Nm $NISSYDATA. -If that variable is unset the folder -.Nm $XDG_DATA_HOME/nissy -or -.Nm $HOME/.nissy -is used instead. If none of this environment variables is defined -(e.g. in a non-UNIX system), the current folder is used. -. -.Sh EXAMPLES -.Pp -The command: -.Dl nissy solve -v -O 1 \(dqR\(aqU\(aqFD2L2FR2U2R2BD2LB2D\(aqB2L\(aqR\(aqBD2BU2LU2R\(aqU\(aqF\(dq -Returns: -.Dl Searching depth 0 -.Dl Searching depth 1 -.Dl (some more lines) -.Dl Searching depth 16 -.Dl D2 F\(aq U2 D2 F\(aq L2 D R2 D F B2 R\(aq L2 F\(aq U\(aq D -.Dl Searching depth 17 -.Dl D2 F\(aq U2 D2 F\(aq L2 D R2 D F B2 R\(aq L2 F\(aq U\(aq D (16) -Notice that the solution is printed twice: the first time it is printed as soon -as it is found as requested by the -v option. -.Pp -The command: -.Dl nissy solve eofb -m 4 -M 5 -N -n 6 \(dqR\(aqU\(aqFD2L2 FR2 U2R2BD2 L B2 D\(aq B2 L\(aq R\(aq\(dq -Returns: -.Dl U B U\(aq B (4) -.Dl U (B R\(aq B) (4) -.Dl (U B R\(aq B) (4) -.Dl U2 F R2 F (4) -.Dl U2 B U2 B (4) -.Dl (U2 B R\(aq B) (4) -.Pp -On a UNIX shell, the composite command -.Dl nissy scramble -n 2 | nissy solve -i > file.txt -Generates two random scrambles, solves them and saves the result to file.txt. -The file will look something like this: -.Dl >>> Line: D U2 F D B\(aq F L2 D\(aq F2 R2 L B2 L\(aq U2 B2 R F2 L\(aq D2 -.Dl U2 R2 F2 L B2 D\(aq R2 D\(aq F U L2 B\(aq U\(aq R2 D2 R2 U (17) -.Dl >>> Line: D B R U\(aq B\(aq L2 U L U D2 R L B2 U2 L2 U2 R U2 B2 L F2 -.Dl D\(aq F R\(aq D B L2 B R2 L U L U2 B D\(aq U R U F2 (18) -. -.Sh AUTHORS -.An Sebastiano Tronto Aq Mt sebastiano@tronto.net -. -.Sh SOURCE CODE -Source code is available at -.Lk https://nissy.tronto.net diff --git a/old/maybe-useful-coord.c b/old/maybe-useful-coord.c @@ -0,0 +1,181 @@ +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 24 * subset_to_index(epos, 12, 4) + perm_to_index(eps, 4); +} + +void +epos_to_compatible_ep(int epos, int *ep, int *ss) +{ + int i, j, k, other[8]; + bool flag; + + for (i = 0; i < 12; i++) + ep[i] = -1; + + epos_to_partial_ep(epos, ep, ss); + + for (i = 0, j = 0; i < 12; i++) { + flag = false; + for (k = 0; k < 4; k++) + flag = flag || (i == ss[k]); + if (!flag) + other[j++] = i; + } + + for (i = 0, j = 0; i < 12; i++) + if (ep[i] == -1) + ep[i] = other[j++]; +} + +void +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 +fix_eorleoud(CubeArray *arr) +{ + int i; + + for (i = 0; i < 12; i++) { + if ((edge_slice(i) == 0 && edge_slice(arr->ep[i]) != 0) || + (edge_slice(i) != 0 && edge_slice(arr->ep[i]) == 0)) { + arr->eorl[i] = 1 - arr->eofb[i]; + } else { + arr->eorl[i] = arr->eofb[i]; + } + + if ((edge_slice(i) == 2 && edge_slice(arr->ep[i]) != 2) || + (edge_slice(i) != 2 && edge_slice(arr->ep[i]) == 2)) { + arr->eoud[i] = 1 - arr->eofb[i]; + } else { + arr->eoud[i] = arr->eofb[i]; + } + } +} + +void +fix_cofbcorl(CubeArray *arr) +{ + int i; + + for (i = 0; i < 8; i++) { + if (i % 2 == arr->cp[i] % 2) { + arr->cofb[i] = arr->coud[i]; + arr->corl[i] = arr->coud[i]; + } else { + if (arr->cp[i] % 2 == 0) { + arr->cofb[i] = (arr->coud[i]+1)%3; + arr->corl[i] = (arr->coud[i]+2)%3; + } else { + arr->cofb[i] = (arr->coud[i]+2)%3; + arr->corl[i] = (arr->coud[i]+1)%3; + } + } + } +} + +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; +} + +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; +} + +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; +} diff --git a/old/maybe-useful-steps.c b/old/maybe-useful-steps.c @@ -0,0 +1,1111 @@ +#include "steps.h" + +#define UPDATECHECKSTOP(a, b, c) if ((a=(MAX((a),(b))))>(c)) return (a); + +static int estimate_stepalt(StepAlt *a, uint64_t *ind); + +/* Checkers and validators ***************************************************/ + +/* TODO: these should be with Cube *cube (and all need to change) */ +/* Maybe move them to cube.c */ +static bool check_centers(Cube cube); +static bool check_coud_HTM(Cube cube); +static bool check_coud_URF(Cube cube); +static bool check_corners_HTM(Cube cube); +static bool check_corners_URF(Cube cube); +static bool check_cornershtr(Cube cube); +static bool check_eofb(Cube cube); +static bool check_drud(Cube cube); +static bool check_htr(Cube cube); + +static bool always_valid(Alg *alg); +static bool validate_singlecw_ending(Alg *alg); + +/* Messages for when cube is not ready ***************************************/ + +static char check_centers_msg[100] = "cube must be oriented (centers solved)"; +static char check_eo_msg[100] = "EO must be solved on given axis"; +static char check_dr_msg[100] = "DR must be solved on given axis"; +static char check_htr_msg[100] = "HTR must be solved"; +static char check_drany_msg[100] = "DR must be solved on at least one axis"; + +/* Steps *********************************************************************/ + +/* Optimal solvers *******************/ + +Step +optimal_HTM = { + .shortname = "optimal", + .name = "Optimal solve (in HTM)", + + .final = true, + .is_done = is_solved, + .estimate = estimate_nxopt31_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = always_valid, + .moveset = &moveset_HTM, + + .pre_trans = uf, + + .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, + .ntables = 2, +}; + +Step +optimal_light_HTM = { + .shortname = "light", + .name = "Optimal solve (in HTM), small table (500Mb RAM total)", + + .final = true, + .is_done = is_solved, + .estimate = estimate_light_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = always_valid, + .moveset = &moveset_HTM, + + .pre_trans = uf, + + .tables = {&pd_drud_sym16_HTM, &pd_corners_HTM}, + .ntables = 2, +}; + +/* Optimal after EO ******************/ + +Step +eofin_eo = { + .shortname = "eofin", + .name = "Optimal solve after EO without breaking EO (detected)", + + .final = true, + .is_done = is_solved, + .estimate = estimate_nxopt31_HTM, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = always_valid, + .moveset = &moveset_eofb, + + .detect = detect_pretrans_eofb, + + .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, + .ntables = 2, +}; + +Step +eofbfin_eofb = { + .shortname = "eofbfin", + .name = "Optimal after EO on F/B without breaking EO", + + .final = true, + .is_done = is_solved, + .estimate = estimate_nxopt31_HTM, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = always_valid, + .moveset = &moveset_eofb, + + .pre_trans = uf, + + .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, + .ntables = 2, +}; + +Step +eorlfin_eorl = { + .shortname = "eorlfin", + .name = "Optimal after EO on R/L without breaking EO", + + .final = true, + .is_done = is_solved, + .estimate = estimate_nxopt31_HTM, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = always_valid, + .moveset = &moveset_eofb, + + .pre_trans = ur, + + .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, + .ntables = 2, +}; + +Step +eoudfin_eoud = { + .shortname = "eoudfin", + .name = "Optimal after EO on U/D without breaking EO", + + .final = true, + .is_done = is_solved, + .estimate = estimate_nxopt31_HTM, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = always_valid, + .moveset = &moveset_eofb, + + .pre_trans = fd, + + .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, + .ntables = 2, +}; + +/* EO steps **************************/ +Step +eoany_HTM = { + .shortname = "eo", + .name = "EO on any axis", + + .final = false, + .is_done = check_eofb, + .estimate = estimate_eofb_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_HTM, + + .detect = detect_pretrans_void_3axis, + + .tables = {&pd_eofb_HTM}, + .ntables = 1, +}; + +Step +eofb_HTM = { + .shortname = "eofb", + .name = "EO on F/B", + + .final = false, + .is_done = check_eofb, + .estimate = estimate_eofb_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_HTM, + + .pre_trans = uf, + + .tables = {&pd_eofb_HTM}, + .ntables = 1, +}; + +Step +eorl_HTM = { + .shortname = "eorl", + .name = "EO on R/L", + + .final = false, + .is_done = check_eofb, + .estimate = estimate_eofb_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_HTM, + + .pre_trans = ur, + + .tables = {&pd_eofb_HTM}, + .ntables = 1, +}; + +Step +eoud_HTM = { + .shortname = "eoud", + .name = "EO on U/D", + + .final = false, + .is_done = check_eofb, + .estimate = estimate_eofb_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_HTM, + + .pre_trans = fd, + + .tables = {&pd_eofb_HTM}, + .ntables = 1, +}; + +/* CO steps **************************/ +Step +coany_HTM = { + .shortname = "co", + .name = "CO on any axis", + + .final = false, + .is_done = check_coud_HTM, + .estimate = estimate_coud_HTM, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_HTM, + + .detect = detect_pretrans_void_3axis, + + .tables = {&pd_coud_HTM}, + .ntables = 1, +}; + +Step +coud_HTM = { + .shortname = "coud", + .name = "CO on U/D", + + .final = false, + .is_done = check_coud_HTM, + .estimate = estimate_coud_HTM, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_HTM, + + .pre_trans = uf, + + .tables = {&pd_coud_HTM}, + .ntables = 1, +}; + +Step +corl_HTM = { + .shortname = "corl", + .name = "CO on R/L", + + .final = false, + .is_done = check_coud_HTM, + .estimate = estimate_coud_HTM, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_HTM, + + .pre_trans = rf, + + .tables = {&pd_coud_HTM}, + .ntables = 1, +}; + +Step +cofb_HTM = { + .shortname = "cofb", + .name = "CO on F/B", + + .final = false, + .is_done = check_coud_HTM, + .estimate = estimate_coud_HTM, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_HTM, + + .pre_trans = fd, + + .tables = {&pd_coud_HTM}, + .ntables = 1, +}; + +Step +coany_URF = { + .shortname = "co-URF", + .name = "CO any axis (URF moveset)", + + .final = false, + .is_done = check_coud_URF, + .estimate = estimate_coud_URF, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_URF, + + .detect = detect_pretrans_void_3axis, + + .tables = {&pd_coud_HTM}, + .ntables = 1, +}; + +Step +coud_URF = { + .shortname = "coud-URF", + .name = "CO on U/D (URF moveset)", + + .final = false, + .is_done = check_coud_URF, + .estimate = estimate_coud_URF, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_URF, + + .pre_trans = uf, + + .tables = {&pd_coud_HTM}, + .ntables = 1, +}; + +Step +corl_URF = { + .shortname = "corl-URF", + .name = "CO on R/L (URF moveset)", + + .final = false, + .is_done = check_coud_URF, + .estimate = estimate_coud_URF, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_URF, + + .pre_trans = rf, + + .tables = {&pd_coud_HTM}, + .ntables = 1, +}; + +Step +cofb_URF = { + .shortname = "cofb-URF", + .name = "CO on F/B (URF moveset)", + + .final = false, + .is_done = check_coud_URF, + .estimate = estimate_coud_URF, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_URF, + + .pre_trans = fd, + + .tables = {&pd_coud_HTM}, + .ntables = 1, +}; + +/* Misc corner steps *****************/ +Step +cornershtr_HTM = { + .shortname = "chtr", + .name = "Solve corners to HTR state", + + .final = false, + .is_done = check_cornershtr, + .estimate = estimate_cornershtr_HTM, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_HTM, + + .pre_trans = uf, + + .tables = {&pd_cornershtr_HTM}, + .ntables = 1, +}; + +Step +cornershtr_URF = { + .shortname = "chtr-URF", + .name = "Solve corners to HTR state (URF moveset)", + + .final = false, + .is_done = check_cornershtr, + .estimate = estimate_cornershtr_URF, + .ready = NULL, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_URF, + + .pre_trans = uf, + + .tables = {&pd_cornershtr_HTM}, + .ntables = 1, +}; + +Step +corners_HTM = { + .shortname = "corners", + .name = "Solve corners", + + .final = true, + .is_done = check_corners_HTM, + .estimate = estimate_corners_HTM, + .ready = NULL, + .is_valid = always_valid, + .moveset = &moveset_HTM, + + .pre_trans = uf, + + .tables = {&pd_corners_HTM}, + .ntables = 1, +}; + +Step +corners_URF = { + .shortname = "corners-URF", + .name = "Solve corners (URF moveset)", + + .final = true, /* TODO: check if this works with reorient */ + .is_done = check_corners_URF, + .estimate = estimate_corners_URF, + .ready = NULL, + .is_valid = always_valid, + .moveset = &moveset_URF, + + .pre_trans = uf, + + .tables = {&pd_corners_HTM}, + .ntables = 1, +}; + +/* DR steps **************************/ +Step +drany_HTM = { + .shortname = "dr", + .name = "DR on any axis", + + .final = false, + .is_done = check_drud, + .estimate = estimate_drud_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_HTM, + + .detect = detect_pretrans_void_3axis, + + .tables = {&pd_drud_sym16_HTM}, + .ntables = 1, +}; + +Step +drud_HTM = { + .shortname = "drud", + .name = "DR on U/D", + + .final = false, + .is_done = check_drud, + .estimate = estimate_drud_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_HTM, + + .pre_trans = uf, + + .tables = {&pd_drud_sym16_HTM}, + .ntables = 1, +}; + +Step +drrl_HTM = { + .shortname = "drrl", + .name = "DR on R/L", + + .final = false, + .is_done = check_drud, + .estimate = estimate_drud_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_HTM, + + .pre_trans = rf, + + .tables = {&pd_drud_sym16_HTM}, + .ntables = 1, +}; + +Step +drfb_HTM = { + .shortname = "drfb", + .name = "DR on F/B", + + .final = false, + .is_done = check_drud, + .estimate = estimate_drud_HTM, + .ready = check_centers, + .ready_msg = check_centers_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_HTM, + + .pre_trans = fd, + + .tables = {&pd_drud_sym16_HTM}, + .ntables = 1, +}; + +/* DR from EO */ +Step +dr_eo = { + .shortname = "dr-eo", + .name = "DR without breaking EO (automatically detected)", + + .final = false, + .is_done = check_drud, + .estimate = estimate_dr_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_eofb, + + .detect = detect_pretrans_eofb, + + .tables = {&pd_drud_eofb}, + .ntables = 1, +}; + +Step +dr_eofb = { + .shortname = "dr-eofb", + .name = "DR on U/D or R/L without breaking EO on F/B", + + .final = false, + .is_done = check_drud, + .estimate = estimate_dr_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_eofb, + + .pre_trans = uf, + + .tables = {&pd_drud_eofb}, + .ntables = 1, +}; + +Step +dr_eorl = { + .shortname = "dr-eorl", + .name = "DR on U/D or F/B without breaking EO on R/L", + + .final = false, + .is_done = check_drud, + .estimate = estimate_dr_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_eofb, + + .pre_trans = ur, + + .tables = {&pd_drud_eofb}, + .ntables = 1, +}; + +Step +dr_eoud = { + .shortname = "dr-eoud", + .name = "DR on R/L or F/B without breaking EO on U/D", + + .final = false, + .is_done = check_drud, + .estimate = estimate_dr_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_eofb, + + .pre_trans = fd, + + .tables = {&pd_drud_eofb}, + .ntables = 1, +}; + +Step +drud_eofb = { + .shortname = "drud-eofb", + .name = "DR on U/D without breaking EO on F/B", + + .final = false, + .is_done = check_drud, + .estimate = estimate_drud_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_eofb, + + .pre_trans = uf, + + .tables = {&pd_drud_eofb}, + .ntables = 1, +}; + +Step +drrl_eofb = { + .shortname = "drrl-eofb", + .name = "DR on R/L without breaking EO on F/B", + + .final = false, + .is_done = check_drud, + .estimate = estimate_drud_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_eofb, + + .pre_trans = rf, + + .tables = {&pd_drud_eofb}, + .ntables = 1, +}; + +Step +drud_eorl = { + .shortname = "drud-eorl", + .name = "DR on U/D without breaking EO on R/L", + + .final = false, + .is_done = check_drud, + .estimate = estimate_drud_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_eofb, + + .pre_trans = ur, + + .tables = {&pd_drud_eofb}, + .ntables = 1, +}; + +Step +drfb_eorl = { + .shortname = "drfb-eorl", + .name = "DR on F/B without breaking EO on R/L", + + .final = false, + .is_done = check_drud, + .estimate = estimate_drud_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_eofb, + + .pre_trans = fr, + + .tables = {&pd_drud_eofb}, + .ntables = 1, +}; + +Step +drfb_eoud = { + .shortname = "drfb-eoud", + .name = "DR on F/B without breaking EO on U/D", + + .final = false, + .is_done = check_drud, + .estimate = estimate_drud_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_eofb, + + .pre_trans = fd, + + .tables = {&pd_drud_eofb}, + .ntables = 1, +}; + +Step +drrl_eoud = { + .shortname = "drrl-eoud", + .name = "DR on R/L without breaking EO on U/D", + + .final = false, + .is_done = check_drud, + .estimate = estimate_drud_eofb, + .ready = check_eofb, + .ready_msg = check_eo_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_eofb, + + .pre_trans = rd, + + .tables = {&pd_drud_eofb}, + .ntables = 1, +}; + +/* DR finish steps */ +Step +dranyfin_DR = { + .shortname = "drfin", + .name = "DR finish on any axis without breaking DR", + + .final = true, + .is_done = is_solved, + .estimate = estimate_drudfin_drud, + .ready = check_drud, + .ready_msg = check_drany_msg, + .is_valid = always_valid, + .moveset = &moveset_drud, + + .detect = detect_pretrans_drud, + + .tables = {&pd_drudfin_noE_sym16_drud}, + .ntables = 1, +}; + +Step +drudfin_drud = { + .shortname = "drudfin", + .name = "DR finish on U/D without breaking DR", + + .final = true, + .is_done = is_solved, + .estimate = estimate_drudfin_drud, + .ready = check_drud, + .ready_msg = check_dr_msg, + .is_valid = always_valid, + .moveset = &moveset_drud, + + .pre_trans = uf, + + .tables = {&pd_drudfin_noE_sym16_drud}, + .ntables = 1, +}; + +Step +drrlfin_drrl = { + .shortname = "drrlfin", + .name = "DR finish on R/L without breaking DR", + + .final = true, + .is_done = is_solved, + .estimate = estimate_drudfin_drud, + .ready = check_drud, + .ready_msg = check_dr_msg, + .is_valid = always_valid, + .moveset = &moveset_drud, + + .pre_trans = rf, + + .tables = {&pd_drudfin_noE_sym16_drud}, + .ntables = 1, +}; + +Step +drfbfin_drfb = { + .shortname = "drfbfin", + .name = "DR finish on F/B without breaking DR", + + .final = true, + .is_done = is_solved, + .estimate = estimate_drudfin_drud, + .ready = check_drud, + .ready_msg = check_dr_msg, + .is_valid = always_valid, + .moveset = &moveset_drud, + + .pre_trans = fd, + + .tables = {&pd_drudfin_noE_sym16_drud}, + .ntables = 1, +}; + +/* HTR from DR */ +Step +htr_any = { + .shortname = "htr", + .name = "HTR from DR", + + .final = false, + .is_done = check_htr, + .estimate = estimate_htr_drud, + .ready = check_drud, + .ready_msg = check_drany_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_drud, + + .detect = detect_pretrans_drud, + + .tables = {&pd_htr_drud}, + .ntables = 1, +}; + +Step +htr_drud = { + .shortname = "htr-drud", + .name = "HTR from DR on U/D", + + .final = false, + .is_done = check_htr, + .estimate = estimate_htr_drud, + .ready = check_drud, + .ready_msg = check_dr_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_drud, + + .pre_trans = uf, + + .tables = {&pd_htr_drud}, + .ntables = 1, +}; + +Step +htr_drrl = { + .shortname = "htr-drrl", + .name = "HTR from DR on R/L", + + .final = false, + .is_done = check_htr, + .estimate = estimate_htr_drud, + .ready = check_drud, + .ready_msg = check_dr_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_drud, + + .pre_trans = rf, + + .tables = {&pd_htr_drud}, + .ntables = 1, +}; + +Step +htr_drfb = { + .shortname = "htr-drfb", + .name = "HTR from DR on F/B", + + .final = false, + .is_done = check_htr, + .estimate = estimate_htr_drud, + .ready = check_drud, + .ready_msg = check_dr_msg, + .is_valid = validate_singlecw_ending, + .moveset = &moveset_drud, + + .pre_trans = fd, + + .tables = {&pd_htr_drud}, + .ntables = 1, +}; + +/* HTR finish */ +Step +htrfin_htr = { + .shortname = "htrfin", + .name = "HTR finish without breaking HTR", + + .final = true, + .is_done = is_solved, + .estimate = estimate_htrfin_htr, + .ready = check_htr, + .ready_msg = check_htr_msg, + .is_valid = always_valid, + .moveset = &moveset_htr, + + .pre_trans = uf, + + .tables = {&pd_htrfin_htr}, + .ntables = 1, +}; + +Step *steps[] = { + &optimal_HTM, /* first is default */ + &optimal_light_HTM, + + &eofin_eo, + &eofbfin_eofb, + &eorlfin_eorl, + &eoudfin_eoud, + + &eoany_HTM, + &eofb_HTM, + &eorl_HTM, + &eoud_HTM, + + &coany_HTM, + &coud_HTM, + &corl_HTM, + &cofb_HTM, + + &coany_URF, + &coud_URF, + &corl_URF, + &cofb_URF, + + &drany_HTM, + &drud_HTM, + &drrl_HTM, + &drfb_HTM, + + &dr_eo, + &dr_eofb, + &dr_eorl, + &dr_eoud, + &drud_eofb, + &drrl_eofb, + &drud_eorl, + &drfb_eorl, + &drfb_eoud, + &drrl_eoud, + + &dranyfin_DR, + &drudfin_drud, + &drrlfin_drrl, + &drfbfin_drfb, + + &htr_any, + &htr_drud, + &htr_drrl, + &htr_drfb, + + &htrfin_htr, + + &cornershtr_HTM, + &cornershtr_URF, + &corners_HTM, + &corners_URF, + + NULL +}; + +/* Checkers and validators ***************************************************/ + +static bool +check_centers(Cube cube) +{ + return cube.cpos == 0; +} + +static bool +check_coud_HTM(Cube cube) +{ + return cube.coud == 0; +} + +static bool +check_coud_URF(Cube cube) +{ + Cube c2, c3; + + c2 = apply_move(z, cube); + c3 = apply_move(x, cube); + + return cube.coud == 0 || c2.coud == 0 || c3.coud == 0; +} + +static bool +check_corners_URF(Cube cube) +{ + Cube c; + Trans i; + + for (i = 0; i < NROTATIONS; i++) { + c = apply_alg(rotation_alg(i), cube); + if (c.cp && c.coud) + return true; + } + + return false; +} + +static bool +check_corners_HTM(Cube cube) +{ + return cube.cp == 0 && cube.coud == 0; +} + +static bool +check_cornershtr(Cube cube) +{ + return coord_cornershtr.index(cube) == 0; +} + +static bool +check_eofb(Cube cube) +{ + return cube.eofb == 0; +} + +static bool +check_drud(Cube cube) +{ + return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0; +} + +static bool +check_htr(Cube cube) +{ + return check_drud(cube) && coord_htr_drud.index(cube) == 0; +} + +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; +} + +/* Public functions **********************************************************/ + +void +compute_ind(StepAlt *a, Cube *cube, uint64_t *ind) +{ + +} + +int +estimate_stepalt(StepAlt *a, uint64_t *ind) +{ + int i, ret, est[a->n_coord]; + + for (i = 0; i < a->n_coord; i++) { + est[i] = ptableval(a->pd[i], ind[i]); + if (est[i] == 0 && a->compact_pd[i]) + est[i] = ptableval(a->fallback_pd, ind[i] / a->fbmod); + } + + for (i = 0; i < a->n_dbtrick; i++) + if (est[a->dbtrick[i][0]] == est[a->dbtrick[i][1]] && + est[a->dbtrick[i][0]] == est[a->dbtrick[i][2]]) + est[a->dbtrick[i][0]] += 1; + + for (i = 0, ret = -1; i < a->n_coord; i++) + ret = max(ret, est[i]); + + return ret; +} + +void +prepare_step(Step *step, SolveOptions *opts) +{ + int i, j; + PDGenData pdg; + StepAlt *a; + + init_moveset(step->moveset); + pdg.moveset = step->moveset; + + for (i = 0; step->alt[i] != NULL; i++) { + a = step->alt[i]; + for (j = 0; j < a->n_coord; j++) { + gen_coord(a->coord[j]); + + pdg.coord = a->coord[j]; + pdg.compact = a->compact[j]; + pdg.pd = NULL; + + a->pd[j] = genptable(&pdg, opts->nthreads); + + if (a->compact_pd[j]) { + gen_coord(a->fallback_coord[j]); + + pdg.coord = a->fallback_coord[j]; + pdg.compact = false; + pdg.pd = NULL; + + a->fallback_pd[j] = + step->genptable(&pdg, opts->nthreads); + } + } + } +} diff --git a/src/alg.c b/src/alg.c @@ -1,68 +1,18 @@ -#include "alg.h" +#define ALG_C -/* Local functions ***********************************************************/ +#include "alg.h" -static bool allowed_HTM(Move m); -static bool allowed_URF(Move m); -static bool allowed_eofb(Move m); -static bool allowed_drud(Move m); -static bool allowed_htr(Move m); -static bool allowed_next_HTM(Move l2, Move l1, Move m); static int axis(Move m); - static void free_alglistnode(AlgListNode *aln); static void realloc_alg(Alg *alg, int n); -/* Movesets ******************************************************************/ - -Moveset -moveset_HTM = { - .allowed = allowed_HTM, - .allowed_next = allowed_next_HTM, -}; - -Moveset -moveset_URF = { - .allowed = allowed_URF, - .allowed_next = allowed_next_HTM, -}; - -Moveset -moveset_eofb = { - .allowed = allowed_eofb, - .allowed_next = allowed_next_HTM, -}; - -Moveset -moveset_drud = { - .allowed = allowed_drud, - .allowed_next = allowed_next_HTM, -}; - -Moveset -moveset_htr = { - .allowed = allowed_htr, - .allowed_next = allowed_next_HTM, -}; - -static int nmoveset = 5; -static Moveset * all_ms[] = { - &moveset_HTM, - &moveset_URF, - &moveset_eofb, - &moveset_drud, - &moveset_htr, -}; - -/* Functions *****************************************************************/ - -static bool +bool allowed_HTM(Move m) { return m >= U && m <= B3; } -static bool +bool allowed_URF(Move m) { Move b = base_move(m); @@ -70,7 +20,7 @@ allowed_URF(Move m) return b == U || b == R || b == F; } -static bool +bool allowed_eofb(Move m) { Move b = base_move(m); @@ -79,7 +29,7 @@ allowed_eofb(Move m) ((b == F || b == B) && m == b+1); } -static bool +bool allowed_drud(Move m) { Move b = base_move(m); @@ -88,7 +38,7 @@ allowed_drud(Move m) ((b == R || b == L || b == F || b == B) && m == b + 1); } -static bool +bool allowed_htr(Move m) { Move b = base_move(m); @@ -96,8 +46,8 @@ allowed_htr(Move m) return moveset_HTM.allowed(m) && m == b + 1; } -static bool -allowed_next_HTM(Move l2, Move l1, Move m) +bool +allowed_next_all(Move l2, Move l1, Move m) { bool p, q; @@ -469,6 +419,34 @@ swapmove(Move *m1, Move *m2) *m2 = aux; } +char * +trans_string(Trans t) +{ + static char trans_string_aux[NTRANS][20] = { + [uf] = "uf", [ur] = "ur", [ub] = "ub", [ul] = "ul", + [df] = "df", [dr] = "dr", [db] = "db", [dl] = "dl", + [rf] = "rf", [rd] = "rd", [rb] = "rb", [ru] = "ru", + [lf] = "lf", [ld] = "ld", [lb] = "lb", [lu] = "lu", + [fu] = "fu", [fr] = "fr", [fd] = "fd", [fl] = "fl", + [bu] = "bu", [br] = "br", [bd] = "bd", [bl] = "bl", + + [uf_mirror] = "uf*", [ur_mirror] = "ur*", + [ub_mirror] = "ub*", [ul_mirror] = "ul*", + [df_mirror] = "df*", [dr_mirror] = "dr*", + [db_mirror] = "db*", [dl_mirror] = "dl*", + [rf_mirror] = "rf*", [rd_mirror] = "rd*", + [rb_mirror] = "rb*", [ru_mirror] = "ru*", + [lf_mirror] = "lf*", [ld_mirror] = "ld*", + [lb_mirror] = "lb*", [lu_mirror] = "lu*", + [fu_mirror] = "fu*", [fr_mirror] = "fr*", + [fd_mirror] = "fd*", [fl_mirror] = "fl*", + [bu_mirror] = "bu*", [br_mirror] = "br*", + [bd_mirror] = "bd*", [bl_mirror] = "bl*", + }; + + return trans_string_aux[t]; +} + Alg * unniss(Alg *alg) { @@ -513,12 +491,3 @@ init_moveset(Moveset *ms) } } } - -void -init_all_movesets() -{ - int i; - - for (i = 0; i < nmoveset; i++) - init_moveset(all_ms[i]); -} diff --git a/src/alg.h b/src/alg.h @@ -8,12 +8,13 @@ #include "cubetypes.h" #include "utils.h" -extern Moveset moveset_HTM; -extern Moveset moveset_URF; -extern Moveset moveset_eofb; -extern Moveset moveset_drud; -extern Moveset moveset_htr; - +bool allowed_all(Move m); +bool allowed_HTM(Move m); +bool allowed_URF(Move m); +bool allowed_eofb(Move m); +bool allowed_drud(Move m); +bool allowed_htr(Move m); +bool allowed_next_all(Move l2, Move l1, Move m); void append_alg(AlgList *l, Alg *alg); void append_move(Alg *alg, Move m, bool inverse); Move base_move(Move m); @@ -34,10 +35,71 @@ Alg * on_inverse(Alg *alg); void print_alg(Alg *alg, bool l); void print_alglist(AlgList *al, bool l); void swapmove(Move *m1, Move *m2); +char * trans_string(Trans t); /* Here because similar to move_string, move? */ Alg * unniss(Alg *alg); void init_moveset(Moveset *ms); -void init_all_movesets(); + +/* Movesets ******************************************************************/ + +#ifndef ALG_C + +extern Moveset moveset_HTM; +extern Moveset moveset_URF; +extern Moveset moveset_eofb; +extern Moveset moveset_drud; +extern Moveset moveset_htr; + +extern Moveset * all_ms[]; + +#else + +Moveset +moveset_HTM = { + .name = "HTM", + .allowed = allowed_HTM, + .allowed_next = allowed_next_all, +}; + +Moveset +moveset_URF = { + .name = "URF", + .allowed = allowed_URF, + .allowed_next = allowed_next_all, +}; + +Moveset +moveset_eofb = { + .name = "eofb", + .allowed = allowed_eofb, + .allowed_next = allowed_next_all, +}; + +Moveset +moveset_drud = { + .name = "drud", + .allowed = allowed_drud, + .allowed_next = allowed_next_all, +}; + +Moveset +moveset_htr = { + .name = "htr", + .allowed = allowed_htr, + .allowed_next = allowed_next_all, +}; + +Moveset * +all_ms[] = { + &moveset_HTM, + &moveset_URF, + &moveset_eofb, + &moveset_drud, + &moveset_htr, + NULL +}; + +#endif #endif diff --git a/src/commands.c b/src/commands.c @@ -1,187 +1,11 @@ -#include "commands.h" +#define COMMANDS_C -/* Arg parsing functions *****************************************************/ - -CommandArgs * gen_parse_args(int c, char **v); -CommandArgs * help_parse_args(int c, char **v); -CommandArgs * parse_only_scramble(int c, char **v); -CommandArgs * parse_no_arg(int c, char **v); -CommandArgs * solve_parse_args(int c, char **v); -CommandArgs * scramble_parse_args(int c, char **v); - -/* Exec functions ************************************************************/ - -static void gen_exec(CommandArgs *args); -static void cleanup_exec(CommandArgs *args); -static void invert_exec(CommandArgs *args); -static void solve_exec(CommandArgs *args); -static void scramble_exec(CommandArgs *args); -static void steps_exec(CommandArgs *args); -static void commands_exec(CommandArgs *args); -static void freemem_exec(CommandArgs *args); -static void print_exec(CommandArgs *args); -static void twophase_exec(CommandArgs *args); -static void help_exec(CommandArgs *args); -static void quit_exec(CommandArgs *args); -static void unniss_exec(CommandArgs *args); -static void version_exec(CommandArgs *args); - -/* Local functions ***********************************************************/ +#include "commands.h" static bool read_step(CommandArgs *args, char *str); static bool read_scrtype(CommandArgs *args, char *str); static bool read_scramble(int c, char **v, CommandArgs *args); -/* Commands ******************************************************************/ - -Command -solve_cmd = { - .name = "solve", - .usage = "solve STEP [OPTIONS] SCRAMBLE", - .description = "Solve a step; see command steps for a list of steps", - .parse_args = solve_parse_args, - .exec = solve_exec -}; - -Command -scramble_cmd = { - .name = "scramble", - .usage = "scramble [TYPE] [-n N]", - .description = "Get a random-position scramble", - .parse_args = scramble_parse_args, - .exec = scramble_exec, -}; - -Command -gen_cmd = { - .name = "gen", - .usage = "gen [-t N]", - .description = "Generate all tables [using N threads]", - .parse_args = gen_parse_args, - .exec = gen_exec -}; - -Command -invert_cmd = { - .name = "invert", - .usage = "invert SCRAMBLE]", - .description = "Invert a scramble", - .parse_args = parse_only_scramble, - .exec = invert_exec, -}; - -Command -steps_cmd = { - .name = "steps", - .usage = "steps", - .description = "List available steps", - .parse_args = parse_no_arg, - .exec = steps_exec -}; - -Command -commands_cmd = { - .name = "commands", - .usage = "commands", - .description = "List available commands", - .parse_args = parse_no_arg, - .exec = commands_exec -}; - -Command -freemem_cmd = { - .name = "freemem", - .usage = "freemem", - .description = "free large tables from RAM", - .parse_args = parse_no_arg, - .exec = freemem_exec, -}; - -Command -print_cmd = { - .name = "print", - .usage = "print SCRAMBLE", - .description = "Print written description of the cube", - .parse_args = parse_only_scramble, - .exec = print_exec, -}; - -Command -help_cmd = { - .name = "help", - .usage = "help [COMMAND]", - .description = "Display nissy manual page or help on specific command", - .parse_args = help_parse_args, - .exec = help_exec, -}; - -Command -twophase_cmd = { - .name = "twophase", - .usage = "twophase", - .description = "Find a solution quickly using a 2-phase method", - .parse_args = parse_only_scramble, - .exec = twophase_exec, -}; - -Command -quit_cmd = { - .name = "quit", - .usage = "quit", - .description = "Quit nissy", - .parse_args = parse_no_arg, - .exec = quit_exec, -}; - -Command -cleanup_cmd = { - .name = "cleanup", - .usage = "cleanup SCRAMBLE", - .description = "Rewrite a scramble using only standard moves (HTM)", - .parse_args = parse_only_scramble, - .exec = cleanup_exec, -}; - -Command -unniss_cmd = { - .name = "unniss", - .usage = "unniss SCRAMBLE", - .description = "Rewrite a scramble without NISS", - .parse_args = parse_only_scramble, - .exec = unniss_exec, -}; - -Command -version_cmd = { - .name = "version", - .usage = "version", - .description = "print nissy version", - .parse_args = parse_no_arg, - .exec = version_exec, -}; - -Command *commands[] = { - &commands_cmd, - &freemem_cmd, - &gen_cmd, - &help_cmd, - &invert_cmd, - &print_cmd, - &quit_cmd, - &solve_cmd, - &scramble_cmd, - &steps_cmd, - &twophase_cmd, - &cleanup_cmd, - &unniss_cmd, - &version_cmd, - NULL -}; - -/* Other constants ***********************************************************/ - -char *scrtypes[20] = { "eo", "corners", "edges", "fmc", "dr", "htr", NULL }; - /* Arg parsing functions implementation **************************************/ CommandArgs * @@ -386,17 +210,15 @@ parse_no_arg(int c, char **v) /* Exec functions implementation *********************************************/ -static void +void solve_exec(CommandArgs *args) { Cube c; AlgList *sols; - init_all_movesets(); - init_symcoord(); - - c = apply_alg(args->scramble, (Cube){0}); - sols = solve(c, args->step, args->opts); + make_solved(&c); + apply_alg(args->scramble, &c); + sols = solve(&c, args->step, args->opts); if (args->opts->count_only) printf("%d\n", sols->len); @@ -406,85 +228,64 @@ solve_exec(CommandArgs *args) free_alglist(sols); } -static void +void scramble_exec(CommandArgs *args) { Cube cube; - CubeArray *arr; Alg *scr, *ruf, *aux; - int i, j, eo, ep, co, cp, a[12]; - int eparr[12] = { [8] = 8, [9] = 9, [10] = 10, [11] = 11 }; + int i, j, eo, ep, co, cp; uint64_t ui, uj, uk; - init_all_movesets(); - init_symcoord(); - srand(time(NULL)); for (i = 0; i < args->n; i++) { if (!strcmp(args->scrtype, "dr")) { - /* Warning: cube is inconsistent because of side CO * - * and EO on U/D. But solve_2phase only solves drfin * - * in this case, so it should be ok. * - * TODO: check this properly * - * Moreover we again need to fix parity after * - * generating epose manually */ - do { - ui = rand() % FACTORIAL8; - uj = rand() % FACTORIAL8; - uk = rand() % FACTORIAL4; - - index_to_perm(ui, 12, a); - arr = malloc(sizeof(CubeArray)); - arr->ep = eparr; - cube = arrays_to_cube(arr, pf_ep); - free(arr); - - cube.cp = uj; - cube.epose += uk; - } while (!is_admissible(cube)); + ui = rand() % FACTORIAL8; + uj = rand() % FACTORIAL8; + uk = rand() % FACTORIAL4; + + make_solved(&cube); + index_to_perm(ui, 8, cube.cp); + index_to_perm(uj, 8, cube.ep); + index_to_perm(uk, 4, cube.ep + 8); + for (j = 8; j < 12; j++) + cube.ep[j] += 8; } else if (!strcmp(args->scrtype, "htr")) { - /* antindex_htrfin() returns a consistent * - * cube, except possibly for parity */ - do { - ui = rand() % (24*24/6); - cube = (Cube){0}; - cube.cp = cornershtrfin_ant[ui]; - cube.epose = rand() % 24; - cube.eposs = rand() % 24; - cube.eposm = rand() % 24; - } while (!is_admissible(cube)); + make_solved(&cube); + /* TODO */ } else { - eo = rand() % POW2TO11; ep = rand() % FACTORIAL12; - co = rand() % POW3TO7; cp = rand() % FACTORIAL8; + eo = rand() % POW2TO11; + co = rand() % POW3TO7; if (!strcmp(args->scrtype, "eo")) { eo = 0; } else if (!strcmp(args->scrtype, "corners")) { eo = 0; ep = 0; - index_to_perm(cp, 8, a); - if (perm_sign(a, 8) == 1) { - swap(&a[0], &a[1]); - cp = perm_to_index(a, 8); - } } else if (!strcmp(args->scrtype, "edges")) { co = 0; cp = 0; - index_to_perm(ep, 12, a); - if (perm_sign(a, 12) == 1) { - swap(&a[0], &a[1]); - ep = perm_to_index(a, 12); - } } - cube = fourval_to_cube(eo, ep, co, cp); + + make_solved(&cube); + index_to_perm(ep, 12, cube.ep); + index_to_perm(cp, 8, cube.cp); + int_to_sum_zero_array(eo, 2, 12, cube.eo); + int_to_sum_zero_array(co, 3, 8, cube.co); + } + + if (!is_admissible(&cube)) { + if (!strcmp(args->scrtype, "corners")) + swap(&cube.cp[UFR], &cube.cp[UFL]); + else + swap(&cube.ep[UF], &cube.ep[UB]); } /* TODO: can be optimized for htr and dr using htrfin, drfin */ - scr = solve_2phase(cube, 1); + scr = solve_2phase(&cube, 1); if (!strcmp(args->scrtype, "fmc")) { aux = new_alg(""); @@ -513,23 +314,22 @@ scramble_exec(CommandArgs *args) } } -static void +void gen_exec(CommandArgs *args) { +/* TODO: int i; fprintf(stderr, "Generating coordinates...\n"); - init_all_movesets(); - init_symcoord(); - fprintf(stderr, "Generating pruning tables...\n"); for (i = 0; all_pd[i] != NULL; i++) genptable(all_pd[i], args->opts->nthreads); +*/ fprintf(stderr, "Done!\n"); } -static void +void invert_exec(CommandArgs *args) { Alg *inv; @@ -540,7 +340,7 @@ invert_exec(CommandArgs *args) free_alg(inv); } -static void +void steps_exec(CommandArgs *args) { int i; @@ -549,7 +349,7 @@ steps_exec(CommandArgs *args) printf("%-15s %s\n", steps[i]->shortname, steps[i]->name); } -static void +void commands_exec(CommandArgs *args) { int i; @@ -559,9 +359,10 @@ commands_exec(CommandArgs *args) } -static void +void freemem_exec(CommandArgs *args) { +/* TODO: int i; for (i = 0; all_pd[i] != NULL; i++) @@ -569,35 +370,34 @@ freemem_exec(CommandArgs *args) for (i = 0; all_sd[i] != NULL; i++) free_sd(all_sd[i]); - - /* TODO: invtables are also large, but for now they are * - * statically allocated. Consider releasing those too. */ +*/ } -static void +void print_exec(CommandArgs *args) { - init_moves(); - print_cube(apply_alg(args->scramble, (Cube){0})); + Cube c; + + make_solved(&c); + apply_alg(args->scramble, &c); + print_cube(&c); } -static void +void twophase_exec(CommandArgs *args) { Cube c; Alg *sol; - init_all_movesets(); - init_symcoord(); - - c = apply_alg(args->scramble, (Cube){0}); - sol = solve_2phase(c, 1); + make_solved(&c); + apply_alg(args->scramble, &c); + sol = solve_2phase(&c, 1); print_alg(sol, false); free_alg(sol); } -static void +void help_exec(CommandArgs *args) { if (args->command == NULL) { @@ -619,26 +419,24 @@ help_exec(CommandArgs *args) } } -static void +void quit_exec(CommandArgs *args) { exit(0); } -static void +void cleanup_exec(CommandArgs *args) { Alg *alg; - init_moves(); - alg = cleanup(args->scramble); print_alg(alg, false); free_alg(alg); } -static void +void unniss_exec(CommandArgs *args) { Alg *aux; @@ -648,7 +446,7 @@ unniss_exec(CommandArgs *args) free(aux); } -static void +void version_exec(CommandArgs *args) { printf(VERSION"\n"); @@ -691,6 +489,8 @@ static bool read_scrtype(CommandArgs *args, char *str) { int i; + static char *scrtypes[20] = + { "eo", "corners", "edges", "fmc", "dr", "htr", NULL }; for (i = 0; scrtypes[i] != NULL; i++) { if (!strcmp(scrtypes[i], str)) { diff --git a/src/commands.h b/src/commands.h @@ -9,6 +9,198 @@ void free_args(CommandArgs *args); CommandArgs * new_args(); -extern Command * commands[]; +/* Arg parsing functions *****************************************************/ + +CommandArgs * gen_parse_args(int c, char **v); +CommandArgs * help_parse_args(int c, char **v); +CommandArgs * parse_only_scramble(int c, char **v); +CommandArgs * parse_no_arg(int c, char **v); +CommandArgs * solve_parse_args(int c, char **v); +CommandArgs * scramble_parse_args(int c, char **v); + +/* Exec functions ************************************************************/ + +void gen_exec(CommandArgs *args); +void cleanup_exec(CommandArgs *args); +void invert_exec(CommandArgs *args); +void solve_exec(CommandArgs *args); +void scramble_exec(CommandArgs *args); +void steps_exec(CommandArgs *args); +void commands_exec(CommandArgs *args); +void freemem_exec(CommandArgs *args); +void print_exec(CommandArgs *args); +void twophase_exec(CommandArgs *args); +void help_exec(CommandArgs *args); +void quit_exec(CommandArgs *args); +void unniss_exec(CommandArgs *args); +void version_exec(CommandArgs *args); + +/* Commands ******************************************************************/ + +#ifndef COMMANDS_C + +extern Command cleanup_cmd; +extern Command commands_cmd; +extern Command freemem_cmd; +extern Command gen_cmd; +extern Command help_cmd; +extern Command invert_cmd; +extern Command print_cmd; +extern Command quit_cmd; +extern Command scramble_cmd; +extern Command solve_cmd; +extern Command steps_cmd; +extern Command unniss_cmd; +extern Command version_cmd; + +extern Command *commands[]; + +#else + +Command +solve_cmd = { + .name = "solve", + .usage = "solve STEP [OPTIONS] SCRAMBLE", + .description = "Solve a step; see command steps for a list of steps", + .parse_args = solve_parse_args, + .exec = solve_exec +}; + +Command +scramble_cmd = { + .name = "scramble", + .usage = "scramble [TYPE] [-n N]", + .description = "Get a random-position scramble", + .parse_args = scramble_parse_args, + .exec = scramble_exec, +}; + +Command +gen_cmd = { + .name = "gen", + .usage = "gen [-t N]", + .description = "Generate all tables [using N threads]", + .parse_args = gen_parse_args, + .exec = gen_exec +}; + +Command +invert_cmd = { + .name = "invert", + .usage = "invert SCRAMBLE]", + .description = "Invert a scramble", + .parse_args = parse_only_scramble, + .exec = invert_exec, +}; + +Command +steps_cmd = { + .name = "steps", + .usage = "steps", + .description = "List available steps", + .parse_args = parse_no_arg, + .exec = steps_exec +}; + +Command +commands_cmd = { + .name = "commands", + .usage = "commands", + .description = "List available commands", + .parse_args = parse_no_arg, + .exec = commands_exec +}; + +Command +freemem_cmd = { + .name = "freemem", + .usage = "freemem", + .description = "free large tables from RAM", + .parse_args = parse_no_arg, + .exec = freemem_exec, +}; + +Command +print_cmd = { + .name = "print", + .usage = "print SCRAMBLE", + .description = "Print written description of the cube", + .parse_args = parse_only_scramble, + .exec = print_exec, +}; + +Command +help_cmd = { + .name = "help", + .usage = "help [COMMAND]", + .description = "Display nissy manual page or help on specific command", + .parse_args = help_parse_args, + .exec = help_exec, +}; + +Command +twophase_cmd = { + .name = "twophase", + .usage = "twophase", + .description = "Find a solution quickly using a 2-phase method", + .parse_args = parse_only_scramble, + .exec = twophase_exec, +}; + +Command +quit_cmd = { + .name = "quit", + .usage = "quit", + .description = "Quit nissy", + .parse_args = parse_no_arg, + .exec = quit_exec, +}; + +Command +cleanup_cmd = { + .name = "cleanup", + .usage = "cleanup SCRAMBLE", + .description = "Rewrite a scramble using only standard moves (HTM)", + .parse_args = parse_only_scramble, + .exec = cleanup_exec, +}; + +Command +unniss_cmd = { + .name = "unniss", + .usage = "unniss SCRAMBLE", + .description = "Rewrite a scramble without NISS", + .parse_args = parse_only_scramble, + .exec = unniss_exec, +}; + +Command +version_cmd = { + .name = "version", + .usage = "version", + .description = "print nissy version", + .parse_args = parse_no_arg, + .exec = version_exec, +}; + +Command *commands[] = { + &commands_cmd, + &freemem_cmd, + &gen_cmd, + &help_cmd, + &invert_cmd, + &print_cmd, + &quit_cmd, + &solve_cmd, + &scramble_cmd, + &steps_cmd, + &twophase_cmd, + &cleanup_cmd, + &unniss_cmd, + &version_cmd, + NULL +}; + +#endif #endif diff --git a/src/coord.c b/src/coord.c @@ -1,611 +1,683 @@ +#define COORD_C + #include "coord.h" -static uint64_t index_eofb(Cube cube); -static uint64_t index_eofbepos(Cube cube); -static uint64_t index_epud(Cube cube); -static uint64_t index_coud(Cube cube); -static uint64_t index_corners(Cube cube); -static uint64_t index_cp(Cube cube); -static uint64_t index_cphtr(Cube cube); -static uint64_t index_cornershtr(Cube cube); -static uint64_t index_cornershtrfin(Cube cube); -static uint64_t index_drud(Cube cube); -static uint64_t index_drud_eofb(Cube cube); -static uint64_t index_htr_drud(Cube cube); -static uint64_t index_htrfin(Cube cube); -static uint64_t index_cpud_separate(Cube cube); - -static uint64_t move_eofb(Move m, uint64_t ind); -static uint64_t move_eofbepos(Move m, uint64_t ind); -static uint64_t move_epud(Move m, uint64_t ind); -static uint64_t move_coud(Move m, uint64_t ind); -static uint64_t move_corners(Move m, uint64_t ind); -static uint64_t move_cp(Move m, uint64_t ind); -static uint64_t move_cphtr(Move m, uint64_t ind); -static uint64_t move_cornershtr(Move m, uint64_t ind); -static uint64_t move_cornershtrfin(Move m, uint64_t ind); -static uint64_t move_drud(Move m, uint64_t ind); -static uint64_t move_drud_eofb(Move m, uint64_t ind); -static uint64_t move_htr_drud(Move m, uint64_t ind); -static uint64_t move_htrfin(Move m, uint64_t ind); -static uint64_t move_cpud_separate(Move m, uint64_t ind); - -static void init_cphtr_cosets(); -static void init_cphtr_left_cosets_bfs(int i, int c); -static void init_cphtr_right_cosets_color(int i, int c); -static void init_cpud_separate(); -static void init_cornershtrfin(); -static void init_htr_eposs(); - - -/* All sorts of useful costants and tables **********************************/ - -static int cphtr_left_cosets[FACTORIAL8]; -static int cphtr_right_cosets[FACTORIAL8]; -static int cphtr_right_rep[BINOM8ON4*6]; -int cpud_separate_ind[FACTORIAL8]; -int cpud_separate_ant[BINOM8ON4]; -static int cornershtrfin_ind[FACTORIAL8]; -int cornershtrfin_ant[24*24/6]; -static int htr_eposs_ind[BINOM12ON4]; -static int htr_eposs_ant[BINOM8ON4]; - -/* Coordinates and their implementation **************************************/ - -Coordinate -coord_eofb = { - .index = index_eofb, - .max = POW2TO11, - .move = move_eofb, -}; - -Coordinate -coord_eofbepos = { - .index = index_eofbepos, - .max = POW2TO11 * BINOM12ON4, - .move = move_eofbepos, -}; - -Coordinate -coord_coud = { - .index = index_coud, - .max = POW3TO7, - .move = move_coud, -}; - -Coordinate -coord_corners = { - .index = index_corners, - .max = POW3TO7 * FACTORIAL8, - .move = move_corners, -}; - -Coordinate -coord_cp = { - .index = index_cp, - .max = FACTORIAL8, - .move = move_cp, -}; - -Coordinate -coord_cphtr = { - .index = index_cphtr, - .max = BINOM8ON4 * 6, - .move = move_cphtr, -}; - -Coordinate -coord_cornershtr = { - .index = index_cornershtr, - .max = POW3TO7 * BINOM8ON4 * 6, - .move = move_cornershtr, -}; - -Coordinate -coord_cornershtrfin = { - .index = index_cornershtrfin, - .max = 24*24/6, - .move = move_cornershtrfin, -}; - -Coordinate -coord_epud = { - .index = index_epud, - .max = FACTORIAL8, - .move = move_epud, -}; - -Coordinate -coord_drud = { - .index = index_drud, - .max = POW2TO11 * POW3TO7 * BINOM12ON4, - .move = move_drud, -}; - -Coordinate -coord_htr_drud = { - .index = index_htr_drud, - .max = BINOM8ON4 * 6 * BINOM8ON4, - .move = move_htr_drud, -}; - -Coordinate -coord_htrfin = { - .index = index_htrfin, - .max = 24 * 24 * 24 *24 * 24 / 6, /* should be /12 but it's ok */ - .move = move_htrfin, -}; - -Coordinate -coord_drud_eofb = { - .index = index_drud_eofb, - .max = POW3TO7 * BINOM12ON4, - .move = move_drud_eofb, -}; - -Coordinate -coord_cpud_separate = { - .index = index_cpud_separate, - .max = BINOM8ON4, - .move = move_cpud_separate, -}; +static uint64_t indexers_getind(Indexer **is, Cube *c); +static uint64_t indexers_getmax(Indexer **is); +static void indexers_makecube(Indexer **is, uint64_t ind, Cube *c); +static void gen_coord_comp(Coordinate *coord); +static void gen_coord_sym(Coordinate *coord); +static bool read_coord_mtable(Coordinate *coord); +static bool read_coord_sd(Coordinate *coord); +static bool read_coord_ttable(Coordinate *coord); +static bool write_coord_mtable(Coordinate *coord); +static bool write_coord_sd(Coordinate *coord); +static bool write_coord_ttable(Coordinate *coord); /* Indexers ******************************************************************/ -static uint64_t -index_eofb(Cube cube) +uint64_t +index_eofb(Cube *cube) { - return cube.eofb; + return (uint64_t)digit_array_to_int(cube->eo, 11, 2); } -static uint64_t -index_eofbepos(Cube cube) +uint64_t +index_coud(Cube *cube) { - return (cube.epose / FACTORIAL4) * POW2TO11 + cube.eofb; + return (uint64_t)digit_array_to_int(cube->co, 7, 3); } -static uint64_t -index_epud(Cube cube) +uint64_t +index_cp(Cube *cube) +{ + return (uint64_t)perm_to_index(cube->cp, 8); +} + +uint64_t +index_cpudsep(Cube *cube) { - uint64_t ret; - CubeArray *arr = new_cubearray(cube, pf_ep); + int i, c[8]; - ret = perm_to_index(arr->ep, 8); - free_cubearray(arr, pf_ep); + for (i = 0; i < 8; i++) + c[i] = cube->cp[i] < 4 ? 0 : 1; - return ret; + return (uint64_t)subset_to_index(c, 8, 4); } -static uint64_t -index_coud(Cube cube) +uint64_t +index_epe(Cube *cube) { - return cube.coud; + 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_corners(Cube cube) +uint64_t +index_epud(Cube *cube) { - return cube.coud * FACTORIAL8 + cube.cp; + return (uint64_t)perm_to_index(cube->ep, 8); } -static uint64_t -index_cp(Cube cube) +uint64_t +index_epos(Cube *cube) { - return cube.cp; + 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_cphtr(Cube cube) +uint64_t +index_eposepe(Cube *cube) { - return cphtr_right_cosets[cube.cp]; + 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 uint64_t -index_cornershtr(Cube cube) +/* Inverse indexers **********************************************************/ + +void +invindex_eofb(uint64_t ind, Cube *cube) { - return cube.coud * BINOM8ON4 * 6 + index_cphtr(cube); + int_to_sum_zero_array(ind, 2, 12, cube->eo); } -static uint64_t -index_cornershtrfin(Cube cube) +void +invindex_coud(uint64_t ind, Cube *cube) { - return cornershtrfin_ind[cube.cp]; + int_to_sum_zero_array(ind, 3, 8, cube->co); } -static uint64_t -index_drud(Cube cube) +void +invindex_cp(uint64_t ind, Cube *cube) { - uint64_t a, b, c; - - a = cube.eofb; - b = cube.coud; - c = cube.epose / FACTORIAL4; + index_to_perm(ind, 8, cube->cp); +} - b *= POW2TO11; - c *= POW2TO11 * POW3TO7; +void +invindex_cpudsep(uint64_t ind, Cube *cube) +{ + int i, j, k, c[8]; - return a + b + c; + index_to_subset(ind, 8, 4, c); + for (i = 0, j = 0, k = 4; i < 8; i++) + cube->cp[i] = c[i] == 0 ? j++ : k++; } -static uint64_t -index_drud_eofb(Cube cube) + +void +invindex_epe(uint64_t ind, Cube *cube) { - return index_drud(cube) / POW2TO11; + int i; + + index_to_perm(ind, 4, &cube->ep[8]); + for (i = 0; i < 4; i++) + cube->ep[i+8] += 8; } -static uint64_t -index_htr_drud(Cube cube) +void +invindex_epud(uint64_t ind, Cube *cube) { - uint64_t a, b; + index_to_perm(ind, 8, cube->ep); +} - a = index_cphtr(cube); - b = htr_eposs_ind[cube.eposs/24]; +void +invindex_epos(uint64_t ind, Cube *cube) +{ + int i, j, k; - return a * BINOM8ON4 + b; + index_to_subset(ind, 12, 4, cube->ep); + for (i = 0, j = 0, k = 8; i < 12; i++) + if (cube->ep[i] == 0) + cube->ep[i] = j++; + else + cube->ep[i] = k++; } -static uint64_t -index_htrfin(Cube cube) +void +invindex_eposepe(uint64_t ind, Cube *cube) { - uint64_t epe, eps, epm, cp, ep; + int i, j, k, e[4]; + uint64_t epos, epe; + + epos = ind / FACTORIAL4; + epe = ind % FACTORIAL4; - epe = cube.epose % 24; - eps = cube.eposs % 24; - epm = cube.eposm % 24; - ep = (epe * 24 + eps) *24 + epm; - cp = index_cornershtrfin(cube); + index_to_subset(epos, 12, 4, cube->ep); + index_to_perm(epe, 4, e); - return cp * 24 * 24 * 24 + ep; + 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; } +/* Other local functions *****************************************************/ + static uint64_t -index_cpud_separate(Cube cube) +indexers_getmax(Indexer **is) { - return cpud_separate_ind[cube.cp]; -} + int i; + uint64_t max = 1; -/* Coordinate movers *********************************************************/ + for (i = 0; is[i] != NULL; i++) + max *= is[i]->n; + + return max; +} static uint64_t -move_eofb(Move m, uint64_t ind) +indexers_getind(Indexer **is, Cube *c) { - return eofb_mtable[m][ind]; + int i; + uint64_t max = 0; + + for (i = 0; is[i] != NULL; i++) { + max *= is[i]->n; + max += is[i]->index(c); + } + + return max; } -static uint64_t -move_eofbepos(Move m, uint64_t ind) +static void +indexers_makecube(Indexer **is, uint64_t ind, Cube *c) { - uint64_t a, b; + /* Warning: anti-indexers are applied in the same order as indexers. */ + /* We assume order does not matter, but it would make more sense to */ + /* Apply them in reverse. */ - a = epose_mtable[m][(ind / POW2TO11)*24]; - b = eofb_mtable[m][ind % POW2TO11]; + int i; + uint64_t m; - return (a/24) * POW2TO11 + b; + make_solved(c); + m = indexers_getmax(is); + for (i = 0; is[i] != NULL; i++) { + m /= is[i]->n; + is[i]->to_cube(ind / m, c); + ind %= m; + } } -static uint64_t -move_epud(Move m, uint64_t ind) -{ - /* TODO: save to file? */ - static bool initialized = false; - static int a[12] = { [8] = 8, [9] = 9, [10] = 10, [11] = 11 }; - static int shortlist[NMOVES] = { - [U] = 0, [U2] = 1, [U3] = 2, [D] = 3, [D2] = 4, [D3] = 5, - [R2] = 6, [L2] = 7, [F2] = 8, [B2] = 9 - }; - static uint64_t aux[10][FACTORIAL8]; +static void +gen_coord_comp(Coordinate *coord) +{ uint64_t ui; - int j; - Move mj; - Cube c; - CubeArray *arr, *auxarr; + Cube c, mvd; + Move m; + Trans t; - if (!moveset_drud.allowed(m)) { - fprintf(stderr, "Move not allowed for epud\n" - "This is a bug, please report\n"); - return coord_epud.max; - } + coord->max = indexers_getmax(coord->i); + + for (m = 0; m < NMOVES; m++) + coord->mtable[m] = malloc(coord->max * sizeof(uint64_t)); + + for (t = 0; t < NTRANS; t++) + coord->ttable[t] = malloc(coord->max * sizeof(uint64_t)); + + if (!read_coord_mtable(coord)) { + fprintf(stderr, "%s: generating mtable\n", coord->name); - if (!initialized) { - auxarr = malloc(sizeof(CubeArray)); - auxarr->ep = a; - for (ui = 0; ui < coord_epud.max; ui++) { - index_to_perm(ui, 8, a); - c = arrays_to_cube(auxarr, pf_ep); - for (j = 0; moveset_drud.sorted_moves[j] != NULLMOVE; - j++) { - mj = moveset_drud.sorted_moves[j]; - arr = new_cubearray(apply_move(mj, c), pf_ep); - aux[shortlist[mj]][ui] = - perm_to_index(arr->ep, 8); - free_cubearray(arr, pf_ep); + for (ui = 0; ui < coord->max; ui++) { + indexers_makecube(coord->i, ui, &c); + for (m = 0; m < NMOVES; m++) { + copy_cube(&c, &mvd); + apply_move(m, &mvd); + coord->mtable[m][ui] = + indexers_getind(coord->i, &mvd); } } - free(auxarr); - - initialized = true; + if (!write_coord_mtable(coord)) + fprintf(stderr, "%s: error writing mtable\n", + coord->name); + + fprintf(stderr, "%s: mtable generated\n", coord->name); } - return aux[shortlist[m]][ind]; -} + if (!read_coord_ttable(coord)) { + fprintf(stderr, "%s: generating ttable\n", coord->name); -static uint64_t -move_coud(Move m, uint64_t ind) -{ - return coud_mtable[m][ind]; + for (ui = 0; ui < coord->max; ui++) { + indexers_makecube(coord->i, ui, &c); + for (t = 0; t < NTRANS; t++) { + copy_cube(&c, &mvd); + apply_trans(t, &mvd); + coord->ttable[t][ui] = + indexers_getind(coord->i, &mvd); + } + } + if (!write_coord_ttable(coord)) + fprintf(stderr, "%s: error writing ttable\n", + coord->name); + } } -static uint64_t -move_corners(Move m, uint64_t ind) +static void +gen_coord_sym(Coordinate *coord) { - uint64_t a, b; + uint64_t i, in, ui, uj, uu, M, nr; + int j; + Move m; + Trans t; - a = coud_mtable[m][ind / FACTORIAL8]; - b = cp_mtable[m][ind % FACTORIAL8]; + M = coord->base[0]->max; + coord->selfsim = malloc(M * sizeof(uint64_t)); + coord->symclass = malloc(M * sizeof(uint64_t)); + coord->symrep = malloc(M * sizeof(uint64_t)); + coord->transtorep = malloc(M * sizeof(Trans)); - return a * FACTORIAL8 + b; -} + if (!read_coord_sd(coord)) { + fprintf(stderr, "%s: generating syms\n", coord->name); -static uint64_t -move_cp(Move m, uint64_t ind) -{ - return cp_mtable[m][ind]; -} + for (i = 0; i < M; i++) + coord->symclass[i] = M+1; -static uint64_t -move_cphtr(Move m, uint64_t ind) -{ - static bool initialized = false; - static uint64_t aux[NMOVES][BINOM8ON4*6]; - uint64_t ui; - Move j; + for (i = 0, nr = 0; i < M; i++) { + if (coord->symclass[i] != M+1) + continue; - if (!initialized) { - for (ui = 0; ui < BINOM8ON4*6; ui++) - for (j = U; j < NMOVES; j++) - aux[j][ui] = cphtr_right_cosets[ - cp_mtable[j][cphtr_right_rep[ui]]]; + coord->symrep[nr] = i; + coord->transtorep[i] = uf; + coord->selfsim[nr] = (uint64_t)0; + for (j = 0; j < coord->tgrp->n; j++) { + t = coord->tgrp->t[j]; + in = trans_coord(coord->base[0], t, i); + coord->symclass[in] = nr; + if (in == i) + coord->selfsim[nr] |= ((uint64_t)1<<t); + else + coord->transtorep[in] = + inverse_trans(t); + } + nr++; + } - initialized = true; + coord->max = nr; + + fprintf(stderr, "%s: found %" PRIu64 " classes\n", + coord->name, nr); + if (!write_coord_sd(coord)) + fprintf(stderr, "%s: error writing symdata\n", + coord->name); } - return aux[m][ind]; + coord->symrep = realloc(coord->symrep, coord->max*sizeof(uint64_t)); + coord->selfsim = realloc(coord->selfsim, coord->max*sizeof(uint64_t)); + + for (m = 0; m < NMOVES; m++) { + coord->mtable[m] = malloc(coord->max*sizeof(uint64_t)); + coord->ttrep_move[m] = malloc(coord->max*sizeof(Trans)); + } + + if (!read_coord_mtable(coord)) { + for (ui = 0; ui < coord->max; ui++) { + uu = coord->symrep[ui]; + for (m = 0; m < NMOVES; m++) { + uj = move_coord(coord->base[0], m, uu, NULL); + coord->mtable[m][ui] = coord->symclass[uj]; + coord->ttrep_move[m][ui] = + coord->transtorep[uj]; + } + } + if (!write_coord_mtable(coord)) + fprintf(stderr, "%s: error writing mtable\n", + coord->name); + } } -static uint64_t -move_cornershtr(Move m, uint64_t ind) +static bool +read_coord_mtable(Coordinate *coord) { - uint64_t a, b; + FILE *f; + char fname[strlen(tabledir)+256]; + Move m; + uint64_t M; + bool r; + + strcpy(fname, tabledir); + strcat(fname, "/mt_"); + strcat(fname, coord->name); + + if ((f = fopen(fname, "rb")) == NULL) + return false; - a = coud_mtable[m][ind/(BINOM8ON4 * 6)]; - b = move_cphtr(m, ind % (BINOM8ON4 * 6)); + M = coord->max; + r = true; + for (m = 0; m < NMOVES; m++) + r = r && fread(coord->mtable[m], sizeof(uint64_t), M, f) == M; - return a * BINOM8ON4 * 6 + b; + if (coord->type == SYM_COORD) + for (m = 0; m < NMOVES; m++) + r = r && fread(coord->ttrep_move[m], + sizeof(Trans), M, f) == M; + + fclose(f); + return r; } -static uint64_t -move_cornershtrfin(Move m, uint64_t ind) +static bool +read_coord_sd(Coordinate *coord) { - int a; + FILE *f; + char fname[strlen(tabledir)+256]; + uint64_t M, N; + bool r; + + strcpy(fname, tabledir); + strcat(fname, "/sd_"); + strcat(fname, coord->name); - a = cp_mtable[m][cornershtrfin_ant[ind]]; + if ((f = fopen(fname, "rb")) == NULL) + return false; - return cornershtrfin_ind[a]; + r = true; + r = r && fread(&coord->max, sizeof(uint64_t), 1, f) == 1; + M = coord->max; + N = coord->base[0]->max; + r = r && fread(coord->symrep, sizeof(uint64_t), M, f) == M; + r = r && fread(coord->selfsim, sizeof(uint64_t), M, f) == M; + r = r && fread(coord->symclass, sizeof(uint64_t), N, f) == N; + r = r && fread(coord->transtorep, sizeof(Trans), N, f) == N; + + fclose(f); + return r; } -static uint64_t -move_drud(Move m, uint64_t ind) +static bool +read_coord_ttable(Coordinate *coord) { - uint64_t a, b, c; + FILE *f; + char fname[strlen(tabledir)+256]; + Trans t; + uint64_t M; + bool r; - a = eofb_mtable[m][ind % POW2TO11]; - b = coud_mtable[m][(ind / POW2TO11) % POW3TO7]; - c = epose_mtable[m][ind / (POW2TO11 * POW3TO7)]; + strcpy(fname, tabledir); + strcat(fname, "/tt_"); + strcat(fname, coord->name); - return a + (b + c * POW3TO7) * POW2TO11; + if ((f = fopen(fname, "rb")) == NULL) + return false; + + M = coord->max; + r = true; + for (t = 0; t < NTRANS; t++) + r = r && fread(coord->ttable[t], sizeof(uint64_t), M, f) == M; + + fclose(f); + return r; } -static uint64_t -move_drud_eofb(Move m, uint64_t ind) +static bool +write_coord_mtable(Coordinate *coord) { - uint64_t a, b; + FILE *f; + char fname[strlen(tabledir)+256]; + Move m; + uint64_t M; + bool r; - a = coud_mtable[m][ind % POW3TO7]; - b = epose_mtable[m][(ind / POW3TO7) * 24] / 24; + strcpy(fname, tabledir); + strcat(fname, "/mt_"); + strcat(fname, coord->name); - return a + b * POW3TO7; + if ((f = fopen(fname, "wb")) == NULL) + return false; + + M = coord->max; + r = true; + for (m = 0; m < NMOVES; m++) + r = r && fwrite(coord->mtable[m], sizeof(uint64_t), M, f) == M; + + if (coord->type == SYM_COORD) + for (m = 0; m < NMOVES; m++) + r = r && fwrite(coord->ttrep_move[m], + sizeof(Trans), M, f) == M; + + fclose(f); + return r; } -static uint64_t -move_htr_drud(Move m, uint64_t ind) +static bool +write_coord_sd(Coordinate *coord) { - uint64_t a, b; + FILE *f; + char fname[strlen(tabledir)+256]; + uint64_t M, N; + bool r; + + strcpy(fname, tabledir); + strcat(fname, "/sd_"); + strcat(fname, coord->name); - a = move_cphtr(m, ind/BINOM8ON4); - b = eposs_mtable[m][htr_eposs_ant[ind%BINOM8ON4]]; + if ((f = fopen(fname, "wb")) == NULL) + return false; - return a*BINOM8ON4 + htr_eposs_ind[b/24]; + r = true; + M = coord->max; + N = coord->base[0]->max; + r = r && fwrite(&coord->max, sizeof(uint64_t), 1, f) == 1; + r = r && fwrite(coord->symrep, sizeof(uint64_t), M, f) == M; + r = r && fwrite(coord->selfsim, sizeof(uint64_t), M, f) == M; + r = r && fwrite(coord->symclass, sizeof(uint64_t), N, f) == N; + r = r && fwrite(coord->transtorep, sizeof(Trans), N, f) == N; + + fclose(f); + return r; } -static uint64_t -move_htrfin(Move m, uint64_t ind) +static bool +write_coord_ttable(Coordinate *coord) { - uint64_t a, b, bm, bs, be; + FILE *f; + char fname[strlen(tabledir)+256]; + Trans t; + uint64_t M; + bool r; + + strcpy(fname, tabledir); + strcat(fname, "/tt_"); + strcat(fname, coord->name); + + if ((f = fopen(fname, "wb")) == NULL) + return false; - a = move_cornershtrfin(m, ind / (24*24*24)); - bm = eposm_mtable[m][ind%24] % 24; - bs = eposs_mtable[m][(ind/24)%24] % 24; - be = epose_mtable[m][(ind/(24*24))%24] % 24; - b = (be * 24 + bs) * 24 + bm; + M = coord->max; + r = true; + for (t = 0; t < NTRANS; t++) + r = r && fwrite(coord->ttable[t], sizeof(uint64_t), M, f) == M; - return a * (24*24*24) + b; + fclose(f); + return r; } -static uint64_t -move_cpud_separate(Move m, uint64_t ind) -{ - return cpud_separate_ind[cp_mtable[m][cpud_separate_ant[ind]]]; -} - -/* 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() +/* Public functions **********************************************************/ + +void +gen_coord(Coordinate *coord) { - unsigned int i; - int c = 0, d = 0; + int i; - for (i = 0; i < FACTORIAL8; i++) { - cphtr_left_cosets[i] = -1; - cphtr_right_cosets[i] = -1; + if (coord == NULL || coord->generated) + return; + + for (i = 0; i < 2; i++) + gen_coord(coord->base[i]); + + switch (coord->type) { + case COMP_COORD: + if (coord->i[0] == NULL) + goto error_gc; + gen_coord_comp(coord); + break; + case SYM_COORD: + if (coord->base[0] == NULL || coord->tgrp == NULL) + goto error_gc; + gen_coord_sym(coord); + break; + case SYMCOMP_COORD: + if (coord->base[0] == NULL || coord->base[1] == NULL) + goto error_gc; + coord->max = coord->base[0]->max * coord->base[1]->max; + break; + default: + break; } - /* 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++); + coord->generated = true; + return; - /* 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++); +error_gc: + fprintf(stderr, "Error generating coordinates.\n" + "This is a bug, pleae report.\n"); + exit(1); } -static void -init_cphtr_left_cosets_bfs(int i, int c) +uint64_t +index_coord(Coordinate *coord, Cube *cube, Trans *offtrans) { - int j, jj, next[FACTORIAL8], next2[FACTORIAL8], n, n2; + uint64_t c[2], cnosym; + Trans ttr; - Move k; + switch (coord->type) { + case COMP_COORD: + if (offtrans != NULL) + *offtrans = uf; - n = 1; - next[0] = i; - cphtr_left_cosets[i] = c; + return indexers_getind(coord->i, cube); + case SYM_COORD: + cnosym = index_coord(coord->base[0], cube, NULL); + ttr = coord->transtorep[cnosym]; - while (n != 0) { - for (j = 0, n2 = 0; j < n; j++) { - for (k = U2; k < B3; k++) { - if (!moveset_htr.allowed(k)) - continue; - jj = apply_move(k, (Cube){ .cp = next[j] }).cp; + if (offtrans != NULL) + *offtrans = ttr; - if (cphtr_left_cosets[jj] == -1) { - cphtr_left_cosets[jj] = c; - next2[n2++] = jj; - } - } - } + return coord->symclass[cnosym]; + case SYMCOMP_COORD: + c[0] = index_coord(coord->base[0], cube, NULL); + cnosym = index_coord(coord->base[0]->base[0], cube, NULL); + ttr = coord->base[0]->transtorep[cnosym]; + c[1] = index_coord(coord->base[1], cube, NULL); + c[1] = trans_coord(coord->base[1], ttr, c[1]); - for (j = 0; j < n2; j++) - next[j] = next2[j]; - n = n2; + if (offtrans != NULL) + *offtrans = ttr; + + return c[0] * coord->base[1]->max + c[1]; + default: + break; } + + return coord->max; /* Only reached in case of error */ } -static void -init_cphtr_right_cosets_color(int i, int d) +uint64_t +move_coord(Coordinate *coord, Move m, uint64_t ind, Trans *offtrans) { - int cp; - unsigned int j; + uint64_t i[2], M; + Trans ttr; - cphtr_right_rep[d] = i; - for (j = 0; j < FACTORIAL8; j++) { - if (cphtr_left_cosets[j] == 0) { - cp = compose((Cube){.cp = i}, (Cube){.cp = j}).cp; - cphtr_right_cosets[cp] = d; - } - } -} + /* Some safety checks should be done here, but for performance * + * reasons we'd rather do them before calling this function. * + * We should check if coord is generated. */ -static void -init_cpud_separate() -{ - unsigned int ui; - int i, co[8]; + switch (coord->type) { + case COMP_COORD: + if (offtrans != NULL) + *offtrans = uf; + + return coord->mtable[m][ind]; + case SYM_COORD: + ttr = coord->ttrep_move[m][ind]; - for (ui = 0; ui < FACTORIAL8; ui++) { - for (i = 0; i < 8; i++) - co[i] = what_corner_at((Cube){.cp=ui},i)>UBR ? 1 : 0; - cpud_separate_ind[ui] = subset_to_index(co, 8, 4); - cpud_separate_ant[cpud_separate_ind[ui]] = ui; + if (offtrans != NULL) + *offtrans = ttr; + + return coord->mtable[m][ind]; + case SYMCOMP_COORD: + M = coord->base[1]->max; + i[0] = ind / M; + i[1] = ind % M; + ttr = coord->base[0]->ttrep_move[m][i[0]]; + i[0] = coord->base[0]->mtable[m][i[0]]; + i[1] = coord->base[1]->mtable[m][i[1]]; + i[1] = coord->base[1]->ttable[ttr][i[1]]; + + if (offtrans != NULL) + *offtrans = ttr; + + return i[0] * M + i[1]; + default: + break; } + + return coord->max; /* Only reached in case of error */ } -static void -init_cornershtrfin() +bool +test_coord(Coordinate *coord) { - unsigned int i, j; - int n, c; - Move m; + uint64_t ui, uj; + Cube c; - for (i = 0; i < FACTORIAL8; i++) - cornershtrfin_ind[i] = -1; - cornershtrfin_ind[0] = 0; + if (coord->type != COMP_COORD) { + fprintf(stderr, "Can only test COMP_COORD\n"); + return false; + } - /* 10-pass, I think 5 is enough, but just in case */ - n = 1; - for (i = 0; i < 10; i++) { - for (j = 0; j < FACTORIAL8; j++) { - if (cornershtrfin_ind[j] == -1) - continue; - for (m = U; m < NMOVES; m++) { - if (moveset_htr.allowed(m)) { - c = cp_mtable[m][j]; - if (cornershtrfin_ind[c] == -1) { - cornershtrfin_ind[c] = n; - cornershtrfin_ant[n] = c; - n++; - } - } - } + gen_coord(coord); + for (ui = 0; ui < coord->max; ui++) { + indexers_makecube(coord->i, ui, &c); + uj = indexers_getind(coord->i, &c); + if (ui != uj) { + fprintf(stderr, "%s: error: %" PRIu64 " different" + " from %" PRIu64 "\n", coord->name, uj, ui); + return false; } } -} -void -init_htr_eposs() -{ - int ep[12], ep2[12]; - int eps_solved[4] = {UL, UR, DL, DR}; - unsigned int i, j; - - for (i = 0; i < BINOM12ON4; i++) { - for (j = 0; j < 12; j++) - ep[j] = ep2[j] = 0; - epos_to_partial_ep(i*24, ep, eps_solved); - for (j = 0; j < 8; j++) - ep2[j/2 + 4*(j%2)] = ep[j] ? 1 : 0; - htr_eposs_ind[i] = subset_to_index(ep2, 8, 4); - htr_eposs_ant[htr_eposs_ind[i]] = i*24; - } + fprintf(stderr, "%s: test passed\n", coord->name); + return true; } -void -init_coord() +uint64_t +trans_coord(Coordinate *coord, Trans t, uint64_t ind) { - static bool initialized = false; - if (initialized) - return; - initialized = true; + uint64_t i[2], M; - init_trans(); + /* Some safety checks should be done here, but for performance * + * reasons we'd rather do them before calling this function. * + * We should check if coord is generated. */ - init_cphtr_cosets(); - init_cornershtrfin(); - init_htr_eposs(); - init_cpud_separate(); -} + switch (coord->type) { + case COMP_COORD: + return coord->ttable[t][ind]; + case SYM_COORD: + return ind; + case SYMCOMP_COORD: + M = coord->base[1]->max; + i[0] = ind / M; /* Always fixed */ + i[1] = ind % M; + i[1] = coord->base[1]->ttable[t][i[1]]; + return i[0] * M + i[1]; + default: + break; + } + return coord->max; /* Only reached in case of error */ +} diff --git a/src/coord.h b/src/coord.h @@ -3,26 +3,232 @@ #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; -extern Coordinate coord_cpud_separate; - -extern int cpud_separate_ant[BINOM8ON4]; -extern int cpud_separate_ind[FACTORIAL8]; -extern int cornershtrfin_ant[24*24/6]; - -void init_coord(); +void gen_coord(Coordinate *coord); +uint64_t index_coord(Coordinate *coord, Cube *cube, + Trans *offtrans); +uint64_t move_coord(Coordinate *coord, Move m, + uint64_t ind, Trans *offtrans); +bool test_coord(Coordinate *coord); +uint64_t trans_coord(Coordinate *coord, Trans t, uint64_t ind); + +/* Base coordinates and their index functions ********************************/ + +#ifndef COORD_C + +extern Coordinate coord_eofb; +extern Coordinate coord_coud; +extern Coordinate coord_cp; +extern Coordinate coord_cpudsep; +extern Coordinate coord_epos; +extern Coordinate coord_epe; +extern Coordinate coord_eposepe; +extern Coordinate coord_epud; +extern Coordinate coord_eofbepos; +extern Coordinate coord_coud_cpudsep; +extern Coordinate coord_eofbepos_sym16; +extern Coordinate coord_cp_sym16; +extern Coordinate coord_corners_sym16; +extern Coordinate coord_drud_sym16; +extern Coordinate coord_drudfin_noE_sym16; +extern Coordinate coord_nxopt31; + +#else + +/* Indexers ******************************************************************/ + +uint64_t index_eofb(Cube *cube); +void invindex_eofb(uint64_t ind, Cube *ret); +Indexer +i_eofb = { + .n = POW2TO11, + .index = index_eofb, + .to_cube = invindex_eofb, +}; + +uint64_t index_coud(Cube *cube); +void invindex_coud(uint64_t ind, Cube *ret); +Indexer +i_coud = { + .n = POW3TO7, + .index = index_coud, + .to_cube = invindex_coud, +}; + +uint64_t index_cp(Cube *cube); +void invindex_cp(uint64_t ind, Cube *ret); +Indexer +i_cp = { + .n = FACTORIAL8, + .index = index_cp, + .to_cube = invindex_cp, +}; + +uint64_t index_cpudsep(Cube *cube); +void invindex_cpudsep(uint64_t ind, Cube *ret); +Indexer +i_cpudsep = { + .n = BINOM8ON4, + .index = index_cpudsep, + .to_cube = invindex_cpudsep, +}; + +uint64_t index_epos(Cube *cube); +void invindex_epos(uint64_t ind, Cube *ret); +Indexer +i_epos = { + .n = BINOM12ON4, + .index = index_epos, + .to_cube = invindex_epos, +}; + +uint64_t index_epe(Cube *cube); +void invindex_epe(uint64_t ind, Cube *ret); +Indexer +i_epe = { + .n = FACTORIAL4, + .index = index_epe, + .to_cube = invindex_epe, +}; + +uint64_t index_eposepe(Cube *cube); +void invindex_eposepe(uint64_t ind, Cube *ret); +Indexer +i_eposepe = { + .n = BINOM12ON4 * FACTORIAL4, + .index = index_eposepe, + .to_cube = invindex_eposepe, +}; + +uint64_t index_epud(Cube *cube); +void invindex_epud(uint64_t ind, Cube *ret); +Indexer +i_epud = { + .n = FACTORIAL8, + .index = index_epud, + .to_cube = invindex_epud, +}; + +/* Composite coordinates *****************************************************/ + +Coordinate +coord_eofb = { + .name = "eofb", + .type = COMP_COORD, + .i = {&i_eofb, NULL}, +}; + +Coordinate +coord_coud = { + .name = "coud", + .type = COMP_COORD, + .i = {&i_coud, NULL}, +}; + +Coordinate +coord_cp = { + .name = "cp", + .type = COMP_COORD, + .i = {&i_cp, NULL}, +}; + +Coordinate +coord_cpudsep = { + .name = "cpudsep", + .type = COMP_COORD, + .i = {&i_cpudsep, NULL}, +}; + +Coordinate +coord_epos = { + .name = "epos", + .type = COMP_COORD, + .i = {&i_epos, NULL}, +}; + +Coordinate +coord_epe = { + .name = "epe", + .type = COMP_COORD, + .i = {&i_epe, NULL}, +}; + +Coordinate +coord_eposepe = { /* Has to be done by hand, hard compose epos + epe */ + .name = "eposepe", + .type = COMP_COORD, + .i = {&i_eposepe, NULL}, +}; + +Coordinate +coord_epud = { + .name = "epud", + .type = COMP_COORD, + .i = {&i_epud, NULL}, +}; + +Coordinate +coord_eofbepos = { + .name = "eofbepos", + .type = COMP_COORD, + .i = {&i_epos, &i_eofb, NULL}, +}; + +Coordinate +coord_coud_cpudsep = { + .name = "coud_cpudsep", + .type = COMP_COORD, + .i = {&i_coud, &i_cpudsep, NULL}, +}; + +/* Symcoordinates ************************************************************/ + +Coordinate +coord_eofbepos_sym16 = { + .name = "eofbepos_sym16", + .type = SYM_COORD, + .base = {&coord_eofbepos, NULL}, + .tgrp = &tgrp_udfix, +}; + +Coordinate +coord_cp_sym16 = { + .name = "cp_sym16", + .type = SYM_COORD, + .base = {&coord_cp, NULL}, + .tgrp = &tgrp_udfix, +}; + +/* "Symcomp" coordinates *****************************************************/ + +Coordinate +coord_corners_sym16 = { + .name = "corners_sym16", + .type = SYMCOMP_COORD, + .base = {&coord_cp_sym16, &coord_coud}, +}; + +Coordinate +coord_drud_sym16 = { + .name = "drud_sym16", + .type = SYMCOMP_COORD, + .base = {&coord_eofbepos_sym16, &coord_coud}, +}; + +Coordinate +coord_drudfin_noE_sym16 = { + .name = "drudfin_noE_sym16", + .type = SYMCOMP_COORD, + .base = {&coord_cp_sym16, &coord_epud}, +}; + +Coordinate +coord_nxopt31 = { + .name = "nxopt31", + .type = SYMCOMP_COORD, + .base = {&coord_eofbepos_sym16, &coord_coud_cpudsep}, +}; + +#endif #endif diff --git a/src/cube.c b/src/cube.c @@ -1,531 +1,121 @@ -#include "cube.h" - -/* Local functions ***********************************************************/ - -static void init_inverse(); -static bool read_invtables_file(); -static bool write_invtables_file(); - -/* Tables ********************************************************************/ +#define CUBE_C -static uint16_t eo_invtable_e[POW2TO11][BINOM12ON4*FACTORIAL4]; -static uint16_t eo_invtable_s[POW2TO11][BINOM12ON4*FACTORIAL4]; -static uint16_t eo_invtable_m[POW2TO11][BINOM12ON4*FACTORIAL4]; -static uint16_t co_invtable[POW3TO7][FACTORIAL8]; -static uint16_t cp_invtable[FACTORIAL8]; -static uint16_t cpos_invtable[FACTORIAL6]; - -/* Functions implementation **************************************************/ - -int -array_ep_to_epos(int *ep, int *ss) -{ - int epos[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - int eps[4]; - int i, j, is; - - for (i = 0, is = 0; i < 12; i++) { - for (j = 0; j < 4; j++) { - if (ep[i] == ss[j]) { - eps[is++] = j; - epos[i] = 1; - } - } - } - - for (i = 0; i < 4; i++) - swap(&epos[ss[i]], &epos[i+8]); - - return 24 * subset_to_index(epos, 12, 4) + perm_to_index(eps, 4); -} - -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; -} +#include "cube.h" -Cube -compose_filtered(Cube c2, Cube c1, PieceFilter f) +void +compose(Cube *c2, Cube *c1) { - CubeArray *arr = new_cubearray(c2, f); - Cube ret; + apply_permutation(c2->ep, c1->ep, 12); + apply_permutation(c2->ep, c1->eo, 12); + sum_arrays_mod(c2->eo, c1->eo, 12, 2); - ret = move_via_arrays(arr, c1, f); - free_cubearray(arr, f); + apply_permutation(c2->cp, c1->cp, 8); + apply_permutation(c2->cp, c1->co, 8); + sum_arrays_mod(c2->co, c1->co, 8, 3); - return ret; + apply_permutation(c2->xp, c1->xp, 6); } void -cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f) +copy_cube(Cube *src, Cube *dst) { - 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); + memcpy(dst->ep, src->ep, 12 * sizeof(int)); + memcpy(dst->eo, src->eo, 12 * sizeof(int)); + memcpy(dst->cp, src->cp, 8 * sizeof(int)); + memcpy(dst->co, src->co, 8 * sizeof(int)); + memcpy(dst->xp, src->xp, 6 * sizeof(int)); } -void -epos_to_compatible_ep(int epos, int *ep, int *ss) +bool +equal(Cube *c1, Cube *c2) { - int i, j, k, other[8]; - bool flag; + int i; for (i = 0; i < 12; i++) - ep[i] = -1; - - epos_to_partial_ep(epos, ep, ss); - - for (i = 0, j = 0; i < 12; i++) { - flag = false; - for (k = 0; k < 4; k++) - flag = flag || (i == ss[k]); - if (!flag) - other[j++] = i; - } - - for (i = 0, j = 0; i < 12; i++) - if (ep[i] == -1) - ep[i] = other[j++]; -} - -void -epos_to_partial_ep(int epos, int *ep, int *ss) -{ - int i, is, eposs[12], eps[4]; + if (c1->ep[i] != c2->ep[i] || c1->eo[i] != c2->eo[i]) + return false; - index_to_perm(epos % FACTORIAL4, 4, eps); - index_to_subset(epos / FACTORIAL4, 12, 4, eposs); + for (i = 0; i < 8; i++) + if (c1->cp[i] != c2->cp[i] || c1->co[i] != c2->co[i]) + return false; - for (i = 0; i < 4; i++) - swap(&eposs[ss[i]], &eposs[i+8]); + for (i = 0; i < 6; i++) + if (c1->xp[i] != c2->xp[i]) + return false; - for (i = 0, is = 0; i < 12; i++) - if (eposs[i]) - ep[i] = ss[eps[is++]]; + return true; } void -fix_eorleoud(CubeArray *arr) +invert_cube(Cube *cube) { + Cube aux; int i; + copy_cube(cube, &aux); + for (i = 0; i < 12; i++) { - if ((edge_slice(i) == 0 && edge_slice(arr->ep[i]) != 0) || - (edge_slice(i) != 0 && edge_slice(arr->ep[i]) == 0)) { - arr->eorl[i] = 1 - arr->eofb[i]; - } else { - arr->eorl[i] = arr->eofb[i]; - } - - if ((edge_slice(i) == 2 && edge_slice(arr->ep[i]) != 2) || - (edge_slice(i) != 2 && edge_slice(arr->ep[i]) == 2)) { - arr->eoud[i] = 1 - arr->eofb[i]; - } else { - arr->eoud[i] = arr->eofb[i]; - } + cube->ep[aux.ep[i]] = i; + cube->eo[aux.ep[i]] = aux.eo[i]; } -} - -void -fix_cofbcorl(CubeArray *arr) -{ - int i; for (i = 0; i < 8; i++) { - if (i % 2 == arr->cp[i] % 2) { - arr->cofb[i] = arr->coud[i]; - arr->corl[i] = arr->coud[i]; - } else { - if (arr->cp[i] % 2 == 0) { - arr->cofb[i] = (arr->coud[i]+1)%3; - arr->corl[i] = (arr->coud[i]+2)%3; - } else { - arr->cofb[i] = (arr->coud[i]+2)%3; - arr->corl[i] = (arr->coud[i]+1)%3; - } - } + cube->cp[aux.cp[i]] = i; + cube->co[aux.cp[i]] = (3 - aux.co[i]) % 3; } -} - -Cube -fourval_to_cube(int eofb, int ep, int coud, int cp) -{ - CubeArray *arr; - - arr = new_cubearray((Cube){0}, pf_all); - - index_to_perm(ep, 12, arr->ep); - index_to_perm(cp, 8, arr->cp); - int_to_sum_zero_array(eofb, 2, 12, arr->eofb); - int_to_sum_zero_array(coud, 3, 8, arr->coud); - /* fix parity */ - if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8)) - swap(&(arr->ep[0]), &(arr->ep[1])); - - fix_eorleoud(arr); - fix_cofbcorl(arr); - - return arrays_to_cube(arr, pf_all); -} - -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; -} - -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 inv; - Cube ret; - int i, ep[12]; - - for (i = 0; i < 12; i++) - ep[i] = where_is_edge(cube, i); - inv = (CubeArray){.ep = ep}; - ret = arrays_to_cube(&inv, pf_ep); - - ret.eofb = ((int)eo_invtable_e[cube.eofb][cube.epose]) | - ((int)eo_invtable_m[cube.eofb][cube.eposm]) | - ((int)eo_invtable_s[cube.eofb][cube.eposs]); - ret.eorl = ((int)eo_invtable_e[cube.eorl][cube.epose]) | - ((int)eo_invtable_m[cube.eorl][cube.eposm]) | - ((int)eo_invtable_s[cube.eorl][cube.eposs]); - ret.eoud = ((int)eo_invtable_e[cube.eoud][cube.epose]) | - ((int)eo_invtable_m[cube.eoud][cube.eposm]) | - ((int)eo_invtable_s[cube.eoud][cube.eposs]); - ret.cp = cp_invtable[cube.cp]; - ret.cpos = cpos_invtable[cube.cpos]; - ret.coud = co_invtable[cube.coud][cube.cp]; - ret.corl = co_invtable[cube.corl][cube.cp]; - ret.cofb = co_invtable[cube.cofb][cube.cp]; - - return ret; + for (i = 0; i < 6; i++) + cube->xp[aux.xp[i]] = i; } bool -is_admissible(Cube cube) { - - /* TODO: this should check consistency of different orientations */ - /* check also that centers are opposite and admissible */ - - CubeArray *a = new_cubearray(cube, pf_all); - int parity; +is_admissible(Cube *c) { bool perm; + int sign, i; + int sum_e, sum_c; - 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); - - free_cubearray(a, pf_all); - - return perm && parity % 2 == 0; -} + perm = is_perm(c->ep, 12) && is_perm(c->cp, 8) && is_perm(c->xp, 6); -bool -is_solved(Cube cube) -{ - return equal(cube, (Cube){0}); -} + sign = perm_sign(c->ep,12) + perm_sign(c->cp,8) + perm_sign(c->xp,6); -bool -is_block_solved(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)) + for (i = 0, sum_e = 0; i < 12; i++) + if (c->eo[i] > 1) return false; + else + sum_e += c->eo[i]; - return true; -} + for (i = 0, sum_c = 0; i < 8; i++) + if (c->co[i] > 2) + return false; + else + sum_c += c->co[i]; -bool -is_solved_center(Cube cube, Center c) -{ - return what_center_at(cube, c) == c; + return (perm && sign % 2 == 0 && sum_e % 2 == 0 && sum_c % 2 == 0); } bool -is_solved_corner(Cube cube, Corner c) +is_solved(Cube *cube) { - return what_corner_at(cube, c) == c && - what_orientation_corner(cube.coud, c); -} + Cube solved_cube; + make_solved(&solved_cube); -bool -is_solved_edge(Cube cube, Edge e) -{ - return what_edge_at(cube, e) == e && - what_orientation_edge(cube.eofb, e); + return equal(cube, &solved_cube); } -int -piece_orientation(Cube cube, int piece, char *orientation) +void +make_solved(Cube *cube) { - int arr[12], n, b, x; - - if (!strcmp(orientation, "eofb")) { - x = cube.eofb; - n = 12; - b = 2; - } else if (!strcmp(orientation, "eorl")) { - x = cube.eorl; - n = 12; - b = 2; - } else if (!strcmp(orientation, "eoud")) { - x = cube.eoud; - n = 12; - b = 2; - } else if (!strcmp(orientation, "coud")) { - x = cube.coud; - n = 8; - b = 3; - } else if (!strcmp(orientation, "corl")) { - x = cube.corl; - n = 8; - b = 3; - } else if (!strcmp(orientation, "cofb")) { - x = cube.cofb; - n = 8; - b = 3; - } else { - return -1; - } - - int_to_sum_zero_array(x, b, n, arr); - if (piece < n) - return arr[piece]; + static int sorted[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; - return -1; + memcpy(cube->ep, sorted, 12 * sizeof(int)); + memset(cube->eo, 0, 12 * sizeof(int)); + memcpy(cube->cp, sorted, 8 * sizeof(int)); + memset(cube->co, 0, 8 * sizeof(int)); + memcpy(cube->xp, sorted, 6 * sizeof(int)); } void -print_cube(Cube cube) +print_cube(Cube *cube) { static char edge_string[12][7] = { [UF] = "UF", [UL] = "UL", [UB] = "UB", [UR] = "UR", @@ -545,388 +135,22 @@ print_cube(Cube cube) }; for (int i = 0; i < 12; i++) - printf(" %s ", edge_string[what_edge_at(cube, i)]); + printf(" %s ", edge_string[cube->ep[i]]); printf("\n"); for (int i = 0; i < 12; i++) - printf(" %d ", what_orientation_edge(cube.eofb, i)); + printf(" %" PRIu8 " ", cube->eo[i]); printf("\n"); for (int i = 0; i < 8; i++) - printf("%s ", corner_string[what_corner_at(cube, i)]); + printf("%s ", corner_string[cube->cp[i]]); printf("\n"); for (int i = 0; i < 8; i++) - printf(" %d ", what_orientation_corner(cube.coud, i)); + printf(" %" PRIu8 " ", cube->co[i]); printf("\n"); for (int i = 0; i < 6; i++) - printf(" %s ", center_string[what_center_at(cube, i)]); + printf(" %s ", center_string[cube->xp[i]]); printf("\n"); } - -Center -what_center_at(Cube cube, Center c) -{ - static bool initialized = false; - static Center aux[FACTORIAL6][6]; - static int i; - static unsigned int ui; - static CubeArray *arr; - - if (!initialized) { - for (ui = 0; ui < FACTORIAL6; ui++) { - arr = new_cubearray((Cube){.cpos = ui}, pf_cpos); - for (i = 0; i < 6; i++) - aux[ui][i] = arr->cpos[i]; - free_cubearray(arr, pf_cpos); - } - - initialized = true; - } - - return aux[cube.cpos][c]; -} - -Corner -what_corner_at(Cube cube, Corner c) -{ - int i; - unsigned int ui; - CubeArray *arr; - - static bool initialized = false; - static Corner aux[FACTORIAL8][8]; - - if (!initialized) { - for (ui = 0; ui < FACTORIAL8; ui++) { - arr = new_cubearray((Cube){.cp = ui}, pf_cp); - for (i = 0; i < 8; i++) - aux[ui][i] = arr->cp[i]; - free_cubearray(arr, pf_cp); - } - - initialized = true; - } - - return aux[cube.cp][c]; -} - -Edge -what_edge_at(Cube cube, Edge e) -{ - 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 c, Edge e) -{ - int r0, r1, r2; - - static bool initialized = false; - static int aux[3][BINOM12ON4*FACTORIAL4][12]; - static int i, j; - static unsigned int ui; - static CubeArray *arr; - - if (!initialized) { - for (ui = 0; ui < BINOM12ON4*FACTORIAL4; ui++) { - for (i = 0; i < 3; i++) - for (j = 0; j < 12; j++) - aux[i][ui][j] = -1; - - arr = new_cubearray((Cube){.epose = ui}, pf_e); - for (i = 0; i < 12; i++) - if (edge_slice(arr->ep[i]) == 0) - aux[0][ui][arr->ep[i]] = i; - free_cubearray(arr, pf_e); - - arr = new_cubearray((Cube){.eposs = ui}, pf_s); - for (i = 0; i < 12; i++) - if (edge_slice(arr->ep[i]) == 1) - aux[1][ui][arr->ep[i]] = i; - free_cubearray(arr, pf_s); - - arr = new_cubearray((Cube){.eposm = ui}, pf_m); - for (i = 0; i < 12; i++) - if (edge_slice(arr->ep[i]) == 2) - aux[2][ui][arr->ep[i]] = i; - free_cubearray(arr, pf_m); - } - - initialized = true; - } - - r0 = aux[0][c.epose][e]; - r1 = aux[1][c.eposs][e]; - r2 = aux[2][c.eposm][e]; - return MAX(r0, MAX(r1, r2)); -} - -static bool -read_invtables_file() -{ - init_env(); - - FILE *f; - char fname[strlen(tabledir)+20]; - int b; - unsigned int ui, meeo, meco, mecp, mecpos; - bool r; - - strcpy(fname, tabledir); - strcat(fname, "/invtables"); - - if ((f = fopen(fname, "rb")) == NULL) - return false; - - b = sizeof(uint16_t); - r = true; - meeo = BINOM12ON4*FACTORIAL4; - meco = FACTORIAL8; - mecp = FACTORIAL8; - mecpos = FACTORIAL6; - - for (ui = 0; ui < POW2TO11; ui++) { - r = r && fread(eo_invtable_e[ui], b, meeo, f) == meeo; - r = r && fread(eo_invtable_m[ui], b, meeo, f) == meeo; - r = r && fread(eo_invtable_s[ui], b, meeo, f) == meeo; - } - - for (ui = 0; ui < POW3TO7; ui++) { - r = r && fread(co_invtable[ui], b, meco, f) == meco; - } - - r = r && fread(cp_invtable, b, mecp, f) == mecp; - r = r && fread(cpos_invtable, b, mecpos, f) == mecpos; - - fclose(f); - return r; -} - -static bool -write_invtables_file() -{ - init_env(); - - FILE *f; - char fname[strlen(tabledir)+20]; - unsigned int ui, meeo, meco, mecp, mecpos; - int b; - bool r; - - strcpy(fname, tabledir); - strcat(fname, "/invtables"); - - if ((f = fopen(fname, "wb")) == NULL) - return false; - - b = sizeof(uint16_t); - r = true; - meeo = BINOM12ON4*FACTORIAL4; - meco = FACTORIAL8; - mecp = FACTORIAL8; - mecpos = FACTORIAL6; - - for (ui = 0; ui < POW2TO11; ui++) { - r = r && fwrite(eo_invtable_e[ui], b, meeo, f) == meeo; - r = r && fwrite(eo_invtable_m[ui], b, meeo, f) == meeo; - r = r && fwrite(eo_invtable_s[ui], b, meeo, f) == meeo; - } - - for (ui = 0; ui < POW3TO7; ui++) { - r = r && fwrite(co_invtable[ui], b, meco, f) == meco; - } - - r = r && fwrite(cp_invtable, b, mecp, f) == mecp; - r = r && fwrite(cpos_invtable, b, mecpos, f) == mecpos; - - fclose(f); - return r; -} - -void -init_inverse() -{ - static bool initialized = false; - if (initialized) - return; - initialized = true; - - if (read_invtables_file()) - return; - - fprintf(stderr, "Cannot load invtables, generating it\n"); - - CubeArray *aux, *inv; - Cube c; - int i, j, eoaux[12], eoinv[12]; - unsigned int ui, uj; - - aux = new_cubearray((Cube){0}, pf_all); - inv = new_cubearray((Cube){0}, pf_all); - - for (ui = 0; ui < POW2TO11; ui++) { - int_to_sum_zero_array(ui, 2, 12, eoaux); - for (uj = 0; uj < BINOM12ON4*FACTORIAL4; uj++) { - for (j = 0; j < 12; j++) - eoinv[j] = 0; - c = (Cube){.epose = uj, .eposm = 0, .eposs = 0}; - eoinv[FR] = eoaux[where_is_edge(c, FR)]; - eoinv[FL] = eoaux[where_is_edge(c, FL)]; - eoinv[BL] = eoaux[where_is_edge(c, BL)]; - eoinv[BR] = eoaux[where_is_edge(c, BR)]; - eo_invtable_e[ui][uj] = digit_array_to_int(eoinv,11,2); - - for (j = 0; j < 12; j++) - eoinv[j] = 0; - c = (Cube){.epose = 0, .eposm = uj, .eposs = 0}; - eoinv[UF] = eoaux[where_is_edge(c, UF)]; - eoinv[UB] = eoaux[where_is_edge(c, UB)]; - eoinv[DF] = eoaux[where_is_edge(c, DF)]; - eoinv[DB] = eoaux[where_is_edge(c, DB)]; - eo_invtable_m[ui][uj] = digit_array_to_int(eoinv,11,2); - - for (j = 0; j < 12; j++) - eoinv[j] = 0; - c = (Cube){.epose = 0, .eposm = 0, .eposs = uj}; - eoinv[UL] = eoaux[where_is_edge(c, UL)]; - eoinv[UR] = eoaux[where_is_edge(c, UR)]; - eoinv[DL] = eoaux[where_is_edge(c, DL)]; - eoinv[DR] = eoaux[where_is_edge(c, DR)]; - eo_invtable_s[ui][uj] = digit_array_to_int(eoinv,11,2); - } - } - - for (ui = 0; ui < FACTORIAL8; ui++) { - cube_to_arrays((Cube){.cp = ui}, aux, pf_cp); - for (i = 0; i < 8; i++) - inv->cp[aux->cp[i]] = i; - cp_invtable[ui] = (uint16_t)arrays_to_cube(inv, pf_cp).cp; - - for (uj = 0; uj < POW3TO7; uj++) { - cube_to_arrays((Cube){.coud = uj}, aux, pf_coud); - for (i = 0; i < 8; i++) - inv->coud[aux->cp[i]] = (3-aux->coud[i])%3; - co_invtable[uj][ui] = - (uint16_t)arrays_to_cube(inv, pf_coud).coud; - } - } - - for (ui = 0; ui < FACTORIAL6; ui++) { - cube_to_arrays((Cube){.cpos = ui}, aux, pf_cpos); - for (i = 0; i < 6; i++) - inv->cpos[aux->cpos[i]] = i; - cpos_invtable[ui] = - (uint16_t)arrays_to_cube(inv, pf_cpos).cpos; - } - - free_cubearray(aux, pf_all); - free_cubearray(inv, pf_all); - - if (!write_invtables_file()) - fprintf(stderr, "Error writing invtables\n"); -} - -void -init_cube() -{ - init_inverse(); -} diff --git a/src/cube.h b/src/cube.h @@ -3,44 +3,18 @@ #include <stdio.h> +#include "cubetypes.h" #include "env.h" -#include "pf.h" #include "utils.h" -Cube admissible_ep(Cube cube, PieceFilter f); -int array_ep_to_epos(int *ep, int *eps_solved); -Cube arrays_to_cube(CubeArray *arr, PieceFilter f); -Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */ -Cube compose_filtered(Cube c2, Cube c1, PieceFilter f); -void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f); -int edge_slice(Edge e); /* E=0, S=1, M=2 */ -bool equal(Cube c1, Cube c2); -Cube inverse_cube(Cube cube); -bool is_admissible(Cube cube); -bool is_solved(Cube cube); -bool is_block_solved(Cube cube, Block); -bool is_solved_center(Cube cube, Center c); -bool is_solved_corner(Cube cube, Corner c); -bool is_solved_edge(Cube cube, Edge e); -void epos_to_partial_ep(int epos, int *ep, int *ss); -void epos_to_compatible_ep(int epos, int *ep, int *ss); -void fix_eorleoud(CubeArray *arr); -void fix_cofbcorl(CubeArray *arr); -Cube fourval_to_cube(int eofb, int ep, int coud, int cp); -void free_cubearray(CubeArray *arr, PieceFilter f); -Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf); -CubeArray * new_cubearray(Cube cube, PieceFilter f); -void print_cube(Cube cube); -Center what_center_at(Cube cube, Center c); -Corner what_corner_at(Cube cube, Corner c); -Edge what_edge_at(Cube cube, Edge e); -int what_orientation_corner(int co, Corner c); -int what_orientation_edge(int eo, Edge e); -Center where_is_center(Cube cube, Center c); -Corner where_is_corner(Cube cube, Corner c); -Edge where_is_edge(Cube cube, Edge e); - -void init_cube(); +void compose(Cube *c2, Cube *c1); /* Use c2 as an alg on c1 */ +void copy_cube(Cube *src, Cube *dst); +bool equal(Cube *c1, Cube *c2); +void invert_cube(Cube *cube); +bool is_admissible(Cube *cube); +bool is_solved(Cube *cube); +void make_solved(Cube *cube); +void print_cube(Cube *cube); #endif diff --git a/src/cubetypes.h b/src/cubetypes.h @@ -10,6 +10,8 @@ #define NROTATIONS 24 #define entry_group_t uint8_t /* For pruning tables */ +#define MAX_N_COORD 6 + /* Enums *********************************************************************/ typedef enum @@ -28,6 +30,12 @@ corner } Corner; typedef enum +coordtype +{ + COMP_COORD, SYM_COORD, SYMCOMP_COORD +} CoordType; + +typedef enum edge { UF, UL, UB, UR, @@ -81,28 +89,24 @@ typedef struct command Command; typedef struct commandargs CommandArgs; typedef struct coordinate Coordinate; typedef struct cube Cube; -typedef struct cubearray CubeArray; typedef struct dfsarg DfsArg; -typedef struct estimatedata EstimateData; +typedef struct indexer Indexer; +typedef struct movable Movable; typedef struct moveset Moveset; -typedef struct piecefilter PieceFilter; +typedef struct pdgendata PDGenData; typedef struct prunedata PruneData; typedef struct solveoptions SolveOptions; typedef struct step Step; +typedef struct stepalt StepAlt; typedef struct symdata SymData; typedef struct threaddatasolve ThreadDataSolve; typedef struct threaddatagenpt ThreadDataGenpt; +typedef struct transgroup TransGroup; -typedef Cube (*AntiIndexer) (uint64_t); -typedef bool (*Checker) (Cube); -typedef uint64_t (*CoordMover) (Move, uint64_t); -typedef uint64_t (*CoordTransformer) (Trans, uint64_t); -typedef int (*Estimator) (DfsArg *); +typedef bool (*Checker) (Cube *); typedef bool (*Validator) (Alg *); typedef void (*Exec) (CommandArgs *); -typedef uint64_t (*Indexer) (Cube); typedef CommandArgs * (*ArgParser) (int, char **); -typedef int (*TransDetector) (Cube, Trans *); typedef int (*TransFinder) (uint64_t, Trans *); @@ -167,83 +171,69 @@ commandargs struct coordinate { - Indexer index; + char * name; + CoordType type; + bool generated; + Indexer * i[99]; uint64_t max; - CoordMover move; - CoordTransformer transform; - SymData * sd; - TransFinder tfind; /* TODO: should be easy to remove */ - Coordinate * base; /* TODO: part of refactor */ + uint64_t * mtable[NMOVES]; + uint64_t * ttable[NTRANS]; + TransGroup * tgrp; + Coordinate * base[2]; + uint64_t * symclass; + uint64_t * symrep; + Trans * transtorep; + Trans * ttrep_move[NMOVES]; + uint64_t * selfsim; }; struct cube { - int epose; - int eposs; - int eposm; - int eofb; - int eorl; - int eoud; - int cp; - int coud; - int cofb; - int corl; - int cpos; + int ep[12]; + int eo[12]; + int cp[8]; + int co[8]; + int xp[6]; }; struct -cubearray +movable { - int * ep; - int * eofb; - int * eorl; - int * eoud; - int * cp; - int * coud; - int * corl; - int * cofb; - int * cpos; + uint64_t val; + Trans t; }; struct dfsarg { - Step * step; - SolveOptions * opts; + Cube * cube; + Movable ind[MAX_N_COORD]; Trans t; - Cube cube; - Cube inverse; + StepAlt * sa; + SolveOptions * opts; int d; - uint64_t badmoves; - uint64_t badmovesinv; + int bound; bool niss; - Move last1; - Move last2; - Move last1inv; - Move last2inv; - EstimateData * ed; + Move last[2]; + Move lastinv[2]; AlgList * sols; pthread_mutex_t * sols_mutex; Alg * current_alg; }; struct -estimatedata +indexer { - int corners; - int normal_ud; - int normal_fb; - int normal_rl; - int inverse_ud; - int inverse_fb; - int inverse_rl; - int oldret; + int n; + uint64_t (*index)(Cube *); + void (*to_cube)(uint64_t, Cube *); }; struct moveset { + char * name; bool (*allowed)(Move); bool (*allowed_next)(Move, Move, Move); Move sorted_moves[NMOVES+1]; @@ -251,34 +241,24 @@ moveset }; struct -piecefilter +pdgendata { - bool epose; - bool eposs; - bool eposm; - bool eofb; - bool eorl; - bool eoud; - bool cp; - bool coud; - bool cofb; - bool corl; - bool cpos; + Coordinate * coord; + Moveset * moveset; + bool compact; + PruneData * pd; }; struct prunedata { - char * filename; entry_group_t * ptable; - bool generated; uint64_t n; Coordinate * coord; Moveset * moveset; bool compact; int base; uint64_t count[16]; - PruneData * fallback; uint64_t fbmod; }; @@ -302,19 +282,35 @@ step { char * shortname; char * name; - bool final; - Checker is_done; - Estimator estimate; - Checker ready; + StepAlt * alt[99]; + Trans t[99]; char * ready_msg; - Validator is_valid; +}; + +struct +stepalt +{ + Checker ready; + bool final; Moveset * moveset; - Trans pre_trans; - TransDetector detect; - int ntables; - PruneData * tables[10]; + /* Just a comment, (TODO: remove this): moveset is really a stepalt + * property, because for example we may want to define a "fingertrick + * friendly ZBLL" step, where we allow either <R U D> or <R U F> as + * movesets (or similar) */ + int n_coord; + Coordinate * coord[MAX_N_COORD]; + Trans coord_trans[MAX_N_COORD]; + PruneData * pd[MAX_N_COORD]; + bool compact_pd[MAX_N_COORD]; + Coordinate * fallback_coord[MAX_N_COORD]; + PruneData * fallback_pd[MAX_N_COORD]; + uint64_t fbmod[MAX_N_COORD]; + int n_dbtrick; + int dbtrick[MAX_N_COORD][3]; + Validator is_valid; }; +/* struct symdata { @@ -328,23 +324,18 @@ symdata uint64_t * unsym; Trans * transtorep; uint64_t * selfsim; - CoordTransformer transform; /* TODO: remove, use that of base coord */ }; +*/ + struct threaddatasolve { + DfsArg arg; int thid; - Trans t; - Cube cube; - Step * step; - int depth; - SolveOptions * opts; AlgList * start; AlgListNode ** node; - AlgList * sols; pthread_mutex_t * start_mutex; - pthread_mutex_t * sols_mutex; }; struct @@ -359,4 +350,11 @@ threaddatagenpt pthread_mutex_t * upmutex; }; +struct +transgroup +{ + int n; + Trans t[NTRANS]; +}; + #endif diff --git a/src/env.c b/src/env.c @@ -1,3 +1,5 @@ +#define ENV_C + #include "env.h" bool initialized_env = false; diff --git a/src/env.h b/src/env.h @@ -8,8 +8,8 @@ #include <unistd.h> #include <sys/stat.h> -extern char *tabledir; - void init_env(); +extern char *tabledir; + #endif diff --git a/src/moves.c b/src/moves.c @@ -1,79 +1,18 @@ +#define MOVES_C + #include "moves.h" /* Local functions ***********************************************************/ -static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f); static void cleanup_aux(Alg *alg, Alg *ret, bool inv); -static bool read_mtables_file(); -static bool write_mtables_file(); /* Tables and other data *****************************************************/ -/* Every move is translated to a an <U, x, y> 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 - } -}; +/* Moves are represented as cubes and applied using compose(). Every move is * + * translated to a an <U, x, y> alg before filling the transition tables. * + * See init_moves(). */ -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 Cube move_array[NMOVES]; static char equiv_alg_string[100][NMOVES] = { [NULLMOVE] = "", @@ -137,89 +76,34 @@ static char equiv_alg_string[100][NMOVES] = { [z3] = " y x yyy " }; -/* Transition tables, to be loaded up at the beginning */ -int epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; -int eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; -int eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; -int eofb_mtable[NMOVES][POW2TO11]; -int eorl_mtable[NMOVES][POW2TO11]; -int eoud_mtable[NMOVES][POW2TO11]; -int cp_mtable[NMOVES][FACTORIAL8]; -int coud_mtable[NMOVES][POW3TO7]; -int cofb_mtable[NMOVES][POW3TO7]; -int corl_mtable[NMOVES][POW3TO7]; -int cpos_mtable[NMOVES][FACTORIAL6]; - - -/* Local functions implementation ********************************************/ - -static Cube -apply_move_cubearray(Move m, Cube cube, PieceFilter f) -{ - /*init_moves();*/ - - CubeArray m_arr = { - edge_cycle[m], - eofb_flipped[m], - eorl_flipped[m], - eoud_flipped[m], - corner_cycle[m], - coud_flipped[m], - corl_flipped[m], - cofb_flipped[m], - center_cycle[m] - }; - - return move_via_arrays(&m_arr, cube, f); -} /* Public functions **********************************************************/ -Cube -apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a) +void +apply_alg(Alg *alg, Cube *cube) { - Cube ret = {0}; + Cube aux; int i; + copy_cube(cube, &aux); + make_solved(cube); + 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); + apply_move(alg->move[i], cube); - ret = compose_filtered(c, inverse_cube(ret), f); + invert_cube(cube); + compose(&aux, cube); 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; + apply_move(alg->move[i], cube); } -Cube -apply_alg(Alg *alg, Cube cube) -{ - return apply_alg_generic(alg, cube, pf_all, true); -} - -Cube -apply_move(Move m, Cube cube) +void +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] - }; + compose(&move_array[m], cube); } Alg * @@ -279,31 +163,27 @@ cleanup_aux(Alg *alg, Alg *ret, bool inv) { int i, j; Cube c, d; - Move m, mm; + Move m; Alg *equiv_alg; - c = (Cube){0}; + make_solved(&c); for (i = 0; i < alg->len; i++) { if (alg->inv[i] != inv) continue; equiv_alg = new_alg(equiv_alg_string[alg->move[i]]); - for (j = 0; j < equiv_alg->len; j++) { - m = equiv_alg->move[j]; - if (m == U) { - mm = 3*what_center_at(c, U_center) + 1; - append_move(ret, mm, inv); - } else { - c = apply_move(m, c); - } - } + for (j = 0; j < equiv_alg->len; j++) + if (equiv_alg->move[j] == U) + append_move(ret, 3 * c.xp[U_center] + 1, inv); + else + apply_move(equiv_alg->move[j], &c); free_alg(equiv_alg); } m = NULLMOVE; - switch (what_center_at(c, F_center)) { + switch (c.xp[F_center]) { case U_center: m = x3; break; @@ -317,7 +197,7 @@ cleanup_aux(Alg *alg, Alg *ret, bool inv) m = y3; break; case B_center: - if (what_center_at(c, U_center) == U_center) + if (c.xp[U_center] == U_center) m = y2; else m = x2; @@ -325,120 +205,24 @@ cleanup_aux(Alg *alg, Alg *ret, bool inv) default: break; } - d = apply_move(m, (Cube){0}); + + make_solved(&d); + apply_move(m, &d); if (m != NULLMOVE) append_move(ret, m, inv); m = NULLMOVE; - if (what_center_at(c, U_center) == what_center_at(d, D_center)) { + if (c.xp[U_center] == d.xp[D_center]) { m = z2; - } else if (what_center_at(c, U_center) == what_center_at(d, R_center)) { + } else if (c.xp[U_center] == d.xp[R_center]) { m = z3; - } else if (what_center_at(c, U_center) == what_center_at(d, L_center)) { + } else if (c.xp[U_center] == d.xp[L_center]) { m = z; } if (m != NULLMOVE) append_move(ret, m, inv); } -static bool -read_mtables_file() -{ - init_env(); - - FILE *f; - char fname[strlen(tabledir)+20]; - int m, b = sizeof(int); - bool r = true; - - /* Table sizes, used for reading and writing files */ - uint64_t me[11] = { - [0] = FACTORIAL12/FACTORIAL8, - [1] = FACTORIAL12/FACTORIAL8, - [2] = FACTORIAL12/FACTORIAL8, - [3] = POW2TO11, - [4] = POW2TO11, - [5] = POW2TO11, - [6] = FACTORIAL8, - [7] = POW3TO7, - [8] = POW3TO7, - [9] = POW3TO7, - [10] = FACTORIAL6 - }; - - strcpy(fname, tabledir); - strcat(fname, "/mtables"); - - if ((f = fopen(fname, "rb")) == NULL) - return false; - - for (m = 0; m < NMOVES; m++) { - r = r && fread(epose_mtable[m], b, me[0], f) == me[0]; - r = r && fread(eposs_mtable[m], b, me[1], f) == me[1]; - r = r && fread(eposm_mtable[m], b, me[2], f) == me[2]; - r = r && fread(eofb_mtable[m], b, me[3], f) == me[3]; - r = r && fread(eorl_mtable[m], b, me[4], f) == me[4]; - r = r && fread(eoud_mtable[m], b, me[5], f) == me[5]; - r = r && fread(cp_mtable[m], b, me[6], f) == me[6]; - r = r && fread(coud_mtable[m], b, me[7], f) == me[7]; - r = r && fread(corl_mtable[m], b, me[8], f) == me[8]; - r = r && fread(cofb_mtable[m], b, me[9], f) == me[9]; - r = r && fread(cpos_mtable[m], b, me[10], f) == me[10]; - } - - fclose(f); - return r; -} - -static bool -write_mtables_file() -{ - init_env(); - - FILE *f; - char fname[strlen(tabledir)+20]; - int m, b = sizeof(int); - bool r = true; - - /* Table sizes, used for reading and writing files */ - uint64_t me[11] = { - [0] = FACTORIAL12/FACTORIAL8, - [1] = FACTORIAL12/FACTORIAL8, - [2] = FACTORIAL12/FACTORIAL8, - [3] = POW2TO11, - [4] = POW2TO11, - [5] = POW2TO11, - [6] = FACTORIAL8, - [7] = POW3TO7, - [8] = POW3TO7, - [9] = POW3TO7, - [10] = FACTORIAL6 - }; - - strcpy(fname, tabledir); - strcat(fname, "/mtables"); - - if ((f = fopen(fname, "wb")) == NULL) - return false; - - for (m = 0; m < NMOVES; m++) { - r = r && fwrite(epose_mtable[m], b, me[0], f) == me[0]; - r = r && fwrite(eposs_mtable[m], b, me[1], f) == me[1]; - r = r && fwrite(eposm_mtable[m], b, me[2], f) == me[2]; - r = r && fwrite(eofb_mtable[m], b, me[3], f) == me[3]; - r = r && fwrite(eorl_mtable[m], b, me[4], f) == me[4]; - r = r && fwrite(eoud_mtable[m], b, me[5], f) == me[5]; - r = r && fwrite(cp_mtable[m], b, me[6], f) == me[6]; - r = r && fwrite(coud_mtable[m], b, me[7], f) == me[7]; - r = r && fwrite(corl_mtable[m], b, me[8], f) == me[8]; - r = r && fwrite(cofb_mtable[m], b, me[9], f) == me[9]; - r = r && fwrite(cpos_mtable[m], b, me[10], f) == me[10]; - } - - fclose(f); - return r; -} - void init_moves() { static bool initialized = false; @@ -446,101 +230,54 @@ init_moves() { return; initialized = true; - Cube c; - CubeArray arrs; - int i; - unsigned int ui; Move m; Alg *equiv_alg[NMOVES]; - init_cube(); - - 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); - } + static const Cube mcu = { + .ep = { UR, UF, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR }, + .cp = { UBR, UFR, UFL, UBL, DFR, DFL, DBL, DBR }, + }; + static const Cube mcx = { + .ep = { DF, FL, UF, FR, DB, BL, UB, BR, DR, DL, UL, UR }, + .eo = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 }, + .cp = { DFR, DFL, UFL, UFR, DBR, DBL, UBL, UBR }, + .co = { [UFR] = 2, [UBR] = 1, [UFL] = 1, [UBL] = 2, + [DBR] = 2, [DFR] = 1, [DBL] = 1, [DFL] = 2 }, + .xp = { F_center, B_center, R_center, + L_center, D_center, U_center }, + }; + static const Cube mcy = { + .ep = { UR, UF, UL, UB, DR, DF, DL, DB, BR, FR, FL, BL }, + .eo = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 }, + .cp = { UBR, UFR, UFL, UBL, DBR, DFR, DFL, DBL }, + .xp = { U_center, D_center, B_center, + F_center, R_center, L_center }, + }; - if (read_mtables_file()) - return; + move_array[U] = mcu; + move_array[x] = mcx; + move_array[y] = mcy; - fprintf(stderr, "Cannot load %s, generating it\n", "mtables"); + for (m = 0; m < NMOVES; m++) + equiv_alg[m] = new_alg(equiv_alg_string[m]); - /* 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; + switch (m) { + case NULLMOVE: + make_solved(&move_array[m]); + break; + case U: + case x: + case y: + break; + default: + make_solved(&move_array[m]); + apply_alg(equiv_alg[m], &move_array[m]); + break; } } - if (!write_mtables_file()) - fprintf(stderr, "Error writing mtables\n"); - - for (i = 0; i < NMOVES; i++) - free_alg(equiv_alg[i]); + for (m = 0; m < NMOVES; m++) + free_alg(equiv_alg[m]); } diff --git a/src/moves.h b/src/moves.h @@ -5,24 +5,8 @@ #include "cube.h" #include "env.h" -/* - * Tables are exposed to allow for faster moves in some cases. - */ -extern int epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; -extern int eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; -extern int eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; -extern int eofb_mtable[NMOVES][POW2TO11]; -extern int eorl_mtable[NMOVES][POW2TO11]; -extern int eoud_mtable[NMOVES][POW2TO11]; -extern int cp_mtable[NMOVES][FACTORIAL8]; -extern int coud_mtable[NMOVES][POW3TO7]; -extern int cofb_mtable[NMOVES][POW3TO7]; -extern int corl_mtable[NMOVES][POW3TO7]; -extern int cpos_mtable[NMOVES][FACTORIAL6]; - -Cube apply_alg(Alg *alg, Cube cube); -Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a); -Cube apply_move(Move m, Cube cube); +void apply_alg(Alg *alg, Cube *cube); +void apply_move(Move m, Cube *cube); Alg * cleanup(Alg *alg); void init_moves(); diff --git a/src/pf.c b/src/pf.c @@ -1,95 +0,0 @@ -#include "pf.h" - -PieceFilter -pf_all = { - .epose = true, - .eposs = true, - .eposm = true, - .eofb = true, - .eorl = true, - .eoud = true, - .cp = true, - .cofb = true, - .corl = true, - .coud = true, - .cpos = true -}; - -PieceFilter -pf_4val = { - .epose = true, - .eposs = true, - .eposm = true, - .eofb = true, - .coud = true, - .cp = true -}; - -PieceFilter -pf_epcp = { - .epose = true, - .eposs = true, - .eposm = true, - .cp = true -}; - -PieceFilter -pf_cpos = { - .cpos = true -}; - -PieceFilter -pf_cp = { - .cp = true -}; - -PieceFilter -pf_ep = { - .epose = true, - .eposs = true, - .eposm = true -}; - -PieceFilter -pf_e = { - .epose = true -}; - -PieceFilter -pf_s = { - .eposs = true -}; - -PieceFilter -pf_m = { - .eposm = true -}; - -PieceFilter -pf_eo = { - .eofb = true, - .eorl = true, - .eoud = true -}; - -PieceFilter -pf_co = { - .cofb = true, - .corl = true, - .coud = true -}; - -PieceFilter -pf_coud = { - .coud = true -}; - -PieceFilter -pf_edges = { - .epose = true, - .eposs = true, - .eposm = true, - .eofb = true, - .eorl = true, - .eoud = true -}; diff --git a/src/pf.h b/src/pf.h @@ -1,20 +0,0 @@ -#ifndef PF_H -#define PF_H - -#include "cubetypes.h" - -extern PieceFilter pf_all; -extern PieceFilter pf_4val; -extern PieceFilter pf_epcp; -extern PieceFilter pf_cpos; -extern PieceFilter pf_cp; -extern PieceFilter pf_ep; -extern PieceFilter pf_e; -extern PieceFilter pf_s; -extern PieceFilter pf_m; -extern PieceFilter pf_eo; -extern PieceFilter pf_co; -extern PieceFilter pf_coud; -extern PieceFilter pf_edges; - -#endif diff --git a/src/pruning.c b/src/pruning.c @@ -1,3 +1,5 @@ +#define PRUNING_C + #include "pruning.h" #define ENTRIES_PER_GROUP (2*sizeof(entry_group_t)) @@ -10,101 +12,11 @@ static void genptable_fixnasty(PruneData *pd, int d, int nthreads); static void genptable_setbase(PruneData *pd); static void * instance_bfs(void *arg); static void * instance_fixnasty(void *arg); -static void ptable_update(PruneData *pd, 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 void ptable_update(PruneData *pd, uint64_t ind, int m); 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_HTM", - .coord = &coord_cornershtr, - .moveset = &moveset_HTM, -}; - -PruneData -pd_corners_HTM = { - .filename = "pt_corners_HTM", - .coord = &coord_corners, - .moveset = &moveset_HTM, -}; - -PruneData -pd_drud_sym16_HTM = { - .filename = "pt_drud_sym16_HTM", - .coord = &coord_drud_sym16, - .moveset = &moveset_HTM, -}; - -PruneData -pd_drud_eofb = { - .filename = "pt_drud_eofb", - .coord = &coord_drud_eofb, - .moveset = &moveset_eofb, -}; - -PruneData -pd_drudfin_noE_sym16_drud = { - .filename = "pt_drudfin_noE_sym16_drud", - .coord = &coord_drudfin_noE_sym16, - .moveset = &moveset_drud, -}; - -PruneData -pd_htr_drud = { - .filename = "pt_htr_drud", - .coord = &coord_htr_drud, - .moveset = &moveset_drud, -}; - -PruneData -pd_htrfin_htr = { - .filename = "pt_htrfin_htr", - .coord = &coord_htrfin, - .moveset = &moveset_htr, -}; - -PruneData -pd_nxopt31_HTM = { - .filename = "pt_nxopt31_HTM", - .coord = &coord_nxopt31, - .moveset = &moveset_HTM, - - .compact = true, - .fallback = &pd_drud_sym16_HTM, - .fbmod = BINOM8ON4, -}; - -PruneData * all_pd[] = { - &pd_eofb_HTM, - &pd_coud_HTM, - &pd_cornershtr_HTM, - &pd_corners_HTM, - &pd_drud_sym16_HTM, - &pd_drud_eofb, - &pd_drudfin_noE_sym16_drud, - &pd_htr_drud, - &pd_htrfin_htr, - &pd_nxopt31_HTM, - NULL -}; - -/* Functions *****************************************************************/ +PDGenData *active_pdg[256]; int findchunk(PruneData *pd, int nchunks, uint64_t i) @@ -117,39 +29,41 @@ findchunk(PruneData *pd, int nchunks, uint64_t i) return MIN(nchunks-1, (int)(i / chunksize)); } -void -free_pd(PruneData *pd) -{ - if (pd->generated) - free(pd->ptable); - - pd->generated = false; -} - -void -genptable(PruneData *pd, int nthreads) +PruneData * +genptable(PDGenData *pdg, int nthreads) { bool compact; - int d, nchunks; + int d, nchunks, i; uint64_t oldn, sz; + PruneData *pd; + + for (i = 0; active_pdg[i] != NULL; i++) { + pd = active_pdg[i]->pd; + if (pd->coord == pdg->coord && + pd->moveset == pdg->moveset && + pd->compact == pdg->compact) + return pd; + } - if (pd->generated) - return; + pd = malloc(sizeof(PruneData)); + pdg->pd = pd; + pd->coord = pdg->coord; + pd->moveset = pdg->moveset; + pd->compact = pdg->compact; - /* TODO: check if memory is enough, otherwise maybe exit gracefully? */ sz = ptablesize(pd) * (pd->compact ? 2 : 1); pd->ptable = malloc(sz * sizeof(entry_group_t)); - if (read_ptable_file(pd)) { - pd->generated = true; - return; - } + gen_coord(pd->coord); + + if (read_ptable_file(pd)) + goto genptable_done; if (nthreads < 4) { fprintf(stderr, "--- Warning ---\n" "You are using only %d threads to generate the pruning" - "tables. This can take a while." + "tables. This can take a while.\n" "Unless you did this intentionally, you should re-run" "this command with `-t 4' or more.\n" "---------------\n\n", nthreads @@ -160,16 +74,16 @@ genptable(PruneData *pd, int nthreads) /* For the first steps we proceed the same way for compact and not */ compact = pd->compact; pd->compact = false; - pd->generated = true; nchunks = MIN(ptablesize(pd), 100000); - fprintf(stderr, "Cannot load %s, generating it with %d threads\n", - pd->filename, nthreads); - + fprintf(stderr, "Generating pt_%s_%s with %d threads\n", + pd->coord->name, pd->moveset->name, nthreads); memset(pd->ptable, ~(uint8_t)0, ptablesize(pd)*sizeof(entry_group_t)); + for (i = 0; i < 16; i++) + pd->count[i] = 0; - ptable_update(pd, (Cube){0}, 0); + ptable_update(pd, 0, 0); pd->n = 1; oldn = 0; genptable_fixnasty(pd, 0, nthreads); @@ -192,9 +106,19 @@ genptable(PruneData *pd, int nthreads) genptable_setbase(pd); if (compact) genptable_compress(pd); - + if (!write_ptable_file(pd)) fprintf(stderr, "Error writing ptable file\n"); + +genptable_done: + for (i = 0; active_pdg[i] != NULL; i++); + active_pdg[i] = malloc(sizeof(PDGenData)); + active_pdg[i]->coord = pdg->coord; + active_pdg[i]->moveset = pdg->moveset; + active_pdg[i]->compact = pdg->compact; + active_pdg[i]->pd = pd; + + return pd; } static void @@ -245,7 +169,7 @@ genptable_compress(PruneData *pd) for (j = 0; j < ENTRIES_PER_GROUP_COMPACT; j++) { if (i+j >= pd->coord->max) break; - val = ptableval_index(pd, i+j) - pd->base; + val = ptableval(pd, i+j) - pd->base; v = (entry_group_t)MIN(3, MAX(0, val)); mask |= v << (2*j); } @@ -264,7 +188,7 @@ genptable_fixnasty(PruneData *pd, int d, int nthreads) ThreadDataGenpt td[nthreads]; pthread_mutex_t *upmtx; - if (pd->coord->tfind == NULL) + if (pd->coord->type != SYMCOMP_COORD) return; upmtx = malloc(sizeof(pthread_mutex_t)); @@ -320,17 +244,17 @@ instance_bfs(void *arg) for (i = rmin; i < rmax; i++) { ichunk = findchunk(td->pd, td->nchunks, i); pthread_mutex_lock(td->mutex[ichunk]); - pval = ptableval_index(td->pd, i); + pval = ptableval(td->pd, i); pthread_mutex_unlock(td->mutex[ichunk]); if (pval == td->d) { for (j = 0; ms[j] != NULLMOVE; j++) { - ii = td->pd->coord->move(ms[j], i); + /* ii = td->pd->coord->move(ms[j], i); */ + ii = move_coord(td->pd->coord, ms[j], i, NULL); ichunk = findchunk(td->pd, td->nchunks, ii); pthread_mutex_lock(td->mutex[ichunk]); - pval = ptableval_index(td->pd, ii); + pval = ptableval(td->pd, ii); if (pval > td->d+1) { - ptable_update_index(td->pd, - ii, td->d+1); + ptable_update(td->pd, ii, td->d+1); updated++; } pthread_mutex_unlock(td->mutex[ichunk]); @@ -349,13 +273,15 @@ static void * instance_fixnasty(void *arg) { ThreadDataGenpt *td; - uint64_t i, ii, nb, blocksize, rmin, rmax, updated; - int j, n; - Trans t, aux[NTRANS]; + uint64_t i, ii, blocksize, rmin, rmax, updated, ss, M; + int j; + Trans t; td = (ThreadDataGenpt *)arg; - nb = td->pd->coord->max / td->pd->coord->base->max; - blocksize = (td->pd->coord->base->max / td->nthreads) * nb; + + /* We know type = SYMCOMP_COORD */ + M = td->pd->coord->base[1]->max; + blocksize = (td->pd->coord->base[0]->max / td->nthreads) * M; rmin = ((uint64_t)td->thid) * blocksize; rmax = td->thid == td->nthreads - 1 ? td->pd->coord->max : @@ -363,16 +289,15 @@ instance_fixnasty(void *arg) updated = 0; for (i = rmin; i < rmax; i++) { - if (ptableval_index(td->pd, i) == td->d) { - if ((n = td->pd->coord->tfind(i, aux)) == 1) - continue; - - for (j = 0; j < n; j++) { - if ((t = aux[j]) == uf) + if (ptableval(td->pd, i) == td->d) { + ss = td->pd->coord->base[0]->selfsim[i/M]; + for (j = 0; j < td->pd->coord->base[0]->tgrp->n; j++) { + t = td->pd->coord->base[0]->tgrp->t[j]; + if (t == uf || !(ss & ((uint64_t)1<<t))) continue; - ii = td->pd->coord->transform(t, i); - if (ptableval_index(td->pd, ii) > td->d) { - ptable_update_index(td->pd, ii, td->d); + ii = trans_coord(td->pd->coord, t, i); + if (ptableval(td->pd, ii) > td->d) { + ptable_update(td->pd, ii, td->d); updated++; } } @@ -391,10 +316,7 @@ print_ptable(PruneData *pd) { uint64_t i; - if (!pd->generated) - genptable(pd, 1); /* TODO: set default nthreads somewhere */ - - printf("Table %s\n", pd->filename); + printf("Table %s_%s\n", pd->coord->name, pd->moveset->name); printf("Base value: %d\n", pd->base); for (i = 0; i < 16; i++) printf("%2" PRIu64 "\t%10" PRIu64 "\n", i, pd->count[i]); @@ -411,13 +333,7 @@ ptablesize(PruneData *pd) } static void -ptable_update(PruneData *pd, Cube cube, int n) -{ - ptable_update_index(pd, pd->coord->index(cube), n); -} - -static void -ptable_update_index(PruneData *pd, uint64_t ind, int n) +ptable_update(PruneData *pd, uint64_t ind, int n) { int sh; entry_group_t mask; @@ -432,27 +348,12 @@ ptable_update_index(PruneData *pd, uint64_t ind, int n) } int -ptableval(PruneData *pd, Cube cube) -{ - return ptableval_index(pd, pd->coord->index(cube)); -} - -static int -ptableval_index(PruneData *pd, uint64_t ind) +ptableval(PruneData *pd, uint64_t ind) { int sh, ret; - entry_group_t mask; - uint64_t i, e; + uint64_t e; entry_group_t m; - if (!pd->generated) { - fprintf(stderr, "Warning: request pruning table value" - " for uninitialized table %s.\n It's fine, but it" - " should not happen. Please report bug.\n", - pd->filename); - genptable(pd, 1); /* TODO: set default or remove this case */ - } - if (pd->compact) { e = ENTRIES_PER_GROUP_COMPACT; m = 3; @@ -463,19 +364,9 @@ ptableval_index(PruneData *pd, uint64_t ind) sh = (ind % e) * 4; } - mask = m << sh; - i = ind/e; - - ret = (pd->ptable[i] & mask) >> sh; - - if (pd->compact) { - if (ret) - ret += pd->base; - else - ret = ptableval_index(pd->fallback, ind / pd->fbmod); - } + ret = (pd->ptable[ind/e] & (m << sh)) >> sh; - return ret; + return pd->compact ? ret + pd->base : ret; } static bool @@ -484,13 +375,15 @@ read_ptable_file(PruneData *pd) init_env(); FILE *f; - char fname[strlen(tabledir)+100]; + char fname[strlen(tabledir)+256]; int i; uint64_t r; strcpy(fname, tabledir); - strcat(fname, "/"); - strcat(fname, pd->filename); + strcat(fname, "/pt_"); + strcat(fname, pd->coord->name); + strcat(fname, "_"); + strcat(fname, pd->moveset->name); if ((f = fopen(fname, "rb")) == NULL) return false; @@ -511,13 +404,15 @@ write_ptable_file(PruneData *pd) init_env(); FILE *f; - char fname[strlen(tabledir)+100]; + char fname[strlen(tabledir)+256]; int i; uint64_t w; strcpy(fname, tabledir); - strcat(fname, "/"); - strcat(fname, pd->filename); + strcat(fname, "/pt_"); + strcat(fname, pd->coord->name); + strcat(fname, "_"); + strcat(fname, pd->moveset->name); if ((f = fopen(fname, "wb")) == NULL) return false; diff --git a/src/pruning.h b/src/pruning.h @@ -1,26 +1,15 @@ #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_nxopt31_HTM; - -extern PruneData * all_pd[]; +#include "coord.h" void free_pd(PruneData *pd); -void genptable(PruneData *pd, int nthreads); +PruneData * genptable(PDGenData *data, int nthreads); void print_ptable(PruneData *pd); uint64_t ptablesize(PruneData *pd); -int ptableval(PruneData *pd, Cube cube); +int ptableval(PruneData *pd, uint64_t ind); + +extern PDGenData *active_pdg[256]; #endif diff --git a/src/shell.c b/src/shell.c @@ -1,3 +1,5 @@ +#define SHELL_C + #include "shell.h" static void cleanwhitespaces(char *line); @@ -7,7 +9,9 @@ bool checkfiles() { /* TODO: add more checks (other files, use checksum...) */ - FILE *f; + /* How to check for pruning tables with new method? */ + /* Solution: use list of steps */ + /* char fname[strlen(tabledir)+100]; int i; @@ -20,6 +24,7 @@ checkfiles() else fclose(f); } + */ return true; } @@ -143,6 +148,21 @@ main(int argc, char *argv[]) char *closing_cmd[1] = { "freemem" }; init_env(); + init_trans(); + +/* + Cube c; + make_solved(&c); + c.co[0] = 1; + c.co[6] = 2; + print_cube(&c); + apply_trans(uf_mirror, &c); + print_cube(&c); +*/ + +/* + test_coord(&coord_coud_cpudsep); +*/ if (!checkfiles()) { fprintf(stderr, diff --git a/src/solve.c b/src/solve.c @@ -1,37 +1,34 @@ +#define SOLVE_C + #include "solve.h" /* Local functions ***********************************************************/ -static bool allowed_next(Move move, DfsArg *arg); +static bool allowed_next(Move move, StepAlt *sa, Move l0, Move l1); static bool cancel_niss(DfsArg *arg); static void copy_dfsarg(DfsArg *src, DfsArg *dst); static void dfs(DfsArg *arg); -static void dfs_branch(DfsArg *arg); -static bool dfs_check_solved(DfsArg *arg); -static bool dfs_switch(DfsArg *arg); +static void dfs_add_sol(DfsArg *arg); static void dfs_niss(DfsArg *arg); -static bool dfs_stop(DfsArg *arg); +static bool dfs_move_checkstop(DfsArg *arg); static void * instance_thread(void *arg); -static void invert_branch(DfsArg *arg); -static void multidfs(Cube c, Trans t, Step *s, SolveOptions *opts, - AlgList *sols, int d); +static void multidfs(DfsArg *arg); static bool niss_makes_sense(DfsArg *arg); static bool solvestop(int d, int op, SolveOptions *opts, AlgList *sols); /* Local functions ***********************************************************/ static bool -allowed_next(Move m, DfsArg *arg) +allowed_next(Move m, StepAlt *sa, Move l0, Move l1) { - bool bad, allowed, order; + bool allowed, order; uint64_t mbit; mbit = ((uint64_t)1) << m; - bad = mbit & arg->badmoves; - allowed = mbit & arg->step->moveset->mask[arg->last2][arg->last1]; - order = !commute(arg->last1, m) || arg->last1 < m; + allowed = mbit & sa->moveset->mask[l1][l0]; + order = !commute(l0, m) || l0 < m; - return allowed && !bad && order; + return allowed && order; } static bool @@ -41,20 +38,20 @@ cancel_niss(DfsArg *arg) Move i1, i2; bool p, p1, p2, q, q1, q2; - if (arg->last1inv == NULLMOVE) + if (arg->lastinv[0] == NULLMOVE) return false; - ms = arg->step->moveset; - i1 = inverse_move(arg->last1inv); - i2 = inverse_move(arg->last2inv); + ms = arg->sa->moveset; + i1 = inverse_move(arg->lastinv[0]); + i2 = inverse_move(arg->lastinv[1]); - p1 = !ms->allowed_next(arg->last2, arg->last1, i1); - p2 = !ms->allowed_next(arg->last2, i1, arg->last1); - p = p1 || (commute(i1, arg->last1) && p2); + p1 = !ms->allowed_next(arg->last[1], arg->last[0], i1); + p2 = !ms->allowed_next(arg->last[1], i1, arg->last[0]); + p = p1 || (commute(i1, arg->last[0]) && p2); - q1 = !ms->allowed_next(arg->last2, arg->last1, i2); - q2 = !ms->allowed_next(arg->last2, i2, arg->last1); - q = q1 || (commute(i2, arg->last1) && q2); + q1 = !ms->allowed_next(arg->last[1], arg->last[0], i2); + q2 = !ms->allowed_next(arg->last[1], i2, arg->last[0]); + q = q1 || (commute(i2, arg->last[0]) && q2); return p || (commute(i1, i2) && q); } @@ -62,142 +59,145 @@ cancel_niss(DfsArg *arg) static void copy_dfsarg(DfsArg *src, DfsArg *dst) { - dst->step = src->step; - dst->opts = src->opts; - dst->t = src->t; - dst->cube = src->cube; - dst->inverse = src->inverse; - dst->d = src->d; - dst->badmoves = src->badmoves; - dst->badmovesinv = src->badmovesinv; - dst->niss = src->niss; - dst->last1 = src->last1; - dst->last2 = src->last2; - dst->last1inv = src->last1inv; - dst->last2inv = src->last2inv; - dst->sols = src->sols; - dst->sols_mutex = src->sols_mutex; - dst->current_alg = src->current_alg; - - copy_estimatedata(src->ed, dst->ed); -} - -static void -dfs(DfsArg *arg) -{ - bool sw = false; - - if (dfs_stop(arg)) - return; - - if (dfs_check_solved(arg)) - return; - - if (arg->step->final && (sw = dfs_switch(arg))) - invert_branch(arg); - dfs_branch(arg); + int i; - if (arg->opts->can_niss && !arg->niss && niss_makes_sense(arg)) - dfs_niss(arg); + dst->cube = src->cube; + dst->t = src->t; + dst->sa = src->sa; + dst->opts = src->opts; + dst->d = src->d; + dst->bound = src->bound; /* In theory not needed */ + dst->niss = src->niss; + dst->sols = src->sols; + dst->sols_mutex = src->sols_mutex; + dst->current_alg = src->current_alg; + + for (i = 0; i < 2; i++) { + dst->last[i] = src->last[i]; + dst->lastinv[i] = src->lastinv[i]; + } - if (sw) - invert_branch(arg); + for (i = 0; i < src->sa->n_coord; i++) { + dst->ind[i].val = src->ind[i].val; + dst->ind[i].t = src->ind[i].t; + } } static void -dfs_branch(DfsArg *arg) +dfs(DfsArg *arg) { int i; Move m; - DfsArg *newarg; - - newarg = malloc(sizeof(DfsArg)); - newarg->ed = malloc(sizeof(EstimateData)); + DfsArg newarg; - for (i = 0; arg->step->moveset->sorted_moves[i] != NULLMOVE; i++) { - m = arg->step->moveset->sorted_moves[i]; - if (allowed_next(m, arg)) { - copy_dfsarg(arg, newarg); - newarg->last2 = arg->last1; - newarg->last1 = m; - newarg->cube = apply_move(m, arg->cube); - append_move(arg->current_alg, m, newarg->niss); + if (dfs_move_checkstop(arg)) + return; - dfs(newarg); + if (arg->bound == 0) { + if (arg->current_alg->len == arg->d) + dfs_add_sol(arg); + return; + } + for (i = 0; arg->sa->moveset->sorted_moves[i] != NULLMOVE; i++) { + m = arg->sa->moveset->sorted_moves[i]; + if (allowed_next(m, arg->sa, 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--; } } - free(newarg->ed); - free(newarg); + if (niss_makes_sense(arg)) + dfs_niss(arg); } -static bool -dfs_check_solved(DfsArg *arg) +static void +dfs_add_sol(DfsArg *arg) { - if (!arg->step->is_done(arg->cube)) - return false; - - if (arg->current_alg->len == arg->d) { - if ((arg->step->is_valid(arg->current_alg) || arg->opts->all) - && (!arg->step->final || !cancel_niss(arg))) { - - pthread_mutex_lock(arg->sols_mutex); + bool valid, accepted, nisscanc; - if (arg->sols->len < arg->opts->max_solutions) { - append_alg(arg->sols, arg->current_alg); + valid = arg->sa->is_valid==NULL || arg->sa->is_valid(arg->current_alg); + accepted = valid || arg->opts->all; + nisscanc = arg->sa->final && cancel_niss(arg); - transform_alg( - inverse_trans(arg->t), - arg->sols->last->alg - ); - if (arg->step->final) - inplace(unniss, arg->sols->last->alg); - - if (arg->opts->verbose) - print_alg(arg->sols->last->alg, false); - } + if (accepted && !nisscanc) { + pthread_mutex_lock(arg->sols_mutex); - pthread_mutex_unlock(arg->sols_mutex); + if (arg->sols->len < arg->opts->max_solutions) { + append_alg(arg->sols, arg->current_alg); + transform_alg( + inverse_trans(arg->t), arg->sols->last->alg); + if (arg->opts->verbose) + print_alg(arg->sols->last->alg, false); } - } - return true; + pthread_mutex_unlock(arg->sols_mutex); + } } static void dfs_niss(DfsArg *arg) { - DfsArg *newarg; - - newarg = malloc(sizeof(DfsArg)); - newarg->ed = malloc(sizeof(EstimateData)); - - copy_dfsarg(arg, newarg); - swapmove(&(newarg->last1), &(newarg->last1inv)); - swapmove(&(newarg->last2), &(newarg->last2inv)); - newarg->niss = !(arg->niss); - newarg->cube = inverse_cube(arg->cube); - - dfs(newarg); - - free(newarg->ed); - free(newarg); + DfsArg newarg; + Alg *inv; + Cube *c; + + copy_dfsarg(arg, &newarg); + + /* Invert current alg and scramble */ + newarg.cube = malloc(sizeof(Cube)); + inv = inverse_alg(arg->current_alg); + c = malloc(sizeof(Cube)); + make_solved(newarg.cube); + apply_alg(inv, newarg.cube); + copy_cube(arg->cube, c); + invert_cube(c); + compose(c, newarg.cube); + + /* New indexes */ + compute_ind(newarg.sa, newarg.cube, newarg.ind); + + swapmove(&(newarg.last[0]), &(newarg.lastinv[0])); + swapmove(&(newarg.last[1]), &(newarg.lastinv[1])); + newarg.niss = !(arg->niss); + + dfs(&newarg); + + free_alg(inv); + free(c); + free(newarg.cube); } static bool -dfs_stop(DfsArg *arg) +dfs_move_checkstop(DfsArg *arg) { - int lowerbound; bool b; + int i, goal; + Move mm; + Trans tt = uf; /* Avoid uninitialized warning */ + + /* Moving */ + if (arg->last[0] != NULLMOVE) { + for (i = 0; i < arg->sa->n_coord; i++) { + mm = transform_move(arg->ind[i].t, arg->last[0]); + arg->ind[i].val = move_coord(arg->sa->coord[i], + mm, arg->ind[i].val, &tt); + arg->ind[i].t = transform_trans(tt, arg->ind[i].t); + } + } - lowerbound = arg->step->estimate(arg); + /* Computing bound for coordinates */ + goal = arg->d - arg->current_alg->len; + arg->bound = estimate_stepalt(arg->sa, arg->ind, goal); if (arg->opts->can_niss && !arg->niss) - lowerbound = MIN(1, lowerbound); + arg->bound = MIN(1, arg->bound); - if (arg->current_alg->len + lowerbound > arg->d) { - b = true; + if (arg->bound > goal) { + b = true; } else { pthread_mutex_lock(arg->sols_mutex); b = arg->sols->len >= arg->opts->max_solutions; @@ -207,37 +207,12 @@ dfs_stop(DfsArg *arg) return b; } -static bool -dfs_switch(DfsArg *arg) -{ - int i, bn, bi; - - bn = 0; - for (i = 0; arg->step->moveset->sorted_moves[i] != NULLMOVE; i++) - if (allowed_next(arg->step->moveset->sorted_moves[i], arg)) - bn++; - - swapmove(&(arg->last1), &(arg->last1inv)); - swapmove(&(arg->last2), &(arg->last2inv)); - swapu64(&(arg->badmoves), &(arg->badmovesinv)); - - bi = 0; - for (i = 0; arg->step->moveset->sorted_moves[i] != NULLMOVE; i++) - if (allowed_next(arg->step->moveset->sorted_moves[i], arg)) - bi++; - - swapmove(&(arg->last1), &(arg->last1inv)); - swapmove(&(arg->last2), &(arg->last2inv)); - swapu64(&(arg->badmoves), &(arg->badmovesinv)); - - return bi < bn; -} - static void * instance_thread(void *arg) { - bool b; + bool b, inv; Cube c; + Move m; ThreadDataSolve *td; AlgListNode *node; DfsArg darg; @@ -257,68 +232,46 @@ instance_thread(void *arg) if (b) break; - c = node->alg->inv[0] ? - apply_move(node->alg->move[0], inverse_cube(td->cube)) : - apply_move(node->alg->move[0], td->cube); - - darg.step = td->step; - darg.opts = td->opts; - darg.t = td->t; - darg.cube = c; - darg.d = td->depth; - darg.niss = node->alg->inv[0]; - darg.last1 = node->alg->move[0]; - darg.last2 = NULLMOVE; - darg.last1inv = NULLMOVE; - darg.last2inv = NULLMOVE; - darg.sols = td->sols; - darg.sols_mutex = td->sols_mutex; + inv = node->alg->inv[0]; + m = node->alg->move[0]; + + copy_cube(td->arg.cube, &c); + if (inv) + invert_cube(&c); + + copy_dfsarg(&td->arg, &darg); + compute_ind(td->arg.sa, &c, darg.ind); + darg.cube = &c; + + darg.niss = inv; + darg.last[0] = m; + darg.last[1] = NULLMOVE; + darg.lastinv[0] = NULLMOVE; + darg.lastinv[1] = NULLMOVE; darg.current_alg = new_alg(""); - append_move(darg.current_alg, node->alg->move[0], - node->alg->inv[0]); - darg.ed = malloc(sizeof(EstimateData)); - reset_estimatedata(darg.ed); - darg.badmoves = 0; - darg.badmovesinv = 0; + append_move(darg.current_alg, m, inv); dfs(&darg); free_alg(darg.current_alg); - free(darg.ed); } return NULL; } static void -invert_branch(DfsArg *arg) -{ - Cube aux; - - aux = arg->cube; - arg->cube = is_solved(arg->inverse) ? - inverse_cube(arg->cube) : arg->inverse; - arg->inverse = aux; - - swapu64(&(arg->badmoves), &(arg->badmovesinv)); - arg->niss = !(arg->niss); - swapmove(&(arg->last1), &(arg->last1inv)); - swapmove(&(arg->last2), &(arg->last2inv)); - invert_estimatedata(arg->ed); -} - -static void -multidfs(Cube c, Trans tr, Step *s, SolveOptions *opts, AlgList *sols, int d) +multidfs(DfsArg *arg) { int i; + Cube local_cube; Alg *alg; AlgList *start; AlgListNode **node; - pthread_t t[opts->nthreads]; - ThreadDataSolve td[opts->nthreads]; + pthread_t t[arg->opts->nthreads]; + ThreadDataSolve td[arg->opts->nthreads]; pthread_mutex_t *start_mutex, *sols_mutex; - node = malloc(sizeof(AlgListNode *)); + node = malloc(sizeof(AlgListNode *)); start_mutex = malloc(sizeof(pthread_mutex_t)); sols_mutex = malloc(sizeof(pthread_mutex_t)); @@ -326,11 +279,11 @@ multidfs(Cube c, Trans tr, Step *s, SolveOptions *opts, AlgList *sols, int d) pthread_mutex_init(start_mutex, NULL); pthread_mutex_init(sols_mutex, NULL); - for (i = 0; s->moveset->sorted_moves[i] != NULLMOVE; i++) { + for (i = 0; arg->sa->moveset->sorted_moves[i] != NULLMOVE; i++) { alg = new_alg(""); - append_move(alg, s->moveset->sorted_moves[i], false); + append_move(alg, arg->sa->moveset->sorted_moves[i], false); append_alg(start, alg); - if (opts->can_niss) { + if (arg->opts->can_niss && !arg->sa->final) { alg->inv[0] = true; append_alg(start, alg); } @@ -338,22 +291,22 @@ multidfs(Cube c, Trans tr, Step *s, SolveOptions *opts, AlgList *sols, int d) } *node = start->first; - for (i = 0; i < opts->nthreads; i++) { - td[i].thid = i; - td[i].t = tr; - td[i].cube = c; - td[i].step = s; - td[i].depth = d; - td[i].opts = opts; - td[i].start = start; - td[i].node = node; - td[i].sols = sols; - td[i].start_mutex = start_mutex; - td[i].sols_mutex = sols_mutex; + copy_cube(arg->cube, &local_cube); + + for (i = 0; i < arg->opts->nthreads; i++) { + copy_dfsarg(arg, &(td[i].arg)); + td[i].arg.cube = &local_cube; + td[i].arg.sols_mutex = sols_mutex; + + td[i].thid = i; + td[i].start = start; + td[i].node = node; + td[i].start_mutex = start_mutex; + pthread_create(&t[i], NULL, instance_thread, &td[i]); } - for (i = 0; i < opts->nthreads; i++) + for (i = 0; i < arg->opts->nthreads; i++) pthread_join(t[i], NULL); free_alglist(start); @@ -367,8 +320,13 @@ niss_makes_sense(DfsArg *arg) { Cube testcube; - testcube = apply_move(inverse_move(arg->last1), (Cube){0}); - return arg->current_alg->len == 0 || !arg->step->is_done(testcube); + if (arg->sa->final || arg->niss || !arg->opts->can_niss) + return false; + + make_solved(&testcube); + apply_move(inverse_move(arg->last[0]), &testcube); + return arg->current_alg->len == 0 || + estimate_stepalt(arg->sa, arg->ind, 0) > 0; } static bool @@ -386,62 +344,84 @@ solvestop(int d, int op, SolveOptions *opts, AlgList *sols) /* Public functions **********************************************************/ AlgList * -solve(Cube cube, Step *step, SolveOptions *opts) +solve(Cube *cube, Step *step, SolveOptions *opts) { - bool ready; - int i, d, op, nt; - AlgList *sols; - Cube c; - Trans tt[NTRANS]; + int i, d, op; + bool ready[99], one_ready, zerosol; + Movable ind[99][10]; + AlgList *s; + Cube *c[99]; + DfsArg arg[99]; prepare_step(step, opts); - - if (step->detect != NULL) { - nt = step->detect(cube, tt); - } else { - tt[0] = step->pre_trans; - ready = step->ready == NULL || - step->ready(apply_trans(tt[0], cube)); - nt = ready ? 1 : 0; + s = new_alglist(); + + for (i = 0, one_ready = false; step->alt[i] != NULL; i++) { + c[i] = malloc(sizeof(Cube)); + copy_cube(cube, c[i]); + apply_trans(step->t[i], c[i]); + + arg[i].cube = c[i]; + arg[i].t = step->t[i]; + arg[i].sa = step->alt[i]; + arg[i].opts = opts; + arg[i].sols = s; + + if ((ready[i] = step->alt[i]->ready(c[i]))) { + one_ready = true; + /* Only for local use for 0 moves solutions */ + compute_ind(step->alt[i], c[i], ind[i]); + } } - - sols = new_alglist(); - - if (nt == 0) { + if (!one_ready) { fprintf(stderr, "Cube not ready for solving step: "); fprintf(stderr, "%s\n", step->ready_msg); - return sols; + return s; } - if (opts->min_moves == 0) { - for (i = 0; i < nt; i++) { - c = apply_trans(tt[i], cube); - if (step->is_done(c)) { - append_alg(sols, new_alg("")); - return sols; - } + /* If the empty moves sequence is a solution for one of the + * alternatives, all longer solutions will be discarded, so we may + * just set its ready[] value to false. If the solution is accepted + * we append it and start searching from d = 1. */ + for (i = 0, zerosol = false; step->alt[i] != NULL; i++) { + if (ready[i] && estimate_stepalt(step->alt[i],ind[i],0) == 0) { + ready[i] = false; + zerosol = true; } } + if (zerosol && opts->min_moves == 0) { + append_alg(s, new_alg("")); + opts->min_moves = 1; + if (opts->verbose) + printf("Step is already solved" + "(empty alg is a solution)\n"); + } - op = -1; - for (d = opts->min_moves; !solvestop(d, op, opts, sols); d++) { + for (d = opts->min_moves, op = -1; !solvestop(d, op, opts, s); d++) { if (opts->verbose) fprintf(stderr, "Searching depth %d\n", d); - for (i = 0; i < nt && !solvestop(d, op, opts, sols); i++) { - c = apply_trans(tt[i], cube); - multidfs(c, tt[i], step, opts, sols, d); - if (sols->len > 0 && op == -1) + for (i=0; step->alt[i]!=NULL && !solvestop(d,op,opts,s); i++) { + if (!ready[i]) + continue; + + arg[i].d = d; + multidfs(&arg[i]); + + if (s->len > 0 && op == -1) op = d; } } - return sols; + for (i = 0; step->alt[i] != NULL; i++) + free(c[i]); + + return s; } /* TODO: make more general! */ Alg * -solve_2phase(Cube cube, int nthreads) +solve_2phase(Cube *cube, int nthreads) { int bestlen, newb; Alg *bestalg, *ret; @@ -466,18 +446,19 @@ solve_2phase(Cube cube, int nthreads) opts2.can_niss = false; opts2.verbose = false; - /* We skip step1 if it is solved on any axis */ - if (drany_HTM.is_done(cube)) { + /* We skip step1 if it is solved on U/D */ + if (check_drud(cube)) { sols1 = new_alglist(); append_alg(sols1, new_alg("")); } else { - sols1 = solve(cube, &drany_HTM, &opts1); + sols1 = solve(cube, &drud_HTM, &opts1); } bestalg = new_alg(""); bestlen = 999; for (i = sols1->first; i != NULL; i = i->next) { - c = apply_alg(i->alg, cube); - sols2 = solve(c, &dranyfin_DR, &opts2); + copy_cube(cube, &c); + apply_alg(i->alg, &c); + sols2 = solve(&c, &dranyfin_DR, &opts2); if (sols2->len > 0) { newb = i->alg->len + sols2->first->alg->len; diff --git a/src/solve.h b/src/solve.h @@ -5,7 +5,7 @@ #include "steps.h" #include "trans.h" -AlgList * solve(Cube cube, Step *step, SolveOptions *opts); -Alg * solve_2phase(Cube cube, int nthreads); +AlgList * solve(Cube *cube, Step *step, SolveOptions *opts); +Alg * solve_2phase(Cube *cube, int nthreads); #endif diff --git a/src/steps.c b/src/steps.c @@ -1,1372 +1,112 @@ -#include "steps.h" - -#define UPDATECHECKSTOP(a, b, c) if ((a=(MAX((a),(b))))>(c)) return (a); - -/* Checkers, estimators and validators ***************************************/ - -static bool check_centers(Cube cube); -static bool check_coud_HTM(Cube cube); -static bool check_coud_URF(Cube cube); -static bool check_corners_HTM(Cube cube); -static bool check_corners_URF(Cube cube); -static bool check_cornershtr(Cube cube); -static bool check_eofb(Cube cube); -static bool check_drud(Cube cube); -static bool check_htr(Cube cube); - -static int estimate_eofb_HTM(DfsArg *arg); -static int estimate_coud_HTM(DfsArg *arg); -static int estimate_coud_URF(DfsArg *arg); -static int estimate_corners_HTM(DfsArg *arg); -static int estimate_cornershtr_HTM(DfsArg *arg); -static int estimate_corners_URF(DfsArg *arg); -static int estimate_cornershtr_URF(DfsArg *arg); -static int estimate_drud_HTM(DfsArg *arg); -static int estimate_drud_eofb(DfsArg *arg); -static int estimate_dr_eofb(DfsArg *arg); -static int estimate_drudfin_drud(DfsArg *arg); -static int estimate_htr_drud(DfsArg *arg); -static int estimate_htrfin_htr(DfsArg *arg); -static int estimate_nxopt31_HTM(DfsArg *arg); -static int estimate_light_HTM(DfsArg *arg); - -static int estimate_nxoptlike(DfsArg *arg, PruneData *pd); - -static bool always_valid(Alg *alg); -static bool validate_singlecw_ending(Alg *alg); - -/* Pre-transformation detectors **********************************************/ - -static int detect_pretrans_eofb(Cube cube, Trans *ret); -static int detect_pretrans_drud(Cube cube, Trans *ret); -static int detect_pretrans_void_3axis(Cube cube, Trans *ret); - -/* Messages for when cube is not ready ***************************************/ - -static char check_centers_msg[100] = "cube must be oriented (centers solved)"; -static char check_eo_msg[100] = "EO must be solved on given axis"; -static char check_dr_msg[100] = "DR must be solved on given axis"; -static char check_htr_msg[100] = "HTR must be solved"; -static char check_drany_msg[100] = "DR must be solved on at least one axis"; - -/* Steps *********************************************************************/ - -/* Optimal solvers *******************/ - -Step -optimal_HTM = { - .shortname = "optimal", - .name = "Optimal solve (in HTM)", - - .final = true, - .is_done = is_solved, - .estimate = estimate_nxopt31_HTM, - .ready = check_centers, - .ready_msg = check_centers_msg, - .is_valid = always_valid, - .moveset = &moveset_HTM, - - .pre_trans = uf, - - .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, - .ntables = 2, -}; - -Step -optimal_light_HTM = { - .shortname = "light", - .name = "Optimal solve (in HTM), small table (500Mb RAM total)", - - .final = true, - .is_done = is_solved, - .estimate = estimate_light_HTM, - .ready = check_centers, - .ready_msg = check_centers_msg, - .is_valid = always_valid, - .moveset = &moveset_HTM, - - .pre_trans = uf, - - .tables = {&pd_drud_sym16_HTM, &pd_corners_HTM}, - .ntables = 2, -}; - -/* Optimal after EO ******************/ - -Step -eofin_eo = { - .shortname = "eofin", - .name = "Optimal solve after EO without breaking EO (detected)", - - .final = true, - .is_done = is_solved, - .estimate = estimate_nxopt31_HTM, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = always_valid, - .moveset = &moveset_eofb, - - .detect = detect_pretrans_eofb, - - .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, - .ntables = 2, -}; - -Step -eofbfin_eofb = { - .shortname = "eofbfin", - .name = "Optimal after EO on F/B without breaking EO", - - .final = true, - .is_done = is_solved, - .estimate = estimate_nxopt31_HTM, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = always_valid, - .moveset = &moveset_eofb, - - .pre_trans = uf, - - .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, - .ntables = 2, -}; - -Step -eorlfin_eorl = { - .shortname = "eorlfin", - .name = "Optimal after EO on R/L without breaking EO", - - .final = true, - .is_done = is_solved, - .estimate = estimate_nxopt31_HTM, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = always_valid, - .moveset = &moveset_eofb, - - .pre_trans = ur, - - .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, - .ntables = 2, -}; - -Step -eoudfin_eoud = { - .shortname = "eoudfin", - .name = "Optimal after EO on U/D without breaking EO", - - .final = true, - .is_done = is_solved, - .estimate = estimate_nxopt31_HTM, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = always_valid, - .moveset = &moveset_eofb, - - .pre_trans = fd, - - .tables = {&pd_nxopt31_HTM, &pd_corners_HTM}, - .ntables = 2, -}; - -/* EO steps **************************/ -Step -eoany_HTM = { - .shortname = "eo", - .name = "EO on any axis", - - .final = false, - .is_done = check_eofb, - .estimate = estimate_eofb_HTM, - .ready = check_centers, - .ready_msg = check_centers_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_HTM, - - .detect = detect_pretrans_void_3axis, - - .tables = {&pd_eofb_HTM}, - .ntables = 1, -}; - -Step -eofb_HTM = { - .shortname = "eofb", - .name = "EO on F/B", - - .final = false, - .is_done = check_eofb, - .estimate = estimate_eofb_HTM, - .ready = check_centers, - .ready_msg = check_centers_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_HTM, - - .pre_trans = uf, - - .tables = {&pd_eofb_HTM}, - .ntables = 1, -}; - -Step -eorl_HTM = { - .shortname = "eorl", - .name = "EO on R/L", - - .final = false, - .is_done = check_eofb, - .estimate = estimate_eofb_HTM, - .ready = check_centers, - .ready_msg = check_centers_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_HTM, - - .pre_trans = ur, - - .tables = {&pd_eofb_HTM}, - .ntables = 1, -}; - -Step -eoud_HTM = { - .shortname = "eoud", - .name = "EO on U/D", - - .final = false, - .is_done = check_eofb, - .estimate = estimate_eofb_HTM, - .ready = check_centers, - .ready_msg = check_centers_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_HTM, - - .pre_trans = fd, - - .tables = {&pd_eofb_HTM}, - .ntables = 1, -}; - -/* CO steps **************************/ -Step -coany_HTM = { - .shortname = "co", - .name = "CO on any axis", - - .final = false, - .is_done = check_coud_HTM, - .estimate = estimate_coud_HTM, - .ready = NULL, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_HTM, - - .detect = detect_pretrans_void_3axis, - - .tables = {&pd_coud_HTM}, - .ntables = 1, -}; - -Step -coud_HTM = { - .shortname = "coud", - .name = "CO on U/D", - - .final = false, - .is_done = check_coud_HTM, - .estimate = estimate_coud_HTM, - .ready = NULL, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_HTM, - - .pre_trans = uf, - - .tables = {&pd_coud_HTM}, - .ntables = 1, -}; - -Step -corl_HTM = { - .shortname = "corl", - .name = "CO on R/L", - - .final = false, - .is_done = check_coud_HTM, - .estimate = estimate_coud_HTM, - .ready = NULL, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_HTM, - - .pre_trans = rf, - - .tables = {&pd_coud_HTM}, - .ntables = 1, -}; - -Step -cofb_HTM = { - .shortname = "cofb", - .name = "CO on F/B", - - .final = false, - .is_done = check_coud_HTM, - .estimate = estimate_coud_HTM, - .ready = NULL, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_HTM, - - .pre_trans = fd, - - .tables = {&pd_coud_HTM}, - .ntables = 1, -}; - -Step -coany_URF = { - .shortname = "co-URF", - .name = "CO any axis (URF moveset)", - - .final = false, - .is_done = check_coud_URF, - .estimate = estimate_coud_URF, - .ready = NULL, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_URF, - - .detect = detect_pretrans_void_3axis, - - .tables = {&pd_coud_HTM}, - .ntables = 1, -}; - -Step -coud_URF = { - .shortname = "coud-URF", - .name = "CO on U/D (URF moveset)", - - .final = false, - .is_done = check_coud_URF, - .estimate = estimate_coud_URF, - .ready = NULL, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_URF, - - .pre_trans = uf, - - .tables = {&pd_coud_HTM}, - .ntables = 1, -}; - -Step -corl_URF = { - .shortname = "corl-URF", - .name = "CO on R/L (URF moveset)", - - .final = false, - .is_done = check_coud_URF, - .estimate = estimate_coud_URF, - .ready = NULL, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_URF, - - .pre_trans = rf, - - .tables = {&pd_coud_HTM}, - .ntables = 1, -}; - -Step -cofb_URF = { - .shortname = "cofb-URF", - .name = "CO on F/B (URF moveset)", - - .final = false, - .is_done = check_coud_URF, - .estimate = estimate_coud_URF, - .ready = NULL, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_URF, - - .pre_trans = fd, - - .tables = {&pd_coud_HTM}, - .ntables = 1, -}; - -/* Misc corner steps *****************/ -Step -cornershtr_HTM = { - .shortname = "chtr", - .name = "Solve corners to HTR state", - - .final = false, - .is_done = check_cornershtr, - .estimate = estimate_cornershtr_HTM, - .ready = NULL, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_HTM, - - .pre_trans = uf, - - .tables = {&pd_cornershtr_HTM}, - .ntables = 1, -}; - -Step -cornershtr_URF = { - .shortname = "chtr-URF", - .name = "Solve corners to HTR state (URF moveset)", - - .final = false, - .is_done = check_cornershtr, - .estimate = estimate_cornershtr_URF, - .ready = NULL, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_URF, - - .pre_trans = uf, - - .tables = {&pd_cornershtr_HTM}, - .ntables = 1, -}; - -Step -corners_HTM = { - .shortname = "corners", - .name = "Solve corners", - - .final = true, - .is_done = check_corners_HTM, - .estimate = estimate_corners_HTM, - .ready = NULL, - .is_valid = always_valid, - .moveset = &moveset_HTM, - - .pre_trans = uf, - - .tables = {&pd_corners_HTM}, - .ntables = 1, -}; - -Step -corners_URF = { - .shortname = "corners-URF", - .name = "Solve corners (URF moveset)", - - .final = true, /* TODO: check if this works with reorient */ - .is_done = check_corners_URF, - .estimate = estimate_corners_URF, - .ready = NULL, - .is_valid = always_valid, - .moveset = &moveset_URF, - - .pre_trans = uf, - - .tables = {&pd_corners_HTM}, - .ntables = 1, -}; - -/* DR steps **************************/ -Step -drany_HTM = { - .shortname = "dr", - .name = "DR on any axis", - - .final = false, - .is_done = check_drud, - .estimate = estimate_drud_HTM, - .ready = check_centers, - .ready_msg = check_centers_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_HTM, - - .detect = detect_pretrans_void_3axis, - - .tables = {&pd_drud_sym16_HTM}, - .ntables = 1, -}; - -Step -drud_HTM = { - .shortname = "drud", - .name = "DR on U/D", - - .final = false, - .is_done = check_drud, - .estimate = estimate_drud_HTM, - .ready = check_centers, - .ready_msg = check_centers_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_HTM, - - .pre_trans = uf, - - .tables = {&pd_drud_sym16_HTM}, - .ntables = 1, -}; - -Step -drrl_HTM = { - .shortname = "drrl", - .name = "DR on R/L", - - .final = false, - .is_done = check_drud, - .estimate = estimate_drud_HTM, - .ready = check_centers, - .ready_msg = check_centers_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_HTM, - - .pre_trans = rf, - - .tables = {&pd_drud_sym16_HTM}, - .ntables = 1, -}; - -Step -drfb_HTM = { - .shortname = "drfb", - .name = "DR on F/B", - - .final = false, - .is_done = check_drud, - .estimate = estimate_drud_HTM, - .ready = check_centers, - .ready_msg = check_centers_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_HTM, - - .pre_trans = fd, - - .tables = {&pd_drud_sym16_HTM}, - .ntables = 1, -}; - -/* DR from EO */ -Step -dr_eo = { - .shortname = "dr-eo", - .name = "DR without breaking EO (automatically detected)", - - .final = false, - .is_done = check_drud, - .estimate = estimate_dr_eofb, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_eofb, - - .detect = detect_pretrans_eofb, - - .tables = {&pd_drud_eofb}, - .ntables = 1, -}; - -Step -dr_eofb = { - .shortname = "dr-eofb", - .name = "DR on U/D or R/L without breaking EO on F/B", - - .final = false, - .is_done = check_drud, - .estimate = estimate_dr_eofb, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_eofb, - - .pre_trans = uf, - - .tables = {&pd_drud_eofb}, - .ntables = 1, -}; - -Step -dr_eorl = { - .shortname = "dr-eorl", - .name = "DR on U/D or F/B without breaking EO on R/L", - - .final = false, - .is_done = check_drud, - .estimate = estimate_dr_eofb, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_eofb, - - .pre_trans = ur, - - .tables = {&pd_drud_eofb}, - .ntables = 1, -}; - -Step -dr_eoud = { - .shortname = "dr-eoud", - .name = "DR on R/L or F/B without breaking EO on U/D", - - .final = false, - .is_done = check_drud, - .estimate = estimate_dr_eofb, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_eofb, - - .pre_trans = fd, - - .tables = {&pd_drud_eofb}, - .ntables = 1, -}; - -Step -drud_eofb = { - .shortname = "drud-eofb", - .name = "DR on U/D without breaking EO on F/B", - - .final = false, - .is_done = check_drud, - .estimate = estimate_drud_eofb, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_eofb, - - .pre_trans = uf, - - .tables = {&pd_drud_eofb}, - .ntables = 1, -}; - -Step -drrl_eofb = { - .shortname = "drrl-eofb", - .name = "DR on R/L without breaking EO on F/B", - - .final = false, - .is_done = check_drud, - .estimate = estimate_drud_eofb, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_eofb, - - .pre_trans = rf, - - .tables = {&pd_drud_eofb}, - .ntables = 1, -}; - -Step -drud_eorl = { - .shortname = "drud-eorl", - .name = "DR on U/D without breaking EO on R/L", - - .final = false, - .is_done = check_drud, - .estimate = estimate_drud_eofb, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_eofb, - - .pre_trans = ur, - - .tables = {&pd_drud_eofb}, - .ntables = 1, -}; - -Step -drfb_eorl = { - .shortname = "drfb-eorl", - .name = "DR on F/B without breaking EO on R/L", - - .final = false, - .is_done = check_drud, - .estimate = estimate_drud_eofb, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_eofb, - - .pre_trans = fr, - - .tables = {&pd_drud_eofb}, - .ntables = 1, -}; - -Step -drfb_eoud = { - .shortname = "drfb-eoud", - .name = "DR on F/B without breaking EO on U/D", - - .final = false, - .is_done = check_drud, - .estimate = estimate_drud_eofb, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_eofb, - - .pre_trans = fd, - - .tables = {&pd_drud_eofb}, - .ntables = 1, -}; - -Step -drrl_eoud = { - .shortname = "drrl-eoud", - .name = "DR on R/L without breaking EO on U/D", - - .final = false, - .is_done = check_drud, - .estimate = estimate_drud_eofb, - .ready = check_eofb, - .ready_msg = check_eo_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_eofb, - - .pre_trans = rd, - - .tables = {&pd_drud_eofb}, - .ntables = 1, -}; - -/* DR finish steps */ -Step -dranyfin_DR = { - .shortname = "drfin", - .name = "DR finish on any axis without breaking DR", - - .final = true, - .is_done = is_solved, - .estimate = estimate_drudfin_drud, - .ready = check_drud, - .ready_msg = check_drany_msg, - .is_valid = always_valid, - .moveset = &moveset_drud, - - .detect = detect_pretrans_drud, - - .tables = {&pd_drudfin_noE_sym16_drud}, - .ntables = 1, -}; - -Step -drudfin_drud = { - .shortname = "drudfin", - .name = "DR finish on U/D without breaking DR", - - .final = true, - .is_done = is_solved, - .estimate = estimate_drudfin_drud, - .ready = check_drud, - .ready_msg = check_dr_msg, - .is_valid = always_valid, - .moveset = &moveset_drud, - - .pre_trans = uf, - - .tables = {&pd_drudfin_noE_sym16_drud}, - .ntables = 1, -}; - -Step -drrlfin_drrl = { - .shortname = "drrlfin", - .name = "DR finish on R/L without breaking DR", - - .final = true, - .is_done = is_solved, - .estimate = estimate_drudfin_drud, - .ready = check_drud, - .ready_msg = check_dr_msg, - .is_valid = always_valid, - .moveset = &moveset_drud, - - .pre_trans = rf, - - .tables = {&pd_drudfin_noE_sym16_drud}, - .ntables = 1, -}; - -Step -drfbfin_drfb = { - .shortname = "drfbfin", - .name = "DR finish on F/B without breaking DR", - - .final = true, - .is_done = is_solved, - .estimate = estimate_drudfin_drud, - .ready = check_drud, - .ready_msg = check_dr_msg, - .is_valid = always_valid, - .moveset = &moveset_drud, - - .pre_trans = fd, - - .tables = {&pd_drudfin_noE_sym16_drud}, - .ntables = 1, -}; - -/* HTR from DR */ -Step -htr_any = { - .shortname = "htr", - .name = "HTR from DR", - - .final = false, - .is_done = check_htr, - .estimate = estimate_htr_drud, - .ready = check_drud, - .ready_msg = check_drany_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_drud, +#define STEPS_C - .detect = detect_pretrans_drud, - - .tables = {&pd_htr_drud}, - .ntables = 1, -}; - -Step -htr_drud = { - .shortname = "htr-drud", - .name = "HTR from DR on U/D", - - .final = false, - .is_done = check_htr, - .estimate = estimate_htr_drud, - .ready = check_drud, - .ready_msg = check_dr_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_drud, - - .pre_trans = uf, - - .tables = {&pd_htr_drud}, - .ntables = 1, -}; - -Step -htr_drrl = { - .shortname = "htr-drrl", - .name = "HTR from DR on R/L", - - .final = false, - .is_done = check_htr, - .estimate = estimate_htr_drud, - .ready = check_drud, - .ready_msg = check_dr_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_drud, - - .pre_trans = rf, - - .tables = {&pd_htr_drud}, - .ntables = 1, -}; - -Step -htr_drfb = { - .shortname = "htr-drfb", - .name = "HTR from DR on F/B", - - .final = false, - .is_done = check_htr, - .estimate = estimate_htr_drud, - .ready = check_drud, - .ready_msg = check_dr_msg, - .is_valid = validate_singlecw_ending, - .moveset = &moveset_drud, - - .pre_trans = fd, - - .tables = {&pd_htr_drud}, - .ntables = 1, -}; - -/* HTR finish */ -Step -htrfin_htr = { - .shortname = "htrfin", - .name = "HTR finish without breaking HTR", - - .final = true, - .is_done = is_solved, - .estimate = estimate_htrfin_htr, - .ready = check_htr, - .ready_msg = check_htr_msg, - .is_valid = always_valid, - .moveset = &moveset_htr, - - .pre_trans = uf, - - .tables = {&pd_htrfin_htr}, - .ntables = 1, -}; - -Step *steps[] = { - &optimal_HTM, /* first is default */ - &optimal_light_HTM, - - &eofin_eo, - &eofbfin_eofb, - &eorlfin_eorl, - &eoudfin_eoud, - - &eoany_HTM, - &eofb_HTM, - &eorl_HTM, - &eoud_HTM, - - &coany_HTM, - &coud_HTM, - &corl_HTM, - &cofb_HTM, - - &coany_URF, - &coud_URF, - &corl_URF, - &cofb_URF, - - &drany_HTM, - &drud_HTM, - &drrl_HTM, - &drfb_HTM, - - &dr_eo, - &dr_eofb, - &dr_eorl, - &dr_eoud, - &drud_eofb, - &drrl_eofb, - &drud_eorl, - &drfb_eorl, - &drfb_eoud, - &drrl_eoud, - - &dranyfin_DR, - &drudfin_drud, - &drrlfin_drrl, - &drfbfin_drfb, - - &htr_any, - &htr_drud, - &htr_drrl, - &htr_drfb, - - &htrfin_htr, - - &cornershtr_HTM, - &cornershtr_URF, - &corners_HTM, - &corners_URF, - - NULL -}; - -/* Checkers, estimators and validators ***************************************/ - -static bool -check_centers(Cube cube) -{ - return cube.cpos == 0; -} - -static bool -check_coud_HTM(Cube cube) -{ - return cube.coud == 0; -} - -static bool -check_coud_URF(Cube cube) -{ - Cube c2, c3; - - c2 = apply_move(z, cube); - c3 = apply_move(x, cube); +#include "steps.h" - return cube.coud == 0 || c2.coud == 0 || c3.coud == 0; -} +/* TODO: change all checkers to use coordinates! */ -static bool -check_corners_URF(Cube cube) +bool +check_centers(Cube *cube) { - Cube c; - Trans i; + int i; - for (i = 0; i < NROTATIONS; i++) { - c = apply_alg(rotation_alg(i), cube); - if (c.cp && c.coud) - return true; - } + for (i = 0; i < 6; i++) + if (cube->xp[i] != i) + return false; - return false; + return true; } -static bool -check_corners_HTM(Cube cube) +bool +check_coud_HTM(Cube *cube) { - return cube.cp == 0 && cube.coud == 0; -} + int i; -static bool -check_cornershtr(Cube cube) -{ - return coord_cornershtr.index(cube) == 0; -} + for (i = 0; i < 8; i++) + if (cube->co[i] != 0) + return false; -static bool -check_eofb(Cube cube) -{ - return cube.eofb == 0; + return true; } -static bool -check_drud(Cube cube) +bool +check_coud_URF(Cube *cube) { - return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0; -} + Cube c2, c3; -static bool -check_htr(Cube cube) -{ - return check_drud(cube) && coord_htr_drud.index(cube) == 0; -} + copy_cube(cube, &c2); + copy_cube(cube, &c3); -static int -estimate_eofb_HTM(DfsArg *arg) -{ - return ptableval(&pd_eofb_HTM, arg->cube); -} + apply_move(z, &c2); + apply_move(x, &c3); -static int -estimate_coud_HTM(DfsArg *arg) -{ - return ptableval(&pd_coud_HTM, arg->cube); + return check_coud_HTM(cube) || + check_coud_HTM(&c2) || + check_coud_HTM(&c3); } -static int -estimate_coud_URF(DfsArg *arg) +bool +check_cp_HTM(Cube *cube) { - /* TODO: I can improve this by checking first the orientation of - * the corner in DBL and use that as a reference */ - - Cube c; - - c = arg->cube; - - int ud = estimate_coud_HTM(arg); - arg->cube = apply_move(z, c); - int rl = estimate_coud_HTM(arg); - arg->cube = apply_move(x, c); - int fb = estimate_coud_HTM(arg); - - arg->cube = c; + int i; - return MIN(ud, MIN(rl, fb)); -} + for (i = 0; i < 8; i++) + if (cube->cp[i] != i) + return false; -static int -estimate_corners_HTM(DfsArg *arg) -{ - return ptableval(&pd_corners_HTM, arg->cube); -} - -static int -estimate_cornershtr_HTM(DfsArg *arg) -{ - return ptableval(&pd_cornershtr_HTM, arg->cube); + return true; } -static int -estimate_cornershtr_URF(DfsArg *arg) +bool +check_corners_HTM(Cube *cube) { - /* TODO: I can improve this by checking first the corner in DBL - * and use that as a reference */ - - int ret; - Cube c; - Trans i; - - c = arg->cube; - ret = 15; - - for (i = 0; i < NROTATIONS; i++) { - arg->cube = apply_alg(rotation_alg(i), c); - ret = MIN(ret, estimate_cornershtr_HTM(arg)); - } - - arg->cube = c; - - return ret; + return check_coud_HTM(cube) && check_cp_HTM(cube); } -static int -estimate_corners_URF(DfsArg *arg) +bool +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; Cube c; Trans i; - c = arg->cube; - ret = 15; - for (i = 0; i < NROTATIONS; i++) { - arg->cube = apply_alg(rotation_alg(i), c); - ret = MIN(ret, estimate_corners_HTM(arg)); + copy_cube(cube, &c); + apply_alg(rotation_alg(i), &c); + if (check_corners_HTM(&c)) + return true; } - arg->cube = c; - - return ret; -} - -static int -estimate_drud_HTM(DfsArg *arg) -{ - return ptableval(&pd_drud_sym16_HTM, arg->cube); -} - -static int -estimate_drud_eofb(DfsArg *arg) -{ - return ptableval(&pd_drud_eofb, arg->cube); -} - -static int -estimate_dr_eofb(DfsArg *arg) -{ - int r1, r2; - - r1 = ptableval(&pd_drud_eofb, arg->cube); - r2 = ptableval(&pd_drud_eofb, apply_trans(rf, arg->cube)); - - return MIN(r1, r2); -} - -static int -estimate_drudfin_drud(DfsArg *arg) -{ - int val = ptableval(&pd_drudfin_noE_sym16_drud, arg->cube); - - if (val != 0) - return val; - - return arg->cube.epose % 24 == 0 ? 0 : 1; -} - -static int -estimate_htr_drud(DfsArg *arg) -{ - return ptableval(&pd_htr_drud, arg->cube); -} - -static int -estimate_htrfin_htr(DfsArg *arg) -{ - return ptableval(&pd_htrfin_htr, arg->cube); + return false; } -static int -estimate_nxopt31_HTM(DfsArg *arg) +bool +check_cornershtr(Cube *cube) { - return estimate_nxoptlike(arg, &pd_nxopt31_HTM); + /* TODO (use coord) */ + return true; } -/* TODO: also use generic procedure for this */ -static int -estimate_light_HTM(DfsArg *arg) +bool +check_eofb(Cube *cube) { - 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 is_solved(arg->cube) ? 0 : 1; - - /* Michel de Bondt's trick*/ - if (arg->ed->normal_ud == arg->ed->normal_fb && - arg->ed->normal_fb == arg->ed->normal_rl) { - UPDATECHECKSTOP(ret, arg->ed->normal_ud + 1, target); - } - - /* Inverse probing */ - if (!((1<<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); - } else { - UPDATECHECKSTOP(ret, arg->ed->inverse_ud, target); - UPDATECHECKSTOP(ret, arg->ed->inverse_fb, target); - UPDATECHECKSTOP(ret, arg->ed->inverse_rl, target); - } - - /* Michel de Bondt's trick*/ - if (arg->ed->inverse_ud == arg->ed->inverse_fb && - arg->ed->inverse_fb == arg->ed->inverse_rl) { - UPDATECHECKSTOP(ret, arg->ed->inverse_ud + 1, target); - } - - /* nxopt trick + half turn trick */ - if (arg->ed->normal_ud == target) - arg->badmovesinv |= udmask | htmask; - if (arg->ed->normal_fb == target) - arg->badmovesinv |= fbmask | htmask; - if (arg->ed->normal_rl == target) - arg->badmovesinv |= rlmask | htmask; - - if (arg->ed->inverse_ud == target) - arg->badmoves |= udmask | htmask; - if (arg->ed->inverse_fb == target) - arg->badmoves |= fbmask | htmask; - if (arg->ed->inverse_rl == target) - arg->badmoves |= rlmask | htmask; - - return arg->ed->oldret = ret; + /* TODO (use coord) */ + return true; } -static int -estimate_nxoptlike(DfsArg *arg, PruneData *pd) +bool +check_drud(Cube *cube) { - 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); - - 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, arg->cube); - UPDATECHECKSTOP(ret, arg->ed->normal_ud, target); - aux = apply_trans(fd, arg->cube); - arg->ed->normal_fb = ptableval(pd, aux); - UPDATECHECKSTOP(ret, arg->ed->normal_fb, target); - aux = apply_trans(rf, arg->cube); - arg->ed->normal_rl = ptableval(pd, aux); - UPDATECHECKSTOP(ret, arg->ed->normal_rl, target); - - if (ret == 0) - return arg->step->is_done(arg->cube) ? 0 : 1; - - /* Michel de Bondt's trick*/ - if (arg->ed->normal_ud == arg->ed->normal_fb && - arg->ed->normal_fb == arg->ed->normal_rl) { - UPDATECHECKSTOP(ret, arg->ed->normal_ud + 1, target); - } - - /* Inverse probing */ - aux = arg->inverse = inverse_cube(arg->cube); - if (!((1<<arg->last1) & udmask) || (arg->ed->inverse_ud == -1)) { - arg->ed->inverse_ud = ptableval(pd, 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, 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, aux); - } - UPDATECHECKSTOP(ret, arg->ed->inverse_rl, target); - - /* Michel de Bondt's trick*/ - if (arg->ed->inverse_ud == arg->ed->inverse_fb && - arg->ed->inverse_fb == arg->ed->inverse_rl) { - UPDATECHECKSTOP(ret, arg->ed->inverse_ud + 1, target); - } - - /* nxopt trick */ - if (arg->ed->normal_ud == target) - arg->badmovesinv |= udmask; - if (arg->ed->normal_fb == target) - arg->badmovesinv |= fbmask; - if (arg->ed->normal_rl == target) - arg->badmovesinv |= rlmask; - - if (arg->ed->inverse_ud == target) - arg->badmoves |= udmask; - if (arg->ed->inverse_fb == target) - arg->badmoves |= fbmask; - if (arg->ed->inverse_rl == target) - arg->badmoves |= rlmask; - - return arg->ed->oldret = ret; + /* TODO (use coord) */ + return true; } - -static bool -always_valid(Alg *alg) +bool +check_htr(Cube *cube) { + /* TODO (check_drud(cube) and coord_htr_drud == 0) */ return true; } -static bool +bool validate_singlecw_ending(Alg *alg) { int i; @@ -1389,93 +129,93 @@ validate_singlecw_ending(Alg *alg) return nor && inv; } -/* Pre-transformation detectors **********************************************/ +/* Public functions **********************************************************/ -static int -detect_pretrans_eofb(Cube cube, Trans *ret) +void +compute_ind(StepAlt *a, Cube *cube, Movable *ind) { - int i, n; - static Trans tt[3] = {uf, ur, fd}; + int i; + Cube mvd; + Trans t, tt; - for (i = 0, n = 0; i < 3; i++) - if (check_eofb(apply_trans(tt[i], cube))) - ret[n++] = tt[i]; + for (i = 0; i < a->n_coord; i++) { + t = a->coord_trans[i]; + copy_cube(cube, &mvd); + apply_trans(t, &mvd); - return n; + ind[i].val = index_coord(a->coord[i], &mvd, &tt); + ind[i].t = transform_trans(tt, t); + } } -static int -detect_pretrans_drud(Cube cube, Trans *ret) +int +estimate_stepalt(StepAlt *a, Movable *ind, int goal) { - int i, n; - static Trans tt[3] = {uf, fr, rd}; + int i, ret, est[a->n_coord]; - for (i = 0, n = 0; i < 3; i++) - if (check_drud(apply_trans(tt[i], cube))) - ret[n++] = tt[i]; + for (i = 0; i < a->n_coord; i++) { + est[i] = ptableval(a->pd[i], ind[i].val); + if (est[i] == a->pd[i]->base && a->compact_pd[i]) + est[i] = ptableval(a->fallback_pd[i], + ind[i].val/a->fbmod[i]); + if (ind[i].val != 0 && est[i] == 0) /* est == 0 iff solved */ + est[i] = 1; +/* +TODO: remove this debug code +printf("%d: est=%d | ", i, est[i]); +*/ - return n; -} + if (est[i] > goal) + return est[i]; + } -static int -detect_pretrans_void_3axis(Cube cube, Trans *ret) -{ - ret[0] = uf; - ret[1] = fr; - ret[2] = rd; + for (i = 0; i < a->n_dbtrick; i++) + if (est[a->dbtrick[i][0]] > 0 && + est[a->dbtrick[i][0]] == est[a->dbtrick[i][1]] && + est[a->dbtrick[i][0]] == est[a->dbtrick[i][2]]) + est[a->dbtrick[i][0]] += 1; - return 3; -} + for (i = 0, ret = -1; i < a->n_coord; i++) + ret = MAX(ret, est[i]); -/* Public functions **********************************************************/ +/* +TODO: remove this debug code +printf("Final estimate: %d\n", ret); +*/ -void -copy_estimatedata(EstimateData *src, EstimateData *dst) -{ - dst->corners = src->corners; - dst->normal_ud = src->normal_ud; - dst->normal_fb = src->normal_fb; - dst->normal_rl = src->normal_rl; - dst->inverse_ud = src->inverse_ud; - dst->inverse_fb = src->inverse_fb; - dst->inverse_rl = src->inverse_rl; - dst->oldret = src->oldret; + return ret; } void -invert_estimatedata(EstimateData *ed) +prepare_step(Step *step, SolveOptions *opts) { - swap(&(ed->normal_ud), &(ed->inverse_ud)); - swap(&(ed->normal_fb), &(ed->inverse_fb)); - swap(&(ed->normal_rl), &(ed->inverse_rl)); -} + int i, j; + PDGenData pdg; + StepAlt *a; -void -reset_estimatedata(EstimateData *ed) -{ - ed->corners = -1; - ed->normal_ud = -1; - ed->normal_fb = -1; - ed->normal_rl = -1; - ed->inverse_ud = -1; - ed->inverse_fb = -1; - ed->inverse_rl = -1; - ed->oldret = -1; -} + for (i = 0; step->alt[i] != NULL; i++) { + a = step->alt[i]; + init_moveset(a->moveset); + pdg.moveset = a->moveset; + for (j = 0; j < a->n_coord; j++) { + gen_coord(a->coord[j]); -void -prepare_step(Step *step, SolveOptions *opts) -{ - int i; + pdg.coord = a->coord[j]; + pdg.compact = a->compact_pd[j]; + pdg.pd = NULL; - if (step->final && opts->can_niss) { - opts->can_niss = false; - fprintf(stderr, "Step is final, NISS not used (-n ignored)\n"); - } + a->pd[j] = genptable(&pdg, opts->nthreads); + + if (a->compact_pd[j]) { + gen_coord(a->fallback_coord[j]); - for (i = 0; i < step->ntables; i++) { - genptable(step->tables[i], opts->nthreads); - if (step->tables[i]->compact) - genptable(step->tables[i]->fallback, opts->nthreads); + pdg.coord = a->fallback_coord[j]; + pdg.compact = false; + pdg.pd = NULL; + + a->fallback_pd[j] = + genptable(&pdg, opts->nthreads); + } + } } } diff --git a/src/steps.h b/src/steps.h @@ -3,15 +3,275 @@ #include "pruning.h" -extern Step * steps[]; +bool check_centers(Cube *cube); +bool check_coud_HTM(Cube *cube); +bool check_coud_URF(Cube *cube); +bool check_cp_HTM(Cube *cube); +bool check_corners_HTM(Cube *cube); +bool check_corners_URF(Cube *cube); +bool check_cornershtr(Cube *cube); +bool check_eofb(Cube *cube); +bool check_drud(Cube *cube); +bool check_htr(Cube *cube); +void compute_ind(StepAlt *a, Cube *cube, Movable *ind); +int estimate_stepalt(StepAlt *a, Movable *ind, int goal); +void prepare_step(Step *step, SolveOptions *opts); +bool always_valid(Alg *alg); +bool validate_singlecw_ending(Alg *alg); -/* Two steps used directly by two-phase solver */ -extern Step drany_HTM; -extern Step dranyfin_DR; +#ifndef STEPS_C -void copy_estimatedata(EstimateData *s, EstimateData *d); -void invert_estimatedata(EstimateData *ed); -void reset_estimatedata(EstimateData *ed); -void prepare_step(Step *step, SolveOptions *opts); +extern char check_centers_msg[100]; +extern char check_eo_msg[100]; +extern char check_dr_msg[100]; +extern char check_htr_msg[100]; +extern char check_drany_msg[100]; + +extern StepAlt sa_nxopt31_HTM; +extern StepAlt sa_eofb_HTM; +extern StepAlt sa_drud_HTM; +extern StepAlt sa_drfin_drud; + +extern Step optimal_HTM; +extern Step eoany_HTM; +extern Step eofb_HTM; +extern Step eorl_HTM; +extern Step eoud_HTM; +extern Step drany_HTM; +extern Step drud_HTM; +extern Step drrl_HTM; +extern Step drfb_HTM; +extern Step dranyfin_DR; +extern Step drudfin_drud; +extern Step drrlfin_drrl; +extern Step drfbfin_drfb; + +extern Step *steps[]; + +#else + +char check_centers_msg[100] = "cube must be oriented (centers solved)"; +char check_eo_msg[100] = "EO must be solved on given axis"; +char check_dr_msg[100] = "DR must be solved on given axis"; +char check_htr_msg[100] = "HTR must be solved"; +char check_drany_msg[100] = "DR must be solved on at least one axis"; + +/* Optimal solvers *******************/ +/* TODO: build options for smaller optimal solvers */ + +StepAlt +sa_nxopt31_HTM = { + .ready = check_centers, + .final = true, + .moveset = &moveset_HTM, + .n_coord = 6, + .coord = {&coord_nxopt31, &coord_nxopt31, &coord_nxopt31, + &coord_eposepe, &coord_eposepe, &coord_eposepe}, + /* TODO: use khuge as fallback? */ + .coord_trans = {uf, rd, bl, uf, rd, bl}, + .compact_pd = {true, true, true, false, false, false}, + .fallback_coord = {&coord_drud_sym16, &coord_drud_sym16, + &coord_drud_sym16}, + .fbmod = {BINOM8ON4, BINOM8ON4, BINOM8ON4}, + .n_dbtrick = 1, /* TODO: change to 2 when khuge */ + .dbtrick = {{0, 1, 2}}, + .is_valid = NULL, +}; +Step +optimal_HTM = { + .shortname = "optimal", + .name = "Optimal solve (in HTM)", + .alt = {&sa_nxopt31_HTM, NULL}, + .t = {uf}, + .ready_msg = check_centers_msg, +}; + +/* Optimal after EO ******************/ +/* TODO: eofin_eo (generic), eofbfin_eofb, eorlfin_eorl, eoudfin_eoud */ + +/* EO steps **************************/ +/* TODO: eoany_HTM (generic), eofb_HTM, eorl_HTM, eoud_HTM */ + +StepAlt +sa_eofb_HTM = { + .ready = check_centers, + .final = false, + .moveset = &moveset_HTM, + .n_coord = 1, + .coord = {&coord_eofb}, + .coord_trans = {uf}, + .compact_pd = {false}, + .n_dbtrick = 0, + .is_valid = validate_singlecw_ending, +}; +Step +eoany_HTM = { + .shortname = "eo", + .name = "EO on any axis", + .alt = {&sa_eofb_HTM, &sa_eofb_HTM, &sa_eofb_HTM, NULL}, + .t = {uf, ur, fd}, + .ready_msg = check_centers_msg, +}; +Step +eofb_HTM = { + .shortname = "eofb", + .name = "EO on F/B", + .alt = {&sa_eofb_HTM, NULL}, + .t = {uf}, + .ready_msg = check_centers_msg, +}; +Step +eorl_HTM = { + .shortname = "eorl", + .name = "EO on R/L", + .alt = {&sa_eofb_HTM, NULL}, + .t = {ur}, + .ready_msg = check_centers_msg, +}; +Step +eoud_HTM = { + .shortname = "eoud", + .name = "EO on U/D", + .alt = {&sa_eofb_HTM, NULL}, + .t = {fd}, + .ready_msg = check_centers_msg, +}; + +/* CO steps **************************/ +/* TODO: coany_HTM (generic), cofb_HTM, corl_HTM, coud_HTM */ +/* TODO: coany_URF (generic), cofb_URF, corl_URF, coud_URF */ + +/* Misc corner steps *****************/ +/* TODO: cornershtr_HTM, cornershtr_URF, corners_HTM, corners_URF */ +/* TODO (new): corners_drud */ + +/* DR steps **************************/ +/* TODO: dr_eo (generic) */ +/* TODO: dr_eofb (generic), dr_eorl (generic), dr_eoud (generic) */ +/* TODO: drud_eofb, drrl_eofb, drud_eorl, drfb_eorl, drrl_eoud, drfb_eoud */ + +StepAlt +sa_drud_HTM = { + .ready = check_centers, + .final = false, + .moveset = &moveset_HTM, + .n_coord = 1, + .coord = {&coord_drud_sym16}, + .coord_trans = {uf}, + .compact_pd = {false}, /* TODO: maybe compactify */ + .n_dbtrick = 0, + .is_valid = validate_singlecw_ending, +}; +Step +drany_HTM = { + .shortname = "dr", + .name = "DR on any axis", + .alt = {&sa_drud_HTM, &sa_drud_HTM, &sa_drud_HTM, NULL}, + .t = {uf, rf, fd}, + .ready_msg = check_centers_msg, +}; +Step +drud_HTM = { + .shortname = "drud", + .name = "DR on U/D", + .alt = {&sa_drud_HTM, NULL}, + .t = {uf}, + .ready_msg = check_centers_msg, +}; +Step +drrl_HTM = { + .shortname = "drrl", + .name = "DR on R/L", + .alt = {&sa_drud_HTM, NULL}, + .t = {rf}, + .ready_msg = check_centers_msg, +}; +Step +drfb_HTM = { + .shortname = "drfb", + .name = "DR on F/B", + .alt = {&sa_drud_HTM, NULL}, + .t = {fd}, + .ready_msg = check_centers_msg, +}; + +/* DR finish steps */ +StepAlt +sa_drfin_drud = { + .ready = check_drud, + .final = true, + .moveset = &moveset_drud, + .n_coord = 1, + .coord = {&coord_drudfin_noE_sym16}, /* TODO: maybe no noE */ + .coord_trans = {uf}, + .compact_pd = {false}, /* TODO: maybe compactify */ + .n_dbtrick = 0, + .is_valid = NULL, +}; +Step +dranyfin_DR = { + .shortname = "drfin", + .name = "DR finish on any axis without breaking DR", + .alt = {&sa_drfin_drud, &sa_drfin_drud, &sa_drfin_drud, NULL}, + .t = {uf, rf, fd}, + .ready_msg = check_dr_msg, +}; +Step +drudfin_drud = { + .shortname = "drudfin", + .name = "DR finis on U/D without breaking DR", + .alt = {&sa_drfin_drud, NULL}, + .t = {uf}, + .ready_msg = check_dr_msg, +}; +Step +drrlfin_drrl = { + .shortname = "drrlfin", + .name = "DR finish on R/L without breaking DR", + .alt = {&sa_drfin_drud, NULL}, + .t = {rf}, + .ready_msg = check_dr_msg, +}; +Step +drfbfin_drfb = { + .shortname = "drfbfin", + .name = "DR finish on F/B without breaking DR", + .alt = {&sa_drfin_drud, NULL}, + .t = {fd}, + .ready_msg = check_dr_msg, +}; + +/* HTR from DR */ +/* TODO: htr_any (generic), htr_drud, htr_drrl, htr_drfb */ + +/* HTR finish */ +/* TODO: htrfin_htr */ + +Step *steps[] = { + &optimal_HTM, /* first is default */ + + &eoany_HTM, &eofb_HTM, &eorl_HTM, &eoud_HTM, + &drany_HTM, &drud_HTM, &drrl_HTM, &drfb_HTM, + &dranyfin_DR, &drudfin_drud, &drrlfin_drrl, &drfbfin_drfb, + +/* TODO: + &optimal_light_HTM, + + &eofin_eo, &eofbfin_eofb, &eorlfin_eorl, &eoudfin_eoud, + &coany_HTM, &coud_HTM, &corl_HTM, &cofb_HTM, + &coany_URF, &coud_URF, &corl_URF, &cofb_URF, + &dr_eo, &dr_eofb, &dr_eorl, &dr_eoud, + &drud_eofb, &drrl_eofb, + &drud_eorl, &drfb_eorl, + &drfb_eoud, &drrl_eoud, + &htr_any, &htr_drud, &htr_drrl, &htr_drfb, + &htrfin_htr, + &cornershtr_HTM, &cornershtr_URF, &corners_HTM, &corners_URF, + NULL +*/ + +}; + +#endif #endif diff --git a/src/symcoord.c b/src/symcoord.c @@ -1,687 +0,0 @@ -#include "symcoord.h" - -/* These constants have been computed generating the respective SymData */ -#define CLASSES_CP_16 2768 -#define CLASSES_EOFBEPOS_16 64430 - -static uint64_t index_cp_sym16(Cube cube); -static uint64_t index_eofbepos_sym16(Cube cube); -static uint64_t index_drud_sym16(Cube cube); -static uint64_t index_drudfin_noE_sym16(Cube cube); -static uint64_t index_nxopt31(Cube cube); - -static uint64_t move_cp_sym16(Move m, uint64_t ind); -static uint64_t move_eofbepos_sym16(Move m, uint64_t ind); -static uint64_t move_drud_sym16(Move m, uint64_t ind); -static uint64_t move_drudfin_noE_sym16(Move m, uint64_t ind); -static uint64_t move_nxopt31(Move m, uint64_t ind); - -static int tfind_from_mask(uint64_t mask, Trans *ret); -static int tfind_drud_sym16(uint64_t ind, Trans *ret); -static int tfind_drudfin_noE_sym16(uint64_t ind, Trans *ret); -static int tfind_nxopt31(uint64_t ind, Trans *ret); - -static uint64_t transform_cp(Trans t, uint64_t ind); -static uint64_t transform_eofbepos(Trans t, uint64_t ind); -static uint64_t transform_drud_sym16(Trans t, uint64_t ind); -static uint64_t transform_drudfin_noE_sym16(Trans t, uint64_t ind); -static uint64_t transform_nxopt31(Trans t, uint64_t ind); - -static void gensym(SymData *sd); -static void init_symc_moves(); -static void init_symc_trans(); -static bool read_symdata_file(SymData *sd); -static bool read_symc_moves_file(); -static bool read_symc_trans_file(); -static bool write_symdata_file(SymData *sd); -static bool write_symc_moves_file(); -static bool write_symc_trans_file(); - -/* Some tables ***************************************************************/ - -static uint64_t move_cp_16[NMOVES][CLASSES_CP_16]; -static uint64_t move_eofbepos_16[NMOVES][CLASSES_EOFBEPOS_16]; - -static int trans_eofbepos[NTRANS][POW2TO11*BINOM12ON4]; -static int trans_epud[NTRANS][FACTORIAL8]; -static int trans_cpud_separate[NTRANS][BINOM8ON4]; - -static Trans ttrep_move_cp_16[NMOVES][CLASSES_CP_16]; -static Trans ttrep_move_eofbepos_16[NMOVES][CLASSES_EOFBEPOS_16]; - - -/* Transformation groups and symmetry data ***********************************/ - -static Trans -trans_group_udfix[16] = { - uf, ur, ub, ul, - df, dr, db, dl, - uf_mirror, ur_mirror, ub_mirror, ul_mirror, - df_mirror, dr_mirror, db_mirror, dl_mirror, -}; - -static SymData -sd_cp_16 = { - .filename = "sd_cp_16_new", - .coord = &coord_cp, - .sym_coord = &coord_cp_sym16, - .ntrans = 16, - .trans = trans_group_udfix, - .transform = transform_cp, -}; - -static SymData -sd_eofbepos_16 = { - .filename = "sd_eofbepos_16_new", - .coord = &coord_eofbepos, - .sym_coord = &coord_eofbepos_sym16, - .ntrans = 16, - .trans = trans_group_udfix, - .transform = transform_eofbepos, -}; - -SymData * all_sd[] = { - &sd_cp_16, - &sd_eofbepos_16, - NULL -}; - - -/* Coordinates and their implementation **************************************/ - -Coordinate -coord_eofbepos_sym16 = { - .index = index_eofbepos_sym16, - .move = move_eofbepos_sym16, -}; - -Coordinate -coord_cp_sym16 = { - .index = index_cp_sym16, - .move = move_cp_sym16, -}; - -Coordinate -coord_drud_sym16 = { - .index = index_drud_sym16, - .move = move_drud_sym16, - .max = POW3TO7 * CLASSES_EOFBEPOS_16, - .base = &coord_eofbepos_sym16, - .transform = transform_drud_sym16, - .tfind = tfind_drud_sym16, -}; - -Coordinate -coord_drudfin_noE_sym16 = { - .index = index_drudfin_noE_sym16, - .move = move_drudfin_noE_sym16, - .max = FACTORIAL8 * CLASSES_CP_16, - .base = &coord_cp_sym16, - .transform = transform_drudfin_noE_sym16, - .tfind = tfind_drudfin_noE_sym16, -}; - -Coordinate -coord_nxopt31 = { - .index = index_nxopt31, - .move = move_nxopt31, - .max = POW3TO7 * BINOM8ON4 * CLASSES_EOFBEPOS_16, - .base = &coord_eofbepos_sym16, - .transform = transform_nxopt31, - .tfind = tfind_nxopt31, -}; - -/* Functions *****************************************************************/ - -static uint64_t -index_cp_sym16(Cube cube) -{ - return sd_cp_16.class[coord_cp.index(cube)]; -} - -static uint64_t -index_drud_sym16(Cube cube) -{ - Trans t; - - t = sd_eofbepos_16.transtorep[coord_eofbepos.index(cube)]; - - return index_eofbepos_sym16(cube) * POW3TO7 + co_ttable[t][cube.coud]; -} - -static uint64_t -index_drudfin_noE_sym16(Cube cube) -{ - Trans t; - Cube c; - - t = sd_cp_16.transtorep[coord_cp.index(cube)]; - c = apply_trans(t, cube); - - /* TODO: add transform to coord_epud to make this faster */ - return index_cp_sym16(c) * FACTORIAL8 + coord_epud.index(c); -} - -static uint64_t -index_eofbepos_sym16(Cube cube) -{ - return sd_eofbepos_16.class[coord_eofbepos.index(cube)]; -} - -static uint64_t -index_nxopt31(Cube cube) -{ - Trans t; - uint64_t a; - int coud, cp; - - t = sd_eofbepos_16.transtorep[coord_eofbepos.index(cube)]; - coud = co_ttable[t][cube.coud]; - cp = cp_ttable[t][cube.cp]; - a = (index_eofbepos_sym16(cube)*POW3TO7) + coud; - - return a * BINOM8ON4 + coord_cpud_separate.index((Cube){.cp = cp}); -} - -static uint64_t -move_cp_sym16(Move m, uint64_t ind) -{ - return move_cp_16[m][ind]; -} - -static uint64_t -move_eofbepos_sym16(Move m, uint64_t ind) -{ - return move_eofbepos_16[m][ind]; -} - -static uint64_t -move_drud_sym16(Move m, uint64_t ind) -{ - uint64_t coud, eofbepos; - Trans ttr; - - eofbepos = move_eofbepos_16[m][ind / POW3TO7]; - ttr = ttrep_move_eofbepos_16[m][ind / POW3TO7]; - coud = coud_mtable[m][ind % POW3TO7]; - coud = co_ttable[ttr][coud]; /* Source is always coud */ - - return eofbepos * POW3TO7 + coud; -} - -static uint64_t -move_drudfin_noE_sym16(Move m, uint64_t ind) -{ - uint64_t cp, epud; - Trans ttr; - - cp = move_cp_16[m][ind / FACTORIAL8]; - ttr = ttrep_move_cp_16[m][ind / FACTORIAL8]; - epud = coord_epud.move(m, ind % FACTORIAL8); - epud = trans_epud[ttr][epud]; - - return cp * FACTORIAL8 + epud; -} - -static uint64_t -move_nxopt31(Move m, uint64_t ind) -{ - uint64_t eofbepos, cpsep, coud; - Trans ttr; - - eofbepos = ind / (POW3TO7 * BINOM8ON4); - coud = (ind / BINOM8ON4) % POW3TO7; - cpsep = ind % BINOM8ON4; - - ttr = ttrep_move_eofbepos_16[m][eofbepos]; - eofbepos = move_eofbepos_16[m][eofbepos]; - coud = coud_mtable[m][coud]; - coud = co_ttable[ttr][coud]; /* Source is always coud */ - cpsep = coord_cpud_separate.move(m, cpsep); - cpsep = trans_cpud_separate[ttr][cpsep]; - - return (eofbepos * POW3TO7 + coud) * BINOM8ON4 + cpsep; -} - -static uint64_t -transform_cp(Trans t, uint64_t ind) -{ - return cp_ttable[t][ind]; -} - -static uint64_t -transform_eofbepos(Trans t, uint64_t ind) -{ - return trans_eofbepos[t][ind]; -} - -static uint64_t -transform_drud_sym16(Trans t, uint64_t ind) -{ - uint64_t coud, eofbepos; - - eofbepos = ind / POW3TO7; /* Assum trans fixes eofbepos */ - coud = co_ttable[t][ind % POW3TO7]; /* Source is always coud */ - - return eofbepos * POW3TO7 + coud; -} - -static uint64_t -transform_drudfin_noE_sym16(Trans t, uint64_t ind) -{ - uint64_t cp, epud; - - cp = ind / FACTORIAL8; /* Assume trans fixes cp */ - epud = trans_epud[t][ind % FACTORIAL8]; - - return cp * FACTORIAL8 + epud; -} - -static uint64_t -transform_nxopt31(Trans t, uint64_t ind) -{ - uint64_t eofbepos, cpsep, coud; - - eofbepos = ind / (POW3TO7 * BINOM8ON4); - coud = (ind / BINOM8ON4) % POW3TO7; - cpsep = ind % BINOM8ON4; - - coud = co_ttable[t][coud]; /* Source is always coud */ - cpsep = trans_cpud_separate[t][cpsep]; - - return (eofbepos * POW3TO7 + coud) * BINOM8ON4 + cpsep; -} - -static int -tfind_from_mask(uint64_t mask, Trans *ret) -{ - Trans t; - int i = 0; - - for (t = uf; t < NTRANS; t++) - if (((uint64_t)1 << t) & mask) - ret[i++] = t; - - return i; -} - -static int -tfind_drud_sym16(uint64_t ind, Trans *ret) -{ - uint64_t mask = sd_eofbepos_16.selfsim[ind / POW3TO7]; - - return tfind_from_mask(mask, ret); -} - -static int -tfind_drudfin_noE_sym16(uint64_t ind, Trans *ret) -{ - uint64_t mask = sd_cp_16.selfsim[ind / FACTORIAL8]; - - return tfind_from_mask(mask, ret); -} - -static int -tfind_nxopt31(uint64_t ind, Trans *ret) -{ - uint64_t mask = sd_eofbepos_16.selfsim[ind / (POW3TO7 * BINOM8ON4)]; - - return tfind_from_mask(mask, ret); -} - -/* Other functions ***********************************************************/ - -void -free_sd(SymData *sd) -{ - if (sd->generated) { - free(sd->class); - free(sd->unsym); - free(sd->transtorep); - } - - sd->generated = false; -} - -static void -gensym(SymData *sd) -{ - uint64_t i, in, nreps = 0; - Trans t; - int j; - - if (sd->generated) - return; - - sd->class = malloc(sd->coord->max * sizeof(uint64_t)); - sd->unsym = malloc(sd->coord->max * sizeof(uint64_t)); - sd->transtorep = malloc(sd->coord->max * sizeof(Trans)); - sd->selfsim = malloc(sd->coord->max * sizeof(uint64_t)); - - if (read_symdata_file(sd)) { - sd->generated = true; - return; - } - - fprintf(stderr, "Cannot load %s, generating it\n", sd->filename); - - for (i = 0; i < sd->coord->max; i++) - sd->class[i] = sd->coord->max + 1; - - for (i = 0; i < sd->coord->max; i++) { - if (sd->class[i] == sd->coord->max + 1) { - sd->unsym[nreps] = i; - sd->transtorep[i] = uf; - sd->selfsim[nreps] = (uint64_t)0; - for (j = 0; j < sd->ntrans; j++) { - t = sd->trans[j]; - in = sd->transform(t, i); - sd->class[in] = nreps; - if (in == i) - sd->selfsim[nreps] |= - ((uint64_t)1 << t); - else - sd->transtorep[in] = inverse_trans(t); - } - nreps++; - } - } - - sd->sym_coord->max = nreps; - sd->unsym = realloc(sd->unsym, nreps * sizeof(uint64_t)); - sd->selfsim = realloc(sd->selfsim, nreps * sizeof(uint64_t)); - sd->generated = true; - - fprintf(stderr, "Found %" PRIu64 " classes\n", nreps); - - if (!write_symdata_file(sd)) - fprintf(stderr, "Error writing SymData file\n"); - - return; -} - -static bool -read_symdata_file(SymData *sd) -{ - init_env(); - - FILE *f; - char fname[strlen(tabledir)+100]; - uint64_t n = sd->coord->max, *sn = &sd->sym_coord->max; - bool r = true; - - strcpy(fname, tabledir); - strcat(fname, "/"); - strcat(fname, sd->filename); - - if ((f = fopen(fname, "rb")) == NULL) - return false; - - r = r && fread(&sd->sym_coord->max, sizeof(uint64_t), 1, f) == 1; - r = r && fread(sd->unsym, sizeof(uint64_t), *sn, f) == *sn; - r = r && fread(sd->selfsim, sizeof(uint64_t), *sn, f) == *sn; - r = r && fread(sd->class, sizeof(uint64_t), n, f) == n; - r = r && fread(sd->transtorep, sizeof(Trans), n, f) == n; - - fclose(f); - return r; -} - -static bool -read_symc_moves_file() -{ - init_env(); - - Move m; - bool r = true; - FILE *f; - char fname[strlen(tabledir)+100]; - - strcpy(fname, tabledir); - strcat(fname, "/symc_moves"); - - if ((f = fopen(fname, "rb")) == NULL) - return false; - - for (m = 0; m < NMOVES; m++) { - r = r && fread(move_cp_16[m], sizeof(uint64_t), - CLASSES_CP_16, f) == CLASSES_CP_16; - r = r && fread(move_eofbepos_16[m], sizeof(uint64_t), - CLASSES_EOFBEPOS_16, f) == CLASSES_EOFBEPOS_16; - - r = r && fread(ttrep_move_cp_16[m], sizeof(Trans), - CLASSES_CP_16, f) == CLASSES_CP_16; - r = r && fread(ttrep_move_eofbepos_16[m], sizeof(Trans), - CLASSES_EOFBEPOS_16, f) == CLASSES_EOFBEPOS_16; - } - - fclose(f); - return r; -} - -static bool -read_symc_trans_file() -{ - init_env(); - - Trans t; - bool r = true; - FILE *f; - char fname[strlen(tabledir)+100]; - - strcpy(fname, tabledir); - strcat(fname, "/symc_trans"); - - if ((f = fopen(fname, "rb")) == NULL) - return false; - - for (t = 0; t < NTRANS; t++) { - r = r && fread(trans_eofbepos[t], sizeof(int), - POW2TO11*BINOM12ON4, f) == POW2TO11*BINOM12ON4; - r = r && fread(trans_epud[t], sizeof(int), - FACTORIAL8, f) == FACTORIAL8; - r = r && fread(trans_cpud_separate[t], sizeof(int), - BINOM8ON4, f) == BINOM8ON4; - } - - fclose(f); - return r; -} - -static bool -write_symdata_file(SymData *sd) -{ - init_env(); - - FILE *f; - char fname[strlen(tabledir)+100]; - uint64_t n = sd->coord->max, *sn = &sd->sym_coord->max; - bool r = true; - - strcpy(fname, tabledir); - strcat(fname, "/"); - strcat(fname, sd->filename); - - if ((f = fopen(fname, "wb")) == NULL) - return false; - - r = r && fwrite(&sd->sym_coord->max, sizeof(uint64_t), 1, f) == 1; - r = r && fwrite(sd->unsym, sizeof(uint64_t), *sn, f) == *sn; - r = r && fwrite(sd->selfsim, sizeof(uint64_t), *sn, f) == *sn; - r = r && fwrite(sd->class, sizeof(uint64_t), n, f) == n; - r = r && fwrite(sd->transtorep, sizeof(Trans), n, f) == n; - - fclose(f); - return r; -} - -static bool -write_symc_moves_file() -{ - init_env(); - - Move m; - bool r = true; - FILE *f; - char fname[strlen(tabledir)+100]; - - strcpy(fname, tabledir); - strcat(fname, "/symc_moves"); - - if ((f = fopen(fname, "wb")) == NULL) - return false; - - for (m = 0; m < NMOVES; m++) { - r = r && fwrite(move_cp_16[m], sizeof(uint64_t), - CLASSES_CP_16, f) == CLASSES_CP_16; - r = r && fwrite(move_eofbepos_16[m], sizeof(uint64_t), - CLASSES_EOFBEPOS_16, f) == CLASSES_EOFBEPOS_16; - - r = r && fwrite(ttrep_move_cp_16[m], sizeof(Trans), - CLASSES_CP_16, f) == CLASSES_CP_16; - r = r && fwrite(ttrep_move_eofbepos_16[m], sizeof(Trans), - CLASSES_EOFBEPOS_16, f) == CLASSES_EOFBEPOS_16; - } - - fclose(f); - return r; -} - -static bool -write_symc_trans_file() -{ - init_env(); - - Trans t; - bool r = true; - FILE *f; - char fname[strlen(tabledir)+100]; - - strcpy(fname, tabledir); - strcat(fname, "/symc_trans"); - - if ((f = fopen(fname, "wb")) == NULL) - return false; - - for (t = 0; t < NTRANS; t++) { - r = r && fwrite(trans_eofbepos[t], sizeof(int), - POW2TO11*BINOM12ON4, f) == POW2TO11*BINOM12ON4; - r = r && fwrite(trans_epud[t], sizeof(int), - FACTORIAL8, f) == FACTORIAL8; - r = r && fwrite(trans_cpud_separate[t], sizeof(int), - BINOM8ON4, f) == BINOM8ON4; - } - - fclose(f); - return r; -} - -static void -init_symc_moves() -{ - uint64_t i, ii, coo; - Move j; - - if (read_symc_moves_file()) - return; - - for (i = 0; i < CLASSES_CP_16; i++) { - ii = sd_cp_16.unsym[i]; - for (j = 0; j < NMOVES; j++) { - coo = sd_cp_16.coord->move(j, ii); - move_cp_16[j][i] = sd_cp_16.class[coo]; - ttrep_move_cp_16[j][i] = sd_cp_16.transtorep[coo]; - } - } - - for (i = 0; i < CLASSES_EOFBEPOS_16; i++) { - ii = sd_eofbepos_16.unsym[i]; - for (j = 0; j < NMOVES; j++) { - coo = sd_eofbepos_16.coord->move(j, ii); - move_eofbepos_16[j][i] = sd_eofbepos_16.class[coo]; - ttrep_move_eofbepos_16[j][i] = - sd_eofbepos_16.transtorep[coo]; - } - } - - if (!write_symc_moves_file()) - fprintf(stderr, "Error writing SymMoves file\n"); -} - -void -init_symc_trans() -{ - uint64_t i; - int j, cp; - int epe[4] = {FR, FL, BL, BR}; - int a[12] = { [8] = 8, [9] = 9, [10] = 10, [11] = 11 }; - Cube c; - CubeArray *arr, *aux; - Trans t; - - if (read_symc_trans_file()) - return; - - for (i = 0; i < POW2TO11*BINOM12ON4; i++) { - for (j = 0; j < 16; j++) { - t = trans_group_udfix[j]; - - arr = new_cubearray((Cube){0}, pf_edges); - int_to_sum_zero_array(i % POW2TO11, 2, 12, arr->eofb); - epos_to_compatible_ep((i / POW2TO11)*24, arr->ep, epe); - fix_eorleoud(arr); - c = arrays_to_cube(arr, pf_edges); - free_cubearray(arr, pf_edges); - - c = apply_trans(t, c); - trans_eofbepos[t][i] = (c.epose/24)*POW2TO11 + c.eofb; - } - } - - aux = malloc(sizeof(CubeArray)); - aux->ep = a; - for (i = 0; i < FACTORIAL8; i++) { - index_to_perm(i, 8, a); - c = arrays_to_cube(aux, pf_ep); - for (j = 0; j < 16; j++) { - t = trans_group_udfix[j]; - arr = new_cubearray(apply_trans(t, c), pf_ep); - trans_epud[t][i] = perm_to_index(arr->ep, 8); - free_cubearray(arr, pf_ep); - } - } - free(aux); - - for (i = 0; i < BINOM8ON4; i++) { - cp = cpud_separate_ant[i]; - for (j = 0; j < 16; j++) { - t = trans_group_udfix[j]; - trans_cpud_separate[t][i] = - cpud_separate_ind[cp_ttable[t][cp]]; - } - } - - if (!write_symc_trans_file()) - fprintf(stderr, "Error writing SymTrans file\n"); -} - -void -init_symcoord() -{ - int i; - - static bool initialized = false; - if (initialized) - return; - initialized = true; - - init_coord(); - - init_symc_trans(); - - for (i = 0; all_sd[i] != NULL; i++) - gensym(all_sd[i]); - - init_symc_moves(); -} - diff --git a/src/symcoord.h b/src/symcoord.h @@ -1,17 +0,0 @@ -#ifndef SYMCOORD_H -#define SYMCOORD_H - -#include "coord.h" - -extern Coordinate coord_cp_sym16; -extern Coordinate coord_eofbepos_sym16; -extern Coordinate coord_drud_sym16; -extern Coordinate coord_drudfin_noE_sym16; -extern Coordinate coord_nxopt31; - -extern SymData *all_sd[]; - -void free_sd(SymData *sd); -void init_symcoord(); - -#endif diff --git a/src/trans.c b/src/trans.c @@ -1,31 +1,23 @@ +#define TRANS_C + #include "trans.h" /* Local functions ***********************************************************/ -static bool read_ttables_file(); -static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f); -static bool write_ttables_file(); - /* Tables and other data *****************************************************/ -static int ep_mirror[12] = { - [UF] = UF, [UL] = UR, [UB] = UB, [UR] = UL, +static Cube mirror_cube = { +.ep = { [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, + [FR] = FL, [FL] = FR, [BL] = BR, [BR] = BL }, +.cp = { [UFR] = UFL, [UFL] = UFR, [UBL] = UBR, [UBR] = UBL, + [DFR] = DFL, [DFL] = DFR, [DBL] = DBR, [DBR] = DBL }, +.xp = { [U_center] = U_center, [D_center] = D_center, [R_center] = L_center, [L_center] = R_center, - [F_center] = F_center, [B_center] = B_center + [F_center] = F_center, [B_center] = B_center } }; -static char rotation_alg_string[100][NROTATIONS] = { +static char rotation_alg_string[100][NROTATIONS] = { [uf] = "", [ur] = "y", [ub] = "y2", [ul] = "y3", [df] = "z2", [dr] = "y z2", [db] = "x2", [dl] = "y3 z2", [rf] = "z3", [rd] = "z3 y", [rb] = "z3 y2", [ru] = "z3 y3", @@ -34,176 +26,39 @@ static char rotation_alg_string[100][NROTATIONS] = { [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 Alg *rotation_alg_arr[NROTATIONS]; +Move moves_ttable[NTRANS][NMOVES]; +Trans trans_ttable[NTRANS][NTRANS]; +Trans trans_itable[NTRANS]; -int epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; -int eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; -int eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; -int eo_ttable[NTRANS][POW2TO11]; -int cp_ttable[NTRANS][FACTORIAL8]; -int co_ttable[NTRANS][POW3TO7]; -int cpos_ttable[NTRANS][FACTORIAL6]; -Move moves_ttable[NTRANS][NMOVES]; - -/* Local functions implementation ********************************************/ +/* Public functions **********************************************************/ -static bool -read_ttables_file() +void +apply_trans(Trans t, Cube *cube) { - 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; + Cube aux; + Alg *inv; + int i; - 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]; + inv = inverse_alg(rotation_alg(t % NROTATIONS)); + copy_cube(cube, &aux); + make_solved(cube); + + if (t >= NROTATIONS) + compose(&mirror_cube, cube); + apply_alg(inv, cube); + compose(&aux, cube); + apply_alg(rotation_alg(t % NROTATIONS), cube); + if (t >= NROTATIONS) { + compose(&mirror_cube, cube); + for (i = 0; i < 8; i++) + cube->co[i] = (3 - cube->co[i]) % 3; } - 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) { @@ -231,23 +86,18 @@ inverse_trans(Trans t) return inverse_trans_aux[t]; } +*/ -Alg * -rotation_alg(Trans t) +Trans +inverse_trans(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 trans_itable[t]; +} - return rotation_alg_arr[t % NROTATIONS]; +Alg * +rotation_alg(Trans i) +{ + return rotation_alg_arr[i % NROTATIONS]; } void @@ -255,10 +105,20 @@ 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]]; + alg->move[i] = transform_move(t, alg->move[i]); +} + +Move +transform_move(Trans t, Move m) +{ + return moves_ttable[t][m]; +} + +Trans +transform_trans(Trans t, Trans m) +{ + return trans_ttable[t][m]; } void @@ -268,106 +128,63 @@ init_trans() { return; initialized = true; - init_moves(); - - Cube aux, cube, c[3]; - CubeArray epcp; - int i, eparr[12], eoarr[12], cparr[8], coarr[8]; - unsigned int ui; + int i; + Alg *nonsym_alg, *nonsym_inv; + Cube aux, cube; Move mi, move; - Trans m; + Trans t, u, v; - /* 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; + init_moves(); - cube = rotate_via_compose(m,c[eposs_source[m]],pf_ep); - eposs_ttable[m][ui] = cube.eposs; + for (i = 0; i < NROTATIONS; i++) + rotation_alg_arr[i] = new_alg(rotation_alg_string[i]); - 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 (t = 0; t < NTRANS; t++) { for (mi = 0; mi < NMOVES; mi++) { - /* Old version: - * - aux = apply_trans(m, apply_move(mi, (Cube){0})); + make_solved(&aux); + apply_move(mi, &aux); + apply_trans(t, &aux); 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; + copy_cube(&aux, &cube); + apply_move(inverse_move(move), &cube); + if (is_solved(&cube)) { + moves_ttable[t][mi] = move; + break; + } } - */ + } + } - 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; + nonsym_alg = new_alg("R' U' F"); + nonsym_inv = inverse_alg(nonsym_alg); + + for (t = 0; t < NTRANS; t++) { + for (u = 0; u < NTRANS; u++) { + make_solved(&aux); + apply_alg(nonsym_alg, &aux); + apply_trans(u, &aux); + apply_trans(t, &aux); + for (v = 0; v < NTRANS; v++) { + copy_cube(&aux, &cube); + apply_trans(v, &cube); + apply_alg(nonsym_inv, &cube); + if (is_solved(&cube)) { + /* This is the inverse of the correct + value, it will be inverted later */ + trans_ttable[t][u] = v; + if (v == uf) + trans_itable[t] = u; break; } } } } + for (t = 0; t < NTRANS; t++) + for (u = 0; u < NTRANS; u++) + trans_ttable[t][u] = trans_itable[trans_ttable[t][u]]; + - if (!write_ttables_file()) - fprintf(stderr, "Error writing ttables\n"); + free_alg(nonsym_alg); + free_alg(nonsym_inv); } diff --git a/src/trans.h b/src/trans.h @@ -3,24 +3,30 @@ #include "moves.h" -/* - * Tables are exposed to allow faster partial transformations in some - * specific cases (in symcoord) - */ -extern int epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; -extern int eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; -extern int eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; -extern int eo_ttable[NTRANS][POW2TO11]; -extern int cp_ttable[NTRANS][FACTORIAL8]; -extern int co_ttable[NTRANS][POW3TO7]; -extern int cpos_ttable[NTRANS][FACTORIAL6]; -extern Move moves_ttable[NTRANS][NMOVES]; - -Cube apply_trans(Trans t, Cube cube); +void apply_trans(Trans t, Cube *cube); Trans inverse_trans(Trans t); Alg * rotation_alg(Trans i); -void transform_alg(Trans i, Alg *alg); +void transform_alg(Trans t, Alg *alg); +Move transform_move(Trans t, Move m); +Trans transform_trans(Trans t, Trans m); void init_trans(); +#ifndef TRANS_C + +extern TransGroup tgrp_udfix; + +#else + +TransGroup +tgrp_udfix = { + .n = 16, + .t = { uf, ur, ub, ul, + df, dr, db, dl, + uf_mirror, ur_mirror, ub_mirror, ul_mirror, + df_mirror, dr_mirror, db_mirror, dl_mirror }, +}; + +#endif + #endif diff --git a/src/utils.c b/src/utils.c @@ -1,3 +1,5 @@ +#define UTILS_C + #include "utils.h" void @@ -159,24 +161,24 @@ is_perm(int *a, int n) { int *aux = malloc(n * sizeof(int)); int i; + bool ret = true; for (i = 0; i < n; i++) aux[i] = 0; for (i = 0; i < n; i++) { if (a[i] < 0 || a[i] >= n) - return false; + ret = false; else aux[a[i]] = 1; } for (i = 0; i < n; i++) if (!aux[i]) - return false; + ret = false; free(aux); - - return true; + return ret; } bool @@ -195,7 +197,7 @@ perm_sign(int *a, int n) { int i, j, ret = 0; - if (!is_perm(a,n)) + if (!is_perm(a, n)) return -1; for (i = 0; i < n; i++) @@ -211,7 +213,7 @@ perm_to_index(int *a, int n) int i, j, c, ret = 0; if (!is_perm(a, n)) - return -1; + return factorial(n); for (i = 0; i < n; i++) { c = 0; diff --git a/www/download/index.html b/www/download/index.html @@ -2,7 +2,7 @@ <html lang="en"> <head> <title> Download | Nissy </title> -<meta name="viewport" content="width=device-width" /> <link rel="stylesheet" type="text/css" href="/style.css"> +<meta name="viewport" content="width=device-width" /> <link rel="stylesheet" type="text/css" href="/style-3.css"> <link rel="icon" href="/favicon.png"> <meta charset="utf-8"> </head> diff --git a/www/examples/index.html b/www/examples/index.html @@ -2,7 +2,7 @@ <html lang="en"> <head> <title> Examples | Nissy </title> -<meta name="viewport" content="width=device-width" /> <link rel="stylesheet" type="text/css" href="/style.css"> +<meta name="viewport" content="width=device-width" /> <link rel="stylesheet" type="text/css" href="/style-3.css"> <link rel="icon" href="/favicon.png"> <meta charset="utf-8"> </head> diff --git a/www/index.html b/www/index.html @@ -2,7 +2,7 @@ <html lang="en"> <head> <title> Nissy | Nissy </title> -<meta name="viewport" content="width=device-width" /> <link rel="stylesheet" type="text/css" href="/style.css"> +<meta name="viewport" content="width=device-width" /> <link rel="stylesheet" type="text/css" href="/style-3.css"> <link rel="icon" href="/favicon.png"> <meta charset="utf-8"> </head> diff --git a/www/style-2.css b/www/style-2.css @@ -0,0 +1,105 @@ +.menu { + width: 100%; +} + +.links { + text-align: right; + font-weight: bold; +} + +.logo img { + width: 50px; + height: 50px; +} + +.footer { + font-style: italic; + width: 100%; +} + +.hosted { + text-align: right; +} + +body { + margin: auto 8px 20px 8px; +} + +img { + display: block; + margin-left: auto; + margin-right: auto; + max-width: 100%; +} + +code { + background-color: #eeeeee; + padding: 2px; +} + +pre code { + padding: 0px; +} + +pre { + background-color: #eeeeee; + border: 2px solid; + padding: 6px; +} + +#blob { + background: #ffffff; + border: none; +} + +a { + color: #0f2899; + text-decoration: none; +} + +.links a { + font-weight: bold; + color: black; +} + +.hosted a, +.contact a { + font-weight: bold; +} + +a:hover { + text-decoration: underline; +} + +html { + margin: 1em auto; + max-width: 42em; +} + +h1 { + text-align: center; +} + +td h1 { + text-align: left; + font-size: 1.5em; +} + +table { + width: 100%; +} + +.url td { + font-family: monospace; +} + +.dltable th, .dltable td { + border: 1px solid black; + padding: 3px; +} + +.subtitle { + text-align: center; + font-weight: bold; + font-size: 1.1em; +} diff --git a/www/style.css b/www/style.css @@ -1,99 +0,0 @@ -.menu { - width: 100%; -} - -.links { - text-align: right; - font-weight: bold; -} - -.logo img { - width: 50px; - height: 50px; -} - -.footer { - font-style: italic; - width: 100%; -} - -.hosted { - text-align: right; -} - -body { - margin: auto 8px 20px 8px; -} - -img { - display: block; - margin-left: auto; - margin-right: auto; - max-width: 100%; -} - -pre, code { - background-color: #eeeeee; -} - -pre { - border: 2px solid; - padding: 6px; -} - -#blob { - background: #ffffff; - border: none; -} - -a { - color: #0f2899; - text-decoration: none; -} - -.links a { - font-weight: bold; - color: black; -} - -.hosted a, -.contact a { - font-weight: bold; -} - -a:hover { - text-decoration: underline; -} - -html { - margin: 1em auto; - max-width: 42em; -} - -h1 { - text-align: center; -} - -td h1 { - text-align: left; - font-size: 1.5em; -} - -table { - width: 100%; -} - -.url td { - font-family: monospace; -} - -.dltable th, .dltable td { - border: 1px solid black; - padding: 3px; -} - -.subtitle { - text-align: center; - font-weight: bold; - font-size: 1.1em; -}