first
This commit is contained in:
757
monopoly.py
Normal file
757
monopoly.py
Normal file
@@ -0,0 +1,757 @@
|
||||
"""
|
||||
Purpose:
|
||||
|
||||
1) To simulate games of Monopoly in order to determine the best strategy
|
||||
2) To play Monopoly on a computer
|
||||
|
||||
|
||||
Along those lines, here's some prior art:
|
||||
|
||||
http://www.tkcs-collins.com/truman/monopoly/monopoly.shtml
|
||||
|
||||
|
||||
# TODO: until_space_type -- evaluate this as a string
|
||||
"""
|
||||
from abc import abstractmethod, ABC
|
||||
from itertools import cycle
|
||||
from pprint import pprint
|
||||
from random import shuffle, choice
|
||||
from typing import Type, NewType, Tuple, cast
|
||||
|
||||
from exceptions import TooManyPlayers, NotEnough, DidntFind, Argument
|
||||
|
||||
Doubles = NewType("Doubles", bool)
|
||||
|
||||
LANGUAGE = "français"
|
||||
BACKUP_LANGUAGE = "English"
|
||||
|
||||
|
||||
class Space:
|
||||
pass
|
||||
|
||||
|
||||
class NothingHappensWhenYouLandOnItSpace(Space):
|
||||
@classmethod
|
||||
def action(self, player: "Player"):
|
||||
pass
|
||||
|
||||
|
||||
class Go(NothingHappensWhenYouLandOnItSpace):
|
||||
pass
|
||||
|
||||
|
||||
class Jail(NothingHappensWhenYouLandOnItSpace):
|
||||
pass
|
||||
|
||||
|
||||
class FreeParking(NothingHappensWhenYouLandOnItSpace):
|
||||
pass
|
||||
|
||||
|
||||
class TaxSpace(Space):
|
||||
amount = None
|
||||
|
||||
@classmethod
|
||||
def action(cls, player):
|
||||
player.pay("Bank", cls.amount)
|
||||
|
||||
|
||||
class LuxuryTax(TaxSpace):
|
||||
_name = {"français": "Impôt Supplémentaire", "deutsch": "Nachsteuer"}
|
||||
amount = 75
|
||||
|
||||
|
||||
class IncomeTax(TaxSpace):
|
||||
# TODO: _name
|
||||
amount = 100
|
||||
|
||||
|
||||
class GoToJail(Space):
|
||||
@classmethod
|
||||
def action(cls, player):
|
||||
player.go_to_jail()
|
||||
|
||||
|
||||
class CardSpace(Space):
|
||||
deck = None
|
||||
|
||||
@classmethod
|
||||
def action(cls, player):
|
||||
deck = eval(cls.deck)
|
||||
card = deck.get_card()
|
||||
return card.action(player)
|
||||
|
||||
|
||||
class CommunityChest(CardSpace):
|
||||
deck = "CommunityChestDeck"
|
||||
_name = {"français": "Chancellerie", "deutsch": "Kanzlei"}
|
||||
|
||||
|
||||
class Chance(CardSpace):
|
||||
deck = "ChanceDeck"
|
||||
_name = {"français": "Chance", "deutsch": "Chance", "English": "Chance"}
|
||||
|
||||
|
||||
class Card(ABC):
|
||||
mandatory_action = False
|
||||
cost = None
|
||||
keep = False
|
||||
|
||||
@abstractmethod
|
||||
def action(self, player: "Player"):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class ElectedPresidentCard(Card):
|
||||
mandatory_action = True
|
||||
text = {
|
||||
"français": "Vous avez été elu president du conseil d'administration. Versez M50 à chaque joueur."
|
||||
}
|
||||
|
||||
def action(self, player):
|
||||
for other_player in Game.game.active_players:
|
||||
if other_player != player:
|
||||
player.pay(other_player, 50)
|
||||
|
||||
|
||||
class GetOutOfJailFreeCard(Card):
|
||||
text = {
|
||||
"français": "Vous êtes libéré de prison. Cette carte peut être conservée jusqu'à ce "
|
||||
"qu'elle soit utilisée ou vendue. "
|
||||
}
|
||||
|
||||
def action(self, player: "Player"):
|
||||
player.get_out_of_jail_free_card = True
|
||||
|
||||
|
||||
class AdvanceCard(Card):
|
||||
mandatory_action = True
|
||||
kwarg = {}
|
||||
|
||||
def action(self, player):
|
||||
player.advance(**self.kwarg)
|
||||
|
||||
|
||||
class GoToJailCard(AdvanceCard):
|
||||
text = {
|
||||
"français": "Allez en prison. Avancez tout droit en prison. Ne passez pas par la case "
|
||||
"départ. Ne recevez pas M200. "
|
||||
}
|
||||
kwarg = {"until_space_type": "Jail", "pass_go": False}
|
||||
|
||||
|
||||
class AdvanceThreeSpacesCard(AdvanceCard):
|
||||
mandatory_action = True
|
||||
text = {"français": "Reculez de trois cases."}
|
||||
kwarg = {"num_spaces": 3}
|
||||
|
||||
|
||||
class GoToClosestRailroadCard(AdvanceCard):
|
||||
text = {"français": "Avancez jusqu'à le chemin de fer le plus proche."}
|
||||
kwarg = {"until_space_type": "Railroad"}
|
||||
|
||||
|
||||
class GoToBernPlaceFederaleCard(AdvanceCard):
|
||||
mandatory_action = True
|
||||
text = {
|
||||
"français": "Avancez jusqu'a Bern Place Federale. Si vous passez par la case départ, "
|
||||
"vous touchez la prime habituelle de M200. "
|
||||
}
|
||||
|
||||
kwarg = {"space_index": "Berne Place Fédérale"}
|
||||
|
||||
|
||||
class BuildingAndLoanMaturesCard(Card):
|
||||
mandatory_action = True
|
||||
text = {
|
||||
"français": "Votre immeuble et votre pret rapportent. Vous devez toucher M150.",
|
||||
"English": "Your building and loan matures. Collect M150.",
|
||||
}
|
||||
|
||||
def action(self, player):
|
||||
Bank.pay(player, 150)
|
||||
|
||||
|
||||
class SpeedingCard(Card):
|
||||
mandatory_action = True
|
||||
text = {"français": "Amende pour excès de vitesse. Payez M15."}
|
||||
|
||||
def action(self, player):
|
||||
player.pay(Bank, 15)
|
||||
|
||||
|
||||
class Deck:
|
||||
deck = None
|
||||
|
||||
@classmethod
|
||||
def shuffle(cls):
|
||||
shuffle(cls.deck)
|
||||
|
||||
@classmethod
|
||||
def get_card(cls):
|
||||
card = cls.deck.pop()
|
||||
if not card.keep:
|
||||
cls.deck.insert(0, card)
|
||||
return card
|
||||
|
||||
|
||||
class ChanceDeck(Deck):
|
||||
deck = [
|
||||
AdvanceThreeSpacesCard,
|
||||
ElectedPresidentCard,
|
||||
BuildingAndLoanMaturesCard,
|
||||
GoToBernPlaceFederaleCard,
|
||||
GoToJailCard,
|
||||
SpeedingCard,
|
||||
]
|
||||
|
||||
|
||||
class CommunityChestDeck(Deck):
|
||||
deck = []
|
||||
|
||||
|
||||
def shuffle_decks():
|
||||
for deck in (ChanceDeck, CommunityChestDeck):
|
||||
deck.shuffle()
|
||||
|
||||
|
||||
class Decision:
|
||||
pass
|
||||
|
||||
|
||||
class BuyDecision(Decision):
|
||||
def __init__(self, property: Type["Property"], player: "Player"):
|
||||
pass
|
||||
|
||||
|
||||
class Property(Space):
|
||||
mortgaged = False
|
||||
|
||||
def __init__(self, _name):
|
||||
self._name = _name
|
||||
|
||||
|
||||
class Utility(Property):
|
||||
cost = 200
|
||||
rent = {1: lambda dice_total: dice_total * 4, 2: lambda dice_total: dice_total * 10}
|
||||
mortgage_cost = 75
|
||||
unmortgage_cost = 83
|
||||
|
||||
|
||||
class Railroad(Property):
|
||||
cost = 200
|
||||
rent = ({1: 25, 2: 50, 3: 100, 4: 200},)
|
||||
mortgage_cost = 100
|
||||
unmortgage_cost = 110
|
||||
|
||||
|
||||
class BuildableProperty(Property):
|
||||
owner = None
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
_name,
|
||||
cost,
|
||||
rent,
|
||||
color,
|
||||
house_and_hotel_cost,
|
||||
mortgage_cost,
|
||||
unmortgage_cost,
|
||||
):
|
||||
super().__init__(_name)
|
||||
self.cost = cost
|
||||
self.rent = rent
|
||||
self.house_and_hotel_cost = house_and_hotel_cost
|
||||
self.color = color
|
||||
self.mortgage_cost = mortgage_cost
|
||||
self.unmortgage_cost = unmortgage_cost
|
||||
|
||||
def action(self, player: "Player"):
|
||||
# TODO: implement on Property, then extend here
|
||||
if self.owner:
|
||||
if self.mortgaged:
|
||||
return
|
||||
player.pay(self.owner, self.calculate_rent())
|
||||
return BuyDecision(self, player)
|
||||
|
||||
def mortgage(self, player: "Player"):
|
||||
Bank.pay(player, self.mortgage_cost)
|
||||
self.mortgaged = True
|
||||
|
||||
def un_mortgage(self, player: "Player"):
|
||||
player.pay(Bank, self.unmortgage_cost)
|
||||
self.mortgaged = False
|
||||
|
||||
def calculate_rent(self):
|
||||
raise NotImplementedError
|
||||
# if not self.owner:
|
||||
# raise NoOwner
|
||||
# if self.buildings:
|
||||
# key = self.buildings
|
||||
# else:
|
||||
# if self.owner.owns_all_type(self.)
|
||||
|
||||
|
||||
class Board:
|
||||
|
||||
spaces = [
|
||||
Go,
|
||||
BuildableProperty(
|
||||
_name={"français": "Coire Kornplatz"},
|
||||
cost=60,
|
||||
color="brown",
|
||||
rent={0: 2, "monopoly": 4, 1: 10, 2: 30, 3: 90, 4: 160, "hotel": 250},
|
||||
house_and_hotel_cost=50,
|
||||
# TODO
|
||||
mortgage_cost=30,
|
||||
unmortgage_cost=33,
|
||||
),
|
||||
CommunityChest,
|
||||
BuildableProperty(
|
||||
_name={"français": "Schaffhouse Vordergasse"},
|
||||
cost=60,
|
||||
color="brown",
|
||||
rent={0: 4, "monopoly": 8, 1: 20, 2: 60, 3: 180, 4: 320, "hotel": 450},
|
||||
house_and_hotel_cost=50,
|
||||
mortgage_cost=30,
|
||||
unmortgage_cost=33,
|
||||
),
|
||||
IncomeTax,
|
||||
Railroad(_name={"français": "Union des Chemins de Fer Privés"}),
|
||||
BuildableProperty(
|
||||
_name={"deutsche": "Aarau Rathausplatz"},
|
||||
cost=100,
|
||||
color="light blue",
|
||||
rent={0: 6, "monopoly": 12, 1: 30, 2: 90, 3: 270, 4: 400, "hotel": 550},
|
||||
house_and_hotel_cost=50,
|
||||
mortgage_cost=50,
|
||||
unmortgage_cost=55,
|
||||
),
|
||||
Chance,
|
||||
BuildableProperty(
|
||||
_name={"français": "Neuchâtel Place Pury"},
|
||||
cost=100,
|
||||
color="light blue",
|
||||
rent={0: 6, "monopoly": 12, 1: 30, 2: 90, 3: 270, 4: 400, "hotel": 550},
|
||||
house_and_hotel_cost=50,
|
||||
mortgage_cost=50,
|
||||
unmortgage_cost=55,
|
||||
),
|
||||
BuildableProperty(
|
||||
_name={"français": "Thoune Hauptgasse"},
|
||||
cost=120,
|
||||
color="light blue",
|
||||
rent={0: 8, "monopoly": 16, 1: 30, 2: 100, 3: 300, 4: 400, "hotel": 600},
|
||||
house_and_hotel_cost=50,
|
||||
mortgage_cost=60,
|
||||
unmortgage_cost=66,
|
||||
),
|
||||
Jail,
|
||||
BuildableProperty(
|
||||
_name={"français": "Bâle Steinen-Vorstadt"},
|
||||
cost=140,
|
||||
color="pink",
|
||||
rent={0: 10, "monopoly": 20, 1: 50, 2: 150, 3: 450, 4: 625, "hotel": 750},
|
||||
house_and_hotel_cost=100,
|
||||
mortgage_cost=70,
|
||||
unmortgage_cost=77,
|
||||
),
|
||||
Utility(_name="Usines Électriques"),
|
||||
BuildableProperty(
|
||||
_name={"français": "Soleure Hauptgasse"},
|
||||
cost=140,
|
||||
color="pink",
|
||||
rent={0: 10, "monopoly": 20, 1: 50, 2: 150, 3: 450, 4: 625, "hotel": 750},
|
||||
house_and_hotel_cost=100,
|
||||
mortgage_cost=70,
|
||||
unmortgage_cost=77,
|
||||
),
|
||||
BuildableProperty(
|
||||
_name={"italian": "Lugano Via Nassa"},
|
||||
cost=160,
|
||||
color="pink",
|
||||
rent={0: 12, "monopoly": 24, 1: 60, 2: 180, 3: 500, 4: 700, "hotel": 900},
|
||||
house_and_hotel_cost=100,
|
||||
mortgage_cost=80,
|
||||
unmortgage_cost=88,
|
||||
),
|
||||
BuildableProperty(
|
||||
_name={"français": "Bienne Rue De Nidau"},
|
||||
cost=180,
|
||||
color="orange",
|
||||
rent={0: 14, "monopoly": 28, 1: 70, 2: 200, 3: 550, 4: 750, "hotel": 950},
|
||||
house_and_hotel_cost=100,
|
||||
mortgage_cost=90,
|
||||
unmortgage_cost=99,
|
||||
),
|
||||
CommunityChest,
|
||||
BuildableProperty(
|
||||
_name={"français": "Fribourg Avenue de la Gare"},
|
||||
cost=180,
|
||||
color="orange",
|
||||
rent={0: 14, "monopoly": 28, 1: 70, 2: 200, 3: 550, 4: 750, "hotel": 950},
|
||||
house_and_hotel_cost=100,
|
||||
mortgage_cost=90,
|
||||
unmortgage_cost=99,
|
||||
),
|
||||
BuildableProperty(
|
||||
_name={"français": "La Chaux-de-Fonds Avenue Louis-Robert"},
|
||||
cost=200,
|
||||
color="orange",
|
||||
rent={0: 16, "monopoly": 32, 1: 80, 2: 220, 3: 600, 4: 800, "hotel": 1_000},
|
||||
house_and_hotel_cost=100,
|
||||
mortgage_cost=100,
|
||||
unmortgage_cost=110,
|
||||
),
|
||||
FreeParking,
|
||||
BuildableProperty(
|
||||
_name={"français": "Winterthour Bahnhofplatz"},
|
||||
cost=220,
|
||||
color="red",
|
||||
rent={0: 18, "monopoly": 39, 1: 90, 2: 250, 3: 700, 4: 875, "hotel": 1_050},
|
||||
house_and_hotel_cost=150,
|
||||
mortgage_cost=110,
|
||||
unmortgage_cost=121,
|
||||
),
|
||||
Chance,
|
||||
BuildableProperty(
|
||||
_name={"français": "St-Gall Markplatz"},
|
||||
cost=220,
|
||||
color="red",
|
||||
rent={0: 18, "monopoly": 39, 1: 90, 2: 250, 3: 700, 4: 875, "hotel": 1_050},
|
||||
house_and_hotel_cost=150,
|
||||
mortgage_cost=110,
|
||||
unmortgage_cost=121,
|
||||
),
|
||||
BuildableProperty(
|
||||
_name={"français": "Berne Place Fédérale"},
|
||||
cost=240,
|
||||
color="red",
|
||||
rent={
|
||||
0: 20,
|
||||
"monopoly": 40,
|
||||
1: 100,
|
||||
2: 300,
|
||||
3: 750,
|
||||
4: 925,
|
||||
"hotel": 1_100,
|
||||
},
|
||||
house_and_hotel_cost=150,
|
||||
mortgage_cost=120,
|
||||
unmortgage_cost=132,
|
||||
),
|
||||
Railroad(_name="Tramways Interurbains"),
|
||||
BuildableProperty(
|
||||
_name={"français": "Lucerne Weggisgasse"},
|
||||
cost=260,
|
||||
color="yellow",
|
||||
rent={
|
||||
0: 22,
|
||||
"monopoly": 34,
|
||||
1: 110,
|
||||
2: 330,
|
||||
3: 800,
|
||||
4: 975,
|
||||
"hotel": 1_150,
|
||||
},
|
||||
house_and_hotel_cost=150,
|
||||
mortgage_cost=130,
|
||||
unmortgage_cost=143,
|
||||
),
|
||||
BuildableProperty(
|
||||
_name={"français": "Zurich Rennweg"},
|
||||
cost=260,
|
||||
color="yellow",
|
||||
rent={
|
||||
0: 22,
|
||||
"monopoly": 34,
|
||||
1: 110,
|
||||
2: 330,
|
||||
3: 800,
|
||||
4: 975,
|
||||
"hotel": 1_150,
|
||||
},
|
||||
house_and_hotel_cost=150,
|
||||
mortgage_cost=130,
|
||||
unmortgage_cost=143,
|
||||
),
|
||||
Utility(_name="Usines Hydrauliques"),
|
||||
BuildableProperty(
|
||||
_name={"français": "Lausanne Rue de Bourg"},
|
||||
cost=280,
|
||||
color="yellow",
|
||||
rent={
|
||||
0: 24,
|
||||
"monopoly": 48,
|
||||
1: 120,
|
||||
2: 360,
|
||||
3: 850,
|
||||
4: 1_025,
|
||||
"hotel": 1_200,
|
||||
},
|
||||
house_and_hotel_cost=150,
|
||||
mortgage_cost=140,
|
||||
unmortgage_cost=154,
|
||||
),
|
||||
GoToJail,
|
||||
BuildableProperty(
|
||||
_name={"français": "Bâle Freie Strasse"},
|
||||
cost=300,
|
||||
color="green",
|
||||
rent={
|
||||
0: 26,
|
||||
"monopoly": 52,
|
||||
1: 130,
|
||||
2: 390,
|
||||
3: 900,
|
||||
4: 1_100,
|
||||
"hotel": 1_275,
|
||||
},
|
||||
house_and_hotel_cost=200,
|
||||
mortgage_cost=150,
|
||||
unmortgage_cost=165,
|
||||
),
|
||||
BuildableProperty(
|
||||
_name={"français": "Genève Rue de la Croix-D'Or"},
|
||||
cost=300,
|
||||
color="green",
|
||||
rent={
|
||||
0: 26,
|
||||
"monopoly": 52,
|
||||
1: 130,
|
||||
2: 390,
|
||||
3: 900,
|
||||
4: 1_100,
|
||||
"hotel": 1_275,
|
||||
},
|
||||
house_and_hotel_cost=200,
|
||||
mortgage_cost=150,
|
||||
unmortgage_cost=165,
|
||||
),
|
||||
CommunityChest,
|
||||
BuildableProperty(
|
||||
_name={"français": "Berne Spitalgasse"},
|
||||
cost=320,
|
||||
color="green",
|
||||
rent={
|
||||
0: 28,
|
||||
"monopoly": 56,
|
||||
1: 150,
|
||||
2: 450,
|
||||
3: 1_000,
|
||||
4: 1_200,
|
||||
"hotel": 1_400,
|
||||
},
|
||||
house_and_hotel_cost=200,
|
||||
mortgage_cost=160,
|
||||
unmortgage_cost=176,
|
||||
),
|
||||
Railroad(_name="Association des Télépheriques"),
|
||||
Chance,
|
||||
BuildableProperty(
|
||||
_name={"français": "Lausanne Place St. François"},
|
||||
cost=350,
|
||||
color="dark blue",
|
||||
rent={
|
||||
0: 35,
|
||||
"monopoly": 70,
|
||||
1: 175,
|
||||
2: 500,
|
||||
3: 1_100,
|
||||
4: 1_300,
|
||||
"hotel": 1_500,
|
||||
},
|
||||
house_and_hotel_cost=200,
|
||||
mortgage_cost=175,
|
||||
unmortgage_cost=193,
|
||||
),
|
||||
LuxuryTax,
|
||||
BuildableProperty(
|
||||
_name={"français": "Zurich Paradeplatz"},
|
||||
cost=400,
|
||||
color="dark blue",
|
||||
rent={
|
||||
0: 50,
|
||||
"monopoly": 100,
|
||||
1: 200,
|
||||
2: 600,
|
||||
3: 1_400,
|
||||
4: 1_700,
|
||||
"hotel": 2_000,
|
||||
},
|
||||
house_and_hotel_cost=200,
|
||||
mortgage_cost=200,
|
||||
unmortgage_cost=220,
|
||||
),
|
||||
]
|
||||
SPACES_DICT = {}
|
||||
for index, space in enumerate(spaces):
|
||||
if hasattr(space, "_name"):
|
||||
space_name = space._name
|
||||
else:
|
||||
space_name = space.__name__
|
||||
|
||||
if isinstance(space_name, dict):
|
||||
space_name = space._name.get(LANGUAGE) or space._name.get(BACKUP_LANGUAGE)
|
||||
SPACES_DICT[space_name] = index
|
||||
|
||||
# SPACES_DICT = {space.name: space for space in spaces}
|
||||
NUM_SPACES = len(spaces)
|
||||
|
||||
|
||||
def get_space_index(name):
|
||||
return Board.SPACES_DICT[name]
|
||||
|
||||
|
||||
class EconomicActor:
|
||||
money = 0
|
||||
|
||||
@classmethod
|
||||
def pay(cls, actor: Type["EconomicActor"], amount: int):
|
||||
if amount > cls.money:
|
||||
print(cls)
|
||||
print("actor:", actor)
|
||||
print("cls.money:", cls.money)
|
||||
raise NotEnough
|
||||
if isinstance(actor, str):
|
||||
actor = eval(actor)
|
||||
cls.money -= amount
|
||||
actor.money += amount
|
||||
|
||||
|
||||
class Bank(EconomicActor):
|
||||
money = 20_580
|
||||
NUM_HOUSES = 32
|
||||
NUM_HOTELS = 12
|
||||
|
||||
@classmethod
|
||||
def get_building(cls, type_, quantity):
|
||||
if type_ not in ("house", "hotel"):
|
||||
raise Argument
|
||||
to_check = cls.NUM_HOUSES if type_ == "house" else cls.NUM_HOTELS
|
||||
if to_check < quantity:
|
||||
raise (f"Not enough {type_}s!")
|
||||
else:
|
||||
to_check -= quantity
|
||||
|
||||
|
||||
def get_index_of_next_space_of_type(current_space_index, until_space_type):
|
||||
space_indices_to_traverse = list(
|
||||
range(current_space_index + 1, Board.NUM_SPACES)
|
||||
) + list(range(current_space_index))
|
||||
for index in space_indices_to_traverse:
|
||||
if isinstance(Board.spaces[index], until_space_type):
|
||||
return index
|
||||
else:
|
||||
# for debugging TODO: delete
|
||||
print(type(Board.spaces[index]))
|
||||
else:
|
||||
# for debugging TODO: delete
|
||||
raise DidntFind
|
||||
|
||||
|
||||
def check_args(num_spaces, space_index, until_space_type):
|
||||
num_args = sum(
|
||||
1 for kwarg in (num_spaces, space_index, until_space_type) if kwarg is not None
|
||||
)
|
||||
if num_args > 1 or num_args == 0:
|
||||
raise Argument("provide either num_spaces or space_index or until_space_type")
|
||||
|
||||
|
||||
class GetOutOfJailDecision(Decision):
|
||||
def __init__(self, player: "Player"):
|
||||
pass
|
||||
|
||||
|
||||
class Player(EconomicActor):
|
||||
in_jail = False
|
||||
bankrupt = False
|
||||
get_out_of_jail_free_card = False
|
||||
go_again = False
|
||||
current_space_index = get_space_index("Go")
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
Bank.pay(self, 1_500)
|
||||
|
||||
def take_a_turn(self):
|
||||
if self.in_jail:
|
||||
return GetOutOfJailDecision(self)
|
||||
num_spaces, doubles = self.roll_the_dice()
|
||||
self.go_again = doubles
|
||||
self.advance(num_spaces)
|
||||
|
||||
@staticmethod
|
||||
def roll_the_dice() -> Tuple[int, Doubles]:
|
||||
die_one, die_two = choice(range(1, 7)), choice(range(1, 7))
|
||||
total = die_one + die_two
|
||||
if die_one == die_two:
|
||||
return total, cast(Doubles, True)
|
||||
return total, cast(Doubles, False)
|
||||
|
||||
def advance(
|
||||
self, num_spaces=None, space_index=None, until_space_type=None, pass_go=True
|
||||
):
|
||||
new_space_index = None
|
||||
check_args(num_spaces, space_index, until_space_type)
|
||||
if num_spaces:
|
||||
new_space_index = self.current_space_index + num_spaces
|
||||
elif space_index:
|
||||
if isinstance(space_index, str):
|
||||
space_index = get_space_index(space_index)
|
||||
new_space_index = space_index
|
||||
elif until_space_type:
|
||||
new_space_index = get_index_of_next_space_of_type(until_space_type)
|
||||
|
||||
if pass_go and new_space_index >= Board.NUM_SPACES - 1:
|
||||
print("You passed go! Here's 200 Monopoly Dollars")
|
||||
self.money += 200
|
||||
new_space_index = new_space_index - Board.NUM_SPACES
|
||||
elif pass_go and self.current_space_index > new_space_index:
|
||||
print("You passed go! Here's 200 Monopoly Dollars")
|
||||
self.money += 200
|
||||
|
||||
self.current_space_index = new_space_index
|
||||
self.do_action_of_current_space()
|
||||
|
||||
def do_action_of_current_space(self):
|
||||
space = Board.spaces[self.current_space_index]
|
||||
print(space)
|
||||
space.action(self)
|
||||
|
||||
def go_to_jail(self):
|
||||
self.in_jail = True
|
||||
self.current_space_index = get_space_index("Jail")
|
||||
|
||||
|
||||
class Game:
|
||||
game = None
|
||||
|
||||
def __init__(self, *player_names):
|
||||
self.game = self
|
||||
if len(player_names) > 8:
|
||||
raise TooManyPlayers
|
||||
self._players = [Player(player_name) for player_name in player_names]
|
||||
self.players = cycle(self._players)
|
||||
# TODO: roll to see who goes first, then order the players accordingly
|
||||
shuffle_decks()
|
||||
self.next()
|
||||
|
||||
@property
|
||||
def active_players(self):
|
||||
return [player for player in self._players if not player.bankrupt]
|
||||
|
||||
def next(self):
|
||||
while len(self.active_players) > 1:
|
||||
current_player = next(self.players)
|
||||
if not current_player.bankrupt:
|
||||
current_player.take_a_turn()
|
||||
while current_player.go_again:
|
||||
current_player.take_a_turn()
|
||||
self.end()
|
||||
|
||||
def end(self):
|
||||
print(self.active_players[0], "is the winner!")
|
||||
|
||||
|
||||
game = Game("Bot", "Ro")
|
||||
Reference in New Issue
Block a user