Determinare le mani di poker


19

Ho fatto un gioco Texas Hold'Em come parte di una valutazione e ho riflettuto su come esaminare le 7 carte disponibili e determinare se esistono le mani.

L'unico metodo possibile a cui riesco a pensare è quello di ordinare le carte numericamente, quindi esaminare ogni possibile gruppo di 5 carte e verificare se corrispondono a un elenco di ogni singola mano possibile. Ciò richiederebbe molto tempo e sarebbe possibile solo per determinare le coppie, poiché il seme è irrilevante.

Le carte sono ciascuna stringhe, composte da un numero / a / j / q / k e un seme (char)3(che rende un piccolo simbolo di picche).

Qualcuno ha suggerimenti, formule o collegamenti che potrei usare per aiutare a creare un sistema di analisi manuale?

Non preoccuparti ancora di mettere le mani l'una contro l'altra, questo è un diverso bollitore di pesce.


1
Basta evidenziarlo, ma il tag vettoriale nel suo contesto riguarda l'algebra lineare. Non il contenitore.
Sidar,

@Sidar Sentiti libero di modificare i tag in futuro se ritieni che non vadano bene. Se passi con il mouse sopra i tag e viene visualizzata l'opzione "Modifica tag" (almeno per me?), E puoi modificare solo i tag senza modificare la domanda.
MichaelHouse

@ Byte56 Ho questa strana abitudine di pensare che non sono sicuro di aver ragione, quindi lo faccio passivamente attraverso un commento ... Ecco perché non ho modificato il post. Forse ho perso qualcosa nel post, quindi stavo aspettando la sua risposta.
Sidar,

C'è anche un bell'articolo qui apparso su Game Developer alcuni anni fa: cowboyprogramming.com/2007/01/04/programming-poker-ai
celion

1
Ho fatto un'implementazione in Java per divertimento qualche tempo fa, puoi trovarla qui: codereview.stackexchange.com/questions/10973/… . Se guardi su PokerHand.java troverai metodi per testare ogni tipo di mano (es. IsFullHouse). Funzionano solo se le carte vengono ordinate per prime.
bughi,

Risposte:


20

Penso che puoi trovare la maggior parte delle mani di poker semplicemente facendo un paio di tavoli su quante carte nella mano ci sono di ogni valore e seme.

In altre parole, crea un rango di carte mappatura array (numeri e A / J / Q / K) al conteggio delle carte di quel rango nella tua mano. Se il giocatore ha una coppia o tre di un tipo, ci sarà un elemento in questo array uguale a 2 o 3, ecc. Hanno un full se c'è un elemento che è 2 e un altro che è 3, e una scala se ci sono cinque elementi consecutivi pari a 1 in questo array.

Allo stesso modo puoi creare un array simile del conteggio delle carte di ogni seme e usarlo per rilevare i flush.

Una volta rilevata la presenza di una mano specifica, è abbastanza facile tornare indietro e trovare le carte specifiche nella mano, per evidenziarle nell'interfaccia utente o qualsiasi altra cosa tu debba fare.

In pseudocodice:

int countByRank[13] = { 0 };        // Initialize counter to zero for each rank
for (cards in hand)
    countByRank[card.rank] += 1;    // Increment counter for this card's rank
if (countByRank.find(2))
    // There's a pair
else if (countByRank.find(3))
    // There's a three-of-a-kind
// etc...

17

È un po 'complicato perché ci sono così tante combinazioni. Fortunatamente hai un processore che può controllare un gran numero di combinazioni in pochissimo tempo.

Avrai bisogno di alcune strategie diverse, per rilevare diversi tipi di mani. Fortunatamente, alcuni dei diversi tipi possono sovrapporsi alle strategie. Vorrei cercare, in ordine di rango della mano.

  1. Scala reale
  2. Quattro nel suo genere
  3. Tutto esaurito
  4. Sciacquone
  5. Dritto
  6. Tre di un tipo
  7. Due coppie
  8. Un paio
  9. Carta alta

