moves.h (5980B)
1 #define MOVE(M, c) compose(c, MOVE_CUBE_ ## M) 2 #define PREMOVE(M, c) compose(MOVE_CUBE_ ## M, c) 3 4 STATIC_INLINE bool allowednextmove(uint8_t *, uint8_t); 5 STATIC_INLINE uint32_t allowednextmove_mask(uint8_t *, uint8_t); 6 7 STATIC_INLINE uint8_t movebase(uint8_t); 8 STATIC_INLINE uint8_t moveaxis(uint8_t); 9 STATIC_INLINE uint32_t disable_moves(uint32_t, uint8_t); 10 11 STATIC cube_t move(cube_t, uint8_t); 12 STATIC cube_t premove(cube_t, uint8_t); 13 STATIC uint8_t inverse_move(uint8_t); 14 STATIC void invertmoves(uint8_t *, uint8_t, uint8_t *); 15 STATIC void sortparallel(uint8_t *, uint8_t); 16 17 STATIC int readmoves(const char *, int, uint8_t *); 18 STATIC cube_t applymoves(cube_t, const char *); 19 20 #define FOREACH_READMOVE(ARG_BUF, ARG_MOVE, ARG_C, ARG_MAX, \ 21 RET_ERROR, ARG_ACTION) \ 22 const char *VAR_B; \ 23 uint8_t VAR_MOVE_NOMOD, VAR_MOD; \ 24 for (VAR_B = ARG_BUF, ARG_C = 0; *VAR_B != '\0'; VAR_B++, ARG_C++) { \ 25 while (*VAR_B == ' ' || *VAR_B == '\t' || *VAR_B == '\n') \ 26 VAR_B++; \ 27 if (*VAR_B == '\0' || ARG_C == ARG_MAX) \ 28 break; \ 29 if ((VAR_MOVE_NOMOD = readmove(*VAR_B)) == UINT8_ERROR) { \ 30 LOG("Error: unknown move '%c'\n", *VAR_B); \ 31 return RET_ERROR; \ 32 } \ 33 if ((VAR_MOD = readmodifier(*(VAR_B+1))) != 0) \ 34 VAR_B++; \ 35 ARG_MOVE = VAR_MOVE_NOMOD + VAR_MOD; \ 36 ARG_ACTION \ 37 } 38 39 STATIC bool 40 allowednextmove(uint8_t *moves, uint8_t n) 41 { 42 return n == 0 ? true : 43 allowednextmove_mask(moves, n-1) & (1 << moves[n-1]); 44 } 45 46 STATIC uint32_t 47 allowednextmove_mask(uint8_t *moves, uint8_t n) 48 { 49 uint32_t result; 50 uint8_t base1, base2, axis1, axis2; 51 52 result = MM_ALLMOVES; 53 54 if (n == 0) 55 return result; 56 57 base1 = movebase(moves[n-1]); 58 axis1 = moveaxis(moves[n-1]); 59 result = disable_moves(result, base1 * 3); 60 61 if (base1 % 2) 62 result = disable_moves(result, (base1 - 1) * 3); 63 64 if (n == 1) 65 return result; 66 67 base2 = movebase(moves[n-2]); 68 axis2 = moveaxis(moves[n-2]); 69 70 if(axis1 == axis2) 71 result = disable_moves(result, base2 * 3); 72 73 return result; 74 } 75 76 STATIC_INLINE uint32_t 77 disable_moves(uint32_t current_result, uint8_t base_index) 78 { 79 return current_result & ~(7 << base_index); 80 } 81 82 STATIC_INLINE uint8_t 83 movebase(uint8_t move) 84 { 85 return move / 3; 86 } 87 88 STATIC_INLINE uint8_t 89 moveaxis(uint8_t move) 90 { 91 return move / 6; 92 } 93 94 STATIC_INLINE uint8_t 95 moveopposite(uint8_t move) 96 { 97 return movebase(move) == 2 * moveaxis(move) ? move + 3 : move - 3; 98 } 99 100 STATIC cube_t 101 move(cube_t c, uint8_t m) 102 { 103 switch (m) { 104 case MOVE_U: 105 return MOVE(U, c); 106 case MOVE_U2: 107 return MOVE(U2, c); 108 case MOVE_U3: 109 return MOVE(U3, c); 110 case MOVE_D: 111 return MOVE(D, c); 112 case MOVE_D2: 113 return MOVE(D2, c); 114 case MOVE_D3: 115 return MOVE(D3, c); 116 case MOVE_R: 117 return MOVE(R, c); 118 case MOVE_R2: 119 return MOVE(R2, c); 120 case MOVE_R3: 121 return MOVE(R3, c); 122 case MOVE_L: 123 return MOVE(L, c); 124 case MOVE_L2: 125 return MOVE(L2, c); 126 case MOVE_L3: 127 return MOVE(L3, c); 128 case MOVE_F: 129 return MOVE(F, c); 130 case MOVE_F2: 131 return MOVE(F2, c); 132 case MOVE_F3: 133 return MOVE(F3, c); 134 case MOVE_B: 135 return MOVE(B, c); 136 case MOVE_B2: 137 return MOVE(B2, c); 138 case MOVE_B3: 139 return MOVE(B3, c); 140 default: 141 LOG("move error: unknown move %" PRIu8 "\n", m); 142 return ZERO_CUBE; 143 } 144 } 145 146 /* Applies the INVERSE of m BEFORE the scramble corresponding to c */ 147 STATIC cube_t 148 premove(cube_t c, uint8_t m) 149 { 150 switch (m) { 151 case MOVE_U: 152 return PREMOVE(U3, c); 153 case MOVE_U2: 154 return PREMOVE(U2, c); 155 case MOVE_U3: 156 return PREMOVE(U, c); 157 case MOVE_D: 158 return PREMOVE(D3, c); 159 case MOVE_D2: 160 return PREMOVE(D2, c); 161 case MOVE_D3: 162 return PREMOVE(D, c); 163 case MOVE_R: 164 return PREMOVE(R3, c); 165 case MOVE_R2: 166 return PREMOVE(R2, c); 167 case MOVE_R3: 168 return PREMOVE(R, c); 169 case MOVE_L: 170 return PREMOVE(L3, c); 171 case MOVE_L2: 172 return PREMOVE(L2, c); 173 case MOVE_L3: 174 return PREMOVE(L, c); 175 case MOVE_F: 176 return PREMOVE(F3, c); 177 case MOVE_F2: 178 return PREMOVE(F2, c); 179 case MOVE_F3: 180 return PREMOVE(F, c); 181 case MOVE_B: 182 return PREMOVE(B3, c); 183 case MOVE_B2: 184 return PREMOVE(B2, c); 185 case MOVE_B3: 186 return PREMOVE(B, c); 187 default: 188 LOG("premove error: unknown move %" PRIu8 "\n", m); 189 return ZERO_CUBE; 190 } 191 } 192 193 STATIC uint8_t 194 inverse_move(uint8_t m) 195 { 196 return m - 2 * (m % 3) + 2; 197 } 198 199 /* 200 GCC has issues when -Wstringop-overflow is used together with O3. It produces 201 warnings like the following: 202 203 In function 'invertmoves', 204 inlined from 'solve_h48_appendsolution' at src/solvers/h48/solve.h:81:3, 205 inlined from 'solve_h48_dfs.isra' at src/solvers/h48/solve.h:139:3: 206 warning: writing 32 bytes into a region of size 0 [-Wstringop-overflow=] 207 197 | ret[i] = inverse_move(moves[nmoves - i - 1]); 208 | ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 209 In function 'solve_h48_dfs.isra': 210 note: at offset 192 into destination object 'invertedpremoves' of size 20 211 71 | uint8_t invertedpremoves[MAXLEN]; 212 213 Clang does not give any warning. 214 Someone else complained here: https://access.redhat.com/solutions/6755371 215 216 To solve this issue temporarily, we use a lower optimization setting for 217 this function only. 218 219 TODO check if the issue is resolved 220 */ 221 #pragma GCC push_options 222 #pragma GCC optimize ("O2") 223 STATIC void 224 invertmoves(uint8_t *moves, uint8_t nmoves, uint8_t *ret) 225 { 226 uint8_t i; 227 228 for (i = 0; i < nmoves; i++) 229 ret[i] = inverse_move(moves[nmoves - i - 1]); 230 } 231 #pragma GCC pop_options 232 233 STATIC void 234 sortparallel(uint8_t *moves, uint8_t n) 235 { 236 uint8_t i; 237 238 for (i = 0; i < n-1; i++) 239 if (moveaxis(moves[i]) == moveaxis(moves[i+1]) && 240 movebase(moves[i]) == movebase(moves[i+1]) + 1) 241 SWAP(moves[i], moves[i+1]); 242 } 243 244 STATIC int 245 readmoves(const char *buf, int max, uint8_t *ret) 246 { 247 uint8_t m; 248 int c; 249 250 FOREACH_READMOVE(buf, m, c, max, NISSY_ERROR_INVALID_MOVES, 251 if (ret != NULL) 252 ret[c] = m; 253 ) 254 255 return c; 256 } 257 258 STATIC cube_t 259 applymoves(cube_t cube, const char *buf) 260 { 261 int c; 262 uint8_t m; 263 264 DBG_ASSERT(isconsistent(cube), ZERO_CUBE, 265 "move error: inconsistent cube\n"); 266 267 FOREACH_READMOVE(buf, m, c, -1, ZERO_CUBE, 268 cube = move(cube, m); 269 ) 270 271 return cube; 272 }