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/MoveProcessor.java

124 lines
5.2 KiB
Java

package dev.kske.chess.game.ai;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import dev.kske.chess.board.Bishop;
import dev.kske.chess.board.Board;
import dev.kske.chess.board.King;
import dev.kske.chess.board.Knight;
import dev.kske.chess.board.Move;
import dev.kske.chess.board.Pawn;
import dev.kske.chess.board.Piece;
import dev.kske.chess.board.Piece.Color;
import dev.kske.chess.board.Queen;
import dev.kske.chess.board.Rook;
/**
* Project: <strong>Chess</strong><br>
* File: <strong>MoveProcessor.java</strong><br>
* Created: <strong>08.07.2019</strong><br>
*
* @since Chess v0.1-alpha
* @author Kai S. K. Engelbart
*/
public class MoveProcessor implements Callable<ProcessingResult> {
private final Board board;
private final List<Move> rootMoves;
private final Color color;
private final int maxDepth;
private final int alphaBetaThreshold;
private Move bestMove;
private static final Map<Class<? extends Piece>, int[][]> positionScores;
static {
positionScores = new HashMap<>();
positionScores.put(King.class,
new int[][] { new int[] { -3, -4, -4, -5, -5, -4, -4, -3 }, new int[] { -3, -4, -4, -5, -4, -4, -4, -3 },
new int[] { -3, -4, -4, -5, -4, -4, -4, -3 }, new int[] { -3, -4, -4, -5, -4, -4, -4, -3 },
new int[] { -2, -3, -3, -2, -2, -2, -2, -1 }, new int[] { -1, -2, -2, -2, -2, -2, -2, -1 },
new int[] { 2, 2, 0, 0, 0, 0, 2, 2 }, new int[] { 2, 3, 1, 0, 0, 1, 3, 2 } });
positionScores.put(Queen.class,
new int[][] { new int[] { -2, -1, -1, -1, -1, -1, -1, -2 }, new int[] { -1, 0, 0, 0, 0, 0, 0, -1 },
new int[] { -1, 0, 1, 1, 1, 1, 0, -1 }, new int[] { -1, 0, 1, 1, 1, 1, 0, -1 }, new int[] { 0, 0, 1, 1, 1, 1, 0, -1 },
new int[] { -1, 1, 1, 1, 1, 1, 0, -1 }, new int[] { -1, 0, 1, 0, 0, 0, 0, -1 },
new int[] { -2, -1, -1, -1, -1, -1, -1, -2 } });
positionScores.put(Rook.class,
new int[][] { new int[] { 0, 0, 0, 0, 0, 0, 0, 0 }, new int[] { 1, 1, 1, 1, 1, 1, 1, 1 }, new int[] { -1, 0, 0, 0, 0, 0, 0, -1 },
new int[] { -1, 0, 0, 0, 0, 0, 0, -1 }, new int[] { -1, 0, 0, 0, 0, 0, 0, -1 }, new int[] { -1, 0, 0, 0, 0, 0, 0, -1 },
new int[] { -1, 0, 0, 0, 0, 0, 0, -1 }, new int[] { 0, 0, 0, 1, 1, 0, 0, 0 } });
positionScores.put(Knight.class,
new int[][] { new int[] { -5, -4, -3, -3, -3, -3, -4, -5 }, new int[] { -4, -2, 0, 0, 0, 0, -2, -4 },
new int[] { -3, 0, 1, 2, 2, 1, 0, -3 }, new int[] { -3, 1, 2, 2, 2, 2, 1, -3 }, new int[] { -3, 0, 2, 2, 2, 2, 0, -1 },
new int[] { -3, 1, 1, 2, 2, 1, 1, -3 }, new int[] { -4, -2, 0, 1, 1, 0, -2, -4 },
new int[] { -5, -4, -3, -3, -3, -3, -4, -5 } });
positionScores.put(Bishop.class,
new int[][] { new int[] { -2, -1, -1, -1, -1, -1, -1, 2 }, new int[] { -1, 0, 0, 0, 0, 0, 0, -1 },
new int[] { -1, 0, 1, 1, 1, 1, 0, -1 }, new int[] { -1, 1, 1, 1, 1, 1, 1, -1 }, new int[] { -1, 0, 1, 1, 1, 1, 0, -1 },
new int[] { -1, 1, 1, 1, 1, 1, 1, -1 }, new int[] { -1, 1, 0, 0, 0, 0, 1, -1 },
new int[] { -2, -1, -1, -1, -1, -1, -1, -2 } });
positionScores.put(Pawn.class,
new int[][] { new int[] { 0, 0, 0, 0, 0, 0, 0, 0 }, new int[] { 5, 5, 5, 5, 5, 5, 5, 5 }, new int[] { 1, 1, 2, 3, 3, 2, 1, 1 },
new int[] { 0, 0, 1, 3, 3, 1, 0, 0 }, new int[] { 0, 0, 0, 2, 2, 0, 0, 0 }, new int[] { 0, 0, -1, 0, 0, -1, 0, 0 },
new int[] { 0, 1, 1, -2, -2, 1, 1, 0 }, new int[] { 0, 0, 0, 0, 0, 0, 0, 0 } });
}
public MoveProcessor(Board board, List<Move> rootMoves, Color color, int maxDepth, int alphaBetaThreshold) {
this.board = board;
this.rootMoves = rootMoves;
this.color = color;
this.maxDepth = maxDepth;
this.alphaBetaThreshold = alphaBetaThreshold;
}
@Override
public ProcessingResult call() throws Exception {
int score = miniMax(board, rootMoves, color, 0);
return new ProcessingResult(bestMove, score);
}
private int miniMax(Board board, List<Move> moves, Color color, int depth) {
int bestValue = Integer.MIN_VALUE;
for (Move move : moves) {
board.move(move);
int teamValue = evaluate(board, color);
int enemyValue = evaluate(board, color.opposite());
int valueChange = teamValue - enemyValue;
if (depth < maxDepth && valueChange >= alphaBetaThreshold)
valueChange -= miniMax(board, board.getMoves(color.opposite()), color.opposite(), depth + 1);
if (valueChange > bestValue) {
bestValue = valueChange;
if (depth == 0) bestMove = move;
}
board.revert();
}
return bestValue;
}
/**
* Evaluated a board.
*
* @param color The color to evaluate for
* @return An positive number representing how good the position is
*/
private int evaluate(Board board, Color color) {
int score = 0;
for (int i = 0; i < 8; i++)
for (int j = 0; j < 8; j++)
if (board.getBoardArr()[i][j] != null && board.getBoardArr()[i][j].getColor() == color) {
score += board.getBoardArr()[i][j].getValue();
if (positionScores.containsKey(board.getBoardArr()[i][j].getClass()))
score += positionScores.get(board.getBoardArr()[i][j].getClass())[i][color == Color.WHITE ? j : 7 - j];
}
return score;
}
}