diff options
Diffstat (limited to 'game-engine/src/main/kotlin/org')
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) + } +} |