diff options
Diffstat (limited to 'src/core/cube.h')
| -rw-r--r-- | src/core/cube.h | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/src/core/cube.h b/src/core/cube.h new file mode 100644 index 0000000..fe36f90 --- /dev/null +++ b/src/core/cube.h | |||
| @@ -0,0 +1,291 @@ | |||
| 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 cube_t solvedcube(void); | ||
| 6 | _static bool isconsistent(cube_t); | ||
| 7 | _static bool issolvable(cube_t); | ||
| 8 | _static bool issolved(cube_t); | ||
| 9 | _static bool iserror(cube_t); | ||
| 10 | _static cube_t applymoves(cube_t, const char *); | ||
| 11 | _static cube_t applytrans(cube_t, const char *); | ||
| 12 | _static cube_t frommoves(const char *); | ||
| 13 | _static void getcube_fix(int64_t *, int64_t *, int64_t *, int64_t *); | ||
| 14 | _static cube_t getcube(int64_t, int64_t, int64_t, int64_t); | ||
| 15 | |||
| 16 | _static cube_t move(cube_t, uint8_t); | ||
| 17 | _static cube_t transform_edges(cube_t, uint8_t); | ||
| 18 | _static cube_t transform_corners(cube_t, uint8_t); | ||
| 19 | _static cube_t transform(cube_t, uint8_t); | ||
| 20 | |||
| 21 | _static cube_t | ||
| 22 | cubefromarray(uint8_t c[static 8], uint8_t e[static 12]) | ||
| 23 | { | ||
| 24 | return static_cube( | ||
| 25 | c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], | ||
| 26 | e[0], e[1], e[2], e[3], e[4], e[5], e[6], e[7], | ||
| 27 | e[8], e[9], e[10], e[11]); | ||
| 28 | } | ||
| 29 | |||
| 30 | _static cube_t | ||
| 31 | solvedcube(void) | ||
| 32 | { | ||
| 33 | return solved; | ||
| 34 | } | ||
| 35 | |||
| 36 | _static bool | ||
| 37 | isconsistent(cube_t cube) | ||
| 38 | { | ||
| 39 | uint8_t i, p, e, piece, corner[8], edge[12]; | ||
| 40 | bool found[12]; | ||
| 41 | |||
| 42 | pieces(&cube, corner, edge); | ||
| 43 | |||
| 44 | for (i = 0; i < 12; i++) | ||
| 45 | found[i] = false; | ||
| 46 | for (i = 0; i < 12; i++) { | ||
| 47 | piece = edge[i]; | ||
| 48 | p = piece & _pbits; | ||
| 49 | e = piece & _eobit; | ||
| 50 | if (p >= 12) | ||
| 51 | goto inconsistent_ep; | ||
| 52 | if (e != 0 && e != _eobit) | ||
| 53 | goto inconsistent_eo; | ||
| 54 | found[p] = true; | ||
| 55 | } | ||
| 56 | for (i = 0; i < 12; i++) | ||
| 57 | if (!found[i]) | ||
| 58 | goto inconsistent_ep; | ||
| 59 | |||
| 60 | for (i = 0; i < 8; i++) | ||
| 61 | found[i] = false; | ||
| 62 | for (i = 0; i < 8; i++) { | ||
| 63 | piece = corner[i]; | ||
| 64 | p = piece & _pbits; | ||
| 65 | e = piece & _cobits; | ||
| 66 | if (p >= 8) | ||
| 67 | goto inconsistent_cp; | ||
| 68 | if (e != 0 && e != _ctwist_cw && e != _ctwist_ccw) | ||
| 69 | goto inconsistent_co; | ||
| 70 | found[p] = true; | ||
| 71 | } | ||
| 72 | for (i = 0; i < 8; i++) | ||
| 73 | if (!found[i]) | ||
| 74 | goto inconsistent_co; | ||
| 75 | |||
| 76 | return true; | ||
| 77 | |||
| 78 | inconsistent_ep: | ||
| 79 | LOG("Inconsistent EP\n"); | ||
| 80 | return false; | ||
| 81 | inconsistent_cp: | ||
| 82 | LOG("Inconsistent CP\n"); | ||
| 83 | return false; | ||
| 84 | inconsistent_eo: | ||
| 85 | LOG("Inconsistent EO\n"); | ||
| 86 | return false; | ||
| 87 | inconsistent_co: | ||
| 88 | LOG("Inconsistent CO\n"); | ||
| 89 | return false; | ||
| 90 | } | ||
| 91 | |||
| 92 | _static bool | ||
| 93 | issolvable(cube_t cube) | ||
| 94 | { | ||
| 95 | uint8_t i, eo, co, piece, edge[12], corner[8], ep[12], cp[8]; | ||
| 96 | |||
| 97 | DBG_ASSERT(isconsistent(cube), false, | ||
| 98 | "issolvable: cube is inconsistent\n"); | ||
| 99 | |||
| 100 | pieces(&cube, corner, edge); | ||
| 101 | for (i = 0; i < 12; i++) | ||
| 102 | ep[i] = edge[i] & _pbits; | ||
| 103 | for (i = 0; i < 8; i++) | ||
| 104 | cp[i] = corner[i] & _pbits; | ||
| 105 | |||
| 106 | if (permsign(ep, 12) != permsign(cp, 8)) | ||
| 107 | goto issolvable_parity; | ||
| 108 | |||
| 109 | eo = 0; | ||
| 110 | for (i = 0; i < 12; i++) { | ||
| 111 | piece = edge[i]; | ||
| 112 | eo += (piece & _eobit) >> _eoshift; | ||
| 113 | } | ||
| 114 | if (eo % 2 != 0) | ||
| 115 | goto issolvable_eo; | ||
| 116 | |||
| 117 | co = 0; | ||
| 118 | for (i = 0; i < 8; i++) { | ||
| 119 | piece = corner[i]; | ||
| 120 | co += (piece & _cobits) >> _coshift; | ||
| 121 | } | ||
| 122 | if (co % 3 != 0) | ||
| 123 | goto issolvable_co; | ||
| 124 | |||
| 125 | return true; | ||
| 126 | |||
| 127 | issolvable_parity: | ||
| 128 | LOG("EP and CP parities are different\n"); | ||
| 129 | return false; | ||
| 130 | issolvable_eo: | ||
| 131 | LOG("Odd number of flipped edges\n"); | ||
| 132 | return false; | ||
| 133 | issolvable_co: | ||
| 134 | LOG("Sum of corner orientation is not multiple of 3\n"); | ||
| 135 | return false; | ||
| 136 | } | ||
| 137 | |||
| 138 | bool | ||
| 139 | issolved(cube_t cube) | ||
| 140 | { | ||
| 141 | return equal(cube, solved); | ||
| 142 | } | ||
| 143 | |||
| 144 | bool | ||
| 145 | iserror(cube_t cube) | ||
| 146 | { | ||
| 147 | return equal(cube, zero); | ||
| 148 | } | ||
| 149 | |||
| 150 | _static cube_t | ||
| 151 | applymoves(cube_t cube, const char *buf) | ||
| 152 | { | ||
| 153 | uint8_t r, m; | ||
| 154 | const char *b; | ||
| 155 | |||
| 156 | DBG_ASSERT(isconsistent(cube), zero, | ||
| 157 | "move error: inconsistent cube\n"); | ||
| 158 | |||
| 159 | for (b = buf; *b != '\0'; b++) { | ||
| 160 | while (*b == ' ' || *b == '\t' || *b == '\n') | ||
| 161 | b++; | ||
| 162 | if (*b == '\0') | ||
| 163 | goto applymoves_finish; | ||
| 164 | if ((r = readmove(*b)) == _error) | ||
| 165 | goto applymoves_error; | ||
| 166 | if ((m = readmodifier(*(b+1))) != 0) | ||
| 167 | b++; | ||
| 168 | cube = move(cube, r + m); | ||
| 169 | } | ||
| 170 | |||
| 171 | applymoves_finish: | ||
| 172 | return cube; | ||
| 173 | |||
| 174 | applymoves_error: | ||
| 175 | LOG("applymoves error\n"); | ||
| 176 | return zero; | ||
| 177 | } | ||
| 178 | |||
| 179 | _static cube_t | ||
| 180 | frommoves(const char *buf) | ||
| 181 | { | ||
| 182 | return applymoves(solved, buf); | ||
| 183 | } | ||
| 184 | |||
| 185 | _static void | ||
| 186 | getcube_fix(int64_t *ep, int64_t *eo, int64_t *cp, int64_t *co) | ||
| 187 | { | ||
| 188 | uint8_t e[12], c[8], coarr[8]; | ||
| 189 | |||
| 190 | *ep = (*ep % _12f + _12f) % _12f; | ||
| 191 | *eo = (*eo % _2p11 + _2p11) % _2p11; | ||
| 192 | *cp = (*cp % _8f + _8f) % _8f; | ||
| 193 | *co = (*cp % _3p7 + _3p7) % _3p7; | ||
| 194 | |||
| 195 | indextoperm(*ep, 12, e); | ||
| 196 | indextoperm(*cp, 8, c); | ||
| 197 | if (permsign(e, 12) != permsign(c, 8)) { | ||
| 198 | _swap(c[0], c[1]); | ||
| 199 | *cp = permtoindex(c, 8); | ||
| 200 | |||
| 201 | sumzerotodigits(*co, 8, 3, coarr); | ||
| 202 | _swap(coarr[0], coarr[1]); | ||
| 203 | *co = digitstosumzero(coarr, 8, 3); | ||
| 204 | } | ||
| 205 | } | ||
| 206 | |||
| 207 | _static cube_t | ||
| 208 | getcube(int64_t ep, int64_t eo, int64_t cp, int64_t co) | ||
| 209 | { | ||
| 210 | uint8_t i, earr[12], carr[8], eoarr[12], coarr[8]; | ||
| 211 | |||
| 212 | sumzerotodigits(eo, 12, 2, eoarr); | ||
| 213 | DBG_ASSERT(eoarr[0] != _error, zero, "Error making EO"); | ||
| 214 | indextoperm(ep, 12, earr); | ||
| 215 | DBG_ASSERT(earr[0] != _error, zero, "Error making EP"); | ||
| 216 | for (i = 0; i < 12; i++) | ||
| 217 | earr[i] |= eoarr[i] << _eoshift; | ||
| 218 | |||
| 219 | sumzerotodigits(co, 8, 3, coarr); | ||
| 220 | DBG_ASSERT(coarr[0] != _error, zero, "Error making CO"); | ||
| 221 | indextoperm(cp, 8, carr); | ||
| 222 | DBG_ASSERT(carr[0] != _error, zero, "Error making CP"); | ||
| 223 | for (i = 0; i < 8; i++) | ||
| 224 | carr[i] |= coarr[i] << _coshift; | ||
| 225 | |||
| 226 | return cubefromarray(carr, earr); | ||
| 227 | } | ||
| 228 | |||
| 229 | _static cube_t | ||
| 230 | applytrans(cube_t cube, const char *buf) | ||
| 231 | { | ||
| 232 | uint8_t t; | ||
| 233 | |||
| 234 | DBG_ASSERT(isconsistent(cube), zero, | ||
| 235 | "transformation error: inconsistent cube\n"); | ||
| 236 | |||
| 237 | t = readtrans(buf); | ||
| 238 | |||
| 239 | return transform(cube, t); | ||
| 240 | } | ||
| 241 | |||
| 242 | _static cube_t | ||
| 243 | move(cube_t c, uint8_t m) | ||
| 244 | { | ||
| 245 | switch (m) { | ||
| 246 | case _move_U: | ||
| 247 | return _move(U, c); | ||
| 248 | case _move_U2: | ||
| 249 | return _move(U2, c); | ||
| 250 | case _move_U3: | ||
| 251 | return _move(U3, c); | ||
| 252 | case _move_D: | ||
| 253 | return _move(D, c); | ||
| 254 | case _move_D2: | ||
| 255 | return _move(D2, c); | ||
| 256 | case _move_D3: | ||
| 257 | return _move(D3, c); | ||
| 258 | case _move_R: | ||
| 259 | return _move(R, c); | ||
| 260 | case _move_R2: | ||
| 261 | return _move(R2, c); | ||
| 262 | case _move_R3: | ||
| 263 | return _move(R3, c); | ||
| 264 | case _move_L: | ||
| 265 | return _move(L, c); | ||
| 266 | case _move_L2: | ||
| 267 | return _move(L2, c); | ||
| 268 | case _move_L3: | ||
| 269 | return _move(L3, c); | ||
| 270 | case _move_F: | ||
| 271 | return _move(F, c); | ||
| 272 | case _move_F2: | ||
| 273 | return _move(F2, c); | ||
| 274 | case _move_F3: | ||
| 275 | return _move(F3, c); | ||
| 276 | case _move_B: | ||
| 277 | return _move(B, c); | ||
| 278 | case _move_B2: | ||
| 279 | return _move(B2, c); | ||
| 280 | case _move_B3: | ||
| 281 | return _move(B3, c); | ||
| 282 | default: | ||
| 283 | LOG("move error, unknown move\n"); | ||
| 284 | return zero; | ||
| 285 | } | ||
| 286 | } | ||
| 287 | |||
| 288 | /* | ||
| 289 | TODO transform is now relegated to a separated file because it is too long. | ||
| 290 | It would be nice to make it shorter without loosing performance. | ||
| 291 | */ | ||
