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: build: clean
rm -rf build/ dist/ *.egg-info/
python -m build --sdist --wheel -n python -m build --sdist --wheel -n
clean:
rm -rf build/ dist/ *.egg-info/ .eggs/ .pytest_cache/ .mypy_cache/ .coverage */__pycache__/ __pycache__/
publish: build publish: build
twine upload dist/* 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, budget=100,
) )
for player in results:
print(player)
results = play_roulette( results = play_roulette(
players=players, players=players,
number_of_games=1000, 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 random import choice, randint, seed
from pyroulette import ( from pyroulette import (FEASIBLE_MOVES, Bet, Placement, Player, Strategy,
FEASIBLE_MOVES, expected, generate_players, init_spread, interpret_bet,
Placement, place_bet, play_roulette)
Bet,
Player,
Strategy,
expected,
generate_players,
init_spread,
interpret_bet,
place_bet,
simulate_games,
)
if __name__ == "__main__": if __name__ == "__main__":
@ -108,7 +98,7 @@ if __name__ == "__main__":
print("SIMULATING GAMES") print("SIMULATING GAMES")
# simulate 10 games # simulate 10 games
# seed(59) # seed(59)
players = simulate_games(players, num_games=100000) players = play_roulette(players, games=100000)
for p in sorted(players): for p in sorted(players):
print(p, "\n") print(p, "\n")

View File

@ -1,14 +1,11 @@
from __future__ import annotations from __future__ import annotations
import json
from dataclasses import dataclass, field from dataclasses import dataclass, field
from functools import reduce from functools import reduce
from random import choice, randint 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
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]: def init_spread() -> Dict[int, float]:
@ -24,7 +21,6 @@ def init_spread() -> Dict[int, float]:
return D 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: def combine_bets(bet_1: Bet, bet_2: Bet) -> Bet:
""" """
Combines two bets into a single bet. Combines two bets into a single bet.
@ -143,19 +139,13 @@ def expected(bet: Bet) -> float:
amt = sum(bets) amt = sum(bets)
payout = amt * 36 / 38 payout = amt * 36 / 38
print( 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 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: def place_bet(bet: Bet, on: int, amount: float) -> Bet:
""" """
Places a bet on a number. Places a bet on a number.
@ -258,7 +248,8 @@ def interpret_bet(on="red", amount=0, bet=Optional[Bet]) -> Bet:
div = 1 div = 1
except ValueError as e: except ValueError as e:
raise 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) bet = reduce(lambda bet, num: place_bet(bet, num, amount / div), NUMS, bet)
@ -287,9 +278,10 @@ class Placement:
on: str on: str
def __post_init__(self): def __post_init__(self):
assert (self.on in FEASIBLE_MOVES) or ( assert (self.on in FEASIBLE_MOVES) or (self.on in ALIASES), (
self.on in ALIASES f"Bet `{self.on}` not understood."
), f"Bet `{self.on}` not understood. Choose from feasible moves:\n {FEASIBLE_MOVES}" + f"Choose from feasible moves:\n {FEASIBLE_MOVES}"
)
def __gt__(self, other): def __gt__(self, other):
return self.amt > other.amt return self.amt > other.amt
@ -316,20 +308,18 @@ class Placement:
return interpret_bet(self.on, self.num * self.amt, bet) 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 @dataclass
class Strategy: 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 Attributes
---------- ----------
budget : float budget : float
The amount of money to spend on the strategy. The amount of money to spend on the strategy.
placements : List[Placement] 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) placements: List[Placement] = field(default_factory=list)
def __repr__(self) -> str: 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 @property
def value(self): def value(self):
@ -369,10 +362,11 @@ class Strategy:
while (budget > 0) and (num_placements < max_placements): while (budget > 0) and (num_placements < max_placements):
amt = choice([v for v in CHIP_VALUES if v <= budget]) amt = choice([v for v in CHIP_VALUES if v <= budget])
# guarantees the max bet cannot exceed 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)) num = randint(1, min(budget // amt, 4))
# select random bet type # 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: # if randint(0, 1) == 0:
# on = choice(list(FEASIBLE_MOVES)) # on = choice(list(FEASIBLE_MOVES))
# else: # else:
@ -446,7 +440,13 @@ class Player:
self.wallet: float = self.budget self.wallet: float = self.budget
def __repr__(self) -> str: 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): def __lt__(self, other):
return self.id < other.id 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) 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]: def generate_players(num_players=10, min_num_games=1, total_budget=200) -> List[Player]:
""" """
Generates a list of players with random strategies. 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 num_players : int
The number of players to generate. The number of players to generate.
min_num_games : int 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 total_budget : float
The total budget for each player. 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) 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: for player in players:
placements = [] placements = []
for placement in player.strategy.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 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 play_round(players, verbose=False) -> List[float]:
def simulate_game(players, verbose=False) -> List[float]:
""" """
Simulates a single game of roulette. 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 # for each player, place their bets on the wheel
bets = [p.strategy.get_bet() for p in players] bets = [p.strategy.get_bet() for p in players]
# for each player, calculate their winnings # 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 # for each player, calculate their expected winnings
return 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 play_roulette(players: List[Player], games: int = 10) -> List[Player]:
def simulate_games(players, num_games=10): """
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 = [] losers = []
for g in range(num_games): for g in range(games):
if not players: if not players:
break break
# print(f"GAME {g}") # print(f"GAME {g}")
winnings = simulate_game(players) winnings = play_round(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.value
p.wallet += winnings[ p.wallet += winnings[i]
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 the list of losers # remove them from the list of players and add them to losers.
if p.wallet < p.strategy.value: if p.wallet < p.strategy.value:
new_losers.append(p) new_losers.append(p)
for l in new_losers: for losing_player in new_losers:
players.remove(l) players.remove(losing_player)
losers.extend(new_losers) losers.extend(new_losers)
return players + losers return players + losers

View File

@ -1,6 +1,7 @@
from setuptools import setup
from pathlib import Path from pathlib import Path
from setuptools import setup
# Globals and constants variables. # Globals and constants variables.
BASEDIR = Path(__file__).parent.resolve() BASEDIR = Path(__file__).parent.resolve()
@ -9,10 +10,10 @@ with open(BASEDIR.joinpath("README.md"), "r") as fp:
setup( setup(
name="pyroulette", name="pyroulette",
version="0.0.1rc1", version="0.0.1rc2",
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",
author="Mathematical Michael", author="Mathematical Michael",
author_email="consistentbayes@gmail.com", author_email="consistentbayes@gmail.com",
url="https://github.com/mathematicalmichael/pyroulette", 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__": if __name__ == "__main__":
print(Bet({-1: 1}).__repr__()) # this should print with 00 print(Bet({-1: 1}).__repr__()) # this should print with 00