Skip to content

Commit

Permalink
wip(building-ops): inject dependency for building rule in ops
Browse files Browse the repository at this point in the history
  • Loading branch information
manuandru committed Oct 9, 2023
1 parent 3111efe commit bc7b988
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 16 deletions.
42 changes: 33 additions & 9 deletions src/main/scala/scatan/model/game/ops/BuildingOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,15 @@ object BuildingOps:
* @return
* Some(ScatanState) if the building is assigned, None otherwise
*/
def assignBuilding(spot: Spot, buildingType: BuildingType, player: ScatanPlayer): Option[ScatanState] =
buildingType match
case BuildingType.City =>
state.assignedBuildings(spot) match
def assignBuilding(
spot: Spot,
buildingType: BuildingType,
player: ScatanPlayer,
roadBuildingRules: ScatanState => (RoadSpot, ScatanPlayer) => Boolean = defaultCheckBuildRoadCondition
): Option[ScatanState] =
spot match
case citySpot: StructureSpot if buildingType == BuildingType.City =>
state.assignedBuildings(citySpot) match
case AssignmentInfo(`player`, BuildingType.Settlement) =>
Some(
state.copy(
Expand All @@ -73,21 +78,40 @@ object BuildingOps:
)
)
case _ => None
case BuildingType.Settlement =>
if state.emptyStructureSpot.contains(spot) then
case settlementSpot: StructureSpot if buildingType == BuildingType.Settlement =>
if state.emptyStructureSpot.contains(spot)
// && state.gameMap.edgesOf(settlementSpot).flatMap(state.assignedBuildings.get).exists()
then
Some(
state.copy(
assignedBuildings = state.assignedBuildings.updated(spot, AssignmentInfo(player, buildingType)),
assignedAwards = state.awards
)
)
else None
case BuildingType.Road =>
if state.emptyRoadSpot.contains(spot) then
case roadSpot: RoadSpot =>
if roadBuildingRules(state)(roadSpot, player)
then
Some(
state.copy(
assignedBuildings = state.assignedBuildings.updated(spot, AssignmentInfo(player, buildingType)),
assignedBuildings = state.assignedBuildings.updated(roadSpot, AssignmentInfo(player, buildingType)),
assignedAwards = state.awards
)
)
else None
case _ => None

private def defaultCheckBuildRoadCondition(spot: RoadSpot, player: ScatanPlayer): Boolean =
val structureSpot1 = spot._1
val structureSpot2 = spot._2
state.emptyRoadSpot.contains(spot)
&& (
state.assignedBuildings
.filter(s => s._1 == structureSpot1 || s._1 == structureSpot2)
.map(_._2)
.exists(p => p.player == player)
|| state.gameMap
.edgesOfNodesConnectedBy(spot)
.flatMap(state.assignedBuildings.get)
.exists(_.player == player)
)
57 changes: 50 additions & 7 deletions src/test/scala/scatan/model/game/ops/BuildingOpsTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import scatan.model.game.BaseScatanStateTest
import scatan.model.game.ScatanState
import scatan.model.map.StructureSpot
import scatan.model.map.RoadSpot
import scatan.model.game.config.ScatanPlayer

class BuildingOpsTest extends BaseScatanStateTest:

Expand All @@ -17,15 +18,23 @@ class BuildingOpsTest extends BaseScatanStateTest:
private def spotToBuildRoad(state: ScatanState): RoadSpot =
state.emptyRoadSpot.head

private def roadNearSpot(state: ScatanState, spot: StructureSpot): RoadSpot =
state.emptyRoadSpot.filter(_.contains(spot)).head

private def noConstrainToBuildRoad: ScatanState => ((RoadSpot, ScatanPlayer) => Boolean) = _ => (_, _) => true
private def spotShouldBeEmptyToBuildRoad: ScatanState => ((RoadSpot, ScatanPlayer) => Boolean) = s =>
(r, _) => s.emptyRoadSpot.contains(r)

"A State with buildings Ops" should "have empty buildings when state start" in {
val state = ScatanState(threePlayers)
state.assignedBuildings.keySet should have size 0
}

it should "permit to assign a road" in {
val state = ScatanState(threePlayers)
given ScatanState = state
state
.assignBuilding(spotToBuildRoad(state), BuildingType.Road, threePlayers.head) match
.assignBuilding(spotToBuildRoad(state), BuildingType.Road, threePlayers.head, noConstrainToBuildRoad) match
case Some(state) => state.assignedBuildings should have size 1
case None => fail("state should be defined")
}
Expand Down Expand Up @@ -61,16 +70,19 @@ class BuildingOpsTest extends BaseScatanStateTest:
it should "not permit to assign a road if the spot is not empty" in {
val state = ScatanState(threePlayers)
val spot = spotToBuildRoad(state)
val stateWithBuilding = for
stateWithWood <- state.assignResourceCard(threePlayers.head, ResourceCard(ResourceType.Wood))
stateWithBrick <- stateWithWood.assignResourceCard(threePlayers.head, ResourceCard(ResourceType.Brick))
stateWithRoad <- stateWithBrick.build(spot, BuildingType.Road, threePlayers.head)
yield stateWithRoad
val stateWithBuilding =
for stateWithRoad <- state.assignBuilding(
spot,
BuildingType.Road,
threePlayers.head,
spotShouldBeEmptyToBuildRoad
)
yield stateWithRoad
stateWithBuilding match
case Some(state) =>
state.assignedBuildings(spot) should be(AssignmentInfo(threePlayers.head, BuildingType.Road))
state
.assignBuilding(spot, BuildingType.Road, threePlayers.head) match
.assignBuilding(spot, BuildingType.Road, threePlayers.head, spotShouldBeEmptyToBuildRoad) match
case Some(_) => fail("state should not be defined")
case None => succeed

Expand Down Expand Up @@ -146,3 +158,34 @@ class BuildingOpsTest extends BaseScatanStateTest:
.assignBuilding(spot, BuildingType.Settlement, player1)
.flatMap(_.assignBuilding(spot, BuildingType.City, player2)) should be(None)
}

it should "not allow to assign a road without nothing near" in {
val state = ScatanState(threePlayers)
val roadSpot = spotToBuildRoad(state)
val stateWithRoad =
state
.assignBuilding(roadSpot, BuildingType.Road, threePlayers.head)
stateWithRoad should be(None)
}

it should "allow to assign a road if it is near a building" in {
val state = ScatanState(threePlayers)
val spot = spotToBuildStructure(state)
val roadSpot = roadNearSpot(state, spot)
val stateAssigned =
state
.assignBuilding(spot, BuildingType.Settlement, threePlayers.head)
.flatMap(_.assignBuilding(roadSpot, BuildingType.Road, threePlayers.head))
stateAssigned should not be (None)
}

it should "allow to assign a road if it has road near" in {
val state = ScatanState(threePlayers)
val roadSpot = spotToBuildRoad(state)
val roadSpot2 = state.gameMap.edgesOfNodesConnectedBy(roadSpot).head
val stateAssigned =
state
.assignBuilding(roadSpot, BuildingType.Road, threePlayers.head, noConstrainToBuildRoad)
.flatMap(_.assignBuilding(roadSpot2, BuildingType.Road, threePlayers.head))
stateAssigned should not be (None)
}

0 comments on commit bc7b988

Please sign in to comment.