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/boards/Board.java179
-rw-r--r--game-engine/src/main/java/org/luxons/sevenwonders/game/boards/BoardElementType.java28
-rw-r--r--game-engine/src/main/java/org/luxons/sevenwonders/game/boards/Military.java56
-rw-r--r--game-engine/src/main/java/org/luxons/sevenwonders/game/boards/RelativeBoardPosition.java28
-rw-r--r--game-engine/src/main/java/org/luxons/sevenwonders/game/boards/Science.java65
-rw-r--r--game-engine/src/main/java/org/luxons/sevenwonders/game/boards/ScienceType.java7
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/Table.kt3
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Board.kt99
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/BoardElementType.kt17
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Military.kt33
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/RelativeBoardPosition.kt25
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Science.kt56
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/GlobalRules.kt4
-rw-r--r--game-engine/src/test/java/org/luxons/sevenwonders/game/boards/BoardTest.java213
-rw-r--r--game-engine/src/test/java/org/luxons/sevenwonders/game/boards/MilitaryTest.java64
-rw-r--r--game-engine/src/test/java/org/luxons/sevenwonders/game/boards/RelativeBoardPositionTest.java44
-rw-r--r--game-engine/src/test/java/org/luxons/sevenwonders/game/boards/ScienceTest.java101
-rw-r--r--game-engine/src/test/kotlin/org/luxons/sevenwonders/game/api/TableTest.kt8
-rw-r--r--game-engine/src/test/kotlin/org/luxons/sevenwonders/game/boards/BoardTest.kt226
-rw-r--r--game-engine/src/test/kotlin/org/luxons/sevenwonders/game/boards/MilitaryTest.kt71
-rw-r--r--game-engine/src/test/kotlin/org/luxons/sevenwonders/game/boards/RelativeBoardPositionTest.kt48
-rw-r--r--game-engine/src/test/kotlin/org/luxons/sevenwonders/game/boards/ScienceTest.kt119
22 files changed, 703 insertions, 791 deletions
diff --git a/game-engine/src/main/java/org/luxons/sevenwonders/game/boards/Board.java b/game-engine/src/main/java/org/luxons/sevenwonders/game/boards/Board.java
deleted file mode 100644
index 23ce5da5..00000000
--- a/game-engine/src/main/java/org/luxons/sevenwonders/game/boards/Board.java
+++ /dev/null
@@ -1,179 +0,0 @@
-package org.luxons.sevenwonders.game.boards;
-
-import java.util.ArrayList;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.luxons.sevenwonders.game.Settings;
-import org.luxons.sevenwonders.game.api.Table;
-import org.luxons.sevenwonders.game.cards.Card;
-import org.luxons.sevenwonders.game.cards.Color;
-import org.luxons.sevenwonders.game.effects.SpecialAbility;
-import org.luxons.sevenwonders.game.resources.Production;
-import org.luxons.sevenwonders.game.resources.TradingRules;
-import org.luxons.sevenwonders.game.scoring.PlayerScore;
-import org.luxons.sevenwonders.game.scoring.ScoreCategory;
-import org.luxons.sevenwonders.game.wonders.Wonder;
-
-public class Board {
-
- private final Wonder wonder;
-
- private final int playerIndex;
-
- private final List<Card> playedCards = new ArrayList<>();
-
- private final Production production = new Production();
-
- private final Production publicProduction = new Production();
-
- private final Science science = new Science();
-
- private final TradingRules tradingRules;
-
- private final Military military;
-
- private final Set<SpecialAbility> specialAbilities = EnumSet.noneOf(SpecialAbility.class);
-
- private Map<Integer, Boolean> consumedFreeCards = new HashMap<>();
-
- private Card copiedGuild;
-
- private int gold;
-
- private int pointsPer3Gold;
-
- public Board(Wonder wonder, int playerIndex, Settings settings) {
- this.wonder = wonder;
- this.playerIndex = playerIndex;
- this.gold = settings.getInitialGold();
- this.tradingRules = new TradingRules(settings.getDefaultTradingCost());
- this.military = new Military(settings.getLostPointsPerDefeat(), settings.getWonPointsPerVictoryPerAge());
- this.pointsPer3Gold = settings.getPointsPer3Gold();
- this.production.addFixedResource(wonder.getInitialResource(), 1);
- this.publicProduction.addFixedResource(wonder.getInitialResource(), 1);
- }
-
- public int getPlayerIndex() {
- return playerIndex;
- }
-
- public Wonder getWonder() {
- return wonder;
- }
-
- public List<Card> getPlayedCards() {
- return playedCards;
- }
-
- public void addCard(Card card) {
- playedCards.add(card);
- }
-
- int getNbCardsOfColor(List<Color> colorFilter) {
- return (int) playedCards.stream().filter(c -> colorFilter.contains(c.getColor())).count();
- }
-
- public boolean isPlayed(String cardName) {
- return getPlayedCards().stream().map(Card::getName).filter(name -> name.equals(cardName)).count() > 0;
- }
-
- public Production getProduction() {
- return production;
- }
-
- public Production getPublicProduction() {
- return publicProduction;
- }
-
- public TradingRules getTradingRules() {
- return tradingRules;
- }
-
- public Science getScience() {
- return science;
- }
-
- public int getGold() {
- return gold;
- }
-
- public void setGold(int amount) {
- this.gold = amount;
- }
-
- public void addGold(int amount) {
- this.gold += amount;
- }
-
- public void removeGold(int amount) {
- if (gold < amount) {
- throw new InsufficientFundsException(gold, amount);
- }
- this.gold -= amount;
- }
-
- public Military getMilitary() {
- return military;
- }
-
- public void addSpecial(SpecialAbility specialAbility) {
- specialAbilities.add(specialAbility);
- }
-
- public boolean hasSpecial(SpecialAbility specialAbility) {
- return specialAbilities.contains(specialAbility);
- }
-
- public boolean canPlayFreeCard(int age) {
- return hasSpecial(SpecialAbility.ONE_FREE_PER_AGE) && !consumedFreeCards.getOrDefault(age, false);
- }
-
- public void consumeFreeCard(int age) {
- consumedFreeCards.put(age, true);
- }
-
- public void setCopiedGuild(Card copiedGuild) {
- if (copiedGuild.getColor() != Color.PURPLE) {
- throw new IllegalArgumentException("The given card '" + copiedGuild + "' is not a Guild card");
- }
- this.copiedGuild = copiedGuild;
- }
-
- public Card getCopiedGuild() {
- return copiedGuild;
- }
-
- public PlayerScore computePoints(Table table) {
- PlayerScore score = new PlayerScore(gold);
- score.put(ScoreCategory.CIVIL, computePointsForCards(table, Color.BLUE));
- score.put(ScoreCategory.MILITARY, military.getTotalPoints());
- score.put(ScoreCategory.SCIENCE, science.computePoints());
- score.put(ScoreCategory.TRADE, computePointsForCards(table, Color.YELLOW));
- score.put(ScoreCategory.GUILD, computePointsForCards(table, Color.PURPLE));
- score.put(ScoreCategory.WONDER, wonder.computePoints(table, playerIndex));
- score.put(ScoreCategory.GOLD, computeGoldPoints());
- return score;
- }
-
- private int computePointsForCards(Table table, Color color) {
- return playedCards.stream()
- .filter(c -> c.getColor() == color)
- .flatMap(c -> c.getEffects().stream())
- .mapToInt(e -> e.computePoints(table, playerIndex))
- .sum();
- }
-
- private int computeGoldPoints() {
- return gold / 3 * pointsPer3Gold;
- }
-
- static class InsufficientFundsException extends RuntimeException {
- InsufficientFundsException(int current, int required) {
- super(String.format("Current balance is %d gold, but %d are required", current, required));
- }
- }
-}
diff --git a/game-engine/src/main/java/org/luxons/sevenwonders/game/boards/BoardElementType.java b/game-engine/src/main/java/org/luxons/sevenwonders/game/boards/BoardElementType.java
deleted file mode 100644
index e50f4ea0..00000000
--- a/game-engine/src/main/java/org/luxons/sevenwonders/game/boards/BoardElementType.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package org.luxons.sevenwonders.game.boards;
-
-import java.util.List;
-
-import org.luxons.sevenwonders.game.cards.Color;
-
-public enum BoardElementType {
- CARD {
- @Override
- public int getElementCount(Board board, List<Color> colors) {
- return board.getNbCardsOfColor(colors);
- }
- },
- BUILT_WONDER_STAGES {
- @Override
- public int getElementCount(Board board, List<Color> colors) {
- return board.getWonder().getNbBuiltStages();
- }
- },
- DEFEAT_TOKEN {
- @Override
- public int getElementCount(Board board, List<Color> colors) {
- return board.getMilitary().getNbDefeatTokens();
- }
- };
-
- public abstract int getElementCount(Board board, List<Color> colors);
-}
diff --git a/game-engine/src/main/java/org/luxons/sevenwonders/game/boards/Military.java b/game-engine/src/main/java/org/luxons/sevenwonders/game/boards/Military.java
deleted file mode 100644
index e5cc7033..00000000
--- a/game-engine/src/main/java/org/luxons/sevenwonders/game/boards/Military.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package org.luxons.sevenwonders.game.boards;
-
-import java.util.Map;
-
-public class Military {
-
- private final int lostPointsPerDefeat;
-
- private final Map<Integer, Integer> wonPointsPerVictoryPerAge;
-
- private int nbShields = 0;
-
- private int totalPoints = 0;
-
- private int nbDefeatTokens = 0;
-
- Military(int lostPointsPerDefeat, Map<Integer, Integer> wonPointsPerVictoryPerAge) {
- this.lostPointsPerDefeat = lostPointsPerDefeat;
- this.wonPointsPerVictoryPerAge = wonPointsPerVictoryPerAge;
- }
-
- public int getNbShields() {
- return nbShields;
- }
-
- public void addShields(int nbShields) {
- this.nbShields += nbShields;
- }
-
- public int getTotalPoints() {
- return totalPoints;
- }
-
- public int getNbDefeatTokens() {
- return nbDefeatTokens;
- }
-
- public void victory(int age) {
- Integer wonPoints = wonPointsPerVictoryPerAge.get(age);
- if (wonPoints == null) {
- throw new UnknownAgeException(age);
- }
- totalPoints += wonPoints;
- }
-
- public void defeat() {
- totalPoints -= lostPointsPerDefeat;
- nbDefeatTokens++;
- }
-
- static final class UnknownAgeException extends IllegalArgumentException {
- UnknownAgeException(int unknownAge) {
- super(String.valueOf(unknownAge));
- }
- }
-}
diff --git a/game-engine/src/main/java/org/luxons/sevenwonders/game/boards/RelativeBoardPosition.java b/game-engine/src/main/java/org/luxons/sevenwonders/game/boards/RelativeBoardPosition.java
deleted file mode 100644
index 16b2f3a9..00000000
--- a/game-engine/src/main/java/org/luxons/sevenwonders/game/boards/RelativeBoardPosition.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package org.luxons.sevenwonders.game.boards;
-
-public enum RelativeBoardPosition {
- LEFT {
- @Override
- public int getIndexFrom(int playerIndex, int nbPlayers) {
- return wrapIndex(playerIndex - 1, nbPlayers);
- }
- },
- SELF {
- @Override
- public int getIndexFrom(int playerIndex, int nbPlayers) {
- return playerIndex;
- }
- },
- RIGHT {
- @Override
- public int getIndexFrom(int playerIndex, int nbPlayers) {
- return wrapIndex(playerIndex + 1, nbPlayers);
- }
- };
-
- public abstract int getIndexFrom(int playerIndex, int nbPlayers);
-
- int wrapIndex(int index, int nbPlayers) {
- return Math.floorMod(index, nbPlayers);
- }
-}
diff --git a/game-engine/src/main/java/org/luxons/sevenwonders/game/boards/Science.java b/game-engine/src/main/java/org/luxons/sevenwonders/game/boards/Science.java
deleted file mode 100644
index 34928bcc..00000000
--- a/game-engine/src/main/java/org/luxons/sevenwonders/game/boards/Science.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package org.luxons.sevenwonders.game.boards;
-
-import java.util.Arrays;
-import java.util.EnumMap;
-import java.util.Map;
-
-public class Science {
-
- private Map<ScienceType, Integer> quantities = new EnumMap<>(ScienceType.class);
-
- private int jokers;
-
- public void add(ScienceType type, int quantity) {
- quantities.merge(type, quantity, (x, y) -> x + y);
- }
-
- public void addJoker(int quantity) {
- jokers += quantity;
- }
-
- public int getJokers() {
- return jokers;
- }
-
- public void addAll(Science science) {
- science.quantities.forEach(this::add);
- jokers += science.jokers;
- }
-
- public int getQuantity(ScienceType type) {
- return quantities.getOrDefault(type, 0);
- }
-
- public int size() {
- return quantities.values().stream().mapToInt(q -> q).sum() + jokers;
- }
-
- public int computePoints() {
- ScienceType[] types = ScienceType.values();
- Integer[] values = new Integer[types.length];
- for (int i = 0; i < types.length; i++) {
- values[i] = quantities.getOrDefault(types[i], 0);
- }
- return computePoints(values, jokers);
- }
-
- private static int computePoints(Integer[] values, int jokers) {
- if (jokers == 0) {
- return computePointsNoJoker(values);
- }
- int maxPoints = 0;
- for (int i = 0; i < values.length; i++) {
- values[i]++;
- maxPoints = Math.max(maxPoints, computePoints(values, jokers - 1));
- values[i]--;
- }
- return maxPoints;
- }
-
- private static int computePointsNoJoker(Integer[] values) {
- int independentSquaresSum = Arrays.stream(values).mapToInt(i -> i * i).sum();
- int nbGroupsOfAll = Arrays.stream(values).mapToInt(i -> i).min().orElse(0);
- return independentSquaresSum + nbGroupsOfAll * 7;
- }
-}
diff --git a/game-engine/src/main/java/org/luxons/sevenwonders/game/boards/ScienceType.java b/game-engine/src/main/java/org/luxons/sevenwonders/game/boards/ScienceType.java
deleted file mode 100644
index f1b14c6d..00000000
--- a/game-engine/src/main/java/org/luxons/sevenwonders/game/boards/ScienceType.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package org.luxons.sevenwonders.game.boards;
-
-public enum ScienceType {
- COMPASS,
- WHEEL,
- TABLET
-}
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 60287c84..2c2e5066 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
@@ -5,6 +5,7 @@ import org.luxons.sevenwonders.game.boards.RelativeBoardPosition
import org.luxons.sevenwonders.game.cards.Card
import org.luxons.sevenwonders.game.cards.Color
import org.luxons.sevenwonders.game.cards.HandRotationDirection
+import org.luxons.sevenwonders.game.data.Age
import org.luxons.sevenwonders.game.moves.Move
import org.luxons.sevenwonders.game.resources.Provider
@@ -16,7 +17,7 @@ class Table(val boards: List<Board>) {
val nbPlayers: Int = boards.size
- var currentAge = 0
+ var currentAge: Age = 0
private set
val handRotationDirection: HandRotationDirection
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Board.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Board.kt
new file mode 100644
index 00000000..b02777e5
--- /dev/null
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Board.kt
@@ -0,0 +1,99 @@
+package org.luxons.sevenwonders.game.boards
+
+import org.luxons.sevenwonders.game.Settings
+import org.luxons.sevenwonders.game.api.Table
+import org.luxons.sevenwonders.game.cards.Card
+import org.luxons.sevenwonders.game.cards.Color
+import org.luxons.sevenwonders.game.data.Age
+import org.luxons.sevenwonders.game.effects.SpecialAbility
+import org.luxons.sevenwonders.game.resources.Production
+import org.luxons.sevenwonders.game.resources.TradingRules
+import org.luxons.sevenwonders.game.scoring.PlayerScore
+import org.luxons.sevenwonders.game.scoring.ScoreCategory
+import org.luxons.sevenwonders.game.wonders.Wonder
+
+class Board(val wonder: Wonder, val playerIndex: Int, settings: Settings) {
+
+ val production = Production()
+ val publicProduction = Production()
+ val science = Science()
+ val tradingRules: TradingRules = TradingRules(settings.defaultTradingCost)
+ val military: Military = Military(settings.lostPointsPerDefeat, settings.wonPointsPerVictoryPerAge)
+ private val pointsPer3Gold: Int = settings.pointsPer3Gold
+
+ private val playedCards: MutableList<Card> = arrayListOf()
+ private val specialAbilities: MutableSet<SpecialAbility> = hashSetOf()
+ private val consumedFreeCards: MutableMap<Age, Boolean> = mutableMapOf()
+
+ var gold: Int = settings.initialGold
+
+ var copiedGuild: Card? = null
+ set(copiedGuild) {
+ if (copiedGuild!!.color !== Color.PURPLE) {
+ throw IllegalArgumentException("The given card '$copiedGuild' is not a Guild card")
+ }
+ field = copiedGuild
+ }
+
+ init {
+ this.production.addFixedResource(wonder.initialResource, 1)
+ this.publicProduction.addFixedResource(wonder.initialResource, 1)
+ }
+
+ fun getPlayedCards(): List<Card> = playedCards
+
+ fun addCard(card: Card) {
+ playedCards.add(card)
+ }
+
+ internal fun getNbCardsOfColor(colorFilter: List<Color>): Int = playedCards.count { colorFilter.contains(it.color) }
+
+ fun isPlayed(cardName: String): Boolean = playedCards.count { it.name == cardName } > 0
+
+ fun addGold(amount: Int) {
+ this.gold += amount
+ }
+
+ fun removeGold(amount: Int) {
+ if (gold < amount) {
+ throw InsufficientFundsException(gold, amount)
+ }
+ this.gold -= amount
+ }
+
+ fun addSpecial(specialAbility: SpecialAbility) {
+ specialAbilities.add(specialAbility)
+ }
+
+ fun hasSpecial(specialAbility: SpecialAbility): Boolean = specialAbilities.contains(specialAbility)
+
+ fun canPlayFreeCard(age: Age): Boolean =
+ hasSpecial(SpecialAbility.ONE_FREE_PER_AGE) && !consumedFreeCards.getOrDefault(age, false)
+
+ fun consumeFreeCard(age: Age) {
+ consumedFreeCards[age] = true
+ }
+
+ fun computePoints(table: Table): PlayerScore {
+ val score = PlayerScore(gold)
+ score.put(ScoreCategory.CIVIL, computePointsForCards(table, Color.BLUE))
+ score.put(ScoreCategory.MILITARY, military.totalPoints)
+ score.put(ScoreCategory.SCIENCE, science.computePoints())
+ score.put(ScoreCategory.TRADE, computePointsForCards(table, Color.YELLOW))
+ score.put(ScoreCategory.GUILD, computePointsForCards(table, Color.PURPLE))
+ score.put(ScoreCategory.WONDER, wonder.computePoints(table, playerIndex))
+ score.put(ScoreCategory.GOLD, computeGoldPoints())
+ return score
+ }
+
+ private fun computePointsForCards(table: Table, color: Color): Int = playedCards
+ .filter { (_, color1) -> color1 === color }
+ .flatMap { (_, _, _, effects) -> effects }
+ .map { e -> e.computePoints(table, playerIndex) }
+ .sum()
+
+ private fun computeGoldPoints(): Int = gold / 3 * pointsPer3Gold
+
+ internal class InsufficientFundsException(current: Int, required: Int) :
+ RuntimeException(String.format("Current balance is %d gold, but %d are required", current, required))
+}
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/BoardElementType.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/BoardElementType.kt
new file mode 100644
index 00000000..d35e9777
--- /dev/null
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/BoardElementType.kt
@@ -0,0 +1,17 @@
+package org.luxons.sevenwonders.game.boards
+
+import org.luxons.sevenwonders.game.cards.Color
+
+enum class BoardElementType {
+ CARD {
+ override fun getElementCount(board: Board, colors: List<Color>?): Int = board.getNbCardsOfColor(colors!!)
+ },
+ BUILT_WONDER_STAGES {
+ override fun getElementCount(board: Board, colors: List<Color>?): Int = board.wonder.nbBuiltStages
+ },
+ DEFEAT_TOKEN {
+ override fun getElementCount(board: Board, colors: List<Color>?): Int = board.military.nbDefeatTokens
+ };
+
+ abstract fun getElementCount(board: Board, colors: List<Color>?): Int
+}
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Military.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Military.kt
new file mode 100644
index 00000000..c00d1ace
--- /dev/null
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Military.kt
@@ -0,0 +1,33 @@
+package org.luxons.sevenwonders.game.boards
+
+import org.luxons.sevenwonders.game.data.Age
+
+class Military internal constructor(
+ private val lostPointsPerDefeat: Int,
+ private val wonPointsPerVictoryPerAge: Map<Age, Int>
+) {
+ var nbShields = 0
+ private set
+
+ var totalPoints = 0
+ private set
+
+ var nbDefeatTokens = 0
+ private set
+
+ fun addShields(nbShields: Int) {
+ this.nbShields += nbShields
+ }
+
+ fun victory(age: Age) {
+ val wonPoints = wonPointsPerVictoryPerAge[age] ?: throw UnknownAgeException(age)
+ totalPoints += wonPoints
+ }
+
+ fun defeat() {
+ totalPoints -= lostPointsPerDefeat
+ nbDefeatTokens++
+ }
+
+ internal class UnknownAgeException(unknownAge: Age) : IllegalArgumentException(unknownAge.toString())
+}
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/RelativeBoardPosition.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/RelativeBoardPosition.kt
new file mode 100644
index 00000000..fcd629ec
--- /dev/null
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/RelativeBoardPosition.kt
@@ -0,0 +1,25 @@
+package org.luxons.sevenwonders.game.boards
+
+enum class RelativeBoardPosition {
+ LEFT {
+ override fun getIndexFrom(playerIndex: Int, nbPlayers: Int): Int {
+ return wrapIndex(playerIndex - 1, nbPlayers)
+ }
+ },
+ SELF {
+ override fun getIndexFrom(playerIndex: Int, nbPlayers: Int): Int {
+ return playerIndex
+ }
+ },
+ RIGHT {
+ override fun getIndexFrom(playerIndex: Int, nbPlayers: Int): Int {
+ return wrapIndex(playerIndex + 1, nbPlayers)
+ }
+ };
+
+ abstract fun getIndexFrom(playerIndex: Int, nbPlayers: Int): Int
+
+ internal fun wrapIndex(index: Int, nbPlayers: Int): Int {
+ return Math.floorMod(index, nbPlayers)
+ }
+}
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Science.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Science.kt
new file mode 100644
index 00000000..839986e0
--- /dev/null
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Science.kt
@@ -0,0 +1,56 @@
+package org.luxons.sevenwonders.game.boards
+
+enum class ScienceType {
+ COMPASS,
+ WHEEL,
+ TABLET
+}
+
+class Science {
+
+ private val quantities : MutableMap<ScienceType, Int> = mutableMapOf()
+
+ var jokers: Int = 0
+ private set
+
+ fun size(): Int = quantities.values.sum() + jokers
+
+ fun add(type: ScienceType, quantity: Int) {
+ quantities.merge(type, quantity) { x, y -> x + y }
+ }
+
+ fun addJoker(quantity: Int) {
+ jokers += quantity
+ }
+
+ fun addAll(science: Science) {
+ science.quantities.forEach { type, quantity -> this.add(type, quantity) }
+ jokers += science.jokers
+ }
+
+ fun getQuantity(type: ScienceType): Int = quantities.getOrDefault(type, 0)
+
+ fun computePoints(): Int {
+ val values = ScienceType.values().map(::getQuantity).toMutableList()
+ return computePoints(values, jokers)
+ }
+
+ private fun computePoints(values: MutableList<Int>, jokers: Int): Int {
+ if (jokers == 0) {
+ return computePointsNoJoker(values)
+ }
+ var maxPoints = 0
+ for (i in values.indices) {
+ values[i]++
+ maxPoints = Math.max(maxPoints, computePoints(values, jokers - 1))
+ values[i]--
+ }
+ return maxPoints
+ }
+
+ private fun computePointsNoJoker(values: List<Int>): Int {
+ val independentSquaresSum = values.map { i -> i * i }.sum()
+ val nbGroupsOfAll = values.min() ?: 0
+ return independentSquaresSum + nbGroupsOfAll * 7
+ }
+}
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/GlobalRules.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/GlobalRules.kt
index 49212ab2..a590efc9 100644
--- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/GlobalRules.kt
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/GlobalRules.kt
@@ -1,6 +1,8 @@
package org.luxons.sevenwonders.game.data
-const val LAST_AGE: Int = 3
+typealias Age = Int
+
+const val LAST_AGE: Age = 3
internal data class GlobalRules(
val minPlayers: Int,
diff --git a/game-engine/src/test/java/org/luxons/sevenwonders/game/boards/BoardTest.java b/game-engine/src/test/java/org/luxons/sevenwonders/game/boards/BoardTest.java
deleted file mode 100644
index 4b373fa2..00000000
--- a/game-engine/src/test/java/org/luxons/sevenwonders/game/boards/BoardTest.java
+++ /dev/null
@@ -1,213 +0,0 @@
-package org.luxons.sevenwonders.game.boards;
-
-import java.util.Arrays;
-import java.util.Collections;
-
-import org.junit.Rule;
-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.rules.ExpectedException;
-import org.junit.runner.RunWith;
-import org.luxons.sevenwonders.game.Settings;
-import org.luxons.sevenwonders.game.api.CustomizableSettings;
-import org.luxons.sevenwonders.game.api.Table;
-import org.luxons.sevenwonders.game.boards.Board.InsufficientFundsException;
-import org.luxons.sevenwonders.game.cards.Card;
-import org.luxons.sevenwonders.game.cards.Color;
-import org.luxons.sevenwonders.game.effects.Effect;
-import org.luxons.sevenwonders.game.effects.RawPointsIncrease;
-import org.luxons.sevenwonders.game.effects.SpecialAbility;
-import org.luxons.sevenwonders.game.effects.SpecialAbilityActivation;
-import org.luxons.sevenwonders.game.resources.ResourceType;
-import org.luxons.sevenwonders.game.resources.Resources;
-import org.luxons.sevenwonders.game.scoring.PlayerScore;
-import org.luxons.sevenwonders.game.scoring.ScoreCategory;
-import org.luxons.sevenwonders.game.test.TestUtilsKt;
-
-import static junit.framework.TestCase.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 BoardTest {
-
- @Rule
- public ExpectedException thrown = ExpectedException.none();
-
- @DataPoints("gold")
- public static int[] goldAmounts() {
- return new int[]{-3, -1, 0, 1, 2, 3};
- }
-
- @DataPoints("nbCards")
- public static int[] nbCards() {
- return new int[]{0, 1, 2};
- }
-
- @DataPoints
- public static ResourceType[] resourceTypes() {
- return ResourceType.values();
- }
-
- @DataPoints
- public static Color[] colors() {
- return Color.values();
- }
-
- @DataPoints
- public static SpecialAbility[] specialAbilities() {
- return SpecialAbility.values();
- }
-
- @Theory
- public void initialGold_respectsSettings(@FromDataPoints("gold") int goldAmountInSettings) {
- CustomizableSettings customSettings = TestUtilsKt.testCustomizableSettings(goldAmountInSettings);
- Settings settings = new Settings(5, customSettings);
- Board board = new Board(TestUtilsKt.testWonder(), 0, settings);
- assertEquals(goldAmountInSettings, board.getGold());
- }
-
- @Theory
- public void initialProduction_containsInitialResource(ResourceType type) {
- Board board = new Board(TestUtilsKt.testWonder(type), 0, new Settings(5));
- Resources resources = TestUtilsKt.createResources(type);
- assertTrue(board.getProduction().contains(resources));
- assertTrue(board.getPublicProduction().contains(resources));
- }
-
- @Theory
- public void removeGold_successfulWhenNotTooMuch(@FromDataPoints("gold") int initialGold,
- @FromDataPoints("gold") int goldRemoved) {
- assumeTrue(goldRemoved >= 0);
- assumeTrue(initialGold >= goldRemoved);
- Board board = new Board(TestUtilsKt.testWonder(), 0, new Settings(5));
- board.setGold(initialGold);
- board.removeGold(goldRemoved);
- assertEquals(initialGold - goldRemoved, board.getGold());
- }
-
- @Theory
- public void removeGold_failsWhenTooMuch(@FromDataPoints("gold") int initialGold,
- @FromDataPoints("gold") int goldRemoved) {
- assumeTrue(goldRemoved >= 0);
- assumeTrue(initialGold < goldRemoved);
- thrown.expect(InsufficientFundsException.class);
- Board board = new Board(TestUtilsKt.testWonder(), 0, new Settings(5));
- board.setGold(initialGold);
- board.removeGold(goldRemoved);
- }
-
- @Theory
- public void getNbCardsOfColor_properCount_singleColor(ResourceType type, @FromDataPoints("nbCards") int nbCards,
- @FromDataPoints("nbCards") int nbOtherCards, Color color) {
- Board board = TestUtilsKt.testBoard(type);
- TestUtilsKt.addCards(board, nbCards, nbOtherCards, color);
- assertEquals(nbCards, board.getNbCardsOfColor(Collections.singletonList(color)));
- }
-
- @Theory
- public void getNbCardsOfColor_properCount_multiColors(ResourceType type, @FromDataPoints("nbCards") int nbCards1,
- @FromDataPoints("nbCards") int nbCards2,
- @FromDataPoints("nbCards") int nbOtherCards, Color color1,
- Color color2) {
- Board board = TestUtilsKt.testBoard(type);
- TestUtilsKt.addCards(board, nbCards1, color1);
- TestUtilsKt.addCards(board, nbCards2, color2);
- TestUtilsKt.addCards(board, nbOtherCards, TestUtilsKt.getDifferentColorFrom(color1, color2));
- assertEquals(nbCards1 + nbCards2, board.getNbCardsOfColor(Arrays.asList(color1, color2)));
- }
-
- @Test
- public void setCopiedGuild_succeedsOnPurpleCard() {
- Board board = TestUtilsKt.testBoard(ResourceType.CLAY);
- Card card = TestUtilsKt.testCard(Color.PURPLE);
-
- board.setCopiedGuild(card);
- assertSame(card, board.getCopiedGuild());
- }
-
- @Theory
- public void setCopiedGuild_failsOnNonPurpleCard(Color color) {
- assumeTrue(color != Color.PURPLE);
- Board board = TestUtilsKt.testBoard(ResourceType.CLAY);
- Card card = TestUtilsKt.testCard(color);
-
- thrown.expect(IllegalArgumentException.class);
- board.setCopiedGuild(card);
- }
-
- @Theory
- public void hasSpecial(SpecialAbility applied, SpecialAbility tested) {
- Board board = TestUtilsKt.testBoard(ResourceType.CLAY);
- Table table = new Table(Collections.singletonList(board));
- SpecialAbilityActivation special = new SpecialAbilityActivation(applied);
-
- special.apply(table, 0);
-
- assertEquals(applied == tested, board.hasSpecial(tested));
- }
-
- @Test
- public void canPlayFreeCard() {
- Board board = TestUtilsKt.testBoard(ResourceType.CLAY);
- Table table = new Table(Collections.singletonList(board));
- SpecialAbilityActivation special = new SpecialAbilityActivation(SpecialAbility.ONE_FREE_PER_AGE);
-
- special.apply(table, 0);
-
- assertTrue(board.canPlayFreeCard(0));
- assertTrue(board.canPlayFreeCard(1));
- assertTrue(board.canPlayFreeCard(2));
-
- board.consumeFreeCard(0);
-
- assertFalse(board.canPlayFreeCard(0));
- assertTrue(board.canPlayFreeCard(1));
- assertTrue(board.canPlayFreeCard(2));
-
- board.consumeFreeCard(1);
-
- assertFalse(board.canPlayFreeCard(0));
- assertFalse(board.canPlayFreeCard(1));
- assertTrue(board.canPlayFreeCard(2));
-
- board.consumeFreeCard(2);
-
- assertFalse(board.canPlayFreeCard(0));
- assertFalse(board.canPlayFreeCard(1));
- assertFalse(board.canPlayFreeCard(2));
- }
-
- @Theory
- public void computePoints_gold(@FromDataPoints("gold") int gold) {
- assumeTrue(gold >= 0);
- Board board = TestUtilsKt.testBoard(ResourceType.WOOD);
- Table table = new Table(Collections.singletonList(board));
- board.setGold(gold);
-
- PlayerScore score = board.computePoints(table);
- assertEquals(gold / 3, (int) score.getPoints(ScoreCategory.GOLD));
- assertEquals(gold / 3, score.getTotalPoints());
- }
-
- @Theory
- public void computePoints_(@FromDataPoints("gold") int gold) {
- assumeTrue(gold >= 0);
- Board board = TestUtilsKt.testBoard(ResourceType.WOOD);
- Table table = new Table(Collections.singletonList(board));
- board.setGold(gold);
-
- Effect effect = new RawPointsIncrease(5);
- TestUtilsKt.playCardWithEffect(table, 0, Color.BLUE, effect);
-
- PlayerScore score = board.computePoints(table);
- assertEquals(gold / 3, (int) score.getPoints(ScoreCategory.GOLD));
- assertEquals(5, (int) score.getPoints(ScoreCategory.CIVIL));
- assertEquals(5 + gold / 3, score.getTotalPoints());
- }
-}
diff --git a/game-engine/src/test/java/org/luxons/sevenwonders/game/boards/MilitaryTest.java b/game-engine/src/test/java/org/luxons/sevenwonders/game/boards/MilitaryTest.java
deleted file mode 100644
index b391c6b0..00000000
--- a/game-engine/src/test/java/org/luxons/sevenwonders/game/boards/MilitaryTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package org.luxons.sevenwonders.game.boards;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.junit.Rule;
-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.rules.ExpectedException;
-import org.junit.runner.RunWith;
-import org.luxons.sevenwonders.game.boards.Military.UnknownAgeException;
-
-import static org.junit.Assert.assertEquals;
-
-@RunWith(Theories.class)
-public class MilitaryTest {
-
- @Rule
- public ExpectedException thrown = ExpectedException.none();
-
- @DataPoints("points")
- public static int[] points() {
- return new int[] {0, 1, 3, 5};
- }
-
- @DataPoints("ages")
- public static int[] ages() {
- return new int[] {1, 2, 3};
- }
-
- private static Military createMilitary(int age, int nbPointsPerVictory, int nbPointsPerDefeat) {
- Map<Integer, Integer> wonPointsPerAge = new HashMap<>();
- wonPointsPerAge.put(age, nbPointsPerVictory);
- return new Military(nbPointsPerDefeat, wonPointsPerAge);
- }
-
- @Theory
- public void victory_addsCorrectPoints(@FromDataPoints("ages") int age,
- @FromDataPoints("points") int nbPointsPerVictory) {
- Military military = createMilitary(age, nbPointsPerVictory, 0);
- int initialPoints = military.getTotalPoints();
-
- military.victory(age);
- assertEquals(initialPoints + nbPointsPerVictory, military.getTotalPoints());
- }
-
- @Theory
- public void victory_failsIfUnknownAge(@FromDataPoints("points") int nbPointsPerVictory) {
- Military military = createMilitary(0, nbPointsPerVictory, 0);
- thrown.expect(UnknownAgeException.class);
- military.victory(1);
- }
-
- @Theory
- public void defeat_removesCorrectPoints(@FromDataPoints("points") int nbPointsLostPerDefeat) {
- Military military = createMilitary(0, 0, nbPointsLostPerDefeat);
- int initialPoints = military.getTotalPoints();
-
- military.defeat();
- assertEquals(initialPoints - nbPointsLostPerDefeat, military.getTotalPoints());
- }
-}
diff --git a/game-engine/src/test/java/org/luxons/sevenwonders/game/boards/RelativeBoardPositionTest.java b/game-engine/src/test/java/org/luxons/sevenwonders/game/boards/RelativeBoardPositionTest.java
deleted file mode 100644
index 9f60e572..00000000
--- a/game-engine/src/test/java/org/luxons/sevenwonders/game/boards/RelativeBoardPositionTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package org.luxons.sevenwonders.game.boards;
-
-import org.junit.experimental.theories.DataPoints;
-import org.junit.experimental.theories.Theories;
-import org.junit.experimental.theories.Theory;
-import org.junit.runner.RunWith;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assume.assumeTrue;
-
-@RunWith(Theories.class)
-public class RelativeBoardPositionTest {
-
- @DataPoints
- public static int[] nbPlayers() {
- return new int[] {1, 2, 3, 5, 7, 9};
- }
-
- @Theory
- public void getIndexFrom_wrapLeft(int nbPlayers) {
- assumeTrue(nbPlayers >= 2);
- int last = nbPlayers - 1;
- assertEquals(last, RelativeBoardPosition.LEFT.getIndexFrom(0, nbPlayers));
- assertEquals(0, RelativeBoardPosition.SELF.getIndexFrom(0, nbPlayers));
- assertEquals(1, RelativeBoardPosition.RIGHT.getIndexFrom(0, nbPlayers));
- }
-
- @Theory
- public void getIndexFrom_wrapRight(int nbPlayers) {
- assumeTrue(nbPlayers >= 2);
- int last = nbPlayers - 1;
- assertEquals(last - 1, RelativeBoardPosition.LEFT.getIndexFrom(last, nbPlayers));
- assertEquals(last, RelativeBoardPosition.SELF.getIndexFrom(last, nbPlayers));
- assertEquals(0, RelativeBoardPosition.RIGHT.getIndexFrom(last, nbPlayers));
- }
-
- @Theory
- public void getIndexFrom_noWrap(int nbPlayers) {
- assumeTrue(nbPlayers >= 3);
- assertEquals(0, RelativeBoardPosition.LEFT.getIndexFrom(1, nbPlayers));
- assertEquals(1, RelativeBoardPosition.SELF.getIndexFrom(1, nbPlayers));
- assertEquals(2, RelativeBoardPosition.RIGHT.getIndexFrom(1, nbPlayers));
- }
-}
diff --git a/game-engine/src/test/java/org/luxons/sevenwonders/game/boards/ScienceTest.java b/game-engine/src/test/java/org/luxons/sevenwonders/game/boards/ScienceTest.java
deleted file mode 100644
index b31da03b..00000000
--- a/game-engine/src/test/java/org/luxons/sevenwonders/game/boards/ScienceTest.java
+++ /dev/null
@@ -1,101 +0,0 @@
-package org.luxons.sevenwonders.game.boards;
-
-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.test.TestUtilsKt;
-
-import static org.junit.Assert.assertEquals;
-
-@RunWith(Theories.class)
-public class ScienceTest {
-
- @DataPoints
- public static int[][] quantitiesWithExpectedPoints() {
- // compasses, wheels, tablets, jokers, expected points
- return new int[][] {{0, 0, 0, 1, 1}, {0, 0, 1, 0, 1}, {0, 0, 0, 2, 4}, {0, 0, 1, 1, 4}, {0, 0, 2, 0, 4},
- {0, 0, 0, 3, 10}, {0, 0, 1, 2, 10}, {0, 1, 1, 1, 10}, {1, 1, 1, 0, 10}, {0, 0, 0, 4, 16},
- {0, 0, 1, 3, 16}, {0, 0, 2, 2, 16}, {0, 0, 3, 1, 16}, {0, 0, 4, 0, 16}};
- }
-
- @DataPoints
- public static int[] quantitiesDataPoints() {
- return new int[] {0, 1, 3, 5, 8};
- }
-
- @Test
- public void addAll_empty() {
- Science initial = TestUtilsKt.createScience(3, 4, 5, 1);
- Science empty = new Science();
- initial.addAll(empty);
- assertEquals(3, initial.getQuantity(ScienceType.COMPASS));
- assertEquals(4, initial.getQuantity(ScienceType.WHEEL));
- assertEquals(5, initial.getQuantity(ScienceType.TABLET));
- assertEquals(1, initial.getJokers());
- }
-
- @Test
- public void addAll_noJoker() {
- Science initial = TestUtilsKt.createScience(3, 4, 5, 1);
- Science other = TestUtilsKt.createScience(1, 2, 3, 0);
- initial.addAll(other);
- assertEquals(4, initial.getQuantity(ScienceType.COMPASS));
- assertEquals(6, initial.getQuantity(ScienceType.WHEEL));
- assertEquals(8, initial.getQuantity(ScienceType.TABLET));
- assertEquals(1, initial.getJokers());
- }
-
- @Test
- public void addAll_withJokers() {
- Science initial = TestUtilsKt.createScience(3, 4, 5, 1);
- Science other = TestUtilsKt.createScience(0, 0, 0, 3);
- initial.addAll(other);
- assertEquals(3, initial.getQuantity(ScienceType.COMPASS));
- assertEquals(4, initial.getQuantity(ScienceType.WHEEL));
- assertEquals(5, initial.getQuantity(ScienceType.TABLET));
- assertEquals(4, initial.getJokers());
- }
-
- @Test
- public void addAll_mixed() {
- Science initial = TestUtilsKt.createScience(3, 4, 5, 1);
- Science other = TestUtilsKt.createScience(1, 2, 3, 4);
- initial.addAll(other);
- assertEquals(4, initial.getQuantity(ScienceType.COMPASS));
- assertEquals(6, initial.getQuantity(ScienceType.WHEEL));
- assertEquals(8, initial.getQuantity(ScienceType.TABLET));
- assertEquals(5, initial.getJokers());
- }
-
- @Theory
- public void computePoints_compassesOnly_noJoker(int compasses) {
- Science science = TestUtilsKt.createScience(compasses, 0, 0, 0);
- assertEquals(compasses * compasses, science.computePoints());
- }
-
- @Theory
- public void computePoints_wheelsOnly_noJoker(int wheels) {
- Science science = TestUtilsKt.createScience(0, wheels, 0, 0);
- assertEquals(wheels * wheels, science.computePoints());
- }
-
- @Theory
- public void computePoints_tabletsOnly_noJoker(int tablets) {
- Science science = TestUtilsKt.createScience(0, 0, tablets, 0);
- assertEquals(tablets * tablets, science.computePoints());
- }
-
- @Theory
- public void computePoints_allSameNoJoker(int eachSymbol) {
- Science science = TestUtilsKt.createScience(eachSymbol, eachSymbol, eachSymbol, 0);
- assertEquals(3 * eachSymbol * eachSymbol + 7 * eachSymbol, science.computePoints());
- }
-
- @Theory
- public void computePoints_expectation(int[] expectation) {
- Science science = TestUtilsKt.createScience(expectation[0], expectation[1], expectation[2], expectation[3]);
- assertEquals(expectation[4], science.computePoints());
- }
-}
diff --git a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/api/TableTest.kt b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/api/TableTest.kt
index ab4655ce..3ae873a2 100644
--- a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/api/TableTest.kt
+++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/api/TableTest.kt
@@ -47,10 +47,10 @@ class TableTest {
assumeTrue(nbPlayers >= 4)
val table = testTable(nbPlayers)
val guildCards = createGuildCards(4)
- table.getBoard(0).playedCards.add(guildCards[0])
- table.getBoard(0).playedCards.add(guildCards[1])
- table.getBoard(1).playedCards.add(guildCards[2])
- table.getBoard(2).playedCards.add(guildCards[3])
+ table.getBoard(0).addCard(guildCards[0])
+ table.getBoard(0).addCard(guildCards[1])
+ table.getBoard(1).addCard(guildCards[2])
+ table.getBoard(2).addCard(guildCards[3])
val neightbourCards0 = table.getNeighbourGuildCards(0)
assertEquals(1, neightbourCards0.size.toLong())
diff --git a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/boards/BoardTest.kt b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/boards/BoardTest.kt
new file mode 100644
index 00000000..4142206b
--- /dev/null
+++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/boards/BoardTest.kt
@@ -0,0 +1,226 @@
+package org.luxons.sevenwonders.game.boards
+
+import junit.framework.TestCase.assertEquals
+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.FromDataPoints
+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.Settings
+import org.luxons.sevenwonders.game.api.Table
+import org.luxons.sevenwonders.game.boards.Board.InsufficientFundsException
+import org.luxons.sevenwonders.game.cards.Color
+import org.luxons.sevenwonders.game.effects.RawPointsIncrease
+import org.luxons.sevenwonders.game.effects.SpecialAbility
+import org.luxons.sevenwonders.game.effects.SpecialAbilityActivation
+import org.luxons.sevenwonders.game.resources.ResourceType
+import org.luxons.sevenwonders.game.scoring.ScoreCategory
+import org.luxons.sevenwonders.game.test.addCards
+import org.luxons.sevenwonders.game.test.createResources
+import org.luxons.sevenwonders.game.test.getDifferentColorFrom
+import org.luxons.sevenwonders.game.test.playCardWithEffect
+import org.luxons.sevenwonders.game.test.testBoard
+import org.luxons.sevenwonders.game.test.testCard
+import org.luxons.sevenwonders.game.test.testCustomizableSettings
+import org.luxons.sevenwonders.game.test.testWonder
+
+@RunWith(Theories::class)
+class BoardTest {
+
+ @JvmField
+ @Rule
+ var thrown: ExpectedException = ExpectedException.none()
+
+ @Theory
+ fun initialGold_respectsSettings(@FromDataPoints("gold") goldAmountInSettings: Int) {
+ val customSettings = testCustomizableSettings(goldAmountInSettings)
+ val settings = Settings(5, customSettings)
+ val board = Board(testWonder(), 0, settings)
+ assertEquals(goldAmountInSettings, board.gold)
+ }
+
+ @Theory
+ fun initialProduction_containsInitialResource(type: ResourceType) {
+ val board = Board(testWonder(type), 0, Settings(5))
+ val resources = createResources(type)
+ assertTrue(board.production.contains(resources))
+ assertTrue(board.publicProduction.contains(resources))
+ }
+
+ @Theory
+ fun removeGold_successfulWhenNotTooMuch(
+ @FromDataPoints("gold") initialGold: Int,
+ @FromDataPoints("gold") goldRemoved: Int
+ ) {
+ assumeTrue(goldRemoved >= 0)
+ assumeTrue(initialGold >= goldRemoved)
+ val board = Board(testWonder(), 0, Settings(5))
+ board.gold = initialGold
+ board.removeGold(goldRemoved)
+ assertEquals(initialGold - goldRemoved, board.gold)
+ }
+
+ @Theory
+ fun removeGold_failsWhenTooMuch(
+ @FromDataPoints("gold") initialGold: Int,
+ @FromDataPoints("gold") goldRemoved: Int
+ ) {
+ assumeTrue(goldRemoved >= 0)
+ assumeTrue(initialGold < goldRemoved)
+ thrown.expect(InsufficientFundsException::class.java)
+ val board = Board(testWonder(), 0, Settings(5))
+ board.gold = initialGold
+ board.removeGold(goldRemoved)
+ }
+
+ @Theory
+ fun getNbCardsOfColor_properCount_singleColor(
+ type: ResourceType, @FromDataPoints("nbCards") nbCards: Int,
+ @FromDataPoints("nbCards") nbOtherCards: Int, color: Color
+ ) {
+ val board = testBoard(type)
+ addCards(board, nbCards, nbOtherCards, color)
+ assertEquals(nbCards, board.getNbCardsOfColor(listOf(color)))
+ }
+
+ @Theory
+ fun getNbCardsOfColor_properCount_multiColors(
+ type: ResourceType, @FromDataPoints("nbCards") nbCards1: Int,
+ @FromDataPoints("nbCards") nbCards2: Int,
+ @FromDataPoints("nbCards") nbOtherCards: Int, color1: Color,
+ color2: Color
+ ) {
+ val board = testBoard(type)
+ addCards(board, nbCards1, color1)
+ addCards(board, nbCards2, color2)
+ addCards(board, nbOtherCards, getDifferentColorFrom(color1, color2))
+ assertEquals(nbCards1 + nbCards2, board.getNbCardsOfColor(listOf(color1, color2)))
+ }
+
+ @Test
+ fun setCopiedGuild_succeedsOnPurpleCard() {
+ val board = testBoard(ResourceType.CLAY)
+ val card = testCard(Color.PURPLE)
+
+ board.copiedGuild = card
+ assertSame(card, board.copiedGuild)
+ }
+
+ @Theory
+ fun setCopiedGuild_failsOnNonPurpleCard(color: Color) {
+ assumeTrue(color !== Color.PURPLE)
+ val board = testBoard(ResourceType.CLAY)
+ val card = testCard(color)
+
+ thrown.expect(IllegalArgumentException::class.java)
+ board.copiedGuild = card
+ }
+
+ @Theory
+ fun hasSpecial(applied: SpecialAbility, tested: SpecialAbility) {
+ val board = testBoard(ResourceType.CLAY)
+ val table = Table(listOf(board))
+ val special = SpecialAbilityActivation(applied)
+
+ special.apply(table, 0)
+
+ assertEquals(applied === tested, board.hasSpecial(tested))
+ }
+
+ @Test
+ fun canPlayFreeCard() {
+ val board = testBoard(ResourceType.CLAY)
+ val table = Table(listOf(board))
+ val special = SpecialAbilityActivation(SpecialAbility.ONE_FREE_PER_AGE)
+
+ special.apply(table, 0)
+
+ assertTrue(board.canPlayFreeCard(0))
+ assertTrue(board.canPlayFreeCard(1))
+ assertTrue(board.canPlayFreeCard(2))
+
+ board.consumeFreeCard(0)
+
+ assertFalse(board.canPlayFreeCard(0))
+ assertTrue(board.canPlayFreeCard(1))
+ assertTrue(board.canPlayFreeCard(2))
+
+ board.consumeFreeCard(1)
+
+ assertFalse(board.canPlayFreeCard(0))
+ assertFalse(board.canPlayFreeCard(1))
+ assertTrue(board.canPlayFreeCard(2))
+
+ board.consumeFreeCard(2)
+
+ assertFalse(board.canPlayFreeCard(0))
+ assertFalse(board.canPlayFreeCard(1))
+ assertFalse(board.canPlayFreeCard(2))
+ }
+
+ @Theory
+ fun computePoints_gold(@FromDataPoints("gold") gold: Int) {
+ assumeTrue(gold >= 0)
+ val board = testBoard(ResourceType.WOOD)
+ val table = Table(listOf(board))
+ board.gold = gold
+
+ val score = board.computePoints(table)
+ assertEquals(gold / 3, score.getPoints(ScoreCategory.GOLD))
+ assertEquals(gold / 3, score.totalPoints)
+ }
+
+ @Theory
+ fun computePoints_(@FromDataPoints("gold") gold: Int) {
+ assumeTrue(gold >= 0)
+ val board = testBoard(ResourceType.WOOD)
+ val table = Table(listOf(board))
+ board.gold = gold
+
+ val effect = RawPointsIncrease(5)
+ playCardWithEffect(table, 0, Color.BLUE, effect)
+
+ val score = board.computePoints(table)
+ assertEquals(gold / 3, score.getPoints(ScoreCategory.GOLD))
+ assertEquals(5, score.getPoints(ScoreCategory.CIVIL))
+ assertEquals(5 + gold / 3, score.totalPoints)
+ }
+
+ companion object {
+
+ @JvmStatic
+ @DataPoints("gold")
+ fun goldAmounts(): IntArray {
+ return intArrayOf(-3, -1, 0, 1, 2, 3)
+ }
+
+ @JvmStatic
+ @DataPoints("nbCards")
+ fun nbCards(): IntArray {
+ return intArrayOf(0, 1, 2)
+ }
+
+ @JvmStatic
+ @DataPoints
+ fun resourceTypes(): Array<ResourceType> {
+ return ResourceType.values()
+ }
+
+ @JvmStatic
+ @DataPoints
+ fun colors(): Array<Color> {
+ return Color.values()
+ }
+
+ @JvmStatic
+ @DataPoints
+ fun specialAbilities(): Array<SpecialAbility> {
+ return SpecialAbility.values()
+ }
+ }
+}
diff --git a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/boards/MilitaryTest.kt b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/boards/MilitaryTest.kt
new file mode 100644
index 00000000..34a599c9
--- /dev/null
+++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/boards/MilitaryTest.kt
@@ -0,0 +1,71 @@
+package org.luxons.sevenwonders.game.boards
+
+import java.util.HashMap
+
+import org.junit.Rule
+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.rules.ExpectedException
+import org.junit.runner.RunWith
+import org.luxons.sevenwonders.game.boards.Military.UnknownAgeException
+
+import org.junit.Assert.assertEquals
+
+@RunWith(Theories::class)
+class MilitaryTest {
+
+ @JvmField
+ @Rule
+ var thrown = ExpectedException.none()
+
+ @Theory
+ fun victory_addsCorrectPoints(
+ @FromDataPoints("ages") age: Int,
+ @FromDataPoints("points") nbPointsPerVictory: Int
+ ) {
+ val military = createMilitary(age, nbPointsPerVictory, 0)
+ val initialPoints = military.totalPoints
+
+ military.victory(age)
+ assertEquals((initialPoints + nbPointsPerVictory).toLong(), military.totalPoints.toLong())
+ }
+
+ @Theory
+ fun victory_failsIfUnknownAge(@FromDataPoints("points") nbPointsPerVictory: Int) {
+ val military = createMilitary(0, nbPointsPerVictory, 0)
+ thrown.expect(UnknownAgeException::class.java)
+ military.victory(1)
+ }
+
+ @Theory
+ fun defeat_removesCorrectPoints(@FromDataPoints("points") nbPointsLostPerDefeat: Int) {
+ val military = createMilitary(0, 0, nbPointsLostPerDefeat)
+ val initialPoints = military.totalPoints
+
+ military.defeat()
+ assertEquals((initialPoints - nbPointsLostPerDefeat).toLong(), military.totalPoints.toLong())
+ }
+
+ companion object {
+
+ @JvmStatic
+ @DataPoints("points")
+ fun points(): IntArray {
+ return intArrayOf(0, 1, 3, 5)
+ }
+
+ @JvmStatic
+ @DataPoints("ages")
+ fun ages(): IntArray {
+ return intArrayOf(1, 2, 3)
+ }
+
+ private fun createMilitary(age: Int, nbPointsPerVictory: Int, nbPointsPerDefeat: Int): Military {
+ val wonPointsPerAge = HashMap<Int, Int>()
+ wonPointsPerAge[age] = nbPointsPerVictory
+ return Military(nbPointsPerDefeat, wonPointsPerAge)
+ }
+ }
+}
diff --git a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/boards/RelativeBoardPositionTest.kt b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/boards/RelativeBoardPositionTest.kt
new file mode 100644
index 00000000..d9c79ac5
--- /dev/null
+++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/boards/RelativeBoardPositionTest.kt
@@ -0,0 +1,48 @@
+package org.luxons.sevenwonders.game.boards
+
+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.junit.Assert.assertEquals
+import org.junit.Assume.assumeTrue
+
+@RunWith(Theories::class)
+class RelativeBoardPositionTest {
+
+ @Theory
+ fun getIndexFrom_wrapLeft(nbPlayers: Int) {
+ assumeTrue(nbPlayers >= 2)
+ val last = nbPlayers - 1
+ assertEquals(last.toLong(), RelativeBoardPosition.LEFT.getIndexFrom(0, nbPlayers).toLong())
+ assertEquals(0, RelativeBoardPosition.SELF.getIndexFrom(0, nbPlayers).toLong())
+ assertEquals(1, RelativeBoardPosition.RIGHT.getIndexFrom(0, nbPlayers).toLong())
+ }
+
+ @Theory
+ fun getIndexFrom_wrapRight(nbPlayers: Int) {
+ assumeTrue(nbPlayers >= 2)
+ val last = nbPlayers - 1
+ assertEquals((last - 1).toLong(), RelativeBoardPosition.LEFT.getIndexFrom(last, nbPlayers).toLong())
+ assertEquals(last.toLong(), RelativeBoardPosition.SELF.getIndexFrom(last, nbPlayers).toLong())
+ assertEquals(0, RelativeBoardPosition.RIGHT.getIndexFrom(last, nbPlayers).toLong())
+ }
+
+ @Theory
+ fun getIndexFrom_noWrap(nbPlayers: Int) {
+ assumeTrue(nbPlayers >= 3)
+ assertEquals(0, RelativeBoardPosition.LEFT.getIndexFrom(1, nbPlayers).toLong())
+ assertEquals(1, RelativeBoardPosition.SELF.getIndexFrom(1, nbPlayers).toLong())
+ assertEquals(2, RelativeBoardPosition.RIGHT.getIndexFrom(1, nbPlayers).toLong())
+ }
+
+ companion object {
+
+ @JvmStatic
+ @DataPoints
+ fun nbPlayers(): IntArray {
+ return intArrayOf(1, 2, 3, 5, 7, 9)
+ }
+ }
+}
diff --git a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/boards/ScienceTest.kt b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/boards/ScienceTest.kt
new file mode 100644
index 00000000..8c2041e4
--- /dev/null
+++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/boards/ScienceTest.kt
@@ -0,0 +1,119 @@
+package org.luxons.sevenwonders.game.boards
+
+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.test.*
+
+import org.junit.Assert.assertEquals
+
+@RunWith(Theories::class)
+class ScienceTest {
+
+ @Test
+ fun addAll_empty() {
+ val initial = createScience(3, 4, 5, 1)
+ val empty = Science()
+ initial.addAll(empty)
+ assertEquals(3, initial.getQuantity(ScienceType.COMPASS).toLong())
+ assertEquals(4, initial.getQuantity(ScienceType.WHEEL).toLong())
+ assertEquals(5, initial.getQuantity(ScienceType.TABLET).toLong())
+ assertEquals(1, initial.jokers.toLong())
+ }
+
+ @Test
+ fun addAll_noJoker() {
+ val initial = createScience(3, 4, 5, 1)
+ val other = createScience(1, 2, 3, 0)
+ initial.addAll(other)
+ assertEquals(4, initial.getQuantity(ScienceType.COMPASS).toLong())
+ assertEquals(6, initial.getQuantity(ScienceType.WHEEL).toLong())
+ assertEquals(8, initial.getQuantity(ScienceType.TABLET).toLong())
+ assertEquals(1, initial.jokers.toLong())
+ }
+
+ @Test
+ fun addAll_withJokers() {
+ val initial = createScience(3, 4, 5, 1)
+ val other = createScience(0, 0, 0, 3)
+ initial.addAll(other)
+ assertEquals(3, initial.getQuantity(ScienceType.COMPASS).toLong())
+ assertEquals(4, initial.getQuantity(ScienceType.WHEEL).toLong())
+ assertEquals(5, initial.getQuantity(ScienceType.TABLET).toLong())
+ assertEquals(4, initial.jokers.toLong())
+ }
+
+ @Test
+ fun addAll_mixed() {
+ val initial = createScience(3, 4, 5, 1)
+ val other = createScience(1, 2, 3, 4)
+ initial.addAll(other)
+ assertEquals(4, initial.getQuantity(ScienceType.COMPASS).toLong())
+ assertEquals(6, initial.getQuantity(ScienceType.WHEEL).toLong())
+ assertEquals(8, initial.getQuantity(ScienceType.TABLET).toLong())
+ assertEquals(5, initial.jokers.toLong())
+ }
+
+ @Theory
+ fun computePoints_compassesOnly_noJoker(compasses: Int) {
+ val science = createScience(compasses, 0, 0, 0)
+ assertEquals((compasses * compasses).toLong(), science.computePoints().toLong())
+ }
+
+ @Theory
+ fun computePoints_wheelsOnly_noJoker(wheels: Int) {
+ val science = createScience(0, wheels, 0, 0)
+ assertEquals((wheels * wheels).toLong(), science.computePoints().toLong())
+ }
+
+ @Theory
+ fun computePoints_tabletsOnly_noJoker(tablets: Int) {
+ val science = createScience(0, 0, tablets, 0)
+ assertEquals((tablets * tablets).toLong(), science.computePoints().toLong())
+ }
+
+ @Theory
+ fun computePoints_allSameNoJoker(eachSymbol: Int) {
+ val science = createScience(eachSymbol, eachSymbol, eachSymbol, 0)
+ assertEquals((3 * eachSymbol * eachSymbol + 7 * eachSymbol).toLong(), science.computePoints().toLong())
+ }
+
+ @Theory
+ fun computePoints_expectation(expectation: IntArray) {
+ val science = createScience(expectation[0], expectation[1], expectation[2], expectation[3])
+ assertEquals(expectation[4].toLong(), science.computePoints().toLong())
+ }
+
+ companion object {
+
+ @JvmStatic
+ @DataPoints
+ fun quantitiesWithExpectedPoints(): Array<IntArray> {
+ // compasses, wheels, tablets, jokers, expected points
+ return arrayOf(
+ intArrayOf(0, 0, 0, 1, 1),
+ intArrayOf(0, 0, 1, 0, 1),
+ intArrayOf(0, 0, 0, 2, 4),
+ intArrayOf(0, 0, 1, 1, 4),
+ intArrayOf(0, 0, 2, 0, 4),
+ intArrayOf(0, 0, 0, 3, 10),
+ intArrayOf(0, 0, 1, 2, 10),
+ intArrayOf(0, 1, 1, 1, 10),
+ intArrayOf(1, 1, 1, 0, 10),
+ intArrayOf(0, 0, 0, 4, 16),
+ intArrayOf(0, 0, 1, 3, 16),
+ intArrayOf(0, 0, 2, 2, 16),
+ intArrayOf(0, 0, 3, 1, 16),
+ intArrayOf(0, 0, 4, 0, 16)
+ )
+ }
+
+ @JvmStatic
+ @DataPoints
+ fun quantitiesDataPoints(): IntArray {
+ return intArrayOf(0, 1, 3, 5, 8)
+ }
+ }
+}
bgstack15