diff --git a/BoardAnalysis.cs b/BoardAnalysis.cs index ec1ae55..98be9f7 100644 --- a/BoardAnalysis.cs +++ b/BoardAnalysis.cs @@ -9,6 +9,8 @@ namespace Shogi { public static class BoardAnalysis { + private static readonly Random rng = new(); + /// /// Determine whether a king can be reached by any of the opponents pieces /// @@ -270,9 +272,10 @@ public PossibleMove(Point source, Point destination, double evaluatedFutureValue /// Use to find the best possible move in the current state of the game /// /// The maximum number of half-moves in the future to search - public static async Task EstimateBestPossibleMove(ShogiGame game, int maxDepth, CancellationToken cancellationToken) + /// Whether or not to randomise the order of moves that have the same score + public static async Task EstimateBestPossibleMove(ShogiGame game, int maxDepth, bool randomise, CancellationToken cancellationToken) { - PossibleMove[] moves = await EvaluatePossibleMoves(game, maxDepth, cancellationToken); + PossibleMove[] moves = await EvaluatePossibleMoves(game, maxDepth, randomise, cancellationToken); PossibleMove bestMove = new(default, default, game.CurrentTurnSente ? double.NegativeInfinity : double.PositiveInfinity, false, false, 0, 0, false, new()); foreach (PossibleMove potentialMove in moves) @@ -311,8 +314,9 @@ public static async Task EstimateBestPossibleMove(ShogiGame game, /// Evaluate each possible move in the current state of the game /// /// The maximum number of half-moves in the future to search + /// Whether or not to randomise the order of moves that have the same score /// An array of all possible moves, with information on board value and ability to checkmate - public static async Task EvaluatePossibleMoves(ShogiGame game, int maxDepth, CancellationToken cancellationToken) + public static async Task EvaluatePossibleMoves(ShogiGame game, int maxDepth, bool randomise, CancellationToken cancellationToken) { List> evaluationTasks = new(); @@ -410,8 +414,14 @@ public static async Task EvaluatePossibleMoves(ShogiGame game, i } try { + IEnumerable moves = + (await Task.WhenAll(evaluationTasks)).Where(m => m.Source != m.Destination); + if (randomise) + { + return moves.OrderBy(_ => rng.Next()).ToArray(); + } // Remove default moves from return value - return (await Task.WhenAll(evaluationTasks)).Where(m => m.Source != m.Destination).ToArray(); + return moves.ToArray(); } catch (TaskCanceledException) { diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs index dc6b9aa..044499e 100644 --- a/MainWindow.xaml.cs +++ b/MainWindow.xaml.cs @@ -534,7 +534,7 @@ private void UpdateEvaluationMeter(BoardAnalysis.PossibleMove? bestMove, bool se { BoardAnalysis.PossibleMove? bestMove = null; // Search deeper in minishogi games - bestMove ??= await BoardAnalysis.EstimateBestPossibleMove(game, game.Board.GetLength(0) == 5 ? 4 : 3, cancellationToken); + bestMove ??= await BoardAnalysis.EstimateBestPossibleMove(game, game.Board.GetLength(0) == 5 ? 4 : 3, true, cancellationToken); return bestMove.Value; }