public ExactCalculator(int playerLevel, ShopProbability shopProbability, List <Unit> units) : base(shopProbability, units) { unitMatrices = new List <UnitProbabilityMatrix>() { new UnitProbabilityMatrix(playerLevel, shopProbability, units) }; }
public ApproximateCalculator(int playerLevel, ShopProbability shopProbability, List <Unit> units) : base(shopProbability, units) { unitMatrices = units.Select(unit => new UnitProbabilityMatrix(playerLevel, shopProbability, new List <Unit>() { unit })).ToList(); }
public CalculationModel(object lockToken, CalculationAccuracy accuracy, ShopProbability shopProbability, List <Unit> units) { this.lockToken = lockToken; this.shopProbability = shopProbability; this.units = units; this.accuracy = accuracy; }
public UnitProbabilityMatrix(int playerLevel, ShopProbability shopProbability, List <Unit> units) // Matrix size is the product of all units we are looking for (+1 to include the possiblity of finding 0) : base(units.Select(unit => unit.LookingFor + 1).Aggregate((count, x) => count * x)) { Units = new List <Unit>(units); ShopProbability = shopProbability; // Every possible permutation of the number of units we are looking for. // e.g. if we are looking for 3 of 2 different units, makes a list containing (0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1) var permutations = (from unit in Units select Enumerable.Range(0, unit.LookingFor + 1)).Product(); foreach (IEnumerable <int> numFound2 in permutations) { List <int> numFound = numFound2.ToList(); int index = StateIndex(numFound); Debug.Assert(index < Size); Debug.Assert(numFound.Count() == Units.Count); List <int> unitTiersFound = new List <int>(Enumerable.Repeat(0, ShopProbability.UnitPool.Count)); // First tally up how many of each tier have been found for this permutation foreach (var unit in Units.Zip(numFound, (unit, found) => new { Tier = unit.Tier, Found = found + unit.AlreadyTaken })) { unitTiersFound[unit.Tier] += unit.Found; } // For each unit in this permutation, add a transition to the matrix for finding 1 more foreach (var unit in Units.Zip(numFound, (one, two) => new Tuple <Unit, int>(one, two)).Zip(Enumerable.Range(0, Units.Count), (unit, unitIndex) => new { unit.Item1.Tier, Found = unit.Item2, Index = unitIndex })) { // If we are looking for 2 of a unit, we need to go from (1, 0), (1, 1), (1, 2) to (2, 0), (2, 1), and (2, 2). // Without this if statement, the permutation list would also trip us over the index going from (1, 2) to (1, 3) // So let's just skip that case if (unit.Found + 1 > units[unit.Index].LookingFor) { continue; } int unitsAvailable = ShopProbability.UnitPool[unit.Tier] - Units[unit.Index].AlreadyTaken - unit.Found; int totalPool = ShopProbability.GetRemainingTierPool(unit.Tier) - unitTiersFound[unit.Tier]; // Probability a single shop slot contains this unit // Cap probability to 1 in case user has done something insane with the other units taken double probability = Math.Min(ShopProbability.TierProbabilities[playerLevel][unit.Tier] * unitsAvailable / totalPool, 1); if (totalPool == 0 || probability < 0) { throw new ArgumentException("The search parameters led to a negative probability.\n\nAre you searching for more units than exist in the game?"); } // Find the matrix index corresponding to +1 of this unit List <int> numFoundPlusOne = new List <int>(numFound); numFoundPlusOne[unit.Index] += 1; int indexPlusOne = StateIndex(numFoundPlusOne); // The probability of staying at the same unit count is 1 - probability of finding any unit // Since we're only considering 1 shop slot here, the probability of finding a unit is additive if (this[index, index] == 0) { this[index, index] = 1 - probability; } else { this[index, index] -= probability; //Debug.Assert(this[index, index] >= 0); if (this[index, index] < -0.0001) { throw new ArgumentException("The search parameters led to a negative probability.\n\nAre you searching for more units than exist in the game?"); } } Debug.Assert(this[index, indexPlusOne] == 0); this[index, indexPlusOne] = probability; } } // Probability of staying in the final state (= we found every unit) is 1, since we stop buying more units at that point. int lastIndex = StateIndex(Units.Select(unit => unit.LookingFor)); Debug.Assert(this[lastIndex, lastIndex] == 0); this[lastIndex, lastIndex] = 1; }
public Calculator(ShopProbability shopProbability, List <Unit> units) { this.shopProbability = shopProbability; this.units = units; }