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:
M | Makefile | | | 5 | ++--- |
M | TODO.md | | | 111 | ++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------- |
D | doc/nissy.1 | | | 271 | ------------------------------------------------------------------------------- |
A | old/maybe-useful-coord.c | | | 181 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | old/maybe-useful-steps.c | | | 1111 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | src/alg.c | | | 105 | ++++++++++++++++++++++++++++--------------------------------------------------- |
M | src/alg.h | | | 76 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- |
M | src/commands.c | | | 324 | +++++++++++++++---------------------------------------------------------------- |
M | src/commands.h | | | 194 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- |
M | src/coord.c | | | 992 | ++++++++++++++++++++++++++++++++++++++++++------------------------------------- |
M | src/coord.h | | | 246 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- |
M | src/cube.c | | | 920 | +++++++------------------------------------------------------------------------ |
M | src/cube.h | | | 44 | +++++++++----------------------------------- |
M | src/cubetypes.h | | | 176 | +++++++++++++++++++++++++++++++++++++++---------------------------------------- |
M | src/env.c | | | 2 | ++ |
M | src/env.h | | | 4 | ++-- |
M | src/moves.c | | | 409 | ++++++++++++++----------------------------------------------------------------- |
M | src/moves.h | | | 20 | ++------------------ |
D | src/pf.c | | | 95 | ------------------------------------------------------------------------------- |
D | src/pf.h | | | 20 | -------------------- |
M | src/pruning.c | | | 265 | ++++++++++++++++++++++++------------------------------------------------------- |
M | src/pruning.h | | | 21 | +++++---------------- |
M | src/shell.c | | | 22 | +++++++++++++++++++++- |
M | src/solve.c | | | 485 | ++++++++++++++++++++++++++++++++++++++----------------------------------------- |
M | src/solve.h | | | 4 | ++-- |
M | src/steps.c | | | 1514 | +++++++------------------------------------------------------------------------ |
M | src/steps.h | | | 276 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- |
D | src/symcoord.c | | | 687 | ------------------------------------------------------------------------------- |
D | src/symcoord.h | | | 17 | ----------------- |
M | src/trans.c | | | 383 | +++++++++++++++++++++---------------------------------------------------------- |
M | src/trans.h | | | 36 | +++++++++++++++++++++--------------- |
M | src/utils.c | | | 14 | ++++++++------ |
M | www/download/index.html | | | 2 | +- |
M | www/examples/index.html | | | 2 | +- |
M | www/index.html | | | 2 | +- |
A | www/style-2.css | | | 105 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
D | www/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;
-}