diff --git a/src/chess/Board.java b/src/chess/Board.java index 284ed4e..f30821a 100644 --- a/src/chess/Board.java +++ b/src/chess/Board.java @@ -33,6 +33,36 @@ public class Board { board[size()-4][0] = new King(this, false, size() - 4, 0); } + public boolean movePiece(int x, int y, int newX, int newY){ + ChessPiece selectedPiece; + // make sure the place we are moving from has a piece + if ((selectedPiece = get(x, y)) == null) + return false; + var moves = selectedPiece.getMoves(); + for (Move m : moves){ + // reject the moves that don't correspond to where we want to move to. + if (m.getX() != newX || m.getY() != newY) + continue; + ChessPiece movedPiece = get(m); + // make sure they are of the same color. Since we know this move is the position we want to move to + // we can early exit because we are not allowed to move on top of our own pieces + if (selectedPiece.isWhite == movedPiece.isWhite) + return false; + // if we were unable to set the piece down we failed to move the piece + if (!set(m, selectedPiece)) + return false; + // run special conditions. Only matters for pieces which have special conditions, since is defaulted to empty body. + selectedPiece.applySpecialMove(m); + set(x, y, null); + return true; + } + return false; + } + + public ChessPiece get(Move m){ + return get(m.getX(), m.getY()); + } + public ChessPiece get(int x, int y){ if (x < 0 || x > board.length) return null; @@ -41,6 +71,19 @@ public class Board { return board[x][y]; } + public boolean set(Move m, ChessPiece piece) { + return set(m.getX(), m.getY(), piece); + } + + protected boolean set(int x, int y, ChessPiece piece){ + if (x < 0 || x > board.length) + return false; + if (y < 0 || y > board.length) + return false; + board[x][y] = piece; + return true; + } + public int size(){ return board.length; } diff --git a/src/chess/ChessPiece.java b/src/chess/ChessPiece.java index ee31582..c2728fc 100644 --- a/src/chess/ChessPiece.java +++ b/src/chess/ChessPiece.java @@ -7,6 +7,7 @@ public abstract class ChessPiece { protected Board b; protected int x, y; protected boolean isInDanger, isWhite; + protected boolean isFirstMove = true; public ChessPiece(Board b, boolean isWhite, int x, int y) { this.b = b; @@ -23,7 +24,16 @@ public abstract class ChessPiece { return isWhite; } + public boolean isFirstMove(){ + return isFirstMove; + } + + public void setMoved(){ + isFirstMove = false; + } + public abstract ArrayList getMoves(); + public void applySpecialMove(Move moveWithSpecial){} protected ArrayList getCardinalMoves(int length){ ArrayList moves = new ArrayList(); diff --git a/src/chess/King.java b/src/chess/King.java index 8e99b38..1e5fc23 100644 --- a/src/chess/King.java +++ b/src/chess/King.java @@ -13,6 +13,50 @@ public class King extends ChessPiece { ArrayList moves = new ArrayList(); moves.addAll(super.getCardinalMoves(1)); moves.addAll(super.getDiagonalMoves(1)); + if (isFirstMove){ + ChessPiece rook = null; + // castling + if (isWhite){ + if ((rook = b.get(0, 0)) != null && checkIfRookValid(rook)) + moves.add(new Move(2, 0, Move.SpecialConditions.leftCastle)); + if ((rook = b.get(b.size() - 1, 0)) != null && checkIfRookValid(rook)) + moves.add(new Move(b.size() - 2, 0, Move.SpecialConditions.rightCastle)); + } else { + if ((rook = b.get(0, b.size()-1)) != null && checkIfRookValid(rook)) + moves.add(new Move(2, b.size()-1, Move.SpecialConditions.leftCastle)); + if ((rook = b.get(b.size() - 1, b.size()-1)) != null && checkIfRookValid(rook)) + moves.add(new Move(b.size() - 2, b.size()-1, Move.SpecialConditions.rightCastle)); + } + } return moves; } + + @Override + public void applySpecialMove(Move moveWithSpecial){ + var specialCondition = moveWithSpecial.getSpecialCondition(); + if(specialCondition == Move.SpecialConditions.leftCastle) + castleLeft(); + else if (specialCondition == Move.SpecialConditions.rightCastle) + castleRight(); + } + + private void castleRight(){ + // casting has to move the rook on the right size of the king from white's perspective + if (this.isWhite) + b.set(b.size()-3, 0, b.get(b.size()-1, 0)); + else + b.set(b.size()-3, b.size()-1, b.get(b.size()-1, b.size()-1)); + } + + private boolean checkIfRookValid(ChessPiece piece){ + return piece.isFirstMove() && piece instanceof Rook; + } + + private void castleLeft(){ + // casting has to move the rook on the left size of the king from white's perspective + if (this.isWhite) + b.set(3, 0, b.get(0, 0)); + else + b.set(3, b.size()-1, b.get(0, b.size()-1)); + } } diff --git a/src/chess/Move.java b/src/chess/Move.java index 1522e3b..127da15 100644 --- a/src/chess/Move.java +++ b/src/chess/Move.java @@ -4,18 +4,22 @@ import java.util.ArrayList; public class Move { + enum SpecialConditions { + none, leftEnPassant, rightEnPassant, leftCastle, rightCastle + } + private final int x,y; - private final boolean enPassant; + private final SpecialConditions specialCondition; public Move(int x, int y){ this.x = x; this.y = y; - enPassant = false; + specialCondition = SpecialConditions.none; } - public Move(int x, int y, boolean enPassant){ + public Move(int x, int y, SpecialConditions specialCondition){ this.x = x; this.y = y; - this.enPassant = enPassant; + this.specialCondition = specialCondition; } public int getX() { @@ -26,7 +30,7 @@ public class Move { return y; } - public boolean isEnPassant(){ - return enPassant; + public SpecialConditions getSpecialCondition(){ + return specialCondition; } } diff --git a/src/chess/Pawn.java b/src/chess/Pawn.java index 317e165..42a0f76 100644 --- a/src/chess/Pawn.java +++ b/src/chess/Pawn.java @@ -4,16 +4,10 @@ import java.util.ArrayList; public class Pawn extends ChessPiece { - private final boolean isFirstMove = true; - public Pawn(Board b, boolean isWhite, int x, int y) { super(b,isWhite,x,y); } - public boolean isFirstMove(){ - return isFirstMove; - } - @Override public ArrayList getMoves() { ArrayList moves = new ArrayList(); @@ -21,12 +15,47 @@ public class Pawn extends ChessPiece { if (isFirstMove) moves.add(new Move(x, y + 2)); ChessPiece neighbour = null; - // En passant - if ((neighbour = b.get(x-1, y)) != null && neighbour instanceof Pawn && ((Pawn) neighbour).isFirstMove()) - moves.add(new Move(x-1, 1, true)); - // En passant - if ((neighbour = b.get(x+1, y)) != null && neighbour instanceof Pawn && ((Pawn) neighbour).isFirstMove()) - moves.add(new Move(x+1, 1, true)); + + if (isWhite){ + // En passant + if ((neighbour = b.get(x-1, y)) != null && neighbour instanceof Pawn && ((Pawn) neighbour).isFirstMove()) + moves.add(new Move(x-1, y + 1, Move.SpecialConditions.leftEnPassant)); + // En passant + if ((neighbour = b.get(x+1, y)) != null && neighbour instanceof Pawn && ((Pawn) neighbour).isFirstMove()) + moves.add(new Move(x+1, + 1, Move.SpecialConditions.rightEnPassant)); + } else { + // unfortunately have to flip the direction depending on player type + // En passant + if ((neighbour = b.get(x-1, y)) != null && neighbour instanceof Pawn && ((Pawn) neighbour).isFirstMove()) + moves.add(new Move(x-1, y - 1, Move.SpecialConditions.leftEnPassant)); + // En passant + if ((neighbour = b.get(x+1, y)) != null && neighbour instanceof Pawn && ((Pawn) neighbour).isFirstMove()) + moves.add(new Move(x+1, - 1, Move.SpecialConditions.rightEnPassant)); + } + return moves; } + + @Override + public void applySpecialMove(Move moveWithSpecial){ + var specialCondition = moveWithSpecial.getSpecialCondition(); + if(specialCondition == Move.SpecialConditions.leftEnPassant) + enPassantLeft(); + else if (specialCondition == Move.SpecialConditions.rightEnPassant) + enPassantRight(); + } + + private void enPassantLeft(){ + if (isWhite) + b.set(x-1, y, null); + else + b.set(x+1, y, null); + } + + private void enPassantRight(){ + if (isWhite) + b.set(x+1, y, null); + else + b.set(x-1, y, null); + } }