summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backend/src/main/kotlin/org/luxons/sevenwonders/lobby/Lobby.kt16
-rw-r--r--backend/src/test/kotlin/org/luxons/sevenwonders/controllers/LobbyControllerTest.kt7
-rw-r--r--backend/src/test/kotlin/org/luxons/sevenwonders/lobby/LobbyTest.kt39
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/Game.kt4
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Board.kt2
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/EffectsDefinition.kt37
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/resources/BestPriceCalculator.kt32
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/resources/Production.kt3
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/resources/Resources.kt6
-rw-r--r--game-engine/src/test/kotlin/org/luxons/sevenwonders/game/resources/BestPriceCalculatorTest.kt9
10 files changed, 79 insertions, 76 deletions
diff --git a/backend/src/main/kotlin/org/luxons/sevenwonders/lobby/Lobby.kt b/backend/src/main/kotlin/org/luxons/sevenwonders/lobby/Lobby.kt
index 173ced64..8498ce85 100644
--- a/backend/src/main/kotlin/org/luxons/sevenwonders/lobby/Lobby.kt
+++ b/backend/src/main/kotlin/org/luxons/sevenwonders/lobby/Lobby.kt
@@ -3,7 +3,6 @@ package org.luxons.sevenwonders.lobby
import org.luxons.sevenwonders.game.Game
import org.luxons.sevenwonders.game.api.CustomizableSettings
import org.luxons.sevenwonders.game.data.GameDefinition
-import java.util.ArrayList
enum class State {
LOBBY, PLAYING
@@ -15,7 +14,7 @@ class Lobby(
var owner: Player,
@field:Transient private val gameDefinition: GameDefinition
) {
- private var players: MutableList<Player> = ArrayList(gameDefinition.maxPlayers)
+ private val players: MutableList<Player> = ArrayList(gameDefinition.maxPlayers)
var settings: CustomizableSettings = CustomizableSettings()
@@ -64,7 +63,11 @@ class Lobby(
@Synchronized
fun reorderPlayers(orderedUsernames: List<String>) {
- players = orderedUsernames.map { find(it) }.toMutableList()
+ val usernames = players.map { it.username }
+ if (orderedUsernames.toSet() != usernames.toSet()) {
+ throw PlayerListMismatchException(orderedUsernames)
+ }
+ players.sortBy { orderedUsernames.indexOf(it.username) }
}
private fun find(username: String): Player =
@@ -98,8 +101,11 @@ class Lobby(
IllegalStateException("Minimum $min players required to start a game")
internal class PlayerNameAlreadyUsedException(displayName: String, gameName: String) :
- IllegalStateException("Name '$displayName' is already used by a player in game '$gameName'")
+ IllegalArgumentException("Name '$displayName' is already used by a player in game '$gameName'")
internal class UnknownPlayerException(username: String) :
- IllegalStateException("Unknown player '$username'")
+ IllegalArgumentException("Unknown player '$username'")
+
+ internal class PlayerListMismatchException(usernames: List<String>) :
+ IllegalArgumentException("Newly ordered usernames $usernames don't match the current player list")
}
diff --git a/backend/src/test/kotlin/org/luxons/sevenwonders/controllers/LobbyControllerTest.kt b/backend/src/test/kotlin/org/luxons/sevenwonders/controllers/LobbyControllerTest.kt
index 2d37b0f4..6e417970 100644
--- a/backend/src/test/kotlin/org/luxons/sevenwonders/controllers/LobbyControllerTest.kt
+++ b/backend/src/test/kotlin/org/luxons/sevenwonders/controllers/LobbyControllerTest.kt
@@ -15,7 +15,6 @@ import org.luxons.sevenwonders.repositories.LobbyRepository
import org.luxons.sevenwonders.repositories.PlayerNotFoundException
import org.luxons.sevenwonders.repositories.PlayerRepository
import org.luxons.sevenwonders.test.mockSimpMessagingTemplate
-import java.util.Arrays
import java.util.HashMap
import kotlin.test.assertEquals
import kotlin.test.assertFalse
@@ -99,10 +98,10 @@ class LobbyControllerTest {
val player3 = addPlayer(lobby, "testuser3")
val player4 = addPlayer(lobby, "testuser4")
- val players = Arrays.asList(player, player2, player3, player4)
+ val players = listOf(player, player2, player3, player4)
assertEquals(players, lobby.getPlayers())
- val reorderedPlayers = Arrays.asList(player3, player, player2, player4)
+ val reorderedPlayers = listOf(player3, player, player2, player4)
val playerNames = reorderedPlayers.map { it.username }
val reorderPlayersAction = ReorderPlayersAction(playerNames)
@@ -120,7 +119,7 @@ class LobbyControllerTest {
val player2 = addPlayer(lobby, "testuser2")
val player3 = addPlayer(lobby, "testuser3")
- val reorderedPlayers = Arrays.asList(player3, player, player2)
+ val reorderedPlayers = listOf(player3, player, player2)
val playerNames = reorderedPlayers.map { it.username }
val reorderPlayersAction = ReorderPlayersAction(playerNames)
diff --git a/backend/src/test/kotlin/org/luxons/sevenwonders/lobby/LobbyTest.kt b/backend/src/test/kotlin/org/luxons/sevenwonders/lobby/LobbyTest.kt
index 85c89595..98e154da 100644
--- a/backend/src/test/kotlin/org/luxons/sevenwonders/lobby/LobbyTest.kt
+++ b/backend/src/test/kotlin/org/luxons/sevenwonders/lobby/LobbyTest.kt
@@ -13,11 +13,11 @@ import org.junit.runner.RunWith
import org.luxons.sevenwonders.game.api.CustomizableSettings
import org.luxons.sevenwonders.game.data.GameDefinition
import org.luxons.sevenwonders.lobby.Lobby.GameAlreadyStartedException
+import org.luxons.sevenwonders.lobby.Lobby.PlayerListMismatchException
import org.luxons.sevenwonders.lobby.Lobby.PlayerNameAlreadyUsedException
import org.luxons.sevenwonders.lobby.Lobby.PlayerOverflowException
import org.luxons.sevenwonders.lobby.Lobby.PlayerUnderflowException
import org.luxons.sevenwonders.lobby.Lobby.UnknownPlayerException
-import java.util.Arrays
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNotNull
@@ -150,21 +150,38 @@ class LobbyTest {
lobby.addPlayer(player1)
lobby.addPlayer(player2)
lobby.addPlayer(player3)
- lobby.reorderPlayers(Arrays.asList("testuser3", "testuser1", "testuser2"))
- assertEquals("testuser3", lobby.getPlayers()[0].username)
- assertEquals("testuser1", lobby.getPlayers()[1].username)
- assertEquals("testuser2", lobby.getPlayers()[2].username)
+
+ val reorderedUsernames = listOf("testuser3", "gameowner", "testuser1", "testuser2")
+ lobby.reorderPlayers(reorderedUsernames)
+
+ assertEquals(reorderedUsernames, lobby.getPlayers().map { it.username })
}
- @Test(expected = UnknownPlayerException::class)
+ @Test(expected = PlayerListMismatchException::class)
fun reorderPlayers_failsOnUnknownPlayer() {
val player1 = Player("testuser1", "Test User 1")
val player2 = Player("testuser2", "Test User 2")
- val player3 = Player("testuser3", "Test User 3")
lobby.addPlayer(player1)
lobby.addPlayer(player2)
- lobby.addPlayer(player3)
- lobby.reorderPlayers(Arrays.asList("unknown", "testuser1", "testuser2"))
+ lobby.reorderPlayers(listOf("unknown", "testuser2", "gameowner"))
+ }
+
+ @Test(expected = PlayerListMismatchException::class)
+ fun reorderPlayers_failsOnExtraPlayer() {
+ val player1 = Player("testuser1", "Test User 1")
+ val player2 = Player("testuser2", "Test User 2")
+ lobby.addPlayer(player1)
+ lobby.addPlayer(player2)
+ lobby.reorderPlayers(listOf("testuser2", "onemore", "testuser1", "gameowner"))
+ }
+
+ @Test(expected = PlayerListMismatchException::class)
+ fun reorderPlayers_failsOnMissingPlayer() {
+ val player1 = Player("testuser1", "Test User 1")
+ val player2 = Player("testuser2", "Test User 2")
+ lobby.addPlayer(player1)
+ lobby.addPlayer(player2)
+ lobby.reorderPlayers(listOf("testuser2", "gameowner"))
}
@Theory
@@ -203,11 +220,11 @@ class LobbyTest {
@Test
fun startGame_switchesState() {
- assertTrue(lobby.state === State.LOBBY)
+ assertEquals(State.LOBBY, lobby.state)
// there is already the owner
addPlayers(gameDefinition.minPlayers - 1)
lobby.startGame()
- assertTrue(lobby.state === State.PLAYING)
+ assertEquals(State.PLAYING, lobby.state)
}
@Test
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/Game.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/Game.kt
index f92177c8..124cf435 100644
--- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/Game.kt
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/Game.kt
@@ -26,8 +26,8 @@ class Game internal constructor(
) {
private val table: Table = Table(boards)
private val players: List<Player> = boards.map { SimplePlayer(it.playerIndex, table) }
- private val discardedCards: MutableList<Card> = ArrayList()
- private val preparedMoves: MutableMap<Int, Move> = HashMap()
+ private val discardedCards: MutableList<Card> = mutableListOf()
+ private val preparedMoves: MutableMap<Int, Move> = mutableMapOf()
private var currentTurnInfo: List<PlayerTurnInfo> = emptyList()
private var hands: Hands = Hands(emptyList())
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Board.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Board.kt
index 22b9ac93..04dd2d25 100644
--- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Board.kt
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/boards/Board.kt
@@ -23,7 +23,7 @@ internal class Board(val wonder: Wonder, val playerIndex: Int, settings: Setting
private val pointsPer3Gold: Int = settings.pointsPer3Gold
- private val playedCards: MutableList<Card> = arrayListOf()
+ private val playedCards: MutableList<Card> = mutableListOf()
private val specialAbilities: MutableSet<SpecialAbility> = hashSetOf()
private val consumedFreeCards: MutableMap<Age, Boolean> = mutableMapOf()
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/EffectsDefinition.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/EffectsDefinition.kt
index 23a8d3ee..4d0348ea 100644
--- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/EffectsDefinition.kt
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/EffectsDefinition.kt
@@ -10,7 +10,6 @@ import org.luxons.sevenwonders.game.effects.RawPointsIncrease
import org.luxons.sevenwonders.game.effects.ScienceProgress
import org.luxons.sevenwonders.game.effects.SpecialAbility
import org.luxons.sevenwonders.game.effects.SpecialAbilityActivation
-import java.util.ArrayList
internal class EffectsDefinition(
private val gold: GoldIncrease? = null,
@@ -22,32 +21,14 @@ internal class EffectsDefinition(
private val points: RawPointsIncrease? = null,
private val action: SpecialAbility? = null
) {
- fun create(): List<Effect> {
- val effects = ArrayList<Effect>()
- if (gold != null) {
- effects.add(gold)
- }
- if (military != null) {
- effects.add(military)
- }
- if (science != null) {
- effects.add(science)
- }
- if (discount != null) {
- effects.add(discount)
- }
- if (perBoardElement != null) {
- effects.add(perBoardElement)
- }
- if (production != null) {
- effects.add(production)
- }
- if (points != null) {
- effects.add(points)
- }
- if (action != null) {
- effects.add(SpecialAbilityActivation(action))
- }
- return effects
+ fun create(): List<Effect> = mutableListOf<Effect>().apply {
+ gold?.let { add(it) }
+ military?.let { add(it) }
+ science?.let { add(it) }
+ discount?.let { add(it) }
+ perBoardElement?.let { add(it) }
+ production?.let { add(it) }
+ points?.let { add(it) }
+ action?.let { add(SpecialAbilityActivation(it)) }
}
}
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/resources/BestPriceCalculator.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/resources/BestPriceCalculator.kt
index 3d051732..dea6f2c2 100644
--- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/resources/BestPriceCalculator.kt
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/resources/BestPriceCalculator.kt
@@ -1,7 +1,6 @@
package org.luxons.sevenwonders.game.resources
import org.luxons.sevenwonders.game.Player
-import java.util.ArrayList
import java.util.EnumSet
internal fun bestSolution(resources: Resources, player: Player): TransactionPlan =
@@ -12,8 +11,10 @@ data class TransactionPlan(val price: Int, val possibleTransactions: Set<Resourc
private class ResourcePool(
val provider: Provider?,
private val rules: TradingRules,
- val choices: Set<MutableSet<ResourceType>>
+ choices: Set<Set<ResourceType>>
) {
+ val choices: Set<MutableSet<ResourceType>> = choices.map { it.toMutableSet() }.toSet()
+
fun getCost(type: ResourceType): Int = if (provider == null) 0 else rules.getCost(type, provider)
}
@@ -34,23 +35,18 @@ private class BestPriceCalculator(resourcesToPay: Resources, player: Player) {
}
private fun createResourcePools(player: Player): List<ResourcePool> {
- val providers = Provider.values()
+ // we only take alternative resources here, because fixed resources were already removed for optimization
+ val ownBoardChoices = player.board.production.getAlternativeResources()
+ val ownPool = ResourcePool(null, player.board.tradingRules, ownBoardChoices)
+ val providerPools = Provider.values().map { it.toResourcePoolFor(player) }
- val board = player.board
- val rules = board.tradingRules
+ return providerPools + ownPool
+ }
- val pools = ArrayList<ResourcePool>(providers.size + 1)
- // we only take alternative resources here, because fixed resources were already removed for optimization
- val ownBoardChoices = board.production.getAlternativeResources()
- pools.add(ResourcePool(null, rules, ownBoardChoices.map { it.toMutableSet() }.toSet()))
-
- for (provider in providers) {
- val providerBoard = player.getBoard(provider.boardPosition)
- val choices = providerBoard.publicProduction.asChoices().map { it.toMutableSet() }.toSet()
- val pool = ResourcePool(provider, rules, choices)
- pools.add(pool)
- }
- return pools
+ private fun Provider.toResourcePoolFor(player: Player): ResourcePool {
+ val providerBoard = player.getBoard(boardPosition)
+ val choices = providerBoard.publicProduction.asChoices()
+ return ResourcePool(this, player.board.tradingRules, choices)
}
fun computeBestSolution(): TransactionPlan {
@@ -120,6 +116,6 @@ private class BestPriceCalculator(resourcesToPay: Resources, player: Player) {
bestSolutions.clear()
}
// avoid mutating the resources from the transactions
- bestSolutions.add(boughtResources.mapValues { MutableResources(HashMap(it.value.quantities)) }.toTransactions())
+ bestSolutions.add(boughtResources.mapValues { (_, res) -> res.copy() }.toTransactions())
}
}
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/resources/Production.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/resources/Production.kt
index 0b069677..66a63463 100644
--- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/resources/Production.kt
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/resources/Production.kt
@@ -1,6 +1,5 @@
package org.luxons.sevenwonders.game.resources
-import java.util.Arrays
import java.util.EnumSet
data class Production internal constructor(
@@ -14,7 +13,7 @@ data class Production internal constructor(
fun addFixedResource(type: ResourceType, quantity: Int) = fixedResources.add(type, quantity)
fun addChoice(vararg options: ResourceType) {
- val optionSet = EnumSet.copyOf(Arrays.asList(*options))
+ val optionSet = EnumSet.copyOf(options.toList())
alternativeResources.add(optionSet)
}
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/resources/Resources.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/resources/Resources.kt
index c02fd260..a91a2af1 100644
--- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/resources/Resources.kt
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/resources/Resources.kt
@@ -10,6 +10,10 @@ fun resourcesOf(vararg resources: Pair<ResourceType, Int>): Resources = mutableR
fun Iterable<Pair<ResourceType, Int>>.toResources(): Resources = toMutableResources()
+/**
+ * Creates [Resources] from a copy of the given map. Future modifications to the input map won't affect the return
+ * resources.
+ */
fun Map<ResourceType, Int>.toResources(): Resources = toMutableResources()
fun Iterable<Resources>.merge(): Resources = fold(MutableResources()) { r1, r2 -> r1.add(r2); r1 }
@@ -53,6 +57,8 @@ interface Resources {
quantities.mapValues { (type, q) -> Math.max(0, q - resources[type]) }.toResources()
fun toList(): List<ResourceType> = quantities.flatMap { (type, quantity) -> List(quantity) { type } }
+
+ fun copy(): Resources = quantities.toResources()
}
class MutableResources(
diff --git a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/resources/BestPriceCalculatorTest.kt b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/resources/BestPriceCalculatorTest.kt
index 5d99ae00..b4c3b886 100644
--- a/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/resources/BestPriceCalculatorTest.kt
+++ b/game-engine/src/test/kotlin/org/luxons/sevenwonders/game/resources/BestPriceCalculatorTest.kt
@@ -14,7 +14,6 @@ import org.luxons.sevenwonders.game.test.createTransaction
import org.luxons.sevenwonders.game.test.createTransactions
import org.luxons.sevenwonders.game.test.testBoard
import org.luxons.sevenwonders.game.test.testTable
-import java.util.Arrays
import kotlin.test.assertEquals
class BestPriceCalculatorTest {
@@ -36,7 +35,7 @@ class BestPriceCalculatorTest {
val left = testBoard(STONE)
val main = testBoard(STONE)
val right = testBoard(WOOD)
- val table = Table(Arrays.asList(main, right, left))
+ val table = Table(listOf(main, right, left))
val player0 = SimplePlayer(0, table)
val player1 = SimplePlayer(1, table)
@@ -64,7 +63,7 @@ class BestPriceCalculatorTest {
val left = testBoard(WOOD)
val right = testBoard(WOOD)
val opposite = testBoard(GLASS)
- val table = Table(Arrays.asList(main, right, opposite, left))
+ val table = Table(listOf(main, right, opposite, left))
val player0 = SimplePlayer(0, table)
val player1 = SimplePlayer(1, table)
@@ -93,7 +92,7 @@ class BestPriceCalculatorTest {
right.production.addChoice(WOOD, CLAY)
right.publicProduction.addChoice(WOOD, CLAY)
- val table = Table(Arrays.asList(main, right, left))
+ val table = Table(listOf(main, right, left))
val player0 = SimplePlayer(0, table)
val player1 = SimplePlayer(1, table)
@@ -121,7 +120,7 @@ class BestPriceCalculatorTest {
right.publicProduction.addFixedResource(ORE, 1)
right.publicProduction.addFixedResource(CLAY, 1)
- val table = Table(Arrays.asList(main, right, left))
+ val table = Table(listOf(main, right, left))
val player0 = SimplePlayer(0, table)
val player1 = SimplePlayer(1, table)
bgstack15