diff options
Diffstat (limited to 'game-engine')
28 files changed, 314 insertions, 154 deletions
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/Game.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/Game.kt index af956695..b535bb96 100644 --- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/Game.kt +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/Game.kt @@ -4,8 +4,10 @@ import org.luxons.sevenwonders.game.api.Action import org.luxons.sevenwonders.game.api.HandCard import org.luxons.sevenwonders.game.api.PlayerMove import org.luxons.sevenwonders.game.api.PlayerTurnInfo -import org.luxons.sevenwonders.game.api.Table +import org.luxons.sevenwonders.game.api.toApiTable +import org.luxons.sevenwonders.game.api.toTableCard import org.luxons.sevenwonders.game.boards.Board +import org.luxons.sevenwonders.game.boards.Table import org.luxons.sevenwonders.game.cards.Card import org.luxons.sevenwonders.game.cards.CardBack import org.luxons.sevenwonders.game.cards.Decks @@ -14,6 +16,7 @@ import org.luxons.sevenwonders.game.data.LAST_AGE import org.luxons.sevenwonders.game.effects.SpecialAbility import org.luxons.sevenwonders.game.moves.Move import org.luxons.sevenwonders.game.score.ScoreBoard +import org.luxons.sevenwonders.game.api.Table as ApiTable class Game internal constructor( val id: Long, @@ -45,9 +48,9 @@ class Game internal constructor( private fun createPlayerTurnInfo(player: Player): PlayerTurnInfo { val hand = hands.createHand(player) val action = determineAction(hand, player.board) - val neighbourGuildCards = table.getNeighbourGuildCards(player.index) + val neighbourGuildCards = table.getNeighbourGuildCards(player.index).map { it.toTableCard() } - return PlayerTurnInfo(player.index, table, action, hand, neighbourGuildCards) + return PlayerTurnInfo(player.index, table.toApiTable(), action, hand, neighbourGuildCards) } /** @@ -95,7 +98,7 @@ class Game internal constructor( * had not prepared their moves (unless these players had nothing to do). To avoid this, please check if everyone * is ready using [allPlayersPreparedTheirMove]. */ - fun playTurn(): Table { + fun playTurn(): ApiTable { makeMoves() if (endOfAgeReached()) { executeEndOfAgeEvents() @@ -106,7 +109,7 @@ class Game internal constructor( rotateHandsIfRelevant() startNewTurn() } - return table + return table.toApiTable() } private fun makeMoves() { diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/Player.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/Player.kt index c7d429ec..2c82b6ff 100644 --- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/Player.kt +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/Player.kt @@ -1,8 +1,8 @@ package org.luxons.sevenwonders.game -import org.luxons.sevenwonders.game.api.Table import org.luxons.sevenwonders.game.boards.Board import org.luxons.sevenwonders.game.boards.RelativeBoardPosition +import org.luxons.sevenwonders.game.boards.Table import org.luxons.sevenwonders.game.cards.Card internal interface Player { diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/Action.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/Action.kt deleted file mode 100644 index a5ffd721..00000000 --- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/Action.kt +++ /dev/null @@ -1,9 +0,0 @@ -package org.luxons.sevenwonders.game.api - -enum class Action(val message: String) { - PLAY("Pick the card you want to play or discard."), - PLAY_2("Pick the first card you want to play or discard. Note that you have the ability to play these 2 last cards. You will choose how to play the last one during your next turn."), - PLAY_LAST("You have the special ability to play your last card. Choose how you want to play it."), - PICK_NEIGHBOR_GUILD("Choose a Guild card (purple) that you want to copy from one of your neighbours."), - WAIT("Please wait for other players to perform extra actions.") -} diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/Boards.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/Boards.kt new file mode 100644 index 00000000..01b840c6 --- /dev/null +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/Boards.kt @@ -0,0 +1,89 @@ +package org.luxons.sevenwonders.game.api + +import org.luxons.sevenwonders.game.boards.Military +import org.luxons.sevenwonders.game.boards.Science +import org.luxons.sevenwonders.game.boards.ScienceType +import org.luxons.sevenwonders.game.cards.CardBack +import org.luxons.sevenwonders.game.resources.Production +import org.luxons.sevenwonders.game.resources.ResourceType +import org.luxons.sevenwonders.game.resources.Resources +import org.luxons.sevenwonders.game.boards.Board as InternalBoard +import org.luxons.sevenwonders.game.wonders.Wonder as InternalWonder +import org.luxons.sevenwonders.game.wonders.WonderStage as InternalWonderStage + +data class Board( + val playerIndex: Int, + val wonder: Wonder, + val production: ApiProduction, + val publicProduction: ApiProduction, + val science: ApiScience, + val military: ApiMilitary, + val playedCards: List<TableCard>, + val gold: Int +) + +internal fun InternalBoard.toApiBoard(): Board = Board( + playerIndex = playerIndex, + wonder = wonder.toApiWonder(), + production = production.toApiProduction(), + publicProduction = publicProduction.toApiProduction(), + science = science.toApiScience(), + military = military.toApiMilitary(), + playedCards = getPlayedCards().map { it.toTableCard() }, + gold = gold +) + +data class Wonder( + val name: String, + val initialResource: ResourceType, + val stages: List<WonderStage>, + val image: String, + val nbBuiltStages: Int +) + +internal fun InternalWonder.toApiWonder(): Wonder = Wonder( + name = name, + initialResource = initialResource, + stages = stages.map { it.toApiWonderStage() }, + image = image, + nbBuiltStages = nbBuiltStages +) + +data class WonderStage( + val cardBack: CardBack?, + val isBuilt: Boolean +) + +internal fun InternalWonderStage.toApiWonderStage(): WonderStage = WonderStage( + cardBack = cardBack, + isBuilt = isBuilt +) + +data class ApiProduction( + val fixedResources: Resources, + val aternativeResources: Set<Set<ResourceType>> +) + +internal fun Production.toApiProduction(): ApiProduction = ApiProduction(getFixedResources(), getAlternativeResources()) + +data class ApiMilitary( + var nbShields: Int, + var totalPoints: Int, + var nbDefeatTokens: Int +) + +internal fun Military.toApiMilitary(): ApiMilitary = ApiMilitary(nbShields, totalPoints, nbDefeatTokens) + +data class ApiScience( + var jokers: Int, + var nbWheels: Int, + var nbCompasses: Int, + var nbTablets: Int +) + +internal fun Science.toApiScience(): ApiScience = ApiScience( + jokers = jokers, + nbWheels = getQuantity(ScienceType.WHEEL), + nbCompasses = getQuantity(ScienceType.COMPASS), + nbTablets = getQuantity(ScienceType.TABLET) +) diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/Cards.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/Cards.kt new file mode 100644 index 00000000..b49c6ab0 --- /dev/null +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/Cards.kt @@ -0,0 +1,61 @@ +package org.luxons.sevenwonders.game.api + +import org.luxons.sevenwonders.game.Player +import org.luxons.sevenwonders.game.cards.Card +import org.luxons.sevenwonders.game.cards.CardBack +import org.luxons.sevenwonders.game.cards.Color +import org.luxons.sevenwonders.game.cards.Requirements +import org.luxons.sevenwonders.game.resources.TransactionPlan +import org.luxons.sevenwonders.game.resources.bestSolution + +data class TableCard( + val name: String, + val color: Color, + val requirements: Requirements, + val chainParent: String?, + val chainChildren: List<String>, + val image: String, + val back: CardBack +) + +internal fun Card.toTableCard(): TableCard = TableCard( + name = name, + color = color, + requirements = requirements, + chainParent = chainParent, + chainChildren = chainChildren, + image = image, + back = back +) + +/** + * A card with contextual information relative to the hand it is sitting in. The extra information is especially useful + * because it frees the client from a painful business logic implementation. + */ +data class HandCard( + val name: String, + val color: Color, + val requirements: Requirements, + val chainParent: String?, + val chainChildren: List<String>, + val image: String, + val back: CardBack, + val isChainable: Boolean, + val isFree: Boolean, + val isPlayable: Boolean, + val cheapestTransactions: TransactionPlan +) + +internal fun Card.toHandCard(player: Player): HandCard = HandCard( + name = name, + color = color, + requirements = requirements, + chainParent = chainParent, + chainChildren = chainChildren, + image = image, + back = back, + isChainable = isChainableOn(player.board), + isFree = isFreeFor(player.board), + isPlayable = isPlayableBy(player), + cheapestTransactions = bestSolution(requirements.resources, player) +) diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/HandCard.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/HandCard.kt deleted file mode 100644 index ca1ffd94..00000000 --- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/HandCard.kt +++ /dev/null @@ -1,14 +0,0 @@ -package org.luxons.sevenwonders.game.api - -import org.luxons.sevenwonders.game.Player -import org.luxons.sevenwonders.game.cards.Card - -/** - * A card with contextual information relative to the hand it is sitting in. The extra information is especially useful - * because it frees the client from a painful business logic implementation. - */ -class HandCard internal constructor(val card: Card, player: Player) { - val isChainable: Boolean = card.isChainableOn(player.board) - val isFree: Boolean = card.isFreeFor(player.board) - val isPlayable: Boolean = card.isPlayableBy(player) -} diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/PlayerTurnInfo.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/PlayerTurnInfo.kt index abf4e7bb..e80cdefd 100644 --- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/PlayerTurnInfo.kt +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/PlayerTurnInfo.kt @@ -1,13 +1,19 @@ package org.luxons.sevenwonders.game.api -import org.luxons.sevenwonders.game.cards.Card +enum class Action(val message: String) { + PLAY("Pick the card you want to play or discard."), + PLAY_2("Pick the first card you want to play or discard. Note that you have the ability to play these 2 last cards. You will choose how to play the last one during your next turn."), + PLAY_LAST("You have the special ability to play your last card. Choose how you want to play it."), + PICK_NEIGHBOR_GUILD("Choose a Guild card (purple) that you want to copy from one of your neighbours."), + WAIT("Please wait for other players to perform extra actions.") +} data class PlayerTurnInfo internal constructor( val playerIndex: Int, val table: Table, val action: Action, val hand: List<HandCard>, - val neighbourGuildCards: List<Card> + val neighbourGuildCards: List<TableCard> ) { val currentAge: Int = table.currentAge val message: String = action.message diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/Table.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/Table.kt index 470f3ba0..05242f00 100644 --- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/Table.kt +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/Table.kt @@ -1,61 +1,38 @@ package org.luxons.sevenwonders.game.api -import org.luxons.sevenwonders.game.boards.Board -import org.luxons.sevenwonders.game.boards.RelativeBoardPosition -import org.luxons.sevenwonders.game.boards.neighboursPositions -import org.luxons.sevenwonders.game.cards.Card -import org.luxons.sevenwonders.game.cards.Color import org.luxons.sevenwonders.game.cards.HandRotationDirection import org.luxons.sevenwonders.game.data.Age import org.luxons.sevenwonders.game.moves.Move - -/** - * The table contains what is visible by all the players in the game: the boards and their played cards, and the - * players' information. - */ -class Table internal constructor(val boards: List<Board>) { - +import org.luxons.sevenwonders.game.moves.MoveType +import org.luxons.sevenwonders.game.resources.ResourceTransactions +import org.luxons.sevenwonders.game.boards.Table as InternalTable + +data class Table( + val boards: List<Board>, + val currentAge: Age, + val handRotationDirection: HandRotationDirection, + val lastPlayedMoves: List<PlayedMove> +) { val nbPlayers: Int = boards.size - - var currentAge: Age = 0 - private set - - val handRotationDirection: HandRotationDirection - get() = HandRotationDirection.forAge(currentAge) - - var lastPlayedMoves: List<Move> = emptyList() - internal set - - internal fun getBoard(playerIndex: Int): Board = boards[playerIndex] - - internal fun getBoard(playerIndex: Int, position: RelativeBoardPosition): Board = - boards[position.getIndexFrom(playerIndex, nbPlayers)] - - internal fun increaseCurrentAge() { - this.currentAge++ - } - - internal fun resolveMilitaryConflicts() { - repeat(nbPlayers) { - val board1 = getBoard(it) - val board2 = getBoard(it, RelativeBoardPosition.RIGHT) - resolveConflict(board1, board2) - } - } - - private fun resolveConflict(board1: Board, board2: Board) { - val shields1 = board1.military.nbShields - val shields2 = board2.military.nbShields - if (shields1 < shields2) { - board1.military.defeat() - board2.military.victory(currentAge) - } else if (shields1 > shields2) { - board1.military.victory(currentAge) - board2.military.defeat() - } - } - - internal fun getNeighbourGuildCards(playerIndex: Int): List<Card> = neighboursPositions() - .flatMap { getBoard(playerIndex, it).getPlayedCards() } - .filter { it.color == Color.PURPLE } } + +internal fun InternalTable.toApiTable(): Table = Table( + boards = boards.map { it.toApiBoard() }, + currentAge = currentAge, + handRotationDirection = handRotationDirection, + lastPlayedMoves = lastPlayedMoves.map { it.toPlayedMove() } +) + +data class PlayedMove( + val playerIndex: Int, + val type: MoveType, + val card: TableCard, + val transactions: ResourceTransactions +) + +internal fun Move.toPlayedMove(): PlayedMove = PlayedMove( + playerIndex = playerContext.index, + type = type, + card = card.toTableCard(), + transactions = transactions +) diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Board.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Board.kt index 00de0239..22b9ac93 100644 --- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Board.kt +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Board.kt @@ -8,17 +8,19 @@ import org.luxons.sevenwonders.game.data.Age import org.luxons.sevenwonders.game.effects.SpecialAbility import org.luxons.sevenwonders.game.resources.Production import org.luxons.sevenwonders.game.resources.TradingRules +import org.luxons.sevenwonders.game.resources.mutableResourcesOf import org.luxons.sevenwonders.game.score.PlayerScore import org.luxons.sevenwonders.game.score.ScoreCategory import org.luxons.sevenwonders.game.wonders.Wonder -class Board internal constructor(val wonder: Wonder, val playerIndex: Int, settings: Settings) { +internal class Board(val wonder: Wonder, val playerIndex: Int, settings: Settings) { - val production = Production() - val publicProduction = Production() + val production = Production(mutableResourcesOf(wonder.initialResource)) + val publicProduction = Production(mutableResourcesOf(wonder.initialResource)) val science = Science() - val tradingRules: TradingRules = TradingRules(settings.defaultTradingCost) val military: Military = Military(settings.lostPointsPerDefeat, settings.wonPointsPerVictoryPerAge) + val tradingRules: TradingRules = TradingRules(settings.defaultTradingCost) + private val pointsPer3Gold: Int = settings.pointsPer3Gold private val playedCards: MutableList<Card> = arrayListOf() @@ -36,33 +38,28 @@ class Board internal constructor(val wonder: Wonder, val playerIndex: Int, setti field = copiedGuild } - init { - this.production.addFixedResource(wonder.initialResource, 1) - this.publicProduction.addFixedResource(wonder.initialResource, 1) - } - fun getPlayedCards(): List<Card> = playedCards - internal fun addCard(card: Card) { + fun addCard(card: Card) { playedCards.add(card) } - internal fun getNbCardsOfColor(colorFilter: List<Color>): Int = playedCards.count { colorFilter.contains(it.color) } + fun getNbCardsOfColor(colorFilter: List<Color>): Int = playedCards.count { colorFilter.contains(it.color) } fun isPlayed(cardName: String): Boolean = playedCards.count { it.name == cardName } > 0 - internal fun addGold(amount: Int) { + fun addGold(amount: Int) { this.gold += amount } - internal fun removeGold(amount: Int) { + fun removeGold(amount: Int) { if (gold < amount) { throw InsufficientFundsException(gold, amount) } this.gold -= amount } - internal fun addSpecial(specialAbility: SpecialAbility) { + fun addSpecial(specialAbility: SpecialAbility) { specialAbilities.add(specialAbility) } @@ -75,7 +72,7 @@ class Board internal constructor(val wonder: Wonder, val playerIndex: Int, setti consumedFreeCards[age] = true } - internal fun computeScore(player: Player): PlayerScore = PlayerScore( + fun computeScore(player: Player): PlayerScore = PlayerScore( boardGold = gold, pointsByCategory = mapOf( ScoreCategory.CIVIL to computePointsForCards(player, Color.BLUE), diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Military.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Military.kt index 593716fd..c482c596 100644 --- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Military.kt +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Military.kt @@ -2,7 +2,7 @@ package org.luxons.sevenwonders.game.boards import org.luxons.sevenwonders.game.data.Age -class Military internal constructor( +internal class Military( private val lostPointsPerDefeat: Int, private val wonPointsPerVictoryPerAge: Map<Age, Int> ) { diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Science.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Science.kt index cf2b7901..a152c7db 100644 --- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Science.kt +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Science.kt @@ -6,7 +6,7 @@ enum class ScienceType { TABLET } -class Science { +internal class Science { private val quantities: MutableMap<ScienceType, Int> = mutableMapOf() diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Table.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Table.kt new file mode 100644 index 00000000..6a0980c4 --- /dev/null +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Table.kt @@ -0,0 +1,58 @@ +package org.luxons.sevenwonders.game.boards + +import org.luxons.sevenwonders.game.cards.Card +import org.luxons.sevenwonders.game.cards.Color +import org.luxons.sevenwonders.game.cards.HandRotationDirection +import org.luxons.sevenwonders.game.data.Age +import org.luxons.sevenwonders.game.moves.Move + +/** + * The table contains what is visible by all the players in the game: the boards and their played cards, and the + * players' information. + */ +internal class Table(val boards: List<Board>) { + + val nbPlayers: Int = boards.size + + var currentAge: Age = 0 + private set + + val handRotationDirection: HandRotationDirection + get() = HandRotationDirection.forAge(currentAge) + + var lastPlayedMoves: List<Move> = emptyList() + internal set + + fun getBoard(playerIndex: Int): Board = boards[playerIndex] + + fun getBoard(playerIndex: Int, position: RelativeBoardPosition): Board = + boards[position.getIndexFrom(playerIndex, nbPlayers)] + + fun increaseCurrentAge() { + this.currentAge++ + } + + fun resolveMilitaryConflicts() { + repeat(nbPlayers) { + val board1 = getBoard(it) + val board2 = getBoard(it, RelativeBoardPosition.RIGHT) + resolveConflict(board1, board2) + } + } + + private fun resolveConflict(board1: Board, board2: Board) { + val shields1 = board1.military.nbShields + val shields2 = board2.military.nbShields + if (shields1 < shields2) { + board1.military.defeat() + board2.military.victory(currentAge) + } else if (shields1 > shields2) { + board1.military.victory(currentAge) + board2.military.defeat() + } + } + + fun getNeighbourGuildCards(playerIndex: Int): List<Card> = neighboursPositions() + .flatMap { getBoard(playerIndex, it).getPlayedCards() } + .filter { it.color == Color.PURPLE } +} diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Cards.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Cards.kt index 83865c74..df0e06cc 100644 --- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Cards.kt +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Cards.kt @@ -7,11 +7,11 @@ import org.luxons.sevenwonders.game.resources.ResourceTransactions data class CardBack(val image: String) -data class Card internal constructor( +internal data class Card( val name: String, val color: Color, val requirements: Requirements, - internal val effects: List<Effect>, + val effects: List<Effect>, val chainParent: String?, val chainChildren: List<String>, val image: String, @@ -19,20 +19,20 @@ data class Card internal constructor( ) { private fun isAllowedOnBoard(board: Board): Boolean = !board.isPlayed(name) // cannot play twice the same card - internal fun isFreeFor(board: Board): Boolean = isChainableOn(board) || isFreeWithoutChainingOn(board) + fun isFreeFor(board: Board): Boolean = isChainableOn(board) || isFreeWithoutChainingOn(board) - internal fun isChainableOn(board: Board): Boolean = + fun isChainableOn(board: Board): Boolean = isAllowedOnBoard(board) && chainParent != null && board.isPlayed(chainParent) private fun isFreeWithoutChainingOn(board: Board) = isAllowedOnBoard(board) && requirements.areMetWithoutNeighboursBy(board) && requirements.gold == 0 - internal fun isPlayableBy(player: Player): Boolean { + fun isPlayableBy(player: Player): Boolean { val board = player.board return isAllowedOnBoard(board) && (isChainableOn(board) || requirements.areMetBy(player)) } - internal fun applyTo(player: Player, transactions: ResourceTransactions) { + fun applyTo(player: Player, transactions: ResourceTransactions) { if (!isChainableOn(player.board)) { requirements.pay(player, transactions) } diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Hands.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Hands.kt index 1e5f839a..0a81db5f 100644 --- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Hands.kt +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Hands.kt @@ -2,6 +2,7 @@ package org.luxons.sevenwonders.game.cards import org.luxons.sevenwonders.game.Player import org.luxons.sevenwonders.game.api.HandCard +import org.luxons.sevenwonders.game.api.toHandCard internal class Hands(private val hands: List<List<Card>>) { @@ -23,9 +24,7 @@ internal class Hands(private val hands: List<List<Card>>) { return Hands(mutatedHands) } - fun createHand(player: Player): List<HandCard> { - return hands[player.index].map { c -> HandCard(c, player) } - } + fun createHand(player: Player): List<HandCard> = hands[player.index].map { c -> c.toHandCard(player) } fun rotate(direction: HandRotationDirection): Hands { val newHands = when (direction) { diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/Move.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/Move.kt index ed982abb..1ac68d27 100644 --- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/Move.kt +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/Move.kt @@ -6,19 +6,18 @@ import org.luxons.sevenwonders.game.api.PlayerMove import org.luxons.sevenwonders.game.cards.Card import org.luxons.sevenwonders.game.resources.ResourceTransactions -abstract class Move internal constructor( +internal abstract class Move( val move: PlayerMove, val card: Card, - internal val playerContext: PlayerContext + val playerContext: PlayerContext ) { val type: MoveType = move.type - // TODO restore visibility to public - internal val transactions: ResourceTransactions = move.transactions + val transactions: ResourceTransactions = move.transactions - internal abstract fun place(discardedCards: MutableList<Card>, settings: Settings) + abstract fun place(discardedCards: MutableList<Card>, settings: Settings) - internal abstract fun activate(discardedCards: List<Card>, settings: Settings) + abstract fun activate(discardedCards: List<Card>, settings: Settings) } class InvalidMoveException internal constructor(move: Move, message: String) : IllegalArgumentException( diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/resources/BestPriceCalculator.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/resources/BestPriceCalculator.kt index 4159cea3..3d051732 100644 --- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/resources/BestPriceCalculator.kt +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/resources/BestPriceCalculator.kt @@ -7,7 +7,7 @@ import java.util.EnumSet internal fun bestSolution(resources: Resources, player: Player): TransactionPlan = BestPriceCalculator(resources, player).computeBestSolution() -internal data class TransactionPlan(val price: Int, val possibleTransactions: Set<ResourceTransactions>) +data class TransactionPlan(val price: Int, val possibleTransactions: Set<ResourceTransactions>) private class ResourcePool( val provider: Provider?, diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/resources/Resources.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/resources/Resources.kt index d662cf1b..c02fd260 100644 --- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/resources/Resources.kt +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/resources/Resources.kt @@ -4,7 +4,7 @@ fun emptyResources(): Resources = MutableResources() fun resourcesOf(singleResource: ResourceType): Resources = mapOf(singleResource to 1).toMutableResources() -fun resourcesOf(vararg resources: ResourceType): Resources = resources.map { it to 1 }.toMutableResources() +fun resourcesOf(vararg resources: ResourceType): Resources = mutableResourcesOf(*resources) fun resourcesOf(vararg resources: Pair<ResourceType, Int>): Resources = mutableResourcesOf(*resources) @@ -16,6 +16,9 @@ fun Iterable<Resources>.merge(): Resources = fold(MutableResources()) { r1, r2 - internal fun mutableResourcesOf() = MutableResources() +internal fun mutableResourcesOf(vararg resources: ResourceType): MutableResources = + resources.map { it to 1 }.toMutableResources() + internal fun mutableResourcesOf(vararg resources: Pair<ResourceType, Int>) = resources.asIterable().toMutableResources() internal fun Iterable<Pair<ResourceType, Int>>.toMutableResources(): MutableResources = diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/wonders/Wonder.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/wonders/Wonder.kt index 5d771491..46e09d40 100644 --- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/wonders/Wonder.kt +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/wonders/Wonder.kt @@ -6,7 +6,7 @@ import org.luxons.sevenwonders.game.cards.CardBack import org.luxons.sevenwonders.game.resources.ResourceTransactions import org.luxons.sevenwonders.game.resources.ResourceType -class Wonder internal constructor( +internal class Wonder( val name: String, val initialResource: ResourceType, val stages: List<WonderStage>, @@ -30,15 +30,15 @@ class Wonder internal constructor( return stages[lastLevel] } - internal fun isNextStageBuildable(board: Board, boughtResources: ResourceTransactions): Boolean = + fun isNextStageBuildable(board: Board, boughtResources: ResourceTransactions): Boolean = nbBuiltStages < stages.size && nextStage.isBuildable(board, boughtResources) - internal fun placeCard(cardBack: CardBack) = nextStage.placeCard(cardBack) + fun placeCard(cardBack: CardBack) = nextStage.placeCard(cardBack) - internal fun activateLastBuiltStage(player: Player, boughtResources: ResourceTransactions) = + fun activateLastBuiltStage(player: Player, boughtResources: ResourceTransactions) = lastBuiltStage.activate(player, boughtResources) - internal fun computePoints(player: Player): Int = + fun computePoints(player: Player): Int = stages.filter { it.isBuilt } .flatMap { it.effects } .map { it.computePoints(player) } diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/wonders/WonderStage.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/wonders/WonderStage.kt index 3953d4dc..39aca254 100644 --- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/wonders/WonderStage.kt +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/wonders/WonderStage.kt @@ -7,7 +7,7 @@ import org.luxons.sevenwonders.game.cards.Requirements import org.luxons.sevenwonders.game.effects.Effect import org.luxons.sevenwonders.game.resources.ResourceTransactions -class WonderStage internal constructor(val requirements: Requirements, internal val effects: List<Effect>) { +internal class WonderStage(val requirements: Requirements, val effects: List<Effect>) { var cardBack: CardBack? = null private set @@ -15,15 +15,15 @@ class WonderStage internal constructor(val requirements: Requirements, internal val isBuilt: Boolean get() = cardBack != null - internal fun isBuildable(board: Board, boughtResources: ResourceTransactions): Boolean { + fun isBuildable(board: Board, boughtResources: ResourceTransactions): Boolean { return requirements.areMetWithHelpBy(board, boughtResources) } - internal fun placeCard(cardBack: CardBack) { + fun placeCard(cardBack: CardBack) { this.cardBack = cardBack } - internal fun activate(player: Player, boughtResources: ResourceTransactions) { + fun activate(player: Player, boughtResources: ResourceTransactions) { effects.forEach { it.applyTo(player) } requirements.pay(player, boughtResources) } diff --git a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/GameTest.kt b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/GameTest.kt index 1917c860..3736ddc0 100644 --- a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/GameTest.kt +++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/GameTest.kt @@ -10,8 +10,6 @@ import org.luxons.sevenwonders.game.data.GameDefinition import org.luxons.sevenwonders.game.data.LAST_AGE import org.luxons.sevenwonders.game.moves.MoveType import org.luxons.sevenwonders.game.resources.ResourceTransactions -import org.luxons.sevenwonders.game.resources.Resources -import org.luxons.sevenwonders.game.resources.bestSolution import org.luxons.sevenwonders.game.resources.noTransactions import org.luxons.sevenwonders.game.test.testCustomizableSettings import java.util.HashMap @@ -73,27 +71,19 @@ class GameTest { private fun createPlayCardMove(turnInfo: PlayerTurnInfo): PlayerMove { for (handCard in turnInfo.hand) { if (handCard.isPlayable) { - val resourcesToBuy = findResourcesToBuyFor(handCard, turnInfo) - return PlayerMove(MoveType.PLAY, handCard.card.name, resourcesToBuy) + val transactions = findResourcesToBuyFor(handCard) + return PlayerMove(MoveType.PLAY, handCard.name, transactions) } } val firstCardInHand = turnInfo.hand[0] - return PlayerMove(MoveType.DISCARD, firstCardInHand.card.name) + return PlayerMove(MoveType.DISCARD, firstCardInHand.name) } - private fun findResourcesToBuyFor(handCard: HandCard, turnInfo: PlayerTurnInfo): ResourceTransactions { + private fun findResourcesToBuyFor(handCard: HandCard): ResourceTransactions { if (handCard.isFree) { return noTransactions() } - val requiredResources = handCard.card.requirements.resources - val table = turnInfo.table - val playerIndex = turnInfo.playerIndex - // we're supposed to have a best transaction plan because the card is playable - return bestTransaction(requiredResources, PlayerContext(playerIndex, table, listOf())) - } - - private fun bestTransaction(resources: Resources, player: Player): ResourceTransactions { - return bestSolution(resources, player).possibleTransactions.first() + return handCard.cheapestTransactions.possibleTransactions.first() } private fun createPickGuildMove(turnInfo: PlayerTurnInfo): PlayerMove { @@ -106,7 +96,7 @@ class GameTest { private fun checkLastPlayedMoves(sentMoves: Map<Int, PlayerMove>, table: Table) { for (move in table.lastPlayedMoves) { - val sentMove = sentMoves[move.playerContext.index] + val sentMove = sentMoves[move.playerIndex] assertNotNull(sentMove) assertNotNull(move.card) assertEquals(sentMove.cardName, move.card.name) diff --git a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/CardTest.kt b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/CardTest.kt index 41c3c070..b6fecbd0 100644 --- a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/CardTest.kt +++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/CardTest.kt @@ -2,8 +2,8 @@ package org.luxons.sevenwonders.game.cards import org.junit.Test import org.luxons.sevenwonders.game.SimplePlayer -import org.luxons.sevenwonders.game.api.Table import org.luxons.sevenwonders.game.boards.Board +import org.luxons.sevenwonders.game.boards.Table import org.luxons.sevenwonders.game.effects.ProductionIncrease import org.luxons.sevenwonders.game.resources.Production import org.luxons.sevenwonders.game.resources.ResourceType diff --git a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/HandsTest.kt b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/HandsTest.kt index eddb4d36..5a71aeda 100644 --- a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/HandsTest.kt +++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/HandsTest.kt @@ -101,7 +101,7 @@ class HandsTest { val table = testTable(2) val hand = hands.createHand(SimplePlayer(0, table)) - hand.map { it.card }.forEach { assertTrue(it in hand0) } + assertEquals(hand0.map { it.name }, hand.map { it.name }) } companion object { diff --git a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/RequirementsTest.kt b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/RequirementsTest.kt index e3e3a393..5abbba6e 100644 --- a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/RequirementsTest.kt +++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/RequirementsTest.kt @@ -7,7 +7,7 @@ import org.junit.experimental.theories.Theories import org.junit.experimental.theories.Theory import org.junit.runner.RunWith import org.luxons.sevenwonders.game.SimplePlayer -import org.luxons.sevenwonders.game.api.Table +import org.luxons.sevenwonders.game.boards.Table import org.luxons.sevenwonders.game.resources.Provider import org.luxons.sevenwonders.game.resources.ResourceType import org.luxons.sevenwonders.game.resources.emptyResources diff --git a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/effects/BonusPerBoardElementTest.kt b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/effects/BonusPerBoardElementTest.kt index 7c8a7e95..700eddb1 100644 --- a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/effects/BonusPerBoardElementTest.kt +++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/effects/BonusPerBoardElementTest.kt @@ -7,8 +7,8 @@ import org.junit.experimental.theories.Theory import org.junit.runner.RunWith import org.luxons.sevenwonders.game.Player import org.luxons.sevenwonders.game.SimplePlayer -import org.luxons.sevenwonders.game.api.Table import org.luxons.sevenwonders.game.boards.RelativeBoardPosition +import org.luxons.sevenwonders.game.boards.Table import org.luxons.sevenwonders.game.cards.CardBack import org.luxons.sevenwonders.game.cards.Color import org.luxons.sevenwonders.game.test.addCards diff --git a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/effects/SpecialAbilityActivationTest.kt b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/effects/SpecialAbilityActivationTest.kt index 41d3d51b..524124b4 100644 --- a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/effects/SpecialAbilityActivationTest.kt +++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/effects/SpecialAbilityActivationTest.kt @@ -39,7 +39,7 @@ class SpecialAbilityActivationTest { } @Theory - fun computePoints_copiedGuild(guildCard: Card, neighbour: RelativeBoardPosition) { + internal fun computePoints_copiedGuild(guildCard: Card, neighbour: RelativeBoardPosition) { val effect = SpecialAbilityActivation(SpecialAbility.COPY_GUILD) val player = SimplePlayer(0, testTable(5)) @@ -71,7 +71,7 @@ class SpecialAbilityActivationTest { @JvmStatic @DataPoints - fun guilds(): Array<Card> { + internal fun guilds(): Array<Card> { val bonus = BonusPerBoardElement( listOf(RelativeBoardPosition.LEFT, RelativeBoardPosition.RIGHT), BoardElementType.CARD, diff --git a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/moves/BuildWonderMoveTest.kt b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/moves/BuildWonderMoveTest.kt index acced6be..b0667d67 100644 --- a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/moves/BuildWonderMoveTest.kt +++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/moves/BuildWonderMoveTest.kt @@ -3,7 +3,7 @@ package org.luxons.sevenwonders.game.moves import org.junit.Test import org.luxons.sevenwonders.game.PlayerContext import org.luxons.sevenwonders.game.Settings -import org.luxons.sevenwonders.game.api.Table +import org.luxons.sevenwonders.game.boards.Table import org.luxons.sevenwonders.game.cards.Card import org.luxons.sevenwonders.game.test.createMove import org.luxons.sevenwonders.game.test.sampleCards diff --git a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/resources/BestPriceCalculatorTest.kt b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/resources/BestPriceCalculatorTest.kt index e6751776..5d99ae00 100644 --- a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/resources/BestPriceCalculatorTest.kt +++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/resources/BestPriceCalculatorTest.kt @@ -2,7 +2,7 @@ package org.luxons.sevenwonders.game.resources import org.junit.Test import org.luxons.sevenwonders.game.SimplePlayer -import org.luxons.sevenwonders.game.api.Table +import org.luxons.sevenwonders.game.boards.Table import org.luxons.sevenwonders.game.resources.Provider.LEFT_PLAYER import org.luxons.sevenwonders.game.resources.Provider.RIGHT_PLAYER import org.luxons.sevenwonders.game.resources.ResourceType.CLAY diff --git a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/test/TestUtils.kt b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/test/TestUtils.kt index 4bf41a8b..78386b3d 100644 --- a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/test/TestUtils.kt +++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/test/TestUtils.kt @@ -5,11 +5,11 @@ import org.luxons.sevenwonders.game.PlayerContext import org.luxons.sevenwonders.game.Settings import org.luxons.sevenwonders.game.api.CustomizableSettings import org.luxons.sevenwonders.game.api.PlayerMove -import org.luxons.sevenwonders.game.api.Table import org.luxons.sevenwonders.game.boards.Board import org.luxons.sevenwonders.game.boards.RelativeBoardPosition import org.luxons.sevenwonders.game.boards.Science import org.luxons.sevenwonders.game.boards.ScienceType +import org.luxons.sevenwonders.game.boards.Table import org.luxons.sevenwonders.game.cards.Card import org.luxons.sevenwonders.game.cards.CardBack import org.luxons.sevenwonders.game.cards.Color @@ -38,7 +38,8 @@ internal fun testSettings(nbPlayers: Int = 5, initialGold: Int = 0): Settings = internal fun testTable(nbPlayers: Int = 5): Table = testTable(testSettings(nbPlayers)) -internal fun testTable(settings: Settings): Table = Table(testBoards(settings.nbPlayers, settings)) +internal fun testTable(settings: Settings): Table = + Table(testBoards(settings.nbPlayers, settings)) private fun testBoards(count: Int, settings: Settings): List<Board> = List(count) { testBoard(settings) } |