/// <summary> /// Terminate the game. /// </summary> public static void TerminateGame() { WinBoard.StopListener(); SuspendPondering(); PlayerWhite.Brain.AbortThinking(); PlayerBlack.Brain.AbortThinking(); try { RegistryKey registryKeySoftware = Registry.CurrentUser.OpenSubKey("Software", true); if (registryKeySoftware != null) { RegistryKey registryKeySharpChess = registryKeySoftware.CreateSubKey(@"PeterHughes.org\SharpChess"); if (registryKeySharpChess != null) { registryKeySharpChess.SetValue("FileName", saveGameFileName); registryKeySharpChess.SetValue("ShowThinking", ShowThinking ? "1" : "0"); } } } catch { } }
/// <summary> /// Make the specified move. For internal use only. /// </summary> /// <param name="moveName"> The move name. </param> /// <param name="piece"> The piece to move. </param> /// <param name="square"> The square to move to. </param> private static void MakeAMoveInternal(Move.MoveNames moveName, Piece piece, Square square) { MoveRedoList.Clear(); Move move = piece.Move(moveName, square); move.EnemyStatus = move.Piece.Player.OpposingPlayer.Status; PlayerToPlay.Clock.Stop(); MoveHistory.Last.TimeStamp = PlayerToPlay.Clock.TimeElapsed; if (PlayerToPlay.Intellegence == Player.PlayerIntellegenceNames.Computer) { WinBoard.SendMove(move); if (!PlayerToPlay.OpposingPlayer.CanMove) { if (PlayerToPlay.OpposingPlayer.IsInCheckMate) { WinBoard.SendCheckMate(); } else if (!PlayerToPlay.OpposingPlayer.IsInCheck) { WinBoard.SendCheckStaleMate(); } } else if (PlayerToPlay.OpposingPlayer.CanClaimThreeMoveRepetitionDraw == true) { WinBoard.SendDrawByRepetition(); } else if (PlayerToPlay.OpposingPlayer.CanClaimFiftyMoveDraw == true) { WinBoard.SendDrawByFiftyMoveRule(); } else if (PlayerToPlay.OpposingPlayer.CanClaimInsufficientMaterialDraw == true) { WinBoard.SendDrawByInsufficientMaterial(); } } BroadcastMovedName(move); CheckGameStatus(); PlayerToPlay = PlayerToPlay.OpposingPlayer; PlayerToPlay.Clock.Start(); }
/// <summary> /// The start thinking. /// </summary> public void StartThinking() { // Bail out if unable to move if (!this.MyPlayer.CanMove) { return; } // Send draw result is playing WinBoard if (WinBoard.Active && this.MyPlayer.Intellegence == Player.PlayerIntellegenceNames.Computer) { if (this.MyPlayer.CanClaimThreeMoveRepetitionDraw) { WinBoard.SendDrawByRepetition(); return; } if (this.MyPlayer.CanClaimFiftyMoveDraw) { WinBoard.SendDrawByFiftyMoveRule(); return; } if (this.MyPlayer.CanClaimInsufficientMaterialDraw) { WinBoard.SendDrawByFiftyMoveRule(); return; } } this.threadThought = new Thread(this.Think); this.threadThought.Name = (++Game.ThreadCounter).ToString(); this.ThinkingBeginningEvent(); this.threadThought.Priority = ThreadPriority.Normal; this.threadThought.Start(); }
/// <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); }