2, 3, 6, 7, 8Sono tutti conteggio semplice. Usando un elenco di carte dall'asso al re, posiziona semplicemente il numero di ciascun valore nell'elenco, aumentando per ogni carta aggiuntiva trovata. Quindi controlla l'elenco per 4s, se non ci sono 4s, non hai un 4 nel suo genere. Controllalo per 3 secondi, se non ci sono 3 secondi, non hai un 3 di un tipo. Se hai un 3, controlla un 2 (che indica il full). E così via...

Per 1, 5puoi usare lo stesso elenco e cercare sequenze in cui tutte le carte hanno una o più voci nell'elenco per una sequenza di 5 carte. Se hanno anche lo stesso seme, è una scala reale.

4può avere la stessa configurazione dell'elenco ma questa volta stai contando il seme. Cerca numeri di 5 o superiori.

Infine, 9hai la carta più alta, che dovrebbe essere una semplice questione di guardare l'ultimo valore più alto da uno dei tuoi elenchi sopra.

Puoi uscire dopo aver trovato una corrispondenza se cerchi in ordine. Sebbene sarebbe banale continuare la ricerca e trovare tutte le corrispondenze se si desidera fornire tutte queste informazioni all'utente.


In sostanza, stai riempiendo secchi. Quindi controllando i secchi per le combinazioni. Illustrare:

inserisci qui la descrizione dell'immagine

A partire da un array, con un secchio per ogni carta, scorrere le carte e contare l'istanza di ogni carta. Quindi è possibile iterare facilmente l'array e verificare determinate combinazioni. In questo esempio, è chiaro che c'è un 4 nel suo genere perché uno dei secchi contiene 4 elementi.


6

Ho incontrato questo algoritmo una volta. Moltiplica i numeri primi per determinare le mani ed è una lettura molto interessante. Valutatore di mani di poker di Cactus Kev


1
Quello è interessante, ma non sono sicuro che tu abbia letto tutto. Tale algoritmo è per 5 carte . Potresti esserti trovato in una ricerca di Google relativa a 7 carte, poiché l'autore afferma di avere un algoritmo per 7 carte, ma non lo sta condividendo. Vedi il testo grigio nella parte superiore della pagina. Quindi non sono sicuro di quanto sia utile quell'algoritmo per un set di 7 carte.
MichaelHouse

1
Dal momento che ci sono solo 21 mani di 5 carte diverse che possono essere fatte da una mano di 7 carte, un'opzione è quella di utilizzare un valutatore di 5 carte su ciascuna e scegliere il migliore.
Adam,

@ Byte56 Hai ragione, ricordo che l'ho usato per 7 carte ma ho dovuto determinare in anticipo le migliori 5 carte, che in qualche modo ne hanno compromesso l'efficienza.
Petervaz,

Il link su questa risposta è marcito e il dominio è stato raccolto da uno spammer. Ho reindirizzato il collegamento a un archivio della pagina originale, ma per rendere questa risposta più solida sarebbe l'ideale modificare la risposta per includere un riepilogo dell'algoritmo proposto all'interno del corpo della risposta stessa.
DMGregory

2

Per integrare le eccellenti risposte che questa domanda ha già ottenuto, ho pensato che sarebbe stato utile offrire uno dei modi più semplici per confrontare le mani una volta che la tecnica di classificazione di base è stata messa in atto. Prima di tutto, ti consigliamo di taggare le mani con la loro classe , come suggerito da numerose risposte - la maggior parte dei tuoi confronti di "la mano X è migliore della mano Y?" può quindi essere fatto semplicemente confrontando le classi delle due mani e vedendo quale classe è migliore. Per il resto, dovrai effettivamente confrontare carta per carta, e si scopre che un po 'più di lavoro nella classificazione renderà questo più facile.

Come caso di base, considera la situazione in cui entrambe le mani sono mani "carta alta"; in questo caso, confronteresti prima le due carte più alte, quindi (se corrispondessero) le due carte successive, ecc. Se supponi che ogni mano di input sia ordinata dalla carta più alta a quella più bassa, questo approccio porta a un codice simile a Questo:

int CompareHandsOfSameClass(Hand h1, Hand h2) {
  for ( int i = 0; i < 5; i++ ) {
    if ( h1[i].rank > h2[i].rank ) {
      return -1;
    } else if ( h1[i].rank < h2[i].rank ) {
      return 1;
    }
  }
  return 0;
}

