private (string option, StateOption optionData)? PickOption(DrawState state) { var options = _gameProcessor.GetCurrentOptionsFullDrawData(gameState, game).Where(a => !game.Metadata.PermanentButtons.Any(b => b.ButtonText == a.option)).ToList(); if (options == null || options.Count == 0) { return(null); } options.ForEach(a => { if (options.Count(b => b.option.ToLower() == a.option.ToLower()) > 1) { data.WarningMessage($"Found a state with two or more options with the same text '{a}' at state with text '{new string(state.StateText.Take(150).ToArray())}'", gameState.Clone()); } }); // Select the option with the fewest times chosen //(StateOption option, string message, int timesChosen) minValue = (options[0].optionData, options[0].option, data.GetTimesChosen(options[0].optionData.Id)); //foreach (var opt in options) //{ // var optionTimesChosen = data.GetTimesChosen(opt.optionData.Id); // if (optionTimesChosen < minValue.timesChosen) // minValue = (opt.optionData, opt.option, optionTimesChosen); // else if (optionTimesChosen == minValue.timesChosen) // { // if (rand.Next(1) == 0) // minValue = (opt.optionData, opt.option, optionTimesChosen); // } //} // Select an option, preferring those that have been visited fewer times var chosen = WeightedRandom(options.Select(a => new WeightedRandomItem <(string option, StateOption optionData)> { Data = a, Weight = data.GetTimesChosen(a.optionData.Id) }).ToList()); return(chosen); // Full random //return options[rand.Next(options.Count)]; }
public (List <string> errors, List <string> warnings, int totalActionsDone) RunTest(DrawGame game, DateTime runUntil) { data = new GameTestData(); Random rand = new Random(); var gameState = new PlayerGameSave(); gameState.GameName = game.GameName; gameState.StateId = game.startState.Id; int totalActionsDone = 0; while (DateTime.Now <= runUntil) { try { data.StateVisited(gameState.StateId); var options = _gameProcessor.GetCurrentOptionsFullDrawData(gameState, game); if (options == null || options.Count == 0) { ReportWarning("No options found - Data:" + PrettifyData(gameState), gameState, game); gameState = new PlayerGameSave(); gameState.GameName = game.GameName; gameState.StateId = game.startState.Id; continue; } options.ForEach(a => { if (options.Count(b => b.option.ToLower() == a.option.ToLower()) > 1) { ReportError("Found a state with two or more options with the same text: " + a, gameState, game); } }); (StateOption option, string message, int timesChosen)minValue = (options[0].optionData, options[0].option, data.GetTimesChosen(options[0].optionData.Id)); foreach (var opt in options) { var optionTimesChosen = data.GetTimesChosen(opt.optionData.Id); if (optionTimesChosen < minValue.timesChosen) { minValue = (opt.optionData, opt.option, optionTimesChosen); } else if (optionTimesChosen == minValue.timesChosen) { if (rand.Next(1) == 0) { minValue = (opt.optionData, opt.option, optionTimesChosen); } } } var optionToExecute = options[rand.Next(options.Count)]; var execResult = _gameProcessor.ProcessMessage(optionToExecute.option, gameState, game); execResult.StatesVisited.ForEach(a => data.StateVisited(a)); data.OptionChosen(optionToExecute.optionData.Id); totalActionsDone++; } catch (Exception e) { ReportError("ERROR: " + e.Message + "\nSTACK: " + e.StackTrace + "\nDATA: " + PrettifyData(gameState), gameState, game); gameState = new PlayerGameSave(); gameState.GameName = game.GameName; gameState.StateId = game.startState.Id; continue; } } var statesNeverVisited = game.Stats.states.Select(a => a.Id).Except(data.GetAllStatesVisited()); statesNeverVisited.ToList().ForEach(a => { var state = game.FindStateById(a); errors.Add($"State never visited with text: '{(!string.IsNullOrWhiteSpace(state.StateText) && state.StateText.Length >= 300 ? state.StateText.Substring(0, 300) : state.StateText)}'"); }); return(errors.ToList(), warnings.ToList(), totalActionsDone); }