From 6c16d2986b73fb37db8b4c48b5ec9ff2b5125f13 Mon Sep 17 00:00:00 2001 From: Michael Pilosov Date: Sat, 26 Nov 2022 22:38:46 -0700 Subject: [PATCH] reorder function definitions so dataclasses come first --- pyroulette/roulette.py | 274 ++++++++++++++++++++--------------------- setup.py | 2 +- 2 files changed, 138 insertions(+), 138 deletions(-) diff --git a/pyroulette/roulette.py b/pyroulette/roulette.py index 9b4e323..4912d5e 100644 --- a/pyroulette/roulette.py +++ b/pyroulette/roulette.py @@ -120,143 +120,6 @@ ALIASES = { CHIP_VALUES = {0.25, 0.5, 1, 5, 10, 25, 50, 100} -def expected(bet: Bet) -> float: - """ - Returns the expected value of a bet. - - Parameters - ---------- - bet : Bet - The bet to calculate the expected value of. - - Returns - ------- - float - The expected value of the bet. - """ - bets = list(bet.spread.values()) - cond_bets = filter(lambda x: x > 0, bets) - amt = sum(bets) - payout = amt * 36 / 38 - print( - 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 - - -def place_bet(bet: Bet, on: int, amount: float) -> Bet: - """ - Places a bet on a number. - - Parameters - ---------- - bet : Bet - The bet to place. - on : int - The number to bet on. - amount : float - The amount to bet. - - Returns - ------- - Bet - A dictionary representing the bet with the new bet placed. - """ - bet = bet.copy() - bet[on] += amount - return bet - - -def interpret_bet(on="red", amount=0, bet=Optional[Bet]) -> Bet: - """ - Interprets a bet and returns a dictionary representing the bet. - - Parameters - ---------- - on : str - The type of bet to place. - amount : float - The amount to bet. - bet : Bet - The bet to add to. - (default is None, which creates a new bet) - - Returns - ------- - Bet - A dictionary representing the bet. - """ - assert (on in FEASIBLE_MOVES) or ( - on in ALIASES - ), f"Bet `{on}` not understood. Choose from feasible moves:\n {FEASIBLE_MOVES}" - if bet is None: - bet = Bet() - else: - bet = bet.copy() - REDS = {1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36} - BLACKS = set(range(37)) - REDS - NUMS = {} - on = on.strip().replace(" ", "-") - div = 18 - if on in ("red", "reds"): - NUMS = REDS - if on in ("black", "blacks"): - NUMS = BLACKS - if on in ("odd", "odds"): - NUMS = {i for i in range(1, 37) if i % 2 == 0} - if on in ("even", "evens"): - NUMS = {i for i in range(1, 37) if i % 2} - if on in ("1-18", "first-18", "first-half"): - NUMS = set(range(1, 19)) - if on in ("19-36", "last-18", "last-half", "second-half", "second-18"): - NUMS = set(range(19, 37)) - if on in ("1-12", "13-24", "25-36"): - low, high = on.split("-") - NUMS = set(range(int(low), int(high) + 1)) - div = 12 - if on in ["triple-0", "triple-00"]: - NUMS = {0, 1, 2} if on == "triple-0" else {-1, 2, 3} - div = 3 - if not NUMS: - other_bet = on.split("-") - if other_bet[0] == "street": - street = int(other_bet[1]) - 1 - assert street in list(range(13)) - NUMS = {i for i in range(street + 1, street + 4)} - div = 3 - elif other_bet[0] == "col": - col = int(other_bet[1]) - 1 - assert col in list(range(0, 3)) - NUMS = {i for i in range(1, 37) if (i - 1) % 3 == col} - div = 12 - elif ( - other_bet[0] == "split" - ): # TODO: validate choices, for now we disallow these. - num_1, num_2 = int(other_bet[1]), int(other_bet[2]) - NUMS = {num_1, num_2} - div = 2 - elif other_bet[0] == "corner": - num_1, num_2 = int(other_bet[1]), int(other_bet[2]) - num_3, num_4 = int(other_bet[3]), int(other_bet[4]) - NUMS = {num_1, num_2, num_3, num_4} - div = 4 - else: - try: - NUMS = {int(on)} - div = 1 - except ValueError as e: - raise e( - 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) - - return bet - - @dataclass class Placement: """ @@ -454,6 +317,143 @@ class Player: return self.id < other.id +def expected(bet: Bet) -> float: + """ + Returns the expected value of a bet. + + Parameters + ---------- + bet : Bet + The bet to calculate the expected value of. + + Returns + ------- + float + The expected value of the bet. + """ + bets = list(bet.spread.values()) + cond_bets = filter(lambda x: x > 0, bets) + amt = sum(bets) + payout = amt * 36 / 38 + print( + 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 + + +def place_bet(bet: Bet, on: int, amount: float) -> Bet: + """ + Places a bet on a number. + + Parameters + ---------- + bet : Bet + The bet to place. + on : int + The number to bet on. + amount : float + The amount to bet. + + Returns + ------- + Bet + A dictionary representing the bet with the new bet placed. + """ + bet = bet.copy() + bet[on] += amount + return bet + + +def interpret_bet(on="red", amount=0, bet=Optional[Bet]) -> Bet: + """ + Interprets a bet and returns a dictionary representing the bet. + + Parameters + ---------- + on : str + The type of bet to place. + amount : float + The amount to bet. + bet : Bet + The bet to add to. + (default is None, which creates a new bet) + + Returns + ------- + Bet + A dictionary representing the bet. + """ + assert (on in FEASIBLE_MOVES) or ( + on in ALIASES + ), f"Bet `{on}` not understood. Choose from feasible moves:\n {FEASIBLE_MOVES}" + if bet is None: + bet = Bet() + else: + bet = bet.copy() + REDS = {1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36} + BLACKS = set(range(37)) - REDS + NUMS = {} + on = on.strip().replace(" ", "-") + div = 18 + if on in ("red", "reds"): + NUMS = REDS + if on in ("black", "blacks"): + NUMS = BLACKS + if on in ("odd", "odds"): + NUMS = {i for i in range(1, 37) if i % 2 == 0} + if on in ("even", "evens"): + NUMS = {i for i in range(1, 37) if i % 2} + if on in ("1-18", "first-18", "first-half"): + NUMS = set(range(1, 19)) + if on in ("19-36", "last-18", "last-half", "second-half", "second-18"): + NUMS = set(range(19, 37)) + if on in ("1-12", "13-24", "25-36"): + low, high = on.split("-") + NUMS = set(range(int(low), int(high) + 1)) + div = 12 + if on in ["triple-0", "triple-00"]: + NUMS = {0, 1, 2} if on == "triple-0" else {-1, 2, 3} + div = 3 + if not NUMS: + other_bet = on.split("-") + if other_bet[0] == "street": + street = int(other_bet[1]) - 1 + assert street in list(range(13)) + NUMS = {i for i in range(street + 1, street + 4)} + div = 3 + elif other_bet[0] == "col": + col = int(other_bet[1]) - 1 + assert col in list(range(0, 3)) + NUMS = {i for i in range(1, 37) if (i - 1) % 3 == col} + div = 12 + elif ( + other_bet[0] == "split" + ): # TODO: validate choices, for now we disallow these. + num_1, num_2 = int(other_bet[1]), int(other_bet[2]) + NUMS = {num_1, num_2} + div = 2 + elif other_bet[0] == "corner": + num_1, num_2 = int(other_bet[1]), int(other_bet[2]) + num_3, num_4 = int(other_bet[3]), int(other_bet[4]) + NUMS = {num_1, num_2, num_3, num_4} + div = 4 + else: + try: + NUMS = {int(on)} + div = 1 + except ValueError as e: + raise e( + 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) + + return bet + + def simulate_random_strategy(min_num_games=1, total_budget=200) -> Strategy: """ Simulates a random strategy based on the minimum number of games that diff --git a/setup.py b/setup.py index 8f9a5eb..de42992 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ with open(BASEDIR.joinpath("README.md"), "r") as fp: setup( name="pyroulette", - version="0.0.1rc4", + version="0.0.1rc5", description="A package for exploring roulette strategies.", long_description=LONG_DESCRIPTION, long_description_content_type="text/markdown",