steps.c (9358B)
1 #include <inttypes.h> 2 #include <stdbool.h> 3 #include <stddef.h> 4 5 #include "cube.h" 6 #include "coord.h" 7 #include "solve.h" 8 9 #define POW2TO11 2048ULL 10 #define POW3TO7 2187ULL 11 #define FACTORIAL4 24ULL 12 #define FACTORIAL8 40320ULL 13 #define BINOM12ON4 495ULL 14 #define BINOM8ON4 70ULL 15 16 static bool moveset_HTM(Move); 17 static bool moveset_eofb(Move); 18 static bool moveset_drud(Move); 19 static bool moveset_htr(Move); 20 21 static int factorial(int); 22 static int perm_to_index(int *, int); 23 static void index_to_perm(int, int, int *); 24 static int binomial(int, int); 25 static int subset_to_index(int *, int, int); 26 static void index_to_subset(int, int, int, int *); 27 static int digit_array_to_int(int *, int, int); 28 static void int_to_digit_array(int, int, int, int *); 29 static void int_to_sum_zero_array(int, int, int, int *); 30 static int perm_sign(int *, int); 31 32 static coord_value_t index_eofb(Cube *cube); 33 static void invindex_eofb(coord_value_t ind, Cube *ret); 34 Indexer i_eofb = { 35 .n = POW2TO11, 36 .index = index_eofb, 37 .to_cube = invindex_eofb, 38 }; 39 40 static coord_value_t index_coud(Cube *cube); 41 static void invindex_coud(coord_value_t ind, Cube *ret); 42 Indexer i_coud = { 43 .n = POW3TO7, 44 .index = index_coud, 45 .to_cube = invindex_coud, 46 }; 47 48 static coord_value_t index_cp(Cube *cube); 49 static void invindex_cp(coord_value_t ind, Cube *ret); 50 Indexer i_cp = { 51 .n = FACTORIAL8, 52 .index = index_cp, 53 .to_cube = invindex_cp, 54 }; 55 56 static coord_value_t index_epos(Cube *cube); 57 static void invindex_epos(coord_value_t ind, Cube *ret); 58 Indexer i_epos = { 59 .n = BINOM12ON4, 60 .index = index_epos, 61 .to_cube = invindex_epos, 62 }; 63 64 static coord_value_t index_epe(Cube *cube); 65 static void invindex_epe(coord_value_t ind, Cube *ret); 66 Indexer i_epe = { 67 .n = FACTORIAL4, 68 .index = index_epe, 69 .to_cube = invindex_epe, 70 }; 71 72 static coord_value_t index_eposepe(Cube *cube); 73 static void invindex_eposepe(coord_value_t ind, Cube *ret); 74 Indexer i_eposepe = { 75 .n = BINOM12ON4 * FACTORIAL4, 76 .index = index_eposepe, 77 .to_cube = invindex_eposepe, 78 }; 79 80 static coord_value_t index_epud(Cube *cube); 81 static void invindex_epud(coord_value_t ind, Cube *ret); 82 Indexer i_epud = { 83 .n = FACTORIAL8, 84 .index = index_epud, 85 .to_cube = invindex_epud, 86 }; 87 88 Coordinate coord_eofb = { 89 .name = "eofb", 90 .type = COMP_COORD, 91 .i = {&i_eofb, NULL}, 92 .moveset = moveset_HTM, 93 }; 94 95 Coordinate coord_coud = { 96 .name = "coud", 97 .type = COMP_COORD, 98 .i = {&i_coud, NULL}, 99 .moveset = moveset_HTM, 100 }; 101 102 Coordinate coord_cp = { 103 .name = "cp", 104 .type = COMP_COORD, 105 .i = {&i_cp, NULL}, 106 .moveset = moveset_HTM, 107 }; 108 109 Coordinate coord_epos = { 110 .name = "epos", 111 .type = COMP_COORD, 112 .i = {&i_epos, NULL}, 113 .moveset = moveset_HTM, 114 }; 115 116 Coordinate coord_epe = { 117 .name = "epe", 118 .type = COMP_COORD, 119 .i = {&i_epe, NULL}, 120 .moveset = moveset_HTM, 121 }; 122 123 Coordinate coord_eposepe = { 124 .name = "eposepe", 125 .type = COMP_COORD, 126 .i = {&i_eposepe, NULL}, 127 .moveset = moveset_HTM, 128 }; 129 130 Coordinate coord_epud = { 131 .name = "epud", 132 .type = COMP_COORD, 133 .i = {&i_epud, NULL}, 134 .moveset = moveset_drud, 135 }; 136 137 Coordinate coord_eofbepos = { 138 .name = "eofbepos", 139 .type = COMP_COORD, 140 .i = {&i_epos, &i_eofb, NULL}, 141 .moveset = moveset_HTM, 142 }; 143 144 Coordinate coord_eofbepos_sym16 = { 145 .name = "eofbepos_sym16", 146 .type = SYM_COORD, 147 .base = {&coord_eofbepos, NULL}, 148 .tgrp = &tgrp_udfix, 149 .moveset = moveset_HTM, 150 }; 151 152 Coordinate coord_cp_sym16 = { 153 .name = "cp_sym16", 154 .type = SYM_COORD, 155 .base = {&coord_cp, NULL}, 156 .tgrp = &tgrp_udfix, 157 .moveset = moveset_HTM, 158 }; 159 160 Coordinate coord_drud_sym16 = { 161 .name = "drud_sym16", 162 .type = SYMCOMP_COORD, 163 .base = {&coord_eofbepos_sym16, &coord_coud}, 164 .moveset = moveset_HTM, 165 }; 166 167 Coordinate coord_drudfin_noE_sym16 = { 168 .name = "drudfin_noE_sym16", 169 .type = SYMCOMP_COORD, 170 .base = {&coord_cp_sym16, &coord_epud}, 171 .moveset = moveset_drud, 172 }; 173 174 Coordinate *coordinates[] = { 175 &coord_eofb, 176 /* 177 TODO: remove non-eo DR step, but add / keep direct DR finish 178 &coord_eofbepos_sym16, &coord_coud, &coord_drud_sym16, 179 */ 180 /* TODO: add back all useful coordinates */ 181 /* 182 &coord_cp_sym16, &coord_epos, &coord_epe, 183 &coord_eposepe, &coord_epud, 184 &coord_drudfin_noE_sym16, 185 */ 186 NULL 187 }; 188 189 Step eofb_HTM = { 190 .shortname = "eofb", 191 .moveset = moveset_HTM, 192 .coord = {&coord_eofb, NULL}, 193 }; 194 195 Step drud_HTM = { 196 .shortname = "drud", 197 .moveset = moveset_HTM, 198 .coord = {&coord_drud_sym16, NULL}, 199 }; 200 201 Step drfin_drud = { 202 .shortname = "drudfin", 203 .moveset = moveset_drud, 204 .coord = {&coord_drudfin_noE_sym16, &coord_epe, NULL}, 205 }; 206 207 Step *steps[] = {&eofb_HTM, &drfin_drud, NULL}; 208 209 static bool 210 moveset_HTM(Move m) 211 { 212 return m >= U && m <= B3; 213 } 214 215 static bool 216 moveset_eofb(Move m) 217 { 218 Move b = base_move(m); 219 220 return b == U || b == D || b == R || b == L || 221 ((b == F || b == B) && m == b+1); 222 } 223 224 static bool 225 moveset_drud(Move m) 226 { 227 Move b = base_move(m); 228 229 return b == U || b == D || 230 ((b == R || b == L || b == F || b == B) && m == b + 1); 231 } 232 233 static bool 234 moveset_htr(Move m) 235 { 236 return moveset_HTM(m) && m == base_move(m) + 1; 237 } 238 239 static int 240 factorial(int n) 241 { 242 int i, ret = 1; 243 244 if (n < 0) 245 return 0; 246 247 for (i = 1; i <= n; i++) 248 ret *= i; 249 250 return ret; 251 } 252 253 static int 254 perm_to_index(int *a, int n) 255 { 256 int i, j, c, ret = 0; 257 258 for (i = 0; i < n; i++) { 259 c = 0; 260 for (j = i+1; j < n; j++) 261 c += (a[i] > a[j]) ? 1 : 0; 262 ret += factorial(n-i-1) * c; 263 } 264 265 return ret; 266 } 267 268 static void 269 index_to_perm(int p, int n, int *r) 270 { 271 int a[n]; 272 int i, j, c; 273 274 for (i = 0; i < n; i++) 275 a[i] = 0; 276 277 if (p < 0 || p >= factorial(n)) 278 for (i = 0; i < n; i++) 279 r[i] = -1; 280 281 for (i = 0; i < n; i++) { 282 c = 0; 283 j = 0; 284 while (c <= p / factorial(n-i-1)) 285 c += a[j++] ? 0 : 1; 286 r[i] = j-1; 287 a[j-1] = 1; 288 p %= factorial(n-i-1); 289 } 290 } 291 292 static int 293 binomial(int n, int k) 294 { 295 if (n < 0 || k < 0 || k > n) 296 return 0; 297 298 return factorial(n) / (factorial(k) * factorial(n-k)); 299 } 300 301 static int 302 subset_to_index(int *a, int n, int k) 303 { 304 int i, ret = 0; 305 306 for (i = 0; i < n; i++) { 307 if (k == n-i) 308 return ret; 309 if (a[i]) { 310 ret += binomial(n-i-1, k); 311 k--; 312 } 313 } 314 315 return ret; 316 } 317 318 static void 319 index_to_subset(int s, int n, int k, int *r) 320 { 321 int i, j, v; 322 323 for (i = 0; i < n; i++) { 324 if (k == n-i) { 325 for (j = i; j < n; j++) 326 r[j] = 1; 327 return; 328 } 329 330 if (k == 0) { 331 for (j = i; j < n; j++) 332 r[j] = 0; 333 return; 334 } 335 336 v = binomial(n-i-1, k); 337 if (s >= v) { 338 r[i] = 1; 339 k--; 340 s -= v; 341 } else { 342 r[i] = 0; 343 } 344 } 345 } 346 347 static int 348 digit_array_to_int(int *a, int n, int b) 349 { 350 int i, ret = 0, p = 1; 351 352 for (i = 0; i < n; i++, p *= b) 353 ret += a[i] * p; 354 355 return ret; 356 } 357 358 static void 359 int_to_digit_array(int a, int b, int n, int *r) 360 { 361 int i; 362 363 for (i = 0; i < n; i++, a /= b) 364 r[i] = a % b; 365 } 366 367 static void 368 int_to_sum_zero_array(int x, int b, int n, int *a) 369 { 370 int i, s = 0; 371 372 int_to_digit_array(x, b, n-1, a); 373 for (i = 0; i < n - 1; i++) 374 s = (s + a[i]) % b; 375 a[n-1] = (b - s) % b; 376 } 377 378 static int 379 perm_sign(int *a, int n) 380 { 381 int i, j, ret = 0; 382 383 for (i = 0; i < n; i++) 384 for (j = i+1; j < n; j++) 385 ret += (a[i] > a[j]) ? 1 : 0; 386 387 return ret % 2; 388 } 389 390 static coord_value_t 391 index_eofb(Cube *cube) 392 { 393 return (coord_value_t)digit_array_to_int(cube->eo, 11, 2); 394 } 395 396 static coord_value_t 397 index_coud(Cube *cube) 398 { 399 return (coord_value_t)digit_array_to_int(cube->co, 7, 3); 400 } 401 402 static coord_value_t 403 index_cp(Cube *cube) 404 { 405 return (coord_value_t)perm_to_index(cube->cp, 8); 406 } 407 408 static coord_value_t 409 index_epe(Cube *cube) 410 { 411 int i, e[4]; 412 413 for (i = 0; i < 4; i++) 414 e[i] = cube->ep[i+8] - 8; 415 416 return (coord_value_t)perm_to_index(e, 4); 417 } 418 419 static coord_value_t 420 index_epud(Cube *cube) 421 { 422 return (coord_value_t)perm_to_index(cube->ep, 8); 423 } 424 425 static coord_value_t 426 index_epos(Cube *cube) 427 { 428 int i, a[12]; 429 430 for (i = 0; i < 12; i++) 431 a[i] = (cube->ep[i] < 8) ? 0 : 1; 432 433 return (coord_value_t)subset_to_index(a, 12, 4); 434 } 435 436 static coord_value_t 437 index_eposepe(Cube *cube) 438 { 439 int i, j, e[4]; 440 coord_value_t epos, epe; 441 442 epos = (coord_value_t)index_epos(cube); 443 for (i = 0, j = 0; i < 12; i++) 444 if (cube->ep[i] >= 8) 445 e[j++] = cube->ep[i] - 8; 446 epe = (coord_value_t)perm_to_index(e, 4); 447 448 return epos * FACTORIAL4 + epe; 449 } 450 451 static void 452 invindex_eofb(coord_value_t ind, Cube *cube) 453 { 454 int_to_sum_zero_array(ind, 2, 12, cube->eo); 455 } 456 457 static void 458 invindex_coud(coord_value_t ind, Cube *cube) 459 { 460 int_to_sum_zero_array(ind, 3, 8, cube->co); 461 } 462 463 static void 464 invindex_cp(coord_value_t ind, Cube *cube) 465 { 466 index_to_perm(ind, 8, cube->cp); 467 } 468 469 static void 470 invindex_epe(coord_value_t ind, Cube *cube) 471 { 472 int i; 473 474 index_to_perm(ind, 4, &cube->ep[8]); 475 for (i = 0; i < 4; i++) 476 cube->ep[i+8] += 8; 477 } 478 479 static void 480 invindex_epud(coord_value_t ind, Cube *cube) 481 { 482 index_to_perm(ind, 8, cube->ep); 483 } 484 485 static void 486 invindex_epos(coord_value_t ind, Cube *cube) 487 { 488 int i, j, k; 489 490 index_to_subset(ind, 12, 4, cube->ep); 491 for (i = 0, j = 0, k = 8; i < 12; i++) 492 if (cube->ep[i] == 0) 493 cube->ep[i] = j++; 494 else 495 cube->ep[i] = k++; 496 } 497 498 static void 499 invindex_eposepe(coord_value_t ind, Cube *cube) 500 { 501 int i, j, k, e[4]; 502 coord_value_t epos, epe; 503 504 epos = ind / FACTORIAL4; 505 epe = ind % FACTORIAL4; 506 507 index_to_subset(epos, 12, 4, cube->ep); 508 index_to_perm(epe, 4, e); 509 510 for (i = 0, j = 0, k = 0; i < 12; i++) 511 if (cube->ep[i] == 0) 512 cube->ep[i] = j++; 513 else 514 cube->ep[i] = e[k++] + 8; 515 }