Representar uma mão de pôquer de 5 cartas


11

Um baralho de cartas é 52. Uma mão é 5 cartas dos 52 (não pode ter uma duplicata).

Qual é a menor quantidade de bits para representar uma mão de 5 cartas e como?
Uma mão NÃO depende da ordem (KQ = QK). 64329 = 96432

Sim, pode usar 52 bits. Isso pode representar uma mão de qualquer número de cartas.

Dada uma mão são exatamente 5 cartas, existe uma maneira de representá-la com menos de 52 bits.

Um único cartão pode ser representado com 6 bits = 64. Então, basta usar 6 bits * 5 cartões = 30 bits. Mas isso seria dependente da ordem. Eu poderia apenas classificar e isso deve funcionar. Se isso não funcionar, por favor me avise.

Existe uma maneira de obter a chave para 32 bits ou menos e não precisar classificar a tupla de 5 placas.

Isso é para simulações de pôquer e a classificação seria muito cara, em comparação com apenas gerar a mão. Se eu tenho um dicionário com o valor relativo de cada mão, são duas pesquisas simples e uma comparação para comparar o valor de duas mãos. Se eu tiver que classificar as mãos primeiro, é grande em comparação com duas pesquisas e uma comparação. Em uma simulação irá comparar milhões. Não receberei as mãos classificadas da simulação. A classificação não é simples como 52 51 50 49 48 antes de 52 51 50 49 47. Você pode ter quads de straight flush ....

Existem 2598960 possíveis 5 mãos para cartas. Esse é o número de linhas. A chave são os 5 cartões. Eu gostaria de obter uma chave de 32 bits ou abaixo de onde os cartões não precisam ser classificados primeiro.

Não é possível apenas solicitar a lista, pois há muitas mãos amarradas. Naipe são pá, taco, diamante e coração. 7c 8c 2d 3d 4s = 7s 8s 2c 3c 4h. Há um grande número de laços.

O próximo passo é de 64 bits e receberá o resultado da classificação em vez de dobrar o tamanho da chave.

Eu testei e SortedSet<int> quickSort = new SortedSet<int>() { i, j, k, m, n };dobra o tempo da operação, mas ainda posso fazê-lo.

Fica mais complexo. Eu preciso ser capaz de representar um barco de dois em cinco (22255). Então, classificá-los quebra isso. Eu sei que você vai dizer, mas isso é rápido. Sim, é rápido e trivial, mas eu preciso o mais rápido possível.

C # para a resposta aceita:

private int[] DeckXOR = new int[] {0x00000001,0x00000002,0x00000004,0x00000008,0x00000010,0x00000020,0x00000040,
                                    0x00000080,0x00000100,0x00000200,0x00000400,0x00000800,0x00001000,0x00002000,
                                    0x00004000,0x00008000,0x00010000,0x00020000,0x00040000,0x00080000,0x00100000,
                                    0x00200000,0x00400000,0x00800000,0x01000000,0x02000000,0x04000000,0x07fe0000,
                                    0x07c1f000,0x0639cc00,0x01b5aa00,0x056b5600,0x04ed6900,0x039ad500,0x0717c280,
                                    0x049b9240,0x00dd0cc0,0x06c823c0,0x07a3ef20,0x002a72e0,0x01191f10,0x02c55870,
                                    0x007bbe88,0x05f1b668,0x07a23418,0x0569d998,0x032ade38,0x03cde534,0x060c076a,
                                    0x04878b06,0x069b3c05,0x054089a3};
