Todas las combinaciones posibles de cartas / manos de póker para un conjunto de jugadores.

Estoy buscando una función de python elegante (rápida) que produzca cada combinación de las siguientes dos matrices.

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"] 

Una combinación se vería como:

 [('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')] 

¡Pero! Sin igual, lo que quiero decir con eso. Ejemplo:

Si las tarjetas fueran:

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

Si los jugadores fueran:

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

    Resultado:

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

    No por ejemplo:

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

    El jugador 2 que tiene (c y d) es igual a (d y c)

    He intentado una función de itertools , como combinations y permutations pero sin suerte. Rechazar iguales después de tener todas las combinaciones no es realmente una opción, debido a la explosión del estado del espacio.

    Espero que alguien tenga una solución, porque la búsqueda de Google para este problema específico falló.

    Yo sugeriría usar un algoritmo recursivo.

    Estoy usando generadores para que el código se ejecute en espacio constante, así como para comenzar a producir resultados lo antes posible en lugar de un gran resultado al final; visite http://www.dabeaz.com/generators/ si no ha oído hablar de generadores antes.

    Como nota al margen, sugeriría usar una estructura de datos normalizada para mantener su lista de jugadores y tamaños de manos para comenzar, de modo que la línea con groupby no sea necesaria en absoluto … Y en cualquier caso, generalmente es una buena idea mantener sus datos normalizados de forma predeterminada / la mayoría del tiempo y usar solo formas desnormalizadas / aplanadas, por ejemplo, para ciertos algoritmos que pueden necesitar o correr más rápido con estructuras planas.

    Aquí está el código; no dude en proponer limpiezas / simplificaciones:

     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) 

    Salidas:

     ['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'] 

    o con las personas mayores:

     ['_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', ... 

    Bien, entonces lo que realmente quieres es:

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

    Pero eso lleva demasiado tiempo. Entonces intentemos.

     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 

    Lo que todavía lleva mucho tiempo, pero son muchas maneras de repartir las cartas.

    Podría usar un conjunto de tarjetas por persona y poner las tarjetas en orden, de modo que cuando coincida con los dos arreglos, serán iguales. Podría usar una tupla (tamaño 2) para cada tarjeta, donde el primer elemento podría representar el valor en el rango (13), y el segundo sería el color (también representado con un número en el rango (4)). Puede generar fácilmente el mazo con un bucle doble, tal vez como un diccionario y después de repartir las cartas, puede quitar las que ya usó, por lo que no habrá duplicados, y cuando repartió todas las manos (si tiene) El código será fácil de modificar para tener un número diferente de jugadores. Puedes ordenar las manos, compararlas con la base de datos que ya tienes y no guardarlas si hay una coincidencia, también puedes guardar el rest. De la cubierta, para hacer algunas estadísticas si lo desea, que puede tener todos los tratos posibles para cada situación, que será una gran base de datos independientemente. De esta manera, tendrá todas las posibilidades, sin duplicados en las manos o en manos de los jugadores. (el jugador uno tiene la mano del jugador dos en un trato diferente y viceversa) Espero que esto le haya ayudado a usted, oa alguien más. No estoy dando ejemplos de código, porque esta pregunta es más como una forma de resolver este problema, y ​​los demás te dieron consejos de encoding. También se puede hacer este enfoque incluso si recién inició Python y solo realizó algunos tutoriales hasta ahora. Buena suerte 😉