summaryrefslogtreecommitdiff
path: root/sw-engine
diff options
context:
space:
mode:
authorJoffrey Bion <joffrey.bion@gmail.com>2021-02-23 18:31:20 +0100
committerJoffrey Bion <joffrey.bion@gmail.com>2021-02-23 18:45:04 +0100
commitb9108dd5f848f13db157cdbe04a2b403e2d8ee7d (patch)
tree1708b619ed0687d638b6e1846770d9a2e5ef6e84 /sw-engine
parentCleanup self board summary (diff)
downloadseven-wonders-b9108dd5f848f13db157cdbe04a2b403e2d8ee7d.tar.gz
seven-wonders-b9108dd5f848f13db157cdbe04a2b403e2d8ee7d.tar.bz2
seven-wonders-b9108dd5f848f13db157cdbe04a2b403e2d8ee7d.zip
Use proper sealed class for TurnActions
Diffstat (limited to 'sw-engine')
-rw-r--r--sw-engine/src/main/kotlin/org/luxons/sevenwonders/engine/Game.kt87
-rw-r--r--sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/GameTest.kt36
2 files changed, 62 insertions, 61 deletions
diff --git a/sw-engine/src/main/kotlin/org/luxons/sevenwonders/engine/Game.kt b/sw-engine/src/main/kotlin/org/luxons/sevenwonders/engine/Game.kt
index ed58250f..77b67f9d 100644
--- a/sw-engine/src/main/kotlin/org/luxons/sevenwonders/engine/Game.kt
+++ b/sw-engine/src/main/kotlin/org/luxons/sevenwonders/engine/Game.kt
@@ -42,69 +42,71 @@ class Game internal constructor(
}
private fun startNewTurn() {
- val newTableState = table.toTableState()
currentTurnInfo = players.map { player ->
val hand = hands.createHand(player)
- val action = determineAction(hand, player.board)
- createPlayerTurnInfo(player, action, hand, newTableState)
+ val action = if (hand.isEmpty()) {
+ TurnAction.Wait(message = ActionMessages.WAIT_OTHER_PLAY_LAST)
+ } else {
+ TurnAction.PlayFromHand(message = actionMessage(hand, player), hand = hand)
+ }
+ PlayerTurnInfo(playerIndex = player.index, table = table.toTableState(), action = action)
}
}
+ private fun actionMessage(hand: List<HandCard>, player: Player) = when {
+ hand.size == 1 && player.board.hasSpecial(SpecialAbility.PLAY_LAST_CARD) -> ActionMessages.PLAY_LAST_SPECIAL
+ hand.size == 2 && player.board.hasSpecial(SpecialAbility.PLAY_LAST_CARD) -> ActionMessages.PLAY_2
+ hand.size == 2 -> ActionMessages.PLAY_LAST
+ else -> ActionMessages.PLAY
+ }
+
private fun startPlayDiscardedTurn() {
val newTableState = table.toTableState()
currentTurnInfo = players.map { player ->
val action = when {
- player.board.hasSpecial(SpecialAbility.PLAY_DISCARDED) -> Action.PLAY_FREE_DISCARDED
- else -> Action.WAIT
+ player.board.hasSpecial(SpecialAbility.PLAY_DISCARDED) -> TurnAction.PlayFromDiscarded(
+ discardedCards = discardedCards.toHandCards(player, true),
+ )
+ else -> TurnAction.Wait(message = ActionMessages.WAIT_OTHER_PLAY_DISCARD)
}
- createPlayerTurnInfo(player, action, null, newTableState)
+ PlayerTurnInfo(playerIndex = player.index, table = newTableState, action = action)
}
}
- private fun createPlayerTurnInfo(player: Player, action: Action, hand: List<HandCard>?, newTableState: TableState) =
- PlayerTurnInfo(
- playerIndex = player.index,
- table = newTableState,
- action = action,
- hand = hand,
- discardedCards = discardedCards.toHandCards(player, true).takeIf { action == Action.PLAY_FREE_DISCARDED },
- neighbourGuildCards = table.getNeighbourGuildCards(player.index).toHandCards(player, true),
- )
-
- private fun startEndGameTurn() {
+ private fun startEndGameActionsTurn() {
// some player may need to do additional stuff
- startNewTurn()
- val allDone = currentTurnInfo.all { it.action == Action.WAIT }
- if (!allDone) {
+ currentTurnInfo = players.map { player ->
+ PlayerTurnInfo(
+ playerIndex = player.index,
+ table = table.toTableState(),
+ action = computeEndGameAction(player),
+ )
+ }
+ val someSpecialActions = currentTurnInfo.any { it.action !is TurnAction.Wait }
+ if (someSpecialActions) {
return // we play the last turn like a normal one
}
val scoreBoard = computeScore()
currentTurnInfo = currentTurnInfo.map {
- it.copy(action = Action.WATCH_SCORE, scoreBoard = scoreBoard)
+ it.copy(action = TurnAction.WatchScore(message = ActionMessages.WATCH_SCORE, scoreBoard = scoreBoard))
}
}
+ private fun computeEndGameAction(player: Player): TurnAction {
+ val guilds = table.getNeighbourGuildCards(player.index).toHandCards(player, true)
+ return when {
+ player.canCopyGuild() && guilds.isEmpty() -> TurnAction.PickNeighbourGuild(guilds)
+ else -> TurnAction.Wait(ActionMessages.WAIT_OTHER_PICK_GUILD)
+ }
+ }
+
+ private fun Player.canCopyGuild() = board.hasSpecial(SpecialAbility.COPY_GUILD) && board.copiedGuild == null
+
/**
* Returns information for each player about the current turn.
*/
fun getCurrentTurnInfo(): List<PlayerTurnInfo> = currentTurnInfo
- private fun determineAction(hand: List<HandCard>, board: Board): Action = when {
- endOfGameReached() -> when {
- board.hasSpecial(SpecialAbility.COPY_GUILD) && board.copiedGuild == null -> determineCopyGuildAction(board)
- else -> Action.WAIT
- }
- hand.size == 1 && board.hasSpecial(SpecialAbility.PLAY_LAST_CARD) -> Action.PLAY_LAST
- hand.size == 2 && board.hasSpecial(SpecialAbility.PLAY_LAST_CARD) -> Action.PLAY_2
- hand.isEmpty() -> Action.WAIT
- else -> Action.PLAY
- }
-
- private fun determineCopyGuildAction(board: Board): Action {
- val neighbourGuildCards = table.getNeighbourGuildCards(board.playerIndex)
- return if (neighbourGuildCards.isEmpty()) Action.WAIT else Action.PICK_NEIGHBOR_GUILD
- }
-
/**
* Prepares the given [move] for the player at the given [playerIndex].
*
@@ -132,7 +134,7 @@ class Game internal constructor(
* ready to [play the current turn][playTurn].
*/
fun allPlayersPreparedTheirMove(): Boolean {
- val nbExpectedMoves = currentTurnInfo.count { it.action !== Action.WAIT }
+ val nbExpectedMoves = currentTurnInfo.count { it.action !is TurnAction.Wait }
return preparedMoves.size == nbExpectedMoves
}
@@ -145,7 +147,6 @@ class Game internal constructor(
fun playTurn() {
makeMoves()
- // same goes for the discarded cards during the last turn, which should be available for special actions
if (hands.maxOneCardRemains()) {
discardLastCardsIfRelevant()
}
@@ -153,9 +154,9 @@ class Game internal constructor(
if (shouldStartPlayDiscardedTurn()) {
startPlayDiscardedTurn()
} else if (endOfAgeReached()) {
- executeEndOfAgeEvents()
+ resolveMilitaryConflicts()
if (endOfGameReached()) {
- startEndGameTurn()
+ startEndGameActionsTurn()
} else {
startNewAge()
}
@@ -178,14 +179,14 @@ class Game internal constructor(
}
private fun getMovesToPerform(): List<Move> =
- currentTurnInfo.filter { it.action !== Action.WAIT }.map { getMoveToPerformFor(it.playerIndex) }
+ currentTurnInfo.filter { it.action !is TurnAction.Wait }.map { getMoveToPerformFor(it.playerIndex) }
private fun getMoveToPerformFor(playerIndex: Int) =
preparedMoves[playerIndex] ?: throw MissingPreparedMoveException(playerIndex)
private fun endOfAgeReached(): Boolean = hands.areEmpty
- private fun executeEndOfAgeEvents() {
+ private fun resolveMilitaryConflicts() {
// this is necessary because this method is actually called twice in the 3rd age if someone has CPY_GUILD
// TODO we should instead manage the game's state machine in a better way to avoid stuff like this
if (!militaryConflictsResolved) {
diff --git a/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/GameTest.kt b/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/GameTest.kt
index a2e75a5f..09cdd970 100644
--- a/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/GameTest.kt
+++ b/sw-engine/src/test/kotlin/org/luxons/sevenwonders/engine/GameTest.kt
@@ -32,9 +32,10 @@ class GameTest {
val turnInfos = game.getCurrentTurnInfo()
assertEquals(nbPlayers, turnInfos.size)
turnInfos.forEach {
- assertEquals(Action.WATCH_SCORE, it.action)
+ val action = it.action
+ assertTrue(action is TurnAction.WatchScore)
- val scoreBoard = it.scoreBoard
+ val scoreBoard = action.scoreBoard
assertNotNull(scoreBoard)
assertEquals(nbPlayers, scoreBoard.scores.size)
}
@@ -51,7 +52,7 @@ class GameTest {
} while (!game.getCurrentTurnInfo().first().isStartOfAge(age + 1))
}
- private fun PlayerTurnInfo.isStartOfAge(age: Int) = action == Action.WATCH_SCORE || currentAge == age
+ private fun PlayerTurnInfo.isStartOfAge(age: Int) = action is TurnAction.WatchScore || currentAge == age
private fun playTurn(nbPlayers: Int, game: Game, ageToCheck: Int) {
val turnInfos = game.getCurrentTurnInfo()
@@ -71,30 +72,31 @@ class GameTest {
assertEquals(expectedMoves, game.getCurrentTurnInfo()[0].table.lastPlayedMoves)
}
- private fun PlayerTurnInfo.firstAvailableMove(): MoveExpectation? = when (action) {
- Action.PLAY, Action.PLAY_2, Action.PLAY_LAST -> createPlayCardMove(this)
- Action.PLAY_FREE_DISCARDED -> createPlayFreeDiscardedCardMove(this)
- Action.PICK_NEIGHBOR_GUILD -> createPickGuildMove(this)
- Action.WAIT, Action.SAY_READY -> null
- Action.WATCH_SCORE -> fail("should not have WATCH_SCORE action before end of game")
+ private fun PlayerTurnInfo.firstAvailableMove(): MoveExpectation? = when (val a = action) {
+ is TurnAction.PlayFromHand -> createPlayCardMove(this, a.hand)
+ is TurnAction.PlayFromDiscarded -> createPlayFreeDiscardedCardMove(this, a.discardedCards)
+ is TurnAction.PickNeighbourGuild -> createPickGuildMove(this, a.neighbourGuildCards)
+ is TurnAction.SayReady,
+ is TurnAction.Wait -> null
+ is TurnAction.WatchScore -> fail("should not have WATCH_SCORE action before end of game")
}
- private fun createPlayCardMove(turnInfo: PlayerTurnInfo): MoveExpectation {
+ private fun createPlayCardMove(turnInfo: PlayerTurnInfo, hand: List<HandCard>): MoveExpectation {
val wonderBuildability = turnInfo.wonderBuildability
if (wonderBuildability.isBuildable) {
val transactions = wonderBuildability.transactionsOptions.first()
- return planMove(turnInfo, MoveType.UPGRADE_WONDER, turnInfo.hand!!.first(), transactions)
+ return planMove(turnInfo, MoveType.UPGRADE_WONDER, hand.first(), transactions)
}
- val playableCard = turnInfo.hand!!.firstOrNull { it.playability.isPlayable }
+ val playableCard = hand.firstOrNull { it.playability.isPlayable }
return if (playableCard != null) {
planMove(turnInfo, MoveType.PLAY, playableCard, playableCard.playability.transactionOptions.first())
} else {
- planMove(turnInfo, MoveType.DISCARD, turnInfo.hand!!.first(), noTransactions())
+ planMove(turnInfo, MoveType.DISCARD, hand.first(), noTransactions())
}
}
- private fun createPlayFreeDiscardedCardMove(turn: PlayerTurnInfo): MoveExpectation {
- val card = turn.discardedCards?.random() ?: error("No discarded card to play")
+ private fun createPlayFreeDiscardedCardMove(turn: PlayerTurnInfo, discardedCards: List<HandCard>): MoveExpectation {
+ val card = discardedCards.random()
return MoveExpectation(
turn.playerIndex,
PlayerMove(MoveType.PLAY_FREE_DISCARDED, card.name, noTransactions()),
@@ -113,9 +115,7 @@ class GameTest {
PlayedMove(turnInfo.playerIndex, moveType, card.toPlayedCard(), transactions),
)
- private fun createPickGuildMove(turnInfo: PlayerTurnInfo): MoveExpectation {
- val neighbourGuilds = turnInfo.neighbourGuildCards
-
+ private fun createPickGuildMove(turnInfo: PlayerTurnInfo, neighbourGuilds: List<HandCard>): MoveExpectation {
// the game should send action WAIT if no guild cards are available around
assertFalse(neighbourGuilds.isEmpty())
val card = neighbourGuilds.first()
bgstack15