diff --git a/battleforhill.game.php b/battleforhill.game.php index 4c7b9ff..5a57250 100644 --- a/battleforhill.game.php +++ b/battleforhill.game.php @@ -383,6 +383,45 @@ private function loadPlayableCards($playerId) return F\map($playableCards, ['BattleForHill', 'parsePlayableCard']); } + /** + * @param int $playerId + * @return boolean + */ + private function doesPlayerHaveAnyPossibleMoves($playerId) + { + return F\some( + $this->loadPossiblePlacementsByCardId($playerId), + function (array $moves) { + return !empty($moves); + } + ); + } + + /** + * @param int $playerId + * @return array + */ + private function loadPossiblePlacementsByCardId($playerId) + { + $playableCards = $this->loadPlayableCards($playerId); + $battlefield = $this->loadBattlefield(); + + return array_combine( + F\map($playableCards, function (PlayerCard $card) { return $card->getId(); }), + F\map( + $playableCards, + function (PlayerCard $card) use ($battlefield) { + return F\map( + $card->getPossiblePlacementPositions($battlefield), + function (Position $position) { + return ['x' => $position->getX(), 'y' => $position->getY()]; + } + ); + } + ) + ); + } + /** * @param array $raw * @return PlayerCard @@ -812,24 +851,9 @@ private function performChooseAttack($playerId, CardPlacement $from, CardPlaceme public function argPlayCard() { $playerId = (int) $this->getActivePlayerId(); - $playableCards = $this->loadPlayableCards($playerId); - $battlefield = $this->loadBattlefield(); return [ '_private' => [ - 'active' => array_combine( - F\map($playableCards, function (PlayerCard $card) { return $card->getId(); }), - F\map( - $playableCards, - function (PlayerCard $card) use ($battlefield) { - return F\map( - $card->getPossiblePlacementPositions($battlefield), - function (Position $position) { - return ['x' => $position->getX(), 'y' => $position->getY()]; - } - ); - } - ) - ) + 'active' => $this->loadPossiblePlacementsByCardId($playerId) ] ]; } @@ -971,27 +995,14 @@ public function stDrawCards() public function stNextPlay() { $playerId = (int) $this->getActivePlayerId(); - - $haveDeckCards = (boolean) self::getUniqueValueFromDB('SELECT COUNT(id) FROM deck_card LIMIT 1'); - $havePlayableCards = (boolean) self::getUniqueValueFromDB('SELECT COUNT(id) FROM playable_card LIMIT 1'); - if (!$haveDeckCards && !$havePlayableCards) { - $this->notifyAllPlayers('endOfGame', '', []); - $this->gamestate->nextState('noCardsLeft'); - return; - } - - $activePlayerHasCards = (boolean) self::getUniqueValueFromDB( - "SELECT COUNT(id) FROM playable_card WHERE player_id = {$playerId} LIMIT 1" - ); self::DbQuery( "UPDATE player SET turn_plays_remaining = turn_plays_remaining - 1 WHERE player_id = {$playerId}" ); $turnsRemaining = self::getIntUniqueValueFromDB( "SELECT turn_plays_remaining FROM player WHERE player_id = {$playerId}" ); - $battlefield = $this->loadBattlefield(); - $playableCards = $this->loadPlayableCards($playerId); - if ($turnsRemaining > 0 && $activePlayerHasCards) { + $activePlayerHasMoves = $this->doesPlayerHaveAnyPossibleMoves($playerId); + if ($turnsRemaining > 0 && $activePlayerHasMoves) { $this->gamestate->nextState('playAgain'); return; } @@ -1002,7 +1013,14 @@ function ($checkId) use ($playerId) { return $checkId !== $playerId; } ); + if (!$activePlayerHasMoves && !$this->doesPlayerHaveAnyPossibleMoves($opponentPlayerId)) { + $this->notifyAllPlayers('endOfGame', '', []); + $this->gamestate->nextState('noMovesLeft'); + return; + } + self::DbQuery("UPDATE player SET turn_plays_remaining = 2 WHERE player_id = {$opponentPlayerId}"); + self::DbQuery("UPDATE player SET turn_plays_remaining = 0 WHERE player_id = {$playerId}"); $this->gamestate->changeActivePlayer($opponentPlayerId); $this->gamestate->nextState('nextPlayer'); } diff --git a/states.inc.php b/states.inc.php index a5e864a..ff112ba 100644 --- a/states.inc.php +++ b/states.inc.php @@ -102,11 +102,11 @@ "name" => "nextPlay", "description" => "", "type" => "game", - "action" => "stNextPlay", - "transitions" => array("playAgain" => 30, "nextPlayer" => 20, "noCardsLeft" => 99), + "action" => 'stNextPlay', + "transitions" => array('playAgain' => 30, 'nextPlayer' => 20, 'noMovesLeft' => 99), "updateGameProgression" => true ), - + // Final state. // Please do not modify. 99 => array( diff --git a/tests/TheBattleForHill218/Tests/NextPlayTest.php b/tests/TheBattleForHill218/Tests/NextPlayTest.php index c90ab97..d6cd0fe 100644 --- a/tests/TheBattleForHill218/Tests/NextPlayTest.php +++ b/tests/TheBattleForHill218/Tests/NextPlayTest.php @@ -34,7 +34,7 @@ private function createGameReadyForNext($callable) $db = $this->table->getDbConnection(); TestUtils::return2RandomCards($game, $db, 66); - TestUtils::return2RandomCards($game, $db,77); + TestUtils::return2RandomCards($game, $db, 77); $game->stubActivePlayerId(77)->stDrawCards(); call_user_func($callable, $db); return $game; @@ -69,7 +69,7 @@ public function testNextPlaySwitchPlayerNoCardsLeftForOnePlayer() assertThat( $this->table->fetchDbRows('player'), containsInAnyOrder([ - M\hasEntries(['player_id' => 66, 'turn_plays_remaining' => 1]), + M\hasEntries(['player_id' => 66, 'turn_plays_remaining' => 0]), M\hasEntries(['player_id' => 77, 'turn_plays_remaining' => 2]) ]) ); @@ -114,10 +114,8 @@ public function testNextPlayNoCardsLeft() ); } - public function testNextPlayNoValidMovesSoSwitch() + public function testNextPlayNoValidMovesForOnePlayer() { - $this->markTestSkipped('TODO'); - $this->createGameReadyForNext(function (Connection $db) { $db->exec('UPDATE player SET turn_plays_remaining = 2 WHERE player_id = 66'); $db->exec('UPDATE player SET turn_plays_remaining = 0 WHERE player_id = 77'); @@ -135,4 +133,30 @@ public function testNextPlayNoValidMovesSoSwitch() ]) ); } + + public function testNextPlayNoValidMovesForAny() + { + $game = $this->createGameReadyForNext(function (Connection $db) { + $db->exec('DELETE FROM playable_card WHERE player_id = 66'); + $db->exec('DELETE FROM playable_card WHERE player_id = 77'); + $db->exec('INSERT INTO playable_card (player_id, type, `order`) VALUES (66, "air-strike", 0)'); + $db->exec('INSERT INTO playable_card (player_id, type, `order`) VALUES (66, "air-strike", 1)'); + $db->exec('INSERT INTO playable_card (player_id, type, `order`) VALUES (77, "air-strike", 0)'); + $db->exec('INSERT INTO playable_card (player_id, type, `order`) VALUES (77, "air-strike", 1)'); + })->stubActivePlayerId(66); + $game->resetNotifications(); + + $game->stNextPlay(); + + assertThat( + $game->getNotifications(), + containsInAnyOrder( + M\hasEntries([ + 'playerId' => 'all', + 'type' => 'endOfGame', + 'log' => '' + ]) + ) + ); + } }