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

convert.c (8428B)


      1 /*
      2 This file contains code related to cube format conversion that used to
      3 be in src/core.  It is to be adapted into a standalone tool for cube
      4 format conversion.
      5 */
      6 
      7 STATIC cube_t readcube(const char *, const char *);
      8 STATIC int64_t writecube(const char *, cube_t, size_t n, char [n]);
      9 STATIC void log_available_formats(void);
     10 STATIC uint8_t readco(const char *);
     11 STATIC uint8_t readcp(const char *);
     12 STATIC uint8_t readeo(const char *);
     13 STATIC uint8_t readep(const char *);
     14 STATIC cube_t readcube_B32(const char *);
     15 STATIC cube_t readcube_H48(const char *);
     16 STATIC uint8_t readpiece_LST(const char **);
     17 STATIC cube_t readcube_LST(const char *);
     18 
     19 STATIC int64_t writepiece_LST(uint8_t, size_t n, char [n]);
     20 STATIC int64_t writecube_B32(cube_t, size_t n, char [n]);
     21 STATIC int64_t writecube_H48(cube_t, size_t n, char [n]);
     22 STATIC int64_t writecube_LST(cube_t, size_t n, char [n]);
     23 
     24 STATIC uint8_t b32toedge(char);
     25 STATIC uint8_t b32tocorner(char);
     26 STATIC char edgetob32(uint8_t);
     27 STATIC char cornertob32(uint8_t);
     28 
     29 STATIC struct {
     30 	const char *name;
     31 	cube_t (*read)(const char *);
     32 	int64_t (*write)(cube_t, size_t n, char [n]);
     33 } ioformat[] =
     34 {
     35 	{ .name = "B32", .read = readcube_B32, .write = writecube_B32 },
     36 	{ .name = "LST", .read = readcube_LST, .write = writecube_LST },
     37 	{ .name = "H48", .read = readcube_H48, .write = writecube_H48 },
     38 	{ .name = "NONE", .read = NULL, .write = NULL },
     39 };
     40 
     41 STATIC cube_t
     42 readcube(const char *format, const char *buf)
     43 {
     44 	int i;
     45 
     46 	for (i = 0; ioformat[i].read != NULL; i++)
     47 		if (!strcmp(format, ioformat[i].name))
     48 			return ioformat[i].read(buf);
     49 
     50 	LOG("Cannot read cube: unknown format '%s'\n", format);
     51 	log_available_formats();
     52 	return ZERO_CUBE;
     53 }
     54 
     55 STATIC int64_t
     56 writecube(const char *format, cube_t cube, size_t buf_size, char buf[buf_size])
     57 {
     58 	int i;
     59 
     60 	for (i = 0; ioformat[i].write != NULL; i++)
     61 		if (!strcmp(format, ioformat[i].name))
     62 			return ioformat[i].write(cube, buf_size, buf);
     63 
     64 	LOG("Cannot write cube: unknown format '%s'\n", format);
     65 	log_available_formats();
     66 	return NISSY_ERROR_INVALID_FORMAT;
     67 }
     68 
     69 STATIC void
     70 log_available_formats(void)
     71 {
     72 	int i;
     73 
     74 	LOG("Available formats: ");
     75 	for (i = 0; ioformat[i].read != NULL; i++)
     76 		LOG("'%s' ", ioformat[i].name);
     77 	LOG("\n");
     78 }
     79 
     80 STATIC uint8_t
     81 readco(const char *str)
     82 {
     83 	if (*str == '0')
     84 		return 0;
     85 	if (*str == '1')
     86 		return CTWIST_CW;
     87 	if (*str == '2')
     88 		return CTWIST_CCW;
     89 
     90 	LOG("Error reading CO\n");
     91 	return UINT8_ERROR;
     92 }
     93 
     94 STATIC uint8_t
     95 readcp(const char *str)
     96 {
     97 	uint8_t c;
     98 
     99 	for (c = 0; c < 8; c++)
    100 		if (!strncmp(str, cornerstr[c], 3) ||
    101 		    !strncmp(str, cornerstralt[c], 3))
    102 			return c;
    103 
    104 	LOG("Error reading CP\n");
    105 	return UINT8_ERROR;
    106 }
    107 
    108 STATIC uint8_t
    109 readeo(const char *str)
    110 {
    111 	if (*str == '0')
    112 		return 0;
    113 	if (*str == '1')
    114 		return EFLIP;
    115 
    116 	LOG("Error reading EO\n");
    117 	return UINT8_ERROR;
    118 }
    119 
    120 STATIC uint8_t
    121 readep(const char *str)
    122 {
    123 	uint8_t e;
    124 
    125 	for (e = 0; e < 12; e++)
    126 		if (!strncmp(str, edgestr[e], 2))
    127 			return e;
    128 
    129 	LOG("Error reading EP\n");
    130 	return UINT8_ERROR;
    131 }
    132 
    133 STATIC cube_t
    134 readcube_B32(const char *buf)
    135 {
    136 	int i;
    137 	uint8_t c[8], e[12];
    138 
    139 	for (i = 0; i < 8; i++) {
    140 		c[i] = b32tocorner(buf[i]);
    141 		if (c[i] == UINT8_ERROR) {
    142 			LOG("Error reading B32 corner %d ", i);
    143 			if (buf[i] == 0) {
    144 				LOG("(string terminated early)\n");
    145 			} else {
    146 				LOG("(char '%c')\n", buf[i]);
    147 			}
    148 			return ZERO_CUBE;
    149 		}
    150 	}
    151 
    152 	if (buf[8] != '=') {
    153 		LOG("Error reading B32 separator: a single '=' "
    154 		    "must be used to separate edges and corners\n");
    155 		return ZERO_CUBE;
    156 	}
    157 
    158 	for (i = 0; i < 12; i++) {
    159 		e[i] = b32toedge(buf[i+9]);
    160 		if (e[i] == UINT8_ERROR) {
    161 			LOG("Error reading B32 edge %d ", i);
    162 			if (buf[i+9] == 0) {
    163 				LOG("(string terminated early)\n");
    164 			} else {
    165 				LOG("(char '%c')\n", buf[i+9]);
    166 			}
    167 			return ZERO_CUBE;
    168 		}
    169 	}
    170 
    171 	return cubefromarray(c, e);
    172 }
    173 
    174 STATIC cube_t
    175 readcube_H48(const char *buf)
    176 {
    177 	int i;
    178 	uint8_t piece, orient, c[8], e[12];
    179 	const char *b;
    180 	
    181 	b = buf;
    182 
    183 	for (i = 0; i < 12; i++) {
    184 		while (*b == ' ' || *b == '\t' || *b == '\n')
    185 			b++;
    186 		if ((piece = readep(b)) == UINT8_ERROR)
    187 			return ZERO_CUBE;
    188 		b += 2;
    189 		if ((orient = readeo(b)) == UINT8_ERROR)
    190 			return ZERO_CUBE;
    191 		b++;
    192 		e[i] = piece | orient;
    193 	}
    194 	for (i = 0; i < 8; i++) {
    195 		while (*b == ' ' || *b == '\t' || *b == '\n')
    196 			b++;
    197 		if ((piece = readcp(b)) == UINT8_ERROR)
    198 			return ZERO_CUBE;
    199 		b += 3;
    200 		if ((orient = readco(b)) == UINT8_ERROR)
    201 			return ZERO_CUBE;
    202 		b++;
    203 		c[i] = piece | orient;
    204 	}
    205 
    206 	return cubefromarray(c, e);
    207 }
    208 
    209 STATIC uint8_t
    210 readpiece_LST(const char **b)
    211 {
    212 	uint8_t ret;
    213 	bool read;
    214 
    215 	while (**b == ',' || **b == ' ' || **b == '\t' || **b == '\n')
    216 		(*b)++;
    217 
    218 	for (ret = 0, read = false; **b >= '0' && **b <= '9'; (*b)++) {
    219 		read = true;
    220 		ret = ret * 10 + (**b) - '0';
    221 	}
    222 
    223 	return read ? ret : UINT8_ERROR;
    224 }
    225 
    226 STATIC cube_t
    227 readcube_LST(const char *buf)
    228 {
    229 	int i;
    230 	uint8_t c[8], e[12];
    231 
    232 	for (i = 0; i < 8; i++)
    233 		c[i] = readpiece_LST(&buf);
    234 
    235 	for (i = 0; i < 12; i++)
    236 		e[i] = readpiece_LST(&buf);
    237 
    238 	return cubefromarray(c, e);
    239 }
    240 
    241 STATIC int64_t
    242 writepiece_LST(uint8_t piece, size_t buf_size, char buf[buf_size])
    243 {
    244 	char digits[3];
    245 	size_t i, len;
    246 
    247 	if (piece > 99 || buf_size < 3)
    248 		return 0;
    249 
    250 	len = 0;
    251 	while (piece != 0) {
    252 		digits[len++] = (piece % 10) + '0';
    253 		piece /= 10;
    254 	}
    255 
    256 	if (buf_size < len+2)
    257 		return 0;
    258 
    259 	if (len == 0)
    260 		digits[len++] = '0';
    261 
    262 	for (i = 0; i < len; i++)
    263 		buf[i] = digits[len-i-1];
    264 
    265 	buf[len] = ',';
    266 	buf[len+1] = ' ';
    267 
    268 	return len+2;
    269 }
    270 
    271 STATIC int64_t
    272 writecube_B32(cube_t cube, size_t buf_size, char buf[buf_size])
    273 {
    274 	int i;
    275 	uint8_t corner[8], edge[12];
    276 
    277 	if (buf_size < NISSY_SIZE_B32) {
    278 		LOG("Cannot write cube in B32 format: buffer size must be at "
    279 		    "least %u bytes, but the provided one is %zu bytes.\n",
    280 		    NISSY_SIZE_B32, buf_size);
    281 		return NISSY_ERROR_BUFFER_SIZE;
    282 	}
    283 
    284 	pieces(&cube, corner, edge);
    285 
    286 	for (i = 0; i < 8; i++)
    287 		buf[i] = cornertob32(corner[i]);
    288 
    289 	buf[8] = '=';
    290 
    291 	for (i = 0; i < 12; i++)
    292 		buf[i+9] = edgetob32(edge[i]);
    293 
    294 	buf[21] = '\0';
    295 
    296 	return NISSY_OK;
    297 }
    298 
    299 STATIC int64_t
    300 writecube_H48(cube_t cube, size_t buf_size, char buf[buf_size])
    301 {
    302 	uint8_t piece, perm, orient, corner[8], edge[12];
    303 	int i;
    304 
    305 	if (buf_size < NISSY_SIZE_H48) {
    306 		LOG("Cannot write cube in H48 format: buffer size must be "
    307 		    "at least %u bytes, but the provided one is %zu bytes.\n",
    308 		    NISSY_SIZE_H48, buf_size);
    309 		return NISSY_ERROR_BUFFER_SIZE;
    310 	}
    311 
    312 	pieces(&cube, corner, edge);
    313 
    314 	for (i = 0; i < 12; i++) {
    315 		piece = edge[i];
    316 		perm = piece & PBITS;
    317 		orient = (piece & EOBIT) >> EOSHIFT;
    318 		buf[4*i    ] = edgestr[perm][0];
    319 		buf[4*i + 1] = edgestr[perm][1];
    320 		buf[4*i + 2] = orient + '0';
    321 		buf[4*i + 3] = ' ';
    322 	}
    323 	for (i = 0; i < 8; i++) {
    324 		piece = corner[i];
    325 		perm = piece & PBITS;
    326 		orient = (piece & COBITS) >> COSHIFT;
    327 		buf[48 + 5*i    ] = cornerstr[perm][0];
    328 		buf[48 + 5*i + 1] = cornerstr[perm][1];
    329 		buf[48 + 5*i + 2] = cornerstr[perm][2];
    330 		buf[48 + 5*i + 3] = orient + '0';
    331 		buf[48 + 5*i + 4] = ' ';
    332 	}
    333 
    334 	buf[48+39] = '\0';
    335 
    336 	return NISSY_OK;
    337 }
    338 
    339 STATIC int64_t
    340 writecube_LST(cube_t cube, size_t buf_size, char buf[buf_size])
    341 {
    342 	int i;
    343 	uint64_t ptr;
    344 	uint8_t piece, corner[8], edge[12];
    345 
    346 	ptr = 0;
    347 	pieces(&cube, corner, edge);
    348 
    349 	for (i = 0; i < 8; i++) {
    350 		piece = corner[i];
    351 		ptr += writepiece_LST(piece, buf_size - ptr, buf + ptr);
    352 		if (ptr == 0)
    353 			goto writecube_LST_error;
    354 	}
    355 
    356 	for (i = 0; i < 12; i++) {
    357 		piece = edge[i];
    358 		ptr += writepiece_LST(piece, buf_size - ptr, buf + ptr);
    359 		if (ptr == 0)
    360 			goto writecube_LST_error;
    361 	}
    362 
    363 	*(buf+ptr-2) = '\0';
    364 
    365 	return NISSY_OK;
    366 
    367 writecube_LST_error:
    368 	LOG("Cannot write cube in LST: buffer is too small (%" PRIu64
    369 	    " bytes given). The LST format has a variable size, try a "
    370 	    "larger buffer.\n", buf_size);
    371 	return NISSY_ERROR_BUFFER_SIZE;
    372 }
    373 
    374 STATIC uint8_t
    375 b32toedge(char c)
    376 {
    377 	if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'f')))
    378 		return UINT8_ERROR;
    379 
    380 	return c <= 'Z' ? (uint8_t)(c - 'A') : (uint8_t)(c - 'a') + 26;
    381 }
    382 
    383 STATIC uint8_t
    384 b32tocorner(char c) {
    385 	uint8_t val;
    386 
    387 	if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'f')))
    388 		return UINT8_ERROR;
    389 
    390 	val = c <= 'Z' ? (uint8_t)(c - 'A') : (uint8_t)(c - 'a') + 26;
    391 
    392 	return (val & 7) | ((val & 24) << 2);
    393 }
    394 
    395 STATIC char
    396 edgetob32(uint8_t edge)
    397 {
    398 	return edge < 26 ? 'A' + (char)edge : 'a' + (char)(edge - 26);
    399 }
    400 
    401 STATIC char
    402 cornertob32(uint8_t corner)
    403 {
    404 	uint8_t val;
    405 
    406 	val = (corner & 7) | ((corner & 96) >> 2);
    407 
    408 	return val < 26 ? 'A' + (char)val : 'a' + (char)(val - 26);
    409 }