diff --git a/README.md b/README.md index 1373242..0644afc 100644 --- a/README.md +++ b/README.md @@ -3,152 +3,152 @@ Results ``` -========================= -cards on table: 5 -------------------------- - high card 34.14% - one pair 4.16% - three of a kind 0.16% - two pair 0.06% - flush 0.04% - straight 0.04% - full house 0.01% - four of a kind 0.00% - straight flush 0.00% -========================= - - -========================= -cards on table: 10 -------------------------- - high card 58.63% - one pair 16.27% - flush 5.56% - straight 4.18% - two pair 1.97% - three of a kind 1.95% - full house 0.33% - four of a kind 0.08% - straight flush 0.04% -========================= - - -========================= -cards on table: 15 -------------------------- - high card 75.52% - one pair 32.62% - flush 29.23% - straight 20.51% - two pair 9.33% - three of a kind 6.74% - full house 2.11% - four of a kind 0.50% - straight flush 0.43% -========================= - - -========================= -cards on table: 20 -------------------------- - high card 86.81% - flush 62.61% - one pair 50.10% - straight 46.66% - two pair 23.60% - three of a kind 15.17% - full house 7.34% - straight flush 2.32% - four of a kind 1.76% -========================= - - -========================= -cards on table: 25 -------------------------- - high card 93.46% - flush 86.91% - straight 70.18% - one pair 66.46% - two pair 42.93% - three of a kind 27.68% - full house 18.05% - straight flush 8.08% - four of a kind 4.71% -========================= - - -========================= -cards on table: 30 -------------------------- - flush 97.28% - high card 97.18% - straight 86.41% - one pair 80.28% - two pair 63.73% - three of a kind 43.11% - full house 34.30% - straight flush 20.66% - four of a kind 10.20% -========================= - - -========================= -cards on table: 35 -------------------------- - flush 99.81% - high card 99.17% - straight 95.85% - one pair 90.40% - two pair 81.44% - three of a kind 60.41% - full house 54.46% - straight flush 42.98% - four of a kind 19.26% -========================= - - -========================= -cards on table: 40 -------------------------- - flush 99.99% - high card 99.82% - straight 99.10% - one pair 96.67% - two pair 93.39% - three of a kind 77.70% - full house 75.08% - straight flush 72.44% - four of a kind 33.51% -========================= - - -========================= -cards on table: 45 -------------------------- - flush 100.00% - high card 99.99% - straight 99.95% - one pair 99.40% - two pair 98.79% - straight flush 95.18% - three of a kind 91.70% - full house 91.16% - four of a kind 55.07% -========================= - - -========================= -cards on table: 50 -------------------------- - two pair 100.00% - high card 100.00% - one pair 100.00% - straight 100.00% - straight flush 100.00% - flush 100.00% - three of a kind 99.55% - full house 99.55% - four of a kind 85.07% -========================= +=========================== + cards on table: 5 +--------------------------- + high card 34.1300% + one pair 4.1423% + three of a kind 0.1862% + two pair 0.0619% + straight 0.0490% + flush 0.0425% + full house 0.0150% + four of a kind 0.0031% + straight flush 0.0020% +=========================== + + +=========================== + cards on table: 10 +--------------------------- + high card 58.6462% + one pair 16.2438% + flush 5.6900% + straight 4.1470% + two pair 1.9659% + three of a kind 1.9515% + full house 0.3208% + four of a kind 0.0815% + straight flush 0.0430% +=========================== + + +=========================== + cards on table: 15 +--------------------------- + high card 75.6608% + one pair 32.5154% + flush 29.1625% + straight 21.1830% + two pair 9.2677% + three of a kind 6.7485% + full house 2.0982% + straight flush 0.4850% + four of a kind 0.4600% +=========================== + + +=========================== + cards on table: 20 +--------------------------- + high card 86.7323% + flush 62.1725% + one pair 50.0654% + straight 46.7040% + two pair 23.5749% + three of a kind 15.2077% + full house 7.3528% + straight flush 2.3450% + four of a kind 1.8408% +=========================== + + +=========================== + cards on table: 25 +--------------------------- + high card 93.5500% + flush 86.8575% + straight 70.4850% + one pair 66.5346% + two pair 43.0365% + three of a kind 27.5062% + full house 17.9522% + straight flush 8.1390% + four of a kind 4.7169% +=========================== + + +=========================== + cards on table: 30 +--------------------------- + flush 97.4700% + high card 97.3762% + straight 87.4620% + one pair 80.1569% + two pair 63.5406% + three of a kind 43.1085% + full house 34.2401% + straight flush 20.9020% + four of a kind 10.1277% +=========================== + + +=========================== + cards on table: 35 +--------------------------- + flush 99.7875% + high card 99.0900% + straight 95.5010% + one pair 90.3608% + two pair 81.3709% + three of a kind 60.4369% + full house 54.4532% + straight flush 42.8760% + four of a kind 19.3431% +=========================== + + +=========================== + cards on table: 40 +--------------------------- + flush 99.9950% + high card 99.8092% + straight 98.9990% + one pair 96.5685% + two pair 93.1968% + three of a kind 77.5346% + full house 74.8518% + straight flush 72.4400% + four of a kind 33.7800% +=========================== + + +=========================== + cards on table: 45 +--------------------------- + flush 100.0000% + high card 99.9869% + straight 99.9430% + one pair 99.3954% + two pair 98.7910% + straight flush 95.2640% + three of a kind 91.7577% + full house 91.2159% + four of a kind 55.0138% +=========================== + + +=========================== + cards on table: 50 +--------------------------- + high card 100.0000% + one pair 100.0000% + two pair 100.0000% + straight 100.0000% + flush 100.0000% + straight flush 100.0000% + three of a kind 99.5700% + full house 99.5700% + four of a kind 85.0454% +=========================== ``` diff --git a/main.py b/main.py index 79948ba..d6c15d3 100755 --- a/main.py +++ b/main.py @@ -90,50 +90,133 @@ def find_hands(table): "straight flush": find_straight_flush(table), } - -def find_hand_averages(result): - output = {} - for hand in result: - output[hand] = 0 - for hand_type in result[hand]: - output[hand] += result[hand][hand_type] / len(result[hand]) - return output +def sanity_check(table, result): + for hand_type in result["one pair"]: + if result["one pair"][hand_type] and not result["high card"][hand_type]: + print(f"Invalid result at one pair of {hand_type} but not high card") + print(table) + print(result) + + for hand_type in result["two pair"]: + [rank1, rank2] = hand_type.split("+") + if result["two pair"][hand_type] and not (result["one pair"][rank1] and result["one pair"][rank2]): + print(f"Invalid result at two pair of {hand_type} but not respective one pairs") + print(table) + print(result) + + for hand_type in result["three of a kind"]: + if result["three of a kind"][hand_type] and not result["one pair"][hand_type]: + print(f"Invalid result at three of a kind of {hand_type} but not one pair") + print(table) + print(result) + + for hand_type in result["straight"]: + i = LOOPED_RANKS.index(hand_type) + if result["straight"][hand_type] and not (result["high card"][LOOPED_RANKS[i-4]] and + result["high card"][LOOPED_RANKS[i-3]] and + result["high card"][LOOPED_RANKS[i-2]] and + result["high card"][LOOPED_RANKS[i-1]] and + result["high card"][LOOPED_RANKS[i]]): + print(f"Invalid result at straight of {hand_type} but not high cards") + print(table) + print(result) + + for hand_type in result["full house"]: + [rank1, rank2] = hand_type.split(" over ") + if result["full house"][hand_type] and not (result["three of a kind"][rank1] and result["one pair"][rank2]): + print(f"Invalid result at full house of {hand_type} but not respective three of a kind and one pair") + print(table) + print(result) + + for hand_type in result["four of a kind"]: + if result["four of a kind"][hand_type] and not result["three of a kind"][hand_type]: + print(f"Invalid result at four of a kind of {hand_type} but not three of a kind") + print(table) + print(result) + + for hand_type in result["straight flush"]: + if result["straight flush"][hand_type] and not result["straight"][hand_type]: + print(f"Invalid result at straight flush of {hand_type} but not straight") + print(table) + print(result) + +# def find_hand_averages(result): +# output = {} +# for hand in result: +# output[hand] = 0 +# for hand_type in result[hand]: +# output[hand] += result[hand][hand_type] +# output[hand] /= len(result[hand]) +# return output def find_probabilities(size): - results = [find_hands(sample(DECK, size)) for _ in range(SAMPLE_SIZE)] - output = {} + results = [] + for _ in range(SAMPLE_SIZE): + table = sample(DECK, size) + result = find_hands(table) + sanity_check(table, result) + results += [result] + + # The idea was to find the probability of each hand this way: + # for each hand + # for each hand_type of this hand + # find the probability of this hand_type with occurrences / SAMPLE_SIZE + # find the probability of the hand by averaging the probability of each hand_type, that is + # sum everything and divide by the number of types (= len(results[0][hand])) + # We don't use this approach becuase finding the intermediate probabilities for each hand_type introduces + # division, which comes with rounding errors. + # To avoid this we postpone division as much as possible, working with integers as much as possible + probabilities = {} for hand in results[0]: - output[hand] = {} + occurrences = 0 for hand_type in results[0][hand]: - output[hand][hand_type] = 0 + occurrences_per_type = 0 for i in range(SAMPLE_SIZE): if results[i][hand][hand_type]: - output[hand][hand_type] += 1/SAMPLE_SIZE - return find_hand_averages(output) + occurrences_per_type += 1 + # probability_per_type should be occurrences_per_type / len(results[0][hand]) but + # it's better to postpone divisions as much as possible to prevent rounding errors + occurrences += occurrences_per_type + probabilities[hand] = occurrences / (SAMPLE_SIZE * len(results[0][hand])) + + return probabilities + + # output = {} + # for hand in results[0]: + # output[hand] = {} + # for hand_type in results[0][hand]: + # output[hand][hand_type] = 0 + # for i in range(SAMPLE_SIZE): + # if results[i][hand][hand_type]: + # output[hand][hand_type] += 1 + # output[hand][hand_type] /= SAMPLE_SIZE + # return find_hand_averages(output) groups = tuple(range(5, 52, 5)) global_results = { "high card": (), + "flush": (), "one pair": (), + "straight": (), "two pair": (), "three of a kind": (), - "straight": (), - "flush": (), "full house": (), - "four of a kind": (), "straight flush": (), + "four of a kind": (), } for size in groups: - print("=========================") - print("cards on table:", str(size).rjust(8)) - print("-------------------------") results = find_probabilities(size) for hand in global_results: global_results[hand] += (results[hand],) + results = sorted(results.items(), key=lambda hand: -hand[1]) + print("===========================") + print(" cards on table:", str(size).rjust(9)) + print("---------------------------") for (hand, p) in results: - str_p = f"{p:.2%}" - print(" " + hand.ljust(15) + str_p.rjust(8)) - print("=========================") + str_p = f"{p:.4%}" + # str_p = f"{p}" + print(" " + hand.ljust(15) + str_p.rjust(10)) + print("===========================") print("") print("") @@ -157,5 +240,3 @@ ax.legend(loc='upper left', ncols=3) ax.set_ylim(0, 1.05) plt.show() - - diff --git a/results.png b/results.png index 2ae8c82..2759592 100644 Binary files a/results.png and b/results.png differ