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


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