From a5a3ae3f16babefec23397ce740221218dcddd1c Mon Sep 17 00:00:00 2001 From: Ilya Bezrukov Date: Tue, 26 Oct 2021 01:23:56 +0300 Subject: [PATCH 1/9] Refactored main.c --- main.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/main.c b/main.c index b1426e1..e5e92bd 100644 --- a/main.c +++ b/main.c @@ -6,14 +6,6 @@ #include "minimax.h" -const char loadingS[] = {'-', '\\', '|', '/'}; - -void print_turn(enum field map[SIZE][SIZE], int turn, char ch) { - printf("===== %d TURN (%c) =====\n\n", turn, ch); - print_map(map); - printf("\n"); -} - int main(int argc, char** argv){ enum field map[SIZE][SIZE]; @@ -66,7 +58,9 @@ int main(int argc, char** argv){ current_ch = field2char(current); // get char representation of player - print_turn(map, turns_count, current_ch); // print map and turn header + printf("===== %d TURN (%c) =====\n\n", turns_count, current_ch); + print_map(map); + printf("\n"); if (current == CROSS) { // Human turn ipt_r = OK; @@ -86,7 +80,6 @@ int main(int argc, char** argv){ map[row][column] = current; // fill cell with player's symbol - print_map(map); winner = check_winner(map); // check winner if (winner != EMPTY) { // if winner exists From 9ec67c9dc1fe96d7cf223ac9d5b02b9d46f986a5 Mon Sep 17 00:00:00 2001 From: Ilya Bezrukov Date: Tue, 26 Oct 2021 01:37:31 +0300 Subject: [PATCH 2/9] Added Cell struct in tictactoe.h and .c --- tictactoe.c | 12 +++++++++--- tictactoe.h | 9 ++++++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/tictactoe.c b/tictactoe.c index 115832a..440da65 100644 --- a/tictactoe.c +++ b/tictactoe.c @@ -5,6 +5,13 @@ #include "tictactoe.h" +Cell* create_cell(int row, int col) { + Cell* cl = (Cell*) malloc(sizeof(Cell)); + cl->row = row; + cl->col = col; + return cl; +} + int randrange(int a, int b) { return rand() % (b - a + 1) + a; } @@ -80,7 +87,7 @@ void print_map(enum field map[SIZE][SIZE]) { // pretty print for map } } -void ai_rand_turn(enum field map[SIZE][SIZE], int* row, int* col) { +Cell* ai_rand_turn(enum field map[SIZE][SIZE]) { enum bool flag = FALSE; int cell_num, rw, cl; do { @@ -89,8 +96,7 @@ void ai_rand_turn(enum field map[SIZE][SIZE], int* row, int* col) { cl = cell_num % SIZE; flag = (map[rw][cl] == EMPTY); } while (!flag); - *row = rw; - *col = cl; + return create_cell(rw, cl); } int check_input(enum field map[SIZE][SIZE], int row, int col) { diff --git a/tictactoe.h b/tictactoe.h index ec2276c..57be793 100644 --- a/tictactoe.h +++ b/tictactoe.h @@ -22,8 +22,15 @@ enum field { ZERO }; +// cell structure +typedef struct { + int row; + int col; +} Cell; + // service functions int randrange(int a, int b); +Cell* new_cell(int row, int col); char field2char(enum field fld); enum field char2field(char ch); @@ -37,7 +44,7 @@ enum field check_winner(enum field map[SIZE][SIZE]); enum bool is_draw(enum field map[SIZE][SIZE]); // turns functions -void ai_rand_turn(enum field map[SIZE][SIZE], int* row, int* col); +Cell* ai_rand_turn(enum field map[SIZE][SIZE]); int check_input(enum field map[SIZE][SIZE], int row, int col); #endif From 316d1540cbd92842930bbe70964d11043a59e2e2 Mon Sep 17 00:00:00 2001 From: Ilya Bezrukov Date: Tue, 26 Oct 2021 23:59:39 +0300 Subject: [PATCH 3/9] Refactored --- main.c | 19 ++++++------ minimax.c | 83 +++++++++++++++++++++++------------------------------ minimax.h | 12 ++------ tictactoe.c | 25 +++++++++------- tictactoe.h | 26 ++++++++++------- 5 files changed, 80 insertions(+), 85 deletions(-) diff --git a/main.c b/main.c index e5e92bd..f7bca46 100644 --- a/main.c +++ b/main.c @@ -47,7 +47,7 @@ int main(int argc, char** argv){ int turns_count = 1; - int row, column; // inputed cell + Cell turn = Cell_create(-1, -1); // turn cell int ipt_r; // result of cell input enum field winner = EMPTY; @@ -63,22 +63,23 @@ int main(int argc, char** argv){ printf("\n"); if (current == CROSS) { // Human turn - ipt_r = OK; + ipt_r = INPUT_OK; do { switch (ipt_r) { case NOTONMAP: printf("Not on map!\n"); break; case NOTEMPTY: printf("Already taken!\n"); break; } printf("Choose row and column to make turn:\n"); - scanf("%d %d", &row, &column); - } while ((ipt_r = check_input(map, --row, --column)) != OK); + scanf("%d %d", &turn.row, &turn.col); + turn.row--; + turn.col--; + } while ((ipt_r = check_input(map, turn)) != INPUT_OK); } - if (current == ZERO) { // AI turn - int val = minimax(&map, &row, &column, current, 0); - printf("Better %d turn: (%d, %d)\n", val, row+1, column+1); + else if (current == ZERO) { // AI turn + minimax(&map, &turn, current, 0); } - - map[row][column] = current; // fill cell with player's symbol + + map[turn.row][turn.col] = current; // fill cell with player's symbol winner = check_winner(map); // check winner diff --git a/minimax.c b/minimax.c index 29e566f..28b9d84 100644 --- a/minimax.c +++ b/minimax.c @@ -15,38 +15,36 @@ void setMode(int value) { depthMode = value; } - -struct cell new_cell(int row, int col) { - struct cell new; - new.row = row; - new.col = col; - return new; -} - - -int get_moves(enum field map[SIZE][SIZE], struct cell **moves) { +int getMoves(enum field map[SIZE][SIZE], Cell** moves, size_t* n) { + if (*n < 1 || *moves == NULL) { + *n = sizeof(Cell); + *moves = (Cell*) malloc(*n); + } int count = 0; for (int i = 0; i < SIZE; i++) { for (int j = 0; j < SIZE; j++) { - if (map[i][j] == EMPTY) { - count += 1; - if (sizeof(**moves) < count * sizeof(struct cell)) { - *moves = (struct cell*) realloc(*moves, sizeof(struct cell) * count); - if (moves == NULL) { - printf("Cant realoc moves!\n"); - exit(1); - } + if (map[i][j] != EMPTY) { + continue; + } + count++; + if (*n < count * sizeof(Cell)) { + *n += sizeof(Cell); + *moves = (Cell*) realloc(*moves, *n); + if (!moves) { + fprintf(stderr, "Not enough memory!\n"); + exit(1); } - (*moves)[count - 1] = new_cell(i, j); - } + } + (*moves)[count - 1] = Cell_create(i, j); } } return count; } -int minimax(enum field (*map)[SIZE][SIZE], int* row, int* col, enum field player, int depth) { - *row = -1; - *col = -1; + +int minimax(enum field (*map)[SIZE][SIZE], Cell* turn, enum field player, int depth) { + turn->row = -1; + turn->col = -1; enum field winner = check_winner(*map); if (winner != EMPTY) { @@ -55,47 +53,38 @@ int minimax(enum field (*map)[SIZE][SIZE], int* row, int* col, enum field player if (is_draw(*map) || (depthMode != 0 && depth > depthMode)) { return 0; } + + Cell* moves; + int count = 0; + size_t allocated = 0; + count = getMoves(*map, &moves, &allocated); - struct cell* moves = (struct cell*) malloc(sizeof(struct cell) * 1); - if (moves == NULL) { - printf("Cant malloc moves!\n"); - exit(1); - } - - int count = get_moves(*map, &moves); - struct cell ch_move = moves[0]; // choosen move + Cell* ch_move; int mnmx = (player == ZERO) ? -20 : 20; // optimized value int res = 0; // last minimax value int rw, cl; // make move - int r, c; // next turn move for (int i = 0; i < count; i++) { rw = moves[i].row; cl = moves[i].col; + (*map)[rw][cl] = player; - res = minimax(map, &r, &c, switch_player(player), depth + 1); + res = minimax(map, turn, switch_player(player), depth + 1); - if (player == ZERO) { - if (res > mnmx) { - mnmx = res; - ch_move = new_cell(rw, cl); - } - } else if (player == CROSS) { - if (res < mnmx) { - mnmx = res; - ch_move = new_cell(rw, cl); - } + if ((player == ZERO && res > mnmx) || (player == CROSS && res < mnmx)) { + mnmx = res; + ch_move = moves + i; } (*map)[rw][cl] = EMPTY; } + + turn->row = ch_move->row; + turn->col = ch_move->col; - free(moves); + free(moves); - *row = ch_move.row; - *col = ch_move.col; - return mnmx; } diff --git a/minimax.h b/minimax.h index 4221be9..44623b0 100644 --- a/minimax.h +++ b/minimax.h @@ -9,17 +9,11 @@ #define MODE_EXPERT 0 -struct cell { - int row; - int col; -}; - -struct cell new_cell(int row, int col); - int getMode(); void setMode(int value); -int get_moves(enum field map[SIZE][SIZE], struct cell** moves); -int minimax(enum field (*map)[SIZE][SIZE], int* row, int* cell, enum field player, int depth); +int getMoves(enum field map[SIZE][SIZE], Cell** moves, size_t* n); + +int minimax(enum field (*map)[SIZE][SIZE], Cell* turn, enum field player, int depth); #endif diff --git a/tictactoe.c b/tictactoe.c index 440da65..96ad7e0 100644 --- a/tictactoe.c +++ b/tictactoe.c @@ -5,17 +5,19 @@ #include "tictactoe.h" -Cell* create_cell(int row, int col) { - Cell* cl = (Cell*) malloc(sizeof(Cell)); - cl->row = row; - cl->col = col; +Cell Cell_create(int row, int col) { + Cell cl; + cl.row = row; + cl.col = col; return cl; } + int randrange(int a, int b) { return rand() % (b - a + 1) + a; } + char field2char(enum field fld) { // get char representation for field switch (fld) { case CROSS: return 'X'; break; @@ -32,6 +34,7 @@ enum field char2field(char ch) { } } + enum field check_winner(enum field map[SIZE][SIZE]) { for (int i = 0; i < SIZE; i++) { // horizontal lines if (map[i][0] == map[i][1] && map[i][1] == map[i][2] && map[i][1] != EMPTY) { @@ -87,7 +90,7 @@ void print_map(enum field map[SIZE][SIZE]) { // pretty print for map } } -Cell* ai_rand_turn(enum field map[SIZE][SIZE]) { +Cell ai_rand_turn(enum field map[SIZE][SIZE]) { enum bool flag = FALSE; int cell_num, rw, cl; do { @@ -96,17 +99,19 @@ Cell* ai_rand_turn(enum field map[SIZE][SIZE]) { cl = cell_num % SIZE; flag = (map[rw][cl] == EMPTY); } while (!flag); - return create_cell(rw, cl); + return Cell_create(rw, cl); } -int check_input(enum field map[SIZE][SIZE], int row, int col) { - if (row > SIZE - 1 || row < 0 || col > SIZE - 1 || col < 0) { +InputCode check_input(enum field map[SIZE][SIZE], Cell turn) { + if (turn.row > SIZE - 1 || turn.row < 0 || + turn.col > SIZE - 1 || turn.col < 0) + { return NOTONMAP; } - if (map[row][col] != EMPTY) { // check if cell already taken + if (map[turn.row][turn.col] != EMPTY) { // check if cell already taken return NOTEMPTY; } else { - return OK; + return INPUT_OK; } } diff --git a/tictactoe.h b/tictactoe.h index 57be793..ce54efe 100644 --- a/tictactoe.h +++ b/tictactoe.h @@ -4,10 +4,12 @@ // size of game map #define SIZE 3 // cant be changed! -// error codes for input_cell -#define OK 0 -#define NOTONMAP 1 -#define NOTEMPTY 2 +// error codes for check_input +typedef enum InputCode { + INPUT_OK, + NOTONMAP, + NOTEMPTY +} InputCode; // boolean values enum bool { @@ -16,11 +18,11 @@ enum bool { }; // cell type or player type -enum field { +typedef enum field { EMPTY, CROSS, ZERO -}; +} FieldType; // cell structure typedef struct { @@ -28,15 +30,19 @@ typedef struct { int col; } Cell; + +// Cell functions +Cell Cell_create(int row, int col); + // service functions int randrange(int a, int b); -Cell* new_cell(int row, int col); +// FieldType functions char field2char(enum field fld); enum field char2field(char ch); - enum field switch_player(enum field current); +// map functions void print_map(enum field map[SIZE][SIZE]); // checks functions @@ -44,7 +50,7 @@ enum field check_winner(enum field map[SIZE][SIZE]); enum bool is_draw(enum field map[SIZE][SIZE]); // turns functions -Cell* ai_rand_turn(enum field map[SIZE][SIZE]); -int check_input(enum field map[SIZE][SIZE], int row, int col); +Cell ai_rand_turn(enum field map[SIZE][SIZE]); +InputCode check_input(enum field map[SIZE][SIZE], Cell turn); #endif From 53863cc8699853734724997d6c5bcd0ebd5f08dc Mon Sep 17 00:00:00 2001 From: Ilya Bezrukov Date: Wed, 27 Oct 2021 00:05:24 +0300 Subject: [PATCH 4/9] Migrated to stdbool for booleans --- main.c | 3 ++- tictactoe.c | 9 +++++---- tictactoe.h | 9 +++------ 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/main.c b/main.c index f7bca46..11672d9 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "tictactoe.h" #include "minimax.h" @@ -51,7 +52,7 @@ int main(int argc, char** argv){ int ipt_r; // result of cell input enum field winner = EMPTY; - enum bool is_running = TRUE; + bool is_running = true; while (is_running) { system("clear"); // clear last output diff --git a/tictactoe.c b/tictactoe.c index 96ad7e0..944f016 100644 --- a/tictactoe.c +++ b/tictactoe.c @@ -1,6 +1,7 @@ #include #include #include +#include #include "tictactoe.h" @@ -56,15 +57,15 @@ enum field check_winner(enum field map[SIZE][SIZE]) { return EMPTY; // winner not found } -enum bool is_draw(enum field map[SIZE][SIZE]) { +bool is_draw(enum field map[SIZE][SIZE]) { for (int i = 0; i < SIZE; i++) { for (int j = 0; j < SIZE; j++) { if (map[i][j] == EMPTY) { - return FALSE; + return false; } } } - return TRUE; + return true; } void print_map(enum field map[SIZE][SIZE]) { // pretty print for map @@ -91,7 +92,7 @@ void print_map(enum field map[SIZE][SIZE]) { // pretty print for map } Cell ai_rand_turn(enum field map[SIZE][SIZE]) { - enum bool flag = FALSE; + bool flag = false; int cell_num, rw, cl; do { cell_num = randrange(0, SIZE*SIZE - 1); diff --git a/tictactoe.h b/tictactoe.h index ce54efe..83a662e 100644 --- a/tictactoe.h +++ b/tictactoe.h @@ -1,6 +1,8 @@ #ifndef TICTACTOE #define TICTACTOE +#include + // size of game map #define SIZE 3 // cant be changed! @@ -11,11 +13,6 @@ typedef enum InputCode { NOTEMPTY } InputCode; -// boolean values -enum bool { - FALSE, - TRUE -}; // cell type or player type typedef enum field { @@ -47,7 +44,7 @@ void print_map(enum field map[SIZE][SIZE]); // checks functions enum field check_winner(enum field map[SIZE][SIZE]); -enum bool is_draw(enum field map[SIZE][SIZE]); +bool is_draw(enum field map[SIZE][SIZE]); // turns functions Cell ai_rand_turn(enum field map[SIZE][SIZE]); From 1c7a17fdd39b30444f33e5f4eae7ae79707a2ed2 Mon Sep 17 00:00:00 2001 From: Ilya Bezrukov Date: Wed, 27 Oct 2021 00:11:56 +0300 Subject: [PATCH 5/9] Changed enum field to FieldT in all declarations and prototypes --- main.c | 4 ++-- minimax.c | 6 +++--- minimax.h | 4 ++-- tictactoe.c | 16 ++++++++-------- tictactoe.h | 18 +++++++++--------- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/main.c b/main.c index 11672d9..8c9cf4e 100644 --- a/main.c +++ b/main.c @@ -21,7 +21,7 @@ int main(int argc, char** argv){ char current_ch; // current player char printf("Who is the first? [X/O]: "); scanf("%c", ¤t_ch); - enum field current = char2field(current_ch); + FieldT current = char2field(current_ch); char ai_mode_ch; int ai_mode; @@ -51,7 +51,7 @@ int main(int argc, char** argv){ Cell turn = Cell_create(-1, -1); // turn cell int ipt_r; // result of cell input - enum field winner = EMPTY; + FieldT winner = EMPTY; bool is_running = true; while (is_running) { diff --git a/minimax.c b/minimax.c index 28b9d84..aee7750 100644 --- a/minimax.c +++ b/minimax.c @@ -15,7 +15,7 @@ void setMode(int value) { depthMode = value; } -int getMoves(enum field map[SIZE][SIZE], Cell** moves, size_t* n) { +int getMoves(FieldT map[SIZE][SIZE], Cell** moves, size_t* n) { if (*n < 1 || *moves == NULL) { *n = sizeof(Cell); *moves = (Cell*) malloc(*n); @@ -42,11 +42,11 @@ int getMoves(enum field map[SIZE][SIZE], Cell** moves, size_t* n) { } -int minimax(enum field (*map)[SIZE][SIZE], Cell* turn, enum field player, int depth) { +int minimax(FieldT (*map)[SIZE][SIZE], Cell* turn, FieldT player, int depth) { turn->row = -1; turn->col = -1; - enum field winner = check_winner(*map); + FieldT winner = check_winner(*map); if (winner != EMPTY) { return (winner == ZERO) ? 10 : -10; } diff --git a/minimax.h b/minimax.h index 44623b0..aa2dce9 100644 --- a/minimax.h +++ b/minimax.h @@ -12,8 +12,8 @@ int getMode(); void setMode(int value); -int getMoves(enum field map[SIZE][SIZE], Cell** moves, size_t* n); +int getMoves(FieldT map[SIZE][SIZE], Cell** moves, size_t* n); -int minimax(enum field (*map)[SIZE][SIZE], Cell* turn, enum field player, int depth); +int minimax(FieldT (*map)[SIZE][SIZE], Cell* turn, FieldT player, int depth); #endif diff --git a/tictactoe.c b/tictactoe.c index 944f016..0f9e5d0 100644 --- a/tictactoe.c +++ b/tictactoe.c @@ -19,7 +19,7 @@ int randrange(int a, int b) { } -char field2char(enum field fld) { // get char representation for field +char field2char(FieldT fld) { // get char representation for field switch (fld) { case CROSS: return 'X'; break; case ZERO: return 'O'; break; @@ -27,7 +27,7 @@ char field2char(enum field fld) { // get char representation for field } } -enum field char2field(char ch) { +FieldT char2field(char ch) { switch (ch) { case 'X': return CROSS; break; case 'O': return ZERO; break; @@ -36,7 +36,7 @@ enum field char2field(char ch) { } -enum field check_winner(enum field map[SIZE][SIZE]) { +FieldT check_winner(FieldT map[SIZE][SIZE]) { for (int i = 0; i < SIZE; i++) { // horizontal lines if (map[i][0] == map[i][1] && map[i][1] == map[i][2] && map[i][1] != EMPTY) { return map[i][1]; @@ -57,7 +57,7 @@ enum field check_winner(enum field map[SIZE][SIZE]) { return EMPTY; // winner not found } -bool is_draw(enum field map[SIZE][SIZE]) { +bool is_draw(FieldT map[SIZE][SIZE]) { for (int i = 0; i < SIZE; i++) { for (int j = 0; j < SIZE; j++) { if (map[i][j] == EMPTY) { @@ -68,7 +68,7 @@ bool is_draw(enum field map[SIZE][SIZE]) { return true; } -void print_map(enum field map[SIZE][SIZE]) { // pretty print for map +void print_map(FieldT map[SIZE][SIZE]) { // pretty print for map printf(" "); for (int i = 0; i < SIZE; i++) { // columns indices printf(" %d", i + 1); @@ -91,7 +91,7 @@ void print_map(enum field map[SIZE][SIZE]) { // pretty print for map } } -Cell ai_rand_turn(enum field map[SIZE][SIZE]) { +Cell ai_rand_turn(FieldT map[SIZE][SIZE]) { bool flag = false; int cell_num, rw, cl; do { @@ -103,7 +103,7 @@ Cell ai_rand_turn(enum field map[SIZE][SIZE]) { return Cell_create(rw, cl); } -InputCode check_input(enum field map[SIZE][SIZE], Cell turn) { +InputCode check_input(FieldT map[SIZE][SIZE], Cell turn) { if (turn.row > SIZE - 1 || turn.row < 0 || turn.col > SIZE - 1 || turn.col < 0) { @@ -116,6 +116,6 @@ InputCode check_input(enum field map[SIZE][SIZE], Cell turn) { } } -enum field switch_player(enum field current) { +FieldT switch_player(FieldT current) { return (current == CROSS) ? ZERO : CROSS; } diff --git a/tictactoe.h b/tictactoe.h index 83a662e..6479c28 100644 --- a/tictactoe.h +++ b/tictactoe.h @@ -19,7 +19,7 @@ typedef enum field { EMPTY, CROSS, ZERO -} FieldType; +} FieldT; // cell structure typedef struct { @@ -35,19 +35,19 @@ Cell Cell_create(int row, int col); int randrange(int a, int b); // FieldType functions -char field2char(enum field fld); -enum field char2field(char ch); -enum field switch_player(enum field current); +char field2char(FieldT fld); +FieldT char2field(char ch); +FieldT switch_player(FieldT current); // map functions -void print_map(enum field map[SIZE][SIZE]); +void print_map(FieldT map[SIZE][SIZE]); // checks functions -enum field check_winner(enum field map[SIZE][SIZE]); -bool is_draw(enum field map[SIZE][SIZE]); +FieldT check_winner(FieldT map[SIZE][SIZE]); +bool is_draw(FieldT map[SIZE][SIZE]); // turns functions -Cell ai_rand_turn(enum field map[SIZE][SIZE]); -InputCode check_input(enum field map[SIZE][SIZE], Cell turn); +Cell ai_rand_turn(FieldT map[SIZE][SIZE]); +InputCode check_input(FieldT map[SIZE][SIZE], Cell turn); #endif From f52669fee09306de6cd4875e8f00e6a9aa0f0acc Mon Sep 17 00:00:00 2001 From: Ilya Bezrukov Date: Wed, 27 Oct 2021 00:19:24 +0300 Subject: [PATCH 6/9] getMoves accept pointer to map --- minimax.c | 6 +++--- minimax.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/minimax.c b/minimax.c index aee7750..f7f0ff4 100644 --- a/minimax.c +++ b/minimax.c @@ -15,7 +15,7 @@ void setMode(int value) { depthMode = value; } -int getMoves(FieldT map[SIZE][SIZE], Cell** moves, size_t* n) { +int getMoves(FieldT (*map)[SIZE][SIZE], Cell** moves, size_t* n) { if (*n < 1 || *moves == NULL) { *n = sizeof(Cell); *moves = (Cell*) malloc(*n); @@ -23,7 +23,7 @@ int getMoves(FieldT map[SIZE][SIZE], Cell** moves, size_t* n) { int count = 0; for (int i = 0; i < SIZE; i++) { for (int j = 0; j < SIZE; j++) { - if (map[i][j] != EMPTY) { + if ((*map)[i][j] != EMPTY) { continue; } count++; @@ -57,7 +57,7 @@ int minimax(FieldT (*map)[SIZE][SIZE], Cell* turn, FieldT player, int depth) { Cell* moves; int count = 0; size_t allocated = 0; - count = getMoves(*map, &moves, &allocated); + count = getMoves(map, &moves, &allocated); Cell* ch_move; int mnmx = (player == ZERO) ? -20 : 20; // optimized value diff --git a/minimax.h b/minimax.h index aa2dce9..3584f6d 100644 --- a/minimax.h +++ b/minimax.h @@ -12,7 +12,7 @@ int getMode(); void setMode(int value); -int getMoves(FieldT map[SIZE][SIZE], Cell** moves, size_t* n); +int getMoves(FieldT (*map)[SIZE][SIZE], Cell** moves, size_t* n); int minimax(FieldT (*map)[SIZE][SIZE], Cell* turn, FieldT player, int depth); From 94ec59f105426dc6aa94dba3edb9cc51cfe36f78 Mon Sep 17 00:00:00 2001 From: Ilya Bezrukov Date: Wed, 27 Oct 2021 00:35:22 +0300 Subject: [PATCH 7/9] Refactored functions locations --- main.c | 3 ++- minimax.c | 21 +++++++++++++++++++-- minimax.h | 10 +++++++++- tictactoe.c | 21 +++++---------------- tictactoe.h | 11 ++++------- 5 files changed, 39 insertions(+), 27 deletions(-) diff --git a/main.c b/main.c index 8c9cf4e..85f52a2 100644 --- a/main.c +++ b/main.c @@ -77,7 +77,8 @@ int main(int argc, char** argv){ } while ((ipt_r = check_input(map, turn)) != INPUT_OK); } else if (current == ZERO) { // AI turn - minimax(&map, &turn, current, 0); + ai_minimax(&map, &turn, current, 0); + // ai_random(&map, &turn); } map[turn.row][turn.col] = current; // fill cell with player's symbol diff --git a/minimax.c b/minimax.c index f7f0ff4..4cfd280 100644 --- a/minimax.c +++ b/minimax.c @@ -7,6 +7,12 @@ static int depthMode = MODE_EXPERT; + +int randrange(int a, int b) { + return rand() % (b - a + 1) + a; +} + + int getMode() { return depthMode; } @@ -15,6 +21,7 @@ void setMode(int value) { depthMode = value; } + int getMoves(FieldT (*map)[SIZE][SIZE], Cell** moves, size_t* n) { if (*n < 1 || *moves == NULL) { *n = sizeof(Cell); @@ -42,7 +49,7 @@ int getMoves(FieldT (*map)[SIZE][SIZE], Cell** moves, size_t* n) { } -int minimax(FieldT (*map)[SIZE][SIZE], Cell* turn, FieldT player, int depth) { +int ai_minimax(FieldT (*map)[SIZE][SIZE], Cell* turn, FieldT player, int depth) { turn->row = -1; turn->col = -1; @@ -70,7 +77,7 @@ int minimax(FieldT (*map)[SIZE][SIZE], Cell* turn, FieldT player, int depth) { (*map)[rw][cl] = player; - res = minimax(map, turn, switch_player(player), depth + 1); + res = ai_minimax(map, turn, switch_player(player), depth + 1); if ((player == ZERO && res > mnmx) || (player == CROSS && res < mnmx)) { mnmx = res; @@ -88,3 +95,13 @@ int minimax(FieldT (*map)[SIZE][SIZE], Cell* turn, FieldT player, int depth) { return mnmx; } + +void ai_random(FieldT (*map)[SIZE][SIZE], Cell* turn) { + Cell* moves; + size_t allocated = 0; + int count = 0; + count = getMoves(map, &moves, &allocated); + int r_i = randrange(0, count - 1); + *turn = moves[r_i]; +} + diff --git a/minimax.h b/minimax.h index 3584f6d..2de308d 100644 --- a/minimax.h +++ b/minimax.h @@ -9,11 +9,19 @@ #define MODE_EXPERT 0 +// random integer from a to b +int randrange(int a, int b); + +// minimax depth control int getMode(); void setMode(int value); +// service functions int getMoves(FieldT (*map)[SIZE][SIZE], Cell** moves, size_t* n); -int minimax(FieldT (*map)[SIZE][SIZE], Cell* turn, FieldT player, int depth); +// turns functions +int ai_minimax(FieldT (*map)[SIZE][SIZE], Cell* turn, FieldT player, int depth); +void ai_random(FieldT (*map)[SIZE][SIZE], Cell* turn); #endif + diff --git a/tictactoe.c b/tictactoe.c index 0f9e5d0..2b98df6 100644 --- a/tictactoe.c +++ b/tictactoe.c @@ -14,11 +14,6 @@ Cell Cell_create(int row, int col) { } -int randrange(int a, int b) { - return rand() % (b - a + 1) + a; -} - - char field2char(FieldT fld) { // get char representation for field switch (fld) { case CROSS: return 'X'; break; @@ -27,6 +22,7 @@ char field2char(FieldT fld) { // get char representation for field } } + FieldT char2field(char ch) { switch (ch) { case 'X': return CROSS; break; @@ -57,6 +53,7 @@ FieldT check_winner(FieldT map[SIZE][SIZE]) { return EMPTY; // winner not found } + bool is_draw(FieldT map[SIZE][SIZE]) { for (int i = 0; i < SIZE; i++) { for (int j = 0; j < SIZE; j++) { @@ -68,6 +65,7 @@ bool is_draw(FieldT map[SIZE][SIZE]) { return true; } + void print_map(FieldT map[SIZE][SIZE]) { // pretty print for map printf(" "); for (int i = 0; i < SIZE; i++) { // columns indices @@ -91,17 +89,6 @@ void print_map(FieldT map[SIZE][SIZE]) { // pretty print for map } } -Cell ai_rand_turn(FieldT map[SIZE][SIZE]) { - bool flag = false; - int cell_num, rw, cl; - do { - cell_num = randrange(0, SIZE*SIZE - 1); - rw = cell_num / SIZE; - cl = cell_num % SIZE; - flag = (map[rw][cl] == EMPTY); - } while (!flag); - return Cell_create(rw, cl); -} InputCode check_input(FieldT map[SIZE][SIZE], Cell turn) { if (turn.row > SIZE - 1 || turn.row < 0 || @@ -116,6 +103,8 @@ InputCode check_input(FieldT map[SIZE][SIZE], Cell turn) { } } + FieldT switch_player(FieldT current) { return (current == CROSS) ? ZERO : CROSS; } + diff --git a/tictactoe.h b/tictactoe.h index 6479c28..e6e88fb 100644 --- a/tictactoe.h +++ b/tictactoe.h @@ -31,10 +31,7 @@ typedef struct { // Cell functions Cell Cell_create(int row, int col); -// service functions -int randrange(int a, int b); - -// FieldType functions +// FieldT functions char field2char(FieldT fld); FieldT char2field(char ch); FieldT switch_player(FieldT current); @@ -42,12 +39,12 @@ FieldT switch_player(FieldT current); // map functions void print_map(FieldT map[SIZE][SIZE]); -// checks functions +// check functions FieldT check_winner(FieldT map[SIZE][SIZE]); bool is_draw(FieldT map[SIZE][SIZE]); -// turns functions -Cell ai_rand_turn(FieldT map[SIZE][SIZE]); +// check posibility of turn InputCode check_input(FieldT map[SIZE][SIZE], Cell turn); #endif + From c557a340e293510e0589b93b3318b2f62b633228 Mon Sep 17 00:00:00 2001 From: Ilya Bezrukov Date: Wed, 27 Oct 2021 00:43:47 +0300 Subject: [PATCH 8/9] Rename minimax.c/.h to ai.c/.h --- Makefile | 8 ++++---- minimax.c => ai.c | 2 +- minimax.h => ai.h | 4 ++-- main.c | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) rename minimax.c => ai.c (99%) rename minimax.h => ai.h (93%) diff --git a/Makefile b/Makefile index 7fa6888..c0e9e6a 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ all: tictactoe -tictactoe: main.o tictactoe.o minimax.o - gcc -o tictactoe main.o tictactoe.o minimax.o +tictactoe: main.o tictactoe.o ai.o + gcc -o tictactoe main.o tictactoe.o ai.o main.o: main.c gcc -c main.c @@ -9,8 +9,8 @@ main.o: main.c tictactoe.o: tictactoe.c gcc -c tictactoe.c -minimax.o: minimax.c - gcc -c minimax.c +ai.o: ai.c + gcc -c ai.c clean: rm -rf *.o tictactoe diff --git a/minimax.c b/ai.c similarity index 99% rename from minimax.c rename to ai.c index 4cfd280..2d3c176 100644 --- a/minimax.c +++ b/ai.c @@ -2,7 +2,7 @@ #include #include "tictactoe.h" -#include "minimax.h" +#include "ai.h" static int depthMode = MODE_EXPERT; diff --git a/minimax.h b/ai.h similarity index 93% rename from minimax.h rename to ai.h index 2de308d..d3627e0 100644 --- a/minimax.h +++ b/ai.h @@ -1,5 +1,5 @@ -#ifndef MINIMAX -#define MINIMAX +#ifndef AI_H +#define AI_H #include "tictactoe.h" diff --git a/main.c b/main.c index 85f52a2..3c42d1c 100644 --- a/main.c +++ b/main.c @@ -4,7 +4,7 @@ #include #include "tictactoe.h" -#include "minimax.h" +#include "ai.h" int main(int argc, char** argv){ From f93d93f67f7ca7ca54f088c5255b194679651e09 Mon Sep 17 00:00:00 2001 From: Ilya Bezrukov Date: Wed, 27 Oct 2021 01:01:46 +0300 Subject: [PATCH 9/9] Added bin directory to Makefile, changed .gitignore --- .gitignore | 2 +- Makefile | 25 +++++++++++++++---------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index a27f2b9..d1b48c4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -binaries/ +bin/ tictactoe *.o *.vim diff --git a/Makefile b/Makefile index c0e9e6a..c82b756 100644 --- a/Makefile +++ b/Makefile @@ -1,17 +1,22 @@ -all: tictactoe +all: outdir tictactoe -tictactoe: main.o tictactoe.o ai.o - gcc -o tictactoe main.o tictactoe.o ai.o +tictactoe: bin/main.o bin/tictactoe.o bin/ai.o + gcc -o tictactoe bin/main.o bin/tictactoe.o bin/ai.o -main.o: main.c - gcc -c main.c +bin/main.o: main.c + gcc -c main.c -o bin/main.o -tictactoe.o: tictactoe.c - gcc -c tictactoe.c +bin/tictactoe.o: tictactoe.c + gcc -c tictactoe.c -o bin/tictactoe.o -ai.o: ai.c - gcc -c ai.c +bin/ai.o: ai.c + gcc -c ai.c -o bin/ai.o clean: - rm -rf *.o tictactoe + rm -rf bin tictactoe + +outdir: bin + +bin: + mkdir -p bin