diff --git a/src/suicideChess/Board.java b/src/suicideChess/Board.java index 787d2a6..5e04bd1 100644 --- a/src/suicideChess/Board.java +++ b/src/suicideChess/Board.java @@ -175,7 +175,25 @@ public class Board { return new Piece(Piece.NONE); } - /** + + /** + * This function returns a boolean telling if a {@link Piece} is on a {@link Square}. + * @param square The Square + * @param piece A Piece constant + * @return boolean + * @see Piece + * @see Square + */ + public boolean isEmpty(Square square, Piece piece) { + long mask = mapSquaresToBits[squareToBitBoardSquare(square)]; + if ((bitBoards[piece.getPieceNumber()] & mask) == 0) { + return true; + } else { + return false; + } + } + + /** * This function converts a {@link Square} to a number representing a bitboard square * @param square The Square to be converted * @return int @@ -227,66 +245,67 @@ public class Board { public void display(){ for (int file = NB_OF_FILES; file >= 1; file--) { System.out.println(" +---+---+---+---+---+---+---+---+"); - String display = file+" | "; + String display = file+" |"; for (int rank=1; rank <= NB_OF_RANKS; rank++) { boolean displayedSomething = false; long mask = mapSquaresToBits[rank-1+(file-1)*NB_OF_RANKS]; if (displayPiece(Piece.BLACK_PAWN,mask)) { displayedSomething=true; - display+=Character.toUpperCase(Piece.PAWN_CHAR)+" | "; + display+="'"+Character.toUpperCase(Piece.PAWN_CHAR)+"'|"; } if (displayPiece(Piece.BLACK_QUEEN,mask)) { displayedSomething=true; - display+=Character.toUpperCase(Piece.QUEEN_CHAR)+" | "; + display+="'"+Character.toUpperCase(Piece.QUEEN_CHAR)+"'|"; } if (displayPiece(Piece.BLACK_KING,mask)) { displayedSomething=true; - display+=Character.toUpperCase(Piece.KING_CHAR)+" | "; + display+="'"+Character.toUpperCase(Piece.KING_CHAR)+"'|"; } if (displayPiece(Piece.BLACK_KNIGHT,mask)) { displayedSomething=true; - display+=Character.toUpperCase(Piece.KNIGHT_CHAR)+" | "; + display+="'"+Character.toUpperCase(Piece.KNIGHT_CHAR)+"'|"; } if (displayPiece(Piece.BLACK_ROOK,mask)) { displayedSomething=true; - display+=Character.toUpperCase(Piece.ROOK_CHAR)+" | "; + display+="'"+Character.toUpperCase(Piece.ROOK_CHAR)+"'|"; } if (displayPiece(Piece.BLACK_BISHOP,mask)) { displayedSomething=true; - display+=Character.toUpperCase(Piece.BISHOP_CHAR)+" | "; + display+="'"+Character.toUpperCase(Piece.BISHOP_CHAR)+"'|"; } if (displayPiece(Piece.WHITE_PAWN,mask)) { displayedSomething=true; - display+=Piece.PAWN_CHAR+" | "; + display+=" "+Piece.PAWN_CHAR+" |"; } if (displayPiece(Piece.WHITE_QUEEN,mask)) { displayedSomething=true; - display+=Piece.QUEEN_CHAR+" | "; + display+=" "+Piece.QUEEN_CHAR+" |"; } if (displayPiece(Piece.WHITE_KING,mask)) { displayedSomething=true; - display+=Piece.KING_CHAR+" | "; + display+=" "+Piece.KING_CHAR+" |"; } if (displayPiece(Piece.WHITE_KNIGHT,mask)) { displayedSomething=true; - display+=Piece.KNIGHT_CHAR+" | "; + display+=" "+Piece.KNIGHT_CHAR+" |"; } if (displayPiece(Piece.WHITE_ROOK,mask)) { displayedSomething=true; - display+=Piece.ROOK_CHAR+" | "; + display+=" "+Piece.ROOK_CHAR+" |"; } if (displayPiece(Piece.WHITE_BISHOP,mask)) { displayedSomething=true; - display+=Piece.BISHOP_CHAR+" | "; + display+=" "+Piece.BISHOP_CHAR+" |"; } if (!displayedSomething) - display+=" | "; + display+=" |"; } System.out.println(display); } System.out.println(" +---+---+---+---+---+---+---+---+"); System.out.println(" a b c d e f g h"); + System.out.println(); } @@ -331,16 +350,7 @@ public class Board { bitBoards[piece.getColor()] ^= mapSquaresToBits[squareToBitBoardSquare(square)];; } - //checks if a square is empty for a certain piece - private boolean isEmpty(Square square, Piece piece) { - long mask = mapSquaresToBits[squareToBitBoardSquare(square)]; - if ((bitBoards[piece.getPieceNumber()] & mask) == 0) { - return true; - } else { - return false; - } - } - + //used by function display() private boolean displayPiece(int whatToDisplay, long mask) { if ((bitBoards[whatToDisplay] & mask)==0) { return false; diff --git a/src/suicideChess/Move.java b/src/suicideChess/Move.java index 9694ed2..1691eb4 100644 --- a/src/suicideChess/Move.java +++ b/src/suicideChess/Move.java @@ -33,7 +33,7 @@ public class Move { private Square enPassantSquare; public class NotAValidMoveException extends Exception { - /** + /* * Generated by Eclipse */ private static final long serialVersionUID = 2194133427162274651L; @@ -305,19 +305,30 @@ public class Move { return fromSquare.toString()+toSquare+promotionPiece; } - /** + + /** + * Tests the equality of two moves by just looking at the fromSquare and the toSquare + * @param that A move to test + * @return boolean + */ + public boolean isSimpleEqual(Move that) { + return ((this.fromSquare.isEqual(that.fromSquare))&&(this.toSquare.isEqual(that.toSquare))); + } + + + /** * Displays a move in great details. */ public void display() { System.out.println(" "); - System.out.println("==== Move ===="); - System.out.println("Move: "+getMovingPiece().getPieceNumber()); - System.out.println("From square:"+fromSquare()); - System.out.println("To square: "+toSquare()); - System.out.println((isPromotionMove() ? "Promotion: "+getPromotionPiece().getPieceNumber() : "No Promotion")); - System.out.println((isCaptureMove() ? "Capture: "+getCapturedPiece().getPieceNumber() : "No Capture")); - System.out.println((enablesEnPassant() ? "En-Passant: "+getEnPassantSquare().getFile()+getEnPassantSquare().getRank() : "No en-passant")); - System.out.println("=============="); + System.out.println("===== Move ====="); + System.out.println("Move: "+getMovingPiece().toString()); + System.out.println("From square: "+fromSquare()); + System.out.println("To square: "+toSquare()); + System.out.println((isPromotionMove() ? "Promotion: "+getPromotionPiece().toString() : "No Promotion")); + System.out.println((isCaptureMove() ? "Capture: "+getCapturedPiece().toString() : "No Capture")); + System.out.println((enablesEnPassant() ? "Set en-pass.: "+getEnPassantSquare().getFile()+getEnPassantSquare().getRank() : "No en-pass. set")); + System.out.println("================"); System.out.println(" "); } diff --git a/src/suicideChess/Piece.java b/src/suicideChess/Piece.java index 8093532..c7c05de 100644 --- a/src/suicideChess/Piece.java +++ b/src/suicideChess/Piece.java @@ -138,4 +138,26 @@ public class Piece { public int getPieceType() { return ((pieceNumber/2)-1); } + + /** + * Displays the agebraic name of the piece + * @return String + */ + public String toString() { + switch (pieceNumber/2-1) { + case BISHOP: + return Character.toString(BISHOP_CHAR); + case QUEEN: + return Character.toString(QUEEN_CHAR); + case KING: + return Character.toString(KING_CHAR); + case ROOK: + return Character.toString(ROOK_CHAR); + case PAWN: + return Character.toString(PAWN_CHAR); + case KNIGHT: + return Character.toString(KNIGHT_CHAR); + } + return "**Error**"; + } } diff --git a/src/suicideChess/Rules.java b/src/suicideChess/Rules.java index 90fb673..ae55a73 100644 --- a/src/suicideChess/Rules.java +++ b/src/suicideChess/Rules.java @@ -13,22 +13,58 @@ import suicideChess.Square.NotAValidSquare; public class Rules { - private ArrayList legalMoves; + private ArrayList legalMovesNonCapture; + private ArrayList legalMovesCapture; + public class UnexpectedError extends Exception { + /* + * Generated by Eclipse + */ + private static final long serialVersionUID = 7448113740797323379L; + + UnexpectedError(String s) { super(s); }; + } + + public Rules () { - legalMoves = new ArrayList(); + legalMovesNonCapture = new ArrayList(); + legalMovesCapture = new ArrayList(); } - /** + /** + * Computes the possible moves according to the current status of the {@link Board} and the + * color of the current player. + * @param board The current board position. + * @param color The color of the current player. + * @throws NotAValidSquare If the program throws this exception then there is a bug. + * @throws UnexpectedError This should never happen. + * @see Square + * @see Board + */ + public void legalMovesForPlayer(Board board, int color) throws NotAValidSquare, UnexpectedError { + // Find it! There is only one king, so look for it and stop + Square square; + for(int squareNb = 0; squareNb < Board.NB_OF_SQUARES; squareNb++) { + square = new Square(squareNb); + if (board.isEmpty(square, new Piece(color))) { + continue; + } + legalMovesFromSquare(square,board); + } + } + + + /** * Computes the possible moves from a given {@link Square} * according to the current status of the {@link Board} * @param square The square from which the move must start * @param board The current board position. * @throws NotAValidSquare If the program throws this exception then there is a bug. + * @throws UnexpectedError This should never happen. * @see Square * @see Board */ - public ArrayList legalMovesFromSquare(Square fromSquare, Board board) throws NotAValidSquare { + public void legalMovesFromSquare(Square fromSquare, Board board) throws NotAValidSquare, UnexpectedError { Move validMove; Square toSquare; @@ -71,6 +107,7 @@ public class Rules { } } else { captureLeft = false; + captureEnPassantLeft=false; } if(fromSquare.getFileNb() of all legal {@link Moves} + * without a capture. + * You need to call legalMovesFromSquare before calling this function. + * @return ArrayList + */ + public ArrayList getLegalMovesNonCapture() { + return legalMovesNonCapture; + } + + /** + * This function return the current status of the ArrayList of all legal {@link Moves} + * with a capture. + * You need to call legalMovesFromSquare before calling this function. + * @return ArrayList + */ + public ArrayList getLegalMovesCapture() { + return legalMovesCapture; + } + + + /*===================* + * PRECOMPUTED MOVES * + *===================*/ + private static int[][][][] movesAllowed; diff --git a/src/suicideChess/Square.java b/src/suicideChess/Square.java index dd217f1..0a1d45a 100644 --- a/src/suicideChess/Square.java +++ b/src/suicideChess/Square.java @@ -14,7 +14,7 @@ public class Square { private int rank; public class NotAValidSquare extends Exception { - /** + /* * Generated by Eclipse */ private static final long serialVersionUID = 7586171991212094565L; diff --git a/src/suicideChess/SuicideChess.java b/src/suicideChess/SuicideChess.java index f977a91..54618ed 100644 --- a/src/suicideChess/SuicideChess.java +++ b/src/suicideChess/SuicideChess.java @@ -46,13 +46,14 @@ public class SuicideChess { Board bitboard = new Board(); bitboard.display(); - /*int playerColor = Piece.WHITE; - System.out.println("White: ");*/ + int playerColor = Piece.WHITE; + System.out.println("White: "); while (true) { try { String whatMove= moveInput.readLine(); + boolean playedALegalMove = false; if (whatMove.startsWith("quit")) { System.out.println("Goodbye!"); @@ -61,10 +62,21 @@ public class SuicideChess { if (whatMove.startsWith("hint")) { Rules rules = new Rules(); - ArrayList allLegalMoves = - rules.legalMovesFromSquare(new Square(whatMove.substring(5,7)),bitboard); + rules.legalMovesForPlayer(bitboard,playerColor); + ArrayList allLegalMoves = rules.getLegalMovesCapture(); + if (allLegalMoves.size()==0) { + allLegalMoves = rules.getLegalMovesNonCapture(); + } for(int i = 0; i allLegalMoves = - rules.legalMovesFromSquare(new Square(whatMove.substring(0,2)),bitboard); - int foundMoveIndex = -1; - for (int moveIndex = 0; moveIndex < allLegalMoves.size(); moveIndex++) { - if (allLegalMoves.get(moveIndex).toSquare().isEqual(theMove.toSquare())) { - foundMoveIndex=moveIndex; - break; - } - } - if (foundMoveIndex == -1) { - System.out.println("This move is not valid. Please type 'hint "+whatMove.substring(0,2) - +"' to see available moves."); - } else { - allLegalMoves.get(foundMoveIndex).display(); - bitboard.doMove(allLegalMoves.get(foundMoveIndex)); - bitboard.display(); - } + boolean needToCapture = false; + int foundMoveIndex = -1; + if(theMove.getMovingPiece().getColor() == playerColor) { + rules.legalMovesForPlayer(bitboard,playerColor); + ArrayList allLegalMoves = rules.getLegalMovesCapture(); + if (allLegalMoves.size()==0) { + allLegalMoves = rules.getLegalMovesNonCapture(); + } else { + needToCapture = true; + } + for (int moveIndex = 0; moveIndex < allLegalMoves.size(); moveIndex++) { + if (allLegalMoves.get(moveIndex).isSimpleEqual(theMove)) { + if(theMove.isPromotionMove()&& + theMove.getPromotionPiece().getPieceNumber()!=allLegalMoves.get(moveIndex).getPromotionPiece().getPieceNumber()) { + continue; + } + foundMoveIndex=moveIndex; + break; + } + } + if (foundMoveIndex == -1) { + if (needToCapture) { + System.out.println("Capturing is mandatory."); + } + System.out.println("This move is not valid. Please type 'hint' to see list of legal moves."); + } else { + allLegalMoves.get(foundMoveIndex).display(); + bitboard.doMove(allLegalMoves.get(foundMoveIndex)); + bitboard.display(); + playedALegalMove=true; + } + } else { + System.out.println("Please play a piece of the right color."); + } - /*if (playerColor == Piece.WHITE) { - playerColor = Piece.BLACK; - System.out.println("Black: "); - } else { - playerColor = Piece.WHITE; - System.out.println("White: "); - }*/ - + if (playedALegalMove) { + if (playerColor == Piece.WHITE) { + playerColor = Piece.BLACK; + System.out.println("Black: "); + } else { + playerColor = Piece.WHITE; + System.out.println("White: "); + } + } } catch (NotAValidMoveException err) { System.out.println(err);