h48

A prototype for an optimal Rubik's cube solver, work in progress.
git clone https://git.tronto.net/h48
Download | Log | Files | Refs | README | LICENSE

portable.h (5293B)


      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 /* TODO: optimize this (use bit tricks?) */
     13 STATIC_INLINE int
     14 popcount_u32(uint32_t x)
     15 {
     16 	int ret;
     17 
     18 	for (ret = 0; x != 0; x >>= 1)
     19 		ret += x & 1;
     20 
     21 	return ret;
     22 }
     23 
     24 STATIC void
     25 pieces(cube_t *cube, uint8_t c[static 8], uint8_t e[static 12])
     26 {
     27 	memcpy(c, cube->corner, 8);
     28 	memcpy(e, cube->edge, 12);
     29 }
     30 
     31 STATIC_INLINE bool
     32 equal(cube_t c1, cube_t c2)
     33 {
     34 	uint8_t i;
     35 	bool ret;
     36 
     37 	ret = true;
     38 	for (i = 0; i < 8; i++)
     39 		ret = ret && c1.corner[i] == c2.corner[i];
     40 	for (i = 0; i < 12; i++)
     41 		ret = ret && c1.edge[i] == c2.edge[i];
     42 
     43 	return ret;
     44 }
     45 
     46 STATIC_INLINE cube_t
     47 invertco(cube_t c)
     48 {
     49 	uint8_t i, piece, orien;
     50 	cube_t ret;
     51 
     52 	ret = c;
     53 	for (i = 0; i < 8; i++) {
     54 		piece = c.corner[i];
     55 		orien = ((piece << 1) | (piece >> 1)) & COBITS_2;
     56 		ret.corner[i] = (piece & PBITS) | orien;
     57 	}
     58 
     59 	return ret;
     60 }
     61 
     62 STATIC_INLINE void
     63 compose_edges_inplace(cube_t c1, cube_t c2, cube_t *ret)
     64 {
     65 	uint8_t i, piece1, piece2, p, orien;
     66 
     67 	for (i = 0; i < 12; i++) {
     68 		piece2 = c2.edge[i];
     69 		p = piece2 & PBITS;
     70 		piece1 = c1.edge[p];
     71 		orien = (piece2 ^ piece1) & EOBIT;
     72 		ret->edge[i] = (piece1 & PBITS) | orien;
     73 	}
     74 }
     75 
     76 STATIC_INLINE void
     77 compose_corners_inplace(cube_t c1, cube_t c2, cube_t *ret)
     78 {
     79 	uint8_t i, piece1, piece2, p, orien, aux, auy;
     80 
     81 	for (i = 0; i < 8; i++) {
     82 		piece2 = c2.corner[i];
     83 		p = piece2 & PBITS;
     84 		piece1 = c1.corner[p];
     85 		aux = (piece2 & COBITS) + (piece1 & COBITS);
     86 		auy = (aux + CTWIST_CW) >> 2;
     87 		orien = (aux + auy) & COBITS_2;
     88 		ret->corner[i] = (piece1 & PBITS) | orien;
     89 	}
     90 }
     91 
     92 STATIC_INLINE cube_t
     93 compose_edges(cube_t c1, cube_t c2)
     94 {
     95 	cube_t ret = ZERO_CUBE;
     96 
     97 	compose_edges_inplace(c1, c2, &ret);
     98 
     99 	return ret;
    100 }
    101 
    102 STATIC_INLINE cube_t
    103 compose_corners(cube_t c1, cube_t c2)
    104 {
    105 	cube_t ret = ZERO_CUBE;
    106 
    107 	compose_corners_inplace(c1, c2, &ret);
    108 
    109 	return ret;
    110 }
    111 
    112 STATIC_INLINE cube_t
    113 compose(cube_t c1, cube_t c2)
    114 {
    115 	cube_t ret = ZERO_CUBE;
    116 
    117 	compose_edges_inplace(c1, c2, &ret);
    118 	compose_corners_inplace(c1, c2, &ret);
    119 
    120 	return ret;
    121 }
    122 
    123 cube_t
    124 inverse(cube_t cube)
    125 {
    126 	uint8_t i, piece, orien;
    127 	cube_t ret;
    128 
    129 	for (i = 0; i < 12; i++) {
    130 		piece = cube.edge[i];
    131 		orien = piece & EOBIT;
    132 		ret.edge[piece & PBITS] = i | orien;
    133 	}
    134 
    135 	for (i = 0; i < 8; i++) {
    136 		piece = cube.corner[i];
    137 		orien = ((piece << 1) | (piece >> 1)) & COBITS_2;
    138 		ret.corner[piece & PBITS] = i | orien;
    139 	}
    140 
    141 	return ret;
    142 }
    143 
    144 STATIC_INLINE int64_t
    145 coord_co(cube_t c)
    146 {
    147 	int i, p;
    148 	int64_t ret;
    149 
    150 	for (ret = 0, i = 0, p = 1; i < 7; i++, p *= 3)
    151 		ret += p * (c.corner[i] >> COSHIFT);
    152 
    153 	return ret;
    154 }
    155 
    156 /*
    157 For corner separation, we consider the axis (a.k.a. tetrad) each
    158 corner belongs to as 0 or 1 and we translate this sequence into binary.
    159 Ignoring the last bit, we have a value up to 2^7, but not all values are
    160 possible. Encoding this as a number from 0 to C(8,4) would save about 40%
    161 of space, but we are not going to use this coordinate in large tables.
    162 */
    163 STATIC_INLINE int64_t
    164 coord_csep(cube_t c)
    165 {
    166 	int i, p;
    167 	int64_t ret;
    168 
    169 	for (ret = 0, i = 0, p = 1; i < 7; i++, p *= 2)
    170 		ret += p * ((c.corner[i] & CSEPBIT) >> 2);
    171 
    172 	return ret;
    173 }
    174 
    175 STATIC_INLINE int64_t
    176 coord_cocsep(cube_t c)
    177 {
    178 	return (coord_co(c) << 7) + coord_csep(c);
    179 }
    180 
    181 STATIC_INLINE int64_t
    182 coord_eo(cube_t c)
    183 {
    184 	int i, p;
    185 	int64_t ret;
    186 
    187 	for (ret = 0, i = 1, p = 1; i < 12; i++, p *= 2)
    188 		ret += p * (c.edge[i] >> EOSHIFT);
    189 
    190 	return ret;
    191 }
    192 
    193 /*
    194 We encode the edge separation as a number from 0 to C(12,4)*C(8,4).
    195 It can be seen as the composition of two "subset index" coordinates.
    196 */
    197 STATIC_INLINE int64_t
    198 coord_esep(cube_t c)
    199 {
    200 	int64_t i, j, jj, k, l, ret1, ret2, bit1, bit2, is1;
    201 
    202 	for (i = 0, j = 0, k = 4, l = 4, ret1 = 0, ret2 = 0; i < 12; i++) {
    203 		/* Simple version:
    204 		if (c.edge[i] & ESEPBIT_2) {
    205 			ret1 += binomial[11-i][k--];
    206 		} else {
    207 			if (c.edge[i] & ESEPBIT_1)
    208 				ret2 += binomial[7-j][l--];
    209 			j++;
    210 		}
    211 		*/
    212 
    213 		bit1 = (c.edge[i] & ESEPBIT_1) >> 2;
    214 		bit2 = (c.edge[i] & ESEPBIT_2) >> 3;
    215 		is1 = (1 - bit2) * bit1;
    216 
    217 		ret1 += bit2 * binomial[11-i][k];
    218 		k -= bit2;
    219 
    220 		jj = j < 8;
    221 		ret2 += jj * is1 * binomial[7-(j*jj)][l];
    222 		l -= is1;
    223 		j += (1-bit2);
    224 	}
    225 
    226 	return ret1 * 70 + ret2;
    227 }
    228 
    229 STATIC_INLINE void
    230 copy_corners(cube_t *dest, cube_t src)
    231 {
    232 	memcpy(&dest->corner, src.corner, sizeof(src.corner));
    233 }
    234 
    235 STATIC_INLINE void
    236 copy_edges(cube_t *dest, cube_t src)
    237 {
    238 	memcpy(&dest->edge, src.edge, sizeof(src.edge));
    239 }
    240 
    241 STATIC_INLINE void
    242 set_eo(cube_t *cube, int64_t eo)
    243 {
    244 	uint8_t i, sum, flip;
    245 
    246 	for (sum = 0, i = 1; i < 12; i++, eo >>= 1) {
    247 		flip = eo % 2;
    248 		sum += flip;
    249 		cube->edge[i] = (cube->edge[i] & ~EOBIT) | (EOBIT * flip);
    250 	}
    251 	cube->edge[0] = (cube->edge[0] & ~EOBIT) | (EOBIT * (sum % 2));
    252 }
    253 
    254 STATIC_INLINE cube_t
    255 invcoord_esep(int64_t esep)
    256 {
    257 	cube_t ret;
    258 
    259 	ret = SOLVED_CUBE;
    260 	invcoord_esep_array(esep % 70, esep / 70, ret.edge);
    261 
    262 	return ret;
    263 }