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:
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");