public void PokerProB()
{
    Stopwatch sw = new Stopwatch();
    sw.Start();
    HashSet<int> cardsXOR = new HashSet<int>();
    int cardXOR;
    int counter = 0;
    for (int i = 51; i >= 4; i--)
    {
        for (int j = i - 1; j >= 3; j--)
        {
            for (int k = j - 1; k >= 2; k--)
            {
                for (int m = k - 1; m >= 1; m--)
                {
                    for (int n = m - 1; n >= 0; n--)
                    {
                        counter++;
                        cardXOR = DeckXOR[i] ^ DeckXOR[j] ^ DeckXOR[k] ^ DeckXOR[m] ^ DeckXOR[n];
                        if (!cardsXOR.Add(cardXOR))
                            Debug.WriteLine("problem");
                    }
                }
            }
        }
    }
    sw.Stop();
    Debug.WriteLine("Count {0} millisec {1} ", counter.ToString("N0"), sw.ElapsedMilliseconds.ToString("N0"));
    Debug.WriteLine("");
}

4
Use um algoritmo de classificação codificado manualmente que funcione para classificar listas de comprimento 5. Isso provavelmente é mais rápido que a função de biblioteca que você está usando no momento.
Yuval Filmus

1
Não entendo por que você diz "O tipo não é simples" . A classificação é simples - converta cada cartão em um número de 1 a 52, para que a mão seja representada por uma lista (de comprimento 5) de cartões. Classifique essa lista. Esse é apenas o problema de classificar uma lista de 5 números inteiros, o que pode ser feito muito rapidamente, como Yuval menciona. Sugiro que você meça antes de assumir que é muito lento, mas meu palpite é que a classificação dessa lista será muito rápida e pode até ser mais rápida do que uma leitura de memória de acesso aleatório que não atinja o cache.
DW

@dw Sim, o tipo é simples, mas o que estou fazendo (milhões de vezes) é simples. Eu testei e uma espécie dobra o tempo.
Paparazzo

1
@Paparazzi Não, Yuval está dizendo para você escrever sua própria rotina de classificação, especificamente ajustada para classificar cinco números entre 1 e 52. Você tentou usar uma rotina de biblioteca, que é lenta porque é muito mais geral do que isso e porque a natureza recursiva O quicksort o torna muito ineficiente em listas curtas.
David Richerby

Na prática, a maioria dos itens que não são <= 16 bits também pode ter 32 bits. Portanto, como você precisa de pelo menos 23 bits, qualquer codificação que use <= 32 bits é provavelmente viável. A codificação trivial de 6 bits por cartão * 5 funciona bem o suficiente. Há uma ressalva: um índice de matriz de 23 bits é muito melhor que um índice de matriz de 32 bits.
MSalters

Respostas:


10

C[52,25,11]C27×521152A1,,A52Ai271100a,b,c,d,eAaAbAcAdAeH1,H2102|H1H2|10

Bob Jenkins descreve esse código em seu site e, a partir disso, podemos extrair a matriz

0x00000001,0x00000002,0x00000004,0x00000008,0x00000010,0x00000020,0x00000040,
0x00000080,0x00000100,0x00000200,0x00000400,0x00000800,0x00001000,0x00002000,
0x00004000,0x00008000,0x00010000,0x00020000,0x00040000,0x00080000,0x00100000,
0x00200000,0x00400000,0x00800000,0x01000000,0x02000000,0x04000000,0x07fe0000,
0x07c1f000,0x0639cc00,0x01b5aa00,0x056b5600,0x04ed6900,0x039ad500,0x0717c280,
0x049b9240,0x00dd0cc0,0x06c823c0,0x07a3ef20,0x002a72e0,0x01191f10,0x02c55870,
0x007bbe88,0x05f1b668,0x07a23418,0x0569d998,0x032ade38,0x03cde534,0x060c076a,
0x04878b06,0x069b3c05,0x054089a3

252271=2251


Eu não sigo exatamente. Quantos bits isso precisa para uma mão?
Paparazzo

Precisa de 27 bits. Você pode usar qualquer número maior de bits.
Yuval Filmus 06/04

Obrigado. Eu testei e os números são únicos e <= 32 bits. Posso derivar os 5 cartões do número? Se não estiver bem, basta perguntar.
Paparazzo

Sim, é simples álgebra linear. Você pode usar a matriz correta para recuperar um vetor de comprimento 52 com 5. Eu vou deixar você descobrir isso.
Yuval Filmus

13

nlgnlg2598960=22

