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 (7953B)


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