cube.h (7776B)
1 STATIC oriented_cube_t solvedcube(void); 2 STATIC cube_t cubefromarray(uint8_t [static 8], uint8_t [static 12]); 3 STATIC bool isconsistent(oriented_cube_t); 4 STATIC bool issolvable(oriented_cube_t); 5 STATIC bool issolved(oriented_cube_t); 6 STATIC bool iserror(oriented_cube_t); 7 STATIC void getcube_fix(long long *, long long *, 8 long long *, long long *, long long *); 9 STATIC cube_t getcube(int64_t, int64_t, int64_t, int64_t); 10 11 STATIC oriented_cube_t readcube(const char *); 12 STATIC int64_t writecube(oriented_cube_t, size_t n, char [n]); 13 STATIC uint8_t readco(const char *); 14 STATIC uint8_t readcp(const char *); 15 STATIC uint8_t readeo(const char *); 16 STATIC uint8_t readep(const char *); 17 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 23 /* This is used only in tests, use SOLVED_ORIENTED_CUBE everywhere else */ 24 STATIC oriented_cube_t 25 solvedcube(void) 26 { 27 return SOLVED_ORIENTED_CUBE; 28 } 29 30 STATIC cube_t 31 cubefromarray(uint8_t c[static 8], uint8_t e[static 12]) 32 { 33 return STATIC_CUBE( 34 c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], 35 e[0], e[1], e[2], e[3], e[4], e[5], e[6], e[7], 36 e[8], e[9], e[10], e[11]); 37 } 38 39 STATIC bool 40 isconsistent(oriented_cube_t cube) 41 { 42 uint8_t i, p, e, piece, corner[8], edge[12]; 43 bool found[12]; 44 45 pieces(&cube.cube, corner, edge); 46 47 for (i = 0; i < 12; i++) 48 found[i] = false; 49 for (i = 0; i < 12; i++) { 50 piece = edge[i]; 51 p = piece & PBITS; 52 e = piece & EOBIT; 53 if (p >= 12) 54 goto inconsistent_ep; 55 if (e != 0 && e != EOBIT) 56 goto inconsistent_eo; 57 found[p] = true; 58 } 59 for (i = 0; i < 12; i++) 60 if (!found[i]) 61 goto inconsistent_ep; 62 63 for (i = 0; i < 8; i++) 64 found[i] = false; 65 for (i = 0; i < 8; i++) { 66 piece = corner[i]; 67 p = piece & PBITS; 68 e = piece & COBITS; 69 if (p >= 8) 70 goto inconsistent_cp; 71 if (e != 0 && e != CTWIST_CW && e != CTWIST_CCW) 72 goto inconsistent_co; 73 found[p] = true; 74 } 75 for (i = 0; i < 8; i++) 76 if (!found[i]) 77 goto inconsistent_cp; 78 79 if (cube.orientation >= 24) 80 goto inconsistent_orientation; 81 82 return true; 83 84 inconsistent_ep: 85 inconsistent_cp: 86 inconsistent_eo: 87 inconsistent_co: 88 inconsistent_orientation: 89 /* We used to do more logging here, hence the different labels */ 90 return false; 91 } 92 93 STATIC bool 94 issolvable(oriented_cube_t cube) 95 { 96 uint8_t i, eo, co, piece, edge[12], corner[8], ep[12], cp[8]; 97 98 DBG_ASSERT(isconsistent(cube), false, 99 "issolvable: cube is inconsistent\n"); 100 101 pieces(&cube.cube, corner, edge); 102 for (i = 0; i < 12; i++) 103 ep[i] = edge[i] & PBITS; 104 for (i = 0; i < 8; i++) 105 cp[i] = corner[i] & PBITS; 106 107 if (permsign(12, ep) != permsign(8, cp)) 108 goto issolvable_parity; 109 110 eo = 0; 111 for (i = 0; i < 12; i++) { 112 piece = edge[i]; 113 eo += (piece & EOBIT) >> EOSHIFT; 114 } 115 if (eo % 2 != 0) 116 goto issolvable_eo; 117 118 co = 0; 119 for (i = 0; i < 8; i++) { 120 piece = corner[i]; 121 co += (piece & COBITS) >> COSHIFT; 122 } 123 if (co % 3 != 0) 124 goto issolvable_co; 125 126 return true; 127 128 issolvable_parity: 129 LOG("There is parity\n"); 130 return false; 131 issolvable_eo: 132 LOG("EO is not solvable\n"); 133 return false; 134 issolvable_co: 135 LOG("CO is not solvable\n"); 136 return false; 137 } 138 139 bool 140 issolved(oriented_cube_t cube) 141 { 142 return equal(cube.cube, SOLVED_CUBE); 143 } 144 145 bool 146 iserror(oriented_cube_t cube) 147 { 148 return equal(cube.cube, ZERO_CUBE); 149 } 150 151 STATIC void 152 getcube_fix( 153 long long *ep, 154 long long *eo, 155 long long *cp, 156 long long *co, 157 long long *orien 158 ) 159 { 160 uint8_t e[12], c[8], coarr[8]; 161 162 *ep = (*ep % FACT_12 + FACT_12) % FACT_12; 163 *eo = (*eo % POW_2_11 + POW_2_11) % POW_2_11; 164 *cp = (*cp % FACT_8 + FACT_8) % FACT_8; 165 *co = (*cp % POW_3_7 + POW_3_7) % POW_3_7; 166 *orien = (*orien % 24 + 24) % 24; 167 168 indextoperm(*ep, 12, e); 169 indextoperm(*cp, 8, c); 170 if (permsign(12, e) != permsign(8, c)) { 171 SWAP(c[0], c[1]); 172 *cp = permtoindex(8, c); 173 174 sumzerotodigits(*co, 8, 3, coarr); 175 SWAP(coarr[0], coarr[1]); 176 *co = digitstosumzero(8, coarr, 3); 177 } 178 } 179 180 STATIC cube_t 181 getcube(int64_t ep, int64_t eo, int64_t cp, int64_t co) 182 { 183 uint8_t i, earr[12], carr[8], eoarr[12], coarr[8]; 184 185 sumzerotodigits(eo, 12, 2, eoarr); 186 DBG_ASSERT(eoarr[0] != UINT8_ERROR, ZERO_CUBE, "Error making EO"); 187 indextoperm(ep, 12, earr); 188 DBG_ASSERT(earr[0] != UINT8_ERROR, ZERO_CUBE, "Error making EP"); 189 for (i = 0; i < 12; i++) 190 earr[i] |= eoarr[i] << EOSHIFT; 191 192 sumzerotodigits(co, 8, 3, coarr); 193 DBG_ASSERT(coarr[0] != UINT8_ERROR, ZERO_CUBE, "Error making CO"); 194 indextoperm(cp, 8, carr); 195 DBG_ASSERT(carr[0] != UINT8_ERROR, ZERO_CUBE, "Error making CP"); 196 for (i = 0; i < 8; i++) 197 carr[i] |= coarr[i] << COSHIFT; 198 199 return cubefromarray(carr, earr); 200 } 201 202 STATIC uint8_t 203 readco(const char *str) 204 { 205 if (*str == '0') 206 return 0; 207 if (*str == '1') 208 return CTWIST_CW; 209 if (*str == '2') 210 return CTWIST_CCW; 211 212 LOG("Error reading CO\n"); 213 return UINT8_ERROR; 214 } 215 216 STATIC uint8_t 217 readcp(const char *str) 218 { 219 uint8_t c; 220 221 for (c = 0; c < 8; c++) 222 if (!strncmp(str, cornerstr[c], 3) || 223 !strncmp(str, cornerstralt[c], 3)) 224 return c; 225 226 LOG("Error reading CP\n"); 227 return UINT8_ERROR; 228 } 229 230 STATIC uint8_t 231 readeo(const char *str) 232 { 233 if (*str == '0') 234 return 0; 235 if (*str == '1') 236 return EFLIP; 237 238 LOG("Error reading EO\n"); 239 return UINT8_ERROR; 240 } 241 242 STATIC uint8_t 243 readep(const char *str) 244 { 245 uint8_t e; 246 247 for (e = 0; e < 12; e++) 248 if (!strncmp(str, edgestr[e], 2)) 249 return e; 250 251 LOG("Error reading EP\n"); 252 return UINT8_ERROR; 253 } 254 255 STATIC oriented_cube_t 256 readcube(const char *buf) 257 { 258 int i; 259 uint8_t c[8], e[12], orientation; 260 261 for (i = 0; i < 8; i++) { 262 c[i] = b32tocorner(buf[i]); 263 if (c[i] == UINT8_ERROR) { 264 LOG("Error reading corner %d ", i); 265 if (buf[i] == 0) { 266 LOG("(string terminated early)\n"); 267 } else { 268 LOG("(char '%c')\n", buf[i]); 269 } 270 return ZERO_ORIENTED_CUBE; 271 } 272 } 273 274 if (buf[8] != '=') { 275 LOG("Error reading separator: a single '=' " 276 "must be used to separate edges and corners\n"); 277 return ZERO_ORIENTED_CUBE; 278 } 279 280 for (i = 0; i < 12; i++) { 281 e[i] = b32toedge(buf[i+9]); 282 if (e[i] == UINT8_ERROR) { 283 LOG("Error reading edge %d ", i); 284 if (buf[i+9] == 0) { 285 LOG("(string terminated early)\n"); 286 } else { 287 LOG("(char '%c')\n", buf[i+9]); 288 } 289 return ZERO_ORIENTED_CUBE; 290 } 291 } 292 293 orientation = (uint8_t)(buf[22] - 'A'); 294 if (orientation >= 24) { 295 LOG("Error reading orientation: impossible value %" PRIu8 296 " (%c)\n", orientation, buf[22]); 297 return ZERO_ORIENTED_CUBE; 298 } 299 300 return (oriented_cube_t) { 301 .cube = cubefromarray(c, e), 302 .orientation = orientation 303 }; 304 } 305 306 STATIC int64_t 307 writecube(oriented_cube_t cube, size_t buf_size, char buf[buf_size]) 308 { 309 int i; 310 uint8_t corner[8], edge[12]; 311 312 if (buf_size < NISSY_SIZE_CUBE) { 313 LOG("Cannot write cube: buffer size must be at least %u " 314 "bytes, but the provided one is %zu bytes.\n", 315 NISSY_SIZE_CUBE, buf_size); 316 return NISSY_ERROR_BUFFER_SIZE; 317 } 318 319 pieces(&cube.cube, corner, edge); 320 321 for (i = 0; i < 8; i++) 322 buf[i] = cornertob32(corner[i]); 323 324 buf[8] = '='; 325 326 for (i = 0; i < 12; i++) 327 buf[i+9] = edgetob32(edge[i]); 328 329 buf[21] = '='; 330 buf[22] = (char)cube.orientation + 'A'; 331 buf[23] = '\0'; 332 333 return NISSY_OK; 334 } 335 336 STATIC uint8_t 337 b32toedge(char c) 338 { 339 if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'f'))) 340 return UINT8_ERROR; 341 342 return c <= 'Z' ? (uint8_t)(c - 'A') : (uint8_t)(c - 'a') + 26; 343 } 344 345 STATIC uint8_t 346 b32tocorner(char c) { 347 uint8_t val; 348 349 if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'f'))) 350 return UINT8_ERROR; 351 352 val = c <= 'Z' ? (uint8_t)(c - 'A') : (uint8_t)(c - 'a') + 26; 353 354 return (val & 7) | ((val & 24) << 2); 355 } 356 357 STATIC char 358 edgetob32(uint8_t edge) 359 { 360 return edge < 26 ? 'A' + (char)edge : 'a' + (char)(edge - 26); 361 } 362 363 STATIC char 364 cornertob32(uint8_t corner) 365 { 366 uint8_t val; 367 368 val = (corner & 7) | ((corner & 96) >> 2); 369 370 return val < 26 ? 'A' + (char)val : 'a' + (char)(val - 26); 371 }