tictactoe

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

commit b3d3893f89067fa04f2a6c7a35cd2a75fe63f566
parent 1ab6db826eac5460a6a030aa062c16410c9bf4c5
Author: Wilson Gheen <wilson@wilsonrgheen.com>
Date:   Sat, 17 Dec 2022 07:23:33 -0600

Add unit testing and begin to implement finding near-wins

Diffstat:
Mtictactoe.c | 72++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Mtictactoe.h | 25+++++++++++++++++++++++--
Aunit_test.c | 46++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 119 insertions(+), 24 deletions(-)

diff --git a/tictactoe.c b/tictactoe.c @@ -8,7 +8,7 @@ #define SIDE_BY_SIDE 0 -void print_board_offset(char *board, int offx, int offy, int clear) { +static void print_board_offset(char *board, int offx, int offy, int clear) { if(clear) tb_clear(); print_box_offset(7, 7, offx, offy, 0); for(int i=0; i < 9; i++) { @@ -16,17 +16,52 @@ void print_board_offset(char *board, int offx, int offy, int clear) { } tb_present(); } -void print_board(char *board) { +static void print_board(char *board) { +#ifndef UNIT_TEST print_board_offset(board, 0, 0, 1); +#endif } -int main(void) { +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)) { struct tb_event ev; char board[9] = " "; char winner = 0; char last_played = 'O'; - void (*get_move)(char*, char) = get_move_from_human; - tb_init(); if(!SIDE_BY_SIDE) print_board(board); for(int turns=0; !winner && turns <= 9; turns++) { @@ -36,24 +71,16 @@ int main(void) { else print_board(board); tb_peek_event(&ev, 300); - char center = board[4]; - for(int i=-4; center != ' ' && i < 0; i++) { - if(board[4+i] == center && board[4-i] == center) { - winner = center; - break; - } - } - for(int i=1; !winner && i <= 7; i+=2){ - if(board[i] == ' ') continue; - if((i+1) & 4) { /* column */ - if(board[i-3] == board[i] && board[i+3] == board[i]) - winner = board[i]; - } else { /* row */ - if(board[i-1] == board[i] && board[i+1] == board[i]) - winner = board[i]; - } - } + get_near_wins(board, &winner); } + return winner; +} + +#ifndef UNIT_TEST +int main(void) { + struct tb_event ev; + tb_init(); + char winner = play(get_random_move); if(winner) print_msg("%c wins.", winner); else @@ -63,3 +90,4 @@ int main(void) { if (ev.type == TB_EVENT_KEY && ev.key == TB_KEY_CTRL_C) tb_shutdown(); } +#endif diff --git a/tictactoe.h b/tictactoe.h @@ -1,4 +1,4 @@ -int m = 0; +#include <string.h> #define SCRATCH_BOARD "XXOOOXXOX" #define X_WINS_COLUMN "XXOXOOXOX" @@ -8,8 +8,13 @@ int m = 0; #define O_WINS_DIAG "OXXOOXX O" #define O_WINS_ROW " XXXOXOOO" +#define scase(s1, s2) if (!strcmp(s1, s2)) + +/*typedef void (*board_fn)(char *, char);*/ +static char the_desired_board[32]; + void get_move_preset_board(char *board, char player) { - char desired_board[9] = SCRATCH_BOARD; + char *desired_board = the_desired_board; for(int i=0; i < 9; i++) { if(desired_board[i] == player && board[i] == ' ') { board[i] = player; @@ -17,6 +22,22 @@ void get_move_preset_board(char *board, char player) { } } } +void set_board(char *board_name) { + scase(board_name, "scratch_board") + strcpy(the_desired_board, SCRATCH_BOARD); + scase(board_name, "x_wins_column") + strcpy(the_desired_board, X_WINS_COLUMN); + scase(board_name, "x_wins_diag") + strcpy(the_desired_board, X_WINS_DIAG); + scase(board_name, "x_wins_row") + strcpy(the_desired_board, X_WINS_ROW); + scase(board_name, "o_wins_column") + strcpy(the_desired_board, O_WINS_COLUMN); + scase(board_name, "o_wins_diag") + strcpy(the_desired_board, O_WINS_DIAG); + scase(board_name, "o_wins_row") + strcpy(the_desired_board, O_WINS_ROW); +} void get_move_from_human(char *board, char player) { int n; diff --git a/unit_test.c b/unit_test.c @@ -0,0 +1,46 @@ +#include <stdio.h> +#define UNIT_TEST + +#include "tictactoe.c" + +struct test_board { char *name; char *expected_result; }; + +struct test_board test_boards[] = { + {"scratch_board", "SCRATCH"}, + {"x_wins_column", "X WINS" }, + {"x_wins_diag", "X WINS" }, + {"x_wins_row", "X WINS" }, + {"o_wins_column", "O WINS" }, + {"o_wins_diag", "O WINS" }, + {"o_wins_row", "O WINS" }, +}; + +int main() { + int failures = 0; + int len = sizeof test_boards / sizeof test_boards[0]; + int i = 0; + while(i < len) { + struct test_board *b = test_boards + (i++); + char actual_result[8]; + printf("TEST %d\n", i); + puts( "--------"); + printf("Testing %s -- expecting '%s' ...\n", b->name, b->expected_result); + set_board(b->name); + char winner = play(get_move_preset_board); + if(winner) + sprintf(actual_result, "%c WINS", winner); + else + sprintf(actual_result, "SCRATCH"); + printf("Result was: %s\n", actual_result); + printf("Test %d ", i); + if(strcmp(actual_result, b->expected_result)) { + puts("FAILURE\n"); + failures++; + } + else puts("SUCCESS\n"); + } + puts("-----------------------------------------------------------"); + printf("\n### SUITE %s ###\n", failures ? "FAILURE" : "SUCCESS"); + printf("%d tests: %d failed, %d succeeded\n", i, failures, i - failures); + return (i - failures == 0) ? 2 : (failures && 1); +}