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

Generated with cgit - Back to sebastiano.tronto.net