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:
M | tictactoe.c | | | 47 | ++++++----------------------------------------- |
M | tictactoe.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);
}