Ora, la buona notizia: si scopre che questo ordinamento lessicografico , opportunamente ottimizzato, funziona per confrontare due mani in qualsiasidelle classi, purché la loro classe sia la stessa. Ad esempio, poiché il modo di confrontare le coppie è di confrontare prima le coppie, quindi le altre tre carte, puoi ordinare la tua mano per mettere la coppia prima (o anche una sola carta della coppia prima!) Ed eseguire questo stesso confronto. (Ad esempio, una mano come A9772 verrebbe memorizzata come 77A92 o, meglio ancora, 7A927; la mano A9972 verrebbe memorizzata come 9A729, e confrontando con il codice sopra inizieresti mettendo 7 contro 9 e scoprendo che A9972 ha vinto). Una mano di due coppie verrebbe memorizzata prima con la più alta delle due coppie, poi con la parte inferiore, quindi con il "kicker" (quindi, ad esempio, A9977 memorizzerebbe come 97A97); il tris sarebbe memorizzato con una carta delle tre prima, poi i kicker, quindi le altre carte (es. A7772 sarebbe 7A277); un full house verrebbe memorizzato con uno dei suoi tre e poi uno dei suoi due (ad esempio, 99777 verrebbe memorizzato come 79779); e rettilinei e scale possono essere entrambi conservati in ordine 'lessicografico diretto' poiché entrambi sono confrontati proprio come le mani con carte alte. Ciò porta a una semplice funzione di comparatore esterno che funziona per tutte le classi di mani con la funzione già assegnata:

// Compare two hands, returning -1/0/+1 as hand 1 is less than, equal to,
// or greater than hand 2. Note that this function assumes the hands have
// already been classified and sorted!
int CompareHands(Hand h1, Hand h2) {
  if ( h1.handClass > h2.handClass ) {
    return -1;
  } else if ( h1.handClass < h2.handClass ) {
    return 1;
  } else {
    return CompareHandsOfSameClass(h1, h2);
  }
}

Spero che questo possa essere di aiuto!


1

Ci sono alcune parallelizzazioni possibili usando rappresentazioni di carte adatte e bit-twiddling. Ad esempio, questo codice Java valuta hard disk a 7 carte restituendo un numero intero che può essere utilizzato per confrontare due mani. Potrebbe essere adattato per segnalare il tipo di mano in un modo più user-friendly. Le idee principali provengono dalla pagina di Cactus Kev a cui si fa riferimento in una risposta precedente.

Se ti interessano solo le possibili implementazioni per nominare la mano in varie lingue piuttosto che l'efficienza e la chiarezza del codice, puoi anche dare un'occhiata alla sfida Name the poker hand su codegolf.SE.


1

Innanzitutto, devi conoscere il rango e il seme di tutte le carte; banale ma necessario.

Quindi, ruota attraverso queste 7 carte e crea due istogrammi; uno per rango (usando un array con 13 indici, tutti inizializzati a zero e incrementati di 1 se e quando viene trovata una carta nella mano con quel rango) e uno per seme (usando un array di quattro elementi costruiti allo stesso modo del rango) . Queste sono operazioni lineari e puoi fare entrambe le operazioni per ogni carta per un solo set di attraversamenti.

