portable.h (8155B)
1 #define STATIC_CUBE(c_ufr, c_ubl, c_dfl, c_dbr, c_ufl, c_ubr, c_dfr, c_dbl, \ 2 e_uf, e_ub, e_db, e_df, e_ur, e_ul, e_dl, e_dr, e_fr, e_fl, e_bl, e_br) \ 3 ((cube_t) { \ 4 .corner = { c_ufr, c_ubl, c_dfl, c_dbr, c_ufl, c_ubr, c_dfr, c_dbl }, \ 5 .edge = { e_uf, e_ub, e_db, e_df, e_ur, e_ul, \ 6 e_dl, e_dr, e_fr, e_fl, e_bl, e_br } }) 7 #define ZERO_CUBE STATIC_CUBE( \ 8 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 9 #define SOLVED_CUBE STATIC_CUBE( \ 10 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) 11 12 STATIC_INLINE int 13 popcount_u32(uint32_t x) 14 { 15 /* 16 Bit trick: accumulate in pairs of bits, quads of bits and so on, 17 until the final result is the sum of all bits. 18 19 x = (x & 0x55555555) + ((x >> 1) & 0x55555555); 20 x = (x & 0x33333333) + ((x >> 2) & 0x33333333); 21 x = (x & 0x0F0F0F0F) + ((x >> 4) & 0x0F0F0F0F); 22 x = (x & 0x00FF00FF) + ((x >> 8) & 0x00FF00FF); 23 x = (x & 0x0000FFFF) + ((x >> 16) & 0x0000FFFF); 24 25 The actual method we use is a small optimization of the one above. 26 */ 27 28 x -= (x >> UINT32_C(1)) & UINT32_C(0x55555555); 29 x = (x & UINT32_C(0x33333333)) + 30 ((x >> UINT32_C(2)) & UINT32_C(0x33333333)); 31 x = (x + (x >> UINT32_C(4))) & UINT32_C(0x0F0F0F0F); 32 x = (x * UINT32_C(0x01010101)) >> UINT32_C(24); 33 34 return (int)x; 35 } 36 37 STATIC_INLINE int 38 popcount_u64(uint64_t x) 39 { 40 int top, bottom; 41 42 bottom = popcount_u32((uint32_t)(x & UINT64_C(0xFFFFFFFF))); 43 top = popcount_u32((uint32_t)(x >> UINT64_C(32))); 44 45 return top + bottom; 46 } 47 48 STATIC void 49 pieces(cube_t cube[NON_NULL], uint8_t c[SIZE(8)], uint8_t e[SIZE(12)]) 50 { 51 memcpy(c, cube->corner, 8); 52 memcpy(e, cube->edge, 12); 53 } 54 55 STATIC_INLINE bool 56 equal(cube_t c1, cube_t c2) 57 { 58 uint8_t i; 59 bool ret; 60 61 ret = true; 62 for (i = 0; i < 8; i++) 63 ret = ret && c1.corner[i] == c2.corner[i]; 64 for (i = 0; i < 12; i++) 65 ret = ret && c1.edge[i] == c2.edge[i]; 66 67 return ret; 68 } 69 70 STATIC_INLINE cube_t 71 invertco(cube_t c) 72 { 73 uint8_t i, piece, orien; 74 cube_t ret; 75 76 ret = c; 77 for (i = 0; i < 8; i++) { 78 piece = c.corner[i]; 79 orien = ((piece << 1) | (piece >> 1)) & COBITS_2; 80 ret.corner[i] = (piece & PBITS) | orien; 81 } 82 83 return ret; 84 } 85 86 STATIC_INLINE void 87 compose_edges_inplace(cube_t c1, cube_t c2, cube_t *ret) 88 { 89 uint8_t i, piece1, piece2, p, orien; 90 91 for (i = 0; i < 12; i++) { 92 piece2 = c2.edge[i]; 93 p = piece2 & PBITS; 94 piece1 = c1.edge[p]; 95 orien = (piece2 ^ piece1) & EOBIT; 96 ret->edge[i] = (piece1 & PBITS) | orien; 97 } 98 } 99 100 STATIC_INLINE void 101 compose_corners_inplace(cube_t c1, cube_t c2, cube_t *ret) 102 { 103 uint8_t i, piece1, piece2, p, orien, aux, auy; 104 105 for (i = 0; i < 8; i++) { 106 piece2 = c2.corner[i]; 107 p = piece2 & PBITS; 108 piece1 = c1.corner[p]; 109 aux = (piece2 & COBITS) + (piece1 & COBITS); 110 auy = (aux + CTWIST_CW) >> 2; 111 orien = (aux + auy) & COBITS_2; 112 ret->corner[i] = (piece1 & PBITS) | orien; 113 } 114 } 115 116 STATIC_INLINE cube_t 117 compose_edges(cube_t c1, cube_t c2) 118 { 119 cube_t ret = ZERO_CUBE; 120 121 compose_edges_inplace(c1, c2, &ret); 122 123 return ret; 124 } 125 126 STATIC_INLINE cube_t 127 compose_corners(cube_t c1, cube_t c2) 128 { 129 cube_t ret = ZERO_CUBE; 130 131 compose_corners_inplace(c1, c2, &ret); 132 133 return ret; 134 } 135 136 STATIC_INLINE cube_t 137 compose(cube_t c1, cube_t c2) 138 { 139 cube_t ret = ZERO_CUBE; 140 141 compose_edges_inplace(c1, c2, &ret); 142 compose_corners_inplace(c1, c2, &ret); 143 144 return ret; 145 } 146 147 cube_t 148 inverse(cube_t cube) 149 { 150 uint8_t i, piece, orien; 151 cube_t ret; 152 153 for (i = 0; i < 12; i++) { 154 piece = cube.edge[i]; 155 orien = piece & EOBIT; 156 ret.edge[piece & PBITS] = i | orien; 157 } 158 159 for (i = 0; i < 8; i++) { 160 piece = cube.corner[i]; 161 orien = ((piece << 1) | (piece >> 1)) & COBITS_2; 162 ret.corner[piece & PBITS] = i | orien; 163 } 164 165 return ret; 166 } 167 168 STATIC_INLINE void 169 copy_co(cube_t cube[NON_NULL], cube_t co) 170 { 171 uint8_t c; 172 size_t i; 173 174 for (i = 0; i < 8; i++) { 175 c = cube->corner[i] & COBITS; 176 cube->corner[i] ^= c; 177 cube->corner[i] |= co.corner[i] & COBITS; 178 } 179 } 180 181 STATIC_INLINE uint64_t 182 coord_co(cube_t c) 183 { 184 int i, p, ret; 185 186 for (ret = 0, i = 0, p = 1; i < 7; i++, p *= 3) 187 ret += p * (c.corner[i] >> COSHIFT); 188 189 return ret; 190 } 191 192 STATIC_INLINE cube_t 193 invcoord_co(uint64_t coord) 194 { 195 uint64_t i, c, p; 196 cube_t cube; 197 198 cube = SOLVED_CUBE; 199 for (i = 0, p = 0, c = coord; i < 7; i++, c /= 3) { 200 p += c % 3; 201 cube.corner[i] |= (c % 3) << COSHIFT; 202 } 203 204 cube.corner[7] |= ((3 - (p % 3)) % 3) << COSHIFT; 205 206 return cube; 207 } 208 209 /* 210 For corner separation, we consider the axis (a.k.a. tetrad) each 211 corner belongs to as 0 or 1 and we translate this sequence into binary. 212 Ignoring the last bit, we have a value up to 2^7, but not all values are 213 possible. Encoding this as a number from 0 to C(8,4) would save about 40% 214 of space, but we are not going to use this coordinate in large tables. 215 */ 216 STATIC_INLINE uint64_t 217 coord_csep(cube_t c) 218 { 219 int i, p; 220 uint64_t ret; 221 222 for (ret = 0, i = 0, p = 1; i < 7; i++, p *= 2) 223 ret += p * ((c.corner[i] & CSEPBIT) >> 2); 224 225 return ret; 226 } 227 228 STATIC_INLINE uint64_t 229 coord_cocsep(cube_t c) 230 { 231 return (coord_co(c) << 7) + coord_csep(c); 232 } 233 234 STATIC_INLINE uint64_t 235 coord_eo(cube_t c) 236 { 237 int i, p; 238 uint64_t ret; 239 240 for (ret = 0, i = 1, p = 1; i < 12; i++, p *= 2) 241 ret += p * (c.edge[i] >> EOSHIFT); 242 243 return ret; 244 } 245 246 /* 247 We encode the edge separation as a number from 0 to C(12,4)*C(8,4). 248 It can be seen as the composition of two "subset index" coordinates. 249 */ 250 STATIC_INLINE uint64_t 251 coord_esep(cube_t c) 252 { 253 uint64_t i, j, jj, k, l, ret1, ret2, bit1, bit2, is1; 254 255 for (i = 0, j = 0, k = 4, l = 4, ret1 = 0, ret2 = 0; i < 12; i++) { 256 /* Simple version: 257 if (c.edge[i] & ESEPBIT_2) { 258 ret1 += binomial[11-i][k--]; 259 } else { 260 if (c.edge[i] & ESEPBIT_1) 261 ret2 += binomial[7-j][l--]; 262 j++; 263 } 264 */ 265 266 bit1 = (c.edge[i] & ESEPBIT_1) >> 2; 267 bit2 = (c.edge[i] & ESEPBIT_2) >> 3; 268 is1 = (1 - bit2) * bit1; 269 270 ret1 += bit2 * binomial[11-i][k]; 271 k -= bit2; 272 273 jj = j < 8; 274 ret2 += jj * is1 * binomial[7-(j*jj)][l]; 275 l -= is1; 276 j += (1-bit2); 277 } 278 279 return ret1 * 70 + ret2; 280 } 281 282 STATIC_INLINE cube_t 283 invcoord_esep(uint64_t esep) 284 { 285 cube_t ret; 286 287 ret = SOLVED_CUBE; 288 invcoord_esep_array(esep % 70, esep / 70, ret.edge); 289 290 return ret; 291 } 292 293 STATIC_INLINE void 294 copy_corners(cube_t dest[NON_NULL], cube_t src) 295 { 296 memcpy(&dest->corner, src.corner, sizeof(src.corner)); 297 } 298 299 STATIC_INLINE void 300 copy_edges(cube_t dest[NON_NULL], cube_t src) 301 { 302 memcpy(&dest->edge, src.edge, sizeof(src.edge)); 303 } 304 305 STATIC_INLINE void 306 set_eo(cube_t cube[NON_NULL], uint64_t eo) 307 { 308 uint8_t i, sum, flip; 309 310 for (sum = 0, i = 1; i < 12; i++, eo >>= 1) { 311 flip = eo % 2; 312 sum += flip; 313 cube->edge[i] = (cube->edge[i] & ~EOBIT) | (EOBIT * flip); 314 } 315 cube->edge[0] = (cube->edge[0] & ~EOBIT) | (EOBIT * (sum % 2)); 316 } 317 318 STATIC_INLINE uint64_t 319 coord_cp(cube_t cube) 320 { 321 int i; 322 323 for (i = 0; i < 8; i++) 324 cube.corner[i] &= PBITS; 325 326 return permtoindex(8, cube.corner); 327 } 328 329 STATIC_INLINE cube_t 330 invcoord_cp(uint64_t i) 331 { 332 uint8_t c[8]; 333 334 indextoperm(i, 8, c); 335 336 return STATIC_CUBE(c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7], 337 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11); 338 } 339 340 STATIC_INLINE uint64_t 341 coord_epud(cube_t cube) 342 { 343 int i; 344 345 for (i = 0; i < 8; i++) 346 cube.edge[i] &= PBITS; 347 348 return permtoindex(8, cube.edge); 349 } 350 351 STATIC_INLINE cube_t 352 invcoord_epud(uint64_t i) 353 { 354 uint8_t e[8]; 355 356 indextoperm(i, 8, e); 357 358 return STATIC_CUBE(0, 1, 2, 3, 4, 5, 6, 7, 359 e[0], e[1], e[2], e[3], e[4], e[5], e[6], e[7], 8, 9, 10, 11); 360 } 361 362 STATIC_INLINE uint64_t 363 coord_epe(cube_t cube) 364 { 365 int i; 366 367 for (i = 8; i < 12; i++) 368 cube.edge[i] = (cube.edge[i] & PBITS) - 8; 369 370 return permtoindex(4, cube.edge+8); 371 } 372 373 STATIC_INLINE cube_t 374 invcoord_epe(uint64_t i) 375 { 376 uint8_t e[4]; 377 378 indextoperm(i, 4, e); 379 380 return STATIC_CUBE(0, 1, 2, 3, 4, 5, 6, 7, 381 0, 1, 2, 3, 4, 5, 6, 7, e[0]+8, e[1]+8, e[2]+8, e[3]+8); 382 } 383 384 STATIC_INLINE bool 385 is_eo_even(cube_t cube) 386 { 387 uint8_t i, count; 388 389 for (i = 0, count = 0; i < 12; i++) 390 count += (cube.edge[i] & EOBIT) >> EOSHIFT; 391 392 return count % 2 == 0; 393 } 394 395 STATIC_INLINE uint64_t 396 coord_epudsep(cube_t cube) 397 { 398 return coord_epudsep_array(cube.edge); 399 } 400 401 STATIC_INLINE cube_t 402 invcoord_epudsep(uint64_t c) 403 { 404 cube_t ret; 405 406 ret = SOLVED_CUBE; 407 invcoord_epudsep_array(c, ret.edge); 408 return ret; 409 }