Exemple #1
0
        // Loading the table from a file
        public bool Load(string fileName)
        {
            // Open the file as a Java tokenizer
            using (var sr = new StreamReader(fileName))
            {
                // Create a game board on which to "play" the opening sequences stored in
                // the book, so that we know which position to associate with which move
                jcBoard board = new jcBoard();
                jcMove mov = new jcMove();
                jcMoveListGenerator successors = new jcMoveListGenerator();

                // How many lines of play do we have in the book?
                var lines = File.ReadAllLines(fileName);
                int numLines = lines.Length;

                for (int wak = 0; wak < numLines; wak++)
                {
                    // Begin the line of play with a clean board
                    board.StartingBoard();

                    // Load the continuation
                    var lineNums = lines[wak].Split(' ');
                    for (int i = 0; i < lineNums.Length; i++)
                    {
                        if (lineNums[i] == "END")
                            break;
                        successors.ComputeLegalMoves(board);

                        var source = Convert.ToInt32(lineNums[i]);
                        var destination = Convert.ToInt32(lineNums[i + 1]);
                        i++;

                        mov = successors.FindMoveForSquares(source, destination);
                        StoreMove(board, mov);
                        board.ApplyMove(mov);

                    }
                }

            }
            return true;
        }
Exemple #2
0
 // Construction
 public jcOpeningBookEntry()
 {
     theLock = 0;
     WhiteMove = new jcMove();
     WhiteMove.MoveType = NO_MOVE;
     BlackMove = new jcMove();
     BlackMove.MoveType = NO_MOVE;
 }
Exemple #3
0
        private bool StoreMove(jcBoard theBoard, jcMove theMove)
        {
            // Where should we store this data?
            int key = Math.Abs(theBoard.HashKey() % TABLE_SIZE);
            int hashLock = theBoard.HashLock();

            // Is there already an entry for a different board position where we
            // want to put this?  If so, mark it deleted
            if (Table[key].theLock != hashLock)
            {
                Table[key].BlackMove.MoveType = jcOpeningBookEntry.NO_MOVE;
                Table[key].WhiteMove.MoveType = jcOpeningBookEntry.NO_MOVE;
            }

            // And store the new move
            Table[key].theLock = hashLock;
            if (theBoard.GetCurrentPlayer() == jcPlayer.SIDE_BLACK)
            {
                Table[key].BlackMove.Copy(theMove);
            }
            else
            {
                Table[key].WhiteMove.Copy(theMove);
            }

            return true;
        }
