public static void ProcessQueue() { float realtimeSinceStartup = Time.get_realtimeSinceStartup(); float num = AIThinkManager.framebudgetms / 1000f; if (AIThinkManager._removalQueue.get_Count() > 0) { using (IEnumerator <IThinker> enumerator = AIThinkManager._removalQueue.GetEnumerator()) { while (enumerator.MoveNext()) { IThinker current = enumerator.Current; AIThinkManager._processQueue.Remove(current); } } AIThinkManager._removalQueue.Clear(); } for (; AIThinkManager.lastIndex < AIThinkManager._processQueue.get_Count() && (double)Time.get_realtimeSinceStartup() < (double)realtimeSinceStartup + (double)num; ++AIThinkManager.lastIndex) { AIThinkManager._processQueue.get_Item(AIThinkManager.lastIndex)?.TryThink(); } if (AIThinkManager.lastIndex != AIThinkManager._processQueue.get_Count()) { return; } AIThinkManager.lastIndex = 0; }
private static void DoProcessing(ListHashSet <IThinker> process, float budgetSeconds, ref int last) { float realtimeSinceStartup = Time.realtimeSinceStartup; while (last < process.Count && Time.realtimeSinceStartup < realtimeSinceStartup + budgetSeconds) { IThinker thinker = process[last]; if (thinker != null) { try { thinker.TryThink(); } catch (Exception message) { Debug.LogWarning(message); } } last++; } if (last >= process.Count) { last = 0; } }
public static void ProcessQueue() { float single = Time.realtimeSinceStartup; float single1 = (float)AIThinkManager.framebudgetms / 1000f; if (AIThinkManager._removalQueue.Count > 0) { foreach (IThinker thinker in AIThinkManager._removalQueue) { AIThinkManager._processQueue.Remove(thinker); } AIThinkManager._removalQueue.Clear(); } while (AIThinkManager.lastIndex < AIThinkManager._processQueue.Count && Time.realtimeSinceStartup < single + single1) { IThinker item = AIThinkManager._processQueue[AIThinkManager.lastIndex]; if (item != null) { item.TryThink(); } AIThinkManager.lastIndex++; } if (AIThinkManager.lastIndex == AIThinkManager._processQueue.Count) { AIThinkManager.lastIndex = 0; } }
private static void Main(string[] args) { // ////////////////////////////////////////////////////////////// // // Create an instance of our Ultron thinker via ThinkerPrototype. // // If we created directly with new, it would not be properly // // configured. // // ////////////////////////////////////////////////////////////// // // Create a configuration for a default ColorShapeLinks match MatchConfig mc = new MatchConfig(); // Get the fully qualified name of our basic Ultron thinker string ultronFullName = typeof(UltronThinker).FullName; // Create a prototype for our thinker ThinkerPrototype tp = new ThinkerPrototype(ultronFullName, "", mc); // Create an instance of our basic Ultron thinker IThinker ultronThinker = tp.Create(); // //////////////////////////////////////////////////////// // // Create a board so we can test how our thinker will play. // // //////////////////////////////////////////////////////// // // A cancellation token, will be ignored CancellationToken ct = new CancellationToken(); // Create a ColorShapeLinks board with default size Board board = new Board(); // Show initial board Console.WriteLine("\n=== Initial board ===\n"); ShowBoard(board); // Make some moves manually board.DoMove(PShape.Round, 0); // White plays round piece in col 0 board.DoMove(PShape.Square, 4); // Red plays square piece in col 4 board.DoMove(PShape.Square, 5); // White plays round piece in col 5 // Show board after our three manual moves Console.WriteLine("\n=== Board after three manual moves ===\n"); ShowBoard(board); // What move would Ultron make at this moment? FutureMove ultronMove = ultronThinker.Think(board, ct); // Show move Console.WriteLine($"-> Ultron will play {ultronMove}"); // Make the move selected by Ultron board.DoMove(ultronMove.shape, ultronMove.column); // Show board after Ultron made its move Console.WriteLine("\n=== Board after Ultron made move ===\n"); ShowBoard(board); }
public void RemoveThinker(IThinker thinker) { if (thinker.NextThinker != null) { thinker.NextThinker.PrevThinker = thinker.PrevThinker; } if (thinker.PrevThinker != null) { thinker.PrevThinker.NextThinker = thinker.NextThinker; } }
public bool MoveNext() { if (cur != null && cur.NextThinker != null) { cur = cur.NextThinker; return(true); } else { return(false); } }
// Raise and invalid play event and return the match winner (which is // the opponent of the thinker that made an invalid play) private Winner OnInvalidPlay( PColor color, IThinker thinker, string reason) { // Set the other thinker as the winner of the match Winner winner = color.Other().ToWinner(); // Set solution to null solution = null; // Notify listeners that thinker made an invalid play InvalidPlay?.Invoke(color, thinker.ToString(), reason); // Return the winner return(winner); }
public void AddThinker(IThinker thinker) { if (Thinkers.First == null) { thinker.PrevThinker = null; thinker.NextThinker = null; Thinkers.SetFirst(thinker); } else { thinker.PrevThinker = null; thinker.NextThinker = Thinkers.First; Thinkers.First.PrevThinker = thinker; Thinkers.SetFirst(thinker); } }
public void SetFirst(IThinker newFirst) { first = newFirst; }
public ThinkerEnumerator(IThinker firstNode) { first = firstNode; }
public void Reset() { cur = enumerator.first; }
public static void Remove(IThinker toRemove) { _removalQueue.Add(toRemove); }
/// Current thinker makes its move private Winner Play() { // Get a reference to the current thinker IThinker thinker = matchData.CurrentThinker; // Determine the color of the current thinker PColor color = board.Turn; // Match result so far Winner winner = Winner.None; // Thinking start time DateTime startTime = DateTime.Now; // Real think time in milliseconds int thinkTimeMillis; // Apparent thinking time left int timeLeftMillis; // Task to execute the thinker in a separate thread Task <FutureMove> thinkTask; // Notify listeners that next turn is about to start NextTurn?.Invoke(color, thinker.ToString()); // Ask thinker to think about its next move thinkTask = Task.Run( () => thinker.Think(board.Copy(), ts.Token)); // The thinking process might throw an exception, so we wrap // task waiting in a try/catch block try { // Wait for thinker to think... until the allowed time limit if (thinkTask.Wait(timeLimitMillis)) { // Thinker successfully made a move within the time limit // Get the move selected by the thinker FutureMove move = thinkTask.Result; // Was the thinker able to chose a move? if (move.IsNoMove) { // Thinker was not able to chose a move // Raise an invalid play event and set the other // thinker as the winner of the match winner = OnInvalidPlay( color, thinker, "Thinker unable to perform move"); } else { // Thinker was able to chose a move // Perform move in game board, get column where move // was performed int row = board.DoMove(move.shape, move.column); // If the column had space for the move... if (row >= 0) { // Obtain thinking end time thinkTimeMillis = (int)(DateTime.Now - startTime) .TotalMilliseconds; // How much time left for the minimum apparent move // time? timeLeftMillis = minMoveTimeMillis - thinkTimeMillis; // Was the minimum apparent move time reached if (timeLeftMillis > 0) { // If not, wait until it is reached Thread.Sleep(timeLeftMillis); } // Notify listeners of the move performed MovePerformed?.Invoke( color, thinker.ToString(), move, thinkTimeMillis); // Get possible winner and solution winner = board.CheckWinner(solution); } else { // If we get here, column didn't have space for the // move, which means that thinker made an invalid // move and should lose the game // Raise an invalid play event and set the other // thinker as the winner of the match winner = OnInvalidPlay( color, thinker, "Tried to place piece in column " + $"{move.column}, which is full"); } } } else // Did the time limit expired? { // Notify thinker to voluntarily stop thinking ts.Cancel(); // Raise an invalid play event and set the other thinker // as the winner of the match winner = OnInvalidPlay( color, thinker, "Time limit expired"); } } catch (Exception e) { // Is this an inner exception? if (e.InnerException != null) { // If so, use it for error message purposes e = e.InnerException; } // Raise an invalid play event and set the other thinker as // the winner of the match winner = OnInvalidPlay( color, thinker, $"Thinker exception: '{e.Message}'"); } // Notify listeners that the board was updated BoardUpdate?.Invoke(board); // Return winner return(winner); }
static void Main(string[] args) { MatchConfig mc = new MatchConfig(); // Use default values ThinkerPrototype tp = new ThinkerPrototype(typeof(MyThinker).FullName, "", mc); IThinker thinker = tp.Create(); }
/// <summary> /// This method will be called before a match starts and is used for /// instantiating a new <see cref="G10NossaAIThinker"/>. /// </summary> /// <seealso cref="AIPlayer.Setup"/> public override void Setup() { thinker = new G10NossaAIThinker(); }
public static void AddAnimal(IThinker toAdd) { _animalProcessQueue.Add(toAdd); }
/// <summary> /// This method will be called before a match starts and is used for /// instantiating a new <see cref="SequentialAIThinker"/>. /// </summary> /// <seealso cref="AIPlayer.Setup"/> public override void Setup() { thinker = new SequentialAIThinker(); }
private static void Main(string[] args) { // ////////////////////////////////////////////////////////////// // // Create an instance of our Oizys thinker via ThinkerPrototype. // // If we created directly with new, it would not be properly // // configured. // // ////////////////////////////////////////////////////////////// // // Create a configuration for a default ColorShapeLinks match MatchConfig mc = new MatchConfig(); // Get the fully qualified name of our basic Oizys thinker string oizysFullName = typeof(OizysThinker).FullName; // Create a prototype for our thinker ThinkerPrototype tp = new ThinkerPrototype(oizysFullName, "", mc); // Create an instance of our basic Oizys thinker IThinker oizysThinker = tp.Create(); // //////////////////////////////////////////////////////// // // Create a board so we can test how our thinker will play. // // //////////////////////////////////////////////////////// // // A cancellation token, will be ignored CancellationToken ct = new CancellationToken(); // Create a ColorShapeLinks board with default size Board board = new Board(); // Show initial board Console.WriteLine("\n=== Initial board ===\n"); ShowBoard(board); // Make some moves manually board.DoMove(PShape.Round, 3); // White plays (Round,col 3) board.DoMove(PShape.Square, 3); // Red plays (Square,col 3) board.DoMove(PShape.Round, 2); // White plays (Round,col 2) // board.DoMove(PShape.Square, 3); // Red plays (Square,col 3) // board.DoMove(PShape.Round, 1); // White plays (Round,col 1) // board.DoMove(PShape.Square, 3); // Red plays (Square,col 3) // board.DoMove(PShape.Round, 3); // White plays (Round,col 3) // Show board after our three manual moves Console.WriteLine("\n=== Board after three manual moves ===\n"); ShowBoard(board); // Starts timer DateTime startTime = DateTime.Now; // What move would Oizys make at this moment? FutureMove oizysMove = oizysThinker.Think(board, ct); // Show move and time Console.WriteLine(string.Format( "-> Oizys will play {0} after {1} ms.", oizysMove, (DateTime.Now - startTime).TotalMilliseconds)); // Make the move selected by Oizys board.DoMove(oizysMove.shape, oizysMove.column); // Show board after Oizys made its move Console.WriteLine("\n=== Board after Oizys made move ===\n"); ShowBoard(board); }
public static void Remove(IThinker toRemove) { AIThinkManager._removalQueue.Add(toRemove); }
public static void Add(IThinker toAdd) { AIThinkManager._processQueue.Add(toAdd); }
public static void RemoveAnimal(IThinker toRemove) { _animalremovalQueue.Add(toRemove); }
public Enumerator(ThinkerEnumerator thinkerEnum) { enumerator = thinkerEnum; first.NextThinker = enumerator.first; cur = first; }
// Update is called once per frame private void Update() { // Don't run update if the game's over if (matchOver) { return; } // Is the current player human? If so, let's see if we're supposed to // show him a message or if we've done so already if (matchData.CurrentPlayer.IsHuman) { if (showHumanTurnMessage) { view.SubmitMessage( $"Attention {CurrPlrNameColor}, it's your turn"); showHumanTurnMessage = false; } ; } // If the current player is an AI, let's see if we have to start // the AI thinking task, if the task is running, if it's completed, etc. else { // If the AI task is null, we need to start an AI thinking task if (aiTask == null) { // Submit a message informing the user the AI is thinking view.SubmitMessage( $"{CurrPlrNameColor} is thinking, please wait..."); // Keep note of task start time (both system time and game time) taskStartSysTime = DateTime.Now; taskStartGameTime = Time.time; // Create a new task cancellation token, so task can be // interrupted ts = new CancellationTokenSource(); // Get this AI's thinker IThinker thinker = matchData.CurrentPlayer.Thinker; // Start task in a separate thread using a copy of the board aiTask = Task.Run(() => thinker.Think(board.Copy(), ts.Token)); } else // This else will run if the task is not null { // Is the AI thinking task completed? if (aiTask.IsCompleted) { // Register task duration, if we haven't done so yet if (float.IsNaN(lastTaskDuration)) { lastTaskDuration = (float)((DateTime.Now - taskStartSysTime).Ticks / (double)(TimeSpan.TicksPerSecond)); } // Did we pass the minimum time between AI moves? if (Time.time > taskStartGameTime + matchData.MinAIGameMoveTime) { // If so, submit a message informing of the move // chosen and the system time it took the AI to think view.SubmitMessage(string.Format( "{0} placed a {1} piece at column {2} after {3}", CurrPlrNameColor, aiTask.Result.shape.ToString().ToLower(), aiTask.Result.column, $"thinking for {lastTaskDuration:f4}s")); // Perform the actual move MakeAMove(aiTask.Result); // Set the task to null, so it can be started again aiTask = null; // Reset the last task duration lastTaskDuration = float.NaN; } } // Did the task throw an exception? else if (aiTask.IsFaulted) { // If so, notify user view.SubmitMessage( aiTask.Exception.InnerException.Message); // Log exception as an error Debug.LogError(aiTask.Exception.InnerException.Message); // Send a cancellation token to the task in the hope it // might actually terminate ts.Cancel(); // Set task to null aiTask = null; // The AI player that throwed the exception will lose the // game, sorry this.Result = board.Turn == PColor.White ? Winner.Red : Winner.White; OnMatchOver(); } // Is the task overdue? else if (DateTime.Now - taskStartSysTime > aiTimeLimit) { // If so, notify user view.SubmitMessage( $"Time limit exceeded for {CurrPlrNameColor}!"); // Inform the task it should cancel its thinking ts.Cancel(); // Set task to null aiTask = null; // The AI player that was overdue loses the game this.Result = board.Turn == PColor.White ? Winner.Red : Winner.White; OnMatchOver(); } } } }
/// <summary> /// This method will be called before a match starts and is used for /// instantiating a new <see cref="RandomAIThinker"/>. /// </summary> /// <seealso cref="AIPlayer.Setup"/> public override void Setup() { thinker = new RandomAIThinker(); }
public override void Setup() { base.Awake(); thinker = new G0A1Thinker(); }
/// <summary> /// This method will be called before a match starts and is used for /// instantiating a new <see cref="LoserSleeperAIThinker"/>. /// </summary> /// <seealso cref="AIPlayer.Setup"/> public override void Setup() { thinker = new LoserSleeperAIThinker(); }
// Update is called once per frame private void Update() { // Don't run update if the game's over if (matchOver) { return; } // Is the current player human? If so, let's see if we're supposed // to show him a message or if we've done so already if (matchData.CurrentThinker is HumanThinker) { if (showHumanTurnMessage) { view.SubmitMessage( $"Attention {CurrPlrNameColor}, it's your turn"); showHumanTurnMessage = false; } ; } // If the current player is an AI, let's see if we have to start // the AI thinking task, if the task is running, if it's completed, // etc. else { // If the AI task is null, we need to start an AI thinking task if (aiTask == null) { // Submit a message informing the user the AI is thinking view.SubmitMessage( $"{CurrPlrNameColor} is thinking, please wait..."); // Keep note of task start time (both system time and game // time) stopwatch.Restart(); taskStartGameTime = Time.time; // Create a new task cancellation token, so task can be // interrupted ts = new CancellationTokenSource(); // Get this AI's thinker thinker = matchData.CurrentThinker; // Start task in a separate thread using a copy of the // board aiTask = Task.Run( () => thinker.Think(board.Copy(), ts.Token)); } else // This else will run if the task is not null { // Did the task throw an exception? if (aiTask.IsFaulted) { // If so, notify user view.SubmitMessage(string.Format( "{0} exception: {1}", CurrPlrNameColor, aiTask.Exception.InnerException.Message)); // Send a cancellation token to the task in the hope it // might actually terminate ts.Cancel(); // Set task to null aiTask = null; // The AI player that throwed the exception will lose // the game, sorry OnMatchOver(board.Turn.Other().ToWinner()); } // Is the AI thinking task completed in time? else if (aiTask.IsCompleted && cancellationStopwatch == null) { // Register task duration, if we haven't done so yet if (float.IsNaN(lastTaskDuration)) { lastTaskDuration = (float)( stopwatch.ElapsedTicks / (double)(TimeSpan.TicksPerSecond)); } // Did we pass the minimum time between AI moves? if (Time.time > taskStartGameTime + matchConfig.MinMoveTimeSeconds) { // Get the move chosen by the thinker FutureMove move = aiTask.Result; // Was the thinker able to chose a move? if (move.IsNoMove) { // Thinker was not able to chose a move, // submit a message informing user of this view.SubmitMessage(string.Format( "{0} unable to perform move", CurrPlrNameColor)); // The AI player unable to move will lose // the game, sorry OnMatchOver(board.Turn.Other().ToWinner()); } else { try { // If so, submit a message informing of // the move chosen and the system time it // took the AI to think view.SubmitMessage(string.Format( "{0} placed a {1} piece at column {2} after {3}", CurrPlrNameColor, aiTask.Result.shape.ToString().ToLower(), aiTask.Result.column, $"thinking for {lastTaskDuration:f4}s")); // Player was able to make a move decision, // let's perform the actual move MakeAMove(aiTask.Result); } catch (Exception e) { // The act of making an actual move caused // an exception, which means the thinker // chose an invalid move, as such, // notify user of this view.SubmitMessage(string.Format( "{0} exception: {1}", CurrPlrNameColor, e.Message)); // The AI player that caused the exception // will lose the game, sorry OnMatchOver(board.Turn.Other().ToWinner()); } } // Set the task to null, so it can be // started again aiTask = null; // Reset the last task duration lastTaskDuration = float.NaN; } } // Is the task overdue? else if (stopwatch.Elapsed > aiTimeLimit) { // If so, check the status of the thinking cancellation // process if (cancellationStopwatch is null) { // The thinking cancellation process has not yet // been started, so let's start it // Inform user that the time limit for // the current thinker has been exceeded view.SubmitMessage( $"Time limit exceeded for {CurrPlrNameColor}!"); // Notify task it should cancel its thinking ts.Cancel(); // Start cancellation stopwatch cancellationStopwatch = Stopwatch.StartNew(); } else if (aiTask.IsCompleted) { // The thinking task is completed after the // cancelation request, terminate match normally // Set task to null aiTask = null; // Set cancellation stopwatch to null cancellationStopwatch = null; // The AI player that was overdue loses the game OnMatchOver(board.Turn.Other().ToWinner()); } else if (cancellationStopwatch.ElapsedMilliseconds > UncooperativeThinkerException.HardThinkingLimitMs) { UnityEngine.Debug.LogWarning($"{cancellationStopwatch.ElapsedMilliseconds}ms have passed :("); // If the hard thinking process time limit has been // reached, throw an exception to terminate the app throw new UncooperativeThinkerException(thinker); } } } } }
public override void Setup() { base.Awake(); thinker = new G06KiwIAThinker(depth); }
/// @copydoc ColorShapeLinks.TextBased.Lib.IThinkerListener.ListenTo /// <seealso cref="ColorShapeLinks.TextBased.Lib.IThinkerListener.ListenTo"/> public void ListenTo(IThinker subject) { subject.ThinkingInfo += ThinkingInfo; }
public static void Add(IThinker toAdd) { _processQueue.Add(toAdd); }