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

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 }