Exemple #4
0
        // public jcMove GetMove( theBoard )
        // Getting a move from the human player.  Sorry, but this is very, very
        // primitive: you need to enter square numbers instead of piece ID's, and
        // both square numbers must be entered with two digits.  Ex.: 04 00
        public override jcMove GetMove(jcBoard theBoard)
        {
            // Read the move from the command line
            bool ok = false;
            jcMove Mov = new jcMove();
            do {
                Console.WriteLine("Your move, " + PlayerStrings[this.GetSide()] + "?");

                // Get data from the command line
                string line = null;
                do {
                    try {
                        line = Console.ReadLine();
                    } catch(Exception) { }
                } while(line.Length < 3);

                if(line.ToUpper().Equals("RESIG")) {
                    Mov.MoveType = jcMove.MOVE_RESIGN;
                    return (Mov);
                }

                // Extract the source and destination squares from the line buffer
                Mov.SourceSquare = Convert.ToInt32(line.Substring(0, 2));
                Mov.DestinationSquare = Convert.ToInt32(line.Substring(3, 2));
                if((Mov.SourceSquare < 0) || (Mov.SourceSquare > 63)) {
                    Console.WriteLine("Sorry, illegal source square " + Mov.SourceSquare);
                    continue;
                }
                if((Mov.DestinationSquare < 0) || (Mov.DestinationSquare > 63)) {
                    Console.WriteLine("Sorry, illegal destination square " + Mov.DestinationSquare);
                    continue;
                }

                // Time to try to figure out what the move means!
                if(theBoard.GetCurrentPlayer() == jcPlayer.SIDE_WHITE) {
                    // Is there a piece (of the moving player) on SourceSquare?
                    // If not, abort
                    Mov.MovingPiece = theBoard.FindWhitePiece(Mov.SourceSquare);
                    if(Mov.MovingPiece == jcBoard.EMPTY_SQUARE) {
                        Console.WriteLine("Sorry, You don't have a piece at square " + Mov.SourceSquare);
                        continue;
                    }

                    // Three cases: there is a piece on the destination square (a capture),
                    // the destination square allows an en passant capture, or it is a
                    // simple non-capture move.  If the destination contains a piece of the
                    // moving side, abort
                    if(theBoard.FindWhitePiece(Mov.DestinationSquare) != jcBoard.EMPTY_SQUARE) {
                        Console.WriteLine("Sorry, can't capture your own piece!");
                        continue;
                    }
                    Mov.CapturedPiece = theBoard.FindBlackPiece(Mov.DestinationSquare);
                    if(Mov.CapturedPiece != jcBoard.EMPTY_SQUARE)
                        Mov.MoveType = jcMove.MOVE_CAPTURE_ORDINARY;
                    else if((theBoard.GetEnPassantPawn() == (1 << Mov.DestinationSquare)) &&
                              (Mov.MovingPiece == jcBoard.WHITE_PAWN)) {
                        Mov.CapturedPiece = jcBoard.BLACK_PAWN;
                        Mov.MoveType = jcMove.MOVE_CAPTURE_EN_PASSANT;
                    }

                    // If the move isn't a capture, it may be a castling attempt
                    else if((Mov.MovingPiece == jcBoard.WHITE_KING) &&
                              ((Mov.SourceSquare - Mov.DestinationSquare) == 2))
                        Mov.MoveType = jcMove.MOVE_CASTLING_KINGSIDE;
                    else if((Mov.MovingPiece == jcBoard.WHITE_KING) &&
                              ((Mov.SourceSquare - Mov.DestinationSquare) == -2))
                        Mov.MoveType = jcMove.MOVE_CASTLING_QUEENSIDE;
                    else
                        Mov.MoveType = jcMove.MOVE_NORMAL;
                } else {
                    Mov.MovingPiece = theBoard.FindBlackPiece(Mov.SourceSquare);
                    if(Mov.MovingPiece == jcBoard.EMPTY_SQUARE) {
                        Console.WriteLine("Sorry, you don't have a piece in square " + Mov.SourceSquare);
                        continue;
                    }

                    if(theBoard.FindBlackPiece(Mov.DestinationSquare) != jcBoard.EMPTY_SQUARE) {
                        Console.WriteLine("Sorry, you can't capture your own piece in square " + Mov.DestinationSquare);
                        continue;
                    }
                    Mov.CapturedPiece = theBoard.FindWhitePiece(Mov.DestinationSquare);
                    if(Mov.CapturedPiece != jcBoard.EMPTY_SQUARE)
                        Mov.MoveType = jcMove.MOVE_CAPTURE_ORDINARY;
                    else if((theBoard.GetEnPassantPawn() == (1 << Mov.DestinationSquare)) &&
                              (Mov.MovingPiece == jcBoard.BLACK_PAWN)) {
                        Mov.CapturedPiece = jcBoard.WHITE_PAWN;
                        Mov.MoveType = jcMove.MOVE_CAPTURE_EN_PASSANT;
                    } else if((Mov.MovingPiece == jcBoard.BLACK_KING) &&
                                ((Mov.SourceSquare - Mov.DestinationSquare) == 2))
                        Mov.MoveType = jcMove.MOVE_CASTLING_KINGSIDE;
                    else if((Mov.MovingPiece == jcBoard.BLACK_KING) &&
                              ((Mov.SourceSquare - Mov.DestinationSquare) == -2))
                        Mov.MoveType = jcMove.MOVE_CASTLING_QUEENSIDE;
                    else
                        Mov.MoveType = jcMove.MOVE_NORMAL;
                }

                // Now, if the move results in a pawn promotion, we must ask the user
                // for the type of promotion!
                if(((Mov.MovingPiece == jcBoard.WHITE_PAWN) && (Mov.DestinationSquare < 8)) ||
                     ((Mov.MovingPiece == jcBoard.BLACK_PAWN) && (Mov.DestinationSquare > 55))) {
                    int car = -1;
                    Console.WriteLine("Promote the pawn to [K]night, [R]ook, [B]ishop, [Q]ueen?");
                    do {
                        try { car = Console.Read(); } catch(Exception) { }
                    } while((car != 'K') && (car != 'k') && (car != 'b') && (car != 'B')
                           && (car != 'R') && (car != 'r') && (car != 'Q') && (car != 'q'));
                    if((car == 'K') || (car == 'k'))
                        Mov.MoveType += jcMove.MOVE_PROMOTION_KNIGHT;
                    else if((car == 'B') || (car == 'b'))
                        Mov.MoveType += jcMove.MOVE_PROMOTION_BISHOP;
                    else if((car == 'R') || (car == 'r'))
                        Mov.MoveType += jcMove.MOVE_PROMOTION_ROOK;
                    else
                        Mov.MoveType += jcMove.MOVE_PROMOTION_QUEEN;
                }

                // OK, now let's see if the move is actually legal!  First step: a check
                // for pseudo-legality, i.e., is it a valid successor to the current
                // board?
                Pseudos.ComputeLegalMoves(theBoard);
                if(!Pseudos.Find(Mov)) {
                    Console.Write("Sorry, this move is not in the pseudo-legal list: ");
                    Mov.Print();
                    Pseudos.Print();
                    continue;
                }

                // If pseudo-legal, then verify whether it leaves the king in check
                Successor.Clone(theBoard);
                Successor.ApplyMove(Mov);
                if(!Pseudos.ComputeLegalMoves(Successor)) {
                    Console.Write("Sorry, this move leaves your king in check: ");
                    Mov.Print();
                    continue;
                }

                // If we have made it here, we have a valid move to play!
                Console.WriteLine("Move is accepted...");
                ok = true;

            } while(!ok);

            return (Mov);
        }
