Add missing Javadoc
This commit is contained in:
parent
f4768b7ac3
commit
2333021bba
@ -13,6 +13,12 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class Bishop extends Piece {
|
public class Bishop extends Piece {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates bishop {@link Piece}.
|
||||||
|
*
|
||||||
|
* @param color the color of this bishop
|
||||||
|
* @param board the board on which this bishop will be placed
|
||||||
|
*/
|
||||||
public Bishop(Color color, Board board) {
|
public Bishop(Color color, Board board) {
|
||||||
super(color, board);
|
super(color, board);
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,6 @@
|
|||||||
package dev.kske.chess.board;
|
package dev.kske.chess.board;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import dev.kske.chess.board.Piece.Color;
|
import dev.kske.chess.board.Piece.Color;
|
||||||
import dev.kske.chess.event.EventBus;
|
import dev.kske.chess.event.EventBus;
|
||||||
@ -65,7 +60,7 @@ public class Board {
|
|||||||
public boolean attemptMove(Move move) {
|
public boolean attemptMove(Move move) {
|
||||||
Piece piece = getPos(move);
|
Piece piece = getPos(move);
|
||||||
if (piece == null || !piece.isValidMove(move)) return false;
|
if (piece == null || !piece.isValidMove(move)) return false;
|
||||||
else {
|
|
||||||
// Move piece
|
// Move piece
|
||||||
move(move);
|
move(move);
|
||||||
|
|
||||||
@ -77,7 +72,6 @@ public class Board {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves a piece across the board without checking if the move is legal.
|
* Moves a piece across the board without checking if the move is legal.
|
||||||
@ -122,6 +116,10 @@ public class Board {
|
|||||||
log.removeLast();
|
log.removeLast();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverts the last move without removing it from the log. After that, a
|
||||||
|
* {@link MoveEvent} is dispatched containing the inverse of the reverted move.
|
||||||
|
*/
|
||||||
public void selectPreviousNode() {
|
public void selectPreviousNode() {
|
||||||
MoveNode moveNode = log.getLast();
|
MoveNode moveNode = log.getLast();
|
||||||
Move move = moveNode.move;
|
Move move = moveNode.move;
|
||||||
@ -133,9 +131,15 @@ public class Board {
|
|||||||
log.selectPreviousNode();
|
log.selectPreviousNode();
|
||||||
|
|
||||||
// Dispatch move event
|
// Dispatch move event
|
||||||
EventBus.getInstance().dispatch(new MoveEvent(move.invert(), getGameEventType(log.getActiveColor().opposite())));
|
EventBus.getInstance().dispatch(new MoveEvent(move.invert(), getState(log.getActiveColor().opposite())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the next move stored in the log. After that, a {@link MoveEvent} is
|
||||||
|
* dispatched.
|
||||||
|
*
|
||||||
|
* @param index the variation index of the move to select
|
||||||
|
*/
|
||||||
public void selectNextNode(int index) {
|
public void selectNextNode(int index) {
|
||||||
log.selectNextNode(index);
|
log.selectNextNode(index);
|
||||||
MoveNode moveNode = log.getLast();
|
MoveNode moveNode = log.getLast();
|
||||||
@ -145,7 +149,7 @@ public class Board {
|
|||||||
move.execute(this);
|
move.execute(this);
|
||||||
|
|
||||||
// Dispatch move event
|
// Dispatch move event
|
||||||
EventBus.getInstance().dispatch(new MoveEvent(move, getGameEventType(log.getActiveColor().opposite())));
|
EventBus.getInstance().dispatch(new MoveEvent(move, getState(log.getActiveColor().opposite())));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -162,6 +166,12 @@ public class Board {
|
|||||||
return moves;
|
return moves;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delegate method for {@link Piece#getMoves(Position)}.
|
||||||
|
*
|
||||||
|
* @param pos the position of the piece to invoke the method on
|
||||||
|
* @return a list of legal moves generated for the piece
|
||||||
|
*/
|
||||||
public List<Move> getMoves(Position pos) { return get(pos).getMoves(pos); }
|
public List<Move> getMoves(Position pos) { return get(pos).getMoves(pos); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -198,7 +208,7 @@ public class Board {
|
|||||||
public boolean checkCheckmate(Color color) {
|
public boolean checkCheckmate(Color color) {
|
||||||
// Return false immediately if the king can move
|
// Return false immediately if the king can move
|
||||||
if (!getMoves(kingPos.get(color)).isEmpty()) return false;
|
if (!getMoves(kingPos.get(color)).isEmpty()) return false;
|
||||||
else {
|
|
||||||
for (Move move : getMoves(color)) {
|
for (Move move : getMoves(color)) {
|
||||||
move(move);
|
move(move);
|
||||||
boolean check = checkCheck(color);
|
boolean check = checkCheck(color);
|
||||||
@ -207,9 +217,15 @@ public class Board {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public BoardState getGameEventType(Color color) {
|
/**
|
||||||
|
* Checks whether the a check, checkmate, stalemate of none of the above is
|
||||||
|
* currently present.
|
||||||
|
*
|
||||||
|
* @param color the color to evaluate the board for
|
||||||
|
* @return the current {@link BoardState}
|
||||||
|
*/
|
||||||
|
public BoardState getState(Color color) {
|
||||||
return checkCheck(color) ? checkCheckmate(color) ? BoardState.CHECKMATE : BoardState.CHECK
|
return checkCheck(color) ? checkCheckmate(color) ? BoardState.CHECKMATE : BoardState.CHECK
|
||||||
: getMoves(color).isEmpty() || log.getLast().halfmoveClock >= 50 ? BoardState.STALEMATE : BoardState.NORMAL;
|
: getMoves(color).isEmpty() || log.getLast().halfmoveClock >= 50 ? BoardState.STALEMATE : BoardState.NORMAL;
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ package dev.kske.chess.board;
|
|||||||
* @since Chess v0.1-alpha
|
* @since Chess v0.1-alpha
|
||||||
* @author Kai S. K. Engelbart
|
* @author Kai S. K. Engelbart
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("javadoc")
|
||||||
public enum BoardState {
|
public enum BoardState {
|
||||||
CHECK, CHECKMATE, STALEMATE, NORMAL;
|
CHECK, CHECKMATE, STALEMATE, NORMAL;
|
||||||
}
|
}
|
||||||
|
@ -12,11 +12,25 @@ public class Castling extends Move {
|
|||||||
|
|
||||||
private final Move rookMove;
|
private final Move rookMove;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a castling move.
|
||||||
|
*
|
||||||
|
* @param pos the position of this castling move
|
||||||
|
* @param dest the destination of this castling move
|
||||||
|
*/
|
||||||
public Castling(Position pos, Position dest) {
|
public Castling(Position pos, Position dest) {
|
||||||
super(pos, dest);
|
super(pos, dest);
|
||||||
rookMove = dest.x == 6 ? new Move(7, pos.y, 5, pos.y) : new Move(0, pos.y, 3, pos.y);
|
rookMove = dest.x == 6 ? new Move(7, pos.y, 5, pos.y) : new Move(0, pos.y, 3, pos.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a castling move.
|
||||||
|
*
|
||||||
|
* @param xPos the horizontal position of this castling move
|
||||||
|
* @param yPos the vertical position of this castling move
|
||||||
|
* @param xDest the horizontal destination of this castling move
|
||||||
|
* @param yDest the vertical destination of this castling move
|
||||||
|
*/
|
||||||
public Castling(int xPos, int yPos, int xDest, int yDest) { this(new Position(xPos, yPos), new Position(xDest, yDest)); }
|
public Castling(int xPos, int yPos, int xDest, int yDest) { this(new Position(xPos, yPos), new Position(xDest, yDest)); }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -12,11 +12,25 @@ public class EnPassant extends Move {
|
|||||||
|
|
||||||
private final Position capturePos;
|
private final Position capturePos;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes an en passant move.
|
||||||
|
*
|
||||||
|
* @param pos the position of this move
|
||||||
|
* @param dest the destination of this move
|
||||||
|
*/
|
||||||
public EnPassant(Position pos, Position dest) {
|
public EnPassant(Position pos, Position dest) {
|
||||||
super(pos, dest);
|
super(pos, dest);
|
||||||
capturePos = new Position(dest.x, dest.y - ySign);
|
capturePos = new Position(dest.x, dest.y - ySign);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes an en passant move.
|
||||||
|
*
|
||||||
|
* @param xPos the horizontal position of this move
|
||||||
|
* @param yPos the vertical position of this move
|
||||||
|
* @param xDest the horizontal destination of this move
|
||||||
|
* @param yDest the vertical destination of this move
|
||||||
|
*/
|
||||||
public EnPassant(int xPos, int yPos, int xDest, int yDest) { this(new Position(xPos, yPos), new Position(xDest, yDest)); }
|
public EnPassant(int xPos, int yPos, int xDest, int yDest) { this(new Position(xPos, yPos), new Position(xDest, yDest)); }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -31,5 +45,8 @@ public class EnPassant extends Move {
|
|||||||
board.set(capturePos, new Pawn(board.get(pos).getColor().opposite(), board));
|
board.set(capturePos, new Pawn(board.get(pos).getColor().opposite(), board));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the position of the piece captures by this move
|
||||||
|
*/
|
||||||
public Position getCapturePos() { return capturePos; }
|
public Position getCapturePos() { return capturePos; }
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ public class FENString {
|
|||||||
* Constructs a {@link FENString} by parsing an existing string.
|
* Constructs a {@link FENString} by parsing an existing string.
|
||||||
*
|
*
|
||||||
* @param fen the FEN string to parse
|
* @param fen the FEN string to parse
|
||||||
* @throws ChessException
|
* @throws ChessException if the FEN string contains invalid syntax
|
||||||
*/
|
*/
|
||||||
public FENString(String fen) throws ChessException {
|
public FENString(String fen) throws ChessException {
|
||||||
// Check fen string against regex
|
// Check fen string against regex
|
||||||
|
@ -13,6 +13,12 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class King extends Piece {
|
public class King extends Piece {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates king {@link Piece}.
|
||||||
|
*
|
||||||
|
* @param color the color of this king
|
||||||
|
* @param board the board on which this king will be placed
|
||||||
|
*/
|
||||||
public King(Color color, Board board) { super(color, board); }
|
public King(Color color, Board board) { super(color, board); }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -47,7 +53,8 @@ public class King extends Piece {
|
|||||||
Position kingDest = new Position(6, y);
|
Position kingDest = new Position(6, y);
|
||||||
Position rookPos = new Position(7, y);
|
Position rookPos = new Position(7, y);
|
||||||
return canCastle(kingPos, kingDest, rookPos, jumpPos);
|
return canCastle(kingPos, kingDest, rookPos, jumpPos);
|
||||||
} else return false;
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean canCastleQueenside() {
|
private boolean canCastleQueenside() {
|
||||||
@ -58,7 +65,8 @@ public class King extends Piece {
|
|||||||
Position freeDest = new Position(1, y);
|
Position freeDest = new Position(1, y);
|
||||||
Position rookPos = new Position(0, y);
|
Position rookPos = new Position(0, y);
|
||||||
return canCastle(kingPos, freeDest, rookPos, jumpPos);
|
return canCastle(kingPos, freeDest, rookPos, jumpPos);
|
||||||
} else return false;
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean canCastle(Position kingPos, Position freeDest, Position rookPos, Position jumpPos) {
|
private boolean canCastle(Position kingPos, Position freeDest, Position rookPos, Position jumpPos) {
|
||||||
|
@ -13,6 +13,12 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class Knight extends Piece {
|
public class Knight extends Piece {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates knight {@link Piece}.
|
||||||
|
*
|
||||||
|
* @param color the color of this knight
|
||||||
|
* @param board the board on which this knight will be placed
|
||||||
|
*/
|
||||||
public Knight(Color color, Board board) {
|
public Knight(Color color, Board board) {
|
||||||
super(color, board);
|
super(color, board);
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,11 @@ import java.util.Iterator;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import dev.kske.chess.board.Piece.Color;
|
import dev.kske.chess.board.Piece.Color;
|
||||||
|
import dev.kske.chess.game.Game;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Manages the move history of a {@link Game}.<br>
|
||||||
|
* <br>
|
||||||
* Project: <strong>Chess</strong><br>
|
* Project: <strong>Chess</strong><br>
|
||||||
* File: <strong>Log.java</strong><br>
|
* File: <strong>Log.java</strong><br>
|
||||||
* Created: <strong>09.07.2019</strong><br>
|
* Created: <strong>09.07.2019</strong><br>
|
||||||
@ -23,6 +26,9 @@ public class Log implements Iterable<MoveNode> {
|
|||||||
private Position enPassant;
|
private Position enPassant;
|
||||||
private int fullmoveNumber, halfmoveClock;
|
private int fullmoveNumber, halfmoveClock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of {@link Log} in the default state.
|
||||||
|
*/
|
||||||
public Log() { reset(); }
|
public Log() { reset(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -230,23 +236,64 @@ public class Log implements Iterable<MoveNode> {
|
|||||||
*/
|
*/
|
||||||
public MoveNode getLast() { return current; }
|
public MoveNode getLast() { return current; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the castling rights present during the current move
|
||||||
|
*/
|
||||||
public boolean[] getCastlingRights() { return castlingRights; }
|
public boolean[] getCastlingRights() { return castlingRights; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the castling rights present during the current move.
|
||||||
|
*
|
||||||
|
* @param castlingRights the castling rights to set
|
||||||
|
*/
|
||||||
public void setCastlingRights(boolean[] castlingRights) { this.castlingRights = castlingRights; }
|
public void setCastlingRights(boolean[] castlingRights) { this.castlingRights = castlingRights; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the en passant target position of the current move or {@code null} if
|
||||||
|
* the current move is not an en passant move.
|
||||||
|
*/
|
||||||
public Position getEnPassant() { return enPassant; }
|
public Position getEnPassant() { return enPassant; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the en passant target position.
|
||||||
|
*
|
||||||
|
* @param enPassant the en passant target position to set
|
||||||
|
*/
|
||||||
public void setEnPassant(Position enPassant) { this.enPassant = enPassant; }
|
public void setEnPassant(Position enPassant) { this.enPassant = enPassant; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the color active during the current move
|
||||||
|
*/
|
||||||
public Color getActiveColor() { return activeColor; }
|
public Color getActiveColor() { return activeColor; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the color active during the current move.
|
||||||
|
*
|
||||||
|
* @param activeColor the active color to set
|
||||||
|
*/
|
||||||
public void setActiveColor(Color activeColor) { this.activeColor = activeColor; }
|
public void setActiveColor(Color activeColor) { this.activeColor = activeColor; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the number of moves made until the current move
|
||||||
|
*/
|
||||||
public int getFullmoveNumber() { return fullmoveNumber; }
|
public int getFullmoveNumber() { return fullmoveNumber; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the number of moves made until the current move.
|
||||||
|
*
|
||||||
|
* @param fullmoveNumber the fullmove number to set
|
||||||
|
*/
|
||||||
public void setFullmoveNumber(int fullmoveNumber) { this.fullmoveNumber = fullmoveNumber; }
|
public void setFullmoveNumber(int fullmoveNumber) { this.fullmoveNumber = fullmoveNumber; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the number of halfmoves since the last capture move or pawn move
|
||||||
|
*/
|
||||||
public int getHalfmoveClock() { return halfmoveClock; }
|
public int getHalfmoveClock() { return halfmoveClock; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets then number of halfmoves since the last capture move or pawn move
|
||||||
|
*
|
||||||
|
* @param halfmoveClock the halfmove clock to set
|
||||||
|
*/
|
||||||
public void setHalfmoveClock(int halfmoveClock) { this.halfmoveClock = halfmoveClock; }
|
public void setHalfmoveClock(int halfmoveClock) { this.halfmoveClock = halfmoveClock; }
|
||||||
}
|
}
|
@ -21,6 +21,12 @@ public class Move {
|
|||||||
protected final Position pos, dest;
|
protected final Position pos, dest;
|
||||||
protected final int xDist, yDist, xSign, ySign;
|
protected final int xDist, yDist, xSign, ySign;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of {@link Move}.
|
||||||
|
*
|
||||||
|
* @param pos the position of this move
|
||||||
|
* @param dest the destination of this move
|
||||||
|
*/
|
||||||
public Move(Position pos, Position dest) {
|
public Move(Position pos, Position dest) {
|
||||||
this.pos = pos;
|
this.pos = pos;
|
||||||
this.dest = dest;
|
this.dest = dest;
|
||||||
@ -30,24 +36,53 @@ public class Move {
|
|||||||
ySign = (int) Math.signum(dest.y - pos.y);
|
ySign = (int) Math.signum(dest.y - pos.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of {@link Move}.
|
||||||
|
*
|
||||||
|
* @param xPos the horizontal position of this move
|
||||||
|
* @param yPos the vertical position of this move
|
||||||
|
* @param xDest the horizontal destination of this move
|
||||||
|
* @param yDest the vertical destination of this move
|
||||||
|
*/
|
||||||
public Move(int xPos, int yPos, int xDest, int yDest) { this(new Position(xPos, yPos), new Position(xDest, yDest)); }
|
public Move(int xPos, int yPos, int xDest, int yDest) { this(new Position(xPos, yPos), new Position(xDest, yDest)); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executed this move on a board.
|
||||||
|
*
|
||||||
|
* @param board the board to execute this move on.
|
||||||
|
*/
|
||||||
public void execute(Board board) {
|
public void execute(Board board) {
|
||||||
// Move the piece to the move's destination square and clean the old position
|
// Move the piece to the move's destination square and clean the old position
|
||||||
board.set(dest, board.get(pos));
|
board.set(dest, board.get(pos));
|
||||||
board.set(pos, null);
|
board.set(pos, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverts this move on a board.
|
||||||
|
*
|
||||||
|
* @param board the board to revert this move on
|
||||||
|
* @param capturedPiece the piece to place at the destination of this move (used
|
||||||
|
* for reinstating captured pieces)
|
||||||
|
*/
|
||||||
public void revert(Board board, Piece capturedPiece) {
|
public void revert(Board board, Piece capturedPiece) {
|
||||||
// Move the piece to the move's position square and clean the destination
|
// Move the piece to the move's position square and clean the destination
|
||||||
board.set(pos, board.get(dest));
|
board.set(pos, board.get(dest));
|
||||||
board.set(dest, capturedPiece);
|
board.set(dest, capturedPiece);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Move invert() {
|
/**
|
||||||
return new Move(dest, pos);
|
* @return a new move containing this move's destination as its position and
|
||||||
}
|
* this move's position as its destination
|
||||||
|
*/
|
||||||
|
public Move invert() { return new Move(dest, pos); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a move from a string representation in Long Algebraic Notation
|
||||||
|
* (LAN).
|
||||||
|
*
|
||||||
|
* @param move the LAN string to construct the move from
|
||||||
|
* @return the constructed move
|
||||||
|
*/
|
||||||
public static Move fromLAN(String move) {
|
public static Move fromLAN(String move) {
|
||||||
Position pos = Position.fromLAN(move.substring(0, 2));
|
Position pos = Position.fromLAN(move.substring(0, 2));
|
||||||
Position dest = Position.fromLAN(move.substring(2));
|
Position dest = Position.fromLAN(move.substring(2));
|
||||||
@ -58,9 +93,16 @@ public class Move {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
} else return new Move(pos, dest);
|
}
|
||||||
|
return new Move(pos, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a string representation of this move in Long Algebraic Notation
|
||||||
|
* (LAN).
|
||||||
|
*
|
||||||
|
* @return the LAN string
|
||||||
|
*/
|
||||||
public String toLAN() { return getPos().toLAN() + getDest().toLAN(); }
|
public String toLAN() { return getPos().toLAN() + getDest().toLAN(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -151,13 +193,19 @@ public class Move {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a string representation of this move in Standard Algebraic Notation
|
||||||
|
* (SAN).
|
||||||
|
*
|
||||||
|
* @param board the {@link Board} providing the context of this move
|
||||||
|
* @return the SAN string
|
||||||
|
*/
|
||||||
public String toSAN(Board board) {
|
public String toSAN(Board board) {
|
||||||
final Piece piece = board.get(pos);
|
final Piece piece = board.get(pos);
|
||||||
StringBuilder sb = new StringBuilder(8);
|
StringBuilder sb = new StringBuilder(8);
|
||||||
|
|
||||||
// Piece symbol
|
// Piece symbol
|
||||||
if(!(piece instanceof Pawn))
|
if (!(piece instanceof Pawn)) sb.append(Character.toUpperCase(piece.firstChar()));
|
||||||
sb.append(Character.toUpperCase(piece.firstChar()));
|
|
||||||
|
|
||||||
// Position
|
// Position
|
||||||
// TODO: Deconstruct position into optional file or rank
|
// TODO: Deconstruct position into optional file or rank
|
||||||
@ -173,10 +221,19 @@ public class Move {
|
|||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {@code true} if the move is purely horizontal
|
||||||
|
*/
|
||||||
public boolean isHorizontal() { return getyDist() == 0; }
|
public boolean isHorizontal() { return getyDist() == 0; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {@code true} if the move is purely vertical
|
||||||
|
*/
|
||||||
public boolean isVertical() { return getxDist() == 0; }
|
public boolean isVertical() { return getxDist() == 0; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {@code true} if the move is diagonal
|
||||||
|
*/
|
||||||
public boolean isDiagonal() { return getxDist() == getyDist(); }
|
public boolean isDiagonal() { return getxDist() == getyDist(); }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -195,15 +252,33 @@ public class Move {
|
|||||||
&& getxSign() == other.getxSign() && getyDist() == other.getyDist() && getySign() == other.getySign();
|
&& getxSign() == other.getxSign() && getyDist() == other.getyDist() && getySign() == other.getySign();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the position
|
||||||
|
*/
|
||||||
public Position getPos() { return pos; }
|
public Position getPos() { return pos; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the destination
|
||||||
|
*/
|
||||||
public Position getDest() { return dest; }
|
public Position getDest() { return dest; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the x distance
|
||||||
|
*/
|
||||||
public int getxDist() { return xDist; }
|
public int getxDist() { return xDist; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the y distance
|
||||||
|
*/
|
||||||
public int getyDist() { return yDist; }
|
public int getyDist() { return yDist; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the sign of the x distance
|
||||||
|
*/
|
||||||
public int getxSign() { return xSign; }
|
public int getxSign() { return xSign; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the sign of the y distance
|
||||||
|
*/
|
||||||
public int getySign() { return ySign; }
|
public int getySign() { return ySign; }
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
package dev.kske.chess.board;
|
package dev.kske.chess.board;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import dev.kske.chess.board.Piece.Color;
|
import dev.kske.chess.board.Piece.Color;
|
||||||
|
|
||||||
@ -17,14 +14,61 @@ import dev.kske.chess.board.Piece.Color;
|
|||||||
*/
|
*/
|
||||||
public class MoveNode {
|
public class MoveNode {
|
||||||
|
|
||||||
public static final int WHITE_KINGSIDE = 0, WHITE_QUEENSIDE = 1, BLACK_KINGSIDE = 2, BLACK_QUEENSIDE = 3;
|
/**
|
||||||
|
* The index of the white kingside casting in a casting rights array.
|
||||||
|
*/
|
||||||
|
public static final int WHITE_KINGSIDE = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The index of the white queenside castling in a castling rights array.
|
||||||
|
*/
|
||||||
|
public static final int WHITE_QUEENSIDE = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The index of the white kingside casting in a casting rights array.
|
||||||
|
*/
|
||||||
|
public static final int BLACK_KINGSIDE = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The index of the white queenside castling in a castling rights array.
|
||||||
|
*/
|
||||||
|
public static final int BLACK_QUEENSIDE = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The move on the board associated with this move node.
|
||||||
|
*/
|
||||||
public final Move move;
|
public final Move move;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The piece captured by the move.
|
||||||
|
*/
|
||||||
public final Piece capturedPiece;
|
public final Piece capturedPiece;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The castling rights present during the move.
|
||||||
|
*/
|
||||||
public final boolean[] castlingRights;
|
public final boolean[] castlingRights;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The en passant target position or {@code null} if the move is not an en
|
||||||
|
* passant move.
|
||||||
|
*/
|
||||||
public final Position enPassant;
|
public final Position enPassant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The color active during the move.
|
||||||
|
*/
|
||||||
public final Color activeColor;
|
public final Color activeColor;
|
||||||
public final int fullmoveCounter, halfmoveClock;
|
|
||||||
|
/**
|
||||||
|
* The number of moves performed since the beginning of the game.
|
||||||
|
*/
|
||||||
|
public final int fullmoveCounter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The halfmoves performed since the last capture move or pawn move.
|
||||||
|
*/
|
||||||
|
public final int halfmoveClock;
|
||||||
|
|
||||||
private MoveNode parent;
|
private MoveNode parent;
|
||||||
private List<MoveNode> variations;
|
private List<MoveNode> variations;
|
||||||
@ -32,16 +76,18 @@ public class MoveNode {
|
|||||||
/**
|
/**
|
||||||
* Creates a new {@link MoveNode}.
|
* Creates a new {@link MoveNode}.
|
||||||
*
|
*
|
||||||
* @param move The logged {@link Move}
|
* @param move the logged {@link Move}
|
||||||
* @param capturedPiece The {@link Piece} captures by the logged {@link Move}
|
* @param capturedPiece the {@link Piece} captures by the logged {@link Move}
|
||||||
* @param enPassant The en passant {@link Position} valid after the logged
|
* @param castlingRights the castling rights present during the move
|
||||||
|
* @param enPassant the en passant {@link Position} valid after the logged
|
||||||
* {@link Move}, or {@code null} if there is none
|
* {@link Move}, or {@code null} if there is none
|
||||||
* @param activeColor The {@link Color} active after the logged {@link Move}
|
* @param activeColor the {@link Color} active after the logged {@link Move}
|
||||||
* @param fullmoveCounter
|
* @param fullmoveCounter the number of moves made until the current move
|
||||||
* @param halfmoveClock
|
* @param halfmoveClock the number of halfmoves since the last capture move or
|
||||||
|
* pawn move
|
||||||
*/
|
*/
|
||||||
public MoveNode(Move move, Piece capturedPiece, boolean castlingRights[], Position enPassant, Color activeColor,
|
public MoveNode(Move move, Piece capturedPiece, boolean castlingRights[], Position enPassant, Color activeColor, int fullmoveCounter,
|
||||||
int fullmoveCounter, int halfmoveClock) {
|
int halfmoveClock) {
|
||||||
this.move = move;
|
this.move = move;
|
||||||
this.capturedPiece = capturedPiece;
|
this.capturedPiece = capturedPiece;
|
||||||
this.castlingRights = castlingRights;
|
this.castlingRights = castlingRights;
|
||||||
@ -60,8 +106,8 @@ public class MoveNode {
|
|||||||
* considers subsequent variations
|
* considers subsequent variations
|
||||||
*/
|
*/
|
||||||
public MoveNode(MoveNode other, boolean copyVariations) {
|
public MoveNode(MoveNode other, boolean copyVariations) {
|
||||||
this(other.move, other.capturedPiece, other.castlingRights.clone(), other.enPassant, other.activeColor,
|
this(other.move, other.capturedPiece, other.castlingRights.clone(), other.enPassant, other.activeColor, other.fullmoveCounter,
|
||||||
other.fullmoveCounter, other.halfmoveClock);
|
other.halfmoveClock);
|
||||||
if (copyVariations && other.variations != null) {
|
if (copyVariations && other.variations != null) {
|
||||||
if (variations == null) variations = new ArrayList<>();
|
if (variations == null) variations = new ArrayList<>();
|
||||||
for (MoveNode variation : other.variations) {
|
for (MoveNode variation : other.variations) {
|
||||||
@ -90,25 +136,34 @@ public class MoveNode {
|
|||||||
*/
|
*/
|
||||||
public List<MoveNode> getVariations() { return variations; }
|
public List<MoveNode> getVariations() { return variations; }
|
||||||
|
|
||||||
public boolean hasVariations() {
|
/**
|
||||||
return variations != null && variations.size() > 0;
|
* @return {@code true} if this move node has any variations
|
||||||
}
|
*/
|
||||||
|
public boolean hasVariations() { return variations != null && variations.size() > 0; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the parent node of this move node
|
||||||
|
*/
|
||||||
public MoveNode getParent() { return parent; }
|
public MoveNode getParent() { return parent; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the parent node of this move node
|
||||||
|
*
|
||||||
|
* @param parent the parent node to set
|
||||||
|
*/
|
||||||
public void setParent(MoveNode parent) { this.parent = parent; }
|
public void setParent(MoveNode parent) { this.parent = parent; }
|
||||||
|
|
||||||
public boolean hasParent() {
|
/**
|
||||||
return parent != null;
|
* @return {@code true} if this move node has a parent
|
||||||
}
|
*/
|
||||||
|
public boolean hasParent() { return parent != null; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
int result = 1;
|
int result = 1;
|
||||||
result = prime * result + Arrays.hashCode(castlingRights);
|
result = prime * result + Arrays.hashCode(castlingRights);
|
||||||
result = prime * result
|
result = prime * result + Objects.hash(activeColor, capturedPiece, enPassant, fullmoveCounter, halfmoveClock, move);
|
||||||
+ Objects.hash(activeColor, capturedPiece, enPassant, fullmoveCounter, halfmoveClock, move);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +175,6 @@ public class MoveNode {
|
|||||||
MoveNode other = (MoveNode) obj;
|
MoveNode other = (MoveNode) obj;
|
||||||
return activeColor == other.activeColor && Objects.equals(capturedPiece, other.capturedPiece)
|
return activeColor == other.activeColor && Objects.equals(capturedPiece, other.capturedPiece)
|
||||||
&& Arrays.equals(castlingRights, other.castlingRights) && Objects.equals(enPassant, other.enPassant)
|
&& Arrays.equals(castlingRights, other.castlingRights) && Objects.equals(enPassant, other.enPassant)
|
||||||
&& fullmoveCounter == other.fullmoveCounter && halfmoveClock == other.halfmoveClock
|
&& fullmoveCounter == other.fullmoveCounter && halfmoveClock == other.halfmoveClock && Objects.equals(move, other.move);
|
||||||
&& Objects.equals(move, other.move);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -13,6 +13,12 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class Pawn extends Piece {
|
public class Pawn extends Piece {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates pawn {@link Piece}.
|
||||||
|
*
|
||||||
|
* @param color the color of this pawn
|
||||||
|
* @param board the board on which this pawn will be placed
|
||||||
|
*/
|
||||||
public Pawn(Color color, Board board) { super(color, board); }
|
public Pawn(Color color, Board board) { super(color, board); }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -19,6 +19,19 @@ public class PawnPromotion extends Move {
|
|||||||
private final Constructor<? extends Piece> promotionPieceConstructor;
|
private final Constructor<? extends Piece> promotionPieceConstructor;
|
||||||
private final char promotionPieceChar;
|
private final char promotionPieceChar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a pawn promotion move.
|
||||||
|
*
|
||||||
|
* @param pos the position of this move
|
||||||
|
* @param dest the destination of this move
|
||||||
|
* @param promotionPieceClass the class of the piece to which the pawn is
|
||||||
|
* promoted
|
||||||
|
*
|
||||||
|
* @throws ReflectiveOperationException if the promotion piece could not be
|
||||||
|
* instantiated
|
||||||
|
* @throws RuntimeException if the promotion piece could not be
|
||||||
|
* instantiated
|
||||||
|
*/
|
||||||
public PawnPromotion(Position pos, Position dest, Class<? extends Piece> promotionPieceClass)
|
public PawnPromotion(Position pos, Position dest, Class<? extends Piece> promotionPieceClass)
|
||||||
throws ReflectiveOperationException, RuntimeException {
|
throws ReflectiveOperationException, RuntimeException {
|
||||||
super(pos, dest);
|
super(pos, dest);
|
||||||
@ -31,9 +44,24 @@ public class PawnPromotion extends Move {
|
|||||||
promotionPieceChar = (char) promotionPieceClass.getMethod("firstChar").invoke(promotionPieceConstructor.newInstance(null, null));
|
promotionPieceChar = (char) promotionPieceClass.getMethod("firstChar").invoke(promotionPieceConstructor.newInstance(null, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
public PawnPromotion(int xPos, int yPos, int xDest, int yDest, Class<? extends Piece> promotionPiece)
|
/**
|
||||||
|
*
|
||||||
|
* Creates an instance of {@link PawnPromotion}.
|
||||||
|
*
|
||||||
|
* @param xPos the horizontal position of this move
|
||||||
|
* @param yPos the vertical position of this move
|
||||||
|
* @param xDest the horizontal destination of this move
|
||||||
|
* @param yDest the vertical destination of this move
|
||||||
|
* @param promotionPieceClass the class of the piece to which the pawn is
|
||||||
|
* promoted
|
||||||
|
* @throws ReflectiveOperationException if the promotion piece could not be
|
||||||
|
* instantiated
|
||||||
|
* @throws RuntimeException if the promotion piece could not be
|
||||||
|
* instantiated
|
||||||
|
*/
|
||||||
|
public PawnPromotion(int xPos, int yPos, int xDest, int yDest, Class<? extends Piece> promotionPieceClass)
|
||||||
throws ReflectiveOperationException, RuntimeException {
|
throws ReflectiveOperationException, RuntimeException {
|
||||||
this(new Position(xPos, yPos), new Position(xDest, yDest), promotionPiece);
|
this(new Position(xPos, yPos), new Position(xDest, yDest), promotionPieceClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -5,6 +5,8 @@ import java.util.List;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Represents a piece on a board with a color.<br>
|
||||||
|
* <br>
|
||||||
* Project: <strong>Chess</strong><br>
|
* Project: <strong>Chess</strong><br>
|
||||||
* File: <strong>Piece.java</strong><br>
|
* File: <strong>Piece.java</strong><br>
|
||||||
* Created: <strong>01.07.2019</strong><br>
|
* Created: <strong>01.07.2019</strong><br>
|
||||||
@ -17,11 +19,23 @@ public abstract class Piece implements Cloneable {
|
|||||||
private final Color color;
|
private final Color color;
|
||||||
protected Board board;
|
protected Board board;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a piece.
|
||||||
|
*
|
||||||
|
* @param color the color of this piece
|
||||||
|
* @param board the board on which this piece is placed
|
||||||
|
*/
|
||||||
public Piece(Color color, Board board) {
|
public Piece(Color color, Board board) {
|
||||||
this.color = color;
|
this.color = color;
|
||||||
this.board = board;
|
this.board = board;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generated a list of legal moves this piece can make.
|
||||||
|
*
|
||||||
|
* @param pos the position of this piece
|
||||||
|
* @return a list of legal moves this piece can make
|
||||||
|
*/
|
||||||
public List<Move> getMoves(Position pos) {
|
public List<Move> getMoves(Position pos) {
|
||||||
List<Move> moves = getPseudolegalMoves(pos);
|
List<Move> moves = getPseudolegalMoves(pos);
|
||||||
for (Iterator<Move> iterator = moves.iterator(); iterator.hasNext();) {
|
for (Iterator<Move> iterator = moves.iterator(); iterator.hasNext();) {
|
||||||
@ -33,8 +47,20 @@ public abstract class Piece implements Cloneable {
|
|||||||
return moves;
|
return moves;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a list of pseudo legal moves this piece can make.
|
||||||
|
*
|
||||||
|
* @param pos the position of this piece
|
||||||
|
* @return a list of pseudo legal moves this piece can make
|
||||||
|
*/
|
||||||
protected abstract List<Move> getPseudolegalMoves(Position pos);
|
protected abstract List<Move> getPseudolegalMoves(Position pos);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks, if a given move is valid.
|
||||||
|
*
|
||||||
|
* @param move the move to check
|
||||||
|
* @return {@code true} if the move is valid
|
||||||
|
*/
|
||||||
public abstract boolean isValidMove(Move move);
|
public abstract boolean isValidMove(Move move);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -42,6 +68,7 @@ public abstract class Piece implements Cloneable {
|
|||||||
* free.
|
* free.
|
||||||
*
|
*
|
||||||
* @param move The move to check
|
* @param move The move to check
|
||||||
|
* @return {@true} if the path is free
|
||||||
*/
|
*/
|
||||||
protected boolean isFreePath(Move move) {
|
protected boolean isFreePath(Move move) {
|
||||||
for (int i = move.getPos().x + move.getxSign(), j = move.getPos().y + move.getySign(); i != move.getDest().x
|
for (int i = move.getPos().x + move.getxSign(), j = move.getPos().y + move.getySign(); i != move.getDest().x
|
||||||
@ -97,6 +124,11 @@ public abstract class Piece implements Cloneable {
|
|||||||
*/
|
*/
|
||||||
public char firstChar() { return Character.toLowerCase(toString().charAt(0)); }
|
public char firstChar() { return Character.toLowerCase(toString().charAt(0)); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param firstChar the first character of a piece's name
|
||||||
|
* @return the class of the piece associated with that character or {@code null}
|
||||||
|
* if no piece is associated with the given character
|
||||||
|
*/
|
||||||
public static Class<? extends Piece> fromFirstChar(char firstChar) {
|
public static Class<? extends Piece> fromFirstChar(char firstChar) {
|
||||||
switch (Character.toLowerCase(firstChar)) {
|
switch (Character.toLowerCase(firstChar)) {
|
||||||
case 'k':
|
case 'k':
|
||||||
@ -121,14 +153,41 @@ public abstract class Piece implements Cloneable {
|
|||||||
*/
|
*/
|
||||||
public Color getColor() { return color; }
|
public Color getColor() { return color; }
|
||||||
|
|
||||||
public static enum Color {
|
/**
|
||||||
|
* Project: <strong>Chess</strong><br>
|
||||||
|
* File: <strong>Piece.java</strong><br>
|
||||||
|
* Created: <strong>01.07.2019</strong><br>
|
||||||
|
*
|
||||||
|
* @author Kai S. K. Engelbart
|
||||||
|
* @since Chess v0.1-alpha
|
||||||
|
*/
|
||||||
|
public enum Color {
|
||||||
|
|
||||||
WHITE, BLACK;
|
/**
|
||||||
|
* Represents the color of the white pieces on a board.
|
||||||
|
*/
|
||||||
|
WHITE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the color of the black pieces on a board.
|
||||||
|
*/
|
||||||
|
BLACK;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param c the first character of a color's name
|
||||||
|
* @return {@code WHITE} if the character is {@code w} or {@code W}, else
|
||||||
|
* {@code BLACK}
|
||||||
|
*/
|
||||||
public static Color fromFirstChar(char c) { return Character.toLowerCase(c) == 'w' ? WHITE : BLACK; }
|
public static Color fromFirstChar(char c) { return Character.toLowerCase(c) == 'w' ? WHITE : BLACK; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the first character (lower case) of this color
|
||||||
|
*/
|
||||||
public char firstChar() { return this == WHITE ? 'w' : 'b'; }
|
public char firstChar() { return this == WHITE ? 'w' : 'b'; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the opposite of this color
|
||||||
|
*/
|
||||||
public Color opposite() { return this == WHITE ? BLACK : WHITE; }
|
public Color opposite() { return this == WHITE ? BLACK : WHITE; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,25 +10,44 @@ package dev.kske.chess.board;
|
|||||||
*/
|
*/
|
||||||
public class Position {
|
public class Position {
|
||||||
|
|
||||||
public final int x, y;
|
/**
|
||||||
|
* The horizontal component of this position.
|
||||||
|
*/
|
||||||
|
public final int x;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The vertical component of this position.
|
||||||
|
*/
|
||||||
|
public final int y;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a position.
|
||||||
|
*
|
||||||
|
* @param x the horizontal component of this position
|
||||||
|
* @param y the vertical component of this position
|
||||||
|
*/
|
||||||
public Position(int x, int y) {
|
public Position(int x, int y) {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Position fromLAN(String pos) {
|
/**
|
||||||
return new Position(pos.charAt(0) - 97, 8 - Character.getNumericValue(pos.charAt(1)));
|
* Constructs a position from Long Algebraic Notation (LAN)
|
||||||
}
|
*
|
||||||
|
* @param pos the LAN string to construct a position from
|
||||||
|
* @return the position constructed from LAN
|
||||||
|
*/
|
||||||
|
public static Position fromLAN(String pos) { return new Position(pos.charAt(0) - 97, 8 - Character.getNumericValue(pos.charAt(1))); }
|
||||||
|
|
||||||
public String toLAN() {
|
/**
|
||||||
return String.valueOf((char) (x + 97)) + String.valueOf(8 - y);
|
* Converts this position to Long Algebraic Notation (LAN)
|
||||||
}
|
*
|
||||||
|
* @return a LAN string representing this position
|
||||||
|
*/
|
||||||
|
public String toLAN() { return String.valueOf((char) (x + 97)) + String.valueOf(8 - y); }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() { return String.format("[%d, %d]", x, y); }
|
||||||
return String.format("[%d, %d]", x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
|
@ -13,6 +13,12 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class Queen extends Piece {
|
public class Queen extends Piece {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates queen {@link Piece}.
|
||||||
|
*
|
||||||
|
* @param color the color of this queen
|
||||||
|
* @param board the board on which this queen will be placed
|
||||||
|
*/
|
||||||
public Queen(Color color, Board board) {
|
public Queen(Color color, Board board) {
|
||||||
super(color, board);
|
super(color, board);
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,12 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class Rook extends Piece {
|
public class Rook extends Piece {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates rook {@link Piece}.
|
||||||
|
*
|
||||||
|
* @param color the color of this rook
|
||||||
|
* @param board the board on which this rook will be placed
|
||||||
|
*/
|
||||||
public Rook(Color color, Board board) {
|
public Rook(Color color, Board board) {
|
||||||
super(color, board);
|
super(color, board);
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ package dev.kske.chess.event;
|
|||||||
*
|
*
|
||||||
* @since Chess v0.4-alpha
|
* @since Chess v0.4-alpha
|
||||||
* @author Kai S. K. Engelbart
|
* @author Kai S. K. Engelbart
|
||||||
|
* @param <T> the type of the event's value
|
||||||
*/
|
*/
|
||||||
public interface Event<T> {
|
public interface Event<T> {
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Dispatches {@link Event}s to various {@link Subscriber}s.<br>
|
||||||
|
* <br>
|
||||||
* Project: <strong>Chess</strong><br>
|
* Project: <strong>Chess</strong><br>
|
||||||
* File: <strong>EventBus.java</strong><br>
|
* File: <strong>EventBus.java</strong><br>
|
||||||
* Created: <strong>7 Aug 2019</strong><br>
|
* Created: <strong>7 Aug 2019</strong><br>
|
||||||
@ -13,26 +15,38 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class EventBus {
|
public class EventBus {
|
||||||
|
|
||||||
private List<Subscribable> subscribers;
|
private List<Subscriber> subscribers;
|
||||||
|
|
||||||
private static EventBus instance;
|
private static EventBus instance;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a singleton instance of {@link EventBus}
|
||||||
|
*/
|
||||||
public static EventBus getInstance() {
|
public static EventBus getInstance() {
|
||||||
if (instance == null) instance = new EventBus();
|
if (instance == null) instance = new EventBus();
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private EventBus() {
|
private EventBus() { subscribers = new ArrayList<>(); }
|
||||||
subscribers = new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void register(Subscribable subscribable) {
|
/**
|
||||||
subscribers.add(subscribable);
|
* Registers a subscriber to which future events will be dispatched.
|
||||||
}
|
*
|
||||||
|
* @param subscribable the subscriber to register
|
||||||
|
*/
|
||||||
|
public void register(Subscriber subscribable) { subscribers.add(subscribable); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispatches an event to all {@Subscriber}s registered at this event bus.
|
||||||
|
*
|
||||||
|
* @param event the event to dispatch
|
||||||
|
*/
|
||||||
public void dispatch(Event<?> event) {
|
public void dispatch(Event<?> event) {
|
||||||
subscribers.stream().filter(e -> e.supports().contains(event.getClass())).forEach(e -> e.handle(event));
|
subscribers.stream().filter(e -> e.supports().contains(event.getClass())).forEach(e -> e.handle(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Subscribable> getSubscribers() { return subscribers; }
|
/**
|
||||||
|
* @return a list of all registered subscribers
|
||||||
|
*/
|
||||||
|
public List<Subscriber> getSubscribers() { return subscribers; }
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,11 @@ public class GameStartEvent implements Event<Game> {
|
|||||||
|
|
||||||
private final Game game;
|
private final Game game;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of {@link GameStartEvent}.
|
||||||
|
*
|
||||||
|
* @param source the game started
|
||||||
|
*/
|
||||||
public GameStartEvent(Game source) { game = source; }
|
public GameStartEvent(Game source) { game = source; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -16,6 +16,12 @@ public class MoveEvent implements Event<Move> {
|
|||||||
private final Move move;
|
private final Move move;
|
||||||
private final BoardState boardState;
|
private final BoardState boardState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of {@link MoveEvent}.
|
||||||
|
*
|
||||||
|
* @param move the move by which the event was triggered
|
||||||
|
* @param boardState the state of the board after the move
|
||||||
|
*/
|
||||||
public MoveEvent(Move move, BoardState boardState) {
|
public MoveEvent(Move move, BoardState boardState) {
|
||||||
this.move = move;
|
this.move = move;
|
||||||
this.boardState = boardState;
|
this.boardState = boardState;
|
||||||
@ -24,5 +30,8 @@ public class MoveEvent implements Event<Move> {
|
|||||||
@Override
|
@Override
|
||||||
public Move getData() { return move; }
|
public Move getData() { return move; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the state of the board after the move
|
||||||
|
*/
|
||||||
public BoardState getBoardState() { return boardState; }
|
public BoardState getBoardState() { return boardState; }
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,10 @@ package dev.kske.chess.event;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Implementations of this interface can register themselves at the
|
||||||
|
* {@link EventBus} and will be triggered every time an {@link Event} of a
|
||||||
|
* supported type.<br>
|
||||||
|
* <br>
|
||||||
* Project: <strong>Chess</strong><br>
|
* Project: <strong>Chess</strong><br>
|
||||||
* File: <strong>Subscribable.java</strong><br>
|
* File: <strong>Subscribable.java</strong><br>
|
||||||
* Created: <strong>7 Aug 2019</strong><br>
|
* Created: <strong>7 Aug 2019</strong><br>
|
||||||
@ -10,7 +14,7 @@ import java.util.Set;
|
|||||||
* @since Chess v0.4-alpha
|
* @since Chess v0.4-alpha
|
||||||
* @author Kai S. K. Engelbart
|
* @author Kai S. K. Engelbart
|
||||||
*/
|
*/
|
||||||
public interface Subscribable {
|
public interface Subscriber {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Consumes an event dispatched by an event bus.
|
* Consumes an event dispatched by an event bus.
|
@ -12,14 +12,30 @@ public class ChessException extends Exception {
|
|||||||
|
|
||||||
private static final long serialVersionUID = -2208596063548245189L;
|
private static final long serialVersionUID = -2208596063548245189L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes chess exception.
|
||||||
|
*
|
||||||
|
* @param message the message associated with this exception
|
||||||
|
* @param cause the cause of this exception
|
||||||
|
*/
|
||||||
public ChessException(String message, Throwable cause) {
|
public ChessException(String message, Throwable cause) {
|
||||||
super(message, cause);
|
super(message, cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes chess exception.
|
||||||
|
*
|
||||||
|
* @param message the message associated with this exception
|
||||||
|
*/
|
||||||
public ChessException(String message) {
|
public ChessException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes chess exception.
|
||||||
|
*
|
||||||
|
* @param cause the cause of this exception
|
||||||
|
*/
|
||||||
public ChessException(Throwable cause) {
|
public ChessException(Throwable cause) {
|
||||||
super(cause);
|
super(cause);
|
||||||
}
|
}
|
||||||
|
@ -34,11 +34,26 @@ public class Game {
|
|||||||
private OverlayComponent overlayComponent;
|
private OverlayComponent overlayComponent;
|
||||||
private BoardComponent boardComponent;
|
private BoardComponent boardComponent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes game with a new {@link Board}.
|
||||||
|
*
|
||||||
|
* @param boardPane the board pane which will display the newly created board
|
||||||
|
* @param whiteName the name of the player controlling the white pieces
|
||||||
|
* @param blackName the name of the player controlling the black pieces
|
||||||
|
*/
|
||||||
public Game(BoardPane boardPane, String whiteName, String blackName) {
|
public Game(BoardPane boardPane, String whiteName, String blackName) {
|
||||||
board = new Board();
|
board = new Board();
|
||||||
init(boardPane, whiteName, blackName);
|
init(boardPane, whiteName, blackName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes game with an existing {@link Board}.
|
||||||
|
*
|
||||||
|
* @param boardPane the board pane which will display the newly created board
|
||||||
|
* @param whiteName the name of the player controlling the white pieces
|
||||||
|
* @param blackName the name of the player controlling the black pieces
|
||||||
|
* @param board the board on which the game will be played
|
||||||
|
*/
|
||||||
public Game(BoardPane boardPane, String whiteName, String blackName, Board board) {
|
public Game(BoardPane boardPane, String whiteName, String blackName, Board board) {
|
||||||
this.board = board;
|
this.board = board;
|
||||||
init(boardPane, whiteName, blackName);
|
init(boardPane, whiteName, blackName);
|
||||||
@ -59,6 +74,17 @@ public class Game {
|
|||||||
players.values().forEach(player -> player.setGame(this));
|
players.values().forEach(player -> player.setGame(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes player subclass.
|
||||||
|
*
|
||||||
|
* @param name the name of the player. {@code Natural Player} will initialize a
|
||||||
|
* {@link NaturalPlayer}, {@code AI Player} will initialize an
|
||||||
|
* {@link AIPlayer}. Everything else will attempt to load an engine
|
||||||
|
* with that name
|
||||||
|
* @param color the color of the player
|
||||||
|
* @return the instantiated player or {@code null} if the name could not be
|
||||||
|
* recognized
|
||||||
|
*/
|
||||||
private Player getPlayer(String name, Color color) {
|
private Player getPlayer(String name, Color color) {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case "Natural Player":
|
case "Natural Player":
|
||||||
@ -73,6 +99,14 @@ public class Game {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should be called once a player makes a move. Depending on the legality of
|
||||||
|
* that move and the state of the game another move might be requested from one
|
||||||
|
* of the players.
|
||||||
|
*
|
||||||
|
* @param player the player who generated the move
|
||||||
|
* @param move the generated move
|
||||||
|
*/
|
||||||
public void onMove(Player player, Move move) {
|
public void onMove(Player player, Move move) {
|
||||||
if (board.getPos(move).getColor() == player.color && board.attemptMove(move)) {
|
if (board.getPos(move).getColor() == player.color && board.attemptMove(move)) {
|
||||||
|
|
||||||
@ -83,7 +117,7 @@ public class Game {
|
|||||||
// Run garbage collection
|
// Run garbage collection
|
||||||
System.gc();
|
System.gc();
|
||||||
|
|
||||||
BoardState boardState = board.getGameEventType(board.getDest(move).getColor().opposite());
|
BoardState boardState = board.getState(board.getDest(move).getColor().opposite());
|
||||||
EventBus.getInstance().dispatch(new MoveEvent(move, boardState));
|
EventBus.getInstance().dispatch(new MoveEvent(move, boardState));
|
||||||
switch (boardState) {
|
switch (boardState) {
|
||||||
case CHECKMATE:
|
case CHECKMATE:
|
||||||
@ -100,11 +134,19 @@ public class Game {
|
|||||||
} else player.requestMove();
|
} else player.requestMove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the game by requesting a move from the player of the currently active
|
||||||
|
* color.
|
||||||
|
*/
|
||||||
public void start() {
|
public void start() {
|
||||||
EventBus.getInstance().dispatch(new GameStartEvent(this));
|
EventBus.getInstance().dispatch(new GameStartEvent(this));
|
||||||
players.get(board.getLog().getActiveColor()).requestMove();
|
players.get(board.getLog().getActiveColor()).requestMove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels move calculations, initializes the default position and clears the
|
||||||
|
* {@link OverlayComponent}.
|
||||||
|
*/
|
||||||
public void reset() {
|
public void reset() {
|
||||||
players.values().forEach(Player::cancelMove);
|
players.values().forEach(Player::cancelMove);
|
||||||
board.initDefaultPositions();
|
board.initDefaultPositions();
|
||||||
@ -114,11 +156,9 @@ public class Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stops the game by disconnecting its players form the UI.
|
* Stops the game by disconnecting its players from the UI.
|
||||||
*/
|
*/
|
||||||
public void stop() {
|
public void stop() { players.values().forEach(Player::disconnect); }
|
||||||
players.values().forEach(Player::disconnect);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assigns the players their opposite colors.
|
* Assigns the players their opposite colors.
|
||||||
|
@ -15,6 +15,10 @@ import dev.kske.chess.board.Position;
|
|||||||
import dev.kske.chess.ui.OverlayComponent;
|
import dev.kske.chess.ui.OverlayComponent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Enables the user to make moves in a {@link Game} by clicking on a
|
||||||
|
* {@link Piece} and then selecting one of the highlighted positions as the move
|
||||||
|
* destination.<br>
|
||||||
|
* <br>
|
||||||
* Project: <strong>Chess</strong><br>
|
* Project: <strong>Chess</strong><br>
|
||||||
* File: <strong>NaturalPlayer.java</strong><br>
|
* File: <strong>NaturalPlayer.java</strong><br>
|
||||||
* Created: <strong>06.07.2019</strong><br>
|
* Created: <strong>06.07.2019</strong><br>
|
||||||
@ -30,6 +34,13 @@ public class NaturalPlayer extends Player implements MouseListener {
|
|||||||
private Piece selectedPiece;
|
private Piece selectedPiece;
|
||||||
private List<Move> possibleMoves;
|
private List<Move> possibleMoves;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of {@link NaturalPlayer}.
|
||||||
|
*
|
||||||
|
* @param color the piece color this player will control
|
||||||
|
* @param overlayComponent the overlay component that will be used to display
|
||||||
|
* possible moves to the user
|
||||||
|
*/
|
||||||
public NaturalPlayer(Color color, OverlayComponent overlayComponent) {
|
public NaturalPlayer(Color color, OverlayComponent overlayComponent) {
|
||||||
super(color);
|
super(color);
|
||||||
this.overlayComponent = overlayComponent;
|
this.overlayComponent = overlayComponent;
|
||||||
@ -82,7 +93,7 @@ public class NaturalPlayer extends Player implements MouseListener {
|
|||||||
if (selectedMoves.size() > 1) {
|
if (selectedMoves.size() > 1) {
|
||||||
|
|
||||||
// Let the user select a promotion piece
|
// Let the user select a promotion piece
|
||||||
JComboBox<Move> comboBox = new JComboBox<Move>(selectedMoves.toArray(new Move[0]));
|
JComboBox<Move> comboBox = new JComboBox<>(selectedMoves.toArray(new Move[0]));
|
||||||
JOptionPane.showMessageDialog(overlayComponent, comboBox, "Select a promotion", JOptionPane.QUESTION_MESSAGE);
|
JOptionPane.showMessageDialog(overlayComponent, comboBox, "Select a promotion", JOptionPane.QUESTION_MESSAGE);
|
||||||
|
|
||||||
move = selectedMoves.get(comboBox.getSelectedIndex());
|
move = selectedMoves.get(comboBox.getSelectedIndex());
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
package dev.kske.chess.game;
|
package dev.kske.chess.game;
|
||||||
|
|
||||||
import dev.kske.chess.board.Board;
|
import dev.kske.chess.board.Board;
|
||||||
|
import dev.kske.chess.board.Move;
|
||||||
import dev.kske.chess.board.Piece.Color;
|
import dev.kske.chess.board.Piece.Color;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Acts as the interface between the {@link Game} class and some kind of move
|
||||||
|
* generation backend implemented as a subclass.<br>
|
||||||
|
* <br>
|
||||||
* Project: <strong>Chess</strong><br>
|
* Project: <strong>Chess</strong><br>
|
||||||
* File: <strong>Player.java</strong><br>
|
* File: <strong>Player.java</strong><br>
|
||||||
* Created: <strong>06.07.2019</strong><br>
|
* Created: <strong>06.07.2019</strong><br>
|
||||||
@ -18,32 +22,71 @@ public abstract class Player {
|
|||||||
protected Color color;
|
protected Color color;
|
||||||
protected String name;
|
protected String name;
|
||||||
|
|
||||||
public Player(Color color) {
|
/**
|
||||||
this.color = color;
|
* Initializes the color of this player.
|
||||||
}
|
*
|
||||||
|
* @param color the piece color that this player will control
|
||||||
|
*/
|
||||||
|
public Player(Color color) { this.color = color; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initiates a move generation and reports the result to the game by calling
|
||||||
|
* {@link Game#onMove(Player, Move)}.
|
||||||
|
*/
|
||||||
public abstract void requestMove();
|
public abstract void requestMove();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels the move generation process.
|
||||||
|
*/
|
||||||
public abstract void cancelMove();
|
public abstract void cancelMove();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes all resources required for move generation.
|
||||||
|
*/
|
||||||
public abstract void disconnect();
|
public abstract void disconnect();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the game in which this player is used
|
||||||
|
*/
|
||||||
public Game getGame() { return game; }
|
public Game getGame() { return game; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the game in which this player is used. The board of that game will be
|
||||||
|
* assigned as well.
|
||||||
|
*
|
||||||
|
* @param game the game to set
|
||||||
|
*/
|
||||||
public void setGame(Game game) {
|
public void setGame(Game game) {
|
||||||
this.game = game;
|
this.game = game;
|
||||||
board = game.getBoard();
|
board = game.getBoard();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the board on which this player is used
|
||||||
|
*/
|
||||||
public Board getBoard() { return board; }
|
public Board getBoard() { return board; }
|
||||||
|
|
||||||
public void setBoard(Board board) { this.board = board; }
|
/**
|
||||||
|
* @return the color of pieces controlled by this player
|
||||||
|
*/
|
||||||
public Color getColor() { return color; }
|
public Color getColor() { return color; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the color of pieces controlled by this player.
|
||||||
|
*
|
||||||
|
* @param color the color to set
|
||||||
|
*/
|
||||||
public void setColor(Color color) { this.color = color; }
|
public void setColor(Color color) { this.color = color; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the name of this player
|
||||||
|
*/
|
||||||
public String getName() { return name; }
|
public String getName() { return name; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the name of this player
|
||||||
|
*
|
||||||
|
* @param name the name to set
|
||||||
|
*/
|
||||||
public void setName(String name) { this.name = name; }
|
public void setName(String name) { this.name = name; }
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,10 @@ import dev.kske.chess.uci.UCIHandle;
|
|||||||
import dev.kske.chess.uci.UCIListener;
|
import dev.kske.chess.uci.UCIListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Acts as the interface between the {@link Game} class and the
|
||||||
|
* {@link dev.kske.chess.uci} package enabling an engine to make moves in a
|
||||||
|
* game.<br>
|
||||||
|
* <br>
|
||||||
* Project: <strong>Chess</strong><br>
|
* Project: <strong>Chess</strong><br>
|
||||||
* File: <strong>UCIPlayer.java</strong><br>
|
* File: <strong>UCIPlayer.java</strong><br>
|
||||||
* Created: <strong>18.07.2019</strong><br>
|
* Created: <strong>18.07.2019</strong><br>
|
||||||
@ -20,11 +24,17 @@ public class UCIPlayer extends Player implements UCIListener {
|
|||||||
|
|
||||||
private UCIHandle handle;
|
private UCIHandle handle;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of {@link UCIPlayer}.
|
||||||
|
*
|
||||||
|
* @param color the piece color that this player will control
|
||||||
|
* @param enginePath the path to the engine executable
|
||||||
|
*/
|
||||||
public UCIPlayer(Color color, String enginePath) {
|
public UCIPlayer(Color color, String enginePath) {
|
||||||
super(color);
|
super(color);
|
||||||
try {
|
try {
|
||||||
handle = new UCIHandle(enginePath);
|
handle = new UCIHandle(enginePath);
|
||||||
handle.setListener(this);
|
handle.registerListener(this);
|
||||||
handle.start();
|
handle.start();
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
@ -38,19 +48,13 @@ public class UCIPlayer extends Player implements UCIListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cancelMove() {
|
public void cancelMove() { handle.stop(); }
|
||||||
handle.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void disconnect() {
|
public void disconnect() { handle.quit(); }
|
||||||
handle.quit();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onIdName(String name) {
|
public void onIdName(String name) { this.name = name; }
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBestMove(String move) {
|
public void onBestMove(String move) {
|
||||||
@ -59,37 +63,23 @@ public class UCIPlayer extends Player implements UCIListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBestMove(String move, Move ponderMove) {
|
public void onBestMove(String move, Move ponderMove) { onBestMove(move); }
|
||||||
onBestMove(move);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCopyProtectionChecking() {
|
public void onCopyProtectionChecking() { System.out.println("Copy protection checking..."); }
|
||||||
System.out.println("Copy protection checking...");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCopyProtectionOk() {
|
public void onCopyProtectionOk() { System.out.println("Copy protection ok"); }
|
||||||
System.out.println("Copy protection ok");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCopyProtectionError() {
|
public void onCopyProtectionError() { System.err.println("Copy protection error!"); }
|
||||||
System.err.println("Copy protection error!");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRegistrationChecking() {
|
public void onRegistrationChecking() { System.out.println("Registration checking..."); }
|
||||||
System.out.println("Registration checking...");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRegistrationOk() {
|
public void onRegistrationOk() { System.out.println("Registration ok"); }
|
||||||
System.out.println("Registration ok");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRegistrationError() {
|
public void onRegistrationError() { System.err.println("Registration error!"); }
|
||||||
System.err.println("Registration error!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,7 @@ package dev.kske.chess.game.ai;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.*;
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
|
||||||
@ -32,6 +28,15 @@ public class AIPlayer extends Player {
|
|||||||
private volatile boolean exitRequested;
|
private volatile boolean exitRequested;
|
||||||
private volatile ExecutorService executor;
|
private volatile ExecutorService executor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of {@link AIPlayer}.
|
||||||
|
*
|
||||||
|
* @param color the piece color this player will control
|
||||||
|
* @param maxDepth the maximum search depth
|
||||||
|
* @param alphaBetaThreshold the board evaluation threshold that has to be
|
||||||
|
* reached to continue searching the children of a
|
||||||
|
* move
|
||||||
|
*/
|
||||||
public AIPlayer(Color color, int maxDepth, int alphaBetaThreshold) {
|
public AIPlayer(Color color, int maxDepth, int alphaBetaThreshold) {
|
||||||
super(color);
|
super(color);
|
||||||
name = "AIPlayer";
|
name = "AIPlayer";
|
||||||
|
@ -5,18 +5,12 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
import dev.kske.chess.board.Bishop;
|
import dev.kske.chess.board.*;
|
||||||
import dev.kske.chess.board.Board;
|
|
||||||
import dev.kske.chess.board.King;
|
|
||||||
import dev.kske.chess.board.Knight;
|
|
||||||
import dev.kske.chess.board.Move;
|
|
||||||
import dev.kske.chess.board.Pawn;
|
|
||||||
import dev.kske.chess.board.Piece;
|
|
||||||
import dev.kske.chess.board.Piece.Color;
|
import dev.kske.chess.board.Piece.Color;
|
||||||
import dev.kske.chess.board.Queen;
|
|
||||||
import dev.kske.chess.board.Rook;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Implements a basic minimax move search algorithm for testing purposes.<br>
|
||||||
|
* <br>
|
||||||
* Project: <strong>Chess</strong><br>
|
* Project: <strong>Chess</strong><br>
|
||||||
* File: <strong>MoveProcessor.java</strong><br>
|
* File: <strong>MoveProcessor.java</strong><br>
|
||||||
* Created: <strong>08.07.2019</strong><br>
|
* Created: <strong>08.07.2019</strong><br>
|
||||||
@ -68,6 +62,16 @@ public class MoveProcessor implements Callable<ProcessingResult> {
|
|||||||
new int[] { 0, 1, 1, -2, -2, 1, 1, 0 }, new int[] { 0, 0, 0, 0, 0, 0, 0, 0 } });
|
new int[] { 0, 1, 1, -2, -2, 1, 1, 0 }, new int[] { 0, 0, 0, 0, 0, 0, 0, 0 } });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of {@link MoveProcessor}.
|
||||||
|
*
|
||||||
|
* @param board the board to search
|
||||||
|
* @param rootMoves the moves on which the search is based
|
||||||
|
* @param color the color for which to search
|
||||||
|
* @param maxDepth the maximal recursion depth to search to
|
||||||
|
* @param alphaBetaThreshold the threshold necessary to continue a search for a
|
||||||
|
* specific move
|
||||||
|
*/
|
||||||
public MoveProcessor(Board board, List<Move> rootMoves, Color color, int maxDepth, int alphaBetaThreshold) {
|
public MoveProcessor(Board board, List<Move> rootMoves, Color color, int maxDepth, int alphaBetaThreshold) {
|
||||||
this.board = board;
|
this.board = board;
|
||||||
this.rootMoves = rootMoves;
|
this.rootMoves = rootMoves;
|
||||||
@ -106,8 +110,9 @@ public class MoveProcessor implements Callable<ProcessingResult> {
|
|||||||
/**
|
/**
|
||||||
* Evaluated a board.
|
* Evaluated a board.
|
||||||
*
|
*
|
||||||
|
* @param board the board to evaluate
|
||||||
* @param color The color to evaluate for
|
* @param color The color to evaluate for
|
||||||
* @return An positive number representing how good the position is
|
* @return a positive number representing how good the position is
|
||||||
*/
|
*/
|
||||||
private int evaluate(Board board, Color color) {
|
private int evaluate(Board board, Color color) {
|
||||||
int score = 0;
|
int score = 0;
|
||||||
|
@ -3,6 +3,8 @@ package dev.kske.chess.game.ai;
|
|||||||
import dev.kske.chess.board.Move;
|
import dev.kske.chess.board.Move;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Contains information about a move search performed by a chess engine.
|
||||||
|
* <br>
|
||||||
* Project: <strong>Chess</strong><br>
|
* Project: <strong>Chess</strong><br>
|
||||||
* File: <strong>ProcessingResult.java</strong><br>
|
* File: <strong>ProcessingResult.java</strong><br>
|
||||||
* Created: <strong>08.07.2019</strong><br>
|
* Created: <strong>08.07.2019</strong><br>
|
||||||
@ -12,16 +14,27 @@ import dev.kske.chess.board.Move;
|
|||||||
*/
|
*/
|
||||||
public class ProcessingResult {
|
public class ProcessingResult {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The best move found by the search
|
||||||
|
*/
|
||||||
public final Move move;
|
public final Move move;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The score associated with the best move
|
||||||
|
*/
|
||||||
public final int score;
|
public final int score;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of {@link ProcessingResult}.
|
||||||
|
*
|
||||||
|
* @param move the best move found by the search
|
||||||
|
* @param score the score associated with the best move
|
||||||
|
*/
|
||||||
public ProcessingResult(Move move, int score) {
|
public ProcessingResult(Move move, int score) {
|
||||||
this.move = move;
|
this.move = move;
|
||||||
this.score = score;
|
this.score = score;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() { return String.format("ProcessingResult[Move = %s,Score = %d]", move, score); }
|
||||||
return String.format("ProcessingResult[Move = %s, Score = %d]", move, score);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,6 @@
|
|||||||
package dev.kske.chess.io;
|
package dev.kske.chess.io;
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
import java.io.*;
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -14,7 +9,7 @@ import dev.kske.chess.uci.UCIListener;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Project: <strong>Chess</strong><br>
|
* Project: <strong>Chess</strong><br>
|
||||||
* File: <strong>MenuBar.java</strong><br>
|
* File: <strong>EngineUtil.java</strong><br>
|
||||||
* Created: <strong>23.07.2019</strong><br>
|
* Created: <strong>23.07.2019</strong><br>
|
||||||
*
|
*
|
||||||
* @since Chess v0.2-alpha
|
* @since Chess v0.2-alpha
|
||||||
@ -33,21 +28,22 @@ public class EngineUtil {
|
|||||||
|
|
||||||
private EngineUtil() {}
|
private EngineUtil() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores information about an engine while checking its availability.
|
||||||
|
*
|
||||||
|
* @param enginePath the path to the executable of the engine
|
||||||
|
*/
|
||||||
public static void addEngine(String enginePath) {
|
public static void addEngine(String enginePath) {
|
||||||
try {
|
try {
|
||||||
EngineInfo info = new EngineInfo(enginePath);
|
EngineInfo info = new EngineInfo(enginePath);
|
||||||
UCIHandle handle = new UCIHandle(enginePath);
|
UCIHandle handle = new UCIHandle(enginePath);
|
||||||
handle.setListener(new UCIListener() {
|
handle.registerListener(new UCIListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onIdName(String name) {
|
public void onIdName(String name) { info.name = name; }
|
||||||
info.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onIdAuthor(String author) {
|
public void onIdAuthor(String author) { info.author = author; }
|
||||||
info.author = author;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUCIOk() {
|
public void onUCIOk() {
|
||||||
@ -81,21 +77,49 @@ public class EngineUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the name and author of an engine, as well as a path to its
|
||||||
|
* executable.<br>
|
||||||
|
* <br>
|
||||||
|
* Project: <strong>Chess</strong><br>
|
||||||
|
* File: <strong>EngineUtil.java</strong><br>
|
||||||
|
* Created: <strong>23.07.2019</strong><br>
|
||||||
|
*
|
||||||
|
* @since Chess v0.2-alpha
|
||||||
|
* @author Kai S. K. Engelbart
|
||||||
|
*/
|
||||||
public static class EngineInfo implements Serializable {
|
public static class EngineInfo implements Serializable {
|
||||||
|
|
||||||
private static final long serialVersionUID = -474177108900833005L;
|
private static final long serialVersionUID = -474177108900833005L;
|
||||||
|
|
||||||
public String path, name, author;
|
/**
|
||||||
|
* The path to the executable of the engine
|
||||||
|
*/
|
||||||
|
public String path;
|
||||||
|
|
||||||
public EngineInfo(String path) {
|
/**
|
||||||
this.path = path;
|
* The name of the engine
|
||||||
}
|
*/
|
||||||
|
public String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The author of the engine
|
||||||
|
*/
|
||||||
|
public String author;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of {@link EngineInfo}.
|
||||||
|
*
|
||||||
|
* @param path the path of the engine executable
|
||||||
|
*/
|
||||||
|
public EngineInfo(String path) { this.path = path; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() { return name + " by " + author + " at " + path; }
|
||||||
return name + " by " + author + " at " + path;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return a list of all stored engine infos
|
||||||
|
*/
|
||||||
public static List<EngineInfo> getEngineInfos() { return engineInfos; }
|
public static List<EngineInfo> getEngineInfos() { return engineInfos; }
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
package dev.kske.chess.pgn;
|
package dev.kske.chess.pgn;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.*;
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
@ -33,10 +30,10 @@ public class PGNDatabase {
|
|||||||
* @throws ChessException if an error occurs while parsing the file
|
* @throws ChessException if an error occurs while parsing the file
|
||||||
*/
|
*/
|
||||||
public void load(File pgnFile) throws FileNotFoundException, ChessException {
|
public void load(File pgnFile) throws FileNotFoundException, ChessException {
|
||||||
Scanner sc = new Scanner(pgnFile);
|
try (Scanner sc = new Scanner(pgnFile)) {
|
||||||
while (sc.hasNext())
|
while (sc.hasNext())
|
||||||
games.add(PGNGame.parse(sc));
|
games.add(PGNGame.parse(sc));
|
||||||
sc.close();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -47,10 +44,13 @@ public class PGNDatabase {
|
|||||||
*/
|
*/
|
||||||
public void save(File pgnFile) throws IOException {
|
public void save(File pgnFile) throws IOException {
|
||||||
pgnFile.getParentFile().mkdirs();
|
pgnFile.getParentFile().mkdirs();
|
||||||
PrintWriter pw = new PrintWriter(pgnFile);
|
try (PrintWriter pw = new PrintWriter(pgnFile)) {
|
||||||
games.forEach(g -> g.writePGN(pw));
|
games.forEach(g -> g.writePGN(pw));
|
||||||
pw.close();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return all games contained inside this database
|
||||||
|
*/
|
||||||
public List<PGNGame> getGames() { return games; }
|
public List<PGNGame> getGames() { return games; }
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,7 @@
|
|||||||
package dev.kske.chess.pgn;
|
package dev.kske.chess.pgn;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Scanner;
|
|
||||||
import java.util.regex.MatchResult;
|
import java.util.regex.MatchResult;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@ -14,7 +9,6 @@ import dev.kske.chess.board.Board;
|
|||||||
import dev.kske.chess.board.FENString;
|
import dev.kske.chess.board.FENString;
|
||||||
import dev.kske.chess.board.Move;
|
import dev.kske.chess.board.Move;
|
||||||
import dev.kske.chess.board.Piece.Color;
|
import dev.kske.chess.board.Piece.Color;
|
||||||
import dev.kske.chess.exception.ChessException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Project: <strong>Chess</strong><br>
|
* Project: <strong>Chess</strong><br>
|
||||||
@ -29,11 +23,27 @@ public class PGNGame {
|
|||||||
private final Map<String, String> tagPairs = new HashMap<>(7);
|
private final Map<String, String> tagPairs = new HashMap<>(7);
|
||||||
private final Board board;
|
private final Board board;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of {@link PGNGame}. A new default {@link Board} will be
|
||||||
|
* created.
|
||||||
|
*/
|
||||||
public PGNGame() { board = new Board(); }
|
public PGNGame() { board = new Board(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of {@link PGNGame}.
|
||||||
|
*
|
||||||
|
* @param board the board associated with the game
|
||||||
|
*/
|
||||||
public PGNGame(Board board) { this.board = board; }
|
public PGNGame(Board board) { this.board = board; }
|
||||||
|
|
||||||
public static PGNGame parse(Scanner sc) throws ChessException {
|
/**
|
||||||
|
* Parses a game in {@code PGN} format from a {@link Scanner} instance
|
||||||
|
*
|
||||||
|
* @param sc the {@link Scanner} to parse the game from, which is not closed
|
||||||
|
* after this process
|
||||||
|
* @return the parsed {@link PGNGame}
|
||||||
|
*/
|
||||||
|
public static PGNGame parse(Scanner sc) {
|
||||||
PGNGame game = new PGNGame();
|
PGNGame game = new PGNGame();
|
||||||
|
|
||||||
MatchResult matchResult;
|
MatchResult matchResult;
|
||||||
@ -72,6 +82,11 @@ public class PGNGame {
|
|||||||
return game;
|
return game;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes this game to {@code PGN} format.
|
||||||
|
*
|
||||||
|
* @param pw the writer to write the game to
|
||||||
|
*/
|
||||||
public void writePGN(PrintWriter pw) {
|
public void writePGN(PrintWriter pw) {
|
||||||
// Set the unknown result tag if no result tag is specified
|
// Set the unknown result tag if no result tag is specified
|
||||||
tagPairs.putIfAbsent("Result", "*");
|
tagPairs.putIfAbsent("Result", "*");
|
||||||
@ -111,11 +126,28 @@ public class PGNGame {
|
|||||||
pw.print(tagPairs.get("Result"));
|
pw.print(tagPairs.get("Result"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tagName the name of a game tag
|
||||||
|
* @return the value of the game tag
|
||||||
|
*/
|
||||||
public String getTag(String tagName) { return tagPairs.get(tagName); }
|
public String getTag(String tagName) { return tagPairs.get(tagName); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tagName the name of a game tag
|
||||||
|
* @return {@code true} if the tag is present
|
||||||
|
*/
|
||||||
public boolean hasTag(String tagName) { return tagPairs.containsKey(tagName); }
|
public boolean hasTag(String tagName) { return tagPairs.containsKey(tagName); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a game tag.
|
||||||
|
*
|
||||||
|
* @param tagName the name of the tag
|
||||||
|
* @param tagValue the value of the tag
|
||||||
|
*/
|
||||||
public void setTag(String tagName, String tagValue) { tagPairs.put(tagName, tagValue); }
|
public void setTag(String tagName, String tagValue) { tagPairs.put(tagName, tagValue); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the board associated with this game
|
||||||
|
*/
|
||||||
public Board getBoard() { return board; }
|
public Board getBoard() { return board; }
|
||||||
}
|
}
|
||||||
|
@ -21,12 +21,22 @@ public class UCIHandle {
|
|||||||
private final PrintWriter out;
|
private final PrintWriter out;
|
||||||
private final UCIReceiver receiver;
|
private final UCIReceiver receiver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of {@link UCIHandle}. The engine process is started and
|
||||||
|
* passed to a new {@link UCIReceiver}.
|
||||||
|
*
|
||||||
|
* @param enginePath the path to the engine executable
|
||||||
|
* @throws IOException if the engine process could not be started
|
||||||
|
*/
|
||||||
public UCIHandle(String enginePath) throws IOException {
|
public UCIHandle(String enginePath) throws IOException {
|
||||||
process = new ProcessBuilder(enginePath).start();
|
process = new ProcessBuilder(enginePath).start();
|
||||||
out = new PrintWriter(process.getOutputStream(), true);
|
out = new PrintWriter(process.getOutputStream(), true);
|
||||||
receiver = new UCIReceiver(process.getInputStream());
|
receiver = new UCIReceiver(process.getInputStream());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the {@link UCIReceiver} used to gather engine output.
|
||||||
|
*/
|
||||||
public void start() {
|
public void start() {
|
||||||
new Thread(receiver, "UCI Receiver").start();
|
new Thread(receiver, "UCI Receiver").start();
|
||||||
uci();
|
uci();
|
||||||
@ -196,5 +206,10 @@ public class UCIHandle {
|
|||||||
*/
|
*/
|
||||||
public void quit() { out.println("quit"); }
|
public void quit() { out.println("quit"); }
|
||||||
|
|
||||||
public void setListener(UCIListener listener) { receiver.addListener(listener); }
|
/**
|
||||||
|
* Registers a UCI listener.
|
||||||
|
*
|
||||||
|
* @param listener the UCI listener to register
|
||||||
|
*/
|
||||||
|
public void registerListener(UCIListener listener) { receiver.registerListener(listener); }
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
package dev.kske.chess.uci;
|
package dev.kske.chess.uci;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import dev.kske.chess.board.Move;
|
import dev.kske.chess.board.Move;
|
||||||
|
|
||||||
@ -47,6 +43,12 @@ public class UCIInfo {
|
|||||||
"refutation",
|
"refutation",
|
||||||
"currline");
|
"currline");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of {@link UCIInfo} by parsing the argument list of a UCI
|
||||||
|
* info command generated from an engine.
|
||||||
|
*
|
||||||
|
* @param line the UCI info argument list to parse
|
||||||
|
*/
|
||||||
public UCIInfo(String line) {
|
public UCIInfo(String line) {
|
||||||
String[] tokens = line.split(" ");
|
String[] tokens = line.split(" ");
|
||||||
|
|
||||||
@ -106,7 +108,7 @@ public class UCIInfo {
|
|||||||
break;
|
break;
|
||||||
case "currline":
|
case "currline":
|
||||||
// A CPU number of 1 can be omitted
|
// A CPU number of 1 can be omitted
|
||||||
final Integer cpu = tokens[i].matches("\\d+") ? Integer.valueOf(tokens[i++]) : 1;
|
final Integer cpu = tokens[i].matches("\\d+") ? Integer.parseInt(tokens[i++]) : 1;
|
||||||
final ArrayList<Move> moves = new ArrayList<>();
|
final ArrayList<Move> moves = new ArrayList<>();
|
||||||
while (i < tokens.length && !params.contains(tokens[i]))
|
while (i < tokens.length && !params.contains(tokens[i]))
|
||||||
moves.add(Move.fromLAN(tokens[i++]));
|
moves.add(Move.fromLAN(tokens[i++]));
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
package dev.kske.chess.uci;
|
package dev.kske.chess.uci;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.*;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -23,11 +20,19 @@ public class UCIReceiver implements Runnable {
|
|||||||
|
|
||||||
private List<UCIListener> listeners;
|
private List<UCIListener> listeners;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of {@link UCIReceiver}.
|
||||||
|
*
|
||||||
|
* @param in the input stream to parse for commands generated by the engine
|
||||||
|
*/
|
||||||
public UCIReceiver(InputStream in) {
|
public UCIReceiver(InputStream in) {
|
||||||
this.in = new BufferedReader(new InputStreamReader(in));
|
this.in = new BufferedReader(new InputStreamReader(in));
|
||||||
listeners = new ArrayList<>();
|
listeners = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts listening for UCI commands passed through the input stream.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
String line;
|
String line;
|
||||||
@ -135,5 +140,10 @@ public class UCIReceiver implements Runnable {
|
|||||||
|
|
||||||
private void parseOption(String line) { listeners.forEach(l -> l.onOption(new UCIOption((line)))); }
|
private void parseOption(String line) { listeners.forEach(l -> l.onOption(new UCIOption((line)))); }
|
||||||
|
|
||||||
public void addListener(UCIListener listener) { listeners.add(listener); }
|
/**
|
||||||
|
* Registers a UCI listener
|
||||||
|
*
|
||||||
|
* @param listener the UCI listener to register
|
||||||
|
*/
|
||||||
|
public void registerListener(UCIListener listener) { listeners.add(listener); }
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,7 @@ package dev.kske.chess.ui;
|
|||||||
|
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
|
|
||||||
import javax.swing.JButton;
|
import javax.swing.*;
|
||||||
import javax.swing.JDialog;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JSpinner;
|
|
||||||
import javax.swing.SpinnerNumberModel;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Project: <strong>Chess</strong><br>
|
* Project: <strong>Chess</strong><br>
|
||||||
@ -17,6 +13,7 @@ import javax.swing.SpinnerNumberModel;
|
|||||||
* @author Kai S. K. Engelbart
|
* @author Kai S. K. Engelbart
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
|
@SuppressWarnings("javadoc")
|
||||||
public class AIConfigDialog extends JDialog {
|
public class AIConfigDialog extends JDialog {
|
||||||
|
|
||||||
private static final long serialVersionUID = -8047984368152479992L;
|
private static final long serialVersionUID = -8047984368152479992L;
|
||||||
@ -28,7 +25,7 @@ public class AIConfigDialog extends JDialog {
|
|||||||
public AIConfigDialog() {
|
public AIConfigDialog() {
|
||||||
setSize(new Dimension(337, 212));
|
setSize(new Dimension(337, 212));
|
||||||
setModal(true);
|
setModal(true);
|
||||||
setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
|
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||||
setTitle("AI Configuration");
|
setTitle("AI Configuration");
|
||||||
getContentPane().setLayout(null);
|
getContentPane().setLayout(null);
|
||||||
|
|
||||||
@ -50,8 +47,8 @@ public class AIConfigDialog extends JDialog {
|
|||||||
btnOk.setBounds(16, 137, 84, 28);
|
btnOk.setBounds(16, 137, 84, 28);
|
||||||
getContentPane().add(btnOk);
|
getContentPane().add(btnOk);
|
||||||
btnOk.addActionListener((evt) -> {
|
btnOk.addActionListener((evt) -> {
|
||||||
maxDepth = ((Integer) spMaxDepth.getValue()).intValue();
|
maxDepth = ((Integer) spMaxDepth.getValue());
|
||||||
alphaBetaThreshold = ((Integer) spAlphaBetaThreshold.getValue()).intValue();
|
alphaBetaThreshold = ((Integer) spAlphaBetaThreshold.getValue());
|
||||||
startGame = true;
|
startGame = true;
|
||||||
dispose();
|
dispose();
|
||||||
});
|
});
|
||||||
|
@ -28,6 +28,12 @@ public class BoardComponent extends JComponent {
|
|||||||
|
|
||||||
private Board board;
|
private Board board;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of {@link BoardComponent}.
|
||||||
|
*
|
||||||
|
* @param boardPane the board pane inside which this board component is
|
||||||
|
* contained
|
||||||
|
*/
|
||||||
public BoardComponent(BoardPane boardPane) {
|
public BoardComponent(BoardPane boardPane) {
|
||||||
this.boardPane = boardPane;
|
this.boardPane = boardPane;
|
||||||
setSize(boardPane.getPreferredSize());
|
setSize(boardPane.getPreferredSize());
|
||||||
@ -37,7 +43,7 @@ public class BoardComponent extends JComponent {
|
|||||||
protected void paintComponent(Graphics g) {
|
protected void paintComponent(Graphics g) {
|
||||||
super.paintComponent(g);
|
super.paintComponent(g);
|
||||||
|
|
||||||
final int tileSize = getTileSize();
|
final int tileSize = boardPane.getTileSize();
|
||||||
|
|
||||||
// Draw the board
|
// Draw the board
|
||||||
g.setColor(Color.white);
|
g.setColor(Color.white);
|
||||||
@ -54,10 +60,16 @@ public class BoardComponent extends JComponent {
|
|||||||
g.drawImage(TextureUtil.getPieceTexture(board.getBoardArr()[i][j]), i * tileSize, j * tileSize, this);
|
g.drawImage(TextureUtil.getPieceTexture(board.getBoardArr()[i][j]), i * tileSize, j * tileSize, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getTileSize() { return boardPane.getTileSize(); }
|
/**
|
||||||
|
* @return the board rendered by this board component
|
||||||
|
*/
|
||||||
public Board getBoard() { return board; }
|
public Board getBoard() { return board; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the board rendered by this board component and repaints the component
|
||||||
|
*
|
||||||
|
* @param board the board rendered by this board component
|
||||||
|
*/
|
||||||
public void setBoard(Board board) {
|
public void setBoard(Board board) {
|
||||||
this.board = board;
|
this.board = board;
|
||||||
repaint();
|
repaint();
|
||||||
|
@ -5,6 +5,9 @@ import java.awt.Dimension;
|
|||||||
import javax.swing.JLayeredPane;
|
import javax.swing.JLayeredPane;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Combines a {@link BoardComponent} and an {@link OverlayComponent} into a
|
||||||
|
* layered pane.
|
||||||
|
* <br>
|
||||||
* Project: <strong>Chess</strong><br>
|
* Project: <strong>Chess</strong><br>
|
||||||
* File: <strong>BoardPane.java</strong><br>
|
* File: <strong>BoardPane.java</strong><br>
|
||||||
* Created: <strong>08.07.2019</strong><br>
|
* Created: <strong>08.07.2019</strong><br>
|
||||||
@ -21,6 +24,9 @@ public class BoardPane extends JLayeredPane {
|
|||||||
|
|
||||||
private int tileSize;
|
private int tileSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of {@link BoardPane}.
|
||||||
|
*/
|
||||||
public BoardPane() {
|
public BoardPane() {
|
||||||
boardComponent = new BoardComponent(this);
|
boardComponent = new BoardComponent(this);
|
||||||
overlayComponent = new OverlayComponent(this);
|
overlayComponent = new OverlayComponent(this);
|
||||||
@ -37,9 +43,18 @@ public class BoardPane extends JLayeredPane {
|
|||||||
@Override
|
@Override
|
||||||
public Dimension getPreferredSize() { return new Dimension(480, 480); }
|
public Dimension getPreferredSize() { return new Dimension(480, 480); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the board component contained inside this board pane
|
||||||
|
*/
|
||||||
public BoardComponent getBoardComponent() { return boardComponent; }
|
public BoardComponent getBoardComponent() { return boardComponent; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return overlay component contained inside this board pane
|
||||||
|
*/
|
||||||
public OverlayComponent getOverlayComponent() { return overlayComponent; }
|
public OverlayComponent getOverlayComponent() { return overlayComponent; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the size of an individual board tile in pixels
|
||||||
|
*/
|
||||||
public int getTileSize() { return tileSize; }
|
public int getTileSize() { return tileSize; }
|
||||||
}
|
}
|
||||||
|
@ -3,20 +3,12 @@ package dev.kske.chess.ui;
|
|||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.prefs.Preferences;
|
import java.util.prefs.Preferences;
|
||||||
|
|
||||||
import javax.swing.DefaultComboBoxModel;
|
import javax.swing.*;
|
||||||
import javax.swing.JComboBox;
|
|
||||||
import javax.swing.JFileChooser;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import javax.swing.filechooser.FileNameExtensionFilter;
|
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||||
|
|
||||||
import dev.kske.chess.io.EngineUtil;
|
import dev.kske.chess.io.EngineUtil;
|
||||||
@ -38,6 +30,13 @@ public class DialogUtil {
|
|||||||
*/
|
*/
|
||||||
private static Preferences preferences = Preferences.userNodeForPackage(DialogUtil.class);
|
private static Preferences preferences = Preferences.userNodeForPackage(DialogUtil.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a parameterized file opening dialog.
|
||||||
|
*
|
||||||
|
* @param parent the parent component of the dialog
|
||||||
|
* @param action the action executed with the selected files a its argument
|
||||||
|
* @param filters the file extension filters passed to the dialog
|
||||||
|
*/
|
||||||
public static void showFileSelectionDialog(Component parent, Consumer<List<File>> action, Collection<FileNameExtensionFilter> filters) {
|
public static void showFileSelectionDialog(Component parent, Consumer<List<File>> action, Collection<FileNameExtensionFilter> filters) {
|
||||||
JFileChooser fileChooser = createFileChooser(filters);
|
JFileChooser fileChooser = createFileChooser(filters);
|
||||||
if (fileChooser.showOpenDialog(parent) == JFileChooser.APPROVE_OPTION) {
|
if (fileChooser.showOpenDialog(parent) == JFileChooser.APPROVE_OPTION) {
|
||||||
@ -46,6 +45,13 @@ public class DialogUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a parameterized file saving dialog.
|
||||||
|
*
|
||||||
|
* @param parent the parent component of the dialog
|
||||||
|
* @param action the action executed with the selected file a its argument
|
||||||
|
* @param filters the file extension filters passed to the dialog
|
||||||
|
*/
|
||||||
public static void showFileSaveDialog(Component parent, Consumer<File> action, Collection<FileNameExtensionFilter> filters) {
|
public static void showFileSaveDialog(Component parent, Consumer<File> action, Collection<FileNameExtensionFilter> filters) {
|
||||||
JFileChooser fileChooser = createFileChooser(filters);
|
JFileChooser fileChooser = createFileChooser(filters);
|
||||||
if (fileChooser.showSaveDialog(parent) == JFileChooser.APPROVE_OPTION) {
|
if (fileChooser.showSaveDialog(parent) == JFileChooser.APPROVE_OPTION) {
|
||||||
@ -63,6 +69,16 @@ public class DialogUtil {
|
|||||||
return fileChooser;
|
return fileChooser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a dialog in which the user can select the player types for a
|
||||||
|
* game.<br>
|
||||||
|
* <br>
|
||||||
|
* The dialog will always display {@code Natural Player} and {@code AIPlayer},
|
||||||
|
* as well as all engine names stored by {@link EngineUtil}.
|
||||||
|
*
|
||||||
|
* @param parent the parent component of the dialog
|
||||||
|
* @param action the action executed with the two selected names as arguments
|
||||||
|
*/
|
||||||
public static void showGameConfigurationDialog(Component parent, BiConsumer<String, String> action) {
|
public static void showGameConfigurationDialog(Component parent, BiConsumer<String, String> action) {
|
||||||
JPanel dialogPanel = new JPanel();
|
JPanel dialogPanel = new JPanel();
|
||||||
|
|
||||||
|
@ -10,6 +10,9 @@ import java.io.IOException;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Enables drag and drop support of {@code FEN} and {@code PGN} files for the
|
||||||
|
* {@link MainWindow}.<br>
|
||||||
|
* <br>
|
||||||
* Project: <strong>Chess</strong><br>
|
* Project: <strong>Chess</strong><br>
|
||||||
* File: <strong>GameDropTarget.java</strong><br>
|
* File: <strong>GameDropTarget.java</strong><br>
|
||||||
* Created: <strong>13 Aug 2019</strong><br>
|
* Created: <strong>13 Aug 2019</strong><br>
|
||||||
@ -21,6 +24,12 @@ public class GameDropTarget extends DropTargetAdapter {
|
|||||||
|
|
||||||
private MainWindow mainWindow;
|
private MainWindow mainWindow;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of {@link GameDropTarget}.
|
||||||
|
*
|
||||||
|
* @param mainWindow the {@link MainWindow} onto which {@code FEN} and
|
||||||
|
* {@code PGN} files can be dropped
|
||||||
|
*/
|
||||||
public GameDropTarget(MainWindow mainWindow) { this.mainWindow = mainWindow; }
|
public GameDropTarget(MainWindow mainWindow) { this.mainWindow = mainWindow; }
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -7,28 +7,19 @@ import java.util.Arrays;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.swing.DefaultListModel;
|
import javax.swing.*;
|
||||||
import javax.swing.JButton;
|
|
||||||
import javax.swing.JComponent;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JList;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import javax.swing.JScrollPane;
|
|
||||||
import javax.swing.ListSelectionModel;
|
|
||||||
|
|
||||||
import dev.kske.chess.board.BoardState;
|
import dev.kske.chess.board.BoardState;
|
||||||
import dev.kske.chess.board.MoveNode;
|
import dev.kske.chess.board.MoveNode;
|
||||||
import dev.kske.chess.board.Piece.Color;
|
import dev.kske.chess.board.Piece.Color;
|
||||||
import dev.kske.chess.event.Event;
|
import dev.kske.chess.event.*;
|
||||||
import dev.kske.chess.event.EventBus;
|
|
||||||
import dev.kske.chess.event.GameStartEvent;
|
|
||||||
import dev.kske.chess.event.MoveEvent;
|
|
||||||
import dev.kske.chess.event.Subscribable;
|
|
||||||
import dev.kske.chess.game.Game;
|
import dev.kske.chess.game.Game;
|
||||||
import dev.kske.chess.game.NaturalPlayer;
|
import dev.kske.chess.game.NaturalPlayer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* The part of this application's {@link MainWindow} that displays {@link Game}s
|
||||||
|
* and other components allowing to manipulate them.<br>
|
||||||
|
* <br>
|
||||||
* Project: <strong>Chess</strong><br>
|
* Project: <strong>Chess</strong><br>
|
||||||
* File: <strong>GamePane.java</strong><br>
|
* File: <strong>GamePane.java</strong><br>
|
||||||
* Created: <strong>23.08.2019</strong><br>
|
* Created: <strong>23.08.2019</strong><br>
|
||||||
@ -47,6 +38,9 @@ public class GamePane extends JComponent {
|
|||||||
private JPanel moveSelectionPanel;
|
private JPanel moveSelectionPanel;
|
||||||
private JButton btnFirst, btnPrevious, btnNext, btnLast;
|
private JButton btnFirst, btnPrevious, btnNext, btnLast;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of {@link GamePane}.
|
||||||
|
*/
|
||||||
public GamePane() {
|
public GamePane() {
|
||||||
activeColor = Color.WHITE;
|
activeColor = Color.WHITE;
|
||||||
|
|
||||||
@ -107,13 +101,11 @@ public class GamePane extends JComponent {
|
|||||||
|
|
||||||
btnNext = new JButton("Next");
|
btnNext = new JButton("Next");
|
||||||
btnNext.addActionListener((evt) -> {
|
btnNext.addActionListener((evt) -> {
|
||||||
if(game != null) {
|
if (game != null) {
|
||||||
int numVariations = game.getBoard().getLog().getLast().getVariations().size();
|
int numVariations = game.getBoard().getLog().getLast().getVariations().size();
|
||||||
int index;
|
int index;
|
||||||
if(numVariations == 1)
|
if (numVariations == 1) index = 1;
|
||||||
index = 1;
|
else index = Integer.parseInt(JOptionPane.showInputDialog("Enter the variation index."));
|
||||||
else
|
|
||||||
index = Integer.parseInt(JOptionPane.showInputDialog("Enter the variation index."));
|
|
||||||
game.getBoard().selectNextNode(index);
|
game.getBoard().selectNextNode(index);
|
||||||
getBoardPane().getOverlayComponent().clearArrow();
|
getBoardPane().getOverlayComponent().clearArrow();
|
||||||
repaint();
|
repaint();
|
||||||
@ -152,7 +144,7 @@ public class GamePane extends JComponent {
|
|||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < 8; i++) {
|
||||||
numberPanel.add(new JLabel(String.valueOf(8 - i)));
|
numberPanel.add(new JLabel(String.valueOf(8 - i)));
|
||||||
JLabel letterLabel = new JLabel(String.valueOf((char) (65 + i)));
|
JLabel letterLabel = new JLabel(String.valueOf((char) (65 + i)));
|
||||||
letterLabel.setHorizontalAlignment(JLabel.CENTER);
|
letterLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
||||||
letterPanel.add(letterLabel);
|
letterPanel.add(letterLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +164,7 @@ public class GamePane extends JComponent {
|
|||||||
|
|
||||||
// Listen to moves and game (re-)starts and update the move list or disable the
|
// Listen to moves and game (re-)starts and update the move list or disable the
|
||||||
// color switching buttons if necessary
|
// color switching buttons if necessary
|
||||||
EventBus.getInstance().register(new Subscribable() {
|
EventBus.getInstance().register(new Subscriber() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(Event<?> event) {
|
public void handle(Event<?> event) {
|
||||||
|
@ -1,22 +1,15 @@
|
|||||||
package dev.kske.chess.ui;
|
package dev.kske.chess.ui;
|
||||||
|
|
||||||
import java.awt.BasicStroke;
|
import java.awt.*;
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.awt.FlowLayout;
|
|
||||||
import java.awt.Graphics;
|
|
||||||
import java.awt.Graphics2D;
|
|
||||||
import java.awt.event.MouseAdapter;
|
import java.awt.event.MouseAdapter;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
|
|
||||||
import javax.swing.BorderFactory;
|
import javax.swing.*;
|
||||||
import javax.swing.JButton;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import javax.swing.JTabbedPane;
|
|
||||||
import javax.swing.plaf.basic.BasicButtonUI;
|
import javax.swing.plaf.basic.BasicButtonUI;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Renders the title and the closing button of a {@link JTabbedPane}.<br>
|
||||||
|
* <br>
|
||||||
* Project: <strong>Chess</strong><br>
|
* Project: <strong>Chess</strong><br>
|
||||||
* File: <strong>GameTabComponent.java</strong><br>
|
* File: <strong>GameTabComponent.java</strong><br>
|
||||||
* Created: <strong>11 Dec 2019</strong><br>
|
* Created: <strong>11 Dec 2019</strong><br>
|
||||||
@ -29,6 +22,12 @@ public class GameTabComponent extends JPanel {
|
|||||||
|
|
||||||
private static final long serialVersionUID = 9022979950018125935L;
|
private static final long serialVersionUID = 9022979950018125935L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of {@link GameTabComponent}.
|
||||||
|
*
|
||||||
|
* @param tabbedPane the tabbed pane which contains this
|
||||||
|
* {@link GameTabComponent}
|
||||||
|
*/
|
||||||
public GameTabComponent(JTabbedPane tabbedPane) {
|
public GameTabComponent(JTabbedPane tabbedPane) {
|
||||||
super(new FlowLayout(FlowLayout.LEFT, 0, 0));
|
super(new FlowLayout(FlowLayout.LEFT, 0, 0));
|
||||||
if (tabbedPane == null) throw new NullPointerException("TabbedPane is null");
|
if (tabbedPane == null) throw new NullPointerException("TabbedPane is null");
|
||||||
|
@ -10,10 +10,7 @@ import java.nio.charset.StandardCharsets;
|
|||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.swing.JComboBox;
|
import javax.swing.*;
|
||||||
import javax.swing.JFrame;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.JTabbedPane;
|
|
||||||
|
|
||||||
import dev.kske.chess.board.Board;
|
import dev.kske.chess.board.Board;
|
||||||
import dev.kske.chess.board.FENString;
|
import dev.kske.chess.board.FENString;
|
||||||
@ -38,6 +35,8 @@ public class MainWindow extends JFrame {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Launch the application.
|
* Launch the application.
|
||||||
|
*
|
||||||
|
* @param args command line arguments are ignored
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
EventQueue.invokeLater(() -> {
|
EventQueue.invokeLater(() -> {
|
||||||
@ -81,7 +80,7 @@ public class MainWindow extends JFrame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The currently selected {@link GamePane} component
|
* @return the currently selected {@link GamePane} component
|
||||||
*/
|
*/
|
||||||
public GamePane getSelectedGamePane() { return (GamePane) tabbedPane.getSelectedComponent(); }
|
public GamePane getSelectedGamePane() { return (GamePane) tabbedPane.getSelectedComponent(); }
|
||||||
|
|
||||||
@ -89,7 +88,7 @@ public class MainWindow extends JFrame {
|
|||||||
* Creates a new {@link GamePane}, adds it to the tabbed pane and opens it.
|
* Creates a new {@link GamePane}, adds it to the tabbed pane and opens it.
|
||||||
* The new tab has the title {@code Game n} where {@code n} is its number.
|
* The new tab has the title {@code Game n} where {@code n} is its number.
|
||||||
*
|
*
|
||||||
* @return The new {@link GamePane}
|
* @return the new {@link GamePane}
|
||||||
*/
|
*/
|
||||||
public GamePane addGamePane() { return addGamePane("Game " + (tabbedPane.getTabCount() + 1)); }
|
public GamePane addGamePane() { return addGamePane("Game " + (tabbedPane.getTabCount() + 1)); }
|
||||||
|
|
||||||
@ -97,7 +96,7 @@ public class MainWindow extends JFrame {
|
|||||||
* Creates a new {@link GamePane}, adds it to the tabbed pane and opens it.
|
* Creates a new {@link GamePane}, adds it to the tabbed pane and opens it.
|
||||||
*
|
*
|
||||||
* @param title The title of the {@link GamePane}
|
* @param title The title of the {@link GamePane}
|
||||||
* @return The new {@link GamePane}
|
* @return the new {@link GamePane}
|
||||||
*/
|
*/
|
||||||
public GamePane addGamePane(String title) {
|
public GamePane addGamePane(String title) {
|
||||||
GamePane gamePane = new GamePane();
|
GamePane gamePane = new GamePane();
|
||||||
@ -107,6 +106,15 @@ public class MainWindow extends JFrame {
|
|||||||
return gamePane;
|
return gamePane;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link GamePane}, adds it to the tabbed pane and immediately
|
||||||
|
* displays a game configuration dialog for a new game on an existing
|
||||||
|
* {@link Board}.
|
||||||
|
*
|
||||||
|
* @param title the title of the {@link GamePane}
|
||||||
|
* @param board the {@link Board} with which the new {@link Game} is started
|
||||||
|
* @return the new {@link GamePane}
|
||||||
|
*/
|
||||||
public GamePane addGamePane(String title, Board board) {
|
public GamePane addGamePane(String title, Board board) {
|
||||||
GamePane gamePane = addGamePane(title);
|
GamePane gamePane = addGamePane(title);
|
||||||
DialogUtil.showGameConfigurationDialog(this,
|
DialogUtil.showGameConfigurationDialog(this,
|
||||||
@ -168,6 +176,12 @@ public class MainWindow extends JFrame {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the current {@link Game} as a file in {@code PGN} or {@code FEN}
|
||||||
|
* format.
|
||||||
|
*
|
||||||
|
* @param file the file in which to save the current {@link Game}
|
||||||
|
*/
|
||||||
public void saveFile(File file) {
|
public void saveFile(File file) {
|
||||||
final int dotIndex = file.getName().lastIndexOf('.');
|
final int dotIndex = file.getName().lastIndexOf('.');
|
||||||
final String extension = file.getName().substring(dotIndex).toLowerCase();
|
final String extension = file.getName().substring(dotIndex).toLowerCase();
|
||||||
|
@ -4,10 +4,7 @@ import java.awt.Toolkit;
|
|||||||
import java.awt.datatransfer.StringSelection;
|
import java.awt.datatransfer.StringSelection;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import javax.swing.JMenu;
|
import javax.swing.*;
|
||||||
import javax.swing.JMenuBar;
|
|
||||||
import javax.swing.JMenuItem;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.filechooser.FileNameExtensionFilter;
|
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||||
|
|
||||||
import dev.kske.chess.board.FENString;
|
import dev.kske.chess.board.FENString;
|
||||||
@ -29,6 +26,11 @@ public class MenuBar extends JMenuBar {
|
|||||||
|
|
||||||
private final MainWindow mainWindow;
|
private final MainWindow mainWindow;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of {@link MenuBar}.
|
||||||
|
*
|
||||||
|
* @param mainWindow the main window inside which this menu bar is contained
|
||||||
|
*/
|
||||||
public MenuBar(MainWindow mainWindow) {
|
public MenuBar(MainWindow mainWindow) {
|
||||||
this.mainWindow = mainWindow;
|
this.mainWindow = mainWindow;
|
||||||
|
|
||||||
|
@ -1,12 +1,6 @@
|
|||||||
package dev.kske.chess.ui;
|
package dev.kske.chess.ui;
|
||||||
|
|
||||||
import java.awt.BasicStroke;
|
import java.awt.*;
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Graphics;
|
|
||||||
import java.awt.Graphics2D;
|
|
||||||
import java.awt.Point;
|
|
||||||
import java.awt.Polygon;
|
|
||||||
import java.awt.Shape;
|
|
||||||
import java.awt.geom.AffineTransform;
|
import java.awt.geom.AffineTransform;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -33,6 +27,12 @@ public class OverlayComponent extends JComponent {
|
|||||||
private List<Position> dots;
|
private List<Position> dots;
|
||||||
private Move arrow;
|
private Move arrow;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of {@link OverlayComponent}.
|
||||||
|
*
|
||||||
|
* @param boardPane the board pane inside which this overlay component is
|
||||||
|
* contained
|
||||||
|
*/
|
||||||
public OverlayComponent(BoardPane boardPane) {
|
public OverlayComponent(BoardPane boardPane) {
|
||||||
this.boardPane = boardPane;
|
this.boardPane = boardPane;
|
||||||
dots = new ArrayList<>();
|
dots = new ArrayList<>();
|
||||||
@ -43,7 +43,7 @@ public class OverlayComponent extends JComponent {
|
|||||||
protected void paintComponent(Graphics g) {
|
protected void paintComponent(Graphics g) {
|
||||||
super.paintComponent(g);
|
super.paintComponent(g);
|
||||||
|
|
||||||
final int tileSize = getTileSize();
|
final int tileSize = boardPane.getTileSize();
|
||||||
|
|
||||||
// Draw an arrow representing the last move and mark its position and
|
// Draw an arrow representing the last move and mark its position and
|
||||||
// destination
|
// destination
|
||||||
@ -107,26 +107,46 @@ public class OverlayComponent extends JComponent {
|
|||||||
return new Point((int) ((p1.x + p2.x) / 2.0), (int) ((p1.y + p2.y) / 2.0));
|
return new Point((int) ((p1.x + p2.x) / 2.0), (int) ((p1.y + p2.y) / 2.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays green dots at a list of positions.
|
||||||
|
*
|
||||||
|
* @param dots the positions at which the dots should be displayed
|
||||||
|
*/
|
||||||
public void displayDots(List<Position> dots) {
|
public void displayDots(List<Position> dots) {
|
||||||
this.dots.clear();
|
this.dots.clear();
|
||||||
this.dots.addAll(dots);
|
this.dots.addAll(dots);
|
||||||
repaint();
|
repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all dots displayed at some positions.
|
||||||
|
*/
|
||||||
public void clearDots() {
|
public void clearDots() {
|
||||||
dots.clear();
|
dots.clear();
|
||||||
repaint();
|
repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays an arrow from the position to the destination of a move.
|
||||||
|
*
|
||||||
|
* @param arrow the move indicating the arrows position and destination
|
||||||
|
*/
|
||||||
public void displayArrow(Move arrow) {
|
public void displayArrow(Move arrow) {
|
||||||
this.arrow = arrow;
|
this.arrow = arrow;
|
||||||
repaint();
|
repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the arrow displayed to indicate a move.
|
||||||
|
*/
|
||||||
public void clearArrow() {
|
public void clearArrow() {
|
||||||
arrow = null;
|
arrow = null;
|
||||||
repaint();
|
repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the size of one board tile in pixels.
|
||||||
|
* @see dev.kske.chess.ui.BoardPane#getTileSize()
|
||||||
|
*/
|
||||||
public int getTileSize() { return boardPane.getTileSize(); }
|
public int getTileSize() { return boardPane.getTileSize(); }
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package dev.kske.chess.board;
|
package dev.kske.chess.board;
|
||||||
|
|
||||||
import static org.junit.Assert.assertNotEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertNotSame;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -16,7 +15,7 @@ import dev.kske.chess.board.Piece.Color;
|
|||||||
*/
|
*/
|
||||||
class BoardTest {
|
class BoardTest {
|
||||||
|
|
||||||
Board board;
|
private Board board;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws java.lang.Exception
|
* @throws java.lang.Exception
|
||||||
@ -27,7 +26,7 @@ class BoardTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test method for {@link dev.kske.chess.board.Board#clone()}.
|
* Test method for {@link Board#Board(Board, boolean)}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testClone() {
|
void testClone() {
|
||||||
|
@ -21,9 +21,14 @@ import dev.kske.chess.exception.ChessException;
|
|||||||
*/
|
*/
|
||||||
class FENStringTest {
|
class FENStringTest {
|
||||||
|
|
||||||
List<String> fenStrings = new ArrayList<>();
|
private List<String> fenStrings = new ArrayList<>();
|
||||||
List<Board> boards = new ArrayList<>();
|
private List<Board> boards = new ArrayList<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all pieces from a board
|
||||||
|
*
|
||||||
|
* @param board the board to clean
|
||||||
|
*/
|
||||||
void cleanBoard(Board board) {
|
void cleanBoard(Board board) {
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
for (int j = 0; j < 8; j++)
|
for (int j = 0; j < 8; j++)
|
||||||
@ -51,7 +56,7 @@ class FENStringTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test method for {@link dev.kske.chess.board.FENString#toString()}.
|
* Test method for {@link FENString#toString()}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testToString() {
|
void testToString() {
|
||||||
@ -60,7 +65,7 @@ class FENStringTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test method for {@link dev.kske.chess.board.FENString#getBoard()}.
|
* Test method for {@link FENString#getBoard()}.
|
||||||
*
|
*
|
||||||
* @throws ChessException
|
* @throws ChessException
|
||||||
*/
|
*/
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
package dev.kske.chess.board;
|
package dev.kske.chess.board;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
@ -18,10 +14,10 @@ import dev.kske.chess.board.Piece.Color;
|
|||||||
*/
|
*/
|
||||||
class LogTest {
|
class LogTest {
|
||||||
|
|
||||||
Log log = new Log();
|
private Log log = new Log();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test method for {@link dev.kske.chess.board.Log#Log()}.
|
* Test method for {@link Log#Log()}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testLog() {
|
void testLog() {
|
||||||
@ -35,7 +31,7 @@ class LogTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test method for {@link dev.kske.chess.board.Log#clone()}.
|
* Test method for {@link Log#Log(Log, boolean)}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testClone() {
|
void testClone() {
|
||||||
@ -52,7 +48,7 @@ class LogTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test method for {@link dev.kske.chess.board.Log#add(dev.kske.chess.board.Move, dev.kske.chess.board.Piece, boolean)}.
|
* Test method for {@link Log#add(Move, Piece, Piece)}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testAdd() {
|
void testAdd() {
|
||||||
@ -60,7 +56,7 @@ class LogTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test method for {@link dev.kske.chess.board.Log#removeLast()}.
|
* Test method for {@link Log#removeLast()}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testRemoveLast() {
|
void testRemoveLast() {
|
||||||
@ -68,7 +64,7 @@ class LogTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test method for {@link dev.kske.chess.board.Log#isEmpty()}.
|
* Test method for {@link Log#isEmpty()}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testIsEmpty() {
|
void testIsEmpty() {
|
||||||
@ -76,7 +72,7 @@ class LogTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test method for {@link dev.kske.chess.board.Log#reset()}.
|
* Test method for {@link Log#reset()}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testReset() {
|
void testReset() {
|
||||||
@ -84,7 +80,7 @@ class LogTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test method for {@link dev.kske.chess.board.Log#getRoot()}.
|
* Test method for {@link Log#getRoot()}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testGetRoot() {
|
void testGetRoot() {
|
||||||
@ -92,7 +88,7 @@ class LogTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test method for {@link dev.kske.chess.board.Log#getLast()}.
|
* Test method for {@link Log#getLast()}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testGetLast() {
|
void testGetLast() {
|
||||||
@ -100,7 +96,7 @@ class LogTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test method for {@link dev.kske.chess.board.Log#getEnPassant()}.
|
* Test method for {@link Log#getEnPassant()}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testGetEnPassant() {
|
void testGetEnPassant() {
|
||||||
@ -108,7 +104,7 @@ class LogTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test method for {@link dev.kske.chess.board.Log#setEnPassant(dev.kske.chess.board.Position)}.
|
* Test method for {@link Log#setEnPassant(dev.kske.chess.board.Position)}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testSetEnPassant() {
|
void testSetEnPassant() {
|
||||||
@ -116,7 +112,7 @@ class LogTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test method for {@link dev.kske.chess.board.Log#getActiveColor()}.
|
* Test method for {@link Log#getActiveColor()}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testGetActiveColor() {
|
void testGetActiveColor() {
|
||||||
@ -124,7 +120,7 @@ class LogTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test method for {@link dev.kske.chess.board.Log#setActiveColor(dev.kske.chess.board.Piece.Color)}.
|
* Test method for {@link Log#setActiveColor(dev.kske.chess.board.Piece.Color)}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testSetActiveColor() {
|
void testSetActiveColor() {
|
||||||
@ -132,7 +128,7 @@ class LogTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test method for {@link dev.kske.chess.board.Log#getFullmoveNumber()}.
|
* Test method for {@link Log#getFullmoveNumber()}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testGetFullmoveCounter() {
|
void testGetFullmoveCounter() {
|
||||||
@ -140,7 +136,7 @@ class LogTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test method for {@link dev.kske.chess.board.Log#setFullmoveNumber(int)}.
|
* Test method for {@link Log#setFullmoveNumber(int)}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testSetFullmoveCounter() {
|
void testSetFullmoveCounter() {
|
||||||
@ -148,7 +144,7 @@ class LogTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test method for {@link dev.kske.chess.board.Log#getHalfmoveClock()}.
|
* Test method for {@link Log#getHalfmoveClock()}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testGetHalfmoveClock() {
|
void testGetHalfmoveClock() {
|
||||||
@ -156,7 +152,7 @@ class LogTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test method for {@link dev.kske.chess.board.Log#setHalfmoveClock(int)}.
|
* Test method for {@link Log#setHalfmoveClock(int)}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testSetHalfmoveClock() {
|
void testSetHalfmoveClock() {
|
||||||
|
@ -12,14 +12,14 @@ import org.junit.jupiter.api.Test;
|
|||||||
*/
|
*/
|
||||||
class PositionTest {
|
class PositionTest {
|
||||||
|
|
||||||
final int n = 4;
|
private final int n = 4;
|
||||||
Position[] positions = new Position[] { new Position(0, 0), new Position(7, 7), new Position(0, 7), new Position(7, 0) };
|
private Position[] positions = new Position[] { new Position(0, 0), new Position(7, 7), new Position(0, 7), new Position(7, 0) };
|
||||||
String[] sans = new String[] { "a8", "h1", "a1", "h8" };
|
private String[] sans = new String[] { "a8", "h1", "a1", "h8" };
|
||||||
String[] strings = new String[] { "[0, 0]", "[7, 7]", "[0, 7]", "[7, 0]" };
|
private String[] strings = new String[] { "[0, 0]", "[7, 7]", "[0, 7]", "[7, 0]" };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test method for
|
* Test method for
|
||||||
* {@link dev.kske.chess.board.Position#fromLAN(java.lang.String)}.
|
* {@link Position#fromLAN(java.lang.String)}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testFromSAN() {
|
void testFromSAN() {
|
||||||
@ -28,7 +28,7 @@ class PositionTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test method for {@link dev.kske.chess.board.Position#toLAN()}.
|
* Test method for {@link Position#toLAN()}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testToSAN() {
|
void testToSAN() {
|
||||||
@ -37,7 +37,7 @@ class PositionTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test method for {@link dev.kske.chess.board.Position#toString()}.
|
* Test method for {@link Position#toString()}.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testToString() {
|
void testToString() {
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package dev.kske.chess.pgn;
|
package dev.kske.chess.pgn;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
|
|
||||||
@ -20,17 +18,13 @@ class PGNDatabaseTest {
|
|||||||
/**
|
/**
|
||||||
* Test method for {@link dev.kske.chess.pgn.PGNDatabase#load(java.io.File)}.
|
* Test method for {@link dev.kske.chess.pgn.PGNDatabase#load(java.io.File)}.
|
||||||
*
|
*
|
||||||
* @throws ChessException
|
* @throws ChessException if an error occurs while parsing the file
|
||||||
* @throws FileNotFoundException
|
* @throws FileNotFoundException if the test file {@code test.pgn} is not
|
||||||
|
* present
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
void testLoad() {
|
void testLoad() throws FileNotFoundException, ChessException {
|
||||||
PGNDatabase db = new PGNDatabase();
|
PGNDatabase db = new PGNDatabase();
|
||||||
try {
|
|
||||||
db.load(new File(getClass().getClassLoader().getResource("test.pgn").getFile()));
|
db.load(new File(getClass().getClassLoader().getResource("test.pgn").getFile()));
|
||||||
} catch (FileNotFoundException | ChessException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
fail(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user