Added pawn promotion #11
@ -62,7 +62,7 @@ public class Board {
|
||||
if (piece == null || !piece.isValidMove(move)) return false;
|
||||
else {
|
||||
// Set type after validation
|
||||
if (move.type == Move.Type.UNKNOWN) move.type = Move.Type.NORMAL;
|
||||
if (move.getType() == Move.Type.UNKNOWN) move.type = Move.Type.NORMAL;
|
||||
|
||||
// Move piece
|
||||
move(move);
|
||||
@ -86,7 +86,7 @@ public class Board {
|
||||
Piece piece = getPos(move);
|
||||
Piece capturePiece = getDest(move);
|
||||
|
||||
switch (move.type) {
|
||||
switch (move.getType()) {
|
||||
case PAWN_PROMOTION:
|
||||
setPos(move, null);
|
||||
// TODO: Select promotion
|
||||
@ -95,7 +95,7 @@ public class Board {
|
||||
case EN_PASSANT:
|
||||
setDest(move, piece);
|
||||
setPos(move, null);
|
||||
boardArr[move.dest.x][move.dest.y - move.ySign] = null;
|
||||
boardArr[move.getDest().x][move.getDest().y - move.getySign()] = null;
|
||||
break;
|
||||
case CASTLING:
|
||||
// Move the king
|
||||
@ -103,8 +103,8 @@ public class Board {
|
||||
setPos(move, null);
|
||||
|
||||
// Move the rook
|
||||
Move rookMove = move.dest.x == 6 ? new Move(7, move.pos.y, 5, move.pos.y) // Kingside
|
||||
: new Move(0, move.pos.y, 3, move.pos.y); // Queenside
|
||||
Move rookMove = move.getDest().x == 6 ? new Move(7, move.getPos().y, 5, move.getPos().y) // Kingside
|
||||
: new Move(0, move.getPos().y, 3, move.getPos().y); // Queenside
|
||||
setDest(rookMove, getPos(rookMove));
|
||||
setPos(rookMove, null);
|
||||
break;
|
||||
@ -119,7 +119,7 @@ public class Board {
|
||||
}
|
||||
|
||||
// Update the king's position if the moved piece is the king
|
||||
if (piece.getType() == Type.KING) kingPos.put(piece.getColor(), move.dest);
|
||||
if (piece.getType() == Type.KING) kingPos.put(piece.getColor(), move.getDest());
|
||||
|
||||
// Update log
|
||||
log.add(move, piece, capturePiece);
|
||||
@ -200,7 +200,7 @@ public class Board {
|
||||
Move move = moveNode.move;
|
||||
Piece capturedPiece = moveNode.capturedPiece;
|
||||
|
||||
switch (move.type) {
|
||||
switch (move.getType()) {
|
||||
case PAWN_PROMOTION:
|
||||
setPos(move, new Pawn(getDest(move).getColor(), this));
|
||||
setDest(move, capturedPiece);
|
||||
@ -208,7 +208,7 @@ public class Board {
|
||||
case EN_PASSANT:
|
||||
setPos(move, getDest(move));
|
||||
setDest(move, null);
|
||||
boardArr[move.dest.x][move.dest.y - move.ySign] = new Pawn(getPos(move).getColor().opposite(), this);
|
||||
boardArr[move.getDest().x][move.getDest().y - move.getySign()] = new Pawn(getPos(move).getColor().opposite(), this);
|
||||
break;
|
||||
case CASTLING:
|
||||
// Move the king
|
||||
@ -216,8 +216,8 @@ public class Board {
|
||||
setDest(move, null);
|
||||
|
||||
// Move the rook
|
||||
Move rookMove = move.dest.x == 6 ? new Move(5, move.pos.y, 7, move.pos.y) // Kingside
|
||||
: new Move(3, move.pos.y, 0, move.pos.y); // Queenside
|
||||
Move rookMove = move.getDest().x == 6 ? new Move(5, move.getPos().y, 7, move.getPos().y) // Kingside
|
||||
: new Move(3, move.getPos().y, 0, move.getPos().y); // Queenside
|
||||
setDest(rookMove, getPos(rookMove));
|
||||
setPos(rookMove, null);
|
||||
break;
|
||||
@ -232,7 +232,7 @@ public class Board {
|
||||
}
|
||||
|
||||
// Update the king's position if the moved piece is the king
|
||||
if (getPos(move).getType() == Type.KING) kingPos.put(getPos(move).getColor(), move.pos);
|
||||
if (getPos(move).getType() == Type.KING) kingPos.put(getPos(move).getColor(), move.getPos());
|
||||
|
||||
// Update log
|
||||
log.removeLast();
|
||||
@ -436,13 +436,13 @@ public class Board {
|
||||
* @param move The move from which position to return a piece
|
||||
* @return The piece at the position of the move
|
||||
*/
|
||||
public Piece getPos(Move move) { return get(move.pos); }
|
||||
public Piece getPos(Move move) { return get(move.getPos()); }
|
||||
|
||||
/**
|
||||
* @param move The move from which destination to return a piece
|
||||
* @return The piece at the destination of the move
|
||||
*/
|
||||
public Piece getDest(Move move) { return get(move.dest); }
|
||||
public Piece getDest(Move move) { return get(move.getDest()); }
|
||||
|
||||
/**
|
||||
* Places a piece at the position of a move.
|
||||
@ -450,7 +450,7 @@ public class Board {
|
||||
* @param move The move at which position to place the piece
|
||||
* @param piece The piece to place
|
||||
*/
|
||||
public void setPos(Move move, Piece piece) { set(move.pos, piece); }
|
||||
public void setPos(Move move, Piece piece) { set(move.getPos(), piece); }
|
||||
|
||||
/**
|
||||
* Places a piece at the destination of a move.
|
||||
@ -458,7 +458,7 @@ public class Board {
|
||||
* @param move The move at which destination to place the piece
|
||||
* @param piece The piece to place
|
||||
*/
|
||||
public void setDest(Move move, Piece piece) { set(move.dest, piece); }
|
||||
public void setDest(Move move, Piece piece) { set(move.getDest(), piece); }
|
||||
|
||||
/**
|
||||
* @return The board array
|
||||
|
@ -18,7 +18,7 @@ public class King extends Piece {
|
||||
@Override
|
||||
public boolean isValidMove(Move move) {
|
||||
// Castling
|
||||
if (move.xDist == 2 && move.yDist == 0) {
|
||||
if (move.getxDist() == 2 && move.getyDist() == 0) {
|
||||
if (canCastleKingside()) {
|
||||
move.type = Move.Type.CASTLING;
|
||||
return true;
|
||||
@ -28,7 +28,7 @@ public class King extends Piece {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return move.xDist <= 1 && move.yDist <= 1 && checkDestination(move);
|
||||
return move.getxDist() <= 1 && move.getyDist() <= 1 && checkDestination(move);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -19,8 +19,8 @@ public class Knight extends Piece {
|
||||
|
||||
@Override
|
||||
public boolean isValidMove(Move move) {
|
||||
return Math.abs(move.xDist - move.yDist) == 1
|
||||
&& (move.xDist == 1 && move.yDist == 2 || move.xDist == 2 && move.yDist == 1) && checkDestination(move);
|
||||
return Math.abs(move.getxDist() - move.getyDist()) == 1
|
||||
&& (move.getxDist() == 1 && move.getyDist() == 2 || move.getxDist() == 2 && move.getyDist() == 1) && checkDestination(move);
|
||||
}
|
||||
|
||||
private void checkAndInsertMove(List<Move> moves, Position pos, int offsetX, int offsetY) {
|
||||
|
@ -78,14 +78,14 @@ public class Log implements Iterable<MoveNode> {
|
||||
* @param capturedPiece The piece captured with the move
|
||||
*/
|
||||
public void add(Move move, Piece piece, Piece capturedPiece) {
|
||||
enPassant = piece.getType() == Type.PAWN && move.yDist == 2 ? new Position(move.pos.x, move.pos.y + move.ySign) : null;
|
||||
enPassant = piece.getType() == Type.PAWN && move.getyDist() == 2 ? new Position(move.getPos().x, move.getPos().y + move.getySign()) : null;
|
||||
if (activeColor == Color.BLACK) ++fullmoveNumber;
|
||||
if (piece.getType() == Type.PAWN || capturedPiece != null) halfmoveClock = 0;
|
||||
else++halfmoveClock;
|
||||
activeColor = activeColor.opposite();
|
||||
|
||||
// Disable castling rights if a king or a rook has been moved
|
||||
if (piece.getType() == Type.KING || piece.getType() == Type.ROOK) disableCastlingRights(piece, move.pos);
|
||||
if (piece.getType() == Type.KING || piece.getType() == Type.ROOK) disableCastlingRights(piece, move.getPos());
|
||||
|
||||
final MoveNode leaf = new MoveNode(move, capturedPiece, castlingRights.clone(), enPassant, activeColor, fullmoveNumber, halfmoveClock);
|
||||
|
||||
|
@ -12,8 +12,8 @@ import java.util.Objects;
|
||||
*/
|
||||
public class Move {
|
||||
|
||||
public final Position pos, dest;
|
||||
public final int xDist, yDist, xSign, ySign;
|
||||
protected final Position pos, dest;
|
||||
protected final int xDist, yDist, xSign, ySign;
|
||||
public Type type;
|
||||
|
||||
public Move(Position pos, Position dest, Type type) {
|
||||
@ -26,38 +26,25 @@ public class Move {
|
||||
ySign = (int) Math.signum(dest.y - pos.y);
|
||||
}
|
||||
|
||||
public Move(Position pos, Position dest) {
|
||||
this(pos, dest, Type.NORMAL);
|
||||
}
|
||||
public Move(Position pos, Position dest) { this(pos, dest, Type.NORMAL); }
|
||||
|
||||
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)); }
|
||||
|
||||
public static Move fromLAN(String move) {
|
||||
return new Move(Position.fromLAN(move.substring(0, 2)),
|
||||
Position.fromLAN(move.substring(2)));
|
||||
}
|
||||
public static Move fromLAN(String move) { return new Move(Position.fromLAN(move.substring(0, 2)), Position.fromLAN(move.substring(2))); }
|
||||
|
||||
public String toLAN() {
|
||||
return pos.toLAN() + dest.toLAN();
|
||||
}
|
||||
public String toLAN() { return getPos().toLAN() + getDest().toLAN(); }
|
||||
|
||||
public boolean isHorizontal() { return yDist == 0; }
|
||||
public boolean isHorizontal() { return getyDist() == 0; }
|
||||
|
||||
public boolean isVertical() { return xDist == 0; }
|
||||
public boolean isVertical() { return getxDist() == 0; }
|
||||
|
||||
public boolean isDiagonal() { return xDist == yDist; }
|
||||
public boolean isDiagonal() { return getxDist() == getyDist(); }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s -> %s", pos, dest);
|
||||
}
|
||||
public String toString() { return String.format("%s -> %s", getPos(), getDest()); }
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(dest, pos, type, xDist, xSign, yDist, ySign);
|
||||
}
|
||||
public int hashCode() { return Objects.hash(getDest(), getPos(), getType(), getxDist(), getxSign(), getyDist(), getySign()); }
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
@ -65,10 +52,25 @@ public class Move {
|
||||
if (obj == null) return false;
|
||||
if (getClass() != obj.getClass()) return false;
|
||||
Move other = (Move) obj;
|
||||
return Objects.equals(dest, other.dest) && Objects.equals(pos, other.pos) && type == other.type
|
||||
&& xDist == other.xDist && xSign == other.xSign && yDist == other.yDist && ySign == other.ySign;
|
||||
return Objects.equals(getDest(), other.getDest()) && Objects.equals(getPos(), other.getPos()) && getType() == other.getType()
|
||||
&& getxDist() == other.getxDist() && getxSign() == other.getxSign() && getyDist() == other.getyDist()
|
||||
&& getySign() == other.getySign();
|
||||
}
|
||||
|
||||
public Position getPos() { return pos; }
|
||||
|
||||
public Position getDest() { return dest; }
|
||||
|
||||
public int getxDist() { return xDist; }
|
||||
|
||||
public int getyDist() { return yDist; }
|
||||
|
||||
public int getxSign() { return xSign; }
|
||||
|
||||
public int getySign() { return ySign; }
|
||||
|
||||
public Type getType() { return type; }
|
||||
|
||||
public static enum Type {
|
||||
NORMAL, PAWN_PROMOTION, CASTLING, EN_PASSANT, UNKNOWN
|
||||
}
|
||||
|
@ -19,34 +19,34 @@ public class Pawn extends Piece {
|
||||
|
||||
@Override
|
||||
public boolean isValidMove(Move move) {
|
||||
boolean step = move.isVertical() && move.yDist == 1;
|
||||
boolean doubleStep = move.isVertical() && move.yDist == 2;
|
||||
boolean strafe = move.isDiagonal() && move.xDist == 1;
|
||||
boolean step = move.isVertical() && move.getyDist() == 1;
|
||||
boolean doubleStep = move.isVertical() && move.getyDist() == 2;
|
||||
boolean strafe = move.isDiagonal() && move.getxDist() == 1;
|
||||
boolean enPassant = false;
|
||||
if (getColor() == Color.WHITE) doubleStep &= move.pos.y == 6;
|
||||
else doubleStep &= move.pos.y == 1;
|
||||
if (getColor() == Color.WHITE) doubleStep &= move.getPos().y == 6;
|
||||
else doubleStep &= move.getPos().y == 1;
|
||||
|
||||
// Mark move as pawn promotion if necessary
|
||||
if (move.ySign == 1 && move.pos.y == 6 || move.ySign == -1 && move.pos.y == 1)
|
||||
move.type = Move.Type.PAWN_PROMOTION;
|
||||
if (move.getySign() == 1 && move.getPos().y == 6 || move.getySign() == -1 && move.getPos().y == 1)
|
||||
move.type = Move.Type.PAWN_PROMOTION; // TODO: Remove
|
||||
|
||||
// Mark the move as en passant if necessary
|
||||
if (strafe && move.dest.equals(board.getLog().getEnPassant())) {
|
||||
if (strafe && move.getDest().equals(board.getLog().getEnPassant())) {
|
||||
enPassant = true;
|
||||
move.type = Move.Type.EN_PASSANT;
|
||||
}
|
||||
|
||||
return enPassant || (step ^ doubleStep ^ strafe) && move.ySign == (getColor() == Color.WHITE ? -1 : 1)
|
||||
return enPassant || (step ^ doubleStep ^ strafe) && move.getySign() == (getColor() == Color.WHITE ? -1 : 1)
|
||||
&& isFreePath(move);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isFreePath(Move move) {
|
||||
// Two steps forward
|
||||
if (move.yDist == 2)
|
||||
return board.getBoardArr()[move.pos.x][move.dest.y - move.ySign] == null && board.getDest(move) == null;
|
||||
if (move.getyDist() == 2)
|
||||
return board.getBoardArr()[move.getPos().x][move.getDest().y - move.getySign()] == null && board.getDest(move) == null;
|
||||
// One step forward
|
||||
else if (move.xDist == 0) return board.getDest(move) == null;
|
||||
else if (move.getxDist() == 0) return board.getDest(move) == null;
|
||||
// Capture move
|
||||
else return board.getDest(move) != null && board.getDest(move).getColor() != getColor();
|
||||
}
|
||||
@ -81,6 +81,7 @@ public class Pawn extends Piece {
|
||||
if (isFreePath(move)) moves.add(move);
|
||||
}
|
||||
|
||||
// TODO: Check against instance
|
||||
// Mark moves as pawn promotion if necessary
|
||||
if (sign == 1 && pos.y == 6 || sign == -1 && pos.y == 1)
|
||||
moves.parallelStream().forEach(m -> m.type = Move.Type.PAWN_PROMOTION);
|
||||
@ -88,7 +89,7 @@ public class Pawn extends Piece {
|
||||
// Add en passant move if necessary
|
||||
if (board.getLog().getEnPassant() != null) {
|
||||
Move move = new Move(pos, board.getLog().getEnPassant(), Move.Type.EN_PASSANT);
|
||||
if (move.isDiagonal() && move.xDist == 1) moves.add(move);
|
||||
if (move.isDiagonal() && move.getxDist() == 1) moves.add(move);
|
||||
}
|
||||
|
||||
return moves;
|
||||
|
@ -44,8 +44,8 @@ public abstract class Piece implements Cloneable {
|
||||
* @param move The move to check
|
||||
*/
|
||||
protected boolean isFreePath(Move move) {
|
||||
for (int i = move.pos.x + move.xSign, j = move.pos.y + move.ySign; i != move.dest.x
|
||||
|| j != move.dest.y; i += move.xSign, j += move.ySign)
|
||||
for (int i = move.getPos().x + move.getxSign(), j = move.getPos().y + move.getySign(); i != move.getDest().x
|
||||
|| j != move.getDest().y; i += move.getxSign(), j += move.getySign())
|
||||
if (board.getBoardArr()[i][j] != null) return false;
|
||||
return checkDestination(move);
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ public class NaturalPlayer extends Player implements MouseListener {
|
||||
if (board.get(pos) != null && board.get(pos).getColor() == color) {
|
||||
List<Position> positions = board.getMoves(pos)
|
||||
.stream()
|
||||
.map(move -> move.dest)
|
||||
.map(move -> move.getDest())
|
||||
.collect(Collectors.toList());
|
||||
overlayComponent.displayDots(positions);
|
||||
} else pos = null;
|
||||
|
@ -48,15 +48,15 @@ public class OverlayComponent extends JComponent {
|
||||
// Draw an arrow representing the last move and mark its position and
|
||||
// destination
|
||||
if (arrow != null) {
|
||||
Point pos = new Point(arrow.pos.x * tileSize + tileSize / 2, arrow.pos.y * tileSize + tileSize / 2);
|
||||
Point dest = new Point(arrow.dest.x * tileSize + tileSize / 2, arrow.dest.y * tileSize + tileSize / 2);
|
||||
Point pos = new Point(arrow.getPos().x * tileSize + tileSize / 2, arrow.getPos().y * tileSize + tileSize / 2);
|
||||
Point dest = new Point(arrow.getDest().x * tileSize + tileSize / 2, arrow.getDest().y * tileSize + tileSize / 2);
|
||||
|
||||
Graphics2D g2d = (Graphics2D) g;
|
||||
g2d.setStroke(new BasicStroke(3));
|
||||
|
||||
g2d.setColor(Color.yellow);
|
||||
g2d.drawRect(arrow.pos.x * tileSize, arrow.pos.y * tileSize, tileSize, tileSize);
|
||||
g2d.drawRect(arrow.dest.x * tileSize, arrow.dest.y * tileSize, tileSize, tileSize);
|
||||
g2d.drawRect(arrow.getPos().x * tileSize, arrow.getPos().y * tileSize, tileSize, tileSize);
|
||||
g2d.drawRect(arrow.getDest().x * tileSize, arrow.getDest().y * tileSize, tileSize, tileSize);
|
||||
|
||||
Shape arrowShape = createArrowShape(pos, dest);
|
||||
g.setColor(new Color(255, 0, 0, 127));
|
||||
|
Reference in New Issue
Block a user