cubecore

A library of core functions for working with 3x3x3 Rubik's cubes
git clone https://git.tronto.net/cubecore
Download | Log | Files | Refs | README | LICENSE

commit ec87f96ffec31c430b6058663ae831c1b3a29ff9
parent a4598b740fe4b8350b7d09a575c793113c8fde2b
Author: Sebastiano Tronto <sebastiano@tronto.net>
Date:   Sat, 13 Apr 2024 17:15:42 +0200

Clean up

Diffstat:
MMakefile | 17++++++++++-------
MREADME.md | 25++++++++++++++++++++++---
DTODO.txt | 2--
Mconstants.h | 16----------------
Mcube.c | 905++++++++++++++++++++++++++++++++++++++-----------------------------------------
Mcube.h | 24++++++++++++++++++++++++
Acube.o | 0
Mtest/030_move/move_tests.c | 10+++++++++-
Mtest/060_transform/transform_tests.c | 4+++-
Mtest/061_inverse_trans/inverse_trans_tests.c | 30+++++++++++++-----------------
10 files changed, 511 insertions(+), 522 deletions(-)

diff --git a/Makefile b/Makefile @@ -3,24 +3,27 @@ DBGFLAGS = -std=c99 -pedantic -Wall -Wextra -g3 -DDEBUG CC = cc -all: cube.o debugcube.o +all: cleancube cube.o -cube.s: clean - ${CC} ${CFLAGS} -c -S -o cube.s cube.c +cleancube: + rm -rf cube.o -cube.o: clean +cube.o: ${CC} ${CFLAGS} -c -o cube.o cube.c -debugcube.o: clean +cleandebug: + rm -rf debugcube.o + +debugcube.o: ${CC} ${DBGFLAGS} -c -o debugcube.o cube.c clean: rm -rf *.o -test: debugcube.o +test: cleandebug debugcube.o CUBETYPE=${CUBETYPE} TEST=${TEST} ./test/test.sh benchmark: cube.o CUBETYPE=${CUBETYPE} ./benchmark/bench.sh -.PHONY: all clean test benchmark +.PHONY: all clean cleancube cleandebug test benchmark diff --git a/README.md b/README.md @@ -2,11 +2,30 @@ A simple set of basic routines for working with a 3x3x3 Rubik's Cube. -Work in progress. - ## How to use CubeCore -TODO +(More details coming soon) + +0. Requirements: a C99 compiler (e.g. GCC) + +1. Compile CubeCore + +``` +$ make +$ make test # optional +``` + +2. Include in your C or C++ project + +``` +#include "cube.h" +``` + +3. Compile including the `cube.o` file + +``` +$ gcc mycode.c cube.o +``` ## The cube diff --git a/TODO.txt b/TODO.txt @@ -1,2 +0,0 @@ -- add public method apply move inplace -- make apply moves work inplace? diff --git a/constants.h b/constants.h @@ -45,22 +45,6 @@ #define _eflip 0x10U #define _error 0xFFU -typedef enum { - U, U2, U3, D, D2, D3, - R, R2, R3, L, L2, L3, - F, F2, F3, B, B2, B3 -} move_t; - -typedef enum { - UFr, ULr, UBr, URr, DFr, DLr, DBr, DRr, - RUr, RFr, RDr, RBr, LUr, LFr, LDr, LBr, - FUr, FRr, FDr, FLr, BUr, BRr, BDr, BLr, - - UFm, ULm, UBm, URm, DFm, DLm, DBm, DRm, - RUm, RFm, RDm, RBm, LUm, LFm, LDm, LBm, - FUm, FRm, FDm, FLm, BUm, BRm, BDm, BLm -} trans_t; - _static cube_t zero = { .corner = {0}, .edge = {0} }; _static cube_t solved = { .corner = {0, 1, 2, 3, 4, 5, 6, 7}, diff --git a/cube.c b/cube.c @@ -43,329 +43,251 @@ _static void write_H48(cube_t, char *); _static void write_LST(cube_t, char *); _static uint8_t readmove(char); _static uint8_t readmodifier(char); -_static uint8_t readtrans(char *); -_static int writemoves(uint8_t *, int, char *); -_static void writetrans(uint8_t, char *); -_static cube_t move(cube_t, move_t); -_static cube_t transform(cube_t, trans_t); -cube_t -cube_new(void) +_static uint8_t +readco(char *str) { - return solved; + if (*str == '0') + return 0; + if (*str == '1') + return _ctwist_cw; + if (*str == '2') + return _ctwist_ccw; + + DBG_LOG("Error reading CO\n"); + return _error; } -cube_t -cube_clone(cube_t c) +_static uint8_t +readcp(char *str) { - cube_t ret; + uint8_t c; - memcpy(&ret, &c, sizeof(cube_t)); + for (c = 0; c < 8; c++) + if (!strncmp(str, cornerstr[c], 3) || + !strncmp(str, cornerstralt[c], 3)) + return c; - return ret; + DBG_LOG("Error reading CP\n"); + return _error; } -bool -cube_consistent(cube_t cube) +_static uint8_t +readeo(char *str) { - uint8_t i, p, e, piece; - bool found[12]; - - for (i = 0; i < 12; i++) - found[i] = false; - for (i = 0; i < 12; i++) { - piece = cube.edge[i]; - p = piece & _pbits; - e = piece & _eobit; - if (p >= 12) - goto inconsistent_ep; - if (e != 0 && e != _eobit) - goto inconsistent_eo; - found[p] = true; - } - for (i = 0; i < 12; i++) - if (!found[i]) - goto inconsistent_ep; - - for (i = 0; i < 8; i++) - found[i] = false; - for (i = 0; i < 8; i++) { - piece = cube.corner[i]; - p = piece & _pbits; - e = piece & _cobits; - if (p >= 8) - goto inconsistent_cp; - if (e != 0 && e != _ctwist_cw && e != _ctwist_ccw) - goto inconsistent_co; - found[p] = true; - } - for (i = 0; i < 8; i++) - if (!found[i]) - goto inconsistent_co; - - return true; + if (*str == '0') + return 0; + if (*str == '1') + return _eflip; -inconsistent_ep: - DBG_LOG("Inconsistent EP\n"); - return false; -inconsistent_cp: - DBG_LOG("Inconsistent CP\n"); - return false; -inconsistent_eo: - DBG_LOG("Inconsistent EO\n"); - return false; -inconsistent_co: - DBG_LOG("Inconsistent CO\n"); - return false; + DBG_LOG("Error reading EO\n"); + return _error; } -bool -cube_solvable(cube_t cube) +_static uint8_t +readep(char *str) { - uint8_t i, eo, co, piece, edges[12], corners[8]; + uint8_t e; - DBG_ASSERT(cube_consistent(cube), false, - "cube_solvable: cube is inconsistent\n"); + for (e = 0; e < 12; e++) + if (!strncmp(str, edgestr[e], 2)) + return e; - for (i = 0; i < 12; i++) - edges[i] = cube.edge[i] & _pbits; - for (i = 0; i < 8; i++) - corners[i] = cube.corner[i] & _pbits; + DBG_LOG("Error reading EP\n"); + return _error; +} - if (permsign(edges, 12) != permsign(corners, 8)) - goto solvable_parity; +_static cube_t +read_H48(char *buf) +{ + int i; + uint8_t piece, orient; + cube_t ret = {0}; + char *b; + + b = buf; - eo = 0; for (i = 0; i < 12; i++) { - piece = cube.edge[i]; - eo += (piece & _eobit) >> _eoshift; + while (*b == ' ' || *b == '\t' || *b == '\n') + b++; + if ((piece = readep(b)) == _error) + return zero; + b += 2; + if ((orient = readeo(b)) == _error) + return zero; + b++; + ret.edge[i] = piece | orient; } - if (eo % 2 != 0) - goto solvable_eo; - - co = 0; for (i = 0; i < 8; i++) { - piece = cube.corner[i]; - co += (piece & _cobits) >> _coshift; + while (*b == ' ' || *b == '\t' || *b == '\n') + b++; + if ((piece = readcp(b)) == _error) + return zero; + b += 3; + if ((orient = readco(b)) == _error) + return zero; + b++; + ret.corner[i] = piece | orient; } - if (co % 3 != 0) - goto solvable_co; - - return true; -solvable_parity: - DBG_LOG("EP and CP parities are different\n"); - return false; -solvable_eo: - DBG_LOG("Odd number of flipped edges\n"); - return false; -solvable_co: - DBG_LOG("Sum of corner orientation is not multiple of 3\n"); - return false; + return ret; } -bool -cube_solved(cube_t cube) +_static uint8_t +readpiece_LST(char **b) { - return cube_equal(cube, solved); + uint8_t ret; + bool read; + + while (**b == ',' || **b == ' ' || **b == '\t' || **b == '\n') + (*b)++; + + for (ret = 0, read = false; **b >= '0' && **b <= '9'; (*b)++) { + read = true; + ret = ret * 10 + (**b) - '0'; + } + + return read ? ret : _error; } -bool -cube_equal(cube_t c1, cube_t c2) +_static cube_t +read_LST(char *buf) { int i; - bool ret; + cube_t ret = {0}; - ret = true; for (i = 0; i < 8; i++) - ret = ret && c1.corner[i] == c2.corner[i]; + ret.corner[i] = readpiece_LST(&buf); + for (i = 0; i < 12; i++) - ret = ret && c1.edge[i] == c2.edge[i]; + ret.edge[i] = readpiece_LST(&buf); return ret; } -bool -cube_error(cube_t cube) -{ - return cube_equal(cube, zero); -} - -cube_t -cube_compose(cube_t c1, cube_t c2) +_static int +writepiece_LST(uint8_t piece, char *buf) { - cube_t ret; - uint8_t i, piece1, piece2, p, orien, aux, auy; + char digits[3]; + int i, len = 0; - DBG_ASSERT(cube_consistent(c1) && cube_consistent(c2), - zero, "cube_compose error: inconsistent cube\n") + while (piece != 0) { + digits[len++] = (piece % 10) + '0'; + piece /= 10; + } - ret = zero; + if (len == 0) + digits[len++] = '0'; - for (i = 0; i < 12; i++) { - piece2 = c2.edge[i]; - p = piece2 & _pbits; - piece1 = c1.edge[p]; - orien = (piece2 ^ piece1) & _eobit; - ret.edge[i] = (piece1 & _pbits) | orien; - } + for (i = 0; i < len; i++) + buf[i] = digits[len-i-1]; - for (i = 0; i < 8; i++) { - piece2 = c2.corner[i]; - p = piece2 & _pbits; - piece1 = c1.corner[p]; - aux = (piece2 & _cobits) + (piece1 & _cobits); - auy = (aux + _ctwist_cw) >> 2U; - orien = (aux + auy) & _cobits2; - ret.corner[i] = (piece1 & _pbits) | orien; - } + buf[len] = ','; + buf[len+1] = ' '; - return ret; + return len+2; } -cube_t -cube_inverse(cube_t cube) +_static void +write_H48(cube_t cube, char *buf) { - cube_t ret; - uint8_t i, piece, orien; - - DBG_ASSERT(cube_consistent(cube), zero, - "cube_inverse error: inconsistent cube\n"); - - ret = zero; + uint8_t piece, perm, orient; + int i; for (i = 0; i < 12; i++) { piece = cube.edge[i]; - orien = piece & _eobit; - ret.edge[piece & _pbits] = i | orien; + perm = piece & _pbits; + orient = (piece & _eobit) >> _eoshift; + buf[4*i ] = edgestr[perm][0]; + buf[4*i + 1] = edgestr[perm][1]; + buf[4*i + 2] = orient + '0'; + buf[4*i + 3] = ' '; } - for (i = 0; i < 8; i++) { piece = cube.corner[i]; - orien = ((piece << 1) | (piece >> 1)) & _cobits2; - ret.corner[piece & _pbits] = i | orien; + perm = piece & _pbits; + orient = (piece & _cobits) >> _coshift; + buf[48 + 5*i ] = cornerstr[perm][0]; + buf[48 + 5*i + 1] = cornerstr[perm][1]; + buf[48 + 5*i + 2] = cornerstr[perm][2]; + buf[48 + 5*i + 3] = orient + '0'; + buf[48 + 5*i + 4] = ' '; } - return ret; + buf[48+39] = '\0'; } -cube_t -applymoves(cube_t cube, char *buf) +_static void +write_LST(cube_t cube, char *buf) { - cube_t ret; - uint8_t r, m; - char *b; - - DBG_ASSERT(cube_consistent(cube), zero, - "move error: inconsistent cube\n"); + int i, ptr; + uint8_t piece; - ret = cube_clone(cube); + ptr = 0; - for (b = buf; *b != '\0'; b++) { - while (*b == ' ' || *b == '\t' || *b == '\n') - b++; - if (*b == '\0') - goto applymoves_finish; - if ((r = readmove(*b)) == _error) - goto applymoves_error; - if ((m = readmodifier(*(b+1))) != 0) - b++; - ret = move(ret, r + m); + for (i = 0; i < 8; i++) { + piece = cube.corner[i]; + ptr += writepiece_LST(piece, buf + ptr); } -applymoves_finish: - return ret; - -applymoves_error: - DBG_LOG("applymoves error\n"); - return zero; -} - -cube_t -applytrans(cube_t cube, char *buf) -{ - cube_t ret; - uint8_t t; - - DBG_ASSERT(cube_consistent(cube), zero, - "transformation error: inconsistent cube\n"); - - t = readtrans(buf); - ret = cube_clone(cube); - ret = transform(ret, t); - - return cube_clone(ret); -} - -int64_t -cube_coord_co(cube_t c) -{ - int i, p; - int64_t ret; - - for (ret = 0, i = 0, p = 1; i < 7; i++, p *= 3) - ret += p * (c.corner[i] >> _coshift); - - return ret; -} - -int64_t -cube_coord_eo(cube_t c) -{ - int i, p; - int64_t ret; - - for (ret = 0, i = 1, p = 1; i < 12; i++, p *= 2) - ret += p * (c.edge[i] >> _eoshift); - - return ret; + for (i = 0; i < 12; i++) { + piece = cube.edge[i]; + ptr += writepiece_LST(piece, buf + ptr); + } + + *(buf+ptr-2) = 0; } -cube_t -cube_read(char *format, char *buf) +_static uint8_t +readmove(char c) { - cube_t cube; - - if (!strcmp(format, "H48")) { - cube = read_H48(buf); - } else if (!strcmp(format, "LST")) { - cube = read_LST(buf); - } else { - DBG_LOG("Cannot read cube in the given format\n"); - cube = zero; + switch (c) { + case 'U': + return U; + case 'D': + return D; + case 'R': + return R; + case 'L': + return L; + case 'F': + return F; + case 'B': + return B; + default: + return _error; } - - return cube; } -void -cube_write(char *format, cube_t cube, char *buf) +_static uint8_t +readmodifier(char c) { - char *errormsg; - size_t len; - - if (!cube_consistent(cube)) { - errormsg = "ERROR: cannot write inconsistent cube"; - goto write_error; + switch (c) { + case '1': /* Fallthrough */ + case '2': /* Fallthrough */ + case '3': + return c - '0' - 1; + case '\'': + return 2; + default: + return 0; } +} - if (!strcmp(format, "H48")) { - write_H48(cube, buf); - } else if (!strcmp(format, "LST")) { - write_LST(cube, buf); - } else { - errormsg = "ERROR: cannot write cube in the given format"; - goto write_error; - } +_static_inline cube_t +invertco(cube_t c) +{ + uint8_t i, piece, orien; + cube_t ret; - return; + ret = c; + for (i = 0; i < 8; i++) { + piece = c.corner[i]; + orien = ((piece << 1) | (piece >> 1)) & _cobits2; + ret.corner[i] = (piece & _pbits) | orien; + } -write_error: - DBG_LOG("cube_write error, see stdout for details\n"); - len = strlen(errormsg); - memcpy(buf, errormsg, len); - buf[len] = '\n'; - buf[len+1] = '\0'; + return ret; } _static int @@ -381,322 +303,355 @@ permsign(uint8_t *a, int n) return ret % 2; } -_static uint8_t -readco(char *str) +cube_t +cube_new(void) { - if (*str == '0') - return 0; - if (*str == '1') - return _ctwist_cw; - if (*str == '2') - return _ctwist_ccw; - - DBG_LOG("Error reading CO\n"); - return _error; + return solved; } -_static uint8_t -readcp(char *str) +cube_t +cube_clone(cube_t c) { - uint8_t c; + cube_t ret; - for (c = 0; c < 8; c++) - if (!strncmp(str, cornerstr[c], 3) || - !strncmp(str, cornerstralt[c], 3)) - return c; + memcpy(&ret, &c, sizeof(cube_t)); - DBG_LOG("Error reading CP\n"); - return _error; + return ret; } -_static uint8_t -readeo(char *str) +bool +cube_consistent(cube_t cube) { - if (*str == '0') - return 0; - if (*str == '1') - return _eflip; + uint8_t i, p, e, piece; + bool found[12]; - DBG_LOG("Error reading EO\n"); - return _error; -} + for (i = 0; i < 12; i++) + found[i] = false; + for (i = 0; i < 12; i++) { + piece = cube.edge[i]; + p = piece & _pbits; + e = piece & _eobit; + if (p >= 12) + goto inconsistent_ep; + if (e != 0 && e != _eobit) + goto inconsistent_eo; + found[p] = true; + } + for (i = 0; i < 12; i++) + if (!found[i]) + goto inconsistent_ep; -_static uint8_t -readep(char *str) -{ - uint8_t e; + for (i = 0; i < 8; i++) + found[i] = false; + for (i = 0; i < 8; i++) { + piece = cube.corner[i]; + p = piece & _pbits; + e = piece & _cobits; + if (p >= 8) + goto inconsistent_cp; + if (e != 0 && e != _ctwist_cw && e != _ctwist_ccw) + goto inconsistent_co; + found[p] = true; + } + for (i = 0; i < 8; i++) + if (!found[i]) + goto inconsistent_co; - for (e = 0; e < 12; e++) - if (!strncmp(str, edgestr[e], 2)) - return e; + return true; - DBG_LOG("Error reading EP\n"); - return _error; +inconsistent_ep: + DBG_LOG("Inconsistent EP\n"); + return false; +inconsistent_cp: + DBG_LOG("Inconsistent CP\n"); + return false; +inconsistent_eo: + DBG_LOG("Inconsistent EO\n"); + return false; +inconsistent_co: + DBG_LOG("Inconsistent CO\n"); + return false; } -_static cube_t -read_H48(char *buf) +bool +cube_solvable(cube_t cube) { - int i; - uint8_t piece, orient; - cube_t ret = {0}; - char *b; - - b = buf; + uint8_t i, eo, co, piece, edges[12], corners[8]; + + DBG_ASSERT(cube_consistent(cube), false, + "cube_solvable: cube is inconsistent\n"); + + for (i = 0; i < 12; i++) + edges[i] = cube.edge[i] & _pbits; + for (i = 0; i < 8; i++) + corners[i] = cube.corner[i] & _pbits; + if (permsign(edges, 12) != permsign(corners, 8)) + goto solvable_parity; + + eo = 0; for (i = 0; i < 12; i++) { - while (*b == ' ' || *b == '\t' || *b == '\n') - b++; - if ((piece = readep(b)) == _error) - return zero; - b += 2; - if ((orient = readeo(b)) == _error) - return zero; - b++; - ret.edge[i] = piece | orient; + piece = cube.edge[i]; + eo += (piece & _eobit) >> _eoshift; } + if (eo % 2 != 0) + goto solvable_eo; + + co = 0; for (i = 0; i < 8; i++) { - while (*b == ' ' || *b == '\t' || *b == '\n') - b++; - if ((piece = readcp(b)) == _error) - return zero; - b += 3; - if ((orient = readco(b)) == _error) - return zero; - b++; - ret.corner[i] = piece | orient; + piece = cube.corner[i]; + co += (piece & _cobits) >> _coshift; } + if (co % 3 != 0) + goto solvable_co; - return ret; -} - -_static uint8_t -readpiece_LST(char **b) -{ - uint8_t ret; - bool read; - - while (**b == ',' || **b == ' ' || **b == '\t' || **b == '\n') - (*b)++; + return true; - for (ret = 0, read = false; **b >= '0' && **b <= '9'; (*b)++) { - read = true; - ret = ret * 10 + (**b) - '0'; - } +solvable_parity: + DBG_LOG("EP and CP parities are different\n"); + return false; +solvable_eo: + DBG_LOG("Odd number of flipped edges\n"); + return false; +solvable_co: + DBG_LOG("Sum of corner orientation is not multiple of 3\n"); + return false; +} - return read ? ret : _error; +bool +cube_solved(cube_t cube) +{ + return cube_equal(cube, solved); } -_static cube_t -read_LST(char *buf) +bool +cube_equal(cube_t c1, cube_t c2) { int i; - cube_t ret = {0}; + bool ret; + ret = true; for (i = 0; i < 8; i++) - ret.corner[i] = readpiece_LST(&buf); - + ret = ret && c1.corner[i] == c2.corner[i]; for (i = 0; i < 12; i++) - ret.edge[i] = readpiece_LST(&buf); + ret = ret && c1.edge[i] == c2.edge[i]; return ret; } -_static int -writepiece_LST(uint8_t piece, char *buf) +bool +cube_error(cube_t cube) { - char digits[3]; - int i, len = 0; + return cube_equal(cube, zero); +} - while (piece != 0) { - digits[len++] = (piece % 10) + '0'; - piece /= 10; - } +cube_t +cube_compose(cube_t c1, cube_t c2) +{ + cube_t ret; + uint8_t i, piece1, piece2, p, orien, aux, auy; - if (len == 0) - digits[len++] = '0'; + DBG_ASSERT(cube_consistent(c1) && cube_consistent(c2), + zero, "cube_compose error: inconsistent cube\n") - for (i = 0; i < len; i++) - buf[i] = digits[len-i-1]; + ret = zero; - buf[len] = ','; - buf[len+1] = ' '; + for (i = 0; i < 12; i++) { + piece2 = c2.edge[i]; + p = piece2 & _pbits; + piece1 = c1.edge[p]; + orien = (piece2 ^ piece1) & _eobit; + ret.edge[i] = (piece1 & _pbits) | orien; + } - return len+2; + for (i = 0; i < 8; i++) { + piece2 = c2.corner[i]; + p = piece2 & _pbits; + piece1 = c1.corner[p]; + aux = (piece2 & _cobits) + (piece1 & _cobits); + auy = (aux + _ctwist_cw) >> 2U; + orien = (aux + auy) & _cobits2; + ret.corner[i] = (piece1 & _pbits) | orien; + } + + return ret; } -_static void -write_H48(cube_t cube, char *buf) +cube_t +cube_inverse(cube_t cube) { - uint8_t piece, perm, orient; - int i; + cube_t ret; + uint8_t i, piece, orien; + + DBG_ASSERT(cube_consistent(cube), zero, + "cube_inverse error: inconsistent cube\n"); + + ret = zero; for (i = 0; i < 12; i++) { piece = cube.edge[i]; - perm = piece & _pbits; - orient = (piece & _eobit) >> _eoshift; - buf[4*i ] = edgestr[perm][0]; - buf[4*i + 1] = edgestr[perm][1]; - buf[4*i + 2] = orient + '0'; - buf[4*i + 3] = ' '; + orien = piece & _eobit; + ret.edge[piece & _pbits] = i | orien; } + for (i = 0; i < 8; i++) { piece = cube.corner[i]; - perm = piece & _pbits; - orient = (piece & _cobits) >> _coshift; - buf[48 + 5*i ] = cornerstr[perm][0]; - buf[48 + 5*i + 1] = cornerstr[perm][1]; - buf[48 + 5*i + 2] = cornerstr[perm][2]; - buf[48 + 5*i + 3] = orient + '0'; - buf[48 + 5*i + 4] = ' '; + orien = ((piece << 1) | (piece >> 1)) & _cobits2; + ret.corner[piece & _pbits] = i | orien; } - buf[48+39] = '\0'; + return ret; } -_static void -write_LST(cube_t cube, char *buf) +cube_t +cube_move(cube_t c, move_t m) { - int i, ptr; - uint8_t piece; - - ptr = 0; + return cube_compose(c, move_table[m]); +} - for (i = 0; i < 8; i++) { - piece = cube.corner[i]; - ptr += writepiece_LST(piece, buf + ptr); - } +cube_t +cube_transform(cube_t c, trans_t t) +{ + cube_t tcube, tinv; - for (i = 0; i < 12; i++) { - piece = cube.edge[i]; - ptr += writepiece_LST(piece, buf + ptr); - } + tcube = trans_table[t][NORMAL]; + tinv = trans_table[t][INVERSE]; - *(buf+ptr-2) = 0; + return t < 24 ? + cube_compose(cube_compose(tcube, c), tinv) : + invertco(cube_compose(cube_compose(tcube, c), tinv)); } -_static uint8_t -readmove(char c) +int64_t +cube_coord_co(cube_t c) { - switch (c) { - case 'U': - return U; - case 'D': - return D; - case 'R': - return R; - case 'L': - return L; - case 'F': - return F; - case 'B': - return B; - default: - return _error; - } + int i, p; + int64_t ret; + + for (ret = 0, i = 0, p = 1; i < 7; i++, p *= 3) + ret += p * (c.corner[i] >> _coshift); + + return ret; } -_static uint8_t -readmodifier(char c) +int64_t +cube_coord_eo(cube_t c) { - switch (c) { - case '1': /* Fallthrough */ - case '2': /* Fallthrough */ - case '3': - return c - '0' - 1; - case '\'': - return 2; - default: - return 0; - } + int i, p; + int64_t ret; + + for (ret = 0, i = 1, p = 1; i < 12; i++, p *= 2) + ret += p * (c.edge[i] >> _eoshift); + + return ret; } -_static uint8_t -readtrans(char *buf) +cube_t +cube_read(char *format, char *buf) { - uint8_t t; + cube_t cube; - for (t = 0; t < 48; t++) - if (!strncmp(buf, transstr[t], 11)) - return t; + if (!strcmp(format, "H48")) { + cube = read_H48(buf); + } else if (!strcmp(format, "LST")) { + cube = read_LST(buf); + } else { + DBG_LOG("Cannot read cube in the given format\n"); + cube = zero; + } - DBG_LOG("readtrans error\n"); - return _error; + return cube; } -_static int -writemoves(uint8_t *m, int n, char *buf) +void +cube_write(char *format, cube_t cube, char *buf) { - int i; + char *errormsg; size_t len; - char *b, *s; - - for (i = 0, b = buf; i < n; i++, b++) { - s = movestr[m[i]]; - len = strlen(s); - memcpy(b, s, len); - b += len; - *b = ' '; + + if (!cube_consistent(cube)) { + errormsg = "ERROR: cannot write inconsistent cube"; + goto write_error; } - if (b != buf) - b--; /* Remove last space */ - *b = '\0'; + if (!strcmp(format, "H48")) { + write_H48(cube, buf); + } else if (!strcmp(format, "LST")) { + write_LST(cube, buf); + } else { + errormsg = "ERROR: cannot write cube in the given format"; + goto write_error; + } - return b - buf; -} + return; -_static void -writetrans(uint8_t t, char *buf) -{ - if (t >= 48) - memcpy(buf, "error trans", 11); - else - memcpy(buf, transstr[t], 11); - buf[11] = '\0'; +write_error: + DBG_LOG("cube_write error, see stdout for details\n"); + len = strlen(errormsg); + memcpy(buf, errormsg, len); + buf[len] = '\n'; + buf[len+1] = '\0'; } -_static cube_t -move(cube_t c, move_t m) +int +cube_readmoves(char *buf, move_t *ret) { - return cube_compose(c, move_table[m]); + int n; + move_t r, m; + char *b; + + for (n = 0, b = buf; *b != '\0'; b++) { + while (*b == ' ' || *b == '\t' || *b == '\n') + b++; + if (*b == '\0') + goto applymoves_finish; + if ((r = readmove(*b)) == _error) + goto applymoves_error; + if ((m = readmodifier(*(b+1))) != 0) + b++; + ret[n++] = m + r; + } + +applymoves_finish: + return n; + +applymoves_error: + DBG_LOG("applymoves error\n"); + return -1; } -_static_inline cube_t -invertco(cube_t c) +trans_t +cube_readtrans(char *buf) { - uint8_t i, piece, orien; - cube_t ret; + trans_t t; - ret = c; - for (i = 0; i < 8; i++) { - piece = c.corner[i]; - orien = ((piece << 1) | (piece >> 1)) & _cobits2; - ret.corner[i] = (piece & _pbits) | orien; - } + for (t = 0; t < 48; t++) + if (!strncmp(buf, transstr[t], 11)) + return t; - return ret; + return -1; } - -_static cube_t -transform(cube_t c, trans_t t) +char * +cube_movestr(move_t m) { - cube_t tcube, tinv; - - tcube = trans_table[t][NORMAL]; - tinv = trans_table[t][INVERSE]; + return movestr[m]; +} - return t < 24 ? - cube_compose(cube_compose(tcube, c), tinv) : - invertco(cube_compose(cube_compose(tcube, c), tinv)); +char * +cube_transstr(trans_t t) +{ + return transstr[t]; } -/* TODO: expose or remove, maybe add inverse move */ -_static_inline uint8_t inverse_trans(uint8_t); +move_t +cube_inversemove(move_t m) +{ + return m - 2*(m%3) + 2; +} -_static_inline uint8_t -inverse_trans(uint8_t t) +trans_t +cube_inversetrans(trans_t t) { return inverse_trans_table[t]; } diff --git a/cube.h b/cube.h @@ -1,3 +1,19 @@ +typedef enum { + U, U2, U3, D, D2, D3, + R, R2, R3, L, L2, L3, + F, F2, F3, B, B2, B3 +} move_t; + +typedef enum { + UFr, ULr, UBr, URr, DFr, DLr, DBr, DRr, + RUr, RFr, RDr, RBr, LUr, LFr, LDr, LBr, + FUr, FRr, FDr, FLr, BUr, BRr, BDr, BLr, + + UFm, ULm, UBm, URm, DFm, DLm, DBm, DRm, + RUm, RFm, RDm, RBm, LUm, LFm, LDm, LBm, + FUm, FRm, FDm, FLm, BUm, BRm, BDm, BLm +} trans_t; + typedef struct { uint8_t corner[8]; uint8_t edge[12]; @@ -12,9 +28,17 @@ bool cube_equal(cube_t, cube_t); bool cube_error(cube_t); cube_t cube_compose(cube_t, cube_t); cube_t cube_inverse(cube_t); +cube_t cube_move(cube_t, move_t); +cube_t cube_transform(cube_t, trans_t); int64_t cube_coord_co(cube_t); int64_t cube_coord_eo(cube_t); cube_t cube_read(char *format, char *buf); void cube_write(char *format, cube_t cube, char *buf); +int cube_readmoves(char *, move_t *); +char *cube_movestr(move_t); +trans_t cube_readtrans(char *); +char *cube_transstr(trans_t); +move_t cube_inversemove(move_t); +trans_t cube_inversetrans(trans_t); diff --git a/cube.o b/cube.o Binary files differ. diff --git a/test/030_move/move_tests.c b/test/030_move/move_tests.c @@ -4,13 +4,21 @@ cube_t applymoves(cube_t, char *); int main(void) { char movestr[STRLENMAX], cubestr[STRLENMAX]; + int i, n; + move_t moves[STRLENMAX]; cube_t cube; fgets(movestr, STRLENMAX, stdin); fgets(cubestr, STRLENMAX, stdin); cube = cube_read("H48", cubestr); - cube = applymoves(cube, movestr); + n = cube_readmoves(movestr, moves); + + if (n == -1) + printf("Error reading moves!\n"); + + for (i = 0; i < n; i++) + cube = cube_move(cube, moves[i]); if (cube_error(cube)) { printf("Error moving cube\n"); diff --git a/test/060_transform/transform_tests.c b/test/060_transform/transform_tests.c @@ -5,12 +5,14 @@ cube_t applytrans(cube_t, char *); int main(void) { char cubestr[STRLENMAX], transtr[STRLENMAX]; cube_t cube; + trans_t t; fgets(transtr, STRLENMAX, stdin); fgets(cubestr, STRLENMAX, stdin); cube = cube_read("H48", cubestr); - cube = applytrans(cube, transtr); + t = cube_readtrans(transtr); + cube = cube_transform(cube, t); if (cube_error(cube)) { printf("Error transforming cube\n"); diff --git a/test/061_inverse_trans/inverse_trans_tests.c b/test/061_inverse_trans/inverse_trans_tests.c @@ -1,36 +1,32 @@ #include "../test.h" -uint8_t readtrans(char *); -uint8_t inverse_trans(uint8_t); -cube_t applymoves(cube_t, char *); -cube_t applytrans(cube_t, char *); -extern char *transstr[]; - int main(void) { - uint8_t t, tinv; + uint8_t t, tinv, tt; cube_t cube; for (t = 0; t < 48; t++) { cube = cube_new(); - cube = applymoves(cube, "R"); - cube = applymoves(cube, "U"); - cube = applymoves(cube, "F"); + cube = cube_move(cube, R); + cube = cube_move(cube, U); + cube = cube_move(cube, F); - cube = applytrans(cube, transstr[t]); - tinv = inverse_trans(t); - cube = applytrans(cube, transstr[tinv]); + tt = cube_readtrans(cube_transstr(t)); + cube = cube_transform(cube, tt); + tinv = cube_inversetrans(t); + tt = cube_readtrans(cube_transstr(tinv)); + cube = cube_transform(cube, tt); if (cube_error(cube)) { printf("Error transforming cube\n"); } else if (!cube_solvable(cube)) { printf("Transformed cube is not solvable\n"); } else { - cube = applymoves(cube, "F'"); - cube = applymoves(cube, "U'"); - cube = applymoves(cube, "R'"); + cube = cube_move(cube, F3); + cube = cube_move(cube, U3); + cube = cube_move(cube, R3); if (!cube_solved(cube)) printf("%s: Error! Got %" PRIu8 "\n", - transstr[t], tinv); + cube_transstr(t), tinv); } }