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; } */ }