2014-03-12 25 views
3

我正在尋找一個優雅(快速)的python函數,它可以產生以下兩個數組中的每個組合。一套球員牌/牌手的所有可能的組合

cards = ["8H", "8S", "8C", "8D", "9H", "9S", "9C", "9D", "10H", "10S", "10C", "10D", "AH", "AS", "AC", "AD"] 
players = ["_1", "_1", "_1", "_2", "_2", "_2", "_3", "_3", "_3", "_4", "_4", "_4", "_To", "_To", "_To", "_Tc"] 

結合會是什麼樣子:

[('8H', '_1'), ('8S', '_1'), ('8C', '_1'), ('8D', '_2'), ('9H', '_2'), ('9S', '_2'), ('9C', '_3'), ('9D', '_3'), ('10H', '_3'), ('10S', '_4'), ('10C', '_4'), ('10D', '_4'), ('AH', '_To'), ('AS', '_To'), ('AC', '_To'), ('AD', '_Tc')] 

但是!沒有平等,我的意思是這樣。 例子:

如果卡是:

["a", "b", "c", "d"] 

如果玩家是:

["1", "1", "2", "2"] 

結果:

[1a, 1b, 2c, 2d] 
[1a, 1c, 2b, 2d] 
[1a, 1d, 2b, 2c] 
[1b, 1c, 2a, 2d] 
[1b, 1d, 2a, 2c] 
[1c, 1d, 2a, 2b] 

不例如:

[1a, 1b, 2d, 2c] 

播放器2具有(c和d)等於(d和c)

我已經嘗試的itertools一個功能,如combinationspermutations但沒有運氣。由於狀態空間爆炸,所有組合都不是真正的選項之後拒絕等於。

我希望有人有一個解決方案,因爲谷歌搜索這個具體問題失敗。

+0

我已經使標題和標籤更適合這個問題和相關的問題;以前的標題並不是人們將要搜索的關於這個特定(撲克相關)問題的東西。而「空間」和「國家」標籤在不注意其含義的情況下被挑選出來。 –

回答

3

我建議使用遞歸算法。

我使用的代碼生成器在恆定空間運行,以及開始生成結果ASAP,而不是在最後的巨大結果;如果您以前沒有聽說過發電機,請參閱http://www.dabeaz.com/generators/。作爲一個方面說明,我建議使用規範化的數據結構來保存你的玩家名單和手的大小,以便groupby這條線根本就不是必須的.​​.....而且在任何情況下情況下,一般來說,保持數據默認/大部分時間都是標準化的,並且只使用非規範化/展平形式,例如某些算法可能需要或運行速度較快的平面結構。

這是代碼;隨意提出清理工作/簡化:

from itertools import combinations, groupby, islice 

cards = ["a", "b", "c", "d"] 
players = ["1", "1", "2", "2"] 

def hand_combinations(players, cards): 
    # convert ["1", "1", "2", "2"] into [("1", 2), ("2", 2)] 
    players = list((x, len(list(y))) for x, y in groupby(players)) 

    # sets are faster to operate on in our case 
    cards = set(cards) 

    def generate(players, cards): 
     if not players: 
      yield [] 
     else: 
      # pick the first player 
      player_name, player_hand_size = players[0] 
      # and then walk over all the possible hands for this player 
      for player_hand in combinations(cards, player_hand_size): 
       # for each hand, use the cards that are left to build all the 
       # possible hands for the rest of the players in this iteration 
       for tail in generate(players[1:], cards - set(player_hand)): 
        yield [(player_name, player_hand)] + tail 

    return generate(players, cards) 

# take only the 100 first combinations; otherwise it'll take 
# forever with the larger example 
combos = islice(hand_combinations(players, cards), 0, 100) 

# convert back to the flat structure 
flattened = [ 
    ' '.join(
     player_name + ':' + card 
     for player_name, player_cards in combo 
     for card in player_cards 
    ) 
    for combo in combos 
] 

from pprint import pprint 
pprint(flattened) 

輸出:

