public OddmentTable <int> Create(SearchContext <object, TicTacToeState, TicTacToeMove, object, TicTacToeMove> context, int samplesForGeneration) { var table = new Dictionary <int, double>(); for (var i = 0; i < samplesForGeneration; i++) { var action = new TicTacToeMove(TicTacToeMoveGenerator.AllEmptyPositions(context.Source).RandomElementOrDefault(), context.Source.ActivePlayerID); var newState = GameLogic.Apply(context, (TicTacToeState)context.Source.Copy(), action); var endState = PlayoutStrategy.Playout(context, newState); var value = EvaluationStrategy.Evaluate(context, new TreeSearchNode <TicTacToeState, TicTacToeMove>(action), endState); if (!table.ContainsKey(action.PositionToPlace)) { table.Add(action.PositionToPlace, 0); } table[action.PositionToPlace] += value; } var maxValue = table.Values.Max(); var minValue = table.Values.Min(); var oddmentTable = new OddmentTable <int>(); foreach (var kvPair in table) { var normalisedValue = Util.Normalise(kvPair.Value, minValue, maxValue); oddmentTable.Add(kvPair.Key, normalisedValue, recalculate: false); } oddmentTable.Recalculate(); return(oddmentTable); }
/// <summary> /// Selects the best half of a collection of actions by evaluating them based on the provided search context. /// </summary> /// <param name="context">The current search context.</param> /// <param name="actions">The collection of actions to filter.</param> /// <param name="samplesPerAction">How many samples to run per action.</param> /// <returns>Collection of actions which Count is half of the original collection, rounded up. This collection is ordered by descending value.</returns> private List <ActionValue> SelectBestHalf(SearchContext <D, P, A, S, A> context, IReadOnlyCollection <ActionValue> actions, int samplesPerAction) { var clone = context.Cloner; // Evaluate each action by running a playout for it. foreach (var item in actions) { var tempNode = new N { Payload = item.Action }; var newState = GameLogic.Apply(context, clone.Clone(context.Source), item.Action); double value = 0; for (var i = 0; i < samplesPerAction; i++) { try { var endState = Playout.Playout(context, clone.Clone(newState)); value += Evaluation.Evaluate(context, tempNode, endState); SamplesUsedEvaluation++; } catch (Exception e) { //Console.WriteLine($"ERROR: {e.GetType()} while cloning state."); // TODO fix // Cloning here seems to very seldom cause a NullReference in the SabberStone dll // I believe failing and just using 0 as a value here is acceptable } } item.Value = value; } // Return the half with the highest value. var half = (int)Math.Max(1, Math.Ceiling(actions.Count / 2.0)); return(actions.OrderByDescending(i => i.Value).Take(half).ToList()); }