diff options
| author | Sebastiano Tronto <sebastiano.tronto@gmail.com> | 2021-11-11 21:37:34 +0100 |
|---|---|---|
| committer | Sebastiano Tronto <sebastiano.tronto@gmail.com> | 2021-11-11 21:37:34 +0100 |
| commit | 3568412f8f230774d0d11d7ed1c897424f95d3ef (patch) | |
| tree | 77223792d8c925a9b1fc32b3f4341e943b5f8209 /src | |
| parent | 67e1b5e6e6a2c917a2fe58a37a1382c982b1e5c5 (diff) | |
| download | nissy-3568412f8f230774d0d11d7ed1c897424f95d3ef.tar.gz nissy-3568412f8f230774d0d11d7ed1c897424f95d3ef.zip | |
Rewritten from scratch. Welocme nissy 2.0!
Diffstat (limited to 'src')
| -rw-r--r-- | src/alg.c | 364 | ||||
| -rw-r--r-- | src/alg.h | 35 | ||||
| -rw-r--r-- | src/commands.c | 346 | ||||
| -rw-r--r-- | src/commands.h | 13 | ||||
| -rw-r--r-- | src/coord.c | 522 | ||||
| -rw-r--r-- | src/coord.h | 23 | ||||
| -rw-r--r-- | src/coordinates.c | 286 | ||||
| -rw-r--r-- | src/coordinates.h | 92 | ||||
| -rw-r--r-- | src/cube.c | 701 | ||||
| -rw-r--r-- | src/cube.h | 40 | ||||
| -rw-r--r-- | src/cubetypes.h | 286 | ||||
| -rw-r--r-- | src/env.c | 45 | ||||
| -rw-r--r-- | src/env.h | 15 | ||||
| -rw-r--r-- | src/helppages.h | 689 | ||||
| -rw-r--r-- | src/io.c | 232 | ||||
| -rw-r--r-- | src/io.h | 21 | ||||
| -rw-r--r-- | src/main.c | 937 | ||||
| -rw-r--r-- | src/moves.c | 860 | ||||
| -rw-r--r-- | src/moves.h | 91 | ||||
| -rw-r--r-- | src/pf.c | 80 | ||||
| -rw-r--r-- | src/pf.h | 18 | ||||
| -rw-r--r-- | src/pruning.c | 271 | ||||
| -rw-r--r-- | src/pruning.h | 23 | ||||
| -rw-r--r-- | src/pruning_tables.c | 483 | ||||
| -rw-r--r-- | src/pruning_tables.h | 66 | ||||
| -rw-r--r-- | src/shell.c | 93 | ||||
| -rw-r--r-- | src/shell.h | 13 | ||||
| -rw-r--r-- | src/solve.c | 173 | ||||
| -rw-r--r-- | src/solve.h | 9 | ||||
| -rw-r--r-- | src/solver.c | 1058 | ||||
| -rw-r--r-- | src/solver.h | 16 | ||||
| -rw-r--r-- | src/steps.c | 941 | ||||
| -rw-r--r-- | src/steps.h | 10 | ||||
| -rw-r--r-- | src/symcoord.c | 355 | ||||
| -rw-r--r-- | src/symcoord.h | 15 | ||||
| -rw-r--r-- | src/trans.c | 375 | ||||
| -rw-r--r-- | src/trans.h | 13 | ||||
| -rw-r--r-- | src/utils.c | 356 | ||||
| -rw-r--r-- | src/utils.h | 91 |
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 | |||
| 5 | static void free_alglistnode(AlgListNode *aln); | ||
| 6 | static void realloc_alg(Alg *alg, int n); | ||
| 7 | |||
| 8 | /* Movesets ******************************************************************/ | ||
| 9 | |||
| 10 | bool | ||
| 11 | moveset_HTM(Move m) | ||
| 12 | { | ||
| 13 | return m >= U && m <= B3; | ||
| 14 | } | ||
| 15 | |||
| 16 | bool | ||
| 17 | moveset_URF(Move m) | ||
| 18 | { | ||
| 19 | Move b = base_move(m); | ||
| 20 | |||
| 21 | return b == U || b == R || b == F; | ||
| 22 | } | ||
| 23 | |||
| 24 | bool | ||
| 25 | moveset_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 | |||
| 33 | bool | ||
| 34 | moveset_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 | |||
| 42 | bool | ||
| 43 | moveset_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 | |||
| 53 | void | ||
| 54 | append_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 | |||
| 71 | void | ||
| 72 | append_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 | |||
| 82 | Move | ||
| 83 | base_move(Move m) | ||
| 84 | { | ||
| 85 | if (m == NULLMOVE) | ||
| 86 | return NULLMOVE; | ||
| 87 | else | ||
| 88 | return m - (m-1)%3; | ||
| 89 | } | ||
| 90 | |||
| 91 | void | ||
| 92 | compose_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 | |||
| 100 | void | ||
| 101 | free_alg(Alg *alg) | ||
| 102 | { | ||
| 103 | free(alg->move); | ||
| 104 | free(alg->inv); | ||
| 105 | free(alg); | ||
| 106 | } | ||
| 107 | |||
| 108 | void | ||
| 109 | free_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 | |||
| 121 | static void | ||
| 122 | free_alglistnode(AlgListNode *aln) | ||
| 123 | { | ||
| 124 | free_alg(aln->alg); | ||
| 125 | free(aln); | ||
| 126 | } | ||
| 127 | |||
| 128 | Alg * | ||
| 129 | inverse_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 | |||
| 140 | Move | ||
| 141 | inverse_move(Move m) | ||
| 142 | { | ||
| 143 | return m == NULLMOVE ? NULLMOVE : m + 2 - 2*((m-1) % 3); | ||
| 144 | } | ||
| 145 | |||
| 146 | char * | ||
| 147 | move_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 | |||
| 174 | void | ||
| 175 | movelist_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 | |||
| 183 | void | ||
| 184 | moveset_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 | |||
| 201 | Alg * | ||
| 202 | new_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 | |||
| 281 | AlgList * | ||
| 282 | new_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 | |||
| 293 | Alg * | ||
| 294 | on_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 | |||
| 305 | void | ||
| 306 | print_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 | |||
| 332 | void | ||
| 333 | print_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 | |||
| 341 | static void | ||
| 342 | realloc_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 | |||
| 11 | bool moveset_HTM(Move m); | ||
| 12 | bool moveset_URF(Move m); | ||
| 13 | bool moveset_eofb(Move m); | ||
| 14 | bool moveset_drud(Move m); | ||
| 15 | bool moveset_htr(Move m); | ||
| 16 | |||
| 17 | void append_alg(AlgList *l, Alg *alg); | ||
| 18 | void append_move(Alg *alg, Move m, bool inverse); | ||
| 19 | void compose_alg(Alg *alg1, Alg *alg2); | ||
| 20 | Move base_move(Move m); | ||
| 21 | void free_alg(Alg *alg); | ||
| 22 | void free_alglist(AlgList *l); | ||
| 23 | Alg * inverse_alg(Alg *alg); | ||
| 24 | Move inverse_move(Move m); | ||
| 25 | char * move_string(Move m); | ||
| 26 | void movelist_to_position(Move *ml, int *pos); | ||
| 27 | void moveset_to_list(Moveset ms, Move *lst); | ||
| 28 | Alg * new_alg(char *str); | ||
| 29 | AlgList * new_alglist(); | ||
| 30 | Alg * on_inverse(Alg *alg); | ||
| 31 | void print_alg(Alg *alg, bool l); | ||
| 32 | void 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 | |||
| 5 | CommandArgs * solve_parse_args(int c, char **v); | ||
| 6 | CommandArgs * help_parse_args(int c, char **v); | ||
| 7 | CommandArgs * print_parse_args(int c, char **v); | ||
| 8 | CommandArgs * parse_no_arg(int c, char **v); | ||
| 9 | |||
| 10 | /* Exec functions ************************************************************/ | ||
| 11 | |||
| 12 | static void solve_exec(CommandArgs *args); | ||
| 13 | static void steps_exec(CommandArgs *args); | ||
| 14 | static void commands_exec(CommandArgs *args); | ||
| 15 | static void print_exec(CommandArgs *args); | ||
| 16 | static void help_exec(CommandArgs *args); | ||
| 17 | static void quit_exec(CommandArgs *args); | ||
| 18 | static void version_exec(CommandArgs *args); | ||
| 19 | |||
| 20 | /* Local functions ***********************************************************/ | ||
| 21 | |||
| 22 | static bool read_step(CommandArgs *args, char *str); | ||
| 23 | static bool read_scramble(int c, char **v, CommandArgs *args); | ||
| 24 | |||
| 25 | /* Commands ******************************************************************/ | ||
| 26 | |||
| 27 | Command | ||
| 28 | solve_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 | |||
| 36 | Command | ||
| 37 | steps_cmd = { | ||
| 38 | .name = "steps", | ||
| 39 | .usage = "steps", | ||
| 40 | .description = "List available steps", | ||
| 41 | .parse_args = parse_no_arg, | ||
| 42 | .exec = steps_exec | ||
| 43 | }; | ||
| 44 | |||
| 45 | Command | ||
| 46 | commands_cmd = { | ||
| 47 | .name = "commands", | ||
| 48 | .usage = "commands", | ||
| 49 | .description = "List available commands", | ||
| 50 | .parse_args = parse_no_arg, | ||
| 51 | .exec = commands_exec | ||
| 52 | }; | ||
| 53 | |||
| 54 | Command | ||
| 55 | print_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 | |||
| 63 | Command | ||
| 64 | help_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 | |||
| 72 | Command | ||
| 73 | quit_cmd = { | ||
| 74 | .name = "quit", | ||
| 75 | .usage = "quit", | ||
| 76 | .description = "Quit nissy", | ||
| 77 | .parse_args = parse_no_arg, | ||
| 78 | .exec = quit_exec, | ||
| 79 | }; | ||
| 80 | |||
| 81 | Command | ||
| 82 | version_cmd = { | ||
| 83 | .name = "version", | ||
| 84 | .usage = "version", | ||
| 85 | .description = "print nissy version", | ||
| 86 | .parse_args = parse_no_arg, | ||
| 87 | .exec = version_exec, | ||
| 88 | }; | ||
| 89 | |||
| 90 | Command *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 | |||
| 102 | CommandArgs * | ||
| 103 | solve_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 | |||
| 169 | CommandArgs * | ||
| 170 | help_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 | |||
| 193 | CommandArgs * | ||
| 194 | parse_no_arg(int c, char **v) | ||
| 195 | { | ||
| 196 | CommandArgs *a = malloc(sizeof(CommandArgs)); | ||
| 197 | |||
| 198 | a->success = true; | ||
| 199 | |||
| 200 | return a; | ||
| 201 | } | ||
| 202 | |||
| 203 | CommandArgs * | ||
| 204 | print_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 | |||
| 214 | static void | ||
| 215 | solve_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 | |||
| 229 | static void | ||
| 230 | steps_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 | |||
| 238 | static void | ||
| 239 | commands_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 | |||
| 248 | static void | ||
| 249 | print_exec(CommandArgs *args) | ||
| 250 | { | ||
| 251 | init_moves(); | ||
| 252 | print_cube(apply_alg(args->scramble, (Cube){0})); | ||
| 253 | } | ||
| 254 | |||
| 255 | static void | ||
| 256 | help_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 | |||
| 269 | static void | ||
| 270 | quit_exec(CommandArgs *args) | ||
| 271 | { | ||
| 272 | exit(0); | ||
| 273 | } | ||
| 274 | |||
| 275 | static void | ||
| 276 | version_exec(CommandArgs *args) | ||
| 277 | { | ||
| 278 | printf(VERSION"\n"); | ||
| 279 | } | ||
| 280 | |||
| 281 | /* Local functions implementation ********************************************/ | ||
| 282 | |||
| 283 | static bool | ||
| 284 | read_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 | |||
| 298 | static bool | ||
| 299 | read_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 | |||
| 332 | void | ||
| 333 | free_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 | |||
| 9 | void free_args(CommandArgs *args); | ||
| 10 | |||
| 11 | extern 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 | |||
| 3 | static Cube antindex_eofb(uint64_t ind); | ||
| 4 | static Cube antindex_eofbepos(uint64_t ind); | ||
| 5 | static Cube antindex_epud(uint64_t ind); | ||
| 6 | static Cube antindex_coud(uint64_t ind); | ||
| 7 | static Cube antindex_corners(uint64_t ind); | ||
| 8 | static Cube antindex_cp(uint64_t ind); | ||
| 9 | static Cube antindex_cphtr(uint64_t); | ||
| 10 | static Cube antindex_cornershtr(uint64_t ind); | ||
| 11 | static Cube antindex_cornershtrfin(uint64_t ind); | ||
| 12 | static Cube antindex_drud(uint64_t ind); | ||
| 13 | static Cube antindex_drud_eofb(uint64_t ind); | ||
| 14 | static Cube antindex_htr_drud(uint64_t ind); | ||
| 15 | static Cube antindex_htrfin(uint64_t ind); | ||
| 16 | |||
| 17 | static uint64_t index_eofb(Cube cube); | ||
| 18 | static uint64_t index_eofbepos(Cube cube); | ||
| 19 | static uint64_t index_epud(Cube cube); | ||
| 20 | static uint64_t index_coud(Cube cube); | ||
| 21 | static uint64_t index_corners(Cube cube); | ||
| 22 | static uint64_t index_cp(Cube cube); | ||
| 23 | static uint64_t index_cphtr(Cube cube); | ||
| 24 | static uint64_t index_cornershtr(Cube cube); | ||
| 25 | static uint64_t index_cornershtrfin(Cube cube); | ||
| 26 | static uint64_t index_drud(Cube cube); | ||
| 27 | static uint64_t index_drud_eofb(Cube cube); | ||
| 28 | static uint64_t index_htr_drud(Cube cube); | ||
| 29 | static uint64_t index_htrfin(Cube cube); | ||
| 30 | |||
| 31 | static void init_cphtr_cosets(); | ||
| 32 | static void init_cphtr_left_cosets_bfs(int i, int c); | ||
| 33 | static void init_cphtr_right_cosets_color(int i, int c); | ||
| 34 | static void init_cornershtrfin(); | ||
| 35 | |||
| 36 | |||
| 37 | /* All sorts of useful costants and tables **********************************/ | ||
| 38 | |||
| 39 | static int cphtr_left_cosets[FACTORIAL8]; | ||
| 40 | static int cphtr_right_cosets[FACTORIAL8]; | ||
| 41 | static int cphtr_right_rep[BINOM8ON4*6]; | ||
| 42 | static int cornershtrfin_ind[FACTORIAL8]; | ||
| 43 | static int cornershtrfin_ant[24*24/6]; | ||
| 44 | |||
| 45 | /* Coordinates and their implementation **************************************/ | ||
| 46 | |||
| 47 | Coordinate | ||
| 48 | coord_eofb = { | ||
| 49 | .index = index_eofb, | ||
| 50 | .cube = antindex_eofb, | ||
| 51 | .max = POW2TO11, | ||
| 52 | .ntrans = 1, | ||
| 53 | }; | ||
| 54 | |||
| 55 | Coordinate | ||
| 56 | coord_eofbepos = { | ||
| 57 | .index = index_eofbepos, | ||
| 58 | .cube = antindex_eofbepos, | ||
| 59 | .max = POW2TO11 * BINOM12ON4, | ||
| 60 | .ntrans = 1, | ||
| 61 | }; | ||
| 62 | |||
| 63 | Coordinate | ||
| 64 | coord_coud = { | ||
| 65 | .index = index_coud, | ||
| 66 | .cube = antindex_coud, | ||
| 67 | .max = POW3TO7, | ||
| 68 | .ntrans = 1, | ||
| 69 | }; | ||
| 70 | |||
| 71 | Coordinate | ||
| 72 | coord_corners = { | ||
| 73 | .index = index_corners, | ||
| 74 | .cube = antindex_corners, | ||
| 75 | .max = POW3TO7 * FACTORIAL8, | ||
| 76 | .ntrans = 1, | ||
| 77 | }; | ||
| 78 | |||
| 79 | Coordinate | ||
| 80 | coord_cp = { | ||
| 81 | .index = index_cp, | ||
| 82 | .cube = antindex_cp, | ||
| 83 | .max = FACTORIAL8, | ||
| 84 | .ntrans = 1, | ||
| 85 | }; | ||
| 86 | |||
| 87 | Coordinate | ||
| 88 | coord_cphtr = { | ||
| 89 | .index = index_cphtr, | ||
| 90 | .cube = antindex_cphtr, | ||
| 91 | .max = BINOM8ON4 * 6, | ||
| 92 | .ntrans = 1, | ||
| 93 | }; | ||
| 94 | |||
| 95 | Coordinate | ||
| 96 | coord_cornershtr = { | ||
| 97 | .index = index_cornershtr, | ||
| 98 | .cube = antindex_cornershtr, | ||
| 99 | .max = POW3TO7 * BINOM8ON4 * 6, | ||
| 100 | .ntrans = 1, | ||
| 101 | }; | ||
| 102 | |||
| 103 | Coordinate | ||
| 104 | coord_cornershtrfin = { | ||
| 105 | .index = index_cornershtrfin, | ||
| 106 | .cube = antindex_cornershtrfin, | ||
| 107 | .max = 24*24/6, | ||
| 108 | .ntrans = 1, | ||
| 109 | }; | ||
| 110 | |||
| 111 | Coordinate | ||
| 112 | coord_epud = { | ||
| 113 | .index = index_epud, | ||
| 114 | .cube = antindex_epud, | ||
| 115 | .max = FACTORIAL8, | ||
| 116 | .ntrans = 1, | ||
| 117 | }; | ||
| 118 | |||
| 119 | Coordinate | ||
| 120 | coord_drud = { | ||
| 121 | .index = index_drud, | ||
| 122 | .cube = antindex_drud, | ||
| 123 | .max = POW2TO11 * POW3TO7 * BINOM12ON4, | ||
| 124 | .ntrans = 1, | ||
| 125 | }; | ||
| 126 | |||
| 127 | Coordinate | ||
| 128 | coord_htr_drud = { | ||
| 129 | .index = index_htr_drud, | ||
| 130 | .cube = antindex_htr_drud, | ||
| 131 | .max = BINOM8ON4 * 6 * BINOM8ON4, | ||
| 132 | .ntrans = 1, | ||
| 133 | }; | ||
| 134 | |||
| 135 | Coordinate | ||
| 136 | coord_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 | |||
| 143 | Coordinate | ||
| 144 | coord_drud_eofb = { | ||
| 145 | .index = index_drud_eofb, | ||
| 146 | .cube = antindex_drud_eofb, | ||
| 147 | .max = POW3TO7 * BINOM12ON4, | ||
| 148 | .ntrans = 1, | ||
| 149 | }; | ||
| 150 | |||
| 151 | /* Functions *****************************************************************/ | ||
| 152 | |||
| 153 | static Cube | ||
| 154 | antindex_eofb(uint64_t ind) | ||
| 155 | { | ||
| 156 | return (Cube){ .eofb = ind, .eorl = ind, .eoud = ind }; | ||
| 157 | } | ||
| 158 | |||
| 159 | static Cube | ||
| 160 | antindex_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 | |||
| 170 | static Cube | ||
| 171 | antindex_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 | |||
| 196 | static Cube | ||
| 197 | antindex_coud(uint64_t ind) | ||
| 198 | { | ||
| 199 | return (Cube){ .coud = ind, .corl = ind, .cofb = ind }; | ||
| 200 | } | ||
| 201 | |||
| 202 | static Cube | ||
| 203 | antindex_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 | |||
| 213 | static Cube | ||
| 214 | antindex_cp(uint64_t ind) | ||
| 215 | { | ||
| 216 | Cube c = {0}; | ||
| 217 | |||
| 218 | c.cp = ind; | ||
| 219 | |||
| 220 | return c; | ||
| 221 | } | ||
| 222 | |||
| 223 | static Cube | ||
| 224 | antindex_cphtr(uint64_t ind) | ||
| 225 | { | ||
| 226 | return (Cube) { .cp = cphtr_right_rep[ind] }; | ||
| 227 | } | ||
| 228 | |||
| 229 | static Cube | ||
| 230 | antindex_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 | |||
| 239 | static Cube | ||
| 240 | antindex_cornershtrfin(uint64_t ind) | ||
| 241 | { | ||
| 242 | return (Cube){ .cp = cornershtrfin_ant[ind] }; | ||
| 243 | } | ||
| 244 | |||
| 245 | static Cube | ||
| 246 | antindex_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 | |||
| 260 | static Cube | ||
| 261 | antindex_drud_eofb(uint64_t ind) | ||
| 262 | { | ||
| 263 | return antindex_drud(ind * POW2TO11); | ||
| 264 | } | ||
| 265 | |||
| 266 | static Cube | ||
| 267 | antindex_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 | |||
| 277 | static Cube | ||
| 278 | antindex_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 | |||
| 293 | static uint64_t | ||
| 294 | index_eofb(Cube cube) | ||
| 295 | { | ||
| 296 | return cube.eofb; | ||
| 297 | } | ||
| 298 | |||
| 299 | static uint64_t | ||
| 300 | index_eofbepos(Cube cube) | ||
| 301 | { | ||
| 302 | return (cube.epose / FACTORIAL4) * POW2TO11 + cube.eofb; | ||
| 303 | } | ||
| 304 | |||
| 305 | static uint64_t | ||
| 306 | index_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 | |||
| 317 | static uint64_t | ||
| 318 | index_coud(Cube cube) | ||
| 319 | { | ||
| 320 | return cube.coud; | ||
| 321 | } | ||
| 322 | |||
| 323 | static uint64_t | ||
| 324 | index_corners(Cube cube) | ||
| 325 | { | ||
| 326 | return cube.coud * FACTORIAL8 + cube.cp; | ||
| 327 | } | ||
| 328 | |||
| 329 | static uint64_t | ||
| 330 | index_cp(Cube cube) | ||
| 331 | { | ||
| 332 | return cube.cp; | ||
| 333 | } | ||
| 334 | |||
| 335 | static uint64_t | ||
| 336 | index_cphtr(Cube cube) | ||
| 337 | { | ||
| 338 | return cphtr_right_cosets[cube.cp]; | ||
| 339 | } | ||
| 340 | |||
| 341 | static uint64_t | ||
| 342 | index_cornershtr(Cube cube) | ||
| 343 | { | ||
| 344 | return cube.coud * BINOM8ON4 * 6 + index_cphtr(cube); | ||
| 345 | } | ||
| 346 | |||
| 347 | static uint64_t | ||
| 348 | index_cornershtrfin(Cube cube) | ||
| 349 | { | ||
| 350 | return cornershtrfin_ind[cube.cp]; | ||
| 351 | } | ||
| 352 | |||
| 353 | static uint64_t | ||
| 354 | index_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 | |||
| 368 | static uint64_t | ||
| 369 | index_drud_eofb(Cube cube) | ||
| 370 | { | ||
| 371 | return index_drud(cube) / POW2TO11; | ||
| 372 | } | ||
| 373 | |||
| 374 | static uint64_t | ||
| 375 | index_htr_drud(Cube cube) | ||
| 376 | { | ||
| 377 | return index_cphtr(cube) * BINOM8ON4 + | ||
| 378 | (cube.eposs / FACTORIAL4) % BINOM8ON4; | ||
| 379 | } | ||
| 380 | |||
| 381 | static uint64_t | ||
| 382 | index_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 | */ | ||
| 410 | static void | ||
| 411 | init_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 | |||
| 432 | static void | ||
| 433 | init_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 | |||
| 463 | static void | ||
| 464 | init_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 | |||
| 478 | static void | ||
| 479 | init_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 | |||
| 509 | void | ||
| 510 | init_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 | |||
| 6 | extern Coordinate coord_eofb; | ||
| 7 | extern Coordinate coord_eofbepos; | ||
| 8 | extern Coordinate coord_coud; | ||
| 9 | extern Coordinate coord_cp; | ||
| 10 | extern Coordinate coord_cphtr; | ||
| 11 | extern Coordinate coord_corners; | ||
| 12 | extern Coordinate coord_cornershtr; | ||
| 13 | extern Coordinate coord_cornershtrfin; | ||
| 14 | extern Coordinate coord_epud; | ||
| 15 | extern Coordinate coord_drud; | ||
| 16 | extern Coordinate coord_drud_eofb; | ||
| 17 | extern Coordinate coord_htr_drud; | ||
| 18 | extern Coordinate coord_htrfin; | ||
| 19 | |||
| 20 | void 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. */ | ||
| 7 | char edge_string_list[12][5] = { | ||
| 8 | "UF", "UL", "UB", "UR", "DF", "DL", "DB", "DR", "FR", "FL", "BL", "BR" | ||
| 9 | }; | ||
| 10 | |||
| 11 | char corner_string_list[8][5] = { | ||
| 12 | "UFR", "UFL", "UBL", "UBR", "DFR", "DFL", "DBL", "DBR" | ||
| 13 | }; | ||
| 14 | |||
| 15 | char 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 | |||
| 21 | int 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 | |||
| 31 | void ep_int_to_array(int ep, int a[12]) { | ||
| 32 | index_to_perm(ep, 12, a); | ||
| 33 | } | ||
| 34 | |||
| 35 | void epud_int_to_array(int epud, int a[12]) { | ||
| 36 | index_to_perm(epud, 8, a); /* Last 4 elements are left untouched. */ | ||
| 37 | } | ||
| 38 | |||
| 39 | void 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 | |||
| 47 | void 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 | |||
| 55 | void 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 | |||
| 62 | void 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 | |||
| 72 | void 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 | |||
| 82 | void 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 | |||
| 88 | void 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 | |||
| 96 | void 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 | |||
| 104 | void 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 | |||
| 132 | void cp_int_to_array(int cp, int a[8]) { | ||
| 133 | index_to_perm(cp, 8, a); | ||
| 134 | } | ||
| 135 | |||
| 136 | void eo_11bits_to_array(int eo, int a[12]) { | ||
| 137 | int_to_sum_zero_array(eo, 2, 12, a); | ||
| 138 | } | ||
| 139 | |||
| 140 | void 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 | |||
| 148 | int ep_array_to_int(int ep[12]) { | ||
| 149 | return perm_to_index(ep, 12); | ||
| 150 | } | ||
| 151 | |||
| 152 | int epud_array_to_int(int ep[12]) { | ||
| 153 | return perm_to_index(ep, 8); /* Last 4 elements are ignored */ | ||
| 154 | } | ||
| 155 | |||
| 156 | int 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 | |||
| 165 | int 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 | |||
| 174 | int 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 | |||
| 181 | int 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 | |||
| 192 | int 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 | |||
| 203 | int 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 | |||
| 210 | int 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 | |||
| 219 | int 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 | |||
| 228 | int 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 | |||
| 275 | int cp_array_to_int(int cp[8]) { | ||
| 276 | return perm_to_index(cp, 8); | ||
| 277 | } | ||
| 278 | |||
| 279 | int eo_array_to_11bits(int a[12]) { | ||
| 280 | return digit_array_to_int(a, 11, 2); | ||
| 281 | } | ||
| 282 | |||
| 283 | int 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 | |||
| 53 | extern char edge_string_list[12][5]; | ||
| 54 | extern char corner_string_list[8][5]; | ||
| 55 | extern char move_string_list[19][5]; | ||
| 56 | extern 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 | |||
| 64 | void ep_int_to_array(int ep, int a[12]); | ||
| 65 | void epud_int_to_array(int epud, int a[12]); | ||
| 66 | void epfb_int_to_array(int epfb, int a[12]); | ||
| 67 | void eprl_int_to_array(int eprl, int a[12]); | ||
| 68 | void epose_int_to_array(int epos, int a[12]); | ||
| 69 | void eposs_int_to_array(int epos, int a[12]); | ||
| 70 | void eposm_int_to_array(int epos, int a[12]); | ||
| 71 | void epe_int_to_array(int epe, int a[12]); | ||
| 72 | void epm_int_to_array(int epe, int a[12]); | ||
| 73 | void eps_int_to_array(int epe, int a[12]); | ||
| 74 | void emslices_int_to_array(int emslices, int a[12]); | ||
| 75 | void cp_int_to_array(int cp, int a[8]); | ||
| 76 | void eo_11bits_to_array(int eo, int a[12]); | ||
| 77 | void co_7trits_to_array(int co, int a[8]); | ||
| 78 | |||
| 79 | int ep_array_to_int(int ep[12]); | ||
| 80 | int epud_array_to_int(int ep[12]); | ||
| 81 | int epfb_array_to_int(int ep[12]); | ||
| 82 | int eprl_array_to_int(int ep[12]); | ||
| 83 | int epose_array_to_int(int ep[12]); | ||
| 84 | int eposs_array_to_int(int ep[12]); | ||
| 85 | int eposm_array_to_int(int ep[12]); | ||
| 86 | int epe_array_to_int(int epe[12]); | ||
| 87 | int epm_array_to_int(int epe[12]); | ||
| 88 | int eps_array_to_int(int epe[12]); | ||
| 89 | int emslices_array_to_int(int ep[12]); | ||
| 90 | int cp_array_to_int(int cp[8]); | ||
| 91 | int eo_array_to_11bits(int a[12]); | ||
| 92 | int 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 | |||
| 5 | static int array_ep_to_epos(int *ep, int *eps_solved); | ||
| 6 | static int epos_from_arrays(int *epos, int *ep); | ||
| 7 | |||
| 8 | /* Local functions implementation ********************************************/ | ||
| 9 | |||
| 10 | static int | ||
| 11 | array_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 | |||
| 32 | static int | ||
| 33 | epos_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 | |||
| 40 | Cube | ||
| 41 | arrays_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 | |||
| 75 | Cube | ||
| 76 | compose_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 | |||
| 87 | void | ||
| 88 | cube_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 | |||
| 124 | void | ||
| 125 | epos_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 | |||
| 140 | void | ||
| 141 | free_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 | |||
| 165 | Cube | ||
| 166 | move_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 | |||
| 216 | CubeArray * | ||
| 217 | new_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 | |||
| 245 | Cube | ||
| 246 | admissible_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 | |||
| 269 | Cube | ||
| 270 | compose(Cube c2, Cube c1) | ||
| 271 | { | ||
| 272 | return compose_filtered(c2, c1, pf_all); | ||
| 273 | } | ||
| 274 | |||
| 275 | int | ||
| 276 | edge_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 | |||
| 288 | bool | ||
| 289 | equal(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 | |||
| 300 | Cube | ||
| 301 | inverse_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 | |||
| 332 | bool | ||
| 333 | is_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 | |||
| 352 | bool | ||
| 353 | is_solved(Cube cube) | ||
| 354 | { | ||
| 355 | return equal(cube, (Cube){0}); | ||
| 356 | } | ||
| 357 | |||
| 358 | bool | ||
| 359 | is_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 | |||
| 376 | bool | ||
| 377 | is_solved_center(Cube cube, Center c) | ||
| 378 | { | ||
| 379 | return what_center_at(cube, c) == c; | ||
| 380 | } | ||
| 381 | |||
| 382 | bool | ||
| 383 | is_solved_corner(Cube cube, Corner c) | ||
| 384 | { | ||
| 385 | return what_corner_at(cube, c) == c && | ||
| 386 | what_orientation_corner(cube.coud, c); | ||
| 387 | } | ||
| 388 | |||
| 389 | bool | ||
| 390 | is_solved_edge(Cube cube, Edge e) | ||
| 391 | { | ||
| 392 | return what_edge_at(cube, e) == e && | ||
| 393 | what_orientation_edge(cube.eofb, e); | ||
| 394 | } | ||
| 395 | |||
| 396 | int | ||
| 397 | piece_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 | |||
| 436 | void | ||
| 437 | print_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 | |||
| 477 | Cube | ||
| 478 | random_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 | |||
| 503 | Center | ||
| 504 | what_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 | |||
| 526 | Corner | ||
| 527 | what_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 | |||
| 549 | Edge | ||
| 550 | what_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 | |||
| 561 | int | ||
| 562 | what_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 | |||
| 584 | int | ||
| 585 | what_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 | |||
| 607 | Center | ||
| 608 | where_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 | |||
| 630 | Corner | ||
| 631 | where_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 | |||
| 652 | Edge | ||
| 653 | where_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 | |||
| 10 | Cube admissible_ep(Cube cube, PieceFilter f); | ||
| 11 | Cube arrays_to_cube(CubeArray *arr, PieceFilter f); | ||
| 12 | Cube compose(Cube c2, Cube c1); /* Use c2 as an alg on c1 */ | ||
| 13 | Cube compose_filtered(Cube c2, Cube c1, PieceFilter f); | ||
| 14 | void cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f); | ||
| 15 | int edge_slice(Edge e); /* E=0, S=1, M=2 */ | ||
| 16 | bool equal(Cube c1, Cube c2); | ||
| 17 | Cube inverse_cube(Cube cube); | ||
| 18 | bool is_admissible(Cube cube); | ||
| 19 | bool is_solved(Cube cube); | ||
| 20 | bool is_block_solved(Cube cube, Block); | ||
| 21 | bool is_solved_center(Cube cube, Center c); | ||
| 22 | bool is_solved_corner(Cube cube, Corner c); | ||
| 23 | bool is_solved_edge(Cube cube, Edge e); | ||
| 24 | void epos_to_partial_ep(int epos, int *ep, int *ss); | ||
| 25 | void free_cubearray(CubeArray *arr, PieceFilter f); | ||
| 26 | Cube move_via_arrays(CubeArray *arr, Cube c, PieceFilter pf); | ||
| 27 | CubeArray * new_cubearray(Cube cube, PieceFilter f); | ||
| 28 | void print_cube(Cube cube); | ||
| 29 | Cube random_cube(); | ||
| 30 | Center what_center_at(Cube cube, Center c); | ||
| 31 | Corner what_corner_at(Cube cube, Corner c); | ||
| 32 | Edge what_edge_at(Cube cube, Edge e); | ||
| 33 | int what_orientation_corner(int co, Corner c); | ||
| 34 | int what_orientation_edge(int eo, Edge e); | ||
| 35 | Center where_is_center(Cube cube, Center c); | ||
| 36 | Corner where_is_corner(Cube cube, Corner c); | ||
| 37 | Edge 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 | |||
| 13 | typedef enum | ||
| 14 | center | ||
| 15 | { | ||
| 16 | U_center, D_center, | ||
| 17 | R_center, L_center, | ||
| 18 | F_center, B_center | ||
| 19 | } Center; | ||
| 20 | |||
| 21 | typedef enum | ||
| 22 | corner | ||
| 23 | { | ||
| 24 | UFR, UFL, UBL, UBR, | ||
| 25 | DFR, DFL, DBL, DBR | ||
| 26 | } Corner; | ||
| 27 | |||
| 28 | typedef enum | ||
| 29 | edge | ||
| 30 | { | ||
| 31 | UF, UL, UB, UR, | ||
| 32 | DF, DL, DB, DR, | ||
| 33 | FR, FL, BL, BR | ||
| 34 | } Edge; | ||
| 35 | |||
| 36 | typedef enum | ||
| 37 | move | ||
| 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 | |||
| 54 | typedef enum | ||
| 55 | trans | ||
| 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 | |||
| 74 | typedef struct alg Alg; | ||
| 75 | typedef struct alglist AlgList; | ||
| 76 | typedef struct alglistnode AlgListNode; | ||
| 77 | typedef struct block Block; | ||
| 78 | typedef struct command Command; | ||
| 79 | typedef struct commandargs CommandArgs; | ||
| 80 | typedef struct coordinate Coordinate; | ||
| 81 | typedef struct cube Cube; | ||
| 82 | typedef struct cubearray CubeArray; | ||
| 83 | typedef struct cubetarget CubeTarget; | ||
| 84 | typedef struct dfsdata DfsData; | ||
| 85 | typedef struct piecefilter PieceFilter; | ||
| 86 | typedef struct prunedata PruneData; | ||
| 87 | typedef struct solveoptions SolveOptions; | ||
| 88 | typedef struct step Step; | ||
| 89 | typedef struct symdata SymData; | ||
| 90 | |||
| 91 | typedef Cube (*AntiIndexer) (uint64_t); | ||
| 92 | typedef bool (*Checker) (Cube); | ||
| 93 | typedef int (*Estimator) (CubeTarget); | ||
| 94 | typedef bool (*Validator) (Alg *); | ||
| 95 | typedef void (*Exec) (CommandArgs *); | ||
| 96 | typedef uint64_t (*Indexer) (Cube); | ||
| 97 | typedef bool (*Moveset) (Move); | ||
| 98 | typedef CommandArgs * (*ArgParser) (int, char **); | ||
| 99 | typedef Trans (*TransDetector) (Cube); | ||
| 100 | |||
| 101 | |||
| 102 | /* Structs *******************************************************************/ | ||
| 103 | |||
| 104 | struct | ||
| 105 | alg | ||
| 106 | { | ||
| 107 | Move * move; | ||
| 108 | bool * inv; | ||
| 109 | int len; | ||
| 110 | int allocated; | ||
| 111 | }; | ||
| 112 | |||
| 113 | struct | ||
| 114 | alglist | ||
| 115 | { | ||
| 116 | AlgListNode * first; | ||
| 117 | AlgListNode * last; | ||
| 118 | int len; | ||
| 119 | }; | ||
| 120 | |||
| 121 | struct | ||
| 122 | alglistnode | ||
| 123 | { | ||
| 124 | Alg * alg; | ||
| 125 | AlgListNode * next; | ||
| 126 | }; | ||
| 127 | |||
| 128 | struct | ||
| 129 | block | ||
| 130 | { | ||
| 131 | bool edge[12]; | ||
| 132 | bool corner[8]; | ||
| 133 | bool center[6]; | ||
| 134 | }; | ||
| 135 | |||
| 136 | struct | ||
| 137 | command | ||
| 138 | { | ||
| 139 | char * name; | ||
| 140 | char * usage; | ||
| 141 | char * description; | ||
| 142 | ArgParser parse_args; | ||
| 143 | Exec exec; | ||
| 144 | }; | ||
| 145 | |||
| 146 | struct | ||
| 147 | commandargs | ||
| 148 | { | ||
| 149 | bool success; | ||
| 150 | Alg * scramble; | ||
| 151 | SolveOptions * opts; | ||
| 152 | Step * step; | ||
| 153 | Command * command; /* For help */ | ||
| 154 | }; | ||
| 155 | |||
| 156 | struct | ||
| 157 | coordinate | ||
| 158 | { | ||
| 159 | Indexer index; | ||
| 160 | AntiIndexer cube; | ||
| 161 | uint64_t max; | ||
| 162 | int ntrans; | ||
| 163 | Trans * trans; | ||
| 164 | }; | ||
| 165 | |||
| 166 | struct | ||
| 167 | cube | ||
| 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 | |||
| 182 | struct | ||
| 183 | cubearray | ||
| 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 | |||
| 196 | struct | ||
| 197 | cubetarget | ||
| 198 | { | ||
| 199 | Cube cube; | ||
| 200 | int target; | ||
| 201 | }; | ||
| 202 | |||
| 203 | struct | ||
| 204 | dfsdata | ||
| 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 | |||
| 218 | struct | ||
| 219 | piecefilter | ||
| 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 | |||
| 234 | struct | ||
| 235 | prunedata | ||
| 236 | { | ||
| 237 | char * filename; | ||
| 238 | uint8_t * ptable; | ||
| 239 | bool generated; | ||
| 240 | uint64_t n; | ||
| 241 | Coordinate * coord; | ||
| 242 | Moveset moveset; | ||
| 243 | }; | ||
| 244 | |||
| 245 | struct | ||
| 246 | solveoptions | ||
| 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 | |||
| 258 | struct | ||
| 259 | step | ||
| 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 | |||
| 272 | struct | ||
| 273 | symdata | ||
| 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 | |||
| 3 | bool initialized_env = false; | ||
| 4 | char *tabledir; | ||
| 5 | |||
| 6 | void | ||
| 7 | init_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 | |||
| 11 | extern char *tabledir; | ||
| 12 | |||
| 13 | void 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 | |||
| 3 | int Npages = 22; | ||
| 4 | |||
| 5 | char *helppages[][10] = { | ||
| 6 | |||
| 7 | { "add", | ||
| 8 | "\ | ||
| 9 | \n\ | ||
| 10 | HELP PAGE FOR COMMAND add\n\ | ||
| 11 | \n\ | ||
| 12 | SYNTAX\n\ | ||
| 13 | add [MOVES|$ID1|@ID1] $ID2\n\ | ||
| 14 | \n\ | ||
| 15 | DESCRIPTION\n\ | ||
| 16 | Appends either MOVES, the scramble memorized under $ID1 or the output sequence\n\ | ||
| 17 | memorized under @ID1 at the end of the scramble memorized under $ID2. If none\n\ | ||
| 18 | of MOVES, $ID1 or @ID1 is specified, the user will be asked to type the moves.\n\ | ||
| 19 | Menmonic: \"add x to y\" or just \"add to y\".\n\ | ||
| 20 | \n\ | ||
| 21 | EXAMPLES\n\ | ||
| 22 | add $1\n\ | ||
| 23 | The user is required to type the moves that will be appended to $1.\n\ | ||
| 24 | add 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\ | ||
| 33 | HELP PAGE FOR COMMAND change\n\ | ||
| 34 | \n\ | ||
| 35 | SYNTAX\n\ | ||
| 36 | change $ID1 [MOVES|$ID2|@ID2]\n\ | ||
| 37 | \n\ | ||
| 38 | DESCRIPTION\n\ | ||
| 39 | Changes the scramble $ID1 to either MOVES, the scramble $ID2, the output @ID2\n\ | ||
| 40 | or, if none is specified, the moves entered by the user. The scramble that was\n\ | ||
| 41 | memorized under $ID1 is then lost.\n\ | ||
| 42 | Mnemonic: \"change x to y\", or just \"change x\".\n\ | ||
| 43 | \n\ | ||
| 44 | EXAMPLES\n\ | ||
| 45 | change $1\n\ | ||
| 46 | The user is required to type the moves that will replace $1.\n\ | ||
| 47 | change $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\ | ||
| 50 | change $1 U R\n\ | ||
| 51 | Saves U R as scramble $1.\n\ | ||
| 52 | \n\ | ||
| 53 | " | ||
| 54 | }, | ||
| 55 | |||
| 56 | { "clear", | ||
| 57 | "\ | ||
| 58 | \n\ | ||
| 59 | HELP PAGE FOR COMMAND clear\n\ | ||
| 60 | \n\ | ||
| 61 | SYNTAX\n\ | ||
| 62 | clear\n\ | ||
| 63 | \n\ | ||
| 64 | DESCRIPTION\n\ | ||
| 65 | Resets all saved scrambles and output sequences.\n\ | ||
| 66 | \n\ | ||
| 67 | " | ||
| 68 | }, | ||
| 69 | |||
| 70 | { "co", | ||
| 71 | "\ | ||
| 72 | \n\ | ||
| 73 | HELP PAGE FOR COMMAND co\n\ | ||
| 74 | \n\ | ||
| 75 | SYNTAX\n\ | ||
| 76 | co [OPTIONS] [MOVES|$ID|@ID]\n\ | ||
| 77 | \n\ | ||
| 78 | DESCRIPTION\n\ | ||
| 79 | Solves CO for a given scramble. A scramble can be given as last argument of the\n\ | ||
| 80 | command, or an ID of a saved scramble can be provided. If none of the two is\n\ | ||
| 81 | given, a prompt will ask the user to input a new scramble.\n\ | ||
| 82 | \n\ | ||
| 83 | OPTIONS\n\ | ||
| 84 | axis={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\ | ||
| 88 | b=N Specify a bound for the number of moves. N must be a number.\n\ | ||
| 89 | Default value: 20.\n\ | ||
| 90 | h 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\ | ||
| 93 | i Ignore centers. By default the CO is aligned with centers.\n\ | ||
| 94 | niss Use NISS.\n\ | ||
| 95 | Default: does not use NISS.\n\ | ||
| 96 | n=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\ | ||
| 100 | EXAMPLES\n\ | ||
| 101 | co axis=fb $1\n\ | ||
| 102 | Finds one optimal CO on fb for the first saved scramble.\n\ | ||
| 103 | \n\ | ||
| 104 | co 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\ | ||
| 107 | co 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\ | ||
| 117 | HELP PAGE FOR COMMAND dr\n\ | ||
| 118 | \n\ | ||
| 119 | SYNTAX\n\ | ||
| 120 | dr [OPTIONS] [MOVES|$ID|@ID]\n\ | ||
| 121 | \n\ | ||
| 122 | DESCRIPTION\n\ | ||
| 123 | Solves DR for a given scramble. A scramble can be given as last argument of the\n\ | ||
| 124 | command, or an ID of a saved scramble can be provided. If none of the two is\n\ | ||
| 125 | given, a prompt will ask the user to input a new scramble.\n\ | ||
| 126 | If the option \"from\" is given (see below), it solves DR from an EO (if edges\n\ | ||
| 127 | are oriented) without breaking that EO.\n\ | ||
| 128 | The first time this command is called without the option from (and, to some\n\ | ||
| 129 | extent, also the first time it is called with the option from), nissy loads\n\ | ||
| 130 | some pruning tables that were not loaded on startup, causing a small but\n\ | ||
| 131 | noticeable delay.\n\ | ||
| 132 | \n\ | ||
| 133 | OPTIONS\n\ | ||
| 134 | axis={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\ | ||
| 138 | b=N Specify a bound for the number of moves. N must be a number.\n\ | ||
| 139 | Default value: 20.\n\ | ||
| 140 | h 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\ | ||
| 143 | from {fb|rl|ud} Solve DR from the specified EO, which must be solved,\n\ | ||
| 144 | without breaking the EO.\n\ | ||
| 145 | niss Use NISS. It works only if solving DR from EO.\n\ | ||
| 146 | Default: does not use NISS.\n\ | ||
| 147 | n=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\ | ||
| 151 | EXAMPLES\n\ | ||
| 152 | dr 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\ | ||
| 155 | dr 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\ | ||
| 158 | dr 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\ | ||
| 167 | HELP PAGE FOR COMMAND drcorners\n\ | ||
| 168 | \n\ | ||
| 169 | SYNTAX\n\ | ||
| 170 | drcorners [OPTIONS] [MOVES|$ID|@ID]\n\ | ||
| 171 | \n\ | ||
| 172 | DESCRIPTION\n\ | ||
| 173 | Similar to drfinish, but only solves corners. CO must be solved. The scramble\n\ | ||
| 174 | can be given as the last argument of the command, or it may be given as an $ID\n\ | ||
| 175 | or @ID, or it can be typed out on the following line.\n\ | ||
| 176 | \n\ | ||
| 177 | OPTIONS\n\ | ||
| 178 | from {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\ | ||
| 181 | i 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\ | ||
| 186 | b=N Specify a bound for the number of moves. N must be a number.\n\ | ||
| 187 | Default value: 20.\n\ | ||
| 188 | n=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\ | ||
| 192 | EXAMPLES\n\ | ||
| 193 | drcorners n=3 R' D R2 D' R' U2 R D R' U2 R' D' R\n\ | ||
| 194 | Produces the following output:\n\ | ||
| 195 | Found 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\ | ||
| 206 | HELP PAGE FOR COMMAND drfinish\n\ | ||
| 207 | \n\ | ||
| 208 | SYNTAX\n\ | ||
| 209 | drfinish [OPTIONS] [MOVES|$ID|@ID]\n\ | ||
| 210 | \n\ | ||
| 211 | DESCRIPTION\n\ | ||
| 212 | Solves the given scramble using the DR moveset. DR must be solved. The scramble\n\ | ||
| 213 | can be given as the last argument of the command, or it may be given as an $ID\n\ | ||
| 214 | or @ID, or it can be typed out on the following line.\n\ | ||
| 215 | \n\ | ||
| 216 | OPTIONS\n\ | ||
| 217 | from {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\ | ||
| 221 | b=N Specify a bound for the number of moves. N must be a number.\n\ | ||
| 222 | Default value: 20.\n\ | ||
| 223 | n=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\ | ||
| 227 | EXAMPLES\n\ | ||
| 228 | dr 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\ | ||
| 231 | drfinish 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\ | ||
| 240 | HELP PAGE FOR COMMAND eo\n\ | ||
| 241 | \n\ | ||
| 242 | SYNTAX\n\ | ||
| 243 | eo [OPTIONS] [MOVES|$ID|@ID]\n\ | ||
| 244 | \n\ | ||
| 245 | DESCRIPTION\n\ | ||
| 246 | Solves EO for a given scramble. A scramble can be given as last argument of the\n\ | ||
| 247 | command, or an ID of a saved scramble can be provided. If none of the two is\n\ | ||
| 248 | given, a prompt will ask the user to input a new scramble.\n\ | ||
| 249 | \n\ | ||
| 250 | OPTIONS\n\ | ||
| 251 | axis={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\ | ||
| 255 | b=N Specify a bound for the number of moves. N must be a number.\n\ | ||
| 256 | Default value: 20.\n\ | ||
| 257 | h 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\ | ||
| 260 | niss Use NISS.\n\ | ||
| 261 | Default: does not use NISS.\n\ | ||
| 262 | n=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\ | ||
| 266 | EXAMPLES\n\ | ||
| 267 | eo axis=fb $1\n\ | ||
| 268 | Finds one optimal EO on fb for the first saved scramble.\n\ | ||
| 269 | \n\ | ||
| 270 | eo 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\ | ||
| 273 | eo 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\ | ||
| 283 | HELP PAGE FOR COMMAND exit\n\ | ||
| 284 | \n\ | ||
| 285 | SYNTAX\n\ | ||
| 286 | exit\n\ | ||
| 287 | \n\ | ||
| 288 | DESCRIPTION\n\ | ||
| 289 | Exits nissy.\n\ | ||
| 290 | \n\ | ||
| 291 | " | ||
| 292 | }, | ||
| 293 | |||
| 294 | { "help", | ||
| 295 | "\ | ||
| 296 | \n\ | ||
| 297 | HELP PAGE FOR COMMAND help\n\ | ||
| 298 | \n\ | ||
| 299 | SYNTAX\n\ | ||
| 300 | help [nissy|COMMAND]\n\ | ||
| 301 | \n\ | ||
| 302 | DESCRIPTION\n\ | ||
| 303 | 'help nissy' prints a general user manual. 'help COMMAND' prints a detailed\n\ | ||
| 304 | help page for the command COMMAND, if it exists. 'help' prints a list of all\n\ | ||
| 305 | available commands a short description for each.\n\ | ||
| 306 | \n\ | ||
| 307 | EXAMPLES\n\ | ||
| 308 | help help\n\ | ||
| 309 | Prints this help page.\n\ | ||
| 310 | \n\ | ||
| 311 | " | ||
| 312 | }, | ||
| 313 | |||
| 314 | { "htr", | ||
| 315 | "\ | ||
| 316 | \n\ | ||
| 317 | HELP PAGE FOR COMMAND htr\n\ | ||
| 318 | \n\ | ||
| 319 | SYNTAX\n\ | ||
| 320 | htr [OPTIONS] [MOVES|$ID|@ID]\n\ | ||
| 321 | \n\ | ||
| 322 | DESCRIPTION\n\ | ||
| 323 | Finds HTR for a given scramble. DR must be solved. A scramble can be given as\n\ | ||
| 324 | last argument of the command, or an ID of a saved scramble can be provided. If\n\ | ||
| 325 | none of the two is given, a prompt will ask the user to input a new scramble.\n\ | ||
| 326 | \n\ | ||
| 327 | OPTIONS\n\ | ||
| 328 | from {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\ | ||
| 330 | b=N Specify a bound for the number of moves. N must be a number.\n\ | ||
| 331 | Default value: 20.\n\ | ||
| 332 | h 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\ | ||
| 335 | niss Use NISS.\n\ | ||
| 336 | Default: does not use NISS.\n\ | ||
| 337 | n=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\ | ||
| 341 | EXAMPLES\n\ | ||
| 342 | eo 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\ | ||
| 352 | HELP PAGE FOR COMMAND htrfinish\n\ | ||
| 353 | \n\ | ||
| 354 | SYNTAX\n\ | ||
| 355 | htrfinish [OPTIONS] [MOVES|$ID|@ID]\n\ | ||
| 356 | \n\ | ||
| 357 | DESCRIPTION\n\ | ||
| 358 | Similar to drfinish, but uses the moveset <U2,D2,R2,L2,F2,B2>. HTR must be\n\ | ||
| 359 | solved. The scramble can be given as the last argument of the command, or it\n\ | ||
| 360 | may be given as an $ID or @ID, or it can be typed out on the following line.\n\ | ||
| 361 | \n\ | ||
| 362 | OPTIONS\n\ | ||
| 363 | b=N Specify a bound for the number of moves. N must be a number.\n\ | ||
| 364 | Default value: 20.\n\ | ||
| 365 | n=N Specify a maximum number ofsolutions to be output. N must be\n\ | ||
| 366 | a number.\n\ | ||
| 367 | Default value: 1.\n\ | ||
| 368 | \n\ | ||
| 369 | EXAMPLES\n\ | ||
| 370 | htrfinish 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\ | ||
| 380 | HELP PAGE FOR COMMAND invert\n\ | ||
| 381 | \n\ | ||
| 382 | SYNTAX\n\ | ||
| 383 | invert [MOVES|$ID|@ID]\n\ | ||
| 384 | \n\ | ||
| 385 | DESCRIPTION\n\ | ||
| 386 | Inverts a sequence of moves, which can be given also as $ID or @ID. The given\n\ | ||
| 387 | sequence must not use NISS (if it does, use the command unniss first).\n\ | ||
| 388 | \n\ | ||
| 389 | EXAMPLES\n\ | ||
| 390 | invert 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\ | ||
| 403 | If you just want to solve the cube, type 'solve' followed by the scramble. This\n\ | ||
| 404 | will not always give you an optimal solution, unless it is 10 moves or less or\n\ | ||
| 405 | you use the \"o\" option. Finding the optimal solution might take very long if it\n\ | ||
| 406 | is 16 moves or more, especially for the first time.\n\ | ||
| 407 | \n\ | ||
| 408 | Now the fun stuff. With nissy you can save and manipulate move sequences, for\n\ | ||
| 409 | example:\n\ | ||
| 410 | \n\ | ||
| 411 | nissy-# save R' U' F\n\ | ||
| 412 | $1: R' U' F\n\ | ||
| 413 | nissy-# add L2D' $1\n\ | ||
| 414 | $1: R' U' F L2 D'\n\ | ||
| 415 | \n\ | ||
| 416 | You can then ask nissy to solve certain substepson a saved scramble:\n\ | ||
| 417 | \n\ | ||
| 418 | nissy-# eo axis=rl $1\n\ | ||
| 419 | @1: U D F' R (4)\n\ | ||
| 420 | \n\ | ||
| 421 | And of course it uses also NISS, if you ask:\n\ | ||
| 422 | \n\ | ||
| 423 | nissy-# eo niss axis=rl $1\n\ | ||
| 424 | @1: (R) (1)\n\ | ||
| 425 | \n\ | ||
| 426 | Notice that the sequences you save are marked with a $, while the \"output\"\n\ | ||
| 427 | sequences are marked with @. The difference between these two type of sequences\n\ | ||
| 428 | is that those marked with @ are temporary and get lost once you get new output.\n\ | ||
| 429 | Most commands accept as input either a move sequence typed out, a $-sequence or\n\ | ||
| 430 | a @-sequence. For example, you can however save a @-sequence and make it\n\ | ||
| 431 | persistent:\n\ | ||
| 432 | \n\ | ||
| 433 | nissy-# save @1\n\ | ||
| 434 | $2: (R)\n\ | ||
| 435 | \n\ | ||
| 436 | Nissy also understands NISS. Let's see a more complicated example where you\n\ | ||
| 437 | save a scramble, ask for some EOs (using NISS) and then a DR on inverse:\n\ | ||
| 438 | \n\ | ||
| 439 | nissy-# 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\ | ||
| 441 | nissy-# eo n=10 niss axis=fb,rl $3\n\ | ||
| 442 | Found 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\ | ||
| 453 | nissy-# 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\ | ||
| 455 | nissy-# 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\ | ||
| 457 | nissy-# 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\ | ||
| 459 | nissy-# 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\ | ||
| 461 | nissy-# dr from rl $5\n\ | ||
| 462 | @1: F2 U D2 F' B D B (7)\n\ | ||
| 463 | nissy-# \n\ | ||
| 464 | \n\ | ||
| 465 | If you ask nissy to solve a substep (or the whole cube) using a sequence with\n\ | ||
| 466 | NISS as scramble, it will first un-NISS it (but without saving the unNISSed\n\ | ||
| 467 | scramble anywhere):\n\ | ||
| 468 | \n\ | ||
| 469 | print $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\ | ||
| 471 | nissy-# 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\ | ||
| 474 | Nissy knows how to solve certain common sub-steps for DR (or Thistlethwaite /\n\ | ||
| 475 | Kociemba algorithms). For now it does know more common speedsolving methods.\n\ | ||
| 476 | \n\ | ||
| 477 | For a full list of commands type \"help\". For a more detailed help on a specific\n\ | ||
| 478 | command, type \"help (command)\". The help pages can also be found in the docs\n\ | ||
| 479 | folder.\n\ | ||
| 480 | \n\ | ||
| 481 | If you want to report a bug (I'm sure there are many!) or give a suggestion,\n\ | ||
| 482 | you can send an email to sebastiano.tronto@gmail.com.\n\ | ||
| 483 | \n\ | ||
| 484 | Have fun!\n\ | ||
| 485 | \n\ | ||
| 486 | " | ||
| 487 | }, | ||
| 488 | |||
| 489 | { "pic", | ||
| 490 | "\ | ||
| 491 | \n\ | ||
| 492 | HELP PAGE FOR COMMAND pic\n\ | ||
| 493 | \n\ | ||
| 494 | SYNTAX\n\ | ||
| 495 | pic [MOVES|$ID|@ID]\n\ | ||
| 496 | \n\ | ||
| 497 | DESCRIPTION\n\ | ||
| 498 | Prints the cube state after applying the given scramble.\n\ | ||
| 499 | \n\ | ||
| 500 | EXAMPLES\n\ | ||
| 501 | pic 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\ | ||
| 504 | EP: FR UL FL UR UF DB DR BL UB BR DL DF \n\ | ||
| 505 | EO(F/B): x x x x x x x x \n\ | ||
| 506 | \n\ | ||
| 507 | UFR UFL UBL UBR DFR DFL DBL DBR \n\ | ||
| 508 | CP: UBR UFR DFL DBL UFL UBL DBR DFR \n\ | ||
| 509 | CO(U/D): ccw cw ccw cw\n\ | ||
| 510 | \n\ | ||
| 511 | " | ||
| 512 | }, | ||
| 513 | |||
| 514 | { "print", | ||
| 515 | "\ | ||
| 516 | \n\ | ||
| 517 | HELP PAGE FOR COMMAND print\n\ | ||
| 518 | \n\ | ||
| 519 | SYNTAX\n\ | ||
| 520 | print [$ID|@ID]\n\ | ||
| 521 | \n\ | ||
| 522 | DESCRIPTION\n\ | ||
| 523 | Prints memorized sequences. If no argument is given, it prints all memorized\n\ | ||
| 524 | scrambles ($ only). If $ID or @ID is specified, it only prints the relative\n\ | ||
| 525 | memorized sequence.\n\ | ||
| 526 | \n\ | ||
| 527 | EXAMPLES\n\ | ||
| 528 | print\n\ | ||
| 529 | Prints a list of all memorized scrambles (only $).\n\ | ||
| 530 | print $2\n\ | ||
| 531 | Prints the second memorized scramble.\n\ | ||
| 532 | print @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\ | ||
| 541 | HELP PAGE FOR COMMAND quit\n\ | ||
| 542 | \n\ | ||
| 543 | SYNTAX\n\ | ||
| 544 | quit\n\ | ||
| 545 | \n\ | ||
| 546 | DESCRIPTION\n\ | ||
| 547 | Exits nissy.\n\ | ||
| 548 | \n\ | ||
| 549 | " | ||
| 550 | }, | ||
| 551 | |||
| 552 | { "replace", | ||
| 553 | "\ | ||
| 554 | \n\ | ||
| 555 | HELP PAGE FOR COMMAND replace\n\ | ||
| 556 | \n\ | ||
| 557 | SYNTAX\n\ | ||
| 558 | eo [OPTIONS] [MOVES|$ID|@ID]\n\ | ||
| 559 | \n\ | ||
| 560 | DESCRIPTION\n\ | ||
| 561 | Looks for non-optimal subsequences and replaces them to shorten the given\n\ | ||
| 562 | sequence. By default it tries to shorten every subsequence of up to 10 moves,\n\ | ||
| 563 | but this can be change with the \"b\" option.\n\ | ||
| 564 | It outputs at most 10 equivalent optimal sequences for each replaceable part.\n\ | ||
| 565 | \n\ | ||
| 566 | OPTIONS\n\ | ||
| 567 | b=N Finds non-optimal subsequences of up to N moves.\n\ | ||
| 568 | \n\ | ||
| 569 | EXAMPLES\n\ | ||
| 570 | replace 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\ | ||
| 572 | Replace [ R2 U' D B2 D B2 ] (moves 7-12) with: [ D R2 D U' ] (-6+4)\n\ | ||
| 573 | Replace [ R2 U' D B2 D B2 U ] (moves 7-13) with: [ D R2 D ] (-7+3)\n\ | ||
| 574 | Replace [ 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\ | ||
| 582 | HELP PAGE FOR COMMAND save\n\ | ||
| 583 | \n\ | ||
| 584 | SYNTAX\n\ | ||
| 585 | save [MOVES|@ID|$ID]\n\ | ||
| 586 | \n\ | ||
| 587 | DESCRIPTION\n\ | ||
| 588 | Memorizes the scramble specified by MOVES, given as input or temporarily saved\n\ | ||
| 589 | as @ID, where ID is a number ('help nissy' for for more on IDs). If an $ID is\n\ | ||
| 590 | given, it makes a copy of the scramble. An identifier of the form $ID, where ID\n\ | ||
| 591 | is a number, is assigned to the memorized scramble.\n\ | ||
| 592 | \n\ | ||
| 593 | EXAMPLES\n\ | ||
| 594 | save R U R' U'\n\ | ||
| 595 | Saves the scramble R U R' U'.\n\ | ||
| 596 | save F (B)\n\ | ||
| 597 | Saves the scramble F (B) (NISS notation).\n\ | ||
| 598 | save @3\n\ | ||
| 599 | Saves the third output sequence of the last command.\n\ | ||
| 600 | save $2\n\ | ||
| 601 | Makes a copy of the second saved scramble.\n\ | ||
| 602 | \n\ | ||
| 603 | " | ||
| 604 | }, | ||
| 605 | |||
| 606 | { "scramble", | ||
| 607 | "\ | ||
| 608 | \n\ | ||
| 609 | HELP PAGE FOR COMMAND scramble\n\ | ||
| 610 | \n\ | ||
| 611 | SYNTAX\n\ | ||
| 612 | scramble [OPTIONS]\n\ | ||
| 613 | \n\ | ||
| 614 | DESCRIPTION\n\ | ||
| 615 | Produces a random-state scramble. There are options to get a corners-only,\n\ | ||
| 616 | edges-only or dr-state scramble.\n\ | ||
| 617 | \n\ | ||
| 618 | OPTIONS\n\ | ||
| 619 | c Scrambles corners only (edges are solved).\n\ | ||
| 620 | e Scrambles edges only (corners are solved).\n\ | ||
| 621 | dr DR-state scramble. The DR is always on the U/D axis.\n\ | ||
| 622 | \n\ | ||
| 623 | \n\ | ||
| 624 | EXAMPLES\n\ | ||
| 625 | scramble\n\ | ||
| 626 | Gives a random-state scramble\n\ | ||
| 627 | scramble dr\n\ | ||
| 628 | Gives a random-DR-state scramble\n\ | ||
| 629 | \n\ | ||
| 630 | " | ||
| 631 | }, | ||
| 632 | |||
| 633 | { "solve", | ||
| 634 | "\ | ||
| 635 | \n\ | ||
| 636 | HELP PAGE FOR COMMAND solve\n\ | ||
| 637 | \n\ | ||
| 638 | SYNTAX\n\ | ||
| 639 | solve [MOVES|$ID|@ID]\n\ | ||
| 640 | \n\ | ||
| 641 | DESCRIPTION\n\ | ||
| 642 | Solves the given scramble, which can be given as a sequence of moves or as $ID\n\ | ||
| 643 | or @ID. If none is given, the user can type it on the next line.\n\ | ||
| 644 | The algorithm first tries to find a short (<=10 moves) solution, and then\n\ | ||
| 645 | switches to a 2-step algorithm (unless the option \"o\" is specified, in which\n\ | ||
| 646 | case it keeps looking for an optimal solution).\n\ | ||
| 647 | The first time it uses the 2-step algorithm it needs to load some tables, which\n\ | ||
| 648 | can take a few seconds. It runs much faster after that. If the option \"o\" is\n\ | ||
| 649 | specified, the first time it loads some large tables, which can take a minute\n\ | ||
| 650 | or two.\n\ | ||
| 651 | \n\ | ||
| 652 | OPTIONS\n\ | ||
| 653 | b=N Only looks for solutions up to N moves.\n\ | ||
| 654 | n=N Tries to find multiple solutions, at most N. Multiple\n\ | ||
| 655 | Solutions will only be found if they are <=10 moves.\n\ | ||
| 656 | o Looks for optimal solution.\n\ | ||
| 657 | \n\ | ||
| 658 | \n\ | ||
| 659 | EXAMPLES\n\ | ||
| 660 | solve R' U' F\n\ | ||
| 661 | Solves the scramble R' U' F.\n\ | ||
| 662 | solve 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\ | ||
| 665 | solve 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\ | ||
| 674 | HELP PAGE FOR COMMAND unniss\n\ | ||
| 675 | \n\ | ||
| 676 | SYNTAX\n\ | ||
| 677 | unniss [MOVES|$ID|@ID]\n\ | ||
| 678 | \n\ | ||
| 679 | DESCRIPTION\n\ | ||
| 680 | Removes NISS from a sequence of moves, which can be given also as $ID or @ID.\n\ | ||
| 681 | A sequence of the form A (B) is translated to B' A.\n\ | ||
| 682 | \n\ | ||
| 683 | EXAMPLES\n\ | ||
| 684 | invert 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 */ | ||
| 10 | char *edge_string(int i) { | ||
| 11 | return (i > -1 && i < 12) ? edge_string_list[i] : "-"; | ||
| 12 | } | ||
| 13 | |||
| 14 | char *corner_string(int i) { | ||
| 15 | return (i > -1 && i < 8) ? corner_string_list[i] : "-"; | ||
| 16 | } | ||
| 17 | |||
| 18 | char *move_string(int i) { | ||
| 19 | return (i > -1 && i < 19) ? move_string_list[i] : "err"; | ||
| 20 | } | ||
| 21 | |||
| 22 | void print_ep_array(int ep[12]) { | ||
| 23 | for (int i = 0; i < 12; i++) | ||
| 24 | printf(" %s ", edge_string(ep[i])); | ||
| 25 | } | ||
| 26 | |||
| 27 | void print_ep_int(int ep) { | ||
| 28 | int aux[12]; | ||
| 29 | ep_int_to_array(ep, aux); | ||
| 30 | print_ep_array(aux); | ||
| 31 | } | ||
| 32 | |||
| 33 | void print_cp_array(int cp[8]) { | ||
| 34 | for (int i = 0; i < 8; i++) | ||
| 35 | printf(" %s ", corner_string(cp[i])); | ||
| 36 | } | ||
| 37 | |||
| 38 | void print_cp_int(int cp) { | ||
| 39 | int aux[8]; | ||
| 40 | cp_int_to_array(cp, aux); | ||
| 41 | print_cp_array(aux); | ||
| 42 | } | ||
| 43 | |||
| 44 | void 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 | |||
| 53 | void print_eo_int(int eo) { | ||
| 54 | int aux[12]; | ||
| 55 | eo_11bits_to_array(eo, aux); | ||
| 56 | print_eo_array(aux); | ||
| 57 | } | ||
| 58 | |||
| 59 | void 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 | |||
| 70 | void print_co_int(int co) { | ||
| 71 | int aux[8]; | ||
| 72 | co_7trits_to_array(co, aux); | ||
| 73 | print_co_array(aux); | ||
| 74 | } | ||
| 75 | |||
| 76 | void 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 | |||
| 94 | void copy_moves(int *src, int *dst) { | ||
| 95 | for (int i = 0; (dst[i] = src[i]); i++); | ||
| 96 | } | ||
| 97 | |||
| 98 | void 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. */ | ||
| 106 | int 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. */ | ||
| 163 | int 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. */ | ||
| 172 | int 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 */ | ||
| 180 | int 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 */ | ||
| 188 | int 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 | |||
| 206 | int 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 | |||
| 212 | int len(int *scram) { | ||
| 213 | int m; | ||
| 214 | for (m = 0; scram[m]; m++); | ||
| 215 | return m; | ||
| 216 | } | ||
| 217 | |||
| 218 | void 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 | |||
| 3 | char *edge_string(int edge); | ||
| 4 | char *corner_string(int edge); | ||
| 5 | char *move_string(int move); | ||
| 6 | |||
| 7 | void print_cube_scram(int *scram); | ||
| 8 | |||
| 9 | void copy_moves(int *src, int *dst); | ||
| 10 | void append_moves(int *src, int *dst); | ||
| 11 | |||
| 12 | int read_moves(char *str, int *a); | ||
| 13 | int read_moves_from_prompt(int *a); | ||
| 14 | int read_moves_from_tok(int n, char tok[][100], int *a); | ||
| 15 | |||
| 16 | int uses_niss(int *str); | ||
| 17 | int unniss(int *src, int *dst); | ||
| 18 | int invert(int *src, int *dst); | ||
| 19 | int len(int *scram); | ||
| 20 | |||
| 21 | void 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 */ | ||
| 12 | int scr_count=1, tmp_count=1, max_tmp=999; | ||
| 13 | int scrambles[255][255], tmp[1000][255]; | ||
| 14 | |||
| 15 | int 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 | |||
| 26 | int 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 | |||
| 31 | void 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 */ | ||
| 54 | int 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 | |||
| 80 | void 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 | |||
| 132 | void 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 | |||
| 152 | void 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 | |||
| 184 | void 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 | |||
| 211 | void 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 | |||
| 245 | void 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 | |||
| 270 | void 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 | |||
| 290 | void 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 | |||
| 304 | void 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 | |||
| 345 | void 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 | |||
| 395 | void 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 | |||
| 403 | void 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 | |||
| 464 | void 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 | |||
| 527 | void 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 | |||
| 609 | void 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 | |||
| 667 | void 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 | |||
| 719 | void 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 | |||
| 760 | void 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 | |||
| 815 | void 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 | |||
| 827 | char *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 | |||
| 873 | void 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 | |||
| 895 | void (*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 | |||
| 905 | void 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 | |||
| 918 | int 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*. */ | ||
| 25 | int possible_next[19][19]; | ||
| 26 | 4 | ||
| 27 | int parallel(int m1, int m2) { | 5 | static Cube apply_move_cubearray(Move m, Cube cube, PieceFilter f); |
| 28 | if (m1 == 0 || m2 == 0) return 0; | 6 | static bool read_mtables_file(); |
| 29 | return ((m1-1)/6 == (m2-1)/6); | 7 | static bool write_mtables_file(); |
| 30 | } | ||
| 31 | 8 | ||
| 32 | int 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); | 14 | static 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)) | 21 | static 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; | 28 | static 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 | ||
| 49 | void init_possible_next() { | 34 | static 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] | 39 | static 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 | ||
| 58 | int edge_cycle[19][12] = { | 44 | static 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 | ||
| 80 | int corner_cycle[19][8] = { | 50 | static 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 */ | 57 | static 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 | ||
| 104 | int eofb_transition_table[pow2to11][19]; | 65 | static int cofb_flipped[NMOVES][8] = { |
| 105 | int eorl_transition_table[pow2to11][19]; | 66 | [U] = { [UFR] = 2, [UBR] = 1, [UBL] = 2, [UFL] = 1 }, |
| 106 | int eoud_transition_table[pow2to11][19]; | 67 | [x] = { |
| 107 | int coud_transition_table[pow3to7][19]; | 68 | [UFR] = 1, [UBR] = 2, [UBL] = 1, [UFL] = 2, |
| 108 | int cofb_transition_table[pow3to7][19]; | 69 | [DFR] = 2, [DBR] = 1, [DBL] = 2, [DFL] = 1 |
| 109 | int corl_transition_table[pow3to7][19]; | 70 | }, |
| 110 | int epud_transition_table[factorial8][19]; | 71 | [y] = { |
| 111 | int eprl_transition_table[factorial8][19]; | 72 | [UFR] = 2, [UBR] = 1, [UBL] = 2, [UFL] = 1, |
| 112 | int epfb_transition_table[factorial8][19]; | 73 | [DFR] = 1, [DBR] = 2, [DBL] = 1, [DFL] = 2 |
| 113 | int epose_transition_table[binom12on4][19]; | 74 | } |
| 114 | int eposs_transition_table[binom12on4][19]; | 75 | }; |
| 115 | int eposm_transition_table[binom12on4][19]; | ||
| 116 | int epe_transition_table[factorial4][19]; | ||
| 117 | int eps_transition_table[factorial4][19]; | ||
| 118 | int epm_transition_table[factorial4][19]; | ||
| 119 | int emslices_transition_table[binom12on4*binom8on4][19]; | ||
| 120 | int cp_transition_table[factorial8][19]; | ||
| 121 | 76 | ||
| 122 | /***/ | 77 | static char equiv_alg_string[100][NMOVES] = { |
| 123 | /* Functions for permuting pieces (given in array format) */ | 78 | [NULLMOVE] = "", |
| 124 | /***/ | ||
| 125 | 79 | ||
| 126 | void 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 | ||
| 134 | void 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 | ||
| 146 | int 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 | ||
| 153 | int apply_move_epud_int(int move, int ep) { | 139 | /* Transition tables, to be loaded up at the beginning */ |
| 154 | int a[12]; | 140 | static int epose_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; |
| 155 | epud_int_to_array(ep, a); | 141 | static int eposs_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; |
| 156 | apply_move_ep_array(move, a); | 142 | static int eposm_mtable[NMOVES][FACTORIAL12/FACTORIAL8]; |
| 157 | return epud_array_to_int(a); | 143 | static int eofb_mtable[NMOVES][POW2TO11]; |
| 158 | } | 144 | static int eorl_mtable[NMOVES][POW2TO11]; |
| 145 | static int eoud_mtable[NMOVES][POW2TO11]; | ||
| 146 | static int cp_mtable[NMOVES][FACTORIAL8]; | ||
| 147 | static int coud_mtable[NMOVES][POW3TO7]; | ||
| 148 | static int cofb_mtable[NMOVES][POW3TO7]; | ||
| 149 | static int corl_mtable[NMOVES][POW3TO7]; | ||
| 150 | static int cpos_mtable[NMOVES][FACTORIAL6]; | ||
| 159 | 151 | ||
| 160 | int 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 | ||
| 167 | int 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 | ||
| 174 | int apply_move_epose_int(int move, int ep) { | 155 | static Cube |
| 175 | int a[12]; | 156 | apply_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 | ||
| 181 | int 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 | ||
| 188 | int 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 | ||
| 195 | int 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 | ||
| 202 | int apply_move_eps_int(int move, int ep) { | 177 | Cube |
| 203 | int a[12]; | 178 | apply_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 | ||
| 209 | int 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 | ||
| 216 | int 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 | ||
| 223 | int 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 | ||
| 230 | int 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 | ||
| 250 | int apply_move_eorl_int(int move, int eo) { | 198 | Cube |
| 251 | int a[12]; | 199 | apply_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 | ||
| 270 | int apply_move_eoud_int(int move, int eo) { | 204 | Cube |
| 271 | int a[12]; | 205 | apply_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 | ||
| 290 | int 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 | ||
| 322 | int apply_move_cofb_int(int move, int co) { | 224 | static bool |
| 323 | int a[8]; | 225 | read_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 | ||
| 354 | int 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 | ||
| 390 | void 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 | ||
| 397 | void 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 | ||
| 404 | void 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 | ||
| 411 | void init_epose_transition_table() { | 273 | static bool |
| 412 | for (int i = 0; i < binom12on4; i++) | 274 | write_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 | ||
| 417 | void 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 | ||
| 423 | void 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 | ||
| 429 | void 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 | ||
| 437 | void 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 | ||
| 445 | void 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 | ||
| 453 | void 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 | ||
| 460 | void init_cp_transition_table() { | 322 | bool |
| 461 | for (int i = 0; i < factorial8; i++) | 323 | commute(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 | ||
| 466 | void 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 | ||
| 472 | void 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 | ||
| 478 | void 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 | ||
| 484 | void 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 | ||
| 490 | void init_cofb_transition_table() { | 346 | bool |
| 491 | for (int i = 0; i < pow3to7; i++) | 347 | possible_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 | ||
| 496 | void 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 | ||
| 502 | void init_transition_table() { | 373 | void |
| 503 | init_epud_transition_table(); | 374 | init_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 | ||
| 13 | extern int possible_next[19][19]; | 8 | Cube apply_alg(Alg *alg, Cube cube); |
| 9 | Cube apply_alg_generic(Alg *alg, Cube c, PieceFilter f, bool a); | ||
| 10 | Cube apply_move(Move m, Cube cube); | ||
| 11 | bool commute(Move m1, Move m2); | ||
| 12 | bool possible_next(Move m1, Move m2, Move m3); | ||
| 14 | 13 | ||
| 15 | int parallel(int m1, int m2); | 14 | void init_moves(); |
| 16 | void init_possible_next(); | ||
| 17 | |||
| 18 | /* Transition tables */ | ||
| 19 | extern int eofb_transition_table[pow2to11][19]; | ||
| 20 | extern int eorl_transition_table[pow2to11][19]; | ||
| 21 | extern int eoud_transition_table[pow2to11][19]; | ||
| 22 | extern int coud_transition_table[pow3to7][19]; | ||
| 23 | extern int cofb_transition_table[pow3to7][19]; | ||
| 24 | extern int corl_transition_table[pow3to7][19]; | ||
| 25 | extern int epud_transition_table[factorial8][19]; | ||
| 26 | extern int epfb_transition_table[factorial8][19]; | ||
| 27 | extern int eprl_transition_table[factorial8][19]; | ||
| 28 | extern int epose_transition_table[binom12on4][19]; | ||
| 29 | extern int eposs_transition_table[binom12on4][19]; | ||
| 30 | extern int eposm_transition_table[binom12on4][19]; | ||
| 31 | extern int epe_transition_table[factorial4][19]; | ||
| 32 | extern int eps_transition_table[factorial4][19]; | ||
| 33 | extern int epm_transition_table[factorial4][19]; | ||
| 34 | extern int emslices_transition_table[binom12on4*binom8on4][19]; | ||
| 35 | extern int cp_transition_table[factorial8][19]; | ||
| 36 | |||
| 37 | |||
| 38 | /* Functions for permuting pieces (given in array format) */ | ||
| 39 | |||
| 40 | void apply_move_ep_array(int move, int ep[12]); | ||
| 41 | void apply_move_cp_array(int move, int cp[8]); | ||
| 42 | |||
| 43 | /* Functions for permuting pieces (given in integer format) */ | ||
| 44 | |||
| 45 | int apply_move_ep_int(int move, int ep); | ||
| 46 | int apply_move_epud_int(int move, int ep); | ||
| 47 | int apply_move_epfb_int(int move, int ep); | ||
| 48 | int apply_move_eprl_int(int move, int ep); | ||
| 49 | int apply_move_epose_int(int move, int ep); | ||
| 50 | int apply_move_eposs_int(int move, int ep); | ||
| 51 | int apply_move_eposm_int(int move, int ep); | ||
| 52 | int apply_move_epe_int(int move, int ep); | ||
| 53 | int apply_move_eps_int(int move, int ep); | ||
| 54 | int apply_move_epm_int(int move, int ep); | ||
| 55 | int apply_move_cp_int(int move, int cp); | ||
| 56 | int apply_move_eofb_int(int move, int eo); | ||
| 57 | int apply_move_eorl_int(int move, int eo); | ||
| 58 | int apply_move_eoud_int(int move, int eo); | ||
| 59 | int apply_move_coud_int(int move, int co); | ||
| 60 | int apply_move_cofb_int(int move, int co); | ||
| 61 | int apply_move_corl_int(int move, int co); | ||
| 62 | |||
| 63 | /* Initialize transition tables */ | ||
| 64 | |||
| 65 | void init_epud_transition_table(); | ||
| 66 | void init_epfb_transition_table(); | ||
| 67 | void init_eprl_transition_table(); | ||
| 68 | void init_epose_transition_table(); | ||
| 69 | void init_eposs_transition_table(); | ||
| 70 | void init_eposm_transition_table(); | ||
| 71 | void init_epe_transition_table(); | ||
| 72 | void init_eps_transition_table(); | ||
| 73 | void init_epm_transition_table(); | ||
| 74 | void init_cp_transition_table(); | ||
| 75 | void init_eofb_transition_table(); | ||
| 76 | void init_eorl_transition_table(); | ||
| 77 | void init_eoud_transition_table(); | ||
| 78 | void init_coud_transition_table(); | ||
| 79 | void init_cofb_transition_table(); | ||
| 80 | void init_corl_transition_table(); | ||
| 81 | |||
| 82 | void 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 | |||
| 3 | PieceFilter | ||
| 4 | pf_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 | |||
| 18 | PieceFilter | ||
| 19 | pf_4val = { | ||
| 20 | .epose = true, | ||
| 21 | .eposs = true, | ||
| 22 | .eposm = true, | ||
| 23 | .eofb = true, | ||
| 24 | .coud = true, | ||
| 25 | .cp = true | ||
| 26 | }; | ||
| 27 | |||
| 28 | PieceFilter | ||
| 29 | pf_epcp = { | ||
| 30 | .epose = true, | ||
| 31 | .eposs = true, | ||
| 32 | .eposm = true, | ||
| 33 | .cp = true | ||
| 34 | }; | ||
| 35 | |||
| 36 | PieceFilter | ||
| 37 | pf_cpos = { | ||
| 38 | .cpos = true | ||
| 39 | }; | ||
| 40 | |||
| 41 | PieceFilter | ||
| 42 | pf_cp = { | ||
| 43 | .cp = true | ||
| 44 | }; | ||
| 45 | |||
| 46 | PieceFilter | ||
| 47 | pf_ep = { | ||
| 48 | .epose = true, | ||
| 49 | .eposs = true, | ||
| 50 | .eposm = true | ||
| 51 | }; | ||
| 52 | |||
| 53 | PieceFilter | ||
| 54 | pf_e = { | ||
| 55 | .epose = true | ||
| 56 | }; | ||
| 57 | |||
| 58 | PieceFilter | ||
| 59 | pf_s = { | ||
| 60 | .eposs = true | ||
| 61 | }; | ||
| 62 | |||
| 63 | PieceFilter | ||
| 64 | pf_m = { | ||
| 65 | .eposm = true | ||
| 66 | }; | ||
| 67 | |||
| 68 | PieceFilter | ||
| 69 | pf_eo = { | ||
| 70 | .eofb = true, | ||
| 71 | .eorl = true, | ||
| 72 | .eoud = true | ||
| 73 | }; | ||
| 74 | |||
| 75 | PieceFilter | ||
| 76 | pf_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 | |||
| 6 | extern PieceFilter pf_all; | ||
| 7 | extern PieceFilter pf_4val; | ||
| 8 | extern PieceFilter pf_epcp; | ||
| 9 | extern PieceFilter pf_cpos; | ||
| 10 | extern PieceFilter pf_cp; | ||
| 11 | extern PieceFilter pf_ep; | ||
| 12 | extern PieceFilter pf_e; | ||
| 13 | extern PieceFilter pf_s; | ||
| 14 | extern PieceFilter pf_m; | ||
| 15 | extern PieceFilter pf_eo; | ||
| 16 | extern 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 | |||
| 3 | static void genptable_bfs(PruneData *pd, int d, Move *ms); | ||
| 4 | static void genptable_branch(PruneData *pd, uint64_t i, int d, Move *m); | ||
| 5 | static void ptable_update(PruneData *pd, Cube cube, int m); | ||
| 6 | static void ptable_update_index(PruneData *pd, uint64_t ind, int m); | ||
| 7 | static int ptableval_index(PruneData *pd, uint64_t ind); | ||
| 8 | static bool read_ptable_file(PruneData *pd); | ||
| 9 | static bool write_ptable_file(PruneData *pd); | ||
| 10 | |||
| 11 | PruneData | ||
| 12 | pd_eofb_HTM = { | ||
| 13 | .filename = "pt_eofb_HTM", | ||
| 14 | .coord = &coord_eofb, | ||
| 15 | .moveset = moveset_HTM, | ||
| 16 | }; | ||
| 17 | |||
| 18 | PruneData | ||
| 19 | pd_coud_HTM = { | ||
| 20 | .filename = "pt_coud_HTM", | ||
| 21 | .coord = &coord_coud, | ||
| 22 | .moveset = moveset_HTM, | ||
| 23 | }; | ||
| 24 | |||
| 25 | PruneData | ||
| 26 | pd_cornershtr_HTM = { | ||
| 27 | .filename = "pt_cornershtr_HTM", | ||
| 28 | .coord = &coord_cornershtr, | ||
| 29 | .moveset = moveset_HTM, | ||
| 30 | }; | ||
| 31 | |||
| 32 | PruneData | ||
| 33 | pd_corners_HTM = { | ||
| 34 | .filename = "pt_corners_HTM", | ||
| 35 | .coord = &coord_corners, | ||
| 36 | .moveset = moveset_HTM, | ||
| 37 | }; | ||
| 38 | |||
| 39 | PruneData | ||
| 40 | pd_drud_sym16_HTM = { | ||
| 41 | .filename = "pt_drud_sym16_HTM", | ||
| 42 | .coord = &coord_drud_sym16, | ||
| 43 | .moveset = moveset_HTM, | ||
| 44 | }; | ||
| 45 | |||
| 46 | PruneData | ||
| 47 | pd_drud_eofb = { | ||
| 48 | .filename = "pt_drud_eofb", | ||
| 49 | .coord = &coord_drud_eofb, | ||
| 50 | .moveset = moveset_eofb, | ||
| 51 | }; | ||
| 52 | |||
| 53 | PruneData | ||
| 54 | pd_drudfin_noE_sym16_drud = { | ||
| 55 | .filename = "pt_drudfin_noE_sym16_drud", | ||
| 56 | .coord = &coord_drudfin_noE_sym16, | ||
| 57 | .moveset = moveset_drud, | ||
| 58 | }; | ||
| 59 | |||
| 60 | PruneData | ||
| 61 | pd_htr_drud = { | ||
| 62 | .filename = "pt_htr_drud", | ||
| 63 | .coord = &coord_htr_drud, | ||
| 64 | .moveset = moveset_drud, | ||
| 65 | }; | ||
| 66 | |||
| 67 | PruneData | ||
| 68 | pd_htrfin_htr = { | ||
| 69 | .filename = "pt_htrfin_htr", | ||
| 70 | .coord = &coord_htrfin, | ||
| 71 | .moveset = moveset_htr, | ||
| 72 | }; | ||
| 73 | |||
| 74 | PruneData | ||
| 75 | pd_khuge_HTM = { | ||
| 76 | .filename = "pt_khuge_HTM", | ||
| 77 | .coord = &coord_khuge, | ||
| 78 | .moveset = moveset_HTM, | ||
| 79 | }; | ||
| 80 | |||
| 81 | void | ||
| 82 | genptable(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 | |||
| 132 | static void | ||
| 133 | genptable_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 | |||
| 142 | static void | ||
| 143 | genptable_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 | |||
| 171 | void | ||
| 172 | print_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 | |||
| 190 | uint64_t | ||
| 191 | ptablesize(PruneData *pd) | ||
| 192 | { | ||
| 193 | return (pd->coord->max + 1) / 2; | ||
| 194 | } | ||
| 195 | |||
| 196 | static void | ||
| 197 | ptable_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 | |||
| 203 | static void | ||
| 204 | ptable_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 | |||
| 213 | int | ||
| 214 | ptableval(PruneData *pd, Cube cube) | ||
| 215 | { | ||
| 216 | return ptableval_index(pd, pd->coord->index(cube)); | ||
| 217 | } | ||
| 218 | |||
| 219 | static int | ||
| 220 | ptableval_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 | |||
| 228 | static bool | ||
| 229 | read_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 | |||
| 250 | static bool | ||
| 251 | write_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 | |||
| 6 | extern PruneData pd_eofb_HTM; | ||
| 7 | extern PruneData pd_coud_HTM; | ||
| 8 | extern PruneData pd_corners_HTM; | ||
| 9 | extern PruneData pd_cornershtr_HTM; | ||
| 10 | extern PruneData pd_drud_sym16_HTM; | ||
| 11 | extern PruneData pd_drud_eofb; | ||
| 12 | extern PruneData pd_drudfin_noE_sym16_drud; | ||
| 13 | extern PruneData pd_htr_drud; | ||
| 14 | extern PruneData pd_htrfin_htr; | ||
| 15 | extern PruneData pd_khuge_HTM; | ||
| 16 | |||
| 17 | void genptable(PruneData *pd); | ||
| 18 | void print_ptable(PruneData *pd); | ||
| 19 | uint64_t ptablesize(PruneData *pd); | ||
| 20 | int 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. */ | ||
| 9 | int eofb_pruning_table[pow2to11]; | ||
| 10 | int eorl_pruning_table[pow2to11]; | ||
| 11 | int eoud_pruning_table[pow2to11]; | ||
| 12 | int coud_pruning_table[pow3to7]; | ||
| 13 | int cofb_pruning_table[pow3to7]; | ||
| 14 | int corl_pruning_table[pow3to7]; | ||
| 15 | int cp_pruning_table[factorial8]; | ||
| 16 | |||
| 17 | int eorl_from_eofb_pruning_table[pow2to11]; | ||
| 18 | int eoud_from_eofb_pruning_table[pow2to11]; | ||
| 19 | int eoud_from_eorl_pruning_table[pow2to11]; | ||
| 20 | int eofb_from_eorl_pruning_table[pow2to11]; | ||
| 21 | int eofb_from_eoud_pruning_table[pow2to11]; | ||
| 22 | int eorl_from_eoud_pruning_table[pow2to11]; | ||
| 23 | |||
| 24 | int coud_from_eofb_pruning_table[pow3to7]; | ||
| 25 | int coud_from_eorl_pruning_table[pow3to7]; | ||
| 26 | int cofb_from_eorl_pruning_table[pow3to7]; | ||
| 27 | int cofb_from_eoud_pruning_table[pow3to7]; | ||
| 28 | int corl_from_eoud_pruning_table[pow3to7]; | ||
| 29 | int corl_from_eofb_pruning_table[pow3to7]; | ||
| 30 | |||
| 31 | int cp_drud_pruning_table[factorial8]; | ||
| 32 | int cp_drfb_pruning_table[factorial8]; | ||
| 33 | int cp_drrl_pruning_table[factorial8]; | ||
| 34 | int epud_pruning_table[factorial8]; | ||
| 35 | int epfb_pruning_table[factorial8]; | ||
| 36 | int eprl_pruning_table[factorial8]; | ||
| 37 | |||
| 38 | int cp_htr_pruning_table[factorial8]; | ||
| 39 | |||
| 40 | int cpud_to_htr_pruning_table[factorial8]; | ||
| 41 | int cpfb_to_htr_pruning_table[factorial8]; | ||
| 42 | int cprl_to_htr_pruning_table[factorial8]; | ||
| 43 | |||
| 44 | |||
| 45 | /* About 1Mb each */ | ||
| 46 | int8_t eofb_epose_pruning_table[pow2to11][binom12on4]; | ||
| 47 | int8_t eorl_eposs_pruning_table[pow2to11][binom12on4]; | ||
| 48 | int8_t eoud_eposm_pruning_table[pow2to11][binom12on4]; | ||
| 49 | |||
| 50 | /* About 4.5Mb each */ | ||
| 51 | int8_t eofb_coud_pruning_table[pow2to11][pow3to7]; | ||
| 52 | int8_t eofb_corl_pruning_table[pow2to11][pow3to7]; | ||
| 53 | int8_t eorl_coud_pruning_table[pow2to11][pow3to7]; | ||
| 54 | int8_t eorl_cofb_pruning_table[pow2to11][pow3to7]; | ||
| 55 | int8_t eoud_cofb_pruning_table[pow2to11][pow3to7]; | ||
| 56 | int8_t eoud_corl_pruning_table[pow2to11][pow3to7]; | ||
| 57 | |||
| 58 | /* About 1Mb each */ | ||
| 59 | int8_t coud_epose_from_eofb_pruning_table[pow3to7][binom12on4]; | ||
| 60 | int8_t cofb_eposs_from_eorl_pruning_table[pow3to7][binom12on4]; | ||
| 61 | int8_t corl_eposm_from_eoud_pruning_table[pow3to7][binom12on4]; | ||
| 62 | int8_t coud_epose_from_eorl_pruning_table[pow3to7][binom12on4]; | ||
| 63 | int8_t cofb_eposs_from_eoud_pruning_table[pow3to7][binom12on4]; | ||
| 64 | int8_t corl_eposm_from_eofb_pruning_table[pow3to7][binom12on4]; | ||
| 65 | |||
| 66 | |||
| 67 | /* Firs one is 88Mb, second one is 71Mb */ | ||
| 68 | int8_t cp_co_pruning_table[factorial8][pow3to7]; | ||
| 69 | int8_t triple_eo_pruning_table[pow2to11][binom12on4*binom8on4]; | ||
| 70 | |||
| 71 | int initialized_small = 0; | ||
| 72 | int initialized_directdr = 0; | ||
| 73 | int initialized_drfromeo = 0; | ||
| 74 | int initialized_huge = 0; | ||
| 75 | |||
| 76 | void 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. */ | ||
| 96 | void 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 | |||
| 126 | void 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 | |||
| 148 | void init_eofb_pruning_table() { | ||
| 149 | init_single_table(pow2to11, eofb_transition_table, eofb_pruning_table, | ||
| 150 | move_mask_all); | ||
| 151 | } | ||
| 152 | |||
| 153 | void init_eorl_pruning_table() { | ||
| 154 | init_single_table(pow2to11, eorl_transition_table, eorl_pruning_table, | ||
| 155 | move_mask_all); | ||
| 156 | } | ||
| 157 | |||
| 158 | void init_eoud_pruning_table() { | ||
| 159 | init_single_table(pow2to11, eoud_transition_table, eoud_pruning_table, | ||
| 160 | move_mask_all); | ||
| 161 | } | ||
| 162 | |||
| 163 | void init_coud_pruning_table() { | ||
| 164 | init_single_table(pow3to7, coud_transition_table, coud_pruning_table, | ||
| 165 | move_mask_all); | ||
| 166 | } | ||
| 167 | |||
| 168 | void init_cofb_pruning_table() { | ||
| 169 | init_single_table(pow3to7, cofb_transition_table, cofb_pruning_table, | ||
| 170 | move_mask_all); | ||
| 171 | } | ||
| 172 | |||
| 173 | void init_corl_pruning_table() { | ||
| 174 | init_single_table(pow3to7, corl_transition_table, corl_pruning_table, | ||
| 175 | move_mask_all); | ||
| 176 | } | ||
| 177 | |||
| 178 | void 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 */ | ||
| 184 | void 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 | |||
| 189 | void 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 | |||
| 194 | void 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 | |||
| 199 | void 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 | |||
| 204 | void 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 | |||
| 209 | void 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 | |||
| 214 | void 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 | |||
| 219 | void 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 | |||
| 224 | void 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 | |||
| 229 | void 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 | |||
| 234 | void 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 | |||
| 239 | void 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 */ | ||
| 245 | void init_epud_pruning_table() { | ||
| 246 | init_single_table(factorial8, epud_transition_table, epud_pruning_table, | ||
| 247 | move_mask_drud); | ||
| 248 | } | ||
| 249 | |||
| 250 | void init_epfb_pruning_table() { | ||
| 251 | init_single_table(factorial8, epfb_transition_table, epfb_pruning_table, | ||
| 252 | move_mask_drfb); | ||
| 253 | } | ||
| 254 | |||
| 255 | void init_eprl_pruning_table() { | ||
| 256 | init_single_table(factorial8, eprl_transition_table, eprl_pruning_table, | ||
| 257 | move_mask_drrl); | ||
| 258 | } | ||
| 259 | |||
| 260 | void init_cp_drud_pruning_table() { | ||
| 261 | init_single_table(factorial8, cp_transition_table, cp_drud_pruning_table, | ||
| 262 | move_mask_drud); | ||
| 263 | } | ||
| 264 | |||
| 265 | void init_cp_drfb_pruning_table() { | ||
| 266 | init_single_table(factorial8, cp_transition_table, cp_drfb_pruning_table, | ||
| 267 | move_mask_drfb); | ||
| 268 | } | ||
| 269 | |||
| 270 | void init_cp_drrl_pruning_table() { | ||
| 271 | init_single_table(factorial8, cp_transition_table, cp_drrl_pruning_table, | ||
| 272 | move_mask_drrl); | ||
| 273 | } | ||
| 274 | |||
| 275 | void init_cp_htr_table() { | ||
| 276 | init_single_table(factorial8, cp_transition_table, cp_htr_pruning_table, | ||
| 277 | move_mask_htr); | ||
| 278 | } | ||
| 279 | |||
| 280 | void init_cpud_to_htr_table() { | ||
| 281 | init_cptohtr_table(factorial8, cp_transition_table, | ||
| 282 | cpud_to_htr_pruning_table, move_mask_drud); | ||
| 283 | } | ||
| 284 | |||
| 285 | void init_cpfb_to_htr_table() { | ||
| 286 | init_cptohtr_table(factorial8, cp_transition_table, | ||
| 287 | cpfb_to_htr_pruning_table, move_mask_drfb); | ||
| 288 | } | ||
| 289 | |||
| 290 | void 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 | |||
| 296 | void 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 | |||
| 302 | void 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 | |||
| 308 | void 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 | |||
| 316 | void 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 | |||
| 322 | void 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 | |||
| 328 | void 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 | |||
| 334 | void 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 | |||
| 340 | void 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 | |||
| 346 | void 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 | |||
| 352 | void 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 | |||
| 358 | void 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 | |||
| 364 | void 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 | |||
| 370 | void 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 | |||
| 376 | void 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 | |||
| 382 | void 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 | |||
| 388 | void 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 | |||
| 394 | void 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 | |||
| 401 | void 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 | |||
| 442 | void 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 | |||
| 460 | void 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 | |||
| 474 | void 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 | |||
| 4 | extern int eofb_pruning_table[pow2to11]; | ||
| 5 | extern int eorl_pruning_table[pow2to11]; | ||
| 6 | extern int eoud_pruning_table[pow2to11]; | ||
| 7 | extern int coud_pruning_table[pow3to7]; | ||
| 8 | extern int cofb_pruning_table[pow3to7]; | ||
| 9 | extern int corl_pruning_table[pow3to7]; | ||
| 10 | extern int cp_pruning_table[factorial8]; | ||
| 11 | |||
| 12 | extern int eorl_from_eofb_pruning_table[pow2to11]; | ||
| 13 | extern int eoud_from_eofb_pruning_table[pow2to11]; | ||
| 14 | extern int eoud_from_eorl_pruning_table[pow2to11]; | ||
| 15 | extern int eofb_from_eorl_pruning_table[pow2to11]; | ||
| 16 | extern int eofb_from_eoud_pruning_table[pow2to11]; | ||
| 17 | extern int eorl_from_eoud_pruning_table[pow2to11]; | ||
| 18 | |||
| 19 | extern int coud_from_eofb_pruning_table[pow3to7]; | ||
| 20 | extern int coud_from_eorl_pruning_table[pow3to7]; | ||
| 21 | extern int cofb_from_eorl_pruning_table[pow3to7]; | ||
| 22 | extern int cofb_from_eoud_pruning_table[pow3to7]; | ||
| 23 | extern int corl_from_eoud_pruning_table[pow3to7]; | ||
| 24 | extern int corl_from_eofb_pruning_table[pow3to7]; | ||
| 25 | |||
| 26 | extern int cp_drud_pruning_table[factorial8]; | ||
| 27 | extern int cp_drfb_pruning_table[factorial8]; | ||
| 28 | extern int cp_drrl_pruning_table[factorial8]; | ||
| 29 | extern int epud_pruning_table[factorial8]; | ||
| 30 | extern int epfb_pruning_table[factorial8]; | ||
| 31 | extern int eprl_pruning_table[factorial8]; | ||
| 32 | |||
| 33 | extern int cp_htr_pruning_table[factorial8]; | ||
| 34 | extern int cpud_to_htr_pruning_table[factorial8]; | ||
| 35 | extern int cpfb_to_htr_pruning_table[factorial8]; | ||
| 36 | extern int cprl_to_htr_pruning_table[factorial8]; | ||
| 37 | |||
| 38 | /* About 1Mb each */ | ||
| 39 | extern int8_t eofb_epose_pruning_table[pow2to11][binom12on4]; | ||
| 40 | extern int8_t eorl_eposs_pruning_table[pow2to11][binom12on4]; | ||
| 41 | extern int8_t eoud_eposm_pruning_table[pow2to11][binom12on4]; | ||
| 42 | |||
| 43 | /* About 4.5Mb each */ | ||
| 44 | extern int8_t eofb_coud_pruning_table[pow2to11][pow3to7]; | ||
| 45 | extern int8_t eofb_corl_pruning_table[pow2to11][pow3to7]; | ||
| 46 | extern int8_t eorl_coud_pruning_table[pow2to11][pow3to7]; | ||
| 47 | extern int8_t eorl_cofb_pruning_table[pow2to11][pow3to7]; | ||
| 48 | extern int8_t eoud_cofb_pruning_table[pow2to11][pow3to7]; | ||
| 49 | extern int8_t eoud_corl_pruning_table[pow2to11][pow3to7]; | ||
| 50 | |||
| 51 | /* About 1Mb each */ | ||
| 52 | extern int8_t coud_epose_from_eofb_pruning_table[pow3to7][binom12on4]; | ||
| 53 | extern int8_t cofb_eposs_from_eorl_pruning_table[pow3to7][binom12on4]; | ||
| 54 | extern int8_t corl_eposm_from_eoud_pruning_table[pow3to7][binom12on4]; | ||
| 55 | extern int8_t coud_epose_from_eorl_pruning_table[pow3to7][binom12on4]; | ||
| 56 | extern int8_t cofb_eposs_from_eoud_pruning_table[pow3to7][binom12on4]; | ||
| 57 | extern int8_t corl_eposm_from_eofb_pruning_table[pow3to7][binom12on4]; | ||
| 58 | |||
| 59 | /* First one 88Mb, second one 21Mb */ | ||
| 60 | extern int8_t cp_co_pruning_table[factorial8][pow3to7]; | ||
| 61 | extern int8_t triple_eo_pruning_table[pow2to11][binom12on4*binom8on4]; | ||
| 62 | |||
| 63 | void init_small_pruning_tables(); | ||
| 64 | void init_directdr_pruning_tables(); | ||
| 65 | void init_drfromeo_pruning_tables(); | ||
| 66 | void 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 | |||
| 3 | static void cleanwhitespaces(char *line); | ||
| 4 | static int parseline(char *line, char **v); | ||
| 5 | |||
| 6 | static void | ||
| 7 | cleanwhitespaces(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 */ | ||
| 17 | static int | ||
| 18 | parseline(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 | |||
| 31 | void | ||
| 32 | exec_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 | |||
| 57 | void | ||
| 58 | launch() | ||
| 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 | |||
| 84 | int | ||
| 85 | main(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 | |||
| 10 | void exec_args(int c, char **v); | ||
| 11 | void 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 | |||
| 5 | static bool allowed_next(Move move, DfsData *dd); | ||
| 6 | static void dfs(Cube c, Step *s, SolveOptions *opts, DfsData *dd); | ||
| 7 | static void dfs_branch(Cube c, Step *s, SolveOptions *os, DfsData *dd); | ||
| 8 | static bool dfs_check_solved(Step *s, SolveOptions *opts, DfsData *dd); | ||
| 9 | static void dfs_niss(Cube c, Step *s, SolveOptions *opts, DfsData *dd); | ||
| 10 | static bool dfs_stop(Cube c, Step *s, SolveOptions *opts, DfsData *dd); | ||
| 11 | |||
| 12 | /* Local functions ***********************************************************/ | ||
| 13 | |||
| 14 | static bool | ||
| 15 | allowed_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 | |||
| 26 | static void | ||
| 27 | dfs(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 | |||
| 41 | static void | ||
| 42 | dfs_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 | |||
| 64 | static bool | ||
| 65 | dfs_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 | |||
| 81 | static void | ||
| 82 | dfs_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 | |||
| 103 | static bool | ||
| 104 | dfs_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 | |||
| 126 | AlgList * | ||
| 127 | solve(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 | |||
| 7 | AlgList * 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. */ | ||
| 12 | int 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 | /******/ | ||
| 34 | void 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 | |||
| 84 | int 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 | /******/ | ||
| 113 | void 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 | |||
| 166 | int 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 */ | ||
| 198 | void 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 | |||
| 255 | int 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 */ | ||
| 338 | void 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 | |||
| 400 | int 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 | /***********************/ | ||
| 455 | void 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 | |||
| 497 | int 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 | /*************/ | ||
| 548 | void 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 | |||
| 586 | int 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 | |||
| 637 | int 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 | /**************/ | ||
| 674 | void 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 | |||
| 717 | int 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 | |||
| 762 | int 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. */ | ||
| 771 | void 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. | ||
| 814 | void 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 */ | ||
| 865 | int 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 | |||
| 892 | int 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). */ | ||
| 984 | int 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 @@ | |||
| 1 | int eo_scram_spam(int scram[], int eo_list[][30], int fb, int rl, int ud, | ||
| 2 | int m, int b, int niss, int h); | ||
| 3 | int 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); | ||
| 5 | int dr_scram_spam(int scram[], int dr_list[][30], int fb, int rl, int ud, | ||
| 6 | int m, int b, int h); | ||
| 7 | int 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); | ||
| 9 | int htr_scram_spam(int scram[], int htr_list[][30], int from, | ||
| 10 | int m, int b, int niss, int hide); | ||
| 11 | int dr_corners_scram_spam(int scram[], int sol[][30], int from, int m, int b, | ||
| 12 | int ignore); | ||
| 13 | int dr_finish_scram_spam(int scram[], int sol[][30], int from, int m, int b); | ||
| 14 | int htr_finish_scram_spam(int scram[], int sol[][30], int m, int b); | ||
| 15 | int solve_scram(int scram[], int sol[][30], int m, int b, int optimal); | ||
| 16 | int 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 | |||
| 5 | static bool check_centers(Cube cube); | ||
| 6 | static bool check_eofb(Cube cube); | ||
| 7 | static bool check_drud(Cube cube); | ||
| 8 | static bool check_htr(Cube cube); | ||
| 9 | |||
| 10 | static int estimate_eoany_HTM(CubeTarget ct); | ||
| 11 | static int estimate_eofb_HTM(CubeTarget ct); | ||
| 12 | static int estimate_coany_HTM(CubeTarget ct); | ||
| 13 | static int estimate_coud_HTM(CubeTarget ct); | ||
| 14 | static int estimate_coany_URF(CubeTarget ct); | ||
| 15 | static int estimate_coud_URF(CubeTarget ct); | ||
| 16 | static int estimate_corners_HTM(CubeTarget ct); | ||
| 17 | static int estimate_cornershtr_HTM(CubeTarget ct); | ||
| 18 | static int estimate_corners_URF(CubeTarget ct); | ||
| 19 | static int estimate_cornershtr_URF(CubeTarget ct); | ||
| 20 | static int estimate_drany_HTM(CubeTarget ct); | ||
| 21 | static int estimate_drud_HTM(CubeTarget ct); | ||
| 22 | static int estimate_drud_eofb(CubeTarget ct); | ||
| 23 | static int estimate_dr_eofb(CubeTarget ct); | ||
| 24 | static int estimate_drudfin_drud(CubeTarget ct); | ||
| 25 | static int estimate_htr_drud(CubeTarget ct); | ||
| 26 | static int estimate_htrfin_htr(CubeTarget ct); | ||
| 27 | static int estimate_optimal_HTM(CubeTarget ct); | ||
| 28 | |||
| 29 | static bool always_valid(Alg *alg); | ||
| 30 | static bool validate_singlecw_ending(Alg *alg); | ||
| 31 | |||
| 32 | /* Pre-transformation detectors **********************************************/ | ||
| 33 | |||
| 34 | static Trans detect_pretrans_eofb(Cube cube); | ||
| 35 | static Trans detect_pretrans_drud(Cube cube); | ||
| 36 | |||
| 37 | /* Messages for when cube is not ready ***************************************/ | ||
| 38 | |||
| 39 | static char check_centers_msg[100] = "cube must be oriented (centers solved)"; | ||
| 40 | static char check_eo_msg[100] = "EO must be solved on given axis"; | ||
| 41 | static char check_dr_msg[100] = "DR must be solved on given axis"; | ||
| 42 | static char check_htr_msg[100] = "HTR must be solved"; | ||
| 43 | static char check_drany_msg[100] = "DR must be solved on at least one axis"; | ||
| 44 | |||
| 45 | /* Steps *********************************************************************/ | ||
| 46 | |||
| 47 | Step | ||
| 48 | optimal_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 **************************/ | ||
| 62 | Step | ||
| 63 | eoany_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 | |||
| 76 | Step | ||
| 77 | eofb_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 | |||
| 90 | Step | ||
| 91 | eorl_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 | |||
| 104 | Step | ||
| 105 | eoud_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 **************************/ | ||
| 119 | Step | ||
| 120 | coany_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 | |||
| 132 | Step | ||
| 133 | coud_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 | |||
| 145 | Step | ||
| 146 | corl_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 | |||
| 158 | Step | ||
| 159 | cofb_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 | |||
| 171 | Step | ||
| 172 | coany_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 | |||
| 184 | Step | ||
| 185 | coud_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 | |||
| 197 | Step | ||
| 198 | corl_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 | |||
| 210 | Step | ||
| 211 | cofb_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 *****************/ | ||
| 224 | Step | ||
| 225 | cornershtr_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 | |||
| 237 | Step | ||
| 238 | cornershtr_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 | |||
| 250 | Step | ||
| 251 | corners_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 | |||
| 263 | Step | ||
| 264 | corners_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 **************************/ | ||
| 277 | Step | ||
| 278 | drany_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 | |||
| 291 | Step | ||
| 292 | drud_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 | |||
| 305 | Step | ||
| 306 | drrl_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 | |||
| 319 | Step | ||
| 320 | drfb_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 */ | ||
| 334 | Step | ||
| 335 | dr_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 | |||
| 348 | Step | ||
| 349 | dr_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 | |||
| 362 | Step | ||
| 363 | dr_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 | |||
| 376 | Step | ||
| 377 | dr_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 | |||
| 390 | Step | ||
| 391 | drud_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 | |||
| 404 | Step | ||
| 405 | drrl_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 | |||
| 418 | Step | ||
| 419 | drud_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 | |||
| 432 | Step | ||
| 433 | drfb_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 | |||
| 446 | Step | ||
| 447 | drfb_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 | |||
| 460 | Step | ||
| 461 | drrl_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 */ | ||
| 475 | Step | ||
| 476 | dranyfin_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 | |||
| 489 | Step | ||
| 490 | drudfin_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 | |||
| 503 | Step | ||
| 504 | drrlfin_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 | |||
| 517 | Step | ||
| 518 | drfbfin_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 */ | ||
| 532 | Step | ||
| 533 | htr_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 | |||
| 546 | Step | ||
| 547 | htr_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 | |||
| 560 | Step | ||
| 561 | htr_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 | |||
| 574 | Step | ||
| 575 | htr_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 */ | ||
| 589 | Step | ||
| 590 | htrfin_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 | |||
| 603 | Step *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 | |||
| 657 | static bool | ||
| 658 | check_centers(Cube cube) | ||
| 659 | { | ||
| 660 | return cube.cpos == 0; | ||
| 661 | } | ||
| 662 | |||
| 663 | static bool | ||
| 664 | check_eofb(Cube cube) | ||
| 665 | { | ||
| 666 | return cube.eofb == 0; | ||
| 667 | } | ||
| 668 | |||
| 669 | static bool | ||
| 670 | check_drud(Cube cube) | ||
| 671 | { | ||
| 672 | return cube.eofb == 0 && cube.eorl == 0 && cube.coud == 0; | ||
| 673 | } | ||
| 674 | |||
| 675 | static bool | ||
| 676 | check_htr(Cube cube) | ||
| 677 | { | ||
| 678 | return check_drud(cube) && coord_htr_drud.index(cube) == 0; | ||
| 679 | } | ||
| 680 | |||
| 681 | static int | ||
| 682 | estimate_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 | |||
| 693 | static int | ||
| 694 | estimate_eofb_HTM(CubeTarget ct) | ||
| 695 | { | ||
| 696 | return ptableval(&pd_eofb_HTM, ct.cube); | ||
| 697 | } | ||
| 698 | |||
| 699 | static int | ||
| 700 | estimate_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 | |||
| 711 | static int | ||
| 712 | estimate_coud_HTM(CubeTarget ct) | ||
| 713 | { | ||
| 714 | return ptableval(&pd_coud_HTM, ct.cube); | ||
| 715 | } | ||
| 716 | |||
| 717 | static int | ||
| 718 | estimate_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 | |||
| 736 | static int | ||
| 737 | estimate_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 | |||
| 752 | static int | ||
| 753 | estimate_corners_HTM(CubeTarget ct) | ||
| 754 | { | ||
| 755 | return ptableval(&pd_corners_HTM, ct.cube); | ||
| 756 | } | ||
| 757 | |||
| 758 | static int | ||
| 759 | estimate_cornershtr_HTM(CubeTarget ct) | ||
| 760 | { | ||
| 761 | return ptableval(&pd_cornershtr_HTM, ct.cube); | ||
| 762 | } | ||
| 763 | |||
| 764 | static int | ||
| 765 | estimate_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 | |||
| 782 | static int | ||
| 783 | estimate_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 | |||
| 800 | static int | ||
| 801 | estimate_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 | |||
| 812 | static int | ||
| 813 | estimate_drud_HTM(CubeTarget ct) | ||
| 814 | { | ||
| 815 | return ptableval(&pd_drud_sym16_HTM, ct.cube); | ||
| 816 | } | ||
| 817 | |||
| 818 | static int | ||
| 819 | estimate_drud_eofb(CubeTarget ct) | ||
| 820 | { | ||
| 821 | return ptableval(&pd_drud_eofb, ct.cube); | ||
| 822 | } | ||
| 823 | |||
| 824 | static int | ||
| 825 | estimate_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 | |||
| 835 | static int | ||
| 836 | estimate_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 | |||
| 846 | static int | ||
| 847 | estimate_htr_drud(CubeTarget ct) | ||
| 848 | { | ||
| 849 | return ptableval(&pd_htr_drud, ct.cube); | ||
| 850 | } | ||
| 851 | |||
| 852 | static int | ||
| 853 | estimate_htrfin_htr(CubeTarget ct) | ||
| 854 | { | ||
| 855 | return ptableval(&pd_htrfin_htr, ct.cube); | ||
| 856 | } | ||
| 857 | |||
| 858 | static int | ||
| 859 | estimate_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 | |||
| 888 | static bool | ||
| 889 | always_valid(Alg *alg) | ||
| 890 | { | ||
| 891 | return true; | ||
| 892 | } | ||
| 893 | |||
| 894 | static bool | ||
| 895 | validate_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 | |||
| 919 | static Trans | ||
| 920 | detect_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 | |||
| 931 | static Trans | ||
| 932 | detect_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 | |||
| 8 | extern 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 | |||
| 3 | static Cube antindex_coud_sym16(uint64_t ind); | ||
| 4 | static Cube antindex_cp_sym16(uint64_t ind); | ||
| 5 | static Cube antindex_eofbepos_sym16(uint64_t ind); | ||
| 6 | static Cube antindex_drud_sym16(uint64_t ind); | ||
| 7 | static Cube antindex_drudfin_noE_sym16(uint64_t ind); | ||
| 8 | static Cube antindex_khuge(uint64_t ind); | ||
| 9 | |||
| 10 | static uint64_t index_coud_sym16(Cube cube); | ||
| 11 | static uint64_t index_cp_sym16(Cube cube); | ||
| 12 | static uint64_t index_eofbepos_sym16(Cube cube); | ||
| 13 | static uint64_t index_drud_sym16(Cube cube); | ||
| 14 | static uint64_t index_drudfin_noE_sym16(Cube cube); | ||
| 15 | static uint64_t index_khuge(Cube cube); | ||
| 16 | |||
| 17 | static void gensym(SymData *sd); | ||
| 18 | static bool read_symdata_file(SymData *sd); | ||
| 19 | static bool write_symdata_file(SymData *sd); | ||
| 20 | |||
| 21 | /* Transformation groups and symmetry data ***********************************/ | ||
| 22 | |||
| 23 | static Trans | ||
| 24 | trans_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 | |||
| 31 | static SymData | ||
| 32 | sd_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 | |||
| 40 | static SymData | ||
| 41 | sd_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 | |||
| 49 | static SymData | ||
| 50 | sd_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 | |||
| 58 | static int nsymdata = 3; | ||
| 59 | static SymData * all_sd[] = { | ||
| 60 | &sd_coud_16, | ||
| 61 | &sd_cp_16, | ||
| 62 | &sd_eofbepos_16, | ||
| 63 | }; | ||
| 64 | |||
| 65 | |||
| 66 | /* Coordinates and their implementation **************************************/ | ||
| 67 | |||
| 68 | Coordinate | ||
| 69 | coord_eofbepos_sym16 = { | ||
| 70 | .index = index_eofbepos_sym16, | ||
| 71 | .cube = antindex_eofbepos_sym16, | ||
| 72 | .ntrans = 16, | ||
| 73 | .trans = trans_group_udfix, | ||
| 74 | }; | ||
| 75 | |||
| 76 | Coordinate | ||
| 77 | coord_coud_sym16 = { | ||
| 78 | .index = index_coud_sym16, | ||
| 79 | .cube = antindex_coud_sym16, | ||
| 80 | .ntrans = 16, | ||
| 81 | .trans = trans_group_udfix, | ||
| 82 | }; | ||
| 83 | |||
| 84 | Coordinate | ||
| 85 | coord_cp_sym16 = { | ||
| 86 | .index = index_cp_sym16, | ||
| 87 | .cube = antindex_cp_sym16, | ||
| 88 | .ntrans = 16, | ||
| 89 | .trans = trans_group_udfix, | ||
| 90 | }; | ||
| 91 | |||
| 92 | Coordinate | ||
| 93 | coord_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 | |||
| 101 | Coordinate | ||
| 102 | coord_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 | |||
| 110 | Coordinate | ||
| 111 | coord_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 | |||
| 121 | static Cube | ||
| 122 | antindex_coud_sym16(uint64_t ind) | ||
| 123 | { | ||
| 124 | return sd_coud_16.rep[ind]; | ||
| 125 | } | ||
| 126 | |||
| 127 | static Cube | ||
| 128 | antindex_cp_sym16(uint64_t ind) | ||
| 129 | { | ||
| 130 | return sd_cp_16.rep[ind]; | ||
| 131 | } | ||
| 132 | |||
| 133 | static Cube | ||
| 134 | antindex_eofbepos_sym16(uint64_t ind) | ||
| 135 | { | ||
| 136 | return sd_eofbepos_16.rep[ind]; | ||
| 137 | } | ||
| 138 | |||
| 139 | static Cube | ||
| 140 | antindex_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 | |||
| 152 | static Cube | ||
| 153 | antindex_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 | |||
| 164 | static Cube | ||
| 165 | antindex_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 | |||
| 176 | static uint64_t | ||
| 177 | index_coud_sym16(Cube cube) | ||
| 178 | { | ||
| 179 | return sd_coud_16.class[coord_coud.index(cube)]; | ||
| 180 | } | ||
| 181 | |||
| 182 | static uint64_t | ||
| 183 | index_cp_sym16(Cube cube) | ||
| 184 | { | ||
| 185 | return sd_cp_16.class[coord_cp.index(cube)]; | ||
| 186 | } | ||
| 187 | |||
| 188 | static uint64_t | ||
| 189 | index_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 | |||
| 200 | static uint64_t | ||
| 201 | index_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 | |||
| 212 | static uint64_t | ||
| 213 | index_eofbepos_sym16(Cube cube) | ||
| 214 | { | ||
| 215 | return sd_eofbepos_16.class[coord_eofbepos.index(cube)]; | ||
| 216 | } | ||
| 217 | |||
| 218 | static uint64_t | ||
| 219 | index_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 | |||
| 234 | static void | ||
| 235 | gensym(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 | |||
| 288 | static bool | ||
| 289 | read_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 | |||
| 314 | static bool | ||
| 315 | write_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 | |||
| 340 | void | ||
| 341 | init_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 | |||
| 6 | extern Coordinate coord_coud_sym16; | ||
| 7 | extern Coordinate coord_cp_sym16; | ||
| 8 | extern Coordinate coord_eofbepos_sym16; | ||
| 9 | extern Coordinate coord_drud_sym16; | ||
| 10 | extern Coordinate coord_drudfin_noE_sym16; | ||
| 11 | extern Coordinate coord_khuge; | ||
| 12 | |||
| 13 | void 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 | |||
| 5 | static bool read_ttables_file(); | ||
| 6 | static Cube rotate_via_compose(Trans r, Cube c, PieceFilter f); | ||
| 7 | static bool write_ttables_file(); | ||
| 8 | |||
| 9 | /* Tables and other data *****************************************************/ | ||
| 10 | |||
| 11 | static 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 | |||
| 17 | static int cp_mirror[8] = { | ||
| 18 | [UFR] = UFL, [UFL] = UFR, [UBL] = UBR, [UBR] = UBL, | ||
| 19 | [DFR] = DFL, [DFL] = DFR, [DBL] = DBR, [DBR] = DBL | ||
| 20 | }; | ||
| 21 | |||
| 22 | static 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? */ | ||
| 29 | static 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 | |||
| 38 | static int epose_source[NTRANS]; /* 0=epose, 1=eposs, 2=eposm */ | ||
| 39 | static int eposs_source[NTRANS]; | ||
| 40 | static int eposm_source[NTRANS]; | ||
| 41 | static int eofb_source[NTRANS]; /* 0=eoud, 1=eorl, 2=eofb */ | ||
| 42 | static int eorl_source[NTRANS]; | ||
| 43 | static int eoud_source[NTRANS]; | ||
| 44 | static int coud_source[NTRANS]; /* 0=coud, 1=corl, 2=cofb */ | ||
| 45 | static int cofb_source[NTRANS]; | ||
| 46 | static int corl_source[NTRANS]; | ||
| 47 | |||
| 48 | static int epose_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; | ||
| 49 | static int eposs_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; | ||
| 50 | static int eposm_ttable[NTRANS][FACTORIAL12/FACTORIAL8]; | ||
| 51 | static int eo_ttable[NTRANS][POW2TO11]; | ||
| 52 | static int cp_ttable[NTRANS][FACTORIAL8]; | ||
| 53 | static int co_ttable[NTRANS][POW3TO7]; | ||
| 54 | static int cpos_ttable[NTRANS][FACTORIAL6]; | ||
| 55 | static Move moves_ttable[NTRANS][NMOVES]; | ||
| 56 | |||
| 57 | /* Local functions implementation ********************************************/ | ||
| 58 | |||
| 59 | static bool | ||
| 60 | read_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 | |||
| 104 | static Cube | ||
| 105 | rotate_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 | |||
| 138 | static bool | ||
| 139 | write_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 | |||
| 184 | Cube | ||
| 185 | apply_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 | |||
| 208 | Trans | ||
| 209 | inverse_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 | |||
| 237 | Alg * | ||
| 238 | rotation_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 | |||
| 255 | void | ||
| 256 | transform_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 | |||
| 266 | void | ||
| 267 | init_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 | |||
| 6 | Cube apply_trans(Trans t, Cube cube); | ||
| 7 | Trans inverse_trans(Trans t); | ||
| 8 | Alg * rotation_alg(Trans i); | ||
| 9 | void transform_alg(Trans i, Alg *alg); | ||
| 10 | |||
| 11 | void 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). */ | 3 | void |
| 4 | int factorial[13] = { | 4 | apply_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)) |
| 9 | void 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 | |||
| 19 | int | ||
| 20 | binomial(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 | |||
| 28 | int | ||
| 29 | digit_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 | |||
| 39 | int | ||
| 40 | factorial(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 | |||
| 53 | void | ||
| 54 | index_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 | |||
| 79 | void | ||
| 80 | index_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 | |||
| 114 | void | ||
| 115 | int_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 | |||
| 127 | void | ||
| 128 | int_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 | 143 | int |
| 16 | * only) and saves the result in r. */ | 144 | invert_digits(int a, int b, int n) |
| 17 | void 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. */ | 157 | bool |
| 25 | int digit_array_to_int(int *a, int n, int b) { | 158 | is_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 | 178 | bool |
| 35 | * of the permutation in the sorted list of all n! such permutations. | 179 | is_subset(int *a, int n, int k) |
| 36 | * Only works for n<=12. */ | 180 | { |
| 37 | int 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 | 189 | int |
| 50 | * (see perm_to_index) and saves the result to r. */ | 190 | perm_sign(int *a, int n) |
| 51 | void 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 | ||
| 204 | int | ||
| 205 | perm_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 | ||
| 69 | int 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 | ||
| 78 | int perm_sign_int(int p, int n) { | 222 | int |
| 79 | int a[n]; | 223 | powint(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 | ||
| 236 | int | ||
| 237 | subset_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]) { |
| 89 | int 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 */ | 256 | void |
| 103 | void index_to_subset(int s, int n, int k, int *r) { | 257 | sum_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; | 265 | void |
| 122 | * then adds one element to the array, so that the sum of the elements of a is | 266 | swap(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 | |
| 126 | void 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 | ||
| 18 | void 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). */ | 23 | void apply_permutation(int *perm, int *set, int n); |
| 21 | extern int factorial[13]; | 24 | int binomial(int n, int k); |
| 22 | 25 | int digit_array_to_int(int *a, int n, int b); | |
| 23 | /* Converts the integer a to its representation in base b (first n digits | 26 | int factorial(int n); |
| 24 | * only) and saves the result in r. */ | 27 | void index_to_perm(int p, int n, int *r); |
| 25 | void int_to_digit_array(int a, int b, int n, int *r); | 28 | void index_to_subset(int s, int n, int k, int *r); |
| 26 | 29 | void 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. */ | 30 | void int_to_sum_zero_array(int x, int b, int n, int *a); |
| 28 | int digit_array_to_int(int *a, int n, int b); | 31 | int invert_digits(int a, int b, int n); |
| 29 | 32 | bool is_perm(int *a, int n); | |
| 30 | /* Converts a permutation on [0..(n-1)] into the integer i which is the index | 33 | bool is_subset(int *a, int n, int k); |
| 31 | * of the permutation in the sorted list of all n! such permutations. | 34 | int perm_sign(int *a, int n); |
| 32 | * Only works for n<=12. */ | 35 | int perm_to_index(int *a, int n); |
| 33 | int perm_to_index(int *a, int n); | 36 | int powint(int a, int b); |
| 34 | 37 | int subset_to_index(int *a, int n, int k); | |
| 35 | /* Converts a permutation index to the actual permutation as an array | 38 | void sum_arrays_mod(int *src, int *dst, int n, int m); |
| 36 | * (see perm_to_index) and saves the result to r. */ | 39 | void swap(int *a, int *b); |
| 37 | void index_to_perm(int p, int n, int *r); | ||
| 38 | |||
| 39 | /* Determine the sign of a permutation, either in integer or array format. */ | ||
| 40 | int perm_sign_array(int a[], int n); | ||
| 41 | int 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. */ | ||
| 47 | int subset_to_index(int *a, int n, int k); | ||
| 48 | |||
| 49 | /* Inverse of the above */ | ||
| 50 | void 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. */ | ||
| 57 | void int_to_sum_zero_array(int x, int b, int n, int *a); | ||
| 58 | 40 | ||
| 41 | #endif | ||
