From 9049dd004df71619e08a350c0a6e49455041d31b Mon Sep 17 00:00:00 2001 From: Joffrey BION Date: Fri, 6 Jul 2018 00:43:50 +0200 Subject: Kotlin mig: cards package --- .../java/org/luxons/sevenwonders/game/Game.java | 6 +- .../org/luxons/sevenwonders/game/cards/Card.java | 128 ----------------- .../luxons/sevenwonders/game/cards/CardBack.java | 14 -- .../org/luxons/sevenwonders/game/cards/Color.java | 11 -- .../org/luxons/sevenwonders/game/cards/Decks.java | 65 --------- .../game/cards/HandRotationDirection.java | 21 --- .../org/luxons/sevenwonders/game/cards/Hands.java | 64 --------- .../sevenwonders/game/cards/Requirements.java | 108 -------------- .../org/luxons/sevenwonders/game/api/HandCard.kt | 3 +- .../org/luxons/sevenwonders/game/api/PlayerMove.kt | 4 +- .../org/luxons/sevenwonders/game/api/Table.kt | 8 +- .../org/luxons/sevenwonders/game/cards/Cards.kt | 52 +++++++ .../org/luxons/sevenwonders/game/cards/Decks.kt | 38 +++++ .../game/cards/HandRotationDirection.kt | 15 ++ .../org/luxons/sevenwonders/game/cards/Hands.kt | 32 +++++ .../luxons/sevenwonders/game/cards/Requirements.kt | 84 +++++++++++ .../game/data/definitions/CardDefinition.kt | 10 +- .../game/data/definitions/DecksDefinition.kt | 7 +- .../org/luxons/sevenwonders/game/GameTest.java | 26 ++-- .../sevenwonders/game/cards/CardBackTest.java | 15 -- .../luxons/sevenwonders/game/cards/CardTest.java | 110 -------------- .../luxons/sevenwonders/game/cards/DecksTest.java | 112 --------------- .../game/cards/HandRotationDirectionTest.java | 15 -- .../luxons/sevenwonders/game/cards/HandsTest.java | 143 ------------------- .../sevenwonders/game/cards/RequirementsTest.java | 145 ------------------- .../game/moves/BuildWonderMoveTest.java | 6 +- .../luxons/sevenwonders/game/cards/CardBackTest.kt | 15 ++ .../org/luxons/sevenwonders/game/cards/CardTest.kt | 50 +++++++ .../luxons/sevenwonders/game/cards/DecksTest.kt | 99 +++++++++++++ .../game/cards/HandRotationDirectionTest.kt | 15 ++ .../luxons/sevenwonders/game/cards/HandsTest.kt | 125 ++++++++++++++++ .../sevenwonders/game/cards/RequirementsTest.kt | 158 +++++++++++++++++++++ .../org/luxons/sevenwonders/game/test/TestUtils.kt | 37 ++--- 33 files changed, 730 insertions(+), 1011 deletions(-) delete mode 100644 game-engine/src/main/java/org/luxons/sevenwonders/game/cards/Card.java delete mode 100644 game-engine/src/main/java/org/luxons/sevenwonders/game/cards/CardBack.java delete mode 100644 game-engine/src/main/java/org/luxons/sevenwonders/game/cards/Color.java delete mode 100644 game-engine/src/main/java/org/luxons/sevenwonders/game/cards/Decks.java delete mode 100644 game-engine/src/main/java/org/luxons/sevenwonders/game/cards/HandRotationDirection.java delete mode 100644 game-engine/src/main/java/org/luxons/sevenwonders/game/cards/Hands.java delete mode 100644 game-engine/src/main/java/org/luxons/sevenwonders/game/cards/Requirements.java create mode 100644 game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Cards.kt create mode 100644 game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Decks.kt create mode 100644 game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/HandRotationDirection.kt create mode 100644 game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Hands.kt create mode 100644 game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Requirements.kt delete mode 100644 game-engine/src/test/java/org/luxons/sevenwonders/game/cards/CardBackTest.java delete mode 100644 game-engine/src/test/java/org/luxons/sevenwonders/game/cards/CardTest.java delete mode 100644 game-engine/src/test/java/org/luxons/sevenwonders/game/cards/DecksTest.java delete mode 100644 game-engine/src/test/java/org/luxons/sevenwonders/game/cards/HandRotationDirectionTest.java delete mode 100644 game-engine/src/test/java/org/luxons/sevenwonders/game/cards/HandsTest.java delete mode 100644 game-engine/src/test/java/org/luxons/sevenwonders/game/cards/RequirementsTest.java create mode 100644 game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/CardBackTest.kt create mode 100644 game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/CardTest.kt create mode 100644 game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/DecksTest.kt create mode 100644 game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/HandRotationDirectionTest.kt create mode 100644 game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/HandsTest.kt create mode 100644 game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/RequirementsTest.kt (limited to 'game-engine/src') diff --git a/game-engine/src/main/java/org/luxons/sevenwonders/game/Game.java b/game-engine/src/main/java/org/luxons/sevenwonders/game/Game.java index 2696adbf..1d88fb9f 100644 --- a/game-engine/src/main/java/org/luxons/sevenwonders/game/Game.java +++ b/game-engine/src/main/java/org/luxons/sevenwonders/game/Game.java @@ -109,7 +109,7 @@ public class Game { } public CardBack prepareMove(int playerIndex, PlayerMove playerMove) throws InvalidMoveException { - Card card = decks.getCard(playerMove.getCardName()); + Card card = decks.getCard(table.getCurrentAge(), playerMove.getCardName()); Move move = playerMove.getType().resolve(playerIndex, card, playerMove); validate(move); preparedMoves.put(playerIndex, move); @@ -143,7 +143,7 @@ public class Game { private void rotateHandsIfRelevant() { // we don't rotate hands if some player can play his last card (with the special ability) if (!hands.maxOneCardRemains()) { - hands.rotate(table.getHandRotationDirection()); + hands = hands.rotate(table.getHandRotationDirection()); } } @@ -196,7 +196,7 @@ public class Game { private void discardHand(int playerIndex) { List hand = hands.get(playerIndex); discardedCards.addAll(hand); - hand.clear(); + hands = hands.discard(playerIndex); } private void removeFromHand(int playerIndex, Card card) { diff --git a/game-engine/src/main/java/org/luxons/sevenwonders/game/cards/Card.java b/game-engine/src/main/java/org/luxons/sevenwonders/game/cards/Card.java deleted file mode 100644 index 2d2f6777..00000000 --- a/game-engine/src/main/java/org/luxons/sevenwonders/game/cards/Card.java +++ /dev/null @@ -1,128 +0,0 @@ -package org.luxons.sevenwonders.game.cards; - -import java.util.List; -import java.util.Objects; - -import org.luxons.sevenwonders.game.api.Table; -import org.luxons.sevenwonders.game.boards.Board; -import org.luxons.sevenwonders.game.effects.Effect; -import org.luxons.sevenwonders.game.resources.ResourceTransactions; - -public class Card { - - private final String name; - - private final Color color; - - private final Requirements requirements; - - private final List effects; - - private final String chainParent; - - private final List chainChildren; - - private final String image; - - private CardBack back; - - public Card(String name, Color color, Requirements requirements, List effects, String chainParent, - List chainChildren, String image) { - this.name = name; - this.color = color; - this.requirements = requirements; - this.chainParent = chainParent; - this.effects = effects; - this.chainChildren = chainChildren; - this.image = image; - } - - public String getName() { - return name; - } - - public Color getColor() { - return color; - } - - public String getChainParent() { - return chainParent; - } - - public Requirements getRequirements() { - return requirements; - } - - public List getEffects() { - return effects; - } - - public List getChainChildren() { - return chainChildren; - } - - public String getImage() { - return image; - } - - public CardBack getBack() { - return back; - } - - public void setBack(CardBack back) { - this.back = back; - } - - private boolean isAllowedOnBoard(Board board) { - return !board.isPlayed(name); // cannot play twice the same card - } - - public boolean isChainableOn(Board board) { - return isAllowedOnBoard(board) && board.isPlayed(chainParent); - } - - public boolean isFreeFor(Board board) { - if (!isAllowedOnBoard(board)) { - return false; - } - return isChainableOn(board) || (requirements.areMetWithoutNeighboursBy(board) && requirements.getGold() == 0); - } - - public boolean isPlayable(Table table, int playerIndex) { - Board board = table.getBoard(playerIndex); - if (!isAllowedOnBoard(board)) { - return false; - } - return isChainableOn(board) || requirements.areMetBy(table, playerIndex); - } - - public void applyTo(Table table, int playerIndex, ResourceTransactions transactions) { - Board playerBoard = table.getBoard(playerIndex); - if (!isChainableOn(playerBoard)) { - requirements.pay(table, playerIndex, transactions); - } - effects.forEach(e -> e.apply(table, playerIndex)); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Card card = (Card) o; - return Objects.equals(name, card.name); - } - - @Override - public int hashCode() { - return Objects.hash(name); - } - - @Override - public String toString() { - return "Card{" + name + '}'; - } -} diff --git a/game-engine/src/main/java/org/luxons/sevenwonders/game/cards/CardBack.java b/game-engine/src/main/java/org/luxons/sevenwonders/game/cards/CardBack.java deleted file mode 100644 index f925b6c4..00000000 --- a/game-engine/src/main/java/org/luxons/sevenwonders/game/cards/CardBack.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.luxons.sevenwonders.game.cards; - -public class CardBack { - - private final String image; - - public CardBack(String image) { - this.image = image; - } - - public String getImage() { - return image; - } -} diff --git a/game-engine/src/main/java/org/luxons/sevenwonders/game/cards/Color.java b/game-engine/src/main/java/org/luxons/sevenwonders/game/cards/Color.java deleted file mode 100644 index 80d06c55..00000000 --- a/game-engine/src/main/java/org/luxons/sevenwonders/game/cards/Color.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.luxons.sevenwonders.game.cards; - -public enum Color { - BROWN, - GREY, - YELLOW, - BLUE, - GREEN, - RED, - PURPLE -} diff --git a/game-engine/src/main/java/org/luxons/sevenwonders/game/cards/Decks.java b/game-engine/src/main/java/org/luxons/sevenwonders/game/cards/Decks.java deleted file mode 100644 index aa2b00bf..00000000 --- a/game-engine/src/main/java/org/luxons/sevenwonders/game/cards/Decks.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.luxons.sevenwonders.game.cards; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class Decks { - - private Map> cardsPerAge = new HashMap<>(); - - public Decks(Map> cardsPerAge) { - this.cardsPerAge = cardsPerAge; - } - - public Card getCard(String cardName) throws CardNotFoundException { - return cardsPerAge.values() - .stream() - .flatMap(List::stream) - .filter(c -> c.getName().equals(cardName)) - .findAny() - .orElseThrow(() -> new CardNotFoundException(cardName)); - } - - public Hands deal(int age, int nbPlayers) { - List deck = getDeck(age); - validateNbCards(deck, nbPlayers); - return deal(deck, nbPlayers); - } - - private List getDeck(int age) { - List deck = cardsPerAge.get(age); - if (deck == null) { - throw new IllegalArgumentException("No deck found for age " + age); - } - return deck; - } - - private void validateNbCards(List deck, int nbPlayers) { - if (nbPlayers == 0) { - throw new IllegalArgumentException("Cannot deal cards between 0 players"); - } - if (deck.size() % nbPlayers != 0) { - throw new IllegalArgumentException( - String.format("Cannot deal %d cards evenly between %d players", deck.size(), nbPlayers)); - } - } - - private Hands deal(List deck, int nbPlayers) { - Map> hands = new HashMap<>(nbPlayers); - for (int i = 0; i < nbPlayers; i++) { - hands.put(i, new ArrayList<>()); - } - for (int i = 0; i < deck.size(); i++) { - hands.get(i % nbPlayers).add(deck.get(i)); - } - return new Hands(hands, nbPlayers); - } - - class CardNotFoundException extends RuntimeException { - CardNotFoundException(String message) { - super(message); - } - } -} diff --git a/game-engine/src/main/java/org/luxons/sevenwonders/game/cards/HandRotationDirection.java b/game-engine/src/main/java/org/luxons/sevenwonders/game/cards/HandRotationDirection.java deleted file mode 100644 index f3902fb5..00000000 --- a/game-engine/src/main/java/org/luxons/sevenwonders/game/cards/HandRotationDirection.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.luxons.sevenwonders.game.cards; - -public enum HandRotationDirection { - LEFT(-1), - RIGHT(1); - - private final int indexOffset; - - HandRotationDirection(int i) { - this.indexOffset = i; - } - - public int getIndexOffset() { - return indexOffset; - } - - public static HandRotationDirection forAge(int age) { - // clockwise (pass to the left) at age 1, and alternating - return age % 2 == 0 ? HandRotationDirection.RIGHT : HandRotationDirection.LEFT; - } -} diff --git a/game-engine/src/main/java/org/luxons/sevenwonders/game/cards/Hands.java b/game-engine/src/main/java/org/luxons/sevenwonders/game/cards/Hands.java deleted file mode 100644 index 4a8bc143..00000000 --- a/game-engine/src/main/java/org/luxons/sevenwonders/game/cards/Hands.java +++ /dev/null @@ -1,64 +0,0 @@ -package org.luxons.sevenwonders.game.cards; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import org.luxons.sevenwonders.game.api.HandCard; -import org.luxons.sevenwonders.game.api.Table; - -public class Hands { - - private final int nbPlayers; - - private Map> hands; - - Hands(Map> hands, int nbPlayers) { - this.hands = hands; - this.nbPlayers = nbPlayers; - } - - public List get(int playerIndex) { - if (!hands.containsKey(playerIndex)) { - throw new PlayerIndexOutOfBoundsException(playerIndex); - } - return hands.get(playerIndex); - } - - public List createHand(Table table, int playerIndex) { - return hands.get(playerIndex) - .stream() - .map(c -> new HandCard(c, table, playerIndex)) - .collect(Collectors.toList()); - } - - public Hands rotate(HandRotationDirection direction) { - Map> newHands = new HashMap<>(hands.size()); - for (int i = 0; i < nbPlayers; i++) { - int newIndex = Math.floorMod(i + direction.getIndexOffset(), nbPlayers); - newHands.put(newIndex, hands.get(i)); - } - return new Hands(newHands, nbPlayers); - } - - public boolean isEmpty() { - return hands.values().stream().allMatch(List::isEmpty); - } - - public boolean maxOneCardRemains() { - return hands.values().stream().mapToInt(List::size).max().orElse(0) <= 1; - } - - public List gatherAndClear() { - List remainingCards = hands.values().stream().flatMap(List::stream).collect(Collectors.toList()); - hands.clear(); - return remainingCards; - } - - class PlayerIndexOutOfBoundsException extends ArrayIndexOutOfBoundsException { - PlayerIndexOutOfBoundsException(int index) { - super(index); - } - } -} diff --git a/game-engine/src/main/java/org/luxons/sevenwonders/game/cards/Requirements.java b/game-engine/src/main/java/org/luxons/sevenwonders/game/cards/Requirements.java deleted file mode 100644 index 8c7245ed..00000000 --- a/game-engine/src/main/java/org/luxons/sevenwonders/game/cards/Requirements.java +++ /dev/null @@ -1,108 +0,0 @@ -package org.luxons.sevenwonders.game.cards; - -import org.luxons.sevenwonders.game.api.Table; -import org.luxons.sevenwonders.game.boards.Board; -import org.luxons.sevenwonders.game.resources.BestPriceCalculator; -import org.luxons.sevenwonders.game.resources.ResourceTransactions; -import org.luxons.sevenwonders.game.resources.Resources; - -public class Requirements { - - private int gold; - - private Resources resources = new Resources(); - - public int getGold() { - return gold; - } - - public void setGold(int gold) { - this.gold = gold; - } - - public Resources getResources() { - return resources; - } - - public void setResources(Resources resources) { - this.resources = resources; - } - - /** - * Returns whether the given board meets these requirements on its own. - * - * @param board - * the board to check - * - * @return true if the given board meets these requirements without any transaction with its neighbours - */ - boolean areMetWithoutNeighboursBy(Board board) { - return hasRequiredGold(board) && producesRequiredResources(board); - } - - /** - * Returns whether the given board meets these requirements, if the specified resources are bought from neighbours. - * - * @param board - * the board to check - * @param boughtResources - * the resources the player intends to buy - * - * @return true if the given board meets these requirements - */ - public boolean areMetWithHelpBy(Board board, ResourceTransactions boughtResources) { - if (!hasRequiredGold(board, boughtResources)) { - return false; - } - if (producesRequiredResources(board)) { - return true; - } - return producesRequiredResourcesWithHelp(board, boughtResources); - } - - /** - * Returns whether the given player's board meets these requirements, either on its own or by buying resources to - * neighbours. - * - * @param table - * the current game table - * @param playerIndex - * the index of the player to check - * - * @return true if the given player's board could meet these requirements - */ - boolean areMetBy(Table table, int playerIndex) { - Board board = table.getBoard(playerIndex); - if (!hasRequiredGold(board)) { - return false; - } - if (producesRequiredResources(board)) { - return true; - } - return BestPriceCalculator.bestPrice(resources, table, playerIndex) <= board.getGold() - gold; - } - - private boolean hasRequiredGold(Board board) { - return board.getGold() >= gold; - } - - private boolean hasRequiredGold(Board board, ResourceTransactions resourceTransactions) { - int resourcesPrice = board.getTradingRules().computeCost(resourceTransactions); - return board.getGold() >= gold + resourcesPrice; - } - - private boolean producesRequiredResources(Board board) { - return board.getProduction().contains(resources); - } - - private boolean producesRequiredResourcesWithHelp(Board board, ResourceTransactions transactions) { - Resources totalBoughtResources = transactions.asResources(); - Resources remainingResources = this.resources.minus(totalBoughtResources); - return board.getProduction().contains(remainingResources); - } - - public void pay(Table table, int playerIndex, ResourceTransactions transactions) { - table.getBoard(playerIndex).removeGold(gold); - transactions.execute(table, playerIndex); - } -} 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 4c3a7a8d..d487a9ac 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 @@ -12,12 +12,11 @@ class HandCard(val card: Card, table: Table, playerIndex: Int) { val isFree: Boolean - val isPlayable: Boolean + val isPlayable: Boolean = card.isPlayable(table, playerIndex) init { val board = table.getBoard(playerIndex) this.isChainable = card.isChainableOn(board) this.isFree = card.isFreeFor(board) - this.isPlayable = card.isPlayable(table, playerIndex) } } 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 d0a1e1b3..4d4ef7cc 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,8 +3,8 @@ package org.luxons.sevenwonders.game.api import org.luxons.sevenwonders.game.moves.MoveType import org.luxons.sevenwonders.game.resources.ResourceTransaction -data class PlayerMove( +data class PlayerMove @JvmOverloads constructor( val type: MoveType, - val cardName: String?, + val cardName: String, val transactions: Collection = emptyList() ) diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/Table.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/Table.kt index 9ecfa6b0..60287c84 100644 --- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/Table.kt +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/Table.kt @@ -40,18 +40,18 @@ class Table(val boards: List) { for (i in 0 until nbPlayers) { val board1 = getBoard(i) val board2 = getBoard((i + 1) % nbPlayers) - resolveConflict(board1, board2, currentAge) + resolveConflict(board1, board2) } } - private fun resolveConflict(board1: Board, board2: Board, age: Int) { + private fun resolveConflict(board1: Board, board2: Board) { val shields1 = board1.military.nbShields val shields2 = board2.military.nbShields if (shields1 < shields2) { board1.military.defeat() - board2.military.victory(age) + board2.military.victory(currentAge) } else if (shields1 > shields2) { - board1.military.victory(age) + board1.military.victory(currentAge) board2.military.defeat() } } diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Cards.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Cards.kt new file mode 100644 index 00000000..cf94bef4 --- /dev/null +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Cards.kt @@ -0,0 +1,52 @@ +package org.luxons.sevenwonders.game.cards + +import org.luxons.sevenwonders.game.api.Table +import org.luxons.sevenwonders.game.boards.Board +import org.luxons.sevenwonders.game.effects.Effect +import org.luxons.sevenwonders.game.resources.ResourceTransactions + +data class CardBack(val image: String) + +data class Card( + val name: String, + val color: Color, + val requirements: Requirements, + val effects: List, + val chainParent: String?, + val chainChildren: List, + val image: String, + val back: CardBack +) { + private fun isAllowedOnBoard(board: Board): Boolean = !board.isPlayed(name) // cannot play twice the same card + + fun isFreeFor(board: Board): Boolean = isChainableOn(board) || isFreeWithoutChainingOn(board) + + fun isChainableOn(board: Board): Boolean = + isAllowedOnBoard(board) && chainParent != null && board.isPlayed(chainParent) + + private fun isFreeWithoutChainingOn(board: Board) = + isAllowedOnBoard(board) && requirements.areMetWithoutNeighboursBy(board) && requirements.gold == 0 + + fun isPlayable(table: Table, playerIndex: Int): Boolean { + val board = table.getBoard(playerIndex) + return isAllowedOnBoard(board) && (isChainableOn(board) || requirements.areMetBy(table, playerIndex)) + } + + fun applyTo(table: Table, playerIndex: Int, transactions: ResourceTransactions) { + val playerBoard = table.getBoard(playerIndex) + if (!isChainableOn(playerBoard)) { + requirements.pay(table, playerIndex, transactions) + } + effects.forEach { e -> e.apply(table, playerIndex) } + } +} + +enum class Color { + BROWN, + GREY, + YELLOW, + BLUE, + GREEN, + RED, + PURPLE +} diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Decks.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Decks.kt new file mode 100644 index 00000000..bd7b4bde --- /dev/null +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Decks.kt @@ -0,0 +1,38 @@ +package org.luxons.sevenwonders.game.cards + +fun List.deal(nbPlayers: Int): Hands { + val hands: Map> = this.withIndex() + .groupBy { (index, _) -> index % nbPlayers } + .mapValues { it.value.map { (_, cards) -> cards } } + + val allHands = List(nbPlayers) { i -> hands[i] ?: emptyList() } + return Hands(allHands) +} + +class Decks(private val cardsPerAge: Map>) { + + @Throws(Decks.CardNotFoundException::class) + fun getCard(age: Int, cardName: String): Card = + getDeck(age).firstOrNull { c -> c.name == cardName } ?: throw CardNotFoundException(cardName) + + fun deal(age: Int, nbPlayers: Int): Hands { + val deck = getDeck(age) + validateNbCards(deck, nbPlayers) + return deck.deal(nbPlayers) + } + + private fun getDeck(age: Int): List { + return cardsPerAge[age] ?: throw IllegalArgumentException("No deck found for age $age") + } + + private fun validateNbCards(deck: List, nbPlayers: Int) { + if (nbPlayers == 0) { + throw IllegalArgumentException("Cannot deal cards between 0 players") + } + if (deck.size % nbPlayers != 0) { + throw IllegalArgumentException("Cannot deal ${deck.size} cards evenly between $nbPlayers players") + } + } + + inner class CardNotFoundException(message: String) : RuntimeException(message) +} diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/HandRotationDirection.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/HandRotationDirection.kt new file mode 100644 index 00000000..13494175 --- /dev/null +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/HandRotationDirection.kt @@ -0,0 +1,15 @@ +package org.luxons.sevenwonders.game.cards + +enum class HandRotationDirection { + LEFT, + RIGHT; + + companion object { + + fun forAge(age: Int): HandRotationDirection { + // clockwise (pass to the left) at age 1, and alternating + return if (age % 2 == 0) HandRotationDirection.RIGHT else HandRotationDirection.LEFT + } + } +} + diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Hands.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Hands.kt new file mode 100644 index 00000000..35d3599a --- /dev/null +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Hands.kt @@ -0,0 +1,32 @@ +package org.luxons.sevenwonders.game.cards + +import org.luxons.sevenwonders.game.api.HandCard +import org.luxons.sevenwonders.game.api.Table + +class Hands internal constructor(private val hands: List>) { + + val isEmpty: Boolean = this.hands.all(List::isEmpty) + + operator fun get(playerIndex: Int): List { + return hands[playerIndex] + } + + fun discard(playerIndex: Int): Hands { + val newHands = hands.mapIndexed { index, hand -> if (index == playerIndex) emptyList() else hand } + return Hands(newHands) + } + + fun createHand(table: Table, playerIndex: Int): List { + return hands[playerIndex].map { c -> HandCard(c, table, playerIndex) } + } + + fun rotate(direction: HandRotationDirection): Hands { + val newHands = when (direction) { + HandRotationDirection.RIGHT -> hands.takeLast(1) + hands.dropLast(1) + HandRotationDirection.LEFT -> hands.drop(1) + hands.take(1) + } + return Hands(newHands) + } + + fun maxOneCardRemains(): Boolean = hands.map { it.size }.max() ?: 0 <= 1 +} diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Requirements.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Requirements.kt new file mode 100644 index 00000000..e04fa7a0 --- /dev/null +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Requirements.kt @@ -0,0 +1,84 @@ +package org.luxons.sevenwonders.game.cards + +import org.luxons.sevenwonders.game.api.Table +import org.luxons.sevenwonders.game.boards.Board +import org.luxons.sevenwonders.game.resources.BestPriceCalculator +import org.luxons.sevenwonders.game.resources.ResourceTransactions +import org.luxons.sevenwonders.game.resources.Resources + +data class Requirements @JvmOverloads constructor( + val gold: Int = 0, + val resources: Resources = Resources() +) { + /** + * Returns whether the given [board] meets these requirements on its own. + * + * @param board the board to check + * + * @return true if the given board meets these requirements without any transaction with its neighbours + */ + fun areMetWithoutNeighboursBy(board: Board): Boolean { + return hasRequiredGold(board) && producesRequiredResources(board) + } + + /** + * Returns whether the given board meets these requirements, if the specified resources are bought from neighbours. + * + * @param board the board to check + * @param boughtResources the resources the player intends to buy + * + * @return true if the given board meets these requirements + */ + fun areMetWithHelpBy(board: Board, boughtResources: ResourceTransactions): Boolean { + if (!hasRequiredGold(board, boughtResources)) { + return false + } + return if (producesRequiredResources(board)) { + true + } else producesRequiredResourcesWithHelp(board, boughtResources) + } + + /** + * Returns whether the given player's board meets these requirements, either on its own or by buying resources to + * neighbours. + * + * @param table the current game table + * @param playerIndex the index of the player to check + * + * @return true if the given player's board could meet these requirements + */ + fun areMetBy(table: Table, playerIndex: Int): Boolean { + val board = table.getBoard(playerIndex) + if (!hasRequiredGold(board)) { + return false + } + if (producesRequiredResources(board)) { + return true + } + return BestPriceCalculator.bestPrice(resources, table, playerIndex) <= board.gold - gold + } + + private fun hasRequiredGold(board: Board): Boolean { + return board.gold >= gold + } + + private fun hasRequiredGold(board: Board, resourceTransactions: ResourceTransactions): Boolean { + val resourcesPrice = board.tradingRules.computeCost(resourceTransactions) + return board.gold >= gold + resourcesPrice + } + + private fun producesRequiredResources(board: Board): Boolean { + return board.production.contains(resources) + } + + private fun producesRequiredResourcesWithHelp(board: Board, transactions: ResourceTransactions): Boolean { + val totalBoughtResources = transactions.asResources() + val remainingResources = this.resources.minus(totalBoughtResources) + return board.production.contains(remainingResources) + } + + fun pay(table: Table, playerIndex: Int, transactions: ResourceTransactions) { + table.getBoard(playerIndex).removeGold(gold) + transactions.execute(table, playerIndex) + } +} diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/CardDefinition.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/CardDefinition.kt index 2827564b..3f42746c 100644 --- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/CardDefinition.kt +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/CardDefinition.kt @@ -1,20 +1,22 @@ package org.luxons.sevenwonders.game.data.definitions import org.luxons.sevenwonders.game.cards.Card +import org.luxons.sevenwonders.game.cards.CardBack import org.luxons.sevenwonders.game.cards.Color import org.luxons.sevenwonders.game.cards.Requirements internal class CardDefinition( private val name: String, private val color: Color, - private val requirements: Requirements? = null, + private val requirements: Requirements = Requirements(), private val effect: EffectsDefinition, private val chainParent: String? = null, private val chainChildren: List = emptyList(), - private val image: String? = null, + private val image: String, private val countPerNbPlayer: Map ) { - fun create(nbPlayers: Int): List = List( countPerNbPlayer[nbPlayers]!!) { create() } + fun create(back: CardBack, nbPlayers: Int): List = List(countPerNbPlayer[nbPlayers] ?: 0) { create(back) } - fun create(): Card = Card(name, color, requirements, effect.create(), chainParent, chainChildren, image) + fun create(back: CardBack): Card = + Card(name, color, requirements, effect.create(), chainParent, chainChildren, image, back) } diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/DecksDefinition.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/DecksDefinition.kt index a09f0642..bc025ea2 100644 --- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/DecksDefinition.kt +++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/DecksDefinition.kt @@ -39,14 +39,11 @@ internal class DecksDefinition( } private fun createDeck(defs: List, settings: Settings, back: CardBack): List { - return defs.flatMap { it.create(settings.nbPlayers) }.onEach { it.back = back } + return defs.flatMap { it.create(back, settings.nbPlayers) } } private fun createGuildCards(settings: Settings, back: CardBack): List { - val guild = guildCards - .map { it.create() } - .map { c -> c.back = back; c } - .toMutableList() + val guild = guildCards.map { it.create(back) }.toMutableList() guild.shuffle(settings.random) return guild.subList(0, settings.nbPlayers + 2) } diff --git a/game-engine/src/test/java/org/luxons/sevenwonders/game/GameTest.java b/game-engine/src/test/java/org/luxons/sevenwonders/game/GameTest.java index 9beb44fd..de187d26 100644 --- a/game-engine/src/test/java/org/luxons/sevenwonders/game/GameTest.java +++ b/game-engine/src/test/java/org/luxons/sevenwonders/game/GameTest.java @@ -71,16 +71,6 @@ public class GameTest { checkLastPlayedMoves(sentMoves, table); } - private static void checkLastPlayedMoves(Map sentMoves, Table table) { - for (Move move : table.getLastPlayedMoves()) { - PlayerMove sentMove = sentMoves.get(move.getPlayerIndex()); - assertNotNull(sentMove); - assertNotNull(move.getCard()); - assertEquals(sentMove.getCardName(), move.getCard().getName()); - assertSame(sentMove.getType(), move.getType()); - } - } - private static PlayerMove getFirstAvailableMove(PlayerTurnInfo turnInfo) { switch (turnInfo.getAction()) { case PLAY: @@ -99,11 +89,11 @@ public class GameTest { for (HandCard handCard : turnInfo.getHand()) { if (handCard.isPlayable()) { Set resourcesToBuy = findResourcesToBuyFor(handCard, turnInfo); - return TestUtilsKt.createPlayerMove(MoveType.PLAY, handCard.getCard().getName(), resourcesToBuy); + return new PlayerMove(MoveType.PLAY, handCard.getCard().getName(), resourcesToBuy); } } HandCard firstCardInHand = turnInfo.getHand().get(0); - return TestUtilsKt.createPlayerMove(MoveType.DISCARD, firstCardInHand.getCard().getName()); + return new PlayerMove(MoveType.DISCARD, firstCardInHand.getCard().getName()); } private static Set findResourcesToBuyFor(HandCard handCard, PlayerTurnInfo turnInfo) { @@ -122,6 +112,16 @@ public class GameTest { assertNotNull(neighbourGuilds); assertFalse(neighbourGuilds.isEmpty()); String cardName = neighbourGuilds.get(0).getName(); - return TestUtilsKt.createPlayerMove(MoveType.COPY_GUILD, cardName); + return new PlayerMove(MoveType.COPY_GUILD, cardName); + } + + private static void checkLastPlayedMoves(Map sentMoves, Table table) { + for (Move move : table.getLastPlayedMoves()) { + PlayerMove sentMove = sentMoves.get(move.getPlayerIndex()); + assertNotNull(sentMove); + assertNotNull(move.getCard()); + assertEquals(sentMove.getCardName(), move.getCard().getName()); + assertSame(sentMove.getType(), move.getType()); + } } } diff --git a/game-engine/src/test/java/org/luxons/sevenwonders/game/cards/CardBackTest.java b/game-engine/src/test/java/org/luxons/sevenwonders/game/cards/CardBackTest.java deleted file mode 100644 index 6f637f87..00000000 --- a/game-engine/src/test/java/org/luxons/sevenwonders/game/cards/CardBackTest.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.luxons.sevenwonders.game.cards; - -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -public class CardBackTest { - - @Test - public void initializedWithImage() { - String imagePath = "whateverimage.png"; - CardBack back = new CardBack(imagePath); - assertEquals(imagePath, back.getImage()); - } -} diff --git a/game-engine/src/test/java/org/luxons/sevenwonders/game/cards/CardTest.java b/game-engine/src/test/java/org/luxons/sevenwonders/game/cards/CardTest.java deleted file mode 100644 index b9681434..00000000 --- a/game-engine/src/test/java/org/luxons/sevenwonders/game/cards/CardTest.java +++ /dev/null @@ -1,110 +0,0 @@ -package org.luxons.sevenwonders.game.cards; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.junit.Before; -import org.junit.Test; -import org.luxons.sevenwonders.game.Settings; -import org.luxons.sevenwonders.game.api.Table; -import org.luxons.sevenwonders.game.boards.Board; -import org.luxons.sevenwonders.game.effects.Effect; -import org.luxons.sevenwonders.game.effects.ProductionIncrease; -import org.luxons.sevenwonders.game.resources.ResourceTransactions; -import org.luxons.sevenwonders.game.resources.ResourceType; -import org.luxons.sevenwonders.game.test.TestUtilsKt; -import org.luxons.sevenwonders.game.wonders.Wonder; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertTrue; - -public class CardTest { - - private Table table; - - private Card treeFarmCard; - - @Before - public void initBoard() { - Settings settings = new Settings(3); - - List boards = new ArrayList<>(3); - boards.add(new Board(new Wonder("TestWonder", ResourceType.WOOD), 0, settings)); - boards.add(new Board(new Wonder("TestWonder", ResourceType.STONE), 1, settings)); - boards.add(new Board(new Wonder("TestWonder", ResourceType.PAPYRUS), 2, settings)); - table = new Table(boards); - - Requirements treeFarmRequirements = new Requirements(); - treeFarmRequirements.setGold(1); - - ProductionIncrease treeFarmEffect = new ProductionIncrease(); - treeFarmEffect.getProduction().addChoice(ResourceType.WOOD, ResourceType.CLAY); - - List effects = Collections.singletonList(treeFarmEffect); - - treeFarmCard = new Card("Tree Farm", Color.BROWN, treeFarmRequirements, effects, "", null, null); - } - - @Test - public void playCardCostingMoney() { - table.getBoard(0).setGold(3); - table.getBoard(1).setGold(3); - table.getBoard(2).setGold(3); - treeFarmCard.applyTo(table, 0, new ResourceTransactions()); - assertEquals(2, table.getBoard(0).getGold()); - assertEquals(3, table.getBoard(1).getGold()); - assertEquals(3, table.getBoard(2).getGold()); - } - - @Test - public void equals_falseWhenNull() { - Card card = TestUtilsKt.testCard("TestCard"); - //noinspection ObjectEqualsNull - assertFalse(card.equals(null)); - } - - @Test - public void equals_falseWhenDifferentClass() { - Card card = TestUtilsKt.testCard("TestCard"); - Object object = new Object(); - //noinspection EqualsBetweenInconvertibleTypes - assertFalse(card.equals(object)); - } - - @Test - public void equals_trueWhenSame() { - Card card = TestUtilsKt.testCard("TestCard"); - assertEquals(card, card); - } - - @Test - public void equals_trueWhenSameContent() { - Card card1 = TestUtilsKt.testCard("TestCard"); - Card card2 = TestUtilsKt.testCard("TestCard"); - assertTrue(card1.equals(card2)); - } - - @Test - public void equals_falseWhenDifferentName() { - Card card1 = TestUtilsKt.testCard("TestCard1"); - Card card2 = TestUtilsKt.testCard("TestCard2"); - assertFalse(card1.equals(card2)); - } - - @Test - public void hashCode_sameWhenSameContent() { - Card card1 = TestUtilsKt.testCard("TestCard"); - Card card2 = TestUtilsKt.testCard("TestCard"); - assertEquals(card1.hashCode(), card2.hashCode()); - } - - @Test - public void hashCode_differentWhenDifferentName() { - Card card1 = TestUtilsKt.testCard("TestCard1"); - Card card2 = TestUtilsKt.testCard("TestCard2"); - assertNotEquals(card1.hashCode(), card2.hashCode()); - } -} diff --git a/game-engine/src/test/java/org/luxons/sevenwonders/game/cards/DecksTest.java b/game-engine/src/test/java/org/luxons/sevenwonders/game/cards/DecksTest.java deleted file mode 100644 index f572c5ac..00000000 --- a/game-engine/src/test/java/org/luxons/sevenwonders/game/cards/DecksTest.java +++ /dev/null @@ -1,112 +0,0 @@ -package org.luxons.sevenwonders.game.cards; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.experimental.theories.DataPoints; -import org.junit.experimental.theories.Theories; -import org.junit.experimental.theories.Theory; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.luxons.sevenwonders.game.cards.Decks.CardNotFoundException; -import org.luxons.sevenwonders.game.test.TestUtilsKt; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeTrue; - -@RunWith(Theories.class) -public class DecksTest { - - @Rule - public ExpectedException thrown = ExpectedException.none(); - - @DataPoints - public static int[] dataPoints() { - return new int[] {1, 2, 3, 5, 10}; - } - - private static Decks createDecks(int nbAges, int nbCardsPerAge) { - Map> cardsPerAge = new HashMap<>(); - for (int age = 1; age <= nbAges; age++) { - int firstCardNumber = (age - 1) * nbCardsPerAge; - cardsPerAge.put(age, TestUtilsKt.createSampleCards(firstCardNumber, nbCardsPerAge)); - } - return new Decks(cardsPerAge); - } - - @Test(expected = CardNotFoundException.class) - public void getCard_failsOnNullNameWhenDeckIsEmpty() { - Decks decks = createDecks(0, 0); - decks.getCard(null); - } - - @Test(expected = CardNotFoundException.class) - public void getCard_failsOnEmptyNameWhenDeckIsEmpty() { - Decks decks = createDecks(0, 0); - decks.getCard(""); - } - - @Test(expected = CardNotFoundException.class) - public void getCard_failsWhenDeckIsEmpty() { - Decks decks = createDecks(0, 0); - decks.getCard("Any name"); - } - - @Test(expected = CardNotFoundException.class) - public void getCard_failsWhenCardIsNotFound() { - Decks decks = createDecks(3, 20); - decks.getCard("Unknown name"); - } - - @Test - public void getCard_succeedsWhenCardIsFound() { - Decks decks = createDecks(3, 20); - Card card = decks.getCard("Test Card 3"); - assertEquals("Test Card 3", card.getName()); - } - - @Test(expected = IllegalArgumentException.class) - public void deal_failsOnZeroPlayers() { - Decks decks = createDecks(3, 20); - decks.deal(1, 0); - } - - @Test(expected = IllegalArgumentException.class) - public void deal_failsOnMissingAge() { - Decks decks = createDecks(2, 0); - decks.deal(4, 10); - } - - @Theory - public void deal_failsWhenTooFewPlayers(int nbPlayers, int nbCards) { - assumeTrue(nbCards % nbPlayers != 0); - thrown.expect(IllegalArgumentException.class); - Decks decks = createDecks(1, nbCards); - decks.deal(1, nbPlayers); - } - - @Theory - public void deal_succeedsOnZeroCards(int nbPlayers) { - Decks decks = createDecks(1, 0); - Hands hands = decks.deal(1, nbPlayers); - for (int i = 0; i < nbPlayers; i++) { - assertNotNull(hands.get(i)); - assertTrue(hands.get(i).isEmpty()); - } - } - - @Theory - public void deal_evenDistribution(int nbPlayers, int nbCardsPerPlayer) { - int nbCardsPerAge = nbPlayers * nbCardsPerPlayer; - Decks decks = createDecks(1, nbCardsPerAge); - Hands hands = decks.deal(1, nbPlayers); - for (int i = 0; i < nbPlayers; i++) { - assertEquals(nbCardsPerPlayer, hands.get(i).size()); - } - } -} diff --git a/game-engine/src/test/java/org/luxons/sevenwonders/game/cards/HandRotationDirectionTest.java b/game-engine/src/test/java/org/luxons/sevenwonders/game/cards/HandRotationDirectionTest.java deleted file mode 100644 index ddd69b70..00000000 --- a/game-engine/src/test/java/org/luxons/sevenwonders/game/cards/HandRotationDirectionTest.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.luxons.sevenwonders.game.cards; - -import org.junit.Test; - -import static org.junit.Assert.assertEquals; - -public class HandRotationDirectionTest { - - @Test - public void testAgesDirections() { - assertEquals(HandRotationDirection.LEFT, HandRotationDirection.forAge(1)); - assertEquals(HandRotationDirection.RIGHT, HandRotationDirection.forAge(2)); - assertEquals(HandRotationDirection.LEFT, HandRotationDirection.forAge(3)); - } -} diff --git a/game-engine/src/test/java/org/luxons/sevenwonders/game/cards/HandsTest.java b/game-engine/src/test/java/org/luxons/sevenwonders/game/cards/HandsTest.java deleted file mode 100644 index 463dafcc..00000000 --- a/game-engine/src/test/java/org/luxons/sevenwonders/game/cards/HandsTest.java +++ /dev/null @@ -1,143 +0,0 @@ -package org.luxons.sevenwonders.game.cards; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.junit.Test; -import org.junit.experimental.theories.DataPoints; -import org.junit.experimental.theories.FromDataPoints; -import org.junit.experimental.theories.Theories; -import org.junit.experimental.theories.Theory; -import org.junit.runner.RunWith; -import org.luxons.sevenwonders.game.api.HandCard; -import org.luxons.sevenwonders.game.api.Table; -import org.luxons.sevenwonders.game.cards.Hands.PlayerIndexOutOfBoundsException; -import org.luxons.sevenwonders.game.test.TestUtilsKt; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeTrue; - -@RunWith(Theories.class) -public class HandsTest { - - @DataPoints("nbCardsPerPlayer") - public static int[] nbCardsPerPlayer() { - return new int[] {0, 1, 2, 3, 4, 5, 6, 7}; - } - - @DataPoints("nbPlayers") - public static int[] nbPlayers() { - return new int[] {3, 4, 5, 6, 7}; - } - - private static Hands createHands(int nbPlayers, int nbCardsPerPlayer) { - Map> hands = new HashMap<>(); - for (int p = 0; p < nbPlayers; p++) { - int firstCardNumber = (p - 1) * nbCardsPerPlayer; - hands.put(p, TestUtilsKt.createSampleCards(firstCardNumber, nbCardsPerPlayer)); - } - return new Hands(hands, nbPlayers); - } - - @Test(expected = PlayerIndexOutOfBoundsException.class) - public void get_failsOnMissingPlayer() { - Hands hands = createHands(4, 7); - hands.get(5); - } - - @Test - public void get_retrievesCorrectCards() { - List hand0 = TestUtilsKt.createSampleCards(0, 5); - List hand1 = TestUtilsKt.createSampleCards(5, 10); - Map> handsMap = new HashMap<>(); - handsMap.put(0, hand0); - handsMap.put(1, hand1); - Hands hands = new Hands(handsMap, 2); - assertEquals(hand0, hands.get(0)); - assertEquals(hand1, hands.get(1)); - } - - @Theory - public void isEmpty_falseWhenAtLeast1_allSame(@FromDataPoints("nbPlayers") int nbPlayers, - @FromDataPoints("nbCardsPerPlayer") int nbCardsPerPlayer) { - assumeTrue(nbCardsPerPlayer >= 1); - Hands hands = createHands(nbPlayers, nbCardsPerPlayer); - assertFalse(hands.isEmpty()); - } - - @Theory - public void isEmpty_trueWhenAllEmpty(@FromDataPoints("nbPlayers") int nbPlayers) { - Hands hands = createHands(nbPlayers, 0); - assertTrue(hands.isEmpty()); - } - - @Theory - public void maxOneCardRemains_falseWhenAtLeast2_allSame(@FromDataPoints("nbPlayers") int nbPlayers, - @FromDataPoints("nbCardsPerPlayer") int nbCardsPerPlayer) { - assumeTrue(nbCardsPerPlayer >= 2); - Hands hands = createHands(nbPlayers, nbCardsPerPlayer); - assertFalse(hands.maxOneCardRemains()); - } - - @Theory - public void maxOneCardRemains_trueWhenAtMost1_allSame(@FromDataPoints("nbPlayers") int nbPlayers, - @FromDataPoints("nbCardsPerPlayer") int nbCardsPerPlayer) { - assumeTrue(nbCardsPerPlayer <= 1); - Hands hands = createHands(nbPlayers, nbCardsPerPlayer); - assertTrue(hands.maxOneCardRemains()); - } - - @Theory - public void maxOneCardRemains_trueWhenAtMost1_someZero(@FromDataPoints("nbPlayers") int nbPlayers) { - Hands hands = createHands(nbPlayers, 1); - hands.get(0).remove(0); - assertTrue(hands.maxOneCardRemains()); - } - - @Theory - public void gatherAndClear(@FromDataPoints("nbPlayers") int nbPlayers, - @FromDataPoints("nbCardsPerPlayer") int nbCardsPerPlayer) { - Hands hands = createHands(nbPlayers, nbCardsPerPlayer); - List remainingCards = hands.gatherAndClear(); - assertEquals(nbPlayers * nbCardsPerPlayer, remainingCards.size()); - assertTrue(hands.isEmpty()); - } - - @Test - public void rotate_movesOfCorrectOffset_right() { - Hands hands = createHands(3, 7); - Hands rotated = hands.rotate(HandRotationDirection.RIGHT); - assertEquals(rotated.get(1), hands.get(0)); - assertEquals(rotated.get(2), hands.get(1)); - assertEquals(rotated.get(0), hands.get(2)); - } - - @Test - public void rotate_movesOfCorrectOffset_left() { - Hands hands = createHands(3, 7); - Hands rotated = hands.rotate(HandRotationDirection.LEFT); - assertEquals(rotated.get(2), hands.get(0)); - assertEquals(rotated.get(0), hands.get(1)); - assertEquals(rotated.get(1), hands.get(2)); - } - - @Test - public void createHand_containsAllCards() { - List hand0 = TestUtilsKt.createSampleCards(0, 5); - List hand1 = TestUtilsKt.createSampleCards(5, 10); - Map> handsMap = new HashMap<>(); - handsMap.put(0, hand0); - handsMap.put(1, hand1); - Hands hands = new Hands(handsMap, 2); - - Table table = TestUtilsKt.testTable(2); - List hand = hands.createHand(table, 0); - - for (HandCard handCard : hand) { - assertTrue(hand0.contains(handCard.getCard())); - } - } -} diff --git a/game-engine/src/test/java/org/luxons/sevenwonders/game/cards/RequirementsTest.java b/game-engine/src/test/java/org/luxons/sevenwonders/game/cards/RequirementsTest.java deleted file mode 100644 index 6707dfab..00000000 --- a/game-engine/src/test/java/org/luxons/sevenwonders/game/cards/RequirementsTest.java +++ /dev/null @@ -1,145 +0,0 @@ -package org.luxons.sevenwonders.game.cards; - -import java.util.Arrays; -import java.util.Collections; - -import org.junit.Test; -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.api.Table; -import org.luxons.sevenwonders.game.boards.Board; -import org.luxons.sevenwonders.game.resources.Provider; -import org.luxons.sevenwonders.game.resources.ResourceTransactions; -import org.luxons.sevenwonders.game.resources.ResourceType; -import org.luxons.sevenwonders.game.resources.Resources; -import org.luxons.sevenwonders.game.test.TestUtilsKt; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeTrue; - -@RunWith(Theories.class) -public class RequirementsTest { - - @DataPoints - public static int[] goldAmounts() { - return new int[] {0, 1, 2, 5}; - } - - @DataPoints - public static ResourceType[] resourceTypes() { - return ResourceType.values(); - } - - @Test - public void getResources_emptyAfterInit() { - Requirements requirements = new Requirements(); - assertTrue(requirements.getResources().isEmpty()); - } - - @Test - public void setResources_success() { - Requirements requirements = new Requirements(); - Resources resources = new Resources(); - requirements.setResources(resources); - assertSame(resources, requirements.getResources()); - } - - @Theory - public void goldRequirement(int boardGold, int requiredGold) { - Requirements requirements = new Requirements(); - requirements.setGold(requiredGold); - - Board board = TestUtilsKt.testBoard(ResourceType.CLAY, boardGold); - Table table = new Table(Collections.singletonList(board)); - - assertEquals(boardGold >= requiredGold, requirements.areMetWithoutNeighboursBy(board)); - assertEquals(boardGold >= requiredGold, requirements.areMetWithHelpBy(board, new ResourceTransactions())); - assertEquals(boardGold >= requiredGold, requirements.areMetBy(table, 0)); - } - - @Theory - public void resourceRequirement_initialResource(ResourceType initialResource, ResourceType requiredResource) { - Requirements requirements = TestUtilsKt.createRequirements(requiredResource); - - Board board = TestUtilsKt.testBoard(initialResource, 0); - Table table = new Table(Collections.singletonList(board)); - - assertEquals(initialResource == requiredResource, requirements.areMetWithoutNeighboursBy(board)); - assertEquals(initialResource == requiredResource, - requirements.areMetWithHelpBy(board, new ResourceTransactions())); - - if (initialResource == requiredResource) { - assertTrue(requirements.areMetBy(table, 0)); - } - } - - @Theory - public void resourceRequirement_ownProduction(ResourceType initialResource, ResourceType producedResource, - ResourceType requiredResource) { - assumeTrue(initialResource != requiredResource); - - Requirements requirements = TestUtilsKt.createRequirements(requiredResource); - - Board board = TestUtilsKt.testBoard(initialResource, 0); - board.getProduction().addFixedResource(producedResource, 1); - Table table = new Table(Collections.singletonList(board)); - - assertEquals(producedResource == requiredResource, requirements.areMetWithoutNeighboursBy(board)); - assertEquals(producedResource == requiredResource, - requirements.areMetWithHelpBy(board, new ResourceTransactions())); - - if (producedResource == requiredResource) { - assertTrue(requirements.areMetBy(table, 0)); - } - } - - @Theory - public void resourceRequirement_boughtResource(ResourceType initialResource, ResourceType boughtResource, - ResourceType requiredResource) { - assumeTrue(initialResource != requiredResource); - - Requirements requirements = TestUtilsKt.createRequirements(requiredResource); - - Board board = TestUtilsKt.testBoard(initialResource, 2); - Board neighbourBoard = TestUtilsKt.testBoard(initialResource, 0); - neighbourBoard.getPublicProduction().addFixedResource(boughtResource, 1); - Table table = new Table(Arrays.asList(board, neighbourBoard)); - - ResourceTransactions resources = TestUtilsKt.createTransactions(Provider.RIGHT_PLAYER, boughtResource); - - assertFalse(requirements.areMetWithoutNeighboursBy(board)); - assertEquals(boughtResource == requiredResource, requirements.areMetWithHelpBy(board, resources)); - - if (boughtResource == requiredResource) { - assertTrue(requirements.areMetBy(table, 0)); - } - } - - @Theory - public void pay_boughtResource(ResourceType initialResource, ResourceType requiredResource) { - assumeTrue(initialResource != requiredResource); - - Requirements requirements = TestUtilsKt.createRequirements(requiredResource); - - Board board = TestUtilsKt.testBoard(initialResource, 2); - Board neighbourBoard = TestUtilsKt.testBoard(requiredResource, 0); - Table table = new Table(Arrays.asList(board, neighbourBoard)); - - ResourceTransactions transactions = TestUtilsKt.createTransactions(Provider.RIGHT_PLAYER, - requiredResource); - - assertFalse(requirements.areMetWithoutNeighboursBy(board)); - assertTrue(requirements.areMetWithHelpBy(board, transactions)); - assertTrue(requirements.areMetBy(table, 0)); - - requirements.pay(table, 0, transactions); - - assertEquals(0, board.getGold()); - assertEquals(2, neighbourBoard.getGold()); - } -} 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 index c58e1671..87e1d704 100644 --- 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 @@ -17,7 +17,7 @@ public class BuildWonderMoveTest { @Test(expected = InvalidMoveException.class) public void validate_failsWhenCardNotInHand() { Table table = TestUtilsKt.testTable(3); - List hand = TestUtilsKt.createSampleCards(0, 7); + List 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); @@ -28,7 +28,7 @@ public class BuildWonderMoveTest { public void validate_failsWhenWonderIsCompletelyBuilt() { Settings settings = TestUtilsKt.testSettings(3); Table table = TestUtilsKt.testTable(settings); - List hand = TestUtilsKt.createSampleCards(0, 7); + List hand = TestUtilsKt.sampleCards(0, 7); fillPlayerWonderLevels(settings, table, hand); @@ -59,7 +59,7 @@ public class BuildWonderMoveTest { public void place_increasesWonderLevel() { Settings settings = TestUtilsKt.testSettings(3); Table table = TestUtilsKt.testTable(settings); - List hand = TestUtilsKt.createSampleCards(0, 7); + List 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 diff --git a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/CardBackTest.kt b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/CardBackTest.kt new file mode 100644 index 00000000..68dcd5e7 --- /dev/null +++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/CardBackTest.kt @@ -0,0 +1,15 @@ +package org.luxons.sevenwonders.game.cards + +import org.junit.Test + +import org.junit.Assert.assertEquals + +class CardBackTest { + + @Test + fun initializedWithImage() { + val imagePath = "whateverimage.png" + val (image) = CardBack(imagePath) + assertEquals(imagePath, image) + } +} diff --git a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/CardTest.kt b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/CardTest.kt new file mode 100644 index 00000000..170ae1e4 --- /dev/null +++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/CardTest.kt @@ -0,0 +1,50 @@ +package org.luxons.sevenwonders.game.cards + +import org.junit.Assert.* +import org.junit.Before +import org.junit.Test +import org.luxons.sevenwonders.game.Settings +import org.luxons.sevenwonders.game.api.Table +import org.luxons.sevenwonders.game.boards.Board +import org.luxons.sevenwonders.game.effects.ProductionIncrease +import org.luxons.sevenwonders.game.resources.ResourceTransactions +import org.luxons.sevenwonders.game.resources.ResourceType +import org.luxons.sevenwonders.game.resources.Resources +import org.luxons.sevenwonders.game.test.testCard +import org.luxons.sevenwonders.game.wonders.Wonder + +class CardTest { + + private var table: Table? = null + + private var treeFarmCard: Card? = null + + @Before + fun initBoard() { + val settings = Settings(3) + + val boards = listOf( + Board(Wonder("TestWonder", ResourceType.WOOD), 0, settings), + Board(Wonder("TestWonder", ResourceType.STONE), 1, settings), + Board(Wonder("TestWonder", ResourceType.PAPYRUS), 2, settings) + ) + table = Table(boards) + + val treeFarmRequirements = Requirements(1) + val treeFarmEffect = ProductionIncrease() + treeFarmEffect.production.addChoice(ResourceType.WOOD, ResourceType.CLAY) + + treeFarmCard = testCard("Tree Farm", Color.BROWN, treeFarmEffect, treeFarmRequirements) + } + + @Test + fun playCardCostingMoney() { + table!!.getBoard(0).gold = 3 + table!!.getBoard(1).gold = 3 + table!!.getBoard(2).gold = 3 + treeFarmCard!!.applyTo(table!!, 0, ResourceTransactions()) + assertEquals(2, table!!.getBoard(0).gold.toLong()) + assertEquals(3, table!!.getBoard(1).gold.toLong()) + assertEquals(3, table!!.getBoard(2).gold.toLong()) + } +} diff --git a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/DecksTest.kt b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/DecksTest.kt new file mode 100644 index 00000000..673f8946 --- /dev/null +++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/DecksTest.kt @@ -0,0 +1,99 @@ +package org.luxons.sevenwonders.game.cards + +import org.junit.Assert.* +import org.junit.Assume.assumeTrue +import org.junit.Rule +import org.junit.Test +import org.junit.experimental.theories.DataPoints +import org.junit.experimental.theories.Theories +import org.junit.experimental.theories.Theory +import org.junit.rules.ExpectedException +import org.junit.runner.RunWith +import org.luxons.sevenwonders.game.cards.Decks.CardNotFoundException +import org.luxons.sevenwonders.game.test.sampleCards + +@RunWith(Theories::class) +class DecksTest { + + @JvmField + @Rule + val thrown: ExpectedException = ExpectedException.none() + + @Test(expected = IllegalArgumentException::class) + fun getCard_failsOnEmptyNameWhenDeckIsEmpty() { + val decks = createDecks(0, 0) + decks.getCard(0, "") + } + + @Test(expected = IllegalArgumentException::class) + fun getCard_failsWhenDeckIsEmpty() { + val decks = createDecks(0, 0) + decks.getCard(0, "Any name") + } + + @Test(expected = CardNotFoundException::class) + fun getCard_failsWhenCardIsNotFound() { + val decks = createDecks(3, 20) + decks.getCard(1, "Unknown name") + } + + @Test + fun getCard_succeedsWhenCardIsFound() { + val decks = createDecks(3, 20) + val (name) = decks.getCard(1, "Test Card 3") + assertEquals("Test Card 3", name) + } + + @Test(expected = IllegalArgumentException::class) + fun deal_failsOnZeroPlayers() { + val decks = createDecks(3, 20) + decks.deal(1, 0) + } + + @Test(expected = IllegalArgumentException::class) + fun deal_failsOnMissingAge() { + val decks = createDecks(2, 0) + decks.deal(4, 10) + } + + @Theory + fun deal_failsWhenTooFewPlayers(nbPlayers: Int, nbCards: Int) { + assumeTrue(nbCards % nbPlayers != 0) + thrown.expect(IllegalArgumentException::class.java) + val decks = createDecks(1, nbCards) + decks.deal(1, nbPlayers) + } + + @Theory + fun deal_succeedsOnZeroCards(nbPlayers: Int) { + val decks = createDecks(1, 0) + val hands = decks.deal(1, nbPlayers) + for (i in 0 until nbPlayers) { + assertNotNull(hands[i]) + assertTrue(hands[i].isEmpty()) + } + } + + @Theory + fun deal_evenDistribution(nbPlayers: Int, nbCardsPerPlayer: Int) { + val nbCardsPerAge = nbPlayers * nbCardsPerPlayer + val decks = createDecks(1, nbCardsPerAge) + val hands = decks.deal(1, nbPlayers) + for (i in 0 until nbPlayers) { + assertEquals(nbCardsPerPlayer.toLong(), hands[i].size.toLong()) + } + } + + companion object { + + @JvmStatic + @DataPoints + fun dataPoints(): IntArray { + return intArrayOf(1, 2, 3, 5, 10) + } + + private fun createDecks(nbAges: Int, nbCardsPerAge: Int): Decks { + return Decks(IntRange(1, nbAges).map { it to sampleCards(0, nbCardsPerAge) }.toMap()) + } + } +} diff --git a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/HandRotationDirectionTest.kt b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/HandRotationDirectionTest.kt new file mode 100644 index 00000000..d3a533ea --- /dev/null +++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/HandRotationDirectionTest.kt @@ -0,0 +1,15 @@ +package org.luxons.sevenwonders.game.cards + +import org.junit.Test + +import org.junit.Assert.assertEquals + +class HandRotationDirectionTest { + + @Test + fun testAgesDirections() { + assertEquals(HandRotationDirection.LEFT, HandRotationDirection.forAge(1)) + assertEquals(HandRotationDirection.RIGHT, HandRotationDirection.forAge(2)) + assertEquals(HandRotationDirection.LEFT, HandRotationDirection.forAge(3)) + } +} diff --git a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/HandsTest.kt b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/HandsTest.kt new file mode 100644 index 00000000..7ba21089 --- /dev/null +++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/HandsTest.kt @@ -0,0 +1,125 @@ +package org.luxons.sevenwonders.game.cards + +import org.junit.Assert.* +import org.junit.Assume.assumeTrue +import org.junit.Test +import org.junit.experimental.theories.DataPoints +import org.junit.experimental.theories.FromDataPoints +import org.junit.experimental.theories.Theories +import org.junit.experimental.theories.Theory +import org.junit.runner.RunWith +import org.luxons.sevenwonders.game.test.sampleCards +import org.luxons.sevenwonders.game.test.testTable + +@RunWith(Theories::class) +class HandsTest { + + @Test(expected = IndexOutOfBoundsException::class) + fun get_failsOnMissingPlayer() { + val hands = createHands(4, 7) + hands[5] + } + + @Test + fun get_retrievesCorrectCards() { + val hand0 = sampleCards(0, 5) + val hand1 = sampleCards(5, 10) + val hands = Hands(listOf(hand0, hand1)) + assertEquals(hand0, hands[0]) + assertEquals(hand1, hands[1]) + } + + @Theory + fun isEmpty_falseWhenAtLeast1_allSame( + @FromDataPoints("nbPlayers") nbPlayers: Int, + @FromDataPoints("nbCardsPerPlayer") nbCardsPerPlayer: Int + ) { + assumeTrue(nbCardsPerPlayer >= 1) + val hands = createHands(nbPlayers, nbCardsPerPlayer) + assertFalse(hands.isEmpty) + } + + @Theory + fun isEmpty_trueWhenAllEmpty(@FromDataPoints("nbPlayers") nbPlayers: Int) { + val hands = createHands(nbPlayers, 0) + assertTrue(hands.isEmpty) + } + + @Theory + fun maxOneCardRemains_falseWhenAtLeast2_allSame( + @FromDataPoints("nbPlayers") nbPlayers: Int, + @FromDataPoints("nbCardsPerPlayer") nbCardsPerPlayer: Int + ) { + assumeTrue(nbCardsPerPlayer >= 2) + val hands = createHands(nbPlayers, nbCardsPerPlayer) + assertFalse(hands.maxOneCardRemains()) + } + + @Theory + fun maxOneCardRemains_trueWhenAtMost1_allSame( + @FromDataPoints("nbPlayers") nbPlayers: Int, + @FromDataPoints("nbCardsPerPlayer") nbCardsPerPlayer: Int + ) { + assumeTrue(nbCardsPerPlayer <= 1) + val hands = createHands(nbPlayers, nbCardsPerPlayer) + assertTrue(hands.maxOneCardRemains()) + } + + @Theory + fun maxOneCardRemains_trueWhenAtMost1_someZero(@FromDataPoints("nbPlayers") nbPlayers: Int) { + val hands = createHands(nbPlayers, 1) + hands[0].drop(1) + assertTrue(hands.maxOneCardRemains()) + } + + @Test + fun rotate_movesOfCorrectOffset_right() { + val hands = createHands(3, 7) + val rotated = hands.rotate(HandRotationDirection.RIGHT) + assertEquals(rotated[1], hands[0]) + assertEquals(rotated[2], hands[1]) + assertEquals(rotated[0], hands[2]) + } + + @Test + fun rotate_movesOfCorrectOffset_left() { + val hands = createHands(3, 7) + val rotated = hands.rotate(HandRotationDirection.LEFT) + assertEquals(rotated[2], hands[0]) + assertEquals(rotated[0], hands[1]) + assertEquals(rotated[1], hands[2]) + } + + @Test + fun createHand_containsAllCards() { + val hand0 = sampleCards(0, 5) + val hand1 = sampleCards(5, 10) + val hands = Hands(listOf(hand0, hand1)) + + val table = testTable(2) + val hand = hands.createHand(table, 0) + + for (handCard in hand) { + assertTrue(hand0.contains(handCard.card)) + } + } + + companion object { + + @JvmStatic + @DataPoints("nbCardsPerPlayer") + fun nbCardsPerPlayer(): IntArray { + return intArrayOf(0, 1, 2, 3, 4, 5, 6, 7) + } + + @JvmStatic + @DataPoints("nbPlayers") + fun nbPlayers(): IntArray { + return intArrayOf(3, 4, 5, 6, 7) + } + + private fun createHands(nbPlayers: Int, nbCardsPerPlayer: Int): Hands { + return sampleCards(0, nbCardsPerPlayer * nbPlayers).deal(nbPlayers) + } + } +} diff --git a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/RequirementsTest.kt b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/RequirementsTest.kt new file mode 100644 index 00000000..196091a6 --- /dev/null +++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/RequirementsTest.kt @@ -0,0 +1,158 @@ +package org.luxons.sevenwonders.game.cards + +import java.util.Arrays +import java.util.Collections + +import org.junit.Test +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.api.Table +import org.luxons.sevenwonders.game.boards.Board +import org.luxons.sevenwonders.game.resources.Provider +import org.luxons.sevenwonders.game.resources.ResourceTransactions +import org.luxons.sevenwonders.game.resources.ResourceType +import org.luxons.sevenwonders.game.resources.Resources +import org.luxons.sevenwonders.game.test.* + +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertSame +import org.junit.Assert.assertTrue +import org.junit.Assume.assumeTrue + +@RunWith(Theories::class) +class RequirementsTest { + + @Test + fun getResources_emptyAfterInit() { + val (_, resources) = Requirements() + assertTrue(resources.isEmpty) + } + + @Test + fun setResources_success() { + val resources = Resources() + val (_, resources1) = Requirements(0, resources) + assertSame(resources, resources1) + } + + @Theory + fun goldRequirement(boardGold: Int, requiredGold: Int) { + val requirements = Requirements(requiredGold) + + val board = testBoard(ResourceType.CLAY, boardGold) + val table = Table(listOf(board)) + + assertEquals(boardGold >= requiredGold, requirements.areMetWithoutNeighboursBy(board)) + assertEquals(boardGold >= requiredGold, requirements.areMetWithHelpBy(board, ResourceTransactions())) + assertEquals(boardGold >= requiredGold, requirements.areMetBy(table, 0)) + } + + @Theory + fun resourceRequirement_initialResource(initialResource: ResourceType, requiredResource: ResourceType) { + val requirements = createRequirements(requiredResource) + + val board = testBoard(initialResource, 0) + val table = Table(listOf(board)) + + assertEquals(initialResource == requiredResource, requirements.areMetWithoutNeighboursBy(board)) + assertEquals( + initialResource == requiredResource, + requirements.areMetWithHelpBy(board, ResourceTransactions()) + ) + + if (initialResource == requiredResource) { + assertTrue(requirements.areMetBy(table, 0)) + } + } + + @Theory + fun resourceRequirement_ownProduction( + initialResource: ResourceType, producedResource: ResourceType, + requiredResource: ResourceType + ) { + assumeTrue(initialResource != requiredResource) + + val requirements = createRequirements(requiredResource) + + val board = testBoard(initialResource, 0) + board.production.addFixedResource(producedResource, 1) + val table = Table(listOf(board)) + + assertEquals(producedResource == requiredResource, requirements.areMetWithoutNeighboursBy(board)) + assertEquals( + producedResource == requiredResource, + requirements.areMetWithHelpBy(board, ResourceTransactions()) + ) + + if (producedResource == requiredResource) { + assertTrue(requirements.areMetBy(table, 0)) + } + } + + @Theory + fun resourceRequirement_boughtResource( + initialResource: ResourceType, boughtResource: ResourceType, + requiredResource: ResourceType + ) { + assumeTrue(initialResource != requiredResource) + + val requirements = createRequirements(requiredResource) + + val board = testBoard(initialResource, 2) + val neighbourBoard = testBoard(initialResource, 0) + neighbourBoard.publicProduction.addFixedResource(boughtResource, 1) + val table = Table(Arrays.asList(board, neighbourBoard)) + + val resources = createTransactions(Provider.RIGHT_PLAYER, boughtResource) + + assertFalse(requirements.areMetWithoutNeighboursBy(board)) + assertEquals(boughtResource == requiredResource, requirements.areMetWithHelpBy(board, resources)) + + if (boughtResource == requiredResource) { + assertTrue(requirements.areMetBy(table, 0)) + } + } + + @Theory + fun pay_boughtResource(initialResource: ResourceType, requiredResource: ResourceType) { + assumeTrue(initialResource != requiredResource) + + val requirements = createRequirements(requiredResource) + + val board = testBoard(initialResource, 2) + val neighbourBoard = testBoard(requiredResource, 0) + val table = Table(Arrays.asList(board, neighbourBoard)) + + val transactions = createTransactions( + Provider.RIGHT_PLAYER, + requiredResource + ) + + assertFalse(requirements.areMetWithoutNeighboursBy(board)) + assertTrue(requirements.areMetWithHelpBy(board, transactions)) + assertTrue(requirements.areMetBy(table, 0)) + + requirements.pay(table, 0, transactions) + + assertEquals(0, board.gold.toLong()) + assertEquals(2, neighbourBoard.gold.toLong()) + } + + companion object { + + @JvmStatic + @DataPoints + fun goldAmounts(): IntArray { + return intArrayOf(0, 1, 2, 5) + } + + @JvmStatic + @DataPoints + fun resourceTypes(): Array { + return ResourceType.values() + } + } +} diff --git a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/test/TestUtils.kt b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/test/TestUtils.kt index 65cf8d5b..85caa35f 100644 --- a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/test/TestUtils.kt +++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/test/TestUtils.kt @@ -115,17 +115,11 @@ fun createTransaction(provider: Provider, vararg resources: ResourceType): Resou fun createRequirements(vararg types: ResourceType): Requirements { val resources = createResources(*types) - val requirements = Requirements() - requirements.resources = resources - return requirements + return Requirements(resources = resources) } -fun createSampleCards(fromIndex: Int, nbCards: Int): List { - val sampleCards = ArrayList() - for (i in fromIndex until fromIndex + nbCards) { - sampleCards.add(testCard(i, Color.BLUE)) - } - return sampleCards +fun sampleCards(fromIndex: Int, nbCards: Int): List { + return List(nbCards) { i -> testCard(i + fromIndex, Color.BLUE) } } fun testCard(name: String): Card { @@ -148,14 +142,18 @@ fun createGuildCards(count: Int): List { return IntRange(0, count).map { createGuildCard(it) } } -fun createGuildCard(num: Int, vararg effects: Effect): Card { - return testCard("Test Guild $num", Color.PURPLE, *effects) +fun createGuildCard(num: Int, effect: Effect? = null): Card { + return testCard("Test Guild $num", Color.PURPLE, effect) } -private fun testCard(name: String, color: Color, vararg effects: Effect): Card { - val card = Card(name, color, Requirements(), Arrays.asList(*effects), null, null, "path/to/card/image") - card.back = createCardBack() - return card +fun testCard( + name: String = "Test Card", + color: Color = Color.BLUE, + effect: Effect? = null, + requirements: Requirements = Requirements() +): Card { + val effects = if (effect == null) emptyList() else listOf(effect) + return Card(name, color, requirements, effects, null, emptyList(), "path/to/card/image", createCardBack()) } private fun createCardBack(): CardBack { @@ -218,12 +216,3 @@ fun createMove(playerIndex: Int, card: Card, type: MoveType, vararg transactions val playerMove = PlayerMove(type, card.name, Arrays.asList(*transactions)) return type.resolve(playerIndex, card, playerMove) } - -@JvmOverloads -fun createPlayerMove( - type: MoveType, - cardName: String?, - transactions: Collection = emptySet() -): PlayerMove { - return PlayerMove(type, cardName, transactions) -} -- cgit