merge: add full turn command comparison runner
This commit is contained in:
@@ -65,7 +65,7 @@ final class TurnComparisonTracingRNG implements RNG
|
||||
$this->calls[] = [
|
||||
'seq' => $this->sequence++,
|
||||
'operation' => $operation,
|
||||
'arguments' => $arguments,
|
||||
'arguments' => $arguments === [] ? (object)[] : $arguments,
|
||||
'result' => $result,
|
||||
];
|
||||
}
|
||||
@@ -110,6 +110,13 @@ function comparisonApplyTurnFixtureSetup(mixed $setup): void
|
||||
$game->setValue($key, $value);
|
||||
}
|
||||
$game->resetCache();
|
||||
if (array_key_exists('hiddenSeed', $world)) {
|
||||
$hiddenSeed = $world['hiddenSeed'];
|
||||
if (!is_string($hiddenSeed) || $hiddenSeed === '' || strlen($hiddenSeed) > 256) {
|
||||
throw new \InvalidArgumentException('setup.world.hiddenSeed is invalid');
|
||||
}
|
||||
UniqueConst::$hiddenSeed = $hiddenSeed;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (['nations', 'cities', 'generals', 'diplomacy'] as $collection) {
|
||||
@@ -118,6 +125,33 @@ function comparisonApplyTurnFixtureSetup(mixed $setup): void
|
||||
}
|
||||
}
|
||||
|
||||
if (($setup['isolateWorld'] ?? false) === true) {
|
||||
$generalIds = array_values(array_map(
|
||||
static fn(array $row): int => (int)$row['id'],
|
||||
$setup['generals'] ?? [],
|
||||
));
|
||||
$nationIds = array_values(array_map(
|
||||
static fn(array $row): int => (int)$row['id'],
|
||||
$setup['nations'] ?? [],
|
||||
));
|
||||
if ($generalIds === [] || $nationIds === []) {
|
||||
throw new \InvalidArgumentException('isolateWorld requires generals and nations');
|
||||
}
|
||||
$db->delete('general_turn', 'general_id NOT IN %li', $generalIds);
|
||||
$db->delete('nation_turn', 'nation_id NOT IN %li', $nationIds);
|
||||
$db->delete('troop', '1 = 1');
|
||||
$db->delete('diplomacy', '1 = 1');
|
||||
$db->delete('general', 'no NOT IN %li', $generalIds);
|
||||
$db->delete('nation', 'nation NOT IN %li', $nationIds);
|
||||
$db->update('city', [
|
||||
'nation' => 0,
|
||||
'supply' => 0,
|
||||
'front' => 0,
|
||||
'state' => 0,
|
||||
'term' => 0,
|
||||
], '1 = 1');
|
||||
}
|
||||
|
||||
foreach ($setup['nations'] ?? [] as $row) {
|
||||
if (!is_array($row) || !is_int($row['id'] ?? null) || $row['id'] < 1) {
|
||||
throw new \InvalidArgumentException('setup.nations requires positive integer ids');
|
||||
@@ -133,6 +167,7 @@ function comparisonApplyTurnFixtureSetup(mixed $setup): void
|
||||
'level' => 'level',
|
||||
'typeCode' => 'type',
|
||||
'war' => 'war',
|
||||
'diplomacyLimit' => 'surlimit',
|
||||
'generalCount' => 'gennum',
|
||||
'power' => 'power',
|
||||
]);
|
||||
@@ -187,16 +222,44 @@ function comparisonApplyTurnFixtureSetup(mixed $setup): void
|
||||
'leadership' => 'leadership',
|
||||
'strength' => 'strength',
|
||||
'intelligence' => 'intel',
|
||||
'leadershipExp' => 'leadership_exp',
|
||||
'strengthExp' => 'strength_exp',
|
||||
'intelExp' => 'intel_exp',
|
||||
'experience' => 'experience',
|
||||
'dedication' => 'dedication',
|
||||
'expLevel' => 'explevel',
|
||||
'officerLevel' => 'officer_level',
|
||||
'officerCityId' => 'officer_city',
|
||||
'injury' => 'injury',
|
||||
'age' => 'age',
|
||||
'gold' => 'gold',
|
||||
'rice' => 'rice',
|
||||
'crew' => 'crew',
|
||||
'crewTypeId' => 'crewtype',
|
||||
'train' => 'train',
|
||||
'atmos' => 'atmos',
|
||||
'dex1' => 'dex1',
|
||||
'dex2' => 'dex2',
|
||||
'dex3' => 'dex3',
|
||||
'dex4' => 'dex4',
|
||||
'dex5' => 'dex5',
|
||||
'killTurn' => 'killturn',
|
||||
'npcState' => 'npc',
|
||||
'blockState' => 'block',
|
||||
'specialDomestic' => 'special',
|
||||
'specialWar' => 'special2',
|
||||
'personality' => 'personal',
|
||||
'itemHorse' => 'horse',
|
||||
'itemWeapon' => 'weapon',
|
||||
'itemBook' => 'book',
|
||||
'itemExtra' => 'item',
|
||||
]);
|
||||
if (isset($row['meta'])) {
|
||||
$patch['aux'] = Json::encode($row['meta']);
|
||||
}
|
||||
if (isset($row['lastTurn']) && is_array($row['lastTurn'])) {
|
||||
$patch['last_turn'] = Json::encode($row['lastTurn']);
|
||||
}
|
||||
if ($patch !== []) {
|
||||
$db->update('general', $patch, 'no = %i', $row['id']);
|
||||
}
|
||||
@@ -252,6 +315,15 @@ function comparisonRunTurnCommand(array $request): array
|
||||
$environment = $gameStorage->getAll();
|
||||
$general = General::createObjFromDB($actorGeneralId);
|
||||
$turn = new TurnExecutionHelper($general);
|
||||
$general->increaseInheritancePoint(Enums\InheritanceKey::lived_month, 1);
|
||||
$preprocessRng = new RandUtil(new LiteHashDRBG(Util::simpleSerialize(
|
||||
UniqueConst::$hiddenSeed,
|
||||
'preprocess',
|
||||
(int)$environment['year'],
|
||||
(int)$environment['month'],
|
||||
$actorGeneralId,
|
||||
)));
|
||||
$turn->preprocessCommand($preprocessRng, $environment);
|
||||
$seedDomain = $kind === 'general' ? 'generalCommand' : 'nationCommand';
|
||||
$seed = Util::simpleSerialize(
|
||||
UniqueConst::$hiddenSeed,
|
||||
@@ -263,7 +335,11 @@ function comparisonRunTurnCommand(array $request): array
|
||||
);
|
||||
$tracingRng = new TurnComparisonTracingRNG(new LiteHashDRBG($seed));
|
||||
$rng = new RandUtil($tracingRng);
|
||||
if ($kind === 'general' && $action === 'che_견문') {
|
||||
\sammo\TextDecoration\SightseeingMessage::setComparisonRng($rng);
|
||||
}
|
||||
|
||||
$previousLastTurnRaw = $general->getLastTurn()->toRaw();
|
||||
if ($kind === 'general') {
|
||||
$command = buildGeneralCommandClass($action, $general, $environment, $args);
|
||||
$resultTurn = $turn->processCommand($rng, $command, false);
|
||||
@@ -276,6 +352,18 @@ function comparisonRunTurnCommand(array $request): array
|
||||
$turn->applyDB();
|
||||
unset($turn);
|
||||
$after = comparisonTurnStateSnapshot($snapshotRequest);
|
||||
$resultTurnRaw = $resultTurn->toRaw();
|
||||
$resultTerm = (int)($resultTurnRaw['term'] ?? 0);
|
||||
$preReqTurn = $command->getPreReqTurn();
|
||||
$completed = ($resultTurnRaw['command'] ?? null) === $command->getName()
|
||||
&& (
|
||||
($preReqTurn === 0 && $resultTerm === 0)
|
||||
|| (
|
||||
$preReqTurn > 0
|
||||
&& ($previousLastTurnRaw['command'] ?? null) === $command->getName()
|
||||
&& (int)($previousLastTurnRaw['term'] ?? 0) === $preReqTurn
|
||||
)
|
||||
);
|
||||
|
||||
return [
|
||||
'schemaVersion' => 1,
|
||||
@@ -287,8 +375,9 @@ function comparisonRunTurnCommand(array $request): array
|
||||
'args' => $args,
|
||||
'seedDomain' => $seedDomain,
|
||||
'outcome' => [
|
||||
'lastTurn' => $resultTurn->toRaw(),
|
||||
'lastTurn' => $resultTurnRaw,
|
||||
'commandName' => $command->getName(),
|
||||
'completed' => $completed,
|
||||
],
|
||||
],
|
||||
'before' => $before,
|
||||
|
||||
@@ -45,6 +45,14 @@ function comparisonJsonValue(mixed $value): mixed
|
||||
}
|
||||
}
|
||||
|
||||
function comparisonOptionalCode(mixed $value): ?string
|
||||
{
|
||||
if (!is_string($value) || $value === '' || $value === 'None') {
|
||||
return null;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/** @param array<string, mixed> $row */
|
||||
function comparisonPickRow(array $row, array $mapping, array $jsonKeys = []): array
|
||||
{
|
||||
@@ -97,11 +105,22 @@ function comparisonTurnStateSnapshot(array $request): array
|
||||
$db = DB::db();
|
||||
$game = KVStorage::getStorage($db, 'game_env');
|
||||
$game->resetCache();
|
||||
$worldValues = $game->getValues(['year', 'month', 'turnterm', 'turntime', 'isunited']);
|
||||
$worldValues = $game->getValues([
|
||||
'year',
|
||||
'month',
|
||||
'turnterm',
|
||||
'turntime',
|
||||
'isunited',
|
||||
'scenario',
|
||||
'init_year',
|
||||
'init_month',
|
||||
'develcost',
|
||||
]);
|
||||
|
||||
$generals = array_map(
|
||||
static fn(array $row): array => comparisonPickRow(
|
||||
$row,
|
||||
static function (array $row): array {
|
||||
$result = comparisonPickRow(
|
||||
$row,
|
||||
[
|
||||
'id' => 'no',
|
||||
'name' => 'name',
|
||||
@@ -113,6 +132,7 @@ function comparisonTurnStateSnapshot(array $request): array
|
||||
'intelligence' => 'intel',
|
||||
'experience' => 'experience',
|
||||
'dedication' => 'dedication',
|
||||
'expLevel' => 'explevel',
|
||||
'officerLevel' => 'officer_level',
|
||||
'injury' => 'injury',
|
||||
'gold' => 'gold',
|
||||
@@ -130,11 +150,36 @@ function comparisonTurnStateSnapshot(array $request): array
|
||||
'leadershipExp' => 'leadership_exp',
|
||||
'strengthExp' => 'strength_exp',
|
||||
'intelExp' => 'intel_exp',
|
||||
'dex1' => 'dex1',
|
||||
'dex2' => 'dex2',
|
||||
'dex3' => 'dex3',
|
||||
'dex4' => 'dex4',
|
||||
'dex5' => 'dex5',
|
||||
'killTurn' => 'killturn',
|
||||
'mySet' => 'myset',
|
||||
'specialDomestic' => 'special',
|
||||
'specialWar' => 'special2',
|
||||
'personality' => 'personal',
|
||||
'itemHorse' => 'horse',
|
||||
'itemWeapon' => 'weapon',
|
||||
'itemBook' => 'book',
|
||||
'itemExtra' => 'item',
|
||||
],
|
||||
['last_turn', 'aux'],
|
||||
),
|
||||
);
|
||||
foreach ([
|
||||
'specialDomestic',
|
||||
'specialWar',
|
||||
'personality',
|
||||
'itemHorse',
|
||||
'itemWeapon',
|
||||
'itemBook',
|
||||
'itemExtra',
|
||||
] as $key) {
|
||||
$result[$key] = comparisonOptionalCode($result[$key] ?? null);
|
||||
}
|
||||
return $result;
|
||||
},
|
||||
comparisonRowsById('general', 'no', $generalIds),
|
||||
);
|
||||
|
||||
@@ -185,6 +230,7 @@ function comparisonTurnStateSnapshot(array $request): array
|
||||
'generalCount' => 'gennum',
|
||||
'power' => 'power',
|
||||
'war' => 'war',
|
||||
'diplomacyLimit' => 'surlimit',
|
||||
'meta' => 'aux',
|
||||
],
|
||||
['aux'],
|
||||
@@ -298,6 +344,10 @@ function comparisonTurnStateSnapshot(array $request): array
|
||||
'tickMinutes' => (int)$worldValues['turnterm'],
|
||||
'turnTime' => (string)$worldValues['turntime'],
|
||||
'isUnited' => (int)$worldValues['isunited'],
|
||||
'scenarioId' => (int)$worldValues['scenario'],
|
||||
'initYear' => (int)$worldValues['init_year'],
|
||||
'initMonth' => (int)$worldValues['init_month'],
|
||||
'develCost' => (int)$worldValues['develcost'],
|
||||
],
|
||||
'generals' => $generals,
|
||||
'cities' => $cities,
|
||||
|
||||
@@ -17,6 +17,15 @@ class SightseeingMessage{
|
||||
const HeavyWounded = 0x2000;
|
||||
|
||||
static protected $messages = null;
|
||||
static protected ?\sammo\RandUtil $comparisonRng = null;
|
||||
|
||||
public static function setComparisonRng(?\sammo\RandUtil $rng): void
|
||||
{
|
||||
if ($rng !== null && getenv('TURN_DIFFERENTIAL_ENABLED') !== '1') {
|
||||
throw new \RuntimeException('comparison RNG is test-only');
|
||||
}
|
||||
static::$comparisonRng = $rng;
|
||||
}
|
||||
|
||||
protected static function getMessageList():array{
|
||||
/* [[속성, [
|
||||
@@ -104,9 +113,14 @@ class SightseeingMessage{
|
||||
}
|
||||
|
||||
public function pickAction():array{
|
||||
[$type, $texts] = Util::choiceRandomUsingWeightPair(static::$messages??[]);
|
||||
$text = Util::choiceRandom($texts);
|
||||
if (static::$comparisonRng !== null) {
|
||||
[$type, $texts] = static::$comparisonRng->choiceUsingWeightPair(static::$messages ?? []);
|
||||
$text = static::$comparisonRng->choice($texts);
|
||||
} else {
|
||||
[$type, $texts] = Util::choiceRandomUsingWeightPair(static::$messages??[]);
|
||||
$text = Util::choiceRandom($texts);
|
||||
}
|
||||
|
||||
return [$type, $text];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user