summaryrefslogtreecommitdiff
path: root/game-engine/src/main/kotlin/org
diff options
context:
space:
mode:
Diffstat (limited to 'game-engine/src/main/kotlin/org')
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/Settings.kt34
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/CustomizableSettings.kt2
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/GameDefinition.kt30
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/GameDefinitionLoader.kt63
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/GlobalRules.kt6
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/WonderSide.kt6
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/WonderSidePickMethod.kt28
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/CardDefinition.kt20
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/DecksDefinition.kt53
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/EffectsDefinition.kt53
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/WonderDefinition.kt21
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/WonderSideDefinition.kt14
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/WonderStageDefinition.kt13
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/NumericEffectSerializer.kt40
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/ProductionIncreaseSerializer.kt51
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/ProductionSerializer.kt58
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/ResourceTypeSerializer.kt29
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/ResourceTypesSerializer.kt39
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/ResourcesSerializer.kt34
-rw-r--r--game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/ScienceProgressSerializer.kt57
20 files changed, 650 insertions, 1 deletions
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/Settings.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/Settings.kt
new file mode 100644
index 00000000..fac3979e
--- /dev/null
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/Settings.kt
@@ -0,0 +1,34 @@
+package org.luxons.sevenwonders.game
+
+import org.luxons.sevenwonders.game.api.CustomizableSettings
+import org.luxons.sevenwonders.game.data.WonderSide
+import org.luxons.sevenwonders.game.data.WonderSidePickMethod
+import java.util.Random
+
+class Settings @JvmOverloads constructor(
+ val nbPlayers: Int,
+ customSettings: CustomizableSettings = CustomizableSettings()
+) {
+ val random: Random
+ val timeLimitInSeconds: Int = customSettings.timeLimitInSeconds
+ val initialGold: Int = customSettings.initialGold
+ val discardedCardGold: Int = customSettings.discardedCardGold
+ val defaultTradingCost: Int = customSettings.defaultTradingCost
+ val pointsPer3Gold: Int = customSettings.pointsPer3Gold
+ val lostPointsPerDefeat: Int = customSettings.lostPointsPerDefeat
+ val wonPointsPerVictoryPerAge: Map<Int, Int> = customSettings.wonPointsPerVictoryPerAge
+
+ private val wonderSidePickMethod: WonderSidePickMethod = customSettings.wonderSidePickMethod
+ private var lastPickedSide: WonderSide? = null
+
+ init {
+ val seed = customSettings.randomSeedForTests
+ this.random = if (seed != null) Random(seed) else Random()
+ }
+
+ fun pickWonderSide(): WonderSide {
+ val newSide = wonderSidePickMethod.pickSide(random, lastPickedSide)
+ lastPickedSide = newSide
+ return newSide
+ }
+}
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/CustomizableSettings.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/CustomizableSettings.kt
index 354aecb6..e4efb9e3 100644
--- a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/CustomizableSettings.kt
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/api/CustomizableSettings.kt
@@ -1,6 +1,6 @@
package org.luxons.sevenwonders.game.api
-import org.luxons.sevenwonders.game.data.definitions.WonderSidePickMethod
+import org.luxons.sevenwonders.game.data.WonderSidePickMethod
data class CustomizableSettings(
val randomSeedForTests: Long? = null,
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/GameDefinition.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/GameDefinition.kt
new file mode 100644
index 00000000..b7a859eb
--- /dev/null
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/GameDefinition.kt
@@ -0,0 +1,30 @@
+package org.luxons.sevenwonders.game.data
+
+import org.luxons.sevenwonders.game.Game
+import org.luxons.sevenwonders.game.Settings
+import org.luxons.sevenwonders.game.api.CustomizableSettings
+import org.luxons.sevenwonders.game.boards.Board
+import org.luxons.sevenwonders.game.data.definitions.DecksDefinition
+import org.luxons.sevenwonders.game.data.definitions.WonderDefinition
+
+class GameDefinition internal constructor(
+ rules: GlobalRules,
+ private val wonders: Array<WonderDefinition>,
+ private val decksDefinition: DecksDefinition
+) {
+ val minPlayers: Int = rules.minPlayers
+ val maxPlayers: Int = rules.maxPlayers
+
+ fun initGame(id: Long, customSettings: CustomizableSettings, nbPlayers: Int): Game {
+ val settings = Settings(nbPlayers, customSettings)
+ val boards = assignBoards(settings, nbPlayers)
+ val decks = decksDefinition.prepareDecks(settings)
+ return Game(id, settings, nbPlayers, boards, decks)
+ }
+
+ private fun assignBoards(settings: Settings, nbPlayers: Int): List<Board> {
+ val randomizedWonders = wonders.toMutableList()
+ randomizedWonders.shuffle(settings.random)
+ return randomizedWonders.take(nbPlayers).mapIndexed { i, wDef -> Board(wDef.create(settings), i, settings) }
+ }
+}
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/GameDefinitionLoader.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/GameDefinitionLoader.kt
new file mode 100644
index 00000000..22ecc488
--- /dev/null
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/GameDefinitionLoader.kt
@@ -0,0 +1,63 @@
+package org.luxons.sevenwonders.game.data
+
+import com.github.salomonbrys.kotson.registerTypeAdapter
+import com.github.salomonbrys.kotson.typeToken
+import com.google.gson.Gson
+import com.google.gson.GsonBuilder
+import com.google.gson.JsonNull
+import com.google.gson.JsonPrimitive
+import org.luxons.sevenwonders.game.data.definitions.DecksDefinition
+import org.luxons.sevenwonders.game.data.definitions.WonderDefinition
+import org.luxons.sevenwonders.game.data.serializers.NumericEffectSerializer
+import org.luxons.sevenwonders.game.data.serializers.ProductionIncreaseSerializer
+import org.luxons.sevenwonders.game.data.serializers.ProductionSerializer
+import org.luxons.sevenwonders.game.data.serializers.ResourceTypeSerializer
+import org.luxons.sevenwonders.game.data.serializers.ResourceTypesSerializer
+import org.luxons.sevenwonders.game.data.serializers.ResourcesSerializer
+import org.luxons.sevenwonders.game.data.serializers.ScienceProgressSerializer
+import org.luxons.sevenwonders.game.effects.GoldIncrease
+import org.luxons.sevenwonders.game.effects.MilitaryReinforcements
+import org.luxons.sevenwonders.game.effects.ProductionIncrease
+import org.luxons.sevenwonders.game.effects.RawPointsIncrease
+import org.luxons.sevenwonders.game.effects.ScienceProgress
+import org.luxons.sevenwonders.game.resources.Production
+import org.luxons.sevenwonders.game.resources.ResourceType
+import org.luxons.sevenwonders.game.resources.Resources
+
+class GameDefinitionLoader {
+
+ val gameDefinition: GameDefinition by lazy { load() }
+
+ private fun load(): GameDefinition {
+ val gson: Gson = createGson()
+ val rules = loadJson("global_rules.json", GlobalRules::class.java, gson)
+ val wonders = loadJson("wonders.json", Array<WonderDefinition>::class.java, gson)
+ val decksDefinition = loadJson("cards.json", DecksDefinition::class.java, gson)
+ return GameDefinition(rules, wonders, decksDefinition)
+ }
+
+ private fun <T> loadJson(filename: String, clazz: Class<T>, gson: Gson): T {
+ val packageAsPath = GameDefinitionLoader::class.java.`package`.name.replace('.', '/')
+ val resourcePath = "/$packageAsPath/$filename"
+ val resource = GameDefinitionLoader::class.java.getResource(resourcePath)
+ val json = resource.readText()
+ return gson.fromJson(json, clazz)
+ }
+
+ private fun createGson(): Gson {
+ return GsonBuilder().disableHtmlEscaping()
+ .registerTypeAdapter<Resources>(ResourcesSerializer())
+ .registerTypeAdapter<ResourceType>(ResourceTypeSerializer())
+ .registerTypeAdapter<List<ResourceType>>(ResourceTypesSerializer())
+ .registerTypeAdapter<Production>(ProductionSerializer())
+ .registerTypeAdapter<ProductionIncrease>(ProductionIncreaseSerializer())
+ .registerTypeAdapter<MilitaryReinforcements>(NumericEffectSerializer())
+ .registerTypeAdapter<RawPointsIncrease>(NumericEffectSerializer())
+ .registerTypeAdapter<GoldIncrease>(NumericEffectSerializer())
+ .registerTypeAdapter<ScienceProgress>(ScienceProgressSerializer())
+ .create()
+ }
+
+ private inline fun <reified T: Any> GsonBuilder.registerTypeAdapter(typeAdapter: Any): GsonBuilder
+ = this.registerTypeAdapter(typeToken<T>(), typeAdapter)
+}
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
new file mode 100644
index 00000000..f472cc2a
--- /dev/null
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/GlobalRules.kt
@@ -0,0 +1,6 @@
+package org.luxons.sevenwonders.game.data
+
+internal data class GlobalRules(
+ val minPlayers: Int,
+ val maxPlayers: Int
+)
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/WonderSide.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/WonderSide.kt
new file mode 100644
index 00000000..4a818fc4
--- /dev/null
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/WonderSide.kt
@@ -0,0 +1,6 @@
+package org.luxons.sevenwonders.game.data
+
+enum class WonderSide {
+ A,
+ B
+}
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/WonderSidePickMethod.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/WonderSidePickMethod.kt
new file mode 100644
index 00000000..29fe2126
--- /dev/null
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/WonderSidePickMethod.kt
@@ -0,0 +1,28 @@
+package org.luxons.sevenwonders.game.data
+
+import java.util.Random
+
+enum class WonderSidePickMethod {
+ ALL_A {
+ override fun pickSide(random: Random, lastPickedSide: WonderSide?): WonderSide {
+ return WonderSide.A
+ }
+ },
+ ALL_B {
+ override fun pickSide(random: Random, lastPickedSide: WonderSide?): WonderSide {
+ return WonderSide.B
+ }
+ },
+ EACH_RANDOM {
+ override fun pickSide(random: Random, lastPickedSide: WonderSide?): WonderSide {
+ return if (random.nextBoolean()) WonderSide.A else WonderSide.B
+ }
+ },
+ SAME_RANDOM_FOR_ALL {
+ override fun pickSide(random: Random, lastPickedSide: WonderSide?): WonderSide {
+ return lastPickedSide ?: if (random.nextBoolean()) WonderSide.A else WonderSide.B
+ }
+ };
+
+ abstract fun pickSide(random: Random, lastPickedSide: WonderSide?): WonderSide
+}
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
new file mode 100644
index 00000000..2827564b
--- /dev/null
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/CardDefinition.kt
@@ -0,0 +1,20 @@
+package org.luxons.sevenwonders.game.data.definitions
+
+import org.luxons.sevenwonders.game.cards.Card
+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 effect: EffectsDefinition,
+ private val chainParent: String? = null,
+ private val chainChildren: List<String> = emptyList(),
+ private val image: String? = null,
+ private val countPerNbPlayer: Map<Int, Int>
+) {
+ fun create(nbPlayers: Int): List<Card> = List( countPerNbPlayer[nbPlayers]!!) { create() }
+
+ fun create(): Card = Card(name, color, requirements, effect.create(), chainParent, chainChildren, image)
+}
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
new file mode 100644
index 00000000..a09f0642
--- /dev/null
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/DecksDefinition.kt
@@ -0,0 +1,53 @@
+package org.luxons.sevenwonders.game.data.definitions
+
+import org.luxons.sevenwonders.game.Settings
+import org.luxons.sevenwonders.game.cards.Card
+import org.luxons.sevenwonders.game.cards.CardBack
+import org.luxons.sevenwonders.game.cards.Decks
+
+internal class DecksDefinition(
+ private val age1: List<CardDefinition>,
+ private val age2: List<CardDefinition>,
+ private val age3: List<CardDefinition>,
+ private val age1Back: String,
+ private val age2Back: String,
+ private val age3Back: String,
+ private val guildCards: List<CardDefinition>
+) {
+ fun prepareDecks(settings: Settings): Decks {
+ val cardsPerAge = mapOf(
+ 1 to prepareStandardDeck(age1, settings, age1Back),
+ 2 to prepareStandardDeck(age2, settings, age2Back),
+ 3 to prepareAge3Deck(settings)
+ )
+ return Decks(cardsPerAge)
+ }
+
+ private fun prepareStandardDeck(defs: List<CardDefinition>, settings: Settings, backImage: String): List<Card> {
+ val back = CardBack(backImage)
+ val cards = createDeck(defs, settings, back).toMutableList()
+ cards.shuffle(settings.random)
+ return cards
+ }
+
+ private fun prepareAge3Deck(settings: Settings): List<Card> {
+ val back = CardBack(age3Back)
+ val age3deck = createDeck(age3, settings, back).toMutableList()
+ age3deck.addAll(createGuildCards(settings, back))
+ age3deck.shuffle(settings.random)
+ return age3deck
+ }
+
+ private fun createDeck(defs: List<CardDefinition>, settings: Settings, back: CardBack): List<Card> {
+ return defs.flatMap { it.create(settings.nbPlayers) }.onEach { it.back = back }
+ }
+
+ private fun createGuildCards(settings: Settings, back: CardBack): List<Card> {
+ val guild = guildCards
+ .map { it.create() }
+ .map { c -> c.back = back; c }
+ .toMutableList()
+ guild.shuffle(settings.random)
+ return guild.subList(0, settings.nbPlayers + 2)
+ }
+}
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
new file mode 100644
index 00000000..978ec4a6
--- /dev/null
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/EffectsDefinition.kt
@@ -0,0 +1,53 @@
+package org.luxons.sevenwonders.game.data.definitions
+
+import org.luxons.sevenwonders.game.effects.BonusPerBoardElement
+import org.luxons.sevenwonders.game.effects.Discount
+import org.luxons.sevenwonders.game.effects.Effect
+import org.luxons.sevenwonders.game.effects.GoldIncrease
+import org.luxons.sevenwonders.game.effects.MilitaryReinforcements
+import org.luxons.sevenwonders.game.effects.ProductionIncrease
+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 data class EffectsDefinition(
+ private val gold: GoldIncrease? = null,
+ private val military: MilitaryReinforcements? = null,
+ private val science: ScienceProgress? = null,
+ private val discount: Discount? = null,
+ private val perBoardElement: BonusPerBoardElement? = null,
+ private val production: ProductionIncrease? = null,
+ 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
+ }
+}
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/WonderDefinition.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/WonderDefinition.kt
new file mode 100644
index 00000000..558f16e8
--- /dev/null
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/WonderDefinition.kt
@@ -0,0 +1,21 @@
+package org.luxons.sevenwonders.game.data.definitions
+
+import org.luxons.sevenwonders.game.Settings
+import org.luxons.sevenwonders.game.data.WonderSide
+import org.luxons.sevenwonders.game.wonders.Wonder
+
+internal data class WonderDefinition(
+ private val name: String,
+ private val sides: Map<WonderSide, WonderSideDefinition>
+) {
+ fun create(settings: Settings): Wonder {
+ val wonder = Wonder()
+ wonder.name = name
+
+ val wonderSideDef = sides[settings.pickWonderSide()]!!
+ wonder.initialResource = wonderSideDef.initialResource
+ wonder.stages = wonderSideDef.createStages()
+ wonder.image = wonderSideDef.image
+ return wonder
+ }
+}
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/WonderSideDefinition.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/WonderSideDefinition.kt
new file mode 100644
index 00000000..247432e3
--- /dev/null
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/WonderSideDefinition.kt
@@ -0,0 +1,14 @@
+package org.luxons.sevenwonders.game.data.definitions
+
+import org.luxons.sevenwonders.game.resources.ResourceType
+import org.luxons.sevenwonders.game.wonders.WonderStage
+
+internal class WonderSideDefinition(
+ val initialResource: ResourceType,
+ private val stages: List<WonderStageDefinition>,
+ val image: String
+) {
+ fun createStages(): List<WonderStage> {
+ return stages.map { def -> def.create() }
+ }
+}
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/WonderStageDefinition.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/WonderStageDefinition.kt
new file mode 100644
index 00000000..3d2872d0
--- /dev/null
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/definitions/WonderStageDefinition.kt
@@ -0,0 +1,13 @@
+package org.luxons.sevenwonders.game.data.definitions
+
+import org.luxons.sevenwonders.game.cards.Requirements
+import org.luxons.sevenwonders.game.wonders.WonderStage
+
+internal class WonderStageDefinition(
+ private val requirements: Requirements,
+ private val effects: EffectsDefinition
+) {
+ fun create(): WonderStage {
+ return WonderStage(requirements, effects.create())
+ }
+}
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/NumericEffectSerializer.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/NumericEffectSerializer.kt
new file mode 100644
index 00000000..510a511c
--- /dev/null
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/NumericEffectSerializer.kt
@@ -0,0 +1,40 @@
+package org.luxons.sevenwonders.game.data.serializers
+
+import java.lang.reflect.Type
+
+import org.luxons.sevenwonders.game.effects.Effect
+import org.luxons.sevenwonders.game.effects.GoldIncrease
+import org.luxons.sevenwonders.game.effects.MilitaryReinforcements
+import org.luxons.sevenwonders.game.effects.RawPointsIncrease
+
+import com.google.gson.JsonDeserializationContext
+import com.google.gson.JsonDeserializer
+import com.google.gson.JsonElement
+import com.google.gson.JsonParseException
+import com.google.gson.JsonPrimitive
+import com.google.gson.JsonSerializationContext
+import com.google.gson.JsonSerializer
+
+class NumericEffectSerializer : JsonSerializer<Effect>, JsonDeserializer<Effect> {
+
+ override fun serialize(effect: Effect, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
+ val value: Int = when (effect) {
+ is MilitaryReinforcements -> effect.count
+ is GoldIncrease -> effect.amount
+ is RawPointsIncrease -> effect.points
+ else -> throw IllegalArgumentException("Unknown numeric effect " + effect.javaClass.name)
+ }
+ return JsonPrimitive(value)
+ }
+
+ @Throws(JsonParseException::class)
+ override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Effect {
+ val value = json.asInt
+ return when (typeOfT) {
+ MilitaryReinforcements::class.java -> MilitaryReinforcements(value)
+ GoldIncrease::class.java -> GoldIncrease(value)
+ RawPointsIncrease::class.java -> RawPointsIncrease(value)
+ else -> throw IllegalArgumentException("Unknown numeric effet " + typeOfT.typeName)
+ }
+ }
+}
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/ProductionIncreaseSerializer.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/ProductionIncreaseSerializer.kt
new file mode 100644
index 00000000..578f816b
--- /dev/null
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/ProductionIncreaseSerializer.kt
@@ -0,0 +1,51 @@
+package org.luxons.sevenwonders.game.data.serializers
+
+import com.google.gson.JsonDeserializationContext
+import com.google.gson.JsonDeserializer
+import com.google.gson.JsonElement
+import com.google.gson.JsonParseException
+import com.google.gson.JsonPrimitive
+import com.google.gson.JsonSerializationContext
+import com.google.gson.JsonSerializer
+import org.luxons.sevenwonders.game.effects.ProductionIncrease
+import org.luxons.sevenwonders.game.resources.Production
+import java.lang.reflect.Type
+
+class ProductionIncreaseSerializer : JsonSerializer<ProductionIncrease>, JsonDeserializer<ProductionIncrease> {
+
+ override fun serialize(
+ productionIncrease: ProductionIncrease,
+ typeOfSrc: Type,
+ context: JsonSerializationContext
+ ): JsonElement {
+ val production = productionIncrease.production
+ val json = context.serialize(production)
+ return if (!json.isJsonNull && !productionIncrease.isSellable) { JsonPrimitive("(${json.asString})")} else json
+ }
+
+ @Throws(JsonParseException::class)
+ override fun deserialize(
+ json: JsonElement,
+ typeOfT: Type,
+ context: JsonDeserializationContext
+ ): ProductionIncrease {
+ var json = json
+ val productionIncrease = ProductionIncrease()
+
+ var resourcesStr = json.asString
+ val isSellable = !resourcesStr.startsWith("(")
+ if (!isSellable) {
+ resourcesStr = unwrapBrackets(resourcesStr)
+ json = JsonPrimitive(resourcesStr)
+ }
+ productionIncrease.isSellable = isSellable
+
+ val production = context.deserialize<Production>(json, Production::class.java)
+ productionIncrease.production = production
+ return productionIncrease
+ }
+
+ private fun unwrapBrackets(str: String): String {
+ return str.substring(1, str.length - 1)
+ }
+}
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/ProductionSerializer.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/ProductionSerializer.kt
new file mode 100644
index 00000000..538fdbb4
--- /dev/null
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/ProductionSerializer.kt
@@ -0,0 +1,58 @@
+package org.luxons.sevenwonders.game.data.serializers
+
+import com.google.gson.JsonDeserializationContext
+import com.google.gson.JsonDeserializer
+import com.google.gson.JsonElement
+import com.google.gson.JsonNull
+import com.google.gson.JsonParseException
+import com.google.gson.JsonSerializationContext
+import com.google.gson.JsonSerializer
+import org.luxons.sevenwonders.game.resources.Production
+import org.luxons.sevenwonders.game.resources.ResourceType
+import org.luxons.sevenwonders.game.resources.Resources
+import java.lang.reflect.Type
+
+class ProductionSerializer : JsonSerializer<Production>, JsonDeserializer<Production> {
+
+ override fun serialize(production: Production, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
+ val fixedResources = production.fixedResources
+ val choices = production.alternativeResources
+ return when {
+ fixedResources.isEmpty -> serializeAsChoice(choices, context)
+ choices.isEmpty() -> serializeAsResources(fixedResources, context)
+ else -> throw IllegalArgumentException("Cannot serialize a production with mixed fixed resources and choices")
+ }
+ }
+
+ private fun serializeAsChoice(choices: Set<Set<ResourceType>>, context: JsonSerializationContext): JsonElement {
+ if (choices.isEmpty()) {
+ return JsonNull.INSTANCE
+ }
+ if (choices.size > 1) {
+ throw IllegalArgumentException("Cannot serialize a production with more than one choice")
+ }
+ val str = choices.flatMap { it }.map { it.symbol }.joinToString("/")
+ return context.serialize(str)
+ }
+
+ private fun serializeAsResources(fixedResources: Resources, context: JsonSerializationContext): JsonElement {
+ return context.serialize(fixedResources)
+ }
+
+ @Throws(JsonParseException::class)
+ override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Production {
+ val resourcesStr = json.asString
+ val production = Production()
+ if (resourcesStr.contains("/")) {
+ production.addChoice(*createChoice(resourcesStr))
+ } else {
+ val fixedResources = context.deserialize<Resources>(json, Resources::class.java)
+ production.addAll(fixedResources)
+ }
+ return production
+ }
+
+ private fun createChoice(choiceStr: String): Array<ResourceType> {
+ return choiceStr.split("/").map { ResourceType.fromSymbol(it) }.toTypedArray()
+ }
+}
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/ResourceTypeSerializer.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/ResourceTypeSerializer.kt
new file mode 100644
index 00000000..1de9334a
--- /dev/null
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/ResourceTypeSerializer.kt
@@ -0,0 +1,29 @@
+package org.luxons.sevenwonders.game.data.serializers
+
+import java.lang.reflect.Type
+
+import org.luxons.sevenwonders.game.resources.ResourceType
+
+import com.google.gson.JsonDeserializationContext
+import com.google.gson.JsonDeserializer
+import com.google.gson.JsonElement
+import com.google.gson.JsonParseException
+import com.google.gson.JsonPrimitive
+import com.google.gson.JsonSerializationContext
+import com.google.gson.JsonSerializer
+
+internal class ResourceTypeSerializer : JsonSerializer<ResourceType>, JsonDeserializer<ResourceType> {
+
+ override fun serialize(type: ResourceType, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
+ return JsonPrimitive(type.symbol!!)
+ }
+
+ @Throws(JsonParseException::class)
+ override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): ResourceType {
+ val str = json.asString
+ if (str.isEmpty()) {
+ throw IllegalArgumentException("Empty string is not a valid resource type")
+ }
+ return ResourceType.fromSymbol(str[0])
+ }
+}
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/ResourceTypesSerializer.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/ResourceTypesSerializer.kt
new file mode 100644
index 00000000..9ba21043
--- /dev/null
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/ResourceTypesSerializer.kt
@@ -0,0 +1,39 @@
+package org.luxons.sevenwonders.game.data.serializers
+
+import java.lang.reflect.Type
+
+import org.luxons.sevenwonders.game.resources.ResourceType
+
+import com.google.gson.JsonDeserializationContext
+import com.google.gson.JsonDeserializer
+import com.google.gson.JsonElement
+import com.google.gson.JsonParseException
+import com.google.gson.JsonPrimitive
+import com.google.gson.JsonSerializationContext
+import com.google.gson.JsonSerializer
+
+internal class ResourceTypesSerializer : JsonSerializer<List<ResourceType>>, JsonDeserializer<List<ResourceType>> {
+
+ override fun serialize(
+ resources: List<ResourceType>,
+ typeOfSrc: Type,
+ context: JsonSerializationContext
+ ): JsonElement {
+ val s = resources.map { it.symbol }.joinToString("")
+ return JsonPrimitive(s)
+ }
+
+ @Throws(JsonParseException::class)
+ override fun deserialize(
+ json: JsonElement,
+ typeOfT: Type,
+ context: JsonDeserializationContext
+ ): List<ResourceType> {
+ val s = json.asString
+ val resources = ArrayList<ResourceType>()
+ for (c in s.toCharArray()) {
+ resources.add(ResourceType.fromSymbol(c))
+ }
+ return resources
+ }
+}
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/ResourcesSerializer.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/ResourcesSerializer.kt
new file mode 100644
index 00000000..2baf7a35
--- /dev/null
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/ResourcesSerializer.kt
@@ -0,0 +1,34 @@
+package org.luxons.sevenwonders.game.data.serializers
+
+import java.lang.reflect.Type
+import java.util.stream.Collectors
+
+import org.luxons.sevenwonders.game.resources.ResourceType
+import org.luxons.sevenwonders.game.resources.Resources
+
+import com.google.gson.JsonDeserializationContext
+import com.google.gson.JsonDeserializer
+import com.google.gson.JsonElement
+import com.google.gson.JsonNull
+import com.google.gson.JsonParseException
+import com.google.gson.JsonPrimitive
+import com.google.gson.JsonSerializationContext
+import com.google.gson.JsonSerializer
+
+internal class ResourcesSerializer : JsonSerializer<Resources>, JsonDeserializer<Resources> {
+
+ override fun serialize(resources: Resources, typeOfSrc: Type, context: JsonSerializationContext): JsonElement {
+ val s = resources.asList().map { it.symbol }.joinToString("")
+ return if (s.isEmpty()) JsonNull.INSTANCE else JsonPrimitive(s)
+ }
+
+ @Throws(JsonParseException::class)
+ override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Resources {
+ val s = json.asString
+ val resources = Resources()
+ for (c in s.toCharArray()) {
+ resources.add(ResourceType.fromSymbol(c), 1)
+ }
+ return resources
+ }
+}
diff --git a/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/ScienceProgressSerializer.kt b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/ScienceProgressSerializer.kt
new file mode 100644
index 00000000..ed383d63
--- /dev/null
+++ b/game-engine/src/main/kotlin/org/luxons/sevenwonders/game/data/serializers/ScienceProgressSerializer.kt
@@ -0,0 +1,57 @@
+package org.luxons.sevenwonders.game.data.serializers
+
+import com.google.gson.JsonDeserializationContext
+import com.google.gson.JsonDeserializer
+import com.google.gson.JsonElement
+import com.google.gson.JsonNull
+import com.google.gson.JsonParseException
+import com.google.gson.JsonPrimitive
+import com.google.gson.JsonSerializationContext
+import com.google.gson.JsonSerializer
+import org.luxons.sevenwonders.game.boards.Science
+import org.luxons.sevenwonders.game.boards.ScienceType
+import org.luxons.sevenwonders.game.effects.ScienceProgress
+import java.lang.reflect.Type
+
+internal class ScienceProgressSerializer : JsonSerializer<ScienceProgress>, JsonDeserializer<ScienceProgress> {
+
+ override fun serialize(
+ scienceProgress: ScienceProgress,
+ typeOfSrc: Type,
+ context: JsonSerializationContext
+ ): JsonElement {
+ val science = scienceProgress.science
+
+ if (science.size() > 1) {
+ throw UnsupportedOperationException("Cannot serialize science containing more than one element")
+ }
+
+ for (type in ScienceType.values()) {
+ val quantity = science.getQuantity(type)
+ if (quantity == 1) {
+ return context.serialize(type)
+ }
+ }
+
+ return if (science.jokers == 1) JsonPrimitive("any") else JsonNull.INSTANCE
+ }
+
+ @Throws(JsonParseException::class)
+ override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): ScienceProgress {
+ val s = json.asString
+ val scienceProgress = ScienceProgress()
+ val science = Science()
+ if ("any" == s) {
+ science.addJoker(1)
+ } else {
+ science.add(deserializeScienceType(json, context), 1)
+ }
+ scienceProgress.science = science
+ return scienceProgress
+ }
+
+ private fun deserializeScienceType(json: JsonElement, context: JsonDeserializationContext): ScienceType {
+ return context.deserialize<ScienceType>(json, ScienceType::class.java)
+ ?: throw IllegalArgumentException("Invalid science type " + json.asString)
+ }
+}
bgstack15