States Module - Diplomacy Missing Statistics (NaN Cascade)
Summary
In the states module, the generateDiplomacy() function attempts to access the state area metric. However, area is only calculated later in the pipeline via the collectStatistics() method. This results in area being undefined during diplomacy generation, causing all area-based logic to silently fail with NaN comparisons.
Problem
In JavaScript, trying to perform math on undefined variables results in NaN (Not a Number). Any logical comparison against NaN (e.g., NaN > 5, NaN < NaN, NaN == NaN) strictly evaluates to false.
The state generation pipeline executes in this order:
// Inside States.generate()
pack.states = this.createStates(); // State objects are created, but 'area' is not initialized
this.expandStates();
this.normalize();
this.getPoles();
this.findNeighbors();
this.assignColors();
this.generateCampaigns();
this.generateDiplomacy(); // Math is performed using state.area here!
However, collectStatistics(), which actually calculates and assigns the area value, is not called until much later in the global generation sequence:
// Global map generation pipeline
Burgs.generate();
States.generate();
Routes.generate();
Religions.generate();
Burgs.specify();
States.collectStatistics(); // <--- 'area' is finally assigned here
States.defineStateForms();
Because collectStatistics() runs after generateDiplomacy(), state.area is undefined. This triggers a catastrophic cascade of NaN values:
d3.mean(valid.map(s => s.area!)) // evaluates to NaN
ap = states[attacker].area! * states[attacker].expansionism // evaluates to NaN
dp += states[d].area! * states[d].expansionism // evaluates to NaN
The Consequence: Massive chunks of the generateDiplomacy algorithm are essentially dead code.
-
Defenders will never break defense pacts out of fear (ap / dp > 2 is always false).
-
Attackers will never abort an attack because the defender is too strong (ap < dp * gauss(...) is always false).
-
Vassalage assignments based on size disparity (area / area > 2) will never trigger.
Code
modules\states-generator.ts - line 364
const areaMean: number = mean(valid.map(s => s.area!)) as number; // areaMean becomes NaN
// ... later in the function ...
if (
neib &&
P(0.8) &&
states[f].area! > areaMean && // NaN > NaN is false
states[t].area! < areaMean && // NaN < NaN is false
states[f].area! / states[t].area! > 2 // NaN > 2 is false
)
status = "Vassal"; // Vassalage is never assigned based on area
Suggestion
Ensure that state.area is calculated prior to running diplomacy resolution.
The easiest fix is to move this.collectStatistics() inside the States.generate() method, placing it immediately before this.generateDiplomacy().
generate() {
TIME && console.time("generateStates");
pack.states = this.createStates();
this.expandStates();
this.normalize();
this.getPoles();
this.findNeighbors();
this.assignColors();
this.generateCampaigns();
this.collectStatistics(); // <--- Move here
this.generateDiplomacy();
TIME && console.timeEnd("generateStates");
}
However, if moving collectStatistics inside generateStates causes downstream side effects in the global pipeline, or if it needs data that is not yet calculated, a lightweight area-calculation loop should be added to the top of generateDiplomacy() instead
States Module - Diplomacy Missing Statistics (NaN Cascade)
Summary
In the states module, the
generateDiplomacy()function attempts to access the state area metric. However,areais only calculated later in the pipeline via thecollectStatistics()method. This results inareabeingundefinedduring diplomacy generation, causing all area-based logic to silently fail withNaNcomparisons.Problem
In JavaScript, trying to perform math on
undefinedvariables results inNaN(Not a Number). Any logical comparison against NaN (e.g.,NaN > 5,NaN < NaN,NaN == NaN) strictly evaluates tofalse.The state generation pipeline executes in this order:
However,
collectStatistics(), which actually calculates and assigns the area value, is not called until much later in the global generation sequence:Because
collectStatistics()runs aftergenerateDiplomacy(),state.areaisundefined. This triggers a catastrophic cascade of NaN values:The Consequence: Massive chunks of the
generateDiplomacyalgorithm are essentially dead code.Defenders will never break defense pacts out of fear (
ap / dp > 2is always false).Attackers will never abort an attack because the defender is too strong (
ap < dp * gauss(...)is always false).Vassalage assignments based on size disparity (
area / area > 2) will never trigger.Code
modules\states-generator.ts - line 364
Suggestion
Ensure that
state.areais calculated prior to running diplomacy resolution.The easiest fix is to move
this.collectStatistics()inside theStates.generate()method, placing it immediately beforethis.generateDiplomacy().However, if moving
collectStatisticsinsidegenerateStatescauses downstream side effects in the global pipeline, or if it needs data that is not yet calculated, a lightweight area-calculation loop should be added to the top ofgenerateDiplomacy()instead