linting problems, rename functions

This commit is contained in:
Michael Pilosov 2022-11-26 22:10:24 -07:00
parent 24a197f760
commit fb66902f59
6 changed files with 80 additions and 66 deletions

View File

@ -1,8 +1,15 @@
build:
rm -rf build/ dist/ *.egg-info/
build: clean
python -m build --sdist --wheel -n
clean:
rm -rf build/ dist/ *.egg-info/ .eggs/ .pytest_cache/ .mypy_cache/ .coverage */__pycache__/ __pycache__/
publish: build
twine upload dist/*
.PHONY: build publish
lint:
black .
isort .
flake8 --max-line-length=88 --extend-ignore=E203,W503 pyroulette/
.PHONY: build publish clean lint

View File

@ -28,13 +28,15 @@ players = generate_players(
budget=100,
)
for player in results:
print(player)
results = play_roulette(
players=players,
number_of_games=1000,
)
for player in results:
print(player)
```

18
app.py
View File

@ -1,18 +1,8 @@
from random import choice, randint, seed
from pyroulette import (
FEASIBLE_MOVES,
Placement,
Bet,
Player,
Strategy,
expected,
generate_players,
init_spread,
interpret_bet,
place_bet,
simulate_games,
)
from pyroulette import (FEASIBLE_MOVES, Bet, Placement, Player, Strategy,
expected, generate_players, init_spread, interpret_bet,
place_bet, play_roulette)
if __name__ == "__main__":
@ -108,7 +98,7 @@ if __name__ == "__main__":
print("SIMULATING GAMES")
# simulate 10 games
# seed(59)
players = simulate_games(players, num_games=100000)
players = play_roulette(players, games=100000)
for p in sorted(players):
print(p, "\n")

View File

@ -1,14 +1,11 @@
from __future__ import annotations
import json
from dataclasses import dataclass, field
from functools import reduce
from random import choice, randint
from statistics import mean, stdev
from typing import Dict, List, Optional
import json
# define the class Bet which inherits from Dict[int, float] and define it's __add__ method as calling combine_bets
# Bet = Dict[int, float]
def init_spread() -> Dict[int, float]:
@ -24,7 +21,6 @@ def init_spread() -> Dict[int, float]:
return D
# for two bets of structure Dict[int, float], iterate through all the keys and add up the values, returning a new dict.
def combine_bets(bet_1: Bet, bet_2: Bet) -> Bet:
"""
Combines two bets into a single bet.
@ -143,19 +139,13 @@ def expected(bet: Bet) -> float:
amt = sum(bets)
payout = amt * 36 / 38
print(
f"bet: {amt:.2f}, expected: {payout:.2f}: {payout/amt:2.4f} with std {stdev(bets*36)} mean win of {36*mean(cond_bets)} {sum(filter(lambda x: x > 0, bets))}/38 times."
f"bet: {amt:.2f}, expected: {payout:.2f}: {payout/amt:2.4f}"
+ f"with std {stdev(bets*36)} mean win of"
+ f"{36*mean(cond_bets)} {sum(filter(lambda x: x > 0, bets))}/38 times."
)
return payout
# 38 numbers, 6 street bets, 2 half-bets,
# payout grid based on bets placed.
# a street bet is the same as splitting the bet across all the numbers in the group.
# will use a function to distribute / interpret the bets, but it seems like we only need to track the numbers on the wheel.
def place_bet(bet: Bet, on: int, amount: float) -> Bet:
"""
Places a bet on a number.
@ -258,7 +248,8 @@ def interpret_bet(on="red", amount=0, bet=Optional[Bet]) -> Bet:
div = 1
except ValueError as e:
raise e(
f"Bet `{on}` not understood. Choose from feasible moves:\n {set(range(-1, 37))}"
f"Bet `{on}` not understood."
+ f"Choose from feasible moves:\n {set(range(-1, 37))}"
)
bet = reduce(lambda bet, num: place_bet(bet, num, amount / div), NUMS, bet)
@ -287,9 +278,10 @@ class Placement:
on: str
def __post_init__(self):
assert (self.on in FEASIBLE_MOVES) or (
self.on in ALIASES
), f"Bet `{self.on}` not understood. Choose from feasible moves:\n {FEASIBLE_MOVES}"
assert (self.on in FEASIBLE_MOVES) or (self.on in ALIASES), (
f"Bet `{self.on}` not understood."
+ f"Choose from feasible moves:\n {FEASIBLE_MOVES}"
)
def __gt__(self, other):
return self.amt > other.amt
@ -316,20 +308,18 @@ class Placement:
return interpret_bet(self.on, self.num * self.amt, bet)
# for a list of Placements, call the place_bet method on each one and combine the results using reduce and combine_bets, starting with an empty dictionary as the initial argument
@dataclass
class Strategy:
"""
A strategy is a list of placements, each of which is a bet on a particular number or group of numbers.
A strategy is a list of placements, each of which is a bet on a
particular number or group of numbers.
Attributes
----------
budget : float
The amount of money to spend on the strategy.
placements : List[Placement]
A list of placements, each of which is a bet on a particular number or group of numbers.
A list of placements the player will make.
"""
@ -337,7 +327,10 @@ class Strategy:
placements: List[Placement] = field(default_factory=list)
def __repr__(self) -> str:
return f"Strategy(budget={self.budget}, value={self.value}, placements={self.placements})"
return (
f"Strategy(budget={self.budget},"
+ f"value={self.value}, placements={self.placements})"
)
@property
def value(self):
@ -369,10 +362,11 @@ class Strategy:
while (budget > 0) and (num_placements < max_placements):
amt = choice([v for v in CHIP_VALUES if v <= budget])
# guarantees the max bet cannot exceed budget:
# 4 is the max number of chips because after that you might as well use a higher chip value.
# 4 is the max number of chips bc you might as well use a higher chip value.
num = randint(1, min(budget // amt, 4))
# select random bet type
# TODO: consider if this is the logic you want... really let's define a player's profile / psychological disposition.
# TODO: consider if this is the logic you want...
# really let's define a player's profile / psychological disposition.
# if randint(0, 1) == 0:
# on = choice(list(FEASIBLE_MOVES))
# else:
@ -446,7 +440,13 @@ class Player:
self.wallet: float = self.budget
def __repr__(self) -> str:
return f"Player(id={self.id}, budget={self.budget}, wallet={self.wallet}, strategy={sorted(self.strategy.placements)}, strategy_cost={self.strategy.value}, strategy_budget={self.strategy.budget}, num_placements={len(self.strategy.placements)}"
return (
f"Player(id={self.id}, budget={self.budget}, wallet={self.wallet},"
+ f"strategy={sorted(self.strategy.placements)},"
+ f"strategy_cost={self.strategy.value},"
+ f"strategy_budget={self.strategy.budget},"
+ f"num_placements={len(self.strategy.placements)}"
)
def __lt__(self, other):
return self.id < other.id
@ -474,7 +474,6 @@ def simulate_random_strategy(min_num_games=1, total_budget=200) -> Strategy:
return Strategy.generate_random(strategy_budget)
# given BUDGET, generate a bunch of random players, each with a random strategy, and return a list of players
def generate_players(num_players=10, min_num_games=1, total_budget=200) -> List[Player]:
"""
Generates a list of players with random strategies.
@ -484,7 +483,8 @@ def generate_players(num_players=10, min_num_games=1, total_budget=200) -> List[
num_players : int
The number of players to generate.
min_num_games : int
The minimum number of games each player will play using their strategy and budget.
The minimum number of games each player wants to play
given their strategy and budget.
total_budget : float
The total budget for each player.
@ -502,7 +502,8 @@ def generate_players(num_players=10, min_num_games=1, total_budget=200) -> List[
for i in range(num_players)
]
# if a player has placements with identical amt and on values, combine them into a single placement
# if a player has placements with identical `amt` and `on` values,
# combine them into a single placement
for player in players:
placements = []
for placement in player.strategy.placements:
@ -514,8 +515,7 @@ def generate_players(num_players=10, min_num_games=1, total_budget=200) -> List[
return players
# simulate a game of roulette, picking a random integer from -1 to 37, taking the players as inputs and returning their expected winnings
def simulate_game(players, verbose=False) -> List[float]:
def play_round(players, verbose=False) -> List[float]:
"""
Simulates a single game of roulette.
@ -538,31 +538,45 @@ def simulate_game(players, verbose=False) -> List[float]:
# for each player, place their bets on the wheel
bets = [p.strategy.get_bet() for p in players]
# for each player, calculate their winnings
winnings = [36 * bet.get(num, 0) for bet in bets]
winnings = [36 * bet.get(num) for bet in bets]
# for each player, calculate their expected winnings
return winnings
# simulate multiple games, reducing each player's budget by the amount of their bet and adding the amount of their winnings
def simulate_games(players, num_games=10):
def play_roulette(players: List[Player], games: int = 10) -> List[Player]:
"""
Simulates playing multiple games of roulette.
Parameters
----------
players : List[Player]
The players in the game.
games : int
The number of games to play.
Returns
-------
List[Player]
The players after playing the games.
"""
losers = []
for g in range(num_games):
for g in range(games):
if not players:
break
# print(f"GAME {g}")
winnings = simulate_game(players)
winnings = play_round(players)
new_losers = []
for i, p in enumerate(players):
p.wallet -= p.strategy.value
p.wallet += winnings[
i
] # TODO: reinvestment logic goes here. maybe add "reinvest" as a player attribute?
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 the list of losers
# remove them from the list of players and add them to losers.
if p.wallet < p.strategy.value:
new_losers.append(p)
for l in new_losers:
players.remove(l)
for losing_player in new_losers:
players.remove(losing_player)
losers.extend(new_losers)
return players + losers

View File

@ -1,6 +1,7 @@
from setuptools import setup
from pathlib import Path
from setuptools import setup
# Globals and constants variables.
BASEDIR = Path(__file__).parent.resolve()
@ -9,10 +10,10 @@ with open(BASEDIR.joinpath("README.md"), "r") as fp:
setup(
name="pyroulette",
version="0.0.1rc1",
version="0.0.1rc2",
description="A package for exploring roulette strategies.",
long_description=LONG_DESCRIPTION,
long_description_content_type='text/markdown',
long_description_content_type="text/markdown",
author="Mathematical Michael",
author_email="consistentbayes@gmail.com",
url="https://github.com/mathematicalmichael/pyroulette",

View File

@ -1,4 +1,4 @@
from pyroulette.roulette import Placement, Strategy, Bet
from pyroulette.roulette import Bet, Placement, Strategy
if __name__ == "__main__":
print(Bet({-1: 1}).__repr__()) # this should print with 00