['1:a 1:c 2:b 2:d', 
'1:a 1:b 2:c 2:d', 
'1:a 1:d 2:c 2:b', 
'1:c 1:b 2:a 2:d', 
'1:c 1:d 2:a 2:b', 
'1:b 1:d 2:a 2:c'] 

或具有較大examople:

['_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:8D _To:AH _To:9S _To:10D _Tc:8S', 
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:8D _To:AH _To:9S _To:8S _Tc:10D', 
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:8D _To:AH _To:10D _To:8S _Tc:9S', 
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:8D _To:9S _To:10D _To:8S _Tc:AH', 
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:10D _To:AH _To:9S _To:8D _Tc:8S', 
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:10D _To:AH _To:9S _To:8S _Tc:8D', 
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:10D _To:AH _To:8D _To:8S _Tc:9S', 
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:10D _To:9S _To:8D _To:8S _Tc:AH', 
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:AH _To:8S _To:9S _To:10D _Tc:8D', 
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:AH _To:8S _To:9S _To:8D _Tc:10D', 
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:AH _To:8S _To:10D _To:8D _Tc:9S', 
'_1:AS _1:9H _1:8H _2:AC _2:10H _2:AD _3:10S _3:10C _3:9C _4:8C _4:9D _4:AH _To:9S _To:10D _To:8D _Tc:8S', 
... 
+0

Tanx!這項工作非常好,現在有些優化。 –

+1

@ user3411641:可能我錯過了一些東西,但我無法真正看到哪裏可以優化任何東西......代碼應該在恆定的空間中運行,如果您沒有熱切地評估,並且一旦啓動它就會發出結果。 –

+0

嗯,更多的方式是沒有內存溢出。 –

1

好了,你真正想要的是:

set(tuple(zip(p, players)) for p in it.permutations(cards)) 

但是,這需要太多的時間。所以我們試試吧。

cards = set(["8H", "8S", "8C", "8D", "9H", "9S", "9C", "9D", "10H", "10S", "10C", "10D", "AH", "AS", "AC", "AD"]) 

def deals(cards, players, cards_per_player): 
    if not cards: 
     yield [] 
     return 
    for hand in it.combinations(cards, cards_per_player[0]): 
     hand = set(hand) 
     for deal in deals(cards - hand, players[1:], cards_per_player[1:]): 
      yield zip([players[0]]*len(hand), hand) + deal 

> for deal in deals(cards, ['_1', '_2', '_3', '_4', '_Tc', '_To'], [3,3,3,3,1,3]): 
     print deal 

仍需要很長的時間,但它的很多的方式來處理卡。

+0

這隻會導致一種組合,我需要所有組合。就像abcd的例子。現在看看產品功能。 –

+0

@ user3411641好的,我明白你的意思了。更新。 – U2EF1

0

你可以使用的每人卡的數組,並按順序放置卡片,所以當你匹配兩個數組時,它們將是相同的。 您可以爲每個卡使用一個元組(大小爲2),其中第一個元素可以表示範圍(13)中的值,第二個元素將是顏色(也可以用範圍(4)中的數字表示)。你可以很容易地生成一個雙循環套牌,也許作爲一個字典,在處理完卡片後,你可以刪除那些已經使用過的卡片,這樣就不會有重複,並且當你處理完所有的手牌(如果你有代碼將很容易修改爲具有不同數量的玩家),您可以訂購手,將其與已有的數據庫進行比較,如果匹配時不保存它,也可以保存剩餘的如果你願意的話,可以做一些統計,比你可以在所有情況下都有可能的交易,無論如何,這將是一個巨大的數據庫。這樣你就可以擁有所有的可能性,手中或玩家手中沒有重複。 (玩家之一在不同的交易中有玩家2的手,反之亦然) 我希望這可以幫助你或其他人。 我沒有給出代碼示例,因爲這個問題更像是一個如何解決這個問題,其他人給你編碼技巧。即使你剛開始使用python,並且直到現在只做了一些教程,這種方法也可以完成。 祝你好運;)