├── .github
└── workflows
│ └── codeql-analysis.yml
├── README.md
├── SECURITY.md
├── pom.xml
└── src
├── main
└── java
│ ├── Engine.java
│ ├── Timer.java
│ ├── commons
│ ├── Color.java
│ ├── LegalMoves.java
│ ├── Line.java
│ ├── Piece.java
│ └── Utils.java
│ ├── game
│ ├── Board.java
│ ├── Cell.java
│ └── Move.java
│ └── pieces
│ ├── Bishop.java
│ ├── King.java
│ ├── Knight.java
│ ├── Pawn.java
│ ├── PieceType.java
│ ├── Queen.java
│ └── Rook.java
└── test
└── java
├── BishopTest.java
├── BoardTest.java
├── EngineTest.java
├── IntenseTest.java
├── KingTest.java
├── KnightTest.java
├── MinMaxTest.java
├── PawnTest.java
├── QueenTest.java
└── RookTest.java
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | #
7 | # ******** NOTE ********
8 | # We have attempted to detect the languages in your repository. Please check
9 | # the `language` matrix defined below to confirm you have the correct set of
10 | # supported CodeQL languages.
11 | #
12 | name: "CodeQL"
13 |
14 | on:
15 | push:
16 | branches: [ main ]
17 | pull_request:
18 | # The branches below must be a subset of the branches above
19 | branches: [ main ]
20 | schedule:
21 | - cron: '28 15 * * 6'
22 |
23 | jobs:
24 | analyze:
25 | name: Analyze
26 | runs-on: ubuntu-latest
27 | permissions:
28 | actions: read
29 | contents: read
30 | security-events: write
31 |
32 | strategy:
33 | fail-fast: false
34 | matrix:
35 | language: [ 'java' ]
36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
37 | # Learn more:
38 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
39 |
40 | steps:
41 | - name: Checkout repository
42 | uses: actions/checkout@v2
43 |
44 | # Initializes the CodeQL tools for scanning.
45 | - name: Initialize CodeQL
46 | uses: github/codeql-action/init@v1
47 | with:
48 | languages: ${{ matrix.language }}
49 | # If you wish to specify custom queries, you can do so here or in a config file.
50 | # By default, queries listed here will override any specified in a config file.
51 | # Prefix the list here with "+" to use these queries and those in the config file.
52 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
53 |
54 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
55 | # If this step fails, then you should remove it and run the build manually (see below)
56 | - name: Autobuild
57 | uses: github/codeql-action/autobuild@v1
58 |
59 | # ℹ️ Command-line programs to run using the OS shell.
60 | # 📚 https://git.io/JvXDl
61 |
62 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
63 | # and modify them (or add more) to build your code if your project
64 | # uses a compiled language
65 |
66 | #- run: |
67 | # make bootstrap
68 | # make release
69 |
70 | - name: Perform CodeQL Analysis
71 | uses: github/codeql-action/analyze@v1
72 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # chess-engine
2 |
3 | 
4 |
5 | ## Part 1:
6 |
7 | The chess engine can generate all legal moves for a given position upto an arbitrary depth.
8 | This includes: Move Engine
9 | ```
10 | -- pawn promotions
11 | -- enpassant moves
12 | -- castling
13 | ```
14 |
15 | The moves which are marked illegal are:
16 | ```
17 | -- x-rays to the king
18 | -- castling through check
19 | -- moves of a piece pinned to the king
20 | -- moving into check
21 | -- enpassant after one move
22 | ```
23 |
24 | The current move generator takes about 2 minutes to go to a depth of 6 ply.
25 |
26 |
27 | ## Part 2: Game Engine (In progress)
28 |
29 | The game engine will use the move generator to select a move. The first version will be using a min-max tree with optimisations to find the best move.
30 |
31 | This includes:
32 | ```
33 | -- basic heuristic ✅
34 | -- iterative deepening ✅
35 | -- alpha-beta pruning ✅
36 | -- killer heuristic
37 | -- quiescence search
38 | -- null heuristic
39 | -- parallel alpha-beta
40 | ```
41 |
42 | ## Part 3: Stochastic Chess Engine (In planning)
43 |
44 | The second version of the chess engine will use Monte Carlo Tree Search with basic hueristics.
45 |
46 | I do not hope much from it, since I don't have experience with neural network training and the compute power required to train NNs is usually high (I have a GPU, so not all hope lost).
47 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | ## Supported Versions
4 |
5 | Use this section to tell people about which versions of your project are
6 | currently being supported with security updates.
7 |
8 | | Version | Supported |
9 | | ------- | ------------------ |
10 | | 5.1.x | :white_check_mark: |
11 | | 5.0.x | :x: |
12 | | 4.0.x | :white_check_mark: |
13 | | < 4.0 | :x: |
14 |
15 | ## Reporting a Vulnerability
16 |
17 | Use this section to tell people how to report a vulnerability.
18 |
19 | Tell them where to go, how often they can expect to get an update on a
20 | reported vulnerability, what to expect if the vulnerability is accepted or
21 | declined, etc.
22 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | chess
8 | gkcs-chess-engine
9 | 1.0-SNAPSHOT
10 |
11 |
12 |
13 | org.apache.maven.plugins
14 | maven-compiler-plugin
15 |
16 | 11
17 | 11
18 |
19 |
20 |
21 |
22 |
23 |
24 | junit
25 | junit
26 | 4.13.1
27 | test
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/main/java/Engine.java:
--------------------------------------------------------------------------------
1 | import commons.Color;
2 | import game.Board;
3 | import game.Move;
4 |
5 | import java.util.Comparator;
6 | import java.util.HashMap;
7 | import java.util.List;
8 | import java.util.Map;
9 | import java.util.concurrent.CompletableFuture;
10 | import java.util.concurrent.ExecutionException;
11 | import java.util.concurrent.TimeUnit;
12 | import java.util.concurrent.TimeoutException;
13 | import java.util.stream.Collectors;
14 |
15 | public class Engine {
16 | public static int nodesEvaluated;
17 | public Map transpositionTable = new HashMap<>();
18 |
19 | public int countAllMoves(final Board board, final int depth) {
20 | return countAllMoves(board, depth, 1000);
21 | }
22 |
23 | public int countAllMoves(final Board board, final int depth, final int printAt) {
24 | final List legalMoves = board.getLegalMoves();
25 | if (legalMoves.isEmpty()) {
26 | return 0;
27 | }
28 | if (depth == 1) {
29 | return legalMoves.size();
30 | }
31 | return legalMoves.stream().mapToInt(move -> {
32 | final Board copy = board.copy();
33 | copy.makeMove(move);
34 | final int countAllMoves = countAllMoves(copy, depth - 1, printAt);
35 | if (depth == printAt) {
36 | System.out.println(getString(move) + ": " + countAllMoves + " " + move +
37 | " " + copy.fenRepresentation());
38 | }
39 | return countAllMoves;
40 | }).sum();
41 | }
42 |
43 | public Evaluation minMax(final Board board, final int depth, final int printAt) {
44 | final List legalMoves = board.getLegalMoves();
45 | nodesEvaluated++;
46 | if (legalMoves.isEmpty() || depth == 0) {
47 | return new Evaluation(null, -board.evaluation(legalMoves.size()));
48 | }
49 | Evaluation bestMove = null;
50 | for (Move move : legalMoves) {
51 | final Board copy = board.copy();
52 | copy.makeMove(move);
53 | final Evaluation eval = minMax(copy, depth - 1, printAt);
54 | if (depth == printAt) {
55 | System.out.println(getString(move) + ": " + eval.getScore() + " " + move +
56 | " " + copy.fenRepresentation());
57 | }
58 | if (bestMove == null || bestMove.getScore() > -eval.getScore()) {
59 | bestMove = new Evaluation(move, -eval.getScore());
60 | if (bestMove.getScore() < 0 && bestMove.getScore() + Integer.MAX_VALUE < 0.0001) {
61 | return bestMove;
62 | }
63 | }
64 | }
65 | return bestMove;
66 | }
67 |
68 | public OutCome alphaBeta(final Board board, final int depth, double alpha, double beta, final int printAt) {
69 | final List legalMoves = board.getLegalMoves();
70 | nodesEvaluated++;
71 | if (legalMoves.isEmpty() || depth == 0) {
72 | final double score;
73 | if (transpositionTable.containsKey(board.zobristHash)) {
74 | score = transpositionTable.get(board.zobristHash).eval;
75 | } else {
76 | score = board.evaluation(legalMoves.size());
77 | transpositionTable.put(board.zobristHash, new Result(score, 0));
78 | }
79 | return new OutCome(board, null, -score);
80 | }
81 | final List outComes = legalMoves.stream().map(move -> {
82 | final Board changedBoard = board.copy();
83 | changedBoard.makeMove(move);
84 | final double score;
85 | if (transpositionTable.containsKey(changedBoard.zobristHash)) {
86 | score = transpositionTable.get(changedBoard.zobristHash).eval;
87 | } else {
88 | score = changedBoard.evaluation(changedBoard.getLegalMoves().size());
89 | transpositionTable.put(changedBoard.zobristHash, new Result(score, 0));
90 | }
91 | return new OutCome(changedBoard, move, score);
92 | }).sorted(Comparator.comparingDouble(OutCome::getScore)).collect(Collectors.toList());
93 | OutCome bestOutCome = null;
94 | for (final OutCome outCome : outComes) {
95 | final OutCome eval = alphaBeta(outCome.getBoard(), depth - 1, alpha, beta, printAt);
96 | if (depth == printAt) {
97 | System.out.println(getString(outCome.getMove()) + ": " + eval.getScore() + " " + outCome +
98 | " " + outCome.getBoard().fenRepresentation());
99 | }
100 | if (bestOutCome == null || bestOutCome.getScore() > -eval.getScore()) {
101 | bestOutCome = new OutCome(board, outCome.getMove(), -eval.getScore());
102 | if (bestOutCome.getScore() < 0 && bestOutCome.getScore() + Integer.MAX_VALUE < 0.0001) {
103 | return bestOutCome;
104 | }
105 | }
106 | if (board.playerToMove.equals(Color.WHITE)) {
107 | if (alpha < -bestOutCome.getScore()) {
108 | alpha = -bestOutCome.getScore();
109 | }
110 | } else {
111 | if (beta > bestOutCome.getScore()) {
112 | beta = bestOutCome.getScore();
113 | }
114 | }
115 | if (alpha >= beta) {
116 | break;
117 | }
118 | }
119 | if (!transpositionTable.containsKey(board.zobristHash) || transpositionTable.get(board.zobristHash).depth < depth) {
120 | transpositionTable.put(board.zobristHash, new Result(-bestOutCome.getScore(), depth));
121 | }
122 | return bestOutCome;
123 | }
124 |
125 | public OutCome iterativeDeepening(final Board board, final long time) {
126 | transpositionTable = new HashMap<>();
127 | final long start = System.currentTimeMillis();
128 | int depth = 1;
129 | OutCome evaluation = alphaBeta(board, depth, Integer.MIN_VALUE, Integer.MAX_VALUE, 1000);
130 | while (System.currentTimeMillis() - start < time * 1000 && Math.abs(evaluation.getScore()) - Integer.MAX_VALUE < 0.0001) {
131 | depth++;
132 | System.out.println("DEPTH: " + depth + " EVAL: " + evaluation + " TIME: " + ((System.currentTimeMillis() - start) / 1000));
133 | try {
134 | int finalDepth = depth;
135 | evaluation = CompletableFuture.supplyAsync(() -> alphaBeta(board, finalDepth, Integer.MIN_VALUE, Integer.MAX_VALUE, 1000)).get(time * 1000 - (System.currentTimeMillis() - start), TimeUnit.MILLISECONDS);
136 | } catch (InterruptedException | ExecutionException | TimeoutException e) {
137 | System.out.println("TIMEOUT: " + depth);
138 | break;
139 | }
140 | }
141 | return evaluation;
142 | }
143 |
144 | private String getString(Move move) {
145 | return move.piece.position.notation() + move.target.notation();
146 | }
147 | }
148 |
149 | class Evaluation {
150 | private final Move move;
151 | private final double score;
152 |
153 | public Evaluation(Move move, double score) {
154 | this.move = move;
155 | this.score = score;
156 | }
157 |
158 | public double getScore() {
159 | return score;
160 | }
161 |
162 | public Move getMove() {
163 | return move;
164 | }
165 |
166 | @Override
167 | public String toString() {
168 | return "{" +
169 | "move=" + move +
170 | ", score=" + score +
171 | '}';
172 | }
173 | }
174 |
175 | class OutCome {
176 | private final Board board;
177 | private final Move move;
178 | private final double score;
179 |
180 | public OutCome(Board board, Move move, double score) {
181 | this.move = move;
182 | this.score = score;
183 | this.board = board;
184 | }
185 |
186 | public double getScore() {
187 | return score;
188 | }
189 |
190 | public Move getMove() {
191 | return move;
192 | }
193 |
194 | public Board getBoard() {
195 | return board;
196 | }
197 |
198 | @Override
199 | public String toString() {
200 | return "{" +
201 | "board=\n" + board +
202 | ", move=" + move +
203 | ", score=" + score +
204 | '}';
205 | }
206 | }
207 |
208 |
209 | class Result {
210 | final double eval;
211 | final int depth;
212 |
213 | public Result(double eval, int depth) {
214 | this.eval = eval;
215 | this.depth = depth;
216 | }
217 | }
--------------------------------------------------------------------------------
/src/main/java/Timer.java:
--------------------------------------------------------------------------------
1 | public class Timer {
2 | private long currentTime = System.nanoTime();
3 |
4 | public long getTimeElapsed() {
5 | final long start = currentTime;
6 | currentTime = System.nanoTime();
7 | return currentTime - start;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/commons/Color.java:
--------------------------------------------------------------------------------
1 | package commons;
2 |
3 | public enum Color {
4 | WHITE, BLACK;
5 |
6 | public static Color opponent(Color playerToMove) {
7 | return playerToMove == BLACK ? WHITE : BLACK;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/commons/LegalMoves.java:
--------------------------------------------------------------------------------
1 | package commons;
2 |
3 | import game.Move;
4 |
5 | import java.util.List;
6 | import java.util.Set;
7 |
8 | public class LegalMoves {
9 | public final Set moves;
10 | public final Set guards;
11 |
12 | public LegalMoves(Set moves, Set guards) {
13 | this.moves = moves;
14 | this.guards = guards;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/commons/Line.java:
--------------------------------------------------------------------------------
1 | package commons;
2 |
3 | import game.Cell;
4 | import pieces.PieceType;
5 |
6 | public class Line {
7 | public final int rowDiff;
8 | public final int colDiff;
9 | public final boolean isStraight;
10 | public final PieceType minorPieceType;
11 |
12 | public Line(final Cell first, final Cell second) {
13 | int rowDistance = Math.abs(first.row - second.row);
14 | int colDistance = Math.abs(first.col - second.col);
15 | isStraight = rowDistance == 0 || colDistance == 0 || rowDistance == colDistance;
16 | rowDiff = Integer.compare(first.row, second.row);
17 | colDiff = Integer.compare(first.col, second.col);
18 | minorPieceType = rowDiff == 0 || colDiff == 0 ? PieceType.ROOK : PieceType.BISHOP;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/commons/Piece.java:
--------------------------------------------------------------------------------
1 | package commons;
2 |
3 | import game.Board;
4 | import game.Cell;
5 | import game.Move;
6 | import pieces.*;
7 |
8 | import java.util.List;
9 | import java.util.Objects;
10 | import java.util.Set;
11 |
12 | public class Piece {
13 | public final Color color;
14 | public final Cell position;
15 | public final PieceType pieceType;
16 | private static final Piece[][][] pieces = getPieces();
17 |
18 | private static Piece[][][] getPieces() {
19 | final Piece[][][] pieces = new Piece[2][64][6];
20 | final Color[] colors = Color.values();
21 | final PieceType[] pieceTypes = PieceType.values();
22 | for (int i = 0; i < 2; i++) {
23 | for (int j = 0; j < 64; j++) {
24 | for (int k = 0; k < 6; k++) {
25 | pieces[i][j][k] = new Piece(colors[i], Cell.get((j >> 3), j & 7), pieceTypes[k]);
26 | }
27 | }
28 | }
29 | return pieces;
30 | }
31 |
32 | public static Piece get(Color color, Cell position, PieceType pieceType) {
33 | return pieces[color.ordinal()][(position.row << 3) + position.col][pieceType.ordinal()];
34 | }
35 |
36 | private Piece(Color color, Cell position, PieceType pieceType) {
37 | this.color = color;
38 | this.position = position;
39 | this.pieceType = pieceType;
40 | }
41 |
42 | @Override
43 | public boolean equals(Object o) {
44 | if (this == o) return true;
45 | if (o == null || getClass() != o.getClass()) return false;
46 | Piece piece = (Piece) o;
47 | return color == piece.color && position.equals(piece.position) && pieceType == piece.pieceType;
48 | }
49 |
50 | @Override
51 | public int hashCode() {
52 | return Objects.hash(color, position, pieceType);
53 | }
54 |
55 | public Set getMoveList(Board board) {
56 | switch (pieceType) {
57 | case BISHOP:
58 | return Bishop.getMoveList(board, this).moves;
59 | case KNIGHT:
60 | return Knight.getMoveList(board, this).moves;
61 | case ROOK:
62 | return Rook.getMoveList(board, this).moves;
63 | case KING:
64 | return King.getMoveList(board, this).moves;
65 | case QUEEN:
66 | return Queen.getMoveList(board, this).moves;
67 | case PAWN:
68 | return Pawn.getMoveList(board, this).moves;
69 | default:
70 | throw new IllegalStateException();
71 | }
72 | }
73 |
74 | public LegalMoves getLegalMoves(Board board) {
75 | switch (pieceType) {
76 | case BISHOP:
77 | return Bishop.getMoveList(board, this);
78 | case KNIGHT:
79 | return Knight.getMoveList(board, this);
80 | case ROOK:
81 | return Rook.getMoveList(board, this);
82 | case KING:
83 | return King.getMoveList(board, this);
84 | case QUEEN:
85 | return Queen.getMoveList(board, this);
86 | case PAWN:
87 | return Pawn.getMoveList(board, this);
88 | default:
89 | throw new IllegalStateException();
90 | }
91 | }
92 |
93 | public String getShortForm() {
94 | switch (pieceType) {
95 | case BISHOP:
96 | return color == Color.WHITE ? "♝" : "♗";
97 | case KNIGHT:
98 | return color == Color.WHITE ? "♞" : "♘";
99 | case ROOK:
100 | return color == Color.WHITE ? "♜" : "♖";
101 | case KING:
102 | return color == Color.WHITE ? "♚" : "♔";
103 | case QUEEN:
104 | return color == Color.WHITE ? "♛" : "♕";
105 | case PAWN:
106 | return color == Color.WHITE ? "♟" : "♙";
107 | default:
108 | throw new IllegalStateException();
109 | }
110 | }
111 |
112 |
113 | @Override
114 | public String toString() {
115 | return "(" + getShortForm() +
116 | ',' + position +
117 | ')';
118 | }
119 |
120 | public boolean sameType(PieceType pieceType) {
121 | return pieceType == this.pieceType;
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/src/main/java/commons/Utils.java:
--------------------------------------------------------------------------------
1 | package commons;
2 |
3 | import game.Board;
4 | import game.Cell;
5 | import game.Move;
6 |
7 | import java.util.HashSet;
8 | import java.util.Set;
9 | import java.util.function.BiFunction;
10 |
11 | public class Utils {
12 | public static LegalMoves getMoves(final Board board,
13 | final int maxDistance,
14 | final BiFunction isLegal,
15 | final Piece piece) {
16 | final Set moves = new HashSet<>();
17 | final Set guards = new HashSet<>();
18 | for (int rowDiff = -1; rowDiff <= 1; rowDiff++) {
19 | for (int colDiff = -1; colDiff <= 1; colDiff++) {
20 | boolean straightRow = rowDiff == 0;
21 | boolean straightCol = colDiff == 0;
22 | if (isLegal.apply(straightRow, straightCol) && !(straightRow && straightCol)) {
23 | int row = piece.position.row + rowDiff, col = piece.position.col + colDiff;
24 | for (int i = 1; i <= maxDistance; i++, row = row + rowDiff, col = col + colDiff) {
25 | if (Utils.withinBoardLimits(row, col)) {
26 | if (board.isEmpty(row, col)) {
27 | moves.add(Move.get(piece, Cell.get(row, col), false));
28 | } else {
29 | if (board.getPiece(row, col).color != piece.color) {
30 | moves.add(Move.get(piece, Cell.get(row, col), true));
31 | } else {
32 | guards.add(Move.get(piece, Cell.get(row, col), false));
33 | }
34 | break;
35 | }
36 | } else {
37 | break;
38 | }
39 | }
40 | }
41 | }
42 | }
43 | return new LegalMoves(moves, guards);
44 | }
45 |
46 | public static boolean withinBoardLimits(final int row, final int col) {
47 | return row < 8 && row >= 0 && col < 8 && col >= 0;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/game/Board.java:
--------------------------------------------------------------------------------
1 | package game;
2 |
3 | import commons.*;
4 | import pieces.Knight;
5 | import pieces.PieceType;
6 |
7 | import java.util.*;
8 | import java.util.function.BiConsumer;
9 | import java.util.function.Consumer;
10 | import java.util.stream.Collectors;
11 |
12 | public class Board {
13 | public final Map pieces;
14 | public final Map> playerPieces;
15 | public final Map> moves;
16 | public final Map> guards;
17 | public final List moveList;
18 | private final long[] positions;
19 | private int positionIndex;
20 | public final boolean[][] canCastle;
21 | public long zobristHash;
22 | public Color playerToMove;
23 | boolean isThreeFoldRepetition;
24 | int halfMoves;
25 | boolean fiftyMoveDraw;
26 | public boolean inCheck;
27 | public Move previousMove;
28 | private final Piece[] kings;
29 | public static final Map approxValue = new HashMap<>();
30 | private static long[][][] zobrist = new long[6][2][64];
31 | private static long zobristSwitchPlayer;
32 | public static long[] zobristCastle = new long[4];
33 | private static long[] zobristEnpassantFiles = new long[8];
34 |
35 | static {
36 | approxValue.put(PieceType.PAWN, 1);
37 | approxValue.put(PieceType.KNIGHT, 3);
38 | approxValue.put(PieceType.BISHOP, 3);
39 | approxValue.put(PieceType.ROOK, 5);
40 | approxValue.put(PieceType.QUEEN, 9);
41 | approxValue.put(PieceType.KING, 0);
42 | final Random random = new Random();
43 | for (int i = 0; i < 6; i++) {
44 | for (int j = 0; j < 2; j++) {
45 | for (int k = 0; k < 64; k++) {
46 | zobrist[i][j][k] = random.nextLong();
47 | }
48 | }
49 | }
50 | zobristSwitchPlayer = random.nextLong();
51 | for (int i = 0; i < 4; i++) {
52 | zobristCastle[i] = random.nextLong();
53 | }
54 | for (int i = 0; i < 8; i++) {
55 | zobristEnpassantFiles[i] = random.nextLong();
56 | }
57 | }
58 |
59 | public Board() {
60 | pieces = new HashMap<>();
61 | moves = new HashMap<>();
62 | guards = new HashMap<>();
63 | moveList = new ArrayList<>();
64 | canCastle = new boolean[][]{{true, true}, {true, true}};
65 | positions = new long[6];
66 | positionIndex = 0;
67 | playerPieces = new HashMap<>();
68 | playerPieces.put(Color.WHITE, new ArrayList<>());
69 | playerPieces.put(Color.BLACK, new ArrayList<>());
70 | playerToMove = Color.WHITE;
71 | kings = new Piece[2];
72 | }
73 |
74 | public boolean isEmpty(final int row, final int col) {
75 | return pieces.get(Cell.get(row, col)) == null;
76 | }
77 |
78 | public Piece getPiece(final int row, final int col) {
79 | return pieces.get(Cell.get(row, col));
80 | }
81 |
82 | public Set getMoveList(final Piece piece) {
83 | final Cell cell = piece.position;
84 | if (pieces.get(cell) != null) {
85 | populateMoves(cell);
86 | return moves.get(cell);
87 | } else {
88 | throw new NullPointerException();
89 | }
90 | }
91 |
92 | public Set getGuardList(final Piece piece) {
93 | final Cell cell = piece.position;
94 | if (pieces.get(cell) != null) {
95 | populateMoves(cell);
96 | return guards.get(cell);
97 | } else {
98 | throw new NullPointerException();
99 | }
100 | }
101 |
102 | private void populateMoves(Cell cell) {
103 | if (!moves.containsKey(cell) || !guards.containsKey(cell)) {
104 | final LegalMoves legalMoves = pieces.get(cell).getLegalMoves(this);
105 | moves.put(cell, legalMoves.moves);
106 | guards.put(cell, legalMoves.guards);
107 | }
108 | }
109 |
110 | public static Board getStartBoard() {
111 | final Board board = new Board();
112 | for (int i = 0; i < 8; i++) {
113 | board.placePawn(1, i, Color.WHITE);
114 | board.placePawn(6, i, Color.BLACK);
115 | }
116 | board.placeRook(0, 0, Color.WHITE);
117 | board.placeRook(0, 7, Color.WHITE);
118 | board.placeRook(7, 0, Color.BLACK);
119 | board.placeRook(7, 7, Color.BLACK);
120 |
121 | board.placeKnight(0, 1, Color.WHITE);
122 | board.placeKnight(0, 6, Color.WHITE);
123 | board.placeKnight(7, 1, Color.BLACK);
124 | board.placeKnight(7, 6, Color.BLACK);
125 |
126 | board.placeBishop(0, 2, Color.WHITE);
127 | board.placeBishop(0, 5, Color.WHITE);
128 | board.placeBishop(7, 2, Color.BLACK);
129 | board.placeBishop(7, 5, Color.BLACK);
130 |
131 | board.placeQueen(0, 3, Color.WHITE);
132 | board.placeQueen(7, 3, Color.BLACK);
133 |
134 | board.placeKing(0, 4, Color.WHITE);
135 | board.placeKing(7, 4, Color.BLACK);
136 |
137 | return board;
138 | }
139 |
140 | public void placePawn(final int row, final int col, final Color color) {
141 | final Cell position = Cell.get(row, col);
142 | final Piece pawn = Piece.get(color, position, PieceType.PAWN);
143 | pieces.put(position, pawn);
144 | playerPieces.get(color).add(pawn);
145 | updateHashForAddition(pawn);
146 | }
147 |
148 | public void placeRook(final int row, final int col, final Color color) {
149 | final Cell position = Cell.get(row, col);
150 | final Piece rook = Piece.get(color, position, PieceType.ROOK);
151 | pieces.put(position, rook);
152 | playerPieces.get(color).add(rook);
153 | updateHashForAddition(rook);
154 | }
155 |
156 | public void placeBishop(final int row, final int col, final Color color) {
157 | final Cell position = Cell.get(row, col);
158 | final Piece bishop = Piece.get(color, position, PieceType.BISHOP);
159 | pieces.put(position, bishop);
160 | playerPieces.get(color).add(bishop);
161 | updateHashForAddition(bishop);
162 | }
163 |
164 | public void placeQueen(final int row, final int col, final Color color) {
165 | final Cell position = Cell.get(row, col);
166 | final Piece queen = Piece.get(color, position, PieceType.QUEEN);
167 | pieces.put(position, queen);
168 | playerPieces.get(color).add(queen);
169 | updateHashForAddition(queen);
170 | }
171 |
172 | public void placeKing(final int row, final int col, final Color color) {
173 | final Cell position = Cell.get(row, col);
174 | final Piece king = Piece.get(color, position, PieceType.KING);
175 | kings[color.ordinal()] = king;
176 | pieces.put(position, king);
177 | playerPieces.get(color).add(king);
178 | updateHashForAddition(king);
179 | }
180 |
181 | public void placeKnight(final int row, final int col, final Color color) {
182 | final Cell position = Cell.get(row, col);
183 | final Piece knight = Piece.get(color, position, PieceType.KNIGHT);
184 | pieces.put(position, knight);
185 | playerPieces.get(color).add(knight);
186 | updateHashForAddition(knight);
187 | }
188 |
189 | public List getLegalMoves() {
190 | final Piece king = getKing(playerToMove);
191 | //better to check for pin from king than discoveries
192 | if (inCheck) {
193 | final Set attackers = attackingKing(king);
194 | final List legalMoves = new ArrayList<>(getMoveList(king));
195 | if (attackers.size() < 2) {
196 | final Set pinnedToKing = pinnedToKing(king).keySet();
197 | final List movableExceptKing = playerPieces.get(playerToMove).stream()
198 | .filter(piece -> !pinnedToKing.contains(piece))
199 | .filter(piece -> !(piece.sameType(PieceType.KING)))
200 | .collect(Collectors.toList());
201 | final Piece attacker = new ArrayList<>(attackers).get(0);
202 | final Set cellsWithCheck = rayOfCheck(king, attacker);
203 | if (attacker.sameType(PieceType.PAWN)) {
204 | //enPassant can capture a checking pawn
205 | movableExceptKing.stream()
206 | .filter(piece -> piece.sameType(PieceType.PAWN))
207 | .map(this::getMoveList)
208 | .flatMap(Collection::stream)
209 | .filter(move -> move.captureMove)
210 | .filter(move -> move.captureCell.equals(attacker.position))
211 | .filter(move -> !move.captureCell.equals(move.target))
212 | .forEach(legalMoves::add);
213 | }
214 | legalMoves.addAll(movableExceptKing.stream()
215 | .map(this::getMoveList)
216 | .flatMap(Collection::stream)
217 | .filter(move -> cellsWithCheck.contains(move.target))
218 | .collect(Collectors.toList()));
219 | }
220 | return legalMoves;
221 | } else {
222 | final Map pinnedToKing = pinnedToKing(king);
223 | final List normalMoves = playerPieces.get(playerToMove).stream()
224 | .filter(piece -> !pinnedToKing.containsKey(piece))
225 | .map(this::getMoveList)
226 | .flatMap(Collection::stream)
227 | .filter(move -> !illegalEnPassant(move, king))
228 | .collect(Collectors.toList());
229 | final List pinnedPieceMoves = pinnedToKing.entrySet()
230 | .stream()
231 | .filter(entry -> !entry.getKey().sameType(PieceType.KNIGHT))
232 | .map(this::getMovesWithinPin)
233 | .flatMap(Collection::stream)
234 | .collect(Collectors.toList());
235 | normalMoves.addAll(pinnedPieceMoves);
236 | return normalMoves;
237 | }
238 | }
239 |
240 | public Piece getKing(Color color) {
241 | return kings[color.ordinal()];
242 | }
243 |
244 | private List getMovesWithinPin(Map.Entry pinnedEntry) {
245 | final Piece pinnedPiece = pinnedEntry.getKey();
246 | final Piece attacker = pinnedEntry.getValue();
247 | final Piece king = getKing(pinnedPiece.color);
248 | final Set moves = getMoveList(pinnedPiece);
249 | final Line line = new Line(pinnedPiece.position, attacker.position);
250 | final Line inverse = new Line(pinnedPiece.position, king.position);
251 | if (line.isStraight) {
252 | return moves.stream().filter(move -> {
253 | final Line otherLine = new Line(move.piece.position, move.target);
254 | final boolean towardsAttacker = otherLine.isStraight && otherLine.rowDiff == line.rowDiff && otherLine.colDiff == line.colDiff;
255 | final boolean towardsKing = otherLine.isStraight && otherLine.rowDiff == inverse.rowDiff && otherLine.colDiff == inverse.colDiff;
256 | return towardsAttacker || towardsKing;
257 | }).collect(Collectors.toList());
258 | }
259 | return new ArrayList<>();
260 | }
261 |
262 | private boolean illegalEnPassant(final Move move, final Piece king) {
263 | if (move.piece.sameType(PieceType.PAWN) && move.captureMove && move.captureCell != move.target) {
264 | //does not expose an attack on the king.
265 | //The king is not discovered with the capture
266 | //ignore the captured and capturing pawn, and then check if the ray is a check.
267 | final Set ignorePawns = new HashSet<>();
268 | ignorePawns.add(move.piece);
269 | ignorePawns.add(getPiece(move.captureCell.row, move.captureCell.col));
270 | final Line line = new Line(move.captureCell, king.position);
271 | if (line.isStraight) {
272 | for (int row = king.position.row + line.rowDiff, col = king.position.col + line.colDiff; Utils.withinBoardLimits(row, col); row = row + line.rowDiff, col = col + line.colDiff) {
273 | if (!isEmpty(row, col) && !ignorePawns.contains(getPiece(row, col))) {
274 | final Piece piece = getPiece(row, col);
275 | return piece.color != king.color && (piece.sameType(line.minorPieceType) || piece.sameType(PieceType.QUEEN));
276 | } else if (move.target.equals(Cell.get(row, col))) {
277 | break;
278 | }
279 | }
280 | }
281 | }
282 | return false;
283 | }
284 |
285 | private Set rayOfCheck(Piece king, Piece attacker) {
286 | final Set stopCheck = new HashSet<>();
287 | if (attacker.sameType(PieceType.QUEEN) || attacker.sameType(PieceType.ROOK) || attacker.sameType(PieceType.BISHOP)) {
288 | final Line line = new Line(attacker.position, king.position);
289 | if (line.isStraight) {
290 | final int rowLowLimit = Math.min(attacker.position.row, king.position.row),
291 | rowHighLimit = Math.max(attacker.position.row, king.position.row),
292 | colLowLimit = Math.min(attacker.position.col, king.position.col),
293 | colHighLimit = Math.max(attacker.position.col, king.position.col);
294 | for (int i = 1; i < 8; i++) {
295 | final int row = king.position.row + i * line.rowDiff, col = king.position.col + i * line.colDiff;
296 | if (row >= rowLowLimit && row <= rowHighLimit && col >= colLowLimit && col <= colHighLimit) {
297 | stopCheck.add(Cell.get(row, col));
298 | }
299 | }
300 | stopCheck.remove(king.position);
301 | }
302 | }
303 | stopCheck.add(attacker.position);
304 | return stopCheck;
305 | }
306 |
307 | private Map pinnedToKing(Piece king) {
308 | final Map blockingChecks = new HashMap<>();
309 | final int kingRow = king.position.row, kingCol = king.position.col;
310 | final Color color = king.color;
311 | for (int rowDiff = -1; rowDiff <= 1; rowDiff++) {
312 | for (int colDiff = -1; colDiff <= 1; colDiff++) {
313 | if (!(rowDiff == 0 && colDiff == 0)) {
314 | final PieceType type = rowDiff == 0 || colDiff == 0 ? PieceType.ROOK : PieceType.BISHOP;
315 | final Reference blockingPiece = new Reference<>();
316 | for (int k = 1; k < 8; k++) {
317 | final int row = kingRow + (rowDiff * k), col = kingCol + (colDiff * k);
318 | if (Utils.withinBoardLimits(row, col)) {
319 | if (stopFindingPin(row, col, color, blockingPiece, blockingChecks, PieceType.QUEEN, type)) {
320 | break;
321 | }
322 | } else {
323 | break;
324 | }
325 | }
326 | }
327 | }
328 | }
329 | return blockingChecks;
330 | }
331 |
332 | public boolean stopFindingPin(int row, int col, Color color,
333 | Reference blockingPiece, Map blockingChecks,
334 | PieceType... attackerTypes) {
335 | if (!isEmpty(row, col)) {
336 | final Piece piece = getPiece(row, col);
337 | if (blockingPiece.object == null) {
338 | if (piece.color == color) {
339 | blockingPiece.object = piece;
340 | return false;
341 | } else {
342 | return true;
343 | }
344 | } else {
345 | if (piece.color != color && Arrays.stream(attackerTypes).anyMatch(piece::sameType)) {
346 | blockingChecks.put(blockingPiece.object, piece);
347 | }
348 | return true;
349 | }
350 | }
351 | return false;
352 | }
353 |
354 | private Set attackingKing(Piece king) {
355 | final HashSet attackers = new HashSet<>();
356 | final int kingRow = king.position.row, kingCol = king.position.col;
357 | final Color color = king.color;
358 | for (int rowDiff = -1; rowDiff <= 1; rowDiff++) {
359 | for (int colDiff = -1; colDiff <= 1; colDiff++) {
360 | if (!(rowDiff == 0 && colDiff == 0) && attackers.size() < 2) {
361 | final PieceType type = rowDiff == 0 || colDiff == 0 ? PieceType.ROOK : PieceType.BISHOP;
362 | for (int row = kingRow + rowDiff, col = kingCol + colDiff; Utils.withinBoardLimits(row, col); row = row + rowDiff, col = col + colDiff) {
363 | if (!isEmpty(row, col)) {
364 | final Piece piece = getPiece(row, col);
365 | if (piece.color != color && (piece.sameType(PieceType.QUEEN) || piece.sameType(type))) {
366 | attackers.add(piece);
367 | }
368 | break;
369 | }
370 | }
371 | }
372 | }
373 | }
374 | if (attackers.size() < 2) {
375 | final int pawnAttackRow = color == Color.BLACK ? kingRow - 1 : kingRow + 1;
376 | if (pawnAttackRow >= 0 && pawnAttackRow < 8) {
377 | final Piece leftPawn = kingCol > 0 ? getPiece(pawnAttackRow, kingCol - 1) : null;
378 | final Piece rightPawn = kingCol < 7 ? getPiece(pawnAttackRow, kingCol + 1) : null;
379 | if (rightPawn != null && rightPawn.sameType(PieceType.PAWN) && rightPawn.color != king.color) {
380 | attackers.add(rightPawn);
381 | } else if (leftPawn != null && leftPawn.sameType(PieceType.PAWN) && leftPawn.color != king.color) {
382 | attackers.add(leftPawn);
383 | }
384 | }
385 | for (int i = 0; i < Knight.diff.length && attackers.size() < 2; i++) {
386 | final int row = kingRow + Knight.diff[i][0], col = kingCol + Knight.diff[i][1];
387 | if (Utils.withinBoardLimits(row, col)) {
388 | final Piece piece = getPiece(row, col);
389 | if (piece != null && piece.sameType(PieceType.KNIGHT) && piece.color != king.color) {
390 | attackers.add(piece);
391 | }
392 | }
393 | }
394 | }
395 | return attackers;
396 | }
397 |
398 | private void updateHashForRemove(Piece piece) {
399 | zobristHash ^= zobrist[piece.pieceType.ordinal()][piece.color.ordinal()][(piece.position.row << 3) + piece.position.col];
400 | }
401 |
402 | private void updateHashForAddition(Piece piece) {
403 | zobristHash ^= zobrist[piece.pieceType.ordinal()][piece.color.ordinal()][(piece.position.row << 3) + piece.position.col];
404 | }
405 |
406 | public void makeMove(Move move) {
407 | //remove captured pieces
408 | final Set affectedCells = new HashSet<>();
409 | if (move.captureMove) {
410 | final Piece delete = pieces.remove(move.captureCell);
411 | playerPieces.get(Color.opponent(move.piece.color)).remove(delete);
412 | updateHashForRemove(delete);
413 | affectedCells.add(move.captureCell);
414 | }
415 | pieces.remove(move.piece.position);
416 | playerPieces.get(move.piece.color).remove(move.piece);
417 | updateHashForRemove(move.piece);
418 | affectedCells.add(move.piece.position);
419 | for (final Cell affectedCell : affectedCells) {
420 | //todo: don't remove all the moves and guards, just the ones affected
421 | updateForClearCell(affectedCell);
422 | }
423 | updateForBlockedCell(move);
424 | for (final Piece king : kings) {
425 | updateKingMoves(move, king);
426 | }
427 | removeUnusedEnpassant();
428 | moveOrPromote(move);
429 | postMoveUpdates(move);
430 | }
431 |
432 | private void updateKingMoves(Move move, Piece king) {
433 | final Cell target = move.target;
434 | final Cell start = move.piece.position;
435 | final Cell capture = move.captureCell;
436 | removeMoves(king.position);
437 | //add guard moves in vicinity
438 | //occupied cell allows more moves ->
439 | //occupied cell allows less moves -> Opponent long piece moved into square. Remove all squares affected.
440 | //free cell allows more moves -> Impossible
441 | //free cell allows less moves -> Opponent long piece on other side, remove squares affected.
442 | //nearby moves of pawn -> My pawns have no affect. Enemy can guard.
443 | //knight moves -> My knight has no affect. Enemy can guard.
444 | //king moves -> If it's my kind, remove moves. Else can guard.
445 | }
446 |
447 | private void updateForClearCell(final Cell affectedCell) {
448 | longRangeUpdate(affectedCell, (piece) -> {
449 | moves.get(piece.position).remove(Move.get(piece, affectedCell, true));
450 | guards.get(piece.position).remove(Move.get(piece, affectedCell, false));
451 | moves.get(piece.position).add(Move.get(piece, affectedCell, false));
452 | },
453 | (m, position) -> moves.get(position).add(m),
454 | (m, position) -> guards.get(position).add(m));
455 | for (final int[] coordinate : Knight.diff) {
456 | final int row = affectedCell.row + coordinate[0];
457 | final int col = affectedCell.col + coordinate[1];
458 | if (Utils.withinBoardLimits(row, col)) {
459 | if (!isEmpty(row, col)) {
460 | final Piece knight = getPiece(row, col);
461 | if (knight.sameType(PieceType.KNIGHT)) {
462 | if (moves.get(knight.position) != null) {
463 | moves.get(knight.position).remove(Move.get(knight, affectedCell, true));
464 | guards.get(knight.position).remove(Move.get(knight, affectedCell, false));
465 | moves.get(knight.position).add(Move.get(knight, affectedCell, false));
466 | }
467 | }
468 | }
469 | }
470 | }
471 | for (int i = -2; i <= 2; i++) {
472 | for (int j = -1; j <= 1; j++) {
473 | if (i != 0 || j != 0) {
474 | final int row = affectedCell.row + i;
475 | final int col = affectedCell.col + j;
476 | if (Utils.withinBoardLimits(row, col)) {
477 | if (!isEmpty(row, col)) {
478 | final Piece pawn = getPiece(row, col);
479 | if (pawn.sameType(PieceType.PAWN) && (pawn.color.equals(Color.BLACK) ? i > 0 : i < 0)) {
480 | removeMoves(pawn.position);
481 | }
482 | }
483 | }
484 | }
485 | }
486 | }
487 | }
488 |
489 | private void longRangeUpdate(final Cell affectedCell,
490 | final Consumer initialOperation,
491 | final BiConsumer moveUpdateOperation,
492 | final BiConsumer guardUpdateOperation) {
493 | for (int i = -1; i <= 1; i++) {
494 | for (int j = -1; j <= 1; j++) {
495 | final PieceType type = (i == 0 || j == 0) ? PieceType.ROOK : PieceType.BISHOP;
496 | if (i != 0 || j != 0) {
497 | for (int k = 0; k < 8; k++) {
498 | final int row = affectedCell.row + i * k;
499 | final int col = affectedCell.col + j * k;
500 | if (Utils.withinBoardLimits(row, col)) {
501 | if (!isEmpty(row, col)) {
502 | final Piece piece = getPiece(row, col);
503 | if (piece.sameType(PieceType.QUEEN) || piece.sameType(type)) {
504 | if (moves.get(piece.position) != null) {
505 | initialOperation.accept(piece);
506 | for (int l = 1; l < 8 - k; l++) {
507 | final int clearedRow = affectedCell.row - i * l;
508 | final int clearedCol = affectedCell.col - j * l;
509 | if (Utils.withinBoardLimits(clearedRow, clearedCol)) {
510 | final Cell visibleCell = Cell.get(clearedRow, clearedCol);
511 | if (isEmpty(clearedRow, clearedCol)) {
512 | moveUpdateOperation.accept(Move.get(piece, visibleCell, false), piece.position);
513 | } else {
514 | final Piece nowVisiblePiece = getPiece(clearedRow, clearedCol);
515 | if (nowVisiblePiece.color.equals(piece.color)) {
516 | guardUpdateOperation.accept(Move.get(piece, visibleCell, false), piece.position);
517 | } else {
518 | moveUpdateOperation.accept(Move.get(piece, visibleCell, true), piece.position);
519 | }
520 | break;
521 | }
522 | } else {
523 | break;
524 | }
525 | }
526 | }
527 | }
528 | break;
529 | }
530 | } else {
531 | break;
532 | }
533 | }
534 | }
535 | }
536 | }
537 | }
538 |
539 | private void updateForBlockedCell(final Move move) {
540 | final Cell affectedCell = move.target;
541 | longRangeUpdate(affectedCell, (piece) -> {
542 | moves.get(piece.position).remove(Move.get(piece, affectedCell, true));
543 | moves.get(piece.position).remove(Move.get(piece, affectedCell, false));
544 | guards.get(piece.position).remove(Move.get(piece, affectedCell, false));
545 | if (move.piece.color.equals(piece.color)) {
546 | guards.get(piece.position).add(Move.get(piece, affectedCell, false));
547 | } else {
548 | moves.get(piece.position).add(Move.get(piece, affectedCell, true));
549 | }
550 | },
551 | (m, position) -> moves.get(position).remove(m),
552 | (m, position) -> guards.get(position).remove(m));
553 | for (final int[] coordinate : Knight.diff) {
554 | final int row = affectedCell.row + coordinate[0];
555 | final int col = affectedCell.col + coordinate[1];
556 | if (Utils.withinBoardLimits(row, col)) {
557 | if (!isEmpty(row, col)) {
558 | final Piece knight = getPiece(row, col);
559 | if (knight.sameType(PieceType.KNIGHT)) {
560 | if (moves.get(knight.position) != null) {
561 | moves.get(knight.position).remove(Move.get(knight, affectedCell, true));
562 | moves.get(knight.position).remove(Move.get(knight, affectedCell, false));
563 | guards.get(knight.position).remove(Move.get(knight, affectedCell, false));
564 | if (move.piece.color.equals(knight.color)) {
565 | guards.get(knight.position).add(Move.get(knight, affectedCell, false));
566 | } else {
567 | moves.get(knight.position).add(Move.get(knight, affectedCell, true));
568 | }
569 | }
570 | }
571 | }
572 | }
573 | }
574 | removeMoves(affectedCell);
575 | for (int i = -2; i <= 2; i++) {
576 | for (int j = -1; j <= 1; j++) {
577 | if ((i != 0 || j != 0) && (Math.abs(i) + Math.abs(j) <= 2)) {
578 | final int row = affectedCell.row + i;
579 | final int col = affectedCell.col + j;
580 | if (Utils.withinBoardLimits(row, col)) {
581 | if (!isEmpty(row, col)) {
582 | final Piece pawn = getPiece(row, col);
583 | if (pawn.sameType(PieceType.PAWN) && (pawn.color == Color.BLACK ? i > 0 : i < 0)) {
584 | removeMoves(pawn.position);
585 | }
586 | }
587 | }
588 | }
589 | }
590 | }
591 | }
592 |
593 | private void removeUnusedEnpassant() {
594 | if (!moveList.isEmpty()) {
595 | final Move previousMoveOfCurrentPlayer = moveList.get(moveList.size() - 1);
596 | if (PieceType.PAWN.equals(previousMoveOfCurrentPlayer.piece.pieceType)) {
597 | final Piece pawnLastMoved = previousMoveOfCurrentPlayer.piece;
598 | if (Math.abs(previousMoveOfCurrentPlayer.target.row - pawnLastMoved.position.row) == 2) {
599 | final int row = previousMoveOfCurrentPlayer.target.row;
600 | for (int j = -1; j <= 1; j = j + 2) {
601 | int col = previousMoveOfCurrentPlayer.target.col + j;
602 | if (Utils.withinBoardLimits(row, col)) {
603 | if (!isEmpty(row, col)) {
604 | final Piece pawn = getPiece(row, col);
605 | if (pawn.sameType(PieceType.PAWN) && pawn.color != previousMoveOfCurrentPlayer.piece.color) {
606 | removeMoves(pawn.position);
607 | }
608 | }
609 | }
610 | }
611 | }
612 | }
613 | }
614 | }
615 |
616 | private void removeMoves(Cell position) {
617 | moves.remove(position);
618 | guards.remove(position);
619 | }
620 |
621 | private void moveOrPromote(Move move) {
622 | if (move.piece.sameType(PieceType.PAWN) && move.target.row == (playerToMove == Color.BLACK ? 0 : 7)) {
623 | switch (move.promoteTo) {
624 | case QUEEN:
625 | placeQueen(move.target.row, move.target.col, playerToMove);
626 | break;
627 | case ROOK:
628 | placeRook(move.target.row, move.target.col, playerToMove);
629 | break;
630 | case KNIGHT:
631 | placeKnight(move.target.row, move.target.col, playerToMove);
632 | break;
633 | case BISHOP:
634 | placeBishop(move.target.row, move.target.col, playerToMove);
635 | break;
636 | default:
637 | throw new AssertionError();
638 | }
639 | } else {
640 | final Piece changedPiece = Piece.get(move.piece.color, move.target, move.piece.pieceType);
641 | pieces.put(move.target, changedPiece);
642 | playerPieces.get(move.piece.color).add(changedPiece);
643 | updateHashForAddition(changedPiece);
644 | if (changedPiece.pieceType == PieceType.KING) {
645 | kings[changedPiece.color.ordinal()] = changedPiece;
646 | }
647 | }
648 | }
649 |
650 | public Board copy() {
651 | final Board board = new Board();
652 | pieces.forEach(board.pieces::put);
653 | playerPieces.forEach((color, pieces) -> board.playerPieces.put(color, new ArrayList<>(pieces)));
654 | moves.forEach((cell, moves) -> board.moves.put(cell, new HashSet<>(moves)));
655 | guards.forEach((cell, moves) -> board.guards.put(cell, new HashSet<>(moves)));
656 | System.arraycopy(positions, 0, board.positions, 0, positions.length);
657 | board.positionIndex = positionIndex;
658 | board.moveList.addAll(moveList);
659 | System.arraycopy(kings, 0, board.kings, 0, 2);
660 | for (int i = 0; i < 2; i++) {
661 | System.arraycopy(canCastle[i], 0, board.canCastle[i], 0, 2);
662 | }
663 | board.previousMove = previousMove;
664 | board.zobristHash = zobristHash;
665 | board.playerToMove = playerToMove;
666 | board.isThreeFoldRepetition = isThreeFoldRepetition;
667 | board.halfMoves = halfMoves;
668 | board.fiftyMoveDraw = fiftyMoveDraw;
669 | board.inCheck = inCheck;
670 | return board;
671 | }
672 |
673 | //todo: idea: Should we compare a list of positions and choose the best? We do not evaluate positions in isolation,
674 | // but rather rank them by comparing the top 20 positions possible
675 | public double evaluation(int availableMoves) {
676 | if (availableMoves == 0) {
677 | if (inCheck) {
678 | return Integer.MIN_VALUE;
679 | } else {
680 | return 0;
681 | }
682 | }
683 | if (isDraw()) {
684 | return 0;
685 | }
686 | return heuristic() + availableMoves / 100.0;
687 | }
688 |
689 | private int heuristic() {
690 | return playerPieces.get(playerToMove).stream().mapToInt(piece -> approxValue.get(piece.pieceType)).sum()
691 | - playerPieces.get(Color.opponent(playerToMove)).stream().mapToInt(piece -> approxValue.get(piece.pieceType)).sum();
692 | }
693 |
694 | public boolean isDraw() {
695 | if (isThreeFoldRepetition || fiftyMoveDraw) {
696 | return true;
697 | }
698 | final List currentPieces = playerPieces.get(playerToMove);
699 | final List opponentPieces = playerPieces.get(Color.opponent(playerToMove));
700 | final boolean playerCannotWin = insufficientMaterial(currentPieces);
701 | final boolean opponentCannotWin = insufficientMaterial(opponentPieces);
702 | return (playerCannotWin && opponentCannotWin);
703 | }
704 |
705 | private boolean insufficientMaterial(List opponentPieces) {
706 | if (opponentPieces.size() == 1) {
707 | return true;
708 | } else if (opponentPieces.size() == 2) {
709 | return opponentPieces.stream().filter(piece -> piece.sameType(PieceType.KNIGHT) || piece.sameType(PieceType.BISHOP)).count() == 1;
710 | } else if (opponentPieces.size() == 3) {
711 | return opponentPieces.stream().filter(piece -> piece.sameType(PieceType.KNIGHT)).count() == 2;
712 | }
713 | return false;
714 | }
715 |
716 | private void postMoveUpdates(Move move) {
717 | moveList.add(move);
718 | if (move.piece.sameType(PieceType.PAWN) && Math.abs(move.piece.position.row - move.target.row) == 2) {
719 | zobristHash ^= zobristEnpassantFiles[move.target.col];
720 | }
721 | if (previousMove != null && previousMove.piece.sameType(PieceType.PAWN) && Math.abs(previousMove.piece.position.row - previousMove.target.row) == 2) {
722 | zobristHash ^= zobristEnpassantFiles[previousMove.target.col];
723 | }
724 | previousMove = move;
725 | zobristHash ^= zobristSwitchPlayer;
726 | markDraw(move);
727 | castlingAllowance(move);
728 | inCheck = lookForChecks(move);
729 | playerToMove = Color.opponent(move.piece.color);
730 | }
731 |
732 | private void castlingAllowance(Move move) {
733 | if (move.piece.sameType(PieceType.KING)) {
734 | final int color = move.piece.color.ordinal();
735 | if (canCastle[color][0]) {
736 | zobristHash ^= zobristCastle[color * 2];
737 | }
738 | if (canCastle[color][1]) {
739 | zobristHash ^= zobristCastle[color * 2 + 1];
740 | }
741 | canCastle[color][1] = canCastle[color][0] = false;
742 | //take castling into account
743 | if (move.target.row == move.piece.position.row && Math.abs(move.piece.position.col - move.target.col) == 2) {
744 | final int row = color * 7;
745 | if (move.target.col == 6) {
746 | makeMove(Move.get(getPiece(row, 7), Cell.get(row, 5), false));
747 | } else {
748 | makeMove(Move.get(getPiece(row, 0), Cell.get(row, 3), false));
749 | }
750 | }
751 | } else {
752 | for (int i = 0; i <= 1; i++) {
753 | for (int j = 0; j <= 1; j++) {
754 | final Cell corner = Cell.get(i * 7, j * 7);
755 | if (move.piece.position.equals(corner) || (move.captureMove && move.captureCell.equals(corner))) {
756 | if (canCastle[i][j]) {
757 | if (move.piece.position.equals(Cell.get(i * 7, j * 7))) {
758 | if (canCastle[i][j]) {
759 | zobristHash ^= zobristCastle[i * 2 + j];
760 | }
761 | canCastle[i][j] = false;
762 | }
763 | }
764 | }
765 | }
766 | }
767 | }
768 | }
769 |
770 | private void markDraw(Move move) {
771 | positions[positionIndex % positions.length] = zobristHash;
772 | positionIndex++;
773 | int frequency = 0;
774 | for (final long position : positions) {
775 | if (position == zobristHash) {
776 | frequency++;
777 | if (frequency >= 3) {
778 | isThreeFoldRepetition = true;
779 | break;
780 | }
781 | }
782 | }
783 | if (move.captureMove || move.piece.sameType(PieceType.PAWN)) {
784 | halfMoves = 0;
785 | } else {
786 | halfMoves++;
787 | if (halfMoves == 100) {
788 | fiftyMoveDraw = true;
789 | }
790 | }
791 | }
792 |
793 | private boolean lookForChecks(Move move) {
794 | final Set moveList = getMoveList(pieces.get(move.target));
795 | for (final Move possibleMove : moveList) {
796 | if (possibleMove.captureMove && pieces.get(possibleMove.target).sameType(PieceType.KING)) {
797 | return true;
798 | }
799 | }
800 | final Piece king = kings[Color.opponent(playerToMove).ordinal()];
801 | return discoveredCheck(king, move.piece.position) || (move.captureMove && move.captureCell != move.target && discoveredCheck(king, move.captureCell));
802 | }
803 |
804 | private boolean discoveredCheck(Piece king, Cell coordinate) {
805 | //knight and pawn can't give discoveries
806 | final Line line = new Line(coordinate, king.position);
807 | if (line.isStraight) {
808 | for (int row = king.position.row + line.rowDiff, col = king.position.col + line.colDiff; Utils.withinBoardLimits(row, col); row = row + line.rowDiff, col = col + line.colDiff) {
809 | if (!isEmpty(row, col)) {
810 | final Piece piece = pieces.get(Cell.get(row, col));
811 | return piece.color != king.color && (piece.sameType(PieceType.QUEEN) || piece.sameType(line.minorPieceType));
812 | }
813 | }
814 | }
815 | return false;
816 | }
817 |
818 | @Override
819 | public String toString() {
820 | final StringBuilder stringBuilder = new StringBuilder();
821 | for (int i = 7; i >= 0; i--) {
822 | for (int j = 0; j < 8; j++) {
823 | if (isEmpty(i, j)) {
824 | stringBuilder.append((i + j) % 2 == 0 ? "◻" : "◼");
825 | } else {
826 | stringBuilder.append(getPiece(i, j).getShortForm());
827 | }
828 | }
829 | stringBuilder.append('\n');
830 | }
831 | stringBuilder.append("{\npieces=")
832 | .append(pieces).append('\n')
833 | .append("moveList=").append(moveList).append('\n')
834 | .append("inCheck: ").append(inCheck).append("\n}");
835 | return stringBuilder.toString();
836 | }
837 |
838 | public String fenRepresentation() {
839 | final StringBuilder stringBuilder = new StringBuilder();
840 | for (int i = 7; i >= 0; i--) {
841 | int count = 0;
842 | for (int j = 0; j < 8; j++) {
843 | if (isEmpty(i, j)) {
844 | count++;
845 | } else {
846 | if (count > 0) {
847 | stringBuilder.append(count);
848 | count = 0;
849 | }
850 | final Piece piece = getPiece(i, j);
851 | char letter = piece.pieceType.getLetter();
852 | if (piece.color == Color.WHITE) {
853 | letter = (char) (letter - 'a' + 'A');
854 | }
855 | stringBuilder.append(letter);
856 | }
857 | }
858 | if (count > 0) {
859 | stringBuilder.append(count);
860 | }
861 | if (i > 0) {
862 | stringBuilder.append('/');
863 | }
864 | }
865 | stringBuilder.append(' ')
866 | .append(playerToMove == Color.WHITE ? 'w' : 'b')
867 | .append(' ')
868 | .append(castlingAllowanceFen(canCastle))
869 | .append(' ');
870 | if (!moveList.isEmpty()) {
871 | final Move lastMove = moveList.get(moveList.size() - 1);
872 | if (lastMove.piece.sameType(PieceType.PAWN) && Math.abs(lastMove.piece.position.row - lastMove.target.row) == 2) {
873 | stringBuilder.append((char) (lastMove.target.col + 'a')).append((lastMove.target.row + (lastMove.piece.color == Color.BLACK ? 2 : 0)));
874 | } else {
875 | stringBuilder.append('-');
876 | }
877 | } else {
878 | stringBuilder.append('-');
879 | }
880 | return stringBuilder.toString();
881 | }
882 |
883 | public static Board getBoard(String fen) {
884 | Board board = new Board();
885 | String[] boardFen = fen.split(" ");
886 | String[] rows = boardFen[0].split("/");
887 | for (int i = 0; i < 8; i++) {
888 | int index = 0;
889 | for (int j = 0; j < rows[i].length(); j++) {
890 | final char current = rows[i].charAt(j);
891 | if (Character.isDigit(current)) {
892 | index += current - '0';
893 | } else {
894 | final Color color = Character.isUpperCase(current) ? Color.WHITE : Color.BLACK;
895 | final int row = 7 - i;
896 | switch (Character.toLowerCase(current)) {
897 | case 'p':
898 | board.placePawn(row, index, color);
899 | break;
900 | case 'n':
901 | board.placeKnight(row, index, color);
902 | break;
903 | case 'b':
904 | board.placeBishop(row, index, color);
905 | break;
906 | case 'r':
907 | board.placeRook(row, index, color);
908 | break;
909 | case 'q':
910 | board.placeQueen(row, index, color);
911 | break;
912 | case 'k':
913 | board.placeKing(row, index, color);
914 | break;
915 | }
916 | index++;
917 | }
918 | }
919 | }
920 | board.playerToMove = boardFen[1].equals("w") ? Color.WHITE : Color.BLACK;
921 | if (board.playerToMove == Color.BLACK) {
922 | board.zobristHash ^= zobristSwitchPlayer;
923 | }
924 | board.canCastle[0][1] = boardFen[2].contains("K");
925 | board.canCastle[0][0] = boardFen[2].contains("Q");
926 | board.canCastle[1][1] = boardFen[2].contains("k");
927 | board.canCastle[1][0] = boardFen[2].contains("q");
928 | for (int i = 0; i < 2; i++) {
929 | for (int j = 0; j < 2; j++) {
930 | if (!board.canCastle[i][j]) {
931 | board.zobristHash ^= zobristCastle[i * 2 + j];
932 | }
933 | }
934 | }
935 | if (!boardFen[3].equals("-")) {
936 | int rowDiff = boardFen[3].charAt(1) == '6' ? -1 : 1;
937 | final int col = boardFen[3].charAt(0) - 'a';
938 | final int row = rowDiff == -1 ? 4 : 3;
939 | final Piece pawn = board.getPiece(row, col);
940 | board.moveList.add(Move.get(Piece.get(pawn.color, Cell.get(rowDiff == -1 ? 6 : 1, col), PieceType.PAWN), pawn.position, false));
941 | board.zobristHash ^= zobristEnpassantFiles[col];
942 | }
943 | return board;
944 | }
945 |
946 | private String castlingAllowanceFen(boolean[][] canCastle) {
947 | String result = "";
948 | if (canCastle[0][1]) {
949 | result = result + "K";
950 | }
951 | if (canCastle[0][0]) {
952 | result = result + "Q";
953 | }
954 | if (canCastle[1][1]) {
955 | result = result + "k";
956 | }
957 | if (canCastle[1][0]) {
958 | result = result + "q";
959 | }
960 | return result.equals("") ? "-" : result;
961 | }
962 |
963 | private static class Reference {
964 | T object;
965 | }
966 | }
--------------------------------------------------------------------------------
/src/main/java/game/Cell.java:
--------------------------------------------------------------------------------
1 | package game;
2 |
3 | public class Cell {
4 | public final int row, col;
5 |
6 | private static final Cell[] cells = setBoard();
7 |
8 | private Cell(int row, int col) {
9 | this.row = row;
10 | this.col = col;
11 | }
12 |
13 | public static Cell get(final int row, final int col) {
14 | return cells[(row << 3) + col];
15 | }
16 |
17 | private static Cell[] setBoard() {
18 | final Cell[] cells = new Cell[64];
19 | for (int i = 0; i < 8; i++) {
20 | for (int j = 0; j < 8; j++) {
21 | cells[(i << 3) + j] = new Cell(i, j);
22 | }
23 | }
24 | return cells;
25 | }
26 |
27 | @Override
28 | public String toString() {
29 | return "(" + row +
30 | ',' + col +
31 | ')';
32 | }
33 |
34 | public String notation() {
35 | return Character.valueOf((char) (col + 'a')).toString() + (row + 1);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/game/Move.java:
--------------------------------------------------------------------------------
1 | package game;
2 |
3 | import commons.Piece;
4 | import pieces.PieceType;
5 |
6 | import java.util.HashMap;
7 | import java.util.Map;
8 | import java.util.Objects;
9 |
10 | public class Move {
11 | public final Piece piece;
12 | public final Cell target;
13 | public final boolean captureMove;
14 | public final Cell captureCell;
15 | public final PieceType promoteTo;
16 | private final int id;
17 | private static final Map moveMap = new HashMap<>();
18 |
19 | public static int count = 0;
20 |
21 | public static Move get(Piece piece, Cell end, boolean captureMove) {
22 | return get(piece, end, captureMove, captureMove ? end : null, null);
23 | }
24 |
25 | public static Move get(Piece piece, Cell end, boolean captureMove, Cell captureCell) {
26 | return get(piece, end, captureMove, captureMove ? captureCell : null, null);
27 | }
28 |
29 | public static Move get(Piece piece, Cell end, boolean captureMove, Cell captureCell, PieceType promoteTo) {
30 | final int colorIndex = piece.color.ordinal() << 6;
31 | final int positionIndex = (piece.position.row << 3) + piece.position.col;
32 | final int pieceIndex = (colorIndex + positionIndex) * 6 + piece.pieceType.ordinal();
33 | final int travelIndex = (end.row << 3) + end.col;
34 | final int captureIndex = captureMove ? ((captureCell.row << 3) + captureCell.col) + 1 : 0;
35 | final int promotionIndex = promoteTo == null ? 0 : promoteTo.ordinal() + 1;
36 | final int index = (((pieceIndex << 9) + travelIndex) * 65 + captureIndex) * 7 + promotionIndex;
37 | if (!moveMap.containsKey(index)) {
38 | moveMap.put(index, new Move(piece, end, captureMove, captureCell, promoteTo, index));
39 | }
40 | return moveMap.get(index);
41 | }
42 |
43 | private Move(Piece piece, Cell target, boolean captureMove, Cell captureCell, PieceType promoteTo, final int id) {
44 | count++;
45 | this.piece = piece;
46 | this.target = target;
47 | this.captureMove = captureMove;
48 | this.captureCell = captureCell;
49 | this.promoteTo = promoteTo;
50 | this.id = id;
51 | }
52 |
53 | @Override
54 | public String toString() {
55 | return "{" + printMove(piece, target) +
56 | ", captureMove=" + captureMove +
57 | ", captureCell=" + captureCell +
58 | ", promoteTo=" + promoteTo +
59 | '}';
60 | }
61 |
62 | private String printMove(Piece piece, Cell cell) {
63 | return piece.getShortForm() + "," + piece.position.notation() + cell.notation();
64 | }
65 |
66 | @Override
67 | public boolean equals(Object o) {
68 | if (this == o) return true;
69 | if (o == null || getClass() != o.getClass()) return false;
70 | Move move = (Move) o;
71 | return id == move.id;
72 | }
73 |
74 | @Override
75 | public int hashCode() {
76 | return id;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/main/java/pieces/Bishop.java:
--------------------------------------------------------------------------------
1 | package pieces;
2 |
3 | import commons.LegalMoves;
4 | import commons.Piece;
5 | import commons.Utils;
6 | import game.Board;
7 |
8 | import java.util.function.BiFunction;
9 |
10 | public class Bishop {
11 |
12 | public static final BiFunction movement = (rowStraight, colStraight) -> !rowStraight && !colStraight;
13 | public static final int MAX_DISTANCE = 7;
14 |
15 | public static LegalMoves getMoveList(Board board, Piece piece) {
16 | return Utils.getMoves(board, MAX_DISTANCE, movement, piece);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/pieces/King.java:
--------------------------------------------------------------------------------
1 | package pieces;
2 |
3 | import commons.*;
4 | import game.Board;
5 | import game.Cell;
6 | import game.Move;
7 |
8 | import java.util.*;
9 | import java.util.function.BiFunction;
10 | import java.util.stream.Collectors;
11 |
12 | public class King {
13 |
14 | public static final BiFunction movement = (rowStraight, colStraight) -> true;
15 | public static final int MAX_DISTANCE = 1;
16 |
17 | public static LegalMoves getMoveList(Board board, Piece piece) {
18 | final LegalMoves legalMoves = Utils.getMoves(board, MAX_DISTANCE, movement, piece);
19 | filterIllegalMoves(board, legalMoves.moves, piece);
20 | return legalMoves;
21 | }
22 |
23 | private static void filterIllegalMoves(Board board, Set moves, Piece king) {
24 | final Set illegalSquares = getIllegalSquares(board, Color.opponent(king.color),
25 | moves.stream().map(move -> move.target).collect(Collectors.toSet()), king.position);
26 | moves.removeIf(move -> illegalSquares.contains(move.target));
27 | if (board.inCheck) {
28 | moves.removeIf(move -> xRay(move, board, king));
29 | } else {
30 | final Move[] castles = castlingMoves(board, king, moves);
31 | for (int i = 0; i < castles.length && castles[i] != null; i++) {
32 | moves.add(castles[i]);
33 | }
34 | }
35 | }
36 |
37 | private static Set getIllegalSquares(final Board board,
38 | final Color opponentColor,
39 | final Set positions,
40 | final Cell kingPosition) {
41 | final Set illegalSquares = new HashSet<>();
42 | final List pieces = board.playerPieces.get(opponentColor).stream()
43 | .filter(piece -> withinKingRange(kingPosition, piece.pieceType, piece.position))
44 | .sorted(Comparator.comparingInt(piece -> -Board.approxValue.get(piece.pieceType)))
45 | .collect(Collectors.toList());
46 | for (final Cell kingMove : positions) {
47 | for (final Piece piece : pieces) {
48 | final int rowDiff = Math.abs(piece.position.row - kingMove.row);
49 | final int colDiff = Math.abs(piece.position.col - kingMove.col);
50 | final int diagDiff = Math.abs(Math.abs(piece.position.col - piece.position.row) - Math.abs(kingMove.col - kingMove.row));
51 | final int revDiff = Math.abs(piece.position.col + piece.position.row - (kingMove.col + kingMove.row));
52 | switch (piece.pieceType) {
53 | case BISHOP:
54 | if (diagDiff <= 0 || revDiff <= 0) {
55 | if (board.getMoveList(piece).contains(Move.get(piece, kingMove, false))
56 | || board.getGuardList(piece).contains(Move.get(piece, kingMove, false))) {
57 | illegalSquares.add(kingMove);
58 | }
59 | }
60 | break;
61 | case ROOK:
62 | if (rowDiff <= 0 || colDiff <= 0) {
63 | if (board.getMoveList(piece).contains(Move.get(piece, kingMove, false))
64 | || board.getGuardList(piece).contains(Move.get(piece, kingMove, false))) {
65 | illegalSquares.add(kingMove);
66 | }
67 | }
68 | break;
69 | case KING:
70 | if ((rowDiff == 1 || colDiff == 1) && (rowDiff <= 1 && colDiff <= 1)) {
71 | for (int i = -1; i <= 1; i++) {
72 | for (int j = -1; j <= 1; j++) {
73 | final int row = piece.position.row + i;
74 | final int col = piece.position.col + j;
75 | if (Utils.withinBoardLimits(row, col)) {
76 | illegalSquares.add(Cell.get(row, col));
77 | }
78 | }
79 | }
80 | }
81 | break;
82 | case PAWN:
83 | if (rowDiff == 1 && colDiff == 1 &&
84 | (opponentColor.equals(Color.WHITE) ? (kingMove.row > piece.position.row) : (kingMove.row < piece.position.row))) {
85 | illegalSquares.add(kingMove);
86 | }
87 | break;
88 | case KNIGHT:
89 | if (rowDiff <= 2 && colDiff <= 2 && rowDiff + colDiff == 3) {
90 | if (board.getMoveList(piece).contains(Move.get(piece, kingMove, false))
91 | || board.getGuardList(piece).contains(Move.get(piece, kingMove, false))) {
92 | illegalSquares.add(kingMove);
93 | }
94 | }
95 | break;
96 | case QUEEN:
97 | if (rowDiff <= 0 || colDiff <= 0 || diagDiff <= 0 || revDiff <= 0) {
98 | if (board.getMoveList(piece).contains(Move.get(piece, kingMove, false))
99 | || board.getGuardList(piece).contains(Move.get(piece, kingMove, false))) {
100 | illegalSquares.add(kingMove);
101 | }
102 | }
103 | break;
104 | }
105 | if (illegalSquares.contains(kingMove)) {
106 | break;
107 | }
108 | }
109 | }
110 | return illegalSquares;
111 | }
112 |
113 | public static boolean withinKingRange(final Cell kingPosition,
114 | final PieceType pieceType,
115 | final Cell piecePosition) {
116 | final int rowDiff = Math.abs(piecePosition.row - kingPosition.row);
117 | final int colDiff = Math.abs(piecePosition.col - kingPosition.col);
118 | final int diagDiff = Math.abs(Math.abs(piecePosition.col - piecePosition.row) - Math.abs(kingPosition.col - kingPosition.row));
119 | final int revDiff = Math.abs(piecePosition.col + piecePosition.row - (kingPosition.col + kingPosition.row));
120 | switch (pieceType) {
121 | case BISHOP:
122 | return diagDiff <= 2 || revDiff <= 2;
123 | case ROOK:
124 | return rowDiff <= 1 || colDiff <= 1;
125 | case KING:
126 | return (rowDiff == 2 || colDiff == 2) && (rowDiff <= 2 && colDiff <= 2);
127 | case PAWN:
128 | return rowDiff <= 2 && colDiff <= 2;
129 | case KNIGHT:
130 | return rowDiff <= 3 && colDiff <= 3 && rowDiff + colDiff <= 5;
131 | case QUEEN:
132 | return rowDiff <= 1 || colDiff <= 1 || diagDiff <= 2 || revDiff <= 2;
133 | }
134 | return false;
135 | }
136 |
137 | private static Move[] castlingMoves(final Board board, final Piece king, final Set kingMoves) {
138 | final Move[] castleMoves = new Move[2];
139 | int castles = 0;
140 | final int row = king.color.ordinal() * 7;
141 | if (king.position.row == row) {
142 | for (int i = 0; i <= 1; i++) {
143 | if (board.canCastle[king.color.ordinal()][i]) {
144 | final Piece rook = board.getPiece(row, i * 7);
145 | if (rook != null && rook.sameType(PieceType.ROOK)) {
146 | final int colDiff = i == 0 ? -1 : 1;
147 | final int col = 4 + colDiff;
148 | final boolean clear = board.isEmpty(row, col)
149 | && kingMoves.stream()
150 | .map(move -> move.target)
151 | .anyMatch(cell -> Cell.get(row, col).equals(cell));
152 | final Cell kingCastleCell = Cell.get(row, col + colDiff);
153 | if (clear && board.isEmpty(row, col + colDiff) && !getIllegalSquares(board, Color.opponent(king.color), Collections.singleton(kingCastleCell), kingCastleCell).contains(kingCastleCell)) {
154 | if (i == 1 || board.isEmpty(row, 1)) {
155 | castleMoves[castles++] = Move.get(king, Cell.get(row, 4 + 2 * colDiff), false);
156 | }
157 | }
158 | }
159 | }
160 | }
161 | }
162 | return castleMoves;
163 | }
164 |
165 | private static boolean xRay(Move move, Board board, Piece king) {
166 | final Line line = new Line(move.piece.position, move.target);
167 | for (int index = 1; index < 8; index++) {
168 | final int row = move.piece.position.row + index * line.rowDiff, col = move.piece.position.col + index * line.colDiff;
169 | if (Utils.withinBoardLimits(row, col)) {
170 | if (!board.isEmpty(row, col)) {
171 | final Piece piece = board.getPiece(row, col);
172 | return piece.color != king.color && (piece.sameType(line.minorPieceType) || piece.sameType(PieceType.QUEEN));
173 | }
174 | } else {
175 | break;
176 | }
177 | }
178 | return false;
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/src/main/java/pieces/Knight.java:
--------------------------------------------------------------------------------
1 | package pieces;
2 |
3 | import commons.LegalMoves;
4 | import commons.Piece;
5 | import commons.Utils;
6 | import game.Board;
7 | import game.Cell;
8 | import game.Move;
9 |
10 | import java.util.HashSet;
11 | import java.util.Set;
12 |
13 | public class Knight {
14 | public static final int[][] diff = new int[][]{
15 | {2, 1}, {1, 2},
16 | {2, -1}, {1, -2},
17 | {-2, -1}, {-1, -2},
18 | {-2, 1}, {-1, 2}
19 | };
20 |
21 | public static LegalMoves getMoveList(Board board, Piece piece) {
22 | final Set moves = new HashSet<>(8);
23 | final Set guards = new HashSet<>(8);
24 | for (final int[] coordinate : diff) {
25 | final int row = piece.position.row + coordinate[0], col = piece.position.col + coordinate[1];
26 | if (Utils.withinBoardLimits(row, col)) {
27 | if (board.isEmpty(row, col)) {
28 | moves.add(Move.get(piece, Cell.get(row, col), false));
29 | } else if (board.getPiece(row, col).color != piece.color) {
30 | moves.add(Move.get(piece, Cell.get(row, col), true));
31 | } else {
32 | guards.add(Move.get(piece, Cell.get(row, col), false));
33 | }
34 | }
35 | }
36 | return new LegalMoves(moves, guards);
37 | }
38 | }
--------------------------------------------------------------------------------
/src/main/java/pieces/Pawn.java:
--------------------------------------------------------------------------------
1 | package pieces;
2 |
3 | import commons.Color;
4 | import commons.LegalMoves;
5 | import commons.Piece;
6 | import game.Board;
7 | import game.Cell;
8 | import game.Move;
9 |
10 | import java.util.HashSet;
11 | import java.util.Set;
12 |
13 | public class Pawn {
14 |
15 | public static LegalMoves getMoveList(Board board, Piece piece) {
16 | final Set moves = new HashSet<>(8);
17 | final Set guards = new HashSet<>(8);
18 | final int rowDiff = piece.color == Color.WHITE ? 1 : -1;
19 | final int row = piece.position.row + rowDiff;
20 | if (row < 8 && row >= 0) {
21 | PieceType[] pieces = null;
22 | if (row == 7 || row == 0) {
23 | pieces = new PieceType[]{PieceType.QUEEN, PieceType.ROOK, PieceType.BISHOP, PieceType.KNIGHT};
24 | }
25 | if (board.isEmpty(row, piece.position.col)) {
26 | addMoves(Cell.get(row, piece.position.col), false, pieces, moves, piece);
27 | }
28 | for (int i = -1; i <= 1; i = i + 2) {
29 | final int col = piece.position.col + i;
30 | if (col < 8 && col >= 0) {
31 | final Piece diag = board.getPiece(row, col);
32 | if (diag != null && diag.color != piece.color) {
33 | addMoves(Cell.get(row, col), true, pieces, moves, piece);
34 | }
35 | if (diag == null || diag.color == piece.color) {
36 | guards.add(Move.get(piece, Cell.get(row, col), false));
37 | }
38 | }
39 | }
40 | if (piece.position.row == (piece.color == Color.BLACK ? 6 : 1)) {
41 | if (board.isEmpty(row, piece.position.col)
42 | && board.isEmpty(piece.position.row + 2 * rowDiff, piece.position.col)) {
43 | moves.add(Move.get(piece, Cell.get(piece.position.row + 2 * rowDiff, piece.position.col), false));
44 | }
45 | }
46 | }
47 | addEnPassant(board, rowDiff, moves, piece);
48 | return new LegalMoves(moves, guards);
49 | }
50 |
51 | private static void addEnPassant(Board board, int rowDiff, Set moves, Piece piece) {
52 | if (!board.moveList.isEmpty()) {
53 | final Move lastMove = board.moveList.get(board.moveList.size() - 1);
54 | if (allowsEnPassant(lastMove, piece) && piece.position.row == (piece.color == Color.BLACK ? 3 : 4)) {
55 | final int colDiff = lastMove.target.col - piece.position.col;
56 | final int col = piece.position.col + colDiff;
57 | if (Math.abs(colDiff) == 1 && col < 8 && col >= 0) {
58 | final Piece diag = board.getPiece(piece.position.row, col);
59 | if (diag != null && diag.sameType(PieceType.PAWN) && diag.color != piece.color) {
60 | final Move enPassant = Move.get(piece, Cell.get(piece.position.row + rowDiff, col), true, lastMove.target);
61 | moves.add(enPassant);
62 | }
63 | }
64 | }
65 | }
66 | }
67 |
68 | private static boolean allowsEnPassant(final Move move, Piece piece) {
69 | return move.piece.sameType(PieceType.PAWN) && Math.abs(move.piece.position.row - move.target.row) == 2 && Math.abs(move.target.col - piece.position.col) == 1;
70 | }
71 |
72 | private static void addMoves(Cell destination, boolean capture, PieceType[] pieces, Set moves, Piece piece) {
73 | if (pieces == null) {
74 | moves.add(Move.get(piece, destination, capture));
75 | } else {
76 | for (final PieceType pieceType : pieces) {
77 | moves.add(Move.get(piece, destination, capture, capture ? destination : null, pieceType));
78 | }
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/main/java/pieces/PieceType.java:
--------------------------------------------------------------------------------
1 | package pieces;
2 |
3 | public enum PieceType {
4 | PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING;
5 |
6 | public char getLetter() {
7 | switch (ordinal()) {
8 | case 0:
9 | return 'p';
10 | case 1:
11 | return 'n';
12 | case 2:
13 | return 'b';
14 | case 3:
15 | return 'r';
16 | case 4:
17 | return 'q';
18 | case 5:
19 | return 'k';
20 | }
21 | throw new RuntimeException();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/pieces/Queen.java:
--------------------------------------------------------------------------------
1 | package pieces;
2 |
3 | import commons.LegalMoves;
4 | import commons.Piece;
5 | import commons.Utils;
6 | import game.Board;
7 | import game.Move;
8 |
9 | import java.util.HashSet;
10 | import java.util.Set;
11 | import java.util.function.BiFunction;
12 |
13 | public class Queen {
14 | public static final BiFunction movement = (rowStraight, colStraight) -> true;
15 | public static final int MAX_DISTANCE = 7;
16 |
17 | public static LegalMoves getMoveList(Board board, Piece piece) {
18 | return Utils.getMoves(board, MAX_DISTANCE, movement, piece);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/pieces/Rook.java:
--------------------------------------------------------------------------------
1 | package pieces;
2 |
3 | import commons.LegalMoves;
4 | import commons.Piece;
5 | import commons.Utils;
6 | import game.Board;
7 |
8 | import java.util.function.BiFunction;
9 |
10 |
11 | public class Rook {
12 | public static final BiFunction movement = (rowStraight, colStraight) -> rowStraight || colStraight;
13 | public static final int MAX_DISTANCE = 7;
14 |
15 | public static LegalMoves getMoveList(Board board, Piece piece) {
16 | return Utils.getMoves(board, MAX_DISTANCE, movement, piece);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/test/java/BishopTest.java:
--------------------------------------------------------------------------------
1 | import commons.Color;
2 | import game.Board;
3 | import org.junit.Assert;
4 | import org.junit.Test;
5 |
6 | public class BishopTest {
7 | @Test
8 | public void moveForward() {
9 | Board board = new Board();
10 | board.placeBishop(0, 0, Color.BLACK);
11 | System.out.println(board);
12 | System.out.println(board.getPiece(0, 0).getMoveList(board));
13 | Assert.assertEquals(7, board.getPiece(0, 0).getMoveList(board).size());
14 | }
15 |
16 | @Test
17 | public void moveAsBishop() {
18 | Board board = new Board();
19 | board.placeBishop(3, 3, Color.BLACK);
20 | System.out.println(board);
21 | System.out.println(board.getPiece(3, 3).getMoveList(board));
22 | Assert.assertEquals(13, board.getPiece(3, 3).getMoveList(board).size());
23 | }
24 |
25 | @Test
26 | public void blockedByPawn() {
27 | Board board = new Board();
28 | board.placeBishop(3, 3, Color.BLACK);
29 | board.placePawn(4, 4, Color.BLACK);
30 | System.out.println(board);
31 | System.out.println(board.getPiece(3, 3).getMoveList(board));
32 | Assert.assertEquals(9, board.getPiece(3, 3).getMoveList(board).size());
33 | Assert.assertTrue(board.getPiece(3, 3).getMoveList(board).stream().noneMatch(c -> c.captureMove));
34 | }
35 |
36 | @Test
37 | public void blockedByEnemyPawn() {
38 | Board board = new Board();
39 | board.placeBishop(3, 3, Color.BLACK);
40 | board.placePawn(4, 4, Color.WHITE);
41 | System.out.println(board);
42 | System.out.println(board.getPiece(3, 3).getMoveList(board));
43 | Assert.assertEquals(10, board.getPiece(3, 3).getMoveList(board).size());
44 | }
45 |
46 | @Test
47 | public void surroundedByPieces() {
48 | Board board = new Board();
49 | board.placeBishop(3, 3, Color.BLACK);
50 | board.placePawn(4, 4, Color.BLACK);
51 | board.placePawn(2, 2, Color.BLACK);
52 | board.placeRook(4, 2, Color.BLACK);
53 | board.placeRook(2, 4, Color.BLACK);
54 | System.out.println(board);
55 | System.out.println(board.getPiece(3, 3).getMoveList(board));
56 | Assert.assertTrue(board.getPiece(3, 3).getMoveList(board).isEmpty());
57 | }
58 |
59 | @Test
60 | public void surroundedByEnemy() {
61 | Board board = new Board();
62 | board.placeBishop(3, 3, Color.BLACK);
63 | board.placePawn(4, 4, Color.WHITE);
64 | board.placePawn(2, 2, Color.WHITE);
65 | board.placeRook(4, 2, Color.WHITE);
66 | board.placeRook(2, 4, Color.WHITE);
67 | System.out.println(board);
68 | System.out.println(board.getPiece(3, 3).getMoveList(board));
69 | Assert.assertEquals(4, board.getPiece(3, 3).getMoveList(board).size());
70 | Assert.assertTrue(board.getPiece(3, 3).getMoveList(board).stream().allMatch(c -> c.captureMove));
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/test/java/BoardTest.java:
--------------------------------------------------------------------------------
1 | import commons.Color;
2 | import game.Board;
3 | import game.Cell;
4 | import game.Move;
5 | import org.junit.Assert;
6 | import org.junit.Test;
7 | import pieces.PieceType;
8 |
9 | import java.util.List;
10 | import java.util.NoSuchElementException;
11 |
12 | public class BoardTest {
13 |
14 | @Test
15 | public void startingBoard() {
16 | Board board = Board.getStartBoard();
17 | final List legalMoves = board.getLegalMoves();
18 | Assert.assertEquals(20, legalMoves.size());
19 | }
20 |
21 | @Test
22 | public void blockCheck() {
23 | Board board = new Board();
24 | board.placeKing(2, 5, Color.WHITE);
25 | board.placeRook(2, 0, Color.BLACK);
26 | board.placeKing(4, 4, Color.BLACK);
27 | board.placeBishop(1, 1, Color.WHITE);
28 | board.inCheck = true;
29 | System.out.println(board);
30 | System.out.println(board.getLegalMoves());
31 | Assert.assertEquals(6, board.getLegalMoves().size());
32 | }
33 |
34 | @Test
35 | public void captureAndReturnCheck() {
36 | Board board = new Board();
37 | board.placeKing(2, 5, Color.WHITE);
38 | board.placeRook(2, 2, Color.BLACK);
39 | board.placeKing(4, 4, Color.BLACK);
40 | board.placeBishop(1, 3, Color.WHITE);
41 | board.inCheck = true;
42 | System.out.println(board);
43 | System.out.println(board.getLegalMoves());
44 | Assert.assertEquals(6, board.getLegalMoves().size());
45 | Assert.assertFalse(board.isDraw());
46 | Assert.assertEquals(-2, board.evaluation(board.getLegalMoves().size()), 0.3);
47 | board.makeMove(board.getLegalMoves().stream().filter(c -> c.captureMove).findAny().get());
48 | System.out.println(board);
49 | System.out.println(board.getLegalMoves());
50 | Assert.assertTrue(board.inCheck);
51 | Assert.assertEquals(Color.BLACK, board.playerToMove);
52 | Assert.assertTrue(board.isDraw());
53 | Assert.assertEquals(4, board.getLegalMoves().size());
54 | }
55 |
56 | @Test
57 | public void checkMate() {
58 | Board board = new Board();
59 | board.placeKing(7, 5, Color.WHITE);
60 | board.placeRook(7, 2, Color.BLACK);
61 | board.placeRook(6, 3, Color.BLACK);
62 | board.placeKing(4, 4, Color.BLACK);
63 | board.inCheck = true;
64 | System.out.println(board);
65 | System.out.println(board.getLegalMoves());
66 | Assert.assertTrue(board.getLegalMoves().isEmpty());
67 | Assert.assertEquals(Integer.MIN_VALUE, board.evaluation(board.getLegalMoves().size()), 0.0001);
68 | }
69 |
70 | @Test
71 | public void staleMate() {
72 | Board board = new Board();
73 | board.placeKing(7, 5, Color.WHITE);
74 | board.placeRook(6, 2, Color.BLACK);
75 | board.placeRook(3, 4, Color.BLACK);
76 | board.placeKing(7, 7, Color.BLACK);
77 | System.out.println(board);
78 | System.out.println(board.getLegalMoves());
79 | Assert.assertTrue(board.getLegalMoves().isEmpty());
80 | Assert.assertEquals(0, board.evaluation(board.getLegalMoves().size()), 0.000001);
81 | }
82 |
83 | @Test
84 | public void checkMateIn1() {
85 | Board board = new Board();
86 | board.placeKing(7, 5, Color.WHITE);
87 | board.placeRook(6, 2, Color.BLACK);
88 | board.placeRook(3, 4, Color.BLACK);
89 | board.placeKing(7, 7, Color.BLACK);
90 | board.placeQueen(0, 6, Color.WHITE);
91 | System.out.println(board);
92 | System.out.println(board.getLegalMoves());
93 | Assert.assertEquals(21, board.getLegalMoves().size());
94 | Assert.assertEquals(-1, board.evaluation(board.getLegalMoves().size()), 0.3);
95 | }
96 |
97 | @Test(expected = NoSuchElementException.class)
98 | public void castleFail() {
99 | Board board = new Board();
100 | board.placeKing(0, 4, Color.WHITE);
101 | board.placeKing(7, 4, Color.BLACK);
102 | board.placeRook(7, 7, Color.BLACK);
103 | board.placeRook(7, 0, Color.BLACK);
104 | board.placeBishop(7, 2, Color.BLACK);
105 | board.placePawn(6, 5, Color.BLACK);
106 | board.placePawn(6, 6, Color.BLACK);
107 | board.placeRook(4, 7, Color.WHITE);
108 | System.out.println(board);
109 | System.out.println(board.getPiece(7, 4).getMoveList(board));
110 | Assert.assertEquals(5, board.getPiece(7, 4).getMoveList(board).size());
111 | Assert.assertTrue(board.getPiece(7, 4).getMoveList(board).stream().anyMatch(c -> Math.abs(c.piece.position.col - c.target.col) == 2));
112 | board.makeMove(board.getPiece(4, 7).getMoveList(board).stream().filter(c -> c.captureMove).findAny().get());
113 | System.out.println(board);
114 | System.out.println(board.getPiece(7, 4).getMoveList(board));
115 | board.makeMove(board.getPiece(7, 4).getMoveList(board).stream().filter(c -> Math.abs(c.piece.position.col - c.target.col) == 2).findAny().get());
116 | }
117 |
118 | @Test(expected = NoSuchElementException.class)
119 | public void castleFailWithKnightCapture() {
120 | Board board = new Board();
121 | board.placeKing(0, 4, Color.WHITE);
122 | board.placeKnight(6, 5, Color.WHITE);
123 | board.placeKing(7, 4, Color.BLACK);
124 | board.placeRook(7, 7, Color.BLACK);
125 | board.placeRook(7, 0, Color.BLACK);
126 | board.placeBishop(7, 2, Color.BLACK);
127 | board.placePawn(6, 6, Color.BLACK);
128 | System.out.println(board);
129 | System.out.println(board.getPiece(7, 4).getMoveList(board));
130 | Assert.assertEquals(5, board.getPiece(7, 4).getMoveList(board).size());
131 | Assert.assertTrue(board.getPiece(7, 4).getMoveList(board).stream().anyMatch(c -> Math.abs(c.piece.position.col - c.target.col) == 2));
132 | board.makeMove(board.getPiece(6, 5).getMoveList(board).stream().filter(c -> c.captureMove).findAny().get());
133 | System.out.println(board);
134 | System.out.println(board.getPiece(7, 4).getMoveList(board));
135 | board.makeMove(board.getPiece(7, 4).getMoveList(board).stream().filter(c -> Math.abs(c.piece.position.col - c.target.col) == 2).findAny().get());
136 | }
137 |
138 | @Test
139 | public void pawnIsPinned() {
140 | Board board = new Board();
141 | board.placeKing(4, 0, Color.WHITE);
142 | board.placeRook(3, 1, Color.WHITE);
143 | board.placePawn(4, 1, Color.WHITE);
144 | board.placePawn(1, 4, Color.WHITE);
145 | board.placePawn(1, 6, Color.WHITE);
146 | board.placeKing(3, 7, Color.BLACK);
147 | board.placeRook(4, 7, Color.BLACK);
148 | board.placePawn(3, 5, Color.BLACK);
149 | board.placePawn(6, 2, Color.BLACK);
150 | board.placePawn(5, 3, Color.BLACK);
151 | System.out.println(board);
152 | System.out.println(board.getPiece(4, 1).getMoveList(board));
153 | System.out.println(board.getLegalMoves());
154 | Assert.assertTrue(board.getLegalMoves().stream().filter(move -> move.piece.sameType(PieceType.PAWN)).noneMatch(move -> move.target.row == 5));
155 | board.makeMove(board.getPiece(1, 4).getMoveList(board).stream().findFirst().get());
156 | System.out.println(board);
157 | System.out.println(board.getPiece(6, 2).getMoveList(board));
158 | board.makeMove(board.getPiece(6, 2).getMoveList(board).stream().filter(c -> Math.abs(c.piece.position.row - c.target.row) == 2).findAny().get());
159 | System.out.println(board);
160 | System.out.println(board.getPiece(4, 1).getMoveList(board));
161 | System.out.println(board.getLegalMoves());
162 | Assert.assertTrue(board.getLegalMoves().stream().filter(move -> move.piece.sameType(PieceType.PAWN)).noneMatch(move -> move.target.row == 5 && move.captureMove));
163 | }
164 |
165 | @Test
166 | public void doubleCheck() {
167 | Board board = new Board();
168 | board.placeKing(4, 0, Color.WHITE);
169 | board.placeRook(3, 1, Color.WHITE);
170 | board.placeKing(3, 7, Color.BLACK);
171 | board.placeRook(1, 0, Color.BLACK);
172 | board.placeKnight(2, 0, Color.BLACK);
173 | System.out.println(board);
174 | System.out.println(board.getPiece(4, 0).getMoveList(board));
175 | System.out.println(board.getLegalMoves());
176 | board.playerToMove = Color.BLACK;
177 | board.makeMove(Move.get(board.getPiece(2, 0), Cell.get(3, 2), false));
178 | System.out.println(board);
179 | System.out.println(board.getLegalMoves());
180 | Assert.assertTrue(board.getLegalMoves().stream().allMatch(move -> move.piece.sameType(PieceType.KING)));
181 | }
182 |
183 | @Test
184 | public void pawnPromotion() {
185 | Board board = new Board();
186 | board.placeKing(4, 0, Color.WHITE);
187 | board.placeKing(3, 7, Color.BLACK);
188 | board.placePawn(1, 1, Color.BLACK);
189 | board.playerToMove = Color.BLACK;
190 | System.out.println(board);
191 | System.out.println(board.getPiece(1, 1).getMoveList(board));
192 | System.out.println(board.getLegalMoves());
193 | board.makeMove(Move.get(board.getPiece(1, 1), Cell.get(0, 1), false, null, PieceType.QUEEN));
194 | System.out.println(board);
195 | System.out.println(board.getLegalMoves());
196 | Assert.assertTrue(board.playerPieces.get(Color.BLACK).stream().anyMatch(piece -> piece.sameType(PieceType.QUEEN)));
197 | }
198 |
199 | @Test
200 | public void pawnPromoteToKnight() {
201 | Board board = new Board();
202 | board.placeKing(4, 0, Color.WHITE);
203 | board.placeKing(3, 7, Color.BLACK);
204 | board.placePawn(1, 1, Color.BLACK);
205 | board.playerToMove = Color.BLACK;
206 | System.out.println(board);
207 | System.out.println(board.getPiece(1, 1).getMoveList(board));
208 | System.out.println(board.getLegalMoves());
209 | board.makeMove(Move.get(board.getPiece(1, 1), Cell.get(0, 1), false, null, PieceType.KNIGHT));
210 | System.out.println(board);
211 | System.out.println(board.getLegalMoves());
212 | Assert.assertTrue(board.playerPieces.get(Color.BLACK).stream().anyMatch(piece -> piece.sameType(PieceType.KNIGHT)));
213 | }
214 |
215 | @Test
216 | public void kingAndQueenOut() {
217 | Board board = Board.getStartBoard();
218 | board = board.copy();
219 | board.makeMove(board.getLegalMoves()
220 | .stream()
221 | .filter(c -> c.piece.sameType(PieceType.PAWN))
222 | .filter(c -> c.piece.position.equals(Cell.get(1, 3)))
223 | .filter(c -> c.target.equals(Cell.get(2, 3)))
224 | .findAny()
225 | .get());
226 | board = board.copy();
227 | board.makeMove(board.getLegalMoves()
228 | .stream()
229 | .filter(c -> c.piece.sameType(PieceType.PAWN))
230 | .filter(c -> c.piece.position.equals(Cell.get(6, 4)))
231 | .filter(c -> c.target.equals(Cell.get(5, 4)))
232 | .findAny()
233 | .get());
234 | board = board.copy();
235 | board.makeMove(board.getLegalMoves()
236 | .stream()
237 | .filter(c -> c.piece.sameType(PieceType.KING))
238 | .filter(c -> c.piece.position.equals(Cell.get(0, 4)))
239 | .filter(c -> c.target.equals(Cell.get(1, 3)))
240 | .findAny()
241 | .get());
242 | board = board.copy();
243 | board.makeMove(board.getLegalMoves()
244 | .stream()
245 | .filter(c -> c.piece.sameType(PieceType.QUEEN))
246 | .filter(c -> c.piece.position.equals(Cell.get(7, 3)))
247 | .filter(c -> c.target.equals(Cell.get(6, 4)))
248 | .findAny()
249 | .get());
250 | System.out.println(board);
251 | System.out.println(board.getLegalMoves());
252 | Assert.assertEquals(23, board.getLegalMoves().size());
253 | }
254 |
255 | @Test
256 | public void kingAndKnightOut() {
257 | Board board = Board.getStartBoard();
258 | board = board.copy();
259 | board.makeMove(board.getLegalMoves()
260 | .stream()
261 | .filter(c -> c.piece.sameType(PieceType.PAWN))
262 | .filter(c -> c.piece.position.equals(Cell.get(1, 3)))
263 | .filter(c -> c.target.equals(Cell.get(2, 3)))
264 | .findAny()
265 | .get());
266 | board = board.copy();
267 | board.makeMove(board.getLegalMoves()
268 | .stream()
269 | .filter(c -> c.piece.sameType(PieceType.PAWN))
270 | .filter(c -> c.piece.position.equals(Cell.get(6, 4)))
271 | .filter(c -> c.target.equals(Cell.get(5, 4)))
272 | .findAny()
273 | .get());
274 | board = board.copy();
275 | board.makeMove(board.getLegalMoves()
276 | .stream()
277 | .filter(c -> c.piece.sameType(PieceType.KING))
278 | .filter(c -> c.piece.position.equals(Cell.get(0, 4)))
279 | .filter(c -> c.target.equals(Cell.get(1, 3)))
280 | .findAny()
281 | .get());
282 | board = board.copy();
283 | board.makeMove(board.getLegalMoves()
284 | .stream()
285 | .filter(c -> c.piece.sameType(PieceType.KNIGHT))
286 | .filter(c -> c.piece.position.equals(Cell.get(7, 6)))
287 | .filter(c -> c.target.equals(Cell.get(5, 5)))
288 | .findAny()
289 | .get());
290 | System.out.println(board);
291 | System.out.println(board.getLegalMoves());
292 | Assert.assertEquals(23, board.getLegalMoves().size());
293 | }
294 |
295 | @Test
296 | public void kingAndPawnOut() {
297 | Board board = Board.getStartBoard();
298 | board = board.copy();
299 | board.makeMove(board.getLegalMoves()
300 | .stream()
301 | .filter(c -> c.piece.sameType(PieceType.PAWN))
302 | .filter(c -> c.piece.position.equals(Cell.get(1, 3)))
303 | .filter(c -> c.target.equals(Cell.get(2, 3)))
304 | .findAny()
305 | .get());
306 | board = board.copy();
307 | board.makeMove(board.getLegalMoves()
308 | .stream()
309 | .filter(c -> c.piece.sameType(PieceType.PAWN))
310 | .filter(c -> c.piece.position.equals(Cell.get(6, 6)))
311 | .filter(c -> c.target.equals(Cell.get(4, 6)))
312 | .findAny()
313 | .get());
314 | board = board.copy();
315 | board.makeMove(board.getLegalMoves()
316 | .stream()
317 | .filter(c -> c.piece.sameType(PieceType.KING))
318 | .filter(c -> c.piece.position.equals(Cell.get(0, 4)))
319 | .filter(c -> c.target.equals(Cell.get(1, 3)))
320 | .findAny()
321 | .get());
322 | board = board.copy();
323 | board.makeMove(board.getLegalMoves()
324 | .stream()
325 | .filter(c -> c.piece.sameType(PieceType.PAWN))
326 | .filter(c -> c.piece.position.equals(Cell.get(4, 6)))
327 | .filter(c -> c.target.equals(Cell.get(3, 6)))
328 | .findAny()
329 | .get());
330 | System.out.println(board);
331 | System.out.println(board.getLegalMoves());
332 | Assert.assertEquals(22, board.getLegalMoves().size());
333 | }
334 | }
335 |
--------------------------------------------------------------------------------
/src/test/java/EngineTest.java:
--------------------------------------------------------------------------------
1 | import commons.Color;
2 | import commons.Piece;
3 | import game.Board;
4 | import game.Cell;
5 | import game.Move;
6 | import org.junit.Assert;
7 | import org.junit.Test;
8 |
9 | public class EngineTest {
10 | @Test
11 | public void fenRepresentation() {
12 | Board board = Board.getStartBoard();
13 | Assert.assertEquals("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -", board.fenRepresentation());
14 | board.makeMove(Move.get(board.getPiece(1, 4), Cell.get(3, 4), false));
15 | Assert.assertEquals("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3", board.fenRepresentation());
16 | board.makeMove(Move.get(board.getPiece(6, 2), Cell.get(4, 2), false));
17 | Assert.assertEquals("rnbqkbnr/pp1ppppp/8/2p5/4P3/8/PPPP1PPP/RNBQKBNR w KQkq c6", board.fenRepresentation());
18 | board.makeMove(Move.get(board.getPiece(0, 6), Cell.get(2, 5), false));
19 | Assert.assertEquals("rnbqkbnr/pp1ppppp/8/2p5/4P3/5N2/PPPP1PPP/RNBQKB1R b KQkq -", board.fenRepresentation());
20 | }
21 |
22 | @Test
23 | public void otherBoard() {
24 | Board board = Board.getStartBoard();
25 | board.makeMove(Move.get(board.getPiece(1, 4), Cell.get(3, 4), false));
26 | Engine engine = new Engine();
27 | board = board.copy();
28 | board.makeMove(Move.get(board.getPiece(6, 3), Cell.get(5, 3), false));
29 | board = board.copy();
30 | board.makeMove(Move.get(board.getPiece(3, 4), Cell.get(4, 4), false));
31 | board = board.copy();
32 | board.makeMove(Move.get(board.getPiece(6, 5), Cell.get(4, 5), false));
33 | // board = board.copy();
34 | // board.makeMove(board.getPiece(4, 4).getMoveList(board).stream().filter(c -> c.captureMove).filter(c -> c.captureCell.equals(Cell.get(4, 5))).findAny().get());
35 | final int positions = engine.countAllMoves(board, 2);
36 | System.out.println(board);
37 | System.out.println("NUMBER OF POSITIONS: " + positions);
38 | System.out.println(board.fenRepresentation());
39 | Assert.assertEquals(729, positions);
40 | }
41 |
42 | @Test
43 | public void countMovesAfterMove() {
44 | Board board = Board.getStartBoard();
45 | Piece piece = board.getPiece(1, 1);
46 | board.makeMove(Move.get(piece, Cell.get(2, 1), false));
47 | piece = board.getPiece(6, 1);
48 | board.makeMove(Move.get(piece, Cell.get(5, 0), false));
49 | Engine engine = new Engine();
50 | System.out.println(board);
51 | Assert.assertEquals("rnbqkbnr/p1pppppp/p7/8/8/1P6/P1PPPPPP/RNBQKBNR w KQkq -", board.fenRepresentation());
52 | Assert.assertEquals(21, engine.countAllMoves(board, 1));
53 | }
54 |
55 | @Test
56 | public void countMovesAtPosition31() {
57 | Board board = Board.getBoard("8/2p5/K2p4/1P4kr/1R3p2/8/4P1P1/8 w - -");
58 | System.out.println(board);
59 | Engine engine = new Engine();
60 | Assert.assertEquals(1563505, engine.countAllMoves(board, 5));
61 | }
62 |
63 | @Test
64 | public void countMovesAtPosition32() {
65 | Board board = Board.getBoard("8/1Kp5/3p4/1P4kr/1R3p2/8/4P1P1/8 b - -");
66 | System.out.println(board);
67 | Engine engine = new Engine();
68 | Assert.assertEquals(129425, engine.countAllMoves(board, 4));
69 | }
70 |
71 | @Test
72 | public void countMovesAtPosition33() {
73 | Board board = Board.getBoard("8/1Kp5/3p4/1P3k1r/1R3p2/8/4P1P1/8 w - -");
74 | System.out.println(board);
75 | Engine engine = new Engine();
76 | Assert.assertEquals(6416, engine.countAllMoves(board, 3, 3));
77 | }
78 |
79 | @Test
80 | public void countDoublePawnMovePossibilities() {
81 | Board board = Board.getBoard("8/1Kp5/3p4/1P3k1r/1R2Pp2/8/6P1/8 b - e3");
82 | board.inCheck = true;
83 | System.out.println(board);
84 | Engine engine = new Engine();
85 | Assert.assertEquals(120, engine.countAllMoves(board, 2, 2));
86 | }
87 |
88 | @Test
89 | public void countEnpassantPossibilities() {
90 | Board board = Board.getBoard("8/1Kp5/3p4/1P3k1r/1R6/4p3/6P1/8 w - -");
91 | System.out.println(board);
92 | Engine engine = new Engine();
93 | Assert.assertEquals(20, engine.countAllMoves(board, 1));
94 | }
95 |
96 |
97 | @Test
98 | public void countMovesAtPosition34() {
99 | Board board = Board.getBoard("8/2K5/3p4/1P3k1r/1R3p2/8/4P1P1/8 b - -");
100 | System.out.println(board);
101 | Engine engine = new Engine();
102 | Assert.assertEquals(318, engine.countAllMoves(board, 2));
103 | }
104 |
105 | @Test
106 | public void countMovesAtPosition35() {
107 | Board board = Board.getBoard("8/2K5/3p4/1P2k2r/1R3p2/8/4P1P1/8 w - -");
108 | System.out.println(board);
109 | Engine engine = new Engine();
110 | Assert.assertEquals(20, engine.countAllMoves(board, 1));
111 | }
112 |
113 | @Test
114 | public void countMovesAtPositionRandom() {
115 | Board board = Board.getBoard("r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R4K1R b kq -");
116 | System.out.println(board);
117 | Engine engine = new Engine();
118 | final int positions = engine.countAllMoves(board, 3);
119 | System.out.println("NUMBER OF POSITIONS: " + positions);
120 | Assert.assertEquals(77887, positions);
121 | }
122 |
123 | @Test
124 | public void countMovesAtPositionInCheck() {
125 | Board board = Board.getBoard("r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q2/PPPBBPpP/R4K1R w kq -");
126 | board.inCheck = true;
127 | System.out.println(board);
128 | Engine engine = new Engine();
129 | final int positions = engine.countAllMoves(board, 2);
130 | System.out.println("NUMBER OF POSITIONS: " + positions);
131 | Assert.assertEquals(188, positions);
132 | }
133 |
134 | @Test
135 | public void countMovesAtPositionMovesAfterCheck() {
136 | Board board = Board.getBoard("r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q2/PPPBBPpP/R3K2R b kq -");
137 | System.out.println(board);
138 | Engine engine = new Engine();
139 | final int positions = engine.countAllMoves(board, 1);
140 | System.out.println("NUMBER OF POSITIONS: " + positions);
141 | Assert.assertEquals(52, positions);
142 | }
143 |
144 | @Test
145 | public void countMovesAtPositionMovesAfterCheck2() {
146 | Board board = Board.getBoard("r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q2/PPPBBPpP/R5KR b kq -");
147 | System.out.println(board);
148 | Engine engine = new Engine();
149 | final int positions = engine.countAllMoves(board, 1);
150 | System.out.println("NUMBER OF POSITIONS: " + positions);
151 | Assert.assertEquals(48, positions);
152 | }
153 |
154 | @Test
155 | public void queenToEdge() {
156 | Board board = Board.getBoard("r3k2r/p1ppqpb1/bn2pnp1/3PN2Q/1p2P3/2N4p/PPPBBPPP/R3K2R b KQkq -");
157 | System.out.println(board);
158 | Engine engine = new Engine();
159 | final int positions = engine.countAllMoves(board, 3);
160 | System.out.println("NUMBER OF POSITIONS: " + positions);
161 | Assert.assertEquals(95034, positions);
162 | }
163 |
164 | @Test
165 | public void queenToDeath() {
166 | Board board = Board.getBoard("r3k1r1/p1ppqpb1/bn2pnp1/3PN2Q/1p2P3/2N4p/PPPBBPPP/R3K2R w KQq -");
167 | System.out.println(board);
168 | Engine engine = new Engine();
169 | final int positions = engine.countAllMoves(board, 2);
170 | System.out.println("NUMBER OF POSITIONS: " + positions);
171 | Assert.assertEquals(2079, positions);
172 | }
173 |
174 | @Test
175 | public void queenToDeathBlockCastle() {
176 | Board board = Board.getBoard("r3k1r1/p1ppqpb1/Bn2pnp1/3PN2Q/1p2P3/2N4p/PPPB1PPP/R3K2R b KQq -");
177 | System.out.println(board);
178 | Engine engine = new Engine();
179 | final int positions = engine.countAllMoves(board, 1);
180 | System.out.println("NUMBER OF POSITIONS: " + positions);
181 | Assert.assertEquals(32, positions);
182 | }
183 |
184 | @Test
185 | public void queenDeterminedToCommitSuicide() {
186 | Board board = Board.getBoard("r3k1rQ/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N4p/PPPBBPPP/R3K2R b KQq -");
187 | System.out.println(board);
188 | Engine engine = new Engine();
189 | final int positions = engine.countAllMoves(board, 1);
190 | System.out.println("NUMBER OF POSITIONS: " + positions);
191 | Assert.assertEquals(38, positions);
192 | }
193 |
194 | @Test
195 | public void rookEndgameWithKing() {
196 | Board board = Board.getBoard("8/2p5/3p4/KP4kr/5p2/8/4P1P1/1R6 w - -");
197 | System.out.println(board);
198 | Engine engine = new Engine();
199 | final int positions = engine.countAllMoves(board, 4, 4);
200 | System.out.println("NUMBER OF POSITIONS: " + positions);
201 | Assert.assertEquals(104371, positions);
202 | }
203 |
204 | @Test
205 | public void rookEndgameWithKing8() {
206 | Board board = Board.getBoard("8/2p5/3p4/KP4kr/5pP1/8/4P3/1R6 b - g3");
207 | System.out.println(board);
208 | Engine engine = new Engine();
209 | final int positions = engine.countAllMoves(board, 3, 1);
210 | System.out.println("NUMBER OF POSITIONS: " + positions);
211 | Assert.assertEquals(5260, positions);
212 | }
213 |
214 | @Test
215 | public void rookEndgameWithKing8_1() {
216 | Board board = Board.getBoard("8/8/2pp4/KP4kr/5pP1/8/4P3/1R6 w - -");
217 | System.out.println(board);
218 | Engine engine = new Engine();
219 | final int positions = engine.countAllMoves(board, 2, 2);
220 | System.out.println("NUMBER OF POSITIONS: " + positions);
221 | Assert.assertEquals(295, positions);
222 | }
223 |
224 | @Test
225 | public void rookEndgameWithKing9() {
226 | Board board = Board.getBoard("8/2p5/3p4/KP4k1/5pP1/8/4P3/1R5r w - -");
227 | System.out.println(board);
228 | Engine engine = new Engine();
229 | final int positions = engine.countAllMoves(board, 2, 1);
230 | System.out.println("NUMBER OF POSITIONS: " + positions);
231 | Assert.assertEquals(328, positions);
232 | }
233 |
234 | @Test
235 | public void rookEndgameWithKing10() {
236 | Board board = Board.getBoard("8/2p5/3p4/KP4k1/5pP1/8/4P3/6Rr b - -");
237 | System.out.println(board);
238 | Engine engine = new Engine();
239 | final int positions = engine.countAllMoves(board, 1, 1);
240 | System.out.println("NUMBER OF POSITIONS: " + positions);
241 | Assert.assertEquals(16, positions);
242 | }
243 |
244 | @Test
245 | public void rookEndgameWithKingPawn() {
246 | Board board = Board.getBoard("8/2p5/3p4/KP4kr/4Pp2/8/6P1/1R6 b - e3");
247 | System.out.println(board);
248 | Engine engine = new Engine();
249 | final int positions = engine.countAllMoves(board, 3, 3);
250 | System.out.println("NUMBER OF POSITIONS: " + positions);
251 | Assert.assertEquals(5503, positions);
252 | }
253 |
254 | @Test
255 | public void rookEndgameWithKingRookMove() {
256 | Board board = Board.getBoard("8/2p5/3p4/KP4k1/4Pp2/7r/6P1/1R6 w - -");
257 | System.out.println(board);
258 | Engine engine = new Engine();
259 | final int positions = engine.countAllMoves(board, 2, 2);
260 | System.out.println("NUMBER OF POSITIONS: " + positions);
261 | Assert.assertEquals(412, positions);
262 | }
263 |
264 | @Test
265 | public void rookEndgameWithKingRookMoving() {
266 | Board board = Board.getBoard("7r/2p5/3p4/KP4k1/4Pp2/8/6P1/1R6 w - -");
267 | System.out.println(board);
268 | Engine engine = new Engine();
269 | final int positions = engine.countAllMoves(board, 2, 2);
270 | System.out.println("NUMBER OF POSITIONS: " + positions);
271 | Assert.assertEquals(407, positions);
272 | }
273 |
274 | @Test
275 | public void rookEndgameWithKingRookMoveA() {
276 | Board board = Board.getBoard("8/2p5/8/KP1p2kr/4Pp2/8/6P1/1R6 w - -");
277 | System.out.println(board);
278 | Engine engine = new Engine();
279 | final int positions = engine.countAllMoves(board, 2, 2);
280 | System.out.println("NUMBER OF POSITIONS: " + positions);
281 | Assert.assertEquals(305, positions);
282 | }
283 |
284 | @Test
285 | public void rookEndgameWithKing2() {
286 | Board board = Board.getBoard("8/2p5/3p4/KP4kr/5p2/8/4P1P1/6R1 b - -");
287 | System.out.println(board);
288 | Engine engine = new Engine();
289 | final int positions = engine.countAllMoves(board, 3);
290 | System.out.println("NUMBER OF POSITIONS: " + positions);
291 | Assert.assertEquals(5007, positions);
292 | }
293 |
294 | @Test
295 | public void rookEndgameWithKing3() {
296 | Board board = Board.getBoard("8/2p5/3p4/KP4k1/5p1r/8/4P1P1/6R1 w - -");
297 | System.out.println(board);
298 | Engine engine = new Engine();
299 | final int positions = engine.countAllMoves(board, 2);
300 | System.out.println("NUMBER OF POSITIONS: " + positions);
301 | Assert.assertEquals(271, positions);
302 | }
303 |
304 | @Test
305 | public void rookEndgameWithKing4() {
306 | Board board = Board.getBoard("8/2p5/3p4/KP4k1/5pPr/8/4P3/6R1 b - g3");
307 | System.out.println(board);
308 | Engine engine = new Engine();
309 | final int positions = engine.countAllMoves(board, 1);
310 | System.out.println("NUMBER OF POSITIONS: " + positions);
311 | Assert.assertEquals(16, positions);
312 | }
313 |
314 | @Test
315 | public void rookEndgameWithKing5() {
316 | Board board = Board.getBoard("8/2p5/3p4/KP4kr/1R3p2/8/4P1P1/8 b - -");
317 | System.out.println(board);
318 | Engine engine = new Engine();
319 | final int positions = engine.countAllMoves(board, 3);
320 | System.out.println("NUMBER OF POSITIONS: " + positions);
321 | Assert.assertEquals(5013, positions);
322 | }
323 |
324 | @Test
325 | public void rookEndgameWithKing6() {
326 | Board board = Board.getBoard("8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - -");
327 | System.out.println(board);
328 | Engine engine = new Engine();
329 | final int positions = engine.countAllMoves(board, 2);
330 | System.out.println("NUMBER OF POSITIONS: " + positions);
331 | Assert.assertEquals(191, positions);
332 | }
333 |
334 | @Test
335 | public void moveKingInChaos() {
336 | Board board = Board.getBoard("r6r/Ppppkppp/1b3nbN/nPP5/BB2P3/q4N2/Pp1P2PP/R2Q1RK1 w - -");
337 | System.out.println(board);
338 | Engine engine = new Engine();
339 | final int positions = engine.countAllMoves(board, 4);
340 | System.out.println("NUMBER OF POSITIONS: " + positions);
341 | Assert.assertEquals(2539008, positions);
342 | }
343 |
344 | @Test
345 | public void moveKingInChaos2() {
346 | Board board = Board.getBoard("r6r/Ppppkppp/1P3nbN/nP6/BB2P3/q4N2/Pp1P2PP/R2Q1RK1 b - -");
347 | board.inCheck = true;
348 | System.out.println(board);
349 | Engine engine = new Engine();
350 | final int positions = engine.countAllMoves(board, 3);
351 | System.out.println("NUMBER OF POSITIONS: " + positions);
352 | Assert.assertEquals(9501, positions);
353 | }
354 |
355 | @Test
356 | public void moveKingInChaos20() {
357 | Board board = Board.getBoard("r2k3r/Pppp1ppp/1P3nbN/nP6/BB2P3/q4N2/Pp1P2PP/R2Q1RK1 w - -");
358 | System.out.println(board);
359 | Engine engine = new Engine();
360 | final int positions = engine.countAllMoves(board, 2);
361 | System.out.println("NUMBER OF POSITIONS: " + positions);
362 | Assert.assertEquals(1475, positions);
363 | }
364 |
365 | @Test
366 | public void moveKingInChaos21() {
367 | Board board = Board.getBoard("r2k3r/PpPp1ppp/5nbN/nP6/BB2P3/q4N2/Pp1P2PP/R2Q1RK1 b - -");
368 | board.inCheck = true;
369 | System.out.println(board);
370 | Engine engine = new Engine();
371 | final int positions = engine.countAllMoves(board, 1);
372 | System.out.println("NUMBER OF POSITIONS: " + positions);
373 | Assert.assertEquals(3, positions);
374 | }
375 |
376 | @Test
377 | public void moveKingInChaos0() {
378 | Board board = Board.getBoard("r6r/Pppp1ppp/1P2knbN/nP6/BB2P3/q4N2/Pp1P2PP/R2Q1RK1 w - -");
379 | System.out.println(board);
380 | Engine engine = new Engine();
381 | final int positions = engine.countAllMoves(board, 2);
382 | System.out.println("NUMBER OF POSITIONS: " + positions);
383 | Assert.assertEquals(1614, positions);
384 | }
385 |
386 | @Test
387 | public void moveKingInChaos1() {
388 | Board board = Board.getBoard("r6r/Pppp1ppp/1P2knbN/nP2P3/BB6/q4N2/Pp1P2PP/R2Q1RK1 b - -");
389 | System.out.println(board);
390 | Engine engine = new Engine();
391 | final int positions = engine.countAllMoves(board, 1);
392 | System.out.println("NUMBER OF POSITIONS: " + positions);
393 | Assert.assertEquals(51, positions);
394 | }
395 |
396 | @Test
397 | public void moveKingInChaos3() {
398 | Board board = Board.getBoard("r6r/Pp1pkppp/1P3nbN/nPp5/BB2P3/q4N2/Pp1P2PP/R2Q1RK1 w - c6");
399 | System.out.println(board);
400 | Engine engine = new Engine();
401 | final int positions = engine.countAllMoves(board, 2);
402 | System.out.println("NUMBER OF POSITIONS: " + positions);
403 | Assert.assertEquals(1550, positions);
404 | }
405 |
406 | @Test
407 | public void moveKingInChaos4() {
408 | Board board = Board.getBoard("r6r/Pp1pkppp/1PP2nbN/n7/BB2P3/q4N2/Pp1P2PP/R2Q1RK1 b - -");
409 | board.inCheck = true;
410 | System.out.println(board);
411 | Engine engine = new Engine();
412 | final int positions = engine.countAllMoves(board, 1);
413 | System.out.println("NUMBER OF POSITIONS: " + positions);
414 | Assert.assertEquals(5, positions);
415 | }
416 |
417 |
418 | @Test
419 | public void kingCastling() {
420 | Board board = Board.getBoard("r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q2/PPPBBPpP/R3K2R b kq -");
421 | System.out.println(board);
422 | System.out.println(board.getKing(Color.BLACK).getMoveList(board).size());
423 | System.out.println(board.getKing(Color.BLACK).getMoveList(board));
424 | }
425 | }
426 |
427 | /*
428 | e2e4: 120
429 | g2g4: 137
430 |
431 |
432 | e2e4: 122
433 | g2g4: 139
434 | */
--------------------------------------------------------------------------------
/src/test/java/IntenseTest.java:
--------------------------------------------------------------------------------
1 | import game.Board;
2 | import game.Move;
3 | import org.junit.Assert;
4 | import org.junit.Ignore;
5 | import org.junit.Test;
6 |
7 | @Ignore
8 | public class IntenseTest {
9 | @Test
10 | public void countMovesAtPosition4() {
11 | Board board = Board.getBoard("r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1");
12 | board.inCheck = true;
13 | System.out.println(board);
14 | Engine engine = new Engine();
15 | Assert.assertEquals(422333, engine.countAllMoves(board, 4));
16 | Assert.assertEquals(15833292, engine.countAllMoves(board, 5));
17 | Assert.assertEquals(706045033, engine.countAllMoves(board, 6));
18 | }
19 |
20 | @Test
21 | public void countMovesAtPosition5() {
22 | Board board = Board.getBoard("rnbq1k1r/pp1Pbppp/2p5/8/2B5/8/PPP1NnPP/RNBQK2R w KQ - 1 8");
23 | System.out.println(board);
24 | Engine engine = new Engine();
25 | Assert.assertEquals(62379, engine.countAllMoves(board, 3));
26 | Assert.assertEquals(2103487, engine.countAllMoves(board, 4));
27 | Assert.assertEquals(89941194, engine.countAllMoves(board, 5));
28 | }
29 |
30 | @Test
31 | public void countMovesAtPosition6() {
32 | Board board = Board.getBoard("r4rk1/1pp1qppp/p1np1n2/2b1p1B1/2B1P1b1/P1NP1N2/1PP1QPPP/R4RK1 w - - 0 10");
33 | System.out.println(board);
34 | Engine engine = new Engine();
35 | final int positions = engine.countAllMoves(board, 5);
36 | System.out.println("NUMBER OF POSITIONS: " + positions);
37 | Assert.assertEquals(164075551, positions);
38 | }
39 |
40 | @Test
41 | public void rookEndgame() {
42 | Board board = Board.getBoard("8/2p5/3p4/KP5r/5p1k/8/4P1P1/1R6 b - -");
43 | System.out.println(board);
44 | Engine engine = new Engine();
45 | final int positions = engine.countAllMoves(board, 5);
46 | System.out.println("NUMBER OF POSITIONS: " + positions);
47 | Assert.assertEquals(1160678, positions);
48 | }
49 |
50 | @Test
51 | public void rookEndgameLowDepth() {
52 | Board board = Board.getBoard("8/2p5/3p4/KP5r/5p1k/8/4P1P1/1R6 b - -");
53 | System.out.println(board);
54 | Engine engine = new Engine();
55 | final int positions = engine.countAllMoves(board, 4);
56 | System.out.println("NUMBER OF POSITIONS: " + positions);
57 | Assert.assertEquals(69665, positions);
58 | }
59 |
60 |
61 | @Test
62 | public void countMovesAtPosition2() {
63 | Board board = Board.getBoard("r3k2r/p1ppqpb1/bn2pnp1/3PN3/1p2P3/2N2Q1p/PPPBBPPP/R3K2R w KQkq -");
64 | System.out.println(board);
65 | Engine engine = new Engine();
66 | Assert.assertEquals(97862, engine.countAllMoves(board, 3));
67 | Assert.assertEquals(4085603, engine.countAllMoves(board, 4));
68 | Assert.assertEquals(193690690, engine.countAllMoves(board, 5));
69 | }
70 |
71 | @Test
72 | public void countMovesAtPosition3() {
73 | Board board = Board.getBoard("8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - -");
74 | System.out.println(board);
75 | Engine engine = new Engine();
76 | Assert.assertEquals(674624, engine.countAllMoves(board, 5));
77 | Assert.assertEquals(11030083, engine.countAllMoves(board, 6));
78 | Assert.assertEquals(178633661, engine.countAllMoves(board, 7));
79 | }
80 |
81 |
82 | @Test
83 | public void countMovesAtPosition30() {
84 | Board board = Board.getBoard("8/2p5/K2p4/1P5r/1R3p1k/8/4P1P1/8 b - -");
85 | System.out.println(board);
86 | Engine engine = new Engine();
87 | Assert.assertEquals(3653, engine.countAllMoves(board, 3));
88 | Assert.assertEquals(59028, engine.countAllMoves(board, 4));
89 | Assert.assertEquals(968724, engine.countAllMoves(board, 5));
90 | Assert.assertEquals(16022983, engine.countAllMoves(board, 6));
91 | }
92 |
93 | @Test
94 | public void countMovesAtPosition301() {
95 | Board board = Board.getBoard("8/2p5/K2p4/1P4kr/1R3p2/8/4P1P1/8 w - -");
96 | System.out.println(board);
97 | Engine engine = new Engine();
98 | Assert.assertEquals(270, engine.countAllMoves(board, 2));
99 | Assert.assertEquals(4666, engine.countAllMoves(board, 3, 3));
100 | }
101 |
102 | @Test
103 | public void countMovesAtPosition302() {
104 | Board board = Board.getBoard("8/2p5/K2p4/1P4kr/1R3pP1/8/4P3/8 b - g3");
105 | System.out.println(board);
106 | Engine engine = new Engine();
107 | Assert.assertEquals(257, engine.countAllMoves(board, 2));
108 | }
109 |
110 | @Test
111 | public void countMovesAtPosition303() {
112 | Board board = Board.getBoard("8/2p5/K2p4/1P4kr/1R6/6p1/4P3/8 w - -");
113 | System.out.println(board);
114 | Engine engine = new Engine();
115 | Assert.assertEquals(16, engine.countAllMoves(board, 1));
116 | }
117 |
118 | @Test
119 | public void countMoves() {
120 | Board board = Board.getStartBoard();
121 | Engine engine = new Engine();
122 | final int positions = engine.countAllMoves(board, 6);
123 | System.out.println("NUMBER OF POSITIONS: " + positions);
124 | Assert.assertEquals(119060324, positions);
125 | System.out.println("NUMBER OF MOVES: " + Move.count);
126 | }
127 |
128 | @Test
129 | public void chaoticPosition() {
130 | Board board = Board.getBoard("r3k2r/Pppp1ppp/1b3nbN/nPP5/BB2P3/q4N2/Pp1P2PP/R2Q1RK1 b kq -");
131 | System.out.println(board);
132 | Engine engine = new Engine();
133 | final int positions = engine.countAllMoves(board, 5);
134 | System.out.println("NUMBER OF POSITIONS: " + positions);
135 | Assert.assertEquals(92063670, positions);
136 | }
137 | }
138 | /*
139 | b4g4
140 | b4h4
141 | */
--------------------------------------------------------------------------------
/src/test/java/KingTest.java:
--------------------------------------------------------------------------------
1 | import commons.Color;
2 | import game.Board;
3 | import org.junit.Assert;
4 | import org.junit.Test;
5 |
6 | public class KingTest {
7 | @Test
8 | public void moveForward() {
9 | Board board = new Board();
10 | board.placeKing(0, 0, Color.BLACK);
11 | board.placeKing(7, 7, Color.WHITE);
12 | System.out.println(board);
13 | System.out.println(board.getPiece(0, 0).getMoveList(board));
14 | Assert.assertEquals(3, board.getPiece(0, 0).getMoveList(board).size());
15 | }
16 |
17 | @Test
18 | public void moveAsKing() {
19 | Board board = new Board();
20 | board.placeKing(3, 3, Color.BLACK);
21 | board.placeKing(3, 7, Color.WHITE);
22 | System.out.println(board);
23 | System.out.println(board.getPiece(3, 3).getMoveList(board));
24 | Assert.assertEquals(8, board.getPiece(3, 3).getMoveList(board).size());
25 | }
26 |
27 | @Test
28 | public void blockedByPawn() {
29 | Board board = new Board();
30 | board.placeKing(3, 3, Color.BLACK);
31 | board.placePawn(4, 3, Color.BLACK);
32 | board.placeKing(7, 7, Color.WHITE);
33 | System.out.println(board);
34 | System.out.println(board.getPiece(3, 3).getMoveList(board));
35 | Assert.assertEquals(7, board.getPiece(3, 3).getMoveList(board).size());
36 | Assert.assertTrue(board.getPiece(3, 3).getMoveList(board).stream().noneMatch(c -> c.captureMove));
37 | }
38 |
39 | @Test
40 | public void blockedByEnemyPawn() {
41 | Board board = new Board();
42 | board.placeKing(3, 3, Color.BLACK);
43 | board.placePawn(4, 3, Color.WHITE);
44 | board.placeKing(7, 7, Color.WHITE);
45 | System.out.println(board);
46 | System.out.println(board.getPiece(3, 3).getMoveList(board));
47 | Assert.assertEquals(8, board.getPiece(3, 3).getMoveList(board).size());
48 | }
49 |
50 | @Test
51 | public void notBlockedByEnemyPawn() {
52 | Board board = new Board();
53 | board.placeKing(3, 3, Color.BLACK);
54 | board.placePawn(5, 3, Color.WHITE);
55 | board.placeKing(7, 7, Color.WHITE);
56 | System.out.println(board);
57 | System.out.println(board.getPiece(3, 3).getMoveList(board));
58 | Assert.assertEquals(8, board.getPiece(3, 3).getMoveList(board).size());
59 | }
60 |
61 | @Test
62 | public void notBlockedByEnemyPawnInFront() {
63 | Board board = new Board();
64 | board.placeKing(3, 3, Color.WHITE);
65 | board.placePawn(5, 3, Color.BLACK);
66 | board.placeKing(7, 7, Color.BLACK);
67 | System.out.println(board);
68 | System.out.println(board.getPiece(3, 3).getMoveList(board));
69 | Assert.assertEquals(6, board.getPiece(3, 3).getMoveList(board).size());
70 | }
71 |
72 | @Test
73 | public void surroundedByPiecesStraight() {
74 | Board board = new Board();
75 | board.placeKing(3, 3, Color.BLACK);
76 | board.placePawn(4, 3, Color.BLACK);
77 | board.placePawn(3, 4, Color.BLACK);
78 | board.placeRook(2, 3, Color.BLACK);
79 | board.placeRook(3, 2, Color.BLACK);
80 | board.placeKing(7, 7, Color.WHITE);
81 | System.out.println(board);
82 | System.out.println(board.getPiece(3, 3).getMoveList(board));
83 | Assert.assertEquals(4, board.getPiece(3, 3).getMoveList(board).size());
84 | }
85 |
86 | @Test
87 | public void surroundedByEnemyStraight() {
88 | Board board = new Board();
89 | board.placeKing(3, 3, Color.BLACK);
90 | board.placePawn(4, 3, Color.WHITE);
91 | board.placePawn(3, 4, Color.WHITE);
92 | board.placeRook(2, 3, Color.WHITE);
93 | board.placeRook(3, 2, Color.WHITE);
94 | board.placeKing(7, 7, Color.WHITE);
95 | board.inCheck = true;
96 | System.out.println(board);
97 | System.out.println(board.getPiece(3, 3).getMoveList(board));
98 | Assert.assertEquals(3, board.getPiece(3, 3).getMoveList(board).size());
99 | }
100 |
101 | @Test
102 | public void surroundedByPiecesDiag() {
103 | Board board = new Board();
104 | board.placeKing(3, 3, Color.BLACK);
105 | board.placePawn(4, 4, Color.BLACK);
106 | board.placePawn(2, 2, Color.BLACK);
107 | board.placeRook(4, 2, Color.BLACK);
108 | board.placeRook(2, 4, Color.BLACK);
109 | board.placeKing(7, 7, Color.WHITE);
110 | System.out.println(board);
111 | System.out.println(board.getPiece(3, 3).getMoveList(board));
112 | Assert.assertEquals(4, board.getPiece(3, 3).getMoveList(board).size());
113 | }
114 |
115 | @Test
116 | public void surroundedByEnemyDiag() {
117 | Board board = new Board();
118 | board.placeKing(3, 3, Color.BLACK);
119 | board.placePawn(4, 4, Color.WHITE);
120 | board.placePawn(2, 2, Color.WHITE);
121 | board.placeRook(4, 2, Color.WHITE);
122 | board.placeRook(2, 4, Color.WHITE);
123 | board.placeKing(7, 7, Color.WHITE);
124 | board.inCheck = true;
125 | System.out.println(board);
126 | System.out.println(board.getPiece(3, 3).getMoveList(board));
127 | Assert.assertEquals(2, board.getPiece(3, 3).getMoveList(board).size());
128 | }
129 |
130 | @Test
131 | public void surroundedByTeam() {
132 | Board board = new Board();
133 | board.placeKing(3, 3, Color.WHITE);
134 | board.placePawn(4, 4, Color.WHITE);
135 | board.placePawn(2, 2, Color.WHITE);
136 | board.placeRook(4, 2, Color.WHITE);
137 | board.placeRook(2, 4, Color.WHITE);
138 | board.placePawn(4, 3, Color.WHITE);
139 | board.placePawn(3, 4, Color.WHITE);
140 | board.placeRook(2, 3, Color.WHITE);
141 | board.placeRook(3, 2, Color.WHITE);
142 | board.placeKing(7, 7, Color.BLACK);
143 | System.out.println(board);
144 | System.out.println(board.getPiece(3, 3).getMoveList(board));
145 | Assert.assertTrue(board.getPiece(3, 3).getMoveList(board).isEmpty());
146 | }
147 |
148 | @Test
149 | public void surroundedByEnemy() {
150 | Board board = new Board();
151 | board.placeKing(3, 3, Color.BLACK);
152 | board.placePawn(4, 4, Color.WHITE);
153 | board.placePawn(2, 2, Color.WHITE);
154 | board.placeRook(4, 2, Color.WHITE);
155 | board.placeRook(2, 4, Color.WHITE);
156 | board.placePawn(4, 3, Color.WHITE);
157 | board.placePawn(3, 4, Color.WHITE);
158 | board.placeRook(2, 3, Color.WHITE);
159 | board.placeRook(3, 2, Color.WHITE);
160 | board.placeKing(7, 7, Color.WHITE);
161 | System.out.println(board);
162 | System.out.println(board.getPiece(3, 3).getMoveList(board));
163 | Assert.assertEquals(1, board.getPiece(3, 3).getMoveList(board).size());
164 | Assert.assertTrue(board.getPiece(3, 3).getMoveList(board).stream().allMatch(c -> c.captureMove));
165 | }
166 |
167 | @Test
168 | public void canCastleLeft() {
169 | Board board = new Board();
170 | board.canCastle[0][1] = false;
171 | board.placeKing(0, 4, Color.WHITE);
172 | board.placeKing(7, 4, Color.BLACK);
173 | board.placeRook(0, 0, Color.WHITE);
174 | System.out.println(board);
175 | System.out.println(board.getPiece(0, 4).getMoveList(board));
176 | Assert.assertEquals(6, board.getPiece(0, 4).getMoveList(board).size());
177 | Assert.assertTrue(board.getPiece(0, 4).getMoveList(board).stream().noneMatch(c -> c.captureMove));
178 | board.makeMove(board.getPiece(0, 4).getMoveList(board).stream().filter(c -> Math.abs(c.piece.position.col - c.target.col) == 2).findAny().get());
179 | System.out.println(board);
180 | System.out.println(board.getPiece(0, 2).getMoveList(board));
181 | Assert.assertEquals(4, board.getPiece(0, 2).getMoveList(board).size());
182 | Assert.assertEquals(11, board.getPiece(0, 3).getMoveList(board).size());
183 | }
184 |
185 | @Test
186 | public void canCastleRight() {
187 | Board board = new Board();
188 | board.canCastle[0][0] = false;
189 | board.placeKing(0, 4, Color.WHITE);
190 | board.placeKing(7, 4, Color.BLACK);
191 | board.placeRook(0, 7, Color.WHITE);
192 | System.out.println(board);
193 | System.out.println(board.getPiece(0, 4).getMoveList(board));
194 | Assert.assertEquals(6, board.getPiece(0, 4).getMoveList(board).size());
195 | Assert.assertTrue(board.getPiece(0, 4).getMoveList(board).stream().noneMatch(c -> c.captureMove));
196 | board.makeMove(board.getPiece(0, 4).getMoveList(board).stream().filter(c -> Math.abs(c.piece.position.col - c.target.col) == 2).findAny().get());
197 | System.out.println(board);
198 | System.out.println(board.getPiece(0, 6).getMoveList(board));
199 | Assert.assertEquals(4, board.getPiece(0, 6).getMoveList(board).size());
200 | Assert.assertEquals(12, board.getPiece(0, 5).getMoveList(board).size());
201 | }
202 |
203 | @Test
204 | public void canCastleBothSides() {
205 | Board board = new Board();
206 | board.placeKing(0, 4, Color.WHITE);
207 | board.placeKing(7, 4, Color.BLACK);
208 | board.placeRook(0, 7, Color.WHITE);
209 | board.placeRook(0, 0, Color.WHITE);
210 | System.out.println(board);
211 | System.out.println(board.getPiece(0, 4).getMoveList(board));
212 | Assert.assertEquals(7, board.getPiece(0, 4).getMoveList(board).size());
213 | Assert.assertTrue(board.getPiece(0, 4).getMoveList(board).stream().noneMatch(c -> c.captureMove));
214 | }
215 |
216 | @Test
217 | public void castleBlockedLeftSide() {
218 | Board board = new Board();
219 | board.placeKing(0, 4, Color.WHITE);
220 | board.placeKing(7, 4, Color.BLACK);
221 | board.placeRook(0, 7, Color.WHITE);
222 | board.placeRook(0, 0, Color.WHITE);
223 | board.placeBishop(0, 2, Color.WHITE);
224 | board.placePawn(1, 6, Color.WHITE);
225 | board.placePawn(1, 7, Color.WHITE);
226 | System.out.println(board);
227 | System.out.println(board.getPiece(0, 4).getMoveList(board));
228 | Assert.assertEquals(6, board.getPiece(0, 4).getMoveList(board).size());
229 | Assert.assertTrue(board.getPiece(0, 4).getMoveList(board).stream().noneMatch(c -> c.captureMove));
230 | board.makeMove(board.getPiece(0, 4).getMoveList(board).stream().filter(c -> Math.abs(c.piece.position.col - c.target.col) == 2).findAny().get());
231 | System.out.println(board);
232 | System.out.println(board.getPiece(0, 6).getMoveList(board));
233 | Assert.assertEquals(2, board.getPiece(0, 6).getMoveList(board).size());
234 | Assert.assertEquals(9, board.getPiece(0, 5).getMoveList(board).size());
235 | }
236 |
237 | @Test
238 | public void castleBlockedByCheck() {
239 | Board board = new Board();
240 | board.placeKing(0, 4, Color.WHITE);
241 | board.placeKing(7, 4, Color.BLACK);
242 | board.placeRook(0, 7, Color.WHITE);
243 | board.placeRook(0, 0, Color.WHITE);
244 | board.placeBishop(0, 2, Color.WHITE);
245 | board.placePawn(1, 6, Color.WHITE);
246 | board.placePawn(1, 7, Color.WHITE);
247 | board.placeRook(5, 5, Color.BLACK);
248 | System.out.println(board);
249 | System.out.println(board.getPiece(0, 4).getMoveList(board));
250 | Assert.assertEquals(3, board.getPiece(0, 4).getMoveList(board).size());
251 | Assert.assertTrue(board.getPiece(0, 4).getMoveList(board).stream().noneMatch(c -> Math.abs(c.piece.position.col - c.target.col) == 2));
252 | }
253 |
254 | @Test
255 | public void castleNotBlockedByCheck() {
256 | Board board = new Board();
257 | board.placeKing(0, 4, Color.WHITE);
258 | board.placeKing(7, 4, Color.BLACK);
259 | board.placeRook(0, 7, Color.WHITE);
260 | board.placeRook(0, 0, Color.WHITE);
261 | board.placeBishop(0, 2, Color.WHITE);
262 | board.placePawn(1, 5, Color.WHITE);
263 | board.placePawn(1, 6, Color.WHITE);
264 | board.placeRook(5, 7, Color.BLACK);
265 | System.out.println(board);
266 | System.out.println(board.getPiece(0, 4).getMoveList(board));
267 | Assert.assertEquals(5, board.getPiece(0, 4).getMoveList(board).size());
268 | Assert.assertTrue(board.getPiece(0, 4).getMoveList(board).stream().anyMatch(c -> Math.abs(c.piece.position.col - c.target.col) == 2));
269 | board.makeMove(board.getPiece(0, 4).getMoveList(board).stream().filter(c -> Math.abs(c.piece.position.col - c.target.col) == 2).findAny().get());
270 | System.out.println(board);
271 | System.out.println(board.getPiece(0, 6).getMoveList(board));
272 | Assert.assertTrue(board.getPiece(0, 6).getMoveList(board).isEmpty());
273 | Assert.assertEquals(2, board.getPiece(0, 5).getMoveList(board).size());
274 | }
275 |
276 | @Test
277 | public void castleBlockedByCheckBlack() {
278 | Board board = new Board();
279 | board.placeKing(0, 4, Color.WHITE);
280 | board.placeKing(7, 4, Color.BLACK);
281 | board.placeRook(7, 7, Color.BLACK);
282 | board.placeRook(7, 0, Color.BLACK);
283 | board.placeBishop(7, 2, Color.BLACK);
284 | board.placePawn(6, 6, Color.BLACK);
285 | board.placePawn(6, 7, Color.BLACK);
286 | board.placeRook(4, 5, Color.WHITE);
287 | System.out.println(board);
288 | System.out.println(board.getPiece(7, 4).getMoveList(board));
289 | Assert.assertEquals(3, board.getPiece(7, 4).getMoveList(board).size());
290 | Assert.assertTrue(board.getPiece(7, 4).getMoveList(board).stream().noneMatch(c -> Math.abs(c.piece.position.col - c.target.col) == 2));
291 | }
292 |
293 | @Test
294 | public void castleNotBlockedByCheckBlack() {
295 | Board board = new Board();
296 | board.placeKing(0, 4, Color.WHITE);
297 | board.placeKing(7, 4, Color.BLACK);
298 | board.placeRook(7, 7, Color.BLACK);
299 | board.placeRook(7, 0, Color.BLACK);
300 | board.placeBishop(7, 2, Color.BLACK);
301 | board.placePawn(6, 5, Color.BLACK);
302 | board.placePawn(6, 6, Color.BLACK);
303 | board.placeRook(4, 7, Color.WHITE);
304 | System.out.println(board);
305 | System.out.println(board.getPiece(7, 4).getMoveList(board));
306 | Assert.assertEquals(5, board.getPiece(7, 4).getMoveList(board).size());
307 | Assert.assertTrue(board.getPiece(7, 4).getMoveList(board).stream().anyMatch(c -> Math.abs(c.piece.position.col - c.target.col) == 2));
308 | board.makeMove(board.getPiece(7, 4).getMoveList(board).stream().filter(c -> Math.abs(c.piece.position.col - c.target.col) == 2).findAny().get());
309 | System.out.println(board);
310 | System.out.println(board.getPiece(7, 6).getMoveList(board));
311 | Assert.assertTrue(board.getPiece(7, 6).getMoveList(board).isEmpty());
312 | Assert.assertEquals(2, board.getPiece(7, 5).getMoveList(board).size());
313 | }
314 |
315 | @Test
316 | public void kingInProximity() {
317 | Board board = new Board();
318 | board.placeKing(2, 5, Color.WHITE);
319 | board.placeRook(2, 0, Color.BLACK);
320 | board.placeKing(4, 4, Color.BLACK);
321 | board.inCheck = true;
322 | System.out.println(board);
323 | System.out.println(board.getPiece(2, 5).getMoveList(board));
324 | Assert.assertEquals(4, board.getPiece(2, 5).getMoveList(board).size());
325 | }
326 |
327 |
328 | @Test
329 | public void canCastleAsBlack() {
330 | Board board = new Board();
331 | board.canCastle[0][0] = board.canCastle[0][1] = false;
332 | board.placeKing(0, 4, Color.WHITE);
333 | board.placeKing(7, 4, Color.BLACK);
334 | board.placeRook(7, 7, Color.BLACK);
335 | board.placeRook(7, 0, Color.BLACK);
336 | board.placePawn(6, 3, Color.BLACK);
337 | board.placePawn(6, 4, Color.BLACK);
338 | board.placePawn(6, 5, Color.BLACK);
339 | System.out.println(board);
340 | System.out.println(board.getPiece(7, 4).getMoveList(board));
341 | }
342 | }
343 |
--------------------------------------------------------------------------------
/src/test/java/KnightTest.java:
--------------------------------------------------------------------------------
1 | import commons.Color;
2 | import game.Board;
3 | import org.junit.Assert;
4 | import org.junit.Test;
5 |
6 | public class KnightTest {
7 | @Test
8 | public void moveForward() {
9 | Board board = new Board();
10 | board.placeKnight(0, 0, Color.BLACK);
11 | System.out.println(board);
12 | System.out.println(board.getPiece(0, 0).getMoveList(board));
13 | Assert.assertEquals(2, board.getPiece(0, 0).getMoveList(board).size());
14 | }
15 |
16 | @Test
17 | public void moveAsKnight() {
18 | Board board = new Board();
19 | board.placeKnight(3, 3, Color.BLACK);
20 | System.out.println(board);
21 | System.out.println(board.getPiece(3, 3).getMoveList(board));
22 | Assert.assertEquals(8, board.getPiece(3, 3).getMoveList(board).size());
23 | }
24 |
25 | @Test
26 | public void blockedByPawn() {
27 | Board board = new Board();
28 | board.placeKnight(3, 3, Color.BLACK);
29 | board.placePawn(4, 3, Color.BLACK);
30 | board.placePawn(5, 4, Color.BLACK);
31 | System.out.println(board);
32 | System.out.println(board.getPiece(3, 3).getMoveList(board));
33 | Assert.assertEquals(7, board.getPiece(3, 3).getMoveList(board).size());
34 | Assert.assertTrue(board.getPiece(3, 3).getMoveList(board).stream().noneMatch(c -> c.captureMove));
35 | }
36 |
37 | @Test
38 | public void blockedByEnemyPawn() {
39 | Board board = new Board();
40 | board.placeKnight(3, 3, Color.BLACK);
41 | board.placePawn(4, 3, Color.WHITE);
42 | board.placePawn(5, 4, Color.WHITE);
43 | System.out.println(board);
44 | System.out.println(board.getPiece(3, 3).getMoveList(board));
45 | Assert.assertEquals(8, board.getPiece(3, 3).getMoveList(board).size());
46 | }
47 |
48 | @Test
49 | public void notBlockedByEnemyPawn() {
50 | Board board = new Board();
51 | board.placeKnight(3, 3, Color.BLACK);
52 | board.placePawn(5, 3, Color.WHITE);
53 | System.out.println(board);
54 | System.out.println(board.getPiece(3, 3).getMoveList(board));
55 | Assert.assertEquals(8, board.getPiece(3, 3).getMoveList(board).size());
56 | }
57 |
58 | @Test
59 | public void surroundedByPiecesFriendly() {
60 | Board board = new Board();
61 | board.placeKnight(3, 3, Color.BLACK);
62 | board.placePawn(5, 4, Color.BLACK);
63 | board.placePawn(4, 5, Color.BLACK);
64 | board.placeRook(2, 5, Color.BLACK);
65 | board.placeRook(1, 2, Color.BLACK);
66 | System.out.println(board);
67 | System.out.println(board.getPiece(3, 3).getMoveList(board));
68 | Assert.assertEquals(4, board.getPiece(3, 3).getMoveList(board).size());
69 | }
70 |
71 | @Test
72 | public void surroundedByEnemyPieces() {
73 | Board board = new Board();
74 | board.placeKnight(3, 3, Color.BLACK);
75 | board.placePawn(5, 4, Color.WHITE);
76 | board.placePawn(4, 5, Color.WHITE);
77 | board.placeRook(2, 5, Color.WHITE);
78 | board.placeRook(1, 2, Color.WHITE);
79 | System.out.println(board);
80 | System.out.println(board.getPiece(3, 3).getMoveList(board));
81 | Assert.assertEquals(8, board.getPiece(3, 3).getMoveList(board).size());
82 | }
83 |
84 | @Test
85 | public void surroundedByPiecesDiag() {
86 | Board board = new Board();
87 | board.placeKnight(3, 3, Color.BLACK);
88 | board.placePawn(4, 4, Color.BLACK);
89 | board.placePawn(2, 2, Color.BLACK);
90 | board.placeRook(4, 2, Color.BLACK);
91 | board.placeRook(2, 4, Color.BLACK);
92 | System.out.println(board);
93 | System.out.println(board.getPiece(3, 3).getMoveList(board));
94 | Assert.assertEquals(8, board.getPiece(3, 3).getMoveList(board).size());
95 | }
96 |
97 | @Test
98 | public void surroundedByEnemyDiag() {
99 | Board board = new Board();
100 | board.placeKnight(3, 3, Color.BLACK);
101 | board.placePawn(4, 4, Color.WHITE);
102 | board.placePawn(2, 2, Color.WHITE);
103 | board.placeRook(4, 2, Color.WHITE);
104 | board.placeRook(2, 4, Color.WHITE);
105 | System.out.println(board);
106 | System.out.println(board.getPiece(3, 3).getMoveList(board));
107 | Assert.assertEquals(8, board.getPiece(3, 3).getMoveList(board).size());
108 | }
109 |
110 | @Test
111 | public void surroundedByTeam() {
112 | Board board = new Board();
113 | board.placeKnight(3, 3, Color.WHITE);
114 | board.placePawn(4, 4, Color.WHITE);
115 | board.placePawn(2, 2, Color.WHITE);
116 | board.placeRook(4, 2, Color.WHITE);
117 | board.placeRook(2, 4, Color.WHITE);
118 | board.placePawn(4, 3, Color.WHITE);
119 | board.placePawn(3, 4, Color.WHITE);
120 | board.placeRook(2, 3, Color.WHITE);
121 | board.placeRook(3, 2, Color.WHITE);
122 | System.out.println(board);
123 | System.out.println(board.getPiece(3, 3).getMoveList(board));
124 | Assert.assertEquals(8, board.getPiece(3, 3).getMoveList(board).size());
125 | }
126 |
127 | @Test
128 | public void surroundedByEnemy() {
129 | Board board = new Board();
130 | board.placeKnight(3, 3, Color.BLACK);
131 | board.placePawn(4, 4, Color.WHITE);
132 | board.placePawn(2, 2, Color.WHITE);
133 | board.placeRook(4, 2, Color.WHITE);
134 | board.placeRook(2, 4, Color.WHITE);
135 | board.placePawn(4, 3, Color.WHITE);
136 | board.placePawn(3, 4, Color.WHITE);
137 | board.placeRook(2, 3, Color.WHITE);
138 | board.placeRook(3, 2, Color.WHITE);
139 | System.out.println(board);
140 | System.out.println(board.getPiece(3, 3).getMoveList(board));
141 | Assert.assertEquals(8, board.getPiece(3, 3).getMoveList(board).size());
142 | Assert.assertEquals(8, board.getPiece(3, 3).getMoveList(board).size());
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/src/test/java/MinMaxTest.java:
--------------------------------------------------------------------------------
1 | import commons.Color;
2 | import game.Board;
3 | import game.Cell;
4 | import org.junit.Assert;
5 | import org.junit.Test;
6 | import pieces.PieceType;
7 |
8 | public class MinMaxTest {
9 |
10 | @Test
11 | public void mateInOne() {
12 | Board board = new Board();
13 | board.placeKing(7, 0, Color.BLACK);
14 | board.placeKing(1, 0, Color.WHITE);
15 | board.placeRook(6, 4, Color.WHITE);
16 | board.placeRook(2, 5, Color.WHITE);
17 | System.out.println(board.fenRepresentation());
18 | System.out.println(board);
19 | Engine engine = new Engine();
20 | final Evaluation bestMove = engine.minMax(board, 1, 1);
21 | System.out.println(bestMove.getMove());
22 | System.out.println(bestMove.getScore());
23 | board.makeMove(bestMove.getMove());
24 | System.out.println(board);
25 | Assert.assertEquals(bestMove.getMove().target, Cell.get(7, 5));
26 | Assert.assertTrue(bestMove.getMove().piece.sameType(PieceType.ROOK));
27 | System.out.println("NODES: " + Engine.nodesEvaluated + " TRANSPOSITIONS: " + engine.transpositionTable.size());
28 | }
29 |
30 | @Test
31 | public void mateInThree() {
32 | Board board = Board.getBoard("7k/4K1pp/7N/8/8/8/8/B7 w - - 0 1");
33 | System.out.println(board);
34 | Engine engine = new Engine();
35 | final Evaluation bestMove = engine.minMax(board, 5, 5);
36 | System.out.println(bestMove.getMove());
37 | System.out.println(bestMove.getScore());
38 | board.makeMove(bestMove.getMove());
39 | System.out.println(board);
40 | Assert.assertEquals(bestMove.getMove().target, Cell.get(5, 5));
41 | Assert.assertTrue(bestMove.getMove().piece.sameType(PieceType.BISHOP));
42 | System.out.println("NODES: " + Engine.nodesEvaluated + " TRANSPOSITIONS: " + engine.transpositionTable.size());
43 | }
44 |
45 | @Test
46 | public void mateInTwo() {
47 | Board board = Board.getBoard("7k/4K2p/5p1N/8/8/8/8/8 w - - 0 2");
48 | System.out.println(board);
49 | Engine engine = new Engine();
50 | final Evaluation bestMove = engine.minMax(board, 3, 3);
51 | System.out.println(bestMove.getMove());
52 | System.out.println(bestMove.getScore());
53 | board.makeMove(bestMove.getMove());
54 | System.out.println(board);
55 | Assert.assertEquals(bestMove.getMove().target, Cell.get(7, 5));
56 | Assert.assertTrue(bestMove.getMove().piece.sameType(PieceType.KING));
57 | System.out.println("NODES: " + Engine.nodesEvaluated + " TRANSPOSITIONS: " + engine.transpositionTable.size());
58 | }
59 |
60 | @Test
61 | public void complexPosition() {
62 | Board board = Board.getBoard("r4rk1/1bp1q1p1/1p5p/3n4/p2Ppp2/2P3QN/PPB2PPP/R3R1K1 w - - 0 22");
63 | System.out.println(board);
64 | Engine engine = new Engine();
65 | final OutCome bestMove = engine.iterativeDeepening(board, 10);
66 | System.out.println(bestMove.getMove());
67 | System.out.println(bestMove.getScore());
68 | board.makeMove(bestMove.getMove());
69 | System.out.println(board);
70 | Assert.assertEquals(Cell.get(5, 6), bestMove.getMove().target);
71 | Assert.assertTrue(bestMove.getMove().piece.sameType(PieceType.QUEEN));
72 | System.out.println("NODES: " + Engine.nodesEvaluated + " TRANSPOSITIONS: " + engine.transpositionTable.size());
73 | }
74 |
75 | @Test
76 | public void winQueen() {
77 | Board board = Board.getBoard("3r1k2/5p2/p4N1p/1p4p1/2pq4/6P1/1P3Q1P/4R1K1 w - - 2 33");
78 | System.out.println(board);
79 | Engine engine = new Engine();
80 | final OutCome bestMove = engine.iterativeDeepening(board, 20);
81 | System.out.println(bestMove.getMove());
82 | System.out.println(bestMove.getScore());
83 | board.makeMove(bestMove.getMove());
84 | System.out.println(board);
85 | Assert.assertEquals(Cell.get(7, 4), bestMove.getMove().target);
86 | Assert.assertTrue(bestMove.getMove().piece.sameType(PieceType.ROOK));
87 | System.out.println("NODES: " + Engine.nodesEvaluated + " TRANSPOSITIONS: " + engine.transpositionTable.size());
88 | }
89 |
90 | @Test
91 | public void endGamePgn() {
92 | Board board = Board.getBoard("2k5/8/5R2/8/8/8/3K4/4R3 w - - 5 6");
93 | System.out.println(board);
94 | Engine engine = new Engine();
95 | final OutCome bestMove = engine.iterativeDeepening(board, 20);
96 | System.out.println(bestMove.getMove());
97 | Assert.assertEquals(Integer.MIN_VALUE, bestMove.getScore(), 0.000001);
98 | System.out.println("NODES: " + Engine.nodesEvaluated + " TRANSPOSITIONS: " + engine.transpositionTable.size());
99 | }
100 |
101 | @Test
102 | public void hardMateIn3() {
103 | Board board = Board.getBoard("8/8/2P1Q3/3P3R/3k4/8/2K5/8 w - - 0 1");
104 | System.out.println(board);
105 | Engine engine = new Engine();
106 | final OutCome bestMove = engine.iterativeDeepening(board, 20);
107 | System.out.println(bestMove.getMove());
108 | Assert.assertEquals(Cell.get(6, 5), bestMove.getMove().target);
109 | Assert.assertTrue(bestMove.getMove().piece.sameType(PieceType.QUEEN));
110 | Assert.assertEquals(Integer.MIN_VALUE, bestMove.getScore(), 0.000001);
111 | System.out.println("NODES: " + Engine.nodesEvaluated + " TRANSPOSITIONS: " + engine.transpositionTable.size());
112 | }
113 |
114 | @Test
115 | public void mateIn4() {
116 | Board board = Board.getBoard("7R/r1p1q1pp/3k4/1p1n1Q2/3N4/8/1PP2PPP/2B3K1 w - - 1 0");
117 | System.out.println(board);
118 | Engine engine = new Engine();
119 | final OutCome bestMove = engine.alphaBeta(board, 7, Integer.MIN_VALUE, Integer.MAX_VALUE, 7);
120 | System.out.println(bestMove.getMove());
121 | Assert.assertEquals(Cell.get(7, 3), bestMove.getMove().target);
122 | Assert.assertTrue(bestMove.getMove().piece.sameType(PieceType.ROOK));
123 | Assert.assertEquals(Integer.MIN_VALUE, bestMove.getScore(), 0.000001);
124 | System.out.println("NODES: " + Engine.nodesEvaluated + " TRANSPOSITIONS: " + engine.transpositionTable.size());
125 | }
126 |
127 | @Test
128 | public void countMovesAtPosition4MinMax() {
129 | Board board = Board.getBoard("r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1");
130 | board.inCheck = true;
131 | System.out.println(board);
132 | Engine engine = new Engine();
133 | Engine.nodesEvaluated = 0;
134 | final Evaluation evaluation = engine.minMax(board, 4, 4);
135 | System.out.println(evaluation + " \nNODES: " + Engine.nodesEvaluated);
136 | }
137 |
138 | @Test
139 | public void countMovesAtPosition4AlphaBeta() {
140 | Board board = Board.getBoard("r3k2r/Pppp1ppp/1b3nbN/nP6/BBP1P3/q4N2/Pp1P2PP/R2Q1RK1 w kq - 0 1");
141 | board.inCheck = true;
142 | System.out.println(board);
143 | Engine engine = new Engine();
144 | Engine.nodesEvaluated = 0;
145 | final OutCome evaluation = engine.alphaBeta(board, 4, Integer.MIN_VALUE, Integer.MAX_VALUE, 4);
146 | System.out.println(evaluation + " \nNODES: " + Engine.nodesEvaluated + " TRANSPOSITIONS: " + engine.transpositionTable.size());
147 | }
148 |
149 | }
150 |
--------------------------------------------------------------------------------
/src/test/java/PawnTest.java:
--------------------------------------------------------------------------------
1 | import commons.Color;
2 | import commons.Piece;
3 | import game.Board;
4 | import game.Cell;
5 | import game.Move;
6 | import org.junit.Assert;
7 | import org.junit.Test;
8 | import pieces.PieceType;
9 |
10 | import java.util.stream.Collectors;
11 |
12 | public class PawnTest {
13 | @Test
14 | public void checkStartingPositions() {
15 | final Board board = Board.getStartBoard();
16 | System.out.println(board);
17 | Assert.assertTrue(board.moveList.isEmpty());
18 | Assert.assertEquals(16, board.pieces.values().stream().filter(piece -> piece.sameType(PieceType.PAWN)).count());
19 | Assert.assertEquals(8, board.pieces.values().stream()
20 | .filter(piece -> piece.sameType(PieceType.PAWN))
21 | .filter(piece -> piece.color == Color.BLACK)
22 | .count());
23 | Assert.assertEquals(8, board.pieces.values().stream()
24 | .filter(piece -> piece.sameType(PieceType.PAWN))
25 | .filter(piece -> piece.color == Color.WHITE)
26 | .count());
27 |
28 | }
29 |
30 | @Test
31 | public void moveForward() {
32 | final Board board = new Board();
33 | board.placePawn(2, 1, Color.WHITE);
34 | System.out.println(board);
35 | Assert.assertEquals(1, board.getPiece(2, 1).getMoveList(board).size());
36 | }
37 |
38 | @Test
39 | public void moveForwardDouble() {
40 | final Board board = new Board();
41 | board.placePawn(1, 1, Color.WHITE);
42 | System.out.println(board);
43 | Assert.assertEquals(2, board.getPiece(1, 1).getMoveList(board).size());
44 | }
45 |
46 | @Test
47 | public void cantMoveForwardOpponent() {
48 | final Board board = new Board();
49 | board.placePawn(2, 1, Color.WHITE);
50 | board.placePawn(3, 1, Color.BLACK);
51 | System.out.println(board);
52 | Assert.assertTrue(board.getPiece(2, 1).getMoveList(board).isEmpty());
53 | }
54 |
55 | @Test
56 | public void cantMoveForwardSameColor() {
57 | final Board board = new Board();
58 | board.placePawn(2, 1, Color.WHITE);
59 | board.placePawn(3, 1, Color.WHITE);
60 | System.out.println(board);
61 | Assert.assertTrue(board.getPiece(2, 1).getMoveList(board).isEmpty());
62 | }
63 |
64 | @Test
65 | public void canCapture() {
66 | final Board board = new Board();
67 | board.placePawn(2, 1, Color.WHITE);
68 | board.placePawn(3, 1, Color.BLACK);
69 | board.placePawn(3, 2, Color.BLACK);
70 | System.out.println(board);
71 | Assert.assertEquals(1, board.getPiece(2, 1).getMoveList(board).size());
72 | System.out.println(board.getPiece(2, 1).getMoveList(board));
73 | }
74 |
75 | @Test
76 | public void canCaptureBlack() {
77 | final Board board = new Board();
78 | board.placePawn(6, 6, Color.BLACK);
79 | board.placePawn(5, 5, Color.WHITE);
80 | System.out.println(board);
81 | System.out.println(board.getPiece(6, 6).getMoveList(board));
82 | Assert.assertEquals(3, board.getPiece(6, 6).getMoveList(board).size());
83 | }
84 |
85 | @Test
86 | public void canCaptureBlackBlocked() {
87 | final Board board = new Board();
88 | board.placePawn(6, 6, Color.BLACK);
89 | board.placePawn(5, 6, Color.BLACK);
90 | board.placePawn(5, 5, Color.WHITE);
91 | System.out.println(board);
92 | System.out.println(board.getPiece(6, 6).getMoveList(board));
93 | Assert.assertEquals(1, board.getPiece(6, 6).getMoveList(board).size());
94 | }
95 |
96 | @Test
97 | public void canCaptureEnPassant() {
98 | final Board board = new Board();
99 | board.placePawn(4, 6, Color.WHITE);
100 | board.placePawn(4, 5, Color.BLACK);
101 | board.placePawn(4, 7, Color.BLACK);
102 | board.moveList.add(Move.get(Piece.get(Color.BLACK, Cell.get(6, 5), PieceType.PAWN), Cell.get(4, 5), false));
103 | System.out.println(board);
104 | System.out.println(board.getPiece(4, 6).getMoveList(board));
105 | Assert.assertEquals(2, board.getPiece(4, 6).getMoveList(board).size());
106 | }
107 |
108 | @Test
109 | public void cannotCaptureEnPassantOnNextTurn() {
110 | final Board board = new Board();
111 | board.placePawn(4, 6, Color.WHITE);
112 | board.placePawn(4, 5, Color.BLACK);
113 | board.placePawn(4, 7, Color.BLACK);
114 | System.out.println(board);
115 | System.out.println(board.getPiece(4, 6).getMoveList(board));
116 | Assert.assertEquals(1, board.getPiece(4, 6).getMoveList(board).size());
117 | }
118 |
119 | @Test
120 | public void captureOnEdge() {
121 | Board board = Board.getStartBoard();
122 | board = board.copy();
123 | board.makeMove(board.getLegalMoves()
124 | .stream()
125 | .filter(c -> c.piece.sameType(PieceType.PAWN))
126 | .filter(c -> c.piece.position.equals(Cell.get(1, 0)))
127 | .filter(c -> c.target.equals(Cell.get(2, 0)))
128 | .findAny()
129 | .get());
130 | board = board.copy();
131 | board.makeMove(board.getLegalMoves()
132 | .stream()
133 | .filter(c -> c.piece.sameType(PieceType.PAWN))
134 | .filter(c -> c.piece.position.equals(Cell.get(6, 0)))
135 | .filter(c -> c.target.equals(Cell.get(5, 0)))
136 | .findAny()
137 | .get());
138 | board = board.copy();
139 | board.makeMove(board.getLegalMoves()
140 | .stream()
141 | .filter(c -> c.piece.sameType(PieceType.PAWN))
142 | .filter(c -> c.piece.position.equals(Cell.get(1, 1)))
143 | .filter(c -> c.target.equals(Cell.get(3, 1)))
144 | .findAny()
145 | .get());
146 | board = board.copy();
147 | board.makeMove(board.getLegalMoves()
148 | .stream()
149 | .filter(c -> c.piece.sameType(PieceType.PAWN))
150 | .filter(c -> c.piece.position.equals(Cell.get(5, 0)))
151 | .filter(c -> c.target.equals(Cell.get(4, 0)))
152 | .findAny()
153 | .get());
154 | System.out.println(board);
155 | System.out.println(board.getLegalMoves().stream().map(Move::toString).collect(Collectors.joining("\n")));
156 | System.out.println(board.fenRepresentation());
157 | Assert.assertEquals(20, board.getLegalMoves().size());
158 | }
159 | }
160 |
161 | /*
162 | b4a5
163 | */
164 |
--------------------------------------------------------------------------------
/src/test/java/QueenTest.java:
--------------------------------------------------------------------------------
1 | import commons.Color;
2 | import game.Board;
3 | import org.junit.Assert;
4 | import org.junit.Test;
5 |
6 | public class QueenTest {
7 | @Test
8 | public void moveForward() {
9 | Board board = new Board();
10 | board.placeQueen(0, 0, Color.BLACK);
11 | System.out.println(board);
12 | System.out.println(board.getPiece(0, 0).getMoveList(board));
13 | Assert.assertEquals(21, board.getPiece(0, 0).getMoveList(board).size());
14 | }
15 |
16 | @Test
17 | public void moveAsQueen() {
18 | Board board = new Board();
19 | board.placeQueen(3, 3, Color.BLACK);
20 | System.out.println(board);
21 | System.out.println(board.getPiece(3, 3).getMoveList(board));
22 | Assert.assertEquals(27, board.getPiece(3, 3).getMoveList(board).size());
23 | }
24 |
25 | @Test
26 | public void blockedByPawn() {
27 | Board board = new Board();
28 | board.placeQueen(3, 3, Color.BLACK);
29 | board.placePawn(4, 3, Color.BLACK);
30 | System.out.println(board);
31 | System.out.println(board.getPiece(3, 3).getMoveList(board));
32 | Assert.assertEquals(23, board.getPiece(3, 3).getMoveList(board).size());
33 | Assert.assertTrue(board.getPiece(3, 3).getMoveList(board).stream().noneMatch(c -> c.captureMove));
34 | }
35 |
36 | @Test
37 | public void blockedByEnemyPawn() {
38 | Board board = new Board();
39 | board.placeQueen(3, 3, Color.BLACK);
40 | board.placePawn(4, 3, Color.WHITE);
41 | System.out.println(board);
42 | System.out.println(board.getPiece(3, 3).getMoveList(board));
43 | Assert.assertEquals(24, board.getPiece(3, 3).getMoveList(board).size());
44 | }
45 |
46 | @Test
47 | public void surroundedByPiecesStraight() {
48 | Board board = new Board();
49 | board.placeQueen(3, 3, Color.BLACK);
50 | board.placePawn(4, 3, Color.BLACK);
51 | board.placePawn(3, 4, Color.BLACK);
52 | board.placeRook(2, 3, Color.BLACK);
53 | board.placeRook(3, 2, Color.BLACK);
54 | System.out.println(board);
55 | System.out.println(board.getPiece(3, 3).getMoveList(board));
56 | Assert.assertEquals(13, board.getPiece(3, 3).getMoveList(board).size());
57 | }
58 |
59 | @Test
60 | public void surroundedByEnemyStraight() {
61 | Board board = new Board();
62 | board.placeQueen(3, 3, Color.BLACK);
63 | board.placePawn(4, 3, Color.WHITE);
64 | board.placePawn(3, 4, Color.WHITE);
65 | board.placeRook(2, 3, Color.WHITE);
66 | board.placeRook(3, 2, Color.WHITE);
67 | System.out.println(board);
68 | System.out.println(board.getPiece(3, 3).getMoveList(board));
69 | Assert.assertEquals(17, board.getPiece(3, 3).getMoveList(board).size());
70 | }
71 |
72 | @Test
73 | public void surroundedByPiecesDiag() {
74 | Board board = new Board();
75 | board.placeQueen(3, 3, Color.BLACK);
76 | board.placePawn(4, 4, Color.BLACK);
77 | board.placePawn(2, 2, Color.BLACK);
78 | board.placeRook(4, 2, Color.BLACK);
79 | board.placeRook(2, 4, Color.BLACK);
80 | System.out.println(board);
81 | System.out.println(board.getPiece(3, 3).getMoveList(board));
82 | Assert.assertEquals(14, board.getPiece(3, 3).getMoveList(board).size());
83 | }
84 |
85 | @Test
86 | public void surroundedByEnemyDiag() {
87 | Board board = new Board();
88 | board.placeQueen(3, 3, Color.BLACK);
89 | board.placePawn(4, 4, Color.WHITE);
90 | board.placePawn(2, 2, Color.WHITE);
91 | board.placeRook(4, 2, Color.WHITE);
92 | board.placeRook(2, 4, Color.WHITE);
93 | System.out.println(board);
94 | System.out.println(board.getPiece(3, 3).getMoveList(board));
95 | Assert.assertEquals(18, board.getPiece(3, 3).getMoveList(board).size());
96 | }
97 |
98 | @Test
99 | public void surroundedByTeam() {
100 | Board board = new Board();
101 | board.placeQueen(3, 3, Color.WHITE);
102 | board.placePawn(4, 4, Color.WHITE);
103 | board.placePawn(2, 2, Color.WHITE);
104 | board.placeRook(4, 2, Color.WHITE);
105 | board.placeRook(2, 4, Color.WHITE);
106 | board.placePawn(4, 3, Color.WHITE);
107 | board.placePawn(3, 4, Color.WHITE);
108 | board.placeRook(2, 3, Color.WHITE);
109 | board.placeRook(3, 2, Color.WHITE);
110 | System.out.println(board);
111 | System.out.println(board.getPiece(3, 3).getMoveList(board));
112 | Assert.assertTrue(board.getPiece(3, 3).getMoveList(board).isEmpty());
113 | }
114 |
115 | @Test
116 | public void surroundedByEnemy() {
117 | Board board = new Board();
118 | board.placeQueen(3, 3, Color.BLACK);
119 | board.placePawn(4, 4, Color.WHITE);
120 | board.placePawn(2, 2, Color.WHITE);
121 | board.placeRook(4, 2, Color.WHITE);
122 | board.placeRook(2, 4, Color.WHITE);
123 | board.placePawn(4, 3, Color.WHITE);
124 | board.placePawn(3, 4, Color.WHITE);
125 | board.placeRook(2, 3, Color.WHITE);
126 | board.placeRook(3, 2, Color.WHITE);
127 | System.out.println(board);
128 | System.out.println(board.getPiece(3, 3).getMoveList(board));
129 | Assert.assertEquals(8, board.getPiece(3, 3).getMoveList(board).size());
130 | Assert.assertTrue(board.getPiece(3, 3).getMoveList(board).stream().allMatch(c -> c.captureMove));
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/src/test/java/RookTest.java:
--------------------------------------------------------------------------------
1 | import commons.Color;
2 | import game.Board;
3 | import org.junit.Assert;
4 | import org.junit.Test;
5 |
6 | public class RookTest {
7 | @Test
8 | public void moveForward() {
9 | Board board = new Board();
10 | board.placeRook(0, 0, Color.BLACK);
11 | System.out.println(board);
12 | System.out.println(board.getPiece(0, 0).getMoveList(board));
13 | Assert.assertEquals(14, board.getPiece(0, 0).getMoveList(board).size());
14 | }
15 |
16 | @Test
17 | public void moveAsRook() {
18 | Board board = new Board();
19 | board.placeRook(3, 3, Color.BLACK);
20 | System.out.println(board);
21 | System.out.println(board.getPiece(3, 3).getMoveList(board));
22 | Assert.assertEquals(14, board.getPiece(3, 3).getMoveList(board).size());
23 | }
24 |
25 | @Test
26 | public void blockedByPawn() {
27 | Board board = new Board();
28 | board.placeRook(3, 3, Color.BLACK);
29 | board.placePawn(4, 3, Color.BLACK);
30 | System.out.println(board);
31 | System.out.println(board.getPiece(3, 3).getMoveList(board));
32 | Assert.assertEquals(10, board.getPiece(3, 3).getMoveList(board).size());
33 | Assert.assertTrue(board.getPiece(3, 3).getMoveList(board).stream().noneMatch(c -> c.captureMove));
34 | }
35 |
36 | @Test
37 | public void blockedByEnemyPawn() {
38 | Board board = new Board();
39 | board.placeRook(3, 3, Color.BLACK);
40 | board.placePawn(4, 3, Color.WHITE);
41 | System.out.println(board);
42 | System.out.println(board.getPiece(3, 3).getMoveList(board));
43 | Assert.assertEquals(11, board.getPiece(3, 3).getMoveList(board).size());
44 | }
45 |
46 | @Test
47 | public void surroundedByPieces() {
48 | Board board = new Board();
49 | board.placeRook(3, 3, Color.BLACK);
50 | board.placePawn(4, 3, Color.BLACK);
51 | board.placePawn(3, 4, Color.BLACK);
52 | board.placeRook(2, 3, Color.BLACK);
53 | board.placeRook(3, 2, Color.BLACK);
54 | System.out.println(board);
55 | System.out.println(board.getPiece(3, 3).getMoveList(board));
56 | Assert.assertTrue(board.getPiece(3, 3).getMoveList(board).isEmpty());
57 | }
58 |
59 | @Test
60 | public void surroundedByEnemy() {
61 | Board board = new Board();
62 | board.placeRook(3, 3, Color.BLACK);
63 | board.placePawn(4, 3, Color.WHITE);
64 | board.placePawn(3, 4, Color.WHITE);
65 | board.placeRook(2, 3, Color.WHITE);
66 | board.placeRook(3, 2, Color.WHITE);
67 | System.out.println(board);
68 | System.out.println(board.getPiece(3, 3).getMoveList(board));
69 | Assert.assertEquals(4, board.getPiece(3, 3).getMoveList(board).size());
70 | Assert.assertTrue(board.getPiece(3, 3).getMoveList(board).stream().allMatch(c -> c.captureMove));
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
| | | | | | | | | | |