Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

save replacement players to session state #775

Merged
merged 1 commit into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions Mimir/src/helpers/SessionState.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ class SessionState
* @var array
*/
protected $_yakitori = [];
/**
* Saved current replacements for proper recalculations
* @var array
*/
protected $_replacements = [];

/**
* SessionState constructor.
Expand Down Expand Up @@ -335,6 +340,24 @@ public function setScores(array $scores)
return $this;
}

/**
* @return array
*/
public function getReplacements()
{
return $this->_replacements;
}

/**
* @param array $replacements
* @return SessionState
*/
public function setReplacements(array $replacements)
{
$this->_replacements = $replacements;
return $this;
}

/**
* @return bool[]
*/
Expand Down
8 changes: 4 additions & 4 deletions Mimir/src/models/EventUserManagement.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public function registerPlayer(int $playerId, int $eventId)
$nextLocalId = PlayerRegistrationPrimitive::findNextFreeLocalId($this->_ds, $eId);
}

$regItemOld = PlayerRegistrationPrimitive::findByPlayerAndEvent($this->_ds, $playerId, $eventId);
$regItemOld = PlayerRegistrationPrimitive::findByPlayerAndEvent($this->_ds, [$playerId], $eventId);
if (count($regItemOld) > 0) {
throw new InvalidParametersException('Player already registered to this event');
}
Expand All @@ -92,7 +92,7 @@ public function unregisterPlayer(int $playerId, int $eventId)
throw new AuthFailedException('Only administrators are allowed to unregister players to event');
}

$regItem = PlayerRegistrationPrimitive::findByPlayerAndEvent($this->_ds, $playerId, $eventId);
$regItem = PlayerRegistrationPrimitive::findByPlayerAndEvent($this->_ds, [$playerId], $eventId);
if (empty($regItem)) {
return false;
}
Expand All @@ -116,7 +116,7 @@ public function updateSeatingFlag(int $playerId, int $eventId, int $ignoreSeatin
throw new AuthFailedException('Only administrators are allowed to update player information');
}

$regItem = PlayerRegistrationPrimitive::findByPlayerAndEvent($this->_ds, $playerId, $eventId);
$regItem = PlayerRegistrationPrimitive::findByPlayerAndEvent($this->_ds, [$playerId], $eventId);
if (empty($regItem)) {
throw new EntityNotFoundException('Player is not registered for this event');
}
Expand All @@ -141,7 +141,7 @@ public function updateReplacement(int $playerId, int $eventId, int $replacementI
throw new AuthFailedException('Only administrators are allowed to update player information');
}

$regItem = PlayerRegistrationPrimitive::findByPlayerAndEvent($this->_ds, $playerId, $eventId);
$regItem = PlayerRegistrationPrimitive::findByPlayerAndEvent($this->_ds, [$playerId], $eventId);
if (empty($regItem)) {
throw new EntityNotFoundException('Player is not registered for this event');
}
Expand Down
8 changes: 4 additions & 4 deletions Mimir/src/primitives/PlayerRegistration.php
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ public function getTeamName()

/**
* @param DataSource $ds
* @param int $playerId
* @param int[] $playerIds
* @param int $eventId
*
* @return self[]
Expand All @@ -163,12 +163,12 @@ public function getTeamName()
*
* @psalm-return array<array-key, self>
*/
public static function findByPlayerAndEvent(DataSource $ds, int $playerId, int $eventId)
public static function findByPlayerAndEvent(DataSource $ds, $playerIds, int $eventId)
{
return self::_findBySeveral($ds, [
'player_id' => [$playerId],
'player_id' => $playerIds,
'event_id' => [$eventId]
], ['onlyLast' => true]);
]);
}

