nissy-fmc

A Rubik's cube FMC assistant
git clone https://git.tronto.net/nissy-fmc
Download | Log | Files | Refs | README | LICENSE

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 }