some minor refactoring, documentation, todos
This commit is contained in:
parent
d08e362ecd
commit
7060fb3744
13
README.md
Normal file
13
README.md
Normal 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
25
app.py
@ -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)
|
||||
|
||||
|
106
roulette.py
106
roulette.py
@ -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)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user