docstring improvements and some renamings
This commit is contained in:
parent
5e776f2eac
commit
d51382960a
4
app.py
4
app.py
@ -76,13 +76,13 @@ if __name__ == "__main__":
|
||||
|
||||
strategy = Strategy.generate_random(50)
|
||||
|
||||
strategy.print_all()
|
||||
strategy.print()
|
||||
|
||||
# define the minimum number of games that you want players to play
|
||||
|
||||
# print the total sum of all the placements
|
||||
print("SUM")
|
||||
print(sum([p.value for p in placements]))
|
||||
print(sum([p.cost for p in placements]))
|
||||
|
||||
# place the bets
|
||||
bet = Strategy.place_bets(placements)
|
||||
|
@ -7,8 +7,14 @@ from random import choice, randint
|
||||
from statistics import mean, stdev
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
"""Set[str]:
|
||||
Bets on single numbers.
|
||||
"""
|
||||
SINGLE_BETS = {str(i) for i in range(-1, 37)}
|
||||
|
||||
"""Set[str]:
|
||||
The possible moves that can be made in a game of roulette.
|
||||
"""
|
||||
FEASIBLE_MOVES = sorted(
|
||||
{
|
||||
*[f"street-{i}" for i in range(1, 14)],
|
||||
@ -20,7 +26,9 @@ FEASIBLE_MOVES = sorted(
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
"""Set[str]:
|
||||
Aliases for different placements.
|
||||
"""
|
||||
ALIASES = {
|
||||
"reds",
|
||||
"blacks",
|
||||
@ -34,7 +42,11 @@ ALIASES = {
|
||||
"second-18",
|
||||
}
|
||||
|
||||
|
||||
CHIP_VALUES = {0.25, 0.5, 1, 5, 10, 25, 50, 100}
|
||||
"""Set[float]:
|
||||
The possible chip values that a player can place on a given placement.
|
||||
"""
|
||||
|
||||
|
||||
def init_spread() -> Dict[int, float]:
|
||||
@ -45,6 +57,7 @@ def init_spread() -> Dict[int, float]:
|
||||
-------
|
||||
Bet
|
||||
A dictionary representing the bet.
|
||||
|
||||
"""
|
||||
D = {i: 0 for i in range(-1, 37)}
|
||||
return D
|
||||
@ -52,7 +65,19 @@ def init_spread() -> Dict[int, float]:
|
||||
|
||||
@dataclass
|
||||
class Bet:
|
||||
"""A class for representing a bet."""
|
||||
"""A class for representing a bet.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
spread : Dict[int, float], optional
|
||||
A dictionary representing the bet, by default init_spread()
|
||||
|
||||
Attributes
|
||||
----------
|
||||
spread : Dict[int, float]
|
||||
A dictionary representing the bet.
|
||||
|
||||
"""
|
||||
|
||||
spread: Dict[int, float] = field(default_factory=init_spread)
|
||||
|
||||
@ -92,7 +117,7 @@ class Bet:
|
||||
"""Return a copy of the bet."""
|
||||
return Bet(self.spread.copy())
|
||||
|
||||
def __iter__(self):
|
||||
def __iter__(self) -> iter:
|
||||
return iter(self.spread.keys())
|
||||
|
||||
def get(self, __name: int) -> float:
|
||||
@ -101,8 +126,17 @@ class Bet:
|
||||
|
||||
@dataclass
|
||||
class Placement:
|
||||
"""
|
||||
Defines a bet based on the number of chips and value of each chip.
|
||||
"""Defines a bet based on the number of chips and value of each chip.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
num : int
|
||||
The number of chips to bet.
|
||||
amt : float
|
||||
The value of each chip.
|
||||
on : str
|
||||
The type of bet to place for which the chips are being used.
|
||||
|
||||
|
||||
Attributes
|
||||
----------
|
||||
@ -137,24 +171,41 @@ class Placement:
|
||||
return self.amt == other.amt and self.on == other.on
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
def cost(self) -> float:
|
||||
"""
|
||||
Returns the value of the bet.
|
||||
"""
|
||||
return self.num * self.amt
|
||||
|
||||
def bet(self, bet=None) -> Bet:
|
||||
def bet(self, bet: Optional[Bet] = None) -> Bet:
|
||||
"""
|
||||
Places a bet on the wheel based on the bet type.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
bet : Bet, optional
|
||||
The bet to place, by default None
|
||||
|
||||
Returns
|
||||
-------
|
||||
Bet
|
||||
The bet placed on the wheel.
|
||||
"""
|
||||
return interpret_bet(self.on, self.num * self.amt, bet)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Strategy:
|
||||
"""
|
||||
A strategy is a list of placements, each of which is a bet on a
|
||||
particular number or group of numbers.
|
||||
"""Represents list of placements on the roulette wheel.
|
||||
Each strategy is a bet on a particular number or group of numbers.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
budget : float
|
||||
The amount of money to spend on the strategy.
|
||||
placements : List[Placement]
|
||||
A list of placements the player will make.
|
||||
|
||||
|
||||
Attributes
|
||||
----------
|
||||
@ -171,17 +222,19 @@ class Strategy:
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f"Strategy(budget={self.budget},"
|
||||
+ f"value={self.value}, placements={self.placements})"
|
||||
+ f"cost={self.cost}, placements={self.placements})"
|
||||
)
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
return sum([p.value for p in self.placements])
|
||||
def cost(self) -> float:
|
||||
"""
|
||||
Returns the total cost of the strategy.
|
||||
"""
|
||||
return sum([p.cost for p in self.placements])
|
||||
|
||||
@classmethod
|
||||
def generate_random(cls, budget: float, max_placements: int = 10) -> Strategy:
|
||||
"""
|
||||
Generates a random strategy.
|
||||
"""Generates a random strategy.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
@ -218,25 +271,42 @@ class Strategy:
|
||||
) # TODO: make a parameter, allow for just single bets.
|
||||
placement = Placement(num, amt, on)
|
||||
placements.append(placement)
|
||||
budget -= placement.value
|
||||
budget -= placement.cost
|
||||
num_placements += 1
|
||||
|
||||
return Strategy(budget=initial_budget, placements=placements)
|
||||
|
||||
def print_all(self) -> None:
|
||||
def print(self) -> None:
|
||||
"""Prints all of the placements involved in the strategy."""
|
||||
for p in self.placements:
|
||||
print(p)
|
||||
|
||||
def get_bet(self):
|
||||
def get_bet(self) -> Bet:
|
||||
"""Returns a bet object based on the strategy's placements.
|
||||
|
||||
Returns
|
||||
-------
|
||||
Bet
|
||||
A bet object representing the individual spread \
|
||||
on the inside of the table.
|
||||
|
||||
"""
|
||||
return self.place_bets(self.placements)
|
||||
|
||||
def get_placements(self):
|
||||
def get_placements(self) -> List[Placement]:
|
||||
"""Returns the placements in the strategy.
|
||||
|
||||
Returns
|
||||
-------
|
||||
List[Placement]
|
||||
A list of placements.
|
||||
|
||||
"""
|
||||
return self.placements
|
||||
|
||||
@staticmethod
|
||||
def place_bets(placements: List[Placement]) -> Bet:
|
||||
"""
|
||||
Places a list of bets on the wheel given a list of Placements.
|
||||
"""Places a list of bets on the wheel given a list of Placements.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
@ -247,14 +317,26 @@ class Strategy:
|
||||
-------
|
||||
Bet
|
||||
A dictionary representing the bet.
|
||||
|
||||
"""
|
||||
return sum([p.bet() for p in placements], Bet())
|
||||
|
||||
|
||||
@dataclass
|
||||
class Player:
|
||||
"""
|
||||
A player of the game.
|
||||
"""A player of the game.
|
||||
|
||||
Note: this dataclass is mutable.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
budget : float
|
||||
The amount of money the player starts with.
|
||||
strategy : Strategy
|
||||
The strategy the player uses to place bets.
|
||||
id: int
|
||||
The id of the player.
|
||||
(default: random int of length 8)
|
||||
|
||||
Attributes
|
||||
----------
|
||||
@ -267,7 +349,8 @@ class Player:
|
||||
(default: random int of length 8)
|
||||
wallet : float
|
||||
The amount of money the player has left.
|
||||
(default: budget)
|
||||
(initialized to equal the budget)
|
||||
|
||||
"""
|
||||
|
||||
budget: float
|
||||
@ -285,18 +368,17 @@ class Player:
|
||||
+ f"wallet={round(self.wallet, 2)}, "
|
||||
+ f"num_placements={len(self.strategy.placements)}, "
|
||||
+ f"strategy_budget={round(self.strategy.budget, 2)}, "
|
||||
+ f"strategy_cost={round(self.strategy.value, 2)}"
|
||||
+ f"strategy_cost={round(self.strategy.cost, 2)}"
|
||||
+ f"\nstrategy:{_nl}{_nl.join(map(str, sorted(self.strategy.placements)))}"
|
||||
+ "\n)"
|
||||
)
|
||||
|
||||
def __lt__(self, other):
|
||||
def __lt__(self, other: Player) -> bool:
|
||||
return self.wallet < other.wallet
|
||||
|
||||
|
||||
def expected(bet: Bet) -> float:
|
||||
"""
|
||||
Returns the expected value of a bet.
|
||||
def expected(bet: Bet) -> float: # todo: move into a stats module.
|
||||
"""Returns the expected value of a bet.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
@ -307,6 +389,7 @@ def expected(bet: Bet) -> float:
|
||||
-------
|
||||
float
|
||||
The expected value of the bet.
|
||||
|
||||
"""
|
||||
bets = list(bet.spread.values())
|
||||
cond_bets = filter(lambda x: x > 0, bets)
|
||||
@ -321,8 +404,9 @@ def expected(bet: Bet) -> float:
|
||||
|
||||
|
||||
def place_bet(bet: Bet, on: int, amount: float) -> Bet:
|
||||
"""
|
||||
Places a bet on a number.
|
||||
"""Places a bet on a number.
|
||||
|
||||
Note: this function creates a copy of the Bet so as not to mutate the original.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
@ -337,15 +421,15 @@ def place_bet(bet: Bet, on: int, amount: float) -> Bet:
|
||||
-------
|
||||
Bet
|
||||
A dictionary representing the bet with the new bet placed.
|
||||
|
||||
"""
|
||||
bet = bet.copy()
|
||||
bet[on] += amount
|
||||
return bet
|
||||
|
||||
|
||||
def interpret_bet(on="red", amount=0, bet=Optional[Bet]) -> Bet:
|
||||
"""
|
||||
Interprets a bet and returns a dictionary representing the bet.
|
||||
def interpret_bet(on: str = "red", amount: float = 0, bet: Optional[Bet] = None) -> Bet:
|
||||
"""Interprets a bet and returns a dictionary representing the bet.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
@ -361,6 +445,7 @@ def interpret_bet(on="red", amount=0, bet=Optional[Bet]) -> Bet:
|
||||
-------
|
||||
Bet
|
||||
A dictionary representing the bet.
|
||||
|
||||
"""
|
||||
assert (on in FEASIBLE_MOVES) or (
|
||||
on in ALIASES
|
||||
@ -431,9 +516,11 @@ def interpret_bet(on="red", amount=0, bet=Optional[Bet]) -> Bet:
|
||||
return bet
|
||||
|
||||
|
||||
def simulate_random_strategy(min_num_games=1, total_budget=200) -> Strategy:
|
||||
"""
|
||||
Simulates a random strategy based on the minimum number of games that
|
||||
def simulate_random_strategy(
|
||||
min_num_games: int = 1, total_budget: float = 200
|
||||
) -> Strategy:
|
||||
"""Simulates a random strategy for playing roulette.
|
||||
The strategy is based on the minimum number of games that
|
||||
the player wants to play and the total budget that the player has.
|
||||
|
||||
Parameters
|
||||
@ -447,15 +534,18 @@ def simulate_random_strategy(min_num_games=1, total_budget=200) -> Strategy:
|
||||
|
||||
Returns
|
||||
-------
|
||||
Strategy
|
||||
The random strategy that the player will follow.
|
||||
|
||||
"""
|
||||
strategy_budget = total_budget // min_num_games
|
||||
return Strategy.generate_random(strategy_budget)
|
||||
|
||||
|
||||
def generate_players(num_players=10, min_num_games=1, total_budget=200) -> List[Player]:
|
||||
"""
|
||||
Generates a list of players with random strategies.
|
||||
def generate_players(
|
||||
num_players: int = 10, min_num_games: int = 1, total_budget: float = 200
|
||||
) -> List[Player]:
|
||||
"""Generates a list of players with random strategies.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
@ -470,6 +560,8 @@ def generate_players(num_players=10, min_num_games=1, total_budget=200) -> List[
|
||||
Returns
|
||||
-------
|
||||
List[Player]
|
||||
A list of players with random strategies.
|
||||
|
||||
"""
|
||||
players = [
|
||||
Player(
|
||||
@ -495,8 +587,7 @@ def generate_players(num_players=10, min_num_games=1, total_budget=200) -> List[
|
||||
|
||||
|
||||
def spin_wheel(players, verbose=False) -> List[float]:
|
||||
"""
|
||||
Simulates a single game of roulette.
|
||||
"""Simulates a single game of roulette.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
@ -508,6 +599,7 @@ def spin_wheel(players, verbose=False) -> List[float]:
|
||||
Returns
|
||||
-------
|
||||
List[float]
|
||||
The amount of money each player won.
|
||||
|
||||
"""
|
||||
# pick a random number
|
||||
@ -523,8 +615,7 @@ def spin_wheel(players, verbose=False) -> List[float]:
|
||||
|
||||
|
||||
def play_roulette(players: List[Player], games: int = 10) -> List[Player]:
|
||||
"""
|
||||
Simulates playing multiple games of roulette.
|
||||
"""Simulates playing multiple games of roulette.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
@ -537,6 +628,7 @@ def play_roulette(players: List[Player], games: int = 10) -> List[Player]:
|
||||
-------
|
||||
List[Player]
|
||||
The players after playing the games.
|
||||
|
||||
"""
|
||||
losers = []
|
||||
for g in range(games):
|
||||
@ -546,13 +638,13 @@ def play_roulette(players: List[Player], games: int = 10) -> List[Player]:
|
||||
winnings = spin_wheel(players)
|
||||
new_losers = []
|
||||
for i, p in enumerate(players):
|
||||
p.wallet -= p.strategy.value
|
||||
p.wallet -= p.strategy.cost
|
||||
p.wallet += winnings[i]
|
||||
# TODO: reinvestment logic goes here.
|
||||
# maybe add "reinvest" as a player attribute?
|
||||
# if a player runs out of money to keep using their strategy,
|
||||
# remove them from the list of players and add them to losers.
|
||||
if p.wallet < p.strategy.value:
|
||||
if p.wallet < p.strategy.cost:
|
||||
new_losers.append(p)
|
||||
for losing_player in new_losers:
|
||||
players.remove(losing_player)
|
||||
|
Loading…
Reference in New Issue
Block a user