BLADEBURNER: Change formula of skill cost (#1443)

This commit is contained in:
catloversg
2024-07-06 04:27:28 +07:00
committed by GitHub
parent 02f5c5b727
commit 29c54df543

View File

@@ -3,7 +3,7 @@ import type { BladeMultName, BladeSkillName } from "@enums";
import { currentNodeMults } from "../BitNode/BitNodeMultipliers"; import { currentNodeMults } from "../BitNode/BitNodeMultipliers";
import { Bladeburner } from "./Bladeburner"; import { Bladeburner } from "./Bladeburner";
import { Availability } from "./Types"; import { Availability } from "./Types";
import { PositiveInteger, PositiveSafeInteger, isPositiveInteger } from "../types"; import { PositiveInteger, isPositiveInteger } from "../types";
import { PartialRecord, getRecordEntries } from "../Types/Record"; import { PartialRecord, getRecordEntries } from "../Types/Record";
interface SkillParams { interface SkillParams {
@@ -35,30 +35,49 @@ export class Skill {
} }
calculateCost(currentLevel: number, count = 1 as PositiveInteger): number { calculateCost(currentLevel: number, count = 1 as PositiveInteger): number {
if (currentLevel + count > this.maxLvl) return Infinity; /**
* The cost of the next level: (baseCost + currentLevel * costInc) * mult. The cost needs to be an integer, so we
const recursiveMode = (currentLevel: number, count: PositiveSafeInteger): number => { * need to use Math.floor or Math.round.
if (count <= 1) { *
return Math.floor((this.baseCost + currentLevel * this.costInc) * currentNodeMults.BladeburnerSkillCost); * Note: there is no notation for Math.round, so I use \lceil and \rceil as alternatives for non-existent \lround
} else { * and \rround. When you see \lceil and \rceil, it means Math.round, not Math.ceil.
const thisUpgrade = Math.floor( *
(this.baseCost + currentLevel * this.costInc) * currentNodeMults.BladeburnerSkillCost, * In order to calculate the cost of "count" levels, we need to run a loop. "count" can be a big number, so it's
); * infeasible to calculate the cost in that way. We need to find the closed forms of:
return this.calculateCost(currentLevel + 1, (count - 1) as PositiveSafeInteger) + thisUpgrade; *
} * [1]:
}; * $$Cost = \sum_{i = CurrentLevel}^{CurrentLevel+Count-1}\lfloor ((BaseCost + i \ast CostInc) \ast Mult) \rfloor$$
*
// Use recursive mode if count is small * Or:
if (count <= 100) return recursiveMode(currentLevel, count as PositiveSafeInteger); *
// Use optimized mode if count is large * [2]:
else { * $$Cost = \sum_{i = CurrentLevel}^{CurrentLevel+Count-1}\lceil ((BaseCost + i \ast CostInc) \ast Mult) \rceil$$
//unFloored is roughly equivalent to *
//(this.baseCost + currentLevel * this.costInc) * BitNodeMultipliers.BladeburnerSkillCost * It's really hard to find the closed forms of those two equations, so we switch to these equations:
//being repeated for increasing currentLevel *
const preMult = (count * (2 * this.baseCost + this.costInc * (2 * currentLevel + count + 1))) / 2; * [3]:
const unFloored = preMult * currentNodeMults.BladeburnerSkillCost - count / 2; * $$Cost = \lfloor\sum_{i = CurrentLevel}^{CurrentLevel+Count-1} ((BaseCost + i \ast CostInc) \ast Mult) \rfloor$$
return Math.floor(unFloored); *
} * Or
*
* [4]:
* $$Cost = \lceil\sum_{i = CurrentLevel}^{CurrentLevel+Count-1} ((BaseCost + i \ast CostInc) \ast Mult) \rceil$$
*
* This means that we do the flooring/rounding at the end instead of each iterative step.
*
* [3] and [4] are not equivalent to [1] and [2] respectively, but it's much easier to find the close forms of [3]
* and [4] than [1] and [2]. After testing, we conclude that the cost calculated by [4] is a good approximation of
* [2], so we choose [4] to calculate the cost. In order to calculate the cost with a big "count", we accept the
* slight inaccuracy.
*
* The closed form of [4]:
*
* $$Cost = \lceil Count \ast Mult \ast (BaseCost + (CostInc \ast (CurrentLevel + \frac{Count - 1}{2}))) \rceil$$
*
*/
return Math.round(
count * currentNodeMults.BladeburnerSkillCost * (this.baseCost + this.costInc * (currentLevel + (count - 1) / 2)),
);
} }
canUpgrade(bladeburner: Bladeburner, count = 1): Availability<{ cost: number }> { canUpgrade(bladeburner: Bladeburner, count = 1): Availability<{ cost: number }> {