Skip to content

Commit

Permalink
Merge pull request #50 from zucchero-sintattico/feature-cleanup
Browse files Browse the repository at this point in the history
Feature cleanup
  • Loading branch information
alemazzo authored Oct 14, 2023
2 parents 8c7ebc3 + a43df87 commit f08d16c
Show file tree
Hide file tree
Showing 89 changed files with 1,900 additions and 749 deletions.
224 changes: 160 additions & 64 deletions src/main/scala/scatan/controllers/game/GameController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,113 @@ import scatan.lib.mvc.{BaseController, Controller}
import scatan.model.ApplicationState
import scatan.model.components.*
import scatan.model.game.ScatanModelOps.{onError, updateGame}
import scatan.model.game.config.ScatanPhases.{Game, Setup}
import scatan.model.game.config.ScatanPlayer
import scatan.model.map.{Hexagon, RoadSpot, StructureSpot}
import scatan.views.game.GameView
import scatan.views.game.components.CardContextMap.CardType

/** The controller for the game.
*/
trait GameController extends Controller[ApplicationState]:
def onRoadSpot(spot: RoadSpot): Unit
def onStructureSpot(spot: StructureSpot): Unit
def onTradeWithBank(offer: ResourceType, request: ResourceType): Unit
def onTradeWithPlayer(receiver: ScatanPlayer, offer: Map[ResourceType, Int], request: Map[ResourceType, Int]): Unit
def state: ApplicationState

/** Goes to the next turn. */
def nextTurn(): Unit

/** Rolls the dice. */
def rollDice(): Unit
def clickCard(card: CardType): Unit

/** Assigns a road to the current player.
* @param spot
* The spot to assign the road to.
*/
def assignRoad(spot: RoadSpot): Unit

/** Assigns a settlement to the current player.
* @param spot
* The spot to assign the settlement to.
*/
def assignSettlement(spot: StructureSpot): Unit

/** Builds a road for the current player.
* @param spot
* The spot to build the road on.
*/
def buildRoad(spot: RoadSpot): Unit

/** Builds a settlement for the current player.
* @param spot
* The spot to build the settlement on.
*/
def buildSettlement(spot: StructureSpot): Unit

/** Builds a city for the current player.
* @param spot
* The spot to build the city on.
*/
def buildCity(spot: StructureSpot): Unit

/** Places the robber on a hexagon.
* @param hexagon
* The hexagon to place the robber on.
*/
def placeRobber(hexagon: Hexagon): Unit

/** Steals a card from a player.
* @param player
* The player to steal a card from.
*/
def stealCard(player: ScatanPlayer): Unit

/** Buys a development card for the current player.
*/
def buyDevelopmentCard(): Unit

/** Plays a knight development card for the current player.
* @param robberPosition
* The hexagon to place the robber on.
*/
def playKnightDevelopment(robberPosition: Hexagon): Unit

/** Plays a year of plenty development card for the current player.
* @param resource1
* The first resource to get.
* @param resource2
* The second resource to get.
*/
def playYearOfPlentyDevelopment(resource1: ResourceType, resource2: ResourceType): Unit

/** Plays a monopoly development card for the current player.
* @param resource
* The resource to get.
*/
def playMonopolyDevelopment(resource: ResourceType): Unit

/** Plays a road building development card for the current player.
* @param spot1
* The first spot to build a road on.
* @param spot2
* The second spot to build a road on.
*/
def playRoadBuildingDevelopment(spot1: RoadSpot, spot2: RoadSpot): Unit

/** Trades with the bank.
* @param offer
* The resource to offer.
* @param request
* The resource to request.
*/
def tradeWithBank(offer: ResourceType, request: ResourceType): Unit

/** Trades with a player.
* @param receiver
* The player to trade with.
* @param offer
* The cards to offer.
* @param request
* The cards to request.
*/
def tradeWithPlayer(receiver: ScatanPlayer, offer: Seq[ResourceCard], request: Seq[ResourceCard]): Unit

