Rappresenta una mano di poker con 5 carte


11

Un mazzo di carte è 52. Una mano è di 5 carte dal 52 (non può avere un duplicato).

Qual è la quantità minima di bit per rappresentare una mano di 5 carte e come?
Una mano NON dipende dall'ordine (KQ = QK). 64329 = 96432

Sì, può usare 52 bit. Ciò può rappresentare una mano di qualsiasi numero di carte.

Dato che una mano è esattamente 5 carte c'è un modo per rappresentarla con meno di 52 bit.

Una singola carta può essere rappresentata con 6 bit = 64. Quindi potrebbe usare solo 6 bit * 5 carte = 30 bit. Ma ciò dipende dall'ordine. Potrei solo ordinare e questo dovrebbe funzionare. Se ciò non funzionasse, per favore fatemi sapere.

C'è un modo per ottenere la chiave a 32 bit o meno e non è necessario ordinare la tupla a 5 carte.

Questo è per le simulazioni di poker e l'ordinamento sarebbe un sacco di spese generali rispetto al solo generare la mano. Se ho un dizionario con il valore relativo di ogni mano, sono due semplici ricerche e un confronto per confrontare il valore di due mani. Se devo prima ordinare le mani è grande rispetto a due ricerche e un confronto. In una simulazione verranno confrontati milioni. Non avrò le mani separate dalla simulazione. L'ordinamento non è semplice come 52 51 50 49 48 prima di 52 51 50 49 47. Puoi avere quadri a livello diritto ....

Ci sono 2598960 possibili 5 mani di carte. Questo è il numero di righe. La chiave è le 5 carte. Vorrei ottenere una chiave di 32 bit o inferiore in cui le carte non devono essere ordinate per prime.

Non posso semplicemente ordinare l'elenco come più mani legate. Il seme è picche, mazza, diamante e cuore. 7c 8c 2d 3d 4s = 7s 8s 2c 3c 4h. C'è un gran numero di legami.

Il passo successivo è 64 bit e prenderà il colpo dell'ordinamento anziché raddoppiare la dimensione della chiave.

Ho testato e SortedSet<int> quickSort = new SortedSet<int>() { i, j, k, m, n };raddoppiato il tempo dell'operazione, ma posso ancora farlo.

Diventa più complesso. Devo essere in grado di rappresentare una barca come due su cinque (22255). Quindi ordinarli li rompe. So che lo dirai, ma è veloce. Sì, è veloce e banale, ma ho bisogno il più velocemente possibile.

C # per la risposta accettata:

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
Usa un algoritmo di ordinamento codificato a mano che funziona per ordinare elenchi di lunghezza 5. Questo è probabilmente più veloce della funzione di libreria che stai attualmente utilizzando.
Yuval Filmus,

1
Non capisco perché dici "Il tipo non è semplice" . L'ordinamento è semplice: converti ogni carta in un numero compreso tra 1 e 52, in modo che la mano sia rappresentata da un elenco (di lunghezza 5) di carte. Ordina quell'elenco. Questo è solo il problema di ordinare un elenco di 5 numeri interi, che può essere fatto molto velocemente, come menziona Yuval. Ti suggerisco di misurare prima di assumere che sia troppo lento, ma la mia ipotesi è che l'ordinamento di un tale elenco sarà molto veloce e potrebbe anche essere più veloce di una lettura di memoria ad accesso casuale che non colpisce la cache.
DW

@dw Sì, l'ordinamento è semplice ma quello che sto facendo (milioni di volte) è semplice. Ho provato e una specie raddoppia il tempo.
paparazzo,

1
@Paparazzi No, Yuval ti sta dicendo di scrivere la tua routine di smistamento che è specificamente sintonizzata sull'ordinamento di cinque numeri tra 1 e 52. Hai provato a usare una routine di libreria, che è lenta perché è molto più generale di questa e perché la natura ricorsiva di quicksort lo rende molto inefficiente nelle liste brevi.
David Richerby,

In pratica, la maggior parte degli elementi che non sono <= 16 bit potrebbe anche essere 32 bit. Pertanto, poiché sono necessari almeno 23 bit, qualsiasi codifica che utilizza <= 32 bit è probabilmente praticabile. La semplice codifica a 6 bit per scheda * 5 funziona abbastanza bene. C'è un avvertimento: un indice di array a 23 bit è molto meglio di un indice di array a 32 bit.
MSalters

Risposte:


10

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

Bob Jenkins descrive un tale codice nel suo sito e da questo possiamo estrarre l'array

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


Non seguo esattamente. Di quanti bit ha bisogno per una mano?
paparazzo,

