package chess.ai.ais; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import chess.ai.*; import chess.ai.actions.*; import chess.ai.alphabeta.*; import chess.controller.CommandExecutor; import chess.model.Color; import common.Signal1; /** * Extends AI. Bot based on the alpha-beta method of resolution. */ public class AlphaBetaAI extends AI { private final int searchDepth; private static final float MAX_FLOAT = Float.MAX_VALUE; private static final float MIN_FLOAT = -MAX_FLOAT; private final ExecutorService threadPool; public final Signal1 onStartEval = new Signal1<>(); public final Signal1 onCompleteEval = new Signal1<>(); public final Signal1 onProgress = new Signal1<>(); public AlphaBetaAI(CommandExecutor commandExecutor, Color color, int searchDepth) { super(commandExecutor, color); this.searchDepth = searchDepth; int threadCount = Runtime.getRuntime().availableProcessors(); this.threadPool = Executors.newFixedThreadPool(threadCount, new AlphaBetaThreadCreator(commandExecutor, color, threadCount)); } private AIAction getBestMove() { List actions = getAllowedActions(); List> moveEvaluations = new ArrayList<>(actions.size()); float bestMoveValue = MIN_FLOAT; AIAction bestMove = null; this.onStartEval.emit(actions.size()); for (AIAction action : actions) { moveEvaluations.add(this.threadPool.submit(() -> { return AlphaBetaThreadCreator.getMoveValue(action, this.searchDepth); })); } for (int i = 0; i < actions.size(); i++) { this.onProgress.emit((float) i / (float) actions.size()); AIAction action = actions.get(i); float value = MIN_FLOAT; try { value = moveEvaluations.get(i).get(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } if (value > bestMoveValue) { bestMoveValue = value; bestMove = action; } } this.onCompleteEval.emit(bestMoveValue); return bestMove; } @Override public void onGameEnd() { this.threadPool.close(); } @Override protected void play() { AIAction move = getBestMove(); move.applyAction(); } @Override public CommandExecutor getCommandExecutor() { return super.getCommandExecutor(); } }