private void ChanceInternal(double rankprob, double probStoppingHere, double rankBonus, double leSkillEffect, double plusBonus, double targetPValue, ref double maxContributionThisRound, List <double> expectations, StableSummer probabilities) { double prob = rankprob * probStoppingHere; // TODO: Properly handle the 2x rounding that happens // first, calculates basepower * rankbonus * quality double expectedPAt100NoPlusbonus = BasePower(a.bbLevel + this.NumBBP) * rankBonus; double expectedPAtLowEndNoPlusbonus = Math.Round(expectedPAt100NoPlusbonus * leSkillEffect); double expectedPAtHighEndNoPlusbonus = Math.Round(expectedPAt100NoPlusbonus * (0.5 + leSkillEffect)); double expectedPAtHighEnd = Math.Round(expectedPAtHighEndNoPlusbonus * plusBonus); if (expectedPAtHighEnd > targetPValue) { double expectedPAtLowEnd = Math.Round(expectedPAtLowEndNoPlusbonus * plusBonus); double value; if (expectedPAtLowEnd > targetPValue) { // APPROXIMATION value = SimpleExpectation(expectedPAtLowEnd, expectedPAtHighEnd); } else { // APPROXIMATION // only portion between targetPValue and expectedPAtHighEnd value = SimpleExpectation(targetPValue, expectedPAtHighEnd); prob = prob * (expectedPAtHighEnd - targetPValue) / (expectedPAtHighEnd - expectedPAtLowEnd); } double contribution = prob * value; if (contribution > maxContributionThisRound) { maxContributionThisRound = contribution; } expectations.Add(contribution); probabilities.Add(prob); } }
private Tuple <double, double> ChanceOfBeatingTargetAndExpectedPIfYouDo(int gwLevel, double targetPValue) { List <double> expectations = new List <double>(); StableSummer probabilities = new StableSummer(); // start with godly ranks with 0 pluses // (no reliable reports of godly ranks ever getting pluses) double prob; double leSkillEffect = Upgrade.bsUpgrades[(int)UpgradeID.BSSKILL & 127][a.bsLevel + NumBS].value; double heSkillEffect = 0.5 + leSkillEffect; double basePower = Upgrade.bsUpgrades[(int)UpgradeID.BSBASEPOWER & 127][a.bbLevel + NumBBP].value; int rank; for (rank = firstGodlyRank; rank < overallNumberRanks; rank++) { prob = rankprobsByGwlevel[gwLevel][rank]; double expectedPAt100 = basePower * rankBonuses[rank]; double expectedPAtLowEnd = expectedPAt100 * leSkillEffect; double expectedPAtHighEnd = expectedPAt100 * heSkillEffect; // no plus bonus multiplier, makes things easy if (targetPValue < expectedPAtLowEnd) { // whole thing contributes // don't have to adjust prob // CODE IS CURRENTLY EXACT expectations.Add(prob * ExpectationOfRange(expectedPAtLowEnd, expectedPAtHighEnd)); probabilities.Add(prob); } else if (targetPValue < expectedPAtHighEnd) { // not all of the range contributes, so we have to adjust prob prob *= (expectedPAtHighEnd - targetPValue) / (expectedPAtHighEnd - expectedPAtLowEnd); // SLIGHT APPROXIMATION: // we may lose a small bit of accuracy here since something smaller than targetValue might be rounded to it expectations.Add(prob * ExpectationOfRange(targetPValue, expectedPAtHighEnd)); probabilities.Add(prob); } } // now we can do it for the mortal ranks (which can get plusbonuses after rounding) double maxContributionThisRound; // outer loop over possible plusbonuses int numPluses = 0; var modifiedPlusProbs = plusprob.Select(x => x + (a.bsLevel + this.NumBX) * .01).ToArray(); var probReachingHere = Enumerable.Repeat(1.0, plusprob.Count()); do { var probStoppingHere = probReachingHere.Zip(modifiedPlusProbs, (prh, mpp) => prh * (1 - mpp)); double plusBonus = GetPlusBonus(numPluses); maxContributionThisRound = 0; // this could be LINQed with a subfunction, zipping rankprob[gwlevel] and probStoppingHere CustomSequenceOperators.TripleForEach(rankprobsByGwlevel[gwLevel], probStoppingHere, rankBonuses, (rp, psh, rb) => ChanceInternal(rp, psh, rb, leSkillEffect, plusBonus, targetPValue, ref maxContributionThisRound, expectations, probabilities)); numPluses++; // might be faster without LINQ? probReachingHere = probReachingHere.Zip(probStoppingHere, (prh, psh) => prh - psh); } while (maxContributionThisRound > 1e-10); // all possible ranks, all possible enchantments double chance = probabilities.Sum(); return(Tuple.Create(chance, StableSum(expectations) / chance)); }