2011-03-14 27 views
6

好吧,我正在爲我的高級項目製作德州撲克AI。我已經創建了gui和投注/交易程序,但是我已經達到了需要確定誰贏了牌局的部分,但我不知道處理此問題的最佳方法。我正在使用python btw。 ATM我有2個列表,一個用於7個播放卡,另一個用於7個電腦卡。目前,所有卡都以結構形式存儲在列表中,其格式爲{'Number':XX,'Suit':x},其中數字爲2-14,套數爲1-4。我要這樣做的方式是爲每種手型制定一個功能,從最高處開始。例如。 self.CheckRoyal(playerCards),並手動瀏覽列表並評估是否實現了皇家沖洗。必須有更好的,數字化的方式來做到這一點。確定德州撲克手贏家的算法

+0

那麼你的問題是什麼? – Gabe 2011-03-14 00:12:22

+0

@UCLcajun:這可能有一些幫助 - http://code.google.com/p/specialkpokereval/。 – SK9 2011-03-24 06:30:27

+0

簡易圖書館在蟒蛇,也處理卡片,甲板等:[https://github.com/worldveil/deuces](https://github.com/worldveil/deuces)。 – lollercoaster 2014-08-19 05:11:28

回答

7

http://www.codingthewheel.com/archives/poker-hand-evaluator-roundup

你會得到最好的算法是7個在外觀尺寸100 MB查找表(如果我沒記錯)

+0

您是否正在談論生成3200萬個條目並遵循基於您的手的路徑的兩種加兩種方法?如果是這樣,我會如何適應python,因爲它使用指針的功能? – ULcajun 2011-03-14 02:25:05

+0

@ULcajun:上面鏈接中列出的http://pokersource.sourceforge.net/有python綁定。 – 2011-03-14 03:37:38

+2

這裏提供的要求不高,至少有很好的評估者:http://code.google.com/p/specialkpokereval/。也在下面描述。 – SK9 2011-03-24 06:27:18

0

Monte Carlo?這是我看到的第一個建議here。這是另一個高級項目。簡單而緩慢,但否則你可能會看到一些複雜的組合,我不會假裝知道很多。

+2

您所引用的論文正試圖解決一個更有趣的問題。提問者只是想要一個算法來確定給定手牌的勝者(例如,直接衝過來)。 – dfan 2011-03-14 00:55:32

+2

蒙特卡洛通過模擬數以百萬計的撲克遊戲來查找對手的近似公平性。它使用OP想要的算法:) – 2011-03-14 01:05:41

+0

啊,是的。正確的你!我清楚地閱讀了這個問題,並回答了我腦海中出現的問題,而不是問了什麼...... – Ricky 2014-03-13 18:48:02

2

ralu的帖子中使用的方法是迄今爲止我見過的最好的選擇。我在自己的項目中使用了這種方法,而且速度非常快。

懸崖:

做一些預處理,以產生一個表,包含用於每個不同的撲克手一個值。確保桌子是按手工排序的。

每個卡片值都有相應的素數值。該表格由手中每張牌值的乘積索引。因此,要找到手AAAAK的價值,你計算黃金乘法,並以此作爲索引表:

int prime = getPrime(hand); // Calculates A.getPrime()...*K.getPrime(); 
int value = table[prime]; 

(很抱歉的Java語法)。

這樣,AAAAK與KAAAA是同一隻手,並且您不需要5個暗表。

請注意,您需要通過所有最好的5張牌組合,以及可以選擇的7張牌來找到最大的值,這是手牌的真實價值。

您使用不同的表格進行沖洗。

表格變得很健壯,因爲這個實現有很多浪費的單元格。爲了解決這個問題,您可以在預處理過程中創建一個映射,它將較大的素數值映射爲整數值,並將其用作源代碼。

+1

要求不高,至少有很好的評估者在這裏提供:code.google.com/p/specialkpokereval。在我的答案中也描述了這個頁面。請享用! – SK9 2011-03-24 06:28:11

+0

看起來很有趣。感謝分享! – 2011-03-24 13:01:35

1

一個現成的德州撲克7和5卡評估器的例子可以找到here和進一步解釋here。這可能會幫助你提高性能。所有的反饋意見歡迎在其中找到的電子郵件地址。

1
import itertools 
from collections import Counter 

# gets the most common element from a list 
def Most_Common(lst): 
    data = Counter(lst) 
    return data.most_common(1)[0] 



# gets card value from a hand. converts A to 14, is_seq function will convert the 14 to a 1 when necessary to evaluate A 2 3 4 5 straights 
def convert_tonums(h, nums = {'T':10, 'J':11, 'Q':12, 'K':13, "A": 14}): 
    for x in xrange(len(h)): 

     if (h[x][0]) in nums.keys(): 

      h[x] = str(nums[h[x][0]]) + h[x][1] 

    return h 


