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