aboutsummaryrefslogtreecommitdiff
path: root/src/cube_routines.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/cube_routines.h')
-rw-r--r--src/cube_routines.h668
1 files changed, 0 insertions, 668 deletions
diff --git a/src/cube_routines.h b/src/cube_routines.h
deleted file mode 100644
index 3730e90..0000000
--- a/src/cube_routines.h
+++ /dev/null
@@ -1,668 +0,0 @@
1#define _move(M, c) compose_fast(c, _move_cube_ ## M)
2#define _premove(M, c) compose_fast(_move_cube_ ## M, c)
3
4_static int permsign(uint8_t *, int);
5_static uint8_t readco(const char *);
6_static uint8_t readcp(const char *);
7_static uint8_t readeo(const char *);
8_static uint8_t readep(const char *);
9_static cube_t readcube_H48(const char *);
10_static uint8_t readpiece_LST(const char **);
11_static cube_t readcube_LST(const char *);
12_static int writepiece_LST(uint8_t, char *);
13_static void writecube_H48(cube_t, char *);
14_static void writecube_LST(cube_t, char *);
15_static uint8_t b32toedge(char);
16_static uint8_t b32tocorner(char);
17_static char edgetob32(uint8_t);
18_static char cornertob32(uint8_t);
19_static uint8_t readmove(char);
20_static uint8_t readmodifier(char);
21_static uint8_t readtrans(const char *);
22_static int writemoves(uint8_t *, int, char *);
23_static void writetrans(uint8_t, char *);
24_static cube_fast_t move(cube_fast_t, uint8_t);
25_static cube_fast_t transform_edges(cube_fast_t, uint8_t);
26_static cube_fast_t transform_corners(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;
430
431 len = 0;
432 while (piece != 0) {
433 digits[len++] = (piece % 10) + '0';
434 piece /= 10;
435 }
436
437 if (len == 0)
438 digits[len++] = '0';
439
440 for (i = 0; i < len; i++)
441 buf[i] = digits[len-i-1];
442
443 buf[len] = ',';
444 buf[len+1] = ' ';
445
446 return len+2;
447}
448
449_static void
450writecube_H48(cube_t cube, char *buf)
451{
452 uint8_t piece, perm, orient;
453 int i;
454
455 for (i = 0; i < 12; i++) {
456 piece = cube.edge[i];
457 perm = piece & _pbits;
458 orient = (piece & _eobit) >> _eoshift;
459 buf[4*i ] = edgestr[perm][0];
460 buf[4*i + 1] = edgestr[perm][1];
461 buf[4*i + 2] = orient + '0';
462 buf[4*i + 3] = ' ';
463 }
464 for (i = 0; i < 8; i++) {
465 piece = cube.corner[i];
466 perm = piece & _pbits;
467 orient = (piece & _cobits) >> _coshift;
468 buf[48 + 5*i ] = cornerstr[perm][0];
469 buf[48 + 5*i + 1] = cornerstr[perm][1];
470 buf[48 + 5*i + 2] = cornerstr[perm][2];
471 buf[48 + 5*i + 3] = orient + '0';
472 buf[48 + 5*i + 4] = ' ';
473 }
474
475 buf[48+39] = '\0';
476}
477
478_static void
479writecube_LST(cube_t cube, char *buf)
480{
481 int i;
482 size_t ptr;
483 uint8_t piece;
484
485 ptr = 0;
486
487 for (i = 0; i < 8; i++) {
488 piece = cube.corner[i];
489 ptr += writepiece_LST(piece, buf + ptr);
490 }
491
492 for (i = 0; i < 12; i++) {
493 piece = cube.edge[i];
494 ptr += writepiece_LST(piece, buf + ptr);
495 }
496
497 *(buf+ptr-2) = 0;
498}
499
500_static uint8_t
501b32toedge(char c)
502{
503 DBG_ASSERT((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'g'), 255,
504 "Error reading base32 piece");
505
506 return c <= 'Z' ? (uint8_t)(c - 'A') : (uint8_t)(c - 'a');
507}
508
509_static uint8_t
510b32tocorner(char c) {
511 uint8_t val;
512
513 DBG_ASSERT((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'g'), 255,
514 "Error reading base32 piece");
515
516 val = c <= 'Z' ? (uint8_t)(c - 'A') : (uint8_t)(c - 'a') + 26;
517
518 return (val & 7) | ((val & 24) << 2);
519}
520
521_static char
522edgetob32(uint8_t edge)
523{
524 return edge <= 26 ? 'A' + (char)edge : 'a' + (char)(edge - 26);
525}
526
527_static char
528cornertob32(uint8_t corner)
529{
530 uint8_t val;
531
532 val = (corner & 7) | ((corner & 96) >> 2);
533
534 return val <= 26 ? 'A' + (char)val : 'a' + (char)(val - 26);
535}
536
537_static uint8_t
538readmove(char c)
539{
540 switch (c) {
541 case 'U':
542 return _move_U;
543 case 'D':
544 return _move_D;
545 case 'R':
546 return _move_R;
547 case 'L':
548 return _move_L;
549 case 'F':
550 return _move_F;
551 case 'B':
552 return _move_B;
553 default:
554 return _error;
555 }
556}
557
558_static uint8_t
559readmodifier(char c)
560{
561 switch (c) {
562 case '1': /* Fallthrough */
563 case '2': /* Fallthrough */
564 case '3':
565 return c - '0' - 1;
566 case '\'':
567 return 2;
568 default:
569 return 0;
570 }
571}
572
573_static uint8_t
574readtrans(const char *buf)
575{
576 uint8_t t;
577
578 for (t = 0; t < 48; t++)
579 if (!strncmp(buf, transstr[t], 11))
580 return t;
581
582 DBG_LOG("readtrans error\n");
583 return _error;
584}
585
586_static int
587writemoves(uint8_t *m, int n, char *buf)
588{
589 int i;
590 size_t len;
591 const char *s;
592 char *b;
593
594 for (i = 0, b = buf; i < n; i++, b++) {
595 s = movestr[m[i]];
596 len = strlen(s);
597 memcpy(b, s, len);
598 b += len;
599 *b = ' ';
600 }
601
602 if (b != buf)
603 b--; /* Remove last space */
604 *b = '\0';
605
606 return b - buf;
607}
608
609_static void
610writetrans(uint8_t t, char *buf)
611{
612 if (t >= 48)
613 memcpy(buf, "error trans", 11);
614 else
615 memcpy(buf, transstr[t], 11);
616 buf[11] = '\0';
617}
618
619_static cube_fast_t
620move(cube_fast_t c, uint8_t m)
621{
622 switch (m) {
623 case _move_U:
624 return _move(U, c);
625 case _move_U2:
626 return _move(U2, c);
627 case _move_U3:
628 return _move(U3, c);
629 case _move_D:
630 return _move(D, c);
631 case _move_D2:
632 return _move(D2, c);
633 case _move_D3:
634 return _move(D3, c);
635 case _move_R:
636 return _move(R, c);
637 case _move_R2:
638 return _move(R2, c);
639 case _move_R3:
640 return _move(R3, c);
641 case _move_L:
642 return _move(L, c);
643 case _move_L2:
644 return _move(L2, c);
645 case _move_L3:
646 return _move(L3, c);
647 case _move_F:
648 return _move(F, c);
649 case _move_F2:
650 return _move(F2, c);
651 case _move_F3:
652 return _move(F3, c);
653 case _move_B:
654 return _move(B, c);
655 case _move_B2:
656 return _move(B2, c);
657 case _move_B3:
658 return _move(B3, c);
659 default:
660 DBG_LOG("move error, unknown move\n");
661 return zero_fast;
662 }
663}
664
665/*
666TODO transform is now relegated to a separated file because it is too long.
667It would be nice to make it shorter without loosing performance.
668*/

Generated with cgit - Back to sebastiano.tronto.net