2017-02-11 34 views
0

我正在嘗試寫一個撲克賠率計算器。背後的想法是,它強制通過可能發揮的所有可能的卡組合的方式。一副撲克牌的所有非重複組合

我當前邏輯(剝離下來以方便的讀數)如下;

For i = 0 To unknownCards - 1 
      For j = 1 To 4 
       'pick suit 

       For k = 1 To 13 
        'pick number 

         'do other work here 

       Next 
      Next 
     Next 

然而這是錯誤的。它只是按順序循環使用卡片。爲了我的目的,牌的順序並不重要(例如,我不想分別處理2,3,4和4,3,2),但重要的是我看到每一種可能的獨特組合。我只是無法圍繞如何做到這一點?任何幫助或建議都會很棒。

P.S.我在VB.net

+0

你的意思是,「有5張牌有多少手」?這是一個數學問題:52選擇5,即(52!)/(5!* 47!)或(52 * 51 * 50 * 49 * 48)/ 5 !.計算給定手的概率也是一個容易搜索的數學問題。 –

+0

@ ElizabethS.Q.Goodman nope,(儘管這是它的一部分),但我試圖通過所有可能的不同手來循環。 – FraserOfSmeg

+0

我會補充一點,如果你試圖計算諸如「獲得四種類型的可能性」之類的東西,那也是一個數學問題,你可以查看它;沒有必要經歷撲克的每一手牌。 –

回答

2

有2,598,960個可能的手。此代碼通過暴力產生所有可能的手。生成52卡指數的組合更容易,更快速/更容易/更好,而不必擔心循環中的套裝和等級。究竟是什麼@ElizabethSQGoodman說,有5個嵌套循環,每個循環都比我之前的要高。

我選擇了一個字節來保存每個卡和結構,以保持手,性能方面的原因。然後,,你可以計算出每一個基於規則什麼牌:第13個卡俱樂部,接下來的13顆鑽石等(見getHumanReadableHand())。在那裏,你也可以定義高或低(但不是兩個,對不起!)。秩(A,2,3,...,J,Q,K)由索引模13確定。訴訟由索引中的整數除13確定。

Module Module1 

    Sub Main() 
     Dim hands As New List(Of Hand)() 
     For c0 As SByte = 0 To 51 
      For c1 As SByte = c0 + 1 To 51 
       For c2 As SByte = c1 + 1 To 51 
        For c3 As SByte = c2 + 1 To 51 
         For c4 As SByte = c3 + 1 To 51 
          Dim hand = New Hand 
          hand.Card0 = c0 
          hand.Card1 = c1 
          hand.Card2 = c2 
          hand.Card3 = c3 
          hand.Card4 = c4 
          hands.Add(hand) 
         Next c4 
        Next c3 
       Next c2 
      Next c1 
     Next c0 
     Console.WriteLine("There are {0} possible hands.", hands.Count) 
     Dim rnd As New Random() 
     Dim r = rnd.Next(hands.Count - 1) 
     Console.WriteLine("Random hand: {0}", getHumanReadableHand(hands(r))) 
     Console.WriteLine("Value: {0}", getHandValue(hands(r))) 
     Console.ReadLine() 
    End Sub 

    Function getHumanReadableHand(hand As Hand) As String 
     Static suits = {"C", "D", "H", "S"} 
     Static ranks = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"} 
     Return String.Join(", ", hand.Cards.Select(Function(card) ranks(rank(card)) & suits(suit(card)))) 
    End Function 

    Private Function rank(card As SByte) As SByte 
     Return card Mod 13 
    End Function 

    Private Function suit(card As SByte) As SByte 
     Return CSByte(card \ 13) 
    End Function 

    Function getHandValue(hand As Hand) As String 
     Dim cards = hand.Cards 
     If cards.Select(Function(card) rank(card)).Max() - cards.Select(Function(card) rank(card)).Min() = 4 AndAlso 
      cards.Select(Function(card) rank(card)).Distinct().Count = 5 AndAlso 
      cards.Select(Function(card) suit(card)).Distinct().Count = 1 Then 
      Return "Straight Flush" 
     ElseIf cards.OrderBy(Function(card) rank(card)).Take(4).Select(Function(card) rank(card)).Distinct().Count = 1 OrElse 
      cards.OrderBy(Function(card) rank(card)).Skip(1).Take(4).Select(Function(card) rank(card)).Distinct().Count = 1 Then 
      Return "Four of a Kind" 
     ElseIf cards.Select(Function(card) rank(card)).Distinct().Count = 2 Then 
      Return "Full House" 
     ElseIf cards.Select(Function(card) suit(card)).Distinct().Count = 1 Then 
      Return "Flush" 
     ElseIf cards.Select(Function(card) rank(card)).Max() - cards.Select(Function(card) rank(card)).Min() = 4 AndAlso 
      cards.Select(Function(card) rank(card)).Distinct().Count = 5 Then 
      Return "Straight" 
     ElseIf cards.OrderBy(Function(card) rank(card)).Take(3).Select(Function(card) rank(card)).Distinct().Count = 1 OrElse 
      cards.OrderBy(Function(card) rank(card)).Skip(1).Take(3).Select(Function(card) rank(card)).Distinct().Count = 1 OrElse 
      cards.OrderBy(Function(card) rank(card)).Skip(2).Take(3).Select(Function(card) rank(card)).Distinct().Count = 1 Then 
      Return "Three of a Kind" 
     ElseIf cards.Select(Function(card) rank(card)).Distinct().Count = 3 Then 
      Return "Two Pairs" 
     ElseIf cards.Select(Function(card) rank(card)).Distinct().Count = 4 Then 
      Return "One Pair" 
     Else 
      Return "Garbage" 
     End If 
    End Function 

    Structure Hand 

     Public Property Card0 As SByte 
     Public Property Card1 As SByte 
     Public Property Card2 As SByte 
     Public Property Card3 As SByte 
     Public Property Card4 As SByte 

     Public ReadOnly Property Cards As IEnumerable(Of SByte) 
      Get 
       Return New List(Of SByte)({Card0, Card1, Card2, Card3, Card4}) 
      End Get 
     End Property 

    End Structure 

End Module 

輸出示例:

有2598960手可能。
隨機手:2C,5C,2D,5S,KS
價值:兩對

此代碼需要大約60毫秒產生我的機器上所有可能的手中。

0

這樣的評論澄清後:蠻力讓所有的手,我知道這樣做是強加給卡訂單的最簡單方法的列表(例如,由數對他們進行排名然後套裝:標準是2低的俱樂部,黑桃王牌高)然後選擇按升序排列的手。這種方式即使順序對你無關緊要,整理你的雙手確保你有一個明確的方式來決定獨特的手。

一個很容易理解但不是最佳的方法是嵌套5個循環:第一張卡片的整個卡片,然後通過循環所有低於該卡片的卡片來選擇第二張卡片,等等。 (實際上,你可以選擇第一張牌從第五張牌開始,即3張牌,等等,但當你完成後,確保每張牌有5張牌可能更容易。)

我的選擇的語言是Python;如果你想要完整的列表,我會列出52張卡片,或者更好的數字卡片和使用範圍;然後用itertools.product名單上的5倍以上,只允許其中的雙手card_1 < card_2 < card_3 < card_4 < card_5。見this question使用。對於迭代器,我會查看他們記錄的代碼並修改它以僅允許上升的手。也許更有經驗的編碼人員可能會提出一個最佳的迭代器。