From 42a235befbb4fc644ec806576211999a27ef1c6e Mon Sep 17 00:00:00 2001 From: Joursoir Date: Fri, 19 Feb 2021 19:00:50 +0000 Subject: add class artificial intelligence with functional --- ai.cpp | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ai.hpp | 19 +++++++++++ 2 files changed, 134 insertions(+) create mode 100644 ai.cpp create mode 100644 ai.hpp diff --git a/ai.cpp b/ai.cpp new file mode 100644 index 0000000..bef4567 --- /dev/null +++ b/ai.cpp @@ -0,0 +1,115 @@ +#include +#include + +#include "ai.hpp" +#include "GameField.hpp" + +enum scores { + MIN_SCORE = -1000, + MAX_SCORE = 1000, + NONE_SCORE = 0, + DRAW_SCORE = 2, + WIN_SCORE = 10, + LOSE_SCORE = -10 +}; + +AI::AI(int d) : max_depth(d) +{ + srand(time(NULL)); +} + +void AI::GetFirstMove(int &my, int &mx, int rows, int cols) +{ + my = rand() % rows; + mx = rand() % cols; +} + +void AI::GetBestMove(int &my, int &mx, GameField field) +{ + int score = MIN_SCORE; + int rows = field.GetRows(); + int cols = field.GetCols(); + + int y, x; + for(y = 0; y < rows; y++) { + for(x = 0; x < cols; x++) + { + if(!field.CanMove(y, x)) + continue; + field.Move(y, x); + int result = min(field, 1); // min because next move by player + field.UndoMove(y, x); + if(result > score) { + score = result; + my = y; + mx = x; + } + } + } +} + +int AI::score(GameField field) +{ + int state = field.GetState(); + if(state == G_DRAW) + return DRAW_SCORE; + if(state == G_XPLAYER) + return field.GetWhoMove() == G_XPLAYER ? WIN_SCORE : LOSE_SCORE; + if(state == G_OPLAYER) + return field.GetWhoMove() == G_OPLAYER ? WIN_SCORE : LOSE_SCORE; + return NONE_SCORE; +} + +int AI::min(GameField field, int depth) +{ + if(field.GetState() != G_NONE || depth >= max_depth) { + return score(field); + } + + int score = MAX_SCORE; + int rows = field.GetRows(); + int cols = field.GetCols(); + + int y, x; + for(y = 0; y < rows; y++) { + for(x = 0; x < cols; x++) + { + if(!field.CanMove(y, x)) + continue; + field.Move(y, x); + int result = max(field, depth + 1); + field.UndoMove(y, x); + if(result < score) + score = result; + } + } + + return score; +} + +int AI::max(GameField field, int depth) +{ + if(field.GetState() != G_NONE || depth >= max_depth) { + return score(field); + } + + int score = MIN_SCORE; + int rows = field.GetRows(); + int cols = field.GetCols(); + + int y, x; + for(y = 0; y < rows; y++) { + for(x = 0; x < cols; x++) + { + if(!field.CanMove(y, x)) + continue; + field.Move(y, x); + int result = max(field, depth + 1); + field.UndoMove(y, x); + if(result > score) + score = result; + } + } + + return score; +} diff --git a/ai.hpp b/ai.hpp new file mode 100644 index 0000000..19420e5 --- /dev/null +++ b/ai.hpp @@ -0,0 +1,19 @@ +#ifndef LPG_AI_H +#define LPG_AI_H + +class GameField; + +class AI { + int max_depth; +public: + AI(int d); + + void GetFirstMove(int &my, int &mx, int rows, int cols); + void GetBestMove(int &my, int &mx, GameField field); +private: + int score(GameField field); + int min(GameField field, int depth); + int max(GameField field, int depth); +}; + +#endif /* LPG_AI_H */ -- cgit v1.2.3-18-g5258