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