aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSebastiano Tronto <sebastiano.tronto@gmail.com>2021-11-11 21:37:34 +0100
committerSebastiano Tronto <sebastiano.tronto@gmail.com>2021-11-11 21:37:34 +0100
commit3568412f8f230774d0d11d7ed1c897424f95d3ef (patch)
tree77223792d8c925a9b1fc32b3f4341e943b5f8209 /src
parent67e1b5e6e6a2c917a2fe58a37a1382c982b1e5c5 (diff)
downloadnissy-3568412f8f230774d0d11d7ed1c897424f95d3ef.tar.gz
nissy-3568412f8f230774d0d11d7ed1c897424f95d3ef.zip
Rewritten from scratch. Welocme nissy 2.0!
Diffstat (limited to '')
-rw-r--r--src/alg.c364
-rw-r--r--src/alg.h35
-rw-r--r--src/commands.c346
-rw-r--r--src/commands.h13
-rw-r--r--src/coord.c522
-rw-r--r--src/coord.h23
-rw-r--r--src/coordinates.c286
-rw-r--r--src/coordinates.h92
-rw-r--r--src/cube.c701
-rw-r--r--src/cube.h40
-rw-r--r--src/cubetypes.h286
-rw-r--r--src/env.c45
-rw-r--r--src/env.h15
-rw-r--r--src/helppages.h689
-rw-r--r--src/io.c232
-rw-r--r--src/io.h21
-rw-r--r--src/main.c937
-rw-r--r--src/moves.c860
-rw-r--r--src/moves.h91
-rw-r--r--src/pf.c80
-rw-r--r--src/pf.h18
-rw-r--r--src/pruning.c271
-rw-r--r--src/pruning.h23
-rw-r--r--src/pruning_tables.c483
-rw-r--r--src/pruning_tables.h66
-rw-r--r--src/shell.c93
-rw-r--r--src/shell.h13
-rw-r--r--src/solve.c173
-rw-r--r--src/solve.h9
-rw-r--r--src/solver.c1058
-rw-r--r--src/solver.h16
-rw-r--r--src/steps.c941
-rw-r--r--src/steps.h10
-rw-r--r--src/symcoord.c355
-rw-r--r--src/symcoord.h15
-rw-r--r--src/trans.c375
-rw-r--r--src/trans.h13
-rw-r--r--src/utils.c356
-rw-r--r--src/utils.h91
39 files changed, 5484 insertions, 4573 deletions
diff --git a/src/alg.c b/src/alg.c
new file mode 100644
index 0000000..354bdb6
--- /dev/null
+++ b/src/alg.c
@@ -0,0 +1,364 @@
1#include "alg.h"
2
3/* Local functions ***********************************************************/
4
5static void free_alglistnode(AlgListNode *aln);
6static void realloc_alg(Alg *alg, int n);
7
8/* Movesets ******************************************************************/
9
10bool
11moveset_HTM(Move m)
12{
13 return m >= U && m <= B3;
14}
15
16bool
17moveset_URF(Move m)
18{
19 Move b = base_move(m);
20
21 return b == U || b == R || b == F;
22}
23
24bool
25moveset_eofb(Move m)
26{
27 Move b = base_move(m);
28
29 return b == U || b == D || b == R || b == L ||
30 ((b == F || b == B) && m == b+1);
31}
32
33bool
34moveset_drud(Move m)
35{
36 Move b = base_move(m);
37
38 return b == U || b == D ||
39 ((b == R || b == L || b == F || b == B) && m == b + 1);
40}
41
42bool
43moveset_htr(Move m)
44{
45 Move b = base_move(m);
46
47 return moveset_HTM(m) && m == b + 1;
48}
49
50
51/* Functions *****************************************************************/
52
53void
54append_alg(AlgList *l, Alg *alg)
55{
56 AlgListNode *node = malloc(sizeof(AlgListNode));
57 int i;
58
59 node->alg = new_alg("");
60 for (i = 0; i < alg->len; i++)
61 append_move(node->alg, alg->move[i], alg->inv[i]);
62 node->next = NULL;
63
64 if (++l->len == 1)
65 l->first = node;
66 else
67 l->last->next = node;
68 l->last = node;
69}
70
71void
72append_move(Alg *alg, Move m, bool inverse)
73{
74 if (alg->len == alg->allocated)
75 realloc_alg(alg, 2*alg->len);
76
77 alg->move[alg->len] = m;
78 alg->inv [alg->len] = inverse;
79 alg->len++;
80}
81
82Move
83base_move(Move m)
84{
85 if (m == NULLMOVE)
86 return NULLMOVE;
87 else
88 return m - (m-1)%3;
89}
90
91void
92compose_alg(Alg *alg1, Alg *alg2)
93{
94 int i;
95
96 for (i = 0; i < alg2->len; i++)
97 append_move(alg1, alg2->move[i], alg2->inv[i]);
98}
99
100void
101free_alg(Alg *alg)
102{
103 free(alg->move);
104 free(alg->inv);
105 free(alg);
106}
107
108void
109free_alglist(AlgList *l)
110{
111 AlgListNode *aux, *i = l->first;
112
113 while (i != NULL) {
114 aux = i->next;
115 free_alglistnode(i);
116 i = aux;
117 }
118 free(l);
119}
120
121static void
122free_alglistnode(AlgListNode *aln)
123{
124 free_alg(aln->alg);
125 free(aln);
126}
127
128Alg *
129inverse_alg(Alg *alg)
130{
131 Alg *ret = new_alg("");
132 int i;
133
134 for (i = alg->len-1; i >= 0; i--)
135 append_move(ret, inverse_move(alg->move[i]), alg->inv[i]);
136
137 return ret;
138}
139
140Move
141inverse_move(Move m)
142{
143 return m == NULLMOVE ? NULLMOVE : m + 2 - 2*((m-1) % 3);
144}
145
146char *
147move_string(Move m)
148{
149 static char move_string_aux[NMOVES][7] = {
150 [NULLMOVE] = "-",
151 [U] = "U", [U2] = "U2", [U3] = "U\'",
152 [D] = "D", [D2] = "D2", [D3] = "D\'",
153 [R] = "R", [R2] = "R2", [R3] = "R\'",
154 [L] = "L", [L2] = "L2", [L3] = "L\'",
155 [F] = "F", [F2] = "F2", [F3] = "F\'",
156 [B] = "B", [B2] = "B2", [B3] = "B\'",
157 [Uw] = "Uw", [Uw2] = "Uw2", [Uw3] = "Uw\'",
158 [Dw] = "Dw", [Dw2] = "Dw2", [Dw3] = "Dw\'",
159 [Rw] = "Rw", [Rw2] = "Rw2", [Rw3] = "Rw\'",
160 [Lw] = "Lw", [Lw2] = "Lw2", [Lw3] = "Lw\'",
161 [Fw] = "Fw", [Fw2] = "Fw2", [Fw3] = "Fw\'",
162 [Bw] = "Bw", [Bw2] = "Bw2", [Bw3] = "Bw\'",
163 [M] = "M", [M2] = "M2", [M3] = "M\'",
164 [E] = "E", [E2] = "E2", [E3] = "E\'",
165 [S] = "S", [S2] = "S2", [S3] = "S\'",
166 [x] = "x", [x2] = "x2", [x3] = "x\'",
167 [y] = "y", [y2] = "y2", [y3] = "y\'",
168 [z] = "z", [z2] = "z2", [z3] = "z\'",
169 };
170
171 return move_string_aux[m];
172}
173
174void
175movelist_to_position(Move *movelist, int *position)
176{
177 Move m;
178
179 for (m = 0; m < NMOVES && movelist[m] != NULLMOVE; m++)
180 position[movelist[m]] = m;
181}
182
183void
184moveset_to_list(Moveset ms, Move *r)
185{
186 int n = 0;
187 Move i;
188
189 if (ms == NULL) {
190 fprintf(stderr, "Error: no moveset given\n");
191 return;
192 }
193
194 for (i = U; i < NMOVES; i++)
195 if (ms(i))
196 r[n++] = i;
197
198 r[n] = NULLMOVE;
199}
200
201Alg *
202new_alg(char *str)
203{
204 Alg *alg = malloc(sizeof(Alg));
205 int i;
206 bool niss = false, move_read;
207 Move j, m;
208
209 alg->move = malloc(30 * sizeof(Move));
210 alg->inv = malloc(30 * sizeof(bool));
211 alg->allocated = 30;
212 alg->len = 0;
213
214 for (i = 0; str[i]; i++) {
215 if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n')
216 continue;
217
218 if (str[i] == '(' && niss) {
219 fprintf(stderr, "Error reading moves: nested ( )\n");
220 return alg;
221 }
222
223 if (str[i] == ')' && !niss) {
224 fprintf(stderr, "Error reading moves: unmatched )\n");
225 return alg;
226 }
227
228 if (str[i] == '(' || str[i] == ')') {
229 niss = !niss;
230 continue;
231 }
232
233 move_read = false;
234 for (j = 0; j < NMOVES; j++) {
235 if (str[i] == move_string(j)[0] ||
236 (str[i] >= 'a' && str[i] <= 'z' &&
237 str[i] == move_string(j)[0]-('A'-'a') && j<=B)) {
238 m = j;
239 if (str[i] >= 'a' && str[i] <= 'z' && j<=B) {
240 m += Uw - U;
241 }
242 if (m <= B && str[i+1]=='w') {
243 m += Uw - U;
244 i++;
245 }
246 if (str[i+1]=='2') {
247 m += 1;
248 i++;
249 } else if (str[i+1] == '\'' ||
250 str[i+1] == '3' ||
251 str[i+1] == '`' ) {
252 m += 2;
253 i++;
254 } else if ((int)str[i+1] == -62 &&
255 (int)str[i+2] == -76) {
256 /* Weird apostrophe */
257 m += 2;
258 i += 2;
259 } else if ((int)str[i+1] == -30 &&
260 (int)str[i+2] == -128 &&
261 (int)str[i+3] == -103) {
262 /* MacOS apostrophe */
263 m += 2;
264 i += 3;
265 }
266 append_move(alg, m, niss);
267 move_read = true;
268 break;
269 }
270 }
271
272 if (!move_read) {
273 alg = new_alg("");
274 return alg;
275 }
276 }
277
278 return alg;
279}
280
281AlgList *
282new_alglist()
283{
284 AlgList *ret = malloc(sizeof(AlgList));
285
286 ret->len = 0;
287 ret->first = NULL;
288 ret->last = NULL;
289
290 return ret;
291}
292
293Alg *
294on_inverse(Alg *alg)
295{
296 Alg *ret = new_alg("");
297 int i;
298
299 for (i = 0; i < alg->len; i++)
300 append_move(ret, alg->move[i], !alg->inv[i]);
301
302 return ret;
303}
304
305void
306print_alg(Alg *alg, bool l)
307{
308 char fill[4];
309 int i;
310 bool niss = false;
311
312 for (i = 0; i < alg->len; i++) {
313 if (!niss && alg->inv[i])
314 strcpy(fill, i == 0 ? "(" : " (");
315 if (niss && !alg->inv[i])
316 strcpy(fill, ") ");
317 if (niss == alg->inv[i])
318 strcpy(fill, i == 0 ? "" : " ");
319
320 printf("%s%s", fill, move_string(alg->move[i]));
321 niss = alg->inv[i];
322 }
323
324 if (niss)
325 printf(")");
326 if (l)
327 printf(" (%d)", alg->len);
328
329 printf("\n");
330}
331
332void
333print_alglist(AlgList *al, bool l)
334{
335 AlgListNode *i;
336
337 for (i = al->first; i != NULL; i = i->next)
338 print_alg(i->alg, l);
339}
340
341static void
342realloc_alg(Alg *alg, int n)
343{
344 if (alg == NULL) {
345 fprintf(stderr, "Error: trying to reallocate NULL alg.\n");
346 return;
347 }
348
349 if (n < alg->len) {
350 fprintf(stderr, "Error: alg too long for reallocation ");
351 fprintf(stderr, "(%d vs %d)\n", alg->len, n);
352 return;
353 }
354
355 if (n > 1000000) {
356 fprintf(stderr, "Warning: very long alg,");
357 fprintf(stderr, "something might go wrong.\n");
358 }
359
360 alg->move = realloc(alg->move, n * sizeof(int));
361 alg->inv = realloc(alg->inv, n * sizeof(int));
362 alg->allocated = n;
363}
364
diff --git a/src/alg.h b/src/alg.h
new file mode 100644
index 0000000..98900b4
--- /dev/null
+++ b/src/alg.h
@@ -0,0 +1,35 @@
1#ifndef ALG_H
2#define ALG_H
3
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7
8#include "cubetypes.h"
9#include "utils.h"
10
11bool moveset_HTM(Move m);
12bool moveset_URF(Move m);
13bool moveset_eofb(Move m);
14bool moveset_drud(Move m);
15bool moveset_htr(Move m);
16
17void append_alg(AlgList *l, Alg *alg);
18void append_move(Alg *alg, Move m, bool inverse);
19void compose_alg(Alg *alg1, Alg *alg2);
20Move base_move(Move m);
21void free_alg(Alg *alg);
22void free_alglist(AlgList *l);
23Alg * inverse_alg(Alg *alg);
24Move inverse_move(Move m);
25char * move_string(Move m);
26void movelist_to_position(Move *ml, int *pos);
27void moveset_to_list(Moveset ms, Move *lst);
28Alg * new_alg(char *str);
29AlgList * new_alglist();
30Alg * on_inverse(Alg *alg);
31void print_alg(Alg *alg, bool l);
32void print_alglist(AlgList *al, bool l);
33
34#endif
35
diff --git a/src/commands.c b/src/commands.c
new file mode 100644
index 0000000..10e4eb8
--- /dev/null
+++ b/src/commands.c
@@ -0,0 +1,346 @@
1#include "commands.h"
2
3/* Arg parsing functions *****************************************************/
4
5CommandArgs * solve_parse_args(int c, char **v);
6CommandArgs * help_parse_args(int c, char **v);
7CommandArgs * print_parse_args(int c, char **v);
8CommandArgs * parse_no_arg(int c, char **v);
9
10/* Exec functions ************************************************************/
11
12static void solve_exec(CommandArgs *args);
13static void steps_exec(CommandArgs *args);
14static void commands_exec(CommandArgs *args);
15static void print_exec(CommandArgs *args);
16static void help_exec(CommandArgs *args);
17static void quit_exec(CommandArgs *args);
18static void version_exec(CommandArgs *args);
19
20/* Local functions ***********************************************************/
21
22static bool read_step(CommandArgs *args, char *str);
23static bool read_scramble(int c, char **v, CommandArgs *args);
24
25/* Commands ******************************************************************/
26
27Command
28solve_cmd = {
29 .name = "solve",
30 .usage = "solve STEP [OPTIONS] SCRAMBLE",
31 .description = "Solve a step",
32 .parse_args = solve_parse_args,
33 .exec = solve_exec
34};
35
36Command
37steps_cmd = {
38 .name = "steps",
39 .usage = "steps",
40 .description = "List available steps",
41 .parse_args = parse_no_arg,
42 .exec = steps_exec
43};
44
45Command
46commands_cmd = {
47 .name = "commands",
48 .usage = "commands",
49 .description = "List available commands",
50 .parse_args = parse_no_arg,
51 .exec = commands_exec
52};
53
54Command
55print_cmd = {
56 .name = "print",
57 .usage = "print SCRAMBLE",
58 .description = "Print written description of the cube",
59 .parse_args = print_parse_args,
60 .exec = print_exec,
61};
62
63Command
64help_cmd = {
65 .name = "help",
66 .usage = "help [COMMAND]",
67 .description = "Display nissy manual page or help on specific command",
68 .parse_args = help_parse_args,
69 .exec = help_exec,
70};
71
72Command
73quit_cmd = {
74 .name = "quit",
75 .usage = "quit",
76 .description = "Quit nissy",
77 .parse_args = parse_no_arg,
78 .exec = quit_exec,
79};
80
81Command
82version_cmd = {
83 .name = "version",
84 .usage = "version",
85 .description = "print nissy version",
86 .parse_args = parse_no_arg,
87 .exec = version_exec,
88};
89
90Command *commands[NCOMMANDS] = {
91 &commands_cmd,
92 &help_cmd,
93 &print_cmd,
94 &quit_cmd,
95 &solve_cmd,
96 &steps_cmd,
97 &version_cmd,
98};
99
100/* Arg parsing functions implementation **************************************/
101
102CommandArgs *
103solve_parse_args(int c, char **v)
104{
105 int i;
106 long val;
107
108 CommandArgs *a = malloc(sizeof(CommandArgs));
109
110 a->success = false;
111 a->opts = malloc(sizeof(SolveOptions));
112 a->step = steps[0];
113 a->command = NULL;
114 a->scramble = NULL;
115
116 a->opts->min_moves = 0;
117 a->opts->max_moves = 20;
118 a->opts->max_solutions = 1;
119 a->opts->optimal_only = false;
120 a->opts->can_niss = false;
121 a->opts->verbose = false;
122 a->opts->all = false;
123 a->opts->print_number = true;
124
125 for (i = 0; i < c; i++) {
126 if (!strcmp(v[i], "-m")) {
127 val = strtol(v[++i], NULL, 10);
128 if (val < 0 || val > 100) {
129 fprintf(stderr,
130 "Invalid min number of moves.\n");
131 return a;
132 }
133 a->opts->min_moves = val;
134 } else if (!strcmp(v[i], "-M")) {
135 val = strtol(v[++i], NULL, 10);
136 if (val < 0 || val > 100) {
137 fprintf(stderr,
138 "Invalid max number of moves.\n");
139 return a;
140 }
141 a->opts->max_moves = val;
142 } else if (!strcmp(v[i], "-s")) {
143 val = strtol(v[++i], NULL, 10);
144 if (val < 1 || val > 1000000) {
145 fprintf(stderr,
146 "Invalid number of solutions.\n");
147 return a;
148 }
149 a->opts->max_solutions = val;
150 } else if (!strcmp(v[i], "-o")) {
151 a->opts->optimal_only = true;
152 } else if (!strcmp(v[i], "-n")) {
153 a->opts->can_niss = true;
154 } else if (!strcmp(v[i], "-v")) {
155 a->opts->verbose = true;
156 } else if (!strcmp(v[i], "-a")) {
157 a->opts->all = true;
158 } else if (!strcmp(v[i], "-p")) {
159 a->opts->print_number = false;
160 } else if (!read_step(a, v[i])) {
161 break;
162 }
163 }
164
165 a->success = read_scramble(c-i, &v[i], a);
166 return a;
167}
168
169CommandArgs *
170help_parse_args(int c, char **v)
171{
172 int i;
173 CommandArgs *a = malloc(sizeof(CommandArgs));
174
175 a->scramble = NULL;
176 a->opts = NULL;
177 a->step = NULL;
178 a->command = NULL;
179
180 if (c == 1) {
181 for (i = 0; i < NCOMMANDS; i++)
182 if (commands[i] != NULL &&
183 !strcmp(v[0], commands[i]->name))
184 a->command = commands[i];
185 if (a->command == NULL)
186 fprintf(stderr, "%s: command not found\n", v[0]);
187 }
188
189 a->success = c == 0 || (c == 1 && a->command != NULL);
190 return a;
191}
192
193CommandArgs *
194parse_no_arg(int c, char **v)
195{
196 CommandArgs *a = malloc(sizeof(CommandArgs));
197
198 a->success = true;
199
200 return a;
201}
202
203CommandArgs *
204print_parse_args(int c, char **v)
205{
206 CommandArgs *a = malloc(sizeof(CommandArgs));
207
208 a->success = read_scramble(c, v, a);
209 return a;
210}
211
212/* Exec functions implementation *********************************************/
213
214static void
215solve_exec(CommandArgs *args)
216{
217 Cube c;
218 AlgList *sols;
219
220 init_symcoord();
221
222 c = apply_alg(args->scramble, (Cube){0});
223 sols = solve(c, args->step, args->opts);
224
225 print_alglist(sols, args->opts->print_number);
226 free_alglist(sols);
227}
228
229static void
230steps_exec(CommandArgs *args)
231{
232 int i;
233
234 for (i = 0; i < NSTEPS && steps[i] != NULL; i++)
235 printf("%-15s %s\n", steps[i]->shortname, steps[i]->name);
236}
237
238static void
239commands_exec(CommandArgs *args)
240{
241 int i;
242
243 for (i = 0; i < NCOMMANDS && commands[i] != NULL; i++)
244 printf("%s\n", commands[i]->usage);
245
246}
247
248static void
249print_exec(CommandArgs *args)
250{
251 init_moves();
252 print_cube(apply_alg(args->scramble, (Cube){0}));
253}
254
255static void
256help_exec(CommandArgs *args)
257{
258 /* TODO: print full nissy manpage */
259 if (args->command == NULL) {
260 printf("Type help COMMAND for information on a ");
261 printf("specific command.\n");
262 printf("A more complete manual page is work in progress.\n");
263 } else {
264 printf("Command %s: %s\nusage: %s\n", args->command->name,
265 args->command->description, args->command->usage);
266 }
267}
268
269static void
270quit_exec(CommandArgs *args)
271{
272 exit(0);
273}
274
275static void
276version_exec(CommandArgs *args)
277{
278 printf(VERSION"\n");
279}
280
281/* Local functions implementation ********************************************/
282
283static bool
284read_step(CommandArgs *args, char *str)
285{
286 int i;
287
288 for (i = 0; i < NSTEPS; i++) {
289 if (steps[i] != NULL && !strcmp(steps[i]->shortname, str)) {
290 args->step = steps[i];
291 return true;
292 }
293 }
294
295 return false;
296}
297
298static bool
299read_scramble(int c, char **v, CommandArgs *args)
300{
301 int i, k, n;
302 unsigned int j;
303 char *algstr;
304
305 if (new_alg(v[0])->len == 0) {
306 fprintf(stderr, "%s: moves or option unrecognized\n", v[0]);
307 return false;
308 }
309
310 n = 0;
311 for(i = 0; i < c; i++)
312 n += strlen(v[i]);
313
314 algstr = malloc((n + 1) * sizeof(char));
315 k = 0;
316 for (i = 0; i < c; i++)
317 for (j = 0; j < strlen(v[i]); j++)
318 algstr[k++] = v[i][j];
319 algstr[k] = 0;
320
321 args->scramble = new_alg(algstr);
322 free(algstr);
323
324 if (args->scramble->len == 0)
325 fprintf(stderr, "Error reading scramble\n");
326
327 return args->scramble->len > 0;
328}
329
330/* Public functions implementation *******************************************/
331
332void
333free_args(CommandArgs *args)
334{
335 if (args == NULL)
336 return;
337
338 if (args->scramble != NULL)
339 free_alg(args->scramble);
340 if (args->opts != NULL)
341 free(args->opts);
342
343 /* step and command must not be freed, they are static! */
344
345 free(args);
346}
diff --git a/src/commands.h b/src/commands.h
new file mode 100644
index 0000000..f2703fa
--- /dev/null
+++ b/src/commands.h
@@ -0,0 +1,13 @@
1#ifndef COMMANDS_H
2#define COMMANDS_H
3
4#include "solve.h"
5#include "steps.h"
6
7#define NCOMMANDS 10
8
9void free_args(CommandArgs *args);
10
11extern Command * commands[NCOMMANDS];
12
13#endif
diff --git a/src/coord.c b/src/coord.c
new file mode 100644
index 0000000..8c978bc
--- /dev/null
+++ b/src/coord.c
@@ -0,0 +1,522 @@
1#include "coord.h"
2
3static Cube antindex_eofb(uint64_t ind);
4static Cube antindex_eofbepos(uint64_t ind);
5static Cube antindex_epud(uint64_t ind);
6static Cube antindex_coud(uint64_t ind);
7static Cube antindex_corners(uint64_t ind);
8static Cube antindex_cp(uint64_t ind);
9static Cube antindex_cphtr(uint64_t);
10static Cube antindex_cornershtr(uint64_t ind);
11static Cube antindex_cornershtrfin(uint64_t ind);
12static Cube antindex_drud(uint64_t ind);
13static Cube antindex_drud_eofb(uint64_t ind);
14static Cube antindex_htr_drud(uint64_t ind);
15static Cube antindex_htrfin(uint64_t ind);
16
17static uint64_t index_eofb(Cube cube);
18static uint64_t index_eofbepos(Cube cube);
19static uint64_t index_epud(Cube cube);
20static uint64_t index_coud(Cube cube);
21static uint64_t index_corners(Cube cube);
22static uint64_t index_cp(Cube cube);
23static uint64_t index_cphtr(Cube cube);
24static uint64_t index_cornershtr(Cube cube);
25static uint64_t index_cornershtrfin(Cube cube);
26static uint64_t index_drud(Cube cube);
27static uint64_t index_drud_eofb(Cube cube);
28static uint64_t index_htr_drud(Cube cube);
29static uint64_t index_htrfin(Cube cube);
30
31static void init_cphtr_cosets();
32static void init_cphtr_left_cosets_bfs(int i, int c);
33static void init_cphtr_right_cosets_color(int i, int c);
34static void init_cornershtrfin();
35
36
37/* All sorts of useful costants and tables **********************************/
38
39static int cphtr_left_cosets[FACTORIAL8];
40static int cphtr_right_cosets[FACTORIAL8];
41static int cphtr_right_rep[BINOM8ON4*6];
42static int cornershtrfin_ind[FACTORIAL8];
43static int cornershtrfin_ant[24*24/6];
44
45/* Coordinates and their implementation **************************************/
46
47Coordinate
48coord_eofb = {
49 .index = index_eofb,
50 .cube = antindex_eofb,
51 .max = POW2TO11,
52 .ntrans = 1,
53};
54
55Coordinate
56coord_eofbepos = {
57 .index = index_eofbepos,
58 .cube = antindex_eofbepos,
59 .max = POW2TO11 * BINOM12ON4,
60 .ntrans = 1,
61};
62
63Coordinate
64coord_coud = {
65 .index = index_coud,
66 .cube = antindex_coud,
67 .max = POW3TO7,
68 .ntrans = 1,
69};
70
71Coordinate
72coord_corners = {
73 .index = index_corners,
74 .cube = antindex_corners,
75 .max = POW3TO7 * FACTORIAL8,
76 .ntrans = 1,
77};
78
79Coordinate
80coord_cp = {
81 .index = index_cp,
82 .cube = antindex_cp,
83 .max = FACTORIAL8,
84 .ntrans = 1,
85};
86
87Coordinate
88coord_cphtr = {
89 .index = index_cphtr,
90 .cube = antindex_cphtr,
91 .max = BINOM8ON4 * 6,
92 .ntrans = 1,
93};
94
95Coordinate
96coord_cornershtr = {
97 .index = index_cornershtr,
98 .cube = antindex_cornershtr,
99 .max = POW3TO7 * BINOM8ON4 * 6,
100 .ntrans = 1,
101};
102
103Coordinate
104coord_cornershtrfin = {
105 .index = index_cornershtrfin,
106 .cube = antindex_cornershtrfin,
107 .max = 24*24/6,
108 .ntrans = 1,
109};
110
111Coordinate
112coord_epud = {
113 .index = index_epud,
114 .cube = antindex_epud,
115 .max = FACTORIAL8,
116 .ntrans = 1,
117};
118
119Coordinate
120coord_drud = {
121 .index = index_drud,
122 .cube = antindex_drud,
123 .max = POW2TO11 * POW3TO7 * BINOM12ON4,
124 .ntrans = 1,
125};
126
127Coordinate
128coord_htr_drud = {
129 .index = index_htr_drud,
130 .cube = antindex_htr_drud,
131 .max = BINOM8ON4 * 6 * BINOM8ON4,
132 .ntrans = 1,
133};
134
135Coordinate
136coord_htrfin = {
137 .index = index_htrfin,
138 .cube = antindex_htrfin,
139 .max = 24 * 24 * 24 *24 * 24 / 6, /* should be /12 but it's ok */
140 .ntrans = 1,
141};
142
143Coordinate
144coord_drud_eofb = {
145 .index = index_drud_eofb,
146 .cube = antindex_drud_eofb,
147 .max = POW3TO7 * BINOM12ON4,
148 .ntrans = 1,
149};
150
151/* Functions *****************************************************************/
152
153static Cube
154antindex_eofb(uint64_t ind)
155{
156 return (Cube){ .eofb = ind, .eorl = ind, .eoud = ind };
157}
158
159static Cube
160antindex_eofbepos(uint64_t ind)
161{
162 Cube ret = {0};
163
164 ret.eofb = ind % POW2TO11;
165 ret.epose = (ind / POW2TO11) * 24;
166
167 return ret;
168}
169
170static Cube
171antindex_epud(uint64_t ind)
172{
173 static bool initialized = false;
174 static Cube epud_aux[FACTORIAL8];
175 int a[12];
176 uint64_t ui;
177 CubeArray arr;
178
179 if (!initialized) {
180 a[FR] = FR;
181 a[FL] = FL;
182 a[BL] = BL;
183 a[BR] = BR;
184 for (ui = 0; ui < FACTORIAL8; ui++) {
185 index_to_perm(ui, 8, a);
186 arr.ep = a;
187 epud_aux[ui] = arrays_to_cube(&arr, pf_ep);
188 }
189
190 initialized = true;
191 }
192
193 return epud_aux[ind];
194}
195
196static Cube
197antindex_coud(uint64_t ind)
198{
199 return (Cube){ .coud = ind, .corl = ind, .cofb = ind };
200}
201
202static Cube
203antindex_corners(uint64_t ind)
204{
205 Cube c = {0};
206
207 c.coud = ind / FACTORIAL8;
208 c.cp = ind % FACTORIAL8;
209
210 return c;
211}
212
213static Cube
214antindex_cp(uint64_t ind)
215{
216 Cube c = {0};
217
218 c.cp = ind;
219
220 return c;
221}
222
223static Cube
224antindex_cphtr(uint64_t ind)
225{
226 return (Cube) { .cp = cphtr_right_rep[ind] };
227}
228
229static Cube
230antindex_cornershtr(uint64_t ind)
231{
232 Cube c = antindex_cphtr(ind % (BINOM8ON4 * 6));
233
234 c.coud = ind / (BINOM8ON4 * 6);
235
236 return c;
237}
238
239static Cube
240antindex_cornershtrfin(uint64_t ind)
241{
242 return (Cube){ .cp = cornershtrfin_ant[ind] };
243}
244
245static Cube
246antindex_drud(uint64_t ind)
247{
248 uint64_t epos, eofb;
249 Cube c;
250
251 eofb = ind % POW2TO11;
252 epos = ind / (POW2TO11 * POW3TO7);
253 c = antindex_eofbepos(eofb + POW2TO11 * epos);
254
255 c.coud = (ind / POW2TO11) % POW3TO7;
256
257 return c;
258}
259
260static Cube
261antindex_drud_eofb(uint64_t ind)
262{
263 return antindex_drud(ind * POW2TO11);
264}
265
266static Cube
267antindex_htr_drud(uint64_t ind)
268{
269 Cube ret;
270
271 ret = antindex_cphtr(ind / BINOM8ON4);
272 ret.eposs = (ind % BINOM8ON4) * FACTORIAL4;
273
274 return ret;
275}
276
277static Cube
278antindex_htrfin(uint64_t ind)
279{
280 Cube ret;
281
282 ret = antindex_cornershtrfin(ind/(24*24*24));
283
284 ret.eposm = ind % 24;
285 ind /= 24;
286 ret.eposs = ind % 24;
287 ind /= 24;
288 ret.epose = ind % 24;
289
290 return ret;
291}
292
293static uint64_t
294index_eofb(Cube cube)
295{
296 return cube.eofb;
297}
298
299static uint64_t
300index_eofbepos(Cube cube)
301{
302 return (cube.epose / FACTORIAL4) * POW2TO11 + cube.eofb;
303}
304
305static uint64_t
306index_epud(Cube cube)
307{
308 uint64_t ret;
309 CubeArray *arr = new_cubearray(cube, pf_ep);
310
311 ret = perm_to_index(arr->ep, 8);
312 free_cubearray(arr, pf_ep);
313
314 return ret;
315}
316
317static uint64_t
318index_coud(Cube cube)
319{
320 return cube.coud;
321}
322
323static uint64_t
324index_corners(Cube cube)
325{
326 return cube.coud * FACTORIAL8 + cube.cp;
327}
328
329static uint64_t
330index_cp(Cube cube)
331{
332 return cube.cp;
333}
334
335static uint64_t
336index_cphtr(Cube cube)
337{
338 return cphtr_right_cosets[cube.cp];
339}
340
341static uint64_t
342index_cornershtr(Cube cube)
343{
344 return cube.coud * BINOM8ON4 * 6 + index_cphtr(cube);
345}
346
347static uint64_t
348index_cornershtrfin(Cube cube)
349{
350 return cornershtrfin_ind[cube.cp];
351}
352
353static uint64_t
354index_drud(Cube cube)
355{
356 uint64_t a, b, c;
357
358 a = cube.eofb;
359 b = cube.coud;
360 c = cube.epose / FACTORIAL4;
361
362 b *= POW2TO11;
363 c *= POW2TO11 * POW3TO7;
364
365 return a + b + c;
366}
367
368static uint64_t
369index_drud_eofb(Cube cube)
370{
371 return index_drud(cube) / POW2TO11;
372}
373
374static uint64_t
375index_htr_drud(Cube cube)
376{
377 return index_cphtr(cube) * BINOM8ON4 +
378 (cube.eposs / FACTORIAL4) % BINOM8ON4;
379}
380
381static uint64_t
382index_htrfin(Cube cube)
383{
384 uint64_t epe, eps, epm, cp, ep;
385
386 epe = cube.epose % 24;
387 eps = cube.eposs % 24;
388 epm = cube.eposm % 24;
389 ep = (epe * 24 + eps) *24 + epm;
390 cp = index_cornershtrfin(cube);
391
392 return cp * 24 * 24 * 24 + ep;
393}
394
395/* Init functions implementation *********************************************/
396
397/*
398 * There is certainly a better way to do this, but for now I just use
399 * a "graph coloring" algorithm to compute the left cosets, and I compose
400 * with every possible cp to get the right cosets (it is possible that I am
401 * mixing up left and right).
402 *
403 * For doing it better "Mathematically", we need 3 things:
404 * - Checking that cp separates the orbits (UFR,UBL,DFL,DBR) and the other
405 * This is easy and it is done in the commented function cphtr_cp().
406 * - Check that there is no ep/cp parity
407 * - Check that we are not in the "3c" case; this is the part I don't
408 * know how to do.
409 */
410static void
411init_cphtr_cosets()
412{
413 unsigned int i;
414 int c = 0, d = 0;
415
416 for (i = 0; i < FACTORIAL8; i++) {
417 cphtr_left_cosets[i] = -1;
418 cphtr_right_cosets[i] = -1;
419 }
420
421 /* First we compute left cosets with a bfs */
422 for (i = 0; i < FACTORIAL8; i++)
423 if (cphtr_left_cosets[i] == -1)
424 init_cphtr_left_cosets_bfs(i, c++);
425
426 /* Then we compute right cosets using compose() */
427 for (i = 0; i < FACTORIAL8; i++)
428 if (cphtr_right_cosets[i] == -1)
429 init_cphtr_right_cosets_color(i, d++);
430}
431
432static void
433init_cphtr_left_cosets_bfs(int i, int c)
434{
435 int j, jj, next[FACTORIAL8], next2[FACTORIAL8], n, n2;
436
437 Move k;
438
439 n = 1;
440 next[0] = i;
441 cphtr_left_cosets[i] = c;
442
443 while (n != 0) {
444 for (j = 0, n2 = 0; j < n; j++) {
445 for (k = U2; k < B3; k++) {
446 if (!moveset_htr(k))
447 continue;
448 jj = apply_move(k, (Cube){ .cp = next[j] }).cp;
449
450 if (cphtr_left_cosets[jj] == -1) {
451 cphtr_left_cosets[jj] = c;
452 next2[n2++] = jj;
453 }
454 }
455 }
456
457 for (j = 0; j < n2; j++)
458 next[j] = next2[j];
459 n = n2;
460 }
461}
462
463static void
464init_cphtr_right_cosets_color(int i, int d)
465{
466 int cp;
467 unsigned int j;
468
469 cphtr_right_rep[d] = i;
470 for (j = 0; j < FACTORIAL8; j++) {
471 if (cphtr_left_cosets[j] == 0) {
472 cp = compose((Cube){.cp = i}, (Cube){.cp = j}).cp;
473 cphtr_right_cosets[cp] = d;
474 }
475 }
476}
477
478static void
479init_cornershtrfin()
480{
481 unsigned int i, j;
482 int n, c;
483 Move m;
484
485 for (i = 0; i < FACTORIAL8; i++)
486 cornershtrfin_ind[i] = -1;
487 cornershtrfin_ind[0] = 0;
488
489 /* 10-pass, I think 5 is enough, but just in case */
490 n = 1;
491 for (i = 0; i < 10; i++) {
492 for (j = 0; j < FACTORIAL8; j++) {
493 if (cornershtrfin_ind[j] == -1)
494 continue;
495 for (m = U; m < NMOVES; m++) {
496 if (moveset_htr(m)) {
497 c = apply_move(m, (Cube){.cp = j}).cp;
498 if (cornershtrfin_ind[c] == -1) {
499 cornershtrfin_ind[c] = n;
500 cornershtrfin_ant[n] = c;
501 n++;
502 }
503 }
504 }
505 }
506 }
507}
508
509void
510init_coord()
511{
512 static bool initialized = false;
513 if (initialized)
514 return;
515 initialized = true;
516
517 init_trans();
518
519 init_cphtr_cosets();
520 init_cornershtrfin();
521}
522
diff --git a/src/coord.h b/src/coord.h
new file mode 100644
index 0000000..be41b96
--- /dev/null
+++ b/src/coord.h
@@ -0,0 +1,23 @@
1#ifndef COORD_H
2#define COORD_H
3
4#include "trans.h"
5
6extern Coordinate coord_eofb;
7extern Coordinate coord_eofbepos;
8extern Coordinate coord_coud;
9extern Coordinate coord_cp;
10extern Coordinate coord_cphtr;
11extern Coordinate coord_corners;
12extern Coordinate coord_cornershtr;
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;
19
20void init_coord();
21
22#endif
23
diff --git a/src/coordinates.c b/src/coordinates.c
deleted file mode 100644
index be61698..0000000
--- a/src/coordinates.c
+++ /dev/null
@@ -1,286 +0,0 @@
1#include <stdio.h>
2
3#include "utils.h"
4#include "coordinates.h"
5
6/* Names of pieces and moves. */
7char edge_string_list[12][5] = {
8 "UF", "UL", "UB", "UR", "DF", "DL", "DB", "DR", "FR", "FL", "BL", "BR"
9};
10
11char corner_string_list[8][5] = {
12 "UFR", "UFL", "UBL", "UBR", "DFR", "DFL", "DBL", "DBR"
13};
14
15char move_string_list[19][5] = {
16 "-",
17 "U", "U2", "U\'", "D", "D2", "D\'", "R", "R2", "R\'",
18 "L", "L2", "L\'", "F", "F2", "F\'", "B", "B2", "B\'"
19};
20
21int inverse_move[19] = {
22 -1, U3, U2, U, D3, D2, D, R3, R2, R, L3, L2, L, F3, F2, F, B3, B2, B
23};
24
25/* Convert piece representation from integer to array.
26 * Come convertions are not "perfect": for example, and epud type of piece
27 * is represented by a permutation index in 8! elements, but it as an array
28 * it is converted to the first 8 elements of a 12 elements ep array (with
29 * meaningless values for the other 4 elements). */
30
31void ep_int_to_array(int ep, int a[12]) {
32 index_to_perm(ep, 12, a);
33}
34
35void epud_int_to_array(int epud, int a[12]) {
36 index_to_perm(epud, 8, a); /* Last 4 elements are left untouched. */
37}
38
39void epfb_int_to_array(int epfb, int a[12]) {
40 int edges[] = {UF, UB, DF, DB, FR, FL, BL, BR};
41 int b[8];
42 index_to_perm(epfb, 8, b);
43 for (int i = 0; i < 8; i++)
44 a[edges[i]] = edges[b[i]];
45}
46
47void eprl_int_to_array(int eprl, int a[12]) {
48 int edges[] = {UL, UR, DL, DR, FR, FL, BL, BR};
49 int b[8];
50 index_to_perm(eprl, 8, b);
51 for (int i = 0; i < 8; i++)
52 a[edges[i]] = edges[b[i]];
53}
54
55void epose_int_to_array(int epos, int a[12]) {
56 int edges[] = {FR, FL, BL, BR};
57 index_to_subset(epos, 12, 4, a);
58 for (int i = 0, j = 0; i < 12; i++)
59 a[i] = (a[i] == 1) ? edges[j++] : -1;
60}
61
62void eposs_int_to_array(int epos, int a[12]) {
63 int edges[] = {UL, UR, DL, DR};
64 index_to_subset(epos, 12, 4, a);
65 for (int i = 0, j = 0; i < 12; i++)
66 a[i] = (a[i] == 1) ? edges[j++] : -1;
67 /* Swap with last 4, so 0 is alway solved state */
68 for (int i = 0; i < 4; i++)
69 swap(&a[edges[i]], &a[i+8]);
70}
71
72void eposm_int_to_array(int epos, int a[12]) {
73 int edges[] = {UF, UB, DF, DB};
74 index_to_subset(epos, 12, 4, a);
75 for (int i = 0, j = 0; i < 12; i++)
76 a[i] = (a[i] == 1) ? edges[j++] : -1;
77 /* Swap with last 4, so 0 is alway solved state */
78 for (int i = 0; i < 4; i++)
79 swap(&a[edges[i]], &a[i+8]);
80}
81
82void epe_int_to_array(int epe, int a[12]) {
83 index_to_perm(epe, 4, a+8);
84 for (int i = 0; i < 4; i++)
85 a[i+8] += 8;
86}
87
88void eps_int_to_array(int eps, int a[12]) {
89 int edges[] = {UL, UR, DL, DR};
90 int b[4];
91 index_to_perm(eps, 4, b);
92 for (int i = 0; i < 4; i++)
93 a[edges[i]] = edges[b[i]];
94}
95
96void epm_int_to_array(int epm, int a[12]) {
97 int edges[] = {UF, UB, DF, DB};
98 int b[4];
99 index_to_perm(epm, 4, b);
100 for (int i = 0; i < 4; i++)
101 a[edges[i]] = edges[b[i]];
102}
103
104void emslices_int_to_array(int emslices, int a[12]) {
105 int b[] = {0,0,0,0,0,0,0,0};
106 int eslice[] = {FR, FL, BL, BR};
107 int mslice[] = {UF, UB, DF, DB};
108
109 index_to_subset(emslices % binom12on4, 12, 4, a);
110 index_to_subset(emslices / binom12on4, 8, 4, b);
111
112 if (emslices % binom12on4 == 0) {
113 swap(&b[UF], &b[DL]);
114 swap(&b[UB], &b[DR]);
115 /*for (int i = 0; i < 4; i++)
116 swap(&b[mslice[i]], &b[i+4]);*/
117 }
118
119 for (int i = 0, j = 0; j < 8; i++, j++) {
120 while (a[i])
121 i++;
122 a[i] = b[j] ? 2 : -1;
123 }
124 for (int i = 0, j1 = 0, j2 = 0; i < 12; i++) {
125 if (a[i] == 1)
126 a[i] = eslice[j1++];
127 if (a[i] == 2)
128 a[i] = mslice[j2++];
129 }
130}
131
132void cp_int_to_array(int cp, int a[8]) {
133 index_to_perm(cp, 8, a);
134}
135
136void eo_11bits_to_array(int eo, int a[12]) {
137 int_to_sum_zero_array(eo, 2, 12, a);
138}
139
140void co_7trits_to_array(int co, int a[8]) {
141 int_to_sum_zero_array(co, 3, 8, a);
142}
143
144
145
146
147
148int ep_array_to_int(int ep[12]) {
149 return perm_to_index(ep, 12);
150}
151
152int epud_array_to_int(int ep[12]) {
153 return perm_to_index(ep, 8); /* Last 4 elements are ignored */
154}
155
156int epfb_array_to_int(int ep[12]) {
157 int index[] = {0, -1, 1, -1, 2, -1, 3, -1, 4, 5, 6, 7};
158 int b[8];
159 for (int i = 0; i < 12; i++)
160 if (index[i] != -1)
161 b[index[i]] = index[ep[i]];
162 return perm_to_index(b, 8);
163}
164
165int eprl_array_to_int(int ep[12]) {
166 int index[] = {-1, 0, -1, 1, -1, 2, -1, 3, 4, 5, 6, 7};
167 int b[8];
168 for (int i = 0; i < 12; i++)
169 if (index[i] != -1)
170 b[index[i]] = index[ep[i]];
171 return perm_to_index(b, 8);
172}
173
174int epose_array_to_int(int ep[12]) {
175 int a[12];
176 for (int i = 0; i < 12; i++)
177 a[i] = (ep[i] >= FR);
178 return subset_to_index(a, 12, 4);
179}
180
181int eposs_array_to_int(int ep[12]) {
182 int a[12];
183 int edges[] = {UL, UR, DL, DR};
184 for (int i = 0; i < 12; i++)
185 a[i] = (ep[i] == UL || ep[i] == UR || ep[i] == DL || ep[i] == DR);
186 /* Swap with last 4, so 0 is alway solved state */
187 for (int i = 0; i < 4; i++)
188 swap(&a[edges[i]], &a[i+8]);
189 return subset_to_index(a, 12, 4);
190}
191
192int eposm_array_to_int(int ep[12]) {
193 int a[12];
194 int edges[] = {UF, UB, DF, DB};
195 for (int i = 0; i < 12; i++)
196 a[i] = (ep[i] == UF || ep[i] == UB || ep[i] == DF || ep[i] == DB);
197 /* Swap with last 4, so 0 is alway solved state */
198 for (int i = 0; i < 4; i++)
199 swap(&a[edges[i]], &a[i+8]);
200 return subset_to_index(a, 12, 4);
201}
202
203int epe_array_to_int(int ep[12]) {
204 int b[4];
205 for (int i = 0; i < 4; i++)
206 b[i] = ep[i+8] - 8;
207 return perm_to_index(b, 4);
208}
209
210int eps_array_to_int(int ep[12]) {
211 int index[] = {-1, 0, -1, 1, -1, 2, -1, 3, -1, -1, -1, -1};
212 int b[4];
213 for (int i = 0; i < 12; i++)
214 if (index[i] != -1)
215 b[index[i]] = index[ep[i]];
216 return perm_to_index(b, 4);
217}
218
219int epm_array_to_int(int ep[12]) {
220 int index[] = {0, -1, 1, -1, 2, -1, 3, -1, -1, -1, -1, -1};
221 int b[4];
222 for (int i = 0; i < 12; i++)
223 if (index[i] != -1)
224 b[index[i]] = index[ep[i]];
225 return perm_to_index(b, 4);
226}
227
228int emslices_array_to_int(int ep[12]) {
229 int a[12], b[12], c[8] = {0, 0, 0, 0, 0, 0, 0, 0};
230 /*int edges[] = {UF, UB, DF, DB};*/
231 for (int i = 0; i < 12; i++) {
232 a[i] = (ep[i] >= FR) ? 1 : 0;
233 b[i] = (ep[i] == UF || ep[i] == UB || ep[i] == DF || ep[i] == DB) ? 1 : 0;
234 }
235
236 /*for ( int i = 0; i < 12; i++)
237 printf("%d ", ep[i]);
238 printf("\n");*/
239
240 for (int i = 0, j = 0; i < 12; i++, j++) {
241 if (a[i])
242 j--;
243 if (b[i])
244 c[j] = 1;
245 }
246
247 int epose = subset_to_index(a, 12, 4);
248
249 /*if (epose == 0) {
250 printf("Before: ");
251 for (int i = 0; i < 8; i++)
252 printf("%d ", c[i]);
253 printf("\n");
254 for (int i = 0; i < 4; i++)
255 swap(&c[edges[i]], &c[i+4]);
256 printf("After: ");
257 for (int i = 0; i < 8; i++)
258 printf("%d ", c[i]);
259 printf("\n");
260 }*/
261 if (epose == 0) {
262 swap(&c[UF], &c[DL]);
263 swap(&c[UB], &c[DR]);
264 }
265
266 /*for ( int i = 0; i < 8; i++)
267 printf("%d ", c[i]);
268 printf("\n");*/
269 int eposm = subset_to_index(c, 8, 4);
270
271 return epose + 495*eposm;
272}
273
274
275int cp_array_to_int(int cp[8]) {
276 return perm_to_index(cp, 8);
277}
278
279int eo_array_to_11bits(int a[12]) {
280 return digit_array_to_int(a, 11, 2);
281}
282
283int co_array_to_7trits(int a[8]) {
284 return digit_array_to_int(a, 7, 3);
285}
286
diff --git a/src/coordinates.h b/src/coordinates.h
deleted file mode 100644
index 10f7d18..0000000
--- a/src/coordinates.h
+++ /dev/null
@@ -1,92 +0,0 @@
1/* General rule for piece numbering (visually nicer):
2 *
3 * 0 1 2 3 4 5 6 7 8 9 10 11
4 * UF UL UB UR DF DL DB DR FR FL BL BR
5 * UFR UFL UBL UBR DFR DFL DBL DBR
6 *
7 * The order of moves is
8 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
9 * - U U2 U' D D2 D' R R2 R' L L2 L' F F2 F' B B2 B'
10 * (0 is reserved for no move) */
11
12#define UF 0
13#define UL 1
14#define UB 2
15#define UR 3
16#define DF 4
17#define DL 5
18#define DB 6
19#define DR 7
20#define FR 8
21#define FL 9
22#define BL 10
23#define BR 11
24
25#define UFR 0
26#define UFL 1
27#define UBL 2
28#define UBR 3
29#define DFR 4
30#define DFL 5
31#define DBL 6
32#define DBR 7
33
34#define U 1
35#define U2 2
36#define U3 3
37#define D 4
38#define D2 5
39#define D3 6
40#define R 7
41#define R2 8
42#define R3 9
43#define L 10
44#define L2 11
45#define L3 12
46#define F 13
47#define F2 14
48#define F3 15
49#define B 16
50#define B2 17
51#define B3 18
52
53extern char edge_string_list[12][5];
54extern char corner_string_list[8][5];
55extern char move_string_list[19][5];
56extern int inverse_move[19];
57
58/* Convert piece representation from integer to array.
59 * Come convertions are not "perfect": for example, and epud type of piece
60 * is represented by a permutation index in 8! elements, but it as an array
61 * it is converted to the first 8 elements of a 12 elements ep array (with
62 * meaningless values for the other 4 elements). */
63
64void ep_int_to_array(int ep, int a[12]);
65void epud_int_to_array(int epud, int a[12]);
66void epfb_int_to_array(int epfb, int a[12]);
67void eprl_int_to_array(int eprl, int a[12]);
68void epose_int_to_array(int epos, int a[12]);
69void eposs_int_to_array(int epos, int a[12]);
70void eposm_int_to_array(int epos, int a[12]);
71void epe_int_to_array(int epe, int a[12]);
72void epm_int_to_array(int epe, int a[12]);
73void eps_int_to_array(int epe, int a[12]);
74void emslices_int_to_array(int emslices, int a[12]);
75void cp_int_to_array(int cp, int a[8]);
76void eo_11bits_to_array(int eo, int a[12]);
77void co_7trits_to_array(int co, int a[8]);
78
79int ep_array_to_int(int ep[12]);
80int epud_array_to_int(int ep[12]);
81int epfb_array_to_int(int ep[12]);
82int eprl_array_to_int(int ep[12]);
83int epose_array_to_int(int ep[12]);
84int eposs_array_to_int(int ep[12]);
85int eposm_array_to_int(int ep[12]);
86int epe_array_to_int(int epe[12]);
87int epm_array_to_int(int epe[12]);
88int eps_array_to_int(int epe[12]);
89int emslices_array_to_int(int ep[12]);
90int cp_array_to_int(int cp[8]);
91int eo_array_to_11bits(int a[12]);
92int co_array_to_7trits(int a[8]);
diff --git a/src/cube.c b/src/cube.c
new file mode 100644
index 0000000..06c8b8c
--- /dev/null
+++ b/src/cube.c
@@ -0,0 +1,701 @@
1#include "cube.h"
2
3/* Local functions **********************************************************/
4
5static int array_ep_to_epos(int *ep, int *eps_solved);
6static int epos_from_arrays(int *epos, int *ep);
7
8/* Local functions implementation ********************************************/
9
10static int
11array_ep_to_epos(int *ep, int *ss)
12{
13 int epos[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
14 int eps[4];
15 int i, j, is;
16
17 for (i = 0, is = 0; i < 12; i++) {
18 for (j = 0; j < 4; j++) {
19 if (ep[i] == ss[j]) {
20 eps[is++] = j;
21 epos[i] = 1;
22 }
23 }
24 }
25
26 for (i = 0; i < 4; i++)
27 swap(&epos[ss[i]], &epos[i+8]);
28
29 return epos_from_arrays(epos, eps);
30}
31
32static int
33epos_from_arrays(int *epos, int *ep)
34{
35 return FACTORIAL4 * subset_to_index(epos,12,4) + perm_to_index(ep,4);
36}
37
38/* Public functions implementation *******************************************/
39
40Cube
41arrays_to_cube(CubeArray *arr, PieceFilter f)
42{
43 Cube ret = {0};
44
45 static int epe_solved[4] = {FR, FL, BL, BR};
46 static int eps_solved[4] = {UL, UR, DL, DR};
47 static int epm_solved[4] = {UF, UB, DF, DB};
48
49 if (f.epose)
50 ret.epose = array_ep_to_epos(arr->ep, epe_solved);
51 if (f.eposs)
52 ret.eposs = array_ep_to_epos(arr->ep, eps_solved);
53 if (f.eposm)
54 ret.eposm = array_ep_to_epos(arr->ep, epm_solved);
55 if (f.eofb)
56 ret.eofb = digit_array_to_int(arr->eofb, 11, 2);
57 if (f.eorl)
58 ret.eorl = digit_array_to_int(arr->eorl, 11, 2);
59 if (f.eoud)
60 ret.eoud = digit_array_to_int(arr->eoud, 11, 2);
61 if (f.cp)
62 ret.cp = perm_to_index(arr->cp, 8);
63 if (f.coud)
64 ret.coud = digit_array_to_int(arr->coud, 7, 3);
65 if (f.corl)
66 ret.corl = digit_array_to_int(arr->corl, 7, 3);
67 if (f.cofb)
68 ret.cofb = digit_array_to_int(arr->cofb, 7, 3);
69 if (f.cpos)
70 ret.cpos = perm_to_index(arr->cpos, 6);
71
72 return ret;
73}
74
75Cube
76compose_filtered(Cube c2, Cube c1, PieceFilter f)
77{
78 CubeArray *arr = new_cubearray(c2, f);
79 Cube ret;
80
81 ret = move_via_arrays(arr, c1, f);
82 free_cubearray(arr, f);
83
84 return ret;
85}
86
87void
88cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f)
89{
90 int i;
91
92 static int epe_solved[4] = {FR, FL, BL, BR};
93 static int eps_solved[4] = {UL, UR, DL, DR};
94 static int epm_solved[4] = {UF, UB, DF, DB};
95
96 if (f.epose || f.eposs || f.eposm)
97 for (i = 0; i < 12; i++)
98 arr->ep[i] = -1;
99
100 if (f.epose)
101 epos_to_partial_ep(cube.epose, arr->ep, epe_solved);
102 if (f.eposs)
103 epos_to_partial_ep(cube.eposs, arr->ep, eps_solved);
104 if (f.eposm)
105 epos_to_partial_ep(cube.eposm, arr->ep, epm_solved);
106 if (f.eofb)
107 int_to_sum_zero_array(cube.eofb, 2, 12, arr->eofb);
108 if (f.eorl)
109 int_to_sum_zero_array(cube.eorl, 2, 12, arr->eorl);
110 if (f.eoud)
111 int_to_sum_zero_array(cube.eoud, 2, 12, arr->eoud);
112 if (f.cp)
113 index_to_perm(cube.cp, 8, arr->cp);
114 if (f.coud)
115 int_to_sum_zero_array(cube.coud, 3, 8, arr->coud);
116 if (f.corl)
117 int_to_sum_zero_array(cube.corl, 3, 8, arr->corl);
118 if (f.cofb)
119 int_to_sum_zero_array(cube.cofb, 3, 8, arr->cofb);
120 if (f.cpos)
121 index_to_perm(cube.cpos, 6, arr->cpos);
122}
123
124void
125epos_to_partial_ep(int epos, int *ep, int *ss)
126{
127 int i, is, eposs[12], eps[4];
128
129 index_to_perm(epos % FACTORIAL4, 4, eps);
130 index_to_subset(epos / FACTORIAL4, 12, 4, eposs);
131
132 for (i = 0; i < 4; i++)
133 swap(&eposs[ss[i]], &eposs[i+8]);
134
135 for (i = 0, is = 0; i < 12; i++)
136 if (eposs[i])
137 ep[i] = ss[eps[is++]];
138}
139
140void
141free_cubearray(CubeArray *arr, PieceFilter f)
142{
143 if (f.epose || f.eposs || f.eposm)
144 free(arr->ep);
145 if (f.eofb)
146 free(arr->eofb);
147 if (f.eorl)
148 free(arr->eorl);
149 if (f.eoud)
150 free(arr->eoud);
151 if (f.cp)
152 free(arr->cp);
153 if (f.coud)
154 free(arr->coud);
155 if (f.corl)
156 free(arr->corl);
157 if (f.cofb)
158 free(arr->cofb);
159 if (f.cpos)
160 free(arr->cpos);
161
162 free(arr);
163}
164
165Cube
166move_via_arrays(CubeArray *arr, Cube c, PieceFilter f)
167{
168 CubeArray *arrc = new_cubearray(c, f);
169 Cube ret;
170
171 if (f.epose || f.eposs || f.eposm)
172 apply_permutation(arr->ep, arrc->ep, 12);
173
174 if (f.eofb) {
175 apply_permutation(arr->ep, arrc->eofb, 12);
176 sum_arrays_mod(arr->eofb, arrc->eofb, 12, 2);
177 }
178
179 if (f.eorl) {
180 apply_permutation(arr->ep, arrc->eorl, 12);
181 sum_arrays_mod(arr->eorl, arrc->eorl, 12, 2);
182 }
183
184 if (f.eoud) {
185 apply_permutation(arr->ep, arrc->eoud, 12);
186 sum_arrays_mod(arr->eoud, arrc->eoud, 12, 2);
187 }
188
189 if (f.cp)
190 apply_permutation(arr->cp, arrc->cp, 8);
191
192 if (f.coud) {
193 apply_permutation(arr->cp, arrc->coud, 8);
194 sum_arrays_mod(arr->coud, arrc->coud, 8, 3);
195 }
196
197 if (f.corl) {
198 apply_permutation(arr->cp, arrc->corl, 8);
199 sum_arrays_mod(arr->corl, arrc->corl, 8, 3);
200 }
201
202 if (f.cofb) {
203 apply_permutation(arr->cp, arrc->cofb, 8);
204 sum_arrays_mod(arr->cofb, arrc->cofb, 8, 3);
205 }
206
207 if (f.cpos)
208 apply_permutation(arr->cpos, arrc->cpos, 6);
209
210 ret = arrays_to_cube(arrc, f);
211 free_cubearray(arrc, f);
212
213 return ret;
214}
215
216CubeArray *
217new_cubearray(Cube cube, PieceFilter f)
218{
219 CubeArray *arr = malloc(sizeof(CubeArray));
220
221 if (f.epose || f.eposs || f.eposm)
222 arr->ep = malloc(12 * sizeof(int));
223 if (f.eofb)
224 arr->eofb = malloc(12 * sizeof(int));
225 if (f.eorl)
226 arr->eorl = malloc(12 * sizeof(int));
227 if (f.eoud)
228 arr->eoud = malloc(12 * sizeof(int));
229 if (f.cp)
230 arr->cp = malloc(8 * sizeof(int));
231 if (f.coud)
232 arr->coud = malloc(8 * sizeof(int));
233 if (f.corl)
234 arr->corl = malloc(8 * sizeof(int));
235 if (f.cofb)
236 arr->cofb = malloc(8 * sizeof(int));
237 if (f.cpos)
238 arr->cpos = malloc(6 * sizeof(int));
239
240 cube_to_arrays(cube, arr, f);
241
242 return arr;
243}
244
245Cube
246admissible_ep(Cube cube, PieceFilter f)
247{
248 CubeArray *arr = new_cubearray(cube, f);
249 Cube ret;
250 bool used[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
251 int i, j;
252
253 for (i = 0; i < 12; i++)
254 if (arr->ep[i] != -1)
255 used[arr->ep[i]] = true;
256
257 for (i = 0, j = 0; i < 12; i++) {
258 for ( ; j < 11 && used[j]; j++);
259 if (arr->ep[i] == -1)
260 arr->ep[i] = j++;
261 }
262
263 ret = arrays_to_cube(arr, pf_ep);
264 free_cubearray(arr, f);
265
266 return ret;
267}
268
269Cube
270compose(Cube c2, Cube c1)
271{
272 return compose_filtered(c2, c1, pf_all);
273}
274
275int
276edge_slice(Edge e) {
277 if (e < 0 || e > 11)
278 return -1;
279
280 if (e == FR || e == FL || e == BL || e == BR)
281 return 0;
282 if (e == UR || e == UL || e == DR || e == DL)
283 return 1;
284
285 return 2;
286}
287
288bool
289equal(Cube c1, Cube c2)
290{
291 return c1.eofb == c2.eofb &&
292 c1.epose == c2.epose &&
293 c1.eposs == c2.eposs &&
294 c1.eposm == c2.eposm &&
295 c1.coud == c2.coud &&
296 c1.cp == c2.cp &&
297 c1.cpos == c2.cpos;
298}
299
300Cube
301inverse_cube(Cube cube)
302{
303 CubeArray *arr = new_cubearray(cube, pf_all);
304 CubeArray *inv = new_cubearray((Cube){0}, pf_all);
305 Cube ret;
306 int i;
307
308 for (i = 0; i < 12; i++) {
309 inv->ep[arr->ep[i]] = i;
310 inv->eofb[arr->ep[i]] = arr->eofb[i];
311 inv->eorl[arr->ep[i]] = arr->eorl[i];
312 inv->eoud[arr->ep[i]] = arr->eoud[i];
313 }
314
315 for (i = 0; i < 8; i++) {
316 inv->cp[arr->cp[i]] = i;
317 inv->coud[arr->cp[i]] = (3 - arr->coud[i]) % 3;
318 inv->corl[arr->cp[i]] = (3 - arr->corl[i]) % 3;
319 inv->cofb[arr->cp[i]] = (3 - arr->cofb[i]) % 3;
320 }
321
322 for (int i = 0; i < 6; i++)
323 inv->cpos[arr->cpos[i]] = i;
324
325 ret = arrays_to_cube(inv, pf_all);
326 free_cubearray(arr, pf_all);
327 free_cubearray(inv, pf_all);
328
329 return ret;
330}
331
332bool
333is_admissible(Cube cube)
334{
335 /* TODO: this should check consistency of different orientations */
336 /* check also that centers are opposite and admissible */
337
338 CubeArray *a = new_cubearray(cube, pf_all);
339 int parity;
340 bool perm;
341
342 perm = is_perm(a->ep, 12) &&
343 is_perm(a->cp, 8) &&
344 is_perm(a->cpos, 6);
345 parity = perm_sign(a->ep, 12) +
346 perm_sign(a->cp, 8) +
347 perm_sign(a->cpos, 6);
348
349 return perm && parity % 2 == 0;
350}
351
352bool
353is_solved(Cube cube)
354{
355 return equal(cube, (Cube){0});
356}
357
358bool
359is_block_solved(Cube cube, Block block)
360{
361 int i;
362
363 for (i = 0; i < 12; i++)
364 if (block.edge[i] && !is_solved_edge(cube, i))
365 return false;
366 for (i = 0; i < 8; i++)
367 if (block.corner[i] && !is_solved_corner(cube, i))
368 return false;
369 for (i = 0; i < 6; i++)
370 if (block.center[i] && !is_solved_center(cube, i))
371 return false;
372
373 return true;
374}
375
376bool
377is_solved_center(Cube cube, Center c)
378{
379 return what_center_at(cube, c) == c;
380}
381
382bool
383is_solved_corner(Cube cube, Corner c)
384{
385 return what_corner_at(cube, c) == c &&
386 what_orientation_corner(cube.coud, c);
387}
388
389bool
390is_solved_edge(Cube cube, Edge e)
391{
392 return what_edge_at(cube, e) == e &&
393 what_orientation_edge(cube.eofb, e);
394}
395
396int
397piece_orientation(Cube cube, int piece, char *orientation)
398{
399 int arr[12], n, b, x;
400
401 if (!strcmp(orientation, "eofb")) {
402 x = cube.eofb;
403 n = 12;
404 b = 2;
405 } else if (!strcmp(orientation, "eorl")) {
406 x = cube.eorl;
407 n = 12;
408 b = 2;
409 } else if (!strcmp(orientation, "eoud")) {
410 x = cube.eoud;
411 n = 12;
412 b = 2;
413 } else if (!strcmp(orientation, "coud")) {
414 x = cube.coud;
415 n = 8;
416 b = 3;
417 } else if (!strcmp(orientation, "corl")) {
418 x = cube.corl;
419 n = 8;
420 b = 3;
421 } else if (!strcmp(orientation, "cofb")) {
422 x = cube.cofb;
423 n = 8;
424 b = 3;
425 } else {
426 return -1;
427 }
428
429 int_to_sum_zero_array(x, b, n, arr);
430 if (piece < n)
431 return arr[piece];
432
433 return -1;
434}
435
436void
437print_cube(Cube cube)
438{
439 static char edge_string[12][7] = {
440 [UF] = "UF", [UL] = "UL", [UB] = "UB", [UR] = "UR",
441 [DF] = "DF", [DL] = "DL", [DB] = "DB", [DR] = "DR",
442 [FR] = "FR", [FL] = "FL", [BL] = "BL", [BR] = "BR"
443 };
444
445 static char corner_string[8][7] = {
446 [UFR] = "UFR", [UFL] = "UFL", [UBL] = "UBL", [UBR] = "UBR",
447 [DFR] = "DFR", [DFL] = "DFL", [DBL] = "DBL", [DBR] = "DBR"
448 };
449
450 static char center_string[6][7] = {
451 [U_center] = "U", [D_center] = "D",
452 [R_center] = "R", [L_center] = "L",
453 [F_center] = "F", [B_center] = "B"
454 };
455
456 for (int i = 0; i < 12; i++)
457 printf(" %s ", edge_string[what_edge_at(cube, i)]);
458 printf("\n");
459
460 for (int i = 0; i < 12; i++)
461 printf(" %d ", what_orientation_edge(cube.eofb, i));
462 printf("\n");
463
464 for (int i = 0; i < 8; i++)
465 printf("%s ", corner_string[what_corner_at(cube, i)]);
466 printf("\n");
467
468 for (int i = 0; i < 8; i++)
469 printf(" %d ", what_orientation_corner(cube.coud, i));
470 printf("\n");
471
472 for (int i = 0; i < 6; i++)
473 printf(" %s ", center_string[what_center_at(cube, i)]);
474 printf("\n");
475}
476
477Cube
478random_cube()
479{
480 CubeArray *arr = new_cubearray((Cube){0}, pf_4val);
481 Cube ret;
482 int ep, cp, eo, co;
483
484 ep = rand() % FACTORIAL12;
485 cp = rand() % FACTORIAL8;
486 eo = rand() % POW2TO11;
487 co = rand() % POW3TO7;
488
489 index_to_perm(ep, 12, arr->ep);
490 index_to_perm(cp, 8, arr->cp);
491 int_to_sum_zero_array(eo, 2, 12, arr->eofb);
492 int_to_sum_zero_array(co, 3, 8, arr->coud);
493
494 if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8))
495 swap(&(arr->ep[0]), &(arr->ep[1]));
496
497 ret = arrays_to_cube(arr, pf_4val);
498 free_cubearray(arr, pf_4val);
499
500 return ret;
501}
502
503Center
504what_center_at(Cube cube, Center c)
505{
506 static bool initialized = false;
507 static Center aux[FACTORIAL6][6];
508 static int i;
509 static unsigned int ui;
510 static CubeArray *arr;
511
512 if (!initialized) {
513 for (ui = 0; ui < FACTORIAL6; ui++) {
514 arr = new_cubearray((Cube){.cpos = ui}, pf_cpos);
515 for (i = 0; i < 6; i++)
516 aux[ui][i] = arr->cpos[i];
517 free_cubearray(arr, pf_cpos);
518 }
519
520 initialized = true;
521 }
522
523 return aux[cube.cpos][c];
524}
525
526Corner
527what_corner_at(Cube cube, Corner c)
528{
529 static bool initialized = false;
530 static Corner aux[FACTORIAL8][8];
531 static int i;
532 static unsigned int ui;
533 static CubeArray *arr;
534
535 if (!initialized) {
536 for (ui = 0; ui < FACTORIAL8; ui++) {
537 arr = new_cubearray((Cube){.cp = ui}, pf_cp);
538 for (i = 0; i < 8; i++)
539 aux[ui][i] = arr->cp[i];
540 free_cubearray(arr, pf_cp);
541 }
542
543 initialized = true;
544 }
545
546 return aux[cube.cp][c];
547}
548
549Edge
550what_edge_at(Cube cube, Edge e)
551{
552 Edge ret;
553 CubeArray *arr = new_cubearray(cube, pf_ep);
554
555 ret = arr->ep[e];
556
557 free_cubearray(arr, pf_ep);
558 return ret;
559}
560
561int
562what_orientation_corner(int co, Corner c)
563{
564 static bool initialized = false;
565 static int auxlast[POW3TO7];
566 static int auxarr[8];
567 static unsigned int ui;
568
569 if (!initialized) {
570 for (ui = 0; ui < POW3TO7; ui++) {
571 int_to_sum_zero_array(ui, 3, 8, auxarr);
572 auxlast[ui] = auxarr[7];
573 }
574
575 initialized = true;
576 }
577
578 if (c < 7)
579 return (co / powint(3, c)) % 3;
580 else
581 return auxlast[co];
582}
583
584int
585what_orientation_edge(int eo, Edge e)
586{
587 static bool initialized = false;
588 static int auxlast[POW2TO11];
589 static int auxarr[12];
590 static unsigned int ui;
591
592 if (!initialized) {
593 for (ui = 0; ui < POW2TO11; ui++) {
594 int_to_sum_zero_array(ui, 2, 12, auxarr);
595 auxlast[ui] = auxarr[11];
596 }
597
598 initialized = true;
599 }
600
601 if (e < 11)
602 return (eo & (1 << e)) ? 1 : 0;
603 else
604 return auxlast[eo];
605}
606
607Center
608where_is_center(Cube cube, Center c)
609{
610 static bool initialized = false;
611 static Center aux[FACTORIAL6][6];
612 static int i;
613 static unsigned int ui;
614 static CubeArray *arr;
615
616 if (!initialized) {
617 for (ui = 0; ui < FACTORIAL6; ui++) {
618 arr = new_cubearray((Cube){.cpos = ui}, pf_cpos);
619 for (i = 0; i < 6; i++)
620 aux[ui][arr->cpos[i]] = i;
621 free_cubearray(arr, pf_cpos);
622 }
623
624 initialized = true;
625 }
626
627 return aux[cube.cpos][c];
628}
629
630Corner
631where_is_corner(Cube cube, Corner c)
632{
633 static bool initialized = false;
634 static Corner aux[FACTORIAL8][8];
635 static int i;
636 static unsigned int ui;
637 static CubeArray *arr;
638
639 if (!initialized) {
640 for (ui = 0; ui < FACTORIAL8; ui++) {
641 arr = new_cubearray((Cube){.cp = ui}, pf_cp);
642 for (i = 0; i < 8; i++)
643 aux[ui][arr->cp[i]] = i;
644 free_cubearray(arr, pf_cp);
645 }
646
647 initialized = true;
648 }
649 return aux[cube.cp][c];
650}
651
652Edge
653where_is_edge(Cube cube, Edge e)
654{
655 /* TODO: when I wrote this code I forgot to add the final
656 part, and now I can't remember how it was supposed to
657 work (i.e. how to recover the location of the edge
658 from these tables. I think it is either very easy or
659 wrong, in any case it is not a priority now.
660 Future Seba can deal with it.
661
662 static bool initialized = false;
663 static Edge aux[3][FACTORIAL12/FACTORIAL8][12];
664 static int i;
665 static unsigned int ui;
666 static CubeArray *arr;
667
668 if (!initialized) {
669 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
670 arr = new_cubearray((Cube){.epose = ui}, pf_e);
671 for (i = 0; i < 12; i++)
672 if (edge_slice(arr->ep[i]) == 0)
673 aux[0][ui][arr->ep[i]] = i;
674 free_cubearray(arr, pf_e);
675
676 arr = new_cubearray((Cube){.eposs = ui}, pf_s);
677 for (i = 0; i < 12; i++)
678 if (edge_slice(arr->ep[i]) == 1)
679 aux[1][ui][arr->ep[i]] = i;
680 free_cubearray(arr, pf_s);
681
682 arr = new_cubearray((Cube){.eposm = ui}, pf_m);
683 for (i = 0; i < 12; i++)
684 if (edge_slice(arr->ep[i]) == 2)
685 aux[2][ui][arr->ep[i]] = i;
686 free_cubearray(arr, pf_m);
687 }
688
689 initialized = true;
690 }
691 */
692
693 int i;
694 CubeArray *arr = new_cubearray(cube, pf_ep);
695
696 for (i = 0; i < 12; i++)
697 if ((Edge)arr->ep[i] == e)
698 return i;
699
700 return -1;
701}
diff --git a/src/cube.h b/src/cube.h
new file mode 100644
index 0000000..d1c5bfc
--- /dev/null
+++ b/src/cube.h
@@ -0,0 +1,40 @@
1#ifndef CUBE_H
2#define CUBE_H
3
4#include <stdio.h>
5#include <time.h>
6
7#include "pf.h"
8#include "utils.h"
9
10Cube admissible_ep(Cube cube, PieceFilter f);
11Cube arrays_to_cube(CubeArray *arr, PieceFilter f);
12Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */
13Cube compose_filtered(Cube c2, Cube c1, PieceFilter f);
14void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f);
15int edge_slice(Edge e); /* E=0, S=1, M=2 */
16bool equal(Cube c1, Cube c2);
17Cube inverse_cube(Cube cube);
18bool is_admissible(Cube cube);
19bool is_solved(Cube cube);
20bool is_block_solved(Cube cube, Block);
21bool is_solved_center(Cube cube, Center c);
22bool is_solved_corner(Cube cube, Corner c);
23bool is_solved_edge(Cube cube, Edge e);
24void epos_to_partial_ep(int epos, int *ep, int *ss);
25void free_cubearray(CubeArray *arr, PieceFilter f);
26Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf);
27CubeArray * new_cubearray(Cube cube, PieceFilter f);
28void print_cube(Cube cube);
29Cube random_cube();
30Center what_center_at(Cube cube, Center c);
31Corner what_corner_at(Cube cube, Corner c);
32Edge what_edge_at(Cube cube, Edge e);
33int what_orientation_corner(int co, Corner c);
34int what_orientation_edge(int eo, Edge e);
35Center where_is_center(Cube cube, Center c);
36Corner where_is_corner(Cube cube, Corner c);
37Edge where_is_edge(Cube cube, Edge e);
38
39#endif
40
diff --git a/src/cubetypes.h b/src/cubetypes.h
new file mode 100644
index 0000000..6602a68
--- /dev/null
+++ b/src/cubetypes.h
@@ -0,0 +1,286 @@
1#ifndef CUBETYPES_H
2#define CUBETYPES_H
3
4#include <stdbool.h>
5#include <stdint.h>
6
7#define NMOVES 55 /* Actually 55, but one is NULLMOVE */
8#define NTRANS 48
9#define NROTATIONS 24
10
11/* Enums *********************************************************************/
12
13typedef enum
14center
15{
16 U_center, D_center,
17 R_center, L_center,
18 F_center, B_center
19} Center;
20
21typedef enum
22corner
23{
24 UFR, UFL, UBL, UBR,
25 DFR, DFL, DBL, DBR
26} Corner;
27
28typedef enum
29edge
30{
31 UF, UL, UB, UR,
32 DF, DL, DB, DR,
33 FR, FL, BL, BR
34} Edge;
35
36typedef enum
37move
38{
39 NULLMOVE,
40 U, U2, U3, D, D2, D3,
41 R, R2, R3, L, L2, L3,
42 F, F2, F3, B, B2, B3,
43 Uw, Uw2, Uw3, Dw, Dw2, Dw3,
44 Rw, Rw2, Rw3, Lw, Lw2, Lw3,
45 Fw, Fw2, Fw3, Bw, Bw2, Bw3,
46 M, M2, M3,
47 S, S2, S3,
48 E, E2, E3,
49 x, x2, x3,
50 y, y2, y3,
51 z, z2, z3,
52} Move;
53
54typedef enum
55trans
56{
57 uf, ur, ub, ul,
58 df, dr, db, dl,
59 rf, rd, rb, ru,
60 lf, ld, lb, lu,
61 fu, fr, fd, fl,
62 bu, br, bd, bl,
63 uf_mirror, ur_mirror, ub_mirror, ul_mirror,
64 df_mirror, dr_mirror, db_mirror, dl_mirror,
65 rf_mirror, rd_mirror, rb_mirror, ru_mirror,
66 lf_mirror, ld_mirror, lb_mirror, lu_mirror,
67 fu_mirror, fr_mirror, fd_mirror, fl_mirror,
68 bu_mirror, br_mirror, bd_mirror, bl_mirror,
69} Trans;
70
71
72/* Typedefs ******************************************************************/
73
74typedef struct alg Alg;
75typedef struct alglist AlgList;
76typedef struct alglistnode AlgListNode;
77typedef struct block Block;
78typedef struct command Command;
79typedef struct commandargs CommandArgs;
80typedef struct coordinate Coordinate;
81typedef struct cube Cube;
82typedef struct cubearray CubeArray;
83typedef struct cubetarget CubeTarget;
84typedef struct dfsdata DfsData;
85typedef struct piecefilter PieceFilter;
86typedef struct prunedata PruneData;
87typedef struct solveoptions SolveOptions;
88typedef struct step Step;
89typedef struct symdata SymData;
90
91typedef Cube (*AntiIndexer) (uint64_t);
92typedef bool (*Checker) (Cube);
93typedef int (*Estimator) (CubeTarget);
94typedef bool (*Validator) (Alg *);
95typedef void (*Exec) (CommandArgs *);
96typedef uint64_t (*Indexer) (Cube);
97typedef bool (*Moveset) (Move);
98typedef CommandArgs * (*ArgParser) (int, char **);
99typedef Trans (*TransDetector) (Cube);
100
101
102/* Structs *******************************************************************/
103
104struct
105alg
106{
107 Move * move;
108 bool * inv;
109 int len;
110 int allocated;
111};
112
113struct
114alglist
115{
116 AlgListNode * first;
117 AlgListNode * last;
118 int len;
119};
120
121struct
122alglistnode
123{
124 Alg * alg;
125 AlgListNode * next;
126};
127
128struct
129block
130{
131 bool edge[12];
132 bool corner[8];
133 bool center[6];
134};
135
136struct
137command
138{
139 char * name;
140 char * usage;
141 char * description;
142 ArgParser parse_args;
143 Exec exec;
144};
145
146struct
147commandargs
148{
149 bool success;
150 Alg * scramble;
151 SolveOptions * opts;
152 Step * step;
153 Command * command; /* For help */
154};
155
156struct
157coordinate
158{
159 Indexer index;
160 AntiIndexer cube;
161 uint64_t max;
162 int ntrans;
163 Trans * trans;
164};
165
166struct
167cube
168{
169 int epose;
170 int eposs;
171 int eposm;
172 int eofb;
173 int eorl;
174 int eoud;
175 int cp;
176 int coud;
177 int cofb;
178 int corl;
179 int cpos;
180};
181
182struct
183cubearray
184{
185 int * ep;
186 int * eofb;
187 int * eorl;
188 int * eoud;
189 int * cp;
190 int * coud;
191 int * corl;
192 int * cofb;
193 int * cpos;
194};
195
196struct
197cubetarget
198{
199 Cube cube;
200 int target;
201};
202
203struct
204dfsdata
205{
206 int d;
207 int m;
208 int lb;
209 bool niss;
210 Move last1;
211 Move last2;
212 AlgList * sols;
213 Alg * current_alg;
214 Move sorted_moves[NMOVES];
215 int move_position[NMOVES];
216};
217
218struct
219piecefilter
220{
221 bool epose;
222 bool eposs;
223 bool eposm;
224 bool eofb;
225 bool eorl;
226 bool eoud;
227 bool cp;
228 bool coud;
229 bool cofb;
230 bool corl;
231 bool cpos;
232};
233
234struct
235prunedata
236{
237 char * filename;
238 uint8_t * ptable;
239 bool generated;
240 uint64_t n;
241 Coordinate * coord;
242 Moveset moveset;
243};
244
245struct
246solveoptions
247{
248 int min_moves;
249 int max_moves;
250 int max_solutions;
251 bool optimal_only;
252 bool can_niss;
253 bool verbose;
254 bool all;
255 bool print_number;
256};
257
258struct
259step
260{
261 char * shortname;
262 char * name;
263 Estimator estimate;
264 Checker ready;
265 char * ready_msg;
266 Validator is_valid;
267 Moveset moveset;
268 Trans pre_trans;
269 TransDetector detect;
270};
271
272struct
273symdata
274{
275 char * filename;
276 bool generated;
277 Coordinate * coord;
278 Coordinate * sym_coord;
279 int ntrans;
280 Trans * trans;
281 uint64_t * class;
282 Cube * rep;
283 Trans * transtorep;
284};
285
286#endif
diff --git a/src/env.c b/src/env.c
new file mode 100644
index 0000000..d13642f
--- /dev/null
+++ b/src/env.c
@@ -0,0 +1,45 @@
1#include "env.h"
2
3bool initialized_env = false;
4char *tabledir;
5
6void
7init_env()
8{
9 char *nissydata = getenv("NISSYDATA");
10 char *localdata = getenv("XDG_DATA_HOME");
11 char *home = getenv("HOME");
12 bool read, write;
13
14 if (initialized_env)
15 return;
16
17 if (nissydata != NULL) {
18 tabledir = malloc(strlen(nissydata) * sizeof(char) + 20);
19 strcpy(tabledir, nissydata);
20 } else if (localdata != NULL) {
21 tabledir = malloc(strlen(localdata) * sizeof(char) + 20);
22 strcpy(tabledir, localdata);
23 strcat(tabledir, "/nissy");
24 } else if (home != NULL) {
25 tabledir = malloc(strlen(home) * sizeof(char) + 20);
26 strcpy(tabledir, home);
27 strcat(tabledir, "/.nissy");
28 }
29
30 mkdir(tabledir, 0777);
31 strcat(tabledir, "/tables");
32 mkdir(tabledir, 0777);
33
34 read = !access(tabledir, R_OK);
35 write = !access(tabledir, W_OK);
36
37 if (!read) {
38 fprintf(stderr, "Table files cannot be read.\n");
39 } else if (!write) {
40 fprintf(stderr, "Data directory not writable: ");
41 fprintf(stderr, "tables can be loaded, but not saved.\n");
42 }
43
44 initialized_env = true;
45}
diff --git a/src/env.h b/src/env.h
new file mode 100644
index 0000000..871a9c1
--- /dev/null
+++ b/src/env.h
@@ -0,0 +1,15 @@
1#ifndef ENV_H
2#define ENV_H
3
4#include <stdbool.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8#include <unistd.h>
9#include <sys/stat.h>
10
11extern char *tabledir;
12
13void init_env();
14
15#endif
diff --git a/src/helppages.h b/src/helppages.h
deleted file mode 100644
index 178de37..0000000
--- a/src/helppages.h
+++ /dev/null
@@ -1,689 +0,0 @@
1/* To generate this help page, use the script makedoc.sh */
2
3int Npages = 22;
4
5char *helppages[][10] = {
6
7{ "add",
8"\
9\n\
10HELP PAGE FOR COMMAND add\n\
11\n\
12SYNTAX\n\
13add [MOVES|$ID1|@ID1] $ID2\n\
14\n\
15DESCRIPTION\n\
16Appends either MOVES, the scramble memorized under $ID1 or the output sequence\n\
17memorized under @ID1 at the end of the scramble memorized under $ID2. If none\n\
18of MOVES, $ID1 or @ID1 is specified, the user will be asked to type the moves.\n\
19Menmonic: \"add x to y\" or just \"add to y\".\n\
20\n\
21EXAMPLES\n\
22add $1\n\
23 The user is required to type the moves that will be appended to $1.\n\
24add F R B $1\n\
25 Appends the moves F R B to scramble $1. Now scramble $1 ends with F R B.\n\
26\n\
27"
28},
29
30{ "change",
31"\
32\n\
33HELP PAGE FOR COMMAND change\n\
34\n\
35SYNTAX\n\
36change $ID1 [MOVES|$ID2|@ID2]\n\
37\n\
38DESCRIPTION\n\
39Changes the scramble $ID1 to either MOVES, the scramble $ID2, the output @ID2\n\
40or, if none is specified, the moves entered by the user. The scramble that was\n\
41memorized under $ID1 is then lost.\n\
42Mnemonic: \"change x to y\", or just \"change x\".\n\
43\n\
44EXAMPLES\n\
45change $1\n\
46 The user is required to type the moves that will replace $1.\n\
47change $2 $3\n\
48 Saves the scramble that was saved under $3 in $2. Now $2 and $3 are the same\n\
49 scrambles, and the old $2 is lost.\n\
50change $1 U R\n\
51 Saves U R as scramble $1.\n\
52\n\
53"
54},
55
56{ "clear",
57"\
58\n\
59HELP PAGE FOR COMMAND clear\n\
60\n\
61SYNTAX\n\
62clear\n\
63\n\
64DESCRIPTION\n\
65Resets all saved scrambles and output sequences.\n\
66\n\
67"
68},
69
70{ "co",
71"\
72\n\
73HELP PAGE FOR COMMAND co\n\
74\n\
75SYNTAX\n\
76co [OPTIONS] [MOVES|$ID|@ID]\n\
77\n\
78DESCRIPTION\n\
79Solves CO for a given scramble. A scramble can be given as last argument of the\n\
80command, or an ID of a saved scramble can be provided. If none of the two is\n\
81given, a prompt will ask the user to input a new scramble.\n\
82\n\
83OPTIONS\n\
84axis={fb,rl,ud} Specify the axis for the CO. One to three axes can be given,\n\
85 comma separated, no spaces.\n\
86 Default: CO on any of the three axis (omitting the option is\n\
87 the same as specifying axis=fb,rl,ud).\n\
88b=N Specify a bound for the number of moves. N must be a number.\n\
89 Default value: 20.\n\
90h Show hidden COs.\n\
91 Default, if an CO ending in e.g. F is shown, the equivalent\n\
92 one ending in F' is hidden.\n\
93i Ignore centers. By default the CO is aligned with centers.\n\
94niss Use NISS.\n\
95 Default: does not use NISS.\n\
96n=N Specify a maximum number of COs to be output. N must be a\n\
97 number.\n\
98 Default value: 1.\n\
99\n\
100EXAMPLES\n\
101co axis=fb $1\n\
102 Finds one optimal CO on fb for the first saved scramble.\n\
103\n\
104co n=5 b=4 U R F \n\
105 Finds up to 5 COs of length at most 4 for scramble U R F.\n\
106\n\
107co n=100 b=5 niss axis=fb,ud h R' U' F L R'U'F\n\
108 Finds up to 100 COs of lenth at most 4, possibly using NISS, including\n\
109 \"hidden\" COs, excluding the rl axis.\n\
110\n\
111"
112},
113
114{ "dr",
115"\
116\n\
117HELP PAGE FOR COMMAND dr\n\
118\n\
119SYNTAX\n\
120dr [OPTIONS] [MOVES|$ID|@ID]\n\
121\n\
122DESCRIPTION\n\
123Solves DR for a given scramble. A scramble can be given as last argument of the\n\
124command, or an ID of a saved scramble can be provided. If none of the two is\n\
125given, a prompt will ask the user to input a new scramble.\n\
126If the option \"from\" is given (see below), it solves DR from an EO (if edges\n\
127are oriented) without breaking that EO.\n\
128The first time this command is called without the option from (and, to some\n\
129extent, also the first time it is called with the option from), nissy loads\n\
130some pruning tables that were not loaded on startup, causing a small but\n\
131noticeable delay.\n\
132\n\
133OPTIONS\n\
134axis={fb,rl,ud} Specify the axis for the DR. One to three axes can be given,\n\
135 comma separated, no spaces.\n\
136 Default: DR on any of the three axis (omitting the option is\n\
137 the same as specifying axis=fb,rl,ud).\n\
138b=N Specify a bound for the number of moves. N must be a number.\n\
139 Default value: 20.\n\
140h Show hidden DRs.\n\
141 Default, if an DR ending in e.g. R is shown, the equivalent\n\
142 one ending in R' is hidden.\n\
143from {fb|rl|ud} Solve DR from the specified EO, which must be solved,\n\
144 without breaking the EO.\n\
145niss Use NISS. It works only if solving DR from EO.\n\
146 Default: does not use NISS.\n\
147n=N Specify a maximum number of EOs to be output. N must be a\n\
148 number.\n\
149 Default value: 1.\n\
150\n\
151EXAMPLES\n\
152dr from rl axis=ud $1\n\
153 Finds optimal DR on ud, starting from EO on rl, for the first saved scramble.\n\
154\n\
155dr niss from fb n=10 m=6 F2 R L B' F D U' R2 L' F D B\n\
156 Finds up to 10 DRs of length at most 6 from EO on fb, possibly using NISS.\n\
157\n\
158dr n=100 axis=ud h\n\
159 Finds 100 DRs on ud, including \"hidden\" DRs.\n\
160\n\
161"
162},
163
164{ "drcorners",
165"\
166\n\
167HELP PAGE FOR COMMAND drcorners\n\
168\n\
169SYNTAX\n\
170drcorners [OPTIONS] [MOVES|$ID|@ID]\n\
171\n\
172DESCRIPTION\n\
173Similar to drfinish, but only solves corners. CO must be solved. The scramble\n\
174can be given as the last argument of the command, or it may be given as an $ID\n\
175or @ID, or it can be typed out on the following line.\n\
176\n\
177OPTIONS\n\
178from {ud|fb|rl} Allows to specify on which axis the CO is solved. It is\n\
179 usually not necessary, since nissy will find a CO on any\n\
180 axis.\n\
181i Ignores E-layer centers. By default cornersare solved\n\
182 relatively to centers; this options allows for solutions\n\
183 which solve corners relatively to each other and to the\n\
184 U and D sides, but not to the E layer (or any equivalent\n\
185 if the CO is not on U/D).\n\
186b=N Specify a bound for the number of moves. N must be a number.\n\
187 Default value: 20.\n\
188n=N Specify a maximum number of solutions to be output. N must\n\
189 be a number.\n\
190 Default value: 1.\n\
191\n\
192EXAMPLES\n\
193drcorners n=3 R' D R2 D' R' U2 R D R' U2 R' D' R\n\
194 Produces the following output:\n\
195Found 3 results.\n\
196@1: U' F2 U R2 U2 F2 U F2 U R2 (10)\n\
197@2: U' F2 U R2 U2 B2 U R2 D R2 (10)\n\
198@3: U' F2 U R2 U2 B2 U L2 U L2 (10)\n\
199\n\
200"
201},
202
203{ "drfinish",
204"\
205\n\
206HELP PAGE FOR COMMAND drfinish\n\
207\n\
208SYNTAX\n\
209drfinish [OPTIONS] [MOVES|$ID|@ID]\n\
210\n\
211DESCRIPTION\n\
212Solves the given scramble using the DR moveset. DR must be solved. The scramble\n\
213can be given as the last argument of the command, or it may be given as an $ID\n\
214or @ID, or it can be typed out on the following line.\n\
215\n\
216OPTIONS\n\
217from {ud|fb|rl} Allows to specify on which axis the DR is solved. It is\n\
218 usually not necessary, since nissy will find a DR on any\n\
219 axis, but it can be useful if one want to e.g. solve an HTR\n\
220 state allowing quarter-turns from a specific DR.\n\
221b=N Specify a bound for the number of moves. N must be a number.\n\
222 Default value: 20.\n\
223n=N Specify a maximum number of solutions to be output. N must\n\
224 be a number.\n\
225 Default value: 1.\n\
226\n\
227EXAMPLES\n\
228dr from ud R L' U2 R' L F2\n\
229 Solves the given scramble using the moveset <U,D,R2,L2,F2,B2>. In this case:\n\
230@1: U2 R2 F2 R2 U2 R2 F2 R2 (8)\n\
231drfinish b=7 n=10 $1\n\
232 Finds (at most) 10 solutions of length at most 7 for the scramble $1.\n\
233\n\
234"
235},
236
237{ "eo",
238"\
239\n\
240HELP PAGE FOR COMMAND eo\n\
241\n\
242SYNTAX\n\
243eo [OPTIONS] [MOVES|$ID|@ID]\n\
244\n\
245DESCRIPTION\n\
246Solves EO for a given scramble. A scramble can be given as last argument of the\n\
247command, or an ID of a saved scramble can be provided. If none of the two is\n\
248given, a prompt will ask the user to input a new scramble.\n\
249\n\
250OPTIONS\n\
251axis={fb,rl,ud} Specify the axis for the EO. One to three axes can be given,\n\
252 comma separated, no spaces.\n\
253 Default: EO on any of the three axis (omitting the option is\n\
254 the same as specifying axis=fb,rl,ud).\n\
255b=N Specify a bound for the number of moves. N must be a number.\n\
256 Default value: 20.\n\
257h Show hidden EOs.\n\
258 Default, if an EO ending in e.g. F is shown, the equivalent\n\
259 one ending in F' is hidden.\n\
260niss Use NISS.\n\
261 Default: does not use NISS.\n\
262n=N Specify a maximum number of EOs to be output. N must be a\n\
263 number.\n\
264 Default value: 1.\n\
265\n\
266EXAMPLES\n\
267eo axis=fb $1\n\
268 Finds one optimal EO on fb for the first saved scramble.\n\
269\n\
270eo n=5 b=4 U R F \n\
271 Finds up to 5 EOs of length at most 4 for scramble U R F.\n\
272\n\
273eo n=100 b=5 niss axis=fb,ud h R' U' F L R'U'F\n\
274 Finds up to 100 EOs of lenth at most 4, possibly using NISS, including\n\
275 \"hidden\" EOs, excluding the rl axis.\n\
276\n\
277"
278},
279
280{ "exit",
281"\
282\n\
283HELP PAGE FOR COMMAND exit\n\
284\n\
285SYNTAX\n\
286exit\n\
287\n\
288DESCRIPTION\n\
289Exits nissy.\n\
290\n\
291"
292},
293
294{ "help",
295"\
296\n\
297HELP PAGE FOR COMMAND help\n\
298\n\
299SYNTAX\n\
300help [nissy|COMMAND]\n\
301\n\
302DESCRIPTION\n\
303'help nissy' prints a general user manual. 'help COMMAND' prints a detailed\n\
304help page for the command COMMAND, if it exists. 'help' prints a list of all\n\
305available commands a short description for each.\n\
306\n\
307EXAMPLES\n\
308help help\n\
309 Prints this help page.\n\
310\n\
311"
312},
313
314{ "htr",
315"\
316\n\
317HELP PAGE FOR COMMAND htr\n\
318\n\
319SYNTAX\n\
320htr [OPTIONS] [MOVES|$ID|@ID]\n\
321\n\
322DESCRIPTION\n\
323Finds HTR for a given scramble. DR must be solved. A scramble can be given as\n\
324last argument of the command, or an ID of a saved scramble can be provided. If\n\
325none of the two is given, a prompt will ask the user to input a new scramble.\n\
326\n\
327OPTIONS\n\
328from {ud|fb|rl} Allows to specify on which axis the DR is. This is usually\n\
329 not needed, since nissy will automatically find it out.\n\
330b=N Specify a bound for the number of moves. N must be a number.\n\
331 Default value: 20.\n\
332h Show hidden HTRs.\n\
333 Default, if an HTR ending in e.g. R is shown, the equivalent\n\
334 one ending in R' is hidden.\n\
335niss Use NISS.\n\
336 Default: does not use NISS.\n\
337n=N Specify a maximum number of HTRs to be output. N must be a\n\
338 number.\n\
339 Default value: 1.\n\
340\n\
341EXAMPLES\n\
342eo n=10 b=7 niss $1\n\
343 Finds up to 100 HTRs of lenth at most 7, possibly using NISS, including\n\
344 \"hidden\" HTRs, for scramble $1. DR must be solved.\n\
345\n\
346"
347},
348
349{ "htrfinish",
350"\
351\n\
352HELP PAGE FOR COMMAND htrfinish\n\
353\n\
354SYNTAX\n\
355htrfinish [OPTIONS] [MOVES|$ID|@ID]\n\
356\n\
357DESCRIPTION\n\
358Similar to drfinish, but uses the moveset <U2,D2,R2,L2,F2,B2>. HTR must be\n\
359solved. The scramble can be given as the last argument of the command, or it\n\
360may be given as an $ID or @ID, or it can be typed out on the following line.\n\
361\n\
362OPTIONS\n\
363b=N Specify a bound for the number of moves. N must be a number.\n\
364 Default value: 20.\n\
365n=N Specify a maximum number ofsolutions to be output. N must be\n\
366 a number.\n\
367 Default value: 1.\n\
368\n\
369EXAMPLES\n\
370htrfinish R L' U2 R' L F2\n\
371 Produces the following solution:\n\
372@1: U2 R2 F2 R2 U2 R2 F2 R2 (8)\n\
373\n\
374"
375},
376
377{ "invert",
378"\
379\n\
380HELP PAGE FOR COMMAND invert\n\
381\n\
382SYNTAX\n\
383invert [MOVES|$ID|@ID]\n\
384\n\
385DESCRIPTION\n\
386Inverts a sequence of moves, which can be given also as $ID or @ID. The given\n\
387sequence must not use NISS (if it does, use the command unniss first).\n\
388\n\
389EXAMPLES\n\
390invert F R D'\n\
391 Prints D R' F'\n\
392\n\
393"
394},
395
396{ "nissy",
397"\
398\n\
399*******************************************************************************\n\
400********************* NISSY: a cube solver and FMC helper *********************\n\
401*******************************************************************************\n\
402\n\
403If you just want to solve the cube, type 'solve' followed by the scramble. This\n\
404will not always give you an optimal solution, unless it is 10 moves or less or\n\
405you use the \"o\" option. Finding the optimal solution might take very long if it\n\
406is 16 moves or more, especially for the first time.\n\
407\n\
408Now the fun stuff. With nissy you can save and manipulate move sequences, for\n\
409example:\n\
410\n\
411nissy-# save R' U' F\n\
412$1: R' U' F\n\
413nissy-# add L2D' $1\n\
414$1: R' U' F L2 D'\n\
415\n\
416You can then ask nissy to solve certain substepson a saved scramble:\n\
417\n\
418nissy-# eo axis=rl $1\n\
419@1: U D F' R (4)\n\
420\n\
421And of course it uses also NISS, if you ask:\n\
422\n\
423nissy-# eo niss axis=rl $1\n\
424@1: (R) (1)\n\
425\n\
426Notice that the sequences you save are marked with a $, while the \"output\"\n\
427sequences are marked with @. The difference between these two type of sequences\n\
428is that those marked with @ are temporary and get lost once you get new output.\n\
429Most commands accept as input either a move sequence typed out, a $-sequence or\n\
430a @-sequence. For example, you can however save a @-sequence and make it\n\
431persistent:\n\
432\n\
433nissy-# save @1\n\
434$2: (R)\n\
435\n\
436Nissy also understands NISS. Let's see a more complicated example where you\n\
437save a scramble, ask for some EOs (using NISS) and then a DR on inverse:\n\
438\n\
439nissy-# save R' U' F R U R2 F2 R2 D R2 U L2 U R2 D2 B' D U' R D R' D U2 F2 R' U' F\n\
440$3: R' U' F R U R2 F2 R2 D R2 U L2 U R2 D2 B' D U' R D R' D U2 F2 R' U' F \n\
441nissy-# eo n=10 niss axis=fb,rl $3\n\
442Found 10 results.\n\
443@1: (U' L B D F) (5)\n\
444@2: (U' L B' D F) (5)\n\
445@3: (L B U D F) (5)\n\
446@4: (L B' U D F) (5)\n\
447@5: R U B U L (5)\n\
448@6: R U' L (B L) (5)\n\
449@7: R U' B U L (5)\n\
450@8: R L (L B L) (5)\n\
451@9: R (U2 D' F R) (5)\n\
452@10: R (U2 F D' R) (5)\n\
453nissy-# add @6 $3\n\
454$3: R' U' F R U R2 F2 R2 D R2 U L2 U R2 D2 B' D U' R D R' D U2 F2 R' U' F R U' L (B L) \n\
455nissy-# unniss $3\n\
456@1: L' B' R' U' F R U R2 F2 R2 D R2 U L2 U R2 D2 B' D U' R D R' D U2 F2 R' U' F R U' L \n\
457nissy-# invert @1\n\
458@1: L' U R' F' U R F2 U2 D' R D' R' U D' B D2 R2 U' L2 U' R2 D' R2 F2 R2 U' R' F' U R B L \n\
459nissy-# save @1\n\
460$5: L' U R' F' U R F2 U2 D' R D' R' U D' B D2 R2 U' L2 U' R2 D' R2 F2 R2 U' R' F' U R B L \n\
461nissy-# dr from rl $5\n\
462@1: F2 U D2 F' B D B (7)\n\
463nissy-# \n\
464\n\
465If you ask nissy to solve a substep (or the whole cube) using a sequence with\n\
466NISS as scramble, it will first un-NISS it (but without saving the unNISSed\n\
467scramble anywhere):\n\
468\n\
469print $3\n\
470$3: R' U' F R U R2 F2 R2 D R2 U L2 U R2 D2 B' D U' R D R' D U2 F2 R' U' F R U' L (B L) \n\
471nissy-# solve $3\n\
472@1: F U' R2 F2 U2 F U2 R2 L2 D R2 U B2 D' L2 D B2 D2 (18)\n\
473\n\
474Nissy knows how to solve certain common sub-steps for DR (or Thistlethwaite /\n\
475Kociemba algorithms). For now it does know more common speedsolving methods.\n\
476\n\
477For a full list of commands type \"help\". For a more detailed help on a specific\n\
478command, type \"help (command)\". The help pages can also be found in the docs\n\
479folder.\n\
480\n\
481If you want to report a bug (I'm sure there are many!) or give a suggestion,\n\
482you can send an email to sebastiano.tronto@gmail.com.\n\
483\n\
484Have fun!\n\
485\n\
486"
487},
488
489{ "pic",
490"\
491\n\
492HELP PAGE FOR COMMAND pic\n\
493\n\
494SYNTAX\n\
495pic [MOVES|$ID|@ID]\n\
496\n\
497DESCRIPTION\n\
498Prints the cube state after applying the given scramble.\n\
499\n\
500EXAMPLES\n\
501pic R' U' F R U R2 F2 R2 D R2 U L2 U R2 D2 B' D U' R D R' D U2 F2 R' U' F \n\
502 Gives the following output:\n\
503 UF UL UB UR DF DL DB DR FR FL BL BR \n\
504EP: FR UL FL UR UF DB DR BL UB BR DL DF \n\
505EO(F/B): x x x x x x x x \n\
506\n\
507 UFR UFL UBL UBR DFR DFL DBL DBR \n\
508CP: UBR UFR DFL DBL UFL UBL DBR DFR \n\
509CO(U/D): ccw cw ccw cw\n\
510\n\
511"
512},
513
514{ "print",
515"\
516\n\
517HELP PAGE FOR COMMAND print\n\
518\n\
519SYNTAX\n\
520print [$ID|@ID]\n\
521\n\
522DESCRIPTION\n\
523Prints memorized sequences. If no argument is given, it prints all memorized\n\
524scrambles ($ only). If $ID or @ID is specified, it only prints the relative\n\
525memorized sequence.\n\
526\n\
527EXAMPLES\n\
528print\n\
529 Prints a list of all memorized scrambles (only $).\n\
530print $2\n\
531 Prints the second memorized scramble.\n\
532print @13\n\
533 Prints the 13th sequence that was part of the output of the last command.\n\
534\n\
535"
536},
537
538{ "quit",
539"\
540\n\
541HELP PAGE FOR COMMAND quit\n\
542\n\
543SYNTAX\n\
544quit\n\
545\n\
546DESCRIPTION\n\
547Exits nissy.\n\
548\n\
549"
550},
551
552{ "replace",
553"\
554\n\
555HELP PAGE FOR COMMAND replace\n\
556\n\
557SYNTAX\n\
558eo [OPTIONS] [MOVES|$ID|@ID]\n\
559\n\
560DESCRIPTION\n\
561Looks for non-optimal subsequences and replaces them to shorten the given\n\
562sequence. By default it tries to shorten every subsequence of up to 10 moves,\n\
563but this can be change with the \"b\" option.\n\
564It outputs at most 10 equivalent optimal sequences for each replaceable part.\n\
565\n\
566OPTIONS\n\
567b=N Finds non-optimal subsequences of up to N moves.\n\
568\n\
569EXAMPLES\n\
570replace D2 F' D2 U2 F' L2 R2 U' D B2 D B2 U B2 F L2 R' F' D U' \n\
571 Produces the following output:\n\
572Replace [ R2 U' D B2 D B2 ] (moves 7-12) with: [ D R2 D U' ] (-6+4)\n\
573Replace [ R2 U' D B2 D B2 U ] (moves 7-13) with: [ D R2 D ] (-7+3)\n\
574Replace [ U' D B2 D B2 U ] (moves 8-13) with: [ R2 D R2 D ] (-6+4)\n\
575\n\
576"
577},
578
579{ "save",
580"\
581\n\
582HELP PAGE FOR COMMAND save\n\
583\n\
584SYNTAX\n\
585save [MOVES|@ID|$ID]\n\
586\n\
587DESCRIPTION\n\
588Memorizes the scramble specified by MOVES, given as input or temporarily saved\n\
589as @ID, where ID is a number ('help nissy' for for more on IDs). If an $ID is\n\
590given, it makes a copy of the scramble. An identifier of the form $ID, where ID\n\
591is a number, is assigned to the memorized scramble.\n\
592\n\
593EXAMPLES\n\
594save R U R' U'\n\
595 Saves the scramble R U R' U'.\n\
596save F (B)\n\
597 Saves the scramble F (B) (NISS notation).\n\
598save @3\n\
599 Saves the third output sequence of the last command.\n\
600save $2\n\
601 Makes a copy of the second saved scramble.\n\
602\n\
603"
604},
605
606{ "scramble",
607"\
608\n\
609HELP PAGE FOR COMMAND scramble\n\
610\n\
611SYNTAX\n\
612scramble [OPTIONS]\n\
613\n\
614DESCRIPTION\n\
615Produces a random-state scramble. There are options to get a corners-only,\n\
616edges-only or dr-state scramble.\n\
617\n\
618OPTIONS\n\
619c Scrambles corners only (edges are solved).\n\
620e Scrambles edges only (corners are solved).\n\
621dr DR-state scramble. The DR is always on the U/D axis.\n\
622\n\
623\n\
624EXAMPLES\n\
625scramble\n\
626 Gives a random-state scramble\n\
627scramble dr\n\
628 Gives a random-DR-state scramble\n\
629\n\
630"
631},
632
633{ "solve",
634"\
635\n\
636HELP PAGE FOR COMMAND solve\n\
637\n\
638SYNTAX\n\
639solve [MOVES|$ID|@ID]\n\
640\n\
641DESCRIPTION\n\
642Solves the given scramble, which can be given as a sequence of moves or as $ID\n\
643or @ID. If none is given, the user can type it on the next line.\n\
644The algorithm first tries to find a short (<=10 moves) solution, and then\n\
645switches to a 2-step algorithm (unless the option \"o\" is specified, in which\n\
646case it keeps looking for an optimal solution).\n\
647The first time it uses the 2-step algorithm it needs to load some tables, which\n\
648can take a few seconds. It runs much faster after that. If the option \"o\" is\n\
649specified, the first time it loads some large tables, which can take a minute\n\
650or two.\n\
651\n\
652OPTIONS\n\
653b=N Only looks for solutions up to N moves.\n\
654n=N Tries to find multiple solutions, at most N. Multiple\n\
655 Solutions will only be found if they are <=10 moves.\n\
656o Looks for optimal solution.\n\
657\n\
658\n\
659EXAMPLES\n\
660solve R' U' F\n\
661 Solves the scramble R' U' F.\n\
662solve o b=14 $1\n\
663 Tries to solve the scramble $1 optimally, but stops if no solution of 14\n\
664 moves or shorter is found.\n\
665solve n=16 R L' U2 R' L F2\n\
666 Finds the 16 shortest solutions for the scramble above.\n\
667\n\
668"
669},
670
671{ "unniss",
672"\
673\n\
674HELP PAGE FOR COMMAND unniss\n\
675\n\
676SYNTAX\n\
677unniss [MOVES|$ID|@ID]\n\
678\n\
679DESCRIPTION\n\
680Removes NISS from a sequence of moves, which can be given also as $ID or @ID.\n\
681A sequence of the form A (B) is translated to B' A.\n\
682\n\
683EXAMPLES\n\
684invert F R (D' L2)\n\
685 Prints L2 D F R\n\
686\n\
687"
688},
689};
diff --git a/src/io.c b/src/io.c
deleted file mode 100644
index ab0f658..0000000
--- a/src/io.c
+++ /dev/null
@@ -1,232 +0,0 @@
1#include <stdio.h>
2#include <stdint.h>
3#include <string.h>
4
5#include "coordinates.h"
6#include "moves.h"
7#include "utils.h"
8
9/* Functions for nice output */
10char *edge_string(int i) {
11 return (i > -1 && i < 12) ? edge_string_list[i] : "-";
12}
13
14char *corner_string(int i) {
15 return (i > -1 && i < 8) ? corner_string_list[i] : "-";
16}
17
18char *move_string(int i) {
19 return (i > -1 && i < 19) ? move_string_list[i] : "err";
20}
21
22void print_ep_array(int ep[12]) {
23 for (int i = 0; i < 12; i++)
24 printf(" %s ", edge_string(ep[i]));
25}
26
27void print_ep_int(int ep) {
28 int aux[12];
29 ep_int_to_array(ep, aux);
30 print_ep_array(aux);
31}
32
33void print_cp_array(int cp[8]) {
34 for (int i = 0; i < 8; i++)
35 printf(" %s ", corner_string(cp[i]));
36}
37
38void print_cp_int(int cp) {
39 int aux[8];
40 cp_int_to_array(cp, aux);
41 print_cp_array(aux);
42}
43
44void print_eo_array(int eo[12]) {
45 for (int i = 0; i < 12; i++) {
46 if (eo[i])
47 printf(" x ");
48 else
49 printf(" ");
50 }
51}
52
53void print_eo_int(int eo) {
54 int aux[12];
55 eo_11bits_to_array(eo, aux);
56 print_eo_array(aux);
57}
58
59void print_co_array(int co[8]) {
60 for (int i = 0; i < 8; i++) {
61 if (co[i] == 0)
62 printf(" ");
63 if (co[i] == 1)
64 printf(" cw ");
65 if (co[i] == 2)
66 printf(" ccw ");
67 }
68}
69
70void print_co_int(int co) {
71 int aux[8];
72 co_7trits_to_array(co, aux);
73 print_co_array(aux);
74}
75
76void print_cube_scram(int *scram) {
77 int ep = 0, cp = 0, eofb = 0, coud = 0;
78 for (int i = 0; scram[i]; i++) {
79 ep = apply_move_ep_int(scram[i], ep);
80 cp = cp_transition_table[cp][scram[i]];
81 eofb = eofb_transition_table[eofb][scram[i]];
82 coud = coud_transition_table[coud][scram[i]];
83 }
84 printf("\t\t"); print_ep_int(0); printf("\n");
85 printf("EP:\t\t"); print_ep_int(ep); printf("\n");
86 printf("EO(F/B):\t"); print_eo_int(eofb); printf("\n");
87 printf("\n");
88 printf("\t\t"); print_cp_int(0); printf("\n");
89 printf("CP:\t\t"); print_cp_int(cp); printf("\n");
90 printf("CO(U/D):\t"); print_co_int(coud); printf("\n");
91}
92
93
94void copy_moves(int *src, int *dst) {
95 for (int i = 0; (dst[i] = src[i]); i++);
96}
97
98void append_moves(int *src, int *dst) {
99 int n = 0;
100 for (; dst[n]; n++);
101 copy_moves(src, dst+n);
102}
103
104/* Parse a string and saves the move in a. Supports NISS notation.
105 * Returns the number of moves, or -1 in case of error. */
106int read_moves(char *str, int *a) {
107 int count = 0;
108 int niss = 0;
109 for (int i = 0; str[i] && str[i] != '\n'; i++) {
110 while (str[i] == ' ' || str[i] == '\t') i++;
111 switch (str[i]) {
112 case 'U':
113 a[count++] = niss ? -U : U;
114 break;
115 case 'D':
116 a[count++] = niss ? -D : D;
117 break;
118 case 'R':
119 a[count++] = niss ? -R : R;
120 break;
121 case 'L':
122 a[count++] = niss ? -L : L;
123 break;
124 case 'F':
125 a[count++] = niss ? -F : F;
126 break;
127 case 'B':
128 a[count++] = niss ? -B : B;
129 break;
130 case '(':
131 if (niss)
132 return -1;
133 else
134 niss = 1;
135 break;
136 case ')':
137 if (!niss)
138 return -1;
139 else
140 niss = 0;
141 break;
142 default:
143 return -1;
144 }
145 switch (str[++i]) {
146 case '2':
147 a[count-1] += niss ? -1 : 1;
148 break;
149 case '\'':
150 case '3':
151 a[count-1] += niss ? -2 : 2;
152 break;
153 case '1':
154 default:
155 --i;
156 }
157 }
158 a[count] = 0;
159 return count;
160}
161
162/* Read moves from standard input, after a prompt. */
163int read_moves_from_prompt(int *a) {
164 char str[1000];
165 printf("Enter moves: ");
166 if (fgets(str, 1000, stdin) == NULL)
167 return -1;
168 return read_moves(str, a);
169}
170
171/* Read moves from a list of token, each containing one or more moves. */
172int read_moves_from_tok(int n, char tok[][100], int *a) {
173 char str[1000] = "";
174 for (int i = 0; i < n; i++)
175 strcat(str, tok[i]);
176 return read_moves(str, a);
177}
178
179/* Checks if a sequence of moves uses NISS */
180int uses_niss(int *str) {
181 for (int i = 0; str[i]; i++)
182 if (str[i] < 0)
183 return 1;
184 return 0;
185}
186
187/* A (B) -> B' A */
188int unniss(int *src, int *dst) {
189 int n = 0;
190 for (int i = 0; src[i]; i++)
191 if (src[i] < 0)
192 n++;
193
194 int norm_count = n, inv_count = n-1;
195 for (int i = 0; src[i]; i++)
196 if (src[i] > 0)
197 dst[norm_count++] = src[i];
198 else
199 dst[inv_count--] = inverse_move[-src[i]];
200
201 dst[norm_count] = 0;
202
203 return n;
204}
205
206int invert(int *src, int *dst) {
207 int aux[255];
208 for (int i = 0; (aux[i] = -src[i]); i++);
209 return unniss(aux, dst);
210}
211
212int len(int *scram) {
213 int m;
214 for (m = 0; scram[m]; m++);
215 return m;
216}
217
218void print_moves(int moves_list[]) {
219 int niss = 0;
220 for (int i = 0; moves_list[i]; i++) {
221 if (!niss && moves_list[i] < 0) {
222 printf("(");
223 niss = 1;
224 }
225 printf("%s", move_string_list[abs(moves_list[i])]);
226 if (niss && moves_list[i+1] >= 0) {
227 niss = 0;
228 printf(")");
229 }
230 printf(" ");
231 }
232}
diff --git a/src/io.h b/src/io.h
deleted file mode 100644
index f1b585d..0000000
--- a/src/io.h
+++ /dev/null
@@ -1,21 +0,0 @@
1#include <stdint.h>
2
3char *edge_string(int edge);
4char *corner_string(int edge);
5char *move_string(int move);
6
7void print_cube_scram(int *scram);
8
9void copy_moves(int *src, int *dst);
10void append_moves(int *src, int *dst);
11
12int read_moves(char *str, int *a);
13int read_moves_from_prompt(int *a);
14int read_moves_from_tok(int n, char tok[][100], int *a);
15
16int uses_niss(int *str);
17int unniss(int *src, int *dst);
18int invert(int *src, int *dst);
19int len(int *scram);
20
21void print_moves(int move_list[]);
diff --git a/src/main.c b/src/main.c
deleted file mode 100644
index a14e365..0000000
--- a/src/main.c
+++ /dev/null
@@ -1,937 +0,0 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <time.h>
4#include "utils.h"
5#include "coordinates.h"
6#include "io.h"
7#include "moves.h"
8#include "solver.h"
9#include "string.h"
10#include "helppages.h"
11/* Saved sequences of moves */
12int scr_count=1, tmp_count=1, max_tmp=999;
13int scrambles[255][255], tmp[1000][255];
14
15int read_moves_from_variable(char *id, int *dst) {
16 char c = id[0];
17 if (c != '$' && c != '@')
18 return -1;
19 int n = atoi(id+1);
20 if (n <= 0 || n >= (c == '$' ? scr_count : tmp_count))
21 return -1;
22 copy_moves(c == '$' ? scrambles[n] : tmp[n], dst);
23 return n;
24}
25
26int read_moves_from_argument(int n, char tok[][100], int *dst) {
27 int r = read_moves_from_variable(tok[0], dst);
28 return (r != -1) ? r : read_moves_from_tok(n, tok, dst);
29}
30
31void print_results(int n, int res[][30]) {
32 if (n == -1)
33 printf("Pre-conditions not satisfied (or other error).\n");
34
35 if (n == 0)
36 printf("No result found (try different bounds).\n");
37
38 if (n > 1)
39 printf("Found %d results.\n", n);
40 tmp_count = 1; /* Reset temporary count */
41 for (int i = 0; i < n; i++) {
42 if (i < max_tmp) {
43 copy_moves(res[i], tmp[tmp_count]);
44 printf("@%d:\t", tmp_count++);
45 } else {
46 printf(" \t");
47 }
48 print_moves(res[i]);
49 printf("(%d)\n", len(res[i]));
50 }
51}
52
53/* Removes extra white spaces from the input string */
54int parsecmd(char *cmd, char cmdtok[][100]) {
55 char *i = cmd, *j = cmd;
56 while (*j != '\n' && *j != EOF) {
57 *i = *j;
58 if (*i == ' ' || *i == '\t')
59 *i = ' ';
60 ++j;
61 if (*i == ' ' || *i == '\t')
62 while (*j == ' ' || *j == '\t')
63 ++j;
64 ++i;
65 }
66 if (*(i-1) == ' ')
67 *(i-1) = 0;
68 else
69 *i = 0;
70
71 int n = 0;
72 char *s = strtok(cmd, " ");
73 while (s != NULL) {
74 strcpy(cmdtok[n++], s);
75 s = strtok(NULL, " ");
76 }
77 return n;
78}
79
80void scramble_cmd(int n, char cmdtok[][100]) {
81 int c = 0, e = 0, dr = 0;
82
83 if (n > 2 || cmdtok[0][0] != 's') { /* Second case avoids warning */
84 printf("scramble: wrong syntax\n");
85 return;
86 } else if (n == 2) {
87 if (!strcmp(cmdtok[1], "c")) {
88 c = 1;
89 } else if (!strcmp(cmdtok[1], "e")) {
90 e = 1;
91 } else if (!strcmp(cmdtok[1], "dr")) {
92 dr = 1;
93 } else {
94 printf("scramble: wrong syntax\n");
95 return;
96 }
97 }
98
99 int scram[2][30];
100
101 srand(time(NULL));
102 int eofb = rand() % pow2to11;
103 int coud = rand() % pow3to7;
104 int ep = rand() % factorial12;
105 int cp = rand() % factorial8;
106
107 if (c) {
108 eofb = ep = 0;
109 } else if (e) {
110 coud = cp = 0;
111 } else if (dr) {
112 eofb = coud = 0;
113 int epud = rand() % factorial8;
114 int epe = rand() % factorial4;
115 int ep_arr[12];
116 epud_int_to_array(epud, ep_arr);
117 epe_int_to_array(epe, ep_arr);
118 ep = ep_array_to_int(ep_arr);
119 while (perm_sign_int(ep, 12) != perm_sign_int(cp, 8))
120 cp = (cp+1) % factorial8;
121 } else {
122 while (perm_sign_int(ep, 12) != perm_sign_int(cp, 8))
123 cp = (cp+1) % factorial8;
124 }
125
126 reach_state(eofb, coud, ep, cp, scram);
127 /* Debug */
128 /* printf("State: %d %d %d %d\n", eofb, coud, ep, cp); */
129 print_results(1, scram);
130}
131
132void save_cmd(int n, char cmdtok[][100]) {
133 int scram[255];
134 if (n == 1) {
135 if (read_moves_from_prompt(scram) == -1) {
136 printf("save: error reading moves. Not saved.\n");
137 return;
138 }
139 } else if (read_moves_from_argument(n-1, cmdtok+1, scram) == -1) {
140 printf("save: error reading moves or ID. Not saved.\n");
141 return;
142 }
143
144 copy_moves(scram, scrambles[scr_count]);
145
146 printf("$%d:\t", scr_count);
147 print_moves(scrambles[scr_count]);
148 printf("\n");
149 scr_count++;
150}
151
152void change_cmd(int n, char cmdtok[][100]) {
153 int id, scram[255];
154 if (n == 1) {
155 printf("change: you must specify an $ID.\n");
156 return;
157 } else if (cmdtok[1][0] != '$') {
158 printf("change: invalid $ID.\n");
159 return;
160 } else {
161 id = atoi(cmdtok[1]+1);
162 if (id <= 0 || id >= scr_count) {
163 printf("change: invalid $ID.\n");
164 return;
165 }
166 if (n == 2) {
167 if (read_moves_from_prompt(scram) == -1) {
168 printf("change: error reading moves.\n");
169 return;
170 }
171 } else if (read_moves_from_argument(n-2, cmdtok+2, scram) == -1 ) {
172 printf("change: error reading moves or ID.\n");
173 return;
174 }
175 }
176
177 copy_moves(scram, scrambles[id]);
178
179 printf("$%d:\t", id);
180 print_moves(scrambles[id]);
181 printf("\n");
182}
183
184void print_cmd(int n, char cmdtok[][100]) {
185 if (n == 1) {
186 for (int i = 1; i < scr_count; i++) {
187 printf("$%d:\t", i);
188 print_moves(scrambles[i]);
189 printf("\n");
190 }
191 } else if (n == 2) {
192 int i = atoi(cmdtok[1]+1);
193 char sign = cmdtok[1][0];
194 if (sign != '$' && sign != '@') {
195 printf("print: invalid ID (must start with $ or @).\n");
196 return;
197 }
198 if (i > 0 && i < (sign == '$' ? scr_count : tmp_count)) {
199 printf("%c%d:\t", sign, i);
200 print_moves(sign == '$' ? scrambles[i] : tmp[i]);
201 printf("\n");
202 } else {
203 printf("print: invalid ID.\n");
204 return;
205 }
206 } else {
207 printf("print: wrong syntax.\n");
208 }
209}
210
211void add_cmd(int n, char cmdtok[][100]) {
212 int id, scram[255];
213 if (n == 1) {
214 printf("add: you must specify a destination $ID.\n");
215 return;
216 } else if (cmdtok[n-1][0] != '$') {
217 printf("add: invalid destination $ID.\n");
218 return;
219 } else {
220 id = atoi(cmdtok[n-1]+1);
221 if (id <= 0 || id >= scr_count) {
222 printf("add: invalid destination $ID.\n");
223 return;
224 }
225 if (n == 2) {
226 if (read_moves_from_prompt(scram) == -1) {
227 printf("add: error reading moves.\n");
228 return;
229 }
230 } else {
231 if (read_moves_from_argument(n-2, cmdtok+1, scram) == -1) {
232 printf("add: error reading moves or ID.\n");
233 return;
234 }
235 }
236 }
237
238 append_moves(scram, scrambles[id]);
239
240 printf("$%d:\t", id);
241 print_moves(scrambles[id]);
242 printf("\n");
243}
244
245void invert_cmd(int n, char cmdtok[][100]) {
246 int scram[255];
247 if (n == 1) {
248 if (read_moves_from_prompt(scram) == -1) {
249 printf("invert: error reading moves.\n");
250 return;
251 }
252 } else if (read_moves_from_argument(n-1, cmdtok+1, scram) == -1) {
253 printf("invert: error reading moves or ID.\n");
254 return;
255 }
256
257 if (uses_niss(scram)) {
258 printf("invert: cannot invert NISS.\n");
259 return;
260 }
261
262 invert(scram, tmp[1]);
263 tmp_count = 2;
264
265 printf("@1:\t");
266 print_moves(tmp[1]);
267 printf("\n");
268}
269
270void unniss_cmd(int n, char cmdtok[][100]) {
271 int scram[255];
272 if (n == 1) {
273 if (read_moves_from_prompt(scram) == -1) {
274 printf("unniss: error reading moves.\n");
275 return;
276 }
277 } else if (read_moves_from_argument(n-1, cmdtok+1, scram) == -1) {
278 printf("unniss: error reading moves or ID.\n");
279 return;
280 }
281
282 unniss(scram, tmp[1]);
283 tmp_count = 2;
284
285 printf("@1:\t");
286 print_moves(tmp[1]);
287 printf("\n");
288}
289
290void pic_cmd(int n, char cmdtok[][100]) {
291 int scram[255];
292 if (n == 1) {
293 if (read_moves_from_prompt(scram) == -1) {
294 printf("pic: error reading moves.\n");
295 return;
296 }
297 } else if (read_moves_from_argument(n-1, cmdtok+1, scram) == -1) {
298 printf("pic: error reading moves or ID.\n");
299 return;
300 }
301 print_cube_scram(scram);
302}
303
304void solve_cmd(int n, char cmdtok[][100]) {
305 int m = 1, b = 25, optimal = 0;
306 int scram[255] = {[0] = 0};
307 int scram_unnissed[255];
308
309 /* Parse options */
310 for (int i = 1; i < n && scram[0] == 0; i++) {
311 if (!strncmp(cmdtok[i], "b=", 2)) {
312 b = atoi(cmdtok[i]+2);
313 if (b <= 0) {
314 printf("solve: bad option b.\n");
315 return;
316 }
317 } else if (!strncmp(cmdtok[i], "n=", 2)) {
318 m = atoi(cmdtok[i]+2);
319 if (m <= 0) {
320 printf("solve: bad option n.\n");
321 return;
322 }
323 } else if (!strcmp(cmdtok[i], "o")) {
324 optimal = 1;
325 } else if (read_moves_from_argument(n-i, cmdtok+i, scram) == -1) {
326 printf("solve: error reading moves or ID.\n");
327 return;
328 }
329 }
330
331 if (scram[0] == 0) {
332 if (read_moves_from_prompt(scram) == -1) {
333 printf("solve: error reading moves.\n");
334 return;
335 }
336 }
337
338 /* Call solver and print results */
339 unniss(scram, scram_unnissed);
340 int sol[m+2][30];
341 int s = solve_scram(scram_unnissed, sol, m, b, optimal);
342 print_results(s, sol);
343}
344
345void replace_cmd(int n, char cmdtok[][100]) {
346 int m = 10; /* max length */
347 int scram[255] = {[0] = 0};
348 int scram_unnissed[255];
349
350 /* Parse options */
351 for (int i = 1; i < n && scram[0] == 0; i++) {
352 if (!strncmp(cmdtok[i], "b=", 2)) {
353 m = atoi(cmdtok[i]+2);
354 if (m <= 0) {
355 printf("replace: bad option n.\n");
356 return;
357 }
358 } else if (read_moves_from_argument(n-i, cmdtok+i, scram) == -1) {
359 printf("replace: error reading moves or ID.\n");
360 return;
361 }
362 }
363
364 if (scram[0] == 0) {
365 if (read_moves_from_prompt(scram) == -1) {
366 printf("replace: error reading moves.\n");
367 return;
368 }
369 }
370
371 unniss(scram, scram_unnissed);
372 int l = len(scram_unnissed);
373 int aux1[255], aux2[15][30], aux3[30];
374 for (int i = 0; i < l; i++) {
375 for (int j = 2; j <= m && i + j <= l; j++) {
376 copy_moves(scram_unnissed+i, aux1);
377 aux1[j] = 0;
378 int s = solve_scram(aux1, aux2, 10, j-1, 1);
379 for (int k = 0; k < s; k++) {
380 invert(aux2[k], aux3);
381 /* TODO: the following part should also chek for the case when
382 * the last moves are R L or similar. */
383 if (aux3[0] != aux1[0] && aux3[len(aux3)-1] != aux1[len(aux1)-1]) {
384 printf("Replace [ ");
385 print_moves(aux1);
386 printf("] (moves %d-%d) with: [ ", i+1, i+j);
387 print_moves(aux3);
388 printf("] (-%d+%d)\n", j, len(aux3));
389 }
390 }
391 }
392 }
393}
394
395void clear_cmd(int n, char cmdtok[][100]) {
396 if (n > 1 || cmdtok[0][0] != 'c') { /* Avoid unused variable warning */
397 printf("clear: syntax error.\n");
398 return;
399 }
400 scr_count = tmp_count = 1;
401}
402
403void eo_cmd(int n, char cmdtok[][100]) {
404
405 /* Default values */
406 int m = 1, b = 20;
407 int niss = 0, hide = 1;
408 int fb = 1, rl = 1, ud = 1;
409 int scram[255] = {[0] = 0};
410 int scram_unnissed[255];
411
412 /* Parse options */
413 for (int i = 1; i < n && scram[0] == 0; i++) {
414 if (!strcmp(cmdtok[i], "h")) {
415 hide = 0;
416 } else if (!strcmp(cmdtok[i], "niss")) {
417 niss = 1;
418 } else if (!strncmp(cmdtok[i], "axis=", 5)) {
419 fb = rl = ud = 0;
420 if (strstr(cmdtok[i], "fb") != NULL)
421 fb = 1;
422 if (strstr(cmdtok[i], "rl") != NULL)
423 rl = 1;
424 if (strstr(cmdtok[i], "ud") != NULL)
425 ud = 1;
426 if (fb + rl + ud == 0) {
427 printf("eo: bad axis option.\n");
428 return;
429 }
430 } else if (!strncmp(cmdtok[i], "n=", 2)) {
431 m = atoi(cmdtok[i]+2);
432 if (m <= 0) {
433 printf("eo: bad option n.\n");
434 return;
435 }
436 } else if (!strncmp(cmdtok[i], "b=", 2)) {
437 b = atoi(cmdtok[i]+2);
438 if (b <= 0) {
439 printf("eo: bad option b.\n");
440 return;
441 }
442 } else if (read_moves_from_argument(n-i, cmdtok+i, scram) == -1) {
443 printf("eo: error reading moves or ID.\n");
444 return;
445 }
446 }
447
448 if (scram[0] == 0) {
449 if (read_moves_from_prompt(scram) == -1) {
450 printf("eo: error reading moves.\n");
451 return;
452 }
453 }
454
455 unniss(scram, scram_unnissed);
456
457 /* Call solver and print results */
458 int eo_list[m+5][30];
459 int neo = eo_scram_spam(scram_unnissed, eo_list, fb, rl, ud, m, b, niss,
460 hide);
461 print_results(neo, eo_list);
462}
463
464void co_cmd(int n, char cmdtok[][100]) {
465
466 /* Default values */
467 int m = 1, b = 20, ignore = 0;
468 int niss = 0, hide = 1;
469 int fb = 1, rl = 1, ud = 1;
470 int scram[255] = {[0] = 0};
471 int scram_unnissed[255];
472
473 /* Parse options */
474 for (int i = 1; i < n && scram[0] == 0; i++) {
475 if (!strcmp(cmdtok[i], "h")) {
476 hide = 0;
477 } else if (!strcmp(cmdtok[i], "niss")) {
478 niss = 1;
479 } else if (!strcmp(cmdtok[i], "i")) {
480 ignore = 1;
481 } else if (!strncmp(cmdtok[i], "axis=", 5)) {
482 fb = rl = ud = 0;
483 if (strstr(cmdtok[i], "fb") != NULL)
484 fb = 1;
485 if (strstr(cmdtok[i], "rl") != NULL)
486 rl = 1;
487 if (strstr(cmdtok[i], "ud") != NULL)
488 ud = 1;
489 if (fb + rl + ud == 0) {
490 printf("co: bad axis option.\n");
491 return;
492 }
493 } else if (!strncmp(cmdtok[i], "n=", 2)) {
494 m = atoi(cmdtok[i]+2);
495 if (m <= 0) {
496 printf("co: bad option n.\n");
497 return;
498 }
499 } else if (!strncmp(cmdtok[i], "b=", 2)) {
500 b = atoi(cmdtok[i]+2);
501 if (b <= 0) {
502 printf("co: bad option b.\n");
503 return;
504 }
505 } else if (read_moves_from_argument(n-i, cmdtok+i, scram) == -1) {
506 printf("co: error reading moves or ID.\n");
507 return;
508 }
509 }
510
511 if (scram[0] == 0) {
512 if (read_moves_from_prompt(scram) == -1) {
513 printf("co: error reading moves.\n");
514 return;
515 }
516 }
517
518 unniss(scram, scram_unnissed);
519
520 /* Call solver and print results */
521 int co_list[m+5][30];
522 int nco = co_scram_spam(scram_unnissed, co_list, fb, rl, ud, m, b, niss,
523 hide, ignore);
524 print_results(nco, co_list);
525}
526
527void dr_cmd(int n, char cmdtok[][100]) {
528
529 /* Default values */
530 int m = 1, b = 20;
531 int niss = 0, hide = 1;
532 int from = 0; /* 0: direct dr; {1,2,3}: from {eofb,eorl,eoud} */
533 int fb = 1, rl = 1, ud = 1;
534 int scram[255] = {[0] = 0};
535 int scram_unnissed[255];
536
537 /* Parse options */
538 for (int i = 1; i < n && scram[0] == 0; i++) {
539 if (!strcmp(cmdtok[i], "h")) {
540 hide = 0;
541 } else if (!strcmp(cmdtok[i], "niss")) {
542 niss = 1;
543 } else if (!strncmp(cmdtok[i], "axis=", 5)) {
544 fb = rl = ud = 0;
545 if (strstr(cmdtok[i], "fb") != NULL)
546 fb = 1;
547 if (strstr(cmdtok[i], "rl") != NULL)
548 rl = 1;
549 if (strstr(cmdtok[i], "ud") != NULL)
550 ud = 1;
551 if (fb + rl + ud == 0) {
552 printf("dr: bad axis option.\n");
553 return;
554 }
555 } else if (!strncmp(cmdtok[i], "n=", 2)) {
556 m = atoi(cmdtok[i]+2);
557 if (m <= 0) {
558 printf("dr: bad option n.\n");
559 return;
560 }
561 } else if (!strncmp(cmdtok[i], "b=", 2)) {
562 b = atoi(cmdtok[i]+2);
563 if (b <= 0) {
564 printf("dr: bad option b.\n");
565 return;
566 }
567 } else if (!strcmp(cmdtok[i], "from")) {
568 i++;
569 char x[3][3] = {"fb", "rl", "ud"};
570 for (int j = 0; j < 3; j++)
571 if (!strcmp(cmdtok[i], x[j]))
572 from = j+1;
573 if (!from) {
574 printf("dr: bad from option.\n");
575 return;
576 }
577 } else if (read_moves_from_argument(n-i, cmdtok+i, scram) == -1) {
578 printf("dr: error reading moves or ID.\n");
579 return;
580 }
581 }
582
583 if (scram[0] == 0) {
584 if (read_moves_from_prompt(scram) == -1) {
585 printf("dr: error reading moves.\n");
586 return;
587 }
588 }
589
590 unniss(scram, scram_unnissed);
591
592 /* Call solver */
593 int dr_list[m+5][30], ndr;
594 if (from) {
595 ndr = drfrom_scram_spam(scram_unnissed, dr_list, from, fb, rl, ud,
596 m, b, niss, hide);
597 if (ndr == -1) {
598 printf("dr: from given, but EO not found (possibly other error).\n");
599 return;
600 }
601 } else {
602 if (niss)
603 printf("Warning: not using NISS for direct DR.\n");
604 ndr = dr_scram_spam(scram_unnissed, dr_list, fb, rl, ud, m, b, hide);
605 }
606 print_results(ndr, dr_list);
607}
608
609void htr_cmd(int n, char cmdtok[][100]) {
610
611 /* Default values */
612 int m = 1, b = 20;
613 int niss = 0, hide = 1;
614 int from = 0; /* 0: unspecified; {1,2,3}: from {ud,fb,rl} */
615 int scram[255] = {[0] = 0};
616 int scram_unnissed[255];
617
618 /* Parse options */
619 for (int i = 1; i < n && scram[0] == 0; i++) {
620 if (!strcmp(cmdtok[i], "h")) {
621 hide = 0;
622 } else if (!strcmp(cmdtok[i], "niss")) {
623 niss = 1;
624 } else if (!strncmp(cmdtok[i], "n=", 2)) {
625 m = atoi(cmdtok[i]+2);
626 if (m <= 0) {
627 printf("htr: bad option n.\n");
628 return;
629 }
630 } else if (!strncmp(cmdtok[i], "b=", 2)) {
631 b = atoi(cmdtok[i]+2);
632 if (b <= 0) {
633 printf("htr: bad option b.\n");
634 return;
635 }
636 } else if (!strcmp(cmdtok[i], "from")) {
637 i++;
638 char x[3][3] = {"ud", "fb", "rl"};
639 for (int j = 0; j < 3; j++)
640 if (!strcmp(cmdtok[i], x[j]))
641 from = j+1;
642 if (!from) {
643 printf("htr: bad from option.\n");
644 return;
645 }
646 } else if (read_moves_from_argument(n-i, cmdtok+i, scram) == -1) {
647 printf("htr: error reading moves or ID.\n");
648 return;
649 }
650 }
651
652 if (scram[0] == 0) {
653 if (read_moves_from_prompt(scram) == -1) {
654 printf("htr: error reading moves.\n");
655 return;
656 }
657 }
658
659 unniss(scram, scram_unnissed);
660
661 /* Call solver */
662 int htr_list[m+5][30], nhtr;
663 nhtr = htr_scram_spam(scram_unnissed, htr_list, from, m, b, niss, hide);
664 print_results(nhtr, htr_list);
665}
666
667void drfinish_cmd(int n, char cmdtok[][100]) {
668 /* Default values */
669 int m = 1, b = 20;
670 int from = 0; /* 0: unspecified; {1,2,3}: from {ud,fb,rl} */
671 int scram[255] = {[0] = 0};
672 int scram_unnissed[255];
673
674 /* Parse options */
675 for (int i = 1; i < n && scram[0] == 0; i++) {
676 if (!strncmp(cmdtok[i], "n=", 2)) {
677 m = atoi(cmdtok[i]+2);
678 if (m <= 0) {
679 printf("drfinish: bad option n.\n");
680 return;
681 }
682 } else if (!strncmp(cmdtok[i], "b=", 2)) {
683 b = atoi(cmdtok[i]+2);
684 if (b <= 0) {
685 printf("drfinish: bad option b.\n");
686 return;
687 }
688 } else if (!strcmp(cmdtok[i], "from")) {
689 i++;
690 char x[3][3] = {"ud", "fb", "rl"};
691 for (int j = 0; j < 3; j++)
692 if (!strcmp(cmdtok[i], x[j]))
693 from = j+1;
694 if (!from) {
695 printf("drfinish: bad from option.\n");
696 return;
697 }
698 } else if (read_moves_from_argument(n-i, cmdtok+i, scram) == -1) {
699 printf("drfinish: error reading moves or ID.\n");
700 return;
701 }
702 }
703
704 if (scram[0] == 0) {
705 if (read_moves_from_prompt(scram) == -1) {
706 printf("drfinish: error reading moves.\n");
707 return;
708 }
709 }
710
711 unniss(scram, scram_unnissed);
712
713 /* Call solver */
714 int c_list[m+5][30], nc;
715 nc = dr_finish_scram_spam(scram_unnissed, c_list, from, m, b);
716 print_results(nc, c_list);
717}
718
719void htrfinish_cmd(int n, char cmdtok[][100]) {
720 /* Default values */
721 int m = 1, b = 20;
722 int scram[255] = {[0] = 0};
723 int scram_unnissed[255];
724
725 /* Parse options */
726 for (int i = 1; i < n && scram[0] == 0; i++) {
727 if (!strncmp(cmdtok[i], "n=", 2)) {
728 m = atoi(cmdtok[i]+2);
729 if (m <= 0) {
730 printf("htrfinish: bad option n.\n");
731 return;
732 }
733 } else if (!strncmp(cmdtok[i], "b=", 2)) {
734 b = atoi(cmdtok[i]+2);
735 if (b <= 0) {
736 printf("htrfinish: bad option b.\n");
737 return;
738 }
739 } else if (read_moves_from_argument(n-i, cmdtok+i, scram) == -1) {
740 printf("htrfinish: error reading moves or ID.\n");
741 return;
742 }
743 }
744
745 if (scram[0] == 0) {
746 if (read_moves_from_prompt(scram) == -1) {
747 printf("htrfinish: error reading moves.\n");
748 return;
749 }
750 }
751
752 unniss(scram, scram_unnissed);
753
754 /* Call solver */
755 int c_list[m+5][30], nc;
756 nc = htr_finish_scram_spam(scram_unnissed, c_list, m, b);
757 print_results(nc, c_list);
758}
759
760void drcorners_cmd(int n, char cmdtok[][100]) {
761 /* Default values */
762 int m = 1, b = 20, ignore = 0;
763 int from = 0; /* 0: unspecified; {1,2,3}: from {ud,fb,rl} */
764 int scram[255] = {[0] = 0};
765 int scram_unnissed[255];
766
767 /* Parse options */
768 for (int i = 1; i < n && scram[0] == 0; i++) {
769 if (!strncmp(cmdtok[i], "n=", 2)) {
770 m = atoi(cmdtok[i]+2);
771 if (m <= 0) {
772 printf("drcorners: bad option n.\n");
773 return;
774 }
775 } else if (!strncmp(cmdtok[i], "b=", 2)) {
776 b = atoi(cmdtok[i]+2);
777 if (b <= 0) {
778 printf("drcorners: bad option b.\n");
779 return;
780 }
781 } else if (!strcmp(cmdtok[i], "i")) {
782 ignore = 1;
783 } else if (!strcmp(cmdtok[i], "from")) {
784 i++;
785 char x[3][3] = {"ud", "fb", "rl"};
786 for (int j = 0; j < 3; j++)
787 if (!strcmp(cmdtok[i], x[j]))
788 from = j+1;
789 if (!from) {
790 printf("drcorners: bad from option.\n");
791 return;
792 }
793 } else if (read_moves_from_argument(n-i, cmdtok+i, scram) == -1) {
794 printf("drcorners: error reading moves or ID.\n");
795 return;
796 }
797 }
798
799 if (scram[0] == 0) {
800 if (read_moves_from_prompt(scram) == -1) {
801 printf("drcorners: error reading moves.\n");
802 return;
803 }
804 }
805
806 unniss(scram, scram_unnissed);
807
808 /* Call solver */
809 int c_list[m+5][30], nc;
810 nc = dr_corners_scram_spam(scram_unnissed, c_list, from, m, b, ignore);
811 print_results(nc, c_list);
812}
813
814
815void exit_quit_cmd(int n, char cmdtok[][100]) {
816 if (n == 1)
817 exit(0);
818 else
819 printf("%s: wrong synstax.\n", cmdtok[0]);
820}
821
822/***************************************************************/
823/* List of all commands */
824/* Important: they must be in the same order in the two arrays */
825/***************************************************************/
826
827char *commands[][10] = {
828 {"help", "[COMMAND]",
829 "Print this help, or a help page for COMMAND."},
830 {"scramble", "[OPTIONS]",
831 "Prints a random-state scramble."},
832 {"save", "[MOVES|@ID|$ID]",
833 "Save or copy a scramble."},
834 {"change", "$ID1 [MOVES|$ID2|@ID2]",
835 "Change a memorized scramble."},
836 {"print", "[$ID|@ID]",
837 "Print memorized sequences."},
838 {"add", "[MOVES|$ID1|@ID1] $ID2",
839 "Add moves at the end of a memorized scramble."},
840 {"invert", "[MOVES|$ID|@ID]",
841 "Inverts the given sequence of moves."},
842 {"unniss", "[MOVES|$ID|@ID]}",
843 "Removes NISS: A (B) -> B\' A."},
844 {"pic", "[MOVES|$ID|@ID]",
845 "Show a text description of the scrambled cube."},
846 {"solve", "[MOVES|$ID|@ID]",
847 "Solves a scramble."},
848 {"replace", "[MOVES|$ID|@ID]",
849 "Find non-optimal subsequences."},
850 {"clear", "",
851 "Delete saved scrambles and output sequences."},
852 {"eo", "[MOVES|$ID|@ID]",
853 "Solves EO."},
854 {"co", "[MOVES|$ID|@ID]",
855 "Solves CO."},
856 {"dr", "[MOVES|$ID|@ID]",
857 "Solves DR, either directly or from eo."},
858 {"htr", "[MOVES|$ID|@ID]",
859 "Solves HTR from DR."},
860 {"drfinish", "[MOVES|$ID|@ID]",
861 "Solves the cube after DR."},
862 {"htrfinish", "[MOVES|$ID|@ID]",
863 "Solves the cube using only half turns."},
864 {"drcorners", "[MOVES|$ID|@ID]",
865 "Solves corners after DR."},
866 {"exit", "",
867 "Exit nissy."},
868 {"quit", "",
869 "Exit nissy."},
870 {"", "", ""}
871};
872
873void help_cmd(int n, char cmdtok[][100]) {
874 if (n == 1) {
875 printf("\n");
876 for (int i = 0; commands[i][0][0]; i++)
877 printf("%-10s%-25s%s\n", commands[i][0], commands[i][1], commands[i][2]);
878 printf("\n");
879 printf("Type \'help\' followed by a command for a detailed help page.\n");
880 printf("Type \'help nissy\' for a general user guide.\n");
881 } else if (n == 2) {
882 for (int i = 0; i < Npages; i++) {
883 if (!strcmp(helppages[i][0], cmdtok[1])) {
884 printf("%s", helppages[i][1]);
885 return;
886 }
887 }
888 printf("No help page for %s.\n", cmdtok[1]);
889 return;
890 } else {
891 printf("help: wrong syntax.\n");
892 }
893}
894
895void (*cmd_list[])(int n, char cmdtok[][100]) = {
896 help_cmd, scramble_cmd, save_cmd, change_cmd, print_cmd,
897 add_cmd, invert_cmd, unniss_cmd, pic_cmd,
898 solve_cmd, replace_cmd, clear_cmd,
899 eo_cmd, co_cmd, dr_cmd, htr_cmd,
900 drfinish_cmd, htrfinish_cmd, drcorners_cmd,
901 exit_quit_cmd, exit_quit_cmd, NULL
902};
903
904
905void execcmd(int n, char cmdtok[][100]) {
906 int i = 0;
907 while (strcmp(commands[i][0], cmdtok[0]) && strcmp(commands[i][0], ""))
908 i++;
909 if (strcmp(commands[i][0], ""))
910 (*cmd_list[i])(n, cmdtok);
911 else
912 printf("%s: not a command.\n", cmdtok[0]);
913}
914
915
916/* Main loop */
917
918int main() {
919 init_transition_table();
920 init_possible_next();
921
922 printf("Type help for a list of commands.\n");
923
924 char cmd[1000] = "";
925 while (1) {
926 printf("nissy-# ");
927 if (fgets(cmd, 1000, stdin) == NULL)
928 break;
929 char cmdtok[100][100];
930 int n = parsecmd(cmd, cmdtok);
931 if (n == 0)
932 continue;
933 execcmd(n, cmdtok);
934 }
935
936 return 0;
937}
diff --git a/src/moves.c b/src/moves.c
index ce47e8f..25ce779 100644
--- a/src/moves.c
+++ b/src/moves.c
@@ -1,521 +1,475 @@
1/* This file contains the definitions of the basic moves of the cube.
2 * There is no object or type representing the cube.
3 * Data about the cube can be represented by arrays (describing the position
4 * of pieces of certain types), integers (representing for example a bitmask
5 * for the orientation of pieces of certain type, or the permutation index of
6 * an array representing the permutation of pieces).
7 * Each of the moves functions operates on one such piece of data.
8 *
9 * For example, a way of representing the cube can be:
10 * - An integer eo, which is a bitmask for the orientation of the edges.
11 * - An integer co, same for corners.
12 * - An array ep[12], where a[i]=j means that the edge j is in place i.
13 * - An integer cp representing the permutation index of a permutation array
14 * which is the analogue of that described for edges.
15 *
16 * Different representations will be used for different use-cases. */
17
18#include "coordinates.h"
19#include "moves.h" 1#include "moves.h"
20 2
21/* possible_next[i][j] is a bitmask representing the possible 3/* Local functions ***********************************************************/
22 * next moves we can apply. For example, if the last moves a 0 R then it does
23 * not make sense to apply R, R2 or R'. If they are U D2 it does not make
24 * sense to apply any U* or D*. */
25int possible_next[19][19];
26 4
27int parallel(int m1, int m2) { 5static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f);
28 if (m1 == 0 || m2 == 0) return 0; 6static bool read_mtables_file();
29 return ((m1-1)/6 == (m2-1)/6); 7static bool write_mtables_file();
30}
31 8
32int compute_possible_next(int last1, int last2) { 9/* Tables and other data *****************************************************/
33 if (last1 == 0) return move_mask_all;
34 10
35 /* Removes the 2 or ' (e.g. turns U2 to U, R' to R). */ 11/* Every move is translated to a an <U, x, y> alg before filling the
36 last2 = (last2 == 0) ? last2 : 3*((last2-1)/3) + 1; 12 transition tables, see init_moves() */
37 last1 = 3*((last1-1)/3) + 1;
38 13
39 int mask = move_mask_all ^ (7 << last1); 14static int edge_cycle[NMOVES][12] =
15{
16 [U] = { UR, UF, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR },
17 [x] = { DF, FL, UF, FR, DB, BL, UB, BR, DR, DL, UL, UR },
18 [y] = { UR, UF, UL, UB, DR, DF, DL, DB, BR, FR, FL, BL }
19};
40 20
41 if (parallel(last1, last2)) 21static int corner_cycle[NMOVES][8] =
42 mask ^= 7 << last2; 22{
43 else if (last1 % 6 == 4) /*Always U before D, R before L, F before B*/ 23 [U] = { UBR, UFR, UFL, UBL, DFR, DFL, DBL, DBR },
44 mask ^= 7 << (last1-3); 24 [x] = { DFR, DFL, UFL, UFR, DBR, DBL, UBL, UBR },
25 [y] = { UBR, UFR, UFL, UBL, DBR, DFR, DFL, DBL }
26};
45 27
46 return mask; 28static int center_cycle[NMOVES][6] =
47} 29{
30 [x] = { F_center, B_center, R_center, L_center, D_center, U_center },
31 [y] = { U_center, D_center, B_center, F_center, R_center, L_center }
32};
48 33
49void init_possible_next() { 34static int eofb_flipped[NMOVES][12] = {
50 for (int i = 0; i < 19; i++) 35 [x] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 },
51 for (int j = 0; j < 19; j++) 36 [y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 }
52 possible_next[i][j] = compute_possible_next(i, j); 37};
53}
54 38
55/* Piece cycles depending on the move. For example edge_cycle[U2][UF] 39static int eorl_flipped[NMOVES][12] = {
56 * gives the piece in position UF after applying U2 to a solved cube */ 40 [x] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
41 [y] = { [FR] = 1, [FL] = 1, [BL] = 1, [BR] = 1 }
42};
57 43
58int edge_cycle[19][12] = { 44static int eoud_flipped[NMOVES][12] = {
59 {UF, UL, UB, UR, DF, DL, DB, DR, FR, FL, BL, BR}, /* - */ 45 [U] = { [UF] = 1, [UL] = 1, [UB] = 1, [UR] = 1 },
60 {UR, UF, UL, UB, DF, DL, DB, DR, FR, FL, BL, BR}, /* U */ 46 [x] = { [UF] = 1, [UB] = 1, [DF] = 1, [DB] = 1 },
61 {UB, UR, UF, UL, DF, DL, DB, DR, FR, FL, BL, BR}, /* U2 */ 47 [y] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
62 {UL, UB, UR, UF, DF, DL, DB, DR, FR, FL, BL, BR}, /* U' */
63 {UF, UL, UB, UR, DL, DB, DR, DF, FR, FL, BL, BR}, /* D */
64 {UF, UL, UB, UR, DB, DR, DF, DL, FR, FL, BL, BR}, /* D2 */
65 {UF, UL, UB, UR, DR, DF, DL, DB, FR, FL, BL, BR}, /* D' */
66 {UF, UL, UB, FR, DF, DL, DB, BR, DR, FL, BL, UR}, /* R */
67 {UF, UL, UB, DR, DF, DL, DB, UR, BR, FL, BL, FR}, /* R2 */
68 {UF, UL, UB, BR, DF, DL, DB, FR, UR, FL, BL, DR}, /* R' */
69 {UF, BL, UB, UR, DF, FL, DB, DR, FR, UL, DL, BR}, /* L */
70 {UF, DL, UB, UR, DF, UL, DB, DR, FR, BL, FL, BR}, /* L2 */
71 {UF, FL, UB, UR, DF, BL, DB, DR, FR, DL, UL, BR}, /* L' */
72 {FL, UL, UB, UR, FR, DL, DB, DR, UF, DF, BL, BR}, /* F */
73 {DF, UL, UB, UR, UF, DL, DB, DR, FL, FR, BL, BR}, /* F2 */
74 {FR, UL, UB, UR, FL, DL, DB, DR, DF, UF, BL, BR}, /* F' */
75 {UF, UL, BR, UR, DF, DL, BL, DR, FR, FL, UB, DB}, /* B */
76 {UF, UL, DB, UR, DF, DL, UB, DR, FR, FL, BR, BL}, /* B2 */
77 {UF, UL, BL, UR, DF, DL, BR, DR, FR, FL, DB, UB} /* B' */
78}; 48};
79 49
80int corner_cycle[19][8] = { 50static int coud_flipped[NMOVES][8] = {
81 {UFR, UFL, UBL, UBR, DFR, DFL, DBL, DBR}, /* - */ 51 [x] = {
82 {UBR, UFR, UFL, UBL, DFR, DFL, DBL, DBR}, /* U */ 52 [UFR] = 2, [UBR] = 1, [UFL] = 1, [UBL] = 2,
83 {UBL, UBR, UFR, UFL, DFR, DFL, DBL, DBR}, /* U2 */ 53 [DBR] = 2, [DFR] = 1, [DBL] = 1, [DFL] = 2
84 {UFL, UBL, UBR, UFR, DFR, DFL, DBL, DBR}, /* U' */ 54 }
85 {UFR, UFL, UBL, UBR, DFL, DBL, DBR, DFR}, /* D */
86 {UFR, UFL, UBL, UBR, DBL, DBR, DFR, DFL}, /* D2 */
87 {UFR, UFL, UBL, UBR, DBR, DFR, DFL, DBL}, /* D' */
88 {DFR, UFL, UBL, UFR, DBR, DFL, DBL, UBR}, /* R */
89 {DBR, UFL, UBL, DFR, UBR, DFL, DBL, UFR}, /* R2 */
90 {UBR, UFL, UBL, DBR, UFR, DFL, DBL, DFR}, /* R' */
91 {UFR, UBL, DBL, UBR, DFR, UFL, DFL, DBR}, /* L */
92 {UFR, DBL, DFL, UBR, DFR, UBL, UFL, DBR}, /* L2 */
93 {UFR, DFL, UFL, UBR, DFR, DBL, UBL, DBR}, /* L' */
94 {UFL, DFL, UBL, UBR, UFR, DFR, DBL, DBR}, /* F */
95 {DFL, DFR, UBL, UBR, UFL, UFR, DBL, DBR}, /* F2 */
96 {DFR, UFR, UBL, UBR, DFL, UFL, DBL, DBR}, /* F' */
97 {UFR, UFL, UBR, DBR, DFR, DFL, UBL, DBL}, /* B */
98 {UFR, UFL, DBR, DBL, DFR, DFL, UBR, UBL}, /* B2 */
99 {UFR, UFL, DBL, UBL, DFR, DFL, DBR, UBR}, /* U' */
100}; 55};
101 56
102/* Transition tables */ 57static int corl_flipped[NMOVES][8] = {
58 [U] = { [UFR] = 1, [UBR] = 2, [UBL] = 1, [UFL] = 2 },
59 [y] = {
60 [UFR] = 1, [UBR] = 2, [UBL] = 1, [UFL] = 2,
61 [DFR] = 2, [DBR] = 1, [DBL] = 2, [DFL] = 1
62 }
63};
103 64
104int eofb_transition_table[pow2to11][19]; 65static int cofb_flipped[NMOVES][8] = {
105int eorl_transition_table[pow2to11][19]; 66 [U] = { [UFR] = 2, [UBR] = 1, [UBL] = 2, [UFL] = 1 },
106int eoud_transition_table[pow2to11][19]; 67 [x] = {
107int coud_transition_table[pow3to7][19]; 68 [UFR] = 1, [UBR] = 2, [UBL] = 1, [UFL] = 2,
108int cofb_transition_table[pow3to7][19]; 69 [DFR] = 2, [DBR] = 1, [DBL] = 2, [DFL] = 1
109int corl_transition_table[pow3to7][19]; 70 },
110int epud_transition_table[factorial8][19]; 71 [y] = {
111int eprl_transition_table[factorial8][19]; 72 [UFR] = 2, [UBR] = 1, [UBL] = 2, [UFL] = 1,
112int epfb_transition_table[factorial8][19]; 73 [DFR] = 1, [DBR] = 2, [DBL] = 1, [DFL] = 2
113int epose_transition_table[binom12on4][19]; 74 }
114int eposs_transition_table[binom12on4][19]; 75};
115int eposm_transition_table[binom12on4][19];
116int epe_transition_table[factorial4][19];
117int eps_transition_table[factorial4][19];
118int epm_transition_table[factorial4][19];
119int emslices_transition_table[binom12on4*binom8on4][19];
120int cp_transition_table[factorial8][19];
121 76
122/***/ 77static char equiv_alg_string[100][NMOVES] = {
123/* Functions for permuting pieces (given in array format) */ 78 [NULLMOVE] = "",
124/***/
125 79
126void apply_move_ep_array(int move, int ep[12]) { 80 [U] = " U ",
127 int aux[12]; 81 [U2] = " UU ",
128 for (int i = 0; i < 12; i++) 82 [U3] = " UUU ",
129 aux[i] = ep[i]; 83 [D] = " xx U xx ",
130 for (int i = 0; i < 12; i++) 84 [D2] = " xx UU xx ",
131 ep[i] = aux[edge_cycle[move][i]]; 85 [D3] = " xx UUU xx ",
132} 86 [R] = " yx U xxxyyy ",
87 [R2] = " yx UU xxxyyy ",
88 [R3] = " yx UUU xxxyyy ",
89 [L] = " yyyx U xxxy ",
90 [L2] = " yyyx UU xxxy ",
91 [L3] = " yyyx UUU xxxy ",
92 [F] = " x U xxx ",
93 [F2] = " x UU xxx ",
94 [F3] = " x UUU xxx ",
95 [B] = " xxx U x ",
96 [B2] = " xxx UU x ",
97 [B3] = " xxx UUU x ",
133 98
134void apply_move_cp_array(int move, int cp[8]) { 99 [Uw] = " xx U xx y ",
135 int aux[8]; 100 [Uw2] = " xx UU xx yy ",
136 for (int i = 0; i < 8; i++) 101 [Uw3] = " xx UUU xx yyy ",
137 aux[i] = cp[i]; 102 [Dw] = " U yyy ",
138 for (int i = 0; i < 8; i++) 103 [Dw2] = " UU yy ",
139 cp[i] = aux[corner_cycle[move][i]]; 104 [Dw3] = " UUU y ",
140} 105 [Rw] = " yyyx U xxxy x ",
106 [Rw2] = " yyyx UU xxxy xx ",
107 [Rw3] = " yyyx UUU xxxy xxx ",
108 [Lw] = " yx U xxxyyy xxx ",
109 [Lw2] = " yx UU xxxyyy xx ",
110 [Lw3] = " yx UUU xxxyyy x ",
111 [Fw] = " xxx U x yxxxyyy ",
112 [Fw2] = " xxx UU x yxxyyy ",
113 [Fw3] = " xxx UUU x yxyyy ",
114 [Bw] = " x U xxx yxyyy ",
115 [Bw2] = " x UU xxx yxxyyy ",
116 [Bw3] = " x UUU xxx yxxxyyy ",
141 117
142/***/ 118 [M] = " yx U xx UUU yxyyy ",
143/* Functions for permuting pieces (given in integer format) */ 119 [M2] = " yx UU xx UU xxxy ",
144/***/ 120 [M3] = " yx UUU xx U yxxxy ",
121 [S] = " x UUU xx U yyyx ",
122 [S2] = " x UU xx UU yyx ",
123 [S3] = " x U xx UUU yx ",
124 [E] = " U xx UUU xxyyy ",
125 [E2] = " UU xx UU xxyy ",
126 [E3] = " UUU xx U xxy ",
145 127
146int apply_move_ep_int(int move, int ep) { 128 [x] = " x ",
147 int a[12]; 129 [x2] = " xx ",
148 ep_int_to_array(ep, a); 130 [x3] = " xxx ",
149 apply_move_ep_array(move, a); 131 [y] = " y ",
150 return ep_array_to_int(a); 132 [y2] = " yy ",
151} 133 [y3] = " yyy ",
134 [z] = " yyy x y ",
135 [z2] = " yy xx ",
136 [z3] = " y x yyy "
137};
152 138
153int apply_move_epud_int(int move, int ep) { 139/* Transition tables, to be loaded up at the beginning */
154 int a[12]; 140static int epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
155 epud_int_to_array(ep, a); 141static int eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
156 apply_move_ep_array(move, a); 142static int eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8];
157 return epud_array_to_int(a); 143static int eofb_mtable[NMOVES][POW2TO11];
158} 144static int eorl_mtable[NMOVES][POW2TO11];
145static int eoud_mtable[NMOVES][POW2TO11];
146static int cp_mtable[NMOVES][FACTORIAL8];
147static int coud_mtable[NMOVES][POW3TO7];
148static int cofb_mtable[NMOVES][POW3TO7];
149static int corl_mtable[NMOVES][POW3TO7];
150static int cpos_mtable[NMOVES][FACTORIAL6];
159 151
160int apply_move_eprl_int(int move, int ep) {
161 int a[12];
162 eprl_int_to_array(ep, a);
163 apply_move_ep_array(move, a);
164 return eprl_array_to_int(a);
165}
166 152
167int apply_move_epfb_int(int move, int ep) { 153/* Local functions implementation ********************************************/
168 int a[12];
169 epfb_int_to_array(ep, a);
170 apply_move_ep_array(move, a);
171 return epfb_array_to_int(a);
172}
173 154
174int apply_move_epose_int(int move, int ep) { 155static Cube
175 int a[12]; 156apply_move_cubearray(Move m, Cube cube, PieceFilter f)
176 epose_int_to_array(ep, a); 157{
177 apply_move_ep_array(move, a); 158 /*init_moves();*/
178 return epose_array_to_int(a);
179}
180 159
181int apply_move_eposs_int(int move, int ep) { 160 CubeArray m_arr = {
182 int a[12]; 161 edge_cycle[m],
183 eposs_int_to_array(ep, a); 162 eofb_flipped[m],
184 apply_move_ep_array(move, a); 163 eorl_flipped[m],
185 return eposs_array_to_int(a); 164 eoud_flipped[m],
186} 165 corner_cycle[m],
166 coud_flipped[m],
167 corl_flipped[m],
168 cofb_flipped[m],
169 center_cycle[m]
170 };
187 171
188int apply_move_eposm_int(int move, int ep) { 172 return move_via_arrays(&m_arr, cube, f);
189 int a[12];
190 eposm_int_to_array(ep, a);
191 apply_move_ep_array(move, a);
192 return eposm_array_to_int(a);
193} 173}
194 174
195int apply_move_epe_int(int move, int ep) { 175/* Public functions **********************************************************/
196 int a[12];
197 epe_int_to_array(ep, a);
198 apply_move_ep_array(move, a);
199 return epe_array_to_int(a);
200}
201 176
202int apply_move_eps_int(int move, int ep) { 177Cube
203 int a[12]; 178apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a)
204 eps_int_to_array(ep, a); 179{
205 apply_move_ep_array(move, a); 180 Cube ret = {0};
206 return eps_array_to_int(a); 181 int i;
207}
208 182
209int apply_move_epm_int(int move, int ep) { 183 for (i = 0; i < alg->len; i++)
210 int a[12]; 184 if (alg->inv[i])
211 epm_int_to_array(ep, a); 185 ret = a ? apply_move(alg->move[i], ret) :
212 apply_move_ep_array(move, a); 186 apply_move_cubearray(alg->move[i], ret, f);
213 return epm_array_to_int(a);
214}
215 187
216int apply_move_emslices_int(int move, int e) { 188 ret = compose_filtered(c, inverse_cube(ret), f);
217 int a[12];
218 emslices_int_to_array(e, a);
219 apply_move_ep_array(move, a);
220 return emslices_array_to_int(a);
221}
222 189
223int apply_move_cp_int(int move, int cp) { 190 for (i = 0; i < alg->len; i++)
224 int a[8]; 191 if (!alg->inv[i])
225 cp_int_to_array(cp, a); 192 ret = a ? apply_move(alg->move[i], ret) :
226 apply_move_cp_array(move, a); 193 apply_move_cubearray(alg->move[i], ret, f);
227 return cp_array_to_int(a);
228}
229 194
230int apply_move_eofb_int(int move, int eo) { 195 return ret;
231 int a[12];
232 eo_11bits_to_array(eo, a);
233 apply_move_ep_array(move, a);
234 /* Change edge orientation */
235 if (move == F || move == F3) {
236 a[UF] = 1 - a[UF];
237 a[DF] = 1 - a[DF];
238 a[FR] = 1 - a[FR];
239 a[FL] = 1 - a[FL];
240 }
241 if (move == B || move == B3) {
242 a[UB] = 1 - a[UB];
243 a[DB] = 1 - a[DB];
244 a[BL] = 1 - a[BL];
245 a[BR] = 1 - a[BR];
246 }
247 return eo_array_to_11bits(a);
248} 196}
249 197
250int apply_move_eorl_int(int move, int eo) { 198Cube
251 int a[12]; 199apply_alg(Alg *alg, Cube cube)
252 eo_11bits_to_array(eo, a); 200{
253 apply_move_ep_array(move, a); 201 return apply_alg_generic(alg, cube, pf_all, true);
254 /* Change edge orientation */
255 if (move == R || move == R3) {
256 a[UR] = 1 - a[UR];
257 a[DR] = 1 - a[DR];
258 a[FR] = 1 - a[FR];
259 a[BR] = 1 - a[BR];
260 }
261 if (move == L || move == L3) {
262 a[UL] = 1 - a[UL];
263 a[DL] = 1 - a[DL];
264 a[FL] = 1 - a[FL];
265 a[BL] = 1 - a[BL];
266 }
267 return eo_array_to_11bits(a);
268} 202}
269 203
270int apply_move_eoud_int(int move, int eo) { 204Cube
271 int a[12]; 205apply_move(Move m, Cube cube)
272 eo_11bits_to_array(eo, a); 206{
273 apply_move_ep_array(move, a); 207 /*init_moves();*/
274 /* Change edge orientation */
275 if (move == U || move == U3) {
276 a[UF] = 1 - a[UF];
277 a[UL] = 1 - a[UL];
278 a[UB] = 1 - a[UB];
279 a[UR] = 1 - a[UR];
280 }
281 if (move == D || move == D3) {
282 a[DF] = 1 - a[DF];
283 a[DL] = 1 - a[DL];
284 a[DB] = 1 - a[DB];
285 a[DR] = 1 - a[DR];
286 }
287 return eo_array_to_11bits(a);
288}
289 208
290int apply_move_coud_int(int move, int co) { 209 return (Cube) {
291 int a[8]; 210 .epose = epose_mtable[m][cube.epose],
292 co_7trits_to_array(co, a); 211 .eposs = eposs_mtable[m][cube.eposs],
293 apply_move_cp_array(move, a); 212 .eposm = eposm_mtable[m][cube.eposm],
294 /* Change corner orientation */ 213 .eofb = eofb_mtable[m][cube.eofb],
295 if (move == R || move == R3) { 214 .eorl = eorl_mtable[m][cube.eorl],
296 a[UFR] = (a[UFR] + 2) % 3; 215 .eoud = eoud_mtable[m][cube.eoud],
297 a[UBR] = (a[UBR] + 1) % 3; 216 .coud = coud_mtable[m][cube.coud],
298 a[DBR] = (a[DBR] + 2) % 3; 217 .cofb = cofb_mtable[m][cube.cofb],
299 a[DFR] = (a[DFR] + 1) % 3; 218 .corl = corl_mtable[m][cube.corl],
300 } 219 .cp = cp_mtable[m][cube.cp],
301 if (move == L || move == L3) { 220 .cpos = cpos_mtable[m][cube.cpos]
302 a[UBL] = (a[UBL] + 2) % 3; 221 };
303 a[UFL] = (a[UFL] + 1) % 3;
304 a[DFL] = (a[DFL] + 2) % 3;
305 a[DBL] = (a[DBL] + 1) % 3;
306 }
307 if (move == F || move == F3) {
308 a[UFL] = (a[UFL] + 2) % 3;
309 a[UFR] = (a[UFR] + 1) % 3;
310 a[DFR] = (a[DFR] + 2) % 3;
311 a[DFL] = (a[DFL] + 1) % 3;
312 }
313 if (move == B || move == B3) {
314 a[UBR] = (a[UBR] + 2) % 3;
315 a[UBL] = (a[UBL] + 1) % 3;
316 a[DBL] = (a[DBL] + 2) % 3;
317 a[DBR] = (a[DBR] + 1) % 3;
318 }
319 return co_array_to_7trits(a);
320} 222}
321 223
322int apply_move_cofb_int(int move, int co) { 224static bool
323 int a[8]; 225read_mtables_file()
324 co_7trits_to_array(co, a); 226{
325 apply_move_cp_array(move, a); 227 init_env();
326 /* Change corner orientation */
327 if (move == R || move == R3) {
328 a[UFR] = (a[UFR] + 1) % 3;
329 a[UBR] = (a[UBR] + 2) % 3;
330 a[DBR] = (a[DBR] + 1) % 3;
331 a[DFR] = (a[DFR] + 2) % 3;
332 }
333 if (move == L || move == L3) {
334 a[UBL] = (a[UBL] + 1) % 3;
335 a[UFL] = (a[UFL] + 2) % 3;
336 a[DFL] = (a[DFL] + 1) % 3;
337 a[DBL] = (a[DBL] + 2) % 3;
338 }
339 if (move == U || move == U3) {
340 a[UFL] = (a[UFL] + 1) % 3;
341 a[UFR] = (a[UFR] + 2) % 3;
342 a[UBL] = (a[UBL] + 2) % 3;
343 a[UBR] = (a[UBR] + 1) % 3;
344 }
345 if (move == D || move == D3) {
346 a[DFL] = (a[DFL] + 2) % 3;
347 a[DFR] = (a[DFR] + 1) % 3;
348 a[DBL] = (a[DBL] + 1) % 3;
349 a[DBR] = (a[DBR] + 2) % 3;
350 }
351 return co_array_to_7trits(a);
352}
353 228
354int apply_move_corl_int(int move, int co) { 229 FILE *f;
355 int a[8]; 230 char fname[strlen(tabledir)+20];
356 co_7trits_to_array(co, a); 231 int m, b = sizeof(int);
357 apply_move_cp_array(move, a); 232 bool r = true;
358 /* Change corner orientation */
359 if (move == F || move == F3) {
360 a[UFR] = (a[UFR] + 2) % 3;
361 a[UFL] = (a[UFL] + 1) % 3;
362 a[DFL] = (a[DFL] + 2) % 3;
363 a[DFR] = (a[DFR] + 1) % 3;
364 }
365 if (move == B || move == B3) {
366 a[UBL] = (a[UBL] + 2) % 3;
367 a[UBR] = (a[UBR] + 1) % 3;
368 a[DBR] = (a[DBR] + 2) % 3;
369 a[DBL] = (a[DBL] + 1) % 3;
370 }
371 if (move == U || move == U3) {
372 a[UFL] = (a[UFL] + 2) % 3;
373 a[UFR] = (a[UFR] + 1) % 3;
374 a[UBL] = (a[UBL] + 1) % 3;
375 a[UBR] = (a[UBR] + 2) % 3;
376 }
377 if (move == D || move == D3) {
378 a[DFL] = (a[DFL] + 1) % 3;
379 a[DFR] = (a[DFR] + 2) % 3;
380 a[DBL] = (a[DBL] + 2) % 3;
381 a[DBR] = (a[DBR] + 1) % 3;
382 }
383 return co_array_to_7trits(a);
384}
385
386 233
234 /* Table sizes, used for reading and writing files */
235 uint64_t me[11] = {
236 [0] = FACTORIAL12/FACTORIAL8,
237 [1] = FACTORIAL12/FACTORIAL8,
238 [2] = FACTORIAL12/FACTORIAL8,
239 [3] = POW2TO11,
240 [4] = POW2TO11,
241 [5] = POW2TO11,
242 [6] = FACTORIAL8,
243 [7] = POW3TO7,
244 [8] = POW3TO7,
245 [9] = POW3TO7,
246 [10] = FACTORIAL6
247 };
387 248
388/* Initialize transition tables */ 249 strcpy(fname, tabledir);
250 strcat(fname, "/mtables");
389 251
390void init_epud_transition_table() { 252 if ((f = fopen(fname, "rb")) == NULL)
391 for (int i = 0; i < factorial8; i++) 253 return false;
392 for (int j = 0; j < 19; j++)
393 if (move_mask_drud & (1 << j))
394 epud_transition_table[i][j] = apply_move_epud_int(j, i);
395}
396 254
397void init_eprl_transition_table() { 255 for (m = 0; m < NMOVES; m++) {
398 for (int i = 0; i < factorial8; i++) 256 r = r && fread(epose_mtable[m], b, me[0], f) == me[0];
399 for (int j = 0; j < 19; j++) 257 r = r && fread(eposs_mtable[m], b, me[1], f) == me[1];
400 if (move_mask_drrl & (1 << j)) 258 r = r && fread(eposm_mtable[m], b, me[2], f) == me[2];
401 eprl_transition_table[i][j] = apply_move_eprl_int(j, i); 259 r = r && fread(eofb_mtable[m], b, me[3], f) == me[3];
402} 260 r = r && fread(eorl_mtable[m], b, me[4], f) == me[4];
261 r = r && fread(eoud_mtable[m], b, me[5], f) == me[5];
262 r = r && fread(cp_mtable[m], b, me[6], f) == me[6];
263 r = r && fread(coud_mtable[m], b, me[7], f) == me[7];
264 r = r && fread(corl_mtable[m], b, me[8], f) == me[8];
265 r = r && fread(cofb_mtable[m], b, me[9], f) == me[9];
266 r = r && fread(cpos_mtable[m], b, me[10], f) == me[10];
267 }
403 268
404void init_epfb_transition_table() { 269 fclose(f);
405 for (int i = 0; i < factorial8; i++) 270 return r;
406 for (int j = 0; j < 19; j++)
407 if (move_mask_drfb & (1 << j))
408 epfb_transition_table[i][j] = apply_move_epfb_int(j, i);
409} 271}
410 272
411void init_epose_transition_table() { 273static bool
412 for (int i = 0; i < binom12on4; i++) 274write_mtables_file()
413 for (int j = 0; j < 19; j++) 275{
414 epose_transition_table[i][j] = apply_move_epose_int(j, i); 276 init_env();
415}
416 277
417void init_eposs_transition_table() { 278 FILE *f;
418 for (int i = 0; i < binom12on4; i++) 279 char fname[strlen(tabledir)+20];
419 for (int j = 0; j < 19; j++) 280 int m, b = sizeof(int);
420 eposs_transition_table[i][j] = apply_move_eposs_int(j, i); 281 bool r = true;
421}
422 282
423void init_eposm_transition_table() { 283 /* Table sizes, used for reading and writing files */
424 for (int i = 0; i < binom12on4; i++) 284 uint64_t me[11] = {
425 for (int j = 0; j < 19; j++) 285 [0] = FACTORIAL12/FACTORIAL8,
426 eposm_transition_table[i][j] = apply_move_eposm_int(j, i); 286 [1] = FACTORIAL12/FACTORIAL8,
427} 287 [2] = FACTORIAL12/FACTORIAL8,
288 [3] = POW2TO11,
289 [4] = POW2TO11,
290 [5] = POW2TO11,
291 [6] = FACTORIAL8,
292 [7] = POW3TO7,
293 [8] = POW3TO7,
294 [9] = POW3TO7,
295 [10] = FACTORIAL6
296 };
428 297
429void init_epe_transition_table() { 298 strcpy(fname, tabledir);
430 for (int i = 0; i < factorial4; i++) { 299 strcat(fname, "/mtables");
431 for (int j = 0; j < 19; j++)
432 if (move_mask_drud & (1 << j))
433 epe_transition_table[i][j] = apply_move_epe_int(j, i);
434 }
435}
436 300
437void init_eps_transition_table() { 301 if ((f = fopen(fname, "wb")) == NULL)
438 for (int i = 0; i < factorial4; i++) { 302 return false;
439 for (int j = 0; j < 19; j++)
440 if (move_mask_drfb & (1 << j))
441 eps_transition_table[i][j] = apply_move_eps_int(j, i);
442 }
443}
444 303
445void init_epm_transition_table() { 304 for (m = 0; m < NMOVES; m++) {
446 for (int i = 0; i < factorial4; i++) { 305 r = r && fwrite(epose_mtable[m], b, me[0], f) == me[0];
447 for (int j = 0; j < 19; j++) 306 r = r && fwrite(eposs_mtable[m], b, me[1], f) == me[1];
448 if (move_mask_drrl & (1 << j)) 307 r = r && fwrite(eposm_mtable[m], b, me[2], f) == me[2];
449 epm_transition_table[i][j] = apply_move_epm_int(j, i); 308 r = r && fwrite(eofb_mtable[m], b, me[3], f) == me[3];
450 } 309 r = r && fwrite(eorl_mtable[m], b, me[4], f) == me[4];
451} 310 r = r && fwrite(eoud_mtable[m], b, me[5], f) == me[5];
311 r = r && fwrite(cp_mtable[m], b, me[6], f) == me[6];
312 r = r && fwrite(coud_mtable[m], b, me[7], f) == me[7];
313 r = r && fwrite(corl_mtable[m], b, me[8], f) == me[8];
314 r = r && fwrite(cofb_mtable[m], b, me[9], f) == me[9];
315 r = r && fwrite(cpos_mtable[m], b, me[10], f) == me[10];
316 }
452 317
453void init_emslices_transition_table() { 318 fclose(f);
454 for (int i = 0; i < binom12on4*binom8on4; i++) { 319 return r;
455 for (int j = 0; j < 19; j++)
456 emslices_transition_table[i][j] = apply_move_emslices_int(j, i);
457 }
458} 320}
459 321
460void init_cp_transition_table() { 322bool
461 for (int i = 0; i < factorial8; i++) 323commute(Move m1, Move m2)
462 for (int j = 0; j < 19; j++) 324{
463 cp_transition_table[i][j] = apply_move_cp_int(j, i); 325 static bool initialized = false;
464} 326 static bool commute_aux[NMOVES][NMOVES];
465 327
466void init_eofb_transition_table() { 328 if (!initialized) {
467 for (int i = 0; i < pow2to11; i++) 329 Cube c1, c2;
468 for (int j = 0; j < 19; j++) 330 int i, j;
469 eofb_transition_table[i][j] = apply_move_eofb_int(j, i);
470}
471 331
472void init_eorl_transition_table() { 332 for (i = 0; i < NMOVES; i++) {
473 for (int i = 0; i < pow2to11; i++) 333 for (j = 0; j < NMOVES; j++) {
474 for (int j = 0; j < 19; j++) 334 c1 = apply_move(i, apply_move(j, (Cube){0}));
475 eorl_transition_table[i][j] = apply_move_eorl_int(j, i); 335 c2 = apply_move(j, apply_move(i, (Cube){0}));
476} 336 commute_aux[i][j] = equal(c1, c2) && i && j;
337 }
338 }
477 339
478void init_eoud_transition_table() { 340 initialized = true;
479 for (int i = 0; i < pow2to11; i++) 341 }
480 for (int j = 0; j < 19; j++)
481 eoud_transition_table[i][j] = apply_move_eoud_int(j, i);
482}
483 342
484void init_coud_transition_table() { 343 return commute_aux[m1][m2];
485 for (int i = 0; i < pow3to7; i++)
486 for (int j = 0; j < 19; j++ )
487 coud_transition_table[i][j] = apply_move_coud_int(j, i);
488} 344}
489 345
490void init_cofb_transition_table() { 346bool
491 for (int i = 0; i < pow3to7; i++) 347possible_next(Move m1, Move m2, Move m3)
492 for (int j = 0; j < 19; j++ ) 348{
493 cofb_transition_table[i][j] = apply_move_cofb_int(j, i); 349 static bool initialized = false;
494} 350 static bool paux[NMOVES][NMOVES][NMOVES];
351
352 if (!initialized) {
353 int i, j, k;
354 bool p, q, c;
495 355
496void init_corl_transition_table() { 356 for (i = 0; i < NMOVES; i++) {
497 for (int i = 0; i < pow3to7; i++) 357 for (j = 0; j < NMOVES; j++) {
498 for (int j = 0; j < 19; j++ ) 358 for (k = 0; k < NMOVES; k++) {
499 corl_transition_table[i][j] = apply_move_corl_int(j, i); 359 p = j && base_move(j) == base_move(k);
360 q = i && base_move(i) == base_move(k);
361 c = commute(i, j);
362 paux[i][j][k] = !(p || (c && q));
363 }
364 }
365 }
366
367 initialized = true;
368 }
369
370 return paux[m1][m2][m3];
500} 371}
501 372
502void init_transition_table() { 373void
503 init_epud_transition_table(); 374init_moves() {
504 init_eprl_transition_table(); 375 static bool initialized = false;
505 init_epfb_transition_table(); 376 if (initialized)
506 init_epose_transition_table(); 377 return;
507 init_eposs_transition_table(); 378 initialized = true;
508 init_eposm_transition_table(); 379
509 init_epe_transition_table(); 380 Cube c;
510 init_eps_transition_table(); 381 CubeArray arrs;
511 init_epm_transition_table(); 382 int i;
512 init_emslices_transition_table(); 383 unsigned int ui;
513 init_cp_transition_table(); 384 Move m;
514 init_eofb_transition_table(); 385 Alg *equiv_alg[NMOVES];
515 init_eorl_transition_table(); 386
516 init_eoud_transition_table(); 387 for (i = 0; i < NMOVES; i++)
517 init_coud_transition_table(); 388 equiv_alg[i] = new_alg(equiv_alg_string[i]);
518 init_cofb_transition_table(); 389
519 init_corl_transition_table(); 390 /* Generate all move cycles and flips; I do this regardless */
391 for (i = 0; i < NMOVES; i++) {
392 if (i == U || i == x || i == y)
393 continue;
394
395 c = apply_alg_generic(equiv_alg[i], (Cube){0}, pf_all, false);
396
397 arrs = (CubeArray) {
398 edge_cycle[i],
399 eofb_flipped[i],
400 eorl_flipped[i],
401 eoud_flipped[i],
402 corner_cycle[i],
403 coud_flipped[i],
404 corl_flipped[i],
405 cofb_flipped[i],
406 center_cycle[i]
407 };
408 cube_to_arrays(c, &arrs, pf_all);
409 }
410
411 if (read_mtables_file())
412 return;
413
414 fprintf(stderr, "Cannot load %s, generating it\n", "mtables");
415
416 /* Initialize transition tables */
417 for (m = 0; m < NMOVES; m++) {
418 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
419 c = (Cube){ .epose = ui };
420 c = apply_move_cubearray(m, c, pf_e);
421 epose_mtable[m][ui] = c.epose;
422
423 c = (Cube){ .eposs = ui };
424 c = apply_move_cubearray(m, c, pf_s);
425 eposs_mtable[m][ui] = c.eposs;
426
427 c = (Cube){ .eposm = ui };
428 c = apply_move_cubearray(m, c, pf_m);
429 eposm_mtable[m][ui] = c.eposm;
430 }
431 for (ui = 0; ui < POW2TO11; ui++ ) {
432 c = (Cube){ .eofb = ui };
433 c = apply_move_cubearray(m, c, pf_eo);
434 eofb_mtable[m][ui] = c.eofb;
435
436 c = (Cube){ .eorl = ui };
437 c = apply_move_cubearray(m, c, pf_eo);
438 eorl_mtable[m][ui] = c.eorl;
439
440 c = (Cube){ .eoud = ui };
441 c = apply_move_cubearray(m, c, pf_eo);
442 eoud_mtable[m][ui] = c.eoud;
443 }
444 for (ui = 0; ui < POW3TO7; ui++) {
445 c = (Cube){ .coud = ui };
446 c = apply_move_cubearray(m, c, pf_co);
447 coud_mtable[m][ui] = c.coud;
448
449 c = (Cube){ .corl = ui };
450 c = apply_move_cubearray(m, c, pf_co);
451 corl_mtable[m][ui] = c.corl;
452
453 c = (Cube){ .cofb = ui };
454 c = apply_move_cubearray(m, c, pf_co);
455 cofb_mtable[m][ui] = c.cofb;
456 }
457 for (ui = 0; ui < FACTORIAL8; ui++) {
458 c = (Cube){ .cp = ui };
459 c = apply_move_cubearray(m, c, pf_cp);
460 cp_mtable[m][ui] = c.cp;
461 }
462 for (ui = 0; ui < FACTORIAL6; ui++) {
463 c = (Cube){ .cpos = ui };
464 c = apply_move_cubearray(m, c, pf_cpos);
465 cpos_mtable[m][ui] = c.cpos;
466 }
467 }
468
469 if (!write_mtables_file())
470 fprintf(stderr, "Error writing mtables\n");
471
472 for (i = 0; i < NMOVES; i++)
473 free_alg(equiv_alg[i]);
520} 474}
521 475
diff --git a/src/moves.h b/src/moves.h
index 99d0ec3..082a080 100644
--- a/src/moves.h
+++ b/src/moves.h
@@ -1,83 +1,16 @@
1#include "utils.h" 1#ifndef MOVES_H
2#define MOVES_H
2 3
3/* Bitmask that define certain movesets. */ 4#include "alg.h"
4#define move_mask_all 524287 /* Reverse 1111111111111111111 */ 5#include "cube.h"
5#define move_mask_eofb 155647 /* Reverse 1111111111111010010 */ 6#include "env.h"
6#define move_mask_eorl 518527 /* Reverse 1111111010101111111 */
7#define move_mask_eoud 524197 /* Reverse 1010010111111111111 */
8#define move_mask_drud 149887 /* Reverse 1111111010010010010 */
9#define move_mask_drfb 518437 /* Reverse 1010010010010111111 */
10#define move_mask_drrl 155557 /* Reverse 1010010111111010010 */
11#define move_mask_htr 149797 /* Reverse 1010010010010010010 */
12 7
13extern int possible_next[19][19]; 8Cube apply_alg(Alg *alg, Cube cube);
9Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a);
10Cube apply_move(Move m, Cube cube);
11bool commute(Move m1, Move m2);
12bool possible_next(Move m1, Move m2, Move m3);
14 13
15int parallel(int m1, int m2); 14void init_moves();
16void init_possible_next();
17
18/* Transition tables */
19extern int eofb_transition_table[pow2to11][19];
20extern int eorl_transition_table[pow2to11][19];
21extern int eoud_transition_table[pow2to11][19];
22extern int coud_transition_table[pow3to7][19];
23extern int cofb_transition_table[pow3to7][19];
24extern int corl_transition_table[pow3to7][19];
25extern int epud_transition_table[factorial8][19];
26extern int epfb_transition_table[factorial8][19];
27extern int eprl_transition_table[factorial8][19];
28extern int epose_transition_table[binom12on4][19];
29extern int eposs_transition_table[binom12on4][19];
30extern int eposm_transition_table[binom12on4][19];
31extern int epe_transition_table[factorial4][19];
32extern int eps_transition_table[factorial4][19];
33extern int epm_transition_table[factorial4][19];
34extern int emslices_transition_table[binom12on4*binom8on4][19];
35extern int cp_transition_table[factorial8][19];
36
37
38/* Functions for permuting pieces (given in array format) */
39
40void apply_move_ep_array(int move, int ep[12]);
41void apply_move_cp_array(int move, int cp[8]);
42
43/* Functions for permuting pieces (given in integer format) */
44
45int apply_move_ep_int(int move, int ep);
46int apply_move_epud_int(int move, int ep);
47int apply_move_epfb_int(int move, int ep);
48int apply_move_eprl_int(int move, int ep);
49int apply_move_epose_int(int move, int ep);
50int apply_move_eposs_int(int move, int ep);
51int apply_move_eposm_int(int move, int ep);
52int apply_move_epe_int(int move, int ep);
53int apply_move_eps_int(int move, int ep);
54int apply_move_epm_int(int move, int ep);
55int apply_move_cp_int(int move, int cp);
56int apply_move_eofb_int(int move, int eo);
57int apply_move_eorl_int(int move, int eo);
58int apply_move_eoud_int(int move, int eo);
59int apply_move_coud_int(int move, int co);
60int apply_move_cofb_int(int move, int co);
61int apply_move_corl_int(int move, int co);
62
63/* Initialize transition tables */
64
65void init_epud_transition_table();
66void init_epfb_transition_table();
67void init_eprl_transition_table();
68void init_epose_transition_table();
69void init_eposs_transition_table();
70void init_eposm_transition_table();
71void init_epe_transition_table();
72void init_eps_transition_table();
73void init_epm_transition_table();
74void init_cp_transition_table();
75void init_eofb_transition_table();
76void init_eorl_transition_table();
77void init_eoud_transition_table();
78void init_coud_transition_table();
79void init_cofb_transition_table();
80void init_corl_transition_table();
81
82void init_transition_table();
83 15
16#endif
diff --git a/src/pf.c b/src/pf.c
new file mode 100644
index 0000000..34be4fd
--- /dev/null
+++ b/src/pf.c
@@ -0,0 +1,80 @@
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};
diff --git a/src/pf.h b/src/pf.h
new file mode 100644
index 0000000..85ee1eb
--- /dev/null
+++ b/src/pf.h
@@ -0,0 +1,18 @@
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;
17
18#endif
diff --git a/src/pruning.c b/src/pruning.c
new file mode 100644
index 0000000..bc9dd59
--- /dev/null
+++ b/src/pruning.c
@@ -0,0 +1,271 @@
1#include "pruning.h"
2
3static void genptable_bfs(PruneData *pd, int d, Move *ms);
4static void genptable_branch(PruneData *pd, uint64_t i, int d, Move *m);
5static void ptable_update(PruneData *pd, Cube cube, int m);
6static void ptable_update_index(PruneData *pd, uint64_t ind, int m);
7static int ptableval_index(PruneData *pd, uint64_t ind);
8static bool read_ptable_file(PruneData *pd);
9static bool write_ptable_file(PruneData *pd);
10
11PruneData
12pd_eofb_HTM = {
13 .filename = "pt_eofb_HTM",
14 .coord = &coord_eofb,
15 .moveset = moveset_HTM,
16};
17
18PruneData
19pd_coud_HTM = {
20 .filename = "pt_coud_HTM",
21 .coord = &coord_coud,
22 .moveset = moveset_HTM,
23};
24
25PruneData
26pd_cornershtr_HTM = {
27 .filename = "pt_cornershtr_HTM",
28 .coord = &coord_cornershtr,
29 .moveset = moveset_HTM,
30};
31
32PruneData
33pd_corners_HTM = {
34 .filename = "pt_corners_HTM",
35 .coord = &coord_corners,
36 .moveset = moveset_HTM,
37};
38
39PruneData
40pd_drud_sym16_HTM = {
41 .filename = "pt_drud_sym16_HTM",
42 .coord = &coord_drud_sym16,
43 .moveset = moveset_HTM,
44};
45
46PruneData
47pd_drud_eofb = {
48 .filename = "pt_drud_eofb",
49 .coord = &coord_drud_eofb,
50 .moveset = moveset_eofb,
51};
52
53PruneData
54pd_drudfin_noE_sym16_drud = {
55 .filename = "pt_drudfin_noE_sym16_drud",
56 .coord = &coord_drudfin_noE_sym16,
57 .moveset = moveset_drud,
58};
59
60PruneData
61pd_htr_drud = {
62 .filename = "pt_htr_drud",
63 .coord = &coord_htr_drud,
64 .moveset = moveset_drud,
65};
66
67PruneData
68pd_htrfin_htr = {
69 .filename = "pt_htrfin_htr",
70 .coord = &coord_htrfin,
71 .moveset = moveset_htr,
72};
73
74PruneData
75pd_khuge_HTM = {
76 .filename = "pt_khuge_HTM",
77 .coord = &coord_khuge,
78 .moveset = moveset_HTM,
79};
80
81void
82genptable(PruneData *pd)
83{
84 Move ms[NMOVES];
85 int d;
86 uint64_t j, oldn;
87
88 if (pd->generated)
89 return;
90
91 /* TODO: check if memory is enough, otherwise maybe exit gracefully? */
92 pd->ptable = malloc(ptablesize(pd) * sizeof(uint8_t));
93
94 if (read_ptable_file(pd)) {
95 pd->generated = true;
96 return;
97 }
98 pd->generated = true;
99
100 fprintf(stderr, "Cannot load %s, generating it\n", pd->filename);
101
102 moveset_to_list(pd->moveset, ms);
103
104 /* We use 4 bits per value, so any distance >= 15 is set to 15 */
105 for (j = 0; j < pd->coord->max; j++)
106 ptable_update_index(pd, j, 15);
107
108 for (j = 0; j < pd->coord->max; j++)
109 if (ptableval_index(pd, j) != 15) {
110 printf("Error, non-max value at index %lu!\n", j);
111 break;
112 }
113 printf("Table set, ready to start\n");
114
115 ptable_update(pd, (Cube){0}, 0);
116 pd->n = 1;
117 oldn = 0;
118 fprintf(stderr, "Depth %d done, generated %lu\t(%lu/%lu)\n",
119 0, pd->n - oldn, pd->n, pd->coord->max);
120 oldn = 1;
121 for (d = 0; d < 15 && pd->n < pd->coord->max; d++) {
122 genptable_bfs(pd, d, ms);
123 fprintf(stderr, "Depth %d done, generated %lu\t(%lu/%lu)\n",
124 d+1, pd->n - oldn, pd->n, pd->coord->max);
125 oldn = pd->n;
126 }
127
128 if (!write_ptable_file(pd))
129 fprintf(stderr, "Error writing ptable file\n");
130}
131
132static void
133genptable_bfs(PruneData *pd, int d, Move *ms)
134{
135 uint64_t i;
136
137 for (i = 0; i < pd->coord->max; i++)
138 if (ptableval_index(pd, i) == d)
139 genptable_branch(pd, i, d, ms);
140}
141
142static void
143genptable_branch(PruneData *pd, uint64_t ind, int d, Move *ms)
144{
145 int i, j;
146 Cube ci, cc, c;
147
148 /*
149 * This is the only line of the whole program where we REALLY need an
150 * anti-indexer function. We could get rid of it if only we could save
151 * a cube object for each index value as we go, but then we would need
152 * an incredible amount of memory to generate each ptable: assuming
153 * fields in struct cube are 32 bit ints that would take 88 times the
154 * memory of the table to be generated, more than 120Gb for
155 * ptable_khuge for example!
156 */
157 ci = pd->coord->cube(ind);
158
159 for (i = 0; i < pd->coord->ntrans; i++) {
160 /* For simplicity trans[] is NULL when ntrans = 1 */
161 c = i == 0 ? ci :
162 apply_trans(pd->coord->trans[i], ci);
163 for (j = 0; ms[j] != NULLMOVE; j++) {
164 cc = apply_move(ms[j], c);
165 if (ptableval(pd, cc) > d+1)
166 ptable_update(pd, cc, d+1);
167 }
168 }
169}
170
171void
172print_ptable(PruneData *pd)
173{
174 uint64_t i, a[16];
175
176 for (i = 0; i < 16; i++)
177 a[i] = 0;
178
179 if (!pd->generated)
180 genptable(pd);
181
182 for (i = 0; i < pd->coord->max; i++)
183 a[ptableval_index(pd, i)]++;
184
185 fprintf(stderr, "Values for table %s\n", pd->filename);
186 for (i = 0; i < 16; i++)
187 printf("%2lu\t%10lu\n", i, a[i]);
188}
189
190uint64_t
191ptablesize(PruneData *pd)
192{
193 return (pd->coord->max + 1) / 2;
194}
195
196static void
197ptable_update(PruneData *pd, Cube cube, int n)
198{
199 uint64_t ind = pd->coord->index(cube);
200 ptable_update_index(pd, ind, n);
201}
202
203static void
204ptable_update_index(PruneData *pd, uint64_t ind, int n)
205{
206 uint8_t oldval2 = pd->ptable[ind/2];
207 int other = (ind % 2) ? oldval2 % 16 : oldval2 / 16;
208
209 pd->ptable[ind/2] = (ind % 2) ? 16*n + other : 16*other + n;
210 pd->n++;
211}
212
213int
214ptableval(PruneData *pd, Cube cube)
215{
216 return ptableval_index(pd, pd->coord->index(cube));
217}
218
219static int
220ptableval_index(PruneData *pd, uint64_t ind)
221{
222 if (!pd->generated)
223 genptable(pd);
224
225 return (ind % 2) ? pd->ptable[ind/2] / 16 : pd->ptable[ind/2] % 16;
226}
227
228static bool
229read_ptable_file(PruneData *pd)
230{
231 init_env();
232
233 FILE *f;
234 char fname[strlen(tabledir)+100];
235 uint64_t r;
236
237 strcpy(fname, tabledir);
238 strcat(fname, "/");
239 strcat(fname, pd->filename);
240
241 if ((f = fopen(fname, "rb")) == NULL)
242 return false;
243
244 r = fread(pd->ptable, sizeof(uint8_t), ptablesize(pd), f);
245 fclose(f);
246
247 return r == ptablesize(pd);
248}
249
250static bool
251write_ptable_file(PruneData *pd)
252{
253 init_env();
254
255 FILE *f;
256 char fname[strlen(tabledir)+100];
257 uint64_t written;
258
259 strcpy(fname, tabledir);
260 strcat(fname, "/");
261 strcat(fname, pd->filename);
262
263 if ((f = fopen(fname, "wb")) == NULL)
264 return false;
265
266 written = fwrite(pd->ptable, sizeof(uint8_t), ptablesize(pd), f);
267 fclose(f);
268
269 return written == ptablesize(pd);
270}
271
diff --git a/src/pruning.h b/src/pruning.h
new file mode 100644
index 0000000..631ee3a
--- /dev/null
+++ b/src/pruning.h
@@ -0,0 +1,23 @@
1#ifndef PRUNING_H
2#define PRUNING_H
3
4#include "symcoord.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_khuge_HTM;
16
17void genptable(PruneData *pd);
18void print_ptable(PruneData *pd);
19uint64_t ptablesize(PruneData *pd);
20int ptableval(PruneData *pd, Cube cube);
21
22#endif
23
diff --git a/src/pruning_tables.c b/src/pruning_tables.c
deleted file mode 100644
index 8936b99..0000000
--- a/src/pruning_tables.c
+++ /dev/null
@@ -1,483 +0,0 @@
1#include <stdint.h>
2#include "pruning_tables.h"
3#include "moves.h"
4
5/* The data contained in e.g. eofb pruning table is the same that is contained
6 * in eolr pruning table and so on. For small tables the memory wasted is not
7 * too much and it makes things easier. I may change this when I implement
8 * bigger tables. */
9int eofb_pruning_table[pow2to11];
10int eorl_pruning_table[pow2to11];
11int eoud_pruning_table[pow2to11];
12int coud_pruning_table[pow3to7];
13int cofb_pruning_table[pow3to7];
14int corl_pruning_table[pow3to7];
15int cp_pruning_table[factorial8];
16
17int eorl_from_eofb_pruning_table[pow2to11];
18int eoud_from_eofb_pruning_table[pow2to11];
19int eoud_from_eorl_pruning_table[pow2to11];
20int eofb_from_eorl_pruning_table[pow2to11];
21int eofb_from_eoud_pruning_table[pow2to11];
22int eorl_from_eoud_pruning_table[pow2to11];
23
24int coud_from_eofb_pruning_table[pow3to7];
25int coud_from_eorl_pruning_table[pow3to7];
26int cofb_from_eorl_pruning_table[pow3to7];
27int cofb_from_eoud_pruning_table[pow3to7];
28int corl_from_eoud_pruning_table[pow3to7];
29int corl_from_eofb_pruning_table[pow3to7];
30
31int cp_drud_pruning_table[factorial8];
32int cp_drfb_pruning_table[factorial8];
33int cp_drrl_pruning_table[factorial8];
34int epud_pruning_table[factorial8];
35int epfb_pruning_table[factorial8];
36int eprl_pruning_table[factorial8];
37
38int cp_htr_pruning_table[factorial8];
39
40int cpud_to_htr_pruning_table[factorial8];
41int cpfb_to_htr_pruning_table[factorial8];
42int cprl_to_htr_pruning_table[factorial8];
43
44
45/* About 1Mb each */
46int8_t eofb_epose_pruning_table[pow2to11][binom12on4];
47int8_t eorl_eposs_pruning_table[pow2to11][binom12on4];
48int8_t eoud_eposm_pruning_table[pow2to11][binom12on4];
49
50/* About 4.5Mb each */
51int8_t eofb_coud_pruning_table[pow2to11][pow3to7];
52int8_t eofb_corl_pruning_table[pow2to11][pow3to7];
53int8_t eorl_coud_pruning_table[pow2to11][pow3to7];
54int8_t eorl_cofb_pruning_table[pow2to11][pow3to7];
55int8_t eoud_cofb_pruning_table[pow2to11][pow3to7];
56int8_t eoud_corl_pruning_table[pow2to11][pow3to7];
57
58/* About 1Mb each */
59int8_t coud_epose_from_eofb_pruning_table[pow3to7][binom12on4];
60int8_t cofb_eposs_from_eorl_pruning_table[pow3to7][binom12on4];
61int8_t corl_eposm_from_eoud_pruning_table[pow3to7][binom12on4];
62int8_t coud_epose_from_eorl_pruning_table[pow3to7][binom12on4];
63int8_t cofb_eposs_from_eoud_pruning_table[pow3to7][binom12on4];
64int8_t corl_eposm_from_eofb_pruning_table[pow3to7][binom12on4];
65
66
67/* Firs one is 88Mb, second one is 71Mb */
68int8_t cp_co_pruning_table[factorial8][pow3to7];
69int8_t triple_eo_pruning_table[pow2to11][binom12on4*binom8on4];
70
71int initialized_small = 0;
72int initialized_directdr = 0;
73int initialized_drfromeo = 0;
74int initialized_huge = 0;
75
76void init_single_table(int n, int t_tab[][19], int p_tab[n], int mask) {
77 int state[n];
78 state[0] = 0; /* 0 should always be the solved state. */
79 p_tab[0] = 0;
80 int state_count = 1;
81 for (int i = 0; i < state_count; i++) {
82 for (int m = 1; m < 19; m++) {
83 int next = t_tab[state[i]][m];
84 if (mask & (1<<m) && !p_tab[next] && next) {
85 p_tab[next] = p_tab[state[i]] + 1;
86 state[state_count++] = next;
87 }
88 }
89 }
90}
91
92/* Similar to single table, but specific to "cp to htr".
93 * The idea is that we are considering the distance not necessarily to the
94 * solved state, but to any state that is either solved or reachable from
95 * cp_pruning_table. */
96void init_cptohtr_table(int n, int t_tab[][19], int p_tab[n], int mask) {
97
98 for (int i = 0; i < n; i++)
99 p_tab[i] = 21;
100
101 /* List of htr states */
102 int good[n]; good[0] = 0;
103 int good_count = 1;
104 for (int i = 0; i < n; i++)
105 if (cp_htr_pruning_table[i])
106 good[good_count++] = i;
107
108 /* Init pruning table starting from each possible state */
109 int state[n];
110 for (int j = 0; j < good_count; j++) {
111 state[0] = good[j];
112 p_tab[state[0]] = 0;
113 int state_count = 1;
114 for (int i = 0; i < state_count; i++) {
115 for (int m = 1; m < 19; m++) {
116 int next = t_tab[state[i]][m];
117 if (mask & (1<<m) && (p_tab[next] > p_tab[state[i]] + 1) && next) {
118 p_tab[next] = p_tab[state[i]] + 1;
119 state[state_count++] = next;
120 }
121 }
122 }
123 }
124}
125
126void init_double_table(int n1, int n2,
127 int t_table1[n1][19], int t_table2[n2][19],
128 int8_t p_table[n1][n2], int mask) {
129 static int state1[factorial8*pow3to7], state2[factorial8*pow3to7];
130 state1[0] = 0;
131 state2[0] = 0;
132 p_table[0][0] = 0;
133 int state_count = 1;
134 for (int i = 0; i < state_count; i++) {
135 for (int m = 1; m < 19; m++) {
136 int next1 = t_table1[state1[i]][m];
137 int next2 = t_table2[state2[i]][m];
138 if (mask & (1<<m) && !p_table[next1][next2] && (next1 || next2)) {
139 p_table[next1][next2] = p_table[state1[i]][state2[i]] + 1;
140 state1[state_count] = next1;
141 state2[state_count] = next2;
142 state_count++;
143 }
144 }
145 }
146}
147
148void init_eofb_pruning_table() {
149 init_single_table(pow2to11, eofb_transition_table, eofb_pruning_table,
150 move_mask_all);
151}
152
153void init_eorl_pruning_table() {
154 init_single_table(pow2to11, eorl_transition_table, eorl_pruning_table,
155 move_mask_all);
156}
157
158void init_eoud_pruning_table() {
159 init_single_table(pow2to11, eoud_transition_table, eoud_pruning_table,
160 move_mask_all);
161}
162
163void init_coud_pruning_table() {
164 init_single_table(pow3to7, coud_transition_table, coud_pruning_table,
165 move_mask_all);
166}
167
168void init_cofb_pruning_table() {
169 init_single_table(pow3to7, cofb_transition_table, cofb_pruning_table,
170 move_mask_all);
171}
172
173void init_corl_pruning_table() {
174 init_single_table(pow3to7, corl_transition_table, corl_pruning_table,
175 move_mask_all);
176}
177
178void init_cp_pruning_table() {
179 init_single_table(factorial8, cp_transition_table, cp_pruning_table,
180 move_mask_all);
181}
182
183/* The following tables use the eo moveset */
184void init_eorl_from_eofb_pruning_table() {
185 init_single_table(pow2to11, eorl_transition_table,
186 eorl_from_eofb_pruning_table, move_mask_eofb);
187}
188
189void init_eoud_from_eofb_pruning_table() {
190 init_single_table(pow2to11, eoud_transition_table,
191 eoud_from_eofb_pruning_table, move_mask_eofb);
192}
193
194void init_eoud_from_eorl_pruning_table() {
195 init_single_table(pow2to11, eoud_transition_table,
196 eoud_from_eorl_pruning_table, move_mask_eorl);
197}
198
199void init_eofb_from_eorl_pruning_table() {
200 init_single_table(pow2to11, eofb_transition_table,
201 eofb_from_eorl_pruning_table, move_mask_eorl);
202}
203
204void init_eofb_from_eoud_pruning_table() {
205 init_single_table(pow2to11, eofb_transition_table,
206 eofb_from_eoud_pruning_table, move_mask_eoud);
207}
208
209void init_eorl_from_eoud_pruning_table() {
210 init_single_table(pow2to11, eorl_transition_table,
211 eorl_from_eoud_pruning_table, move_mask_eoud);
212}
213
214void init_coud_from_eofb_pruning_table() {
215 init_single_table(pow3to7, coud_transition_table,
216 coud_from_eofb_pruning_table, move_mask_eofb);
217}
218
219void init_corl_from_eofb_pruning_table() {
220 init_single_table(pow3to7, corl_transition_table,
221 corl_from_eofb_pruning_table, move_mask_eofb);
222}
223
224void init_coud_from_eorl_pruning_table() {
225 init_single_table(pow3to7, coud_transition_table,
226 coud_from_eorl_pruning_table, move_mask_eorl);
227}
228
229void init_cofb_from_eorl_pruning_table() {
230 init_single_table(pow3to7, cofb_transition_table,
231 cofb_from_eorl_pruning_table, move_mask_eorl);
232}
233
234void init_corl_from_eoud_pruning_table() {
235 init_single_table(pow3to7, corl_transition_table,
236 corl_from_eoud_pruning_table, move_mask_eoud);
237}
238
239void init_cofb_from_eoud_pruning_table() {
240 init_single_table(pow3to7, cofb_transition_table,
241 cofb_from_eoud_pruning_table, move_mask_eoud);
242}
243
244/* The following tables always use DR moveset */
245void init_epud_pruning_table() {
246 init_single_table(factorial8, epud_transition_table, epud_pruning_table,
247 move_mask_drud);
248}
249
250void init_epfb_pruning_table() {
251 init_single_table(factorial8, epfb_transition_table, epfb_pruning_table,
252 move_mask_drfb);
253}
254
255void init_eprl_pruning_table() {
256 init_single_table(factorial8, eprl_transition_table, eprl_pruning_table,
257 move_mask_drrl);
258}
259
260void init_cp_drud_pruning_table() {
261 init_single_table(factorial8, cp_transition_table, cp_drud_pruning_table,
262 move_mask_drud);
263}
264
265void init_cp_drfb_pruning_table() {
266 init_single_table(factorial8, cp_transition_table, cp_drfb_pruning_table,
267 move_mask_drfb);
268}
269
270void init_cp_drrl_pruning_table() {
271 init_single_table(factorial8, cp_transition_table, cp_drrl_pruning_table,
272 move_mask_drrl);
273}
274
275void init_cp_htr_table() {
276 init_single_table(factorial8, cp_transition_table, cp_htr_pruning_table,
277 move_mask_htr);
278}
279
280void init_cpud_to_htr_table() {
281 init_cptohtr_table(factorial8, cp_transition_table,
282 cpud_to_htr_pruning_table, move_mask_drud);
283}
284
285void init_cpfb_to_htr_table() {
286 init_cptohtr_table(factorial8, cp_transition_table,
287 cpfb_to_htr_pruning_table, move_mask_drfb);
288}
289
290void init_cprl_to_htr_table() {
291 init_cptohtr_table(factorial8, cp_transition_table,
292 cprl_to_htr_pruning_table, move_mask_drrl);
293}
294
295
296void init_eofb_epose_pruning_table() {
297 init_double_table(pow2to11, binom12on4,
298 eofb_transition_table, epose_transition_table,
299 eofb_epose_pruning_table, move_mask_all);
300}
301
302void init_eorl_eposs_pruning_table() {
303 init_double_table(pow2to11, binom12on4,
304 eorl_transition_table, eposs_transition_table,
305 eorl_eposs_pruning_table, move_mask_all);
306}
307
308void init_eoud_eposm_pruning_table() {
309 init_double_table(pow2to11, binom12on4,
310 eoud_transition_table, eposm_transition_table,
311 eoud_eposm_pruning_table, move_mask_all);
312}
313
314
315
316void init_eofb_coud_pruning_table() {
317 init_double_table(pow2to11, pow3to7,
318 eofb_transition_table, coud_transition_table,
319 eofb_coud_pruning_table, move_mask_all);
320}
321
322void init_eofb_corl_pruning_table() {
323 init_double_table(pow2to11, pow3to7,
324 eofb_transition_table, corl_transition_table,
325 eofb_corl_pruning_table, move_mask_all);
326}
327
328void init_eorl_coud_pruning_table() {
329 init_double_table(pow2to11, pow3to7,
330 eorl_transition_table, coud_transition_table,
331 eorl_coud_pruning_table, move_mask_all);
332}
333
334void init_eorl_cofb_pruning_table() {
335 init_double_table(pow2to11, pow3to7,
336 eorl_transition_table, cofb_transition_table,
337 eorl_cofb_pruning_table, move_mask_all);
338}
339
340void init_eoud_corl_pruning_table() {
341 init_double_table(pow2to11, pow3to7,
342 eoud_transition_table, corl_transition_table,
343 eoud_corl_pruning_table, move_mask_all);
344}
345
346void init_eoud_cofb_pruning_table() {
347 init_double_table(pow2to11, pow3to7,
348 eoud_transition_table, cofb_transition_table,
349 eoud_cofb_pruning_table, move_mask_all);
350}
351
352void init_coud_epose_from_eofb_pruning_table() {
353 init_double_table(pow3to7, binom12on4,
354 coud_transition_table, epose_transition_table,
355 coud_epose_from_eofb_pruning_table, move_mask_eofb);
356}
357
358void init_cofb_eposs_from_eorl_pruning_table() {
359 init_double_table(pow3to7, binom12on4,
360 cofb_transition_table, eposs_transition_table,
361 cofb_eposs_from_eorl_pruning_table, move_mask_eorl);
362}
363
364void init_corl_eposm_from_eoud_pruning_table() {
365 init_double_table(pow3to7, binom12on4,
366 corl_transition_table, eposm_transition_table,
367 corl_eposm_from_eoud_pruning_table, move_mask_eoud);
368}
369
370void init_coud_epose_from_eorl_pruning_table() {
371 init_double_table(pow3to7, binom12on4,
372 coud_transition_table, epose_transition_table,
373 coud_epose_from_eorl_pruning_table, move_mask_eorl);
374}
375
376void init_cofb_eposs_from_eoud_pruning_table() {
377 init_double_table(pow3to7, binom12on4,
378 cofb_transition_table, eposs_transition_table,
379 cofb_eposs_from_eoud_pruning_table, move_mask_eoud);
380}
381
382void init_corl_eposm_from_eofb_pruning_table() {
383 init_double_table(pow3to7, binom12on4,
384 corl_transition_table, eposm_transition_table,
385 corl_eposm_from_eofb_pruning_table, move_mask_eofb);
386}
387
388void init_cp_co_pruning_table() {
389 init_double_table(factorial8, pow3to7,
390 cp_transition_table, coud_transition_table,
391 cp_co_pruning_table, move_mask_all);
392}
393
394void init_triple_eo_pruning_table() {
395 init_double_table(pow2to11, binom12on4*binom8on4,
396 eofb_transition_table, emslices_transition_table,
397 triple_eo_pruning_table, move_mask_all);
398}
399
400
401void init_small_pruning_tables() {
402 if (initialized_small)
403 return;
404
405 init_eofb_pruning_table();
406 init_eorl_pruning_table();
407 init_eoud_pruning_table();
408 init_coud_pruning_table();
409 init_cofb_pruning_table();
410 init_corl_pruning_table();
411 init_cp_pruning_table();
412
413 init_eorl_from_eofb_pruning_table();
414 init_eoud_from_eofb_pruning_table();
415 init_eoud_from_eorl_pruning_table();
416 init_eofb_from_eorl_pruning_table();
417 init_eofb_from_eoud_pruning_table();
418 init_eorl_from_eoud_pruning_table();
419
420 init_coud_from_eofb_pruning_table();
421 init_corl_from_eofb_pruning_table();
422 init_coud_from_eorl_pruning_table();
423 init_cofb_from_eorl_pruning_table();
424 init_cofb_from_eoud_pruning_table();
425 init_corl_from_eoud_pruning_table();
426
427 init_epud_pruning_table();
428 init_epfb_pruning_table();
429 init_eprl_pruning_table();
430 init_cp_drud_pruning_table();
431 init_cp_drfb_pruning_table();
432 init_cp_drrl_pruning_table();
433
434 init_cp_htr_table();
435 init_cpud_to_htr_table();
436 init_cpfb_to_htr_table();
437 init_cprl_to_htr_table();
438
439 initialized_small = 1;
440}
441
442void init_directdr_pruning_tables() {
443 if (initialized_directdr)
444 return;
445
446 init_eofb_epose_pruning_table();
447 init_eorl_eposs_pruning_table();
448 init_eoud_eposm_pruning_table();
449
450 init_eofb_coud_pruning_table();
451 init_eofb_corl_pruning_table();
452 init_eorl_coud_pruning_table();
453 init_eorl_cofb_pruning_table();
454 init_eoud_cofb_pruning_table();
455 init_eoud_corl_pruning_table();
456
457 initialized_directdr = 1;
458}
459
460void init_drfromeo_pruning_tables() {
461 if (initialized_drfromeo)
462 return;
463
464 init_coud_epose_from_eofb_pruning_table();
465 init_cofb_eposs_from_eorl_pruning_table();
466 init_corl_eposm_from_eoud_pruning_table();
467 init_coud_epose_from_eorl_pruning_table();
468 init_cofb_eposs_from_eoud_pruning_table();
469 init_corl_eposm_from_eofb_pruning_table();
470
471 initialized_drfromeo = 1;
472}
473
474void init_huge_pruning_tables() {
475 if (initialized_huge)
476 return;
477
478 init_cp_co_pruning_table();
479 init_triple_eo_pruning_table();
480
481 initialized_huge = 1;
482}
483
diff --git a/src/pruning_tables.h b/src/pruning_tables.h
deleted file mode 100644
index 7921e97..0000000
--- a/src/pruning_tables.h
+++ /dev/null
@@ -1,66 +0,0 @@
1#include <stdint.h>
2#include "utils.h"
3
4extern int eofb_pruning_table[pow2to11];
5extern int eorl_pruning_table[pow2to11];
6extern int eoud_pruning_table[pow2to11];
7extern int coud_pruning_table[pow3to7];
8extern int cofb_pruning_table[pow3to7];
9extern int corl_pruning_table[pow3to7];
10extern int cp_pruning_table[factorial8];
11
12extern int eorl_from_eofb_pruning_table[pow2to11];
13extern int eoud_from_eofb_pruning_table[pow2to11];
14extern int eoud_from_eorl_pruning_table[pow2to11];
15extern int eofb_from_eorl_pruning_table[pow2to11];
16extern int eofb_from_eoud_pruning_table[pow2to11];
17extern int eorl_from_eoud_pruning_table[pow2to11];
18
19extern int coud_from_eofb_pruning_table[pow3to7];
20extern int coud_from_eorl_pruning_table[pow3to7];
21extern int cofb_from_eorl_pruning_table[pow3to7];
22extern int cofb_from_eoud_pruning_table[pow3to7];
23extern int corl_from_eoud_pruning_table[pow3to7];
24extern int corl_from_eofb_pruning_table[pow3to7];
25
26extern int cp_drud_pruning_table[factorial8];
27extern int cp_drfb_pruning_table[factorial8];
28extern int cp_drrl_pruning_table[factorial8];
29extern int epud_pruning_table[factorial8];
30extern int epfb_pruning_table[factorial8];
31extern int eprl_pruning_table[factorial8];
32
33extern int cp_htr_pruning_table[factorial8];
34extern int cpud_to_htr_pruning_table[factorial8];
35extern int cpfb_to_htr_pruning_table[factorial8];
36extern int cprl_to_htr_pruning_table[factorial8];
37
38/* About 1Mb each */
39extern int8_t eofb_epose_pruning_table[pow2to11][binom12on4];
40extern int8_t eorl_eposs_pruning_table[pow2to11][binom12on4];
41extern int8_t eoud_eposm_pruning_table[pow2to11][binom12on4];
42
43/* About 4.5Mb each */
44extern int8_t eofb_coud_pruning_table[pow2to11][pow3to7];
45extern int8_t eofb_corl_pruning_table[pow2to11][pow3to7];
46extern int8_t eorl_coud_pruning_table[pow2to11][pow3to7];
47extern int8_t eorl_cofb_pruning_table[pow2to11][pow3to7];
48extern int8_t eoud_cofb_pruning_table[pow2to11][pow3to7];
49extern int8_t eoud_corl_pruning_table[pow2to11][pow3to7];
50
51/* About 1Mb each */
52extern int8_t coud_epose_from_eofb_pruning_table[pow3to7][binom12on4];
53extern int8_t cofb_eposs_from_eorl_pruning_table[pow3to7][binom12on4];
54extern int8_t corl_eposm_from_eoud_pruning_table[pow3to7][binom12on4];
55extern int8_t coud_epose_from_eorl_pruning_table[pow3to7][binom12on4];
56extern int8_t cofb_eposs_from_eoud_pruning_table[pow3to7][binom12on4];
57extern int8_t corl_eposm_from_eofb_pruning_table[pow3to7][binom12on4];
58
59/* First one 88Mb, second one 21Mb */
60extern int8_t cp_co_pruning_table[factorial8][pow3to7];
61extern int8_t triple_eo_pruning_table[pow2to11][binom12on4*binom8on4];
62
63void init_small_pruning_tables();
64void init_directdr_pruning_tables();
65void init_drfromeo_pruning_tables();
66void init_huge_pruning_tables();
diff --git a/src/shell.c b/src/shell.c
new file mode 100644
index 0000000..0880f8a
--- /dev/null
+++ b/src/shell.c
@@ -0,0 +1,93 @@
1#include "shell.h"
2
3static void cleanwhitespaces(char *line);
4static int parseline(char *line, char **v);
5
6static void
7cleanwhitespaces(char *line)
8{
9 char *i;
10
11 for (i = line; *i != 0; i++)
12 if (*i == '\t' || *i == '\n')
13 *i = ' ';
14}
15
16/* This function assumes that **v is large enough */
17static int
18parseline(char *line, char **v)
19{
20 char *t;
21 int n = 0;
22
23 cleanwhitespaces(line);
24
25 for (t = strtok(line, " "); t != NULL; t = strtok(NULL, " "))
26 strcpy(v[n++], t);
27
28 return n;
29}
30
31void
32exec_args(int c, char **v)
33{
34 int i;
35 Command *cmd = NULL;
36 CommandArgs *args;
37
38 for (i = 0; i < NCOMMANDS; i++)
39 if (commands[i] != NULL && !strcmp(v[0], commands[i]->name))
40 cmd = commands[i];
41
42 if (cmd == NULL) {
43 fprintf(stderr, "%s: command not found\n", v[0]);
44 return;
45 }
46
47 args = cmd->parse_args(c-1, &v[1]);
48 if (!args->success) {
49 fprintf(stderr, "usage: %s\n", cmd->usage);
50 return;
51 }
52
53 cmd->exec(args);
54 free_args(args);
55}
56
57void
58launch()
59{
60 int i, shell_argc;
61 char line[MAXLINELEN], **shell_argv;
62
63 shell_argv = malloc(MAXNTOKENS * sizeof(char *));
64 for (i = 0; i < MAXNTOKENS; i++)
65 shell_argv[i] = malloc((MAXTOKENLEN+1) * sizeof(char));
66
67 fprintf(stderr, "Welcome to Nissy "VERSION".\n");
68 fprintf(stderr, "Type 'help' for a list.\n");
69
70 while (true) {
71 fprintf(stderr, "nissy-# ");
72 if (fgets(line, MAXLINELEN, stdin) == NULL)
73 break;
74 shell_argc = parseline(line, shell_argv);
75 if (shell_argc > 0)
76 exec_args(shell_argc, shell_argv);
77 }
78
79 for (i = 0; i < MAXNTOKENS; i++)
80 free(shell_argv[i]);
81 free(shell_argv);
82}
83
84int
85main(int argc, char *argv[])
86{
87 if (argc > 1)
88 exec_args(argc-1, &argv[1]);
89 else
90 launch();
91
92 return 0;
93}
diff --git a/src/shell.h b/src/shell.h
new file mode 100644
index 0000000..a72d136
--- /dev/null
+++ b/src/shell.h
@@ -0,0 +1,13 @@
1#ifndef SHELL_H
2#define SHELL_H
3
4#include "commands.h"
5
6#define MAXLINELEN 10000
7#define MAXTOKENLEN 255
8#define MAXNTOKENS 255
9
10void exec_args(int c, char **v);
11void launch();
12
13#endif
diff --git a/src/solve.c b/src/solve.c
new file mode 100644
index 0000000..1f4a155
--- /dev/null
+++ b/src/solve.c
@@ -0,0 +1,173 @@
1#include "solve.h"
2
3/* Local functions ***********************************************************/
4
5static bool allowed_next(Move move, DfsData *dd);
6static void dfs(Cube c, Step *s, SolveOptions *opts, DfsData *dd);
7static void dfs_branch(Cube c, Step *s, SolveOptions *os, DfsData *dd);
8static bool dfs_check_solved(Step *s, SolveOptions *opts, DfsData *dd);
9static void dfs_niss(Cube c, Step *s, SolveOptions *opts, DfsData *dd);
10static bool dfs_stop(Cube c, Step *s, SolveOptions *opts, DfsData *dd);
11
12/* Local functions ***********************************************************/
13
14static bool
15allowed_next(Move move, DfsData *dd)
16{
17 if (!possible_next(dd->last2, dd->last1, move))
18 return false;
19
20 if (commute(dd->last1, move))
21 return dd->move_position[dd->last1] < dd->move_position[move];
22
23 return true;
24}
25
26static void
27dfs(Cube c, Step *s, SolveOptions *opts, DfsData *dd)
28{
29 if (dfs_stop(c, s, opts, dd))
30 return;
31
32 if (dfs_check_solved(s, opts, dd))
33 return;
34
35 dfs_branch(c, s, opts, dd);
36
37 if (opts->can_niss && !dd->niss)
38 dfs_niss(c, s, opts, dd);
39}
40
41static void
42dfs_branch(Cube c, Step *s, SolveOptions *opts, DfsData *dd)
43{
44 Move m, l1 = dd->last1, l2 = dd->last2, *moves = dd->sorted_moves;
45
46 int i, maxnsol = opts->max_solutions;
47
48 for (i = 0; moves[i] != NULLMOVE && dd->sols->len < maxnsol; i++) {
49 m = moves[i];
50 if (allowed_next(m, dd)) {
51 dd->last2 = dd->last1;
52 dd->last1 = m;
53 append_move(dd->current_alg, m, dd->niss);
54
55 dfs(apply_move(m, c), s, opts, dd);
56
57 dd->current_alg->len--;
58 dd->last2 = l2;
59 dd->last1 = l1;
60 }
61 }
62}
63
64static bool
65dfs_check_solved(Step *s, SolveOptions *opts, DfsData *dd)
66{
67 if (dd->lb != 0)
68 return false;
69
70 if (dd->current_alg->len == dd->d) {
71 if (s->is_valid(dd->current_alg) || opts->all)
72 append_alg(dd->sols, dd->current_alg);
73
74 if (opts->verbose)
75 print_alg(dd->current_alg, false);
76 }
77
78 return true;
79}
80
81static void
82dfs_niss(Cube c, Step *s, SolveOptions *opts, DfsData *dd)
83{
84 Move l1 = dd->last1, l2 = dd->last2;
85 CubeTarget ct;
86
87 ct.cube = apply_move(inverse_move(l1), (Cube){0});
88 ct.target = 1;
89
90 if (dd->current_alg->len == 0 || s->estimate(ct)) {
91 dd->niss = true;
92 dd->last1 = NULLMOVE;
93 dd->last2 = NULLMOVE;
94
95 dfs(inverse_cube(c), s, opts, dd);
96
97 dd->last1 = l1;
98 dd->last2 = l2;
99 dd->niss = false;
100 }
101}
102
103static bool
104dfs_stop(Cube c, Step *s, SolveOptions *opts, DfsData *dd)
105{
106 CubeTarget ct = {
107 .cube = c,
108 .target = dd->d - dd->current_alg->len
109 };
110
111 if (dd->sols->len >= opts->max_solutions)
112 return true;
113
114 dd->lb = s->estimate(ct);
115 if (opts->can_niss && !dd->niss)
116 dd->lb = MIN(1, dd->lb);
117
118 if (dd->current_alg->len + dd->lb > dd->d)
119 return true;
120
121 return false;
122}
123
124/* Public functions **********************************************************/
125
126AlgList *
127solve(Cube cube, Step *step, SolveOptions *opts)
128{
129 AlgListNode *node;
130 AlgList *sols = new_alglist();
131 Cube c;
132
133 if (step->detect != NULL)
134 step->pre_trans = step->detect(cube);
135 c = apply_trans(step->pre_trans, cube);
136
137 DfsData dd = {
138 .m = 0,
139 .niss = false,
140 .lb = -1,
141 .last1 = NULLMOVE,
142 .last2 = NULLMOVE,
143 .sols = sols,
144 .current_alg = new_alg("")
145 };
146
147 if (step->ready != NULL && !step->ready(c)) {
148 fprintf(stderr, "Cube not ready for solving step: ");
149 fprintf(stderr, "%s\n", step->ready_msg);
150 return sols;
151 }
152
153 moveset_to_list(step->moveset, dd.sorted_moves);
154 movelist_to_position(dd.sorted_moves, dd.move_position);
155
156 for (dd.d = opts->min_moves;
157 dd.d <= opts->max_moves &&
158 !(sols->len && opts->optimal_only) &&
159 sols->len < opts->max_solutions;
160 dd.d++) {
161 if (opts->verbose)
162 fprintf(stderr,
163 "Found %d solutions, searching depth %d...\n",
164 sols->len, dd.d);
165 dfs(c, step, opts, &dd);
166 }
167
168 for (node = sols->first; node != NULL; node = node->next)
169 transform_alg(inverse_trans(step->pre_trans), node->alg);
170
171 free_alg(dd.current_alg);
172 return sols;
173}
diff --git a/src/solve.h b/src/solve.h
new file mode 100644
index 0000000..ff84e7e
--- /dev/null
+++ b/src/solve.h
@@ -0,0 +1,9 @@
1#ifndef SOLVE_H
2#define SOLVE_H
3
4#include "moves.h"
5#include "trans.h"
6
7AlgList * solve(Cube cube, Step *step, SolveOptions *opts);
8
9#endif
diff --git a/src/solver.c b/src/solver.c
deleted file mode 100644
index 48e845f..0000000
--- a/src/solver.c
+++ /dev/null
@@ -1,1058 +0,0 @@
1#include <stdint.h>
2#include <stdio.h>
3
4#include "utils.h"
5#include "coordinates.h"
6#include "moves.h"
7#include "io.h"
8#include "pruning_tables.h"
9
10/* Applies inverse of moves, inverse of prev_moves and then inverse of scramble
11 * and returns a coordinate determined by t_table. */
12int premoves_inverse(int moves[30], int scramble[], int prev_moves[30],
13 int t_table[][19]) {
14 int nprevmoves, nmoves, nscramble, coord = 0;
15
16 for (nmoves = 0; moves[nmoves]; nmoves++);
17 for (nprevmoves = 0; prev_moves[nprevmoves]; nprevmoves++);
18 for (nscramble = 0; scramble[nscramble]; nscramble++);
19
20 for (int i = nmoves - 1; i >= 0; i--)
21 coord = t_table[coord][inverse_move[moves[i]]];
22 for (int i = nprevmoves - 1; i >= 0; i--)
23 coord = t_table[coord][inverse_move[prev_moves[i]]];
24 for (int i = nscramble - 1; i >= 0; i--)
25 coord = t_table[coord][inverse_move[scramble[i]]];
26
27 return coord;
28}
29
30
31/******/
32/* EO */
33/******/
34void niss_eo_dfs(int eo, int scramble[], int eo_list[][30], int *eo_count,
35 int t_table[pow2to11][19], int p_table[pow2to11],
36 int last1, int last2, int moves, int m, int d, int niss,
37 int can_use_niss, int hide) {
38
39
40 if (*eo_count >= m || moves > d ||
41 ((!can_use_niss || niss) && moves + p_table[eo] > d))
42 return;
43
44 eo_list[*eo_count][moves] = 0;
45
46 if (eo == 0) {
47 /* If an early EO is found, or if "case F2 B", or if hide is on. */
48 if (moves != d || (parallel(last1, last2) && last2 % 3 == 2) ||
49 (hide && moves > 0 &&
50 (last1 % 3 == 0 || (parallel(last1, last2) && last2 % 3 == 0))))
51 return;
52 /* Copy moves for the next solution */
53 if (*eo_count < m - 1)
54 copy_moves(eo_list[*eo_count], eo_list[(*eo_count)+1]);
55 (*eo_count)++;
56 return;
57 }
58
59 for (int i = 1; i < 19; i++) {
60 if (possible_next[last1][last2] & (1 << i)) {
61 eo_list[*eo_count][moves] = niss ? -i : i;
62 niss_eo_dfs(t_table[eo][i], scramble, eo_list, eo_count, t_table,
63 p_table, i, last1, moves+1, m, d, niss,
64 can_use_niss, hide);
65 }
66 }
67
68 if (*eo_count >= m)
69 return;
70 eo_list[*eo_count][moves] = 0;
71
72 /* If not nissing already and we either have not done any move yet or
73 * the last move was F/F' etc, and if I am allowed to niss, try niss! */
74 if (!niss && (last1 == 0 || t_table[0][last1] != 0) && can_use_niss &&
75 !(hide && moves > 0 &&
76 (last1 % 3 == 0 || (parallel(last1, last2) && last2 % 3 == 0)))) {
77 int aux[] = {0,0};
78 niss_eo_dfs(premoves_inverse(eo_list[*eo_count], scramble, aux, t_table),
79 scramble, eo_list, eo_count, t_table, p_table,
80 0, 0, moves, m, d, 1, can_use_niss, hide);
81 }
82}
83
84int eo_scram_spam(int scram[], int eo_list[][30], int fb, int rl, int ud,
85 int m, int b, int niss, int h) {
86
87 init_small_pruning_tables();
88
89 int n = 0, eofb = 0, eorl = 0, eoud = 0;
90 for (int i = 0; scram[i]; i++) {
91 eofb = eofb_transition_table[eofb][scram[i]];
92 eorl = eorl_transition_table[eorl][scram[i]];
93 eoud = eoud_transition_table[eoud][scram[i]];
94 }
95 for (int i = 0; i <= b; i++) {
96 if (fb)
97 niss_eo_dfs(eofb, scram, eo_list, &n, eofb_transition_table,
98 eofb_pruning_table, 0, 0, 0, m, i, 0, niss, h);
99 if (rl)
100 niss_eo_dfs(eorl, scram, eo_list, &n, eorl_transition_table,
101 eorl_pruning_table, 0, 0, 0, m, i, 0, niss, h);
102 if (ud)
103 niss_eo_dfs(eoud, scram, eo_list, &n, eoud_transition_table,
104 eoud_pruning_table, 0, 0, 0, m, i, 0, niss, h);
105 }
106 return n;
107}
108
109
110/******/
111/* CO */
112/******/
113void niss_co_dfs(int co, int scramble[], int co_list[][30], int *co_count,
114 int t_table[pow3to7][19], int p_table[pow3to7],
115 int last1, int last2, int moves, int m, int d, int niss,
116 int can_use_niss, int hide, int ignore) {
117
118
119 if (*co_count >= m || moves > d ||
120 ((!can_use_niss || niss) && ((!ignore && moves + p_table[co] > d) ||
121 ( ignore && moves + p_table[co] - 2 > d))))
122 return;
123
124 co_list[*co_count][moves] = 0;
125
126 if (co == 0 || (ignore && ( t_table[t_table[co][F]][B] == 0 ||
127 t_table[t_table[co][R]][L] == 0 ||
128 t_table[t_table[co][U]][D] == 0 ))) {
129 /* If an early CO is found, or if "case F2 B", or if hide is on. */
130 if (moves != d || (parallel(last1, last2) && last2 % 3 == 2) ||
131 (hide && moves > 0 &&
132 (last1 % 3 == 0 || (parallel(last1, last2) && last2 % 3 == 0))))
133 return;
134 /* Copy moves for the next solution */
135 if (*co_count < m - 1)
136 copy_moves(co_list[*co_count], co_list[(*co_count)+1]);
137 (*co_count)++;
138 return;
139 }
140
141 for (int i = 1; i < 19; i++) {
142 if (possible_next[last1][last2] & (1 << i)) {
143 co_list[*co_count][moves] = niss ? -i : i;
144 niss_co_dfs(t_table[co][i], scramble, co_list, co_count, t_table,
145 p_table, i, last1, moves+1, m, d, niss,
146 can_use_niss, hide, ignore);
147 }
148 }
149
150 if (*co_count >= m)
151 return;
152 co_list[*co_count][moves] = 0;
153
154 /* If not nissing already and we either have not done any move yet or
155 * the last move was F/F' etc, and if I am allowed to niss, try niss! */
156 if (!niss && (last1 == 0 || t_table[0][last1] != 0) && can_use_niss &&
157 !(hide && moves > 0 &&
158 (last1 % 3 == 0 || (parallel(last1, last2) && last2 % 3 == 0)))) {
159 int aux[] = {0,0};
160 niss_co_dfs(premoves_inverse(co_list[*co_count], scramble, aux, t_table),
161 scramble, co_list, co_count, t_table, p_table,
162 0, 0, moves, m, d, 1, can_use_niss, hide, ignore);
163 }
164}
165
166int co_scram_spam(int scram[], int co_list[][30], int fb, int rl, int ud,
167 int m, int b, int niss, int h, int ignore) {
168
169 init_small_pruning_tables();
170
171 int n = 0, cofb = 0, corl = 0, coud = 0;
172 for (int i = 0; scram[i]; i++) {
173 cofb = cofb_transition_table[cofb][scram[i]];
174 corl = corl_transition_table[corl][scram[i]];
175 coud = coud_transition_table[coud][scram[i]];
176 }
177 for (int i = 0; i <= b; i++) {
178 if (fb)
179 niss_co_dfs(cofb, scram, co_list, &n, cofb_transition_table,
180 cofb_pruning_table, 0, 0, 0, m, i, 0, niss, h, ignore);
181 if (rl)
182 niss_co_dfs(corl, scram, co_list, &n, corl_transition_table,
183 corl_pruning_table, 0, 0, 0, m, i, 0, niss, h, ignore);
184 if (ud)
185 niss_co_dfs(coud, scram, co_list, &n, coud_transition_table,
186 coud_pruning_table, 0, 0, 0, m, i, 0, niss, h, ignore);
187 }
188 return n;
189}
190
191
192/**************/
193/* DR from EO */
194/**************/
195
196
197/* Scramble includes premoves for previous EO */
198void niss_dr_from_eo_dfs(int co, int epos, int scramble[], int eo_moves[30],
199 int dr_list[][30], int *dr_count,
200 int co_t_table[pow3to7][19],
201 int epos_t_table[binom12on4][19],
202 int8_t p_table[pow3to7][binom12on4], int mask,
203 int last1, int last2, int last1_inv, int last2_inv,
204 int moves, int m, int d, int niss,
205 int can_use_niss, int hide) {
206
207 if (*dr_count >= m || moves > d ||
208 ((!can_use_niss || niss) && moves + p_table[co][epos] > d))
209 return;
210
211 dr_list[*dr_count][moves] = 0;
212
213 if (co == 0 && epos == 0) {
214 if (moves != d || (parallel(last1, last2) && last2 % 3 == 2) ||
215 (hide && moves > 0 &&
216 (last1 % 3 == 0 || (parallel(last1, last2) && last2 % 3 == 0))))
217 return;
218 /* Copy moves for the next solution */
219 if (*dr_count < m - 1)
220 copy_moves(dr_list[*dr_count], dr_list[(*dr_count)+1]);
221 (*dr_count)++;
222 return;
223 }
224
225 for (int i = 1; i < 19; i++) {
226 if (possible_next[last1][last2] & (1 << i) & mask) {
227 dr_list[*dr_count][moves] = niss ? -i : i;
228 niss_dr_from_eo_dfs(co_t_table[co][i], epos_t_table[epos][i],
229 scramble, eo_moves, dr_list, dr_count,
230 co_t_table, epos_t_table, p_table, mask,
231 i, last1, last1_inv, last2_inv,
232 moves+1, m, d, niss, can_use_niss, hide);
233 }
234 }
235
236 if (*dr_count >= m)
237 return;
238 dr_list[*dr_count][moves] = 0;
239
240 /* If not nissing already and we either have not done any move yet or
241 * the last move was F/F' etc and I am allowed to niss, try niss! */
242 if (!niss && (last1 == 0 || co_t_table[0][last1] != 0) && can_use_niss &&
243 !(hide && moves > 0 &&
244 (last1 % 3 == 0 || (parallel(last1, last2) && last2 % 3 == 0))))
245 niss_dr_from_eo_dfs(premoves_inverse(dr_list[*dr_count], scramble,
246 eo_moves, co_t_table),
247 premoves_inverse(dr_list[*dr_count], scramble,
248 eo_moves, epos_t_table),
249 scramble, eo_moves, dr_list, dr_count,
250 co_t_table, epos_t_table, p_table,
251 mask, last1_inv, last2_inv, 0, 0,
252 moves, m, d, 1, can_use_niss, hide);
253}
254
255int drfrom_scram_spam(int scram[], int dr_list[][30], int from, int fb,
256 int rl, int ud, int m, int b, int niss, int hide) {
257
258 init_drfromeo_pruning_tables();
259
260 int n = 0;
261 int eofb = 0, eorl = 0, eoud = 0;
262 int epose = 0, eposm = 0, eposs = 0;
263 int coud = 0, corl = 0, cofb = 0;
264
265 for (int i = 0; scram[i]; i++) {
266 eofb = eofb_transition_table[eofb][scram[i]];
267 eorl = eorl_transition_table[eorl][scram[i]];
268 eoud = eoud_transition_table[eoud][scram[i]];
269
270 cofb = cofb_transition_table[cofb][scram[i]];
271 corl = corl_transition_table[corl][scram[i]];
272 coud = coud_transition_table[coud][scram[i]];
273
274 epose = epose_transition_table[epose][scram[i]];
275 eposm = eposm_transition_table[eposm][scram[i]];
276 eposs = eposs_transition_table[eposs][scram[i]];
277 }
278
279 int fake_eom[2] = {0, 0}; /* Fake EO moves */
280
281 if (from == 1) {
282 if (eofb)
283 return -1;
284 for (int i = 0; i <= b; i++) {
285 if (ud)
286 niss_dr_from_eo_dfs(coud, epose, scram, fake_eom, dr_list, &n,
287 coud_transition_table, epose_transition_table,
288 coud_epose_from_eofb_pruning_table, move_mask_eofb,
289 0, 0, 0, 0, 0, m, i, 0, niss, hide);
290 if (rl)
291 niss_dr_from_eo_dfs(corl, eposm, scram, fake_eom, dr_list, &n,
292 corl_transition_table, eposm_transition_table,
293 corl_eposm_from_eofb_pruning_table, move_mask_eofb,
294 0, 0, 0, 0, 0, m, i, 0, niss, hide);
295 }
296 } else if (from == 2) {
297 if (eorl)
298 return -1;
299 for (int i = 0; i <= b; i++) {
300 if (fb)
301 niss_dr_from_eo_dfs(cofb, eposs, scram, fake_eom, dr_list, &n,
302 cofb_transition_table, eposs_transition_table,
303 cofb_eposs_from_eorl_pruning_table, move_mask_eorl,
304 0, 0, 0, 0, 0, m, i, 0, niss, hide);
305 if (ud)
306 niss_dr_from_eo_dfs(coud, epose, scram, fake_eom, dr_list, &n,
307 coud_transition_table, epose_transition_table,
308 coud_epose_from_eorl_pruning_table, move_mask_eorl,
309 0, 0, 0, 0, 0, m, i, 0, niss, hide);
310 }
311 } else if (from == 3) {
312 if (eoud)
313 return -1;
314 for (int i = 0; i <= b; i++) {
315 if (rl)
316 niss_dr_from_eo_dfs(corl, eposm, scram, fake_eom, dr_list, &n,
317 corl_transition_table, eposm_transition_table,
318 corl_eposm_from_eoud_pruning_table, move_mask_eoud,
319 0, 0, 0, 0, 0, m, i, 0, niss, hide);
320 if (fb)
321 niss_dr_from_eo_dfs(cofb, eposs, scram, fake_eom, dr_list, &n,
322 cofb_transition_table, eposs_transition_table,
323 cofb_eposs_from_eoud_pruning_table, move_mask_eoud,
324 0, 0, 0, 0, 0, m, i, 0, niss, hide);
325 }
326 } else {
327 return -1;
328 }
329 return n;
330}
331
332
333/***************/
334/* HTR from DR */
335/***************/
336
337/* Scramble includes premoves for previous DR */
338void niss_htr_from_dr_dfs(int cp, int eo3, int scramble[], int eodr_moves[30],
339 int htr_list[][30], int *htr_count,
340 int eo3_t_table[pow2to11][19],
341 int cp_to_htr_pruning_table[factorial8],
342 int cp_htr_pruning_table[factorial8],
343 int cp_finish_pruning_table[factorial8],
344 int mask, int last1, int last2,
345 int last1_inv, int last2_inv, int moves,
346 int m, int d, int niss,
347 int can_use_niss, int hide) {
348
349 if (*htr_count >= m || moves > d ||
350 ((!can_use_niss || niss) && moves + cp_to_htr_pruning_table[cp] > d) ||
351 moves + cp_finish_pruning_table[cp] - 4 > d)
352 return;
353
354 htr_list[*htr_count][moves] = 0;
355
356 if ((cp == 0 || cp_htr_pruning_table[cp]) && eo3 == 0) {
357 if (moves != d || (parallel(last1, last2) && last2 % 3 == 2) ||
358 (hide && moves > 0 &&
359 (last1 % 3 == 0 || (parallel(last1, last2) && last2 % 3 == 0))))
360 return;
361 /* Copy moves for the next solution */
362 if (*htr_count < m - 1)
363 copy_moves(htr_list[*htr_count], htr_list[(*htr_count)+1]);
364 (*htr_count)++;
365 return;
366 }
367
368 for (int i = 1; i < 19; i++) {
369 if (possible_next[last1][last2] & (1 << i) & mask) {
370 htr_list[*htr_count][moves] = niss ? -i : i;
371 niss_htr_from_dr_dfs(cp_transition_table[cp][i], eo3_t_table[eo3][i],
372 scramble, eodr_moves, htr_list, htr_count,
373 eo3_t_table, cp_to_htr_pruning_table,
374 cp_htr_pruning_table, cp_finish_pruning_table,
375 mask, i, last1, last1_inv, last2_inv,
376 moves+1, m, d, niss, can_use_niss, hide);
377 }
378 }
379
380 if (*htr_count >= m)
381 return;
382 htr_list[*htr_count][moves] = 0;
383
384 /* If not nissing already and we either have not done any move yet or
385 * the last move was a quarter turn and I am allowed to niss, try niss! */
386 if (!niss && last1 % 3 != 2 && can_use_niss &&
387 !(hide && moves > 0 &&
388 (last1 % 3 == 0 || (parallel(last1, last2) && last2 % 3 == 0))))
389 niss_htr_from_dr_dfs(premoves_inverse(htr_list[*htr_count], scramble,
390 eodr_moves, cp_transition_table),
391 premoves_inverse(htr_list[*htr_count], scramble,
392 eodr_moves, eo3_t_table),
393 scramble, eodr_moves, htr_list, htr_count,
394 eo3_t_table, cp_to_htr_pruning_table,
395 cp_htr_pruning_table, cp_finish_pruning_table,
396 mask, last1_inv, last2_inv,
397 0, 0, moves, m, d, 1, can_use_niss, hide);
398}
399
400int htr_scram_spam(int scram[], int htr_list[][30], int from,
401 int m, int b, int niss, int hide) {
402
403 init_small_pruning_tables();
404
405 int n = 0;
406 int eofb = 0, eorl = 0, eoud = 0;
407 int coud = 0, corl = 0, cofb = 0;
408 int cp = 0;
409
410 for (int i = 0; scram[i]; i++) {
411 eofb = eofb_transition_table[eofb][scram[i]];
412 eorl = eorl_transition_table[eorl][scram[i]];
413 eoud = eoud_transition_table[eoud][scram[i]];
414
415 cofb = cofb_transition_table[cofb][scram[i]];
416 corl = corl_transition_table[corl][scram[i]];
417 coud = coud_transition_table[coud][scram[i]];
418
419 cp = cp_transition_table[cp][scram[i]];
420 }
421
422 int fake_drm[2] = {0, 0}; /* Fake DR moves */
423
424 if ((from == 1 || from == 0) && (!eofb && !eorl && !coud)) {
425 for (int i = 0; i <= b; i++) {
426 niss_htr_from_dr_dfs(cp, eoud, scram, fake_drm, htr_list, &n,
427 eoud_transition_table, cpud_to_htr_pruning_table,
428 cp_htr_pruning_table, cp_drud_pruning_table,
429 move_mask_drud, 0, 0, 0, 0, 0, m, i, 0, niss, hide);
430 }
431 } else if ((from == 2 || from == 0) && (!eorl && !eoud && !cofb)) {
432 for (int i = 0; i <= b; i++) {
433 niss_htr_from_dr_dfs(cp, eofb, scram, fake_drm, htr_list, &n,
434 eofb_transition_table, cpfb_to_htr_pruning_table,
435 cp_htr_pruning_table, cp_drfb_pruning_table,
436 move_mask_drfb, 0, 0, 0, 0, 0, m, i, 0, niss, hide);
437 }
438 } else if ((from == 3 || from == 0) && (!eoud && !eofb && !corl)) {
439 for (int i = 0; i <= b; i++) {
440 niss_htr_from_dr_dfs(cp, eorl, scram, fake_drm, htr_list, &n,
441 eorl_transition_table, cprl_to_htr_pruning_table,
442 cp_htr_pruning_table, cp_drrl_pruning_table,
443 move_mask_drrl, 0, 0, 0, 0, 0, m, i, 0, niss, hide);
444 }
445 } else {
446 return -1;
447 }
448 return n;
449}
450
451
452/***********************/
453/* Direct DR (no NISS) */
454/***********************/
455void dr_dfs(int eo, int eo2, int eslice, int co,
456 int dr_list[][30], int *dr_count,
457 int eo_t_table[pow2to11][19], int eo2_t_table[pow2to11][19],
458 int eslice_t_table[binom12on4][19], int co_t_table[pow3to7][19],
459 int8_t eo_eslice_p_table[pow2to11][binom12on4],
460 int8_t eo_co_p_table[pow2to11][pow3to7],
461 int8_t eo2_co_p_table[pow2to11][pow3to7],
462 int last1, int last2, int moves, int max_sol,
463 int depth, int hide) {
464 if (*dr_count >= max_sol || moves + eo_eslice_p_table[eo][eslice] > depth ||
465 moves + eo_co_p_table[eo][co] > depth ||
466 moves + eo2_co_p_table[eo2][co] > depth)
467 return;
468
469 dr_list[*dr_count][moves] = 0;
470
471 if (eo == 0 && eslice == 0 && co == 0) {
472 /* If an early DR is found, or if "case R2 L". */
473 if (moves != depth || (parallel(last1, last2) && last2 % 3 == 2) ||
474 (hide && moves > 0 &&
475 (last1 % 3 == 0 || (parallel(last1, last2) && last2 % 3 == 0))))
476 return;
477 /* Copy moves for the next solution */
478 if (*dr_count < max_sol - 1)
479 copy_moves(dr_list[*dr_count], dr_list[(*dr_count)+1]);
480 (*dr_count)++;
481 return;
482 }
483
484 for (int i = 1; i < 19; i++) {
485 if (possible_next[last1][last2] & (1 << i)) {
486 dr_list[*dr_count][moves] = i;
487 dr_dfs(eo_t_table[eo][i], eo2_t_table[eo2][i],
488 eslice_t_table[eslice][i], co_t_table[co][i],
489 dr_list, dr_count,
490 eo_t_table, eo2_t_table, eslice_t_table, co_t_table,
491 eo_eslice_p_table, eo_co_p_table, eo2_co_p_table,
492 i, last1, moves+1, max_sol, depth, hide);
493 }
494 }
495}
496
497int dr_scram_spam(int scram[], int dr_list[][30], int fb, int rl, int ud,
498 int m, int b, int h) {
499
500 init_directdr_pruning_tables();
501
502 int n = 0;
503 int eofb = 0, eorl = 0, eoud = 0;
504 int epose = 0, eposm = 0, eposs = 0;
505 int coud = 0, corl = 0, cofb = 0;
506
507 for (int i = 0; scram[i]; i++) {
508 eofb = eofb_transition_table[eofb][scram[i]];
509 eorl = eorl_transition_table[eorl][scram[i]];
510 eoud = eoud_transition_table[eoud][scram[i]];
511
512 cofb = cofb_transition_table[cofb][scram[i]];
513 corl = corl_transition_table[corl][scram[i]];
514 coud = coud_transition_table[coud][scram[i]];
515
516 epose = epose_transition_table[epose][scram[i]];
517 eposm = eposm_transition_table[eposm][scram[i]];
518 eposs = eposs_transition_table[eposs][scram[i]];
519 }
520
521 for (int i = 0; i <= b; i++) {
522 if (ud)
523 dr_dfs(eofb, eorl, epose, coud, dr_list, &n,
524 eofb_transition_table, eorl_transition_table,
525 epose_transition_table, coud_transition_table,
526 eofb_epose_pruning_table, eofb_coud_pruning_table,
527 eorl_coud_pruning_table, 0, 0, 0, m, i, h);
528 if (fb)
529 dr_dfs(eorl, eoud, eposs, cofb, dr_list, &n,
530 eorl_transition_table, eoud_transition_table,
531 eposs_transition_table, cofb_transition_table,
532 eorl_eposs_pruning_table, eorl_cofb_pruning_table,
533 eoud_cofb_pruning_table, 0, 0, 0, m, i, h);
534 if (rl)
535 dr_dfs(eoud, eofb, eposm, corl, dr_list, &n,
536 eoud_transition_table, eofb_transition_table,
537 eposm_transition_table, corl_transition_table,
538 eoud_eposm_pruning_table, eoud_corl_pruning_table,
539 eofb_corl_pruning_table, 0, 0, 0, m, i, h);
540 }
541 return n;
542}
543
544
545/*************/
546/* DR finish */
547/*************/
548void dr_finish_dfs(int cp, int ep8, int ep4, int sol[][30], int *sol_count,
549 int ep8_t_table[factorial8][19],
550 int ep4_t_table[factorial4][19],
551 int cp_p_table[factorial8],
552 int ep8_p_table[factorial8],
553 int mask, int last1, int last2, int moves, int m, int d) {
554
555
556 if (*sol_count >= m || moves + cp_p_table[cp] > d ||
557 moves + ep8_p_table[ep8] > d)
558 return;
559
560 sol[*sol_count][moves] = 0;
561
562 if (cp == 0 && ep8 == 0 && ep4 == 0) {
563 if (moves != d)
564 return;
565 /* Copy moves for the next solution */
566 if (*sol_count < m - 1)
567 copy_moves(sol[*sol_count], sol[(*sol_count)+1]);
568 (*sol_count)++;
569 return;
570 }
571
572 for (int i = 1; i < 19; i++) {
573 if (possible_next[last1][last2] & (1 << i) & mask) {
574 sol[*sol_count][moves] = i;
575 dr_finish_dfs(cp_transition_table[cp][i], ep8_t_table[ep8][i],
576 ep4_t_table[ep4][i], sol, sol_count,
577 ep8_t_table, ep4_t_table,
578 cp_p_table, ep8_p_table,
579 mask, i, last1, moves+1, m, d);
580 }
581 }
582
583 return;
584}
585
586int dr_finish_scram_spam(int scram[], int sol[][30], int from, int m, int b) {
587
588 init_small_pruning_tables();
589
590 int n = 0;
591 int eofb = 0, eorl = 0, eoud = 0;
592 int coud = 0, corl = 0, cofb = 0;
593 int cp = 0;
594 int ep[12];
595 ep_int_to_array(0, ep);
596
597 for (int i = 0; scram[i]; i++) {
598 eofb = eofb_transition_table[eofb][scram[i]];
599 eorl = eorl_transition_table[eorl][scram[i]];
600 eoud = eoud_transition_table[eoud][scram[i]];
601
602 cofb = cofb_transition_table[cofb][scram[i]];
603 corl = corl_transition_table[corl][scram[i]];
604 coud = coud_transition_table[coud][scram[i]];
605
606 cp = cp_transition_table[cp][scram[i]];
607 apply_move_ep_array(scram[i], ep);
608 }
609
610 if ((from == 1 && (eofb || eorl || coud)) ||
611 (from == 2 && (eorl || eoud || cofb)) ||
612 (from == 3 && (eoud || eofb || corl)) ||
613 ((eofb || eorl || coud) && (eorl || eoud ||cofb) && (eoud ||eofb || corl)))
614 return -1;
615
616 for (int i = 0; i <= b; i++) {
617 if ((from == 1 || from == 0) && (!eofb && !eorl && !coud))
618 dr_finish_dfs(cp, epud_array_to_int(ep), epe_array_to_int(ep),
619 sol, &n, epud_transition_table, epe_transition_table,
620 cp_drud_pruning_table, epud_pruning_table,
621 move_mask_drud, 0, 0, 0, m, i);
622 if ((from == 2 || from == 0) && (!eorl && !eoud && !cofb))
623 dr_finish_dfs(cp, epfb_array_to_int(ep), eps_array_to_int(ep),
624 sol, &n, epfb_transition_table, eps_transition_table,
625 cp_drfb_pruning_table, epfb_pruning_table,
626 move_mask_drfb, 0, 0, 0, m, i);
627 if ((from == 3 || from == 0) && (!eoud && !eofb && !corl))
628 dr_finish_dfs(cp, eprl_array_to_int(ep), epm_array_to_int(ep),
629 sol, &n, eprl_transition_table, epm_transition_table,
630 cp_drrl_pruning_table, eprl_pruning_table,
631 move_mask_drrl, 0, 0, 0, m, i);
632 }
633
634 return n;
635}
636
637int htr_finish_scram_spam(int scram[], int sol[][30], int m, int b) {
638
639 init_small_pruning_tables();
640
641 int n = 0;
642 int eofb = 0, eorl = 0, eoud = 0;
643 int coud = 0, cp = 0;
644 int ep[12];
645 ep_int_to_array(0, ep);
646
647 for (int i = 0; scram[i]; i++) {
648 eofb = eofb_transition_table[eofb][scram[i]];
649 eorl = eorl_transition_table[eorl][scram[i]];
650 eoud = eoud_transition_table[eoud][scram[i]];
651
652 coud = coud_transition_table[coud][scram[i]];
653
654 cp = cp_transition_table[cp][scram[i]];
655 apply_move_ep_array(scram[i], ep);
656 }
657
658 if (eofb || eorl || eoud || coud || cpud_to_htr_pruning_table[cp] != 0)
659 return -1;
660
661 for (int i = 0; i <= b; i++)
662 dr_finish_dfs(cp, epud_array_to_int(ep), epe_array_to_int(ep),
663 sol, &n, epud_transition_table, epe_transition_table,
664 cp_drud_pruning_table, epud_pruning_table,
665 move_mask_htr, 0, 0, 0, m, i);
666
667 return n;
668}
669
670
671/**************/
672/* DR corners */
673/**************/
674void dr_corners_dfs(int cp, int sol[][30], int *sol_count,
675 int cp_p_table[factorial8], int mask, int last1, int last2,
676 int moves, int m, int d, int ignore) {
677
678 if (*sol_count >= m || (!ignore && moves + cp_p_table[cp] > d) ||
679 (ignore && moves + cp_p_table[cp] - 2 > d))
680 return;
681
682
683 sol[*sol_count][moves] = 0;
684
685 if (cp == 0 ||
686 (ignore && mask == move_mask_drud &&
687 (cp_transition_table[cp_transition_table[cp][U]][D3] == 0 ||
688 cp_transition_table[cp_transition_table[cp][U2]][D2] == 0 ||
689 cp_transition_table[cp_transition_table[cp][U3]][D] == 0 )) ||
690 (ignore && mask == move_mask_drfb &&
691 (cp_transition_table[cp_transition_table[cp][F]][B3] == 0 ||
692 cp_transition_table[cp_transition_table[cp][F2]][B2] == 0 ||
693 cp_transition_table[cp_transition_table[cp][F3]][B] == 0 )) ||
694 (ignore && mask == move_mask_drrl &&
695 (cp_transition_table[cp_transition_table[cp][R]][L3] == 0 ||
696 cp_transition_table[cp_transition_table[cp][R2]][L2] == 0 ||
697 cp_transition_table[cp_transition_table[cp][R3]][L] == 0 ))
698 ) {
699 if (moves != d)
700 return;
701 /* Copy moves for the next solution */
702 if (*sol_count < m - 1)
703 copy_moves(sol[*sol_count], sol[(*sol_count)+1]);
704 (*sol_count)++;
705 return;
706 }
707
708 for (int i = 1; i < 19; i++) {
709 if (possible_next[last1][last2] & (1 << i) & mask) {
710 sol[*sol_count][moves] = i;
711 dr_corners_dfs(cp_transition_table[cp][i], sol, sol_count,
712 cp_p_table, mask, i, last1, moves+1, m, d, ignore);
713 }
714 }
715}
716
717int dr_corners_scram_spam(int scram[], int sol[][30], int from, int m, int b,
718 int ignore) {
719
720 init_small_pruning_tables();
721
722 int n = 0;
723 int eofb = 0, eorl = 0, eoud = 0;
724 int coud = 0, corl = 0, cofb = 0;
725 int cp = 0;
726
727 for (int i = 0; scram[i]; i++) {
728 eofb = eofb_transition_table[eofb][scram[i]];
729 eorl = eorl_transition_table[eorl][scram[i]];
730 eoud = eoud_transition_table[eoud][scram[i]];
731
732 cofb = cofb_transition_table[cofb][scram[i]];
733 corl = corl_transition_table[corl][scram[i]];
734 coud = coud_transition_table[coud][scram[i]];
735
736 cp = cp_transition_table[cp][scram[i]];
737 }
738
739 if ((from == 1 && coud) || (from == 2 && cofb) || (from == 3 && corl) ||
740 (coud && cofb && corl))
741 return -1;
742
743 for (int i = 0; i <= b; i++) {
744 if ((from == 1 || from == 0) && !coud)
745 dr_corners_dfs(cp, sol, &n, cp_drud_pruning_table, move_mask_drud,
746 0, 0, 0, m, i, ignore);
747 if ((from == 2 || from == 0) && !cofb)
748 dr_corners_dfs(cp, sol, &n, cp_drfb_pruning_table, move_mask_drfb,
749 0, 0, 0, m, i, ignore);
750 if ((from == 3 || from == 0) && !corl)
751 dr_corners_dfs(cp, sol, &n, cp_drrl_pruning_table, move_mask_drrl,
752 0, 0, 0, m, i, ignore);
753 }
754
755 return n;
756}
757
758/***************/
759/* Full solver */
760/***************/
761
762int is_ep_solved(int ep, int moves[30]) {
763 int ep_arr[12];
764 ep_int_to_array(ep, ep_arr);
765 for (int i = 0; moves[i]; i++)
766 apply_move_ep_array(moves[i], ep_arr);
767 return !ep_array_to_int(ep_arr);
768}
769
770/* Solves directly using only small tables. Suitable for short solutions. */
771void small_optimal_dfs(int eofb, int eorl, int eoud, int ep,
772 int coud, int cofb, int corl, int cp,
773 int sol[][30], int *sol_count, int last1, int last2,
774 int moves, int m, int d) {
775 if (moves + eofb_pruning_table[eofb] > d ||
776 moves + eorl_pruning_table[eorl] > d ||
777 moves + eoud_pruning_table[eoud] > d ||
778 moves + coud_pruning_table[coud] > d ||
779 moves + cofb_pruning_table[cofb] > d ||
780 moves + corl_pruning_table[corl] > d ||
781 moves + cp_pruning_table[cp] > d ||
782 *sol_count >= m)
783 return;
784
785 sol[*sol_count][moves] = 0;
786
787 if (eofb == 0 && coud == 0 && cp == 0) {
788 if (is_ep_solved(ep, sol[*sol_count])) {
789 if (moves != d)
790 return;
791 if (*sol_count < m - 1)
792 copy_moves(sol[*sol_count], sol[(*sol_count)+1]);
793 (*sol_count)++;
794 return;
795 }
796 }
797
798 for (int i = 1; i < 19; i++) {
799 if (possible_next[last1][last2] & (1 << i)) {
800 sol[*sol_count][moves] = i;
801 small_optimal_dfs(eofb_transition_table[eofb][i],
802 eorl_transition_table[eorl][i],
803 eoud_transition_table[eoud][i], ep,
804 coud_transition_table[coud][i],
805 cofb_transition_table[cofb][i],
806 corl_transition_table[corl][i],
807 cp_transition_table[cp][i],
808 sol, sol_count, i, last1, moves+1, m, d);
809 }
810 }
811}
812
813/* Solves directly using only medium tables. Suitable for short solutions.
814void medium_optimal_dfs(int eofb, int eorl, int eoud,
815 int epose, int eposs, int eposm, int ep,
816 int coud, int cofb, int corl, int cp,
817 int sol[][30], int *sol_count, int last1, int last2,
818 int moves, int m, int d) {
819 if (moves + eofb_epose_pruning_table[eofb][epose] > d ||
820 moves + eorl_eposs_pruning_table[eorl][eposs] > d ||
821 moves + eoud_eposm_pruning_table[eoud][eposm] > d ||
822 moves + eofb_coud_pruning_table[eofb][coud] > d ||
823 moves + eofb_corl_pruning_table[eofb][corl] > d ||
824 moves + eorl_coud_pruning_table[eorl][coud] > d ||
825 moves + eorl_cofb_pruning_table[eorl][cofb] > d ||
826 moves + eoud_cofb_pruning_table[eoud][cofb] > d ||
827 moves + eoud_corl_pruning_table[eoud][corl] > d ||
828 moves + cp_pruning_table[cp] > d ||
829 *sol_count >= m)
830 return;
831
832 sol[*sol_count][moves] = 0;
833
834 if (eofb == 0 && coud == 0 && cp == 0) {
835 if (is_ep_solved(ep, sol[*sol_count])) {
836 if (moves != d)
837 return;
838 if (*sol_count < m - 1)
839 copy_moves(sol[*sol_count], sol[(*sol_count)+1]);
840 (*sol_count)++;
841 return;
842 }
843 }
844
845 for (int i = 1; i < 19; i++) {
846 if (possible_next[last1][last2] & (1 << i)) {
847 sol[*sol_count][moves] = i;
848 medium_optimal_dfs(eofb_transition_table[eofb][i],
849 eorl_transition_table[eorl][i],
850 eoud_transition_table[eoud][i],
851 epose_transition_table[epose][i],
852 eposs_transition_table[eposs][i],
853 eposm_transition_table[eposm][i], ep,
854 coud_transition_table[coud][i],
855 cofb_transition_table[cofb][i],
856 corl_transition_table[corl][i],
857 cp_transition_table[cp][i],
858 sol, sol_count, i, last1, moves+1, m, d);
859 }
860 }
861}
862*/
863
864/* Uses huge tables */
865int optimal_dfs(int ep, int cp, int eo, int co, int emslices,
866 int sol[][30], int last1, int last2, int moves, int d) {
867 if (moves + cp_co_pruning_table[cp][co] > d ||
868 moves + triple_eo_pruning_table[eo][emslices] > d)
869 return 0;
870
871 sol[0][moves] = 0;
872
873 /* If solved, no need to check the depth */
874 if (cp == 0 && co == 0 && eo == 0 && emslices == 0)
875 if (is_ep_solved(ep, sol[0]))
876 return 1;
877
878 for (int i = 1; i < 19; i++) {
879 if (possible_next[last1][last2] & (1 << i)) {
880 sol[0][moves] = i;
881 if (optimal_dfs(ep, cp_transition_table[cp][i],
882 eofb_transition_table[eo][i],
883 coud_transition_table[co][i],
884 emslices_transition_table[emslices][i],
885 sol, i, last1, moves+1, d))
886 return 1;
887 }
888 }
889 return 0;
890}
891
892int solve_scram(int scram[], int sol[][30], int m, int b, int optimal) {
893
894 /* Initialize pieces. */
895 int eofb = 0, eorl = 0, eoud = 0, ep = 0;
896 int epose = 0, eposs = 0, eposm = 0;
897 int coud = 0, cofb = 0, corl = 0, cp = 0;
898 int emslices = 0;
899 for (int i = 0; scram[i]; i++) {
900 eofb = eofb_transition_table[eofb][scram[i]];
901 eorl = eorl_transition_table[eorl][scram[i]];
902 eoud = eoud_transition_table[eoud][scram[i]];
903
904 epose = epose_transition_table[epose][scram[i]];
905 eposs = eposs_transition_table[eposs][scram[i]];
906 eposm = eposm_transition_table[eposm][scram[i]];
907
908 ep = apply_move_ep_int(scram[i], ep);
909
910 coud = coud_transition_table[coud][scram[i]];
911 cofb = cofb_transition_table[cofb][scram[i]];
912 corl = corl_transition_table[corl][scram[i]];
913 cp = cp_transition_table[cp][scram[i]];
914
915 emslices = emslices_transition_table[emslices][scram[i]];
916 }
917
918 /* First we check if there are solutions of up to max_small moves. */
919 int max_small = 10;
920 int n = 0;
921 init_small_pruning_tables();
922 for (int i = 0; i <= min(b, max_small); i++) {
923 small_optimal_dfs(eofb, eorl, eoud, ep, coud, cofb, corl, cp,
924 sol, &n, 0, 0, 0, m, i);
925 if (n > 0 && optimal)
926 b = min(b, len(sol[0]));
927 }
928
929
930 if (n >= m || b <= 10)
931 return n;
932
933
934 /* If we found at least a solution, we return */
935 if (n > 0)
936 return n;
937
938 /* Then we try a 2-step solver */
939 int max_step1 = 100;
940 int db = 12;
941 int step1[max_step1+10][30];
942 int ss[300], step2[2][30];
943 int best = b+1;
944
945 /* TODO maybe: for now, multiple solutions can be found only using the
946 * short solver. */
947
948 int n_step1 = dr_scram_spam(scram, step1, 1, 1, 1, max_step1, min(b, db), 0);
949 for (int i = 0; i < n_step1; i++) {
950 copy_moves(scram, ss);
951 append_moves(step1[i], ss);
952 if (dr_finish_scram_spam(ss, step2, 0, 1, min(best-1,b) - len(step1[i]))) {
953 copy_moves(step1[i], sol[0]);
954 append_moves(step2[0], sol[0]);
955 best = len(sol[0]);
956 }
957 }
958
959 /* If optimal solving was not required, or we have already found an optimal
960 * solution, we return. */
961 if (best <= len(step1[n_step1-1]) || !optimal)
962 return best > b ? 0 : 1;
963
964 /* Otherwise, we go on with the optimal solver. */
965 int searched = len(step1[n_step1-1])-1;
966
967 printf("Searched up to %d moves, no solution found.\n", searched);
968 printf("Using huge pruning tables, if not loaded it might take a while.\n");
969 init_huge_pruning_tables();
970
971 for (int i = searched+1; i <= min(b, best-1); i++) {
972 if (i >= 10)
973 printf("Searching at depth %d.\n", i);
974 if (optimal_dfs(ep, cp, eofb, coud, emslices, sol, 0, 0, 0, i)) {
975 return 1;
976 }
977 }
978 return best > b ? 0 : 1;
979}
980
981/* Given eofb, coud, ep and cp it finds a scramble that reaches that state.
982 * It uses a simple 3-step solver to find a preliminary "solution", and then
983 * gives this solutions as a scramble to a better solver (see above). */
984int reach_state(int eofb, int coud, int ep, int cp, int sol[][30]) {
985
986 int fake_count = 0, fake_scram[30];
987 int eo_list[2][30], dr_list[2][30], finish_list[2][30];
988
989 /* Convert ep to array */
990 int ep_arr[12];
991 ep_int_to_array(ep, ep_arr);
992
993 /* Find EO */
994 init_small_pruning_tables();
995 for (int d = 0; d < 10; d++) {
996 niss_eo_dfs(eofb, fake_scram, eo_list, &fake_count, eofb_transition_table,
997 eofb_pruning_table, 0, 0, 0, 1, d, 0, 0, 0);
998 if (fake_count) {
999 fake_count = 0;
1000 break;
1001 }
1002 }
1003
1004 /* Apply moves found, find epose */
1005 for (int i = 0; eo_list[0][i]; i++) {
1006 coud = coud_transition_table[coud][eo_list[0][i]];
1007 cp = cp_transition_table[cp][eo_list[0][i]];
1008 apply_move_ep_array(eo_list[0][i], ep_arr);
1009 }
1010 int epose = epose_array_to_int(ep_arr);
1011
1012 /* Find DR */
1013 init_drfromeo_pruning_tables();
1014 for (int d = 0; d < 16; d++) {
1015 niss_dr_from_eo_dfs(coud, epose, fake_scram, fake_scram, dr_list,
1016 &fake_count, coud_transition_table,
1017 epose_transition_table,
1018 coud_epose_from_eofb_pruning_table, move_mask_eofb,
1019 0, 0, 0, 0, 0, 1, d, 0, 0, 0);
1020 if (fake_count) {
1021 fake_count = 0;
1022 break;
1023 }
1024 }
1025
1026 /* Apply moves found, find epud and epe */
1027 for (int i = 0; dr_list[0][i]; i++) {
1028 cp = cp_transition_table[cp][dr_list[0][i]];
1029 apply_move_ep_array(dr_list[0][i], ep_arr);
1030 }
1031 int epud = epud_array_to_int(ep_arr);
1032 int epe = epe_array_to_int(ep_arr);
1033
1034 /* Find finish */
1035 init_small_pruning_tables();
1036 for (int d = 0; d < 16; d++) {
1037 dr_finish_dfs(cp, epud, epe, finish_list, &fake_count,
1038 epud_transition_table, epe_transition_table,
1039 cp_drud_pruning_table, epud_pruning_table, move_mask_drud,
1040 0, 0, 0, 1, d);
1041 if (fake_count) {
1042 fake_count = 0;
1043 break;
1044 }
1045 }
1046
1047 int scram[50];
1048
1049 /* Debug */
1050 /*print_moves(eo_list[0]); printf("\n");
1051 print_moves(dr_list[0]); printf("\n");
1052 print_moves(finish_list[0]); printf("\n");*/
1053
1054 copy_moves(eo_list[0], scram);
1055 append_moves(dr_list[0], scram);
1056 append_moves(finish_list[0], scram);
1057 return solve_scram(scram, sol, 1, 25, 0);
1058}
diff --git a/src/solver.h b/src/solver.h
deleted file mode 100644
index abb55d3..0000000
--- a/src/solver.h
+++ /dev/null
@@ -1,16 +0,0 @@
1int eo_scram_spam(int scram[], int eo_list[][30], int fb, int rl, int ud,
2 int m, int b, int niss, int h);
3int co_scram_spam(int scram[], int co_list[][30], int fb, int rl, int ud,
4 int m, int b, int niss, int h, int i);
5int dr_scram_spam(int scram[], int dr_list[][30], int fb, int rl, int ud,
6 int m, int b, int h);
7int drfrom_scram_spam(int scram[], int dr_list[][30], int from, int fb,
8 int rl, int ud, int m, int b, int niss, int hide);
9int htr_scram_spam(int scram[], int htr_list[][30], int from,
10 int m, int b, int niss, int hide);
11int dr_corners_scram_spam(int scram[], int sol[][30], int from, int m, int b,
12 int ignore);
13int dr_finish_scram_spam(int scram[], int sol[][30], int from, int m, int b);
14int htr_finish_scram_spam(int scram[], int sol[][30], int m, int b);
15int solve_scram(int scram[], int sol[][30], int m, int b, int optimal);
16int reach_state(int eofb, int coud, int ep, int cp, int sol[][30]);
diff --git a/src/steps.c b/src/steps.c
new file mode 100644
index 0000000..56f7369
--- /dev/null
+++ b/src/steps.c
@@ -0,0 +1,941 @@
1#include "steps.h"
2
3/* Checkers, estimators and validators ***************************************/
4
5static bool check_centers(Cube cube);
6static bool check_eofb(Cube cube);
7static bool check_drud(Cube cube);
8static bool check_htr(Cube cube);
9
10static int estimate_eoany_HTM(CubeTarget ct);
11static int estimate_eofb_HTM(CubeTarget ct);
12static int estimate_coany_HTM(CubeTarget ct);
13static int estimate_coud_HTM(CubeTarget ct);
14static int estimate_coany_URF(CubeTarget ct);
15static int estimate_coud_URF(CubeTarget ct);
16static int estimate_corners_HTM(CubeTarget ct);
17static int estimate_cornershtr_HTM(CubeTarget ct);
18static int estimate_corners_URF(CubeTarget ct);
19static int estimate_cornershtr_URF(CubeTarget ct);
20static int estimate_drany_HTM(CubeTarget ct);
21static int estimate_drud_HTM(CubeTarget ct);
22static int estimate_drud_eofb(CubeTarget ct);
23static int estimate_dr_eofb(CubeTarget ct);
24static int estimate_drudfin_drud(CubeTarget ct);
25static int estimate_htr_drud(CubeTarget ct);
26static int estimate_htrfin_htr(CubeTarget ct);
27static int estimate_optimal_HTM(CubeTarget ct);
28
29static bool always_valid(Alg *alg);
30static bool validate_singlecw_ending(Alg *alg);
31
32/* Pre-transformation detectors **********************************************/
33
34static Trans detect_pretrans_eofb(Cube cube);
35static Trans detect_pretrans_drud(Cube cube);
36
37/* Messages for when cube is not ready ***************************************/
38
39static char check_centers_msg[100] = "cube must be oriented (centers solved)";
40static char check_eo_msg[100] = "EO must be solved on given axis";
41static char check_dr_msg[100] = "DR must be solved on given axis";
42static char check_htr_msg[100] = "HTR must be solved";
43static char check_drany_msg[100] = "DR must be solved on at least one axis";
44
45/* Steps *********************************************************************/
46
47Step
48optimal_HTM = {
49 .shortname = "optimal",
50 .name = "Optimal solve (in HTM)",
51
52 .estimate = estimate_optimal_HTM,
53 .ready = check_centers,
54 .ready_msg = check_centers_msg,
55 .is_valid = always_valid,
56 .moveset = moveset_HTM,
57
58 .pre_trans = uf,
59};
60
61/* EO steps **************************/
62Step
63eoany_HTM = {
64 .shortname = "eo",
65 .name = "EO on any axis",
66
67 .estimate = estimate_eoany_HTM,
68 .ready = check_centers,
69 .ready_msg = check_centers_msg,
70 .is_valid = validate_singlecw_ending,
71 .moveset = moveset_HTM,
72
73 .pre_trans = uf,
74};
75
76Step
77eofb_HTM = {
78 .shortname = "eofb",
79 .name = "EO on F/B",
80
81 .estimate = estimate_eofb_HTM,
82 .ready = check_centers,
83 .ready_msg = check_centers_msg,
84 .is_valid = validate_singlecw_ending,
85 .moveset = moveset_HTM,
86
87 .pre_trans = uf,
88};
89
90Step
91eorl_HTM = {
92 .shortname = "eorl",
93 .name = "EO on R/L",
94
95 .estimate = estimate_eofb_HTM,
96 .ready = check_centers,
97 .ready_msg = check_centers_msg,
98 .is_valid = validate_singlecw_ending,
99 .moveset = moveset_HTM,
100
101 .pre_trans = ur,
102};
103
104Step
105eoud_HTM = {
106 .shortname = "eoud",
107 .name = "EO on U/D",
108
109 .estimate = estimate_eofb_HTM,
110 .ready = check_centers,
111 .ready_msg = check_centers_msg,
112 .is_valid = validate_singlecw_ending,
113 .moveset = moveset_HTM,
114
115 .pre_trans = fd,
116};
117
118/* CO steps **************************/
119Step
120coany_HTM = {
121 .shortname = "co",
122 .name = "CO on any axis",
123
124 .estimate = estimate_coany_HTM,
125 .ready = NULL,
126 .is_valid = validate_singlecw_ending,
127 .moveset = moveset_HTM,
128
129 .pre_trans = uf,
130};
131
132Step
133coud_HTM = {
134 .shortname = "coud",
135 .name = "CO on U/D",
136
137 .estimate = estimate_coud_HTM,
138 .ready = NULL,
139 .is_valid = validate_singlecw_ending,
140 .moveset = moveset_HTM,
141
142 .pre_trans = uf,
143};
144
145Step
146corl_HTM = {
147 .shortname = "corl",
148 .name = "CO on R/L",
149
150 .estimate = estimate_coud_HTM,
151 .ready = NULL,
152 .is_valid = validate_singlecw_ending,
153 .moveset = moveset_HTM,
154
155 .pre_trans = rf,
156};
157
158Step
159cofb_HTM = {
160 .shortname = "cofb",
161 .name = "CO on F/B",
162
163 .estimate = estimate_coud_HTM,
164 .ready = NULL,
165 .is_valid = validate_singlecw_ending,
166 .moveset = moveset_HTM,
167
168 .pre_trans = fd,
169};
170
171Step
172coany_URF = {
173 .shortname = "co-URF",
174 .name = "CO any axis (URF moveset)",
175
176 .estimate = estimate_coany_URF,
177 .ready = NULL,
178 .is_valid = validate_singlecw_ending,
179 .moveset = moveset_URF,
180
181 .pre_trans = uf,
182};
183
184Step
185coud_URF = {
186 .shortname = "coud-URF",
187 .name = "CO on U/D (URF moveset)",
188
189 .estimate = estimate_coud_URF,
190 .ready = NULL,
191 .is_valid = validate_singlecw_ending,
192 .moveset = moveset_URF,
193
194 .pre_trans = uf,
195};
196
197Step
198corl_URF = {
199 .shortname = "corl-URF",
200 .name = "CO on R/L (URF moveset)",
201
202 .estimate = estimate_coud_URF,
203 .ready = NULL,
204 .is_valid = validate_singlecw_ending,
205 .moveset = moveset_URF,
206
207 .pre_trans = rf,
208};
209
210Step
211cofb_URF = {
212 .shortname = "cofb-URF",
213 .name = "CO on F/B (URF moveset)",
214
215 .estimate = estimate_coud_URF,
216 .ready = NULL,
217 .is_valid = validate_singlecw_ending,
218 .moveset = moveset_URF,
219
220 .pre_trans = fd,
221};
222
223/* Misc corner steps *****************/
224Step
225cornershtr_HTM = {
226 .shortname = "chtr",
227 .name = "Solve corners to HTR state",
228
229 .estimate = estimate_cornershtr_HTM,
230 .ready = NULL,
231 .is_valid = validate_singlecw_ending,
232 .moveset = moveset_HTM,
233
234 .pre_trans = uf,
235};
236
237Step
238cornershtr_URF = {
239 .shortname = "chtr-URF",
240 .name = "Solve corners to HTR state (URF moveset)",
241
242 .estimate = estimate_cornershtr_URF,
243 .ready = NULL,
244 .is_valid = validate_singlecw_ending,
245 .moveset = moveset_URF,
246
247 .pre_trans = uf,
248};
249
250Step
251corners_HTM = {
252 .shortname = "corners",
253 .name = "Solve corners",
254
255 .estimate = estimate_corners_HTM,
256 .ready = NULL,
257 .is_valid = always_valid,
258 .moveset = moveset_HTM,
259
260 .pre_trans = uf,
261};
262
263Step
264corners_URF = {
265 .shortname = "corners-URF",
266 .name = "Solve corners (URF moveset)",
267
268 .estimate = estimate_corners_URF,
269 .ready = NULL,
270 .is_valid = always_valid,
271 .moveset = moveset_URF,
272
273 .pre_trans = uf,
274};
275
276/* DR steps **************************/
277Step
278drany_HTM = {
279 .shortname = "dr",
280 .name = "DR on any axis",
281
282 .estimate = estimate_drany_HTM,
283 .ready = check_centers,
284 .ready_msg = check_centers_msg,
285 .is_valid = validate_singlecw_ending,
286 .moveset = moveset_HTM,
287
288 .pre_trans = uf,
289};
290
291Step
292drud_HTM = {
293 .shortname = "drud",
294 .name = "DR on U/D",
295
296 .estimate = estimate_drud_HTM,
297 .ready = check_centers,
298 .ready_msg = check_centers_msg,
299 .is_valid = validate_singlecw_ending,
300 .moveset = moveset_HTM,
301
302 .pre_trans = uf,
303};
304
305Step
306drrl_HTM = {
307 .shortname = "drrl",
308 .name = "DR on R/L",
309
310 .estimate = estimate_drud_HTM,
311 .ready = check_centers,
312 .ready_msg = check_centers_msg,
313 .is_valid = validate_singlecw_ending,
314 .moveset = moveset_HTM,
315
316 .pre_trans = rf,
317};
318
319Step
320drfb_HTM = {
321 .shortname = "drfb",
322 .name = "DR on F/B",
323
324 .estimate = estimate_drud_HTM,
325 .ready = check_centers,
326 .ready_msg = check_centers_msg,
327 .is_valid = validate_singlecw_ending,
328 .moveset = moveset_HTM,
329
330 .pre_trans = fd,
331};
332
333/* DR from EO */
334Step
335dr_eo = {
336 .shortname = "dr-eo",
337 .name = "DR without breaking EO (automatically detected)",
338
339 .estimate = estimate_dr_eofb,
340 .ready = check_eofb,
341 .ready_msg = check_eo_msg,
342 .is_valid = validate_singlecw_ending,
343 .moveset = moveset_eofb,
344
345 .detect = detect_pretrans_eofb,
346};
347
348Step
349dr_eofb = {
350 .shortname = "dr-eofb",
351 .name = "DR on U/D or R/L without breaking EO on F/B",
352
353 .estimate = estimate_dr_eofb,
354 .ready = check_eofb,
355 .ready_msg = check_eo_msg,
356 .is_valid = validate_singlecw_ending,
357 .moveset = moveset_eofb,
358
359 .pre_trans = uf,
360};
361
362Step
363dr_eorl = {
364 .shortname = "dr-eorl",
365 .name = "DR on U/D or F/B without breaking EO on R/L",
366
367 .estimate = estimate_dr_eofb,
368 .ready = check_eofb,
369 .ready_msg = check_eo_msg,
370 .is_valid = validate_singlecw_ending,
371 .moveset = moveset_eofb,
372
373 .pre_trans = ur,
374};
375
376Step
377dr_eoud = {
378 .shortname = "dr-eoud",
379 .name = "DR on R/L or F/B without breaking EO on U/R",
380
381 .estimate = estimate_dr_eofb,
382 .ready = check_eofb,
383 .ready_msg = check_eo_msg,
384 .is_valid = validate_singlecw_ending,
385 .moveset = moveset_eofb,
386
387 .pre_trans = fd,
388};
389
390Step
391drud_eofb = {
392 .shortname = "drud-eofb",
393 .name = "DR on U/D without breaking EO on F/B",
394
395 .estimate = estimate_drud_eofb,
396 .ready = check_eofb,
397 .ready_msg = check_eo_msg,
398 .is_valid = validate_singlecw_ending,
399 .moveset = moveset_eofb,
400
401 .pre_trans = uf,
402};
403
404Step
405drrl_eofb = {
406 .shortname = "drrl-eofb",
407 .name = "DR on R/L without breaking EO on F/B",
408
409 .estimate = estimate_drud_eofb,
410 .ready = check_eofb,
411 .ready_msg = check_eo_msg,
412 .is_valid = validate_singlecw_ending,
413 .moveset = moveset_eofb,
414
415 .pre_trans = rf,
416};
417
418Step
419drud_eorl = {
420 .shortname = "drud-eorl",
421 .name = "DR on U/D without breaking EO on R/L",
422
423 .estimate = estimate_drud_eofb,
424 .ready = check_eofb,
425 .ready_msg = check_eo_msg,
426 .is_valid = validate_singlecw_ending,
427 .moveset = moveset_eofb,
428
429 .pre_trans = ur,
430};
431
432Step
433drfb_eorl = {
434 .shortname = "drfb-eorl",
435 .name = "DR on F/B without breaking EO on R/L",
436
437 .estimate = estimate_drud_eofb,
438 .ready = check_eofb,
439 .ready_msg = check_eo_msg,
440 .is_valid = validate_singlecw_ending,
441 .moveset = moveset_eofb,
442
443 .pre_trans = fr,
444};
445
446Step
447drfb_eoud = {
448 .shortname = "drfb-eoud",
449 .name = "DR on F/B without breaking EO on U/D",
450
451 .estimate = estimate_drud_eofb,
452 .ready = check_eofb,
453 .ready_msg = check_eo_msg,
454 .is_valid = validate_singlecw_ending,
455 .moveset = moveset_eofb,
456
457 .pre_trans = fd,
458};
459
460Step
461drrl_eoud = {
462 .shortname = "drrl-eoud",
463 .name = "DR on R/L without breaking EO on U/D",
464
465 .estimate = estimate_drud_eofb,
466 .ready = check_eofb,
467 .ready_msg = check_eo_msg,
468 .is_valid = validate_singlecw_ending,
469 .moveset = moveset_eofb,
470
471 .pre_trans = rd,
472};
473
474/* DR finish steps */
475Step
476dranyfin_DR = {
477 .shortname = "drfin",
478 .name = "DR finish on any axis without breaking DR",
479
480 .estimate = estimate_drudfin_drud,
481 .ready = check_drud,
482 .ready_msg = check_drany_msg,
483 .is_valid = always_valid,
484 .moveset = moveset_drud,
485
486 .detect = detect_pretrans_drud,
487};
488
489Step
490drudfin_drud = {
491 .shortname = "drudfin",
492 .name = "DR finish on U/D without breaking DR",
493
494 .estimate = estimate_drudfin_drud,
495 .ready = check_drud,
496 .ready_msg = check_dr_msg,
497 .is_valid = always_valid,
498 .moveset = moveset_drud,
499
500 .pre_trans = uf,
501};
502
503Step
504drrlfin_drrl = {
505 .shortname = "drrlfin",
506 .name = "DR finish on R/L without breaking DR",
507
508 .estimate = estimate_drudfin_drud,
509 .ready = check_drud,
510 .ready_msg = check_dr_msg,
511 .is_valid = always_valid,
512 .moveset = moveset_drud,
513
514 .pre_trans = rf,
515};
516
517Step
518drfbfin_drfb = {
519 .shortname = "drfbfin",
520 .name = "DR finish on F/B without breaking DR",
521
522 .estimate = estimate_drudfin_drud,
523 .ready = check_drud,
524 .ready_msg = check_dr_msg,
525 .is_valid = always_valid,
526 .moveset = moveset_drud,
527
528 .pre_trans = fd,
529};
530
531/* HTR from DR */
532Step
533htr_any = {
534 .shortname = "htr",
535 .name = "HTR from DR",
536
537 .estimate = estimate_htr_drud,
538 .ready = check_drud,
539 .ready_msg = check_drany_msg,
540 .is_valid = validate_singlecw_ending,
541 .moveset = moveset_drud,
542
543 .detect = detect_pretrans_drud,
544};
545
546Step
547htr_drud = {
548 .shortname = "htr-drud",
549 .name = "HTR from DR on U/D",
550
551 .estimate = estimate_htr_drud,
552 .ready = check_drud,
553 .ready_msg = check_dr_msg,
554 .is_valid = validate_singlecw_ending,
555 .moveset = moveset_drud,
556
557 .pre_trans = uf,
558};
559
560Step
561htr_drrl = {
562 .shortname = "htr-drrl",
563 .name = "HTR from DR on R/L",
564
565 .estimate = estimate_htr_drud,
566 .ready = check_drud,
567 .ready_msg = check_dr_msg,
568 .is_valid = validate_singlecw_ending,
569 .moveset = moveset_drud,
570
571 .pre_trans = rf,
572};
573
574Step
575htr_drfb = {
576 .shortname = "htr-drfb",
577 .name = "HTR from DR on F/B",
578
579 .estimate = estimate_htr_drud,
580 .ready = check_drud,
581 .ready_msg = check_dr_msg,
582 .is_valid = validate_singlecw_ending,
583 .moveset = moveset_drud,
584
585 .pre_trans = fd,
586};
587
588/* HTR finish */
589Step
590htrfin_htr = {
591 .shortname = "htrfin",
592 .name = "HTR finish without breaking HTR",
593
594 .estimate = estimate_htrfin_htr,
595 .ready = check_htr,
596 .ready_msg = check_htr_msg,
597 .is_valid = always_valid,
598 .moveset = moveset_htr,
599
600 .pre_trans = uf,
601};
602
603Step *steps[NSTEPS] = {
604 &optimal_HTM, /* first is default */
605
606 &eoany_HTM,
607 &eofb_HTM,
608 &eorl_HTM,
609 &eoud_HTM,
610
611 &coany_HTM,
612 &coud_HTM,
613 &corl_HTM,
614 &cofb_HTM,
615
616 &coany_URF,
617 &coud_URF,
618 &corl_URF,
619 &cofb_URF,
620
621 &drany_HTM,
622 &drud_HTM,
623 &drrl_HTM,
624 &drfb_HTM,
625
626 &dr_eo,
627 &dr_eofb,
628 &dr_eorl,
629 &dr_eoud,
630 &drud_eofb,
631 &drrl_eofb,
632 &drud_eorl,
633 &drfb_eorl,
634 &drfb_eoud,
635 &drrl_eoud,
636
637 &dranyfin_DR,
638 &drudfin_drud,
639 &drrlfin_drrl,
640 &drfbfin_drfb,
641
642 &htr_any,
643 &htr_drud,
644 &htr_drrl,
645 &htr_drfb,
646
647 &htrfin_htr,
648
649 &cornershtr_HTM,
650 &cornershtr_URF,
651 &corners_HTM,
652 &corners_URF,
653};
654
655/* Checkers, estimators and validators ***************************************/
656
657static bool
658check_centers(Cube cube)
659{
660 return cube.cpos == 0;
661}
662
663static bool
664check_eofb(Cube cube)
665{
666 return cube.eofb == 0;
667}
668
669static bool
670check_drud(Cube cube)
671{
672 return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0;
673}
674
675static bool
676check_htr(Cube cube)
677{
678 return check_drud(cube) && coord_htr_drud.index(cube) == 0;
679}
680
681static int
682estimate_eoany_HTM(CubeTarget ct)
683{
684 int r1, r2, r3;
685
686 r1 = ptableval(&pd_eofb_HTM, ct.cube);
687 r2 = ptableval(&pd_eofb_HTM, apply_trans(ur, ct.cube));
688 r3 = ptableval(&pd_eofb_HTM, apply_trans(fd, ct.cube));
689
690 return MIN(r1, MIN(r2, r3));
691}
692
693static int
694estimate_eofb_HTM(CubeTarget ct)
695{
696 return ptableval(&pd_eofb_HTM, ct.cube);
697}
698
699static int
700estimate_coany_HTM(CubeTarget ct)
701{
702 int r1, r2, r3;
703
704 r1 = ptableval(&pd_coud_HTM, ct.cube);
705 r2 = ptableval(&pd_coud_HTM, apply_trans(rf, ct.cube));
706 r3 = ptableval(&pd_coud_HTM, apply_trans(fd, ct.cube));
707
708 return MIN(r1, MIN(r2, r3));
709}
710
711static int
712estimate_coud_HTM(CubeTarget ct)
713{
714 return ptableval(&pd_coud_HTM, ct.cube);
715}
716
717static int
718estimate_coany_URF(CubeTarget ct)
719{
720 int r1, r2, r3;
721 CubeTarget ct2, ct3;
722
723 ct2.cube = apply_trans(rf, ct.cube);
724 ct2.target = ct.target;
725
726 ct3.cube = apply_trans(fd, ct.cube);
727 ct3.target = ct.target;
728
729 r1 = estimate_coud_URF(ct);
730 r2 = estimate_coud_URF(ct2);
731 r3 = estimate_coud_URF(ct3);
732
733 return MIN(r1, MIN(r2, r3));
734}
735
736static int
737estimate_coud_URF(CubeTarget ct)
738{
739 /* TODO: I can improve this by checking first the orientation of
740 * the corner in DBL and use that as a reference */
741
742 CubeTarget ct2 = {.cube = apply_move(z, ct.cube), .target = ct.target};
743 CubeTarget ct3 = {.cube = apply_move(x, ct.cube), .target = ct.target};
744
745 int ud = estimate_coud_HTM(ct);
746 int rl = estimate_coud_HTM(ct2);
747 int fb = estimate_coud_HTM(ct3);
748
749 return MIN(ud, MIN(rl, fb));
750}
751
752static int
753estimate_corners_HTM(CubeTarget ct)
754{
755 return ptableval(&pd_corners_HTM, ct.cube);
756}
757
758static int
759estimate_cornershtr_HTM(CubeTarget ct)
760{
761 return ptableval(&pd_cornershtr_HTM, ct.cube);
762}
763
764static int
765estimate_cornershtr_URF(CubeTarget ct)
766{
767 /* TODO: I can improve this by checking first the corner in DBL
768 * and use that as a reference */
769
770 int c, ret = 15;
771 Trans i;
772
773 for (i = 0; i < NROTATIONS; i++) {
774 ct.cube = apply_alg(rotation_alg(i), ct.cube);
775 c = estimate_cornershtr_HTM(ct);
776 ret = MIN(ret, c);
777 }
778
779 return ret;
780}
781
782static int
783estimate_corners_URF(CubeTarget ct)
784{
785 /* TODO: I can improve this by checking first the corner in DBL
786 * and use that as a reference */
787
788 int c, ret = 15;
789 Trans i;
790
791 for (i = 0; i < NROTATIONS; i++) {
792 ct.cube = apply_alg(rotation_alg(i), ct.cube);
793 c = estimate_corners_HTM(ct);
794 ret = MIN(ret, c);
795 }
796
797 return ret;
798}
799
800static int
801estimate_drany_HTM(CubeTarget ct)
802{
803 int r1, r2, r3;
804
805 r1 = ptableval(&pd_drud_sym16_HTM, ct.cube);
806 r2 = ptableval(&pd_drud_sym16_HTM, apply_trans(rf, ct.cube));
807 r3 = ptableval(&pd_drud_sym16_HTM, apply_trans(fd, ct.cube));
808
809 return MIN(r1, MIN(r2, r3));
810}
811
812static int
813estimate_drud_HTM(CubeTarget ct)
814{
815 return ptableval(&pd_drud_sym16_HTM, ct.cube);
816}
817
818static int
819estimate_drud_eofb(CubeTarget ct)
820{
821 return ptableval(&pd_drud_eofb, ct.cube);
822}
823
824static int
825estimate_dr_eofb(CubeTarget ct)
826{
827 int r1, r2;
828
829 r1 = ptableval(&pd_drud_eofb, ct.cube);
830 r2 = ptableval(&pd_drud_eofb, apply_trans(rf, ct.cube));
831
832 return MIN(r1, r2);
833}
834
835static int
836estimate_drudfin_drud(CubeTarget ct)
837{
838 int val = ptableval(&pd_drudfin_noE_sym16_drud, ct.cube);
839
840 if (val != 0)
841 return val;
842
843 return ct.cube.epose % 24 == 0 ? 0 : 1;
844}
845
846static int
847estimate_htr_drud(CubeTarget ct)
848{
849 return ptableval(&pd_htr_drud, ct.cube);
850}
851
852static int
853estimate_htrfin_htr(CubeTarget ct)
854{
855 return ptableval(&pd_htrfin_htr, ct.cube);
856}
857
858static int
859estimate_optimal_HTM(CubeTarget ct)
860{
861 int dr1, dr2, dr3, cor, ret;
862 Cube cube = ct.cube;
863
864 dr1 = ptableval(&pd_khuge_HTM, cube);
865 cor = estimate_corners_HTM(ct);
866 ret = MAX(dr1, cor);
867
868 if (ret > ct.target)
869 return ret;
870
871 cube = apply_trans(rf, ct.cube);
872 dr2 = ptableval(&pd_khuge_HTM, cube);
873 ret = MAX(ret, dr2);
874
875 if (ret > ct.target)
876 return ret;
877
878 cube = apply_trans(fd, ct.cube);
879 dr3 = ptableval(&pd_khuge_HTM, cube);
880
881 /* Michiel de Bondt's trick */
882 if (dr1 == dr2 && dr2 == dr3 && dr1 != 0)
883 dr3++;
884
885 return MAX(ret, dr3);
886}
887
888static bool
889always_valid(Alg *alg)
890{
891 return true;
892}
893
894static bool
895validate_singlecw_ending(Alg *alg)
896{
897 int i;
898 bool nor, inv;
899 Move l2 = NULLMOVE, l1 = NULLMOVE, l2i = NULLMOVE, l1i = NULLMOVE;
900
901 for (i = 0; i < alg->len; i++) {
902 if (alg->inv[i]) {
903 l2i = l1i;
904 l1i = alg->move[i];
905 } else {
906 l2 = l1;
907 l1 = alg->move[i];
908 }
909 }
910
911 nor = l1 ==base_move(l1) && (!commute(l1, l2) ||l2 ==base_move(l2));
912 inv = l1i==base_move(l1i) && (!commute(l1i,l2i)||l2i==base_move(l2i));
913
914 return nor && inv;
915}
916
917/* Pre-transformation detectors **********************************************/
918
919static Trans
920detect_pretrans_eofb(Cube cube)
921{
922 Trans i;
923
924 for (i = 0; i < NROTATIONS; i++)
925 if (check_eofb(apply_trans(i, cube)))
926 return i;
927
928 return 0;
929}
930
931static Trans
932detect_pretrans_drud(Cube cube)
933{
934 Trans i;
935
936 for (i = 0; i < NROTATIONS; i++)
937 if (check_drud(apply_trans(i, cube)))
938 return i;
939
940 return 0;
941}
diff --git a/src/steps.h b/src/steps.h
new file mode 100644
index 0000000..aa3178c
--- /dev/null
+++ b/src/steps.h
@@ -0,0 +1,10 @@
1#ifndef STEPS_H
2#define STEPS_H
3
4#include "pruning.h"
5
6#define NSTEPS 50
7
8extern Step * steps[NSTEPS];
9
10#endif
diff --git a/src/symcoord.c b/src/symcoord.c
new file mode 100644
index 0000000..97a8d9a
--- /dev/null
+++ b/src/symcoord.c
@@ -0,0 +1,355 @@
1#include "symcoord.h"
2
3static Cube antindex_coud_sym16(uint64_t ind);
4static Cube antindex_cp_sym16(uint64_t ind);
5static Cube antindex_eofbepos_sym16(uint64_t ind);
6static Cube antindex_drud_sym16(uint64_t ind);
7static Cube antindex_drudfin_noE_sym16(uint64_t ind);
8static Cube antindex_khuge(uint64_t ind);
9
10static uint64_t index_coud_sym16(Cube cube);
11static uint64_t index_cp_sym16(Cube cube);
12static uint64_t index_eofbepos_sym16(Cube cube);
13static uint64_t index_drud_sym16(Cube cube);
14static uint64_t index_drudfin_noE_sym16(Cube cube);
15static uint64_t index_khuge(Cube cube);
16
17static void gensym(SymData *sd);
18static bool read_symdata_file(SymData *sd);
19static bool write_symdata_file(SymData *sd);
20
21/* Transformation groups and symmetry data ***********************************/
22
23static Trans
24trans_group_udfix[16] = {
25 uf, ur, ub, ul,
26 df, dr, db, dl,
27 uf_mirror, ur_mirror, ub_mirror, ul_mirror,
28 df_mirror, dr_mirror, db_mirror, dl_mirror,
29};
30
31static SymData
32sd_coud_16 = {
33 .filename = "sd_coud_16",
34 .coord = &coord_coud,
35 .sym_coord = &coord_coud_sym16,
36 .ntrans = 16,
37 .trans = trans_group_udfix
38};
39
40static SymData
41sd_cp_16 = {
42 .filename = "sd_cp_16",
43 .coord = &coord_cp,
44 .sym_coord = &coord_cp_sym16,
45 .ntrans = 16,
46 .trans = trans_group_udfix
47};
48
49static SymData
50sd_eofbepos_16 = {
51 .filename = "sd_eofbepos_16",
52 .coord = &coord_eofbepos,
53 .sym_coord = &coord_eofbepos_sym16,
54 .ntrans = 16,
55 .trans = trans_group_udfix
56};
57
58static int nsymdata = 3;
59static SymData * all_sd[] = {
60 &sd_coud_16,
61 &sd_cp_16,
62 &sd_eofbepos_16,
63};
64
65
66/* Coordinates and their implementation **************************************/
67
68Coordinate
69coord_eofbepos_sym16 = {
70 .index = index_eofbepos_sym16,
71 .cube = antindex_eofbepos_sym16,
72 .ntrans = 16,
73 .trans = trans_group_udfix,
74};
75
76Coordinate
77coord_coud_sym16 = {
78 .index = index_coud_sym16,
79 .cube = antindex_coud_sym16,
80 .ntrans = 16,
81 .trans = trans_group_udfix,
82};
83
84Coordinate
85coord_cp_sym16 = {
86 .index = index_cp_sym16,
87 .cube = antindex_cp_sym16,
88 .ntrans = 16,
89 .trans = trans_group_udfix,
90};
91
92Coordinate
93coord_drud_sym16 = {
94 .index = index_drud_sym16,
95 .cube = antindex_drud_sym16,
96 .max = POW3TO7 * 64430,
97 .ntrans = 16,
98 .trans = trans_group_udfix,
99};
100
101Coordinate
102coord_drudfin_noE_sym16 = {
103 .index = index_drudfin_noE_sym16,
104 .cube = antindex_drudfin_noE_sym16,
105 .max = FACTORIAL8 * 2768,
106 .ntrans = 16,
107 .trans = trans_group_udfix,
108};
109
110Coordinate
111coord_khuge = {
112 .index = index_khuge,
113 .cube = antindex_khuge,
114 .max = POW3TO7 * FACTORIAL4 * 64430,
115 .ntrans = 16,
116 .trans = trans_group_udfix,
117};
118
119/* Functions *****************************************************************/
120
121static Cube
122antindex_coud_sym16(uint64_t ind)
123{
124 return sd_coud_16.rep[ind];
125}
126
127static Cube
128antindex_cp_sym16(uint64_t ind)
129{
130 return sd_cp_16.rep[ind];
131}
132
133static Cube
134antindex_eofbepos_sym16(uint64_t ind)
135{
136 return sd_eofbepos_16.rep[ind];
137}
138
139static Cube
140antindex_drud_sym16(uint64_t ind)
141{
142 Cube c;
143
144 c = antindex_eofbepos_sym16(ind/POW3TO7);
145 c.coud = ind % POW3TO7;
146 c.cofb = c.coud;
147 c.corl = c.coud;
148
149 return c;
150}
151
152static Cube
153antindex_drudfin_noE_sym16(uint64_t ind)
154{
155 Cube c1, c2;
156
157 c1 = coord_epud.cube(ind % FACTORIAL8);
158 c2 = antindex_cp_sym16(ind/FACTORIAL8);
159 c1.cp = c2.cp;
160
161 return c1;
162}
163
164static Cube
165antindex_khuge(uint64_t ind)
166{
167 Cube c;
168
169 c = antindex_eofbepos_sym16(ind/(FACTORIAL4*POW3TO7));
170 c.epose = ((c.epose / 24) * 24) + ((ind/POW3TO7) % 24);
171 c.coud = ind % POW3TO7;
172
173 return c;
174}
175
176static uint64_t
177index_coud_sym16(Cube cube)
178{
179 return sd_coud_16.class[coord_coud.index(cube)];
180}
181
182static uint64_t
183index_cp_sym16(Cube cube)
184{
185 return sd_cp_16.class[coord_cp.index(cube)];
186}
187
188static uint64_t
189index_drud_sym16(Cube cube)
190{
191 Trans t;
192 Cube c;
193
194 t = sd_eofbepos_16.transtorep[coord_eofbepos.index(cube)];
195 c = apply_trans(t, cube);
196
197 return index_eofbepos_sym16(c) * POW3TO7 + c.coud;
198}
199
200static uint64_t
201index_drudfin_noE_sym16(Cube cube)
202{
203 Trans t;
204 Cube c;
205
206 t = sd_cp_16.transtorep[coord_cp.index(cube)];
207 c = apply_trans(t, cube);
208
209 return index_cp_sym16(c) * FACTORIAL8 + coord_epud.index(c);
210}
211
212static uint64_t
213index_eofbepos_sym16(Cube cube)
214{
215 return sd_eofbepos_16.class[coord_eofbepos.index(cube)];
216}
217
218static uint64_t
219index_khuge(Cube cube)
220{
221 Trans t;
222 Cube c;
223 uint64_t a;
224
225 t = sd_eofbepos_16.transtorep[coord_eofbepos.index(cube)];
226 c = apply_trans(t, cube);
227 a = (index_eofbepos_sym16(c) * 24) + (c.epose % 24);
228
229 return a * POW3TO7 + c.coud;
230}
231
232/* Other functions ***********************************************************/
233
234static void
235gensym(SymData *sd)
236{
237 uint64_t i, in, nreps = 0;
238 int j;
239 Cube c, d;
240
241 if (sd->generated)
242 return;
243
244 sd->class = malloc(sd->coord->max * sizeof(uint64_t));
245 sd->rep = malloc(sd->coord->max * sizeof(Cube));
246 sd->transtorep = malloc(sd->coord->max * sizeof(Trans));
247
248 if (read_symdata_file(sd)) {
249 sd->generated = true;
250 return;
251 }
252
253 fprintf(stderr, "Cannot load %s, generating it\n", sd->filename);
254
255 for (i = 0; i < sd->coord->max; i++)
256 sd->class[i] = sd->coord->max + 1;
257
258 for (i = 0; i < sd->coord->max; i++) {
259 if (sd->class[i] == sd->coord->max + 1) {
260 c = sd->coord->cube(i);
261 sd->rep[nreps] = c;
262 for (j = 0; j < sd->ntrans; j++) {
263 d = apply_trans(sd->trans[j], c);
264 in = sd->coord->index(d);
265
266 if (sd->class[in] == sd->coord->max + 1) {
267 sd->class[in] = nreps;
268 sd->transtorep[in] =
269 inverse_trans(sd->trans[j]);
270 }
271 }
272 nreps++;
273 }
274 }
275
276 sd->sym_coord->max = nreps;
277 sd->rep = realloc(sd->rep, nreps * sizeof(Cube));
278 sd->generated = true;
279
280 fprintf(stderr, "Found %lu classes\n", nreps);
281
282 if (!write_symdata_file(sd))
283 fprintf(stderr, "Error writing SymData file\n");
284
285 return;
286}
287
288static bool
289read_symdata_file(SymData *sd)
290{
291 init_env();
292
293 FILE *f;
294 char fname[strlen(tabledir)+100];
295 uint64_t n = sd->coord->max, *sn = &sd->sym_coord->max;
296 bool r = true;
297
298 strcpy(fname, tabledir);
299 strcat(fname, "/");
300 strcat(fname, sd->filename);
301
302 if ((f = fopen(fname, "rb")) == NULL)
303 return false;
304
305 r = r && fread(&sd->sym_coord->max, sizeof(uint64_t), 1, f) == 1;
306 r = r && fread(sd->rep, sizeof(Cube), *sn, f) == *sn;
307 r = r && fread(sd->class, sizeof(uint64_t), n, f) == n;
308 r = r && fread(sd->transtorep, sizeof(Trans), n, f) == n;
309
310 fclose(f);
311 return r;
312}
313
314static bool
315write_symdata_file(SymData *sd)
316{
317 init_env();
318
319 FILE *f;
320 char fname[strlen(tabledir)+100];
321 uint64_t n = sd->coord->max, *sn = &sd->sym_coord->max;
322 bool r = true;
323
324 strcpy(fname, tabledir);
325 strcat(fname, "/");
326 strcat(fname, sd->filename);
327
328 if ((f = fopen(fname, "wb")) == NULL)
329 return false;
330
331 r = r && fwrite(&sd->sym_coord->max, sizeof(uint64_t), 1, f) == 1;
332 r = r && fwrite(sd->rep, sizeof(Cube), *sn, f) == *sn;
333 r = r && fwrite(sd->class, sizeof(uint64_t), n, f) == n;
334 r = r && fwrite(sd->transtorep, sizeof(Trans), n, f) == n;
335
336 fclose(f);
337 return r;
338}
339
340void
341init_symcoord()
342{
343 int i;
344
345 static bool initialized = false;
346 if (initialized)
347 return;
348 initialized = true;
349
350 init_coord();
351
352 for (i = 0; i < nsymdata; i++)
353 gensym(all_sd[i]);
354}
355
diff --git a/src/symcoord.h b/src/symcoord.h
new file mode 100644
index 0000000..f231c92
--- /dev/null
+++ b/src/symcoord.h
@@ -0,0 +1,15 @@
1#ifndef SYMCOORD_H
2#define SYMCOORD_H
3
4#include "coord.h"
5
6extern Coordinate coord_coud_sym16;
7extern Coordinate coord_cp_sym16;
8extern Coordinate coord_eofbepos_sym16;
9extern Coordinate coord_drud_sym16;
10extern Coordinate coord_drudfin_noE_sym16;
11extern Coordinate coord_khuge;
12
13void init_symcoord();
14
15#endif
diff --git a/src/trans.c b/src/trans.c
new file mode 100644
index 0000000..2946c58
--- /dev/null
+++ b/src/trans.c
@@ -0,0 +1,375 @@
1#include "trans.h"
2
3/* Local functions ***********************************************************/
4
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 *****************************************************/
10
11static int ep_mirror[12] = {
12 [UF] = UF, [UL] = UR, [UB] = UB, [UR] = UL,
13 [DF] = DF, [DL] = DR, [DB] = DB, [DR] = DL,
14 [FR] = FL, [FL] = FR, [BL] = BR, [BR] = BL
15};
16
17static int cp_mirror[8] = {
18 [UFR] = UFL, [UFL] = UFR, [UBL] = UBR, [UBR] = UBL,
19 [DFR] = DFL, [DFL] = DFR, [DBL] = DBR, [DBR] = DBL
20};
21
22static int cpos_mirror[6] = {
23 [U_center] = U_center, [D_center] = D_center,
24 [R_center] = L_center, [L_center] = R_center,
25 [F_center] = F_center, [B_center] = B_center
26};
27
28/* TODO Is there a more elegant way? */
29static char rotation_alg_string[100][NROTATIONS] = {
30 [uf] = "", [ur] = "y", [ub] = "y2", [ul] = "y3",
31 [df] = "z2", [dr] = "y z2", [db] = "x2", [dl] = "y3 z2",
32 [rf] = "z3", [rd] = "z3 y", [rb] = "z3 y2", [ru] = "z3 y3",
33 [lf] = "z", [ld] = "z y3", [lb] = "z y2", [lu] = "z y",
34 [fu] = "x y2", [fr] = "x y", [fd] = "x", [fl] = "x y3",
35 [bu] = "x3", [br] = "x3 y", [bd] = "x3 y2", [bl] = "x3 y3",
36};
37
38static int epose_source[NTRANS]; /* 0=epose, 1=eposs, 2=eposm */
39static int eposs_source[NTRANS];
40static int eposm_source[NTRANS];
41static int eofb_source[NTRANS]; /* 0=eoud, 1=eorl, 2=eofb */
42static int eorl_source[NTRANS];
43static int eoud_source[NTRANS];
44static int coud_source[NTRANS]; /* 0=coud, 1=corl, 2=cofb */
45static int cofb_source[NTRANS];
46static int corl_source[NTRANS];
47
48static int epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
49static int eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
50static int eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8];
51static int eo_ttable[NTRANS][POW2TO11];
52static int cp_ttable[NTRANS][FACTORIAL8];
53static int co_ttable[NTRANS][POW3TO7];
54static int cpos_ttable[NTRANS][FACTORIAL6];
55static Move moves_ttable[NTRANS][NMOVES];
56
57/* Local functions implementation ********************************************/
58
59static bool
60read_ttables_file()
61{
62 init_env();
63
64 FILE *f;
65 char fname[strlen(tabledir)+20];
66 int b = sizeof(int);
67 bool r = true;
68 Move m;
69
70 /* Table sizes, used for reading and writing files */
71 uint64_t me[11] = {
72 [0] = FACTORIAL12/FACTORIAL8,
73 [1] = FACTORIAL12/FACTORIAL8,
74 [2] = FACTORIAL12/FACTORIAL8,
75 [3] = POW2TO11,
76 [4] = FACTORIAL8,
77 [5] = POW3TO7,
78 [6] = FACTORIAL6,
79 [7] = NMOVES
80 };
81
82 strcpy(fname, tabledir);
83 strcat(fname, "/");
84 strcat(fname, "ttables");
85
86 if ((f = fopen(fname, "rb")) == NULL)
87 return false;
88
89 for (m = 0; m < NTRANS; m++) {
90 r = r && fread(epose_ttable[m], b, me[0], f) == me[0];
91 r = r && fread(eposs_ttable[m], b, me[1], f) == me[1];
92 r = r && fread(eposm_ttable[m], b, me[2], f) == me[2];
93 r = r && fread(eo_ttable[m], b, me[3], f) == me[3];
94 r = r && fread(cp_ttable[m], b, me[4], f) == me[4];
95 r = r && fread(co_ttable[m], b, me[5], f) == me[5];
96 r = r && fread(cpos_ttable[m], b, me[6], f) == me[6];
97 r = r && fread(moves_ttable[m], b, me[7], f) == me[7];
98 }
99
100 fclose(f);
101 return r;
102}
103
104static Cube
105rotate_via_compose(Trans r, Cube c, PieceFilter f)
106{
107 static int zero12[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
108 static int zero8[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
109 static CubeArray ma = {
110 .ep = ep_mirror,
111 .eofb = zero12,
112 .eorl = zero12,
113 .eoud = zero12,
114 .cp = cp_mirror,
115 .coud = zero8,
116 .corl = zero8,
117 .cofb = zero8,
118 .cpos = cpos_mirror
119 };
120
121 Alg *inv = inverse_alg(rotation_alg(r));
122 Cube ret = {0};
123
124 if (r >= NROTATIONS)
125 ret = move_via_arrays(&ma, ret, f);
126 ret = apply_alg_generic(inv, ret, f, true);
127
128 ret = compose_filtered(c, ret, f);
129
130 ret = apply_alg_generic(rotation_alg(r), ret, f, true);
131 if (r >= NROTATIONS)
132 ret = move_via_arrays(&ma, ret, f);
133
134 free_alg(inv);
135 return ret;
136}
137
138static bool
139write_ttables_file()
140{
141 init_env();
142
143 FILE *f;
144 char fname[strlen(tabledir)+20];
145 bool r = true;
146 int b = sizeof(int);
147 Move m;
148
149 /* Table sizes, used for reading and writing files */
150 uint64_t me[11] = {
151 [0] = FACTORIAL12/FACTORIAL8,
152 [1] = FACTORIAL12/FACTORIAL8,
153 [2] = FACTORIAL12/FACTORIAL8,
154 [3] = POW2TO11,
155 [4] = FACTORIAL8,
156 [5] = POW3TO7,
157 [6] = FACTORIAL6,
158 [7] = NMOVES
159 };
160
161 strcpy(fname, tabledir);
162 strcat(fname, "/ttables");
163
164 if ((f = fopen(fname, "wb")) == NULL)
165 return false;
166
167 for (m = 0; m < NTRANS; m++) {
168 r = r && fwrite(epose_ttable[m], b, me[0], f) == me[0];
169 r = r && fwrite(eposs_ttable[m], b, me[1], f) == me[1];
170 r = r && fwrite(eposm_ttable[m], b, me[2], f) == me[2];
171 r = r && fwrite(eo_ttable[m], b, me[3], f) == me[3];
172 r = r && fwrite(cp_ttable[m], b, me[4], f) == me[4];
173 r = r && fwrite(co_ttable[m], b, me[5], f) == me[5];
174 r = r && fwrite(cpos_ttable[m], b, me[6], f) == me[6];
175 r = r && fwrite(moves_ttable[m], b, me[7], f) == me[7];
176 }
177
178 fclose(f);
179 return r;
180}
181
182/* Public functions **********************************************************/
183
184Cube
185apply_trans(Trans t, Cube cube)
186{
187 /*init_trans();*/
188
189 int aux_epos[3] = { cube.epose, cube.eposs, cube.eposm };
190 int aux_eo[3] = { cube.eoud, cube.eorl, cube.eofb };
191 int aux_co[3] = { cube.coud, cube.corl, cube.cofb };
192
193 return (Cube) {
194 .epose = epose_ttable[t][aux_epos[epose_source[t]]],
195 .eposs = eposs_ttable[t][aux_epos[eposs_source[t]]],
196 .eposm = eposm_ttable[t][aux_epos[eposm_source[t]]],
197 .eofb = eo_ttable[t][aux_eo[eofb_source[t]]],
198 .eorl = eo_ttable[t][aux_eo[eorl_source[t]]],
199 .eoud = eo_ttable[t][aux_eo[eoud_source[t]]],
200 .coud = co_ttable[t][aux_co[coud_source[t]]],
201 .corl = co_ttable[t][aux_co[corl_source[t]]],
202 .cofb = co_ttable[t][aux_co[cofb_source[t]]],
203 .cp = cp_ttable[t][cube.cp],
204 .cpos = cpos_ttable[t][cube.cpos]
205 };
206}
207
208Trans
209inverse_trans(Trans t)
210{
211 /* TODO is there a more elegant way? */
212 static Trans inverse_trans_aux[NTRANS] = {
213 [uf] = uf, [ur] = ul, [ul] = ur, [ub] = ub,
214 [df] = df, [dr] = dr, [dl] = dl, [db] = db,
215 [rf] = lf, [rd] = bl, [rb] = rb, [ru] = fr,
216 [lf] = rf, [ld] = br, [lb] = lb, [lu] = fl,
217 [fu] = fu, [fr] = ru, [fd] = bu, [fl] = lu,
218 [bu] = fd, [br] = ld, [bd] = bd, [bl] = rd,
219
220 [uf_mirror] = uf_mirror, [ur_mirror] = ur_mirror,
221 [ul_mirror] = ul_mirror, [ub_mirror] = ub_mirror,
222 [df_mirror] = df_mirror, [dr_mirror] = dl_mirror,
223 [dl_mirror] = dr_mirror, [db_mirror] = db_mirror,
224 [rf_mirror] = rf_mirror, [rd_mirror] = br_mirror,
225 [rb_mirror] = lb_mirror, [ru_mirror] = fl_mirror,
226 [lf_mirror] = lf_mirror, [ld_mirror] = bl_mirror,
227 [lb_mirror] = rb_mirror, [lu_mirror] = fr_mirror,
228 [fu_mirror] = fu_mirror, [fr_mirror] = lu_mirror,
229 [fd_mirror] = bu_mirror, [fl_mirror] = ru_mirror,
230 [bu_mirror] = fd_mirror, [br_mirror] = rd_mirror,
231 [bd_mirror] = bd_mirror, [bl_mirror] = ld_mirror
232 };
233
234 return inverse_trans_aux[t];
235}
236
237Alg *
238rotation_alg(Trans t)
239{
240 int i;
241
242 static Alg *rotation_alg_arr[NROTATIONS];
243 static bool initialized = false;
244
245 if (!initialized) {
246 for (i = 0; i < NROTATIONS; i++)
247 rotation_alg_arr[i] = new_alg(rotation_alg_string[i]);
248
249 initialized = true;
250 }
251
252 return rotation_alg_arr[t % NROTATIONS];
253}
254
255void
256transform_alg(Trans t, Alg *alg)
257{
258 int i;
259
260 /*init_trans();*/
261
262 for (i = 0; i < alg->len; i++)
263 alg->move[i] = moves_ttable[t][alg->move[i]];
264}
265
266void
267init_trans() {
268 static bool initialized = false;
269 if (initialized)
270 return;
271 initialized = true;
272
273 init_moves();
274
275 Cube aux, cube, c[3];
276 CubeArray epcp;
277 int i, eparr[12], eoarr[12], cparr[8], coarr[8];
278 unsigned int ui;
279 Move mi, move;
280 Trans m;
281
282 /* Compute sources */
283 for (i = 0; i < NTRANS; i++) {
284 cube = apply_alg(rotation_alg(i), (Cube){0});
285
286 epose_source[i] = edge_slice(what_edge_at(cube, FR));
287 eposs_source[i] = edge_slice(what_edge_at(cube, UR));
288 eposm_source[i] = edge_slice(what_edge_at(cube, UF));
289 eofb_source[i] = what_center_at(cube, F_center)/2;
290 eorl_source[i] = what_center_at(cube, R_center)/2;
291 eoud_source[i] = what_center_at(cube, U_center)/2;
292 coud_source[i] = what_center_at(cube, U_center)/2;
293 cofb_source[i] = what_center_at(cube, F_center)/2;
294 corl_source[i] = what_center_at(cube, R_center)/2;
295 }
296
297 if (read_ttables_file())
298 return;
299
300 fprintf(stderr, "Cannot load %s, generating it\n", "ttables");
301
302 /* Initialize tables */
303 for (m = 0; m < NTRANS; m++) {
304 epcp = (CubeArray){ .ep = eparr, .cp = cparr };
305 cube = apply_alg(rotation_alg(m), (Cube){0});
306 cube_to_arrays(cube, &epcp, pf_epcp);
307 if (m >= NROTATIONS) {
308 apply_permutation(ep_mirror, eparr, 12);
309 apply_permutation(cp_mirror, cparr, 8);
310 }
311
312 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
313 c[0] = admissible_ep((Cube){ .epose = ui }, pf_e);
314 c[1] = admissible_ep((Cube){ .eposs = ui }, pf_s);
315 c[2] = admissible_ep((Cube){ .eposm = ui }, pf_m);
316
317 cube = rotate_via_compose(m,c[epose_source[m]],pf_ep);
318 epose_ttable[m][ui] = cube.epose;
319
320 cube = rotate_via_compose(m,c[eposs_source[m]],pf_ep);
321 eposs_ttable[m][ui] = cube.eposs;
322
323 cube = rotate_via_compose(m,c[eposm_source[m]],pf_ep);
324 eposm_ttable[m][ui] = cube.eposm;
325 }
326 for (ui = 0; ui < POW2TO11; ui++ ) {
327 int_to_sum_zero_array(ui, 2, 12, eoarr);
328 apply_permutation(eparr, eoarr, 12);
329 eo_ttable[m][ui] = digit_array_to_int(eoarr, 11, 2);
330 }
331 for (ui = 0; ui < POW3TO7; ui++) {
332 int_to_sum_zero_array(ui, 3, 8, coarr);
333 apply_permutation(cparr, coarr, 8);
334 co_ttable[m][ui] = digit_array_to_int(coarr, 7, 3);
335 if (m >= NROTATIONS)
336 co_ttable[m][ui] =
337 invert_digits(co_ttable[m][ui], 3, 7);
338 }
339 for (ui = 0; ui < FACTORIAL8; ui++) {
340 cube = (Cube){ .cp = ui };
341 cube = rotate_via_compose(m, cube, pf_cp);
342 cp_ttable[m][ui] = cube.cp;
343 }
344 for (ui = 0; ui < FACTORIAL6; ui++) {
345 cube = (Cube){ .cpos = ui };
346 cube = rotate_via_compose(m, cube, pf_cpos);
347 cpos_ttable[m][ui] = cube.cpos;
348 }
349 for (mi = 0; mi < NMOVES; mi++) {
350 /* Old version:
351 *
352 aux = apply_trans(m, apply_move(mi, (Cube){0}));
353 for (move = 0; move < NMOVES; move++) {
354 cube = apply_move(inverse_move(move), aux);
355 mirr = apply_trans(uf_mirror, cube);
356 if (is_solved(cube) || is_solved(mirr))
357 moves_ttable[m][mi] = move;
358 }
359 */
360
361 aux = apply_trans(m, apply_move(mi, (Cube){0}));
362 for (move = 0; move < NMOVES; move++) {
363 cube = apply_move(inverse_move(move), aux);
364 if (is_solved(cube)) {
365 moves_ttable[m][mi] = move;
366 break;
367 }
368 }
369 }
370 }
371
372 if (!write_ttables_file())
373 fprintf(stderr, "Error writing ttables\n");
374}
375
diff --git a/src/trans.h b/src/trans.h
new file mode 100644
index 0000000..2eda568
--- /dev/null
+++ b/src/trans.h
@@ -0,0 +1,13 @@
1#ifndef TRANS_H
2#define TRANS_H
3
4#include "moves.h"
5
6Cube apply_trans(Trans t, Cube cube);
7Trans inverse_trans(Trans t);
8Alg * rotation_alg(Trans i);
9void transform_alg(Trans i, Alg *alg);
10
11void init_trans();
12
13#endif
diff --git a/src/utils.c b/src/utils.c
index 5b7df06..f72a00e 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -1,132 +1,274 @@
1#include "utils.h" 1#include "utils.h"
2 2
3/* Hardcoded factorial of small numbers (n<=12). */ 3void
4int factorial[13] = { 4apply_permutation(int *perm, int *set, int n)
5 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600 5{
6}; 6 int *aux = malloc(n * sizeof(int));
7 int i;
7 8
8/* swaps two integers */ 9 if (!is_perm(perm, n))
9void swap(int *a, int *b) { 10 return;
10 int aux = *a; 11
11 *a = *b; 12 for (i = 0; i < n; i++)
12 *b = aux; 13 aux[i] = set[perm[i]];
14
15 memcpy(set, aux, n * sizeof(int));
16 free(aux);
17}
18
19int
20binomial(int n, int k)
21{
22 if (n < 0 || k < 0 || k > n)
23 return 0;
24
25 return factorial(n) / (factorial(k) * factorial(n-k));
26}
27
28int
29digit_array_to_int(int *a, int n, int b)
30{
31 int i, ret = 0, p = 1;
32
33 for (i = 0; i < n; i++, p *= b)
34 ret += a[i] * p;
35
36 return ret;
37}
38
39int
40factorial(int n)
41{
42 int i, ret = 1;
43
44 if (n < 0)
45 return 0;
46
47 for (i = 1; i <= n; i++)
48 ret *= i;
49
50 return ret;
51}
52
53void
54index_to_perm(int p, int n, int *r)
55{
56 int *a = malloc(n * sizeof(int));
57 int i, j, c;
58
59 for (i = 0; i < n; i++)
60 a[i] = 0;
61
62 if (p < 0 || p >= factorial(n))
63 for (i = 0; i < n; i++)
64 r[i] = -1;
65
66 for (i = 0; i < n; i++) {
67 c = 0;
68 j = 0;
69 while (c <= p / factorial(n-i-1))
70 c += a[j++] ? 0 : 1;
71 r[i] = j-1;
72 a[j-1] = 1;
73 p %= factorial(n-i-1);
74 }
75
76 free(a);
77}
78
79void
80index_to_subset(int s, int n, int k, int *r)
81{
82 int i, j, v;
83
84 if (s < 0 || s >= binomial(n, k)) {
85 for (i = 0; i < n; i++)
86 r[i] = -1;
87 return;
88 }
89
90 for (i = 0; i < n; i++) {
91 if (k == n-i) {
92 for (j = i; j < n; j++)
93 r[j] = 1;
94 return;
95 }
96
97 if (k == 0) {
98 for (j = i; j < n; j++)
99 r[j] = 0;
100 return;
101 }
102
103 v = binomial(n-i-1, k);
104 if (s >= v) {
105 r[i] = 1;
106 k--;
107 s -= v;
108 } else {
109 r[i] = 0;
110 }
111 }
112}
113
114void
115int_to_digit_array(int a, int b, int n, int *r)
116{
117 int i;
118
119 if (b <= 1)
120 for (i = 0; i < n; i++)
121 r[i] = 0;
122 else
123 for (i = 0; i < n; i++, a /= b)
124 r[i] = a % b;
125}
126
127void
128int_to_sum_zero_array(int x, int b, int n, int *a)
129{
130 int i, s = 0;
131
132 if (b <= 1) {
133 for (i = 0; i < n; i++)
134 a[i] = 0;
135 } else {
136 int_to_digit_array(x, b, n-1, a);
137 for (i = 0; i < n - 1; i++)
138 s = (s + a[i]) % b;
139 a[n-1] = (b - s) % b;
140 }
13} 141}
14 142
15/* Converts the integer a to its representation in base b (first n digits 143int
16 * only) and saves the result in r. */ 144invert_digits(int a, int b, int n)
17void int_to_digit_array(int a, int b, int n, int *r) { 145{
18 for (int i = 0; i < n; i++) { 146 int i, ret, *r = malloc(n * sizeof(int));
19 r[i] = a % b; 147
20 a /= b; 148 int_to_digit_array(a, b, n, r);
21 } 149 for (i = 0; i < n; i++)
150 r[i] = (b-r[i]) % b;
151
152 ret = digit_array_to_int(r, n, b);
153 free(r);
154 return ret;
22} 155}
23 156
24/* Converts the array of n digits a to a integer using base b. */ 157bool
25int digit_array_to_int(int *a, int n, int b) { 158is_perm(int *a, int n)
26 int ret = 0, p = 1; 159{
27 for (int i = 0; i < n; i++) { 160 int *aux = malloc(n * sizeof(int));
28 ret += a[i] * p; 161 int i;
29 p *= b; 162
30 } 163 for (i = 0; i < n; i++)
31 return ret; 164 if (a[i] < 0 || a[i] >= n)
165 return false;
166 else
167 aux[a[i]] = 1;
168
169 for (i = 0; i < n; i++)
170 if (!aux[i])
171 return false;
172
173 free(aux);
174
175 return true;
32} 176}
33 177
34/* Converts a permutation on [0..(n-1)] into the integer i which is the index 178bool
35 * of the permutation in the sorted list of all n! such permutations. 179is_subset(int *a, int n, int k)
36 * Only works for n<=12. */ 180{
37int perm_to_index(int *a, int n) { 181 int i, sum = 0;
38 int ret = 0; 182
39 for (int i = 0; i < n; i++) { 183 for (i = 0; i < n; i++)
40 int c = 0; 184 sum += a[i] ? 1 : 0;
41 for (int j = i+1; j < n; j++) 185
42 if (a[i] > a[j]) 186 return sum == k;
43 c++;
44 ret += factorial[n-i-1] * c;
45 }
46 return ret;
47} 187}
48 188
49/* Converts a permutation index to the actual permutation as an array 189int
50 * (see perm_to_index) and saves the result to r. */ 190perm_sign(int *a, int n)
51void index_to_perm(int p, int n, int *r) { 191{
52 int a[n]; 192 int i, j, ret = 0;
53 for (int j = 0; j < n; j++) 193
54 a[j] = 0; /* picked elements */ 194 if (!is_perm(a,n))
55 for (int i = 0; i < n; i++) { 195 return -1;
56 int c = 0, j = 0; 196
57 while (c <= p / factorial[n-i-1]) { 197 for (i = 0; i < n; i++)
58 if (!a[j]) 198 for (j = i+1; j < n; j++)
59 c++; 199 ret += (a[i] > a[j]) ? 1 : 0;
60 j++; 200
61 } 201 return ret % 2;
62 r[i] = j-1;
63 a[j-1] = 1;
64 p %= factorial[n-i-1];
65 }
66} 202}
67 203
204int
205perm_to_index(int *a, int n)
206{
207 int i, j, c, ret = 0;
208
209 if (!is_perm(a, n))
210 return -1;
68 211
69int perm_sign_array(int a[], int n) { 212 for (i = 0; i < n; i++) {
70 int ret = 0; 213 c = 0;
71 for (int i = 0; i < n; i++) 214 for (j = i+1; j < n; j++)
72 for (int j = i+1; j < n; j++) 215 c += (a[i] > a[j]) ? 1 : 0;
73 if (a[i]>a[j]) 216 ret += factorial(n-i-1) * c;
74 ret++; 217 }
75 return ret % 2; 218
219 return ret;
76} 220}
77 221
78int perm_sign_int(int p, int n) { 222int
79 int a[n]; 223powint(int a, int b)
80 index_to_perm(p, n, a); 224{
81 return perm_sign_array(a, n); 225 if (b < 0)
226 return 0;
227 if (b == 0)
228 return 1;
229
230 if (b % 2)
231 return a * powint(a, b-1);
232 else
233 return powint(a*a, b/2);
82} 234}
83 235
236int
237subset_to_index(int *a, int n, int k)
238{
239 int i, ret = 0;
240
241 if (!is_subset(a, n, k))
242 return binomial(n, k);
84 243
85/* Converts a k-element subset of a set with an element from an array of n 244 for (i = 0; i < n; i++) {
86 * elements, of which k are 1 (or just non-zero) and n-k are 0, to its index 245 if (k == n-i)
87 * in the sorted list of all such subsets. 246 return ret;
88 * Works only for n <= 12. */ 247 if (a[i]) {
89int subset_to_index(int *a, int n, int k) { 248 ret += binomial(n-i-1, k);
90 int ret = 0; 249 k--;
91 for (int i = 0; i < n; i++) { 250 }
92 if (k == n-i) 251 }
93 return ret; 252
94 if (a[i]) { 253 return ret;
95 ret += factorial[n-i-1] / (factorial[k] * factorial[n-i-1-k]);
96 k--;
97 }
98 }
99 return ret;
100} 254}
101 255
102/* Inverse of the above */ 256void
103void index_to_subset(int s, int n, int k, int *r) { 257sum_arrays_mod(int *src, int *dst, int n, int m)
104 for (int i = 0; i < n; i++) { 258{
105 if (k == n-i) { 259 int i;
106 for (int j = i; j < n; j++) 260
107 r[j] = 1; 261 for (i = 0; i < n; i++)
108 return; 262 dst[i] = (m <= 0) ? 0 : (src[i] + dst[i]) % m;
109 }
110 int v = factorial[n-i-1] / (factorial[k] * factorial[n-i-1-k]);
111 if (s >= v) {
112 r[i] = 1;
113 k--;
114 s -= v;
115 } else {
116 r[i] = 0;
117 }
118 }
119} 263}
120 264
121/* Converts the first n-1 digits of a number to an array a of digits in base b; 265void
122 * then adds one element to the array, so that the sum of the elements of a is 266swap(int *a, int *b)
123 * zero modulo b. 267{
124 * This is used for determing the edge orientation from an 11-bits integer or 268 int aux;
125 * the corner orientation from a 7-trits integer. */ 269
126void int_to_sum_zero_array(int x, int b, int n, int *a) { 270 aux = *a;
127 int_to_digit_array(x, b, n-1, a); 271 *a = *b;
128 int s = 0; 272 *b = aux;
129 for (int i = 0; i < n - 1; i++) s = (s + a[i]) % b;
130 a[n-1] = (b - s) % b;
131} 273}
132 274
diff --git a/src/utils.h b/src/utils.h
index 45a6302..80c33ae 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -1,58 +1,41 @@
1#define min(a,b) (((a) < (b)) ? (a) : (b)) 1#ifndef UTILS_H
2#define max(a,b) (((a) > (b)) ? (a) : (b)) 2#define UTILS_H
3#define abs(a) (((a) > 0) ? (a) : (-(a)))
4 3
5/* Some useful constants */ 4#include <stdbool.h>
6#define pow2to11 2048 5#include <stdlib.h>
7#define pow2to12 4096 6#include <string.h>
8#define pow3to7 2187
9#define pow3to8 6561
10#define pow12to4 20736
11#define factorial4 24
12#define factorial6 720
13#define factorial8 40320
14#define factorial12 479001600
15#define binom12on4 495
16#define binom8on4 70
17 7
18void swap(int *a, int *b); 8#define POW2TO6 64ULL
9#define POW2TO11 2048ULL
10#define POW2TO12 4096ULL
11#define POW3TO7 2187ULL
12#define POW3TO8 6561ULL
13#define FACTORIAL4 24ULL
14#define FACTORIAL6 720ULL
15#define FACTORIAL7 5040ULL
16#define FACTORIAL8 40320ULL
17#define FACTORIAL12 479001600ULL
18#define BINOM12ON4 495ULL
19#define BINOM8ON4 70ULL
20#define MIN(a,b) (((a) < (b)) ? (a) : (b))
21#define MAX(a,b) (((a) > (b)) ? (a) : (b))
19 22
20/* Hardcoded factorial of small numbers (n<=12). */ 23void apply_permutation(int *perm, int *set, int n);
21extern int factorial[13]; 24int binomial(int n, int k);
22 25int digit_array_to_int(int *a, int n, int b);
23/* Converts the integer a to its representation in base b (first n digits 26int factorial(int n);
24 * only) and saves the result in r. */ 27void index_to_perm(int p, int n, int *r);
25void int_to_digit_array(int a, int b, int n, int *r); 28void index_to_subset(int s, int n, int k, int *r);
26 29void int_to_digit_array(int a, int b, int n, int *r);
27/* Converts the array of n digits a to a integer using base b. */ 30void int_to_sum_zero_array(int x, int b, int n, int *a);
28int digit_array_to_int(int *a, int n, int b); 31int invert_digits(int a, int b, int n);
29 32bool is_perm(int *a, int n);
30/* Converts a permutation on [0..(n-1)] into the integer i which is the index 33bool is_subset(int *a, int n, int k);
31 * of the permutation in the sorted list of all n! such permutations. 34int perm_sign(int *a, int n);
32 * Only works for n<=12. */ 35int perm_to_index(int *a, int n);
33int perm_to_index(int *a, int n); 36int powint(int a, int b);
34 37int subset_to_index(int *a, int n, int k);
35/* Converts a permutation index to the actual permutation as an array 38void sum_arrays_mod(int *src, int *dst, int n, int m);
36 * (see perm_to_index) and saves the result to r. */ 39void swap(int *a, int *b);
37void index_to_perm(int p, int n, int *r);
38
39/* Determine the sign of a permutation, either in integer or array format. */
40int perm_sign_array(int a[], int n);
41int perm_sign_int(int p, int n);
42
43/* Converts a k-element subset of a set with an element from an array of n
44 * elements, of which k are 1 and n-k are 0, to its index in the sorted list
45 * of all such subsets.
46 * Works only for n <= 12. */
47int subset_to_index(int *a, int n, int k);
48
49/* Inverse of the above */
50void index_to_subset(int s, int n, int k, int *r);
51
52/* Converts the first n-1 digits of a number to an array a of digits in base b;
53 * then adds one element to the array, so that the sum of the elements of a is
54 * zero modulo b.
55 * This is used for determing the edge orientation from an 11-bits integer or
56 * the corner orientation from a 7-trits integer. */
57void int_to_sum_zero_array(int x, int b, int n, int *a);
58 40
41#endif

Generated with cgit - Back to sebastiano.tronto.net