Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
37f2dda0c3 | |||
5ba5cedd02 | |||
|
d51382960a | ||
|
5e776f2eac | ||
|
0e744004c7 | ||
|
da49513ac8 | ||
|
8a400a3f30 | ||
|
ae65305d8d | ||
|
69547c2b79 | ||
|
857338ba5f | ||
|
250649d439 | ||
|
88c386d440 | ||
|
6f3b00d266 | ||
|
6ccecba442 | ||
|
d15b44340d | ||
|
3ef0072a80 | ||
|
b78eadc4dc | ||
|
38b1d28ecd | ||
|
37375b2fac |
5
Makefile
5
Makefile
@ -15,4 +15,7 @@ lint:
|
|||||||
test: # TODO: replace with real tests
|
test: # TODO: replace with real tests
|
||||||
python app.py && python strategy.py
|
python app.py && python strategy.py
|
||||||
|
|
||||||
.PHONY: build publish clean lint test
|
serve:
|
||||||
|
python -m http.server 1337
|
||||||
|
|
||||||
|
.PHONY: build publish clean lint test
|
||||||
|
48
README.md
48
README.md
@ -23,27 +23,41 @@ pip install pyroulette
|
|||||||
from pyroulette import generate_players, play_roulette
|
from pyroulette import generate_players, play_roulette
|
||||||
|
|
||||||
players = generate_players(
|
players = generate_players(
|
||||||
number_of_players=10,
|
num_players=50,
|
||||||
minimum_number_of_games=10,
|
min_num_games=min_games,
|
||||||
budget=100,
|
total_budget=100
|
||||||
)
|
)
|
||||||
|
|
||||||
for player in results:
|
players = play_roulette(
|
||||||
print(player)
|
|
||||||
|
|
||||||
results = play_roulette(
|
|
||||||
players=players,
|
players=players,
|
||||||
number_of_games=1000,
|
games=1000,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
print("Results:")
|
||||||
|
for p in sorted(players, reverse=True):
|
||||||
|
print("\n", p)
|
||||||
|
|
||||||
|
print("Statistics")
|
||||||
|
# get the wallet values for all players as a list
|
||||||
|
wallets = [player.wallet for player in players]
|
||||||
|
|
||||||
|
# calculate some statistics
|
||||||
|
avg_wallet = sum(wallets) / len(wallets)
|
||||||
|
median_wallet = sorted(wallets)[len(wallets) // 2]
|
||||||
|
|
||||||
|
# calculate winnings
|
||||||
|
winnings = [p.wallet - p.budget for p in players]
|
||||||
|
|
||||||
|
num_losers = len([w for w in winnings if w <= 0])
|
||||||
|
num_winners = len([w for w in winnings if w > 0])
|
||||||
|
num_bankrupt = len([l for l in wallets if l == 0])
|
||||||
|
|
||||||
|
# print the results
|
||||||
|
print(f"Average wallet value: {avg_wallet}\n")
|
||||||
|
print(f"Median wallet value: {median_wallet}\n")
|
||||||
|
print(f"Number of players who lost money: {num_losers}, proportion: {num_losers / len(players):.2f}")
|
||||||
|
print(f"Number of players who went bankrupt: {num_bankrupt}, proportion: {num_bankrupt / len(players):.2f}")
|
||||||
|
print()
|
||||||
|
print(f"Number of players who won more than they started with: {num_winners}, proportion: {num_winners / len(players):.2f}")
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
# uploading to pypi
|
|
||||||
|
|
||||||
```
|
|
||||||
pip install build
|
|
||||||
python -m build --sdist --wheel -n
|
|
||||||
twine upload dist/*
|
|
||||||
```
|
|
||||||
|
7
app.py
7
app.py
@ -76,13 +76,13 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
strategy = Strategy.generate_random(50)
|
strategy = Strategy.generate_random(50)
|
||||||
|
|
||||||
strategy.print_all()
|
strategy.print()
|
||||||
|
|
||||||
# define the minimum number of games that you want players to play
|
# define the minimum number of games that you want players to play
|
||||||
|
|
||||||
# print the total sum of all the placements
|
# print the total sum of all the placements
|
||||||
print("SUM")
|
print("SUM")
|
||||||
print(sum([p.value for p in placements]))
|
print(sum([p.cost for p in placements]))
|
||||||
|
|
||||||
# place the bets
|
# place the bets
|
||||||
bet = Strategy.place_bets(placements)
|
bet = Strategy.place_bets(placements)
|
||||||
@ -112,9 +112,8 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
print("======================")
|
print("======================")
|
||||||
print("SIMULATING GAMES")
|
print("SIMULATING GAMES")
|
||||||
# simulate 10 games
|
|
||||||
# seed(59)
|
# seed(59)
|
||||||
players = play_roulette(players, games=100000)
|
players = play_roulette(players, games=1000)
|
||||||
|
|
||||||
for p in sorted(players):
|
for p in sorted(players):
|
||||||
print(p, "\n")
|
print(p, "\n")
|
||||||
|
103
index.html
Normal file
103
index.html
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
|
||||||
|
<title>Roulette Demo</title>
|
||||||
|
|
||||||
|
<!-- <link rel="icon" type="image/png" href="favicon.png" /> -->
|
||||||
|
<link rel="stylesheet" href="https://pyscript.net/releases/2022.09.1/pyscript.css" />
|
||||||
|
|
||||||
|
<script defer src="https://pyscript.net/releases/2022.09.1/pyscript.js"></script>
|
||||||
|
<link rel="stylesheet" href="./assets/css/examples.css" />
|
||||||
|
<link rel="stylesheet" href="./assets/prism/prism.css" />
|
||||||
|
<script defer src="./assets/prism/prism.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<nav class="navbar" style="background-color: #000000;">
|
||||||
|
<div class="app-header">
|
||||||
|
<!-- <a href="/">
|
||||||
|
<img src="./logo.png" class="logo">
|
||||||
|
</a> -->
|
||||||
|
<a class="title" href="" style="color: #0d88c2;">Roulette</a>
|
||||||
|
<a href="https://git.clfx.cc/mm/roulette/src/branch/main/pyroulette/roulette.py" style="color: #ffffff;">(roulette.py)</a>
|
||||||
|
<a href="https://git.clfx.cc/mm/roulette/src/branch/main/index.html" style="color: #a6dc28;">(index.html)</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<section class="pyscript">
|
||||||
|
<div class="font-mono">
|
||||||
|
<h1 align="center">Let's Hack Roulette!</h1>
|
||||||
|
<h2 align="center">
|
||||||
|
Simulating 100 Games for 500 Players
|
||||||
|
</h2>
|
||||||
|
<p>
|
||||||
|
Note: winnings are re-invested, each player starts with $100 and chooses a strategy at random.
|
||||||
|
</p>
|
||||||
|
<label id="outputDiv"></label>
|
||||||
|
</div>
|
||||||
|
<center>
|
||||||
|
<div id="outputDiv2" class="font-mono"></div>
|
||||||
|
</center>
|
||||||
|
<br>
|
||||||
|
<div id="outputDiv3" class="font-mono"></div>
|
||||||
|
<br>
|
||||||
|
<py-config>
|
||||||
|
packages = [
|
||||||
|
"pyroulette",
|
||||||
|
]
|
||||||
|
</py-config>
|
||||||
|
<py-script output="outputDiv2">
|
||||||
|
import pyroulette as pr
|
||||||
|
|
||||||
|
# seed(59)
|
||||||
|
from random import random, randint
|
||||||
|
|
||||||
|
players = []
|
||||||
|
# iterations * num_per_group = num_players
|
||||||
|
for _ in range(1, 50):
|
||||||
|
c = random()
|
||||||
|
if c < 0.25:
|
||||||
|
min_games = randint(1, 100)
|
||||||
|
elif c < 0.5:
|
||||||
|
min_games = randint(1, 25)
|
||||||
|
else: # bold half
|
||||||
|
min_games = randint(1, 2)
|
||||||
|
|
||||||
|
# min_games = 100 # this caps out at about $250 wallet. need to bet bigger to win bigger.
|
||||||
|
players.extend(pr.generate_players(num_players=10, min_num_games=min_games, total_budget=100))
|
||||||
|
|
||||||
|
players = pr.play_roulette(players, games=100)
|
||||||
|
|
||||||
|
# get the wallet values for all players as a list
|
||||||
|
wallets = [player.wallet for player in players]
|
||||||
|
# calculate some statistics
|
||||||
|
avg_wallet = sum(wallets) / len(wallets)
|
||||||
|
median_wallet = sorted(wallets)[len(wallets) // 2]
|
||||||
|
|
||||||
|
# calculate winnings
|
||||||
|
winnings = [p.wallet - p.budget for p in players]
|
||||||
|
|
||||||
|
num_losers = len([w for w in winnings if w <= 0])
|
||||||
|
num_winners = len([w for w in winnings if w > 0])
|
||||||
|
num_bankrupt = len([l for l in wallets if l == 0])
|
||||||
|
|
||||||
|
# print the results
|
||||||
|
print(f"Average wallet value: {avg_wallet}\n")
|
||||||
|
print(f"Median wallet value: {median_wallet}\n")
|
||||||
|
print(f"Number of players who lost money: {num_losers}, proportion: {num_losers / len(players):.2f}")
|
||||||
|
print(f"Number of players who went bankrupt: {num_bankrupt}, proportion: {num_bankrupt / len(players):.2f}")
|
||||||
|
print()
|
||||||
|
print(f"Number of players who won more than they started with: {num_winners}, proportion: {num_winners / len(players):.2f}")
|
||||||
|
</py-script>
|
||||||
|
|
||||||
|
<py-script output="outputDiv3">
|
||||||
|
for p in sorted(players, reverse=True):
|
||||||
|
print("\n<br>", p)
|
||||||
|
</py-script>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
@ -7,8 +7,14 @@ from random import choice, randint
|
|||||||
from statistics import mean, stdev
|
from statistics import mean, stdev
|
||||||
from typing import Dict, List, Optional
|
from typing import Dict, List, Optional
|
||||||
|
|
||||||
|
"""Set[str]:
|
||||||
|
Bets on single numbers.
|
||||||
|
"""
|
||||||
SINGLE_BETS = {str(i) for i in range(-1, 37)}
|
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(
|
FEASIBLE_MOVES = sorted(
|
||||||
{
|
{
|
||||||
*[f"street-{i}" for i in range(1, 14)],
|
*[f"street-{i}" for i in range(1, 14)],
|
||||||
@ -20,7 +26,9 @@ FEASIBLE_MOVES = sorted(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
"""Set[str]:
|
||||||
|
Aliases for different placements.
|
||||||
|
"""
|
||||||
ALIASES = {
|
ALIASES = {
|
||||||
"reds",
|
"reds",
|
||||||
"blacks",
|
"blacks",
|
||||||
@ -34,7 +42,11 @@ ALIASES = {
|
|||||||
"second-18",
|
"second-18",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CHIP_VALUES = {0.25, 0.5, 1, 5, 10, 25, 50, 100}
|
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]:
|
def init_spread() -> Dict[int, float]:
|
||||||
@ -45,6 +57,7 @@ def init_spread() -> Dict[int, float]:
|
|||||||
-------
|
-------
|
||||||
Bet
|
Bet
|
||||||
A dictionary representing the bet.
|
A dictionary representing the bet.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
D = {i: 0 for i in range(-1, 37)}
|
D = {i: 0 for i in range(-1, 37)}
|
||||||
return D
|
return D
|
||||||
@ -52,7 +65,19 @@ def init_spread() -> Dict[int, float]:
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Bet:
|
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)
|
spread: Dict[int, float] = field(default_factory=init_spread)
|
||||||
|
|
||||||
@ -92,7 +117,7 @@ class Bet:
|
|||||||
"""Return a copy of the bet."""
|
"""Return a copy of the bet."""
|
||||||
return Bet(self.spread.copy())
|
return Bet(self.spread.copy())
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self) -> iter:
|
||||||
return iter(self.spread.keys())
|
return iter(self.spread.keys())
|
||||||
|
|
||||||
def get(self, __name: int) -> float:
|
def get(self, __name: int) -> float:
|
||||||
@ -101,8 +126,17 @@ class Bet:
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Placement:
|
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
|
Attributes
|
||||||
----------
|
----------
|
||||||
@ -137,24 +171,41 @@ class Placement:
|
|||||||
return self.amt == other.amt and self.on == other.on
|
return self.amt == other.amt and self.on == other.on
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def value(self):
|
def cost(self) -> float:
|
||||||
"""
|
"""
|
||||||
Returns the value of the bet.
|
Returns the value of the bet.
|
||||||
"""
|
"""
|
||||||
return self.num * self.amt
|
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.
|
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)
|
return interpret_bet(self.on, self.num * self.amt, bet)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Strategy:
|
class Strategy:
|
||||||
"""
|
"""Represents list of placements on the roulette wheel.
|
||||||
A strategy is a list of placements, each of which is a bet on a
|
Each strategy is a bet on a particular number or group of numbers.
|
||||||
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
|
Attributes
|
||||||
----------
|
----------
|
||||||
@ -171,17 +222,19 @@ class Strategy:
|
|||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return (
|
return (
|
||||||
f"Strategy(budget={self.budget},"
|
f"Strategy(budget={self.budget},"
|
||||||
+ f"value={self.value}, placements={self.placements})"
|
+ f"cost={self.cost}, placements={self.placements})"
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def value(self):
|
def cost(self) -> float:
|
||||||
return sum([p.value for p in self.placements])
|
"""
|
||||||
|
Returns the total cost of the strategy.
|
||||||
|
"""
|
||||||
|
return sum([p.cost for p in self.placements])
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def generate_random(cls, budget: float, max_placements: int = 10) -> Strategy:
|
def generate_random(cls, budget: float, max_placements: int = 10) -> Strategy:
|
||||||
"""
|
"""Generates a random strategy.
|
||||||
Generates a random strategy.
|
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -218,25 +271,42 @@ class Strategy:
|
|||||||
) # TODO: make a parameter, allow for just single bets.
|
) # TODO: make a parameter, allow for just single bets.
|
||||||
placement = Placement(num, amt, on)
|
placement = Placement(num, amt, on)
|
||||||
placements.append(placement)
|
placements.append(placement)
|
||||||
budget -= placement.value
|
budget -= placement.cost
|
||||||
num_placements += 1
|
num_placements += 1
|
||||||
|
|
||||||
return Strategy(budget=initial_budget, placements=placements)
|
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:
|
for p in self.placements:
|
||||||
print(p)
|
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)
|
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
|
return self.placements
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def place_bets(placements: List[Placement]) -> Bet:
|
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
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -247,14 +317,26 @@ class Strategy:
|
|||||||
-------
|
-------
|
||||||
Bet
|
Bet
|
||||||
A dictionary representing the bet.
|
A dictionary representing the bet.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return sum([p.bet() for p in placements], Bet())
|
return sum([p.bet() for p in placements], Bet())
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Player:
|
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
|
Attributes
|
||||||
----------
|
----------
|
||||||
@ -267,7 +349,8 @@ class Player:
|
|||||||
(default: random int of length 8)
|
(default: random int of length 8)
|
||||||
wallet : float
|
wallet : float
|
||||||
The amount of money the player has left.
|
The amount of money the player has left.
|
||||||
(default: budget)
|
(initialized to equal the budget)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
budget: float
|
budget: float
|
||||||
@ -280,21 +363,22 @@ class Player:
|
|||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
_nl = "\n\t" # custom newline character
|
_nl = "\n\t" # custom newline character
|
||||||
return (
|
return (
|
||||||
f"Player(id={self.id}, budget={self.budget}, wallet={self.wallet}, "
|
f"Player(id={self.id}, "
|
||||||
|
+ f"budget={round(self.budget, 2)}, "
|
||||||
|
+ f"wallet={round(self.wallet, 2)}, "
|
||||||
+ f"num_placements={len(self.strategy.placements)}, "
|
+ f"num_placements={len(self.strategy.placements)}, "
|
||||||
+ f"strategy_budget={self.strategy.budget}, "
|
+ f"strategy_budget={round(self.strategy.budget, 2)}, "
|
||||||
+ f"strategy_cost={self.strategy.value}"
|
+ f"strategy_cost={round(self.strategy.cost, 2)}"
|
||||||
+ f"\nstrategy:{_nl}{_nl.join(map(str, sorted(self.strategy.placements)))}"
|
+ f"\nstrategy:{_nl}{_nl.join(map(str, sorted(self.strategy.placements)))}"
|
||||||
+ "\n)"
|
+ "\n)"
|
||||||
)
|
)
|
||||||
|
|
||||||
def __lt__(self, other):
|
def __lt__(self, other: Player) -> bool:
|
||||||
return self.wallet < other.wallet
|
return self.wallet < other.wallet
|
||||||
|
|
||||||
|
|
||||||
def expected(bet: Bet) -> float:
|
def expected(bet: Bet) -> float: # todo: move into a stats module.
|
||||||
"""
|
"""Returns the expected value of a bet.
|
||||||
Returns the expected value of a bet.
|
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -305,6 +389,7 @@ def expected(bet: Bet) -> float:
|
|||||||
-------
|
-------
|
||||||
float
|
float
|
||||||
The expected value of the bet.
|
The expected value of the bet.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
bets = list(bet.spread.values())
|
bets = list(bet.spread.values())
|
||||||
cond_bets = filter(lambda x: x > 0, bets)
|
cond_bets = filter(lambda x: x > 0, bets)
|
||||||
@ -319,8 +404,9 @@ def expected(bet: Bet) -> float:
|
|||||||
|
|
||||||
|
|
||||||
def place_bet(bet: Bet, on: int, amount: float) -> Bet:
|
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
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -335,15 +421,15 @@ def place_bet(bet: Bet, on: int, amount: float) -> Bet:
|
|||||||
-------
|
-------
|
||||||
Bet
|
Bet
|
||||||
A dictionary representing the bet with the new bet placed.
|
A dictionary representing the bet with the new bet placed.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
bet = bet.copy()
|
bet = bet.copy()
|
||||||
bet[on] += amount
|
bet[on] += amount
|
||||||
return bet
|
return bet
|
||||||
|
|
||||||
|
|
||||||
def interpret_bet(on="red", amount=0, bet=Optional[Bet]) -> 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.
|
||||||
Interprets a bet and returns a dictionary representing the bet.
|
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -359,6 +445,7 @@ def interpret_bet(on="red", amount=0, bet=Optional[Bet]) -> Bet:
|
|||||||
-------
|
-------
|
||||||
Bet
|
Bet
|
||||||
A dictionary representing the bet.
|
A dictionary representing the bet.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
assert (on in FEASIBLE_MOVES) or (
|
assert (on in FEASIBLE_MOVES) or (
|
||||||
on in ALIASES
|
on in ALIASES
|
||||||
@ -429,9 +516,11 @@ def interpret_bet(on="red", amount=0, bet=Optional[Bet]) -> Bet:
|
|||||||
return bet
|
return bet
|
||||||
|
|
||||||
|
|
||||||
def simulate_random_strategy(min_num_games=1, total_budget=200) -> Strategy:
|
def simulate_random_strategy(
|
||||||
"""
|
min_num_games: int = 1, total_budget: float = 200
|
||||||
Simulates a random strategy based on the minimum number of games that
|
) -> 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.
|
the player wants to play and the total budget that the player has.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
@ -445,15 +534,18 @@ def simulate_random_strategy(min_num_games=1, total_budget=200) -> Strategy:
|
|||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
Strategy
|
||||||
|
The random strategy that the player will follow.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
strategy_budget = total_budget // min_num_games
|
strategy_budget = total_budget // min_num_games
|
||||||
return Strategy.generate_random(strategy_budget)
|
return Strategy.generate_random(strategy_budget)
|
||||||
|
|
||||||
|
|
||||||
def generate_players(num_players=10, min_num_games=1, total_budget=200) -> List[Player]:
|
def generate_players(
|
||||||
"""
|
num_players: int = 10, min_num_games: int = 1, total_budget: float = 200
|
||||||
Generates a list of players with random strategies.
|
) -> List[Player]:
|
||||||
|
"""Generates a list of players with random strategies.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -468,6 +560,8 @@ def generate_players(num_players=10, min_num_games=1, total_budget=200) -> List[
|
|||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
List[Player]
|
List[Player]
|
||||||
|
A list of players with random strategies.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
players = [
|
players = [
|
||||||
Player(
|
Player(
|
||||||
@ -493,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]:
|
def spin_wheel(players, verbose=False) -> List[float]:
|
||||||
"""
|
"""Simulates a single game of roulette.
|
||||||
Simulates a single game of roulette.
|
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -506,6 +599,7 @@ def spin_wheel(players, verbose=False) -> List[float]:
|
|||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
List[float]
|
List[float]
|
||||||
|
The amount of money each player won.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# pick a random number
|
# pick a random number
|
||||||
@ -521,8 +615,7 @@ def spin_wheel(players, verbose=False) -> List[float]:
|
|||||||
|
|
||||||
|
|
||||||
def play_roulette(players: List[Player], games: int = 10) -> List[Player]:
|
def play_roulette(players: List[Player], games: int = 10) -> List[Player]:
|
||||||
"""
|
"""Simulates playing multiple games of roulette.
|
||||||
Simulates playing multiple games of roulette.
|
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
@ -535,6 +628,7 @@ def play_roulette(players: List[Player], games: int = 10) -> List[Player]:
|
|||||||
-------
|
-------
|
||||||
List[Player]
|
List[Player]
|
||||||
The players after playing the games.
|
The players after playing the games.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
losers = []
|
losers = []
|
||||||
for g in range(games):
|
for g in range(games):
|
||||||
@ -544,13 +638,13 @@ def play_roulette(players: List[Player], games: int = 10) -> List[Player]:
|
|||||||
winnings = spin_wheel(players)
|
winnings = spin_wheel(players)
|
||||||
new_losers = []
|
new_losers = []
|
||||||
for i, p in enumerate(players):
|
for i, p in enumerate(players):
|
||||||
p.wallet -= p.strategy.value
|
p.wallet -= p.strategy.cost
|
||||||
p.wallet += winnings[i]
|
p.wallet += winnings[i]
|
||||||
# TODO: reinvestment logic goes here.
|
# TODO: reinvestment logic goes here.
|
||||||
# maybe add "reinvest" as a player attribute?
|
# maybe add "reinvest" as a player attribute?
|
||||||
# if a player runs out of money to keep using their strategy,
|
# if a player runs out of money to keep using their strategy,
|
||||||
# remove them from the list of players and add them to losers.
|
# 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)
|
new_losers.append(p)
|
||||||
for losing_player in new_losers:
|
for losing_player in new_losers:
|
||||||
players.remove(losing_player)
|
players.remove(losing_player)
|
||||||
|
2
setup.py
2
setup.py
@ -10,7 +10,7 @@ with open(BASEDIR.joinpath("README.md"), "r") as fp:
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="pyroulette",
|
name="pyroulette",
|
||||||
version="0.0.3",
|
version="0.0.5",
|
||||||
description="A package for exploring roulette strategies.",
|
description="A package for exploring roulette strategies.",
|
||||||
long_description=LONG_DESCRIPTION,
|
long_description=LONG_DESCRIPTION,
|
||||||
long_description_content_type="text/markdown",
|
long_description_content_type="text/markdown",
|
||||||
|
Loading…
Reference in New Issue
Block a user