nissy-classic

Stable branch of nissy
git clone https://git.tronto.net/nissy-classic
Download | Log | Files | Refs | README | LICENSE

cube.c (20155B)


      1 #include "cube.h"
      2 
      3 /* Local functions ***********************************************************/
      4 
      5 static void             init_inverse(void);
      6 static bool             read_invtables_file(void);
      7 static bool             write_invtables_file(void);
      8 
      9 /* Tables ********************************************************************/
     10 
     11 static uint16_t         eo_invtable_e[POW2TO11][BINOM12ON4*FACTORIAL4];
     12 static uint16_t         eo_invtable_s[POW2TO11][BINOM12ON4*FACTORIAL4];
     13 static uint16_t         eo_invtable_m[POW2TO11][BINOM12ON4*FACTORIAL4];
     14 static uint16_t         co_invtable[POW3TO7][FACTORIAL8];
     15 static uint16_t         cp_invtable[FACTORIAL8];
     16 static uint16_t         cpos_invtable[FACTORIAL6];
     17 
     18 /* Functions implementation **************************************************/
     19 
     20 int
     21 array_ep_to_epos(int *ep, int *ss)
     22 {
     23 	int epos[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
     24 	int eps[4];
     25 	int i, j, is;
     26 
     27 	for (i = 0, is = 0; i < 12; i++) {
     28 		for (j = 0; j < 4; j++) {
     29 			if (ep[i] == ss[j]) {
     30 				eps[is++] = j;
     31 				epos[i] = 1;
     32 			}
     33 		}
     34 	}
     35 
     36 	for (i = 0; i < 4; i++)
     37 		swap(&epos[ss[i]], &epos[i+8]);
     38 
     39 	return 24 * subset_to_index(epos, 12, 4) + perm_to_index(eps, 4);
     40 }
     41 
     42 Cube
     43 arrays_to_cube(CubeArray *arr, PieceFilter f)
     44 {
     45 	Cube ret = {0};
     46 
     47 	static int epe_solved[4] = {FR, FL, BL, BR};
     48 	static int eps_solved[4] = {UL, UR, DL, DR};
     49 	static int epm_solved[4] = {UF, UB, DF, DB};
     50 
     51 	if (f.epose)
     52 		ret.epose = array_ep_to_epos(arr->ep, epe_solved);
     53 	if (f.eposs)
     54 		ret.eposs = array_ep_to_epos(arr->ep, eps_solved);
     55 	if (f.eposm)
     56 		ret.eposm = array_ep_to_epos(arr->ep, epm_solved);
     57 	if (f.eofb)
     58 		ret.eofb = digit_array_to_int(arr->eofb, 11, 2);
     59 	if (f.eorl)
     60 		ret.eorl = digit_array_to_int(arr->eorl, 11, 2);
     61 	if (f.eoud)
     62 		ret.eoud = digit_array_to_int(arr->eoud, 11, 2);
     63 	if (f.cp)
     64 		ret.cp = perm_to_index(arr->cp, 8);
     65 	if (f.coud)
     66 		ret.coud = digit_array_to_int(arr->coud, 7, 3);
     67 	if (f.corl)
     68 		ret.corl = digit_array_to_int(arr->corl, 7, 3);
     69 	if (f.cofb)
     70 		ret.cofb = digit_array_to_int(arr->cofb, 7, 3);
     71 	if (f.cpos)
     72 		ret.cpos = perm_to_index(arr->cpos, 6);
     73 
     74 	return ret;
     75 }
     76 
     77 Cube
     78 compose_filtered(Cube c2, Cube c1, PieceFilter f)
     79 {
     80 	CubeArray *arr = new_cubearray(c2, f);
     81 	Cube ret;
     82 
     83 	ret = move_via_arrays(arr, c1, f);
     84 	free_cubearray(arr, f);
     85 
     86 	return ret;
     87 }
     88 
     89 void
     90 cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f)
     91 {
     92 	int i;
     93 
     94 	static int epe_solved[4] = {FR, FL, BL, BR};
     95 	static int eps_solved[4] = {UL, UR, DL, DR};
     96 	static int epm_solved[4] = {UF, UB, DF, DB};
     97 
     98 	if (f.epose || f.eposs || f.eposm)
     99 		for (i = 0; i < 12; i++)
    100 			arr->ep[i] = -1;
    101 
    102 	if (f.epose) 
    103 		epos_to_partial_ep(cube.epose, arr->ep, epe_solved); 
    104 	if (f.eposs) 
    105 		epos_to_partial_ep(cube.eposs, arr->ep, eps_solved); 
    106 	if (f.eposm)
    107 		epos_to_partial_ep(cube.eposm, arr->ep, epm_solved); 
    108 	if (f.eofb)
    109 		int_to_sum_zero_array(cube.eofb, 2, 12, arr->eofb);
    110 	if (f.eorl)
    111 		int_to_sum_zero_array(cube.eorl, 2, 12, arr->eorl);
    112 	if (f.eoud)
    113 		int_to_sum_zero_array(cube.eoud, 2, 12, arr->eoud);
    114 	if (f.cp)
    115 		index_to_perm(cube.cp, 8, arr->cp);
    116 	if (f.coud)
    117 		int_to_sum_zero_array(cube.coud, 3, 8, arr->coud);
    118 	if (f.corl)
    119 		int_to_sum_zero_array(cube.corl, 3, 8, arr->corl);
    120 	if (f.cofb)
    121 		int_to_sum_zero_array(cube.cofb, 3, 8, arr->cofb);
    122 	if (f.cpos)
    123 		index_to_perm(cube.cpos, 6, arr->cpos);
    124 }
    125 
    126 void
    127 epos_to_compatible_ep(int epos, int *ep, int *ss)
    128 {
    129 	int i, j, k, other[8];
    130 	bool flag;
    131 
    132 	for (i = 0; i < 12; i++)
    133 		ep[i] = -1;
    134 
    135 	epos_to_partial_ep(epos, ep, ss);
    136 
    137 	for (i = 0, j = 0; i < 12; i++) {
    138 		flag = false;
    139 		for (k = 0; k < 4; k++)
    140 			flag = flag || (i == ss[k]);
    141 		if (!flag)
    142 			other[j++] = i;
    143 	}
    144 		
    145 	for (i = 0, j = 0; i < 12; i++)
    146 		if (ep[i] == -1)
    147 			ep[i] = other[j++];
    148 }
    149 
    150 void
    151 epos_to_partial_ep(int epos, int *ep, int *ss)
    152 {
    153 	int i, is, eposs[12], eps[4];
    154 
    155 	index_to_perm(epos % FACTORIAL4, 4, eps);
    156 	index_to_subset(epos / FACTORIAL4, 12, 4, eposs);
    157 
    158 	for (i = 0; i < 4; i++)
    159 		swap(&eposs[ss[i]], &eposs[i+8]);
    160 
    161 	for (i = 0, is = 0; i < 12; i++)
    162 		if (eposs[i])
    163 			ep[i] = ss[eps[is++]];
    164 }
    165 
    166 void
    167 fix_eorleoud(CubeArray *arr)
    168 {
    169 	int i;
    170 
    171 	for (i = 0; i < 12; i++) {
    172 		if ((edge_slice(i) == 0 && edge_slice(arr->ep[i]) != 0) ||
    173 		    (edge_slice(i) != 0 && edge_slice(arr->ep[i]) == 0)) {
    174 			arr->eorl[i] = 1 - arr->eofb[i];
    175 		} else {
    176 			arr->eorl[i] = arr->eofb[i];
    177 		}
    178 
    179 		if ((edge_slice(i) == 2 && edge_slice(arr->ep[i]) != 2) ||
    180 		    (edge_slice(i) != 2 && edge_slice(arr->ep[i]) == 2)) {
    181 			arr->eoud[i] = 1 - arr->eofb[i];
    182 		} else {
    183 			arr->eoud[i] = arr->eofb[i];
    184 		}
    185 	}
    186 }
    187 
    188 void
    189 fix_cofbcorl(CubeArray *arr)
    190 {
    191 	int i;
    192 
    193 	for (i = 0; i < 8; i++) {
    194 		if (i % 2 == arr->cp[i] % 2) {
    195 			arr->cofb[i] = arr->coud[i];
    196 			arr->corl[i] = arr->coud[i];
    197 		} else {
    198 			if (arr->cp[i] % 2 == 0) {
    199 				arr->cofb[i] = (arr->coud[i]+1)%3;
    200 				arr->corl[i] = (arr->coud[i]+2)%3;
    201 			} else {
    202 				arr->cofb[i] = (arr->coud[i]+2)%3;
    203 				arr->corl[i] = (arr->coud[i]+1)%3;
    204 			}
    205 		}
    206 	}
    207 }
    208 
    209 Cube
    210 fourval_to_cube(int eofb, int ep, int coud, int cp)
    211 {
    212 	CubeArray *arr;
    213 
    214 	arr = new_cubearray((Cube){0}, pf_all);
    215 
    216 	index_to_perm(ep, 12, arr->ep);
    217 	index_to_perm(cp,  8, arr->cp);
    218 	int_to_sum_zero_array(eofb, 2, 12, arr->eofb);
    219 	int_to_sum_zero_array(coud, 3,  8, arr->coud);
    220 
    221 	/* fix parity */
    222 	if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8))
    223 		swap(&(arr->ep[0]), &(arr->ep[1]));
    224 
    225 	fix_eorleoud(arr);
    226 	fix_cofbcorl(arr);
    227 
    228 	return arrays_to_cube(arr, pf_all);
    229 }
    230 
    231 void
    232 free_cubearray(CubeArray *arr, PieceFilter f)
    233 {
    234 	if (f.epose || f.eposs || f.eposm)
    235 		free(arr->ep);
    236 	if (f.eofb)
    237 		free(arr->eofb);
    238 	if (f.eorl)
    239 		free(arr->eorl);
    240 	if (f.eoud)
    241 		free(arr->eoud);
    242 	if (f.cp)
    243 		free(arr->cp);
    244 	if (f.coud)
    245 		free(arr->coud);
    246 	if (f.corl)
    247 		free(arr->corl);
    248 	if (f.cofb)
    249 		free(arr->cofb);
    250 	if (f.cpos)
    251 		free(arr->cpos);
    252 
    253 	free(arr);
    254 }
    255 
    256 Cube
    257 move_via_arrays(CubeArray *arr, Cube c, PieceFilter f)
    258 {
    259 	CubeArray *arrc = new_cubearray(c, f);
    260 	Cube ret;
    261 
    262 	if (f.epose || f.eposs || f.eposm)
    263 		apply_permutation(arr->ep, arrc->ep, 12);
    264 
    265 	if (f.eofb) {
    266 		apply_permutation(arr->ep, arrc->eofb, 12);
    267 		sum_arrays_mod(arr->eofb, arrc->eofb, 12, 2);
    268 	}
    269 
    270 	if (f.eorl) {
    271 		apply_permutation(arr->ep, arrc->eorl, 12);
    272 		sum_arrays_mod(arr->eorl, arrc->eorl, 12, 2);
    273 	}
    274 
    275 	if (f.eoud) {
    276 		apply_permutation(arr->ep, arrc->eoud, 12);
    277 		sum_arrays_mod(arr->eoud, arrc->eoud, 12, 2);
    278 	}
    279 
    280 	if (f.cp)
    281 		apply_permutation(arr->cp, arrc->cp, 8);
    282 
    283 	if (f.coud) {
    284 		apply_permutation(arr->cp, arrc->coud, 8);
    285 		sum_arrays_mod(arr->coud, arrc->coud, 8, 3);
    286 	}
    287 
    288 	if (f.corl) {
    289 		apply_permutation(arr->cp, arrc->corl, 8);
    290 		sum_arrays_mod(arr->corl, arrc->corl, 8, 3);
    291 	}
    292 
    293 	if (f.cofb) {
    294 		apply_permutation(arr->cp, arrc->cofb, 8);
    295 		sum_arrays_mod(arr->cofb, arrc->cofb, 8, 3);
    296 	}
    297 
    298 	if (f.cpos)
    299 		apply_permutation(arr->cpos, arrc->cpos, 6);
    300 
    301 	ret = arrays_to_cube(arrc, f);
    302 	free_cubearray(arrc, f);
    303 
    304 	return ret;
    305 }
    306 
    307 CubeArray *
    308 new_cubearray(Cube cube, PieceFilter f)
    309 {
    310 	CubeArray *arr = malloc(sizeof(CubeArray));
    311 
    312 	if (f.epose || f.eposs || f.eposm)
    313 		arr->ep   = malloc(12 * sizeof(int));
    314 	if (f.eofb)
    315 		arr->eofb = malloc(12 * sizeof(int));
    316 	if (f.eorl)
    317 		arr->eorl = malloc(12 * sizeof(int));
    318 	if (f.eoud)
    319 		arr->eoud = malloc(12 * sizeof(int));
    320 	if (f.cp)
    321 		arr->cp   = malloc(8  * sizeof(int));
    322 	if (f.coud)
    323 		arr->coud = malloc(8  * sizeof(int));
    324 	if (f.corl)
    325 		arr->corl = malloc(8  * sizeof(int));
    326 	if (f.cofb)
    327 		arr->cofb = malloc(8  * sizeof(int));
    328 	if (f.cpos)
    329 		arr->cpos = malloc(6  * sizeof(int));
    330 
    331 	cube_to_arrays(cube, arr, f);
    332 
    333 	return arr;
    334 }
    335 
    336 Cube
    337 admissible_ep(Cube cube, PieceFilter f)
    338 {
    339 	CubeArray *arr = new_cubearray(cube, f);
    340 	Cube ret;
    341 	bool used[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    342 	int i, j;
    343 
    344 	for (i = 0; i < 12; i++)
    345 		if (arr->ep[i] != -1)
    346 			used[arr->ep[i]] = true;
    347 
    348 	for (i = 0, j = 0; i < 12; i++) {
    349 		for ( ; j < 11 && used[j]; j++);
    350 		if (arr->ep[i] == -1)
    351 			arr->ep[i] = j++;
    352 	}
    353 
    354 	ret = arrays_to_cube(arr, pf_ep);
    355 	free_cubearray(arr, f);
    356 
    357 	return ret;
    358 }
    359 
    360 Cube
    361 compose(Cube c2, Cube c1)
    362 {
    363 	return compose_filtered(c2, c1, pf_all);
    364 }
    365 
    366 int
    367 edge_slice(Edge e) {
    368 	if (e < 0 || e > 11)
    369 		return -1;
    370 
    371 	if (e == FR || e == FL || e == BL || e == BR)
    372 		return 0;
    373 	if (e == UR || e == UL || e == DR || e == DL)
    374 		return 1;
    375 
    376 	return 2;
    377 }
    378 
    379 bool
    380 equal(Cube c1, Cube c2)
    381 {
    382 	return c1.eofb  == c2.eofb  &&
    383 	       c1.epose == c2.epose &&
    384 	       c1.eposs == c2.eposs &&
    385 	       c1.eposm == c2.eposm &&
    386 	       c1.coud  == c2.coud  &&
    387 	       c1.cp    == c2.cp    &&
    388 	       c1.cpos  == c2.cpos;
    389 }
    390 
    391 Cube
    392 inverse_cube(Cube cube)
    393 {
    394 	CubeArray inv;
    395 	Cube ret;
    396 	int i, ep[12];
    397 
    398 	for (i = 0; i < 12; i++)
    399 		ep[i] = where_is_edge(cube, i);
    400 	inv = (CubeArray){.ep = ep};
    401 	ret = arrays_to_cube(&inv, pf_ep);
    402 
    403 	ret.eofb = ((int)eo_invtable_e[cube.eofb][cube.epose]) |
    404 		   ((int)eo_invtable_m[cube.eofb][cube.eposm]) |
    405 		   ((int)eo_invtable_s[cube.eofb][cube.eposs]);
    406 	ret.eorl = ((int)eo_invtable_e[cube.eorl][cube.epose]) |
    407 		   ((int)eo_invtable_m[cube.eorl][cube.eposm]) |
    408 		   ((int)eo_invtable_s[cube.eorl][cube.eposs]);
    409 	ret.eoud = ((int)eo_invtable_e[cube.eoud][cube.epose]) |
    410 		   ((int)eo_invtable_m[cube.eoud][cube.eposm]) |
    411 		   ((int)eo_invtable_s[cube.eoud][cube.eposs]);
    412 	ret.cp   = cp_invtable[cube.cp];
    413 	ret.cpos = cpos_invtable[cube.cpos];
    414 	ret.coud = co_invtable[cube.coud][cube.cp];
    415 	ret.corl = co_invtable[cube.corl][cube.cp];
    416 	ret.cofb = co_invtable[cube.cofb][cube.cp];
    417 
    418 	return ret;
    419 }
    420 
    421 bool
    422 is_admissible(Cube cube) {
    423 
    424 	/* TODO: this should check consistency of different orientations */
    425 	/* check also that centers are opposite and admissible */
    426 
    427 	CubeArray *a = new_cubearray(cube, pf_all);
    428 	int parity;
    429 	bool perm;
    430 
    431 	perm   = is_perm(a->ep,  12)  &&
    432 	         is_perm(a->cp,   8)  &&
    433 	         is_perm(a->cpos, 6);
    434 	parity = perm_sign(a->ep,  12) +
    435 	         perm_sign(a->cp,   8) +
    436 	         perm_sign(a->cpos, 6);
    437 
    438 	free_cubearray(a, pf_all);
    439 
    440 	return perm && parity % 2 == 0;
    441 }
    442 
    443 bool
    444 is_solved(Cube cube)
    445 {
    446 	return equal(cube, (Cube){0});
    447 }
    448 
    449 bool
    450 is_block_solved(Cube cube, Block block)
    451 {
    452 	int i;
    453 
    454 	for (i = 0; i < 12; i++)
    455 		if (block.edge[i] && !is_solved_edge(cube, i))
    456 			return false;
    457 	for (i = 0; i < 8; i++)
    458 		if (block.corner[i] && !is_solved_corner(cube, i))
    459 			return false;
    460 	for (i = 0; i < 6; i++)
    461 		if (block.center[i] && !is_solved_center(cube, i))
    462 			return false;
    463 
    464 	return true;
    465 }
    466 
    467 bool
    468 is_solved_center(Cube cube, Center c)
    469 {
    470 	return what_center_at(cube, c) == c;
    471 }
    472 
    473 bool
    474 is_solved_corner(Cube cube, Corner c)
    475 {
    476 	return what_corner_at(cube, c) == c &&
    477 	       what_orientation_corner(cube.coud, c);
    478 }
    479 
    480 bool
    481 is_solved_edge(Cube cube, Edge e)
    482 {
    483 	return what_edge_at(cube, e) == e &&
    484 	       what_orientation_edge(cube.eofb, e);
    485 }
    486 
    487 int
    488 piece_orientation(Cube cube, int piece, char *orientation)
    489 {
    490 	int arr[12], n, b, x;
    491 
    492 	if (!strcmp(orientation, "eofb")) {
    493 		x = cube.eofb;
    494 		n = 12;
    495 		b = 2;
    496 	} else if (!strcmp(orientation, "eorl")) {
    497 		x = cube.eorl;
    498 		n = 12;
    499 		b = 2;
    500 	} else if (!strcmp(orientation, "eoud")) {
    501 		x = cube.eoud;
    502 		n = 12;
    503 		b = 2;
    504 	} else if (!strcmp(orientation, "coud")) {
    505 		x = cube.coud;
    506 		n = 8;
    507 		b = 3;
    508 	} else if (!strcmp(orientation, "corl")) {
    509 		x = cube.corl;
    510 		n = 8;
    511 		b = 3;
    512 	} else if (!strcmp(orientation, "cofb")) {
    513 		x = cube.cofb;
    514 		n = 8;
    515 		b = 3;
    516 	} else {
    517 		return -1;
    518 	}
    519 
    520 	int_to_sum_zero_array(x, b, n, arr);
    521 	if (piece < n)
    522 		return arr[piece];
    523 
    524 	return -1;
    525 }
    526 
    527 void
    528 print_cube(Cube cube)
    529 {
    530 	static char edge_string[12][7] = {
    531 		[UF] = "UF", [UL] = "UL", [UB] = "UB", [UR] = "UR",
    532 		[DF] = "DF", [DL] = "DL", [DB] = "DB", [DR] = "DR",
    533 		[FR] = "FR", [FL] = "FL", [BL] = "BL", [BR] = "BR"
    534 	};
    535 
    536 	static char corner_string[8][7] = {
    537 		[UFR] = "UFR", [UFL] = "UFL", [UBL] = "UBL", [UBR] = "UBR",
    538 		[DFR] = "DFR", [DFL] = "DFL", [DBL] = "DBL", [DBR] = "DBR"
    539 	};
    540 
    541 	static char center_string[6][7] = {
    542 		[U_center] = "U", [D_center] = "D",
    543 		[R_center] = "R", [L_center] = "L", 
    544 		[F_center] = "F", [B_center] = "B"
    545 	};
    546 
    547 	for (int i = 0; i < 12; i++)
    548 		printf(" %s ", edge_string[what_edge_at(cube, i)]);
    549 	printf("\n");
    550 
    551 	for (int i = 0; i < 12; i++)
    552 		printf("  %d ", what_orientation_edge(cube.eofb, i));
    553 	printf("\n");
    554 
    555 	for (int i = 0; i < 8; i++)
    556 		printf("%s ", corner_string[what_corner_at(cube, i)]);
    557 	printf("\n");
    558 
    559 	for (int i = 0; i < 8; i++)
    560 		printf("  %d ", what_orientation_corner(cube.coud, i));
    561 	printf("\n");
    562 
    563 	for (int i = 0; i < 6; i++)
    564 		printf("  %s ", center_string[what_center_at(cube, i)]);
    565 	printf("\n");
    566 }
    567 
    568 Center
    569 what_center_at(Cube cube, Center c)
    570 {
    571 	static bool initialized = false;
    572 	static Center aux[FACTORIAL6][6];
    573 	static int i;
    574 	static unsigned int ui;
    575 	static CubeArray *arr;
    576 
    577 	if (!initialized) {
    578 		for (ui = 0; ui < FACTORIAL6; ui++) {
    579 			arr = new_cubearray((Cube){.cpos = ui}, pf_cpos);
    580 			for (i = 0; i < 6; i++)
    581 				aux[ui][i] = arr->cpos[i];
    582 			free_cubearray(arr, pf_cpos);
    583 		}
    584 
    585 		initialized = true;
    586 	}
    587 
    588 	return aux[cube.cpos][c];
    589 }
    590 
    591 Corner
    592 what_corner_at(Cube cube, Corner c)
    593 {
    594 	int i;
    595 	unsigned int ui;
    596 	CubeArray *arr;
    597 
    598 	static bool initialized = false;
    599 	static Corner aux[FACTORIAL8][8];
    600 
    601 	if (!initialized) {
    602 		for (ui = 0; ui < FACTORIAL8; ui++) {
    603 			arr = new_cubearray((Cube){.cp = ui}, pf_cp);
    604 			for (i = 0; i < 8; i++)
    605 				aux[ui][i] = arr->cp[i];
    606 			free_cubearray(arr, pf_cp);
    607 		}
    608 
    609 		initialized = true;
    610 	}
    611 
    612 	return aux[cube.cp][c];
    613 }
    614 
    615 Edge
    616 what_edge_at(Cube cube, Edge e)
    617 {
    618 	Edge ret;
    619 	CubeArray *arr = new_cubearray(cube, pf_ep);
    620 
    621 	ret = arr->ep[e];
    622 
    623 	free_cubearray(arr, pf_ep);
    624 	return ret;
    625 }
    626 
    627 int
    628 what_orientation_corner(int co, Corner c)
    629 {
    630 	static bool initialized = false;
    631 	static int auxlast[POW3TO7];
    632 	static int auxarr[8];
    633 	static unsigned int ui;
    634 
    635 	if (!initialized) {
    636 		for (ui = 0; ui < POW3TO7; ui++) {
    637 			int_to_sum_zero_array(ui, 3, 8, auxarr);
    638 			auxlast[ui] = auxarr[7];
    639 		}
    640 
    641 		initialized = true;
    642 	}
    643 
    644 	if (c < 7)
    645 		return (co / powint(3, c)) % 3;
    646 	else
    647 		return auxlast[co];
    648 }
    649 
    650 int
    651 what_orientation_edge(int eo, Edge e)
    652 {
    653 	static bool initialized = false;
    654 	static int auxlast[POW2TO11];
    655 	static int auxarr[12];
    656 	static unsigned int ui;
    657 
    658 	if (!initialized) {
    659 		for (ui = 0; ui < POW2TO11; ui++) {
    660 			int_to_sum_zero_array(ui, 2, 12, auxarr);
    661 			auxlast[ui] = auxarr[11];
    662 		}
    663 
    664 		initialized = true;
    665 	}
    666 
    667 	if (e < 11)
    668 		return (eo & (1 << e)) ? 1 : 0;
    669 	else
    670 		return auxlast[eo];
    671 }
    672 
    673 Center
    674 where_is_center(Cube cube, Center c)
    675 {
    676 	static bool initialized = false;
    677 	static Center aux[FACTORIAL6][6];
    678 	static int i;
    679 	static unsigned int ui;
    680 	static CubeArray *arr;
    681 
    682 	if (!initialized) {
    683 		for (ui = 0; ui < FACTORIAL6; ui++) {
    684 			arr = new_cubearray((Cube){.cpos = ui}, pf_cpos);
    685 			for (i = 0; i < 6; i++)
    686 				aux[ui][arr->cpos[i]] = i;
    687 			free_cubearray(arr, pf_cpos);
    688 		}
    689 
    690 		initialized = true;
    691 	}
    692 
    693 	return aux[cube.cpos][c];
    694 }
    695 
    696 Corner
    697 where_is_corner(Cube cube, Corner c)
    698 {
    699 	static bool initialized = false;
    700 	static Corner aux[FACTORIAL8][8];
    701 	static int i;
    702 	static unsigned int ui;
    703 	static CubeArray *arr;
    704 
    705 	if (!initialized) {
    706 		for (ui = 0; ui < FACTORIAL8; ui++) {
    707 			arr = new_cubearray((Cube){.cp = ui}, pf_cp);
    708 			for (i = 0; i < 8; i++)
    709 				aux[ui][arr->cp[i]] = i;
    710 			free_cubearray(arr, pf_cp);
    711 		}
    712 
    713 		initialized = true;
    714 	}
    715 	return aux[cube.cp][c];
    716 }
    717 
    718 Edge
    719 where_is_edge(Cube c, Edge e)
    720 {
    721 	int r0, r1, r2;
    722 
    723 	static bool initialized = false;
    724 	static int aux[3][BINOM12ON4*FACTORIAL4][12];
    725 	static int i, j;
    726 	static unsigned int ui;
    727 	static CubeArray *arr;
    728 
    729 	if (!initialized) {
    730 		for (ui = 0; ui < BINOM12ON4*FACTORIAL4; ui++) {
    731 			for (i = 0; i < 3; i++)
    732 				for (j = 0; j < 12; j++)
    733 					aux[i][ui][j] = -1;
    734 				
    735 			arr = new_cubearray((Cube){.epose = ui}, pf_e);
    736 			for (i = 0; i < 12; i++)
    737 				if (edge_slice(arr->ep[i]) == 0)
    738 					aux[0][ui][arr->ep[i]] = i;
    739 			free_cubearray(arr, pf_e);
    740 
    741 			arr = new_cubearray((Cube){.eposs = ui}, pf_s);
    742 			for (i = 0; i < 12; i++)
    743 				if (edge_slice(arr->ep[i]) == 1)
    744 					aux[1][ui][arr->ep[i]] = i;
    745 			free_cubearray(arr, pf_s);
    746 
    747 			arr = new_cubearray((Cube){.eposm = ui}, pf_m);
    748 			for (i = 0; i < 12; i++)
    749 				if (edge_slice(arr->ep[i]) == 2)
    750 					aux[2][ui][arr->ep[i]] = i;
    751 			free_cubearray(arr, pf_m);
    752 		}
    753 
    754 		initialized = true;
    755 	}
    756 
    757 	r0 = aux[0][c.epose][e];
    758 	r1 = aux[1][c.eposs][e];
    759 	r2 = aux[2][c.eposm][e];
    760 	return MAX(r0, MAX(r1, r2));
    761 }
    762 
    763 static bool
    764 read_invtables_file(void)
    765 {
    766 	init_env();
    767 
    768 	FILE *f;
    769 	char fname[strlen(tabledir)+20];
    770 	int b;
    771 	unsigned int ui, meeo, meco, mecp, mecpos;
    772 	bool r;
    773 
    774 	strcpy(fname, tabledir);
    775 	strcat(fname, "/invtables");
    776 
    777 	if ((f = fopen(fname, "rb")) == NULL)
    778 		return false;
    779 
    780 	b = sizeof(uint16_t);
    781 	r = true;
    782 	meeo = BINOM12ON4*FACTORIAL4;
    783 	meco = FACTORIAL8;
    784 	mecp = FACTORIAL8;
    785 	mecpos = FACTORIAL6;
    786 
    787 	for (ui = 0; ui < POW2TO11; ui++) {
    788 		r = r && fread(eo_invtable_e[ui], b, meeo, f) == meeo;
    789 		r = r && fread(eo_invtable_m[ui], b, meeo, f) == meeo;
    790 		r = r && fread(eo_invtable_s[ui], b, meeo, f) == meeo;
    791 	}
    792 
    793 	for (ui = 0; ui < POW3TO7; ui++) {
    794 		r = r && fread(co_invtable[ui], b, meco, f) == meco;
    795 	}
    796 
    797 	r = r && fread(cp_invtable,   b, mecp,   f) == mecp;
    798 	r = r && fread(cpos_invtable, b, mecpos, f) == mecpos;
    799 
    800 	fclose(f);
    801 	return r;
    802 }
    803 
    804 static bool
    805 write_invtables_file(void)
    806 {
    807 	init_env();
    808 
    809 	FILE *f;
    810 	char fname[strlen(tabledir)+20];
    811 	unsigned int ui, meeo, meco, mecp, mecpos;
    812 	int b;
    813 	bool r;
    814 
    815 	strcpy(fname, tabledir);
    816 	strcat(fname, "/invtables");
    817 
    818 	if ((f = fopen(fname, "wb")) == NULL)
    819 		return false;
    820 
    821 	b = sizeof(uint16_t);
    822 	r = true;
    823 	meeo = BINOM12ON4*FACTORIAL4;
    824 	meco = FACTORIAL8;
    825 	mecp = FACTORIAL8;
    826 	mecpos = FACTORIAL6;
    827 
    828 	for (ui = 0; ui < POW2TO11; ui++) {
    829 		r = r && fwrite(eo_invtable_e[ui], b, meeo, f) == meeo;
    830 		r = r && fwrite(eo_invtable_m[ui], b, meeo, f) == meeo;
    831 		r = r && fwrite(eo_invtable_s[ui], b, meeo, f) == meeo;
    832 	}
    833 
    834 	for (ui = 0; ui < POW3TO7; ui++) {
    835 		r = r && fwrite(co_invtable[ui], b, meco, f) == meco;
    836 	}
    837 
    838 	r = r && fwrite(cp_invtable,   b, mecp,   f) == mecp;
    839 	r = r && fwrite(cpos_invtable, b, mecpos, f) == mecpos;
    840 
    841 	fclose(f);
    842 	return r;
    843 }
    844 
    845 void
    846 init_inverse(void)
    847 {
    848 	static bool initialized = false;
    849 	if (initialized)
    850 		return;
    851 	initialized = true;
    852 
    853 	if (read_invtables_file())
    854 		return;
    855 
    856 	fprintf(stderr, "Cannot load invtables, generating it\n");
    857 
    858 	CubeArray *aux, *inv;
    859 	Cube c;
    860 	int i, j, eoaux[12], eoinv[12];
    861 	unsigned int ui, uj;
    862 
    863 	aux = new_cubearray((Cube){0}, pf_all);
    864 	inv = new_cubearray((Cube){0}, pf_all);
    865 
    866 	for (ui = 0; ui < POW2TO11; ui++) {
    867 		int_to_sum_zero_array(ui, 2, 12, eoaux);
    868 		for (uj = 0; uj < BINOM12ON4*FACTORIAL4; uj++) {
    869 			for (j = 0; j < 12; j++)
    870 				eoinv[j] = 0;
    871 			c = (Cube){.epose = uj, .eposm = 0, .eposs = 0};
    872 			eoinv[FR] = eoaux[where_is_edge(c, FR)];
    873 			eoinv[FL] = eoaux[where_is_edge(c, FL)];
    874 			eoinv[BL] = eoaux[where_is_edge(c, BL)];
    875 			eoinv[BR] = eoaux[where_is_edge(c, BR)];
    876 			eo_invtable_e[ui][uj] = digit_array_to_int(eoinv,11,2);
    877  
    878 			for (j = 0; j < 12; j++)
    879 				eoinv[j] = 0;
    880 			c = (Cube){.epose = 0, .eposm = uj, .eposs = 0};
    881 			eoinv[UF] = eoaux[where_is_edge(c, UF)];
    882 			eoinv[UB] = eoaux[where_is_edge(c, UB)];
    883 			eoinv[DF] = eoaux[where_is_edge(c, DF)];
    884 			eoinv[DB] = eoaux[where_is_edge(c, DB)];
    885 			eo_invtable_m[ui][uj] = digit_array_to_int(eoinv,11,2);
    886  
    887 			for (j = 0; j < 12; j++)
    888 				eoinv[j] = 0;
    889 			c = (Cube){.epose = 0, .eposm = 0, .eposs = uj};
    890 			eoinv[UL] = eoaux[where_is_edge(c, UL)];
    891 			eoinv[UR] = eoaux[where_is_edge(c, UR)];
    892 			eoinv[DL] = eoaux[where_is_edge(c, DL)];
    893 			eoinv[DR] = eoaux[where_is_edge(c, DR)];
    894 			eo_invtable_s[ui][uj] = digit_array_to_int(eoinv,11,2);
    895 		}
    896 	}
    897 
    898 	for (ui = 0; ui < FACTORIAL8; ui++) {
    899 		cube_to_arrays((Cube){.cp = ui}, aux, pf_cp);
    900 		for (i = 0; i < 8; i++)
    901 			inv->cp[aux->cp[i]] = i;
    902 		cp_invtable[ui] = (uint16_t)arrays_to_cube(inv, pf_cp).cp;
    903 
    904 		for (uj = 0; uj < POW3TO7; uj++) {
    905 			cube_to_arrays((Cube){.coud = uj}, aux, pf_coud);
    906 			for (i = 0; i < 8; i++)
    907 				inv->coud[aux->cp[i]] = (3-aux->coud[i])%3;
    908 			co_invtable[uj][ui] =
    909 			    (uint16_t)arrays_to_cube(inv, pf_coud).coud;
    910 		}
    911 	}
    912 	
    913 	for (ui = 0; ui < FACTORIAL6; ui++) {
    914 		cube_to_arrays((Cube){.cpos = ui}, aux, pf_cpos);
    915 		for (i = 0; i < 6; i++)
    916 			inv->cpos[aux->cpos[i]] = i;
    917 		cpos_invtable[ui] =
    918 		    (uint16_t)arrays_to_cube(inv, pf_cpos).cpos;
    919 	}
    920 
    921 	free_cubearray(aux, pf_all);
    922 	free_cubearray(inv, pf_all);
    923 
    924 	if (!write_invtables_file())
    925 		fprintf(stderr, "Error writing invtables\n");
    926 }
    927 
    928 void
    929 init_cube(void)
    930 {
    931 	init_inverse();
    932 }