tictactoe

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

commit be1fb705d3a882cb48e650355d4cba5352c45604
parent 7d8009aecfd298c86419f3e99249f9f08bc90e83
Author: Wilson Gheen <wilson@wilsonrgheen.com>
Date:   Sun, 18 Dec 2022 06:14:40 -0600

Fix up get_winner...() to detect moves that win for either player; add "AI" that blocks if it can't win this turn

Diffstat:
Mtictactoe.c | 6+++---
Mtictactoe.h | 53+++++++++++++++++++++++++++++++++++++++++++++--------
Munit_test.c | 1+
3 files changed, 49 insertions(+), 11 deletions(-)

diff --git a/tictactoe.c b/tictactoe.c @@ -6,20 +6,20 @@ #include "../life/print_box.h" #include "tictactoe.h" -#define SIDE_BY_SIDE 0 +#define SIDE_BY_SIDE 1 static void print_board_offset(char *board, int offx, int offy, int clear) { +#ifndef NO_PRINT_BOARD if(clear) tb_clear(); print_box_offset(7, 7, offx, offy, 0); for(int i=0; i < 9; i++) { print_bw(((i%3) * 2) + 2 + offx, (i/3*2) + 2 + offy, board[i]); } tb_present(); +#endif } static void print_board(char *board) { -#ifndef UNIT_TEST print_board_offset(board, 0, 0, 1); -#endif } char play(char (*get_move)(char*, char)) { diff --git a/tictactoe.h b/tictactoe.h @@ -11,6 +11,7 @@ #define O_WINS_ROW " XXXOXOOO" #define scase(s1, s2) if (!strcmp(s1, s2)) +/*#define NO_PRINT_BOARD*/ /*typedef void (*board_fn)(char *, char);*/ static char the_desired_board[32]; @@ -26,6 +27,7 @@ static int get_rand(int max_excl) { char get_winner_or_winning_moves(char *b, char *winning_moves) { char center = b[4]; _Bool add_to_wm = 0; + /* Check status of squares on either side of center: row, column and diagonal */ for(int i=-4; i < 0; i++) { int sq1 = 4+i; int sq3 = 4-i; @@ -37,18 +39,21 @@ char get_winner_or_winning_moves(char *b, char *winning_moves) { } if(winning_moves == NULL) continue; if(add_to_wm) { - winning_moves[i] = b[sq1]; + /* Normally means `w...[4] = b[s...]`, but allows us + * to detect later on if it is a winning move for both */ + winning_moves[4] |= b[sq1]; add_to_wm = 0; } else if(center == ' ') continue; else if((b[sq1] == center) ^ (b[sq3] == center)) { if(b[sq1] == ' ') - winning_moves[sq1] = center; + winning_moves[sq1] |= center; else if(b[sq3] == ' ') - winning_moves[sq3] = center; + winning_moves[sq3] |= center; } } for(int i=1; i <= 7; i+=2){ + /* i&4 -> side column, else upper or lower row */ int distance = ((i+1) & 4) ? 3 : 1; int sq1 = i - distance; int sq3 = i + distance; @@ -60,15 +65,15 @@ char get_winner_or_winning_moves(char *b, char *winning_moves) { } if(winning_moves == NULL) continue; if(add_to_wm) { - winning_moves[i] = b[sq1]; + winning_moves[i] |= b[sq1]; add_to_wm = 0; } else if(b[i] == ' ') continue; else if((b[sq1] == b[i]) ^ (b[sq3] == b[i])) { if(b[sq1] == ' ') - winning_moves[sq1] = b[i]; + winning_moves[sq1] |= b[i]; else if(b[sq3] == ' ') - winning_moves[sq3] = b[i]; + winning_moves[sq3] |= b[i]; } } return 0; @@ -101,6 +106,13 @@ char get_move_preset_board(char *board, char player) { } return 0; } +char get_these_moves(char *board, char player) { + /* Automate any specific sequence of moves, for debugging */ + static int moves[9] = {1, 2, 5, 6, 7,}; + static int m = 0; + board[moves[m++]] = player; + return 0; +} char get_move_from_human(char *board, char player) { int n; print_msg("%c's move? [1-9]: ", player); @@ -118,18 +130,43 @@ char get_random_move(char *board, char player) { board[legal_moves[get_rand(lm_ind)]] = player; return get_winner_or_winning_moves(board, NULL); } -char get_winning_move_else_random(char *board, char player) { +static char try_get_winning_move(char *board, char player) { char winning_moves[9] = ""; int my_winning_moves[5]; int mwm_ind = 0; get_winner_or_winning_moves(board, winning_moves); for(int i=0; i < 9; i++) - if(winning_moves[i] == player) + if((winning_moves[i] & player) == player) my_winning_moves[mwm_ind++] = i; if(mwm_ind) { board[my_winning_moves[get_rand(mwm_ind)]] = player; return player; } + return 0; +} +char get_winning_move_else_random(char *board, char player) { + char winner = try_get_winning_move(board, player); + if(winner) + return winner; + else + return get_random_move(board, player); +} +char get_winning_move_else_block_else_random(char *board, char player) { + char winner = try_get_winning_move(board, player); + if(winner) return winner; + char winning_moves[9] = ""; + int his_winning_moves[5]; + int hwm_ind = 0; + char opponent = (player == 'O' ? 'X' : 'O'); + get_winner_or_winning_moves(board, winning_moves); + for(int i=0; i < 9; i++) + if(winning_moves[i] == opponent) + his_winning_moves[hwm_ind++] = i; + if(hwm_ind) { + board[his_winning_moves[get_rand(hwm_ind)]] = player; + /*N.B. This will not be reached if the move is a winning move for both players */ + return 0; + } else return get_random_move(board, player); } diff --git a/unit_test.c b/unit_test.c @@ -1,5 +1,6 @@ #include <stdio.h> #define UNIT_TEST +#define NO_PRINT_BOARD #include "tictactoe.c"