test(compare): trace deterministic monthly seed progression
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace sammo;
|
||||
|
||||
if (PHP_SAPI !== 'cli' || getenv('REF_DETERMINISTIC_INSTALL_ENABLED') !== '1') {
|
||||
http_response_code(404);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
chdir(dirname(__DIR__));
|
||||
require_once 'lib.php';
|
||||
require_once 'func.php';
|
||||
|
||||
$request = json_decode(stream_get_contents(STDIN), true, flags: JSON_THROW_ON_ERROR);
|
||||
$generalIds = $request['generalIds'] ?? null;
|
||||
if (!is_array($generalIds) || $generalIds === []) {
|
||||
throw new \InvalidArgumentException('generalIds must be a non-empty array');
|
||||
}
|
||||
|
||||
$db = DB::db();
|
||||
$gameStorage = KVStorage::getStorage($db, 'game_env');
|
||||
$env = $gameStorage->getAll(true);
|
||||
$result = [];
|
||||
$includeNation = ($request['includeNation'] ?? false) === true;
|
||||
foreach ($generalIds as $generalId) {
|
||||
if (!is_int($generalId) || $generalId < 1) {
|
||||
throw new \InvalidArgumentException('generalIds must contain positive integers');
|
||||
}
|
||||
$general = General::createObjFromDB($generalId);
|
||||
if ($general->getNPCType() < 2) {
|
||||
throw new \InvalidArgumentException("general {$generalId} is not an NPC");
|
||||
}
|
||||
$ai = new GeneralAI($general);
|
||||
$nationDecision = null;
|
||||
if ($includeNation && $general->getNationID() !== 0 && $general->getVar('officer_level') >= 5) {
|
||||
$nationStorage = KVStorage::getStorage($db, $general->getNationID(), 'nation_env');
|
||||
$lastNationTurn = LastTurn::fromRaw($nationStorage->getValue("turn_last_{$general->getVar('officer_level')}"));
|
||||
$reservedNation = buildNationCommandClass(null, $general, $env, $lastNationTurn);
|
||||
$selectedNation = $ai->chooseNationTurn($reservedNation);
|
||||
$nationDecision = [
|
||||
'action' => $selectedNation->getRawClassName(),
|
||||
'args' => $selectedNation->getArg(),
|
||||
'reason' => $selectedNation->reason,
|
||||
];
|
||||
}
|
||||
$reserved = $general->getReservedTurn(0, $env);
|
||||
$selected = $ai->chooseGeneralTurn($reserved);
|
||||
$result[] = [
|
||||
'generalId' => $generalId,
|
||||
'name' => $general->getName(),
|
||||
'action' => $selected->getRawClassName(),
|
||||
'brief' => $selected->getBrief(),
|
||||
'args' => $selected->getArg(),
|
||||
'reason' => $selected->reason,
|
||||
'nationDecision' => $nationDecision,
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'year' => (int) $env['year'],
|
||||
'month' => (int) $env['month'],
|
||||
'decisions' => $result,
|
||||
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR);
|
||||
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace sammo;
|
||||
|
||||
if (PHP_SAPI !== 'cli' || getenv('REF_DETERMINISTIC_INSTALL_ENABLED') !== '1') {
|
||||
http_response_code(404);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
chdir(dirname(__DIR__));
|
||||
require_once 'lib.php';
|
||||
require_once 'func.php';
|
||||
|
||||
/** @return mixed */
|
||||
function monthlySnapshotJson(mixed $value): mixed
|
||||
{
|
||||
if (!is_string($value) || $value === '') {
|
||||
return $value;
|
||||
}
|
||||
try {
|
||||
return json_decode($value, true, flags: JSON_THROW_ON_ERROR);
|
||||
} catch (\JsonException) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
function monthlySnapshotPick(array $row, array $mapping, array $jsonColumns = []): array
|
||||
{
|
||||
$result = [];
|
||||
foreach ($mapping as $target => $source) {
|
||||
$value = $row[$source] ?? null;
|
||||
$result[$target] = in_array($source, $jsonColumns, true)
|
||||
? monthlySnapshotJson($value)
|
||||
: $value;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
$db = DB::db();
|
||||
$game = KVStorage::getStorage($db, 'game_env');
|
||||
$game->resetCache();
|
||||
$world = $game->getValues([
|
||||
'scenario', 'year', 'month', 'turnterm', 'turntime', 'starttime',
|
||||
'init_year', 'init_month', 'develcost', 'killturn', 'isunited',
|
||||
]);
|
||||
|
||||
$generals = [];
|
||||
foreach ($db->query('SELECT * FROM general ORDER BY no') as $row) {
|
||||
$general = monthlySnapshotPick($row, [
|
||||
'id' => 'no', 'name' => 'name', 'nationId' => 'nation', 'cityId' => 'city',
|
||||
'troopId' => 'troop', 'leadership' => 'leadership', 'strength' => 'strength',
|
||||
'intelligence' => 'intel', 'experience' => 'experience', 'dedication' => 'dedication',
|
||||
'officerLevel' => 'officer_level', 'injury' => 'injury', 'gold' => 'gold',
|
||||
'rice' => 'rice', 'crew' => 'crew', 'crewTypeId' => 'crewtype', 'train' => 'train',
|
||||
'atmos' => 'atmos', 'age' => 'age', 'npcState' => 'npc', 'turnTime' => 'turntime',
|
||||
'recentWarTime' => 'recent_war', 'lastTurn' => 'last_turn', 'meta' => 'aux',
|
||||
'affinity' => 'affinity', 'birthYear' => 'bornyear', 'deathYear' => 'deadyear',
|
||||
'personality' => 'personal', 'specialDomestic' => 'special', 'specialWar' => 'special2',
|
||||
'specAge' => 'specage', 'specAge2' => 'specage2',
|
||||
'dex1' => 'dex1', 'dex2' => 'dex2', 'dex3' => 'dex3', 'dex4' => 'dex4', 'dex5' => 'dex5',
|
||||
'killTurn' => 'killturn',
|
||||
], ['last_turn', 'aux']);
|
||||
foreach (['id', 'nationId', 'cityId', 'troopId', 'leadership', 'strength', 'intelligence',
|
||||
'experience', 'dedication', 'officerLevel', 'injury', 'gold', 'rice', 'crew',
|
||||
'crewTypeId', 'train', 'atmos', 'age', 'npcState', 'dex1', 'dex2', 'dex3',
|
||||
'dex4', 'dex5', 'killTurn', 'affinity', 'birthYear', 'deathYear', 'specAge', 'specAge2'] as $key) {
|
||||
$general[$key] = (int)$general[$key];
|
||||
}
|
||||
$generals[] = $general;
|
||||
}
|
||||
|
||||
$cities = [];
|
||||
foreach ($db->query('SELECT * FROM city ORDER BY city') as $row) {
|
||||
$city = monthlySnapshotPick($row, [
|
||||
'id' => 'city', 'name' => 'name', 'nationId' => 'nation', 'level' => 'level',
|
||||
'population' => 'pop', 'populationMax' => 'pop_max', 'agriculture' => 'agri',
|
||||
'agricultureMax' => 'agri_max', 'commerce' => 'comm', 'commerceMax' => 'comm_max',
|
||||
'security' => 'secu', 'securityMax' => 'secu_max', 'supplyState' => 'supply',
|
||||
'frontState' => 'front', 'defence' => 'def', 'defenceMax' => 'def_max',
|
||||
'wall' => 'wall', 'wallMax' => 'wall_max', 'state' => 'state', 'term' => 'term',
|
||||
'trust' => 'trust', 'trade' => 'trade', 'conflict' => 'conflict',
|
||||
], ['conflict']);
|
||||
foreach (array_keys($city) as $key) {
|
||||
if ($key !== 'name' && $key !== 'conflict' && $key !== 'trust') {
|
||||
$city[$key] = (int)$city[$key];
|
||||
}
|
||||
}
|
||||
$cities[] = $city;
|
||||
}
|
||||
|
||||
$nations = [];
|
||||
foreach ($db->query('SELECT * FROM nation ORDER BY nation') as $row) {
|
||||
$nation = monthlySnapshotPick($row, [
|
||||
'id' => 'nation', 'name' => 'name', 'color' => 'color', 'capitalCityId' => 'capital',
|
||||
'gold' => 'gold', 'rice' => 'rice', 'tech' => 'tech', 'level' => 'level',
|
||||
'typeCode' => 'type', 'generalCount' => 'gennum', 'power' => 'power',
|
||||
'war' => 'war', 'diplomacyLimit' => 'surlimit', 'capitalRevision' => 'capset',
|
||||
'strategicCommandLimit' => 'strategic_cmd_limit', 'rate' => 'rate',
|
||||
'rateTmp' => 'rate_tmp', 'bill' => 'bill', 'meta' => 'aux',
|
||||
], ['aux']);
|
||||
foreach (['id', 'capitalCityId', 'gold', 'rice', 'level', 'generalCount',
|
||||
'power', 'war', 'diplomacyLimit', 'capitalRevision', 'strategicCommandLimit',
|
||||
'rate', 'rateTmp', 'bill'] as $key) {
|
||||
$nation[$key] = (int)$nation[$key];
|
||||
}
|
||||
$nation['tech'] = (float)$nation['tech'];
|
||||
$nations[] = $nation;
|
||||
}
|
||||
|
||||
$diplomacy = [];
|
||||
foreach ($db->query('SELECT me, you, state, term, dead FROM diplomacy ORDER BY me, you') as $row) {
|
||||
$diplomacy[] = [
|
||||
'fromNationId' => (int)$row['me'], 'toNationId' => (int)$row['you'],
|
||||
'state' => (int)$row['state'], 'term' => (int)$row['term'], 'dead' => (int)$row['dead'],
|
||||
];
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'schemaVersion' => 1,
|
||||
'engine' => 'ref',
|
||||
'world' => $world,
|
||||
'generals' => $generals,
|
||||
'cities' => $cities,
|
||||
'nations' => $nations,
|
||||
'diplomacy' => $diplomacy,
|
||||
], JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRESERVE_ZERO_FRACTION), PHP_EOL;
|
||||
@@ -181,6 +181,7 @@ function comparisonRowsById(string $table, string $idColumn, array $ids): array
|
||||
|
||||
function comparisonTurnStateSnapshot(array $request): array
|
||||
{
|
||||
$db = DB::db();
|
||||
$observe = $request['observe'] ?? [];
|
||||
if (!is_array($observe)) {
|
||||
throw new \InvalidArgumentException('observe must be an object');
|
||||
@@ -188,6 +189,15 @@ function comparisonTurnStateSnapshot(array $request): array
|
||||
$generalIds = comparisonIntegerList($observe['generalIds'] ?? [], 'generalIds');
|
||||
$cityIds = comparisonIntegerList($observe['cityIds'] ?? [], 'cityIds');
|
||||
$nationIds = comparisonIntegerList($observe['nationIds'] ?? [], 'nationIds');
|
||||
if (($observe['allGenerals'] ?? false) === true) {
|
||||
$generalIds = array_map('intval', $db->queryFirstColumn('SELECT no FROM general ORDER BY no'));
|
||||
}
|
||||
if (($observe['allCities'] ?? false) === true) {
|
||||
$cityIds = array_map('intval', $db->queryFirstColumn('SELECT city FROM city ORDER BY city'));
|
||||
}
|
||||
if (($observe['allNations'] ?? false) === true) {
|
||||
$nationIds = array_map('intval', $db->queryFirstColumn('SELECT nation FROM nation ORDER BY nation'));
|
||||
}
|
||||
$logAfterId = $observe['logAfterId'] ?? 0;
|
||||
$messageAfterId = $observe['messageAfterId'] ?? 0;
|
||||
$includeNationHistoryLogs = $observe['includeNationHistoryLogs'] ?? false;
|
||||
@@ -219,7 +229,6 @@ function comparisonTurnStateSnapshot(array $request): array
|
||||
throw new \InvalidArgumentException('includeGlobalHistoryLogs must be a boolean');
|
||||
}
|
||||
|
||||
$db = DB::db();
|
||||
$game = KVStorage::getStorage($db, 'game_env');
|
||||
$game->resetCache();
|
||||
$worldValues = $game->getValues([
|
||||
|
||||
Reference in New Issue
Block a user