package com.editev.chess.piece; import java.util.NoSuchElementException; import java.util.Enumeration; import com.editev.util.Enum; import com.editev.chess.Move; import com.editev.chess.Board; import com.editev.chess.Chess; import com.editev.chess.Square; import com.editev.chess.Game; /** Contains a list of possible piece moves as byte offsets, * and encompasses all the rules about legal moves and actually performing * the move as an operation on the Game. * * @see See the source here. */ abstract public class Piece extends Chess { /** Is there a piece between the "from" and "target" squares? * Only the Knight overrides this method. */ public boolean pieceBetween( Move move, Board board ) { byte c = getColumnOffset( move ); // number of columns and rows to check. byte r = getRowOffset( move ); byte squares = (byte) Math.max( Math.abs( c ), Math.abs( r ) ); // number of squares between from and to. if (squares > 1) { // there might be pieces between! byte dc = (byte) (c / squares); // increment for the col and row... byte dr = (byte) (r / squares); // dc and dr can only be 0, +1 or -1. Square sq = new Square( // increment through all squares between (byte) (move.source.column+dc), // first column between (byte) (move.source.row +dr) // first row between. ); for (byte s=1; // first square s < squares; // up to but not including the end. sq.column += dc, // increment column, row, square sq.row += dr, s++) { if (board.hasPiece( sq )) return true; // we found a piece in the way! } } return false; // we found no pieces between "from" and "to". } /** Adjust the board's pieces only. @return the captured piece if any. * * Only the King and Pawn override this method. */ public byte applyMoveToBoard( Move move, Board board ) { byte toPiece = board.getPieceIndex( move.target ); // save the captured piece. board.setPieceIndex( move.target, board.getPieceIndex( move.source ) ); // move the piece to "target"... board.setPieceIndex( move.source, NO_PIECE ); // from "from". return toPiece; // return the captured piece on } /** Undo a move, using the piece captured, if any. * * Only the King and Pawn override this method. */ public void undoMoveToBoard( Move move, Board board, byte captured ) { board.setPieceIndex( move.source, board.getPieceIndex( move.target ) ); // undo the move. board.setPieceIndex( move.target, captured ); // replace any captured pieces. } /** Adjust the board's game, which is everything that isn't the board's squares: * handles promotions, e.p., castling rules, 50 move rule. We DO need the Game and * and not just the game because we need to see if the move is a capture... * * The King, the Pawn and the Rook override this method. */ public void applyMoveToState( Move move, Game game ) { game.incrementMoves(); game.clearEP(); } /** Go to the first move Index. * @return false if there are no more possible moves to go to. * * Only the Pawn overrides this method. */ public void firstMoveIndex( Move move ) { setMoveIndex( move, (byte) 0 ); } /** Go to a specific move index. * @return false if there are no more possible moves to go to. * * Only the Pawn overrides this method. */ public void setMoveIndex( Move move, byte index ) { move.index = index; move.target.column = (byte) (move.source.column + getColumnOffset( move ) ); move.target.row = (byte) (move.source.row + getRowOffset( move ) ); move.resetPromotion(); } /** Go to next possible move. * @return false if there are no more possible moves to go to. * * Only the Pawn overrides this. */ public boolean incrementMoveIndex( Move move ) { if (!moreMoves( move ) ) return false; setMoveIndex( move, ++move.index ); return true; } /** Any more possible moves? * @return true if there are more possible moves after this move. * * Only the Pawn overrides this. */ public boolean moreMoves( Move move ) { return move.index < (moves.length-1); } /** Is this move a capture on this board? * @return whether this move is a capture for this board. * * Only the Pawn overrides this, for e.p. captures and to prevent capturing by advancing straight */ public boolean isCapture( Move move, Board board ) { return board.hasPiece( move.target ); } /** Is this move irreversible? * @return true if this move restarts the 50 move rule. * * Only the Pawn overrides this. */ public boolean isIrreversible( Move move, Board board ) { return isCapture( move, board ); } /** Is this illegal because of a piece-specific rule? * @return true if the piece makes this move illegal for this game. * * We only override this for King and Pawn. */ public boolean isIllegal( Move move, Game game ) { return false; } /** The moves describe all the possible moves in left-to-right, top-to-bottom order. */ public final byte[][] moves; public Piece( byte[][] moves ) { this.moves = moves; } /** Convenience function to translate a move's index into a column offset from the move table.*/ public final byte getColumnOffset( Move move ) { return moves[ move.index ][ 0 ]; } /** Convenience function to translate a move's index into a row offset from the move table.*/ public final byte getRowOffset( Move move ) { return moves[ move.index ][ 1 ]; } }