// changed June 15, 1999 by RL // remove reference to Board (space,mflag) // replaced with Board (Space, SetSpace, Flag, ang SetFlag) // changed June 16, 1999 by RL // change reference to from_row, from_col, to_row, to_col as methods // change constructors for Move definitions /** A simple move that just moves a piece from a source location to a destination location, possibly with a capture. */ class SimpleMove extends Move { // Piece that was previously at the destination. private int saved_piece; private int epsq; // Save the contents of the move flag for the source and destination // positions. boolean to_flag, from_flag; /** Construct a move that moves the piece from f_row, f_col to t_row, t_col */ SimpleMove(Board b, int f_row, int f_col, int t_row, int t_col ) { super(b, f_row, f_col, t_row, t_col); } /** Move a piece from the from position to the to position */ public void apply( Board b ) { // Make a copy of the target piece. saved_piece = b.Space(to_row(),to_col()); epsq = b.getEPsq(); b.setEPsq(0); if (piece() == Board.B_PAWN || piece() == Board.R_PAWN) { if (from_row()+2 == to_row()) b.setEPsq(((from_row()+1) << 3) | from_col()); else if (from_row()-2 == to_row()) b.setEPsq(((from_row()-1) << 3) | from_col()); } // Make copies of the source and destination move flags. to_flag = b.Flag(to_row(), to_col()); from_flag = b.Flag(from_row(), from_col()); // Flag these two spaces as having been moved. b.SetFlag(to_row(), to_col(), true); b.SetFlag(from_row(), from_col(), true); // Make a copy of the piece in the to position b.SetSpace(to_row(), to_col(), b.Space(from_row(), from_col())); // Empty the from position b.SetSpace(from_row(), from_col(), Board.EMPTY); // Added June 17, 1999 by RL if (!b.thinking()) display(); // Added June 23, 1999 by RL b.GameHistory(pvCode()); } /** Erase the mark from the space at row/col. */ public void undo( Board b ) { // Added June 23, 1999 by RL b.GameHistory(-1); // Restore the source and destination move flags b.SetFlag(to_row(), to_col(), to_flag); b.SetFlag(from_row(), from_col(), from_flag); // Put a copy of the piece in the back in the from position b.SetSpace(from_row(), from_col(), b.Space(to_row(), to_col())); // Empty the to position b.SetSpace(to_row(), to_col(), saved_piece); b.setEPsq(epsq); } } // change June 17, 1999 by RL // changed to handle promotion to other pieces /** A special move that moves a pawn and promotes it to a queen at the same time. This code assumes that the pawn is stored as a value of 1. */ class PromoteMove extends Move { // Piece that was previously at the destination. private int saved_piece; private int epsq; // Save the contents of the move flag for the source and destination // positions. boolean to_flag, from_flag; /** Construct a move that moves the piece from f_row, f_col to t_row, t_col */ PromoteMove(Board b, int f_row, int f_col, int t_row, int t_col ) { super(b, f_row, f_col, t_row, t_col, b.Space(f_row, f_col) * Board.B_QUEEN); } // Added June 17, 1999 by RL /** Construct a move that moves the piece from f_row, f_col to t_row, t_col and promoted to a p_promote */ PromoteMove(Board b, int f_row, int f_col, int t_row, int t_col, int p_promote ) { super(b, f_row, f_col, t_row, t_col, p_promote); } /** Move a piece from the from position to the to position */ public void apply( Board b ) { // Make a copy of the saved piece. saved_piece = b.Space(to_row(), to_col()); epsq = b.getEPsq(); b.setEPsq(0); // Make copies of the source and destination move flags. to_flag = b.Flag(to_row(), to_col()); from_flag = b.Flag(from_row(), from_col()); // Flag these two spaces as having been moved. b.SetFlag(to_row(), to_col(), true); b.SetFlag(from_row(), from_col(), true); // Make a copy of the piece in the to position b.SetSpace(to_row(), to_col(), promote()); // Empty the from position b.SetSpace(from_row(), from_col(), Board.EMPTY); // Added June 17, 1999 by RL if (!b.thinking()) display(); // Added June 23, 1999 by RL b.GameHistory(pvCode()); } /** Erase the mark from the space at row/col. */ public void undo( Board b ) { // Added June 23, 1999 by RL b.GameHistory(-1); // Put a copy of the piece in the back in the from position b.SetSpace(from_row(), from_col(), piece()); // Restore the source and destination move flags b.SetFlag(to_row(), to_col(), to_flag); b.SetFlag(from_row(), from_col(), from_flag); // Empty the to position b.SetSpace(to_row(), to_col(), saved_piece); b.setEPsq(epsq); } } /** A CastleMove performs the castle operation between a king and the rook at the other end of the move. */ class CastleMove extends Move { int epsq; /** Construct a move that moves the piece from f_row, f_col to t_row, t_col */ CastleMove(Board b, int f_row, int f_col, int t_row, int t_col ) { super(b, f_row, f_col, t_row, t_col); } /** Move a piece from the from position to the to position */ public void apply( Board b ) { epsq = b.getEPsq(); b.setEPsq(0); if( to_col() < from_col() ){ b.SetSpace(to_row(), from_col() - 2, b.Space(from_row(), from_col())); b.SetSpace(to_row(), from_col() - 1, b.Space(to_row(), 0)); // Original position of rook made empty. b.SetSpace(to_row(), 0, Board.EMPTY); // Flag rook space as having been moved. b.SetFlag(to_row(), 0, true); } else { b.SetSpace(to_row(), from_col() + 2, b.Space(from_row(), from_col())); b.SetSpace(to_row(), from_col() + 1, b.Space(to_row(), Board.WIDTH-1)); // Original position of rook made empty. b.SetSpace(to_row(), Board.WIDTH-1, Board.EMPTY); // Flag rook space as having been moved. b.SetFlag(to_row(), Board.WIDTH-1, true); } // Original position king made empty. b.SetSpace(from_row(), from_col(), Board.EMPTY); // Flag king space as having been moved. b.SetFlag(from_row(), from_col(), true); // Added June 17, 1999 by RL if (!b.thinking()) display(); // Added June 23, 1999 by RL b.GameHistory(pvCode()); } /** Erase the mark from the space at row/col. */ public void undo( Board b ) { // Added June 23, 1999 by RL b.GameHistory(-1); // Restore the positions of the king and the rook. if( to_col() < from_col() ){ b.SetSpace(to_row(), 0, b.Space(to_row(), from_col() - 1)); b.SetSpace(from_row(), from_col(), b.Space(to_row(), from_col() - 2)); b.SetSpace(to_row(), from_col() - 2, Board.EMPTY); b.SetSpace(to_row(), from_col() - 1, Board.EMPTY); // Restore the move flags for rook space b.SetFlag(to_row(), 0, false); } else { b.SetSpace(to_row(), Board.WIDTH-1, b.Space(to_row(), from_col() + 1)); b.SetSpace(from_row(), from_col(), b.Space(to_row() ,from_col() + 2)); b.SetSpace(to_row(), from_col() + 2, Board.EMPTY); b.SetSpace(to_row(), from_col() + 1, Board.EMPTY); // Restore the move flags for rook space b.SetFlag(to_row(), Board.WIDTH-1, false); } // Restore the move flags for king space b.SetFlag(from_row(), from_col(), false); b.setEPsq(epsq); } // Added June 16, 1999 by RL /** Return the captured piece. */ public int captured() { return 0; } // Added June 17, 1999 by RL /** Make a string presentation of a Move. */ public String string() { if( to_col() < from_col() ) return "O-O-O"; else return "O-O"; } } /** A EPMove performs the en passant capture of pawn. */ class EPMove extends Move { int saved_piece; int epsq; boolean from_flag, to_flag; /** Construct a move that moves the piece from f_row, f_col to t_row, t_col */ EPMove(Board b, int f_row, int f_col, int t_row, int t_col ) { super(b, f_row, f_col, t_row, t_col); epsq = b.getEPsq(); } /** Move a piece from the from position to the to position */ public void apply( Board b ) { epsq = b.getEPsq(); b.setEPsq(0); saved_piece = b.Space(from_row(), epsq & 07); b.SetSpace(from_row(), epsq & 07 , Board.EMPTY); b.SetSpace(to_row(), to_col() , piece()); b.SetSpace(from_row(), from_col() , Board.EMPTY); // Flag these two spaces as having been moved. from_flag = b.Flag(from_row(), from_col()); to_flag = b.Flag(to_row(), to_col()); b.SetFlag(from_row(), from_col(), true); b.SetFlag(to_row(), to_col(), true); // Added June 17, 1999 by RL if (!b.thinking()) display(); // Added June 23, 1999 by RL b.GameHistory(pvCode()); } /** Erase the mark from the space at row/col. */ public void undo( Board b ) { // Added June 23, 1999 by RL b.GameHistory(-1); b.SetSpace(from_row(), from_col() , piece()); b.SetSpace(to_row(), to_col() , Board.EMPTY); b.SetSpace(from_row(), epsq & 07 , saved_piece); // Restore the move flags for these two spaces b.SetFlag(from_row(), from_col(), from_flag); b.SetFlag(to_row(), to_col(), to_flag); b.setEPsq(epsq); } } /** A fancy move generator that knows how to move every piece in chess. */ public class ChessGenerator extends Generator { // Generate all possible moves for the checker at position // row, col. Add these moves to the front of move_list and return // the result. private Move movePawn( Move move_list, Board b, int side, int row, int col ) { // Pawns always move in the same direction, fortunately, // the side constant gives us the right direction. if( row + side >= 0 && row + side < Board.HEIGHT ){ if( b.Space(row + side, col) == Board.EMPTY ){ Move m; // See if we get to promote the pawn if( row + side == 0 || row + side == Board.HEIGHT - 1 ) m = new PromoteMove( b, row, col, row + side, col ); else m = new SimpleMove( b, row, col, row + side, col ); m.next = move_list; move_list = m; // See if this is the pawn's first move or some later move. if( ( side == Board.B_SIDE && row == 1 ) || ( side == Board.R_SIDE && row == 6 ) ) if( b.Space(row + side * 2, col) == Board.EMPTY ){ // Record the new move and link it into the move_list m = new SimpleMove( b, row, col, row + side * 2, col ); m.next = move_list; move_list = m; } } // Consider capture moves // First, to the left. if( col > 0 && b.Space(row + side, col - 1) * side < 0 ){ Move m; // See if we get to promote the pawn if( row + side == 0 || row + side == Board.HEIGHT - 1 ) m = new PromoteMove( b, row, col, row + side, col - 1 ); else m = new SimpleMove( b, row, col, row + side, col - 1 ); m.next = move_list; move_list = m; } // Then to the right if( col + 1 < Board.WIDTH && b.Space(row + side, col + 1) * side < 0 ){ // Record the new move and link it into the move_list Move m; // See if we get to promote the pawn if( row + side == 0 || row + side == Board.HEIGHT - 1 ) m = new PromoteMove( b, row, col, row + side, col + 1 ); else m = new SimpleMove( b, row, col, row + side, col + 1 ); m.next = move_list; move_list = m; } // e.p capture int epsq = b.getEPsq(); if ( epsq > 0 && col + 1 < Board.WIDTH && epsq == ( ((row+side) << 3) | (col + 1) ) ) { Move m = new EPMove( b, row, col, row + side, col + 1 ); m.next = move_list; move_list = m; } else if ( epsq > 0 && col > 0 && epsq == ( ((row+side) << 3) | (col - 1) ) ) { Move m = new EPMove( b, row, col, row + side, col - 1 ); m.next = move_list; move_list = m; } } return move_list; } private Move moveKnight( Move move_list, Board b, int side, int row, int col ) { if( row > 0 ){ // See if the destination space is empty or has an enemy piece. if( col - 2 >= 0 && b.Space( row - 1, col - 2) * side <= 0 ){ Move m = new SimpleMove( b, row, col, row - 1, col - 2 ); m.next = move_list; move_list = m; } // See if the destination space is empty or has an enemy piece. if( col + 2 < Board.WIDTH && b.Space( row - 1, col + 2) * side <= 0 ){ Move m = new SimpleMove( b, row, col, row - 1, col + 2 ); m.next = move_list; move_list = m; } if( row - 1 > 0 ){ // See if the destination space is empty or has an enemy piece. if( col > 0 && b.Space(row - 2, col - 1) * side <= 0 ){ Move m = new SimpleMove( b, row, col, row - 2, col - 1 ); m.next = move_list; move_list = m; } // See if the destination space is empty or has an enemy piece. if( col + 1 < Board.WIDTH && b.Space(row - 2, col + 1) * side <= 0 ){ Move m = new SimpleMove( b, row, col, row - 2, col + 1 ); m.next = move_list; move_list = m; } } } if( row + 1 < Board.HEIGHT ){ // See if the destination space is empty or has an enemy piece. if( col - 2 >= 0 && b.Space(row + 1, col - 2) * side <= 0 ){ Move m = new SimpleMove( b, row, col, row + 1, col - 2 ); m.next = move_list; move_list = m; } // See if the destination space is empty or has an enemy piece. if( col + 2 < Board.WIDTH && b.Space(row + 1 ,col + 2) * side <= 0 ){ Move m = new SimpleMove( b, row, col, row + 1, col + 2 ); m.next = move_list; move_list = m; } if( row + 2 < Board.HEIGHT ){ // See if the destination space is empty or has an enemy piece. if( col > 0 && b.Space(row + 2, col - 1) * side <= 0 ){ Move m = new SimpleMove( b, row, col, row + 2, col - 1 ); m.next = move_list; move_list = m; } // See if the destination space is empty or has an enemy piece. if( col + 1 < Board.WIDTH && b.Space(row + 2, col + 1) * side <= 0 ){ Move m = new SimpleMove( b, row, col, row + 2, col + 1 ); m.next = move_list; move_list = m; } } } return move_list; } // Generate the moves for the king. This is a little // tricky since the king can castle. private Move moveKing( Move move_list, Board b, int side, int row, int col ) { // Move straight up or diagonal if( row > 0 ){ if( b.Space( row - 1, col) * side <= 0 ){ Move m = new SimpleMove( b, row, col, row - 1, col ); m.next = move_list; move_list = m; } if( col > 0 && b.Space(row - 1 ,col - 1) * side <= 0 ){ Move m = new SimpleMove( b, row, col, row - 1, col - 1 ); m.next = move_list; move_list = m; } if( col + 1 < Board.WIDTH && b.Space(row - 1, col + 1) * side <= 0 ){ Move m = new SimpleMove( b, row, col, row - 1, col + 1 ); m.next = move_list; move_list = m; } } // Move straight down or diagonal if( row + 1 < Board.HEIGHT ){ if( b.Space(row + 1, col) * side <= 0 ){ Move m = new SimpleMove( b, row, col, row + 1, col ); m.next = move_list; move_list = m; } if( col > 0 && b.Space( row + 1 , col - 1 ) * side <= 0 ){ Move m = new SimpleMove( b, row, col, row + 1, col - 1 ); m.next = move_list; move_list = m; } if( col + 1 < Board.WIDTH && b.Space( row + 1 , col + 1 ) * side <= 0 ){ Move m = new SimpleMove( b, row, col, row + 1, col + 1 ); m.next = move_list; move_list = m; } } // Move left or right if( col > 0 && b.Space( row , col - 1 ) * side <= 0 ){ Move m = new SimpleMove( b, row, col, row, col - 1 ); m.next = move_list; move_list = m; } if( col + 1 < Board.WIDTH && b.Space( row , col + 1 ) * side <= 0 ){ Move m = new SimpleMove( b, row, col, row, col + 1 ); m.next = move_list; move_list = m; } // Detect legal castle moves. if( b.Flag( row , col ) == false ){ // See if we can castle to the left if( b.Flag( row , 0 ) == false ){ // Make sure the path between the king and the rook is vacant. boolean vacant = true; for( int i = col - 1; i != 0; i-- ) if( b.Space( row , i ) != Board.EMPTY ) vacant = false; if( vacant ){ // Now, the really expensive check. Make sure none of the // spaces on the way is threatened. for( int i = col; i != col - 3 && vacant; i-- ) if( threatened( b, side, row, i ) ) vacant = false; if( vacant ){ // Move m = new CastleMove( b, row, col, row, 0 ); Move m = new CastleMove( b, row, col, row, col-2 ); m.next = move_list; move_list = m; } } } // See if we can castle to the right if( b.Flag( row , Board.WIDTH - 1 ) == false ){ // Make sure the path between the king and the rook is vacant. boolean vacant = true; for( int i = col + 1; i != Board.WIDTH - 1; i++ ) if( b.Space( row , i ) != Board.EMPTY ) vacant = false; if( vacant ){ // Now, the really expensive check. Make sure none of the // spaces on the way is threatened. for( int i = col; i != col + 3 && vacant; i++ ) if( threatened( b, side, row, i ) ) vacant = false; if( vacant ){ // Move m = new CastleMove( b, row, col, row, Board.WIDTH - 1 ); Move m = new CastleMove( b, row, col, row, col+2 ); m.next = move_list; move_list = m; } } } } return move_list; } // Utility function for pieces that can move diagonally. // Concatenate moves onto the given move_list. protected Move moveDiagonal( Move move_list, Board b, int side, int row, int col ) { //left-up boolean NoPiece = true; int tmpcol = -1; int tmprow = -1; while (col + tmpcol >= 0 && row + tmprow >= 0 && NoPiece) { if (b.Space(row+tmprow,col+tmpcol) == 0) { Move m = new SimpleMove( b, row, col, row+tmprow, col+tmpcol); m.next = move_list; move_list = m; tmpcol--; tmprow--; } else { if (b.Space(row+tmprow,col+tmpcol) * side < 0) { Move m = new SimpleMove( b, row, col, row+tmprow, col+tmpcol); m.next = move_list; move_list = m; } NoPiece = false; } } //right-up NoPiece = true; tmpcol = 1; tmprow = -1; while (col + tmpcol <= 7 && row + tmprow >= 0 && NoPiece) { if (b.Space(row+tmprow,col+tmpcol) == 0) { Move m = new SimpleMove( b, row, col, row+tmprow, col+tmpcol); m.next = move_list; move_list = m; tmpcol++; tmprow--; } else { if (b.Space(row+tmprow,col+tmpcol) * side < 0) { Move m = new SimpleMove( b, row, col, row+tmprow, col+tmpcol); m.next = move_list; move_list = m; } NoPiece = false; } } //right-down NoPiece = true; tmpcol = 1; tmprow = 1; while (col + tmpcol <= 7 && row + tmprow <= 7 && NoPiece) { if (b.Space(row+tmprow,col+tmpcol) == 0) { Move m = new SimpleMove( b, row, col, row+tmprow, col+tmpcol); m.next = move_list; move_list = m; tmpcol++; tmprow++; } else { if (b.Space(row+tmprow,col+tmpcol) * side < 0) { Move m = new SimpleMove( b, row, col, row+tmprow, col+tmpcol); m.next = move_list; move_list = m; } NoPiece = false; } } //left-down NoPiece = true; tmpcol = -1; tmprow = 1; while (col + tmpcol >= 0 && row + tmprow <= 7 && NoPiece) { if (b.Space(row+tmprow,col+tmpcol) == 0) { Move m = new SimpleMove( b, row, col, row+tmprow, col+tmpcol); m.next = move_list; move_list = m; tmpcol--; tmprow++; } else { if (b.Space(row+tmprow,col+tmpcol) * side < 0) { Move m = new SimpleMove( b, row, col, row+tmprow, col+tmpcol); m.next = move_list; move_list = m; } NoPiece = false; } } return move_list; } // Utility function for pieces that move in rows or columns // Insert moves into move_list protected Move moveRectangular( Move move_list, Board b, int side, int row, int col ) { boolean NoPiece = true; //left int tmpcol = -1; while (col + tmpcol >= 0 && NoPiece) { if(b.Space(row,col+tmpcol) == 0) { Move m = new SimpleMove( b, row, col, row, col+tmpcol); m.next = move_list; move_list = m; tmpcol--; } else { if(b.Space(row,col+tmpcol) * side < 0) { Move m = new SimpleMove( b, row, col, row, col+tmpcol); m.next = move_list; move_list = m; } NoPiece = false; } } //up NoPiece = true; int tmprow = -1; while (row + tmprow >= 0 && NoPiece) { if(b.Space(row+tmprow,col) == 0) { Move m = new SimpleMove( b, row, col, row+tmprow, col); m.next = move_list; move_list = m; tmprow--; } else { if(b.Space(row+tmprow,col) * side < 0) { Move m = new SimpleMove( b, row, col, row+tmprow, col); m.next = move_list; move_list = m; } NoPiece = false; } } //right NoPiece = true; tmpcol = 1; while (col + tmpcol <= 7 && NoPiece) { if(b.Space(row,col+tmpcol) == 0) { Move m = new SimpleMove( b, row, col, row, col+tmpcol); m.next = move_list; move_list = m; tmpcol++; } else { if(b.Space(row,col+tmpcol) * side < 0) { Move m = new SimpleMove( b, row, col, row, col+tmpcol); m.next = move_list; move_list = m; } NoPiece = false; } } //down NoPiece = true; tmprow = 1; while (row + tmprow <= 7 && NoPiece) { if(b.Space(row+tmprow,col) == 0) { Move m = new SimpleMove( b, row, col, row+tmprow, col); m.next = move_list; move_list = m; tmprow++; } else { if(b.Space(row+tmprow,col) * side < 0) { Move m = new SimpleMove( b, row, col, row+tmprow, col); m.next = move_list; move_list = m; } NoPiece = false; } } return move_list; } // Return true if the given side is threatened (i.e. could a // piece at that space be captured. This function is a bit // of a hack, but it should work for all of the standard pieces // in chess. private boolean threatened( Board b, int side, int row, int col ) { Move move_list; Move m; // This tries each possible threat backward from the row, col // space. Then it checks to see if there is the right kind // of piece at the to position to make that move back to the row, col // space. move_list = movePawn( null, b, side, row, col ); for( m = move_list; m != null; m = m.next ) if( b.Space( m.to_row() , m.to_col() ) * side == Board.R_PAWN ) return true; move_list = moveRectangular( null, b, side, row, col ); for( m = move_list; m != null; m = m.next ) if( b.Space( m.to_row() , m.to_col() ) * side == Board.R_ROOK || b.Space( m.to_row() , m.to_col() ) * side == Board.R_QUEEN ) return true; move_list = moveDiagonal( null, b, side, row, col ); for( m = move_list; m != null; m = m.next ) if( b.Space( m.to_row() , m.to_col() ) * side == Board.R_BISHOP || b.Space( m.to_row() , m.to_col() ) * side == Board.R_QUEEN ) return true; move_list = moveKnight( null, b, side, row, col ); for( m = move_list; m != null; m = m.next ) if( b.Space( m.to_row() , m.to_col() ) * side == Board.R_KNIGHT ) return true; // Temporarily set the moved flag so we don't try to castle from // inside this function boolean saved_flag = b.Flag( row , col ); b.SetFlag( row , col , true); move_list = moveKing( null, b, side, row, col ); for( m = move_list; m != null; m = m.next ) if( b.Space( m.to_row() , m.to_col() ) * side == Board.R_KING ){ b.SetFlag( row , col , saved_flag); return true; } b.SetFlag( row , col , saved_flag); return false; } public Move generateMoves( Board b, int side ) { // Start out with an empty move list. Move move_list = null; // Check every space on the board. for( int row = 0; row < Board.HEIGHT; row++ ) for( int col = 0; col < Board.WIDTH; col++ ){ // See if this space contains a pawn for the given side. if( b.Space( row , col ) == Board.B_PAWN * side ) move_list = movePawn( move_list, b, side, row, col ); // See if this space contains a rook for the given side. if( b.Space( row , col ) == Board.B_ROOK * side ) move_list = moveRectangular( move_list, b, side, row, col ); if( b.Space( row , col ) == Board.B_KNIGHT * side ) move_list = moveKnight( move_list, b, side, row, col ); if( b.Space( row , col ) == Board.B_BISHOP * side ) move_list = moveDiagonal( move_list, b, side, row, col ); if( b.Space( row , col ) == Board.B_QUEEN * side ){ // Queens move like rooks and like bishops move_list = moveDiagonal( move_list, b, side, row, col ); move_list = moveRectangular( move_list, b, side, row, col ); } if( b.Space( row , col ) == Board.B_KING * side ) move_list = moveKing( move_list, b, side, row, col ); } return move_list; } }