This repository has been archived on 2021-02-18. You can view files and clone it, but cannot push or open issues or pull requests.
chess/src/dev/kske/chess/game/ai/AIPlayer.java

106 lines
3.2 KiB
Java

package dev.kske.chess.game.ai;
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 java.util.concurrent.TimeUnit;
import javax.swing.SwingUtilities;
import dev.kske.chess.board.Board;
import dev.kske.chess.board.Move;
import dev.kske.chess.board.Piece.Color;
import dev.kske.chess.game.Player;
/**
* Project: <strong>Chess</strong><br>
* File: <strong>AIPlayer.java</strong><br>
* Created: <strong>06.07.2019</strong><br>
* Author: <strong>Kai S. K. Engelbart</strong>
*/
public class AIPlayer extends Player {
private int availableProcessors;
private int maxDepth;
private int alphaBetaThreshold;
private volatile boolean exitRequested;
private volatile ExecutorService executor;
public AIPlayer(Color color, int maxDepth, int alphaBetaThreshold) {
super(color);
name = "AIPlayer";
availableProcessors = Runtime.getRuntime().availableProcessors();
this.maxDepth = maxDepth;
this.alphaBetaThreshold = alphaBetaThreshold;
exitRequested = false;
}
@Override
public void requestMove() {
exitRequested = false;
/*
* Define some processing threads, split the available moves between them and
* retrieve the result after their execution.
*/
new Thread(() -> {
/*
* Get a copy of the board and the available moves.
*/
Board board = new Board(this.board);
List<Move> moves = board.getMoves(color);
/*
* Define move processors and split the available moves between them.
*/
int numThreads = Math.min(moves.size(), availableProcessors);
List<MoveProcessor> processors = new ArrayList<>(numThreads);
final int step = moves.size() / numThreads;
int rem = moves.size() % numThreads;
int beginIndex = 0, endIndex = 0;
for (int i = 0; i < numThreads; i++) {
if (rem-- > 0) ++endIndex;
endIndex += step;
processors.add(new MoveProcessor(new Board(board), moves.subList(beginIndex, endIndex), color,
maxDepth, alphaBetaThreshold));
beginIndex = endIndex;
}
/*
* Execute processors, get the best result and pass it back to the Game class
*/
executor = Executors.newFixedThreadPool(numThreads);
List<ProcessingResult> results = new ArrayList<>(numThreads);
try {
List<Future<ProcessingResult>> futures = executor.invokeAll(processors);
for (Future<ProcessingResult> f : futures)
results.add(f.get());
executor.shutdown();
} catch (InterruptedException | ExecutionException ex) {
ex.printStackTrace();
}
results.sort((r1, r2) -> Integer.compare(r2.score, r1.score));
if (!exitRequested) SwingUtilities.invokeLater(() -> game.onMove(this, results.get(0).move));
}, "AIPlayer calculation setup").start();
}
@Override
public void cancelMove() {
exitRequested = true;
if (executor != null) {
executor.shutdownNow();
try {
executor.awaitTermination(500, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
public void disconnect() {}
}