From 41c8d2fb79d029e1d9dd9c2877b2148f02a07ee8 Mon Sep 17 00:00:00 2001 From: Brian Le Date: Thu, 18 Jan 2024 15:45:25 -0500 Subject: [PATCH 01/15] Finished setup and pair & flush detection --- .gitignore | 1 + python_skeleton/player.py | 1 + .../skeleton/probability_engine.py | 241 ++++++++++++++++++ research.ipynb | 2 +- 4 files changed, 244 insertions(+), 1 deletion(-) create mode 100644 python_skeleton/skeleton/probability_engine.py diff --git a/.gitignore b/.gitignore index b4fb085..0701b75 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ __pycache__/ A.txt B.txt gamelog.txt +game_log_analyze.txt *.class .DS_Store .idea/ diff --git a/python_skeleton/player.py b/python_skeleton/player.py index 6882149..51dea52 100644 --- a/python_skeleton/player.py +++ b/python_skeleton/player.py @@ -9,6 +9,7 @@ import helper import random import eval7 +import probability_engine class Player(Bot): diff --git a/python_skeleton/skeleton/probability_engine.py b/python_skeleton/skeleton/probability_engine.py new file mode 100644 index 0000000..a06600e --- /dev/null +++ b/python_skeleton/skeleton/probability_engine.py @@ -0,0 +1,241 @@ +import eval7 + +def calculate_win_probability(my_cards, round_state, iters): + ''' + Calculates win probability given hand. + Considers currently revealed cards, + potential strong hands (outs), + and monte carlo sim. + + Arguments: + my_cards: The 2-3 cards in your hand + round_state: Round object, used to get street cards + iters: iterations for the monte carlo sim + + Returns: + winrate: % chance of winning with current hand and street cards + ''' + + # Set up our deck + deck = eval7.Deck() + my_cards = [eval7.Card(card) for card in my_cards] + + if round_state.street == 3: + board_cards = [eval7.Card(card) for card in round_state.deck[:3]] + else: + board_cards = [eval7.Card(card) for card in round_state.deck[:4]] + + total_cards = my_cards + board_cards + + for card in total_cards: + deck.cards.remove(card) + + # Calculates current handtype + hand_type = eval7.handtype(eval7.evaluate(my_cards + board_cards)) + + # Estimated winrate based on handtype + hand_strengths = { + 'Straight Flush': 1.0, + 'Quads': 0.99, + 'Full House': 0.98, + 'Flush': 0.97, + 'Straight': 0.96, + 'Trips': 0.9, + 'Two Pair': 0.8, + 'Pair': 0.6, + 'High Card': 0.5, + } + + # Scales winrate based on number of hand cards that come from hole + hole_factors = [0.5, 0.9, 1, 1.2] + + # Calculates winrate with currently revealed cards + base_probability = hand_strengths[hand_type] * hole_factors[base_hole_cards_used(my_cards, board_cards, hand_type)] + + # Calculates potential hands and probability of hitting them (post-flop) + # Based on the most likely hands, calculate a scaled winrate given we hit + if hand_type in {'Straight Flush', 'Quads', 'Full House', 'Flush', 'Straight'}: + return base_probability # want to check for board wetness? + elif hand_type == 'Trips': + # detect flush, full house, quads + pass + elif hand_type == 'Two Pair': + # detect flush, full house + pass + elif hand_type == 'Pair': + # detect two pair, trips, straight, flush, full house, quads?, straight flush + pass + elif hand_type == 'High Card': + # detect pair, twopair, flush, straight, straight flush + pass + + # Potential probability should be a function of the probability of winning given we hit + # scaled by chance of hitting scaled by hole card usage? + # Combine base and potential probabilities and return a winrate (factor in Monte Carlo Sim prob?) + # Probably only want to run certain calculations on certain rounds + # If the board is wet but not for us, win probability should be low + # sim_probability = monte_carlo_flop_and_turn(my_cards, board_cards, deck, iters) + +def base_hole_cards_used(my_cards, board_cards, hand_type): + ''' + Calculate how many hole cards contribute to the current hand type. + + Arguments: + my_cards: cards in hole + board_cards: cards on board + hand_type: best hand given current cards + + Returns: + hole_cards_used + ''' + + # Counts how many hole cards were used to get that handtype + hole_cards_used = 0 + for _ in range(len(my_cards)): + removed_card = my_cards.pop(0) + if eval7.handtype(eval7.evaluate(my_cards + board_cards)) != hand_type: + hole_cards_used += 1 + my_cards.append(removed_card) + + return hole_cards_used + +def detect_flush(my_cards, board_cards): + ''' + Returns chance of hitting a flush as well as how many come from hole cards. + ''' + # Counts revealed suits + suits = { + 's': 0, + 'd': 0, + 'h': 0, + 'c': 0 + } + + total_cards = my_cards + board_cards + for card in total_cards: + card = str(card) + suits[card[1]] += 1 + + highest_quantity = max(suits.values()) + + # Run post-flop, so if only 2 of the same suit, flush not possible + if highest_quantity <= 2: + return (0, 0) + + # Counts how many of the max suits come from the hole cards + max_suits = {suit:0 for suit, quantity in suits.items() if quantity == highest_quantity} + for card in my_cards: + card = str(card) + if card[1] in max_suits: + max_suits[card[1]] += 1 + + # Grabs the max suit that pulls the most from the hole cards + max_suit = max(max_suits.items(), key=lambda x: x[1]) + + # Calculates chances of hitting the flush + hit_rate = 0 + if highest_quantity == 3: + if len(board_cards) == 3: + hit_rate = 1/16 + return (0, 0) + elif highest_quantity == 4: + if len(board_cards) == 3: + hit_rate = 7/16 + elif len(board_cards) == 4: + hit_rate = 1/4 + return (0, 0) + elif highest_quantity >= 5: + hit_rate = 1 + + + # Returns hitrate and number of cards coming from hole cards + # Cannot hit a flush if none come from hole cards + if max_suit[1] == 0: + return(0, 0) + return (hit_rate, max_suit[1]) + +def detect_quads(my_cards, board_cards): + ''' + Returns chance of hitting quads as well as how many comes from hole cards. + ''' + pass + +def detect_straight(my_cards, board_cards): + ''' + Returns chance of hitting straight as well as how many comes from hole cards. + ''' + pass + +def detect_full_house(my_cards, board_cards): + ''' + Returns chance of hitting full house as well as how many comes from hole cards. + ''' + pass + +def detect_straight_flush(my_cards, board_cards): + ''' + Returns chance of hitting straight flush as well as how many comes from hole cards. + ''' + pass + +def detect_trips(my_cards, board_cards): + ''' + Returns chance of hitting trips as well as how many comes from hole cards. + ''' + pass + +def detect_two_pair(my_cards, board_cards): + ''' + Returns chance of hitting two pair as well as how many comes from hole cards. + ''' + pass + +def detect_pair(my_cards, board_cards): + ''' + Returns chance of hitting pair as well as how many comes from hole cards. + ''' + remaining_cards = 52 - 5 - len(board_cards) + cards_to_hit = len(my_cards) * 3 + chances_left = 5 - len(board_cards) + hit_rate = 1 - ((remaining_cards - cards_to_hit) / remaining_cards) ** chances_left + return (hit_rate, 1) + +def monte_carlo_flop_and_turn(my_cards, board_cards, deck, iters): + ''' + Runs a monte carlo simulation for your current hand on the turn + (4 cards revealed on the board) + We are simulating the opponent cards + final board card + + Arguments: + my_cards: The 2-3 cards in your hand + + Returns: + winrate: % chance of winning with current hand and street cards + ''' + win_count = 0.0 + + for i in range(iters): + # Set up game state + deck.shuffle() + opp_num = 3 if len(my_cards) == 2 else 2 + draw = deck.peek(opp_num + (5 - len(board_cards))) + opp_cards = draw[:opp_num] + community_cards = draw[opp_num:] + + my_hand = my_cards + community_cards + board_cards + opp_hand = opp_cards + community_cards + board_cards + + our_hand_eval = eval7.evaluate(my_hand) + opp_hand_eval = eval7.evaluate(opp_hand) + + if our_hand_eval > opp_hand_eval: + # We win the round + win_count += 1 + elif our_hand_eval == opp_hand_eval: + # We tie this round + win_count += 0.5 + else: + # We lose this round + win_count += 0 + + return win_count/iters \ No newline at end of file diff --git a/research.ipynb b/research.ipynb index 7338507..c7f5f5e 100644 --- a/research.ipynb +++ b/research.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ From af57c3866a44ea4ea13a797b8aa237eed5746bbe Mon Sep 17 00:00:00 2001 From: Brian Le Date: Thu, 18 Jan 2024 17:19:19 -0500 Subject: [PATCH 02/15] Finished straight detection --- .../skeleton/probability_engine.py | 61 ++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/python_skeleton/skeleton/probability_engine.py b/python_skeleton/skeleton/probability_engine.py index a06600e..4bcc072 100644 --- a/python_skeleton/skeleton/probability_engine.py +++ b/python_skeleton/skeleton/probability_engine.py @@ -164,7 +164,66 @@ def detect_straight(my_cards, board_cards): ''' Returns chance of hitting straight as well as how many comes from hole cards. ''' - pass + # Process revealed cards + revealed_cards = {} + for card in my_cards + board_cards: + revealed_cards.add(str(card)[0]) + + needed_cards = '' + for card in 'AKQJT98765432': + if card in revealed_cards: + needed_cards += card + else: + needed_cards += 'x' + + # Detect closest potential straight substring + closest_straights = [] + min_to_hit = 5 + + for i in range(0, 9): + current_to_hit = 0 + for j in range(5): + if needed_cards[i + j] == 'x': + current_to_hit += 1 + if current_to_hit < min_to_hit: + min_to_hit = current_to_hit + closest_straights = [needed_cards[i:i+5]] + elif current_to_hit == min_to_hit: + closest_straights.append(needed_cards[i:i+5]) + + # Detect number of hole cards used in potential straight + hole_cards = '' + for card in my_cards: + hole_cards += str(card)[0] + + potential_straights = [] + for straight in closest_straights: + hole_cards_used = 0 + for card in hole_cards: + if card in straight: + hole_cards_used += 1 + if hole_cards_used != 0: + potential_straights.append((straight, hole_cards_used)) + + # Calculate hitrate for potential straight + if potential_straights == []: + return (0, 0) + + chances_left = 5 - len(board_cards) + + if chances_left < min_to_hit: + return (0, 0) + + cards_left = 52 - 5 - len(board_cards) + outs = len(potential_straights) + + hit_rate = 0 + if min_to_hit == 1: + hit_rate = 1 - ((cards_left - outs) / cards_left) ** chances_left + elif min_to_hit == 2: + hit_rate = 2 * outs / (cards_left ** 2) + + return (hit_rate, max(potential_straights, key=lambda x: x[1])) def detect_full_house(my_cards, board_cards): ''' From 031129e03c64a7ab5ad74542558de5333ad2a24e Mon Sep 17 00:00:00 2001 From: Brian Le Date: Thu, 18 Jan 2024 17:50:30 -0500 Subject: [PATCH 03/15] Finished two-pair detection and fixed bug with outs calculation in straight detection --- .../skeleton/probability_engine.py | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/python_skeleton/skeleton/probability_engine.py b/python_skeleton/skeleton/probability_engine.py index 4bcc072..a2d76ee 100644 --- a/python_skeleton/skeleton/probability_engine.py +++ b/python_skeleton/skeleton/probability_engine.py @@ -66,7 +66,7 @@ def calculate_win_probability(my_cards, round_state, iters): # detect two pair, trips, straight, flush, full house, quads?, straight flush pass elif hand_type == 'High Card': - # detect pair, twopair, flush, straight, straight flush + # detect pair, two pair, flush, straight, straight flush pass # Potential probability should be a function of the probability of winning given we hit @@ -219,9 +219,9 @@ def detect_straight(my_cards, board_cards): hit_rate = 0 if min_to_hit == 1: - hit_rate = 1 - ((cards_left - outs) / cards_left) ** chances_left + hit_rate = 1 - ((cards_left - (outs * 4)) / cards_left) ** chances_left elif min_to_hit == 2: - hit_rate = 2 * outs / (cards_left ** 2) + hit_rate = 2 * (outs * 16) / (cards_left ** 2) return (hit_rate, max(potential_straights, key=lambda x: x[1])) @@ -247,7 +247,33 @@ def detect_two_pair(my_cards, board_cards): ''' Returns chance of hitting two pair as well as how many comes from hole cards. ''' - pass + if eval7.handtype(eval7.evaluate(my_cards + board_cards)) == 'Pair': + hole_cards_used = base_hole_cards_used(my_cards, board_cards, 'Pair') + + cards_left = 52 - 5 - len(board_cards) + chances_left = 5 - len(board_cards) + + if hole_cards_used == 0: + outs = len(my_cards) * 3 + elif hole_cards_used == 1: + outs = (len(my_cards) - 1 + len(board_cards) - 1) * 3 + else: # hole_cards_used == 2 + outs = (len(my_cards) - 2 + len(board_cards)) * 3 + + hit_rate = 1 - ((cards_left - outs) / cards_left) ** chances_left + + return (hit_rate, max(1, hole_cards_used)) + else: # High Card + if len(board_cards) > 3: + return (0, 0) + + cards_left = 52 - 5 - len(board_cards) + my_cards = len(my_cards) + board_cards = len(board_cards) + + hit_rate = ((my_cards * 3) * ((my_cards - 1 + board_cards) * 3)) + ((board_cards * 3) * (my_cards * 3)) / (cards_left ** 2) + + return (hit_rate, 1) def detect_pair(my_cards, board_cards): ''' From 8fc363714ed05c860abb0d9e834d36ffb654fd4b Mon Sep 17 00:00:00 2001 From: Brian Le Date: Thu, 18 Jan 2024 18:40:54 -0500 Subject: [PATCH 04/15] Finished full house detection --- .../skeleton/probability_engine.py | 115 ++++++++++++++---- 1 file changed, 88 insertions(+), 27 deletions(-) diff --git a/python_skeleton/skeleton/probability_engine.py b/python_skeleton/skeleton/probability_engine.py index a2d76ee..0bba584 100644 --- a/python_skeleton/skeleton/probability_engine.py +++ b/python_skeleton/skeleton/probability_engine.py @@ -60,7 +60,7 @@ def calculate_win_probability(my_cards, round_state, iters): # detect flush, full house, quads pass elif hand_type == 'Two Pair': - # detect flush, full house + # detect flush, full house, quads? pass elif hand_type == 'Pair': # detect two pair, trips, straight, flush, full house, quads?, straight flush @@ -154,12 +154,6 @@ def detect_flush(my_cards, board_cards): return(0, 0) return (hit_rate, max_suit[1]) -def detect_quads(my_cards, board_cards): - ''' - Returns chance of hitting quads as well as how many comes from hole cards. - ''' - pass - def detect_straight(my_cards, board_cards): ''' Returns chance of hitting straight as well as how many comes from hole cards. @@ -225,29 +219,11 @@ def detect_straight(my_cards, board_cards): return (hit_rate, max(potential_straights, key=lambda x: x[1])) -def detect_full_house(my_cards, board_cards): - ''' - Returns chance of hitting full house as well as how many comes from hole cards. - ''' - pass - -def detect_straight_flush(my_cards, board_cards): - ''' - Returns chance of hitting straight flush as well as how many comes from hole cards. - ''' - pass - -def detect_trips(my_cards, board_cards): - ''' - Returns chance of hitting trips as well as how many comes from hole cards. - ''' - pass - -def detect_two_pair(my_cards, board_cards): +def detect_two_pair(my_cards, board_cards, hand_type): ''' Returns chance of hitting two pair as well as how many comes from hole cards. ''' - if eval7.handtype(eval7.evaluate(my_cards + board_cards)) == 'Pair': + if hand_type == 'Pair': hole_cards_used = base_hole_cards_used(my_cards, board_cards, 'Pair') cards_left = 52 - 5 - len(board_cards) @@ -285,6 +261,91 @@ def detect_pair(my_cards, board_cards): hit_rate = 1 - ((remaining_cards - cards_to_hit) / remaining_cards) ** chances_left return (hit_rate, 1) +def detect_full_house(my_cards, board_cards, hand_type): + ''' + Returns chance of hitting full house as well as how many comes from hole cards. + ''' + if hand_type == 'Trips': + + hole_cards_used = base_hole_cards_used(my_cards, board_cards, 'Trips') + remaining_cards = 52 - 5 - len(board_cards) + chances_left = 5 - len(board_cards) + my_cards = len(my_cards) + board_cards = len(board_cards) + + + if hole_cards_used == 0: + outs = my_cards * 3 + elif hole_cards_used == 1: + outs = (my_cards - 1 + board_cards - 2) * 3 + elif hole_cards_used == 2: + outs = (my_cards - 2 + board_cards - 1) * 3 + else: # 3 + outs = board_cards * 3 + + hit_rate = 1 - ((remaining_cards - outs) / remaining_cards) ** chances_left + + return (hit_rate, hole_cards_used) + + elif hand_type == 'Two Pair': + + hole_cards_used = base_hole_cards_used(my_cards, board_cards, 'Two Pair') + remaining_cards = 52 - 5 - len(board_cards) + chances_left = 5 - len(board_cards) + my_cards = len(my_cards) + board_cards = len(board_cards) + + if hole_cards_used == 0: + return (0, 0) + else: + if chances_left == 2: + hit_rate = (my_cards - 1 * 6) + (4 * remaining_cards * 2)/ remaining_cards ** 2 + else: # 1 + outs = 4 + hit_rate = 1 - ((remaining_cards - outs) / remaining_cards) + return (hit_rate, hole_cards_used) + + else: # Pair + + hole_cards_used = base_hole_cards_used(my_cards, board_cards, 'Pair') + remaining_cards = 52 - 5 - len(board_cards) + chances_left = 5 - len(board_cards) + my_cards = len(my_cards) + board_cards = len(board_cards) + + if hole_cards_used == 0: + if chances_left == 2: + # need to hit one pair and one hole card or two of the same hole card + hit_rate = (2 * my_cards * 3 * 2) + (my_cards * 3 * 2) / remaining_cards ** 2 + else: # 1 + return (0, 0) + else: + if chances_left == 2: + # need to hit one pair and any card or two of the same card + hit_rate = (2 * (my_cards - 1 + board_cards - 1) * 3 * 2) + ((my_cards - 1 + board_cards - 1) * 3 * 2) / remaining_cards ** 2 + else: # 1 + return (0, 0) + + return (hit_rate, hole_cards_used) + +def detect_straight_flush(my_cards, board_cards): + ''' + Returns chance of hitting straight flush as well as how many comes from hole cards. + ''' + pass + +def detect_quads(my_cards, board_cards): + ''' + Returns chance of hitting quads as well as how many comes from hole cards. + ''' + pass + +def detect_trips(my_cards, board_cards): + ''' + Returns chance of hitting trips as well as how many comes from hole cards. + ''' + pass + def monte_carlo_flop_and_turn(my_cards, board_cards, deck, iters): ''' Runs a monte carlo simulation for your current hand on the turn From 5bfe1bb1a8ff4a028df49020b7b139c0078b3bc8 Mon Sep 17 00:00:00 2001 From: Brian Le Date: Thu, 18 Jan 2024 18:58:10 -0500 Subject: [PATCH 05/15] Finished quads and trips detection and started straight flush detection --- .../skeleton/probability_engine.py | 166 ++++++++++++++++-- research.ipynb | 18 +- 2 files changed, 171 insertions(+), 13 deletions(-) diff --git a/python_skeleton/skeleton/probability_engine.py b/python_skeleton/skeleton/probability_engine.py index 0bba584..59e7d78 100644 --- a/python_skeleton/skeleton/probability_engine.py +++ b/python_skeleton/skeleton/probability_engine.py @@ -63,12 +63,13 @@ def calculate_win_probability(my_cards, round_state, iters): # detect flush, full house, quads? pass elif hand_type == 'Pair': - # detect two pair, trips, straight, flush, full house, quads?, straight flush + # detect two pair, trips, straight, flush, full house, quads? pass elif hand_type == 'High Card': - # detect pair, two pair, flush, straight, straight flush + # detect pair, two pair, flush, straight pass + # straight flush can just be flush and straight detection and if both are high we probably have a potential straight flush??? # Potential probability should be a function of the probability of winning given we hit # scaled by chance of hitting scaled by hole card usage? # Combine base and potential probabilities and return a winrate (factor in Monte Carlo Sim prob?) @@ -327,24 +328,169 @@ def detect_full_house(my_cards, board_cards, hand_type): return (0, 0) return (hit_rate, hole_cards_used) - + def detect_straight_flush(my_cards, board_cards): ''' Returns chance of hitting straight flush as well as how many comes from hole cards. + Basically uses detect_straight logic then checks for flush on the most probable straights ''' - pass + # Process revealed cards + revealed_cards = {} + for card in my_cards + board_cards: + revealed_cards.add(str(card)[0]) + + needed_cards = '' + for card in 'AKQJT98765432': + if card in revealed_cards: + needed_cards += card + else: + needed_cards += 'x' + + # Detect closest potential straight substring + closest_straights = [] + min_to_hit = 5 + + for i in range(0, 9): + current_to_hit = 0 + for j in range(5): + if needed_cards[i + j] == 'x': + current_to_hit += 1 + if current_to_hit < min_to_hit: + min_to_hit = current_to_hit + closest_straights = [needed_cards[i:i+5]] + elif current_to_hit == min_to_hit: + closest_straights.append(needed_cards[i:i+5]) + + # Detect number of hole cards used in potential straight + hole_cards = '' + for card in my_cards: + hole_cards += str(card)[0] + + potential_straights = [] + for straight in closest_straights: + hole_cards_used = 0 + for card in hole_cards: + if card in straight: + hole_cards_used += 1 + if hole_cards_used != 0: + potential_straights.append((straight, hole_cards_used)) + + # Calculate hitrate for potential straight + # TODO flush detection on potential straights + if potential_straights == []: + return (0, 0) + + chances_left = 5 - len(board_cards) + + if chances_left < min_to_hit: + return (0, 0) + + cards_left = 52 - 5 - len(board_cards) + outs = len(potential_straights) + + hit_rate = 0 + if min_to_hit == 1: + hit_rate = 1 - ((cards_left - (outs * 4)) / cards_left) ** chances_left + elif min_to_hit == 2: + hit_rate = 2 * (outs * 16) / (cards_left ** 2) + + return (hit_rate, max(potential_straights, key=lambda x: x[1])) -def detect_quads(my_cards, board_cards): - ''' - Returns chance of hitting quads as well as how many comes from hole cards. - ''' - pass def detect_trips(my_cards, board_cards): ''' Returns chance of hitting trips as well as how many comes from hole cards. ''' - pass + # Counts ranks of revealed cards + ranks = {'A': 0, 'K': 0, 'Q': 0, 'J': 0, 'T': 0, '9': 0, '8': 0, '7': 0, '6': 0, '5': 0, '4': 0, '3': 0, '2': 0, '1': 0} + + total_cards = my_cards + board_cards + for card in total_cards: + card = str(card) + ranks[card[1]] += 1 + + highest_quantity = max(ranks.values()) + + # Counts how many of the max ranks come from the hole cards + max_ranks = {rank:0 for rank, quantity in ranks.items() if quantity == highest_quantity} + for card in my_cards: + card = str(card) + if card[0] in max_ranks: + max_ranks[card[0]] += 1 + + # Grabs the max rank that pulls the most from the hole cards + max_rank = max(max_ranks.items(), key=lambda x: x[1]) + + # Calculates the chance of getting a trip + remaining_cards = 52 - 5 - len(board_cards) + if highest_quantity == 1: + if len(board_cards) == 3: + hit_rate = 1 - ((remaining_cards - 2) / remaining_cards) ** 2 + return (0,0) + elif highest_quantity == 2: + if len(board_cards) == 3: + hit_rate = 1 - ((remaining_cards - 1) / remaining_cards) ** 2 + elif len(board_cards) == 4: + hit_rate = 1 - ((remaining_cards - 1) / remaining_cards) + return (0,0) + elif highest_quantity >= 3: + hit_rate = 1 + + # Return the chance of hitting a trip and number of hole cards used + # If no hole cards were used then no trip occur + if max_rank[1] == 0: + return (0,0) + else: + return (hit_rate, max_rank[1]) + +def detect_quads(my_cards, board_cards): + ''' + Returns chance of hitting quads as well as how many comes from hole cards. + ''' + # Counts ranks of revealed cards + ranks = {'A': 0, 'K': 0, 'Q': 0, 'J': 0, 'T': 0, '9': 0, '8': 0, '7': 0, '6': 0, '5': 0, '4': 0, '3': 0, '2': 0, '1': 0} + + total_cards = my_cards + board_cards + for card in total_cards: + card = str(card) + ranks[card[1]] += 1 + + highest_quantity = max(ranks.values()) + + # Runs post-flop, so if only 1 then no quad can occur + if highest_quantity == 1: + return (0,0) + + # Counts how many of the max ranks come from the hole cards + max_ranks = {rank:0 for rank, quantity in ranks.items() if quantity == highest_quantity} + for card in my_cards: + card = str(card) + if card[0] in max_ranks: + max_ranks[card[0]] += 1 + + # Grabs the max rank that pulls the most from the hole cards + max_rank = max(max_ranks.items(), key=lambda x: x[1]) + + # Calculates the chance of getting a quad + remaining_cards = 52 - 5 - len(board_cards) + if highest_quantity == 2: + if len(board_cards) == 3: + hit_rate = 1 - ((remaining_cards - 2) / remaining_cards) ** 2 + return (0,0) + elif highest_quantity == 3: + if len(board_cards) == 3: + hit_rate = 1 - ((remaining_cards - 1) / remaining_cards) ** 2 + elif len(board_cards) == 4: + hit_rate = 1 - ((remaining_cards - 1) / remaining_cards) + elif highest_quantity >= 4: + hit_rate = 1 + + # Return the chance of hitting a trip and number of hole cards used + # If no hole cards were used then no trip occur + if max_rank[1] == 0: + return (0,0) + else: + return (hit_rate, max_rank[1]) def monte_carlo_flop_and_turn(my_cards, board_cards, deck, iters): ''' diff --git a/research.ipynb b/research.ipynb index c7f5f5e..98a99ec 100644 --- a/research.ipynb +++ b/research.ipynb @@ -4,14 +4,26 @@ "cell_type": "code", "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "('a', 2)\n" + ] + } + ], "source": [ - "import eval7" + "import eval7\n", + "\n", + "a = {'a': 2}\n", + "\n", + "print(max(a.items(), key=lambda x: x[1]))" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ From e149f112ed9abadb9336234fba1f805f7172901a Mon Sep 17 00:00:00 2001 From: Brian Le Date: Tue, 23 Jan 2024 15:10:37 -0500 Subject: [PATCH 06/15] Framework for unit tests --- .../skeleton/probability_engine.py | 1046 +++++++++-------- .../monte_carlo_tests.py | 1 + .../probability_engine_tests/unit_tests.py | 187 +++ 3 files changed, 738 insertions(+), 496 deletions(-) create mode 100644 python_skeleton/skeleton/probability_engine_tests/monte_carlo_tests.py create mode 100644 python_skeleton/skeleton/probability_engine_tests/unit_tests.py diff --git a/python_skeleton/skeleton/probability_engine.py b/python_skeleton/skeleton/probability_engine.py index 59e7d78..a810229 100644 --- a/python_skeleton/skeleton/probability_engine.py +++ b/python_skeleton/skeleton/probability_engine.py @@ -1,533 +1,587 @@ import eval7 -def calculate_win_probability(my_cards, round_state, iters): - ''' - Calculates win probability given hand. - Considers currently revealed cards, - potential strong hands (outs), - and monte carlo sim. - - Arguments: - my_cards: The 2-3 cards in your hand - round_state: Round object, used to get street cards - iters: iterations for the monte carlo sim - - Returns: - winrate: % chance of winning with current hand and street cards - ''' - - # Set up our deck - deck = eval7.Deck() - my_cards = [eval7.Card(card) for card in my_cards] - - if round_state.street == 3: - board_cards = [eval7.Card(card) for card in round_state.deck[:3]] - else: - board_cards = [eval7.Card(card) for card in round_state.deck[:4]] - - total_cards = my_cards + board_cards - - for card in total_cards: - deck.cards.remove(card) - - # Calculates current handtype - hand_type = eval7.handtype(eval7.evaluate(my_cards + board_cards)) - - # Estimated winrate based on handtype - hand_strengths = { - 'Straight Flush': 1.0, - 'Quads': 0.99, - 'Full House': 0.98, - 'Flush': 0.97, - 'Straight': 0.96, - 'Trips': 0.9, - 'Two Pair': 0.8, - 'Pair': 0.6, - 'High Card': 0.5, - } - - # Scales winrate based on number of hand cards that come from hole - hole_factors = [0.5, 0.9, 1, 1.2] - - # Calculates winrate with currently revealed cards - base_probability = hand_strengths[hand_type] * hole_factors[base_hole_cards_used(my_cards, board_cards, hand_type)] - - # Calculates potential hands and probability of hitting them (post-flop) - # Based on the most likely hands, calculate a scaled winrate given we hit - if hand_type in {'Straight Flush', 'Quads', 'Full House', 'Flush', 'Straight'}: - return base_probability # want to check for board wetness? - elif hand_type == 'Trips': - # detect flush, full house, quads - pass - elif hand_type == 'Two Pair': - # detect flush, full house, quads? - pass - elif hand_type == 'Pair': - # detect two pair, trips, straight, flush, full house, quads? - pass - elif hand_type == 'High Card': - # detect pair, two pair, flush, straight +class Probability_Engine(): + def __init__(self): pass - # straight flush can just be flush and straight detection and if both are high we probably have a potential straight flush??? - # Potential probability should be a function of the probability of winning given we hit - # scaled by chance of hitting scaled by hole card usage? - # Combine base and potential probabilities and return a winrate (factor in Monte Carlo Sim prob?) - # Probably only want to run certain calculations on certain rounds - # If the board is wet but not for us, win probability should be low - # sim_probability = monte_carlo_flop_and_turn(my_cards, board_cards, deck, iters) - -def base_hole_cards_used(my_cards, board_cards, hand_type): - ''' - Calculate how many hole cards contribute to the current hand type. - - Arguments: - my_cards: cards in hole - board_cards: cards on board - hand_type: best hand given current cards - - Returns: - hole_cards_used - ''' - - # Counts how many hole cards were used to get that handtype - hole_cards_used = 0 - for _ in range(len(my_cards)): - removed_card = my_cards.pop(0) - if eval7.handtype(eval7.evaluate(my_cards + board_cards)) != hand_type: - hole_cards_used += 1 - my_cards.append(removed_card) - - return hole_cards_used - -def detect_flush(my_cards, board_cards): - ''' - Returns chance of hitting a flush as well as how many come from hole cards. - ''' - # Counts revealed suits - suits = { - 's': 0, - 'd': 0, - 'h': 0, - 'c': 0 - } - - total_cards = my_cards + board_cards - for card in total_cards: - card = str(card) - suits[card[1]] += 1 - - highest_quantity = max(suits.values()) - - # Run post-flop, so if only 2 of the same suit, flush not possible - if highest_quantity <= 2: - return (0, 0) - - # Counts how many of the max suits come from the hole cards - max_suits = {suit:0 for suit, quantity in suits.items() if quantity == highest_quantity} - for card in my_cards: - card = str(card) - if card[1] in max_suits: - max_suits[card[1]] += 1 - - # Grabs the max suit that pulls the most from the hole cards - max_suit = max(max_suits.items(), key=lambda x: x[1]) - - # Calculates chances of hitting the flush - hit_rate = 0 - if highest_quantity == 3: - if len(board_cards) == 3: - hit_rate = 1/16 - return (0, 0) - elif highest_quantity == 4: - if len(board_cards) == 3: - hit_rate = 7/16 - elif len(board_cards) == 4: - hit_rate = 1/4 - return (0, 0) - elif highest_quantity >= 5: - hit_rate = 1 - - - # Returns hitrate and number of cards coming from hole cards - # Cannot hit a flush if none come from hole cards - if max_suit[1] == 0: - return(0, 0) - return (hit_rate, max_suit[1]) - -def detect_straight(my_cards, board_cards): - ''' - Returns chance of hitting straight as well as how many comes from hole cards. - ''' - # Process revealed cards - revealed_cards = {} - for card in my_cards + board_cards: - revealed_cards.add(str(card)[0]) - - needed_cards = '' - for card in 'AKQJT98765432': - if card in revealed_cards: - needed_cards += card - else: - needed_cards += 'x' - - # Detect closest potential straight substring - closest_straights = [] - min_to_hit = 5 - - for i in range(0, 9): - current_to_hit = 0 - for j in range(5): - if needed_cards[i + j] == 'x': - current_to_hit += 1 - if current_to_hit < min_to_hit: - min_to_hit = current_to_hit - closest_straights = [needed_cards[i:i+5]] - elif current_to_hit == min_to_hit: - closest_straights.append(needed_cards[i:i+5]) - - # Detect number of hole cards used in potential straight - hole_cards = '' - for card in my_cards: - hole_cards += str(card)[0] - - potential_straights = [] - for straight in closest_straights: - hole_cards_used = 0 - for card in hole_cards: - if card in straight: - hole_cards_used += 1 - if hole_cards_used != 0: - potential_straights.append((straight, hole_cards_used)) - - # Calculate hitrate for potential straight - if potential_straights == []: - return (0, 0) + def calculate_win_probability(self, my_cards, round_state): + ''' + Calculates win probability given hand. + Considers currently revealed cards, + potential strong hands (outs), + and monte carlo sim. - chances_left = 5 - len(board_cards) + Arguments: + my_cards: The 2-3 cards in your hand + round_state: Round object, used to get street cards + iters: iterations for the monte carlo sim - if chances_left < min_to_hit: - return (0, 0) - - cards_left = 52 - 5 - len(board_cards) - outs = len(potential_straights) + Returns: + winrate: % chance of winning with current hand and street cards + ''' - hit_rate = 0 - if min_to_hit == 1: - hit_rate = 1 - ((cards_left - (outs * 4)) / cards_left) ** chances_left - elif min_to_hit == 2: - hit_rate = 2 * (outs * 16) / (cards_left ** 2) + # Set up our deck + deck = eval7.Deck() + my_cards = [eval7.Card(card) for card in my_cards] - return (hit_rate, max(potential_straights, key=lambda x: x[1])) + if round_state.street == 3: + board_cards = [eval7.Card(card) for card in round_state.deck[:3]] + else: + board_cards = [eval7.Card(card) for card in round_state.deck[:4]] + + total_cards = my_cards + board_cards + + for card in total_cards: + deck.cards.remove(card) + + # Calculates current handtype + hand_type = eval7.handtype(eval7.evaluate(my_cards + board_cards)) + + # Estimated winrate based on handtype + hand_strengths = { + 'Straight Flush': 1.0, + 'Quads': 0.99, + 'Full House': 0.98, + 'Flush': 0.97, + 'Straight': 0.96, + 'Trips': 0.9, + 'Two Pair': 0.8, + 'Pair': 0.6, + 'High Card': 0.5, + } + + # Scales winrate based on number of hand cards that come from hole + hole_factors = [0.5, 0.9, 1, 1.2] + + # Calculates winrate with currently revealed cards + base_probability = hand_strengths[hand_type] * hole_factors[self.base_hole_cards_used(my_cards, board_cards, hand_type)] + + # Calculates potential hands and probability of hitting them (post-flop) + # Based on the most likely hands, calculate a scaled winrate given we hit + if hand_type in {'Straight Flush', 'Quads', 'Full House', 'Flush', 'Straight'}: + return base_probability # want to check for board wetness? + elif hand_type == 'Trips': + # detect flush, full house, quads + flush_odds = self.detect_flush(my_cards, board_cards) + full_house_odds = self.detect_full_house(my_cards, board_cards, hand_type) + quads_odds = self.detect_quads(my_cards, board_cards) + + most_probable_out = max(flush_odds, full_house_odds, quads_odds, key=lambda odds: odds[0]) + + potential_probability = most_probable_out[0] * hole_factors[most_probable_out[1]] + if most_probable_out == flush_odds: + potential_probability *= hand_strengths['Flush'] + elif most_probable_out == full_house_odds: + potential_probability *= hand_strengths['Full House'] + elif most_probable_out == quads_odds: + potential_probability *= hand_strengths['Quads'] + + return potential_probability + base_probability / 2 + + elif hand_type == 'Two Pair': + # detect flush, full house, quads + flush_odds = self.detect_flush(my_cards, board_cards) + full_house_odds = self.detect_full_house(my_cards, board_cards, hand_type) + quads_odds = self.detect_quads(my_cards, board_cards) + + most_probable_out = max(flush_odds, full_house_odds, quads_odds, key=lambda odds: odds[0]) + + potential_probability = most_probable_out[0] * hole_factors[most_probable_out[1]] + if most_probable_out == flush_odds: + potential_probability *= hand_strengths['Flush'] + elif most_probable_out == full_house_odds: + potential_probability *= hand_strengths['Full House'] + elif most_probable_out == quads_odds: + potential_probability *= hand_strengths['Quads'] + + return potential_probability + base_probability / 2 + elif hand_type == 'Pair': + # detect two pair, trips, straight, flush, full house, quads, straight flush + flush_odds = self.detect_flush(my_cards, board_cards) + full_house_odds = self.detect_full_house(my_cards, hand_type) + quads_odds = self.detect_quads(my_cards, board_cards) + two_pair_odds = self.detect_two_pair(my_cards, board_cards, hand_type) + trips_odds = self.detect_trips(my_cards, board_cards) + straight_odds = self.detect_straight(my_cards, board_cards) + straight_flush_odds = self.detect_straight_flush(my_cards, board_cards) + + most_probable_out = max(flush_odds, full_house_odds, quads_odds, two_pair_odds, trips_odds, straight_odds, straight_flush_odds, key=lambda odds: odds[0]) + + potential_probability = most_probable_out[0] * hole_factors[most_probable_out[1]] + if most_probable_out == flush_odds: + potential_probability *= hand_strengths['Flush'] + elif most_probable_out == full_house_odds: + potential_probability *= hand_strengths['Full House'] + elif most_probable_out == quads_odds: + potential_probability *= hand_strengths['Quads'] + elif most_probable_out == two_pair_odds: + potential_probability *= hand_strengths['Two Pair'] + elif most_probable_out == trips_odds: + potential_probability *= hand_strengths['Trips'] + elif most_probable_out == straight_odds: + potential_probability *= hand_strengths['Straight'] + elif most_probable_out == straight_flush_odds: + potential_probability *= hand_strengths['Straight Flush'] + + return potential_probability + base_probability / 2 + elif hand_type == 'High Card': + # detect pair, two pair, flush, straight, straight flush + flush_odds = self.detect_flush(my_cards, board_cards) + two_pair_odds = self.detect_two_pair(my_cards, board_cards, hand_type) + straight_odds = self.detect_straight(my_cards, board_cards) + straight_flush_odds = self.detect_straight_flush(my_cards, board_cards) + pair_odds = self.detect_pair(my_cards, board_cards) + + most_probable_out = max(flush_odds, two_pair_odds, pair_odds, straight_odds, straight_flush_odds, key=lambda odds: odds[0]) + + potential_probability = most_probable_out[0] * hole_factors[most_probable_out[1]] + if most_probable_out == flush_odds: + potential_probability *= hand_strengths['Flush'] + elif most_probable_out == two_pair_odds: + potential_probability *= hand_strengths['Two Pair'] + elif most_probable_out == pair_odds: + potential_probability *= hand_strengths['Pair'] + elif most_probable_out == straight_odds: + potential_probability *= hand_strengths['Straight'] + elif most_probable_out == straight_flush_odds: + potential_probability *= hand_strengths['Straight Flush'] + + return potential_probability + base_probability / 2 + + # straight flush can just be flush and straight detection and if both are high we probably have a potential straight flush??? + # Potential probability should be a function of the probability of winning given we hit + # scaled by chance of hitting scaled by hole card usage? + # Combine base and potential probabilities and return a winrate (factor in Monte Carlo Sim prob?) + # Probably only want to run certain calculations on certain rounds + # If the board is wet but not for us, win probability should be low + # sim_probability = monte_carlo_flop_and_turn(my_cards, board_cards, deck, iters) + + def base_hole_cards_used(self, my_cards, board_cards, hand_type): + ''' + Calculate how many hole cards contribute to the current hand type. + + Arguments: + my_cards: cards in hole + board_cards: cards on board + hand_type: best hand given current cards + + Returns: + hole_cards_used + ''' + + # Counts how many hole cards were used to get that handtype + hole_cards_used = 0 + for _ in range(len(my_cards)): + removed_card = my_cards.pop(0) + if eval7.handtype(eval7.evaluate(my_cards + board_cards)) != hand_type: + hole_cards_used += 1 + my_cards.append(removed_card) + + return hole_cards_used + + def detect_flush(self, my_cards, board_cards): + ''' + Returns chance of hitting a flush as well as how many come from hole cards. + ''' + # Counts revealed suits + suits = { + 's': 0, + 'd': 0, + 'h': 0, + 'c': 0 + } + + total_cards = my_cards + board_cards + for card in total_cards: + card = str(card) + suits[card[1]] += 1 + + highest_quantity = max(suits.values()) + + # Run post-flop, so if only 2 of the same suit, flush not possible + if highest_quantity <= 2: + return (0, 0) + + # Counts how many of the max suits come from the hole cards + max_suits = {suit:0 for suit, quantity in suits.items() if quantity == highest_quantity} + for card in my_cards: + card = str(card) + if card[1] in max_suits: + max_suits[card[1]] += 1 + + # Grabs the max suit that pulls the most from the hole cards + max_suit = max(max_suits.items(), key=lambda x: x[1]) + + # Calculates chances of hitting the flush + hit_rate = 0 + if highest_quantity == 3: + if len(board_cards) == 3: + hit_rate = 1/16 + return (0, 0) + elif highest_quantity == 4: + if len(board_cards) == 3: + hit_rate = 7/16 + elif len(board_cards) == 4: + hit_rate = 1/4 + return (0, 0) + elif highest_quantity >= 5: + hit_rate = 1 + -def detect_two_pair(my_cards, board_cards, hand_type): - ''' - Returns chance of hitting two pair as well as how many comes from hole cards. - ''' - if hand_type == 'Pair': - hole_cards_used = base_hole_cards_used(my_cards, board_cards, 'Pair') + # Returns hitrate and number of cards coming from hole cards + # Cannot hit a flush if none come from hole cards + if max_suit[1] == 0: + return(0, 0) + return (hit_rate, max_suit[1]) + + def detect_straight(self, my_cards, board_cards, flush=False): + ''' + Returns chance of hitting straight as well as how many comes from hole cards. + ''' + # Process revealed cards + revealed_cards = {} + for card in my_cards + board_cards: + revealed_cards.add(str(card)[0]) + + needed_cards = '' + for card in 'AKQJT98765432': + if card in revealed_cards: + needed_cards += card + else: + needed_cards += 'x' + + # Detect closest potential straight substring + closest_straights = [] + min_to_hit = 5 + + for i in range(0, 9): + current_to_hit = 0 + for j in range(5): + if needed_cards[i + j] == 'x': + current_to_hit += 1 + if current_to_hit < min_to_hit: + min_to_hit = current_to_hit + closest_straights = [needed_cards[i:i+5]] + elif current_to_hit == min_to_hit: + closest_straights.append(needed_cards[i:i+5]) + + # Detect number of hole cards used in potential straight + hole_cards = '' + for card in my_cards: + hole_cards += str(card)[0] + + potential_straights = [] + for straight in closest_straights: + hole_cards_used = 0 + for card in hole_cards: + if card in straight: + hole_cards_used += 1 + if hole_cards_used != 0: + potential_straights.append((straight, hole_cards_used)) + + # Calculate hitrate for potential straight + if potential_straights == []: + return (0, 0) - cards_left = 52 - 5 - len(board_cards) chances_left = 5 - len(board_cards) - - if hole_cards_used == 0: - outs = len(my_cards) * 3 - elif hole_cards_used == 1: - outs = (len(my_cards) - 1 + len(board_cards) - 1) * 3 - else: # hole_cards_used == 2 - outs = (len(my_cards) - 2 + len(board_cards)) * 3 - - hit_rate = 1 - ((cards_left - outs) / cards_left) ** chances_left - - return (hit_rate, max(1, hole_cards_used)) - else: # High Card - if len(board_cards) > 3: + + if chances_left < min_to_hit: return (0, 0) cards_left = 52 - 5 - len(board_cards) - my_cards = len(my_cards) - board_cards = len(board_cards) + outs = len(potential_straights) + + hit_rate = 0 + if flush: + if min_to_hit == 1: + hit_rate = 1 - ((cards_left - outs) / cards_left) ** chances_left + elif min_to_hit == 2: + hit_rate = 2 * outs / (cards_left ** 2) + else: + if min_to_hit == 1: + hit_rate = 1 - ((cards_left - (outs * 4)) / cards_left) ** chances_left + elif min_to_hit == 2: + hit_rate = 2 * (outs * 16) / (cards_left ** 2) + + return (hit_rate, max(potential_straights, key=lambda x: x[1])) + + def detect_two_pair(self, my_cards, board_cards, hand_type): + ''' + Returns chance of hitting two pair as well as how many comes from hole cards. + ''' + if hand_type == 'Pair': + hole_cards_used = self.base_hole_cards_used(my_cards, board_cards, 'Pair') + + cards_left = 52 - 5 - len(board_cards) + chances_left = 5 - len(board_cards) + + if hole_cards_used == 0: + outs = len(my_cards) * 3 + elif hole_cards_used == 1: + outs = (len(my_cards) - 1 + len(board_cards) - 1) * 3 + else: # hole_cards_used == 2 + outs = (len(my_cards) - 2 + len(board_cards)) * 3 + + hit_rate = 1 - ((cards_left - outs) / cards_left) ** chances_left + + return (hit_rate, max(1, hole_cards_used)) + else: # High Card + if len(board_cards) > 3: + return (0, 0) + + cards_left = 52 - 5 - len(board_cards) + my_cards = len(my_cards) + board_cards = len(board_cards) - hit_rate = ((my_cards * 3) * ((my_cards - 1 + board_cards) * 3)) + ((board_cards * 3) * (my_cards * 3)) / (cards_left ** 2) + hit_rate = ((my_cards * 3) * ((my_cards - 1 + board_cards) * 3)) + ((board_cards * 3) * (my_cards * 3)) / (cards_left ** 2) - return (hit_rate, 1) + return (hit_rate, 1) -def detect_pair(my_cards, board_cards): - ''' - Returns chance of hitting pair as well as how many comes from hole cards. - ''' - remaining_cards = 52 - 5 - len(board_cards) - cards_to_hit = len(my_cards) * 3 - chances_left = 5 - len(board_cards) - hit_rate = 1 - ((remaining_cards - cards_to_hit) / remaining_cards) ** chances_left - return (hit_rate, 1) - -def detect_full_house(my_cards, board_cards, hand_type): - ''' - Returns chance of hitting full house as well as how many comes from hole cards. - ''' - if hand_type == 'Trips': - - hole_cards_used = base_hole_cards_used(my_cards, board_cards, 'Trips') + def detect_pair(self, my_cards, board_cards): + ''' + Returns chance of hitting pair as well as how many comes from hole cards. + ''' remaining_cards = 52 - 5 - len(board_cards) + cards_to_hit = len(my_cards) * 3 chances_left = 5 - len(board_cards) - my_cards = len(my_cards) - board_cards = len(board_cards) - + hit_rate = 1 - ((remaining_cards - cards_to_hit) / remaining_cards) ** chances_left + return (hit_rate, 1) - if hole_cards_used == 0: - outs = my_cards * 3 - elif hole_cards_used == 1: - outs = (my_cards - 1 + board_cards - 2) * 3 - elif hole_cards_used == 2: - outs = (my_cards - 2 + board_cards - 1) * 3 - else: # 3 - outs = board_cards * 3 - - hit_rate = 1 - ((remaining_cards - outs) / remaining_cards) ** chances_left + def detect_full_house(self, my_cards, board_cards, hand_type): + ''' + Returns chance of hitting full house as well as how many comes from hole cards. + ''' + if hand_type == 'Trips': + + hole_cards_used = self.base_hole_cards_used(my_cards, board_cards, 'Trips') + remaining_cards = 52 - 5 - len(board_cards) + chances_left = 5 - len(board_cards) + my_cards = len(my_cards) + board_cards = len(board_cards) + - return (hit_rate, hole_cards_used) + if hole_cards_used == 0: + outs = my_cards * 3 + elif hole_cards_used == 1: + outs = (my_cards - 1 + board_cards - 2) * 3 + elif hole_cards_used == 2: + outs = (my_cards - 2 + board_cards - 1) * 3 + else: # 3 + outs = board_cards * 3 - elif hand_type == 'Two Pair': + hit_rate = 1 - ((remaining_cards - outs) / remaining_cards) ** chances_left - hole_cards_used = base_hole_cards_used(my_cards, board_cards, 'Two Pair') - remaining_cards = 52 - 5 - len(board_cards) - chances_left = 5 - len(board_cards) - my_cards = len(my_cards) - board_cards = len(board_cards) + return (hit_rate, hole_cards_used) + + elif hand_type == 'Two Pair': + + hole_cards_used = self.base_hole_cards_used(my_cards, board_cards, 'Two Pair') + remaining_cards = 52 - 5 - len(board_cards) + chances_left = 5 - len(board_cards) + my_cards = len(my_cards) + board_cards = len(board_cards) + + if hole_cards_used == 0: + return (0, 0) + else: + if chances_left == 2: + hit_rate = (my_cards - 1 * 6) + (4 * remaining_cards * 2)/ remaining_cards ** 2 + else: # 1 + outs = 4 + hit_rate = 1 - ((remaining_cards - outs) / remaining_cards) + return (hit_rate, hole_cards_used) + + else: # Pair + + hole_cards_used = self.base_hole_cards_used(my_cards, board_cards, 'Pair') + remaining_cards = 52 - 5 - len(board_cards) + chances_left = 5 - len(board_cards) + my_cards = len(my_cards) + board_cards = len(board_cards) + + if hole_cards_used == 0: + if chances_left == 2: + # need to hit one pair and one hole card or two of the same hole card + hit_rate = (2 * my_cards * 3 * 2) + (my_cards * 3 * 2) / remaining_cards ** 2 + else: # 1 + return (0, 0) + else: + if chances_left == 2: + # need to hit one pair and any card or two of the same card + hit_rate = (2 * (my_cards - 1 + board_cards - 1) * 3 * 2) + ((my_cards - 1 + board_cards - 1) * 3 * 2) / remaining_cards ** 2 + else: # 1 + return (0, 0) + + return (hit_rate, hole_cards_used) + + def detect_straight_flush(self, my_cards, board_cards): + ''' + Returns chance of hitting straight flush as well as how many comes from hole cards. + Basically uses detect_straight logic then checks for flush on the most probable straights + ''' + # Counts revealed suits + suits = { + 's': 0, + 'd': 0, + 'h': 0, + 'c': 0 + } + + total_cards = my_cards + board_cards + for card in total_cards: + card = str(card) + suits[card[1]] += 1 + + highest_quantity = max(suits.values()) + + # Run post-flop, so if only 2 of the same suit, flush not possible + if highest_quantity <= 2: + return (0, 0) + + # Grabs suits that occur most often + max_suits = [suit for suit, quantity in suits.items() if quantity == highest_quantity] + + # Keep hole and board cards if they are that max suit + suited_my_cards = [card for card in my_cards if card[1] in max_suits] + suited_board_cards = [card for card in board_cards if card[1] in max_suits] - if hole_cards_used == 0: + if len(suited_my_cards) == 0: return (0, 0) else: - if chances_left == 2: - hit_rate = (my_cards - 1 * 6) + (4 * remaining_cards * 2)/ remaining_cards ** 2 - else: # 1 - outs = 4 - hit_rate = 1 - ((remaining_cards - outs) / remaining_cards) - return (hit_rate, hole_cards_used) + return self.detect_straight(suited_my_cards, suited_board_cards, True) + + + def detect_trips(self, my_cards, board_cards): + ''' + Returns chance of hitting trips as well as how many comes from hole cards. + ''' + # Counts ranks of revealed cards + ranks = {'A': 0, 'K': 0, 'Q': 0, 'J': 0, 'T': 0, '9': 0, '8': 0, '7': 0, '6': 0, '5': 0, '4': 0, '3': 0, '2': 0, '1': 0} - else: # Pair + total_cards = my_cards + board_cards + for card in total_cards: + card = str(card) + ranks[card[1]] += 1 + + highest_quantity = max(ranks.values()) + + # Counts how many of the max ranks come from the hole cards + max_ranks = {rank:0 for rank, quantity in ranks.items() if quantity == highest_quantity} + for card in my_cards: + card = str(card) + if card[0] in max_ranks: + max_ranks[card[0]] += 1 - hole_cards_used = base_hole_cards_used(my_cards, board_cards, 'Pair') + # Grabs the max rank that pulls the most from the hole cards + max_rank = max(max_ranks.items(), key=lambda x: x[1]) + + # Calculates the chance of getting a trip remaining_cards = 52 - 5 - len(board_cards) - chances_left = 5 - len(board_cards) - my_cards = len(my_cards) - board_cards = len(board_cards) - - if hole_cards_used == 0: - if chances_left == 2: - # need to hit one pair and one hole card or two of the same hole card - hit_rate = (2 * my_cards * 3 * 2) + (my_cards * 3 * 2) / remaining_cards ** 2 - else: # 1 - return (0, 0) + if highest_quantity == 1: + if len(board_cards) == 3: + hit_rate = 1 - ((remaining_cards - 2) / remaining_cards) ** 2 + return (0,0) + elif highest_quantity == 2: + if len(board_cards) == 3: + hit_rate = 1 - ((remaining_cards - 1) / remaining_cards) ** 2 + elif len(board_cards) == 4: + hit_rate = 1 - ((remaining_cards - 1) / remaining_cards) + return (0,0) + elif highest_quantity >= 3: + hit_rate = 1 + + # Return the chance of hitting a trip and number of hole cards used + # If no hole cards were used then no trip occur + if max_rank[1] == 0: + return (0,0) else: - if chances_left == 2: - # need to hit one pair and any card or two of the same card - hit_rate = (2 * (my_cards - 1 + board_cards - 1) * 3 * 2) + ((my_cards - 1 + board_cards - 1) * 3 * 2) / remaining_cards ** 2 - else: # 1 - return (0, 0) - - return (hit_rate, hole_cards_used) + return (hit_rate, max_rank[1]) + + def detect_quads(self, my_cards, board_cards): + ''' + Returns chance of hitting quads as well as how many comes from hole cards. + ''' + # Counts ranks of revealed cards + ranks = {'A': 0, 'K': 0, 'Q': 0, 'J': 0, 'T': 0, '9': 0, '8': 0, '7': 0, '6': 0, '5': 0, '4': 0, '3': 0, '2': 0, '1': 0} -def detect_straight_flush(my_cards, board_cards): - ''' - Returns chance of hitting straight flush as well as how many comes from hole cards. - Basically uses detect_straight logic then checks for flush on the most probable straights - ''' - # Process revealed cards - revealed_cards = {} - for card in my_cards + board_cards: - revealed_cards.add(str(card)[0]) - - needed_cards = '' - for card in 'AKQJT98765432': - if card in revealed_cards: - needed_cards += card - else: - needed_cards += 'x' - - # Detect closest potential straight substring - closest_straights = [] - min_to_hit = 5 - - for i in range(0, 9): - current_to_hit = 0 - for j in range(5): - if needed_cards[i + j] == 'x': - current_to_hit += 1 - if current_to_hit < min_to_hit: - min_to_hit = current_to_hit - closest_straights = [needed_cards[i:i+5]] - elif current_to_hit == min_to_hit: - closest_straights.append(needed_cards[i:i+5]) - - # Detect number of hole cards used in potential straight - hole_cards = '' - for card in my_cards: - hole_cards += str(card)[0] + total_cards = my_cards + board_cards + for card in total_cards: + card = str(card) + ranks[card[1]] += 1 - potential_straights = [] - for straight in closest_straights: - hole_cards_used = 0 - for card in hole_cards: - if card in straight: - hole_cards_used += 1 - if hole_cards_used != 0: - potential_straights.append((straight, hole_cards_used)) + highest_quantity = max(ranks.values()) - # Calculate hitrate for potential straight - # TODO flush detection on potential straights - if potential_straights == []: - return (0, 0) + # Runs post-flop, so if only 1 then no quad can occur + if highest_quantity == 1: + return (0,0) - chances_left = 5 - len(board_cards) + # Counts how many of the max ranks come from the hole cards + max_ranks = {rank:0 for rank, quantity in ranks.items() if quantity == highest_quantity} + for card in my_cards: + card = str(card) + if card[0] in max_ranks: + max_ranks[card[0]] += 1 - if chances_left < min_to_hit: - return (0, 0) + # Grabs the max rank that pulls the most from the hole cards + max_rank = max(max_ranks.items(), key=lambda x: x[1]) + + # Calculates the chance of getting a quad + remaining_cards = 52 - 5 - len(board_cards) + if highest_quantity == 2: + if len(board_cards) == 3: + hit_rate = 1 - ((remaining_cards - 2) / remaining_cards) ** 2 + return (0,0) + elif highest_quantity == 3: + if len(board_cards) == 3: + hit_rate = 1 - ((remaining_cards - 1) / remaining_cards) ** 2 + elif len(board_cards) == 4: + hit_rate = 1 - ((remaining_cards - 1) / remaining_cards) + elif highest_quantity >= 4: + hit_rate = 1 - cards_left = 52 - 5 - len(board_cards) - outs = len(potential_straights) - - hit_rate = 0 - if min_to_hit == 1: - hit_rate = 1 - ((cards_left - (outs * 4)) / cards_left) ** chances_left - elif min_to_hit == 2: - hit_rate = 2 * (outs * 16) / (cards_left ** 2) - - return (hit_rate, max(potential_straights, key=lambda x: x[1])) - - -def detect_trips(my_cards, board_cards): - ''' - Returns chance of hitting trips as well as how many comes from hole cards. - ''' - # Counts ranks of revealed cards - ranks = {'A': 0, 'K': 0, 'Q': 0, 'J': 0, 'T': 0, '9': 0, '8': 0, '7': 0, '6': 0, '5': 0, '4': 0, '3': 0, '2': 0, '1': 0} - - total_cards = my_cards + board_cards - for card in total_cards: - card = str(card) - ranks[card[1]] += 1 - - highest_quantity = max(ranks.values()) - - # Counts how many of the max ranks come from the hole cards - max_ranks = {rank:0 for rank, quantity in ranks.items() if quantity == highest_quantity} - for card in my_cards: - card = str(card) - if card[0] in max_ranks: - max_ranks[card[0]] += 1 - - # Grabs the max rank that pulls the most from the hole cards - max_rank = max(max_ranks.items(), key=lambda x: x[1]) - - # Calculates the chance of getting a trip - remaining_cards = 52 - 5 - len(board_cards) - if highest_quantity == 1: - if len(board_cards) == 3: - hit_rate = 1 - ((remaining_cards - 2) / remaining_cards) ** 2 - return (0,0) - elif highest_quantity == 2: - if len(board_cards) == 3: - hit_rate = 1 - ((remaining_cards - 1) / remaining_cards) ** 2 - elif len(board_cards) == 4: - hit_rate = 1 - ((remaining_cards - 1) / remaining_cards) - return (0,0) - elif highest_quantity >= 3: - hit_rate = 1 - - # Return the chance of hitting a trip and number of hole cards used - # If no hole cards were used then no trip occur - if max_rank[1] == 0: - return (0,0) - else: - return (hit_rate, max_rank[1]) - -def detect_quads(my_cards, board_cards): - ''' - Returns chance of hitting quads as well as how many comes from hole cards. - ''' - # Counts ranks of revealed cards - ranks = {'A': 0, 'K': 0, 'Q': 0, 'J': 0, 'T': 0, '9': 0, '8': 0, '7': 0, '6': 0, '5': 0, '4': 0, '3': 0, '2': 0, '1': 0} - - total_cards = my_cards + board_cards - for card in total_cards: - card = str(card) - ranks[card[1]] += 1 - - highest_quantity = max(ranks.values()) - - # Runs post-flop, so if only 1 then no quad can occur - if highest_quantity == 1: - return (0,0) - - # Counts how many of the max ranks come from the hole cards - max_ranks = {rank:0 for rank, quantity in ranks.items() if quantity == highest_quantity} - for card in my_cards: - card = str(card) - if card[0] in max_ranks: - max_ranks[card[0]] += 1 - - # Grabs the max rank that pulls the most from the hole cards - max_rank = max(max_ranks.items(), key=lambda x: x[1]) - - # Calculates the chance of getting a quad - remaining_cards = 52 - 5 - len(board_cards) - if highest_quantity == 2: - if len(board_cards) == 3: - hit_rate = 1 - ((remaining_cards - 2) / remaining_cards) ** 2 - return (0,0) - elif highest_quantity == 3: - if len(board_cards) == 3: - hit_rate = 1 - ((remaining_cards - 1) / remaining_cards) ** 2 - elif len(board_cards) == 4: - hit_rate = 1 - ((remaining_cards - 1) / remaining_cards) - elif highest_quantity >= 4: - hit_rate = 1 - - # Return the chance of hitting a trip and number of hole cards used - # If no hole cards were used then no trip occur - if max_rank[1] == 0: - return (0,0) - else: - return (hit_rate, max_rank[1]) - -def monte_carlo_flop_and_turn(my_cards, board_cards, deck, iters): - ''' - Runs a monte carlo simulation for your current hand on the turn - (4 cards revealed on the board) - We are simulating the opponent cards + final board card - - Arguments: - my_cards: The 2-3 cards in your hand - - Returns: - winrate: % chance of winning with current hand and street cards - ''' - win_count = 0.0 - - for i in range(iters): - # Set up game state - deck.shuffle() - opp_num = 3 if len(my_cards) == 2 else 2 - draw = deck.peek(opp_num + (5 - len(board_cards))) - opp_cards = draw[:opp_num] - community_cards = draw[opp_num:] - - my_hand = my_cards + community_cards + board_cards - opp_hand = opp_cards + community_cards + board_cards - - our_hand_eval = eval7.evaluate(my_hand) - opp_hand_eval = eval7.evaluate(opp_hand) - - if our_hand_eval > opp_hand_eval: - # We win the round - win_count += 1 - elif our_hand_eval == opp_hand_eval: - # We tie this round - win_count += 0.5 + # Return the chance of hitting a trip and number of hole cards used + # If no hole cards were used then no trip occur + if max_rank[1] == 0: + return (0,0) else: - # We lose this round - win_count += 0 - - return win_count/iters \ No newline at end of file + return (hit_rate, max_rank[1]) + + def monte_carlo_flop_and_turn(self, my_cards, board_cards, deck, iters): + ''' + Runs a monte carlo simulation for your current hand on the turn + (4 cards revealed on the board) + We are simulating the opponent cards + final board card + + Arguments: + my_cards: The 2-3 cards in your hand + + Returns: + winrate: % chance of winning with current hand and street cards + ''' + win_count = 0.0 + + for i in range(iters): + # Set up game state + deck.shuffle() + opp_num = 3 if len(my_cards) == 2 else 2 + draw = deck.peek(opp_num + (5 - len(board_cards))) + opp_cards = draw[:opp_num] + community_cards = draw[opp_num:] + + my_hand = my_cards + community_cards + board_cards + opp_hand = opp_cards + community_cards + board_cards + + our_hand_eval = eval7.evaluate(my_hand) + opp_hand_eval = eval7.evaluate(opp_hand) + + if our_hand_eval > opp_hand_eval: + # We win the round + win_count += 1 + elif our_hand_eval == opp_hand_eval: + # We tie this round + win_count += 0.5 + else: + # We lose this round + win_count += 0 + + return win_count/iters \ No newline at end of file diff --git a/python_skeleton/skeleton/probability_engine_tests/monte_carlo_tests.py b/python_skeleton/skeleton/probability_engine_tests/monte_carlo_tests.py new file mode 100644 index 0000000..6b7b448 --- /dev/null +++ b/python_skeleton/skeleton/probability_engine_tests/monte_carlo_tests.py @@ -0,0 +1 @@ +from ..probability_engine import Probability_Engine \ No newline at end of file diff --git a/python_skeleton/skeleton/probability_engine_tests/unit_tests.py b/python_skeleton/skeleton/probability_engine_tests/unit_tests.py new file mode 100644 index 0000000..95192fc --- /dev/null +++ b/python_skeleton/skeleton/probability_engine_tests/unit_tests.py @@ -0,0 +1,187 @@ +from ..probability_engine import Probability_Engine + +class Unit_Tests(): + def __init__(self): + self.probability_engine = Probability_Engine() + + def test_all(self): + print('Running all Unit Tests') + + detect_results = self.test_detect() + base_hole_cards_used_results = self.test_base_hole_cards_used() + + passed = [] + failed = [] + passed.append('test_detect') if detect_results else failed.append('test_detect') + passed.append('test_base_hole_cards_used') if base_hole_cards_used_results else failed.append('test_base_hole_cards_used') + + print('Finished running all Unit Tests') + if len(failed) == 0: + print('Passed all tests') + else: + print(f'Failed {len(failed)} tests') + print(f'Passed: {passed}') + print(f'Failed: {failed}') + + def test_detect(self): + print('Running detect Unit Tests') + + flush_results = self.test_flush() + full_house_results = self.test_full_house() + pair_results = self.test_pair() + quads_results = self.test_quads() + straight_results = self.test_straight() + straight_flush_results = self.test_straight_flush() + trips_results = self.test_trips() + two_pair_results = self.test_two_pair() + + passed = [] + failed = [] + passed.append('test_flush') if flush_results else failed.append('test_flush') + passed.append('test_full_house') if full_house_results else failed.append('test_full_house') + passed.append('test_pair') if pair_results else failed.append('test_pair') + passed.append('test_quads') if quads_results else failed.append('test_quads') + passed.append('test_straight') if straight_results else failed.append('test_straight') + passed.append('test_straight_flush') if straight_flush_results else failed.append('test_straight_flush') + passed.append('test_trips') if trips_results else failed.append('test_trips') + passed.append('test_two_pair') if two_pair_results else failed.append('test_two_pair') + + print('Finished running detect Unit Tests') + if len(failed) == 0: + print('Passed all tests') + else: + print(f'Failed {len(failed)} tests') + print(f'Passed: {passed}') + print(f'Failed: {failed}') + + def test_base_hole_cards_used(self): + print('Running base_hole_cards_used Unit Tests') + + + + passed = [] + failed = [] + + print('Finished running base_hole_cards_used Unit Tests') + if len(failed) == 0: + print('Passed all tests') + else: + print(f'Failed {len(failed)} tests') + print(f'Passed: {passed}') + print(f'Failed: {failed}') + + def test_flush(self): + print('Running flush Unit Tests') + + passed = [] + failed = [] + + print('Finished running flush Unit Tests') + if len(failed) == 0: + print('Passed all tests') + else: + print(f'Failed {len(failed)} tests') + print(f'Passed: {passed}') + print(f'Failed: {failed}') + + def test_full_house(self): + print('Running full_house Unit Tests') + + passed = [] + failed = [] + + print('Finished running full_house Unit Tests') + if len(failed) == 0: + print('Passed all tests') + else: + print(f'Failed {len(failed)} tests') + print(f'Passed: {passed}') + print(f'Failed: {failed}') + + def test_pair(self): + print('Running pair Unit Tests') + + passed = [] + failed = [] + + print('Finished running pair Unit Tests') + if len(failed) == 0: + print('Passed all tests') + else: + print(f'Failed {len(failed)} tests') + print(f'Passed: {passed}') + print(f'Failed: {failed}') + + def test_quads(self): + print('Running quads Unit Tests') + + passed = [] + failed = [] + + print('Finished running quads Unit Tests') + if len(failed) == 0: + print('Passed all tests') + else: + print(f'Failed {len(failed)} tests') + print(f'Passed: {passed}') + print(f'Failed: {failed}') + + def test_trips(self): + print('Running trips Unit Tests') + + passed = [] + failed = [] + + print('Finished running trips Unit Tests') + if len(failed) == 0: + print('Passed all tests') + else: + print(f'Failed {len(failed)} tests') + print(f'Passed: {passed}') + print(f'Failed: {failed}') + + def test_straight(self): + print('Running straight Unit Tests') + + passed = [] + failed = [] + + print('Finished running straight Unit Tests') + if len(failed) == 0: + print('Passed all tests') + else: + print(f'Failed {len(failed)} tests') + print(f'Passed: {passed}') + print(f'Failed: {failed}') + + def test_straight_flush(self): + print('Running straight_flush Unit Tests') + + passed = [] + failed = [] + + print('Finished running straight_flush Unit Tests') + if len(failed) == 0: + print('Passed all tests') + else: + print(f'Failed {len(failed)} tests') + print(f'Passed: {passed}') + print(f'Failed: {failed}') + + def test_two_pair(self): + print('Running two_pair Unit Tests') + + passed = [] + failed = [] + + print('Finished running two_pair Unit Tests') + if len(failed) == 0: + print('Passed all tests') + else: + print(f'Failed {len(failed)} tests') + print(f'Passed: {passed}') + print(f'Failed: {failed}') + +if __name__ == '__main__': + unit_tests = Unit_Tests() + unit_tests.test_all() \ No newline at end of file From 7578830b2c58e91d6cc62d19631c7b3996cca9ac Mon Sep 17 00:00:00 2001 From: Brian Le Date: Tue, 23 Jan 2024 15:16:17 -0500 Subject: [PATCH 07/15] More unit test framework --- .../probability_engine_tests/unit_tests.py | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/python_skeleton/skeleton/probability_engine_tests/unit_tests.py b/python_skeleton/skeleton/probability_engine_tests/unit_tests.py index 95192fc..8011df4 100644 --- a/python_skeleton/skeleton/probability_engine_tests/unit_tests.py +++ b/python_skeleton/skeleton/probability_engine_tests/unit_tests.py @@ -57,10 +57,28 @@ def test_detect(self): def test_base_hole_cards_used(self): print('Running base_hole_cards_used Unit Tests') - + test_1 = self.probability_engine.base_hole_cards_used() == + test_2 = self.probability_engine.base_hole_cards_used() == + test_3 = self.probability_engine.base_hole_cards_used() == + test_4 = self.probability_engine.base_hole_cards_used() == + test_5 = self.probability_engine.base_hole_cards_used() == + test_6 = self.probability_engine.base_hole_cards_used() == + test_7 = self.probability_engine.base_hole_cards_used() == + test_8 = self.probability_engine.base_hole_cards_used() == + test_9 = self.probability_engine.base_hole_cards_used() == passed = [] failed = [] + passed.append('test_1') if test_1 else failed.append('test_1') + passed.append('test_2') if test_2 else failed.append('test_2') + passed.append('test_3') if test_3 else failed.append('test_3') + passed.append('test_4') if test_4 else failed.append('test_4') + passed.append('test_5') if test_5 else failed.append('test_5') + passed.append('test_6') if test_6 else failed.append('test_6') + passed.append('test_7') if test_7 else failed.append('test_7') + passed.append('test_8') if test_8 else failed.append('test_8') + passed.append('test_9') if test_9 else failed.append('test_9') + print('Finished running base_hole_cards_used Unit Tests') if len(failed) == 0: From c76b73b56e56c6ff2ccf263beb25115f45a48606 Mon Sep 17 00:00:00 2001 From: Brian Le Date: Tue, 23 Jan 2024 15:20:23 -0500 Subject: [PATCH 08/15] More unit test framework 2 --- .../probability_engine_tests/unit_tests.py | 154 +++++++++++++++++- 1 file changed, 153 insertions(+), 1 deletion(-) diff --git a/python_skeleton/skeleton/probability_engine_tests/unit_tests.py b/python_skeleton/skeleton/probability_engine_tests/unit_tests.py index 8011df4..b17eb99 100644 --- a/python_skeleton/skeleton/probability_engine_tests/unit_tests.py +++ b/python_skeleton/skeleton/probability_engine_tests/unit_tests.py @@ -91,8 +91,27 @@ def test_base_hole_cards_used(self): def test_flush(self): print('Running flush Unit Tests') + test_1 = self.probability_engine.detect_flush() == + test_2 = self.probability_engine.detect_flush() == + test_3 = self.probability_engine.detect_flush() == + test_4 = self.probability_engine.detect_flush() == + test_5 = self.probability_engine.detect_flush() == + test_6 = self.probability_engine.detect_flush() == + test_7 = self.probability_engine.detect_flush() == + test_8 = self.probability_engine.detect_flush() == + test_9 = self.probability_engine.detect_flush() == + passed = [] failed = [] + passed.append('test_1') if test_1 else failed.append('test_1') + passed.append('test_2') if test_2 else failed.append('test_2') + passed.append('test_3') if test_3 else failed.append('test_3') + passed.append('test_4') if test_4 else failed.append('test_4') + passed.append('test_5') if test_5 else failed.append('test_5') + passed.append('test_6') if test_6 else failed.append('test_6') + passed.append('test_7') if test_7 else failed.append('test_7') + passed.append('test_8') if test_8 else failed.append('test_8') + passed.append('test_9') if test_9 else failed.append('test_9') print('Finished running flush Unit Tests') if len(failed) == 0: @@ -105,8 +124,27 @@ def test_flush(self): def test_full_house(self): print('Running full_house Unit Tests') + test_1 = self.probability_engine.detect_full_house() == + test_2 = self.probability_engine.detect_full_house() == + test_3 = self.probability_engine.detect_full_house() == + test_4 = self.probability_engine.detect_full_house() == + test_5 = self.probability_engine.detect_full_house() == + test_6 = self.probability_engine.detect_full_house() == + test_7 = self.probability_engine.detect_full_house() == + test_8 = self.probability_engine.detect_full_house() == + test_9 = self.probability_engine.detect_full_house() == + passed = [] failed = [] + passed.append('test_1') if test_1 else failed.append('test_1') + passed.append('test_2') if test_2 else failed.append('test_2') + passed.append('test_3') if test_3 else failed.append('test_3') + passed.append('test_4') if test_4 else failed.append('test_4') + passed.append('test_5') if test_5 else failed.append('test_5') + passed.append('test_6') if test_6 else failed.append('test_6') + passed.append('test_7') if test_7 else failed.append('test_7') + passed.append('test_8') if test_8 else failed.append('test_8') + passed.append('test_9') if test_9 else failed.append('test_9') print('Finished running full_house Unit Tests') if len(failed) == 0: @@ -119,8 +157,27 @@ def test_full_house(self): def test_pair(self): print('Running pair Unit Tests') + test_1 = self.probability_engine.detect_pair() == + test_2 = self.probability_engine.detect_pair() == + test_3 = self.probability_engine.detect_pair() == + test_4 = self.probability_engine.detect_pair() == + test_5 = self.probability_engine.detect_pair() == + test_6 = self.probability_engine.detect_pair() == + test_7 = self.probability_engine.detect_pair() == + test_8 = self.probability_engine.detect_pair() == + test_9 = self.probability_engine.detect_pair() == + passed = [] failed = [] + passed.append('test_1') if test_1 else failed.append('test_1') + passed.append('test_2') if test_2 else failed.append('test_2') + passed.append('test_3') if test_3 else failed.append('test_3') + passed.append('test_4') if test_4 else failed.append('test_4') + passed.append('test_5') if test_5 else failed.append('test_5') + passed.append('test_6') if test_6 else failed.append('test_6') + passed.append('test_7') if test_7 else failed.append('test_7') + passed.append('test_8') if test_8 else failed.append('test_8') + passed.append('test_9') if test_9 else failed.append('test_9') print('Finished running pair Unit Tests') if len(failed) == 0: @@ -133,8 +190,27 @@ def test_pair(self): def test_quads(self): print('Running quads Unit Tests') + test_1 = self.probability_engine.detect_quads() == + test_2 = self.probability_engine.detect_quads() == + test_3 = self.probability_engine.detect_quads() == + test_4 = self.probability_engine.detect_quads() == + test_5 = self.probability_engine.detect_quads() == + test_6 = self.probability_engine.detect_quads() == + test_7 = self.probability_engine.detect_quads() == + test_8 = self.probability_engine.detect_quads() == + test_9 = self.probability_engine.detect_quads() == + passed = [] failed = [] + passed.append('test_1') if test_1 else failed.append('test_1') + passed.append('test_2') if test_2 else failed.append('test_2') + passed.append('test_3') if test_3 else failed.append('test_3') + passed.append('test_4') if test_4 else failed.append('test_4') + passed.append('test_5') if test_5 else failed.append('test_5') + passed.append('test_6') if test_6 else failed.append('test_6') + passed.append('test_7') if test_7 else failed.append('test_7') + passed.append('test_8') if test_8 else failed.append('test_8') + passed.append('test_9') if test_9 else failed.append('test_9') print('Finished running quads Unit Tests') if len(failed) == 0: @@ -147,8 +223,27 @@ def test_quads(self): def test_trips(self): print('Running trips Unit Tests') + test_1 = self.probability_engine.detect_trips() == + test_2 = self.probability_engine.detect_trips() == + test_3 = self.probability_engine.detect_trips() == + test_4 = self.probability_engine.detect_trips() == + test_5 = self.probability_engine.detect_trips() == + test_6 = self.probability_engine.detect_trips() == + test_7 = self.probability_engine.detect_trips() == + test_8 = self.probability_engine.detect_trips() == + test_9 = self.probability_engine.detect_trips() == + passed = [] failed = [] + passed.append('test_1') if test_1 else failed.append('test_1') + passed.append('test_2') if test_2 else failed.append('test_2') + passed.append('test_3') if test_3 else failed.append('test_3') + passed.append('test_4') if test_4 else failed.append('test_4') + passed.append('test_5') if test_5 else failed.append('test_5') + passed.append('test_6') if test_6 else failed.append('test_6') + passed.append('test_7') if test_7 else failed.append('test_7') + passed.append('test_8') if test_8 else failed.append('test_8') + passed.append('test_9') if test_9 else failed.append('test_9') print('Finished running trips Unit Tests') if len(failed) == 0: @@ -160,9 +255,28 @@ def test_trips(self): def test_straight(self): print('Running straight Unit Tests') - + + test_1 = self.probability_engine.detect_straight() == + test_2 = self.probability_engine.detect_straight() == + test_3 = self.probability_engine.detect_straight() == + test_4 = self.probability_engine.detect_straight() == + test_5 = self.probability_engine.detect_straight() == + test_6 = self.probability_engine.detect_straight() == + test_7 = self.probability_engine.detect_straight() == + test_8 = self.probability_engine.detect_straight() == + test_9 = self.probability_engine.detect_straight() == + passed = [] failed = [] + passed.append('test_1') if test_1 else failed.append('test_1') + passed.append('test_2') if test_2 else failed.append('test_2') + passed.append('test_3') if test_3 else failed.append('test_3') + passed.append('test_4') if test_4 else failed.append('test_4') + passed.append('test_5') if test_5 else failed.append('test_5') + passed.append('test_6') if test_6 else failed.append('test_6') + passed.append('test_7') if test_7 else failed.append('test_7') + passed.append('test_8') if test_8 else failed.append('test_8') + passed.append('test_9') if test_9 else failed.append('test_9') print('Finished running straight Unit Tests') if len(failed) == 0: @@ -175,8 +289,27 @@ def test_straight(self): def test_straight_flush(self): print('Running straight_flush Unit Tests') + test_1 = self.probability_engine.detect_straight_flush() == + test_2 = self.probability_engine.detect_straight_flush() == + test_3 = self.probability_engine.detect_straight_flush() == + test_4 = self.probability_engine.detect_straight_flush() == + test_5 = self.probability_engine.detect_straight_flush() == + test_6 = self.probability_engine.detect_straight_flush() == + test_7 = self.probability_engine.detect_straight_flush() == + test_8 = self.probability_engine.detect_straight_flush() == + test_9 = self.probability_engine.detect_straight_flush() == + passed = [] failed = [] + passed.append('test_1') if test_1 else failed.append('test_1') + passed.append('test_2') if test_2 else failed.append('test_2') + passed.append('test_3') if test_3 else failed.append('test_3') + passed.append('test_4') if test_4 else failed.append('test_4') + passed.append('test_5') if test_5 else failed.append('test_5') + passed.append('test_6') if test_6 else failed.append('test_6') + passed.append('test_7') if test_7 else failed.append('test_7') + passed.append('test_8') if test_8 else failed.append('test_8') + passed.append('test_9') if test_9 else failed.append('test_9') print('Finished running straight_flush Unit Tests') if len(failed) == 0: @@ -189,8 +322,27 @@ def test_straight_flush(self): def test_two_pair(self): print('Running two_pair Unit Tests') + test_1 = self.probability_engine.detect_two_pair() == + test_2 = self.probability_engine.detect_two_pair() == + test_3 = self.probability_engine.detect_two_pair() == + test_4 = self.probability_engine.detect_two_pair() == + test_5 = self.probability_engine.detect_two_pair() == + test_6 = self.probability_engine.detect_two_pair() == + test_7 = self.probability_engine.detect_two_pair() == + test_8 = self.probability_engine.detect_two_pair() == + test_9 = self.probability_engine.detect_two_pair() == + passed = [] failed = [] + passed.append('test_1') if test_1 else failed.append('test_1') + passed.append('test_2') if test_2 else failed.append('test_2') + passed.append('test_3') if test_3 else failed.append('test_3') + passed.append('test_4') if test_4 else failed.append('test_4') + passed.append('test_5') if test_5 else failed.append('test_5') + passed.append('test_6') if test_6 else failed.append('test_6') + passed.append('test_7') if test_7 else failed.append('test_7') + passed.append('test_8') if test_8 else failed.append('test_8') + passed.append('test_9') if test_9 else failed.append('test_9') print('Finished running two_pair Unit Tests') if len(failed) == 0: From 9736be7bc9a897fc15ae77e96f6d67b740c2eff5 Mon Sep 17 00:00:00 2001 From: Brian Le Date: Tue, 23 Jan 2024 15:43:53 -0500 Subject: [PATCH 09/15] Finished base hole used test --- python_skeleton/skeleton/monte_carlo_tests.py | 1 + .../monte_carlo_tests.py | 1 - .../unit_tests.py | 32 ++++++++++++------- 3 files changed, 21 insertions(+), 13 deletions(-) create mode 100644 python_skeleton/skeleton/monte_carlo_tests.py delete mode 100644 python_skeleton/skeleton/probability_engine_tests/monte_carlo_tests.py rename python_skeleton/skeleton/{probability_engine_tests => }/unit_tests.py (87%) diff --git a/python_skeleton/skeleton/monte_carlo_tests.py b/python_skeleton/skeleton/monte_carlo_tests.py new file mode 100644 index 0000000..e6ca352 --- /dev/null +++ b/python_skeleton/skeleton/monte_carlo_tests.py @@ -0,0 +1 @@ +from probability_engine import Probability_Engine \ No newline at end of file diff --git a/python_skeleton/skeleton/probability_engine_tests/monte_carlo_tests.py b/python_skeleton/skeleton/probability_engine_tests/monte_carlo_tests.py deleted file mode 100644 index 6b7b448..0000000 --- a/python_skeleton/skeleton/probability_engine_tests/monte_carlo_tests.py +++ /dev/null @@ -1 +0,0 @@ -from ..probability_engine import Probability_Engine \ No newline at end of file diff --git a/python_skeleton/skeleton/probability_engine_tests/unit_tests.py b/python_skeleton/skeleton/unit_tests.py similarity index 87% rename from python_skeleton/skeleton/probability_engine_tests/unit_tests.py rename to python_skeleton/skeleton/unit_tests.py index b17eb99..60350c6 100644 --- a/python_skeleton/skeleton/probability_engine_tests/unit_tests.py +++ b/python_skeleton/skeleton/unit_tests.py @@ -1,10 +1,12 @@ -from ..probability_engine import Probability_Engine +import eval7 +from probability_engine import Probability_Engine class Unit_Tests(): def __init__(self): self.probability_engine = Probability_Engine() def test_all(self): + print('==================================================') print('Running all Unit Tests') detect_results = self.test_detect() @@ -24,6 +26,7 @@ def test_all(self): print(f'Failed: {failed}') def test_detect(self): + print('==================================================') print('Running detect Unit Tests') flush_results = self.test_flush() @@ -55,17 +58,16 @@ def test_detect(self): print(f'Failed: {failed}') def test_base_hole_cards_used(self): + print('==================================================') print('Running base_hole_cards_used Unit Tests') - test_1 = self.probability_engine.base_hole_cards_used() == - test_2 = self.probability_engine.base_hole_cards_used() == - test_3 = self.probability_engine.base_hole_cards_used() == - test_4 = self.probability_engine.base_hole_cards_used() == - test_5 = self.probability_engine.base_hole_cards_used() == - test_6 = self.probability_engine.base_hole_cards_used() == - test_7 = self.probability_engine.base_hole_cards_used() == - test_8 = self.probability_engine.base_hole_cards_used() == - test_9 = self.probability_engine.base_hole_cards_used() == + test_1 = self.probability_engine.base_hole_cards_used([eval7.Card('Ac'), eval7.Card('Ad'), ], [eval7.Card('Ah'), eval7.Card('7c'), eval7.Card('6d'), ], 'Trips') == 2 + test_2 = self.probability_engine.base_hole_cards_used([eval7.Card('3h'), eval7.Card('4h'), eval7.Card('7h')], [eval7.Card('Ah'), eval7.Card('7c'), eval7.Card('6h')], 'Flush') == 3 + test_3 = self.probability_engine.base_hole_cards_used([eval7.Card('Ac'), eval7.Card('2d'), ], [eval7.Card('Ah'), eval7.Card('7c'), eval7.Card('6d')], 'Pair') == 1 + test_4 = self.probability_engine.base_hole_cards_used([eval7.Card('2h'), eval7.Card('Kd'), ], [eval7.Card('2d'), eval7.Card('Ks'), eval7.Card('6d'), eval7.Card('8d')], 'Two Pair') == 2 + test_5 = self.probability_engine.base_hole_cards_used([eval7.Card('Ac'), eval7.Card('Ad'), eval7.Card('Jc')], [eval7.Card('Ah'), eval7.Card('7c'), eval7.Card('6d'), eval7.Card('7h')], 'Full House') == 2 + test_6 = self.probability_engine.base_hole_cards_used([eval7.Card('Ac'), eval7.Card('Td'), ], [eval7.Card('Ah'), eval7.Card('7c'), eval7.Card('6d'), eval7.Card('5h'), eval7.Card('9h')], 'Pair') == 1 + test_7 = self.probability_engine.base_hole_cards_used([eval7.Card('Ac'), eval7.Card('8c'), eval7.Card('6d')], [eval7.Card('4h'), eval7.Card('4c'), eval7.Card('4d'), eval7.Card('2s'), eval7.Card('5s')], 'Trips') == 0 passed = [] failed = [] @@ -76,8 +78,6 @@ def test_base_hole_cards_used(self): passed.append('test_5') if test_5 else failed.append('test_5') passed.append('test_6') if test_6 else failed.append('test_6') passed.append('test_7') if test_7 else failed.append('test_7') - passed.append('test_8') if test_8 else failed.append('test_8') - passed.append('test_9') if test_9 else failed.append('test_9') print('Finished running base_hole_cards_used Unit Tests') @@ -89,6 +89,7 @@ def test_base_hole_cards_used(self): print(f'Failed: {failed}') def test_flush(self): + print('==================================================') print('Running flush Unit Tests') test_1 = self.probability_engine.detect_flush() == @@ -122,6 +123,7 @@ def test_flush(self): print(f'Failed: {failed}') def test_full_house(self): + print('==================================================') print('Running full_house Unit Tests') test_1 = self.probability_engine.detect_full_house() == @@ -155,6 +157,7 @@ def test_full_house(self): print(f'Failed: {failed}') def test_pair(self): + print('==================================================') print('Running pair Unit Tests') test_1 = self.probability_engine.detect_pair() == @@ -188,6 +191,7 @@ def test_pair(self): print(f'Failed: {failed}') def test_quads(self): + print('==================================================') print('Running quads Unit Tests') test_1 = self.probability_engine.detect_quads() == @@ -221,6 +225,7 @@ def test_quads(self): print(f'Failed: {failed}') def test_trips(self): + print('==================================================') print('Running trips Unit Tests') test_1 = self.probability_engine.detect_trips() == @@ -254,6 +259,7 @@ def test_trips(self): print(f'Failed: {failed}') def test_straight(self): + print('==================================================') print('Running straight Unit Tests') test_1 = self.probability_engine.detect_straight() == @@ -287,6 +293,7 @@ def test_straight(self): print(f'Failed: {failed}') def test_straight_flush(self): + print('==================================================') print('Running straight_flush Unit Tests') test_1 = self.probability_engine.detect_straight_flush() == @@ -320,6 +327,7 @@ def test_straight_flush(self): print(f'Failed: {failed}') def test_two_pair(self): + print('==================================================') print('Running two_pair Unit Tests') test_1 = self.probability_engine.detect_two_pair() == From b1d1e14b7e20f90083a2ac617499ee34e3c45cd4 Mon Sep 17 00:00:00 2001 From: rwang155 Date: Tue, 23 Jan 2024 17:14:08 -0500 Subject: [PATCH 10/15] unit tests for trips and quads --- python_skeleton/skeleton/unit_tests.py | 728 ++++++++++++------------- 1 file changed, 364 insertions(+), 364 deletions(-) diff --git a/python_skeleton/skeleton/unit_tests.py b/python_skeleton/skeleton/unit_tests.py index 60350c6..7b462f0 100644 --- a/python_skeleton/skeleton/unit_tests.py +++ b/python_skeleton/skeleton/unit_tests.py @@ -1,365 +1,365 @@ -import eval7 -from probability_engine import Probability_Engine - -class Unit_Tests(): - def __init__(self): - self.probability_engine = Probability_Engine() - - def test_all(self): - print('==================================================') - print('Running all Unit Tests') - - detect_results = self.test_detect() - base_hole_cards_used_results = self.test_base_hole_cards_used() - - passed = [] - failed = [] - passed.append('test_detect') if detect_results else failed.append('test_detect') - passed.append('test_base_hole_cards_used') if base_hole_cards_used_results else failed.append('test_base_hole_cards_used') - - print('Finished running all Unit Tests') - if len(failed) == 0: - print('Passed all tests') - else: - print(f'Failed {len(failed)} tests') - print(f'Passed: {passed}') - print(f'Failed: {failed}') - - def test_detect(self): - print('==================================================') - print('Running detect Unit Tests') - - flush_results = self.test_flush() - full_house_results = self.test_full_house() - pair_results = self.test_pair() - quads_results = self.test_quads() - straight_results = self.test_straight() - straight_flush_results = self.test_straight_flush() - trips_results = self.test_trips() - two_pair_results = self.test_two_pair() - - passed = [] - failed = [] - passed.append('test_flush') if flush_results else failed.append('test_flush') - passed.append('test_full_house') if full_house_results else failed.append('test_full_house') - passed.append('test_pair') if pair_results else failed.append('test_pair') - passed.append('test_quads') if quads_results else failed.append('test_quads') - passed.append('test_straight') if straight_results else failed.append('test_straight') - passed.append('test_straight_flush') if straight_flush_results else failed.append('test_straight_flush') - passed.append('test_trips') if trips_results else failed.append('test_trips') - passed.append('test_two_pair') if two_pair_results else failed.append('test_two_pair') - - print('Finished running detect Unit Tests') - if len(failed) == 0: - print('Passed all tests') - else: - print(f'Failed {len(failed)} tests') - print(f'Passed: {passed}') - print(f'Failed: {failed}') - - def test_base_hole_cards_used(self): - print('==================================================') - print('Running base_hole_cards_used Unit Tests') - - test_1 = self.probability_engine.base_hole_cards_used([eval7.Card('Ac'), eval7.Card('Ad'), ], [eval7.Card('Ah'), eval7.Card('7c'), eval7.Card('6d'), ], 'Trips') == 2 - test_2 = self.probability_engine.base_hole_cards_used([eval7.Card('3h'), eval7.Card('4h'), eval7.Card('7h')], [eval7.Card('Ah'), eval7.Card('7c'), eval7.Card('6h')], 'Flush') == 3 - test_3 = self.probability_engine.base_hole_cards_used([eval7.Card('Ac'), eval7.Card('2d'), ], [eval7.Card('Ah'), eval7.Card('7c'), eval7.Card('6d')], 'Pair') == 1 - test_4 = self.probability_engine.base_hole_cards_used([eval7.Card('2h'), eval7.Card('Kd'), ], [eval7.Card('2d'), eval7.Card('Ks'), eval7.Card('6d'), eval7.Card('8d')], 'Two Pair') == 2 - test_5 = self.probability_engine.base_hole_cards_used([eval7.Card('Ac'), eval7.Card('Ad'), eval7.Card('Jc')], [eval7.Card('Ah'), eval7.Card('7c'), eval7.Card('6d'), eval7.Card('7h')], 'Full House') == 2 - test_6 = self.probability_engine.base_hole_cards_used([eval7.Card('Ac'), eval7.Card('Td'), ], [eval7.Card('Ah'), eval7.Card('7c'), eval7.Card('6d'), eval7.Card('5h'), eval7.Card('9h')], 'Pair') == 1 - test_7 = self.probability_engine.base_hole_cards_used([eval7.Card('Ac'), eval7.Card('8c'), eval7.Card('6d')], [eval7.Card('4h'), eval7.Card('4c'), eval7.Card('4d'), eval7.Card('2s'), eval7.Card('5s')], 'Trips') == 0 - - passed = [] - failed = [] - passed.append('test_1') if test_1 else failed.append('test_1') - passed.append('test_2') if test_2 else failed.append('test_2') - passed.append('test_3') if test_3 else failed.append('test_3') - passed.append('test_4') if test_4 else failed.append('test_4') - passed.append('test_5') if test_5 else failed.append('test_5') - passed.append('test_6') if test_6 else failed.append('test_6') - passed.append('test_7') if test_7 else failed.append('test_7') - - - print('Finished running base_hole_cards_used Unit Tests') - if len(failed) == 0: - print('Passed all tests') - else: - print(f'Failed {len(failed)} tests') - print(f'Passed: {passed}') - print(f'Failed: {failed}') - - def test_flush(self): - print('==================================================') - print('Running flush Unit Tests') - - test_1 = self.probability_engine.detect_flush() == - test_2 = self.probability_engine.detect_flush() == - test_3 = self.probability_engine.detect_flush() == - test_4 = self.probability_engine.detect_flush() == - test_5 = self.probability_engine.detect_flush() == - test_6 = self.probability_engine.detect_flush() == - test_7 = self.probability_engine.detect_flush() == - test_8 = self.probability_engine.detect_flush() == - test_9 = self.probability_engine.detect_flush() == - - passed = [] - failed = [] - passed.append('test_1') if test_1 else failed.append('test_1') - passed.append('test_2') if test_2 else failed.append('test_2') - passed.append('test_3') if test_3 else failed.append('test_3') - passed.append('test_4') if test_4 else failed.append('test_4') - passed.append('test_5') if test_5 else failed.append('test_5') - passed.append('test_6') if test_6 else failed.append('test_6') - passed.append('test_7') if test_7 else failed.append('test_7') - passed.append('test_8') if test_8 else failed.append('test_8') - passed.append('test_9') if test_9 else failed.append('test_9') - - print('Finished running flush Unit Tests') - if len(failed) == 0: - print('Passed all tests') - else: - print(f'Failed {len(failed)} tests') - print(f'Passed: {passed}') - print(f'Failed: {failed}') - - def test_full_house(self): - print('==================================================') - print('Running full_house Unit Tests') - - test_1 = self.probability_engine.detect_full_house() == - test_2 = self.probability_engine.detect_full_house() == - test_3 = self.probability_engine.detect_full_house() == - test_4 = self.probability_engine.detect_full_house() == - test_5 = self.probability_engine.detect_full_house() == - test_6 = self.probability_engine.detect_full_house() == - test_7 = self.probability_engine.detect_full_house() == - test_8 = self.probability_engine.detect_full_house() == - test_9 = self.probability_engine.detect_full_house() == - - passed = [] - failed = [] - passed.append('test_1') if test_1 else failed.append('test_1') - passed.append('test_2') if test_2 else failed.append('test_2') - passed.append('test_3') if test_3 else failed.append('test_3') - passed.append('test_4') if test_4 else failed.append('test_4') - passed.append('test_5') if test_5 else failed.append('test_5') - passed.append('test_6') if test_6 else failed.append('test_6') - passed.append('test_7') if test_7 else failed.append('test_7') - passed.append('test_8') if test_8 else failed.append('test_8') - passed.append('test_9') if test_9 else failed.append('test_9') - - print('Finished running full_house Unit Tests') - if len(failed) == 0: - print('Passed all tests') - else: - print(f'Failed {len(failed)} tests') - print(f'Passed: {passed}') - print(f'Failed: {failed}') - - def test_pair(self): - print('==================================================') - print('Running pair Unit Tests') - - test_1 = self.probability_engine.detect_pair() == - test_2 = self.probability_engine.detect_pair() == - test_3 = self.probability_engine.detect_pair() == - test_4 = self.probability_engine.detect_pair() == - test_5 = self.probability_engine.detect_pair() == - test_6 = self.probability_engine.detect_pair() == - test_7 = self.probability_engine.detect_pair() == - test_8 = self.probability_engine.detect_pair() == - test_9 = self.probability_engine.detect_pair() == - - passed = [] - failed = [] - passed.append('test_1') if test_1 else failed.append('test_1') - passed.append('test_2') if test_2 else failed.append('test_2') - passed.append('test_3') if test_3 else failed.append('test_3') - passed.append('test_4') if test_4 else failed.append('test_4') - passed.append('test_5') if test_5 else failed.append('test_5') - passed.append('test_6') if test_6 else failed.append('test_6') - passed.append('test_7') if test_7 else failed.append('test_7') - passed.append('test_8') if test_8 else failed.append('test_8') - passed.append('test_9') if test_9 else failed.append('test_9') - - print('Finished running pair Unit Tests') - if len(failed) == 0: - print('Passed all tests') - else: - print(f'Failed {len(failed)} tests') - print(f'Passed: {passed}') - print(f'Failed: {failed}') - - def test_quads(self): - print('==================================================') - print('Running quads Unit Tests') - - test_1 = self.probability_engine.detect_quads() == - test_2 = self.probability_engine.detect_quads() == - test_3 = self.probability_engine.detect_quads() == - test_4 = self.probability_engine.detect_quads() == - test_5 = self.probability_engine.detect_quads() == - test_6 = self.probability_engine.detect_quads() == - test_7 = self.probability_engine.detect_quads() == - test_8 = self.probability_engine.detect_quads() == - test_9 = self.probability_engine.detect_quads() == - - passed = [] - failed = [] - passed.append('test_1') if test_1 else failed.append('test_1') - passed.append('test_2') if test_2 else failed.append('test_2') - passed.append('test_3') if test_3 else failed.append('test_3') - passed.append('test_4') if test_4 else failed.append('test_4') - passed.append('test_5') if test_5 else failed.append('test_5') - passed.append('test_6') if test_6 else failed.append('test_6') - passed.append('test_7') if test_7 else failed.append('test_7') - passed.append('test_8') if test_8 else failed.append('test_8') - passed.append('test_9') if test_9 else failed.append('test_9') - - print('Finished running quads Unit Tests') - if len(failed) == 0: - print('Passed all tests') - else: - print(f'Failed {len(failed)} tests') - print(f'Passed: {passed}') - print(f'Failed: {failed}') - - def test_trips(self): - print('==================================================') - print('Running trips Unit Tests') - - test_1 = self.probability_engine.detect_trips() == - test_2 = self.probability_engine.detect_trips() == - test_3 = self.probability_engine.detect_trips() == - test_4 = self.probability_engine.detect_trips() == - test_5 = self.probability_engine.detect_trips() == - test_6 = self.probability_engine.detect_trips() == - test_7 = self.probability_engine.detect_trips() == - test_8 = self.probability_engine.detect_trips() == - test_9 = self.probability_engine.detect_trips() == - - passed = [] - failed = [] - passed.append('test_1') if test_1 else failed.append('test_1') - passed.append('test_2') if test_2 else failed.append('test_2') - passed.append('test_3') if test_3 else failed.append('test_3') - passed.append('test_4') if test_4 else failed.append('test_4') - passed.append('test_5') if test_5 else failed.append('test_5') - passed.append('test_6') if test_6 else failed.append('test_6') - passed.append('test_7') if test_7 else failed.append('test_7') - passed.append('test_8') if test_8 else failed.append('test_8') - passed.append('test_9') if test_9 else failed.append('test_9') - - print('Finished running trips Unit Tests') - if len(failed) == 0: - print('Passed all tests') - else: - print(f'Failed {len(failed)} tests') - print(f'Passed: {passed}') - print(f'Failed: {failed}') - - def test_straight(self): - print('==================================================') - print('Running straight Unit Tests') - - test_1 = self.probability_engine.detect_straight() == - test_2 = self.probability_engine.detect_straight() == - test_3 = self.probability_engine.detect_straight() == - test_4 = self.probability_engine.detect_straight() == - test_5 = self.probability_engine.detect_straight() == - test_6 = self.probability_engine.detect_straight() == - test_7 = self.probability_engine.detect_straight() == - test_8 = self.probability_engine.detect_straight() == - test_9 = self.probability_engine.detect_straight() == - - passed = [] - failed = [] - passed.append('test_1') if test_1 else failed.append('test_1') - passed.append('test_2') if test_2 else failed.append('test_2') - passed.append('test_3') if test_3 else failed.append('test_3') - passed.append('test_4') if test_4 else failed.append('test_4') - passed.append('test_5') if test_5 else failed.append('test_5') - passed.append('test_6') if test_6 else failed.append('test_6') - passed.append('test_7') if test_7 else failed.append('test_7') - passed.append('test_8') if test_8 else failed.append('test_8') - passed.append('test_9') if test_9 else failed.append('test_9') - - print('Finished running straight Unit Tests') - if len(failed) == 0: - print('Passed all tests') - else: - print(f'Failed {len(failed)} tests') - print(f'Passed: {passed}') - print(f'Failed: {failed}') - - def test_straight_flush(self): - print('==================================================') - print('Running straight_flush Unit Tests') - - test_1 = self.probability_engine.detect_straight_flush() == - test_2 = self.probability_engine.detect_straight_flush() == - test_3 = self.probability_engine.detect_straight_flush() == - test_4 = self.probability_engine.detect_straight_flush() == - test_5 = self.probability_engine.detect_straight_flush() == - test_6 = self.probability_engine.detect_straight_flush() == - test_7 = self.probability_engine.detect_straight_flush() == - test_8 = self.probability_engine.detect_straight_flush() == - test_9 = self.probability_engine.detect_straight_flush() == - - passed = [] - failed = [] - passed.append('test_1') if test_1 else failed.append('test_1') - passed.append('test_2') if test_2 else failed.append('test_2') - passed.append('test_3') if test_3 else failed.append('test_3') - passed.append('test_4') if test_4 else failed.append('test_4') - passed.append('test_5') if test_5 else failed.append('test_5') - passed.append('test_6') if test_6 else failed.append('test_6') - passed.append('test_7') if test_7 else failed.append('test_7') - passed.append('test_8') if test_8 else failed.append('test_8') - passed.append('test_9') if test_9 else failed.append('test_9') - - print('Finished running straight_flush Unit Tests') - if len(failed) == 0: - print('Passed all tests') - else: - print(f'Failed {len(failed)} tests') - print(f'Passed: {passed}') - print(f'Failed: {failed}') - - def test_two_pair(self): - print('==================================================') - print('Running two_pair Unit Tests') - - test_1 = self.probability_engine.detect_two_pair() == - test_2 = self.probability_engine.detect_two_pair() == - test_3 = self.probability_engine.detect_two_pair() == - test_4 = self.probability_engine.detect_two_pair() == - test_5 = self.probability_engine.detect_two_pair() == - test_6 = self.probability_engine.detect_two_pair() == - test_7 = self.probability_engine.detect_two_pair() == - test_8 = self.probability_engine.detect_two_pair() == - test_9 = self.probability_engine.detect_two_pair() == - - passed = [] - failed = [] - passed.append('test_1') if test_1 else failed.append('test_1') - passed.append('test_2') if test_2 else failed.append('test_2') - passed.append('test_3') if test_3 else failed.append('test_3') - passed.append('test_4') if test_4 else failed.append('test_4') - passed.append('test_5') if test_5 else failed.append('test_5') - passed.append('test_6') if test_6 else failed.append('test_6') - passed.append('test_7') if test_7 else failed.append('test_7') - passed.append('test_8') if test_8 else failed.append('test_8') - passed.append('test_9') if test_9 else failed.append('test_9') - - print('Finished running two_pair Unit Tests') - if len(failed) == 0: - print('Passed all tests') - else: - print(f'Failed {len(failed)} tests') - print(f'Passed: {passed}') - print(f'Failed: {failed}') - -if __name__ == '__main__': - unit_tests = Unit_Tests() +import eval7 +from probability_engine import Probability_Engine + +class Unit_Tests(): + def __init__(self): + self.probability_engine = Probability_Engine() + + def test_all(self): + print('==================================================') + print('Running all Unit Tests') + + detect_results = self.test_detect() + base_hole_cards_used_results = self.test_base_hole_cards_used() + + passed = [] + failed = [] + passed.append('test_detect') if detect_results else failed.append('test_detect') + passed.append('test_base_hole_cards_used') if base_hole_cards_used_results else failed.append('test_base_hole_cards_used') + + print('Finished running all Unit Tests') + if len(failed) == 0: + print('Passed all tests') + else: + print(f'Failed {len(failed)} tests') + print(f'Passed: {passed}') + print(f'Failed: {failed}') + + def test_detect(self): + print('==================================================') + print('Running detect Unit Tests') + + flush_results = self.test_flush() + full_house_results = self.test_full_house() + pair_results = self.test_pair() + quads_results = self.test_quads() + straight_results = self.test_straight() + straight_flush_results = self.test_straight_flush() + trips_results = self.test_trips() + two_pair_results = self.test_two_pair() + + passed = [] + failed = [] + passed.append('test_flush') if flush_results else failed.append('test_flush') + passed.append('test_full_house') if full_house_results else failed.append('test_full_house') + passed.append('test_pair') if pair_results else failed.append('test_pair') + passed.append('test_quads') if quads_results else failed.append('test_quads') + passed.append('test_straight') if straight_results else failed.append('test_straight') + passed.append('test_straight_flush') if straight_flush_results else failed.append('test_straight_flush') + passed.append('test_trips') if trips_results else failed.append('test_trips') + passed.append('test_two_pair') if two_pair_results else failed.append('test_two_pair') + + print('Finished running detect Unit Tests') + if len(failed) == 0: + print('Passed all tests') + else: + print(f'Failed {len(failed)} tests') + print(f'Passed: {passed}') + print(f'Failed: {failed}') + + def test_base_hole_cards_used(self): + print('==================================================') + print('Running base_hole_cards_used Unit Tests') + + test_1 = self.probability_engine.base_hole_cards_used([eval7.Card('Ac'), eval7.Card('Ad'), ], [eval7.Card('Ah'), eval7.Card('7c'), eval7.Card('6d'), ], 'Trips') == 2 + test_2 = self.probability_engine.base_hole_cards_used([eval7.Card('3h'), eval7.Card('4h'), eval7.Card('7h')], [eval7.Card('Ah'), eval7.Card('7c'), eval7.Card('6h')], 'Flush') == 3 + test_3 = self.probability_engine.base_hole_cards_used([eval7.Card('Ac'), eval7.Card('2d'), ], [eval7.Card('Ah'), eval7.Card('7c'), eval7.Card('6d')], 'Pair') == 1 + test_4 = self.probability_engine.base_hole_cards_used([eval7.Card('2h'), eval7.Card('Kd'), ], [eval7.Card('2d'), eval7.Card('Ks'), eval7.Card('6d'), eval7.Card('8d')], 'Two Pair') == 2 + test_5 = self.probability_engine.base_hole_cards_used([eval7.Card('Ac'), eval7.Card('Ad'), eval7.Card('Jc')], [eval7.Card('Ah'), eval7.Card('7c'), eval7.Card('6d'), eval7.Card('7h')], 'Full House') == 2 + test_6 = self.probability_engine.base_hole_cards_used([eval7.Card('Ac'), eval7.Card('Td'), ], [eval7.Card('Ah'), eval7.Card('7c'), eval7.Card('6d'), eval7.Card('5h'), eval7.Card('9h')], 'Pair') == 1 + test_7 = self.probability_engine.base_hole_cards_used([eval7.Card('Ac'), eval7.Card('8c'), eval7.Card('6d')], [eval7.Card('4h'), eval7.Card('4c'), eval7.Card('4d'), eval7.Card('2s'), eval7.Card('5s')], 'Trips') == 0 + + passed = [] + failed = [] + passed.append('test_1') if test_1 else failed.append('test_1') + passed.append('test_2') if test_2 else failed.append('test_2') + passed.append('test_3') if test_3 else failed.append('test_3') + passed.append('test_4') if test_4 else failed.append('test_4') + passed.append('test_5') if test_5 else failed.append('test_5') + passed.append('test_6') if test_6 else failed.append('test_6') + passed.append('test_7') if test_7 else failed.append('test_7') + + + print('Finished running base_hole_cards_used Unit Tests') + if len(failed) == 0: + print('Passed all tests') + else: + print(f'Failed {len(failed)} tests') + print(f'Passed: {passed}') + print(f'Failed: {failed}') + + def test_flush(self): + print('==================================================') + print('Running flush Unit Tests') + + test_1 = self.probability_engine.detect_flush() == + test_2 = self.probability_engine.detect_flush() == + test_3 = self.probability_engine.detect_flush() == + test_4 = self.probability_engine.detect_flush() == + test_5 = self.probability_engine.detect_flush() == + test_6 = self.probability_engine.detect_flush() == + test_7 = self.probability_engine.detect_flush() == + test_8 = self.probability_engine.detect_flush() == + test_9 = self.probability_engine.detect_flush() == + + passed = [] + failed = [] + passed.append('test_1') if test_1 else failed.append('test_1') + passed.append('test_2') if test_2 else failed.append('test_2') + passed.append('test_3') if test_3 else failed.append('test_3') + passed.append('test_4') if test_4 else failed.append('test_4') + passed.append('test_5') if test_5 else failed.append('test_5') + passed.append('test_6') if test_6 else failed.append('test_6') + passed.append('test_7') if test_7 else failed.append('test_7') + passed.append('test_8') if test_8 else failed.append('test_8') + passed.append('test_9') if test_9 else failed.append('test_9') + + print('Finished running flush Unit Tests') + if len(failed) == 0: + print('Passed all tests') + else: + print(f'Failed {len(failed)} tests') + print(f'Passed: {passed}') + print(f'Failed: {failed}') + + def test_full_house(self): + print('==================================================') + print('Running full_house Unit Tests') + + test_1 = self.probability_engine.detect_full_house() == + test_2 = self.probability_engine.detect_full_house() == + test_3 = self.probability_engine.detect_full_house() == + test_4 = self.probability_engine.detect_full_house() == + test_5 = self.probability_engine.detect_full_house() == + test_6 = self.probability_engine.detect_full_house() == + test_7 = self.probability_engine.detect_full_house() == + test_8 = self.probability_engine.detect_full_house() == + test_9 = self.probability_engine.detect_full_house() == + + passed = [] + failed = [] + passed.append('test_1') if test_1 else failed.append('test_1') + passed.append('test_2') if test_2 else failed.append('test_2') + passed.append('test_3') if test_3 else failed.append('test_3') + passed.append('test_4') if test_4 else failed.append('test_4') + passed.append('test_5') if test_5 else failed.append('test_5') + passed.append('test_6') if test_6 else failed.append('test_6') + passed.append('test_7') if test_7 else failed.append('test_7') + passed.append('test_8') if test_8 else failed.append('test_8') + passed.append('test_9') if test_9 else failed.append('test_9') + + print('Finished running full_house Unit Tests') + if len(failed) == 0: + print('Passed all tests') + else: + print(f'Failed {len(failed)} tests') + print(f'Passed: {passed}') + print(f'Failed: {failed}') + + def test_pair(self): + print('==================================================') + print('Running pair Unit Tests') + + test_1 = self.probability_engine.detect_pair() == + test_2 = self.probability_engine.detect_pair() == + test_3 = self.probability_engine.detect_pair() == + test_4 = self.probability_engine.detect_pair() == + test_5 = self.probability_engine.detect_pair() == + test_6 = self.probability_engine.detect_pair() == + test_7 = self.probability_engine.detect_pair() == + test_8 = self.probability_engine.detect_pair() == + test_9 = self.probability_engine.detect_pair() == + + passed = [] + failed = [] + passed.append('test_1') if test_1 else failed.append('test_1') + passed.append('test_2') if test_2 else failed.append('test_2') + passed.append('test_3') if test_3 else failed.append('test_3') + passed.append('test_4') if test_4 else failed.append('test_4') + passed.append('test_5') if test_5 else failed.append('test_5') + passed.append('test_6') if test_6 else failed.append('test_6') + passed.append('test_7') if test_7 else failed.append('test_7') + passed.append('test_8') if test_8 else failed.append('test_8') + passed.append('test_9') if test_9 else failed.append('test_9') + + print('Finished running pair Unit Tests') + if len(failed) == 0: + print('Passed all tests') + else: + print(f'Failed {len(failed)} tests') + print(f'Passed: {passed}') + print(f'Failed: {failed}') + + def test_quads(self): + print('==================================================') + print('Running quads Unit Tests') + + test_1 = self.probability_engine.detect_quads() == + test_2 = self.probability_engine.detect_quads() == + test_3 = self.probability_engine.detect_quads() == + test_4 = self.probability_engine.detect_quads() == + test_5 = self.probability_engine.detect_quads() == + test_6 = self.probability_engine.detect_quads() == + test_7 = self.probability_engine.detect_quads() == + test_8 = self.probability_engine.detect_quads() == + test_9 = self.probability_engine.detect_quads() == + + passed = [] + failed = [] + passed.append('test_1') if test_1 else failed.append('test_1') + passed.append('test_2') if test_2 else failed.append('test_2') + passed.append('test_3') if test_3 else failed.append('test_3') + passed.append('test_4') if test_4 else failed.append('test_4') + passed.append('test_5') if test_5 else failed.append('test_5') + passed.append('test_6') if test_6 else failed.append('test_6') + passed.append('test_7') if test_7 else failed.append('test_7') + passed.append('test_8') if test_8 else failed.append('test_8') + passed.append('test_9') if test_9 else failed.append('test_9') + + print('Finished running quads Unit Tests') + if len(failed) == 0: + print('Passed all tests') + else: + print(f'Failed {len(failed)} tests') + print(f'Passed: {passed}') + print(f'Failed: {failed}') + + def test_trips(self): + print('==================================================') + print('Running trips Unit Tests') + + test_1 = self.probability_engine.detect_trips() == + test_2 = self.probability_engine.detect_trips() == + test_3 = self.probability_engine.detect_trips() == + test_4 = self.probability_engine.detect_trips() == + test_5 = self.probability_engine.detect_trips() == + test_6 = self.probability_engine.detect_trips() == + test_7 = self.probability_engine.detect_trips() == + test_8 = self.probability_engine.detect_trips() == + test_9 = self.probability_engine.detect_trips() == + + passed = [] + failed = [] + passed.append('test_1') if test_1 else failed.append('test_1') + passed.append('test_2') if test_2 else failed.append('test_2') + passed.append('test_3') if test_3 else failed.append('test_3') + passed.append('test_4') if test_4 else failed.append('test_4') + passed.append('test_5') if test_5 else failed.append('test_5') + passed.append('test_6') if test_6 else failed.append('test_6') + passed.append('test_7') if test_7 else failed.append('test_7') + passed.append('test_8') if test_8 else failed.append('test_8') + passed.append('test_9') if test_9 else failed.append('test_9') + + print('Finished running trips Unit Tests') + if len(failed) == 0: + print('Passed all tests') + else: + print(f'Failed {len(failed)} tests') + print(f'Passed: {passed}') + print(f'Failed: {failed}') + + def test_straight(self): + print('==================================================') + print('Running straight Unit Tests') + + test_1 = self.probability_engine.detect_straight() == + test_2 = self.probability_engine.detect_straight() == + test_3 = self.probability_engine.detect_straight() == + test_4 = self.probability_engine.detect_straight() == + test_5 = self.probability_engine.detect_straight() == + test_6 = self.probability_engine.detect_straight() == + test_7 = self.probability_engine.detect_straight() == + test_8 = self.probability_engine.detect_straight() == + test_9 = self.probability_engine.detect_straight() == + + passed = [] + failed = [] + passed.append('test_1') if test_1 else failed.append('test_1') + passed.append('test_2') if test_2 else failed.append('test_2') + passed.append('test_3') if test_3 else failed.append('test_3') + passed.append('test_4') if test_4 else failed.append('test_4') + passed.append('test_5') if test_5 else failed.append('test_5') + passed.append('test_6') if test_6 else failed.append('test_6') + passed.append('test_7') if test_7 else failed.append('test_7') + passed.append('test_8') if test_8 else failed.append('test_8') + passed.append('test_9') if test_9 else failed.append('test_9') + + print('Finished running straight Unit Tests') + if len(failed) == 0: + print('Passed all tests') + else: + print(f'Failed {len(failed)} tests') + print(f'Passed: {passed}') + print(f'Failed: {failed}') + + def test_straight_flush(self): + print('==================================================') + print('Running straight_flush Unit Tests') + + test_1 = self.probability_engine.detect_straight_flush() == + test_2 = self.probability_engine.detect_straight_flush() == + test_3 = self.probability_engine.detect_straight_flush() == + test_4 = self.probability_engine.detect_straight_flush() == + test_5 = self.probability_engine.detect_straight_flush() == + test_6 = self.probability_engine.detect_straight_flush() == + test_7 = self.probability_engine.detect_straight_flush() == + test_8 = self.probability_engine.detect_straight_flush() == + test_9 = self.probability_engine.detect_straight_flush() == + + passed = [] + failed = [] + passed.append('test_1') if test_1 else failed.append('test_1') + passed.append('test_2') if test_2 else failed.append('test_2') + passed.append('test_3') if test_3 else failed.append('test_3') + passed.append('test_4') if test_4 else failed.append('test_4') + passed.append('test_5') if test_5 else failed.append('test_5') + passed.append('test_6') if test_6 else failed.append('test_6') + passed.append('test_7') if test_7 else failed.append('test_7') + passed.append('test_8') if test_8 else failed.append('test_8') + passed.append('test_9') if test_9 else failed.append('test_9') + + print('Finished running straight_flush Unit Tests') + if len(failed) == 0: + print('Passed all tests') + else: + print(f'Failed {len(failed)} tests') + print(f'Passed: {passed}') + print(f'Failed: {failed}') + + def test_two_pair(self): + print('==================================================') + print('Running two_pair Unit Tests') + + test_1 = self.probability_engine.detect_two_pair() == + test_2 = self.probability_engine.detect_two_pair() == + test_3 = self.probability_engine.detect_two_pair() == + test_4 = self.probability_engine.detect_two_pair() == + test_5 = self.probability_engine.detect_two_pair() == + test_6 = self.probability_engine.detect_two_pair() == + test_7 = self.probability_engine.detect_two_pair() == + test_8 = self.probability_engine.detect_two_pair() == + test_9 = self.probability_engine.detect_two_pair() == + + passed = [] + failed = [] + passed.append('test_1') if test_1 else failed.append('test_1') + passed.append('test_2') if test_2 else failed.append('test_2') + passed.append('test_3') if test_3 else failed.append('test_3') + passed.append('test_4') if test_4 else failed.append('test_4') + passed.append('test_5') if test_5 else failed.append('test_5') + passed.append('test_6') if test_6 else failed.append('test_6') + passed.append('test_7') if test_7 else failed.append('test_7') + passed.append('test_8') if test_8 else failed.append('test_8') + passed.append('test_9') if test_9 else failed.append('test_9') + + print('Finished running two_pair Unit Tests') + if len(failed) == 0: + print('Passed all tests') + else: + print(f'Failed {len(failed)} tests') + print(f'Passed: {passed}') + print(f'Failed: {failed}') + +if __name__ == '__main__': + unit_tests = Unit_Tests() unit_tests.test_all() \ No newline at end of file From c0095ef6e4834064b10f9b2c8289616ca6f5f233 Mon Sep 17 00:00:00 2001 From: Brian Le Date: Tue, 23 Jan 2024 17:19:51 -0500 Subject: [PATCH 11/15] Finished Monte Carlo Test --- python_skeleton/skeleton/monte_carlo_tests.py | 310 +++++++++++++++++- .../skeleton/probability_engine.py | 16 +- python_skeleton/skeleton/unit_tests.py | 147 +++------ 3 files changed, 366 insertions(+), 107 deletions(-) diff --git a/python_skeleton/skeleton/monte_carlo_tests.py b/python_skeleton/skeleton/monte_carlo_tests.py index e6ca352..130a4b7 100644 --- a/python_skeleton/skeleton/monte_carlo_tests.py +++ b/python_skeleton/skeleton/monte_carlo_tests.py @@ -1 +1,309 @@ -from probability_engine import Probability_Engine \ No newline at end of file +import time +import eval7 + +from probability_engine import Probability_Engine + +class Pseudo_Round_State(): + def __init__(self): + self.street = 0 + self.deck = [] + +class Monte_Carlo_Tests(): + def __init__(self): + self.probability_engine = Probability_Engine() + + def test_all(self, iters, precision): + print('=================================================') + print('Testing Probability Engine on the Flop, Turn, and River') + + flop_results = self.test_flop(iters, precision) + turn_results = self.test_turn(iters, precision) + river_results = self.test_river(iters, precision) + + print('=================================================') + print(f'Ran {3 * iters} tests, {iters} tests on each flop, turn, and river, and half with auction, half without auction') + print(f'Average Auction Diff: {flop_results[0] + turn_results[0] + river_results[0] / (iters * 3)}') + print(f'Average Non Auction Diff: {flop_results[1] + turn_results[1] + river_results[1] / (iters * 3)}') + print(f'Average Engine Runtime: {flop_results[2] + turn_results[2] + river_results[2] / (iters * 3)}') + print(f'Average Sim Runtime: {flop_results[3] + turn_results[3] + river_results[3] / (iters * 3)}') + + return (flop_results[0] + turn_results[0] + river_results[0] / (iters * 3), + flop_results[1] + turn_results[1] + river_results[1] / (iters * 3), + flop_results[2] + turn_results[2] + river_results[2] / (iters * 3), + flop_results[3] + turn_results[3] + river_results[3] / (iters * 3)) + + def test_flop(self, iters, precision): + print('=================================================') + print(f'Testing Probability Engine on the Flop') + + engine_runtime = 0 + sim_runtime = 0 + + print('=================================================') + print('Testing with auction card') + + avg_auction_diff = 0 + + for _ in range(iters // 2): + print('-------------------------') + + deck = eval7.Deck() + deck.shuffle() + draw = deck.peek(6) + my_cards = [str(card) for card in draw[:3]] + board_cards = [str(card) for card in draw[3:]] + + round_state = Pseudo_Round_State() + round_state.street = 3 + round_state.deck = board_cards + + engine_start = time.time() + engine_probability = self.probability_engine.calculate_win_probability(my_cards, round_state) + engine_end = time.time() + + sim_start = time.time() + monte_carlo_probability = self.probability_engine.monte_carlo_flop_and_turn(draw[:3], draw[3:], deck, precision) + sim_end = time.time() + + net_diff = abs(engine_probability - monte_carlo_probability) + + avg_auction_diff += net_diff + engine_runtime += engine_end - engine_start + sim_runtime += sim_end - sim_start + + print('Probabilities') + print(f'Engine: {engine_probability} | Sim: {monte_carlo_probability} | Diff: {net_diff}') + print('Runtimes') + print(f'Engine: {engine_end - engine_start} | Sim: {sim_end - sim_start} | Diff: {abs((engine_end - engine_start) - (sim_end - sim_start))}') + + print('=================================================') + print('Testing without auction card') + + avg_non_auction_diff = 0 + + for _ in range(iters // 2): + print('-------------------------') + + deck = eval7.Deck() + deck.shuffle() + draw = deck.peek(5) + my_cards = [str(card) for card in draw[:2]] + board_cards = [str(card) for card in draw[2:]] + + round_state = Pseudo_Round_State() + round_state.street = 3 + round_state.deck = board_cards + + engine_start = time.time() + engine_probability = self.probability_engine.calculate_win_probability(my_cards, round_state) + engine_end = time.time() + + sim_start = time.time() + monte_carlo_probability = self.probability_engine.monte_carlo_flop_and_turn(draw[:2], draw[2:], deck, precision) + sim_end = time.time() + + net_diff = abs(engine_probability - monte_carlo_probability) + + avg_non_auction_diff += net_diff + engine_runtime += engine_end - engine_start + sim_runtime += sim_end - sim_start + + print('Probabilities') + print(f'Engine: {engine_probability} | Sim: {monte_carlo_probability} | Diff: {net_diff}') + print('Runtimes') + print(f'Engine: {engine_end - engine_start} | Sim: {sim_end - sim_start} | Diff: {abs((engine_end - engine_start) - (sim_end - sim_start))}') + + print('=================================================') + print(f'Ran {iters} tests, half with auction and half without auction') + print(f'Average Auction Diff: {avg_auction_diff / (iters // 2)}') + print(f'Average Non Auction Diff: {avg_non_auction_diff / (iters // 2)}') + print(f'Average Engine Runtime: {engine_runtime / (iters // 2)}') + print(f'Average Sim Runtime: {sim_runtime / (iters // 2)}') + + return (avg_auction_diff / (iters // 2), avg_non_auction_diff / (iters // 2), engine_runtime / (iters // 2), sim_runtime / (iters // 2)) + + + def test_turn(self, iters, precision): + print('=================================================') + print(f'Testing Probability Engine on the Turn') + + engine_runtime = 0 + sim_runtime = 0 + + print('=================================================') + print('Testing with auction card') + + avg_auction_diff = 0 + + for _ in range(iters // 2): + print('-------------------------') + + deck = eval7.Deck() + deck.shuffle() + draw = deck.peek(7) + my_cards = [str(card) for card in draw[:3]] + board_cards = [str(card) for card in draw[3:]] + + round_state = Pseudo_Round_State() + round_state.street = 3 + round_state.deck = board_cards + + engine_start = time.time() + engine_probability = self.probability_engine.calculate_win_probability(my_cards, round_state) + engine_end = time.time() + + sim_start = time.time() + monte_carlo_probability = self.probability_engine.monte_carlo_flop_and_turn(draw[:3], draw[3:], deck, precision) + sim_end = time.time() + + net_diff = abs(engine_probability - monte_carlo_probability) + + avg_auction_diff += net_diff + engine_runtime += engine_end - engine_start + sim_runtime += sim_end - sim_start + + print('Probabilities') + print(f'Engine: {engine_probability} | Sim: {monte_carlo_probability} | Diff: {net_diff}') + print('Runtimes') + print(f'Engine: {engine_end - engine_start} | Sim: {sim_end - sim_start} | Diff: {abs((engine_end - engine_start) - (sim_end - sim_start))}') + + print('=================================================') + print('Testing without auction card') + + avg_non_auction_diff = 0 + + for _ in range(iters // 2): + print('-------------------------') + + deck = eval7.Deck() + deck.shuffle() + draw = deck.peek(6) + my_cards = [str(card) for card in draw[:2]] + board_cards = [str(card) for card in draw[2:]] + + round_state = Pseudo_Round_State() + round_state.street = 3 + round_state.deck = board_cards + + engine_start = time.time() + engine_probability = self.probability_engine.calculate_win_probability(my_cards, round_state) + engine_end = time.time() + + sim_start = time.time() + monte_carlo_probability = self.probability_engine.monte_carlo_flop_and_turn(draw[:2], draw[2:], deck, precision) + sim_end = time.time() + + net_diff = abs(engine_probability - monte_carlo_probability) + + avg_non_auction_diff += net_diff + engine_runtime += engine_end - engine_start + sim_runtime += sim_end - sim_start + + print('Probabilities') + print(f'Engine: {engine_probability} | Sim: {monte_carlo_probability} | Diff: {net_diff}') + print('Runtimes') + print(f'Engine: {engine_end - engine_start} | Sim: {sim_end - sim_start} | Diff: {abs((engine_end - engine_start) - (sim_end - sim_start))}') + + print('=================================================') + print(f'Ran {iters} tests, half with auction and half without auction') + print(f'Average Auction Diff: {avg_auction_diff / (iters // 2)}') + print(f'Average Non Auction Diff: {avg_non_auction_diff / (iters // 2)}') + print(f'Average Engine Runtime: {engine_runtime / (iters // 2)}') + print(f'Average Sim Runtime: {sim_runtime / (iters // 2)}') + + return (avg_auction_diff / (iters // 2), avg_non_auction_diff / (iters // 2), engine_runtime / (iters // 2), sim_runtime / (iters // 2)) + + def test_river(self, iters, precision): + print('=================================================') + print(f'Testing Probability Engine on the River') + + engine_runtime = 0 + sim_runtime = 0 + + print('=================================================') + print('Testing with auction card') + + avg_auction_diff = 0 + + for _ in range(iters // 2): + print('-------------------------') + + deck = eval7.Deck() + deck.shuffle() + draw = deck.peek(8) + my_cards = [str(card) for card in draw[:3]] + board_cards = [str(card) for card in draw[3:]] + + round_state = Pseudo_Round_State() + round_state.street = 3 + round_state.deck = board_cards + + engine_start = time.time() + engine_probability = self.probability_engine.calculate_win_probability(my_cards, round_state) + engine_end = time.time() + + sim_start = time.time() + monte_carlo_probability = self.probability_engine.monte_carlo_flop_and_turn(draw[:3], draw[3:], deck, precision) + sim_end = time.time() + + net_diff = abs(engine_probability - monte_carlo_probability) + + avg_auction_diff += net_diff + engine_runtime += engine_end - engine_start + sim_runtime += sim_end - sim_start + + print('Probabilities') + print(f'Engine: {engine_probability} | Sim: {monte_carlo_probability} | Diff: {net_diff}') + print('Runtimes') + print(f'Engine: {engine_end - engine_start} | Sim: {sim_end - sim_start} | Diff: {abs((engine_end - engine_start) - (sim_end - sim_start))}') + + print('=================================================') + print('Testing without auction card') + + avg_non_auction_diff = 0 + + for _ in range(iters // 2): + print('-------------------------') + + deck = eval7.Deck() + deck.shuffle() + draw = deck.peek(7) + my_cards = [str(card) for card in draw[:2]] + board_cards = [str(card) for card in draw[2:]] + + round_state = Pseudo_Round_State() + round_state.street = 3 + round_state.deck = board_cards + + engine_start = time.time() + engine_probability = self.probability_engine.calculate_win_probability(my_cards, round_state) + engine_end = time.time() + + sim_start = time.time() + monte_carlo_probability = self.probability_engine.monte_carlo_flop_and_turn(draw[:2], draw[2:], deck, precision) + sim_end = time.time() + + net_diff = abs(engine_probability - monte_carlo_probability) + + avg_non_auction_diff += net_diff + engine_runtime += engine_end - engine_start + sim_runtime += sim_end - sim_start + + print('Probabilities') + print(f'Engine: {engine_probability} | Sim: {monte_carlo_probability} | Diff: {net_diff}') + print('Runtimes') + print(f'Engine: {engine_end - engine_start} | Sim: {sim_end - sim_start} | Diff: {abs((engine_end - engine_start) - (sim_end - sim_start))}') + + print('=================================================') + print(f'Ran {iters} tests, half with auction and half without auction') + print(f'Average Auction Diff: {avg_auction_diff / (iters // 2)}') + print(f'Average Non Auction Diff: {avg_non_auction_diff / (iters // 2)}') + print(f'Average Engine Runtime: {engine_runtime / (iters // 2)}') + print(f'Average Sim Runtime: {sim_runtime / (iters // 2)}') + + return (avg_auction_diff / (iters // 2), avg_non_auction_diff / (iters // 2), engine_runtime / (iters // 2), sim_runtime / (iters // 2)) + + +if __name__ == '__main__': + test_suite = Monte_Carlo_Tests() + test_suite.test_all(2000, 2000) \ No newline at end of file diff --git a/python_skeleton/skeleton/probability_engine.py b/python_skeleton/skeleton/probability_engine.py index a810229..bf43f89 100644 --- a/python_skeleton/skeleton/probability_engine.py +++ b/python_skeleton/skeleton/probability_engine.py @@ -6,7 +6,8 @@ def __init__(self): def calculate_win_probability(self, my_cards, round_state): ''' - Calculates win probability given hand. + Calculates win probability given hand during flop, turn, and river. + (Preflop and auction uses hole_strengths table) Considers currently revealed cards, potential strong hands (outs), and monte carlo sim. @@ -26,8 +27,10 @@ def calculate_win_probability(self, my_cards, round_state): if round_state.street == 3: board_cards = [eval7.Card(card) for card in round_state.deck[:3]] - else: + elif round_state.street == 4: board_cards = [eval7.Card(card) for card in round_state.deck[:4]] + else: + board_cards = [eval7.Card(card) for card in round_state.deck[:5]] total_cards = my_cards + board_cards @@ -55,7 +58,12 @@ def calculate_win_probability(self, my_cards, round_state): # Calculates winrate with currently revealed cards base_probability = hand_strengths[hand_type] * hole_factors[self.base_hole_cards_used(my_cards, board_cards, hand_type)] + + # On the river + if len(board_cards) == 5: + return base_probability + # On the flop and turn # Calculates potential hands and probability of hitting them (post-flop) # Based on the most likely hands, calculate a scaled winrate given we hit if hand_type in {'Straight Flush', 'Quads', 'Full House', 'Flush', 'Straight'}: @@ -108,7 +116,9 @@ def calculate_win_probability(self, my_cards, round_state): most_probable_out = max(flush_odds, full_house_odds, quads_odds, two_pair_odds, trips_odds, straight_odds, straight_flush_odds, key=lambda odds: odds[0]) potential_probability = most_probable_out[0] * hole_factors[most_probable_out[1]] - if most_probable_out == flush_odds: + if potential_probability == 0: + potential_probability = base_probability + elif most_probable_out == flush_odds: potential_probability *= hand_strengths['Flush'] elif most_probable_out == full_house_odds: potential_probability *= hand_strengths['Full House'] diff --git a/python_skeleton/skeleton/unit_tests.py b/python_skeleton/skeleton/unit_tests.py index 60350c6..0f80087 100644 --- a/python_skeleton/skeleton/unit_tests.py +++ b/python_skeleton/skeleton/unit_tests.py @@ -1,4 +1,5 @@ import eval7 + from probability_engine import Probability_Engine class Unit_Tests(): @@ -92,15 +93,11 @@ def test_flush(self): print('==================================================') print('Running flush Unit Tests') - test_1 = self.probability_engine.detect_flush() == - test_2 = self.probability_engine.detect_flush() == - test_3 = self.probability_engine.detect_flush() == - test_4 = self.probability_engine.detect_flush() == - test_5 = self.probability_engine.detect_flush() == - test_6 = self.probability_engine.detect_flush() == - test_7 = self.probability_engine.detect_flush() == - test_8 = self.probability_engine.detect_flush() == - test_9 = self.probability_engine.detect_flush() == + test_1 = self.probability_engine.detect_flush([eval7.Card('Ac'), eval7.Card('2h')], [eval7.Card('3h'), eval7.Card('4h'), eval7.Card('5d')]) == (1/16,1) + test_2 = self.probability_engine.detect_flush([eval7.Card('2c'), eval7.Card('5s'), eval7.Card('3s')], [eval7.Card('5h'), eval7.Card('9d'), eval7.Card('Kc')]) == (0,0) + test_3 = self.probability_engine.detect_flush([eval7.Card('3d'), eval7.Card('7d')], [eval7.Card('4h'), eval7.Card('2h'), eval7.Card('Td'), eval7.Card('Ad')]) == (1/4,2) + test_4 = self.probability_engine.detect_flush([eval7.Card('Jc'), eval7.Card('Tc'), eval7.Card('2c')], [eval7.Card('5h'), eval7.Card('Ad'), eval7.Card('3d'), eval7.Card('4s')]) == (0,0) + test_5 = self.probability_engine.detect_flush([eval7.Card('Jc'), eval7.Card('Tc'), eval7.Card('2c')], [eval7.Card('5h'), eval7.Card('Ad'), eval7.Card('3d'), eval7.Card('4c')]) == (1/4,3) passed = [] failed = [] @@ -109,10 +106,6 @@ def test_flush(self): passed.append('test_3') if test_3 else failed.append('test_3') passed.append('test_4') if test_4 else failed.append('test_4') passed.append('test_5') if test_5 else failed.append('test_5') - passed.append('test_6') if test_6 else failed.append('test_6') - passed.append('test_7') if test_7 else failed.append('test_7') - passed.append('test_8') if test_8 else failed.append('test_8') - passed.append('test_9') if test_9 else failed.append('test_9') print('Finished running flush Unit Tests') if len(failed) == 0: @@ -126,27 +119,17 @@ def test_full_house(self): print('==================================================') print('Running full_house Unit Tests') - test_1 = self.probability_engine.detect_full_house() == - test_2 = self.probability_engine.detect_full_house() == - test_3 = self.probability_engine.detect_full_house() == - test_4 = self.probability_engine.detect_full_house() == - test_5 = self.probability_engine.detect_full_house() == - test_6 = self.probability_engine.detect_full_house() == - test_7 = self.probability_engine.detect_full_house() == - test_8 = self.probability_engine.detect_full_house() == - test_9 = self.probability_engine.detect_full_house() == - + test_1 = self.probability_engine.detect_full_house([eval7.Card('3h'), eval7.Card('3c')], [eval7.Card('5h'), eval7.Card('5c'), eval7.Card('2d')], 'Two Pair') == (0.17,2) + test_2 = self.probability_engine.detect_full_house([eval7.Card('Ac'), eval7.Card('Ad'), eval7.Card('Ah')], [eval7.Card('4h'), eval7.Card('5d'), eval7.Card('3c')], 'Trips') == (0.37,3) + test_3 = self.probability_engine.detect_full_house([eval7.Card('3h'), eval7.Card('3c')], [eval7.Card('7c'), eval7.Card('8d'), eval7.Card('Ts'), eval7.Card('4h')], 'Pair') == (0,0) + test_4 = self.probability_engine.detect_full_house([eval7.Card('3h'), eval7.Card('3c'), eval7.Card('7d')], [eval7.Card('7c'), eval7.Card('8d'), eval7.Card('Ts'), eval7.Card('4h')], 'Two Pair') == (0.5,3) + passed = [] failed = [] passed.append('test_1') if test_1 else failed.append('test_1') passed.append('test_2') if test_2 else failed.append('test_2') passed.append('test_3') if test_3 else failed.append('test_3') passed.append('test_4') if test_4 else failed.append('test_4') - passed.append('test_5') if test_5 else failed.append('test_5') - passed.append('test_6') if test_6 else failed.append('test_6') - passed.append('test_7') if test_7 else failed.append('test_7') - passed.append('test_8') if test_8 else failed.append('test_8') - passed.append('test_9') if test_9 else failed.append('test_9') print('Finished running full_house Unit Tests') if len(failed) == 0: @@ -160,27 +143,15 @@ def test_pair(self): print('==================================================') print('Running pair Unit Tests') - test_1 = self.probability_engine.detect_pair() == - test_2 = self.probability_engine.detect_pair() == - test_3 = self.probability_engine.detect_pair() == - test_4 = self.probability_engine.detect_pair() == - test_5 = self.probability_engine.detect_pair() == - test_6 = self.probability_engine.detect_pair() == - test_7 = self.probability_engine.detect_pair() == - test_8 = self.probability_engine.detect_pair() == - test_9 = self.probability_engine.detect_pair() == + test_1 = round(self.probability_engine.detect_pair([eval7.Card('2s'), eval7.Card('3h')], [eval7.Card('6d'), eval7.Card('7s'), eval7.Card('Tc')]), 2) == (0.25,1) + test_2 = round(self.probability_engine.detect_pair([eval7.Card('2s'), eval7.Card('3h'), eval7.Card('8d')], [eval7.Card('6d'), eval7.Card('7s'), eval7.Card('Tc')]), 2) == (0.37,1) + test_3 = round(self.probability_engine.detect_pair([eval7.Card('2s'), eval7.Card('3h')], [eval7.Card('6d'), eval7.Card('7s'), eval7.Card('Tc')], eval7.Card('Ac'), 2)) == (0.14,1) passed = [] failed = [] passed.append('test_1') if test_1 else failed.append('test_1') passed.append('test_2') if test_2 else failed.append('test_2') passed.append('test_3') if test_3 else failed.append('test_3') - passed.append('test_4') if test_4 else failed.append('test_4') - passed.append('test_5') if test_5 else failed.append('test_5') - passed.append('test_6') if test_6 else failed.append('test_6') - passed.append('test_7') if test_7 else failed.append('test_7') - passed.append('test_8') if test_8 else failed.append('test_8') - passed.append('test_9') if test_9 else failed.append('test_9') print('Finished running pair Unit Tests') if len(failed) == 0: @@ -194,15 +165,12 @@ def test_quads(self): print('==================================================') print('Running quads Unit Tests') - test_1 = self.probability_engine.detect_quads() == - test_2 = self.probability_engine.detect_quads() == - test_3 = self.probability_engine.detect_quads() == - test_4 = self.probability_engine.detect_quads() == - test_5 = self.probability_engine.detect_quads() == - test_6 = self.probability_engine.detect_quads() == - test_7 = self.probability_engine.detect_quads() == - test_8 = self.probability_engine.detect_quads() == - test_9 = self.probability_engine.detect_quads() == + test_1 = self.probability_engine.detect_quads([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + test_2 = self.probability_engine.detect_quads([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + test_3 = self.probability_engine.detect_quads([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + test_4 = self.probability_engine.detect_quads([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + test_5 = self.probability_engine.detect_quads([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + test_6 = self.probability_engine.detect_quads([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == passed = [] failed = [] @@ -212,9 +180,6 @@ def test_quads(self): passed.append('test_4') if test_4 else failed.append('test_4') passed.append('test_5') if test_5 else failed.append('test_5') passed.append('test_6') if test_6 else failed.append('test_6') - passed.append('test_7') if test_7 else failed.append('test_7') - passed.append('test_8') if test_8 else failed.append('test_8') - passed.append('test_9') if test_9 else failed.append('test_9') print('Finished running quads Unit Tests') if len(failed) == 0: @@ -228,15 +193,12 @@ def test_trips(self): print('==================================================') print('Running trips Unit Tests') - test_1 = self.probability_engine.detect_trips() == - test_2 = self.probability_engine.detect_trips() == - test_3 = self.probability_engine.detect_trips() == - test_4 = self.probability_engine.detect_trips() == - test_5 = self.probability_engine.detect_trips() == - test_6 = self.probability_engine.detect_trips() == - test_7 = self.probability_engine.detect_trips() == - test_8 = self.probability_engine.detect_trips() == - test_9 = self.probability_engine.detect_trips() == + test_1 = self.probability_engine.detect_trips([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + test_2 = self.probability_engine.detect_trips([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + test_3 = self.probability_engine.detect_trips([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + test_4 = self.probability_engine.detect_trips([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + test_5 = self.probability_engine.detect_trips([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + test_6 = self.probability_engine.detect_trips([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == passed = [] failed = [] @@ -246,9 +208,6 @@ def test_trips(self): passed.append('test_4') if test_4 else failed.append('test_4') passed.append('test_5') if test_5 else failed.append('test_5') passed.append('test_6') if test_6 else failed.append('test_6') - passed.append('test_7') if test_7 else failed.append('test_7') - passed.append('test_8') if test_8 else failed.append('test_8') - passed.append('test_9') if test_9 else failed.append('test_9') print('Finished running trips Unit Tests') if len(failed) == 0: @@ -262,15 +221,12 @@ def test_straight(self): print('==================================================') print('Running straight Unit Tests') - test_1 = self.probability_engine.detect_straight() == - test_2 = self.probability_engine.detect_straight() == - test_3 = self.probability_engine.detect_straight() == - test_4 = self.probability_engine.detect_straight() == - test_5 = self.probability_engine.detect_straight() == - test_6 = self.probability_engine.detect_straight() == - test_7 = self.probability_engine.detect_straight() == - test_8 = self.probability_engine.detect_straight() == - test_9 = self.probability_engine.detect_straight() == + test_1 = self.probability_engine.detect_straight([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + test_2 = self.probability_engine.detect_straight([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + test_3 = self.probability_engine.detect_straight([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + test_4 = self.probability_engine.detect_straight([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + test_5 = self.probability_engine.detect_straight([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + test_6 = self.probability_engine.detect_straight([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == passed = [] failed = [] @@ -280,9 +236,6 @@ def test_straight(self): passed.append('test_4') if test_4 else failed.append('test_4') passed.append('test_5') if test_5 else failed.append('test_5') passed.append('test_6') if test_6 else failed.append('test_6') - passed.append('test_7') if test_7 else failed.append('test_7') - passed.append('test_8') if test_8 else failed.append('test_8') - passed.append('test_9') if test_9 else failed.append('test_9') print('Finished running straight Unit Tests') if len(failed) == 0: @@ -296,15 +249,12 @@ def test_straight_flush(self): print('==================================================') print('Running straight_flush Unit Tests') - test_1 = self.probability_engine.detect_straight_flush() == - test_2 = self.probability_engine.detect_straight_flush() == - test_3 = self.probability_engine.detect_straight_flush() == - test_4 = self.probability_engine.detect_straight_flush() == - test_5 = self.probability_engine.detect_straight_flush() == - test_6 = self.probability_engine.detect_straight_flush() == - test_7 = self.probability_engine.detect_straight_flush() == - test_8 = self.probability_engine.detect_straight_flush() == - test_9 = self.probability_engine.detect_straight_flush() == + test_1 = self.probability_engine.detect_straight_flush([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + test_2 = self.probability_engine.detect_straight_flush([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + test_3 = self.probability_engine.detect_straight_flush([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + test_4 = self.probability_engine.detect_straight_flush([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + test_5 = self.probability_engine.detect_straight_flush([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + test_6 = self.probability_engine.detect_straight_flush([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == passed = [] failed = [] @@ -314,9 +264,6 @@ def test_straight_flush(self): passed.append('test_4') if test_4 else failed.append('test_4') passed.append('test_5') if test_5 else failed.append('test_5') passed.append('test_6') if test_6 else failed.append('test_6') - passed.append('test_7') if test_7 else failed.append('test_7') - passed.append('test_8') if test_8 else failed.append('test_8') - passed.append('test_9') if test_9 else failed.append('test_9') print('Finished running straight_flush Unit Tests') if len(failed) == 0: @@ -330,15 +277,12 @@ def test_two_pair(self): print('==================================================') print('Running two_pair Unit Tests') - test_1 = self.probability_engine.detect_two_pair() == - test_2 = self.probability_engine.detect_two_pair() == - test_3 = self.probability_engine.detect_two_pair() == - test_4 = self.probability_engine.detect_two_pair() == - test_5 = self.probability_engine.detect_two_pair() == - test_6 = self.probability_engine.detect_two_pair() == - test_7 = self.probability_engine.detect_two_pair() == - test_8 = self.probability_engine.detect_two_pair() == - test_9 = self.probability_engine.detect_two_pair() == + test_1 = self.probability_engine.detect_two_pair([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')], '') == + test_2 = self.probability_engine.detect_two_pair([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')], '') == + test_3 = self.probability_engine.detect_two_pair([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')], '') == + test_4 = self.probability_engine.detect_two_pair([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')], '') == + test_5 = self.probability_engine.detect_two_pair([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')], '') == + test_6 = self.probability_engine.detect_two_pair([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')], '') == passed = [] failed = [] @@ -348,9 +292,6 @@ def test_two_pair(self): passed.append('test_4') if test_4 else failed.append('test_4') passed.append('test_5') if test_5 else failed.append('test_5') passed.append('test_6') if test_6 else failed.append('test_6') - passed.append('test_7') if test_7 else failed.append('test_7') - passed.append('test_8') if test_8 else failed.append('test_8') - passed.append('test_9') if test_9 else failed.append('test_9') print('Finished running two_pair Unit Tests') if len(failed) == 0: From b7ee60f455c180cc929851458184e080281d4838 Mon Sep 17 00:00:00 2001 From: Brian Le Date: Thu, 25 Jan 2024 16:34:50 -0500 Subject: [PATCH 12/15] New Changes --- .gitignore | 1 + python_skeleton/skeleton/monte_carlo_tests.py | 8 +- .../skeleton/probability_engine.py | 4 +- python_skeleton/skeleton/unit_tests.py | 260 +++++++++++------- 4 files changed, 166 insertions(+), 107 deletions(-) diff --git a/.gitignore b/.gitignore index 0701b75..39bdde7 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ A.txt B.txt gamelog.txt game_log_analyze.txt +monte_carlo_test_logs.txt *.class .DS_Store .idea/ diff --git a/python_skeleton/skeleton/monte_carlo_tests.py b/python_skeleton/skeleton/monte_carlo_tests.py index 130a4b7..c678d46 100644 --- a/python_skeleton/skeleton/monte_carlo_tests.py +++ b/python_skeleton/skeleton/monte_carlo_tests.py @@ -1,5 +1,6 @@ import time import eval7 +import sys from probability_engine import Probability_Engine @@ -305,5 +306,10 @@ def test_river(self, iters, precision): if __name__ == '__main__': + temp = sys.stdout + sys.stdout = open('monte_carlo_test_logs.txt','wt') + test_suite = Monte_Carlo_Tests() - test_suite.test_all(2000, 2000) \ No newline at end of file + test_suite.test_all(2000, 2000) + + temp = sys.stdout \ No newline at end of file diff --git a/python_skeleton/skeleton/probability_engine.py b/python_skeleton/skeleton/probability_engine.py index bf43f89..de612b2 100644 --- a/python_skeleton/skeleton/probability_engine.py +++ b/python_skeleton/skeleton/probability_engine.py @@ -471,7 +471,7 @@ def detect_trips(self, my_cards, board_cards): total_cards = my_cards + board_cards for card in total_cards: card = str(card) - ranks[card[1]] += 1 + ranks[card[0]] += 1 highest_quantity = max(ranks.values()) @@ -517,7 +517,7 @@ def detect_quads(self, my_cards, board_cards): total_cards = my_cards + board_cards for card in total_cards: card = str(card) - ranks[card[1]] += 1 + ranks[card[0]] += 1 highest_quantity = max(ranks.values()) diff --git a/python_skeleton/skeleton/unit_tests.py b/python_skeleton/skeleton/unit_tests.py index 3b9f816..1d51504 100644 --- a/python_skeleton/skeleton/unit_tests.py +++ b/python_skeleton/skeleton/unit_tests.py @@ -18,6 +18,7 @@ def test_all(self): passed.append('test_detect') if detect_results else failed.append('test_detect') passed.append('test_base_hole_cards_used') if base_hole_cards_used_results else failed.append('test_base_hole_cards_used') + print('==================================================') print('Finished running all Unit Tests') if len(failed) == 0: print('Passed all tests') @@ -25,6 +26,9 @@ def test_all(self): print(f'Failed {len(failed)} tests') print(f'Passed: {passed}') print(f'Failed: {failed}') + if len(failed) == 0: + return True + return False def test_detect(self): print('==================================================') @@ -34,10 +38,10 @@ def test_detect(self): full_house_results = self.test_full_house() pair_results = self.test_pair() quads_results = self.test_quads() - straight_results = self.test_straight() - straight_flush_results = self.test_straight_flush() trips_results = self.test_trips() - two_pair_results = self.test_two_pair() + # straight_results = self.test_straight() + # straight_flush_results = self.test_straight_flush() + # two_pair_results = self.test_two_pair() passed = [] failed = [] @@ -45,11 +49,12 @@ def test_detect(self): passed.append('test_full_house') if full_house_results else failed.append('test_full_house') passed.append('test_pair') if pair_results else failed.append('test_pair') passed.append('test_quads') if quads_results else failed.append('test_quads') - passed.append('test_straight') if straight_results else failed.append('test_straight') - passed.append('test_straight_flush') if straight_flush_results else failed.append('test_straight_flush') passed.append('test_trips') if trips_results else failed.append('test_trips') - passed.append('test_two_pair') if two_pair_results else failed.append('test_two_pair') + # passed.append('test_straight') if straight_results else failed.append('test_straight') + # passed.append('test_straight_flush') if straight_flush_results else failed.append('test_straight_flush') + # passed.append('test_two_pair') if two_pair_results else failed.append('test_two_pair') + print('==================================================') print('Finished running detect Unit Tests') if len(failed) == 0: print('Passed all tests') @@ -57,6 +62,9 @@ def test_detect(self): print(f'Failed {len(failed)} tests') print(f'Passed: {passed}') print(f'Failed: {failed}') + if len(failed) == 0: + return True + return False def test_base_hole_cards_used(self): print('==================================================') @@ -88,6 +96,9 @@ def test_base_hole_cards_used(self): print(f'Failed {len(failed)} tests') print(f'Passed: {passed}') print(f'Failed: {failed}') + if len(failed) == 0: + return True + return False def test_flush(self): print('==================================================') @@ -114,6 +125,9 @@ def test_flush(self): print(f'Failed {len(failed)} tests') print(f'Passed: {passed}') print(f'Failed: {failed}') + if len(failed) == 0: + return True + return False def test_full_house(self): print('==================================================') @@ -138,14 +152,20 @@ def test_full_house(self): print(f'Failed {len(failed)} tests') print(f'Passed: {passed}') print(f'Failed: {failed}') + if len(failed) == 0: + return True + return False def test_pair(self): print('==================================================') print('Running pair Unit Tests') - test_1 = round(self.probability_engine.detect_pair([eval7.Card('2s'), eval7.Card('3h')], [eval7.Card('6d'), eval7.Card('7s'), eval7.Card('Tc')]), 2) == (0.25,1) - test_2 = round(self.probability_engine.detect_pair([eval7.Card('2s'), eval7.Card('3h'), eval7.Card('8d')], [eval7.Card('6d'), eval7.Card('7s'), eval7.Card('Tc')]), 2) == (0.37,1) - test_3 = round(self.probability_engine.detect_pair([eval7.Card('2s'), eval7.Card('3h')], [eval7.Card('6d'), eval7.Card('7s'), eval7.Card('Tc')], eval7.Card('Ac'), 2)) == (0.14,1) + test_1 = self.probability_engine.detect_pair([eval7.Card('2s'), eval7.Card('3h')], [eval7.Card('6d'), eval7.Card('7s'), eval7.Card('Tc')]) + test_1 = (round(test_1[0], 2), test_1[1]) == (0.25,1) + test_2 = self.probability_engine.detect_pair([eval7.Card('2s'), eval7.Card('3h'), eval7.Card('8d')], [eval7.Card('6d'), eval7.Card('7s'), eval7.Card('Tc')]) + test_2 = (round(test_2[0], 2), test_2[1]) == (0.37,1) + test_3 = self.probability_engine.detect_pair([eval7.Card('2s'), eval7.Card('3h')], [eval7.Card('6d'), eval7.Card('7s'), eval7.Card('Tc'), eval7.Card('Ac')]) + test_3 = (round(test_3[0], 2), test_3[1]) == (0.14,1) passed = [] failed = [] @@ -160,26 +180,36 @@ def test_pair(self): print(f'Failed {len(failed)} tests') print(f'Passed: {passed}') print(f'Failed: {failed}') + if len(failed) == 0: + return True + return False def test_quads(self): print('==================================================') print('Running quads Unit Tests') - - test_1 = self.probability_engine.detect_quads([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - test_2 = self.probability_engine.detect_quads([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - test_3 = self.probability_engine.detect_quads([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - test_4 = self.probability_engine.detect_quads([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - test_5 = self.probability_engine.detect_quads([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - test_6 = self.probability_engine.detect_quads([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + + test_1 = self.probability_engine.detect_quads([eval7.Card('As'), eval7.Card('4d')], [eval7.Card('5d'), eval7.Card('8c'), eval7.Card('Th')]) == (0, 0) + test_2 = self.probability_engine.detect_quads([eval7.Card('4s'), eval7.Card('4d')], [eval7.Card('5s'), eval7.Card('Jd'), eval7.Card('Kc')]) == (1 - ((44 - 2) / 44) ** 2, 2) + test_3 = self.probability_engine.detect_quads([eval7.Card('5h'), eval7.Card('As')], [eval7.Card('5d'), eval7.Card('8s'), eval7.Card('Qd')]) == (1 - ((44 - 2) / 44) ** 2, 1) + test_4 = self.probability_engine.detect_quads([eval7.Card('6h'), eval7.Card('Kc')],[eval7.Card('7d'), eval7.Card('7s'), eval7.Card('2d')]) == (0, 0) + test_5 = self.probability_engine.detect_quads([eval7.Card('9c'), eval7.Card('8h'), eval7.Card('Kd')], [eval7.Card('9c'), eval7.Card('Td'), eval7.Card('As')]) == (1 - ((44 - 2) / 44) ** 2, 1) + test_6 = self.probability_engine.detect_quads([eval7.Card('4c'), eval7.Card('4s')], [eval7.Card('4h'), eval7.Card('4d'), eval7.Card('Qs')]) == (1, 2) + test_7 = self.probability_engine.detect_quads([eval7.Card('9s'), eval7.Card('2d'), eval7.Card('2s')], [eval7.Card('2h'), eval7.Card('Jd'), eval7.Card('2c')]) == (1, 2) + test_8 = self.probability_engine.detect_quads([eval7.Card('As'), eval7.Card('3d')], [eval7.Card('Ad'), eval7.Card('8d'), eval7.Card('9s'), eval7.Card('Tc')]) == (0, 1) + test_9 = self.probability_engine.detect_quads([eval7.Card('7d'), eval7.Card('7s')], [eval7.Card('As'), eval7.Card('4d'), eval7.Card('Tc'), eval7.Card('7h')]) == (1 - ((43 - 1) / 43), 2) passed = [] failed = [] + passed.append('test_1') if test_1 else failed.append('test_1') passed.append('test_2') if test_2 else failed.append('test_2') passed.append('test_3') if test_3 else failed.append('test_3') passed.append('test_4') if test_4 else failed.append('test_4') passed.append('test_5') if test_5 else failed.append('test_5') passed.append('test_6') if test_6 else failed.append('test_6') + passed.append('test_7') if test_7 else failed.append('test_7') + passed.append('test_8') if test_8 else failed.append('test_8') + passed.append('test_9') if test_9 else failed.append('test_9') print('Finished running quads Unit Tests') if len(failed) == 0: @@ -188,26 +218,36 @@ def test_quads(self): print(f'Failed {len(failed)} tests') print(f'Passed: {passed}') print(f'Failed: {failed}') + if len(failed) == 0: + return True + return False def test_trips(self): print('==================================================') print('Running trips Unit Tests') - - test_1 = self.probability_engine.detect_trips([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - test_2 = self.probability_engine.detect_trips([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - test_3 = self.probability_engine.detect_trips([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - test_4 = self.probability_engine.detect_trips([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - test_5 = self.probability_engine.detect_trips([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - test_6 = self.probability_engine.detect_trips([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + + test_1 = self.probability_engine.detect_trips([eval7.Card('As'), eval7.Card('4d')], [eval7.Card('5d'), eval7.Card('8c'), eval7.Card('Th')]) == (1 - ((44 - 2) / 44) ** 2, 1) + test_2 = self.probability_engine.detect_trips([eval7.Card('4s'), eval7.Card('4d')], [eval7.Card('5s'), eval7.Card('Jd'), eval7.Card('Kc')]) == (1 - ((44 - 1) / 44) ** 2, 2) + test_3 = self.probability_engine.detect_trips([eval7.Card('5h'), eval7.Card('As')], [eval7.Card('5d'), eval7.Card('8s'), eval7.Card('Qd')]) == (1 - ((44 - 1) / 44) ** 2, 1) + test_4 = self.probability_engine.detect_trips([eval7.Card('6h'), eval7.Card('Kc')], [eval7.Card('7d'), eval7.Card('7s'), eval7.Card('2d')]) == (0, 0) + test_5 = self.probability_engine.detect_trips([eval7.Card('9c'), eval7.Card('8h'), eval7.Card('Kd')], [eval7.Card('9c'), eval7.Card('Td'), eval7.Card('As')]) == (1 - ((44 - 1) / 44) ** 2, 1) + test_6 = self.probability_engine.detect_trips([eval7.Card('4c'), eval7.Card('Td')], [eval7.Card('4h'), eval7.Card('4d'), eval7.Card('Qs')]) == (1, 1) + test_7 = self.probability_engine.detect_trips([eval7.Card('9s'), eval7.Card('2d'), eval7.Card('2s')], [eval7.Card('2h'), eval7.Card('Jd'), eval7.Card('Ks')]) == (1, 2) + test_8 = self.probability_engine.detect_trips([eval7.Card('As'), eval7.Card('3d')], [eval7.Card('Ad'), eval7.Card('8d'), eval7.Card('9s'), eval7.Card('Tc')]) == (1 - ((43 - 1) / 43), 1) + test_9 = self.probability_engine.detect_trips([eval7.Card('7d'), eval7.Card('7s')], [eval7.Card('As'), eval7.Card('4d'), eval7.Card('Tc'), eval7.Card('9h')]) == (1 - ((43 - 1) / 43), 2) passed = [] failed = [] + passed.append('test_1') if test_1 else failed.append('test_1') passed.append('test_2') if test_2 else failed.append('test_2') passed.append('test_3') if test_3 else failed.append('test_3') passed.append('test_4') if test_4 else failed.append('test_4') passed.append('test_5') if test_5 else failed.append('test_5') passed.append('test_6') if test_6 else failed.append('test_6') + passed.append('test_7') if test_7 else failed.append('test_7') + passed.append('test_8') if test_8 else failed.append('test_8') + passed.append('test_9') if test_9 else failed.append('test_9') print('Finished running trips Unit Tests') if len(failed) == 0: @@ -216,90 +256,102 @@ def test_trips(self): print(f'Failed {len(failed)} tests') print(f'Passed: {passed}') print(f'Failed: {failed}') - - def test_straight(self): - print('==================================================') - print('Running straight Unit Tests') - - test_1 = self.probability_engine.detect_straight([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - test_2 = self.probability_engine.detect_straight([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - test_3 = self.probability_engine.detect_straight([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - test_4 = self.probability_engine.detect_straight([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - test_5 = self.probability_engine.detect_straight([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - test_6 = self.probability_engine.detect_straight([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - - passed = [] - failed = [] - passed.append('test_1') if test_1 else failed.append('test_1') - passed.append('test_2') if test_2 else failed.append('test_2') - passed.append('test_3') if test_3 else failed.append('test_3') - passed.append('test_4') if test_4 else failed.append('test_4') - passed.append('test_5') if test_5 else failed.append('test_5') - passed.append('test_6') if test_6 else failed.append('test_6') - - print('Finished running straight Unit Tests') if len(failed) == 0: - print('Passed all tests') - else: - print(f'Failed {len(failed)} tests') - print(f'Passed: {passed}') - print(f'Failed: {failed}') - - def test_straight_flush(self): - print('==================================================') - print('Running straight_flush Unit Tests') + return True + return False + + # def test_straight(self): + # print('==================================================') + # print('Running straight Unit Tests') + + # test_1 = self.probability_engine.detect_straight([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + # test_2 = self.probability_engine.detect_straight([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + # test_3 = self.probability_engine.detect_straight([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + # test_4 = self.probability_engine.detect_straight([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + # test_5 = self.probability_engine.detect_straight([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + # test_6 = self.probability_engine.detect_straight([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + + # passed = [] + # failed = [] + # passed.append('test_1') if test_1 else failed.append('test_1') + # passed.append('test_2') if test_2 else failed.append('test_2') + # passed.append('test_3') if test_3 else failed.append('test_3') + # passed.append('test_4') if test_4 else failed.append('test_4') + # passed.append('test_5') if test_5 else failed.append('test_5') + # passed.append('test_6') if test_6 else failed.append('test_6') + + # print('Finished running straight Unit Tests') + # if len(failed) == 0: + # print('Passed all tests') + # else: + # print(f'Failed {len(failed)} tests') + # print(f'Passed: {passed}') + # print(f'Failed: {failed}') + # if len(failed) == 0: + # return True + # return False + + # def test_straight_flush(self): + # print('==================================================') + # print('Running straight_flush Unit Tests') - test_1 = self.probability_engine.detect_straight_flush([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - test_2 = self.probability_engine.detect_straight_flush([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - test_3 = self.probability_engine.detect_straight_flush([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - test_4 = self.probability_engine.detect_straight_flush([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - test_5 = self.probability_engine.detect_straight_flush([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - test_6 = self.probability_engine.detect_straight_flush([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - - passed = [] - failed = [] - passed.append('test_1') if test_1 else failed.append('test_1') - passed.append('test_2') if test_2 else failed.append('test_2') - passed.append('test_3') if test_3 else failed.append('test_3') - passed.append('test_4') if test_4 else failed.append('test_4') - passed.append('test_5') if test_5 else failed.append('test_5') - passed.append('test_6') if test_6 else failed.append('test_6') - - print('Finished running straight_flush Unit Tests') - if len(failed) == 0: - print('Passed all tests') - else: - print(f'Failed {len(failed)} tests') - print(f'Passed: {passed}') - print(f'Failed: {failed}') - - def test_two_pair(self): - print('==================================================') - print('Running two_pair Unit Tests') + # test_1 = self.probability_engine.detect_straight_flush([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + # test_2 = self.probability_engine.detect_straight_flush([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + # test_3 = self.probability_engine.detect_straight_flush([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + # test_4 = self.probability_engine.detect_straight_flush([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + # test_5 = self.probability_engine.detect_straight_flush([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + # test_6 = self.probability_engine.detect_straight_flush([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == + + # passed = [] + # failed = [] + # passed.append('test_1') if test_1 else failed.append('test_1') + # passed.append('test_2') if test_2 else failed.append('test_2') + # passed.append('test_3') if test_3 else failed.append('test_3') + # passed.append('test_4') if test_4 else failed.append('test_4') + # passed.append('test_5') if test_5 else failed.append('test_5') + # passed.append('test_6') if test_6 else failed.append('test_6') + + # print('Finished running straight_flush Unit Tests') + # if len(failed) == 0: + # print('Passed all tests') + # else: + # print(f'Failed {len(failed)} tests') + # print(f'Passed: {passed}') + # print(f'Failed: {failed}') + # if len(failed) == 0: + # return True + # return False + + # def test_two_pair(self): + # print('==================================================') + # print('Running two_pair Unit Tests') - test_1 = self.probability_engine.detect_two_pair([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')], '') == - test_2 = self.probability_engine.detect_two_pair([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')], '') == - test_3 = self.probability_engine.detect_two_pair([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')], '') == - test_4 = self.probability_engine.detect_two_pair([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')], '') == - test_5 = self.probability_engine.detect_two_pair([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')], '') == - test_6 = self.probability_engine.detect_two_pair([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')], '') == - - passed = [] - failed = [] - passed.append('test_1') if test_1 else failed.append('test_1') - passed.append('test_2') if test_2 else failed.append('test_2') - passed.append('test_3') if test_3 else failed.append('test_3') - passed.append('test_4') if test_4 else failed.append('test_4') - passed.append('test_5') if test_5 else failed.append('test_5') - passed.append('test_6') if test_6 else failed.append('test_6') - - print('Finished running two_pair Unit Tests') - if len(failed) == 0: - print('Passed all tests') - else: - print(f'Failed {len(failed)} tests') - print(f'Passed: {passed}') - print(f'Failed: {failed}') + # test_1 = self.probability_engine.detect_two_pair([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')], '') == + # test_2 = self.probability_engine.detect_two_pair([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')], '') == + # test_3 = self.probability_engine.detect_two_pair([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')], '') == + # test_4 = self.probability_engine.detect_two_pair([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')], '') == + # test_5 = self.probability_engine.detect_two_pair([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')], '') == + # test_6 = self.probability_engine.detect_two_pair([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')], '') == + + # passed = [] + # failed = [] + # passed.append('test_1') if test_1 else failed.append('test_1') + # passed.append('test_2') if test_2 else failed.append('test_2') + # passed.append('test_3') if test_3 else failed.append('test_3') + # passed.append('test_4') if test_4 else failed.append('test_4') + # passed.append('test_5') if test_5 else failed.append('test_5') + # passed.append('test_6') if test_6 else failed.append('test_6') + + # print('Finished running two_pair Unit Tests') + # if len(failed) == 0: + # print('Passed all tests') + # else: + # print(f'Failed {len(failed)} tests') + # print(f'Passed: {passed}') + # print(f'Failed: {failed}') + # if len(failed) == 0: + # return True + # return False if __name__ == '__main__': unit_tests = Unit_Tests() From dcb6d8478857ce3fe9cbadbee72cd3eb44dd0add Mon Sep 17 00:00:00 2001 From: Brian Le Date: Thu, 25 Jan 2024 18:03:30 -0500 Subject: [PATCH 13/15] Finished unit tests --- python_skeleton/skeleton/monte_carlo_tests.py | 2 +- .../skeleton/probability_engine.py | 49 +++- python_skeleton/skeleton/unit_tests.py | 268 ++++++++++-------- research.ipynb | 31 ++ 4 files changed, 232 insertions(+), 118 deletions(-) diff --git a/python_skeleton/skeleton/monte_carlo_tests.py b/python_skeleton/skeleton/monte_carlo_tests.py index c678d46..7e763cd 100644 --- a/python_skeleton/skeleton/monte_carlo_tests.py +++ b/python_skeleton/skeleton/monte_carlo_tests.py @@ -310,6 +310,6 @@ def test_river(self, iters, precision): sys.stdout = open('monte_carlo_test_logs.txt','wt') test_suite = Monte_Carlo_Tests() - test_suite.test_all(2000, 2000) + test_suite.test_all(500, 2000) temp = sys.stdout \ No newline at end of file diff --git a/python_skeleton/skeleton/probability_engine.py b/python_skeleton/skeleton/probability_engine.py index de612b2..50e9ddf 100644 --- a/python_skeleton/skeleton/probability_engine.py +++ b/python_skeleton/skeleton/probability_engine.py @@ -2,6 +2,9 @@ class Probability_Engine(): def __init__(self): + # Version to output winrate + # Run montecarlo test and tweak scalars? + # Version to output buckets: (current, draw, hole cards used, round???, specific cards in hand???) pass def calculate_win_probability(self, my_cards, round_state): @@ -189,6 +192,40 @@ def base_hole_cards_used(self, my_cards, board_cards, hand_type): return hole_cards_used + def detect_top_pair(self, my_cards, board_cards): + ''' + Returns Bool for whether we have top pair on the flop given our hand is a Pair + ''' + def rank_order(char): + if char == 'T': + return 4 + elif char == 'J': + return 3 + elif char == 'Q': + return 2 + elif char == 'K': + return 1 + elif char == 'A': + return 0 + else: + return 14 - int(char) + + if self.base_hole_cards_used(my_cards, board_cards, 'Pair') == 0: + return False + + total_cards = my_cards + board_cards + ranks = '' + for card in total_cards: + card = str(card) + ranks += card[0] + + ranks = sorted(ranks, key=rank_order) + + if ranks[0] == ranks[1]: + return True + return False + + def detect_flush(self, my_cards, board_cards): ''' Returns chance of hitting a flush as well as how many come from hole cards. @@ -227,13 +264,15 @@ def detect_flush(self, my_cards, board_cards): if highest_quantity == 3: if len(board_cards) == 3: hit_rate = 1/16 - return (0, 0) + else: + return (0, 0) elif highest_quantity == 4: if len(board_cards) == 3: hit_rate = 7/16 elif len(board_cards) == 4: hit_rate = 1/4 - return (0, 0) + else: + return (0, 0) elif highest_quantity >= 5: hit_rate = 1 @@ -395,7 +434,8 @@ def detect_full_house(self, my_cards, board_cards, hand_type): return (0, 0) else: if chances_left == 2: - hit_rate = (my_cards - 1 * 6) + (4 * remaining_cards * 2)/ remaining_cards ** 2 + outs = 4 + hit_rate = 1 - ((remaining_cards - outs) / remaining_cards) ** 2 else: # 1 outs = 4 hit_rate = 1 - ((remaining_cards - outs) / remaining_cards) @@ -488,8 +528,6 @@ def detect_trips(self, my_cards, board_cards): # Calculates the chance of getting a trip remaining_cards = 52 - 5 - len(board_cards) if highest_quantity == 1: - if len(board_cards) == 3: - hit_rate = 1 - ((remaining_cards - 2) / remaining_cards) ** 2 return (0,0) elif highest_quantity == 2: if len(board_cards) == 3: @@ -546,6 +584,7 @@ def detect_quads(self, my_cards, board_cards): hit_rate = 1 - ((remaining_cards - 1) / remaining_cards) ** 2 elif len(board_cards) == 4: hit_rate = 1 - ((remaining_cards - 1) / remaining_cards) + return (0,0) elif highest_quantity >= 4: hit_rate = 1 diff --git a/python_skeleton/skeleton/unit_tests.py b/python_skeleton/skeleton/unit_tests.py index 1d51504..53bf307 100644 --- a/python_skeleton/skeleton/unit_tests.py +++ b/python_skeleton/skeleton/unit_tests.py @@ -39,9 +39,10 @@ def test_detect(self): pair_results = self.test_pair() quads_results = self.test_quads() trips_results = self.test_trips() - # straight_results = self.test_straight() - # straight_flush_results = self.test_straight_flush() - # two_pair_results = self.test_two_pair() + top_pair_results = self.test_top_pair() + straight_results = self.test_straight() + straight_flush_results = self.test_straight_flush() + two_pair_results = self.test_two_pair() passed = [] failed = [] @@ -50,9 +51,10 @@ def test_detect(self): passed.append('test_pair') if pair_results else failed.append('test_pair') passed.append('test_quads') if quads_results else failed.append('test_quads') passed.append('test_trips') if trips_results else failed.append('test_trips') - # passed.append('test_straight') if straight_results else failed.append('test_straight') - # passed.append('test_straight_flush') if straight_flush_results else failed.append('test_straight_flush') - # passed.append('test_two_pair') if two_pair_results else failed.append('test_two_pair') + passed.append('test_top_pair') if top_pair_results else failed.append('test_top_pair') + passed.append('test_straight') if straight_results else failed.append('test_straight') + passed.append('test_straight_flush') if straight_flush_results else failed.append('test_straight_flush') + passed.append('test_two_pair') if two_pair_results else failed.append('test_two_pair') print('==================================================') print('Finished running detect Unit Tests') @@ -100,6 +102,32 @@ def test_base_hole_cards_used(self): return True return False + def test_top_pair(self): + print('==================================================') + print('Running top_pair Unit Tests') + + test_1 = self.probability_engine.detect_top_pair([eval7.Card('Ac'), eval7.Card('Ad'), ], [eval7.Card('2h'), eval7.Card('7c'), eval7.Card('6d'), ]) == True + test_2 = self.probability_engine.detect_top_pair([eval7.Card('3h'), eval7.Card('4h'), eval7.Card('7h')], [eval7.Card('Ah'), eval7.Card('8c'), eval7.Card('8h')]) == False + test_3 = self.probability_engine.detect_top_pair([eval7.Card('Ac'), eval7.Card('2d'), ], [eval7.Card('2h'), eval7.Card('7c'), eval7.Card('6d')]) == False + + passed = [] + failed = [] + passed.append('test_1') if test_1 else failed.append('test_1') + passed.append('test_2') if test_2 else failed.append('test_2') + passed.append('test_3') if test_3 else failed.append('test_3') + + + print('Finished running top_pair Unit Tests') + if len(failed) == 0: + print('Passed all tests') + else: + print(f'Failed {len(failed)} tests') + print(f'Passed: {passed}') + print(f'Failed: {failed}') + if len(failed) == 0: + return True + return False + def test_flush(self): print('==================================================') print('Running flush Unit Tests') @@ -133,11 +161,15 @@ def test_full_house(self): print('==================================================') print('Running full_house Unit Tests') - test_1 = self.probability_engine.detect_full_house([eval7.Card('3h'), eval7.Card('3c')], [eval7.Card('5h'), eval7.Card('5c'), eval7.Card('2d')], 'Two Pair') == (0.17,2) - test_2 = self.probability_engine.detect_full_house([eval7.Card('Ac'), eval7.Card('Ad'), eval7.Card('Ah')], [eval7.Card('4h'), eval7.Card('5d'), eval7.Card('3c')], 'Trips') == (0.37,3) - test_3 = self.probability_engine.detect_full_house([eval7.Card('3h'), eval7.Card('3c')], [eval7.Card('7c'), eval7.Card('8d'), eval7.Card('Ts'), eval7.Card('4h')], 'Pair') == (0,0) - test_4 = self.probability_engine.detect_full_house([eval7.Card('3h'), eval7.Card('3c'), eval7.Card('7d')], [eval7.Card('7c'), eval7.Card('8d'), eval7.Card('Ts'), eval7.Card('4h')], 'Two Pair') == (0.5,3) - + test_1 = self.probability_engine.detect_full_house([eval7.Card('3h'), eval7.Card('3c')], [eval7.Card('5h'), eval7.Card('5c'), eval7.Card('2d')], 'Two Pair') + test_1 = (round(test_1[0], 2), test_1[1]) == (0.17,2) + test_2 = self.probability_engine.detect_full_house([eval7.Card('Ac'), eval7.Card('Ad'), eval7.Card('Ah')], [eval7.Card('4h'), eval7.Card('5d'), eval7.Card('3c')], 'Trips') + test_2 = (round(test_2[0], 2), test_2[1]) == (0.37,3) + test_3 = self.probability_engine.detect_full_house([eval7.Card('3h'), eval7.Card('3c')], [eval7.Card('7c'), eval7.Card('8d'), eval7.Card('Ts'), eval7.Card('4h')], 'Pair') + test_3 = (round(test_3[0], 2), test_3[1]) == (0,0) + test_4 = self.probability_engine.detect_full_house([eval7.Card('3h'), eval7.Card('3c'), eval7.Card('7d')], [eval7.Card('7c'), eval7.Card('8d'), eval7.Card('Ts'), eval7.Card('4h')], 'Two Pair') + test_4 = (round(test_4[0], 2), test_4[1]) == (0.09,3) + passed = [] failed = [] passed.append('test_1') if test_1 else failed.append('test_1') @@ -189,14 +221,19 @@ def test_quads(self): print('Running quads Unit Tests') test_1 = self.probability_engine.detect_quads([eval7.Card('As'), eval7.Card('4d')], [eval7.Card('5d'), eval7.Card('8c'), eval7.Card('Th')]) == (0, 0) - test_2 = self.probability_engine.detect_quads([eval7.Card('4s'), eval7.Card('4d')], [eval7.Card('5s'), eval7.Card('Jd'), eval7.Card('Kc')]) == (1 - ((44 - 2) / 44) ** 2, 2) - test_3 = self.probability_engine.detect_quads([eval7.Card('5h'), eval7.Card('As')], [eval7.Card('5d'), eval7.Card('8s'), eval7.Card('Qd')]) == (1 - ((44 - 2) / 44) ** 2, 1) + test_2 = self.probability_engine.detect_quads([eval7.Card('4s'), eval7.Card('4d')], [eval7.Card('5s'), eval7.Card('Jd'), eval7.Card('Kc')]) + test_2 = (round(test_2[0], 2), test_2[1]) == (0.08, 2) + test_3 = self.probability_engine.detect_quads([eval7.Card('5h'), eval7.Card('As')], [eval7.Card('5d'), eval7.Card('8s'), eval7.Card('Qd')]) + test_3 = (round(test_3[0], 2), test_3[1]) == (0.08, 1) test_4 = self.probability_engine.detect_quads([eval7.Card('6h'), eval7.Card('Kc')],[eval7.Card('7d'), eval7.Card('7s'), eval7.Card('2d')]) == (0, 0) - test_5 = self.probability_engine.detect_quads([eval7.Card('9c'), eval7.Card('8h'), eval7.Card('Kd')], [eval7.Card('9c'), eval7.Card('Td'), eval7.Card('As')]) == (1 - ((44 - 2) / 44) ** 2, 1) + test_5 = self.probability_engine.detect_quads([eval7.Card('9c'), eval7.Card('8h'), eval7.Card('Kd')], [eval7.Card('9c'), eval7.Card('Td'), eval7.Card('As')]) + test_5 = (round(test_5[0], 2), test_5[1]) == (0.08, 1) test_6 = self.probability_engine.detect_quads([eval7.Card('4c'), eval7.Card('4s')], [eval7.Card('4h'), eval7.Card('4d'), eval7.Card('Qs')]) == (1, 2) test_7 = self.probability_engine.detect_quads([eval7.Card('9s'), eval7.Card('2d'), eval7.Card('2s')], [eval7.Card('2h'), eval7.Card('Jd'), eval7.Card('2c')]) == (1, 2) - test_8 = self.probability_engine.detect_quads([eval7.Card('As'), eval7.Card('3d')], [eval7.Card('Ad'), eval7.Card('8d'), eval7.Card('9s'), eval7.Card('Tc')]) == (0, 1) - test_9 = self.probability_engine.detect_quads([eval7.Card('7d'), eval7.Card('7s')], [eval7.Card('As'), eval7.Card('4d'), eval7.Card('Tc'), eval7.Card('7h')]) == (1 - ((43 - 1) / 43), 2) + test_8 = self.probability_engine.detect_quads([eval7.Card('As'), eval7.Card('3d')], [eval7.Card('Ad'), eval7.Card('8d'), eval7.Card('9s'), eval7.Card('Tc')]) == (0, 0) + test_9 = self.probability_engine.detect_quads([eval7.Card('7d'), eval7.Card('7s')], [eval7.Card('As'), eval7.Card('4d'), eval7.Card('Tc'), eval7.Card('7h')]) + test_9 = (round(test_9[0], 2), test_9[1]) == (0.02, 2) + passed = [] failed = [] @@ -226,15 +263,20 @@ def test_trips(self): print('==================================================') print('Running trips Unit Tests') - test_1 = self.probability_engine.detect_trips([eval7.Card('As'), eval7.Card('4d')], [eval7.Card('5d'), eval7.Card('8c'), eval7.Card('Th')]) == (1 - ((44 - 2) / 44) ** 2, 1) - test_2 = self.probability_engine.detect_trips([eval7.Card('4s'), eval7.Card('4d')], [eval7.Card('5s'), eval7.Card('Jd'), eval7.Card('Kc')]) == (1 - ((44 - 1) / 44) ** 2, 2) - test_3 = self.probability_engine.detect_trips([eval7.Card('5h'), eval7.Card('As')], [eval7.Card('5d'), eval7.Card('8s'), eval7.Card('Qd')]) == (1 - ((44 - 1) / 44) ** 2, 1) + test_1 = self.probability_engine.detect_trips([eval7.Card('As'), eval7.Card('4d')], [eval7.Card('5d'), eval7.Card('8c'), eval7.Card('Th')]) == (0, 0) + test_2 = self.probability_engine.detect_trips([eval7.Card('4s'), eval7.Card('4d')], [eval7.Card('5s'), eval7.Card('Jd'), eval7.Card('Kc')]) == (0.04, 2) + test_2 = (round(test_2[0], 2), test_2[1]) == (0.04, 2) + test_3 = self.probability_engine.detect_trips([eval7.Card('5h'), eval7.Card('As')], [eval7.Card('5d'), eval7.Card('8s'), eval7.Card('Qd')]) + test_3 = (round(test_3[0], 2), test_3[1]) == (0.04, 1) test_4 = self.probability_engine.detect_trips([eval7.Card('6h'), eval7.Card('Kc')], [eval7.Card('7d'), eval7.Card('7s'), eval7.Card('2d')]) == (0, 0) - test_5 = self.probability_engine.detect_trips([eval7.Card('9c'), eval7.Card('8h'), eval7.Card('Kd')], [eval7.Card('9c'), eval7.Card('Td'), eval7.Card('As')]) == (1 - ((44 - 1) / 44) ** 2, 1) + test_5 = self.probability_engine.detect_trips([eval7.Card('9c'), eval7.Card('8h'), eval7.Card('Kd')], [eval7.Card('9c'), eval7.Card('Td'), eval7.Card('As')]) + test_5 = (round(test_5[0], 2), test_5[1]) == (0.04, 1) test_6 = self.probability_engine.detect_trips([eval7.Card('4c'), eval7.Card('Td')], [eval7.Card('4h'), eval7.Card('4d'), eval7.Card('Qs')]) == (1, 1) test_7 = self.probability_engine.detect_trips([eval7.Card('9s'), eval7.Card('2d'), eval7.Card('2s')], [eval7.Card('2h'), eval7.Card('Jd'), eval7.Card('Ks')]) == (1, 2) - test_8 = self.probability_engine.detect_trips([eval7.Card('As'), eval7.Card('3d')], [eval7.Card('Ad'), eval7.Card('8d'), eval7.Card('9s'), eval7.Card('Tc')]) == (1 - ((43 - 1) / 43), 1) - test_9 = self.probability_engine.detect_trips([eval7.Card('7d'), eval7.Card('7s')], [eval7.Card('As'), eval7.Card('4d'), eval7.Card('Tc'), eval7.Card('9h')]) == (1 - ((43 - 1) / 43), 2) + test_8 = self.probability_engine.detect_trips([eval7.Card('As'), eval7.Card('3d')], [eval7.Card('Ad'), eval7.Card('8d'), eval7.Card('9s'), eval7.Card('Tc')]) + test_8 = (round(test_8[0], 2), test_8[1]) == (0.02, 1) + test_9 = self.probability_engine.detect_trips([eval7.Card('7d'), eval7.Card('7s')], [eval7.Card('As'), eval7.Card('4d'), eval7.Card('Tc'), eval7.Card('9h')]) + test_9 = (round(test_9[0], 2), test_9[1]) == (0.02, 2) passed = [] failed = [] @@ -260,98 +302,100 @@ def test_trips(self): return True return False - # def test_straight(self): - # print('==================================================') - # print('Running straight Unit Tests') - - # test_1 = self.probability_engine.detect_straight([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - # test_2 = self.probability_engine.detect_straight([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - # test_3 = self.probability_engine.detect_straight([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - # test_4 = self.probability_engine.detect_straight([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - # test_5 = self.probability_engine.detect_straight([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - # test_6 = self.probability_engine.detect_straight([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - - # passed = [] - # failed = [] - # passed.append('test_1') if test_1 else failed.append('test_1') - # passed.append('test_2') if test_2 else failed.append('test_2') - # passed.append('test_3') if test_3 else failed.append('test_3') - # passed.append('test_4') if test_4 else failed.append('test_4') - # passed.append('test_5') if test_5 else failed.append('test_5') - # passed.append('test_6') if test_6 else failed.append('test_6') - - # print('Finished running straight Unit Tests') - # if len(failed) == 0: - # print('Passed all tests') - # else: - # print(f'Failed {len(failed)} tests') - # print(f'Passed: {passed}') - # print(f'Failed: {failed}') - # if len(failed) == 0: - # return True - # return False - - # def test_straight_flush(self): - # print('==================================================') - # print('Running straight_flush Unit Tests') + def test_straight(self): + print('==================================================') + print('Running straight Unit Tests') + + test_1 = self.probability_engine.detect_straight([eval7.Card('4s'), eval7.Card('7d')], [eval7.Card('5c'), eval7.Card('6h'), eval7.Card('Ac')]) + test_1 = (round(test_1[0], 2), test_1[1]) == (0.33, 2) + test_2 = self.probability_engine.detect_straight([eval7.Card('8s'), eval7.Card('3h'), eval7.Card('4d')], [eval7.Card('5s'), eval7.Card('Ac'), eval7.Card('Jc')]) + test_2 = (round(test_2[0], 2), test_2[1]) == (0.01, 2) + test_3 = self.probability_engine.detect_straight([eval7.Card('6s'), eval7.Card('7s')], [eval7.Card('9s'), eval7.Card('2s'), eval7.Card('Ks'), eval7.Card('Qh')]) + test_3 = (round(test_3[0], 2), test_3[1]) == (0.21, 2) + test_4 = self.probability_engine.detect_straight([eval7.Card('Tc'), eval7.Card('9c'), eval7.Card('Qc')], [eval7.Card('Jc'), eval7.Card('2c'), eval7.Card('6d'), eval7.Card('6s')]) + test_4 = (round(test_4[0], 2), test_4[1]) == (0.19, 3) + test_5 = self.probability_engine.detect_straight([eval7.Card('2d'), eval7.Card('Jc')], [eval7.Card('Jd'), eval7.Card('Th'), eval7.Card('9s'), eval7.Card('6c'), eval7.Card('Ad')]) == (0, 0) + test_6 = self.probability_engine.detect_straight([eval7.Card('2d'), eval7.Card('Ad'), eval7.Card('Ks')], [eval7.Card('6h'), eval7.Card('5c'), eval7.Card('4s'), eval7.Card('7d'), eval7.Card('8c')]) == (0,0) + test_7 = self.probability_engine.detect_straight([eval7.Card('Ah'), eval7.Card('7h')], [eval7.Card('Ks'), eval7.Card('Jh'), eval7.Card('Tc')]) + test_7 = (round(test_7[0], 2), test_7[1]) == (0.17, 1) + test_8 = self.probability_engine.detect_straight([eval7.Card('5h'), eval7.Card('7h')], [eval7.Card('6s'), eval7.Card('8h'), eval7.Card('Kc'), eval7.Card('Ah')]) + test_8 = (round(test_8[0], 2), test_8[1]) == (0.19, 2) + + + passed = [] + failed = [] + passed.append('test_5') if test_5 else failed.append('test_5') + passed.append('test_6') if test_6 else failed.append('test_6') + + print('Finished running straight Unit Tests') + if len(failed) == 0: + print('Passed all tests') + else: + print(f'Failed {len(failed)} tests') + print(f'Passed: {passed}') + print(f'Failed: {failed}') + if len(failed) == 0: + return True + return False + + def test_straight_flush(self): + print('==================================================') + print('Running straight_flush Unit Tests') - # test_1 = self.probability_engine.detect_straight_flush([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - # test_2 = self.probability_engine.detect_straight_flush([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - # test_3 = self.probability_engine.detect_straight_flush([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - # test_4 = self.probability_engine.detect_straight_flush([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - # test_5 = self.probability_engine.detect_straight_flush([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - # test_6 = self.probability_engine.detect_straight_flush([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')]) == - - # passed = [] - # failed = [] - # passed.append('test_1') if test_1 else failed.append('test_1') - # passed.append('test_2') if test_2 else failed.append('test_2') - # passed.append('test_3') if test_3 else failed.append('test_3') - # passed.append('test_4') if test_4 else failed.append('test_4') - # passed.append('test_5') if test_5 else failed.append('test_5') - # passed.append('test_6') if test_6 else failed.append('test_6') - - # print('Finished running straight_flush Unit Tests') - # if len(failed) == 0: - # print('Passed all tests') - # else: - # print(f'Failed {len(failed)} tests') - # print(f'Passed: {passed}') - # print(f'Failed: {failed}') - # if len(failed) == 0: - # return True - # return False - - # def test_two_pair(self): - # print('==================================================') - # print('Running two_pair Unit Tests') + test_1 = self.probability_engine.detect_straight_flush([eval7.Card('Ac'), eval7.Card('Tc')], [eval7.Card('Jc'), eval7.Card('Qc'), eval7.Card('9h')]) + test_1 = (round(test_1[0], 2), test_1[1]) == (0.04, 2) + test_2 = self.probability_engine.detect_straight_flush([eval7.Card('5h'), eval7.Card('Tc')], [eval7.Card('6h'), eval7.Card('8h'), eval7.Card('9h'), eval7.Card('Kd')]) + test_2 = (round(test_2[0], 2), test_2[1]) == (0.02, 1) + test_3 = self.probability_engine.detect_straight_flush([eval7.Card('Ac'), eval7.Card('Tc'), eval7.Card('Jc')], [eval7.Card('Th'), eval7.Card('Qc'), eval7.Card('9h')]) + test_3 = (round(test_3[0], 2), test_3[1]) == (0.04, 3) + test_4 = self.probability_engine.detect_straight_flush([eval7.Card('Ac'), eval7.Card('Tc')], [eval7.Card('Jc'), eval7.Card('Qh'), eval7.Card('9h')]) + test_4 = (round(test_4[0], 2), test_4[1]) == (0, 0) + + passed = [] + failed = [] + passed.append('test_1') if test_1 else failed.append('test_1') + passed.append('test_2') if test_2 else failed.append('test_2') + passed.append('test_3') if test_3 else failed.append('test_3') + passed.append('test_4') if test_4 else failed.append('test_4') + + print('Finished running straight_flush Unit Tests') + if len(failed) == 0: + print('Passed all tests') + else: + print(f'Failed {len(failed)} tests') + print(f'Passed: {passed}') + print(f'Failed: {failed}') + if len(failed) == 0: + return True + return False + + def test_two_pair(self): + print('==================================================') + print('Running two_pair Unit Tests') - # test_1 = self.probability_engine.detect_two_pair([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')], '') == - # test_2 = self.probability_engine.detect_two_pair([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card('')], '') == - # test_3 = self.probability_engine.detect_two_pair([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')], '') == - # test_4 = self.probability_engine.detect_two_pair([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')], '') == - # test_5 = self.probability_engine.detect_two_pair([eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')], '') == - # test_6 = self.probability_engine.detect_two_pair([eval7.Card(''), eval7.Card(''), eval7.Card('')], [eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card(''), eval7.Card('')], '') == - - # passed = [] - # failed = [] - # passed.append('test_1') if test_1 else failed.append('test_1') - # passed.append('test_2') if test_2 else failed.append('test_2') - # passed.append('test_3') if test_3 else failed.append('test_3') - # passed.append('test_4') if test_4 else failed.append('test_4') - # passed.append('test_5') if test_5 else failed.append('test_5') - # passed.append('test_6') if test_6 else failed.append('test_6') - - # print('Finished running two_pair Unit Tests') - # if len(failed) == 0: - # print('Passed all tests') - # else: - # print(f'Failed {len(failed)} tests') - # print(f'Passed: {passed}') - # print(f'Failed: {failed}') - # if len(failed) == 0: - # return True - # return False + test_1 = self.probability_engine.detect_two_pair([eval7.Card('Th'), eval7.Card('7c')], [eval7.Card('As'), eval7.Card('7h'), eval7.Card('4d')], 'Pair') + test_1 = (round(test_1[0], 2), test_1[1]) == (0.37, 1) + test_2 = self.probability_engine.detect_two_pair([eval7.Card('3h'), eval7.Card('4h'), eval7.Card('Td')], [eval7.Card('7c'), eval7.Card('9s'), eval7.Card('9c')], 'Pair') + test_2 = (round(test_2[0], 2), test_2[1]) == (0.37, 1) + test_3 = self.probability_engine.detect_two_pair([eval7.Card('Ac'), eval7.Card('Td')], [eval7.Card('3h'), eval7.Card('5s'), eval7.Card('9d'), eval7.Card('8h')], 'High Card') + test_3 = (round(test_3[0], 2), test_3[1]) == (0, 0) + + passed = [] + failed = [] + passed.append('test_1') if test_1 else failed.append('test_1') + passed.append('test_2') if test_2 else failed.append('test_2') + passed.append('test_3') if test_3 else failed.append('test_3') + + print('Finished running two_pair Unit Tests') + if len(failed) == 0: + print('Passed all tests') + else: + print(f'Failed {len(failed)} tests') + print(f'Passed: {passed}') + print(f'Failed: {failed}') + if len(failed) == 0: + return True + return False if __name__ == '__main__': unit_tests = Unit_Tests() diff --git a/research.ipynb b/research.ipynb index 98a99ec..1881412 100644 --- a/research.ipynb +++ b/research.ipynb @@ -21,6 +21,37 @@ "print(max(a.items(), key=lambda x: x[1]))" ] }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['6', '9', 'T', 'J', 'K', 'K']\n" + ] + } + ], + "source": [ + "sample = 'KT96JK'\n", + "def rank_order(char):\n", + " if char == 'T':\n", + " return 4\n", + " elif char == 'J':\n", + " return 3\n", + " elif char == 'Q':\n", + " return 2\n", + " elif char == 'K':\n", + " return 1\n", + " elif char == 'A':\n", + " return 0\n", + " else:\n", + " return 14 - int(char)\n", + "print(sorted(sample, key=rank_order))" + ] + }, { "cell_type": "code", "execution_count": 1, From 14e47174110b89c3b043315a9f942325f850fbad Mon Sep 17 00:00:00 2001 From: Brian Le Date: Thu, 25 Jan 2024 18:59:41 -0500 Subject: [PATCH 14/15] Passed All Unit Tests --- .../skeleton/probability_engine.py | 30 ++++++++-------- python_skeleton/skeleton/unit_tests.py | 34 +++++++++++-------- 2 files changed, 35 insertions(+), 29 deletions(-) diff --git a/python_skeleton/skeleton/probability_engine.py b/python_skeleton/skeleton/probability_engine.py index 50e9ddf..8399326 100644 --- a/python_skeleton/skeleton/probability_engine.py +++ b/python_skeleton/skeleton/probability_engine.py @@ -283,12 +283,12 @@ def detect_flush(self, my_cards, board_cards): return(0, 0) return (hit_rate, max_suit[1]) - def detect_straight(self, my_cards, board_cards, flush=False): + def detect_straight(self, my_cards, board_cards, flush=0): ''' Returns chance of hitting straight as well as how many comes from hole cards. ''' # Process revealed cards - revealed_cards = {} + revealed_cards = set() for card in my_cards + board_cards: revealed_cards.add(str(card)[0]) @@ -332,7 +332,7 @@ def detect_straight(self, my_cards, board_cards, flush=False): if potential_straights == []: return (0, 0) - chances_left = 5 - len(board_cards) + chances_left = 5 - len(board_cards) if flush == 0 else 5 - flush if chances_left < min_to_hit: return (0, 0) @@ -341,7 +341,7 @@ def detect_straight(self, my_cards, board_cards, flush=False): outs = len(potential_straights) hit_rate = 0 - if flush: + if flush != 0: if min_to_hit == 1: hit_rate = 1 - ((cards_left - outs) / cards_left) ** chances_left elif min_to_hit == 2: @@ -352,7 +352,7 @@ def detect_straight(self, my_cards, board_cards, flush=False): elif min_to_hit == 2: hit_rate = 2 * (outs * 16) / (cards_left ** 2) - return (hit_rate, max(potential_straights, key=lambda x: x[1])) + return (hit_rate, max(potential_straights, key=lambda x: x[1])[1]) def detect_two_pair(self, my_cards, board_cards, hand_type): ''' @@ -492,14 +492,13 @@ def detect_straight_flush(self, my_cards, board_cards): max_suits = [suit for suit, quantity in suits.items() if quantity == highest_quantity] # Keep hole and board cards if they are that max suit - suited_my_cards = [card for card in my_cards if card[1] in max_suits] - suited_board_cards = [card for card in board_cards if card[1] in max_suits] + suited_my_cards = [card for card in my_cards if str(card)[1] in max_suits] + suited_board_cards = [card for card in board_cards if str(card)[1] in max_suits] if len(suited_my_cards) == 0: return (0, 0) else: - return self.detect_straight(suited_my_cards, suited_board_cards, True) - + return self.detect_straight(suited_my_cards, suited_board_cards, len(board_cards)) def detect_trips(self, my_cards, board_cards): ''' @@ -525,16 +524,16 @@ def detect_trips(self, my_cards, board_cards): # Grabs the max rank that pulls the most from the hole cards max_rank = max(max_ranks.items(), key=lambda x: x[1]) + hit_rate = 0 # Calculates the chance of getting a trip remaining_cards = 52 - 5 - len(board_cards) if highest_quantity == 1: return (0,0) elif highest_quantity == 2: if len(board_cards) == 3: - hit_rate = 1 - ((remaining_cards - 1) / remaining_cards) ** 2 + hit_rate = 1 - ((remaining_cards - 2) / remaining_cards) ** 2 elif len(board_cards) == 4: - hit_rate = 1 - ((remaining_cards - 1) / remaining_cards) - return (0,0) + hit_rate = 1 - ((remaining_cards - 2) / remaining_cards) elif highest_quantity >= 3: hit_rate = 1 @@ -573,18 +572,19 @@ def detect_quads(self, my_cards, board_cards): # Grabs the max rank that pulls the most from the hole cards max_rank = max(max_ranks.items(), key=lambda x: x[1]) + hit_rate = 0 # Calculates the chance of getting a quad remaining_cards = 52 - 5 - len(board_cards) if highest_quantity == 2: if len(board_cards) == 3: - hit_rate = 1 - ((remaining_cards - 2) / remaining_cards) ** 2 - return (0,0) + hit_rate = (2 / remaining_cards) * (1 / (remaining_cards - 1)) + elif len(board_cards) == 4: + return (0, 0) elif highest_quantity == 3: if len(board_cards) == 3: hit_rate = 1 - ((remaining_cards - 1) / remaining_cards) ** 2 elif len(board_cards) == 4: hit_rate = 1 - ((remaining_cards - 1) / remaining_cards) - return (0,0) elif highest_quantity >= 4: hit_rate = 1 diff --git a/python_skeleton/skeleton/unit_tests.py b/python_skeleton/skeleton/unit_tests.py index 53bf307..fbbf3f7 100644 --- a/python_skeleton/skeleton/unit_tests.py +++ b/python_skeleton/skeleton/unit_tests.py @@ -222,13 +222,14 @@ def test_quads(self): test_1 = self.probability_engine.detect_quads([eval7.Card('As'), eval7.Card('4d')], [eval7.Card('5d'), eval7.Card('8c'), eval7.Card('Th')]) == (0, 0) test_2 = self.probability_engine.detect_quads([eval7.Card('4s'), eval7.Card('4d')], [eval7.Card('5s'), eval7.Card('Jd'), eval7.Card('Kc')]) - test_2 = (round(test_2[0], 2), test_2[1]) == (0.08, 2) + test_2 = (round(test_2[0], 3), test_2[1]) == (0.001, 2) test_3 = self.probability_engine.detect_quads([eval7.Card('5h'), eval7.Card('As')], [eval7.Card('5d'), eval7.Card('8s'), eval7.Card('Qd')]) - test_3 = (round(test_3[0], 2), test_3[1]) == (0.08, 1) + test_3 = (round(test_3[0], 3), test_3[1]) == (0.001, 1) test_4 = self.probability_engine.detect_quads([eval7.Card('6h'), eval7.Card('Kc')],[eval7.Card('7d'), eval7.Card('7s'), eval7.Card('2d')]) == (0, 0) test_5 = self.probability_engine.detect_quads([eval7.Card('9c'), eval7.Card('8h'), eval7.Card('Kd')], [eval7.Card('9c'), eval7.Card('Td'), eval7.Card('As')]) - test_5 = (round(test_5[0], 2), test_5[1]) == (0.08, 1) - test_6 = self.probability_engine.detect_quads([eval7.Card('4c'), eval7.Card('4s')], [eval7.Card('4h'), eval7.Card('4d'), eval7.Card('Qs')]) == (1, 2) + test_5 = (round(test_5[0], 3), test_5[1]) == (0.001, 1) + test_6 = self.probability_engine.detect_quads([eval7.Card('4c'), eval7.Card('4s')], [eval7.Card('4h'), eval7.Card('5d'), eval7.Card('Qs')]) + test_6 = (round(test_6[0], 2), test_6[1]) == (0.04, 2) test_7 = self.probability_engine.detect_quads([eval7.Card('9s'), eval7.Card('2d'), eval7.Card('2s')], [eval7.Card('2h'), eval7.Card('Jd'), eval7.Card('2c')]) == (1, 2) test_8 = self.probability_engine.detect_quads([eval7.Card('As'), eval7.Card('3d')], [eval7.Card('Ad'), eval7.Card('8d'), eval7.Card('9s'), eval7.Card('Tc')]) == (0, 0) test_9 = self.probability_engine.detect_quads([eval7.Card('7d'), eval7.Card('7s')], [eval7.Card('As'), eval7.Card('4d'), eval7.Card('Tc'), eval7.Card('7h')]) @@ -264,19 +265,19 @@ def test_trips(self): print('Running trips Unit Tests') test_1 = self.probability_engine.detect_trips([eval7.Card('As'), eval7.Card('4d')], [eval7.Card('5d'), eval7.Card('8c'), eval7.Card('Th')]) == (0, 0) - test_2 = self.probability_engine.detect_trips([eval7.Card('4s'), eval7.Card('4d')], [eval7.Card('5s'), eval7.Card('Jd'), eval7.Card('Kc')]) == (0.04, 2) - test_2 = (round(test_2[0], 2), test_2[1]) == (0.04, 2) + test_2 = self.probability_engine.detect_trips([eval7.Card('4s'), eval7.Card('4d')], [eval7.Card('5s'), eval7.Card('Jd'), eval7.Card('Kc')]) + test_2 = (round(test_2[0], 2), test_2[1]) == (0.09, 2) test_3 = self.probability_engine.detect_trips([eval7.Card('5h'), eval7.Card('As')], [eval7.Card('5d'), eval7.Card('8s'), eval7.Card('Qd')]) - test_3 = (round(test_3[0], 2), test_3[1]) == (0.04, 1) + test_3 = (round(test_3[0], 2), test_3[1]) == (0.09, 1) test_4 = self.probability_engine.detect_trips([eval7.Card('6h'), eval7.Card('Kc')], [eval7.Card('7d'), eval7.Card('7s'), eval7.Card('2d')]) == (0, 0) test_5 = self.probability_engine.detect_trips([eval7.Card('9c'), eval7.Card('8h'), eval7.Card('Kd')], [eval7.Card('9c'), eval7.Card('Td'), eval7.Card('As')]) - test_5 = (round(test_5[0], 2), test_5[1]) == (0.04, 1) + test_5 = (round(test_5[0], 2), test_5[1]) == (0.09, 1) test_6 = self.probability_engine.detect_trips([eval7.Card('4c'), eval7.Card('Td')], [eval7.Card('4h'), eval7.Card('4d'), eval7.Card('Qs')]) == (1, 1) test_7 = self.probability_engine.detect_trips([eval7.Card('9s'), eval7.Card('2d'), eval7.Card('2s')], [eval7.Card('2h'), eval7.Card('Jd'), eval7.Card('Ks')]) == (1, 2) test_8 = self.probability_engine.detect_trips([eval7.Card('As'), eval7.Card('3d')], [eval7.Card('Ad'), eval7.Card('8d'), eval7.Card('9s'), eval7.Card('Tc')]) - test_8 = (round(test_8[0], 2), test_8[1]) == (0.02, 1) + test_8 = (round(test_8[0], 2), test_8[1]) == (0.05, 1) test_9 = self.probability_engine.detect_trips([eval7.Card('7d'), eval7.Card('7s')], [eval7.Card('As'), eval7.Card('4d'), eval7.Card('Tc'), eval7.Card('9h')]) - test_9 = (round(test_9[0], 2), test_9[1]) == (0.02, 2) + test_9 = (round(test_9[0], 2), test_9[1]) == (0.05, 2) passed = [] failed = [] @@ -309,9 +310,8 @@ def test_straight(self): test_1 = self.probability_engine.detect_straight([eval7.Card('4s'), eval7.Card('7d')], [eval7.Card('5c'), eval7.Card('6h'), eval7.Card('Ac')]) test_1 = (round(test_1[0], 2), test_1[1]) == (0.33, 2) test_2 = self.probability_engine.detect_straight([eval7.Card('8s'), eval7.Card('3h'), eval7.Card('4d')], [eval7.Card('5s'), eval7.Card('Ac'), eval7.Card('Jc')]) - test_2 = (round(test_2[0], 2), test_2[1]) == (0.01, 2) - test_3 = self.probability_engine.detect_straight([eval7.Card('6s'), eval7.Card('7s')], [eval7.Card('9s'), eval7.Card('2s'), eval7.Card('Ks'), eval7.Card('Qh')]) - test_3 = (round(test_3[0], 2), test_3[1]) == (0.21, 2) + test_2 = (round(test_2[0], 2), test_2[1]) == (0.05, 2) + test_3 = self.probability_engine.detect_straight([eval7.Card('6s'), eval7.Card('7s')], [eval7.Card('9s'), eval7.Card('2s'), eval7.Card('Ks'), eval7.Card('Qh')]) == (0, 0) test_4 = self.probability_engine.detect_straight([eval7.Card('Tc'), eval7.Card('9c'), eval7.Card('Qc')], [eval7.Card('Jc'), eval7.Card('2c'), eval7.Card('6d'), eval7.Card('6s')]) test_4 = (round(test_4[0], 2), test_4[1]) == (0.19, 3) test_5 = self.probability_engine.detect_straight([eval7.Card('2d'), eval7.Card('Jc')], [eval7.Card('Jd'), eval7.Card('Th'), eval7.Card('9s'), eval7.Card('6c'), eval7.Card('Ad')]) == (0, 0) @@ -324,8 +324,14 @@ def test_straight(self): passed = [] failed = [] + passed.append('test_1') if test_1 else failed.append('test_1') + passed.append('test_2') if test_2 else failed.append('test_2') + passed.append('test_3') if test_3 else failed.append('test_3') + passed.append('test_4') if test_4 else failed.append('test_4') passed.append('test_5') if test_5 else failed.append('test_5') passed.append('test_6') if test_6 else failed.append('test_6') + passed.append('test_7') if test_7 else failed.append('test_7') + passed.append('test_8') if test_8 else failed.append('test_8') print('Finished running straight Unit Tests') if len(failed) == 0: @@ -349,7 +355,7 @@ def test_straight_flush(self): test_3 = self.probability_engine.detect_straight_flush([eval7.Card('Ac'), eval7.Card('Tc'), eval7.Card('Jc')], [eval7.Card('Th'), eval7.Card('Qc'), eval7.Card('9h')]) test_3 = (round(test_3[0], 2), test_3[1]) == (0.04, 3) test_4 = self.probability_engine.detect_straight_flush([eval7.Card('Ac'), eval7.Card('Tc')], [eval7.Card('Jc'), eval7.Card('Qh'), eval7.Card('9h')]) - test_4 = (round(test_4[0], 2), test_4[1]) == (0, 0) + test_4 = (round(test_4[0], 3), test_4[1]) == (0.001, 2) passed = [] failed = [] From 5483b2fde6af991a08370236ab22bc0471ce7371 Mon Sep 17 00:00:00 2001 From: Brian Le Date: Thu, 25 Jan 2024 20:50:32 -0500 Subject: [PATCH 15/15] Finished testing winrate finder --- python_skeleton/skeleton/monte_carlo_tests.py | 79 +++++++++++++++---- .../skeleton/probability_engine.py | 55 +++++++++---- python_skeleton/skeleton/unit_tests.py | 3 +- 3 files changed, 106 insertions(+), 31 deletions(-) diff --git a/python_skeleton/skeleton/monte_carlo_tests.py b/python_skeleton/skeleton/monte_carlo_tests.py index 7e763cd..5d69abd 100644 --- a/python_skeleton/skeleton/monte_carlo_tests.py +++ b/python_skeleton/skeleton/monte_carlo_tests.py @@ -13,13 +13,13 @@ class Monte_Carlo_Tests(): def __init__(self): self.probability_engine = Probability_Engine() - def test_all(self, iters, precision): + def test_all(self, iters, precision, sim): print('=================================================') print('Testing Probability Engine on the Flop, Turn, and River') - flop_results = self.test_flop(iters, precision) - turn_results = self.test_turn(iters, precision) - river_results = self.test_river(iters, precision) + flop_results = self.test_flop(iters, precision, sim) + turn_results = self.test_turn(iters, precision, sim) + river_results = self.test_river(iters, precision, sim) print('=================================================') print(f'Ran {3 * iters} tests, {iters} tests on each flop, turn, and river, and half with auction, half without auction') @@ -33,7 +33,7 @@ def test_all(self, iters, precision): flop_results[2] + turn_results[2] + river_results[2] / (iters * 3), flop_results[3] + turn_results[3] + river_results[3] / (iters * 3)) - def test_flop(self, iters, precision): + def test_flop(self, iters, precision, sim): print('=================================================') print(f'Testing Probability Engine on the Flop') @@ -58,8 +58,11 @@ def test_flop(self, iters, precision): round_state.street = 3 round_state.deck = board_cards + print(f'my_cards = {my_cards}') + print(f'board_cards = {board_cards}') + engine_start = time.time() - engine_probability = self.probability_engine.calculate_win_probability(my_cards, round_state) + engine_probability = self.probability_engine.calculate_win_probability(my_cards, round_state, sim) engine_end = time.time() sim_start = time.time() @@ -95,8 +98,11 @@ def test_flop(self, iters, precision): round_state.street = 3 round_state.deck = board_cards + print(f'my_cards = {my_cards}') + print(f'board_cards = {board_cards}') + engine_start = time.time() - engine_probability = self.probability_engine.calculate_win_probability(my_cards, round_state) + engine_probability = self.probability_engine.calculate_win_probability(my_cards, round_state, sim) engine_end = time.time() sim_start = time.time() @@ -124,7 +130,7 @@ def test_flop(self, iters, precision): return (avg_auction_diff / (iters // 2), avg_non_auction_diff / (iters // 2), engine_runtime / (iters // 2), sim_runtime / (iters // 2)) - def test_turn(self, iters, precision): + def test_turn(self, iters, precision, sim): print('=================================================') print(f'Testing Probability Engine on the Turn') @@ -149,8 +155,11 @@ def test_turn(self, iters, precision): round_state.street = 3 round_state.deck = board_cards + print(f'my_cards = {my_cards}') + print(f'board_cards = {board_cards}') + engine_start = time.time() - engine_probability = self.probability_engine.calculate_win_probability(my_cards, round_state) + engine_probability = self.probability_engine.calculate_win_probability(my_cards, round_state, sim) engine_end = time.time() sim_start = time.time() @@ -186,8 +195,11 @@ def test_turn(self, iters, precision): round_state.street = 3 round_state.deck = board_cards + print(f'my_cards = {my_cards}') + print(f'board_cards = {board_cards}') + engine_start = time.time() - engine_probability = self.probability_engine.calculate_win_probability(my_cards, round_state) + engine_probability = self.probability_engine.calculate_win_probability(my_cards, round_state, sim) engine_end = time.time() sim_start = time.time() @@ -214,7 +226,7 @@ def test_turn(self, iters, precision): return (avg_auction_diff / (iters // 2), avg_non_auction_diff / (iters // 2), engine_runtime / (iters // 2), sim_runtime / (iters // 2)) - def test_river(self, iters, precision): + def test_river(self, iters, precision, sim): print('=================================================') print(f'Testing Probability Engine on the River') @@ -239,8 +251,11 @@ def test_river(self, iters, precision): round_state.street = 3 round_state.deck = board_cards + print(f'my_cards = {my_cards}') + print(f'board_cards = {board_cards}') + engine_start = time.time() - engine_probability = self.probability_engine.calculate_win_probability(my_cards, round_state) + engine_probability = self.probability_engine.calculate_win_probability(my_cards, round_state, sim) engine_end = time.time() sim_start = time.time() @@ -276,8 +291,11 @@ def test_river(self, iters, precision): round_state.street = 3 round_state.deck = board_cards + print(f'my_cards = {my_cards}') + print(f'board_cards = {board_cards}') + engine_start = time.time() - engine_probability = self.probability_engine.calculate_win_probability(my_cards, round_state) + engine_probability = self.probability_engine.calculate_win_probability(my_cards, round_state, sim) engine_end = time.time() sim_start = time.time() @@ -306,10 +324,41 @@ def test_river(self, iters, precision): if __name__ == '__main__': + + ################################################### + # Calculate winrate using engine on a single hand # + ################################################### + + # # Initialize Test + # round_state = Pseudo_Round_State() + # engine = Probability_Engine() + + # # Set up Arguments + # my_cards = ['6d', '7s', 'Qs'] + # board_cards = ['3c', 'Ad', '8h'] + # round_state.street = 3 + # round_state.deck = board_cards + # monte_carlo_sim_iters = 0 + + # # Run Test + # print(engine.calculate_win_probability(my_cards, round_state, monte_carlo_sim_iters)) + + ######################### + # Run Monte Carlo Tests # + ######################### + + # Initialize Test temp = sys.stdout sys.stdout = open('monte_carlo_test_logs.txt','wt') - test_suite = Monte_Carlo_Tests() - test_suite.test_all(500, 2000) + # Set up Arguments + iters = 1000 + precision = 10000 + sim = 10 + + # Run Test + test_suite.test_all(iters, precision, sim) + + # Close Test temp = sys.stdout \ No newline at end of file diff --git a/python_skeleton/skeleton/probability_engine.py b/python_skeleton/skeleton/probability_engine.py index 8399326..0fefa2f 100644 --- a/python_skeleton/skeleton/probability_engine.py +++ b/python_skeleton/skeleton/probability_engine.py @@ -2,12 +2,11 @@ class Probability_Engine(): def __init__(self): - # Version to output winrate - # Run montecarlo test and tweak scalars? + # Version to output winrate (BAD) # Version to output buckets: (current, draw, hole cards used, round???, specific cards in hand???) pass - def calculate_win_probability(self, my_cards, round_state): + def calculate_win_probability(self, my_cards, round_state, iters=0): ''' Calculates win probability given hand during flop, turn, and river. (Preflop and auction uses hole_strengths table) @@ -57,13 +56,13 @@ def calculate_win_probability(self, my_cards, round_state): } # Scales winrate based on number of hand cards that come from hole - hole_factors = [0.5, 0.9, 1, 1.2] + hole_factors = [0.5, 0.95, 1, 1.05] # Calculates winrate with currently revealed cards base_probability = hand_strengths[hand_type] * hole_factors[self.base_hole_cards_used(my_cards, board_cards, hand_type)] # On the river - if len(board_cards) == 5: + if round_state.street == 5: return base_probability # On the flop and turn @@ -86,8 +85,9 @@ def calculate_win_probability(self, my_cards, round_state): potential_probability *= hand_strengths['Full House'] elif most_probable_out == quads_odds: potential_probability *= hand_strengths['Quads'] - - return potential_probability + base_probability / 2 + + trips_scaling = 1 + potential_probability *= trips_scaling elif hand_type == 'Two Pair': # detect flush, full house, quads @@ -105,11 +105,13 @@ def calculate_win_probability(self, my_cards, round_state): elif most_probable_out == quads_odds: potential_probability *= hand_strengths['Quads'] - return potential_probability + base_probability / 2 + two_pair_scaling = 1.5 + potential_probability *= two_pair_scaling + elif hand_type == 'Pair': # detect two pair, trips, straight, flush, full house, quads, straight flush flush_odds = self.detect_flush(my_cards, board_cards) - full_house_odds = self.detect_full_house(my_cards, hand_type) + full_house_odds = self.detect_full_house(my_cards, board_cards, hand_type) quads_odds = self.detect_quads(my_cards, board_cards) two_pair_odds = self.detect_two_pair(my_cards, board_cards, hand_type) trips_odds = self.detect_trips(my_cards, board_cards) @@ -136,7 +138,9 @@ def calculate_win_probability(self, my_cards, round_state): elif most_probable_out == straight_flush_odds: potential_probability *= hand_strengths['Straight Flush'] - return potential_probability + base_probability / 2 + pair_scaling = 1 + potential_probability *= pair_scaling + elif hand_type == 'High Card': # detect pair, two pair, flush, straight, straight flush flush_odds = self.detect_flush(my_cards, board_cards) @@ -159,7 +163,27 @@ def calculate_win_probability(self, my_cards, round_state): elif most_probable_out == straight_flush_odds: potential_probability *= hand_strengths['Straight Flush'] - return potential_probability + base_probability / 2 + high_card_scaling = 1 + potential_probability *= high_card_scaling + + base_scaling = 1.5 + potential_scaling = 1 + monte_carlo_scaling = 1 + + if iters == 0: + monte_carlo_probability = 'Not Used' + win_probability = base_probability * base_scaling + potential_probability * potential_scaling / (base_scaling + potential_scaling) + else: + monte_carlo_probability = self.monte_carlo_flop_and_turn(my_cards, board_cards, deck, iters) + win_probability = ((potential_scaling * potential_probability + base_scaling * base_probability + monte_carlo_scaling * monte_carlo_probability) / + (base_scaling + potential_scaling + monte_carlo_scaling)) + + # Debug Print Statements + print('base probability: ', base_probability) + print('potential probability: ', potential_probability) + print('monte carlo probability: ', monte_carlo_probability) + + return win_probability # straight flush can just be flush and straight detection and if both are high we probably have a potential straight flush??? # Potential probability should be a function of the probability of winning given we hit @@ -382,7 +406,7 @@ def detect_two_pair(self, my_cards, board_cards, hand_type): my_cards = len(my_cards) board_cards = len(board_cards) - hit_rate = ((my_cards * 3) * ((my_cards - 1 + board_cards) * 3)) + ((board_cards * 3) * (my_cards * 3)) / (cards_left ** 2) + hit_rate = (my_cards + board_cards) * 3 * (my_cards + board_cards - 1) * 3 / cards_left ** 2 return (hit_rate, 1) @@ -452,13 +476,13 @@ def detect_full_house(self, my_cards, board_cards, hand_type): if hole_cards_used == 0: if chances_left == 2: # need to hit one pair and one hole card or two of the same hole card - hit_rate = (2 * my_cards * 3 * 2) + (my_cards * 3 * 2) / remaining_cards ** 2 + hit_rate = my_cards * 18 / remaining_cards ** 2 else: # 1 return (0, 0) else: if chances_left == 2: # need to hit one pair and any card or two of the same card - hit_rate = (2 * (my_cards - 1 + board_cards - 1) * 3 * 2) + ((my_cards - 1 + board_cards - 1) * 3 * 2) / remaining_cards ** 2 + hit_rate = (my_cards + board_cards - 2) * 18 / remaining_cards ** 2 else: # 1 return (0, 0) @@ -633,4 +657,5 @@ def monte_carlo_flop_and_turn(self, my_cards, board_cards, deck, iters): # We lose this round win_count += 0 - return win_count/iters \ No newline at end of file + return win_count/iters + \ No newline at end of file diff --git a/python_skeleton/skeleton/unit_tests.py b/python_skeleton/skeleton/unit_tests.py index fbbf3f7..18960b3 100644 --- a/python_skeleton/skeleton/unit_tests.py +++ b/python_skeleton/skeleton/unit_tests.py @@ -405,4 +405,5 @@ def test_two_pair(self): if __name__ == '__main__': unit_tests = Unit_Tests() - unit_tests.test_all() \ No newline at end of file + unit_tests.test_all() + \ No newline at end of file