aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--INSTALL93
-rw-r--r--Makefile21
-rw-r--r--TODO/2.1.md51
-rw-r--r--TODO/build-options.md33
-rw-r--r--TODO/documentation.md41
-rw-r--r--TODO/easy.md16
-rw-r--r--TODO/installation.md14
-rw-r--r--TODO/new-feature-ideas.md32
-rw-r--r--TODO/parser.md13
-rw-r--r--TODO/refactoring.md28
-rw-r--r--TODO/testing.md6
-rw-r--r--TODO/webapp.md19
-rw-r--r--old/maybe-useful-coord.c181
-rw-r--r--old/maybe-useful-steps.c1111
-rw-r--r--old/solve_old.c447
-rw-r--r--old/solve_old.h9
-rw-r--r--src/alg.c295
-rw-r--r--src/alg.h16
-rw-r--r--src/commands.c356
-rw-r--r--src/commands.h199
-rw-r--r--src/coord.c959
-rw-r--r--src/coord.h267
-rw-r--r--src/cube.c932
-rw-r--r--src/cube.h59
-rw-r--r--src/cubetypes.h240
-rw-r--r--src/env.c2
-rw-r--r--src/env.h4
-rw-r--r--src/fst.c401
-rw-r--r--src/fst.h13
-rw-r--r--src/moves.c417
-rw-r--r--src/moves.h23
-rw-r--r--src/movesets.c194
-rw-r--r--src/movesets.h15
-rw-r--r--src/pf.c95
-rw-r--r--src/pf.h20
-rw-r--r--src/pruning.c371
-rw-r--r--src/pruning.h22
-rw-r--r--src/shell.c10
-rw-r--r--src/solve.c538
-rw-r--r--src/solve.h51
-rw-r--r--src/solver_step.c306
-rw-r--r--src/solver_step.h12
-rw-r--r--src/steps.c1490
-rw-r--r--src/steps.h243
-rw-r--r--src/symcoord.c687
-rw-r--r--src/symcoord.h17
-rw-r--r--src/threader_eager.c163
-rw-r--r--src/threader_eager.h8
-rw-r--r--src/threader_single.c35
-rw-r--r--src/threader_single.h8
-rw-r--r--src/trans.c381
-rw-r--r--src/trans.h36
-rw-r--r--src/utils.c14
-rw-r--r--tests/alg_tests.c266
-rw-r--r--tests/alg_tests.h21
-rw-r--r--tests/coord_tests.c50
-rw-r--r--tests/coord_tests.h13
-rw-r--r--tests/fst_tests.c184
-rw-r--r--tests/fst_tests.h19
-rw-r--r--tests/test.c85
-rw-r--r--tests/test_common.h41
-rw-r--r--www/download/index.html217
-rw-r--r--www/examples/index.html49
-rw-r--r--www/favicon.pngbin6550 -> 0 bytes
-rw-r--r--www/index.html93
-rw-r--r--www/screenshot.pngbin61239 -> 0 bytes
-rw-r--r--www/style-3.css105
68 files changed, 5547 insertions, 6611 deletions
diff --git a/.gitignore b/.gitignore
index 17008a0..2ea98c6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,3 @@ doc/*.html
2doc/*.pdf 2doc/*.pdf
3nissy 3nissy
4nissy-* 4nissy-*
5test
diff --git a/INSTALL b/INSTALL
index ffc461d..f0bba55 100644
--- a/INSTALL
+++ b/INSTALL
@@ -4,78 +4,57 @@ Nissy is available at https://nissy.tronto.net
4 4
5# Requirements 5# Requirements
6 6
7A full installation of nissy requires about 3Gb of space, of which 7A full installation of nissy requires about 3Gb of space,
82.3Gb are occupied by the huge pruning table for fast optimal solving, 8of which 2.3Gb are occupied by the huge pruning table for fast optimal solving,
9and running it requires the same amount of RAM. One can choose to never 9and running it requires the same amount of RAM.
10use this function and not to install the relative pruning table. There 10One can choose to never use this function and not to install the relative
11is an alternative (slower) optimal solving function that uses about 11pruning table. There is an alternative (slower)
12500Mb of RAM. When generating the pruning tables automatically (see 12optimal solving function that uses about 500Mb of RAM.
13the section Tables below), at least 5.3Gb or RAM are required.
14 13
15# Installation 14# Installation
16 15
17## On Windows 16## On Windows
18 17
19Try downloading and executing in a terminal the file nissy.exe, then 18Try downloading and executing in a terminal the file nissy.exe, then
20follow the instructions in the Tables section below for installing the 19follow the instructions in the Tables section below for
21pruning tables. If nissy.exe does not work, you can try following the 20installing the pruning tables.
22UNIX instructions in WSL (Windows Subsystem for Linux) or in a similar 21If nissy.exe does not work, you can try following the UNIX instructions
23environment. 22in WSL (Windows Subsystem for Linux) or in a similar environment.
24 23
25## On a UNIX system: 24Sorry for the inconvenience, I don't have a Windows machine to test this on.
26
27Download the source archive (.tar.gz). Extract it with your favorite
28archive program, for example with
29
30 tar -xvzf nissy-VERSION.tar.gz
31
32Open a terminal in the directory just extracted. If you wish, edit the
33Makefile to match your local configuration (this is usually not necessary,
34but you may want to change the PREFIX variable to change the installation
35path) and run
36
37 make
38
39followed by
40 25
41 make install 26## On a UNIX system:
42 27
43Then follow the instructions below to install the pruning tables. 28Edit the Makefile to match your local configuration (usually not necessary, but you
29may want to change the PREFIX variable) and run make, followed by make install.
30Follow the instructions below to install the pruning tables.
44 31
45## Tables 32## Tables
33Nissy needs to generate certain large tables to work. These tables are by default
34generated the first time they are needed (e.g the first time you ask to solve a
35certain step) and then saved to a file. Whenever these tables are needed again,
36nissy simply loads the corresponding file from the hard disk.
46 37
47Once you have installed nissy, run 38The very large table for optimal solving can take some time to generate
39(about 1.5 hours on my fairly old but decent laptop, using 8 CPU threads).
40In order to generate it you need at least 5Gb of RAM.
41All other tables are much faster.
48 42
49 nissy gen 43You can ask nissy to generate all the tables it will ever need with the gen
44command. It is recommended to use more than one thread, if your CPU has them.
45For example, you can run:
50 46
51to generate all the tables that Nissy will ever need. Running this 47nissy gen -t 8
52command requires around 5.3Gb of RAM, and it can take some time (about
5340 minutes on my fairly old but decent laptop, with 8 CPU threads).
54 48
55Some unnecessary technical detail: by default this command is going to 49to generate all tables using 8 threads.
56use at most 64 threads. If you want you can choose to use more threads
57(if your CPU is very powerful) or fewer threads (if you for example
58want to run this command in the background while you do other stuff)
59with the -t option, for example nissy gen -t 1.
60 50
61Alternatively, you can download all the tables (1.7Gb) and copy them 51Alternatively, you can simply download all the tables and copy them into the
62into the correct folder (see manual page, ENVIRONMENT section). On UNIX 52correct folder (see manual page, ENVIRONMENT section). On UNIX operating
63operating systems this folder is either .nissy/tables in the user's 53systems this folder is either .nissy/tables in the user's home directory or
64home directory or $XDG_DATA_HOME/nissy/tables if the XDG variable 54$XDG_DATA_HOME/nissy/tables if the XDG variable is configured. On Windows
65is configured. On Windows it is the same directory as the nissy.exe 55it is the same directory as the nissy.exe executable file.
66executable file.
67 56
68You can downloads all the tables from the following link: 57You can downloads all the tables from the following link:
69 58 https://nissy.tronto.net/nissy-tables-2.0.zip
70 https://nissy.tronto.net/nissy-tables-2.0.2.zip 59The version 2.0 at the end of the file name is only indicative.
71 60Later versions will use the same tables, unless otherwise specified.
72# Upgrading
73
74If you already have nissy installed and you want to upgrade to a more
75recent version, you can simply repeat the installation process:
76* On Windows: simply replace nissy.exe with the new file with the same name.
77* On UNIX systems: download the new version of the source code, extract it
78 in a new folder and run make and make install again.
79
80Between each version new table files might have been added, or old ones
81may be not used anymore. Nissy will deal with this automatically.
diff --git a/Makefile b/Makefile
index 71eda6b..ab062f7 100644
--- a/Makefile
+++ b/Makefile
@@ -1,18 +1,19 @@
1# See LICENSE file for copyright and license details. 1# See LICENSE file for copyright and license details.
2 2
3VERSION = post-2.0.2 3VERSION = 2.0.3
4 4
5PREFIX = /usr/local 5PREFIX = /usr/local
6MANPREFIX = ${PREFIX}/share/man 6MANPREFIX = ${PREFIX}/share/man
7 7
8CPPFLAGS = -DVERSION=\"${VERSION}\" 8CPPFLAGS = -DVERSION=\"${VERSION}\"
9CFLAGS = -std=c99 -pthread -pedantic -Wall -Wextra \ 9CFLAGS = -std=c99 -pthread -pedantic -Wall -Wextra \
10 -Wno-unused-parameter -O3 ${CPPFLAGS} 10 -Wno-unused-parameter -O3 ${CPPFLAGS}
11DBGFLAGS = -std=c99 -pthread -pedantic -Wall -Wextra \ 11DBGFLAGS = -std=c99 -pthread -pedantic -Wall -Wextra \
12 -Wno-unused-parameter -g ${CPPFLAGS} 12 -Wno-unused-parameter -g ${CPPFLAGS}
13 13
14CC = cc 14CC = cc
15 15
16
16all: nissy 17all: nissy
17 18
18nissy: clean 19nissy: clean
@@ -24,11 +25,8 @@ nissy.exe:
24debug: 25debug:
25 ${CC} ${DBGFLAGS} -o nissy src/*.c 26 ${CC} ${DBGFLAGS} -o nissy src/*.c
26 27
27test:
28 ${CC} ${DBGFLAGS} -DTEST -o test src/*.c tests/*.c
29
30clean: 28clean:
31 rm -rf nissy nissy*.exe nissy*.tar.gz doc/nissy.html doc/nissy.pdf 29 rm -rf nissy nissy*.exe nissy*.tar.gz
32 30
33dist: clean nissy.exe 31dist: clean nissy.exe
34 mkdir -p nissy-${VERSION} 32 mkdir -p nissy-${VERSION}
@@ -65,4 +63,5 @@ uninstall:
65 rm -rf ${DESTDIR}${PREFIX}/bin/nissy ${DESTDIR}${MANPREFIX}/man1/nissy.1 63 rm -rf ${DESTDIR}${PREFIX}/bin/nissy ${DESTDIR}${MANPREFIX}/man1/nissy.1
66 for s in ${SCRIPTS}; do rm -rf ${DESTDIR}${PREFIX}/bin/$$s; done 64 for s in ${SCRIPTS}; do rm -rf ${DESTDIR}${PREFIX}/bin/$$s; done
67 65
68.PHONY: all debug test clean dist install uninstall upload 66.PHONY: all debug clean dist install uninstall upload
67
diff --git a/TODO/2.1.md b/TODO/2.1.md
deleted file mode 100644
index 7448094..0000000
--- a/TODO/2.1.md
+++ /dev/null
@@ -1,51 +0,0 @@
1# TODO-list for version 2.1 (or is it 3.0 at this point?)
2
3## Rework solver
4
5### 1. Implement minimum viable
6
7* Implement nxopt31 with fst_cube. Remember that the function
8 move_check_solved() should do one axis at the time, so that we don't move
9 everything before checking.
10* test?
11
12### 2. Rework achitecture and file dependencies
13
14* solve.h depends only on moves(alg?) (dependency on step and trans is removed).
15* Other modules have changed dependencies, might as well rework all.
16* Make files smaller, do not include definition in .h, separate
17data from abstract operations.
18* remove cubetypes.h
19* Create a module for multi-step (maybe wait?)
20* Possible changes: in step solver, copy cube only if niss; add cleanup function
21in solver (called by solve()) to free cube and perhaps pruning tables.
22* see various TODO's in files
23
24### 4. More threading options
25
26* Lazy multithread: threads are as independent as possible and only
27merged at the end. Ideal when all solutions of a certain length are requested.
28* (Done) Eager multithread: current implementation, branches communicate the
29number and list of solutions to stop as soon as possible. Good when only one
30solution of a certain depth is required.
31
32## Simplify steps
33
34* Remove one type of rotation.
35* Change steps to choicestep and stepalt to step (or was this already done?).
36
37## Add missing coordinates and steps
38
39* Check the old file for a list. Many are missing.
40* Checkers in steps.c should use coordinates.
41
42## Missing and new commands
43
44* gen
45* freemem
46* twophase
47
48## Easy improvements
49
50* Solve should re-orient the cube if centers are off
51* Solve: add options for -I (inverse only) and -L (linear = normal + inverse).
diff --git a/TODO/build-options.md b/TODO/build-options.md
deleted file mode 100644
index 83b8a34..0000000
--- a/TODO/build-options.md
+++ /dev/null
@@ -1,33 +0,0 @@
1# Build options for memory and multithreading
2
3## Investigate
4
5* Check exactly how much memory is needed for everything.
6* Take note of which parts use threading (solving, genptable, other?).
7
8## Prepare code
9
10* Use define / ifdef or similar to compile and build tables only for the
11 parts to be used.
12* If threads = 1, use a much simpler version of the solve method. Remember
13 that checking if enough solutions have been found is the first thing to
14 do in singlethread (no locking).
15* Do not include pthread if threads = 1.
16* Only one optimal solver should be compiled.
17* Some simple steps may also need alternatives with smaller tables
18 (e.g. for staying sub 1Gb). For example dr and drfin.
19* If necessary, work out alternatives to "twophase" for low-resource versions.
20
21## Makefile
22
23* Figure out how to change these options via makefile. For example: one
24 variable for the maximum allowed ram and one for the number of threads.
25* (Optional) use a configure script?
26* (Optional) interactive installation script?
27
28## Automate
29
30* Scout for resources during installation and choose best configuration
31 automatically.
32* How to do this in Linux / POSIX?
33* How to do this in Windows?
diff --git a/TODO/documentation.md b/TODO/documentation.md
deleted file mode 100644
index 050a854..0000000
--- a/TODO/documentation.md
+++ /dev/null
@@ -1,41 +0,0 @@
1# Documentation
2
3## Big documentation file on nissy's internals
4
5* Coordinates
6* Symcoordinates
7* Pruning tables
8* Coordinate solving
9* fst cube
10* Optimized solver
11* Multithreading
12* Commands etc...
13* Code architecture
14
15## examples.md
16
17* Example file for nissy's website and documentation folder
18* With screenshots!
19
20## Random info
21
22Where to collect random information like this table?
23
24Table pt_nxopt31_HTM
25Base value: 9
260 1
271 6
282 29
293 164
304 1433
315 16772
326 205033
337 2513871
348 30329976
359 342440769
3610 2815191126
3711 6147967200
3812 524918774
3913 3546
4014 0
4115 0
diff --git a/TODO/easy.md b/TODO/easy.md
deleted file mode 100644
index 7d780e2..0000000
--- a/TODO/easy.md
+++ /dev/null
@@ -1,16 +0,0 @@
1# Easy things to improve or add
2
3## Improvements
4
5* Silent batch mode without >>>
6* Solutions should be shown sorted: by length first, then by normal moves
7 (no niss) first, then it depends on the step (e.g. EO by axis).
8
9## Old commands and steps
10
11* drcorners (solve corners after DR)
12* Search and improve suboptimal subsequences
13
14## New commands
15
16* notation: show valid moves
diff --git a/TODO/installation.md b/TODO/installation.md
deleted file mode 100644
index 7f632c2..0000000
--- a/TODO/installation.md
+++ /dev/null
@@ -1,14 +0,0 @@
1# Simplify and improve installation
2
3## Tables
4
5* Make install should generate tables, or add a "make tables" target to
6 generate tables.
7* Make tables should also check for existing files and remove old ones
8 (maybe more for nissy's command than for makefile).
9
10## Correctness
11
12* Add checksum for all generated files.
13* Hard-code results? Check for compatibility problems between different OSes
14 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
deleted file mode 100644
index 067d440..0000000
--- a/TODO/new-feature-ideas.md
+++ /dev/null
@@ -1,32 +0,0 @@
1# Possible new features and improvements
2
3This file contains non-refined ideas. Once an idea gets refined, it will
4get its own file and more details.
5
6## Steps
7
8* QTM solver
9* 5-side solver (for robots)
10* Other steps (cross, blocks, LSE...)
11
12## UX features
13
14* Save algs as variables and edit them (like in old nissy)
15* Use a logging system for previously run commands, info, results...
16 (e.g. when solving with -c solutions are not shown, they can be logged here)
17* Configurability: add an "alias" command, run config file at startup
18* Input cube state directly instead of moves (ugly from command line / file)
19
20## Improvements
21
22* Optimal solver: when asking only for one solution, scan for upper bound in
23 parallel using a non-optimal (but fast) solver (e.g. twophase).
24* Optimal solver: up to a small bound, try with a small pruning table.
25* Optimal solver: start at different depths in parallel
26* Multi-step solver: make more general
27
28## New features
29
30* Allow user to specify moveset manually (see issue \#5 on github)
31* EO analysis (and also DR and HTR analysis): group similar EOs (Jay)
32* HTR "maze" analysis?
diff --git a/TODO/parser.md b/TODO/parser.md
deleted file mode 100644
index 134f0d7..0000000
--- a/TODO/parser.md
+++ /dev/null
@@ -1,13 +0,0 @@
1# Improve command parser
2
3First, expand this TODO file to be more precise.
4
5## Refactor
6
7* The syntax of a command's options should be described by data, not by a
8 parser function.
9* A single parser function can then parse options for all commands.
10
11## Usability
12
13* Better error messages!
diff --git a/TODO/refactoring.md b/TODO/refactoring.md
deleted file mode 100644
index eedbd20..0000000
--- a/TODO/refactoring.md
+++ /dev/null
@@ -1,28 +0,0 @@
1# Refactoring
2
3## Init functions
4
5* All .h files should have a single init function.
6* This function should initialize everything that this module needs, including
7 calling the init functions of the modules it depends on.
8* To avoid multiple initialization of the same module, each should have a
9 static bool initialized variable.
10* Everything that a module needs should be initialized by init(), avoid
11 initializing stuff when solving. Exception: pruning tables, move tables.
12* Most functions should generate some tables and save them to disk.
13* Init functions should have a consistent structure (e.g. the way they check
14 if the tables are already generated should be the same).
15
16## Cube types
17
18* Get rid of cubetype.h, split type definitionss into the other modules.
19* Every type definition should be in the most fundamental module that needs it.
20
21## Code style
22
23* Stop declaring all variables at the beginning of a function.
24* Remove variable names from prototypes.
25* Sort function implementations alphabetically, ignore static vs non static.
26* Rename functions and variable to have a consistent naming scheme.
27* Functions that copy data: swap src and dest, follow memcpy standard.
28* Read style(9) and decide what to implement.
diff --git a/TODO/testing.md b/TODO/testing.md
deleted file mode 100644
index 1deb93a..0000000
--- a/TODO/testing.md
+++ /dev/null
@@ -1,6 +0,0 @@
1# Testing
2
3## Write tests
4
5* Write tests for each module. Some of might require refactoring (this is
6 a good thing!)
diff --git a/TODO/webapp.md b/TODO/webapp.md
deleted file mode 100644
index 4f8eddf..0000000
--- a/TODO/webapp.md
+++ /dev/null
@@ -1,19 +0,0 @@
1# Towards a nissy webapp
2
3## Architecture
4
5* Split in client / server.
6* Server can load and keep in memory all the tables, client(s) send messages to
7 the server to run commands.
8* Use UNIX sockets only first, maybe later try WinSock.
9
10## Simple webapp
11
12* Investigate how to use fastcgi, try simple program first.
13* Decide what limits to put in terms of resources and write a "filter" script
14 to block big requests (maybe use a timeout).
15
16## Advanced webapp
17
18* Use cubing.js for nice graphics.
19* Port it to a graphical desktop version too.
diff --git a/old/maybe-useful-coord.c b/old/maybe-useful-coord.c
deleted file mode 100644
index 9ab2971..0000000
--- a/old/maybe-useful-coord.c
+++ /dev/null
@@ -1,181 +0,0 @@
1int
2array_ep_to_epos(int *ep, int *ss)
3{
4 int epos[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
5 int eps[4];
6 int i, j, is;
7
8 for (i = 0, is = 0; i < 12; i++) {
9 for (j = 0; j < 4; j++) {
10 if (ep[i] == ss[j]) {
11 eps[is++] = j;
12 epos[i] = 1;
13 }
14 }
15 }
16
17 for (i = 0; i < 4; i++)
18 swap(&epos[ss[i]], &epos[i+8]);
19
20 return 24 * subset_to_index(epos, 12, 4) + perm_to_index(eps, 4);
21}
22
23void
24epos_to_compatible_ep(int epos, int *ep, int *ss)
25{
26 int i, j, k, other[8];
27 bool flag;
28
29 for (i = 0; i < 12; i++)
30 ep[i] = -1;
31
32 epos_to_partial_ep(epos, ep, ss);
33
34 for (i = 0, j = 0; i < 12; i++) {
35 flag = false;
36 for (k = 0; k < 4; k++)
37 flag = flag || (i == ss[k]);
38 if (!flag)
39 other[j++] = i;
40 }
41
42 for (i = 0, j = 0; i < 12; i++)
43 if (ep[i] == -1)
44 ep[i] = other[j++];
45}
46
47void
48epos_to_partial_ep(int epos, int *ep, int *ss)
49{
50 int i, is, eposs[12], eps[4];
51
52 index_to_perm(epos % FACTORIAL4, 4, eps);
53 index_to_subset(epos / FACTORIAL4, 12, 4, eposs);
54
55 for (i = 0; i < 4; i++)
56 swap(&eposs[ss[i]], &eposs[i+8]);
57
58 for (i = 0, is = 0; i < 12; i++)
59 if (eposs[i])
60 ep[i] = ss[eps[is++]];
61}
62
63void
64fix_eorleoud(CubeArray *arr)
65{
66 int i;
67
68 for (i = 0; i < 12; i++) {
69 if ((edge_slice(i) == 0 && edge_slice(arr->ep[i]) != 0) ||
70 (edge_slice(i) != 0 && edge_slice(arr->ep[i]) == 0)) {
71 arr->eorl[i] = 1 - arr->eofb[i];
72 } else {
73 arr->eorl[i] = arr->eofb[i];
74 }
75
76 if ((edge_slice(i) == 2 && edge_slice(arr->ep[i]) != 2) ||
77 (edge_slice(i) != 2 && edge_slice(arr->ep[i]) == 2)) {
78 arr->eoud[i] = 1 - arr->eofb[i];
79 } else {
80 arr->eoud[i] = arr->eofb[i];
81 }
82 }
83}
84
85void
86fix_cofbcorl(CubeArray *arr)
87{
88 int i;
89
90 for (i = 0; i < 8; i++) {
91 if (i % 2 == arr->cp[i] % 2) {
92 arr->cofb[i] = arr->coud[i];
93 arr->corl[i] = arr->coud[i];
94 } else {
95 if (arr->cp[i] % 2 == 0) {
96 arr->cofb[i] = (arr->coud[i]+1)%3;
97 arr->corl[i] = (arr->coud[i]+2)%3;
98 } else {
99 arr->cofb[i] = (arr->coud[i]+2)%3;
100 arr->corl[i] = (arr->coud[i]+1)%3;
101 }
102 }
103 }
104}
105
106Cube
107admissible_ep(Cube cube, PieceFilter f)
108{
109 CubeArray *arr = new_cubearray(cube, f);
110 Cube ret;
111 bool used[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
112 int i, j;
113
114 for (i = 0; i < 12; i++)
115 if (arr->ep[i] != -1)
116 used[arr->ep[i]] = true;
117
118 for (i = 0, j = 0; i < 12; i++) {
119 for ( ; j < 11 && used[j]; j++);
120 if (arr->ep[i] == -1)
121 arr->ep[i] = j++;
122 }
123
124 ret = arrays_to_cube(arr, pf_ep);
125 free_cubearray(arr, f);
126
127 return ret;
128}
129
130int
131edge_slice(Edge e) {
132 if (e < 0 || e > 11)
133 return -1;
134
135 if (e == FR || e == FL || e == BL || e == BR)
136 return 0;
137 if (e == UR || e == UL || e == DR || e == DL)
138 return 1;
139
140 return 2;
141}
142
143int
144piece_orientation(Cube cube, int piece, char *orientation)
145{
146 int arr[12], n, b, x;
147
148 if (!strcmp(orientation, "eofb")) {
149 x = cube.eofb;
150 n = 12;
151 b = 2;
152 } else if (!strcmp(orientation, "eorl")) {
153 x = cube.eorl;
154 n = 12;
155 b = 2;
156 } else if (!strcmp(orientation, "eoud")) {
157 x = cube.eoud;
158 n = 12;
159 b = 2;
160 } else if (!strcmp(orientation, "coud")) {
161 x = cube.coud;
162 n = 8;
163 b = 3;
164 } else if (!strcmp(orientation, "corl")) {
165 x = cube.corl;
166 n = 8;
167 b = 3;
168 } else if (!strcmp(orientation, "cofb")) {
169 x = cube.cofb;
170 n = 8;
171 b = 3;
172 } else {
173 return -1;
174 }
175
176 int_to_sum_zero_array(x, b, n, arr);
177 if (piece < n)
178 return arr[piece];
179
180 return -1;
181}
diff --git a/old/maybe-useful-steps.c b/old/maybe-useful-steps.c
deleted file mode 100644
index 2a20dd9..0000000
--- a/old/maybe-useful-steps.c
+++ /dev/null
@@ -1,1111 +0,0 @@
1#include "steps.h"
2
3#define UPDATECHECKSTOP(a, b, c) if ((a=(MAX((a),(b))))>(c)) return (a);
4
5static int estimate_stepalt(StepAlt *a, uint64_t *ind);
6
7/* Checkers and validators ***************************************************/
8
9/* TODO: these should be with Cube *cube (and all need to change) */
10/* Maybe move them to cube.c */
11static bool check_centers(Cube cube);
12static bool check_coud_HTM(Cube cube);
13static bool check_coud_URF(Cube cube);
14static bool check_corners_HTM(Cube cube);
15static bool check_corners_URF(Cube cube);
16static bool check_cornershtr(Cube cube);
17static bool check_eofb(Cube cube);
18static bool check_drud(Cube cube);
19static bool check_htr(Cube cube);
20
21static bool always_valid(Alg *alg);
22static bool validate_singlecw_ending(Alg *alg);
23
24/* Messages for when cube is not ready ***************************************/
25
26static char check_centers_msg[100] = "cube must be oriented (centers solved)";
27static char check_eo_msg[100] = "EO must be solved on given axis";
28static char check_dr_msg[100] = "DR must be solved on given axis";
29static char check_htr_msg[100] = "HTR must be solved";
30static char check_drany_msg[100] = "DR must be solved on at least one axis";
31
32/* Steps *********************************************************************/
33
34/* Optimal solvers *******************/
35
36Step
37optimal_HTM = {
38 .shortname = "optimal",
39 .name = "Optimal solve (in HTM)",
40
41 .final = true,
42 .is_done = is_solved,
43 .estimate = estimate_nxopt31_HTM,
44 .ready = check_centers,
45 .ready_msg = check_centers_msg,
46 .is_valid = always_valid,
47 .moveset = &moveset_HTM,
48
49 .pre_trans = uf,
50
51 .tables = {&pd_nxopt31_HTM, &pd_corners_HTM},
52 .ntables = 2,
53};
54
55Step
56optimal_light_HTM = {
57 .shortname = "light",
58 .name = "Optimal solve (in HTM), small table (500Mb RAM total)",
59
60 .final = true,
61 .is_done = is_solved,
62 .estimate = estimate_light_HTM,
63 .ready = check_centers,
64 .ready_msg = check_centers_msg,
65 .is_valid = always_valid,
66 .moveset = &moveset_HTM,
67
68 .pre_trans = uf,
69
70 .tables = {&pd_drud_sym16_HTM, &pd_corners_HTM},
71 .ntables = 2,
72};
73
74/* Optimal after EO ******************/
75
76Step
77eofin_eo = {
78 .shortname = "eofin",
79 .name = "Optimal solve after EO without breaking EO (detected)",
80
81 .final = true,
82 .is_done = is_solved,
83 .estimate = estimate_nxopt31_HTM,
84 .ready = check_eofb,
85 .ready_msg = check_eo_msg,
86 .is_valid = always_valid,
87 .moveset = &moveset_eofb,
88
89 .detect = detect_pretrans_eofb,
90
91 .tables = {&pd_nxopt31_HTM, &pd_corners_HTM},
92 .ntables = 2,
93};
94
95Step
96eofbfin_eofb = {
97 .shortname = "eofbfin",
98 .name = "Optimal after EO on F/B without breaking EO",
99
100 .final = true,
101 .is_done = is_solved,
102 .estimate = estimate_nxopt31_HTM,
103 .ready = check_eofb,
104 .ready_msg = check_eo_msg,
105 .is_valid = always_valid,
106 .moveset = &moveset_eofb,
107
108 .pre_trans = uf,
109
110 .tables = {&pd_nxopt31_HTM, &pd_corners_HTM},
111 .ntables = 2,
112};
113
114Step
115eorlfin_eorl = {
116 .shortname = "eorlfin",
117 .name = "Optimal after EO on R/L without breaking EO",
118
119 .final = true,
120 .is_done = is_solved,
121 .estimate = estimate_nxopt31_HTM,
122 .ready = check_eofb,
123 .ready_msg = check_eo_msg,
124 .is_valid = always_valid,
125 .moveset = &moveset_eofb,
126
127 .pre_trans = ur,
128
129 .tables = {&pd_nxopt31_HTM, &pd_corners_HTM},
130 .ntables = 2,
131};
132
133Step
134eoudfin_eoud = {
135 .shortname = "eoudfin",
136 .name = "Optimal after EO on U/D without breaking EO",
137
138 .final = true,
139 .is_done = is_solved,
140 .estimate = estimate_nxopt31_HTM,
141 .ready = check_eofb,
142 .ready_msg = check_eo_msg,
143 .is_valid = always_valid,
144 .moveset = &moveset_eofb,
145
146 .pre_trans = fd,
147
148 .tables = {&pd_nxopt31_HTM, &pd_corners_HTM},
149 .ntables = 2,
150};
151
152/* EO steps **************************/
153Step
154eoany_HTM = {
155 .shortname = "eo",
156 .name = "EO on any axis",
157
158 .final = false,
159 .is_done = check_eofb,
160 .estimate = estimate_eofb_HTM,
161 .ready = check_centers,
162 .ready_msg = check_centers_msg,
163 .is_valid = validate_singlecw_ending,
164 .moveset = &moveset_HTM,
165
166 .detect = detect_pretrans_void_3axis,
167
168 .tables = {&pd_eofb_HTM},
169 .ntables = 1,
170};
171
172Step
173eofb_HTM = {
174 .shortname = "eofb",
175 .name = "EO on F/B",
176
177 .final = false,
178 .is_done = check_eofb,
179 .estimate = estimate_eofb_HTM,
180 .ready = check_centers,
181 .ready_msg = check_centers_msg,
182 .is_valid = validate_singlecw_ending,
183 .moveset = &moveset_HTM,
184
185 .pre_trans = uf,
186
187 .tables = {&pd_eofb_HTM},
188 .ntables = 1,
189};
190
191Step
192eorl_HTM = {
193 .shortname = "eorl",
194 .name = "EO on R/L",
195
196 .final = false,
197 .is_done = check_eofb,
198 .estimate = estimate_eofb_HTM,
199 .ready = check_centers,
200 .ready_msg = check_centers_msg,
201 .is_valid = validate_singlecw_ending,
202 .moveset = &moveset_HTM,
203
204 .pre_trans = ur,
205
206 .tables = {&pd_eofb_HTM},
207 .ntables = 1,
208};
209
210Step
211eoud_HTM = {
212 .shortname = "eoud",
213 .name = "EO on U/D",
214
215 .final = false,
216 .is_done = check_eofb,
217 .estimate = estimate_eofb_HTM,
218 .ready = check_centers,
219 .ready_msg = check_centers_msg,
220 .is_valid = validate_singlecw_ending,
221 .moveset = &moveset_HTM,
222
223 .pre_trans = fd,
224
225 .tables = {&pd_eofb_HTM},
226 .ntables = 1,
227};
228
229/* CO steps **************************/
230Step
231coany_HTM = {
232 .shortname = "co",
233 .name = "CO on any axis",
234
235 .final = false,
236 .is_done = check_coud_HTM,
237 .estimate = estimate_coud_HTM,
238 .ready = NULL,
239 .is_valid = validate_singlecw_ending,
240 .moveset = &moveset_HTM,
241
242 .detect = detect_pretrans_void_3axis,
243
244 .tables = {&pd_coud_HTM},
245 .ntables = 1,
246};
247
248Step
249coud_HTM = {
250 .shortname = "coud",
251 .name = "CO on U/D",
252
253 .final = false,
254 .is_done = check_coud_HTM,
255 .estimate = estimate_coud_HTM,
256 .ready = NULL,
257 .is_valid = validate_singlecw_ending,
258 .moveset = &moveset_HTM,
259
260 .pre_trans = uf,
261
262 .tables = {&pd_coud_HTM},
263 .ntables = 1,
264};
265
266Step
267corl_HTM = {
268 .shortname = "corl",
269 .name = "CO on R/L",
270
271 .final = false,
272 .is_done = check_coud_HTM,
273 .estimate = estimate_coud_HTM,
274 .ready = NULL,
275 .is_valid = validate_singlecw_ending,
276 .moveset = &moveset_HTM,
277
278 .pre_trans = rf,
279
280 .tables = {&pd_coud_HTM},
281 .ntables = 1,
282};
283
284Step
285cofb_HTM = {
286 .shortname = "cofb",
287 .name = "CO on F/B",
288
289 .final = false,
290 .is_done = check_coud_HTM,
291 .estimate = estimate_coud_HTM,
292 .ready = NULL,
293 .is_valid = validate_singlecw_ending,
294 .moveset = &moveset_HTM,
295
296 .pre_trans = fd,
297
298 .tables = {&pd_coud_HTM},
299 .ntables = 1,
300};
301
302Step
303coany_URF = {
304 .shortname = "co-URF",
305 .name = "CO any axis (URF moveset)",
306
307 .final = false,
308 .is_done = check_coud_URF,
309 .estimate = estimate_coud_URF,
310 .ready = NULL,
311 .is_valid = validate_singlecw_ending,
312 .moveset = &moveset_URF,
313
314 .detect = detect_pretrans_void_3axis,
315
316 .tables = {&pd_coud_HTM},
317 .ntables = 1,
318};
319
320Step
321coud_URF = {
322 .shortname = "coud-URF",
323 .name = "CO on U/D (URF moveset)",
324
325 .final = false,
326 .is_done = check_coud_URF,
327 .estimate = estimate_coud_URF,
328 .ready = NULL,
329 .is_valid = validate_singlecw_ending,
330 .moveset = &moveset_URF,
331
332 .pre_trans = uf,
333
334 .tables = {&pd_coud_HTM},
335 .ntables = 1,
336};
337
338Step
339corl_URF = {
340 .shortname = "corl-URF",
341 .name = "CO on R/L (URF moveset)",
342
343 .final = false,
344 .is_done = check_coud_URF,
345 .estimate = estimate_coud_URF,
346 .ready = NULL,
347 .is_valid = validate_singlecw_ending,
348 .moveset = &moveset_URF,
349
350 .pre_trans = rf,
351
352 .tables = {&pd_coud_HTM},
353 .ntables = 1,
354};
355
356Step
357cofb_URF = {
358 .shortname = "cofb-URF",
359 .name = "CO on F/B (URF moveset)",
360
361 .final = false,
362 .is_done = check_coud_URF,
363 .estimate = estimate_coud_URF,
364 .ready = NULL,
365 .is_valid = validate_singlecw_ending,
366 .moveset = &moveset_URF,
367
368 .pre_trans = fd,
369
370 .tables = {&pd_coud_HTM},
371 .ntables = 1,
372};
373
374/* Misc corner steps *****************/
375Step
376cornershtr_HTM = {
377 .shortname = "chtr",
378 .name = "Solve corners to HTR state",
379
380 .final = false,
381 .is_done = check_cornershtr,
382 .estimate = estimate_cornershtr_HTM,
383 .ready = NULL,
384 .is_valid = validate_singlecw_ending,
385 .moveset = &moveset_HTM,
386
387 .pre_trans = uf,
388
389 .tables = {&pd_cornershtr_HTM},
390 .ntables = 1,
391};
392
393Step
394cornershtr_URF = {
395 .shortname = "chtr-URF",
396 .name = "Solve corners to HTR state (URF moveset)",
397
398 .final = false,
399 .is_done = check_cornershtr,
400 .estimate = estimate_cornershtr_URF,
401 .ready = NULL,
402 .is_valid = validate_singlecw_ending,
403 .moveset = &moveset_URF,
404
405 .pre_trans = uf,
406
407 .tables = {&pd_cornershtr_HTM},
408 .ntables = 1,
409};
410
411Step
412corners_HTM = {
413 .shortname = "corners",
414 .name = "Solve corners",
415
416 .final = true,
417 .is_done = check_corners_HTM,
418 .estimate = estimate_corners_HTM,
419 .ready = NULL,
420 .is_valid = always_valid,
421 .moveset = &moveset_HTM,
422
423 .pre_trans = uf,
424
425 .tables = {&pd_corners_HTM},
426 .ntables = 1,
427};
428
429Step
430corners_URF = {
431 .shortname = "corners-URF",
432 .name = "Solve corners (URF moveset)",
433
434 .final = true, /* TODO: check if this works with reorient */
435 .is_done = check_corners_URF,
436 .estimate = estimate_corners_URF,
437 .ready = NULL,
438 .is_valid = always_valid,
439 .moveset = &moveset_URF,
440
441 .pre_trans = uf,
442
443 .tables = {&pd_corners_HTM},
444 .ntables = 1,
445};
446
447/* DR steps **************************/
448Step
449drany_HTM = {
450 .shortname = "dr",
451 .name = "DR on any axis",
452
453 .final = false,
454 .is_done = check_drud,
455 .estimate = estimate_drud_HTM,
456 .ready = check_centers,
457 .ready_msg = check_centers_msg,
458 .is_valid = validate_singlecw_ending,
459 .moveset = &moveset_HTM,
460
461 .detect = detect_pretrans_void_3axis,
462
463 .tables = {&pd_drud_sym16_HTM},
464 .ntables = 1,
465};
466
467Step
468drud_HTM = {
469 .shortname = "drud",
470 .name = "DR on U/D",
471
472 .final = false,
473 .is_done = check_drud,
474 .estimate = estimate_drud_HTM,
475 .ready = check_centers,
476 .ready_msg = check_centers_msg,
477 .is_valid = validate_singlecw_ending,
478 .moveset = &moveset_HTM,
479
480 .pre_trans = uf,
481
482 .tables = {&pd_drud_sym16_HTM},
483 .ntables = 1,
484};
485
486Step
487drrl_HTM = {
488 .shortname = "drrl",
489 .name = "DR on R/L",
490
491 .final = false,
492 .is_done = check_drud,
493 .estimate = estimate_drud_HTM,
494 .ready = check_centers,
495 .ready_msg = check_centers_msg,
496 .is_valid = validate_singlecw_ending,
497 .moveset = &moveset_HTM,
498
499 .pre_trans = rf,
500
501 .tables = {&pd_drud_sym16_HTM},
502 .ntables = 1,
503};
504
505Step
506drfb_HTM = {
507 .shortname = "drfb",
508 .name = "DR on F/B",
509
510 .final = false,
511 .is_done = check_drud,
512 .estimate = estimate_drud_HTM,
513 .ready = check_centers,
514 .ready_msg = check_centers_msg,
515 .is_valid = validate_singlecw_ending,
516 .moveset = &moveset_HTM,
517
518 .pre_trans = fd,
519
520 .tables = {&pd_drud_sym16_HTM},
521 .ntables = 1,
522};
523
524/* DR from EO */
525Step
526dr_eo = {
527 .shortname = "dr-eo",
528 .name = "DR without breaking EO (automatically detected)",
529
530 .final = false,
531 .is_done = check_drud,
532 .estimate = estimate_dr_eofb,
533 .ready = check_eofb,
534 .ready_msg = check_eo_msg,
535 .is_valid = validate_singlecw_ending,
536 .moveset = &moveset_eofb,
537
538 .detect = detect_pretrans_eofb,
539
540 .tables = {&pd_drud_eofb},
541 .ntables = 1,
542};
543
544Step
545dr_eofb = {
546 .shortname = "dr-eofb",
547 .name = "DR on U/D or R/L without breaking EO on F/B",
548
549 .final = false,
550 .is_done = check_drud,
551 .estimate = estimate_dr_eofb,
552 .ready = check_eofb,
553 .ready_msg = check_eo_msg,
554 .is_valid = validate_singlecw_ending,
555 .moveset = &moveset_eofb,
556
557 .pre_trans = uf,
558
559 .tables = {&pd_drud_eofb},
560 .ntables = 1,
561};
562
563Step
564dr_eorl = {
565 .shortname = "dr-eorl",
566 .name = "DR on U/D or F/B without breaking EO on R/L",
567
568 .final = false,
569 .is_done = check_drud,
570 .estimate = estimate_dr_eofb,
571 .ready = check_eofb,
572 .ready_msg = check_eo_msg,
573 .is_valid = validate_singlecw_ending,
574 .moveset = &moveset_eofb,
575
576 .pre_trans = ur,
577
578 .tables = {&pd_drud_eofb},
579 .ntables = 1,
580};
581
582Step
583dr_eoud = {
584 .shortname = "dr-eoud",
585 .name = "DR on R/L or F/B without breaking EO on U/D",
586
587 .final = false,
588 .is_done = check_drud,
589 .estimate = estimate_dr_eofb,
590 .ready = check_eofb,
591 .ready_msg = check_eo_msg,
592 .is_valid = validate_singlecw_ending,
593 .moveset = &moveset_eofb,
594
595 .pre_trans = fd,
596
597 .tables = {&pd_drud_eofb},
598 .ntables = 1,
599};
600
601Step
602drud_eofb = {
603 .shortname = "drud-eofb",
604 .name = "DR on U/D without breaking EO on F/B",
605
606 .final = false,
607 .is_done = check_drud,
608 .estimate = estimate_drud_eofb,
609 .ready = check_eofb,
610 .ready_msg = check_eo_msg,
611 .is_valid = validate_singlecw_ending,
612 .moveset = &moveset_eofb,
613
614 .pre_trans = uf,
615
616 .tables = {&pd_drud_eofb},
617 .ntables = 1,
618};
619
620Step
621drrl_eofb = {
622 .shortname = "drrl-eofb",
623 .name = "DR on R/L without breaking EO on F/B",
624
625 .final = false,
626 .is_done = check_drud,
627 .estimate = estimate_drud_eofb,
628 .ready = check_eofb,
629 .ready_msg = check_eo_msg,
630 .is_valid = validate_singlecw_ending,
631 .moveset = &moveset_eofb,
632
633 .pre_trans = rf,
634
635 .tables = {&pd_drud_eofb},
636 .ntables = 1,
637};
638
639Step
640drud_eorl = {
641 .shortname = "drud-eorl",
642 .name = "DR on U/D without breaking EO on R/L",
643
644 .final = false,
645 .is_done = check_drud,
646 .estimate = estimate_drud_eofb,
647 .ready = check_eofb,
648 .ready_msg = check_eo_msg,
649 .is_valid = validate_singlecw_ending,
650 .moveset = &moveset_eofb,
651
652 .pre_trans = ur,
653
654 .tables = {&pd_drud_eofb},
655 .ntables = 1,
656};
657
658Step
659drfb_eorl = {
660 .shortname = "drfb-eorl",
661 .name = "DR on F/B without breaking EO on R/L",
662
663 .final = false,
664 .is_done = check_drud,
665 .estimate = estimate_drud_eofb,
666 .ready = check_eofb,
667 .ready_msg = check_eo_msg,
668 .is_valid = validate_singlecw_ending,
669 .moveset = &moveset_eofb,
670
671 .pre_trans = fr,
672
673 .tables = {&pd_drud_eofb},
674 .ntables = 1,
675};
676
677Step
678drfb_eoud = {
679 .shortname = "drfb-eoud",
680 .name = "DR on F/B without breaking EO on U/D",
681
682 .final = false,
683 .is_done = check_drud,
684 .estimate = estimate_drud_eofb,
685 .ready = check_eofb,
686 .ready_msg = check_eo_msg,
687 .is_valid = validate_singlecw_ending,
688 .moveset = &moveset_eofb,
689
690 .pre_trans = fd,
691
692 .tables = {&pd_drud_eofb},
693 .ntables = 1,
694};
695
696Step
697drrl_eoud = {
698 .shortname = "drrl-eoud",
699 .name = "DR on R/L without breaking EO on U/D",
700
701 .final = false,
702 .is_done = check_drud,
703 .estimate = estimate_drud_eofb,
704 .ready = check_eofb,
705 .ready_msg = check_eo_msg,
706 .is_valid = validate_singlecw_ending,
707 .moveset = &moveset_eofb,
708
709 .pre_trans = rd,
710
711 .tables = {&pd_drud_eofb},
712 .ntables = 1,
713};
714
715/* DR finish steps */
716Step
717dranyfin_DR = {
718 .shortname = "drfin",
719 .name = "DR finish on any axis without breaking DR",
720
721 .final = true,
722 .is_done = is_solved,
723 .estimate = estimate_drudfin_drud,
724 .ready = check_drud,
725 .ready_msg = check_drany_msg,
726 .is_valid = always_valid,
727 .moveset = &moveset_drud,
728
729 .detect = detect_pretrans_drud,
730
731 .tables = {&pd_drudfin_noE_sym16_drud},
732 .ntables = 1,
733};
734
735Step
736drudfin_drud = {
737 .shortname = "drudfin",
738 .name = "DR finish on U/D without breaking DR",
739
740 .final = true,
741 .is_done = is_solved,
742 .estimate = estimate_drudfin_drud,
743 .ready = check_drud,
744 .ready_msg = check_dr_msg,
745 .is_valid = always_valid,
746 .moveset = &moveset_drud,
747
748 .pre_trans = uf,
749
750 .tables = {&pd_drudfin_noE_sym16_drud},
751 .ntables = 1,
752};
753
754Step
755drrlfin_drrl = {
756 .shortname = "drrlfin",
757 .name = "DR finish on R/L without breaking DR",
758
759 .final = true,
760 .is_done = is_solved,
761 .estimate = estimate_drudfin_drud,
762 .ready = check_drud,
763 .ready_msg = check_dr_msg,
764 .is_valid = always_valid,
765 .moveset = &moveset_drud,
766
767 .pre_trans = rf,
768
769 .tables = {&pd_drudfin_noE_sym16_drud},
770 .ntables = 1,
771};
772
773Step
774drfbfin_drfb = {
775 .shortname = "drfbfin",
776 .name = "DR finish on F/B without breaking DR",
777
778 .final = true,
779 .is_done = is_solved,
780 .estimate = estimate_drudfin_drud,
781 .ready = check_drud,
782 .ready_msg = check_dr_msg,
783 .is_valid = always_valid,
784 .moveset = &moveset_drud,
785
786 .pre_trans = fd,
787
788 .tables = {&pd_drudfin_noE_sym16_drud},
789 .ntables = 1,
790};
791
792/* HTR from DR */
793Step
794htr_any = {
795 .shortname = "htr",
796 .name = "HTR from DR",
797
798 .final = false,
799 .is_done = check_htr,
800 .estimate = estimate_htr_drud,
801 .ready = check_drud,
802 .ready_msg = check_drany_msg,
803 .is_valid = validate_singlecw_ending,
804 .moveset = &moveset_drud,
805
806 .detect = detect_pretrans_drud,
807
808 .tables = {&pd_htr_drud},
809 .ntables = 1,
810};
811
812Step
813htr_drud = {
814 .shortname = "htr-drud",
815 .name = "HTR from DR on U/D",
816
817 .final = false,
818 .is_done = check_htr,
819 .estimate = estimate_htr_drud,
820 .ready = check_drud,
821 .ready_msg = check_dr_msg,
822 .is_valid = validate_singlecw_ending,
823 .moveset = &moveset_drud,
824
825 .pre_trans = uf,
826
827 .tables = {&pd_htr_drud},
828 .ntables = 1,
829};
830
831Step
832htr_drrl = {
833 .shortname = "htr-drrl",
834 .name = "HTR from DR on R/L",
835
836 .final = false,
837 .is_done = check_htr,
838 .estimate = estimate_htr_drud,
839 .ready = check_drud,
840 .ready_msg = check_dr_msg,
841 .is_valid = validate_singlecw_ending,
842 .moveset = &moveset_drud,
843
844 .pre_trans = rf,
845
846 .tables = {&pd_htr_drud},
847 .ntables = 1,
848};
849
850Step
851htr_drfb = {
852 .shortname = "htr-drfb",
853 .name = "HTR from DR on F/B",
854
855 .final = false,
856 .is_done = check_htr,
857 .estimate = estimate_htr_drud,
858 .ready = check_drud,
859 .ready_msg = check_dr_msg,
860 .is_valid = validate_singlecw_ending,
861 .moveset = &moveset_drud,
862
863 .pre_trans = fd,
864
865 .tables = {&pd_htr_drud},
866 .ntables = 1,
867};
868
869/* HTR finish */
870Step
871htrfin_htr = {
872 .shortname = "htrfin",
873 .name = "HTR finish without breaking HTR",
874
875 .final = true,
876 .is_done = is_solved,
877 .estimate = estimate_htrfin_htr,
878 .ready = check_htr,
879 .ready_msg = check_htr_msg,
880 .is_valid = always_valid,
881 .moveset = &moveset_htr,
882
883 .pre_trans = uf,
884
885 .tables = {&pd_htrfin_htr},
886 .ntables = 1,
887};
888
889Step *steps[] = {
890 &optimal_HTM, /* first is default */
891 &optimal_light_HTM,
892
893 &eofin_eo,
894 &eofbfin_eofb,
895 &eorlfin_eorl,
896 &eoudfin_eoud,
897
898 &eoany_HTM,
899 &eofb_HTM,
900 &eorl_HTM,
901 &eoud_HTM,
902
903 &coany_HTM,
904 &coud_HTM,
905 &corl_HTM,
906 &cofb_HTM,
907
908 &coany_URF,
909 &coud_URF,
910 &corl_URF,
911 &cofb_URF,
912
913 &drany_HTM,
914 &drud_HTM,
915 &drrl_HTM,
916 &drfb_HTM,
917
918 &dr_eo,
919 &dr_eofb,
920 &dr_eorl,
921 &dr_eoud,
922 &drud_eofb,
923 &drrl_eofb,
924 &drud_eorl,
925 &drfb_eorl,
926 &drfb_eoud,
927 &drrl_eoud,
928
929 &dranyfin_DR,
930 &drudfin_drud,
931 &drrlfin_drrl,
932 &drfbfin_drfb,
933
934 &htr_any,
935 &htr_drud,
936 &htr_drrl,
937 &htr_drfb,
938
939 &htrfin_htr,
940
941 &cornershtr_HTM,
942 &cornershtr_URF,
943 &corners_HTM,
944 &corners_URF,
945
946 NULL
947};
948
949/* Checkers and validators ***************************************************/
950
951static bool
952check_centers(Cube cube)
953{
954 return cube.cpos == 0;
955}
956
957static bool
958check_coud_HTM(Cube cube)
959{
960 return cube.coud == 0;
961}
962
963static bool
964check_coud_URF(Cube cube)
965{
966 Cube c2, c3;
967
968 c2 = apply_move(z, cube);
969 c3 = apply_move(x, cube);
970
971 return cube.coud == 0 || c2.coud == 0 || c3.coud == 0;
972}
973
974static bool
975check_corners_URF(Cube cube)
976{
977 Cube c;
978 Trans i;
979
980 for (i = 0; i < NROTATIONS; i++) {
981 c = apply_alg(rotation_alg(i), cube);
982 if (c.cp && c.coud)
983 return true;
984 }
985
986 return false;
987}
988
989static bool
990check_corners_HTM(Cube cube)
991{
992 return cube.cp == 0 && cube.coud == 0;
993}
994
995static bool
996check_cornershtr(Cube cube)
997{
998 return coord_cornershtr.index(cube) == 0;
999}
1000
1001static bool
1002check_eofb(Cube cube)
1003{
1004 return cube.eofb == 0;
1005}
1006
1007static bool
1008check_drud(Cube cube)
1009{
1010 return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0;
1011}
1012
1013static bool
1014check_htr(Cube cube)
1015{
1016 return check_drud(cube) && coord_htr_drud.index(cube) == 0;
1017}
1018
1019static bool
1020always_valid(Alg *alg)
1021{
1022 return true;
1023}
1024
1025static bool
1026validate_singlecw_ending(Alg *alg)
1027{
1028 int i;
1029 bool nor, inv;
1030 Move l2 = NULLMOVE, l1 = NULLMOVE, l2i = NULLMOVE, l1i = NULLMOVE;
1031
1032 for (i = 0; i < alg->len; i++) {
1033 if (alg->inv[i]) {
1034 l2i = l1i;
1035 l1i = alg->move[i];
1036 } else {
1037 l2 = l1;
1038 l1 = alg->move[i];
1039 }
1040 }
1041
1042 nor = l1 ==base_move(l1) && (!commute(l1, l2) ||l2 ==base_move(l2));
1043 inv = l1i==base_move(l1i) && (!commute(l1i,l2i)||l2i==base_move(l2i));
1044
1045 return nor && inv;
1046}
1047
1048/* Public functions **********************************************************/
1049
1050void
1051compute_ind(StepAlt *a, Cube *cube, uint64_t *ind)
1052{
1053
1054}
1055
1056int
1057estimate_stepalt(StepAlt *a, uint64_t *ind)
1058{
1059 int i, ret, est[a->n_coord];
1060
1061 for (i = 0; i < a->n_coord; i++) {
1062 est[i] = ptableval(a->pd[i], ind[i]);
1063 if (est[i] == 0 && a->compact_pd[i])
1064 est[i] = ptableval(a->fallback_pd, ind[i] / a->fbmod);
1065 }
1066
1067 for (i = 0; i < a->n_dbtrick; i++)
1068 if (est[a->dbtrick[i][0]] == est[a->dbtrick[i][1]] &&
1069 est[a->dbtrick[i][0]] == est[a->dbtrick[i][2]])
1070 est[a->dbtrick[i][0]] += 1;
1071
1072 for (i = 0, ret = -1; i < a->n_coord; i++)
1073 ret = max(ret, est[i]);
1074
1075 return ret;
1076}
1077
1078void
1079prepare_step(Step *step, SolveOptions *opts)
1080{
1081 int i, j;
1082 PDGenData pdg;
1083 StepAlt *a;
1084
1085 init_moveset(step->moveset);
1086 pdg.moveset = step->moveset;
1087
1088 for (i = 0; step->alt[i] != NULL; i++) {
1089 a = step->alt[i];
1090 for (j = 0; j < a->n_coord; j++) {
1091 gen_coord(a->coord[j]);
1092
1093 pdg.coord = a->coord[j];
1094 pdg.compact = a->compact[j];
1095 pdg.pd = NULL;
1096
1097 a->pd[j] = genptable(&pdg, opts->nthreads);
1098
1099 if (a->compact_pd[j]) {
1100 gen_coord(a->fallback_coord[j]);
1101
1102 pdg.coord = a->fallback_coord[j];
1103 pdg.compact = false;
1104 pdg.pd = NULL;
1105
1106 a->fallback_pd[j] =
1107 step->genptable(&pdg, opts->nthreads);
1108 }
1109 }
1110 }
1111}
diff --git a/old/solve_old.c b/old/solve_old.c
deleted file mode 100644
index 8662c9e..0000000
--- a/old/solve_old.c
+++ /dev/null
@@ -1,447 +0,0 @@
1#define SOLVE_C
2
3#include "solve.h"
4
5/* Local functions ***********************************************************/
6
7static void copy_dfsarg(DfsArg *src, DfsArg *dst);
8static void dfs(DfsArg *arg);
9static void dfs_add_sol(DfsArg *arg);
10static void dfs_niss(DfsArg *arg);
11static bool dfs_move_checkstop(DfsArg *arg);
12static void * instance_thread(void *arg);
13static void multidfs(DfsArg *arg);
14static bool niss_makes_sense(DfsArg *arg);
15static bool solvestop(int d, int op, SolveOptions *opts, AlgList *sols);
16
17/* Local functions ***********************************************************/
18
19static void
20copy_dfsarg(DfsArg *src, DfsArg *dst)
21{
22 int i;
23
24 dst->cube = src->cube;
25 dst->t = src->t;
26 dst->s = src->s;
27 dst->opts = src->opts;
28 dst->d = src->d;
29 dst->bound = src->bound; /* In theory not needed */
30 dst->niss = src->niss;
31 dst->sols = src->sols;
32 dst->sols_mutex = src->sols_mutex;
33 dst->current_alg = src->current_alg;
34
35 for (i = 0; i < src->s->n_coord; i++) {
36 dst->ind[i].val = src->ind[i].val;
37 dst->ind[i].t = src->ind[i].t;
38 }
39
40 src->s->copy_extra(src, dst);
41}
42
43static void
44dfs(DfsArg *arg)
45{
46 int i;
47 Move m, l0, l1;
48 DfsArg newarg;
49
50 if (dfs_move_checkstop(arg))
51 return;
52
53 if (arg->bound == 0) {
54 if (arg->current_alg->len == arg->d)
55 dfs_add_sol(arg);
56 return;
57 }
58
59 for (i = 0; arg->s->moveset->sorted_moves[i] != NULLMOVE; i++) {
60 m = arg->s->moveset->sorted_moves[i];
61 if (arg->s->moveset->can_append(arg->current_alg, m, arg->niss)
62 && compare_last(arg->current_alg, m, arg->niss) >= 0) {
63 copy_dfsarg(arg, &newarg);
64 append_move(arg->current_alg, m, newarg.niss);
65 dfs(&newarg);
66 remove_last_move(arg->current_alg);
67 }
68 }
69
70 if (niss_makes_sense(arg))
71 dfs_niss(arg);
72}
73
74static void
75dfs_add_sol(DfsArg *arg)
76{
77 bool valid, accepted, nisscanc;
78
79 valid = arg->s->is_valid==NULL || arg->s->is_valid(arg->current_alg);
80 accepted = valid || arg->opts->all;
81 nisscanc = arg->s->final &&
82 arg->s->moveset->cancel_niss(arg->current_alg);
83
84 if (accepted && !nisscanc) {
85 pthread_mutex_lock(arg->sols_mutex);
86
87 if (arg->sols->len < arg->opts->max_solutions) {
88 append_alg(arg->sols, arg->current_alg);
89 transform_alg(
90 inverse_trans(arg->t), arg->sols->last->alg);
91 if (arg->opts->verbose)
92 print_alg(arg->sols->last->alg, false);
93 }
94
95 pthread_mutex_unlock(arg->sols_mutex);
96 }
97}
98
99static void
100dfs_niss(DfsArg *arg)
101{
102 DfsArg newarg;
103 Alg *inv;
104 Cube *c;
105
106 copy_dfsarg(arg, &newarg);
107
108 /* Invert current alg and scramble */
109 newarg.cube = malloc(sizeof(Cube));
110 inv = inverse_alg(arg->current_alg);
111 c = malloc(sizeof(Cube));
112 make_solved(newarg.cube);
113 apply_alg(inv, newarg.cube);
114 copy_cube(arg->cube, c);
115 invert_cube(c);
116 compose(c, newarg.cube);
117
118 /* New indexes */
119 compute_ind(newarg.s, newarg.cube, newarg.ind);
120
121 newarg.niss = !(arg->niss);
122
123 dfs(&newarg);
124
125 free_alg(inv);
126 free(c);
127 free(newarg.cube);
128}
129
130static bool
131dfs_move_checkstop(DfsArg *arg)
132{
133 int i, goal, nsols;
134 Move mm;
135 Trans tt = uf; /* Avoid uninitialized warning */
136
137 /* Moving and computing bound */
138 arg->bound = 0;
139 goal = arg->d - arg->current_alg->len;
140 for (i = 0; i < arg->s->n_coord; i++) {
141 if (arg->last[0] != NULLMOVE) {
142 mm = transform_move(arg->ind[i].t, arg->last[0]);
143 arg->ind[i].val = move_coord(arg->s->coord[i],
144 mm, arg->ind[i].val, &tt);
145 arg->ind[i].t = transform_trans(tt, arg->ind[i].t);
146 }
147
148 arg->bound =
149 MAX(arg->bound, ptableval(arg->s->pd[i], arg->ind[i].val));
150 if (arg->opts->can_niss && !arg->niss)
151 arg->bound = MIN(1, arg->bound);
152
153 if (arg->bound > goal)
154 return true;
155 }
156
157 pthread_mutex_lock(arg->sols_mutex);
158 nsols = arg->sols->len;
159 pthread_mutex_unlock(arg->sols_mutex);
160
161 return nsols >= arg->opts->max_solutions;
162}
163
164static void *
165instance_thread(void *arg)
166{
167 bool b, inv;
168 Cube c;
169 Move m;
170 ThreadDataSolve *td;
171 AlgListNode *node;
172 DfsArg darg;
173
174 td = (ThreadDataSolve *)arg;
175
176 while (1) {
177 b = false;
178
179 pthread_mutex_lock(td->start_mutex);
180 if ((node = *(td->node)) == NULL)
181 b = true;
182 else
183 *(td->node) = (*(td->node))->next;
184 pthread_mutex_unlock(td->start_mutex);
185
186 if (b)
187 break;
188
189 inv = node->alg->inv[0];
190 m = node->alg->move[0];
191
192 copy_cube(td->arg.cube, &c);
193 if (inv)
194 invert_cube(&c);
195
196 copy_dfsarg(&td->arg, &darg);
197 compute_ind(td->arg.s, &c, darg.ind);
198 darg.cube = &c;
199
200 darg.niss = inv;
201 darg.current_alg = new_alg("");
202 append_move(darg.current_alg, m, inv);
203
204 dfs(&darg);
205
206 free_alg(darg.current_alg);
207 }
208
209 return NULL;
210}
211
212static void
213multidfs(DfsArg *arg)
214{
215 int i;
216 Cube local_cube;
217 Alg *alg;
218 AlgList *start;
219 AlgListNode **node;
220 pthread_t t[arg->opts->nthreads];
221 ThreadDataSolve td[arg->opts->nthreads];
222 pthread_mutex_t *start_mutex, *sols_mutex;
223
224 node = malloc(sizeof(AlgListNode *));
225 start_mutex = malloc(sizeof(pthread_mutex_t));
226 sols_mutex = malloc(sizeof(pthread_mutex_t));
227
228 start = new_alglist();
229 pthread_mutex_init(start_mutex, NULL);
230 pthread_mutex_init(sols_mutex, NULL);
231
232 for (i = 0; arg->s->moveset->sorted_moves[i] != NULLMOVE; i++) {
233 alg = new_alg("");
234 append_move(alg, arg->s->moveset->sorted_moves[i], false);
235 append_alg(start, alg);
236 if (arg->opts->can_niss && !arg->s->final) {
237 alg->inv[0] = true;
238 append_alg(start, alg);
239 }
240 free_alg(alg);
241 }
242 *node = start->first;
243
244 copy_cube(arg->cube, &local_cube);
245
246 for (i = 0; i < arg->opts->nthreads; i++) {
247 copy_dfsarg(arg, &(td[i].arg));
248 td[i].arg.cube = &local_cube;
249 td[i].arg.sols_mutex = sols_mutex;
250
251 td[i].thid = i;
252 td[i].start = start;
253 td[i].node = node;
254 td[i].start_mutex = start_mutex;
255
256 pthread_create(&t[i], NULL, instance_thread, &td[i]);
257 }
258
259 for (i = 0; i < arg->opts->nthreads; i++)
260 pthread_join(t[i], NULL);
261
262 free_alglist(start);
263 free(node);
264 free(start_mutex);
265 free(sols_mutex);
266}
267
268static bool
269niss_makes_sense(DfsArg *arg)
270{
271 Move m, mm;
272 uint64_t u;
273 int i;
274
275 if (arg->s->final || arg->niss || !arg->opts->can_niss)
276 return false;
277
278 if (arg->current_alg->len_normal == 0)
279 return true;
280
281 m = inverse_move(arg->last[0]);
282 for (i = 0; i < arg->s->n_coord; i++) {
283 mm = transform_move(arg->ind[i].t, m);
284 u = move_coord(arg->s->coord[i], mm, 0, NULL);
285 if (ptableval(arg->s->pd[i], u) > 0)
286 return true;
287 }
288
289 return false;
290}
291
292static bool
293solvestop(int d, int op, SolveOptions *opts, AlgList *sols)
294{
295 bool opt_done, max_moves_exceeded, max_sols_exceeded;
296
297 opt_done = opts->optimal != -1 && op != -1 && d > opts->optimal + op;
298 max_moves_exceeded = d > opts->max_moves;
299 max_sols_exceeded = sols->len >= opts->max_solutions;
300
301 return opt_done || max_moves_exceeded || max_sols_exceeded;
302}
303
304/* Public functions **********************************************************/
305
306AlgList *
307solve(Cube *cube, ChoiceStep *cs, SolveOptions *opts)
308{
309 int i, j, d, op, est;
310 bool ready[99], one_ready, zerosol;
311 Movable ind[99][10];
312 AlgList *s;
313 Cube *c[99];
314 DfsArg arg[99];
315
316 prepare_cs(cs, opts);
317 s = new_alglist();
318
319 for (i = 0, one_ready = false; cs->step[i] != NULL; i++) {
320 c[i] = malloc(sizeof(Cube));
321 copy_cube(cube, c[i]);
322 apply_trans(cs->t[i], c[i]);
323
324 arg[i].cube = c[i];
325 arg[i].t = cs->t[i];
326 arg[i].s = cs->step[i];
327 arg[i].opts = opts;
328 arg[i].sols = s;
329
330 if ((ready[i] = cs->step[i]->ready(c[i]))) {
331 one_ready = true;
332 /* Only for local use for 0 moves solutions */
333 compute_ind(cs->step[i], c[i], ind[i]);
334 }
335 }
336 if (!one_ready) {
337 fprintf(stderr, "Cube not ready for solving step: ");
338 fprintf(stderr, "%s\n", cs->ready_msg);
339 return s;
340 }
341
342 /* If the empty moves sequence is a solution for one of the
343 * alternatives, all longer solutions will be discarded, so we may
344 * just set its ready[] value to false. If the solution is accepted
345 * we append it and start searching from d = 1. */
346 for (i = 0, zerosol = false; cs->step[i] != NULL; i++) {
347 if (ready[i]) {
348 est = 0;
349 for (j = 0; j < cs->step[i]->n_coord; j++)
350 est = MAX(est, ptableval(cs->step[i]->pd[j],
351 ind[i][j].val));
352 if (est == 0) {
353 ready[i] = false;
354 zerosol = true;
355 }
356 }
357 }
358 if (zerosol && opts->min_moves == 0) {
359 append_alg(s, new_alg(""));
360 opts->min_moves = 1;
361 if (opts->verbose)
362 printf("Step is already solved"
363 "(empty alg is a solution)\n");
364 }
365
366 for (d = opts->min_moves, op = -1; !solvestop(d, op, opts, s); d++) {
367 if (opts->verbose)
368 fprintf(stderr, "Searching depth %d\n", d);
369
370 for (i=0; cs->step[i]!=NULL && !solvestop(d,op,opts,s); i++) {
371 if (!ready[i])
372 continue;
373
374 arg[i].d = d;
375 multidfs(&arg[i]);
376
377 if (s->len > 0 && op == -1)
378 op = d;
379 }
380 }
381
382 for (i = 0; cs->step[i] != NULL; i++)
383 free(c[i]);
384
385 return s;
386}
387
388/* TODO: make more general! */
389Alg *
390solve_2phase(Cube *cube, int nthreads)
391{
392 int bestlen, newb;
393 Alg *bestalg, *ret;
394 AlgList *sols1, *sols2;
395 AlgListNode *i;
396 Cube c;
397 SolveOptions opts1, opts2;
398
399 opts1.min_moves = 0;
400 opts1.max_moves = 13;
401 opts1.max_solutions = 20;
402 opts1.nthreads = nthreads;
403 opts1.optimal = 3;
404 opts1.can_niss = false;
405 opts1.verbose = false;
406 opts1.all = true;
407
408 opts2.min_moves = 0;
409 opts2.max_moves = 19;
410 opts2.max_solutions = 1;
411 opts2.nthreads = nthreads;
412 opts2.can_niss = false;
413 opts2.verbose = false;
414
415 /* We skip step1 if it is solved on U/D */
416 if (check_drud(cube)) {
417 sols1 = new_alglist();
418 append_alg(sols1, new_alg(""));
419 } else {
420 sols1 = solve(cube, &drud_HTM, &opts1);
421 }
422 bestalg = new_alg("");
423 bestlen = 999;
424 for (i = sols1->first; i != NULL; i = i->next) {
425 copy_cube(cube, &c);
426 apply_alg(i->alg, &c);
427 sols2 = solve(&c, &dranyfin_DR, &opts2);
428
429 if (sols2->len > 0) {
430 newb = i->alg->len + sols2->first->alg->len;
431 if (newb < bestlen) {
432 bestlen = newb;
433 copy_alg(i->alg, bestalg);
434 compose_alg(bestalg, sols2->first->alg);
435 }
436 }
437
438 free_alglist(sols2);
439 }
440
441 free_alglist(sols1);
442
443 ret = cleanup(bestalg);
444 free_alg(bestalg);
445
446 return ret;
447}
diff --git a/old/solve_old.h b/old/solve_old.h
deleted file mode 100644
index 010389e..0000000
--- a/old/solve_old.h
+++ /dev/null
@@ -1,9 +0,0 @@
1#ifndef SOLVE_H
2#define SOLVE_H
3
4#include "movesets.h"
5
6AlgList * solve(Cube *cube, ChoiceStep *cs, SolveOptions *opts);
7Alg * solve_2phase(Cube *cube, int nthreads);
8
9#endif
diff --git a/src/alg.c b/src/alg.c
index d806178..52bebc0 100644
--- a/src/alg.c
+++ b/src/alg.c
@@ -1,11 +1,112 @@
1#define ALG_C
2
3#include "alg.h" 1#include "alg.h"
4 2
3/* Local functions ***********************************************************/
4
5static bool allowed_HTM(Move m);
6static bool allowed_URF(Move m);
7static bool allowed_eofb(Move m);
8static bool allowed_drud(Move m);
9static bool allowed_htr(Move m);
10static bool allowed_next_HTM(Move l2, Move l1, Move m);
5static int axis(Move m); 11static int axis(Move m);
12
6static void free_alglistnode(AlgListNode *aln); 13static void free_alglistnode(AlgListNode *aln);
7static void realloc_alg(Alg *alg, int n); 14static void realloc_alg(Alg *alg, int n);
8 15
16/* Movesets ******************************************************************/
17
18Moveset
19moveset_HTM = {
20 .allowed = allowed_HTM,
21 .allowed_next = allowed_next_HTM,
22};
23
24Moveset
25moveset_URF = {
26 .allowed = allowed_URF,
27 .allowed_next = allowed_next_HTM,
28};
29
30Moveset
31moveset_eofb = {
32 .allowed = allowed_eofb,
33 .allowed_next = allowed_next_HTM,
34};
35
36Moveset
37moveset_drud = {
38 .allowed = allowed_drud,
39 .allowed_next = allowed_next_HTM,
40};
41
42Moveset
43moveset_htr = {
44 .allowed = allowed_htr,
45 .allowed_next = allowed_next_HTM,
46};
47
48static int nmoveset = 5;
49static Moveset * all_ms[] = {
50 &moveset_HTM,
51 &moveset_URF,
52 &moveset_eofb,
53 &moveset_drud,
54 &moveset_htr,
55};
56
57/* Functions *****************************************************************/
58
59static bool
60allowed_HTM(Move m)
61{
62 return m >= U && m <= B3;
63}
64
65static bool
66allowed_URF(Move m)
67{
68 Move b = base_move(m);
69
70 return b == U || b == R || b == F;
71}
72
73static bool
74allowed_eofb(Move m)
75{
76 Move b = base_move(m);
77
78 return b == U || b == D || b == R || b == L ||
79 ((b == F || b == B) && m == b+1);
80}
81
82static bool
83allowed_drud(Move m)
84{
85 Move b = base_move(m);
86
87 return b == U || b == D ||
88 ((b == R || b == L || b == F || b == B) && m == b + 1);
89}
90
91static bool
92allowed_htr(Move m)
93{
94 Move b = base_move(m);
95
96 return moveset_HTM.allowed(m) && m == b + 1;
97}
98
99static bool
100allowed_next_HTM(Move l2, Move l1, Move m)
101{
102 bool p, q;
103
104 p = l1 != NULLMOVE && base_move(l1) == base_move(m);
105 q = l2 != NULLMOVE && base_move(l2) == base_move(m);
106
107 return !(p || (commute(l1, l2) && q));
108}
109
9void 110void
10append_alg(AlgList *l, Alg *alg) 111append_alg(AlgList *l, Alg *alg)
11{ 112{
@@ -33,42 +134,30 @@ append_move(Alg *alg, Move m, bool inverse)
33 alg->move[alg->len] = m; 134 alg->move[alg->len] = m;
34 alg->inv [alg->len] = inverse; 135 alg->inv [alg->len] = inverse;
35 alg->len++; 136 alg->len++;
36
37 if (inverse)
38 alg->move_inverse[alg->len_inverse++] = m;
39 else
40 alg->move_normal[alg->len_normal++] = m;
41} 137}
42 138
43static int 139static int
44axis(Move m) 140axis(Move m)
45{ 141{
46 static int aux[] = { 142 if (m == NULLMOVE)
47 [NULLMOVE] = 0, 143 return 0;
48 144
49 [U] = 1, [U2] = 1, [U3] = 1, 145 if (m >= U && m <= B3)
50 [D] = 1, [D2] = 1, [D3] = 1, 146 return (m-1)/6 + 1;
51 [Uw] = 1, [Uw2] = 1, [Uw3] = 1, 147
52 [Dw] = 1, [Dw2] = 1, [Dw3] = 1, 148 if (m >= Uw && m <= Bw3)
53 [E] = 1, [E2] = 1, [E3] = 1, 149 return (m-1)/6 - 2;
54 [y] = 1, [y2] = 1, [y3] = 1,
55 150
56 [R] = 2, [R2] = 2, [R3] = 2, 151 if (base_move(m) == E || base_move(m) == y)
57 [L] = 2, [L2] = 2, [L3] = 2, 152 return 1;
58 [Rw] = 2, [Rw2] = 2, [Rw3] = 2,
59 [Lw] = 2, [Lw2] = 2, [Lw3] = 2,
60 [M] = 2, [M2] = 2, [M3] = 2,
61 [x] = 2, [x2] = 2, [x3] = 2,
62 153
63 [F] = 3, [F2] = 3, [F3] = 3, 154 if (base_move(m) == M || base_move(m) == x)
64 [B] = 3, [B2] = 3, [B3] = 3, 155 return 2;
65 [Fw] = 3, [Fw2] = 3, [Fw3] = 3, 156
66 [Bw] = 3, [Bw2] = 3, [Bw3] = 3, 157 if (base_move(m) == S || base_move(m) == z)
67 [S] = 3, [S2] = 3, [S3] = 3, 158 return 3;
68 [z] = 3, [z2] = 3, [z3] = 3,
69 };
70 159
71 return aux[m]; 160 return -1;
72} 161}
73 162
74Move 163Move
@@ -86,32 +175,6 @@ commute(Move m1, Move m2)
86 return axis(m1) == axis(m2); 175 return axis(m1) == axis(m2);
87} 176}
88 177
89int
90compare(Move m1, Move m2)
91{
92 if (!commute(m1, m2))
93 return 0;
94
95 return m1 < m2 ? 1 : -1;
96}
97
98int
99compare_last(Alg *alg, Move m, bool inverse)
100{
101 Move last;
102 int n;
103
104 if (inverse) {
105 n = alg->len_inverse;
106 last = n > 0 ? alg->move_inverse[n-1] : NULLMOVE;
107 } else {
108 n = alg->len_normal;
109 last = n > 0 ? alg->move_normal[n-1] : NULLMOVE;
110 }
111
112 return compare(last, m);
113}
114
115void 178void
116compose_alg(Alg *alg1, Alg *alg2) 179compose_alg(Alg *alg1, Alg *alg2)
117{ 180{
@@ -124,7 +187,7 @@ compose_alg(Alg *alg1, Alg *alg2)
124void 187void
125copy_alg(Alg *src, Alg *dst) 188copy_alg(Alg *src, Alg *dst)
126{ 189{
127 dst->len = dst->len_normal = dst->len_inverse = 0; 190 dst->len = 0; /* Overwrites */
128 compose_alg(dst, src); 191 compose_alg(dst, src);
129} 192}
130 193
@@ -156,6 +219,16 @@ free_alglistnode(AlgListNode *aln)
156 free(aln); 219 free(aln);
157} 220}
158 221
222void
223inplace(Alg * (*f)(Alg *), Alg *alg)
224{
225 Alg *aux;
226
227 aux = f(alg);
228 copy_alg(aux, alg);
229 free(aux);
230}
231
159Alg * 232Alg *
160inverse_alg(Alg *alg) 233inverse_alg(Alg *alg)
161{ 234{
@@ -211,14 +284,10 @@ new_alg(char *str)
211 Move j, m; 284 Move j, m;
212 285
213 alg = malloc(sizeof(Alg)); 286 alg = malloc(sizeof(Alg));
214 alg->allocated = 30; 287 alg->move = malloc(30 * sizeof(Move));
215 alg->move = malloc(alg->allocated * sizeof(Move)); 288 alg->inv = malloc(30 * sizeof(bool));
216 alg->inv = malloc(alg->allocated * sizeof(bool)); 289 alg->allocated = 30;
217 alg->move_normal = malloc(alg->allocated * sizeof(Move)); 290 alg->len = 0;
218 alg->move_inverse = malloc(alg->allocated * sizeof(Move));
219 alg->len = 0;
220 alg->len_normal = 0;
221 alg->len_inverse = 0;
222 291
223 niss = false; 292 niss = false;
224 for (i = 0; str[i]; i++) { 293 for (i = 0; str[i]; i++) {
@@ -227,13 +296,13 @@ new_alg(char *str)
227 296
228 if (str[i] == '(' && niss) { 297 if (str[i] == '(' && niss) {
229 fprintf(stderr, "Error reading moves: nested ( )\n"); 298 fprintf(stderr, "Error reading moves: nested ( )\n");
230 alg->len = alg->len_normal = alg->len_inverse = 0; 299 alg->len = 0;
231 return alg; 300 return alg;
232 } 301 }
233 302
234 if (str[i] == ')' && !niss) { 303 if (str[i] == ')' && !niss) {
235 fprintf(stderr, "Error reading moves: unmatched )\n"); 304 fprintf(stderr, "Error reading moves: unmatched )\n");
236 alg->len = alg->len_normal = alg->len_inverse = 0; 305 alg->len = 0;
237 return alg; 306 return alg;
238 } 307 }
239 308
@@ -300,7 +369,7 @@ new_alg(char *str)
300 369
301 if (niss) { 370 if (niss) {
302 fprintf(stderr, "Error reading moves: unmatched (\n"); 371 fprintf(stderr, "Error reading moves: unmatched (\n");
303 alg->len = alg->len_normal = alg->len_inverse = 0; 372 alg->len = 0;
304 } 373 }
305 374
306 return alg; 375 return alg;
@@ -385,25 +454,12 @@ realloc_alg(Alg *alg, int n)
385 fprintf(stderr, "something might go wrong.\n"); 454 fprintf(stderr, "something might go wrong.\n");
386 } 455 }
387 456
388 alg->move = realloc(alg->move, n * sizeof(int)); 457 alg->move = realloc(alg->move, n * sizeof(int));
389 alg->inv = realloc(alg->inv, n * sizeof(int)); 458 alg->inv = realloc(alg->inv, n * sizeof(int));
390 alg->move_normal = realloc(alg->move_normal, n * sizeof(int));
391 alg->move_inverse = realloc(alg->move_inverse, n * sizeof(int));
392 alg->allocated = n; 459 alg->allocated = n;
393} 460}
394 461
395void 462void
396remove_last_move(Alg *a)
397{
398 a->len--;
399
400 if (a->inv[a->len])
401 a->len_inverse--;
402 else
403 a->len_normal--;
404}
405
406void
407swapmove(Move *m1, Move *m2) 463swapmove(Move *m1, Move *m2)
408{ 464{
409 Move aux; 465 Move aux;
@@ -413,34 +469,6 @@ swapmove(Move *m1, Move *m2)
413 *m2 = aux; 469 *m2 = aux;
414} 470}
415 471
416char *
417trans_string(Trans t)
418{
419 static char trans_string_aux[NTRANS][20] = {
420 [uf] = "uf", [ur] = "ur", [ub] = "ub", [ul] = "ul",
421 [df] = "df", [dr] = "dr", [db] = "db", [dl] = "dl",
422 [rf] = "rf", [rd] = "rd", [rb] = "rb", [ru] = "ru",
423 [lf] = "lf", [ld] = "ld", [lb] = "lb", [lu] = "lu",
424 [fu] = "fu", [fr] = "fr", [fd] = "fd", [fl] = "fl",
425 [bu] = "bu", [br] = "br", [bd] = "bd", [bl] = "bl",
426
427 [uf_mirror] = "uf*", [ur_mirror] = "ur*",
428 [ub_mirror] = "ub*", [ul_mirror] = "ul*",
429 [df_mirror] = "df*", [dr_mirror] = "dr*",
430 [db_mirror] = "db*", [dl_mirror] = "dl*",
431 [rf_mirror] = "rf*", [rd_mirror] = "rd*",
432 [rb_mirror] = "rb*", [ru_mirror] = "ru*",
433 [lf_mirror] = "lf*", [ld_mirror] = "ld*",
434 [lb_mirror] = "lb*", [lu_mirror] = "lu*",
435 [fu_mirror] = "fu*", [fr_mirror] = "fr*",
436 [fd_mirror] = "fd*", [fl_mirror] = "fl*",
437 [bu_mirror] = "bu*", [br_mirror] = "br*",
438 [bd_mirror] = "bd*", [bl_mirror] = "bl*",
439 };
440
441 return trans_string_aux[t];
442}
443
444Alg * 472Alg *
445unniss(Alg *alg) 473unniss(Alg *alg)
446{ 474{
@@ -449,11 +477,48 @@ unniss(Alg *alg)
449 477
450 ret = new_alg(""); 478 ret = new_alg("");
451 479
452 for (i = 0; i < alg->len_normal; i++) 480 for (i = 0; i < alg->len; i++)
453 append_move(ret, alg->move_normal[i], false); 481 if (!alg->inv[i])
482 append_move(ret, alg->move[i], false);
483
484 for (i = alg->len-1; i >= 0; i--)
485 if (alg->inv[i])
486 append_move(ret, inverse_move(alg->move[i]), false);
487
488 return ret;
489}
454 490
455 for (i = 0; i < alg->len_inverse; i++) 491void
456 append_move(ret, inverse_move(alg->move_inverse[i]), false); 492init_moveset(Moveset *ms)
493{
494 int j;
495 uint64_t l, one;
496 Move m, l2, l1;
457 497
458 return ret; 498 one = 1;
499
500 for (j = 0, m = U; m < NMOVES; m++)
501 if (ms->allowed(m))
502 ms->sorted_moves[j++] = m;
503 ms->sorted_moves[j] = NULLMOVE;
504
505 for (l1 = 0; l1 < NMOVES; l1++) {
506 for (l2 = 0; l2 < NMOVES; l2++) {
507 ms->mask[l2][l1] = 0;
508 for (l=0; ms->sorted_moves[l]!=NULLMOVE; l++) {
509 m = ms->sorted_moves[l];
510 if (ms->allowed_next(l2, l1, m))
511 ms->mask[l2][l1] |= (one<<m);
512 }
513 }
514 }
515}
516
517void
518init_all_movesets()
519{
520 int i;
521
522 for (i = 0; i < nmoveset; i++)
523 init_moveset(all_ms[i]);
459} 524}
diff --git a/src/alg.h b/src/alg.h
index 967cd92..6bee26b 100644
--- a/src/alg.h
+++ b/src/alg.h
@@ -8,28 +8,36 @@
8#include "cubetypes.h" 8#include "cubetypes.h"
9#include "utils.h" 9#include "utils.h"
10 10
11extern Moveset moveset_HTM;
12extern Moveset moveset_URF;
13extern Moveset moveset_eofb;
14extern Moveset moveset_drud;
15extern Moveset moveset_htr;
16
11void append_alg(AlgList *l, Alg *alg); 17void append_alg(AlgList *l, Alg *alg);
12void append_move(Alg *alg, Move m, bool inverse); 18void append_move(Alg *alg, Move m, bool inverse);
13Move base_move(Move m); 19Move base_move(Move m);
14int compare(Move m1, Move m2); /* Return 1 (m1<m2), 0 or -1 (m1>m2) */
15int compare_last(Alg *alg, Move m, bool inverse);
16void compose_alg(Alg *alg1, Alg *alg2); 20void compose_alg(Alg *alg1, Alg *alg2);
17bool commute(Move m1, Move m2); 21bool commute(Move m1, Move m2);
18void copy_alg(Alg *src, Alg *dst); 22void copy_alg(Alg *src, Alg *dst);
19void free_alg(Alg *alg); 23void free_alg(Alg *alg);
20void free_alglist(AlgList *l); 24void free_alglist(AlgList *l);
25void inplace(Alg * (*f)(Alg *), Alg *alg);
21Alg * inverse_alg(Alg *alg); 26Alg * inverse_alg(Alg *alg);
22Move inverse_move(Move m); 27Move inverse_move(Move m);
23char * move_string(Move m); 28char * move_string(Move m);
29void movelist_to_position(Move *ml, int *pos);
30void moveset_to_list(Moveset ms, Move *lst);
24Alg * new_alg(char *str); 31Alg * new_alg(char *str);
25AlgList * new_alglist(); 32AlgList * new_alglist();
26Alg * on_inverse(Alg *alg); 33Alg * on_inverse(Alg *alg);
27void print_alg(Alg *alg, bool l); 34void print_alg(Alg *alg, bool l);
28void print_alglist(AlgList *al, bool l); 35void print_alglist(AlgList *al, bool l);
29void remove_last_move(Alg *alg);
30void swapmove(Move *m1, Move *m2); 36void swapmove(Move *m1, Move *m2);
31char * trans_string(Trans t); /* Here because similar to move_string, move? */
32Alg * unniss(Alg *alg); 37Alg * unniss(Alg *alg);
33 38
39void init_moveset(Moveset *ms);
40void init_all_movesets();
41
34#endif 42#endif
35 43
diff --git a/src/commands.c b/src/commands.c
index a9e8fc9..4d3ad50 100644
--- a/src/commands.c
+++ b/src/commands.c
@@ -1,11 +1,187 @@
1#define COMMANDS_C
2
3#include "commands.h" 1#include "commands.h"
4 2
5static bool read_cs(CommandArgs *args, char *str); 3/* Arg parsing functions *****************************************************/
4
5CommandArgs * gen_parse_args(int c, char **v);
6CommandArgs * help_parse_args(int c, char **v);
7CommandArgs * parse_only_scramble(int c, char **v);
8CommandArgs * parse_no_arg(int c, char **v);
9CommandArgs * solve_parse_args(int c, char **v);
10CommandArgs * scramble_parse_args(int c, char **v);
11
12/* Exec functions ************************************************************/
13
14static void gen_exec(CommandArgs *args);
15static void cleanup_exec(CommandArgs *args);
16static void invert_exec(CommandArgs *args);
17static void solve_exec(CommandArgs *args);
18static void scramble_exec(CommandArgs *args);
19static void steps_exec(CommandArgs *args);
20static void commands_exec(CommandArgs *args);
21static void freemem_exec(CommandArgs *args);
22static void print_exec(CommandArgs *args);
23static void twophase_exec(CommandArgs *args);
24static void help_exec(CommandArgs *args);
25static void quit_exec(CommandArgs *args);
26static void unniss_exec(CommandArgs *args);
27static void version_exec(CommandArgs *args);
28
29/* Local functions ***********************************************************/
30
31static bool read_step(CommandArgs *args, char *str);
6static bool read_scrtype(CommandArgs *args, char *str); 32static bool read_scrtype(CommandArgs *args, char *str);
7static bool read_scramble(int c, char **v, CommandArgs *args); 33static bool read_scramble(int c, char **v, CommandArgs *args);
8 34
35/* Commands ******************************************************************/
36
37Command
38solve_cmd = {
39 .name = "solve",
40 .usage = "solve STEP [OPTIONS] SCRAMBLE",
41 .description = "Solve a step; see command steps for a list of steps",
42 .parse_args = solve_parse_args,
43 .exec = solve_exec
44};
45
46Command
47scramble_cmd = {
48 .name = "scramble",
49 .usage = "scramble [TYPE] [-n N]",
50 .description = "Get a random-position scramble",
51 .parse_args = scramble_parse_args,
52 .exec = scramble_exec,
53};
54
55Command
56gen_cmd = {
57 .name = "gen",
58 .usage = "gen [-t N]",
59 .description = "Generate all tables [using N threads]",
60 .parse_args = gen_parse_args,
61 .exec = gen_exec
62};
63
64Command
65invert_cmd = {
66 .name = "invert",
67 .usage = "invert SCRAMBLE]",
68 .description = "Invert a scramble",
69 .parse_args = parse_only_scramble,
70 .exec = invert_exec,
71};
72
73Command
74steps_cmd = {
75 .name = "steps",
76 .usage = "steps",
77 .description = "List available steps",
78 .parse_args = parse_no_arg,
79 .exec = steps_exec
80};
81
82Command
83commands_cmd = {
84 .name = "commands",
85 .usage = "commands",
86 .description = "List available commands",
87 .parse_args = parse_no_arg,
88 .exec = commands_exec
89};
90
91Command
92freemem_cmd = {
93 .name = "freemem",
94 .usage = "freemem",
95 .description = "free large tables from RAM",
96 .parse_args = parse_no_arg,
97 .exec = freemem_exec,
98};
99
100Command
101print_cmd = {
102 .name = "print",
103 .usage = "print SCRAMBLE",
104 .description = "Print written description of the cube",
105 .parse_args = parse_only_scramble,
106 .exec = print_exec,
107};
108
109Command
110help_cmd = {
111 .name = "help",
112 .usage = "help [COMMAND]",
113 .description = "Display nissy manual page or help on specific command",
114 .parse_args = help_parse_args,
115 .exec = help_exec,
116};
117
118Command
119twophase_cmd = {
120 .name = "twophase",
121 .usage = "twophase",
122 .description = "Find a solution quickly using a 2-phase method",
123 .parse_args = parse_only_scramble,
124 .exec = twophase_exec,
125};
126
127Command
128quit_cmd = {
129 .name = "quit",
130 .usage = "quit",
131 .description = "Quit nissy",
132 .parse_args = parse_no_arg,
133 .exec = quit_exec,
134};
135
136Command
137cleanup_cmd = {
138 .name = "cleanup",
139 .usage = "cleanup SCRAMBLE",
140 .description = "Rewrite a scramble using only standard moves (HTM)",
141 .parse_args = parse_only_scramble,
142 .exec = cleanup_exec,
143};
144
145Command
146unniss_cmd = {
147 .name = "unniss",
148 .usage = "unniss SCRAMBLE",
149 .description = "Rewrite a scramble without NISS",
150 .parse_args = parse_only_scramble,
151 .exec = unniss_exec,
152};
153
154Command
155version_cmd = {
156 .name = "version",
157 .usage = "version",
158 .description = "print nissy version",
159 .parse_args = parse_no_arg,
160 .exec = version_exec,
161};
162
163Command *commands[] = {
164 &commands_cmd,
165 &freemem_cmd,
166 &gen_cmd,
167 &help_cmd,
168 &invert_cmd,
169 &print_cmd,
170 &quit_cmd,
171 &solve_cmd,
172 &scramble_cmd,
173 &steps_cmd,
174 &twophase_cmd,
175 &cleanup_cmd,
176 &unniss_cmd,
177 &version_cmd,
178 NULL
179};
180
181/* Other constants ***********************************************************/
182
183char *scrtypes[20] = { "eo", "corners", "edges", "fmc", "dr", "htr", NULL };
184
9/* Arg parsing functions implementation **************************************/ 185/* Arg parsing functions implementation **************************************/
10 186
11CommandArgs * 187CommandArgs *
@@ -95,7 +271,7 @@ solve_parse_args(int c, char **v)
95 a->opts->print_number = false; 271 a->opts->print_number = false;
96 } else if (!strcmp(v[i], "-c")) { 272 } else if (!strcmp(v[i], "-c")) {
97 a->opts->count_only = true; 273 a->opts->count_only = true;
98 } else if (!read_cs(a, v[i])) { 274 } else if (!read_step(a, v[i])) {
99 break; 275 break;
100 } 276 }
101 } 277 }
@@ -210,26 +386,17 @@ parse_no_arg(int c, char **v)
210 386
211/* Exec functions implementation *********************************************/ 387/* Exec functions implementation *********************************************/
212 388
213void 389static void
214solve_exec(CommandArgs *args) 390solve_exec(CommandArgs *args)
215{ 391{
216 Cube c; 392 Cube c;
217 AlgList *sols; 393 AlgList *sols;
218 Solver *solver[99];
219 Threader *threader;
220 394
221 make_solved(&c); 395 init_all_movesets();
222 apply_alg(args->scramble, &c); 396 init_symcoord();
223/* TODO: adjust */
224/* threader = &threader_single;*/
225 threader = &threader_eager;
226 397
227/* TODO: adjust */ 398 c = apply_alg(args->scramble, (Cube){0});
228 int i; 399 sols = solve(c, args->step, args->opts);
229 for (i = 0; args->cs->step[i] != NULL; i++)
230 solver[i] = new_stepsolver_lazy(args->cs->step[i]);
231 solver[i] = NULL;
232 sols = solve(&c, args->opts, solver, threader);
233 400
234 if (args->opts->count_only) 401 if (args->opts->count_only)
235 printf("%d\n", sols->len); 402 printf("%d\n", sols->len);
@@ -239,67 +406,85 @@ solve_exec(CommandArgs *args)
239 free_alglist(sols); 406 free_alglist(sols);
240} 407}
241 408
242void 409static void
243scramble_exec(CommandArgs *args) 410scramble_exec(CommandArgs *args)
244{ 411{
245 Cube cube; 412 Cube cube;
413 CubeArray *arr;
246 Alg *scr, *ruf, *aux; 414 Alg *scr, *ruf, *aux;
247 int i, j, eo, ep, co, cp; 415 int i, j, eo, ep, co, cp, a[12];
416 int eparr[12] = { [8] = 8, [9] = 9, [10] = 10, [11] = 11 };
248 uint64_t ui, uj, uk; 417 uint64_t ui, uj, uk;
249 418
419 init_all_movesets();
420 init_symcoord();
421
250 srand(time(NULL)); 422 srand(time(NULL));
251 423
252 for (i = 0; i < args->n; i++) { 424 for (i = 0; i < args->n; i++) {
253 425
254 if (!strcmp(args->scrtype, "dr")) { 426 if (!strcmp(args->scrtype, "dr")) {
255 ui = rand() % FACTORIAL8; 427 /* Warning: cube is inconsistent because of side CO *
256 uj = rand() % FACTORIAL8; 428 * and EO on U/D. But solve_2phase only solves drfin *
257 uk = rand() % FACTORIAL4; 429 * in this case, so it should be ok. *
430 * TODO: check this properly *
431 * Moreover we again need to fix parity after *
432 * generating epose manually */
433 do {
434 ui = rand() % FACTORIAL8;
435 uj = rand() % FACTORIAL8;
436 uk = rand() % FACTORIAL4;
437
438 index_to_perm(ui, 8, eparr);
439 arr = malloc(sizeof(CubeArray));
440 arr->ep = eparr;
441 cube = arrays_to_cube(arr, pf_ep);
442 free(arr);
258 443
259 make_solved(&cube); 444 cube.cp = uj;
260 index_to_perm(ui, 8, cube.cp); 445 cube.epose = uk;
261 index_to_perm(uj, 8, cube.ep); 446 } while (!is_admissible(cube));
262 index_to_perm(uk, 4, cube.ep + 8);
263 for (j = 8; j < 12; j++)
264 cube.ep[j] += 8;
265 } else if (!strcmp(args->scrtype, "htr")) { 447 } else if (!strcmp(args->scrtype, "htr")) {
266 make_solved(&cube); 448 /* antindex_htrfin() returns a consistent *
267 /* TODO */ 449 * cube, except possibly for parity */
450 do {
451 ui = rand() % (24*24/6);
452 cube = (Cube){0};
453 cube.cp = cornershtrfin_ant[ui];
454 cube.epose = rand() % 24;
455 cube.eposs = rand() % 24;
456 cube.eposm = rand() % 24;
457 } while (!is_admissible(cube));
268 } else { 458 } else {
269 ep = rand() % FACTORIAL12;
270 cp = rand() % FACTORIAL8;
271 eo = rand() % POW2TO11; 459 eo = rand() % POW2TO11;
460 ep = rand() % FACTORIAL12;
272 co = rand() % POW3TO7; 461 co = rand() % POW3TO7;
462 cp = rand() % FACTORIAL8;
273 463
274 if (!strcmp(args->scrtype, "eo")) { 464 if (!strcmp(args->scrtype, "eo")) {
275 eo = 0; 465 eo = 0;
276 } else if (!strcmp(args->scrtype, "corners")) { 466 } else if (!strcmp(args->scrtype, "corners")) {
277 eo = 0; 467 eo = 0;
278 ep = 0; 468 ep = 0;
469 index_to_perm(cp, 8, a);
470 if (perm_sign(a, 8) == 1) {
471 swap(&a[0], &a[1]);
472 cp = perm_to_index(a, 8);
473 }
279 } else if (!strcmp(args->scrtype, "edges")) { 474 } else if (!strcmp(args->scrtype, "edges")) {
280 co = 0; 475 co = 0;
281 cp = 0; 476 cp = 0;
477 index_to_perm(ep, 12, a);
478 if (perm_sign(a, 12) == 1) {
479 swap(&a[0], &a[1]);
480 ep = perm_to_index(a, 12);
481 }
282 } 482 }
283 483 cube = fourval_to_cube(eo, ep, co, cp);
284 make_solved(&cube);
285 index_to_perm(ep, 12, cube.ep);
286 index_to_perm(cp, 8, cube.cp);
287 int_to_sum_zero_array(eo, 2, 12, cube.eo);
288 int_to_sum_zero_array(co, 3, 8, cube.co);
289 }
290
291 if (!is_admissible(&cube)) {
292 if (!strcmp(args->scrtype, "corners"))
293 swap(&cube.cp[UFR], &cube.cp[UFL]);
294 else
295 swap(&cube.ep[UF], &cube.ep[UB]);
296 } 484 }
297 485
298 /* TODO: can be optimized for htr and dr using htrfin, drfin */ 486 /* TODO: can be optimized for htr and dr using htrfin, drfin */
299 /* 487 scr = solve_2phase(cube, 1);
300 TODO: solve_2phase was removed
301 scr = solve_2phase(&cube, 1);
302 */
303 488
304 if (!strcmp(args->scrtype, "fmc")) { 489 if (!strcmp(args->scrtype, "fmc")) {
305 aux = new_alg(""); 490 aux = new_alg("");
@@ -328,22 +513,23 @@ scramble_exec(CommandArgs *args)
328 } 513 }
329} 514}
330 515
331void 516static void
332gen_exec(CommandArgs *args) 517gen_exec(CommandArgs *args)
333{ 518{
334/* TODO:
335 int i; 519 int i;
336 520
337 fprintf(stderr, "Generating coordinates...\n"); 521 fprintf(stderr, "Generating coordinates...\n");
522 init_all_movesets();
523 init_symcoord();
524
338 fprintf(stderr, "Generating pruning tables...\n"); 525 fprintf(stderr, "Generating pruning tables...\n");
339 for (i = 0; all_pd[i] != NULL; i++) 526 for (i = 0; all_pd[i] != NULL; i++)
340 genptable(all_pd[i], args->opts->nthreads); 527 genptable(all_pd[i], args->opts->nthreads);
341*/
342 528
343 fprintf(stderr, "Done!\n"); 529 fprintf(stderr, "Done!\n");
344} 530}
345 531
346void 532static void
347invert_exec(CommandArgs *args) 533invert_exec(CommandArgs *args)
348{ 534{
349 Alg *inv; 535 Alg *inv;
@@ -354,16 +540,16 @@ invert_exec(CommandArgs *args)
354 free_alg(inv); 540 free_alg(inv);
355} 541}
356 542
357void 543static void
358steps_exec(CommandArgs *args) 544steps_exec(CommandArgs *args)
359{ 545{
360 int i; 546 int i;
361 547
362 for (i = 0; csteps[i] != NULL; i++) 548 for (i = 0; steps[i] != NULL; i++)
363 printf("%-15s %s\n", csteps[i]->shortname, csteps[i]->name); 549 printf("%-15s %s\n", steps[i]->shortname, steps[i]->name);
364} 550}
365 551
366void 552static void
367commands_exec(CommandArgs *args) 553commands_exec(CommandArgs *args)
368{ 554{
369 int i; 555 int i;
@@ -373,10 +559,9 @@ commands_exec(CommandArgs *args)
373 559
374} 560}
375 561
376void 562static void
377freemem_exec(CommandArgs *args) 563freemem_exec(CommandArgs *args)
378{ 564{
379/* TODO:
380 int i; 565 int i;
381 566
382 for (i = 0; all_pd[i] != NULL; i++) 567 for (i = 0; all_pd[i] != NULL; i++)
@@ -384,36 +569,35 @@ freemem_exec(CommandArgs *args)
384 569
385 for (i = 0; all_sd[i] != NULL; i++) 570 for (i = 0; all_sd[i] != NULL; i++)
386 free_sd(all_sd[i]); 571 free_sd(all_sd[i]);
387*/ 572
573 /* TODO: invtables are also large, but for now they are *
574 * statically allocated. Consider releasing those too. */
388} 575}
389 576
390void 577static void
391print_exec(CommandArgs *args) 578print_exec(CommandArgs *args)
392{ 579{
393 Cube c; 580 init_moves();
394 581 print_cube(apply_alg(args->scramble, (Cube){0}));
395 make_solved(&c);
396 apply_alg(args->scramble, &c);
397 print_cube(&c);
398} 582}
399 583
400/* 584static void
401void
402twophase_exec(CommandArgs *args) 585twophase_exec(CommandArgs *args)
403{ 586{
404 Cube c; 587 Cube c;
405 Alg *sol; 588 Alg *sol;
406 589
407 make_solved(&c); 590 init_all_movesets();
408 apply_alg(args->scramble, &c); 591 init_symcoord();
409 sol = solve_2phase(&c, 1); 592
593 c = apply_alg(args->scramble, (Cube){0});
594 sol = solve_2phase(c, 1);
410 595
411 print_alg(sol, false); 596 print_alg(sol, false);
412 free_alg(sol); 597 free_alg(sol);
413} 598}
414*/
415 599
416void 600static void
417help_exec(CommandArgs *args) 601help_exec(CommandArgs *args)
418{ 602{
419 if (args->command == NULL) { 603 if (args->command == NULL) {
@@ -427,7 +611,7 @@ help_exec(CommandArgs *args)
427 " system (such as Linux or MacOS) or in pdf and html" 611 " system (such as Linux or MacOS) or in pdf and html"
428 " format in the docs folder.\n" 612 " format in the docs folder.\n"
429 "Nissy is available for free at " 613 "Nissy is available for free at "
430 "https://nissy.tronto.net\n" 614 "https://github.com/sebastianotronto/nissy\n"
431 ); 615 );
432 } else { 616 } else {
433 printf("Command %s: %s\nusage: %s\n", args->command->name, 617 printf("Command %s: %s\nusage: %s\n", args->command->name,
@@ -435,24 +619,26 @@ help_exec(CommandArgs *args)
435 } 619 }
436} 620}
437 621
438void 622static void
439quit_exec(CommandArgs *args) 623quit_exec(CommandArgs *args)
440{ 624{
441 exit(0); 625 exit(0);
442} 626}
443 627
444void 628static void
445cleanup_exec(CommandArgs *args) 629cleanup_exec(CommandArgs *args)
446{ 630{
447 Alg *alg; 631 Alg *alg;
448 632
633 init_moves();
634
449 alg = cleanup(args->scramble); 635 alg = cleanup(args->scramble);
450 print_alg(alg, false); 636 print_alg(alg, false);
451 637
452 free_alg(alg); 638 free_alg(alg);
453} 639}
454 640
455void 641static void
456unniss_exec(CommandArgs *args) 642unniss_exec(CommandArgs *args)
457{ 643{
458 Alg *aux; 644 Alg *aux;
@@ -462,7 +648,7 @@ unniss_exec(CommandArgs *args)
462 free(aux); 648 free(aux);
463} 649}
464 650
465void 651static void
466version_exec(CommandArgs *args) 652version_exec(CommandArgs *args)
467{ 653{
468 printf(VERSION"\n"); 654 printf(VERSION"\n");
@@ -505,8 +691,6 @@ static bool
505read_scrtype(CommandArgs *args, char *str) 691read_scrtype(CommandArgs *args, char *str)
506{ 692{
507 int i; 693 int i;
508 static char *scrtypes[20] =
509 { "eo", "corners", "edges", "fmc", "dr", "htr", NULL };
510 694
511 for (i = 0; scrtypes[i] != NULL; i++) { 695 for (i = 0; scrtypes[i] != NULL; i++) {
512 if (!strcmp(scrtypes[i], str)) { 696 if (!strcmp(scrtypes[i], str)) {
@@ -519,13 +703,13 @@ read_scrtype(CommandArgs *args, char *str)
519} 703}
520 704
521static bool 705static bool
522read_cs(CommandArgs *args, char *str) 706read_step(CommandArgs *args, char *str)
523{ 707{
524 int i; 708 int i;
525 709
526 for (i = 0; csteps[i] != NULL; i++) { 710 for (i = 0; steps[i] != NULL; i++) {
527 if (!strcmp(csteps[i]->shortname, str)) { 711 if (!strcmp(steps[i]->shortname, str)) {
528 args->cs = csteps[i]; 712 args->step = steps[i];
529 return true; 713 return true;
530 } 714 }
531 } 715 }
@@ -562,7 +746,7 @@ new_args()
562 args->opts = malloc(sizeof(SolveOptions)); 746 args->opts = malloc(sizeof(SolveOptions));
563 747
564 /* step and command are static */ 748 /* step and command are static */
565 args->cs = csteps[0]; /* default: first step in list */ 749 args->step = steps[0]; /* default: first step in list */
566 args->command = NULL; 750 args->command = NULL;
567 751
568 return args; 752 return args;
diff --git a/src/commands.h b/src/commands.h
index 65708e0..b7a4c36 100644
--- a/src/commands.h
+++ b/src/commands.h
@@ -5,207 +5,10 @@
5 5
6#include "solve.h" 6#include "solve.h"
7#include "steps.h" 7#include "steps.h"
8#include "solver_step.h"
9#include "threader_single.h"
10#include "threader_eager.h"
11 8
12void free_args(CommandArgs *args); 9void free_args(CommandArgs *args);
13CommandArgs * new_args(); 10CommandArgs * new_args();
14 11
15/* Arg parsing functions *****************************************************/ 12extern Command * commands[];
16
17CommandArgs * gen_parse_args(int c, char **v);
18CommandArgs * help_parse_args(int c, char **v);
19CommandArgs * parse_only_scramble(int c, char **v);
20CommandArgs * parse_no_arg(int c, char **v);
21CommandArgs * solve_parse_args(int c, char **v);
22CommandArgs * scramble_parse_args(int c, char **v);
23
24/* Exec functions ************************************************************/
25
26void gen_exec(CommandArgs *args);
27void cleanup_exec(CommandArgs *args);
28void invert_exec(CommandArgs *args);
29void solve_exec(CommandArgs *args);
30void scramble_exec(CommandArgs *args);
31void steps_exec(CommandArgs *args);
32void commands_exec(CommandArgs *args);
33void freemem_exec(CommandArgs *args);
34void print_exec(CommandArgs *args);
35/*void twophase_exec(CommandArgs *args);*/
36void help_exec(CommandArgs *args);
37void quit_exec(CommandArgs *args);
38void unniss_exec(CommandArgs *args);
39void version_exec(CommandArgs *args);
40
41/* Commands ******************************************************************/
42
43#ifndef COMMANDS_C
44
45extern Command cleanup_cmd;
46extern Command commands_cmd;
47extern Command freemem_cmd;
48extern Command gen_cmd;
49extern Command help_cmd;
50extern Command invert_cmd;
51extern Command print_cmd;
52extern Command quit_cmd;
53extern Command scramble_cmd;
54extern Command solve_cmd;
55extern Command steps_cmd;
56extern Command unniss_cmd;
57extern Command version_cmd;
58
59extern Command *commands[];
60
61#else
62
63Command
64solve_cmd = {
65 .name = "solve",
66 .usage = "solve STEP [OPTIONS] SCRAMBLE",
67 .description = "Solve a step; see command steps for a list of steps",
68 .parse_args = solve_parse_args,
69 .exec = solve_exec
70};
71
72Command
73scramble_cmd = {
74 .name = "scramble",
75 .usage = "scramble [TYPE] [-n N]",
76 .description = "Get a random-position scramble",
77 .parse_args = scramble_parse_args,
78 .exec = scramble_exec,
79};
80
81Command
82gen_cmd = {
83 .name = "gen",
84 .usage = "gen [-t N]",
85 .description = "Generate all tables [using N threads]",
86 .parse_args = gen_parse_args,
87 .exec = gen_exec
88};
89
90Command
91invert_cmd = {
92 .name = "invert",
93 .usage = "invert SCRAMBLE]",
94 .description = "Invert a scramble",
95 .parse_args = parse_only_scramble,
96 .exec = invert_exec,
97};
98
99Command
100steps_cmd = {
101 .name = "steps",
102 .usage = "steps",
103 .description = "List available steps",
104 .parse_args = parse_no_arg,
105 .exec = steps_exec
106};
107
108Command
109commands_cmd = {
110 .name = "commands",
111 .usage = "commands",
112 .description = "List available commands",
113 .parse_args = parse_no_arg,
114 .exec = commands_exec
115};
116
117Command
118freemem_cmd = {
119 .name = "freemem",
120 .usage = "freemem",
121 .description = "free large tables from RAM",
122 .parse_args = parse_no_arg,
123 .exec = freemem_exec,
124};
125
126Command
127print_cmd = {
128 .name = "print",
129 .usage = "print SCRAMBLE",
130 .description = "Print written description of the cube",
131 .parse_args = parse_only_scramble,
132 .exec = print_exec,
133};
134
135Command
136help_cmd = {
137 .name = "help",
138 .usage = "help [COMMAND]",
139 .description = "Display nissy manual page or help on specific command",
140 .parse_args = help_parse_args,
141 .exec = help_exec,
142};
143
144/*
145Command
146twophase_cmd = {
147 .name = "twophase",
148 .usage = "twophase",
149 .description = "Find a solution quickly using a 2-phase method",
150 .parse_args = parse_only_scramble,
151 .exec = twophase_exec,
152};
153*/
154
155Command
156quit_cmd = {
157 .name = "quit",
158 .usage = "quit",
159 .description = "Quit nissy",
160 .parse_args = parse_no_arg,
161 .exec = quit_exec,
162};
163
164Command
165cleanup_cmd = {
166 .name = "cleanup",
167 .usage = "cleanup SCRAMBLE",
168 .description = "Rewrite a scramble using only standard moves (HTM)",
169 .parse_args = parse_only_scramble,
170 .exec = cleanup_exec,
171};
172
173Command
174unniss_cmd = {
175 .name = "unniss",
176 .usage = "unniss SCRAMBLE",
177 .description = "Rewrite a scramble without NISS",
178 .parse_args = parse_only_scramble,
179 .exec = unniss_exec,
180};
181
182Command
183version_cmd = {
184 .name = "version",
185 .usage = "version",
186 .description = "print nissy version",
187 .parse_args = parse_no_arg,
188 .exec = version_exec,
189};
190
191Command *commands[] = {
192 &commands_cmd,
193 &freemem_cmd,
194 &gen_cmd,
195 &help_cmd,
196 &invert_cmd,
197 &print_cmd,
198 &quit_cmd,
199 &solve_cmd,
200 &scramble_cmd,
201 &steps_cmd,
202/* &twophase_cmd,*/
203 &cleanup_cmd,
204 &unniss_cmd,
205 &version_cmd,
206 NULL
207};
208
209#endif
210 13
211#endif 14#endif
diff --git a/src/coord.c b/src/coord.c
index 673434f..a9df9fd 100644
--- a/src/coord.c
+++ b/src/coord.c
@@ -1,654 +1,611 @@
1#define COORD_C
2
3#include "coord.h" 1#include "coord.h"
4 2
5static void gen_coord_comp(Coordinate *coord); 3static uint64_t index_eofb(Cube cube);
6static void gen_coord_sym(Coordinate *coord); 4static uint64_t index_eofbepos(Cube cube);
7static bool read_coord_mtable(Coordinate *coord); 5static uint64_t index_epud(Cube cube);
8static bool read_coord_sd(Coordinate *coord); 6static uint64_t index_coud(Cube cube);
9static bool read_coord_ttable(Coordinate *coord); 7static uint64_t index_corners(Cube cube);
10static bool write_coord_mtable(Coordinate *coord); 8static uint64_t index_cp(Cube cube);
11static bool write_coord_sd(Coordinate *coord); 9static uint64_t index_cphtr(Cube cube);
12static bool write_coord_ttable(Coordinate *coord); 10static uint64_t index_cornershtr(Cube cube);
11static uint64_t index_cornershtrfin(Cube cube);
12static uint64_t index_drud(Cube cube);
13static uint64_t index_drud_eofb(Cube cube);
14static uint64_t index_htr_drud(Cube cube);
15static uint64_t index_htrfin(Cube cube);
16static uint64_t index_cpud_separate(Cube cube);
13 17
14/* Indexers ******************************************************************/ 18static uint64_t move_eofb(Move m, uint64_t ind);
19static uint64_t move_eofbepos(Move m, uint64_t ind);
20static uint64_t move_epud(Move m, uint64_t ind);
21static uint64_t move_coud(Move m, uint64_t ind);
22static uint64_t move_corners(Move m, uint64_t ind);
23static uint64_t move_cp(Move m, uint64_t ind);
24static uint64_t move_cphtr(Move m, uint64_t ind);
25static uint64_t move_cornershtr(Move m, uint64_t ind);
26static uint64_t move_cornershtrfin(Move m, uint64_t ind);
27static uint64_t move_drud(Move m, uint64_t ind);
28static uint64_t move_drud_eofb(Move m, uint64_t ind);
29static uint64_t move_htr_drud(Move m, uint64_t ind);
30static uint64_t move_htrfin(Move m, uint64_t ind);
31static uint64_t move_cpud_separate(Move m, uint64_t ind);
15 32
16uint64_t 33static void init_cphtr_cosets();
17index_eofb(Cube *cube) 34static void init_cphtr_left_cosets_bfs(int i, int c);
18{ 35static void init_cphtr_right_cosets_color(int i, int c);
19 return (uint64_t)digit_array_to_int(cube->eo, 11, 2); 36static void init_cpud_separate();
20} 37static void init_cornershtrfin();
38static void init_htr_eposs();
21 39
22uint64_t
23index_coud(Cube *cube)
24{
25 return (uint64_t)digit_array_to_int(cube->co, 7, 3);
26}
27 40
28uint64_t 41/* All sorts of useful costants and tables **********************************/
29index_cp(Cube *cube)
30{
31 return (uint64_t)perm_to_index(cube->cp, 8);
32}
33 42
34uint64_t 43static int cphtr_left_cosets[FACTORIAL8];
35index_cpudsep(Cube *cube) 44static int cphtr_right_cosets[FACTORIAL8];
36{ 45static int cphtr_right_rep[BINOM8ON4*6];
37 int i, c[8]; 46int cpud_separate_ind[FACTORIAL8];
47int cpud_separate_ant[BINOM8ON4];
48static int cornershtrfin_ind[FACTORIAL8];
49int cornershtrfin_ant[24*24/6];
50static int htr_eposs_ind[BINOM12ON4];
51static int htr_eposs_ant[BINOM8ON4];
38 52
39 for (i = 0; i < 8; i++) 53/* Coordinates and their implementation **************************************/
40 c[i] = cube->cp[i] < 4 ? 0 : 1;
41 54
42 return (uint64_t)subset_to_index(c, 8, 4); 55Coordinate
43} 56coord_eofb = {
57 .index = index_eofb,
58 .max = POW2TO11,
59 .move = move_eofb,
60};
44 61
45uint64_t 62Coordinate
46index_epe(Cube *cube) 63coord_eofbepos = {
47{ 64 .index = index_eofbepos,
48 int i, e[4]; 65 .max = POW2TO11 * BINOM12ON4,
66 .move = move_eofbepos,
67};
49 68
50 for (i = 0; i < 4; i++) 69Coordinate
51 e[i] = cube->ep[i+8] - 8; 70coord_coud = {
71 .index = index_coud,
72 .max = POW3TO7,
73 .move = move_coud,
74};
52 75
53 return (uint64_t)perm_to_index(e, 4); 76Coordinate
54} 77coord_corners = {
78 .index = index_corners,
79 .max = POW3TO7 * FACTORIAL8,
80 .move = move_corners,
81};
55 82
56uint64_t 83Coordinate
57index_epud(Cube *cube) 84coord_cp = {
58{ 85 .index = index_cp,
59 return (uint64_t)perm_to_index(cube->ep, 8); 86 .max = FACTORIAL8,
60} 87 .move = move_cp,
88};
61 89
62uint64_t 90Coordinate
63index_epos(Cube *cube) 91coord_cphtr = {
64{ 92 .index = index_cphtr,
65 int i, a[12]; 93 .max = BINOM8ON4 * 6,
94 .move = move_cphtr,
95};
66 96
67 for (i = 0; i < 12; i++) 97Coordinate
68 a[i] = (cube->ep[i] < 8) ? 0 : 1; 98coord_cornershtr = {
99 .index = index_cornershtr,
100 .max = POW3TO7 * BINOM8ON4 * 6,
101 .move = move_cornershtr,
102};
69 103
70 return (uint64_t)subset_to_index(a, 12, 4); 104Coordinate
71} 105coord_cornershtrfin = {
106 .index = index_cornershtrfin,
107 .max = 24*24/6,
108 .move = move_cornershtrfin,
109};
72 110
73uint64_t 111Coordinate
74index_eposepe(Cube *cube) 112coord_epud = {
75{ 113 .index = index_epud,
76 int i, j, e[4]; 114 .max = FACTORIAL8,
77 uint64_t epos, epe; 115 .move = move_epud,
116};
78 117
79 epos = (uint64_t)index_epos(cube); 118Coordinate
80 for (i = 0, j = 0; i < 12; i++) 119coord_drud = {
81 if (cube->ep[i] >= 8) 120 .index = index_drud,
82 e[j++] = cube->ep[i] - 8; 121 .max = POW2TO11 * POW3TO7 * BINOM12ON4,
83 epe = (uint64_t)perm_to_index(e, 4); 122 .move = move_drud,
123};
84 124
85 return epos * FACTORIAL4 + epe; 125Coordinate
86} 126coord_htr_drud = {
127 .index = index_htr_drud,
128 .max = BINOM8ON4 * 6 * BINOM8ON4,
129 .move = move_htr_drud,
130};
87 131
88/* Inverse indexers **********************************************************/ 132Coordinate
133coord_htrfin = {
134 .index = index_htrfin,
135 .max = 24 * 24 * 24 *24 * 24 / 6, /* should be /12 but it's ok */
136 .move = move_htrfin,
137};
89 138
90void 139Coordinate
91invindex_eofb(uint64_t ind, Cube *cube) 140coord_drud_eofb = {
92{ 141 .index = index_drud_eofb,
93 int_to_sum_zero_array(ind, 2, 12, cube->eo); 142 .max = POW3TO7 * BINOM12ON4,
94} 143 .move = move_drud_eofb,
144};
95 145
96void 146Coordinate
97invindex_coud(uint64_t ind, Cube *cube) 147coord_cpud_separate = {
148 .index = index_cpud_separate,
149 .max = BINOM8ON4,
150 .move = move_cpud_separate,
151};
152
153/* Indexers ******************************************************************/
154
155static uint64_t
156index_eofb(Cube cube)
98{ 157{
99 int_to_sum_zero_array(ind, 3, 8, cube->co); 158 return cube.eofb;
100} 159}
101 160
102void 161static uint64_t
103invindex_cp(uint64_t ind, Cube *cube) 162index_eofbepos(Cube cube)
104{ 163{
105 index_to_perm(ind, 8, cube->cp); 164 return (cube.epose / FACTORIAL4) * POW2TO11 + cube.eofb;
106} 165}
107 166
108void 167static uint64_t
109invindex_cpudsep(uint64_t ind, Cube *cube) 168index_epud(Cube cube)
110{ 169{
111 int i, j, k, c[8]; 170 uint64_t ret;
171 CubeArray *arr = new_cubearray(cube, pf_ep);
112 172
113 index_to_subset(ind, 8, 4, c); 173 ret = perm_to_index(arr->ep, 8);
114 for (i = 0, j = 0, k = 4; i < 8; i++) 174 free_cubearray(arr, pf_ep);
115 cube->cp[i] = c[i] == 0 ? j++ : k++; 175
176 return ret;
116} 177}
117 178
179static uint64_t
180index_coud(Cube cube)
181{
182 return cube.coud;
183}
118 184
119void 185static uint64_t
120invindex_epe(uint64_t ind, Cube *cube) 186index_corners(Cube cube)
121{ 187{
122 int i; 188 return cube.coud * FACTORIAL8 + cube.cp;
189}
123 190
124 index_to_perm(ind, 4, &cube->ep[8]); 191static uint64_t
125 for (i = 0; i < 4; i++) 192index_cp(Cube cube)
126 cube->ep[i+8] += 8; 193{
194 return cube.cp;
127} 195}
128 196
129void 197static uint64_t
130invindex_epud(uint64_t ind, Cube *cube) 198index_cphtr(Cube cube)
131{ 199{
132 index_to_perm(ind, 8, cube->ep); 200 return cphtr_right_cosets[cube.cp];
133} 201}
134 202
135void 203static uint64_t
136invindex_epos(uint64_t ind, Cube *cube) 204index_cornershtr(Cube cube)
137{ 205{
138 int i, j, k; 206 return cube.coud * BINOM8ON4 * 6 + index_cphtr(cube);
207}
139 208
140 index_to_subset(ind, 12, 4, cube->ep); 209static uint64_t
141 for (i = 0, j = 0, k = 8; i < 12; i++) 210index_cornershtrfin(Cube cube)
142 if (cube->ep[i] == 0) 211{
143 cube->ep[i] = j++; 212 return cornershtrfin_ind[cube.cp];
144 else
145 cube->ep[i] = k++;
146} 213}
147 214
148void 215static uint64_t
149invindex_eposepe(uint64_t ind, Cube *cube) 216index_drud(Cube cube)
150{ 217{
151 int i, j, k, e[4]; 218 uint64_t a, b, c;
152 uint64_t epos, epe;
153 219
154 epos = ind / FACTORIAL4; 220 a = cube.eofb;
155 epe = ind % FACTORIAL4; 221 b = cube.coud;
222 c = cube.epose / FACTORIAL4;
156 223
157 index_to_subset(epos, 12, 4, cube->ep); 224 b *= POW2TO11;
158 index_to_perm(epe, 4, e); 225 c *= POW2TO11 * POW3TO7;
159 226
160 for (i = 0, j = 0, k = 0; i < 12; i++) 227 return a + b + c;
161 if (cube->ep[i] == 0)
162 cube->ep[i] = j++;
163 else
164 cube->ep[i] = e[k++] + 8;
165} 228}
166 229
167/* Other local functions *****************************************************/ 230static uint64_t
168 231index_drud_eofb(Cube cube)
169uint64_t
170indexers_getmax(Indexer **is)
171{ 232{
172 int i; 233 return index_drud(cube) / POW2TO11;
173 uint64_t max = 1;
174
175 for (i = 0; is[i] != NULL; i++)
176 max *= is[i]->n;
177
178 return max;
179} 234}
180 235
181uint64_t 236static uint64_t
182indexers_getind(Indexer **is, Cube *c) 237index_htr_drud(Cube cube)
183{ 238{
184 int i; 239 uint64_t a, b;
185 uint64_t max = 0;
186 240
187 for (i = 0; is[i] != NULL; i++) { 241 a = index_cphtr(cube);
188 max *= is[i]->n; 242 b = htr_eposs_ind[cube.eposs/24];
189 max += is[i]->index(c);
190 }
191 243
192 return max; 244 return a * BINOM8ON4 + b;
193} 245}
194 246
195void 247static uint64_t
196indexers_makecube(Indexer **is, uint64_t ind, Cube *c) 248index_htrfin(Cube cube)
197{ 249{
198 /* Warning: anti-indexers are applied in the same order as indexers. */ 250 uint64_t epe, eps, epm, cp, ep;
199 /* We assume order does not matter, but it would make more sense to */
200 /* apply them in reverse. */
201 251
202 int i; 252 epe = cube.epose % 24;
203 uint64_t m; 253 eps = cube.eposs % 24;
254 epm = cube.eposm % 24;
255 ep = (epe * 24 + eps) *24 + epm;
256 cp = index_cornershtrfin(cube);
204 257
205 make_solved(c); 258 return cp * 24 * 24 * 24 + ep;
206 m = indexers_getmax(is);
207 for (i = 0; is[i] != NULL; i++) {
208 m /= is[i]->n;
209 is[i]->to_cube(ind / m, c);
210 ind %= m;
211 }
212} 259}
213 260
214static void 261static uint64_t
215gen_coord_comp(Coordinate *coord) 262index_cpud_separate(Cube cube)
216{ 263{
217 uint64_t ui; 264 return cpud_separate_ind[cube.cp];
218 Cube c, mvd; 265}
219 Move m;
220 Trans t;
221
222 coord->max = indexers_getmax(coord->i);
223
224 for (m = 0; m < NMOVES; m++)
225 coord->mtable[m] = malloc(coord->max * sizeof(uint64_t));
226 266
227 for (t = 0; t < NTRANS; t++) 267/* Coordinate movers *********************************************************/
228 coord->ttable[t] = malloc(coord->max * sizeof(uint64_t));
229 268
230 if (!read_coord_mtable(coord)) { 269static uint64_t
231 fprintf(stderr, "%s: generating mtable\n", coord->name); 270move_eofb(Move m, uint64_t ind)
271{
272 return eofb_mtable[m][ind];
273}
232 274
233 for (ui = 0; ui < coord->max; ui++) { 275static uint64_t
234 indexers_makecube(coord->i, ui, &c); 276move_eofbepos(Move m, uint64_t ind)
235 for (m = 0; m < NMOVES; m++) { 277{
236 copy_cube(&c, &mvd); 278 uint64_t a, b;
237 apply_move(m, &mvd);
238 coord->mtable[m][ui] =
239 indexers_getind(coord->i, &mvd);
240 }
241 }
242 if (!write_coord_mtable(coord))
243 fprintf(stderr, "%s: error writing mtable\n",
244 coord->name);
245
246 fprintf(stderr, "%s: mtable generated\n", coord->name);
247 }
248 279
249 if (!read_coord_ttable(coord)) { 280 a = epose_mtable[m][(ind / POW2TO11)*24];
250 fprintf(stderr, "%s: generating ttable\n", coord->name); 281 b = eofb_mtable[m][ind % POW2TO11];
251 282
252 for (ui = 0; ui < coord->max; ui++) { 283 return (a/24) * POW2TO11 + b;
253 indexers_makecube(coord->i, ui, &c);
254 for (t = 0; t < NTRANS; t++) {
255 copy_cube(&c, &mvd);
256 apply_trans(t, &mvd);
257 coord->ttable[t][ui] =
258 indexers_getind(coord->i, &mvd);
259 }
260 }
261 if (!write_coord_ttable(coord))
262 fprintf(stderr, "%s: error writing ttable\n",
263 coord->name);
264 }
265} 284}
266 285
267static void 286static uint64_t
268gen_coord_sym(Coordinate *coord) 287move_epud(Move m, uint64_t ind)
269{ 288{
270 uint64_t i, in, ui, uj, uu, M, nr; 289 /* TODO: save to file? */
290 static bool initialized = false;
291 static int a[12] = { [8] = 8, [9] = 9, [10] = 10, [11] = 11 };
292 static int shortlist[NMOVES] = {
293 [U] = 0, [U2] = 1, [U3] = 2, [D] = 3, [D2] = 4, [D3] = 5,
294 [R2] = 6, [L2] = 7, [F2] = 8, [B2] = 9
295 };
296 static uint64_t aux[10][FACTORIAL8];
297 uint64_t ui;
271 int j; 298 int j;
272 Move m; 299 Move mj;
273 Trans t; 300 Cube c;
274 301 CubeArray *arr, *auxarr;
275 M = coord->base[0]->max;
276 coord->selfsim = malloc(M * sizeof(uint64_t));
277 coord->symclass = malloc(M * sizeof(uint64_t));
278 coord->symrep = malloc(M * sizeof(uint64_t));
279 coord->transtorep = malloc(M * sizeof(Trans));
280
281 if (!read_coord_sd(coord)) {
282 fprintf(stderr, "%s: generating syms\n", coord->name);
283
284 for (i = 0; i < M; i++)
285 coord->symclass[i] = M+1;
286 302
287 for (i = 0, nr = 0; i < M; i++) { 303 if (!moveset_drud.allowed(m)) {
288 if (coord->symclass[i] != M+1) 304 fprintf(stderr, "Move not allowed for epud\n"
289 continue; 305 "This is a bug, please report\n");
306 return coord_epud.max;
307 }
290 308
291 coord->symrep[nr] = i; 309 if (!initialized) {
292 coord->transtorep[i] = uf; 310 auxarr = malloc(sizeof(CubeArray));
293 coord->selfsim[nr] = (uint64_t)0; 311 auxarr->ep = a;
294 for (j = 0; j < coord->tgrp->n; j++) { 312 for (ui = 0; ui < coord_epud.max; ui++) {
295 t = coord->tgrp->t[j]; 313 index_to_perm(ui, 8, a);
296 in = trans_coord(coord->base[0], t, i); 314 c = arrays_to_cube(auxarr, pf_ep);
297 coord->symclass[in] = nr; 315 for (j = 0; moveset_drud.sorted_moves[j] != NULLMOVE;
298 if (in == i) 316 j++) {
299 coord->selfsim[nr] |= ((uint64_t)1<<t); 317 mj = moveset_drud.sorted_moves[j];
300 else 318 arr = new_cubearray(apply_move(mj, c), pf_ep);
301 coord->transtorep[in] = 319 aux[shortlist[mj]][ui] =
302 inverse_trans(t); 320 perm_to_index(arr->ep, 8);
321 free_cubearray(arr, pf_ep);
303 } 322 }
304 nr++;
305 } 323 }
324 free(auxarr);
306 325
307 coord->max = nr; 326 initialized = true;
308
309 fprintf(stderr, "%s: found %" PRIu64 " classes\n",
310 coord->name, nr);
311 if (!write_coord_sd(coord))
312 fprintf(stderr, "%s: error writing symdata\n",
313 coord->name);
314 }
315
316 coord->symrep = realloc(coord->symrep, coord->max*sizeof(uint64_t));
317 coord->selfsim = realloc(coord->selfsim, coord->max*sizeof(uint64_t));
318
319 for (m = 0; m < NMOVES; m++) {
320 coord->mtable[m] = malloc(coord->max*sizeof(uint64_t));
321 coord->ttrep_move[m] = malloc(coord->max*sizeof(Trans));
322 } 327 }
323 328
324 if (!read_coord_mtable(coord)) { 329 return aux[shortlist[m]][ind];
325 for (ui = 0; ui < coord->max; ui++) {
326 uu = coord->symrep[ui];
327 for (m = 0; m < NMOVES; m++) {
328 uj = move_coord(coord->base[0], m, uu, NULL);
329 coord->mtable[m][ui] = coord->symclass[uj];
330 coord->ttrep_move[m][ui] =
331 coord->transtorep[uj];
332 }
333 }
334 if (!write_coord_mtable(coord))
335 fprintf(stderr, "%s: error writing mtable\n",
336 coord->name);
337 }
338} 330}
339 331
340static bool 332static uint64_t
341read_coord_mtable(Coordinate *coord) 333move_coud(Move m, uint64_t ind)
342{ 334{
343 FILE *f; 335 return coud_mtable[m][ind];
344 char fname[strlen(tabledir)+256]; 336}
345 Move m;
346 uint64_t M;
347 bool r;
348
349 strcpy(fname, tabledir);
350 strcat(fname, "/mt_");
351 strcat(fname, coord->name);
352
353 if ((f = fopen(fname, "rb")) == NULL)
354 return false;
355 337
356 M = coord->max; 338static uint64_t
357 r = true; 339move_corners(Move m, uint64_t ind)
358 for (m = 0; m < NMOVES; m++) 340{
359 r = r && fread(coord->mtable[m], sizeof(uint64_t), M, f) == M; 341 uint64_t a, b;
360 342
361 if (coord->type == SYM_COORD) 343 a = coud_mtable[m][ind / FACTORIAL8];
362 for (m = 0; m < NMOVES; m++) 344 b = cp_mtable[m][ind % FACTORIAL8];
363 r = r && fread(coord->ttrep_move[m],
364 sizeof(Trans), M, f) == M;
365 345
366 fclose(f); 346 return a * FACTORIAL8 + b;
367 return r;
368} 347}
369 348
370static bool 349static uint64_t
371read_coord_sd(Coordinate *coord) 350move_cp(Move m, uint64_t ind)
372{ 351{
373 FILE *f; 352 return cp_mtable[m][ind];
374 char fname[strlen(tabledir)+256]; 353}
375 uint64_t M, N;
376 bool r;
377 354
378 strcpy(fname, tabledir); 355static uint64_t
379 strcat(fname, "/sd_"); 356move_cphtr(Move m, uint64_t ind)
380 strcat(fname, coord->name); 357{
358 static bool initialized = false;
359 static uint64_t aux[NMOVES][BINOM8ON4*6];
360 uint64_t ui;
361 Move j;
381 362
382 if ((f = fopen(fname, "rb")) == NULL) 363 if (!initialized) {
383 return false; 364 for (ui = 0; ui < BINOM8ON4*6; ui++)
365 for (j = U; j < NMOVES; j++)
366 aux[j][ui] = cphtr_right_cosets[
367 cp_mtable[j][cphtr_right_rep[ui]]];
384 368
385 r = true; 369 initialized = true;
386 r = r && fread(&coord->max, sizeof(uint64_t), 1, f) == 1; 370 }
387 M = coord->max;
388 N = coord->base[0]->max;
389 r = r && fread(coord->symrep, sizeof(uint64_t), M, f) == M;
390 r = r && fread(coord->selfsim, sizeof(uint64_t), M, f) == M;
391 r = r && fread(coord->symclass, sizeof(uint64_t), N, f) == N;
392 r = r && fread(coord->transtorep, sizeof(Trans), N, f) == N;
393 371
394 fclose(f); 372 return aux[m][ind];
395 return r;
396} 373}
397 374
398static bool 375static uint64_t
399read_coord_ttable(Coordinate *coord) 376move_cornershtr(Move m, uint64_t ind)
400{ 377{
401 FILE *f; 378 uint64_t a, b;
402 char fname[strlen(tabledir)+256];
403 Trans t;
404 uint64_t M;
405 bool r;
406
407 strcpy(fname, tabledir);
408 strcat(fname, "/tt_");
409 strcat(fname, coord->name);
410
411 if ((f = fopen(fname, "rb")) == NULL)
412 return false;
413 379
414 M = coord->max; 380 a = coud_mtable[m][ind/(BINOM8ON4 * 6)];
415 r = true; 381 b = move_cphtr(m, ind % (BINOM8ON4 * 6));
416 for (t = 0; t < NTRANS; t++)
417 r = r && fread(coord->ttable[t], sizeof(uint64_t), M, f) == M;
418 382
419 fclose(f); 383 return a * BINOM8ON4 * 6 + b;
420 return r;
421} 384}
422 385
423static bool 386static uint64_t
424write_coord_mtable(Coordinate *coord) 387move_cornershtrfin(Move m, uint64_t ind)
425{ 388{
426 FILE *f; 389 int a;
427 char fname[strlen(tabledir)+256];
428 Move m;
429 uint64_t M;
430 bool r;
431 390
432 strcpy(fname, tabledir); 391 a = cp_mtable[m][cornershtrfin_ant[ind]];
433 strcat(fname, "/mt_");
434 strcat(fname, coord->name);
435 392
436 if ((f = fopen(fname, "wb")) == NULL) 393 return cornershtrfin_ind[a];
437 return false; 394}
438 395
439 M = coord->max; 396static uint64_t
440 r = true; 397move_drud(Move m, uint64_t ind)
441 for (m = 0; m < NMOVES; m++) 398{
442 r = r && fwrite(coord->mtable[m], sizeof(uint64_t), M, f) == M; 399 uint64_t a, b, c;
443 400
444 if (coord->type == SYM_COORD) 401 a = eofb_mtable[m][ind % POW2TO11];
445 for (m = 0; m < NMOVES; m++) 402 b = coud_mtable[m][(ind / POW2TO11) % POW3TO7];
446 r = r && fwrite(coord->ttrep_move[m], 403 c = epose_mtable[m][ind / (POW2TO11 * POW3TO7)];
447 sizeof(Trans), M, f) == M;
448 404
449 fclose(f); 405 return a + (b + c * POW3TO7) * POW2TO11;
450 return r;
451} 406}
452 407
453static bool 408static uint64_t
454write_coord_sd(Coordinate *coord) 409move_drud_eofb(Move m, uint64_t ind)
455{ 410{
456 FILE *f; 411 uint64_t a, b;
457 char fname[strlen(tabledir)+256];
458 uint64_t M, N;
459 bool r;
460
461 strcpy(fname, tabledir);
462 strcat(fname, "/sd_");
463 strcat(fname, coord->name);
464 412
465 if ((f = fopen(fname, "wb")) == NULL) 413 a = coud_mtable[m][ind % POW3TO7];
466 return false; 414 b = epose_mtable[m][(ind / POW3TO7) * 24] / 24;
467 415
468 r = true; 416 return a + b * POW3TO7;
469 M = coord->max;
470 N = coord->base[0]->max;
471 r = r && fwrite(&coord->max, sizeof(uint64_t), 1, f) == 1;
472 r = r && fwrite(coord->symrep, sizeof(uint64_t), M, f) == M;
473 r = r && fwrite(coord->selfsim, sizeof(uint64_t), M, f) == M;
474 r = r && fwrite(coord->symclass, sizeof(uint64_t), N, f) == N;
475 r = r && fwrite(coord->transtorep, sizeof(Trans), N, f) == N;
476
477 fclose(f);
478 return r;
479} 417}
480 418
481static bool 419static uint64_t
482write_coord_ttable(Coordinate *coord) 420move_htr_drud(Move m, uint64_t ind)
483{ 421{
484 FILE *f; 422 uint64_t a, b;
485 char fname[strlen(tabledir)+256];
486 Trans t;
487 uint64_t M;
488 bool r;
489 423
490 strcpy(fname, tabledir); 424 a = move_cphtr(m, ind/BINOM8ON4);
491 strcat(fname, "/tt_"); 425 b = eposs_mtable[m][htr_eposs_ant[ind%BINOM8ON4]];
492 strcat(fname, coord->name);
493 426
494 if ((f = fopen(fname, "wb")) == NULL) 427 return a*BINOM8ON4 + htr_eposs_ind[b/24];
495 return false; 428}
496 429
497 M = coord->max; 430static uint64_t
498 r = true; 431move_htrfin(Move m, uint64_t ind)
499 for (t = 0; t < NTRANS; t++) 432{
500 r = r && fwrite(coord->ttable[t], sizeof(uint64_t), M, f) == M; 433 uint64_t a, b, bm, bs, be;
501 434
502 fclose(f); 435 a = move_cornershtrfin(m, ind / (24*24*24));
503 return r; 436 bm = eposm_mtable[m][ind%24] % 24;
504} 437 bs = eposs_mtable[m][(ind/24)%24] % 24;
438 be = epose_mtable[m][(ind/(24*24))%24] % 24;
439 b = (be * 24 + bs) * 24 + bm;
505 440
506/* Public functions **********************************************************/ 441 return a * (24*24*24) + b;
442}
507 443
508void 444static uint64_t
509gen_coord(Coordinate *coord) 445move_cpud_separate(Move m, uint64_t ind)
510{ 446{
511 int i; 447 return cpud_separate_ind[cp_mtable[m][cpud_separate_ant[ind]]];
448}
512 449
513 if (coord == NULL || coord->generated) 450/* Init functions implementation *********************************************/
514 return;
515 451
516 for (i = 0; i < 2; i++) 452/*
517 gen_coord(coord->base[i]); 453 * There is certainly a better way to do this, but for now I just use
454 * a "graph coloring" algorithm to compute the left cosets, and I compose
455 * with every possible cp to get the right cosets (it is possible that I am
456 * mixing up left and right).
457 *
458 * For doing it better "Mathematically", we need 3 things:
459 * - Checking that cp separates the orbits (UFR,UBL,DFL,DBR) and the other
460 * This is easy and it is done in the commented function cphtr_cp().
461 * - Check that there is no ep/cp parity
462 * - Check that we are not in the "3c" case; this is the part I don't
463 * know how to do.
464 */
465static void
466init_cphtr_cosets()
467{
468 unsigned int i;
469 int c = 0, d = 0;
518 470
519 switch (coord->type) { 471 for (i = 0; i < FACTORIAL8; i++) {
520 case COMP_COORD: 472 cphtr_left_cosets[i] = -1;
521 if (coord->i[0] == NULL) 473 cphtr_right_cosets[i] = -1;
522 goto error_gc;
523 gen_coord_comp(coord);
524 break;
525 case SYM_COORD:
526 if (coord->base[0] == NULL || coord->tgrp == NULL)
527 goto error_gc;
528 gen_coord_sym(coord);
529 break;
530 case SYMCOMP_COORD:
531 if (coord->base[0] == NULL || coord->base[1] == NULL)
532 goto error_gc;
533 coord->max = coord->base[0]->max * coord->base[1]->max;
534 break;
535 default:
536 break;
537 } 474 }
538 475
539 coord->generated = true; 476 /* First we compute left cosets with a bfs */
540 return; 477 for (i = 0; i < FACTORIAL8; i++)
478 if (cphtr_left_cosets[i] == -1)
479 init_cphtr_left_cosets_bfs(i, c++);
541 480
542error_gc: 481 /* Then we compute right cosets using compose() */
543 fprintf(stderr, "Error generating coordinates.\n" 482 for (i = 0; i < FACTORIAL8; i++)
544 "This is a bug, pleae report.\n"); 483 if (cphtr_right_cosets[i] == -1)
545 exit(1); 484 init_cphtr_right_cosets_color(i, d++);
546} 485}
547 486
548uint64_t 487static void
549index_coord(Coordinate *coord, Cube *cube, Trans *offtrans) 488init_cphtr_left_cosets_bfs(int i, int c)
550{ 489{
551 uint64_t c[2], cnosym; 490 int j, jj, next[FACTORIAL8], next2[FACTORIAL8], n, n2;
552 Trans ttr;
553
554 switch (coord->type) {
555 case COMP_COORD:
556 if (offtrans != NULL)
557 *offtrans = uf;
558 491
559 return indexers_getind(coord->i, cube); 492 Move k;
560 case SYM_COORD:
561 cnosym = index_coord(coord->base[0], cube, NULL);
562 ttr = coord->transtorep[cnosym];
563 493
564 if (offtrans != NULL) 494 n = 1;
565 *offtrans = ttr; 495 next[0] = i;
496 cphtr_left_cosets[i] = c;
566 497
567 return coord->symclass[cnosym]; 498 while (n != 0) {
568 case SYMCOMP_COORD: 499 for (j = 0, n2 = 0; j < n; j++) {
569 c[0] = index_coord(coord->base[0], cube, NULL); 500 for (k = U2; k < B3; k++) {
570 cnosym = index_coord(coord->base[0]->base[0], cube, NULL); 501 if (!moveset_htr.allowed(k))
571 ttr = coord->base[0]->transtorep[cnosym]; 502 continue;
572 c[1] = index_coord(coord->base[1], cube, NULL); 503 jj = apply_move(k, (Cube){ .cp = next[j] }).cp;
573 c[1] = trans_coord(coord->base[1], ttr, c[1]);
574 504
575 if (offtrans != NULL) 505 if (cphtr_left_cosets[jj] == -1) {
576 *offtrans = ttr; 506 cphtr_left_cosets[jj] = c;
507 next2[n2++] = jj;
508 }
509 }
510 }
577 511
578 return c[0] * coord->base[1]->max + c[1]; 512 for (j = 0; j < n2; j++)
579 default: 513 next[j] = next2[j];
580 break; 514 n = n2;
581 } 515 }
582
583 return coord->max; /* Only reached in case of error */
584} 516}
585 517
586uint64_t 518static void
587move_coord(Coordinate *coord, Move m, uint64_t ind, Trans *offtrans) 519init_cphtr_right_cosets_color(int i, int d)
588{ 520{
589 uint64_t i[2], M; 521 int cp;
590 Trans ttr; 522 unsigned int j;
591 523
592 /* Some safety checks should be done here, but for performance * 524 cphtr_right_rep[d] = i;
593 * reasons we'd rather do them before calling this function. * 525 for (j = 0; j < FACTORIAL8; j++) {
594 * We should check if coord is generated. */ 526 if (cphtr_left_cosets[j] == 0) {
595 527 cp = compose((Cube){.cp = i}, (Cube){.cp = j}).cp;
596 switch (coord->type) { 528 cphtr_right_cosets[cp] = d;
597 case COMP_COORD: 529 }
598 if (offtrans != NULL) 530 }
599 *offtrans = uf; 531}
600 532
601 return coord->mtable[m][ind]; 533static void
602 case SYM_COORD: 534init_cpud_separate()
603 ttr = coord->ttrep_move[m][ind]; 535{
536 unsigned int ui;
537 int i, co[8];
604 538
605 if (offtrans != NULL) 539 for (ui = 0; ui < FACTORIAL8; ui++) {
606 *offtrans = ttr; 540 for (i = 0; i < 8; i++)
541 co[i] = what_corner_at((Cube){.cp=ui},i)>UBR ? 1 : 0;
542 cpud_separate_ind[ui] = subset_to_index(co, 8, 4);
543 cpud_separate_ant[cpud_separate_ind[ui]] = ui;
544 }
545}
607 546
608 return coord->mtable[m][ind]; 547static void
609 case SYMCOMP_COORD: 548init_cornershtrfin()
610 M = coord->base[1]->max; 549{
611 i[0] = ind / M; 550 unsigned int i, j;
612 i[1] = ind % M; 551 int n, c;
613 ttr = coord->base[0]->ttrep_move[m][i[0]]; 552 Move m;
614 i[0] = coord->base[0]->mtable[m][i[0]];
615 i[1] = coord->base[1]->mtable[m][i[1]];
616 i[1] = coord->base[1]->ttable[ttr][i[1]];
617 553
618 if (offtrans != NULL) 554 for (i = 0; i < FACTORIAL8; i++)
619 *offtrans = ttr; 555 cornershtrfin_ind[i] = -1;
556 cornershtrfin_ind[0] = 0;
620 557
621 return i[0] * M + i[1]; 558 /* 10-pass, I think 5 is enough, but just in case */
622 default: 559 n = 1;
623 break; 560 for (i = 0; i < 10; i++) {
561 for (j = 0; j < FACTORIAL8; j++) {
562 if (cornershtrfin_ind[j] == -1)
563 continue;
564 for (m = U; m < NMOVES; m++) {
565 if (moveset_htr.allowed(m)) {
566 c = cp_mtable[m][j];
567 if (cornershtrfin_ind[c] == -1) {
568 cornershtrfin_ind[c] = n;
569 cornershtrfin_ant[n] = c;
570 n++;
571 }
572 }
573 }
574 }
624 } 575 }
625
626 return coord->max; /* Only reached in case of error */
627} 576}
628 577
629uint64_t 578void
630trans_coord(Coordinate *coord, Trans t, uint64_t ind) 579init_htr_eposs()
631{ 580{
632 uint64_t i[2], M; 581 int ep[12], ep2[12];
582 int eps_solved[4] = {UL, UR, DL, DR};
583 unsigned int i, j;
633 584
634 /* Some safety checks should be done here, but for performance * 585 for (i = 0; i < BINOM12ON4; i++) {
635 * reasons we'd rather do them before calling this function. * 586 for (j = 0; j < 12; j++)
636 * We should check if coord is generated. */ 587 ep[j] = ep2[j] = 0;
637 588 epos_to_partial_ep(i*24, ep, eps_solved);
638 switch (coord->type) { 589 for (j = 0; j < 8; j++)
639 case COMP_COORD: 590 ep2[j/2 + 4*(j%2)] = ep[j] ? 1 : 0;
640 return coord->ttable[t][ind]; 591 htr_eposs_ind[i] = subset_to_index(ep2, 8, 4);
641 case SYM_COORD: 592 htr_eposs_ant[htr_eposs_ind[i]] = i*24;
642 return ind;
643 case SYMCOMP_COORD:
644 M = coord->base[1]->max;
645 i[0] = ind / M; /* Always fixed */
646 i[1] = ind % M;
647 i[1] = coord->base[1]->ttable[t][i[1]];
648 return i[0] * M + i[1];
649 default:
650 break;
651 } 593 }
594}
595
596void
597init_coord()
598{
599 static bool initialized = false;
600 if (initialized)
601 return;
602 initialized = true;
652 603
653 return coord->max; /* Only reached in case of error */ 604 init_trans();
605
606 init_cphtr_cosets();
607 init_cornershtrfin();
608 init_htr_eposs();
609 init_cpud_separate();
654} 610}
611
diff --git a/src/coord.h b/src/coord.h
index 4cd7e47..61398a4 100644
--- a/src/coord.h
+++ b/src/coord.h
@@ -3,257 +3,26 @@
3 3
4#include "trans.h" 4#include "trans.h"
5 5
6void gen_coord(Coordinate *coord); 6extern Coordinate coord_eofb;
7uint64_t index_coord(Coordinate *coord, Cube *cube, 7extern Coordinate coord_eofbepos;
8 Trans *offtrans); 8extern Coordinate coord_coud;
9uint64_t indexers_getind(Indexer **is, Cube *c); 9extern Coordinate coord_cp;
10void indexers_makecube(Indexer **is, uint64_t ind, Cube *c); 10extern Coordinate coord_cphtr;
11uint64_t move_coord(Coordinate *coord, Move m, 11extern Coordinate coord_corners;
12 uint64_t ind, Trans *offtrans); 12extern Coordinate coord_cornershtr;
13uint64_t trans_coord(Coordinate *coord, Trans t, uint64_t ind); 13extern Coordinate coord_cornershtrfin;
14extern Coordinate coord_epud;
15extern Coordinate coord_drud;
16extern Coordinate coord_drud_eofb;
17extern Coordinate coord_htr_drud;
18extern Coordinate coord_htrfin;
19extern Coordinate coord_cpud_separate;
14 20
15/* Base coordinates and their index functions ********************************/ 21extern int cpud_separate_ant[BINOM8ON4];
22extern int cpud_separate_ind[FACTORIAL8];
23extern int cornershtrfin_ant[24*24/6];
16 24
17#ifndef COORD_C 25void init_coord();
18
19extern Coordinate coord_eofb;
20extern Coordinate coord_coud;
21extern Coordinate coord_cp;
22extern Coordinate coord_cpudsep;
23extern Coordinate coord_epos;
24extern Coordinate coord_epe;
25extern Coordinate coord_eposepe;
26extern Coordinate coord_epud;
27extern Coordinate coord_eofbepos;
28extern Coordinate coord_coud_cpudsep;
29extern Coordinate coord_eofbepos_sym16;
30extern Coordinate coord_cp_sym16;
31extern Coordinate coord_corners_sym16;
32extern Coordinate coord_drud_sym16;
33extern Coordinate coord_drudfin_noE_sym16;
34extern Coordinate coord_nxopt31;
35
36extern Coordinate *all_coordinates[];
37
38#else
39
40/* Indexers ******************************************************************/
41
42uint64_t index_eofb(Cube *cube);
43void invindex_eofb(uint64_t ind, Cube *ret);
44Indexer
45i_eofb = {
46 .n = POW2TO11,
47 .index = index_eofb,
48 .to_cube = invindex_eofb,
49};
50
51uint64_t index_coud(Cube *cube);
52void invindex_coud(uint64_t ind, Cube *ret);
53Indexer
54i_coud = {
55 .n = POW3TO7,
56 .index = index_coud,
57 .to_cube = invindex_coud,
58};
59
60uint64_t index_cp(Cube *cube);
61void invindex_cp(uint64_t ind, Cube *ret);
62Indexer
63i_cp = {
64 .n = FACTORIAL8,
65 .index = index_cp,
66 .to_cube = invindex_cp,
67};
68
69uint64_t index_cpudsep(Cube *cube);
70void invindex_cpudsep(uint64_t ind, Cube *ret);
71Indexer
72i_cpudsep = {
73 .n = BINOM8ON4,
74 .index = index_cpudsep,
75 .to_cube = invindex_cpudsep,
76};
77
78uint64_t index_epos(Cube *cube);
79void invindex_epos(uint64_t ind, Cube *ret);
80Indexer
81i_epos = {
82 .n = BINOM12ON4,
83 .index = index_epos,
84 .to_cube = invindex_epos,
85};
86
87uint64_t index_epe(Cube *cube);
88void invindex_epe(uint64_t ind, Cube *ret);
89Indexer
90i_epe = {
91 .n = FACTORIAL4,
92 .index = index_epe,
93 .to_cube = invindex_epe,
94};
95
96uint64_t index_eposepe(Cube *cube);
97void invindex_eposepe(uint64_t ind, Cube *ret);
98Indexer
99i_eposepe = {
100 .n = BINOM12ON4 * FACTORIAL4,
101 .index = index_eposepe,
102 .to_cube = invindex_eposepe,
103};
104
105uint64_t index_epud(Cube *cube);
106void invindex_epud(uint64_t ind, Cube *ret);
107Indexer
108i_epud = {
109 .n = FACTORIAL8,
110 .index = index_epud,
111 .to_cube = invindex_epud,
112};
113
114/* Composite coordinates *****************************************************/
115
116Coordinate
117coord_eofb = {
118 .name = "eofb",
119 .type = COMP_COORD,
120 .i = {&i_eofb, NULL},
121};
122
123Coordinate
124coord_coud = {
125 .name = "coud",
126 .type = COMP_COORD,
127 .i = {&i_coud, NULL},
128};
129
130Coordinate
131coord_cp = {
132 .name = "cp",
133 .type = COMP_COORD,
134 .i = {&i_cp, NULL},
135};
136
137Coordinate
138coord_cpudsep = {
139 .name = "cpudsep",
140 .type = COMP_COORD,
141 .i = {&i_cpudsep, NULL},
142};
143
144Coordinate
145coord_epos = {
146 .name = "epos",
147 .type = COMP_COORD,
148 .i = {&i_epos, NULL},
149};
150
151Coordinate
152coord_epe = {
153 .name = "epe",
154 .type = COMP_COORD,
155 .i = {&i_epe, NULL},
156};
157
158Coordinate
159coord_eposepe = { /* Has to be done by hand, hard compose epos + epe */
160 .name = "eposepe",
161 .type = COMP_COORD,
162 .i = {&i_eposepe, NULL},
163};
164
165Coordinate
166coord_epud = {
167 .name = "epud",
168 .type = COMP_COORD,
169 .i = {&i_epud, NULL},
170};
171
172Coordinate
173coord_eofbepos = {
174 .name = "eofbepos",
175 .type = COMP_COORD,
176 .i = {&i_epos, &i_eofb, NULL},
177};
178
179Coordinate
180coord_coud_cpudsep = {
181 .name = "coud_cpudsep",
182 .type = COMP_COORD,
183 .i = {&i_coud, &i_cpudsep, NULL},
184};
185
186/* Symcoordinates ************************************************************/
187
188Coordinate
189coord_eofbepos_sym16 = {
190 .name = "eofbepos_sym16",
191 .type = SYM_COORD,
192 .base = {&coord_eofbepos, NULL},
193 .tgrp = &tgrp_udfix,
194};
195
196Coordinate
197coord_cp_sym16 = {
198 .name = "cp_sym16",
199 .type = SYM_COORD,
200 .base = {&coord_cp, NULL},
201 .tgrp = &tgrp_udfix,
202};
203
204/* "Symcomp" coordinates *****************************************************/
205
206Coordinate
207coord_corners_sym16 = {
208 .name = "corners_sym16",
209 .type = SYMCOMP_COORD,
210 .base = {&coord_cp_sym16, &coord_coud},
211};
212
213Coordinate
214coord_drud_sym16 = {
215 .name = "drud_sym16",
216 .type = SYMCOMP_COORD,
217 .base = {&coord_eofbepos_sym16, &coord_coud},
218};
219
220Coordinate
221coord_drudfin_noE_sym16 = {
222 .name = "drudfin_noE_sym16",
223 .type = SYMCOMP_COORD,
224 .base = {&coord_cp_sym16, &coord_epud},
225};
226
227Coordinate
228coord_nxopt31 = {
229 .name = "nxopt31",
230 .type = SYMCOMP_COORD,
231 .base = {&coord_eofbepos_sym16, &coord_coud_cpudsep},
232};
233
234/* All coordinates ***********************************************************/
235
236Coordinate *all_coordinates[] = {
237 &coord_eofb,
238 &coord_coud,
239 &coord_cp,
240 &coord_cpudsep,
241 &coord_epos,
242 &coord_epe,
243 &coord_eposepe,
244 &coord_epud,
245 &coord_eofbepos,
246 &coord_coud_cpudsep,
247 &coord_eofbepos_sym16,
248 &coord_cp_sym16,
249 &coord_corners_sym16,
250 &coord_drud_sym16,
251 &coord_drudfin_noE_sym16,
252 &coord_nxopt31,
253 NULL
254};
255
256#endif
257 26
258#endif 27#endif
259 28
diff --git a/src/cube.c b/src/cube.c
index 92c6713..aae3a6e 100644
--- a/src/cube.c
+++ b/src/cube.c
@@ -1,205 +1,531 @@
1#define CUBE_C
2
3#include "cube.h" 1#include "cube.h"
4 2
5static int where_is_piece(int piece, int *arr, int n); 3/* Local functions ***********************************************************/
6 4
7void 5static void init_inverse();
8compose_centers(Cube *c2, Cube *c1) 6static bool read_invtables_file();
7static bool write_invtables_file();
8
9/* Tables ********************************************************************/
10
11static uint16_t eo_invtable_e[POW2TO11][BINOM12ON4*FACTORIAL4];
12static uint16_t eo_invtable_s[POW2TO11][BINOM12ON4*FACTORIAL4];
13static uint16_t eo_invtable_m[POW2TO11][BINOM12ON4*FACTORIAL4];
14static uint16_t co_invtable[POW3TO7][FACTORIAL8];
15static uint16_t cp_invtable[FACTORIAL8];
16static uint16_t cpos_invtable[FACTORIAL6];
17
18/* Functions implementation **************************************************/
19
20int
21array_ep_to_epos(int *ep, int *ss)
9{ 22{
10 apply_permutation(c2->xp, c1->xp, 6); 23 int epos[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
24 int eps[4];
25 int i, j, is;
26
27 for (i = 0, is = 0; i < 12; i++) {
28 for (j = 0; j < 4; j++) {
29 if (ep[i] == ss[j]) {
30 eps[is++] = j;
31 epos[i] = 1;
32 }
33 }
34 }
35
36 for (i = 0; i < 4; i++)
37 swap(&epos[ss[i]], &epos[i+8]);
38
39 return 24 * subset_to_index(epos, 12, 4) + perm_to_index(eps, 4);
11} 40}
12 41
13void 42Cube
14compose_corners(Cube *c2, Cube *c1) 43arrays_to_cube(CubeArray *arr, PieceFilter f)
15{ 44{
16 apply_permutation(c2->cp, c1->cp, 8); 45 Cube ret = {0};
17 apply_permutation(c2->cp, c1->co, 8); 46
18 sum_arrays_mod(c2->co, c1->co, 8, 3); 47 static int epe_solved[4] = {FR, FL, BL, BR};
48 static int eps_solved[4] = {UL, UR, DL, DR};
49 static int epm_solved[4] = {UF, UB, DF, DB};
50
51 if (f.epose)
52 ret.epose = array_ep_to_epos(arr->ep, epe_solved);
53 if (f.eposs)
54 ret.eposs = array_ep_to_epos(arr->ep, eps_solved);
55 if (f.eposm)
56 ret.eposm = array_ep_to_epos(arr->ep, epm_solved);
57 if (f.eofb)
58 ret.eofb = digit_array_to_int(arr->eofb, 11, 2);
59 if (f.eorl)
60 ret.eorl = digit_array_to_int(arr->eorl, 11, 2);
61 if (f.eoud)
62 ret.eoud = digit_array_to_int(arr->eoud, 11, 2);
63 if (f.cp)
64 ret.cp = perm_to_index(arr->cp, 8);
65 if (f.coud)
66 ret.coud = digit_array_to_int(arr->coud, 7, 3);
67 if (f.corl)
68 ret.corl = digit_array_to_int(arr->corl, 7, 3);
69 if (f.cofb)
70 ret.cofb = digit_array_to_int(arr->cofb, 7, 3);
71 if (f.cpos)
72 ret.cpos = perm_to_index(arr->cpos, 6);
73
74 return ret;
19} 75}
20 76
21void 77Cube
22compose_edges(Cube *c2, Cube *c1) 78compose_filtered(Cube c2, Cube c1, PieceFilter f)
23{ 79{
24 apply_permutation(c2->ep, c1->ep, 12); 80 CubeArray *arr = new_cubearray(c2, f);
25 apply_permutation(c2->ep, c1->eo, 12); 81 Cube ret;
26 sum_arrays_mod(c2->eo, c1->eo, 12, 2); 82
83 ret = move_via_arrays(arr, c1, f);
84 free_cubearray(arr, f);
85
86 return ret;
27} 87}
28 88
29void 89void
30compose(Cube *c2, Cube *c1) 90cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f)
31{ 91{
32 compose_centers(c2, c1); 92 int i;
33 compose_corners(c2, c1); 93
34 compose_edges(c2, c1); 94 static int epe_solved[4] = {FR, FL, BL, BR};
95 static int eps_solved[4] = {UL, UR, DL, DR};
96 static int epm_solved[4] = {UF, UB, DF, DB};
97
98 if (f.epose || f.eposs || f.eposm)
99 for (i = 0; i < 12; i++)
100 arr->ep[i] = -1;
101
102 if (f.epose)
103 epos_to_partial_ep(cube.epose, arr->ep, epe_solved);
104 if (f.eposs)
105 epos_to_partial_ep(cube.eposs, arr->ep, eps_solved);
106 if (f.eposm)
107 epos_to_partial_ep(cube.eposm, arr->ep, epm_solved);
108 if (f.eofb)
109 int_to_sum_zero_array(cube.eofb, 2, 12, arr->eofb);
110 if (f.eorl)
111 int_to_sum_zero_array(cube.eorl, 2, 12, arr->eorl);
112 if (f.eoud)
113 int_to_sum_zero_array(cube.eoud, 2, 12, arr->eoud);
114 if (f.cp)
115 index_to_perm(cube.cp, 8, arr->cp);
116 if (f.coud)
117 int_to_sum_zero_array(cube.coud, 3, 8, arr->coud);
118 if (f.corl)
119 int_to_sum_zero_array(cube.corl, 3, 8, arr->corl);
120 if (f.cofb)
121 int_to_sum_zero_array(cube.cofb, 3, 8, arr->cofb);
122 if (f.cpos)
123 index_to_perm(cube.cpos, 6, arr->cpos);
35} 124}
36 125
37void 126void
38copy_cube_centers(Cube *src, Cube *dst) 127epos_to_compatible_ep(int epos, int *ep, int *ss)
39{ 128{
40 memcpy(dst->xp, src->xp, 6 * sizeof(int)); 129 int i, j, k, other[8];
130 bool flag;
131
132 for (i = 0; i < 12; i++)
133 ep[i] = -1;
134
135 epos_to_partial_ep(epos, ep, ss);
136
137 for (i = 0, j = 0; i < 12; i++) {
138 flag = false;
139 for (k = 0; k < 4; k++)
140 flag = flag || (i == ss[k]);
141 if (!flag)
142 other[j++] = i;
143 }
144
145 for (i = 0, j = 0; i < 12; i++)
146 if (ep[i] == -1)
147 ep[i] = other[j++];
41} 148}
42 149
43void 150void
44copy_cube_corners(Cube *src, Cube *dst) 151epos_to_partial_ep(int epos, int *ep, int *ss)
45{ 152{
46 memcpy(dst->cp, src->cp, 8 * sizeof(int)); 153 int i, is, eposs[12], eps[4];
47 memcpy(dst->co, src->co, 8 * sizeof(int)); 154
155 index_to_perm(epos % FACTORIAL4, 4, eps);
156 index_to_subset(epos / FACTORIAL4, 12, 4, eposs);
157
158 for (i = 0; i < 4; i++)
159 swap(&eposs[ss[i]], &eposs[i+8]);
160
161 for (i = 0, is = 0; i < 12; i++)
162 if (eposs[i])
163 ep[i] = ss[eps[is++]];
48} 164}
49 165
50void 166void
51copy_cube_edges(Cube *src, Cube *dst) 167fix_eorleoud(CubeArray *arr)
52{ 168{
53 memcpy(dst->ep, src->ep, 12 * sizeof(int)); 169 int i;
54 memcpy(dst->eo, src->eo, 12 * sizeof(int)); 170
171 for (i = 0; i < 12; i++) {
172 if ((edge_slice(i) == 0 && edge_slice(arr->ep[i]) != 0) ||
173 (edge_slice(i) != 0 && edge_slice(arr->ep[i]) == 0)) {
174 arr->eorl[i] = 1 - arr->eofb[i];
175 } else {
176 arr->eorl[i] = arr->eofb[i];
177 }
178
179 if ((edge_slice(i) == 2 && edge_slice(arr->ep[i]) != 2) ||
180 (edge_slice(i) != 2 && edge_slice(arr->ep[i]) == 2)) {
181 arr->eoud[i] = 1 - arr->eofb[i];
182 } else {
183 arr->eoud[i] = arr->eofb[i];
184 }
185 }
55} 186}
56 187
57void 188void
58copy_cube(Cube *src, Cube *dst) 189fix_cofbcorl(CubeArray *arr)
59{ 190{
60 copy_cube_centers(src, dst); 191 int i;
61 copy_cube_corners(src, dst); 192
62 copy_cube_edges(src, dst); 193 for (i = 0; i < 8; i++) {
194 if (i % 2 == arr->cp[i] % 2) {
195 arr->cofb[i] = arr->coud[i];
196 arr->corl[i] = arr->coud[i];
197 } else {
198 if (arr->cp[i] % 2 == 0) {
199 arr->cofb[i] = (arr->coud[i]+1)%3;
200 arr->corl[i] = (arr->coud[i]+2)%3;
201 } else {
202 arr->cofb[i] = (arr->coud[i]+2)%3;
203 arr->corl[i] = (arr->coud[i]+1)%3;
204 }
205 }
206 }
63} 207}
64 208
65bool 209Cube
66equal(Cube *c1, Cube *c2) 210fourval_to_cube(int eofb, int ep, int coud, int cp)
67{ 211{
68 int i; 212 CubeArray *arr;
69 213
70 for (i = 0; i < 12; i++) 214 arr = new_cubearray((Cube){0}, pf_all);
71 if (c1->ep[i] != c2->ep[i] || c1->eo[i] != c2->eo[i])
72 return false;
73 215
74 for (i = 0; i < 8; i++) 216 index_to_perm(ep, 12, arr->ep);
75 if (c1->cp[i] != c2->cp[i] || c1->co[i] != c2->co[i]) 217 index_to_perm(cp, 8, arr->cp);
76 return false; 218 int_to_sum_zero_array(eofb, 2, 12, arr->eofb);
219 int_to_sum_zero_array(coud, 3, 8, arr->coud);
77 220
78 for (i = 0; i < 6; i++) 221 /* fix parity */
79 if (c1->xp[i] != c2->xp[i]) 222 if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8))
80 return false; 223 swap(&(arr->ep[0]), &(arr->ep[1]));
81 224
82 return true; 225 fix_eorleoud(arr);
226 fix_cofbcorl(arr);
227
228 return arrays_to_cube(arr, pf_all);
83} 229}
84 230
85void 231void
86invert_cube_centers(Cube *cube) 232free_cubearray(CubeArray *arr, PieceFilter f)
87{ 233{
88 int i; 234 if (f.epose || f.eposs || f.eposm)
89 Cube aux; 235 free(arr->ep);
90 236 if (f.eofb)
91 copy_cube_centers(cube, &aux); 237 free(arr->eofb);
238 if (f.eorl)
239 free(arr->eorl);
240 if (f.eoud)
241 free(arr->eoud);
242 if (f.cp)
243 free(arr->cp);
244 if (f.coud)
245 free(arr->coud);
246 if (f.corl)
247 free(arr->corl);
248 if (f.cofb)
249 free(arr->cofb);
250 if (f.cpos)
251 free(arr->cpos);
92 252
93 for (i = 0; i < 6; i++) 253 free(arr);
94 cube->xp[aux.xp[i]] = i;
95} 254}
96 255
97void 256Cube
98invert_cube_corners(Cube *cube) 257move_via_arrays(CubeArray *arr, Cube c, PieceFilter f)
99{ 258{
100 int i; 259 CubeArray *arrc = new_cubearray(c, f);
101 Cube aux; 260 Cube ret;
102 261
103 copy_cube_corners(cube, &aux); 262 if (f.epose || f.eposs || f.eposm)
263 apply_permutation(arr->ep, arrc->ep, 12);
104 264
105 for (i = 0; i < 8; i++) { 265 if (f.eofb) {
106 cube->cp[aux.cp[i]] = i; 266 apply_permutation(arr->ep, arrc->eofb, 12);
107 cube->co[aux.cp[i]] = (3 - aux.co[i]) % 3; 267 sum_arrays_mod(arr->eofb, arrc->eofb, 12, 2);
108 } 268 }
269
270 if (f.eorl) {
271 apply_permutation(arr->ep, arrc->eorl, 12);
272 sum_arrays_mod(arr->eorl, arrc->eorl, 12, 2);
273 }
274
275 if (f.eoud) {
276 apply_permutation(arr->ep, arrc->eoud, 12);
277 sum_arrays_mod(arr->eoud, arrc->eoud, 12, 2);
278 }
279
280 if (f.cp)
281 apply_permutation(arr->cp, arrc->cp, 8);
282
283 if (f.coud) {
284 apply_permutation(arr->cp, arrc->coud, 8);
285 sum_arrays_mod(arr->coud, arrc->coud, 8, 3);
286 }
287
288 if (f.corl) {
289 apply_permutation(arr->cp, arrc->corl, 8);
290 sum_arrays_mod(arr->corl, arrc->corl, 8, 3);
291 }
292
293 if (f.cofb) {
294 apply_permutation(arr->cp, arrc->cofb, 8);
295 sum_arrays_mod(arr->cofb, arrc->cofb, 8, 3);
296 }
297
298 if (f.cpos)
299 apply_permutation(arr->cpos, arrc->cpos, 6);
300
301 ret = arrays_to_cube(arrc, f);
302 free_cubearray(arrc, f);
303
304 return ret;
109} 305}
110 306
111void 307CubeArray *
112invert_cube_edges(Cube *cube) 308new_cubearray(Cube cube, PieceFilter f)
113{ 309{
114 int i; 310 CubeArray *arr = malloc(sizeof(CubeArray));
115 Cube aux;
116 311
117 copy_cube_edges(cube, &aux); 312 if (f.epose || f.eposs || f.eposm)
313 arr->ep = malloc(12 * sizeof(int));
314 if (f.eofb)
315 arr->eofb = malloc(12 * sizeof(int));
316 if (f.eorl)
317 arr->eorl = malloc(12 * sizeof(int));
318 if (f.eoud)
319 arr->eoud = malloc(12 * sizeof(int));
320 if (f.cp)
321 arr->cp = malloc(8 * sizeof(int));
322 if (f.coud)
323 arr->coud = malloc(8 * sizeof(int));
324 if (f.corl)
325 arr->corl = malloc(8 * sizeof(int));
326 if (f.cofb)
327 arr->cofb = malloc(8 * sizeof(int));
328 if (f.cpos)
329 arr->cpos = malloc(6 * sizeof(int));
118 330
119 for (i = 0; i < 12; i++) { 331 cube_to_arrays(cube, arr, f);
120 cube->ep[aux.ep[i]] = i; 332
121 cube->eo[aux.ep[i]] = aux.eo[i]; 333 return arr;
334}
335
336Cube
337admissible_ep(Cube cube, PieceFilter f)
338{
339 CubeArray *arr = new_cubearray(cube, f);
340 Cube ret;
341 bool used[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
342 int i, j;
343
344 for (i = 0; i < 12; i++)
345 if (arr->ep[i] != -1)
346 used[arr->ep[i]] = true;
347
348 for (i = 0, j = 0; i < 12; i++) {
349 for ( ; j < 11 && used[j]; j++);
350 if (arr->ep[i] == -1)
351 arr->ep[i] = j++;
122 } 352 }
353
354 ret = arrays_to_cube(arr, pf_ep);
355 free_cubearray(arr, f);
356
357 return ret;
123} 358}
124 359
125void 360Cube
126invert_cube(Cube *cube) 361compose(Cube c2, Cube c1)
127{ 362{
128 invert_cube_centers(cube); 363 return compose_filtered(c2, c1, pf_all);
129 invert_cube_corners(cube); 364}
130 invert_cube_edges(cube); 365
366int
367edge_slice(Edge e) {
368 if (e < 0 || e > 11)
369 return -1;
370
371 if (e == FR || e == FL || e == BL || e == BR)
372 return 0;
373 if (e == UR || e == UL || e == DR || e == DL)
374 return 1;
375
376 return 2;
131} 377}
132 378
133bool 379bool
134is_admissible(Cube *c) { 380equal(Cube c1, Cube c2)
135 bool perm; 381{
136 int sign, i; 382 return c1.eofb == c2.eofb &&
137 int sum_e, sum_c; 383 c1.epose == c2.epose &&
384 c1.eposs == c2.eposs &&
385 c1.eposm == c2.eposm &&
386 c1.coud == c2.coud &&
387 c1.cp == c2.cp &&
388 c1.cpos == c2.cpos;
389}
390
391Cube
392inverse_cube(Cube cube)
393{
394 CubeArray inv;
395 Cube ret;
396 int i, ep[12];
138 397
139 perm = is_perm(c->ep, 12) && is_perm(c->cp, 8) && is_perm(c->xp, 6); 398 for (i = 0; i < 12; i++)
399 ep[i] = where_is_edge(cube, i);
400 inv = (CubeArray){.ep = ep};
401 ret = arrays_to_cube(&inv, pf_ep);
140 402
141 sign = perm_sign(c->ep,12) + perm_sign(c->cp,8) + perm_sign(c->xp,6); 403 ret.eofb = ((int)eo_invtable_e[cube.eofb][cube.epose]) |
404 ((int)eo_invtable_m[cube.eofb][cube.eposm]) |
405 ((int)eo_invtable_s[cube.eofb][cube.eposs]);
406 ret.eorl = ((int)eo_invtable_e[cube.eorl][cube.epose]) |
407 ((int)eo_invtable_m[cube.eorl][cube.eposm]) |
408 ((int)eo_invtable_s[cube.eorl][cube.eposs]);
409 ret.eoud = ((int)eo_invtable_e[cube.eoud][cube.epose]) |
410 ((int)eo_invtable_m[cube.eoud][cube.eposm]) |
411 ((int)eo_invtable_s[cube.eoud][cube.eposs]);
412 ret.cp = cp_invtable[cube.cp];
413 ret.cpos = cpos_invtable[cube.cpos];
414 ret.coud = co_invtable[cube.coud][cube.cp];
415 ret.corl = co_invtable[cube.corl][cube.cp];
416 ret.cofb = co_invtable[cube.cofb][cube.cp];
142 417
143 for (i = 0, sum_e = 0; i < 12; i++) 418 return ret;
144 if (c->eo[i] > 1) 419}
145 return false;
146 else
147 sum_e += c->eo[i];
148 420
149 for (i = 0, sum_c = 0; i < 8; i++) 421bool
150 if (c->co[i] > 2) 422is_admissible(Cube cube) {
151 return false; 423
152 else 424 /* TODO: this should check consistency of different orientations */
153 sum_c += c->co[i]; 425 /* check also that centers are opposite and admissible */
154 426
155 return (perm && sign % 2 == 0 && sum_e % 2 == 0 && sum_c % 2 == 0); 427 CubeArray *a = new_cubearray(cube, pf_all);
428 int parity;
429 bool perm;
430
431 perm = is_perm(a->ep, 12) &&
432 is_perm(a->cp, 8) &&
433 is_perm(a->cpos, 6);
434 parity = perm_sign(a->ep, 12) +
435 perm_sign(a->cp, 8) +
436 perm_sign(a->cpos, 6);
437
438 free_cubearray(a, pf_all);
439
440 return perm && parity % 2 == 0;
156} 441}
157 442
158bool 443bool
159is_solved(Cube *cube) 444is_solved(Cube cube)
160{ 445{
161 Cube solved_cube; 446 return equal(cube, (Cube){0});
162 make_solved(&solved_cube);
163
164 return equal(cube, &solved_cube);
165} 447}
166 448
167void 449bool
168make_solved_centers(Cube *cube) 450is_block_solved(Cube cube, Block block)
169{ 451{
170 static int sorted[6] = {0, 1, 2, 3, 4, 5}; 452 int i;
453
454 for (i = 0; i < 12; i++)
455 if (block.edge[i] && !is_solved_edge(cube, i))
456 return false;
457 for (i = 0; i < 8; i++)
458 if (block.corner[i] && !is_solved_corner(cube, i))
459 return false;
460 for (i = 0; i < 6; i++)
461 if (block.center[i] && !is_solved_center(cube, i))
462 return false;
171 463
172 memcpy(cube->xp, sorted, 6 * sizeof(int)); 464 return true;
173} 465}
174 466
175void 467bool
176make_solved_corners(Cube *cube) 468is_solved_center(Cube cube, Center c)
177{ 469{
178 static int sorted[8] = {0, 1, 2, 3, 4, 5, 6, 7}; 470 return what_center_at(cube, c) == c;
179
180 memcpy(cube->cp, sorted, 8 * sizeof(int));
181 memset(cube->co, 0, 8 * sizeof(int));
182} 471}
183 472
184void 473bool
185make_solved_edges(Cube *cube) 474is_solved_corner(Cube cube, Corner c)
186{ 475{
187 static int sorted[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; 476 return what_corner_at(cube, c) == c &&
477 what_orientation_corner(cube.coud, c);
478}
188 479
189 memcpy(cube->ep, sorted, 12 * sizeof(int)); 480bool
190 memset(cube->eo, 0, 12 * sizeof(int)); 481is_solved_edge(Cube cube, Edge e)
482{
483 return what_edge_at(cube, e) == e &&
484 what_orientation_edge(cube.eofb, e);
191} 485}
192 486
193void 487int
194make_solved(Cube *cube) 488piece_orientation(Cube cube, int piece, char *orientation)
195{ 489{
196 make_solved_centers(cube); 490 int arr[12], n, b, x;
197 make_solved_corners(cube); 491
198 make_solved_edges(cube); 492 if (!strcmp(orientation, "eofb")) {
493 x = cube.eofb;
494 n = 12;
495 b = 2;
496 } else if (!strcmp(orientation, "eorl")) {
497 x = cube.eorl;
498 n = 12;
499 b = 2;
500 } else if (!strcmp(orientation, "eoud")) {
501 x = cube.eoud;
502 n = 12;
503 b = 2;
504 } else if (!strcmp(orientation, "coud")) {
505 x = cube.coud;
506 n = 8;
507 b = 3;
508 } else if (!strcmp(orientation, "corl")) {
509 x = cube.corl;
510 n = 8;
511 b = 3;
512 } else if (!strcmp(orientation, "cofb")) {
513 x = cube.cofb;
514 n = 8;
515 b = 3;
516 } else {
517 return -1;
518 }
519
520 int_to_sum_zero_array(x, b, n, arr);
521 if (piece < n)
522 return arr[piece];
523
524 return -1;
199} 525}
200 526
201void 527void
202print_cube(Cube *cube) 528print_cube(Cube cube)
203{ 529{
204 static char edge_string[12][7] = { 530 static char edge_string[12][7] = {
205 [UF] = "UF", [UL] = "UL", [UB] = "UB", [UR] = "UR", 531 [UF] = "UF", [UL] = "UL", [UB] = "UB", [UR] = "UR",
@@ -219,52 +545,388 @@ print_cube(Cube *cube)
219 }; 545 };
220 546
221 for (int i = 0; i < 12; i++) 547 for (int i = 0; i < 12; i++)
222 printf(" %s ", edge_string[cube->ep[i]]); 548 printf(" %s ", edge_string[what_edge_at(cube, i)]);
223 printf("\n"); 549 printf("\n");
224 550
225 for (int i = 0; i < 12; i++) 551 for (int i = 0; i < 12; i++)
226 printf(" %" PRIu8 " ", cube->eo[i]); 552 printf(" %d ", what_orientation_edge(cube.eofb, i));
227 printf("\n"); 553 printf("\n");
228 554
229 for (int i = 0; i < 8; i++) 555 for (int i = 0; i < 8; i++)
230 printf("%s ", corner_string[cube->cp[i]]); 556 printf("%s ", corner_string[what_corner_at(cube, i)]);
231 printf("\n"); 557 printf("\n");
232 558
233 for (int i = 0; i < 8; i++) 559 for (int i = 0; i < 8; i++)
234 printf(" %" PRIu8 " ", cube->co[i]); 560 printf(" %d ", what_orientation_corner(cube.coud, i));
235 printf("\n"); 561 printf("\n");
236 562
237 for (int i = 0; i < 6; i++) 563 for (int i = 0; i < 6; i++)
238 printf(" %s ", center_string[cube->xp[i]]); 564 printf(" %s ", center_string[what_center_at(cube, i)]);
239 printf("\n"); 565 printf("\n");
240} 566}
241 567
242int 568Center
243where_is_center(Center x, Cube *c) 569what_center_at(Cube cube, Center c)
570{
571 static bool initialized = false;
572 static Center aux[FACTORIAL6][6];
573 static int i;
574 static unsigned int ui;
575 static CubeArray *arr;
576
577 if (!initialized) {
578 for (ui = 0; ui < FACTORIAL6; ui++) {
579 arr = new_cubearray((Cube){.cpos = ui}, pf_cpos);
580 for (i = 0; i < 6; i++)
581 aux[ui][i] = arr->cpos[i];
582 free_cubearray(arr, pf_cpos);
583 }
584
585 initialized = true;
586 }
587
588 return aux[cube.cpos][c];
589}
590
591Corner
592what_corner_at(Cube cube, Corner c)
593{
594 int i;
595 unsigned int ui;
596 CubeArray *arr;
597
598 static bool initialized = false;
599 static Corner aux[FACTORIAL8][8];
600
601 if (!initialized) {
602 for (ui = 0; ui < FACTORIAL8; ui++) {
603 arr = new_cubearray((Cube){.cp = ui}, pf_cp);
604 for (i = 0; i < 8; i++)
605 aux[ui][i] = arr->cp[i];
606 free_cubearray(arr, pf_cp);
607 }
608
609 initialized = true;
610 }
611
612 return aux[cube.cp][c];
613}
614
615Edge
616what_edge_at(Cube cube, Edge e)
244{ 617{
245 return where_is_piece(x, c->xp, 6); 618 Edge ret;
619 CubeArray *arr = new_cubearray(cube, pf_ep);
620
621 ret = arr->ep[e];
622
623 free_cubearray(arr, pf_ep);
624 return ret;
246} 625}
247 626
248int 627int
249where_is_corner(Corner k, Cube *c) 628what_orientation_corner(int co, Corner c)
250{ 629{
251 return where_is_piece(k, c->cp, 8); 630 static bool initialized = false;
631 static int auxlast[POW3TO7];
632 static int auxarr[8];
633 static unsigned int ui;
634
635 if (!initialized) {
636 for (ui = 0; ui < POW3TO7; ui++) {
637 int_to_sum_zero_array(ui, 3, 8, auxarr);
638 auxlast[ui] = auxarr[7];
639 }
640
641 initialized = true;
642 }
643
644 if (c < 7)
645 return (co / powint(3, c)) % 3;
646 else
647 return auxlast[co];
252} 648}
253 649
254int 650int
255where_is_edge(Edge e, Cube *c) 651what_orientation_edge(int eo, Edge e)
652{
653 static bool initialized = false;
654 static int auxlast[POW2TO11];
655 static int auxarr[12];
656 static unsigned int ui;
657
658 if (!initialized) {
659 for (ui = 0; ui < POW2TO11; ui++) {
660 int_to_sum_zero_array(ui, 2, 12, auxarr);
661 auxlast[ui] = auxarr[11];
662 }
663
664 initialized = true;
665 }
666
667 if (e < 11)
668 return (eo & (1 << e)) ? 1 : 0;
669 else
670 return auxlast[eo];
671}
672
673Center
674where_is_center(Cube cube, Center c)
256{ 675{
257 return where_is_piece(e, c->ep, 12); 676 static bool initialized = false;
677 static Center aux[FACTORIAL6][6];
678 static int i;
679 static unsigned int ui;
680 static CubeArray *arr;
681
682 if (!initialized) {
683 for (ui = 0; ui < FACTORIAL6; ui++) {
684 arr = new_cubearray((Cube){.cpos = ui}, pf_cpos);
685 for (i = 0; i < 6; i++)
686 aux[ui][arr->cpos[i]] = i;
687 free_cubearray(arr, pf_cpos);
688 }
689
690 initialized = true;
691 }
692
693 return aux[cube.cpos][c];
258} 694}
259 695
260static int 696Corner
261where_is_piece(int piece, int *arr, int n) 697where_is_corner(Cube cube, Corner c)
262{ 698{
263 int i; 699 static bool initialized = false;
700 static Corner aux[FACTORIAL8][8];
701 static int i;
702 static unsigned int ui;
703 static CubeArray *arr;
264 704
265 for (i = 0; i < n; i++) 705 if (!initialized) {
266 if (arr[i] == piece) 706 for (ui = 0; ui < FACTORIAL8; ui++) {
267 return i; 707 arr = new_cubearray((Cube){.cp = ui}, pf_cp);
708 for (i = 0; i < 8; i++)
709 aux[ui][arr->cp[i]] = i;
710 free_cubearray(arr, pf_cp);
711 }
268 712
269 return -1; 713 initialized = true;
714 }
715 return aux[cube.cp][c];
716}
717
718Edge
719where_is_edge(Cube c, Edge e)
720{
721 int r0, r1, r2;
722
723 static bool initialized = false;
724 static int aux[3][BINOM12ON4*FACTORIAL4][12];
725 static int i, j;
726 static unsigned int ui;
727 static CubeArray *arr;
728
729 if (!initialized) {
730 for (ui = 0; ui < BINOM12ON4*FACTORIAL4; ui++) {
731 for (i = 0; i < 3; i++)
732 for (j = 0; j < 12; j++)
733 aux[i][ui][j] = -1;
734
735 arr = new_cubearray((Cube){.epose = ui}, pf_e);
736 for (i = 0; i < 12; i++)
737 if (edge_slice(arr->ep[i]) == 0)
738 aux[0][ui][arr->ep[i]] = i;
739 free_cubearray(arr, pf_e);
740
741 arr = new_cubearray((Cube){.eposs = ui}, pf_s);
742 for (i = 0; i < 12; i++)
743 if (edge_slice(arr->ep[i]) == 1)
744 aux[1][ui][arr->ep[i]] = i;
745 free_cubearray(arr, pf_s);
746
747 arr = new_cubearray((Cube){.eposm = ui}, pf_m);
748 for (i = 0; i < 12; i++)
749 if (edge_slice(arr->ep[i]) == 2)
750 aux[2][ui][arr->ep[i]] = i;
751 free_cubearray(arr, pf_m);
752 }
753
754 initialized = true;
755 }
756
757 r0 = aux[0][c.epose][e];
758 r1 = aux[1][c.eposs][e];
759 r2 = aux[2][c.eposm][e];
760 return MAX(r0, MAX(r1, r2));
761}
762
763static bool
764read_invtables_file()
765{
766 init_env();
767
768 FILE *f;
769 char fname[strlen(tabledir)+20];
770 int b;
771 unsigned int ui, meeo, meco, mecp, mecpos;
772 bool r;
773
774 strcpy(fname, tabledir);
775 strcat(fname, "/invtables");
776
777 if ((f = fopen(fname, "rb")) == NULL)
778 return false;
779
780 b = sizeof(uint16_t);
781 r = true;
782 meeo = BINOM12ON4*FACTORIAL4;
783 meco = FACTORIAL8;
784 mecp = FACTORIAL8;
785 mecpos = FACTORIAL6;
786
787 for (ui = 0; ui < POW2TO11; ui++) {
788 r = r && fread(eo_invtable_e[ui], b, meeo, f) == meeo;
789 r = r && fread(eo_invtable_m[ui], b, meeo, f) == meeo;
790 r = r && fread(eo_invtable_s[ui], b, meeo, f) == meeo;
791 }
792
793 for (ui = 0; ui < POW3TO7; ui++) {
794 r = r && fread(co_invtable[ui], b, meco, f) == meco;
795 }
796
797 r = r && fread(cp_invtable, b, mecp, f) == mecp;
798 r = r && fread(cpos_invtable, b, mecpos, f) == mecpos;
799
800 fclose(f);
801 return r;
802}
803
804static bool
805write_invtables_file()
806{
807 init_env();
808
809 FILE *f;
810 char fname[strlen(tabledir)+20];
811 unsigned int ui, meeo, meco, mecp, mecpos;
812 int b;
813 bool r;
814
815 strcpy(fname, tabledir);
816 strcat(fname, "/invtables");
817
818 if ((f = fopen(fname, "wb")) == NULL)
819 return false;
820
821 b = sizeof(uint16_t);
822 r = true;
823 meeo = BINOM12ON4*FACTORIAL4;
824 meco = FACTORIAL8;
825 mecp = FACTORIAL8;
826 mecpos = FACTORIAL6;
827
828 for (ui = 0; ui < POW2TO11; ui++) {
829 r = r && fwrite(eo_invtable_e[ui], b, meeo, f) == meeo;
830 r = r && fwrite(eo_invtable_m[ui], b, meeo, f) == meeo;
831 r = r && fwrite(eo_invtable_s[ui], b, meeo, f) == meeo;
832 }
833
834 for (ui = 0; ui < POW3TO7; ui++) {
835 r = r && fwrite(co_invtable[ui], b, meco, f) == meco;
836 }
837
838 r = r && fwrite(cp_invtable, b, mecp, f) == mecp;
839 r = r && fwrite(cpos_invtable, b, mecpos, f) == mecpos;
840
841 fclose(f);
842 return r;
843}
844
845void
846init_inverse()
847{
848 static bool initialized = false;
849 if (initialized)
850 return;
851 initialized = true;
852
853 if (read_invtables_file())
854 return;
855
856 fprintf(stderr, "Cannot load invtables, generating it\n");
857
858 CubeArray *aux, *inv;
859 Cube c;
860 int i, j, eoaux[12], eoinv[12];
861 unsigned int ui, uj;
862
863 aux = new_cubearray((Cube){0}, pf_all);
864 inv = new_cubearray((Cube){0}, pf_all);
865
866 for (ui = 0; ui < POW2TO11; ui++) {
867 int_to_sum_zero_array(ui, 2, 12, eoaux);
868 for (uj = 0; uj < BINOM12ON4*FACTORIAL4; uj++) {
869 for (j = 0; j < 12; j++)
870 eoinv[j] = 0;
871 c = (Cube){.epose = uj, .eposm = 0, .eposs = 0};
872 eoinv[FR] = eoaux[where_is_edge(c, FR)];
873 eoinv[FL] = eoaux[where_is_edge(c, FL)];
874 eoinv[BL] = eoaux[where_is_edge(c, BL)];
875 eoinv[BR] = eoaux[where_is_edge(c, BR)];
876 eo_invtable_e[ui][uj] = digit_array_to_int(eoinv,11,2);
877
878 for (j = 0; j < 12; j++)
879 eoinv[j] = 0;
880 c = (Cube){.epose = 0, .eposm = uj, .eposs = 0};
881 eoinv[UF] = eoaux[where_is_edge(c, UF)];
882 eoinv[UB] = eoaux[where_is_edge(c, UB)];
883 eoinv[DF] = eoaux[where_is_edge(c, DF)];
884 eoinv[DB] = eoaux[where_is_edge(c, DB)];
885 eo_invtable_m[ui][uj] = digit_array_to_int(eoinv,11,2);
886
887 for (j = 0; j < 12; j++)
888 eoinv[j] = 0;
889 c = (Cube){.epose = 0, .eposm = 0, .eposs = uj};
890 eoinv[UL] = eoaux[where_is_edge(c, UL)];
891 eoinv[UR] = eoaux[where_is_edge(c, UR)];
892 eoinv[DL] = eoaux[where_is_edge(c, DL)];
893 eoinv[DR] = eoaux[where_is_edge(c, DR)];
894 eo_invtable_s[ui][uj] = digit_array_to_int(eoinv,11,2);
895 }
896 }
897
898 for (ui = 0; ui < FACTORIAL8; ui++) {
899 cube_to_arrays((Cube){.cp = ui}, aux, pf_cp);
900 for (i = 0; i < 8; i++)
901 inv->cp[aux->cp[i]] = i;
902 cp_invtable[ui] = (uint16_t)arrays_to_cube(inv, pf_cp).cp;
903
904 for (uj = 0; uj < POW3TO7; uj++) {
905 cube_to_arrays((Cube){.coud = uj}, aux, pf_coud);
906 for (i = 0; i < 8; i++)
907 inv->coud[aux->cp[i]] = (3-aux->coud[i])%3;
908 co_invtable[uj][ui] =
909 (uint16_t)arrays_to_cube(inv, pf_coud).coud;
910 }
911 }
912
913 for (ui = 0; ui < FACTORIAL6; ui++) {
914 cube_to_arrays((Cube){.cpos = ui}, aux, pf_cpos);
915 for (i = 0; i < 6; i++)
916 inv->cpos[aux->cpos[i]] = i;
917 cpos_invtable[ui] =
918 (uint16_t)arrays_to_cube(inv, pf_cpos).cpos;
919 }
920
921 free_cubearray(aux, pf_all);
922 free_cubearray(inv, pf_all);
923
924 if (!write_invtables_file())
925 fprintf(stderr, "Error writing invtables\n");
926}
927
928void
929init_cube()
930{
931 init_inverse();
270} 932}
diff --git a/src/cube.h b/src/cube.h
index f182b27..483a89a 100644
--- a/src/cube.h
+++ b/src/cube.h
@@ -3,33 +3,44 @@
3 3
4#include <stdio.h> 4#include <stdio.h>
5 5
6#include "cubetypes.h"
7#include "env.h" 6#include "env.h"
7#include "pf.h"
8#include "utils.h" 8#include "utils.h"
9 9
10void compose(Cube *c2, Cube *c1); /* Use c2 as an alg on c1 */ 10Cube admissible_ep(Cube cube, PieceFilter f);
11void compose_centers(Cube *c2, Cube *c1); 11int array_ep_to_epos(int *ep, int *eps_solved);
12void compose_corners(Cube *c2, Cube *c1); 12Cube arrays_to_cube(CubeArray *arr, PieceFilter f);
13void compose_edges(Cube *c2, Cube *c1); 13Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */
14void copy_cube(Cube *src, Cube *dst); 14Cube compose_filtered(Cube c2, Cube c1, PieceFilter f);
15void copy_cube_centers(Cube *src, Cube *dst); 15void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f);
16void copy_cube_corners(Cube *src, Cube *dst); 16int edge_slice(Edge e); /* E=0, S=1, M=2 */
17void copy_cube_edges(Cube *src, Cube *dst); 17bool equal(Cube c1, Cube c2);
18bool equal(Cube *c1, Cube *c2); 18Cube inverse_cube(Cube cube);
19void invert_cube(Cube *cube); 19bool is_admissible(Cube cube);
20void invert_cube_centers(Cube *cube); 20bool is_solved(Cube cube);
21void invert_cube_corners(Cube *cube); 21bool is_block_solved(Cube cube, Block);
22void invert_cube_edges(Cube *cube); 22bool is_solved_center(Cube cube, Center c);
23bool is_admissible(Cube *cube); 23bool is_solved_corner(Cube cube, Corner c);
24bool is_solved(Cube *cube); 24bool is_solved_edge(Cube cube, Edge e);
25void make_solved(Cube *cube); 25void epos_to_partial_ep(int epos, int *ep, int *ss);
26void make_solved_centers(Cube *cube); 26void epos_to_compatible_ep(int epos, int *ep, int *ss);
27void make_solved_corners(Cube *cube); 27void fix_eorleoud(CubeArray *arr);
28void make_solved_edges(Cube *cube); 28void fix_cofbcorl(CubeArray *arr);
29void print_cube(Cube *cube); 29Cube fourval_to_cube(int eofb, int ep, int coud, int cp);
30int where_is_center(Center x, Cube *c); 30void free_cubearray(CubeArray *arr, PieceFilter f);
31int where_is_corner(Corner k, Cube *c); 31Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf);
32int where_is_edge(Edge e, Cube *c); 32CubeArray * new_cubearray(Cube cube, PieceFilter f);
33void print_cube(Cube cube);
34Center what_center_at(Cube cube, Center c);
35Corner what_corner_at(Cube cube, Corner c);
36Edge what_edge_at(Cube cube, Edge e);
37int what_orientation_corner(int co, Corner c);
38int what_orientation_edge(int eo, Edge e);
39Center where_is_center(Cube cube, Center c);
40Corner where_is_corner(Cube cube, Corner c);
41Edge where_is_edge(Cube cube, Edge e);
42
43void init_cube();
33 44
34#endif 45#endif
35 46
diff --git a/src/cubetypes.h b/src/cubetypes.h
index 3752019..ad9c627 100644
--- a/src/cubetypes.h
+++ b/src/cubetypes.h
@@ -10,8 +10,6 @@
10#define NROTATIONS 24 10#define NROTATIONS 24
11#define entry_group_t uint8_t /* For pruning tables */ 11#define entry_group_t uint8_t /* For pruning tables */
12 12
13#define MAX_N_COORD 6
14
15/* Enums *********************************************************************/ 13/* Enums *********************************************************************/
16 14
17typedef enum 15typedef enum
@@ -30,12 +28,6 @@ corner
30} Corner; 28} Corner;
31 29
32typedef enum 30typedef enum
33coordtype
34{
35 COMP_COORD, SYM_COORD, SYMCOMP_COORD
36} CoordType;
37
38typedef enum
39edge 31edge
40{ 32{
41 UF, UL, UB, UR, 33 UF, UL, UB, UR,
@@ -84,32 +76,33 @@ trans
84typedef struct alg Alg; 76typedef struct alg Alg;
85typedef struct alglist AlgList; 77typedef struct alglist AlgList;
86typedef struct alglistnode AlgListNode; 78typedef struct alglistnode AlgListNode;
87typedef struct choicestep ChoiceStep; 79typedef struct block Block;
88typedef struct command Command; 80typedef struct command Command;
89typedef struct commandargs CommandArgs; 81typedef struct commandargs CommandArgs;
90typedef struct coordinate Coordinate; 82typedef struct coordinate Coordinate;
91typedef struct cube Cube; 83typedef struct cube Cube;
92/*typedef struct dfsarg DfsArg;*/ 84typedef struct cubearray CubeArray;
93typedef struct fstcube FstCube; 85typedef struct dfsarg DfsArg;
94typedef struct indexer Indexer; 86typedef struct estimatedata EstimateData;
95typedef struct movable Movable;
96typedef struct moveset Moveset; 87typedef struct moveset Moveset;
88typedef struct piecefilter PieceFilter;
97typedef struct prunedata PruneData; 89typedef struct prunedata PruneData;
98typedef struct solveoptions SolveOptions; 90typedef struct solveoptions SolveOptions;
99typedef struct step Step; 91typedef struct step Step;
100typedef struct symdata SymData; 92typedef struct symdata SymData;
101typedef struct threaddatasolve ThreadDataSolve; 93typedef struct threaddatasolve ThreadDataSolve;
102typedef struct threaddatagenpt ThreadDataGenpt; 94typedef struct threaddatagenpt ThreadDataGenpt;
103typedef struct transgroup TransGroup;
104 95
105typedef bool (*Checker) (Cube *); 96typedef Cube (*AntiIndexer) (uint64_t);
106typedef bool (*CubeTester) (Cube *, Alg *); 97typedef bool (*Checker) (Cube);
107/*typedef bool (*DfsMover) (DfsArg *);*/ 98typedef uint64_t (*CoordMover) (Move, uint64_t);
108typedef void (*DfsExtraCopier) (void *, void *); 99typedef uint64_t (*CoordTransformer) (Trans, uint64_t);
109typedef Alg * (*Validator) (Alg *); 100typedef int (*Estimator) (DfsArg *);
101typedef bool (*Validator) (Alg *);
110typedef void (*Exec) (CommandArgs *); 102typedef void (*Exec) (CommandArgs *);
103typedef uint64_t (*Indexer) (Cube);
111typedef CommandArgs * (*ArgParser) (int, char **); 104typedef CommandArgs * (*ArgParser) (int, char **);
112typedef bool (*Tester) (void); 105typedef int (*TransDetector) (Cube, Trans *);
113typedef int (*TransFinder) (uint64_t, Trans *); 106typedef int (*TransFinder) (uint64_t, Trans *);
114 107
115 108
@@ -122,10 +115,6 @@ alg
122 bool * inv; 115 bool * inv;
123 int len; 116 int len;
124 int allocated; 117 int allocated;
125 Move * move_normal;
126 int len_normal;
127 Move * move_inverse;
128 int len_inverse;
129}; 118};
130 119
131struct 120struct
@@ -144,13 +133,11 @@ alglistnode
144}; 133};
145 134
146struct 135struct
147choicestep 136block
148{ 137{
149 char * shortname; 138 bool edge[12];
150 char * name; 139 bool corner[8];
151 Step * step[99]; 140 bool center[6];
152 Trans t[99];
153 char * ready_msg;
154}; 141};
155 142
156struct 143struct
@@ -169,7 +156,7 @@ commandargs
169 bool success; 156 bool success;
170 Alg * scramble; 157 Alg * scramble;
171 SolveOptions * opts; 158 SolveOptions * opts;
172 ChoiceStep * cs; 159 Step * step;
173 Command * command; /* For help */ 160 Command * command; /* For help */
174 int n; 161 int n;
175 char scrtype[20]; 162 char scrtype[20];
@@ -180,119 +167,119 @@ commandargs
180struct 167struct
181coordinate 168coordinate
182{ 169{
183 char * name; 170 Indexer index;
184 CoordType type;
185 bool generated;
186 Indexer * i[99];
187 uint64_t max; 171 uint64_t max;
188 uint64_t * mtable[NMOVES]; 172 CoordMover move;
189 uint64_t * ttable[NTRANS]; 173 CoordTransformer transform;
190 TransGroup * tgrp; 174 SymData * sd;
191 Coordinate * base[2]; 175 TransFinder tfind; /* TODO: should be easy to remove */
192 uint64_t * symclass; 176 Coordinate * base; /* TODO: part of refactor */
193 uint64_t * symrep;
194 Trans * transtorep;
195 Trans * ttrep_move[NMOVES];
196 uint64_t * selfsim;
197}; 177};
198 178
199struct 179struct
200cube 180cube
201{ 181{
202 int ep[12]; 182 int epose;
203 int eo[12]; 183 int eposs;
204 int cp[8]; 184 int eposm;
205 int co[8]; 185 int eofb;
206 int xp[6]; 186 int eorl;
187 int eoud;
188 int cp;
189 int coud;
190 int cofb;
191 int corl;
192 int cpos;
207}; 193};
208 194
209/*
210struct 195struct
211movable 196cubearray
212{ 197{
213 uint64_t val; 198 int * ep;
214 Trans t; 199 int * eofb;
200 int * eorl;
201 int * eoud;
202 int * cp;
203 int * coud;
204 int * corl;
205 int * cofb;
206 int * cpos;
215}; 207};
216*/
217 208
218/*
219struct 209struct
220dfsarg 210dfsarg
221{ 211{
222 Cube * cube; 212 Step * step;
223 Movable ind[MAX_N_COORD];
224 Trans t;
225 Step * s;
226 SolveOptions * opts; 213 SolveOptions * opts;
214 Trans t;
215 Cube cube;
216 Cube inverse;
227 int d; 217 int d;
228 int bound; 218 uint64_t badmoves;
219 uint64_t badmovesinv;
229 bool niss; 220 bool niss;
221 Move last1;
222 Move last2;
223 Move last1inv;
224 Move last2inv;
225 EstimateData * ed;
230 AlgList * sols; 226 AlgList * sols;
231 pthread_mutex_t * sols_mutex; 227 pthread_mutex_t * sols_mutex;
232 Alg * current_alg; 228 Alg * current_alg;
233 void * extra;
234}; 229};
235*/
236 230
237/*
238struct 231struct
239dfsarg 232estimatedata
240{ 233{
241 void * cube_data; 234 int corners;
242 SolveOptions * opts; 235 int normal_ud;
243 int d; 236 int normal_fb;
244 int bound; 237 int normal_rl;
245 bool niss; 238 int inverse_ud;
246 AlgList * sols; 239 int inverse_fb;
247 Alg * current_alg; 240 int inverse_rl;
248 Solver * solver; 241 int oldret;
249 Threader * threader;
250}; 242};
251*/
252 243
253struct 244struct
254fstcube 245moveset
255{ 246{
256 uint16_t uf_eofb; 247 bool (*allowed)(Move);
257 uint16_t uf_eposepe; 248 bool (*allowed_next)(Move, Move, Move);
258 uint16_t uf_coud; 249 Move sorted_moves[NMOVES+1];
259 uint16_t uf_cp; 250 uint64_t mask[NMOVES][NMOVES];
260 uint16_t fr_eofb;
261 uint16_t fr_eposepe;
262 uint16_t fr_coud;
263 uint16_t rd_eofb;
264 uint16_t rd_eposepe;
265 uint16_t rd_coud;
266}; 251};
267 252
268struct 253struct
269indexer 254piecefilter
270{ 255{
271 int n; 256 bool epose;
272 uint64_t (*index)(Cube *); 257 bool eposs;
273 void (*to_cube)(uint64_t, Cube *); 258 bool eposm;
274}; 259 bool eofb;
275 260 bool eorl;
276struct 261 bool eoud;
277moveset 262 bool cp;
278{ 263 bool coud;
279 char * name; 264 bool cofb;
280 bool (*allowed)(Move); 265 bool corl;
281 bool (*can_append)(Alg *, Move, bool); 266 bool cpos;
282 bool (*cancel_niss)(Alg *);
283 Move sorted_moves[NMOVES+1];
284}; 267};
285 268
286struct 269struct
287prunedata 270prunedata
288{ 271{
272 char * filename;
289 entry_group_t * ptable; 273 entry_group_t * ptable;
274 bool generated;
290 uint64_t n; 275 uint64_t n;
291 Coordinate * coord; 276 Coordinate * coord;
292 Moveset * moveset; 277 Moveset * moveset;
293 uint64_t count[16];
294 bool compact; 278 bool compact;
295 int base; 279 int base;
280 uint64_t count[16];
281 PruneData * fallback;
282 uint64_t fbmod;
296}; 283};
297 284
298struct 285struct
@@ -313,30 +300,52 @@ solveoptions
313struct 300struct
314step 301step
315{ 302{
316 Checker ready; 303 char * shortname;
304 char * name;
317 bool final; 305 bool final;
318 Moveset * moveset; 306 Checker is_done;
319 int n_coord; 307 Estimator estimate;
320 Coordinate * coord[MAX_N_COORD]; 308 Checker ready;
321 Trans coord_trans[MAX_N_COORD]; 309 char * ready_msg;
322 PruneData * pd[MAX_N_COORD];
323 bool pd_compact[MAX_N_COORD];
324 Validator is_valid; 310 Validator is_valid;
325 /*DfsMover custom_move_checkstop;*/ 311 Moveset * moveset;
326 DfsExtraCopier copy_extra; 312 Trans pre_trans;
313 TransDetector detect;
314 int ntables;
315 PruneData * tables[10];
316};
317
318struct
319symdata
320{
321 char * filename;
322 bool generated;
323 Coordinate * coord;
324 Coordinate * sym_coord;
325 int ntrans;
326 Trans * trans;
327 uint64_t * class;
328 uint64_t * unsym;
329 Trans * transtorep;
330 uint64_t * selfsim;
331 CoordTransformer transform; /* TODO: remove, use that of base coord */
327}; 332};
328 333
329/*
330struct 334struct
331threaddatasolve 335threaddatasolve
332{ 336{
333 DfsArg arg;
334 int thid; 337 int thid;
338 Trans t;
339 Cube cube;
340 Step * step;
341 int depth;
342 SolveOptions * opts;
335 AlgList * start; 343 AlgList * start;
336 AlgListNode ** node; 344 AlgListNode ** node;
345 AlgList * sols;
337 pthread_mutex_t * start_mutex; 346 pthread_mutex_t * start_mutex;
347 pthread_mutex_t * sols_mutex;
338}; 348};
339*/
340 349
341struct 350struct
342threaddatagenpt 351threaddatagenpt
@@ -350,11 +359,4 @@ threaddatagenpt
350 pthread_mutex_t * upmutex; 359 pthread_mutex_t * upmutex;
351}; 360};
352 361
353struct
354transgroup
355{
356 int n;
357 Trans t[NTRANS];
358};
359
360#endif 362#endif
diff --git a/src/env.c b/src/env.c
index 375bfa8..282bc8f 100644
--- a/src/env.c
+++ b/src/env.c
@@ -1,5 +1,3 @@
1#define ENV_C
2
3#include "env.h" 1#include "env.h"
4 2
5bool initialized_env = false; 3bool initialized_env = false;
diff --git a/src/env.h b/src/env.h
index a49d643..871a9c1 100644
--- a/src/env.h
+++ b/src/env.h
@@ -8,8 +8,8 @@
8#include <unistd.h> 8#include <unistd.h>
9#include <sys/stat.h> 9#include <sys/stat.h>
10 10
11void init_env();
12
13extern char *tabledir; 11extern char *tabledir;
14 12
13void init_env();
14
15#endif 15#endif
diff --git a/src/fst.c b/src/fst.c
deleted file mode 100644
index b51e2d4..0000000
--- a/src/fst.c
+++ /dev/null
@@ -1,401 +0,0 @@
1#define FST_C
2
3#include "fst.h"
4
5static FstCube ep_to_fst_epos(int *ep);
6static void init_fst_corner_invtables();
7static void init_fst_eo_invtables();
8static void init_fst_eo_update(uint64_t, uint64_t, int, Cube *);
9static void init_fst_where_is_edge();
10static bool read_fst_tables_file();
11static bool write_fst_tables_file();
12
13static int edge_slice[12] = {[FR] = 0, [FL] = 0, [BL] = 0, [BR] = 0,
14 [UL] = 1, [UR] = 1, [DR] = 1, [DL] = 1,
15 [UF] = 2, [UB] = 2, [DF] = 2, [DB] = 2};
16
17static uint16_t inv_coud[FACTORIAL8][POW3TO7];
18static uint16_t inv_cp[FACTORIAL8];
19static uint16_t uf_cp_to_fr_cp[FACTORIAL8];
20static uint16_t uf_cp_to_rd_cp[FACTORIAL8];
21static uint16_t eo_invtable[3][POW2TO11][BINOM12ON4*FACTORIAL4];
22static uint16_t fst_where_is_edge_arr[3][12][BINOM12ON4*FACTORIAL4];
23
24FstCube
25cube_to_fst(Cube *cube)
26{
27 Cube c;
28 FstCube ret;
29
30 copy_cube(cube, &c);
31 ret.uf_eofb = coord_eofb.i[0]->index(&c);
32 ret.uf_eposepe = coord_eposepe.i[0]->index(&c);
33 ret.uf_coud = coord_coud.i[0]->index(&c);
34 ret.uf_cp = coord_cp.i[0]->index(&c);
35 copy_cube(cube, &c);
36 apply_trans(fr, &c);
37 ret.fr_eofb = coord_eofb.i[0]->index(&c);
38 ret.fr_eposepe = coord_eposepe.i[0]->index(&c);
39 ret.fr_coud = coord_coud.i[0]->index(&c);
40 copy_cube(cube, &c);
41 apply_trans(rd, &c);
42 ret.rd_eofb = coord_eofb.i[0]->index(&c);
43 ret.rd_eposepe = coord_eposepe.i[0]->index(&c);
44 ret.rd_coud = coord_coud.i[0]->index(&c);
45
46 return ret;
47}
48
49static FstCube
50ep_to_fst_epos(int *ep)
51{
52 static int eind[12] = {
53 [FR] = 0, [FL] = 1, [BL] = 2, [BR] = 3,
54 [UR] = 0, [DR] = 1, [DL] = 2, [UL] = 3,
55 [DB] = 0, [DF] = 1, [UF] = 2, [UB] = 3
56 };
57 static int eptrans_fr[12] = {
58 [FR] = UF, [DF] = UL, [FL] = UB, [UF] = UR,
59 [BR] = DF, [DB] = DL, [BL] = DB, [UB] = DR,
60 [UR] = FR, [DR] = FL, [DL] = BL, [UL] = BR
61 };
62 static int eptrans_rd[12] = {
63 [DR] = UF, [FR] = UL, [UR] = UB, [BR] = UR,
64 [DL] = DF, [FL] = DL, [UL] = DB, [BL] = DR,
65 [DB] = FR, [DF] = FL, [UF] = BL, [UB] = BR
66 };
67
68 FstCube ret;
69 int i, ce, cs, cm;
70 int epe[4], eps[4], epm[4], epose[12], eposs[12], eposm[12];
71
72 memset(epose, 0, 12*sizeof(int));
73 memset(eposs, 0, 12*sizeof(int));
74 memset(eposm, 0, 12*sizeof(int));
75
76 for (i = 0, ce = 0; i < 12; i++) {
77 switch (edge_slice[ep[i]]) {
78 case 0:
79 epose[i] = 1;
80 epe[ce++] = eind[ep[i]];
81 break;
82 case 1:
83 eposs[eptrans_fr[i]] = eind[ep[i]] + 1;
84 break;
85 default:
86 eposm[eptrans_rd[i]] = eind[ep[i]] + 1;
87 break;
88 }
89 }
90
91 for (i = 0, cs = 0, cm = 0; i < 12; i++) {
92 if (eposs[i]) {
93 eps[cs++] = eposs[i] - 1;
94 eposs[i] = 1;
95 }
96 if (eposm[i]) {
97 epm[cm++] = eposm[i] - 1;
98 eposm[i] = 1;
99 }
100 }
101
102 ret.uf_eposepe = subset_to_index(epose, 12, 4) * FACTORIAL4 +
103 perm_to_index(epe, 4);
104 ret.fr_eposepe = subset_to_index(eposs, 12, 4) * FACTORIAL4 +
105 perm_to_index(eps, 4);
106 ret.rd_eposepe = subset_to_index(eposm, 12, 4) * FACTORIAL4 +
107 perm_to_index(epm, 4);
108
109 return ret;
110}
111
112FstCube
113fst_inverse(FstCube fst)
114{
115 FstCube ret;
116 int ep_inv[12];
117
118 ep_inv[FR] = fst_where_is_edge_arr[0][FR][fst.uf_eposepe];
119 ep_inv[FL] = fst_where_is_edge_arr[0][FL][fst.uf_eposepe];
120 ep_inv[BL] = fst_where_is_edge_arr[0][BL][fst.uf_eposepe];
121 ep_inv[BR] = fst_where_is_edge_arr[0][BR][fst.uf_eposepe];
122
123 ep_inv[UR] = fst_where_is_edge_arr[1][UR][fst.fr_eposepe];
124 ep_inv[UL] = fst_where_is_edge_arr[1][UL][fst.fr_eposepe];
125 ep_inv[DR] = fst_where_is_edge_arr[1][DR][fst.fr_eposepe];
126 ep_inv[DL] = fst_where_is_edge_arr[1][DL][fst.fr_eposepe];
127
128 ep_inv[UF] = fst_where_is_edge_arr[2][UF][fst.rd_eposepe];
129 ep_inv[UB] = fst_where_is_edge_arr[2][UB][fst.rd_eposepe];
130 ep_inv[DF] = fst_where_is_edge_arr[2][DF][fst.rd_eposepe];
131 ep_inv[DB] = fst_where_is_edge_arr[2][DB][fst.rd_eposepe];
132
133 ret = ep_to_fst_epos(ep_inv);
134
135 ret.uf_eofb = ((uint16_t)eo_invtable[0][fst.uf_eofb][fst.uf_eposepe]) |
136 ((uint16_t)eo_invtable[1][fst.uf_eofb][fst.fr_eposepe]) |
137 ((uint16_t)eo_invtable[2][fst.uf_eofb][fst.rd_eposepe]);
138 ret.fr_eofb = ((uint16_t)eo_invtable[0][fst.fr_eofb][fst.uf_eposepe]) |
139 ((uint16_t)eo_invtable[1][fst.fr_eofb][fst.fr_eposepe]) |
140 ((uint16_t)eo_invtable[2][fst.fr_eofb][fst.rd_eposepe]);
141 ret.rd_eofb = ((uint16_t)eo_invtable[0][fst.rd_eofb][fst.uf_eposepe]) |
142 ((uint16_t)eo_invtable[1][fst.rd_eofb][fst.fr_eposepe]) |
143 ((uint16_t)eo_invtable[2][fst.rd_eofb][fst.rd_eposepe]);
144
145 ret.uf_cp = inv_cp[fst.uf_cp];
146
147 ret.uf_coud = inv_coud[fst.uf_cp][fst.uf_coud];
148 ret.fr_coud = inv_coud[uf_cp_to_fr_cp[fst.uf_cp]][fst.fr_coud];
149 ret.rd_coud = inv_coud[uf_cp_to_rd_cp[fst.uf_cp]][fst.rd_coud];
150
151 return ret;
152}
153
154FstCube
155fst_move(Move m, FstCube fst)
156{
157 FstCube ret;
158 Move m_fr, m_rd;
159
160 m_fr = transform_move(fr, m);
161 m_rd = transform_move(rd, m);
162
163 ret.uf_eofb = coord_eofb.mtable[m][fst.uf_eofb];
164 ret.uf_eposepe = coord_eposepe.mtable[m][fst.uf_eposepe];
165 ret.uf_coud = coord_coud.mtable[m][fst.uf_coud];
166 ret.uf_cp = coord_cp.mtable[m][fst.uf_cp];
167
168 ret.fr_eofb = coord_eofb.mtable[m_fr][fst.fr_eofb];
169 ret.fr_eposepe = coord_eposepe.mtable[m_fr][fst.fr_eposepe];
170 ret.fr_coud = coord_coud.mtable[m_fr][fst.fr_coud];
171
172 ret.rd_eofb = coord_eofb.mtable[m_rd][fst.rd_eofb];
173 ret.rd_eposepe = coord_eposepe.mtable[m_rd][fst.rd_eposepe];
174 ret.rd_coud = coord_coud.mtable[m_rd][fst.rd_coud];
175
176 return ret;
177}
178
179void
180fst_to_cube(FstCube fst, Cube *cube)
181{
182 Cube e, s, m;
183 int i;
184
185 coord_eposepe.i[0]->to_cube(fst.uf_eposepe, &e);
186 coord_eposepe.i[0]->to_cube(fst.fr_eposepe, &s);
187 apply_trans(inverse_trans(fr), &s);
188 coord_eposepe.i[0]->to_cube(fst.rd_eposepe, &m);
189 apply_trans(inverse_trans(rd), &m);
190
191 for (i = 0; i < 12; i++) {
192 if (edge_slice[e.ep[i]] == 0)
193 cube->ep[i] = e.ep[i];
194 if (edge_slice[s.ep[i]] == 1)
195 cube->ep[i] = s.ep[i];
196 if (edge_slice[m.ep[i]] == 2)
197 cube->ep[i] = m.ep[i];
198 }
199
200 coord_eofb.i[0]->to_cube((uint64_t)fst.uf_eofb, cube);
201 coord_coud.i[0]->to_cube((uint64_t)fst.uf_coud, cube);
202 coord_cp.i[0]->to_cube((uint64_t)fst.uf_cp, cube);
203
204 for (i = 0; i < 6; i++)
205 cube->xp[i] = i;
206}
207
208void
209init_fst()
210{
211 init_trans();
212 gen_coord(&coord_eofb);
213 gen_coord(&coord_eposepe);
214 gen_coord(&coord_coud);
215 gen_coord(&coord_cp);
216
217 if (!read_fst_tables_file()) {
218 fprintf(stderr,
219 "Could not load fst_tables, generating them\n");
220 init_fst_corner_invtables();
221 init_fst_eo_invtables();
222 init_fst_where_is_edge();
223 if (!write_fst_tables_file())
224 fprintf(stderr, "fst_tables could not be written\b");
225 }
226}
227
228static void
229init_fst_corner_invtables()
230{
231 Cube c, d;
232 uint64_t cp, coud;
233
234 for (cp = 0; cp < FACTORIAL8; cp++) {
235 make_solved_corners(&c);
236 coord_cp.i[0]->to_cube(cp, &c);
237
238 copy_cube_corners(&c, &d);
239 invert_cube_corners(&d);
240 inv_cp[cp] = coord_cp.i[0]->index(&d);
241
242 for (coud = 0; coud < POW3TO7; coud++) {
243 copy_cube_corners(&c, &d);
244 coord_coud.i[0]->to_cube(coud, &d);
245 invert_cube_corners(&d);
246 inv_coud[cp][coud] = coord_coud.i[0]->index(&d);
247 }
248
249 copy_cube_corners(&c, &d);
250 apply_trans(fr, &d);
251 uf_cp_to_fr_cp[cp] = coord_cp.i[0]->index(&d);
252
253 copy_cube_corners(&c, &d);
254 apply_trans(rd, &d);
255 uf_cp_to_rd_cp[cp] = coord_cp.i[0]->index(&d);
256 }
257}
258
259static void
260init_fst_eo_invtables()
261{
262 uint64_t ep, eo;
263 Cube c, d;
264
265 for (ep = 0; ep < BINOM12ON4 * FACTORIAL4; ep++) {
266 make_solved(&c);
267 coord_eposepe.i[0]->to_cube(ep, &c);
268 for (eo = 0; eo < POW2TO11; eo++) {
269 copy_cube_edges(&c, &d);
270 coord_eofb.i[0]->to_cube(eo, &d);
271 init_fst_eo_update(eo, ep, 0, &d);
272
273 apply_trans(inverse_trans(fr), &d);
274 coord_eofb.i[0]->to_cube(eo, &d);
275 init_fst_eo_update(eo, ep, 1, &d);
276
277 copy_cube_edges(&c, &d);
278 apply_trans(inverse_trans(rd), &d);
279 coord_eofb.i[0]->to_cube(eo, &d);
280 init_fst_eo_update(eo, ep, 2, &d);
281 }
282 }
283}
284
285static void
286init_fst_eo_update(uint64_t eo, uint64_t ep, int s, Cube *d)
287{
288 int i;
289
290 for (i = 0; i < 12; i++) {
291 if (edge_slice[d->ep[i]] == s && d->eo[i] && d->ep[i] != 11)
292 eo_invtable[s][eo][ep] |=
293 ((uint16_t)1) << ((uint16_t)d->ep[i]);
294 }
295}
296
297static void
298init_fst_where_is_edge()
299{
300 Cube c, d;
301 uint64_t e;
302
303 make_solved(&c);
304 for (e = 0; e < BINOM12ON4 * FACTORIAL4; e++) {
305 coord_eposepe.i[0]->to_cube(e, &c);
306
307 copy_cube_edges(&c, &d);
308 fst_where_is_edge_arr[0][FR][e] = where_is_edge(FR, &d);
309 fst_where_is_edge_arr[0][FL][e] = where_is_edge(FL, &d);
310 fst_where_is_edge_arr[0][BL][e] = where_is_edge(BL, &d);
311 fst_where_is_edge_arr[0][BR][e] = where_is_edge(BR, &d);
312
313 copy_cube_edges(&c, &d);
314 apply_trans(inverse_trans(fr), &d);
315 fst_where_is_edge_arr[1][UL][e] = where_is_edge(UL, &d);
316 fst_where_is_edge_arr[1][UR][e] = where_is_edge(UR, &d);
317 fst_where_is_edge_arr[1][DL][e] = where_is_edge(DL, &d);
318 fst_where_is_edge_arr[1][DR][e] = where_is_edge(DR, &d);
319
320 copy_cube_edges(&c, &d);
321 apply_trans(inverse_trans(rd), &d);
322 fst_where_is_edge_arr[2][UF][e] = where_is_edge(UF, &d);
323 fst_where_is_edge_arr[2][UB][e] = where_is_edge(UB, &d);
324 fst_where_is_edge_arr[2][DF][e] = where_is_edge(DF, &d);
325 fst_where_is_edge_arr[2][DB][e] = where_is_edge(DB, &d);
326 }
327}
328
329static bool
330read_fst_tables_file()
331{
332 init_env();
333
334 FILE *f;
335 char fname[strlen(tabledir)+256];
336 uint64_t i, j, r, total;
337
338 strcpy(fname, tabledir);
339 strcat(fname, "/fst_tables");
340
341 if ((f = fopen(fname, "rb")) == NULL)
342 return false;
343
344 r = 0;
345 total = FACTORIAL8*(POW3TO7+3) + 3*BINOM12ON4*FACTORIAL4*(12+POW2TO11);
346
347 for (i = 0; i < FACTORIAL8; i++)
348 r += fread(inv_coud[i], sizeof(uint16_t), POW3TO7, f);
349 r += fread(inv_cp, sizeof(uint16_t), FACTORIAL8, f);
350 r += fread(uf_cp_to_fr_cp, sizeof(uint16_t), FACTORIAL8, f);
351 r += fread(uf_cp_to_rd_cp, sizeof(uint16_t), FACTORIAL8, f);
352 for (i = 0; i < 3; i++)
353 for (j = 0; j < POW2TO11; j++)
354 r += fread(eo_invtable[i][j],
355 sizeof(uint16_t), BINOM12ON4*FACTORIAL4, f);
356 for (i = 0; i < 3; i++)
357 for (j = 0; j < 12; j++)
358 r += fread(fst_where_is_edge_arr[i][j],
359 sizeof(uint16_t), BINOM12ON4*FACTORIAL4, f);
360
361 fclose(f);
362
363 return r == total;
364}
365
366static bool
367write_fst_tables_file()
368{
369 init_env();
370
371 FILE *f;
372 char fname[strlen(tabledir)+256];
373 uint64_t i, j, w, total;
374
375 strcpy(fname, tabledir);
376 strcat(fname, "/fst_tables");
377
378 if ((f = fopen(fname, "wb")) == NULL)
379 return false;
380
381 w = 0;
382 total = FACTORIAL8*(POW3TO7+3) + 3*BINOM12ON4*FACTORIAL4*(12+POW2TO11);
383
384 for (i = 0; i < FACTORIAL8; i++)
385 w += fwrite(inv_coud[i], sizeof(uint16_t), POW3TO7, f);
386 w += fwrite(inv_cp, sizeof(uint16_t), FACTORIAL8, f);
387 w += fwrite(uf_cp_to_fr_cp, sizeof(uint16_t), FACTORIAL8, f);
388 w += fwrite(uf_cp_to_rd_cp, sizeof(uint16_t), FACTORIAL8, f);
389 for (i = 0; i < 3; i++)
390 for (j = 0; j < POW2TO11; j++)
391 w += fwrite(eo_invtable[i][j],
392 sizeof(uint16_t), BINOM12ON4*FACTORIAL4, f);
393 for (i = 0; i < 3; i++)
394 for (j = 0; j < 12; j++)
395 w += fwrite(fst_where_is_edge_arr[i][j],
396 sizeof(uint16_t), BINOM12ON4*FACTORIAL4, f);
397
398 fclose(f);
399
400 return w == total;
401}
diff --git a/src/fst.h b/src/fst.h
deleted file mode 100644
index c3b226c..0000000
--- a/src/fst.h
+++ /dev/null
@@ -1,13 +0,0 @@
1#ifndef FST_H
2#define FST_H
3
4#include "coord.h"
5
6FstCube cube_to_fst(Cube *cube);
7FstCube fst_inverse(FstCube fst);
8FstCube fst_move(Move m, FstCube fst);
9void fst_to_cube(FstCube fst, Cube *cube);
10void init_fst();
11
12#endif
13
diff --git a/src/moves.c b/src/moves.c
index a9dfdc0..02880ca 100644
--- a/src/moves.c
+++ b/src/moves.c
@@ -1,18 +1,79 @@
1#define MOVES_C
2
3#include "moves.h" 1#include "moves.h"
4 2
5/* Local functions ***********************************************************/ 3/* Local functions ***********************************************************/
6 4
5static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f);
7static void cleanup_aux(Alg *alg, Alg *ret, bool inv); 6static void cleanup_aux(Alg *alg, Alg *ret, bool inv);
7static bool read_mtables_file();
8static bool write_mtables_file();
8 9
9/* Tables and other data *****************************************************/ 10/* Tables and other data *****************************************************/
10 11
11/* Moves are represented as cubes and applied using compose(). Every move is * 12/* Every move is translated to a an <U, x, y> alg before filling the
12 * translated to a an <U, x, y> alg before filling the transition tables. * 13 transition tables, see init_moves() */
13 * See init_moves(). */ 14
15static int edge_cycle[NMOVES][12] =
16{
17 [U] = { UR, UF, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR },
18 [x] = { DF, FL, UF, FR, DB, BL, UB, BR, DR, DL, UL, UR },
19 [y] = { UR, UF, UL, UB, DR, DF, DL, DB, BR, FR, FL, BL }
20};
21
22static int corner_cycle[NMOVES][8] =
23{
24 [U] = { UBR, UFR, UFL, UBL, DFR, DFL, DBL, DBR },
25 [x] = { DFR, DFL, UFL, UFR, DBR, DBL, UBL, UBR },
26 [y] = { UBR, UFR, UFL, UBL, DBR, DFR, DFL, DBL }
27};
28
29static int center_cycle[NMOVES][6] =
30{
31 [x] = { F_center, B_center, R_center, L_center, D_center, U_center },
32 [y] = { U_center, D_center, B_center, F_center, R_center, L_center }
33};
34
35static int eofb_flipped[NMOVES][12] = {
36 [x] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 },
37 [y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 }
38};
39
40static int eorl_flipped[NMOVES][12] = {
41 [x] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
42 [y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 }
43};
44
45static int eoud_flipped[NMOVES][12] = {
46 [U] = { [UF] = 1, [UL] = 1, [UB] = 1, [UR] = 1 },
47 [x] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 },
48 [y] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
49};
50
51static int coud_flipped[NMOVES][8] = {
52 [x] = {
53 [UFR] = 2, [UBR] = 1, [UFL] = 1, [UBL] = 2,
54 [DBR] = 2, [DFR] = 1, [DBL] = 1, [DFL] = 2
55 }
56};
57
58static int corl_flipped[NMOVES][8] = {
59 [U] = { [UFR] = 1, [UBR] = 2, [UBL] = 1, [UFL] = 2 },
60 [y] = {
61 [UFR] = 1, [UBR] = 2, [UBL] = 1, [UFL] = 2,
62 [DFR] = 2, [DBR] = 1, [DBL] = 2, [DFL] = 1
63 }
64};
14 65
15static Cube move_array[NMOVES]; 66static int cofb_flipped[NMOVES][8] = {
67 [U] = { [UFR] = 2, [UBR] = 1, [UBL] = 2, [UFL] = 1 },
68 [x] = {
69 [UFR] = 1, [UBR] = 2, [UBL] = 1, [UFL] = 2,
70 [DFR] = 2, [DBR] = 1, [DBL] = 2, [DFL] = 1
71 },
72 [y] = {
73 [UFR] = 2, [UBR] = 1, [UBL] = 2, [UFL] = 1,
74 [DFR] = 1, [DBR] = 2, [DBL] = 1, [DFL] = 2
75 }
76};
16 77
17static char equiv_alg_string[100][NMOVES] = { 78static char equiv_alg_string[100][NMOVES] = {
18 [NULLMOVE] = "", 79 [NULLMOVE] = "",
@@ -76,52 +137,89 @@ static char equiv_alg_string[100][NMOVES] = {
76 [z3] = " y x yyy " 137 [z3] = " y x yyy "
77}; 138};
78 139
140/* Transition tables, to be loaded up at the beginning */
141int epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
142int eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
143int eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
144int eofb_mtable[NMOVES][POW2TO11];
145int eorl_mtable[NMOVES][POW2TO11];
146int eoud_mtable[NMOVES][POW2TO11];
147int cp_mtable[NMOVES][FACTORIAL8];
148int coud_mtable[NMOVES][POW3TO7];
149int cofb_mtable[NMOVES][POW3TO7];
150int corl_mtable[NMOVES][POW3TO7];
151int cpos_mtable[NMOVES][FACTORIAL6];
152
153
154/* Local functions implementation ********************************************/
155
156static Cube
157apply_move_cubearray(Move m, Cube cube, PieceFilter f)
158{
159 /*init_moves();*/
160
161 CubeArray m_arr = {
162 edge_cycle[m],
163 eofb_flipped[m],
164 eorl_flipped[m],
165 eoud_flipped[m],
166 corner_cycle[m],
167 coud_flipped[m],
168 corl_flipped[m],
169 cofb_flipped[m],
170 center_cycle[m]
171 };
172
173 return move_via_arrays(&m_arr, cube, f);
174}
79 175
80/* Public functions **********************************************************/ 176/* Public functions **********************************************************/
81 177
82void 178Cube
83apply_alg(Alg *alg, Cube *cube) 179apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a)
84{ 180{
85 Cube aux; 181 Cube ret = {0};
86 int i; 182 int i;
87 183
88 copy_cube(cube, &aux);
89 make_solved(cube);
90
91 for (i = 0; i < alg->len; i++) 184 for (i = 0; i < alg->len; i++)
92 if (alg->inv[i]) 185 if (alg->inv[i])
93 apply_move(alg->move[i], cube); 186 ret = a ? apply_move(alg->move[i], ret) :
187 apply_move_cubearray(alg->move[i], ret, f);
94 188
95 invert_cube(cube); 189 ret = compose_filtered(c, inverse_cube(ret), f);
96 compose(&aux, cube);
97 190
98 for (i = 0; i < alg->len; i++) 191 for (i = 0; i < alg->len; i++)
99 if (!alg->inv[i]) 192 if (!alg->inv[i])
100 apply_move(alg->move[i], cube); 193 ret = a ? apply_move(alg->move[i], ret) :
101} 194 apply_move_cubearray(alg->move[i], ret, f);
102 195
103void 196 return ret;
104apply_move(Move m, Cube *cube)
105{
106 compose(&move_array[m], cube);
107} 197}
108 198
109void 199Cube
110apply_move_centers(Move m, Cube *cube) 200apply_alg(Alg *alg, Cube cube)
111{ 201{
112 compose_centers(&move_array[m], cube); 202 return apply_alg_generic(alg, cube, pf_all, true);
113} 203}
114 204
115void 205Cube
116apply_move_corners(Move m, Cube *cube) 206apply_move(Move m, Cube cube)
117{ 207{
118 compose_corners(&move_array[m], cube); 208 /*init_moves();*/
119}
120 209
121void 210 return (Cube) {
122apply_move_edges(Move m, Cube *cube) 211 .epose = epose_mtable[m][cube.epose],
123{ 212 .eposs = eposs_mtable[m][cube.eposs],
124 compose_edges(&move_array[m], cube); 213 .eposm = eposm_mtable[m][cube.eposm],
214 .eofb = eofb_mtable[m][cube.eofb],
215 .eorl = eorl_mtable[m][cube.eorl],
216 .eoud = eoud_mtable[m][cube.eoud],
217 .coud = coud_mtable[m][cube.coud],
218 .cofb = cofb_mtable[m][cube.cofb],
219 .corl = corl_mtable[m][cube.corl],
220 .cp = cp_mtable[m][cube.cp],
221 .cpos = cpos_mtable[m][cube.cpos]
222 };
125} 223}
126 224
127Alg * 225Alg *
@@ -181,27 +279,31 @@ cleanup_aux(Alg *alg, Alg *ret, bool inv)
181{ 279{
182 int i, j; 280 int i, j;
183 Cube c, d; 281 Cube c, d;
184 Move m; 282 Move m, mm;
185 Alg *equiv_alg; 283 Alg *equiv_alg;
186 284
187 make_solved(&c); 285 c = (Cube){0};
188 for (i = 0; i < alg->len; i++) { 286 for (i = 0; i < alg->len; i++) {
189 if (alg->inv[i] != inv) 287 if (alg->inv[i] != inv)
190 continue; 288 continue;
191 289
192 equiv_alg = new_alg(equiv_alg_string[alg->move[i]]); 290 equiv_alg = new_alg(equiv_alg_string[alg->move[i]]);
193 291
194 for (j = 0; j < equiv_alg->len; j++) 292 for (j = 0; j < equiv_alg->len; j++) {
195 if (equiv_alg->move[j] == U) 293 m = equiv_alg->move[j];
196 append_move(ret, 3 * c.xp[U_center] + 1, inv); 294 if (m == U) {
197 else 295 mm = 3*what_center_at(c, U_center) + 1;
198 apply_move(equiv_alg->move[j], &c); 296 append_move(ret, mm, inv);
297 } else {
298 c = apply_move(m, c);
299 }
300 }
199 301
200 free_alg(equiv_alg); 302 free_alg(equiv_alg);
201 } 303 }
202 304
203 m = NULLMOVE; 305 m = NULLMOVE;
204 switch (c.xp[F_center]) { 306 switch (what_center_at(c, F_center)) {
205 case U_center: 307 case U_center:
206 m = x3; 308 m = x3;
207 break; 309 break;
@@ -215,7 +317,7 @@ cleanup_aux(Alg *alg, Alg *ret, bool inv)
215 m = y3; 317 m = y3;
216 break; 318 break;
217 case B_center: 319 case B_center:
218 if (c.xp[U_center] == U_center) 320 if (what_center_at(c, U_center) == U_center)
219 m = y2; 321 m = y2;
220 else 322 else
221 m = x2; 323 m = x2;
@@ -223,24 +325,120 @@ cleanup_aux(Alg *alg, Alg *ret, bool inv)
223 default: 325 default:
224 break; 326 break;
225 } 327 }
226 328 d = apply_move(m, (Cube){0});
227 make_solved(&d);
228 apply_move(m, &d);
229 if (m != NULLMOVE) 329 if (m != NULLMOVE)
230 append_move(ret, m, inv); 330 append_move(ret, m, inv);
231 331
232 m = NULLMOVE; 332 m = NULLMOVE;
233 if (c.xp[U_center] == d.xp[D_center]) { 333 if (what_center_at(c, U_center) == what_center_at(d, D_center)) {
234 m = z2; 334 m = z2;
235 } else if (c.xp[U_center] == d.xp[R_center]) { 335 } else if (what_center_at(c, U_center) == what_center_at(d, R_center)) {
236 m = z3; 336 m = z3;
237 } else if (c.xp[U_center] == d.xp[L_center]) { 337 } else if (what_center_at(c, U_center) == what_center_at(d, L_center)) {
238 m = z; 338 m = z;
239 } 339 }
240 if (m != NULLMOVE) 340 if (m != NULLMOVE)
241 append_move(ret, m, inv); 341 append_move(ret, m, inv);
242} 342}
243 343
344static bool
345read_mtables_file()
346{
347 init_env();
348
349 FILE *f;
350 char fname[strlen(tabledir)+20];
351 int m, b = sizeof(int);
352 bool r = true;
353
354 /* Table sizes, used for reading and writing files */
355 uint64_t me[11] = {
356 [0] = FACTORIAL12/FACTORIAL8,
357 [1] = FACTORIAL12/FACTORIAL8,
358 [2] = FACTORIAL12/FACTORIAL8,
359 [3] = POW2TO11,
360 [4] = POW2TO11,
361 [5] = POW2TO11,
362 [6] = FACTORIAL8,
363 [7] = POW3TO7,
364 [8] = POW3TO7,
365 [9] = POW3TO7,
366 [10] = FACTORIAL6
367 };
368
369 strcpy(fname, tabledir);
370 strcat(fname, "/mtables");
371
372 if ((f = fopen(fname, "rb")) == NULL)
373 return false;
374
375 for (m = 0; m < NMOVES; m++) {
376 r = r && fread(epose_mtable[m], b, me[0], f) == me[0];
377 r = r && fread(eposs_mtable[m], b, me[1], f) == me[1];
378 r = r && fread(eposm_mtable[m], b, me[2], f) == me[2];
379 r = r && fread(eofb_mtable[m], b, me[3], f) == me[3];
380 r = r && fread(eorl_mtable[m], b, me[4], f) == me[4];
381 r = r && fread(eoud_mtable[m], b, me[5], f) == me[5];
382 r = r && fread(cp_mtable[m], b, me[6], f) == me[6];
383 r = r && fread(coud_mtable[m], b, me[7], f) == me[7];
384 r = r && fread(corl_mtable[m], b, me[8], f) == me[8];
385 r = r && fread(cofb_mtable[m], b, me[9], f) == me[9];
386 r = r && fread(cpos_mtable[m], b, me[10], f) == me[10];
387 }
388
389 fclose(f);
390 return r;
391}
392
393static bool
394write_mtables_file()
395{
396 init_env();
397
398 FILE *f;
399 char fname[strlen(tabledir)+20];
400 int m, b = sizeof(int);
401 bool r = true;
402
403 /* Table sizes, used for reading and writing files */
404 uint64_t me[11] = {
405 [0] = FACTORIAL12/FACTORIAL8,
406 [1] = FACTORIAL12/FACTORIAL8,
407 [2] = FACTORIAL12/FACTORIAL8,
408 [3] = POW2TO11,
409 [4] = POW2TO11,
410 [5] = POW2TO11,
411 [6] = FACTORIAL8,
412 [7] = POW3TO7,
413 [8] = POW3TO7,
414 [9] = POW3TO7,
415 [10] = FACTORIAL6
416 };
417
418 strcpy(fname, tabledir);
419 strcat(fname, "/mtables");
420
421 if ((f = fopen(fname, "wb")) == NULL)
422 return false;
423
424 for (m = 0; m < NMOVES; m++) {
425 r = r && fwrite(epose_mtable[m], b, me[0], f) == me[0];
426 r = r && fwrite(eposs_mtable[m], b, me[1], f) == me[1];
427 r = r && fwrite(eposm_mtable[m], b, me[2], f) == me[2];
428 r = r && fwrite(eofb_mtable[m], b, me[3], f) == me[3];
429 r = r && fwrite(eorl_mtable[m], b, me[4], f) == me[4];
430 r = r && fwrite(eoud_mtable[m], b, me[5], f) == me[5];
431 r = r && fwrite(cp_mtable[m], b, me[6], f) == me[6];
432 r = r && fwrite(coud_mtable[m], b, me[7], f) == me[7];
433 r = r && fwrite(corl_mtable[m], b, me[8], f) == me[8];
434 r = r && fwrite(cofb_mtable[m], b, me[9], f) == me[9];
435 r = r && fwrite(cpos_mtable[m], b, me[10], f) == me[10];
436 }
437
438 fclose(f);
439 return r;
440}
441
244void 442void
245init_moves() { 443init_moves() {
246 static bool initialized = false; 444 static bool initialized = false;
@@ -248,54 +446,101 @@ init_moves() {
248 return; 446 return;
249 initialized = true; 447 initialized = true;
250 448
449 Cube c;
450 CubeArray arrs;
451 int i;
452 unsigned int ui;
251 Move m; 453 Move m;
252 Alg *equiv_alg[NMOVES]; 454 Alg *equiv_alg[NMOVES];
253 455
254 static const Cube mcu = { 456 init_cube();
255 .ep = { UR, UF, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR }, 457
256 .cp = { UBR, UFR, UFL, UBL, DFR, DFL, DBL, DBR }, 458 for (i = 0; i < NMOVES; i++)
257 }; 459 equiv_alg[i] = new_alg(equiv_alg_string[i]);
258 static const Cube mcx = {
259 .ep = { DF, FL, UF, FR, DB, BL, UB, BR, DR, DL, UL, UR },
260 .eo = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 },
261 .cp = { DFR, DFL, UFL, UFR, DBR, DBL, UBL, UBR },
262 .co = { [UFR] = 2, [UBR] = 1, [UFL] = 1, [UBL] = 2,
263 [DBR] = 2, [DFR] = 1, [DBL] = 1, [DFL] = 2 },
264 .xp = { F_center, B_center, R_center,
265 L_center, D_center, U_center },
266 };
267 static const Cube mcy = {
268 .ep = { UR, UF, UL, UB, DR, DF, DL, DB, BR, FR, FL, BL },
269 .eo = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 },
270 .cp = { UBR, UFR, UFL, UBL, DBR, DFR, DFL, DBL },
271 .xp = { U_center, D_center, B_center,
272 F_center, R_center, L_center },
273 };
274 460
275 move_array[U] = mcu; 461 /* Generate all move cycles and flips; I do this regardless */
276 move_array[x] = mcx; 462 for (i = 0; i < NMOVES; i++) {
277 move_array[y] = mcy; 463 if (i == U || i == x || i == y)
464 continue;
465
466 c = apply_alg_generic(equiv_alg[i], (Cube){0}, pf_all, false);
467
468 arrs = (CubeArray) {
469 edge_cycle[i],
470 eofb_flipped[i],
471 eorl_flipped[i],
472 eoud_flipped[i],
473 corner_cycle[i],
474 coud_flipped[i],
475 corl_flipped[i],
476 cofb_flipped[i],
477 center_cycle[i]
478 };
479 cube_to_arrays(c, &arrs, pf_all);
480 }
481
482 if (read_mtables_file())
483 return;
278 484
279 for (m = 0; m < NMOVES; m++) 485 fprintf(stderr, "Cannot load %s, generating it\n", "mtables");
280 equiv_alg[m] = new_alg(equiv_alg_string[m]);
281 486
487 /* Initialize transition tables */
282 for (m = 0; m < NMOVES; m++) { 488 for (m = 0; m < NMOVES; m++) {
283 switch (m) { 489 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
284 case NULLMOVE: 490 c = (Cube){ .epose = ui };
285 make_solved(&move_array[m]); 491 c = apply_move_cubearray(m, c, pf_e);
286 break; 492 epose_mtable[m][ui] = c.epose;
287 case U: 493
288 case x: 494 c = (Cube){ .eposs = ui };
289 case y: 495 c = apply_move_cubearray(m, c, pf_s);
290 break; 496 eposs_mtable[m][ui] = c.eposs;
291 default: 497
292 make_solved(&move_array[m]); 498 c = (Cube){ .eposm = ui };
293 apply_alg(equiv_alg[m], &move_array[m]); 499 c = apply_move_cubearray(m, c, pf_m);
294 break; 500 eposm_mtable[m][ui] = c.eposm;
501 }
502 for (ui = 0; ui < POW2TO11; ui++ ) {
503 c = (Cube){ .eofb = ui };
504 c = apply_move_cubearray(m, c, pf_eo);
505 eofb_mtable[m][ui] = c.eofb;
506
507 c = (Cube){ .eorl = ui };
508 c = apply_move_cubearray(m, c, pf_eo);
509 eorl_mtable[m][ui] = c.eorl;
510
511 c = (Cube){ .eoud = ui };
512 c = apply_move_cubearray(m, c, pf_eo);
513 eoud_mtable[m][ui] = c.eoud;
514 }
515 for (ui = 0; ui < POW3TO7; ui++) {
516 c = (Cube){ .coud = ui };
517 c = apply_move_cubearray(m, c, pf_co);
518 coud_mtable[m][ui] = c.coud;
519
520 c = (Cube){ .corl = ui };
521 c = apply_move_cubearray(m, c, pf_co);
522 corl_mtable[m][ui] = c.corl;
523
524 c = (Cube){ .cofb = ui };
525 c = apply_move_cubearray(m, c, pf_co);
526 cofb_mtable[m][ui] = c.cofb;
527 }
528 for (ui = 0; ui < FACTORIAL8; ui++) {
529 c = (Cube){ .cp = ui };
530 c = apply_move_cubearray(m, c, pf_cp);
531 cp_mtable[m][ui] = c.cp;
532 }
533 for (ui = 0; ui < FACTORIAL6; ui++) {
534 c = (Cube){ .cpos = ui };
535 c = apply_move_cubearray(m, c, pf_cpos);
536 cpos_mtable[m][ui] = c.cpos;
295 } 537 }
296 } 538 }
297 539
298 for (m = 0; m < NMOVES; m++) 540 if (!write_mtables_file())
299 free_alg(equiv_alg[m]); 541 fprintf(stderr, "Error writing mtables\n");
542
543 for (i = 0; i < NMOVES; i++)
544 free_alg(equiv_alg[i]);
300} 545}
301 546
diff --git a/src/moves.h b/src/moves.h
index 4e8be7f..14ae087 100644
--- a/src/moves.h
+++ b/src/moves.h
@@ -5,11 +5,24 @@
5#include "cube.h" 5#include "cube.h"
6#include "env.h" 6#include "env.h"
7 7
8void apply_alg(Alg *alg, Cube *cube); 8/*
9void apply_move(Move m, Cube *cube); 9 * Tables are exposed to allow for faster moves in some cases.
10void apply_move_centers(Move m, Cube *cube); 10 */
11void apply_move_corners(Move m, Cube *cube); 11extern int epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
12void apply_move_edges(Move m, Cube *cube); 12extern int eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
13extern int eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
14extern int eofb_mtable[NMOVES][POW2TO11];
15extern int eorl_mtable[NMOVES][POW2TO11];
16extern int eoud_mtable[NMOVES][POW2TO11];
17extern int cp_mtable[NMOVES][FACTORIAL8];
18extern int coud_mtable[NMOVES][POW3TO7];
19extern int cofb_mtable[NMOVES][POW3TO7];
20extern int corl_mtable[NMOVES][POW3TO7];
21extern int cpos_mtable[NMOVES][FACTORIAL6];
22
23Cube apply_alg(Alg *alg, Cube cube);
24Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a);
25Cube apply_move(Move m, Cube cube);
13Alg * cleanup(Alg *alg); 26Alg * cleanup(Alg *alg);
14 27
15void init_moves(); 28void init_moves();
diff --git a/src/movesets.c b/src/movesets.c
deleted file mode 100644
index d8f5bc1..0000000
--- a/src/movesets.c
+++ /dev/null
@@ -1,194 +0,0 @@
1#define MOVESETS_C
2
3#include "movesets.h"
4
5static bool allowed_HTM(Move m);
6static bool allowed_URF(Move m);
7static bool allowed_eofb(Move m);
8static bool allowed_drud(Move m);
9static bool allowed_htr(Move m);
10static bool can_append_HTM(Move l2, Move l1, Move m);
11static bool can_append_HTM_cached(Alg *alg, Move m, bool inverse);
12static bool cancel_niss_HTM_cached(Alg *alg);
13static void init_can_append_HTM();
14
15Moveset
16moveset_HTM = {
17 .name = "HTM",
18 .allowed = allowed_HTM,
19 .can_append = can_append_HTM_cached,
20 .cancel_niss = cancel_niss_HTM_cached,
21};
22
23Moveset
24moveset_URF = {
25 .name = "URF",
26 .allowed = allowed_URF,
27 .can_append = can_append_HTM_cached,
28 .cancel_niss = cancel_niss_HTM_cached,
29};
30
31Moveset
32moveset_eofb = {
33 .name = "eofb",
34 .allowed = allowed_eofb,
35 .can_append = can_append_HTM_cached,
36 .cancel_niss = cancel_niss_HTM_cached,
37};
38
39Moveset
40moveset_drud = {
41 .name = "drud",
42 .allowed = allowed_drud,
43 .can_append = can_append_HTM_cached,
44 .cancel_niss = cancel_niss_HTM_cached,
45};
46
47Moveset
48moveset_htr = {
49 .name = "htr",
50 .allowed = allowed_htr,
51 .can_append = can_append_HTM_cached,
52 .cancel_niss = cancel_niss_HTM_cached,
53};
54
55Moveset *
56all_movesets[] = {
57 &moveset_HTM,
58 &moveset_URF,
59 &moveset_eofb,
60 &moveset_drud,
61 &moveset_htr,
62 NULL
63};
64
65static uint64_t can_append_HTM_mask[NMOVES][NMOVES];
66
67static bool
68allowed_HTM(Move m)
69{
70 return m >= U && m <= B3;
71}
72
73static bool
74allowed_URF(Move m)
75{
76 Move b = base_move(m);
77
78 return b == U || b == R || b == F;
79}
80
81static bool
82allowed_eofb(Move m)
83{
84 Move b = base_move(m);
85
86 return b == U || b == D || b == R || b == L ||
87 ((b == F || b == B) && m == b+1);
88}
89
90static bool
91allowed_drud(Move m)
92{
93 Move b = base_move(m);
94
95 return b == U || b == D ||
96 ((b == R || b == L || b == F || b == B) && m == b + 1);
97}
98
99static bool
100allowed_htr(Move m)
101{
102 Move b = base_move(m);
103
104 return moveset_HTM.allowed(m) && m == b + 1;
105}
106
107static bool
108can_append_HTM(Move l2, Move l1, Move m)
109{
110 bool cancel, cancel_last, cancel_swap;
111
112 cancel_last = l1 != NULLMOVE && base_move(l1) == base_move(m);
113 cancel_swap = l2 != NULLMOVE && base_move(l2) == base_move(m);
114 cancel = cancel_last || (commute(l1, l2) && cancel_swap);
115
116 return !cancel;
117}
118
119static bool
120can_append_HTM_cached(Alg *alg, Move m, bool inverse)
121{
122 Move *moves, l1, l2;
123 uint64_t mbit;
124 int n;
125
126 if (inverse) {
127 moves = alg->move_inverse;
128 n = alg->len_inverse;
129 } else {
130 moves = alg->move_normal;
131 n = alg->len_normal;
132 }
133
134 l1 = n > 0 ? moves[n-1] : NULLMOVE;
135 l2 = n > 1 ? moves[n-2] : NULLMOVE;
136
137 mbit = ((uint64_t)1) << m;
138
139 return can_append_HTM_mask[l2][l1] & mbit;
140}
141
142static bool
143cancel_niss_HTM_cached(Alg *alg)
144{
145 Move i1, i2;
146 int n;
147 bool can_first, can_swap;
148
149 n = alg->len_inverse;
150 i1 = n > 0 ? alg->move_inverse[n-1] : NULLMOVE;
151 i2 = n > 1 ? alg->move_inverse[n-2] : NULLMOVE;
152
153 can_first = can_append_HTM_cached(alg, inverse_move(i1), false);
154 can_swap = can_append_HTM_cached(alg, inverse_move(i2), false);
155
156 return can_first && (!commute(i1, i2) || can_swap);
157}
158
159static void
160init_can_append_HTM()
161{
162 Move l2, l1, m;
163
164 for (l1 = 0; l1 < NMOVES; l1++)
165 for (l2 = 0; l2 < NMOVES; l2++)
166 for (m = 0; m < NMOVES; m++)
167 if (can_append_HTM(l2, l1, m))
168 can_append_HTM_mask[l2][l1]
169 |= (((uint64_t)1) << m);
170}
171
172void
173init_moveset(Moveset *ms)
174{
175 int j;
176 Move m;
177
178 for (j = 0, m = U; m < NMOVES; m++)
179 if (ms->allowed(m))
180 ms->sorted_moves[j++] = m;
181 ms->sorted_moves[j] = NULLMOVE;
182
183/* TODO: should be here? maybe just init all movesets together anyway... */
184 init_can_append_HTM();
185}
186
187void
188init_movesets()
189{
190 int i;
191
192 for (i = 0; all_movesets[i] != NULL; i++)
193 init_moveset(all_movesets[i]);
194}
diff --git a/src/movesets.h b/src/movesets.h
deleted file mode 100644
index a02d171..0000000
--- a/src/movesets.h
+++ /dev/null
@@ -1,15 +0,0 @@
1#ifndef MOVESETS_H
2#define MOVESETS_H
3
4#include "alg.h"
5
6void init_moveset(Moveset *);
7void init_movesets();
8
9extern Moveset moveset_HTM;
10extern Moveset moveset_URF;
11extern Moveset moveset_eofb;
12extern Moveset moveset_drud;
13extern Moveset moveset_htr;
14
15#endif
diff --git a/src/pf.c b/src/pf.c
new file mode 100644
index 0000000..7d86e4e
--- /dev/null
+++ b/src/pf.c
@@ -0,0 +1,95 @@
1#include "pf.h"
2
3PieceFilter
4pf_all = {
5 .epose = true,
6 .eposs = true,
7 .eposm = true,
8 .eofb = true,
9 .eorl = true,
10 .eoud = true,
11 .cp = true,
12 .cofb = true,
13 .corl = true,
14 .coud = true,
15 .cpos = true
16};
17
18PieceFilter
19pf_4val = {
20 .epose = true,
21 .eposs = true,
22 .eposm = true,
23 .eofb = true,
24 .coud = true,
25 .cp = true
26};
27
28PieceFilter
29pf_epcp = {
30 .epose = true,
31 .eposs = true,
32 .eposm = true,
33 .cp = true
34};
35
36PieceFilter
37pf_cpos = {
38 .cpos = true
39};
40
41PieceFilter
42pf_cp = {
43 .cp = true
44};
45
46PieceFilter
47pf_ep = {
48 .epose = true,
49 .eposs = true,
50 .eposm = true
51};
52
53PieceFilter
54pf_e = {
55 .epose = true
56};
57
58PieceFilter
59pf_s = {
60 .eposs = true
61};
62
63PieceFilter
64pf_m = {
65 .eposm = true
66};
67
68PieceFilter
69pf_eo = {
70 .eofb = true,
71 .eorl = true,
72 .eoud = true
73};
74
75PieceFilter
76pf_co = {
77 .cofb = true,
78 .corl = true,
79 .coud = true
80};
81
82PieceFilter
83pf_coud = {
84 .coud = true
85};
86
87PieceFilter
88pf_edges = {
89 .epose = true,
90 .eposs = true,
91 .eposm = true,
92 .eofb = true,
93 .eorl = true,
94 .eoud = true
95};
diff --git a/src/pf.h b/src/pf.h
new file mode 100644
index 0000000..0b552dc
--- /dev/null
+++ b/src/pf.h
@@ -0,0 +1,20 @@
1#ifndef PF_H
2#define PF_H
3
4#include "cubetypes.h"
5
6extern PieceFilter pf_all;
7extern PieceFilter pf_4val;
8extern PieceFilter pf_epcp;
9extern PieceFilter pf_cpos;
10extern PieceFilter pf_cp;
11extern PieceFilter pf_ep;
12extern PieceFilter pf_e;
13extern PieceFilter pf_s;
14extern PieceFilter pf_m;
15extern PieceFilter pf_eo;
16extern PieceFilter pf_co;
17extern PieceFilter pf_coud;
18extern PieceFilter pf_edges;
19
20#endif
diff --git a/src/pruning.c b/src/pruning.c
index 3cc9152..1dba949 100644
--- a/src/pruning.c
+++ b/src/pruning.c
@@ -1,5 +1,3 @@
1#define PRUNING_C
2
3#include "pruning.h" 1#include "pruning.h"
4 2
5#define ENTRIES_PER_GROUP (2*sizeof(entry_group_t)) 3#define ENTRIES_PER_GROUP (2*sizeof(entry_group_t))
@@ -7,14 +5,106 @@
7 5
8static int findchunk(PruneData *pd, int nchunks, uint64_t i); 6static int findchunk(PruneData *pd, int nchunks, uint64_t i);
9static void genptable_bfs(PruneData *pd, int d, int nt, int nc); 7static void genptable_bfs(PruneData *pd, int d, int nt, int nc);
8static void genptable_compress(PruneData *pd);
10static void genptable_fixnasty(PruneData *pd, int d, int nthreads); 9static void genptable_fixnasty(PruneData *pd, int d, int nthreads);
10static void genptable_setbase(PruneData *pd);
11static void * instance_bfs(void *arg); 11static void * instance_bfs(void *arg);
12static void * instance_fixnasty(void *arg); 12static void * instance_fixnasty(void *arg);
13static void ptable_update(PruneData *pd, uint64_t ind, int m); 13static void ptable_update(PruneData *pd, Cube cube, int m);
14static void ptable_update_index(PruneData *pd, uint64_t ind, int m);
15static int ptableval_index(PruneData *pd, uint64_t ind);
14static bool read_ptable_file(PruneData *pd); 16static bool read_ptable_file(PruneData *pd);
15static bool write_ptable_file(PruneData *pd); 17static bool write_ptable_file(PruneData *pd);
16 18
17PruneData *active_pd[256]; 19PruneData
20pd_eofb_HTM = {
21 .filename = "pt_eofb_HTM",
22 .coord = &coord_eofb,
23 .moveset = &moveset_HTM,
24};
25
26PruneData
27pd_coud_HTM = {
28 .filename = "pt_coud_HTM",
29 .coord = &coord_coud,
30 .moveset = &moveset_HTM,
31};
32
33PruneData
34pd_cornershtr_HTM = {
35 .filename = "pt_cornershtr_HTM",
36 .coord = &coord_cornershtr,
37 .moveset = &moveset_HTM,
38};
39
40PruneData
41pd_corners_HTM = {
42 .filename = "pt_corners_HTM",
43 .coord = &coord_corners,
44 .moveset = &moveset_HTM,
45};
46
47PruneData
48pd_drud_sym16_HTM = {
49 .filename = "pt_drud_sym16_HTM",
50 .coord = &coord_drud_sym16,
51 .moveset = &moveset_HTM,
52};
53
54PruneData
55pd_drud_eofb = {
56 .filename = "pt_drud_eofb",
57 .coord = &coord_drud_eofb,
58 .moveset = &moveset_eofb,
59};
60
61PruneData
62pd_drudfin_noE_sym16_drud = {
63 .filename = "pt_drudfin_noE_sym16_drud",
64 .coord = &coord_drudfin_noE_sym16,
65 .moveset = &moveset_drud,
66};
67
68PruneData
69pd_htr_drud = {
70 .filename = "pt_htr_drud",
71 .coord = &coord_htr_drud,
72 .moveset = &moveset_drud,
73};
74
75PruneData
76pd_htrfin_htr = {
77 .filename = "pt_htrfin_htr",
78 .coord = &coord_htrfin,
79 .moveset = &moveset_htr,
80};
81
82PruneData
83pd_nxopt31_HTM = {
84 .filename = "pt_nxopt31_HTM",
85 .coord = &coord_nxopt31,
86 .moveset = &moveset_HTM,
87
88 .compact = true,
89 .fallback = &pd_drud_sym16_HTM,
90 .fbmod = BINOM8ON4,
91};
92
93PruneData * all_pd[] = {
94 &pd_eofb_HTM,
95 &pd_coud_HTM,
96 &pd_cornershtr_HTM,
97 &pd_corners_HTM,
98 &pd_drud_sym16_HTM,
99 &pd_drud_eofb,
100 &pd_drudfin_noE_sym16_drud,
101 &pd_htr_drud,
102 &pd_htrfin_htr,
103 &pd_nxopt31_HTM,
104 NULL
105};
106
107/* Functions *****************************************************************/
18 108
19int 109int
20findchunk(PruneData *pd, int nchunks, uint64_t i) 110findchunk(PruneData *pd, int nchunks, uint64_t i)
@@ -27,47 +117,59 @@ findchunk(PruneData *pd, int nchunks, uint64_t i)
27 return MIN(nchunks-1, (int)(i / chunksize)); 117 return MIN(nchunks-1, (int)(i / chunksize));
28} 118}
29 119
30PruneData * 120void
31genptable(PruneData *pd, int nthreads) 121free_pd(PruneData *pd)
32{ 122{
33 int d, nchunks, i, maxv; 123 if (pd->generated)
34 uint64_t oldn; 124 free(pd->ptable);
35 125
36 for (i = 0; active_pd[i] != NULL; i++) { 126 pd->generated = false;
37 if (active_pd[i]->coord == pd->coord && 127}
38 active_pd[i]->moveset == pd->moveset && 128
39 active_pd[i]->compact == pd->compact) 129void
40 return active_pd[i]; 130genptable(PruneData *pd, int nthreads)
41 } 131{
132 bool compact;
133 int d, nchunks;
134 uint64_t oldn, sz;
42 135
43 init_moveset(pd->moveset); 136 if (pd->generated)
44 gen_coord(pd->coord); 137 return;
45 138
46 pd->ptable = malloc(ptablesize(pd) * sizeof(entry_group_t)); 139 /* TODO: check if memory is enough, otherwise maybe exit gracefully? */
140 sz = ptablesize(pd) * (pd->compact ? 2 : 1);
141 pd->ptable = malloc(sz * sizeof(entry_group_t));
47 142
48 if (read_ptable_file(pd)) 143 if (read_ptable_file(pd)) {
49 goto genptable_done; 144 pd->generated = true;
145 return;
146 }
50 147
51 if (nthreads < 4) { 148 if (nthreads < 4) {
52 fprintf(stderr, 149 fprintf(stderr,
53 "--- Warning ---\n" 150 "--- Warning ---\n"
54 "You are using only %d threads to generate the pruning" 151 "You are using only %d threads to generate the pruning"
55 "tables. This can take a while.\n" 152 "tables. This can take a while."
56 "Unless you did this intentionally, you should re-run" 153 "Unless you did this intentionally, you should re-run"
57 "this command with `-t 4' or more.\n" 154 "this command with `-t 4' or more.\n"
58 "---------------\n\n", nthreads 155 "---------------\n\n", nthreads
59 ); 156 );
60 } 157 }
61 158
159
160 /* For the first steps we proceed the same way for compact and not */
161 compact = pd->compact;
162 pd->compact = false;
163 pd->generated = true;
164
62 nchunks = MIN(ptablesize(pd), 100000); 165 nchunks = MIN(ptablesize(pd), 100000);
63 fprintf(stderr, "Generating pt_%s_%s with %d threads\n", 166 fprintf(stderr, "Cannot load %s, generating it with %d threads\n",
64 pd->coord->name, pd->moveset->name, nthreads); 167 pd->filename, nthreads);
168
65 169
66 memset(pd->ptable, ~(uint8_t)0, ptablesize(pd)*sizeof(entry_group_t)); 170 memset(pd->ptable, ~(uint8_t)0, ptablesize(pd)*sizeof(entry_group_t));
67 for (i = 0; i < 16; i++)
68 pd->count[i] = 0;
69 171
70 ptable_update(pd, 0, 0); 172 ptable_update(pd, (Cube){0}, 0);
71 pd->n = 1; 173 pd->n = 1;
72 oldn = 0; 174 oldn = 0;
73 genptable_fixnasty(pd, 0, nthreads); 175 genptable_fixnasty(pd, 0, nthreads);
@@ -76,9 +178,7 @@ genptable(PruneData *pd, int nthreads)
76 0, pd->n - oldn, pd->n, pd->coord->max); 178 0, pd->n - oldn, pd->n, pd->coord->max);
77 oldn = pd->n; 179 oldn = pd->n;
78 pd->count[0] = pd->n; 180 pd->count[0] = pd->n;
79 181 for (d = 0; d < 15 && pd->n < pd->coord->max; d++) {
80 maxv = pd->compact ? MIN(15, pd->base + 4) : 15;
81 for (d = 0; d < maxv && pd->n < pd->coord->max; d++) {
82 genptable_bfs(pd, d, nthreads, nchunks); 182 genptable_bfs(pd, d, nthreads, nchunks);
83 genptable_fixnasty(pd, d+1, nthreads); 183 genptable_fixnasty(pd, d+1, nthreads);
84 fprintf(stderr, "Depth %d done, generated %" 184 fprintf(stderr, "Depth %d done, generated %"
@@ -87,17 +187,14 @@ genptable(PruneData *pd, int nthreads)
87 pd->count[d+1] = pd->n - oldn; 187 pd->count[d+1] = pd->n - oldn;
88 oldn = pd->n; 188 oldn = pd->n;
89 } 189 }
90 if (pd->compact)
91 fprintf(stderr, "Compact table, values above "
92 "%d are inaccurate.\n", maxv-1);
93 fprintf(stderr, "Pruning table generated!\n"); 190 fprintf(stderr, "Pruning table generated!\n");
94 191
192 genptable_setbase(pd);
193 if (compact)
194 genptable_compress(pd);
195
95 if (!write_ptable_file(pd)) 196 if (!write_ptable_file(pd))
96 fprintf(stderr, "Error writing ptable file\n"); 197 fprintf(stderr, "Error writing ptable file\n");
97
98genptable_done:
99 for (i = 0; active_pd[i] != NULL; i++);
100 return active_pd[i] = pd;
101} 198}
102 199
103static void 200static void
@@ -135,6 +232,31 @@ genptable_bfs(PruneData *pd, int d, int nthreads, int nchunks)
135} 232}
136 233
137static void 234static void
235genptable_compress(PruneData *pd)
236{
237 int val;
238 uint64_t i, j;
239 entry_group_t mask, v;
240
241 fprintf(stderr, "Compressing table to 2 bits per entry\n");
242
243 for (i = 0; i < pd->coord->max; i += ENTRIES_PER_GROUP_COMPACT) {
244 mask = (entry_group_t)0;
245 for (j = 0; j < ENTRIES_PER_GROUP_COMPACT; j++) {
246 if (i+j >= pd->coord->max)
247 break;
248 val = ptableval_index(pd, i+j) - pd->base;
249 v = (entry_group_t)MIN(3, MAX(0, val));
250 mask |= v << (2*j);
251 }
252 pd->ptable[i/ENTRIES_PER_GROUP_COMPACT] = mask;
253 }
254
255 pd->compact = true;
256 pd->ptable = realloc(pd->ptable, sizeof(entry_group_t)*ptablesize(pd));
257}
258
259static void
138genptable_fixnasty(PruneData *pd, int d, int nthreads) 260genptable_fixnasty(PruneData *pd, int d, int nthreads)
139{ 261{
140 int i; 262 int i;
@@ -142,7 +264,7 @@ genptable_fixnasty(PruneData *pd, int d, int nthreads)
142 ThreadDataGenpt td[nthreads]; 264 ThreadDataGenpt td[nthreads];
143 pthread_mutex_t *upmtx; 265 pthread_mutex_t *upmtx;
144 266
145 if (pd->coord->type != SYMCOMP_COORD) 267 if (pd->coord->tfind == NULL)
146 return; 268 return;
147 269
148 upmtx = malloc(sizeof(pthread_mutex_t)); 270 upmtx = malloc(sizeof(pthread_mutex_t));
@@ -162,12 +284,28 @@ genptable_fixnasty(PruneData *pd, int d, int nthreads)
162 free(upmtx); 284 free(upmtx);
163} 285}
164 286
287static void
288genptable_setbase(PruneData *pd)
289{
290 int i;
291 uint64_t sum, newsum;
292
293 pd->base = 0;
294 sum = pd->count[0] + pd->count[1] + pd->count[2];
295 for (i = 3; i < 16; i++) {
296 newsum = sum + pd->count[i] - pd->count[i-3];
297 if (newsum > sum)
298 pd->base = i-3;
299 sum = newsum;
300 }
301}
302
165static void * 303static void *
166instance_bfs(void *arg) 304instance_bfs(void *arg)
167{ 305{
168 ThreadDataGenpt *td; 306 ThreadDataGenpt *td;
169 uint64_t i, ii, blocksize, rmin, rmax, updated; 307 uint64_t i, ii, blocksize, rmin, rmax, updated;
170 int j, pval, ichunk, oldc, newc; 308 int j, pval, ichunk;
171 Move *ms; 309 Move *ms;
172 310
173 td = (ThreadDataGenpt *)arg; 311 td = (ThreadDataGenpt *)arg;
@@ -178,43 +316,25 @@ instance_bfs(void *arg)
178 td->pd->coord->max : 316 td->pd->coord->max :
179 ((uint64_t)td->thid + 1) * blocksize; 317 ((uint64_t)td->thid + 1) * blocksize;
180 318
181 if (td->pd->compact) {
182 if (td->d <= td->pd->base) {
183 oldc = 1;
184 newc = 1;
185 } else {
186 oldc = td->d - td->pd->base;
187 newc = td->d - td->pd->base;
188 }
189 } else {
190 oldc = td->d;
191 newc = td->d + 1;
192 }
193
194 updated = 0; 319 updated = 0;
195 for (i = rmin; i < rmax; i++) { 320 for (i = rmin; i < rmax; i++) {
196 ichunk = findchunk(td->pd, td->nchunks, i); 321 ichunk = findchunk(td->pd, td->nchunks, i);
197 pthread_mutex_lock(td->mutex[ichunk]); 322 pthread_mutex_lock(td->mutex[ichunk]);
198 pval = ptableval(td->pd, i); 323 pval = ptableval_index(td->pd, i);
199 pthread_mutex_unlock(td->mutex[ichunk]); 324 pthread_mutex_unlock(td->mutex[ichunk]);
200 if (pval == oldc) { 325 if (pval == td->d) {
201 for (j = 0; ms[j] != NULLMOVE; j++) { 326 for (j = 0; ms[j] != NULLMOVE; j++) {
202 ii = move_coord(td->pd->coord, ms[j], i, NULL); 327 ii = td->pd->coord->move(ms[j], i);
203 ichunk = findchunk(td->pd, td->nchunks, ii); 328 ichunk = findchunk(td->pd, td->nchunks, ii);
204 pthread_mutex_lock(td->mutex[ichunk]); 329 pthread_mutex_lock(td->mutex[ichunk]);
205 pval = ptableval(td->pd, ii); 330 pval = ptableval_index(td->pd, ii);
206 if (pval > newc) { 331 if (pval > td->d+1) {
207 ptable_update(td->pd, ii, newc); 332 ptable_update_index(td->pd,
333 ii, td->d+1);
208 updated++; 334 updated++;
209 } 335 }
210 pthread_mutex_unlock(td->mutex[ichunk]); 336 pthread_mutex_unlock(td->mutex[ichunk]);
211 } 337 }
212 if (td->pd->compact && td->d <= td->pd->base) {
213 ichunk = findchunk(td->pd, td->nchunks, i);
214 pthread_mutex_lock(td->mutex[ichunk]);
215 ptable_update(td->pd, i, 0);
216 pthread_mutex_unlock(td->mutex[ichunk]);
217 }
218 } 338 }
219 } 339 }
220 340
@@ -229,40 +349,30 @@ static void *
229instance_fixnasty(void *arg) 349instance_fixnasty(void *arg)
230{ 350{
231 ThreadDataGenpt *td; 351 ThreadDataGenpt *td;
232 uint64_t i, ii, blocksize, rmin, rmax, updated, ss, M; 352 uint64_t i, ii, nb, blocksize, rmin, rmax, updated;
233 int j, oldc; 353 int j, n;
234 Trans t; 354 Trans t, aux[NTRANS];
235 355
236 td = (ThreadDataGenpt *)arg; 356 td = (ThreadDataGenpt *)arg;
237 357 nb = td->pd->coord->max / td->pd->coord->base->max;
238 /* We know type = SYMCOMP_COORD */ 358 blocksize = (td->pd->coord->base->max / td->nthreads) * nb;
239 M = td->pd->coord->base[1]->max;
240 blocksize = (td->pd->coord->base[0]->max / td->nthreads) * M;
241 rmin = ((uint64_t)td->thid) * blocksize; 359 rmin = ((uint64_t)td->thid) * blocksize;
242 rmax = td->thid == td->nthreads - 1 ? 360 rmax = td->thid == td->nthreads - 1 ?
243 td->pd->coord->max : 361 td->pd->coord->max :
244 ((uint64_t)td->thid + 1) * blocksize; 362 ((uint64_t)td->thid + 1) * blocksize;
245 363
246 if (td->pd->compact) {
247 if (td->d <= td->pd->base)
248 oldc = 1;
249 else
250 oldc = td->d - td->pd->base;
251 } else {
252 oldc = td->d;
253 }
254
255 updated = 0; 364 updated = 0;
256 for (i = rmin; i < rmax; i++) { 365 for (i = rmin; i < rmax; i++) {
257 if (ptableval(td->pd, i) == oldc) { 366 if (ptableval_index(td->pd, i) == td->d) {
258 ss = td->pd->coord->base[0]->selfsim[i/M]; 367 if ((n = td->pd->coord->tfind(i, aux)) == 1)
259 for (j = 0; j < td->pd->coord->base[0]->tgrp->n; j++) { 368 continue;
260 t = td->pd->coord->base[0]->tgrp->t[j]; 369
261 if (t == uf || !(ss & ((uint64_t)1<<t))) 370 for (j = 0; j < n; j++) {
371 if ((t = aux[j]) == uf)
262 continue; 372 continue;
263 ii = trans_coord(td->pd->coord, t, i); 373 ii = td->pd->coord->transform(t, i);
264 if (ptableval(td->pd, ii) > oldc) { 374 if (ptableval_index(td->pd, ii) > td->d) {
265 ptable_update(td->pd, ii, oldc); 375 ptable_update_index(td->pd, ii, td->d);
266 updated++; 376 updated++;
267 } 377 }
268 } 378 }
@@ -281,13 +391,11 @@ print_ptable(PruneData *pd)
281{ 391{
282 uint64_t i; 392 uint64_t i;
283 393
284 printf("Table %s_%s\n", pd->coord->name, pd->moveset->name); 394 if (!pd->generated)
285 395 genptable(pd, 1); /* TODO: set default nthreads somewhere */
286 if (pd->compact) { 396
287 printf("Compract table with base value: %d\n", pd->base); 397 printf("Table %s\n", pd->filename);
288 printf("Values above %d are inaccurate.\n", pd->base + 3); 398 printf("Base value: %d\n", pd->base);
289 }
290
291 for (i = 0; i < 16; i++) 399 for (i = 0; i < 16; i++)
292 printf("%2" PRIu64 "\t%10" PRIu64 "\n", i, pd->count[i]); 400 printf("%2" PRIu64 "\t%10" PRIu64 "\n", i, pd->count[i]);
293} 401}
@@ -303,31 +411,48 @@ ptablesize(PruneData *pd)
303} 411}
304 412
305static void 413static void
306ptable_update(PruneData *pd, uint64_t ind, int n) 414ptable_update(PruneData *pd, Cube cube, int n)
307{ 415{
308 int sh; 416 ptable_update_index(pd, pd->coord->index(cube), n);
309 entry_group_t f, mask; 417}
310 uint64_t i, e, b;
311 418
312 e = pd->compact ? ENTRIES_PER_GROUP_COMPACT : ENTRIES_PER_GROUP; 419static void
313 b = pd->compact ? 2 : 4; 420ptable_update_index(PruneData *pd, uint64_t ind, int n)
314 f = pd->compact ? 3 : 15; 421{
422 int sh;
423 entry_group_t mask;
424 uint64_t i;
315 425
316 sh = b * (ind % e); 426 sh = 4 * (ind % ENTRIES_PER_GROUP);
317 mask = f << sh; 427 mask = ((entry_group_t)15) << sh;
318 i = ind / e; 428 i = ind/ENTRIES_PER_GROUP;
319 429
320 pd->ptable[i] &= ~mask; 430 pd->ptable[i] &= ~mask;
321 pd->ptable[i] |= (((entry_group_t)n) & f) << sh; 431 pd->ptable[i] |= (((entry_group_t)n)&15) << sh;
322} 432}
323 433
324int 434int
325ptableval(PruneData *pd, uint64_t ind) 435ptableval(PruneData *pd, Cube cube)
326{ 436{
327 int sh; 437 return ptableval_index(pd, pd->coord->index(cube));
328 uint64_t e; 438}
439
440static int
441ptableval_index(PruneData *pd, uint64_t ind)
442{
443 int sh, ret;
444 entry_group_t mask;
445 uint64_t i, e;
329 entry_group_t m; 446 entry_group_t m;
330 447
448 if (!pd->generated) {
449 fprintf(stderr, "Warning: request pruning table value"
450 " for uninitialized table %s.\n It's fine, but it"
451 " should not happen. Please report bug.\n",
452 pd->filename);
453 genptable(pd, 1); /* TODO: set default or remove this case */
454 }
455
331 if (pd->compact) { 456 if (pd->compact) {
332 e = ENTRIES_PER_GROUP_COMPACT; 457 e = ENTRIES_PER_GROUP_COMPACT;
333 m = 3; 458 m = 3;
@@ -338,7 +463,19 @@ ptableval(PruneData *pd, uint64_t ind)
338 sh = (ind % e) * 4; 463 sh = (ind % e) * 4;
339 } 464 }
340 465
341 return (pd->ptable[ind/e] & (m << sh)) >> sh; 466 mask = m << sh;
467 i = ind/e;
468
469 ret = (pd->ptable[i] & mask) >> sh;
470
471 if (pd->compact) {
472 if (ret)
473 ret += pd->base;
474 else
475 ret = ptableval_index(pd->fallback, ind / pd->fbmod);
476 }
477
478 return ret;
342} 479}
343 480
344static bool 481static bool
@@ -347,15 +484,13 @@ read_ptable_file(PruneData *pd)
347 init_env(); 484 init_env();
348 485
349 FILE *f; 486 FILE *f;
350 char fname[strlen(tabledir)+256]; 487 char fname[strlen(tabledir)+100];
351 int i; 488 int i;
352 uint64_t r; 489 uint64_t r;
353 490
354 strcpy(fname, tabledir); 491 strcpy(fname, tabledir);
355 strcat(fname, "/pt_"); 492 strcat(fname, "/");
356 strcat(fname, pd->coord->name); 493 strcat(fname, pd->filename);
357 strcat(fname, "_");
358 strcat(fname, pd->moveset->name);
359 494
360 if ((f = fopen(fname, "rb")) == NULL) 495 if ((f = fopen(fname, "rb")) == NULL)
361 return false; 496 return false;
@@ -376,15 +511,13 @@ write_ptable_file(PruneData *pd)
376 init_env(); 511 init_env();
377 512
378 FILE *f; 513 FILE *f;
379 char fname[strlen(tabledir)+256]; 514 char fname[strlen(tabledir)+100];
380 int i; 515 int i;
381 uint64_t w; 516 uint64_t w;
382 517
383 strcpy(fname, tabledir); 518 strcpy(fname, tabledir);
384 strcat(fname, "/pt_"); 519 strcat(fname, "/");
385 strcat(fname, pd->coord->name); 520 strcat(fname, pd->filename);
386 strcat(fname, "_");
387 strcat(fname, pd->moveset->name);
388 521
389 if ((f = fopen(fname, "wb")) == NULL) 522 if ((f = fopen(fname, "wb")) == NULL)
390 return false; 523 return false;
diff --git a/src/pruning.h b/src/pruning.h
index 93ae863..6bdbee1 100644
--- a/src/pruning.h
+++ b/src/pruning.h
@@ -1,16 +1,26 @@
1#ifndef PRUNING_H 1#ifndef PRUNING_H
2#define PRUNING_H 2#define PRUNING_H
3 3
4#include "coord.h" 4#include "symcoord.h"
5#include "movesets.h" 5
6extern PruneData pd_eofb_HTM;
7extern PruneData pd_coud_HTM;
8extern PruneData pd_corners_HTM;
9extern PruneData pd_cornershtr_HTM;
10extern PruneData pd_drud_sym16_HTM;
11extern PruneData pd_drud_eofb;
12extern PruneData pd_drudfin_noE_sym16_drud;
13extern PruneData pd_htr_drud;
14extern PruneData pd_htrfin_htr;
15extern PruneData pd_nxopt31_HTM;
16
17extern PruneData * all_pd[];
6 18
7void free_pd(PruneData *pd); 19void free_pd(PruneData *pd);
8PruneData * genptable(PruneData *data, int nthreads); 20void genptable(PruneData *pd, int nthreads);
9void print_ptable(PruneData *pd); 21void print_ptable(PruneData *pd);
10uint64_t ptablesize(PruneData *pd); 22uint64_t ptablesize(PruneData *pd);
11int ptableval(PruneData *pd, uint64_t ind); 23int ptableval(PruneData *pd, Cube cube);
12
13extern PruneData *active_pd[256];
14 24
15#endif 25#endif
16 26
diff --git a/src/shell.c b/src/shell.c
index 4faa0a8..0001e0d 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -1,5 +1,3 @@
1#define SHELL_C
2
3#include "shell.h" 1#include "shell.h"
4 2
5static void cleanwhitespaces(char *line); 3static void cleanwhitespaces(char *line);
@@ -9,9 +7,7 @@ bool
9checkfiles() 7checkfiles()
10{ 8{
11 /* TODO: add more checks (other files, use checksum...) */ 9 /* TODO: add more checks (other files, use checksum...) */
12 /* How to check for pruning tables with new method? */ 10 FILE *f;
13 /* Solution: use list of steps */
14 /*
15 char fname[strlen(tabledir)+100]; 11 char fname[strlen(tabledir)+100];
16 int i; 12 int i;
17 13
@@ -24,7 +20,6 @@ checkfiles()
24 else 20 else
25 fclose(f); 21 fclose(f);
26 } 22 }
27 */
28 23
29 return true; 24 return true;
30} 25}
@@ -142,14 +137,12 @@ launch(bool batchmode)
142 free(shell_argv); 137 free(shell_argv);
143} 138}
144 139
145#ifndef TEST
146int 140int
147main(int argc, char *argv[]) 141main(int argc, char *argv[])
148{ 142{
149 char *closing_cmd[1] = { "freemem" }; 143 char *closing_cmd[1] = { "freemem" };
150 144
151 init_env(); 145 init_env();
152 init_trans();
153 146
154 if (!checkfiles()) { 147 if (!checkfiles()) {
155 fprintf(stderr, 148 fprintf(stderr,
@@ -174,4 +167,3 @@ main(int argc, char *argv[])
174 167
175 return 0; 168 return 0;
176} 169}
177#endif
diff --git a/src/solve.c b/src/solve.c
index 2d0c94d..d4c0f18 100644
--- a/src/solve.c
+++ b/src/solve.c
@@ -1,122 +1,500 @@
1#define SOLVE_C
2
3#include "solve.h" 1#include "solve.h"
4 2
5void 3/* Local functions ***********************************************************/
6dfs(DfsArg *arg, Solver *solver, Threader *threader) 4
5static bool allowed_next(Move move, DfsArg *arg);
6static bool cancel_niss(DfsArg *arg);
7static void copy_dfsarg(DfsArg *src, DfsArg *dst);
8static void dfs(DfsArg *arg);
9static void dfs_branch(DfsArg *arg);
10static bool dfs_check_solved(DfsArg *arg);
11static bool dfs_switch(DfsArg *arg);
12static void dfs_niss(DfsArg *arg);
13static bool dfs_stop(DfsArg *arg);
14static void * instance_thread(void *arg);
15static void invert_branch(DfsArg *arg);
16static void multidfs(Cube c, Trans t, Step *s, SolveOptions *opts,
17 AlgList *sols, int d);
18static bool niss_makes_sense(DfsArg *arg);
19static bool solvestop(int d, int op, SolveOptions *opts, AlgList *sols);
20
21/* Local functions ***********************************************************/
22
23static bool
24allowed_next(Move m, DfsArg *arg)
25{
26 bool bad, allowed, order;
27 uint64_t mbit;
28
29 mbit = ((uint64_t)1) << m;
30 bad = mbit & arg->badmoves;
31 allowed = mbit & arg->step->moveset->mask[arg->last2][arg->last1];
32 order = !commute(arg->last1, m) || arg->last1 < m;
33
34 return allowed && !bad && order;
35}
36
37static bool
38cancel_niss(DfsArg *arg)
39{
40 Moveset *ms;
41 Move i1, i2;
42 bool p, p1, p2, q, q1, q2;
43
44 if (arg->last1inv == NULLMOVE)
45 return false;
46
47 ms = arg->step->moveset;
48 i1 = inverse_move(arg->last1inv);
49 i2 = inverse_move(arg->last2inv);
50
51 p1 = !ms->allowed_next(arg->last2, arg->last1, i1);
52 p2 = !ms->allowed_next(arg->last2, i1, arg->last1);
53 p = p1 || (commute(i1, arg->last1) && p2);
54
55 q1 = !ms->allowed_next(arg->last2, arg->last1, i2);
56 q2 = !ms->allowed_next(arg->last2, i2, arg->last1);
57 q = q1 || (commute(i2, arg->last1) && q2);
58
59 return p || (commute(i1, i2) && q);
60}
61
62static void
63copy_dfsarg(DfsArg *src, DfsArg *dst)
64{
65 dst->step = src->step;
66 dst->opts = src->opts;
67 dst->t = src->t;
68 dst->cube = src->cube;
69 dst->inverse = src->inverse;
70 dst->d = src->d;
71 dst->badmoves = src->badmoves;
72 dst->badmovesinv = src->badmovesinv;
73 dst->niss = src->niss;
74 dst->last1 = src->last1;
75 dst->last2 = src->last2;
76 dst->last1inv = src->last1inv;
77 dst->last2inv = src->last2inv;
78 dst->sols = src->sols;
79 dst->sols_mutex = src->sols_mutex;
80 dst->current_alg = src->current_alg;
81
82 copy_estimatedata(src->ed, dst->ed);
83}
84
85static void
86dfs(DfsArg *arg)
87{
88 bool sw = false;
89
90 if (dfs_stop(arg))
91 return;
92
93 if (dfs_check_solved(arg))
94 return;
95
96 if (arg->step->final && (sw = dfs_switch(arg)))
97 invert_branch(arg);
98 dfs_branch(arg);
99
100 if (arg->opts->can_niss && !arg->niss && niss_makes_sense(arg))
101 dfs_niss(arg);
102
103 if (sw)
104 invert_branch(arg);
105}
106
107static void
108dfs_branch(DfsArg *arg)
7{ 109{
8 int i; 110 int i;
9 DfsArg newarg;
10 Alg *sol;
11 Move m; 111 Move m;
112 DfsArg *newarg;
12 113
13 if (arg->current_alg->len > arg->d) 114 newarg = malloc(sizeof(DfsArg));
14 return; 115 newarg->ed = malloc(sizeof(EstimateData));
15 116
16 if (solver->is_solved(solver->param, arg->cubedata)) { 117 for (i = 0; arg->step->moveset->sorted_moves[i] != NULLMOVE; i++) {
17/* TODO: the "all" option should be re-implemented as setting 118 m = arg->step->moveset->sorted_moves[i];
18validate to null */ 119 if (allowed_next(m, arg)) {
120 copy_dfsarg(arg, newarg);
121 newarg->last2 = arg->last1;
122 newarg->last1 = m;
123 newarg->cube = apply_move(m, arg->cube);
124 append_move(arg->current_alg, m, newarg->niss);
19 125
20/* TODO: we also have to check if cancel with NISS; 126 dfs(newarg);
21we can't because we have no access to the s->final field
22this should be done by the step's validator? */
23 sol = solver->validate_solution(solver->param,arg->current_alg);
24 bool accepted = sol != NULL;
25 bool too_short = arg->current_alg->len != arg->d;
26 127
27 if (accepted && !too_short) { 128 arg->current_alg->len--;
28/* TODO: arg->t got lost in refactoring */
29/* transform_alg(inverse_trans(arg->t), sol);*/
30 if (arg->opts->verbose)
31 print_alg(sol, false);
32 threader->append_sol(sol, arg->threaddata);
33 } 129 }
34 return;
35 } 130 }
36 131
37 if (arg->current_alg->len == arg->d) 132 free(newarg->ed);
38 return; 133 free(newarg);
134}
135
136static bool
137dfs_check_solved(DfsArg *arg)
138{
139 if (!arg->step->is_done(arg->cube))
140 return false;
141
142 if (arg->current_alg->len == arg->d) {
143 if ((arg->step->is_valid(arg->current_alg) || arg->opts->all)
144 && (!arg->step->final || !cancel_niss(arg))) {
145
146 pthread_mutex_lock(arg->sols_mutex);
147
148 if (arg->sols->len < arg->opts->max_solutions) {
149 append_alg(arg->sols, arg->current_alg);
150
151 transform_alg(
152 inverse_trans(arg->t),
153 arg->sols->last->alg
154 );
155 if (arg->step->final)
156 inplace(unniss, arg->sols->last->alg);
157
158 if (arg->opts->verbose)
159 print_alg(arg->sols->last->alg, false);
160 }
161
162 pthread_mutex_unlock(arg->sols_mutex);
163 }
164 }
165
166 return true;
167}
168
169static void
170dfs_niss(DfsArg *arg)
171{
172 DfsArg *newarg;
173
174 newarg = malloc(sizeof(DfsArg));
175 newarg->ed = malloc(sizeof(EstimateData));
176
177 copy_dfsarg(arg, newarg);
178 swapmove(&(newarg->last1), &(newarg->last1inv));
179 swapmove(&(newarg->last2), &(newarg->last2inv));
180 newarg->niss = !(arg->niss);
181 newarg->cube = inverse_cube(arg->cube);
182
183 dfs(newarg);
184
185 free(newarg->ed);
186 free(newarg);
187}
188
189static bool
190dfs_stop(DfsArg *arg)
191{
192 int lowerbound;
193 bool b;
194
195 lowerbound = arg->step->estimate(arg);
196 if (arg->opts->can_niss && !arg->niss)
197 lowerbound = MIN(1, lowerbound);
198
199 if (arg->current_alg->len + lowerbound > arg->d) {
200 b = true;
201 } else {
202 pthread_mutex_lock(arg->sols_mutex);
203 b = arg->sols->len >= arg->opts->max_solutions;
204 pthread_mutex_unlock(arg->sols_mutex);
205 }
206
207 return b;
208}
209
210static bool
211dfs_switch(DfsArg *arg)
212{
213 int i, bn, bi;
214
215 bn = 0;
216 for (i = 0; arg->step->moveset->sorted_moves[i] != NULLMOVE; i++)
217 if (allowed_next(arg->step->moveset->sorted_moves[i], arg))
218 bn++;
219
220 swapmove(&(arg->last1), &(arg->last1inv));
221 swapmove(&(arg->last2), &(arg->last2inv));
222 swapu64(&(arg->badmoves), &(arg->badmovesinv));
223
224 bi = 0;
225 for (i = 0; arg->step->moveset->sorted_moves[i] != NULLMOVE; i++)
226 if (allowed_next(arg->step->moveset->sorted_moves[i], arg))
227 bi++;
228
229 swapmove(&(arg->last1), &(arg->last1inv));
230 swapmove(&(arg->last2), &(arg->last2inv));
231 swapu64(&(arg->badmoves), &(arg->badmovesinv));
232
233 return bi < bn;
234}
235
236static void *
237instance_thread(void *arg)
238{
239 bool b;
240 Cube c;
241 ThreadDataSolve *td;
242 AlgListNode *node;
243 DfsArg darg;
244
245 td = (ThreadDataSolve *)arg;
246
247 while (1) {
248 b = false;
249
250 pthread_mutex_lock(td->start_mutex);
251 if ((node = *(td->node)) == NULL)
252 b = true;
253 else
254 *(td->node) = (*(td->node))->next;
255 pthread_mutex_unlock(td->start_mutex);
256
257 if (b)
258 break;
259
260 c = node->alg->inv[0] ?
261 apply_move(node->alg->move[0], inverse_cube(td->cube)) :
262 apply_move(node->alg->move[0], td->cube);
263
264 darg.step = td->step;
265 darg.opts = td->opts;
266 darg.t = td->t;
267 darg.cube = c;
268 darg.d = td->depth;
269 darg.niss = node->alg->inv[0];
270 darg.last1 = node->alg->move[0];
271 darg.last2 = NULLMOVE;
272 darg.last1inv = NULLMOVE;
273 darg.last2inv = NULLMOVE;
274 darg.sols = td->sols;
275 darg.sols_mutex = td->sols_mutex;
276 darg.current_alg = new_alg("");
277 append_move(darg.current_alg, node->alg->move[0],
278 node->alg->inv[0]);
279 darg.ed = malloc(sizeof(EstimateData));
280 reset_estimatedata(darg.ed);
281 darg.badmoves = 0;
282 darg.badmovesinv = 0;
283
284 dfs(&darg);
285
286 free_alg(darg.current_alg);
287 free(darg.ed);
288 }
289
290 return NULL;
291}
292
293static void
294invert_branch(DfsArg *arg)
295{
296 Cube aux;
297
298 aux = arg->cube;
299 arg->cube = is_solved(arg->inverse) ?
300 inverse_cube(arg->cube) : arg->inverse;
301 arg->inverse = aux;
302
303 swapu64(&(arg->badmoves), &(arg->badmovesinv));
304 arg->niss = !(arg->niss);
305 swapmove(&(arg->last1), &(arg->last1inv));
306 swapmove(&(arg->last2), &(arg->last2inv));
307 invert_estimatedata(arg->ed);
308}
309
310static void
311multidfs(Cube c, Trans tr, Step *s, SolveOptions *opts, AlgList *sols, int d)
312{
313 int i;
314 Alg *alg;
315 AlgList *start;
316 AlgListNode **node;
317 pthread_t t[opts->nthreads];
318 ThreadDataSolve td[opts->nthreads];
319 pthread_mutex_t *start_mutex, *sols_mutex;
39 320
40/* TODO: do not alloc */ 321 node = malloc(sizeof(AlgListNode *));
41 newarg.cubedata = solver->alloc_cubedata(solver->param); 322 start_mutex = malloc(sizeof(pthread_mutex_t));
42 for (i = 0; solver->moveset->sorted_moves[i] != NULLMOVE; i++) { 323 sols_mutex = malloc(sizeof(pthread_mutex_t));
43 m = solver->moveset->sorted_moves[i];
44 if (solver->moveset->can_append(arg->current_alg, m, arg->niss)
45 && compare_last(arg->current_alg, m, arg->niss) >= 0) {
46 append_move(arg->current_alg, m, arg->niss);
47 324
48 solver->copy_cubedata( 325 start = new_alglist();
49 solver->param, arg->cubedata, newarg.cubedata); 326 pthread_mutex_init(start_mutex, NULL);
50 newarg.threaddata = arg->threaddata; 327 pthread_mutex_init(sols_mutex, NULL);
51 newarg.opts = arg->opts;
52 newarg.d = arg->d;
53 newarg.niss = arg->niss;
54 newarg.current_alg = arg->current_alg;
55 if (!solver->move_check_stop(
56 solver->param, &newarg, threader))
57 dfs(&newarg, solver, threader);
58 328
59 remove_last_move(arg->current_alg); 329 for (i = 0; s->moveset->sorted_moves[i] != NULLMOVE; i++) {
330 alg = new_alg("");
331 append_move(alg, s->moveset->sorted_moves[i], false);
332 append_alg(start, alg);
333 if (opts->can_niss) {
334 alg->inv[0] = true;
335 append_alg(start, alg);
60 } 336 }
337 free_alg(alg);
61 } 338 }
62 solver->free_cubedata(solver->param, newarg.cubedata); 339 *node = start->first;
63 340
64 if (arg->opts->can_niss && !arg->niss && 341 for (i = 0; i < opts->nthreads; i++) {
65 solver->niss_makes_sense( 342 td[i].thid = i;
66 solver->param, arg->cubedata, arg->current_alg)) { 343 td[i].t = tr;
67 solver->invert_cube(solver->param, arg->cubedata); 344 td[i].cube = c;
68 arg->niss = true; 345 td[i].step = s;
69 dfs(arg, solver, threader); 346 td[i].depth = d;
347 td[i].opts = opts;
348 td[i].start = start;
349 td[i].node = node;
350 td[i].sols = sols;
351 td[i].start_mutex = start_mutex;
352 td[i].sols_mutex = sols_mutex;
353 pthread_create(&t[i], NULL, instance_thread, &td[i]);
70 } 354 }
355
356 for (i = 0; i < opts->nthreads; i++)
357 pthread_join(t[i], NULL);
358
359 free_alglist(start);
360 free(node);
361 free(start_mutex);
362 free(sols_mutex);
363}
364
365static bool
366niss_makes_sense(DfsArg *arg)
367{
368 Cube testcube;
369
370 testcube = apply_move(inverse_move(arg->last1), (Cube){0});
371 return arg->current_alg->len == 0 || !arg->step->is_done(testcube);
71} 372}
72 373
374static bool
375solvestop(int d, int op, SolveOptions *opts, AlgList *sols)
376{
377 bool opt_done, max_moves_exceeded, max_sols_exceeded;
378
379 opt_done = opts->optimal != -1 && op != -1 && d > opts->optimal + op;
380 max_moves_exceeded = d > opts->max_moves;
381 max_sols_exceeded = sols->len >= opts->max_solutions;
382
383 return opt_done || max_moves_exceeded || max_sols_exceeded;
384}
385
386/* Public functions **********************************************************/
387
73AlgList * 388AlgList *
74solve(Cube *cube, SolveOptions *opts, Solver **solver, Threader *threader) 389solve(Cube cube, Step *step, SolveOptions *opts)
75{ 390{
76 int i, d, optimal; 391 bool ready;
77 bool ready[MAX_SOLVERS], stop, one_ready; 392 int i, d, op, nt;
78 DfsArg arg[MAX_SOLVERS];
79 AlgList *sols; 393 AlgList *sols;
394 Cube c;
395 Trans tt[NTRANS];
396
397 prepare_step(step, opts);
80 398
81 one_ready = false; 399 if (step->detect != NULL) {
82 for (i = 0; solver[i] != NULL; i++) { 400 nt = step->detect(cube, tt);
83 arg[i].cubedata = 401 } else {
84 solver[i]->prepare_cube(solver[i]->param, cube); 402 tt[0] = step->pre_trans;
85 arg[i].opts = opts; 403 ready = step->ready == NULL ||
86 ready[i] = arg[i].cubedata != NULL; 404 step->ready(apply_trans(tt[0], cube));
87 one_ready = one_ready || ready[i]; 405 nt = ready ? 1 : 0;
88 } 406 }
89 407
90 sols = new_alglist(); 408 sols = new_alglist();
91 if (!one_ready) { 409
92 fprintf(stderr, "Cube not ready for solving\n"); 410 if (nt == 0) {
411 fprintf(stderr, "Cube not ready for solving step: ");
412 fprintf(stderr, "%s\n", step->ready_msg);
93 return sols; 413 return sols;
94 } 414 }
95 415
96 optimal = opts->max_moves; 416 if (opts->min_moves == 0) {
97 stop = false; 417 for (i = 0; i < nt; i++) {
98 for (d = opts->min_moves; d <= opts->max_moves && !stop; d++) { 418 c = apply_trans(tt[i], cube);
419 if (step->is_done(c)) {
420 append_alg(sols, new_alg(""));
421 return sols;
422 }
423 }
424 }
425
426 op = -1;
427 for (d = opts->min_moves; !solvestop(d, op, opts, sols); d++) {
99 if (opts->verbose) 428 if (opts->verbose)
100 fprintf(stderr, "Searching depth %d\n", d); 429 fprintf(stderr, "Searching depth %d\n", d);
101 430
102 for (i = 0; solver[i] != NULL && !stop; i++) { 431 for (i = 0; i < nt && !solvestop(d, op, opts, sols); i++) {
103 if (!ready[i]) 432 c = apply_trans(tt[i], cube);
104 continue; 433 multidfs(c, tt[i], step, opts, sols, d);
434 if (sols->len > 0 && op == -1)
435 op = d;
436 }
437 }
438
439 return sols;
440}
441
442/* TODO: make more general! */
443Alg *
444solve_2phase(Cube cube, int nthreads)
445{
446 int bestlen, newb;
447 Alg *bestalg, *ret;
448 AlgList *sols1, *sols2;
449 AlgListNode *i;
450 Cube c;
451 SolveOptions opts1, opts2;
105 452
106 arg[i].d = d; 453 opts1.min_moves = 0;
107 threader->dispatch(&arg[i], sols, solver[i], threader); 454 opts1.max_moves = 13;
455 opts1.max_solutions = 20;
456 opts1.nthreads = nthreads;
457 opts1.optimal = 3;
458 opts1.can_niss = false;
459 opts1.verbose = false;
460 opts1.all = true;
108 461
109 if (sols->len > 0) 462 opts2.min_moves = 0;
110 optimal = MIN(optimal, d); 463 opts2.max_moves = 19;
464 opts2.max_solutions = 1;
465 opts2.nthreads = nthreads;
466 opts2.can_niss = false;
467 opts2.verbose = false;
111 468
112 stop = sols->len >= opts->max_solutions; 469 /* We skip step1 if it is solved on any axis */
470 if (drany_HTM.is_done(cube)) {
471 sols1 = new_alglist();
472 append_alg(sols1, new_alg(""));
473 } else {
474 sols1 = solve(cube, &drany_HTM, &opts1);
475 }
476 bestalg = new_alg("");
477 bestlen = 999;
478 for (i = sols1->first; i != NULL; i = i->next) {
479 c = apply_alg(i->alg, cube);
480 sols2 = solve(c, &dranyfin_DR, &opts2);
481
482 if (sols2->len > 0) {
483 newb = i->alg->len + sols2->first->alg->len;
484 if (newb < bestlen) {
485 bestlen = newb;
486 copy_alg(i->alg, bestalg);
487 compose_alg(bestalg, sols2->first->alg);
488 }
113 } 489 }
114 stop = stop || 490
115 (opts->optimal != -1 && d >= opts->optimal + optimal); 491 free_alglist(sols2);
116 } 492 }
117 493
118/* TODO: some cleanup (free cubedata) */ 494 free_alglist(sols1);
119/* TODO: actually, preparation should be done somewhere else */
120 495
121 return sols; 496 ret = cleanup(bestalg);
497 free_alg(bestalg);
498
499 return ret;
122} 500}
diff --git a/src/solve.h b/src/solve.h
index 8182887..6ce6609 100644
--- a/src/solve.h
+++ b/src/solve.h
@@ -2,53 +2,10 @@
2#define SOLVE_H 2#define SOLVE_H
3 3
4#include "moves.h" 4#include "moves.h"
5#include "steps.h"
6#include "trans.h"
5 7
6#define MAX_SOLVERS 99 8AlgList * solve(Cube cube, Step *step, SolveOptions *opts);
7 9Alg * solve_2phase(Cube cube, int nthreads);
8typedef struct dfsarg DfsArg;
9typedef struct threader Threader;
10typedef struct solver Solver;
11
12/* TODO: add solver and threader in DfsData, remove from dispatch args and similar */
13
14struct dfsarg {
15 void * cubedata;
16 void * threaddata;
17 SolveOptions * opts;
18 int d;
19 bool niss;
20 Alg * current_alg;
21};
22
23struct threader {
24 void (*append_sol)(Alg *, void *);
25 void (*dispatch)(DfsArg *, AlgList *, Solver *, Threader *);
26 int (*get_nsol)(void *);
27/* TODO: threader should have param, like solver? */
28};
29
30struct solver {
31 Moveset * moveset;
32 bool (*move_check_stop)(void *, DfsArg *, Threader *);
33 Alg * (*validate_solution)(void *, Alg *);
34 bool (*niss_makes_sense)(void *, void *, Alg *);
35/* TODO: move param to somewhere where it makes more sense */
36 void * param;
37/* TODO: the following should be part of a generic cube description */
38/* TODO: remove alloc? */
39/* TODO: revisit apply_move, maybe apply_alg? or both? */
40 void * (*alloc_cubedata)(void *);
41 void (*copy_cubedata)(void *, void *, void *);
42 void (*free_cubedata)(void *, void *);
43 void (*invert_cube)(void *, void *);
44 bool (*is_solved)(void *, void *);
45 void (*apply_move)(void *, void *, Move);
46/* TODO: remove dependence on Cube, preparation should be done before */
47 void * (*prepare_cube)(void *, Cube *);
48};
49
50void dfs(DfsArg *, Solver *, Threader *);
51/* TODO: remove dependence on Cube, preparation should be done before */
52AlgList * solve(Cube *, SolveOptions *, Solver **, Threader *);
53 10
54#endif 11#endif
diff --git a/src/solver_step.c b/src/solver_step.c
deleted file mode 100644
index 52fa347..0000000
--- a/src/solver_step.c
+++ /dev/null
@@ -1,306 +0,0 @@
1#include "solver_step.h"
2
3typedef struct {
4 Cube * cube;
5 uint64_t * val;
6 Trans * t;
7} CubeData;
8
9static void apply_move_cubedata(void *, void *, Move);
10static void init_indexes(Step *, CubeData *);
11static void * prepare_cube(void *, Cube *);
12static bool move_check_stop_eager(void *, DfsArg *, Threader *);
13static bool move_check_stop_lazy(void *, DfsArg *, Threader *);
14static bool move_check_stop_nonsol(void *, DfsArg *, Threader *);
15static bool is_solved_step(void *, void *);
16static Alg * validate_solution(void *, Alg *);
17static void * alloc_cubedata(void *);
18static void copy_cubedata(void *, void *, void *);
19static void free_cubedata(void *, void *);
20static void invert_cubedata(void *, void *);
21static bool niss_makes_sense(void *, void *, Alg *);
22static Solver * new_stepsolver_nocheckstop(Step *step);
23
24static void
25apply_move_cubedata(void *param, void *cubedata, Move m)
26{
27 Step *s = (Step *)param;
28 CubeData *data = (CubeData *)cubedata;
29
30 Trans tt;
31 for (int i = 0; i < s->n_coord; i++) {
32 Move mm = transform_move(data->t[i], m);
33 data->val[i] = move_coord(s->coord[i], mm, data->val[i], &tt);
34 data->t[i] = transform_trans(tt, data->t[i]);
35 }
36}
37
38static void
39init_indexes(Step *step, CubeData *data)
40{
41 int i;
42 Cube moved;
43 Trans t, tt;
44
45 for (i = 0; i < step->n_coord; i++) {
46 t = step->coord_trans[i];
47 copy_cube(data->cube, &moved);
48 apply_trans(t, &moved);
49 data->val[i] = index_coord(step->coord[i], &moved, &tt);
50 data->t[i] = transform_trans(tt, t);
51 }
52}
53
54static void *
55prepare_cube(void *param, Cube *cube)
56{
57 int i;
58 Step *s;
59 CubeData *data;
60
61 s = (Step *)param;
62
63 for (i = 0; i < s->n_coord; i++) {
64 s->pd[i] = malloc(sizeof(PruneData));
65 s->pd[i]->moveset = s->moveset;
66/* TODO: check if moveset initialization works fine,
67 e.g. if there is a variable to save the initialized status
68 or if it gets initialized multiple times */
69 init_moveset(s->moveset);
70 s->pd[i]->coord = s->coord[i];
71 gen_coord(s->coord[i]);
72 s->pd[i]->compact = s->pd_compact[i];
73 s->pd[i] = genptable(s->pd[i], 4); /* TODO: threads */
74 }
75
76 data = alloc_cubedata(param);
77 data->cube = malloc(sizeof(Cube));
78 copy_cube(cube, data->cube);
79 init_indexes(s, data);
80
81 return data;
82}
83
84static bool
85move_check_stop_eager(void *param, DfsArg *arg, Threader *threader)
86{
87 int nsol;
88
89 if (move_check_stop_nonsol(param, arg, threader))
90 return true;
91
92 nsol = threader->get_nsol(arg->threaddata);
93 return nsol >= arg->opts->max_solutions;
94}
95
96static bool
97move_check_stop_lazy(void *param, DfsArg *arg, Threader *threader)
98{
99 int nsol;
100
101 nsol = threader->get_nsol(arg->threaddata);
102 if (nsol >= arg->opts->max_solutions)
103 return true;
104
105 return move_check_stop_nonsol(param, arg, threader);
106}
107
108/* TODO: split in 2 (nissable / non-nissable) and only move cube
109 when nissable */
110static bool
111move_check_stop_nonsol(void *param, DfsArg *arg, Threader *threader)
112{
113 int i, goal, bound;
114 Move mm, lastmove;
115 Trans tt = uf;
116 CubeData *data;
117 Step *s;
118
119 s = (Step *)param;
120 data = (CubeData *)arg->cubedata;
121
122
123 bound = 0;
124 goal = arg->d - arg->current_alg->len;
125/* TODO: check if len is 0 */
126 lastmove = arg->current_alg->move[arg->current_alg->len-1];
127 for (i = 0; i < s->n_coord; i++) {
128 mm = transform_move(data->t[i], lastmove);
129 data->val[i] = move_coord(s->coord[i], mm, data->val[i], &tt);
130 data->t[i] = transform_trans(tt, data->t[i]);
131
132 bound = MAX(bound, ptableval(s->pd[i], data->val[i]));
133 if (arg->opts->can_niss && !arg->niss)
134 bound = MIN(1, bound);
135
136 if (bound > goal) {
137 return true;
138 }
139 }
140 if (arg->opts->can_niss && !arg->niss)
141 apply_move(lastmove, data->cube);
142
143 return false;
144}
145
146static bool
147is_solved_step(void *param, void *cubedata)
148{
149 int i;
150 Step *s;
151 CubeData *data;
152
153 s = (Step *)param;
154 data = (CubeData *)cubedata;
155
156 for (i = 0; i < s->n_coord; i++)
157 if (data->val[i] != 0)
158 return false;
159
160 return true;
161}
162
163static Alg *
164validate_solution(void *param, Alg *alg)
165{
166 return ((Step *)param)->is_valid(alg);
167}
168
169static void *
170alloc_cubedata(void *param)
171{
172 Step *s;
173 CubeData *data;
174
175 s = (Step *)param;
176
177 data = malloc(sizeof(CubeData));
178 /* We do not need to allocate a cube */
179 data->val = malloc(s->n_coord * sizeof(uint64_t));
180 data->t = malloc(s->n_coord * sizeof(Trans));
181
182 return data;
183}
184
185static void
186copy_cubedata(void *param, void *src, void *dst)
187{
188 int i;
189 Step *s;
190 CubeData *newdata, *olddata;
191
192 s = (Step *)param;
193 olddata = (CubeData *)src;
194 newdata = (CubeData *)dst;
195
196/* TODO: do not copy if not nissable */
197 newdata->cube = malloc(sizeof(Cube));
198 copy_cube(olddata->cube, newdata->cube);
199 for (i = 0; i < s->n_coord; i++) {
200 newdata->val[i] = olddata->val[i];
201 newdata->t[i] = olddata->t[i];
202 }
203}
204
205static void
206free_cubedata(void *param, void *cubedata)
207{
208 CubeData *data;
209
210 data = (CubeData *)cubedata;
211
212 free(data->t);
213 free(data->val);
214 free(data->cube);
215 free(data);
216}
217
218static void
219invert_cubedata(void *param, void *cubedata)
220{
221 Step *s;
222 CubeData *data;
223
224 s = (Step *)param;
225 data = (CubeData *)cubedata;
226
227 invert_cube(data->cube);
228 init_indexes(s, data);
229}
230
231static bool
232niss_makes_sense(void *param, void *cubedata, Alg *alg)
233{
234 Step *s;
235 CubeData *data;
236
237 s = (Step *)param;
238 data = (CubeData *)cubedata;
239
240 if (s->final)
241 return false;
242
243 if (alg->len_normal == 0)
244 return true;
245
246 Move m = inverse_move(alg->move_normal[alg->len_normal-1]);
247 for (int i = 0; i < s->n_coord; i++) {
248 Move mm = transform_move(data->t[i], m);
249 uint64_t u = move_coord(s->coord[i], mm, 0, NULL);
250 if (ptableval(s->pd[i], u) > 0)
251 return true;
252 }
253
254 return false;
255}
256
257static Solver *
258new_stepsolver_nocheckstop(Step *step)
259{
260 Solver *solver;
261
262 solver = malloc(sizeof(Solver));
263
264 solver->moveset = step->moveset;
265 solver->param = step;
266
267 solver->apply_move = apply_move_cubedata;
268 solver->prepare_cube = prepare_cube;
269 solver->is_solved = is_solved_step;
270 solver->validate_solution = validate_solution;
271 solver->alloc_cubedata = alloc_cubedata;
272 solver->copy_cubedata = copy_cubedata;
273 solver->free_cubedata = free_cubedata;
274 solver->invert_cube = invert_cubedata;
275 solver->niss_makes_sense = niss_makes_sense;
276
277 return solver;
278}
279
280Solver *
281new_stepsolver_eager(Step *step)
282{
283 Solver *solver;
284
285 solver = new_stepsolver_nocheckstop(step);
286 solver->move_check_stop = move_check_stop_eager;
287
288 return solver;
289}
290
291Solver *
292new_stepsolver_lazy(Step *step)
293{
294 Solver *solver;
295
296 solver = new_stepsolver_nocheckstop(step);
297 solver->move_check_stop = move_check_stop_lazy;
298
299 return solver;
300}
301
302void
303free_stepsolver(Solver *solver)
304{
305 free(solver);
306}
diff --git a/src/solver_step.h b/src/solver_step.h
deleted file mode 100644
index f68d077..0000000
--- a/src/solver_step.h
+++ /dev/null
@@ -1,12 +0,0 @@
1#ifndef SOLVER_STEP_H
2#define SOLVER_STEP_H
3
4#include "cube.h"
5#include "solve.h"
6#include "steps.h"
7
8Solver *new_stepsolver_eager(Step *);
9Solver *new_stepsolver_lazy(Step *);
10void free_stepsolver(Solver *);
11
12#endif
diff --git a/src/steps.c b/src/steps.c
index cdba763..3189811 100644
--- a/src/steps.c
+++ b/src/steps.c
@@ -1,117 +1,1376 @@
1#define STEPS_C
2
3#include "steps.h" 1#include "steps.h"
4 2
5/* TODO: change all checkers to use coordinates! */ 3#define UPDATECHECKSTOP(a, b, c) if ((a=(MAX((a),(b))))>(c)) return (a);
4
5/* Checkers, estimators and validators ***************************************/
6
7static bool check_centers(Cube cube);
8static bool check_coud_HTM(Cube cube);
9static bool check_coud_URF(Cube cube);
10static bool check_corners_HTM(Cube cube);
11static bool check_corners_URF(Cube cube);
12static bool check_cornershtr(Cube cube);
13static bool check_eofb(Cube cube);
14static bool check_drud(Cube cube);
15static bool check_htr(Cube cube);
16
17static int estimate_eofb_HTM(DfsArg *arg);
18static int estimate_coud_HTM(DfsArg *arg);
19static int estimate_coud_URF(DfsArg *arg);
20static int estimate_corners_HTM(DfsArg *arg);
21static int estimate_cornershtr_HTM(DfsArg *arg);
22static int estimate_corners_URF(DfsArg *arg);
23static int estimate_cornershtr_URF(DfsArg *arg);
24static int estimate_drud_HTM(DfsArg *arg);
25static int estimate_drud_eofb(DfsArg *arg);
26static int estimate_dr_eofb(DfsArg *arg);
27static int estimate_drudfin_drud(DfsArg *arg);
28static int estimate_htr_drud(DfsArg *arg);
29static int estimate_htrfin_htr(DfsArg *arg);
30static int estimate_nxopt31_HTM(DfsArg *arg);
31static int estimate_light_HTM(DfsArg *arg);
32
33static int estimate_nxoptlike(DfsArg *arg, PruneData *pd);
34
35static bool always_valid(Alg *alg);
36static bool validate_singlecw_ending(Alg *alg);
37
38/* Pre-transformation detectors **********************************************/
39
40static int detect_pretrans_eofb(Cube cube, Trans *ret);
41static int detect_pretrans_drud(Cube cube, Trans *ret);
42static int detect_pretrans_void_3axis(Cube cube, Trans *ret);
43
44/* Messages for when cube is not ready ***************************************/
45
46static char check_centers_msg[100] = "cube must be oriented (centers solved)";
47static char check_eo_msg[100] = "EO must be solved on given axis";
48static char check_dr_msg[100] = "DR must be solved on given axis";
49static char check_htr_msg[100] = "HTR must be solved";
50static char check_drany_msg[100] = "DR must be solved on at least one axis";
51
52/* Steps *********************************************************************/
53
54/* Optimal solvers *******************/
55
56Step
57optimal_HTM = {
58 .shortname = "optimal",
59 .name = "Optimal solve (in HTM)",
60
61 .final = true,
62 .is_done = is_solved,
63 .estimate = estimate_nxopt31_HTM,
64 .ready = check_centers,
65 .ready_msg = check_centers_msg,
66 .is_valid = always_valid,
67 .moveset = &moveset_HTM,
68
69 .pre_trans = uf,
70
71 .tables = {&pd_nxopt31_HTM, &pd_corners_HTM},
72 .ntables = 2,
73};
74
75Step
76optimal_light_HTM = {
77 .shortname = "light",
78 .name = "Optimal solve (in HTM), small table (500Mb RAM total)",
79
80 .final = true,
81 .is_done = is_solved,
82 .estimate = estimate_light_HTM,
83 .ready = check_centers,
84 .ready_msg = check_centers_msg,
85 .is_valid = always_valid,
86 .moveset = &moveset_HTM,
87
88 .pre_trans = uf,
89
90 .tables = {&pd_drud_sym16_HTM, &pd_corners_HTM},
91 .ntables = 2,
92};
93
94/* Optimal after EO ******************/
95
96Step
97eofin_eo = {
98 .shortname = "eofin",
99 .name = "Optimal solve after EO without breaking EO (detected)",
100
101 .final = true,
102 .is_done = is_solved,
103 .estimate = estimate_nxopt31_HTM,
104 .ready = check_eofb,
105 .ready_msg = check_eo_msg,
106 .is_valid = always_valid,
107 .moveset = &moveset_eofb,
108
109 .detect = detect_pretrans_eofb,
110
111 .tables = {&pd_nxopt31_HTM, &pd_corners_HTM},
112 .ntables = 2,
113};
114
115Step
116eofbfin_eofb = {
117 .shortname = "eofbfin",
118 .name = "Optimal after EO on F/B without breaking EO",
119
120 .final = true,
121 .is_done = is_solved,
122 .estimate = estimate_nxopt31_HTM,
123 .ready = check_eofb,
124 .ready_msg = check_eo_msg,
125 .is_valid = always_valid,
126 .moveset = &moveset_eofb,
127
128 .pre_trans = uf,
129
130 .tables = {&pd_nxopt31_HTM, &pd_corners_HTM},
131 .ntables = 2,
132};
133
134Step
135eorlfin_eorl = {
136 .shortname = "eorlfin",
137 .name = "Optimal after EO on R/L without breaking EO",
138
139 .final = true,
140 .is_done = is_solved,
141 .estimate = estimate_nxopt31_HTM,
142 .ready = check_eofb,
143 .ready_msg = check_eo_msg,
144 .is_valid = always_valid,
145 .moveset = &moveset_eofb,
146
147 .pre_trans = ur,
148
149 .tables = {&pd_nxopt31_HTM, &pd_corners_HTM},
150 .ntables = 2,
151};
152
153Step
154eoudfin_eoud = {
155 .shortname = "eoudfin",
156 .name = "Optimal after EO on U/D without breaking EO",
157
158 .final = true,
159 .is_done = is_solved,
160 .estimate = estimate_nxopt31_HTM,
161 .ready = check_eofb,
162 .ready_msg = check_eo_msg,
163 .is_valid = always_valid,
164 .moveset = &moveset_eofb,
165
166 .pre_trans = fd,
167
168 .tables = {&pd_nxopt31_HTM, &pd_corners_HTM},
169 .ntables = 2,
170};
171
172/* EO steps **************************/
173Step
174eoany_HTM = {
175 .shortname = "eo",
176 .name = "EO on any axis",
177
178 .final = false,
179 .is_done = check_eofb,
180 .estimate = estimate_eofb_HTM,
181 .ready = check_centers,
182 .ready_msg = check_centers_msg,
183 .is_valid = validate_singlecw_ending,
184 .moveset = &moveset_HTM,
185
186 .detect = detect_pretrans_void_3axis,
187
188 .tables = {&pd_eofb_HTM},
189 .ntables = 1,
190};
191
192Step
193eofb_HTM = {
194 .shortname = "eofb",
195 .name = "EO on F/B",
196
197 .final = false,
198 .is_done = check_eofb,
199 .estimate = estimate_eofb_HTM,
200 .ready = check_centers,
201 .ready_msg = check_centers_msg,
202 .is_valid = validate_singlecw_ending,
203 .moveset = &moveset_HTM,
204
205 .pre_trans = uf,
206
207 .tables = {&pd_eofb_HTM},
208 .ntables = 1,
209};
210
211Step
212eorl_HTM = {
213 .shortname = "eorl",
214 .name = "EO on R/L",
215
216 .final = false,
217 .is_done = check_eofb,
218 .estimate = estimate_eofb_HTM,
219 .ready = check_centers,
220 .ready_msg = check_centers_msg,
221 .is_valid = validate_singlecw_ending,
222 .moveset = &moveset_HTM,
223
224 .pre_trans = ur,
225
226 .tables = {&pd_eofb_HTM},
227 .ntables = 1,
228};
229
230Step
231eoud_HTM = {
232 .shortname = "eoud",
233 .name = "EO on U/D",
234
235 .final = false,
236 .is_done = check_eofb,
237 .estimate = estimate_eofb_HTM,
238 .ready = check_centers,
239 .ready_msg = check_centers_msg,
240 .is_valid = validate_singlecw_ending,
241 .moveset = &moveset_HTM,
242
243 .pre_trans = fd,
244
245 .tables = {&pd_eofb_HTM},
246 .ntables = 1,
247};
248
249/* CO steps **************************/
250Step
251coany_HTM = {
252 .shortname = "co",
253 .name = "CO on any axis",
254
255 .final = false,
256 .is_done = check_coud_HTM,
257 .estimate = estimate_coud_HTM,
258 .ready = NULL,
259 .is_valid = validate_singlecw_ending,
260 .moveset = &moveset_HTM,
261
262 .detect = detect_pretrans_void_3axis,
263
264 .tables = {&pd_coud_HTM},
265 .ntables = 1,
266};
267
268Step
269coud_HTM = {
270 .shortname = "coud",
271 .name = "CO on U/D",
272
273 .final = false,
274 .is_done = check_coud_HTM,
275 .estimate = estimate_coud_HTM,
276 .ready = NULL,
277 .is_valid = validate_singlecw_ending,
278 .moveset = &moveset_HTM,
279
280 .pre_trans = uf,
281
282 .tables = {&pd_coud_HTM},
283 .ntables = 1,
284};
285
286Step
287corl_HTM = {
288 .shortname = "corl",
289 .name = "CO on R/L",
290
291 .final = false,
292 .is_done = check_coud_HTM,
293 .estimate = estimate_coud_HTM,
294 .ready = NULL,
295 .is_valid = validate_singlecw_ending,
296 .moveset = &moveset_HTM,
297
298 .pre_trans = rf,
299
300 .tables = {&pd_coud_HTM},
301 .ntables = 1,
302};
303
304Step
305cofb_HTM = {
306 .shortname = "cofb",
307 .name = "CO on F/B",
308
309 .final = false,
310 .is_done = check_coud_HTM,
311 .estimate = estimate_coud_HTM,
312 .ready = NULL,
313 .is_valid = validate_singlecw_ending,
314 .moveset = &moveset_HTM,
315
316 .pre_trans = fd,
317
318 .tables = {&pd_coud_HTM},
319 .ntables = 1,
320};
321
322Step
323coany_URF = {
324 .shortname = "co-URF",
325 .name = "CO any axis (URF moveset)",
326
327 .final = false,
328 .is_done = check_coud_URF,
329 .estimate = estimate_coud_URF,
330 .ready = NULL,
331 .is_valid = validate_singlecw_ending,
332 .moveset = &moveset_URF,
333
334 .detect = detect_pretrans_void_3axis,
335
336 .tables = {&pd_coud_HTM},
337 .ntables = 1,
338};
339
340Step
341coud_URF = {
342 .shortname = "coud-URF",
343 .name = "CO on U/D (URF moveset)",
344
345 .final = false,
346 .is_done = check_coud_URF,
347 .estimate = estimate_coud_URF,
348 .ready = NULL,
349 .is_valid = validate_singlecw_ending,
350 .moveset = &moveset_URF,
351
352 .pre_trans = uf,
353
354 .tables = {&pd_coud_HTM},
355 .ntables = 1,
356};
357
358Step
359corl_URF = {
360 .shortname = "corl-URF",
361 .name = "CO on R/L (URF moveset)",
362
363 .final = false,
364 .is_done = check_coud_URF,
365 .estimate = estimate_coud_URF,
366 .ready = NULL,
367 .is_valid = validate_singlecw_ending,
368 .moveset = &moveset_URF,
369
370 .pre_trans = rf,
371
372 .tables = {&pd_coud_HTM},
373 .ntables = 1,
374};
375
376Step
377cofb_URF = {
378 .shortname = "cofb-URF",
379 .name = "CO on F/B (URF moveset)",
380
381 .final = false,
382 .is_done = check_coud_URF,
383 .estimate = estimate_coud_URF,
384 .ready = NULL,
385 .is_valid = validate_singlecw_ending,
386 .moveset = &moveset_URF,
387
388 .pre_trans = fd,
389
390 .tables = {&pd_coud_HTM},
391 .ntables = 1,
392};
393
394/* Misc corner steps *****************/
395Step
396cornershtr_HTM = {
397 .shortname = "chtr",
398 .name = "Solve corners to HTR state",
399
400 .final = false,
401 .is_done = check_cornershtr,
402 .estimate = estimate_cornershtr_HTM,
403 .ready = NULL,
404 .is_valid = validate_singlecw_ending,
405 .moveset = &moveset_HTM,
406
407 .pre_trans = uf,
408
409 .tables = {&pd_cornershtr_HTM},
410 .ntables = 1,
411};
412
413Step
414cornershtr_URF = {
415 .shortname = "chtr-URF",
416 .name = "Solve corners to HTR state (URF moveset)",
417
418 .final = false,
419 .is_done = check_cornershtr,
420 .estimate = estimate_cornershtr_URF,
421 .ready = NULL,
422 .is_valid = validate_singlecw_ending,
423 .moveset = &moveset_URF,
424
425 .pre_trans = uf,
426
427 .tables = {&pd_cornershtr_HTM},
428 .ntables = 1,
429};
430
431Step
432corners_HTM = {
433 .shortname = "corners",
434 .name = "Solve corners",
435
436 .final = true,
437 .is_done = check_corners_HTM,
438 .estimate = estimate_corners_HTM,
439 .ready = NULL,
440 .is_valid = always_valid,
441 .moveset = &moveset_HTM,
442
443 .pre_trans = uf,
444
445 .tables = {&pd_corners_HTM},
446 .ntables = 1,
447};
448
449Step
450corners_URF = {
451 .shortname = "corners-URF",
452 .name = "Solve corners (URF moveset)",
453
454 .final = true, /* TODO: check if this works with reorient */
455 .is_done = check_corners_URF,
456 .estimate = estimate_corners_URF,
457 .ready = NULL,
458 .is_valid = always_valid,
459 .moveset = &moveset_URF,
460
461 .pre_trans = uf,
462
463 .tables = {&pd_corners_HTM},
464 .ntables = 1,
465};
466
467/* DR steps **************************/
468Step
469drany_HTM = {
470 .shortname = "dr",
471 .name = "DR on any axis",
472
473 .final = false,
474 .is_done = check_drud,
475 .estimate = estimate_drud_HTM,
476 .ready = check_centers,
477 .ready_msg = check_centers_msg,
478 .is_valid = validate_singlecw_ending,
479 .moveset = &moveset_HTM,
480
481 .detect = detect_pretrans_void_3axis,
482
483 .tables = {&pd_drud_sym16_HTM},
484 .ntables = 1,
485};
486
487Step
488drud_HTM = {
489 .shortname = "drud",
490 .name = "DR on U/D",
491
492 .final = false,
493 .is_done = check_drud,
494 .estimate = estimate_drud_HTM,
495 .ready = check_centers,
496 .ready_msg = check_centers_msg,
497 .is_valid = validate_singlecw_ending,
498 .moveset = &moveset_HTM,
499
500 .pre_trans = uf,
501
502 .tables = {&pd_drud_sym16_HTM},
503 .ntables = 1,
504};
505
506Step
507drrl_HTM = {
508 .shortname = "drrl",
509 .name = "DR on R/L",
510
511 .final = false,
512 .is_done = check_drud,
513 .estimate = estimate_drud_HTM,
514 .ready = check_centers,
515 .ready_msg = check_centers_msg,
516 .is_valid = validate_singlecw_ending,
517 .moveset = &moveset_HTM,
518
519 .pre_trans = rf,
520
521 .tables = {&pd_drud_sym16_HTM},
522 .ntables = 1,
523};
524
525Step
526drfb_HTM = {
527 .shortname = "drfb",
528 .name = "DR on F/B",
529
530 .final = false,
531 .is_done = check_drud,
532 .estimate = estimate_drud_HTM,
533 .ready = check_centers,
534 .ready_msg = check_centers_msg,
535 .is_valid = validate_singlecw_ending,
536 .moveset = &moveset_HTM,
537
538 .pre_trans = fd,
539
540 .tables = {&pd_drud_sym16_HTM},
541 .ntables = 1,
542};
543
544/* DR from EO */
545Step
546dr_eo = {
547 .shortname = "dr-eo",
548 .name = "DR without breaking EO (automatically detected)",
549
550 .final = false,
551 .is_done = check_drud,
552 .estimate = estimate_dr_eofb,
553 .ready = check_eofb,
554 .ready_msg = check_eo_msg,
555 .is_valid = validate_singlecw_ending,
556 .moveset = &moveset_eofb,
557
558 .detect = detect_pretrans_eofb,
559
560 .tables = {&pd_drud_eofb},
561 .ntables = 1,
562};
563
564Step
565dr_eofb = {
566 .shortname = "dr-eofb",
567 .name = "DR on U/D or R/L without breaking EO on F/B",
568
569 .final = false,
570 .is_done = check_drud,
571 .estimate = estimate_dr_eofb,
572 .ready = check_eofb,
573 .ready_msg = check_eo_msg,
574 .is_valid = validate_singlecw_ending,
575 .moveset = &moveset_eofb,
576
577 .pre_trans = uf,
578
579 .tables = {&pd_drud_eofb},
580 .ntables = 1,
581};
582
583Step
584dr_eorl = {
585 .shortname = "dr-eorl",
586 .name = "DR on U/D or F/B without breaking EO on R/L",
587
588 .final = false,
589 .is_done = check_drud,
590 .estimate = estimate_dr_eofb,
591 .ready = check_eofb,
592 .ready_msg = check_eo_msg,
593 .is_valid = validate_singlecw_ending,
594 .moveset = &moveset_eofb,
595
596 .pre_trans = ur,
597
598 .tables = {&pd_drud_eofb},
599 .ntables = 1,
600};
601
602Step
603dr_eoud = {
604 .shortname = "dr-eoud",
605 .name = "DR on R/L or F/B without breaking EO on U/D",
606
607 .final = false,
608 .is_done = check_drud,
609 .estimate = estimate_dr_eofb,
610 .ready = check_eofb,
611 .ready_msg = check_eo_msg,
612 .is_valid = validate_singlecw_ending,
613 .moveset = &moveset_eofb,
614
615 .pre_trans = fd,
616
617 .tables = {&pd_drud_eofb},
618 .ntables = 1,
619};
620
621Step
622drud_eofb = {
623 .shortname = "drud-eofb",
624 .name = "DR on U/D without breaking EO on F/B",
625
626 .final = false,
627 .is_done = check_drud,
628 .estimate = estimate_drud_eofb,
629 .ready = check_eofb,
630 .ready_msg = check_eo_msg,
631 .is_valid = validate_singlecw_ending,
632 .moveset = &moveset_eofb,
633
634 .pre_trans = uf,
635
636 .tables = {&pd_drud_eofb},
637 .ntables = 1,
638};
639
640Step
641drrl_eofb = {
642 .shortname = "drrl-eofb",
643 .name = "DR on R/L without breaking EO on F/B",
644
645 .final = false,
646 .is_done = check_drud,
647 .estimate = estimate_drud_eofb,
648 .ready = check_eofb,
649 .ready_msg = check_eo_msg,
650 .is_valid = validate_singlecw_ending,
651 .moveset = &moveset_eofb,
652
653 .pre_trans = rf,
654
655 .tables = {&pd_drud_eofb},
656 .ntables = 1,
657};
658
659Step
660drud_eorl = {
661 .shortname = "drud-eorl",
662 .name = "DR on U/D without breaking EO on R/L",
663
664 .final = false,
665 .is_done = check_drud,
666 .estimate = estimate_drud_eofb,
667 .ready = check_eofb,
668 .ready_msg = check_eo_msg,
669 .is_valid = validate_singlecw_ending,
670 .moveset = &moveset_eofb,
671
672 .pre_trans = ur,
673
674 .tables = {&pd_drud_eofb},
675 .ntables = 1,
676};
677
678Step
679drfb_eorl = {
680 .shortname = "drfb-eorl",
681 .name = "DR on F/B without breaking EO on R/L",
682
683 .final = false,
684 .is_done = check_drud,
685 .estimate = estimate_drud_eofb,
686 .ready = check_eofb,
687 .ready_msg = check_eo_msg,
688 .is_valid = validate_singlecw_ending,
689 .moveset = &moveset_eofb,
690
691 .pre_trans = fr,
692
693 .tables = {&pd_drud_eofb},
694 .ntables = 1,
695};
696
697Step
698drfb_eoud = {
699 .shortname = "drfb-eoud",
700 .name = "DR on F/B without breaking EO on U/D",
701
702 .final = false,
703 .is_done = check_drud,
704 .estimate = estimate_drud_eofb,
705 .ready = check_eofb,
706 .ready_msg = check_eo_msg,
707 .is_valid = validate_singlecw_ending,
708 .moveset = &moveset_eofb,
709
710 .pre_trans = fd,
711
712 .tables = {&pd_drud_eofb},
713 .ntables = 1,
714};
715
716Step
717drrl_eoud = {
718 .shortname = "drrl-eoud",
719 .name = "DR on R/L without breaking EO on U/D",
720
721 .final = false,
722 .is_done = check_drud,
723 .estimate = estimate_drud_eofb,
724 .ready = check_eofb,
725 .ready_msg = check_eo_msg,
726 .is_valid = validate_singlecw_ending,
727 .moveset = &moveset_eofb,
728
729 .pre_trans = rd,
730
731 .tables = {&pd_drud_eofb},
732 .ntables = 1,
733};
734
735/* DR finish steps */
736Step
737dranyfin_DR = {
738 .shortname = "drfin",
739 .name = "DR finish on any axis without breaking DR",
740
741 .final = true,
742 .is_done = is_solved,
743 .estimate = estimate_drudfin_drud,
744 .ready = check_drud,
745 .ready_msg = check_drany_msg,
746 .is_valid = always_valid,
747 .moveset = &moveset_drud,
748
749 .detect = detect_pretrans_drud,
750
751 .tables = {&pd_drudfin_noE_sym16_drud},
752 .ntables = 1,
753};
754
755Step
756drudfin_drud = {
757 .shortname = "drudfin",
758 .name = "DR finish on U/D without breaking DR",
759
760 .final = true,
761 .is_done = is_solved,
762 .estimate = estimate_drudfin_drud,
763 .ready = check_drud,
764 .ready_msg = check_dr_msg,
765 .is_valid = always_valid,
766 .moveset = &moveset_drud,
767
768 .pre_trans = uf,
769
770 .tables = {&pd_drudfin_noE_sym16_drud},
771 .ntables = 1,
772};
773
774Step
775drrlfin_drrl = {
776 .shortname = "drrlfin",
777 .name = "DR finish on R/L without breaking DR",
778
779 .final = true,
780 .is_done = is_solved,
781 .estimate = estimate_drudfin_drud,
782 .ready = check_drud,
783 .ready_msg = check_dr_msg,
784 .is_valid = always_valid,
785 .moveset = &moveset_drud,
786
787 .pre_trans = rf,
788
789 .tables = {&pd_drudfin_noE_sym16_drud},
790 .ntables = 1,
791};
792
793Step
794drfbfin_drfb = {
795 .shortname = "drfbfin",
796 .name = "DR finish on F/B without breaking DR",
797
798 .final = true,
799 .is_done = is_solved,
800 .estimate = estimate_drudfin_drud,
801 .ready = check_drud,
802 .ready_msg = check_dr_msg,
803 .is_valid = always_valid,
804 .moveset = &moveset_drud,
805
806 .pre_trans = fd,
807
808 .tables = {&pd_drudfin_noE_sym16_drud},
809 .ntables = 1,
810};
811
812/* HTR from DR */
813Step
814htr_any = {
815 .shortname = "htr",
816 .name = "HTR from DR",
817
818 .final = false,
819 .is_done = check_htr,
820 .estimate = estimate_htr_drud,
821 .ready = check_drud,
822 .ready_msg = check_drany_msg,
823 .is_valid = validate_singlecw_ending,
824 .moveset = &moveset_drud,
825
826 .detect = detect_pretrans_drud,
827
828 .tables = {&pd_htr_drud},
829 .ntables = 1,
830};
831
832Step
833htr_drud = {
834 .shortname = "htr-drud",
835 .name = "HTR from DR on U/D",
6 836
7bool 837 .final = false,
8check_centers(Cube *cube) 838 .is_done = check_htr,
839 .estimate = estimate_htr_drud,
840 .ready = check_drud,
841 .ready_msg = check_dr_msg,
842 .is_valid = validate_singlecw_ending,
843 .moveset = &moveset_drud,
844
845 .pre_trans = uf,
846
847 .tables = {&pd_htr_drud},
848 .ntables = 1,
849};
850
851Step
852htr_drrl = {
853 .shortname = "htr-drrl",
854 .name = "HTR from DR on R/L",
855
856 .final = false,
857 .is_done = check_htr,
858 .estimate = estimate_htr_drud,
859 .ready = check_drud,
860 .ready_msg = check_dr_msg,
861 .is_valid = validate_singlecw_ending,
862 .moveset = &moveset_drud,
863
864 .pre_trans = rf,
865
866 .tables = {&pd_htr_drud},
867 .ntables = 1,
868};
869
870Step
871htr_drfb = {
872 .shortname = "htr-drfb",
873 .name = "HTR from DR on F/B",
874
875 .final = false,
876 .is_done = check_htr,
877 .estimate = estimate_htr_drud,
878 .ready = check_drud,
879 .ready_msg = check_dr_msg,
880 .is_valid = validate_singlecw_ending,
881 .moveset = &moveset_drud,
882
883 .pre_trans = fd,
884
885 .tables = {&pd_htr_drud},
886 .ntables = 1,
887};
888
889/* HTR finish */
890Step
891htrfin_htr = {
892 .shortname = "htrfin",
893 .name = "HTR finish without breaking HTR",
894
895 .final = true,
896 .is_done = is_solved,
897 .estimate = estimate_htrfin_htr,
898 .ready = check_htr,
899 .ready_msg = check_htr_msg,
900 .is_valid = always_valid,
901 .moveset = &moveset_htr,
902
903 .pre_trans = uf,
904
905 .tables = {&pd_htrfin_htr},
906 .ntables = 1,
907};
908
909Step *steps[] = {
910 &optimal_HTM, /* first is default */
911 &optimal_light_HTM,
912
913 &eofin_eo,
914 &eofbfin_eofb,
915 &eorlfin_eorl,
916 &eoudfin_eoud,
917
918 &eoany_HTM,
919 &eofb_HTM,
920 &eorl_HTM,
921 &eoud_HTM,
922
923 &coany_HTM,
924 &coud_HTM,
925 &corl_HTM,
926 &cofb_HTM,
927
928 &coany_URF,
929 &coud_URF,
930 &corl_URF,
931 &cofb_URF,
932
933 &drany_HTM,
934 &drud_HTM,
935 &drrl_HTM,
936 &drfb_HTM,
937
938 &dr_eo,
939 &dr_eofb,
940 &dr_eorl,
941 &dr_eoud,
942 &drud_eofb,
943 &drrl_eofb,
944 &drud_eorl,
945 &drfb_eorl,
946 &drfb_eoud,
947 &drrl_eoud,
948
949 &dranyfin_DR,
950 &drudfin_drud,
951 &drrlfin_drrl,
952 &drfbfin_drfb,
953
954 &htr_any,
955 &htr_drud,
956 &htr_drrl,
957 &htr_drfb,
958
959 &htrfin_htr,
960
961 &cornershtr_HTM,
962 &cornershtr_URF,
963 &corners_HTM,
964 &corners_URF,
965
966 NULL
967};
968
969/* Checkers, estimators and validators ***************************************/
970
971static bool
972check_centers(Cube cube)
9{ 973{
10 int i; 974 return cube.cpos == 0;
975}
11 976
12 for (i = 0; i < 6; i++) 977static bool
13 if (cube->xp[i] != i) 978check_coud_HTM(Cube cube)
14 return false; 979{
980 return cube.coud == 0;
981}
15 982
16 return true; 983static bool
984check_coud_URF(Cube cube)
985{
986 Cube c2, c3;
987
988 c2 = apply_move(z, cube);
989 c3 = apply_move(x, cube);
990
991 return cube.coud == 0 || c2.coud == 0 || c3.coud == 0;
17} 992}
18 993
19bool 994static bool
20check_coud_HTM(Cube *cube) 995check_corners_URF(Cube cube)
21{ 996{
22 int i; 997 Cube c;
998 Trans i;
23 999
24 for (i = 0; i < 8; i++) 1000 for (i = 0; i < NROTATIONS; i++) {
25 if (cube->co[i] != 0) 1001 c = apply_alg(rotation_alg(i), cube);
26 return false; 1002 if (c.cp && c.coud)
1003 return true;
1004 }
27 1005
28 return true; 1006 return false;
29} 1007}
30 1008
31bool 1009static bool
32check_coud_URF(Cube *cube) 1010check_corners_HTM(Cube cube)
33{ 1011{
34 Cube c2, c3; 1012 return cube.cp == 0 && cube.coud == 0;
1013}
35 1014
36 copy_cube(cube, &c2); 1015static bool
37 copy_cube(cube, &c3); 1016check_cornershtr(Cube cube)
1017{
1018 return coord_cornershtr.index(cube) == 0;
1019}
38 1020
39 apply_move(z, &c2); 1021static bool
40 apply_move(x, &c3); 1022check_eofb(Cube cube)
1023{
1024 return cube.eofb == 0;
1025}
41 1026
42 return check_coud_HTM(cube) || 1027static bool
43 check_coud_HTM(&c2) || 1028check_drud(Cube cube)
44 check_coud_HTM(&c3); 1029{
1030 return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0;
45} 1031}
46 1032
47bool 1033static bool
48check_cp_HTM(Cube *cube) 1034check_htr(Cube cube)
49{ 1035{
50 int i; 1036 return check_drud(cube) && coord_htr_drud.index(cube) == 0;
1037}
1038
1039static int
1040estimate_eofb_HTM(DfsArg *arg)
1041{
1042 return ptableval(&pd_eofb_HTM, arg->cube);
1043}
1044
1045static int
1046estimate_coud_HTM(DfsArg *arg)
1047{
1048 return ptableval(&pd_coud_HTM, arg->cube);
1049}
51 1050
52 for (i = 0; i < 8; i++) 1051static int
53 if (cube->cp[i] != i) 1052estimate_coud_URF(DfsArg *arg)
54 return false; 1053{
1054 /* TODO: I can improve this by checking first the orientation of
1055 * the corner in DBL and use that as a reference */
55 1056
56 return true; 1057 Cube c;
1058
1059 c = arg->cube;
1060
1061 int ud = estimate_coud_HTM(arg);
1062 arg->cube = apply_move(z, c);
1063 int rl = estimate_coud_HTM(arg);
1064 arg->cube = apply_move(x, c);
1065 int fb = estimate_coud_HTM(arg);
1066
1067 arg->cube = c;
1068
1069 return MIN(ud, MIN(rl, fb));
57} 1070}
58 1071
59bool 1072static int
60check_corners_HTM(Cube *cube) 1073estimate_corners_HTM(DfsArg *arg)
61{ 1074{
62 return check_coud_HTM(cube) && check_cp_HTM(cube); 1075 return ptableval(&pd_corners_HTM, arg->cube);
63} 1076}
64 1077
65bool 1078static int
66check_corners_URF(Cube *cube) 1079estimate_cornershtr_HTM(DfsArg *arg)
67{ 1080{
1081 return ptableval(&pd_cornershtr_HTM, arg->cube);
1082}
1083
1084static int
1085estimate_cornershtr_URF(DfsArg *arg)
1086{
1087 /* TODO: I can improve this by checking first the corner in DBL
1088 * and use that as a reference */
1089
1090 int ret;
68 Cube c; 1091 Cube c;
69 Trans i; 1092 Trans i;
70 1093
1094 c = arg->cube;
1095 ret = 15;
1096
71 for (i = 0; i < NROTATIONS; i++) { 1097 for (i = 0; i < NROTATIONS; i++) {
72 copy_cube(cube, &c); 1098 arg->cube = apply_alg(rotation_alg(i), c);
73 apply_alg(rotation_alg(i), &c); 1099 ret = MIN(ret, estimate_cornershtr_HTM(arg));
74 if (check_corners_HTM(&c))
75 return true;
76 } 1100 }
77 1101
78 return false; 1102 arg->cube = c;
1103
1104 return ret;
79} 1105}
80 1106
81bool 1107static int
82check_cornershtr(Cube *cube) 1108estimate_corners_URF(DfsArg *arg)
83{ 1109{
84 /* TODO (use coord) */ 1110 /* TODO: I can improve this by checking first the corner in DBL
85 return true; 1111 * and use that as a reference */
1112
1113 int ret;
1114 Cube c;
1115 Trans i;
1116
1117 c = arg->cube;
1118 ret = 15;
1119
1120 for (i = 0; i < NROTATIONS; i++) {
1121 arg->cube = apply_alg(rotation_alg(i), c);
1122 ret = MIN(ret, estimate_corners_HTM(arg));
1123 }
1124
1125 arg->cube = c;
1126
1127 return ret;
86} 1128}
87 1129
88bool 1130static int
89check_eofb(Cube *cube) 1131estimate_drud_HTM(DfsArg *arg)
90{ 1132{
91 /* TODO (use coord) */ 1133 return ptableval(&pd_drud_sym16_HTM, arg->cube);
92 return true;
93} 1134}
94 1135
95bool 1136static int
96check_drud(Cube *cube) 1137estimate_drud_eofb(DfsArg *arg)
97{ 1138{
98 /* TODO (use coord) */ 1139 return ptableval(&pd_drud_eofb, arg->cube);
99 return true;
100} 1140}
101 1141
102bool 1142static int
103check_htr(Cube *cube) 1143estimate_dr_eofb(DfsArg *arg)
1144{
1145 int r1, r2;
1146
1147 r1 = ptableval(&pd_drud_eofb, arg->cube);
1148 r2 = ptableval(&pd_drud_eofb, apply_trans(rf, arg->cube));
1149
1150 return MIN(r1, r2);
1151}
1152
1153static int
1154estimate_drudfin_drud(DfsArg *arg)
1155{
1156 int val = ptableval(&pd_drudfin_noE_sym16_drud, arg->cube);
1157
1158 if (val != 0)
1159 return val;
1160
1161 return arg->cube.epose % 24 == 0 ? 0 : 1;
1162}
1163
1164static int
1165estimate_htr_drud(DfsArg *arg)
1166{
1167 return ptableval(&pd_htr_drud, arg->cube);
1168}
1169
1170static int
1171estimate_htrfin_htr(DfsArg *arg)
1172{
1173 return ptableval(&pd_htrfin_htr, arg->cube);
1174}
1175
1176static int
1177estimate_nxopt31_HTM(DfsArg *arg)
1178{
1179 return estimate_nxoptlike(arg, &pd_nxopt31_HTM);
1180}
1181
1182/* TODO: also use generic procedure for this */
1183static int
1184estimate_light_HTM(DfsArg *arg)
1185{
1186 int target, ret;
1187 Cube aux;
1188
1189 static const uint64_t udmask = (1<<U) | (1<<U2) | (1<<U3) |
1190 (1<<D) | (1<<D2) | (1<<D3);
1191 static const uint64_t rlmask = (1<<R) | (1<<R2) | (1<<R3) |
1192 (1<<L) | (1<<L2) | (1<<L3);
1193 static const uint64_t fbmask = (1<<F) | (1<<F2) | (1<<F3) |
1194 (1<<B) | (1<<B2) | (1<<B3);
1195 static const uint64_t htmask = (1<<U2) | (1<<D2) |
1196 (1<<R2) | (1<<L2) |
1197 (1<<F2) | (1<<B2);
1198
1199 ret = -1;
1200 target = arg->d - arg->current_alg->len;
1201 arg->inverse = (Cube){0};
1202 arg->badmovesinv = 0;
1203 arg->badmoves = 0;
1204
1205 /* Corners */
1206 arg->ed->corners = ptableval(&pd_corners_HTM, arg->cube);
1207 UPDATECHECKSTOP(ret, arg->ed->corners, target);
1208
1209 /* Normal probing */
1210 arg->ed->normal_ud = ptableval(&pd_drud_sym16_HTM, arg->cube);
1211 UPDATECHECKSTOP(ret, arg->ed->normal_ud, target);
1212 aux = apply_trans(fd, arg->cube);
1213 arg->ed->normal_fb = ptableval(&pd_drud_sym16_HTM, aux);
1214 UPDATECHECKSTOP(ret, arg->ed->normal_fb, target);
1215 aux = apply_trans(rf, arg->cube);
1216 arg->ed->normal_rl = ptableval(&pd_drud_sym16_HTM, aux);
1217 UPDATECHECKSTOP(ret, arg->ed->normal_rl, target);
1218
1219 /* If ret == 0, it's solved (corners + triple slice solved) */
1220 if (ret == 0)
1221 return is_solved(arg->cube) ? 0 : 1;
1222
1223 /* Michel de Bondt's trick*/
1224 if (arg->ed->normal_ud == arg->ed->normal_fb &&
1225 arg->ed->normal_fb == arg->ed->normal_rl) {
1226 UPDATECHECKSTOP(ret, arg->ed->normal_ud + 1, target);
1227 }
1228
1229 /* Inverse probing */
1230 if (!((1<<arg->last1) & htmask)) {
1231 aux = arg->inverse = inverse_cube(arg->cube);
1232 if (!((1<<arg->last1) & udmask) || (arg->ed->inverse_ud==-1)) {
1233 arg->ed->inverse_ud =
1234 ptableval(&pd_drud_sym16_HTM, aux);
1235 }
1236 UPDATECHECKSTOP(ret, arg->ed->inverse_ud, target);
1237 if (!((1<<arg->last1) & fbmask) || (arg->ed->inverse_fb==-1)) {
1238 aux = apply_trans(fd, arg->inverse);
1239 arg->ed->inverse_fb =
1240 ptableval(&pd_drud_sym16_HTM, aux);
1241 }
1242 UPDATECHECKSTOP(ret, arg->ed->inverse_fb, target);
1243 if (!((1<<arg->last1) & rlmask) || (arg->ed->inverse_rl==-1)) {
1244 aux = apply_trans(rf, arg->inverse);
1245 arg->ed->inverse_rl =
1246 ptableval(&pd_drud_sym16_HTM, aux);
1247 }
1248 UPDATECHECKSTOP(ret, arg->ed->inverse_rl, target);
1249 } else {
1250 UPDATECHECKSTOP(ret, arg->ed->inverse_ud, target);
1251 UPDATECHECKSTOP(ret, arg->ed->inverse_fb, target);
1252 UPDATECHECKSTOP(ret, arg->ed->inverse_rl, target);
1253 }
1254
1255 /* Michel de Bondt's trick*/
1256 if (arg->ed->inverse_ud == arg->ed->inverse_fb &&
1257 arg->ed->inverse_fb == arg->ed->inverse_rl) {
1258 UPDATECHECKSTOP(ret, arg->ed->inverse_ud + 1, target);
1259 }
1260
1261 /* nxopt trick + half turn trick */
1262 if (arg->ed->normal_ud == target)
1263 arg->badmovesinv |= udmask | htmask;
1264 if (arg->ed->normal_fb == target)
1265 arg->badmovesinv |= fbmask | htmask;
1266 if (arg->ed->normal_rl == target)
1267 arg->badmovesinv |= rlmask | htmask;
1268
1269 if (arg->ed->inverse_ud == target)
1270 arg->badmoves |= udmask | htmask;
1271 if (arg->ed->inverse_fb == target)
1272 arg->badmoves |= fbmask | htmask;
1273 if (arg->ed->inverse_rl == target)
1274 arg->badmoves |= rlmask | htmask;
1275
1276 return arg->ed->oldret = ret;
1277}
1278
1279static int
1280estimate_nxoptlike(DfsArg *arg, PruneData *pd)
1281{
1282 int target, ret;
1283 Cube aux;
1284
1285 static const uint64_t udmask = (1<<U) | (1<<U2) | (1<<U3) |
1286 (1<<D) | (1<<D2) | (1<<D3);
1287 static const uint64_t rlmask = (1<<R) | (1<<R2) | (1<<R3) |
1288 (1<<L) | (1<<L2) | (1<<L3);
1289 static const uint64_t fbmask = (1<<F) | (1<<F2) | (1<<F3) |
1290 (1<<B) | (1<<B2) | (1<<B3);
1291
1292 ret = -1;
1293 target = arg->d - arg->current_alg->len;
1294 arg->inverse = (Cube){0};
1295 arg->badmovesinv = 0;
1296 arg->badmoves = 0;
1297
1298 /* Corners */
1299 arg->ed->corners = ptableval(&pd_corners_HTM, arg->cube);
1300 UPDATECHECKSTOP(ret, arg->ed->corners, target);
1301
1302 /* Normal probing */
1303 arg->ed->normal_ud = ptableval(pd, arg->cube);
1304 UPDATECHECKSTOP(ret, arg->ed->normal_ud, target);
1305 aux = apply_trans(fd, arg->cube);
1306 arg->ed->normal_fb = ptableval(pd, aux);
1307 UPDATECHECKSTOP(ret, arg->ed->normal_fb, target);
1308 aux = apply_trans(rf, arg->cube);
1309 arg->ed->normal_rl = ptableval(pd, aux);
1310 UPDATECHECKSTOP(ret, arg->ed->normal_rl, target);
1311
1312 if (ret == 0)
1313 return arg->step->is_done(arg->cube) ? 0 : 1;
1314
1315 /* Michel de Bondt's trick*/
1316 if (arg->ed->normal_ud == arg->ed->normal_fb &&
1317 arg->ed->normal_fb == arg->ed->normal_rl) {
1318 UPDATECHECKSTOP(ret, arg->ed->normal_ud + 1, target);
1319 }
1320
1321 /* Inverse probing */
1322 aux = arg->inverse = inverse_cube(arg->cube);
1323 if (!((1<<arg->last1) & udmask) || (arg->ed->inverse_ud == -1)) {
1324 arg->ed->inverse_ud = ptableval(pd, aux);
1325 }
1326 UPDATECHECKSTOP(ret, arg->ed->inverse_ud, target);
1327 if (!((1<<arg->last1) & fbmask) || (arg->ed->inverse_fb == -1)) {
1328 aux = apply_trans(fd, arg->inverse);
1329 arg->ed->inverse_fb = ptableval(pd, aux);
1330 }
1331 UPDATECHECKSTOP(ret, arg->ed->inverse_fb, target);
1332 if (!((1<<arg->last1) & rlmask) || (arg->ed->inverse_rl == -1)) {
1333 aux = apply_trans(rf, arg->inverse);
1334 arg->ed->inverse_rl = ptableval(pd, aux);
1335 }
1336 UPDATECHECKSTOP(ret, arg->ed->inverse_rl, target);
1337
1338 /* Michel de Bondt's trick*/
1339 if (arg->ed->inverse_ud == arg->ed->inverse_fb &&
1340 arg->ed->inverse_fb == arg->ed->inverse_rl) {
1341 UPDATECHECKSTOP(ret, arg->ed->inverse_ud + 1, target);
1342 }
1343
1344 /* nxopt trick */
1345 if (arg->ed->normal_ud == target)
1346 arg->badmovesinv |= udmask;
1347 if (arg->ed->normal_fb == target)
1348 arg->badmovesinv |= fbmask;
1349 if (arg->ed->normal_rl == target)
1350 arg->badmovesinv |= rlmask;
1351
1352 if (arg->ed->inverse_ud == target)
1353 arg->badmoves |= udmask;
1354 if (arg->ed->inverse_fb == target)
1355 arg->badmoves |= fbmask;
1356 if (arg->ed->inverse_rl == target)
1357 arg->badmoves |= rlmask;
1358
1359 return arg->ed->oldret = ret;
1360}
1361
1362
1363static bool
1364always_valid(Alg *alg)
104{ 1365{
105 /* TODO (check_drud(cube) and coord_htr_drud == 0) */
106 return true; 1366 return true;
107} 1367}
108 1368
109Alg * 1369static bool
110validate_singlecw_ending(Alg *alg) 1370validate_singlecw_ending(Alg *alg)
111{ 1371{
112 int i; 1372 int i;
113 bool nor, inv; 1373 bool nor, inv;
114 Alg *ret;
115 Move l2 = NULLMOVE, l1 = NULLMOVE, l2i = NULLMOVE, l1i = NULLMOVE; 1374 Move l2 = NULLMOVE, l1 = NULLMOVE, l2i = NULLMOVE, l1i = NULLMOVE;
116 1375
117 for (i = 0; i < alg->len; i++) { 1376 for (i = 0; i < alg->len; i++) {
@@ -127,51 +1386,96 @@ validate_singlecw_ending(Alg *alg)
127 nor = l1 ==base_move(l1) && (!commute(l1, l2) ||l2 ==base_move(l2)); 1386 nor = l1 ==base_move(l1) && (!commute(l1, l2) ||l2 ==base_move(l2));
128 inv = l1i==base_move(l1i) && (!commute(l1i,l2i)||l2i==base_move(l2i)); 1387 inv = l1i==base_move(l1i) && (!commute(l1i,l2i)||l2i==base_move(l2i));
129 1388
130 if (nor && inv) { 1389 return nor && inv;
131 ret = new_alg(""); 1390}
132 copy_alg(alg, ret);
133 } else {
134 ret = NULL;
135 }
136 1391
137 return ret; 1392/* Pre-transformation detectors **********************************************/
1393
1394static int
1395detect_pretrans_eofb(Cube cube, Trans *ret)
1396{
1397 int i, n;
1398 static Trans tt[3] = {uf, ur, fd};
1399
1400 for (i = 0, n = 0; i < 3; i++)
1401 if (check_eofb(apply_trans(tt[i], cube)))
1402 ret[n++] = tt[i];
1403
1404 return n;
1405}
1406
1407static int
1408detect_pretrans_drud(Cube cube, Trans *ret)
1409{
1410 int i, n;
1411 static Trans tt[3] = {uf, fr, rd};
1412
1413 for (i = 0, n = 0; i < 3; i++)
1414 if (check_drud(apply_trans(tt[i], cube)))
1415 ret[n++] = tt[i];
1416
1417 return n;
1418}
1419
1420static int
1421detect_pretrans_void_3axis(Cube cube, Trans *ret)
1422{
1423 ret[0] = uf;
1424 ret[1] = fr;
1425 ret[2] = rd;
1426
1427 return 3;
138} 1428}
139 1429
140/* Public functions **********************************************************/ 1430/* Public functions **********************************************************/
141 1431
142/*
143void 1432void
144compute_ind(Step *s, Cube *cube, Movable *ind) 1433copy_estimatedata(EstimateData *src, EstimateData *dst)
145{ 1434{
146 int i; 1435 dst->corners = src->corners;
147 Cube mvd; 1436 dst->normal_ud = src->normal_ud;
148 Trans t, tt; 1437 dst->normal_fb = src->normal_fb;
1438 dst->normal_rl = src->normal_rl;
1439 dst->inverse_ud = src->inverse_ud;
1440 dst->inverse_fb = src->inverse_fb;
1441 dst->inverse_rl = src->inverse_rl;
1442 dst->oldret = src->oldret;
1443}
149 1444
150 for (i = 0; i < s->n_coord; i++) { 1445void
151 t = s->coord_trans[i]; 1446invert_estimatedata(EstimateData *ed)
152 copy_cube(cube, &mvd); 1447{
153 apply_trans(t, &mvd); 1448 swap(&(ed->normal_ud), &(ed->inverse_ud));
1449 swap(&(ed->normal_fb), &(ed->inverse_fb));
1450 swap(&(ed->normal_rl), &(ed->inverse_rl));
1451}
154 1452
155 ind[i].val = index_coord(s->coord[i], &mvd, &tt); 1453void
156 ind[i].t = transform_trans(tt, t); 1454reset_estimatedata(EstimateData *ed)
157 } 1455{
1456 ed->corners = -1;
1457 ed->normal_ud = -1;
1458 ed->normal_fb = -1;
1459 ed->normal_rl = -1;
1460 ed->inverse_ud = -1;
1461 ed->inverse_fb = -1;
1462 ed->inverse_rl = -1;
1463 ed->oldret = -1;
158} 1464}
159*/
160 1465
161void 1466void
162prepare_cs(ChoiceStep *cs, SolveOptions *opts) 1467prepare_step(Step *step, SolveOptions *opts)
163{ 1468{
164 int i, j; 1469 int i;
165 Step *s;
166 1470
167 for (i = 0; cs->step[i] != NULL; i++) { 1471 if (step->final && opts->can_niss) {
168 s = cs->step[i]; 1472 opts->can_niss = false;
169 for (j = 0; j < s->n_coord; j++) { 1473 fprintf(stderr, "Step is final, NISS not used (-n ignored)\n");
170 s->pd[j] = malloc(sizeof(PruneData)); 1474 }
171 s->pd[j]->moveset = s->moveset; 1475
172 s->pd[j]->coord = s->coord[j]; 1476 for (i = 0; i < step->ntables; i++) {
173 s->pd[j]->compact = s->pd_compact[j]; 1477 genptable(step->tables[i], opts->nthreads);
174 s->pd[j] = genptable(s->pd[j], opts->nthreads); 1478 if (step->tables[i]->compact)
175 } 1479 genptable(step->tables[i]->fallback, opts->nthreads);
176 } 1480 }
177} 1481}
diff --git a/src/steps.h b/src/steps.h
index 206f8b4..da5c041 100644
--- a/src/steps.h
+++ b/src/steps.h
@@ -2,243 +2,16 @@
2#define STEPS_H 2#define STEPS_H
3 3
4#include "pruning.h" 4#include "pruning.h"
5#include "movesets.h"
6 5
7bool check_centers(Cube *cube); 6extern Step * steps[];
8bool check_coud_HTM(Cube *cube);
9bool check_coud_URF(Cube *cube);
10bool check_cp_HTM(Cube *cube);
11bool check_corners_HTM(Cube *cube);
12bool check_corners_URF(Cube *cube);
13bool check_cornershtr(Cube *cube);
14bool check_eofb(Cube *cube);
15bool check_drud(Cube *cube);
16bool check_htr(Cube *cube);
17/*void compute_ind(Step *a, Cube *cube, Movable *ind);*/
18void prepare_cs(ChoiceStep *cs, SolveOptions *opts);
19bool always_valid(Alg *alg);
20Alg * validate_singlecw_ending(Alg *alg);
21 7
22#ifndef STEPS_C 8/* Two steps used directly by two-phase solver */
9extern Step drany_HTM;
10extern Step dranyfin_DR;
23 11
24extern char check_centers_msg[100]; 12void copy_estimatedata(EstimateData *s, EstimateData *d);
25extern char check_eo_msg[100]; 13void invert_estimatedata(EstimateData *ed);
26extern char check_dr_msg[100]; 14void reset_estimatedata(EstimateData *ed);
27extern char check_htr_msg[100]; 15void prepare_step(Step *step, SolveOptions *opts);
28extern char check_drany_msg[100];
29
30extern Step step_eofb_HTM;
31extern Step step_drud_HTM;
32extern Step step_drfin_drud;
33
34extern ChoiceStep optimal_HTM;
35extern ChoiceStep eoany_HTM;
36extern ChoiceStep eofb_HTM;
37extern ChoiceStep eorl_HTM;
38extern ChoiceStep eoud_HTM;
39extern ChoiceStep drany_HTM;
40extern ChoiceStep drud_HTM;
41extern ChoiceStep drrl_HTM;
42extern ChoiceStep drfb_HTM;
43extern ChoiceStep dranyfin_DR;
44extern ChoiceStep drudfin_drud;
45extern ChoiceStep drrlfin_drrl;
46extern ChoiceStep drfbfin_drfb;
47
48extern ChoiceStep *csteps[];
49
50#else
51
52char check_centers_msg[100] = "cube must be oriented (centers solved)";
53char check_eo_msg[100] = "EO must be solved on given axis";
54char check_dr_msg[100] = "DR must be solved on given axis";
55char check_htr_msg[100] = "HTR must be solved";
56char check_drany_msg[100] = "DR must be solved on at least one axis";
57
58/* Optimal after EO ******************/
59/* TODO: eofin_eo (generic), eofbfin_eofb, eorlfin_eorl, eoudfin_eoud */
60
61/* EO steps **************************/
62/* TODO: eoany_HTM (generic), eofb_HTM, eorl_HTM, eoud_HTM */
63
64Step
65step_eofb_HTM = {
66 .ready = check_centers,
67 .final = false,
68 .moveset = &moveset_HTM,
69 .n_coord = 1,
70 .coord = {&coord_eofb},
71 .coord_trans = {uf},
72 .is_valid = validate_singlecw_ending,
73};
74ChoiceStep
75eoany_HTM = {
76 .shortname = "eo",
77 .name = "EO on any axis",
78 .step = {&step_eofb_HTM, &step_eofb_HTM, &step_eofb_HTM, NULL},
79 .t = {uf, ur, fd},
80 .ready_msg = check_centers_msg,
81};
82ChoiceStep
83eofb_HTM = {
84 .shortname = "eofb",
85 .name = "EO on F/B",
86 .step = {&step_eofb_HTM, NULL},
87 .t = {uf},
88 .ready_msg = check_centers_msg,
89};
90ChoiceStep
91eorl_HTM = {
92 .shortname = "eorl",
93 .name = "EO on R/L",
94 .step = {&step_eofb_HTM, NULL},
95 .t = {ur},
96 .ready_msg = check_centers_msg,
97};
98ChoiceStep
99eoud_HTM = {
100 .shortname = "eoud",
101 .name = "EO on U/D",
102 .step = {&step_eofb_HTM, NULL},
103 .t = {fd},
104 .ready_msg = check_centers_msg,
105};
106
107/* CO steps **************************/
108/* TODO: coany_HTM (generic), cofb_HTM, corl_HTM, coud_HTM */
109/* TODO: coany_URF (generic), cofb_URF, corl_URF, coud_URF */
110
111/* Misc corner steps *****************/
112/* TODO: cornershtr_HTM, cornershtr_URF, corners_HTM, corners_URF */
113/* TODO (new): corners_drud */
114
115/* DR steps **************************/
116/* TODO: dr_eo (generic) */
117/* TODO: dr_eofb (generic), dr_eorl (generic), dr_eoud (generic) */
118/* TODO: drud_eofb, drrl_eofb, drud_eorl, drfb_eorl, drrl_eoud, drfb_eoud */
119
120Step
121step_drud_HTM = {
122 .ready = check_centers,
123 .final = false,
124 .moveset = &moveset_HTM,
125 .n_coord = 1,
126 .coord = {&coord_drud_sym16},
127 .coord_trans = {uf},
128 .is_valid = validate_singlecw_ending,
129};
130ChoiceStep
131drany_HTM = {
132 .shortname = "dr",
133 .name = "DR on any axis",
134 .step = {&step_drud_HTM, &step_drud_HTM, &step_drud_HTM, NULL},
135 .t = {uf, rf, fd},
136 .ready_msg = check_centers_msg,
137};
138ChoiceStep
139drud_HTM = {
140 .shortname = "drud",
141 .name = "DR on U/D",
142 .step = {&step_drud_HTM, NULL},
143 .t = {uf},
144 .ready_msg = check_centers_msg,
145};
146ChoiceStep
147drrl_HTM = {
148 .shortname = "drrl",
149 .name = "DR on R/L",
150 .step = {&step_drud_HTM, NULL},
151 .t = {rf},
152 .ready_msg = check_centers_msg,
153};
154ChoiceStep
155drfb_HTM = {
156 .shortname = "drfb",
157 .name = "DR on F/B",
158 .step = {&step_drud_HTM, NULL},
159 .t = {fd},
160 .ready_msg = check_centers_msg,
161};
162
163/* DR finish steps */
164Step
165step_drfin_drud = {
166 .ready = check_drud,
167 .final = true,
168 .moveset = &moveset_drud,
169 .n_coord = 1,
170 .coord = {&coord_drudfin_noE_sym16}, /* TODO: maybe no noE */
171 .coord_trans = {uf},
172 .is_valid = NULL,
173};
174ChoiceStep
175dranyfin_DR = {
176 .shortname = "drfin",
177 .name = "DR finish on any axis without breaking DR",
178 .step = {&step_drfin_drud, &step_drfin_drud,
179 &step_drfin_drud, NULL},
180 .t = {uf, rf, fd},
181 .ready_msg = check_dr_msg,
182};
183ChoiceStep
184drudfin_drud = {
185 .shortname = "drudfin",
186 .name = "DR finis on U/D without breaking DR",
187 .step = {&step_drfin_drud, NULL},
188 .t = {uf},
189 .ready_msg = check_dr_msg,
190};
191ChoiceStep
192drrlfin_drrl = {
193 .shortname = "drrlfin",
194 .name = "DR finish on R/L without breaking DR",
195 .step = {&step_drfin_drud, NULL},
196 .t = {rf},
197 .ready_msg = check_dr_msg,
198};
199ChoiceStep
200drfbfin_drfb = {
201 .shortname = "drfbfin",
202 .name = "DR finish on F/B without breaking DR",
203 .step = {&step_drfin_drud, NULL},
204 .t = {fd},
205 .ready_msg = check_dr_msg,
206};
207
208/* HTR from DR */
209/* TODO: htr_any (generic), htr_drud, htr_drrl, htr_drfb */
210
211/* HTR finish */
212/* TODO: htrfin_htr */
213
214ChoiceStep *csteps[] = {
215/* TODO: re-implement optimal
216 &optimal_HTM,
217*/
218
219 &eoany_HTM, &eofb_HTM, &eorl_HTM, &eoud_HTM,
220 &drany_HTM, &drud_HTM, &drrl_HTM, &drfb_HTM,
221 &dranyfin_DR, &drudfin_drud, &drrlfin_drrl, &drfbfin_drfb,
222
223NULL
224/* TODO:
225 &optimal_light_HTM,
226
227 &eofin_eo, &eofbfin_eofb, &eorlfin_eorl, &eoudfin_eoud,
228 &coany_HTM, &coud_HTM, &corl_HTM, &cofb_HTM,
229 &coany_URF, &coud_URF, &corl_URF, &cofb_URF,
230 &dr_eo, &dr_eofb, &dr_eorl, &dr_eoud,
231 &drud_eofb, &drrl_eofb,
232 &drud_eorl, &drfb_eorl,
233 &drfb_eoud, &drrl_eoud,
234 &htr_any, &htr_drud, &htr_drrl, &htr_drfb,
235 &htrfin_htr,
236 &cornershtr_HTM, &cornershtr_URF, &corners_HTM, &corners_URF,
237 NULL
238*/
239
240};
241
242#endif
243 16
244#endif 17#endif
diff --git a/src/symcoord.c b/src/symcoord.c
new file mode 100644
index 0000000..20d7c28
--- /dev/null
+++ b/src/symcoord.c
@@ -0,0 +1,687 @@
1#include "symcoord.h"
2
3/* These constants have been computed generating the respective SymData */
4#define CLASSES_CP_16 2768
5#define CLASSES_EOFBEPOS_16 64430
6
7static uint64_t index_cp_sym16(Cube cube);
8static uint64_t index_eofbepos_sym16(Cube cube);
9static uint64_t index_drud_sym16(Cube cube);
10static uint64_t index_drudfin_noE_sym16(Cube cube);
11static uint64_t index_nxopt31(Cube cube);
12
13static uint64_t move_cp_sym16(Move m, uint64_t ind);
14static uint64_t move_eofbepos_sym16(Move m, uint64_t ind);
15static uint64_t move_drud_sym16(Move m, uint64_t ind);
16static uint64_t move_drudfin_noE_sym16(Move m, uint64_t ind);
17static uint64_t move_nxopt31(Move m, uint64_t ind);
18
19static int tfind_from_mask(uint64_t mask, Trans *ret);
20static int tfind_drud_sym16(uint64_t ind, Trans *ret);
21static int tfind_drudfin_noE_sym16(uint64_t ind, Trans *ret);
22static int tfind_nxopt31(uint64_t ind, Trans *ret);
23
24static uint64_t transform_cp(Trans t, uint64_t ind);
25static uint64_t transform_eofbepos(Trans t, uint64_t ind);
26static uint64_t transform_drud_sym16(Trans t, uint64_t ind);
27static uint64_t transform_drudfin_noE_sym16(Trans t, uint64_t ind);
28static uint64_t transform_nxopt31(Trans t, uint64_t ind);
29
30static void gensym(SymData *sd);
31static void init_symc_moves();
32static void init_symc_trans();
33static bool read_symdata_file(SymData *sd);
34static bool read_symc_moves_file();
35static bool read_symc_trans_file();
36static bool write_symdata_file(SymData *sd);
37static bool write_symc_moves_file();
38static bool write_symc_trans_file();
39
40/* Some tables ***************************************************************/
41
42static uint64_t move_cp_16[NMOVES][CLASSES_CP_16];
43static uint64_t move_eofbepos_16[NMOVES][CLASSES_EOFBEPOS_16];
44
45static int trans_eofbepos[NTRANS][POW2TO11*BINOM12ON4];
46static int trans_epud[NTRANS][FACTORIAL8];
47static int trans_cpud_separate[NTRANS][BINOM8ON4];
48
49static Trans ttrep_move_cp_16[NMOVES][CLASSES_CP_16];
50static Trans ttrep_move_eofbepos_16[NMOVES][CLASSES_EOFBEPOS_16];
51
52
53/* Transformation groups and symmetry data ***********************************/
54
55static Trans
56trans_group_udfix[16] = {
57 uf, ur, ub, ul,
58 df, dr, db, dl,
59 uf_mirror, ur_mirror, ub_mirror, ul_mirror,
60 df_mirror, dr_mirror, db_mirror, dl_mirror,
61};
62
63static SymData
64sd_cp_16 = {
65 .filename = "sd_cp_16_new",
66 .coord = &coord_cp,
67 .sym_coord = &coord_cp_sym16,
68 .ntrans = 16,
69 .trans = trans_group_udfix,
70 .transform = transform_cp,
71};
72
73static SymData
74sd_eofbepos_16 = {
75 .filename = "sd_eofbepos_16_new",
76 .coord = &coord_eofbepos,
77 .sym_coord = &coord_eofbepos_sym16,
78 .ntrans = 16,
79 .trans = trans_group_udfix,
80 .transform = transform_eofbepos,
81};
82
83SymData * all_sd[] = {
84 &sd_cp_16,
85 &sd_eofbepos_16,
86 NULL
87};
88
89
90/* Coordinates and their implementation **************************************/
91
92Coordinate
93coord_eofbepos_sym16 = {
94 .index = index_eofbepos_sym16,
95 .move = move_eofbepos_sym16,
96};
97
98Coordinate
99coord_cp_sym16 = {
100 .index = index_cp_sym16,
101 .move = move_cp_sym16,
102};
103
104Coordinate
105coord_drud_sym16 = {
106 .index = index_drud_sym16,
107 .move = move_drud_sym16,
108 .max = POW3TO7 * CLASSES_EOFBEPOS_16,
109 .base = &coord_eofbepos_sym16,
110 .transform = transform_drud_sym16,
111 .tfind = tfind_drud_sym16,
112};
113
114Coordinate
115coord_drudfin_noE_sym16 = {
116 .index = index_drudfin_noE_sym16,
117 .move = move_drudfin_noE_sym16,
118 .max = FACTORIAL8 * CLASSES_CP_16,
119 .base = &coord_cp_sym16,
120 .transform = transform_drudfin_noE_sym16,
121 .tfind = tfind_drudfin_noE_sym16,
122};
123
124Coordinate
125coord_nxopt31 = {
126 .index = index_nxopt31,
127 .move = move_nxopt31,
128 .max = POW3TO7 * BINOM8ON4 * CLASSES_EOFBEPOS_16,
129 .base = &coord_eofbepos_sym16,
130 .transform = transform_nxopt31,
131 .tfind = tfind_nxopt31,
132};
133
134/* Functions *****************************************************************/
135
136static uint64_t
137index_cp_sym16(Cube cube)
138{
139 return sd_cp_16.class[coord_cp.index(cube)];
140}
141
142static uint64_t
143index_drud_sym16(Cube cube)
144{
145 Trans t;
146
147 t = sd_eofbepos_16.transtorep[coord_eofbepos.index(cube)];
148
149 return index_eofbepos_sym16(cube) * POW3TO7 + co_ttable[t][cube.coud];
150}
151
152static uint64_t
153index_drudfin_noE_sym16(Cube cube)
154{
155 Trans t;
156 Cube c;
157
158 t = sd_cp_16.transtorep[coord_cp.index(cube)];
159 c = apply_trans(t, cube);
160
161 /* TODO: add transform to coord_epud to make this faster */
162 return index_cp_sym16(c) * FACTORIAL8 + coord_epud.index(c);
163}
164
165static uint64_t
166index_eofbepos_sym16(Cube cube)
167{
168 return sd_eofbepos_16.class[coord_eofbepos.index(cube)];
169}
170
171static uint64_t
172index_nxopt31(Cube cube)
173{
174 Trans t;
175 uint64_t a;
176 int coud, cp;
177
178 t = sd_eofbepos_16.transtorep[coord_eofbepos.index(cube)];
179 coud = co_ttable[t][cube.coud];
180 cp = cp_ttable[t][cube.cp];
181 a = (index_eofbepos_sym16(cube)*POW3TO7) + coud;
182
183 return a * BINOM8ON4 + coord_cpud_separate.index((Cube){.cp = cp});
184}
185
186static uint64_t
187move_cp_sym16(Move m, uint64_t ind)
188{
189 return move_cp_16[m][ind];
190}
191
192static uint64_t
193move_eofbepos_sym16(Move m, uint64_t ind)
194{
195 return move_eofbepos_16[m][ind];
196}
197
198static uint64_t
199move_drud_sym16(Move m, uint64_t ind)
200{
201 uint64_t coud, eofbepos;
202 Trans ttr;
203
204 eofbepos = move_eofbepos_16[m][ind / POW3TO7];
205 ttr = ttrep_move_eofbepos_16[m][ind / POW3TO7];
206 coud = coud_mtable[m][ind % POW3TO7];
207 coud = co_ttable[ttr][coud]; /* Source is always coud */
208
209 return eofbepos * POW3TO7 + coud;
210}
211
212static uint64_t
213move_drudfin_noE_sym16(Move m, uint64_t ind)
214{
215 uint64_t cp, epud;
216 Trans ttr;
217
218 cp = move_cp_16[m][ind / FACTORIAL8];
219 ttr = ttrep_move_cp_16[m][ind / FACTORIAL8];
220 epud = coord_epud.move(m, ind % FACTORIAL8);
221 epud = trans_epud[ttr][epud];
222
223 return cp * FACTORIAL8 + epud;
224}
225
226static uint64_t
227move_nxopt31(Move m, uint64_t ind)
228{
229 uint64_t eofbepos, cpsep, coud;
230 Trans ttr;
231
232 eofbepos = ind / (POW3TO7 * BINOM8ON4);
233 coud = (ind / BINOM8ON4) % POW3TO7;
234 cpsep = ind % BINOM8ON4;
235
236 ttr = ttrep_move_eofbepos_16[m][eofbepos];
237 eofbepos = move_eofbepos_16[m][eofbepos];
238 coud = coud_mtable[m][coud];
239 coud = co_ttable[ttr][coud]; /* Source is always coud */
240 cpsep = coord_cpud_separate.move(m, cpsep);
241 cpsep = trans_cpud_separate[ttr][cpsep];
242
243 return (eofbepos * POW3TO7 + coud) * BINOM8ON4 + cpsep;
244}
245
246static uint64_t
247transform_cp(Trans t, uint64_t ind)
248{
249 return cp_ttable[t][ind];
250}
251
252static uint64_t
253transform_eofbepos(Trans t, uint64_t ind)
254{
255 return trans_eofbepos[t][ind];
256}
257
258static uint64_t
259transform_drud_sym16(Trans t, uint64_t ind)
260{
261 uint64_t coud, eofbepos;
262
263 eofbepos = ind / POW3TO7; /* Assum trans fixes eofbepos */
264 coud = co_ttable[t][ind % POW3TO7]; /* Source is always coud */
265
266 return eofbepos * POW3TO7 + coud;
267}
268
269static uint64_t
270transform_drudfin_noE_sym16(Trans t, uint64_t ind)
271{
272 uint64_t cp, epud;
273
274 cp = ind / FACTORIAL8; /* Assume trans fixes cp */
275 epud = trans_epud[t][ind % FACTORIAL8];
276
277 return cp * FACTORIAL8 + epud;
278}
279
280static uint64_t
281transform_nxopt31(Trans t, uint64_t ind)
282{
283 uint64_t eofbepos, cpsep, coud;
284
285 eofbepos = ind / (POW3TO7 * BINOM8ON4);
286 coud = (ind / BINOM8ON4) % POW3TO7;
287 cpsep = ind % BINOM8ON4;
288
289 coud = co_ttable[t][coud]; /* Source is always coud */
290 cpsep = trans_cpud_separate[t][cpsep];
291
292 return (eofbepos * POW3TO7 + coud) * BINOM8ON4 + cpsep;
293}
294
295static int
296tfind_from_mask(uint64_t mask, Trans *ret)
297{
298 Trans t;
299 int i = 0;
300
301 for (t = uf; t < NTRANS; t++)
302 if (((uint64_t)1 << t) & mask)
303 ret[i++] = t;
304
305 return i;
306}
307
308static int
309tfind_drud_sym16(uint64_t ind, Trans *ret)
310{
311 uint64_t mask = sd_eofbepos_16.selfsim[ind / POW3TO7];
312
313 return tfind_from_mask(mask, ret);
314}
315
316static int
317tfind_drudfin_noE_sym16(uint64_t ind, Trans *ret)
318{
319 uint64_t mask = sd_cp_16.selfsim[ind / FACTORIAL8];
320
321 return tfind_from_mask(mask, ret);
322}
323
324static int
325tfind_nxopt31(uint64_t ind, Trans *ret)
326{
327 uint64_t mask = sd_eofbepos_16.selfsim[ind / (POW3TO7 * BINOM8ON4)];
328
329 return tfind_from_mask(mask, ret);
330}
331
332/* Other functions ***********************************************************/
333
334void
335free_sd(SymData *sd)
336{
337 if (sd->generated) {
338 free(sd->class);
339 free(sd->unsym);
340 free(sd->transtorep);
341 }
342
343 sd->generated = false;
344}
345
346static void
347gensym(SymData *sd)
348{
349 uint64_t i, in, nreps = 0;
350 Trans t;
351 int j;
352
353 if (sd->generated)
354 return;
355
356 sd->class = malloc(sd->coord->max * sizeof(uint64_t));
357 sd->unsym = malloc(sd->coord->max * sizeof(uint64_t));
358 sd->transtorep = malloc(sd->coord->max * sizeof(Trans));
359 sd->selfsim = malloc(sd->coord->max * sizeof(uint64_t));
360
361 if (read_symdata_file(sd)) {
362 sd->generated = true;
363 return;
364 }
365
366 fprintf(stderr, "Cannot load %s, generating it\n", sd->filename);
367
368 for (i = 0; i < sd->coord->max; i++)
369 sd->class[i] = sd->coord->max + 1;
370
371 for (i = 0; i < sd->coord->max; i++) {
372 if (sd->class[i] == sd->coord->max + 1) {
373 sd->unsym[nreps] = i;
374 sd->transtorep[i] = uf;
375 sd->selfsim[nreps] = (uint64_t)0;
376 for (j = 0; j < sd->ntrans; j++) {
377 t = sd->trans[j];
378 in = sd->transform(t, i);
379 sd->class[in] = nreps;
380 if (in == i)
381 sd->selfsim[nreps] |=
382 ((uint64_t)1 << t);
383 else
384 sd->transtorep[in] = inverse_trans(t);
385 }
386 nreps++;
387 }
388 }
389
390 sd->sym_coord->max = nreps;
391 sd->unsym = realloc(sd->unsym, nreps * sizeof(uint64_t));
392 sd->selfsim = realloc(sd->selfsim, nreps * sizeof(uint64_t));
393 sd->generated = true;
394
395 fprintf(stderr, "Found %" PRIu64 " classes\n", nreps);
396
397 if (!write_symdata_file(sd))
398 fprintf(stderr, "Error writing SymData file\n");
399
400 return;
401}
402
403static bool
404read_symdata_file(SymData *sd)
405{
406 init_env();
407
408 FILE *f;
409 char fname[strlen(tabledir)+100];
410 uint64_t n = sd->coord->max, *sn = &sd->sym_coord->max;
411 bool r = true;
412
413 strcpy(fname, tabledir);
414 strcat(fname, "/");
415 strcat(fname, sd->filename);
416
417 if ((f = fopen(fname, "rb")) == NULL)
418 return false;
419
420 r = r && fread(&sd->sym_coord->max, sizeof(uint64_t), 1, f) == 1;
421 r = r && fread(sd->unsym, sizeof(uint64_t), *sn, f) == *sn;
422 r = r && fread(sd->selfsim, sizeof(uint64_t), *sn, f) == *sn;
423 r = r && fread(sd->class, sizeof(uint64_t), n, f) == n;
424 r = r && fread(sd->transtorep, sizeof(Trans), n, f) == n;
425
426 fclose(f);
427 return r;
428}
429
430static bool
431read_symc_moves_file()
432{
433 init_env();
434
435 Move m;
436 bool r = true;
437 FILE *f;
438 char fname[strlen(tabledir)+100];
439
440 strcpy(fname, tabledir);
441 strcat(fname, "/symc_moves");
442
443 if ((f = fopen(fname, "rb")) == NULL)
444 return false;
445
446 for (m = 0; m < NMOVES; m++) {
447 r = r && fread(move_cp_16[m], sizeof(uint64_t),
448 CLASSES_CP_16, f) == CLASSES_CP_16;
449 r = r && fread(move_eofbepos_16[m], sizeof(uint64_t),
450 CLASSES_EOFBEPOS_16, f) == CLASSES_EOFBEPOS_16;
451
452 r = r && fread(ttrep_move_cp_16[m], sizeof(Trans),
453 CLASSES_CP_16, f) == CLASSES_CP_16;
454 r = r && fread(ttrep_move_eofbepos_16[m], sizeof(Trans),
455 CLASSES_EOFBEPOS_16, f) == CLASSES_EOFBEPOS_16;
456 }
457
458 fclose(f);
459 return r;
460}
461
462static bool
463read_symc_trans_file()
464{
465 init_env();
466
467 Trans t;
468 bool r = true;
469 FILE *f;
470 char fname[strlen(tabledir)+100];
471
472 strcpy(fname, tabledir);
473 strcat(fname, "/symc_trans");
474
475 if ((f = fopen(fname, "rb")) == NULL)
476 return false;
477
478 for (t = 0; t < NTRANS; t++) {
479 r = r && fread(trans_eofbepos[t], sizeof(int),
480 POW2TO11*BINOM12ON4, f) == POW2TO11*BINOM12ON4;
481 r = r && fread(trans_epud[t], sizeof(int),
482 FACTORIAL8, f) == FACTORIAL8;
483 r = r && fread(trans_cpud_separate[t], sizeof(int),
484 BINOM8ON4, f) == BINOM8ON4;
485 }
486
487 fclose(f);
488 return r;
489}
490
491static bool
492write_symdata_file(SymData *sd)
493{
494 init_env();
495
496 FILE *f;
497 char fname[strlen(tabledir)+100];
498 uint64_t n = sd->coord->max, *sn = &sd->sym_coord->max;
499 bool r = true;
500
501 strcpy(fname, tabledir);
502 strcat(fname, "/");
503 strcat(fname, sd->filename);
504
505 if ((f = fopen(fname, "wb")) == NULL)
506 return false;
507
508 r = r && fwrite(&sd->sym_coord->max, sizeof(uint64_t), 1, f) == 1;
509 r = r && fwrite(sd->unsym, sizeof(uint64_t), *sn, f) == *sn;
510 r = r && fwrite(sd->selfsim, sizeof(uint64_t), *sn, f) == *sn;
511 r = r && fwrite(sd->class, sizeof(uint64_t), n, f) == n;
512 r = r && fwrite(sd->transtorep, sizeof(Trans), n, f) == n;
513
514 fclose(f);
515 return r;
516}
517
518static bool
519write_symc_moves_file()
520{
521 init_env();
522
523 Move m;
524 bool r = true;
525 FILE *f;
526 char fname[strlen(tabledir)+100];
527
528 strcpy(fname, tabledir);
529 strcat(fname, "/symc_moves");
530
531 if ((f = fopen(fname, "wb")) == NULL)
532 return false;
533
534 for (m = 0; m < NMOVES; m++) {
535 r = r && fwrite(move_cp_16[m], sizeof(uint64_t),
536 CLASSES_CP_16, f) == CLASSES_CP_16;
537 r = r && fwrite(move_eofbepos_16[m], sizeof(uint64_t),
538 CLASSES_EOFBEPOS_16, f) == CLASSES_EOFBEPOS_16;
539
540 r = r && fwrite(ttrep_move_cp_16[m], sizeof(Trans),
541 CLASSES_CP_16, f) == CLASSES_CP_16;
542 r = r && fwrite(ttrep_move_eofbepos_16[m], sizeof(Trans),
543 CLASSES_EOFBEPOS_16, f) == CLASSES_EOFBEPOS_16;
544 }
545
546 fclose(f);
547 return r;
548}
549
550static bool
551write_symc_trans_file()
552{
553 init_env();
554
555 Trans t;
556 bool r = true;
557 FILE *f;
558 char fname[strlen(tabledir)+100];
559
560 strcpy(fname, tabledir);
561 strcat(fname, "/symc_trans");
562
563 if ((f = fopen(fname, "wb")) == NULL)
564 return false;
565
566 for (t = 0; t < NTRANS; t++) {
567 r = r && fwrite(trans_eofbepos[t], sizeof(int),
568 POW2TO11*BINOM12ON4, f) == POW2TO11*BINOM12ON4;
569 r = r && fwrite(trans_epud[t], sizeof(int),
570 FACTORIAL8, f) == FACTORIAL8;
571 r = r && fwrite(trans_cpud_separate[t], sizeof(int),
572 BINOM8ON4, f) == BINOM8ON4;
573 }
574
575 fclose(f);
576 return r;
577}
578
579static void
580init_symc_moves()
581{
582 uint64_t i, ii, coo;
583 Move j;
584
585 if (read_symc_moves_file())
586 return;
587
588 for (i = 0; i < CLASSES_CP_16; i++) {
589 ii = sd_cp_16.unsym[i];
590 for (j = 0; j < NMOVES; j++) {
591 coo = sd_cp_16.coord->move(j, ii);
592 move_cp_16[j][i] = sd_cp_16.class[coo];
593 ttrep_move_cp_16[j][i] = sd_cp_16.transtorep[coo];
594 }
595 }
596
597 for (i = 0; i < CLASSES_EOFBEPOS_16; i++) {
598 ii = sd_eofbepos_16.unsym[i];
599 for (j = 0; j < NMOVES; j++) {
600 coo = sd_eofbepos_16.coord->move(j, ii);
601 move_eofbepos_16[j][i] = sd_eofbepos_16.class[coo];
602 ttrep_move_eofbepos_16[j][i] =
603 sd_eofbepos_16.transtorep[coo];
604 }
605 }
606
607 if (!write_symc_moves_file())
608 fprintf(stderr, "Error writing SymMoves file\n");
609}
610
611void
612init_symc_trans()
613{
614 uint64_t i;
615 int j, cp;
616 int epe[4] = {FR, FL, BL, BR};
617 int a[12] = { [8] = 8, [9] = 9, [10] = 10, [11] = 11 };
618 Cube c;
619 CubeArray *arr, *aux;
620 Trans t;
621
622 if (read_symc_trans_file())
623 return;
624
625 for (i = 0; i < POW2TO11*BINOM12ON4; i++) {
626 for (j = 0; j < 16; j++) {
627 t = trans_group_udfix[j];
628
629 arr = new_cubearray((Cube){0}, pf_edges);
630 int_to_sum_zero_array(i % POW2TO11, 2, 12, arr->eofb);
631 epos_to_compatible_ep((i / POW2TO11)*24, arr->ep, epe);
632 fix_eorleoud(arr);
633 c = arrays_to_cube(arr, pf_edges);
634 free_cubearray(arr, pf_edges);
635
636 c = apply_trans(t, c);
637 trans_eofbepos[t][i] = (c.epose/24)*POW2TO11 + c.eofb;
638 }
639 }
640
641 aux = malloc(sizeof(CubeArray));
642 aux->ep = a;
643 for (i = 0; i < FACTORIAL8; i++) {
644 index_to_perm(i, 8, a);
645 c = arrays_to_cube(aux, pf_ep);
646 for (j = 0; j < 16; j++) {
647 t = trans_group_udfix[j];
648 arr = new_cubearray(apply_trans(t, c), pf_ep);
649 trans_epud[t][i] = perm_to_index(arr->ep, 8);
650 free_cubearray(arr, pf_ep);
651 }
652 }
653 free(aux);
654
655 for (i = 0; i < BINOM8ON4; i++) {
656 cp = cpud_separate_ant[i];
657 for (j = 0; j < 16; j++) {
658 t = trans_group_udfix[j];
659 trans_cpud_separate[t][i] =
660 cpud_separate_ind[cp_ttable[t][cp]];
661 }
662 }
663
664 if (!write_symc_trans_file())
665 fprintf(stderr, "Error writing SymTrans file\n");
666}
667
668void
669init_symcoord()
670{
671 int i;
672
673 static bool initialized = false;
674 if (initialized)
675 return;
676 initialized = true;
677
678 init_coord();
679
680 init_symc_trans();
681
682 for (i = 0; all_sd[i] != NULL; i++)
683 gensym(all_sd[i]);
684
685 init_symc_moves();
686}
687
diff --git a/src/symcoord.h b/src/symcoord.h
new file mode 100644
index 0000000..0882bff
--- /dev/null
+++ b/src/symcoord.h
@@ -0,0 +1,17 @@
1#ifndef SYMCOORD_H
2#define SYMCOORD_H
3
4#include "coord.h"
5
6extern Coordinate coord_cp_sym16;
7extern Coordinate coord_eofbepos_sym16;
8extern Coordinate coord_drud_sym16;
9extern Coordinate coord_drudfin_noE_sym16;
10extern Coordinate coord_nxopt31;
11
12extern SymData *all_sd[];
13
14void free_sd(SymData *sd);
15void init_symcoord();
16
17#endif
diff --git a/src/threader_eager.c b/src/threader_eager.c
deleted file mode 100644
index 261b995..0000000
--- a/src/threader_eager.c
+++ /dev/null
@@ -1,163 +0,0 @@
1#include <pthread.h>
2#include "threader_eager.h"
3
4typedef struct {
5 AlgList * sols;
6 pthread_mutex_t * sols_mutex;
7} ThreadData;
8
9typedef struct {
10 DfsArg * arg;
11 Solver * solver;
12 Threader * threader;
13 AlgList * starts;
14 AlgListNode ** node;
15 pthread_mutex_t * start_mutex;
16} ThreadInitData;
17
18static void append_sol(Alg *, void *);
19static void * instance_thread(void *);
20static void dispatch(DfsArg *, AlgList *, Solver *, Threader *);
21static AlgList * possible_starts(DfsArg *, Solver *);
22static int get_nsol(void *);
23
24Threader threader_eager = {
25 .append_sol = append_sol,
26 .dispatch = dispatch,
27 .get_nsol = get_nsol,
28};
29
30static void
31append_sol(Alg *alg, void *threaddata)
32{
33 ThreadData *td = (ThreadData *)threaddata;
34
35 pthread_mutex_lock(td->sols_mutex);
36 append_alg(td->sols, alg);
37 pthread_mutex_unlock(td->sols_mutex);
38}
39
40static AlgList *
41possible_starts(DfsArg *arg, Solver *solver)
42{
43 AlgList *ret = new_alglist();
44
45 if (solver->is_solved(solver->param, arg->cubedata)) {
46 if (arg->opts->min_moves == 0 && arg->d == 0)
47 append_sol(new_alg(""), arg->threaddata);
48 return ret;
49 }
50
51 for (int i = 0; solver->moveset->sorted_moves[i] != NULLMOVE; i++) {
52 Move m = solver->moveset->sorted_moves[i];
53 Alg *alg = new_alg("");
54 append_move(alg, m, false);
55 append_alg(ret, alg);
56 free_alg(alg);
57
58/* TODO: check if step not final */
59 if (arg->opts->can_niss) {
60 alg = new_alg("");
61 append_move(alg, m, true);
62 append_alg(ret, alg);
63 free_alg(alg);
64 }
65 }
66
67 return ret;
68}
69
70static void *
71instance_thread(void *arg)
72{
73 ThreadInitData *tid = (ThreadInitData *)arg;
74
75 while (true) {
76 pthread_mutex_lock(tid->start_mutex);
77 AlgListNode *node = *(tid->node);
78 if (node == NULL) {
79 pthread_mutex_unlock(tid->start_mutex);
80 break;
81 }
82 *(tid->node) = (*(tid->node))->next;
83 pthread_mutex_unlock(tid->start_mutex);
84
85/* TODO: adjust for longer (arbitrarily long?) starting sequences */
86 void *data = tid->solver->alloc_cubedata(tid->solver->param);
87 tid->solver->copy_cubedata(
88 tid->solver->param, tid->arg->cubedata, data);
89 bool inv = node->alg->inv[node->alg->len-1];
90 if (inv)
91 tid->solver->invert_cube(
92 tid->solver->param, data);
93 tid->solver->apply_move(
94 tid->solver->param, data, node->alg->move[0]);
95
96 DfsArg newarg;
97 newarg.cubedata = data;
98 newarg.threaddata = tid->arg->threaddata;
99 newarg.opts = tid->arg->opts;
100 newarg.d = tid->arg->d;
101 newarg.niss = inv;
102 newarg.current_alg = new_alg("");
103 copy_alg(node->alg, newarg.current_alg);
104
105 dfs(&newarg, tid->solver, tid->threader);
106
107 tid->solver->free_cubedata(tid->solver->param, data);
108 free_alg(newarg.current_alg);
109 }
110
111 return NULL;
112}
113
114static void
115dispatch(DfsArg *arg, AlgList *sols, Solver *solver, Threader *threader)
116{
117 int nthreads = arg->opts->nthreads;
118 ThreadInitData tid[nthreads];
119 pthread_t t[nthreads];
120
121 pthread_mutex_t *sols_mutex = malloc(sizeof(pthread_mutex_t));
122 pthread_mutex_init(sols_mutex, NULL);
123
124 arg->threaddata = malloc(sizeof(ThreadData));
125 ThreadData *td = (ThreadData *)arg->threaddata;
126 td->sols = sols;
127 td->sols_mutex = sols_mutex;
128
129 AlgList *starts = possible_starts(arg, solver);
130 AlgListNode *node = starts->first;
131 pthread_mutex_t *start_mutex = malloc(sizeof(pthread_mutex_t));
132 pthread_mutex_init(start_mutex, NULL);
133 for (int i = 0; i < nthreads; i++) {
134 tid[i].arg = arg;
135 tid[i].solver = solver;
136 tid[i].threader = threader;
137 tid[i].starts = starts;
138 tid[i].node = &node;
139 tid[i].start_mutex = start_mutex;
140
141 pthread_create(&t[i], NULL, instance_thread, &tid[i]);
142 }
143
144 for (int i = 0; i < nthreads; i++)
145 pthread_join(t[i], NULL);
146
147 free(td);
148 free(sols_mutex);
149 free_alglist(starts);
150 free(start_mutex);
151}
152
153static int
154get_nsol(void *threaddata)
155{
156 ThreadData *td = (ThreadData *)threaddata;
157
158 pthread_mutex_lock(td->sols_mutex);
159 int n = td->sols->len;
160 pthread_mutex_unlock(td->sols_mutex);
161
162 return n;
163}
diff --git a/src/threader_eager.h b/src/threader_eager.h
deleted file mode 100644
index e39b27f..0000000
--- a/src/threader_eager.h
+++ /dev/null
@@ -1,8 +0,0 @@
1#ifndef THREADER_EAGER_H
2#define THREADER_EAGER_H
3
4#include "solve.h"
5
6extern Threader threader_eager;
7
8#endif
diff --git a/src/threader_single.c b/src/threader_single.c
deleted file mode 100644
index 232835d..0000000
--- a/src/threader_single.c
+++ /dev/null
@@ -1,35 +0,0 @@
1#include "threader_single.h"
2
3static void append_sol(Alg *, void *);
4static void dispatch(DfsArg *, AlgList *, Solver *, Threader *);
5static int get_nsol(void *);
6
7Threader threader_single = {
8 .append_sol = append_sol,
9 .dispatch = dispatch,
10 .get_nsol = get_nsol,
11};
12
13static void
14append_sol(Alg *alg, void *threaddata)
15{
16 append_alg((AlgList *)threaddata, alg);
17}
18
19static void
20dispatch(DfsArg *arg, AlgList *sols, Solver *solver, Threader *threader)
21{
22 arg->threaddata = sols;
23 arg->niss = false;
24 arg->current_alg = new_alg("");
25
26 dfs(arg, solver, threader);
27
28 free_alg(arg->current_alg);
29}
30
31static int
32get_nsol(void *threaddata)
33{
34 return ((AlgList *)threaddata)->len;
35}
diff --git a/src/threader_single.h b/src/threader_single.h
deleted file mode 100644
index 2c0bfab..0000000
--- a/src/threader_single.h
+++ /dev/null
@@ -1,8 +0,0 @@
1#ifndef THREADER_SINGLE_H
2#define THREADER_SINGLE_H
3
4#include "solve.h"
5
6extern Threader threader_single;
7
8#endif
diff --git a/src/trans.c b/src/trans.c
index 898c2be..e267a17 100644
--- a/src/trans.c
+++ b/src/trans.c
@@ -1,23 +1,31 @@
1#define TRANS_C
2
3#include "trans.h" 1#include "trans.h"
4 2
5/* Local functions ***********************************************************/ 3/* Local functions ***********************************************************/
6 4
5static bool read_ttables_file();
6static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f);
7static bool write_ttables_file();
8
7/* Tables and other data *****************************************************/ 9/* Tables and other data *****************************************************/
8 10
9static Cube mirror_cube = { 11static int ep_mirror[12] = {
10.ep = { [UF] = UF, [UL] = UR, [UB] = UB, [UR] = UL, 12 [UF] = UF, [UL] = UR, [UB] = UB, [UR] = UL,
11 [DF] = DF, [DL] = DR, [DB] = DB, [DR] = DL, 13 [DF] = DF, [DL] = DR, [DB] = DB, [DR] = DL,
12 [FR] = FL, [FL] = FR, [BL] = BR, [BR] = BL }, 14 [FR] = FL, [FL] = FR, [BL] = BR, [BR] = BL
13.cp = { [UFR] = UFL, [UFL] = UFR, [UBL] = UBR, [UBR] = UBL, 15};
14 [DFR] = DFL, [DFL] = DFR, [DBL] = DBR, [DBR] = DBL }, 16
15.xp = { [U_center] = U_center, [D_center] = D_center, 17static int cp_mirror[8] = {
18 [UFR] = UFL, [UFL] = UFR, [UBL] = UBR, [UBR] = UBL,
19 [DFR] = DFL, [DFL] = DFR, [DBL] = DBR, [DBR] = DBL
20};
21
22static int cpos_mirror[6] = {
23 [U_center] = U_center, [D_center] = D_center,
16 [R_center] = L_center, [L_center] = R_center, 24 [R_center] = L_center, [L_center] = R_center,
17 [F_center] = F_center, [B_center] = B_center } 25 [F_center] = F_center, [B_center] = B_center
18}; 26};
19 27
20static char rotation_alg_string[100][NROTATIONS] = { 28static char rotation_alg_string[100][NROTATIONS] = {
21 [uf] = "", [ur] = "y", [ub] = "y2", [ul] = "y3", 29 [uf] = "", [ur] = "y", [ub] = "y2", [ul] = "y3",
22 [df] = "z2", [dr] = "y z2", [db] = "x2", [dl] = "y3 z2", 30 [df] = "z2", [dr] = "y z2", [db] = "x2", [dl] = "y3 z2",
23 [rf] = "z3", [rd] = "z3 y", [rb] = "z3 y2", [ru] = "z3 y3", 31 [rf] = "z3", [rd] = "z3 y", [rb] = "z3 y2", [ru] = "z3 y3",
@@ -26,39 +34,176 @@ static char rotation_alg_string[100][NROTATIONS] = {
26 [bu] = "x3", [br] = "x3 y", [bd] = "x3 y2", [bl] = "x3 y3", 34 [bu] = "x3", [br] = "x3 y", [bd] = "x3 y2", [bl] = "x3 y3",
27}; 35};
28 36
29Alg *rotation_alg_arr[NROTATIONS]; 37static int epose_source[NTRANS]; /* 0=epose, 1=eposs, 2=eposm */
30Move moves_ttable[NTRANS][NMOVES]; 38static int eposs_source[NTRANS];
31Trans trans_ttable[NTRANS][NTRANS]; 39static int eposm_source[NTRANS];
32Trans trans_itable[NTRANS]; 40static int eofb_source[NTRANS]; /* 0=eoud, 1=eorl, 2=eofb */
41static int eorl_source[NTRANS];
42static int eoud_source[NTRANS];
43static int coud_source[NTRANS]; /* 0=coud, 1=corl, 2=cofb */
44static int cofb_source[NTRANS];
45static int corl_source[NTRANS];
33 46
34/* Public functions **********************************************************/ 47int epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
48int eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
49int eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
50int eo_ttable[NTRANS][POW2TO11];
51int cp_ttable[NTRANS][FACTORIAL8];
52int co_ttable[NTRANS][POW3TO7];
53int cpos_ttable[NTRANS][FACTORIAL6];
54Move moves_ttable[NTRANS][NMOVES];
35 55
36void 56/* Local functions implementation ********************************************/
37apply_trans(Trans t, Cube *cube) 57
58static bool
59read_ttables_file()
38{ 60{
39 Cube aux; 61 init_env();
40 Alg *inv; 62
41 int i; 63 FILE *f;
64 char fname[strlen(tabledir)+20];
65 int b = sizeof(int);
66 bool r = true;
67 Move m;
42 68
43 inv = inverse_alg(rotation_alg(t % NROTATIONS)); 69 /* Table sizes, used for reading and writing files */
44 copy_cube(cube, &aux); 70 uint64_t me[11] = {
45 make_solved(cube); 71 [0] = FACTORIAL12/FACTORIAL8,
72 [1] = FACTORIAL12/FACTORIAL8,
73 [2] = FACTORIAL12/FACTORIAL8,
74 [3] = POW2TO11,
75 [4] = FACTORIAL8,
76 [5] = POW3TO7,
77 [6] = FACTORIAL6,
78 [7] = NMOVES
79 };
80
81 strcpy(fname, tabledir);
82 strcat(fname, "/");
83 strcat(fname, "ttables");
84
85 if ((f = fopen(fname, "rb")) == NULL)
86 return false;
46 87
47 if (t >= NROTATIONS) 88 for (m = 0; m < NTRANS; m++) {
48 compose(&mirror_cube, cube); 89 r = r && fread(epose_ttable[m], b, me[0], f) == me[0];
49 apply_alg(inv, cube); 90 r = r && fread(eposs_ttable[m], b, me[1], f) == me[1];
50 compose(&aux, cube); 91 r = r && fread(eposm_ttable[m], b, me[2], f) == me[2];
51 apply_alg(rotation_alg(t % NROTATIONS), cube); 92 r = r && fread(eo_ttable[m], b, me[3], f) == me[3];
52 if (t >= NROTATIONS) { 93 r = r && fread(cp_ttable[m], b, me[4], f) == me[4];
53 compose(&mirror_cube, cube); 94 r = r && fread(co_ttable[m], b, me[5], f) == me[5];
54 for (i = 0; i < 8; i++) 95 r = r && fread(cpos_ttable[m], b, me[6], f) == me[6];
55 cube->co[i] = (3 - cube->co[i]) % 3; 96 r = r && fread(moves_ttable[m], b, me[7], f) == me[7];
56 } 97 }
57 98
99 fclose(f);
100 return r;
101}
102
103static Cube
104rotate_via_compose(Trans r, Cube c, PieceFilter f)
105{
106 static int zero12[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
107 static int zero8[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
108 static CubeArray ma = {
109 .ep = ep_mirror,
110 .eofb = zero12,
111 .eorl = zero12,
112 .eoud = zero12,
113 .cp = cp_mirror,
114 .coud = zero8,
115 .corl = zero8,
116 .cofb = zero8,
117 .cpos = cpos_mirror
118 };
119
120 Alg *inv = inverse_alg(rotation_alg(r));
121 Cube ret = {0};
122
123 if (r >= NROTATIONS)
124 ret = move_via_arrays(&ma, ret, f);
125 ret = apply_alg_generic(inv, ret, f, true);
126
127 ret = compose_filtered(c, ret, f);
128
129 ret = apply_alg_generic(rotation_alg(r), ret, f, true);
130 if (r >= NROTATIONS)
131 ret = move_via_arrays(&ma, ret, f);
132
58 free_alg(inv); 133 free_alg(inv);
134 return ret;
135}
136
137static bool
138write_ttables_file()
139{
140 init_env();
141
142 FILE *f;
143 char fname[strlen(tabledir)+20];
144 bool r = true;
145 int b = sizeof(int);
146 Move m;
147
148 /* Table sizes, used for reading and writing files */
149 uint64_t me[11] = {
150 [0] = FACTORIAL12/FACTORIAL8,
151 [1] = FACTORIAL12/FACTORIAL8,
152 [2] = FACTORIAL12/FACTORIAL8,
153 [3] = POW2TO11,
154 [4] = FACTORIAL8,
155 [5] = POW3TO7,
156 [6] = FACTORIAL6,
157 [7] = NMOVES
158 };
159
160 strcpy(fname, tabledir);
161 strcat(fname, "/ttables");
162
163 if ((f = fopen(fname, "wb")) == NULL)
164 return false;
165
166 for (m = 0; m < NTRANS; m++) {
167 r = r && fwrite(epose_ttable[m], b, me[0], f) == me[0];
168 r = r && fwrite(eposs_ttable[m], b, me[1], f) == me[1];
169 r = r && fwrite(eposm_ttable[m], b, me[2], f) == me[2];
170 r = r && fwrite(eo_ttable[m], b, me[3], f) == me[3];
171 r = r && fwrite(cp_ttable[m], b, me[4], f) == me[4];
172 r = r && fwrite(co_ttable[m], b, me[5], f) == me[5];
173 r = r && fwrite(cpos_ttable[m], b, me[6], f) == me[6];
174 r = r && fwrite(moves_ttable[m], b, me[7], f) == me[7];
175 }
176
177 fclose(f);
178 return r;
179}
180
181/* Public functions **********************************************************/
182
183Cube
184apply_trans(Trans t, Cube cube)
185{
186 /*init_trans();*/
187
188 int aux_epos[3] = { cube.epose, cube.eposs, cube.eposm };
189 int aux_eo[3] = { cube.eoud, cube.eorl, cube.eofb };
190 int aux_co[3] = { cube.coud, cube.corl, cube.cofb };
191
192 return (Cube) {
193 .epose = epose_ttable[t][aux_epos[epose_source[t]]],
194 .eposs = eposs_ttable[t][aux_epos[eposs_source[t]]],
195 .eposm = eposm_ttable[t][aux_epos[eposm_source[t]]],
196 .eofb = eo_ttable[t][aux_eo[eofb_source[t]]],
197 .eorl = eo_ttable[t][aux_eo[eorl_source[t]]],
198 .eoud = eo_ttable[t][aux_eo[eoud_source[t]]],
199 .coud = co_ttable[t][aux_co[coud_source[t]]],
200 .corl = co_ttable[t][aux_co[corl_source[t]]],
201 .cofb = co_ttable[t][aux_co[cofb_source[t]]],
202 .cp = cp_ttable[t][cube.cp],
203 .cpos = cpos_ttable[t][cube.cpos]
204 };
59} 205}
60 206
61/*
62Trans 207Trans
63inverse_trans(Trans t) 208inverse_trans(Trans t)
64{ 209{
@@ -86,18 +231,23 @@ inverse_trans(Trans t)
86 231
87 return inverse_trans_aux[t]; 232 return inverse_trans_aux[t];
88} 233}
89*/
90
91Trans
92inverse_trans(Trans t)
93{
94 return trans_itable[t];
95}
96 234
97Alg * 235Alg *
98rotation_alg(Trans i) 236rotation_alg(Trans t)
99{ 237{
100 return rotation_alg_arr[i % NROTATIONS]; 238 int i;
239
240 static Alg *rotation_alg_arr[NROTATIONS];
241 static bool initialized = false;
242
243 if (!initialized) {
244 for (i = 0; i < NROTATIONS; i++)
245 rotation_alg_arr[i] = new_alg(rotation_alg_string[i]);
246
247 initialized = true;
248 }
249
250 return rotation_alg_arr[t % NROTATIONS];
101} 251}
102 252
103void 253void
@@ -105,20 +255,10 @@ transform_alg(Trans t, Alg *alg)
105{ 255{
106 int i; 256 int i;
107 257
258 /*init_trans();*/
259
108 for (i = 0; i < alg->len; i++) 260 for (i = 0; i < alg->len; i++)
109 alg->move[i] = transform_move(t, alg->move[i]); 261 alg->move[i] = moves_ttable[t][alg->move[i]];
110}
111
112Move
113transform_move(Trans t, Move m)
114{
115 return moves_ttable[t][m];
116}
117
118Trans
119transform_trans(Trans t, Trans m)
120{
121 return trans_ttable[t][m];
122} 262}
123 263
124void 264void
@@ -128,63 +268,106 @@ init_trans() {
128 return; 268 return;
129 initialized = true; 269 initialized = true;
130 270
131 int i; 271 init_moves();
132 Alg *nonsym_alg, *nonsym_inv; 272
133 Cube aux, cube; 273 Cube aux, cube, c[3];
274 CubeArray epcp;
275 int i, eparr[12], eoarr[12], cparr[8], coarr[8];
276 unsigned int ui;
134 Move mi, move; 277 Move mi, move;
135 Trans t, u, v; 278 Trans m;
136 279
137 init_moves(); 280 /* Compute sources */
281 for (i = 0; i < NTRANS; i++) {
282 cube = apply_alg(rotation_alg(i), (Cube){0});
283
284 epose_source[i] = edge_slice(what_edge_at(cube, FR));
285 eposs_source[i] = edge_slice(what_edge_at(cube, UR));
286 eposm_source[i] = edge_slice(what_edge_at(cube, UF));
287 eofb_source[i] = what_center_at(cube, F_center)/2;
288 eorl_source[i] = what_center_at(cube, R_center)/2;
289 eoud_source[i] = what_center_at(cube, U_center)/2;
290 coud_source[i] = what_center_at(cube, U_center)/2;
291 cofb_source[i] = what_center_at(cube, F_center)/2;
292 corl_source[i] = what_center_at(cube, R_center)/2;
293 }
138 294
139 for (i = 0; i < NROTATIONS; i++) 295 if (read_ttables_file())
140 rotation_alg_arr[i] = new_alg(rotation_alg_string[i]); 296 return;
297
298 fprintf(stderr, "Cannot load %s, generating it\n", "ttables");
141 299
142 for (t = 0; t < NTRANS; t++) { 300 /* Initialize tables */
301 for (m = 0; m < NTRANS; m++) {
302 epcp = (CubeArray){ .ep = eparr, .cp = cparr };
303 cube = apply_alg(rotation_alg(m), (Cube){0});
304 cube_to_arrays(cube, &epcp, pf_epcp);
305 if (m >= NROTATIONS) {
306 apply_permutation(ep_mirror, eparr, 12);
307 apply_permutation(cp_mirror, cparr, 8);
308 }
309
310 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
311 c[0] = admissible_ep((Cube){ .epose = ui }, pf_e);
312 c[1] = admissible_ep((Cube){ .eposs = ui }, pf_s);
313 c[2] = admissible_ep((Cube){ .eposm = ui }, pf_m);
314
315 cube = rotate_via_compose(m,c[epose_source[m]],pf_ep);
316 epose_ttable[m][ui] = cube.epose;
317
318 cube = rotate_via_compose(m,c[eposs_source[m]],pf_ep);
319 eposs_ttable[m][ui] = cube.eposs;
320
321 cube = rotate_via_compose(m,c[eposm_source[m]],pf_ep);
322 eposm_ttable[m][ui] = cube.eposm;
323 }
324 for (ui = 0; ui < POW2TO11; ui++ ) {
325 int_to_sum_zero_array(ui, 2, 12, eoarr);
326 apply_permutation(eparr, eoarr, 12);
327 eo_ttable[m][ui] = digit_array_to_int(eoarr, 11, 2);
328 }
329 for (ui = 0; ui < POW3TO7; ui++) {
330 int_to_sum_zero_array(ui, 3, 8, coarr);
331 apply_permutation(cparr, coarr, 8);
332 co_ttable[m][ui] = digit_array_to_int(coarr, 7, 3);
333 if (m >= NROTATIONS)
334 co_ttable[m][ui] =
335 invert_digits(co_ttable[m][ui], 3, 7);
336 }
337 for (ui = 0; ui < FACTORIAL8; ui++) {
338 cube = (Cube){ .cp = ui };
339 cube = rotate_via_compose(m, cube, pf_cp);
340 cp_ttable[m][ui] = cube.cp;
341 }
342 for (ui = 0; ui < FACTORIAL6; ui++) {
343 cube = (Cube){ .cpos = ui };
344 cube = rotate_via_compose(m, cube, pf_cpos);
345 cpos_ttable[m][ui] = cube.cpos;
346 }
143 for (mi = 0; mi < NMOVES; mi++) { 347 for (mi = 0; mi < NMOVES; mi++) {
144 make_solved(&aux); 348 /* Old version:
145 apply_move(mi, &aux); 349 *
146 apply_trans(t, &aux); 350 aux = apply_trans(m, apply_move(mi, (Cube){0}));
147 for (move = 0; move < NMOVES; move++) { 351 for (move = 0; move < NMOVES; move++) {
148 copy_cube(&aux, &cube); 352 cube = apply_move(inverse_move(move), aux);
149 apply_move(inverse_move(move), &cube); 353 mirr = apply_trans(uf_mirror, cube);
150 if (is_solved(&cube)) { 354 if (is_solved(cube) || is_solved(mirr))
151 moves_ttable[t][mi] = move; 355 moves_ttable[m][mi] = move;
152 break;
153 }
154 } 356 }
155 } 357 */
156 }
157 358
158 nonsym_alg = new_alg("R' U' F"); 359 aux = apply_trans(m, apply_move(mi, (Cube){0}));
159 nonsym_inv = inverse_alg(nonsym_alg); 360 for (move = 0; move < NMOVES; move++) {
160 361 cube = apply_move(inverse_move(move), aux);
161 for (t = 0; t < NTRANS; t++) { 362 if (is_solved(cube)) {
162 for (u = 0; u < NTRANS; u++) { 363 moves_ttable[m][mi] = move;
163 make_solved(&aux);
164 apply_alg(nonsym_alg, &aux);
165 apply_trans(u, &aux);
166 apply_trans(t, &aux);
167 for (v = 0; v < NTRANS; v++) {
168 copy_cube(&aux, &cube);
169 apply_trans(v, &cube);
170 apply_alg(nonsym_inv, &cube);
171 if (is_solved(&cube)) {
172 /* This is the inverse of the correct
173 value, it will be inverted later */
174 trans_ttable[t][u] = v;
175 if (v == uf)
176 trans_itable[t] = u;
177 break; 364 break;
178 } 365 }
179 } 366 }
180 } 367 }
181 } 368 }
182 for (t = 0; t < NTRANS; t++)
183 for (u = 0; u < NTRANS; u++)
184 trans_ttable[t][u] = trans_itable[trans_ttable[t][u]];
185
186 369
187 free_alg(nonsym_alg); 370 if (!write_ttables_file())
188 free_alg(nonsym_inv); 371 fprintf(stderr, "Error writing ttables\n");
189} 372}
190 373
diff --git a/src/trans.h b/src/trans.h
index 0cc8cef..51df12f 100644
--- a/src/trans.h
+++ b/src/trans.h
@@ -3,30 +3,24 @@
3 3
4#include "moves.h" 4#include "moves.h"
5 5
6void apply_trans(Trans t, Cube *cube); 6/*
7 * Tables are exposed to allow faster partial transformations in some
8 * specific cases (in symcoord)
9 */
10extern int epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
11extern int eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
12extern int eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
13extern int eo_ttable[NTRANS][POW2TO11];
14extern int cp_ttable[NTRANS][FACTORIAL8];
15extern int co_ttable[NTRANS][POW3TO7];
16extern int cpos_ttable[NTRANS][FACTORIAL6];
17extern Move moves_ttable[NTRANS][NMOVES];
18
19Cube apply_trans(Trans t, Cube cube);
7Trans inverse_trans(Trans t); 20Trans inverse_trans(Trans t);
8Alg * rotation_alg(Trans i); 21Alg * rotation_alg(Trans i);
9void transform_alg(Trans t, Alg *alg); 22void transform_alg(Trans i, Alg *alg);
10Move transform_move(Trans t, Move m);
11Trans transform_trans(Trans t, Trans m);
12 23
13void init_trans(); 24void init_trans();
14 25
15#ifndef TRANS_C
16
17extern TransGroup tgrp_udfix;
18
19#else
20
21TransGroup
22tgrp_udfix = {
23 .n = 16,
24 .t = { uf, ur, ub, ul,
25 df, dr, db, dl,
26 uf_mirror, ur_mirror, ub_mirror, ul_mirror,
27 df_mirror, dr_mirror, db_mirror, dl_mirror },
28};
29
30#endif
31
32#endif 26#endif
diff --git a/src/utils.c b/src/utils.c
index cbf951e..e0d3268 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -1,5 +1,3 @@
1#define UTILS_C
2
3#include "utils.h" 1#include "utils.h"
4 2
5void 3void
@@ -161,24 +159,24 @@ is_perm(int *a, int n)
161{ 159{
162 int *aux = malloc(n * sizeof(int)); 160 int *aux = malloc(n * sizeof(int));
163 int i; 161 int i;
164 bool ret = true;
165 162
166 for (i = 0; i < n; i++) 163 for (i = 0; i < n; i++)
167 aux[i] = 0; 164 aux[i] = 0;
168 165
169 for (i = 0; i < n; i++) { 166 for (i = 0; i < n; i++) {
170 if (a[i] < 0 || a[i] >= n) 167 if (a[i] < 0 || a[i] >= n)
171 ret = false; 168 return false;
172 else 169 else
173 aux[a[i]] = 1; 170 aux[a[i]] = 1;
174 } 171 }
175 172
176 for (i = 0; i < n; i++) 173 for (i = 0; i < n; i++)
177 if (!aux[i]) 174 if (!aux[i])
178 ret = false; 175 return false;
179 176
180 free(aux); 177 free(aux);
181 return ret; 178
179 return true;
182} 180}
183 181
184bool 182bool
@@ -197,7 +195,7 @@ perm_sign(int *a, int n)
197{ 195{
198 int i, j, ret = 0; 196 int i, j, ret = 0;
199 197
200 if (!is_perm(a, n)) 198 if (!is_perm(a,n))
201 return -1; 199 return -1;
202 200
203 for (i = 0; i < n; i++) 201 for (i = 0; i < n; i++)
@@ -213,7 +211,7 @@ perm_to_index(int *a, int n)
213 int i, j, c, ret = 0; 211 int i, j, c, ret = 0;
214 212
215 if (!is_perm(a, n)) 213 if (!is_perm(a, n))
216 return factorial(n); 214 return -1;
217 215
218 for (i = 0; i < n; i++) { 216 for (i = 0; i < n; i++) {
219 c = 0; 217 c = 0;
diff --git a/tests/alg_tests.c b/tests/alg_tests.c
deleted file mode 100644
index 9ac1595..0000000
--- a/tests/alg_tests.c
+++ /dev/null
@@ -1,266 +0,0 @@
1#include "alg_tests.h"
2
3bool testmethod_append_move(void *);
4bool testmethod_new_alg(void *);
5/*
6bool testmethod_compose_alg(void *);
7bool testmethod_inverse_alg(void *);
8bool testmethod_on_inverse(void *);
9bool testmethod_unniss(void *);
10*/
11
12typedef struct {
13 Move *move;
14 bool *inv;
15 int len;
16 Move m;
17 bool inverse;
18} append_move_t;
19
20Move m_app1[] = {F, x, D3};
21bool i_app1[] = {true, false, false};
22append_move_t append_move_case1 = {
23 .move = m_app1,
24 .inv = i_app1,
25 .len = 3,
26 .m = L3,
27 .inverse = false,
28};
29
30Move m_app2[] = {S, U, x2, M2};
31bool i_app2[] = {true, false, true, true};
32append_move_t append_move_case2 = {
33 .move = m_app2,
34 .inv = i_app2,
35 .len = 4,
36 .m = R,
37 .inverse = true,
38};
39
40Move m_app3[] = {U, U, U, U, U};
41bool i_app3[] = {false, false, false, false, false};
42append_move_t append_move_case3 = {
43 .move = m_app3,
44 .inv = i_app3,
45 .len = 5,
46 .m = U,
47 .inverse = false,
48};
49
50append_move_t *append_move_cases[] = {
51 &append_move_case1,
52 &append_move_case2,
53 &append_move_case3,
54};
55
56Test test_append_move = {
57 .name = "Appending a move to and alg",
58 .t = testmethod_append_move,
59 .cases = (void **)append_move_cases,
60};
61
62typedef struct {
63 char *str;
64 Move *move;
65 bool *inv;
66 int len;
67 Move *move_normal;
68 int len_normal;
69 Move *move_inverse;
70 int len_inverse;
71} new_alg_t;
72
73/* Alg F U B' (L3 D) x M (S) y3 */
74Move m_new1[] = {F, U, B3, L3, D, x, M, S, y3};
75Move mn_new1[] = {F, U, B3, x, M, y3};
76Move mi_new1[] = {L3, D, S};
77bool i_new1[] = {false, false, false, true, true, false, false, true, false};
78new_alg_t new_alg_case1 = {
79 .str = "F U B' (L3 D) x M (S) y3",
80 .move = m_new1,
81 .inv = i_new1,
82 .len = 9,
83 .move_normal = mn_new1,
84 .len_normal = 6,
85 .move_inverse = mi_new1,
86 .len_inverse = 3,
87};
88new_alg_t *new_alg_cases[] = {&new_alg_case1};
89
90Test test_new_alg = {
91 .name = "Initializing an alg from a string",
92 .t = testmethod_new_alg,
93 .cases = (void **)new_alg_cases,
94};
95
96Test *alg_all_tests[] = {
97 &test_append_move,
98 &test_new_alg,
99/*
100 &test_append_alg,
101 &test_compose_alg,
102 &test_inverse_alg,
103 &test_on_inverse,
104 &test_unniss,
105*/
106 NULL
107};
108TestSuite alg_suite = {
109 .setup = NULL,
110 .tests = alg_all_tests,
111 .teardown = NULL,
112};
113
114TestSuite *alg_suites[] = {
115 &alg_suite,
116 NULL
117};
118
119bool
120testmethod_append_move(void *a)
121{
122 append_move_t *b = (append_move_t *)a;
123 int li, ln;
124 Alg *alg;
125
126 /* Small to test reallocation */
127 alg = malloc(sizeof(Alg));
128 alg->allocated = 5;
129 alg->move = malloc(alg->allocated * sizeof(Move));
130 alg->inv = malloc(alg->allocated * sizeof(bool));
131 alg->len = b->len;
132 memcpy(alg->move, b->move, alg->len * sizeof(Move));
133 memcpy(alg->inv, b->inv, alg->len * sizeof(bool));
134 alg->move_normal = malloc(alg->allocated * sizeof(Move));
135 alg->move_inverse = malloc(alg->allocated * sizeof(Move));
136
137 li = ln = 0;
138 for (int i = 0; i < alg->len; i++) {
139 if (alg->inv[i])
140 alg->move_inverse[li++] = alg->move[i];
141 else
142 alg->move_normal[ln++] = alg->move[i];
143 }
144 alg->len_inverse = li;
145 alg->len_normal = ln;
146
147 append_move(alg, b->m, b->inverse);
148
149 if (alg->len != b->len + 1) {
150 printf("Alg has wrong len (%d instead of %d)\n",
151 alg->len, b->len + 1);
152 goto append_move_fail;
153 }
154 if (alg->move[alg->len-1] != b->m) {
155 printf("Wrong last move (%s instead of %s)\n",
156 move_string(alg->move[alg->len-1]),
157 move_string(b->m));
158 goto append_move_fail;
159 }
160 if (alg->inv[alg->len-1] != b->inverse) {
161 printf("Wrong inverse flag for last move "
162 "(%s instead of %s)\n",
163 b->inverse ? "normal" : "inverse",
164 b->inverse ? "inverse" : "normal");
165 goto append_move_fail;
166 }
167 if (b->inverse) {
168 if (alg->len_inverse != li + 1 ||
169 alg->len_normal != ln) {
170 printf("%d moves on normal (should be %d)"
171 " and %d on inverse (should be %d)\n",
172 alg->len_normal, ln,
173 alg->len_inverse, li + 1);
174 goto append_move_fail;
175 }
176 if (alg->move_inverse[alg->len_inverse-1] != b->m) {
177 printf("Wrong move on inverse (%s instead of %s)\n",
178 move_string(alg->move_inverse[alg->len-1]),
179 move_string(b->m));
180 goto append_move_fail;
181 }
182 } else {
183 if (alg->len_inverse != li ||
184 alg->len_normal != ln + 1) {
185 printf("%d moves on normal (should be %d)"
186 " and %d on inverse (should be %d)\n",
187 alg->len_normal, ln,
188 alg->len_inverse, li + 1);
189 goto append_move_fail;
190 }
191 if (alg->move_normal[alg->len_normal-1] != b->m) {
192 printf("Wrong move on normal (%s instead of %s)\n",
193 move_string(alg->move_normal[alg->len-1]),
194 move_string(b->m));
195 goto append_move_fail;
196 }
197 }
198
199 free(alg);
200 return true;
201
202append_move_fail:
203 free(alg);
204 return false;
205}
206
207bool
208testmethod_new_alg(void *a)
209{
210 new_alg_t *b = (new_alg_t *)a;
211 Alg *alg = new_alg(b->str);
212
213 if (alg->len != b->len) {
214 printf("Algs have different length (%d instead of %d)\n",
215 alg->len, b->len);
216 goto new_alg_fail;
217 }
218
219 for (int i = 0; i < alg->len; i++) {
220 if (alg->move[i] != b->move[i] || alg->inv[i] != b->inv[i]) {
221 printf("Algs differ on move %d\n", i);
222 printf("Expected: %s\nActual: ", b->str);
223 print_alg(alg, false);
224 goto new_alg_fail;
225 }
226 }
227
228 if (alg->len_normal != b->len_normal) {
229 printf("Algs have different number of moves on normal"
230 " (%d instead of %d)\n",
231 alg->len_normal, b->len_normal);
232 goto new_alg_fail;
233 }
234 for (int i = 0; i < alg->len_normal; i++) {
235 if (alg->move_normal[i] != b->move_normal[i]) {
236 printf("Algs have different move %d on normal"
237 " (%s instead of %s)\n", i,
238 move_string(alg->move_normal[i]),
239 move_string(b->move_normal[i]));
240 goto new_alg_fail;
241 }
242 }
243
244 if (alg->len_inverse != b->len_inverse) {
245 printf("Algs have different number of moves on inverse"
246 " (%d instead of %d)\n",
247 alg->len_inverse, b->len_inverse);
248 goto new_alg_fail;
249 }
250 for (int i = 0; i < alg->len_inverse; i++) {
251 if (alg->move_inverse[i] != b->move_inverse[i]) {
252 printf("Algs have different move %d on inverse:\n"
253 " (%s instead of %s)\n", i,
254 move_string(alg->move_inverse[i]),
255 move_string(b->move_inverse[i]));
256 goto new_alg_fail;
257 }
258 }
259
260 free(alg);
261 return true;
262
263new_alg_fail:
264 free(alg);
265 return false;
266}
diff --git a/tests/alg_tests.h b/tests/alg_tests.h
deleted file mode 100644
index a24b51f..0000000
--- a/tests/alg_tests.h
+++ /dev/null
@@ -1,21 +0,0 @@
1#ifndef ALG_TESTS_H
2#define ALG_TESTS_H
3
4#include "../src/alg.h"
5#include "test_common.h"
6
7extern Test test_append_move;
8extern Test test_new_alg;
9/*
10extern Test remove_last_move;
11extern Test test_compose_alg;
12extern Test test_inverse_alg;
13extern Test test_on_inverse;
14extern Test test_unniss;
15*/
16
17extern TestSuite alg_suite;
18
19extern TestSuite *alg_suites[];
20
21#endif
diff --git a/tests/coord_tests.c b/tests/coord_tests.c
deleted file mode 100644
index 8d6b6d3..0000000
--- a/tests/coord_tests.c
+++ /dev/null
@@ -1,50 +0,0 @@
1#include "coord_tests.h"
2
3bool testmethod_indexes_consistent(void *);
4
5Test test_indexes_consistent = {
6 .name = "Consitency of index and anti-index",
7 .t = testmethod_indexes_consistent,
8 .cases = (void **)all_coordinates,
9};
10Test *coord_pre_init[] = {
11 &test_indexes_consistent,
12 NULL
13};
14TestSuite coord_pre_init_suite = {
15 .setup = NULL,
16 .tests = coord_pre_init,
17 .teardown = NULL,
18};
19
20TestSuite *coord_suites[] = {
21 &coord_pre_init_suite,
22 NULL
23};
24
25bool
26testmethod_indexes_consistent(void *a)
27{
28 uint64_t ui, uj;
29 Cube c;
30 Coordinate *coord;
31
32 coord = (Coordinate *)a;
33
34 if (coord->type != COMP_COORD)
35 return true; /* Not applicable */
36
37 gen_coord(coord);
38 for (ui = 0; ui < coord->max; ui++) {
39 indexers_makecube(coord->i, ui, &c);
40 uj = indexers_getind(coord->i, &c);
41 if (ui != uj) {
42 fprintf(stderr, "Error with coordinate %s: "
43 "%" PRIu64 " != %" PRIu64 "\n",
44 coord->name, uj, ui);
45 return false;
46 }
47 }
48
49 return true;
50}
diff --git a/tests/coord_tests.h b/tests/coord_tests.h
deleted file mode 100644
index 0cfd145..0000000
--- a/tests/coord_tests.h
+++ /dev/null
@@ -1,13 +0,0 @@
1#ifndef COORD_TESTS_H
2#define COORD_TESTS_H
3
4#include "../src/coord.h"
5#include "test_common.h"
6
7extern Test test_indexes_consistent;
8
9extern TestSuite coord_pre_init_suite;
10
11extern TestSuite *coord_suites[];
12
13#endif
diff --git a/tests/fst_tests.c b/tests/fst_tests.c
deleted file mode 100644
index 1a9bedd..0000000
--- a/tests/fst_tests.c
+++ /dev/null
@@ -1,184 +0,0 @@
1#include "fst_tests.h"
2
3static bool testmethod_fst_is_consistent(void *);
4static bool testmethod_cube_to_fst_to_cube(void *);
5static bool testmethod_fst_move(void *);
6static bool testmethod_fst_inverse(void *);
7static bool check_equal_and_log(Cube *, Cube *);
8static void void_to_cube(void *, Cube *);
9
10char *algs[] = {
11 "",
12 "U", "U2", "U'", "D", "D2", "D'", "R", "R2", "R'",
13 "L", "L2", "L'", "F", "F2", "F'", "B", "B2", "B'",
14 "U2 R2 U2 R2 U2",
15 "U2 F2 R2 B2 U2 D2 F2 L2 B2",
16 "RUR'URU2R'",
17 "L2 D R U2 B2 L",
18 "R'U'F",
19 "F2 U' R2 D' B2 D2 R2 D2 R2 U' F L' U' R B F2 R B' D2",
20 "D L2 F2 R2 D R2 U L2 U' B2 D L' F2 U2 B' L D' U' R' B2 F2",
21 "F' L2 F' D' R F2 L U L' D2 R2 F2 D2 R2 B' L2 B2 U2 F D2 B",
22 NULL,
23};
24
25Test test_fst_is_consistent = {
26 .name = "Consitency of FST (converted from cube)",
27 .t = testmethod_fst_is_consistent,
28 .cases = (void **)algs,
29};
30Test test_cube_to_fst_to_cube = {
31 .name = "Cube to FST to cube",
32 .t = testmethod_cube_to_fst_to_cube,
33 .cases = (void **)algs,
34};
35Test test_fst_move = {
36 .name = "FST move",
37 .t = testmethod_fst_move,
38 .cases = (void **)algs,
39};
40Test test_fst_inverse = {
41 .name = "FST inverse",
42 .t = testmethod_fst_inverse,
43 .cases = (void **)algs,
44};
45
46Test *fst_pre_init[] = {
47 &test_fst_is_consistent,
48 &test_cube_to_fst_to_cube,
49 NULL
50};
51TestSuite fst_pre_init_suite = {
52 .setup = NULL,
53 .tests = fst_pre_init,
54 .teardown = NULL,
55};
56
57Test *fst_post_init[] = {
58 &test_fst_move,
59 &test_fst_inverse,
60 NULL
61};
62TestSuite fst_post_init_suite = {
63 .setup = init_fst,
64 .tests = fst_post_init,
65 .teardown = NULL,
66};
67
68TestSuite *fst_suites[] = {
69 &fst_pre_init_suite,
70 &fst_post_init_suite,
71 NULL
72};
73
74static bool
75check_equal_and_log(Cube *c, Cube *d)
76{
77 bool ret = equal(c, d);
78
79 if (!ret) {
80 printf("\n");
81 printf("These cubes should be equal, but are not:\n\n");
82 print_cube(c);
83 printf("\n");
84 print_cube(d);
85 printf("\n");
86 }
87
88 return ret;
89}
90
91static void
92void_to_cube(void *a, Cube *c)
93{
94 char *algstr;
95 Alg *alg;
96
97 algstr = (char *)a;
98 alg = new_alg(algstr);
99 make_solved(c);
100 apply_alg(alg, c);
101 free_alg(alg);
102}
103
104bool
105testmethod_fst_is_consistent(void *a)
106{
107 FstCube fst_uf, fst_fr, fst_rd;
108 Cube c, c_fr, c_rd;
109 bool consistent_fr, consistent_rd, result;
110
111 void_to_cube(a, &c);
112 copy_cube(&c, &c_fr);
113 apply_trans(fr, &c_fr);
114
115 copy_cube(&c, &c_rd);
116 apply_trans(rd, &c_rd);
117
118 fst_uf = cube_to_fst(&c);
119 fst_fr = cube_to_fst(&c_fr);
120 fst_rd = cube_to_fst(&c_rd);
121
122 consistent_fr = fst_uf.fr_eofb == fst_fr.uf_eofb &&
123 fst_uf.fr_eposepe == fst_fr.uf_eposepe &&
124 fst_uf.fr_coud == fst_fr.uf_coud;
125
126 consistent_rd = fst_uf.rd_eofb == fst_rd.uf_eofb &&
127 fst_uf.rd_eposepe == fst_rd.uf_eposepe &&
128 fst_uf.rd_coud == fst_rd.uf_coud;
129
130 result = consistent_fr && consistent_rd;
131
132 if (!result)
133 printf("\nFailed with alg %s\n", (char *)a);
134
135 return result;
136}
137
138bool
139testmethod_cube_to_fst_to_cube(void *a)
140{
141 Cube c, d;
142 FstCube fst;
143
144 void_to_cube(a, &c);
145 fst = cube_to_fst(&c);
146 fst_to_cube(fst, &d);
147
148 return check_equal_and_log(&c, &d);;
149}
150
151bool
152testmethod_fst_move(void *a)
153{
154 int i;
155 Alg *alg;
156 Cube c, d;
157 FstCube fst;
158
159 void_to_cube(a, &c);
160 alg = new_alg((char *)a);
161 make_solved(&d);
162 fst = cube_to_fst(&d);
163
164 for (i = 0; i < alg->len; i++)
165 fst = fst_move(alg->move[i], fst);
166
167 fst_to_cube(fst, &d);
168
169 free_alg(alg);
170
171 return check_equal_and_log(&c, &d);
172}
173
174bool
175testmethod_fst_inverse(void *a)
176{
177 Cube c, d;
178
179 void_to_cube(a, &c);
180 fst_to_cube(fst_inverse(cube_to_fst(&c)), &d);
181 invert_cube(&c);
182
183 return check_equal_and_log(&c, &d);
184}
diff --git a/tests/fst_tests.h b/tests/fst_tests.h
deleted file mode 100644
index 68bbf04..0000000
--- a/tests/fst_tests.h
+++ /dev/null
@@ -1,19 +0,0 @@
1#ifndef FST_TESTS_H
2#define FST_TESTS_H
3
4#include "../src/fst.h"
5#include "test_common.h"
6
7extern char *algs[];
8
9extern Test test_fst_is_consistent;
10extern Test test_cube_to_fst_to_cube;
11extern Test test_fst_move;
12extern Test test_fst_inverse;
13
14extern TestSuite fst_pre_init_suite;
15extern TestSuite fst_post_init_suite;
16
17extern TestSuite *fst_suites[];
18
19#endif
diff --git a/tests/test.c b/tests/test.c
deleted file mode 100644
index 8961de1..0000000
--- a/tests/test.c
+++ /dev/null
@@ -1,85 +0,0 @@
1#include <stdio.h>
2
3#include "alg_tests.h"
4#include "coord_tests.h"
5#include "fst_tests.h"
6
7static bool run_test(Test *);
8static bool run_suite(TestSuite *);
9
10static bool
11run_test(Test *test)
12{
13 int i;
14
15 printf("Running test %s...", test->name);
16 for (i = 0; test->cases[i] != NULL; i++) {
17 if (!test->t(test->cases[i])) {
18 printf("FAILED!\n");
19 return false;
20 }
21 }
22
23 printf("OK\n");
24 return true;
25}
26
27static bool
28run_suite(TestSuite *suite)
29{
30 int i;
31
32 if (suite->setup != NULL)
33 suite->setup();
34 for (i = 0; suite->tests[i] != NULL; i++)
35 if(!run_test(suite->tests[i]))
36 return false;
37 if (suite->teardown != NULL)
38 suite->teardown();
39
40 return true;
41}
42
43static bool
44module_in_args(char *module, int argc, char *argv[])
45{
46 for (int i = 0; i < argc; i++)
47 if (!strcmp(module, argv[i]))
48 return true;
49 return false;
50}
51
52int main(int argc, char *argv[]) {
53 /* TODO: init should be in testsuites */
54 init_env();
55 init_trans();
56 /**************************************/
57
58 TestModule alg = { .name = "alg", .suites = alg_suites };
59 TestModule fst = { .name = "fst", .suites = fst_suites };
60 TestModule coord = { .name = "coord", .suites = coord_suites };
61 TestModule *modules[999] = {
62 &alg,
63 &fst,
64 &coord,
65 NULL
66 };
67
68
69 bool all = argc == 1 || module_in_args("all", argc, argv);
70 int count = 0;
71 for (int i = 0; modules[i] != NULL; i++) {
72 if (all || module_in_args(modules[i]->name, argc, argv)) {
73 for (int j = 0; modules[i]->suites[j] != NULL; j++) {
74 if (!run_suite(modules[i]->suites[j])) {
75 return 1;
76 } else {
77 count++;
78 }
79 }
80 }
81 }
82
83 printf("All tests passed (%d test suites).\n", count);
84 return 0;
85}
diff --git a/tests/test_common.h b/tests/test_common.h
deleted file mode 100644
index 03511ef..0000000
--- a/tests/test_common.h
+++ /dev/null
@@ -1,41 +0,0 @@
1#ifndef TEST_COMMON_H
2#define TEST_COMMON_H
3
4/*
5 * Common utilities for testing.
6 * A VoidMethod can be used as a setup or teardown method for testing, see
7 * the TestSuite struct. A TestMethod takes a void pointer (usually cast
8 * to some data to be used for testing, but can also be ignored) and returns
9 * a bool: true for pass, false for fail.
10 * A Test consists of a name (string), a TestMethod and an array of void
11 * pointers that describe the test cases. Each element of this array is
12 * passed to the test method sequentially, and the test session stops on
13 * the first failure.
14 * A test suite is just a list of tests with a setup and a teardown method.
15 * The setup method is run once and for all before the first test, and the
16 * teardown is run at the end of the testsuite.
17 * Finally, a TestModule roughly corresponds to a test file. This type is
18 * only used in test.c to collect multiple test modules.
19 */
20
21typedef void (*VoidMethod)(void);
22typedef bool (*TestMethod)(void *);
23
24typedef struct {
25 char * name;
26 TestMethod t;
27 void ** cases;
28} Test;
29
30typedef struct {
31 VoidMethod setup;
32 Test ** tests;
33 VoidMethod teardown;
34} TestSuite;
35
36typedef struct {
37 char * name;
38 TestSuite ** suites;
39} TestModule;
40
41#endif
diff --git a/www/download/index.html b/www/download/index.html
deleted file mode 100644
index 8e4cccd..0000000
--- a/www/download/index.html
+++ /dev/null
@@ -1,217 +0,0 @@
1<!doctype html>
2<html lang="en">
3<head>
4 <title> Download | Nissy </title>
5<meta name="viewport" content="width=device-width" /> <link rel="stylesheet" type="text/css" href="/style-3.css">
6 <link rel="icon" href="/favicon.png">
7 <meta charset="utf-8">
8</head>
9
10<body>
11
12<nav class="top">
13 <table class="menu">
14 <tr>
15 <td class="logo"> <a href="/"><img src="/favicon.png" alt="logo"></a> </td>
16 <td class="links">
17 <a href="/download/">Download</a> |
18 <a href="/examples/">Examples</a>
19 </td>
20 </tr>
21 </table>
22</nav>
23
24<hr class="line">
25
26
27<h1>Get Nissy</h1>
28
29<table class="dltable">
30<tr>
31 <td></td>
32 <td><strong>Source code</strong></td>
33 <td><strong>Windows executable</strong></td>
34</tr>
35<tr>
36 <td><strong>Latest version</strong></td>
37 <td><a href="/nissy-2.0.3.tar.gz">nissy-2.0.3.tar.gz (67Kb)</a></td>
38 <td><a href="/nissy-2.0.3.exe">nissy-2.0.3.exe (780Kb)</a></td>
39</tr>
40</table>
41
42<p>
43In this page you can find download links (see above),
44<a href="#Installation">installation instructions</a> and
45<a href="#Upgrade">upgrade instructions</a>
46for nissy. If instead you wish to clone the
47<a href="https://git.tronto.net/nissy/">git repository</a>,
48you can use git:
49</p>
50
51<pre>
52<code>git clone https://git.tronto.net/nissy</code>
53</pre>
54
55<p>
56For a summary of changes and a list of older versions see below. Some versions
57(for example 1.0) are not available directly, but can be obtained from
58the git repository.
59</p>
60
61<h2 id="Installation">Installation</h2>
62
63<h3>System requirements</h3>
64
65<p>
66A full installation of nissy requires about 3.1Gb of space,
67of which 2.3Gb are occupied by the huge pruning table for fast optimal solving,
68and running it requires the same amount of RAM.
69One can choose to never use this function and not to install the relative
70pruning table. There is an alternative (slower)
71optimal solving function that uses about 500Mb of RAM.
72
73When generating the pruning tables automatically (see the section Tables below),
74at least 5.3Gb or RAM are required.
75</p>
76
77<h3>Windows</h3>
78
79<p>
80Try downloading and executing in a terminal the file <code>nissy.exe</code>,
81then follow the instructions in the <strong>Tables</strong> section below for
82installing the pruning tables.
83If <code>nissy.exe</code> does not work, you can try following the UNIX instructions
84in WSL (Windows Subsystem for Linux) or in a similar environment.
85</p>
86
87<h3>UNIX (Linux, MacOS, *BSD...)</h3>
88<p>
89Download the source archive (.tar.gz). Extract it
90with your favorite archive program, for example with
91</p>
92<pre><code>tar -xvzf nissy-VERSION.tar.gz</code></pre>
93<p>
94Open a terminal in the directory just extracted.
95If you wish, edit the <code>Makefile</code> to match your local configuration
96(this is usually not necessary, but you may want to change the
97<code>PREFIX</code> variable to change the installation path) and run
98<pre><code>make</code></pre>
99<p>
100followed by
101</p>
102<pre><code>make install</code></pre>
103<p>
104Then follow the instructions below to install the pruning tables.
105</p>
106
107<h3>Tables</h3>
108
109<p>
110Once you have installed nissy, run
111</p>
112
113<pre><code>nissy gen</code></pre>
114
115<p>
116to generate all the tables that Nissy will ever need.
117Running this command requires around 5.3Gb of RAM, and it can take some time
118(about 40 minutes on my fairly old but decent laptop, with 8 CPU threads).
119</p>
120
121<p>
122Some unnecessary technical detail: by default this command is going to use
123at most 64 threads. If you want you can choose to use more threads (if your CPU
124is very powerful) or fewer threads (if you for example want to run this command
125in the background while you do other stuff) with the <code>-t</code> option, for
126example <code>nissy gen -t 1</code>.
127</p>
128
129<p>
130Alternatively, you can
131<a href="/nissy-tables-2.0.2.zip">download all the tables (1.7Gb)</a> and
132copy them into the correct folder (see manual page, <code>ENVIRONMENT</code>
133section). On UNIX operating systems this folder is either
134<code>.nissy/tables</code> in the user's home directory or
135<code>$XDG_DATA_HOME/nissy/tables</code> if the XDG variable is configured.
136On Windows it is the same directory as the <code>nissy.exe</code> executable
137file.
138</p>
139
140<h2 id="Upgrade">Upgrading</h2>
141<p>
142If you already have nissy installed and you want to upgrade to a more
143recent version, you can simply repeat the installation process:
144</p>
145<ul>
146<li>
147On Windows: simply replace nissy.exe with the new file with the same name.
148</li>
149<li>
150On UNIX systems: download the new version of the source code, extract it in
151a new folder and run <code>make</code> and <code>make install</code> again.
152</li>
153</ul>
154<p>
155Between each version new table files might have been added, or old ones
156may be not used anymore. Nissy will deal with this automatically.
157</p>
158
159<h2>Version history</h2>
160
161<h3>Nissy v2</h3>
162
163<table class=dltable>
164<tr>
165 <td><strong>Version</strong></td>
166 <td><strong>Date</strong></td>
167 <td><strong>Comment</strong></td>
168</tr>
169<tr>
170 <td><a href="/nissy-2.0.3.tar.gz">2.0.3</a></td>
171 <td>2022-09-10</td>
172 <td>Fixed bug in scramble dr</td>
173</tr>
174<tr>
175 <td><a href="/nissy-2.0.2.tar.gz">2.0.2</a></td>
176 <td>2022-06-01</td>
177 <td>Improved table generation speed</td>
178</tr>
179<tr>
180 <td><a href="/nissy-2.0.1.tar.gz">2.0.1</a></td>
181 <td>2022-02-22</td>
182 <td>Bugfix release</td>
183</tr>
184<tr>
185 <td>2.0</td>
186 <td>2021-12-29</td>
187 <td>Rewritten from scratch; much faster optimal solver</td>
188</tr>
189</table>
190
191<h3>Nissy v1</h3>
192
193<p>
194Nissy v1 was released in 2020. It was slow, full of bugs and the code
195was quite terrible. But in practice it got its job done most of the time.
196</p>
197
198
199<hr class="line">
200
201<nav class="bottom">
202 <table class="footer">
203 <tr>
204 <td class="contact">
205 <a href="https://sebastiano.tronto.net">sebastiano.tronto.net</a>
206 </td>
207 <td class="hosted">
208 <a href="mailto:sebastiano@tronto.net">
209 sebastiano@tronto.net
210 </a>
211 </td>
212 </tr>
213 </table>
214</nav>
215
216</body>
217</html>
diff --git a/www/examples/index.html b/www/examples/index.html
deleted file mode 100644
index 517c251..0000000
--- a/www/examples/index.html
+++ /dev/null
@@ -1,49 +0,0 @@
1<!doctype html>
2<html lang="en">
3<head>
4 <title> Examples | Nissy </title>
5<meta name="viewport" content="width=device-width" /> <link rel="stylesheet" type="text/css" href="/style-3.css">
6 <link rel="icon" href="/favicon.png">
7 <meta charset="utf-8">
8</head>
9
10<body>
11
12<nav class="top">
13 <table class="menu">
14 <tr>
15 <td class="logo"> <a href="/"><img src="/favicon.png" alt="logo"></a> </td>
16 <td class="links">
17 <a href="/download/">Download</a> |
18 <a href="/examples/">Examples</a>
19 </td>
20 </tr>
21 </table>
22</nav>
23
24<hr class="line">
25
26
27<h1>Examples</h1>
28
29(Coming soon...)
30
31<hr class="line">
32
33<nav class="bottom">
34 <table class="footer">
35 <tr>
36 <td class="contact">
37 <a href="https://sebastiano.tronto.net">sebastiano.tronto.net</a>
38 </td>
39 <td class="hosted">
40 <a href="mailto:sebastiano@tronto.net">
41 sebastiano@tronto.net
42 </a>
43 </td>
44 </tr>
45 </table>
46</nav>
47
48</body>
49</html>
diff --git a/www/favicon.png b/www/favicon.png
deleted file mode 100644
index 3ec80a1..0000000
--- a/www/favicon.png
+++ /dev/null
Binary files differ
diff --git a/www/index.html b/www/index.html
deleted file mode 100644
index 500952c..0000000
--- a/www/index.html
+++ /dev/null
@@ -1,93 +0,0 @@
1<!doctype html>
2<html lang="en">
3<head>
4 <title> Nissy | Nissy </title>
5<meta name="viewport" content="width=device-width" /> <link rel="stylesheet" type="text/css" href="/style-3.css">
6 <link rel="icon" href="/favicon.png">
7 <meta charset="utf-8">
8</head>
9
10<body>
11
12<nav class="top">
13 <table class="menu">
14 <tr>
15 <td class="logo"> <a href="/"><img src="/favicon.png" alt="logo"></a> </td>
16 <td class="links">
17 <a href="/download/">Download</a> |
18 <a href="/examples/">Examples</a>
19 </td>
20 </tr>
21 </table>
22</nav>
23
24<hr class="line">
25
26
27<h1>Nissy</h1>
28
29<p class=subtitle>A Rubik's cube solver and FMC assistant</p>
30
31<img src="/screenshot.png" alt="A screenshot of nissy running in a terminal emulator">
32
33<p>
34Nissy is a command-line Rubik's cube solver. It can find optimal solutions
35for random positions using techniques from Herbert Kociemba's
36<a href="http://kociemba.org/cube.htm">Cube Explorer</a> and
37Tomas Rokicki's
38<a href="https://github.com/rokici/cube20src/blob/master/nxopt.md">nxopt</a>.
39With 4 cores at 2.5GHz and using about 3Gb of RAM, Nissy can find an optimal
40solution in about a minute on average.
41</p>
42
43<p>
44Nissy aims at being a complete tool
45for FMC (Fewest Moves Challenge) practice. It can solve different steps
46of Thistlethwaite's algorithm (also know as DR/HTR) and cans use NISS
47(Normal-Inverse Scramble Switch).
48</p>
49
50<p>
51You should use Nissy if:
52</p>
53<ul>
54<li>
55You want to analyze your DR solutions or check for multiple optimal
56(or sub-optimal) solutions for EO/DR/HTR or similar steps.
57</li>
58<li>
59You just want a Rubik's cube solver and you like command line interfaces.
60</li>
61<li>
62You want an alternative to Cube Explorer.
63</li>
64</ul>
65
66<p>
67To get started, head to the <a href="/download/">download</a> page.
68</p>
69
70<p>
71You can also see its source code by cloning the git repository
72<a href="https://git.tronto.net/nissy/">git.tronto.net/nissy</a>
73</p>
74
75<hr class="line">
76
77<nav class="bottom">
78 <table class="footer">
79 <tr>
80 <td class="contact">
81 <a href="https://sebastiano.tronto.net">sebastiano.tronto.net</a>
82 </td>
83 <td class="hosted">
84 <a href="mailto:sebastiano@tronto.net">
85 sebastiano@tronto.net
86 </a>
87 </td>
88 </tr>
89 </table>
90</nav>
91
92</body>
93</html>
diff --git a/www/screenshot.png b/www/screenshot.png
deleted file mode 100644
index a73f2fd..0000000
--- a/www/screenshot.png
+++ /dev/null
Binary files differ
diff --git a/www/style-3.css b/www/style-3.css
deleted file mode 100644
index ec70635..0000000
--- a/www/style-3.css
+++ /dev/null
@@ -1,105 +0,0 @@
1.menu {
2 width: 100%;
3}
4
5.links {
6 text-align: right;
7 font-weight: bold;
8}
9
10.logo img {
11 width: 50px;
12 height: 50px;
13}
14
15.footer {
16 font-style: italic;
17 width: 100%;
18}
19
20.hosted {
21 text-align: right;
22}
23
24body {
25 margin: auto 8px 20px 8px;
26}
27
28img {
29 display: block;
30 margin-left: auto;
31 margin-right: auto;
32 max-width: 100%;
33}
34
35code {
36 background-color: #eeeeee;
37 padding: 2px;
38}
39
40pre code {
41 padding: 0px;
42}
43
44pre {
45 background-color: #eeeeee;
46 border: 2px solid;
47 padding: 6px;
48}
49
50#blob {
51 background: #ffffff;
52 border: none;
53}
54
55a {
56 color: #0f2899;
57 text-decoration: none;
58}
59
60.links a {
61 font-weight: bold;
62 color: black;
63}
64
65.hosted a,
66.contact a {
67 font-weight: bold;
68}
69
70a:hover {
71 text-decoration: underline;
72}
73
74html {
75 margin: 1em auto;
76 max-width: 42em;
77}
78
79h1 {
80 text-align: center;
81}
82
83td h1 {
84 text-align: left;
85 font-size: 1.5em;
86}
87
88table {
89 width: 100%;
90}
91
92.url td {
93 font-family: monospace;
94}
95
96.dltable th, .dltable td {
97 border: 1px solid black;
98 padding: 3px;
99}
100
101.subtitle {
102 text-align: center;
103 font-weight: bold;
104 font-size: 1.1em;
105}

Generated with cgit - Back to sebastiano.tronto.net