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_moves.h (2436B)


      1 STATIC uint8_t readmove(char);
      2 STATIC int64_t readmoves(const char *, size_t n, uint8_t [n]);
      3 STATIC int64_t countmoves(const char *);
      4 STATIC uint8_t readmodifier(char);
      5 STATIC int64_t writemoves(size_t n, const uint8_t [n], size_t m, char [m]);
      6 
      7 #define FOREACH_READMOVE(ARG_BUF, ARG_MOVE, ARG_C, ARG_MAX, \
      8 	RET_ERROR, ARG_ACTION) \
      9 	const char *VAR_B; \
     10 	uint8_t VAR_MOVE_NOMOD, VAR_MOD; \
     11 	for (VAR_B = ARG_BUF, ARG_C = 0; *VAR_B != '\0'; VAR_B++, ARG_C++) { \
     12 		while (*VAR_B == ' ' || *VAR_B == '\t' || *VAR_B == '\n') \
     13 			VAR_B++; \
     14 		if (*VAR_B == '\0' || ARG_C == ARG_MAX) \
     15 			break; \
     16 		if ((VAR_MOVE_NOMOD = readmove(*VAR_B)) == UINT8_ERROR) { \
     17 			LOG("Error: unknown move '%c'\n", *VAR_B); \
     18 			return RET_ERROR; \
     19 		} \
     20 		if ((VAR_MOD = readmodifier(*(VAR_B+1))) != 0) \
     21 			VAR_B++; \
     22 		ARG_MOVE = VAR_MOVE_NOMOD + VAR_MOD; \
     23 		ARG_ACTION \
     24 	}
     25 
     26 STATIC uint8_t
     27 readmove(char c)
     28 {
     29 	switch (c) {
     30 	case 'U':
     31 		return MOVE_U;
     32 	case 'D':
     33 		return MOVE_D;
     34 	case 'R':
     35 		return MOVE_R;
     36 	case 'L':
     37 		return MOVE_L;
     38 	case 'F':
     39 		return MOVE_F;
     40 	case 'B':
     41 		return MOVE_B;
     42 	default:
     43 		return UINT8_ERROR;
     44 	}
     45 }
     46 
     47 STATIC uint8_t
     48 readmodifier(char c)
     49 {
     50 	switch (c) {
     51 	case '1': /* Fallthrough */
     52 	case '2': /* Fallthrough */
     53 	case '3':
     54 		return c - '0' - 1;
     55 	case '\'':
     56 		return 2;
     57 	default:
     58 		return 0;
     59 	}
     60 }
     61 
     62 STATIC int64_t
     63 readmoves(const char *buf, size_t n, uint8_t ret[n])
     64 {
     65 	uint8_t m;
     66 	uint64_t c;
     67 
     68 	FOREACH_READMOVE(buf, m, c, n, NISSY_ERROR_INVALID_MOVES,
     69 		ret[c] = m;
     70 	)
     71 
     72 	return (int64_t)c;
     73 }
     74 
     75 STATIC int64_t
     76 countmoves(const char *buf)
     77 {
     78 	uint8_t m;
     79 	uint64_t c;
     80 
     81 	FOREACH_READMOVE(buf, m, c, INT_MAX, NISSY_ERROR_INVALID_MOVES,
     82 		{}
     83 	)
     84 
     85 	(void)m; /* Ignore "variable set but not used" warning */
     86 
     87 	return (int64_t)c;
     88 }
     89 
     90 STATIC int64_t
     91 writemoves(
     92 	size_t nmoves,
     93 	const uint8_t m[nmoves],
     94 	size_t buf_size,
     95 	char buf[buf_size]
     96 )
     97 {
     98 	size_t i, len, w;
     99 	const char *s;
    100 
    101 	if (buf_size == 0) {
    102 		LOG("Error: cannot write moves to buffer of size 0.\n");
    103 		return NISSY_ERROR_BUFFER_SIZE;
    104 	}
    105 
    106 	for (i = 0, w = 0; i < nmoves; i++, w++) {
    107 		s = movestr[m[i]];
    108 		len = strlen(s);
    109 		if (len + w >= buf_size) {
    110 			LOG("Error: the given buffer is too small for "
    111 			     "writing the given moves.\n");
    112 			goto writemoves_error;
    113 		}
    114 		memcpy(buf+w, s, len);
    115 		w += len;
    116 		buf[w] = ' ';
    117 	}
    118 
    119 	if (w > 0) w--; /* Remove last space */
    120 	buf[w] = '\0';
    121 
    122 	return (int64_t)w;
    123 
    124 writemoves_error:
    125 	*buf = '\0';
    126 	return NISSY_ERROR_BUFFER_SIZE;
    127 }