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 }