tictactoe

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

commit 9f2d8a095f26cf60f5b0979dbfae93a10e2b4049
parent a73984d7008722c51eb0d2ded486e1c6153a6865
Author: Wilson Gheen <wilson@wilsonrgheen.com>
Date:   Thu, 22 Dec 2022 15:44:38 -0600

Refactor unit_test.c and add tests 9-11

Diffstat:
Mtictactoe.c | 10++++++----
Mtictactoe.h | 2--
Munit_test.c | 57+++++++++++++++++++++++++++++++++++++++++----------------
3 files changed, 47 insertions(+), 22 deletions(-)

diff --git a/tictactoe.c b/tictactoe.c @@ -5,6 +5,8 @@ #define SIDE_BY_SIDE 1 +typedef char (*Get_move_fn)(char*, char); + static void print_board_offset(char *board, int offx, int offy, int clear) { #ifndef DEBUG if(clear) tb_clear(); @@ -19,17 +21,17 @@ static void print_board(char *board) { print_board_offset(board, 0, 0, 1); } -char play(char (*get_move)(char*, char), char (*get_move_2)(char*, char)) { +char play(Get_move_fn get_x_move, Get_move_fn get_o_move) { struct tb_event ev; char board[10] = " "; char winner = 0; char player = 'O'; - if(get_move_2 == NULL) - get_move_2 = get_move; + if(get_o_move == NULL) + get_o_move = get_x_move; if(!SIDE_BY_SIDE) print_board(board); for(int turns=0; !winner && turns < 9; turns++) { - winner = (turns & 1) ? get_move(board, player) : get_move_2(board, player); + winner = (turns & 1) ? get_x_move(board, player) : get_o_move(board, player); player = OPPONENT; if(SIDE_BY_SIDE) print_board_offset(board, turns * 10, 0, 0); diff --git a/tictactoe.h b/tictactoe.h @@ -29,8 +29,6 @@ static int get_rand(int max_excl) { fprintf(f, "%ld\n", seed); fclose(f); } - else - puts("Failed to open file"); srand(seed); srand_seeded = 1; } diff --git a/unit_test.c b/unit_test.c @@ -16,18 +16,50 @@ struct test_board test_boards[] = { {"o_wins_row", "O WINS" }, }; +typedef _Bool (*Result_checker)(char); +_Bool is_draw(char actual_result) { + return actual_result == 0; +} +_Bool is_draw_or_win(char actual_result) { + return actual_result != 'O'; +} + + +void print_test_header(int test_num, char *desc, char *ex_res) { + printf("TEST %d\n", test_num); + puts( "--------"); + printf("Testing %s -- expecting %s ...\n", desc, ex_res); +} +_Bool print_test_results(int test_num, _Bool succeeded) { + printf("Test %d ", test_num); + if(succeeded) { + puts("SUCCESS\n"); + return 0; + } + else { + puts("FAILURE\n"); + return 1; + } +} + +_Bool test_ai_against(Get_move_fn get_o_move, int iters, int test_num, char *opp_desc, char *ex_res, Result_checker is_expected) { + char desc[120]; + int i; + sprintf(desc, "our allegedly perfect AI against %s %d times", opp_desc, iters); + print_test_header(test_num, desc, ex_res); + for(i=0; i < iters && is_expected(play(get_move_minimax, get_o_move)); ++i); + return print_test_results(test_num, i == iters); +} + int main() { int failures = 0; int len = sizeof test_boards / sizeof test_boards[0]; int i = 0; - int c = 0; /* Testing that particular presets will be correctly interpreted as a draw/win/loss */ 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); + print_test_header(i, b->name, b->expected_result); set_board(b->name); char winner = play(get_move_preset_board, NULL); if(winner) @@ -35,19 +67,12 @@ int main() { 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"); + failures += print_test_results(i, !strcmp(actual_result, b->expected_result)); } - printf("TEST %d\n", ++i); - puts( "--------"); - puts("Pitting our allegedly perfect AI against itself 50 times. Expecting a draw for all executions."); - for(c=0; c < 50 && play(get_move_minimax, NULL) == 0; ++c); - if(c < 50) failures++, puts("FAILURE\n"); - else puts("SUCCESS\n"); + failures += test_ai_against(get_move_minimax, 50, ++i, "itself", "a draw for all executions", is_draw); + failures += test_ai_against(get_random_move, 500, ++i, "a random move generator", "the AI wins or draws for all executions", is_draw_or_win); + failures += test_ai_against(get_winning_move_else_random, 500, ++i, "a slightly dumber AI", "the AI wins or draws for all executions", is_draw_or_win); + failures += test_ai_against(get_winning_move_else_block_else_random, 500, ++i, "a slightly smarter, dumber AI", "the AI wins or draws for all executions", is_draw_or_win); puts("-----------------------------------------------------------"); printf("\n### SUITE %s ###\n", failures ? "FAILURE" : "SUCCESS");