diff options
33 files changed, 1384 insertions, 1487 deletions
diff --git a/game-engine/src/main/java/org/luxons/sevenwonders/game/moves/BuildWonderMove.java b/game-engine/src/main/java/org/luxons/sevenwonders/game/moves/BuildWonderMove.java deleted file mode 100644 index f70d2626..00000000 --- a/game-engine/src/main/java/org/luxons/sevenwonders/game/moves/BuildWonderMove.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.luxons.sevenwonders.game.moves; - -import java.util.List; - -import org.luxons.sevenwonders.game.Settings; -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.cards.Card; - -public class BuildWonderMove extends CardFromHandMove { - - BuildWonderMove(int playerIndex, Card card, PlayerMove move) { - super(playerIndex, card, move); - } - - @Override - public void validate(Table table, List<Card> playerHand) throws InvalidMoveException { - super.validate(table, playerHand); - Board board = table.getBoard(getPlayerIndex()); - if (!board.getWonder().isNextStageBuildable(table, getPlayerIndex(), getTransactions())) { - throw new InvalidMoveException( - String.format("Player %d cannot upgrade his wonder with the given resources", getPlayerIndex())); - } - } - - @Override - public void place(Table table, List<Card> discardedCards, Settings settings) { - Board board = table.getBoard(getPlayerIndex()); - board.getWonder().buildLevel(getCard().getBack()); - } - - @Override - public void activate(Table table, List<Card> discardedCards, Settings settings) { - int playerIndex = getPlayerIndex(); - Board board = table.getBoard(playerIndex); - board.getWonder().activateLastBuiltStage(table, playerIndex, getTransactions()); - } -} diff --git a/game-engine/src/main/java/org/luxons/sevenwonders/game/moves/CardFromHandMove.java b/game-engine/src/main/java/org/luxons/sevenwonders/game/moves/CardFromHandMove.java deleted file mode 100644 index 1794966d..00000000 --- a/game-engine/src/main/java/org/luxons/sevenwonders/game/moves/CardFromHandMove.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.luxons.sevenwonders.game.moves; - -import java.util.List; - -import org.luxons.sevenwonders.game.api.PlayerMove; -import org.luxons.sevenwonders.game.api.Table; -import org.luxons.sevenwonders.game.cards.Card; - -public abstract class CardFromHandMove extends Move { - - CardFromHandMove(int playerIndex, Card card, PlayerMove move) { - super(playerIndex, card, move); - } - - @Override - public void validate(Table table, List<Card> playerHand) throws InvalidMoveException { - if (!playerHand.contains(getCard())) { - throw new InvalidMoveException( - String.format("Player %d does not have the card '%s' in his hand", getPlayerIndex(), - getCard().getName())); - } - } -} diff --git a/game-engine/src/main/java/org/luxons/sevenwonders/game/moves/CopyGuildMove.java b/game-engine/src/main/java/org/luxons/sevenwonders/game/moves/CopyGuildMove.java deleted file mode 100644 index a93670c5..00000000 --- a/game-engine/src/main/java/org/luxons/sevenwonders/game/moves/CopyGuildMove.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.luxons.sevenwonders.game.moves; - -import java.util.List; - -import org.luxons.sevenwonders.game.Settings; -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.cards.Card; -import org.luxons.sevenwonders.game.cards.Color; -import org.luxons.sevenwonders.game.effects.SpecialAbility; - -public class CopyGuildMove extends Move { - - CopyGuildMove(int playerIndex, Card card, PlayerMove move) { - super(playerIndex, card, move); - } - - @Override - public void validate(Table table, List<Card> playerHand) throws InvalidMoveException { - Board board = table.getBoard(getPlayerIndex()); - if (!board.hasSpecial(SpecialAbility.COPY_GUILD)) { - throw new InvalidMoveException( - String.format("Player %d does not have the ability to copy guild cards", getPlayerIndex())); - } - if (getCard().getColor() != Color.PURPLE) { - throw new InvalidMoveException( - String.format("Player %d cannot copy card %s because it is not a guild card", getPlayerIndex(), - getCard().getName())); - } - boolean leftNeighbourHasIt = neighbourHasTheCard(table, RelativeBoardPosition.LEFT); - boolean rightNeighbourHasIt = neighbourHasTheCard(table, RelativeBoardPosition.RIGHT); - if (!leftNeighbourHasIt && !rightNeighbourHasIt) { - throw new InvalidMoveException( - String.format("Player %d cannot copy card %s because none of his neighbour has it", - getPlayerIndex(), getCard().getName())); - } - } - - private boolean neighbourHasTheCard(Table table, RelativeBoardPosition position) { - Board neighbourBoard = table.getBoard(getPlayerIndex(), position); - return neighbourBoard.getPlayedCards().contains(getCard()); - } - - @Override - public void place(Table table, List<Card> discardedCards, Settings settings) { - // nothing special to do here - } - - @Override - public void activate(Table table, List<Card> discardedCards, Settings settings) { - Board board = table.getBoard(getPlayerIndex()); - board.setCopiedGuild(getCard()); - } -} diff --git a/game-engine/src/main/java/org/luxons/sevenwonders/game/moves/DiscardMove.java b/game-engine/src/main/java/org/luxons/sevenwonders/game/moves/DiscardMove.java deleted file mode 100644 index 076a593c..00000000 --- a/game-engine/src/main/java/org/luxons/sevenwonders/game/moves/DiscardMove.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.luxons.sevenwonders.game.moves; - -import java.util.List; - -import org.luxons.sevenwonders.game.Settings; -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.cards.Card; - -public class DiscardMove extends CardFromHandMove { - - DiscardMove(int playerIndex, Card card, PlayerMove move) { - super(playerIndex, card, move); - } - - @Override - public void place(Table table, List<Card> discardedCards, Settings settings) { - discardedCards.add(getCard()); - } - - @Override - public void activate(Table table, List<Card> discardedCards, Settings settings) { - Board board = table.getBoard(getPlayerIndex()); - board.addGold(settings.getDiscardedCardGold()); - } -} diff --git a/game-engine/src/main/java/org/luxons/sevenwonders/game/moves/InvalidMoveException.java b/game-engine/src/main/java/org/luxons/sevenwonders/game/moves/InvalidMoveException.java deleted file mode 100644 index 58190274..00000000 --- a/game-engine/src/main/java/org/luxons/sevenwonders/game/moves/InvalidMoveException.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.luxons.sevenwonders.game.moves; - -public class InvalidMoveException extends IllegalArgumentException { - - public InvalidMoveException(String message) { - super(message); - } -} diff --git a/game-engine/src/main/java/org/luxons/sevenwonders/game/moves/Move.java b/game-engine/src/main/java/org/luxons/sevenwonders/game/moves/Move.java deleted file mode 100644 index cfb12e67..00000000 --- a/game-engine/src/main/java/org/luxons/sevenwonders/game/moves/Move.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.luxons.sevenwonders.game.moves; - -import java.util.List; - -import org.luxons.sevenwonders.game.Settings; -import org.luxons.sevenwonders.game.api.PlayerMove; -import org.luxons.sevenwonders.game.api.Table; -import org.luxons.sevenwonders.game.cards.Card; -import org.luxons.sevenwonders.game.resources.ResourceTransactions; - -public abstract class Move { - - private int playerIndex; - - private Card card; - - private MoveType type; - - private ResourceTransactions transactions; - - Move(int playerIndex, Card card, PlayerMove move) { - this.playerIndex = playerIndex; - this.card = card; - this.type = move.getType(); - this.transactions = new ResourceTransactions(move.getTransactions()); - } - - public int getPlayerIndex() { - return playerIndex; - } - - public Card getCard() { - return card; - } - - public MoveType getType() { - return type; - } - - public ResourceTransactions getTransactions() { - return transactions; - } - - public abstract void validate(Table table, List<Card> playerHand) throws InvalidMoveException; - - public abstract void place(Table table, List<Card> discardedCards, Settings settings); - - public abstract void activate(Table table, List<Card> discardedCards, Settings settings); -} diff --git a/game-engine/src/main/java/org/luxons/sevenwonders/game/moves/MoveType.java b/game-engine/src/main/java/org/luxons/sevenwonders/game/moves/MoveType.java deleted file mode 100644 index bf64344d..00000000 --- a/game-engine/src/main/java/org/luxons/sevenwonders/game/moves/MoveType.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.luxons.sevenwonders.game.moves; - -import org.luxons.sevenwonders.game.api.PlayerMove; -import org.luxons.sevenwonders.game.cards.Card; - -public enum MoveType { - PLAY { - @Override - public Move resolve(int playerIndex, Card card, PlayerMove move) { - return new PlayCardMove(playerIndex, card, move); - } - }, - PLAY_FREE { - @Override - public Move resolve(int playerIndex, Card card, PlayerMove move) { - return new PlayFreeCardMove(playerIndex, card, move); - } - }, - UPGRADE_WONDER { - @Override - public Move resolve(int playerIndex, Card card, PlayerMove move) { - return new BuildWonderMove(playerIndex, card, move); - } - }, - DISCARD { - @Override - public Move resolve(int playerIndex, Card card, PlayerMove move) { - return new DiscardMove(playerIndex, card, move); - } - }, - COPY_GUILD { - @Override - public Move resolve(int playerIndex, Card card, PlayerMove move) { - return new CopyGuildMove(playerIndex, card, move); - } - }; - - public abstract Move resolve(int playerIndex, Card card, PlayerMove move); -} diff --git a/game-engine/src/main/java/org/luxons/sevenwonders/game/moves/PlayCardMove.java b/game-engine/src/main/java/org/luxons/sevenwonders/game/moves/PlayCardMove.java deleted file mode 100644 index 18d6ba90..00000000 --- a/game-engine/src/main/java/org/luxons/sevenwonders/game/moves/PlayCardMove.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.luxons.sevenwonders.game.moves; - -import java.util.List; - -import org.luxons.sevenwonders.game.Settings; -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.cards.Card; - -public class PlayCardMove extends CardFromHandMove { - - PlayCardMove(int playerIndex, Card card, PlayerMove move) { - super(playerIndex, card, move); - } - - @Override - public void validate(Table table, List<Card> playerHand) throws InvalidMoveException { - super.validate(table, playerHand); - Board board = table.getBoard(getPlayerIndex()); - if (!getCard().isChainableOn(board) && !getCard().getRequirements() - .areMetWithHelpBy(board, getTransactions())) { - throw new InvalidMoveException( - String.format("Player %d cannot play the card %s with the given resources", getPlayerIndex(), - getCard().getName())); - } - } - - @Override - public void place(Table table, List<Card> discardedCards, Settings settings) { - Board board = table.getBoard(getPlayerIndex()); - board.addCard(getCard()); - } - - @Override - public void activate(Table table, List<Card> discardedCards, Settings settings) { - getCard().applyTo(table, getPlayerIndex(), getTransactions()); - } -} diff --git a/game-engine/src/main/java/org/luxons/sevenwonders/game/moves/PlayFreeCardMove.java b/game-engine/src/main/java/org/luxons/sevenwonders/game/moves/PlayFreeCardMove.java deleted file mode 100644 index 4e8eefa5..00000000 --- a/game-engine/src/main/java/org/luxons/sevenwonders/game/moves/PlayFreeCardMove.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.luxons.sevenwonders.game.moves; - -import java.util.List; - -import org.luxons.sevenwonders.game.Settings; -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.cards.Card; - -public class PlayFreeCardMove extends CardFromHandMove { - - PlayFreeCardMove(int playerIndex, Card card, PlayerMove move) { - super(playerIndex, card, move); - } - - @Override - public void validate(Table table, List<Card> playerHand) throws InvalidMoveException { - super.validate(table, playerHand); - Board board = table.getBoard(getPlayerIndex()); - if (!board.canPlayFreeCard(table.getCurrentAge())) { - throw new InvalidMoveException( - String.format("Player %d cannot play the card %s for free", getPlayerIndex(), getCard().getName())); - } - } - - @Override - public void place(Table table, List<Card> discardedCards, Settings settings) { - Board board = table.getBoard(getPlayerIndex()); - board.addCard(getCard()); - } - - @Override - public void activate(Table table, List<Card> discardedCards, Settings settings) { - // only apply effects, without paying the cost - getCard().getEffects().forEach(e -> e.apply(table, getPlayerIndex())); - Board board = table.getBoard(getPlayerIndex()); - board.consumeFreeCard(table.getCurrentAge()); - } -} 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 index 37ab3e6f..6cfd3679 100644 --- 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 @@ -1,6 +1,6 @@ package org.luxons.sevenwonders.game.api -enum class Action constructor(val message: String) { +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."), 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 index d487a9ac..1b11edef 100644 --- 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 @@ -9,9 +9,7 @@ import org.luxons.sevenwonders.game.cards.Card class HandCard(val card: Card, table: Table, playerIndex: Int) { val isChainable: Boolean - val isFree: Boolean - val isPlayable: Boolean = card.isPlayable(table, playerIndex) init { diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/PlayerMove.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/PlayerMove.kt index 4d4ef7cc..95e6b13c 100644 --- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/PlayerMove.kt +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/PlayerMove.kt @@ -3,7 +3,7 @@ package org.luxons.sevenwonders.game.api import org.luxons.sevenwonders.game.moves.MoveType import org.luxons.sevenwonders.game.resources.ResourceTransaction -data class PlayerMove @JvmOverloads constructor( +data class PlayerMove( val type: MoveType, val cardName: String, val transactions: Collection<ResourceTransaction> = emptyList() diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/BuildWonderMove.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/BuildWonderMove.kt new file mode 100644 index 00000000..bbd9ebab --- /dev/null +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/BuildWonderMove.kt @@ -0,0 +1,25 @@ +package org.luxons.sevenwonders.game.moves + +import org.luxons.sevenwonders.game.Settings +import org.luxons.sevenwonders.game.api.PlayerMove +import org.luxons.sevenwonders.game.api.Table +import org.luxons.sevenwonders.game.cards.Card + +class BuildWonderMove internal constructor(playerIndex: Int, card: Card, move: PlayerMove) : + CardFromHandMove(playerIndex, card, move) { + + @Throws(InvalidMoveException::class) + override fun validate(table: Table, playerHand: List<Card>) { + super.validate(table, playerHand) + val board = table.getBoard(playerIndex) + if (!board.wonder.isNextStageBuildable(table, playerIndex, transactions)) { + throw InvalidMoveException("Player $playerIndex cannot upgrade his wonder with the given resources") + } + } + + override fun place(table: Table, discardedCards: MutableList<Card>, settings: Settings) = + table.getBoard(playerIndex).wonder.buildLevel(card.back) + + override fun activate(table: Table, discardedCards: List<Card>, settings: Settings) = + table.getBoard(playerIndex).wonder.activateLastBuiltStage(table, playerIndex, transactions) +} diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/CardFromHandMove.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/CardFromHandMove.kt new file mode 100644 index 00000000..7b084d43 --- /dev/null +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/CardFromHandMove.kt @@ -0,0 +1,16 @@ +package org.luxons.sevenwonders.game.moves + +import org.luxons.sevenwonders.game.api.PlayerMove +import org.luxons.sevenwonders.game.api.Table +import org.luxons.sevenwonders.game.cards.Card + +abstract class CardFromHandMove internal constructor(playerIndex: Int, card: Card, move: PlayerMove) : + Move(playerIndex, card, move) { + + @Throws(InvalidMoveException::class) + override fun validate(table: Table, playerHand: List<Card>) { + if (!playerHand.contains(card)) { + throw InvalidMoveException("Player $playerIndex does not have the card '${card.name}' in his hand") + } + } +} diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/CopyGuildMove.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/CopyGuildMove.kt new file mode 100644 index 00000000..5a017e53 --- /dev/null +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/CopyGuildMove.kt @@ -0,0 +1,41 @@ +package org.luxons.sevenwonders.game.moves + +import org.luxons.sevenwonders.game.Settings +import org.luxons.sevenwonders.game.api.PlayerMove +import org.luxons.sevenwonders.game.api.Table +import org.luxons.sevenwonders.game.boards.RelativeBoardPosition +import org.luxons.sevenwonders.game.cards.Card +import org.luxons.sevenwonders.game.cards.Color +import org.luxons.sevenwonders.game.effects.SpecialAbility + +class CopyGuildMove internal constructor(playerIndex: Int, card: Card, move: PlayerMove) : + Move(playerIndex, card, move) { + + @Throws(InvalidMoveException::class) + override fun validate(table: Table, playerHand: List<Card>) { + val board = table.getBoard(playerIndex) + if (!board.hasSpecial(SpecialAbility.COPY_GUILD)) { + throw InvalidMoveException("Player $playerIndex does not have the ability to copy guild cards") + } + if (card.color !== Color.PURPLE) { + throw InvalidMoveException("Player $playerIndex cannot copy card ${card.name} because it is not a guild card") + } + val leftNeighbourHasIt = neighbourHasTheCard(table, RelativeBoardPosition.LEFT) + val rightNeighbourHasIt = neighbourHasTheCard(table, RelativeBoardPosition.RIGHT) + if (!leftNeighbourHasIt && !rightNeighbourHasIt) { + throw InvalidMoveException("Player $playerIndex cannot copy card ${card.name} because none of his neighbour has it") + } + } + + private fun neighbourHasTheCard(table: Table, position: RelativeBoardPosition): Boolean { + val neighbourBoard = table.getBoard(playerIndex, position) + return neighbourBoard.getPlayedCards().contains(card) + } + + // nothing special to do here + override fun place(table: Table, discardedCards: MutableList<Card>, settings: Settings) = Unit + + override fun activate(table: Table, discardedCards: List<Card>, settings: Settings) { + table.getBoard(playerIndex).copiedGuild = card + } +} diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/DiscardMove.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/DiscardMove.kt new file mode 100644 index 00000000..cf1b69ba --- /dev/null +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/DiscardMove.kt @@ -0,0 +1,20 @@ +package org.luxons.sevenwonders.game.moves + +import org.luxons.sevenwonders.game.Settings +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.cards.Card + +class DiscardMove internal constructor(playerIndex: Int, card: Card, move: PlayerMove) : + CardFromHandMove(playerIndex, card, move) { + + override fun place(table: Table, discardedCards: MutableList<Card>, settings: Settings) { + discardedCards.add(card) + } + + override fun activate(table: Table, discardedCards: List<Card>, settings: Settings) { + val board = table.getBoard(playerIndex) + board.addGold(settings.discardedCardGold) + } +} diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/InvalidMoveException.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/InvalidMoveException.kt new file mode 100644 index 00000000..d816355d --- /dev/null +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/InvalidMoveException.kt @@ -0,0 +1,3 @@ +package org.luxons.sevenwonders.game.moves + +class InvalidMoveException(message: String) : IllegalArgumentException(message) 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 new file mode 100644 index 00000000..885f267f --- /dev/null +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/Move.kt @@ -0,0 +1,21 @@ +package org.luxons.sevenwonders.game.moves + +import org.luxons.sevenwonders.game.Settings +import org.luxons.sevenwonders.game.api.PlayerMove +import org.luxons.sevenwonders.game.api.Table +import org.luxons.sevenwonders.game.cards.Card +import org.luxons.sevenwonders.game.resources.ResourceTransactions + +abstract class Move internal constructor(val playerIndex: Int, val card: Card, move: PlayerMove) { + + val type: MoveType = move.type + + val transactions: ResourceTransactions = ResourceTransactions(move.transactions) + + @Throws(InvalidMoveException::class) + abstract fun validate(table: Table, playerHand: List<Card>) + + abstract fun place(table: Table, discardedCards: MutableList<Card>, settings: Settings) + + abstract fun activate(table: Table, discardedCards: List<Card>, settings: Settings) +} diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/MoveType.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/MoveType.kt new file mode 100644 index 00000000..ced0f3a1 --- /dev/null +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/MoveType.kt @@ -0,0 +1,24 @@ +package org.luxons.sevenwonders.game.moves + +import org.luxons.sevenwonders.game.api.PlayerMove +import org.luxons.sevenwonders.game.cards.Card + +enum class MoveType { + PLAY { + override fun resolve(playerIndex: Int, card: Card, move: PlayerMove) = PlayCardMove(playerIndex, card, move) + }, + PLAY_FREE { + override fun resolve(playerIndex: Int, card: Card, move: PlayerMove) = PlayFreeCardMove(playerIndex, card, move) + }, + UPGRADE_WONDER { + override fun resolve(playerIndex: Int, card: Card, move: PlayerMove) = BuildWonderMove(playerIndex, card, move) + }, + DISCARD { + override fun resolve(playerIndex: Int, card: Card, move: PlayerMove) = DiscardMove(playerIndex, card, move) + }, + COPY_GUILD { + override fun resolve(playerIndex: Int, card: Card, move: PlayerMove) = CopyGuildMove(playerIndex, card, move) + }; + + abstract fun resolve(playerIndex: Int, card: Card, move: PlayerMove): Move +} diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/PlayCardMove.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/PlayCardMove.kt new file mode 100644 index 00000000..b87916b1 --- /dev/null +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/PlayCardMove.kt @@ -0,0 +1,25 @@ +package org.luxons.sevenwonders.game.moves + +import org.luxons.sevenwonders.game.Settings +import org.luxons.sevenwonders.game.api.PlayerMove +import org.luxons.sevenwonders.game.api.Table +import org.luxons.sevenwonders.game.cards.Card + +class PlayCardMove internal constructor(playerIndex: Int, card: Card, move: PlayerMove) : + CardFromHandMove(playerIndex, card, move) { + + @Throws(InvalidMoveException::class) + override fun validate(table: Table, playerHand: List<Card>) { + super.validate(table, playerHand) + val board = table.getBoard(playerIndex) + if (!card.isChainableOn(board) && !card.requirements.areMetWithHelpBy(board, transactions)) { + throw InvalidMoveException("Player $playerIndex cannot play the card ${card.name} with the given resources") + } + } + + override fun place(table: Table, discardedCards: MutableList<Card>, settings: Settings) = + table.getBoard(playerIndex).addCard(card) + + override fun activate(table: Table, discardedCards: List<Card>, settings: Settings) = + card.applyTo(table, playerIndex, transactions) +} diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/PlayFreeCardMove.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/PlayFreeCardMove.kt new file mode 100644 index 00000000..125b34a6 --- /dev/null +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/moves/PlayFreeCardMove.kt @@ -0,0 +1,34 @@ +package org.luxons.sevenwonders.game.moves + +import org.luxons.sevenwonders.game.Settings +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.cards.Card + +class PlayFreeCardMove internal constructor(playerIndex: Int, card: Card, move: PlayerMove) : + CardFromHandMove(playerIndex, card, move) { + + @Throws(InvalidMoveException::class) + override fun validate(table: Table, playerHand: List<Card>) { + super.validate(table, playerHand) + val board = table.getBoard(playerIndex) + if (!board.canPlayFreeCard(table.currentAge)) { + throw InvalidMoveException( + String.format("Player %d cannot play the card %s for free", playerIndex, card.name) + ) + } + } + + override fun place(table: Table, discardedCards: MutableList<Card>, settings: Settings) { + val board = table.getBoard(playerIndex) + board.addCard(card) + } + + override fun activate(table: Table, discardedCards: List<Card>, settings: Settings) { + // only apply effects, without paying the cost + card.effects.forEach { e -> e.apply(table, playerIndex) } + val board = table.getBoard(playerIndex) + board.consumeFreeCard(table.currentAge) + } +} diff --git a/game-engine/src/test/java/org/luxons/sevenwonders/game/moves/BuildWonderMoveTest.java b/game-engine/src/test/java/org/luxons/sevenwonders/game/moves/BuildWonderMoveTest.java deleted file mode 100644 index 87e1d704..00000000 --- a/game-engine/src/test/java/org/luxons/sevenwonders/game/moves/BuildWonderMoveTest.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.luxons.sevenwonders.game.moves; - -import java.util.Collections; -import java.util.List; - -import org.junit.Test; -import org.luxons.sevenwonders.game.Settings; -import org.luxons.sevenwonders.game.api.Table; -import org.luxons.sevenwonders.game.cards.Card; -import org.luxons.sevenwonders.game.test.TestUtilsKt; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - -public class BuildWonderMoveTest { - - @Test(expected = InvalidMoveException.class) - public void validate_failsWhenCardNotInHand() { - Table table = TestUtilsKt.testTable(3); - List<Card> hand = TestUtilsKt.sampleCards(0, 7); - Card anotherCard = TestUtilsKt.testCard("Card that is not in the hand"); - Move move = TestUtilsKt.createMove(0, anotherCard, MoveType.UPGRADE_WONDER); - - move.validate(table, hand); - } - - @Test(expected = InvalidMoveException.class) - public void validate_failsWhenWonderIsCompletelyBuilt() { - Settings settings = TestUtilsKt.testSettings(3); - Table table = TestUtilsKt.testTable(settings); - List<Card> hand = TestUtilsKt.sampleCards(0, 7); - - fillPlayerWonderLevels(settings, table, hand); - - // should fail because the wonder is already full - buildOneWonderLevel(settings, table, hand, 4); - } - - private static void fillPlayerWonderLevels(Settings settings, Table table, List<Card> hand) { - try { - int nbLevels = table.getBoard(0).getWonder().getStages().size(); - for (int i = 0; i < nbLevels; i++) { - buildOneWonderLevel(settings, table, hand, i); - } - } catch (InvalidMoveException e) { - fail("Building wonder levels should not fail before being full"); - } - } - - private static void buildOneWonderLevel(Settings settings, Table table, List<Card> hand, int cardIndex) { - Card card = hand.get(cardIndex); - Move move = TestUtilsKt.createMove(0, card, MoveType.UPGRADE_WONDER); - move.validate(table, hand); - move.place(table, Collections.emptyList(), settings); - move.activate(table, Collections.emptyList(), settings); - } - - @Test - public void place_increasesWonderLevel() { - Settings settings = TestUtilsKt.testSettings(3); - Table table = TestUtilsKt.testTable(settings); - List<Card> hand = TestUtilsKt.sampleCards(0, 7); - Card cardToUse = hand.get(0); - Move move = TestUtilsKt.createMove(0, cardToUse, MoveType.UPGRADE_WONDER); - move.validate(table, hand); // should not fail - - int initialStage = table.getBoard(0).getWonder().getNbBuiltStages(); - - move.place(table, Collections.emptyList(), settings); - - int newStage = table.getBoard(0).getWonder().getNbBuiltStages(); - - // we need to see the level increase before activation so that other players - assertEquals(initialStage + 1, newStage); - } - -} diff --git a/game-engine/src/test/java/org/luxons/sevenwonders/game/resources/BestPriceCalculatorTest.java b/game-engine/src/test/java/org/luxons/sevenwonders/game/resources/BestPriceCalculatorTest.java deleted file mode 100644 index bb0e757b..00000000 --- a/game-engine/src/test/java/org/luxons/sevenwonders/game/resources/BestPriceCalculatorTest.java +++ /dev/null @@ -1,129 +0,0 @@ -package org.luxons.sevenwonders.game.resources; - -import java.util.Arrays; - -import org.junit.Test; -import org.luxons.sevenwonders.game.api.Table; -import org.luxons.sevenwonders.game.boards.Board; -import org.luxons.sevenwonders.game.test.TestUtilsKt; - -import static org.junit.Assert.assertEquals; -import static org.luxons.sevenwonders.game.resources.Provider.LEFT_PLAYER; -import static org.luxons.sevenwonders.game.resources.Provider.RIGHT_PLAYER; -import static org.luxons.sevenwonders.game.resources.ResourceType.CLAY; -import static org.luxons.sevenwonders.game.resources.ResourceType.GLASS; -import static org.luxons.sevenwonders.game.resources.ResourceType.ORE; -import static org.luxons.sevenwonders.game.resources.ResourceType.STONE; -import static org.luxons.sevenwonders.game.resources.ResourceType.WOOD; - -public class BestPriceCalculatorTest { - - @Test - public void bestPrice_0forEmptyResources() { - Table table = TestUtilsKt.testTable(3); - Resources resources = new Resources(); - assertEquals(0, BestPriceCalculator.bestPrice(resources, table, 0)); - assertEquals(new ResourceTransactions(), BestPriceCalculator.bestSolution(resources, table, 0)); - } - - @Test - public void bestPrice_fixedResources_defaultCost() { - Board left = TestUtilsKt.testBoard(STONE); - Board main = TestUtilsKt.testBoard(STONE); - Board right = TestUtilsKt.testBoard(WOOD); - Table table = new Table(Arrays.asList(main, right, left)); - - Resources resources = TestUtilsKt.createResources(STONE, STONE); - assertEquals(2, BestPriceCalculator.bestPrice(resources, table, 0)); - assertEquals(4, BestPriceCalculator.bestPrice(resources, table, 1)); - assertEquals(2, BestPriceCalculator.bestPrice(resources, table, 2)); - - ResourceTransaction stoneLeftSingle = TestUtilsKt.createTransaction(LEFT_PLAYER, STONE); - ResourceTransaction stoneRightSingle = TestUtilsKt.createTransaction(RIGHT_PLAYER, STONE); - - ResourceTransactions stoneLeft = TestUtilsKt.createTransactions(stoneLeftSingle); - ResourceTransactions stoneRight = TestUtilsKt.createTransactions(stoneRightSingle); - ResourceTransactions stoneLeftAndRight = TestUtilsKt.createTransactions(stoneLeftSingle, stoneRightSingle); - - assertEquals(stoneLeft, BestPriceCalculator.bestSolution(resources, table, 0)); - assertEquals(stoneLeftAndRight, BestPriceCalculator.bestSolution(resources, table, 1)); - assertEquals(stoneRight, BestPriceCalculator.bestSolution(resources, table, 2)); - } - - @Test - public void bestPrice_fixedResources_overridenCost() { - Board main = TestUtilsKt.testBoard(STONE); - main.getTradingRules().setCost(WOOD, RIGHT_PLAYER, 1); - - Board left = TestUtilsKt.testBoard(WOOD); - Board right = TestUtilsKt.testBoard(WOOD); - Board opposite = TestUtilsKt.testBoard(GLASS); - Table table = new Table(Arrays.asList(main, right, opposite, left)); - - Resources resources = TestUtilsKt.createResources(WOOD); - assertEquals(1, BestPriceCalculator.bestPrice(resources, table, 0)); - assertEquals(0, BestPriceCalculator.bestPrice(resources, table, 1)); - assertEquals(2, BestPriceCalculator.bestPrice(resources, table, 2)); - assertEquals(0, BestPriceCalculator.bestPrice(resources, table, 3)); - - ResourceTransactions woodLeft = TestUtilsKt.createTransactions(LEFT_PLAYER, WOOD); - ResourceTransactions woodRight = TestUtilsKt.createTransactions(RIGHT_PLAYER, WOOD); - assertEquals(woodRight, BestPriceCalculator.bestSolution(resources, table, 0)); - assertEquals(new ResourceTransactions(), BestPriceCalculator.bestSolution(resources, table, 1)); - assertEquals(woodLeft, BestPriceCalculator.bestSolution(resources, table, 2)); - assertEquals(new ResourceTransactions(), BestPriceCalculator.bestSolution(resources, table, 3)); - } - - @Test - public void bestPrice_mixedResources_overridenCost() { - Board left = TestUtilsKt.testBoard(WOOD); - - Board main = TestUtilsKt.testBoard(STONE); - main.getTradingRules().setCost(WOOD, RIGHT_PLAYER, 1); - - Board right = TestUtilsKt.testBoard(ORE); - right.getProduction().addChoice(WOOD, CLAY); - right.getPublicProduction().addChoice(WOOD, CLAY); - - Table table = new Table(Arrays.asList(main, right, left)); - - Resources resources = TestUtilsKt.createResources(WOOD); - assertEquals(1, BestPriceCalculator.bestPrice(resources, table, 0)); - assertEquals(0, BestPriceCalculator.bestPrice(resources, table, 1)); - assertEquals(0, BestPriceCalculator.bestPrice(resources, table, 2)); - - ResourceTransactions woodRight = TestUtilsKt.createTransactions(RIGHT_PLAYER, WOOD); - - assertEquals(woodRight, BestPriceCalculator.bestSolution(resources, table, 0)); - assertEquals(new ResourceTransactions(), BestPriceCalculator.bestSolution(resources, table, 1)); - assertEquals(new ResourceTransactions(), BestPriceCalculator.bestSolution(resources, table, 2)); - } - - @Test - public void bestPrice_chooseCheapest() { - Board left = TestUtilsKt.testBoard(WOOD); - - Board main = TestUtilsKt.testBoard(WOOD); - main.getProduction().addChoice(CLAY, ORE); - main.getTradingRules().setCost(CLAY, RIGHT_PLAYER, 1); - - Board right = TestUtilsKt.testBoard(WOOD); - right.getProduction().addFixedResource(ORE, 1); - right.getProduction().addFixedResource(CLAY, 1); - right.getPublicProduction().addFixedResource(ORE, 1); - right.getPublicProduction().addFixedResource(CLAY, 1); - - Table table = new Table(Arrays.asList(main, right, left)); - - Resources resources = TestUtilsKt.createResources(ORE, CLAY); - assertEquals(1, BestPriceCalculator.bestPrice(resources, table, 0)); - assertEquals(0, BestPriceCalculator.bestPrice(resources, table, 1)); - assertEquals(4, BestPriceCalculator.bestPrice(resources, table, 2)); - - ResourceTransactions oreAndClayLeft = TestUtilsKt.createTransactions(LEFT_PLAYER, ORE, CLAY); - ResourceTransactions clayRight = TestUtilsKt.createTransactions(RIGHT_PLAYER, CLAY); - assertEquals(clayRight, BestPriceCalculator.bestSolution(resources, table, 0)); - assertEquals(new ResourceTransactions(), BestPriceCalculator.bestSolution(resources, table, 1)); - assertEquals(oreAndClayLeft, BestPriceCalculator.bestSolution(resources, table, 2)); - } -} diff --git a/game-engine/src/test/java/org/luxons/sevenwonders/game/resources/ProductionTest.java b/game-engine/src/test/java/org/luxons/sevenwonders/game/resources/ProductionTest.java deleted file mode 100644 index 2247147c..00000000 --- a/game-engine/src/test/java/org/luxons/sevenwonders/game/resources/ProductionTest.java +++ /dev/null @@ -1,324 +0,0 @@ -package org.luxons.sevenwonders.game.resources; - -import java.util.EnumSet; -import java.util.HashSet; -import java.util.Set; - -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -public class ProductionTest { - - private Resources emptyResources; - - private Resources resources1Wood; - - private Resources resources1Stone; - - private Resources resources1Stone1Wood; - - private Resources resources2Stones; - - private Resources resources2Stones3Clay; - - @Before - public void init() { - emptyResources = new Resources(); - - resources1Wood = new Resources(); - resources1Wood.add(ResourceType.WOOD, 1); - - resources1Stone = new Resources(); - resources1Stone.add(ResourceType.STONE, 1); - - resources1Stone1Wood = new Resources(); - resources1Stone1Wood.add(ResourceType.STONE, 1); - resources1Stone1Wood.add(ResourceType.WOOD, 1); - - resources2Stones = new Resources(); - resources2Stones.add(ResourceType.STONE, 2); - - resources2Stones3Clay = new Resources(); - resources2Stones3Clay.add(ResourceType.STONE, 2); - resources2Stones3Clay.add(ResourceType.CLAY, 3); - } - - @Test - public void contains_newProductionContainsEmpty() { - Production production = new Production(); - assertTrue(production.contains(emptyResources)); - } - - @Test - public void contains_singleFixedResource_noneAtAll() { - Production production = new Production(); - assertFalse(production.contains(resources2Stones)); - } - - @Test - public void contains_singleFixedResource_notEnough() { - Production production = new Production(); - production.addFixedResource(ResourceType.STONE, 1); - assertFalse(production.contains(resources2Stones)); - } - - @Test - public void contains_singleFixedResource_justEnough() { - Production production = new Production(); - production.addFixedResource(ResourceType.STONE, 2); - assertTrue(production.contains(resources2Stones)); - } - - @Test - public void contains_singleFixedResource_moreThanEnough() { - Production production = new Production(); - production.addFixedResource(ResourceType.STONE, 3); - assertTrue(production.contains(resources2Stones)); - } - - @Test - public void contains_singleFixedResource_moreThanEnough_amongOthers() { - Production production = new Production(); - production.addFixedResource(ResourceType.STONE, 3); - production.addFixedResource(ResourceType.CLAY, 2); - assertTrue(production.contains(resources2Stones)); - } - - @Test - public void contains_multipleFixedResources_notEnoughOfOne() { - Production production = new Production(); - production.addFixedResource(ResourceType.STONE, 3); - production.addFixedResource(ResourceType.CLAY, 1); - assertFalse(production.contains(resources2Stones3Clay)); - } - - @Test - public void contains_multipleFixedResources_notEnoughOfBoth() { - Production production = new Production(); - production.addFixedResource(ResourceType.STONE, 1); - production.addFixedResource(ResourceType.CLAY, 1); - assertFalse(production.contains(resources2Stones3Clay)); - } - - @Test - public void contains_multipleFixedResources_moreThanEnough() { - Production production = new Production(); - production.addFixedResource(ResourceType.STONE, 3); - production.addFixedResource(ResourceType.CLAY, 5); - assertTrue(production.contains(resources2Stones3Clay)); - } - - @Test - public void contains_singleChoice_containsEmpty() { - Production production = new Production(); - production.addChoice(ResourceType.STONE, ResourceType.CLAY); - assertTrue(production.contains(emptyResources)); - } - - @Test - public void contains_singleChoice_enough() { - Production production = new Production(); - production.addChoice(ResourceType.STONE, ResourceType.WOOD); - assertTrue(production.contains(resources1Wood)); - assertTrue(production.contains(resources1Stone)); - } - - @Test - public void contains_multipleChoices_notBoth() { - Production production = new Production(); - production.addChoice(ResourceType.STONE, ResourceType.CLAY); - production.addChoice(ResourceType.STONE, ResourceType.CLAY); - production.addChoice(ResourceType.STONE, ResourceType.CLAY); - assertFalse(production.contains(resources2Stones3Clay)); - } - - @Test - public void contains_multipleChoices_enough() { - Production production = new Production(); - production.addChoice(ResourceType.STONE, ResourceType.ORE); - production.addChoice(ResourceType.STONE, ResourceType.WOOD); - assertTrue(production.contains(resources1Stone1Wood)); - } - - @Test - public void contains_multipleChoices_enoughReverseOrder() { - Production production = new Production(); - production.addChoice(ResourceType.STONE, ResourceType.WOOD); - production.addChoice(ResourceType.STONE, ResourceType.ORE); - assertTrue(production.contains(resources1Stone1Wood)); - } - - @Test - public void contains_multipleChoices_moreThanEnough() { - Production production = new Production(); - production.addChoice(ResourceType.LOOM, ResourceType.GLASS, ResourceType.PAPYRUS); - production.addChoice(ResourceType.STONE, ResourceType.ORE); - production.addChoice(ResourceType.STONE, ResourceType.WOOD); - assertTrue(production.contains(resources1Stone1Wood)); - } - - @Test - public void contains_mixedFixedAndChoice_enough() { - Production production = new Production(); - production.addFixedResource(ResourceType.WOOD, 1); - production.addChoice(ResourceType.STONE, ResourceType.WOOD); - assertTrue(production.contains(resources1Stone1Wood)); - } - - @Test - public void addAll_empty() { - Production production = new Production(); - production.addAll(emptyResources); - assertTrue(production.contains(emptyResources)); - } - - @Test - public void addAll_singleResource() { - Production production = new Production(); - production.addAll(resources1Stone); - assertTrue(production.contains(resources1Stone)); - } - - @Test - public void addAll_multipleResources() { - Production production = new Production(); - production.addAll(resources2Stones3Clay); - assertTrue(production.contains(resources2Stones3Clay)); - } - - @Test - public void addAll_production_multipleFixedResources() { - Production production = new Production(); - production.addAll(resources2Stones3Clay); - - Production production2 = new Production(); - production2.addAll(production); - - assertTrue(production2.contains(resources2Stones3Clay)); - } - - @Test - public void addAll_production_multipleChoices() { - Production production = new Production(); - production.addChoice(ResourceType.STONE, ResourceType.WOOD); - production.addChoice(ResourceType.STONE, ResourceType.ORE); - - Production production2 = new Production(); - production2.addAll(production); - assertTrue(production.contains(resources1Stone1Wood)); - } - - @Test - public void addAll_production_mixedFixedResourcesAndChoices() { - Production production = new Production(); - production.addFixedResource(ResourceType.WOOD, 1); - production.addChoice(ResourceType.STONE, ResourceType.WOOD); - - Production production2 = new Production(); - production2.addAll(production); - - assertTrue(production.contains(resources1Stone1Wood)); - } - - @Test - public void asChoices_empty() { - Production production = new Production(); - assertTrue(production.asChoices().isEmpty()); - } - - @Test - public void asChoices_onlyChoices() { - Production production = new Production(); - production.addChoice(ResourceType.STONE, ResourceType.WOOD); - production.addChoice(ResourceType.STONE, ResourceType.ORE); - production.addChoice(ResourceType.CLAY, ResourceType.LOOM, ResourceType.GLASS); - assertEquals(production.getAlternativeResources(), production.asChoices()); - } - - @Test - public void asChoices_onlyFixed() { - Production production = new Production(); - production.addFixedResource(ResourceType.WOOD, 1); - production.addFixedResource(ResourceType.CLAY, 2); - - Set<Set<ResourceType>> expected = new HashSet<>(); - expected.add(EnumSet.of(ResourceType.WOOD)); - expected.add(EnumSet.of(ResourceType.CLAY)); - expected.add(EnumSet.of(ResourceType.CLAY)); - - assertEquals(expected, production.asChoices()); - } - - @Test - public void asChoices_mixed() { - Production production = new Production(); - production.addChoice(ResourceType.STONE, ResourceType.ORE); - production.addChoice(ResourceType.CLAY, ResourceType.LOOM, ResourceType.GLASS); - production.addFixedResource(ResourceType.WOOD, 1); - production.addFixedResource(ResourceType.CLAY, 2); - - Set<Set<ResourceType>> expected = new HashSet<>(); - expected.add(EnumSet.of(ResourceType.STONE, ResourceType.ORE)); - expected.add(EnumSet.of(ResourceType.CLAY, ResourceType.LOOM, ResourceType.GLASS)); - expected.add(EnumSet.of(ResourceType.WOOD)); - expected.add(EnumSet.of(ResourceType.CLAY)); - expected.add(EnumSet.of(ResourceType.CLAY)); - - assertEquals(expected, production.asChoices()); - } - - @Test - public void equals_falseWhenNull() { - Production production = new Production(); - production.addFixedResource(ResourceType.GLASS, 1); - production.addChoice(ResourceType.ORE, ResourceType.WOOD); - //noinspection ObjectEqualsNull - assertFalse(production.equals(null)); - } - - @Test - public void equals_falseWhenDifferentClass() { - Production production = new Production(); - production.addFixedResource(ResourceType.GLASS, 1); - Resources resources = new Resources(); - resources.add(ResourceType.GLASS, 1); - //noinspection EqualsBetweenInconvertibleTypes - assertFalse(production.equals(resources)); - } - - @Test - public void equals_trueWhenSame() { - Production production = new Production(); - assertEquals(production, production); - } - - @Test - public void equals_trueWhenSameContent() { - Production production1 = new Production(); - Production production2 = new Production(); - assertTrue(production1.equals(production2)); - production1.addFixedResource(ResourceType.GLASS, 1); - production2.addFixedResource(ResourceType.GLASS, 1); - assertTrue(production1.equals(production2)); - production1.addChoice(ResourceType.ORE, ResourceType.WOOD); - production2.addChoice(ResourceType.ORE, ResourceType.WOOD); - assertTrue(production1.equals(production2)); - } - - @Test - public void hashCode_sameWhenSameContent() { - Production production1 = new Production(); - Production production2 = new Production(); - assertEquals(production1.hashCode(), production2.hashCode()); - production1.addFixedResource(ResourceType.GLASS, 1); - production2.addFixedResource(ResourceType.GLASS, 1); - assertEquals(production1.hashCode(), production2.hashCode()); - production1.addChoice(ResourceType.ORE, ResourceType.WOOD); - production2.addChoice(ResourceType.ORE, ResourceType.WOOD); - assertEquals(production1.hashCode(), production2.hashCode()); - } -} diff --git a/game-engine/src/test/java/org/luxons/sevenwonders/game/resources/ResourceTransactionsTest.java b/game-engine/src/test/java/org/luxons/sevenwonders/game/resources/ResourceTransactionsTest.java deleted file mode 100644 index 775973b5..00000000 --- a/game-engine/src/test/java/org/luxons/sevenwonders/game/resources/ResourceTransactionsTest.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.luxons.sevenwonders.game.resources; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.junit.Test; -import org.luxons.sevenwonders.game.test.TestUtilsKt; - -import static org.junit.Assert.assertEquals; - -public class ResourceTransactionsTest { - - @Test - public void toTransactions() { - List<ResourceTransaction> transactionList = new ArrayList<>(); - transactionList.add(TestUtilsKt.createTransaction(Provider.LEFT_PLAYER, ResourceType.WOOD)); - transactionList.add(TestUtilsKt.createTransaction(Provider.LEFT_PLAYER, ResourceType.CLAY)); - transactionList.add(TestUtilsKt.createTransaction(Provider.RIGHT_PLAYER, ResourceType.WOOD)); - - ResourceTransactions transactions = new ResourceTransactions(transactionList); - - Set<ResourceTransaction> expectedNormalized = new HashSet<>(); - expectedNormalized.add( - TestUtilsKt.createTransaction(Provider.LEFT_PLAYER, ResourceType.WOOD, ResourceType.CLAY)); - expectedNormalized.add(TestUtilsKt.createTransaction(Provider.RIGHT_PLAYER, ResourceType.WOOD)); - - assertEquals(expectedNormalized, new HashSet<>(transactions.toTransactions())); - } - - @Test(expected = IllegalStateException.class) - public void remove_failsIfNoResourceForThatProvider() { - ResourceTransactions transactions = new ResourceTransactions(); - transactions.remove(Provider.LEFT_PLAYER, Resources.of(ResourceType.WOOD)); - } -} diff --git a/game-engine/src/test/java/org/luxons/sevenwonders/game/resources/ResourcesTest.java b/game-engine/src/test/java/org/luxons/sevenwonders/game/resources/ResourcesTest.java deleted file mode 100644 index 1f260a11..00000000 --- a/game-engine/src/test/java/org/luxons/sevenwonders/game/resources/ResourcesTest.java +++ /dev/null @@ -1,485 +0,0 @@ -package org.luxons.sevenwonders.game.resources; - -import java.util.NoSuchElementException; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -public class ResourcesTest { - - @Rule - public ExpectedException thrown = ExpectedException.none(); - - @Test - public void init_shouldBeEmpty() { - Resources resources = new Resources(); - for (ResourceType resourceType : ResourceType.values()) { - assertEquals(0, resources.getQuantity(resourceType)); - } - assertEquals(0, resources.size()); - assertTrue(resources.isEmpty()); - } - - @Test - public void add_zero() { - Resources resources = new Resources(); - resources.add(ResourceType.CLAY, 0); - assertEquals(0, resources.getQuantity(ResourceType.CLAY)); - assertEquals(0, resources.size()); - assertTrue(resources.isEmpty()); - } - - @Test - public void add_simple() { - Resources resources = new Resources(); - resources.add(ResourceType.WOOD, 3); - assertEquals(3, resources.getQuantity(ResourceType.WOOD)); - assertEquals(3, resources.size()); - assertFalse(resources.isEmpty()); - } - - @Test - public void add_multipleCallsStacked() { - Resources resources = new Resources(); - resources.add(ResourceType.ORE, 3); - resources.add(ResourceType.ORE, 2); - assertEquals(5, resources.getQuantity(ResourceType.ORE)); - assertEquals(5, resources.size()); - assertFalse(resources.isEmpty()); - } - - @Test - public void add_interlaced() { - Resources resources = new Resources(); - resources.add(ResourceType.GLASS, 3); - resources.add(ResourceType.STONE, 1); - resources.add(ResourceType.WOOD, 4); - resources.add(ResourceType.GLASS, 2); - assertEquals(5, resources.getQuantity(ResourceType.GLASS)); - assertEquals(10, resources.size()); - assertFalse(resources.isEmpty()); - } - - @Test - public void remove_some() { - Resources resources = new Resources(); - resources.add(ResourceType.WOOD, 3); - resources.remove(ResourceType.WOOD, 2); - assertEquals(1, resources.getQuantity(ResourceType.WOOD)); - assertEquals(1, resources.size()); - assertFalse(resources.isEmpty()); - } - - @Test - public void remove_all() { - Resources resources = new Resources(); - resources.add(ResourceType.WOOD, 3); - resources.remove(ResourceType.WOOD, 3); - assertEquals(0, resources.getQuantity(ResourceType.WOOD)); - assertEquals(0, resources.size()); - assertTrue(resources.isEmpty()); - } - - @Test - public void remove_tooMany() { - Resources resources = new Resources(); - resources.add(ResourceType.WOOD, 2); - - thrown.expect(NoSuchElementException.class); - resources.remove(ResourceType.WOOD, 3); - } - - @Test - public void addAll_empty() { - Resources resources = new Resources(); - resources.add(ResourceType.STONE, 1); - resources.add(ResourceType.CLAY, 3); - - Resources emptyResources = new Resources(); - - resources.addAll(emptyResources); - assertEquals(1, resources.getQuantity(ResourceType.STONE)); - assertEquals(3, resources.getQuantity(ResourceType.CLAY)); - assertEquals(0, resources.getQuantity(ResourceType.ORE)); - assertEquals(0, resources.getQuantity(ResourceType.GLASS)); - assertEquals(0, resources.getQuantity(ResourceType.LOOM)); - assertEquals(4, resources.size()); - assertFalse(resources.isEmpty()); - } - - @Test - public void addAll_zeros() { - Resources resources = new Resources(); - resources.add(ResourceType.STONE, 1); - resources.add(ResourceType.CLAY, 3); - - Resources emptyResources = new Resources(); - emptyResources.add(ResourceType.STONE, 0); - emptyResources.add(ResourceType.CLAY, 0); - - resources.addAll(emptyResources); - assertEquals(1, resources.getQuantity(ResourceType.STONE)); - assertEquals(3, resources.getQuantity(ResourceType.CLAY)); - assertEquals(0, resources.getQuantity(ResourceType.ORE)); - assertEquals(0, resources.getQuantity(ResourceType.GLASS)); - assertEquals(0, resources.getQuantity(ResourceType.LOOM)); - assertEquals(4, resources.size()); - assertFalse(resources.isEmpty()); - } - - @Test - public void addAll_same() { - Resources resources = new Resources(); - resources.add(ResourceType.STONE, 1); - resources.add(ResourceType.CLAY, 3); - - Resources resources2 = new Resources(); - resources.add(ResourceType.STONE, 2); - resources.add(ResourceType.CLAY, 6); - - resources.addAll(resources2); - assertEquals(3, resources.getQuantity(ResourceType.STONE)); - assertEquals(9, resources.getQuantity(ResourceType.CLAY)); - assertEquals(0, resources.getQuantity(ResourceType.ORE)); - assertEquals(0, resources.getQuantity(ResourceType.GLASS)); - assertEquals(0, resources.getQuantity(ResourceType.LOOM)); - assertEquals(12, resources.size()); - assertFalse(resources.isEmpty()); - } - - @Test - public void addAll_overlap() { - Resources resources = new Resources(); - resources.add(ResourceType.STONE, 1); - resources.add(ResourceType.CLAY, 3); - - Resources resources2 = new Resources(); - resources.add(ResourceType.CLAY, 6); - resources.add(ResourceType.ORE, 4); - - resources.addAll(resources2); - assertEquals(1, resources.getQuantity(ResourceType.STONE)); - assertEquals(9, resources.getQuantity(ResourceType.CLAY)); - assertEquals(4, resources.getQuantity(ResourceType.ORE)); - assertEquals(0, resources.getQuantity(ResourceType.GLASS)); - assertEquals(0, resources.getQuantity(ResourceType.LOOM)); - assertEquals(14, resources.size()); - assertFalse(resources.isEmpty()); - } - - @Test - public void contains_emptyContainsEmpty() { - Resources emptyResources = new Resources(); - Resources emptyResources2 = new Resources(); - assertTrue(emptyResources.contains(emptyResources2)); - } - - @Test - public void contains_singleTypeContainsEmpty() { - Resources resources = new Resources(); - resources.add(ResourceType.STONE, 1); - - Resources emptyResources = new Resources(); - - assertTrue(resources.contains(emptyResources)); - } - - @Test - public void contains_multipleTypesContainsEmpty() { - Resources resources = new Resources(); - resources.add(ResourceType.STONE, 1); - resources.add(ResourceType.CLAY, 3); - - Resources emptyResources = new Resources(); - - assertTrue(resources.contains(emptyResources)); - } - - @Test - public void contains_self() { - Resources resources = new Resources(); - resources.add(ResourceType.STONE, 1); - resources.add(ResourceType.CLAY, 3); - - assertTrue(resources.contains(resources)); - } - - @Test - public void contains_allOfEachType() { - Resources resources = new Resources(); - resources.add(ResourceType.STONE, 1); - resources.add(ResourceType.CLAY, 3); - - Resources resources2 = new Resources(); - resources2.add(ResourceType.STONE, 1); - resources2.add(ResourceType.CLAY, 3); - - assertTrue(resources.contains(resources2)); - } - - @Test - public void contains_someOfEachType() { - Resources resources = new Resources(); - resources.add(ResourceType.STONE, 2); - resources.add(ResourceType.CLAY, 4); - - Resources resources2 = new Resources(); - resources2.add(ResourceType.STONE, 1); - resources2.add(ResourceType.CLAY, 3); - - assertTrue(resources.contains(resources2)); - } - - @Test - public void contains_someOfSomeTypes() { - Resources resources = new Resources(); - resources.add(ResourceType.STONE, 2); - resources.add(ResourceType.CLAY, 4); - - Resources resources2 = new Resources(); - resources2.add(ResourceType.CLAY, 3); - - assertTrue(resources.contains(resources2)); - } - - @Test - public void contains_allOfSomeTypes() { - Resources resources = new Resources(); - resources.add(ResourceType.STONE, 2); - resources.add(ResourceType.CLAY, 4); - - Resources resources2 = new Resources(); - resources2.add(ResourceType.CLAY, 4); - - assertTrue(resources.contains(resources2)); - } - - @Test - public void minus_empty() { - Resources resources = new Resources(); - resources.add(ResourceType.STONE, 1); - resources.add(ResourceType.CLAY, 3); - - Resources emptyResources = new Resources(); - - Resources diff = resources.minus(emptyResources); - assertEquals(1, diff.getQuantity(ResourceType.STONE)); - assertEquals(3, diff.getQuantity(ResourceType.CLAY)); - assertEquals(0, diff.getQuantity(ResourceType.ORE)); - assertEquals(0, diff.getQuantity(ResourceType.GLASS)); - assertEquals(0, diff.getQuantity(ResourceType.LOOM)); - } - - @Test - public void minus_self() { - Resources resources = new Resources(); - resources.add(ResourceType.STONE, 1); - resources.add(ResourceType.CLAY, 3); - - Resources diff = resources.minus(resources); - assertEquals(0, diff.getQuantity(ResourceType.STONE)); - assertEquals(0, diff.getQuantity(ResourceType.CLAY)); - assertEquals(0, diff.getQuantity(ResourceType.ORE)); - assertEquals(0, diff.getQuantity(ResourceType.GLASS)); - assertEquals(0, diff.getQuantity(ResourceType.LOOM)); - } - - @Test - public void minus_allOfEachType() { - Resources resources = new Resources(); - resources.add(ResourceType.STONE, 1); - resources.add(ResourceType.CLAY, 3); - - Resources resources2 = new Resources(); - resources2.add(ResourceType.STONE, 1); - resources2.add(ResourceType.CLAY, 3); - - Resources diff = resources.minus(resources2); - assertEquals(0, diff.getQuantity(ResourceType.STONE)); - assertEquals(0, diff.getQuantity(ResourceType.CLAY)); - assertEquals(0, diff.getQuantity(ResourceType.ORE)); - assertEquals(0, diff.getQuantity(ResourceType.GLASS)); - assertEquals(0, diff.getQuantity(ResourceType.LOOM)); - } - - @Test - public void minus_someOfEachType() { - Resources resources = new Resources(); - resources.add(ResourceType.STONE, 2); - resources.add(ResourceType.CLAY, 4); - - Resources resources2 = new Resources(); - resources2.add(ResourceType.STONE, 1); - resources2.add(ResourceType.CLAY, 3); - - Resources diff = resources.minus(resources2); - assertEquals(1, diff.getQuantity(ResourceType.STONE)); - assertEquals(1, diff.getQuantity(ResourceType.CLAY)); - assertEquals(0, diff.getQuantity(ResourceType.ORE)); - assertEquals(0, diff.getQuantity(ResourceType.GLASS)); - assertEquals(0, diff.getQuantity(ResourceType.LOOM)); - } - - @Test - public void minus_someOfSomeTypes() { - Resources resources = new Resources(); - resources.add(ResourceType.STONE, 2); - resources.add(ResourceType.CLAY, 4); - - Resources resources2 = new Resources(); - resources2.add(ResourceType.CLAY, 3); - - Resources diff = resources.minus(resources2); - assertEquals(2, diff.getQuantity(ResourceType.STONE)); - assertEquals(1, diff.getQuantity(ResourceType.CLAY)); - assertEquals(0, diff.getQuantity(ResourceType.ORE)); - assertEquals(0, diff.getQuantity(ResourceType.GLASS)); - assertEquals(0, diff.getQuantity(ResourceType.LOOM)); - } - - @Test - public void minus_allOfSomeTypes() { - Resources resources = new Resources(); - resources.add(ResourceType.STONE, 2); - resources.add(ResourceType.CLAY, 4); - - Resources resources2 = new Resources(); - resources2.add(ResourceType.CLAY, 4); - - Resources diff = resources.minus(resources2); - assertEquals(2, diff.getQuantity(ResourceType.STONE)); - assertEquals(0, diff.getQuantity(ResourceType.CLAY)); - assertEquals(0, diff.getQuantity(ResourceType.ORE)); - assertEquals(0, diff.getQuantity(ResourceType.GLASS)); - assertEquals(0, diff.getQuantity(ResourceType.LOOM)); - } - - @Test - public void minus_tooMuchOfExistingType() { - Resources resources = new Resources(); - resources.add(ResourceType.CLAY, 4); - - Resources resources2 = new Resources(); - resources2.add(ResourceType.CLAY, 5); - - Resources diff = resources.minus(resources2); - assertEquals(0, diff.getQuantity(ResourceType.CLAY)); - } - - @Test - public void minus_someOfAnAbsentType() { - Resources resources = new Resources(); - - Resources resources2 = new Resources(); - resources2.add(ResourceType.LOOM, 5); - - Resources diff = resources.minus(resources2); - assertEquals(0, diff.getQuantity(ResourceType.LOOM)); - } - - @Test - public void minus_someOfATypeWithZero() { - Resources resources = new Resources(); - resources.add(ResourceType.LOOM, 0); - - Resources resources2 = new Resources(); - resources2.add(ResourceType.LOOM, 5); - - Resources diff = resources.minus(resources2); - assertEquals(0, diff.getQuantity(ResourceType.LOOM)); - } - - @Test - public void isEmpty_noElement() { - Resources resources = new Resources(); - assertTrue(resources.isEmpty()); - } - - @Test - public void isEmpty_singleZeroElement() { - Resources resources = new Resources(); - resources.add(ResourceType.LOOM, 0); - assertTrue(resources.isEmpty()); - } - - @Test - public void isEmpty_multipleZeroElements() { - Resources resources = new Resources(); - resources.add(ResourceType.WOOD, 0); - resources.add(ResourceType.ORE, 0); - resources.add(ResourceType.LOOM, 0); - assertTrue(resources.isEmpty()); - } - - @Test - public void isEmpty_singleElementMoreThanZero() { - Resources resources = new Resources(); - resources.add(ResourceType.LOOM, 3); - assertFalse(resources.isEmpty()); - } - - @Test - public void isEmpty_mixedZeroAndNonZeroElements() { - Resources resources = new Resources(); - resources.add(ResourceType.WOOD, 0); - resources.add(ResourceType.LOOM, 3); - assertFalse(resources.isEmpty()); - } - - @Test - public void isEmpty_mixedZeroAndNonZeroElements_reverseOrder() { - Resources resources = new Resources(); - resources.add(ResourceType.ORE, 3); - resources.add(ResourceType.PAPYRUS, 0); - assertFalse(resources.isEmpty()); - } - - @Test - public void equals_falseWhenNull() { - Resources resources = new Resources(); - resources.add(ResourceType.GLASS, 1); - //noinspection ObjectEqualsNull - assertFalse(resources.equals(null)); - } - - @Test - public void equals_falseWhenDifferentClass() { - Resources resources = new Resources(); - resources.add(ResourceType.GLASS, 1); - Production production = new Production(); - production.addFixedResource(ResourceType.GLASS, 1); - //noinspection EqualsBetweenInconvertibleTypes - assertFalse(resources.equals(production)); - } - - @Test - public void equals_trueWhenSame() { - Resources resources = new Resources(); - assertEquals(resources, resources); - } - - @Test - public void equals_trueWhenSameContent() { - Resources resources1 = new Resources(); - Resources resources2 = new Resources(); - assertTrue(resources1.equals(resources2)); - resources1.add(ResourceType.GLASS, 1); - resources2.add(ResourceType.GLASS, 1); - assertTrue(resources1.equals(resources2)); - } - - @Test - public void hashCode_sameWhenSameContent() { - Resources resources1 = new Resources(); - Resources resources2 = new Resources(); - assertEquals(resources1.hashCode(), resources2.hashCode()); - resources1.add(ResourceType.GLASS, 1); - resources2.add(ResourceType.GLASS, 1); - assertEquals(resources1.hashCode(), resources2.hashCode()); - } -} diff --git a/game-engine/src/test/java/org/luxons/sevenwonders/game/resources/TradingRulesTest.java b/game-engine/src/test/java/org/luxons/sevenwonders/game/resources/TradingRulesTest.java deleted file mode 100644 index 3c447753..00000000 --- a/game-engine/src/test/java/org/luxons/sevenwonders/game/resources/TradingRulesTest.java +++ /dev/null @@ -1,111 +0,0 @@ -package org.luxons.sevenwonders.game.resources; - -import java.util.ArrayList; -import java.util.List; - -import org.junit.experimental.theories.DataPoints; -import org.junit.experimental.theories.Theories; -import org.junit.experimental.theories.Theory; -import org.junit.runner.RunWith; -import org.luxons.sevenwonders.game.test.TestUtilsKt; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assume.assumeTrue; - -@RunWith(Theories.class) -public class TradingRulesTest { - - @DataPoints - public static int[] costs() { - return new int[]{0, 1, 2}; - } - - @DataPoints - public static Provider[] providers() { - return Provider.values(); - } - - @DataPoints - public static ResourceType[] resourceTypes() { - return ResourceType.values(); - } - - @Theory - public void setCost_overridesCost(int defaultCost, int overriddenCost, Provider overriddenProvider, - Provider provider, ResourceType type) { - assumeTrue(defaultCost != overriddenCost); - assumeTrue(overriddenProvider != provider); - - TradingRules rules = new TradingRules(defaultCost); - rules.setCost(type, overriddenProvider, overriddenCost); - - assertEquals(overriddenCost, rules.getCost(type, overriddenProvider)); - assertEquals(defaultCost, rules.getCost(type, provider)); - } - - @Theory - public void computeCost_zeroForNoResources(int defaultCost) { - TradingRules rules = new TradingRules(defaultCost); - assertEquals(0, rules.computeCost(new ResourceTransactions())); - } - - @Theory - public void computeCost_defaultCostWhenNoOverride(int defaultCost, Provider provider, ResourceType type) { - TradingRules rules = new TradingRules(defaultCost); - ResourceTransactions transactions = TestUtilsKt.createTransactions(provider, type); - assertEquals(defaultCost, rules.computeCost(transactions)); - } - - @Theory - public void computeCost_twiceDefaultFor2Resources(int defaultCost, Provider provider, ResourceType type) { - TradingRules rules = new TradingRules(defaultCost); - ResourceTransactions transactions = TestUtilsKt.createTransactions(provider, type, type); - assertEquals(2 * defaultCost, rules.computeCost(transactions)); - } - - @Theory - public void computeCost_overriddenCost(int defaultCost, int overriddenCost, Provider provider, ResourceType type) { - TradingRules rules = new TradingRules(defaultCost); - rules.setCost(type, provider, overriddenCost); - ResourceTransactions transactions = TestUtilsKt.createTransactions(provider, type); - assertEquals(overriddenCost, rules.computeCost(transactions)); - } - - @Theory - public void computeCost_defaultCostWhenOverrideOnOtherProviderOrType(int defaultCost, int overriddenCost, - Provider overriddenProvider, - ResourceType overriddenType, Provider provider, - ResourceType type) { - assumeTrue(overriddenProvider != provider || overriddenType != type); - TradingRules rules = new TradingRules(defaultCost); - rules.setCost(overriddenType, overriddenProvider, overriddenCost); - ResourceTransactions transactions = TestUtilsKt.createTransactions(provider, type); - assertEquals(defaultCost, rules.computeCost(transactions)); - } - - @Theory - public void computeCost_oneDefaultAndOneOverriddenType(int defaultCost, int overriddenCost, - ResourceType overriddenType, Provider provider, - ResourceType type) { - assumeTrue(overriddenType != type); - TradingRules rules = new TradingRules(defaultCost); - rules.setCost(overriddenType, provider, overriddenCost); - ResourceTransactions transactions = TestUtilsKt.createTransactions(provider, overriddenType, type); - assertEquals(defaultCost + overriddenCost, rules.computeCost(transactions)); - } - - @Theory - public void computeCost_oneDefaultAndOneOverriddenProvider(int defaultCost, int overriddenCost, - Provider overriddenProvider, Provider provider, - ResourceType type) { - assumeTrue(overriddenProvider != provider); - TradingRules rules = new TradingRules(defaultCost); - rules.setCost(type, overriddenProvider, overriddenCost); - - List<ResourceTransaction> boughtResources = new ArrayList<>(2); - boughtResources.add(TestUtilsKt.createTransaction(provider, type)); - boughtResources.add(TestUtilsKt.createTransaction(overriddenProvider, type)); - - assertEquals(defaultCost + overriddenCost, rules.computeCost(new ResourceTransactions(boughtResources))); - } -} 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 new file mode 100644 index 00000000..ee461e38 --- /dev/null +++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/moves/BuildWonderMoveTest.kt @@ -0,0 +1,76 @@ +package org.luxons.sevenwonders.game.moves + +import org.junit.Assert.assertEquals +import org.junit.Assert.fail +import org.junit.Test +import org.luxons.sevenwonders.game.Settings +import org.luxons.sevenwonders.game.api.Table +import org.luxons.sevenwonders.game.cards.Card +import org.luxons.sevenwonders.game.test.createMove +import org.luxons.sevenwonders.game.test.sampleCards +import org.luxons.sevenwonders.game.test.testCard +import org.luxons.sevenwonders.game.test.testSettings +import org.luxons.sevenwonders.game.test.testTable + +class BuildWonderMoveTest { + + @Test(expected = InvalidMoveException::class) + fun validate_failsWhenCardNotInHand() { + val table = testTable(3) + val hand = sampleCards(0, 7) + val anotherCard = testCard("Card that is not in the hand") + val move = createMove(0, anotherCard, MoveType.UPGRADE_WONDER) + + move.validate(table, hand) + } + + @Test(expected = InvalidMoveException::class) + fun validate_failsWhenWonderIsCompletelyBuilt() { + val settings = testSettings(3) + val table = testTable(settings) + val hand = sampleCards(0, 7) + + fillPlayerWonderLevels(settings, table, hand) + + // should fail because the wonder is already full + buildOneWonderLevel(settings, table, hand, 4) + } + + private fun fillPlayerWonderLevels(settings: Settings, table: Table, hand: List<Card>) { + try { + val nbLevels = table.getBoard(0).wonder.stages.size + for (i in 0 until nbLevels) { + buildOneWonderLevel(settings, table, hand, i) + } + } catch (e: InvalidMoveException) { + fail("Building wonder levels should not fail before being full") + } + } + + private fun buildOneWonderLevel(settings: Settings, table: Table, hand: List<Card>, cardIndex: Int) { + val card = hand[cardIndex] + val move = createMove(0, card, MoveType.UPGRADE_WONDER) + move.validate(table, hand) + move.place(table, mutableListOf(), settings) + move.activate(table, emptyList(), settings) + } + + @Test + fun place_increasesWonderLevel() { + val settings = testSettings(3) + val table = testTable(settings) + val hand = sampleCards(0, 7) + val cardToUse = hand[0] + val move = createMove(0, cardToUse, MoveType.UPGRADE_WONDER) + move.validate(table, hand) // should not fail + + val initialStage = table.getBoard(0).wonder.nbBuiltStages + + move.place(table, mutableListOf(), settings) + + val newStage = table.getBoard(0).wonder.nbBuiltStages + + // we need to see the level increase before activation so that other players + assertEquals((initialStage + 1).toLong(), newStage.toLong()) + } +} 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 new file mode 100644 index 00000000..f4cf5294 --- /dev/null +++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/resources/BestPriceCalculatorTest.kt @@ -0,0 +1,129 @@ +package org.luxons.sevenwonders.game.resources + +import java.util.Arrays + +import org.junit.Test +import org.luxons.sevenwonders.game.api.Table +import org.luxons.sevenwonders.game.boards.Board +import org.luxons.sevenwonders.game.test.* + +import org.junit.Assert.assertEquals +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 +import org.luxons.sevenwonders.game.resources.ResourceType.GLASS +import org.luxons.sevenwonders.game.resources.ResourceType.ORE +import org.luxons.sevenwonders.game.resources.ResourceType.STONE +import org.luxons.sevenwonders.game.resources.ResourceType.WOOD + +class BestPriceCalculatorTest { + + @Test + fun bestPrice_0forEmptyResources() { + val table = testTable(3) + val resources = Resources() + assertEquals(0, BestPriceCalculator.bestPrice(resources, table, 0).toLong()) + assertEquals(ResourceTransactions(), BestPriceCalculator.bestSolution(resources, table, 0)) + } + + @Test + fun bestPrice_fixedResources_defaultCost() { + val left = testBoard(STONE) + val main = testBoard(STONE) + val right = testBoard(WOOD) + val table = Table(Arrays.asList(main, right, left)) + + val resources = createResources(STONE, STONE) + assertEquals(2, BestPriceCalculator.bestPrice(resources, table, 0).toLong()) + assertEquals(4, BestPriceCalculator.bestPrice(resources, table, 1).toLong()) + assertEquals(2, BestPriceCalculator.bestPrice(resources, table, 2).toLong()) + + val stoneLeftSingle = createTransaction(LEFT_PLAYER, STONE) + val stoneRightSingle = createTransaction(RIGHT_PLAYER, STONE) + + val stoneLeft = createTransactions(stoneLeftSingle) + val stoneRight = createTransactions(stoneRightSingle) + val stoneLeftAndRight = createTransactions(stoneLeftSingle, stoneRightSingle) + + assertEquals(stoneLeft, BestPriceCalculator.bestSolution(resources, table, 0)) + assertEquals(stoneLeftAndRight, BestPriceCalculator.bestSolution(resources, table, 1)) + assertEquals(stoneRight, BestPriceCalculator.bestSolution(resources, table, 2)) + } + + @Test + fun bestPrice_fixedResources_overridenCost() { + val main = testBoard(STONE) + main.tradingRules.setCost(WOOD, RIGHT_PLAYER, 1) + + val left = testBoard(WOOD) + val right = testBoard(WOOD) + val opposite = testBoard(GLASS) + val table = Table(Arrays.asList(main, right, opposite, left)) + + val resources = createResources(WOOD) + assertEquals(1, BestPriceCalculator.bestPrice(resources, table, 0).toLong()) + assertEquals(0, BestPriceCalculator.bestPrice(resources, table, 1).toLong()) + assertEquals(2, BestPriceCalculator.bestPrice(resources, table, 2).toLong()) + assertEquals(0, BestPriceCalculator.bestPrice(resources, table, 3).toLong()) + + val woodLeft = createTransactions(LEFT_PLAYER, WOOD) + val woodRight = createTransactions(RIGHT_PLAYER, WOOD) + assertEquals(woodRight, BestPriceCalculator.bestSolution(resources, table, 0)) + assertEquals(ResourceTransactions(), BestPriceCalculator.bestSolution(resources, table, 1)) + assertEquals(woodLeft, BestPriceCalculator.bestSolution(resources, table, 2)) + assertEquals(ResourceTransactions(), BestPriceCalculator.bestSolution(resources, table, 3)) + } + + @Test + fun bestPrice_mixedResources_overridenCost() { + val left = testBoard(WOOD) + + val main = testBoard(STONE) + main.tradingRules.setCost(WOOD, RIGHT_PLAYER, 1) + + val right = testBoard(ORE) + right.production.addChoice(WOOD, CLAY) + right.publicProduction.addChoice(WOOD, CLAY) + + val table = Table(Arrays.asList(main, right, left)) + + val resources = createResources(WOOD) + assertEquals(1, BestPriceCalculator.bestPrice(resources, table, 0).toLong()) + assertEquals(0, BestPriceCalculator.bestPrice(resources, table, 1).toLong()) + assertEquals(0, BestPriceCalculator.bestPrice(resources, table, 2).toLong()) + + val woodRight = createTransactions(RIGHT_PLAYER, WOOD) + + assertEquals(woodRight, BestPriceCalculator.bestSolution(resources, table, 0)) + assertEquals(ResourceTransactions(), BestPriceCalculator.bestSolution(resources, table, 1)) + assertEquals(ResourceTransactions(), BestPriceCalculator.bestSolution(resources, table, 2)) + } + + @Test + fun bestPrice_chooseCheapest() { + val left = testBoard(WOOD) + + val main = testBoard(WOOD) + main.production.addChoice(CLAY, ORE) + main.tradingRules.setCost(CLAY, RIGHT_PLAYER, 1) + + val right = testBoard(WOOD) + right.production.addFixedResource(ORE, 1) + right.production.addFixedResource(CLAY, 1) + right.publicProduction.addFixedResource(ORE, 1) + right.publicProduction.addFixedResource(CLAY, 1) + + val table = Table(Arrays.asList(main, right, left)) + + val resources = createResources(ORE, CLAY) + assertEquals(1, BestPriceCalculator.bestPrice(resources, table, 0).toLong()) + assertEquals(0, BestPriceCalculator.bestPrice(resources, table, 1).toLong()) + assertEquals(4, BestPriceCalculator.bestPrice(resources, table, 2).toLong()) + + val oreAndClayLeft = createTransactions(LEFT_PLAYER, ORE, CLAY) + val clayRight = createTransactions(RIGHT_PLAYER, CLAY) + assertEquals(clayRight, BestPriceCalculator.bestSolution(resources, table, 0)) + assertEquals(ResourceTransactions(), BestPriceCalculator.bestSolution(resources, table, 1)) + assertEquals(oreAndClayLeft, BestPriceCalculator.bestSolution(resources, table, 2)) + } +} diff --git a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/resources/ProductionTest.kt b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/resources/ProductionTest.kt new file mode 100644 index 00000000..27f85c1a --- /dev/null +++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/resources/ProductionTest.kt @@ -0,0 +1,323 @@ +package org.luxons.sevenwonders.game.resources + +import java.util.EnumSet +import java.util.HashSet + +import org.junit.Before +import org.junit.Test + +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue + +class ProductionTest { + + private var emptyResources: Resources? = null + + private var resources1Wood: Resources? = null + + private var resources1Stone: Resources? = null + + private var resources1Stone1Wood: Resources? = null + + private var resources2Stones: Resources? = null + + private var resources2Stones3Clay: Resources? = null + + @Before + fun init() { + emptyResources = Resources() + + resources1Wood = Resources() + resources1Wood!!.add(ResourceType.WOOD, 1) + + resources1Stone = Resources() + resources1Stone!!.add(ResourceType.STONE, 1) + + resources1Stone1Wood = Resources() + resources1Stone1Wood!!.add(ResourceType.STONE, 1) + resources1Stone1Wood!!.add(ResourceType.WOOD, 1) + + resources2Stones = Resources() + resources2Stones!!.add(ResourceType.STONE, 2) + + resources2Stones3Clay = Resources() + resources2Stones3Clay!!.add(ResourceType.STONE, 2) + resources2Stones3Clay!!.add(ResourceType.CLAY, 3) + } + + @Test + fun contains_newProductionContainsEmpty() { + val production = Production() + assertTrue(production.contains(emptyResources)) + } + + @Test + fun contains_singleFixedResource_noneAtAll() { + val production = Production() + assertFalse(production.contains(resources2Stones)) + } + + @Test + fun contains_singleFixedResource_notEnough() { + val production = Production() + production.addFixedResource(ResourceType.STONE, 1) + assertFalse(production.contains(resources2Stones)) + } + + @Test + fun contains_singleFixedResource_justEnough() { + val production = Production() + production.addFixedResource(ResourceType.STONE, 2) + assertTrue(production.contains(resources2Stones)) + } + + @Test + fun contains_singleFixedResource_moreThanEnough() { + val production = Production() + production.addFixedResource(ResourceType.STONE, 3) + assertTrue(production.contains(resources2Stones)) + } + + @Test + fun contains_singleFixedResource_moreThanEnough_amongOthers() { + val production = Production() + production.addFixedResource(ResourceType.STONE, 3) + production.addFixedResource(ResourceType.CLAY, 2) + assertTrue(production.contains(resources2Stones)) + } + + @Test + fun contains_multipleFixedResources_notEnoughOfOne() { + val production = Production() + production.addFixedResource(ResourceType.STONE, 3) + production.addFixedResource(ResourceType.CLAY, 1) + assertFalse(production.contains(resources2Stones3Clay)) + } + + @Test + fun contains_multipleFixedResources_notEnoughOfBoth() { + val production = Production() + production.addFixedResource(ResourceType.STONE, 1) + production.addFixedResource(ResourceType.CLAY, 1) + assertFalse(production.contains(resources2Stones3Clay)) + } + + @Test + fun contains_multipleFixedResources_moreThanEnough() { + val production = Production() + production.addFixedResource(ResourceType.STONE, 3) + production.addFixedResource(ResourceType.CLAY, 5) + assertTrue(production.contains(resources2Stones3Clay)) + } + + @Test + fun contains_singleChoice_containsEmpty() { + val production = Production() + production.addChoice(ResourceType.STONE, ResourceType.CLAY) + assertTrue(production.contains(emptyResources)) + } + + @Test + fun contains_singleChoice_enough() { + val production = Production() + production.addChoice(ResourceType.STONE, ResourceType.WOOD) + assertTrue(production.contains(resources1Wood)) + assertTrue(production.contains(resources1Stone)) + } + + @Test + fun contains_multipleChoices_notBoth() { + val production = Production() + production.addChoice(ResourceType.STONE, ResourceType.CLAY) + production.addChoice(ResourceType.STONE, ResourceType.CLAY) + production.addChoice(ResourceType.STONE, ResourceType.CLAY) + assertFalse(production.contains(resources2Stones3Clay)) + } + + @Test + fun contains_multipleChoices_enough() { + val production = Production() + production.addChoice(ResourceType.STONE, ResourceType.ORE) + production.addChoice(ResourceType.STONE, ResourceType.WOOD) + assertTrue(production.contains(resources1Stone1Wood)) + } + + @Test + fun contains_multipleChoices_enoughReverseOrder() { + val production = Production() + production.addChoice(ResourceType.STONE, ResourceType.WOOD) + production.addChoice(ResourceType.STONE, ResourceType.ORE) + assertTrue(production.contains(resources1Stone1Wood)) + } + + @Test + fun contains_multipleChoices_moreThanEnough() { + val production = Production() + production.addChoice(ResourceType.LOOM, ResourceType.GLASS, ResourceType.PAPYRUS) + production.addChoice(ResourceType.STONE, ResourceType.ORE) + production.addChoice(ResourceType.STONE, ResourceType.WOOD) + assertTrue(production.contains(resources1Stone1Wood)) + } + + @Test + fun contains_mixedFixedAndChoice_enough() { + val production = Production() + production.addFixedResource(ResourceType.WOOD, 1) + production.addChoice(ResourceType.STONE, ResourceType.WOOD) + assertTrue(production.contains(resources1Stone1Wood)) + } + + @Test + fun addAll_empty() { + val production = Production() + production.addAll(emptyResources) + assertTrue(production.contains(emptyResources)) + } + + @Test + fun addAll_singleResource() { + val production = Production() + production.addAll(resources1Stone) + assertTrue(production.contains(resources1Stone)) + } + + @Test + fun addAll_multipleResources() { + val production = Production() + production.addAll(resources2Stones3Clay) + assertTrue(production.contains(resources2Stones3Clay)) + } + + @Test + fun addAll_production_multipleFixedResources() { + val production = Production() + production.addAll(resources2Stones3Clay) + + val production2 = Production() + production2.addAll(production) + + assertTrue(production2.contains(resources2Stones3Clay)) + } + + @Test + fun addAll_production_multipleChoices() { + val production = Production() + production.addChoice(ResourceType.STONE, ResourceType.WOOD) + production.addChoice(ResourceType.STONE, ResourceType.ORE) + + val production2 = Production() + production2.addAll(production) + assertTrue(production.contains(resources1Stone1Wood)) + } + + @Test + fun addAll_production_mixedFixedResourcesAndChoices() { + val production = Production() + production.addFixedResource(ResourceType.WOOD, 1) + production.addChoice(ResourceType.STONE, ResourceType.WOOD) + + val production2 = Production() + production2.addAll(production) + + assertTrue(production.contains(resources1Stone1Wood)) + } + + @Test + fun asChoices_empty() { + val production = Production() + assertTrue(production.asChoices().isEmpty()) + } + + @Test + fun asChoices_onlyChoices() { + val production = Production() + production.addChoice(ResourceType.STONE, ResourceType.WOOD) + production.addChoice(ResourceType.STONE, ResourceType.ORE) + production.addChoice(ResourceType.CLAY, ResourceType.LOOM, ResourceType.GLASS) + assertEquals(production.alternativeResources, production.asChoices()) + } + + @Test + fun asChoices_onlyFixed() { + val production = Production() + production.addFixedResource(ResourceType.WOOD, 1) + production.addFixedResource(ResourceType.CLAY, 2) + + val expected = HashSet<Set<ResourceType>>() + expected.add(EnumSet.of(ResourceType.WOOD)) + expected.add(EnumSet.of(ResourceType.CLAY)) + expected.add(EnumSet.of(ResourceType.CLAY)) + + assertEquals(expected, production.asChoices()) + } + + @Test + fun asChoices_mixed() { + val production = Production() + production.addChoice(ResourceType.STONE, ResourceType.ORE) + production.addChoice(ResourceType.CLAY, ResourceType.LOOM, ResourceType.GLASS) + production.addFixedResource(ResourceType.WOOD, 1) + production.addFixedResource(ResourceType.CLAY, 2) + + val expected = HashSet<Set<ResourceType>>() + expected.add(EnumSet.of(ResourceType.STONE, ResourceType.ORE)) + expected.add(EnumSet.of(ResourceType.CLAY, ResourceType.LOOM, ResourceType.GLASS)) + expected.add(EnumSet.of(ResourceType.WOOD)) + expected.add(EnumSet.of(ResourceType.CLAY)) + expected.add(EnumSet.of(ResourceType.CLAY)) + + assertEquals(expected, production.asChoices()) + } + + @Test + fun equals_falseWhenNull() { + val production = Production() + production.addFixedResource(ResourceType.GLASS, 1) + production.addChoice(ResourceType.ORE, ResourceType.WOOD) + + assertFalse(production == null) + } + + @Test + fun equals_falseWhenDifferentClass() { + val production = Production() + production.addFixedResource(ResourceType.GLASS, 1) + val resources = Resources() + resources.add(ResourceType.GLASS, 1) + + assertFalse(production == resources) + } + + @Test + fun equals_trueWhenSame() { + val production = Production() + assertEquals(production, production) + } + + @Test + fun equals_trueWhenSameContent() { + val production1 = Production() + val production2 = Production() + assertTrue(production1 == production2) + production1.addFixedResource(ResourceType.GLASS, 1) + production2.addFixedResource(ResourceType.GLASS, 1) + assertTrue(production1 == production2) + production1.addChoice(ResourceType.ORE, ResourceType.WOOD) + production2.addChoice(ResourceType.ORE, ResourceType.WOOD) + assertTrue(production1 == production2) + } + + @Test + fun hashCode_sameWhenSameContent() { + val production1 = Production() + val production2 = Production() + assertEquals(production1.hashCode().toLong(), production2.hashCode().toLong()) + production1.addFixedResource(ResourceType.GLASS, 1) + production2.addFixedResource(ResourceType.GLASS, 1) + assertEquals(production1.hashCode().toLong(), production2.hashCode().toLong()) + production1.addChoice(ResourceType.ORE, ResourceType.WOOD) + production2.addChoice(ResourceType.ORE, ResourceType.WOOD) + assertEquals(production1.hashCode().toLong(), production2.hashCode().toLong()) + } +} diff --git a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/resources/ResourceTransactionsTest.kt b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/resources/ResourceTransactionsTest.kt new file mode 100644 index 00000000..11a03cd4 --- /dev/null +++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/resources/ResourceTransactionsTest.kt @@ -0,0 +1,36 @@ +package org.luxons.sevenwonders.game.resources + +import java.util.ArrayList +import java.util.HashSet + +import org.junit.Test +import org.luxons.sevenwonders.game.test.* + +import org.junit.Assert.assertEquals + +class ResourceTransactionsTest { + + @Test + fun toTransactions() { + val transactionList = ArrayList<ResourceTransaction>() + transactionList.add(createTransaction(Provider.LEFT_PLAYER, ResourceType.WOOD)) + transactionList.add(createTransaction(Provider.LEFT_PLAYER, ResourceType.CLAY)) + transactionList.add(createTransaction(Provider.RIGHT_PLAYER, ResourceType.WOOD)) + + val transactions = ResourceTransactions(transactionList) + + val expectedNormalized = HashSet<ResourceTransaction>() + expectedNormalized.add( + createTransaction(Provider.LEFT_PLAYER, ResourceType.WOOD, ResourceType.CLAY) + ) + expectedNormalized.add(createTransaction(Provider.RIGHT_PLAYER, ResourceType.WOOD)) + + assertEquals(expectedNormalized, HashSet(transactions.toTransactions())) + } + + @Test(expected = IllegalStateException::class) + fun remove_failsIfNoResourceForThatProvider() { + val transactions = ResourceTransactions() + transactions.remove(Provider.LEFT_PLAYER, Resources.of(ResourceType.WOOD)) + } +} diff --git a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/resources/ResourcesTest.kt b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/resources/ResourcesTest.kt new file mode 100644 index 00000000..72419fe3 --- /dev/null +++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/resources/ResourcesTest.kt @@ -0,0 +1,482 @@ +package org.luxons.sevenwonders.game.resources + +import org.junit.Assert.* +import org.junit.Rule +import org.junit.Test +import org.junit.rules.ExpectedException +import java.util.NoSuchElementException + +class ResourcesTest { + + @JvmField + @Rule + var thrown = ExpectedException.none() + + @Test + fun init_shouldBeEmpty() { + val resources = Resources() + for (resourceType in ResourceType.values()) { + assertEquals(0, resources.getQuantity(resourceType).toLong()) + } + assertEquals(0, resources.size().toLong()) + assertTrue(resources.isEmpty) + } + + @Test + fun add_zero() { + val resources = Resources() + resources.add(ResourceType.CLAY, 0) + assertEquals(0, resources.getQuantity(ResourceType.CLAY).toLong()) + assertEquals(0, resources.size().toLong()) + assertTrue(resources.isEmpty) + } + + @Test + fun add_simple() { + val resources = Resources() + resources.add(ResourceType.WOOD, 3) + assertEquals(3, resources.getQuantity(ResourceType.WOOD).toLong()) + assertEquals(3, resources.size().toLong()) + assertFalse(resources.isEmpty) + } + + @Test + fun add_multipleCallsStacked() { + val resources = Resources() + resources.add(ResourceType.ORE, 3) + resources.add(ResourceType.ORE, 2) + assertEquals(5, resources.getQuantity(ResourceType.ORE).toLong()) + assertEquals(5, resources.size().toLong()) + assertFalse(resources.isEmpty) + } + + @Test + fun add_interlaced() { + val resources = Resources() + resources.add(ResourceType.GLASS, 3) + resources.add(ResourceType.STONE, 1) + resources.add(ResourceType.WOOD, 4) + resources.add(ResourceType.GLASS, 2) + assertEquals(5, resources.getQuantity(ResourceType.GLASS).toLong()) + assertEquals(10, resources.size().toLong()) + assertFalse(resources.isEmpty) + } + + @Test + fun remove_some() { + val resources = Resources() + resources.add(ResourceType.WOOD, 3) + resources.remove(ResourceType.WOOD, 2) + assertEquals(1, resources.getQuantity(ResourceType.WOOD).toLong()) + assertEquals(1, resources.size().toLong()) + assertFalse(resources.isEmpty) + } + + @Test + fun remove_all() { + val resources = Resources() + resources.add(ResourceType.WOOD, 3) + resources.remove(ResourceType.WOOD, 3) + assertEquals(0, resources.getQuantity(ResourceType.WOOD).toLong()) + assertEquals(0, resources.size().toLong()) + assertTrue(resources.isEmpty) + } + + @Test + fun remove_tooMany() { + val resources = Resources() + resources.add(ResourceType.WOOD, 2) + + thrown.expect(NoSuchElementException::class.java) + resources.remove(ResourceType.WOOD, 3) + } + + @Test + fun addAll_empty() { + val resources = Resources() + resources.add(ResourceType.STONE, 1) + resources.add(ResourceType.CLAY, 3) + + val emptyResources = Resources() + + resources.addAll(emptyResources) + assertEquals(1, resources.getQuantity(ResourceType.STONE).toLong()) + assertEquals(3, resources.getQuantity(ResourceType.CLAY).toLong()) + assertEquals(0, resources.getQuantity(ResourceType.ORE).toLong()) + assertEquals(0, resources.getQuantity(ResourceType.GLASS).toLong()) + assertEquals(0, resources.getQuantity(ResourceType.LOOM).toLong()) + assertEquals(4, resources.size().toLong()) + assertFalse(resources.isEmpty) + } + + @Test + fun addAll_zeros() { + val resources = Resources() + resources.add(ResourceType.STONE, 1) + resources.add(ResourceType.CLAY, 3) + + val emptyResources = Resources() + emptyResources.add(ResourceType.STONE, 0) + emptyResources.add(ResourceType.CLAY, 0) + + resources.addAll(emptyResources) + assertEquals(1, resources.getQuantity(ResourceType.STONE).toLong()) + assertEquals(3, resources.getQuantity(ResourceType.CLAY).toLong()) + assertEquals(0, resources.getQuantity(ResourceType.ORE).toLong()) + assertEquals(0, resources.getQuantity(ResourceType.GLASS).toLong()) + assertEquals(0, resources.getQuantity(ResourceType.LOOM).toLong()) + assertEquals(4, resources.size().toLong()) + assertFalse(resources.isEmpty) + } + + @Test + fun addAll_same() { + val resources = Resources() + resources.add(ResourceType.STONE, 1) + resources.add(ResourceType.CLAY, 3) + + val resources2 = Resources() + resources.add(ResourceType.STONE, 2) + resources.add(ResourceType.CLAY, 6) + + resources.addAll(resources2) + assertEquals(3, resources.getQuantity(ResourceType.STONE).toLong()) + assertEquals(9, resources.getQuantity(ResourceType.CLAY).toLong()) + assertEquals(0, resources.getQuantity(ResourceType.ORE).toLong()) + assertEquals(0, resources.getQuantity(ResourceType.GLASS).toLong()) + assertEquals(0, resources.getQuantity(ResourceType.LOOM).toLong()) + assertEquals(12, resources.size().toLong()) + assertFalse(resources.isEmpty) + } + + @Test + fun addAll_overlap() { + val resources = Resources() + resources.add(ResourceType.STONE, 1) + resources.add(ResourceType.CLAY, 3) + + val resources2 = Resources() + resources.add(ResourceType.CLAY, 6) + resources.add(ResourceType.ORE, 4) + + resources.addAll(resources2) + assertEquals(1, resources.getQuantity(ResourceType.STONE).toLong()) + assertEquals(9, resources.getQuantity(ResourceType.CLAY).toLong()) + assertEquals(4, resources.getQuantity(ResourceType.ORE).toLong()) + assertEquals(0, resources.getQuantity(ResourceType.GLASS).toLong()) + assertEquals(0, resources.getQuantity(ResourceType.LOOM).toLong()) + assertEquals(14, resources.size().toLong()) + assertFalse(resources.isEmpty) + } + + @Test + fun contains_emptyContainsEmpty() { + val emptyResources = Resources() + val emptyResources2 = Resources() + assertTrue(emptyResources.contains(emptyResources2)) + } + + @Test + fun contains_singleTypeContainsEmpty() { + val resources = Resources() + resources.add(ResourceType.STONE, 1) + + val emptyResources = Resources() + + assertTrue(resources.contains(emptyResources)) + } + + @Test + fun contains_multipleTypesContainsEmpty() { + val resources = Resources() + resources.add(ResourceType.STONE, 1) + resources.add(ResourceType.CLAY, 3) + + val emptyResources = Resources() + + assertTrue(resources.contains(emptyResources)) + } + + @Test + fun contains_self() { + val resources = Resources() + resources.add(ResourceType.STONE, 1) + resources.add(ResourceType.CLAY, 3) + + assertTrue(resources.contains(resources)) + } + + @Test + fun contains_allOfEachType() { + val resources = Resources() + resources.add(ResourceType.STONE, 1) + resources.add(ResourceType.CLAY, 3) + + val resources2 = Resources() + resources2.add(ResourceType.STONE, 1) + resources2.add(ResourceType.CLAY, 3) + + assertTrue(resources.contains(resources2)) + } + + @Test + fun contains_someOfEachType() { + val resources = Resources() + resources.add(ResourceType.STONE, 2) + resources.add(ResourceType.CLAY, 4) + + val resources2 = Resources() + resources2.add(ResourceType.STONE, 1) + resources2.add(ResourceType.CLAY, 3) + + assertTrue(resources.contains(resources2)) + } + + @Test + fun contains_someOfSomeTypes() { + val resources = Resources() + resources.add(ResourceType.STONE, 2) + resources.add(ResourceType.CLAY, 4) + + val resources2 = Resources() + resources2.add(ResourceType.CLAY, 3) + + assertTrue(resources.contains(resources2)) + } + + @Test + fun contains_allOfSomeTypes() { + val resources = Resources() + resources.add(ResourceType.STONE, 2) + resources.add(ResourceType.CLAY, 4) + + val resources2 = Resources() + resources2.add(ResourceType.CLAY, 4) + + assertTrue(resources.contains(resources2)) + } + + @Test + fun minus_empty() { + val resources = Resources() + resources.add(ResourceType.STONE, 1) + resources.add(ResourceType.CLAY, 3) + + val emptyResources = Resources() + + val diff = resources.minus(emptyResources) + assertEquals(1, diff.getQuantity(ResourceType.STONE).toLong()) + assertEquals(3, diff.getQuantity(ResourceType.CLAY).toLong()) + assertEquals(0, diff.getQuantity(ResourceType.ORE).toLong()) + assertEquals(0, diff.getQuantity(ResourceType.GLASS).toLong()) + assertEquals(0, diff.getQuantity(ResourceType.LOOM).toLong()) + } + + @Test + fun minus_self() { + val resources = Resources() + resources.add(ResourceType.STONE, 1) + resources.add(ResourceType.CLAY, 3) + + val diff = resources.minus(resources) + assertEquals(0, diff.getQuantity(ResourceType.STONE).toLong()) + assertEquals(0, diff.getQuantity(ResourceType.CLAY).toLong()) + assertEquals(0, diff.getQuantity(ResourceType.ORE).toLong()) + assertEquals(0, diff.getQuantity(ResourceType.GLASS).toLong()) + assertEquals(0, diff.getQuantity(ResourceType.LOOM).toLong()) + } + + @Test + fun minus_allOfEachType() { + val resources = Resources() + resources.add(ResourceType.STONE, 1) + resources.add(ResourceType.CLAY, 3) + + val resources2 = Resources() + resources2.add(ResourceType.STONE, 1) + resources2.add(ResourceType.CLAY, 3) + + val diff = resources.minus(resources2) + assertEquals(0, diff.getQuantity(ResourceType.STONE).toLong()) + assertEquals(0, diff.getQuantity(ResourceType.CLAY).toLong()) + assertEquals(0, diff.getQuantity(ResourceType.ORE).toLong()) + assertEquals(0, diff.getQuantity(ResourceType.GLASS).toLong()) + assertEquals(0, diff.getQuantity(ResourceType.LOOM).toLong()) + } + + @Test + fun minus_someOfEachType() { + val resources = Resources() + resources.add(ResourceType.STONE, 2) + resources.add(ResourceType.CLAY, 4) + + val resources2 = Resources() + resources2.add(ResourceType.STONE, 1) + resources2.add(ResourceType.CLAY, 3) + + val diff = resources.minus(resources2) + assertEquals(1, diff.getQuantity(ResourceType.STONE).toLong()) + assertEquals(1, diff.getQuantity(ResourceType.CLAY).toLong()) + assertEquals(0, diff.getQuantity(ResourceType.ORE).toLong()) + assertEquals(0, diff.getQuantity(ResourceType.GLASS).toLong()) + assertEquals(0, diff.getQuantity(ResourceType.LOOM).toLong()) + } + + @Test + fun minus_someOfSomeTypes() { + val resources = Resources() + resources.add(ResourceType.STONE, 2) + resources.add(ResourceType.CLAY, 4) + + val resources2 = Resources() + resources2.add(ResourceType.CLAY, 3) + + val diff = resources.minus(resources2) + assertEquals(2, diff.getQuantity(ResourceType.STONE).toLong()) + assertEquals(1, diff.getQuantity(ResourceType.CLAY).toLong()) + assertEquals(0, diff.getQuantity(ResourceType.ORE).toLong()) + assertEquals(0, diff.getQuantity(ResourceType.GLASS).toLong()) + assertEquals(0, diff.getQuantity(ResourceType.LOOM).toLong()) + } + + @Test + fun minus_allOfSomeTypes() { + val resources = Resources() + resources.add(ResourceType.STONE, 2) + resources.add(ResourceType.CLAY, 4) + + val resources2 = Resources() + resources2.add(ResourceType.CLAY, 4) + + val diff = resources.minus(resources2) + assertEquals(2, diff.getQuantity(ResourceType.STONE).toLong()) + assertEquals(0, diff.getQuantity(ResourceType.CLAY).toLong()) + assertEquals(0, diff.getQuantity(ResourceType.ORE).toLong()) + assertEquals(0, diff.getQuantity(ResourceType.GLASS).toLong()) + assertEquals(0, diff.getQuantity(ResourceType.LOOM).toLong()) + } + + @Test + fun minus_tooMuchOfExistingType() { + val resources = Resources() + resources.add(ResourceType.CLAY, 4) + + val resources2 = Resources() + resources2.add(ResourceType.CLAY, 5) + + val diff = resources.minus(resources2) + assertEquals(0, diff.getQuantity(ResourceType.CLAY).toLong()) + } + + @Test + fun minus_someOfAnAbsentType() { + val resources = Resources() + + val resources2 = Resources() + resources2.add(ResourceType.LOOM, 5) + + val diff = resources.minus(resources2) + assertEquals(0, diff.getQuantity(ResourceType.LOOM).toLong()) + } + + @Test + fun minus_someOfATypeWithZero() { + val resources = Resources() + resources.add(ResourceType.LOOM, 0) + + val resources2 = Resources() + resources2.add(ResourceType.LOOM, 5) + + val diff = resources.minus(resources2) + assertEquals(0, diff.getQuantity(ResourceType.LOOM).toLong()) + } + + @Test + fun isEmpty_noElement() { + val resources = Resources() + assertTrue(resources.isEmpty) + } + + @Test + fun isEmpty_singleZeroElement() { + val resources = Resources() + resources.add(ResourceType.LOOM, 0) + assertTrue(resources.isEmpty) + } + + @Test + fun isEmpty_multipleZeroElements() { + val resources = Resources() + resources.add(ResourceType.WOOD, 0) + resources.add(ResourceType.ORE, 0) + resources.add(ResourceType.LOOM, 0) + assertTrue(resources.isEmpty) + } + + @Test + fun isEmpty_singleElementMoreThanZero() { + val resources = Resources() + resources.add(ResourceType.LOOM, 3) + assertFalse(resources.isEmpty) + } + + @Test + fun isEmpty_mixedZeroAndNonZeroElements() { + val resources = Resources() + resources.add(ResourceType.WOOD, 0) + resources.add(ResourceType.LOOM, 3) + assertFalse(resources.isEmpty) + } + + @Test + fun isEmpty_mixedZeroAndNonZeroElements_reverseOrder() { + val resources = Resources() + resources.add(ResourceType.ORE, 3) + resources.add(ResourceType.PAPYRUS, 0) + assertFalse(resources.isEmpty) + } + + @Test + fun equals_falseWhenNull() { + val resources = Resources() + resources.add(ResourceType.GLASS, 1) + + assertFalse(resources == null) + } + + @Test + fun equals_falseWhenDifferentClass() { + val resources = Resources() + resources.add(ResourceType.GLASS, 1) + val production = Production() + production.addFixedResource(ResourceType.GLASS, 1) + + assertFalse(resources == production) + } + + @Test + fun equals_trueWhenSame() { + val resources = Resources() + assertEquals(resources, resources) + } + + @Test + fun equals_trueWhenSameContent() { + val resources1 = Resources() + val resources2 = Resources() + assertTrue(resources1 == resources2) + resources1.add(ResourceType.GLASS, 1) + resources2.add(ResourceType.GLASS, 1) + assertTrue(resources1 == resources2) + } + + @Test + fun hashCode_sameWhenSameContent() { + val resources1 = Resources() + val resources2 = Resources() + assertEquals(resources1.hashCode().toLong(), resources2.hashCode().toLong()) + resources1.add(ResourceType.GLASS, 1) + resources2.add(ResourceType.GLASS, 1) + assertEquals(resources1.hashCode().toLong(), resources2.hashCode().toLong()) + } +} diff --git a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/resources/TradingRulesTest.kt b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/resources/TradingRulesTest.kt new file mode 100644 index 00000000..859c997a --- /dev/null +++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/resources/TradingRulesTest.kt @@ -0,0 +1,127 @@ +package org.luxons.sevenwonders.game.resources + +import java.util.ArrayList + +import org.junit.experimental.theories.DataPoints +import org.junit.experimental.theories.Theories +import org.junit.experimental.theories.Theory +import org.junit.runner.RunWith +import org.luxons.sevenwonders.game.test.* + +import org.junit.Assert.assertEquals +import org.junit.Assume.assumeTrue + +@RunWith(Theories::class) +class TradingRulesTest { + + @Theory + fun setCost_overridesCost( + defaultCost: Int, overriddenCost: Int, overriddenProvider: Provider, + provider: Provider, type: ResourceType + ) { + assumeTrue(defaultCost != overriddenCost) + assumeTrue(overriddenProvider != provider) + + val rules = TradingRules(defaultCost) + rules.setCost(type, overriddenProvider, overriddenCost) + + assertEquals(overriddenCost.toLong(), rules.getCost(type, overriddenProvider).toLong()) + assertEquals(defaultCost.toLong(), rules.getCost(type, provider).toLong()) + } + + @Theory + fun computeCost_zeroForNoResources(defaultCost: Int) { + val rules = TradingRules(defaultCost) + assertEquals(0, rules.computeCost(ResourceTransactions()).toLong()) + } + + @Theory + fun computeCost_defaultCostWhenNoOverride(defaultCost: Int, provider: Provider, type: ResourceType) { + val rules = TradingRules(defaultCost) + val transactions = createTransactions(provider, type) + assertEquals(defaultCost.toLong(), rules.computeCost(transactions).toLong()) + } + + @Theory + fun computeCost_twiceDefaultFor2Resources(defaultCost: Int, provider: Provider, type: ResourceType) { + val rules = TradingRules(defaultCost) + val transactions = createTransactions(provider, type, type) + assertEquals((2 * defaultCost).toLong(), rules.computeCost(transactions).toLong()) + } + + @Theory + fun computeCost_overriddenCost(defaultCost: Int, overriddenCost: Int, provider: Provider, type: ResourceType) { + val rules = TradingRules(defaultCost) + rules.setCost(type, provider, overriddenCost) + val transactions = createTransactions(provider, type) + assertEquals(overriddenCost.toLong(), rules.computeCost(transactions).toLong()) + } + + @Theory + fun computeCost_defaultCostWhenOverrideOnOtherProviderOrType( + defaultCost: Int, overriddenCost: Int, + overriddenProvider: Provider, + overriddenType: ResourceType, provider: Provider, + type: ResourceType + ) { + assumeTrue(overriddenProvider != provider || overriddenType != type) + val rules = TradingRules(defaultCost) + rules.setCost(overriddenType, overriddenProvider, overriddenCost) + val transactions = createTransactions(provider, type) + assertEquals(defaultCost.toLong(), rules.computeCost(transactions).toLong()) + } + + @Theory + fun computeCost_oneDefaultAndOneOverriddenType( + defaultCost: Int, overriddenCost: Int, + overriddenType: ResourceType, provider: Provider, + type: ResourceType + ) { + assumeTrue(overriddenType != type) + val rules = TradingRules(defaultCost) + rules.setCost(overriddenType, provider, overriddenCost) + val transactions = createTransactions(provider, overriddenType, type) + assertEquals((defaultCost + overriddenCost).toLong(), rules.computeCost(transactions).toLong()) + } + + @Theory + fun computeCost_oneDefaultAndOneOverriddenProvider( + defaultCost: Int, overriddenCost: Int, + overriddenProvider: Provider, provider: Provider, + type: ResourceType + ) { + assumeTrue(overriddenProvider != provider) + val rules = TradingRules(defaultCost) + rules.setCost(type, overriddenProvider, overriddenCost) + + val boughtResources = ArrayList<ResourceTransaction>(2) + boughtResources.add(createTransaction(provider, type)) + boughtResources.add(createTransaction(overriddenProvider, type)) + + assertEquals( + (defaultCost + overriddenCost).toLong(), + rules.computeCost(ResourceTransactions(boughtResources)).toLong() + ) + } + + companion object { + + @JvmStatic + @DataPoints + fun costs(): IntArray { + return intArrayOf(0, 1, 2) + } + + @JvmStatic + @DataPoints + fun providers(): Array<Provider> { + return Provider.values() + } + + @JvmStatic + @DataPoints + fun resourceTypes(): Array<ResourceType> { + return ResourceType.values() + } + } +} |