Esempio n. 1
0
        /// <summary>
        /// Instruct the computer to think and make its next move.
        /// </summary>
        public void Think()
        {
            // Determine the best move available for "this" player instance, from the current board position.
            Debug.WriteLine(
                string.Format(
                    "Thread {0} is " + (this.IsPondering ? "pondering" : "thinking"), Thread.CurrentThread.Name));

            Player player = this.MyPlayer;

            // Set the player, whose move is to be computed, to "this" player object instance
            this.PrincipalVariation = new Moves(); // Best moves line (Principal Variation) found so far.

            // TimeSpan tsnTimePondered = new TimeSpan();
            int intTurnNo = Game.TurnNo;

            // Set whether to build a post-analysis tree of positions searched
            try
            {
                if (!this.IsPondering && !Game.IsInAnalyseMode)
                {
                    // Query Simple Opening Book
                    if (Game.UseRandomOpeningMoves)
                    {
                        Move moveBook;
                        if ((moveBook = OpeningBookSimple.SuggestRandomMove(player)) != null)
                        {
                            this.PrincipalVariation.Add(moveBook);
                            this.MoveConsideredEvent();
                            throw new ForceImmediateMoveException();
                        }
                    }

                    /* Query Best Opening Book
                     *  if ((m_moveBest = OpeningBook.SearchForGoodMove(Board.HashCodeA, Board.HashCodeB, this.Colour) )!=null)
                     *  {
                     *      m_moveCurrent = m_moveBest;
                     *      this.MoveConsidered();
                     *      throw new ForceImmediateMoveException();
                     *  }
                     */
                }

                // Time allowed for this player to think
                if (Game.ClockFixedTimePerMove.TotalSeconds > 0)
                {
                    // Absolute fixed time per move. No time is carried over from one move to the next.
                    this.ThinkingTimeAllotted = Game.ClockFixedTimePerMove;
                }
                else if (Game.ClockIncrementPerMove.TotalSeconds > 0)
                {
                    // Incremental clock
                    this.ThinkingTimeAllotted =
                        new TimeSpan(
                            Game.ClockIncrementPerMove.Ticks
                            +
                            ((
                                 ((Game.ClockIncrementPerMove.Ticks * Game.MoveNo)
                                  + (Game.ClockTime.Ticks * Math.Min(Game.MoveNo, 40) / 40))
                                 - this.MyPlayer.Clock.TimeElapsed.Ticks) / 3));

                    // Make sure we never think for less than half the "Increment" time
                    this.ThinkingTimeAllotted =
                        new TimeSpan(
                            Math.Max(this.ThinkingTimeAllotted.Ticks, (Game.ClockIncrementPerMove.Ticks / 2) + 1));
                }
                else if (Game.ClockMaxMoves == 0 && Game.ClockIncrementPerMove.TotalSeconds <= 0)
                {
                    // Fixed game time
                    this.ThinkingTimeAllotted = new TimeSpan(this.MyPlayer.Clock.TimeRemaining.Ticks / 30);
                }
                else
                {
                    // Conventional n moves in x minutes time
                    this.ThinkingTimeAllotted =
                        new TimeSpan(this.MyPlayer.Clock.TimeRemaining.Ticks / this.MyPlayer.Clock.MovesRemaining);
                }

                // Minimum of 1 second thinking time
                if (this.ThinkingTimeAllotted.TotalSeconds < 1)
                {
                    this.ThinkingTimeAllotted = new TimeSpan(0, 0, 1);
                }

                // The computer only stops "thinking" when it has finished a full ply of thought,
                // UNLESS m_tsnThinkingTimeMaxAllowed is exceeded, or clock runs out, then it stops right away.
                if (Game.ClockFixedTimePerMove.TotalSeconds > 0)
                {
                    // Fixed time per move
                    this.ThinkingTimeMaxAllowed = Game.ClockFixedTimePerMove;
                }
                else
                {
                    // Variable time per move
                    this.ThinkingTimeMaxAllowed =
                        new TimeSpan(
                            Math.Min(
                                this.ThinkingTimeAllotted.Ticks * 2,
                                this.MyPlayer.Clock.TimeRemaining.Ticks - (new TimeSpan(0, 0, 0, 2)).Ticks));
                }

                // Minimum of 2 seconds thinking time
                if (this.ThinkingTimeMaxAllowed.TotalSeconds < 2)
                {
                    this.ThinkingTimeMaxAllowed = new TimeSpan(0, 0, 2);
                }

                // Total number of times the evaluation function has been called (May be less than PositonsSearched if hashtable works well)
                if (Game.IsInAnalyseMode)
                {
                    HashTable.Clear();
                    HashTableCheck.Clear();
                    HashTablePawnKing.Clear();
                    History.Clear();
                }
                else
                {
                    if (this.MyPlayer.CanClaimMoveRepetitionDraw(2))
                    {
                        // See if' we're in a 2 move repetition position, and if so, clear the hashtable, as old hashtable entries corrupt 3MR detection
                        HashTable.Clear();
                    }
                    else
                    {
                        HashTable.ResetStats(); // Reset the main hash table hit stats
                    }

                    HashTableCheck.ResetStats();

                    // We also have a hash table in which we just store the check status for both players
                    HashTablePawnKing.ResetStats();

                    // And finally a hash table that stores the positional score of just the pawns.
                    History.Clear(); // Clear down the History Heuristic info, at the start of each move.
                }

                if (!this.IsPondering)
                {
                    this.MyPlayer.Clock.Start();
                }

                int score = this.Search.IterativeDeepeningSearch(
                    this.MyPlayer, this.PrincipalVariation, this.ThinkingTimeAllotted, this.ThinkingTimeMaxAllowed);
            }
            catch (ForceImmediateMoveException x)
            {
                // Undo any moves made during thinking
                Debug.WriteLine(x.ToString());
                while (Game.TurnNo > intTurnNo)
                {
                    Move.Undo(Game.MoveHistory.Last);
                }
            }

            if (this.MoveConsideredEvent != null)
            {
                this.MoveConsideredEvent();
            }

            Debug.WriteLine(
                string.Format(
                    "Thread {0} is ending " + (this.IsPondering ? "pondering" : "thinking"), Thread.CurrentThread.Name));

            this.threadThought = null;
            if (this.MoveConsideredEvent != null && !this.IsPondering)
            {
                this.ReadyToMakeMoveEvent();
            }

            this.IsPondering = false;

            // Send total elapsed time to generate this move.
            WinBoard.SendMoveTime(DateTime.Now - this.MyPlayer.Clock.TurnStartTime);
        }