some minor refactoring, documentation, todos

This commit is contained in:
Michael Pilosov 2022-11-26 19:34:24 -07:00
parent d08e362ecd
commit 7060fb3744
3 changed files with 100 additions and 44 deletions

13
README.md Normal file
View File

@ -0,0 +1,13 @@
# pyroulette
## Explanation
- A `Player` has a `Strategy` which is comprised of a list of `Placements`, which represent a collective `Bet`.
- The player will stick to their strategy.
- Winnings are re-invested (todo: allow specifying player's pyschology, e.g. pocket winnings of certain proportion)
- A player's placement cannot be too complicated (max is 10)
- A `Strategy` is formed at random based on exhausting the strategy budget, which is determined by considering the player's total budget and the minimum number of games they desire to play.
- It is possible to have some money left over (either due to reaching the maximum number of placements or not having enough money to place a bet with the remaining available chips), meaning the strategy budget is less than the cost to play the strategy.
- When players cannot play their strategy anymore, they leave the game, meaning they can end the simulation with some remaining money (e.g. $100 to play a $40 strategy that you lose twice in a row will leave you with $20 remaining).
- When using `generate_players`, all players will have the same number of minimum games and budget.

25
app.py
View File

@ -1,16 +1,17 @@
from random import choice, randint, seed
from roulette import (
init_bet,
place_bet,
interpret_bet,
generate_players,
simulate_games,
FEASIBLE_MOVES,
Placement,
Player,
Strategy,
Placement,
FEASIBLE_MOVES,
expected,
generate_players,
init_bet,
interpret_bet,
place_bet,
simulate_games,
)
from random import choice, randint, seed
if __name__ == "__main__":
@ -62,9 +63,9 @@ if __name__ == "__main__":
# print(min_games, Player(200, simulate_random_strategy(min_num_games=min_games, total_budget=200)))
# create a list of random Placements
placements = [
Placement(randint(1, 10), 1, choice(list(FEASIBLE_MOVES))) for _ in range(10)
]
# placements = [
# Placement(randint(1, 10), 1, choice(list(FEASIBLE_MOVES))) for _ in range(10)
# ]
# strategy = Strategy.generate_random(50)
@ -77,7 +78,7 @@ if __name__ == "__main__":
# print(sum([p.value for p in placements]))
# # place the bets
# bet = place_bets(placements)
# bet = Strategy.place_bets(placements)
# print(bet)

View File

@ -1,9 +1,10 @@
from typing import List, Dict, Optional
from functools import reduce
from dataclasses import dataclass, field
from random import choice, randint
from statistics import stdev, mean
from __future__ import annotations
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
Bet = Dict[int, float]
@ -263,23 +264,6 @@ def combine_bets(bet_1: Bet, bet_2: Bet) -> 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
def place_bets(placements: List[Placement]) -> Bet:
"""
Places a list of bets on the wheel given a list of Placements.
Parameters
----------
placements : List[Placement]
A list of Placements to place on the wheel.
Returns
-------
Bet
A dictionary representing the bet.
"""
return reduce(
lambda bet, placement: combine_bets(bet, placement.place_bet()), placements, {}
)
@dataclass
@ -307,25 +291,42 @@ class Strategy:
return sum([p.value for p in self.placements])
@classmethod
def generate_random(cls, budget) -> "Strategy":
def generate_random(cls, budget: float, max_placements: int = 10) -> Strategy:
"""
Generates a random strategy.
Parameters
----------
budget : float
The amount of money to spend on the strategy.
max_placements : int, optional
The maximum number of placements to include in the strategy.
(default is 10)
Returns
-------
Strategy
A random strategy.
"""
placements = []
initial_budget = budget
num_placements = 0
max_placements = 10
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.
num = randint(1, min(budget // amt, 4))
# select random bet type
# todo: consider if this is the logic you want...
if randint(0, 1) == 0:
on = choice(list(FEASIBLE_MOVES))
else:
on = choice(list(SINGLE_BETS))
# 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:
# on = choice(list(SINGLE_BETS))
on = choice(
list(FEASIBLE_MOVES)
) # todo: make a parameter, allow for just single bets.
) # TODO: make a parameter, allow for just single bets.
placement = Placement(num, amt, on)
placements.append(placement)
budget -= placement.value
@ -338,7 +339,31 @@ class Strategy:
print(p)
def get_bet(self):
return place_bets(self.placements)
return self.place_bets(self.placements)
def get_placements(self):
return self.placements
@staticmethod
def place_bets(placements: List[Placement]) -> Bet:
"""
Places a list of bets on the wheel given a list of Placements.
Parameters
----------
placements : List[Placement]
A list of Placements to place on the wheel.
Returns
-------
Bet
A dictionary representing the bet.
"""
return reduce(
lambda bet, placement: combine_bets(bet, placement.place_bet()), placements, {}
)
@dataclass
@ -374,7 +399,24 @@ class Player:
return self.id < other.id
def simulate_random_strategy(min_num_games=1, total_budget=200):
def simulate_random_strategy(min_num_games=1, total_budget=200) -> Strategy:
"""
Simulates a random strategy based on the minimum number of games that
the player wants to play and the total budget that the player has.
Parameters
----------
min_num_games : int, optional
The minimum number of games that the player wants to play.
(default is 1)
total_budget : float, optional
The total budget that the player has.
(default is 200)
Returns
-------
"""
strategy_budget = total_budget // min_num_games
return Strategy.generate_random(strategy_budget)