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