Files

60 lines
3.2 KiB
JavaScript

// Plays the whole game with a bot and prints a timeline: use it to tune the pacing.
//
// npm run campaign -- <hours> [seconds-per-step] e.g. npm run campaign -- 120 10
//
// Tuning knobs can be tried without editing the data files, from the environment:
// THRESH LEGACY_EXP PASSIVE_SCALE PASSIVE_POW legacy points and passive bonus
// PERK_GROWTH legacy perk cost growth
// RP_RATE LAB_GROWTH RESEARCH_COST research
// ENDLESS_COST ENDLESS_GROWTH_ADD endless upgrades
// SHOW=<n> how many restarts to list (default 8)
import { loadContext } from './context.js';
import { runCampaign } from './campaign.js';
const ctx = loadContext();
const env = (name, fallback) => (process.env[name] === undefined ? fallback : Number(process.env[name]));
ctx.rules.legacy.threshold = env('THRESH', ctx.rules.legacy.threshold);
ctx.rules.legacy.exponent = env('LEGACY_EXP', ctx.rules.legacy.exponent);
ctx.rules.legacy.passiveScale = env('PASSIVE_SCALE', ctx.rules.legacy.passiveScale);
ctx.rules.legacy.passivePower = env('PASSIVE_POW', ctx.rules.legacy.passivePower);
ctx.rules.research.rpPerLabPerSecond = env('RP_RATE', ctx.rules.research.rpPerLabPerSecond);
ctx.rules.research.labCostGrowth = env('LAB_GROWTH', ctx.rules.research.labCostGrowth);
for (const perk of ctx.legacy) perk.costGrowth = env('PERK_GROWTH', perk.costGrowth);
for (const node of ctx.research) node.cost *= env('RESEARCH_COST', 1);
for (const line of ctx.endless) {
line.baseCost *= env('ENDLESS_COST', 1);
line.costGrowth += env('ENDLESS_GROWTH_ADD', 0);
}
const hours = Number(process.argv[2] ?? 24);
const dt = Number(process.argv[3] ?? 5);
const show = Number(process.env.SHOW ?? 8);
const sci = (n) => (n >= 1e6 ? n.toExponential(2) : n.toFixed(1));
const { state, restarts, goals, probes } = runCampaign(ctx, { hours, dt });
console.log(`Simulated ${hours} h of play (one step = ${dt} s)\n`);
for (const r of restarts.slice(0, show)) {
console.log(
` hour ${r.hour.toFixed(1).padStart(6)} restart #${String(restarts.indexOf(r) + 1).padEnd(3)} after ${String(Math.round(r.minutes)).padStart(5)} min: ${sci(r.units)} units (${sci(r.rate)}/s), +${r.points} points (total ${r.earned})`,
);
}
if (restarts.length > show) console.log(` ... ${restarts.length - show} more`);
console.log('\nHow a run starts (production per second, X minutes after a restart):');
for (const run of [...new Set(probes.map((p) => p.run))].slice(0, 6)) {
const row = probes.filter((p) => p.run === run).map((p) => `${String(p.minutes).padStart(2)} min: ${sci(p.rate)}/s`);
console.log(` run ${String(run).padEnd(3)} ${row.join(' ')}`);
}
console.log('\nGoals (hour of play when reached):');
for (const [name, hour] of goals) console.log(` ${name.padEnd(26)} ${hour.toFixed(1)} h`);
const missing = ['ALL research nodes', 'ONE perk maxed', 'ALL perks maxed'].filter((n) => !goals.has(n));
if (missing.length) console.log(` not reached in ${hours} h: ${missing.join(', ')}`);
console.log(
`\nAt the end: ${restarts.length} restarts, ${state.legacy.earned} points, ${state.research.length}/${ctx.research.length} research, ${state.labs} labs, ${state.achievements.length} achievements`,
);