aboutsummaryrefslogtreecommitdiff
path: root/src/cube.c
diff options
context:
space:
mode:
authorSebastiano Tronto <sebastiano.tronto@gmail.com>2021-11-11 21:37:34 +0100
committerSebastiano Tronto <sebastiano.tronto@gmail.com>2021-11-11 21:37:34 +0100
commit3568412f8f230774d0d11d7ed1c897424f95d3ef (patch)
tree77223792d8c925a9b1fc32b3f4341e943b5f8209 /src/cube.c
parent67e1b5e6e6a2c917a2fe58a37a1382c982b1e5c5 (diff)
downloadnissy-3568412f8f230774d0d11d7ed1c897424f95d3ef.tar.gz
nissy-3568412f8f230774d0d11d7ed1c897424f95d3ef.zip
Rewritten from scratch. Welocme nissy 2.0!
Diffstat (limited to '')
-rw-r--r--src/cube.c701
1 files changed, 701 insertions, 0 deletions
diff --git a/src/cube.c b/src/cube.c
new file mode 100644
index 0000000..06c8b8c
--- /dev/null
+++ b/src/cube.c
@@ -0,0 +1,701 @@
1#include "cube.h"
2
3/* Local functions **********************************************************/
4
5static int array_ep_to_epos(int *ep, int *eps_solved);
6static int epos_from_arrays(int *epos, int *ep);
7
8/* Local functions implementation ********************************************/
9
10static int
11array_ep_to_epos(int *ep, int *ss)
12{
13 int epos[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
14 int eps[4];
15 int i, j, is;
16
17 for (i = 0, is = 0; i < 12; i++) {
18 for (j = 0; j < 4; j++) {
19 if (ep[i] == ss[j]) {
20 eps[is++] = j;
21 epos[i] = 1;
22 }
23 }
24 }
25
26 for (i = 0; i < 4; i++)
27 swap(&epos[ss[i]], &epos[i+8]);
28
29 return epos_from_arrays(epos, eps);
30}
31
32static int
33epos_from_arrays(int *epos, int *ep)
34{
35 return FACTORIAL4 * subset_to_index(epos,12,4) + perm_to_index(ep,4);
36}
37
38/* Public functions implementation *******************************************/
39
40Cube
41arrays_to_cube(CubeArray *arr, PieceFilter f)
42{
43 Cube ret = {0};
44
45 static int epe_solved[4] = {FR, FL, BL, BR};
46 static int eps_solved[4] = {UL, UR, DL, DR};
47 static int epm_solved[4] = {UF, UB, DF, DB};
48
49 if (f.epose)
50 ret.epose = array_ep_to_epos(arr->ep, epe_solved);
51 if (f.eposs)
52 ret.eposs = array_ep_to_epos(arr->ep, eps_solved);
53 if (f.eposm)
54 ret.eposm = array_ep_to_epos(arr->ep, epm_solved);
55 if (f.eofb)
56 ret.eofb = digit_array_to_int(arr->eofb, 11, 2);
57 if (f.eorl)
58 ret.eorl = digit_array_to_int(arr->eorl, 11, 2);
59 if (f.eoud)
60 ret.eoud = digit_array_to_int(arr->eoud, 11, 2);
61 if (f.cp)
62 ret.cp = perm_to_index(arr->cp, 8);
63 if (f.coud)
64 ret.coud = digit_array_to_int(arr->coud, 7, 3);
65 if (f.corl)
66 ret.corl = digit_array_to_int(arr->corl, 7, 3);
67 if (f.cofb)
68 ret.cofb = digit_array_to_int(arr->cofb, 7, 3);
69 if (f.cpos)
70 ret.cpos = perm_to_index(arr->cpos, 6);
71
72 return ret;
73}
74
75Cube
76compose_filtered(Cube c2, Cube c1, PieceFilter f)
77{
78 CubeArray *arr = new_cubearray(c2, f);
79 Cube ret;
80
81 ret = move_via_arrays(arr, c1, f);
82 free_cubearray(arr, f);
83
84 return ret;
85}
86
87void
88cube_to_arrays(Cube cube, CubeArray *arr, PieceFilter f)
89{
90 int i;
91
92 static int epe_solved[4] = {FR, FL, BL, BR};
93 static int eps_solved[4] = {UL, UR, DL, DR};
94 static int epm_solved[4] = {UF, UB, DF, DB};
95
96 if (f.epose || f.eposs || f.eposm)
97 for (i = 0; i < 12; i++)
98 arr->ep[i] = -1;
99
100 if (f.epose)
101 epos_to_partial_ep(cube.epose, arr->ep, epe_solved);
102 if (f.eposs)
103 epos_to_partial_ep(cube.eposs, arr->ep, eps_solved);
104 if (f.eposm)
105 epos_to_partial_ep(cube.eposm, arr->ep, epm_solved);
106 if (f.eofb)
107 int_to_sum_zero_array(cube.eofb, 2, 12, arr->eofb);
108 if (f.eorl)
109 int_to_sum_zero_array(cube.eorl, 2, 12, arr->eorl);
110 if (f.eoud)
111 int_to_sum_zero_array(cube.eoud, 2, 12, arr->eoud);
112 if (f.cp)
113 index_to_perm(cube.cp, 8, arr->cp);
114 if (f.coud)
115 int_to_sum_zero_array(cube.coud, 3, 8, arr->coud);
116 if (f.corl)
117 int_to_sum_zero_array(cube.corl, 3, 8, arr->corl);
118 if (f.cofb)
119 int_to_sum_zero_array(cube.cofb, 3, 8, arr->cofb);
120 if (f.cpos)
121 index_to_perm(cube.cpos, 6, arr->cpos);
122}
123
124void
125epos_to_partial_ep(int epos, int *ep, int *ss)
126{
127 int i, is, eposs[12], eps[4];
128
129 index_to_perm(epos % FACTORIAL4, 4, eps);
130 index_to_subset(epos / FACTORIAL4, 12, 4, eposs);
131
132 for (i = 0; i < 4; i++)
133 swap(&eposs[ss[i]], &eposs[i+8]);
134
135 for (i = 0, is = 0; i < 12; i++)
136 if (eposs[i])
137 ep[i] = ss[eps[is++]];
138}
139
140void
141free_cubearray(CubeArray *arr, PieceFilter f)
142{
143 if (f.epose || f.eposs || f.eposm)
144 free(arr->ep);
145 if (f.eofb)
146 free(arr->eofb);
147 if (f.eorl)
148 free(arr->eorl);
149 if (f.eoud)
150 free(arr->eoud);
151 if (f.cp)
152 free(arr->cp);
153 if (f.coud)
154 free(arr->coud);
155 if (f.corl)
156 free(arr->corl);
157 if (f.cofb)
158 free(arr->cofb);
159 if (f.cpos)
160 free(arr->cpos);
161
162 free(arr);
163}
164
165Cube
166move_via_arrays(CubeArray *arr, Cube c, PieceFilter f)
167{
168 CubeArray *arrc = new_cubearray(c, f);
169 Cube ret;
170
171 if (f.epose || f.eposs || f.eposm)
172 apply_permutation(arr->ep, arrc->ep, 12);
173
174 if (f.eofb) {
175 apply_permutation(arr->ep, arrc->eofb, 12);
176 sum_arrays_mod(arr->eofb, arrc->eofb, 12, 2);
177 }
178
179 if (f.eorl) {
180 apply_permutation(arr->ep, arrc->eorl, 12);
181 sum_arrays_mod(arr->eorl, arrc->eorl, 12, 2);
182 }
183
184 if (f.eoud) {
185 apply_permutation(arr->ep, arrc->eoud, 12);
186 sum_arrays_mod(arr->eoud, arrc->eoud, 12, 2);
187 }
188
189 if (f.cp)
190 apply_permutation(arr->cp, arrc->cp, 8);
191
192 if (f.coud) {
193 apply_permutation(arr->cp, arrc->coud, 8);
194 sum_arrays_mod(arr->coud, arrc->coud, 8, 3);
195 }
196
197 if (f.corl) {
198 apply_permutation(arr->cp, arrc->corl, 8);
199 sum_arrays_mod(arr->corl, arrc->corl, 8, 3);
200 }
201
202 if (f.cofb) {
203 apply_permutation(arr->cp, arrc->cofb, 8);
204 sum_arrays_mod(arr->cofb, arrc->cofb, 8, 3);
205 }
206
207 if (f.cpos)
208 apply_permutation(arr->cpos, arrc->cpos, 6);
209
210 ret = arrays_to_cube(arrc, f);
211 free_cubearray(arrc, f);
212
213 return ret;
214}
215
216CubeArray *
217new_cubearray(Cube cube, PieceFilter f)
218{
219 CubeArray *arr = malloc(sizeof(CubeArray));
220
221 if (f.epose || f.eposs || f.eposm)
222 arr->ep = malloc(12 * sizeof(int));
223 if (f.eofb)
224 arr->eofb = malloc(12 * sizeof(int));
225 if (f.eorl)
226 arr->eorl = malloc(12 * sizeof(int));
227 if (f.eoud)
228 arr->eoud = malloc(12 * sizeof(int));
229 if (f.cp)
230 arr->cp = malloc(8 * sizeof(int));
231 if (f.coud)
232 arr->coud = malloc(8 * sizeof(int));
233 if (f.corl)
234 arr->corl = malloc(8 * sizeof(int));
235 if (f.cofb)
236 arr->cofb = malloc(8 * sizeof(int));
237 if (f.cpos)
238 arr->cpos = malloc(6 * sizeof(int));
239
240 cube_to_arrays(cube, arr, f);
241
242 return arr;
243}
244
245Cube
246admissible_ep(Cube cube, PieceFilter f)
247{
248 CubeArray *arr = new_cubearray(cube, f);
249 Cube ret;
250 bool used[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
251 int i, j;
252
253 for (i = 0; i < 12; i++)
254 if (arr->ep[i] != -1)
255 used[arr->ep[i]] = true;
256
257 for (i = 0, j = 0; i < 12; i++) {
258 for ( ; j < 11 && used[j]; j++);
259 if (arr->ep[i] == -1)
260 arr->ep[i] = j++;
261 }
262
263 ret = arrays_to_cube(arr, pf_ep);
264 free_cubearray(arr, f);
265
266 return ret;
267}
268
269Cube
270compose(Cube c2, Cube c1)
271{
272 return compose_filtered(c2, c1, pf_all);
273}
274
275int
276edge_slice(Edge e) {
277 if (e < 0 || e > 11)
278 return -1;
279
280 if (e == FR || e == FL || e == BL || e == BR)
281 return 0;
282 if (e == UR || e == UL || e == DR || e == DL)
283 return 1;
284
285 return 2;
286}
287
288bool
289equal(Cube c1, Cube c2)
290{
291 return c1.eofb == c2.eofb &&
292 c1.epose == c2.epose &&
293 c1.eposs == c2.eposs &&
294 c1.eposm == c2.eposm &&
295 c1.coud == c2.coud &&
296 c1.cp == c2.cp &&
297 c1.cpos == c2.cpos;
298}
299
300Cube
301inverse_cube(Cube cube)
302{
303 CubeArray *arr = new_cubearray(cube, pf_all);
304 CubeArray *inv = new_cubearray((Cube){0}, pf_all);
305 Cube ret;
306 int i;
307
308 for (i = 0; i < 12; i++) {
309 inv->ep[arr->ep[i]] = i;
310 inv->eofb[arr->ep[i]] = arr->eofb[i];
311 inv->eorl[arr->ep[i]] = arr->eorl[i];
312 inv->eoud[arr->ep[i]] = arr->eoud[i];
313 }
314
315 for (i = 0; i < 8; i++) {
316 inv->cp[arr->cp[i]] = i;
317 inv->coud[arr->cp[i]] = (3 - arr->coud[i]) % 3;
318 inv->corl[arr->cp[i]] = (3 - arr->corl[i]) % 3;
319 inv->cofb[arr->cp[i]] = (3 - arr->cofb[i]) % 3;
320 }
321
322 for (int i = 0; i < 6; i++)
323 inv->cpos[arr->cpos[i]] = i;
324
325 ret = arrays_to_cube(inv, pf_all);
326 free_cubearray(arr, pf_all);
327 free_cubearray(inv, pf_all);
328
329 return ret;
330}
331
332bool
333is_admissible(Cube cube)
334{
335 /* TODO: this should check consistency of different orientations */
336 /* check also that centers are opposite and admissible */
337
338 CubeArray *a = new_cubearray(cube, pf_all);
339 int parity;
340 bool perm;
341
342 perm = is_perm(a->ep, 12) &&
343 is_perm(a->cp, 8) &&
344 is_perm(a->cpos, 6);
345 parity = perm_sign(a->ep, 12) +
346 perm_sign(a->cp, 8) +
347 perm_sign(a->cpos, 6);
348
349 return perm && parity % 2 == 0;
350}
351
352bool
353is_solved(Cube cube)
354{
355 return equal(cube, (Cube){0});
356}
357
358bool
359is_block_solved(Cube cube, Block block)
360{
361 int i;
362
363 for (i = 0; i < 12; i++)
364 if (block.edge[i] && !is_solved_edge(cube, i))
365 return false;
366 for (i = 0; i < 8; i++)
367 if (block.corner[i] && !is_solved_corner(cube, i))
368 return false;
369 for (i = 0; i < 6; i++)
370 if (block.center[i] && !is_solved_center(cube, i))
371 return false;
372
373 return true;
374}
375
376bool
377is_solved_center(Cube cube, Center c)
378{
379 return what_center_at(cube, c) == c;
380}
381
382bool
383is_solved_corner(Cube cube, Corner c)
384{
385 return what_corner_at(cube, c) == c &&
386 what_orientation_corner(cube.coud, c);
387}
388
389bool
390is_solved_edge(Cube cube, Edge e)
391{
392 return what_edge_at(cube, e) == e &&
393 what_orientation_edge(cube.eofb, e);
394}
395
396int
397piece_orientation(Cube cube, int piece, char *orientation)
398{
399 int arr[12], n, b, x;
400
401 if (!strcmp(orientation, "eofb")) {
402 x = cube.eofb;
403 n = 12;
404 b = 2;
405 } else if (!strcmp(orientation, "eorl")) {
406 x = cube.eorl;
407 n = 12;
408 b = 2;
409 } else if (!strcmp(orientation, "eoud")) {
410 x = cube.eoud;
411 n = 12;
412 b = 2;
413 } else if (!strcmp(orientation, "coud")) {
414 x = cube.coud;
415 n = 8;
416 b = 3;
417 } else if (!strcmp(orientation, "corl")) {
418 x = cube.corl;
419 n = 8;
420 b = 3;
421 } else if (!strcmp(orientation, "cofb")) {
422 x = cube.cofb;
423 n = 8;
424 b = 3;
425 } else {
426 return -1;
427 }
428
429 int_to_sum_zero_array(x, b, n, arr);
430 if (piece < n)
431 return arr[piece];
432
433 return -1;
434}
435
436void
437print_cube(Cube cube)
438{
439 static char edge_string[12][7] = {
440 [UF] = "UF", [UL] = "UL", [UB] = "UB", [UR] = "UR",
441 [DF] = "DF", [DL] = "DL", [DB] = "DB", [DR] = "DR",
442 [FR] = "FR", [FL] = "FL", [BL] = "BL", [BR] = "BR"
443 };
444
445 static char corner_string[8][7] = {
446 [UFR] = "UFR", [UFL] = "UFL", [UBL] = "UBL", [UBR] = "UBR",
447 [DFR] = "DFR", [DFL] = "DFL", [DBL] = "DBL", [DBR] = "DBR"
448 };
449
450 static char center_string[6][7] = {
451 [U_center] = "U", [D_center] = "D",
452 [R_center] = "R", [L_center] = "L",
453 [F_center] = "F", [B_center] = "B"
454 };
455
456 for (int i = 0; i < 12; i++)
457 printf(" %s ", edge_string[what_edge_at(cube, i)]);
458 printf("\n");
459
460 for (int i = 0; i < 12; i++)
461 printf(" %d ", what_orientation_edge(cube.eofb, i));
462 printf("\n");
463
464 for (int i = 0; i < 8; i++)
465 printf("%s ", corner_string[what_corner_at(cube, i)]);
466 printf("\n");
467
468 for (int i = 0; i < 8; i++)
469 printf(" %d ", what_orientation_corner(cube.coud, i));
470 printf("\n");
471
472 for (int i = 0; i < 6; i++)
473 printf(" %s ", center_string[what_center_at(cube, i)]);
474 printf("\n");
475}
476
477Cube
478random_cube()
479{
480 CubeArray *arr = new_cubearray((Cube){0}, pf_4val);
481 Cube ret;
482 int ep, cp, eo, co;
483
484 ep = rand() % FACTORIAL12;
485 cp = rand() % FACTORIAL8;
486 eo = rand() % POW2TO11;
487 co = rand() % POW3TO7;
488
489 index_to_perm(ep, 12, arr->ep);
490 index_to_perm(cp, 8, arr->cp);
491 int_to_sum_zero_array(eo, 2, 12, arr->eofb);
492 int_to_sum_zero_array(co, 3, 8, arr->coud);
493
494 if (perm_sign(arr->ep, 12) != perm_sign(arr->cp, 8))
495 swap(&(arr->ep[0]), &(arr->ep[1]));
496
497 ret = arrays_to_cube(arr, pf_4val);
498 free_cubearray(arr, pf_4val);
499
500 return ret;
501}
502
503Center
504what_center_at(Cube cube, Center c)
505{
506 static bool initialized = false;
507 static Center aux[FACTORIAL6][6];
508 static int i;
509 static unsigned int ui;
510 static CubeArray *arr;
511
512 if (!initialized) {
513 for (ui = 0; ui < FACTORIAL6; ui++) {
514 arr = new_cubearray((Cube){.cpos = ui}, pf_cpos);
515 for (i = 0; i < 6; i++)
516 aux[ui][i] = arr->cpos[i];
517 free_cubearray(arr, pf_cpos);
518 }
519
520 initialized = true;
521 }
522
523 return aux[cube.cpos][c];
524}
525
526Corner
527what_corner_at(Cube cube, Corner c)
528{
529 static bool initialized = false;
530 static Corner aux[FACTORIAL8][8];
531 static int i;
532 static unsigned int ui;
533 static CubeArray *arr;
534
535 if (!initialized) {
536 for (ui = 0; ui < FACTORIAL8; ui++) {
537 arr = new_cubearray((Cube){.cp = ui}, pf_cp);
538 for (i = 0; i < 8; i++)
539 aux[ui][i] = arr->cp[i];
540 free_cubearray(arr, pf_cp);
541 }
542
543 initialized = true;
544 }
545
546 return aux[cube.cp][c];
547}
548
549Edge
550what_edge_at(Cube cube, Edge e)
551{
552 Edge ret;
553 CubeArray *arr = new_cubearray(cube, pf_ep);
554
555 ret = arr->ep[e];
556
557 free_cubearray(arr, pf_ep);
558 return ret;
559}
560
561int
562what_orientation_corner(int co, Corner c)
563{
564 static bool initialized = false;
565 static int auxlast[POW3TO7];
566 static int auxarr[8];
567 static unsigned int ui;
568
569 if (!initialized) {
570 for (ui = 0; ui < POW3TO7; ui++) {
571 int_to_sum_zero_array(ui, 3, 8, auxarr);
572 auxlast[ui] = auxarr[7];
573 }
574
575 initialized = true;
576 }
577
578 if (c < 7)
579 return (co / powint(3, c)) % 3;
580 else
581 return auxlast[co];
582}
583
584int
585what_orientation_edge(int eo, Edge e)
586{
587 static bool initialized = false;
588 static int auxlast[POW2TO11];
589 static int auxarr[12];
590 static unsigned int ui;
591
592 if (!initialized) {
593 for (ui = 0; ui < POW2TO11; ui++) {
594 int_to_sum_zero_array(ui, 2, 12, auxarr);
595 auxlast[ui] = auxarr[11];
596 }
597
598 initialized = true;
599 }
600
601 if (e < 11)
602 return (eo & (1 << e)) ? 1 : 0;
603 else
604 return auxlast[eo];
605}
606
607Center
608where_is_center(Cube cube, Center c)
609{
610 static bool initialized = false;
611 static Center aux[FACTORIAL6][6];
612 static int i;
613 static unsigned int ui;
614 static CubeArray *arr;
615
616 if (!initialized) {
617 for (ui = 0; ui < FACTORIAL6; ui++) {
618 arr = new_cubearray((Cube){.cpos = ui}, pf_cpos);
619 for (i = 0; i < 6; i++)
620 aux[ui][arr->cpos[i]] = i;
621 free_cubearray(arr, pf_cpos);
622 }
623
624 initialized = true;
625 }
626
627 return aux[cube.cpos][c];
628}
629
630Corner
631where_is_corner(Cube cube, Corner c)
632{
633 static bool initialized = false;
634 static Corner aux[FACTORIAL8][8];
635 static int i;
636 static unsigned int ui;
637 static CubeArray *arr;
638
639 if (!initialized) {
640 for (ui = 0; ui < FACTORIAL8; ui++) {
641 arr = new_cubearray((Cube){.cp = ui}, pf_cp);
642 for (i = 0; i < 8; i++)
643 aux[ui][arr->cp[i]] = i;
644 free_cubearray(arr, pf_cp);
645 }
646
647 initialized = true;
648 }
649 return aux[cube.cp][c];
650}
651
652Edge
653where_is_edge(Cube cube, Edge e)
654{
655 /* TODO: when I wrote this code I forgot to add the final
656 part, and now I can't remember how it was supposed to
657 work (i.e. how to recover the location of the edge
658 from these tables. I think it is either very easy or
659 wrong, in any case it is not a priority now.
660 Future Seba can deal with it.
661
662 static bool initialized = false;
663 static Edge aux[3][FACTORIAL12/FACTORIAL8][12];
664 static int i;
665 static unsigned int ui;
666 static CubeArray *arr;
667
668 if (!initialized) {
669 for (ui = 0; ui < FACTORIAL12/FACTORIAL8; ui++) {
670 arr = new_cubearray((Cube){.epose = ui}, pf_e);
671 for (i = 0; i < 12; i++)
672 if (edge_slice(arr->ep[i]) == 0)
673 aux[0][ui][arr->ep[i]] = i;
674 free_cubearray(arr, pf_e);
675
676 arr = new_cubearray((Cube){.eposs = ui}, pf_s);
677 for (i = 0; i < 12; i++)
678 if (edge_slice(arr->ep[i]) == 1)
679 aux[1][ui][arr->ep[i]] = i;
680 free_cubearray(arr, pf_s);
681
682 arr = new_cubearray((Cube){.eposm = ui}, pf_m);
683 for (i = 0; i < 12; i++)
684 if (edge_slice(arr->ep[i]) == 2)
685 aux[2][ui][arr->ep[i]] = i;
686 free_cubearray(arr, pf_m);
687 }
688
689 initialized = true;
690 }
691 */
692
693 int i;
694 CubeArray *arr = new_cubearray(cube, pf_ep);
695
696 for (i = 0; i < 12; i++)
697 if ((Edge)arr->ep[i] == e)
698 return i;
699
700 return -1;
701}

Generated with cgit - Back to sebastiano.tronto.net