Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature cleanup #50

Merged
merged 25 commits into from
Oct 14, 2023
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
13f5e86
chore: setup effects and methods to support playable development card
alemazzo Oct 11, 2023
6f1fa41
feat: implemented playable development card in ScatanGame and ScatanS…
alemazzo Oct 11, 2023
d38d778
chore: refactor method
alemazzo Oct 11, 2023
be71a64
chore: refactored and moved click handler away from controller to avo…
alemazzo Oct 11, 2023
8fe2f97
chore: implemented graphic but need to fix logic
alemazzo Oct 11, 2023
7734b16
feat: added check for buying a development or playing a development
alemazzo Oct 12, 2023
29cc261
feat: restore previous state when a development card fail
alemazzo Oct 12, 2023
3ea2fb8
Merge branch 'develop' into feature-play-development-card
alemazzo Oct 12, 2023
262e50b
chore: fix merge
alemazzo Oct 12, 2023
6085240
chore: refactor
alemazzo Oct 12, 2023
39fadb4
chore: fix and optimize imports
alemazzo Oct 12, 2023
dc37009
chore: formatted
alemazzo Oct 12, 2023
94d74e6
chore: controlled randomness of development card deck
alemazzo Oct 12, 2023
0772508
chore: cleanup imports
alemazzo Oct 13, 2023
97abb34
chore: refactor
alemazzo Oct 13, 2023
dd21f02
Merge branch 'feature-play-development-card' into feature-cleanup
alemazzo Oct 13, 2023
48fcd4e
chore: refactor
alemazzo Oct 13, 2023
62e0635
Merge branch 'develop' into feature-cleanup
alemazzo Oct 13, 2023
8dd81f9
refactor(map): extract some replicated code
manuandru Oct 13, 2023
1826079
refactor(game-map): extract some other common logic
manuandru Oct 14, 2023
3edb1e6
refactor(game-map-model): move and add some docs
manuandru Oct 14, 2023
0f25c6b
docs: add some docs
manuandru Oct 14, 2023
4b1737d
chore: removed unused stuff
alemazzo Oct 14, 2023
c0f49c6
refactor(ops): add doc and make some changes
luigi-borriello00 Oct 14, 2023
a43df87
Merge branch 'feature-cleanup' of github.com:zucchero-sintattico/pps-…
luigi-borriello00 Oct 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
2 changes: 1 addition & 1 deletion 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
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
2 changes: 1 addition & 1 deletion src/main/scala/scatan/lib/game/dsl/ops/GameCtxOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package scatan.lib.game.dsl.ops

import scatan.lib.game.dsl.GameDSLDomain.*
import scatan.lib.game.dsl.PropertiesDSL.*
import scatan.model.GameMap
import scatan.model.map.GameMap

object GameCtxOps:

Expand Down
4 changes: 3 additions & 1 deletion src/main/scala/scatan/lib/game/ops/GamePlayOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,7 @@ object GamePlayOps:
else newGame

extension (bool: Boolean)
def option: Option[Unit] =
/** Convert a boolean to an option, returning Some(()) if true, None if false
*/
private def option: Option[Unit] =
if bool then Some(()) else None
2 changes: 1 addition & 1 deletion src/main/scala/scatan/lib/game/ops/RulesOps.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package scatan.lib.game.ops

import scatan.lib.game.{GameStatus, Rules}
import scatan.model.GameMap
import scatan.model.map.GameMap

/** Operations on [[Rules]] related to their construction.
*/
Expand Down
Loading