tictactoe

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

commit fe0f1f2cb5e0ae8e5656ce2e3136c392abcfed8b
parent b3d3893f89067fa04f2a6c7a35cd2a75fe63f566
Author: Wilson Gheen <wilson@wilsonrgheen.com>
Date:   Sat, 17 Dec 2022 09:28:24 -0600

Add function for "AI" that tries to win

Diffstat:
Mtictactoe.c | 47++++++-----------------------------------------
Mtictactoe.h | 84++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
2 files changed, 83 insertions(+), 48 deletions(-)

diff --git a/tictactoe.c b/tictactoe.c @@ -22,56 +22,21 @@ static void print_board(char *board) { #endif } -static void get_near_wins(char *b, char *winner) { - char winning_moves[9]; - char center = b[4]; - for(int i=-4; center != ' ' && i < 0; i++) { - int s2 = 4+i; - int s3 = 4-i; - if(b[s2] == center && b[s3] == center) { - *winner = center; - return; - } - if(b[s2] == center || b[s3] == center) { - if(b[s2] == ' ') - winning_moves[s2] = center; - else if(b[s3] == ' ') - winning_moves[s3] = center; - } - } - for(int i=1; i <= 7; i+=2){ - if(b[i] == ' ') continue; - int distance = ((i+1) & 4) ? 3 : 1; - int s2 = i - distance; - int s3 = i + distance; - if(b[s2] == b[i] && b[s3] == b[i]) { - *winner = b[i]; - return; - } - if(b[s2] == b[i] || b[s3] == b[i]) { - if(b[s2] == ' ') - winning_moves[s2] = b[i]; - else if(b[s3] == ' ') - winning_moves[s3] = b[i]; - } - } -} - -char play(void (*get_move)(char*, char)) { +char play(char (*get_move)(char*, char)) { struct tb_event ev; char board[9] = " "; char winner = 0; - char last_played = 'O'; + char player = 'O'; if(!SIDE_BY_SIDE) print_board(board); - for(int turns=0; !winner && turns <= 9; turns++) { - get_move(board, (last_played = (last_played == 'O' ? 'X' : 'O'))); + for(int turns=0; !winner && turns < 9; turns++) { + player = (player == 'O' ? 'X' : 'O'); + winner = get_move(board, player); if(SIDE_BY_SIDE) print_board_offset(board, turns * 10, 0, 0); else print_board(board); tb_peek_event(&ev, 300); - get_near_wins(board, &winner); } return winner; } @@ -80,7 +45,7 @@ char play(void (*get_move)(char*, char)) { int main(void) { struct tb_event ev; tb_init(); - char winner = play(get_random_move); + char winner = play(get_winning_move_else_random); if(winner) print_msg("%c wins.", winner); else diff --git a/tictactoe.h b/tictactoe.h @@ -1,4 +1,6 @@ +#include <stdlib.h> #include <string.h> +#include <time.h> #define SCRATCH_BOARD "XXOOOXXOX" #define X_WINS_COLUMN "XXOXOOXOX" @@ -12,16 +14,49 @@ /*typedef void (*board_fn)(char *, char);*/ static char the_desired_board[32]; +static int srand_seeded = 0; -void get_move_preset_board(char *board, char player) { - char *desired_board = the_desired_board; - for(int i=0; i < 9; i++) { - if(desired_board[i] == player && board[i] == ' ') { - board[i] = player; - return; +static int get_rand(int max_excl) { + if (!srand_seeded) { + srand(time(NULL)); + srand_seeded = 1; + } + return rand() % max_excl; +} +char get_near_wins(char *b, char *winning_moves) { + char center = b[4]; + for(int i=-4; center != ' ' && i < 0; i++) { + int s2 = 4+i; + int s3 = 4-i; + if(b[s2] == center && b[s3] == center) + return center; + if(winning_moves == NULL) continue; + if(b[s2] == center || b[s3] == center) { + if(b[s2] == ' ') + winning_moves[s2] = center; + else if(b[s3] == ' ') + winning_moves[s3] = center; } } + for(int i=1; i <= 7; i+=2){ + if(b[i] == ' ') continue; + int distance = ((i+1) & 4) ? 3 : 1; + int s2 = i - distance; + int s3 = i + distance; + if(b[s2] == b[i] && b[s3] == b[i]) { + return b[i]; + } + if(winning_moves == NULL) continue; + if(b[s2] == b[i] || b[s3] == b[i]) { + if(b[s2] == ' ') + winning_moves[s2] = b[i]; + else if(b[s3] == ' ') + winning_moves[s3] = b[i]; + } + } + return 0; } + void set_board(char *board_name) { scase(board_name, "scratch_board") strcpy(the_desired_board, SCRATCH_BOARD); @@ -39,10 +74,45 @@ void set_board(char *board_name) { strcpy(the_desired_board, O_WINS_ROW); } -void get_move_from_human(char *board, char player) { +char get_move_preset_board(char *board, char player) { + char *desired_board = the_desired_board; + for(int i=0; i < 9; i++) { + if(desired_board[i] == player && board[i] == ' ') { + board[i] = player; + return get_near_wins(board, NULL); + } + } + return 0; +} +char get_move_from_human(char *board, char player) { int n; print_msg("%c's move? [1-9]: ", player); tb_present(); scanf("%d", &n); board[n-1] = player; + return get_near_wins(board, NULL); +} +char get_random_move(char *board, char player) { + int legal_moves[9]; + int lm_ind = 0; + for(int i=0; i < 9; i++) + if(board[i] == ' ') + legal_moves[lm_ind++] = i; + board[legal_moves[get_rand(lm_ind)]] = player; + return get_near_wins(board, NULL); +} +char get_winning_move_else_random(char *board, char player) { + char winning_moves[9] = {0}; + int my_winning_moves[5]; + int mwm_ind = 0; + get_near_wins(board, winning_moves); + for(int i=0; i < 9; i++) + if(winning_moves[i] == player) + my_winning_moves[mwm_ind++] = i; + if(mwm_ind) { + board[my_winning_moves[get_rand(mwm_ind)]] = player; + return player; + } + else + return get_random_move(board, player); }