test(compare): trace deterministic monthly seed progression

This commit is contained in:
2026-08-03 18:57:01 +00:00
parent 3b2fd1082f
commit f16a6b6880
23 changed files with 1274 additions and 213 deletions
+78 -2
View File
@@ -42,10 +42,20 @@ function processWar(string $warSeed, General $attackerGeneral, array $rawAttacke
/** @var WarUnit[] */
$defenderList = [];
$defenderCandidateTrace = [];
foreach($defenderCityGeneralList as $defenderGeneral){
$defenderGeneral->setRawCity($rawDefenderCity);
$defenderCandidate = new WarUnitGeneral($rng, $defenderGeneral, $rawDefenderNation, false);
if(extractBattleOrder($defenderCandidate, $attacker) <= 0){
$defenderOrder = extractBattleOrder($defenderCandidate, $attacker);
$defenderCandidateTrace[] = [
'id' => $defenderGeneral->getID(),
'crew' => $defenderGeneral->getVar('crew'),
'crewtype' => $defenderGeneral->getVar('crewtype'),
'train' => $defenderGeneral->getVar('train'),
'atmos' => $defenderGeneral->getVar('atmos'),
'order' => $defenderOrder,
];
if($defenderOrder <= 0){
continue;
}
@@ -56,6 +66,14 @@ function processWar(string $warSeed, General $attackerGeneral, array $rawAttacke
$defenderList[] = $city;
}
$summarizeDefenderOrder = static function (WarUnit $unit) use ($attacker): array {
return [
'id' => $unit instanceof WarUnitGeneral ? $unit->getGeneral()->getID() : 0,
'order' => extractBattleOrder($unit, $attacker),
];
};
$defenderOrderBeforeSort = array_map($summarizeDefenderOrder, $defenderList);
usort($defenderList, function (WarUnit $lhs, WarUnit $rhs) use ($attacker) {
return - (extractBattleOrder($lhs, $attacker) <=> extractBattleOrder($rhs, $attacker));
});
@@ -85,7 +103,39 @@ function processWar(string $warSeed, General $attackerGeneral, array $rawAttacke
return $nextDefender;
};
$conquerCity = processWar_NG($warSeed, $attacker, $getNextDefender, $city);
$traceGeneralIds = getenv('REF_AI_TRACE_GENERAL_IDS');
$traceGeneralIdList = is_string($traceGeneralIds) ? explode(',', $traceGeneralIds) : [];
$traceDefender = false;
foreach ($defenderCityGeneralList as $defenderGeneral) {
if (in_array((string)$defenderGeneral->getID(), $traceGeneralIdList, true)) {
$traceDefender = true;
break;
}
}
$warTrace =
PHP_SAPI === 'cli'
&& getenv('REF_DETERMINISTIC_INSTALL_ENABLED') === '1'
&& is_string($traceGeneralIds)
&& (in_array((string)$attackerGeneral->getID(), $traceGeneralIdList, true) || $traceDefender)
? static function (array $event) use ($attackerGeneral): void {
fwrite(STDOUT, 'AI_WAR_TRACE ' . Json::encode([
'generalId' => $attackerGeneral->getID(),
'event' => $event,
]) . "\n");
}
: null;
if ($warTrace !== null) {
fwrite(STDOUT, 'AI_WAR_DEFENDER_CANDIDATE_TRACE ' . Json::encode([
'generalId' => $attackerGeneral->getID(),
'candidates' => $defenderCandidateTrace,
]) . "\n");
fwrite(STDOUT, 'AI_WAR_DEFENDER_ORDER_TRACE ' . Json::encode([
'generalId' => $attackerGeneral->getID(),
'before' => $defenderOrderBeforeSort,
'after' => array_map($summarizeDefenderOrder, $defenderList),
]) . "\n");
}
$conquerCity = processWar_NG($warSeed, $attacker, $getNextDefender, $city, $warTrace);
$attacker->applyDB($db);
@@ -157,6 +207,32 @@ function processWar(string $warSeed, General $attackerGeneral, array $rawAttacke
$defenderIncTech /= 4;
}
$traceNationIds = array_filter(explode(',', (string) getenv('REF_WAR_TECH_TRACE_NATION_IDS')), 'strlen');
if (getenv('REF_DETERMINISTIC_INSTALL_ENABLED') === '1') {
foreach ([
['side' => 'attacker', 'nation' => $rawAttackerNation, 'baseGain' => $attacker->getDead() * 0.012, 'gain' => $attackerIncTech, 'effective' => $attackerGenCnt_eff],
['side' => 'defender', 'nation' => $rawDefenderNation, 'baseGain' => $attacker->getKilled() * 0.009, 'gain' => $defenderIncTech, 'effective' => $defenderGenCnt_eff],
] as $traceEntry) {
if (!in_array((string) $traceEntry['nation']['nation'], $traceNationIds, true)) {
continue;
}
$divisor = max(GameConst::$initialNationGenLimit, $traceEntry['nation']['gennum']);
fwrite(STDOUT, 'WAR_TECH_TRACE ' . Json::encode([
'engine' => 'ref',
'nationId' => $traceEntry['nation']['nation'],
'side' => $traceEntry['side'],
'currentTech' => $traceEntry['nation']['tech'],
'baseGain' => $traceEntry['baseGain'],
'gain' => $traceEntry['gain'],
'total' => $traceEntry['nation']['gennum'],
'effective' => $traceEntry['effective'],
'divisor' => $divisor,
'delta' => $traceEntry['gain'] / $divisor,
'attackerGeneralId' => $attacker->getGeneral()->getID(),
]) . "\n");
}
}
$updateAttackerNation['tech'] = $db->sqleval(
'tech + %d',
$attackerIncTech / max(GameConst::$initialNationGenLimit, $rawAttackerNation['gennum'])