mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-12-22 14:12:27 +01:00
77 lines
4.1 KiB
TypeScript
77 lines
4.1 KiB
TypeScript
import { PlayerObject } from "../../src/PersonObjects/Player/PlayerObject";
|
|
import { Server } from "../../src/Server/Server";
|
|
import { calculateServerGrowth } from "../../src/Server/formulas/grow";
|
|
import { numCycleForGrowthCorrected } from "../../src/Server/ServerHelpers";
|
|
|
|
test("Grow is accurate", () => {
|
|
// Tests that certain special values work out to exactly what we'd expect,
|
|
// given the formulas. The growth multiplier maxes out at 1.0035, and the
|
|
// increment is .03 so with a difficulty of 10 it should be .003.
|
|
// These tests are *exact* because the whole point is that the math should
|
|
// get exactly the right value (or as close as is possible with floating-point).
|
|
const server = new Server({ hostname: "foo", hackDifficulty: 5, serverGrowth: 100 });
|
|
const player = new PlayerObject();
|
|
expect(calculateServerGrowth(server, 1, player)).toBe(1.0035);
|
|
expect(calculateServerGrowth(server, 2, player)).toBe(1.00701225);
|
|
server.hackDifficulty = 10;
|
|
expect(calculateServerGrowth(server, 1, player)).toBe(1.003);
|
|
expect(calculateServerGrowth(server, 2, player)).toBe(1.006009);
|
|
expect(calculateServerGrowth(server, 3, player)).toBe(1.009027027);
|
|
expect(calculateServerGrowth(server, 4, player)).toBe(1.012054108081);
|
|
});
|
|
|
|
describe("numCycleForGrowthCorrected reverses calculateServerGrowth", () => {
|
|
// Test that numCycleForGrowthCorrected() functions properly as the inverse
|
|
// of calculateServerGrowth().
|
|
// calculateServerGrowth() works for *any* given number of threads, but is
|
|
// usually passed an integer. numCycleForGrowthCorrected() *always* returns
|
|
// an integer, the ceiling of the floating-point value. When reversing an
|
|
// integer number of threads, it should *always* return the same integer.
|
|
// Similarly, if we pass the next-highest representable number as a target,
|
|
// it should *always* return the next largest integer, since the previous
|
|
// number is no longer sufficient.
|
|
|
|
// This is an arbitrary transcedental constant.
|
|
const multiplier = Math.exp(1.4);
|
|
const server = new Server({ hostname: "foo", hackDifficulty: 10 * multiplier, serverGrowth: 100 });
|
|
server.moneyMax = 1e308; // Not available as a constructor param
|
|
const player = new PlayerObject();
|
|
const tests = [];
|
|
while (server.moneyAvailable < 5e49) {
|
|
tests.push(server.moneyAvailable);
|
|
server.moneyAvailable = (server.moneyAvailable + 59) * calculateServerGrowth(server, 59, player);
|
|
}
|
|
test.each(tests)("startMoney: %f", (money: number) => {
|
|
// Do fewer threads to save on test time
|
|
for (let threads = 0; threads < 30; threads++) {
|
|
const newMoney = (money + threads) * calculateServerGrowth(server, threads, player);
|
|
const eps = newMoney ? 2 ** (Math.floor(Math.log2(newMoney)) - 52) : Number.MIN_VALUE;
|
|
expect(numCycleForGrowthCorrected(server, newMoney, money, 1, player)).toBe(threads);
|
|
const value = numCycleForGrowthCorrected(server, newMoney + eps, money, 1, player);
|
|
// Write our own check because Jest is a goblin that can't provide context
|
|
if (value !== threads + 1) {
|
|
throw new Error(
|
|
`value (${value}) was not equal to threads+1 (${threads + 1})\n\n` +
|
|
`newMoney: ${newMoney} eps: ${eps} newMoney+eps: ${newMoney + eps} value: ${value} threads: ${threads}`,
|
|
);
|
|
}
|
|
}
|
|
});
|
|
const tests2 = [];
|
|
for (let t = 0; t <= 900000; t += 2000) {
|
|
tests2.push([t, t * calculateServerGrowth(server, t, player)]);
|
|
}
|
|
test.each(tests2)("threads: %f newMoney: %f", (threads: number, newMoney: number) => {
|
|
const eps = newMoney ? 2 ** (Math.floor(Math.log2(newMoney)) - 52) : Number.MIN_VALUE;
|
|
expect(numCycleForGrowthCorrected(server, newMoney, 0, 1, player)).toBe(threads);
|
|
const value = numCycleForGrowthCorrected(server, newMoney + eps, 0, 1, player);
|
|
// Write our own check because Jest is a goblin that can't provide context
|
|
if (value !== threads + 1) {
|
|
throw new Error(
|
|
`value (${value}) was not equal to threads+1 (${threads + 1})\n\n` +
|
|
`newMoney: ${newMoney} eps: ${eps} newMoney+eps: ${newMoney + eps} value: ${value} threads: ${threads}`,
|
|
);
|
|
}
|
|
});
|
|
});
|