Exemple #5
0
        // public bool ApplyMove
        // Change the jcBoard's internal representation to reflect the move
        // received as a parameter
        public bool ApplyMove(jcMove theMove)
        {
            // If the move includes a pawn promotion, an extra step will be required
            // at the end
            bool isPromotion = (theMove.MoveType >= jcMove.MOVE_PROMOTION_KNIGHT);
            int moveWithoutPromotion = (theMove.MoveType & jcMove.NO_PROMOTION_MASK);
            int side = theMove.MovingPiece % 2;

            // For now, ignore pawn promotions
            switch(moveWithoutPromotion) {
                case jcMove.MOVE_NORMAL:
                    // The simple case
                    RemovePiece(theMove.SourceSquare, theMove.MovingPiece);
                    AddPiece(theMove.DestinationSquare, theMove.MovingPiece);
                    break;
                case jcMove.MOVE_CAPTURE_ORDINARY:
                    // Don't forget to remove the captured piece!
                    RemovePiece(theMove.SourceSquare, theMove.MovingPiece);
                    RemovePiece(theMove.DestinationSquare, theMove.CapturedPiece);
                    AddPiece(theMove.DestinationSquare, theMove.MovingPiece);
                    break;
                case jcMove.MOVE_CAPTURE_EN_PASSANT:
                    // Here, we can use our knowledge of the board to make a small
                    // optimization, since the pawn to be captured is always
                    // "behind" the moving pawn's destination square, we can compute its
                    // position on the fly
                    RemovePiece(theMove.SourceSquare, theMove.MovingPiece);
                    AddPiece(theMove.DestinationSquare, theMove.MovingPiece);
                    if((theMove.MovingPiece % 2) == jcPlayer.SIDE_WHITE)
                        RemovePiece(theMove.DestinationSquare + 8, theMove.CapturedPiece);
                    else
                        RemovePiece(theMove.DestinationSquare - 8, theMove.CapturedPiece);
                    break;
                case jcMove.MOVE_CASTLING_QUEENSIDE:
                    // Again, we can compute the rook's source and destination squares
                    // because of our knowledge of the board's structure
                    RemovePiece(theMove.SourceSquare, theMove.MovingPiece);
                    AddPiece(theMove.DestinationSquare, theMove.MovingPiece);
                    int theRook = ROOK + (theMove.MovingPiece % 2);
                    RemovePiece(theMove.SourceSquare - 4, theRook);
                    AddPiece(theMove.SourceSquare - 1, theRook);
                    // We must now mark some squares as containing "phantom kings" so that
                    // the castling can be cancelled by the next opponent's move, if he
                    // can move to one of them
                    if(side == jcPlayer.SIDE_WHITE) {
                        SetExtraKings(side, EXTRAKINGS_WHITE_QUEENSIDE);
                    } else {
                        SetExtraKings(side, EXTRAKINGS_BLACK_QUEENSIDE);
                    }
                    HasCastled[side] = true;
                    break;
                case jcMove.MOVE_CASTLING_KINGSIDE:
                    // Again, we can compute the rook's source and destination squares
                    // because of our knowledge of the board's structure
                    RemovePiece(theMove.SourceSquare, theMove.MovingPiece);
                    AddPiece(theMove.DestinationSquare, theMove.MovingPiece);
                    theRook = ROOK + (theMove.MovingPiece % 2);
                    RemovePiece(theMove.SourceSquare + 3, theRook);
                    AddPiece(theMove.SourceSquare + 1, theRook);
                    // We must now mark some squares as containing "phantom kings" so that
                    // the castling can be cancelled by the next opponent's move, if he
                    // can move to one of them
                    if(side == jcPlayer.SIDE_WHITE) {
                        SetExtraKings(side, EXTRAKINGS_WHITE_KINGSIDE);
                    } else {
                        SetExtraKings(side, EXTRAKINGS_BLACK_KINGSIDE);
                    }
                    HasCastled[side] = true;
                    break;
                case jcMove.MOVE_RESIGN:
                    // FDL Later, ask the AI player who resigned to print the continuation
                    break;
                case jcMove.MOVE_STALEMATE:
                    Console.WriteLine("Stalemate - Game is a draw.");
                    break;
            }

            // And now, apply the promotion
            if(isPromotion) {
                int promotionType = (theMove.MoveType & jcMove.PROMOTION_MASK);
                int color = (theMove.MovingPiece % 2);
                switch(promotionType) {
                    case jcMove.MOVE_PROMOTION_KNIGHT:
                        RemovePiece(theMove.DestinationSquare, theMove.MovingPiece);
                        AddPiece(theMove.DestinationSquare, KNIGHT + color);
                        break;
                    case jcMove.MOVE_PROMOTION_BISHOP:
                        RemovePiece(theMove.DestinationSquare, theMove.MovingPiece);
                        AddPiece(theMove.DestinationSquare, BISHOP + color);
                        break;
                    case jcMove.MOVE_PROMOTION_ROOK:
                        RemovePiece(theMove.DestinationSquare, theMove.MovingPiece);
                        AddPiece(theMove.DestinationSquare, ROOK + color);
                        break;
                    case jcMove.MOVE_PROMOTION_QUEEN:
                        RemovePiece(theMove.DestinationSquare, theMove.MovingPiece);
                        AddPiece(theMove.DestinationSquare, QUEEN + color);
                        break;
                }
            }

            // If this was a 2-step pawn move, we now have a valid en passant
            // capture possibility.  Otherwise, no.
            if((theMove.MovingPiece == jcBoard.WHITE_PAWN) &&
                 (theMove.SourceSquare - theMove.DestinationSquare == 16))
                SetEnPassantPawn(theMove.DestinationSquare + 8);
            else if((theMove.MovingPiece == jcBoard.BLACK_PAWN) &&
                      (theMove.DestinationSquare - theMove.SourceSquare == 16))
                SetEnPassantPawn(theMove.SourceSquare + 8);
            else
                ClearEnPassantPawn();

            // And now, maintain castling status
            // If a king moves, castling becomes impossible for that side, for the
            // rest of the game
            switch(theMove.MovingPiece) {
                case WHITE_KING:
                    SetCastlingStatus(CASTLE_KINGSIDE + jcPlayer.SIDE_WHITE, false);
                    SetCastlingStatus(CASTLE_QUEENSIDE + jcPlayer.SIDE_WHITE, false);
                    break;
                case BLACK_KING:
                    SetCastlingStatus(CASTLE_KINGSIDE + jcPlayer.SIDE_BLACK, false);
                    SetCastlingStatus(CASTLE_QUEENSIDE + jcPlayer.SIDE_BLACK, false);
                    break;
                default:
                    break;
            }

            // Or, if ANYTHING moves from a corner, castling becomes impossible on
            // that side (either because it's the rook that is moving, or because
            // it has been captured by whatever moves, or because it is already gone)
            switch(theMove.SourceSquare) {
                case 0:
                    SetCastlingStatus(CASTLE_QUEENSIDE + jcPlayer.SIDE_BLACK, false);
                    break;
                case 7:
                    SetCastlingStatus(CASTLE_KINGSIDE + jcPlayer.SIDE_BLACK, false);
                    break;
                case 56:
                    SetCastlingStatus(CASTLE_QUEENSIDE + jcPlayer.SIDE_WHITE, false);
                    break;
                case 63:
                    SetCastlingStatus(CASTLE_KINGSIDE + jcPlayer.SIDE_WHITE, false);
                    break;
                default:
                    break;
            }

            // All that remains to do is switch sides
            SetCurrentPlayer((GetCurrentPlayer() + 1) % 2);
            return true;
        }
        // private jcMove UnrolledAlphabeta
        // The standard alphabeta, with the top level "unrolled" so that it can
        // return a jcMove structure instead of a mere minimax value
        // See jcAISearchAgent.Alphabeta for detailed comments on this code
        private jcMove UnrolledAlphabeta(jcBoard theBoard, int depth, int alpha, int beta)
        {
            jcMove BestMov = new jcMove();

            jcMoveListGenerator movegen = new jcMoveListGenerator();
            movegen.ComputeLegalMoves(theBoard);
            HistoryTable.SortMoveList(movegen, theBoard.GetCurrentPlayer());

            jcBoard newBoard = new jcBoard();
            int bestSoFar;

            bestSoFar = ALPHABETA_MINVAL;
            int currentAlpha = alpha;
            jcMove mov;

            // Loop on the successors
            while((mov = movegen.Next()) != null) {
                // Compute a board position resulting from the current successor
                newBoard.Clone(theBoard);
                newBoard.ApplyMove(mov);

                // And search it in turn
                int movScore = AlphaBeta(MINNODE, newBoard, depth - 1, currentAlpha, beta);

                // Ignore illegal moves in the alphabeta evaluation
                if(movScore == ALPHABETA_ILLEGAL)
                    continue;
                currentAlpha = Math.Max(currentAlpha, movScore);

                // Is the current successor better than the previous best?
                if(movScore > bestSoFar) {
                    BestMov.Copy(mov);
                    bestSoFar = movScore;
                    BestMov.MoveEvaluation = bestSoFar;

                    // Can we cutoff now?
                    if(bestSoFar >= beta) {
                        TransTable.StoreBoard(theBoard, bestSoFar, jcMove.EVALTYPE_UPPERBOUND, depth, MoveCounter);

                        // Add this move's efficiency in the HistoryTable
                        HistoryTable.AddCount(theBoard.GetCurrentPlayer(), mov);
                        return BestMov;
                    }
                }
            }

            // Test for checkmate or stalemate
            if(bestSoFar <= ALPHABETA_GIVEUP) {
                newBoard.Clone(theBoard);
                jcMoveListGenerator secondary = new jcMoveListGenerator();
                newBoard.SwitchSides();
                if(secondary.ComputeLegalMoves(newBoard)) {
                    // Then, we are not in check and may continue our efforts.
                    HistoryTable.SortMoveList(movegen, newBoard.GetCurrentPlayer());
                    movegen.ResetIterator();
                    BestMov.MoveType = jcMove.MOVE_STALEMATE;
                    BestMov.MovingPiece = jcBoard.KING + theBoard.GetCurrentPlayer();
                    while((mov = movegen.Next()) != null) {
                        newBoard.Clone(theBoard);
                        newBoard.ApplyMove(mov);
                        if(secondary.ComputeLegalMoves(newBoard)) {
                            BestMov.MoveType = jcMove.MOVE_RESIGN;
                        }
                    }
                } else {
                    // We're in check and our best hope is GIVEUP or worse, so either we are
                    // already checkmated or will be soon, without hope of escape
                    BestMov.MovingPiece = jcBoard.KING + theBoard.GetCurrentPlayer();
                    BestMov.MoveType = jcMove.MOVE_RESIGN;
                }
            }

            // If we haven't returned yet, we have found an accurate minimax score
            // for a position which is neither a checkmate nor a stalemate
            TransTable.StoreBoard(theBoard, bestSoFar, jcMove.EVALTYPE_ACCURATE, depth, MoveCounter);

            return BestMov;
        }