From fd16f5b7a6709b25e9890e1db7d9e73e521edde0 Mon Sep 17 00:00:00 2001 From: Manuel Andruccioli Date: Wed, 11 Oct 2023 20:18:35 +0200 Subject: [PATCH 01/16] wip(random-map): add factory for random content --- .../scala/scatan/model/map/TileContent.scala | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/main/scala/scatan/model/map/TileContent.scala b/src/main/scala/scatan/model/map/TileContent.scala index d43cf6a1..5f2b719a 100644 --- a/src/main/scala/scatan/model/map/TileContent.scala +++ b/src/main/scala/scatan/model/map/TileContent.scala @@ -15,11 +15,15 @@ trait MapWithTileContent: */ def toContent: Map[Hexagon, TileContent] +trait TileContentConfig: + def numbers: Seq[Int] + def terrains: Seq[Terrain] + /** A factory to create terrains. */ object TileContentFactory: - def fixedForLayer2(tiles: Seq[Hexagon]): Map[Hexagon, TileContent] = + object ConfigForLayer2 extends TileContentConfig: val terrains: List[Terrain] = List( 4 * Wood, 4 * Sheep, @@ -27,16 +31,28 @@ object TileContentFactory: 3 * Rock, 3 * Brick ).flatten - val numbers = 2 :: 12 :: (for i <- (3 to 11).toList if i != 7 yield List(i, i)).flatten - val tileContents = - terrains.zip(numbers).map(p => TileContent(p._1, Some(p._2))) - + private def fromConfig(using config: TileContentConfig)(tiles: Seq[Hexagon]): Map[Hexagon, TileContent] = + val tileContents = config.terrains.zip(config.numbers).map(p => TileContent(p._1, Some(p._2))) Map - .from(tiles.zip(TileContent(Desert, None) :: tileContents)) + .from(tiles.zip(TileContent(Desert, None) +: tileContents)) .withDefaultValue(TileContent(Sea, None)) + + def fixedForLayer2(tiles: Seq[Hexagon]): Map[Hexagon, TileContent] = + import ConfigForLayer2.* + given TileContentConfig = ConfigForLayer2 + fromConfig(tiles) + + def randomForLayer2(tiles: Seq[Hexagon]): Map[Hexagon, TileContent] = + import ConfigForLayer2.* + import scala.util.Random.shuffle + + given TileContentConfig with + val terrains = shuffle(ConfigForLayer2.terrains) + val numbers = shuffle(ConfigForLayer2.numbers) + fromConfig(tiles) From 56dccb5af5a41590ad21201a845784b4446e91b1 Mon Sep 17 00:00:00 2001 From: Manuel Andruccioli Date: Thu, 12 Oct 2023 17:35:56 +0200 Subject: [PATCH 02/16] wip(game-map): add factory for game map --- src/main/scala/scatan/model/GameMap.scala | 19 +++++++++++++++---- .../scala/scatan/model/map/TileContent.scala | 14 ++++++++++---- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/main/scala/scatan/model/GameMap.scala b/src/main/scala/scatan/model/GameMap.scala index f22ab6f0..74285e2d 100644 --- a/src/main/scala/scatan/model/GameMap.scala +++ b/src/main/scala/scatan/model/GameMap.scala @@ -2,6 +2,7 @@ package scatan.model import scatan.model.map.* import scatan.model.map.HexagonInMap.* +import scatan.model.components.Terrain /** Hexagonal tiled game map of Scatan. * @@ -11,12 +12,22 @@ import scatan.model.map.HexagonInMap.* * @param withSeaLayers * number of concentric circles of hexagons the terrain ones. */ -final case class GameMap(withTerrainLayers: Int = 2, withSeaLayers: Int = 1) - extends HexagonalTiledMap(withTerrainLayers + withSeaLayers) +final case class GameMap( + withTerrainLayers: Int = 2, + withSeaLayers: Int = 1, + tileContentsStrategy: Seq[Hexagon] => Map[Hexagon, TileContent] = TileContentStrategyFactory.fixedForLayer2 +) extends HexagonalTiledMap(withTerrainLayers + withSeaLayers) with MapWithTileContent: val totalLayers = withTerrainLayers + withSeaLayers val tileWithTerrain = tiles.toSeq.filter(_.layer <= withTerrainLayers) - override val toContent: Map[Hexagon, TileContent] = - TileContentFactory.fixedForLayer2(tileWithTerrain) + override val toContent: Map[Hexagon, TileContent] = tileContentsStrategy(tileWithTerrain) + +object GameMapFactory: + + def defaultMap: GameMap = + GameMap(tileContentsStrategy = TileContentStrategyFactory.fixedForLayer2) + + def randomMap: GameMap = + GameMap(tileContentsStrategy = TileContentStrategyFactory.randomForLayer2) diff --git a/src/main/scala/scatan/model/map/TileContent.scala b/src/main/scala/scatan/model/map/TileContent.scala index 5f2b719a..2a347ffe 100644 --- a/src/main/scala/scatan/model/map/TileContent.scala +++ b/src/main/scala/scatan/model/map/TileContent.scala @@ -21,7 +21,7 @@ trait TileContentConfig: /** A factory to create terrains. */ -object TileContentFactory: +object TileContentStrategyFactory: object ConfigForLayer2 extends TileContentConfig: val terrains: List[Terrain] = List( @@ -29,7 +29,8 @@ object TileContentFactory: 4 * Sheep, 4 * Wheat, 3 * Rock, - 3 * Brick + 3 * Brick, + 1 * Desert ).flatten val numbers = 2 :: 12 :: (for @@ -38,9 +39,14 @@ object TileContentFactory: yield List(i, i)).flatten private def fromConfig(using config: TileContentConfig)(tiles: Seq[Hexagon]): Map[Hexagon, TileContent] = - val tileContents = config.terrains.zip(config.numbers).map(p => TileContent(p._1, Some(p._2))) + val iterator = config.numbers.iterator + val tileContents = config.terrains.map { t => + t match + case Desert => TileContent(t, None) + case _ => TileContent(t, iterator.nextOption()) + } Map - .from(tiles.zip(TileContent(Desert, None) +: tileContents)) + .from(tiles.zip(tileContents)) .withDefaultValue(TileContent(Sea, None)) def fixedForLayer2(tiles: Seq[Hexagon]): Map[Hexagon, TileContent] = From 7b7e118a34a7e537e75c99d29bf2c83333c562de Mon Sep 17 00:00:00 2001 From: luigi-borriello00 Date: Thu, 12 Oct 2023 18:41:54 +0200 Subject: [PATCH 03/16] feat: unpack CardOps in ResCardOps and DevCardOps --- .../scala/scatan/model/game/ScatanDSL.scala | 2 +- .../scatan/model/game/ScatanEffects.scala | 10 +-- .../scatan/model/game/ops/BuildingOps.scala | 2 +- .../scatan/model/game/ops/DevCardOps.scala | 86 +++++++++++++++++++ ...EmptySpotsOps.scala => EmptySpotOps.scala} | 2 +- .../ops/{CardOps.scala => ResCardOps.scala} | 82 ++---------------- .../scatan/model/game/ops/TradeOps.scala | 2 +- src/test/scala/scatan/model/GameTest.scala | 2 +- .../scatan/model/ScatanEffectsTest.scala | 2 +- .../model/game/BaseScatanStateTest.scala | 4 +- .../scatan/model/game/ops/AwardOpsTest.scala | 4 +- .../model/game/ops/BuildingOpsTest.scala | 4 +- .../model/game/ops/DevCardOpsTest.scala | 8 +- .../model/game/ops/ResCardOpsTest.scala | 10 +-- .../scatan/model/game/ops/ScoreOpsTest.scala | 4 +- .../scatan/model/game/ops/TradeOpsTest.scala | 2 +- 16 files changed, 118 insertions(+), 108 deletions(-) create mode 100644 src/main/scala/scatan/model/game/ops/DevCardOps.scala rename src/main/scala/scatan/model/game/ops/{EmptySpotsOps.scala => EmptySpotOps.scala} (98%) rename src/main/scala/scatan/model/game/ops/{CardOps.scala => ResCardOps.scala} (67%) diff --git a/src/main/scala/scatan/model/game/ScatanDSL.scala b/src/main/scala/scatan/model/game/ScatanDSL.scala index 78e3ff04..0a754b39 100644 --- a/src/main/scala/scatan/model/game/ScatanDSL.scala +++ b/src/main/scala/scatan/model/game/ScatanDSL.scala @@ -2,7 +2,7 @@ package scatan.model.game import scatan.lib.game.Rules import scatan.model.game.config.{ScatanActions, ScatanPhases, ScatanPlayer, ScatanSteps} -import scatan.model.game.ops.CardOps.assignResourcesAfterInitialPlacement +import scatan.model.game.ops.ResCardOps.assignResourcesAfterInitialPlacement import scatan.model.game.ops.ScoreOps.winner import scala.language.postfixOps diff --git a/src/main/scala/scatan/model/game/ScatanEffects.scala b/src/main/scala/scatan/model/game/ScatanEffects.scala index 0031e484..dbbd51db 100644 --- a/src/main/scala/scatan/model/game/ScatanEffects.scala +++ b/src/main/scala/scatan/model/game/ScatanEffects.scala @@ -4,14 +4,10 @@ import scatan.lib.game.ops.Effect import scatan.model.components.{BuildingType, ResourceCard} import scatan.model.game.config.ScatanActions.* import scatan.model.game.config.ScatanPlayer +import scatan.model.game.ops.ResCardOps.{assignResourcesFromNumber, stoleResourceCard} +import scatan.model.game.ops.DevCardOps.buyDevelopmentCard + import scatan.model.game.ops.BuildingOps.{assignBuilding, build} -import scatan.model.game.ops.CardOps.{ - assignResourceCard, - assignResourcesFromNumber, - buyDevelopmentCard, - removeResourceCard, - stoleResourceCard -} import scatan.model.map.{Hexagon, RoadSpot, StructureSpot} import scatan.model.components.ResourceCard import scatan.model.game.ops.TradeOps.tradeWithPlayer diff --git a/src/main/scala/scatan/model/game/ops/BuildingOps.scala b/src/main/scala/scatan/model/game/ops/BuildingOps.scala index cc1e35d7..8fc690d0 100644 --- a/src/main/scala/scatan/model/game/ops/BuildingOps.scala +++ b/src/main/scala/scatan/model/game/ops/BuildingOps.scala @@ -4,7 +4,7 @@ import scatan.model.components.{AssignedBuildings, AssignmentInfo, BuildingType, import scatan.model.game.ScatanState import scatan.model.game.config.ScatanPlayer import scatan.model.game.ops.AwardOps.* -import scatan.model.game.ops.EmptySpotsOps.{emptyRoadSpot, emptyStructureSpot} +import EmptySpotOps.{emptyRoadSpot, emptyStructureSpot} import scatan.model.map.{RoadSpot, Spot, StructureSpot} object BuildingOps: diff --git a/src/main/scala/scatan/model/game/ops/DevCardOps.scala b/src/main/scala/scatan/model/game/ops/DevCardOps.scala new file mode 100644 index 00000000..d40978f9 --- /dev/null +++ b/src/main/scala/scatan/model/game/ops/DevCardOps.scala @@ -0,0 +1,86 @@ +package scatan.model.game.ops + +import scatan.model.game.ScatanState +import scatan.model.game.config.ScatanPlayer +import scatan.model.components.DevelopmentCard +import scatan.model.game.ops.AwardOps.awards +import scatan.model.components.ResourceType + +object DevCardOps: + + extension (state: ScatanState) + /** Returns a new ScatanState with the given development card assigned to the given player. The development card is + * added to the player's list of development cards. The assigned awards are updated. + * + * @param player + * The player to assign the development card to. + * @param developmentCard + * The development card to assign to the player. + * @return + * Some(ScatanState) if the player added the development card, None otherwise + */ + def assignDevelopmentCard(player: ScatanPlayer, developmentCard: DevelopmentCard): Option[ScatanState] = + Some( + state.copy( + developmentCards = state.developmentCards.updated(player, state.developmentCards(player) :+ developmentCard), + assignedAwards = state.awards + ) + ) + + /** Buys a development card for a given player and returns a new ScatanState with the updated resource cards and + * development cards. The player must have the required resources to buy the development card. + * + * @param player, + * the player who is buying the development card + * @param turnNumber, + * the turn number when the development card was bought + * @return + * Some(ScatanState) if the player bought the development card, None otherwise + */ + def buyDevelopmentCard(player: ScatanPlayer, turnNumber: Int): Option[ScatanState] = + val requiredResources = Seq( + ResourceType.Wheat, + ResourceType.Sheep, + ResourceType.Rock + ) + val playerResources = state.resourceCards(player) + val hasRequiredResources = requiredResources.forall(playerResources.map(_.resourceType).contains) + if !hasRequiredResources then None + else + val card = state.developmentCardsDeck.headOption + val cardWithTurnNumber = card.map(_.copy(drewAt = Some(turnNumber))) + cardWithTurnNumber match + case Some(developmentCard) => + val updatedResources = requiredResources.foldLeft(playerResources)((resources, resource) => + resources.filterNot(_.resourceType == resource) + ) + Some( + state.copy( + resourceCards = state.resourceCards.updated(player, updatedResources), + developmentCards = + state.developmentCards.updated(player, state.developmentCards(player) :+ developmentCard), + developmentCardsDeck = state.developmentCardsDeck.tail + ) + ) + case None => None + + /** Consumes a development card for a given player and returns a new ScatanState with the updated development cards + * and assigned awards. + * @param player + * the player who is consuming the development card + * @param developmentCard + * the development card to be consumed + * @return + * Some(ScatanState) if the player has the development card, None otherwise + */ + def consumeDevelopmentCard(player: ScatanPlayer, developmentCard: DevelopmentCard): Option[ScatanState] = + if !state.developmentCards(player).contains(developmentCard) then None + else + val remainingCards = + state.developmentCards(player).filter(_.developmentType == developmentCard.developmentType).drop(1) + Some( + state.copy( + developmentCards = state.developmentCards.updated(player, remainingCards), + assignedAwards = state.awards + ) + ) diff --git a/src/main/scala/scatan/model/game/ops/EmptySpotsOps.scala b/src/main/scala/scatan/model/game/ops/EmptySpotOps.scala similarity index 98% rename from src/main/scala/scatan/model/game/ops/EmptySpotsOps.scala rename to src/main/scala/scatan/model/game/ops/EmptySpotOps.scala index ca47bd6f..3250b835 100644 --- a/src/main/scala/scatan/model/game/ops/EmptySpotsOps.scala +++ b/src/main/scala/scatan/model/game/ops/EmptySpotOps.scala @@ -4,7 +4,7 @@ import scatan.model.game.ScatanState import scatan.model.map.HexagonInMap.layer import scatan.model.map.{RoadSpot, Spot, StructureSpot} -object EmptySpotsOps: +object EmptySpotOps: extension (state: ScatanState) diff --git a/src/main/scala/scatan/model/game/ops/CardOps.scala b/src/main/scala/scatan/model/game/ops/ResCardOps.scala similarity index 67% rename from src/main/scala/scatan/model/game/ops/CardOps.scala rename to src/main/scala/scatan/model/game/ops/ResCardOps.scala index 6f583737..dd00018f 100644 --- a/src/main/scala/scatan/model/game/ops/CardOps.scala +++ b/src/main/scala/scatan/model/game/ops/ResCardOps.scala @@ -1,17 +1,20 @@ package scatan.model.game.ops -import scatan.model.components.* import scatan.model.game.ScatanState import scatan.model.game.config.ScatanPlayer -import scatan.model.game.ops.AwardOps.* -import scatan.model.map.{Hexagon, RoadSpot, StructureSpot, TileContent} - +import scatan.model.components.ResourceCard import scala.util.Random +import scatan.model.map.Hexagon +import scatan.model.map.TileContent +import scatan.model.components.AssignedBuildings +import scatan.model.map.StructureSpot +import scatan.model.map.RoadSpot +import scatan.model.components.ResourceType +import scatan.model.components.BuildingType -object CardOps: +object ResCardOps: extension (state: ScatanState) - /** Stole a card from a victim. * @param currentPlayer * the player who stole the card @@ -151,70 +154,3 @@ object CardOps: .filter((_, building) => building.buildingType == BuildingType.Settlement) .takeRight(structureBuildingCount / 2) assignResourceFromHexagonsAndBuildings(buildings = buildings) - - /** Returns a new ScatanState with the given development card assigned to the given player. The development card is - * added to the player's list of development cards. The assigned awards are updated. - * - * @param player - * The player to assign the development card to. - * @param developmentCard - * The development card to assign to the player. - * @return - * Some(ScatanState) if the player added the development card, None otherwise - */ - def assignDevelopmentCard(player: ScatanPlayer, developmentCard: DevelopmentCard): Option[ScatanState] = - Some( - state.copy( - developmentCards = state.developmentCards.updated(player, state.developmentCards(player) :+ developmentCard), - assignedAwards = state.awards - ) - ) - - def buyDevelopmentCard(player: ScatanPlayer, turnNumber: Int): Option[ScatanState] = - // Check that player has required resources and remove them - val requiredResources = Seq( - ResourceType.Wheat, - ResourceType.Sheep, - ResourceType.Rock - ) - val playerResources = state.resourceCards(player) - val hasRequiredResources = requiredResources.forall(playerResources.map(_.resourceType).contains) - if !hasRequiredResources then None - else - val card = state.developmentCardsDeck.headOption - val cardWithTurnNumber = card.map(_.copy(drewAt = Some(turnNumber))) - cardWithTurnNumber match - case Some(developmentCard) => - val updatedResources = requiredResources.foldLeft(playerResources)((resources, resource) => - resources.filterNot(_.resourceType == resource) - ) - Some( - state.copy( - resourceCards = state.resourceCards.updated(player, updatedResources), - developmentCards = - state.developmentCards.updated(player, state.developmentCards(player) :+ developmentCard), - developmentCardsDeck = state.developmentCardsDeck.tail - ) - ) - case None => None - - /** Consumes a development card for a given player and returns a new ScatanState with the updated development cards - * and assigned awards. - * @param player - * the player who is consuming the development card - * @param developmentCard - * the development card to be consumed - * @return - * Some(ScatanState) if the player has the development card, None otherwise - */ - def consumeDevelopmentCard(player: ScatanPlayer, developmentCard: DevelopmentCard): Option[ScatanState] = - if !state.developmentCards(player).contains(developmentCard) then None - else - val remainingCards = - state.developmentCards(player).filter(_.developmentType == developmentCard.developmentType).drop(1) - Some( - state.copy( - developmentCards = state.developmentCards.updated(player, remainingCards), - assignedAwards = state.awards - ) - ) diff --git a/src/main/scala/scatan/model/game/ops/TradeOps.scala b/src/main/scala/scatan/model/game/ops/TradeOps.scala index 3675820c..fb2cd0ca 100644 --- a/src/main/scala/scatan/model/game/ops/TradeOps.scala +++ b/src/main/scala/scatan/model/game/ops/TradeOps.scala @@ -3,7 +3,7 @@ package scatan.model.game.ops import scatan.model.components.{ResourceCard, ResourceType} import scatan.model.game.ScatanState import scatan.model.game.config.ScatanPlayer -import scatan.model.game.ops.CardOps.{assignResourceCard, removeResourceCard} +import scatan.model.game.ops.ResCardOps.{assignResourceCard, removeResourceCard} import scatan.views.game.components.ContextMap.resources object TradeOps: diff --git a/src/test/scala/scatan/model/GameTest.scala b/src/test/scala/scatan/model/GameTest.scala index 90a8c67f..4d559af1 100644 --- a/src/test/scala/scatan/model/GameTest.scala +++ b/src/test/scala/scatan/model/GameTest.scala @@ -8,7 +8,7 @@ import scatan.lib.game.{Game, GameStatus, Rules} import scatan.model.game.ScatanEffects.{AssignRoadEffect, AssignSettlementEffect, NextTurnEffect} import scatan.model.game.config.ScatanActions.* import scatan.model.game.config.{ScatanActions, ScatanPhases, ScatanPlayer, ScatanSteps} -import scatan.model.game.ops.EmptySpotsOps.{emptyRoadSpot, emptyStructureSpot} +import scatan.model.game.ops.EmptySpotOps.{emptyRoadSpot, emptyStructureSpot} import scatan.model.game.{ScatanDSL, ScatanState} class GameTest extends BaseTest: diff --git a/src/test/scala/scatan/model/ScatanEffectsTest.scala b/src/test/scala/scatan/model/ScatanEffectsTest.scala index 36ed67c4..bf93c358 100644 --- a/src/test/scala/scatan/model/ScatanEffectsTest.scala +++ b/src/test/scala/scatan/model/ScatanEffectsTest.scala @@ -5,7 +5,7 @@ import scatan.model.components.{ResourceCard, ResourceType} import scatan.model.game.ScatanEffects.{NextTurnEffect, PlaceRobberEffect, RollEffect, TradeWithPlayerEffect} import scatan.model.game.{ScatanGame, ScatanState} import scatan.model.game.config.ScatanPlayer -import scatan.model.game.ops.CardOps.assignResourceCard +import scatan.model.game.ops.ResCardOps.assignResourceCard class ScatanEffectsTest extends BaseTest: diff --git a/src/test/scala/scatan/model/game/BaseScatanStateTest.scala b/src/test/scala/scatan/model/game/BaseScatanStateTest.scala index 560793f2..fa9b87a7 100644 --- a/src/test/scala/scatan/model/game/BaseScatanStateTest.scala +++ b/src/test/scala/scatan/model/game/BaseScatanStateTest.scala @@ -2,10 +2,10 @@ package scatan.model.game import scatan.BaseTest import scatan.model.game.config.ScatanPlayer -import scatan.model.game.ops.EmptySpotsOps.emptySpots +import scatan.model.game.ops.EmptySpotOps.emptySpots import scatan.model.map.Spot import scatan.model.map.RoadSpot -import scatan.model.game.ops.EmptySpotsOps.emptyRoadSpot +import scatan.model.game.ops.EmptySpotOps.emptyRoadSpot import scatan.model.game.ops.BuildingOps.assignBuilding import scatan.model.components.BuildingType import scatan.model.map.StructureSpot diff --git a/src/test/scala/scatan/model/game/ops/AwardOpsTest.scala b/src/test/scala/scatan/model/game/ops/AwardOpsTest.scala index 13a375bf..7439f520 100644 --- a/src/test/scala/scatan/model/game/ops/AwardOpsTest.scala +++ b/src/test/scala/scatan/model/game/ops/AwardOpsTest.scala @@ -4,8 +4,8 @@ import scatan.model.components.* import scatan.model.game.{BaseScatanStateTest, ScatanState} import scatan.model.game.ops.AwardOps.* import scatan.model.game.ops.BuildingOps.assignBuilding -import scatan.model.game.ops.CardOps.assignDevelopmentCard -import scatan.model.game.ops.EmptySpotsOps.{emptyRoadSpot, emptyStructureSpot} +import scatan.model.game.ops.DevCardOps.assignDevelopmentCard +import scatan.model.game.ops.EmptySpotOps.{emptyRoadSpot, emptyStructureSpot} class AwardOpsTest extends BaseScatanStateTest: diff --git a/src/test/scala/scatan/model/game/ops/BuildingOpsTest.scala b/src/test/scala/scatan/model/game/ops/BuildingOpsTest.scala index cc29ac7d..4e82dc92 100644 --- a/src/test/scala/scatan/model/game/ops/BuildingOpsTest.scala +++ b/src/test/scala/scatan/model/game/ops/BuildingOpsTest.scala @@ -4,8 +4,8 @@ import scatan.model.components.* import scatan.model.game.ScatanState import scatan.model.game.{BaseScatanStateTest, ScatanState} import scatan.model.game.ops.BuildingOps.{assignBuilding, build} -import scatan.model.game.ops.CardOps.assignResourceCard -import scatan.model.game.ops.EmptySpotsOps.{emptyStructureSpot, emptyRoadSpot} +import scatan.model.game.ops.ResCardOps.assignResourceCard +import scatan.model.game.ops.EmptySpotOps.{emptyStructureSpot, emptyRoadSpot} import scatan.model.game.BaseScatanStateTest import scatan.model.game.config.ScatanPlayer import scatan.model.map.{RoadSpot, StructureSpot} diff --git a/src/test/scala/scatan/model/game/ops/DevCardOpsTest.scala b/src/test/scala/scatan/model/game/ops/DevCardOpsTest.scala index cf2d8407..5ae0d260 100644 --- a/src/test/scala/scatan/model/game/ops/DevCardOpsTest.scala +++ b/src/test/scala/scatan/model/game/ops/DevCardOpsTest.scala @@ -3,12 +3,8 @@ package scatan.model.game.ops import scatan.lib.game.Game import scatan.model.components.{DevelopmentCard, DevelopmentType, ResourceCard, ResourceType} import scatan.model.game.{BaseScatanStateTest, ScatanState} -import scatan.model.game.ops.CardOps.{ - assignDevelopmentCard, - assignResourceCard, - buyDevelopmentCard, - consumeDevelopmentCard -} +import scatan.model.game.ops.DevCardOps.{buyDevelopmentCard, consumeDevelopmentCard, assignDevelopmentCard} +import scatan.model.game.ops.ResCardOps.assignResourceCard class DevCardOpsTest extends BaseScatanStateTest: diff --git a/src/test/scala/scatan/model/game/ops/ResCardOpsTest.scala b/src/test/scala/scatan/model/game/ops/ResCardOpsTest.scala index 2c0c40ac..caea079c 100644 --- a/src/test/scala/scatan/model/game/ops/ResCardOpsTest.scala +++ b/src/test/scala/scatan/model/game/ops/ResCardOpsTest.scala @@ -3,13 +3,9 @@ package scatan.model.game.ops import scatan.model.components.{BuildingType, ResourceCard, ResourceCards, ResourceType} import scatan.model.game.{BaseScatanStateTest, ScatanState} import scatan.model.game.ops.BuildingOps.assignBuilding -import scatan.model.game.ops.CardOps.{ - assignResourceCard, - assignResourcesAfterInitialPlacement, - assignResourcesFromNumber, - removeResourceCard -} -import scatan.model.game.ops.EmptySpotsOps.emptyStructureSpot +import scatan.model.game.ops.ResCardOps.* + +import scatan.model.game.ops.EmptySpotOps.emptyStructureSpot import scatan.model.game.{BaseScatanStateTest, ScatanState} import scatan.model.map.HexagonInMap.layer import scatan.model.map.{RoadSpot, Spot, StructureSpot} diff --git a/src/test/scala/scatan/model/game/ops/ScoreOpsTest.scala b/src/test/scala/scatan/model/game/ops/ScoreOpsTest.scala index bb90f681..7d234cfd 100644 --- a/src/test/scala/scatan/model/game/ops/ScoreOpsTest.scala +++ b/src/test/scala/scatan/model/game/ops/ScoreOpsTest.scala @@ -3,9 +3,9 @@ package scatan.model.game.ops import scatan.model.components.{AssignedBuildings, BuildingType, Scores} import scatan.model.game.{BaseScatanStateTest, ScatanState} import scatan.model.game.ops.BuildingOps.assignBuilding -import scatan.model.game.ops.EmptySpotsOps.{emptyRoadSpot, emptyStructureSpot} +import scatan.model.game.ops.EmptySpotOps.{emptyRoadSpot, emptyStructureSpot} import scatan.model.game.ops.ScoreOps.* -import scatan.model.game.ops.CardOps.assignDevelopmentCard +import scatan.model.game.ops.DevCardOps.assignDevelopmentCard import scatan.model.components.DevelopmentCard import scatan.model.components.DevelopmentType diff --git a/src/test/scala/scatan/model/game/ops/TradeOpsTest.scala b/src/test/scala/scatan/model/game/ops/TradeOpsTest.scala index 320718de..c0162c90 100644 --- a/src/test/scala/scatan/model/game/ops/TradeOpsTest.scala +++ b/src/test/scala/scatan/model/game/ops/TradeOpsTest.scala @@ -1,7 +1,7 @@ package scatan.model.game.ops import scatan.model.components.* -import scatan.model.game.ops.CardOps.assignResourceCard +import scatan.model.game.ops.ResCardOps.assignResourceCard import scatan.model.game.ops.TradeOps.{tradeWithBank, tradeWithPlayer} import scatan.model.game.{BaseScatanStateTest, ScatanState} From b222672f7221080ae7d15e3bc7a7c735d77280dd Mon Sep 17 00:00:00 2001 From: luigi-borriello00 Date: Thu, 12 Oct 2023 18:47:00 +0200 Subject: [PATCH 04/16] feat(project): optimize imports --- .../scala/scatan/model/game/ScatanEffects.scala | 14 ++++---------- src/main/scala/scatan/model/game/ScatanGame.scala | 3 +-- .../scala/scatan/model/game/ops/AwardOps.scala | 2 +- .../scala/scatan/model/game/ops/BuildingOps.scala | 2 +- .../scala/scatan/model/game/ops/DevCardOps.scala | 3 +-- .../scala/scatan/model/game/ops/ResCardOps.scala | 11 +++-------- .../scala/scatan/model/game/ops/RobberOps.scala | 2 +- .../views/game/components/CardsComponent.scala | 9 ++++----- .../views/game/components/RightTabComponent.scala | 4 ++-- .../scala/scatan/model/ScatanEffectsTest.scala | 2 +- .../scatan/model/game/BaseScatanStateTest.scala | 9 +++------ .../scala/scatan/model/game/ops/AwardOpsTest.scala | 2 +- .../scatan/model/game/ops/BuildingOpsTest.scala | 8 +++----- .../scatan/model/game/ops/DevCardOpsTest.scala | 4 ++-- .../scatan/model/game/ops/ResCardOpsTest.scala | 4 +--- .../scatan/model/game/ops/RobberOpsTest.scala | 2 +- .../scala/scatan/model/game/ops/ScoreOpsTest.scala | 8 +++----- .../scatan/model/map/GameMapWithGraphOps.scala | 5 ++--- 18 files changed, 35 insertions(+), 59 deletions(-) diff --git a/src/main/scala/scatan/model/game/ScatanEffects.scala b/src/main/scala/scatan/model/game/ScatanEffects.scala index dbbd51db..4653c78b 100644 --- a/src/main/scala/scatan/model/game/ScatanEffects.scala +++ b/src/main/scala/scatan/model/game/ScatanEffects.scala @@ -1,21 +1,15 @@ package scatan.model.game import scatan.lib.game.ops.Effect -import scatan.model.components.{BuildingType, ResourceCard} +import scatan.model.components.{BuildingType, ResourceCard, ResourceType} import scatan.model.game.config.ScatanActions.* import scatan.model.game.config.ScatanPlayer -import scatan.model.game.ops.ResCardOps.{assignResourcesFromNumber, stoleResourceCard} -import scatan.model.game.ops.DevCardOps.buyDevelopmentCard - import scatan.model.game.ops.BuildingOps.{assignBuilding, build} -import scatan.model.map.{Hexagon, RoadSpot, StructureSpot} -import scatan.model.components.ResourceCard -import scatan.model.game.ops.TradeOps.tradeWithPlayer +import scatan.model.game.ops.DevCardOps.buyDevelopmentCard +import scatan.model.game.ops.ResCardOps.{assignResourcesFromNumber, stoleResourceCard} import scatan.model.game.ops.RobberOps.moveRobber -import scatan.model.game.ops.TradeOps.tradeWithPlayer +import scatan.model.game.ops.TradeOps.{tradeWithBank, tradeWithPlayer} import scatan.model.map.{Hexagon, RoadSpot, StructureSpot} -import scatan.model.components.ResourceType -import scatan.model.game.ops.TradeOps.tradeWithBank object ScatanEffects: diff --git a/src/main/scala/scatan/model/game/ScatanGame.scala b/src/main/scala/scatan/model/game/ScatanGame.scala index 763af25c..4c9f1bc4 100644 --- a/src/main/scala/scatan/model/game/ScatanGame.scala +++ b/src/main/scala/scatan/model/game/ScatanGame.scala @@ -9,11 +9,10 @@ import scatan.model.components.{ResourceCard, ResourceType} import scatan.model.game.ScatanEffects.* import scatan.model.game.config.ScatanActions.* import scatan.model.game.config.{ScatanActions, ScatanPhases, ScatanPlayer, ScatanSteps} +import scatan.model.game.ops.RobberOps.playersOnRobber import scatan.model.map.{Hexagon, RoadSpot, StructureSpot} import scala.util.Random -import scatan.model.components.ResourceCard -import scatan.model.game.ops.RobberOps.playersOnRobber /** The status of a game of Scatan. It contains all the data without any possible action. * @param game diff --git a/src/main/scala/scatan/model/game/ops/AwardOps.scala b/src/main/scala/scatan/model/game/ops/AwardOps.scala index eaade073..1b84a7cc 100644 --- a/src/main/scala/scatan/model/game/ops/AwardOps.scala +++ b/src/main/scala/scatan/model/game/ops/AwardOps.scala @@ -1,7 +1,7 @@ package scatan.model.game.ops -import scatan.model.components.AssignedBuildingsAdapter.asPlayerMap import scatan.model.components.* +import scatan.model.components.AssignedBuildingsAdapter.asPlayerMap import scatan.model.game.ScatanState import scatan.model.game.config.ScatanPlayer diff --git a/src/main/scala/scatan/model/game/ops/BuildingOps.scala b/src/main/scala/scatan/model/game/ops/BuildingOps.scala index 8fc690d0..0cd9aa6b 100644 --- a/src/main/scala/scatan/model/game/ops/BuildingOps.scala +++ b/src/main/scala/scatan/model/game/ops/BuildingOps.scala @@ -4,7 +4,7 @@ import scatan.model.components.{AssignedBuildings, AssignmentInfo, BuildingType, import scatan.model.game.ScatanState import scatan.model.game.config.ScatanPlayer import scatan.model.game.ops.AwardOps.* -import EmptySpotOps.{emptyRoadSpot, emptyStructureSpot} +import scatan.model.game.ops.EmptySpotOps.{emptyRoadSpot, emptyStructureSpot} import scatan.model.map.{RoadSpot, Spot, StructureSpot} object BuildingOps: diff --git a/src/main/scala/scatan/model/game/ops/DevCardOps.scala b/src/main/scala/scatan/model/game/ops/DevCardOps.scala index d40978f9..b1f56fb2 100644 --- a/src/main/scala/scatan/model/game/ops/DevCardOps.scala +++ b/src/main/scala/scatan/model/game/ops/DevCardOps.scala @@ -1,10 +1,9 @@ package scatan.model.game.ops +import scatan.model.components.{DevelopmentCard, ResourceType} import scatan.model.game.ScatanState import scatan.model.game.config.ScatanPlayer -import scatan.model.components.DevelopmentCard import scatan.model.game.ops.AwardOps.awards -import scatan.model.components.ResourceType object DevCardOps: diff --git a/src/main/scala/scatan/model/game/ops/ResCardOps.scala b/src/main/scala/scatan/model/game/ops/ResCardOps.scala index dd00018f..6c3a0dfe 100644 --- a/src/main/scala/scatan/model/game/ops/ResCardOps.scala +++ b/src/main/scala/scatan/model/game/ops/ResCardOps.scala @@ -1,16 +1,11 @@ package scatan.model.game.ops +import scatan.model.components.{AssignedBuildings, BuildingType, ResourceCard, ResourceType} import scatan.model.game.ScatanState import scatan.model.game.config.ScatanPlayer -import scatan.model.components.ResourceCard +import scatan.model.map.{Hexagon, RoadSpot, StructureSpot, TileContent} + import scala.util.Random -import scatan.model.map.Hexagon -import scatan.model.map.TileContent -import scatan.model.components.AssignedBuildings -import scatan.model.map.StructureSpot -import scatan.model.map.RoadSpot -import scatan.model.components.ResourceType -import scatan.model.components.BuildingType object ResCardOps: diff --git a/src/main/scala/scatan/model/game/ops/RobberOps.scala b/src/main/scala/scatan/model/game/ops/RobberOps.scala index 2d437fcc..4b56919a 100644 --- a/src/main/scala/scatan/model/game/ops/RobberOps.scala +++ b/src/main/scala/scatan/model/game/ops/RobberOps.scala @@ -3,8 +3,8 @@ package scatan.model.game.ops import scatan.model.components.AssignmentInfo import scatan.model.game.ScatanState import scatan.model.game.config.ScatanPlayer -import scatan.model.map.{Hexagon, RoadSpot, StructureSpot} import scatan.model.map.HexagonInMap.layer +import scatan.model.map.{Hexagon, RoadSpot, StructureSpot} object RobberOps: extension (state: ScatanState) diff --git a/src/main/scala/scatan/views/game/components/CardsComponent.scala b/src/main/scala/scatan/views/game/components/CardsComponent.scala index fd44c088..981180db 100644 --- a/src/main/scala/scatan/views/game/components/CardsComponent.scala +++ b/src/main/scala/scatan/views/game/components/CardsComponent.scala @@ -2,14 +2,13 @@ package scatan.views.game.components import com.raquo.laminar.api.L.* import scatan.controllers.game.GameController +import scatan.model.components.* +import scatan.model.components.DevelopmentType.* +import scatan.model.components.ResourceType.* import scatan.model.game.* import scatan.model.game.config.* -import scatan.model.components.* -import scatan.views.utils.TypeUtils.{Displayable, DisplayableSource} -import scatan.views.utils.TypeUtils.{gameController, reactiveState, state} -import ResourceType.* -import DevelopmentType.* import scatan.views.game.components.CardContextMap.{CardType, cardImages, countCardOf} +import scatan.views.utils.TypeUtils.* object CardContextMap: extension (state: ScatanState) diff --git a/src/main/scala/scatan/views/game/components/RightTabComponent.scala b/src/main/scala/scatan/views/game/components/RightTabComponent.scala index 12d1948c..0945d762 100644 --- a/src/main/scala/scatan/views/game/components/RightTabComponent.scala +++ b/src/main/scala/scatan/views/game/components/RightTabComponent.scala @@ -4,8 +4,8 @@ import com.raquo.laminar.api.L.* import scatan.controllers.game.GameController import scatan.model.ApplicationState import scatan.model.components.ResourceType -import scatan.model.game.config.{ScatanActions, ScatanPhases} -import scatan.model.game.{ScatanGame, ScatanState} +import scatan.model.game.ScatanGame +import scatan.model.game.config.ScatanActions import scatan.views.utils.TypeUtils.* object RightTabComponent: diff --git a/src/test/scala/scatan/model/ScatanEffectsTest.scala b/src/test/scala/scatan/model/ScatanEffectsTest.scala index bf93c358..abb83821 100644 --- a/src/test/scala/scatan/model/ScatanEffectsTest.scala +++ b/src/test/scala/scatan/model/ScatanEffectsTest.scala @@ -3,9 +3,9 @@ package scatan.model import scatan.BaseTest import scatan.model.components.{ResourceCard, ResourceType} import scatan.model.game.ScatanEffects.{NextTurnEffect, PlaceRobberEffect, RollEffect, TradeWithPlayerEffect} -import scatan.model.game.{ScatanGame, ScatanState} import scatan.model.game.config.ScatanPlayer import scatan.model.game.ops.ResCardOps.assignResourceCard +import scatan.model.game.{ScatanGame, ScatanState} class ScatanEffectsTest extends BaseTest: diff --git a/src/test/scala/scatan/model/game/BaseScatanStateTest.scala b/src/test/scala/scatan/model/game/BaseScatanStateTest.scala index fa9b87a7..ab9faace 100644 --- a/src/test/scala/scatan/model/game/BaseScatanStateTest.scala +++ b/src/test/scala/scatan/model/game/BaseScatanStateTest.scala @@ -1,14 +1,11 @@ package scatan.model.game import scatan.BaseTest +import scatan.model.components.BuildingType import scatan.model.game.config.ScatanPlayer -import scatan.model.game.ops.EmptySpotOps.emptySpots -import scatan.model.map.Spot -import scatan.model.map.RoadSpot -import scatan.model.game.ops.EmptySpotOps.emptyRoadSpot import scatan.model.game.ops.BuildingOps.assignBuilding -import scatan.model.components.BuildingType -import scatan.model.map.StructureSpot +import scatan.model.game.ops.EmptySpotOps.{emptyRoadSpot, emptySpots} +import scatan.model.map.{RoadSpot, Spot, StructureSpot} abstract class BaseScatanStateTest extends BaseTest: diff --git a/src/test/scala/scatan/model/game/ops/AwardOpsTest.scala b/src/test/scala/scatan/model/game/ops/AwardOpsTest.scala index 7439f520..c6fa59d7 100644 --- a/src/test/scala/scatan/model/game/ops/AwardOpsTest.scala +++ b/src/test/scala/scatan/model/game/ops/AwardOpsTest.scala @@ -1,11 +1,11 @@ package scatan.model.game.ops import scatan.model.components.* -import scatan.model.game.{BaseScatanStateTest, ScatanState} import scatan.model.game.ops.AwardOps.* import scatan.model.game.ops.BuildingOps.assignBuilding import scatan.model.game.ops.DevCardOps.assignDevelopmentCard import scatan.model.game.ops.EmptySpotOps.{emptyRoadSpot, emptyStructureSpot} +import scatan.model.game.{BaseScatanStateTest, ScatanState} class AwardOpsTest extends BaseScatanStateTest: diff --git a/src/test/scala/scatan/model/game/ops/BuildingOpsTest.scala b/src/test/scala/scatan/model/game/ops/BuildingOpsTest.scala index 4e82dc92..0838ba9f 100644 --- a/src/test/scala/scatan/model/game/ops/BuildingOpsTest.scala +++ b/src/test/scala/scatan/model/game/ops/BuildingOpsTest.scala @@ -1,13 +1,11 @@ package scatan.model.game.ops import scatan.model.components.* -import scatan.model.game.ScatanState -import scatan.model.game.{BaseScatanStateTest, ScatanState} +import scatan.model.game.config.ScatanPlayer import scatan.model.game.ops.BuildingOps.{assignBuilding, build} +import scatan.model.game.ops.EmptySpotOps.{emptyRoadSpot, emptyStructureSpot} import scatan.model.game.ops.ResCardOps.assignResourceCard -import scatan.model.game.ops.EmptySpotOps.{emptyStructureSpot, emptyRoadSpot} -import scatan.model.game.BaseScatanStateTest -import scatan.model.game.config.ScatanPlayer +import scatan.model.game.{BaseScatanStateTest, ScatanState} import scatan.model.map.{RoadSpot, StructureSpot} class BuildingOpsTest extends BaseScatanStateTest: diff --git a/src/test/scala/scatan/model/game/ops/DevCardOpsTest.scala b/src/test/scala/scatan/model/game/ops/DevCardOpsTest.scala index 5ae0d260..a7fd9e46 100644 --- a/src/test/scala/scatan/model/game/ops/DevCardOpsTest.scala +++ b/src/test/scala/scatan/model/game/ops/DevCardOpsTest.scala @@ -2,9 +2,9 @@ package scatan.model.game.ops import scatan.lib.game.Game import scatan.model.components.{DevelopmentCard, DevelopmentType, ResourceCard, ResourceType} -import scatan.model.game.{BaseScatanStateTest, ScatanState} -import scatan.model.game.ops.DevCardOps.{buyDevelopmentCard, consumeDevelopmentCard, assignDevelopmentCard} +import scatan.model.game.ops.DevCardOps.{assignDevelopmentCard, buyDevelopmentCard, consumeDevelopmentCard} import scatan.model.game.ops.ResCardOps.assignResourceCard +import scatan.model.game.{BaseScatanStateTest, ScatanState} class DevCardOpsTest extends BaseScatanStateTest: diff --git a/src/test/scala/scatan/model/game/ops/ResCardOpsTest.scala b/src/test/scala/scatan/model/game/ops/ResCardOpsTest.scala index caea079c..5898aa87 100644 --- a/src/test/scala/scatan/model/game/ops/ResCardOpsTest.scala +++ b/src/test/scala/scatan/model/game/ops/ResCardOpsTest.scala @@ -1,11 +1,9 @@ package scatan.model.game.ops import scatan.model.components.{BuildingType, ResourceCard, ResourceCards, ResourceType} -import scatan.model.game.{BaseScatanStateTest, ScatanState} import scatan.model.game.ops.BuildingOps.assignBuilding -import scatan.model.game.ops.ResCardOps.* - import scatan.model.game.ops.EmptySpotOps.emptyStructureSpot +import scatan.model.game.ops.ResCardOps.* import scatan.model.game.{BaseScatanStateTest, ScatanState} import scatan.model.map.HexagonInMap.layer import scatan.model.map.{RoadSpot, Spot, StructureSpot} diff --git a/src/test/scala/scatan/model/game/ops/RobberOpsTest.scala b/src/test/scala/scatan/model/game/ops/RobberOpsTest.scala index 9b53ac66..6d347ec1 100644 --- a/src/test/scala/scatan/model/game/ops/RobberOpsTest.scala +++ b/src/test/scala/scatan/model/game/ops/RobberOpsTest.scala @@ -1,8 +1,8 @@ package scatan.model.game.ops import scatan.model.components.UnproductiveTerrain.Desert -import scatan.model.game.{BaseScatanStateTest, ScatanState} import scatan.model.game.ops.RobberOps.moveRobber +import scatan.model.game.{BaseScatanStateTest, ScatanState} import scatan.model.map.Hexagon class RobberOpsTest extends BaseScatanStateTest: diff --git a/src/test/scala/scatan/model/game/ops/ScoreOpsTest.scala b/src/test/scala/scatan/model/game/ops/ScoreOpsTest.scala index 7d234cfd..36222ac9 100644 --- a/src/test/scala/scatan/model/game/ops/ScoreOpsTest.scala +++ b/src/test/scala/scatan/model/game/ops/ScoreOpsTest.scala @@ -1,13 +1,11 @@ package scatan.model.game.ops -import scatan.model.components.{AssignedBuildings, BuildingType, Scores} -import scatan.model.game.{BaseScatanStateTest, ScatanState} +import scatan.model.components.* import scatan.model.game.ops.BuildingOps.assignBuilding +import scatan.model.game.ops.DevCardOps.assignDevelopmentCard import scatan.model.game.ops.EmptySpotOps.{emptyRoadSpot, emptyStructureSpot} import scatan.model.game.ops.ScoreOps.* -import scatan.model.game.ops.DevCardOps.assignDevelopmentCard -import scatan.model.components.DevelopmentCard -import scatan.model.components.DevelopmentType +import scatan.model.game.{BaseScatanStateTest, ScatanState} class ScoreOpsTest extends BaseScatanStateTest: diff --git a/src/test/scala/scatan/model/map/GameMapWithGraphOps.scala b/src/test/scala/scatan/model/map/GameMapWithGraphOps.scala index c0a1f4e4..8cca28ea 100644 --- a/src/test/scala/scatan/model/map/GameMapWithGraphOps.scala +++ b/src/test/scala/scatan/model/map/GameMapWithGraphOps.scala @@ -1,10 +1,9 @@ package scatan.model.map -import scatan.BaseTest import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks +import scatan.BaseTest import scatan.model.GameMap -import scatan.utils.UnorderedTriple -import scatan.utils.UnorderedPair +import scatan.utils.{UnorderedPair, UnorderedTriple} class GameMapWithGraphOpsTest extends BaseTest with ScalaCheckPropertyChecks: From 0b8de3fbd7948b797ea7fb46238c61f7e831952f Mon Sep 17 00:00:00 2001 From: Manuel Andruccioli Date: Thu, 12 Oct 2023 18:58:40 +0200 Subject: [PATCH 05/16] wip(tile-content): implement the useless feature ever --> creating map with permutation :) --- src/main/scala/scatan/model/GameMap.scala | 6 ++- .../scala/scatan/model/map/TileContent.scala | 49 ++++++++++++++----- 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/src/main/scala/scatan/model/GameMap.scala b/src/main/scala/scatan/model/GameMap.scala index 74285e2d..8f3a664d 100644 --- a/src/main/scala/scatan/model/GameMap.scala +++ b/src/main/scala/scatan/model/GameMap.scala @@ -15,7 +15,7 @@ import scatan.model.components.Terrain final case class GameMap( withTerrainLayers: Int = 2, withSeaLayers: Int = 1, - tileContentsStrategy: Seq[Hexagon] => Map[Hexagon, TileContent] = TileContentStrategyFactory.fixedForLayer2 + tileContentsStrategy: TileContentStrategy = TileContentStrategyFactory.fixedForLayer2 ) extends HexagonalTiledMap(withTerrainLayers + withSeaLayers) with MapWithTileContent: @@ -31,3 +31,7 @@ object GameMapFactory: def randomMap: GameMap = GameMap(tileContentsStrategy = TileContentStrategyFactory.randomForLayer2) + + val strategies: Iterator[TileContentStrategy] = TileContentStrategyFactory.permutationForLayer2.toIterator + def nextPermutation: GameMap = + GameMap(tileContentsStrategy = strategies.next()) diff --git a/src/main/scala/scatan/model/map/TileContent.scala b/src/main/scala/scatan/model/map/TileContent.scala index 2a347ffe..93de0d7e 100644 --- a/src/main/scala/scatan/model/map/TileContent.scala +++ b/src/main/scala/scatan/model/map/TileContent.scala @@ -19,18 +19,20 @@ trait TileContentConfig: def numbers: Seq[Int] def terrains: Seq[Terrain] +type TileContentStrategy = Seq[Hexagon] => Map[Hexagon, TileContent] + /** A factory to create terrains. */ object TileContentStrategyFactory: object ConfigForLayer2 extends TileContentConfig: val terrains: List[Terrain] = List( + 1 * Desert, 4 * Wood, 4 * Sheep, 4 * Wheat, 3 * Rock, - 3 * Brick, - 1 * Desert + 3 * Brick ).flatten val numbers = 2 :: 12 :: (for @@ -38,27 +40,52 @@ object TileContentStrategyFactory: if i != 7 yield List(i, i)).flatten - private def fromConfig(using config: TileContentConfig)(tiles: Seq[Hexagon]): Map[Hexagon, TileContent] = + private def fromConfig(using config: TileContentConfig): TileContentStrategy = val iterator = config.numbers.iterator val tileContents = config.terrains.map { t => t match case Desert => TileContent(t, None) case _ => TileContent(t, iterator.nextOption()) } - Map - .from(tiles.zip(tileContents)) - .withDefaultValue(TileContent(Sea, None)) + tiles => + Map + .from(tiles.zip(tileContents)) + .withDefaultValue(TileContent(Sea, None)) - def fixedForLayer2(tiles: Seq[Hexagon]): Map[Hexagon, TileContent] = + def fixedForLayer2: TileContentStrategy = import ConfigForLayer2.* given TileContentConfig = ConfigForLayer2 - fromConfig(tiles) + fromConfig - def randomForLayer2(tiles: Seq[Hexagon]): Map[Hexagon, TileContent] = + def randomForLayer2: TileContentStrategy = import ConfigForLayer2.* import scala.util.Random.shuffle - given TileContentConfig with val terrains = shuffle(ConfigForLayer2.terrains) val numbers = shuffle(ConfigForLayer2.numbers) - fromConfig(tiles) + fromConfig + + private def removeAtPos[A](list: List[A], n: Int): List[A] = + val splitted = list.splitAt(n) + splitted._1 ::: splitted._2.tail + + private def permutations[A](list: List[A]): LazyList[List[A]] = list match + case Nil => LazyList(Nil) + case _ => + for + i <- list.indices.to(LazyList) + e = list(i) + r = removeAtPos(list, i) + pr <- permutations(r) + yield e :: pr + + def permutationForLayer2: LazyList[TileContentStrategy] = + import ConfigForLayer2.* + for + t <- permutations(terrains) + n <- permutations(numbers.toList) + yield + given TileContentConfig with + val terrains = t + val numbers = n + fromConfig From e11ff41fb5c74456612f440d40808bead714239a Mon Sep 17 00:00:00 2001 From: Manuel Andruccioli Date: Thu, 12 Oct 2023 19:00:00 +0200 Subject: [PATCH 06/16] chore: add some ignores in wartremover --- build.sbt | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/build.sbt b/build.sbt index 7c5754f9..5be83a0b 100644 --- a/build.sbt +++ b/build.sbt @@ -1,15 +1,20 @@ ThisBuild / scalaVersion := "3.3.1" wartremoverWarnings ++= Warts.all -wartremoverWarnings -= Wart.Equals -wartremoverWarnings -= Wart.Overloading -wartremoverWarnings -= Wart.ImplicitParameter -wartremoverWarnings -= Wart.IterableOps -wartremoverWarnings -= Wart.DefaultArguments -wartremoverWarnings -= Wart.AsInstanceOf -wartremoverWarnings -= Wart.OptionPartial -wartremoverWarnings -= Wart.IsInstanceOf -wartremoverWarnings -= Wart.Var + +wartremoverWarnings --= Seq( + Wart.Equals, + Wart.Overloading, + Wart.ImplicitParameter, + Wart.IterableOps, + Wart.DefaultArguments, + Wart.AsInstanceOf, + Wart.OptionPartial, + Wart.IsInstanceOf, + Wart.Var, + Wart.SeqApply, + Wart.Recursion +) lazy val scatan = (project in file(".")) .enablePlugins(ScalaJSPlugin) From 2285c79f2f7995377e3d3c9286cb653c4b8beff5 Mon Sep 17 00:00:00 2001 From: luigi-borriello00 Date: Thu, 12 Oct 2023 19:14:28 +0200 Subject: [PATCH 07/16] feat(application): implement and decored about view --- .../scala/scatan/views/home/AboutView.scala | 22 ++++++++++++++++++- style.css | 8 +++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/main/scala/scatan/views/home/AboutView.scala b/src/main/scala/scatan/views/home/AboutView.scala index 8622bf48..46bd2f4d 100644 --- a/src/main/scala/scatan/views/home/AboutView.scala +++ b/src/main/scala/scatan/views/home/AboutView.scala @@ -17,9 +17,29 @@ private class ScalaJSAboutView(container: String, requirements: View.Requirement with AboutView: override def element: Element = div( + cls := "about-view-container", h1("About"), - p("This is a ScalaJS view"), + p( + "The goal of the project is to create a clone of the board game 'Settlers of Catan', a game for 3 or 4 players. " + ), + p( + "In the game, each participant takes on the role of a settler trying to establish themselves on the island of Catan. " + ), + p( + "The game is played on a board consisting of hexagonal tiles, which are arranged randomly at the beginning of the game. " + ), + p( + "The primary objective is to accumulate essential resources, including wood, clay, wheat, wool, and ore, through the construction of strategically placed settlements, cities, and roads on the island. These resources are obtained based on the results of dice rolls and the location of the structures built." + ), + h2("Built with"), + ul( + li("Scala 3"), + li("Scala.js"), + li("Laminar"), + li("ScalaTest") + ), button( + cls := "home-menu-button", "Back", onClick --> (_ => this.navigateBack()) ) diff --git a/style.css b/style.css index 838fed79..9822bc18 100644 --- a/style.css +++ b/style.css @@ -336,3 +336,11 @@ body { border-radius: 5px; z-index: 1000; } + +.about-view-container{ + color: white; + font-size: x-large; + background-color: rgba(0, 0, 0, 0.5); + border-radius: 1em; + padding: 1em; +} \ No newline at end of file From 986b33b54c4d5b6b0491d91c721589a60387ca9e Mon Sep 17 00:00:00 2001 From: luigi-borriello00 Date: Thu, 12 Oct 2023 19:21:24 +0200 Subject: [PATCH 08/16] feat(about-view): add credits --- .../scala/scatan/views/home/AboutView.scala | 21 +++++++++++++++++++ style.css | 5 +++++ 2 files changed, 26 insertions(+) diff --git a/src/main/scala/scatan/views/home/AboutView.scala b/src/main/scala/scatan/views/home/AboutView.scala index 46bd2f4d..bb26c89b 100644 --- a/src/main/scala/scatan/views/home/AboutView.scala +++ b/src/main/scala/scatan/views/home/AboutView.scala @@ -38,6 +38,27 @@ private class ScalaJSAboutView(container: String, requirements: View.Requirement li("Laminar"), li("ScalaTest") ), + h2("Authors"), + ul( + // add links to github profiles + li( + a( + cls := "about-link", + "Luigi Borriello", + href := "https://github.com/luigi-borriello00" + ) + ), + li( + a( + cls := "about-link", + "Manuel Andruccioli", + href := "https://github.com/manuandru" + ) + ), + li( + a(cls := "about-link", "Alessandro Mazzoli", href := "https://github.com/alemazzo") + ) + ), button( cls := "home-menu-button", "Back", diff --git a/style.css b/style.css index 9822bc18..22bfb2fc 100644 --- a/style.css +++ b/style.css @@ -343,4 +343,9 @@ body { background-color: rgba(0, 0, 0, 0.5); border-radius: 1em; padding: 1em; +} + +.about-link{ + color: white; + text-decoration: none; } \ No newline at end of file From 5f4d81aa00f120c590bf24e2dceac860588d1ae1 Mon Sep 17 00:00:00 2001 From: Manuel Andruccioli Date: Thu, 12 Oct 2023 20:11:53 +0200 Subject: [PATCH 09/16] wip(state): add gamemap as a parameter in state creation --- src/main/scala/scatan/lib/game/Game.scala | 5 ++++- src/main/scala/scatan/lib/game/Rules.scala | 8 +++++--- .../scala/scatan/lib/game/dsl/GameDSLDomain.scala | 5 ++++- .../scala/scatan/lib/game/dsl/ops/GameCtxOps.scala | 4 +++- src/main/scala/scatan/lib/game/ops/RulesOps.scala | 3 ++- src/main/scala/scatan/model/ApplicationState.scala | 4 ++-- src/main/scala/scatan/model/game/ScatanDSL.scala | 2 +- src/main/scala/scatan/model/game/ScatanGame.scala | 5 +++-- src/main/scala/scatan/model/game/ScatanState.scala | 11 +++++++---- 9 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/main/scala/scatan/lib/game/Game.scala b/src/main/scala/scatan/lib/game/Game.scala index f7188365..ba0266ab 100644 --- a/src/main/scala/scatan/lib/game/Game.scala +++ b/src/main/scala/scatan/lib/game/Game.scala @@ -1,5 +1,7 @@ package scatan.lib.game +import scatan.model.GameMap + /** A game status is a pair of phase and step. * @param phase * the current phase @@ -48,6 +50,7 @@ final case class Game[State, PhaseType, StepType, ActionType, Player]( object Game: def apply[State, PhaseType, StepType, ActionType, Player]( + gameMap: GameMap, players: Seq[Player] )(using rules: Rules[State, PhaseType, StepType, ActionType, Player] @@ -56,7 +59,7 @@ object Game: val iterator = rules.phaseTurnIteratorFactories.get(rules.startingPhase).map(_(players)).getOrElse(players.iterator) Game( players = players, - state = rules.startingStateFactory(players), + state = rules.startingStateFactory(gameMap, players), gameStatus = GameStatus(rules.startingPhase, rules.startingSteps(rules.startingPhase)), turn = Turn[Player](1, iterator.next()), playersIterator = iterator, diff --git a/src/main/scala/scatan/lib/game/Rules.scala b/src/main/scala/scatan/lib/game/Rules.scala index f8accef6..3b8c7f68 100644 --- a/src/main/scala/scatan/lib/game/Rules.scala +++ b/src/main/scala/scatan/lib/game/Rules.scala @@ -1,5 +1,7 @@ package scatan.lib.game +import scatan.model.GameMap + /** Rules of a game. * @param startingStateFactory * initial state of the game @@ -30,7 +32,7 @@ package scatan.lib.game */ final case class Rules[State, P, S, A, Player]( allowedPlayersSizes: Set[Int], - startingStateFactory: Seq[Player] => State, + startingStateFactory: (GameMap, Seq[Player]) => State, startingPhase: P, startingSteps: Map[P, S], endingSteps: Map[P, S], @@ -71,10 +73,10 @@ final case class Rules[State, P, S, A, Player]( object Rules: def empty[State, P, S, A, Player]: Rules[State, P, S, A, Player] = - fromStateFactory(_ => null.asInstanceOf[State]) + fromStateFactory((_, _) => null.asInstanceOf[State]) def fromStateFactory[State, P, S, A, Player]( - initialStateFactory: Seq[Player] => State + initialStateFactory: (GameMap, Seq[Player]) => State ): Rules[State, P, S, A, Player] = Rules[State, P, S, A, Player]( startingStateFactory = initialStateFactory, diff --git a/src/main/scala/scatan/lib/game/dsl/GameDSLDomain.scala b/src/main/scala/scatan/lib/game/dsl/GameDSLDomain.scala index 50db1a68..d47e7abe 100644 --- a/src/main/scala/scatan/lib/game/dsl/GameDSLDomain.scala +++ b/src/main/scala/scatan/lib/game/dsl/GameDSLDomain.scala @@ -1,5 +1,7 @@ package scatan.lib.game.dsl +import scatan.model.GameMap + private object GameDSLDomain: import PropertiesDSL.* @@ -12,7 +14,8 @@ private object GameDSLDomain: players: OptionalProperty[PlayersCtx] = OptionalProperty[PlayersCtx](), winner: OptionalProperty[State => Option[Player]] = OptionalProperty[State => Option[Player]](), initialPhase: OptionalProperty[P] = OptionalProperty[P](), - stateFactory: OptionalProperty[Seq[Player] => State] = OptionalProperty[Seq[Player] => State]() + stateFactory: OptionalProperty[(GameMap, Seq[Player]) => State] = + OptionalProperty[(GameMap, Seq[Player]) => State]() ) /** The players context is used to define the players info of the game. diff --git a/src/main/scala/scatan/lib/game/dsl/ops/GameCtxOps.scala b/src/main/scala/scatan/lib/game/dsl/ops/GameCtxOps.scala index a3a3b210..662fe640 100644 --- a/src/main/scala/scatan/lib/game/dsl/ops/GameCtxOps.scala +++ b/src/main/scala/scatan/lib/game/dsl/ops/GameCtxOps.scala @@ -2,6 +2,7 @@ package scatan.lib.game.dsl.ops import scatan.lib.game.dsl.GameDSLDomain.* import scatan.lib.game.dsl.PropertiesDSL.* +import scatan.model.GameMap object GameCtxOps: @@ -31,5 +32,6 @@ object GameCtxOps: /** Define the initial state factory of the game. */ - def StateFactory[State, Player]: Contexted[GameCtx[State, ?, ?, ?, Player], PropertySetter[Seq[Player] => State]] = + def StateFactory[State, Player] + : Contexted[GameCtx[State, ?, ?, ?, Player], PropertySetter[(GameMap, Seq[Player]) => State]] = ctx ?=> ctx.stateFactory diff --git a/src/main/scala/scatan/lib/game/ops/RulesOps.scala b/src/main/scala/scatan/lib/game/ops/RulesOps.scala index ebfd7afd..50b1716f 100644 --- a/src/main/scala/scatan/lib/game/ops/RulesOps.scala +++ b/src/main/scala/scatan/lib/game/ops/RulesOps.scala @@ -1,6 +1,7 @@ package scatan.lib.game.ops import scatan.lib.game.{GameStatus, Rules} +import scatan.model.GameMap /** Operations on [[Rules]] related to their construction. */ @@ -16,7 +17,7 @@ object RulesOps: def withAllowedPlayersSizes(sizes: Set[Int]): Rules[State, P, S, A, Player] = rules.copy(allowedPlayersSizes = sizes) - def withStartingStateFactory(stateFactory: Seq[Player] => State): Rules[State, P, S, A, Player] = + def withStartingStateFactory(stateFactory: (GameMap, Seq[Player]) => State): Rules[State, P, S, A, Player] = rules.copy(startingStateFactory = stateFactory) /** Set the starting phase for this game. diff --git a/src/main/scala/scatan/model/ApplicationState.scala b/src/main/scala/scatan/model/ApplicationState.scala index c5687eb6..6af88524 100644 --- a/src/main/scala/scatan/model/ApplicationState.scala +++ b/src/main/scala/scatan/model/ApplicationState.scala @@ -5,9 +5,9 @@ import scatan.model.game.ScatanGame import scatan.model.game.config.ScatanPlayer final case class ApplicationState(game: Option[ScatanGame]) extends Model.State: - def createGame(usernames: String*): ApplicationState = + def createGame(gameMap: GameMap, usernames: String*): ApplicationState = val players = usernames.map(ScatanPlayer(_)) - ApplicationState(Option(ScatanGame(players))) + ApplicationState(Option(ScatanGame(gameMap, players))) object ApplicationState: def apply(): ApplicationState = ApplicationState(Option.empty) diff --git a/src/main/scala/scatan/model/game/ScatanDSL.scala b/src/main/scala/scatan/model/game/ScatanDSL.scala index 0f7798ea..813be4d1 100644 --- a/src/main/scala/scatan/model/game/ScatanDSL.scala +++ b/src/main/scala/scatan/model/game/ScatanDSL.scala @@ -19,7 +19,7 @@ object ScatanDSL: WinnerFunction := winner InitialPhase := ScatanPhases.Setup - StateFactory := ScatanState.apply + StateFactory := { (m, p) => ScatanState(m, p) } Phase { PhaseType := ScatanPhases.Setup diff --git a/src/main/scala/scatan/model/game/ScatanGame.scala b/src/main/scala/scatan/model/game/ScatanGame.scala index 2e188149..db958951 100644 --- a/src/main/scala/scatan/model/game/ScatanGame.scala +++ b/src/main/scala/scatan/model/game/ScatanGame.scala @@ -12,6 +12,7 @@ import scatan.model.game.config.{ScatanActions, ScatanPhases, ScatanPlayer, Scat import scatan.model.map.{Hexagon, RoadSpot, StructureSpot} import scala.util.Random +import scatan.model.GameMap /** The status of a game of Scatan. It contains all the data without any possible action. * @param game @@ -95,5 +96,5 @@ class ScatanGame(game: Game[ScatanState, ScatanPhases, ScatanSteps, ScatanAction object ScatanGame: def apply(game: Game[ScatanState, ScatanPhases, ScatanSteps, ScatanActions, ScatanPlayer]): ScatanGame = new ScatanGame(game) - def apply(players: Seq[ScatanPlayer]): ScatanGame = - new ScatanGame(Game(players)(using ScatanDSL.rules)) + def apply(gameMap: GameMap, players: Seq[ScatanPlayer]): ScatanGame = + new ScatanGame(Game(gameMap, players)(using ScatanDSL.rules)) diff --git a/src/main/scala/scatan/model/game/ScatanState.scala b/src/main/scala/scatan/model/game/ScatanState.scala index cb269eb0..bbc87f5d 100644 --- a/src/main/scala/scatan/model/game/ScatanState.scala +++ b/src/main/scala/scatan/model/game/ScatanState.scala @@ -47,15 +47,18 @@ object ScatanState: * a new ScatanState with the specified players */ def apply(players: Seq[ScatanPlayer]): ScatanState = - ScatanState(players, DevelopmentCardsDeck.defaultOrdered) + ScatanState(GameMap(), players, DevelopmentCardsDeck.defaultOrdered) - def apply(players: Seq[ScatanPlayer], developmentCardsDeck: DevelopmentCardsDeck): ScatanState = + def apply( + gameMap: GameMap, + players: Seq[ScatanPlayer], + developmentCardsDeck: DevelopmentCardsDeck = DevelopmentCardsDeck.defaultOrdered + ): ScatanState = require(players.sizeIs >= 3 && players.sizeIs <= 4, "The number of players must be between 3 and 4") - val gameMap = GameMap() val desertHexagon = gameMap.tiles.find(gameMap.toContent(_).terrain == Desert).get ScatanState( players, - GameMap(), + gameMap, AssignedBuildings.empty, Awards.empty, ResourceCards.empty(players), From 0577b2eb8b8a0245ee81720d9c0d0fcc638af107 Mon Sep 17 00:00:00 2001 From: Manuel Andruccioli Date: Thu, 12 Oct 2023 20:20:26 +0200 Subject: [PATCH 10/16] test: adjust syntax --- .../scala/scatan/lib/game/EmptyDomain.scala | 2 +- src/test/scala/scatan/lib/game/GameTest.scala | 14 ++++++++------ src/test/scala/scatan/lib/game/RulesTest.scala | 6 ++++-- .../scatan/lib/game/ops/GamePlayOpsTest.scala | 3 ++- .../scatan/lib/game/ops/GameTurnOpsTest.scala | 5 +++-- .../scatan/lib/game/ops/GameWinOpsTest.scala | 9 +++++---- .../scatan/lib/game/ops/RulesOpsTest.scala | 5 +++-- .../scatan/model/ApplicationStateTest.scala | 10 +++++----- src/test/scala/scatan/model/GameTest.scala | 18 +++++++++--------- .../scatan/model/game/ScatanRulesTest.scala | 4 +++- .../scatan/model/game/ScatanStateTest.scala | 3 ++- 11 files changed, 45 insertions(+), 34 deletions(-) diff --git a/src/test/scala/scatan/lib/game/EmptyDomain.scala b/src/test/scala/scatan/lib/game/EmptyDomain.scala index 6469884e..0907a52c 100644 --- a/src/test/scala/scatan/lib/game/EmptyDomain.scala +++ b/src/test/scala/scatan/lib/game/EmptyDomain.scala @@ -28,7 +28,7 @@ object EmptyDomain: Players { CanBe := 2 to 4 } - StateFactory := (_ => State()) + StateFactory := ((_, _) => State()) InitialPhase := MyPhases.Game WinnerFunction := (_ => None) diff --git a/src/test/scala/scatan/lib/game/GameTest.scala b/src/test/scala/scatan/lib/game/GameTest.scala index 82480f92..3c266f1e 100644 --- a/src/test/scala/scatan/lib/game/GameTest.scala +++ b/src/test/scala/scatan/lib/game/GameTest.scala @@ -1,38 +1,40 @@ package scatan.lib.game import scatan.BaseTest +import scatan.model.GameMap class GameTest extends BaseTest: import EmptyDomain.* val players = Seq(Player("A"), Player("B"), Player("C")) + val gameMap = GameMap() given EmptyDomainRules = EmptyDomain.rules "A Game" should "exists given the rules" in { - val game = Game(players) + val game = Game(gameMap, players) } it should "have a state" in { - val game = Game(players) + val game = Game(gameMap, players) game.state should be(State()) } it should "have a turn" in { - val game = Game(players) + val game = Game(gameMap, players) game.turn should be(Turn.initial(players.head)) } it should "have a game status" in { - val game = Game(players) + val game = Game(gameMap, players) game.gameStatus should be(GameStatus(MyPhases.Game, Steps.Initial)) } it should "have a players iterator" in { - val game = Game(players) + val game = Game(gameMap, players) game.playersIterator.toSeq should be(players.tail) } it should "contains the rules" in { - val game = Game(players) + val game = Game(gameMap, players) game.rules shouldBe a[EmptyDomainRules] } diff --git a/src/test/scala/scatan/lib/game/RulesTest.scala b/src/test/scala/scatan/lib/game/RulesTest.scala index c000b107..1dedf3a4 100644 --- a/src/test/scala/scatan/lib/game/RulesTest.scala +++ b/src/test/scala/scatan/lib/game/RulesTest.scala @@ -1,11 +1,13 @@ package scatan.lib.game import scatan.BaseTest +import scatan.model.GameMap class RulesTest extends BaseTest: import EmptyDomain.* val players = Seq(Player("Alice"), Player("Bob"), Player("Carol")) + val gameMap = GameMap() val emptyGameRules = EmptyDomain.rules "The Rules" should "exists" in { @@ -22,8 +24,8 @@ class RulesTest extends BaseTest: it should "have an initial state factory" in { emptyGameRules.startingStateFactory shouldBe a[Seq[Player] => State] - emptyGameRules.startingStateFactory(players) shouldBe a[State] - emptyGameRules.startingStateFactory(players) shouldBe State() + emptyGameRules.startingStateFactory(gameMap, players) shouldBe a[State] + emptyGameRules.startingStateFactory(gameMap, players) shouldBe State() } it should "have a initial phase" in { diff --git a/src/test/scala/scatan/lib/game/ops/GamePlayOpsTest.scala b/src/test/scala/scatan/lib/game/ops/GamePlayOpsTest.scala index 51d184f1..2dadcd76 100644 --- a/src/test/scala/scatan/lib/game/ops/GamePlayOpsTest.scala +++ b/src/test/scala/scatan/lib/game/ops/GamePlayOpsTest.scala @@ -4,6 +4,7 @@ import scatan.BaseTest import scatan.lib.game.EmptyDomain.Actions.{NotPlayableAction, StartGame} import scatan.lib.game.ops.GamePlayOps.{canPlay, play} import scatan.lib.game.{EmptyDomain, Game} +import scatan.model.GameMap class GamePlayOpsTest extends BaseTest: @@ -11,7 +12,7 @@ class GamePlayOpsTest extends BaseTest: given EmptyDomainRules = EmptyDomain.rules val players = Seq(Player("p1"), Player("p2"), Player("p3")) - val game = Game(players) + val game = Game(GameMap(), players) "A Game" should "allow to check if an action is playable" in { game.canPlay(StartGame) shouldBe true diff --git a/src/test/scala/scatan/lib/game/ops/GameTurnOpsTest.scala b/src/test/scala/scatan/lib/game/ops/GameTurnOpsTest.scala index f78b0ca4..39398a86 100644 --- a/src/test/scala/scatan/lib/game/ops/GameTurnOpsTest.scala +++ b/src/test/scala/scatan/lib/game/ops/GameTurnOpsTest.scala @@ -7,6 +7,7 @@ import scatan.lib.game.ops.GamePlayOps.play import scatan.lib.game.ops.GameTurnOps.nextTurn import scatan.lib.game.ops.RulesOps.{withNextPhase, withStartingStep} import scatan.lib.game.{EmptyDomain, Game, GameStatus} +import scatan.model.GameMap class GameTurnOpsTest extends BaseTest: @@ -15,14 +16,14 @@ class GameTurnOpsTest extends BaseTest: val players = Seq(Player("p1"), Player("p2"), Player("p3")) "A Game" should "allow to change turn" in { - val game = Game(players) + val game = Game(GameMap(), players) val newGame = game.play(NextTurn)(using NextTurnEffect) newGame should be(defined) newGame.get.turn.player should be(players(1)) } it should "also change the phase if the iterator is empty" in { - val game = Game(players) + val game = Game(GameMap(), players) var newGame = game newGame.gameStatus should be(GameStatus(MyPhases.Game, Steps.Initial)) newGame = newGame.play(NextTurn)(using NextTurnEffect).get diff --git a/src/test/scala/scatan/lib/game/ops/GameWinOpsTest.scala b/src/test/scala/scatan/lib/game/ops/GameWinOpsTest.scala index a5b4713c..42215b42 100644 --- a/src/test/scala/scatan/lib/game/ops/GameWinOpsTest.scala +++ b/src/test/scala/scatan/lib/game/ops/GameWinOpsTest.scala @@ -4,6 +4,7 @@ import scatan.BaseTest import scatan.lib.game.ops.GameWinOps.* import scatan.lib.game.ops.RulesOps.withWinnerFunction import scatan.lib.game.{EmptyDomain, Game} +import scatan.model.GameMap class GameWinOpsTest extends BaseTest: @@ -12,15 +13,15 @@ class GameWinOpsTest extends BaseTest: val players = Seq(Player("p1"), Player("p2"), Player("p3")) "A Game" should "expose a isOver method" in { - val game = Game(players) + val game = Game(GameMap(), players) game.isOver shouldBe false - val endedGame = Game(players)(using EmptyDomain.rules.withWinnerFunction(_ => Some(players.head))) + val endedGame = Game(GameMap(), players)(using EmptyDomain.rules.withWinnerFunction(_ => Some(players.head))) endedGame.isOver shouldBe true } it should "expose a winner method" in { - val game = Game(players) + val game = Game(GameMap(), players) game.winner shouldBe None - val endedGame = Game(players)(using EmptyDomain.rules.withWinnerFunction(_ => Some(players.head))) + val endedGame = Game(GameMap(), players)(using EmptyDomain.rules.withWinnerFunction(_ => Some(players.head))) endedGame.winner shouldBe Some(players.head) } diff --git a/src/test/scala/scatan/lib/game/ops/RulesOpsTest.scala b/src/test/scala/scatan/lib/game/ops/RulesOpsTest.scala index 3282816e..12f6ad56 100644 --- a/src/test/scala/scatan/lib/game/ops/RulesOpsTest.scala +++ b/src/test/scala/scatan/lib/game/ops/RulesOpsTest.scala @@ -3,6 +3,7 @@ package scatan.lib.game.ops import scatan.BaseTest import scatan.lib.game.ops.RulesOps.* import scatan.lib.game.{EmptyDomain, GameStatus} +import scatan.model.GameMap class RulesOpsTest extends BaseTest: @@ -14,9 +15,9 @@ class RulesOpsTest extends BaseTest: } it should "allow to specify the starting state factory" in { - val newRules = rules.withStartingStateFactory((_) => State()) + val newRules = rules.withStartingStateFactory((_, _) => State()) val players = Seq(Player("a"), Player("b")) - newRules.startingStateFactory(players) should be(EmptyDomain.State()) + newRules.startingStateFactory(GameMap(), players) should be(EmptyDomain.State()) } it should "allow to specify the starting phase" in { diff --git a/src/test/scala/scatan/model/ApplicationStateTest.scala b/src/test/scala/scatan/model/ApplicationStateTest.scala index 85341e15..8c8e73c1 100644 --- a/src/test/scala/scatan/model/ApplicationStateTest.scala +++ b/src/test/scala/scatan/model/ApplicationStateTest.scala @@ -18,19 +18,19 @@ class ApplicationStateTest extends BaseTest: it should "allow to create a game" in { val applicationState: ApplicationState = ApplicationState() - val applicationState2 = applicationState.createGame("Player 1", "Player 2", "Player 3", "Player 4") + val applicationState2 = applicationState.createGame(GameMap(), "Player 1", "Player 2", "Player 3", "Player 4") applicationState2.game should not be (Option.empty[UnkownGame]) } it should "allow to create a game with 3 players" in { val applicationState: ApplicationState = ApplicationState() - val applicationState2 = applicationState.createGame("Player 1", "Player 2", "Player 3") + val applicationState2 = applicationState.createGame(GameMap(), "Player 1", "Player 2", "Player 3") applicationState2.game should not be (Option.empty[UnkownGame]) } it should "allow to create a game with 4 players" in { val applicationState: ApplicationState = ApplicationState() - val applicationState2 = applicationState.createGame("Player 1", "Player 2", "Player 3", "Player 4") + val applicationState2 = applicationState.createGame(GameMap(), "Player 1", "Player 2", "Player 3", "Player 4") applicationState2.game should not be (Option.empty[UnkownGame]) } @@ -38,7 +38,7 @@ class ApplicationStateTest extends BaseTest: val applicationState: ApplicationState = ApplicationState() for n <- 0 to 2 yield assertThrows[IllegalArgumentException] { - applicationState.createGame((1 to n).map(i => s"Player $i")*) + applicationState.createGame(GameMap(), (1 to n).map(i => s"Player $i")*) } } @@ -46,6 +46,6 @@ class ApplicationStateTest extends BaseTest: val applicationState: ApplicationState = ApplicationState() for n <- 5 to 10 yield assertThrows[IllegalArgumentException] { - applicationState.createGame((1 to n).map(i => s"Player $i")*) + applicationState.createGame(GameMap(), (1 to n).map(i => s"Player $i")*) } } diff --git a/src/test/scala/scatan/model/GameTest.scala b/src/test/scala/scatan/model/GameTest.scala index 90a8c67f..e3a1d563 100644 --- a/src/test/scala/scatan/model/GameTest.scala +++ b/src/test/scala/scatan/model/GameTest.scala @@ -29,46 +29,46 @@ class GameTest extends BaseTest: } it should "have players" in { - val game = Game(threePlayers) + val game = Game(GameMap(), threePlayers) game.players should be(threePlayers) } it should "expose if the game is over" in { - val game = Game(threePlayers) + val game = Game(GameMap(), threePlayers) game.isOver shouldBe false } it should "have a winner when the game is over" in { - val game = Game(threePlayers) + val game = Game(GameMap(), threePlayers) game.winner shouldBe None } it should "take players" in { - val game = Game(threePlayers) + val game = Game(GameMap(), threePlayers) game.players should be(threePlayers) } it should "not allow fewer than 3 players" in { for n <- 0 to 2 yield assertThrows[IllegalArgumentException] { - Game(players(n)) + Game(GameMap(), players(n)) } } it should "not allow more than 4 players" in { for n <- 5 to 10 yield assertThrows[IllegalArgumentException] { - Game(players(n)) + Game(GameMap(), players(n)) } } it should "have a status" in { - val game = Game(threePlayers) + val game = Game(GameMap(), threePlayers) game.gameStatus shouldBe GameStatus(ScatanPhases.Setup, ScatanSteps.SetupSettlement) } it should "have a turn" in { - val game = Game(threePlayers) + val game = Game(GameMap(), threePlayers) game.turn.number shouldBe 1 game.turn.player shouldBe threePlayers.head } @@ -87,7 +87,7 @@ class GameTest extends BaseTest: yield newGame it should "allow to change turn" in { - val game = Game(threePlayers) + val game = Game(GameMap(), threePlayers) for newGame <- nextTurn(game) do newGame.turn.number shouldBe 2 diff --git a/src/test/scala/scatan/model/game/ScatanRulesTest.scala b/src/test/scala/scatan/model/game/ScatanRulesTest.scala index 56b52000..9e45fedb 100644 --- a/src/test/scala/scatan/model/game/ScatanRulesTest.scala +++ b/src/test/scala/scatan/model/game/ScatanRulesTest.scala @@ -4,6 +4,7 @@ import org.scalatest.matchers.should.Matchers.shouldBe import scatan.BaseTest import scatan.lib.game.GameStatus import scatan.model.game.config.{ScatanActions, ScatanPhases, ScatanPlayer, ScatanSteps} +import scatan.model.GameMap class ScatanRulesTest extends BaseTest: @@ -19,7 +20,8 @@ class ScatanRulesTest extends BaseTest: it should "start with a Scatan State" in { val players = Seq(ScatanPlayer("a"), ScatanPlayer("b"), ScatanPlayer("c")) - val initialState = rules.startingStateFactory(players) + + val initialState = rules.startingStateFactory(GameMap(), players) initialState should be(ScatanState(players)) } diff --git a/src/test/scala/scatan/model/game/ScatanStateTest.scala b/src/test/scala/scatan/model/game/ScatanStateTest.scala index 75954f70..e6995fdf 100644 --- a/src/test/scala/scatan/model/game/ScatanStateTest.scala +++ b/src/test/scala/scatan/model/game/ScatanStateTest.scala @@ -64,6 +64,7 @@ class ScatanStateTest extends BaseScatanStateTest: it should "have a development cards deck" in { val state = ScatanState(threePlayers) state.developmentCardsDeck shouldBe a[DevelopmentCardsDeck] - val stateWithOrderedDeck = ScatanState(threePlayers, developmentCardsDeck = DevelopmentCardsDeck.defaultOrdered) + val stateWithOrderedDeck = + ScatanState(GameMap(), threePlayers, developmentCardsDeck = DevelopmentCardsDeck.defaultOrdered) stateWithOrderedDeck.developmentCardsDeck shouldBe DevelopmentCardsDeck.defaultOrdered } From 5ef1a99a3dcb628f4eff1175c591db00330a8c47 Mon Sep 17 00:00:00 2001 From: Manuel Andruccioli Date: Thu, 12 Oct 2023 20:27:30 +0200 Subject: [PATCH 11/16] fix(state): remove repeated map initialization --- src/main/scala/scatan/model/game/ScatanState.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/scatan/model/game/ScatanState.scala b/src/main/scala/scatan/model/game/ScatanState.scala index bbc87f5d..3d251db9 100644 --- a/src/main/scala/scatan/model/game/ScatanState.scala +++ b/src/main/scala/scatan/model/game/ScatanState.scala @@ -50,7 +50,7 @@ object ScatanState: ScatanState(GameMap(), players, DevelopmentCardsDeck.defaultOrdered) def apply( - gameMap: GameMap, + gameMap: GameMap = GameMap(), players: Seq[ScatanPlayer], developmentCardsDeck: DevelopmentCardsDeck = DevelopmentCardsDeck.defaultOrdered ): ScatanState = From 2ff5db083518c2d81789f0d1890424967abec103 Mon Sep 17 00:00:00 2001 From: Manuel Andruccioli Date: Thu, 12 Oct 2023 20:32:07 +0200 Subject: [PATCH 12/16] fix(test): adjust types --- src/test/scala/scatan/lib/game/RulesTest.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/scala/scatan/lib/game/RulesTest.scala b/src/test/scala/scatan/lib/game/RulesTest.scala index 1dedf3a4..e708c09a 100644 --- a/src/test/scala/scatan/lib/game/RulesTest.scala +++ b/src/test/scala/scatan/lib/game/RulesTest.scala @@ -23,7 +23,7 @@ class RulesTest extends BaseTest: } it should "have an initial state factory" in { - emptyGameRules.startingStateFactory shouldBe a[Seq[Player] => State] + emptyGameRules.startingStateFactory shouldBe a[(GameMap, Seq[Player]) => State] emptyGameRules.startingStateFactory(gameMap, players) shouldBe a[State] emptyGameRules.startingStateFactory(gameMap, players) shouldBe State() } From 7b2ca2ae211951112706d4eabd3f48115e225373 Mon Sep 17 00:00:00 2001 From: Manuel Andruccioli Date: Thu, 12 Oct 2023 21:14:16 +0200 Subject: [PATCH 13/16] wip(game-map): implement gamemap factory --- src/main/scala/scatan/model/GameMap.scala | 8 +++++++ .../scatan/model/map/GameMapFactoryTest.scala | 24 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 src/test/scala/scatan/model/map/GameMapFactoryTest.scala diff --git a/src/main/scala/scatan/model/GameMap.scala b/src/main/scala/scatan/model/GameMap.scala index 8f3a664d..5d246ce8 100644 --- a/src/main/scala/scatan/model/GameMap.scala +++ b/src/main/scala/scatan/model/GameMap.scala @@ -24,6 +24,14 @@ final case class GameMap( override val toContent: Map[Hexagon, TileContent] = tileContentsStrategy(tileWithTerrain) + override def equals(x: Any): Boolean = + x match + case that: GameMap => + this.withTerrainLayers == that.withTerrainLayers && + this.withSeaLayers == that.withSeaLayers && + (this.toContent.toSet & that.toContent.toSet).sizeIs == this.toContent.size + case _ => false + object GameMapFactory: def defaultMap: GameMap = diff --git a/src/test/scala/scatan/model/map/GameMapFactoryTest.scala b/src/test/scala/scatan/model/map/GameMapFactoryTest.scala new file mode 100644 index 00000000..28845fef --- /dev/null +++ b/src/test/scala/scatan/model/map/GameMapFactoryTest.scala @@ -0,0 +1,24 @@ +package scatan.model.map + +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks +import scatan.BaseTest +import scatan.model.GameMap +import scatan.model.GameMapFactory + +class GameMapFactoryTest extends BaseTest with ScalaCheckPropertyChecks: + + "A GameMapFactory" should "generate a default map" in { + val map = GameMapFactory.defaultMap + map should be(GameMap()) + } + + // If the random generate the same map, it will fail. Which is the probability of that? :) + it should "generate a random map" in { + val random = GameMapFactory.randomMap + random should not be GameMap() + } + + it should "generate a map with a permutation" in { + val permutations = (1 to 100).map(_ => GameMapFactory.nextPermutation) + permutations.toSet.size should be > 1 + } From 05725d4801a749cf405aa79881d5a4bdceb18bf3 Mon Sep 17 00:00:00 2001 From: Manuel Andruccioli Date: Thu, 12 Oct 2023 21:22:12 +0200 Subject: [PATCH 14/16] wip(map-pick): add map picker in setup view --- .../controllers/game/SetUpController.scala | 7 +- .../scala/scatan/views/game/SetUpView.scala | 46 +++++++++- .../game/components/map/MapComponent.scala | 87 +++++++++++++++++++ style.css | 32 +++++++ 4 files changed, 168 insertions(+), 4 deletions(-) create mode 100644 src/main/scala/scatan/views/game/components/map/MapComponent.scala diff --git a/src/main/scala/scatan/controllers/game/SetUpController.scala b/src/main/scala/scatan/controllers/game/SetUpController.scala index 8c5782b2..a0fa4cdb 100644 --- a/src/main/scala/scatan/controllers/game/SetUpController.scala +++ b/src/main/scala/scatan/controllers/game/SetUpController.scala @@ -3,11 +3,12 @@ package scatan.controllers.game import scatan.lib.mvc.{BaseController, Controller} import scatan.model.ApplicationState import scatan.views.game.SetUpView +import scatan.model.GameMap /** This is the controller for the setup page. */ trait SetUpController extends Controller[ApplicationState]: - def startGame(usernames: String*): Unit + def startGame(gameMap: GameMap, usernames: String*): Unit object SetUpController: def apply(requirements: Controller.Requirements[SetUpView, ApplicationState]): SetUpController = @@ -21,5 +22,5 @@ private class SetUpControllerImpl(requirements: Controller.Requirements[SetUpVie extends BaseController(requirements) with SetUpController: - override def startGame(usernames: String*): Unit = - this.model.update(_.createGame(usernames*)) + override def startGame(gameMap: GameMap, usernames: String*): Unit = + this.model.update(_.createGame(gameMap, usernames*)) diff --git a/src/main/scala/scatan/views/game/SetUpView.scala b/src/main/scala/scatan/views/game/SetUpView.scala index 3f34892d..7dd1f440 100644 --- a/src/main/scala/scatan/views/game/SetUpView.scala +++ b/src/main/scala/scatan/views/game/SetUpView.scala @@ -5,6 +5,14 @@ import scatan.Pages import scatan.controllers.game.SetUpController import scatan.lib.mvc.{BaseScalaJSView, View} import scatan.model.ApplicationState +import scatan.views.game.components.map.MapComponent +import scatan.model.GameMap +import MapSelectionMode.* +import scatan.views.game.components.LeftTabComponent.buttonsComponent +import scatan.model.GameMapFactory + +enum MapSelectionMode: + case Default, Random, WithIterator /** This is the view for the setup page. */ @@ -35,6 +43,18 @@ private class ScalaJsSetUpView(container: String, requirements: View.Requirement val numberOfUsers: Var[Int] = Var(3) val reactiveNumberOfUsers: Signal[Int] = numberOfUsers.signal + val mapSelectionMode: Var[MapSelectionMode] = Var(MapSelectionMode.Default) + val reactiveGameMap: Var[GameMap] = Var(GameMapFactory.defaultMap) + + def changeMap: Unit = + mapSelectionMode.now() match + case Default => + reactiveGameMap.set(GameMapFactory.defaultMap) + case Random => + reactiveGameMap.set(GameMapFactory.randomMap) + case WithIterator => + reactiveGameMap.set(GameMapFactory.nextPermutation) + private def validateNames(usernames: String*) = usernames.forall(_.matches(".*\\S.*")) @@ -48,7 +68,7 @@ private class ScalaJsSetUpView(container: String, requirements: View.Requirement .value if validateNames(usernames*) then println(usernames) - this.controller.startGame(usernames*) + this.controller.startGame(reactiveGameMap.now(), usernames*) this.navigateTo(Pages.Game) override def switchToHome(): Unit = @@ -104,5 +124,29 @@ private class ScalaJsSetUpView(container: String, requirements: View.Requirement cls := "setup-menu-button", onClick --> (_ => this.switchToHome()), "Back" + ), + div( + cls := "setup-menu-map-picker", + div( + cls := "setup-menu-map-picker-left-tab", + select( + cls := "setup-menu-map-picker-combobox", + onChange.mapToValue.map(v => MapSelectionMode.fromOrdinal(v.toInt)) --> mapSelectionMode, + for (mode <- MapSelectionMode.values) + yield option( + value := s"${mode.ordinal}", + mode.toString + ) + ), + button( + cls := "setup-menu-map-picker-button", + "Change Map", + onClick --> (_ => changeMap) + ) + ), + div( + cls := "setup-menu-map", + child <-- reactiveGameMap.signal.map(gameMap => MapComponent.map(using gameMap)) + ) ) ) diff --git a/src/main/scala/scatan/views/game/components/map/MapComponent.scala b/src/main/scala/scatan/views/game/components/map/MapComponent.scala new file mode 100644 index 00000000..eacfc5f7 --- /dev/null +++ b/src/main/scala/scatan/views/game/components/map/MapComponent.scala @@ -0,0 +1,87 @@ +package scatan.views.game.components.map + +import scatan.model.GameMap +import com.raquo.laminar.api.L.* +import scatan.model.map.Hexagon +import scatan.views.utils.Coordinates.center +import scatan.views.utils.Coordinates +import scatan.views.game.components.ContextMap +import scatan.views.game.components.ContextMap.toImgId +import scatan.model.map.TileContent +import scatan.model.components.UnproductiveTerrain + +object MapComponent: + + private given hexSize: Int = 100 + private val radius = hexSize / 4 + private val svgCornersPoints: String = + (for + i <- 0 to 5 + angleDeg = 60 * i + 30 + angleRad = Math.PI / 180 * angleDeg + x = hexSize * math.cos(angleRad) + y = hexSize * math.sin(angleRad) + yield s"$x,$y").mkString(" ") + private val layersToCanvasSize: Int => Int = x => (2 * x * hexSize) + 50 + + def map: GameMap ?=> Element = + val gameMap = summon[GameMap] + val canvasSize = layersToCanvasSize(gameMap.totalLayers) + svg.svg( + svgImages, + svg.viewBox := s"-${canvasSize} -${canvasSize} ${2 * canvasSize} ${2 * canvasSize}", + for + hex <- gameMap.tiles.toList + content = gameMap.toContent(hex) + yield svgHexagon(hex, content) + ) + + private def svgHexagon(hex: Hexagon, content: TileContent): Element = + val Coordinates(x, y) = hex.center + svg.g( + svg.transform := s"translate($x, $y)", + svg.polygon( + svg.points := svgCornersPoints, + svg.cls := "hexagon", + svg.fill := s"url(#${content.terrain.toImgId})" + ), + content.terrain match + case UnproductiveTerrain.Sea => "" + case _ => circularNumber(hex, content) + ) + + def circularNumber(hex: Hexagon, content: TileContent): Element = + svg.g( + svg.circle( + svg.cx := "0", + svg.cy := "0", + svg.r := s"$radius", + svg.className := "hexagon-center-circle" + ), + svg.text( + svg.x := "0", + svg.y := "0", + svg.fontSize := s"$radius", + svg.className := "hexagon-center-number", + content.number.map(_.toString).getOrElse("") + ) + ) + + private val svgImages: Element = + svg.svg( + svg.defs( + for (terrain, path) <- ContextMap.resources.toList + yield svg.pattern( + svg.idAttr := terrain.toImgId, + svg.width := "100%", + svg.height := "100%", + svg.patternContentUnits := "objectBoundingBox", + svg.image( + svg.href := path, + svg.width := "1", + svg.height := "1", + svg.preserveAspectRatio := "none" + ) + ) + ) + ) diff --git a/style.css b/style.css index 52893c1b..0a828a26 100644 --- a/style.css +++ b/style.css @@ -173,6 +173,36 @@ body { margin-top: 2.5em; } +.setup-menu-map-picker { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + width: 100%; +} + +.setup-menu-map-picker-left-tab { + display: flex; + padding: 0 4em; + flex-direction: column; +} + +.setup-menu-map-picker-button { + font-size: 1.5em; + padding: 0.6em 0.8em; + margin-top: 3em; + border-radius: 1em; + background-color: var(--button-color); +} + +.setup-menu-map-picker-combobox { + font-size: 3em; +} + +.setup-menu-map { + width: 25%; +} + /* Game */ .game-view-left-tab { display: inline-flex; @@ -203,9 +233,11 @@ body { .game-view-phase { font-size: 1em; } + .game-view-step { font-size: 1em; } + .game-view-buttons { margin-top: 1em; display: flex; From 918301f020f5a95cf136d36cfcc024f951f4bfaf Mon Sep 17 00:00:00 2001 From: Manuel Andruccioli Date: Fri, 13 Oct 2023 10:47:28 +0200 Subject: [PATCH 15/16] fix: format --- src/main/scala/scatan/model/game/ScatanGame.scala | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/scala/scatan/model/game/ScatanGame.scala b/src/main/scala/scatan/model/game/ScatanGame.scala index b6459714..efbf7a5e 100644 --- a/src/main/scala/scatan/model/game/ScatanGame.scala +++ b/src/main/scala/scatan/model/game/ScatanGame.scala @@ -16,7 +16,6 @@ import scatan.model.GameMap import scatan.model.components.ResourceCard import scatan.model.game.ops.RobberOps.playersOnRobber - /** The status of a game of Scatan. It contains all the data without any possible action. * @param game * The internal game From fc35c34c7bceb7a30f5b3d0f59f078ed1f21f5fc Mon Sep 17 00:00:00 2001 From: luigi-borriello00 Date: Fri, 13 Oct 2023 10:52:46 +0200 Subject: [PATCH 16/16] chore(names): rename ResCardOps and DevCardOps in ResourceCardOps and DevelopmentCardOps --- src/main/scala/scatan/model/game/ScatanDSL.scala | 2 +- src/main/scala/scatan/model/game/ScatanEffects.scala | 4 ++-- .../game/ops/{DevCardOps.scala => DevelopmentCardOps.scala} | 2 +- .../game/ops/{ResCardOps.scala => ResourceCardOps.scala} | 2 +- src/main/scala/scatan/model/game/ops/TradeOps.scala | 2 +- src/test/scala/scatan/model/ScatanEffectsTest.scala | 2 +- src/test/scala/scatan/model/game/ops/AwardOpsTest.scala | 2 +- src/test/scala/scatan/model/game/ops/BuildingOpsTest.scala | 2 +- .../{DevCardOpsTest.scala => DevelopmentCardOpsTest.scala} | 6 +++--- .../ops/{ResCardOpsTest.scala => ResourceCardOpsTest.scala} | 4 ++-- src/test/scala/scatan/model/game/ops/ScoreOpsTest.scala | 2 +- src/test/scala/scatan/model/game/ops/TradeOpsTest.scala | 2 +- 12 files changed, 16 insertions(+), 16 deletions(-) rename src/main/scala/scatan/model/game/ops/{DevCardOps.scala => DevelopmentCardOps.scala} (99%) rename src/main/scala/scatan/model/game/ops/{ResCardOps.scala => ResourceCardOps.scala} (99%) rename src/test/scala/scatan/model/game/ops/{DevCardOpsTest.scala => DevelopmentCardOpsTest.scala} (95%) rename src/test/scala/scatan/model/game/ops/{ResCardOpsTest.scala => ResourceCardOpsTest.scala} (98%) diff --git a/src/main/scala/scatan/model/game/ScatanDSL.scala b/src/main/scala/scatan/model/game/ScatanDSL.scala index 0a754b39..2f7f7e8b 100644 --- a/src/main/scala/scatan/model/game/ScatanDSL.scala +++ b/src/main/scala/scatan/model/game/ScatanDSL.scala @@ -2,7 +2,7 @@ package scatan.model.game import scatan.lib.game.Rules import scatan.model.game.config.{ScatanActions, ScatanPhases, ScatanPlayer, ScatanSteps} -import scatan.model.game.ops.ResCardOps.assignResourcesAfterInitialPlacement +import scatan.model.game.ops.ResourceCardOps.assignResourcesAfterInitialPlacement import scatan.model.game.ops.ScoreOps.winner import scala.language.postfixOps diff --git a/src/main/scala/scatan/model/game/ScatanEffects.scala b/src/main/scala/scatan/model/game/ScatanEffects.scala index 4653c78b..9c9b9761 100644 --- a/src/main/scala/scatan/model/game/ScatanEffects.scala +++ b/src/main/scala/scatan/model/game/ScatanEffects.scala @@ -5,8 +5,8 @@ import scatan.model.components.{BuildingType, ResourceCard, ResourceType} import scatan.model.game.config.ScatanActions.* import scatan.model.game.config.ScatanPlayer import scatan.model.game.ops.BuildingOps.{assignBuilding, build} -import scatan.model.game.ops.DevCardOps.buyDevelopmentCard -import scatan.model.game.ops.ResCardOps.{assignResourcesFromNumber, stoleResourceCard} +import scatan.model.game.ops.DevelopmentCardOps.buyDevelopmentCard +import scatan.model.game.ops.ResourceCardOps.{assignResourcesFromNumber, stoleResourceCard} import scatan.model.game.ops.RobberOps.moveRobber import scatan.model.game.ops.TradeOps.{tradeWithBank, tradeWithPlayer} import scatan.model.map.{Hexagon, RoadSpot, StructureSpot} diff --git a/src/main/scala/scatan/model/game/ops/DevCardOps.scala b/src/main/scala/scatan/model/game/ops/DevelopmentCardOps.scala similarity index 99% rename from src/main/scala/scatan/model/game/ops/DevCardOps.scala rename to src/main/scala/scatan/model/game/ops/DevelopmentCardOps.scala index b1f56fb2..09bd7704 100644 --- a/src/main/scala/scatan/model/game/ops/DevCardOps.scala +++ b/src/main/scala/scatan/model/game/ops/DevelopmentCardOps.scala @@ -5,7 +5,7 @@ import scatan.model.game.ScatanState import scatan.model.game.config.ScatanPlayer import scatan.model.game.ops.AwardOps.awards -object DevCardOps: +object DevelopmentCardOps: extension (state: ScatanState) /** Returns a new ScatanState with the given development card assigned to the given player. The development card is diff --git a/src/main/scala/scatan/model/game/ops/ResCardOps.scala b/src/main/scala/scatan/model/game/ops/ResourceCardOps.scala similarity index 99% rename from src/main/scala/scatan/model/game/ops/ResCardOps.scala rename to src/main/scala/scatan/model/game/ops/ResourceCardOps.scala index 6c3a0dfe..668e58f5 100644 --- a/src/main/scala/scatan/model/game/ops/ResCardOps.scala +++ b/src/main/scala/scatan/model/game/ops/ResourceCardOps.scala @@ -7,7 +7,7 @@ import scatan.model.map.{Hexagon, RoadSpot, StructureSpot, TileContent} import scala.util.Random -object ResCardOps: +object ResourceCardOps: extension (state: ScatanState) /** Stole a card from a victim. diff --git a/src/main/scala/scatan/model/game/ops/TradeOps.scala b/src/main/scala/scatan/model/game/ops/TradeOps.scala index fb2cd0ca..d7b279fa 100644 --- a/src/main/scala/scatan/model/game/ops/TradeOps.scala +++ b/src/main/scala/scatan/model/game/ops/TradeOps.scala @@ -3,7 +3,7 @@ package scatan.model.game.ops import scatan.model.components.{ResourceCard, ResourceType} import scatan.model.game.ScatanState import scatan.model.game.config.ScatanPlayer -import scatan.model.game.ops.ResCardOps.{assignResourceCard, removeResourceCard} +import scatan.model.game.ops.ResourceCardOps.{assignResourceCard, removeResourceCard} import scatan.views.game.components.ContextMap.resources object TradeOps: diff --git a/src/test/scala/scatan/model/ScatanEffectsTest.scala b/src/test/scala/scatan/model/ScatanEffectsTest.scala index abb83821..53cf60ab 100644 --- a/src/test/scala/scatan/model/ScatanEffectsTest.scala +++ b/src/test/scala/scatan/model/ScatanEffectsTest.scala @@ -4,7 +4,7 @@ import scatan.BaseTest import scatan.model.components.{ResourceCard, ResourceType} import scatan.model.game.ScatanEffects.{NextTurnEffect, PlaceRobberEffect, RollEffect, TradeWithPlayerEffect} import scatan.model.game.config.ScatanPlayer -import scatan.model.game.ops.ResCardOps.assignResourceCard +import scatan.model.game.ops.ResourceCardOps.assignResourceCard import scatan.model.game.{ScatanGame, ScatanState} class ScatanEffectsTest extends BaseTest: diff --git a/src/test/scala/scatan/model/game/ops/AwardOpsTest.scala b/src/test/scala/scatan/model/game/ops/AwardOpsTest.scala index c6fa59d7..e89455e9 100644 --- a/src/test/scala/scatan/model/game/ops/AwardOpsTest.scala +++ b/src/test/scala/scatan/model/game/ops/AwardOpsTest.scala @@ -3,7 +3,7 @@ package scatan.model.game.ops import scatan.model.components.* import scatan.model.game.ops.AwardOps.* import scatan.model.game.ops.BuildingOps.assignBuilding -import scatan.model.game.ops.DevCardOps.assignDevelopmentCard +import scatan.model.game.ops.DevelopmentCardOps.assignDevelopmentCard import scatan.model.game.ops.EmptySpotOps.{emptyRoadSpot, emptyStructureSpot} import scatan.model.game.{BaseScatanStateTest, ScatanState} diff --git a/src/test/scala/scatan/model/game/ops/BuildingOpsTest.scala b/src/test/scala/scatan/model/game/ops/BuildingOpsTest.scala index 0838ba9f..8eb7c9b5 100644 --- a/src/test/scala/scatan/model/game/ops/BuildingOpsTest.scala +++ b/src/test/scala/scatan/model/game/ops/BuildingOpsTest.scala @@ -4,7 +4,7 @@ import scatan.model.components.* import scatan.model.game.config.ScatanPlayer import scatan.model.game.ops.BuildingOps.{assignBuilding, build} import scatan.model.game.ops.EmptySpotOps.{emptyRoadSpot, emptyStructureSpot} -import scatan.model.game.ops.ResCardOps.assignResourceCard +import scatan.model.game.ops.ResourceCardOps.assignResourceCard import scatan.model.game.{BaseScatanStateTest, ScatanState} import scatan.model.map.{RoadSpot, StructureSpot} diff --git a/src/test/scala/scatan/model/game/ops/DevCardOpsTest.scala b/src/test/scala/scatan/model/game/ops/DevelopmentCardOpsTest.scala similarity index 95% rename from src/test/scala/scatan/model/game/ops/DevCardOpsTest.scala rename to src/test/scala/scatan/model/game/ops/DevelopmentCardOpsTest.scala index a7fd9e46..6c863b64 100644 --- a/src/test/scala/scatan/model/game/ops/DevCardOpsTest.scala +++ b/src/test/scala/scatan/model/game/ops/DevelopmentCardOpsTest.scala @@ -2,11 +2,11 @@ package scatan.model.game.ops import scatan.lib.game.Game import scatan.model.components.{DevelopmentCard, DevelopmentType, ResourceCard, ResourceType} -import scatan.model.game.ops.DevCardOps.{assignDevelopmentCard, buyDevelopmentCard, consumeDevelopmentCard} -import scatan.model.game.ops.ResCardOps.assignResourceCard +import scatan.model.game.ops.DevelopmentCardOps.{assignDevelopmentCard, buyDevelopmentCard, consumeDevelopmentCard} +import scatan.model.game.ops.ResourceCardOps.assignResourceCard import scatan.model.game.{BaseScatanStateTest, ScatanState} -class DevCardOpsTest extends BaseScatanStateTest: +class DevelopmentCardOpsTest extends BaseScatanStateTest: "A State with development cards Ops" should "have empty development cards when game start" in { val state = ScatanState(threePlayers) diff --git a/src/test/scala/scatan/model/game/ops/ResCardOpsTest.scala b/src/test/scala/scatan/model/game/ops/ResourceCardOpsTest.scala similarity index 98% rename from src/test/scala/scatan/model/game/ops/ResCardOpsTest.scala rename to src/test/scala/scatan/model/game/ops/ResourceCardOpsTest.scala index 5898aa87..306dc120 100644 --- a/src/test/scala/scatan/model/game/ops/ResCardOpsTest.scala +++ b/src/test/scala/scatan/model/game/ops/ResourceCardOpsTest.scala @@ -3,13 +3,13 @@ package scatan.model.game.ops import scatan.model.components.{BuildingType, ResourceCard, ResourceCards, ResourceType} import scatan.model.game.ops.BuildingOps.assignBuilding import scatan.model.game.ops.EmptySpotOps.emptyStructureSpot -import scatan.model.game.ops.ResCardOps.* +import scatan.model.game.ops.ResourceCardOps.* import scatan.model.game.{BaseScatanStateTest, ScatanState} import scatan.model.map.HexagonInMap.layer import scatan.model.map.{RoadSpot, Spot, StructureSpot} import scatan.utils.UnorderedTriple -class ResCardOpsTest extends BaseScatanStateTest: +class ResourceCardOpsTest extends BaseScatanStateTest: extension (state: ScatanState) /** This method assigns resources to players based on the number of the hexagons where their buildings are located. diff --git a/src/test/scala/scatan/model/game/ops/ScoreOpsTest.scala b/src/test/scala/scatan/model/game/ops/ScoreOpsTest.scala index 36222ac9..09230e59 100644 --- a/src/test/scala/scatan/model/game/ops/ScoreOpsTest.scala +++ b/src/test/scala/scatan/model/game/ops/ScoreOpsTest.scala @@ -2,7 +2,7 @@ package scatan.model.game.ops import scatan.model.components.* import scatan.model.game.ops.BuildingOps.assignBuilding -import scatan.model.game.ops.DevCardOps.assignDevelopmentCard +import scatan.model.game.ops.DevelopmentCardOps.assignDevelopmentCard import scatan.model.game.ops.EmptySpotOps.{emptyRoadSpot, emptyStructureSpot} import scatan.model.game.ops.ScoreOps.* import scatan.model.game.{BaseScatanStateTest, ScatanState} diff --git a/src/test/scala/scatan/model/game/ops/TradeOpsTest.scala b/src/test/scala/scatan/model/game/ops/TradeOpsTest.scala index c0162c90..c4e0b013 100644 --- a/src/test/scala/scatan/model/game/ops/TradeOpsTest.scala +++ b/src/test/scala/scatan/model/game/ops/TradeOpsTest.scala @@ -1,7 +1,7 @@ package scatan.model.game.ops import scatan.model.components.* -import scatan.model.game.ops.ResCardOps.assignResourceCard +import scatan.model.game.ops.ResourceCardOps.assignResourceCard import scatan.model.game.ops.TradeOps.{tradeWithBank, tradeWithPlayer} import scatan.model.game.{BaseScatanStateTest, ScatanState}