diff options
| author | tslil <tslil@posteo.de> | 2021-01-01 12:11:30 -0500 |
|---|---|---|
| committer | tslil <tslil@posteo.de> | 2026-08-28 19:37:41 +0100 |
| commit | a39287c8f7121ca0b6f4cbd173a64f0347a5c4a4 (patch) | |
| tree | c4bb45cf9eee9f26406fd41615beb3d6aadf361d | |
| parent | f0d5cde50cc7a825acadbfe58b6046a4912f4814 (diff) | |
In-lined a few things, reworked flat count to iterate only once
| -rw-r--r-- | include/tak.c | 137 |
1 files changed, 74 insertions, 63 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; - } - - 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++; + // can't drop more than the carry limit, or less than 1 + if ( (*ptn < '1') || (*ptn > '0' + board_size) ) + 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++; } + // 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; |
