Skip to content

Commit

Permalink
wip(trades-view): implementing trade on click
Browse files Browse the repository at this point in the history
  • Loading branch information
luigi-borriello00 committed Oct 10, 2023
1 parent 947fb60 commit 67bb761
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 58 deletions.
7 changes: 7 additions & 0 deletions src/main/scala/scatan/controllers/game/GameController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ import scatan.model.map.{RoadSpot, StructureSpot}
import scatan.views.game.GameView
import scatan.views.game.components.CardContextMap.CardType
import scatan.model.map.Hexagon
import scatan.model.components.ResourceType

trait GameController extends Controller[ApplicationState]:
def onRoadSpot(spot: RoadSpot): Unit
def onStructureSpot(spot: StructureSpot): Unit
def onTradeWithBank(offer: ResourceType, request: ResourceType): Unit
def nextTurn(): Unit
def rollDice(): Unit
def clickCard(card: CardType): Unit
Expand Down Expand Up @@ -71,3 +73,8 @@ private class GameControllerImpl(requirements: Controller.Requirements[GameView,
this.model
.updateGame(_.buildSettlement(spot))
.onError(view.displayMessage("Cannot build settlement here"))

override def onTradeWithBank(offer: ResourceType, request: ResourceType): Unit =
this.model
.updateGame(_.tradeWithBank(offer, request))
.onError(view.displayMessage("Cannot trade this cards with bank" + offer.toString() + request.toString()))
11 changes: 11 additions & 0 deletions src/main/scala/scatan/model/components/ResourceCard.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,19 @@ enum ResourceType:
case Wheat
case Rock

object ResourceType:
def withName(name: String): ResourceType =
name match
case "Wood" => Wood
case "Brick" => Brick
case "Sheep" => Sheep
case "Wheat" => Wheat
case "Rock" => Rock

final case class ResourceCard(resourceType: ResourceType)

extension (card: ResourceCard) def *(amount: Int): Seq[ResourceCard] = Seq.fill(amount)(card)

type ResourceCards = Map[ScatanPlayer, Seq[ResourceCard]]

object ResourceCards:
Expand Down
14 changes: 13 additions & 1 deletion src/main/scala/scatan/model/game/ScatanEffects.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import scatan.model.game.ops.CardOps.assignResourceCard
import scatan.model.game.ops.TradeOps.tradeWithPlayer
import scatan.model.game.ops.CardOps.assignResourcesFromNumber
import scatan.model.game.ops.RobberOps.moveRobber
import scatan.model.components.ResourceType
import scatan.model.game.ops.TradeOps.tradeWithBank
import scatan.model.components.*

object ScatanEffects:

Expand Down Expand Up @@ -55,7 +58,16 @@ object ScatanEffects:

def PlayDevelopmentCardEffect(): Effect[PlayDevelopmentCard.type, ScatanState] = EmptyEffect

def TradeWithBankEffect(): Effect[TradeWithBank.type, ScatanState] = EmptyEffect
def TradeWithBankEffect(
player: ScatanPlayer,
offer: ResourceType,
request: ResourceType
): Effect[TradeWithBank.type, ScatanState] = (state: ScatanState) =>
state.tradeWithBank(
player,
offer,
request
)

def TradeWithPlayerEffect(
sender: ScatanPlayer,
Expand Down
6 changes: 5 additions & 1 deletion src/main/scala/scatan/model/game/ScatanGame.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import scatan.model.map.{Hexagon, RoadSpot, StructureSpot}

import scala.util.Random
import scatan.model.components.ResourceCard
import scatan.model.components.ResourceType

/** The status of a game of Scatan. It contains all the data without any possible action.
* @param game
Expand Down Expand Up @@ -78,7 +79,10 @@ private trait ScatanGameActions extends ScatanGameStatus:
play(ScatanActions.BuyDevelopmentCard)(using BuyDevelopmentCardEffect(game.turn.player, game.turn.number))

def playDevelopmentCard: Option[ScatanGame] = ???
def tradeWithBank: Option[ScatanGame] = ???

def tradeWithBank(offer: ResourceType, request: ResourceType): Option[ScatanGame] =
play(ScatanActions.TradeWithBank)(using TradeWithBankEffect(game.turn.player, offer, request))

def tradeWithPlayer(
receiver: ScatanPlayer,
senderTradeCards: Seq[ResourceCard],
Expand Down
24 changes: 13 additions & 11 deletions src/main/scala/scatan/model/game/ops/TradeOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import scatan.model.components.ResourceCard
import scatan.model.game.ops.CardOps.removeResourceCard
import scatan.model.game.ops.CardOps.assignResourceCard
import scatan.views.game.components.ContextMap.resources
import scatan.model.components.ResourceType

object TradeOps:
val tradeWithBankRequiredCards = 4
Expand Down Expand Up @@ -34,23 +35,24 @@ object TradeOps:
*
* @param player,
* the player that will trade with the bank
* @param playerCards,
* the cards that the player will give to the bank
* @param bankCard,
* the card that the bank will give to the player
* @param playerCardsType,
* the cards type that the player will give to the bank
* @param bankCardType,
* the card type that the bank will give to the player
* @return
* Some(state) if the trade is allowed, None otherwise
*/
def tradeWithBank(
player: ScatanPlayer,
playerCards: Seq[ResourceCard],
bankCard: ResourceCard
playerCardsType: ResourceType,
bankCardType: ResourceType
): Option[ScatanState] =
if playerCards.sizeIs == tradeWithBankRequiredCards && playerCards.forall(
_.resourceType == playerCards.head.resourceType
)
println("" + state.resourceCards(player).count(_.resourceType == playerCardsType))
if state.resourceCards(player).count(_.resourceType == playerCardsType) >= tradeWithBankRequiredCards
then
playerCards
state
.resourceCards(player)
// FIX ME: This is a hack to remove 4 cards of the same type
.foldLeft(Option(state))((state, card) => state.flatMap(_.removeResourceCard(player, card)))
.flatMap(_.assignResourceCard(player, bankCard))
.flatMap(_.assignResourceCard(player, ResourceCard(bankCardType)))
else None
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import scatan.views.utils.TypeUtils.InputSource

object RightTabComponent:

val tradeOffer: Var[ResourceType] = Var(ResourceType.values.head)
val tradeRequest: Var[ResourceType] = Var(ResourceType.values.head)

def rightTabCssClass: String = "game-view-right-tab"

def tradeComponent: DisplayableSource[Element] =
Expand Down Expand Up @@ -50,10 +53,20 @@ object RightTabComponent:
h3("Bank:"),
div(
"Trade four of ",
resourceTypeChoiceComponent,
resourceTypeChoiceComponent(tradeOffer),
" for one of ",
resourceTypeChoiceComponent,
button(className := "trade-bank-button", "Trade")
resourceTypeChoiceComponent(tradeRequest),
button(
className := "trade-bank-button",
onClick --> (_ =>
println("" + tradeOffer.now() + tradeRequest.now())
gameController.onTradeWithBank(
tradeOffer.now(),
tradeRequest.now()
)
),
"Trade"
)
)
)

Expand Down Expand Up @@ -87,10 +100,11 @@ object RightTabComponent:
)
)

