aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile5
-rw-r--r--TODO.md111
-rw-r--r--doc/nissy.1271
-rw-r--r--old/maybe-useful-coord.c181
-rw-r--r--old/maybe-useful-steps.c1111
-rw-r--r--src/alg.c105
-rw-r--r--src/alg.h76
-rw-r--r--src/commands.c322
-rw-r--r--src/commands.h194
-rw-r--r--src/coord.c976
-rw-r--r--src/coord.h242
-rw-r--r--src/cube.c920
-rw-r--r--src/cube.h44
-rw-r--r--src/cubetypes.h176
-rw-r--r--src/env.c2
-rw-r--r--src/env.h4
-rw-r--r--src/moves.c409
-rw-r--r--src/moves.h20
-rw-r--r--src/pf.c95
-rw-r--r--src/pf.h20
-rw-r--r--src/pruning.c265
-rw-r--r--src/pruning.h21
-rw-r--r--src/shell.c22
-rw-r--r--src/solve.c469
-rw-r--r--src/solve.h4
-rw-r--r--src/steps.c1514
-rw-r--r--src/steps.h276
-rw-r--r--src/symcoord.c687
-rw-r--r--src/symcoord.h17
-rw-r--r--src/trans.c381
-rw-r--r--src/trans.h36
-rw-r--r--src/utils.c14
-rw-r--r--www/download/index.html2
-rw-r--r--www/examples/index.html2
-rw-r--r--www/index.html2
-rw-r--r--www/style-2.css (renamed from www/style.css)8
36 files changed, 3586 insertions, 5418 deletions
diff --git a/Makefile b/Makefile
index 735571f..6686b86 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
1# See LICENSE file for copyright and license details. 1# See LICENSE file for copyright and license details.
2 2
3VERSION = 2.0.2 3VERSION = post-2.0.2
4 4
5PREFIX = /usr/local 5PREFIX = /usr/local
6MANPREFIX = ${PREFIX}/share/man 6MANPREFIX = ${PREFIX}/share/man
@@ -26,8 +26,7 @@ debug:
26 ${CC} ${DBGFLAGS} -o nissy src/*.c 26 ${CC} ${DBGFLAGS} -o nissy src/*.c
27 27
28clean: 28clean:
29 rm -rf nissy nissy*.exe nissy*.tar.gz 29 rm -rf nissy nissy*.exe nissy*.tar.gz doc/nissy.html doc/nissy.pdf
30 rm doc/nissy.html doc/nissy.pdf
31 30
32dist: clean nissy.exe 31dist: clean nissy.exe
33 mkdir -p nissy-${VERSION} 32 mkdir -p nissy-${VERSION}
diff --git a/TODO.md b/TODO.md
index 2ef405d..b7481f1 100644
--- a/TODO.md
+++ b/TODO.md
@@ -3,50 +3,48 @@
3This is a list of things that I would like to add or change at some point. 3This is a list of things that I would like to add or change at some point.
4It's more of a personal reminder than anything else. 4It's more of a personal reminder than anything else.
5 5
6## Version 2.0.2
7### Website
8* now gen takes 40 minutes
9### Changelog
10* Only improved table generation speed, but this required huge changes in
11 coordinates.c and symcoord.c (+ some minor changes in other parts).
12
13## For version 2.1 6## For version 2.1
14### Coordinates 7### Slow: it is slower than the old nissy 2.0.2 :(
15* Text (README.md) description of coordinate system with 3 (or 4) types of 8* nxopt's trick (switching to reduce branching) actually saves about 50%!
16 coordinates: basic (+ fundamental), sym, composite (consisting of at most 9* Another factor is estimating *while* moving (i.e. do not move all
17 one sym + one or more basic) 10 coordinates if the first one already gives a high value!)
18* Use this to restructure the coordinate part; maybe fundamental coordinates 11* simplify solve, remove everything that is used only by optimal solvers
19 do not need to exist??? 12* Good compromise: each stepalt offers one of two alternatives: either solve
20* Add also "transform" for every coordinate. For example, for EO and similar 13 by simply using pruning tables and moving coordinates, or using a custom
21 only allow transformations that fix the EO axis. 14 estimator and moving a cube (or fast_cube) and computing coordinates
22* Also: "basic" symcoord do not allow trans, composite coordinates assume 15 in the estimator
23 the transformation fixes the basic sumcoord 16* is there really no way to use inverse branching trick with current system?
24* For each coordinate, manually disallow "bad" moves, or just ignore the error 17* new file optimal.c with the old solve logic; try first with the simple
25 (probably better to check: low performance cost, detect problems that I might 18 cube implementation and the new indexers, if it is still slow change
26 be overlooking) 19 to fast_cube (intermediate nissy v2.0.2 implementation)
27### Changes to Step and Solve 20### Changes to Step and Solve
28* Revolutionize: do everything based on coordinates, replace Cube with 21* remove cube from dfsarg? (i still need to save the scramble somewhere,
29 CubeArray (or just 4 values, so consistency check is super easy); 22 but I really only use it in dfs_niss)
30 remove tables for fast inverse. 23* coord.c: all old coordinates (WIP...)
31* No need for most of step data: just solve a list of coordinates 24* steps.c: checkers (use coordinates), all stepalt and steps (WIP...)
32 (+ associated pruning tables) 25* commands gen and freemem
33* For steps that accept multiple solved states (e.g. drany): 26* commands.c: twophase, ...?
34 just find a way to "merge" multiple steps as alternatives; or 27* Coordinate should have a moveset field? No, at worst there are some garbage
35 offer multiple lists of coordinates as alternatives 28 values in mtable, but no risk for errors
36* De Bondt's trick: list of 3 coords (as indexes in coord array of the step) 29### Rotate, not transform, before solving
37 that if evaluated to the same pruning value allow for de bondt's trick. 30* solve should re-orient first if needed and not just give up if centers are off
38* NISS: compute inverse based on current use moves just before switching,
39 using CubeArray; it is not too slow.
40### Loading at startup vs dynamically
41* Consider moving more things to the initial loading phase (i.e. remove
42 many of the "initialized" parts)
43### Documentation 31### Documentation
32* Document how coordinates and pruning tables work now
44* Write an examples.md file 33* Write an examples.md file
45* More screenshots! 34* More screenshots!
46### Tables management 35### Tables management
47* Check files in tables directory, add command to remove old / extraneous files 36* Check files in tables directory automatically remove old / extraneous files
48* Add checksum to check that tables are generated / downloaded correctly 37* Add checksum to check that tables are generated / downloaded correctly
49* Edit download page update instructions to tell what to do when changing tables 38### Conditional compiling
39* Option to avoid large tables at compile time
40* option to avoid multithreading (write a simpler solve for t=1, and also
41 check if found enough solutions before checking pruning values)
42### Technical
43* generic option parser
44* testing? Maybe just hardcode some examples generated with old nissy
45### Commands
46* Easy: add option -I (inverse) and -L (linear, like inverse + normal)
47 to do only linear NISS
50 48
51## Commands 49## Commands
52 50
@@ -62,16 +60,21 @@ including e.g. solutions that were not shown because -c)
62* 5-side solve (for robots) 60* 5-side solve (for robots)
63* Block-building steps (cross, roux blocks, ...) 61* Block-building steps (cross, roux blocks, ...)
64* Other common steps (LSE, ...) 62* Other common steps (LSE, ...)
63* Larger table for drudfin (include epe)? About 1Gb uncompressed,
64 500Mb compressed (fallback to noE), 250 compressed + parity trick
65 (is it doable?)
65 66
66### Improvements to currently implemented commands 67### Improvements to currently implemented commands
67* solve should re-orient first if needed and not just give up if centers are off 68* solve multidfs: do multithread by step, not by alternative (this way
69 if there are multiple alternatives it can make use of more threads)
68* solve should try up to a small bound without loading the large pruning table 70* solve should try up to a small bound without loading the large pruning table
71 (maybe this is not necessary if loading the table is fast enough)
69* silent batch mode without >>> 72* silent batch mode without >>>
70 73
71### New features 74### New features
75* EO analysis (and also DR and HTR analysis): group similar EOs together
76 and such (suggested by Jay)
72* configurability: add an `alias` command, run config file at startup 77* configurability: add an `alias` command, run config file at startup
73* configure max ram to be used (via config file and/or command line option)
74* transform alg, rufify etc...
75* command notation to list available moves 78* command notation to list available moves
76* make multi-step solve much more general and create command 79* make multi-step solve much more general and create command
77* input directly cube status instead of moves 80* input directly cube status instead of moves
@@ -105,7 +108,35 @@ including e.g. solutions that were not shown because -c)
105 108
106### Cleanup 109### Cleanup
107* sort again functions alphabetically in their files 110* sort again functions alphabetically in their files
111* change some function and variable names to make everything consistent
108* more stuff to load at start (or when suitable command is called) rather 112* more stuff to load at start (or when suitable command is called) rather
109 than when called directly, to avoid nasty problems with threading 113 than when called directly, to avoid nasty problems with threading
110* parse command args: one function per arg type, then each command has 114* parse command args: one function per arg type, then each command has
111 a list of options that it accepts (as a string) 115 a list of options that it accepts (as a string)
116
117### Style
118* do not declare all variables at the beginning of a function
119* remove var names from prototypes
120* various stuff from style(9)
121
122### Random
123Collect random info like this somewhere:
124
125Table pt_nxopt31_HTM
126Base value: 9
1270 1
1281 6
1292 29
1303 164
1314 1433
1325 16772
1336 205033
1347 2513871
1358 30329976
1369 342440769
13710 2815191126
13811 6147967200
13912 524918774
14013 3546
14114 0
14215 0
diff --git a/doc/nissy.1 b/doc/nissy.1
deleted file mode 100644
index 138d6ae..0000000
--- a/doc/nissy.1
+++ /dev/null
@@ -1,271 +0,0 @@
1.Dd November 2021
2.Dt NISSY 1
3.Os
4.Sh NAME
5.Nm nissy
6.Nd a Rubik's cube solver and FMC assistant
7.
8.Sh SYNOPSIS
9.Nm
10.Op Fl b
11.Nm
12.Ar command
13.Op options...
14.
15.Sh DESCRIPTION
16.Nm
17is a Rubik's Cube solver.
18It uses techniques from Herbert Kociemba's Cube Explorer and
19Tomas Rokicki's nxopt. With 4 cores at 2.5GHz and using about 3Gb
20of RAM, Nissy can find the optimal solution for a random Rubik's cube position
21in about a minute on average.
22Nissy can also solve different substeps of the Thistlethwaite's algorithm and more.
23.Pp
24When run without any argument an interactive shell is launched, otherwise
25the provided
26.Ar command
27is executed and nissy terminates. If the option
28.Fl b
29is given, every argument after it is ignored and the shell is launched without
30any prompt or welcome message. This can be used to run nissy in batch mode,
31for example writing a list of commands in a
32.Ar file
33(one per line) and running
34.Ar nissy -b < file
35.Pp
36The commands that can be run in the interactive shell are the same that can
37be run non-interactively and are provided below.
38.
39.Sh COMMANDS
40The available
41.Ar commands
42are the following:
43.
44.Bl -tag -width Ds
45.
46.It Nm cleanup Ar scramble
47Rewrites the given scramble using only the 18 base (HTM) moves and at most two
48rotations at the end. If
49Ar scramble
50uses NISS, all moves done on normal scramble are written first, followed by
51all moves done on inverse.
52.
53.It Nm commands
54List all available commands.
55.
56.It Nm freemem
57Release some large tables from memory. You can use this command in case
58you want to keep nissy open without using too much RAM.
59.
60.It Nm gen Op Fl t Ar N
61Generate all tables used by nissy. Run this to complete your installation.
62If
63.Ar N
64is specified,
65.Ar N
66CPU threads will be used (defaults to 64, use less only if you don't want
67nissy to use all of your CPU resources).
68.
69.It Nm help Op Ar command
70Display help. If no
71.Ar command
72is given, a generic help message is printed, otherwise a specific help
73relative to
74.Ar command
75is returned.
76.
77.It Nm invert Ar scramble
78Invert the given scramble.
79.
80.It Nm print Ar scramble
81Display a text-only description of the cube obtained after applying
82.Ar scramble .
83.
84.It Nm quit
85Quit nissy.
86.
87.It Nm scramble Oo Fl n Ar N Oc Oo Ar type Oc
88Print a randomly-generated (random position) scramble
89.
90If
91.Ar N
92is given, it produces
93.Ar N
94scrambles.
95.Ar type
96can be specified to be one of the following:
97.Bl -tag -width Ds
98.It Ar corners
99Scramble with solved edges (only cornes are scrambled).
100.It Ar dr
101Scramble with solved DR on U/D.
102.It Ar edges
103Scramble with solved corners (only edges are scrambled).
104.It Ar eo
105Scramble with solved EO on F/B axis.
106.It Ar fmc
107Scramble the full cube and the resulting scramble starts and ends with
108the moves R\(aq U\(aq F.
109.It Ar htr
110Scramble with HTR solved.
111.El
112.
113.It Nm solve Ar step Oo Ar options Oc Ar scramble
114Solve the given
115.Ar step
116on the given
117.Ar scramble.
118By default it finds only one (shortest) solution, without using niss, and it
119displays the number of moves at the end of the line.
120.
121The options for the
122.Ar solve
123command are the following:
124.
125.Bl -tag -width Ds
126.
127.It Fl a
128Print all solutions: some solutions are filtered out by default for some
129steps, for examples EOs that finish with F\(aq, with this options they are not.
130.
131.It Fl c
132Display only the number of solutions found, not the solutions themselves.
133.
134.It Fl m Ar min
135Only look for solution that are at least
136.Ar min
137moves long.
138.
139.It Fl M Ar MAX
140Only look for solution that are at most
141.Ar MAX
142moves long.
143.
144.It Fl n Ar N
145Try to find
146.Ar N
147solutions. By default and unless the
148.Fl M
149or
150.Fl o
151options are used, at most one solution is returned.
152If at least one of
153.Fl M
154and
155.Fl o
156is used, all the solutions found within the given bounds are returned.
157The option
158.Fl s
159overwrites these default behaviors and at most
160.Ar N
161solutions are returned, still satisfiyng the other constraints.
162.
163.It Fl N
164Allow use of NISS.
165.
166.It Fl o
167Only find solutions that require the minimum number of moves.
168.
169.It Fl O Ar N
170Only find solutions that require at most
171.Ar N
172moves more than the optimal solution. If
173.Ar N
174is 0, this is equivalent to
175.Fl o
176.
177.It Fl p
178Plain style: do not print the number of moves.
179.
180.It Fl t Ar N
181Use
182.Ar N
183CPU threads. By default nissy uses only 1 thread. Using more than one
184thread will improve performance, but the optimal number depends on your
185machine and operating system. Generally, using one less than the number
186of threads of your CPU works quite well.
187.
188.It Fl v
189Verbose mode: print some information during the search and print each solution
190as it is found instead of only printing them all together at the end.
191.
192.
193.El
194.
195.It Nm steps
196List all available
197.Ar steps
198for the
199.Ar solve
200command.
201.
202.It Nm twophase Ar scramble
203Find a solution using a two-phase method. This does not guarantee
204to return an optimal solution (and in fact most often it does not),
205but it is very fast.
206.
207.It Nm unniss Ar scramble
208Rewrite the scramble without using NISS.
209.
210.It Nm version
211Display version information.
212.
213.El
214.
215.Sh SCRAMBLES
216All the commands above that accept a scramble also accept a
217.Fl Nm i
218option with no arguments.
219If this option is given, multiple scrambles are read from standard
220input (one per line) until and EOF is found, at which point stdin is cleared.
221.
222.Sh ENVIRONMENT
223Data is stored in the folder pointed to by
224.Nm $NISSYDATA.
225If that variable is unset the folder
226.Nm $XDG_DATA_HOME/nissy
227or
228.Nm $HOME/.nissy
229is used instead. If none of this environment variables is defined
230(e.g. in a non-UNIX system), the current folder is used.
231.
232.Sh EXAMPLES
233.Pp
234The command:
235.Dl nissy solve -v -O 1 \(dqR\(aqU\(aqFD2L2FR2U2R2BD2LB2D\(aqB2L\(aqR\(aqBD2BU2LU2R\(aqU\(aqF\(dq
236Returns:
237.Dl Searching depth 0
238.Dl Searching depth 1
239.Dl (some more lines)
240.Dl Searching depth 16
241.Dl D2 F\(aq U2 D2 F\(aq L2 D R2 D F B2 R\(aq L2 F\(aq U\(aq D
242.Dl Searching depth 17
243.Dl D2 F\(aq U2 D2 F\(aq L2 D R2 D F B2 R\(aq L2 F\(aq U\(aq D (16)
244Notice that the solution is printed twice: the first time it is printed as soon
245as it is found as requested by the -v option.
246.Pp
247The command:
248.Dl nissy solve eofb -m 4 -M 5 -N -n 6 \(dqR\(aqU\(aqFD2L2 FR2 U2R2BD2 L B2 D\(aq B2 L\(aq R\(aq\(dq
249Returns:
250.Dl U B U\(aq B (4)
251.Dl U (B R\(aq B) (4)
252.Dl (U B R\(aq B) (4)
253.Dl U2 F R2 F (4)
254.Dl U2 B U2 B (4)
255.Dl (U2 B R\(aq B) (4)
256.Pp
257On a UNIX shell, the composite command
258.Dl nissy scramble -n 2 | nissy solve -i > file.txt
259Generates two random scrambles, solves them and saves the result to file.txt.
260The file will look something like this:
261.Dl >>> Line: D U2 F D B\(aq F L2 D\(aq F2 R2 L B2 L\(aq U2 B2 R F2 L\(aq D2
262.Dl U2 R2 F2 L B2 D\(aq R2 D\(aq F U L2 B\(aq U\(aq R2 D2 R2 U (17)
263.Dl >>> Line: D B R U\(aq B\(aq L2 U L U D2 R L B2 U2 L2 U2 R U2 B2 L F2
264.Dl D\(aq F R\(aq D B L2 B R2 L U L U2 B D\(aq U R U F2 (18)
265.
266.Sh AUTHORS
267.An Sebastiano Tronto Aq Mt sebastiano@tronto.net
268.
269.Sh SOURCE CODE
270Source code is available at
271.Lk https://nissy.tronto.net
diff --git a/old/maybe-useful-coord.c b/old/maybe-useful-coord.c
new file mode 100644
index 0000000..9ab2971
--- /dev/null
+++ b/old/maybe-useful-coord.c
@@ -0,0 +1,181 @@
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
new file mode 100644
index 0000000..2a20dd9
--- /dev/null
+++ b/old/maybe-useful-steps.c
@@ -0,0 +1,1111 @@
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/src/alg.c b/src/alg.c
index 52bebc0..47e222b 100644
--- a/src/alg.c
+++ b/src/alg.c
@@ -1,68 +1,18 @@
1#include "alg.h" 1#define ALG_C
2 2
3/* Local functions ***********************************************************/ 3#include "alg.h"
4 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);
11static int axis(Move m); 5static int axis(Move m);
12
13static void free_alglistnode(AlgListNode *aln); 6static void free_alglistnode(AlgListNode *aln);
14static void realloc_alg(Alg *alg, int n); 7static void realloc_alg(Alg *alg, int n);
15 8
16/* Movesets ******************************************************************/ 9bool
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) 10allowed_HTM(Move m)
61{ 11{
62 return m >= U && m <= B3; 12 return m >= U && m <= B3;
63} 13}
64 14
65static bool 15bool
66allowed_URF(Move m) 16allowed_URF(Move m)
67{ 17{
68 Move b = base_move(m); 18 Move b = base_move(m);
@@ -70,7 +20,7 @@ allowed_URF(Move m)
70 return b == U || b == R || b == F; 20 return b == U || b == R || b == F;
71} 21}
72 22
73static bool 23bool
74allowed_eofb(Move m) 24allowed_eofb(Move m)
75{ 25{
76 Move b = base_move(m); 26 Move b = base_move(m);
@@ -79,7 +29,7 @@ allowed_eofb(Move m)
79 ((b == F || b == B) && m == b+1); 29 ((b == F || b == B) && m == b+1);
80} 30}
81 31
82static bool 32bool
83allowed_drud(Move m) 33allowed_drud(Move m)
84{ 34{
85 Move b = base_move(m); 35 Move b = base_move(m);
@@ -88,7 +38,7 @@ allowed_drud(Move m)
88 ((b == R || b == L || b == F || b == B) && m == b + 1); 38 ((b == R || b == L || b == F || b == B) && m == b + 1);
89} 39}
90 40
91static bool 41bool
92allowed_htr(Move m) 42allowed_htr(Move m)
93{ 43{
94 Move b = base_move(m); 44 Move b = base_move(m);
@@ -96,8 +46,8 @@ allowed_htr(Move m)
96 return moveset_HTM.allowed(m) && m == b + 1; 46 return moveset_HTM.allowed(m) && m == b + 1;
97} 47}
98 48
99static bool 49bool
100allowed_next_HTM(Move l2, Move l1, Move m) 50allowed_next_all(Move l2, Move l1, Move m)
101{ 51{
102 bool p, q; 52 bool p, q;
103 53
@@ -469,6 +419,34 @@ swapmove(Move *m1, Move *m2)
469 *m2 = aux; 419 *m2 = aux;
470} 420}
471 421
422char *
423trans_string(Trans t)
424{
425 static char trans_string_aux[NTRANS][20] = {
426 [uf] = "uf", [ur] = "ur", [ub] = "ub", [ul] = "ul",
427 [df] = "df", [dr] = "dr", [db] = "db", [dl] = "dl",
428 [rf] = "rf", [rd] = "rd", [rb] = "rb", [ru] = "ru",
429 [lf] = "lf", [ld] = "ld", [lb] = "lb", [lu] = "lu",
430 [fu] = "fu", [fr] = "fr", [fd] = "fd", [fl] = "fl",
431 [bu] = "bu", [br] = "br", [bd] = "bd", [bl] = "bl",
432
433 [uf_mirror] = "uf*", [ur_mirror] = "ur*",
434 [ub_mirror] = "ub*", [ul_mirror] = "ul*",
435 [df_mirror] = "df*", [dr_mirror] = "dr*",
436 [db_mirror] = "db*", [dl_mirror] = "dl*",
437 [rf_mirror] = "rf*", [rd_mirror] = "rd*",
438 [rb_mirror] = "rb*", [ru_mirror] = "ru*",
439 [lf_mirror] = "lf*", [ld_mirror] = "ld*",
440 [lb_mirror] = "lb*", [lu_mirror] = "lu*",
441 [fu_mirror] = "fu*", [fr_mirror] = "fr*",
442 [fd_mirror] = "fd*", [fl_mirror] = "fl*",
443 [bu_mirror] = "bu*", [br_mirror] = "br*",
444 [bd_mirror] = "bd*", [bl_mirror] = "bl*",
445 };
446
447 return trans_string_aux[t];
448}
449
472Alg * 450Alg *
473unniss(Alg *alg) 451unniss(Alg *alg)
474{ 452{
@@ -513,12 +491,3 @@ init_moveset(Moveset *ms)
513 } 491 }
514 } 492 }
515} 493}
516
517void
518init_all_movesets()
519{
520 int i;
521
522 for (i = 0; i < nmoveset; i++)
523 init_moveset(all_ms[i]);
524}
diff --git a/src/alg.h b/src/alg.h
index 6bee26b..51e66b0 100644
--- a/src/alg.h
+++ b/src/alg.h
@@ -8,12 +8,13 @@
8#include "cubetypes.h" 8#include "cubetypes.h"
9#include "utils.h" 9#include "utils.h"
10 10
11extern Moveset moveset_HTM; 11bool allowed_all(Move m);
12extern Moveset moveset_URF; 12bool allowed_HTM(Move m);
13extern Moveset moveset_eofb; 13bool allowed_URF(Move m);
14extern Moveset moveset_drud; 14bool allowed_eofb(Move m);
15extern Moveset moveset_htr; 15bool allowed_drud(Move m);
16 16bool allowed_htr(Move m);
17bool allowed_next_all(Move l2, Move l1, Move m);
17void append_alg(AlgList *l, Alg *alg); 18void append_alg(AlgList *l, Alg *alg);
18void append_move(Alg *alg, Move m, bool inverse); 19void append_move(Alg *alg, Move m, bool inverse);
19Move base_move(Move m); 20Move base_move(Move m);
@@ -34,10 +35,71 @@ Alg * on_inverse(Alg *alg);
34void print_alg(Alg *alg, bool l); 35void print_alg(Alg *alg, bool l);
35void print_alglist(AlgList *al, bool l); 36void print_alglist(AlgList *al, bool l);
36void swapmove(Move *m1, Move *m2); 37void swapmove(Move *m1, Move *m2);
38char * trans_string(Trans t); /* Here because similar to move_string, move? */
37Alg * unniss(Alg *alg); 39Alg * unniss(Alg *alg);
38 40
39void init_moveset(Moveset *ms); 41void init_moveset(Moveset *ms);
40void init_all_movesets(); 42
43/* Movesets ******************************************************************/
44
45#ifndef ALG_C
46
47extern Moveset moveset_HTM;
48extern Moveset moveset_URF;
49extern Moveset moveset_eofb;
50extern Moveset moveset_drud;
51extern Moveset moveset_htr;
52
53extern Moveset * all_ms[];
54
55#else
56
57Moveset
58moveset_HTM = {
59 .name = "HTM",
60 .allowed = allowed_HTM,
61 .allowed_next = allowed_next_all,
62};
63
64Moveset
65moveset_URF = {
66 .name = "URF",
67 .allowed = allowed_URF,
68 .allowed_next = allowed_next_all,
69};
70
71Moveset
72moveset_eofb = {
73 .name = "eofb",
74 .allowed = allowed_eofb,
75 .allowed_next = allowed_next_all,
76};
77
78Moveset
79moveset_drud = {
80 .name = "drud",
81 .allowed = allowed_drud,
82 .allowed_next = allowed_next_all,
83};
84
85Moveset
86moveset_htr = {
87 .name = "htr",
88 .allowed = allowed_htr,
89 .allowed_next = allowed_next_all,
90};
91
92Moveset *
93all_ms[] = {
94 &moveset_HTM,
95 &moveset_URF,
96 &moveset_eofb,
97 &moveset_drud,
98 &moveset_htr,
99 NULL
100};
101
102#endif
41 103
42#endif 104#endif
43 105
diff --git a/src/commands.c b/src/commands.c
index a91fb4f..7f58ef5 100644
--- a/src/commands.c
+++ b/src/commands.c
@@ -1,187 +1,11 @@
1#include "commands.h" 1#define COMMANDS_C
2
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 2
14static void gen_exec(CommandArgs *args); 3#include "commands.h"
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 4
31static bool read_step(CommandArgs *args, char *str); 5static bool read_step(CommandArgs *args, char *str);
32static bool read_scrtype(CommandArgs *args, char *str); 6static bool read_scrtype(CommandArgs *args, char *str);
33static bool read_scramble(int c, char **v, CommandArgs *args); 7static bool read_scramble(int c, char **v, CommandArgs *args);
34 8
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
185/* Arg parsing functions implementation **************************************/ 9/* Arg parsing functions implementation **************************************/
186 10
187CommandArgs * 11CommandArgs *
@@ -386,17 +210,15 @@ parse_no_arg(int c, char **v)
386 210
387/* Exec functions implementation *********************************************/ 211/* Exec functions implementation *********************************************/
388 212
389static void 213void
390solve_exec(CommandArgs *args) 214solve_exec(CommandArgs *args)
391{ 215{
392 Cube c; 216 Cube c;
393 AlgList *sols; 217 AlgList *sols;
394 218
395 init_all_movesets(); 219 make_solved(&c);
396 init_symcoord(); 220 apply_alg(args->scramble, &c);
397 221 sols = solve(&c, args->step, args->opts);
398 c = apply_alg(args->scramble, (Cube){0});
399 sols = solve(c, args->step, args->opts);
400 222
401 if (args->opts->count_only) 223 if (args->opts->count_only)
402 printf("%d\n", sols->len); 224 printf("%d\n", sols->len);
@@ -406,85 +228,64 @@ solve_exec(CommandArgs *args)
406 free_alglist(sols); 228 free_alglist(sols);
407} 229}
408 230
409static void 231void
410scramble_exec(CommandArgs *args) 232scramble_exec(CommandArgs *args)
411{ 233{
412 Cube cube; 234 Cube cube;
413 CubeArray *arr;
414 Alg *scr, *ruf, *aux; 235 Alg *scr, *ruf, *aux;
415 int i, j, eo, ep, co, cp, a[12]; 236 int i, j, eo, ep, co, cp;
416 int eparr[12] = { [8] = 8, [9] = 9, [10] = 10, [11] = 11 };
417 uint64_t ui, uj, uk; 237 uint64_t ui, uj, uk;
418 238
419 init_all_movesets();
420 init_symcoord();
421
422 srand(time(NULL)); 239 srand(time(NULL));
423 240
424 for (i = 0; i < args->n; i++) { 241 for (i = 0; i < args->n; i++) {
425 242
426 if (!strcmp(args->scrtype, "dr")) { 243 if (!strcmp(args->scrtype, "dr")) {
427 /* Warning: cube is inconsistent because of side CO * 244 ui = rand() % FACTORIAL8;
428 * and EO on U/D. But solve_2phase only solves drfin * 245 uj = rand() % FACTORIAL8;
429 * in this case, so it should be ok. * 246 uk = rand() % FACTORIAL4;
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, 12, a);
439 arr = malloc(sizeof(CubeArray));
440 arr->ep = eparr;
441 cube = arrays_to_cube(arr, pf_ep);
442 free(arr);
443 247
444 cube.cp = uj; 248 make_solved(&cube);
445 cube.epose += uk; 249 index_to_perm(ui, 8, cube.cp);
446 } while (!is_admissible(cube)); 250 index_to_perm(uj, 8, cube.ep);
251 index_to_perm(uk, 4, cube.ep + 8);
252 for (j = 8; j < 12; j++)
253 cube.ep[j] += 8;
447 } else if (!strcmp(args->scrtype, "htr")) { 254 } else if (!strcmp(args->scrtype, "htr")) {
448 /* antindex_htrfin() returns a consistent * 255 make_solved(&cube);
449 * cube, except possibly for parity */ 256 /* TODO */
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));
458 } else { 257 } else {
459 eo = rand() % POW2TO11;
460 ep = rand() % FACTORIAL12; 258 ep = rand() % FACTORIAL12;
461 co = rand() % POW3TO7;
462 cp = rand() % FACTORIAL8; 259 cp = rand() % FACTORIAL8;
260 eo = rand() % POW2TO11;
261 co = rand() % POW3TO7;
463 262
464 if (!strcmp(args->scrtype, "eo")) { 263 if (!strcmp(args->scrtype, "eo")) {
465 eo = 0; 264 eo = 0;
466 } else if (!strcmp(args->scrtype, "corners")) { 265 } else if (!strcmp(args->scrtype, "corners")) {
467 eo = 0; 266 eo = 0;
468 ep = 0; 267 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 }
474 } else if (!strcmp(args->scrtype, "edges")) { 268 } else if (!strcmp(args->scrtype, "edges")) {
475 co = 0; 269 co = 0;
476 cp = 0; 270 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 }
482 } 271 }
483 cube = fourval_to_cube(eo, ep, co, cp); 272
273 make_solved(&cube);
274 index_to_perm(ep, 12, cube.ep);
275 index_to_perm(cp, 8, cube.cp);
276 int_to_sum_zero_array(eo, 2, 12, cube.eo);
277 int_to_sum_zero_array(co, 3, 8, cube.co);
278 }
279
280 if (!is_admissible(&cube)) {
281 if (!strcmp(args->scrtype, "corners"))
282 swap(&cube.cp[UFR], &cube.cp[UFL]);
283 else
284 swap(&cube.ep[UF], &cube.ep[UB]);
484 } 285 }
485 286
486 /* TODO: can be optimized for htr and dr using htrfin, drfin */ 287 /* TODO: can be optimized for htr and dr using htrfin, drfin */
487 scr = solve_2phase(cube, 1); 288 scr = solve_2phase(&cube, 1);
488 289
489 if (!strcmp(args->scrtype, "fmc")) { 290 if (!strcmp(args->scrtype, "fmc")) {
490 aux = new_alg(""); 291 aux = new_alg("");
@@ -513,23 +314,22 @@ scramble_exec(CommandArgs *args)
513 } 314 }
514} 315}
515 316
516static void 317void
517gen_exec(CommandArgs *args) 318gen_exec(CommandArgs *args)
518{ 319{
320/* TODO:
519 int i; 321 int i;
520 322
521 fprintf(stderr, "Generating coordinates...\n"); 323 fprintf(stderr, "Generating coordinates...\n");
522 init_all_movesets();
523 init_symcoord();
524
525 fprintf(stderr, "Generating pruning tables...\n"); 324 fprintf(stderr, "Generating pruning tables...\n");
526 for (i = 0; all_pd[i] != NULL; i++) 325 for (i = 0; all_pd[i] != NULL; i++)
527 genptable(all_pd[i], args->opts->nthreads); 326 genptable(all_pd[i], args->opts->nthreads);
327*/
528 328
529 fprintf(stderr, "Done!\n"); 329 fprintf(stderr, "Done!\n");
530} 330}
531 331
532static void 332void
533invert_exec(CommandArgs *args) 333invert_exec(CommandArgs *args)
534{ 334{
535 Alg *inv; 335 Alg *inv;
@@ -540,7 +340,7 @@ invert_exec(CommandArgs *args)
540 free_alg(inv); 340 free_alg(inv);
541} 341}
542 342
543static void 343void
544steps_exec(CommandArgs *args) 344steps_exec(CommandArgs *args)
545{ 345{
546 int i; 346 int i;
@@ -549,7 +349,7 @@ steps_exec(CommandArgs *args)
549 printf("%-15s %s\n", steps[i]->shortname, steps[i]->name); 349 printf("%-15s %s\n", steps[i]->shortname, steps[i]->name);
550} 350}
551 351
552static void 352void
553commands_exec(CommandArgs *args) 353commands_exec(CommandArgs *args)
554{ 354{
555 int i; 355 int i;
@@ -559,9 +359,10 @@ commands_exec(CommandArgs *args)
559 359
560} 360}
561 361
562static void 362void
563freemem_exec(CommandArgs *args) 363freemem_exec(CommandArgs *args)
564{ 364{
365/* TODO:
565 int i; 366 int i;
566 367
567 for (i = 0; all_pd[i] != NULL; i++) 368 for (i = 0; all_pd[i] != NULL; i++)
@@ -569,35 +370,34 @@ freemem_exec(CommandArgs *args)
569 370
570 for (i = 0; all_sd[i] != NULL; i++) 371 for (i = 0; all_sd[i] != NULL; i++)
571 free_sd(all_sd[i]); 372 free_sd(all_sd[i]);
572 373*/
573 /* TODO: invtables are also large, but for now they are *
574 * statically allocated. Consider releasing those too. */
575} 374}
576 375
577static void 376void
578print_exec(CommandArgs *args) 377print_exec(CommandArgs *args)
579{ 378{
580 init_moves(); 379 Cube c;
581 print_cube(apply_alg(args->scramble, (Cube){0})); 380
381 make_solved(&c);
382 apply_alg(args->scramble, &c);
383 print_cube(&c);
582} 384}
583 385
584static void 386void
585twophase_exec(CommandArgs *args) 387twophase_exec(CommandArgs *args)
586{ 388{
587 Cube c; 389 Cube c;
588 Alg *sol; 390 Alg *sol;
589 391
590 init_all_movesets(); 392 make_solved(&c);
591 init_symcoord(); 393 apply_alg(args->scramble, &c);
592 394 sol = solve_2phase(&c, 1);
593 c = apply_alg(args->scramble, (Cube){0});
594 sol = solve_2phase(c, 1);
595 395
596 print_alg(sol, false); 396 print_alg(sol, false);
597 free_alg(sol); 397 free_alg(sol);
598} 398}
599 399
600static void 400void
601help_exec(CommandArgs *args) 401help_exec(CommandArgs *args)
602{ 402{
603 if (args->command == NULL) { 403 if (args->command == NULL) {
@@ -619,26 +419,24 @@ help_exec(CommandArgs *args)
619 } 419 }
620} 420}
621 421
622static void 422void
623quit_exec(CommandArgs *args) 423quit_exec(CommandArgs *args)
624{ 424{
625 exit(0); 425 exit(0);
626} 426}
627 427
628static void 428void
629cleanup_exec(CommandArgs *args) 429cleanup_exec(CommandArgs *args)
630{ 430{
631 Alg *alg; 431 Alg *alg;
632 432
633 init_moves();
634
635 alg = cleanup(args->scramble); 433 alg = cleanup(args->scramble);
636 print_alg(alg, false); 434 print_alg(alg, false);
637 435
638 free_alg(alg); 436 free_alg(alg);
639} 437}
640 438
641static void 439void
642unniss_exec(CommandArgs *args) 440unniss_exec(CommandArgs *args)
643{ 441{
644 Alg *aux; 442 Alg *aux;
@@ -648,7 +446,7 @@ unniss_exec(CommandArgs *args)
648 free(aux); 446 free(aux);
649} 447}
650 448
651static void 449void
652version_exec(CommandArgs *args) 450version_exec(CommandArgs *args)
653{ 451{
654 printf(VERSION"\n"); 452 printf(VERSION"\n");
@@ -691,6 +489,8 @@ static bool
691read_scrtype(CommandArgs *args, char *str) 489read_scrtype(CommandArgs *args, char *str)
692{ 490{
693 int i; 491 int i;
492 static char *scrtypes[20] =
493 { "eo", "corners", "edges", "fmc", "dr", "htr", NULL };
694 494
695 for (i = 0; scrtypes[i] != NULL; i++) { 495 for (i = 0; scrtypes[i] != NULL; i++) {
696 if (!strcmp(scrtypes[i], str)) { 496 if (!strcmp(scrtypes[i], str)) {
diff --git a/src/commands.h b/src/commands.h
index b7a4c36..5d9f4ee 100644
--- a/src/commands.h
+++ b/src/commands.h
@@ -9,6 +9,198 @@
9void free_args(CommandArgs *args); 9void free_args(CommandArgs *args);
10CommandArgs * new_args(); 10CommandArgs * new_args();
11 11
12extern Command * commands[]; 12/* Arg parsing functions *****************************************************/
13
14CommandArgs * gen_parse_args(int c, char **v);
15CommandArgs * help_parse_args(int c, char **v);
16CommandArgs * parse_only_scramble(int c, char **v);
17CommandArgs * parse_no_arg(int c, char **v);
18CommandArgs * solve_parse_args(int c, char **v);
19CommandArgs * scramble_parse_args(int c, char **v);
20
21/* Exec functions ************************************************************/
22
23void gen_exec(CommandArgs *args);
24void cleanup_exec(CommandArgs *args);
25void invert_exec(CommandArgs *args);
26void solve_exec(CommandArgs *args);
27void scramble_exec(CommandArgs *args);
28void steps_exec(CommandArgs *args);
29void commands_exec(CommandArgs *args);
30void freemem_exec(CommandArgs *args);
31void print_exec(CommandArgs *args);
32void twophase_exec(CommandArgs *args);
33void help_exec(CommandArgs *args);
34void quit_exec(CommandArgs *args);
35void unniss_exec(CommandArgs *args);
36void version_exec(CommandArgs *args);
37
38/* Commands ******************************************************************/
39
40#ifndef COMMANDS_C
41
42extern Command cleanup_cmd;
43extern Command commands_cmd;
44extern Command freemem_cmd;
45extern Command gen_cmd;
46extern Command help_cmd;
47extern Command invert_cmd;
48extern Command print_cmd;
49extern Command quit_cmd;
50extern Command scramble_cmd;
51extern Command solve_cmd;
52extern Command steps_cmd;
53extern Command unniss_cmd;
54extern Command version_cmd;
55
56extern Command *commands[];
57
58#else
59
60Command
61solve_cmd = {
62 .name = "solve",
63 .usage = "solve STEP [OPTIONS] SCRAMBLE",
64 .description = "Solve a step; see command steps for a list of steps",
65 .parse_args = solve_parse_args,
66 .exec = solve_exec
67};
68
69Command
70scramble_cmd = {
71 .name = "scramble",
72 .usage = "scramble [TYPE] [-n N]",
73 .description = "Get a random-position scramble",
74 .parse_args = scramble_parse_args,
75 .exec = scramble_exec,
76};
77
78Command
79gen_cmd = {
80 .name = "gen",
81 .usage = "gen [-t N]",
82 .description = "Generate all tables [using N threads]",
83 .parse_args = gen_parse_args,
84 .exec = gen_exec
85};
86
87Command
88invert_cmd = {
89 .name = "invert",
90 .usage = "invert SCRAMBLE]",
91 .description = "Invert a scramble",
92 .parse_args = parse_only_scramble,
93 .exec = invert_exec,
94};
95
96Command
97steps_cmd = {
98 .name = "steps",
99 .usage = "steps",
100 .description = "List available steps",
101 .parse_args = parse_no_arg,
102 .exec = steps_exec
103};
104
105Command
106commands_cmd = {
107 .name = "commands",
108 .usage = "commands",
109 .description = "List available commands",
110 .parse_args = parse_no_arg,
111 .exec = commands_exec
112};
113
114Command
115freemem_cmd = {
116 .name = "freemem",
117 .usage = "freemem",
118 .description = "free large tables from RAM",
119 .parse_args = parse_no_arg,
120 .exec = freemem_exec,
121};
122
123Command
124print_cmd = {
125 .name = "print",
126 .usage = "print SCRAMBLE",
127 .description = "Print written description of the cube",
128 .parse_args = parse_only_scramble,
129 .exec = print_exec,
130};
131
132Command
133help_cmd = {
134 .name = "help",
135 .usage = "help [COMMAND]",
136 .description = "Display nissy manual page or help on specific command",
137 .parse_args = help_parse_args,
138 .exec = help_exec,
139};
140
141Command
142twophase_cmd = {
143 .name = "twophase",
144 .usage = "twophase",
145 .description = "Find a solution quickly using a 2-phase method",
146 .parse_args = parse_only_scramble,
147 .exec = twophase_exec,
148};
149
150Command
151quit_cmd = {
152 .name = "quit",
153 .usage = "quit",
154 .description = "Quit nissy",
155 .parse_args = parse_no_arg,
156 .exec = quit_exec,
157};
158
159Command
160cleanup_cmd = {
161 .name = "cleanup",
162 .usage = "cleanup SCRAMBLE",
163 .description = "Rewrite a scramble using only standard moves (HTM)",
164 .parse_args = parse_only_scramble,
165 .exec = cleanup_exec,
166};
167
168Command
169unniss_cmd = {
170 .name = "unniss",
171 .usage = "unniss SCRAMBLE",
172 .description = "Rewrite a scramble without NISS",
173 .parse_args = parse_only_scramble,
174 .exec = unniss_exec,
175};
176
177Command
178version_cmd = {
179 .name = "version",
180 .usage = "version",
181 .description = "print nissy version",
182 .parse_args = parse_no_arg,
183 .exec = version_exec,
184};
185
186Command *commands[] = {
187 &commands_cmd,
188 &freemem_cmd,
189 &gen_cmd,
190 &help_cmd,
191 &invert_cmd,
192 &print_cmd,
193 &quit_cmd,
194 &solve_cmd,
195 &scramble_cmd,
196 &steps_cmd,
197 &twophase_cmd,
198 &cleanup_cmd,
199 &unniss_cmd,
200 &version_cmd,
201 NULL
202};
203
204#endif
13 205
14#endif 206#endif
diff --git a/src/coord.c b/src/coord.c
index a9df9fd..06f7474 100644
--- a/src/coord.c
+++ b/src/coord.c
@@ -1,611 +1,683 @@
1#include "coord.h" 1#define COORD_C
2
3static uint64_t index_eofb(Cube cube);
4static uint64_t index_eofbepos(Cube cube);
5static uint64_t index_epud(Cube cube);
6static uint64_t index_coud(Cube cube);
7static uint64_t index_corners(Cube cube);
8static uint64_t index_cp(Cube cube);
9static uint64_t index_cphtr(Cube cube);
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);
17
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);
32 2
33static void init_cphtr_cosets(); 3#include "coord.h"
34static void init_cphtr_left_cosets_bfs(int i, int c);
35static void init_cphtr_right_cosets_color(int i, int c);
36static void init_cpud_separate();
37static void init_cornershtrfin();
38static void init_htr_eposs();
39 4
5static uint64_t indexers_getind(Indexer **is, Cube *c);
6static uint64_t indexers_getmax(Indexer **is);
7static void indexers_makecube(Indexer **is, uint64_t ind, Cube *c);
8static void gen_coord_comp(Coordinate *coord);
9static void gen_coord_sym(Coordinate *coord);
10static bool read_coord_mtable(Coordinate *coord);
11static bool read_coord_sd(Coordinate *coord);
12static bool read_coord_ttable(Coordinate *coord);
13static bool write_coord_mtable(Coordinate *coord);
14static bool write_coord_sd(Coordinate *coord);
15static bool write_coord_ttable(Coordinate *coord);
40 16
41/* All sorts of useful costants and tables **********************************/ 17/* Indexers ******************************************************************/
42 18
43static int cphtr_left_cosets[FACTORIAL8]; 19uint64_t
44static int cphtr_right_cosets[FACTORIAL8]; 20index_eofb(Cube *cube)
45static int cphtr_right_rep[BINOM8ON4*6]; 21{
46int cpud_separate_ind[FACTORIAL8]; 22 return (uint64_t)digit_array_to_int(cube->eo, 11, 2);
47int cpud_separate_ant[BINOM8ON4]; 23}
48static int cornershtrfin_ind[FACTORIAL8];
49int cornershtrfin_ant[24*24/6];
50static int htr_eposs_ind[BINOM12ON4];
51static int htr_eposs_ant[BINOM8ON4];
52 24
53/* Coordinates and their implementation **************************************/ 25uint64_t
26index_coud(Cube *cube)
27{
28 return (uint64_t)digit_array_to_int(cube->co, 7, 3);
29}
54 30
55Coordinate 31uint64_t
56coord_eofb = { 32index_cp(Cube *cube)
57 .index = index_eofb, 33{
58 .max = POW2TO11, 34 return (uint64_t)perm_to_index(cube->cp, 8);
59 .move = move_eofb, 35}
60};
61 36
62Coordinate 37uint64_t
63coord_eofbepos = { 38index_cpudsep(Cube *cube)
64 .index = index_eofbepos, 39{
65 .max = POW2TO11 * BINOM12ON4, 40 int i, c[8];
66 .move = move_eofbepos,
67};
68 41
69Coordinate 42 for (i = 0; i < 8; i++)
70coord_coud = { 43 c[i] = cube->cp[i] < 4 ? 0 : 1;
71 .index = index_coud,
72 .max = POW3TO7,
73 .move = move_coud,
74};
75 44
76Coordinate 45 return (uint64_t)subset_to_index(c, 8, 4);
77coord_corners = { 46}
78 .index = index_corners,
79 .max = POW3TO7 * FACTORIAL8,
80 .move = move_corners,
81};
82 47
83Coordinate 48uint64_t
84coord_cp = { 49index_epe(Cube *cube)
85 .index = index_cp, 50{
86 .max = FACTORIAL8, 51 int i, e[4];
87 .move = move_cp,
88};
89 52
90Coordinate 53 for (i = 0; i < 4; i++)
91coord_cphtr = { 54 e[i] = cube->ep[i+8] - 8;
92 .index = index_cphtr,
93 .max = BINOM8ON4 * 6,
94 .move = move_cphtr,
95};
96 55
97Coordinate 56 return (uint64_t)perm_to_index(e, 4);
98coord_cornershtr = { 57}
99 .index = index_cornershtr,
100 .max = POW3TO7 * BINOM8ON4 * 6,
101 .move = move_cornershtr,
102};
103 58
104Coordinate 59uint64_t
105coord_cornershtrfin = { 60index_epud(Cube *cube)
106 .index = index_cornershtrfin, 61{
107 .max = 24*24/6, 62 return (uint64_t)perm_to_index(cube->ep, 8);
108 .move = move_cornershtrfin, 63}
109};
110 64
111Coordinate 65uint64_t
112coord_epud = { 66index_epos(Cube *cube)
113 .index = index_epud, 67{
114 .max = FACTORIAL8, 68 int i, a[12];
115 .move = move_epud,
116};
117 69
118Coordinate 70 for (i = 0; i < 12; i++)
119coord_drud = { 71 a[i] = (cube->ep[i] < 8) ? 0 : 1;
120 .index = index_drud,
121 .max = POW2TO11 * POW3TO7 * BINOM12ON4,
122 .move = move_drud,
123};
124 72
125Coordinate 73 return (uint64_t)subset_to_index(a, 12, 4);
126coord_htr_drud = { 74}
127 .index = index_htr_drud,
128 .max = BINOM8ON4 * 6 * BINOM8ON4,
129 .move = move_htr_drud,
130};
131 75
132Coordinate 76uint64_t
133coord_htrfin = { 77index_eposepe(Cube *cube)
134 .index = index_htrfin, 78{
135 .max = 24 * 24 * 24 *24 * 24 / 6, /* should be /12 but it's ok */ 79 int i, j, e[4];
136 .move = move_htrfin, 80 uint64_t epos, epe;
137};
138 81
139Coordinate 82 epos = (uint64_t)index_epos(cube);
140coord_drud_eofb = { 83 for (i = 0, j = 0; i < 12; i++)
141 .index = index_drud_eofb, 84 if (cube->ep[i] >= 8)
142 .max = POW3TO7 * BINOM12ON4, 85 e[j++] = cube->ep[i] - 8;
143 .move = move_drud_eofb, 86 epe = (uint64_t)perm_to_index(e, 4);
144};
145 87
146Coordinate 88 return epos * FACTORIAL4 + epe;
147coord_cpud_separate = { 89}
148 .index = index_cpud_separate,
149 .max = BINOM8ON4,
150 .move = move_cpud_separate,
151};
152 90
153/* Indexers ******************************************************************/ 91/* Inverse indexers **********************************************************/
154 92
155static uint64_t 93void
156index_eofb(Cube cube) 94invindex_eofb(uint64_t ind, Cube *cube)
157{ 95{
158 return cube.eofb; 96 int_to_sum_zero_array(ind, 2, 12, cube->eo);
159} 97}
160 98
161static uint64_t 99void
162index_eofbepos(Cube cube) 100invindex_coud(uint64_t ind, Cube *cube)
163{ 101{
164 return (cube.epose / FACTORIAL4) * POW2TO11 + cube.eofb; 102 int_to_sum_zero_array(ind, 3, 8, cube->co);
165} 103}
166 104
167static uint64_t 105void
168index_epud(Cube cube) 106invindex_cp(uint64_t ind, Cube *cube)
169{ 107{
170 uint64_t ret; 108 index_to_perm(ind, 8, cube->cp);
171 CubeArray *arr = new_cubearray(cube, pf_ep);
172
173 ret = perm_to_index(arr->ep, 8);
174 free_cubearray(arr, pf_ep);
175
176 return ret;
177} 109}
178 110
179static uint64_t 111void
180index_coud(Cube cube) 112invindex_cpudsep(uint64_t ind, Cube *cube)
181{ 113{
182 return cube.coud; 114 int i, j, k, c[8];
183}
184 115
185static uint64_t 116 index_to_subset(ind, 8, 4, c);
186index_corners(Cube cube) 117 for (i = 0, j = 0, k = 4; i < 8; i++)
187{ 118 cube->cp[i] = c[i] == 0 ? j++ : k++;
188 return cube.coud * FACTORIAL8 + cube.cp;
189} 119}
190 120
191static uint64_t
192index_cp(Cube cube)
193{
194 return cube.cp;
195}
196 121
197static uint64_t 122void
198index_cphtr(Cube cube) 123invindex_epe(uint64_t ind, Cube *cube)
199{ 124{
200 return cphtr_right_cosets[cube.cp]; 125 int i;
126
127 index_to_perm(ind, 4, &cube->ep[8]);
128 for (i = 0; i < 4; i++)
129 cube->ep[i+8] += 8;
201} 130}
202 131
203static uint64_t 132void
204index_cornershtr(Cube cube) 133invindex_epud(uint64_t ind, Cube *cube)
205{ 134{
206 return cube.coud * BINOM8ON4 * 6 + index_cphtr(cube); 135 index_to_perm(ind, 8, cube->ep);
207} 136}
208 137
209static uint64_t 138void
210index_cornershtrfin(Cube cube) 139invindex_epos(uint64_t ind, Cube *cube)
211{ 140{
212 return cornershtrfin_ind[cube.cp]; 141 int i, j, k;
142
143 index_to_subset(ind, 12, 4, cube->ep);
144 for (i = 0, j = 0, k = 8; i < 12; i++)
145 if (cube->ep[i] == 0)
146 cube->ep[i] = j++;
147 else
148 cube->ep[i] = k++;
213} 149}
214 150
215static uint64_t 151void
216index_drud(Cube cube) 152invindex_eposepe(uint64_t ind, Cube *cube)
217{ 153{
218 uint64_t a, b, c; 154 int i, j, k, e[4];
155 uint64_t epos, epe;
219 156
220 a = cube.eofb; 157 epos = ind / FACTORIAL4;
221 b = cube.coud; 158 epe = ind % FACTORIAL4;
222 c = cube.epose / FACTORIAL4;
223 159
224 b *= POW2TO11; 160 index_to_subset(epos, 12, 4, cube->ep);
225 c *= POW2TO11 * POW3TO7; 161 index_to_perm(epe, 4, e);
226 162
227 return a + b + c; 163 for (i = 0, j = 0, k = 0; i < 12; i++)
164 if (cube->ep[i] == 0)
165 cube->ep[i] = j++;
166 else
167 cube->ep[i] = e[k++] + 8;
228} 168}
229 169
230static uint64_t 170/* Other local functions *****************************************************/
231index_drud_eofb(Cube cube)
232{
233 return index_drud(cube) / POW2TO11;
234}
235 171
236static uint64_t 172static uint64_t
237index_htr_drud(Cube cube) 173indexers_getmax(Indexer **is)
238{ 174{
239 uint64_t a, b; 175 int i;
176 uint64_t max = 1;
240 177
241 a = index_cphtr(cube); 178 for (i = 0; is[i] != NULL; i++)
242 b = htr_eposs_ind[cube.eposs/24]; 179 max *= is[i]->n;
243 180
244 return a * BINOM8ON4 + b; 181 return max;
245} 182}
246 183
247static uint64_t 184static uint64_t
248index_htrfin(Cube cube) 185indexers_getind(Indexer **is, Cube *c)
249{ 186{
250 uint64_t epe, eps, epm, cp, ep; 187 int i;
188 uint64_t max = 0;
251 189
252 epe = cube.epose % 24; 190 for (i = 0; is[i] != NULL; i++) {
253 eps = cube.eposs % 24; 191 max *= is[i]->n;
254 epm = cube.eposm % 24; 192 max += is[i]->index(c);
255 ep = (epe * 24 + eps) *24 + epm; 193 }
256 cp = index_cornershtrfin(cube);
257 194
258 return cp * 24 * 24 * 24 + ep; 195 return max;
259} 196}
260 197
261static uint64_t 198static void
262index_cpud_separate(Cube cube) 199indexers_makecube(Indexer **is, uint64_t ind, Cube *c)
263{ 200{
264 return cpud_separate_ind[cube.cp]; 201 /* Warning: anti-indexers are applied in the same order as indexers. */
265} 202 /* We assume order does not matter, but it would make more sense to */
203 /* Apply them in reverse. */
266 204
267/* Coordinate movers *********************************************************/ 205 int i;
206 uint64_t m;
268 207
269static uint64_t 208 make_solved(c);
270move_eofb(Move m, uint64_t ind) 209 m = indexers_getmax(is);
271{ 210 for (i = 0; is[i] != NULL; i++) {
272 return eofb_mtable[m][ind]; 211 m /= is[i]->n;
212 is[i]->to_cube(ind / m, c);
213 ind %= m;
214 }
273} 215}
274 216
275static uint64_t 217static void
276move_eofbepos(Move m, uint64_t ind) 218gen_coord_comp(Coordinate *coord)
277{ 219{
278 uint64_t a, b; 220 uint64_t ui;
221 Cube c, mvd;
222 Move m;
223 Trans t;
279 224
280 a = epose_mtable[m][(ind / POW2TO11)*24]; 225 coord->max = indexers_getmax(coord->i);
281 b = eofb_mtable[m][ind % POW2TO11];
282 226
283 return (a/24) * POW2TO11 + b; 227 for (m = 0; m < NMOVES; m++)
284} 228 coord->mtable[m] = malloc(coord->max * sizeof(uint64_t));
285 229
286static uint64_t 230 for (t = 0; t < NTRANS; t++)
287move_epud(Move m, uint64_t ind) 231 coord->ttable[t] = malloc(coord->max * sizeof(uint64_t));
288{
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;
298 int j;
299 Move mj;
300 Cube c;
301 CubeArray *arr, *auxarr;
302 232
303 if (!moveset_drud.allowed(m)) { 233 if (!read_coord_mtable(coord)) {
304 fprintf(stderr, "Move not allowed for epud\n" 234 fprintf(stderr, "%s: generating mtable\n", coord->name);
305 "This is a bug, please report\n");
306 return coord_epud.max;
307 }
308 235
309 if (!initialized) { 236 for (ui = 0; ui < coord->max; ui++) {
310 auxarr = malloc(sizeof(CubeArray)); 237 indexers_makecube(coord->i, ui, &c);
311 auxarr->ep = a; 238 for (m = 0; m < NMOVES; m++) {
312 for (ui = 0; ui < coord_epud.max; ui++) { 239 copy_cube(&c, &mvd);
313 index_to_perm(ui, 8, a); 240 apply_move(m, &mvd);
314 c = arrays_to_cube(auxarr, pf_ep); 241 coord->mtable[m][ui] =
315 for (j = 0; moveset_drud.sorted_moves[j] != NULLMOVE; 242 indexers_getind(coord->i, &mvd);
316 j++) {
317 mj = moveset_drud.sorted_moves[j];
318 arr = new_cubearray(apply_move(mj, c), pf_ep);
319 aux[shortlist[mj]][ui] =
320 perm_to_index(arr->ep, 8);
321 free_cubearray(arr, pf_ep);
322 } 243 }
323 } 244 }
324 free(auxarr); 245 if (!write_coord_mtable(coord))
325 246 fprintf(stderr, "%s: error writing mtable\n",
326 initialized = true; 247 coord->name);
248
249 fprintf(stderr, "%s: mtable generated\n", coord->name);
327 } 250 }
328 251
329 return aux[shortlist[m]][ind]; 252 if (!read_coord_ttable(coord)) {
330} 253 fprintf(stderr, "%s: generating ttable\n", coord->name);
331 254
332static uint64_t 255 for (ui = 0; ui < coord->max; ui++) {
333move_coud(Move m, uint64_t ind) 256 indexers_makecube(coord->i, ui, &c);
334{ 257 for (t = 0; t < NTRANS; t++) {
335 return coud_mtable[m][ind]; 258 copy_cube(&c, &mvd);
259 apply_trans(t, &mvd);
260 coord->ttable[t][ui] =
261 indexers_getind(coord->i, &mvd);
262 }
263 }
264 if (!write_coord_ttable(coord))
265 fprintf(stderr, "%s: error writing ttable\n",
266 coord->name);
267 }
336} 268}
337 269
338static uint64_t 270static void
339move_corners(Move m, uint64_t ind) 271gen_coord_sym(Coordinate *coord)
340{ 272{
341 uint64_t a, b; 273 uint64_t i, in, ui, uj, uu, M, nr;
274 int j;
275 Move m;
276 Trans t;
342 277
343 a = coud_mtable[m][ind / FACTORIAL8]; 278 M = coord->base[0]->max;
344 b = cp_mtable[m][ind % FACTORIAL8]; 279 coord->selfsim = malloc(M * sizeof(uint64_t));
280 coord->symclass = malloc(M * sizeof(uint64_t));
281 coord->symrep = malloc(M * sizeof(uint64_t));
282 coord->transtorep = malloc(M * sizeof(Trans));
345 283
346 return a * FACTORIAL8 + b; 284 if (!read_coord_sd(coord)) {
347} 285 fprintf(stderr, "%s: generating syms\n", coord->name);
348 286
349static uint64_t 287 for (i = 0; i < M; i++)
350move_cp(Move m, uint64_t ind) 288 coord->symclass[i] = M+1;
351{
352 return cp_mtable[m][ind];
353}
354 289
355static uint64_t 290 for (i = 0, nr = 0; i < M; i++) {
356move_cphtr(Move m, uint64_t ind) 291 if (coord->symclass[i] != M+1)
357{ 292 continue;
358 static bool initialized = false; 293
359 static uint64_t aux[NMOVES][BINOM8ON4*6]; 294 coord->symrep[nr] = i;
360 uint64_t ui; 295 coord->transtorep[i] = uf;
361 Move j; 296 coord->selfsim[nr] = (uint64_t)0;
297 for (j = 0; j < coord->tgrp->n; j++) {
298 t = coord->tgrp->t[j];
299 in = trans_coord(coord->base[0], t, i);
300 coord->symclass[in] = nr;
301 if (in == i)
302 coord->selfsim[nr] |= ((uint64_t)1<<t);
303 else
304 coord->transtorep[in] =
305 inverse_trans(t);
306 }
307 nr++;
308 }
309
310 coord->max = nr;
311
312 fprintf(stderr, "%s: found %" PRIu64 " classes\n",
313 coord->name, nr);
314 if (!write_coord_sd(coord))
315 fprintf(stderr, "%s: error writing symdata\n",
316 coord->name);
317 }
362 318
363 if (!initialized) { 319 coord->symrep = realloc(coord->symrep, coord->max*sizeof(uint64_t));
364 for (ui = 0; ui < BINOM8ON4*6; ui++) 320 coord->selfsim = realloc(coord->selfsim, coord->max*sizeof(uint64_t));
365 for (j = U; j < NMOVES; j++)
366 aux[j][ui] = cphtr_right_cosets[
367 cp_mtable[j][cphtr_right_rep[ui]]];
368 321
369 initialized = true; 322 for (m = 0; m < NMOVES; m++) {
323 coord->mtable[m] = malloc(coord->max*sizeof(uint64_t));
324 coord->ttrep_move[m] = malloc(coord->max*sizeof(Trans));
370 } 325 }
371 326
372 return aux[m][ind]; 327 if (!read_coord_mtable(coord)) {
328 for (ui = 0; ui < coord->max; ui++) {
329 uu = coord->symrep[ui];
330 for (m = 0; m < NMOVES; m++) {
331 uj = move_coord(coord->base[0], m, uu, NULL);
332 coord->mtable[m][ui] = coord->symclass[uj];
333 coord->ttrep_move[m][ui] =
334 coord->transtorep[uj];
335 }
336 }
337 if (!write_coord_mtable(coord))
338 fprintf(stderr, "%s: error writing mtable\n",
339 coord->name);
340 }
373} 341}
374 342
375static uint64_t 343static bool
376move_cornershtr(Move m, uint64_t ind) 344read_coord_mtable(Coordinate *coord)
377{ 345{
378 uint64_t a, b; 346 FILE *f;
347 char fname[strlen(tabledir)+256];
348 Move m;
349 uint64_t M;
350 bool r;
379 351
380 a = coud_mtable[m][ind/(BINOM8ON4 * 6)]; 352 strcpy(fname, tabledir);
381 b = move_cphtr(m, ind % (BINOM8ON4 * 6)); 353 strcat(fname, "/mt_");
354 strcat(fname, coord->name);
382 355
383 return a * BINOM8ON4 * 6 + b; 356 if ((f = fopen(fname, "rb")) == NULL)
384} 357 return false;
385 358
386static uint64_t 359 M = coord->max;
387move_cornershtrfin(Move m, uint64_t ind) 360 r = true;
388{ 361 for (m = 0; m < NMOVES; m++)
389 int a; 362 r = r && fread(coord->mtable[m], sizeof(uint64_t), M, f) == M;
390 363
391 a = cp_mtable[m][cornershtrfin_ant[ind]]; 364 if (coord->type == SYM_COORD)
365 for (m = 0; m < NMOVES; m++)
366 r = r && fread(coord->ttrep_move[m],
367 sizeof(Trans), M, f) == M;
392 368
393 return cornershtrfin_ind[a]; 369 fclose(f);
370 return r;
394} 371}
395 372
396static uint64_t 373static bool
397move_drud(Move m, uint64_t ind) 374read_coord_sd(Coordinate *coord)
398{ 375{
399 uint64_t a, b, c; 376 FILE *f;
377 char fname[strlen(tabledir)+256];
378 uint64_t M, N;
379 bool r;
380
381 strcpy(fname, tabledir);
382 strcat(fname, "/sd_");
383 strcat(fname, coord->name);
400 384
401 a = eofb_mtable[m][ind % POW2TO11]; 385 if ((f = fopen(fname, "rb")) == NULL)
402 b = coud_mtable[m][(ind / POW2TO11) % POW3TO7]; 386 return false;
403 c = epose_mtable[m][ind / (POW2TO11 * POW3TO7)];
404 387
405 return a + (b + c * POW3TO7) * POW2TO11; 388 r = true;
389 r = r && fread(&coord->max, sizeof(uint64_t), 1, f) == 1;
390 M = coord->max;
391 N = coord->base[0]->max;
392 r = r && fread(coord->symrep, sizeof(uint64_t), M, f) == M;
393 r = r && fread(coord->selfsim, sizeof(uint64_t), M, f) == M;
394 r = r && fread(coord->symclass, sizeof(uint64_t), N, f) == N;
395 r = r && fread(coord->transtorep, sizeof(Trans), N, f) == N;
396
397 fclose(f);
398 return r;
406} 399}
407 400
408static uint64_t 401static bool
409move_drud_eofb(Move m, uint64_t ind) 402read_coord_ttable(Coordinate *coord)
410{ 403{
411 uint64_t a, b; 404 FILE *f;
405 char fname[strlen(tabledir)+256];
406 Trans t;
407 uint64_t M;
408 bool r;
409
410 strcpy(fname, tabledir);
411 strcat(fname, "/tt_");
412 strcat(fname, coord->name);
412 413
413 a = coud_mtable[m][ind % POW3TO7]; 414 if ((f = fopen(fname, "rb")) == NULL)
414 b = epose_mtable[m][(ind / POW3TO7) * 24] / 24; 415 return false;
415 416
416 return a + b * POW3TO7; 417 M = coord->max;
418 r = true;
419 for (t = 0; t < NTRANS; t++)
420 r = r && fread(coord->ttable[t], sizeof(uint64_t), M, f) == M;
421
422 fclose(f);
423 return r;
417} 424}
418 425
419static uint64_t 426static bool
420move_htr_drud(Move m, uint64_t ind) 427write_coord_mtable(Coordinate *coord)
421{ 428{
422 uint64_t a, b; 429 FILE *f;
430 char fname[strlen(tabledir)+256];
431 Move m;
432 uint64_t M;
433 bool r;
434
435 strcpy(fname, tabledir);
436 strcat(fname, "/mt_");
437 strcat(fname, coord->name);
438
439 if ((f = fopen(fname, "wb")) == NULL)
440 return false;
423 441
424 a = move_cphtr(m, ind/BINOM8ON4); 442 M = coord->max;
425 b = eposs_mtable[m][htr_eposs_ant[ind%BINOM8ON4]]; 443 r = true;
444 for (m = 0; m < NMOVES; m++)
445 r = r && fwrite(coord->mtable[m], sizeof(uint64_t), M, f) == M;
426 446
427 return a*BINOM8ON4 + htr_eposs_ind[b/24]; 447 if (coord->type == SYM_COORD)
448 for (m = 0; m < NMOVES; m++)
449 r = r && fwrite(coord->ttrep_move[m],
450 sizeof(Trans), M, f) == M;
451
452 fclose(f);
453 return r;
428} 454}
429 455
430static uint64_t 456static bool
431move_htrfin(Move m, uint64_t ind) 457write_coord_sd(Coordinate *coord)
432{ 458{
433 uint64_t a, b, bm, bs, be; 459 FILE *f;
460 char fname[strlen(tabledir)+256];
461 uint64_t M, N;
462 bool r;
434 463
435 a = move_cornershtrfin(m, ind / (24*24*24)); 464 strcpy(fname, tabledir);
436 bm = eposm_mtable[m][ind%24] % 24; 465 strcat(fname, "/sd_");
437 bs = eposs_mtable[m][(ind/24)%24] % 24; 466 strcat(fname, coord->name);
438 be = epose_mtable[m][(ind/(24*24))%24] % 24;
439 b = (be * 24 + bs) * 24 + bm;
440 467
441 return a * (24*24*24) + b; 468 if ((f = fopen(fname, "wb")) == NULL)
469 return false;
470
471 r = true;
472 M = coord->max;
473 N = coord->base[0]->max;
474 r = r && fwrite(&coord->max, sizeof(uint64_t), 1, f) == 1;
475 r = r && fwrite(coord->symrep, sizeof(uint64_t), M, f) == M;
476 r = r && fwrite(coord->selfsim, sizeof(uint64_t), M, f) == M;
477 r = r && fwrite(coord->symclass, sizeof(uint64_t), N, f) == N;
478 r = r && fwrite(coord->transtorep, sizeof(Trans), N, f) == N;
479
480 fclose(f);
481 return r;
442} 482}
443 483
444static uint64_t 484static bool
445move_cpud_separate(Move m, uint64_t ind) 485write_coord_ttable(Coordinate *coord)
446{ 486{
447 return cpud_separate_ind[cp_mtable[m][cpud_separate_ant[ind]]]; 487 FILE *f;
488 char fname[strlen(tabledir)+256];
489 Trans t;
490 uint64_t M;
491 bool r;
492
493 strcpy(fname, tabledir);
494 strcat(fname, "/tt_");
495 strcat(fname, coord->name);
496
497 if ((f = fopen(fname, "wb")) == NULL)
498 return false;
499
500 M = coord->max;
501 r = true;
502 for (t = 0; t < NTRANS; t++)
503 r = r && fwrite(coord->ttable[t], sizeof(uint64_t), M, f) == M;
504
505 fclose(f);
506 return r;
448} 507}
449 508
450/* Init functions implementation *********************************************/ 509/* Public functions **********************************************************/
451 510
452/* 511void
453 * There is certainly a better way to do this, but for now I just use 512gen_coord(Coordinate *coord)
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{ 513{
468 unsigned int i; 514 int i;
469 int c = 0, d = 0; 515
516 if (coord == NULL || coord->generated)
517 return;
518
519 for (i = 0; i < 2; i++)
520 gen_coord(coord->base[i]);
470 521
471 for (i = 0; i < FACTORIAL8; i++) { 522 switch (coord->type) {
472 cphtr_left_cosets[i] = -1; 523 case COMP_COORD:
473 cphtr_right_cosets[i] = -1; 524 if (coord->i[0] == NULL)
525 goto error_gc;
526 gen_coord_comp(coord);
527 break;
528 case SYM_COORD:
529 if (coord->base[0] == NULL || coord->tgrp == NULL)
530 goto error_gc;
531 gen_coord_sym(coord);
532 break;
533 case SYMCOMP_COORD:
534 if (coord->base[0] == NULL || coord->base[1] == NULL)
535 goto error_gc;
536 coord->max = coord->base[0]->max * coord->base[1]->max;
537 break;
538 default:
539 break;
474 } 540 }
475 541
476 /* First we compute left cosets with a bfs */ 542 coord->generated = true;
477 for (i = 0; i < FACTORIAL8; i++) 543 return;
478 if (cphtr_left_cosets[i] == -1)
479 init_cphtr_left_cosets_bfs(i, c++);
480 544
481 /* Then we compute right cosets using compose() */ 545error_gc:
482 for (i = 0; i < FACTORIAL8; i++) 546 fprintf(stderr, "Error generating coordinates.\n"
483 if (cphtr_right_cosets[i] == -1) 547 "This is a bug, pleae report.\n");
484 init_cphtr_right_cosets_color(i, d++); 548 exit(1);
485} 549}
486 550
487static void 551uint64_t
488init_cphtr_left_cosets_bfs(int i, int c) 552index_coord(Coordinate *coord, Cube *cube, Trans *offtrans)
489{ 553{
490 int j, jj, next[FACTORIAL8], next2[FACTORIAL8], n, n2; 554 uint64_t c[2], cnosym;
555 Trans ttr;
491 556
492 Move k; 557 switch (coord->type) {
558 case COMP_COORD:
559 if (offtrans != NULL)
560 *offtrans = uf;
493 561
494 n = 1; 562 return indexers_getind(coord->i, cube);
495 next[0] = i; 563 case SYM_COORD:
496 cphtr_left_cosets[i] = c; 564 cnosym = index_coord(coord->base[0], cube, NULL);
565 ttr = coord->transtorep[cnosym];
497 566
498 while (n != 0) { 567 if (offtrans != NULL)
499 for (j = 0, n2 = 0; j < n; j++) { 568 *offtrans = ttr;
500 for (k = U2; k < B3; k++) {
501 if (!moveset_htr.allowed(k))
502 continue;
503 jj = apply_move(k, (Cube){ .cp = next[j] }).cp;
504 569
505 if (cphtr_left_cosets[jj] == -1) { 570 return coord->symclass[cnosym];
506 cphtr_left_cosets[jj] = c; 571 case SYMCOMP_COORD:
507 next2[n2++] = jj; 572 c[0] = index_coord(coord->base[0], cube, NULL);
508 } 573 cnosym = index_coord(coord->base[0]->base[0], cube, NULL);
509 } 574 ttr = coord->base[0]->transtorep[cnosym];
510 } 575 c[1] = index_coord(coord->base[1], cube, NULL);
576 c[1] = trans_coord(coord->base[1], ttr, c[1]);
511 577
512 for (j = 0; j < n2; j++) 578 if (offtrans != NULL)
513 next[j] = next2[j]; 579 *offtrans = ttr;
514 n = n2; 580
581 return c[0] * coord->base[1]->max + c[1];
582 default:
583 break;
515 } 584 }
585
586 return coord->max; /* Only reached in case of error */
516} 587}
517 588
518static void 589uint64_t
519init_cphtr_right_cosets_color(int i, int d) 590move_coord(Coordinate *coord, Move m, uint64_t ind, Trans *offtrans)
520{ 591{
521 int cp; 592 uint64_t i[2], M;
522 unsigned int j; 593 Trans ttr;
523 594
524 cphtr_right_rep[d] = i; 595 /* Some safety checks should be done here, but for performance *
525 for (j = 0; j < FACTORIAL8; j++) { 596 * reasons we'd rather do them before calling this function. *
526 if (cphtr_left_cosets[j] == 0) { 597 * We should check if coord is generated. */
527 cp = compose((Cube){.cp = i}, (Cube){.cp = j}).cp;
528 cphtr_right_cosets[cp] = d;
529 }
530 }
531}
532 598
533static void 599 switch (coord->type) {
534init_cpud_separate() 600 case COMP_COORD:
535{ 601 if (offtrans != NULL)
536 unsigned int ui; 602 *offtrans = uf;
537 int i, co[8];
538 603
539 for (ui = 0; ui < FACTORIAL8; ui++) { 604 return coord->mtable[m][ind];
540 for (i = 0; i < 8; i++) 605 case SYM_COORD:
541 co[i] = what_corner_at((Cube){.cp=ui},i)>UBR ? 1 : 0; 606 ttr = coord->ttrep_move[m][ind];
542 cpud_separate_ind[ui] = subset_to_index(co, 8, 4);
543 cpud_separate_ant[cpud_separate_ind[ui]] = ui;
544 }
545}
546 607
547static void 608 if (offtrans != NULL)
548init_cornershtrfin() 609 *offtrans = ttr;
549{
550 unsigned int i, j;
551 int n, c;
552 Move m;
553 610
554 for (i = 0; i < FACTORIAL8; i++) 611 return coord->mtable[m][ind];
555 cornershtrfin_ind[i] = -1; 612 case SYMCOMP_COORD:
556 cornershtrfin_ind[0] = 0; 613 M = coord->base[1]->max;
614 i[0] = ind / M;
615 i[1] = ind % M;
616 ttr = coord->base[0]->ttrep_move[m][i[0]];
617 i[0] = coord->base[0]->mtable[m][i[0]];
618 i[1] = coord->base[1]->mtable[m][i[1]];
619 i[1] = coord->base[1]->ttable[ttr][i[1]];
557 620
558 /* 10-pass, I think 5 is enough, but just in case */ 621 if (offtrans != NULL)
559 n = 1; 622 *offtrans = ttr;
560 for (i = 0; i < 10; i++) { 623
561 for (j = 0; j < FACTORIAL8; j++) { 624 return i[0] * M + i[1];
562 if (cornershtrfin_ind[j] == -1) 625 default:
563 continue; 626 break;
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 }
575 } 627 }
628
629 return coord->max; /* Only reached in case of error */
576} 630}
577 631
578void 632bool
579init_htr_eposs() 633test_coord(Coordinate *coord)
580{ 634{
581 int ep[12], ep2[12]; 635 uint64_t ui, uj;
582 int eps_solved[4] = {UL, UR, DL, DR}; 636 Cube c;
583 unsigned int i, j;
584 637
585 for (i = 0; i < BINOM12ON4; i++) { 638 if (coord->type != COMP_COORD) {
586 for (j = 0; j < 12; j++) 639 fprintf(stderr, "Can only test COMP_COORD\n");
587 ep[j] = ep2[j] = 0; 640 return false;
588 epos_to_partial_ep(i*24, ep, eps_solved);
589 for (j = 0; j < 8; j++)
590 ep2[j/2 + 4*(j%2)] = ep[j] ? 1 : 0;
591 htr_eposs_ind[i] = subset_to_index(ep2, 8, 4);
592 htr_eposs_ant[htr_eposs_ind[i]] = i*24;
593 } 641 }
642
643 gen_coord(coord);
644 for (ui = 0; ui < coord->max; ui++) {
645 indexers_makecube(coord->i, ui, &c);
646 uj = indexers_getind(coord->i, &c);
647 if (ui != uj) {
648 fprintf(stderr, "%s: error: %" PRIu64 " different"
649 " from %" PRIu64 "\n", coord->name, uj, ui);
650 return false;
651 }
652 }
653
654 fprintf(stderr, "%s: test passed\n", coord->name);
655 return true;
594} 656}
595 657
596void 658uint64_t
597init_coord() 659trans_coord(Coordinate *coord, Trans t, uint64_t ind)
598{ 660{
599 static bool initialized = false; 661 uint64_t i[2], M;
600 if (initialized)
601 return;
602 initialized = true;
603 662
604 init_trans(); 663 /* Some safety checks should be done here, but for performance *
664 * reasons we'd rather do them before calling this function. *
665 * We should check if coord is generated. */
605 666
606 init_cphtr_cosets(); 667 switch (coord->type) {
607 init_cornershtrfin(); 668 case COMP_COORD:
608 init_htr_eposs(); 669 return coord->ttable[t][ind];
609 init_cpud_separate(); 670 case SYM_COORD:
610} 671 return ind;
672 case SYMCOMP_COORD:
673 M = coord->base[1]->max;
674 i[0] = ind / M; /* Always fixed */
675 i[1] = ind % M;
676 i[1] = coord->base[1]->ttable[t][i[1]];
677 return i[0] * M + i[1];
678 default:
679 break;
680 }
611 681
682 return coord->max; /* Only reached in case of error */
683}
diff --git a/src/coord.h b/src/coord.h
index 61398a4..47c0579 100644
--- a/src/coord.h
+++ b/src/coord.h
@@ -3,26 +3,232 @@
3 3
4#include "trans.h" 4#include "trans.h"
5 5
6extern Coordinate coord_eofb; 6void gen_coord(Coordinate *coord);
7extern Coordinate coord_eofbepos; 7uint64_t index_coord(Coordinate *coord, Cube *cube,
8extern Coordinate coord_coud; 8 Trans *offtrans);
9extern Coordinate coord_cp; 9uint64_t move_coord(Coordinate *coord, Move m,
10extern Coordinate coord_cphtr; 10 uint64_t ind, Trans *offtrans);
11extern Coordinate coord_corners; 11bool test_coord(Coordinate *coord);
12extern Coordinate coord_cornershtr; 12uint64_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;
20 13
21extern int cpud_separate_ant[BINOM8ON4]; 14/* Base coordinates and their index functions ********************************/
22extern int cpud_separate_ind[FACTORIAL8];
23extern int cornershtrfin_ant[24*24/6];
24 15
25void init_coord(); 16#ifndef COORD_C
17
18extern Coordinate coord_eofb;
19extern Coordinate coord_coud;
20extern Coordinate coord_cp;
21extern Coordinate coord_cpudsep;
22extern Coordinate coord_epos;
23extern Coordinate coord_epe;
24extern Coordinate coord_eposepe;
25extern Coordinate coord_epud;
26extern Coordinate coord_eofbepos;
27extern Coordinate coord_coud_cpudsep;
28extern Coordinate coord_eofbepos_sym16;
29extern Coordinate coord_cp_sym16;
30extern Coordinate coord_corners_sym16;
31extern Coordinate coord_drud_sym16;
32extern Coordinate coord_drudfin_noE_sym16;
33extern Coordinate coord_nxopt31;
34
35#else
36
37/* Indexers ******************************************************************/
38
39uint64_t index_eofb(Cube *cube);
40void invindex_eofb(uint64_t ind, Cube *ret);
41Indexer
42i_eofb = {
43 .n = POW2TO11,
44 .index = index_eofb,
45 .to_cube = invindex_eofb,
46};
47
48uint64_t index_coud(Cube *cube);
49void invindex_coud(uint64_t ind, Cube *ret);
50Indexer
51i_coud = {
52 .n = POW3TO7,
53 .index = index_coud,
54 .to_cube = invindex_coud,
55};
56
57uint64_t index_cp(Cube *cube);
58void invindex_cp(uint64_t ind, Cube *ret);
59Indexer
60i_cp = {
61 .n = FACTORIAL8,
62 .index = index_cp,
63 .to_cube = invindex_cp,
64};
65
66uint64_t index_cpudsep(Cube *cube);
67void invindex_cpudsep(uint64_t ind, Cube *ret);
68Indexer
69i_cpudsep = {
70 .n = BINOM8ON4,
71 .index = index_cpudsep,
72 .to_cube = invindex_cpudsep,
73};
74
75uint64_t index_epos(Cube *cube);
76void invindex_epos(uint64_t ind, Cube *ret);
77Indexer
78i_epos = {
79 .n = BINOM12ON4,
80 .index = index_epos,
81 .to_cube = invindex_epos,
82};
83
84uint64_t index_epe(Cube *cube);
85void invindex_epe(uint64_t ind, Cube *ret);
86Indexer
87i_epe = {
88 .n = FACTORIAL4,
89 .index = index_epe,
90 .to_cube = invindex_epe,
91};
92
93uint64_t index_eposepe(Cube *cube);
94void invindex_eposepe(uint64_t ind, Cube *ret);
95Indexer
96i_eposepe = {
97 .n = BINOM12ON4 * FACTORIAL4,
98 .index = index_eposepe,
99 .to_cube = invindex_eposepe,
100};
101
102uint64_t index_epud(Cube *cube);
103void invindex_epud(uint64_t ind, Cube *ret);
104Indexer
105i_epud = {
106 .n = FACTORIAL8,
107 .index = index_epud,
108 .to_cube = invindex_epud,
109};
110
111/* Composite coordinates *****************************************************/
112
113Coordinate
114coord_eofb = {
115 .name = "eofb",
116 .type = COMP_COORD,
117 .i = {&i_eofb, NULL},
118};
119
120Coordinate
121coord_coud = {
122 .name = "coud",
123 .type = COMP_COORD,
124 .i = {&i_coud, NULL},
125};
126
127Coordinate
128coord_cp = {
129 .name = "cp",
130 .type = COMP_COORD,
131 .i = {&i_cp, NULL},
132};
133
134Coordinate
135coord_cpudsep = {
136 .name = "cpudsep",
137 .type = COMP_COORD,
138 .i = {&i_cpudsep, NULL},
139};
140
141Coordinate
142coord_epos = {
143 .name = "epos",
144 .type = COMP_COORD,
145 .i = {&i_epos, NULL},
146};
147
148Coordinate
149coord_epe = {
150 .name = "epe",
151 .type = COMP_COORD,
152 .i = {&i_epe, NULL},
153};
154
155Coordinate
156coord_eposepe = { /* Has to be done by hand, hard compose epos + epe */
157 .name = "eposepe",
158 .type = COMP_COORD,
159 .i = {&i_eposepe, NULL},
160};
161
162Coordinate
163coord_epud = {
164 .name = "epud",
165 .type = COMP_COORD,
166 .i = {&i_epud, NULL},
167};
168
169Coordinate
170coord_eofbepos = {
171 .name = "eofbepos",
172 .type = COMP_COORD,
173 .i = {&i_epos, &i_eofb, NULL},
174};
175
176Coordinate
177coord_coud_cpudsep = {
178 .name = "coud_cpudsep",
179 .type = COMP_COORD,
180 .i = {&i_coud, &i_cpudsep, NULL},
181};
182
183/* Symcoordinates ************************************************************/
184
185Coordinate
186coord_eofbepos_sym16 = {
187 .name = "eofbepos_sym16",
188 .type = SYM_COORD,
189 .base = {&coord_eofbepos, NULL},
190 .tgrp = &tgrp_udfix,
191};
192
193Coordinate
194coord_cp_sym16 = {
195 .name = "cp_sym16",
196 .type = SYM_COORD,
197 .base = {&coord_cp, NULL},
198 .tgrp = &tgrp_udfix,
199};
200
201/* "Symcomp" coordinates *****************************************************/
202
203Coordinate
204coord_corners_sym16 = {
205 .name = "corners_sym16",
206 .type = SYMCOMP_COORD,
207 .base = {&coord_cp_sym16, &coord_coud},
208};
209
210Coordinate
211coord_drud_sym16 = {
212 .name = "drud_sym16",
213 .type = SYMCOMP_COORD,
214 .base = {&coord_eofbepos_sym16, &coord_coud},
215};
216
217Coordinate
218coord_drudfin_noE_sym16 = {
219 .name = "drudfin_noE_sym16",
220 .type = SYMCOMP_COORD,
221 .base = {&coord_cp_sym16, &coord_epud},
222};
223
224Coordinate
225coord_nxopt31 = {
226 .name = "nxopt31",
227 .type = SYMCOMP_COORD,
228 .base = {&coord_eofbepos_sym16, &coord_coud_cpudsep},
229};
230
231#endif
26 232
27#endif 233#endif
28 234
diff --git a/src/cube.c b/src/cube.c
index aae3a6e..0ccffa4 100644
--- a/src/cube.c
+++ b/src/cube.c
@@ -1,531 +1,121 @@
1#include "cube.h" 1#define CUBE_C
2
3/* Local functions ***********************************************************/
4
5static void init_inverse();
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)
22{
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);
40}
41
42Cube
43arrays_to_cube(CubeArray *arr, PieceFilter f)
44{
45 Cube ret = {0};
46
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 2
51 if (f.epose) 3#include "cube.h"
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;
75}
76 4
77Cube 5void
78compose_filtered(Cube c2, Cube c1, PieceFilter f) 6compose(Cube *c2, Cube *c1)
79{ 7{
80 CubeArray *arr = new_cubearray(c2, f); 8 apply_permutation(c2->ep, c1->ep, 12);
81 Cube ret; 9 apply_permutation(c2->ep, c1->eo, 12);
10 sum_arrays_mod(c2->eo, c1->eo, 12, 2);
82 11
83 ret = move_via_arrays(arr, c1, f); 12 apply_permutation(c2->cp, c1->cp, 8);
84 free_cubearray(arr, f); 13 apply_permutation(c2->cp, c1->co, 8);
14 sum_arrays_mod(c2->co, c1->co, 8, 3);
85 15
86 return ret; 16 apply_permutation(c2->xp, c1->xp, 6);
87} 17}
88 18
89void 19void
90cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f) 20copy_cube(Cube *src, Cube *dst)
91{ 21{
92 int i; 22 memcpy(dst->ep, src->ep, 12 * sizeof(int));
93 23 memcpy(dst->eo, src->eo, 12 * sizeof(int));
94 static int epe_solved[4] = {FR, FL, BL, BR}; 24 memcpy(dst->cp, src->cp, 8 * sizeof(int));
95 static int eps_solved[4] = {UL, UR, DL, DR}; 25 memcpy(dst->co, src->co, 8 * sizeof(int));
96 static int epm_solved[4] = {UF, UB, DF, DB}; 26 memcpy(dst->xp, src->xp, 6 * sizeof(int));
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);
124} 27}
125 28
126void 29bool
127epos_to_compatible_ep(int epos, int *ep, int *ss) 30equal(Cube *c1, Cube *c2)
128{ 31{
129 int i, j, k, other[8]; 32 int i;
130 bool flag;
131 33
132 for (i = 0; i < 12; i++) 34 for (i = 0; i < 12; i++)
133 ep[i] = -1; 35 if (c1->ep[i] != c2->ep[i] || c1->eo[i] != c2->eo[i])
134 36 return false;
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++];
148}
149
150void
151epos_to_partial_ep(int epos, int *ep, int *ss)
152{
153 int i, is, eposs[12], eps[4];
154 37
155 index_to_perm(epos % FACTORIAL4, 4, eps); 38 for (i = 0; i < 8; i++)
156 index_to_subset(epos / FACTORIAL4, 12, 4, eposs); 39 if (c1->cp[i] != c2->cp[i] || c1->co[i] != c2->co[i])
40 return false;
157 41
158 for (i = 0; i < 4; i++) 42 for (i = 0; i < 6; i++)
159 swap(&eposs[ss[i]], &eposs[i+8]); 43 if (c1->xp[i] != c2->xp[i])
44 return false;
160 45
161 for (i = 0, is = 0; i < 12; i++) 46 return true;
162 if (eposs[i])
163 ep[i] = ss[eps[is++]];
164} 47}
165 48
166void 49void
167fix_eorleoud(CubeArray *arr) 50invert_cube(Cube *cube)
168{ 51{
52 Cube aux;
169 int i; 53 int i;
170 54
171 for (i = 0; i < 12; i++) { 55 copy_cube(cube, &aux);
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 56
179 if ((edge_slice(i) == 2 && edge_slice(arr->ep[i]) != 2) || 57 for (i = 0; i < 12; i++) {
180 (edge_slice(i) != 2 && edge_slice(arr->ep[i]) == 2)) { 58 cube->ep[aux.ep[i]] = i;
181 arr->eoud[i] = 1 - arr->eofb[i]; 59 cube->eo[aux.ep[i]] = aux.eo[i];
182 } else {
183 arr->eoud[i] = arr->eofb[i];
184 }
185 } 60 }
186}
187
188void
189fix_cofbcorl(CubeArray *arr)
190{
191 int i;
192 61
193 for (i = 0; i < 8; i++) { 62 for (i = 0; i < 8; i++) {
194 if (i % 2 == arr->cp[i] % 2) { 63 cube->cp[aux.cp[i]] = i;
195 arr->cofb[i] = arr->coud[i]; 64 cube->co[aux.cp[i]] = (3 - aux.co[i]) % 3;
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 } 65 }
207}
208
209Cube
210fourval_to_cube(int eofb, int ep, int coud, int cp)
211{
212 CubeArray *arr;
213
214 arr = new_cubearray((Cube){0}, pf_all);
215 66
216 index_to_perm(ep, 12, arr->ep); 67 for (i = 0; i < 6; i++)
217 index_to_perm(cp, 8, arr->cp); 68 cube->xp[aux.xp[i]] = i;
218 int_to_sum_zero_array(eofb, 2, 12, arr->eofb);
219 int_to_sum_zero_array(coud, 3, 8, arr->coud);
220
221 /* fix parity */
222 if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8))
223 swap(&(arr->ep[0]), &(arr->ep[1]));
224
225 fix_eorleoud(arr);
226 fix_cofbcorl(arr);
227
228 return arrays_to_cube(arr, pf_all);
229}
230
231void
232free_cubearray(CubeArray *arr, PieceFilter f)
233{
234 if (f.epose || f.eposs || f.eposm)
235 free(arr->ep);
236 if (f.eofb)
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);
252
253 free(arr);
254}
255
256Cube
257move_via_arrays(CubeArray *arr, Cube c, PieceFilter f)
258{
259 CubeArray *arrc = new_cubearray(c, f);
260 Cube ret;
261
262 if (f.epose || f.eposs || f.eposm)
263 apply_permutation(arr->ep, arrc->ep, 12);
264
265 if (f.eofb) {
266 apply_permutation(arr->ep, arrc->eofb, 12);
267 sum_arrays_mod(arr->eofb, arrc->eofb, 12, 2);
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;
305}
306
307CubeArray *
308new_cubearray(Cube cube, PieceFilter f)
309{
310 CubeArray *arr = malloc(sizeof(CubeArray));
311
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));
330
331 cube_to_arrays(cube, arr, f);
332
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++;
352 }
353
354 ret = arrays_to_cube(arr, pf_ep);
355 free_cubearray(arr, f);
356
357 return ret;
358}
359
360Cube
361compose(Cube c2, Cube c1)
362{
363 return compose_filtered(c2, c1, pf_all);
364}
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;
377}
378
379bool
380equal(Cube c1, Cube c2)
381{
382 return c1.eofb == c2.eofb &&
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];
397
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);
402
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];
417
418 return ret;
419} 69}
420 70
421bool 71bool
422is_admissible(Cube cube) { 72is_admissible(Cube *c) {
423
424 /* TODO: this should check consistency of different orientations */
425 /* check also that centers are opposite and admissible */
426
427 CubeArray *a = new_cubearray(cube, pf_all);
428 int parity;
429 bool perm; 73 bool perm;
74 int sign, i;
75 int sum_e, sum_c;
430 76
431 perm = is_perm(a->ep, 12) && 77 perm = is_perm(c->ep, 12) && is_perm(c->cp, 8) && is_perm(c->xp, 6);
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 78
440 return perm && parity % 2 == 0; 79 sign = perm_sign(c->ep,12) + perm_sign(c->cp,8) + perm_sign(c->xp,6);
441}
442
443bool
444is_solved(Cube cube)
445{
446 return equal(cube, (Cube){0});
447}
448
449bool
450is_block_solved(Cube cube, Block block)
451{
452 int i;
453 80
454 for (i = 0; i < 12; i++) 81 for (i = 0, sum_e = 0; i < 12; i++)
455 if (block.edge[i] && !is_solved_edge(cube, i)) 82 if (c->eo[i] > 1)
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; 83 return false;
84 else
85 sum_e += c->eo[i];
463 86
464 return true; 87 for (i = 0, sum_c = 0; i < 8; i++)
465} 88 if (c->co[i] > 2)
89 return false;
90 else
91 sum_c += c->co[i];
466 92
467bool 93 return (perm && sign % 2 == 0 && sum_e % 2 == 0 && sum_c % 2 == 0);
468is_solved_center(Cube cube, Center c)
469{
470 return what_center_at(cube, c) == c;
471} 94}
472 95
473bool 96bool
474is_solved_corner(Cube cube, Corner c) 97is_solved(Cube *cube)
475{ 98{
476 return what_corner_at(cube, c) == c && 99 Cube solved_cube;
477 what_orientation_corner(cube.coud, c); 100 make_solved(&solved_cube);
478}
479 101
480bool 102 return equal(cube, &solved_cube);
481is_solved_edge(Cube cube, Edge e)
482{
483 return what_edge_at(cube, e) == e &&
484 what_orientation_edge(cube.eofb, e);
485} 103}
486 104
487int 105void
488piece_orientation(Cube cube, int piece, char *orientation) 106make_solved(Cube *cube)
489{ 107{
490 int arr[12], n, b, x; 108 static int sorted[12] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
491 109
492 if (!strcmp(orientation, "eofb")) { 110 memcpy(cube->ep, sorted, 12 * sizeof(int));
493 x = cube.eofb; 111 memset(cube->eo, 0, 12 * sizeof(int));
494 n = 12; 112 memcpy(cube->cp, sorted, 8 * sizeof(int));
495 b = 2; 113 memset(cube->co, 0, 8 * sizeof(int));
496 } else if (!strcmp(orientation, "eorl")) { 114 memcpy(cube->xp, sorted, 6 * sizeof(int));
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;
525} 115}
526 116
527void 117void
528print_cube(Cube cube) 118print_cube(Cube *cube)
529{ 119{
530 static char edge_string[12][7] = { 120 static char edge_string[12][7] = {
531 [UF] = "UF", [UL] = "UL", [UB] = "UB", [UR] = "UR", 121 [UF] = "UF", [UL] = "UL", [UB] = "UB", [UR] = "UR",
@@ -545,388 +135,22 @@ print_cube(Cube cube)
545 }; 135 };
546 136
547 for (int i = 0; i < 12; i++) 137 for (int i = 0; i < 12; i++)
548 printf(" %s ", edge_string[what_edge_at(cube, i)]); 138 printf(" %s ", edge_string[cube->ep[i]]);
549 printf("\n"); 139 printf("\n");
550 140
551 for (int i = 0; i < 12; i++) 141 for (int i = 0; i < 12; i++)
552 printf(" %d ", what_orientation_edge(cube.eofb, i)); 142 printf(" %" PRIu8 " ", cube->eo[i]);
553 printf("\n"); 143 printf("\n");
554 144
555 for (int i = 0; i < 8; i++) 145 for (int i = 0; i < 8; i++)
556 printf("%s ", corner_string[what_corner_at(cube, i)]); 146 printf("%s ", corner_string[cube->cp[i]]);
557 printf("\n"); 147 printf("\n");
558 148
559 for (int i = 0; i < 8; i++) 149 for (int i = 0; i < 8; i++)
560 printf(" %d ", what_orientation_corner(cube.coud, i)); 150 printf(" %" PRIu8 " ", cube->co[i]);
561 printf("\n"); 151 printf("\n");
562 152
563 for (int i = 0; i < 6; i++) 153 for (int i = 0; i < 6; i++)
564 printf(" %s ", center_string[what_center_at(cube, i)]); 154 printf(" %s ", center_string[cube->xp[i]]);
565 printf("\n"); 155 printf("\n");
566} 156}
567
568Center
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)
617{
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;
625}
626
627int
628what_orientation_corner(int co, Corner c)
629{
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];
648}
649
650int
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)
675{
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];
694}
695
696Corner
697where_is_corner(Cube cube, Corner c)
698{
699 static bool initialized = false;
700 static Corner aux[FACTORIAL8][8];
701 static int i;
702 static unsigned int ui;
703 static CubeArray *arr;
704
705 if (!initialized) {
706 for (ui = 0; ui < FACTORIAL8; ui++) {
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 }
712
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();
932}
diff --git a/src/cube.h b/src/cube.h
index 483a89a..9f8b23d 100644
--- a/src/cube.h
+++ b/src/cube.h
@@ -3,44 +3,18 @@
3 3
4#include <stdio.h> 4#include <stdio.h>
5 5
6#include "cubetypes.h"
6#include "env.h" 7#include "env.h"
7#include "pf.h"
8#include "utils.h" 8#include "utils.h"
9 9
10Cube admissible_ep(Cube cube, PieceFilter f); 10void compose(Cube *c2, Cube *c1); /* Use c2 as an alg on c1 */
11int array_ep_to_epos(int *ep, int *eps_solved); 11void copy_cube(Cube *src, Cube *dst);
12Cube arrays_to_cube(CubeArray *arr, PieceFilter f); 12bool equal(Cube *c1, Cube *c2);
13Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */ 13void invert_cube(Cube *cube);
14Cube compose_filtered(Cube c2, Cube c1, PieceFilter f); 14bool is_admissible(Cube *cube);
15void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f); 15bool is_solved(Cube *cube);
16int edge_slice(Edge e); /* E=0, S=1, M=2 */ 16void make_solved(Cube *cube);
17bool equal(Cube c1, Cube c2); 17void print_cube(Cube *cube);
18Cube inverse_cube(Cube cube);
19bool is_admissible(Cube cube);
20bool is_solved(Cube cube);
21bool is_block_solved(Cube cube, Block);
22bool is_solved_center(Cube cube, Center c);
23bool is_solved_corner(Cube cube, Corner c);
24bool is_solved_edge(Cube cube, Edge e);
25void epos_to_partial_ep(int epos, int *ep, int *ss);
26void epos_to_compatible_ep(int epos, int *ep, int *ss);
27void fix_eorleoud(CubeArray *arr);
28void fix_cofbcorl(CubeArray *arr);
29Cube fourval_to_cube(int eofb, int ep, int coud, int cp);
30void free_cubearray(CubeArray *arr, PieceFilter f);
31Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf);
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();
44 18
45#endif 19#endif
46 20
diff --git a/src/cubetypes.h b/src/cubetypes.h
index ad9c627..cf6b7d5 100644
--- a/src/cubetypes.h
+++ b/src/cubetypes.h
@@ -10,6 +10,8 @@
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
13/* Enums *********************************************************************/ 15/* Enums *********************************************************************/
14 16
15typedef enum 17typedef enum
@@ -28,6 +30,12 @@ corner
28} Corner; 30} Corner;
29 31
30typedef enum 32typedef enum
33coordtype
34{
35 COMP_COORD, SYM_COORD, SYMCOMP_COORD
36} CoordType;
37
38typedef enum
31edge 39edge
32{ 40{
33 UF, UL, UB, UR, 41 UF, UL, UB, UR,
@@ -81,28 +89,24 @@ typedef struct command Command;
81typedef struct commandargs CommandArgs; 89typedef struct commandargs CommandArgs;
82typedef struct coordinate Coordinate; 90typedef struct coordinate Coordinate;
83typedef struct cube Cube; 91typedef struct cube Cube;
84typedef struct cubearray CubeArray;
85typedef struct dfsarg DfsArg; 92typedef struct dfsarg DfsArg;
86typedef struct estimatedata EstimateData; 93typedef struct indexer Indexer;
94typedef struct movable Movable;
87typedef struct moveset Moveset; 95typedef struct moveset Moveset;
88typedef struct piecefilter PieceFilter; 96typedef struct pdgendata PDGenData;
89typedef struct prunedata PruneData; 97typedef struct prunedata PruneData;
90typedef struct solveoptions SolveOptions; 98typedef struct solveoptions SolveOptions;
91typedef struct step Step; 99typedef struct step Step;
100typedef struct stepalt StepAlt;
92typedef struct symdata SymData; 101typedef struct symdata SymData;
93typedef struct threaddatasolve ThreadDataSolve; 102typedef struct threaddatasolve ThreadDataSolve;
94typedef struct threaddatagenpt ThreadDataGenpt; 103typedef struct threaddatagenpt ThreadDataGenpt;
104typedef struct transgroup TransGroup;
95 105
96typedef Cube (*AntiIndexer) (uint64_t); 106typedef bool (*Checker) (Cube *);
97typedef bool (*Checker) (Cube);
98typedef uint64_t (*CoordMover) (Move, uint64_t);
99typedef uint64_t (*CoordTransformer) (Trans, uint64_t);
100typedef int (*Estimator) (DfsArg *);
101typedef bool (*Validator) (Alg *); 107typedef bool (*Validator) (Alg *);
102typedef void (*Exec) (CommandArgs *); 108typedef void (*Exec) (CommandArgs *);
103typedef uint64_t (*Indexer) (Cube);
104typedef CommandArgs * (*ArgParser) (int, char **); 109typedef CommandArgs * (*ArgParser) (int, char **);
105typedef int (*TransDetector) (Cube, Trans *);
106typedef int (*TransFinder) (uint64_t, Trans *); 110typedef int (*TransFinder) (uint64_t, Trans *);
107 111
108 112
@@ -167,83 +171,69 @@ commandargs
167struct 171struct
168coordinate 172coordinate
169{ 173{
170 Indexer index; 174 char * name;
175 CoordType type;
176 bool generated;
177 Indexer * i[99];
171 uint64_t max; 178 uint64_t max;
172 CoordMover move; 179 uint64_t * mtable[NMOVES];
173 CoordTransformer transform; 180 uint64_t * ttable[NTRANS];
174 SymData * sd; 181 TransGroup * tgrp;
175 TransFinder tfind; /* TODO: should be easy to remove */ 182 Coordinate * base[2];
176 Coordinate * base; /* TODO: part of refactor */ 183 uint64_t * symclass;
184 uint64_t * symrep;
185 Trans * transtorep;
186 Trans * ttrep_move[NMOVES];
187 uint64_t * selfsim;
177}; 188};
178 189
179struct 190struct
180cube 191cube
181{ 192{
182 int epose; 193 int ep[12];
183 int eposs; 194 int eo[12];
184 int eposm; 195 int cp[8];
185 int eofb; 196 int co[8];
186 int eorl; 197 int xp[6];
187 int eoud;
188 int cp;
189 int coud;
190 int cofb;
191 int corl;
192 int cpos;
193}; 198};
194 199
195struct 200struct
196cubearray 201movable
197{ 202{
198 int * ep; 203 uint64_t val;
199 int * eofb; 204 Trans t;
200 int * eorl;
201 int * eoud;
202 int * cp;
203 int * coud;
204 int * corl;
205 int * cofb;
206 int * cpos;
207}; 205};
208 206
209struct 207struct
210dfsarg 208dfsarg
211{ 209{
212 Step * step; 210 Cube * cube;
213 SolveOptions * opts; 211 Movable ind[MAX_N_COORD];
214 Trans t; 212 Trans t;
215 Cube cube; 213 StepAlt * sa;
216 Cube inverse; 214 SolveOptions * opts;
217 int d; 215 int d;
218 uint64_t badmoves; 216 int bound;
219 uint64_t badmovesinv;
220 bool niss; 217 bool niss;
221 Move last1; 218 Move last[2];
222 Move last2; 219 Move lastinv[2];
223 Move last1inv;
224 Move last2inv;
225 EstimateData * ed;
226 AlgList * sols; 220 AlgList * sols;
227 pthread_mutex_t * sols_mutex; 221 pthread_mutex_t * sols_mutex;
228 Alg * current_alg; 222 Alg * current_alg;
229}; 223};
230 224
231struct 225struct
232estimatedata 226indexer
233{ 227{
234 int corners; 228 int n;
235 int normal_ud; 229 uint64_t (*index)(Cube *);
236 int normal_fb; 230 void (*to_cube)(uint64_t, Cube *);
237 int normal_rl;
238 int inverse_ud;
239 int inverse_fb;
240 int inverse_rl;
241 int oldret;
242}; 231};
243 232
244struct 233struct
245moveset 234moveset
246{ 235{
236 char * name;
247 bool (*allowed)(Move); 237 bool (*allowed)(Move);
248 bool (*allowed_next)(Move, Move, Move); 238 bool (*allowed_next)(Move, Move, Move);
249 Move sorted_moves[NMOVES+1]; 239 Move sorted_moves[NMOVES+1];
@@ -251,34 +241,24 @@ moveset
251}; 241};
252 242
253struct 243struct
254piecefilter 244pdgendata
255{ 245{
256 bool epose; 246 Coordinate * coord;
257 bool eposs; 247 Moveset * moveset;
258 bool eposm; 248 bool compact;
259 bool eofb; 249 PruneData * pd;
260 bool eorl;
261 bool eoud;
262 bool cp;
263 bool coud;
264 bool cofb;
265 bool corl;
266 bool cpos;
267}; 250};
268 251
269struct 252struct
270prunedata 253prunedata
271{ 254{
272 char * filename;
273 entry_group_t * ptable; 255 entry_group_t * ptable;
274 bool generated;
275 uint64_t n; 256 uint64_t n;
276 Coordinate * coord; 257 Coordinate * coord;
277 Moveset * moveset; 258 Moveset * moveset;
278 bool compact; 259 bool compact;
279 int base; 260 int base;
280 uint64_t count[16]; 261 uint64_t count[16];
281 PruneData * fallback;
282 uint64_t fbmod; 262 uint64_t fbmod;
283}; 263};
284 264
@@ -302,19 +282,35 @@ step
302{ 282{
303 char * shortname; 283 char * shortname;
304 char * name; 284 char * name;
305 bool final; 285 StepAlt * alt[99];
306 Checker is_done; 286 Trans t[99];
307 Estimator estimate;
308 Checker ready;
309 char * ready_msg; 287 char * ready_msg;
310 Validator is_valid; 288};
289
290struct
291stepalt
292{
293 Checker ready;
294 bool final;
311 Moveset * moveset; 295 Moveset * moveset;
312 Trans pre_trans; 296 /* Just a comment, (TODO: remove this): moveset is really a stepalt
313 TransDetector detect; 297 * property, because for example we may want to define a "fingertrick
314 int ntables; 298 * friendly ZBLL" step, where we allow either <R U D> or <R U F> as
315 PruneData * tables[10]; 299 * movesets (or similar) */
300 int n_coord;
301 Coordinate * coord[MAX_N_COORD];
302 Trans coord_trans[MAX_N_COORD];
303 PruneData * pd[MAX_N_COORD];
304 bool compact_pd[MAX_N_COORD];
305 Coordinate * fallback_coord[MAX_N_COORD];
306 PruneData * fallback_pd[MAX_N_COORD];
307 uint64_t fbmod[MAX_N_COORD];
308 int n_dbtrick;
309 int dbtrick[MAX_N_COORD][3];
310 Validator is_valid;
316}; 311};
317 312
313/*
318struct 314struct
319symdata 315symdata
320{ 316{
@@ -328,23 +324,18 @@ symdata
328 uint64_t * unsym; 324 uint64_t * unsym;
329 Trans * transtorep; 325 Trans * transtorep;
330 uint64_t * selfsim; 326 uint64_t * selfsim;
331 CoordTransformer transform; /* TODO: remove, use that of base coord */
332}; 327};
328*/
329
333 330
334struct 331struct
335threaddatasolve 332threaddatasolve
336{ 333{
334 DfsArg arg;
337 int thid; 335 int thid;
338 Trans t;
339 Cube cube;
340 Step * step;
341 int depth;
342 SolveOptions * opts;
343 AlgList * start; 336 AlgList * start;
344 AlgListNode ** node; 337 AlgListNode ** node;
345 AlgList * sols;
346 pthread_mutex_t * start_mutex; 338 pthread_mutex_t * start_mutex;
347 pthread_mutex_t * sols_mutex;
348}; 339};
349 340
350struct 341struct
@@ -359,4 +350,11 @@ threaddatagenpt
359 pthread_mutex_t * upmutex; 350 pthread_mutex_t * upmutex;
360}; 351};
361 352
353struct
354transgroup
355{
356 int n;
357 Trans t[NTRANS];
358};
359
362#endif 360#endif
diff --git a/src/env.c b/src/env.c
index 282bc8f..375bfa8 100644
--- a/src/env.c
+++ b/src/env.c
@@ -1,3 +1,5 @@
1#define ENV_C
2
1#include "env.h" 3#include "env.h"
2 4
3bool initialized_env = false; 5bool initialized_env = false;
diff --git a/src/env.h b/src/env.h
index 871a9c1..a49d643 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
11extern char *tabledir;
12
13void init_env(); 11void init_env();
14 12
13extern char *tabledir;
14
15#endif 15#endif
diff --git a/src/moves.c b/src/moves.c
index 02880ca..51012db 100644
--- a/src/moves.c
+++ b/src/moves.c
@@ -1,79 +1,18 @@
1#define MOVES_C
2
1#include "moves.h" 3#include "moves.h"
2 4
3/* Local functions ***********************************************************/ 5/* Local functions ***********************************************************/
4 6
5static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f);
6static void cleanup_aux(Alg *alg, Alg *ret, bool inv); 7static void cleanup_aux(Alg *alg, Alg *ret, bool inv);
7static bool read_mtables_file();
8static bool write_mtables_file();
9 8
10/* Tables and other data *****************************************************/ 9/* Tables and other data *****************************************************/
11 10
12/* Every move is translated to a an <U, x, y> alg before filling the 11/* Moves are represented as cubes and applied using compose(). Every move is *
13 transition tables, see init_moves() */ 12 * translated to a an <U, x, y> alg before filling the transition tables. *
14 13 * See init_moves(). */
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 14
40static int eorl_flipped[NMOVES][12] = { 15static Cube move_array[NMOVES];
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};
65
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};
77 16
78static char equiv_alg_string[100][NMOVES] = { 17static char equiv_alg_string[100][NMOVES] = {
79 [NULLMOVE] = "", 18 [NULLMOVE] = "",
@@ -137,89 +76,34 @@ static char equiv_alg_string[100][NMOVES] = {
137 [z3] = " y x yyy " 76 [z3] = " y x yyy "
138}; 77};
139 78
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}
175 79
176/* Public functions **********************************************************/ 80/* Public functions **********************************************************/
177 81
178Cube 82void
179apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a) 83apply_alg(Alg *alg, Cube *cube)
180{ 84{
181 Cube ret = {0}; 85 Cube aux;
182 int i; 86 int i;
183 87
88 copy_cube(cube, &aux);
89 make_solved(cube);
90
184 for (i = 0; i < alg->len; i++) 91 for (i = 0; i < alg->len; i++)
185 if (alg->inv[i]) 92 if (alg->inv[i])
186 ret = a ? apply_move(alg->move[i], ret) : 93 apply_move(alg->move[i], cube);
187 apply_move_cubearray(alg->move[i], ret, f);
188 94
189 ret = compose_filtered(c, inverse_cube(ret), f); 95 invert_cube(cube);
96 compose(&aux, cube);
190 97
191 for (i = 0; i < alg->len; i++) 98 for (i = 0; i < alg->len; i++)
192 if (!alg->inv[i]) 99 if (!alg->inv[i])
193 ret = a ? apply_move(alg->move[i], ret) : 100 apply_move(alg->move[i], cube);
194 apply_move_cubearray(alg->move[i], ret, f);
195
196 return ret;
197} 101}
198 102
199Cube 103void
200apply_alg(Alg *alg, Cube cube) 104apply_move(Move m, Cube *cube)
201{ 105{
202 return apply_alg_generic(alg, cube, pf_all, true); 106 compose(&move_array[m], cube);
203}
204
205Cube
206apply_move(Move m, Cube cube)
207{
208 /*init_moves();*/
209
210 return (Cube) {
211 .epose = epose_mtable[m][cube.epose],
212 .eposs = eposs_mtable[m][cube.eposs],
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 };
223} 107}
224 108
225Alg * 109Alg *
@@ -279,31 +163,27 @@ cleanup_aux(Alg *alg, Alg *ret, bool inv)
279{ 163{
280 int i, j; 164 int i, j;
281 Cube c, d; 165 Cube c, d;
282 Move m, mm; 166 Move m;
283 Alg *equiv_alg; 167 Alg *equiv_alg;
284 168
285 c = (Cube){0}; 169 make_solved(&c);
286 for (i = 0; i < alg->len; i++) { 170 for (i = 0; i < alg->len; i++) {
287 if (alg->inv[i] != inv) 171 if (alg->inv[i] != inv)
288 continue; 172 continue;
289 173
290 equiv_alg = new_alg(equiv_alg_string[alg->move[i]]); 174 equiv_alg = new_alg(equiv_alg_string[alg->move[i]]);
291 175
292 for (j = 0; j < equiv_alg->len; j++) { 176 for (j = 0; j < equiv_alg->len; j++)
293 m = equiv_alg->move[j]; 177 if (equiv_alg->move[j] == U)
294 if (m == U) { 178 append_move(ret, 3 * c.xp[U_center] + 1, inv);
295 mm = 3*what_center_at(c, U_center) + 1; 179 else
296 append_move(ret, mm, inv); 180 apply_move(equiv_alg->move[j], &c);
297 } else {
298 c = apply_move(m, c);
299 }
300 }
301 181
302 free_alg(equiv_alg); 182 free_alg(equiv_alg);
303 } 183 }
304 184
305 m = NULLMOVE; 185 m = NULLMOVE;
306 switch (what_center_at(c, F_center)) { 186 switch (c.xp[F_center]) {
307 case U_center: 187 case U_center:
308 m = x3; 188 m = x3;
309 break; 189 break;
@@ -317,7 +197,7 @@ cleanup_aux(Alg *alg, Alg *ret, bool inv)
317 m = y3; 197 m = y3;
318 break; 198 break;
319 case B_center: 199 case B_center:
320 if (what_center_at(c, U_center) == U_center) 200 if (c.xp[U_center] == U_center)
321 m = y2; 201 m = y2;
322 else 202 else
323 m = x2; 203 m = x2;
@@ -325,120 +205,24 @@ cleanup_aux(Alg *alg, Alg *ret, bool inv)
325 default: 205 default:
326 break; 206 break;
327 } 207 }
328 d = apply_move(m, (Cube){0}); 208
209 make_solved(&d);
210 apply_move(m, &d);
329 if (m != NULLMOVE) 211 if (m != NULLMOVE)
330 append_move(ret, m, inv); 212 append_move(ret, m, inv);
331 213
332 m = NULLMOVE; 214 m = NULLMOVE;
333 if (what_center_at(c, U_center) == what_center_at(d, D_center)) { 215 if (c.xp[U_center] == d.xp[D_center]) {
334 m = z2; 216 m = z2;
335 } else if (what_center_at(c, U_center) == what_center_at(d, R_center)) { 217 } else if (c.xp[U_center] == d.xp[R_center]) {
336 m = z3; 218 m = z3;
337 } else if (what_center_at(c, U_center) == what_center_at(d, L_center)) { 219 } else if (c.xp[U_center] == d.xp[L_center]) {
338 m = z; 220 m = z;
339 } 221 }
340 if (m != NULLMOVE) 222 if (m != NULLMOVE)
341 append_move(ret, m, inv); 223 append_move(ret, m, inv);
342} 224}
343 225
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
442void 226void
443init_moves() { 227init_moves() {
444 static bool initialized = false; 228 static bool initialized = false;
@@ -446,101 +230,54 @@ init_moves() {
446 return; 230 return;
447 initialized = true; 231 initialized = true;
448 232
449 Cube c;
450 CubeArray arrs;
451 int i;
452 unsigned int ui;
453 Move m; 233 Move m;
454 Alg *equiv_alg[NMOVES]; 234 Alg *equiv_alg[NMOVES];
455 235
456 init_cube(); 236 static const Cube mcu = {
457 237 .ep = { UR, UF, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR },
458 for (i = 0; i < NMOVES; i++) 238 .cp = { UBR, UFR, UFL, UBL, DFR, DFL, DBL, DBR },
459 equiv_alg[i] = new_alg(equiv_alg_string[i]); 239 };
460 240 static const Cube mcx = {
461 /* Generate all move cycles and flips; I do this regardless */ 241 .ep = { DF, FL, UF, FR, DB, BL, UB, BR, DR, DL, UL, UR },
462 for (i = 0; i < NMOVES; i++) { 242 .eo = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 },
463 if (i == U || i == x || i == y) 243 .cp = { DFR, DFL, UFL, UFR, DBR, DBL, UBL, UBR },
464 continue; 244 .co = { [UFR] = 2, [UBR] = 1, [UFL] = 1, [UBL] = 2,
465 245 [DBR] = 2, [DFR] = 1, [DBL] = 1, [DFL] = 2 },
466 c = apply_alg_generic(equiv_alg[i], (Cube){0}, pf_all, false); 246 .xp = { F_center, B_center, R_center,
467 247 L_center, D_center, U_center },
468 arrs = (CubeArray) { 248 };
469 edge_cycle[i], 249 static const Cube mcy = {
470 eofb_flipped[i], 250 .ep = { UR, UF, UL, UB, DR, DF, DL, DB, BR, FR, FL, BL },
471 eorl_flipped[i], 251 .eo = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 },
472 eoud_flipped[i], 252 .cp = { UBR, UFR, UFL, UBL, DBR, DFR, DFL, DBL },
473 corner_cycle[i], 253 .xp = { U_center, D_center, B_center,
474 coud_flipped[i], 254 F_center, R_center, L_center },
475 corl_flipped[i], 255 };
476 cofb_flipped[i],
477 center_cycle[i]
478 };
479 cube_to_arrays(c, &arrs, pf_all);
480 }
481 256
482 if (read_mtables_file()) 257 move_array[U] = mcu;
483 return; 258 move_array[x] = mcx;
259 move_array[y] = mcy;
484 260
485 fprintf(stderr, "Cannot load %s, generating it\n", "mtables"); 261 for (m = 0; m < NMOVES; m++)
262 equiv_alg[m] = new_alg(equiv_alg_string[m]);
486 263
487 /* Initialize transition tables */
488 for (m = 0; m < NMOVES; m++) { 264 for (m = 0; m < NMOVES; m++) {
489 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) { 265 switch (m) {
490 c = (Cube){ .epose = ui }; 266 case NULLMOVE:
491 c = apply_move_cubearray(m, c, pf_e); 267 make_solved(&move_array[m]);
492 epose_mtable[m][ui] = c.epose; 268 break;
493 269 case U:
494 c = (Cube){ .eposs = ui }; 270 case x:
495 c = apply_move_cubearray(m, c, pf_s); 271 case y:
496 eposs_mtable[m][ui] = c.eposs; 272 break;
497 273 default:
498 c = (Cube){ .eposm = ui }; 274 make_solved(&move_array[m]);
499 c = apply_move_cubearray(m, c, pf_m); 275 apply_alg(equiv_alg[m], &move_array[m]);
500 eposm_mtable[m][ui] = c.eposm; 276 break;
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;
537 } 277 }
538 } 278 }
539 279
540 if (!write_mtables_file()) 280 for (m = 0; m < NMOVES; m++)
541 fprintf(stderr, "Error writing mtables\n"); 281 free_alg(equiv_alg[m]);
542
543 for (i = 0; i < NMOVES; i++)
544 free_alg(equiv_alg[i]);
545} 282}
546 283
diff --git a/src/moves.h b/src/moves.h
index 14ae087..4afe8fb 100644
--- a/src/moves.h
+++ b/src/moves.h
@@ -5,24 +5,8 @@
5#include "cube.h" 5#include "cube.h"
6#include "env.h" 6#include "env.h"
7 7
8/* 8void apply_alg(Alg *alg, Cube *cube);
9 * Tables are exposed to allow for faster moves in some cases. 9void apply_move(Move m, Cube *cube);
10 */
11extern int epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
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);
26Alg * cleanup(Alg *alg); 10Alg * cleanup(Alg *alg);
27 11
28void init_moves(); 12void init_moves();
diff --git a/src/pf.c b/src/pf.c
deleted file mode 100644
index 7d86e4e..0000000
--- a/src/pf.c
+++ /dev/null
@@ -1,95 +0,0 @@
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
deleted file mode 100644
index 0b552dc..0000000
--- a/src/pf.h
+++ /dev/null
@@ -1,20 +0,0 @@
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 1dba949..5be977c 100644
--- a/src/pruning.c
+++ b/src/pruning.c
@@ -1,3 +1,5 @@
1#define PRUNING_C
2
1#include "pruning.h" 3#include "pruning.h"
2 4
3#define ENTRIES_PER_GROUP (2*sizeof(entry_group_t)) 5#define ENTRIES_PER_GROUP (2*sizeof(entry_group_t))
@@ -10,101 +12,11 @@ static void genptable_fixnasty(PruneData *pd, int d, int nthreads);
10static void genptable_setbase(PruneData *pd); 12static void genptable_setbase(PruneData *pd);
11static void * instance_bfs(void *arg); 13static void * instance_bfs(void *arg);
12static void * instance_fixnasty(void *arg); 14static void * instance_fixnasty(void *arg);
13static void ptable_update(PruneData *pd, Cube cube, int m); 15static void ptable_update(PruneData *pd, uint64_t ind, int m);
14static void ptable_update_index(PruneData *pd, uint64_t ind, int m);
15static int ptableval_index(PruneData *pd, uint64_t ind);
16static bool read_ptable_file(PruneData *pd); 16static bool read_ptable_file(PruneData *pd);
17static bool write_ptable_file(PruneData *pd); 17static bool write_ptable_file(PruneData *pd);
18 18
19PruneData 19PDGenData *active_pdg[256];
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 *****************************************************************/
108 20
109int 21int
110findchunk(PruneData *pd, int nchunks, uint64_t i) 22findchunk(PruneData *pd, int nchunks, uint64_t i)
@@ -117,39 +29,41 @@ findchunk(PruneData *pd, int nchunks, uint64_t i)
117 return MIN(nchunks-1, (int)(i / chunksize)); 29 return MIN(nchunks-1, (int)(i / chunksize));
118} 30}
119 31
120void 32PruneData *
121free_pd(PruneData *pd) 33genptable(PDGenData *pdg, int nthreads)
122{
123 if (pd->generated)
124 free(pd->ptable);
125
126 pd->generated = false;
127}
128
129void
130genptable(PruneData *pd, int nthreads)
131{ 34{
132 bool compact; 35 bool compact;
133 int d, nchunks; 36 int d, nchunks, i;
134 uint64_t oldn, sz; 37 uint64_t oldn, sz;
38 PruneData *pd;
135 39
136 if (pd->generated) 40 for (i = 0; active_pdg[i] != NULL; i++) {
137 return; 41 pd = active_pdg[i]->pd;
42 if (pd->coord == pdg->coord &&
43 pd->moveset == pdg->moveset &&
44 pd->compact == pdg->compact)
45 return pd;
46 }
47
48 pd = malloc(sizeof(PruneData));
49 pdg->pd = pd;
50 pd->coord = pdg->coord;
51 pd->moveset = pdg->moveset;
52 pd->compact = pdg->compact;
138 53
139 /* TODO: check if memory is enough, otherwise maybe exit gracefully? */
140 sz = ptablesize(pd) * (pd->compact ? 2 : 1); 54 sz = ptablesize(pd) * (pd->compact ? 2 : 1);
141 pd->ptable = malloc(sz * sizeof(entry_group_t)); 55 pd->ptable = malloc(sz * sizeof(entry_group_t));
142 56
143 if (read_ptable_file(pd)) { 57 gen_coord(pd->coord);
144 pd->generated = true; 58
145 return; 59 if (read_ptable_file(pd))
146 } 60 goto genptable_done;
147 61
148 if (nthreads < 4) { 62 if (nthreads < 4) {
149 fprintf(stderr, 63 fprintf(stderr,
150 "--- Warning ---\n" 64 "--- Warning ---\n"
151 "You are using only %d threads to generate the pruning" 65 "You are using only %d threads to generate the pruning"
152 "tables. This can take a while." 66 "tables. This can take a while.\n"
153 "Unless you did this intentionally, you should re-run" 67 "Unless you did this intentionally, you should re-run"
154 "this command with `-t 4' or more.\n" 68 "this command with `-t 4' or more.\n"
155 "---------------\n\n", nthreads 69 "---------------\n\n", nthreads
@@ -160,16 +74,16 @@ genptable(PruneData *pd, int nthreads)
160 /* For the first steps we proceed the same way for compact and not */ 74 /* For the first steps we proceed the same way for compact and not */
161 compact = pd->compact; 75 compact = pd->compact;
162 pd->compact = false; 76 pd->compact = false;
163 pd->generated = true;
164 77
165 nchunks = MIN(ptablesize(pd), 100000); 78 nchunks = MIN(ptablesize(pd), 100000);
166 fprintf(stderr, "Cannot load %s, generating it with %d threads\n", 79 fprintf(stderr, "Generating pt_%s_%s with %d threads\n",
167 pd->filename, nthreads); 80 pd->coord->name, pd->moveset->name, nthreads);
168
169 81
170 memset(pd->ptable, ~(uint8_t)0, ptablesize(pd)*sizeof(entry_group_t)); 82 memset(pd->ptable, ~(uint8_t)0, ptablesize(pd)*sizeof(entry_group_t));
83 for (i = 0; i < 16; i++)
84 pd->count[i] = 0;
171 85
172 ptable_update(pd, (Cube){0}, 0); 86 ptable_update(pd, 0, 0);
173 pd->n = 1; 87 pd->n = 1;
174 oldn = 0; 88 oldn = 0;
175 genptable_fixnasty(pd, 0, nthreads); 89 genptable_fixnasty(pd, 0, nthreads);
@@ -192,9 +106,19 @@ genptable(PruneData *pd, int nthreads)
192 genptable_setbase(pd); 106 genptable_setbase(pd);
193 if (compact) 107 if (compact)
194 genptable_compress(pd); 108 genptable_compress(pd);
195 109
196 if (!write_ptable_file(pd)) 110 if (!write_ptable_file(pd))
197 fprintf(stderr, "Error writing ptable file\n"); 111 fprintf(stderr, "Error writing ptable file\n");
112
113genptable_done:
114 for (i = 0; active_pdg[i] != NULL; i++);
115 active_pdg[i] = malloc(sizeof(PDGenData));
116 active_pdg[i]->coord = pdg->coord;
117 active_pdg[i]->moveset = pdg->moveset;
118 active_pdg[i]->compact = pdg->compact;
119 active_pdg[i]->pd = pd;
120
121 return pd;
198} 122}
199 123
200static void 124static void
@@ -245,7 +169,7 @@ genptable_compress(PruneData *pd)
245 for (j = 0; j < ENTRIES_PER_GROUP_COMPACT; j++) { 169 for (j = 0; j < ENTRIES_PER_GROUP_COMPACT; j++) {
246 if (i+j >= pd->coord->max) 170 if (i+j >= pd->coord->max)
247 break; 171 break;
248 val = ptableval_index(pd, i+j) - pd->base; 172 val = ptableval(pd, i+j) - pd->base;
249 v = (entry_group_t)MIN(3, MAX(0, val)); 173 v = (entry_group_t)MIN(3, MAX(0, val));
250 mask |= v << (2*j); 174 mask |= v << (2*j);
251 } 175 }
@@ -264,7 +188,7 @@ genptable_fixnasty(PruneData *pd, int d, int nthreads)
264 ThreadDataGenpt td[nthreads]; 188 ThreadDataGenpt td[nthreads];
265 pthread_mutex_t *upmtx; 189 pthread_mutex_t *upmtx;
266 190
267 if (pd->coord->tfind == NULL) 191 if (pd->coord->type != SYMCOMP_COORD)
268 return; 192 return;
269 193
270 upmtx = malloc(sizeof(pthread_mutex_t)); 194 upmtx = malloc(sizeof(pthread_mutex_t));
@@ -320,17 +244,17 @@ instance_bfs(void *arg)
320 for (i = rmin; i < rmax; i++) { 244 for (i = rmin; i < rmax; i++) {
321 ichunk = findchunk(td->pd, td->nchunks, i); 245 ichunk = findchunk(td->pd, td->nchunks, i);
322 pthread_mutex_lock(td->mutex[ichunk]); 246 pthread_mutex_lock(td->mutex[ichunk]);
323 pval = ptableval_index(td->pd, i); 247 pval = ptableval(td->pd, i);
324 pthread_mutex_unlock(td->mutex[ichunk]); 248 pthread_mutex_unlock(td->mutex[ichunk]);
325 if (pval == td->d) { 249 if (pval == td->d) {
326 for (j = 0; ms[j] != NULLMOVE; j++) { 250 for (j = 0; ms[j] != NULLMOVE; j++) {
327 ii = td->pd->coord->move(ms[j], i); 251 /* ii = td->pd->coord->move(ms[j], i); */
252 ii = move_coord(td->pd->coord, ms[j], i, NULL);
328 ichunk = findchunk(td->pd, td->nchunks, ii); 253 ichunk = findchunk(td->pd, td->nchunks, ii);
329 pthread_mutex_lock(td->mutex[ichunk]); 254 pthread_mutex_lock(td->mutex[ichunk]);
330 pval = ptableval_index(td->pd, ii); 255 pval = ptableval(td->pd, ii);
331 if (pval > td->d+1) { 256 if (pval > td->d+1) {
332 ptable_update_index(td->pd, 257 ptable_update(td->pd, ii, td->d+1);
333 ii, td->d+1);
334 updated++; 258 updated++;
335 } 259 }
336 pthread_mutex_unlock(td->mutex[ichunk]); 260 pthread_mutex_unlock(td->mutex[ichunk]);
@@ -349,13 +273,15 @@ static void *
349instance_fixnasty(void *arg) 273instance_fixnasty(void *arg)
350{ 274{
351 ThreadDataGenpt *td; 275 ThreadDataGenpt *td;
352 uint64_t i, ii, nb, blocksize, rmin, rmax, updated; 276 uint64_t i, ii, blocksize, rmin, rmax, updated, ss, M;
353 int j, n; 277 int j;
354 Trans t, aux[NTRANS]; 278 Trans t;
355 279
356 td = (ThreadDataGenpt *)arg; 280 td = (ThreadDataGenpt *)arg;
357 nb = td->pd->coord->max / td->pd->coord->base->max; 281
358 blocksize = (td->pd->coord->base->max / td->nthreads) * nb; 282 /* We know type = SYMCOMP_COORD */
283 M = td->pd->coord->base[1]->max;
284 blocksize = (td->pd->coord->base[0]->max / td->nthreads) * M;
359 rmin = ((uint64_t)td->thid) * blocksize; 285 rmin = ((uint64_t)td->thid) * blocksize;
360 rmax = td->thid == td->nthreads - 1 ? 286 rmax = td->thid == td->nthreads - 1 ?
361 td->pd->coord->max : 287 td->pd->coord->max :
@@ -363,16 +289,15 @@ instance_fixnasty(void *arg)
363 289
364 updated = 0; 290 updated = 0;
365 for (i = rmin; i < rmax; i++) { 291 for (i = rmin; i < rmax; i++) {
366 if (ptableval_index(td->pd, i) == td->d) { 292 if (ptableval(td->pd, i) == td->d) {
367 if ((n = td->pd->coord->tfind(i, aux)) == 1) 293 ss = td->pd->coord->base[0]->selfsim[i/M];
368 continue; 294 for (j = 0; j < td->pd->coord->base[0]->tgrp->n; j++) {
369 295 t = td->pd->coord->base[0]->tgrp->t[j];
370 for (j = 0; j < n; j++) { 296 if (t == uf || !(ss & ((uint64_t)1<<t)))
371 if ((t = aux[j]) == uf)
372 continue; 297 continue;
373 ii = td->pd->coord->transform(t, i); 298 ii = trans_coord(td->pd->coord, t, i);
374 if (ptableval_index(td->pd, ii) > td->d) { 299 if (ptableval(td->pd, ii) > td->d) {
375 ptable_update_index(td->pd, ii, td->d); 300 ptable_update(td->pd, ii, td->d);
376 updated++; 301 updated++;
377 } 302 }
378 } 303 }
@@ -391,10 +316,7 @@ print_ptable(PruneData *pd)
391{ 316{
392 uint64_t i; 317 uint64_t i;
393 318
394 if (!pd->generated) 319 printf("Table %s_%s\n", pd->coord->name, pd->moveset->name);
395 genptable(pd, 1); /* TODO: set default nthreads somewhere */
396
397 printf("Table %s\n", pd->filename);
398 printf("Base value: %d\n", pd->base); 320 printf("Base value: %d\n", pd->base);
399 for (i = 0; i < 16; i++) 321 for (i = 0; i < 16; i++)
400 printf("%2" PRIu64 "\t%10" PRIu64 "\n", i, pd->count[i]); 322 printf("%2" PRIu64 "\t%10" PRIu64 "\n", i, pd->count[i]);
@@ -411,13 +333,7 @@ ptablesize(PruneData *pd)
411} 333}
412 334
413static void 335static void
414ptable_update(PruneData *pd, Cube cube, int n) 336ptable_update(PruneData *pd, uint64_t ind, int n)
415{
416 ptable_update_index(pd, pd->coord->index(cube), n);
417}
418
419static void
420ptable_update_index(PruneData *pd, uint64_t ind, int n)
421{ 337{
422 int sh; 338 int sh;
423 entry_group_t mask; 339 entry_group_t mask;
@@ -432,27 +348,12 @@ ptable_update_index(PruneData *pd, uint64_t ind, int n)
432} 348}
433 349
434int 350int
435ptableval(PruneData *pd, Cube cube) 351ptableval(PruneData *pd, uint64_t ind)
436{
437 return ptableval_index(pd, pd->coord->index(cube));
438}
439
440static int
441ptableval_index(PruneData *pd, uint64_t ind)
442{ 352{
443 int sh, ret; 353 int sh, ret;
444 entry_group_t mask; 354 uint64_t e;
445 uint64_t i, e;
446 entry_group_t m; 355 entry_group_t m;
447 356
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
456 if (pd->compact) { 357 if (pd->compact) {
457 e = ENTRIES_PER_GROUP_COMPACT; 358 e = ENTRIES_PER_GROUP_COMPACT;
458 m = 3; 359 m = 3;
@@ -463,19 +364,9 @@ ptableval_index(PruneData *pd, uint64_t ind)
463 sh = (ind % e) * 4; 364 sh = (ind % e) * 4;
464 } 365 }
465 366
466 mask = m << sh; 367 ret = (pd->ptable[ind/e] & (m << sh)) >> 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 368
478 return ret; 369 return pd->compact ? ret + pd->base : ret;
479} 370}
480 371
481static bool 372static bool
@@ -484,13 +375,15 @@ read_ptable_file(PruneData *pd)
484 init_env(); 375 init_env();
485 376
486 FILE *f; 377 FILE *f;
487 char fname[strlen(tabledir)+100]; 378 char fname[strlen(tabledir)+256];
488 int i; 379 int i;
489 uint64_t r; 380 uint64_t r;
490 381
491 strcpy(fname, tabledir); 382 strcpy(fname, tabledir);
492 strcat(fname, "/"); 383 strcat(fname, "/pt_");
493 strcat(fname, pd->filename); 384 strcat(fname, pd->coord->name);
385 strcat(fname, "_");
386 strcat(fname, pd->moveset->name);
494 387
495 if ((f = fopen(fname, "rb")) == NULL) 388 if ((f = fopen(fname, "rb")) == NULL)
496 return false; 389 return false;
@@ -511,13 +404,15 @@ write_ptable_file(PruneData *pd)
511 init_env(); 404 init_env();
512 405
513 FILE *f; 406 FILE *f;
514 char fname[strlen(tabledir)+100]; 407 char fname[strlen(tabledir)+256];
515 int i; 408 int i;
516 uint64_t w; 409 uint64_t w;
517 410
518 strcpy(fname, tabledir); 411 strcpy(fname, tabledir);
519 strcat(fname, "/"); 412 strcat(fname, "/pt_");
520 strcat(fname, pd->filename); 413 strcat(fname, pd->coord->name);
414 strcat(fname, "_");
415 strcat(fname, pd->moveset->name);
521 416
522 if ((f = fopen(fname, "wb")) == NULL) 417 if ((f = fopen(fname, "wb")) == NULL)
523 return false; 418 return false;
diff --git a/src/pruning.h b/src/pruning.h
index 6bdbee1..6965910 100644
--- a/src/pruning.h
+++ b/src/pruning.h
@@ -1,26 +1,15 @@
1#ifndef PRUNING_H 1#ifndef PRUNING_H
2#define PRUNING_H 2#define PRUNING_H
3 3
4#include "symcoord.h" 4#include "coord.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[];
18 5
19void free_pd(PruneData *pd); 6void free_pd(PruneData *pd);
20void genptable(PruneData *pd, int nthreads); 7PruneData * genptable(PDGenData *data, int nthreads);
21void print_ptable(PruneData *pd); 8void print_ptable(PruneData *pd);
22uint64_t ptablesize(PruneData *pd); 9uint64_t ptablesize(PruneData *pd);
23int ptableval(PruneData *pd, Cube cube); 10int ptableval(PruneData *pd, uint64_t ind);
11
12extern PDGenData *active_pdg[256];
24 13
25#endif 14#endif
26 15
diff --git a/src/shell.c b/src/shell.c
index 0001e0d..44665a8 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -1,3 +1,5 @@
1#define SHELL_C
2
1#include "shell.h" 3#include "shell.h"
2 4
3static void cleanwhitespaces(char *line); 5static void cleanwhitespaces(char *line);
@@ -7,7 +9,9 @@ bool
7checkfiles() 9checkfiles()
8{ 10{
9 /* TODO: add more checks (other files, use checksum...) */ 11 /* TODO: add more checks (other files, use checksum...) */
10 FILE *f; 12 /* How to check for pruning tables with new method? */
13 /* Solution: use list of steps */
14 /*
11 char fname[strlen(tabledir)+100]; 15 char fname[strlen(tabledir)+100];
12 int i; 16 int i;
13 17
@@ -20,6 +24,7 @@ checkfiles()
20 else 24 else
21 fclose(f); 25 fclose(f);
22 } 26 }
27 */
23 28
24 return true; 29 return true;
25} 30}
@@ -143,6 +148,21 @@ main(int argc, char *argv[])
143 char *closing_cmd[1] = { "freemem" }; 148 char *closing_cmd[1] = { "freemem" };
144 149
145 init_env(); 150 init_env();
151 init_trans();
152
153/*
154 Cube c;
155 make_solved(&c);
156 c.co[0] = 1;
157 c.co[6] = 2;
158 print_cube(&c);
159 apply_trans(uf_mirror, &c);
160 print_cube(&c);
161*/
162
163/*
164 test_coord(&coord_coud_cpudsep);
165*/
146 166
147 if (!checkfiles()) { 167 if (!checkfiles()) {
148 fprintf(stderr, 168 fprintf(stderr,
diff --git a/src/solve.c b/src/solve.c
index d4c0f18..911d208 100644
--- a/src/solve.c
+++ b/src/solve.c
@@ -1,37 +1,34 @@
1#define SOLVE_C
2
1#include "solve.h" 3#include "solve.h"
2 4
3/* Local functions ***********************************************************/ 5/* Local functions ***********************************************************/
4 6
5static bool allowed_next(Move move, DfsArg *arg); 7static bool allowed_next(Move move, StepAlt *sa, Move l0, Move l1);
6static bool cancel_niss(DfsArg *arg); 8static bool cancel_niss(DfsArg *arg);
7static void copy_dfsarg(DfsArg *src, DfsArg *dst); 9static void copy_dfsarg(DfsArg *src, DfsArg *dst);
8static void dfs(DfsArg *arg); 10static void dfs(DfsArg *arg);
9static void dfs_branch(DfsArg *arg); 11static void dfs_add_sol(DfsArg *arg);
10static bool dfs_check_solved(DfsArg *arg);
11static bool dfs_switch(DfsArg *arg);
12static void dfs_niss(DfsArg *arg); 12static void dfs_niss(DfsArg *arg);
13static bool dfs_stop(DfsArg *arg); 13static bool dfs_move_checkstop(DfsArg *arg);
14static void * instance_thread(void *arg); 14static void * instance_thread(void *arg);
15static void invert_branch(DfsArg *arg); 15static void multidfs(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); 16static bool niss_makes_sense(DfsArg *arg);
19static bool solvestop(int d, int op, SolveOptions *opts, AlgList *sols); 17static bool solvestop(int d, int op, SolveOptions *opts, AlgList *sols);
20 18
21/* Local functions ***********************************************************/ 19/* Local functions ***********************************************************/
22 20
23static bool 21static bool
24allowed_next(Move m, DfsArg *arg) 22allowed_next(Move m, StepAlt *sa, Move l0, Move l1)
25{ 23{
26 bool bad, allowed, order; 24 bool allowed, order;
27 uint64_t mbit; 25 uint64_t mbit;
28 26
29 mbit = ((uint64_t)1) << m; 27 mbit = ((uint64_t)1) << m;
30 bad = mbit & arg->badmoves; 28 allowed = mbit & sa->moveset->mask[l1][l0];
31 allowed = mbit & arg->step->moveset->mask[arg->last2][arg->last1]; 29 order = !commute(l0, m) || l0 < m;
32 order = !commute(arg->last1, m) || arg->last1 < m;
33 30
34 return allowed && !bad && order; 31 return allowed && order;
35} 32}
36 33
37static bool 34static bool
@@ -41,20 +38,20 @@ cancel_niss(DfsArg *arg)
41 Move i1, i2; 38 Move i1, i2;
42 bool p, p1, p2, q, q1, q2; 39 bool p, p1, p2, q, q1, q2;
43 40
44 if (arg->last1inv == NULLMOVE) 41 if (arg->lastinv[0] == NULLMOVE)
45 return false; 42 return false;
46 43
47 ms = arg->step->moveset; 44 ms = arg->sa->moveset;
48 i1 = inverse_move(arg->last1inv); 45 i1 = inverse_move(arg->lastinv[0]);
49 i2 = inverse_move(arg->last2inv); 46 i2 = inverse_move(arg->lastinv[1]);
50 47
51 p1 = !ms->allowed_next(arg->last2, arg->last1, i1); 48 p1 = !ms->allowed_next(arg->last[1], arg->last[0], i1);
52 p2 = !ms->allowed_next(arg->last2, i1, arg->last1); 49 p2 = !ms->allowed_next(arg->last[1], i1, arg->last[0]);
53 p = p1 || (commute(i1, arg->last1) && p2); 50 p = p1 || (commute(i1, arg->last[0]) && p2);
54 51
55 q1 = !ms->allowed_next(arg->last2, arg->last1, i2); 52 q1 = !ms->allowed_next(arg->last[1], arg->last[0], i2);
56 q2 = !ms->allowed_next(arg->last2, i2, arg->last1); 53 q2 = !ms->allowed_next(arg->last[1], i2, arg->last[0]);
57 q = q1 || (commute(i2, arg->last1) && q2); 54 q = q1 || (commute(i2, arg->last[0]) && q2);
58 55
59 return p || (commute(i1, i2) && q); 56 return p || (commute(i1, i2) && q);
60} 57}
@@ -62,142 +59,145 @@ cancel_niss(DfsArg *arg)
62static void 59static void
63copy_dfsarg(DfsArg *src, DfsArg *dst) 60copy_dfsarg(DfsArg *src, DfsArg *dst)
64{ 61{
65 dst->step = src->step; 62 int i;
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 63
96 if (arg->step->final && (sw = dfs_switch(arg))) 64 dst->cube = src->cube;
97 invert_branch(arg); 65 dst->t = src->t;
98 dfs_branch(arg); 66 dst->sa = src->sa;
67 dst->opts = src->opts;
68 dst->d = src->d;
69 dst->bound = src->bound; /* In theory not needed */
70 dst->niss = src->niss;
71 dst->sols = src->sols;
72 dst->sols_mutex = src->sols_mutex;
73 dst->current_alg = src->current_alg;
99 74
100 if (arg->opts->can_niss && !arg->niss && niss_makes_sense(arg)) 75 for (i = 0; i < 2; i++) {
101 dfs_niss(arg); 76 dst->last[i] = src->last[i];
77 dst->lastinv[i] = src->lastinv[i];
78 }
102 79
103 if (sw) 80 for (i = 0; i < src->sa->n_coord; i++) {
104 invert_branch(arg); 81 dst->ind[i].val = src->ind[i].val;
82 dst->ind[i].t = src->ind[i].t;
83 }
105} 84}
106 85
107static void 86static void
108dfs_branch(DfsArg *arg) 87dfs(DfsArg *arg)
109{ 88{
110 int i; 89 int i;
111 Move m; 90 Move m;
112 DfsArg *newarg; 91 DfsArg newarg;
113 92
114 newarg = malloc(sizeof(DfsArg)); 93 if (dfs_move_checkstop(arg))
115 newarg->ed = malloc(sizeof(EstimateData)); 94 return;
116
117 for (i = 0; arg->step->moveset->sorted_moves[i] != NULLMOVE; i++) {
118 m = arg->step->moveset->sorted_moves[i];
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);
125 95
126 dfs(newarg); 96 if (arg->bound == 0) {
97 if (arg->current_alg->len == arg->d)
98 dfs_add_sol(arg);
99 return;
100 }
127 101
102 for (i = 0; arg->sa->moveset->sorted_moves[i] != NULLMOVE; i++) {
103 m = arg->sa->moveset->sorted_moves[i];
104 if (allowed_next(m, arg->sa, arg->last[0], arg->last[1])) {
105 copy_dfsarg(arg, &newarg);
106 newarg.last[1] = arg->last[0];
107 newarg.last[0] = m;
108 append_move(arg->current_alg, m, newarg.niss);
109 dfs(&newarg);
128 arg->current_alg->len--; 110 arg->current_alg->len--;
129 } 111 }
130 } 112 }
131 113
132 free(newarg->ed); 114 if (niss_makes_sense(arg))
133 free(newarg); 115 dfs_niss(arg);
134} 116}
135 117
136static bool 118static void
137dfs_check_solved(DfsArg *arg) 119dfs_add_sol(DfsArg *arg)
138{ 120{
139 if (!arg->step->is_done(arg->cube)) 121 bool valid, accepted, nisscanc;
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 122
151 transform_alg( 123 valid = arg->sa->is_valid==NULL || arg->sa->is_valid(arg->current_alg);
152 inverse_trans(arg->t), 124 accepted = valid || arg->opts->all;
153 arg->sols->last->alg 125 nisscanc = arg->sa->final && cancel_niss(arg);
154 );
155 if (arg->step->final)
156 inplace(unniss, arg->sols->last->alg);
157 126
158 if (arg->opts->verbose) 127 if (accepted && !nisscanc) {
159 print_alg(arg->sols->last->alg, false); 128 pthread_mutex_lock(arg->sols_mutex);
160 }
161 129
162 pthread_mutex_unlock(arg->sols_mutex); 130 if (arg->sols->len < arg->opts->max_solutions) {
131 append_alg(arg->sols, arg->current_alg);
132 transform_alg(
133 inverse_trans(arg->t), arg->sols->last->alg);
134 if (arg->opts->verbose)
135 print_alg(arg->sols->last->alg, false);
163 } 136 }
164 }
165 137
166 return true; 138 pthread_mutex_unlock(arg->sols_mutex);
139 }
167} 140}
168 141
169static void 142static void
170dfs_niss(DfsArg *arg) 143dfs_niss(DfsArg *arg)
171{ 144{
172 DfsArg *newarg; 145 DfsArg newarg;
146 Alg *inv;
147 Cube *c;
148
149 copy_dfsarg(arg, &newarg);
173 150
174 newarg = malloc(sizeof(DfsArg)); 151 /* Invert current alg and scramble */
175 newarg->ed = malloc(sizeof(EstimateData)); 152 newarg.cube = malloc(sizeof(Cube));
153 inv = inverse_alg(arg->current_alg);
154 c = malloc(sizeof(Cube));
155 make_solved(newarg.cube);
156 apply_alg(inv, newarg.cube);
157 copy_cube(arg->cube, c);
158 invert_cube(c);
159 compose(c, newarg.cube);
176 160
177 copy_dfsarg(arg, newarg); 161 /* New indexes */
178 swapmove(&(newarg->last1), &(newarg->last1inv)); 162 compute_ind(newarg.sa, newarg.cube, newarg.ind);
179 swapmove(&(newarg->last2), &(newarg->last2inv));
180 newarg->niss = !(arg->niss);
181 newarg->cube = inverse_cube(arg->cube);
182 163
183 dfs(newarg); 164 swapmove(&(newarg.last[0]), &(newarg.lastinv[0]));
165 swapmove(&(newarg.last[1]), &(newarg.lastinv[1]));
166 newarg.niss = !(arg->niss);
184 167
185 free(newarg->ed); 168 dfs(&newarg);
186 free(newarg); 169
170 free_alg(inv);
171 free(c);
172 free(newarg.cube);
187} 173}
188 174
189static bool 175static bool
190dfs_stop(DfsArg *arg) 176dfs_move_checkstop(DfsArg *arg)
191{ 177{
192 int lowerbound;
193 bool b; 178 bool b;
179 int i, goal;
180 Move mm;
181 Trans tt = uf; /* Avoid uninitialized warning */
182
183 /* Moving */
184 if (arg->last[0] != NULLMOVE) {
185 for (i = 0; i < arg->sa->n_coord; i++) {
186 mm = transform_move(arg->ind[i].t, arg->last[0]);
187 arg->ind[i].val = move_coord(arg->sa->coord[i],
188 mm, arg->ind[i].val, &tt);
189 arg->ind[i].t = transform_trans(tt, arg->ind[i].t);
190 }
191 }
194 192
195 lowerbound = arg->step->estimate(arg); 193 /* Computing bound for coordinates */
194 goal = arg->d - arg->current_alg->len;
195 arg->bound = estimate_stepalt(arg->sa, arg->ind, goal);
196 if (arg->opts->can_niss && !arg->niss) 196 if (arg->opts->can_niss && !arg->niss)
197 lowerbound = MIN(1, lowerbound); 197 arg->bound = MIN(1, arg->bound);
198 198
199 if (arg->current_alg->len + lowerbound > arg->d) { 199 if (arg->bound > goal) {
200 b = true; 200 b = true;
201 } else { 201 } else {
202 pthread_mutex_lock(arg->sols_mutex); 202 pthread_mutex_lock(arg->sols_mutex);
203 b = arg->sols->len >= arg->opts->max_solutions; 203 b = arg->sols->len >= arg->opts->max_solutions;
@@ -207,37 +207,12 @@ dfs_stop(DfsArg *arg)
207 return b; 207 return b;
208} 208}
209 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 * 210static void *
237instance_thread(void *arg) 211instance_thread(void *arg)
238{ 212{
239 bool b; 213 bool b, inv;
240 Cube c; 214 Cube c;
215 Move m;
241 ThreadDataSolve *td; 216 ThreadDataSolve *td;
242 AlgListNode *node; 217 AlgListNode *node;
243 DfsArg darg; 218 DfsArg darg;
@@ -257,68 +232,46 @@ instance_thread(void *arg)
257 if (b) 232 if (b)
258 break; 233 break;
259 234
260 c = node->alg->inv[0] ? 235 inv = node->alg->inv[0];
261 apply_move(node->alg->move[0], inverse_cube(td->cube)) : 236 m = node->alg->move[0];
262 apply_move(node->alg->move[0], td->cube); 237
238 copy_cube(td->arg.cube, &c);
239 if (inv)
240 invert_cube(&c);
263 241
264 darg.step = td->step; 242 copy_dfsarg(&td->arg, &darg);
265 darg.opts = td->opts; 243 compute_ind(td->arg.sa, &c, darg.ind);
266 darg.t = td->t; 244 darg.cube = &c;
267 darg.cube = c; 245
268 darg.d = td->depth; 246 darg.niss = inv;
269 darg.niss = node->alg->inv[0]; 247 darg.last[0] = m;
270 darg.last1 = node->alg->move[0]; 248 darg.last[1] = NULLMOVE;
271 darg.last2 = NULLMOVE; 249 darg.lastinv[0] = NULLMOVE;
272 darg.last1inv = NULLMOVE; 250 darg.lastinv[1] = NULLMOVE;
273 darg.last2inv = NULLMOVE;
274 darg.sols = td->sols;
275 darg.sols_mutex = td->sols_mutex;
276 darg.current_alg = new_alg(""); 251 darg.current_alg = new_alg("");
277 append_move(darg.current_alg, node->alg->move[0], 252 append_move(darg.current_alg, m, inv);
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 253
284 dfs(&darg); 254 dfs(&darg);
285 255
286 free_alg(darg.current_alg); 256 free_alg(darg.current_alg);
287 free(darg.ed);
288 } 257 }
289 258
290 return NULL; 259 return NULL;
291} 260}
292 261
293static void 262static void
294invert_branch(DfsArg *arg) 263multidfs(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{ 264{
313 int i; 265 int i;
266 Cube local_cube;
314 Alg *alg; 267 Alg *alg;
315 AlgList *start; 268 AlgList *start;
316 AlgListNode **node; 269 AlgListNode **node;
317 pthread_t t[opts->nthreads]; 270 pthread_t t[arg->opts->nthreads];
318 ThreadDataSolve td[opts->nthreads]; 271 ThreadDataSolve td[arg->opts->nthreads];
319 pthread_mutex_t *start_mutex, *sols_mutex; 272 pthread_mutex_t *start_mutex, *sols_mutex;
320 273
321 node = malloc(sizeof(AlgListNode *)); 274 node = malloc(sizeof(AlgListNode *));
322 start_mutex = malloc(sizeof(pthread_mutex_t)); 275 start_mutex = malloc(sizeof(pthread_mutex_t));
323 sols_mutex = malloc(sizeof(pthread_mutex_t)); 276 sols_mutex = malloc(sizeof(pthread_mutex_t));
324 277
@@ -326,11 +279,11 @@ multidfs(Cube c, Trans tr, Step *s, SolveOptions *opts, AlgList *sols, int d)
326 pthread_mutex_init(start_mutex, NULL); 279 pthread_mutex_init(start_mutex, NULL);
327 pthread_mutex_init(sols_mutex, NULL); 280 pthread_mutex_init(sols_mutex, NULL);
328 281
329 for (i = 0; s->moveset->sorted_moves[i] != NULLMOVE; i++) { 282 for (i = 0; arg->sa->moveset->sorted_moves[i] != NULLMOVE; i++) {
330 alg = new_alg(""); 283 alg = new_alg("");
331 append_move(alg, s->moveset->sorted_moves[i], false); 284 append_move(alg, arg->sa->moveset->sorted_moves[i], false);
332 append_alg(start, alg); 285 append_alg(start, alg);
333 if (opts->can_niss) { 286 if (arg->opts->can_niss && !arg->sa->final) {
334 alg->inv[0] = true; 287 alg->inv[0] = true;
335 append_alg(start, alg); 288 append_alg(start, alg);
336 } 289 }
@@ -338,22 +291,22 @@ multidfs(Cube c, Trans tr, Step *s, SolveOptions *opts, AlgList *sols, int d)
338 } 291 }
339 *node = start->first; 292 *node = start->first;
340 293
341 for (i = 0; i < opts->nthreads; i++) { 294 copy_cube(arg->cube, &local_cube);
342 td[i].thid = i; 295
343 td[i].t = tr; 296 for (i = 0; i < arg->opts->nthreads; i++) {
344 td[i].cube = c; 297 copy_dfsarg(arg, &(td[i].arg));
345 td[i].step = s; 298 td[i].arg.cube = &local_cube;
346 td[i].depth = d; 299 td[i].arg.sols_mutex = sols_mutex;
347 td[i].opts = opts; 300
348 td[i].start = start; 301 td[i].thid = i;
349 td[i].node = node; 302 td[i].start = start;
350 td[i].sols = sols; 303 td[i].node = node;
351 td[i].start_mutex = start_mutex; 304 td[i].start_mutex = start_mutex;
352 td[i].sols_mutex = sols_mutex; 305
353 pthread_create(&t[i], NULL, instance_thread, &td[i]); 306 pthread_create(&t[i], NULL, instance_thread, &td[i]);
354 } 307 }
355 308
356 for (i = 0; i < opts->nthreads; i++) 309 for (i = 0; i < arg->opts->nthreads; i++)
357 pthread_join(t[i], NULL); 310 pthread_join(t[i], NULL);
358 311
359 free_alglist(start); 312 free_alglist(start);
@@ -367,8 +320,13 @@ niss_makes_sense(DfsArg *arg)
367{ 320{
368 Cube testcube; 321 Cube testcube;
369 322
370 testcube = apply_move(inverse_move(arg->last1), (Cube){0}); 323 if (arg->sa->final || arg->niss || !arg->opts->can_niss)
371 return arg->current_alg->len == 0 || !arg->step->is_done(testcube); 324 return false;
325
326 make_solved(&testcube);
327 apply_move(inverse_move(arg->last[0]), &testcube);
328 return arg->current_alg->len == 0 ||
329 estimate_stepalt(arg->sa, arg->ind, 0) > 0;
372} 330}
373 331
374static bool 332static bool
@@ -386,62 +344,84 @@ solvestop(int d, int op, SolveOptions *opts, AlgList *sols)
386/* Public functions **********************************************************/ 344/* Public functions **********************************************************/
387 345
388AlgList * 346AlgList *
389solve(Cube cube, Step *step, SolveOptions *opts) 347solve(Cube *cube, Step *step, SolveOptions *opts)
390{ 348{
391 bool ready; 349 int i, d, op;
392 int i, d, op, nt; 350 bool ready[99], one_ready, zerosol;
393 AlgList *sols; 351 Movable ind[99][10];
394 Cube c; 352 AlgList *s;
395 Trans tt[NTRANS]; 353 Cube *c[99];
354 DfsArg arg[99];
396 355
397 prepare_step(step, opts); 356 prepare_step(step, opts);
357 s = new_alglist();
398 358
399 if (step->detect != NULL) { 359 for (i = 0, one_ready = false; step->alt[i] != NULL; i++) {
400 nt = step->detect(cube, tt); 360 c[i] = malloc(sizeof(Cube));
401 } else { 361 copy_cube(cube, c[i]);
402 tt[0] = step->pre_trans; 362 apply_trans(step->t[i], c[i]);
403 ready = step->ready == NULL ||
404 step->ready(apply_trans(tt[0], cube));
405 nt = ready ? 1 : 0;
406 }
407 363
408 sols = new_alglist(); 364 arg[i].cube = c[i];
365 arg[i].t = step->t[i];
366 arg[i].sa = step->alt[i];
367 arg[i].opts = opts;
368 arg[i].sols = s;
409 369
410 if (nt == 0) { 370 if ((ready[i] = step->alt[i]->ready(c[i]))) {
371 one_ready = true;
372 /* Only for local use for 0 moves solutions */
373 compute_ind(step->alt[i], c[i], ind[i]);
374 }
375 }
376 if (!one_ready) {
411 fprintf(stderr, "Cube not ready for solving step: "); 377 fprintf(stderr, "Cube not ready for solving step: ");
412 fprintf(stderr, "%s\n", step->ready_msg); 378 fprintf(stderr, "%s\n", step->ready_msg);
413 return sols; 379 return s;
414 } 380 }
415 381
416 if (opts->min_moves == 0) { 382 /* If the empty moves sequence is a solution for one of the
417 for (i = 0; i < nt; i++) { 383 * alternatives, all longer solutions will be discarded, so we may
418 c = apply_trans(tt[i], cube); 384 * just set its ready[] value to false. If the solution is accepted
419 if (step->is_done(c)) { 385 * we append it and start searching from d = 1. */
420 append_alg(sols, new_alg("")); 386 for (i = 0, zerosol = false; step->alt[i] != NULL; i++) {
421 return sols; 387 if (ready[i] && estimate_stepalt(step->alt[i],ind[i],0) == 0) {
422 } 388 ready[i] = false;
389 zerosol = true;
423 } 390 }
424 } 391 }
392 if (zerosol && opts->min_moves == 0) {
393 append_alg(s, new_alg(""));
394 opts->min_moves = 1;
395 if (opts->verbose)
396 printf("Step is already solved"
397 "(empty alg is a solution)\n");
398 }
425 399
426 op = -1; 400 for (d = opts->min_moves, op = -1; !solvestop(d, op, opts, s); d++) {
427 for (d = opts->min_moves; !solvestop(d, op, opts, sols); d++) {
428 if (opts->verbose) 401 if (opts->verbose)
429 fprintf(stderr, "Searching depth %d\n", d); 402 fprintf(stderr, "Searching depth %d\n", d);
430 403
431 for (i = 0; i < nt && !solvestop(d, op, opts, sols); i++) { 404 for (i=0; step->alt[i]!=NULL && !solvestop(d,op,opts,s); i++) {
432 c = apply_trans(tt[i], cube); 405 if (!ready[i])
433 multidfs(c, tt[i], step, opts, sols, d); 406 continue;
434 if (sols->len > 0 && op == -1) 407
408 arg[i].d = d;
409 multidfs(&arg[i]);
410
411 if (s->len > 0 && op == -1)
435 op = d; 412 op = d;
436 } 413 }
437 } 414 }
438 415
439 return sols; 416 for (i = 0; step->alt[i] != NULL; i++)
417 free(c[i]);
418
419 return s;
440} 420}
441 421
442/* TODO: make more general! */ 422/* TODO: make more general! */
443Alg * 423Alg *
444solve_2phase(Cube cube, int nthreads) 424solve_2phase(Cube *cube, int nthreads)
445{ 425{
446 int bestlen, newb; 426 int bestlen, newb;
447 Alg *bestalg, *ret; 427 Alg *bestalg, *ret;
@@ -466,18 +446,19 @@ solve_2phase(Cube cube, int nthreads)
466 opts2.can_niss = false; 446 opts2.can_niss = false;
467 opts2.verbose = false; 447 opts2.verbose = false;
468 448
469 /* We skip step1 if it is solved on any axis */ 449 /* We skip step1 if it is solved on U/D */
470 if (drany_HTM.is_done(cube)) { 450 if (check_drud(cube)) {
471 sols1 = new_alglist(); 451 sols1 = new_alglist();
472 append_alg(sols1, new_alg("")); 452 append_alg(sols1, new_alg(""));
473 } else { 453 } else {
474 sols1 = solve(cube, &drany_HTM, &opts1); 454 sols1 = solve(cube, &drud_HTM, &opts1);
475 } 455 }
476 bestalg = new_alg(""); 456 bestalg = new_alg("");
477 bestlen = 999; 457 bestlen = 999;
478 for (i = sols1->first; i != NULL; i = i->next) { 458 for (i = sols1->first; i != NULL; i = i->next) {
479 c = apply_alg(i->alg, cube); 459 copy_cube(cube, &c);
480 sols2 = solve(c, &dranyfin_DR, &opts2); 460 apply_alg(i->alg, &c);
461 sols2 = solve(&c, &dranyfin_DR, &opts2);
481 462
482 if (sols2->len > 0) { 463 if (sols2->len > 0) {
483 newb = i->alg->len + sols2->first->alg->len; 464 newb = i->alg->len + sols2->first->alg->len;
diff --git a/src/solve.h b/src/solve.h
index 6ce6609..9039e4a 100644
--- a/src/solve.h
+++ b/src/solve.h
@@ -5,7 +5,7 @@
5#include "steps.h" 5#include "steps.h"
6#include "trans.h" 6#include "trans.h"
7 7
8AlgList * solve(Cube cube, Step *step, SolveOptions *opts); 8AlgList * solve(Cube *cube, Step *step, SolveOptions *opts);
9Alg * solve_2phase(Cube cube, int nthreads); 9Alg * solve_2phase(Cube *cube, int nthreads);
10 10
11#endif 11#endif
diff --git a/src/steps.c b/src/steps.c
index 3189811..81af269 100644
--- a/src/steps.c
+++ b/src/steps.c
@@ -1,1372 +1,112 @@
1#include "steps.h" 1#define STEPS_C
2
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 2
826 .detect = detect_pretrans_drud, 3#include "steps.h"
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",
836
837 .final = false,
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)
973{
974 return cube.cpos == 0;
975}
976
977static bool
978check_coud_HTM(Cube cube)
979{
980 return cube.coud == 0;
981}
982
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 4
991 return cube.coud == 0 || c2.coud == 0 || c3.coud == 0; 5/* TODO: change all checkers to use coordinates! */
992}
993 6
994static bool 7bool
995check_corners_URF(Cube cube) 8check_centers(Cube *cube)
996{ 9{
997 Cube c; 10 int i;
998 Trans i;
999 11
1000 for (i = 0; i < NROTATIONS; i++) { 12 for (i = 0; i < 6; i++)
1001 c = apply_alg(rotation_alg(i), cube); 13 if (cube->xp[i] != i)
1002 if (c.cp && c.coud) 14 return false;
1003 return true;
1004 }
1005 15
1006 return false; 16 return true;
1007} 17}
1008 18
1009static bool 19bool
1010check_corners_HTM(Cube cube) 20check_coud_HTM(Cube *cube)
1011{ 21{
1012 return cube.cp == 0 && cube.coud == 0; 22 int i;
1013}
1014 23
1015static bool 24 for (i = 0; i < 8; i++)
1016check_cornershtr(Cube cube) 25 if (cube->co[i] != 0)
1017{ 26 return false;
1018 return coord_cornershtr.index(cube) == 0;
1019}
1020 27
1021static bool 28 return true;
1022check_eofb(Cube cube)
1023{
1024 return cube.eofb == 0;
1025} 29}
1026 30
1027static bool 31bool
1028check_drud(Cube cube) 32check_coud_URF(Cube *cube)
1029{ 33{
1030 return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0; 34 Cube c2, c3;
1031}
1032 35
1033static bool 36 copy_cube(cube, &c2);
1034check_htr(Cube cube) 37 copy_cube(cube, &c3);
1035{
1036 return check_drud(cube) && coord_htr_drud.index(cube) == 0;
1037}
1038 38
1039static int 39 apply_move(z, &c2);
1040estimate_eofb_HTM(DfsArg *arg) 40 apply_move(x, &c3);
1041{
1042 return ptableval(&pd_eofb_HTM, arg->cube);
1043}
1044 41
1045static int 42 return check_coud_HTM(cube) ||
1046estimate_coud_HTM(DfsArg *arg) 43 check_coud_HTM(&c2) ||
1047{ 44 check_coud_HTM(&c3);
1048 return ptableval(&pd_coud_HTM, arg->cube);
1049} 45}
1050 46
1051static int 47bool
1052estimate_coud_URF(DfsArg *arg) 48check_cp_HTM(Cube *cube)
1053{ 49{
1054 /* TODO: I can improve this by checking first the orientation of 50 int i;
1055 * the corner in DBL and use that as a reference */
1056
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 51
1069 return MIN(ud, MIN(rl, fb)); 52 for (i = 0; i < 8; i++)
1070} 53 if (cube->cp[i] != i)
54 return false;
1071 55
1072static int 56 return true;
1073estimate_corners_HTM(DfsArg *arg)
1074{
1075 return ptableval(&pd_corners_HTM, arg->cube);
1076}
1077
1078static int
1079estimate_cornershtr_HTM(DfsArg *arg)
1080{
1081 return ptableval(&pd_cornershtr_HTM, arg->cube);
1082} 57}
1083 58
1084static int 59bool
1085estimate_cornershtr_URF(DfsArg *arg) 60check_corners_HTM(Cube *cube)
1086{ 61{
1087 /* TODO: I can improve this by checking first the corner in DBL 62 return check_coud_HTM(cube) && check_cp_HTM(cube);
1088 * and use that as a reference */
1089
1090 int ret;
1091 Cube c;
1092 Trans i;
1093
1094 c = arg->cube;
1095 ret = 15;
1096
1097 for (i = 0; i < NROTATIONS; i++) {
1098 arg->cube = apply_alg(rotation_alg(i), c);
1099 ret = MIN(ret, estimate_cornershtr_HTM(arg));
1100 }
1101
1102 arg->cube = c;
1103
1104 return ret;
1105} 63}
1106 64
1107static int 65bool
1108estimate_corners_URF(DfsArg *arg) 66check_corners_URF(Cube *cube)
1109{ 67{
1110 /* TODO: I can improve this by checking first the corner in DBL
1111 * and use that as a reference */
1112
1113 int ret;
1114 Cube c; 68 Cube c;
1115 Trans i; 69 Trans i;
1116 70
1117 c = arg->cube;
1118 ret = 15;
1119
1120 for (i = 0; i < NROTATIONS; i++) { 71 for (i = 0; i < NROTATIONS; i++) {
1121 arg->cube = apply_alg(rotation_alg(i), c); 72 copy_cube(cube, &c);
1122 ret = MIN(ret, estimate_corners_HTM(arg)); 73 apply_alg(rotation_alg(i), &c);
74 if (check_corners_HTM(&c))
75 return true;
1123 } 76 }
1124 77
1125 arg->cube = c; 78 return false;
1126
1127 return ret;
1128}
1129
1130static int
1131estimate_drud_HTM(DfsArg *arg)
1132{
1133 return ptableval(&pd_drud_sym16_HTM, arg->cube);
1134}
1135
1136static int
1137estimate_drud_eofb(DfsArg *arg)
1138{
1139 return ptableval(&pd_drud_eofb, arg->cube);
1140}
1141
1142static int
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} 79}
1175 80
1176static int 81bool
1177estimate_nxopt31_HTM(DfsArg *arg) 82check_cornershtr(Cube *cube)
1178{ 83{
1179 return estimate_nxoptlike(arg, &pd_nxopt31_HTM); 84 /* TODO (use coord) */
85 return true;
1180} 86}
1181 87
1182/* TODO: also use generic procedure for this */ 88bool
1183static int 89check_eofb(Cube *cube)
1184estimate_light_HTM(DfsArg *arg)
1185{ 90{
1186 int target, ret; 91 /* TODO (use coord) */
1187 Cube aux; 92 return true;
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} 93}
1278 94
1279static int 95bool
1280estimate_nxoptlike(DfsArg *arg, PruneData *pd) 96check_drud(Cube *cube)
1281{ 97{
1282 int target, ret; 98 /* TODO (use coord) */
1283 Cube aux; 99 return true;
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} 100}
1361 101
1362 102bool
1363static bool 103check_htr(Cube *cube)
1364always_valid(Alg *alg)
1365{ 104{
105 /* TODO (check_drud(cube) and coord_htr_drud == 0) */
1366 return true; 106 return true;
1367} 107}
1368 108
1369static bool 109bool
1370validate_singlecw_ending(Alg *alg) 110validate_singlecw_ending(Alg *alg)
1371{ 111{
1372 int i; 112 int i;
@@ -1389,93 +129,93 @@ validate_singlecw_ending(Alg *alg)
1389 return nor && inv; 129 return nor && inv;
1390} 130}
1391 131
1392/* Pre-transformation detectors **********************************************/ 132/* Public functions **********************************************************/
1393 133
1394static int 134void
1395detect_pretrans_eofb(Cube cube, Trans *ret) 135compute_ind(StepAlt *a, Cube *cube, Movable *ind)
1396{ 136{
1397 int i, n; 137 int i;
1398 static Trans tt[3] = {uf, ur, fd}; 138 Cube mvd;
139 Trans t, tt;
1399 140
1400 for (i = 0, n = 0; i < 3; i++) 141 for (i = 0; i < a->n_coord; i++) {
1401 if (check_eofb(apply_trans(tt[i], cube))) 142 t = a->coord_trans[i];
1402 ret[n++] = tt[i]; 143 copy_cube(cube, &mvd);
144 apply_trans(t, &mvd);
1403 145
1404 return n; 146 ind[i].val = index_coord(a->coord[i], &mvd, &tt);
147 ind[i].t = transform_trans(tt, t);
148 }
1405} 149}
1406 150
1407static int 151int
1408detect_pretrans_drud(Cube cube, Trans *ret) 152estimate_stepalt(StepAlt *a, Movable *ind, int goal)
1409{ 153{
1410 int i, n; 154 int i, ret, est[a->n_coord];
1411 static Trans tt[3] = {uf, fr, rd};
1412 155
1413 for (i = 0, n = 0; i < 3; i++) 156 for (i = 0; i < a->n_coord; i++) {
1414 if (check_drud(apply_trans(tt[i], cube))) 157 est[i] = ptableval(a->pd[i], ind[i].val);
1415 ret[n++] = tt[i]; 158 if (est[i] == a->pd[i]->base && a->compact_pd[i])
159 est[i] = ptableval(a->fallback_pd[i],
160 ind[i].val/a->fbmod[i]);
161 if (ind[i].val != 0 && est[i] == 0) /* est == 0 iff solved */
162 est[i] = 1;
163/*
164TODO: remove this debug code
165printf("%d: est=%d | ", i, est[i]);
166*/
1416 167
1417 return n; 168 if (est[i] > goal)
1418} 169 return est[i];
170 }
1419 171
1420static int 172 for (i = 0; i < a->n_dbtrick; i++)
1421detect_pretrans_void_3axis(Cube cube, Trans *ret) 173 if (est[a->dbtrick[i][0]] > 0 &&
1422{ 174 est[a->dbtrick[i][0]] == est[a->dbtrick[i][1]] &&
1423 ret[0] = uf; 175 est[a->dbtrick[i][0]] == est[a->dbtrick[i][2]])
1424 ret[1] = fr; 176 est[a->dbtrick[i][0]] += 1;
1425 ret[2] = rd;
1426 177
1427 return 3; 178 for (i = 0, ret = -1; i < a->n_coord; i++)
1428} 179 ret = MAX(ret, est[i]);
1429 180
1430/* Public functions **********************************************************/ 181/*
182TODO: remove this debug code
183printf("Final estimate: %d\n", ret);
184*/
1431 185
1432void 186 return ret;
1433copy_estimatedata(EstimateData *src, EstimateData *dst)
1434{
1435 dst->corners = src->corners;
1436 dst->normal_ud = src->normal_ud;
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} 187}
1444 188
1445void 189void
1446invert_estimatedata(EstimateData *ed) 190prepare_step(Step *step, SolveOptions *opts)
1447{ 191{
1448 swap(&(ed->normal_ud), &(ed->inverse_ud)); 192 int i, j;
1449 swap(&(ed->normal_fb), &(ed->inverse_fb)); 193 PDGenData pdg;
1450 swap(&(ed->normal_rl), &(ed->inverse_rl)); 194 StepAlt *a;
1451}
1452 195
1453void 196 for (i = 0; step->alt[i] != NULL; i++) {
1454reset_estimatedata(EstimateData *ed) 197 a = step->alt[i];
1455{ 198 init_moveset(a->moveset);
1456 ed->corners = -1; 199 pdg.moveset = a->moveset;
1457 ed->normal_ud = -1; 200 for (j = 0; j < a->n_coord; j++) {
1458 ed->normal_fb = -1; 201 gen_coord(a->coord[j]);
1459 ed->normal_rl = -1;
1460 ed->inverse_ud = -1;
1461 ed->inverse_fb = -1;
1462 ed->inverse_rl = -1;
1463 ed->oldret = -1;
1464}
1465 202
1466void 203 pdg.coord = a->coord[j];
1467prepare_step(Step *step, SolveOptions *opts) 204 pdg.compact = a->compact_pd[j];
1468{ 205 pdg.pd = NULL;
1469 int i;
1470 206
1471 if (step->final && opts->can_niss) { 207 a->pd[j] = genptable(&pdg, opts->nthreads);
1472 opts->can_niss = false; 208
1473 fprintf(stderr, "Step is final, NISS not used (-n ignored)\n"); 209 if (a->compact_pd[j]) {
1474 } 210 gen_coord(a->fallback_coord[j]);
1475 211
1476 for (i = 0; i < step->ntables; i++) { 212 pdg.coord = a->fallback_coord[j];
1477 genptable(step->tables[i], opts->nthreads); 213 pdg.compact = false;
1478 if (step->tables[i]->compact) 214 pdg.pd = NULL;
1479 genptable(step->tables[i]->fallback, opts->nthreads); 215
216 a->fallback_pd[j] =
217 genptable(&pdg, opts->nthreads);
218 }
219 }
1480 } 220 }
1481} 221}
diff --git a/src/steps.h b/src/steps.h
index da5c041..341be98 100644
--- a/src/steps.h
+++ b/src/steps.h
@@ -3,15 +3,275 @@
3 3
4#include "pruning.h" 4#include "pruning.h"
5 5
6extern Step * steps[]; 6bool check_centers(Cube *cube);
7bool check_coud_HTM(Cube *cube);
8bool check_coud_URF(Cube *cube);
9bool check_cp_HTM(Cube *cube);
10bool check_corners_HTM(Cube *cube);
11bool check_corners_URF(Cube *cube);
12bool check_cornershtr(Cube *cube);
13bool check_eofb(Cube *cube);
14bool check_drud(Cube *cube);
15bool check_htr(Cube *cube);
16void compute_ind(StepAlt *a, Cube *cube, Movable *ind);
17int estimate_stepalt(StepAlt *a, Movable *ind, int goal);
18void prepare_step(Step *step, SolveOptions *opts);
19bool always_valid(Alg *alg);
20bool validate_singlecw_ending(Alg *alg);
7 21
8/* Two steps used directly by two-phase solver */ 22#ifndef STEPS_C
9extern Step drany_HTM;
10extern Step dranyfin_DR;
11 23
12void copy_estimatedata(EstimateData *s, EstimateData *d); 24extern char check_centers_msg[100];
13void invert_estimatedata(EstimateData *ed); 25extern char check_eo_msg[100];
14void reset_estimatedata(EstimateData *ed); 26extern char check_dr_msg[100];
15void prepare_step(Step *step, SolveOptions *opts); 27extern char check_htr_msg[100];
28extern char check_drany_msg[100];
29
30extern StepAlt sa_nxopt31_HTM;
31extern StepAlt sa_eofb_HTM;
32extern StepAlt sa_drud_HTM;
33extern StepAlt sa_drfin_drud;
34
35extern Step optimal_HTM;
36extern Step eoany_HTM;
37extern Step eofb_HTM;
38extern Step eorl_HTM;
39extern Step eoud_HTM;
40extern Step drany_HTM;
41extern Step drud_HTM;
42extern Step drrl_HTM;
43extern Step drfb_HTM;
44extern Step dranyfin_DR;
45extern Step drudfin_drud;
46extern Step drrlfin_drrl;
47extern Step drfbfin_drfb;
48
49extern Step *steps[];
50
51#else
52
53char check_centers_msg[100] = "cube must be oriented (centers solved)";
54char check_eo_msg[100] = "EO must be solved on given axis";
55char check_dr_msg[100] = "DR must be solved on given axis";
56char check_htr_msg[100] = "HTR must be solved";
57char check_drany_msg[100] = "DR must be solved on at least one axis";
58
59/* Optimal solvers *******************/
60/* TODO: build options for smaller optimal solvers */
61
62StepAlt
63sa_nxopt31_HTM = {
64 .ready = check_centers,
65 .final = true,
66 .moveset = &moveset_HTM,
67 .n_coord = 6,
68 .coord = {&coord_nxopt31, &coord_nxopt31, &coord_nxopt31,
69 &coord_eposepe, &coord_eposepe, &coord_eposepe},
70 /* TODO: use khuge as fallback? */
71 .coord_trans = {uf, rd, bl, uf, rd, bl},
72 .compact_pd = {true, true, true, false, false, false},
73 .fallback_coord = {&coord_drud_sym16, &coord_drud_sym16,
74 &coord_drud_sym16},
75 .fbmod = {BINOM8ON4, BINOM8ON4, BINOM8ON4},
76 .n_dbtrick = 1, /* TODO: change to 2 when khuge */
77 .dbtrick = {{0, 1, 2}},
78 .is_valid = NULL,
79};
80Step
81optimal_HTM = {
82 .shortname = "optimal",
83 .name = "Optimal solve (in HTM)",
84 .alt = {&sa_nxopt31_HTM, NULL},
85 .t = {uf},
86 .ready_msg = check_centers_msg,
87};
88
89/* Optimal after EO ******************/
90/* TODO: eofin_eo (generic), eofbfin_eofb, eorlfin_eorl, eoudfin_eoud */
91
92/* EO steps **************************/
93/* TODO: eoany_HTM (generic), eofb_HTM, eorl_HTM, eoud_HTM */
94
95StepAlt
96sa_eofb_HTM = {
97 .ready = check_centers,
98 .final = false,
99 .moveset = &moveset_HTM,
100 .n_coord = 1,
101 .coord = {&coord_eofb},
102 .coord_trans = {uf},
103 .compact_pd = {false},
104 .n_dbtrick = 0,
105 .is_valid = validate_singlecw_ending,
106};
107Step
108eoany_HTM = {
109 .shortname = "eo",
110 .name = "EO on any axis",
111 .alt = {&sa_eofb_HTM, &sa_eofb_HTM, &sa_eofb_HTM, NULL},
112 .t = {uf, ur, fd},
113 .ready_msg = check_centers_msg,
114};
115Step
116eofb_HTM = {
117 .shortname = "eofb",
118 .name = "EO on F/B",
119 .alt = {&sa_eofb_HTM, NULL},
120 .t = {uf},
121 .ready_msg = check_centers_msg,
122};
123Step
124eorl_HTM = {
125 .shortname = "eorl",
126 .name = "EO on R/L",
127 .alt = {&sa_eofb_HTM, NULL},
128 .t = {ur},
129 .ready_msg = check_centers_msg,
130};
131Step
132eoud_HTM = {
133 .shortname = "eoud",
134 .name = "EO on U/D",
135 .alt = {&sa_eofb_HTM, NULL},
136 .t = {fd},
137 .ready_msg = check_centers_msg,
138};
139
140/* CO steps **************************/
141/* TODO: coany_HTM (generic), cofb_HTM, corl_HTM, coud_HTM */
142/* TODO: coany_URF (generic), cofb_URF, corl_URF, coud_URF */
143
144/* Misc corner steps *****************/
145/* TODO: cornershtr_HTM, cornershtr_URF, corners_HTM, corners_URF */
146/* TODO (new): corners_drud */
147
148/* DR steps **************************/
149/* TODO: dr_eo (generic) */
150/* TODO: dr_eofb (generic), dr_eorl (generic), dr_eoud (generic) */
151/* TODO: drud_eofb, drrl_eofb, drud_eorl, drfb_eorl, drrl_eoud, drfb_eoud */
152
153StepAlt
154sa_drud_HTM = {
155 .ready = check_centers,
156 .final = false,
157 .moveset = &moveset_HTM,
158 .n_coord = 1,
159 .coord = {&coord_drud_sym16},
160 .coord_trans = {uf},
161 .compact_pd = {false}, /* TODO: maybe compactify */
162 .n_dbtrick = 0,
163 .is_valid = validate_singlecw_ending,
164};
165Step
166drany_HTM = {
167 .shortname = "dr",
168 .name = "DR on any axis",
169 .alt = {&sa_drud_HTM, &sa_drud_HTM, &sa_drud_HTM, NULL},
170 .t = {uf, rf, fd},
171 .ready_msg = check_centers_msg,
172};
173Step
174drud_HTM = {
175 .shortname = "drud",
176 .name = "DR on U/D",
177 .alt = {&sa_drud_HTM, NULL},
178 .t = {uf},
179 .ready_msg = check_centers_msg,
180};
181Step
182drrl_HTM = {
183 .shortname = "drrl",
184 .name = "DR on R/L",
185 .alt = {&sa_drud_HTM, NULL},
186 .t = {rf},
187 .ready_msg = check_centers_msg,
188};
189Step
190drfb_HTM = {
191 .shortname = "drfb",
192 .name = "DR on F/B",
193 .alt = {&sa_drud_HTM, NULL},
194 .t = {fd},
195 .ready_msg = check_centers_msg,
196};
197
198/* DR finish steps */
199StepAlt
200sa_drfin_drud = {
201 .ready = check_drud,
202 .final = true,
203 .moveset = &moveset_drud,
204 .n_coord = 1,
205 .coord = {&coord_drudfin_noE_sym16}, /* TODO: maybe no noE */
206 .coord_trans = {uf},
207 .compact_pd = {false}, /* TODO: maybe compactify */
208 .n_dbtrick = 0,
209 .is_valid = NULL,
210};
211Step
212dranyfin_DR = {
213 .shortname = "drfin",
214 .name = "DR finish on any axis without breaking DR",
215 .alt = {&sa_drfin_drud, &sa_drfin_drud, &sa_drfin_drud, NULL},
216 .t = {uf, rf, fd},
217 .ready_msg = check_dr_msg,
218};
219Step
220drudfin_drud = {
221 .shortname = "drudfin",
222 .name = "DR finis on U/D without breaking DR",
223 .alt = {&sa_drfin_drud, NULL},
224 .t = {uf},
225 .ready_msg = check_dr_msg,
226};
227Step
228drrlfin_drrl = {
229 .shortname = "drrlfin",
230 .name = "DR finish on R/L without breaking DR",
231 .alt = {&sa_drfin_drud, NULL},
232 .t = {rf},
233 .ready_msg = check_dr_msg,
234};
235Step
236drfbfin_drfb = {
237 .shortname = "drfbfin",
238 .name = "DR finish on F/B without breaking DR",
239 .alt = {&sa_drfin_drud, NULL},
240 .t = {fd},
241 .ready_msg = check_dr_msg,
242};
243
244/* HTR from DR */
245/* TODO: htr_any (generic), htr_drud, htr_drrl, htr_drfb */
246
247/* HTR finish */
248/* TODO: htrfin_htr */
249
250Step *steps[] = {
251 &optimal_HTM, /* first is default */
252
253 &eoany_HTM, &eofb_HTM, &eorl_HTM, &eoud_HTM,
254 &drany_HTM, &drud_HTM, &drrl_HTM, &drfb_HTM,
255 &dranyfin_DR, &drudfin_drud, &drrlfin_drrl, &drfbfin_drfb,
256
257/* TODO:
258 &optimal_light_HTM,
259
260 &eofin_eo, &eofbfin_eofb, &eorlfin_eorl, &eoudfin_eoud,
261 &coany_HTM, &coud_HTM, &corl_HTM, &cofb_HTM,
262 &coany_URF, &coud_URF, &corl_URF, &cofb_URF,
263 &dr_eo, &dr_eofb, &dr_eorl, &dr_eoud,
264 &drud_eofb, &drrl_eofb,
265 &drud_eorl, &drfb_eorl,
266 &drfb_eoud, &drrl_eoud,
267 &htr_any, &htr_drud, &htr_drrl, &htr_drfb,
268 &htrfin_htr,
269 &cornershtr_HTM, &cornershtr_URF, &corners_HTM, &corners_URF,
270 NULL
271*/
272
273};
274
275#endif
16 276
17#endif 277#endif
diff --git a/src/symcoord.c b/src/symcoord.c
deleted file mode 100644
index 20d7c28..0000000
--- a/src/symcoord.c
+++ /dev/null
@@ -1,687 +0,0 @@
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
deleted file mode 100644
index 0882bff..0000000
--- a/src/symcoord.h
+++ /dev/null
@@ -1,17 +0,0 @@
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/trans.c b/src/trans.c
index e267a17..da2dca3 100644
--- a/src/trans.c
+++ b/src/trans.c
@@ -1,31 +1,23 @@
1#define TRANS_C
2
1#include "trans.h" 3#include "trans.h"
2 4
3/* Local functions ***********************************************************/ 5/* Local functions ***********************************************************/
4 6
5static bool read_ttables_file();
6static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f);
7static bool write_ttables_file();
8
9/* Tables and other data *****************************************************/ 7/* Tables and other data *****************************************************/
10 8
11static int ep_mirror[12] = { 9static Cube mirror_cube = {
12 [UF] = UF, [UL] = UR, [UB] = UB, [UR] = UL, 10.ep = { [UF] = UF, [UL] = UR, [UB] = UB, [UR] = UL,
13 [DF] = DF, [DL] = DR, [DB] = DB, [DR] = DL, 11 [DF] = DF, [DL] = DR, [DB] = DB, [DR] = DL,
14 [FR] = FL, [FL] = FR, [BL] = BR, [BR] = BL 12 [FR] = FL, [FL] = FR, [BL] = BR, [BR] = BL },
15}; 13.cp = { [UFR] = UFL, [UFL] = UFR, [UBL] = UBR, [UBR] = UBL,
16 14 [DFR] = DFL, [DFL] = DFR, [DBL] = DBR, [DBR] = DBL },
17static int cp_mirror[8] = { 15.xp = { [U_center] = U_center, [D_center] = D_center,
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,
24 [R_center] = L_center, [L_center] = R_center, 16 [R_center] = L_center, [L_center] = R_center,
25 [F_center] = F_center, [B_center] = B_center 17 [F_center] = F_center, [B_center] = B_center }
26}; 18};
27 19
28static char rotation_alg_string[100][NROTATIONS] = { 20static char rotation_alg_string[100][NROTATIONS] = {
29 [uf] = "", [ur] = "y", [ub] = "y2", [ul] = "y3", 21 [uf] = "", [ur] = "y", [ub] = "y2", [ul] = "y3",
30 [df] = "z2", [dr] = "y z2", [db] = "x2", [dl] = "y3 z2", 22 [df] = "z2", [dr] = "y z2", [db] = "x2", [dl] = "y3 z2",
31 [rf] = "z3", [rd] = "z3 y", [rb] = "z3 y2", [ru] = "z3 y3", 23 [rf] = "z3", [rd] = "z3 y", [rb] = "z3 y2", [ru] = "z3 y3",
@@ -34,176 +26,39 @@ static char rotation_alg_string[100][NROTATIONS] = {
34 [bu] = "x3", [br] = "x3 y", [bd] = "x3 y2", [bl] = "x3 y3", 26 [bu] = "x3", [br] = "x3 y", [bd] = "x3 y2", [bl] = "x3 y3",
35}; 27};
36 28
37static int epose_source[NTRANS]; /* 0=epose, 1=eposs, 2=eposm */ 29static Alg *rotation_alg_arr[NROTATIONS];
38static int eposs_source[NTRANS]; 30Move moves_ttable[NTRANS][NMOVES];
39static int eposm_source[NTRANS]; 31Trans trans_ttable[NTRANS][NTRANS];
40static int eofb_source[NTRANS]; /* 0=eoud, 1=eorl, 2=eofb */ 32Trans trans_itable[NTRANS];
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];
46 33
47int epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; 34/* Public functions **********************************************************/
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];
55
56/* Local functions implementation ********************************************/
57 35
58static bool 36void
59read_ttables_file() 37apply_trans(Trans t, Cube *cube)
60{ 38{
61 init_env(); 39 Cube aux;
62 40 Alg *inv;
63 FILE *f; 41 int i;
64 char fname[strlen(tabledir)+20];
65 int b = sizeof(int);
66 bool r = true;
67 Move m;
68
69 /* Table sizes, used for reading and writing files */
70 uint64_t me[11] = {
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 42
85 if ((f = fopen(fname, "rb")) == NULL) 43 inv = inverse_alg(rotation_alg(t % NROTATIONS));
86 return false; 44 copy_cube(cube, &aux);
45 make_solved(cube);
87 46
88 for (m = 0; m < NTRANS; m++) { 47 if (t >= NROTATIONS)
89 r = r && fread(epose_ttable[m], b, me[0], f) == me[0]; 48 compose(&mirror_cube, cube);
90 r = r && fread(eposs_ttable[m], b, me[1], f) == me[1]; 49 apply_alg(inv, cube);
91 r = r && fread(eposm_ttable[m], b, me[2], f) == me[2]; 50 compose(&aux, cube);
92 r = r && fread(eo_ttable[m], b, me[3], f) == me[3]; 51 apply_alg(rotation_alg(t % NROTATIONS), cube);
93 r = r && fread(cp_ttable[m], b, me[4], f) == me[4]; 52 if (t >= NROTATIONS) {
94 r = r && fread(co_ttable[m], b, me[5], f) == me[5]; 53 compose(&mirror_cube, cube);
95 r = r && fread(cpos_ttable[m], b, me[6], f) == me[6]; 54 for (i = 0; i < 8; i++)
96 r = r && fread(moves_ttable[m], b, me[7], f) == me[7]; 55 cube->co[i] = (3 - cube->co[i]) % 3;
97 } 56 }
98 57
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
133 free_alg(inv); 58 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 };
205} 59}
206 60
61/*
207Trans 62Trans
208inverse_trans(Trans t) 63inverse_trans(Trans t)
209{ 64{
@@ -231,23 +86,18 @@ inverse_trans(Trans t)
231 86
232 return inverse_trans_aux[t]; 87 return inverse_trans_aux[t];
233} 88}
89*/
234 90
235Alg * 91Trans
236rotation_alg(Trans t) 92inverse_trans(Trans t)
237{ 93{
238 int i; 94 return trans_itable[t];
239 95}
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 96
250 return rotation_alg_arr[t % NROTATIONS]; 97Alg *
98rotation_alg(Trans i)
99{
100 return rotation_alg_arr[i % NROTATIONS];
251} 101}
252 102
253void 103void
@@ -255,10 +105,20 @@ transform_alg(Trans t, Alg *alg)
255{ 105{
256 int i; 106 int i;
257 107
258 /*init_trans();*/
259
260 for (i = 0; i < alg->len; i++) 108 for (i = 0; i < alg->len; i++)
261 alg->move[i] = moves_ttable[t][alg->move[i]]; 109 alg->move[i] = transform_move(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];
262} 122}
263 123
264void 124void
@@ -268,106 +128,63 @@ init_trans() {
268 return; 128 return;
269 initialized = true; 129 initialized = true;
270 130
271 init_moves(); 131 int i;
272 132 Alg *nonsym_alg, *nonsym_inv;
273 Cube aux, cube, c[3]; 133 Cube aux, cube;
274 CubeArray epcp;
275 int i, eparr[12], eoarr[12], cparr[8], coarr[8];
276 unsigned int ui;
277 Move mi, move; 134 Move mi, move;
278 Trans m; 135 Trans t, u, v;
279 136
280 /* Compute sources */ 137 init_moves();
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 }
294
295 if (read_ttables_file())
296 return;
297
298 fprintf(stderr, "Cannot load %s, generating it\n", "ttables");
299
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 138
318 cube = rotate_via_compose(m,c[eposs_source[m]],pf_ep); 139 for (i = 0; i < NROTATIONS; i++)
319 eposs_ttable[m][ui] = cube.eposs; 140 rotation_alg_arr[i] = new_alg(rotation_alg_string[i]);
320 141
321 cube = rotate_via_compose(m,c[eposm_source[m]],pf_ep); 142 for (t = 0; t < NTRANS; t++) {
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 }
347 for (mi = 0; mi < NMOVES; mi++) { 143 for (mi = 0; mi < NMOVES; mi++) {
348 /* Old version: 144 make_solved(&aux);
349 * 145 apply_move(mi, &aux);
350 aux = apply_trans(m, apply_move(mi, (Cube){0})); 146 apply_trans(t, &aux);
351 for (move = 0; move < NMOVES; move++) { 147 for (move = 0; move < NMOVES; move++) {
352 cube = apply_move(inverse_move(move), aux); 148 copy_cube(&aux, &cube);
353 mirr = apply_trans(uf_mirror, cube); 149 apply_move(inverse_move(move), &cube);
354 if (is_solved(cube) || is_solved(mirr)) 150 if (is_solved(&cube)) {
355 moves_ttable[m][mi] = move; 151 moves_ttable[t][mi] = move;
152 break;
153 }
356 } 154 }
357 */ 155 }
156 }
358 157
359 aux = apply_trans(m, apply_move(mi, (Cube){0})); 158 nonsym_alg = new_alg("R' U' F");
360 for (move = 0; move < NMOVES; move++) { 159 nonsym_inv = inverse_alg(nonsym_alg);
361 cube = apply_move(inverse_move(move), aux); 160
362 if (is_solved(cube)) { 161 for (t = 0; t < NTRANS; t++) {
363 moves_ttable[m][mi] = move; 162 for (u = 0; u < NTRANS; u++) {
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;
364 break; 177 break;
365 } 178 }
366 } 179 }
367 } 180 }
368 } 181 }
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
369 186
370 if (!write_ttables_file()) 187 free_alg(nonsym_alg);
371 fprintf(stderr, "Error writing ttables\n"); 188 free_alg(nonsym_inv);
372} 189}
373 190
diff --git a/src/trans.h b/src/trans.h
index 51df12f..0cc8cef 100644
--- a/src/trans.h
+++ b/src/trans.h
@@ -3,24 +3,30 @@
3 3
4#include "moves.h" 4#include "moves.h"
5 5
6/* 6void apply_trans(Trans t, Cube *cube);
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);
20Trans inverse_trans(Trans t); 7Trans inverse_trans(Trans t);
21Alg * rotation_alg(Trans i); 8Alg * rotation_alg(Trans i);
22void transform_alg(Trans i, Alg *alg); 9void transform_alg(Trans t, Alg *alg);
10Move transform_move(Trans t, Move m);
11Trans transform_trans(Trans t, Trans m);
23 12
24void init_trans(); 13void init_trans();
25 14
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
26#endif 32#endif
diff --git a/src/utils.c b/src/utils.c
index e0d3268..cbf951e 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -1,3 +1,5 @@
1#define UTILS_C
2
1#include "utils.h" 3#include "utils.h"
2 4
3void 5void
@@ -159,24 +161,24 @@ is_perm(int *a, int n)
159{ 161{
160 int *aux = malloc(n * sizeof(int)); 162 int *aux = malloc(n * sizeof(int));
161 int i; 163 int i;
164 bool ret = true;
162 165
163 for (i = 0; i < n; i++) 166 for (i = 0; i < n; i++)
164 aux[i] = 0; 167 aux[i] = 0;
165 168
166 for (i = 0; i < n; i++) { 169 for (i = 0; i < n; i++) {
167 if (a[i] < 0 || a[i] >= n) 170 if (a[i] < 0 || a[i] >= n)
168 return false; 171 ret = false;
169 else 172 else
170 aux[a[i]] = 1; 173 aux[a[i]] = 1;
171 } 174 }
172 175
173 for (i = 0; i < n; i++) 176 for (i = 0; i < n; i++)
174 if (!aux[i]) 177 if (!aux[i])
175 return false; 178 ret = false;
176 179
177 free(aux); 180 free(aux);
178 181 return ret;
179 return true;
180} 182}
181 183
182bool 184bool
@@ -195,7 +197,7 @@ perm_sign(int *a, int n)
195{ 197{
196 int i, j, ret = 0; 198 int i, j, ret = 0;
197 199
198 if (!is_perm(a,n)) 200 if (!is_perm(a, n))
199 return -1; 201 return -1;
200 202
201 for (i = 0; i < n; i++) 203 for (i = 0; i < n; i++)
@@ -211,7 +213,7 @@ perm_to_index(int *a, int n)
211 int i, j, c, ret = 0; 213 int i, j, c, ret = 0;
212 214
213 if (!is_perm(a, n)) 215 if (!is_perm(a, n))
214 return -1; 216 return factorial(n);
215 217
216 for (i = 0; i < n; i++) { 218 for (i = 0; i < n; i++) {
217 c = 0; 219 c = 0;
diff --git a/www/download/index.html b/www/download/index.html
index b115244..01c4895 100644
--- a/www/download/index.html
+++ b/www/download/index.html
@@ -2,7 +2,7 @@
2<html lang="en"> 2<html lang="en">
3<head> 3<head>
4 <title> Download | Nissy </title> 4 <title> Download | Nissy </title>
5<meta name="viewport" content="width=device-width" /> <link rel="stylesheet" type="text/css" href="/style.css"> 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"> 6 <link rel="icon" href="/favicon.png">
7 <meta charset="utf-8"> 7 <meta charset="utf-8">
8</head> 8</head>
diff --git a/www/examples/index.html b/www/examples/index.html
index 24eda85..517c251 100644
--- a/www/examples/index.html
+++ b/www/examples/index.html
@@ -2,7 +2,7 @@
2<html lang="en"> 2<html lang="en">
3<head> 3<head>
4 <title> Examples | Nissy </title> 4 <title> Examples | Nissy </title>
5<meta name="viewport" content="width=device-width" /> <link rel="stylesheet" type="text/css" href="/style.css"> 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"> 6 <link rel="icon" href="/favicon.png">
7 <meta charset="utf-8"> 7 <meta charset="utf-8">
8</head> 8</head>
diff --git a/www/index.html b/www/index.html
index 0b7e67e..500952c 100644
--- a/www/index.html
+++ b/www/index.html
@@ -2,7 +2,7 @@
2<html lang="en"> 2<html lang="en">
3<head> 3<head>
4 <title> Nissy | Nissy </title> 4 <title> Nissy | Nissy </title>
5<meta name="viewport" content="width=device-width" /> <link rel="stylesheet" type="text/css" href="/style.css"> 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"> 6 <link rel="icon" href="/favicon.png">
7 <meta charset="utf-8"> 7 <meta charset="utf-8">
8</head> 8</head>
diff --git a/www/style.css b/www/style-2.css
index 1487497..ec70635 100644
--- a/www/style.css
+++ b/www/style-2.css
@@ -32,11 +32,17 @@ img {
32 max-width: 100%; 32 max-width: 100%;
33} 33}
34 34
35pre, code { 35code {
36 background-color: #eeeeee; 36 background-color: #eeeeee;
37 padding: 2px;
38}
39
40pre code {
41 padding: 0px;
37} 42}
38 43
39pre { 44pre {
45 background-color: #eeeeee;
40 border: 2px solid; 46 border: 2px solid;
41 padding: 6px; 47 padding: 6px;
42} 48}

Generated with cgit - Back to sebastiano.tronto.net