wip: process_war에서 defenderList 변경

- defenderList를 General[] 에서 WarUnit[]으로 변경
- extractBattleOrder를 WarUnit을 받도록 변경
This commit is contained in:
2023-05-10 02:31:43 +09:00
parent 483641bcd5
commit 486ac65767
2 changed files with 287 additions and 237 deletions
+265 -219
View File
@@ -1,4 +1,5 @@
<?php <?php
namespace sammo; namespace sammo;
use Ds\Map; use Ds\Map;
@@ -15,48 +16,48 @@ $userID = Session::getUserID();
increaseRefresh("시뮬레이터", 0); increaseRefresh("시뮬레이터", 0);
$query = Util::getPost('query'); $query = Util::getPost('query');
if($query === null){ if ($query === null) {
Json::die([ Json::die([
'result'=>false, 'result' => false,
'reason'=>'입력값이 없습니다.' 'reason' => '입력값이 없습니다.'
]); ]);
} }
$action = Util::getPost('action'); $action = Util::getPost('action');
if($action === null || !in_array($action, ['reorder', 'battle'])){ if ($action === null || !in_array($action, ['reorder', 'battle'])) {
Json::die([ Json::die([
'result'=>false, 'result' => false,
'reason'=>'원하는 동작이 지정되지 않았습니다.' 'reason' => '원하는 동작이 지정되지 않았습니다.'
]); ]);
} }
$query = Json::decode($query); $query = Json::decode($query);
if($query === null){ if ($query === null) {
Json::die([ Json::die([
'result'=>false, 'result' => false,
'reason'=>'올바르지 않은 JSON입니다.' 'reason' => '올바르지 않은 JSON입니다.'
]); ]);
} }
$defaultCheck = [ $defaultCheck = [
'required'=>[ 'required' => [
'attackerGeneral', 'attackerCity', 'attackerNation', 'attackerGeneral', 'attackerCity', 'attackerNation',
'defenderGenerals', 'defenderCity', 'defenderNation', 'defenderGenerals', 'defenderCity', 'defenderNation',
'year', 'month', 'repeatCnt' 'year', 'month', 'repeatCnt'
], ],
'integer'=>[ 'integer' => [
'year','month','repeatCnt' 'year', 'month', 'repeatCnt'
], ],
'between'=>[ 'between' => [
['month', [1, 12]] ['month', [1, 12]]
], ],
'in'=>[ 'in' => [
['repeatCnt', [1, 1000]] ['repeatCnt', [1, 1000]]
], ],
'min'=>[ 'min' => [
['year', 0] ['year', 0]
], ],
'array'=>[ 'array' => [
'attackerGeneral', 'attackerCity', 'attackerNation', 'attackerGeneral', 'attackerCity', 'attackerNation',
'defenderGenerals', 'defenderCity', 'defenderNation' 'defenderGenerals', 'defenderCity', 'defenderNation'
], ],
@@ -64,10 +65,10 @@ $defaultCheck = [
$v = new Validator($query); $v = new Validator($query);
$v->rules($defaultCheck); $v->rules($defaultCheck);
if(!$v->validate()){ if (!$v->validate()) {
Json::die([ Json::die([
'result'=>false, 'result' => false,
'reason'=>$v->errorStr() 'reason' => $v->errorStr()
]); ]);
} }
@@ -86,20 +87,110 @@ $rawDefenderNation = $query['defenderNation'];
$warSeed = $query['seed'] ?? ''; $warSeed = $query['seed'] ?? '';
$cityCheck = [
'required' => [
'city', 'nation', 'supply', 'name',
'pop', 'agri', 'comm', 'secu', 'def', 'wall',
'trust', 'level',
'pop_max', 'agri_max', 'comm_max', 'secu_max', 'def_max', 'wall_max',
'dead', 'state', 'conflict',
],
'numeric' => [
'pop', 'agri', 'comm', 'secu', 'def', 'wall', 'trust', 'dead'
],
'integer' => [
'city', 'nation', 'supply',
'pop_max', 'agri_max', 'comm_max', 'secu_max', 'def_max', 'wall_max',
'state',
],
'min' => [
['def', 0],
['wall', 0],
['trust', 0],
['pop', 0],
['comm', 0],
['secu', 0],
['city', 1],
['nation', 0]
],
'in' => [
['level', array_keys(getCityLevelList())]
]
];
$v = new Validator($rawAttackerCity);
$v->rules($cityCheck);
if (!$v->validate()) {
Json::die([
'result' => false,
'reason' => '[출병도시]' . $v->errorStr()
]);
}
$v = new Validator($rawDefenderCity);
$v->rules($cityCheck);
if (!$v->validate()) {
Json::die([
'result' => false,
'reason' => '[수비도시]' . $v->errorStr()
]);
}
$nationCheck = [
'required' => [
'type', 'tech', 'level', 'capital',
'nation', 'name', 'gold', 'rice', 'gennum'
],
'integer' => [
'level', 'capital', 'nation', 'gennum',
],
'numeric' => [
'tech', 'gold', 'rice'
],
'min' => [
['tech', 0],
['gold', 0],
['rice', 0],
['gennum', 1],
],
'in' => [
['type', GameConst::$availableNationType],
['level', array_keys(getNationLevelList())]
]
];
$v = new Validator($rawAttackerNation);
$v->rules($nationCheck);
if (!$v->validate()) {
Json::die([
'result' => false,
'reason' => '[출병국]' . $v->errorStr()
]);
}
$v = new Validator($rawDefenderNation);
$v->rules($nationCheck);
if (!$v->validate()) {
Json::die([
'result' => false,
'reason' => '[수비국]' . $v->errorStr()
]);
}
$generalCheck = [ $generalCheck = [
'required'=>[ 'required' => [
'no', 'name', 'nation', 'turntime', 'personal', 'special2', 'crew', 'crewtype', 'atmos', 'train', 'no', 'name', 'nation', 'turntime', 'personal', 'special2', 'crew', 'crewtype', 'atmos', 'train',
'intel', 'intel_exp', 'book', 'strength', 'strength_exp', 'weapon', 'injury', 'leadership', 'leadership_exp', 'horse', 'item', 'intel', 'intel_exp', 'book', 'strength', 'strength_exp', 'weapon', 'injury', 'leadership', 'leadership_exp', 'horse', 'item',
'explevel', 'experience', 'dedication', 'officer_level', 'officer_city', 'gold', 'rice', 'dex1', 'dex2', 'dex3', 'dex4', 'dex5', 'explevel', 'experience', 'dedication', 'officer_level', 'officer_city', 'gold', 'rice', 'dex1', 'dex2', 'dex3', 'dex4', 'dex5',
'recent_war', 'warnum', 'killnum', 'killcrew', 'recent_war', 'warnum', 'killnum', 'killcrew',
], ],
'integer'=>[ 'integer' => [
'no', 'nation', 'crew', 'crewtype', 'atmos', 'train', 'no', 'nation', 'crew', 'crewtype', 'atmos', 'train',
'intel', 'intel_exp', 'strength', 'strength_exp', 'injury', 'leadership', 'leadership_exp', 'intel', 'intel_exp', 'strength', 'strength_exp', 'injury', 'leadership', 'leadership_exp',
'explevel', 'experience', 'dedication', 'officer_level', 'officer_city', 'gold', 'rice', 'dex1', 'dex2', 'dex3', 'dex4', 'dex5', 'explevel', 'experience', 'dedication', 'officer_level', 'officer_city', 'gold', 'rice', 'dex1', 'dex2', 'dex3', 'dex4', 'dex5',
'warnum', 'killnum', 'killcrew', 'warnum', 'killnum', 'killcrew',
], ],
'min'=>[ 'min' => [
['no', 1], ['no', 1],
['nation', 1], ['nation', 1],
['crew', 0], ['crew', 0],
@@ -118,14 +209,14 @@ $generalCheck = [
['killnum', 0], ['killnum', 0],
['killcrew', 0], ['killcrew', 0],
], ],
'between'=>[ 'between' => [
['train', [40, GameConst::$maxTrainByWar]], ['train', [40, GameConst::$maxTrainByWar]],
['atmos', [40, GameConst::$maxAtmosByWar]], ['atmos', [40, GameConst::$maxAtmosByWar]],
['explevel', [0, 300]], ['explevel', [0, 300]],
['injury', [0, 80]], ['injury', [0, 80]],
['officer_level', [1, 12]] ['officer_level', [1, 12]]
], ],
'in'=>[ 'in' => [
['personal', array_merge(GameConst::$availablePersonality, GameConst::$optionalPersonality)], ['personal', array_merge(GameConst::$availablePersonality, GameConst::$optionalPersonality)],
['special2', array_merge(GameConst::$availableSpecialWar, GameConst::$optionalSpecialWar)], ['special2', array_merge(GameConst::$availableSpecialWar, GameConst::$optionalSpecialWar)],
['crewtype', array_keys(GameUnitConst::all())], ['crewtype', array_keys(GameUnitConst::all())],
@@ -134,11 +225,11 @@ $generalCheck = [
['book', array_merge(array_keys(GameConst::$allItems['book']), ['None'])], ['book', array_merge(array_keys(GameConst::$allItems['book']), ['None'])],
['item', array_merge(array_keys(GameConst::$allItems['item']), ['None'])], ['item', array_merge(array_keys(GameConst::$allItems['item']), ['None'])],
], ],
'array'=>['inheritBuff'], 'array' => ['inheritBuff'],
]; ];
$inheritBuffCheck = [ $inheritBuffCheck = [
'between'=>[ 'between' => [
[TriggerInheritBuff::WAR_AVOID_RATIO, [0, 5]], [TriggerInheritBuff::WAR_AVOID_RATIO, [0, 5]],
[TriggerInheritBuff::WAR_CRITICAL_RATIO, [0, 5]], [TriggerInheritBuff::WAR_CRITICAL_RATIO, [0, 5]],
[TriggerInheritBuff::WAR_MAGIC_TRIAL_PROB, [0, 5]], [TriggerInheritBuff::WAR_MAGIC_TRIAL_PROB, [0, 5]],
@@ -149,49 +240,67 @@ $inheritBuffCheck = [
] ]
]; ];
if(!$warSeed){
$warSeed = bin2hex(random_bytes(16));
}
else {
$repeatCnt = 1;
}
$tmpRNG = new RandUtil(new LiteHashDRBG($warSeed));
$v = new Validator($rawAttacker); $v = new Validator($rawAttacker);
$v->rules($generalCheck); $v->rules($generalCheck);
if(!$v->validate()){ if (!$v->validate()) {
Json::die([ Json::die([
'result'=>false, 'result' => false,
'reason'=>'[출병자]'.$v->errorStr() 'reason' => '[출병자]' . $v->errorStr()
]); ]);
} }
$rawAttacker['aux'] = []; $rawAttacker['aux'] = [];
if(key_exists('inheritBuff', $rawAttacker)){ if (key_exists('inheritBuff', $rawAttacker)) {
$v = new Validator($rawAttacker['inheritBuff']); $v = new Validator($rawAttacker['inheritBuff']);
$v->rules($inheritBuffCheck); $v->rules($inheritBuffCheck);
if(!$v->validate()){ if (!$v->validate()) {
Json::die([ Json::die([
'result'=>false, 'result' => false,
'reason'=>'[출병자]'.$v->errorStr() 'reason' => '[출병자]' . $v->errorStr()
]); ]);
} }
$rawAttacker['aux']['inheritBuff'] = $rawAttacker['inheritBuff']; $rawAttacker['aux']['inheritBuff'] = $rawAttacker['inheritBuff'];
} }
$rawAttacker['aux'] = Json::encode($rawAttacker['aux']); $rawAttacker['aux'] = Json::encode($rawAttacker['aux']);
$rawAttacker['owner'] = 0; $rawAttacker['owner'] = 0;
$attackerGeneral = new General($rawAttacker, extractRankVar($rawAttacker), $rawAttackerCity, $rawAttackerNation, $year, $month);
$attacker = new WarUnitGeneral(
$tmpRNG,
$attackerGeneral,
$rawAttackerNation,
true
);
/** @var WarUnit[] */
$defenderList = []; $defenderList = [];
foreach($rawDefenderList as $idx=>$rawDefenderGeneral){
foreach ($rawDefenderList as $idx => $rawDefenderGeneral) {
$v = new Validator($rawDefenderGeneral); $v = new Validator($rawDefenderGeneral);
$v->rules($generalCheck); $v->rules($generalCheck);
if(!$v->validate()){ if (!$v->validate()) {
$idx+=1; $idx += 1;
Json::die([ Json::die([
'result'=>false, 'result' => false,
'reason'=>"[수비자{$idx}]".$v->errorStr() 'reason' => "[수비자{$idx}]" . $v->errorStr()
]); ]);
} }
$rawDefenderGeneral['aux'] = []; $rawDefenderGeneral['aux'] = [];
if(key_exists('inheritBuff', $rawDefenderGeneral)){ if (key_exists('inheritBuff', $rawDefenderGeneral)) {
$v = new Validator($rawDefenderGeneral['inheritBuff']); $v = new Validator($rawDefenderGeneral['inheritBuff']);
$v->rules($inheritBuffCheck); $v->rules($inheritBuffCheck);
if(!$v->validate()){ if (!$v->validate()) {
$idx+=1; $idx += 1;
Json::die([ Json::die([
'result'=>false, 'result' => false,
'reason'=>"[수비자{$idx}]".$v->errorStr() 'reason' => "[수비자{$idx}]" . $v->errorStr()
]); ]);
} }
$rawDefenderGeneral['aux']['inheritBuff'] = $rawDefenderGeneral['inheritBuff']; $rawDefenderGeneral['aux']['inheritBuff'] = $rawDefenderGeneral['inheritBuff'];
@@ -199,126 +308,41 @@ foreach($rawDefenderList as $idx=>$rawDefenderGeneral){
$rawDefenderGeneral['aux'] = Json::encode($rawDefenderGeneral['aux']); $rawDefenderGeneral['aux'] = Json::encode($rawDefenderGeneral['aux']);
$rawDefenderGeneral['owner'] = 0; $rawDefenderGeneral['owner'] = 0;
$defenderList[] = new General($rawDefenderGeneral, extractRankVar($rawDefenderGeneral), $rawDefenderCity, $rawAttackerNation, $year, $month, true); $defenderGeneral = new General($rawDefenderGeneral, extractRankVar($rawDefenderGeneral), $rawDefenderCity, $rawAttackerNation, $year, $month, true);
$defenderList[] = new WarUnitGeneral(
$tmpRNG,
$defenderGeneral,
$rawDefenderNation,
false
);
} }
if ($action == 'reorder') {
$noRng = NoRNG::rngInstance();
$cityCheck = [ usort($defenderList, function (WarUnit $lhs, WarUnit $rhs) use ($attacker) {
'required'=>[ return - (extractBattleOrder($lhs, $attacker) <=> extractBattleOrder($rhs, $attacker));
'city', 'nation', 'supply', 'name',
'pop', 'agri', 'comm', 'secu', 'def', 'wall',
'trust', 'level',
'pop_max', 'agri_max', 'comm_max', 'secu_max', 'def_max', 'wall_max',
'dead', 'state', 'conflict',
],
'numeric'=>[
'pop', 'agri', 'comm', 'secu', 'def', 'wall', 'trust', 'dead'
],
'integer'=>[
'city', 'nation', 'supply',
'pop_max', 'agri_max', 'comm_max', 'secu_max', 'def_max', 'wall_max',
'state',
],
'min'=>[
['def', 0],
['wall', 0],
['trust', 0],
['pop', 0],
['comm', 0],
['secu', 0],
['city', 1],
['nation', 0]
],
'in'=>[
['level', array_keys(getCityLevelList())]
]
];
$v = new Validator($rawAttackerCity);
$v->rules($cityCheck);
if(!$v->validate()){
Json::die([
'result'=>false,
'reason'=>'[출병도시]'.$v->errorStr()
]);
}
$v = new Validator($rawDefenderCity);
$v->rules($cityCheck);
if(!$v->validate()){
Json::die([
'result'=>false,
'reason'=>'[수비도시]'.$v->errorStr()
]);
}
$nationCheck = [
'required'=>[
'type', 'tech', 'level', 'capital',
'nation', 'name', 'gold', 'rice', 'gennum'
],
'integer'=>[
'level', 'capital', 'nation', 'gennum',
],
'numeric'=>[
'tech', 'gold', 'rice'
],
'min'=>[
['tech', 0],
['gold', 0],
['rice', 0],
['gennum', 1],
],
'in'=>[
['type', GameConst::$availableNationType],
['level', array_keys(getNationLevelList())]
]
];
$v = new Validator($rawAttackerNation);
$v->rules($nationCheck);
if(!$v->validate()){
Json::die([
'result'=>false,
'reason'=>'[출병국]'.$v->errorStr()
]);
}
$v = new Validator($rawDefenderNation);
$v->rules($nationCheck);
if(!$v->validate()){
Json::die([
'result'=>false,
'reason'=>'[수비국]'.$v->errorStr()
]);
}
$attackerGeneral = new General($rawAttacker, extractRankVar($rawAttacker), $rawAttackerCity, $rawAttackerNation, $year, $month);
if($action == 'reorder'){
usort($defenderList, function(General $lhs, General $rhs) use ($attackerGeneral){
return -(extractBattleOrder($lhs, $attackerGeneral) <=> extractBattleOrder($rhs, $attackerGeneral));
}); });
$order = []; $order = [];
foreach($defenderList as $defenderGeneral){ foreach ($defenderList as $defender) {
$order[] = $defenderGeneral->getID(); $order[] = $defender->getGeneral()->getID();
} }
Json::die([ Json::die([
'result'=>true, 'result' => true,
'reason'=>'success', 'reason' => 'success',
'order'=>$order 'order' => $order
]); ]);
} }
usort($defenderList, function(General $lhs, General $rhs) use ($attackerGeneral){ usort($defenderList, function (WarUnit $lhs, WarUnit $rhs) use ($attacker) {
return -(extractBattleOrder($lhs, $attackerGeneral) <=> extractBattleOrder($rhs, $attackerGeneral)); return - (extractBattleOrder($lhs, $attacker) <=> extractBattleOrder($rhs, $attacker));
}); });
$rawDefenderList = array_map(function(General $general){ $rawDefenderList = array_map(function (WarUnit $unit) {
return $general->getRaw(); return $unit->getRaw();
}, $defenderList); }, $defenderList);
unset($defenderList); unset($defenderList);
@@ -326,11 +350,12 @@ $db = DB::db();
$gameStor = KVStorage::getStorage($db, 'game_env'); $gameStor = KVStorage::getStorage($db, 'game_env');
$startYear = $gameStor->startyear; $startYear = $gameStor->startyear;
function extractRankVar(array $rawVal):Map{ function extractRankVar(array $rawVal): Map
{
$rankVars = new Map; $rankVars = new Map;
foreach($rawVal as $rawKey=>$rawVal){ foreach ($rawVal as $rawKey => $rawVal) {
$key = RankColumn::tryFrom($rawKey); $key = RankColumn::tryFrom($rawKey);
if($key === null){ if ($key === null) {
continue; continue;
} }
$rankVars[$key] = $rawVal; $rankVars[$key] = $rawVal;
@@ -339,12 +364,19 @@ function extractRankVar(array $rawVal):Map{
} }
function simulateBattle( function simulateBattle(
$rawAttacker, $rawAttackerCity, $rawAttackerNation, $rawAttacker,
$rawDefenderList, $rawDefenderCity, $rawDefenderNation, $rawAttackerCity,
$startYear, $year, $month, $warSeed $rawAttackerNation,
){ $rawDefenderList,
$rawDefenderCity,
$rawDefenderNation,
$startYear,
$year,
$month,
$warSeed
) {
if(!$warSeed){ if (!$warSeed) {
$warSeed = bin2hex(random_bytes(16)); $warSeed = bin2hex(random_bytes(16));
} }
@@ -359,61 +391,70 @@ function simulateBattle(
); );
$city = new WarUnitCity($warRng, $rawDefenderCity, $rawDefenderNation, $year, $month, $startYear); $city = new WarUnitCity($warRng, $rawDefenderCity, $rawDefenderNation, $year, $month, $startYear);
$iterDefender = new \ArrayIterator($rawDefenderList); /** @var WarUnit[] */
$defenderList = [];
foreach ($rawDefenderList as $rawDefenderGeneral) {
$defenderGeneral = new General($rawDefenderGeneral, extractRankVar($rawDefenderGeneral), $rawDefenderCity, $rawAttackerNation, $year, $month, true);
$defenderList[] = new WarUnitGeneral(
$warRng,
$defenderGeneral,
$rawDefenderNation,
false
);
}
$defenderList[] = $city;
$iterDefender = new \ArrayIterator($defenderList);
$iterDefender->rewind(); $iterDefender->rewind();
$battleResult = []; $battleResult = [];
$attackerRice = $rawAttacker['rice']; $attackerRice = $attacker->getGeneral()->getVar('rice');
$defenderRice = 0; $defenderRice = 0;
$getNextDefender = function(?WarUnit $prevDefender, bool $reqNext) $getNextDefender = function (?WarUnit $prevDefender, bool $reqNext)
use ($warRng, $iterDefender, $rawDefenderCity, $rawDefenderNation, $year, $month, &$battleResult, &$defenderRice, $attackerGeneral) { use ($iterDefender, &$battleResult, &$defenderRice, $attacker): ?WarUnit {
if($prevDefender !== null){ if ($prevDefender !== null) {
$prevDefender->getLogger()->rollback(); $prevDefender->getLogger()->rollback();
$battleResult[] = $prevDefender; $battleResult[] = $prevDefender;
if($prevDefender instanceof WarUnitGeneral){ if ($prevDefender instanceof WarUnitGeneral) {
$defenderRice -= $prevDefender->getVar('rice'); $defenderRice -= $prevDefender->getVar('rice');
} }
} }
if(!$reqNext){ if (!$reqNext) {
return null; return null;
} }
if(!$iterDefender->valid()){ if (!$iterDefender->valid()) {
return null; return null;
} }
$defenderObj = new General($iterDefender->current(), extractRankVar($iterDefender->current()), $rawDefenderCity, $rawDefenderNation, $year, $month); /** @var WarUnit */
if(extractBattleOrder($defenderObj, $attackerGeneral) <= 0){ $defender = $iterDefender->current();
if (extractBattleOrder($defender, $attacker) <= 0) {
return null; return null;
} }
$defenderRice += $defenderObj->getVar('rice'); $defenderRice += $defender->getVar('rice');
$retVal = new WarUnitGeneral(
$warRng,
$defenderObj,
$rawDefenderNation,
false
);
$iterDefender->next(); $iterDefender->next();
return $retVal; return $defender;
}; };
$conquerCity = processWar_NG($warSeed, $attacker, $getNextDefender, $city, $year - $startYear); $conquerCity = processWar_NG($warSeed, $attacker, $getNextDefender, $city);
$rawDefenderCity = $city->getRaw();
$updateAttackerNation = [];
$updateDefenderNation = [];
$attackerRice -= $attacker->getVar('rice'); $attackerRice -= $attacker->getVar('rice');
if($city->getPhase() > 0){ if ($city->getPhase() > 0) {
$rice = $city->getKilled() / 100 * 0.8; $rice = $city->getKilled() / 100 * 0.8;
$rice *= $city->getCrewType()->rice; $rice *= $city->getCrewType()->rice;
$rice *= getTechCost($rawDefenderNation['tech']); $rice *= getTechCost($city->getRawNation()['tech']);
$rice *= $city->getCityTrainAtmos() / 100 - 0.2; $rice *= $city->getCityTrainAtmos() / 100 - 0.2;
Util::setRound($rice); Util::setRound($rice);
@@ -421,8 +462,8 @@ function simulateBattle(
} }
$totalDead = $attacker->getKilled() + $attacker->getDead(); $totalDead = $attacker->getKilled() + $attacker->getDead();
$attackerCityDead = $totalDead * 0.4; //$attackerCityDead = $totalDead * 0.4;
$defenderCityDead = $totalDead * 0.6; //$defenderCityDead = $totalDead * 0.6;
return [$attacker, $city, $battleResult, $conquerCity, $attackerRice, $defenderRice]; return [$attacker, $city, $battleResult, $conquerCity, $attackerRice, $defenderRice];
} }
@@ -448,18 +489,26 @@ $avgWar = 0;
$attackerActivatedSkills = []; $attackerActivatedSkills = [];
$defendersActivatedSkills = []; $defendersActivatedSkills = [];
if($warSeed){
$repeatCnt = 1;
}
foreach(Util::range($repeatCnt) as $repeatIdx){ foreach (Util::range($repeatCnt) as $repeatIdx) {
if($repeatIdx > 0){
$warSeed = bin2hex(random_bytes(16));
}
/** @var WarUnit $attacker */ /** @var WarUnit $attacker */
[$attacker, $city, $battleResult, $conquerCity, $attackerRice, $defenderRice] = simulateBattle( [$attacker, $city, $battleResult, $conquerCity, $attackerRice, $defenderRice] = simulateBattle(
$rawAttacker, $rawAttackerCity, $rawAttackerNation, $rawAttacker,
$rawDefenderList, $rawDefenderCity, $rawDefenderNation, $rawAttackerCity,
$startYear, $year, $month, $warSeed $rawAttackerNation,
$rawDefenderList,
$rawDefenderCity,
$rawDefenderNation,
$startYear,
$year,
$month,
$warSeed
); );
$lastWarLog = Util::mapWithKey(function($key, $values){ $lastWarLog = Util::mapWithKey(function ($key, $values) {
return ConvertLog(join('<br>', $values)); return ConvertLog(join('<br>', $values));
}, $attacker->getLogger()->rollback()); }, $attacker->getLogger()->rollback());
@@ -482,48 +531,45 @@ foreach(Util::range($repeatCnt) as $repeatIdx){
$avgWar += count($battleResult) / $repeatCnt; $avgWar += count($battleResult) / $repeatCnt;
foreach($attacker->getActivatedSkillLog() as $skillName => $skillCnt){ foreach ($attacker->getActivatedSkillLog() as $skillName => $skillCnt) {
if(!key_exists($skillName, $attackerActivatedSkills)){ if (!key_exists($skillName, $attackerActivatedSkills)) {
$attackerActivatedSkills[$skillName] = $skillCnt / $repeatCnt; $attackerActivatedSkills[$skillName] = $skillCnt / $repeatCnt;
} } else {
else{
$attackerActivatedSkills[$skillName] += $skillCnt / $repeatCnt; $attackerActivatedSkills[$skillName] += $skillCnt / $repeatCnt;
} }
} }
foreach($battleResult as $idx=>$defender){ foreach ($battleResult as $idx => $defender) {
while($idx >= count($defendersActivatedSkills)){ while ($idx >= count($defendersActivatedSkills)) {
$defendersActivatedSkills[] = []; $defendersActivatedSkills[] = [];
} }
$activatedSkills = &$defendersActivatedSkills[$idx]; $activatedSkills = &$defendersActivatedSkills[$idx];
foreach($defender->getActivatedSkillLog() as $skillName => $skillCnt){ foreach ($defender->getActivatedSkillLog() as $skillName => $skillCnt) {
if(!key_exists($skillName, $activatedSkills)){ if (!key_exists($skillName, $activatedSkills)) {
$activatedSkills[$skillName] = $skillCnt / $repeatCnt; $activatedSkills[$skillName] = $skillCnt / $repeatCnt;
} } else {
else{
$activatedSkills[$skillName] += $skillCnt / $repeatCnt; $activatedSkills[$skillName] += $skillCnt / $repeatCnt;
} }
} }
} }
} }
Json::die([ Json::die([
'result'=>true, 'result' => true,
'datetime'=>$rawAttacker['turntime'], 'datetime' => $rawAttacker['turntime'],
'reason'=>'success', 'reason' => 'success',
'lastWarLog'=>$lastWarLog, 'lastWarLog' => $lastWarLog,
'avgWar'=>$avgWar, 'avgWar' => $avgWar,
'phase'=>$avgPhase, 'phase' => $avgPhase,
'killed'=>$attackerKilled, 'killed' => $attackerKilled,
'maxKilled'=>$attackerMaxKilled, 'maxKilled' => $attackerMaxKilled,
'minKilled'=>$attackerMinKilled, 'minKilled' => $attackerMinKilled,
'dead'=>$attackerDead, 'dead' => $attackerDead,
'maxDead'=>$attackerMaxDead, 'maxDead' => $attackerMaxDead,
'minDead'=>$attackerMinDead, 'minDead' => $attackerMinDead,
'attackerRice'=>$attackerAvgRice, 'attackerRice' => $attackerAvgRice,
'defenderRice'=>$defenderAvgRice, 'defenderRice' => $defenderAvgRice,
'attackerSkills'=>$attackerActivatedSkills, 'attackerSkills' => $attackerActivatedSkills,
'defendersSkills'=>$defendersActivatedSkills, 'defendersSkills' => $defendersActivatedSkills,
]); ]);
+22 -18
View File
@@ -37,16 +37,24 @@ function processWar(string $warSeed, General $attackerGeneral, array $rawAttacke
$city = new WarUnitCity($rng, $rawDefenderCity, $rawDefenderNation, $year, $month, $startYear); $city = new WarUnitCity($rng, $rawDefenderCity, $rawDefenderNation, $year, $month, $startYear);
$defenderIDList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND city=%i AND nation!=0 and crew > 0 and rice>(crew/100) and train>=defence_train and atmos>=defence_train', $city->getVar('nation'), $city->getVar('city')); $defenderIDList = $db->queryFirstColumn('SELECT no FROM general WHERE nation=%i AND city=%i AND nation!=0 and crew > 0 and rice>(crew/100) and train>=defence_train and atmos>=defence_train', $city->getVar('nation'), $city->getVar('city'));
$defenderList = General::createGeneralObjListFromDB($defenderIDList, null, 2); $defenderGeneralList = General::createGeneralObjListFromDB($defenderIDList, null, 2);
usort($defenderList, function (General $lhs, General $rhs) use ($attackerGeneral) { /** @var WarUnit[] */
return - (extractBattleOrder($lhs, $attackerGeneral) <=> extractBattleOrder($rhs, $attackerGeneral)); $defenderList = [];
foreach($defenderGeneralList as $defenderGeneral){
$defenderList[] = new WarUnitGeneral($rng, $defenderGeneral, $rawDefenderNation, false);
}
$defenderList[] = $city;
usort($defenderList, function (WarUnit $lhs, WarUnit $rhs) use ($attacker) {
return - (extractBattleOrder($lhs, $attacker) <=> extractBattleOrder($rhs, $attacker));
}); });
$iterDefender = new \ArrayIterator($defenderList); $iterDefender = new \ArrayIterator($defenderList);
$iterDefender->rewind(); $iterDefender->rewind();
$getNextDefender = function (?WarUnit $prevDefender, bool $reqNext) use ($rng, $iterDefender, $rawDefenderNation, $rawDefenderCity, $db, $attackerGeneral) { $getNextDefender = function (?WarUnit $prevDefender, bool $reqNext) use ($iterDefender, $db, $attacker) {
if ($prevDefender !== null) { if ($prevDefender !== null) {
$prevDefender->applyDB($db); $prevDefender->applyDB($db);
} }
@@ -59,24 +67,16 @@ function processWar(string $warSeed, General $attackerGeneral, array $rawAttacke
return null; return null;
} }
/** @var WarUnit */
$nextDefender = $iterDefender->current(); $nextDefender = $iterDefender->current();
$nextDefender->setRawCity($rawDefenderCity); if (extractBattleOrder($nextDefender, $attacker) <= 0) {
if (extractBattleOrder($nextDefender, $attackerGeneral) <= 0) {
return null; return null;
} }
$retVal = new WarUnitGeneral(
$rng,
$nextDefender,
$rawDefenderNation,
false
);
$iterDefender->next(); $iterDefender->next();
return $retVal; return $nextDefender;
}; };
$conquerCity = processWar_NG($warSeed, $attacker, $getNextDefender, $city, $year - $startYear); $conquerCity = processWar_NG($warSeed, $attacker, $getNextDefender, $city);
$attacker->applyDB($db); $attacker->applyDB($db);
@@ -180,8 +180,13 @@ function processWar(string $warSeed, General $attackerGeneral, array $rawAttacke
], $attacker->getGeneral(), $city->getRaw()); ], $attacker->getGeneral(), $city->getRaw());
} }
function extractBattleOrder(General $general, General $attackerGeneral) function extractBattleOrder(WarUnit $defender, WarUnit $attacker)
{ {
if($defender instanceof WarUnitCity){
return -1;
}
$general = $defender->getGeneral();
if ($general->getVar('crew') == 0) { if ($general->getVar('crew') == 0) {
return 0; return 0;
} }
@@ -212,7 +217,6 @@ function processWar_NG(
WarUnitGeneral $attacker, WarUnitGeneral $attacker,
callable $getNextDefender, callable $getNextDefender,
WarUnitCity $city, WarUnitCity $city,
int $relYear
): bool { ): bool {
$templates = new \League\Plates\Engine(__DIR__ . '/templates'); $templates = new \League\Plates\Engine(__DIR__ . '/templates');