private def resourceTypeChoiceComponent: InputSource[Element] =
private def resourceTypeChoiceComponent(changing: Var[ResourceType]): InputSource[Element] =
div(
className := "game-view-resource-type-choice",
select(
onChange.mapToValue.map(ResourceType.withName(_)) --> changing,
className := "game-view-resource-type-choice-select",
// for each type of resource add an option
for resource <- ResourceType.values
Expand Down
47 changes: 6 additions & 41 deletions src/test/scala/scatan/model/game/ops/TradeOpsTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -87,22 +87,18 @@ class TradeOpsTest extends BaseScatanStateTest:
val stateWithTrade =
state.tradeWithBank(
player,
Seq(
ResourceCard(ResourceType.Wood),
ResourceCard(ResourceType.Wood),
ResourceCard(ResourceType.Wood),
ResourceCard(ResourceType.Wood)
),
ResourceCard(ResourceType.Brick)
ResourceType.Wood,
ResourceType.Brick
)
stateWithTrade match
case Some(state) =>
state.resourceCards(player) should contain(ResourceCard(ResourceType.Brick))
state.resourceCards(player) should have size 1
case None => fail("Trade not allowed")
case None => fail("Resources not assigned")
}

it should "not allow to trade with bank if the player hasn't the cards" in {
it should "not allow to trade with bank if player doesn't have four identical cards" in {
val state = ScatanState(threePlayers)
val player = threePlayers.head
val stateWithResourceAssigned = state
Expand All @@ -114,39 +110,8 @@ class TradeOpsTest extends BaseScatanStateTest:
val stateWithTrade =
state.tradeWithBank(
player,
Seq(
ResourceCard(ResourceType.Wood),
ResourceCard(ResourceType.Wood),
ResourceCard(ResourceType.Wood),
ResourceCard(ResourceType.Wood)
),
ResourceCard(ResourceType.Brick)
)
stateWithTrade should be(None)
case None => fail("Resources not assigned")
}

it should "not allow to trade with bank if the offer not contains four identical cards" in {
val state = ScatanState(threePlayers)
val player = threePlayers.head
val stateWithResourceAssigned = state
.assignResourceCard(player, ResourceCard(ResourceType.Wood))
.flatMap(_.assignResourceCard(player, ResourceCard(ResourceType.Wood)))
.flatMap(_.assignResourceCard(player, ResourceCard(ResourceType.Wood)))
.flatMap(_.assignResourceCard(player, ResourceCard(ResourceType.Wood)))
.flatMap(_.assignResourceCard(player, ResourceCard(ResourceType.Brick)))
stateWithResourceAssigned match
case Some(state) =>
val stateWithTrade =
state.tradeWithBank(
player,
Seq(
ResourceCard(ResourceType.Wood),
ResourceCard(ResourceType.Wood),
ResourceCard(ResourceType.Wood),
ResourceCard(ResourceType.Brick)
),
ResourceCard(ResourceType.Brick)
ResourceType.Wood,
ResourceType.Brick
)
stateWithTrade should be(None)
case None => fail("Resources not assigned")
Expand Down

0 comments on commit 67bb761

Please sign in to comment.