game-client

Play TicTacToe and Reversi
Log | Files | Refs

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 }