commit 6f4313bc1ed5be794146e6ca2fd73f48c7906061
parent 1a5bfe9b08707b0aef748d7921a419ba4a046fba
Author: Sebastiano Tronto <sebastiano@tronto.net>
Date: Mon, 1 May 2023 12:48:55 +0200
Reverted to 2.0.3
Diffstat:
68 files changed, 5571 insertions(+), 6635 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -2,4 +2,3 @@ doc/*.html
doc/*.pdf
nissy
nissy-*
-test
diff --git a/INSTALL b/INSTALL
@@ -4,78 +4,57 @@ Nissy is available at https://nissy.tronto.net
# Requirements
-A full installation of nissy requires about 3Gb of space, of which
-2.3Gb are occupied by the huge pruning table for fast optimal solving,
-and running it requires the same amount of RAM. One can choose to never
-use this function and not to install the relative pruning table. There
-is an alternative (slower) optimal solving function that uses about
-500Mb of RAM. When generating the pruning tables automatically (see
-the section Tables below), at least 5.3Gb or RAM are required.
+A full installation of nissy requires about 3Gb of space,
+of which 2.3Gb are occupied by the huge pruning table for fast optimal solving,
+and running it requires the same amount of RAM.
+One can choose to never use this function and not to install the relative
+pruning table. There is an alternative (slower)
+optimal solving function that uses about 500Mb of RAM.
# Installation
## On Windows
Try downloading and executing in a terminal the file nissy.exe, then
-follow the instructions in the Tables section below for installing the
-pruning tables. If nissy.exe does not work, you can try following the
-UNIX instructions in WSL (Windows Subsystem for Linux) or in a similar
-environment.
+follow the instructions in the Tables section below for
+installing the pruning tables.
+If nissy.exe does not work, you can try following the UNIX instructions
+in WSL (Windows Subsystem for Linux) or in a similar environment.
-## On a UNIX system:
-
-Download the source archive (.tar.gz). Extract it with your favorite
-archive program, for example with
-
- tar -xvzf nissy-VERSION.tar.gz
-
-Open a terminal in the directory just extracted. If you wish, edit the
-Makefile to match your local configuration (this is usually not necessary,
-but you may want to change the PREFIX variable to change the installation
-path) and run
-
- make
-
-followed by
+Sorry for the inconvenience, I don't have a Windows machine to test this on.
- make install
+## On a UNIX system:
-Then follow the instructions below to install the pruning tables.
+Edit the Makefile to match your local configuration (usually not necessary, but you
+may want to change the PREFIX variable) and run make, followed by make install.
+Follow the instructions below to install the pruning tables.
## Tables
+Nissy needs to generate certain large tables to work. These tables are by default
+generated the first time they are needed (e.g the first time you ask to solve a
+certain step) and then saved to a file. Whenever these tables are needed again,
+nissy simply loads the corresponding file from the hard disk.
-Once you have installed nissy, run
+The very large table for optimal solving can take some time to generate
+(about 1.5 hours on my fairly old but decent laptop, using 8 CPU threads).
+In order to generate it you need at least 5Gb of RAM.
+All other tables are much faster.
- nissy gen
+You can ask nissy to generate all the tables it will ever need with the gen
+command. It is recommended to use more than one thread, if your CPU has them.
+For example, you can run:
-to generate all the tables that Nissy will ever need. Running this
-command requires around 5.3Gb of RAM, and it can take some time (about
-40 minutes on my fairly old but decent laptop, with 8 CPU threads).
+nissy gen -t 8
-Some unnecessary technical detail: by default this command is going to
-use at most 64 threads. If you want you can choose to use more threads
-(if your CPU is very powerful) or fewer threads (if you for example
-want to run this command in the background while you do other stuff)
-with the -t option, for example nissy gen -t 1.
+to generate all tables using 8 threads.
-Alternatively, you can download all the tables (1.7Gb) and copy them
-into the correct folder (see manual page, ENVIRONMENT section). On UNIX
-operating systems this folder is either .nissy/tables in the user's
-home directory or $XDG_DATA_HOME/nissy/tables if the XDG variable
-is configured. On Windows it is the same directory as the nissy.exe
-executable file.
+Alternatively, you can simply download all the tables and copy them into the
+correct folder (see manual page, ENVIRONMENT section). On UNIX operating
+systems this folder is either .nissy/tables in the user's home directory or
+$XDG_DATA_HOME/nissy/tables if the XDG variable is configured. On Windows
+it is the same directory as the nissy.exe executable file.
You can downloads all the tables from the following link:
-
- https://nissy.tronto.net/nissy-tables-2.0.2.zip
-
-# Upgrading
-
-If you already have nissy installed and you want to upgrade to a more
-recent version, you can simply repeat the installation process:
-* On Windows: simply replace nissy.exe with the new file with the same name.
-* On UNIX systems: download the new version of the source code, extract it
- in a new folder and run make and make install again.
-
-Between each version new table files might have been added, or old ones
-may be not used anymore. Nissy will deal with this automatically.
+ https://nissy.tronto.net/nissy-tables-2.0.zip
+The version 2.0 at the end of the file name is only indicative.
+Later versions will use the same tables, unless otherwise specified.
diff --git a/Makefile b/Makefile
@@ -1,18 +1,19 @@
# See LICENSE file for copyright and license details.
-VERSION = post-2.0.2
+VERSION = 2.0.3
PREFIX = /usr/local
MANPREFIX = ${PREFIX}/share/man
-CPPFLAGS = -DVERSION=\"${VERSION}\"
-CFLAGS = -std=c99 -pthread -pedantic -Wall -Wextra \
- -Wno-unused-parameter -O3 ${CPPFLAGS}
-DBGFLAGS = -std=c99 -pthread -pedantic -Wall -Wextra \
- -Wno-unused-parameter -g ${CPPFLAGS}
+CPPFLAGS = -DVERSION=\"${VERSION}\"
+CFLAGS = -std=c99 -pthread -pedantic -Wall -Wextra \
+ -Wno-unused-parameter -O3 ${CPPFLAGS}
+DBGFLAGS = -std=c99 -pthread -pedantic -Wall -Wextra \
+ -Wno-unused-parameter -g ${CPPFLAGS}
CC = cc
+
all: nissy
nissy: clean
@@ -24,11 +25,8 @@ nissy.exe:
debug:
${CC} ${DBGFLAGS} -o nissy src/*.c
-test:
- ${CC} ${DBGFLAGS} -DTEST -o test src/*.c tests/*.c
-
clean:
- rm -rf nissy nissy*.exe nissy*.tar.gz doc/nissy.html doc/nissy.pdf
+ rm -rf nissy nissy*.exe nissy*.tar.gz
dist: clean nissy.exe
mkdir -p nissy-${VERSION}
@@ -65,4 +63,5 @@ uninstall:
rm -rf ${DESTDIR}${PREFIX}/bin/nissy ${DESTDIR}${MANPREFIX}/man1/nissy.1
for s in ${SCRIPTS}; do rm -rf ${DESTDIR}${PREFIX}/bin/$$s; done
-.PHONY: all debug test clean dist install uninstall upload
+.PHONY: all debug clean dist install uninstall upload
+
diff --git a/TODO/2.1.md b/TODO/2.1.md
@@ -1,51 +0,0 @@
-# TODO-list for version 2.1 (or is it 3.0 at this point?)
-
-## Rework solver
-
-### 1. Implement minimum viable
-
-* Implement nxopt31 with fst_cube. Remember that the function
- move_check_solved() should do one axis at the time, so that we don't move
- everything before checking.
-* test?
-
-### 2. Rework achitecture and file dependencies
-
-* solve.h depends only on moves(alg?) (dependency on step and trans is removed).
-* Other modules have changed dependencies, might as well rework all.
-* Make files smaller, do not include definition in .h, separate
-data from abstract operations.
-* remove cubetypes.h
-* Create a module for multi-step (maybe wait?)
-* Possible changes: in step solver, copy cube only if niss; add cleanup function
-in solver (called by solve()) to free cube and perhaps pruning tables.
-* see various TODO's in files
-
-### 4. More threading options
-
-* Lazy multithread: threads are as independent as possible and only
-merged at the end. Ideal when all solutions of a certain length are requested.
-* (Done) Eager multithread: current implementation, branches communicate the
-number and list of solutions to stop as soon as possible. Good when only one
-solution of a certain depth is required.
-
-## Simplify steps
-
-* Remove one type of rotation.
-* Change steps to choicestep and stepalt to step (or was this already done?).
-
-## Add missing coordinates and steps
-
-* Check the old file for a list. Many are missing.
-* Checkers in steps.c should use coordinates.
-
-## Missing and new commands
-
-* gen
-* freemem
-* twophase
-
-## Easy improvements
-
-* Solve should re-orient the cube if centers are off
-* Solve: add options for -I (inverse only) and -L (linear = normal + inverse).
diff --git a/TODO/build-options.md b/TODO/build-options.md
@@ -1,33 +0,0 @@
-# Build options for memory and multithreading
-
-## Investigate
-
-* Check exactly how much memory is needed for everything.
-* Take note of which parts use threading (solving, genptable, other?).
-
-## Prepare code
-
-* Use define / ifdef or similar to compile and build tables only for the
- parts to be used.
-* If threads = 1, use a much simpler version of the solve method. Remember
- that checking if enough solutions have been found is the first thing to
- do in singlethread (no locking).
-* Do not include pthread if threads = 1.
-* Only one optimal solver should be compiled.
-* Some simple steps may also need alternatives with smaller tables
- (e.g. for staying sub 1Gb). For example dr and drfin.
-* If necessary, work out alternatives to "twophase" for low-resource versions.
-
-## Makefile
-
-* Figure out how to change these options via makefile. For example: one
- variable for the maximum allowed ram and one for the number of threads.
-* (Optional) use a configure script?
-* (Optional) interactive installation script?
-
-## Automate
-
-* Scout for resources during installation and choose best configuration
- automatically.
-* How to do this in Linux / POSIX?
-* How to do this in Windows?
diff --git a/TODO/documentation.md b/TODO/documentation.md
@@ -1,41 +0,0 @@
-# Documentation
-
-## Big documentation file on nissy's internals
-
-* Coordinates
-* Symcoordinates
-* Pruning tables
-* Coordinate solving
-* fst cube
-* Optimized solver
-* Multithreading
-* Commands etc...
-* Code architecture
-
-## examples.md
-
-* Example file for nissy's website and documentation folder
-* With screenshots!
-
-## Random info
-
-Where to collect random information like this table?
-
-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/TODO/easy.md b/TODO/easy.md
@@ -1,16 +0,0 @@
-# Easy things to improve or add
-
-## Improvements
-
-* Silent batch mode without >>>
-* Solutions should be shown sorted: by length first, then by normal moves
- (no niss) first, then it depends on the step (e.g. EO by axis).
-
-## Old commands and steps
-
-* drcorners (solve corners after DR)
-* Search and improve suboptimal subsequences
-
-## New commands
-
-* notation: show valid moves
diff --git a/TODO/installation.md b/TODO/installation.md
@@ -1,14 +0,0 @@
-# Simplify and improve installation
-
-## Tables
-
-* Make install should generate tables, or add a "make tables" target to
- generate tables.
-* Make tables should also check for existing files and remove old ones
- (maybe more for nissy's command than for makefile).
-
-## Correctness
-
-* Add checksum for all generated files.
-* Hard-code results? Check for compatibility problems between different OSes
- and filesystems - but there should not be any, since we use stdint.h.
diff --git a/TODO/new-feature-ideas.md b/TODO/new-feature-ideas.md
@@ -1,32 +0,0 @@
-# Possible new features and improvements
-
-This file contains non-refined ideas. Once an idea gets refined, it will
-get its own file and more details.
-
-## Steps
-
-* QTM solver
-* 5-side solver (for robots)
-* Other steps (cross, blocks, LSE...)
-
-## UX features
-
-* Save algs as variables and edit them (like in old nissy)
-* Use a logging system for previously run commands, info, results...
- (e.g. when solving with -c solutions are not shown, they can be logged here)
-* Configurability: add an "alias" command, run config file at startup
-* Input cube state directly instead of moves (ugly from command line / file)
-
-## Improvements
-
-* Optimal solver: when asking only for one solution, scan for upper bound in
- parallel using a non-optimal (but fast) solver (e.g. twophase).
-* Optimal solver: up to a small bound, try with a small pruning table.
-* Optimal solver: start at different depths in parallel
-* Multi-step solver: make more general
-
-## New features
-
-* Allow user to specify moveset manually (see issue \#5 on github)
-* EO analysis (and also DR and HTR analysis): group similar EOs (Jay)
-* HTR "maze" analysis?
diff --git a/TODO/parser.md b/TODO/parser.md
@@ -1,13 +0,0 @@
-# Improve command parser
-
-First, expand this TODO file to be more precise.
-
-## Refactor
-
-* The syntax of a command's options should be described by data, not by a
- parser function.
-* A single parser function can then parse options for all commands.
-
-## Usability
-
-* Better error messages!
diff --git a/TODO/refactoring.md b/TODO/refactoring.md
@@ -1,28 +0,0 @@
-# Refactoring
-
-## Init functions
-
-* All .h files should have a single init function.
-* This function should initialize everything that this module needs, including
- calling the init functions of the modules it depends on.
-* To avoid multiple initialization of the same module, each should have a
- static bool initialized variable.
-* Everything that a module needs should be initialized by init(), avoid
- initializing stuff when solving. Exception: pruning tables, move tables.
-* Most functions should generate some tables and save them to disk.
-* Init functions should have a consistent structure (e.g. the way they check
- if the tables are already generated should be the same).
-
-## Cube types
-
-* Get rid of cubetype.h, split type definitionss into the other modules.
-* Every type definition should be in the most fundamental module that needs it.
-
-## Code style
-
-* Stop declaring all variables at the beginning of a function.
-* Remove variable names from prototypes.
-* Sort function implementations alphabetically, ignore static vs non static.
-* Rename functions and variable to have a consistent naming scheme.
-* Functions that copy data: swap src and dest, follow memcpy standard.
-* Read style(9) and decide what to implement.
diff --git a/TODO/testing.md b/TODO/testing.md
@@ -1,6 +0,0 @@
-# Testing
-
-## Write tests
-
-* Write tests for each module. Some of might require refactoring (this is
- a good thing!)
diff --git a/TODO/webapp.md b/TODO/webapp.md
@@ -1,19 +0,0 @@
-# Towards a nissy webapp
-
-## Architecture
-
-* Split in client / server.
-* Server can load and keep in memory all the tables, client(s) send messages to
- the server to run commands.
-* Use UNIX sockets only first, maybe later try WinSock.
-
-## Simple webapp
-
-* Investigate how to use fastcgi, try simple program first.
-* Decide what limits to put in terms of resources and write a "filter" script
- to block big requests (maybe use a timeout).
-
-## Advanced webapp
-
-* Use cubing.js for nice graphics.
-* Port it to a graphical desktop version too.
diff --git a/old/maybe-useful-coord.c b/old/maybe-useful-coord.c
@@ -1,181 +0,0 @@
-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
@@ -1,1111 +0,0 @@
-#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/old/solve_old.c b/old/solve_old.c
@@ -1,447 +0,0 @@
-#define SOLVE_C
-
-#include "solve.h"
-
-/* Local functions ***********************************************************/
-
-static void copy_dfsarg(DfsArg *src, DfsArg *dst);
-static void dfs(DfsArg *arg);
-static void dfs_add_sol(DfsArg *arg);
-static void dfs_niss(DfsArg *arg);
-static bool dfs_move_checkstop(DfsArg *arg);
-static void * instance_thread(void *arg);
-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 void
-copy_dfsarg(DfsArg *src, DfsArg *dst)
-{
- int i;
-
- dst->cube = src->cube;
- dst->t = src->t;
- dst->s = src->s;
- 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 < src->s->n_coord; i++) {
- dst->ind[i].val = src->ind[i].val;
- dst->ind[i].t = src->ind[i].t;
- }
-
- src->s->copy_extra(src, dst);
-}
-
-static void
-dfs(DfsArg *arg)
-{
- int i;
- Move m, l0, l1;
- DfsArg newarg;
-
- if (dfs_move_checkstop(arg))
- return;
-
- if (arg->bound == 0) {
- if (arg->current_alg->len == arg->d)
- dfs_add_sol(arg);
- return;
- }
-
- for (i = 0; arg->s->moveset->sorted_moves[i] != NULLMOVE; i++) {
- m = arg->s->moveset->sorted_moves[i];
- if (arg->s->moveset->can_append(arg->current_alg, m, arg->niss)
- && compare_last(arg->current_alg, m, arg->niss) >= 0) {
- copy_dfsarg(arg, &newarg);
- append_move(arg->current_alg, m, newarg.niss);
- dfs(&newarg);
- remove_last_move(arg->current_alg);
- }
- }
-
- if (niss_makes_sense(arg))
- dfs_niss(arg);
-}
-
-static void
-dfs_add_sol(DfsArg *arg)
-{
- bool valid, accepted, nisscanc;
-
- valid = arg->s->is_valid==NULL || arg->s->is_valid(arg->current_alg);
- accepted = valid || arg->opts->all;
- nisscanc = arg->s->final &&
- arg->s->moveset->cancel_niss(arg->current_alg);
-
- if (accepted && !nisscanc) {
- pthread_mutex_lock(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);
- }
-
- pthread_mutex_unlock(arg->sols_mutex);
- }
-}
-
-static void
-dfs_niss(DfsArg *arg)
-{
- 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.s, newarg.cube, newarg.ind);
-
- newarg.niss = !(arg->niss);
-
- dfs(&newarg);
-
- free_alg(inv);
- free(c);
- free(newarg.cube);
-}
-
-static bool
-dfs_move_checkstop(DfsArg *arg)
-{
- int i, goal, nsols;
- Move mm;
- Trans tt = uf; /* Avoid uninitialized warning */
-
- /* Moving and computing bound */
- arg->bound = 0;
- goal = arg->d - arg->current_alg->len;
- for (i = 0; i < arg->s->n_coord; i++) {
- if (arg->last[0] != NULLMOVE) {
- mm = transform_move(arg->ind[i].t, arg->last[0]);
- arg->ind[i].val = move_coord(arg->s->coord[i],
- mm, arg->ind[i].val, &tt);
- arg->ind[i].t = transform_trans(tt, arg->ind[i].t);
- }
-
- arg->bound =
- MAX(arg->bound, ptableval(arg->s->pd[i], arg->ind[i].val));
- if (arg->opts->can_niss && !arg->niss)
- arg->bound = MIN(1, arg->bound);
-
- if (arg->bound > goal)
- return true;
- }
-
- pthread_mutex_lock(arg->sols_mutex);
- nsols = arg->sols->len;
- pthread_mutex_unlock(arg->sols_mutex);
-
- return nsols >= arg->opts->max_solutions;
-}
-
-static void *
-instance_thread(void *arg)
-{
- bool b, inv;
- Cube c;
- Move m;
- ThreadDataSolve *td;
- AlgListNode *node;
- DfsArg darg;
-
- td = (ThreadDataSolve *)arg;
-
- while (1) {
- b = false;
-
- pthread_mutex_lock(td->start_mutex);
- if ((node = *(td->node)) == NULL)
- b = true;
- else
- *(td->node) = (*(td->node))->next;
- pthread_mutex_unlock(td->start_mutex);
-
- if (b)
- break;
-
- 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.s, &c, darg.ind);
- darg.cube = &c;
-
- darg.niss = inv;
- darg.current_alg = new_alg("");
- append_move(darg.current_alg, m, inv);
-
- dfs(&darg);
-
- free_alg(darg.current_alg);
- }
-
- return NULL;
-}
-
-static void
-multidfs(DfsArg *arg)
-{
- int i;
- Cube local_cube;
- Alg *alg;
- AlgList *start;
- AlgListNode **node;
- pthread_t t[arg->opts->nthreads];
- ThreadDataSolve td[arg->opts->nthreads];
- pthread_mutex_t *start_mutex, *sols_mutex;
-
- node = malloc(sizeof(AlgListNode *));
- start_mutex = malloc(sizeof(pthread_mutex_t));
- sols_mutex = malloc(sizeof(pthread_mutex_t));
-
- start = new_alglist();
- pthread_mutex_init(start_mutex, NULL);
- pthread_mutex_init(sols_mutex, NULL);
-
- for (i = 0; arg->s->moveset->sorted_moves[i] != NULLMOVE; i++) {
- alg = new_alg("");
- append_move(alg, arg->s->moveset->sorted_moves[i], false);
- append_alg(start, alg);
- if (arg->opts->can_niss && !arg->s->final) {
- alg->inv[0] = true;
- append_alg(start, alg);
- }
- free_alg(alg);
- }
- *node = start->first;
-
- 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 < arg->opts->nthreads; i++)
- pthread_join(t[i], NULL);
-
- free_alglist(start);
- free(node);
- free(start_mutex);
- free(sols_mutex);
-}
-
-static bool
-niss_makes_sense(DfsArg *arg)
-{
- Move m, mm;
- uint64_t u;
- int i;
-
- if (arg->s->final || arg->niss || !arg->opts->can_niss)
- return false;
-
- if (arg->current_alg->len_normal == 0)
- return true;
-
- m = inverse_move(arg->last[0]);
- for (i = 0; i < arg->s->n_coord; i++) {
- mm = transform_move(arg->ind[i].t, m);
- u = move_coord(arg->s->coord[i], mm, 0, NULL);
- if (ptableval(arg->s->pd[i], u) > 0)
- return true;
- }
-
- return false;
-}
-
-static bool
-solvestop(int d, int op, SolveOptions *opts, AlgList *sols)
-{
- bool opt_done, max_moves_exceeded, max_sols_exceeded;
-
- opt_done = opts->optimal != -1 && op != -1 && d > opts->optimal + op;
- max_moves_exceeded = d > opts->max_moves;
- max_sols_exceeded = sols->len >= opts->max_solutions;
-
- return opt_done || max_moves_exceeded || max_sols_exceeded;
-}
-
-/* Public functions **********************************************************/
-
-AlgList *
-solve(Cube *cube, ChoiceStep *cs, SolveOptions *opts)
-{
- int i, j, d, op, est;
- bool ready[99], one_ready, zerosol;
- Movable ind[99][10];
- AlgList *s;
- Cube *c[99];
- DfsArg arg[99];
-
- prepare_cs(cs, opts);
- s = new_alglist();
-
- for (i = 0, one_ready = false; cs->step[i] != NULL; i++) {
- c[i] = malloc(sizeof(Cube));
- copy_cube(cube, c[i]);
- apply_trans(cs->t[i], c[i]);
-
- arg[i].cube = c[i];
- arg[i].t = cs->t[i];
- arg[i].s = cs->step[i];
- arg[i].opts = opts;
- arg[i].sols = s;
-
- if ((ready[i] = cs->step[i]->ready(c[i]))) {
- one_ready = true;
- /* Only for local use for 0 moves solutions */
- compute_ind(cs->step[i], c[i], ind[i]);
- }
- }
- if (!one_ready) {
- fprintf(stderr, "Cube not ready for solving step: ");
- fprintf(stderr, "%s\n", cs->ready_msg);
- return s;
- }
-
- /* 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; cs->step[i] != NULL; i++) {
- if (ready[i]) {
- est = 0;
- for (j = 0; j < cs->step[i]->n_coord; j++)
- est = MAX(est, ptableval(cs->step[i]->pd[j],
- ind[i][j].val));
- if (est == 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");
- }
-
- 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; cs->step[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;
- }
- }
-
- for (i = 0; cs->step[i] != NULL; i++)
- free(c[i]);
-
- return s;
-}
-
-/* TODO: make more general! */
-Alg *
-solve_2phase(Cube *cube, int nthreads)
-{
- int bestlen, newb;
- Alg *bestalg, *ret;
- AlgList *sols1, *sols2;
- AlgListNode *i;
- Cube c;
- SolveOptions opts1, opts2;
-
- opts1.min_moves = 0;
- opts1.max_moves = 13;
- opts1.max_solutions = 20;
- opts1.nthreads = nthreads;
- opts1.optimal = 3;
- opts1.can_niss = false;
- opts1.verbose = false;
- opts1.all = true;
-
- opts2.min_moves = 0;
- opts2.max_moves = 19;
- opts2.max_solutions = 1;
- opts2.nthreads = nthreads;
- opts2.can_niss = false;
- opts2.verbose = false;
-
- /* 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, &drud_HTM, &opts1);
- }
- bestalg = new_alg("");
- bestlen = 999;
- for (i = sols1->first; i != NULL; i = i->next) {
- 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;
- if (newb < bestlen) {
- bestlen = newb;
- copy_alg(i->alg, bestalg);
- compose_alg(bestalg, sols2->first->alg);
- }
- }
-
- free_alglist(sols2);
- }
-
- free_alglist(sols1);
-
- ret = cleanup(bestalg);
- free_alg(bestalg);
-
- return ret;
-}
diff --git a/old/solve_old.h b/old/solve_old.h
@@ -1,9 +0,0 @@
-#ifndef SOLVE_H
-#define SOLVE_H
-
-#include "movesets.h"
-
-AlgList * solve(Cube *cube, ChoiceStep *cs, SolveOptions *opts);
-Alg * solve_2phase(Cube *cube, int nthreads);
-
-#endif
diff --git a/src/alg.c b/src/alg.c
@@ -1,11 +1,112 @@
-#define ALG_C
-
#include "alg.h"
+/* Local functions ***********************************************************/
+
+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
+allowed_HTM(Move m)
+{
+ return m >= U && m <= B3;
+}
+
+static bool
+allowed_URF(Move m)
+{
+ Move b = base_move(m);
+
+ return b == U || b == R || b == F;
+}
+
+static bool
+allowed_eofb(Move m)
+{
+ Move b = base_move(m);
+
+ return b == U || b == D || b == R || b == L ||
+ ((b == F || b == B) && m == b+1);
+}
+
+static bool
+allowed_drud(Move m)
+{
+ Move b = base_move(m);
+
+ return b == U || b == D ||
+ ((b == R || b == L || b == F || b == B) && m == b + 1);
+}
+
+static bool
+allowed_htr(Move m)
+{
+ Move b = base_move(m);
+
+ return moveset_HTM.allowed(m) && m == b + 1;
+}
+
+static bool
+allowed_next_HTM(Move l2, Move l1, Move m)
+{
+ bool p, q;
+
+ p = l1 != NULLMOVE && base_move(l1) == base_move(m);
+ q = l2 != NULLMOVE && base_move(l2) == base_move(m);
+
+ return !(p || (commute(l1, l2) && q));
+}
+
void
append_alg(AlgList *l, Alg *alg)
{
@@ -33,42 +134,30 @@ append_move(Alg *alg, Move m, bool inverse)
alg->move[alg->len] = m;
alg->inv [alg->len] = inverse;
alg->len++;
-
- if (inverse)
- alg->move_inverse[alg->len_inverse++] = m;
- else
- alg->move_normal[alg->len_normal++] = m;
}
static int
axis(Move m)
{
- static int aux[] = {
- [NULLMOVE] = 0,
-
- [U] = 1, [U2] = 1, [U3] = 1,
- [D] = 1, [D2] = 1, [D3] = 1,
- [Uw] = 1, [Uw2] = 1, [Uw3] = 1,
- [Dw] = 1, [Dw2] = 1, [Dw3] = 1,
- [E] = 1, [E2] = 1, [E3] = 1,
- [y] = 1, [y2] = 1, [y3] = 1,
-
- [R] = 2, [R2] = 2, [R3] = 2,
- [L] = 2, [L2] = 2, [L3] = 2,
- [Rw] = 2, [Rw2] = 2, [Rw3] = 2,
- [Lw] = 2, [Lw2] = 2, [Lw3] = 2,
- [M] = 2, [M2] = 2, [M3] = 2,
- [x] = 2, [x2] = 2, [x3] = 2,
-
- [F] = 3, [F2] = 3, [F3] = 3,
- [B] = 3, [B2] = 3, [B3] = 3,
- [Fw] = 3, [Fw2] = 3, [Fw3] = 3,
- [Bw] = 3, [Bw2] = 3, [Bw3] = 3,
- [S] = 3, [S2] = 3, [S3] = 3,
- [z] = 3, [z2] = 3, [z3] = 3,
- };
+ if (m == NULLMOVE)
+ return 0;
+
+ if (m >= U && m <= B3)
+ return (m-1)/6 + 1;
+
+ if (m >= Uw && m <= Bw3)
+ return (m-1)/6 - 2;
+
+ if (base_move(m) == E || base_move(m) == y)
+ return 1;
+
+ if (base_move(m) == M || base_move(m) == x)
+ return 2;
- return aux[m];
+ if (base_move(m) == S || base_move(m) == z)
+ return 3;
+
+ return -1;
}
Move
@@ -86,32 +175,6 @@ commute(Move m1, Move m2)
return axis(m1) == axis(m2);
}
-int
-compare(Move m1, Move m2)
-{
- if (!commute(m1, m2))
- return 0;
-
- return m1 < m2 ? 1 : -1;
-}
-
-int
-compare_last(Alg *alg, Move m, bool inverse)
-{
- Move last;
- int n;
-
- if (inverse) {
- n = alg->len_inverse;
- last = n > 0 ? alg->move_inverse[n-1] : NULLMOVE;
- } else {
- n = alg->len_normal;
- last = n > 0 ? alg->move_normal[n-1] : NULLMOVE;
- }
-
- return compare(last, m);
-}
-
void
compose_alg(Alg *alg1, Alg *alg2)
{
@@ -124,7 +187,7 @@ compose_alg(Alg *alg1, Alg *alg2)
void
copy_alg(Alg *src, Alg *dst)
{
- dst->len = dst->len_normal = dst->len_inverse = 0;
+ dst->len = 0; /* Overwrites */
compose_alg(dst, src);
}
@@ -156,6 +219,16 @@ free_alglistnode(AlgListNode *aln)
free(aln);
}
+void
+inplace(Alg * (*f)(Alg *), Alg *alg)
+{
+ Alg *aux;
+
+ aux = f(alg);
+ copy_alg(aux, alg);
+ free(aux);
+}
+
Alg *
inverse_alg(Alg *alg)
{
@@ -211,14 +284,10 @@ new_alg(char *str)
Move j, m;
alg = malloc(sizeof(Alg));
- alg->allocated = 30;
- alg->move = malloc(alg->allocated * sizeof(Move));
- alg->inv = malloc(alg->allocated * sizeof(bool));
- alg->move_normal = malloc(alg->allocated * sizeof(Move));
- alg->move_inverse = malloc(alg->allocated * sizeof(Move));
- alg->len = 0;
- alg->len_normal = 0;
- alg->len_inverse = 0;
+ alg->move = malloc(30 * sizeof(Move));
+ alg->inv = malloc(30 * sizeof(bool));
+ alg->allocated = 30;
+ alg->len = 0;
niss = false;
for (i = 0; str[i]; i++) {
@@ -227,13 +296,13 @@ new_alg(char *str)
if (str[i] == '(' && niss) {
fprintf(stderr, "Error reading moves: nested ( )\n");
- alg->len = alg->len_normal = alg->len_inverse = 0;
+ alg->len = 0;
return alg;
}
if (str[i] == ')' && !niss) {
fprintf(stderr, "Error reading moves: unmatched )\n");
- alg->len = alg->len_normal = alg->len_inverse = 0;
+ alg->len = 0;
return alg;
}
@@ -300,7 +369,7 @@ new_alg(char *str)
if (niss) {
fprintf(stderr, "Error reading moves: unmatched (\n");
- alg->len = alg->len_normal = alg->len_inverse = 0;
+ alg->len = 0;
}
return alg;
@@ -385,25 +454,12 @@ realloc_alg(Alg *alg, int n)
fprintf(stderr, "something might go wrong.\n");
}
- alg->move = realloc(alg->move, n * sizeof(int));
- alg->inv = realloc(alg->inv, n * sizeof(int));
- alg->move_normal = realloc(alg->move_normal, n * sizeof(int));
- alg->move_inverse = realloc(alg->move_inverse, n * sizeof(int));
+ alg->move = realloc(alg->move, n * sizeof(int));
+ alg->inv = realloc(alg->inv, n * sizeof(int));
alg->allocated = n;
}
void
-remove_last_move(Alg *a)
-{
- a->len--;
-
- if (a->inv[a->len])
- a->len_inverse--;
- else
- a->len_normal--;
-}
-
-void
swapmove(Move *m1, Move *m2)
{
Move aux;
@@ -413,34 +469,6 @@ 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)
{
@@ -449,11 +477,48 @@ unniss(Alg *alg)
ret = new_alg("");
- for (i = 0; i < alg->len_normal; i++)
- append_move(ret, alg->move_normal[i], false);
+ for (i = 0; i < alg->len; i++)
+ if (!alg->inv[i])
+ append_move(ret, alg->move[i], false);
+
+ for (i = alg->len-1; i >= 0; i--)
+ if (alg->inv[i])
+ append_move(ret, inverse_move(alg->move[i]), false);
+
+ return ret;
+}
- for (i = 0; i < alg->len_inverse; i++)
- append_move(ret, inverse_move(alg->move_inverse[i]), false);
+void
+init_moveset(Moveset *ms)
+{
+ int j;
+ uint64_t l, one;
+ Move m, l2, l1;
+
+ one = 1;
+
+ for (j = 0, m = U; m < NMOVES; m++)
+ if (ms->allowed(m))
+ ms->sorted_moves[j++] = m;
+ ms->sorted_moves[j] = NULLMOVE;
+
+ for (l1 = 0; l1 < NMOVES; l1++) {
+ for (l2 = 0; l2 < NMOVES; l2++) {
+ ms->mask[l2][l1] = 0;
+ for (l=0; ms->sorted_moves[l]!=NULLMOVE; l++) {
+ m = ms->sorted_moves[l];
+ if (ms->allowed_next(l2, l1, m))
+ ms->mask[l2][l1] |= (one<<m);
+ }
+ }
+ }
+}
- return ret;
+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,28 +8,36 @@
#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;
+
void append_alg(AlgList *l, Alg *alg);
void append_move(Alg *alg, Move m, bool inverse);
Move base_move(Move m);
-int compare(Move m1, Move m2); /* Return 1 (m1<m2), 0 or -1 (m1>m2) */
-int compare_last(Alg *alg, Move m, bool inverse);
void compose_alg(Alg *alg1, Alg *alg2);
bool commute(Move m1, Move m2);
void copy_alg(Alg *src, Alg *dst);
void free_alg(Alg *alg);
void free_alglist(AlgList *l);
+void inplace(Alg * (*f)(Alg *), Alg *alg);
Alg * inverse_alg(Alg *alg);
Move inverse_move(Move m);
char * move_string(Move m);
+void movelist_to_position(Move *ml, int *pos);
+void moveset_to_list(Moveset ms, Move *lst);
Alg * new_alg(char *str);
AlgList * new_alglist();
Alg * on_inverse(Alg *alg);
void print_alg(Alg *alg, bool l);
void print_alglist(AlgList *al, bool l);
-void remove_last_move(Alg *alg);
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();
+
#endif
diff --git a/src/commands.c b/src/commands.c
@@ -1,11 +1,187 @@
-#define COMMANDS_C
-
#include "commands.h"
-static bool read_cs(CommandArgs *args, char *str);
+/* 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 ***********************************************************/
+
+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 *
@@ -95,7 +271,7 @@ solve_parse_args(int c, char **v)
a->opts->print_number = false;
} else if (!strcmp(v[i], "-c")) {
a->opts->count_only = true;
- } else if (!read_cs(a, v[i])) {
+ } else if (!read_step(a, v[i])) {
break;
}
}
@@ -210,26 +386,17 @@ parse_no_arg(int c, char **v)
/* Exec functions implementation *********************************************/
-void
+static void
solve_exec(CommandArgs *args)
{
Cube c;
AlgList *sols;
- Solver *solver[99];
- Threader *threader;
- make_solved(&c);
- apply_alg(args->scramble, &c);
-/* TODO: adjust */
-/* threader = &threader_single;*/
- threader = &threader_eager;
+ init_all_movesets();
+ init_symcoord();
-/* TODO: adjust */
- int i;
- for (i = 0; args->cs->step[i] != NULL; i++)
- solver[i] = new_stepsolver_lazy(args->cs->step[i]);
- solver[i] = NULL;
- sols = solve(&c, args->opts, solver, threader);
+ c = apply_alg(args->scramble, (Cube){0});
+ sols = solve(c, args->step, args->opts);
if (args->opts->count_only)
printf("%d\n", sols->len);
@@ -239,67 +406,85 @@ solve_exec(CommandArgs *args)
free_alglist(sols);
}
-void
+static void
scramble_exec(CommandArgs *args)
{
Cube cube;
+ CubeArray *arr;
Alg *scr, *ruf, *aux;
- int i, j, eo, ep, co, cp;
+ int i, j, eo, ep, co, cp, a[12];
+ int eparr[12] = { [8] = 8, [9] = 9, [10] = 10, [11] = 11 };
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")) {
- 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;
+ /* 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, 8, eparr);
+ 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));
} else if (!strcmp(args->scrtype, "htr")) {
- make_solved(&cube);
- /* TODO */
+ /* 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));
} else {
- ep = rand() % FACTORIAL12;
- cp = rand() % FACTORIAL8;
eo = rand() % POW2TO11;
+ ep = rand() % FACTORIAL12;
co = rand() % POW3TO7;
+ cp = rand() % FACTORIAL8;
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);
+ }
}
-
- 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]);
+ cube = fourval_to_cube(eo, ep, co, cp);
}
/* TODO: can be optimized for htr and dr using htrfin, drfin */
- /*
- TODO: solve_2phase was removed
- scr = solve_2phase(&cube, 1);
- */
+ scr = solve_2phase(cube, 1);
if (!strcmp(args->scrtype, "fmc")) {
aux = new_alg("");
@@ -328,22 +513,23 @@ scramble_exec(CommandArgs *args)
}
}
-void
+static 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");
}
-void
+static void
invert_exec(CommandArgs *args)
{
Alg *inv;
@@ -354,16 +540,16 @@ invert_exec(CommandArgs *args)
free_alg(inv);
}
-void
+static void
steps_exec(CommandArgs *args)
{
int i;
- for (i = 0; csteps[i] != NULL; i++)
- printf("%-15s %s\n", csteps[i]->shortname, csteps[i]->name);
+ for (i = 0; steps[i] != NULL; i++)
+ printf("%-15s %s\n", steps[i]->shortname, steps[i]->name);
}
-void
+static void
commands_exec(CommandArgs *args)
{
int i;
@@ -373,10 +559,9 @@ commands_exec(CommandArgs *args)
}
-void
+static void
freemem_exec(CommandArgs *args)
{
-/* TODO:
int i;
for (i = 0; all_pd[i] != NULL; i++)
@@ -384,36 +569,35 @@ 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. */
}
-void
+static void
print_exec(CommandArgs *args)
{
- Cube c;
-
- make_solved(&c);
- apply_alg(args->scramble, &c);
- print_cube(&c);
+ init_moves();
+ print_cube(apply_alg(args->scramble, (Cube){0}));
}
-/*
-void
+static void
twophase_exec(CommandArgs *args)
{
Cube c;
Alg *sol;
- make_solved(&c);
- apply_alg(args->scramble, &c);
- sol = solve_2phase(&c, 1);
+ init_all_movesets();
+ init_symcoord();
+
+ c = apply_alg(args->scramble, (Cube){0});
+ sol = solve_2phase(c, 1);
print_alg(sol, false);
free_alg(sol);
}
-*/
-void
+static void
help_exec(CommandArgs *args)
{
if (args->command == NULL) {
@@ -427,7 +611,7 @@ help_exec(CommandArgs *args)
" system (such as Linux or MacOS) or in pdf and html"
" format in the docs folder.\n"
"Nissy is available for free at "
- "https://nissy.tronto.net\n"
+ "https://github.com/sebastianotronto/nissy\n"
);
} else {
printf("Command %s: %s\nusage: %s\n", args->command->name,
@@ -435,24 +619,26 @@ help_exec(CommandArgs *args)
}
}
-void
+static void
quit_exec(CommandArgs *args)
{
exit(0);
}
-void
+static void
cleanup_exec(CommandArgs *args)
{
Alg *alg;
+ init_moves();
+
alg = cleanup(args->scramble);
print_alg(alg, false);
free_alg(alg);
}
-void
+static void
unniss_exec(CommandArgs *args)
{
Alg *aux;
@@ -462,7 +648,7 @@ unniss_exec(CommandArgs *args)
free(aux);
}
-void
+static void
version_exec(CommandArgs *args)
{
printf(VERSION"\n");
@@ -505,8 +691,6 @@ 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)) {
@@ -519,13 +703,13 @@ read_scrtype(CommandArgs *args, char *str)
}
static bool
-read_cs(CommandArgs *args, char *str)
+read_step(CommandArgs *args, char *str)
{
int i;
- for (i = 0; csteps[i] != NULL; i++) {
- if (!strcmp(csteps[i]->shortname, str)) {
- args->cs = csteps[i];
+ for (i = 0; steps[i] != NULL; i++) {
+ if (!strcmp(steps[i]->shortname, str)) {
+ args->step = steps[i];
return true;
}
}
@@ -562,7 +746,7 @@ new_args()
args->opts = malloc(sizeof(SolveOptions));
/* step and command are static */
- args->cs = csteps[0]; /* default: first step in list */
+ args->step = steps[0]; /* default: first step in list */
args->command = NULL;
return args;
diff --git a/src/commands.h b/src/commands.h
@@ -5,207 +5,10 @@
#include "solve.h"
#include "steps.h"
-#include "solver_step.h"
-#include "threader_single.h"
-#include "threader_eager.h"
void free_args(CommandArgs *args);
CommandArgs * new_args();
-/* 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
+extern Command * commands[];
#endif
diff --git a/src/coord.c b/src/coord.c
@@ -1,654 +1,611 @@
-#define COORD_C
-
#include "coord.h"
-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);
+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,
+};
/* Indexers ******************************************************************/
-uint64_t
-index_eofb(Cube *cube)
-{
- return (uint64_t)digit_array_to_int(cube->eo, 11, 2);
-}
-
-uint64_t
-index_coud(Cube *cube)
+static uint64_t
+index_eofb(Cube cube)
{
- return (uint64_t)digit_array_to_int(cube->co, 7, 3);
+ return cube.eofb;
}
-uint64_t
-index_cp(Cube *cube)
+static uint64_t
+index_eofbepos(Cube cube)
{
- return (uint64_t)perm_to_index(cube->cp, 8);
+ return (cube.epose / FACTORIAL4) * POW2TO11 + cube.eofb;
}
-uint64_t
-index_cpudsep(Cube *cube)
+static uint64_t
+index_epud(Cube cube)
{
- int i, c[8];
+ uint64_t ret;
+ CubeArray *arr = new_cubearray(cube, pf_ep);
- for (i = 0; i < 8; i++)
- c[i] = cube->cp[i] < 4 ? 0 : 1;
+ ret = perm_to_index(arr->ep, 8);
+ free_cubearray(arr, pf_ep);
- return (uint64_t)subset_to_index(c, 8, 4);
+ return ret;
}
-uint64_t
-index_epe(Cube *cube)
+static uint64_t
+index_coud(Cube cube)
{
- int i, e[4];
-
- for (i = 0; i < 4; i++)
- e[i] = cube->ep[i+8] - 8;
-
- return (uint64_t)perm_to_index(e, 4);
+ return cube.coud;
}
-uint64_t
-index_epud(Cube *cube)
+static uint64_t
+index_corners(Cube cube)
{
- return (uint64_t)perm_to_index(cube->ep, 8);
+ return cube.coud * FACTORIAL8 + cube.cp;
}
-uint64_t
-index_epos(Cube *cube)
+static uint64_t
+index_cp(Cube cube)
{
- int i, a[12];
-
- for (i = 0; i < 12; i++)
- a[i] = (cube->ep[i] < 8) ? 0 : 1;
-
- return (uint64_t)subset_to_index(a, 12, 4);
+ return cube.cp;
}
-uint64_t
-index_eposepe(Cube *cube)
+static uint64_t
+index_cphtr(Cube cube)
{
- int i, j, e[4];
- uint64_t epos, epe;
-
- epos = (uint64_t)index_epos(cube);
- for (i = 0, j = 0; i < 12; i++)
- if (cube->ep[i] >= 8)
- e[j++] = cube->ep[i] - 8;
- epe = (uint64_t)perm_to_index(e, 4);
-
- return epos * FACTORIAL4 + epe;
+ return cphtr_right_cosets[cube.cp];
}
-/* Inverse indexers **********************************************************/
-
-void
-invindex_eofb(uint64_t ind, Cube *cube)
+static uint64_t
+index_cornershtr(Cube cube)
{
- int_to_sum_zero_array(ind, 2, 12, cube->eo);
+ return cube.coud * BINOM8ON4 * 6 + index_cphtr(cube);
}
-void
-invindex_coud(uint64_t ind, Cube *cube)
+static uint64_t
+index_cornershtrfin(Cube cube)
{
- int_to_sum_zero_array(ind, 3, 8, cube->co);
+ return cornershtrfin_ind[cube.cp];
}
-void
-invindex_cp(uint64_t ind, Cube *cube)
+static uint64_t
+index_drud(Cube cube)
{
- index_to_perm(ind, 8, cube->cp);
-}
-
-void
-invindex_cpudsep(uint64_t ind, Cube *cube)
-{
- int i, j, k, c[8];
-
- 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++;
-}
+ uint64_t a, b, c;
+ a = cube.eofb;
+ b = cube.coud;
+ c = cube.epose / FACTORIAL4;
-void
-invindex_epe(uint64_t ind, Cube *cube)
-{
- int i;
+ b *= POW2TO11;
+ c *= POW2TO11 * POW3TO7;
- index_to_perm(ind, 4, &cube->ep[8]);
- for (i = 0; i < 4; i++)
- cube->ep[i+8] += 8;
+ return a + b + c;
}
-void
-invindex_epud(uint64_t ind, Cube *cube)
+static uint64_t
+index_drud_eofb(Cube cube)
{
- index_to_perm(ind, 8, cube->ep);
+ return index_drud(cube) / POW2TO11;
}
-void
-invindex_epos(uint64_t ind, Cube *cube)
+static uint64_t
+index_htr_drud(Cube cube)
{
- int i, j, k;
+ uint64_t a, 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++;
-}
-
-void
-invindex_eposepe(uint64_t ind, Cube *cube)
-{
- int i, j, k, e[4];
- uint64_t epos, epe;
+ a = index_cphtr(cube);
+ b = htr_eposs_ind[cube.eposs/24];
- epos = ind / FACTORIAL4;
- epe = ind % FACTORIAL4;
-
- index_to_subset(epos, 12, 4, cube->ep);
- index_to_perm(epe, 4, e);
-
- for (i = 0, j = 0, k = 0; i < 12; i++)
- if (cube->ep[i] == 0)
- cube->ep[i] = j++;
- else
- cube->ep[i] = e[k++] + 8;
+ return a * BINOM8ON4 + b;
}
-/* Other local functions *****************************************************/
-
-uint64_t
-indexers_getmax(Indexer **is)
+static uint64_t
+index_htrfin(Cube cube)
{
- int i;
- uint64_t max = 1;
+ uint64_t epe, eps, epm, cp, ep;
- for (i = 0; is[i] != NULL; i++)
- max *= is[i]->n;
+ epe = cube.epose % 24;
+ eps = cube.eposs % 24;
+ epm = cube.eposm % 24;
+ ep = (epe * 24 + eps) *24 + epm;
+ cp = index_cornershtrfin(cube);
- return max;
+ return cp * 24 * 24 * 24 + ep;
}
-uint64_t
-indexers_getind(Indexer **is, Cube *c)
+static uint64_t
+index_cpud_separate(Cube cube)
{
- int i;
- uint64_t max = 0;
+ return cpud_separate_ind[cube.cp];
+}
- for (i = 0; is[i] != NULL; i++) {
- max *= is[i]->n;
- max += is[i]->index(c);
- }
+/* Coordinate movers *********************************************************/
- return max;
+static uint64_t
+move_eofb(Move m, uint64_t ind)
+{
+ return eofb_mtable[m][ind];
}
-void
-indexers_makecube(Indexer **is, uint64_t ind, Cube *c)
+static uint64_t
+move_eofbepos(Move m, uint64_t ind)
{
- /* 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. */
+ uint64_t a, b;
- int i;
- uint64_t m;
+ a = epose_mtable[m][(ind / POW2TO11)*24];
+ b = eofb_mtable[m][ind % POW2TO11];
- 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;
- }
+ return (a/24) * POW2TO11 + b;
}
-static void
-gen_coord_comp(Coordinate *coord)
+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];
uint64_t ui;
- Cube c, mvd;
- Move m;
- Trans t;
-
- 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);
-
- 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);
- }
- }
- if (!write_coord_mtable(coord))
- fprintf(stderr, "%s: error writing mtable\n",
- coord->name);
-
- fprintf(stderr, "%s: mtable generated\n", coord->name);
+ int j;
+ Move mj;
+ Cube c;
+ CubeArray *arr, *auxarr;
+
+ if (!moveset_drud.allowed(m)) {
+ fprintf(stderr, "Move not allowed for epud\n"
+ "This is a bug, please report\n");
+ return coord_epud.max;
}
- if (!read_coord_ttable(coord)) {
- fprintf(stderr, "%s: generating ttable\n", coord->name);
-
- 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 (!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);
}
}
- if (!write_coord_ttable(coord))
- fprintf(stderr, "%s: error writing ttable\n",
- coord->name);
+ free(auxarr);
+
+ initialized = true;
}
+
+ return aux[shortlist[m]][ind];
}
-static void
-gen_coord_sym(Coordinate *coord)
+static uint64_t
+move_coud(Move m, uint64_t ind)
{
- uint64_t i, in, ui, uj, uu, M, nr;
- int j;
- Move m;
- Trans t;
-
- 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));
-
- if (!read_coord_sd(coord)) {
- fprintf(stderr, "%s: generating syms\n", coord->name);
+ return coud_mtable[m][ind];
+}
- for (i = 0; i < M; i++)
- coord->symclass[i] = M+1;
+static uint64_t
+move_corners(Move m, uint64_t ind)
+{
+ uint64_t a, b;
- for (i = 0, nr = 0; i < M; i++) {
- if (coord->symclass[i] != M+1)
- continue;
+ a = coud_mtable[m][ind / FACTORIAL8];
+ b = cp_mtable[m][ind % FACTORIAL8];
- 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++;
- }
+ return a * FACTORIAL8 + b;
+}
- coord->max = nr;
+static uint64_t
+move_cp(Move m, uint64_t ind)
+{
+ return cp_mtable[m][ind];
+}
- fprintf(stderr, "%s: found %" PRIu64 " classes\n",
- coord->name, nr);
- if (!write_coord_sd(coord))
- fprintf(stderr, "%s: error writing symdata\n",
- coord->name);
- }
+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;
- coord->symrep = realloc(coord->symrep, coord->max*sizeof(uint64_t));
- coord->selfsim = realloc(coord->selfsim, coord->max*sizeof(uint64_t));
+ 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]]];
- for (m = 0; m < NMOVES; m++) {
- coord->mtable[m] = malloc(coord->max*sizeof(uint64_t));
- coord->ttrep_move[m] = malloc(coord->max*sizeof(Trans));
+ initialized = true;
}
- 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);
- }
+ return aux[m][ind];
}
-static bool
-read_coord_mtable(Coordinate *coord)
+static uint64_t
+move_cornershtr(Move m, uint64_t ind)
{
- FILE *f;
- char fname[strlen(tabledir)+256];
- Move m;
- uint64_t M;
- bool r;
+ uint64_t a, b;
- strcpy(fname, tabledir);
- strcat(fname, "/mt_");
- strcat(fname, coord->name);
+ a = coud_mtable[m][ind/(BINOM8ON4 * 6)];
+ b = move_cphtr(m, ind % (BINOM8ON4 * 6));
- if ((f = fopen(fname, "rb")) == NULL)
- return false;
-
- M = coord->max;
- r = true;
- for (m = 0; m < NMOVES; m++)
- r = r && fread(coord->mtable[m], sizeof(uint64_t), M, f) == M;
-
- 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;
+ return a * BINOM8ON4 * 6 + b;
}
-static bool
-read_coord_sd(Coordinate *coord)
+static uint64_t
+move_cornershtrfin(Move m, uint64_t ind)
{
- FILE *f;
- char fname[strlen(tabledir)+256];
- uint64_t M, N;
- bool r;
-
- strcpy(fname, tabledir);
- strcat(fname, "/sd_");
- strcat(fname, coord->name);
+ int a;
- if ((f = fopen(fname, "rb")) == NULL)
- return false;
+ a = cp_mtable[m][cornershtrfin_ant[ind]];
- 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;
+ return cornershtrfin_ind[a];
}
-static bool
-read_coord_ttable(Coordinate *coord)
+static uint64_t
+move_drud(Move m, uint64_t ind)
{
- 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, "rb")) == NULL)
- return false;
+ uint64_t a, b, c;
- M = coord->max;
- r = true;
- for (t = 0; t < NTRANS; t++)
- r = r && fread(coord->ttable[t], sizeof(uint64_t), M, f) == M;
+ a = eofb_mtable[m][ind % POW2TO11];
+ b = coud_mtable[m][(ind / POW2TO11) % POW3TO7];
+ c = epose_mtable[m][ind / (POW2TO11 * POW3TO7)];
- fclose(f);
- return r;
+ return a + (b + c * POW3TO7) * POW2TO11;
}
-static bool
-write_coord_mtable(Coordinate *coord)
+static uint64_t
+move_drud_eofb(Move m, uint64_t ind)
{
- 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, "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;
+ uint64_t a, b;
- if (coord->type == SYM_COORD)
- for (m = 0; m < NMOVES; m++)
- r = r && fwrite(coord->ttrep_move[m],
- sizeof(Trans), M, f) == M;
+ a = coud_mtable[m][ind % POW3TO7];
+ b = epose_mtable[m][(ind / POW3TO7) * 24] / 24;
- fclose(f);
- return r;
+ return a + b * POW3TO7;
}
-static bool
-write_coord_sd(Coordinate *coord)
+static uint64_t
+move_htr_drud(Move m, uint64_t ind)
{
- FILE *f;
- char fname[strlen(tabledir)+256];
- uint64_t M, N;
- bool r;
+ uint64_t a, b;
- 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;
-
- 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;
+ return a*BINOM8ON4 + htr_eposs_ind[b/24];
}
-static bool
-write_coord_ttable(Coordinate *coord)
+static uint64_t
+move_htrfin(Move m, uint64_t ind)
{
- 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;
+ uint64_t a, b, bm, bs, be;
- M = coord->max;
- r = true;
- for (t = 0; t < NTRANS; t++)
- r = r && fwrite(coord->ttable[t], sizeof(uint64_t), M, f) == M;
+ 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;
- fclose(f);
- return r;
+ return a * (24*24*24) + b;
}
-/* Public functions **********************************************************/
-
-void
-gen_coord(Coordinate *coord)
+static uint64_t
+move_cpud_separate(Move m, uint64_t ind)
{
- int i;
+ return cpud_separate_ind[cp_mtable[m][cpud_separate_ant[ind]]];
+}
- if (coord == NULL || coord->generated)
- return;
+/* 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()
+{
+ unsigned int i;
+ int c = 0, d = 0;
- 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;
+ for (i = 0; i < FACTORIAL8; i++) {
+ cphtr_left_cosets[i] = -1;
+ cphtr_right_cosets[i] = -1;
}
- coord->generated = true;
- return;
+ /* 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++);
-error_gc:
- fprintf(stderr, "Error generating coordinates.\n"
- "This is a bug, pleae report.\n");
- exit(1);
+ /* 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++);
}
-uint64_t
-index_coord(Coordinate *coord, Cube *cube, Trans *offtrans)
+static void
+init_cphtr_left_cosets_bfs(int i, int c)
{
- uint64_t c[2], cnosym;
- Trans ttr;
+ int j, jj, next[FACTORIAL8], next2[FACTORIAL8], n, n2;
- switch (coord->type) {
- case COMP_COORD:
- if (offtrans != NULL)
- *offtrans = uf;
+ Move k;
- return indexers_getind(coord->i, cube);
- case SYM_COORD:
- cnosym = index_coord(coord->base[0], cube, NULL);
- ttr = coord->transtorep[cnosym];
+ n = 1;
+ next[0] = i;
+ cphtr_left_cosets[i] = c;
- if (offtrans != NULL)
- *offtrans = ttr;
+ 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;
- 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]);
-
- if (offtrans != NULL)
- *offtrans = ttr;
+ if (cphtr_left_cosets[jj] == -1) {
+ cphtr_left_cosets[jj] = c;
+ next2[n2++] = jj;
+ }
+ }
+ }
- return c[0] * coord->base[1]->max + c[1];
- default:
- break;
+ for (j = 0; j < n2; j++)
+ next[j] = next2[j];
+ n = n2;
}
-
- return coord->max; /* Only reached in case of error */
}
-uint64_t
-move_coord(Coordinate *coord, Move m, uint64_t ind, Trans *offtrans)
+static void
+init_cphtr_right_cosets_color(int i, int d)
{
- uint64_t i[2], M;
- Trans ttr;
-
- /* 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. */
-
- 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];
+ int cp;
+ unsigned int j;
+
+ 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;
+ }
+ }
+}
- if (offtrans != NULL)
- *offtrans = ttr;
+static void
+init_cpud_separate()
+{
+ unsigned int ui;
+ int i, co[8];
+
+ 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;
+ }
+}
- 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]];
+static void
+init_cornershtrfin()
+{
+ unsigned int i, j;
+ int n, c;
+ Move m;
- if (offtrans != NULL)
- *offtrans = ttr;
+ for (i = 0; i < FACTORIAL8; i++)
+ cornershtrfin_ind[i] = -1;
+ cornershtrfin_ind[0] = 0;
- return i[0] * M + i[1];
- default:
- break;
+ /* 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++;
+ }
+ }
+ }
+ }
}
-
- return coord->max; /* Only reached in case of error */
}
-uint64_t
-trans_coord(Coordinate *coord, Trans t, uint64_t ind)
+void
+init_htr_eposs()
{
- uint64_t i[2], M;
+ 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;
+ }
+}
- /* 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. */
+void
+init_coord()
+{
+ static bool initialized = false;
+ if (initialized)
+ return;
+ initialized = true;
- 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;
- }
+ init_trans();
- return coord->max; /* Only reached in case of error */
+ init_cphtr_cosets();
+ init_cornershtrfin();
+ init_htr_eposs();
+ init_cpud_separate();
}
+
diff --git a/src/coord.h b/src/coord.h
@@ -3,257 +3,26 @@
#include "trans.h"
-void gen_coord(Coordinate *coord);
-uint64_t index_coord(Coordinate *coord, Cube *cube,
- Trans *offtrans);
-uint64_t indexers_getind(Indexer **is, Cube *c);
-void indexers_makecube(Indexer **is, uint64_t ind, Cube *c);
-uint64_t move_coord(Coordinate *coord, Move m,
- uint64_t ind, Trans *offtrans);
-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;
-
-extern Coordinate *all_coordinates[];
-
-#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},
-};
-
-/* All coordinates ***********************************************************/
-
-Coordinate *all_coordinates[] = {
- &coord_eofb,
- &coord_coud,
- &coord_cp,
- &coord_cpudsep,
- &coord_epos,
- &coord_epe,
- &coord_eposepe,
- &coord_epud,
- &coord_eofbepos,
- &coord_coud_cpudsep,
- &coord_eofbepos_sym16,
- &coord_cp_sym16,
- &coord_corners_sym16,
- &coord_drud_sym16,
- &coord_drudfin_noE_sym16,
- &coord_nxopt31,
- NULL
-};
-
-#endif
+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();
#endif
diff --git a/src/cube.c b/src/cube.c
@@ -1,205 +1,531 @@
-#define CUBE_C
-
#include "cube.h"
-static int where_is_piece(int piece, int *arr, int n);
+/* Local functions ***********************************************************/
-void
-compose_centers(Cube *c2, Cube *c1)
+static void init_inverse();
+static bool read_invtables_file();
+static bool write_invtables_file();
+
+/* Tables ********************************************************************/
+
+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)
{
- apply_permutation(c2->xp, c1->xp, 6);
+ 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
-compose_corners(Cube *c2, Cube *c1)
+Cube
+arrays_to_cube(CubeArray *arr, PieceFilter f)
{
- apply_permutation(c2->cp, c1->cp, 8);
- apply_permutation(c2->cp, c1->co, 8);
- sum_arrays_mod(c2->co, c1->co, 8, 3);
+ 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;
}
-void
-compose_edges(Cube *c2, Cube *c1)
+Cube
+compose_filtered(Cube c2, Cube c1, PieceFilter f)
{
- apply_permutation(c2->ep, c1->ep, 12);
- apply_permutation(c2->ep, c1->eo, 12);
- sum_arrays_mod(c2->eo, c1->eo, 12, 2);
+ CubeArray *arr = new_cubearray(c2, f);
+ Cube ret;
+
+ ret = move_via_arrays(arr, c1, f);
+ free_cubearray(arr, f);
+
+ return ret;
}
void
-compose(Cube *c2, Cube *c1)
+cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f)
{
- compose_centers(c2, c1);
- compose_corners(c2, c1);
- compose_edges(c2, c1);
+ 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);
}
void
-copy_cube_centers(Cube *src, Cube *dst)
+epos_to_compatible_ep(int epos, int *ep, int *ss)
{
- memcpy(dst->xp, src->xp, 6 * sizeof(int));
+ 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
-copy_cube_corners(Cube *src, Cube *dst)
+epos_to_partial_ep(int epos, int *ep, int *ss)
{
- memcpy(dst->cp, src->cp, 8 * sizeof(int));
- memcpy(dst->co, src->co, 8 * sizeof(int));
+ 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
-copy_cube_edges(Cube *src, Cube *dst)
+fix_eorleoud(CubeArray *arr)
{
- memcpy(dst->ep, src->ep, 12 * sizeof(int));
- memcpy(dst->eo, src->eo, 12 * sizeof(int));
+ 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
-copy_cube(Cube *src, Cube *dst)
+fix_cofbcorl(CubeArray *arr)
{
- copy_cube_centers(src, dst);
- copy_cube_corners(src, dst);
- copy_cube_edges(src, dst);
+ 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;
+ }
+ }
+ }
}
-bool
-equal(Cube *c1, Cube *c2)
+Cube
+fourval_to_cube(int eofb, int ep, int coud, int cp)
{
- int i;
+ CubeArray *arr;
- for (i = 0; i < 12; i++)
- if (c1->ep[i] != c2->ep[i] || c1->eo[i] != c2->eo[i])
- return false;
+ arr = new_cubearray((Cube){0}, pf_all);
- for (i = 0; i < 8; i++)
- if (c1->cp[i] != c2->cp[i] || c1->co[i] != c2->co[i])
- return false;
+ 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);
- for (i = 0; i < 6; i++)
- if (c1->xp[i] != c2->xp[i])
- return false;
+ /* fix parity */
+ if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8))
+ swap(&(arr->ep[0]), &(arr->ep[1]));
- return true;
+ fix_eorleoud(arr);
+ fix_cofbcorl(arr);
+
+ return arrays_to_cube(arr, pf_all);
}
void
-invert_cube_centers(Cube *cube)
+free_cubearray(CubeArray *arr, PieceFilter f)
{
- int i;
- Cube aux;
+ 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);
+}
- copy_cube_centers(cube, &aux);
+Cube
+move_via_arrays(CubeArray *arr, Cube c, PieceFilter f)
+{
+ CubeArray *arrc = new_cubearray(c, f);
+ Cube ret;
- for (i = 0; i < 6; i++)
- cube->xp[aux.xp[i]] = i;
+ 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;
}
-void
-invert_cube_corners(Cube *cube)
+CubeArray *
+new_cubearray(Cube cube, PieceFilter f)
{
- int i;
- Cube aux;
+ 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;
+}
- copy_cube_corners(cube, &aux);
+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 < 8; i++) {
- cube->cp[aux.cp[i]] = i;
- cube->co[aux.cp[i]] = (3 - aux.co[i]) % 3;
+ 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;
}
-void
-invert_cube_edges(Cube *cube)
+Cube
+compose(Cube c2, Cube c1)
{
- int i;
- Cube aux;
+ return compose_filtered(c2, c1, pf_all);
+}
- copy_cube_edges(cube, &aux);
+int
+edge_slice(Edge e) {
+ if (e < 0 || e > 11)
+ return -1;
- for (i = 0; i < 12; i++) {
- cube->ep[aux.ep[i]] = i;
- cube->eo[aux.ep[i]] = aux.eo[i];
- }
+ if (e == FR || e == FL || e == BL || e == BR)
+ return 0;
+ if (e == UR || e == UL || e == DR || e == DL)
+ return 1;
+
+ return 2;
}
-void
-invert_cube(Cube *cube)
+bool
+equal(Cube c1, Cube c2)
{
- invert_cube_centers(cube);
- invert_cube_corners(cube);
- invert_cube_edges(cube);
+ 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;
}
bool
-is_admissible(Cube *c) {
- bool perm;
- int sign, i;
- int sum_e, sum_c;
+is_admissible(Cube cube) {
- perm = is_perm(c->ep, 12) && is_perm(c->cp, 8) && is_perm(c->xp, 6);
+ /* TODO: this should check consistency of different orientations */
+ /* check also that centers are opposite and admissible */
- sign = perm_sign(c->ep,12) + perm_sign(c->cp,8) + perm_sign(c->xp,6);
+ CubeArray *a = new_cubearray(cube, pf_all);
+ int parity;
+ bool perm;
- for (i = 0, sum_e = 0; i < 12; i++)
- if (c->eo[i] > 1)
- return false;
- else
- sum_e += c->eo[i];
+ 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);
- for (i = 0, sum_c = 0; i < 8; i++)
- if (c->co[i] > 2)
- return false;
- else
- sum_c += c->co[i];
+ free_cubearray(a, pf_all);
- return (perm && sign % 2 == 0 && sum_e % 2 == 0 && sum_c % 2 == 0);
+ return perm && parity % 2 == 0;
}
bool
-is_solved(Cube *cube)
+is_solved(Cube cube)
{
- Cube solved_cube;
- make_solved(&solved_cube);
-
- return equal(cube, &solved_cube);
+ return equal(cube, (Cube){0});
}
-void
-make_solved_centers(Cube *cube)
+bool
+is_block_solved(Cube cube, Block block)
{
- static int sorted[6] = {0, 1, 2, 3, 4, 5};
+ 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))
+ return false;
- memcpy(cube->xp, sorted, 6 * sizeof(int));
+ return true;
}
-void
-make_solved_corners(Cube *cube)
+bool
+is_solved_center(Cube cube, Center c)
{
- static int sorted[8] = {0, 1, 2, 3, 4, 5, 6, 7};
-
- memcpy(cube->cp, sorted, 8 * sizeof(int));
- memset(cube->co, 0, 8 * sizeof(int));
+ return what_center_at(cube, c) == c;
}
-void
-make_solved_edges(Cube *cube)
+bool
+is_solved_corner(Cube cube, Corner c)
{
- static int sorted[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
+ return what_corner_at(cube, c) == c &&
+ what_orientation_corner(cube.coud, c);
+}
- memcpy(cube->ep, sorted, 12 * sizeof(int));
- memset(cube->eo, 0, 12 * sizeof(int));
+bool
+is_solved_edge(Cube cube, Edge e)
+{
+ return what_edge_at(cube, e) == e &&
+ what_orientation_edge(cube.eofb, e);
}
-void
-make_solved(Cube *cube)
+int
+piece_orientation(Cube cube, int piece, char *orientation)
{
- make_solved_centers(cube);
- make_solved_corners(cube);
- make_solved_edges(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];
+
+ return -1;
}
void
-print_cube(Cube *cube)
+print_cube(Cube cube)
{
static char edge_string[12][7] = {
[UF] = "UF", [UL] = "UL", [UB] = "UB", [UR] = "UR",
@@ -219,52 +545,388 @@ print_cube(Cube *cube)
};
for (int i = 0; i < 12; i++)
- printf(" %s ", edge_string[cube->ep[i]]);
+ printf(" %s ", edge_string[what_edge_at(cube, i)]);
printf("\n");
for (int i = 0; i < 12; i++)
- printf(" %" PRIu8 " ", cube->eo[i]);
+ printf(" %d ", what_orientation_edge(cube.eofb, i));
printf("\n");
for (int i = 0; i < 8; i++)
- printf("%s ", corner_string[cube->cp[i]]);
+ printf("%s ", corner_string[what_corner_at(cube, i)]);
printf("\n");
for (int i = 0; i < 8; i++)
- printf(" %" PRIu8 " ", cube->co[i]);
+ printf(" %d ", what_orientation_corner(cube.coud, i));
printf("\n");
for (int i = 0; i < 6; i++)
- printf(" %s ", center_string[cube->xp[i]]);
+ printf(" %s ", center_string[what_center_at(cube, i)]);
printf("\n");
}
-int
-where_is_center(Center x, Cube *c)
+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)
{
- return where_is_piece(x, c->xp, 6);
+ Edge ret;
+ CubeArray *arr = new_cubearray(cube, pf_ep);
+
+ ret = arr->ep[e];
+
+ free_cubearray(arr, pf_ep);
+ return ret;
}
int
-where_is_corner(Corner k, Cube *c)
+what_orientation_corner(int co, Corner c)
{
- return where_is_piece(k, c->cp, 8);
+ 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
-where_is_edge(Edge e, Cube *c)
+what_orientation_edge(int eo, Edge e)
{
- return where_is_piece(e, c->ep, 12);
+ 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];
}
-static int
-where_is_piece(int piece, int *arr, int n)
+Center
+where_is_center(Cube cube, Center c)
{
- int i;
+ 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;
+ }
- for (i = 0; i < n; i++)
- if (arr[i] == piece)
- return i;
+ return aux[cube.cpos][c];
+}
- return -1;
+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,33 +3,44 @@
#include <stdio.h>
-#include "cubetypes.h"
#include "env.h"
+#include "pf.h"
#include "utils.h"
-void compose(Cube *c2, Cube *c1); /* Use c2 as an alg on c1 */
-void compose_centers(Cube *c2, Cube *c1);
-void compose_corners(Cube *c2, Cube *c1);
-void compose_edges(Cube *c2, Cube *c1);
-void copy_cube(Cube *src, Cube *dst);
-void copy_cube_centers(Cube *src, Cube *dst);
-void copy_cube_corners(Cube *src, Cube *dst);
-void copy_cube_edges(Cube *src, Cube *dst);
-bool equal(Cube *c1, Cube *c2);
-void invert_cube(Cube *cube);
-void invert_cube_centers(Cube *cube);
-void invert_cube_corners(Cube *cube);
-void invert_cube_edges(Cube *cube);
-bool is_admissible(Cube *cube);
-bool is_solved(Cube *cube);
-void make_solved(Cube *cube);
-void make_solved_centers(Cube *cube);
-void make_solved_corners(Cube *cube);
-void make_solved_edges(Cube *cube);
-void print_cube(Cube *cube);
-int where_is_center(Center x, Cube *c);
-int where_is_corner(Corner k, Cube *c);
-int where_is_edge(Edge e, Cube *c);
+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();
#endif
diff --git a/src/cubetypes.h b/src/cubetypes.h
@@ -10,8 +10,6 @@
#define NROTATIONS 24
#define entry_group_t uint8_t /* For pruning tables */
-#define MAX_N_COORD 6
-
/* Enums *********************************************************************/
typedef enum
@@ -30,12 +28,6 @@ corner
} Corner;
typedef enum
-coordtype
-{
- COMP_COORD, SYM_COORD, SYMCOMP_COORD
-} CoordType;
-
-typedef enum
edge
{
UF, UL, UB, UR,
@@ -84,32 +76,33 @@ trans
typedef struct alg Alg;
typedef struct alglist AlgList;
typedef struct alglistnode AlgListNode;
-typedef struct choicestep ChoiceStep;
+typedef struct block Block;
typedef struct command Command;
typedef struct commandargs CommandArgs;
typedef struct coordinate Coordinate;
typedef struct cube Cube;
-/*typedef struct dfsarg DfsArg;*/
-typedef struct fstcube FstCube;
-typedef struct indexer Indexer;
-typedef struct movable Movable;
+typedef struct cubearray CubeArray;
+typedef struct dfsarg DfsArg;
+typedef struct estimatedata EstimateData;
typedef struct moveset Moveset;
+typedef struct piecefilter PieceFilter;
typedef struct prunedata PruneData;
typedef struct solveoptions SolveOptions;
typedef struct step Step;
typedef struct symdata SymData;
typedef struct threaddatasolve ThreadDataSolve;
typedef struct threaddatagenpt ThreadDataGenpt;
-typedef struct transgroup TransGroup;
-typedef bool (*Checker) (Cube *);
-typedef bool (*CubeTester) (Cube *, Alg *);
-/*typedef bool (*DfsMover) (DfsArg *);*/
-typedef void (*DfsExtraCopier) (void *, void *);
-typedef Alg * (*Validator) (Alg *);
+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 (*Validator) (Alg *);
typedef void (*Exec) (CommandArgs *);
+typedef uint64_t (*Indexer) (Cube);
typedef CommandArgs * (*ArgParser) (int, char **);
-typedef bool (*Tester) (void);
+typedef int (*TransDetector) (Cube, Trans *);
typedef int (*TransFinder) (uint64_t, Trans *);
@@ -122,10 +115,6 @@ alg
bool * inv;
int len;
int allocated;
- Move * move_normal;
- int len_normal;
- Move * move_inverse;
- int len_inverse;
};
struct
@@ -144,13 +133,11 @@ alglistnode
};
struct
-choicestep
+block
{
- char * shortname;
- char * name;
- Step * step[99];
- Trans t[99];
- char * ready_msg;
+ bool edge[12];
+ bool corner[8];
+ bool center[6];
};
struct
@@ -169,7 +156,7 @@ commandargs
bool success;
Alg * scramble;
SolveOptions * opts;
- ChoiceStep * cs;
+ Step * step;
Command * command; /* For help */
int n;
char scrtype[20];
@@ -180,119 +167,119 @@ commandargs
struct
coordinate
{
- char * name;
- CoordType type;
- bool generated;
- Indexer * i[99];
+ Indexer index;
uint64_t max;
- 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;
+ CoordMover move;
+ CoordTransformer transform;
+ SymData * sd;
+ TransFinder tfind; /* TODO: should be easy to remove */
+ Coordinate * base; /* TODO: part of refactor */
};
struct
cube
{
- int ep[12];
- int eo[12];
- int cp[8];
- int co[8];
- int xp[6];
+ int epose;
+ int eposs;
+ int eposm;
+ int eofb;
+ int eorl;
+ int eoud;
+ int cp;
+ int coud;
+ int cofb;
+ int corl;
+ int cpos;
};
-/*
struct
-movable
+cubearray
{
- uint64_t val;
- Trans t;
+ int * ep;
+ int * eofb;
+ int * eorl;
+ int * eoud;
+ int * cp;
+ int * coud;
+ int * corl;
+ int * cofb;
+ int * cpos;
};
-*/
-/*
struct
dfsarg
{
- Cube * cube;
- Movable ind[MAX_N_COORD];
- Trans t;
- Step * s;
+ Step * step;
SolveOptions * opts;
+ Trans t;
+ Cube cube;
+ Cube inverse;
int d;
- int bound;
+ uint64_t badmoves;
+ uint64_t badmovesinv;
bool niss;
+ Move last1;
+ Move last2;
+ Move last1inv;
+ Move last2inv;
+ EstimateData * ed;
AlgList * sols;
pthread_mutex_t * sols_mutex;
Alg * current_alg;
- void * extra;
};
-*/
-/*
struct
-dfsarg
+estimatedata
{
- void * cube_data;
- SolveOptions * opts;
- int d;
- int bound;
- bool niss;
- AlgList * sols;
- Alg * current_alg;
- Solver * solver;
- Threader * threader;
+ int corners;
+ int normal_ud;
+ int normal_fb;
+ int normal_rl;
+ int inverse_ud;
+ int inverse_fb;
+ int inverse_rl;
+ int oldret;
};
-*/
struct
-fstcube
+moveset
{
- uint16_t uf_eofb;
- uint16_t uf_eposepe;
- uint16_t uf_coud;
- uint16_t uf_cp;
- uint16_t fr_eofb;
- uint16_t fr_eposepe;
- uint16_t fr_coud;
- uint16_t rd_eofb;
- uint16_t rd_eposepe;
- uint16_t rd_coud;
+ bool (*allowed)(Move);
+ bool (*allowed_next)(Move, Move, Move);
+ Move sorted_moves[NMOVES+1];
+ uint64_t mask[NMOVES][NMOVES];
};
struct
-indexer
+piecefilter
{
- int n;
- uint64_t (*index)(Cube *);
- void (*to_cube)(uint64_t, Cube *);
-};
-
-struct
-moveset
-{
- char * name;
- bool (*allowed)(Move);
- bool (*can_append)(Alg *, Move, bool);
- bool (*cancel_niss)(Alg *);
- Move sorted_moves[NMOVES+1];
+ bool epose;
+ bool eposs;
+ bool eposm;
+ bool eofb;
+ bool eorl;
+ bool eoud;
+ bool cp;
+ bool coud;
+ bool cofb;
+ bool corl;
+ bool cpos;
};
struct
prunedata
{
+ char * filename;
entry_group_t * ptable;
+ bool generated;
uint64_t n;
Coordinate * coord;
Moveset * moveset;
- uint64_t count[16];
bool compact;
int base;
+ uint64_t count[16];
+ PruneData * fallback;
+ uint64_t fbmod;
};
struct
@@ -313,30 +300,52 @@ solveoptions
struct
step
{
- Checker ready;
+ char * shortname;
+ char * name;
bool final;
- Moveset * moveset;
- int n_coord;
- Coordinate * coord[MAX_N_COORD];
- Trans coord_trans[MAX_N_COORD];
- PruneData * pd[MAX_N_COORD];
- bool pd_compact[MAX_N_COORD];
+ Checker is_done;
+ Estimator estimate;
+ Checker ready;
+ char * ready_msg;
Validator is_valid;
- /*DfsMover custom_move_checkstop;*/
- DfsExtraCopier copy_extra;
+ Moveset * moveset;
+ Trans pre_trans;
+ TransDetector detect;
+ int ntables;
+ PruneData * tables[10];
+};
+
+struct
+symdata
+{
+ char * filename;
+ bool generated;
+ Coordinate * coord;
+ Coordinate * sym_coord;
+ int ntrans;
+ Trans * trans;
+ uint64_t * class;
+ 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
threaddatagenpt
@@ -350,11 +359,4 @@ threaddatagenpt
pthread_mutex_t * upmutex;
};
-struct
-transgroup
-{
- int n;
- Trans t[NTRANS];
-};
-
#endif
diff --git a/src/env.c b/src/env.c
@@ -1,5 +1,3 @@
-#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>
-void init_env();
-
extern char *tabledir;
+void init_env();
+
#endif
diff --git a/src/fst.c b/src/fst.c
@@ -1,401 +0,0 @@
-#define FST_C
-
-#include "fst.h"
-
-static FstCube ep_to_fst_epos(int *ep);
-static void init_fst_corner_invtables();
-static void init_fst_eo_invtables();
-static void init_fst_eo_update(uint64_t, uint64_t, int, Cube *);
-static void init_fst_where_is_edge();
-static bool read_fst_tables_file();
-static bool write_fst_tables_file();
-
-static int edge_slice[12] = {[FR] = 0, [FL] = 0, [BL] = 0, [BR] = 0,
- [UL] = 1, [UR] = 1, [DR] = 1, [DL] = 1,
- [UF] = 2, [UB] = 2, [DF] = 2, [DB] = 2};
-
-static uint16_t inv_coud[FACTORIAL8][POW3TO7];
-static uint16_t inv_cp[FACTORIAL8];
-static uint16_t uf_cp_to_fr_cp[FACTORIAL8];
-static uint16_t uf_cp_to_rd_cp[FACTORIAL8];
-static uint16_t eo_invtable[3][POW2TO11][BINOM12ON4*FACTORIAL4];
-static uint16_t fst_where_is_edge_arr[3][12][BINOM12ON4*FACTORIAL4];
-
-FstCube
-cube_to_fst(Cube *cube)
-{
- Cube c;
- FstCube ret;
-
- copy_cube(cube, &c);
- ret.uf_eofb = coord_eofb.i[0]->index(&c);
- ret.uf_eposepe = coord_eposepe.i[0]->index(&c);
- ret.uf_coud = coord_coud.i[0]->index(&c);
- ret.uf_cp = coord_cp.i[0]->index(&c);
- copy_cube(cube, &c);
- apply_trans(fr, &c);
- ret.fr_eofb = coord_eofb.i[0]->index(&c);
- ret.fr_eposepe = coord_eposepe.i[0]->index(&c);
- ret.fr_coud = coord_coud.i[0]->index(&c);
- copy_cube(cube, &c);
- apply_trans(rd, &c);
- ret.rd_eofb = coord_eofb.i[0]->index(&c);
- ret.rd_eposepe = coord_eposepe.i[0]->index(&c);
- ret.rd_coud = coord_coud.i[0]->index(&c);
-
- return ret;
-}
-
-static FstCube
-ep_to_fst_epos(int *ep)
-{
- static int eind[12] = {
- [FR] = 0, [FL] = 1, [BL] = 2, [BR] = 3,
- [UR] = 0, [DR] = 1, [DL] = 2, [UL] = 3,
- [DB] = 0, [DF] = 1, [UF] = 2, [UB] = 3
- };
- static int eptrans_fr[12] = {
- [FR] = UF, [DF] = UL, [FL] = UB, [UF] = UR,
- [BR] = DF, [DB] = DL, [BL] = DB, [UB] = DR,
- [UR] = FR, [DR] = FL, [DL] = BL, [UL] = BR
- };
- static int eptrans_rd[12] = {
- [DR] = UF, [FR] = UL, [UR] = UB, [BR] = UR,
- [DL] = DF, [FL] = DL, [UL] = DB, [BL] = DR,
- [DB] = FR, [DF] = FL, [UF] = BL, [UB] = BR
- };
-
- FstCube ret;
- int i, ce, cs, cm;
- int epe[4], eps[4], epm[4], epose[12], eposs[12], eposm[12];
-
- memset(epose, 0, 12*sizeof(int));
- memset(eposs, 0, 12*sizeof(int));
- memset(eposm, 0, 12*sizeof(int));
-
- for (i = 0, ce = 0; i < 12; i++) {
- switch (edge_slice[ep[i]]) {
- case 0:
- epose[i] = 1;
- epe[ce++] = eind[ep[i]];
- break;
- case 1:
- eposs[eptrans_fr[i]] = eind[ep[i]] + 1;
- break;
- default:
- eposm[eptrans_rd[i]] = eind[ep[i]] + 1;
- break;
- }
- }
-
- for (i = 0, cs = 0, cm = 0; i < 12; i++) {
- if (eposs[i]) {
- eps[cs++] = eposs[i] - 1;
- eposs[i] = 1;
- }
- if (eposm[i]) {
- epm[cm++] = eposm[i] - 1;
- eposm[i] = 1;
- }
- }
-
- ret.uf_eposepe = subset_to_index(epose, 12, 4) * FACTORIAL4 +
- perm_to_index(epe, 4);
- ret.fr_eposepe = subset_to_index(eposs, 12, 4) * FACTORIAL4 +
- perm_to_index(eps, 4);
- ret.rd_eposepe = subset_to_index(eposm, 12, 4) * FACTORIAL4 +
- perm_to_index(epm, 4);
-
- return ret;
-}
-
-FstCube
-fst_inverse(FstCube fst)
-{
- FstCube ret;
- int ep_inv[12];
-
- ep_inv[FR] = fst_where_is_edge_arr[0][FR][fst.uf_eposepe];
- ep_inv[FL] = fst_where_is_edge_arr[0][FL][fst.uf_eposepe];
- ep_inv[BL] = fst_where_is_edge_arr[0][BL][fst.uf_eposepe];
- ep_inv[BR] = fst_where_is_edge_arr[0][BR][fst.uf_eposepe];
-
- ep_inv[UR] = fst_where_is_edge_arr[1][UR][fst.fr_eposepe];
- ep_inv[UL] = fst_where_is_edge_arr[1][UL][fst.fr_eposepe];
- ep_inv[DR] = fst_where_is_edge_arr[1][DR][fst.fr_eposepe];
- ep_inv[DL] = fst_where_is_edge_arr[1][DL][fst.fr_eposepe];
-
- ep_inv[UF] = fst_where_is_edge_arr[2][UF][fst.rd_eposepe];
- ep_inv[UB] = fst_where_is_edge_arr[2][UB][fst.rd_eposepe];
- ep_inv[DF] = fst_where_is_edge_arr[2][DF][fst.rd_eposepe];
- ep_inv[DB] = fst_where_is_edge_arr[2][DB][fst.rd_eposepe];
-
- ret = ep_to_fst_epos(ep_inv);
-
- ret.uf_eofb = ((uint16_t)eo_invtable[0][fst.uf_eofb][fst.uf_eposepe]) |
- ((uint16_t)eo_invtable[1][fst.uf_eofb][fst.fr_eposepe]) |
- ((uint16_t)eo_invtable[2][fst.uf_eofb][fst.rd_eposepe]);
- ret.fr_eofb = ((uint16_t)eo_invtable[0][fst.fr_eofb][fst.uf_eposepe]) |
- ((uint16_t)eo_invtable[1][fst.fr_eofb][fst.fr_eposepe]) |
- ((uint16_t)eo_invtable[2][fst.fr_eofb][fst.rd_eposepe]);
- ret.rd_eofb = ((uint16_t)eo_invtable[0][fst.rd_eofb][fst.uf_eposepe]) |
- ((uint16_t)eo_invtable[1][fst.rd_eofb][fst.fr_eposepe]) |
- ((uint16_t)eo_invtable[2][fst.rd_eofb][fst.rd_eposepe]);
-
- ret.uf_cp = inv_cp[fst.uf_cp];
-
- ret.uf_coud = inv_coud[fst.uf_cp][fst.uf_coud];
- ret.fr_coud = inv_coud[uf_cp_to_fr_cp[fst.uf_cp]][fst.fr_coud];
- ret.rd_coud = inv_coud[uf_cp_to_rd_cp[fst.uf_cp]][fst.rd_coud];
-
- return ret;
-}
-
-FstCube
-fst_move(Move m, FstCube fst)
-{
- FstCube ret;
- Move m_fr, m_rd;
-
- m_fr = transform_move(fr, m);
- m_rd = transform_move(rd, m);
-
- ret.uf_eofb = coord_eofb.mtable[m][fst.uf_eofb];
- ret.uf_eposepe = coord_eposepe.mtable[m][fst.uf_eposepe];
- ret.uf_coud = coord_coud.mtable[m][fst.uf_coud];
- ret.uf_cp = coord_cp.mtable[m][fst.uf_cp];
-
- ret.fr_eofb = coord_eofb.mtable[m_fr][fst.fr_eofb];
- ret.fr_eposepe = coord_eposepe.mtable[m_fr][fst.fr_eposepe];
- ret.fr_coud = coord_coud.mtable[m_fr][fst.fr_coud];
-
- ret.rd_eofb = coord_eofb.mtable[m_rd][fst.rd_eofb];
- ret.rd_eposepe = coord_eposepe.mtable[m_rd][fst.rd_eposepe];
- ret.rd_coud = coord_coud.mtable[m_rd][fst.rd_coud];
-
- return ret;
-}
-
-void
-fst_to_cube(FstCube fst, Cube *cube)
-{
- Cube e, s, m;
- int i;
-
- coord_eposepe.i[0]->to_cube(fst.uf_eposepe, &e);
- coord_eposepe.i[0]->to_cube(fst.fr_eposepe, &s);
- apply_trans(inverse_trans(fr), &s);
- coord_eposepe.i[0]->to_cube(fst.rd_eposepe, &m);
- apply_trans(inverse_trans(rd), &m);
-
- for (i = 0; i < 12; i++) {
- if (edge_slice[e.ep[i]] == 0)
- cube->ep[i] = e.ep[i];
- if (edge_slice[s.ep[i]] == 1)
- cube->ep[i] = s.ep[i];
- if (edge_slice[m.ep[i]] == 2)
- cube->ep[i] = m.ep[i];
- }
-
- coord_eofb.i[0]->to_cube((uint64_t)fst.uf_eofb, cube);
- coord_coud.i[0]->to_cube((uint64_t)fst.uf_coud, cube);
- coord_cp.i[0]->to_cube((uint64_t)fst.uf_cp, cube);
-
- for (i = 0; i < 6; i++)
- cube->xp[i] = i;
-}
-
-void
-init_fst()
-{
- init_trans();
- gen_coord(&coord_eofb);
- gen_coord(&coord_eposepe);
- gen_coord(&coord_coud);
- gen_coord(&coord_cp);
-
- if (!read_fst_tables_file()) {
- fprintf(stderr,
- "Could not load fst_tables, generating them\n");
- init_fst_corner_invtables();
- init_fst_eo_invtables();
- init_fst_where_is_edge();
- if (!write_fst_tables_file())
- fprintf(stderr, "fst_tables could not be written\b");
- }
-}
-
-static void
-init_fst_corner_invtables()
-{
- Cube c, d;
- uint64_t cp, coud;
-
- for (cp = 0; cp < FACTORIAL8; cp++) {
- make_solved_corners(&c);
- coord_cp.i[0]->to_cube(cp, &c);
-
- copy_cube_corners(&c, &d);
- invert_cube_corners(&d);
- inv_cp[cp] = coord_cp.i[0]->index(&d);
-
- for (coud = 0; coud < POW3TO7; coud++) {
- copy_cube_corners(&c, &d);
- coord_coud.i[0]->to_cube(coud, &d);
- invert_cube_corners(&d);
- inv_coud[cp][coud] = coord_coud.i[0]->index(&d);
- }
-
- copy_cube_corners(&c, &d);
- apply_trans(fr, &d);
- uf_cp_to_fr_cp[cp] = coord_cp.i[0]->index(&d);
-
- copy_cube_corners(&c, &d);
- apply_trans(rd, &d);
- uf_cp_to_rd_cp[cp] = coord_cp.i[0]->index(&d);
- }
-}
-
-static void
-init_fst_eo_invtables()
-{
- uint64_t ep, eo;
- Cube c, d;
-
- for (ep = 0; ep < BINOM12ON4 * FACTORIAL4; ep++) {
- make_solved(&c);
- coord_eposepe.i[0]->to_cube(ep, &c);
- for (eo = 0; eo < POW2TO11; eo++) {
- copy_cube_edges(&c, &d);
- coord_eofb.i[0]->to_cube(eo, &d);
- init_fst_eo_update(eo, ep, 0, &d);
-
- apply_trans(inverse_trans(fr), &d);
- coord_eofb.i[0]->to_cube(eo, &d);
- init_fst_eo_update(eo, ep, 1, &d);
-
- copy_cube_edges(&c, &d);
- apply_trans(inverse_trans(rd), &d);
- coord_eofb.i[0]->to_cube(eo, &d);
- init_fst_eo_update(eo, ep, 2, &d);
- }
- }
-}
-
-static void
-init_fst_eo_update(uint64_t eo, uint64_t ep, int s, Cube *d)
-{
- int i;
-
- for (i = 0; i < 12; i++) {
- if (edge_slice[d->ep[i]] == s && d->eo[i] && d->ep[i] != 11)
- eo_invtable[s][eo][ep] |=
- ((uint16_t)1) << ((uint16_t)d->ep[i]);
- }
-}
-
-static void
-init_fst_where_is_edge()
-{
- Cube c, d;
- uint64_t e;
-
- make_solved(&c);
- for (e = 0; e < BINOM12ON4 * FACTORIAL4; e++) {
- coord_eposepe.i[0]->to_cube(e, &c);
-
- copy_cube_edges(&c, &d);
- fst_where_is_edge_arr[0][FR][e] = where_is_edge(FR, &d);
- fst_where_is_edge_arr[0][FL][e] = where_is_edge(FL, &d);
- fst_where_is_edge_arr[0][BL][e] = where_is_edge(BL, &d);
- fst_where_is_edge_arr[0][BR][e] = where_is_edge(BR, &d);
-
- copy_cube_edges(&c, &d);
- apply_trans(inverse_trans(fr), &d);
- fst_where_is_edge_arr[1][UL][e] = where_is_edge(UL, &d);
- fst_where_is_edge_arr[1][UR][e] = where_is_edge(UR, &d);
- fst_where_is_edge_arr[1][DL][e] = where_is_edge(DL, &d);
- fst_where_is_edge_arr[1][DR][e] = where_is_edge(DR, &d);
-
- copy_cube_edges(&c, &d);
- apply_trans(inverse_trans(rd), &d);
- fst_where_is_edge_arr[2][UF][e] = where_is_edge(UF, &d);
- fst_where_is_edge_arr[2][UB][e] = where_is_edge(UB, &d);
- fst_where_is_edge_arr[2][DF][e] = where_is_edge(DF, &d);
- fst_where_is_edge_arr[2][DB][e] = where_is_edge(DB, &d);
- }
-}
-
-static bool
-read_fst_tables_file()
-{
- init_env();
-
- FILE *f;
- char fname[strlen(tabledir)+256];
- uint64_t i, j, r, total;
-
- strcpy(fname, tabledir);
- strcat(fname, "/fst_tables");
-
- if ((f = fopen(fname, "rb")) == NULL)
- return false;
-
- r = 0;
- total = FACTORIAL8*(POW3TO7+3) + 3*BINOM12ON4*FACTORIAL4*(12+POW2TO11);
-
- for (i = 0; i < FACTORIAL8; i++)
- r += fread(inv_coud[i], sizeof(uint16_t), POW3TO7, f);
- r += fread(inv_cp, sizeof(uint16_t), FACTORIAL8, f);
- r += fread(uf_cp_to_fr_cp, sizeof(uint16_t), FACTORIAL8, f);
- r += fread(uf_cp_to_rd_cp, sizeof(uint16_t), FACTORIAL8, f);
- for (i = 0; i < 3; i++)
- for (j = 0; j < POW2TO11; j++)
- r += fread(eo_invtable[i][j],
- sizeof(uint16_t), BINOM12ON4*FACTORIAL4, f);
- for (i = 0; i < 3; i++)
- for (j = 0; j < 12; j++)
- r += fread(fst_where_is_edge_arr[i][j],
- sizeof(uint16_t), BINOM12ON4*FACTORIAL4, f);
-
- fclose(f);
-
- return r == total;
-}
-
-static bool
-write_fst_tables_file()
-{
- init_env();
-
- FILE *f;
- char fname[strlen(tabledir)+256];
- uint64_t i, j, w, total;
-
- strcpy(fname, tabledir);
- strcat(fname, "/fst_tables");
-
- if ((f = fopen(fname, "wb")) == NULL)
- return false;
-
- w = 0;
- total = FACTORIAL8*(POW3TO7+3) + 3*BINOM12ON4*FACTORIAL4*(12+POW2TO11);
-
- for (i = 0; i < FACTORIAL8; i++)
- w += fwrite(inv_coud[i], sizeof(uint16_t), POW3TO7, f);
- w += fwrite(inv_cp, sizeof(uint16_t), FACTORIAL8, f);
- w += fwrite(uf_cp_to_fr_cp, sizeof(uint16_t), FACTORIAL8, f);
- w += fwrite(uf_cp_to_rd_cp, sizeof(uint16_t), FACTORIAL8, f);
- for (i = 0; i < 3; i++)
- for (j = 0; j < POW2TO11; j++)
- w += fwrite(eo_invtable[i][j],
- sizeof(uint16_t), BINOM12ON4*FACTORIAL4, f);
- for (i = 0; i < 3; i++)
- for (j = 0; j < 12; j++)
- w += fwrite(fst_where_is_edge_arr[i][j],
- sizeof(uint16_t), BINOM12ON4*FACTORIAL4, f);
-
- fclose(f);
-
- return w == total;
-}
diff --git a/src/fst.h b/src/fst.h
@@ -1,13 +0,0 @@
-#ifndef FST_H
-#define FST_H
-
-#include "coord.h"
-
-FstCube cube_to_fst(Cube *cube);
-FstCube fst_inverse(FstCube fst);
-FstCube fst_move(Move m, FstCube fst);
-void fst_to_cube(FstCube fst, Cube *cube);
-void init_fst();
-
-#endif
-
diff --git a/src/moves.c b/src/moves.c
@@ -1,18 +1,79 @@
-#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 *****************************************************/
-/* 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(). */
+/* 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
+ }
+};
-static Cube move_array[NMOVES];
+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 char equiv_alg_string[100][NMOVES] = {
[NULLMOVE] = "",
@@ -76,52 +137,89 @@ 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 **********************************************************/
-void
-apply_alg(Alg *alg, Cube *cube)
+Cube
+apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a)
{
- Cube aux;
+ Cube ret = {0};
int i;
- copy_cube(cube, &aux);
- make_solved(cube);
-
for (i = 0; i < alg->len; i++)
if (alg->inv[i])
- apply_move(alg->move[i], cube);
+ ret = a ? apply_move(alg->move[i], ret) :
+ apply_move_cubearray(alg->move[i], ret, f);
- invert_cube(cube);
- compose(&aux, cube);
+ ret = compose_filtered(c, inverse_cube(ret), f);
for (i = 0; i < alg->len; i++)
if (!alg->inv[i])
- apply_move(alg->move[i], cube);
-}
+ ret = a ? apply_move(alg->move[i], ret) :
+ apply_move_cubearray(alg->move[i], ret, f);
-void
-apply_move(Move m, Cube *cube)
-{
- compose(&move_array[m], cube);
+ return ret;
}
-void
-apply_move_centers(Move m, Cube *cube)
+Cube
+apply_alg(Alg *alg, Cube cube)
{
- compose_centers(&move_array[m], cube);
+ return apply_alg_generic(alg, cube, pf_all, true);
}
-void
-apply_move_corners(Move m, Cube *cube)
+Cube
+apply_move(Move m, Cube cube)
{
- compose_corners(&move_array[m], cube);
-}
-
-void
-apply_move_edges(Move m, Cube *cube)
-{
- compose_edges(&move_array[m], 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]
+ };
}
Alg *
@@ -181,27 +279,31 @@ cleanup_aux(Alg *alg, Alg *ret, bool inv)
{
int i, j;
Cube c, d;
- Move m;
+ Move m, mm;
Alg *equiv_alg;
- make_solved(&c);
+ c = (Cube){0};
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++)
- if (equiv_alg->move[j] == U)
- append_move(ret, 3 * c.xp[U_center] + 1, inv);
- else
- apply_move(equiv_alg->move[j], &c);
+ 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);
+ }
+ }
free_alg(equiv_alg);
}
m = NULLMOVE;
- switch (c.xp[F_center]) {
+ switch (what_center_at(c, F_center)) {
case U_center:
m = x3;
break;
@@ -215,7 +317,7 @@ cleanup_aux(Alg *alg, Alg *ret, bool inv)
m = y3;
break;
case B_center:
- if (c.xp[U_center] == U_center)
+ if (what_center_at(c, U_center) == U_center)
m = y2;
else
m = x2;
@@ -223,24 +325,120 @@ cleanup_aux(Alg *alg, Alg *ret, bool inv)
default:
break;
}
-
- make_solved(&d);
- apply_move(m, &d);
+ d = apply_move(m, (Cube){0});
if (m != NULLMOVE)
append_move(ret, m, inv);
m = NULLMOVE;
- if (c.xp[U_center] == d.xp[D_center]) {
+ if (what_center_at(c, U_center) == what_center_at(d, D_center)) {
m = z2;
- } else if (c.xp[U_center] == d.xp[R_center]) {
+ } else if (what_center_at(c, U_center) == what_center_at(d, R_center)) {
m = z3;
- } else if (c.xp[U_center] == d.xp[L_center]) {
+ } else if (what_center_at(c, U_center) == what_center_at(d, 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;
@@ -248,54 +446,101 @@ init_moves() {
return;
initialized = true;
+ Cube c;
+ CubeArray arrs;
+ int i;
+ unsigned int ui;
Move m;
Alg *equiv_alg[NMOVES];
- 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 },
- };
+ init_cube();
+
+ for (i = 0; i < NMOVES; i++)
+ equiv_alg[i] = new_alg(equiv_alg_string[i]);
- move_array[U] = mcu;
- move_array[x] = mcx;
- move_array[y] = mcy;
+ /* 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);
+ }
+
+ if (read_mtables_file())
+ return;
- for (m = 0; m < NMOVES; m++)
- equiv_alg[m] = new_alg(equiv_alg_string[m]);
+ fprintf(stderr, "Cannot load %s, generating it\n", "mtables");
+ /* Initialize transition tables */
for (m = 0; m < NMOVES; m++) {
- 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;
+ 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;
}
}
- for (m = 0; m < NMOVES; m++)
- free_alg(equiv_alg[m]);
+ if (!write_mtables_file())
+ fprintf(stderr, "Error writing mtables\n");
+
+ for (i = 0; i < NMOVES; i++)
+ free_alg(equiv_alg[i]);
}
diff --git a/src/moves.h b/src/moves.h
@@ -5,11 +5,24 @@
#include "cube.h"
#include "env.h"
-void apply_alg(Alg *alg, Cube *cube);
-void apply_move(Move m, Cube *cube);
-void apply_move_centers(Move m, Cube *cube);
-void apply_move_corners(Move m, Cube *cube);
-void apply_move_edges(Move m, Cube *cube);
+/*
+ * 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);
Alg * cleanup(Alg *alg);
void init_moves();
diff --git a/src/movesets.c b/src/movesets.c
@@ -1,194 +0,0 @@
-#define MOVESETS_C
-
-#include "movesets.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 can_append_HTM(Move l2, Move l1, Move m);
-static bool can_append_HTM_cached(Alg *alg, Move m, bool inverse);
-static bool cancel_niss_HTM_cached(Alg *alg);
-static void init_can_append_HTM();
-
-Moveset
-moveset_HTM = {
- .name = "HTM",
- .allowed = allowed_HTM,
- .can_append = can_append_HTM_cached,
- .cancel_niss = cancel_niss_HTM_cached,
-};
-
-Moveset
-moveset_URF = {
- .name = "URF",
- .allowed = allowed_URF,
- .can_append = can_append_HTM_cached,
- .cancel_niss = cancel_niss_HTM_cached,
-};
-
-Moveset
-moveset_eofb = {
- .name = "eofb",
- .allowed = allowed_eofb,
- .can_append = can_append_HTM_cached,
- .cancel_niss = cancel_niss_HTM_cached,
-};
-
-Moveset
-moveset_drud = {
- .name = "drud",
- .allowed = allowed_drud,
- .can_append = can_append_HTM_cached,
- .cancel_niss = cancel_niss_HTM_cached,
-};
-
-Moveset
-moveset_htr = {
- .name = "htr",
- .allowed = allowed_htr,
- .can_append = can_append_HTM_cached,
- .cancel_niss = cancel_niss_HTM_cached,
-};
-
-Moveset *
-all_movesets[] = {
- &moveset_HTM,
- &moveset_URF,
- &moveset_eofb,
- &moveset_drud,
- &moveset_htr,
- NULL
-};
-
-static uint64_t can_append_HTM_mask[NMOVES][NMOVES];
-
-static bool
-allowed_HTM(Move m)
-{
- return m >= U && m <= B3;
-}
-
-static bool
-allowed_URF(Move m)
-{
- Move b = base_move(m);
-
- return b == U || b == R || b == F;
-}
-
-static bool
-allowed_eofb(Move m)
-{
- Move b = base_move(m);
-
- return b == U || b == D || b == R || b == L ||
- ((b == F || b == B) && m == b+1);
-}
-
-static bool
-allowed_drud(Move m)
-{
- Move b = base_move(m);
-
- return b == U || b == D ||
- ((b == R || b == L || b == F || b == B) && m == b + 1);
-}
-
-static bool
-allowed_htr(Move m)
-{
- Move b = base_move(m);
-
- return moveset_HTM.allowed(m) && m == b + 1;
-}
-
-static bool
-can_append_HTM(Move l2, Move l1, Move m)
-{
- bool cancel, cancel_last, cancel_swap;
-
- cancel_last = l1 != NULLMOVE && base_move(l1) == base_move(m);
- cancel_swap = l2 != NULLMOVE && base_move(l2) == base_move(m);
- cancel = cancel_last || (commute(l1, l2) && cancel_swap);
-
- return !cancel;
-}
-
-static bool
-can_append_HTM_cached(Alg *alg, Move m, bool inverse)
-{
- Move *moves, l1, l2;
- uint64_t mbit;
- int n;
-
- if (inverse) {
- moves = alg->move_inverse;
- n = alg->len_inverse;
- } else {
- moves = alg->move_normal;
- n = alg->len_normal;
- }
-
- l1 = n > 0 ? moves[n-1] : NULLMOVE;
- l2 = n > 1 ? moves[n-2] : NULLMOVE;
-
- mbit = ((uint64_t)1) << m;
-
- return can_append_HTM_mask[l2][l1] & mbit;
-}
-
-static bool
-cancel_niss_HTM_cached(Alg *alg)
-{
- Move i1, i2;
- int n;
- bool can_first, can_swap;
-
- n = alg->len_inverse;
- i1 = n > 0 ? alg->move_inverse[n-1] : NULLMOVE;
- i2 = n > 1 ? alg->move_inverse[n-2] : NULLMOVE;
-
- can_first = can_append_HTM_cached(alg, inverse_move(i1), false);
- can_swap = can_append_HTM_cached(alg, inverse_move(i2), false);
-
- return can_first && (!commute(i1, i2) || can_swap);
-}
-
-static void
-init_can_append_HTM()
-{
- Move l2, l1, m;
-
- for (l1 = 0; l1 < NMOVES; l1++)
- for (l2 = 0; l2 < NMOVES; l2++)
- for (m = 0; m < NMOVES; m++)
- if (can_append_HTM(l2, l1, m))
- can_append_HTM_mask[l2][l1]
- |= (((uint64_t)1) << m);
-}
-
-void
-init_moveset(Moveset *ms)
-{
- int j;
- Move m;
-
- for (j = 0, m = U; m < NMOVES; m++)
- if (ms->allowed(m))
- ms->sorted_moves[j++] = m;
- ms->sorted_moves[j] = NULLMOVE;
-
-/* TODO: should be here? maybe just init all movesets together anyway... */
- init_can_append_HTM();
-}
-
-void
-init_movesets()
-{
- int i;
-
- for (i = 0; all_movesets[i] != NULL; i++)
- init_moveset(all_movesets[i]);
-}
diff --git a/src/movesets.h b/src/movesets.h
@@ -1,15 +0,0 @@
-#ifndef MOVESETS_H
-#define MOVESETS_H
-
-#include "alg.h"
-
-void init_moveset(Moveset *);
-void init_movesets();
-
-extern Moveset moveset_HTM;
-extern Moveset moveset_URF;
-extern Moveset moveset_eofb;
-extern Moveset moveset_drud;
-extern Moveset moveset_htr;
-
-#endif
diff --git a/src/pf.c b/src/pf.c
@@ -0,0 +1,95 @@
+#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
@@ -0,0 +1,20 @@
+#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,5 +1,3 @@
-#define PRUNING_C
-
#include "pruning.h"
#define ENTRIES_PER_GROUP (2*sizeof(entry_group_t))
@@ -7,14 +5,106 @@
static int findchunk(PruneData *pd, int nchunks, uint64_t i);
static void genptable_bfs(PruneData *pd, int d, int nt, int nc);
+static void genptable_compress(PruneData *pd);
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, uint64_t ind, int m);
+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 bool read_ptable_file(PruneData *pd);
static bool write_ptable_file(PruneData *pd);
-PruneData *active_pd[256];
+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 *****************************************************************/
int
findchunk(PruneData *pd, int nchunks, uint64_t i)
@@ -27,47 +117,59 @@ findchunk(PruneData *pd, int nchunks, uint64_t i)
return MIN(nchunks-1, (int)(i / chunksize));
}
-PruneData *
+void
+free_pd(PruneData *pd)
+{
+ if (pd->generated)
+ free(pd->ptable);
+
+ pd->generated = false;
+}
+
+void
genptable(PruneData *pd, int nthreads)
{
- int d, nchunks, i, maxv;
- uint64_t oldn;
-
- for (i = 0; active_pd[i] != NULL; i++) {
- if (active_pd[i]->coord == pd->coord &&
- active_pd[i]->moveset == pd->moveset &&
- active_pd[i]->compact == pd->compact)
- return active_pd[i];
- }
+ bool compact;
+ int d, nchunks;
+ uint64_t oldn, sz;
- init_moveset(pd->moveset);
- gen_coord(pd->coord);
+ if (pd->generated)
+ return;
- pd->ptable = malloc(ptablesize(pd) * sizeof(entry_group_t));
+ /* 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))
- goto genptable_done;
+ if (read_ptable_file(pd)) {
+ pd->generated = true;
+ return;
+ }
if (nthreads < 4) {
fprintf(stderr,
"--- Warning ---\n"
"You are using only %d threads to generate the pruning"
- "tables. This can take a while.\n"
+ "tables. This can take a while."
"Unless you did this intentionally, you should re-run"
"this command with `-t 4' or more.\n"
"---------------\n\n", 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, "Generating pt_%s_%s with %d threads\n",
- pd->coord->name, pd->moveset->name, nthreads);
+ fprintf(stderr, "Cannot load %s, generating it with %d threads\n",
+ pd->filename, 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, 0, 0);
+ ptable_update(pd, (Cube){0}, 0);
pd->n = 1;
oldn = 0;
genptable_fixnasty(pd, 0, nthreads);
@@ -76,9 +178,7 @@ genptable(PruneData *pd, int nthreads)
0, pd->n - oldn, pd->n, pd->coord->max);
oldn = pd->n;
pd->count[0] = pd->n;
-
- maxv = pd->compact ? MIN(15, pd->base + 4) : 15;
- for (d = 0; d < maxv && pd->n < pd->coord->max; d++) {
+ for (d = 0; d < 15 && pd->n < pd->coord->max; d++) {
genptable_bfs(pd, d, nthreads, nchunks);
genptable_fixnasty(pd, d+1, nthreads);
fprintf(stderr, "Depth %d done, generated %"
@@ -87,17 +187,14 @@ genptable(PruneData *pd, int nthreads)
pd->count[d+1] = pd->n - oldn;
oldn = pd->n;
}
- if (pd->compact)
- fprintf(stderr, "Compact table, values above "
- "%d are inaccurate.\n", maxv-1);
fprintf(stderr, "Pruning table generated!\n");
-
+
+ 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_pd[i] != NULL; i++);
- return active_pd[i] = pd;
}
static void
@@ -135,6 +232,31 @@ genptable_bfs(PruneData *pd, int d, int nthreads, int nchunks)
}
static void
+genptable_compress(PruneData *pd)
+{
+ int val;
+ uint64_t i, j;
+ entry_group_t mask, v;
+
+ fprintf(stderr, "Compressing table to 2 bits per entry\n");
+
+ for (i = 0; i < pd->coord->max; i += ENTRIES_PER_GROUP_COMPACT) {
+ mask = (entry_group_t)0;
+ for (j = 0; j < ENTRIES_PER_GROUP_COMPACT; j++) {
+ if (i+j >= pd->coord->max)
+ break;
+ val = ptableval_index(pd, i+j) - pd->base;
+ v = (entry_group_t)MIN(3, MAX(0, val));
+ mask |= v << (2*j);
+ }
+ pd->ptable[i/ENTRIES_PER_GROUP_COMPACT] = mask;
+ }
+
+ pd->compact = true;
+ pd->ptable = realloc(pd->ptable, sizeof(entry_group_t)*ptablesize(pd));
+}
+
+static void
genptable_fixnasty(PruneData *pd, int d, int nthreads)
{
int i;
@@ -142,7 +264,7 @@ genptable_fixnasty(PruneData *pd, int d, int nthreads)
ThreadDataGenpt td[nthreads];
pthread_mutex_t *upmtx;
- if (pd->coord->type != SYMCOMP_COORD)
+ if (pd->coord->tfind == NULL)
return;
upmtx = malloc(sizeof(pthread_mutex_t));
@@ -162,12 +284,28 @@ genptable_fixnasty(PruneData *pd, int d, int nthreads)
free(upmtx);
}
+static void
+genptable_setbase(PruneData *pd)
+{
+ int i;
+ uint64_t sum, newsum;
+
+ pd->base = 0;
+ sum = pd->count[0] + pd->count[1] + pd->count[2];
+ for (i = 3; i < 16; i++) {
+ newsum = sum + pd->count[i] - pd->count[i-3];
+ if (newsum > sum)
+ pd->base = i-3;
+ sum = newsum;
+ }
+}
+
static void *
instance_bfs(void *arg)
{
ThreadDataGenpt *td;
uint64_t i, ii, blocksize, rmin, rmax, updated;
- int j, pval, ichunk, oldc, newc;
+ int j, pval, ichunk;
Move *ms;
td = (ThreadDataGenpt *)arg;
@@ -178,43 +316,25 @@ instance_bfs(void *arg)
td->pd->coord->max :
((uint64_t)td->thid + 1) * blocksize;
- if (td->pd->compact) {
- if (td->d <= td->pd->base) {
- oldc = 1;
- newc = 1;
- } else {
- oldc = td->d - td->pd->base;
- newc = td->d - td->pd->base;
- }
- } else {
- oldc = td->d;
- newc = td->d + 1;
- }
-
updated = 0;
for (i = rmin; i < rmax; i++) {
ichunk = findchunk(td->pd, td->nchunks, i);
pthread_mutex_lock(td->mutex[ichunk]);
- pval = ptableval(td->pd, i);
+ pval = ptableval_index(td->pd, i);
pthread_mutex_unlock(td->mutex[ichunk]);
- if (pval == oldc) {
+ if (pval == td->d) {
for (j = 0; ms[j] != NULLMOVE; j++) {
- ii = move_coord(td->pd->coord, ms[j], i, NULL);
+ ii = td->pd->coord->move(ms[j], i);
ichunk = findchunk(td->pd, td->nchunks, ii);
pthread_mutex_lock(td->mutex[ichunk]);
- pval = ptableval(td->pd, ii);
- if (pval > newc) {
- ptable_update(td->pd, ii, newc);
+ pval = ptableval_index(td->pd, ii);
+ if (pval > td->d+1) {
+ ptable_update_index(td->pd,
+ ii, td->d+1);
updated++;
}
pthread_mutex_unlock(td->mutex[ichunk]);
}
- if (td->pd->compact && td->d <= td->pd->base) {
- ichunk = findchunk(td->pd, td->nchunks, i);
- pthread_mutex_lock(td->mutex[ichunk]);
- ptable_update(td->pd, i, 0);
- pthread_mutex_unlock(td->mutex[ichunk]);
- }
}
}
@@ -229,40 +349,30 @@ static void *
instance_fixnasty(void *arg)
{
ThreadDataGenpt *td;
- uint64_t i, ii, blocksize, rmin, rmax, updated, ss, M;
- int j, oldc;
- Trans t;
+ uint64_t i, ii, nb, blocksize, rmin, rmax, updated;
+ int j, n;
+ Trans t, aux[NTRANS];
td = (ThreadDataGenpt *)arg;
-
- /* We know type = SYMCOMP_COORD */
- M = td->pd->coord->base[1]->max;
- blocksize = (td->pd->coord->base[0]->max / td->nthreads) * M;
+ nb = td->pd->coord->max / td->pd->coord->base->max;
+ blocksize = (td->pd->coord->base->max / td->nthreads) * nb;
rmin = ((uint64_t)td->thid) * blocksize;
rmax = td->thid == td->nthreads - 1 ?
td->pd->coord->max :
((uint64_t)td->thid + 1) * blocksize;
- if (td->pd->compact) {
- if (td->d <= td->pd->base)
- oldc = 1;
- else
- oldc = td->d - td->pd->base;
- } else {
- oldc = td->d;
- }
-
updated = 0;
for (i = rmin; i < rmax; i++) {
- if (ptableval(td->pd, i) == oldc) {
- 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)))
+ 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)
continue;
- ii = trans_coord(td->pd->coord, t, i);
- if (ptableval(td->pd, ii) > oldc) {
- ptable_update(td->pd, ii, oldc);
+ ii = td->pd->coord->transform(t, i);
+ if (ptableval_index(td->pd, ii) > td->d) {
+ ptable_update_index(td->pd, ii, td->d);
updated++;
}
}
@@ -281,13 +391,11 @@ print_ptable(PruneData *pd)
{
uint64_t i;
- printf("Table %s_%s\n", pd->coord->name, pd->moveset->name);
-
- if (pd->compact) {
- printf("Compract table with base value: %d\n", pd->base);
- printf("Values above %d are inaccurate.\n", pd->base + 3);
- }
-
+ if (!pd->generated)
+ genptable(pd, 1); /* TODO: set default nthreads somewhere */
+
+ printf("Table %s\n", pd->filename);
+ printf("Base value: %d\n", pd->base);
for (i = 0; i < 16; i++)
printf("%2" PRIu64 "\t%10" PRIu64 "\n", i, pd->count[i]);
}
@@ -303,31 +411,48 @@ ptablesize(PruneData *pd)
}
static void
-ptable_update(PruneData *pd, uint64_t ind, int n)
+ptable_update(PruneData *pd, Cube cube, int n)
{
- int sh;
- entry_group_t f, mask;
- uint64_t i, e, b;
+ ptable_update_index(pd, pd->coord->index(cube), n);
+}
- e = pd->compact ? ENTRIES_PER_GROUP_COMPACT : ENTRIES_PER_GROUP;
- b = pd->compact ? 2 : 4;
- f = pd->compact ? 3 : 15;
+static void
+ptable_update_index(PruneData *pd, uint64_t ind, int n)
+{
+ int sh;
+ entry_group_t mask;
+ uint64_t i;
- sh = b * (ind % e);
- mask = f << sh;
- i = ind / e;
+ sh = 4 * (ind % ENTRIES_PER_GROUP);
+ mask = ((entry_group_t)15) << sh;
+ i = ind/ENTRIES_PER_GROUP;
pd->ptable[i] &= ~mask;
- pd->ptable[i] |= (((entry_group_t)n) & f) << sh;
+ pd->ptable[i] |= (((entry_group_t)n)&15) << sh;
}
int
-ptableval(PruneData *pd, uint64_t ind)
+ptableval(PruneData *pd, Cube cube)
{
- int sh;
- uint64_t e;
+ return ptableval_index(pd, pd->coord->index(cube));
+}
+
+static int
+ptableval_index(PruneData *pd, uint64_t ind)
+{
+ int sh, ret;
+ entry_group_t mask;
+ uint64_t i, 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;
@@ -338,7 +463,19 @@ ptableval(PruneData *pd, uint64_t ind)
sh = (ind % e) * 4;
}
- return (pd->ptable[ind/e] & (m << sh)) >> sh;
+ 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);
+ }
+
+ return ret;
}
static bool
@@ -347,15 +484,13 @@ read_ptable_file(PruneData *pd)
init_env();
FILE *f;
- char fname[strlen(tabledir)+256];
+ char fname[strlen(tabledir)+100];
int i;
uint64_t r;
strcpy(fname, tabledir);
- strcat(fname, "/pt_");
- strcat(fname, pd->coord->name);
- strcat(fname, "_");
- strcat(fname, pd->moveset->name);
+ strcat(fname, "/");
+ strcat(fname, pd->filename);
if ((f = fopen(fname, "rb")) == NULL)
return false;
@@ -376,15 +511,13 @@ write_ptable_file(PruneData *pd)
init_env();
FILE *f;
- char fname[strlen(tabledir)+256];
+ char fname[strlen(tabledir)+100];
int i;
uint64_t w;
strcpy(fname, tabledir);
- strcat(fname, "/pt_");
- strcat(fname, pd->coord->name);
- strcat(fname, "_");
- strcat(fname, pd->moveset->name);
+ strcat(fname, "/");
+ strcat(fname, pd->filename);
if ((f = fopen(fname, "wb")) == NULL)
return false;
diff --git a/src/pruning.h b/src/pruning.h
@@ -1,16 +1,26 @@
#ifndef PRUNING_H
#define PRUNING_H
-#include "coord.h"
-#include "movesets.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[];
void free_pd(PruneData *pd);
-PruneData * genptable(PruneData *data, int nthreads);
+void genptable(PruneData *pd, int nthreads);
void print_ptable(PruneData *pd);
uint64_t ptablesize(PruneData *pd);
-int ptableval(PruneData *pd, uint64_t ind);
-
-extern PruneData *active_pd[256];
+int ptableval(PruneData *pd, Cube cube);
#endif
diff --git a/src/shell.c b/src/shell.c
@@ -1,5 +1,3 @@
-#define SHELL_C
-
#include "shell.h"
static void cleanwhitespaces(char *line);
@@ -9,9 +7,7 @@ bool
checkfiles()
{
/* TODO: add more checks (other files, use checksum...) */
- /* How to check for pruning tables with new method? */
- /* Solution: use list of steps */
- /*
+ FILE *f;
char fname[strlen(tabledir)+100];
int i;
@@ -24,7 +20,6 @@ checkfiles()
else
fclose(f);
}
- */
return true;
}
@@ -142,14 +137,12 @@ launch(bool batchmode)
free(shell_argv);
}
-#ifndef TEST
int
main(int argc, char *argv[])
{
char *closing_cmd[1] = { "freemem" };
init_env();
- init_trans();
if (!checkfiles()) {
fprintf(stderr,
@@ -174,4 +167,3 @@ main(int argc, char *argv[])
return 0;
}
-#endif
diff --git a/src/solve.c b/src/solve.c
@@ -1,122 +1,500 @@
-#define SOLVE_C
-
#include "solve.h"
-void
-dfs(DfsArg *arg, Solver *solver, Threader *threader)
+/* Local functions ***********************************************************/
+
+static bool allowed_next(Move move, DfsArg *arg);
+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_niss(DfsArg *arg);
+static bool dfs_stop(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 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)
+{
+ bool bad, 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;
+
+ return allowed && !bad && order;
+}
+
+static bool
+cancel_niss(DfsArg *arg)
+{
+ Moveset *ms;
+ Move i1, i2;
+ bool p, p1, p2, q, q1, q2;
+
+ if (arg->last1inv == NULLMOVE)
+ return false;
+
+ ms = arg->step->moveset;
+ i1 = inverse_move(arg->last1inv);
+ i2 = inverse_move(arg->last2inv);
+
+ 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);
+
+ 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);
+
+ return p || (commute(i1, i2) && q);
+}
+
+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);
+
+ if (arg->opts->can_niss && !arg->niss && niss_makes_sense(arg))
+ dfs_niss(arg);
+
+ if (sw)
+ invert_branch(arg);
+}
+
+static void
+dfs_branch(DfsArg *arg)
{
int i;
- DfsArg newarg;
- Alg *sol;
Move m;
+ DfsArg *newarg;
- if (arg->current_alg->len > arg->d)
- return;
+ newarg = malloc(sizeof(DfsArg));
+ newarg->ed = malloc(sizeof(EstimateData));
+
+ 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 (solver->is_solved(solver->param, arg->cubedata)) {
-/* TODO: the "all" option should be re-implemented as setting
-validate to null */
-
-/* TODO: we also have to check if cancel with NISS;
-we can't because we have no access to the s->final field
-this should be done by the step's validator? */
- sol = solver->validate_solution(solver->param,arg->current_alg);
- bool accepted = sol != NULL;
- bool too_short = arg->current_alg->len != arg->d;
-
- if (accepted && !too_short) {
-/* TODO: arg->t got lost in refactoring */
-/* transform_alg(inverse_trans(arg->t), sol);*/
- if (arg->opts->verbose)
- print_alg(sol, false);
- threader->append_sol(sol, arg->threaddata);
+ dfs(newarg);
+
+ arg->current_alg->len--;
}
- return;
}
- if (arg->current_alg->len == arg->d)
- return;
+ free(newarg->ed);
+ free(newarg);
+}
+
+static bool
+dfs_check_solved(DfsArg *arg)
+{
+ if (!arg->step->is_done(arg->cube))
+ return false;
-/* TODO: do not alloc */
- newarg.cubedata = solver->alloc_cubedata(solver->param);
- for (i = 0; solver->moveset->sorted_moves[i] != NULLMOVE; i++) {
- m = solver->moveset->sorted_moves[i];
- if (solver->moveset->can_append(arg->current_alg, m, arg->niss)
- && compare_last(arg->current_alg, m, arg->niss) >= 0) {
- append_move(arg->current_alg, m, arg->niss);
-
- solver->copy_cubedata(
- solver->param, arg->cubedata, newarg.cubedata);
- newarg.threaddata = arg->threaddata;
- newarg.opts = arg->opts;
- newarg.d = arg->d;
- newarg.niss = arg->niss;
- newarg.current_alg = arg->current_alg;
- if (!solver->move_check_stop(
- solver->param, &newarg, threader))
- dfs(&newarg, solver, threader);
-
- remove_last_move(arg->current_alg);
+ 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);
+
+ 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->step->final)
+ inplace(unniss, arg->sols->last->alg);
+
+ if (arg->opts->verbose)
+ print_alg(arg->sols->last->alg, false);
+ }
+
+ pthread_mutex_unlock(arg->sols_mutex);
}
}
- solver->free_cubedata(solver->param, newarg.cubedata);
-
- if (arg->opts->can_niss && !arg->niss &&
- solver->niss_makes_sense(
- solver->param, arg->cubedata, arg->current_alg)) {
- solver->invert_cube(solver->param, arg->cubedata);
- arg->niss = true;
- dfs(arg, solver, threader);
+
+ return true;
+}
+
+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);
+}
+
+static bool
+dfs_stop(DfsArg *arg)
+{
+ int lowerbound;
+ bool b;
+
+ lowerbound = arg->step->estimate(arg);
+ if (arg->opts->can_niss && !arg->niss)
+ lowerbound = MIN(1, lowerbound);
+
+ if (arg->current_alg->len + lowerbound > arg->d) {
+ b = true;
+ } else {
+ pthread_mutex_lock(arg->sols_mutex);
+ b = arg->sols->len >= arg->opts->max_solutions;
+ pthread_mutex_unlock(arg->sols_mutex);
}
+
+ 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;
+ Cube c;
+ ThreadDataSolve *td;
+ AlgListNode *node;
+ DfsArg darg;
+
+ td = (ThreadDataSolve *)arg;
+
+ while (1) {
+ b = false;
+
+ pthread_mutex_lock(td->start_mutex);
+ if ((node = *(td->node)) == NULL)
+ b = true;
+ else
+ *(td->node) = (*(td->node))->next;
+ pthread_mutex_unlock(td->start_mutex);
+
+ 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;
+ 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;
+
+ 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)
+{
+ int i;
+ Alg *alg;
+ AlgList *start;
+ AlgListNode **node;
+ pthread_t t[opts->nthreads];
+ ThreadDataSolve td[opts->nthreads];
+ pthread_mutex_t *start_mutex, *sols_mutex;
+
+ node = malloc(sizeof(AlgListNode *));
+ start_mutex = malloc(sizeof(pthread_mutex_t));
+ sols_mutex = malloc(sizeof(pthread_mutex_t));
+
+ start = new_alglist();
+ pthread_mutex_init(start_mutex, NULL);
+ pthread_mutex_init(sols_mutex, NULL);
+
+ for (i = 0; s->moveset->sorted_moves[i] != NULLMOVE; i++) {
+ alg = new_alg("");
+ append_move(alg, s->moveset->sorted_moves[i], false);
+ append_alg(start, alg);
+ if (opts->can_niss) {
+ alg->inv[0] = true;
+ append_alg(start, alg);
+ }
+ free_alg(alg);
+ }
+ *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;
+ pthread_create(&t[i], NULL, instance_thread, &td[i]);
+ }
+
+ for (i = 0; i < opts->nthreads; i++)
+ pthread_join(t[i], NULL);
+
+ free_alglist(start);
+ free(node);
+ free(start_mutex);
+ free(sols_mutex);
+}
+
+static bool
+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);
+}
+
+static bool
+solvestop(int d, int op, SolveOptions *opts, AlgList *sols)
+{
+ bool opt_done, max_moves_exceeded, max_sols_exceeded;
+
+ opt_done = opts->optimal != -1 && op != -1 && d > opts->optimal + op;
+ max_moves_exceeded = d > opts->max_moves;
+ max_sols_exceeded = sols->len >= opts->max_solutions;
+
+ return opt_done || max_moves_exceeded || max_sols_exceeded;
+}
+
+/* Public functions **********************************************************/
+
AlgList *
-solve(Cube *cube, SolveOptions *opts, Solver **solver, Threader *threader)
+solve(Cube cube, Step *step, SolveOptions *opts)
{
- int i, d, optimal;
- bool ready[MAX_SOLVERS], stop, one_ready;
- DfsArg arg[MAX_SOLVERS];
+ bool ready;
+ int i, d, op, nt;
AlgList *sols;
+ Cube c;
+ Trans tt[NTRANS];
+
+ prepare_step(step, opts);
- one_ready = false;
- for (i = 0; solver[i] != NULL; i++) {
- arg[i].cubedata =
- solver[i]->prepare_cube(solver[i]->param, cube);
- arg[i].opts = opts;
- ready[i] = arg[i].cubedata != NULL;
- one_ready = one_ready || ready[i];
+ 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;
}
sols = new_alglist();
- if (!one_ready) {
- fprintf(stderr, "Cube not ready for solving\n");
+
+ if (nt == 0) {
+ fprintf(stderr, "Cube not ready for solving step: ");
+ fprintf(stderr, "%s\n", step->ready_msg);
return sols;
}
- optimal = opts->max_moves;
- stop = false;
- for (d = opts->min_moves; d <= opts->max_moves && !stop; d++) {
+ 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;
+ }
+ }
+ }
+
+ op = -1;
+ for (d = opts->min_moves; !solvestop(d, op, opts, sols); d++) {
if (opts->verbose)
fprintf(stderr, "Searching depth %d\n", d);
- for (i = 0; solver[i] != NULL && !stop; i++) {
- if (!ready[i])
- continue;
+ 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)
+ op = d;
+ }
+ }
- arg[i].d = d;
- threader->dispatch(&arg[i], sols, solver[i], threader);
+ return sols;
+}
- if (sols->len > 0)
- optimal = MIN(optimal, d);
+/* TODO: make more general! */
+Alg *
+solve_2phase(Cube cube, int nthreads)
+{
+ int bestlen, newb;
+ Alg *bestalg, *ret;
+ AlgList *sols1, *sols2;
+ AlgListNode *i;
+ Cube c;
+ SolveOptions opts1, opts2;
+
+ opts1.min_moves = 0;
+ opts1.max_moves = 13;
+ opts1.max_solutions = 20;
+ opts1.nthreads = nthreads;
+ opts1.optimal = 3;
+ opts1.can_niss = false;
+ opts1.verbose = false;
+ opts1.all = true;
- stop = sols->len >= opts->max_solutions;
+ opts2.min_moves = 0;
+ opts2.max_moves = 19;
+ opts2.max_solutions = 1;
+ opts2.nthreads = nthreads;
+ opts2.can_niss = false;
+ opts2.verbose = false;
+
+ /* We skip step1 if it is solved on any axis */
+ if (drany_HTM.is_done(cube)) {
+ sols1 = new_alglist();
+ append_alg(sols1, new_alg(""));
+ } else {
+ sols1 = solve(cube, &drany_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);
+
+ if (sols2->len > 0) {
+ newb = i->alg->len + sols2->first->alg->len;
+ if (newb < bestlen) {
+ bestlen = newb;
+ copy_alg(i->alg, bestalg);
+ compose_alg(bestalg, sols2->first->alg);
+ }
}
- stop = stop ||
- (opts->optimal != -1 && d >= opts->optimal + optimal);
+
+ free_alglist(sols2);
}
-/* TODO: some cleanup (free cubedata) */
-/* TODO: actually, preparation should be done somewhere else */
+ free_alglist(sols1);
- return sols;
+ ret = cleanup(bestalg);
+ free_alg(bestalg);
+
+ return ret;
}
diff --git a/src/solve.h b/src/solve.h
@@ -2,53 +2,10 @@
#define SOLVE_H
#include "moves.h"
+#include "steps.h"
+#include "trans.h"
-#define MAX_SOLVERS 99
-
-typedef struct dfsarg DfsArg;
-typedef struct threader Threader;
-typedef struct solver Solver;
-
-/* TODO: add solver and threader in DfsData, remove from dispatch args and similar */
-
-struct dfsarg {
- void * cubedata;
- void * threaddata;
- SolveOptions * opts;
- int d;
- bool niss;
- Alg * current_alg;
-};
-
-struct threader {
- void (*append_sol)(Alg *, void *);
- void (*dispatch)(DfsArg *, AlgList *, Solver *, Threader *);
- int (*get_nsol)(void *);
-/* TODO: threader should have param, like solver? */
-};
-
-struct solver {
- Moveset * moveset;
- bool (*move_check_stop)(void *, DfsArg *, Threader *);
- Alg * (*validate_solution)(void *, Alg *);
- bool (*niss_makes_sense)(void *, void *, Alg *);
-/* TODO: move param to somewhere where it makes more sense */
- void * param;
-/* TODO: the following should be part of a generic cube description */
-/* TODO: remove alloc? */
-/* TODO: revisit apply_move, maybe apply_alg? or both? */
- void * (*alloc_cubedata)(void *);
- void (*copy_cubedata)(void *, void *, void *);
- void (*free_cubedata)(void *, void *);
- void (*invert_cube)(void *, void *);
- bool (*is_solved)(void *, void *);
- void (*apply_move)(void *, void *, Move);
-/* TODO: remove dependence on Cube, preparation should be done before */
- void * (*prepare_cube)(void *, Cube *);
-};
-
-void dfs(DfsArg *, Solver *, Threader *);
-/* TODO: remove dependence on Cube, preparation should be done before */
-AlgList * solve(Cube *, SolveOptions *, Solver **, Threader *);
+AlgList * solve(Cube cube, Step *step, SolveOptions *opts);
+Alg * solve_2phase(Cube cube, int nthreads);
#endif
diff --git a/src/solver_step.c b/src/solver_step.c
@@ -1,306 +0,0 @@
-#include "solver_step.h"
-
-typedef struct {
- Cube * cube;
- uint64_t * val;
- Trans * t;
-} CubeData;
-
-static void apply_move_cubedata(void *, void *, Move);
-static void init_indexes(Step *, CubeData *);
-static void * prepare_cube(void *, Cube *);
-static bool move_check_stop_eager(void *, DfsArg *, Threader *);
-static bool move_check_stop_lazy(void *, DfsArg *, Threader *);
-static bool move_check_stop_nonsol(void *, DfsArg *, Threader *);
-static bool is_solved_step(void *, void *);
-static Alg * validate_solution(void *, Alg *);
-static void * alloc_cubedata(void *);
-static void copy_cubedata(void *, void *, void *);
-static void free_cubedata(void *, void *);
-static void invert_cubedata(void *, void *);
-static bool niss_makes_sense(void *, void *, Alg *);
-static Solver * new_stepsolver_nocheckstop(Step *step);
-
-static void
-apply_move_cubedata(void *param, void *cubedata, Move m)
-{
- Step *s = (Step *)param;
- CubeData *data = (CubeData *)cubedata;
-
- Trans tt;
- for (int i = 0; i < s->n_coord; i++) {
- Move mm = transform_move(data->t[i], m);
- data->val[i] = move_coord(s->coord[i], mm, data->val[i], &tt);
- data->t[i] = transform_trans(tt, data->t[i]);
- }
-}
-
-static void
-init_indexes(Step *step, CubeData *data)
-{
- int i;
- Cube moved;
- Trans t, tt;
-
- for (i = 0; i < step->n_coord; i++) {
- t = step->coord_trans[i];
- copy_cube(data->cube, &moved);
- apply_trans(t, &moved);
- data->val[i] = index_coord(step->coord[i], &moved, &tt);
- data->t[i] = transform_trans(tt, t);
- }
-}
-
-static void *
-prepare_cube(void *param, Cube *cube)
-{
- int i;
- Step *s;
- CubeData *data;
-
- s = (Step *)param;
-
- for (i = 0; i < s->n_coord; i++) {
- s->pd[i] = malloc(sizeof(PruneData));
- s->pd[i]->moveset = s->moveset;
-/* TODO: check if moveset initialization works fine,
- e.g. if there is a variable to save the initialized status
- or if it gets initialized multiple times */
- init_moveset(s->moveset);
- s->pd[i]->coord = s->coord[i];
- gen_coord(s->coord[i]);
- s->pd[i]->compact = s->pd_compact[i];
- s->pd[i] = genptable(s->pd[i], 4); /* TODO: threads */
- }
-
- data = alloc_cubedata(param);
- data->cube = malloc(sizeof(Cube));
- copy_cube(cube, data->cube);
- init_indexes(s, data);
-
- return data;
-}
-
-static bool
-move_check_stop_eager(void *param, DfsArg *arg, Threader *threader)
-{
- int nsol;
-
- if (move_check_stop_nonsol(param, arg, threader))
- return true;
-
- nsol = threader->get_nsol(arg->threaddata);
- return nsol >= arg->opts->max_solutions;
-}
-
-static bool
-move_check_stop_lazy(void *param, DfsArg *arg, Threader *threader)
-{
- int nsol;
-
- nsol = threader->get_nsol(arg->threaddata);
- if (nsol >= arg->opts->max_solutions)
- return true;
-
- return move_check_stop_nonsol(param, arg, threader);
-}
-
-/* TODO: split in 2 (nissable / non-nissable) and only move cube
- when nissable */
-static bool
-move_check_stop_nonsol(void *param, DfsArg *arg, Threader *threader)
-{
- int i, goal, bound;
- Move mm, lastmove;
- Trans tt = uf;
- CubeData *data;
- Step *s;
-
- s = (Step *)param;
- data = (CubeData *)arg->cubedata;
-
-
- bound = 0;
- goal = arg->d - arg->current_alg->len;
-/* TODO: check if len is 0 */
- lastmove = arg->current_alg->move[arg->current_alg->len-1];
- for (i = 0; i < s->n_coord; i++) {
- mm = transform_move(data->t[i], lastmove);
- data->val[i] = move_coord(s->coord[i], mm, data->val[i], &tt);
- data->t[i] = transform_trans(tt, data->t[i]);
-
- bound = MAX(bound, ptableval(s->pd[i], data->val[i]));
- if (arg->opts->can_niss && !arg->niss)
- bound = MIN(1, bound);
-
- if (bound > goal) {
- return true;
- }
- }
- if (arg->opts->can_niss && !arg->niss)
- apply_move(lastmove, data->cube);
-
- return false;
-}
-
-static bool
-is_solved_step(void *param, void *cubedata)
-{
- int i;
- Step *s;
- CubeData *data;
-
- s = (Step *)param;
- data = (CubeData *)cubedata;
-
- for (i = 0; i < s->n_coord; i++)
- if (data->val[i] != 0)
- return false;
-
- return true;
-}
-
-static Alg *
-validate_solution(void *param, Alg *alg)
-{
- return ((Step *)param)->is_valid(alg);
-}
-
-static void *
-alloc_cubedata(void *param)
-{
- Step *s;
- CubeData *data;
-
- s = (Step *)param;
-
- data = malloc(sizeof(CubeData));
- /* We do not need to allocate a cube */
- data->val = malloc(s->n_coord * sizeof(uint64_t));
- data->t = malloc(s->n_coord * sizeof(Trans));
-
- return data;
-}
-
-static void
-copy_cubedata(void *param, void *src, void *dst)
-{
- int i;
- Step *s;
- CubeData *newdata, *olddata;
-
- s = (Step *)param;
- olddata = (CubeData *)src;
- newdata = (CubeData *)dst;
-
-/* TODO: do not copy if not nissable */
- newdata->cube = malloc(sizeof(Cube));
- copy_cube(olddata->cube, newdata->cube);
- for (i = 0; i < s->n_coord; i++) {
- newdata->val[i] = olddata->val[i];
- newdata->t[i] = olddata->t[i];
- }
-}
-
-static void
-free_cubedata(void *param, void *cubedata)
-{
- CubeData *data;
-
- data = (CubeData *)cubedata;
-
- free(data->t);
- free(data->val);
- free(data->cube);
- free(data);
-}
-
-static void
-invert_cubedata(void *param, void *cubedata)
-{
- Step *s;
- CubeData *data;
-
- s = (Step *)param;
- data = (CubeData *)cubedata;
-
- invert_cube(data->cube);
- init_indexes(s, data);
-}
-
-static bool
-niss_makes_sense(void *param, void *cubedata, Alg *alg)
-{
- Step *s;
- CubeData *data;
-
- s = (Step *)param;
- data = (CubeData *)cubedata;
-
- if (s->final)
- return false;
-
- if (alg->len_normal == 0)
- return true;
-
- Move m = inverse_move(alg->move_normal[alg->len_normal-1]);
- for (int i = 0; i < s->n_coord; i++) {
- Move mm = transform_move(data->t[i], m);
- uint64_t u = move_coord(s->coord[i], mm, 0, NULL);
- if (ptableval(s->pd[i], u) > 0)
- return true;
- }
-
- return false;
-}
-
-static Solver *
-new_stepsolver_nocheckstop(Step *step)
-{
- Solver *solver;
-
- solver = malloc(sizeof(Solver));
-
- solver->moveset = step->moveset;
- solver->param = step;
-
- solver->apply_move = apply_move_cubedata;
- solver->prepare_cube = prepare_cube;
- solver->is_solved = is_solved_step;
- solver->validate_solution = validate_solution;
- solver->alloc_cubedata = alloc_cubedata;
- solver->copy_cubedata = copy_cubedata;
- solver->free_cubedata = free_cubedata;
- solver->invert_cube = invert_cubedata;
- solver->niss_makes_sense = niss_makes_sense;
-
- return solver;
-}
-
-Solver *
-new_stepsolver_eager(Step *step)
-{
- Solver *solver;
-
- solver = new_stepsolver_nocheckstop(step);
- solver->move_check_stop = move_check_stop_eager;
-
- return solver;
-}
-
-Solver *
-new_stepsolver_lazy(Step *step)
-{
- Solver *solver;
-
- solver = new_stepsolver_nocheckstop(step);
- solver->move_check_stop = move_check_stop_lazy;
-
- return solver;
-}
-
-void
-free_stepsolver(Solver *solver)
-{
- free(solver);
-}
diff --git a/src/solver_step.h b/src/solver_step.h
@@ -1,12 +0,0 @@
-#ifndef SOLVER_STEP_H
-#define SOLVER_STEP_H
-
-#include "cube.h"
-#include "solve.h"
-#include "steps.h"
-
-Solver *new_stepsolver_eager(Step *);
-Solver *new_stepsolver_lazy(Step *);
-void free_stepsolver(Solver *);
-
-#endif
diff --git a/src/steps.c b/src/steps.c
@@ -1,117 +1,1376 @@
-#define STEPS_C
-
#include "steps.h"
-/* TODO: change all checkers to use coordinates! */
+#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,
+
+ .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,
-bool
-check_centers(Cube *cube)
+ .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)
{
- int i;
+ return cube.cpos == 0;
+}
- for (i = 0; i < 6; i++)
- if (cube->xp[i] != i)
- return false;
+static bool
+check_coud_HTM(Cube cube)
+{
+ return cube.coud == 0;
+}
- return true;
+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;
}
-bool
-check_coud_HTM(Cube *cube)
+static bool
+check_corners_URF(Cube cube)
{
- int i;
+ Cube c;
+ Trans i;
- for (i = 0; i < 8; i++)
- if (cube->co[i] != 0)
- return false;
+ for (i = 0; i < NROTATIONS; i++) {
+ c = apply_alg(rotation_alg(i), cube);
+ if (c.cp && c.coud)
+ return true;
+ }
- return true;
+ return false;
}
-bool
-check_coud_URF(Cube *cube)
+static bool
+check_corners_HTM(Cube cube)
{
- Cube c2, c3;
+ return cube.cp == 0 && cube.coud == 0;
+}
- copy_cube(cube, &c2);
- copy_cube(cube, &c3);
+static bool
+check_cornershtr(Cube cube)
+{
+ return coord_cornershtr.index(cube) == 0;
+}
- apply_move(z, &c2);
- apply_move(x, &c3);
+static bool
+check_eofb(Cube cube)
+{
+ return cube.eofb == 0;
+}
- return check_coud_HTM(cube) ||
- check_coud_HTM(&c2) ||
- check_coud_HTM(&c3);
+static bool
+check_drud(Cube cube)
+{
+ return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0;
}
-bool
-check_cp_HTM(Cube *cube)
+static bool
+check_htr(Cube cube)
{
- int i;
+ return check_drud(cube) && coord_htr_drud.index(cube) == 0;
+}
- for (i = 0; i < 8; i++)
- if (cube->cp[i] != i)
- return false;
+static int
+estimate_eofb_HTM(DfsArg *arg)
+{
+ return ptableval(&pd_eofb_HTM, arg->cube);
+}
- return true;
+static int
+estimate_coud_HTM(DfsArg *arg)
+{
+ return ptableval(&pd_coud_HTM, arg->cube);
}
-bool
-check_corners_HTM(Cube *cube)
+static int
+estimate_coud_URF(DfsArg *arg)
{
- return check_coud_HTM(cube) && check_cp_HTM(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;
+
+ return MIN(ud, MIN(rl, fb));
}
-bool
-check_corners_URF(Cube *cube)
+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);
+}
+
+static int
+estimate_cornershtr_URF(DfsArg *arg)
+{
+ /* 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++) {
- copy_cube(cube, &c);
- apply_alg(rotation_alg(i), &c);
- if (check_corners_HTM(&c))
- return true;
+ arg->cube = apply_alg(rotation_alg(i), c);
+ ret = MIN(ret, estimate_cornershtr_HTM(arg));
}
- return false;
+ arg->cube = c;
+
+ return ret;
}
-bool
-check_cornershtr(Cube *cube)
+static int
+estimate_corners_URF(DfsArg *arg)
{
- /* TODO (use coord) */
- return true;
+ /* 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));
+ }
+
+ arg->cube = c;
+
+ return ret;
}
-bool
-check_eofb(Cube *cube)
+static int
+estimate_drud_HTM(DfsArg *arg)
{
- /* TODO (use coord) */
- return true;
+ return ptableval(&pd_drud_sym16_HTM, arg->cube);
}
-bool
-check_drud(Cube *cube)
+static int
+estimate_drud_eofb(DfsArg *arg)
{
- /* TODO (use coord) */
- return true;
+ return ptableval(&pd_drud_eofb, arg->cube);
}
-bool
-check_htr(Cube *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);
+}
+
+static int
+estimate_nxopt31_HTM(DfsArg *arg)
+{
+ return estimate_nxoptlike(arg, &pd_nxopt31_HTM);
+}
+
+/* TODO: also use generic procedure for this */
+static int
+estimate_light_HTM(DfsArg *arg)
+{
+ int target, ret;
+ Cube aux;
+
+ static const uint64_t udmask = (1<<U) | (1<<U2) | (1<<U3) |
+ (1<<D) | (1<<D2) | (1<<D3);
+ static const uint64_t rlmask = (1<<R) | (1<<R2) | (1<<R3) |
+ (1<<L) | (1<<L2) | (1<<L3);
+ static const uint64_t fbmask = (1<<F) | (1<<F2) | (1<<F3) |
+ (1<<B) | (1<<B2) | (1<<B3);
+ static const uint64_t htmask = (1<<U2) | (1<<D2) |
+ (1<<R2) | (1<<L2) |
+ (1<<F2) | (1<<B2);
+
+ ret = -1;
+ target = arg->d - arg->current_alg->len;
+ arg->inverse = (Cube){0};
+ arg->badmovesinv = 0;
+ arg->badmoves = 0;
+
+ /* Corners */
+ arg->ed->corners = ptableval(&pd_corners_HTM, arg->cube);
+ UPDATECHECKSTOP(ret, arg->ed->corners, target);
+
+ /* Normal probing */
+ arg->ed->normal_ud = ptableval(&pd_drud_sym16_HTM, arg->cube);
+ UPDATECHECKSTOP(ret, arg->ed->normal_ud, target);
+ aux = apply_trans(fd, arg->cube);
+ arg->ed->normal_fb = ptableval(&pd_drud_sym16_HTM, aux);
+ UPDATECHECKSTOP(ret, arg->ed->normal_fb, target);
+ aux = apply_trans(rf, arg->cube);
+ arg->ed->normal_rl = ptableval(&pd_drud_sym16_HTM, aux);
+ UPDATECHECKSTOP(ret, arg->ed->normal_rl, target);
+
+ /* If ret == 0, it's solved (corners + triple slice solved) */
+ if (ret == 0)
+ return 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;
+}
+
+static int
+estimate_nxoptlike(DfsArg *arg, PruneData *pd)
+{
+ 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;
+}
+
+
+static bool
+always_valid(Alg *alg)
{
- /* TODO (check_drud(cube) and coord_htr_drud == 0) */
return true;
}
-Alg *
+static bool
validate_singlecw_ending(Alg *alg)
{
int i;
bool nor, inv;
- Alg *ret;
Move l2 = NULLMOVE, l1 = NULLMOVE, l2i = NULLMOVE, l1i = NULLMOVE;
for (i = 0; i < alg->len; i++) {
@@ -127,51 +1386,96 @@ validate_singlecw_ending(Alg *alg)
nor = l1 ==base_move(l1) && (!commute(l1, l2) ||l2 ==base_move(l2));
inv = l1i==base_move(l1i) && (!commute(l1i,l2i)||l2i==base_move(l2i));
- if (nor && inv) {
- ret = new_alg("");
- copy_alg(alg, ret);
- } else {
- ret = NULL;
- }
+ return nor && inv;
+}
- return ret;
+/* Pre-transformation detectors **********************************************/
+
+static int
+detect_pretrans_eofb(Cube cube, Trans *ret)
+{
+ int i, n;
+ static Trans tt[3] = {uf, ur, fd};
+
+ for (i = 0, n = 0; i < 3; i++)
+ if (check_eofb(apply_trans(tt[i], cube)))
+ ret[n++] = tt[i];
+
+ return n;
+}
+
+static int
+detect_pretrans_drud(Cube cube, Trans *ret)
+{
+ int i, n;
+ static Trans tt[3] = {uf, fr, rd};
+
+ for (i = 0, n = 0; i < 3; i++)
+ if (check_drud(apply_trans(tt[i], cube)))
+ ret[n++] = tt[i];
+
+ return n;
+}
+
+static int
+detect_pretrans_void_3axis(Cube cube, Trans *ret)
+{
+ ret[0] = uf;
+ ret[1] = fr;
+ ret[2] = rd;
+
+ return 3;
}
/* Public functions **********************************************************/
-/*
void
-compute_ind(Step *s, Cube *cube, Movable *ind)
+copy_estimatedata(EstimateData *src, EstimateData *dst)
{
- int i;
- Cube mvd;
- Trans t, tt;
+ 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;
+}
- for (i = 0; i < s->n_coord; i++) {
- t = s->coord_trans[i];
- copy_cube(cube, &mvd);
- apply_trans(t, &mvd);
+void
+invert_estimatedata(EstimateData *ed)
+{
+ swap(&(ed->normal_ud), &(ed->inverse_ud));
+ swap(&(ed->normal_fb), &(ed->inverse_fb));
+ swap(&(ed->normal_rl), &(ed->inverse_rl));
+}
- ind[i].val = index_coord(s->coord[i], &mvd, &tt);
- ind[i].t = transform_trans(tt, t);
- }
+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;
}
-*/
void
-prepare_cs(ChoiceStep *cs, SolveOptions *opts)
-{
- int i, j;
- Step *s;
-
- for (i = 0; cs->step[i] != NULL; i++) {
- s = cs->step[i];
- for (j = 0; j < s->n_coord; j++) {
- s->pd[j] = malloc(sizeof(PruneData));
- s->pd[j]->moveset = s->moveset;
- s->pd[j]->coord = s->coord[j];
- s->pd[j]->compact = s->pd_compact[j];
- s->pd[j] = genptable(s->pd[j], opts->nthreads);
- }
+prepare_step(Step *step, SolveOptions *opts)
+{
+ int i;
+
+ if (step->final && opts->can_niss) {
+ opts->can_niss = false;
+ fprintf(stderr, "Step is final, NISS not used (-n ignored)\n");
+ }
+
+ 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);
}
}
diff --git a/src/steps.h b/src/steps.h
@@ -2,243 +2,16 @@
#define STEPS_H
#include "pruning.h"
-#include "movesets.h"
-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(Step *a, Cube *cube, Movable *ind);*/
-void prepare_cs(ChoiceStep *cs, SolveOptions *opts);
-bool always_valid(Alg *alg);
-Alg * validate_singlecw_ending(Alg *alg);
+extern Step * steps[];
-#ifndef STEPS_C
+/* Two steps used directly by two-phase solver */
+extern Step drany_HTM;
+extern Step dranyfin_DR;
-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 Step step_eofb_HTM;
-extern Step step_drud_HTM;
-extern Step step_drfin_drud;
-
-extern ChoiceStep optimal_HTM;
-extern ChoiceStep eoany_HTM;
-extern ChoiceStep eofb_HTM;
-extern ChoiceStep eorl_HTM;
-extern ChoiceStep eoud_HTM;
-extern ChoiceStep drany_HTM;
-extern ChoiceStep drud_HTM;
-extern ChoiceStep drrl_HTM;
-extern ChoiceStep drfb_HTM;
-extern ChoiceStep dranyfin_DR;
-extern ChoiceStep drudfin_drud;
-extern ChoiceStep drrlfin_drrl;
-extern ChoiceStep drfbfin_drfb;
-
-extern ChoiceStep *csteps[];
-
-#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 after EO ******************/
-/* TODO: eofin_eo (generic), eofbfin_eofb, eorlfin_eorl, eoudfin_eoud */
-
-/* EO steps **************************/
-/* TODO: eoany_HTM (generic), eofb_HTM, eorl_HTM, eoud_HTM */
-
-Step
-step_eofb_HTM = {
- .ready = check_centers,
- .final = false,
- .moveset = &moveset_HTM,
- .n_coord = 1,
- .coord = {&coord_eofb},
- .coord_trans = {uf},
- .is_valid = validate_singlecw_ending,
-};
-ChoiceStep
-eoany_HTM = {
- .shortname = "eo",
- .name = "EO on any axis",
- .step = {&step_eofb_HTM, &step_eofb_HTM, &step_eofb_HTM, NULL},
- .t = {uf, ur, fd},
- .ready_msg = check_centers_msg,
-};
-ChoiceStep
-eofb_HTM = {
- .shortname = "eofb",
- .name = "EO on F/B",
- .step = {&step_eofb_HTM, NULL},
- .t = {uf},
- .ready_msg = check_centers_msg,
-};
-ChoiceStep
-eorl_HTM = {
- .shortname = "eorl",
- .name = "EO on R/L",
- .step = {&step_eofb_HTM, NULL},
- .t = {ur},
- .ready_msg = check_centers_msg,
-};
-ChoiceStep
-eoud_HTM = {
- .shortname = "eoud",
- .name = "EO on U/D",
- .step = {&step_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 */
-
-Step
-step_drud_HTM = {
- .ready = check_centers,
- .final = false,
- .moveset = &moveset_HTM,
- .n_coord = 1,
- .coord = {&coord_drud_sym16},
- .coord_trans = {uf},
- .is_valid = validate_singlecw_ending,
-};
-ChoiceStep
-drany_HTM = {
- .shortname = "dr",
- .name = "DR on any axis",
- .step = {&step_drud_HTM, &step_drud_HTM, &step_drud_HTM, NULL},
- .t = {uf, rf, fd},
- .ready_msg = check_centers_msg,
-};
-ChoiceStep
-drud_HTM = {
- .shortname = "drud",
- .name = "DR on U/D",
- .step = {&step_drud_HTM, NULL},
- .t = {uf},
- .ready_msg = check_centers_msg,
-};
-ChoiceStep
-drrl_HTM = {
- .shortname = "drrl",
- .name = "DR on R/L",
- .step = {&step_drud_HTM, NULL},
- .t = {rf},
- .ready_msg = check_centers_msg,
-};
-ChoiceStep
-drfb_HTM = {
- .shortname = "drfb",
- .name = "DR on F/B",
- .step = {&step_drud_HTM, NULL},
- .t = {fd},
- .ready_msg = check_centers_msg,
-};
-
-/* DR finish steps */
-Step
-step_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},
- .is_valid = NULL,
-};
-ChoiceStep
-dranyfin_DR = {
- .shortname = "drfin",
- .name = "DR finish on any axis without breaking DR",
- .step = {&step_drfin_drud, &step_drfin_drud,
- &step_drfin_drud, NULL},
- .t = {uf, rf, fd},
- .ready_msg = check_dr_msg,
-};
-ChoiceStep
-drudfin_drud = {
- .shortname = "drudfin",
- .name = "DR finis on U/D without breaking DR",
- .step = {&step_drfin_drud, NULL},
- .t = {uf},
- .ready_msg = check_dr_msg,
-};
-ChoiceStep
-drrlfin_drrl = {
- .shortname = "drrlfin",
- .name = "DR finish on R/L without breaking DR",
- .step = {&step_drfin_drud, NULL},
- .t = {rf},
- .ready_msg = check_dr_msg,
-};
-ChoiceStep
-drfbfin_drfb = {
- .shortname = "drfbfin",
- .name = "DR finish on F/B without breaking DR",
- .step = {&step_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 */
-
-ChoiceStep *csteps[] = {
-/* TODO: re-implement optimal
- &optimal_HTM,
-*/
-
- &eoany_HTM, &eofb_HTM, &eorl_HTM, &eoud_HTM,
- &drany_HTM, &drud_HTM, &drrl_HTM, &drfb_HTM,
- &dranyfin_DR, &drudfin_drud, &drrlfin_drrl, &drfbfin_drfb,
-
-NULL
-/* 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
+void copy_estimatedata(EstimateData *s, EstimateData *d);
+void invert_estimatedata(EstimateData *ed);
+void reset_estimatedata(EstimateData *ed);
+void prepare_step(Step *step, SolveOptions *opts);
#endif
diff --git a/src/symcoord.c b/src/symcoord.c
@@ -0,0 +1,687 @@
+#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
@@ -0,0 +1,17 @@
+#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/threader_eager.c b/src/threader_eager.c
@@ -1,163 +0,0 @@
-#include <pthread.h>
-#include "threader_eager.h"
-
-typedef struct {
- AlgList * sols;
- pthread_mutex_t * sols_mutex;
-} ThreadData;
-
-typedef struct {
- DfsArg * arg;
- Solver * solver;
- Threader * threader;
- AlgList * starts;
- AlgListNode ** node;
- pthread_mutex_t * start_mutex;
-} ThreadInitData;
-
-static void append_sol(Alg *, void *);
-static void * instance_thread(void *);
-static void dispatch(DfsArg *, AlgList *, Solver *, Threader *);
-static AlgList * possible_starts(DfsArg *, Solver *);
-static int get_nsol(void *);
-
-Threader threader_eager = {
- .append_sol = append_sol,
- .dispatch = dispatch,
- .get_nsol = get_nsol,
-};
-
-static void
-append_sol(Alg *alg, void *threaddata)
-{
- ThreadData *td = (ThreadData *)threaddata;
-
- pthread_mutex_lock(td->sols_mutex);
- append_alg(td->sols, alg);
- pthread_mutex_unlock(td->sols_mutex);
-}
-
-static AlgList *
-possible_starts(DfsArg *arg, Solver *solver)
-{
- AlgList *ret = new_alglist();
-
- if (solver->is_solved(solver->param, arg->cubedata)) {
- if (arg->opts->min_moves == 0 && arg->d == 0)
- append_sol(new_alg(""), arg->threaddata);
- return ret;
- }
-
- for (int i = 0; solver->moveset->sorted_moves[i] != NULLMOVE; i++) {
- Move m = solver->moveset->sorted_moves[i];
- Alg *alg = new_alg("");
- append_move(alg, m, false);
- append_alg(ret, alg);
- free_alg(alg);
-
-/* TODO: check if step not final */
- if (arg->opts->can_niss) {
- alg = new_alg("");
- append_move(alg, m, true);
- append_alg(ret, alg);
- free_alg(alg);
- }
- }
-
- return ret;
-}
-
-static void *
-instance_thread(void *arg)
-{
- ThreadInitData *tid = (ThreadInitData *)arg;
-
- while (true) {
- pthread_mutex_lock(tid->start_mutex);
- AlgListNode *node = *(tid->node);
- if (node == NULL) {
- pthread_mutex_unlock(tid->start_mutex);
- break;
- }
- *(tid->node) = (*(tid->node))->next;
- pthread_mutex_unlock(tid->start_mutex);
-
-/* TODO: adjust for longer (arbitrarily long?) starting sequences */
- void *data = tid->solver->alloc_cubedata(tid->solver->param);
- tid->solver->copy_cubedata(
- tid->solver->param, tid->arg->cubedata, data);
- bool inv = node->alg->inv[node->alg->len-1];
- if (inv)
- tid->solver->invert_cube(
- tid->solver->param, data);
- tid->solver->apply_move(
- tid->solver->param, data, node->alg->move[0]);
-
- DfsArg newarg;
- newarg.cubedata = data;
- newarg.threaddata = tid->arg->threaddata;
- newarg.opts = tid->arg->opts;
- newarg.d = tid->arg->d;
- newarg.niss = inv;
- newarg.current_alg = new_alg("");
- copy_alg(node->alg, newarg.current_alg);
-
- dfs(&newarg, tid->solver, tid->threader);
-
- tid->solver->free_cubedata(tid->solver->param, data);
- free_alg(newarg.current_alg);
- }
-
- return NULL;
-}
-
-static void
-dispatch(DfsArg *arg, AlgList *sols, Solver *solver, Threader *threader)
-{
- int nthreads = arg->opts->nthreads;
- ThreadInitData tid[nthreads];
- pthread_t t[nthreads];
-
- pthread_mutex_t *sols_mutex = malloc(sizeof(pthread_mutex_t));
- pthread_mutex_init(sols_mutex, NULL);
-
- arg->threaddata = malloc(sizeof(ThreadData));
- ThreadData *td = (ThreadData *)arg->threaddata;
- td->sols = sols;
- td->sols_mutex = sols_mutex;
-
- AlgList *starts = possible_starts(arg, solver);
- AlgListNode *node = starts->first;
- pthread_mutex_t *start_mutex = malloc(sizeof(pthread_mutex_t));
- pthread_mutex_init(start_mutex, NULL);
- for (int i = 0; i < nthreads; i++) {
- tid[i].arg = arg;
- tid[i].solver = solver;
- tid[i].threader = threader;
- tid[i].starts = starts;
- tid[i].node = &node;
- tid[i].start_mutex = start_mutex;
-
- pthread_create(&t[i], NULL, instance_thread, &tid[i]);
- }
-
- for (int i = 0; i < nthreads; i++)
- pthread_join(t[i], NULL);
-
- free(td);
- free(sols_mutex);
- free_alglist(starts);
- free(start_mutex);
-}
-
-static int
-get_nsol(void *threaddata)
-{
- ThreadData *td = (ThreadData *)threaddata;
-
- pthread_mutex_lock(td->sols_mutex);
- int n = td->sols->len;
- pthread_mutex_unlock(td->sols_mutex);
-
- return n;
-}
diff --git a/src/threader_eager.h b/src/threader_eager.h
@@ -1,8 +0,0 @@
-#ifndef THREADER_EAGER_H
-#define THREADER_EAGER_H
-
-#include "solve.h"
-
-extern Threader threader_eager;
-
-#endif
diff --git a/src/threader_single.c b/src/threader_single.c
@@ -1,35 +0,0 @@
-#include "threader_single.h"
-
-static void append_sol(Alg *, void *);
-static void dispatch(DfsArg *, AlgList *, Solver *, Threader *);
-static int get_nsol(void *);
-
-Threader threader_single = {
- .append_sol = append_sol,
- .dispatch = dispatch,
- .get_nsol = get_nsol,
-};
-
-static void
-append_sol(Alg *alg, void *threaddata)
-{
- append_alg((AlgList *)threaddata, alg);
-}
-
-static void
-dispatch(DfsArg *arg, AlgList *sols, Solver *solver, Threader *threader)
-{
- arg->threaddata = sols;
- arg->niss = false;
- arg->current_alg = new_alg("");
-
- dfs(arg, solver, threader);
-
- free_alg(arg->current_alg);
-}
-
-static int
-get_nsol(void *threaddata)
-{
- return ((AlgList *)threaddata)->len;
-}
diff --git a/src/threader_single.h b/src/threader_single.h
@@ -1,8 +0,0 @@
-#ifndef THREADER_SINGLE_H
-#define THREADER_SINGLE_H
-
-#include "solve.h"
-
-extern Threader threader_single;
-
-#endif
diff --git a/src/trans.c b/src/trans.c
@@ -1,23 +1,31 @@
-#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 Cube mirror_cube = {
-.ep = { [UF] = UF, [UL] = UR, [UB] = UB, [UR] = UL,
+static int ep_mirror[12] = {
+ [UF] = UF, [UL] = UR, [UB] = UB, [UR] = UL,
[DF] = DF, [DL] = DR, [DB] = DB, [DR] = DL,
- [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,
+ [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,
[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",
@@ -26,39 +34,176 @@ static char rotation_alg_string[100][NROTATIONS] = {
[bu] = "x3", [br] = "x3 y", [bd] = "x3 y2", [bl] = "x3 y3",
};
-Alg *rotation_alg_arr[NROTATIONS];
-Move moves_ttable[NTRANS][NMOVES];
-Trans trans_ttable[NTRANS][NTRANS];
-Trans trans_itable[NTRANS];
+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];
-/* Public functions **********************************************************/
+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];
-void
-apply_trans(Trans t, Cube *cube)
+/* Local functions implementation ********************************************/
+
+static bool
+read_ttables_file()
{
- Cube aux;
- Alg *inv;
- int i;
+ init_env();
+
+ FILE *f;
+ char fname[strlen(tabledir)+20];
+ int b = sizeof(int);
+ bool r = true;
+ Move m;
- 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;
+ /* 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;
+
+ 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];
}
+ 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)
{
@@ -86,18 +231,23 @@ inverse_trans(Trans t)
return inverse_trans_aux[t];
}
-*/
-
-Trans
-inverse_trans(Trans t)
-{
- return trans_itable[t];
-}
Alg *
-rotation_alg(Trans i)
+rotation_alg(Trans t)
{
- return rotation_alg_arr[i % NROTATIONS];
+ 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 rotation_alg_arr[t % NROTATIONS];
}
void
@@ -105,20 +255,10 @@ transform_alg(Trans t, Alg *alg)
{
int i;
+ /*init_trans();*/
+
for (i = 0; i < alg->len; 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];
+ alg->move[i] = moves_ttable[t][alg->move[i]];
}
void
@@ -128,63 +268,106 @@ init_trans() {
return;
initialized = true;
- int i;
- Alg *nonsym_alg, *nonsym_inv;
- Cube aux, cube;
+ init_moves();
+
+ Cube aux, cube, c[3];
+ CubeArray epcp;
+ int i, eparr[12], eoarr[12], cparr[8], coarr[8];
+ unsigned int ui;
Move mi, move;
- Trans t, u, v;
+ Trans m;
- init_moves();
+ /* 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;
+ }
- for (i = 0; i < NROTATIONS; i++)
- rotation_alg_arr[i] = new_alg(rotation_alg_string[i]);
+ if (read_ttables_file())
+ return;
+
+ fprintf(stderr, "Cannot load %s, generating it\n", "ttables");
- for (t = 0; t < NTRANS; t++) {
+ /* 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;
+
+ cube = rotate_via_compose(m,c[eposs_source[m]],pf_ep);
+ eposs_ttable[m][ui] = cube.eposs;
+
+ 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 (mi = 0; mi < NMOVES; mi++) {
- make_solved(&aux);
- apply_move(mi, &aux);
- apply_trans(t, &aux);
+ /* Old version:
+ *
+ aux = apply_trans(m, apply_move(mi, (Cube){0}));
for (move = 0; move < NMOVES; move++) {
- copy_cube(&aux, &cube);
- apply_move(inverse_move(move), &cube);
- if (is_solved(&cube)) {
- moves_ttable[t][mi] = move;
- break;
- }
+ 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;
}
- }
- }
+ */
- 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;
+ 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;
break;
}
}
}
}
- for (t = 0; t < NTRANS; t++)
- for (u = 0; u < NTRANS; u++)
- trans_ttable[t][u] = trans_itable[trans_ttable[t][u]];
-
- free_alg(nonsym_alg);
- free_alg(nonsym_inv);
+ if (!write_ttables_file())
+ fprintf(stderr, "Error writing ttables\n");
}
diff --git a/src/trans.h b/src/trans.h
@@ -3,30 +3,24 @@
#include "moves.h"
-void apply_trans(Trans t, Cube *cube);
+/*
+ * 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);
Trans inverse_trans(Trans t);
Alg * rotation_alg(Trans i);
-void transform_alg(Trans t, Alg *alg);
-Move transform_move(Trans t, Move m);
-Trans transform_trans(Trans t, Trans m);
+void transform_alg(Trans i, Alg *alg);
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,5 +1,3 @@
-#define UTILS_C
-
#include "utils.h"
void
@@ -161,24 +159,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)
- ret = false;
+ return false;
else
aux[a[i]] = 1;
}
for (i = 0; i < n; i++)
if (!aux[i])
- ret = false;
+ return false;
free(aux);
- return ret;
+
+ return true;
}
bool
@@ -197,7 +195,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++)
@@ -213,7 +211,7 @@ perm_to_index(int *a, int n)
int i, j, c, ret = 0;
if (!is_perm(a, n))
- return factorial(n);
+ return -1;
for (i = 0; i < n; i++) {
c = 0;
diff --git a/tests/alg_tests.c b/tests/alg_tests.c
@@ -1,266 +0,0 @@
-#include "alg_tests.h"
-
-bool testmethod_append_move(void *);
-bool testmethod_new_alg(void *);
-/*
-bool testmethod_compose_alg(void *);
-bool testmethod_inverse_alg(void *);
-bool testmethod_on_inverse(void *);
-bool testmethod_unniss(void *);
-*/
-
-typedef struct {
- Move *move;
- bool *inv;
- int len;
- Move m;
- bool inverse;
-} append_move_t;
-
-Move m_app1[] = {F, x, D3};
-bool i_app1[] = {true, false, false};
-append_move_t append_move_case1 = {
- .move = m_app1,
- .inv = i_app1,
- .len = 3,
- .m = L3,
- .inverse = false,
-};
-
-Move m_app2[] = {S, U, x2, M2};
-bool i_app2[] = {true, false, true, true};
-append_move_t append_move_case2 = {
- .move = m_app2,
- .inv = i_app2,
- .len = 4,
- .m = R,
- .inverse = true,
-};
-
-Move m_app3[] = {U, U, U, U, U};
-bool i_app3[] = {false, false, false, false, false};
-append_move_t append_move_case3 = {
- .move = m_app3,
- .inv = i_app3,
- .len = 5,
- .m = U,
- .inverse = false,
-};
-
-append_move_t *append_move_cases[] = {
- &append_move_case1,
- &append_move_case2,
- &append_move_case3,
-};
-
-Test test_append_move = {
- .name = "Appending a move to and alg",
- .t = testmethod_append_move,
- .cases = (void **)append_move_cases,
-};
-
-typedef struct {
- char *str;
- Move *move;
- bool *inv;
- int len;
- Move *move_normal;
- int len_normal;
- Move *move_inverse;
- int len_inverse;
-} new_alg_t;
-
-/* Alg F U B' (L3 D) x M (S) y3 */
-Move m_new1[] = {F, U, B3, L3, D, x, M, S, y3};
-Move mn_new1[] = {F, U, B3, x, M, y3};
-Move mi_new1[] = {L3, D, S};
-bool i_new1[] = {false, false, false, true, true, false, false, true, false};
-new_alg_t new_alg_case1 = {
- .str = "F U B' (L3 D) x M (S) y3",
- .move = m_new1,
- .inv = i_new1,
- .len = 9,
- .move_normal = mn_new1,
- .len_normal = 6,
- .move_inverse = mi_new1,
- .len_inverse = 3,
-};
-new_alg_t *new_alg_cases[] = {&new_alg_case1};
-
-Test test_new_alg = {
- .name = "Initializing an alg from a string",
- .t = testmethod_new_alg,
- .cases = (void **)new_alg_cases,
-};
-
-Test *alg_all_tests[] = {
- &test_append_move,
- &test_new_alg,
-/*
- &test_append_alg,
- &test_compose_alg,
- &test_inverse_alg,
- &test_on_inverse,
- &test_unniss,
-*/
- NULL
-};
-TestSuite alg_suite = {
- .setup = NULL,
- .tests = alg_all_tests,
- .teardown = NULL,
-};
-
-TestSuite *alg_suites[] = {
- &alg_suite,
- NULL
-};
-
-bool
-testmethod_append_move(void *a)
-{
- append_move_t *b = (append_move_t *)a;
- int li, ln;
- Alg *alg;
-
- /* Small to test reallocation */
- alg = malloc(sizeof(Alg));
- alg->allocated = 5;
- alg->move = malloc(alg->allocated * sizeof(Move));
- alg->inv = malloc(alg->allocated * sizeof(bool));
- alg->len = b->len;
- memcpy(alg->move, b->move, alg->len * sizeof(Move));
- memcpy(alg->inv, b->inv, alg->len * sizeof(bool));
- alg->move_normal = malloc(alg->allocated * sizeof(Move));
- alg->move_inverse = malloc(alg->allocated * sizeof(Move));
-
- li = ln = 0;
- for (int i = 0; i < alg->len; i++) {
- if (alg->inv[i])
- alg->move_inverse[li++] = alg->move[i];
- else
- alg->move_normal[ln++] = alg->move[i];
- }
- alg->len_inverse = li;
- alg->len_normal = ln;
-
- append_move(alg, b->m, b->inverse);
-
- if (alg->len != b->len + 1) {
- printf("Alg has wrong len (%d instead of %d)\n",
- alg->len, b->len + 1);
- goto append_move_fail;
- }
- if (alg->move[alg->len-1] != b->m) {
- printf("Wrong last move (%s instead of %s)\n",
- move_string(alg->move[alg->len-1]),
- move_string(b->m));
- goto append_move_fail;
- }
- if (alg->inv[alg->len-1] != b->inverse) {
- printf("Wrong inverse flag for last move "
- "(%s instead of %s)\n",
- b->inverse ? "normal" : "inverse",
- b->inverse ? "inverse" : "normal");
- goto append_move_fail;
- }
- if (b->inverse) {
- if (alg->len_inverse != li + 1 ||
- alg->len_normal != ln) {
- printf("%d moves on normal (should be %d)"
- " and %d on inverse (should be %d)\n",
- alg->len_normal, ln,
- alg->len_inverse, li + 1);
- goto append_move_fail;
- }
- if (alg->move_inverse[alg->len_inverse-1] != b->m) {
- printf("Wrong move on inverse (%s instead of %s)\n",
- move_string(alg->move_inverse[alg->len-1]),
- move_string(b->m));
- goto append_move_fail;
- }
- } else {
- if (alg->len_inverse != li ||
- alg->len_normal != ln + 1) {
- printf("%d moves on normal (should be %d)"
- " and %d on inverse (should be %d)\n",
- alg->len_normal, ln,
- alg->len_inverse, li + 1);
- goto append_move_fail;
- }
- if (alg->move_normal[alg->len_normal-1] != b->m) {
- printf("Wrong move on normal (%s instead of %s)\n",
- move_string(alg->move_normal[alg->len-1]),
- move_string(b->m));
- goto append_move_fail;
- }
- }
-
- free(alg);
- return true;
-
-append_move_fail:
- free(alg);
- return false;
-}
-
-bool
-testmethod_new_alg(void *a)
-{
- new_alg_t *b = (new_alg_t *)a;
- Alg *alg = new_alg(b->str);
-
- if (alg->len != b->len) {
- printf("Algs have different length (%d instead of %d)\n",
- alg->len, b->len);
- goto new_alg_fail;
- }
-
- for (int i = 0; i < alg->len; i++) {
- if (alg->move[i] != b->move[i] || alg->inv[i] != b->inv[i]) {
- printf("Algs differ on move %d\n", i);
- printf("Expected: %s\nActual: ", b->str);
- print_alg(alg, false);
- goto new_alg_fail;
- }
- }
-
- if (alg->len_normal != b->len_normal) {
- printf("Algs have different number of moves on normal"
- " (%d instead of %d)\n",
- alg->len_normal, b->len_normal);
- goto new_alg_fail;
- }
- for (int i = 0; i < alg->len_normal; i++) {
- if (alg->move_normal[i] != b->move_normal[i]) {
- printf("Algs have different move %d on normal"
- " (%s instead of %s)\n", i,
- move_string(alg->move_normal[i]),
- move_string(b->move_normal[i]));
- goto new_alg_fail;
- }
- }
-
- if (alg->len_inverse != b->len_inverse) {
- printf("Algs have different number of moves on inverse"
- " (%d instead of %d)\n",
- alg->len_inverse, b->len_inverse);
- goto new_alg_fail;
- }
- for (int i = 0; i < alg->len_inverse; i++) {
- if (alg->move_inverse[i] != b->move_inverse[i]) {
- printf("Algs have different move %d on inverse:\n"
- " (%s instead of %s)\n", i,
- move_string(alg->move_inverse[i]),
- move_string(b->move_inverse[i]));
- goto new_alg_fail;
- }
- }
-
- free(alg);
- return true;
-
-new_alg_fail:
- free(alg);
- return false;
-}
diff --git a/tests/alg_tests.h b/tests/alg_tests.h
@@ -1,21 +0,0 @@
-#ifndef ALG_TESTS_H
-#define ALG_TESTS_H
-
-#include "../src/alg.h"
-#include "test_common.h"
-
-extern Test test_append_move;
-extern Test test_new_alg;
-/*
-extern Test remove_last_move;
-extern Test test_compose_alg;
-extern Test test_inverse_alg;
-extern Test test_on_inverse;
-extern Test test_unniss;
-*/
-
-extern TestSuite alg_suite;
-
-extern TestSuite *alg_suites[];
-
-#endif
diff --git a/tests/coord_tests.c b/tests/coord_tests.c
@@ -1,50 +0,0 @@
-#include "coord_tests.h"
-
-bool testmethod_indexes_consistent(void *);
-
-Test test_indexes_consistent = {
- .name = "Consitency of index and anti-index",
- .t = testmethod_indexes_consistent,
- .cases = (void **)all_coordinates,
-};
-Test *coord_pre_init[] = {
- &test_indexes_consistent,
- NULL
-};
-TestSuite coord_pre_init_suite = {
- .setup = NULL,
- .tests = coord_pre_init,
- .teardown = NULL,
-};
-
-TestSuite *coord_suites[] = {
- &coord_pre_init_suite,
- NULL
-};
-
-bool
-testmethod_indexes_consistent(void *a)
-{
- uint64_t ui, uj;
- Cube c;
- Coordinate *coord;
-
- coord = (Coordinate *)a;
-
- if (coord->type != COMP_COORD)
- return true; /* Not applicable */
-
- 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, "Error with coordinate %s: "
- "%" PRIu64 " != %" PRIu64 "\n",
- coord->name, uj, ui);
- return false;
- }
- }
-
- return true;
-}
diff --git a/tests/coord_tests.h b/tests/coord_tests.h
@@ -1,13 +0,0 @@
-#ifndef COORD_TESTS_H
-#define COORD_TESTS_H
-
-#include "../src/coord.h"
-#include "test_common.h"
-
-extern Test test_indexes_consistent;
-
-extern TestSuite coord_pre_init_suite;
-
-extern TestSuite *coord_suites[];
-
-#endif
diff --git a/tests/fst_tests.c b/tests/fst_tests.c
@@ -1,184 +0,0 @@
-#include "fst_tests.h"
-
-static bool testmethod_fst_is_consistent(void *);
-static bool testmethod_cube_to_fst_to_cube(void *);
-static bool testmethod_fst_move(void *);
-static bool testmethod_fst_inverse(void *);
-static bool check_equal_and_log(Cube *, Cube *);
-static void void_to_cube(void *, Cube *);
-
-char *algs[] = {
- "",
- "U", "U2", "U'", "D", "D2", "D'", "R", "R2", "R'",
- "L", "L2", "L'", "F", "F2", "F'", "B", "B2", "B'",
- "U2 R2 U2 R2 U2",
- "U2 F2 R2 B2 U2 D2 F2 L2 B2",
- "RUR'URU2R'",
- "L2 D R U2 B2 L",
- "R'U'F",
- "F2 U' R2 D' B2 D2 R2 D2 R2 U' F L' U' R B F2 R B' D2",
- "D L2 F2 R2 D R2 U L2 U' B2 D L' F2 U2 B' L D' U' R' B2 F2",
- "F' L2 F' D' R F2 L U L' D2 R2 F2 D2 R2 B' L2 B2 U2 F D2 B",
- NULL,
-};
-
-Test test_fst_is_consistent = {
- .name = "Consitency of FST (converted from cube)",
- .t = testmethod_fst_is_consistent,
- .cases = (void **)algs,
-};
-Test test_cube_to_fst_to_cube = {
- .name = "Cube to FST to cube",
- .t = testmethod_cube_to_fst_to_cube,
- .cases = (void **)algs,
-};
-Test test_fst_move = {
- .name = "FST move",
- .t = testmethod_fst_move,
- .cases = (void **)algs,
-};
-Test test_fst_inverse = {
- .name = "FST inverse",
- .t = testmethod_fst_inverse,
- .cases = (void **)algs,
-};
-
-Test *fst_pre_init[] = {
- &test_fst_is_consistent,
- &test_cube_to_fst_to_cube,
- NULL
-};
-TestSuite fst_pre_init_suite = {
- .setup = NULL,
- .tests = fst_pre_init,
- .teardown = NULL,
-};
-
-Test *fst_post_init[] = {
- &test_fst_move,
- &test_fst_inverse,
- NULL
-};
-TestSuite fst_post_init_suite = {
- .setup = init_fst,
- .tests = fst_post_init,
- .teardown = NULL,
-};
-
-TestSuite *fst_suites[] = {
- &fst_pre_init_suite,
- &fst_post_init_suite,
- NULL
-};
-
-static bool
-check_equal_and_log(Cube *c, Cube *d)
-{
- bool ret = equal(c, d);
-
- if (!ret) {
- printf("\n");
- printf("These cubes should be equal, but are not:\n\n");
- print_cube(c);
- printf("\n");
- print_cube(d);
- printf("\n");
- }
-
- return ret;
-}
-
-static void
-void_to_cube(void *a, Cube *c)
-{
- char *algstr;
- Alg *alg;
-
- algstr = (char *)a;
- alg = new_alg(algstr);
- make_solved(c);
- apply_alg(alg, c);
- free_alg(alg);
-}
-
-bool
-testmethod_fst_is_consistent(void *a)
-{
- FstCube fst_uf, fst_fr, fst_rd;
- Cube c, c_fr, c_rd;
- bool consistent_fr, consistent_rd, result;
-
- void_to_cube(a, &c);
- copy_cube(&c, &c_fr);
- apply_trans(fr, &c_fr);
-
- copy_cube(&c, &c_rd);
- apply_trans(rd, &c_rd);
-
- fst_uf = cube_to_fst(&c);
- fst_fr = cube_to_fst(&c_fr);
- fst_rd = cube_to_fst(&c_rd);
-
- consistent_fr = fst_uf.fr_eofb == fst_fr.uf_eofb &&
- fst_uf.fr_eposepe == fst_fr.uf_eposepe &&
- fst_uf.fr_coud == fst_fr.uf_coud;
-
- consistent_rd = fst_uf.rd_eofb == fst_rd.uf_eofb &&
- fst_uf.rd_eposepe == fst_rd.uf_eposepe &&
- fst_uf.rd_coud == fst_rd.uf_coud;
-
- result = consistent_fr && consistent_rd;
-
- if (!result)
- printf("\nFailed with alg %s\n", (char *)a);
-
- return result;
-}
-
-bool
-testmethod_cube_to_fst_to_cube(void *a)
-{
- Cube c, d;
- FstCube fst;
-
- void_to_cube(a, &c);
- fst = cube_to_fst(&c);
- fst_to_cube(fst, &d);
-
- return check_equal_and_log(&c, &d);;
-}
-
-bool
-testmethod_fst_move(void *a)
-{
- int i;
- Alg *alg;
- Cube c, d;
- FstCube fst;
-
- void_to_cube(a, &c);
- alg = new_alg((char *)a);
- make_solved(&d);
- fst = cube_to_fst(&d);
-
- for (i = 0; i < alg->len; i++)
- fst = fst_move(alg->move[i], fst);
-
- fst_to_cube(fst, &d);
-
- free_alg(alg);
-
- return check_equal_and_log(&c, &d);
-}
-
-bool
-testmethod_fst_inverse(void *a)
-{
- Cube c, d;
-
- void_to_cube(a, &c);
- fst_to_cube(fst_inverse(cube_to_fst(&c)), &d);
- invert_cube(&c);
-
- return check_equal_and_log(&c, &d);
-}
diff --git a/tests/fst_tests.h b/tests/fst_tests.h
@@ -1,19 +0,0 @@
-#ifndef FST_TESTS_H
-#define FST_TESTS_H
-
-#include "../src/fst.h"
-#include "test_common.h"
-
-extern char *algs[];
-
-extern Test test_fst_is_consistent;
-extern Test test_cube_to_fst_to_cube;
-extern Test test_fst_move;
-extern Test test_fst_inverse;
-
-extern TestSuite fst_pre_init_suite;
-extern TestSuite fst_post_init_suite;
-
-extern TestSuite *fst_suites[];
-
-#endif
diff --git a/tests/test.c b/tests/test.c
@@ -1,85 +0,0 @@
-#include <stdio.h>
-
-#include "alg_tests.h"
-#include "coord_tests.h"
-#include "fst_tests.h"
-
-static bool run_test(Test *);
-static bool run_suite(TestSuite *);
-
-static bool
-run_test(Test *test)
-{
- int i;
-
- printf("Running test %s...", test->name);
- for (i = 0; test->cases[i] != NULL; i++) {
- if (!test->t(test->cases[i])) {
- printf("FAILED!\n");
- return false;
- }
- }
-
- printf("OK\n");
- return true;
-}
-
-static bool
-run_suite(TestSuite *suite)
-{
- int i;
-
- if (suite->setup != NULL)
- suite->setup();
- for (i = 0; suite->tests[i] != NULL; i++)
- if(!run_test(suite->tests[i]))
- return false;
- if (suite->teardown != NULL)
- suite->teardown();
-
- return true;
-}
-
-static bool
-module_in_args(char *module, int argc, char *argv[])
-{
- for (int i = 0; i < argc; i++)
- if (!strcmp(module, argv[i]))
- return true;
- return false;
-}
-
-int main(int argc, char *argv[]) {
- /* TODO: init should be in testsuites */
- init_env();
- init_trans();
- /**************************************/
-
- TestModule alg = { .name = "alg", .suites = alg_suites };
- TestModule fst = { .name = "fst", .suites = fst_suites };
- TestModule coord = { .name = "coord", .suites = coord_suites };
- TestModule *modules[999] = {
- &alg,
- &fst,
- &coord,
- NULL
- };
-
-
- bool all = argc == 1 || module_in_args("all", argc, argv);
- int count = 0;
- for (int i = 0; modules[i] != NULL; i++) {
- if (all || module_in_args(modules[i]->name, argc, argv)) {
- for (int j = 0; modules[i]->suites[j] != NULL; j++) {
- if (!run_suite(modules[i]->suites[j])) {
- return 1;
- } else {
- count++;
- }
- }
- }
- }
-
- printf("All tests passed (%d test suites).\n", count);
- return 0;
-}
diff --git a/tests/test_common.h b/tests/test_common.h
@@ -1,41 +0,0 @@
-#ifndef TEST_COMMON_H
-#define TEST_COMMON_H
-
-/*
- * Common utilities for testing.
- * A VoidMethod can be used as a setup or teardown method for testing, see
- * the TestSuite struct. A TestMethod takes a void pointer (usually cast
- * to some data to be used for testing, but can also be ignored) and returns
- * a bool: true for pass, false for fail.
- * A Test consists of a name (string), a TestMethod and an array of void
- * pointers that describe the test cases. Each element of this array is
- * passed to the test method sequentially, and the test session stops on
- * the first failure.
- * A test suite is just a list of tests with a setup and a teardown method.
- * The setup method is run once and for all before the first test, and the
- * teardown is run at the end of the testsuite.
- * Finally, a TestModule roughly corresponds to a test file. This type is
- * only used in test.c to collect multiple test modules.
- */
-
-typedef void (*VoidMethod)(void);
-typedef bool (*TestMethod)(void *);
-
-typedef struct {
- char * name;
- TestMethod t;
- void ** cases;
-} Test;
-
-typedef struct {
- VoidMethod setup;
- Test ** tests;
- VoidMethod teardown;
-} TestSuite;
-
-typedef struct {
- char * name;
- TestSuite ** suites;
-} TestModule;
-
-#endif
diff --git a/www/download/index.html b/www/download/index.html
@@ -1,217 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
- <title> Download | Nissy </title>
-<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>
-
-<body>
-
-<nav class="top">
- <table class="menu">
- <tr>
- <td class="logo"> <a href="/"><img src="/favicon.png" alt="logo"></a> </td>
- <td class="links">
- <a href="/download/">Download</a> |
- <a href="/examples/">Examples</a>
- </td>
- </tr>
- </table>
-</nav>
-
-<hr class="line">
-
-
-<h1>Get Nissy</h1>
-
-<table class="dltable">
-<tr>
- <td></td>
- <td><strong>Source code</strong></td>
- <td><strong>Windows executable</strong></td>
-</tr>
-<tr>
- <td><strong>Latest version</strong></td>
- <td><a href="/nissy-2.0.3.tar.gz">nissy-2.0.3.tar.gz (67Kb)</a></td>
- <td><a href="/nissy-2.0.3.exe">nissy-2.0.3.exe (780Kb)</a></td>
-</tr>
-</table>
-
-<p>
-In this page you can find download links (see above),
-<a href="#Installation">installation instructions</a> and
-<a href="#Upgrade">upgrade instructions</a>
-for nissy. If instead you wish to clone the
-<a href="https://git.tronto.net/nissy/">git repository</a>,
-you can use git:
-</p>
-
-<pre>
-<code>git clone https://git.tronto.net/nissy</code>
-</pre>
-
-<p>
-For a summary of changes and a list of older versions see below. Some versions
-(for example 1.0) are not available directly, but can be obtained from
-the git repository.
-</p>
-
-<h2 id="Installation">Installation</h2>
-
-<h3>System requirements</h3>
-
-<p>
-A full installation of nissy requires about 3.1Gb of space,
-of which 2.3Gb are occupied by the huge pruning table for fast optimal solving,
-and running it requires the same amount of RAM.
-One can choose to never use this function and not to install the relative
-pruning table. There is an alternative (slower)
-optimal solving function that uses about 500Mb of RAM.
-
-When generating the pruning tables automatically (see the section Tables below),
-at least 5.3Gb or RAM are required.
-</p>
-
-<h3>Windows</h3>
-
-<p>
-Try downloading and executing in a terminal the file <code>nissy.exe</code>,
-then follow the instructions in the <strong>Tables</strong> section below for
-installing the pruning tables.
-If <code>nissy.exe</code> does not work, you can try following the UNIX instructions
-in WSL (Windows Subsystem for Linux) or in a similar environment.
-</p>
-
-<h3>UNIX (Linux, MacOS, *BSD...)</h3>
-<p>
-Download the source archive (.tar.gz). Extract it
-with your favorite archive program, for example with
-</p>
-<pre><code>tar -xvzf nissy-VERSION.tar.gz</code></pre>
-<p>
-Open a terminal in the directory just extracted.
-If you wish, edit the <code>Makefile</code> to match your local configuration
-(this is usually not necessary, but you may want to change the
-<code>PREFIX</code> variable to change the installation path) and run
-<pre><code>make</code></pre>
-<p>
-followed by
-</p>
-<pre><code>make install</code></pre>
-<p>
-Then follow the instructions below to install the pruning tables.
-</p>
-
-<h3>Tables</h3>
-
-<p>
-Once you have installed nissy, run
-</p>
-
-<pre><code>nissy gen</code></pre>
-
-<p>
-to generate all the tables that Nissy will ever need.
-Running this command requires around 5.3Gb of RAM, and it can take some time
-(about 40 minutes on my fairly old but decent laptop, with 8 CPU threads).
-</p>
-
-<p>
-Some unnecessary technical detail: by default this command is going to use
-at most 64 threads. If you want you can choose to use more threads (if your CPU
-is very powerful) or fewer threads (if you for example want to run this command
-in the background while you do other stuff) with the <code>-t</code> option, for
-example <code>nissy gen -t 1</code>.
-</p>
-
-<p>
-Alternatively, you can
-<a href="/nissy-tables-2.0.2.zip">download all the tables (1.7Gb)</a> and
-copy them into the correct folder (see manual page, <code>ENVIRONMENT</code>
-section). On UNIX operating systems this folder is either
-<code>.nissy/tables</code> in the user's home directory or
-<code>$XDG_DATA_HOME/nissy/tables</code> if the XDG variable is configured.
-On Windows it is the same directory as the <code>nissy.exe</code> executable
-file.
-</p>
-
-<h2 id="Upgrade">Upgrading</h2>
-<p>
-If you already have nissy installed and you want to upgrade to a more
-recent version, you can simply repeat the installation process:
-</p>
-<ul>
-<li>
-On Windows: simply replace nissy.exe with the new file with the same name.
-</li>
-<li>
-On UNIX systems: download the new version of the source code, extract it in
-a new folder and run <code>make</code> and <code>make install</code> again.
-</li>
-</ul>
-<p>
-Between each version new table files might have been added, or old ones
-may be not used anymore. Nissy will deal with this automatically.
-</p>
-
-<h2>Version history</h2>
-
-<h3>Nissy v2</h3>
-
-<table class=dltable>
-<tr>
- <td><strong>Version</strong></td>
- <td><strong>Date</strong></td>
- <td><strong>Comment</strong></td>
-</tr>
-<tr>
- <td><a href="/nissy-2.0.3.tar.gz">2.0.3</a></td>
- <td>2022-09-10</td>
- <td>Fixed bug in scramble dr</td>
-</tr>
-<tr>
- <td><a href="/nissy-2.0.2.tar.gz">2.0.2</a></td>
- <td>2022-06-01</td>
- <td>Improved table generation speed</td>
-</tr>
-<tr>
- <td><a href="/nissy-2.0.1.tar.gz">2.0.1</a></td>
- <td>2022-02-22</td>
- <td>Bugfix release</td>
-</tr>
-<tr>
- <td>2.0</td>
- <td>2021-12-29</td>
- <td>Rewritten from scratch; much faster optimal solver</td>
-</tr>
-</table>
-
-<h3>Nissy v1</h3>
-
-<p>
-Nissy v1 was released in 2020. It was slow, full of bugs and the code
-was quite terrible. But in practice it got its job done most of the time.
-</p>
-
-
-<hr class="line">
-
-<nav class="bottom">
- <table class="footer">
- <tr>
- <td class="contact">
- <a href="https://sebastiano.tronto.net">sebastiano.tronto.net</a>
- </td>
- <td class="hosted">
- <a href="mailto:sebastiano@tronto.net">
- sebastiano@tronto.net
- </a>
- </td>
- </tr>
- </table>
-</nav>
-
-</body>
-</html>
diff --git a/www/examples/index.html b/www/examples/index.html
@@ -1,49 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
- <title> Examples | Nissy </title>
-<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>
-
-<body>
-
-<nav class="top">
- <table class="menu">
- <tr>
- <td class="logo"> <a href="/"><img src="/favicon.png" alt="logo"></a> </td>
- <td class="links">
- <a href="/download/">Download</a> |
- <a href="/examples/">Examples</a>
- </td>
- </tr>
- </table>
-</nav>
-
-<hr class="line">
-
-
-<h1>Examples</h1>
-
-(Coming soon...)
-
-<hr class="line">
-
-<nav class="bottom">
- <table class="footer">
- <tr>
- <td class="contact">
- <a href="https://sebastiano.tronto.net">sebastiano.tronto.net</a>
- </td>
- <td class="hosted">
- <a href="mailto:sebastiano@tronto.net">
- sebastiano@tronto.net
- </a>
- </td>
- </tr>
- </table>
-</nav>
-
-</body>
-</html>
diff --git a/www/favicon.png b/www/favicon.png
Binary files differ.
diff --git a/www/index.html b/www/index.html
@@ -1,93 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
- <title> Nissy | Nissy </title>
-<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>
-
-<body>
-
-<nav class="top">
- <table class="menu">
- <tr>
- <td class="logo"> <a href="/"><img src="/favicon.png" alt="logo"></a> </td>
- <td class="links">
- <a href="/download/">Download</a> |
- <a href="/examples/">Examples</a>
- </td>
- </tr>
- </table>
-</nav>
-
-<hr class="line">
-
-
-<h1>Nissy</h1>
-
-<p class=subtitle>A Rubik's cube solver and FMC assistant</p>
-
-<img src="/screenshot.png" alt="A screenshot of nissy running in a terminal emulator">
-
-<p>
-Nissy is a command-line Rubik's cube solver. It can find optimal solutions
-for random positions using techniques from Herbert Kociemba's
-<a href="http://kociemba.org/cube.htm">Cube Explorer</a> and
-Tomas Rokicki's
-<a href="https://github.com/rokici/cube20src/blob/master/nxopt.md">nxopt</a>.
-With 4 cores at 2.5GHz and using about 3Gb of RAM, Nissy can find an optimal
-solution in about a minute on average.
-</p>
-
-<p>
-Nissy aims at being a complete tool
-for FMC (Fewest Moves Challenge) practice. It can solve different steps
-of Thistlethwaite's algorithm (also know as DR/HTR) and cans use NISS
-(Normal-Inverse Scramble Switch).
-</p>
-
-<p>
-You should use Nissy if:
-</p>
-<ul>
-<li>
-You want to analyze your DR solutions or check for multiple optimal
-(or sub-optimal) solutions for EO/DR/HTR or similar steps.
-</li>
-<li>
-You just want a Rubik's cube solver and you like command line interfaces.
-</li>
-<li>
-You want an alternative to Cube Explorer.
-</li>
-</ul>
-
-<p>
-To get started, head to the <a href="/download/">download</a> page.
-</p>
-
-<p>
-You can also see its source code by cloning the git repository
-<a href="https://git.tronto.net/nissy/">git.tronto.net/nissy</a>
-</p>
-
-<hr class="line">
-
-<nav class="bottom">
- <table class="footer">
- <tr>
- <td class="contact">
- <a href="https://sebastiano.tronto.net">sebastiano.tronto.net</a>
- </td>
- <td class="hosted">
- <a href="mailto:sebastiano@tronto.net">
- sebastiano@tronto.net
- </a>
- </td>
- </tr>
- </table>
-</nav>
-
-</body>
-</html>
diff --git a/www/screenshot.png b/www/screenshot.png
Binary files differ.
diff --git a/www/style-3.css b/www/style-3.css
@@ -1,105 +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%;
-}
-
-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;
-}