# is royal flush 
# if a hand is a straight and a flush and the lowest value is a 10 then it is a royal flush 
def is_royal(h): 
    nh = convert_tonums(h) 
    if is_seq(h): 
     if is_flush(h): 
      nn = [int(x[:-1]) for x in nh] 
      if min(nn) == 10: 
       return True 

    else: 
     return False 


# converts hand to number valeus and then evaluates if they are sequential AKA a straight 
def is_seq(h): 
    ace = False 
    r = h[:] 

    h = [x[:-1] for x in convert_tonums(h)] 


    h = [int(x) for x in h] 
    h = list(sorted(h)) 
    ref = True 
    for x in xrange(0,len(h)-1): 
     if not h[x]+1 == h[x+1]: 
      ref = False 
      break 

    if ref: 
     return True, r 

    aces = [i for i in h if str(i) == "14"] 
    if len(aces) == 1: 
     for x in xrange(len(h)): 
      if str(h[x]) == "14": 
       h[x] = 1 

    h = list(sorted(h)) 
    for x in xrange(0,len(h)-1): 
     if not h[x]+1 == h[x+1]: 

      return False 
    return True, r 

# call set() on the suite values of the hand and if it is 1 then they are all the same suit 
def is_flush(h): 
    suits = [x[-1] for x in h] 
    if len(set(suits)) == 1: 
     return True, h 
    else: 
     return False 


# if the most common element occurs 4 times then it is a four of a kind 
def is_fourofakind(h): 
    h = [a[:-1] for a in h] 
    i = Most_Common(h) 
    if i[1] == 4: 
     return True, i[0] 
    else: 
     return False 


# if the most common element occurs 3 times then it is a three of a kind 
def is_threeofakind(h): 
    h = [a[:-1] for a in h] 
    i = Most_Common(h) 
    if i[1] == 3: 
     return True, i[0] 
    else: 
     return False 


# if the first 2 most common elements have counts of 3 and 2, then it is a full house 
def is_fullhouse(h): 
    h = [a[:-1] for a in h] 
    data = Counter(h) 
    a, b = data.most_common(1)[0], data.most_common(2)[-1] 
    if str(a[1]) == '3' and str(b[1]) == '2': 
     return True, (a, b) 
    return False 

# if the first 2 most common elements have counts of 2 and 2 then it is a two pair 
def is_twopair(h): 
    h = [a[:-1] for a in h] 
    data = Counter(h) 
    a, b = data.most_common(1)[0], data.most_common(2)[-1] 
    if str(a[1]) == '2' and str(b[1]) == '2': 
     return True, (a[0], b[0]) 
    return False 


#if the first most common element is 2 then it is a pair 
# DISCLAIMER: this will return true if the hand is a two pair, but this should not be a conflict because is_twopair is always evaluated and returned first 
def is_pair(h): 
    h = [a[:-1] for a in h] 
    data = Counter(h) 
    a = data.most_common(1)[0] 

    if str(a[1]) == '2': 
     return True, (a[0]) 
    else: 
     return False 

#get the high card 
def get_high(h): 
    return list(sorted([int(x[:-1]) for x in convert_tonums(h)], reverse =True))[0] 

# FOR HIGH CARD or ties, this function compares two hands by ordering the hands from highest to lowest and comparing each card and returning when one is higher then the other 
def compare(xs, ys): 
    xs, ys = list(sorted(xs, reverse =True)), list(sorted(ys, reverse = True)) 

    for i, c in enumerate(xs): 
    if ys[i] > c: 
     return 'RIGHT' 
    elif ys[i] < c: 
     return 'LEFT' 

    return "TIE" 


# categorized a hand based on previous functions 
def evaluate_hand(h): 

    if is_royal(h): 
     return "ROYAL FLUSH", h, 10 
    elif is_seq(h) and is_flush(h) : 
     return "STRAIGHT FLUSH", h, 9 
    elif is_fourofakind(h): 
     _, fourofakind = is_fourofakind(h) 
     return "FOUR OF A KIND", fourofakind, 8 
    elif is_fullhouse(h): 
     return "FULL HOUSE", h, 7 
    elif is_flush(h): 
     _, flush = is_flush(h) 
     return "FLUSH", h, 6 
    elif is_seq(h): 
     _, seq = is_seq(h) 
     return "STRAIGHT", h, 5 
    elif is_threeofakind(h): 
     _, threeofakind = is_threeofakind(h) 
     return "THREE OF A KIND", threeofakind, 4 
    elif is_twopair(h): 
     _, two_pair = is_twopair(h) 
     return "TWO PAIR", two_pair, 3 
    elif is_pair(h): 
     _, pair = is_pair(h) 
     return "PAIR", pair, 2 
    else: 
     return "HIGH CARD", h, 1 



