Skip to content

Commit

Permalink
Play Year of Plenty
Browse files Browse the repository at this point in the history
  • Loading branch information
dagarcia7 committed Sep 27, 2020
1 parent daf4b0b commit 383eb7c
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 1 deletion.
22 changes: 22 additions & 0 deletions catanatron/game.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
city_possible_actions,
settlement_possible_actions,
robber_possibilities,
year_of_plenty_possible_actions,
)
from catanatron.models.player import Player
from catanatron.models.decks import ResourceDeck, DevelopmentDeck
Expand Down Expand Up @@ -179,6 +180,11 @@ def playable_actions(self, player):
for action in city_possible_actions(player, self.board):
actions.append(action)

# Can only do if the player has not already played a development card
if player.has_year_of_plenty_card():
for action in year_of_plenty_possible_actions(player, self.resource_deck):
actions.append(action)

if (
player.resource_deck.includes(ResourceDeck.development_card_cost())
and self.development_deck.num_cards() > 0
Expand Down Expand Up @@ -274,6 +280,22 @@ def execute(self, action, initial_build_phase=False):
self.resource_deck += ResourceDeck.development_card_cost()

action = Action(action.player, action.action_type, development_card)
elif action.action_type == ActionType.PLAY_YEAR_OF_PLENTY:
cards_selected = action.value # Assuming action.value is a resource deck
player_to_act = action.player
if (
not player_to_act.development_deck.count(DevelopmentCard.YEAR_OF_PLENTY)
> 0
):
raise ValueError("Player doesn't have year of plenty card")
if not self.resource_deck.includes(cards_selected):
raise ValueError(
"Not enough resources of this type (these types?) in bank"
)
player_to_act.resource_deck += cards_selected
player_to_act.development_deck.draw(1, DevelopmentCard.YEAR_OF_PLENTY)
self.resource_deck -= cards_selected

else:
raise RuntimeError("Unknown ActionType " + str(action.action_type))

Expand Down
24 changes: 24 additions & 0 deletions catanatron/models/actions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from catanatron.models.decks import ResourceDeck
from catanatron.models.board import BuildingType
from catanatron.models.enums import Resource


class ActionType(Enum):
Expand All @@ -29,6 +30,29 @@ class ActionType(Enum):
Action = namedtuple("Action", ["player", "action_type", "value"])


def year_of_plenty_possible_actions(player, resource_deck):
possible_combinations = set()
actions = []
for first_card in Resource:
for second_card in Resource:
if (
resource_deck.can_draw(1, first_card)
and resource_deck.can_draw(1, second_card)
and (second_card, first_card) not in possible_combinations
):
possible_combinations.add((first_card, second_card))
cards_selected = ResourceDeck()
cards_selected.replenish(1, first_card)
cards_selected.replenish(1, second_card)
actions.append(
Action(player, ActionType.PLAY_YEAR_OF_PLENTY, cards_selected)
)

# TODO: If none of the combinations are possible due to shortages
# in the deck, allow player to draw one card
return actions


def road_possible_actions(player, board):
has_money = player.resource_deck.includes(ResourceDeck.road_cost())

Expand Down
4 changes: 4 additions & 0 deletions catanatron/models/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from enum import Enum

from catanatron.models.decks import ResourceDeck, DevelopmentDeck
from catanatron.models.enums import DevelopmentCard


class Color(Enum):
Expand Down Expand Up @@ -38,6 +39,9 @@ def receive(self, resource_deck):
def has_knight_card(self):
return False

def has_year_of_plenty_card(self):
return self.development_deck.count(DevelopmentCard.YEAR_OF_PLENTY) > 0


class SimplePlayer(Player):
def decide(self, game, playable_actions):
Expand Down
14 changes: 14 additions & 0 deletions tests/models/test_actions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from catanatron.models.actions import (
year_of_plenty_possible_actions,
road_possible_actions,
settlement_possible_actions,
city_possible_actions,
Expand All @@ -22,6 +23,19 @@ def test_playable_actions():
assert actions[0].action_type == ActionType.ROLL


def test_year_of_plenty_possible_actions_full_resource_bank():
player = SimplePlayer(Color.RED)
bank_resource_deck = ResourceDeck.starting_bank()
assert len(year_of_plenty_possible_actions(player, bank_resource_deck)) == 15


def test_year_of_plenty_possible_actions_not_enough_cards():
player = SimplePlayer(Color.RED)
bank_resource_deck = ResourceDeck()
bank_resource_deck.replenish(2, Resource.ORE)
assert len(year_of_plenty_possible_actions(player, bank_resource_deck)) == 1


def test_road_possible_actions():
board = Board()
player = SimplePlayer(Color.RED)
Expand Down
55 changes: 54 additions & 1 deletion tests/test_game.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from catanatron.algorithms import longest_road, continuous_roads_by_player
from catanatron.models.board import Board
from catanatron.models.board_initializer import NodeRef, EdgeRef
from catanatron.models.enums import Resource
from catanatron.models.enums import Resource, DevelopmentCard
from catanatron.models.actions import ActionType, Action
from catanatron.models.player import Player, Color, SimplePlayer
from catanatron.models.decks import ResourceDeck
Expand Down Expand Up @@ -139,6 +139,59 @@ def test_cant_buy_more_than_max_card():
assert players[0].resource_deck.num_cards() == 3


def test_play_year_of_plenty_gives_player_resources():
players = [SimplePlayer(Color.RED), SimplePlayer(Color.BLUE)]
game = Game(players)
player_to_act = players[0]
player_to_act.development_deck.replenish(1, DevelopmentCard.YEAR_OF_PLENTY)
cards_to_add = ResourceDeck()
cards_to_add.replenish(1, Resource.ORE)
cards_to_add.replenish(1, Resource.WHEAT)
action_to_execute = Action(
player_to_act, ActionType.PLAY_YEAR_OF_PLENTY, cards_to_add
)

game.execute(action_to_execute)

for card_type in Resource:
if card_type == Resource.ORE or card_type == Resource.WHEAT:
assert player_to_act.resource_deck.count(card_type) == 1
assert game.resource_deck.count(card_type) == 18
else:
assert player_to_act.resource_deck.count(card_type) == 0
assert game.resource_deck.count(card_type) == 19
assert player_to_act.development_deck.count(DevelopmentCard.YEAR_OF_PLENTY) == 0


def test_play_year_of_plenty_not_enough_resources():
players = [SimplePlayer(Color.RED), SimplePlayer(Color.BLUE)]
player_to_act = players[0]
game = Game(players)
game.resource_deck = ResourceDeck()
player_to_act.development_deck.replenish(1, DevelopmentCard.YEAR_OF_PLENTY)

cards_to_add = ResourceDeck()
cards_to_add.replenish(1, Resource.ORE)
cards_to_add.replenish(1, Resource.WHEAT)
action_to_execute = Action(players[0], ActionType.PLAY_YEAR_OF_PLENTY, cards_to_add)

with pytest.raises(ValueError): # not enough cards in bank
game.execute(action_to_execute)


def test_play_year_of_plenty_no_year_of_plenty_card():
players = [SimplePlayer(Color.RED), SimplePlayer(Color.BLUE)]
game = Game(players)

cards_to_add = ResourceDeck()
cards_to_add.replenish(1, Resource.ORE)
cards_to_add.replenish(1, Resource.WHEAT)
action_to_execute = Action(players[0], ActionType.PLAY_YEAR_OF_PLENTY, cards_to_add)

with pytest.raises(ValueError): # no year of plenty card
game.execute(action_to_execute)


# ===== Yield Resources
def test_yield_resources():
board = Board()
Expand Down

0 comments on commit 383eb7c

Please sign in to comment.