Ai.java (2866B)
1 package nl.isygameclient.models; 2 3 import java.security.SecureRandom; 4 import java.util.*; 5 import nl.isygameclient.util.Vector2D; 6 7 public class Ai extends Player { 8 9 public static final int DEPTH = 5; 10 public static final Random AI_RANDOM = new Random(); 11 12 private final int[][] heuristics; 13 14 public Ai(String name, String playingAs, int[][] heuristics) { 15 super(name, playingAs); 16 this.heuristics = heuristics; 17 } 18 19 public static <T> T randomMove(Collection<T> possibleMoves) { 20 int size = possibleMoves.size(); 21 int item = AI_RANDOM.nextInt(size); // In real life, the Random object should be rather more shared than this 22 int i = 0; 23 for (T obj : possibleMoves) 24 if (i == item) 25 return obj; 26 else 27 i++; 28 return null; 29 } 30 31 private double miniMaxAlphaBeta(double alpha, double beta, Integer depth, boolean isMaximizing) { 32 var playerManager = game.getPlayerManager(); 33 var currentPlayer = playerManager.getCurrentPlayer(); 34 var possibleMoves = game.getValidMoves(currentPlayer); 35 36 if (depth == 0 || game.isGameOver()) { 37 return heuristicScore(currentPlayer); 38 } 39 40 double bestValue; 41 if (isMaximizing) { 42 bestValue = Double.MIN_VALUE; 43 for (Vector2D<Integer, Integer> move : possibleMoves) { 44 game.move(currentPlayer, move); 45 double value = miniMaxAlphaBeta(alpha, beta, depth - 1, false); 46 game.undo(); 47 48 bestValue = Math.max(bestValue, value); 49 alpha = Math.max(alpha, bestValue); 50 if (beta <= alpha) { 51 break; 52 } 53 } 54 55 } else { 56 bestValue = Double.MAX_VALUE; 57 for (Vector2D<Integer, Integer> move : possibleMoves) { 58 game.move(currentPlayer, move); 59 double value = miniMaxAlphaBeta(alpha, beta, depth - 1, true); 60 game.undo(); 61 62 bestValue = Math.min(bestValue, value); 63 beta = Math.min(beta, bestValue); 64 if (beta <= alpha) { 65 break; 66 } 67 } 68 } 69 return bestValue; 70 } 71 72 @Override 73 public Vector2D<Integer, Integer> onPlayerTurn() { 74 var manager = game.getPlayerManager(); 75 var currentPlayer = manager.getCurrentPlayer(); 76 var possibleMoves = game.getValidMoves(currentPlayer); 77 78 double bestValue = Integer.MIN_VALUE; 79 var bestMove = randomMove(possibleMoves); 80 81 for (Vector2D<Integer, Integer> move : possibleMoves) { 82 game.move(currentPlayer, move); 83 double moveValue = miniMaxAlphaBeta(Double.MIN_VALUE, Double.MAX_VALUE, DEPTH, false); 84 if (moveValue > bestValue) { 85 bestValue = moveValue; 86 bestMove = move; 87 } 88 game.undo(); 89 } 90 return bestMove; 91 } 92 93 public int heuristicScore(Player player) { 94 var board = game.getBoard(); 95 int score = 0; 96 for (int y = 0; y < board.getHeight(); y++) { 97 for (int x = 0; x < board.getWidth(); x++) { 98 if (Objects.equals(player, board.get(new Vector2D<>(x, y)))) { 99 score += heuristics[y][x]; 100 } 101 } 102 } 103 return score; 104 } 105 106 public void setGame(Game game) { 107 this.game = game; 108 } 109 }