From f0d5cde50cc7a825acadbfe58b6046a4912f4814 Mon Sep 17 00:00:00 2001 From: tslil Date: Fri, 1 Jan 2021 11:45:12 -0500 Subject: tak.h now tracks win state, optimisations, saved a byte on counts --- include/tak.c | 59 +++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 24 deletions(-) (limited to 'include/tak.c') 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; -- cgit v1.3.1