Ai.java (5065B) download
1package nl.isygameclient.models;
2
3import com.google.gson.Gson;
4import com.google.gson.reflect.TypeToken;
5import nl.isygameclient.util.Vector2D;
6
7import java.io.IOException;
8import java.lang.reflect.Type;
9import java.nio.file.Files;
10import java.nio.file.NoSuchFileException;
11import java.nio.file.Paths;
12import java.util.*;
13
14public class Ai extends Player{
15
16 public static final int DEPTH = 5;
17
18 private int[][] heuristics;
19
20 public Ai(String name, String playingAs, int[][] heuristics) {
21 super(name, playingAs);
22 this.heuristics = heuristics;
23 }
24
25 public static Map<String, int[][]> loadHeuristics(String fileName) {
26 try {
27 Type mapType = new TypeToken<Map<String, int[][]>>() {
28 }.getType();
29 String inFile = new String(Files.readAllBytes(Paths.get(fileName)));
30 return new Gson().fromJson(inFile, mapType);
31 } catch (NoSuchFileException e) {
32 System.err.println("NO HEURISTICS JSON HAS BEEN PROVIDED.");
33 e.printStackTrace();
34 } catch (IOException e) {
35 e.printStackTrace();
36 }
37 return null;
38 }
39
40 public static <T> T randomMove(Collection<T> possibleMoves) {
41 int size = possibleMoves.size();
42 int item = new Random().nextInt(size); // In real life, the Random object should be rather more shared than this
43 int i = 0;
44 for (T obj : possibleMoves)
45 if (i == item)
46 return obj;
47 else
48 i++;
49 return null;
50 }
51
52 private double miniMax(Integer depth, boolean isMaximizing) {
53 var playerManager = game.getPlayerManager();
54 var currentPlayer = playerManager.getCurrentPlayer();
55 var possibleMoves = game.getValidMoves(currentPlayer);
56
57 if (depth == 0 || game.isGameOver()) {
58 return heuristicScore(currentPlayer);
59 }
60
61 double bestValue = isMaximizing ? 0 : Double.MAX_VALUE;
62 for (Vector2D<Integer, Integer> move : possibleMoves) {
63 game.move(currentPlayer, move);
64 double value = miniMax(depth - 1, !isMaximizing);
65 bestValue = isMaximizing ? Math.max(bestValue, value) : Math.min(bestValue, value);
66 game.undo();
67 }
68 return bestValue;
69 }
70
71 private double miniMaxAlphaBeta(double alpha, double beta, Integer depth, boolean isMaximizing) {
72 var playerManager = game.getPlayerManager();
73 var currentPlayer = playerManager.getCurrentPlayer();
74 var possibleMoves = game.getValidMoves(currentPlayer);
75
76 if (depth == 0 || game.isGameOver()) {
77 return heuristicScore(currentPlayer);
78 }
79
80 double bestValue;
81 if (isMaximizing) {
82 bestValue = Double.MIN_VALUE;
83 for (Vector2D<Integer, Integer> move : possibleMoves) {
84 game.move(currentPlayer, move);
85 double value = miniMaxAlphaBeta(alpha, beta, depth - 1, false);
86 game.undo();
87
88 bestValue = Math.max(bestValue, value);
89 alpha = Math.max(alpha, bestValue);
90 if (beta <= alpha) {
91 break;
92 }
93 }
94
95 } else {
96 bestValue = Double.MAX_VALUE;
97 for (Vector2D<Integer, Integer> move : possibleMoves) {
98 game.move(currentPlayer, move);
99 double value = miniMaxAlphaBeta(alpha, beta, depth - 1, true);
100 game.undo();
101
102 bestValue = Math.min(bestValue, value);
103 beta = Math.min(beta, bestValue);
104 if (beta <= alpha) {
105 break;
106 }
107 }
108 }
109 return bestValue;
110 }
111
112 @Override
113 public Vector2D<Integer, Integer> onPlayerTurn() {
114 var manager = game.getPlayerManager();
115 var currentPlayer = manager.getCurrentPlayer();
116 var possibleMoves = game.getValidMoves(currentPlayer);
117
118 double bestValue = Integer.MIN_VALUE;
119 var bestMove = randomMove(possibleMoves);
120
121 for (Vector2D<Integer, Integer> move : possibleMoves) {
122 game.move(currentPlayer, move);
123 double moveValue = miniMaxAlphaBeta(Double.MIN_VALUE, Double.MAX_VALUE, DEPTH, false);
124 if (moveValue > bestValue) {
125 bestValue = moveValue;
126 bestMove = move;
127 }
128 game.undo();
129 }
130 return bestMove;
131 }
132
133 public int heuristicScore(Player player) {
134 var board = game.getBoard();
135 int score = 0;
136 for (int y = 0; y < board.getHeight(); y++) {
137 for (int x = 0; x < board.getWidth(); x++) {
138 if (Objects.equals(player, board.get(new Vector2D<>(x, y)))) {
139 score += heuristics[y][x];
140 }
141 }
142 }
143 return score;
144 }
145
146 public void setGame(Game game) {
147 this.game = game;
148 }
149
150 public void setHeuristics(int[][] heuristics) {
151 this.heuristics = heuristics;
152 }
153}