object GameController:
def apply(requirements: Controller.Requirements[GameView, ApplicationState]): GameController =
GameControllerImpl(requirements)
Expand All @@ -30,71 +119,48 @@ private class GameControllerImpl(requirements: Controller.Requirements[GameView,
extends BaseController(requirements)
with GameController:

override def state: ApplicationState = this.model.state

override def assignRoad(spot: RoadSpot): Unit =
this.model
.updateGame(_.assignRoad(spot))
.onError(view.displayMessage("Cannot assign road here"))

override def assignSettlement(spot: StructureSpot): Unit =
this.model
.updateGame(_.assignSettlement(spot))
.onError(view.displayMessage("Cannot assign settlement here"))

override def buildRoad(spot: RoadSpot): Unit =
this.model
.updateGame(_.buildRoad(spot))
.onError(view.displayMessage("Cannot build road here"))

override def buildSettlement(spot: StructureSpot): Unit =
this.model
.updateGame(_.buildSettlement(spot))
.onError(view.displayMessage("Cannot build settlement here"))

override def buildCity(spot: StructureSpot): Unit =
this.model
.updateGame(_.buildCity(spot))
.onError(view.displayMessage("Cannot build city here"))

override def placeRobber(hexagon: Hexagon): Unit =
this.model
.updateGame(_.placeRobber(hexagon))
.onError(view.displayMessage("Cannot place robber"))

override def clickCard(card: CardType): Unit = ???

override def nextTurn(): Unit = this.model.updateGame(_.nextTurn)
override def nextTurn(): Unit =
this.model
.updateGame(_.nextTurn)
.onError(view.displayMessage("Cannot go to next turn"))

override def rollDice(): Unit =
this.model.updateGame(_.rollDice(diceResult => this.view.displayMessage(s"Roll dice result: $diceResult")));

override def onRoadSpot(spot: RoadSpot): Unit =
val phase = this.model.state.game.map(_.gameStatus.phase).get
phase match
case Setup =>
this.model
.updateGame(_.assignRoad(spot))
.onError(view.displayMessage("Cannot assign road here"))
case Game =>
this.model
.updateGame(_.buildRoad(spot))
.onError(view.displayMessage("Cannot build road here"))

override def onStructureSpot(spot: StructureSpot): Unit =
val phase = this.model.state.game.map(_.gameStatus.phase).get
phase match
case Setup =>
this.model
.updateGame(_.assignSettlement(spot))
.onError(view.displayMessage("Cannot assign settlement here"))
case Game =>
val alreadyContainsSettlement = this.model.state.game
.map(_.state)
.map(_.assignedBuildings)
.flatMap(_.get(spot))
.exists(_.buildingType == BuildingType.Settlement)
if alreadyContainsSettlement then
this.model
.updateGame(_.buildCity(spot))
.onError(view.displayMessage("Cannot build city here"))
else
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")
)

override def onTradeWithPlayer(
receiver: ScatanPlayer,
offer: Map[ResourceType, Int],
request: Map[ResourceType, Int]
): Unit =
val offerCards = offer.flatMap((resourceType, amount) => ResourceCard(resourceType) ** amount).toSeq
val requestCards = request.flatMap((resourceType, amount) => ResourceCard(resourceType) ** amount).toSeq
this.model
.updateGame(_.tradeWithPlayer(receiver, offerCards, requestCards))
.onError(
view.displayMessage("Cannot trade this cards with player")
)
.updateGame(_.rollDice(diceResult => this.view.displayMessage(s"Roll dice result: $diceResult")))
.onError(view.displayMessage("Cannot roll dice"))

override def stealCard(player: ScatanPlayer): Unit =
this.model
.updateGame(_.stealCard(player))
Expand All @@ -104,3 +170,33 @@ private class GameControllerImpl(requirements: Controller.Requirements[GameView,
this.model
.updateGame(_.buyDevelopmentCard)
.onError(view.displayMessage("Cannot buy development card"))

override def playKnightDevelopment(robberPosition: Hexagon): Unit =
this.model
.updateGame(_.playKnightDevelopment(robberPosition))
.onError(view.displayMessage("Cannot play knight development card"))

override def playYearOfPlentyDevelopment(resource1: ResourceType, resource2: ResourceType): Unit =
this.model
.updateGame(_.playYearOfPlentyDevelopment(resource1, resource2))
.onError(view.displayMessage("Cannot play year of plenty development card"))

override def playMonopolyDevelopment(resource: ResourceType): Unit =
this.model
.updateGame(_.playMonopolyDevelopment(resource))
.onError(view.displayMessage("Cannot play monopoly development card"))

override def playRoadBuildingDevelopment(spot1: RoadSpot, spot2: RoadSpot): Unit =
this.model
.updateGame(_.playRoadBuildingDevelopment(spot1, spot2))
.onError(view.displayMessage("Cannot play road building development card"))

override def tradeWithBank(offer: ResourceType, request: ResourceType): Unit =
this.model
.updateGame(_.tradeWithBank(offer, request))
.onError(view.displayMessage("Cannot trade with bank"))

override def tradeWithPlayer(receiver: ScatanPlayer, offer: Seq[ResourceCard], request: Seq[ResourceCard]): Unit =
this.model
.updateGame(_.tradeWithPlayer(receiver, offer, request))
.onError(view.displayMessage("Cannot trade with player"))
28 changes: 13 additions & 15 deletions src/main/scala/scatan/controllers/game/SetUpController.scala
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
package scatan.controllers.game

import scatan.lib.mvc.{BaseController, Controller}
import scatan.lib.mvc.{Controller, EmptyController}
import scatan.model.ApplicationState
import scatan.model.map.GameMap
import scatan.views.game.SetUpView
import scatan.model.GameMap

/** This is the controller for the setup page.
/** The controller for the game setup screen.
*/
trait SetUpController extends Controller[ApplicationState]:

/** Starts the game with the given usernames.
* @param gameMap,
* the game map to use.
* @param usernames,
* the usernames of the players.
*/
def startGame(gameMap: GameMap, usernames: String*): Unit

object SetUpController:
def apply(requirements: Controller.Requirements[SetUpView, ApplicationState]): SetUpController =
SetUpControllerImpl(requirements)

/** This is the implementation of the controller for the setup page.
* @param requirements,
* the requirements for the controller.
*/
private class SetUpControllerImpl(requirements: Controller.Requirements[SetUpView, ApplicationState])
extends BaseController(requirements)
with SetUpController:

override def startGame(gameMap: GameMap, usernames: String*): Unit =
this.model.update(_.createGame(gameMap, usernames*))
new EmptyController(requirements) with SetUpController:
override def startGame(gameMap: GameMap, usernames: String*): Unit =
this.model.update(_.createGame(gameMap, usernames*))
11 changes: 4 additions & 7 deletions src/main/scala/scatan/controllers/home/AboutController.scala
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
package scatan.controllers.home

import scatan.Pages
import scatan.lib.mvc.{BaseController, Controller}
import scatan.lib.mvc.{Controller, EmptyController}
import scatan.model.ApplicationState
import scatan.views.home.AboutView

/** The about page controller.
*/
trait AboutController extends Controller[ApplicationState]

object AboutController:
def apply(requirements: Controller.Requirements[AboutView, ApplicationState]): AboutController =
AboutControllerImpl(requirements)

private class AboutControllerImpl(requirements: Controller.Requirements[AboutView, ApplicationState])
extends BaseController(requirements)
with AboutController
new EmptyController(requirements) with AboutController
15 changes: 3 additions & 12 deletions src/main/scala/scatan/controllers/home/HomeController.scala
Original file line number Diff line number Diff line change
@@ -1,22 +1,13 @@
package scatan.controllers.home

import scatan.Pages
import scatan.lib.mvc.{BaseController, Controller}
import scatan.lib.mvc.{Controller, EmptyController}
import scatan.model.ApplicationState
import scatan.views.home.HomeView

/** This is the controller for the home page.
/** The home page controller.
*/
trait HomeController extends Controller[ApplicationState]

object HomeController:
def apply(requirements: Controller.Requirements[HomeView, ApplicationState]): HomeController =
HomeControllerImpl(requirements)

/** This is the implementation of the controller for the home page.
* @param requirements,
* the requirements for the controller.
*/
class HomeControllerImpl(requirements: Controller.Requirements[HomeView, ApplicationState])
extends BaseController(requirements)
with HomeController
new EmptyController(requirements) with HomeController
2 changes: 1 addition & 1 deletion src/main/scala/scatan/lib/game/Game.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package scatan.lib.game

import scatan.model.GameMap
import scatan.model.map.GameMap

/** A game status is a pair of phase and step.
* @param phase
Expand Down
22 changes: 1 addition & 21 deletions src/main/scala/scatan/lib/game/Rules.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package scatan.lib.game

import scatan.model.GameMap
import scatan.model.map.GameMap

/** Rules of a game.
* @param startingStateFactory
Expand Down Expand Up @@ -70,23 +70,3 @@ final case class Rules[State, P, S, A, Player](
(status, action) -> step
}
}

object Rules:
def empty[State, P, S, A, Player]: Rules[State, P, S, A, Player] =
fromStateFactory((_, _) => null.asInstanceOf[State])

def fromStateFactory[State, P, S, A, Player](
initialStateFactory: (GameMap, Seq[Player]) => State
): Rules[State, P, S, A, Player] =
Rules[State, P, S, A, Player](
startingStateFactory = initialStateFactory,
startingPhase = null.asInstanceOf[P],
actions = Map.empty,
allowedPlayersSizes = Set.empty,
startingSteps = Map.empty,
phaseTurnIteratorFactories = Map.empty,
nextPhase = Map.empty,
endingSteps = Map.empty,
winnerFunction = (_: State) => None,
initialAction = Map.empty
)
2 changes: 1 addition & 1 deletion src/main/scala/scatan/lib/game/dsl/GameDSLDomain.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package scatan.lib.game.dsl

import scatan.model.GameMap
import scatan.model.map.GameMap

private object GameDSLDomain:

Expand Down
Loading

0 comments on commit f08d16c

Please sign in to comment.