summaryrefslogtreecommitdiff
path: root/include/tak.c
diff options
context:
space:
mode:
authortslil <tslil@posteo.de>2021-01-01 11:45:12 -0500
committertslil <tslil@posteo.de>2026-08-28 19:37:41 +0100
commitf0d5cde50cc7a825acadbfe58b6046a4912f4814 (patch)
treecaddafa40551bfa99c98d9931457aa4655352d06 /include/tak.c
parent604ea936443f86afd6df2af50cf73c930f687400 (diff)
tak.h now tracks win state, optimisations, saved a byte on counts
Diffstat (limited to 'include/tak.c')
-rw-r--r--include/tak.c59
1 files changed, 35 insertions, 24 deletions
diff --git a/include/tak.c b/include/tak.c
index e8bc846..d236b42 100644
--- a/include/tak.c
+++ b/include/tak.c
@@ -17,15 +17,16 @@ void
reset_state(const uint8_t new_board_size) {
if (new_board_size == 6) {
board_size = 6;
- white_flats = 30; black_flats = 30;
+ white_count = 128 | 30;
+ black_count = 128 | 30;
} else {
board_size = 5;
- white_flats = 21; black_flats = 21;
+ white_count = 128 | 21;
+ black_count = 128 | 21;
}
- white_caps = 1;
- black_caps = 1;
ply = 0;
+ won = -1;
current_colour = C_BLACK;
for (uint8_t k = 0; k < NUM_SQUARES; k++ ) {
@@ -51,6 +52,8 @@ enum E_RESULT
try_place(const int8_t location, const enum COLOUR colour,
const enum STONE_VARIANT stone)
{
+ // Game is over?
+ if (won < -1) return GAME_END;
// Can't place on an occupied square
if (COUNT_AT(location)) {
return ACT_ILLEGAL;
@@ -59,10 +62,10 @@ try_place(const int8_t location, const enum COLOUR colour,
case STONE_STANDING: if (ply < 2) return ACT_ILLEGAL;
case STONE_FLAT: {
if (colour == C_BLACK) {
- if (black_flats) black_flats--;
+ if (black_count & 127) black_count--;
else return ACT_ILLEGAL;
} else {
- if (white_flats) white_flats--;
+ if (white_count & 127) white_count--;
else return ACT_ILLEGAL;
}
break;
@@ -70,10 +73,10 @@ try_place(const int8_t location, const enum COLOUR colour,
case STONE_CAPSTONE: {
if (ply < 2) return ACT_ILLEGAL;
if (colour == C_BLACK) {
- if (black_caps) black_caps--;
+ if (black_count & 128) black_count &= 127;
else return ACT_ILLEGAL;
} else {
- if (white_caps) white_caps--;
+ if (white_count & 128) white_count &= 127;
else return ACT_ILLEGAL;
}
break;
@@ -107,11 +110,12 @@ drop_stones(const int8_t location, const uint8_t count) {
enum E_RESULT
try_move(const int8_t location, const enum MOVE_DIRECTION direction,
const uint8_t steps, const uint8_t drops[5]) {
+ // Game is over?
+ if (won < -1) return GAME_END;
// Can't do this
if (steps == 0 || steps > 5) return ACT_ILLEGAL;
-
- int8_t delta;
// Is the desired direction and count on the board?
+ int8_t delta = 0;
switch (direction) {
case M_UP: {
delta = +board_size;
@@ -128,7 +132,6 @@ try_move(const int8_t location, const enum MOVE_DIRECTION direction,
if (location + delta * steps > NUM_SQUARES) return ACT_ILLEGAL;
break;
};
- default: // Why do i need this to satisfy GCC?
case M_LEFT: {
delta = -1;
if (location + delta * steps < 0) return ACT_ILLEGAL;
@@ -166,7 +169,8 @@ try_move(const int8_t location, const enum MOVE_DIRECTION direction,
if ( (total > board_size) || (total > COUNT_AT(location)) )
return ACT_ILLEGAL;
- // Nothing illegal, do it
+ // Nothing illegal, do it. First we add the stones to the
+ // destination squares
uint8_t j = total;
for (uint8_t k = 0; k < steps; k++) {
j -= drops[k];
@@ -175,7 +179,7 @@ try_move(const int8_t location, const enum MOVE_DIRECTION direction,
(colours[location] >> j) & (0xFFFF >> (0x10 - drops[k])),
(k == steps - 1) ? STONE_AT(location) : STONE_FLAT);
}
-
+ // Then we drop them from the source
drop_stones(location, total);
return ACT_OK;
@@ -192,7 +196,9 @@ board_full(void) {
return 1;
}
-// direction == 0 --> left-to-right, direction == 1 --> bottom-to-top
+// Depth-first search of the board for a road with a given
+// directionality:
+// direction = 0 --> left-to-right, direction = 1 --> bottom-to-top
static uint8_t
dfs_road(uint8_t dfs_stack[NUM_SQUARES], uint8_t dfs_pntr,
const enum COLOUR colour, const uint8_t direction) {
@@ -207,8 +213,8 @@ dfs_road(uint8_t dfs_stack[NUM_SQUARES], uint8_t dfs_pntr,
// are inhabited, and are of the appropriate colour
// Direction: > (same row)
- if ( (cur + 1 < NUM_SQUARES) && ((cur + 1) % board_size > 0)
- && (COUNT_AT(cur + 1))
+ if ( ((cur % board_size) + 1 < board_size)
+ && (COUNT_AT(cur + 1)) // wont ever be out of bounds
&& ((colours[cur+1] & 1) == colour)
&& ((celldat[cur+1] & DFS_MASK) == 0) ) {
dfs_stack[dfs_pntr++] = cur + 1;
@@ -217,7 +223,7 @@ dfs_road(uint8_t dfs_stack[NUM_SQUARES], uint8_t dfs_pntr,
// Direction: < (same row)
if ( (cur % board_size > 0)
- && (COUNT_AT(cur - 1))
+ && (COUNT_AT(cur - 1)) // wont ever be out of bounds
&& ((colours[cur-1] & 1) == colour)
&& ((celldat[cur-1] & DFS_MASK) == 0) ) {
dfs_stack[dfs_pntr++] = cur - 1;
@@ -245,7 +251,7 @@ dfs_road(uint8_t dfs_stack[NUM_SQUARES], uint8_t dfs_pntr,
return 0;
}
-static enum E_RESULT
+static enum WIN_TYPE
check_road_colour(const enum COLOUR colour) {
uint8_t dfs_stack[NUM_SQUARES];
uint8_t dfs_pntr;
@@ -253,7 +259,7 @@ check_road_colour(const enum COLOUR colour) {
// Prime the depth-first-search stack with all boundary cells of
// colour COLOUR.
- const enum E_RESULT winner =
+ const enum WIN_TYPE winner =
(colour == C_BLACK) ? WIN_ROAD_BLACK : WIN_ROAD_WHITE;
// We're using the two left-over bits in data_t to track whether
@@ -288,13 +294,13 @@ check_road_colour(const enum COLOUR colour) {
}
if (dfs_road(dfs_stack, dfs_pntr, colour, 1)) return winner;
- return ACT_OK;
+ return -1;
}
-enum E_RESULT
+enum WIN_TYPE
check_win(void) {
// Do we do a flat count?
- if (black_flats == 0 || white_flats == 0 || board_full()) {
+ 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) {
@@ -312,7 +318,7 @@ check_win(void) {
// Road?
- enum E_RESULT rb, rw;
+ enum WIN_TYPE rb, rw;
rb = check_road_colour(C_BLACK);
rw = check_road_colour(C_WHITE);
@@ -498,6 +504,8 @@ is_not_placement(char *ptn) {
enum E_RESULT
do_ptn(char *ptn) {
+ if (won < -1) return GAME_END;
+
enum E_RESULT res;
uint8_t location;
@@ -520,7 +528,10 @@ do_ptn(char *ptn) {
if (res == ACT_OK) {
next_ply();
// Could be less conservative here :)
- if (ply > 2) return check_win();
+ if (ply > board_size) {
+ won = check_win();
+ if (won < -1) return GAME_END;
+ }
}
return res;