Como funciona a representação? Existem várias opções, com diferentes trocas. Listo dois abaixo.

Dicionário codificado

Nesse caso, o número possível de mãos com 5 cartas é pequeno o suficiente para que você possa ter um dicionário codificado que lista todas as 2598960 mãos e você representa uma mão por seu índice no dicionário (representado em binário).

Em outras palavras, o dicionário pode ser uma lista ordenada de mãos. Cada mão é a 5-tupla das cartas na mão, em ordem ordenada. Você pode procurar uma mão no dicionário usando a pesquisa binária e encontrar seu índice correspondente; e com um índice, você pode encontrar a mão correspondente. Ou você pode armazenar o dicionário como um mapa de hash que mapeia da mão para seu índice. O índice é um número inteiro entre 0 e 2598959, portanto, pode ser representado usando 23 bits.

Essa abordagem funcionará e será muito simples de programar, mas é um desperdício de espaço (tamanho do programa executável).

Classificação / desagregação

Como alternativa, se você se importa, existem métodos melhores. Veja, por exemplo, qualquer uma das seguintes referências:

O tópico geral é conhecido como "classificação (e sem classificação) de combinações". Eles são um pouco mais complexos de implementar e entender, mas evitam a necessidade de incluir um dicionário codificado no programa.


Vou atualizar a pergunta. Sim, existem 2598960 mãos. O dicionário terá muitas linhas. Meu problema é a geração da chave. Em 5 cartões, preciso gerar uma chave para realizar a pesquisa no dicionário.
Paparazzo

@Paparazzi, se você usar a abordagem de dicionário, a mão é a chave. Em outras palavras, a chave é a 5-tupla das cartas na mão (em ordem classificada). O dicionário pode ser armazenado como uma hashtable usando-o como chave. Se você não gosta dos custos de memória de um dicionário, use a abordagem alternativa: classificação / não classificação.
DW

Sim, eu sei que posso obter a chave de 30 bits se eu classificar. Gostaria de saber se existe uma maneira de obter a chave de 32 bits ou menos sem classificar a tupla de 5 placas. Vou olhar para classificação e classificação.
Paparazzo

Eu não sigo a classificação / classificação, mas obrigado. Vou tentar descobrir. Também tem as possibilidades de laços. Há muitos laços.
Paparazzo


3

Você pode classificar os cinco itens e verificar se há duplicatas simultaneamente, sem nenhuma comparação em alguns processadores: Suponha que um processador tenha uma instrução rápida que determina a posição do conjunto de bits mais alto e uma instrução rápida calculando um número apenas com o conjunto de n-ésimos bits .

Seja bit (n) o número exatamente com o n-ésimo bit definido. Seja o mais alto bit (x) o número do bit mais alto definido no número x, com um valor não especificado se x = 0. Seja x ^ y o exclusivo ou de x e y.

Dado são cinco números a, b, c, d e e, cada um de 0 a 51, representando as cinco cartas na mão.

Seja x = bit (a) ^ bit (b) ^ bit (c) ^ bit (d) ^ bit (e).

Seja A = maior_bit (x), altere x para x ^ bit (A).

Seja B = maior_bit (x), altere x para x ^ bit (B).

Seja C = maior_bit (x), altere x para x ^ bit (C).

Seja D = maior_bit (x), altere x para x ^ bit (D).

Seja E = maior_bit (x).

Se x = 0, havia duplicatas nos números a, b, c, d e e. Caso contrário, use A * bit (24) + B * bit (18) + C * bit (12) + D * bit (6) + E como a codificação da mão, onde A, B, C, D e E são definido como acima. Isso codifica uma mão como uma string de 30 bits, enquanto faz a classificação de uma maneira muito eficiente.


Isso usa 52 bits?
Paparazzo

@Paparazzi, não. Dê uma outra olhada no último parágrafo. Eu o editei para tentar fornecer uma clareza ainda maior.
DW

1
Requer uma CPU de 64 bits, mas o resultado final é de apenas 30 bits.
Yuval Filmus
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.