diff options
Diffstat (limited to 'src/arch/portable.h')
| -rw-r--r-- | src/arch/portable.h | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/src/arch/portable.h b/src/arch/portable.h new file mode 100644 index 0000000..b8330af --- /dev/null +++ b/src/arch/portable.h | |||
| @@ -0,0 +1,272 @@ | |||
| 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 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 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)) & _cobits2; | ||
| 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) & _cobits2; | ||
| 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; | ||
| 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; | ||
| 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; | ||
| 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)) & _cobits2; | ||
| 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] & _esepbit2) { | ||
| 193 | ret1 += binomial[11-i][k--]; | ||
| 194 | } else { | ||
| 195 | if (c.edge[i] & _esepbit1) | ||
| 196 | ret2 += binomial[7-j][l--]; | ||
| 197 | j++; | ||
| 198 | } | ||
| 199 | */ | ||
| 200 | |||
| 201 | bit1 = (c.edge[i] & _esepbit1) >> 2; | ||
| 202 | bit2 = (c.edge[i] & _esepbit2) >> 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 | int64_t bit1, bit2, i, j, jj, k, l, s, v, w, is1, set1, set2; | ||
| 247 | uint8_t slice[3] = {0}; | ||
| 248 | |||
| 249 | ret = solved; | ||
| 250 | set1 = esep % 70; | ||
| 251 | set2 = esep / 70; | ||
| 252 | |||
| 253 | for (i = 0, j = 0, k = 4, l = 4; i < 12; i++) { | ||
| 254 | v = binomial[11-i][k]; | ||
| 255 | jj = j < 8; | ||
| 256 | w = jj * binomial[7-(j*jj)][l]; | ||
| 257 | bit2 = set2 >= v; | ||
| 258 | bit1 = set1 >= w; | ||
| 259 | is1 = (1 - bit2) * bit1; | ||
| 260 | |||
| 261 | set2 -= bit2 * v; | ||
| 262 | k -= bit2; | ||
| 263 | set1 -= is1 * w; | ||
| 264 | l -= is1; | ||
| 265 | j += (1-bit2); | ||
| 266 | s = 2*bit2 + (1-bit2)*bit1; | ||
| 267 | |||
| 268 | ret.edge[i] = (slice[s]++) | (uint8_t)(s << 2); | ||
| 269 | } | ||
| 270 | |||
| 271 | return ret; | ||
| 272 | } | ||
