diff options
| -rw-r--r-- | Makefile | 17 | ||||
| -rw-r--r-- | README.md | 25 | ||||
| -rw-r--r-- | TODO.txt | 2 | ||||
| -rw-r--r-- | constants.h | 16 | ||||
| -rw-r--r-- | cube.c | 643 | ||||
| -rw-r--r-- | cube.h | 24 | ||||
| -rw-r--r-- | cube.o | bin | 0 -> 22112 bytes | |||
| -rw-r--r-- | test/030_move/move_tests.c | 10 | ||||
| -rw-r--r-- | test/060_transform/transform_tests.c | 4 | ||||
| -rw-r--r-- | test/061_inverse_trans/inverse_trans_tests.c | 30 |
10 files changed, 380 insertions, 391 deletions
| @@ -3,24 +3,27 @@ DBGFLAGS = -std=c99 -pedantic -Wall -Wextra -g3 -DDEBUG | |||
| 3 | 3 | ||
| 4 | CC = cc | 4 | CC = cc |
| 5 | 5 | ||
| 6 | all: cube.o debugcube.o | 6 | all: cleancube cube.o |
| 7 | 7 | ||
| 8 | cube.s: clean | 8 | cleancube: |
| 9 | ${CC} ${CFLAGS} -c -S -o cube.s cube.c | 9 | rm -rf cube.o |
| 10 | 10 | ||
| 11 | cube.o: clean | 11 | cube.o: |
| 12 | ${CC} ${CFLAGS} -c -o cube.o cube.c | 12 | ${CC} ${CFLAGS} -c -o cube.o cube.c |
| 13 | 13 | ||
| 14 | debugcube.o: clean | 14 | cleandebug: |
| 15 | rm -rf debugcube.o | ||
| 16 | |||
| 17 | debugcube.o: | ||
| 15 | ${CC} ${DBGFLAGS} -c -o debugcube.o cube.c | 18 | ${CC} ${DBGFLAGS} -c -o debugcube.o cube.c |
| 16 | 19 | ||
| 17 | clean: | 20 | clean: |
| 18 | rm -rf *.o | 21 | rm -rf *.o |
| 19 | 22 | ||
| 20 | test: debugcube.o | 23 | test: cleandebug debugcube.o |
| 21 | CUBETYPE=${CUBETYPE} TEST=${TEST} ./test/test.sh | 24 | CUBETYPE=${CUBETYPE} TEST=${TEST} ./test/test.sh |
| 22 | 25 | ||
| 23 | benchmark: cube.o | 26 | benchmark: cube.o |
| 24 | CUBETYPE=${CUBETYPE} ./benchmark/bench.sh | 27 | CUBETYPE=${CUBETYPE} ./benchmark/bench.sh |
| 25 | 28 | ||
| 26 | .PHONY: all clean test benchmark | 29 | .PHONY: all clean cleancube cleandebug test benchmark |
| @@ -2,11 +2,30 @@ | |||
| 2 | 2 | ||
| 3 | A simple set of basic routines for working with a 3x3x3 Rubik's Cube. | 3 | A simple set of basic routines for working with a 3x3x3 Rubik's Cube. |
| 4 | 4 | ||
| 5 | Work in progress. | ||
| 6 | |||
| 7 | ## How to use CubeCore | 5 | ## How to use CubeCore |
| 8 | 6 | ||
| 9 | TODO | 7 | (More details coming soon) |
| 8 | |||
| 9 | 0. Requirements: a C99 compiler (e.g. GCC) | ||
| 10 | |||
| 11 | 1. Compile CubeCore | ||
| 12 | |||
| 13 | ``` | ||
| 14 | $ make | ||
| 15 | $ make test # optional | ||
| 16 | ``` | ||
| 17 | |||
| 18 | 2. Include in your C or C++ project | ||
| 19 | |||
| 20 | ``` | ||
| 21 | #include "cube.h" | ||
| 22 | ``` | ||
| 23 | |||
| 24 | 3. Compile including the `cube.o` file | ||
| 25 | |||
| 26 | ``` | ||
| 27 | $ gcc mycode.c cube.o | ||
| 28 | ``` | ||
| 10 | 29 | ||
| 11 | ## The cube | 30 | ## The cube |
| 12 | 31 | ||
diff --git a/TODO.txt b/TODO.txt deleted file mode 100644 index e8bf4f7..0000000 --- a/TODO.txt +++ /dev/null | |||
| @@ -1,2 +0,0 @@ | |||
| 1 | - add public method apply move inplace | ||
| 2 | - make apply moves work inplace? | ||
diff --git a/constants.h b/constants.h index c3b9312..cf584b1 100644 --- a/constants.h +++ b/constants.h | |||
| @@ -45,22 +45,6 @@ | |||
| 45 | #define _eflip 0x10U | 45 | #define _eflip 0x10U |
| 46 | #define _error 0xFFU | 46 | #define _error 0xFFU |
| 47 | 47 | ||
| 48 | typedef enum { | ||
| 49 | U, U2, U3, D, D2, D3, | ||
| 50 | R, R2, R3, L, L2, L3, | ||
| 51 | F, F2, F3, B, B2, B3 | ||
| 52 | } move_t; | ||
| 53 | |||
| 54 | typedef enum { | ||
| 55 | UFr, ULr, UBr, URr, DFr, DLr, DBr, DRr, | ||
| 56 | RUr, RFr, RDr, RBr, LUr, LFr, LDr, LBr, | ||
| 57 | FUr, FRr, FDr, FLr, BUr, BRr, BDr, BLr, | ||
| 58 | |||
| 59 | UFm, ULm, UBm, URm, DFm, DLm, DBm, DRm, | ||
| 60 | RUm, RFm, RDm, RBm, LUm, LFm, LDm, LBm, | ||
| 61 | FUm, FRm, FDm, FLm, BUm, BRm, BDm, BLm | ||
| 62 | } trans_t; | ||
| 63 | |||
| 64 | _static cube_t zero = { .corner = {0}, .edge = {0} }; | 48 | _static cube_t zero = { .corner = {0}, .edge = {0} }; |
| 65 | _static cube_t solved = { | 49 | _static cube_t solved = { |
| 66 | .corner = {0, 1, 2, 3, 4, 5, 6, 7}, | 50 | .corner = {0, 1, 2, 3, 4, 5, 6, 7}, |
| @@ -43,11 +43,265 @@ _static void write_H48(cube_t, char *); | |||
| 43 | _static void write_LST(cube_t, char *); | 43 | _static void write_LST(cube_t, char *); |
| 44 | _static uint8_t readmove(char); | 44 | _static uint8_t readmove(char); |
| 45 | _static uint8_t readmodifier(char); | 45 | _static uint8_t readmodifier(char); |
| 46 | _static uint8_t readtrans(char *); | 46 | |
| 47 | _static int writemoves(uint8_t *, int, char *); | 47 | _static uint8_t |
| 48 | _static void writetrans(uint8_t, char *); | 48 | readco(char *str) |
| 49 | _static cube_t move(cube_t, move_t); | 49 | { |
| 50 | _static cube_t transform(cube_t, trans_t); | 50 | if (*str == '0') |
| 51 | return 0; | ||
| 52 | if (*str == '1') | ||
| 53 | return _ctwist_cw; | ||
| 54 | if (*str == '2') | ||
| 55 | return _ctwist_ccw; | ||
| 56 | |||
| 57 | DBG_LOG("Error reading CO\n"); | ||
| 58 | return _error; | ||
| 59 | } | ||
| 60 | |||
| 61 | _static uint8_t | ||
| 62 | readcp(char *str) | ||
| 63 | { | ||
| 64 | uint8_t c; | ||
| 65 | |||
| 66 | for (c = 0; c < 8; c++) | ||
| 67 | if (!strncmp(str, cornerstr[c], 3) || | ||
| 68 | !strncmp(str, cornerstralt[c], 3)) | ||
| 69 | return c; | ||
| 70 | |||
| 71 | DBG_LOG("Error reading CP\n"); | ||
| 72 | return _error; | ||
| 73 | } | ||
| 74 | |||
| 75 | _static uint8_t | ||
| 76 | readeo(char *str) | ||
| 77 | { | ||
| 78 | if (*str == '0') | ||
| 79 | return 0; | ||
| 80 | if (*str == '1') | ||
| 81 | return _eflip; | ||
| 82 | |||
| 83 | DBG_LOG("Error reading EO\n"); | ||
| 84 | return _error; | ||
| 85 | } | ||
| 86 | |||
| 87 | _static uint8_t | ||
| 88 | readep(char *str) | ||
| 89 | { | ||
| 90 | uint8_t e; | ||
| 91 | |||
| 92 | for (e = 0; e < 12; e++) | ||
| 93 | if (!strncmp(str, edgestr[e], 2)) | ||
| 94 | return e; | ||
| 95 | |||
| 96 | DBG_LOG("Error reading EP\n"); | ||
| 97 | return _error; | ||
| 98 | } | ||
| 99 | |||
| 100 | _static cube_t | ||
| 101 | read_H48(char *buf) | ||
| 102 | { | ||
| 103 | int i; | ||
| 104 | uint8_t piece, orient; | ||
| 105 | cube_t ret = {0}; | ||
| 106 | char *b; | ||
| 107 | |||
| 108 | b = buf; | ||
| 109 | |||
| 110 | for (i = 0; i < 12; i++) { | ||
| 111 | while (*b == ' ' || *b == '\t' || *b == '\n') | ||
| 112 | b++; | ||
| 113 | if ((piece = readep(b)) == _error) | ||
| 114 | return zero; | ||
| 115 | b += 2; | ||
| 116 | if ((orient = readeo(b)) == _error) | ||
| 117 | return zero; | ||
| 118 | b++; | ||
| 119 | ret.edge[i] = piece | orient; | ||
| 120 | } | ||
| 121 | for (i = 0; i < 8; i++) { | ||
| 122 | while (*b == ' ' || *b == '\t' || *b == '\n') | ||
| 123 | b++; | ||
| 124 | if ((piece = readcp(b)) == _error) | ||
| 125 | return zero; | ||
| 126 | b += 3; | ||
| 127 | if ((orient = readco(b)) == _error) | ||
| 128 | return zero; | ||
| 129 | b++; | ||
| 130 | ret.corner[i] = piece | orient; | ||
| 131 | } | ||
| 132 | |||
| 133 | return ret; | ||
| 134 | } | ||
| 135 | |||
| 136 | _static uint8_t | ||
| 137 | readpiece_LST(char **b) | ||
| 138 | { | ||
| 139 | uint8_t ret; | ||
| 140 | bool read; | ||
| 141 | |||
| 142 | while (**b == ',' || **b == ' ' || **b == '\t' || **b == '\n') | ||
| 143 | (*b)++; | ||
| 144 | |||
| 145 | for (ret = 0, read = false; **b >= '0' && **b <= '9'; (*b)++) { | ||
| 146 | read = true; | ||
| 147 | ret = ret * 10 + (**b) - '0'; | ||
| 148 | } | ||
| 149 | |||
| 150 | return read ? ret : _error; | ||
| 151 | } | ||
| 152 | |||
| 153 | _static cube_t | ||
| 154 | read_LST(char *buf) | ||
| 155 | { | ||
| 156 | int i; | ||
| 157 | cube_t ret = {0}; | ||
| 158 | |||
| 159 | for (i = 0; i < 8; i++) | ||
| 160 | ret.corner[i] = readpiece_LST(&buf); | ||
| 161 | |||
| 162 | for (i = 0; i < 12; i++) | ||
| 163 | ret.edge[i] = readpiece_LST(&buf); | ||
| 164 | |||
| 165 | return ret; | ||
| 166 | } | ||
| 167 | |||
| 168 | _static int | ||
| 169 | writepiece_LST(uint8_t piece, char *buf) | ||
| 170 | { | ||
| 171 | char digits[3]; | ||
| 172 | int i, len = 0; | ||
| 173 | |||
| 174 | while (piece != 0) { | ||
| 175 | digits[len++] = (piece % 10) + '0'; | ||
| 176 | piece /= 10; | ||
| 177 | } | ||
| 178 | |||
| 179 | if (len == 0) | ||
| 180 | digits[len++] = '0'; | ||
| 181 | |||
| 182 | for (i = 0; i < len; i++) | ||
| 183 | buf[i] = digits[len-i-1]; | ||
| 184 | |||
| 185 | buf[len] = ','; | ||
| 186 | buf[len+1] = ' '; | ||
| 187 | |||
| 188 | return len+2; | ||
| 189 | } | ||
| 190 | |||
| 191 | _static void | ||
| 192 | write_H48(cube_t cube, char *buf) | ||
| 193 | { | ||
| 194 | uint8_t piece, perm, orient; | ||
| 195 | int i; | ||
| 196 | |||
| 197 | for (i = 0; i < 12; i++) { | ||
| 198 | piece = cube.edge[i]; | ||
| 199 | perm = piece & _pbits; | ||
| 200 | orient = (piece & _eobit) >> _eoshift; | ||
| 201 | buf[4*i ] = edgestr[perm][0]; | ||
| 202 | buf[4*i + 1] = edgestr[perm][1]; | ||
| 203 | buf[4*i + 2] = orient + '0'; | ||
| 204 | buf[4*i + 3] = ' '; | ||
| 205 | } | ||
| 206 | for (i = 0; i < 8; i++) { | ||
| 207 | piece = cube.corner[i]; | ||
| 208 | perm = piece & _pbits; | ||
| 209 | orient = (piece & _cobits) >> _coshift; | ||
| 210 | buf[48 + 5*i ] = cornerstr[perm][0]; | ||
| 211 | buf[48 + 5*i + 1] = cornerstr[perm][1]; | ||
| 212 | buf[48 + 5*i + 2] = cornerstr[perm][2]; | ||
| 213 | buf[48 + 5*i + 3] = orient + '0'; | ||
| 214 | buf[48 + 5*i + 4] = ' '; | ||
| 215 | } | ||
| 216 | |||
| 217 | buf[48+39] = '\0'; | ||
| 218 | } | ||
| 219 | |||
| 220 | _static void | ||
| 221 | write_LST(cube_t cube, char *buf) | ||
| 222 | { | ||
| 223 | int i, ptr; | ||
| 224 | uint8_t piece; | ||
| 225 | |||
| 226 | ptr = 0; | ||
| 227 | |||
| 228 | for (i = 0; i < 8; i++) { | ||
| 229 | piece = cube.corner[i]; | ||
| 230 | ptr += writepiece_LST(piece, buf + ptr); | ||
| 231 | } | ||
| 232 | |||
| 233 | for (i = 0; i < 12; i++) { | ||
| 234 | piece = cube.edge[i]; | ||
| 235 | ptr += writepiece_LST(piece, buf + ptr); | ||
| 236 | } | ||
| 237 | |||
| 238 | *(buf+ptr-2) = 0; | ||
| 239 | } | ||
| 240 | |||
| 241 | _static uint8_t | ||
| 242 | readmove(char c) | ||
| 243 | { | ||
| 244 | switch (c) { | ||
| 245 | case 'U': | ||
| 246 | return U; | ||
| 247 | case 'D': | ||
| 248 | return D; | ||
| 249 | case 'R': | ||
| 250 | return R; | ||
| 251 | case 'L': | ||
| 252 | return L; | ||
| 253 | case 'F': | ||
| 254 | return F; | ||
| 255 | case 'B': | ||
| 256 | return B; | ||
| 257 | default: | ||
| 258 | return _error; | ||
| 259 | } | ||
| 260 | } | ||
| 261 | |||
| 262 | _static uint8_t | ||
| 263 | readmodifier(char c) | ||
| 264 | { | ||
| 265 | switch (c) { | ||
| 266 | case '1': /* Fallthrough */ | ||
| 267 | case '2': /* Fallthrough */ | ||
| 268 | case '3': | ||
| 269 | return c - '0' - 1; | ||
| 270 | case '\'': | ||
| 271 | return 2; | ||
| 272 | default: | ||
| 273 | return 0; | ||
| 274 | } | ||
| 275 | } | ||
| 276 | |||
| 277 | _static_inline cube_t | ||
| 278 | invertco(cube_t c) | ||
| 279 | { | ||
| 280 | uint8_t i, piece, orien; | ||
| 281 | cube_t ret; | ||
| 282 | |||
| 283 | ret = c; | ||
| 284 | for (i = 0; i < 8; i++) { | ||
| 285 | piece = c.corner[i]; | ||
| 286 | orien = ((piece << 1) | (piece >> 1)) & _cobits2; | ||
| 287 | ret.corner[i] = (piece & _pbits) | orien; | ||
| 288 | } | ||
| 289 | |||
| 290 | return ret; | ||
| 291 | } | ||
| 292 | |||
| 293 | _static int | ||
| 294 | permsign(uint8_t *a, int n) | ||
| 295 | { | ||
| 296 | int i, j; | ||
| 297 | uint8_t ret = 0; | ||
| 298 | |||
| 299 | for (i = 0; i < n; i++) | ||
| 300 | for (j = i+1; j < n; j++) | ||
| 301 | ret += a[i] > a[j] ? 1 : 0; | ||
| 302 | |||
| 303 | return ret % 2; | ||
| 304 | } | ||
| 51 | 305 | ||
| 52 | cube_t | 306 | cube_t |
| 53 | cube_new(void) | 307 | cube_new(void) |
| @@ -250,51 +504,22 @@ cube_inverse(cube_t cube) | |||
| 250 | } | 504 | } |
| 251 | 505 | ||
| 252 | cube_t | 506 | cube_t |
| 253 | applymoves(cube_t cube, char *buf) | 507 | cube_move(cube_t c, move_t m) |
| 254 | { | 508 | { |
| 255 | cube_t ret; | 509 | return cube_compose(c, move_table[m]); |
| 256 | uint8_t r, m; | ||
| 257 | char *b; | ||
| 258 | |||
| 259 | DBG_ASSERT(cube_consistent(cube), zero, | ||
| 260 | "move error: inconsistent cube\n"); | ||
| 261 | |||
| 262 | ret = cube_clone(cube); | ||
| 263 | |||
| 264 | for (b = buf; *b != '\0'; b++) { | ||
| 265 | while (*b == ' ' || *b == '\t' || *b == '\n') | ||
| 266 | b++; | ||
| 267 | if (*b == '\0') | ||
| 268 | goto applymoves_finish; | ||
| 269 | if ((r = readmove(*b)) == _error) | ||
| 270 | goto applymoves_error; | ||
| 271 | if ((m = readmodifier(*(b+1))) != 0) | ||
| 272 | b++; | ||
| 273 | ret = move(ret, r + m); | ||
| 274 | } | ||
| 275 | |||
| 276 | applymoves_finish: | ||
| 277 | return ret; | ||
| 278 | |||
| 279 | applymoves_error: | ||
| 280 | DBG_LOG("applymoves error\n"); | ||
| 281 | return zero; | ||
| 282 | } | 510 | } |
| 283 | 511 | ||
| 284 | cube_t | 512 | cube_t |
| 285 | applytrans(cube_t cube, char *buf) | 513 | cube_transform(cube_t c, trans_t t) |
| 286 | { | 514 | { |
| 287 | cube_t ret; | 515 | cube_t tcube, tinv; |
| 288 | uint8_t t; | ||
| 289 | |||
| 290 | DBG_ASSERT(cube_consistent(cube), zero, | ||
| 291 | "transformation error: inconsistent cube\n"); | ||
| 292 | 516 | ||
| 293 | t = readtrans(buf); | 517 | tcube = trans_table[t][NORMAL]; |
| 294 | ret = cube_clone(cube); | 518 | tinv = trans_table[t][INVERSE]; |
| 295 | ret = transform(ret, t); | ||
| 296 | 519 | ||
| 297 | return cube_clone(ret); | 520 | return t < 24 ? |
| 521 | cube_compose(cube_compose(tcube, c), tinv) : | ||
| 522 | invertco(cube_compose(cube_compose(tcube, c), tinv)); | ||
| 298 | } | 523 | } |
| 299 | 524 | ||
| 300 | int64_t | 525 | int64_t |
| @@ -368,335 +593,65 @@ write_error: | |||
| 368 | buf[len+1] = '\0'; | 593 | buf[len+1] = '\0'; |
| 369 | } | 594 | } |
| 370 | 595 | ||
| 371 | _static int | 596 | int |
| 372 | permsign(uint8_t *a, int n) | 597 | cube_readmoves(char *buf, move_t *ret) |
| 373 | { | ||
| 374 | int i, j; | ||
| 375 | uint8_t ret = 0; | ||
| 376 | |||
| 377 | for (i = 0; i < n; i++) | ||
| 378 | for (j = i+1; j < n; j++) | ||
| 379 | ret += a[i] > a[j] ? 1 : 0; | ||
| 380 | |||
| 381 | return ret % 2; | ||
| 382 | } | ||
| 383 | |||
| 384 | _static uint8_t | ||
| 385 | readco(char *str) | ||
| 386 | { | ||
| 387 | if (*str == '0') | ||
| 388 | return 0; | ||
| 389 | if (*str == '1') | ||
| 390 | return _ctwist_cw; | ||
| 391 | if (*str == '2') | ||
| 392 | return _ctwist_ccw; | ||
| 393 | |||
| 394 | DBG_LOG("Error reading CO\n"); | ||
| 395 | return _error; | ||
| 396 | } | ||
| 397 | |||
| 398 | _static uint8_t | ||
| 399 | readcp(char *str) | ||
| 400 | { | ||
| 401 | uint8_t c; | ||
| 402 | |||
| 403 | for (c = 0; c < 8; c++) | ||
| 404 | if (!strncmp(str, cornerstr[c], 3) || | ||
| 405 | !strncmp(str, cornerstralt[c], 3)) | ||
| 406 | return c; | ||
| 407 | |||
| 408 | DBG_LOG("Error reading CP\n"); | ||
| 409 | return _error; | ||
| 410 | } | ||
| 411 | |||
| 412 | _static uint8_t | ||
| 413 | readeo(char *str) | ||
| 414 | { | ||
| 415 | if (*str == '0') | ||
| 416 | return 0; | ||
| 417 | if (*str == '1') | ||
| 418 | return _eflip; | ||
| 419 | |||
| 420 | DBG_LOG("Error reading EO\n"); | ||
| 421 | return _error; | ||
| 422 | } | ||
| 423 | |||
| 424 | _static uint8_t | ||
| 425 | readep(char *str) | ||
| 426 | { | ||
| 427 | uint8_t e; | ||
| 428 | |||
| 429 | for (e = 0; e < 12; e++) | ||
| 430 | if (!strncmp(str, edgestr[e], 2)) | ||
| 431 | return e; | ||
| 432 | |||
| 433 | DBG_LOG("Error reading EP\n"); | ||
| 434 | return _error; | ||
| 435 | } | ||
| 436 | |||
| 437 | _static cube_t | ||
| 438 | read_H48(char *buf) | ||
| 439 | { | 598 | { |
| 440 | int i; | 599 | int n; |
| 441 | uint8_t piece, orient; | 600 | move_t r, m; |
| 442 | cube_t ret = {0}; | ||
| 443 | char *b; | 601 | char *b; |
| 444 | |||
| 445 | b = buf; | ||
| 446 | 602 | ||
| 447 | for (i = 0; i < 12; i++) { | 603 | for (n = 0, b = buf; *b != '\0'; b++) { |
| 448 | while (*b == ' ' || *b == '\t' || *b == '\n') | 604 | while (*b == ' ' || *b == '\t' || *b == '\n') |
| 449 | b++; | 605 | b++; |
| 450 | if ((piece = readep(b)) == _error) | 606 | if (*b == '\0') |
| 451 | return zero; | 607 | goto applymoves_finish; |
| 452 | b += 2; | 608 | if ((r = readmove(*b)) == _error) |
| 453 | if ((orient = readeo(b)) == _error) | 609 | goto applymoves_error; |
| 454 | return zero; | 610 | if ((m = readmodifier(*(b+1))) != 0) |
| 455 | b++; | ||
| 456 | ret.edge[i] = piece | orient; | ||
| 457 | } | ||
| 458 | for (i = 0; i < 8; i++) { | ||
| 459 | while (*b == ' ' || *b == '\t' || *b == '\n') | ||
| 460 | b++; | 611 | b++; |
| 461 | if ((piece = readcp(b)) == _error) | 612 | ret[n++] = m + r; |
| 462 | return zero; | ||
| 463 | b += 3; | ||
| 464 | if ((orient = readco(b)) == _error) | ||
| 465 | return zero; | ||
| 466 | b++; | ||
| 467 | ret.corner[i] = piece | orient; | ||
| 468 | } | ||
| 469 | |||
| 470 | return ret; | ||
| 471 | } | ||
| 472 | |||
| 473 | _static uint8_t | ||
| 474 | readpiece_LST(char **b) | ||
| 475 | { | ||
| 476 | uint8_t ret; | ||
| 477 | bool read; | ||
| 478 | |||
| 479 | while (**b == ',' || **b == ' ' || **b == '\t' || **b == '\n') | ||
| 480 | (*b)++; | ||
| 481 | |||
| 482 | for (ret = 0, read = false; **b >= '0' && **b <= '9'; (*b)++) { | ||
| 483 | read = true; | ||
| 484 | ret = ret * 10 + (**b) - '0'; | ||
| 485 | } | ||
| 486 | |||
| 487 | return read ? ret : _error; | ||
| 488 | } | ||
| 489 | |||
| 490 | _static cube_t | ||
| 491 | read_LST(char *buf) | ||
| 492 | { | ||
| 493 | int i; | ||
| 494 | cube_t ret = {0}; | ||
| 495 | |||
| 496 | for (i = 0; i < 8; i++) | ||
| 497 | ret.corner[i] = readpiece_LST(&buf); | ||
| 498 | |||
| 499 | for (i = 0; i < 12; i++) | ||
| 500 | ret.edge[i] = readpiece_LST(&buf); | ||
| 501 | |||
| 502 | return ret; | ||
| 503 | } | ||
| 504 | |||
| 505 | _static int | ||
| 506 | writepiece_LST(uint8_t piece, char *buf) | ||
| 507 | { | ||
| 508 | char digits[3]; | ||
| 509 | int i, len = 0; | ||
| 510 | |||
| 511 | while (piece != 0) { | ||
| 512 | digits[len++] = (piece % 10) + '0'; | ||
| 513 | piece /= 10; | ||
| 514 | } | ||
| 515 | |||
| 516 | if (len == 0) | ||
| 517 | digits[len++] = '0'; | ||
| 518 | |||
| 519 | for (i = 0; i < len; i++) | ||
| 520 | buf[i] = digits[len-i-1]; | ||
| 521 | |||
| 522 | buf[len] = ','; | ||
| 523 | buf[len+1] = ' '; | ||
| 524 | |||
| 525 | return len+2; | ||
| 526 | } | ||
| 527 | |||
| 528 | _static void | ||
| 529 | write_H48(cube_t cube, char *buf) | ||
| 530 | { | ||
| 531 | uint8_t piece, perm, orient; | ||
| 532 | int i; | ||
| 533 | |||
| 534 | for (i = 0; i < 12; i++) { | ||
| 535 | piece = cube.edge[i]; | ||
| 536 | perm = piece & _pbits; | ||
| 537 | orient = (piece & _eobit) >> _eoshift; | ||
| 538 | buf[4*i ] = edgestr[perm][0]; | ||
| 539 | buf[4*i + 1] = edgestr[perm][1]; | ||
| 540 | buf[4*i + 2] = orient + '0'; | ||
| 541 | buf[4*i + 3] = ' '; | ||
| 542 | } | ||
| 543 | for (i = 0; i < 8; i++) { | ||
| 544 | piece = cube.corner[i]; | ||
| 545 | perm = piece & _pbits; | ||
| 546 | orient = (piece & _cobits) >> _coshift; | ||
| 547 | buf[48 + 5*i ] = cornerstr[perm][0]; | ||
| 548 | buf[48 + 5*i + 1] = cornerstr[perm][1]; | ||
| 549 | buf[48 + 5*i + 2] = cornerstr[perm][2]; | ||
| 550 | buf[48 + 5*i + 3] = orient + '0'; | ||
| 551 | buf[48 + 5*i + 4] = ' '; | ||
| 552 | } | ||
| 553 | |||
| 554 | buf[48+39] = '\0'; | ||
| 555 | } | ||
| 556 | |||
| 557 | _static void | ||
| 558 | write_LST(cube_t cube, char *buf) | ||
| 559 | { | ||
| 560 | int i, ptr; | ||
| 561 | uint8_t piece; | ||
| 562 | |||
| 563 | ptr = 0; | ||
| 564 | |||
| 565 | for (i = 0; i < 8; i++) { | ||
| 566 | piece = cube.corner[i]; | ||
| 567 | ptr += writepiece_LST(piece, buf + ptr); | ||
| 568 | } | 613 | } |
| 569 | 614 | ||
| 570 | for (i = 0; i < 12; i++) { | 615 | applymoves_finish: |
| 571 | piece = cube.edge[i]; | 616 | return n; |
| 572 | ptr += writepiece_LST(piece, buf + ptr); | ||
| 573 | } | ||
| 574 | |||
| 575 | *(buf+ptr-2) = 0; | ||
| 576 | } | ||
| 577 | |||
| 578 | _static uint8_t | ||
| 579 | readmove(char c) | ||
| 580 | { | ||
| 581 | switch (c) { | ||
| 582 | case 'U': | ||
| 583 | return U; | ||
| 584 | case 'D': | ||
| 585 | return D; | ||
| 586 | case 'R': | ||
| 587 | return R; | ||
| 588 | case 'L': | ||
| 589 | return L; | ||
| 590 | case 'F': | ||
| 591 | return F; | ||
| 592 | case 'B': | ||
| 593 | return B; | ||
| 594 | default: | ||
| 595 | return _error; | ||
| 596 | } | ||
| 597 | } | ||
| 598 | 617 | ||
| 599 | _static uint8_t | 618 | applymoves_error: |
| 600 | readmodifier(char c) | 619 | DBG_LOG("applymoves error\n"); |
| 601 | { | 620 | return -1; |
| 602 | switch (c) { | ||
| 603 | case '1': /* Fallthrough */ | ||
| 604 | case '2': /* Fallthrough */ | ||
| 605 | case '3': | ||
| 606 | return c - '0' - 1; | ||
| 607 | case '\'': | ||
| 608 | return 2; | ||
| 609 | default: | ||
| 610 | return 0; | ||
| 611 | } | ||
| 612 | } | 621 | } |
| 613 | 622 | ||
| 614 | _static uint8_t | 623 | trans_t |
| 615 | readtrans(char *buf) | 624 | cube_readtrans(char *buf) |
| 616 | { | 625 | { |
| 617 | uint8_t t; | 626 | trans_t t; |
| 618 | 627 | ||
| 619 | for (t = 0; t < 48; t++) | 628 | for (t = 0; t < 48; t++) |
| 620 | if (!strncmp(buf, transstr[t], 11)) | 629 | if (!strncmp(buf, transstr[t], 11)) |
| 621 | return t; | 630 | return t; |
| 622 | 631 | ||
| 623 | DBG_LOG("readtrans error\n"); | 632 | return -1; |
| 624 | return _error; | ||
| 625 | } | 633 | } |
| 626 | 634 | ||
| 627 | _static int | 635 | char * |
| 628 | writemoves(uint8_t *m, int n, char *buf) | 636 | cube_movestr(move_t m) |
| 629 | { | 637 | { |
| 630 | int i; | 638 | return movestr[m]; |
| 631 | size_t len; | ||
| 632 | char *b, *s; | ||
| 633 | |||
| 634 | for (i = 0, b = buf; i < n; i++, b++) { | ||
| 635 | s = movestr[m[i]]; | ||
| 636 | len = strlen(s); | ||
| 637 | memcpy(b, s, len); | ||
| 638 | b += len; | ||
| 639 | *b = ' '; | ||
| 640 | } | ||
| 641 | |||
| 642 | if (b != buf) | ||
| 643 | b--; /* Remove last space */ | ||
| 644 | *b = '\0'; | ||
| 645 | |||
| 646 | return b - buf; | ||
| 647 | } | 639 | } |
| 648 | 640 | ||
| 649 | _static void | 641 | char * |
| 650 | writetrans(uint8_t t, char *buf) | 642 | cube_transstr(trans_t t) |
| 651 | { | 643 | { |
| 652 | if (t >= 48) | 644 | return transstr[t]; |
| 653 | memcpy(buf, "error trans", 11); | ||
| 654 | else | ||
| 655 | memcpy(buf, transstr[t], 11); | ||
| 656 | buf[11] = '\0'; | ||
| 657 | } | 645 | } |
| 658 | 646 | ||
| 659 | _static cube_t | 647 | move_t |
| 660 | move(cube_t c, move_t m) | 648 | cube_inversemove(move_t m) |
| 661 | { | 649 | { |
| 662 | return cube_compose(c, move_table[m]); | 650 | return m - 2*(m%3) + 2; |
| 663 | } | 651 | } |
| 664 | 652 | ||
| 665 | _static_inline cube_t | 653 | trans_t |
| 666 | invertco(cube_t c) | 654 | cube_inversetrans(trans_t t) |
| 667 | { | ||
| 668 | uint8_t i, piece, orien; | ||
| 669 | cube_t ret; | ||
| 670 | |||
| 671 | ret = c; | ||
| 672 | for (i = 0; i < 8; i++) { | ||
| 673 | piece = c.corner[i]; | ||
| 674 | orien = ((piece << 1) | (piece >> 1)) & _cobits2; | ||
| 675 | ret.corner[i] = (piece & _pbits) | orien; | ||
| 676 | } | ||
| 677 | |||
| 678 | return ret; | ||
| 679 | } | ||
| 680 | |||
| 681 | |||
| 682 | _static cube_t | ||
| 683 | transform(cube_t c, trans_t t) | ||
| 684 | { | ||
| 685 | cube_t tcube, tinv; | ||
| 686 | |||
| 687 | tcube = trans_table[t][NORMAL]; | ||
| 688 | tinv = trans_table[t][INVERSE]; | ||
| 689 | |||
| 690 | return t < 24 ? | ||
| 691 | cube_compose(cube_compose(tcube, c), tinv) : | ||
| 692 | invertco(cube_compose(cube_compose(tcube, c), tinv)); | ||
| 693 | } | ||
| 694 | |||
| 695 | /* TODO: expose or remove, maybe add inverse move */ | ||
| 696 | _static_inline uint8_t inverse_trans(uint8_t); | ||
| 697 | |||
| 698 | _static_inline uint8_t | ||
| 699 | inverse_trans(uint8_t t) | ||
| 700 | { | 655 | { |
| 701 | return inverse_trans_table[t]; | 656 | return inverse_trans_table[t]; |
| 702 | } | 657 | } |
| @@ -1,3 +1,19 @@ | |||
| 1 | typedef enum { | ||
| 2 | U, U2, U3, D, D2, D3, | ||
| 3 | R, R2, R3, L, L2, L3, | ||
| 4 | F, F2, F3, B, B2, B3 | ||
| 5 | } move_t; | ||
| 6 | |||
| 7 | typedef enum { | ||
| 8 | UFr, ULr, UBr, URr, DFr, DLr, DBr, DRr, | ||
| 9 | RUr, RFr, RDr, RBr, LUr, LFr, LDr, LBr, | ||
| 10 | FUr, FRr, FDr, FLr, BUr, BRr, BDr, BLr, | ||
| 11 | |||
| 12 | UFm, ULm, UBm, URm, DFm, DLm, DBm, DRm, | ||
| 13 | RUm, RFm, RDm, RBm, LUm, LFm, LDm, LBm, | ||
| 14 | FUm, FRm, FDm, FLm, BUm, BRm, BDm, BLm | ||
| 15 | } trans_t; | ||
| 16 | |||
| 1 | typedef struct { | 17 | typedef struct { |
| 2 | uint8_t corner[8]; | 18 | uint8_t corner[8]; |
| 3 | uint8_t edge[12]; | 19 | uint8_t edge[12]; |
| @@ -12,9 +28,17 @@ bool cube_equal(cube_t, cube_t); | |||
| 12 | bool cube_error(cube_t); | 28 | bool cube_error(cube_t); |
| 13 | cube_t cube_compose(cube_t, cube_t); | 29 | cube_t cube_compose(cube_t, cube_t); |
| 14 | cube_t cube_inverse(cube_t); | 30 | cube_t cube_inverse(cube_t); |
| 31 | cube_t cube_move(cube_t, move_t); | ||
| 32 | cube_t cube_transform(cube_t, trans_t); | ||
| 15 | 33 | ||
| 16 | int64_t cube_coord_co(cube_t); | 34 | int64_t cube_coord_co(cube_t); |
| 17 | int64_t cube_coord_eo(cube_t); | 35 | int64_t cube_coord_eo(cube_t); |
| 18 | 36 | ||
| 19 | cube_t cube_read(char *format, char *buf); | 37 | cube_t cube_read(char *format, char *buf); |
| 20 | void cube_write(char *format, cube_t cube, char *buf); | 38 | void cube_write(char *format, cube_t cube, char *buf); |
| 39 | int cube_readmoves(char *, move_t *); | ||
| 40 | char *cube_movestr(move_t); | ||
| 41 | trans_t cube_readtrans(char *); | ||
| 42 | char *cube_transstr(trans_t); | ||
| 43 | move_t cube_inversemove(move_t); | ||
| 44 | trans_t cube_inversetrans(trans_t); | ||
| Binary files differ | |||
diff --git a/test/030_move/move_tests.c b/test/030_move/move_tests.c index 497ac6c..b940ecb 100644 --- a/test/030_move/move_tests.c +++ b/test/030_move/move_tests.c | |||
| @@ -4,13 +4,21 @@ cube_t applymoves(cube_t, char *); | |||
| 4 | 4 | ||
| 5 | int main(void) { | 5 | int main(void) { |
| 6 | char movestr[STRLENMAX], cubestr[STRLENMAX]; | 6 | char movestr[STRLENMAX], cubestr[STRLENMAX]; |
| 7 | int i, n; | ||
| 8 | move_t moves[STRLENMAX]; | ||
| 7 | cube_t cube; | 9 | cube_t cube; |
| 8 | 10 | ||
| 9 | fgets(movestr, STRLENMAX, stdin); | 11 | fgets(movestr, STRLENMAX, stdin); |
| 10 | fgets(cubestr, STRLENMAX, stdin); | 12 | fgets(cubestr, STRLENMAX, stdin); |
| 11 | cube = cube_read("H48", cubestr); | 13 | cube = cube_read("H48", cubestr); |
| 12 | 14 | ||
| 13 | cube = applymoves(cube, movestr); | 15 | n = cube_readmoves(movestr, moves); |
| 16 | |||
| 17 | if (n == -1) | ||
| 18 | printf("Error reading moves!\n"); | ||
| 19 | |||
| 20 | for (i = 0; i < n; i++) | ||
| 21 | cube = cube_move(cube, moves[i]); | ||
| 14 | 22 | ||
| 15 | if (cube_error(cube)) { | 23 | if (cube_error(cube)) { |
| 16 | printf("Error moving cube\n"); | 24 | printf("Error moving cube\n"); |
diff --git a/test/060_transform/transform_tests.c b/test/060_transform/transform_tests.c index 454bc22..1748d6d 100644 --- a/test/060_transform/transform_tests.c +++ b/test/060_transform/transform_tests.c | |||
| @@ -5,12 +5,14 @@ cube_t applytrans(cube_t, char *); | |||
| 5 | int main(void) { | 5 | int main(void) { |
| 6 | char cubestr[STRLENMAX], transtr[STRLENMAX]; | 6 | char cubestr[STRLENMAX], transtr[STRLENMAX]; |
| 7 | cube_t cube; | 7 | cube_t cube; |
| 8 | trans_t t; | ||
| 8 | 9 | ||
| 9 | fgets(transtr, STRLENMAX, stdin); | 10 | fgets(transtr, STRLENMAX, stdin); |
| 10 | fgets(cubestr, STRLENMAX, stdin); | 11 | fgets(cubestr, STRLENMAX, stdin); |
| 11 | cube = cube_read("H48", cubestr); | 12 | cube = cube_read("H48", cubestr); |
| 12 | 13 | ||
| 13 | cube = applytrans(cube, transtr); | 14 | t = cube_readtrans(transtr); |
| 15 | cube = cube_transform(cube, t); | ||
| 14 | 16 | ||
| 15 | if (cube_error(cube)) { | 17 | if (cube_error(cube)) { |
| 16 | printf("Error transforming cube\n"); | 18 | 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 index 7de8f66..725e2f9 100644 --- a/test/061_inverse_trans/inverse_trans_tests.c +++ b/test/061_inverse_trans/inverse_trans_tests.c | |||
| @@ -1,36 +1,32 @@ | |||
| 1 | #include "../test.h" | 1 | #include "../test.h" |
| 2 | 2 | ||
| 3 | uint8_t readtrans(char *); | ||
| 4 | uint8_t inverse_trans(uint8_t); | ||
| 5 | cube_t applymoves(cube_t, char *); | ||
| 6 | cube_t applytrans(cube_t, char *); | ||
| 7 | extern char *transstr[]; | ||
| 8 | |||
| 9 | int main(void) { | 3 | int main(void) { |
| 10 | uint8_t t, tinv; | 4 | uint8_t t, tinv, tt; |
| 11 | cube_t cube; | 5 | cube_t cube; |
| 12 | 6 | ||
| 13 | for (t = 0; t < 48; t++) { | 7 | for (t = 0; t < 48; t++) { |
| 14 | cube = cube_new(); | 8 | cube = cube_new(); |
| 15 | cube = applymoves(cube, "R"); | 9 | cube = cube_move(cube, R); |
| 16 | cube = applymoves(cube, "U"); | 10 | cube = cube_move(cube, U); |
| 17 | cube = applymoves(cube, "F"); | 11 | cube = cube_move(cube, F); |
| 18 | 12 | ||
| 19 | cube = applytrans(cube, transstr[t]); | 13 | tt = cube_readtrans(cube_transstr(t)); |
| 20 | tinv = inverse_trans(t); | 14 | cube = cube_transform(cube, tt); |
| 21 | cube = applytrans(cube, transstr[tinv]); | 15 | tinv = cube_inversetrans(t); |
| 16 | tt = cube_readtrans(cube_transstr(tinv)); | ||
| 17 | cube = cube_transform(cube, tt); | ||
| 22 | 18 | ||
| 23 | if (cube_error(cube)) { | 19 | if (cube_error(cube)) { |
| 24 | printf("Error transforming cube\n"); | 20 | printf("Error transforming cube\n"); |
| 25 | } else if (!cube_solvable(cube)) { | 21 | } else if (!cube_solvable(cube)) { |
| 26 | printf("Transformed cube is not solvable\n"); | 22 | printf("Transformed cube is not solvable\n"); |
| 27 | } else { | 23 | } else { |
| 28 | cube = applymoves(cube, "F'"); | 24 | cube = cube_move(cube, F3); |
| 29 | cube = applymoves(cube, "U'"); | 25 | cube = cube_move(cube, U3); |
| 30 | cube = applymoves(cube, "R'"); | 26 | cube = cube_move(cube, R3); |
| 31 | if (!cube_solved(cube)) | 27 | if (!cube_solved(cube)) |
| 32 | printf("%s: Error! Got %" PRIu8 "\n", | 28 | printf("%s: Error! Got %" PRIu8 "\n", |
| 33 | transstr[t], tinv); | 29 | cube_transstr(t), tinv); |
| 34 | } | 30 | } |
| 35 | } | 31 | } |
| 36 | 32 | ||
