diff options
Diffstat (limited to 'sw-common-model/src/commonMain/kotlin/org/luxons')
9 files changed, 317 insertions, 0 deletions
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/Moves.kt b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/Moves.kt new file mode 100644 index 00000000..79a238b0 --- /dev/null +++ b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/Moves.kt @@ -0,0 +1,49 @@ +package org.luxons.sevenwonders.game.api + +import org.luxons.sevenwonders.game.api.cards.HandCard +import org.luxons.sevenwonders.game.api.cards.TableCard +import org.luxons.sevenwonders.game.api.resources.ResourceTransactions +import org.luxons.sevenwonders.game.api.resources.noTransactions +import org.luxons.sevenwonders.game.api.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: ApiTable, + 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 PlayedMove( + val playerIndex: Int, + val type: MoveType, + val card: TableCard, + val transactions: ResourceTransactions +) + +data class PlayerMove( + val type: MoveType, + val cardName: String, + val transactions: ResourceTransactions = noTransactions() +) + +enum class MoveType { + PLAY, + PLAY_FREE, + UPGRADE_WONDER, + DISCARD, + COPY_GUILD; +} 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..62f66b21 --- /dev/null +++ b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/Table.kt @@ -0,0 +1,15 @@ +package org.luxons.sevenwonders.game.api + +import org.luxons.sevenwonders.game.api.boards.ApiBoard +import org.luxons.sevenwonders.game.api.cards.HandRotationDirection + +typealias Age = Int + +data class ApiTable( + val boards: List<ApiBoard>, + val currentAge: Age, + val handRotationDirection: HandRotationDirection, + val lastPlayedMoves: List<PlayedMove> +) { + val nbPlayers: Int = boards.size +} diff --git a/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/boards/Boards.kt b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/boards/Boards.kt new file mode 100644 index 00000000..061bdcad --- /dev/null +++ b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/boards/Boards.kt @@ -0,0 +1,40 @@ +package org.luxons.sevenwonders.game.api.boards + +import org.luxons.sevenwonders.game.api.cards.TableCard +import org.luxons.sevenwonders.game.api.resources.CountedResource +import org.luxons.sevenwonders.game.api.resources.ResourceType +import org.luxons.sevenwonders.game.api.wonders.ApiWonder + +data class ApiBoard( + 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<CountedResource> = emptyList() +) + +data class ApiProduction( + val fixedResources: List<CountedResource>, + val alternativeResources: Set<Set<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/boards/RelativeBoardPosition.kt b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/boards/RelativeBoardPosition.kt new file mode 100644 index 00000000..c7c3b5dc --- /dev/null +++ b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/boards/RelativeBoardPosition.kt @@ -0,0 +1,16 @@ +package org.luxons.sevenwonders.game.api.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/api/cards/Cards.kt b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/cards/Cards.kt new file mode 100644 index 00000000..4ccfe23b --- /dev/null +++ b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/cards/Cards.kt @@ -0,0 +1,65 @@ +package org.luxons.sevenwonders.game.api.cards + +import org.luxons.sevenwonders.game.api.boards.ApiRequirements +import org.luxons.sevenwonders.game.api.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/api/cards/HandRotationDirection.kt b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/cards/HandRotationDirection.kt new file mode 100644 index 00000000..b4669fbb --- /dev/null +++ b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/cards/HandRotationDirection.kt @@ -0,0 +1,11 @@ +package org.luxons.sevenwonders.game.api.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/api/resources/Resources.kt b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/resources/Resources.kt new file mode 100644 index 00000000..fcfdd634 --- /dev/null +++ b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/resources/Resources.kt @@ -0,0 +1,44 @@ +package org.luxons.sevenwonders.game.api.resources + +import org.luxons.sevenwonders.game.api.boards.RelativeBoardPosition + +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'") + } +} + +data class CountedResource( + val count: Int, + val type: ResourceType +) + +enum class Provider(val boardPosition: RelativeBoardPosition) { + LEFT_PLAYER(RelativeBoardPosition.LEFT), + RIGHT_PLAYER(RelativeBoardPosition.RIGHT) +} + +data class ResourceTransaction(val provider: Provider, val resources: List<CountedResource>) + +typealias ResourceTransactions = Collection<ResourceTransaction> + +fun noTransactions(): ResourceTransactions = emptySet() diff --git a/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/wonders/Wonders.kt b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/wonders/Wonders.kt new file mode 100644 index 00000000..7148a924 --- /dev/null +++ b/sw-common-model/src/commonMain/kotlin/org/luxons/sevenwonders/game/api/wonders/Wonders.kt @@ -0,0 +1,32 @@ +package org.luxons.sevenwonders.game.api.wonders + +import org.luxons.sevenwonders.game.api.boards.ApiRequirements +import org.luxons.sevenwonders.game.api.cards.CardBack +import org.luxons.sevenwonders.game.api.cards.PlayabilityLevel +import org.luxons.sevenwonders.game.api.resources.ResourceTransactions +import org.luxons.sevenwonders.game.api.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 +} |