Ha bisogno di 27 bit. È possibile utilizzare un numero maggiore di bit.
Yuval Filmus,

Grazie. Ho provato e i numeri sono unici e <= 32 bit. Posso derivare le 5 carte dal numero? Se non va bene, basta chiedere.
paparazzo,

Sì, è semplice algebra lineare. È possibile utilizzare la matrice corretta per ottenere un vettore di lunghezza 52 con 5 unità. Ti lascio capire.
Yuval Filmus,

13

nlgnlg2598960=22

Come funziona la rappresentazione? Esistono varie opzioni, con diversi compromessi. Ne elenco due di seguito.

Dizionario hardcoded

In questo caso, il numero di possibili mani da 5 carte è abbastanza piccolo da poter avere solo un dizionario hardcoded che elenca tutte le mani 2598960 e tu rappresenti una mano dal suo indice nel dizionario (rappresentato in binario).

In altre parole, il dizionario può essere un elenco ordinato di mani. Ogni mano è la 5 tupla delle carte nella mano, in ordine ordinato. Puoi cercare una mano nel dizionario usando la ricerca binaria e trovare il suo indice corrispondente; e dato un indice, puoi trovare la mano corrispondente. In alternativa, è possibile memorizzare il dizionario come hashmap che mappa dalla mano al suo indice. L'indice è un numero intero compreso tra 0 e 2598959, quindi può essere rappresentato utilizzando 23 bit.

Questo approccio funzionerà e sarà molto semplice da programmare, ma è dispendioso nello spazio (dimensione del programma eseguibile).

Classifica / unranking

In alternativa, se ti interessa, ci sono metodi migliori. Vedi, ad esempio, uno dei seguenti riferimenti:

L'argomento generale è noto come "classificazione (e non classificazione) delle combinazioni". Questi sono un po 'più complessi da implementare e comprendere, ma evitano la necessità di includere un dizionario hardcoded nel programma.


Aggiornerò la domanda. Sì, ci sono 2598960 mani. Il dizionario avrà tante righe. Il mio problema è la generazione della chiave. Da 5 carte ho bisogno di generare una chiave per eseguire la ricerca nel dizionario.
paparazzo,

@Paparazzi, se usi l'approccio del dizionario, la mano è la chiave. In altre parole, la chiave è la 5 tupla delle carte nella mano (in ordine ordinato). Il dizionario può essere memorizzato come hashtable usando quello come chiave. Se non ti piacciono i costi di memoria di un dizionario, usa l'approccio alternativo: classifica / non classificare.
DW

Sì, so che posso ordinare la chiave di 30 bit se ordino. Mi chiedo se c'è un modo per ottenere la chiave a 32 bit o meno senza ordinare la tupla a 5 carte. Esaminerò il grado e il ranking.
paparazzo,

Non seguo la classifica / non classifica ma grazie. Proverò a capirlo. Hanno anche la possibilità di legami. Ci sono molti legami.
paparazzo,


3

È possibile ordinare i cinque elementi e verificare contemporaneamente la presenza di duplicati senza alcun confronto su alcuni processori: si supponga che un processore abbia un'istruzione rapida che determina la posizione del set di bit più alto e un'istruzione veloce che calcola un numero con solo l'n-esimo bit impostato .

Sia bit (n) il numero con esattamente l'n-esimo bit impostato. Sia most_bit (x) il numero del bit più alto impostato nel numero x, con un valore non specificato se x = 0. Sia x ^ y l'esclusivo o di xe y.

Dato sono cinque numeri a, b, c, d ed e, ciascuno da 0 a 51, che rappresentano le cinque carte nella mano.

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

Lascia A = bit_più alto (x), cambia x in x ^ bit (A).

Sia B =bit_più alto (x), cambia x in x ^ bit (B).

Lascia C = bit_più alto (x), cambia x in x ^ bit (C).

Lascia che D =bit_più alto (x), cambia x in x ^ bit (D).

Sia E = maximum_bit (x).

Se x = 0 allora c'erano duplicati nei numeri a, b, c, d ed e. Altrimenti, usa A * bit (24) + B * bit (18) + C * bit (12) + D * bit (6) + E come codifica della mano, dove A, B, C, D ed E sono definito come sopra. Questo codifica una mano come una stringa di 30 bit, mentre esegue l'ordinamento in modo molto efficiente.


Questo utilizza 52 bit?
paparazzo,

@Paparazzi, no. Dai un'occhiata all'ultimo paragrafo. L'ho modificato per cercare di fornire una chiarezza ancora maggiore.
DW

1
Richiede una CPU a 64 bit, ma il risultato finale è di soli 30 bit.
Yuval Filmus,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.