Implemented proper pawn promotion
* Moved move execution and reversion to the Move class * Removed Move.Type enumeration * Added Move subclasses Castling, EnPassant and PawnPromotion * Generating all four possible pawn promotions in the Pawn class * Temporarily removed special move support from NaturalPlayer
This commit is contained in:
parent
0edb83087b
commit
71f48895df
@ -61,9 +61,6 @@ public class Board {
|
|||||||
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 {
|
else {
|
||||||
// Set type after validation
|
|
||||||
if (move.getType() == Move.Type.UNKNOWN) move.type = Move.Type.NORMAL;
|
|
||||||
|
|
||||||
// Move piece
|
// Move piece
|
||||||
move(move);
|
move(move);
|
||||||
|
|
||||||
@ -86,37 +83,8 @@ public class Board {
|
|||||||
Piece piece = getPos(move);
|
Piece piece = getPos(move);
|
||||||
Piece capturePiece = getDest(move);
|
Piece capturePiece = getDest(move);
|
||||||
|
|
||||||
switch (move.getType()) {
|
// Execute the move
|
||||||
case PAWN_PROMOTION:
|
move.execute(this);
|
||||||
setPos(move, null);
|
|
||||||
// TODO: Select promotion
|
|
||||||
setDest(move, new Queen(piece.getColor(), this));
|
|
||||||
break;
|
|
||||||
case EN_PASSANT:
|
|
||||||
setDest(move, piece);
|
|
||||||
setPos(move, null);
|
|
||||||
boardArr[move.getDest().x][move.getDest().y - move.getySign()] = null;
|
|
||||||
break;
|
|
||||||
case CASTLING:
|
|
||||||
// Move the king
|
|
||||||
setDest(move, piece);
|
|
||||||
setPos(move, null);
|
|
||||||
|
|
||||||
// Move the rook
|
|
||||||
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;
|
|
||||||
case UNKNOWN:
|
|
||||||
System.err.printf("Move of unknown type %s found!%n", move);
|
|
||||||
case NORMAL:
|
|
||||||
setDest(move, piece);
|
|
||||||
setPos(move, null);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
System.err.printf("Move %s of unimplemented type found!%n", move);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the king's position if the moved piece is the king
|
// Update the king's position if the moved piece is the king
|
||||||
if (piece.getType() == Type.KING) kingPos.put(piece.getColor(), move.getDest());
|
if (piece.getType() == Type.KING) kingPos.put(piece.getColor(), move.getDest());
|
||||||
@ -136,15 +104,15 @@ public class Board {
|
|||||||
Pattern.compile(
|
Pattern.compile(
|
||||||
"^(?<pieceType>[NBRQK])(?:(?<fromFile>[a-h])|(?<fromRank>[1-8])|(?<fromSquare>[a-h][1-8]))?x?(?<toSquare>[a-h][1-8])(?:\\+{0,2}|\\#)$"));
|
"^(?<pieceType>[NBRQK])(?:(?<fromFile>[a-h])|(?<fromRank>[1-8])|(?<fromSquare>[a-h][1-8]))?x?(?<toSquare>[a-h][1-8])(?:\\+{0,2}|\\#)$"));
|
||||||
patterns.put("pawnCapture",
|
patterns.put("pawnCapture",
|
||||||
Pattern.compile("^(?<fromFile>[a-h])(?<fromRank>[1-8])?x(?<toSquare>[a-h][1-8])(?<promotedTo>[NBRQK])?(?:\\+{0,2}|\\#)?$"));
|
Pattern.compile("^(?<fromFile>[a-h])(?<fromRank>[1-8])?x(?<toSquare>[a-h][1-8])(?<promotedTo>[NBRQ])?(?:\\+{0,2}|\\#)?$"));
|
||||||
patterns.put("pawnPush", Pattern.compile("^(?<toSquare>[a-h][1-8])(?<promotedTo>[NBRQK])?(?:\\+{0,2}|\\#)$"));
|
patterns.put("pawnPush", Pattern.compile("^(?<toSquare>[a-h][1-8])(?<promotedTo>[NBRQ])?(?:\\+{0,2}|\\#)$"));
|
||||||
patterns.put("castling", Pattern.compile("^(?<queenside>O-O-O)|(?<kingside>O-O)(?:\\+{0,2}|\\#)?$"));
|
patterns.put("castling", Pattern.compile("^(?<queenside>O-O-O)|(?<kingside>O-O)(?:\\+{0,2}|\\#)?$"));
|
||||||
|
|
||||||
patterns.forEach((patternName, pattern) -> {
|
patterns.forEach((patternName, pattern) -> {
|
||||||
Matcher m = pattern.matcher(sanMove);
|
Matcher m = pattern.matcher(sanMove);
|
||||||
if (m.find()) {
|
if (m.find()) {
|
||||||
Position pos = null, dest = null;
|
Position pos = null, dest = null;
|
||||||
Move.Type moveType = Move.Type.NORMAL;
|
Move move = null;
|
||||||
switch (patternName) {
|
switch (patternName) {
|
||||||
case "pieceMove":
|
case "pieceMove":
|
||||||
dest = Position.fromLAN(m.group("toSquare"));
|
dest = Position.fromLAN(m.group("toSquare"));
|
||||||
@ -163,12 +131,16 @@ public class Board {
|
|||||||
pos = Position.fromLAN(String.format("%c%d", file, rank));
|
pos = Position.fromLAN(String.format("%c%d", file, rank));
|
||||||
} else pos = get(type, dest);
|
} else pos = get(type, dest);
|
||||||
}
|
}
|
||||||
|
move = new Move(pos, dest);
|
||||||
break;
|
break;
|
||||||
case "pawnCapture":
|
case "pawnCapture":
|
||||||
dest = Position.fromLAN(m.group("toSquare"));
|
dest = Position.fromLAN(m.group("toSquare"));
|
||||||
char file = m.group("fromFile").charAt(0);
|
char file = m.group("fromFile").charAt(0);
|
||||||
int rank = m.group("fromRank") == null ? get(Type.PAWN, file) : Integer.parseInt(m.group("fromRank"));
|
int rank = m.group("fromRank") == null ? get(Type.PAWN, file) : Integer.parseInt(m.group("fromRank"));
|
||||||
pos = Position.fromLAN(String.format("%c%d", file, rank));
|
pos = Position.fromLAN(String.format("%c%d", file, rank));
|
||||||
|
if (m.group("promotedTo") != null) {
|
||||||
|
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "pawnPush":
|
case "pawnPush":
|
||||||
dest = Position.fromLAN(m.group("toSquare"));
|
dest = Position.fromLAN(m.group("toSquare"));
|
||||||
@ -183,10 +155,10 @@ public class Board {
|
|||||||
case "castling":
|
case "castling":
|
||||||
pos = new Position(4, log.getActiveColor() == Color.WHITE ? 7 : 0);
|
pos = new Position(4, log.getActiveColor() == Color.WHITE ? 7 : 0);
|
||||||
dest = new Position(m.group("kingside") != null ? 6 : 2, pos.y);
|
dest = new Position(m.group("kingside") != null ? 6 : 2, pos.y);
|
||||||
moveType = Move.Type.CASTLING;
|
move = new Castling(pos, dest);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
move(new Move(pos, dest, moveType));
|
move(move);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -198,38 +170,9 @@ public class Board {
|
|||||||
public void revert() {
|
public void revert() {
|
||||||
MoveNode moveNode = log.getLast();
|
MoveNode moveNode = log.getLast();
|
||||||
Move move = moveNode.move;
|
Move move = moveNode.move;
|
||||||
Piece capturedPiece = moveNode.capturedPiece;
|
|
||||||
|
|
||||||
switch (move.getType()) {
|
// Revert the move
|
||||||
case PAWN_PROMOTION:
|
move.revert(this, moveNode.capturedPiece);
|
||||||
setPos(move, new Pawn(getDest(move).getColor(), this));
|
|
||||||
setDest(move, capturedPiece);
|
|
||||||
break;
|
|
||||||
case EN_PASSANT:
|
|
||||||
setPos(move, getDest(move));
|
|
||||||
setDest(move, null);
|
|
||||||
boardArr[move.getDest().x][move.getDest().y - move.getySign()] = new Pawn(getPos(move).getColor().opposite(), this);
|
|
||||||
break;
|
|
||||||
case CASTLING:
|
|
||||||
// Move the king
|
|
||||||
setPos(move, getDest(move));
|
|
||||||
setDest(move, null);
|
|
||||||
|
|
||||||
// Move the rook
|
|
||||||
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;
|
|
||||||
case UNKNOWN:
|
|
||||||
System.err.printf("Move of unknown type %s found!%n", move);
|
|
||||||
case NORMAL:
|
|
||||||
setPos(move, getDest(move));
|
|
||||||
setDest(move, capturedPiece);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
System.err.printf("Move %s of unimplemented type found!%n", move);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the king's position if the moved piece is the king
|
// Update the king's position if the moved piece is the king
|
||||||
if (getPos(move).getType() == Type.KING) kingPos.put(getPos(move).getColor(), move.getPos());
|
if (getPos(move).getType() == Type.KING) kingPos.put(getPos(move).getColor(), move.getPos());
|
||||||
|
35
src/dev/kske/chess/board/Castling.java
Normal file
35
src/dev/kske/chess/board/Castling.java
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package dev.kske.chess.board;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Project: <strong>Chess</strong><br>
|
||||||
|
* File: <strong>Castling.java</strong><br>
|
||||||
|
* Created: <strong>2 Nov 2019</strong><br>
|
||||||
|
*
|
||||||
|
* @since Chess v0.5-alpha
|
||||||
|
* @author Kai S. K. Engelbart
|
||||||
|
*/
|
||||||
|
public class Castling extends Move {
|
||||||
|
|
||||||
|
private final Move rookMove;
|
||||||
|
|
||||||
|
public Castling(Position pos, Position dest) {
|
||||||
|
super(pos, dest);
|
||||||
|
rookMove = dest.x == 6 ? new Move(7, pos.y, 5, pos.y) : new Move(0, pos.y, 3, pos.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Castling(int xPos, int yPos, int xDest, int yDest) { this(new Position(xPos, yPos), new Position(xDest, yDest)); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Board board) {
|
||||||
|
// Move the king and the rook
|
||||||
|
super.execute(board);
|
||||||
|
rookMove.execute(board);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void revert(Board board, Piece capturedPiece) {
|
||||||
|
// Move the king and the rook
|
||||||
|
super.revert(board, capturedPiece);
|
||||||
|
rookMove.revert(board, null);
|
||||||
|
}
|
||||||
|
}
|
35
src/dev/kske/chess/board/EnPassant.java
Normal file
35
src/dev/kske/chess/board/EnPassant.java
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package dev.kske.chess.board;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Project: <strong>Chess</strong><br>
|
||||||
|
* File: <strong>EnPassant.java</strong><br>
|
||||||
|
* Created: <strong>2 Nov 2019</strong><br>
|
||||||
|
*
|
||||||
|
* @since Chess v0.5-alpha
|
||||||
|
* @author Kai S. K. Engelbart
|
||||||
|
*/
|
||||||
|
public class EnPassant extends Move {
|
||||||
|
|
||||||
|
private final Position capturePos;
|
||||||
|
|
||||||
|
public EnPassant(Position pos, Position dest) {
|
||||||
|
super(pos, dest);
|
||||||
|
capturePos = new Position(dest.x, dest.y - ySign);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EnPassant(int xPos, int yPos, int xDest, int yDest) { this(new Position(xPos, yPos), new Position(xDest, yDest)); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Board board) {
|
||||||
|
super.execute(board);
|
||||||
|
board.set(capturePos, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void revert(Board board, Piece capturedPiece) {
|
||||||
|
super.revert(board, capturedPiece);
|
||||||
|
board.set(capturePos, new Pawn(board.get(pos).getColor().opposite(), board));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Position getCapturePos() { return capturePos; }
|
||||||
|
}
|
@ -17,18 +17,9 @@ public class King extends Piece {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isValidMove(Move move) {
|
public boolean isValidMove(Move move) {
|
||||||
// Castling
|
return (move.getxDist() == 2 && move.getyDist() == 0
|
||||||
if (move.getxDist() == 2 && move.getyDist() == 0) {
|
&& (move.getDest().x == 6 && canCastleKingside() || move.getDest().x == 2 && canCastleQueenside()))
|
||||||
if (canCastleKingside()) {
|
|| move.getxDist() <= 1 && move.getyDist() <= 1 && checkDestination(move);
|
||||||
move.type = Move.Type.CASTLING;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (canCastleQueenside()) {
|
|
||||||
move.type = Move.Type.CASTLING;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return move.getxDist() <= 1 && move.getyDist() <= 1 && checkDestination(move);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -42,8 +33,8 @@ public class King extends Piece {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Castling
|
// Castling
|
||||||
if (canCastleKingside()) moves.add(new Move(pos, new Position(6, pos.y), Move.Type.CASTLING));
|
if (canCastleKingside()) moves.add(new Castling(pos, new Position(6, pos.y)));
|
||||||
if (canCastleQueenside()) moves.add(new Move(pos, new Position(2, pos.y), Move.Type.CASTLING));
|
if (canCastleQueenside()) moves.add(new Castling(pos, new Position(2, pos.y)));
|
||||||
|
|
||||||
return moves;
|
return moves;
|
||||||
}
|
}
|
||||||
|
@ -14,24 +14,33 @@ 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;
|
||||||
public Type type;
|
|
||||||
|
|
||||||
public Move(Position pos, Position dest, Type type) {
|
public Move(Position pos, Position dest) {
|
||||||
this.pos = pos;
|
this.pos = pos;
|
||||||
this.dest = dest;
|
this.dest = dest;
|
||||||
this.type = type;
|
|
||||||
xDist = Math.abs(dest.x - pos.x);
|
xDist = Math.abs(dest.x - pos.x);
|
||||||
yDist = Math.abs(dest.y - pos.y);
|
yDist = Math.abs(dest.y - pos.y);
|
||||||
xSign = (int) Math.signum(dest.x - pos.x);
|
xSign = (int) Math.signum(dest.x - pos.x);
|
||||||
ySign = (int) Math.signum(dest.y - pos.y);
|
ySign = (int) Math.signum(dest.y - pos.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
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)); }
|
||||||
|
|
||||||
|
// TODO: Pawn promotion
|
||||||
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 void execute(Board board) {
|
||||||
|
// Move the piece to the move's destination square and clean the old position
|
||||||
|
board.set(dest, board.get(pos));
|
||||||
|
board.set(pos, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void revert(Board board, Piece capturedPiece) {
|
||||||
|
// Move the piece to the move's position square and clean the destination
|
||||||
|
board.set(pos, board.get(dest));
|
||||||
|
board.set(dest, capturedPiece);
|
||||||
|
}
|
||||||
|
|
||||||
public String toLAN() { return getPos().toLAN() + getDest().toLAN(); }
|
public String toLAN() { return getPos().toLAN() + getDest().toLAN(); }
|
||||||
|
|
||||||
public boolean isHorizontal() { return getyDist() == 0; }
|
public boolean isHorizontal() { return getyDist() == 0; }
|
||||||
@ -44,7 +53,7 @@ public class Move {
|
|||||||
public String toString() { return String.format("%s -> %s", getPos(), getDest()); }
|
public String toString() { return String.format("%s -> %s", getPos(), getDest()); }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() { return Objects.hash(getDest(), getPos(), getType(), getxDist(), getxSign(), getyDist(), getySign()); }
|
public int hashCode() { return Objects.hash(getDest(), getPos(), getxDist(), getxSign(), getyDist(), getySign()); }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
@ -52,9 +61,8 @@ public class Move {
|
|||||||
if (obj == null) return false;
|
if (obj == null) return false;
|
||||||
if (getClass() != obj.getClass()) return false;
|
if (getClass() != obj.getClass()) return false;
|
||||||
Move other = (Move) obj;
|
Move other = (Move) obj;
|
||||||
return Objects.equals(getDest(), other.getDest()) && Objects.equals(getPos(), other.getPos()) && getType() == other.getType()
|
return Objects.equals(getDest(), other.getDest()) && Objects.equals(getPos(), other.getPos()) && getxDist() == other.getxDist()
|
||||||
&& getxDist() == other.getxDist() && getxSign() == other.getxSign() && getyDist() == other.getyDist()
|
&& getxSign() == other.getxSign() && getyDist() == other.getyDist() && getySign() == other.getySign();
|
||||||
&& getySign() == other.getySign();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Position getPos() { return pos; }
|
public Position getPos() { return pos; }
|
||||||
@ -68,10 +76,4 @@ public class Move {
|
|||||||
public int getxSign() { return xSign; }
|
public int getxSign() { return xSign; }
|
||||||
|
|
||||||
public int getySign() { return ySign; }
|
public int getySign() { return ySign; }
|
||||||
|
|
||||||
public Type getType() { return type; }
|
|
||||||
|
|
||||||
public static enum Type {
|
|
||||||
NORMAL, PAWN_PROMOTION, CASTLING, EN_PASSANT, UNKNOWN
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -13,31 +13,18 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class Pawn extends Piece {
|
public class Pawn extends Piece {
|
||||||
|
|
||||||
public Pawn(Color color, Board board) {
|
public Pawn(Color color, Board board) { super(color, board); }
|
||||||
super(color, board);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isValidMove(Move move) {
|
public boolean isValidMove(Move move) {
|
||||||
boolean step = move.isVertical() && move.getyDist() == 1;
|
boolean step = move.isVertical() && move.getyDist() == 1;
|
||||||
boolean doubleStep = move.isVertical() && move.getyDist() == 2;
|
boolean doubleStep = move.isVertical() && move.getyDist() == 2;
|
||||||
boolean strafe = move.isDiagonal() && move.getxDist() == 1;
|
boolean strafe = move.isDiagonal() && move.getxDist() == 1;
|
||||||
boolean enPassant = false;
|
boolean enPassant = strafe && move.getDest().equals(board.getLog().getEnPassant());
|
||||||
if (getColor() == Color.WHITE) doubleStep &= move.getPos().y == 6;
|
if (getColor() == Color.WHITE) doubleStep &= move.getPos().y == 6;
|
||||||
else doubleStep &= move.getPos().y == 1;
|
else doubleStep &= move.getPos().y == 1;
|
||||||
|
|
||||||
// Mark move as pawn promotion if necessary
|
return enPassant || (step ^ doubleStep ^ strafe) && move.getySign() == (getColor() == Color.WHITE ? -1 : 1) && isFreePath(move);
|
||||||
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.getDest().equals(board.getLog().getEnPassant())) {
|
|
||||||
enPassant = true;
|
|
||||||
move.type = Move.Type.EN_PASSANT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return enPassant || (step ^ doubleStep ^ strafe) && move.getySign() == (getColor() == Color.WHITE ? -1 : 1)
|
|
||||||
&& isFreePath(move);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -54,47 +41,46 @@ public class Pawn extends Piece {
|
|||||||
@Override
|
@Override
|
||||||
protected List<Move> getPseudolegalMoves(Position pos) {
|
protected List<Move> getPseudolegalMoves(Position pos) {
|
||||||
List<Move> moves = new ArrayList<>();
|
List<Move> moves = new ArrayList<>();
|
||||||
|
|
||||||
int sign = getColor() == Color.WHITE ? -1 : 1;
|
int sign = getColor() == Color.WHITE ? -1 : 1;
|
||||||
|
boolean pawnPromotion = sign == 1 && pos.y == 6 || sign == -1 && pos.y == 1;
|
||||||
|
|
||||||
// Strafe left
|
// Strafe left
|
||||||
if (pos.x > 0) {
|
if (pos.x > 0) addMoveIfValid(moves, pos, new Position(pos.x - 1, pos.y + sign), pawnPromotion);
|
||||||
Move move = new Move(pos, new Position(pos.x - 1, pos.y + sign));
|
|
||||||
if (isFreePath(move)) moves.add(move);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strafe right
|
// Strafe right
|
||||||
if (pos.x < 7) {
|
if (pos.x < 7) addMoveIfValid(moves, pos, new Position(pos.x + 1, pos.y + sign), pawnPromotion);
|
||||||
Move move = new Move(pos, new Position(pos.x + 1, pos.y + sign));
|
|
||||||
if (isFreePath(move)) moves.add(move);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Step forward
|
// Step forward
|
||||||
if (sign == 1 && pos.y < 7 || sign == -1 && pos.y > 0) {
|
if (sign == 1 && pos.y < 7 || sign == -1 && pos.y > 0) addMoveIfValid(moves, pos, new Position(pos.x, pos.y + sign), pawnPromotion);
|
||||||
Move move = new Move(pos, new Position(pos.x, pos.y + sign));
|
|
||||||
if (isFreePath(move)) moves.add(move);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Double step forward
|
// Double step forward
|
||||||
if (sign == 1 && pos.y == 1 || sign == -1 && pos.y == 6) {
|
if (sign == 1 && pos.y == 1 || sign == -1 && pos.y == 6) addMoveIfValid(moves, pos, new Position(pos.x, pos.y + 2 * sign), pawnPromotion);
|
||||||
Move move = new Move(pos, new Position(pos.x, pos.y + 2 * sign));
|
|
||||||
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);
|
|
||||||
|
|
||||||
// Add en passant move if necessary
|
// Add en passant move if necessary
|
||||||
if (board.getLog().getEnPassant() != null) {
|
if (board.getLog().getEnPassant() != null) {
|
||||||
Move move = new Move(pos, board.getLog().getEnPassant(), Move.Type.EN_PASSANT);
|
Move move = new EnPassant(pos, board.getLog().getEnPassant());
|
||||||
if (move.isDiagonal() && move.getxDist() == 1) moves.add(move);
|
if (move.isDiagonal() && move.getxDist() == 1) moves.add(move);
|
||||||
}
|
}
|
||||||
|
|
||||||
return moves;
|
return moves;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addMoveIfValid(List<Move> moves, Position pos, Position dest, boolean pawnPromotion) {
|
||||||
|
Move move = new Move(pos, dest);
|
||||||
|
if (isFreePath(move)) {
|
||||||
|
if (pawnPromotion) {
|
||||||
|
try {
|
||||||
|
moves.add(new PawnPromotion(pos, dest, Queen.class));
|
||||||
|
moves.add(new PawnPromotion(pos, dest, Rook.class));
|
||||||
|
moves.add(new PawnPromotion(pos, dest, Knight.class));
|
||||||
|
moves.add(new PawnPromotion(pos, dest, Bishop.class));
|
||||||
|
} catch (NoSuchMethodException | SecurityException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
} else moves.add(move);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Type getType() { return Type.PAWN; }
|
public Type getType() { return Type.PAWN; }
|
||||||
}
|
}
|
||||||
|
46
src/dev/kske/chess/board/PawnPromotion.java
Normal file
46
src/dev/kske/chess/board/PawnPromotion.java
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package dev.kske.chess.board;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
|
||||||
|
import dev.kske.chess.board.Piece.Color;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Project: <strong>Chess</strong><br>
|
||||||
|
* File: <strong>PawnPromotion.java</strong><br>
|
||||||
|
* Created: <strong>2 Nov 2019</strong><br>
|
||||||
|
*
|
||||||
|
* @since Chess v0.5-alpha
|
||||||
|
* @author Kai S. K. Engelbart
|
||||||
|
*/
|
||||||
|
public class PawnPromotion extends Move {
|
||||||
|
|
||||||
|
private Constructor<? extends Piece> promotionPieceConstructor;
|
||||||
|
|
||||||
|
public PawnPromotion(Position pos, Position dest, Class<? extends Piece> promotionPiece) throws NoSuchMethodException, SecurityException {
|
||||||
|
super(pos, dest);
|
||||||
|
promotionPieceConstructor = promotionPiece.getDeclaredConstructor(Color.class, Board.class);
|
||||||
|
promotionPieceConstructor.setAccessible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PawnPromotion(int xPos, int yPos, int xDest, int yDest, Class<? extends Piece> promotionPiece)
|
||||||
|
throws NoSuchMethodException, SecurityException {
|
||||||
|
this(new Position(xPos, yPos), new Position(xDest, yDest), promotionPiece);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Board board) {
|
||||||
|
try {
|
||||||
|
board.set(pos, promotionPieceConstructor.newInstance(board.get(pos).getColor(), board));
|
||||||
|
super.execute(board);
|
||||||
|
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | SecurityException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void revert(Board board, Piece capturedPiece) {
|
||||||
|
super.revert(board, capturedPiece);
|
||||||
|
board.set(pos, new Pawn(board.get(dest).getColor(), board));
|
||||||
|
}
|
||||||
|
}
|
@ -7,7 +7,6 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
import dev.kske.chess.board.Board;
|
import dev.kske.chess.board.Board;
|
||||||
import dev.kske.chess.board.Move;
|
import dev.kske.chess.board.Move;
|
||||||
import dev.kske.chess.board.Move.Type;
|
|
||||||
import dev.kske.chess.board.Piece.Color;
|
import dev.kske.chess.board.Piece.Color;
|
||||||
import dev.kske.chess.board.Position;
|
import dev.kske.chess.board.Position;
|
||||||
import dev.kske.chess.ui.OverlayComponent;
|
import dev.kske.chess.ui.OverlayComponent;
|
||||||
@ -37,42 +36,32 @@ public class NaturalPlayer extends Player implements MouseListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void requestMove() {
|
public void requestMove() { moveRequested = true; }
|
||||||
moveRequested = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cancelMove() {
|
public void cancelMove() { moveRequested = false; }
|
||||||
moveRequested = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void disconnect() {
|
public void disconnect() { overlayComponent.removeMouseListener(this); }
|
||||||
overlayComponent.removeMouseListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mousePressed(MouseEvent evt) {
|
public void mousePressed(MouseEvent evt) {
|
||||||
if (!moveRequested) return;
|
if (!moveRequested) return;
|
||||||
if (pos == null) {
|
if (pos == null) {
|
||||||
pos = new Position(evt.getPoint().x / overlayComponent.getTileSize(),
|
pos = new Position(evt.getPoint().x / overlayComponent.getTileSize(), evt.getPoint().y / overlayComponent.getTileSize());
|
||||||
evt.getPoint().y / overlayComponent.getTileSize());
|
|
||||||
|
|
||||||
Board board = new Board(this.board);
|
Board board = new Board(this.board);
|
||||||
if (board.get(pos) != null && board.get(pos).getColor() == color) {
|
if (board.get(pos) != null && board.get(pos).getColor() == color) {
|
||||||
List<Position> positions = board.getMoves(pos)
|
List<Position> positions = board.getMoves(pos).stream().map(move -> move.getDest()).collect(Collectors.toList());
|
||||||
.stream()
|
|
||||||
.map(move -> move.getDest())
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
overlayComponent.displayDots(positions);
|
overlayComponent.displayDots(positions);
|
||||||
} else pos = null;
|
} else pos = null;
|
||||||
} else {
|
} else {
|
||||||
Position dest = new Position(evt.getPoint().x / overlayComponent.getTileSize(),
|
Position dest = new Position(evt.getPoint().x / overlayComponent.getTileSize(), evt.getPoint().y / overlayComponent.getTileSize());
|
||||||
evt.getPoint().y / overlayComponent.getTileSize());
|
|
||||||
|
|
||||||
overlayComponent.clearDots();
|
overlayComponent.clearDots();
|
||||||
moveRequested = false;
|
moveRequested = false;
|
||||||
game.onMove(NaturalPlayer.this, new Move(pos, dest, Type.UNKNOWN));
|
// TODO: Special moves
|
||||||
|
game.onMove(NaturalPlayer.this, new Move(pos, dest));
|
||||||
pos = null;
|
pos = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user