public static Army operator -(Army a, Army b) { if (a == null) { return(null); } if (b == null) { return(a); } Army result = new Army(); foreach (var kvp in a) { if (!b.ContainsKey(kvp.Key)) { result.Add(kvp.Key, a[kvp.Key]); // basically a - 0 } else { result.Add(kvp.Key, a[kvp.Key] - b[kvp.Key]); } } return(result); }
public Army Only(params TroopType[] troopTypes) { var result = new Army(); foreach (var type in this.Keys.Where((t) => troopTypes.Contains(t))) { result.Add(type, this[type]); } return(result); }
public Army OfType(UnitType unitType) { var result = new Army(); foreach (var type in this.Keys.Where((t) => Native.ArmyStats.UnitType[t] == unitType)) { result.Add(type, this[type]); } return(result); }
public Army BasedOn(TroopType troopType) { var maxSpeed = Native.ArmyStats.TravelSpeed[troopType]; var result = new Army(); foreach (var type in this.Keys.Where(type => Native.ArmyStats.TravelSpeed[type] <= maxSpeed)) { result.Add(type, this[type]); } return(result); }
public static Army operator *(Army a, double f) { if (a == null) { return(null); } Army result = new Army(); foreach (var kvp in a) { result.Add(kvp.Key, (int)Math.Round(kvp.Value * f)); } return(result); }
public static JSON.Army OfType(this JSON.Army army, JSON.UnitBuild build) { if (army == null) { return(new JSON.Army()); } var result = new JSON.Army(); foreach (var type in army.Keys) { if (Native.ArmyStats.UnitBuild[type] == build) { result.Add(type, army[type]); } } return(result); }
public static Army Max(params Army[] armies) { var result = new Army(); foreach (var army in armies.Where(a => a != null)) { foreach (var type in army.Keys) { if (!result.ContainsKey(type)) { result.Add(type, army[type]); } else if (result[type] < army[type]) { result[type] = army[type]; } } } return(result); }
public JSON.Army CalculatePossibleArmyRecruitment(TimeSpan timeSpan, List <JSON.TroopType> troopTypes, Dictionary <JSON.TroopType, int> maxCounts = null) { // Keep time span reasonable so we don't get integer overflow if (timeSpan.TotalDays > 30) { timeSpan = TimeSpan.FromDays(30); } var result = new JSON.Army(); foreach (var type in troopTypes) { result.Add(type, 0); } var typesBySource = troopTypes.GroupBy(t => Native.ArmyStats.UnitSource[t]).ToDictionary((s) => s.Key, s => s.Select(t => t)); // Simulate recruitment by time interval var interval = TimeSpan.FromHours(6); var simulatedTime = TimeSpan.Zero; int totalPop = 0; int previousPop = -1; bool ReachedCountLimit(JSON.TroopType troopType) { return(maxCounts != null && maxCounts.ContainsKey(troopType) && result[troopType] >= maxCounts[troopType]); } while (simulatedTime < timeSpan && totalPop < MaxPopulation && totalPop != previousPop) { foreach (var source in typesBySource.Keys) { var types = typesBySource[source].Where(t => !ReachedCountLimit(t)); var sumTimeSeconds = types.Sum(t => Native.ArmyStats.BaseRecruitTime[t].TotalSeconds); foreach (var type in types) { var factor = 1 - Native.ArmyStats.BaseRecruitTime[type].TotalSeconds / sumTimeSeconds; // If there's only 1 unit type for this building if (factor <= float.Epsilon) { factor = 1; } var troops = CalculatePossibleUnitRecruitment(type, interval * factor); result[type] += troops; } } if (maxCounts != null) { foreach (var type in maxCounts.Keys) { if (!result.ContainsKey(type)) { continue; } if (result[type] > maxCounts[type]) { result[type] = maxCounts[type]; } } } // Keep track of previous/total in case we reach max counts before time limit or pop limit are reached // (otherwise we may get infinite loop) previousPop = totalPop; totalPop = Native.ArmyStats.CalculateTotalPopulation(result); simulatedTime += interval; } return(result); }