nissy-core

The "engine" of nissy, including the H48 optimal solver.
git clone https://git.tronto.net/nissy-core
Download | Log | Files | Refs | README | LICENSE

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 }