aboutsummaryrefslogtreecommitdiff
path: root/src/cube_routines.h
diff options
context:
space:
mode:
authorSebastiano Tronto <sebastiano@tronto.net>2024-05-10 09:10:12 +0200
committerSebastiano Tronto <sebastiano@tronto.net>2024-05-10 09:10:12 +0200
commita660922d738b78b11fc78207daabea031058f710 (patch)
treedb46bd95bffeb330cea6066c77f2709f96c033aa /src/cube_routines.h
parent75966319fd5891c2c1bd35b1f7c93eab172fd28e (diff)
downloadnissy-core-a660922d738b78b11fc78207daabea031058f710.tar.gz
nissy-core-a660922d738b78b11fc78207daabea031058f710.zip
Split into .h files
Diffstat (limited to '')
-rw-r--r--src/cube_routines.h730
1 files changed, 730 insertions, 0 deletions
diff --git a/src/cube_routines.h b/src/cube_routines.h
new file mode 100644
index 0000000..b1f8eac
--- /dev/null
+++ b/src/cube_routines.h
@@ -0,0 +1,730 @@
1#define _move(M, c) compose_fast(c, _move_cube_ ## M)
2#define _premove(M, c) compose_fast(_move_cube_ ## M, c)
3#define _trans_rotation(T, c) \
4 compose_fast(compose_fast(_trans_cube_ ## T, c), \
5 _trans_cube_ ## T ## _inverse)
6#define _trans_mirrored(T, c) \
7 invertco_fast(compose_fast(compose_fast(_trans_cube_ ## T, c), \
8 _trans_cube_ ## T ## _inverse))
9
10_static int permsign(uint8_t *, int);
11_static uint8_t readco(const char *);
12_static uint8_t readcp(const char *);
13_static uint8_t readeo(const char *);
14_static uint8_t readep(const char *);
15_static cube_t readcube_H48(const char *);
16_static uint8_t readpiece_LST(const char **);
17_static cube_t readcube_LST(const char *);
18_static int writepiece_LST(uint8_t, char *);
19_static void writecube_H48(cube_t, char *);
20_static void writecube_LST(cube_t, char *);
21_static uint8_t readmove(char);
22_static uint8_t readmodifier(char);
23_static uint8_t readtrans(const char *);
24_static int writemoves(uint8_t *, int, char *);
25_static void writetrans(uint8_t, char *);
26_static cube_fast_t move(cube_fast_t, uint8_t);
27_static cube_fast_t transform(cube_fast_t, uint8_t);
28
29cube_t
30solvedcube(void)
31{
32 return solved;
33}
34
35bool
36isconsistent(cube_t cube)
37{
38 uint8_t i, p, e, piece;
39 bool found[12];
40
41 for (i = 0; i < 12; i++)
42 found[i] = false;
43 for (i = 0; i < 12; i++) {
44 piece = cube.edge[i];
45 p = piece & _pbits;
46 e = piece & _eobit;
47 if (p >= 12)
48 goto inconsistent_ep;
49 if (e != 0 && e != _eobit)
50 goto inconsistent_eo;
51 found[p] = true;
52 }
53 for (i = 0; i < 12; i++)
54 if (!found[i])
55 goto inconsistent_ep;
56
57 for (i = 0; i < 8; i++)
58 found[i] = false;
59 for (i = 0; i < 8; i++) {
60 piece = cube.corner[i];
61 p = piece & _pbits;
62 e = piece & _cobits;
63 if (p >= 8)
64 goto inconsistent_cp;
65 if (e != 0 && e != _ctwist_cw && e != _ctwist_ccw)
66 goto inconsistent_co;
67 found[p] = true;
68 }
69 for (i = 0; i < 8; i++)
70 if (!found[i])
71 goto inconsistent_co;
72
73 return true;
74
75inconsistent_ep:
76 DBG_LOG("Inconsistent EP\n");
77 return false;
78inconsistent_cp:
79 DBG_LOG("Inconsistent CP\n");
80 return false;
81inconsistent_eo:
82 DBG_LOG("Inconsistent EO\n");
83 return false;
84inconsistent_co:
85 DBG_LOG("Inconsistent CO\n");
86 return false;
87}
88
89bool
90issolvable(cube_t cube)
91{
92 uint8_t i, eo, co, piece, edges[12], corners[8];
93
94 DBG_ASSERT(isconsistent(cube), false,
95 "issolvable: cube is inconsistent\n");
96
97 for (i = 0; i < 12; i++)
98 edges[i] = cube.edge[i] & _pbits;
99 for (i = 0; i < 8; i++)
100 corners[i] = cube.corner[i] & _pbits;
101
102 if (permsign(edges, 12) != permsign(corners, 8))
103 goto issolvable_parity;
104
105 eo = 0;
106 for (i = 0; i < 12; i++) {
107 piece = cube.edge[i];
108 eo += (piece & _eobit) >> _eoshift;
109 }
110 if (eo % 2 != 0)
111 goto issolvable_eo;
112
113 co = 0;
114 for (i = 0; i < 8; i++) {
115 piece = cube.corner[i];
116 co += (piece & _cobits) >> _coshift;
117 }
118 if (co % 3 != 0)
119 goto issolvable_co;
120
121 return true;
122
123issolvable_parity:
124 DBG_LOG("EP and CP parities are different\n");
125 return false;
126issolvable_eo:
127 DBG_LOG("Odd number of flipped edges\n");
128 return false;
129issolvable_co:
130 DBG_LOG("Sum of corner orientation is not multiple of 3\n");
131 return false;
132}
133
134bool
135issolved(cube_t cube)
136{
137 return equal(cube, solved);
138}
139
140bool
141equal(cube_t c1, cube_t c2)
142{
143 int i;
144 bool ret;
145
146 ret = true;
147 for (i = 0; i < 8; i++)
148 ret = ret && c1.corner[i] == c2.corner[i];
149 for (i = 0; i < 12; i++)
150 ret = ret && c1.edge[i] == c2.edge[i];
151
152 return ret;
153}
154
155bool
156iserror(cube_t cube)
157{
158 return equal(cube, zero);
159}
160
161cube_t
162compose(cube_t c1, cube_t c2)
163{
164 DBG_ASSERT(isconsistent(c1) && isconsistent(c2),
165 zero, "compose error: inconsistent cube\n")
166
167 return fasttocube(compose_fast(cubetofast(c1), cubetofast(c2)));
168}
169
170cube_t
171inverse(cube_t cube)
172{
173 cube_t ret;
174 uint8_t i, piece, orien;
175
176 DBG_ASSERT(isconsistent(cube), zero,
177 "inverse error: inconsistent cube\n");
178
179 ret = zero;
180
181 for (i = 0; i < 12; i++) {
182 piece = cube.edge[i];
183 orien = piece & _eobit;
184 ret.edge[piece & _pbits] = i | orien;
185 }
186
187 for (i = 0; i < 8; i++) {
188 piece = cube.corner[i];
189 orien = ((piece << 1) | (piece >> 1)) & _cobits2;
190 ret.corner[piece & _pbits] = i | orien;
191 }
192
193 return ret;
194}
195
196cube_t
197applymoves(cube_t cube, const char *buf)
198{
199 cube_fast_t fast;
200 uint8_t r, m;
201 const char *b;
202
203 DBG_ASSERT(isconsistent(cube), zero,
204 "move error: inconsistent cube\n");
205
206 fast = cubetofast(cube);
207
208 for (b = buf; *b != '\0'; b++) {
209 while (*b == ' ' || *b == '\t' || *b == '\n')
210 b++;
211 if (*b == '\0')
212 goto applymoves_finish;
213 if ((r = readmove(*b)) == _error)
214 goto applymoves_error;
215 if ((m = readmodifier(*(b+1))) != 0)
216 b++;
217 fast = move(fast, r + m);
218 }
219
220applymoves_finish:
221 return fasttocube(fast);
222
223applymoves_error:
224 DBG_LOG("applymoves error\n");
225 return zero;
226}
227
228cube_t
229applytrans(cube_t cube, const char *buf)
230{
231 cube_fast_t fast;
232 uint8_t t;
233
234 DBG_ASSERT(isconsistent(cube), zero,
235 "transformation error: inconsistent cube\n");
236
237 t = readtrans(buf);
238 fast = cubetofast(cube);
239 fast = transform(fast, t);
240
241 return fasttocube(fast);
242}
243
244cube_t
245readcube(const char *format, const char *buf)
246{
247 cube_t cube;
248
249 if (!strcmp(format, "H48")) {
250 cube = readcube_H48(buf);
251 } else if (!strcmp(format, "LST")) {
252 cube = readcube_LST(buf);
253 } else {
254 DBG_LOG("Cannot read cube in the given format\n");
255 cube = zero;
256 }
257
258 return cube;
259}
260
261void
262writecube(const char *format, cube_t cube, char *buf)
263{
264 char *errormsg;
265 size_t len;
266
267 if (!isconsistent(cube)) {
268 errormsg = "ERROR: cannot write inconsistent cube";
269 goto writecube_error;
270 }
271
272 if (!strcmp(format, "H48")) {
273 writecube_H48(cube, buf);
274 } else if (!strcmp(format, "LST")) {
275 writecube_LST(cube, buf);
276 } else {
277 errormsg = "ERROR: cannot write cube in the given format";
278 goto writecube_error;
279 }
280
281 return;
282
283writecube_error:
284 DBG_LOG("writecube error, see stdout for details\n");
285 len = strlen(errormsg);
286 memcpy(buf, errormsg, len);
287 buf[len] = '\n';
288 buf[len+1] = '\0';
289}
290
291_static int
292permsign(uint8_t *a, int n)
293{
294 int i, j;
295 uint8_t ret = 0;
296
297 for (i = 0; i < n; i++)
298 for (j = i+1; j < n; j++)
299 ret += a[i] > a[j] ? 1 : 0;
300
301 return ret % 2;
302}
303
304_static uint8_t
305readco(const char *str)
306{
307 if (*str == '0')
308 return 0;
309 if (*str == '1')
310 return _ctwist_cw;
311 if (*str == '2')
312 return _ctwist_ccw;
313
314 DBG_LOG("Error reading CO\n");
315 return _error;
316}
317
318_static uint8_t
319readcp(const char *str)
320{
321 uint8_t c;
322
323 for (c = 0; c < 8; c++)
324 if (!strncmp(str, cornerstr[c], 3) ||
325 !strncmp(str, cornerstralt[c], 3))
326 return c;
327
328 DBG_LOG("Error reading CP\n");
329 return _error;
330}
331
332_static uint8_t
333readeo(const char *str)
334{
335 if (*str == '0')
336 return 0;
337 if (*str == '1')
338 return _eflip;
339
340 DBG_LOG("Error reading EO\n");
341 return _error;
342}
343
344_static uint8_t
345readep(const char *str)
346{
347 uint8_t e;
348
349 for (e = 0; e < 12; e++)
350 if (!strncmp(str, edgestr[e], 2))
351 return e;
352
353 DBG_LOG("Error reading EP\n");
354 return _error;
355}
356
357_static cube_t
358readcube_H48(const char *buf)
359{
360 int i;
361 uint8_t piece, orient;
362 cube_t ret = {0};
363 const char *b;
364
365 b = buf;
366
367 for (i = 0; i < 12; i++) {
368 while (*b == ' ' || *b == '\t' || *b == '\n')
369 b++;
370 if ((piece = readep(b)) == _error)
371 return zero;
372 b += 2;
373 if ((orient = readeo(b)) == _error)
374 return zero;
375 b++;
376 ret.edge[i] = piece | orient;
377 }
378 for (i = 0; i < 8; i++) {
379 while (*b == ' ' || *b == '\t' || *b == '\n')
380 b++;
381 if ((piece = readcp(b)) == _error)
382 return zero;
383 b += 3;
384 if ((orient = readco(b)) == _error)
385 return zero;
386 b++;
387 ret.corner[i] = piece | orient;
388 }
389
390 return ret;
391}
392
393_static uint8_t
394readpiece_LST(const char **b)
395{
396 uint8_t ret;
397 bool read;
398
399 while (**b == ',' || **b == ' ' || **b == '\t' || **b == '\n')
400 (*b)++;
401
402 for (ret = 0, read = false; **b >= '0' && **b <= '9'; (*b)++) {
403 read = true;
404 ret = ret * 10 + (**b) - '0';
405 }
406
407 return read ? ret : _error;
408}
409
410_static cube_t
411readcube_LST(const char *buf)
412{
413 int i;
414 cube_t ret = {0};
415
416 for (i = 0; i < 8; i++)
417 ret.corner[i] = readpiece_LST(&buf);
418
419 for (i = 0; i < 12; i++)
420 ret.edge[i] = readpiece_LST(&buf);
421
422 return ret;
423}
424
425_static int
426writepiece_LST(uint8_t piece, char *buf)
427{
428 char digits[3];
429 int i, len = 0;
430
431 while (piece != 0) {
432 digits[len++] = (piece % 10) + '0';
433 piece /= 10;
434 }
435
436 if (len == 0)
437 digits[len++] = '0';
438
439 for (i = 0; i < len; i++)
440 buf[i] = digits[len-i-1];
441
442 buf[len] = ',';
443 buf[len+1] = ' ';
444
445 return len+2;
446}
447
448_static void
449writecube_H48(cube_t cube, char *buf)
450{
451 uint8_t piece, perm, orient;
452 int i;
453
454 for (i = 0; i < 12; i++) {
455 piece = cube.edge[i];
456 perm = piece & _pbits;
457 orient = (piece & _eobit) >> _eoshift;
458 buf[4*i ] = edgestr[perm][0];
459 buf[4*i + 1] = edgestr[perm][1];
460 buf[4*i + 2] = orient + '0';
461 buf[4*i + 3] = ' ';
462 }
463 for (i = 0; i < 8; i++) {
464 piece = cube.corner[i];
465 perm = piece & _pbits;
466 orient = (piece & _cobits) >> _coshift;
467 buf[48 + 5*i ] = cornerstr[perm][0];
468 buf[48 + 5*i + 1] = cornerstr[perm][1];
469 buf[48 + 5*i + 2] = cornerstr[perm][2];
470 buf[48 + 5*i + 3] = orient + '0';
471 buf[48 + 5*i + 4] = ' ';
472 }
473
474 buf[48+39] = '\0';
475}
476
477_static void
478writecube_LST(cube_t cube, char *buf)
479{
480 int i, ptr;
481 uint8_t piece;
482
483 ptr = 0;
484
485 for (i = 0; i < 8; i++) {
486 piece = cube.corner[i];
487 ptr += writepiece_LST(piece, buf + ptr);
488 }
489
490 for (i = 0; i < 12; i++) {
491 piece = cube.edge[i];
492 ptr += writepiece_LST(piece, buf + ptr);
493 }
494
495 *(buf+ptr-2) = 0;
496}
497
498_static uint8_t
499readmove(char c)
500{
501 switch (c) {
502 case 'U':
503 return _move_U;
504 case 'D':
505 return _move_D;
506 case 'R':
507 return _move_R;
508 case 'L':
509 return _move_L;
510 case 'F':
511 return _move_F;
512 case 'B':
513 return _move_B;
514 default:
515 return _error;
516 }
517}
518
519_static uint8_t
520readmodifier(char c)
521{
522 switch (c) {
523 case '1': /* Fallthrough */
524 case '2': /* Fallthrough */
525 case '3':
526 return c - '0' - 1;
527 case '\'':
528 return 2;
529 default:
530 return 0;
531 }
532}
533
534_static uint8_t
535readtrans(const char *buf)
536{
537 uint8_t t;
538
539 for (t = 0; t < 48; t++)
540 if (!strncmp(buf, transstr[t], 11))
541 return t;
542
543 DBG_LOG("readtrans error\n");
544 return _error;
545}
546
547_static int
548writemoves(uint8_t *m, int n, char *buf)
549{
550 int i;
551 size_t len;
552 const char *s;
553 char *b;
554
555 for (i = 0, b = buf; i < n; i++, b++) {
556 s = movestr[m[i]];
557 len = strlen(s);
558 memcpy(b, s, len);
559 b += len;
560 *b = ' ';
561 }
562
563 if (b != buf)
564 b--; /* Remove last space */
565 *b = '\0';
566
567 return b - buf;
568}
569
570_static void
571writetrans(uint8_t t, char *buf)
572{
573 if (t >= 48)
574 memcpy(buf, "error trans", 11);
575 else
576 memcpy(buf, transstr[t], 11);
577 buf[11] = '\0';
578}
579
580_static cube_fast_t
581move(cube_fast_t c, uint8_t m)
582{
583 switch (m) {
584 case _move_U:
585 return _move(U, c);
586 case _move_U2:
587 return _move(U2, c);
588 case _move_U3:
589 return _move(U3, c);
590 case _move_D:
591 return _move(D, c);
592 case _move_D2:
593 return _move(D2, c);
594 case _move_D3:
595 return _move(D3, c);
596 case _move_R:
597 return _move(R, c);
598 case _move_R2:
599 return _move(R2, c);
600 case _move_R3:
601 return _move(R3, c);
602 case _move_L:
603 return _move(L, c);
604 case _move_L2:
605 return _move(L2, c);
606 case _move_L3:
607 return _move(L3, c);
608 case _move_F:
609 return _move(F, c);
610 case _move_F2:
611 return _move(F2, c);
612 case _move_F3:
613 return _move(F3, c);
614 case _move_B:
615 return _move(B, c);
616 case _move_B2:
617 return _move(B2, c);
618 case _move_B3:
619 return _move(B3, c);
620 default:
621 DBG_LOG("move error, unknown move\n");
622 return zero_fast;
623 }
624}
625
626_static cube_fast_t
627transform(cube_fast_t c, uint8_t t)
628{
629 switch (t) {
630 case _trans_UFr:
631 return _trans_rotation(UFr, c);
632 case _trans_ULr:
633 return _trans_rotation(ULr, c);
634 case _trans_UBr:
635 return _trans_rotation(UBr, c);
636 case _trans_URr:
637 return _trans_rotation(URr, c);
638 case _trans_DFr:
639 return _trans_rotation(DFr, c);
640 case _trans_DLr:
641 return _trans_rotation(DLr, c);
642 case _trans_DBr:
643 return _trans_rotation(DBr, c);
644 case _trans_DRr:
645 return _trans_rotation(DRr, c);
646 case _trans_RUr:
647 return _trans_rotation(RUr, c);
648 case _trans_RFr:
649 return _trans_rotation(RFr, c);
650 case _trans_RDr:
651 return _trans_rotation(RDr, c);
652 case _trans_RBr:
653 return _trans_rotation(RBr, c);
654 case _trans_LUr:
655 return _trans_rotation(LUr, c);
656 case _trans_LFr:
657 return _trans_rotation(LFr, c);
658 case _trans_LDr:
659 return _trans_rotation(LDr, c);
660 case _trans_LBr:
661 return _trans_rotation(LBr, c);
662 case _trans_FUr:
663 return _trans_rotation(FUr, c);
664 case _trans_FRr:
665 return _trans_rotation(FRr, c);
666 case _trans_FDr:
667 return _trans_rotation(FDr, c);
668 case _trans_FLr:
669 return _trans_rotation(FLr, c);
670 case _trans_BUr:
671 return _trans_rotation(BUr, c);
672 case _trans_BRr:
673 return _trans_rotation(BRr, c);
674 case _trans_BDr:
675 return _trans_rotation(BDr, c);
676 case _trans_BLr:
677 return _trans_rotation(BLr, c);
678 case _trans_UFm:
679 return _trans_mirrored(UFm, c);
680 case _trans_ULm:
681 return _trans_mirrored(ULm, c);
682 case _trans_UBm:
683 return _trans_mirrored(UBm, c);
684 case _trans_URm:
685 return _trans_mirrored(URm, c);
686 case _trans_DFm:
687 return _trans_mirrored(DFm, c);
688 case _trans_DLm:
689 return _trans_mirrored(DLm, c);
690 case _trans_DBm:
691 return _trans_mirrored(DBm, c);
692 case _trans_DRm:
693 return _trans_mirrored(DRm, c);
694 case _trans_RUm:
695 return _trans_mirrored(RUm, c);
696 case _trans_RFm:
697 return _trans_mirrored(RFm, c);
698 case _trans_RDm:
699 return _trans_mirrored(RDm, c);
700 case _trans_RBm:
701 return _trans_mirrored(RBm, c);
702 case _trans_LUm:
703 return _trans_mirrored(LUm, c);
704 case _trans_LFm:
705 return _trans_mirrored(LFm, c);
706 case _trans_LDm:
707 return _trans_mirrored(LDm, c);
708 case _trans_LBm:
709 return _trans_mirrored(LBm, c);
710 case _trans_FUm:
711 return _trans_mirrored(FUm, c);
712 case _trans_FRm:
713 return _trans_mirrored(FRm, c);
714 case _trans_FDm:
715 return _trans_mirrored(FDm, c);
716 case _trans_FLm:
717 return _trans_mirrored(FLm, c);
718 case _trans_BUm:
719 return _trans_mirrored(BUm, c);
720 case _trans_BRm:
721 return _trans_mirrored(BRm, c);
722 case _trans_BDm:
723 return _trans_mirrored(BDm, c);
724 case _trans_BLm:
725 return _trans_mirrored(BLm, c);
726 default:
727 DBG_LOG("transform error, unknown transformation\n");
728 return zero_fast;
729 }
730}

Generated with cgit - Back to sebastiano.tronto.net