aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/tak.c133
1 files changed, 72 insertions, 61 deletions
diff --git a/include/tak.c b/include/tak.c
index d236b42..3a8dff4 100644
--- a/include/tak.c
+++ b/include/tak.c
@@ -1,7 +1,8 @@
#include "tak.h"
-// -------------------------------------------------------------------
+// ===================================================================
// Helpers
+// ===================================================================
#define NUM_INC (0x1<<NUM_SHIFT) // 0b00010000
#define NUM_MASK (0xF<<NUM_SHIFT) // 0b11110000
@@ -10,8 +11,9 @@
#define NUM_SQUARES (board_size * board_size)
-// -------------------------------------------------------------------
+// ===================================================================
// General state stuff
+// ===================================================================
void
reset_state(const uint8_t new_board_size) {
@@ -26,7 +28,7 @@ reset_state(const uint8_t new_board_size) {
}
ply = 0;
- won = -1;
+ won = -1; // i may live to regret this hack
current_colour = C_BLACK;
for (uint8_t k = 0; k < NUM_SQUARES; k++ ) {
@@ -45,8 +47,9 @@ next_ply(void) {
}
}
-// -------------------------------------------------------------------
-// Place stone
+// ===================================================================
+// Placing stones
+// ===================================================================
enum E_RESULT
try_place(const int8_t location, const enum COLOUR colour,
@@ -89,8 +92,9 @@ try_place(const int8_t location, const enum COLOUR colour,
}
}
-// -------------------------------------------------------------------
-// Move stack
+// ===================================================================
+// Moving stacks
+// ===================================================================
static void
push_stones(const int8_t location, const uint8_t count, const uint8_t new_colours,
@@ -99,14 +103,6 @@ push_stones(const int8_t location, const uint8_t count, const uint8_t new_colour
celldat[location] = ((celldat[location] + ((count << NUM_SHIFT))) & NUM_MASK) | top_stone;
}
-static void
-drop_stones(const int8_t location, const uint8_t count) {
- // Calling this with count = 0 is destructive
- colours[location] >>= count;
- const uint8_t dec_count = celldat[location] - (count << NUM_SHIFT);
- celldat[location] = dec_count & NUM_MASK;
-}
-
enum E_RESULT
try_move(const int8_t location, const enum MOVE_DIRECTION direction,
const uint8_t steps, const uint8_t drops[5]) {
@@ -165,8 +161,9 @@ try_move(const int8_t location, const enum MOVE_DIRECTION direction,
total += drops[k];
}
- // Can't ask to move more than BOARD_SIZE or stones available
- if ( (total > board_size) || (total > COUNT_AT(location)) )
+ // Can't ask to move 0, more than board_size, or stones available
+ if ( (total == 0) || (total > board_size)
+ || (total > COUNT_AT(location)) )
return ACT_ILLEGAL;
// Nothing illegal, do it. First we add the stones to the
@@ -180,21 +177,16 @@ try_move(const int8_t location, const enum MOVE_DIRECTION direction,
(k == steps - 1) ? STONE_AT(location) : STONE_FLAT);
}
// Then we drop them from the source
- drop_stones(location, total);
+ colours[location] >>= total;
+ const uint8_t dec_count = celldat[location] - (total << NUM_SHIFT);
+ celldat[location] = dec_count & NUM_MASK;
return ACT_OK;
}
-// -------------------------------------------------------------------
-// Win conditions
-
-static uint8_t
-board_full(void) {
- for (uint8_t k = 0; k < NUM_SQUARES; k++) {
- if (COUNT_AT(k) == 0) return 0;
- }
- return 1;
-}
+// ===================================================================
+// Checking win
+// ===================================================================
// Depth-first search of the board for a road with a given
// directionality:
@@ -299,25 +291,25 @@ check_road_colour(const enum COLOUR colour) {
enum WIN_TYPE
check_win(void) {
+
+ int8_t total = 0, board_full = 1;
+ for (uint8_t k = 0; k < NUM_SQUARES; k++) {
+ if (COUNT_AT(k) == 0) {
+ board_full = 0;
+ } else if (STONE_AT(k) == STONE_FLAT) {
+ total += ((colours[k] & 1) == C_BLACK) ? +1 : -1 ;
+ }
+ }
+
// Do we do a flat count?
- if ((black_count & 127) == 0 || (white_count & 127) == 0 || board_full()) {
- int8_t total = 0;
- for (uint8_t k = 0; k < NUM_SQUARES; k++) {
- if (STONE_AT(k) == STONE_FLAT) {
- total += ((colours[k] & 1) == C_BLACK) ? +1 : -1 ;
- }
- }
- if (total > 0) {
- return WIN_FLAT_BLACK;
- } else if (total < 0) {
- return WIN_FLAT_WHITE;
- } else {
- return WIN_DRAW;
- }
+ if (black_count == 0 || white_count == 0 || board_full) {
+ // Decide based on count
+ if (total > 0) return WIN_FLAT_BLACK;
+ else if (total < 0) return WIN_FLAT_WHITE;
+ else return WIN_DRAW;
}
// Road?
-
enum WIN_TYPE rb, rw;
rb = check_road_colour(C_BLACK);
rw = check_road_colour(C_WHITE);
@@ -332,9 +324,9 @@ check_win(void) {
return rw;
}
}
-
-// -------------------------------------------------------------------
+// ===================================================================
// PTN place parser
+// ===================================================================
#define ASSERT_NONEMPTY { if (ptn == 0 || *ptn == 0) return PTN_INVALID; }
#define ASSERT_MORE { if (*ptn == 0) return PTN_INVALID; }
@@ -369,8 +361,9 @@ parse_place(const uint8_t board_size, char *ptn,
return PTN_VALID;
}
-// -------------------------------------------------------------------
+// ===================================================================
// PTN move parser
+// ===================================================================
enum E_RESULT
parse_move(const uint8_t board_size, char *ptn,
@@ -383,21 +376,25 @@ parse_move(const uint8_t board_size, char *ptn,
uint8_t picked_up = 1;
+ // Optionally indicate how many stones picked up
if ( (*ptn >= '1') && (*ptn <= '0' + board_size)) {
picked_up = *ptn - '0';
ptn++; ASSERT_MORE;
}
+ // column must be on the board
if ( (*ptn < 'a') || (*ptn > '`' + board_size) ) return PTN_INVALID;
*out_location = *ptn - 'a';
ptn++; ASSERT_MORE;
+ // row must be on the board
if ( (*ptn < '1') || (*ptn > board_size + '0') ) return PTN_INVALID;
*out_location += board_size * (*ptn - '1');
ptn++; ASSERT_MORE;
+ // valid direction
switch (*ptn) {
case '+': { *out_direction = M_UP; break; }
case '-': { *out_direction = M_DOWN; break; }
@@ -406,38 +403,43 @@ parse_move(const uint8_t board_size, char *ptn,
default: return PTN_INVALID;
}
- ptn++;
// Handle the case 'n<column><row><direction>' as
// 'n<column><row><direction>n' for convenience, if n is omitted
// assume n = 1
+ ptn++;
if (*ptn == 0) {
*out_steps = picked_up;
out_drops[0] = picked_up;
return PTN_VALID;
}
+ // Parse the drops in each subsequent square
*out_steps = 0;
uint8_t total = 0;
while (*ptn) {
- if ( (*ptn < '1') || (*ptn > '0' + board_size) ) {
- return PTN_INVALID;
- }
+ // can't drop more than the carry limit, or less than 1
+ if ( (*ptn < '1') || (*ptn > '0' + board_size) )
+ return PTN_INVALID;
- if ( (*out_steps + 1 >= board_size) && *ptn) return PTN_INVALID;
+ // can't move more than the size of the board in any direction
+ 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++;
+ out_drops[*out_steps] = *ptn - '0';
+ total += out_drops[*out_steps];
+ *out_steps += 1;
+ ptn++;
}
+ // Mismatch between number of stones picked up and total dropped
if ( total != picked_up ) return PTN_INVALID;
return PTN_VALID;
}
-// -------------------------------------------------------------------
+// ===================================================================
// Generate PTN for place
+// ===================================================================
void
generate_place(const uint8_t board_size, const uint8_t in_location,
@@ -452,8 +454,9 @@ generate_place(const uint8_t board_size, const uint8_t in_location,
*out_ptn = 0;
}
-// -------------------------------------------------------------------
+// ===================================================================
// Generate PTN for move
+// ===================================================================
void
generate_move(const uint8_t board_size, const uint8_t in_location,
@@ -484,8 +487,9 @@ generate_move(const uint8_t board_size, const uint8_t in_location,
*out_ptn = 0;
}
-// -------------------------------------------------------------------
+// ===================================================================
// Driver
+// ===================================================================
static uint8_t
is_not_placement(char *ptn) {
@@ -503,31 +507,38 @@ is_not_placement(char *ptn) {
enum E_RESULT
do_ptn(char *ptn) {
-
+ // Game over?
if (won < -1) return GAME_END;
enum E_RESULT res;
uint8_t location;
+ // Placing or moving?
if (is_not_placement(ptn)) {
uint8_t steps, drops[5];
enum MOVE_DIRECTION direction;
+ // Parse it as a move
res = parse_move(board_size, ptn, &location,
&direction, &steps, drops);
+ // If valid PTN, try to do it
if (res == PTN_VALID) {
if (ply < 2) return ACT_ILLEGAL;
res = try_move(location, direction, steps, drops);
}
} else {
+ // It was not a move
enum STONE_VARIANT stone;
+ // Was it a valid placement?
res = parse_place(board_size, ptn, &location, &stone);
+ // If so, try it
if (res == PTN_VALID)
res = try_place(location, current_colour, stone);
}
-
+ // A valid ply occured
if (res == ACT_OK) {
next_ply();
- // Could be less conservative here :)
+ // Don't bother checking that the game was won early on, could be
+ // more conservative here :)
if (ply > board_size) {
won = check_win();
if (won < -1) return GAME_END;