/**
Expand Down
28 changes: 24 additions & 4 deletions Mimir/src/primitives/Session.php
Original file line number Diff line number Diff line change
Expand Up @@ -921,12 +921,13 @@ public function updateScoresWithChipsBonus()

/**
* Generate session results
* @param bool $useSavedReplacements
* @throws \Exception
* @return bool
*/
protected function _finalizeGame()
protected function _finalizeGame($useSavedReplacements = false)
{
$sessionResults = $this->getSessionResults();
$sessionResults = $this->getSessionResults($useSavedReplacements);

return array_reduce($sessionResults, function ($acc, SessionResultsPrimitive $result) {
$playerHistoryItem = PlayerHistoryPrimitive::makeNewHistoryItem(
Expand All @@ -949,15 +950,16 @@ protected function _finalizeGame()
*/
public function recreateHistory()
{
$this->_finalizeGame();
$this->_finalizeGame(true);
}

/**
* Get a list on unsaved session results primitives
* @param bool $useSavedReplacements
* @throws \Exception
* @return SessionResultsPrimitive[]
*/
public function getSessionResults()
public function getSessionResults($useSavedReplacements = false)
{
if ($this->getEvent()->getRulesetConfig()->rules()->getRiichiGoesToWinner()) {
$placesMap = SessionResultsPrimitive::calcPlacesMap($this->getCurrentState()->getScores(), $this->getPlayersIds());
Expand Down Expand Up @@ -986,6 +988,24 @@ public function getSessionResults()
}
}

if (!$useSavedReplacements) {
// save replacements to session state for possible recalculations
$players = PlayerRegistrationPrimitive::findByPlayerAndEvent($this->_ds, $this->getPlayersIds(), $this->_eventId);
$replacements = array_reduce(
$players,
function ($acc, PlayerRegistrationPrimitive $reg) {
if ($reg->getReplacementPlayerId()) {
$acc[$reg->getPlayerId()] = $reg->getReplacementPlayerId();
}
return $acc;
},
[]
);

$this->getCurrentState()->setReplacements($replacements);
$this->save();
}

return array_map(function (PlayerPrimitive $player) {
return (new SessionResultsPrimitive($this->_ds))
->setPlayer($player)
Expand Down
16 changes: 5 additions & 11 deletions Mimir/src/primitives/SessionResults.php
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ public function calc(\Common\Ruleset $rules, SessionState $results, array $playe
throw new InvalidParametersException('No player place found');
}

$this->_ratingDelta = $this->_calcRatingDelta($rules, $results->getScores());
$this->_ratingDelta = $this->_calcRatingDelta($rules, $results->getScores(), $results->getReplacements());

if ($withChips) {
$this->_ratingDelta += $this->_chips * $rules->rules()->getChipsValue();
Expand Down Expand Up @@ -507,23 +507,17 @@ public static function calcPlacesMap(array $scoreList, array $originalPlayersSeq
*
* @param \Common\Ruleset $rules
* @param int[] $allScores
* @param array $replacements
*
* @return float|int
* @throws InvalidParametersException
*/
protected function _calcRatingDelta(\Common\Ruleset $rules, array $allScores)
protected function _calcRatingDelta(\Common\Ruleset $rules, array $allScores, array $replacements)
{
$reg = PlayerRegistrationPrimitive::findByPlayerAndEvent($this->_ds, $this->_playerId, $this->_eventId);
if (empty($reg)) {
throw new InvalidParametersException('No player/event id pair found (' .
$this->_playerId . '/' . $this->_eventId . '), can\'t calculate delta');
}

$score = ($reg[0]->getReplacementPlayerId() && $rules->rules()->getReplacementPlayerFixedPoints() !== false)
$score = (!empty($replacements[$this->_playerId]) && $rules->rules()->getReplacementPlayerFixedPoints() !== false)
? $rules->rules()->getReplacementPlayerFixedPoints()
: $this->_score - $rules->rules()->getStartPoints();

$uma = ($reg[0]->getReplacementPlayerId() && $rules->rules()->getReplacementPlayerOverrideUma() !== false)
$uma = (!empty($replacements[$this->_playerId]) && $rules->rules()->getReplacementPlayerOverrideUma() !== false)
? $rules->rules()->getReplacementPlayerOverrideUma()
: $rules->uma($allScores)[$this->_place - 1];

Expand Down
8 changes: 4 additions & 4 deletions Mimir/tests/helpers/SessionStateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,7 @@ public function testSerialDraw()
public function testSessionStateToJson()
{
$this->assertEquals(
'{"_scores":{"1":30000,"2":30000,"3":30000,"4":30000},"_chombo":[],"_round":1,"_honba":0,"_riichiBets":0,"_prematurelyFinished":false,"_roundJustChanged":true,"_lastHandStarted":false,"_lastOutcome":null,"_yakitori":[],"_isFinished":false}',
'{"_scores":{"1":30000,"2":30000,"3":30000,"4":30000},"_chombo":[],"_round":1,"_honba":0,"_riichiBets":0,"_prematurelyFinished":false,"_roundJustChanged":true,"_lastHandStarted":false,"_lastOutcome":null,"_yakitori":[],"_replacements":[],"_isFinished":false}',
$this->_state->toJson()
);

Expand All @@ -631,14 +631,14 @@ public function testSessionStateToJson()
$this->_state->update($round);

$this->assertEquals(
'{"_scores":{"1":30000,"2":30000,"3":30000,"4":30000},"_chombo":[],"_round":2,"_honba":1,"_riichiBets":0,"_prematurelyFinished":false,"_roundJustChanged":true,"_lastHandStarted":false,"_lastOutcome":"draw","_yakitori":[],"_isFinished":false}',
'{"_scores":{"1":30000,"2":30000,"3":30000,"4":30000},"_chombo":[],"_round":2,"_honba":1,"_riichiBets":0,"_prematurelyFinished":false,"_roundJustChanged":true,"_lastHandStarted":false,"_lastOutcome":"draw","_yakitori":[],"_replacements":[],"_isFinished":false}',
$this->_state->toJson()
);
}

public function testSessionStateFromJson()
{
$json1 = '{"_scores":{"1":30000,"2":30000,"3":30000,"4":30000},"_chombo":[],"_round":1,"_honba":0,"_riichiBets":0,"_prematurelyFinished":false,"_roundJustChanged":true,"_lastHandStarted":false,"_lastOutcome":null,"_yakitori":[],"_isFinished":false}';
$json1 = '{"_scores":{"1":30000,"2":30000,"3":30000,"4":30000},"_chombo":[],"_round":1,"_honba":0,"_riichiBets":0,"_prematurelyFinished":false,"_roundJustChanged":true,"_lastHandStarted":false,"_lastOutcome":null,"_yakitori":[],"_replacements":[],"_isFinished":false}';

$state = SessionState::fromJson(
$this->_ruleset,
Expand All @@ -652,7 +652,7 @@ public function testSessionStateFromJson()
$this->assertEquals(1, $state->getRound());
$this->assertEquals(0, $state->getHonba());

$json2 = '{"_scores":{"1":30000,"2":30000,"3":30000,"4":30000},"_chombo":[],"_round":2,"_honba":1,"_riichiBets":0,"_prematurelyFinished":false,"_roundJustChanged":true,"_lastHandStarted":false,"_yakitori":[],"_lastOutcome":null}';
$json2 = '{"_scores":{"1":30000,"2":30000,"3":30000,"4":30000},"_chombo":[],"_round":2,"_honba":1,"_riichiBets":0,"_prematurelyFinished":false,"_roundJustChanged":true,"_lastHandStarted":false,"_yakitori":[],"_replacements":[],"_lastOutcome":null}';

$state = SessionState::fromJson(
$this->_ruleset,
Expand Down
2 changes: 1 addition & 1 deletion Mimir/tests/models/InteractiveSessionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@ public function testRoundRollback()
/** @var SessionPrimitive $session */
list($session) = SessionPrimitive::findByRepresentationalHash($this->_ds, [$hash]);
$this->assertEquals(
'{"_scores":{"1":29400,"2":32800,"3":29900,"4":27900},"_chombo":[],"_round":2,"_honba":0,"_riichiBets":0,"_prematurelyFinished":false,"_roundJustChanged":true,"_lastHandStarted":false,"_lastOutcome":"tsumo","_yakitori":[],"_isFinished":false}',
'{"_scores":{"1":29400,"2":32800,"3":29900,"4":27900},"_chombo":[],"_round":2,"_honba":0,"_riichiBets":0,"_prematurelyFinished":false,"_roundJustChanged":true,"_lastHandStarted":false,"_lastOutcome":"tsumo","_yakitori":[],"_replacements":[],"_isFinished":false}',
$session->getCurrentState()->toJson()
);

Expand Down
6 changes: 6 additions & 0 deletions Mimir/tests/primitives/SessionResultsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ public function testReplacementPlayerRatingDelta()
$player = $this->_players[0];
$this->_regs[$player->getId()]->setReplacementPlayerId(true);
$this->_regs[$player->getId()]->save();
$this->_session->getCurrentState()->setReplacements([$player->getId() => true]);
$this->_session->save();

$result = (new SessionResultsPrimitive($this->_ds))
->setPlayer($player)
Expand All @@ -134,6 +136,10 @@ public function testReplacementPlayerRatingDelta()
$result->save();

$this->assertEquals(-30000, $result->getRatingDelta());

// cleanup for following tests
$this->_session->getCurrentState()->setReplacements([]);
$this->_session->save();
}

public function testUmaRule()
Expand Down
Loading