Ejemplo n.º 1
0
        /// <summary>
        /// Populates the given array with the legal moves for the position and
        /// returns the number of legal moves.
        /// </summary>
        /// <param name="moves">The array to populate with the legal moves.</param>
        /// <returns>The number of legal moves for the position.</returns>
        public Int32 LegalMoves(Int32[] moves)
        {
            // Initialize bitboards and squares that describe the position.
            Int32 enemy      = 1 - SideToMove;
            Int32 kingSquare = Bit.Read(Bitboard[SideToMove | Piece.King]);

            UInt64 selfBitboard   = Bitboard[SideToMove];
            UInt64 enemyBitboard  = Bitboard[enemy];
            UInt64 targetBitboard = ~selfBitboard;

            UInt64 enemyBishopQueenBitboard = Bitboard[enemy | Piece.Bishop] | Bitboard[enemy | Piece.Queen];
            UInt64 enemyRookQueenBitboard   = Bitboard[enemy | Piece.Rook] | Bitboard[enemy | Piece.Queen];

            // Initialize variables for move generation.
            UInt64 checkingBitboard = 0;
            UInt64 pinningBitboard  = 0;
            Int32  index            = 0;

            // Consider knight and pawn checks.
            checkingBitboard |= Bitboard[enemy | Piece.Knight] & Attack.Knight(kingSquare);
            checkingBitboard |= Bitboard[enemy | Piece.Pawn] & Attack.Pawn(kingSquare, SideToMove);

            // Consider bishop and queen checks and pins.
            if ((enemyBishopQueenBitboard & Bit.Diagonals[kingSquare]) != 0)
            {
                checkingBitboard |= enemyBishopQueenBitboard & Attack.Bishop(kingSquare, OccupiedBitboard);

                // Determine pinning pieces by removing the first line of defence around the
                // the king, then seeing which pieces are able to attack.
                UInt64 defenceRemovedBitboard = OccupiedBitboard;
                UInt64 defenceBitboard        = Bit.RayNE[kingSquare] & selfBitboard;
                if (defenceBitboard != 0)
                {
                    defenceRemovedBitboard ^= Bit.IsolateReverse(defenceBitboard);
                }
                defenceBitboard = Bit.RayNW[kingSquare] & selfBitboard;
                if (defenceBitboard != 0)
                {
                    defenceRemovedBitboard ^= Bit.IsolateReverse(defenceBitboard);
                }
                defenceBitboard = Bit.RaySE[kingSquare] & selfBitboard;
                if (defenceBitboard != 0)
                {
                    defenceRemovedBitboard ^= Bit.Isolate(defenceBitboard);
                }
                defenceBitboard = Bit.RaySW[kingSquare] & selfBitboard;
                if (defenceBitboard != 0)
                {
                    defenceRemovedBitboard ^= Bit.Isolate(defenceBitboard);
                }

                if (defenceRemovedBitboard != OccupiedBitboard)
                {
                    pinningBitboard |= enemyBishopQueenBitboard & Attack.Bishop(kingSquare, defenceRemovedBitboard);
                }
            }

            // Consider rook and queen checks and pins.
            if ((enemyRookQueenBitboard & Bit.Axes[kingSquare]) != 0)
            {
                checkingBitboard |= enemyRookQueenBitboard & Attack.Rook(kingSquare, OccupiedBitboard);

                // Determine pinning pieces by removing the first line of defence around the
                // the king, then seeing which pieces are able to attack.
                UInt64 defenceRemovedBitboard = OccupiedBitboard;
                UInt64 defenceBitboard        = Bit.RayN[kingSquare] & selfBitboard;
                if (defenceBitboard != 0)
                {
                    defenceRemovedBitboard ^= Bit.IsolateReverse(defenceBitboard);
                }
                defenceBitboard = Bit.RayE[kingSquare] & selfBitboard;
                if (defenceBitboard != 0)
                {
                    defenceRemovedBitboard ^= Bit.Isolate(defenceBitboard);
                }
                defenceBitboard = Bit.RayS[kingSquare] & selfBitboard;
                if (defenceBitboard != 0)
                {
                    defenceRemovedBitboard ^= Bit.Isolate(defenceBitboard);
                }
                defenceBitboard = Bit.RayW[kingSquare] & selfBitboard;
                if (defenceBitboard != 0)
                {
                    defenceRemovedBitboard ^= Bit.IsolateReverse(defenceBitboard);
                }

                if (defenceRemovedBitboard != OccupiedBitboard)
                {
                    pinningBitboard |= enemyRookQueenBitboard & Attack.Rook(kingSquare, defenceRemovedBitboard);
                }
            }

            // Consider castling. This is always fully tested for legality.
            if (checkingBitboard == 0)
            {
                Int32 rank = -56 * SideToMove + 56;

                if (CastleQueenside[SideToMove] > 0 && (Square[1 + rank] | Square[2 + rank] | Square[3 + rank]) == Piece.Empty)
                {
                    if (!IsAttacked(SideToMove, 3 + rank) && !IsAttacked(SideToMove, 2 + rank))
                    {
                        moves[index++] = Move.Create(this, kingSquare, 2 + rank, SideToMove | Piece.King);
                    }
                }

                if (CastleKingside[SideToMove] > 0 && (Square[5 + rank] | Square[6 + rank]) == Piece.Empty)
                {
                    if (!IsAttacked(SideToMove, 5 + rank) && !IsAttacked(SideToMove, 6 + rank))
                    {
                        moves[index++] = Move.Create(this, kingSquare, 6 + rank, SideToMove | Piece.King);
                    }
                }
            }

            // Consider en passant. This is always fully tested for legality.
            if (EnPassantSquare != InvalidSquare)
            {
                UInt64 enPassantPawnBitboard   = Bitboard[SideToMove | Piece.Pawn] & Attack.Pawn(EnPassantSquare, enemy);
                UInt64 enPassantVictimBitboard = Move.Pawn(EnPassantSquare, enemy);
                while (enPassantPawnBitboard != 0)
                {
                    // Perform minimal state changes to mimick en passant and check for
                    // legality.
                    Int32 from = Bit.Pop(ref enPassantPawnBitboard);
                    Bitboard[enemy | Piece.Pawn] ^= enPassantVictimBitboard;
                    OccupiedBitboard             ^= enPassantVictimBitboard;
                    OccupiedBitboard             ^= (1UL << from) | (1UL << EnPassantSquare);

                    // Check for legality and add move.
                    if (!IsAttacked(SideToMove, kingSquare))
                    {
                        moves[index++] = Move.Create(this, from, EnPassantSquare, enemy | Piece.Pawn);
                    }

                    // Revert state changes.
                    Bitboard[enemy | Piece.Pawn] ^= enPassantVictimBitboard;
                    OccupiedBitboard             ^= enPassantVictimBitboard;
                    OccupiedBitboard             ^= (1UL << from) | (1UL << EnPassantSquare);
                }
            }

            // Consider king moves. This is always fully tested for legality.
            {
                Int32  from         = kingSquare;
                UInt64 moveBitboard = targetBitboard & Attack.King(from);
                while (moveBitboard != 0)
                {
                    // Perform minimal state changes to mimick real move and check for legality.
                    Int32  to = Bit.Pop(ref moveBitboard);
                    UInt64 occupiedBitboardCopy = OccupiedBitboard;
                    Int32  capture = Square[to];
                    Bitboard[capture] ^= 1UL << to;
                    OccupiedBitboard  ^= 1UL << from;
                    OccupiedBitboard  |= 1UL << to;

                    // Check for legality and add move.
                    if (!IsAttacked(SideToMove, to))
                    {
                        moves[index++] = Move.Create(this, from, to);
                    }

                    // Revert state changes.
                    Bitboard[capture] ^= 1UL << to;
                    OccupiedBitboard   = occupiedBitboardCopy;
                }
            }

            // Case 1. If we are not in check and there are no pinned pieces, we don't
            //         need to test normal moves for legality.
            if (checkingBitboard == 0 & pinningBitboard == 0)
            {
                // Consider normal pawn moves.
                UInt64 pieceBitboard = Bitboard[SideToMove | Piece.Pawn];
                while (pieceBitboard != 0)
                {
                    // Consider single square advance.
                    Int32  from         = Bit.Pop(ref pieceBitboard);
                    Int32  to           = from + 16 * SideToMove - 8;
                    UInt64 moveBitboard = ~OccupiedBitboard & (1UL << to);

                    // Consider two square advance.
                    if (moveBitboard != 0 && (from - 16) * (from - 47) > 0 && (to - 8) * (to - 55) < 0)
                    {
                        moveBitboard |= ~OccupiedBitboard & (1UL << (from + 32 * SideToMove - 16));
                    }

                    // Consider captures.
                    UInt64 attackBitboard = Attack.Pawn(from, SideToMove);
                    moveBitboard |= enemyBitboard & attackBitboard;

                    // Populate pawn moves.
                    while (moveBitboard != 0)
                    {
                        to = Bit.Pop(ref moveBitboard);
                        if ((to - 8) * (to - 55) > 0)
                        {
                            moves[index++] = Move.Create(this, from, to, SideToMove | Piece.Queen);
                            moves[index++] = Move.Create(this, from, to, SideToMove | Piece.Knight);
                            moves[index++] = Move.Create(this, from, to, SideToMove | Piece.Rook);
                            moves[index++] = Move.Create(this, from, to, SideToMove | Piece.Bishop);
                        }
                        else
                        {
                            moves[index++] = Move.Create(this, from, to);
                        }
                    }
                }

                // Consider knight moves.
                pieceBitboard = Bitboard[SideToMove | Piece.Knight];
                while (pieceBitboard != 0)
                {
                    Int32  from         = Bit.Pop(ref pieceBitboard);
                    UInt64 moveBitboard = targetBitboard & Attack.Knight(from);
                    while (moveBitboard != 0)
                    {
                        Int32 to = Bit.Pop(ref moveBitboard);
                        moves[index++] = Move.Create(this, from, to);
                    }
                }

                // Consider bishop moves.
                pieceBitboard = Bitboard[SideToMove | Piece.Bishop];
                while (pieceBitboard != 0)
                {
                    Int32  from         = Bit.Pop(ref pieceBitboard);
                    UInt64 moveBitboard = targetBitboard & Attack.Bishop(from, OccupiedBitboard);
                    while (moveBitboard != 0)
                    {
                        Int32 to = Bit.Pop(ref moveBitboard);
                        moves[index++] = Move.Create(this, from, to);
                    }
                }

                // Consider queen moves.
                pieceBitboard = Bitboard[SideToMove | Piece.Queen];
                while (pieceBitboard != 0)
                {
                    Int32  from         = Bit.Pop(ref pieceBitboard);
                    UInt64 moveBitboard = targetBitboard & Attack.Queen(from, OccupiedBitboard);
                    while (moveBitboard != 0)
                    {
                        Int32 to = Bit.Pop(ref moveBitboard);
                        moves[index++] = Move.Create(this, from, to);
                    }
                }

                // Consider rook moves.
                pieceBitboard = Bitboard[SideToMove | Piece.Rook];
                while (pieceBitboard != 0)
                {
                    Int32  from         = Bit.Pop(ref pieceBitboard);
                    UInt64 moveBitboard = targetBitboard & Attack.Rook(from, OccupiedBitboard);
                    while (moveBitboard != 0)
                    {
                        Int32 to = Bit.Pop(ref moveBitboard);
                        moves[index++] = Move.Create(this, from, to);
                    }
                }
            }

            // Case 2. There are pinned pieces or a single check. We can still move but
            //         all moves are tested for legality.
            else if ((checkingBitboard & (checkingBitboard - 1)) == 0)
            {
                // Consider pawn moves.
                UInt64 pieceBitboard = Bitboard[SideToMove | Piece.Pawn];
                while (pieceBitboard != 0)
                {
                    // Consider single square advance.
                    Int32  from         = Bit.Pop(ref pieceBitboard);
                    Int32  to           = from + 16 * SideToMove - 8;
                    UInt64 moveBitboard = ~OccupiedBitboard & (1UL << to);

                    // Consider two square advance.
                    if (moveBitboard != 0 && (from - 16) * (from - 47) > 0 && (to - 8) * (to - 55) < 0)
                    {
                        moveBitboard |= ~OccupiedBitboard & (1UL << (from + 32 * SideToMove - 16));
                    }

                    // Consider captures.
                    UInt64 attackBitboard = Attack.Pawn(from, SideToMove);
                    moveBitboard |= enemyBitboard & attackBitboard;

                    // Populate pawn moves.
                    while (moveBitboard != 0)
                    {
                        // Perform minimal state changes to mimick real move and check for legality.
                        to = Bit.Pop(ref moveBitboard);
                        UInt64 occupiedBitboardCopy = OccupiedBitboard;
                        Int32  capture = Square[to];
                        Bitboard[capture] ^= 1UL << to;
                        OccupiedBitboard  ^= 1UL << from;
                        OccupiedBitboard  |= 1UL << to;

                        // Check for legality and add moves.
                        if (!IsAttacked(SideToMove, kingSquare))
                        {
                            if ((to - 8) * (to - 55) > 0)
                            {
                                moves[index++] = Move.Create(this, from, to, SideToMove | Piece.Queen);
                                moves[index++] = Move.Create(this, from, to, SideToMove | Piece.Knight);
                                moves[index++] = Move.Create(this, from, to, SideToMove | Piece.Rook);
                                moves[index++] = Move.Create(this, from, to, SideToMove | Piece.Bishop);
                            }
                            else
                            {
                                moves[index++] = Move.Create(this, from, to);
                            }
                        }

                        // Revert state changes.
                        Bitboard[capture] ^= 1UL << to;
                        OccupiedBitboard   = occupiedBitboardCopy;
                    }
                }

                // Consider knight moves.
                pieceBitboard = Bitboard[SideToMove | Piece.Knight];
                while (pieceBitboard != 0)
                {
                    Int32  from         = Bit.Pop(ref pieceBitboard);
                    UInt64 moveBitboard = targetBitboard & Attack.Knight(from);
                    while (moveBitboard != 0)
                    {
                        // Perform minimal state changes to mimick real move and check for legality.
                        Int32  to = Bit.Pop(ref moveBitboard);
                        UInt64 occupiedBitboardCopy = OccupiedBitboard;
                        Int32  capture = Square[to];
                        Bitboard[capture] ^= 1UL << to;
                        OccupiedBitboard  ^= 1UL << from;
                        OccupiedBitboard  |= 1UL << to;

                        // Check for legality and add move.
                        if (!IsAttacked(SideToMove, kingSquare))
                        {
                            moves[index++] = Move.Create(this, from, to);
                        }

                        // Revert state changes.
                        Bitboard[capture] ^= 1UL << to;
                        OccupiedBitboard   = occupiedBitboardCopy;
                    }
                }

                // Consider bishop moves.
                pieceBitboard = Bitboard[SideToMove | Piece.Bishop];
                while (pieceBitboard != 0)
                {
                    Int32  from         = Bit.Pop(ref pieceBitboard);
                    UInt64 moveBitboard = targetBitboard & Attack.Bishop(from, OccupiedBitboard);
                    while (moveBitboard != 0)
                    {
                        // Perform minimal state changes to mimick real move and check for legality.
                        Int32  to = Bit.Pop(ref moveBitboard);
                        UInt64 occupiedBitboardCopy = OccupiedBitboard;
                        Int32  capture = Square[to];
                        Bitboard[capture] ^= 1UL << to;
                        OccupiedBitboard  ^= 1UL << from;
                        OccupiedBitboard  |= 1UL << to;

                        // Check for legality and add move.
                        if (!IsAttacked(SideToMove, kingSquare))
                        {
                            moves[index++] = Move.Create(this, from, to);
                        }

                        // Revert state changes.
                        Bitboard[capture] ^= 1UL << to;
                        OccupiedBitboard   = occupiedBitboardCopy;
                    }
                }

                // Consider queen moves.
                pieceBitboard = Bitboard[SideToMove | Piece.Queen];
                while (pieceBitboard != 0)
                {
                    Int32  from         = Bit.Pop(ref pieceBitboard);
                    UInt64 moveBitboard = targetBitboard & Attack.Queen(from, OccupiedBitboard);
                    while (moveBitboard != 0)
                    {
                        // Perform minimal state changes to mimick real move and check for legality.
                        Int32  to = Bit.Pop(ref moveBitboard);
                        UInt64 occupiedBitboardCopy = OccupiedBitboard;
                        Int32  capture = Square[to];
                        Bitboard[capture] ^= 1UL << to;
                        OccupiedBitboard  ^= 1UL << from;
                        OccupiedBitboard  |= 1UL << to;

                        // Check for legality and add move.
                        if (!IsAttacked(SideToMove, kingSquare))
                        {
                            moves[index++] = Move.Create(this, from, to);
                        }

                        // Revert state changes.
                        Bitboard[capture] ^= 1UL << to;
                        OccupiedBitboard   = occupiedBitboardCopy;
                    }
                }

                // Consider rook moves.
                pieceBitboard = Bitboard[SideToMove | Piece.Rook];
                while (pieceBitboard != 0)
                {
                    Int32  from         = Bit.Pop(ref pieceBitboard);
                    UInt64 moveBitboard = targetBitboard & Attack.Rook(from, OccupiedBitboard);
                    while (moveBitboard != 0)
                    {
                        // Perform minimal state changes to mimick real move and check for legality.
                        Int32  to = Bit.Pop(ref moveBitboard);
                        UInt64 occupiedBitboardCopy = OccupiedBitboard;
                        Int32  capture = Square[to];
                        Bitboard[capture] ^= 1UL << to;
                        OccupiedBitboard  ^= 1UL << from;
                        OccupiedBitboard  |= 1UL << to;

                        // Check for legality and add move.
                        if (!IsAttacked(SideToMove, kingSquare))
                        {
                            moves[index++] = Move.Create(this, from, to);
                        }

                        // Revert state changes.
                        Bitboard[capture] ^= 1UL << to;
                        OccupiedBitboard   = occupiedBitboardCopy;
                    }
                }
            }
            return(index);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Populates the given array with the pseudo-legal capturing and queen
        /// promotion moves for the position and returns the number of moves.
        /// </summary>
        /// <param name="moves">The array to populate with the pseudo-legal moves.</param>
        /// <returns>The number of moves generated for the position.</returns>
        public Int32 PseudoQuiescenceMoves(Int32[] moves)
        {
            UInt64 targetBitboard = Bitboard[(1 - SideToMove)];
            Int32  index          = 0;

            // Consider king moves.
            UInt64 pieceBitboard = Bitboard[SideToMove | Piece.King];
            Int32  from          = Bit.Read(pieceBitboard);
            UInt64 moveBitboard  = targetBitboard & Attack.King(from);

            while (moveBitboard != 0)
            {
                Int32 to = Bit.Pop(ref moveBitboard);
                moves[index++] = Move.Create(this, from, to);
            }


            // Consider queen moves.
            pieceBitboard = Bitboard[SideToMove | Piece.Queen];
            while (pieceBitboard != 0)
            {
                from         = Bit.Pop(ref pieceBitboard);
                moveBitboard = targetBitboard & Attack.Queen(from, OccupiedBitboard);
                while (moveBitboard != 0)
                {
                    Int32 to = Bit.Pop(ref moveBitboard);
                    moves[index++] = Move.Create(this, from, to);
                }
            }

            // Consider rook moves.
            pieceBitboard = Bitboard[SideToMove | Piece.Rook];
            while (pieceBitboard != 0)
            {
                from         = Bit.Pop(ref pieceBitboard);
                moveBitboard = targetBitboard & Attack.Rook(from, OccupiedBitboard);
                while (moveBitboard != 0)
                {
                    Int32 to = Bit.Pop(ref moveBitboard);
                    moves[index++] = Move.Create(this, from, to);
                }
            }

            // Consider knight moves.
            pieceBitboard = Bitboard[SideToMove | Piece.Knight];
            while (pieceBitboard != 0)
            {
                from         = Bit.Pop(ref pieceBitboard);
                moveBitboard = targetBitboard & Attack.Knight(from);
                while (moveBitboard != 0)
                {
                    Int32 to = Bit.Pop(ref moveBitboard);
                    moves[index++] = Move.Create(this, from, to);
                }
            }

            // Consider bishop moves.
            pieceBitboard = Bitboard[SideToMove | Piece.Bishop];
            while (pieceBitboard != 0)
            {
                from         = Bit.Pop(ref pieceBitboard);
                moveBitboard = targetBitboard & Attack.Bishop(from, OccupiedBitboard);
                while (moveBitboard != 0)
                {
                    Int32 to = Bit.Pop(ref moveBitboard);
                    moves[index++] = Move.Create(this, from, to);
                }
            }

            // Consider pawn moves.
            pieceBitboard = Bitboard[SideToMove | Piece.Pawn];
            while (pieceBitboard != 0)
            {
                from         = Bit.Pop(ref pieceBitboard);
                moveBitboard = targetBitboard & Attack.Pawn(from, SideToMove);
                Int32   to        = from + 16 * SideToMove - 8;
                Boolean promotion = (to - 8) * (to - 55) > 0;
                if (promotion)
                {
                    moveBitboard |= ~OccupiedBitboard & (1UL << to);
                }
                while (moveBitboard != 0)
                {
                    to = Bit.Pop(ref moveBitboard);
                    if (promotion)
                    {
                        moves[index++] = Move.Create(this, from, to, SideToMove | Piece.Queen);
                    }
                    else
                    {
                        moves[index++] = Move.Create(this, from, to);
                    }
                }
            }
            return(index);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Executes the parsing.
        /// </summary>
        public static void Run()
        {
            Restrictions.Output = OutputType.Universal;
            IEngine  engine   = new Zero();
            Position position = new Position(Position.StartingFEN);

            String command;

            while ((command = Console.ReadLine()) != null)
            {
                List <String> terms = new List <String>(command.Split(' '));

                switch (terms[0])
                {
                default:
                    Terminal.WriteLine("Unknown command: {0}", terms[0]);
                    Terminal.WriteLine("Enter \"help\" for assistance.");
                    break;

                case "uci":
                    Terminal.WriteLine("id name " + engine.Name);
                    Terminal.WriteLine("id author Zong Zheng Li");
                    Terminal.WriteLine("option name Hash type spin default " + Zero.DefaultHashAllocation + " min 1 max 2047");
                    Terminal.WriteLine("uciok");
                    break;

                case "ucinewgame":
                    engine.Reset();
                    break;

                case "setoption":
                    if (terms.Contains("Hash"))
                    {
                        engine.HashAllocation = Int32.Parse(terms[terms.IndexOf("value") + 1]);
                    }
                    break;

                case "position":
                    String fen = Position.StartingFEN;
                    if (terms[1] != "startpos")
                    {
                        fen = command.Substring(command.IndexOf("fen") + 4);
                    }
                    position = new Position(fen);

                    Int32 movesIndex = terms.IndexOf("moves");
                    if (movesIndex >= 0)
                    {
                        for (Int32 i = movesIndex + 1; i < terms.Count; i++)
                        {
                            position.Make(Move.Create(position, terms[i]));
                        }
                    }
                    break;

                case "go":
                    Restrictions.Reset();
                    for (Int32 i = 1; i < terms.Count; i++)
                    {
                        switch (terms[i])
                        {
                        default:
                        case "infinite":
                            break;

                        case "depth":
                            Restrictions.Depth           = Int32.Parse(terms[i + 1]);
                            Restrictions.UseTimeControls = false;
                            break;

                        case "movetime":
                            Restrictions.MoveTime        = Int32.Parse(terms[i + 1]);
                            Restrictions.UseTimeControls = false;
                            break;

                        case "wtime":
                            Restrictions.TimeControl[Colour.White] = Int32.Parse(terms[i + 1]);
                            Restrictions.UseTimeControls           = true;
                            break;

                        case "btime":
                            Restrictions.TimeControl[Colour.Black] = Int32.Parse(terms[i + 1]);
                            Restrictions.UseTimeControls           = true;
                            break;

                        case "winc":
                            Restrictions.TimeIncrement[Colour.White] = Int32.Parse(terms[i + 1]);
                            Restrictions.UseTimeControls             = true;
                            break;

                        case "binc":
                            Restrictions.TimeIncrement[Colour.Black] = Int32.Parse(terms[i + 1]);
                            Restrictions.UseTimeControls             = true;
                            break;

                        case "nodes":
                            Restrictions.Nodes           = Int32.Parse(terms[i + 1]);
                            Restrictions.UseTimeControls = false;
                            break;

                        case "ponder":
                            // TODO: implement command.
                            break;

                        case "mate":
                            // TODO: implement command.
                            break;

                        case "movestogo":
                            // TODO: implement command.
                            break;
                        }
                    }
                    new Thread(new ThreadStart(() => {
                        Int32 bestMove = engine.GetMove(position);
                        Terminal.WriteLine("bestmove " + Stringify.Move(bestMove));
                    }))
                    {
                        IsBackground = true
                    }.Start();
                    break;

                case "stop":
                    engine.Stop();
                    break;

                case "isready":
                    Terminal.WriteLine("readyok");
                    break;

                case "quit":
                    return;

                case "perft":
                    Perft.Iterate(position, Int32.Parse(terms[1]));
                    break;

                case "divide":
                    Perft.Divide(position, Int32.Parse(terms[1]));
                    break;

                case "draw":
                    Terminal.WriteLine(position);
                    break;

                case "fen":
                    Terminal.WriteLine(position.GetFEN());
                    break;

                case "ponderhit":
                    // TODO: implement command.
                    break;

                case "register":
                    // TODO: implement command.
                    break;

                case "help":
                    Terminal.WriteLine("Command             Function");
                    Terminal.WriteLine("-----------------------------------------------------------------------");
                    Terminal.WriteLine("position [fen]      Sets the current position to the position denoted");
                    Terminal.WriteLine("                    by the given FEN. \"startpos\" is accepted for the");
                    Terminal.WriteLine("                    starting position");
                    Terminal.WriteLine("go [type] [number]  Searches the current position. Search types include");
                    Terminal.WriteLine("                    \"movetime\", \"depth\", \"nodes\", \"wtime\", \"btime\",");
                    Terminal.WriteLine("                    \"winc\", and \"binc\"");
                    Terminal.WriteLine("perft [number]      Runs perft() on the current position to the given");
                    Terminal.WriteLine("                    depth");
                    Terminal.WriteLine("divide [number]     Runs divide() on the current position for the given");
                    Terminal.WriteLine("                    depth");
                    Terminal.WriteLine("fen                 Prints the FEN of the current position.");
                    Terminal.WriteLine("draw                Draws the current position");
                    Terminal.WriteLine("stop                Stops an ongoing search");
                    Terminal.WriteLine("quit                Exits the application");
                    Terminal.WriteLine("-----------------------------------------------------------------------");
                    break;
                }
            }
        }