summaryrefslogtreecommitdiff
path: root/game-engine/src
diff options
context:
space:
mode:
Diffstat (limited to 'game-engine/src')
-rw-r--r--game-engine/src/main/java/org/luxons/sevenwonders/game/Game.java6
-rw-r--r--game-engine/src/main/java/org/luxons/sevenwonders/game/cards/Card.java128
-rw-r--r--game-engine/src/main/java/org/luxons/sevenwonders/game/cards/CardBack.java14
-rw-r--r--game-engine/src/main/java/org/luxons/sevenwonders/game/cards/Color.java11
-rw-r--r--game-engine/src/main/java/org/luxons/sevenwonders/game/cards/Decks.java65
-rw-r--r--game-engine/src/main/java/org/luxons/sevenwonders/game/cards/HandRotationDirection.java21
-rw-r--r--game-engine/src/main/java/org/luxons/sevenwonders/game/cards/Hands.java64
-rw-r--r--game-engine/src/main/java/org/luxons/sevenwonders/game/cards/Requirements.java108
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/HandCard.kt3
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/PlayerMove.kt4
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/Table.kt8
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Cards.kt52
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Decks.kt38
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/HandRotationDirection.kt15
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Hands.kt32
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/cards/Requirements.kt84
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/CardDefinition.kt10
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/DecksDefinition.kt7
-rw-r--r--game-engine/src/test/java/org/luxons/sevenwonders/game/GameTest.java26
-rw-r--r--game-engine/src/test/java/org/luxons/sevenwonders/game/cards/CardBackTest.java15
-rw-r--r--game-engine/src/test/java/org/luxons/sevenwonders/game/cards/CardTest.java110
-rw-r--r--game-engine/src/test/java/org/luxons/sevenwonders/game/cards/DecksTest.java112
-rw-r--r--game-engine/src/test/java/org/luxons/sevenwonders/game/cards/HandRotationDirectionTest.java15
-rw-r--r--game-engine/src/test/java/org/luxons/sevenwonders/game/cards/HandsTest.java143
-rw-r--r--game-engine/src/test/java/org/luxons/sevenwonders/game/cards/RequirementsTest.java145
-rw-r--r--game-engine/src/test/java/org/luxons/sevenwonders/game/moves/BuildWonderMoveTest.java6
-rw-r--r--game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/CardBackTest.kt15
-rw-r--r--game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/CardTest.kt50
-rw-r--r--game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/DecksTest.kt99
-rw-r--r--game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/HandRotationDirectionTest.kt15
-rw-r--r--game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/HandsTest.kt125
-rw-r--r--game-engine/src/test/kotlin/org/luxons/sevenwonders/game/cards/RequirementsTest.kt158
-rw-r--r--game-engine/src/test/kotlin/org/luxons/sevenwonders/game/test/TestUtils.kt37
33 files changed, 730 insertions, 1011 deletions
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<Card> 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<Effect> effects;
-
- private final String chainParent;
-
- private final List<String> chainChildren;
-
- private final String image;
-
- private CardBack back;
-
- public Card(String name, Color color, Requirements requirements, List<Effect> effects, String chainParent,
- List<String> 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<Effect> getEffects() {
- return effects;
- }
-
- public List<String> 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<Integer, List<Card>> cardsPerAge = new HashMap<>();
-
- public Decks(Map<Integer, List<Card>> 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<Card> deck = getDeck(age);
- validateNbCards(deck, nbPlayers);
- return deal(deck, nbPlayers);
- }
-
- private List<Card> getDeck(int age) {
- List<Card> deck = cardsPerAge.get(age);
- if (deck == null) {
- throw new IllegalArgumentException("No deck found for age " + age);
- }
- return deck;
- }
-
- private void validateNbCards(List<Card> 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<Card> deck, int nbPlayers) {
- Map<Integer, List<Card>> 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<Integer, List<Card>> hands;
-
- Hands(Map<Integer, List<Card>> hands, int nbPlayers) {
- this.hands = hands;
- this.nbPlayers = nbPlayers;
- }
-
- public List<Card> get(int playerIndex) {
- if (!hands.containsKey(playerIndex)) {
- throw new PlayerIndexOutOfBoundsException(playerIndex);
- }
- return hands.get(playerIndex);
- }
-
- public List<HandCard> 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<Integer, List<Card>> 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<Card> gatherAndClear() {
- List<Card> 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<ResourceTransaction> = 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<Board>) {
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<Effect>,
+ val chainParent: String?,
+ val chainChildren: List<String>,
+ 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<Card>.deal(nbPlayers: Int): Hands {
+ val hands: Map<Int, List<Card>> = 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<Int, List<Card>>) {
+
+ @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<Card> {
+ return cardsPerAge[age] ?: throw IllegalArgumentException("No deck found for age $age")
+ }
+
+ private fun validateNbCards(deck: List<Card>, 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<List<Card>>) {
+
+ val isEmpty: Boolean = this.hands.all(List<Card>::isEmpty)
+
+ operator fun get(playerIndex: Int): List<Card> {
+ 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<HandCard> {
+ 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<String> = emptyList(),
- private val image: String? = null,
+ private val image: String,
private val countPerNbPlayer: Map<Int, Int>
) {
- fun create(nbPlayers: Int): List<Card> = List( countPerNbPlayer[nbPlayers]!!) { create() }
+ fun create(back: CardBack, nbPlayers: Int): List<Card> = 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<CardDefinition>, settings: Settings, back: CardBack): List<Card> {
- 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<Card> {
- 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<Integer, PlayerMove> 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<ResourceTransaction> 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<ResourceTransaction> 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<Integer, PlayerMove> 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<Board> 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<Effect> 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<Integer, List<Card>> 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<Integer, List<Card>> 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<Card> hand0 = TestUtilsKt.createSampleCards(0, 5);
- List<Card> hand1 = TestUtilsKt.createSampleCards(5, 10);
- Map<Integer, List<Card>> 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<Card> 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<Card> hand0 = TestUtilsKt.createSampleCards(0, 5);
- List<Card> hand1 = TestUtilsKt.createSampleCards(5, 10);
- Map<Integer, List<Card>> handsMap = new HashMap<>();
- handsMap.put(0, hand0);
- handsMap.put(1, hand1);
- Hands hands = new Hands(handsMap, 2);
-
- Table table = TestUtilsKt.testTable(2);
- List<HandCard> 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<Card> hand = TestUtilsKt.createSampleCards(0, 7);
+ 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);
@@ -28,7 +28,7 @@ public class BuildWonderMoveTest {
public void validate_failsWhenWonderIsCompletelyBuilt() {
Settings settings = TestUtilsKt.testSettings(3);
Table table = TestUtilsKt.testTable(settings);
- List<Card> hand = TestUtilsKt.createSampleCards(0, 7);
+ List<Card> 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<Card> hand = TestUtilsKt.createSampleCards(0, 7);
+ 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
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<ResourceType> {
+ 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<Card> {
- val sampleCards = ArrayList<Card>()
- for (i in fromIndex until fromIndex + nbCards) {
- sampleCards.add(testCard(i, Color.BLUE))
- }
- return sampleCards
+fun sampleCards(fromIndex: Int, nbCards: Int): List<Card> {
+ return List(nbCards) { i -> testCard(i + fromIndex, Color.BLUE) }
}
fun testCard(name: String): Card {
@@ -148,14 +142,18 @@ fun createGuildCards(count: Int): List<Card> {
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<ResourceTransaction> = emptySet()
-): PlayerMove {
- return PlayerMove(type, cardName, transactions)
-}
bgstack15