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

io_cube.h (8251B)


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