moves.h (8729B)
1 #define MOVE(M, c) compose(c, MOVE_CUBE_ ## M) 2 #define PREMOVE(M, c) compose(MOVE_CUBE_ ## M, c) 3 4 STATIC uint8_t readmove(char); 5 STATIC int64_t readmoves(const char *, 6 size_t n, size_t m, uint64_t *, uint64_t *, uint8_t [n], uint8_t [m]); 7 STATIC int64_t countmoves(const char *); 8 STATIC uint8_t readmodifier(char); 9 STATIC int64_t writemoves(size_t n, const uint8_t [n], size_t m, char [m]); 10 11 STATIC_INLINE bool allowednextmove(uint8_t, uint8_t); 12 STATIC bool allowedmoves(size_t n, const uint8_t [n]); 13 14 STATIC_INLINE uint8_t movebase(uint8_t); 15 STATIC_INLINE uint8_t moveaxis(uint8_t); 16 STATIC_INLINE bool isbase(uint8_t); 17 STATIC_INLINE bool parallel(uint8_t, uint8_t); 18 STATIC_INLINE uint8_t moveopposite(uint8_t); 19 STATIC_INLINE uint8_t reorient_move(uint8_t, uint8_t); 20 STATIC_INLINE uint8_t inverse_reorient_move(uint8_t, uint8_t); 21 STATIC_INLINE uint8_t movefollow(uint8_t); 22 STATIC uint8_t transform_move(uint8_t, uint8_t); 23 24 STATIC cube_t move(cube_t, uint8_t); 25 STATIC cube_t premove(cube_t, uint8_t); 26 STATIC uint8_t inverse_move(uint8_t); 27 STATIC void sortparallel_moves(size_t n, uint8_t [n]); 28 STATIC bool are_lastmoves_singlecw(size_t n, const uint8_t [n]); 29 30 #define FOREACH_READMOVE(ARG_BUF, ARG_MOVE, ARG_C, ARG_MAX, \ 31 RET_ERROR, ARG_ACTION) \ 32 const char *VAR_B; \ 33 uint8_t VAR_MOVE_NOMOD, VAR_MOD; \ 34 bool VAR_IN_PARENTHESES = false; \ 35 for (VAR_B = ARG_BUF, ARG_C = 0; *VAR_B != '\0'; VAR_B++, ARG_C++) { \ 36 while (*VAR_B == ' ' || *VAR_B == '\t' || *VAR_B == '\n') \ 37 VAR_B++; \ 38 if (*VAR_B == '\0' || ARG_C == ARG_MAX) \ 39 break; \ 40 if (*VAR_B == '(') { \ 41 if (VAR_IN_PARENTHESES) { \ 42 LOG("Nested parentheses in move sequence\n"); \ 43 return RET_ERROR; \ 44 } \ 45 VAR_IN_PARENTHESES = true; \ 46 continue; \ 47 } \ 48 if (*VAR_B == ')') { \ 49 if (!VAR_IN_PARENTHESES) { \ 50 LOG("Mismatched ')' in move sequence\n"); \ 51 return RET_ERROR; \ 52 } \ 53 VAR_IN_PARENTHESES = false; \ 54 continue; \ 55 } \ 56 if ((VAR_MOVE_NOMOD = readmove(*VAR_B)) == UINT8_ERROR) { \ 57 LOG("Unknown move: %c\n", *VAR_B); \ 58 return RET_ERROR; \ 59 } \ 60 if (*(VAR_B+1) == 'w') { \ 61 VAR_MOVE_NOMOD += 18; \ 62 VAR_B++; \ 63 } \ 64 if ((VAR_MOD = readmodifier(*(VAR_B+1))) != 0) \ 65 VAR_B++; \ 66 ARG_MOVE = VAR_MOVE_NOMOD + VAR_MOD; \ 67 ARG_ACTION \ 68 } \ 69 if (VAR_IN_PARENTHESES) { \ 70 LOG("Mismatched '(' in move sequence\n"); \ 71 return RET_ERROR; \ 72 } 73 74 STATIC uint8_t 75 readmove(char c) 76 { 77 switch (c) { 78 case 'U': 79 return MOVE_U; 80 case 'D': 81 return MOVE_D; 82 case 'R': 83 return MOVE_R; 84 case 'L': 85 return MOVE_L; 86 case 'F': 87 return MOVE_F; 88 case 'B': 89 return MOVE_B; 90 case 'M': 91 return MOVE_M; 92 case 'S': 93 return MOVE_S; 94 case 'E': 95 return MOVE_E; 96 case 'x': 97 return MOVE_x; 98 case 'y': 99 return MOVE_y; 100 case 'z': 101 return MOVE_z; 102 default: 103 return UINT8_ERROR; 104 } 105 } 106 107 STATIC uint8_t 108 readmodifier(char c) 109 { 110 switch (c) { 111 case '1': /* Fallthrough */ 112 case '2': /* Fallthrough */ 113 case '3': 114 return c - '0' - 1; 115 case '\'': 116 return 2; 117 default: 118 return 0; 119 } 120 } 121 122 STATIC int64_t 123 readmoves( 124 const char *buf, 125 size_t nsize, 126 size_t invsize, 127 uint64_t *n, 128 uint64_t *i, 129 uint8_t normal[nsize], 130 uint8_t inverse[invsize] 131 ) 132 { 133 uint8_t m; 134 uint64_t c; 135 136 *n = *i = 0; 137 FOREACH_READMOVE(buf, m, c, nsize+invsize, NISSY_ERROR_INVALID_MOVES, 138 if (!VAR_IN_PARENTHESES) { 139 if (*n >= nsize-1) { 140 LOG("Error in readmoves: normal buffer\n"); 141 return NISSY_ERROR_BUFFER_SIZE; 142 } 143 normal[(*n)++] = m; 144 } else { 145 if (*i >= invsize-1) { 146 LOG("Error in readmoves: inverse buffer\n"); 147 return NISSY_ERROR_BUFFER_SIZE; 148 } 149 inverse[(*i)++] = m; 150 } 151 ) 152 153 return (int64_t)c; 154 } 155 156 STATIC int64_t 157 countmoves(const char *buf) 158 { 159 uint8_t m; 160 uint64_t c; 161 int64_t count; 162 163 count = 0; 164 FOREACH_READMOVE(buf, m, c, INT_MAX, NISSY_ERROR_INVALID_MOVES, 165 count += m <= MOVE_Bw3 ? 1 : (m <= MOVE_E3 ? 2 : 0); 166 ) 167 168 return count; 169 } 170 171 STATIC int64_t 172 writemoves( 173 size_t nmoves, 174 const uint8_t m[nmoves], 175 size_t buf_size, 176 char buf[buf_size] 177 ) 178 { 179 size_t i, len, w; 180 const char *s; 181 182 if (buf_size == 0) { 183 LOG("Error: cannot write moves to buffer of size 0.\n"); 184 return NISSY_ERROR_BUFFER_SIZE; 185 } 186 187 for (i = 0, w = 0; i < nmoves; i++, w++) { 188 s = movestr[m[i]]; 189 len = strlen(s); 190 if (len + w >= buf_size) { 191 LOG("Error: the given buffer is too small for " 192 "writing the given moves.\n"); 193 goto writemoves_error; 194 } 195 memcpy(buf+w, s, len); 196 w += len; 197 buf[w] = ' '; 198 } 199 200 if (w > 0) w--; /* Remove last space */ 201 buf[w] = '\0'; 202 203 return (int64_t)w; 204 205 writemoves_error: 206 *buf = '\0'; 207 return NISSY_ERROR_BUFFER_SIZE; 208 } 209 210 STATIC_INLINE bool 211 allowednextmove(uint8_t m1, uint8_t m2) 212 { 213 return allowedmask[movebase(m1)] & MM_SINGLE(m2); 214 } 215 216 STATIC bool 217 allowedmoves(size_t n, const uint8_t m[n]) 218 { 219 uint8_t j; 220 221 for (j = 1; j < n; j++) 222 if (!allowednextmove(m[j-1], m[j])) 223 return false; 224 225 return true; 226 } 227 228 STATIC_INLINE uint8_t 229 movebase(uint8_t move) 230 { 231 return move / 3; 232 } 233 234 STATIC_INLINE uint8_t 235 moveaxis(uint8_t move) 236 { 237 return move / 6; 238 } 239 240 STATIC_INLINE bool 241 isbase(uint8_t move) 242 { 243 return move == 3 * movebase(move); 244 } 245 246 STATIC_INLINE bool 247 parallel(uint8_t m1, uint8_t m2) 248 { 249 return moveaxis(movefollow(m1)) == moveaxis(movefollow(m2)); 250 } 251 252 STATIC_INLINE uint8_t 253 moveopposite(uint8_t move) 254 { 255 return movebase(move) == 2 * moveaxis(move) ? move + 3 : move - 3; 256 } 257 258 STATIC_INLINE uint8_t 259 reorient_move(uint8_t m, uint8_t or) 260 { 261 return transform_move(m, orientation_trans[or]); 262 } 263 264 STATIC_INLINE uint8_t 265 inverse_reorient_move(uint8_t m, uint8_t or) 266 { 267 return transform_move(m, inverse_trans_table[orientation_trans[or]]); 268 } 269 270 STATIC_INLINE uint8_t 271 movefollow(uint8_t move) 272 { 273 uint8_t b, m; 274 275 if (move <= MOVE_B3) 276 return move; 277 278 if (move <= MOVE_Bw3) 279 return move - MOVE_Uw; 280 281 b = UINT8_C(3) * (move / UINT8_C(3)); 282 m = move - b; 283 switch (b) { 284 case MOVE_M: 285 return MOVE_L + m; 286 case MOVE_S: 287 return MOVE_F + m; 288 case MOVE_E: 289 return MOVE_D + m; 290 case MOVE_x: 291 return MOVE_R + m; 292 case MOVE_y: 293 return MOVE_U + m; 294 case MOVE_z: 295 return MOVE_F + m; 296 default: 297 return UINT8_ERROR; 298 } 299 } 300 301 STATIC cube_t 302 move(cube_t c, uint8_t m) 303 { 304 switch (m) { 305 case MOVE_U: 306 return MOVE(U, c); 307 case MOVE_U2: 308 return MOVE(U2, c); 309 case MOVE_U3: 310 return MOVE(U3, c); 311 case MOVE_D: 312 return MOVE(D, c); 313 case MOVE_D2: 314 return MOVE(D2, c); 315 case MOVE_D3: 316 return MOVE(D3, c); 317 case MOVE_R: 318 return MOVE(R, c); 319 case MOVE_R2: 320 return MOVE(R2, c); 321 case MOVE_R3: 322 return MOVE(R3, c); 323 case MOVE_L: 324 return MOVE(L, c); 325 case MOVE_L2: 326 return MOVE(L2, c); 327 case MOVE_L3: 328 return MOVE(L3, c); 329 case MOVE_F: 330 return MOVE(F, c); 331 case MOVE_F2: 332 return MOVE(F2, c); 333 case MOVE_F3: 334 return MOVE(F3, c); 335 case MOVE_B: 336 return MOVE(B, c); 337 case MOVE_B2: 338 return MOVE(B2, c); 339 case MOVE_B3: 340 return MOVE(B3, c); 341 default: 342 LOG("move error: %" PRIu8 " is not a basic move\n", m); 343 return ZERO_CUBE; 344 } 345 } 346 347 STATIC uint8_t 348 transform_move(uint8_t m, uint8_t t) 349 { 350 uint8_t a, base, modifier; 351 352 if (m > MOVE_B3) { 353 LOG("transform_move: attempting to transform %s, but " 354 "transofrmations are only supported for basic moves\n", 355 movestr[m]); 356 return UINT8_ERROR; 357 } 358 359 a = moveaxis(m); 360 base = trans_move_table[t][a]; 361 if (movebase(m) != 2 * a) 362 base = moveopposite(base); 363 364 modifier = m % 3; 365 if (t >= TRANS_UFm) 366 modifier = 2 - modifier; 367 368 return base + modifier; 369 } 370 371 /* Applies the INVERSE of m BEFORE the scramble corresponding to c */ 372 STATIC cube_t 373 premove(cube_t c, uint8_t m) 374 { 375 switch (m) { 376 case MOVE_U: 377 return PREMOVE(U3, c); 378 case MOVE_U2: 379 return PREMOVE(U2, c); 380 case MOVE_U3: 381 return PREMOVE(U, c); 382 case MOVE_D: 383 return PREMOVE(D3, c); 384 case MOVE_D2: 385 return PREMOVE(D2, c); 386 case MOVE_D3: 387 return PREMOVE(D, c); 388 case MOVE_R: 389 return PREMOVE(R3, c); 390 case MOVE_R2: 391 return PREMOVE(R2, c); 392 case MOVE_R3: 393 return PREMOVE(R, c); 394 case MOVE_L: 395 return PREMOVE(L3, c); 396 case MOVE_L2: 397 return PREMOVE(L2, c); 398 case MOVE_L3: 399 return PREMOVE(L, c); 400 case MOVE_F: 401 return PREMOVE(F3, c); 402 case MOVE_F2: 403 return PREMOVE(F2, c); 404 case MOVE_F3: 405 return PREMOVE(F, c); 406 case MOVE_B: 407 return PREMOVE(B3, c); 408 case MOVE_B2: 409 return PREMOVE(B2, c); 410 case MOVE_B3: 411 return PREMOVE(B, c); 412 default: 413 LOG("premove error: unknown move %" PRIu8 "\n", m); 414 return ZERO_CUBE; 415 } 416 } 417 418 STATIC uint8_t 419 inverse_move(uint8_t m) 420 { 421 return m - 2 * (m % 3) + 2; 422 } 423 424 STATIC void 425 sortparallel_moves(size_t n, uint8_t moves[n]) 426 { 427 uint8_t i; 428 429 if (n < 2) 430 return; 431 432 for (i = 0; i < n-1; i++) 433 if (parallel(moves[i], moves[i+1]) && moves[i] > moves[i+1]) 434 SWAP(moves[i], moves[i+1]); 435 } 436 437 STATIC bool 438 are_lastmoves_singlecw(size_t n, const uint8_t moves[n]) 439 { 440 bool two; 441 442 if (n == 0) 443 return true; 444 445 two = n > 1 && parallel(moves[n-1], moves[n-2]); 446 447 return isbase(moves[n-1]) && (!two || isbase(moves[n-2])); 448 }