#this monster function evaluates two hands and also deals with ties and edge cases 
# this probably should be broken up into separate functions but aint no body got time for that 
def compare_hands(h1,h2): 
    one, two = evaluate_hand(h1), evaluate_hand(h2) 
    if one[0] == two[0]: 

     if one[0] =="STRAIGHT FLUSH": 

      sett1, sett2 = convert_tonums(h1), convert_tonums(h2) 
      sett1, sett2 = [int(x[:-1]) for x in sett1], [int(x[:-1]) for x in sett2] 
      com = compare(sett1, sett2) 

      if com == "TIE": 
       return "none", one[1], two[1] 
      elif com == "RIGHT": 
       return "right", two[0], two[1] 
      else: 
       return "left", one[0], one[1] 

     elif one[0] == "TWO PAIR": 

      leftover1, leftover2 = is_twopair(h1), is_twopair(h2) 
      twm1, twm2 = max([int(x) for x in list(leftover1[1])]), max([int(x) for x in list(leftover2[1])]) 
      if twm1 > twm2: 
       return "left", one[0], one[1] 
      elif twm1 < twm2: 
       return "right", two[0], two[1] 


      if compare(list(leftover1[1]), list(leftover2[1])) == "TIE": 
       l1 = [x[:-1] for x in h1 if x[:-1] not in leftover1[1]] 
       l2 = [x[:-1] for x in h2 if x[:-1] not in leftover2[1]] 
       if int(l1[0]) == int(l2[0]): 
        return "none", one[1], two[1] 
       elif int(l1[0]) > int(l2[0]): 
        return "left", one[0], one[1] 
       else: 
        return "right", two[0], two[1] 
      elif compare(list(leftover1[1]), list(leftover2[1])) == "RIGHT": 
       return "right", two[0], two[1] 
      elif compare(list(leftover1[1]), list(leftover2[1])) == "LEFT": 
       return "left", one[0], one[1] 


     elif one[0] == "PAIR": 
      sh1, sh2 = int(is_pair(h1)[1]), int(is_pair(h2)[1]) 
      if sh1 == sh2: 

       c1 = [int(x[:-1]) for x in convert_tonums(h1) if not int(sh1) == int(x[:-1])] 
       c2 = [int(x[:-1]) for x in convert_tonums(h2) if not int(sh1) == int(x[:-1])] 
       if compare(c1, c2) == "TIE": 
        return "none", one[1], two[1] 
       elif compare(c1, c2) == "RIGHT": 
        return "right", two[0], two[1] 
       else: 
        return "left", one[0], one[1] 




      elif h1 > h2: 
       return "right", two[0], two[1] 
      else: 
       return "left", one[0], one[1] 

     elif one[0] == 'FULL HOUSE': 

      fh1, fh2 = int(is_fullhouse(h1)[1][0][0]), int(is_fullhouse(h2)[1][0][0]) 
      if fh1 > fh2: 
       return "left", one[0], one[1] 
      else: 
       return "right", two[0], two[1] 
     elif one[0] == "HIGH CARD": 
      sett1, sett2 = convert_tonums(h1), convert_tonums(h2) 
      sett1, sett2 = [int(x[:-1]) for x in sett1], [int(x[:-1]) for x in sett2] 
      com = compare(sett1, sett2) 
      if com == "TIE": 
       return "none", one[1], two[1] 
      elif com == "RIGHT": 
       return "right", two[0], two[1] 
      else: 
       return "left", one[0], one[1] 



     elif len(one[1]) < 5: 
      if max(one[1]) == max(two[1]): 
       return "none", one[1], two[1] 
      elif max(one[1]) > max(two[1]): 
       return "left", one[0], one[1] 
      else: 
       return "right", two[0], two[1] 
     else: 
      n_one, n_two = convert_tonums(one[1]), convert_tonums(two[1]) 
      n_one, n_two = [int(x[:-1]) for x in n_one], [int(x[:-1]) for x in n_two] 

      if max(n_one) == max(n_two): 
       return "none", one[1], two[1] 
      elif max(n_one) > max(n_two): 
       return "left", one[0], one[1] 
      else: 
       return "right", two[0], two[1] 
    elif one[2] > two[2]: 
     return "left", one[0], one[1] 
    else: 
     return "right", two[0], two[1] 



''' 
a = ['QD', 'KD', '9D', 'JD', 'TD'] 
b = ['JS', '8S', 'KS', 'AS', 'QS'] 
print compare_hands(a,b) 
'''