102e05c8ba
Adds a full simulation harness (game-simulation package) with greedy/random strategies, 36-metric diagnostics, multi-run orchestration via child processes, and a statistical interpreter. Includes 2.3x engine performance optimizations (research bonus caching, per-DC dirty tracking, reduced allocations in tick pipeline, single-pass loops). Fixes a critical balance bug where training pipelines stalled on insufficient VRAM would permanently block training slots — the engine never re-checked stalled pipelines, and the greedy strategy didn't pre-check VRAM requirements. This caused 20-25% of seeds to get stuck in Scale-up era. All three fixes (engine un-stalling, strategy VRAM pre-check, stalled pipeline cancellation) bring pass rate from 75% to 100% across 20 random seeds. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
100 lines
3.2 KiB
TypeScript
100 lines
3.2 KiB
TypeScript
import { TECH_TREE } from '../data/techTree';
|
|
|
|
export interface ResearchBonuses {
|
|
energyCostReduction: number;
|
|
pipelineSpeedBonus: number;
|
|
trainingSpeedBonus: number;
|
|
inferenceEfficiencyBonus: number;
|
|
tokensPerFlopBonus: number;
|
|
dataQualityBonus: number;
|
|
sdkCoverageBonus: number;
|
|
|
|
globalCapabilityBonus: number;
|
|
reasoningBonus: number;
|
|
codingBonus: number;
|
|
creativeBonus: number;
|
|
multimodalBonus: number;
|
|
agentsBonus: number;
|
|
reputationBonus: number;
|
|
|
|
safetyBonus: number;
|
|
autoScalingBonus: number;
|
|
}
|
|
|
|
const techTreeById = new Map(TECH_TREE.map(n => [n.id, n]));
|
|
|
|
let _cachedBonuses: ResearchBonuses | null = null;
|
|
let _cachedResearchCount = -1;
|
|
|
|
export function getResearchBonuses(completedResearch: string[]): ResearchBonuses {
|
|
if (_cachedBonuses && completedResearch.length === _cachedResearchCount) {
|
|
return _cachedBonuses;
|
|
}
|
|
|
|
const bonuses: ResearchBonuses = {
|
|
energyCostReduction: 0,
|
|
pipelineSpeedBonus: 0,
|
|
trainingSpeedBonus: 0,
|
|
inferenceEfficiencyBonus: 0,
|
|
tokensPerFlopBonus: 0,
|
|
dataQualityBonus: 0,
|
|
sdkCoverageBonus: 0,
|
|
globalCapabilityBonus: 0,
|
|
reasoningBonus: 0,
|
|
codingBonus: 0,
|
|
creativeBonus: 0,
|
|
multimodalBonus: 0,
|
|
agentsBonus: 0,
|
|
reputationBonus: 0,
|
|
safetyBonus: 0,
|
|
autoScalingBonus: 0,
|
|
};
|
|
|
|
for (const id of completedResearch) {
|
|
const node = techTreeById.get(id);
|
|
if (!node) continue;
|
|
|
|
for (const effect of node.effects) {
|
|
switch (effect.type) {
|
|
case 'efficiency_boost':
|
|
switch (effect.target) {
|
|
case 'training_speed': bonuses.trainingSpeedBonus += effect.value; break;
|
|
case 'inference': bonuses.inferenceEfficiencyBonus += effect.value; break;
|
|
case 'tokens_per_flop': bonuses.tokensPerFlopBonus += effect.value; break;
|
|
case 'pipeline_speed': bonuses.pipelineSpeedBonus += effect.value; break;
|
|
case 'data_quality': bonuses.dataQualityBonus += effect.value; break;
|
|
case 'sdk_coverage': bonuses.sdkCoverageBonus += effect.value; break;
|
|
case 'auto_scaling': bonuses.autoScalingBonus += effect.value; break;
|
|
}
|
|
break;
|
|
case 'capability_boost':
|
|
switch (effect.target) {
|
|
case 'all': bonuses.globalCapabilityBonus += effect.value; break;
|
|
case 'reasoning': bonuses.reasoningBonus += effect.value; break;
|
|
case 'coding': bonuses.codingBonus += effect.value; break;
|
|
case 'creative': bonuses.creativeBonus += effect.value; break;
|
|
case 'multimodal': bonuses.multimodalBonus += effect.value; break;
|
|
case 'agents': bonuses.agentsBonus += effect.value; break;
|
|
case 'reputation': bonuses.reputationBonus += effect.value; break;
|
|
}
|
|
break;
|
|
case 'cost_reduction':
|
|
if (effect.target === 'energy') bonuses.energyCostReduction += effect.value;
|
|
break;
|
|
case 'safety_boost':
|
|
bonuses.safetyBonus += effect.value;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
_cachedBonuses = bonuses;
|
|
_cachedResearchCount = completedResearch.length;
|
|
return bonuses;
|
|
}
|
|
|
|
export function resetResearchBonusCache(): void {
|
|
_cachedBonuses = null;
|
|
_cachedResearchCount = -1;
|
|
}
|