aboutsummaryrefslogtreecommitdiff
path: root/src/array_cube.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/array_cube.c712
1 files changed, 712 insertions, 0 deletions
diff --git a/src/array_cube.c b/src/array_cube.c
new file mode 100644
index 0000000..3445658
--- /dev/null
+++ b/src/array_cube.c
@@ -0,0 +1,712 @@
1/*
2In this implementation of the cube.h interface, the cube is represented
3by two arrays of 8-bit unsigned integers, one for centers and one for
4corners. The 4 leas-significant digits of each bit determine the piece,
5the other 4 are used for orientation or kept to 0.
6
7Edges:
8 xxxopppp (x = unused, o = orientation, p = piece)
9
10Corners:
11 xooxpppp (x = unused, o = orientation, p = piece)
12
13The two bits for CO are shifted to make it possible to perform mod 3
14operations (sum, inverse) using only addition and bitwise operators.
15See below for details.
16
17The third bit is needed because x+y+1 can exceed 4.
18*/
19
20#include <inttypes.h>
21#include <stdbool.h>
22#include <string.h>
23
24#ifdef DEBUG
25#include <stdio.h>
26#endif
27
28#include "cube.h"
29
30#define _c_ufr 0U
31#define _c_ubl 1U
32#define _c_dfl 2U
33#define _c_dbr 3U
34#define _c_ufl 4U
35#define _c_ubr 5U
36#define _c_dfr 6U
37#define _c_dbl 7U
38
39#define _e_uf 0U
40#define _e_ub 1U
41#define _e_db 2U
42#define _e_df 3U
43#define _e_ur 4U
44#define _e_ul 5U
45#define _e_dl 6U
46#define _e_dr 7U
47#define _e_fr 8U
48#define _e_fl 9U
49#define _e_bl 10U
50#define _e_br 11U
51
52#define _eoshift 4U
53#define _coshift 5U
54
55#define _pbits 0xFU
56#define _eobit 0x10U
57#define _cobits 0xF0U
58#define _cobits2 0x60U
59#define _ctwist_cw 0x20U
60#define _ctwist_ccw 0x40U
61#define _eflip 0x10U
62#define _error 0xFFU
63
64static char *cornerstr[] = {
65 [_c_ufr] = "UFR",
66 [_c_ubl] = "UBL",
67 [_c_dfl] = "DFL",
68 [_c_dbr] = "DBR",
69 [_c_ufl] = "UFL",
70 [_c_ubr] = "UBR",
71 [_c_dfr] = "DFR",
72 [_c_dbl] = "DBL"
73};
74
75static char *cornerstralt[] = {
76 [_c_ufr] = "URF",
77 [_c_ubl] = "ULB",
78 [_c_dfl] = "DLF",
79 [_c_dbr] = "DRB",
80 [_c_ufl] = "ULF",
81 [_c_ubr] = "URB",
82 [_c_dfr] = "DRF",
83 [_c_dbl] = "DLB"
84};
85
86static char *edgestr[] = {
87 [_e_uf] = "UF",
88 [_e_ub] = "UB",
89 [_e_db] = "DB",
90 [_e_df] = "DF",
91 [_e_ur] = "UR",
92 [_e_ul] = "UL",
93 [_e_dl] = "DL",
94 [_e_dr] = "DR",
95 [_e_fr] = "FR",
96 [_e_fl] = "FL",
97 [_e_bl] = "BL",
98 [_e_br] = "BR"
99};
100
101static char *movestr[] = {
102 [U] = "U",
103 [U2] = "U2",
104 [U3] = "U'",
105 [D] = "D",
106 [D2] = "D2",
107 [D3] = "D'",
108 [R] = "R",
109 [R2] = "R2",
110 [R3] = "R'",
111 [L] = "L",
112 [L2] = "L2",
113 [L3] = "L'",
114 [F] = "F",
115 [F2] = "F2",
116 [F3] = "F'",
117 [B] = "B",
118 [B2] = "B2",
119 [B3] = "B'",
120};
121
122cube_t solvedcube = {
123 .c = {
124 [_c_ufr] = _c_ufr,
125 [_c_ubl] = _c_ubl,
126 [_c_dfl] = _c_dfl,
127 [_c_dbr] = _c_dbr,
128 [_c_ufl] = _c_ufl,
129 [_c_ubr] = _c_ubr,
130 [_c_dfr] = _c_dfr,
131 [_c_dbl] = _c_dbl
132 },
133 .e = {
134 [_e_uf] = _e_uf,
135 [_e_ub] = _e_ub,
136 [_e_db] = _e_db,
137 [_e_df] = _e_df,
138 [_e_ur] = _e_ur,
139 [_e_ul] = _e_ul,
140 [_e_dl] = _e_dl,
141 [_e_dr] = _e_dr,
142 [_e_fr] = _e_fr,
143 [_e_fl] = _e_fl,
144 [_e_bl] = _e_bl,
145 [_e_br] = _e_br
146 }
147};
148
149static cube_t errorcube = { .e = {0}, .c = {0} };
150
151static uint8_t readco(char *);
152static uint8_t readcp(char *);
153static uint8_t readeo(char *);
154static uint8_t readep(char *);
155static uint8_t readmove(char);
156static uint8_t readmodifier(char);
157static int permsign(uint8_t *, int);
158static cube_t compose(cube_t, cube_t);
159
160static uint8_t
161readco(char *str)
162{
163 if (*str == '0')
164 return 0;
165 if (*str == '1')
166 return _ctwist_cw;
167 if (*str == '2')
168 return _ctwist_ccw;
169
170#ifdef DEBUG
171 fprintf(stderr, "Error reading CO\n");
172#endif
173 return _error;
174}
175
176static uint8_t
177readcp(char *str)
178{
179 uint8_t c;
180
181 for (c = 0; c < 8; c++)
182 if (!strncmp(str, cornerstr[c], 3) ||
183 !strncmp(str, cornerstralt[c], 3))
184 return c;
185
186#ifdef DEBUG
187 fprintf(stderr, "Error reading CP\n");
188#endif
189 return _error;
190}
191
192static uint8_t
193readeo(char *str)
194{
195 if (*str == '0')
196 return 0;
197 if (*str == '1')
198 return _eflip;
199
200#ifdef DEBUG
201 fprintf(stderr, "Error reading EO\n");
202#endif
203 return _error;
204}
205
206static uint8_t
207readep(char *str)
208{
209 uint8_t e;
210
211 for (e = 0; e < 12; e++)
212 if (!strncmp(str, edgestr[e], 2))
213 return e;
214
215#ifdef DEBUG
216 fprintf(stderr, "Error reading EP\n");
217#endif
218 return _error;
219}
220
221cube_t
222readcube(char *buf)
223{
224 int i;
225 uint8_t piece, orient;
226 cube_t ret = {0};
227 char *b = buf;
228
229 for (i = 0; i < 12; i++) {
230 while (*b == ' ' || *b == '\t' || *b == '\n')
231 b++;
232 if ((piece = readep(b)) == _error)
233 goto readcube_error;
234 b += 2;
235 if ((orient = readeo(b)) == _error)
236 goto readcube_error;
237 b++;
238 ret.e[i] = piece | orient;
239 }
240 for (i = 0; i < 8; i++) {
241 while (*b == ' ' || *b == '\t' || *b == '\n')
242 b++;
243 if ((piece = readcp(b)) == _error)
244 goto readcube_error;
245 b += 3;
246 if ((orient = readco(b)) == _error)
247 goto readcube_error;
248 b++;
249 ret.c[i] = piece | orient;
250 }
251
252 return ret;
253
254readcube_error:
255#ifdef DEBUG
256 fprintf(stderr, "readcube error\n");
257#endif
258 return errorcube;
259}
260
261void
262writecube(cube_t cube, char *buf)
263{
264 char *errormsg;
265 uint8_t piece, orient;
266 size_t len;
267 int i;
268
269 if (!isconsistent(cube)) {
270 errormsg = "ERROR: cannot write inconsistent cube";
271 goto writecube_error;
272 }
273
274 for (i = 0; i < 12; i++) {
275 piece = cube.e[i] & _pbits;
276 orient = (cube.e[i] & _eobit) >> _eoshift;
277 buf[4*i ] = edgestr[piece][0];
278 buf[4*i + 1] = edgestr[piece][1];
279 buf[4*i + 2] = orient + '0';
280 buf[4*i + 3] = ' ';
281 }
282 for (i = 0; i < 8; i++) {
283 piece = cube.c[i] & _pbits;
284 orient = (cube.c[i] & _cobits) >> _coshift;
285 buf[48 + 5*i ] = cornerstr[piece][0];
286 buf[48 + 5*i + 1] = cornerstr[piece][1];
287 buf[48 + 5*i + 2] = cornerstr[piece][2];
288 buf[48 + 5*i + 3] = orient + '0';
289 buf[48 + 5*i + 4] = ' ';
290 }
291
292 buf[48+39] = '\0';
293
294 return;
295
296writecube_error:
297#ifdef DEBUG
298 fprintf(stderr, "writecube error, see stdout for details\n");
299#endif
300 len = strlen(errormsg);
301 memcpy(buf, errormsg, len);
302 buf[len] = '\n';
303 buf[len+1] = '\0';
304}
305
306
307static uint8_t
308readmove(char c)
309{
310 switch (c) {
311 case 'U':
312 return U;
313 case 'D':
314 return D;
315 case 'R':
316 return R;
317 case 'L':
318 return L;
319 case 'F':
320 return F;
321 case 'B':
322 return B;
323 default:
324 return _error;
325 }
326}
327
328static uint8_t
329readmodifier(char c)
330{
331 switch (c) {
332 case '1': /* Fallthrough */
333 case '2': /* Fallthrough */
334 case '3':
335 return c - '0' - 1;
336 case '\'':
337 return 2;
338 default:
339 return 0;
340 }
341}
342
343int
344readmoves(char *buf, move_t *m)
345{
346 int n;
347 uint64_t r;
348 char *b;
349
350 for (b = buf, n = 0; *b != '\0'; b++) {
351 while (*b == ' ' || *b == '\t' || *b == '\n')
352 b++;
353 if (*b == '\0')
354 return n;
355 if ((r = readmove(*b)) == _error)
356 goto readmoves_error;
357 m[n] = (move_t)r;
358 if ((r = readmodifier(*(b+1))) != 0) {
359 b++;
360 m[n] += r;
361 }
362 n++;
363 }
364
365 return n;
366
367readmoves_error:
368#ifdef DEBUG
369 fprintf(stderr, "readmoves error\n");
370#endif
371 return -1;
372}
373
374void
375writemoves(move_t *m, int n, char *buf)
376{
377 int i;
378 size_t len;
379 char *b, *s;
380
381 for (i = 0, b = buf; i < n; i++, b++) {
382 s = movestr[m[i]];
383 len = strlen(s);
384 memcpy(b, s, len);
385 b += len;
386 *b = ' ';
387 }
388 *b = '\0';
389}
390
391
392static int
393permsign(uint8_t *a, int n)
394{
395 int i, j;
396 uint8_t ret = 0;
397
398 for (i = 0; i < n; i++)
399 for (j = i+1; j < n; j++)
400 ret += (a[i] & _pbits) > (a[j] & _pbits) ? 1 : 0;
401
402 return ret % 2;
403}
404
405bool
406isconsistent(cube_t cube)
407{
408 int8_t p, psum, eosum, co, cosum;
409 bool found[12];
410 int i;
411
412 psum = 0;
413 for (i = 0; i < 12; i++)
414 found[i] = false;
415 for (i = 0; i < 12; i++) {
416 p = cube.e[i] & _pbits;
417 if (p >= 12)
418 goto inconsistent_ep;
419 found[p] = true;
420 }
421 for (i = 0; i < 12; i++)
422 if (!found[i])
423 goto inconsistent_ep;
424 psum = permsign(cube.e, 12);
425
426 for (i = 0; i < 8; i++)
427 found[i] = false;
428 for (i = 0; i < 8; i++) {
429 p = cube.c[i] & _pbits;
430 if (p >= 8)
431 goto inconsistent_cp;
432 found[p] = true;
433 }
434 for (i = 0; i < 8; i++)
435 if (!found[i])
436 goto inconsistent_cp;
437 psum += permsign(cube.c, 8);
438
439 if (psum % 2 != 0)
440 goto inconsistent_parity;
441
442 eosum = 0;
443 for (i = 0; i < 12; i++)
444 eosum += (cube.e[i] & _eobit) >> _eoshift;
445 if (eosum % 2 != 0)
446 goto inconsistent_eo;
447
448 cosum = 0;
449 for (i = 0; i < 8; i++) {
450 co = (cube.c[i] & _cobits) >> _coshift;
451 if (co > 2)
452 goto inconsistent_co;
453 cosum += co;
454 }
455 if (cosum % 3 != 0)
456 goto inconsistent_co;
457
458 return true;
459
460inconsistent_ep:
461#ifdef DEBUG
462 fprintf(stderr, "Inconsistent EP\n");
463#endif
464 goto inconsistent_return;
465inconsistent_cp:
466#ifdef DEBUG
467 fprintf(stderr, "Inconsistent CP\n");
468#endif
469 goto inconsistent_return;
470inconsistent_parity:
471#ifdef DEBUG
472 fprintf(stderr, "Inconsistent parity\n");
473#endif
474 goto inconsistent_return;
475inconsistent_eo:
476#ifdef DEBUG
477 fprintf(stderr, "Inconsistent EO\n");
478#endif
479 goto inconsistent_return;
480inconsistent_co:
481#ifdef DEBUG
482 fprintf(stderr, "Inconsistent CO\n");
483#endif
484 goto inconsistent_return;
485inconsistent_return:
486 return false;
487}
488
489bool
490equal(cube_t cube1, cube_t cube2)
491{
492 uint8_t i;
493
494 for (i = 0; i < 12; i++)
495 if (cube1.e[i] != cube2.e[i])
496 return false;
497
498 for (i = 0; i < 8; i++)
499 if (cube1.c[i] != cube2.c[i])
500 return false;
501
502 return true;
503}
504
505bool
506issolved(cube_t cube)
507{
508 return equal(cube, solvedcube);
509}
510
511bool
512iserror(cube_t cube)
513{
514 return equal(cube, errorcube);
515}
516
517cube_t
518move(cube_t c, move_t m)
519{
520 cube_t ret;
521 uint8_t aux, auy, auz;
522
523#ifdef DEBUG
524 if (!isconsistent(c))
525 goto move_inconsistent;
526#endif
527
528#define PERM4(r, i, j, k, l) \
529 aux = r[i]; \
530 r[i] = r[l]; \
531 r[l] = r[k]; \
532 r[k] = r[j]; \
533 r[j] = aux;
534#define PERM22(r, i, j, k, l) \
535 aux = r[i]; \
536 r[i] = r[j]; \
537 r[j] = aux; \
538 aux = r[k]; \
539 r[k] = r[l]; \
540 r[l] = aux;
541#define CO(a, b) \
542 aux = (a & _cobits) + (b & _cobits); \
543 auy = (aux + _ctwist_cw) >> 2U; \
544 auz = (aux + auy) & _cobits2; \
545 a = (a & _pbits) | auz;
546#define CO4(r, i, j, k, l) \
547 CO(r[i], _ctwist_cw) \
548 CO(r[j], _ctwist_cw) \
549 CO(r[k], _ctwist_ccw) \
550 CO(r[l], _ctwist_ccw)
551#define EO4(r, i, j, k, l) \
552 r[i] ^= _eobit; \
553 r[j] ^= _eobit; \
554 r[k] ^= _eobit; \
555 r[l] ^= _eobit;
556
557 ret = c;
558
559 switch (m) {
560 case U:
561 PERM4(ret.e, _e_uf, _e_ul, _e_ub, _e_ur)
562 PERM4(ret.c, _c_ufr, _c_ufl, _c_ubl, _c_ubr)
563
564 return ret;
565 case U2:
566 PERM22(ret.e, _e_uf, _e_ub, _e_ul, _e_ur)
567 PERM22(ret.c, _c_ufr, _c_ubl, _c_ufl, _c_ubr)
568
569 return ret;
570 case U3:
571 PERM4(ret.e, _e_uf, _e_ur, _e_ub, _e_ul)
572 PERM4(ret.c, _c_ufr, _c_ubr, _c_ubl, _c_ufl)
573
574 return ret;
575 case D:
576 PERM4(ret.e, _e_df, _e_dr, _e_db, _e_dl)
577 PERM4(ret.c, _c_dfr, _c_dbr, _c_dbl, _c_dfl)
578
579 return ret;
580 case D2:
581 PERM22(ret.e, _e_df, _e_db, _e_dr, _e_dl)
582 PERM22(ret.c, _c_dfr, _c_dbl, _c_dbr, _c_dfl)
583
584 return ret;
585 case D3:
586 PERM4(ret.e, _e_df, _e_dl, _e_db, _e_dr)
587 PERM4(ret.c, _c_dfr, _c_dfl, _c_dbl, _c_dbr)
588
589 return ret;
590 case R:
591 PERM4(ret.e, _e_ur, _e_br, _e_dr, _e_fr)
592 PERM4(ret.c, _c_ufr, _c_ubr, _c_dbr, _c_dfr)
593
594 CO4(ret.c, _c_ubr, _c_dfr, _c_ufr, _c_dbr)
595
596 return ret;
597 case R2:
598 PERM22(ret.e, _e_ur, _e_dr, _e_fr, _e_br)
599 PERM22(ret.c, _c_ufr, _c_dbr, _c_ubr, _c_dfr)
600
601 return ret;
602 case R3:
603 PERM4(ret.e, _e_ur, _e_fr, _e_dr, _e_br)
604 PERM4(ret.c, _c_ufr, _c_dfr, _c_dbr, _c_ubr)
605
606 CO4(ret.c, _c_ubr, _c_dfr, _c_ufr, _c_dbr)
607
608 return ret;
609 case L:
610 PERM4(ret.e, _e_ul, _e_fl, _e_dl, _e_bl)
611 PERM4(ret.c, _c_ufl, _c_dfl, _c_dbl, _c_ubl)
612
613 CO4(ret.c, _c_ufl, _c_dbl, _c_dfl, _c_ubl)
614
615 return ret;
616 case L2:
617 PERM22(ret.e, _e_ul, _e_dl, _e_fl, _e_bl)
618 PERM22(ret.c, _c_ufl, _c_dbl, _c_ubl, _c_dfl)
619
620 return ret;
621 case L3:
622 PERM4(ret.e, _e_ul, _e_bl, _e_dl, _e_fl)
623 PERM4(ret.c, _c_ufl, _c_ubl, _c_dbl, _c_dfl)
624
625 CO4(ret.c, _c_ufl, _c_dbl, _c_dfl, _c_ubl)
626
627 return ret;
628 case F:
629 PERM4(ret.e, _e_uf, _e_fr, _e_df, _e_fl)
630 PERM4(ret.c, _c_ufr, _c_dfr, _c_dfl, _c_ufl)
631
632 EO4(ret.e, _e_uf, _e_fr, _e_df, _e_fl)
633 CO4(ret.c, _c_ufr, _c_dfl, _c_dfr, _c_ufl)
634
635 return ret;
636 case F2:
637 PERM22(ret.e, _e_uf, _e_df, _e_fr, _e_fl)
638 PERM22(ret.c, _c_ufr, _c_dfl, _c_ufl, _c_dfr)
639
640 return ret;
641 case F3:
642 PERM4(ret.e, _e_uf, _e_fl, _e_df, _e_fr)
643 PERM4(ret.c, _c_ufr, _c_ufl, _c_dfl, _c_dfr)
644
645 EO4(ret.e, _e_uf, _e_fr, _e_df, _e_fl)
646 CO4(ret.c, _c_ufr, _c_dfl, _c_dfr, _c_ufl)
647
648 return ret;
649 case B:
650 PERM4(ret.e, _e_ub, _e_bl, _e_db, _e_br)
651 PERM4(ret.c, _c_ubr, _c_ubl, _c_dbl, _c_dbr)
652
653 EO4(ret.e, _e_ub, _e_br, _e_db, _e_bl)
654 CO4(ret.c, _c_ubl, _c_dbr, _c_dbl, _c_ubr)
655
656 return ret;
657 case B2:
658 PERM22(ret.e, _e_ub, _e_db, _e_br, _e_bl)
659 PERM22(ret.c, _c_ubr, _c_dbl, _c_ubl, _c_dbr)
660
661 return ret;
662 case B3:
663 PERM4(ret.e, _e_ub, _e_br, _e_db, _e_bl)
664 PERM4(ret.c, _c_ubr, _c_dbr, _c_dbl, _c_ubl)
665
666 EO4(ret.e, _e_ub, _e_br, _e_db, _e_bl)
667 CO4(ret.c, _c_ubl, _c_dbr, _c_dbl, _c_ubr)
668
669 return ret;
670 default:
671 goto move_unknown;
672 }
673
674move_inconsistent:
675 fprintf(stderr, "move error, inconsistent cube\n");
676 goto move_error;
677move_unknown:
678 fprintf(stderr, "mover error, unknown move\n");
679 goto move_error;
680move_error:
681 return errorcube;
682}
683
684cube_t
685inverse(cube_t c)
686{
687 uint8_t i, piece, orien;
688 cube_t ret = {0};
689
690#ifdef DEBUG
691 if (!isconsistent(c))
692 goto inverse_inconsistent;
693#endif
694
695 for (i = 0; i < 12; i++) {
696 piece = c.e[i & _pbits];
697 orien = piece & _eobit;
698 ret.e[piece & _pbits] = i | orien;
699 }
700
701 for (i = 0; i < 8; i++) {
702 piece = c.c[i & _pbits];
703 orien = ((piece << 1) | (piece >> 1)) & _cobits2;
704 ret.c[piece & _pbits] = i | orien;
705 }
706
707 return ret;
708
709inverse_inconsistent:
710 fprintf(stderr, "inverse error, inconsistent cube\n");
711 return errorcube;
712}

Generated with cgit - Back to sebastiano.tronto.net