11package net.zomis.games.impl
22
33import net.zomis.games.cards.CardZone
4+ import net.zomis.games.common.next
45import net.zomis.games.dsl.*
56import kotlin.math.absoluteValue
67
78object SpiceRoadDsl {
89 data class PlayParameter (val card : SpiceRoadGameModel .ActionCard , val remove : SpiceRoadGameModel .Caravan , val add : SpiceRoadGameModel .Caravan )
10+ data class AcquireParameter (val card : SpiceRoadGameModel .ActionCard , val payArray : List <SpiceRoadGameModel .Spice >)
911
1012 val factory = GameCreator (SpiceRoadGameModel ::class )
1113 val play = factory.action(" play" , PlayParameter ::class )
1214 val claim = factory.action(" claim" , SpiceRoadGameModel .PointCard ::class )
1315 val rest = factory.action(" rest" , Unit ::class )
14- val acquire = factory.action(" acquire" , SpiceRoadGameModel . ActionCard ::class )
16+ val acquire = factory.action(" acquire" , AcquireParameter ::class )
1517 val game = factory.game(" Spice Road" ) {
1618 this .setup {
1719 this .players(2 .. 5 )
@@ -33,8 +35,10 @@ object SpiceRoadDsl {
3335 this .view(" silverCoins" ) { game.silverCoins.size }
3436 this .action(claim).requires { game.currentPlayer.caravan.has(this .action.parameter.cost) }
3537 this .action(claim).effect {
38+ // TODO add gold and silver logic
3639 game.currentPlayer.caravan - = this .action.parameter.cost
3740 game.currentPlayer.points + = this .action.parameter.points
41+ game.currentPlayer.pointCards++
3842 game.visiblePointCards.card(this .action.parameter).remove()
3943 if (game.pointsDeck.size > 0 ) {
4044 game.pointsDeck.random(this .replayable, 1 , " NewPointCard" ) { it.toStateString() }.forEach { it.moveTo(game.visiblePointCards) }
@@ -54,7 +58,8 @@ object SpiceRoadDsl {
5458 card.gain != null -> parameter(PlayParameter (card, SpiceRoadGameModel .Caravan (), card.gain))
5559 card.upgrade != null -> {
5660 fun rec (scope : ActionChoicesNextScope <SpiceRoadGameModel , PlayParameter >,
57- remaining : SpiceRoadGameModel .Caravan , upgrades : Int ,
61+ remaining : SpiceRoadGameModel .Caravan ,
62+ upgrades : Int ,
5863 remove : SpiceRoadGameModel .Caravan = SpiceRoadGameModel .Caravan (),
5964 add : SpiceRoadGameModel .Caravan = SpiceRoadGameModel .Caravan ()) {
6065 scope.parameter(PlayParameter (card, remove, add))
@@ -78,14 +83,60 @@ object SpiceRoadDsl {
7883 }
7984 }
8085 }
86+ this .action(acquire).effect {
87+ game.currentPlayer.caravan - = action.parameter.payArray.fold(SpiceRoadGameModel .Caravan (), { acc, x -> acc + x.toCaravan() })
88+ game.visibleActionCards.cards.mapIndexed { index, card -> card.addSpice(action.parameter.payArray.getOrNull(index)) }
89+
90+ game.currentPlayer.caravan + = action.parameter.card.takeAllSpice()
91+ game.visibleActionCards.card(action.parameter.card).moveTo(game.currentPlayer.hand)
92+
93+ if (game.actionDeck.size > 0 ) {
94+ game.actionDeck.random(this .replayable, 1 , " NewActionCard" ) { it.toStateString() }.forEach { it.moveTo(game.visibleActionCards) }
95+ }
96+ }
97+ this .action(acquire).choose {
98+ options({ game.visibleActionCards.cards.filterIndexed { index, _ -> index <= game.currentPlayer.caravan.count } }) { card ->
99+ fun rec (scope : ActionChoicesNextScope <SpiceRoadGameModel , AcquireParameter >,
100+ remaining : SpiceRoadGameModel .Caravan ,
101+ leftToPay : Int ,
102+ payList : List <SpiceRoadGameModel .Spice > = emptyList()
103+ ) {
104+ if (leftToPay <= 0 ) {
105+ scope.parameter(AcquireParameter (card, payList))
106+ return
107+ }
108+ scope.options({ remaining.spice.keys }) { payWith ->
109+ rec(this , remaining - payWith.toCaravan(), leftToPay - 1 , payList + payWith)
110+ }
111+ }
112+ rec(this , context.game.currentPlayer.caravan, context.game.visibleActionCards.card(card).index)
113+ }
114+ }
115+ this .allActions.precondition { game.currentPlayer.index == playerIndex }
116+ this .allActions.after {
117+ val gameEnd = when (game.playerCount) {
118+ 1 , 2 , 3 -> game.currentPlayer.pointCards == 6
119+ else -> game.currentPlayer.pointCards == 5
120+ }
121+ if (gameEnd) {
122+ when (game.turnsLeft) {
123+ - 1 -> game.turnsLeft = game.playerCount - (game.currentPlayerIndex + 1 )
124+ 0 -> this .eliminations.eliminateBy(game.players.mapIndexed { index, player -> index to player }, compareBy({ it.points }, { + it.index }))
125+ else -> game.turnsLeft--
126+ }
127+ }
128+ }
129+ this .allActions.after { game.currentPlayerIndex = game.currentPlayerIndex.next(game.playerCount) }
130+
81131 }
82132 }
83133}
84134
85135class SpiceRoadGameModel (val playerCount : Int ) {
86136 // Turn: Action -> Caravan Limit (discard to hand size) (-> Game end trigger check)
87137 // Actions: acquire, claim, rest, play
88- val currentPlayerIndex = 0
138+ var turnsLeft = - 1
139+ var currentPlayerIndex = 0
89140 val currentPlayer: Player get() = players[currentPlayerIndex]
90141 val players = (0 until playerCount).map { Player (it) }
91142 val pointsDeck = CardZone <PointCard >(pointsCards.split(" \n " ).map { x -> x.split(" ," ) }.map { (x, y) -> PointCard (x.toInt(), y.toCaravan()!! ) }.toMutableList())
@@ -104,9 +155,22 @@ class SpiceRoadGameModel(val playerCount: Int) {
104155 val silverCoins = (0 until playerCount * 2 ).map { Coin (1 ) }
105156
106157 class ActionCard (val upgrade : Int? , val gain : Caravan ? , val trade : Pair <Caravan , Caravan >? ) {
158+ var spiceOnMe = Caravan ()
107159 fun toStateString (): String = " $upgrade $gain ${trade?.first} ->${trade?.second} "
108160
109- fun toViewable (): Map <String , Any ?> = mapOf (" upgrade" to upgrade, " gain" to gain?.toViewable(), " trade" to if (trade == null ) null else mapOf (" give" to trade.first.toViewable(), " get" to trade.second.toViewable()))
161+ fun toViewable (): Map <String , Any ?> = mapOf (" upgrade" to upgrade, " gain" to gain?.toViewable(), " trade" to if (trade == null ) null else mapOf (" give" to trade.first.toViewable(), " get" to trade.second.toViewable()), " bonusSpice" to spiceOnMe.toViewable())
162+
163+ fun addSpice (spice : Spice ? ) {
164+ if (spice != null ) {
165+ spiceOnMe + = spice.toCaravan()
166+ }
167+ }
168+
169+ fun takeAllSpice (): Caravan {
170+ val tmp = spiceOnMe
171+ spiceOnMe = Caravan ()
172+ return tmp
173+ }
110174 }
111175
112176 class PointCard (val points : Int , val cost : Caravan ) {
@@ -130,6 +194,7 @@ class SpiceRoadGameModel(val playerCount: Int) {
130194 ActionCard (null , Spice .YELLOW .toCaravan(2 ), null ))
131195 )
132196 var points = 0
197+ var pointCards = 0
133198
134199 fun toViewable (): Map <String , Any ?> {
135200 return mapOf (
0 commit comments