aboutsummaryrefslogtreecommitdiff
path: root/include/tps.c
diff options
context:
space:
mode:
Diffstat (limited to 'include/tps.c')
-rw-r--r--include/tps.c351
1 files changed, 201 insertions, 150 deletions
diff --git a/include/tps.c b/include/tps.c
index 7be0e8d..ad0fe21 100644
--- a/include/tps.c
+++ b/include/tps.c
@@ -4,134 +4,166 @@
// Load TPS string
// ===================================================================
-#define TPS_ASSERT_MORE { if (*tps == 0) return TPS_INVALID; }
+#define TPS_ASSERT_MORE \
+ { \
+ if (*tps == 0) \
+ return TPS_INVALID; \
+ }
-enum TPS_RESULT
-load_tps(char* tps) {
+enum TPS_RESULT load_tps(tak_state_p state, char *tps) {
// TODO: Ensure NULL termination?
- if (tps == NULL) return TPS_INVALID;
+ if (tps == NULL)
+ return TPS_INVALID;
uint8_t prefix = 0;
// Check if we're likely of the form [TPS "blah"]
if (!strncmp(tps, "[TPS \"", 6)) {
- prefix=1;
+ prefix = 1;
// Now we can worry about just the TPS part
tps += 6;
}
// Reset everything
- reset_state(board_size);
+ reset_state(state, state->board_size);
// Parse squares, NOTE: We assume that board_size matches TPS size.
- int col = 0, row = board_size-1, skip, parsing = 1;
+ int col = 0, row = state->board_size - 1, skip, parsing = 1;
while (parsing) {
switch (*tps) {
- case ' ': {
- // we're done
- parsing = 0;
- tps++; TPS_ASSERT_MORE;
- break;
- }
- case 'x': {
- // empty squares
- tps++; TPS_ASSERT_MORE;
- skip = 0;
- if (*tps >= '2' && *tps <= '0'+board_size) {
- skip = *tps - '1';
- tps++; TPS_ASSERT_MORE;
- } else if (*tps != ',' && *tps != '/' && *tps != ' ') {
- return TPS_INVALID;
- }
- col += skip;
- if (col >= board_size + 1) return TPS_INVALID;
- break;
- }
- case '/': {
- // next row
- if (col + 1 != board_size) return TPS_INVALID;
- row--; col = 0;
- if (row < 0) return TPS_INVALID;
- tps++; TPS_ASSERT_MORE;
- break;
- }
- case ',': {
- // next column
- col++;
- if (col >= board_size) return TPS_INVALID;
- tps++; TPS_ASSERT_MORE;
- break;
+ case ' ': {
+ // we're done
+ parsing = 0;
+ tps++;
+ TPS_ASSERT_MORE;
+ break;
+ }
+ case 'x': {
+ // empty squares
+ tps++;
+ TPS_ASSERT_MORE;
+ skip = 0;
+ if (*tps >= '2' && *tps <= '0' + state->board_size) {
+ skip = *tps - '1';
+ tps++;
+ TPS_ASSERT_MORE;
+ } else if (*tps != ',' && *tps != '/' && *tps != ' ') {
+ return TPS_INVALID;
}
- default: {
- const int l = THE_COORDS(col, row);
- uint8_t num_read = 0, reading = 1;
- // Read in a stack of colours, optionally terminated by an S
- // or C to change the top stone type
- while (reading) {
- switch (*tps) {
- // Reading a stone colour
- case '2': {
- // check next letter to make sure we have the material
- tps++; TPS_ASSERT_MORE;
- if (*tps == 'C') {
- if (black_count & 128) black_count &= 127;
- else return TPS_INVALID;
- } else if (black_count & 127) {
- black_count--;
- } else return TPS_INVALID;
- colours[l] <<= 1;
- celldat[l] += NUM_INC;
- colours[l] |= 1;
- num_read++;
- break;
- }
- case '1': {
- tps++; TPS_ASSERT_MORE;
- if (*tps == 'C') {
- if (white_count & 128) white_count &= 127;
- else return TPS_INVALID;
- } else if (white_count & 127) {
- white_count--;
- } else return TPS_INVALID;
- colours[l] <<= 1;
- celldat[l] += NUM_INC;
- num_read++;
- break;
- }
- case 'S': {
- // Have we already read a stone type?
- if (STONE_AT(l) != STONE_FLAT) return TPS_INVALID;
- celldat[l] |= STONE_STANDING;
- tps++; TPS_ASSERT_MORE;
- break;
- }
- case 'C': {
- if (STONE_AT(l) != STONE_FLAT) return TPS_INVALID;
- celldat[l] |= STONE_CAPSTONE;
- tps++; TPS_ASSERT_MORE;
- break;
- }
- case ',': // fall-through
- case '/': {
- // done here
- reading=0;
- break;
- }
- default: return TPS_INVALID;
- }
- if (num_read > 0xF) return TPS_INVALID;
- }
+ col += skip;
+ if (col >= state->board_size + 1)
+ return TPS_INVALID;
+ break;
+ }
+ case '/': {
+ // next row
+ if (col + 1 != state->board_size)
+ return TPS_INVALID;
+ row--;
+ col = 0;
+ if (row < 0)
+ return TPS_INVALID;
+ tps++;
+ TPS_ASSERT_MORE;
+ break;
+ }
+ case ',': {
+ // next column
+ col++;
+ if (col >= state->board_size)
+ return TPS_INVALID;
+ tps++;
+ TPS_ASSERT_MORE;
+ break;
+ }
+ default: {
+ const int l = THE_COORDS(state->board_size, col, row);
+ uint8_t num_read = 0, reading = 1;
+ // Read in a stack of colours, optionally terminated by an S
+ // or C to change the top stone type
+ while (reading) {
+ switch (*tps) {
+ // Reading a stone colour
+ case '2': {
+ // check next letter to make sure we have the material
+ tps++;
+ TPS_ASSERT_MORE;
+ if (*tps == 'C') {
+ if (state->black_count & 128)
+ state->black_count &= 127;
+ else
+ return TPS_INVALID;
+ } else if (state->black_count & 127) {
+ state->black_count--;
+ } else
+ return TPS_INVALID;
+ state->colours[l] <<= 1;
+ state->celldat[l] += NUM_INC;
+ state->colours[l] |= 1;
+ num_read++;
+ break;
+ }
+ case '1': {
+ tps++;
+ TPS_ASSERT_MORE;
+ if (*tps == 'C') {
+ if (state->white_count & 128)
+ state->white_count &= 127;
+ else
+ return TPS_INVALID;
+ } else if (state->white_count & 127) {
+ state->white_count--;
+ } else
+ return TPS_INVALID;
+ state->colours[l] <<= 1;
+ state->celldat[l] += NUM_INC;
+ num_read++;
+ break;
+ }
+ case 'S': {
+ // Have we already read a stone type?
+ if (STONE_AT(state, l) != STONE_FLAT)
+ return TPS_INVALID;
+ state->celldat[l] |= STONE_STANDING;
+ tps++;
+ TPS_ASSERT_MORE;
+ break;
+ }
+ case 'C': {
+ if (STONE_AT(state, l) != STONE_FLAT)
+ return TPS_INVALID;
+ state->celldat[l] |= STONE_CAPSTONE;
+ tps++;
+ TPS_ASSERT_MORE;
+ break;
+ }
+ case ',': // fall-through
+ case '/': {
+ // done here
+ reading = 0;
+ break;
+ }
+ default:
+ return TPS_INVALID;
+ }
+ if (num_read > 0xF)
+ return TPS_INVALID;
}
}
+ }
}
// Now it's time to parse the ply number. First, the active player
- if (*tps != '1' && *tps != '2') return TPS_INVALID;
- ply += *tps - '1';
- tps++; TPS_ASSERT_MORE;
+ if (*tps != '1' && *tps != '2')
+ return TPS_INVALID;
+ state->ply += *tps - '1';
+ tps++;
+ TPS_ASSERT_MORE;
// Space
- if (*tps != ' ') return TPS_INVALID;
- tps++; TPS_ASSERT_MORE;
+ if (*tps != ' ')
+ return TPS_INVALID;
+ tps++;
+ TPS_ASSERT_MORE;
// Turn number, atoi doesn't detect errors so let's do it ourselves
uint8_t p = 0;
@@ -139,21 +171,27 @@ load_tps(char* tps) {
p *= 10;
if (*tps >= '0' && *tps <= '9') {
p += *tps - '0';
- } else return TPS_INVALID;
+ } else
+ return TPS_INVALID;
tps++;
- } while ( (prefix && *tps && *tps != '"') || (!prefix && *tps) );
- if (p == 0) return TPS_INVALID;
- ply += 2*(p - 1);
+ } while ((prefix && *tps && *tps != '"') || (!prefix && *tps));
+ if (p == 0)
+ return TPS_INVALID;
+ state->ply += 2 * (p - 1);
- current_colour = (ply & 1) ? C_BLACK : C_WHITE;
- if (ply < 2) current_colour = C_BLACK - current_colour;
+ state->current_colour = (state->ply & 1) ? C_BLACK : C_WHITE;
+ if (state->ply < 2)
+ state->current_colour = C_BLACK - state->current_colour;
if (prefix) {
- tps++; TPS_ASSERT_MORE;
- if (*tps != ']' ) return TPS_INVALID;
+ tps++;
+ TPS_ASSERT_MORE;
+ if (*tps != ']')
+ return TPS_INVALID;
tps++;
- if (*tps != 0) return TPS_INVALID;
+ if (*tps != 0)
+ return TPS_INVALID;
}
return TPS_OK;
@@ -163,55 +201,68 @@ load_tps(char* tps) {
// Generate TPS string
// ===================================================================
-void
-generate_tps(char *out_tps) {
+void generate_tps(tak_state_p state, char *out_tps) {
strcpy(out_tps, "[TPS \"");
out_tps += 6;
- for (int8_t row = board_size - 1; row >= 0; row--) {
- for (int8_t col = 0; col < board_size; col++) {
- const int8_t l = THE_COORDS(col, row);
- const uint8_t count = COUNT_AT(l);
+ for (int8_t row = state->board_size - 1; row >= 0; row--) {
+ for (int8_t col = 0; col < state->board_size; col++) {
+ const int8_t l = THE_COORDS(state->board_size, col, row);
+ const uint8_t count = COUNT_AT(state, l);
if (count) {
- colour_stack_t c = colours[l], s = 1<<(count - 1);
- for (int k=0; k<count; k++, s >>=1, out_tps++) {
- if (c & s) *out_tps = '2';
- else *out_tps = '1';
- }
- switch (STONE_AT(l)) {
- case STONE_CAPSTONE: {
- *out_tps = 'C'; out_tps++; break;
- }
- case STONE_STANDING: {
- *out_tps = 'S'; out_tps++; break;
- }
- default: break;
- }
+ colour_stack_t c = state->colours[l], s = 1 << (count - 1);
+ for (int k = 0; k < count; k++, s >>= 1, out_tps++) {
+ if (c & s)
+ *out_tps = '2';
+ else
+ *out_tps = '1';
+ }
+ switch (STONE_AT(state, l)) {
+ case STONE_CAPSTONE: {
+ *out_tps = 'C';
+ out_tps++;
+ break;
+ }
+ case STONE_STANDING: {
+ *out_tps = 'S';
+ out_tps++;
+ break;
+ }
+ default:
+ break;
+ }
} else {
- int8_t skip = 1;
- while (col < board_size && COUNT_AT(l+skip) == 0) {
- skip++;
- col++;
- }
- *out_tps = 'x'; out_tps++;
- if (skip > 1) {
- *out_tps = '0'+skip; out_tps++;
- }
+ int8_t skip = 1;
+ while (col < state->board_size && COUNT_AT(state, l + skip) == 0) {
+ skip++;
+ col++;
+ }
+ *out_tps = 'x';
+ out_tps++;
+ if (skip > 1) {
+ *out_tps = '0' + skip;
+ out_tps++;
+ }
}
- if (col + 1 < board_size) {
- *out_tps = ','; out_tps++;
+ if (col + 1 < state->board_size) {
+ *out_tps = ',';
+ out_tps++;
}
}
if (row > 0) {
- *out_tps = '/'; out_tps++;
+ *out_tps = '/';
+ out_tps++;
}
}
- *out_tps = ' '; out_tps++;
- *out_tps = '1' + (ply & 1); out_tps++;
- *out_tps = ' '; out_tps++;
+ *out_tps = ' ';
+ out_tps++;
+ *out_tps = '1' + (state->ply & 1);
+ out_tps++;
+ *out_tps = ' ';
+ out_tps++;
- out_tps += sprintf(out_tps, "%d", ply/2 + 1);
+ out_tps += sprintf(out_tps, "%d", state->ply / 2 + 1);
strcpy(out_tps, "\"]");
}