package com.editev.chess; import com.editev.util.Enum; import com.editev.util.Filter; import com.editev.util.ExceptionWrapper; import com.editev.chess.piece.*; /** Represent just the Pieces on the 64 Squares of the chess board as byte indices. * * @see See the source here. */ public class Board extends Chess implements Cloneable { /** The actual 64 squares in an 8x8 array. Pieces are represented as simple byte indices for efficiency. */ private final byte[][] squares = { { Black.ROOK, Black.KNIGHT, Black.BISHOP, Black.QUEEN, Black.KING, Black.BISHOP, Black.KNIGHT, Black.ROOK }, { Black.PAWN, Black.PAWN, Black.PAWN, Black.PAWN, Black.PAWN, Black.PAWN, Black.PAWN, Black.PAWN }, { NO_PIECE, NO_PIECE, NO_PIECE, NO_PIECE, NO_PIECE, NO_PIECE, NO_PIECE, NO_PIECE }, { NO_PIECE, NO_PIECE, NO_PIECE, NO_PIECE, NO_PIECE, NO_PIECE, NO_PIECE, NO_PIECE }, { NO_PIECE, NO_PIECE, NO_PIECE, NO_PIECE, NO_PIECE, NO_PIECE, NO_PIECE, NO_PIECE }, { NO_PIECE, NO_PIECE, NO_PIECE, NO_PIECE, NO_PIECE, NO_PIECE, NO_PIECE, NO_PIECE }, { White.PAWN, White.PAWN, White.PAWN, White.PAWN, White.PAWN, White.PAWN, White.PAWN, White.PAWN }, { White.ROOK, White.KNIGHT, White.BISHOP, White.QUEEN, White.KING, White.BISHOP, White.KNIGHT, White.ROOK } }; /** Get a piece index by Square. */ public byte getPieceIndex( Square sq ) { return squares[ sq.row ][ sq.column ]; } /** Get a piece index by source of Move. */ public byte getPieceIndex( Move move ) { return getPieceIndex( move.source ); } /** Set a piece index by Square. */ public void setPieceIndex( Square sq, byte piece ) { squares[ sq.row ][ sq.column ] = piece; } /** Is there a piece on this square? @return true if there is a piece at this Square */ public boolean hasPiece( Square sq ) { return squares[ sq.row ][ sq.column ] != NO_PIECE; } /** A list of Pieces for each piece index which is * used to translate the indices representing pieces in the Board into Pieces with rules. */ public static Piece PIECES[] = { null, King.PIECE, Queen.PIECE, Rook.PIECE, Bishop.PIECE, Knight.PIECE, Pawn.Black.PIECE, null, King.PIECE, Queen.PIECE, Rook.PIECE, Bishop.PIECE, Knight.PIECE, Pawn.White.PIECE, }; /** Gets the Piece at the given square. * @return the Piece at that square or null if there is no piece at that Square. * * @param sq the Square on the Board containing the Piece. */ public Piece getPiece( Square sq ) { return PIECES[ getPieceIndex( sq ) ]; } /** Gets the Piece being Moved.. * @return the Piece at the source of the Move or null if there is no piece at the source.. * * @param sq the Square on the Board containing the Piece. */ public Piece getPiece( Move move ) { return getPiece( move.source ); } /** Find a Piece on the board. * @return a square containing the first matching piece on the board when searched * in row-major order or null if no such piece. */ public Square findPieceSquare( byte piece ) { Square sq = new Square(); for (sq.row=0; sq.row<8; sq.row++) { // look through the rows for (sq.column=0; sq.column<8; sq.column++) { // and the columns if (getPieceIndex( sq ) == piece) { // found that piece! return sq; // return its location. } } } return null; } /** Is the king of this color in check? */ public boolean inCheck( boolean isWhite ) { byte king = toColor( isWhite, Black.KING ); // the king for which we are looking! Square square = findPieceSquare( king ); // the king's location. if (square == null) { throw new RuntimeException( "Board.resultsInCheck: no king on the board!" ); // we should never get here. } return isAttacked( isWhite, square ); // is the king attacked? } /** Does this move result in check? * @return true if making this move would result in check. */ public boolean resultsInCheck( Move move, Piece piece ) { boolean whitesMove = White.is( getPieceIndex( move ) ); // is the move white? byte captured = piece.applyMoveToBoard( move, this ); // make the move, and store any piece captured boolean inCheck = inCheck( whitesMove ); // is the king attacked? piece.undoMoveToBoard( move, this, captured ); // unmove the move regardless. return inCheck; // was the king attacked? } /** Is this square attacked? * @return true if this row/column square is attacked. */ public boolean isAttacked( boolean whitesMove, Square square ) { Move move = new Move(); Square source = move.source; for ( source.row=0; source.row<8; source.row++) { // look through the rows for ( source.column=0; source.column<8; source.column++) { // and the columns byte pieceIndex = getPieceIndex( source ); // the index of the piece at the fromation. boolean whitePiece = White.is( pieceIndex ); // is it a white piece? if (pieceIndex != NO_PIECE && whitePiece != whitesMove) { // this piece could attack the square! Piece piece = Board.PIECES[ pieceIndex ]; // the actual piece. piece.firstMoveIndex( move ); do { if ( move.target.equals( square ) // the piece could be attacking the square! && !piece .pieceBetween( move, this ) // and there are no pieces in the way!! ) { if ( !(piece instanceof Pawn) // only Pawns are a special case || piece.isCapture( move, this ) ) // they attack only diagonally. { return true; // we did find a capture! } } } while (piece.incrementMoveIndex( move )); // while there are more possible moves. } } } return false; // the square is not attacked! } /** Two boards are equal if all their squares are equal. */ public boolean equals( Object x ) { if (!(x instanceof Board)) return false; Board board = (Board) x; Square square = new Square(); for (square.row=0; square.row<8; square.row++) { for (square.column=0; square.column<8; square.column++) { if (getPieceIndex( square ) != board.getPieceIndex( square )) { return false; } } } return true; } /** A deep copy clone(). * @return a deep copy clone of the board with entirely new arrays. */ public Object clone() { return cloneBoard(); } /** A deep copy clone() that returns a Board. * @return a deep copy clone of the board with entirely new arrays. */ public Board cloneBoard() { Board board; try { board = (Board) super.clone(); } catch (CloneNotSupportedException e) { throw new ExceptionWrapper( e ); } // can't happen! for (byte b=0; b<8; b++) { board.squares[b] = (byte[]) board.squares[b].clone(); } return board; } /** Copy the contents of another Board into this Board. */ /* public void copyFrom( Board board ) { Square sq = new Square(); for (; sq.row<8; sq.row++) { for (sq.column=0; sq.column<8; sq.column++) { setPieceIndex( sq, board.getPieceIndex( sq ) ); } } } */ /** Character identifiers for the pieces. */ public static final char[] PIECE_NAMES = { '.', 'k', 'q', 'r', 'b', 'n', 'p', '.', 'K', 'Q', 'R', 'B', 'N', 'P' }; /** @return a String version of the board for debugging purposes. */ public String toString() { StringBuffer buf = new StringBuffer(); Square sq = new Square(); for ( sq.row=0; sq.row<8; sq.row++) { // look through the rows for ( sq.column=0; sq.column<8; sq.column++) { // and the columns buf.append( PIECE_NAMES[ getPieceIndex( sq ) ] ); // the index of the piece at the square. } buf.append('\n'); } return buf.toString(); } }