package com.editev.chess;
import com.editev.util.Filter;
import com.editev.util.Function;
import com.editev.util.Enum;
import com.editev.chess.piece.Piece;
import java.util.Enumeration;
/** A Game that can enumerate its legal Moves.
*
* @see See the source here.
*/
public class Game extends GameState {
/** @return true if this move is illegal for this Game.
* Checks a move for legality for this Game.
*
* @param move the move to check for legality.
*/
public boolean isIllegal( Move move ) {
//if (isStalemate) return true; // all moves are invalid after a stalemate
if (!move.target.isValid()) return true; // don't even consider invalid moves.
byte fromPiece = getPieceIndex( move ); // piece on the start square
byte toPiece = getPieceIndex( move.target ); // piece on the end square
Piece piece = getPiece( move );
return
!canMove( fromPiece ) // moving opponent's piece
|| canMove( toPiece ) // capturing your own piece
|| piece.pieceBetween( move, this ) // moving over pieces
|| piece.isIllegal( move, this ) // piece rules: castling, check, promotion.
|| resultsInCheck( move, piece ); // moving into check
}
/** apply a Move to the Game -- in other words, to the board and to the game.
*
* @return the index of the captured piece, if any (special case for ep).
* @param sq the Move to apply.
*/
public byte applyMove( Move move ) {
Piece piece = getPiece( move.source ); // get the Piece from the Board.
if (piece.isIrreversible( move, this )) { // Irreversible moves let us clear out the history list.
irreversibleMove();
//history.clear();
} else {
//history.append( this ); // remember this board position
}
byte captured = piece.applyMoveToBoard( move, this );
piece.applyMoveToState( move, this );
//if (getReversibleMoves() > 50 || thirdTime()) isStalemate = true;
return captured;
}
/** Enumeration of every legal move for this Game.
* Don't change the game in the middle of getting the enumeration or this might not work.
* @return a new Enumeration of all legal moves for this game.
*/
public Enumeration enumerateAllLegalMoves() {
return
new Enum.Filtered(
new AcceptLegalMoves(), // filter accepts only legal moves..
new Enum.Compound( // for each legal move for each piece.
new Enum.Mapped(
new MakePieceMoveEnumerator(), // map Pieces to a list of moves for that Piece.
new Enum.Filtered(
new AcceptOnTheMove(), // filter accepts only pieces that are on-the move
new Move().getEnumeration() // for each square on the board,
)
)
)
);
}
/** An enumeration of all Moves for the piece in the Move. */
class PieceMoveEnumerator extends Enum.Lookahead {
/** The Piece that's doing the moving. */
public final Piece piece;
/** The Move that's being enumerated. */
public final Move move;
/** Create the iterator starting with a Move. */
public PieceMoveEnumerator( Move move ) {
this.move = move;
this.piece = getPiece( move ); // get the Piece for this move.
next = move;
piece.firstMoveIndex( move );
}
/** Retrieve the next move (legal or not!)
* @see com.editev.util.Enum.Lookahead. */
protected void next() { next = piece.incrementMoveIndex( move ) ? move : null; }
}
/** Constructs a list of Piece moves from a Square. */
class MakePieceMoveEnumerator implements Function {
/** Create a new emumeration of the Pieces
* @return an enumeration of moves for the piece moving.
* @param discard ignore this: we look at the central iterator Move.
*/
public Object eval( Object move ) { return new PieceMoveEnumerator( (Move) move ); }
};
/** A class only accept legal moves. */
class AcceptLegalMoves implements Filter {
/** @param move a move to check for legality.
* @return true if the Move is legal.*/
public boolean accept( Object move ) { return !isIllegal( (Move) move ); }
};
/** Only accepts Squares containing pieces that are on-the-move. */
class AcceptOnTheMove implements Filter {
/** @param move a move which might have a Piece.
*
* @return true if the source of the Move contains a Piece and that Piece is on-the-move.
*/
public boolean accept( Object move ) {
byte piece = getPieceIndex( (Move) move );
return piece != NO_PIECE && isWhiteMove() == White.is( piece );
}
}
/** Is this board position appearing for the third time? */
/*
public boolean thirdTime() {
boolean first=false;
for (int i=history.getLength()-1; i>=0; i--) {
if (history.getAt( i ).equals( this )) {
if (first) return true; // found the second dupe of this board.
first = true; // found the first dupe.
}
}
return false;
}
*/
}