#include "ptn.h" #define ASSERT_NONEMPTY { if (ptn == 0 || *ptn == 0) return PTN_INVALID; } #define ASSERT_MORE { if (*ptn == 0) return PTN_INVALID; } uint8_t likely_move(char *ptn) { if (ptn == 0) return 0; for (;;ptn++) { switch (*ptn) { case '+': case '-': case '>': case '<': return 1; case 0: return 0; } } } enum E_RESULT parse_place(const uint8_t board_size, char *ptn, uint8_t *out_location, enum STONE_VARIANT *out_stone) { if (board_size < 5 || board_size > 6) return PTN_INVALID; ASSERT_NONEMPTY; *out_stone = STONE_FLAT; switch (*ptn) { case 'C' : { ptn++; *out_stone = STONE_CAPSTONE; break; }; case 'S' : { ptn++; *out_stone = STONE_STANDING; break; }; case 'F' : { ptn++; break; }; } ASSERT_MORE; if ( (*ptn < 'a') || (*ptn > '`' + board_size) ) return PTN_INVALID; *out_location = *ptn - 'a'; ptn++; ASSERT_MORE; if ( (*ptn < '1') || (*ptn > board_size + '0') ) return PTN_INVALID; *out_location += board_size * (*ptn - '1'); if (*(++ptn) > 0) return PTN_INVALID; return PTN_VALID; } enum E_RESULT parse_move(const uint8_t board_size, char *ptn, uint8_t *out_location, enum MOVE_DIRECTION *out_direction, uint8_t *out_steps, uint8_t out_drops[5]) { if (board_size < 5 || board_size > 6) return PTN_INVALID; ASSERT_NONEMPTY; uint8_t picked_up = 1; if ( (*ptn >= '1') && (*ptn <= '0' + board_size)) { picked_up = *ptn - '0'; ptn++; ASSERT_MORE; } if ( (*ptn < 'a') || (*ptn > '`' + board_size) ) return PTN_INVALID; *out_location = *ptn - 'a'; ptn++; ASSERT_MORE; if ( (*ptn < '1') || (*ptn > board_size + '0') ) return PTN_INVALID; *out_location += board_size * (*ptn - '1'); ptn++; ASSERT_MORE; switch (*ptn) { case '+': { *out_direction = M_UP; break; } case '-': { *out_direction = M_DOWN; break; } case '<': { *out_direction = M_LEFT; break; } case '>': { *out_direction = M_RIGHT; break; } default: return PTN_INVALID; } ptn++; // Handle the case '[1]' as // '11' for convenience if (*ptn == 0) { if (picked_up == 1) { *out_steps = 1; out_drops[0] = 1; } else { return PTN_INVALID; } } *out_steps = 0; uint8_t total = 0; while (*ptn) { if ( (*ptn < '1') || (*ptn > '0' + board_size) ) { return PTN_INVALID; } if ( (*out_steps + 1 >= board_size) && *ptn) return PTN_INVALID; out_drops[*out_steps] = *ptn - '0'; total += out_drops[*out_steps]; *out_steps += 1; ptn++; } if ( total != picked_up ) return PTN_INVALID; return PTN_VALID; } void generate_place(const uint8_t board_size, const uint8_t in_location, const enum STONE_VARIANT in_stone, char out_ptn[4]) { switch (in_stone) { case STONE_FLAT: { break; } case STONE_STANDING: { *out_ptn = 'S'; out_ptn++; break; } case STONE_CAPSTONE: { *out_ptn = 'C'; out_ptn++; break; } } *out_ptn = 'a' + (in_location % board_size); out_ptn++; *out_ptn = '1' + (in_location / board_size); out_ptn++; *out_ptn = 0; } void generate_move(const uint8_t board_size, const uint8_t in_location, const enum MOVE_DIRECTION in_direction, const uint8_t in_steps, const uint8_t in_drops[5], char out_ptn[10]) { uint8_t total = 0; for (uint8_t k = 0; k 1) { *out_ptn = '0' + total; out_ptn++; } *out_ptn = 'a' + (in_location % board_size); out_ptn++; *out_ptn = '1' + (in_location / board_size); out_ptn++; switch (in_direction) { case M_UP: { *out_ptn = '+'; break; } case M_DOWN: { *out_ptn = '-'; break; } case M_LEFT: { *out_ptn = '<'; break; } case M_RIGHT: { *out_ptn = '>'; break; } }; out_ptn++; for (uint8_t k = 0; (total > 1) && (k < in_steps); k++) { *out_ptn = '0' + in_drops[k]; out_ptn++; } *out_ptn = 0; }