private static LeaderPipResult DistributePips(double averageBasePips, LeaderPipModifiers leaderPipModifiers) { double remainingPips = averageBasePips; var result = new LeaderPipResult(); while (remainingPips > 10) { remainingPips -= 4; result.Fire++; result.Shock++; result.Maneuver++; result.Siege++; } result.AddGuaranteedPips(leaderPipModifiers ?? new LeaderPipModifiers()); // The approximation here is that these percentages don't reflect pip overflow from maxed out categories result.Fire += Math.Round(0.3 * remainingPips, 2); result.Shock += Math.Round(0.3 * remainingPips, 2); result.Maneuver += Math.Round(0.3 * remainingPips, 2); result.Siege += Math.Round(0.1 * remainingPips, 2); result.Fire = result.Fire > LeaderConstants.MaxPipsInCategory ? LeaderConstants.MaxPipsInCategory : result.Fire; result.Shock = result.Shock > LeaderConstants.MaxPipsInCategory ? LeaderConstants.MaxPipsInCategory : result.Shock; result.Maneuver = result.Maneuver > LeaderConstants.MaxPipsInCategory ? LeaderConstants.MaxPipsInCategory : result.Maneuver; result.Siege = result.Siege > LeaderConstants.MaxPipsInCategory ? LeaderConstants.MaxPipsInCategory : result.Siege; return(result); }
public async Task SimulateRulerGeneralPipsAsync( [Summary("Army tradition (0-100)")] double tradition, [Summary("Ruler military skill (0-6)")] int militarySkill, [Summary("Guaranteed pips (0-6 in each category), formatted like 'fire=1,maneuver=2'")] LeaderPipModifiers pipModifiers = null) { if (!LeaderValidator.IsTraditionValid(tradition, out string traditionError)) { await ReplyAsync($"Argument error: {traditionError}."); return; } if (!LeaderValidator.IsRulerMilitarySkillValid(militarySkill, out string militarySkillError)) { await ReplyAsync($"Argument error: {militarySkillError}."); return; } var leaderPipResult = await Task.Run(() => leaderPipService.CalculateAverageLeaderPipsAsync( tradition, LeaderType.General, new LeaderPipSimulationStrategy(), pipModifiers)); await ReplyAsync($"Average general pips: Fire {leaderPipResult.Fire}, Shock {leaderPipResult.Shock}, Maneuver {leaderPipResult.Maneuver}, Siege {leaderPipResult.Siege}"); }
public static void AddGuaranteedPips(this LeaderPipResult leaderPipResult, LeaderPipModifiers leaderPipModifiers) { AddGuaranteedPipsSingleCategory(() => leaderPipResult.Fire, x => leaderPipResult.Fire = x, leaderPipModifiers.BonusFire); AddGuaranteedPipsSingleCategory(() => leaderPipResult.Shock, x => leaderPipResult.Shock = x, leaderPipModifiers.BonusShock); AddGuaranteedPipsSingleCategory(() => leaderPipResult.Maneuver, x => leaderPipResult.Maneuver = x, leaderPipModifiers.BonusManeuver); AddGuaranteedPipsSingleCategory(() => leaderPipResult.Siege, x => leaderPipResult.Siege = x, leaderPipModifiers.BonusSiege); }
public Task <LeaderPipResult> CalculateAverageRulerLeaderPipsAsync( double tradition, int militarySkill, ILeaderPipDistributionStrategy leaderPipDistributionStrategy, LeaderPipModifiers leaderPipModifiers = null) { double effectiveTradition = CalculateRulerEffectiveTradition(tradition, militarySkill); return(CalculateAndDistributePips(leaderPipDistributionStrategy, leaderPipModifiers, effectiveTradition)); }
public Task <LeaderPipResult> CalculateAverageLeaderPipsAsync( double tradition, LeaderType leaderType, ILeaderPipDistributionStrategy leaderPipDistributionStrategy, LeaderPipModifiers leaderPipModifiers = null) { double effectiveTradition = CalculateEffectiveTradition(tradition, leaderType); return(CalculateAndDistributePips(leaderPipDistributionStrategy, leaderPipModifiers, effectiveTradition)); }
public override Task <TypeReaderResult> ReadAsync(ICommandContext context, string input, IServiceProvider services) { string[] tokens = input.Split(LeaderConstants.LeaderPipModifiersCommandDelimiter, StringSplitOptions.RemoveEmptyEntries); var leaderPipModifiers = new LeaderPipModifiers(); foreach (string token in tokens) { if (!TryParseToken(token, leaderPipModifiers)) { return(Task.FromResult(TypeReaderResult.FromError(CommandError.ParseFailed, $"Could not parse pip modifier from token {token}."))); } } return(Task.FromResult(TypeReaderResult.FromSuccess(leaderPipModifiers))); }
public static bool ArePipModifiersValid(LeaderPipModifiers leaderPipRequest, out string message) { foreach (PropertyInfo propertyInfo in typeof(LeaderPipModifiers).GetProperties()) { int value = (int)propertyInfo.GetValue(leaderPipRequest); if (value < 0 || value > 6) { message = $"Category {propertyInfo.Name} is out of range: {value}"; return(false); } } message = null; return(true); }
private bool TryParseToken(string token, LeaderPipModifiers leaderPipModifiers) { const string tokenRegex = "(fire|shock|maneuver|siege)=(\\d)"; Match match = Regex.Match(token, tokenRegex); if (!match.Success) { return(false); } if (!int.TryParse(match.Groups[2].Value, out int pipAmount)) { return(false); } switch (match.Groups[1].Value) { case "fire": leaderPipModifiers.BonusFire = pipAmount; break; case "shock": leaderPipModifiers.BonusShock = pipAmount; break; case "maneuver": leaderPipModifiers.BonusManeuver = pipAmount; break; case "siege": leaderPipModifiers.BonusSiege = pipAmount; break; default: return(false); } return(true); }
private Task <LeaderPipResult> CalculateAndDistributePips(ILeaderPipDistributionStrategy leaderPipDistributionStrategy, LeaderPipModifiers leaderPipModifiers, double effectiveTradition) { double averagePips = CalculateAveragePips(effectiveTradition); return(leaderPipDistributionStrategy.DistributePipsAsync(averagePips, leaderPipModifiers)); }
private static LeaderPipResult DistributePipsSimulation(double averageBasePips, LeaderPipModifiers leaderPipModifiers, Random random) { double remainingPips = averageBasePips; var result = new LeaderPipResult(); while (remainingPips > 10) { remainingPips -= 4; result.Fire++; result.Shock++; result.Maneuver++; result.Siege++; } result.AddGuaranteedPips(leaderPipModifiers ?? new LeaderPipModifiers()); while (remainingPips > 0) { int which = random.Next(0, 10); double amount = remainingPips >= 1 ? 1 : remainingPips; if (which == 0 && result.Siege < LeaderConstants.MaxPipsInCategory) { result.Siege += amount; remainingPips -= amount; } else if (which < 4 && result.Shock < LeaderConstants.MaxPipsInCategory) { result.Shock += amount; remainingPips -= amount; } else if (which < 7 && result.Fire < LeaderConstants.MaxPipsInCategory) { result.Fire += amount; remainingPips -= amount; } else if (result.Maneuver < LeaderConstants.MaxPipsInCategory) { result.Maneuver += amount; remainingPips -= amount; } // else go back to generating new which } return(result); }
private static LeaderPipResult RunSimulation(int iterations, double averageBasePips, LeaderPipModifiers leaderPipModifiers = null) { var random = new Random(DateTime.UtcNow.Millisecond); var result = new LeaderPipResult(); for (int i = 0; i < iterations; i++) { LeaderPipResult iterationResult = DistributePipsSimulation(averageBasePips, leaderPipModifiers, random); result.Fire += iterationResult.Fire; result.Shock += iterationResult.Shock; result.Maneuver += iterationResult.Maneuver; result.Siege += iterationResult.Siege; } result.Fire = Math.Round(result.Fire / iterations, RoundingDigits); result.Shock = Math.Round(result.Shock / iterations, RoundingDigits); result.Maneuver = Math.Round(result.Maneuver / iterations, RoundingDigits); result.Siege = Math.Round(result.Siege / iterations, RoundingDigits); return(result); }
public async Task <LeaderPipResult> DistributePipsAsync(double averageBasePips, LeaderPipModifiers leaderPipModifiers = null) { var slaveTasks = new List <Task <LeaderPipResult> >(); for (int i = 0; i < DegreeOfParallelism; i++) { slaveTasks.Add(Task.Run(() => RunSimulation(IterationsPerSlave, averageBasePips, leaderPipModifiers))); } await Task.WhenAll(slaveTasks); var result = new LeaderPipResult(); foreach (var slaveResult in slaveTasks.Select(s => s.Result)) { result.Fire += slaveResult.Fire; result.Shock += slaveResult.Shock; result.Maneuver += slaveResult.Maneuver; result.Siege += slaveResult.Siege; } result.Fire = Math.Round(result.Fire / DegreeOfParallelism, RoundingDigits); result.Shock = Math.Round(result.Shock / DegreeOfParallelism, RoundingDigits); result.Maneuver = Math.Round(result.Maneuver / DegreeOfParallelism, RoundingDigits); result.Siege = Math.Round(result.Siege / DegreeOfParallelism, RoundingDigits); return(result); }
public Task <LeaderPipResult> DistributePipsAsync(double averageBasePips, LeaderPipModifiers leaderPipModifiers = null) { return(Task.Run(() => DistributePips(averageBasePips, leaderPipModifiers))); }