diff options
Diffstat (limited to 'sw-common-model')
13 files changed, 366 insertions, 0 deletions
diff --git a/sw-common-model/build.gradle b/sw-common-model/build.gradle new file mode 100644 index 00000000..b8bdb97b --- /dev/null +++ b/sw-common-model/build.gradle @@ -0,0 +1,42 @@ +plugins { + id 'kotlin-multiplatform' +} + +kotlin { + jvm() + js() + sourceSets { + commonMain { + dependencies { + implementation kotlin('stdlib-common') + } + } + commonTest { + dependencies { + implementation kotlin('test-common') + implementation kotlin('test-annotations-common') + } + } + jvmMain { + dependencies { + implementation kotlin('stdlib-jdk8') + } + } + jvmTest { + dependencies { + implementation kotlin('test') + implementation kotlin('test-junit') + } + } + jsMain { + dependencies { + implementation kotlin('stdlib-js') + } + } + jsTest { + dependencies { + implementation kotlin('test-js') + } + } + } +} diff --git a/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/Boards.kt b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/Boards.kt new file mode 100644 index 00000000..698615e9 --- /dev/null +++ b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/Boards.kt @@ -0,0 +1,44 @@ +package org.luxons.sevenwonders.game.api + +import org.luxons.sevenwonders.game.cards.TableCard +import org.luxons.sevenwonders.game.resources.ResourceType +import org.luxons.sevenwonders.game.wonders.ApiWonder + +data class Board( + val playerIndex: Int, + val wonder: ApiWonder, + val production: ApiProduction, + val publicProduction: ApiProduction, + val science: ApiScience, + val military: ApiMilitary, + val playedCards: List<List<TableCard>>, + val gold: Int +) + +data class ApiRequirements( + val gold: Int = 0, + val resources: List<ApiCountedResource> = emptyList() +) + +data class ApiProduction( + val fixedResources: List<ApiCountedResource>, + val alternativeResources: Set<Set<ResourceType>> +) + +data class ApiCountedResource( + val count: Int, + val type: ResourceType +) + +data class ApiMilitary( + val nbShields: Int, + val totalPoints: Int, + val nbDefeatTokens: Int +) + +data class ApiScience( + val jokers: Int, + val nbWheels: Int, + val nbCompasses: Int, + val nbTablets: Int +) diff --git a/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/CustomizableSettings.kt b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/CustomizableSettings.kt new file mode 100644 index 00000000..ac2c2b14 --- /dev/null +++ b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/CustomizableSettings.kt @@ -0,0 +1,45 @@ +package org.luxons.sevenwonders.game.api + +import kotlin.random.Random + +data class CustomizableSettings( + val randomSeedForTests: Long? = null, + val timeLimitInSeconds: Int = 45, + val wonderSidePickMethod: WonderSidePickMethod = WonderSidePickMethod.EACH_RANDOM, + val initialGold: Int = 3, + val discardedCardGold: Int = 3, + val defaultTradingCost: Int = 2, + val pointsPer3Gold: Int = 1, + val lostPointsPerDefeat: Int = 1, + val wonPointsPerVictoryPerAge: Map<Int, Int> = mapOf(1 to 1, 2 to 3, 3 to 5) +) + +enum class WonderSide { + A, + B +} + +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/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/PlayerTurnInfo.kt b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/PlayerTurnInfo.kt new file mode 100644 index 00000000..c5feb6c5 --- /dev/null +++ b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/PlayerTurnInfo.kt @@ -0,0 +1,35 @@ +package org.luxons.sevenwonders.game.api + +import org.luxons.sevenwonders.game.cards.HandCard +import org.luxons.sevenwonders.game.cards.TableCard +import org.luxons.sevenwonders.game.moves.MoveType +import org.luxons.sevenwonders.game.resources.ResourceTransactions +import org.luxons.sevenwonders.game.resources.noTransactions +import org.luxons.sevenwonders.game.wonders.WonderBuildability + +enum class Action(val message: String) { + PLAY("Pick the card you want to play or discard."), + PLAY_2("Pick the first card you want to play or discard. Note that you have the ability to play these 2 last cards. You will choose how to play the last one during your next turn."), + PLAY_LAST("You have the special ability to play your last card. Choose how you want to play it."), + PICK_NEIGHBOR_GUILD("Choose a Guild card (purple) that you want to copy from one of your neighbours."), + WAIT("Please wait for other players to perform extra actions.") +} + +data class PlayerTurnInfo( + val playerIndex: Int, + val table: Table, + val action: Action, + val hand: List<HandCard>, + val preparedMove: PlayedMove?, + val neighbourGuildCards: List<TableCard> +) { + val currentAge: Int = table.currentAge + val message: String = action.message + val wonderBuildability: WonderBuildability = table.boards[playerIndex].wonder.buildability +} + +data class PlayerMove( + val type: MoveType, + val cardName: String, + val transactions: ResourceTransactions = noTransactions() +) diff --git a/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/Table.kt b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/Table.kt new file mode 100644 index 00000000..23ab6ee2 --- /dev/null +++ b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/Table.kt @@ -0,0 +1,24 @@ +package org.luxons.sevenwonders.game.api + +import org.luxons.sevenwonders.game.cards.HandRotationDirection +import org.luxons.sevenwonders.game.cards.TableCard +import org.luxons.sevenwonders.game.moves.MoveType +import org.luxons.sevenwonders.game.resources.ResourceTransactions + +typealias Age = Int + +data class Table( + val boards: List<Board>, + val currentAge: Age, + val handRotationDirection: HandRotationDirection, + val lastPlayedMoves: List<PlayedMove> +) { + val nbPlayers: Int = boards.size +} + +data class PlayedMove( + val playerIndex: Int, + val type: MoveType, + val card: TableCard, + val transactions: ResourceTransactions +) diff --git a/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/boards/RelativeBoardPosition.kt b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/boards/RelativeBoardPosition.kt new file mode 100644 index 00000000..3a8387a3 --- /dev/null +++ b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/boards/RelativeBoardPosition.kt @@ -0,0 +1,16 @@ +package org.luxons.sevenwonders.game.boards + +enum class RelativeBoardPosition(private val offset: Int) { + LEFT(-1), + SELF(0), + RIGHT(1); + + fun getIndexFrom(playerIndex: Int, nbPlayers: Int): Int = (playerIndex + offset) floorMod nbPlayers +} + +fun neighboursPositions() = listOf(RelativeBoardPosition.LEFT, RelativeBoardPosition.RIGHT) + +private infix fun Int.floorMod(divisor: Int): Int { + val rem = this % divisor + return if (rem >= 0) rem else rem + divisor +} diff --git a/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/cards/Cards.kt b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/cards/Cards.kt new file mode 100644 index 00000000..ab0e0297 --- /dev/null +++ b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/cards/Cards.kt @@ -0,0 +1,65 @@ +package org.luxons.sevenwonders.game.cards + +import org.luxons.sevenwonders.game.api.ApiRequirements +import org.luxons.sevenwonders.game.resources.ResourceTransactions + +data class TableCard( + val name: String, + val color: Color, + val requirements: ApiRequirements, + val chainParent: String?, + val chainChildren: List<String>, + val image: String, + val back: CardBack, + val playedDuringLastMove: Boolean +) + +/** + * A card with contextual information relative to the hand it is sitting in. The extra information is especially useful + * because it frees the client from a painful business logic implementation. + */ +data class HandCard( + val name: String, + val color: Color, + val requirements: ApiRequirements, + val chainParent: String?, + val chainChildren: List<String>, + val image: String, + val back: CardBack, + val playability: CardPlayability +) + +data class CardBack(val image: String) + +enum class PlayabilityLevel { + CHAINABLE, + NO_REQUIREMENTS, + ENOUGH_RESOURCES, + ENOUGH_GOLD, + ENOUGH_GOLD_AND_RES, + REQUIRES_HELP, + MISSING_REQUIRED_GOLD, + MISSING_GOLD_FOR_RES, + UNAVAILABLE_RESOURCES, + INCOMPATIBLE_WITH_BOARD +} + +enum class Color(val isResource: Boolean) { + BROWN(true), + GREY(true), + YELLOW(false), + BLUE(false), + GREEN(false), + RED(false), + PURPLE(false) +} + +data class CardPlayability( + val isPlayable: Boolean, + val isChainable: Boolean = false, + val minPrice: Int = Int.MAX_VALUE, + val cheapestTransactions: Set<ResourceTransactions> = emptySet(), + val playabilityLevel: PlayabilityLevel +) { + val isFree: Boolean = minPrice == 0 +} diff --git a/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/cards/HandRotationDirection.kt b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/cards/HandRotationDirection.kt new file mode 100644 index 00000000..a10ec19f --- /dev/null +++ b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/cards/HandRotationDirection.kt @@ -0,0 +1,11 @@ +package org.luxons.sevenwonders.game.cards + +enum class HandRotationDirection { + LEFT, + RIGHT; + + companion object { + // clockwise (pass to the left) at age 1, and alternating + fun forAge(age: Int): HandRotationDirection = if (age % 2 == 0) RIGHT else LEFT + } +} diff --git a/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/moves/MoveType.kt b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/moves/MoveType.kt new file mode 100644 index 00000000..d982c100 --- /dev/null +++ b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/moves/MoveType.kt @@ -0,0 +1,9 @@ +package org.luxons.sevenwonders.game.moves + +enum class MoveType { + PLAY, + PLAY_FREE, + UPGRADE_WONDER, + DISCARD, + COPY_GUILD; +} diff --git a/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/resources/Provider.kt b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/resources/Provider.kt new file mode 100644 index 00000000..5d0f3159 --- /dev/null +++ b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/resources/Provider.kt @@ -0,0 +1,8 @@ +package org.luxons.sevenwonders.game.resources + +import org.luxons.sevenwonders.game.boards.RelativeBoardPosition + +enum class Provider(val boardPosition: RelativeBoardPosition) { + LEFT_PLAYER(RelativeBoardPosition.LEFT), + RIGHT_PLAYER(RelativeBoardPosition.RIGHT) +} diff --git a/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/resources/ResourceTransactions.kt b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/resources/ResourceTransactions.kt new file mode 100644 index 00000000..77a8670d --- /dev/null +++ b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/resources/ResourceTransactions.kt @@ -0,0 +1,9 @@ +package org.luxons.sevenwonders.game.resources + +import org.luxons.sevenwonders.game.api.ApiCountedResource + +typealias ResourceTransactions = Collection<ResourceTransaction> + +data class ResourceTransaction(val provider: Provider, val resources: List<ApiCountedResource>) + +fun noTransactions(): ResourceTransactions = emptySet() diff --git a/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/resources/ResourceType.kt b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/resources/ResourceType.kt new file mode 100644 index 00000000..5c92b887 --- /dev/null +++ b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/resources/ResourceType.kt @@ -0,0 +1,26 @@ +package org.luxons.sevenwonders.game.resources + +enum class ResourceType(val symbol: Char) { + WOOD('W'), + STONE('S'), + ORE('O'), + CLAY('C'), + GLASS('G'), + PAPYRUS('P'), + LOOM('L'); + + companion object { + + private val typesPerSymbol = values().map { it.symbol to it }.toMap() + + fun fromSymbol(symbol: String): ResourceType { + if (symbol.length != 1) { + throw IllegalArgumentException("The given symbol must be a valid single-char resource type, got $symbol") + } + return fromSymbol(symbol[0]) + } + + fun fromSymbol(symbol: Char?): ResourceType = + typesPerSymbol[symbol] ?: throw IllegalArgumentException("Unknown resource type symbol '$symbol'") + } +} diff --git a/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/wonders/Wonder.kt b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/wonders/Wonder.kt new file mode 100644 index 00000000..6480e935 --- /dev/null +++ b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/wonders/Wonder.kt @@ -0,0 +1,32 @@ +package org.luxons.sevenwonders.game.wonders + +import org.luxons.sevenwonders.game.api.ApiRequirements +import org.luxons.sevenwonders.game.cards.CardBack +import org.luxons.sevenwonders.game.cards.PlayabilityLevel +import org.luxons.sevenwonders.game.resources.ResourceTransactions +import org.luxons.sevenwonders.game.resources.ResourceType + +data class ApiWonder( + val name: String, + val initialResource: ResourceType, + val stages: List<ApiWonderStage>, + val image: String, + val nbBuiltStages: Int, + val buildability: WonderBuildability +) + +data class ApiWonderStage( + val cardBack: CardBack?, + val isBuilt: Boolean, + val requirements: ApiRequirements, + val builtDuringLastMove: Boolean +) + +data class WonderBuildability( + val isBuildable: Boolean, + val minPrice: Int = Int.MAX_VALUE, + val cheapestTransactions: Set<ResourceTransactions> = emptySet(), + val playabilityLevel: PlayabilityLevel +) { + val isFree: Boolean = minPrice == 0 +} |