summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoursoir <chat@joursoir.net>2021-02-19 19:00:50 +0000
committerJoursoir <chat@joursoir.net>2021-02-19 19:00:50 +0000
commit42a235befbb4fc644ec806576211999a27ef1c6e (patch)
tree774908df1c4966c86b88cfea3e67dd7ee189cd0f
parent0f2504aaa684d53bb30a6d3c152e35f9dfe6e47e (diff)
downloadlp-gomoku-42a235befbb4fc644ec806576211999a27ef1c6e.tar.gz
lp-gomoku-42a235befbb4fc644ec806576211999a27ef1c6e.tar.bz2
lp-gomoku-42a235befbb4fc644ec806576211999a27ef1c6e.zip
add class artificial intelligence with functional
-rw-r--r--ai.cpp115
-rw-r--r--ai.hpp19
2 files changed, 134 insertions, 0 deletions
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 <stdlib.h>
+#include <time.h>
+
+#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 */