È quindi possibile determinare se esiste una delle seguenti mani semplicemente esaminando ciascun istogramma per i bucket che soddisfano i criteri e / o un semplice test di follow-up:

  • Coppia: esattamente un bucket di rango ha un valore esattamente di 2, senza altri bucket con un valore superiore a 1 e senza flush?
  • Doppia coppia: due o più bucket di rango hanno un valore esattamente di 2, senza bucket con più di 2 e senza flush? (ovviamente la tripla non è una mano, ma è una possibilità data sette carte; la doppia coppia più forte è la mano del giocatore)
  • TOAK: Esattamente un bucket ha un valore esattamente di 3, senza altri bucket con un valore maggiore di 1 e senza flush?
  • Dritto: cinque secchi di rango consecutivi hanno un valore di 1 o più senza colore? (Non dimenticare che gli assi sono sia alti che bassi; puoi usare un istogramma di rango di 14 elementi e contare gli assi in due secchi se vuoi)
  • Colore: un secchio seme ha 5 o più carte? (in tal caso, scansiona la mano alla ricerca di carte di quel seme e scegli le prime 5)
  • Full House: un bucket di un rango ha un valore di 3 e qualsiasi altro bucket ha un valore di 2 (con 7 carte, un colore è impossibile con un full a meno che tu non stia giocando con un mazzo Pinochle)
  • Four of a Kind: Qualcuno ha un valore di 4? (nessun'altra combinazione dovrebbe essere possibile)
  • Scala reale: esiste sia una scala che una scala indicate dagli istogrammi? In tal caso, esiste almeno una carta nel seme di colore indicato con un valore corrispondente a ogni valore della scala indicata? (questo è probabilmente il più computazionalmente costoso, ma dovrebbe essere semplice contare quanti ranghi consecutivi ci sono, e dovresti scansionare la mano solo una volta per 5 gradi consecutivi, due volte per 6 e tre volte per 7)

Puoi, naturalmente, combinare molti di questi controlli:

  • C'è un filo?
  • C'è una scala?
    • Se ci sono entrambi, è una scala reale?
    • Se è una scala reale, ha sia un asso che un re?
  • C'è un quattro nel suo genere?
  • Quanti tris ci sono? (Due, è un full. Uno, controlla le coppie)
  • Quante coppie ci sono? (Con due o più, sono due coppie. Con uno, se c'è anche un tre è un full, altrimenti è una coppia)
  • Nessuna delle precedenti (carta alta).

Fondamentalmente, se le risposte a queste danno una mano, imposta il valore "forza mano" risultante sulla forza della mano trovata, se il valore non è già più alto. Ad esempio, se hai un full, forza 7 di 9, allora hai anche un tris, forza 4 e una coppia, forza 2.

Ci sono alcune scorciatoie e fast-out, ma nel complesso non è poi così costoso eseguire tutti i controlli.


0

Puoi fare relativamente facilmente le mani di poker con un semplice approccio iterativo.

Per ogni carta, controlla se ce ne sono una o due o tre con la stessa faccia per controllare la coppia o tre / quattro di un tipo.

Le case complete sono simili. O se trovi sia una coppia che una tris che non hanno la stessa faccia, contrassegna un full come trovato.

Per i colori, controlla ogni seme per vedere se ce ne sono cinque dello stesso seme.

Controllare direttamente è facile, anche se non ordinato. Per ogni carta, controlla se ce n'è una più alta e ripeti fino a quando non vengono trovate o meno cinque carte consecutive.

Le vampate reali e quelle diritte possono essere trovate in modo simile ai rettilinei. Le vampate reali hanno alcune condizioni extra in quanto carte di valore inferiore possono essere ignorate.

Sì, questo approccio è inefficiente, ma per la maggior parte dei giochi di poker è irrilevante. Stai controllando una manciata di giocatori ogni mezzo minuto circa, non controllando migliaia di mani al secondo.

Esistono metodi migliori, ma potrebbe richiedere più tempo per la codifica, e probabilmente avrai cose più importanti su cui spendere tempo / denaro che renderanno il gioco migliore dal punto di vista dei giocatori, oltre all'abilità e all'efficienza di un algoritmo.


0

un modo semplice per trovare coppie, doppie coppie, toak, full, poker ecc è il seguente:

confrontare ciascuna carta tra loro in un ciclo annidato come questo:

int matches=0;
for (int i=0;i<5;i++)
   for (int j=0;j<5;j++)
      if (i!=j && cardvalue(card[j])==cardvalue(card[i])) matches++;

le partite terranno quanto segue:
2 per una coppia
4 per due coppie
6 per prendere
8 per una fullhouse
12 per un poker

per ottimizzare questo: non è necessario eseguire j-loop fino a 5, può essere eseguito su i-1. il confronto "i! = j" può quindi essere rimosso, i valori per la corrispondenza vengono quindi dimezzati (1 = coppia, 2 = 2 coppia ecc.)

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.