Added pawn promotion #11

Merged
CyB3RC0nN0R merged 5 commits from f/pawn_promotion into master 2019-11-05 05:44:11 +01:00
9 changed files with 70 additions and 67 deletions
Showing only changes of commit 0edb83087b - Show all commits

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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);

View File

@ -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
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

View File

@ -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));