diff --git a/helpers/helpers.c b/helpers/helpers.c index 8d5a750811b485ed539fb9399117e83b6231c226..0cceed2ebf0e843a260cd1272337e221866efa19 100755 --- a/helpers/helpers.c +++ b/helpers/helpers.c @@ -62,12 +62,12 @@ void request_cofig(int *size, int *mode) printInColor("white", "please choose game mode:\n"); printf("-[1] for player vs player normal mode\n"); printf("-[2] for player vs computer normal mode \n"); - printf("-[3] for player vs computer smartAI Machine start the game (MIN_MAX)\n"); - printf("-[4] for player vs computer smartAI Player start the game (MIN_MAX)\n"); + printf("-[3] for player vs computer smartAI Minimax (normal)\n"); + printf("-[4] for player vs computer smartAI Minimax (Alpha beta)\n"); printf("---------------------------------------------------------------------------\n"); scanf("%d", mode); - while (*mode <= 0 || *mode > 5) + while (*mode <= 0 || *mode > 4) { printInColor("red", "please choose the correct option ! \n"); printInColor("white", " "); diff --git a/main.c b/main.c index 66a3b24cca62f44c051fd6d11786615da55d9918..1ead9566768f61b3913f15e162d9dc3734a8cbca 100755 --- a/main.c +++ b/main.c @@ -11,7 +11,7 @@ int main() { int size, mode; - request_cofig(&size, &mode); + request_cofig(&size, &mode); // display menu & request bord size board brd = board_alloc(size, size); switch (mode) @@ -23,14 +23,10 @@ int main() player_random_AI(brd); break; case 3: - player_vs_smart_ai_mini_max_machine_start(brd); + player_vs_smart_ai_mini_max(brd, false); break; case 4: - player_vs_smart_ai_mini_max_player_start(brd); - break; - - case 5: - ai_vs_ai(brd); + player_vs_smart_ai_mini_max(brd, true); break; default: diff --git a/play/play.c b/play/play.c index 2df0ae2daf7cc693508eaffef2039452390883f6..688a1ffb605597d5985ff9ea116d5a3ed0a4fc47 100755 --- a/play/play.c +++ b/play/play.c @@ -292,29 +292,81 @@ int remaining_case(board brd) int min(int a, int b) { - return (a < b) ? a : b; + return (a <= b) ? a : b; } int max(int a, int b) { - return (a > b) ? a : b; + return (a >= b) ? a : b; } int mini_max(board brd, bool is_max, int depth) { - if (brd->row >= 4) + int score = evaluate(brd); + + // if maximizer has won + if (score == 1) + return score * (remaining_case(brd) + 1); + + // if minimizer has won + if (score == -1) + return score * (remaining_case(brd) + 1); + + if (board_is_full(brd)) + { + return 0; + } + if (is_max) + { + int best_score = _MIN_INF_; + for (int i = 0; i < brd->row; i++) + { + for (int j = 0; j < brd->col; j++) + { + // the case is available + if (case_is_available(brd->matrix[i][j])) + { + // make a move + add_to_board(brd, i + 1, j + 1, PC); + + // calculate score of this move + best_score = max(best_score, mini_max(brd, false, depth + 1)); + // undo move + add_to_board(brd, i + 1, j + 1, (char)0); + } + } + } + return best_score; + } + else { - if (depth >= 7) + int best_score = _MAX_INF_; + + for (int i = 0; i < brd->row; i++) { - return 0; + for (int j = 0; j < brd->col; j++) + { + // the case is available + if (case_is_available(brd->matrix[i][j])) + { + // make a move + add_to_board(brd, i + 1, j + 1, PLAYER); + + best_score = min(best_score, mini_max(brd, true, depth + 1)); + // undo move + add_to_board(brd, i + 1, j + 1, (char)0); + } + } } + return best_score; } +} +int mini_max_alpha(board brd, bool is_max, int depth, int *alpha, int *beta) +{ int score = evaluate(brd); - // if the board is full - // if maximizer has won if (score == 1) return score * (remaining_case(brd) + 1); @@ -323,8 +375,10 @@ int mini_max(board brd, bool is_max, int depth) if (score == -1) return score * (remaining_case(brd) + 1); - if (board_is_full(brd)) + if (board_is_full(brd) || depth == brd->row) + { return 0; + } if (is_max) { int best_score = _MIN_INF_; @@ -339,9 +393,17 @@ int mini_max(board brd, bool is_max, int depth) add_to_board(brd, i + 1, j + 1, PC); // calculate score of this move - best_score = max(best_score, mini_max(brd, false, depth + 1)); + best_score = max(best_score, mini_max_alpha(brd, false, depth + 1, alpha, beta)); + // int score = mini_max(brd, false, depth + 1, alpha, beta); // undo move add_to_board(brd, i + 1, j + 1, (char)0); + // best_score = max(score, best_score); + + *alpha = max(*alpha, best_score); + if (best_score >= *beta) + { + return best_score; + } } } } @@ -361,11 +423,15 @@ int mini_max(board brd, bool is_max, int depth) // make a move add_to_board(brd, i + 1, j + 1, PLAYER); - // calculate score of this move - best_score = min(best_score, mini_max(brd, true, depth + 1)); - + best_score = min(best_score, mini_max_alpha(brd, true, depth + 1, alpha, beta)); // undo move add_to_board(brd, i + 1, j + 1, (char)0); + + *beta = min(*beta, best_score); + if (best_score <= *alpha) + { + return best_score; + } } } } @@ -402,13 +468,16 @@ void make_move(board brd, bool turn, int *i, int *j) *j = tmp_j; } -void best_move(board brd) +void best_move(board brd, bool machine_starts, bool prun) { int best_score = _MIN_INF_; move bst_move; bst_move.row = -1; bst_move.col = -1; + int alpha = _MIN_INF_; + int beta = _MAX_INF_; + // for available case add and undo -> to see best score for (int i = 0; i < brd->row; i++) { @@ -421,8 +490,8 @@ void best_move(board brd) add_to_board(brd, i + 1, j + 1, PC); // find max score - int score = mini_max(brd, false, 0); - printf("row: %d col: %d score : %d\n", i, j, score); + int score = (prun) ? mini_max_alpha(brd, machine_starts, 0, &alpha, &beta) : mini_max(brd, !machine_starts, 0); + // undo move add_to_board(brd, i + 1, j + 1, (char)0); // find the case with max probab @@ -569,12 +638,27 @@ void player_random_AI(board brd) } } } - -void player_vs_smart_ai_mini_max_machine_start(board brd) +void player_vs_smart_ai_mini_max(board brd, bool prun) { bool win = false; bool turn = true; // computer starts + printInColor("blue", "who starts the game :\n"); + printInColor("white", "[1] : you\n[2]: Machine ? \n"); + int t; + bool machin_start = false; + scanf("%d", &t); + + if (t == 1) + { + turn = false; + } + else + { + turn = true; + machin_start = true; + } + while (!win) { bool is_full = board_is_full(brd); @@ -582,7 +666,7 @@ void player_vs_smart_ai_mini_max_machine_start(board brd) { if (turn) { - best_move(brd); + best_move(brd, machin_start, prun); print_board(brd); if (evaluate(brd) == 1) @@ -628,198 +712,3 @@ void player_vs_smart_ai_mini_max_machine_start(board brd) } } } - -void player_vs_smart_ai_mini_max_player_start(board brd) -{ - - bool win = false; - - while (!win) - { - - bool is_full = board_is_full(brd); - if (!is_full) - { - int row, col; - printf("please choose the case by [row][col] :\n"); - scanf("%d %d", &row, &col); - - if (case_is_available(brd->matrix[row - 1][col - 1])) - { - add_to_board(brd, row, col, PLAYER); - print_board(brd); - - if (evaluate(brd) == -1) - { - printf("you win the game !!!\n"); - return; - } - // continue; - } - else - { - printInColor("red", "choose another box this box is taking\n"); - printInColor("white", " "); - continue; - } - - if (!board_is_full(brd)) - { - - best_move(brd); - print_board(brd); - - if (evaluate(brd) == 1) - { - printf("computer win the game !!!"); - return; - } - } - } - else - { - printf("the game is draw !!! \n"); - return; - } - } -} - -int min_max_double(board brd, bool is_max, int depth, bool turn) -{ - - if (brd->row >= 4) - { - if (depth > 8) - { - return 0; - } - } - - int score = evaluate(brd); - - // if the board is full - - // if maximizer has won - if (score == 1) - return score * (remaining_case(brd) + 1); - - // if minimizer has won - if (score == -1) - return score * (remaining_case(brd) + 1); - - if (board_is_full(brd)) - return 0; - if (is_max) - { - int best_score = _MIN_INF_; - for (int i = 0; i < brd->row; i++) - { - for (int j = 0; j < brd->col; j++) - { - // the case is available - if (case_is_available(brd->matrix[i][j])) - { - // make a move - add_to_board(brd, i + 1, j + 1, (turn) ? PC : PLAYER); - - // calculate score of this move - best_score = max(best_score, mini_max(brd, false, depth + 1)); - // undo move - add_to_board(brd, i + 1, j + 1, (char)0); - } - } - } - return best_score; - } - else - { - int best_score = _MAX_INF_; - - for (int i = 0; i < brd->row; i++) - { - for (int j = 0; j < brd->col; j++) - { - // the case is available - if (case_is_available(brd->matrix[i][j])) - { - // make a move - add_to_board(brd, i + 1, j + 1, (turn) ? PC : PLAYER); - - // calculate score of this move - best_score = min(best_score, mini_max(brd, true, depth + 1)); - - // undo move - add_to_board(brd, i + 1, j + 1, (char)0); - - // min(score, best_score_score); - } - } - } - return best_score; - } -} - -void best_move_o(board brd, bool turn) -{ - int best_score = _MIN_INF_; - move bst_move; - bst_move.row = -1; - bst_move.col = -1; - - // for available case add and undo -> to see best score - for (int i = 0; i < brd->row; i++) - { - for (int j = 0; j < brd->col; j++) - { - // the case is available - if (case_is_available(brd->matrix[i][j])) - { - // add move to evalaute - add_to_board(brd, i + 1, j + 1, (turn) ? PC : PLAYER); - - // find max score - int score = min_max_double(brd, false, 0, turn); - printf("row: %d col: %d score : %d\n", i, j, score); - // undo move - add_to_board(brd, i + 1, j + 1, (char)0); - // find the case with max probab - if (score > best_score) - { - bst_move.row = i; - bst_move.col = j; - best_score = score; - } - } - } - } - add_to_board(brd, bst_move.row + 1, bst_move.col + 1, (turn) ? PC : PLAYER); - - printf("\nmove : %d move : %d\n", bst_move.row, bst_move.col); -} -void ai_vs_ai(board brd) -{ - bool win = false; - bool turn = true; - while (!win) - { - - bool is_full = board_is_full(brd); - if (!is_full) - { - best_move_o(brd, !turn); - print_board(brd); - sleep(1); - turn = !turn; - if (evaluate(brd) == 1) - { - printf("pc 1 win the game !!!"); - return; - } - } - else - { - printf("the game is draw !!! \n"); - return; - } - } -} diff --git a/play/play.h b/play/play.h index 5c7b928a4c5ef4e63d8e114020f8ae9d7215bda5..48d8edda19e8f3d1b5a50facdf15cfaefac3290a 100755 --- a/play/play.h +++ b/play/play.h @@ -31,15 +31,14 @@ int check_win(board brd); bool case_is_available(char chr); void case_to_coordinates(board brd, int cas, int *i, int *j); bool board_is_full(board brd); + int mini_max(board brd, bool is_max, int depth); -void best_move(board brd); +int mini_max_alpha(board brd, bool is_max, int depth, int *alpha, int *beta); +void best_move(board brd, bool machine_starts, bool prun); void two_player(board brd); void player_random_AI(board brd); -void player_vs_smart_ai_mini_max_machine_start(board brd); - -void player_vs_smart_ai_mini_max_player_start(board brd); -void ai_vs_ai(board brd); +void player_vs_smart_ai_mini_max(board brd, bool prun); #endif \ No newline at end of file