科技改變生活 · 科技引領未來
介紹在本文中,我們展示了如何在Python中表示基本的撲克元素,例如"手"和"組合",以及如何計算撲克賠率,即在無限額德州撲克中獲勝/平局/失敗的可能性。我們根據《拉斯維加斯威尼斯之夜》中的真實故事提供實用的
介紹
在本文中,我們展示了如何在Python中表示基本的撲克元素,例如"手"和"組合",以及如何計算撲克賠率,即在無限額德州撲克中獲勝/平局/失敗的可能性。
我們根據《拉斯維加斯威尼斯之夜》中的真實故事提供實用的分析。
我們將使用poker包來表示手牌,連擊和范圍。 我已經擴展了來自Kevin Tseng的撲克賠率計算器,因此它除了能夠計算單個手牌之外,還可以基于范圍(可能的手牌)來計算撲克概率。
from poker import Range from poker.hand import Combo import holdem_calc import holdem_functions import numpy as np import pandas as pd import matplotlib.pyplot as plt from IPython.core.display import display, HTML hero_odds = [] hero_range_odds = []
翻牌圈
我的手牌為K和J(K?J?),我使用來自poker.hand的Combo類構造我的手牌。
# my hand = King of spades and Jack of clubs hero_hand = Combo('KsJc') print(hero_hand)
我記不清翻牌前發生的事情以及我的位置。 但是,我確實記得翻牌前有加注,而翻牌后只剩下兩名選手:我和對方。
我們現在要注意。 翻牌圈出現梅花Q,紅桃10和梅花J。 是的,我翻到了順子!
讓我們假設沒有對方撲克的先驗知識來計算翻牌后的賠率,即在翻牌后,我們將計算出我的牌勝過隨機的一對牌的可能性。
odds[0] {'tie': 0.04138424018164999, 'win': 0.9308440557284221, 'lose': 0.027771704089927955}
Holdemcalc中的函數calculateodds_villan可以計算出特定的德州撲克贏手的概率。 通過運行蒙特卡洛方法可以估算出該概率,也可以通過模擬所有可能的情況來準確地計算出該概率,快速計算翻牌后的確切賠率。因此在這里我們不需要蒙特卡洛近似值。 這是我們的賠率:
odds[0] {'tie': 0.04138424018164999, 'win': 0.9308440557284221, 'lose': 0.027771704089927955}
此時,我感覺還不錯。 在隨機的情況下,我只有2.77%的機會輸,獲勝的機會超過93%。 這很樂觀。
考慮到翻牌前有加注,而只有我和對方在翻牌后才離開,所以對方有一些手牌,對吧? 我們稱這種可能的手為范圍。 這是我們根據幾個因素(包括對方的舉止,位置,下注大小等)做出的推論。該推論導致我們假設對方可能擁有一組手牌。 在這一點上,我認為對方有:
· 一對7或更好
· A /10或更好
· K/J或更好
我們可以使用"類別范圍"來表示該范圍,如下所示:
villan_range = Range('77+, AT+, KJ+') display(HTML(villan_range.to_html())) print("#combo combinations:" + str(len(villan_range.combos)))
這使對方手牌組合從總共51 * 52–1 = 2651個可能減少到144種可能。 現在假設對方手牌的范圍來計算我的賠率。
{'tie': 0.11423324150596878, 'win': 0.8030711151923272, 'lose': 0.08269564330170391}
for hand_ranking in holdem_functions.hand_rankings: print(hand_ranking +": " + str(np.mean([res[1][1][hand_ranking] for res in items if res])))
在假定的范圍內,我的獲勝幾率從93%下降至80%。 但是,我仍然很可能損失8.2%。 在這一點上,我很明確。 但是我應該繼續嗎? 我絕對希望對方繼續比賽并且不棄牌。 但是他在翻牌后有個好牌的可能性有多大? 讓我們看看如果我們繼續玩到最后,他伸手的幾率是多少。
High Card: 0.06978879706152433 Pair: 0.3662891541679421 Two Pair: 0.23085399449035812 Three of a Kind: 0.09733700642791548 Straight: 0.18498112437506367 Flush: 0.0040608101214161816 Full House: 0.04205693296602388 Four of a Kind: 0.004560759106213652 Straight Flush: 2.0406081012141617e-05 Royal Flush: 5.101520253035404e-05
High Card: 0.06978879706152433 Pair: 0.3662891541679421 Two Pair: 0.23085399449035812 Three of a Kind: 0.09733700642791548 Straight: 0.18498112437506367 Flush: 0.0040608101214161816 Full House: 0.04205693296602388 Four of a Kind: 0.004560759106213652 Straight Flush: 2.0406081012141617e-05 Royal Flush: 5.101520253035404e-05
如果我們繼續玩,對方很有可能做出一對(36%)或兩對(23%)。 他極有可能直接命中(18%)甚至打出盤(9.7%)或滿堂(4%)。 由于對方很有可能擁有合理的手牌,因此我決定下高注,大約底池的2/3。
轉牌
到轉牌了,是方片2(2?)。 基本上,這是一張空白牌,也就是說,它對我們的游戲沒有太大影響。
turn= ["2d"] board = flop + turn villan_hand = None odds = holdem_calc.calculate_odds_villan(board, exact_calculation, num_sims, read_from_file , hero_hand, villan_hand, verbose, print_elapsed_time = True) hero_odds.append(odds[0]['win']) print(odds[0])
{'tie': 0.0233201581027668, 'win': 0.9677206851119895, 'lose': 0.008959156785243741}
假設對方的牌是隨機的,那么我現在有96%的獲勝幾率。
但是,考慮到我假定的對方手牌范圍,我的獲勝幾率現在從翻牌時的80%上升到86%。 我再次下注,對方跟注,河牌來了。
items = [holdem_calc.calculate_odds_villan(board, exact_calculation, num_sims, read_from_file , hero_hand, villan_hand, verbose, print_elapsed_time = False) for villan_hand in villan_range.combos] odds = {} [odds.update({odd_type: np.mean([res[0][odd_type] for res in items if res])}) for odd_type in ["tie", "win", "lose"]]
{'tie': 0.10123966942148759, 'win': 0.8615702479338843, 'lose': 0.0371900826446281}
河牌
是梅花K(K?)。 這使對方更容易勝利。 所以這對我來說是個壞消息。
river = ["Kc"] board = flop + turn + river verbose = True villan_hand = None odds = holdem_calc.calculate_odds_villan(board, exact_calculation, num_sims, read_from_file , hero_hand, villan_hand, verbose, print_elapsed_time = True) hero_odds.append(odds[0]['win']) print(odds[0])
{'tie': 0.11818181818181818, 'win': 0.8696969696969697, 'lose': 0.012121212121212121}
現在,我對隨機牌的獲勝幾率從96%降至約87%。 但我仍然只以1.2%的極低概率輸掉。 好吧,那條壞的河牌不是那么糟吧?
好吧,還有另外一個因素。 對方在翻牌圈和河牌圈都跟我有大賭注。 他可能比我想像的要好...對嗎? 然后,我應該調整我的假定范圍。
現在,我認為對方不再擁有77或88的一對,否則,鑒于我的高賭注,他不會跟下去。 我認為他可能有一對9或更好的一對,才能與99、10或QQ配對。 他可能還會有JJ從而導致平局。 或KK和AA,直到轉牌時都是頭對。 我決定保持10和K或更好的牌,因為有所謂的隱含賠率。 隱含賠率是對您打出的一筆錢可以從投注中贏取多少錢的估計。 因此,對方可能會等待中獎(他可能剛剛中了?)。 因此,我將對方的更新范圍定義如下:
villan_range = Range('99+, AT+, KJ+') display(HTML(villan_range.to_html())) print("#combo combinations:" + str(len(villan_range.combos)))
現在,對方的連擊數從144降低到了132。讓我們計算更新后的賠率。
items = [holdem_calc.calculate_odds_villan(board, exact_calculation, num_sims, read_from_file , hero_hand, villan_hand, verbose, print_elapsed_time = False) for villan_hand in villan_range.combos] odds = {} [odds.update({odd_type: np.mean([res[0][odd_type] for res in items if res])}) for odd_type in ["tie", "win", "lose"]]
{'tie': 0.12, 'win': 0.72, 'lose': 0.16}
現在,我有72%的機會獲勝(從86%下降的),而我在轉牌時的失利幾率從3.7%增加到16%。 我決定慎重一下,對方則全押,下注大約70%的彩池。
基本的河牌戰略可以告訴您以下內容:
1. 用你最小的牌作為河牌
1. 利用您最強的資產押注
1. 以中等強度的攤牌值檢查手牌,以期達到攤牌
for hand_ranking in holdem_functions.hand_rankings: print(hand_ranking +": " + str(np.mean([res[1][1][hand_ranking] for res in items if res])))
High Card: 0.0 Pair: 0.5066666666666667 Two Pair: 0.08 Three of a Kind: 0.13333333333333333 Straight: 0.28 Flush: 0.0 Full House: 0.0 Four of a Kind: 0.0 Straight Flush: 0.0 Royal Flush: 0.0
從賠率直方圖中,我們可以將對方的可能手牌分為3種類型:
1. 虛張聲勢:他拿著{好牌,成對}的幾率為60.66%
1. 中強度牌:他以{0.8}的幾率拿著{Two Pair}
1. 價值下注:他以41.33%的幾率持有{三種牌}
對方的全押是有道理的,他持有好牌的概率太低而無法檢查。 所以在這里我在想他要么因為虛弱而虛張聲勢,要么他發瘋了,這是一個有價值的選擇。 如果您的持牌量最差,那么會虛張聲勢;如果您的牌很強,則進行價值下注的基本策略有時被稱為兩極分化下注。 那就是對方在這里所做的。
回顧每種類型的概率(虛張聲勢,中等強度的手牌,價值下注),我基本上應該至少有60.66%的勝率,這是一個保守的衡量標準,因為對方可能會押注三分之一。 但是我應該跟進嗎?
這是另一個稱為底池賠率的概念。 底池賠率是指相對于底池大小進行下注的價格。 總而言之,如果我贏得底池的概率大于底池限注價格和底池大小之間的比率,我應該跟注。 讓我們做一些數學運算:
1. 贏取機會≥60.66%(保守估計)
1. 底池價格= 0.7 *底池大小
1. 預測底池大小=(1 + 0.7 + 0.7)*底池大小
1. 底池賠率=底池價格/預測底池大小= 29%
我獲勝的機會至少是底池賠率的兩倍。 因此,我繼續跟進。 結果呢? 對方轉過牌。 桌子一度安靜,卻凝視著桌子上的Ace Jack。
討論和結論
在本文中,我展示了如何表示基本的撲克元素(例如手牌和組合),以及如何在講述威尼斯人夜晚的故事的同時,假設Python中的隨機手牌和范圍來計算撲克賠率。
我們展示了撲克有多么令人興奮(概率上很有趣)。 在下面,我展示了我的獲勝賠率是如何從翻牌到轉牌,然后是河牌的改變過程,假設對方的隨機牌以及推斷范圍。
我們觀察到,即使最終結果不利于我,我還是贏得這一單挑局的主要人選。 這就是為什么撲克玩家說
你應該專注于做出決定,而不關注所取得的結果。
當然,本文中的所有分析都假設了一些范圍和基本的撲克策略,這些策略和基本的撲克策略構成了我在玩游戲時的思維模型,并在本文中以Python實現。 我不是職業撲克玩家,還有很多方法。 我相信我犯了一些錯誤,例如,低估了對方在翻牌前加注時持有A和J的可能。
我很好奇,其他人將如何使用此處使用的Python框架來分析手牌。
作者:Thársis Souza, PhD
翻譯:孟翔杰
高原明