Come i lettori piu’ attenti sapranno, e’ da tempo che mi frulla per la testa l’idea di scrivere un software in grado di giocare un “buon” (aggettivo arduo da definire in un paper, figuriamoci in un blog…) poker. Ho tante idee che mi frullano per la testa e relative al come implementare i suoi vari elementi costitutivi. Tra l’altro proprio oggi ho trovato per caso un articoletto a riguardo che, per quanto non dica in assoluto niente di nuovo, risulta una lettura piacevole. Il mio problema, come sempre, e’ il tempo. Qualche mese fa avevo iniziato ad abbozzare un po’ di codice (pseudo e anche reale), ma poi non ho avuto modo di proseguire il discorso. Cosi’, come suggerisce il titolo di questo post, ora ho deciso di cercare un po’ di aiuto dagli studenti che seguono il mio (in realta’ non e’ “mio”, ma siccome preparo il materiale didattico, tengo le lezioni, preparo i testi degli esami e valuto gli studenti, credo di poter legittimamente usurpare il possessivo) corso di Laboratorio II ad UniMORE. Si’, in realta’ potrebbe configurarsi il reato di sfruttamento. O, meglio, abuso di posizione dominante. Fatto sta che per il primo appello di questo anno accademico (25 giugno 2009) ho deciso di preparare un testo d’esame tutto dedicato al poker. Scrivere il tutto mi e’ costato un pomeriggio abbondante di lavoro (ovviamente mi imbarco in queste cose quando e’ festa e io dovrei essere fuori casa a fare altro). Ma credo ne sia valsa la pena. Vedremo la risposta degli studenti. Sperando innanzitutto che risposta vi sia e che non decidano tutti (gia’ che sono pochini) di saltare pari pari questo appello.

Per coloro che fossero interessati propongo il testo dell’appello qui di seguito. La parte piu’ corposa, come potrete notare e’ quella relativa alla spiegazione delle regole del gioco (per facilita’ mi sono orientato sul Fixed-Limit Hold’Em giocato in HU). Che penso tuttavia sia venuta bene. A voi il giudizio.
Specifiche del progetto da realizzare
Come tema d’esame, si richiede allo studente di scrivere un programma, in linguaggio C, che permetta all’utente di disputare una partita di poker contro il computer.
La variante del poker adottata a questo fine e’ il Fixed-Limit Texas Hold’Em in modalita’ torneo. Il gioco si svolgera’ in Heads Up, ovvero con soltanto due giocatori attivi: l’utente e il computer. Internet abbonda di materiale riguardante le regole del gioco (vedi ad esempio http://it.wikipedia.org/wiki/Texas_Hold’em). Un breve riepilogo e’ comunque fornito in questo documento.
L’avvio del programma coincide con l’inizio di una nuova partita. Attraverso un menu a scelta rapida, visualizzato preferibilmente in forma semi-grafica (intesa semplicemente come utilizzo dei caratteri ‘-‘, ‘|’ e simili), l’utente dovra’ effettuare durante ogni mano di gioco la scelta tra una delle seguenti opzioni:
- Fold
- Check
- Call x (dove x sta per l’ammontare che deve essere chiamato)
- Bet (nel caso in cui il giocatore sia il primo a parlare al flop, al turn o al river, oppure dopo che in una di queste fasi l’avversario abbia fatto check)
- Raise (nel caso in cui l’avversario abbia effettuato per primo una puntata)
- Re-Raise (nel caso in cui il giocatore abbia effettuato una puntata e l’avversario abbia rilanciato)
- Termina la partita
L’utente dovra’ scegliere l’operazione da eseguire digitando il numero corrispondente e premendo il tasto INVIO. Si tenga presente che l’utente non dovra’ avere sempre accesso a tutte le funzionalità del programma. Il check, ad esempio, non e’ possibile pre-flop (se non dal grande buio ed in caso di semplice call del piccolo buio) e post-flop dopo che l’avversario ha effettuato una puntata.
Il software dovra’ costantemente visualizzare sullo schermo tutte le informazioni di cui l’utente necessita per poter prendere le proprie decisioni: stack suo e dell’avversario, eventuali carte presenti sul board, livello dei bui, posizione del bottone, ammontare del piatto, ultima azione intrapresa dall’avversario.
Fixed-limit Texas Hold’Em
Nel Texas Hold’Em in modalita’ torneo, ogni giocatore inizia la partita con un certo ammontare di chips, uguale per tutti i partecipanti. Le chips passano da un giocatore all’altro nel corso di ogni mano. La partita termina quando uno dei giocatori riesce a conquistare tutte le chips in gioco. Questa variante del poker si svolge utilizzando un mazzo composto da 52 carte francesi (54 meno i due jolly), di quattro semi diversi (cuori, quadri, fiori, picche). Alle singole carte e’ possibile fare riferimento utilizzando due caratteri: il primo ad indicare il valore della carta (da quella di valore minore a quella di valore maggiore la sequenza e’: 2, 3, 4, 5, 6, 7, 8, 9, T: 10/ten, J: fante/jack, Q: donna/queen, K: re/king, A: asso/ace), il secondo il suo seme (h: cuori/hearts, d: quadri/diamonds, c: fiori/clubs, s: picche/spades).
Il gioco si articola in un numero non predefinito di mani. All’inizio di ciascuna mano, uno dei giocatori riceve il bottone (dealer button), un disco che indica qual e’ il giocatore che deve occuparsi di distribuire le carte. Il bottone passa da un giocatore all’altro all’inizio di ciascuna nuova mano. Prima che le carte vengano distribuite, entrambi i giocatori devono effettuare una puntata obbligatoria (motivo per il quale queste vengono definite puntate effettuate “al buio”). In condizione di heads up, ovvero quando vi sono soltanto due giocatori attivi, il giocatore sul bottone deve effettuare una puntata pari al “piccolo buio” (small blind, SB), mentre l’altro giocatore deve puntare un importo pari al “grande buio” (big blind, BB, di ammontare doppio rispetto allo small blind). L’ammontare dei bui aumenta con il passare del tempo in maniera tale da velocizzare lo svolgimento della partita. Una volta “postati” i bui a ciascun giocatore vengono distribuite due carte (la prima e la terza vanno al giocatore di grande buio, la seconda e la quarta a quello sul bottone), le quali costituiscono le carte private (in gergo “hole cards”).
La mano puo’ quindi avere inizio. Essa consiste in un massimo di quattro fasi di gioco sequenziali, corrispondenti ad altrettanti turni (rounds) di puntate: pre-flop, flop, turn e river. Il primo giocatore ad agire (“parlare”) e’ quello di piccolo buio, che ha a disposizione diverse opzioni. Egli puo’ infatti: scartare la sua mano (fold), “chiamare”, ovvero pareggiare la puntata del grande buio (call, aggiungendo nel piatto la differenza tra grande e piccolo buio) oppure rilanciare la puntata (raise, ovvero coprendo la differenza tra grande e piccolo buio ed aggiungendo altre chips). A seconda dell’azione eseguita dal primo giocatore derivano le opzioni possibili per il suo avversario. In caso di call del giocatore sul bottone, quello di grande buio puo’ optare per: fold (opzione possibile, ma non particolarmente sensata, dato che regalerebbe il piatto all’avversario), check (la fase pre-flop termina senza nessun ulteriore investimento in termini di chips e si passa al turno di gioco successivo) o raise (nel piatto vengono puntate altre chips e l’avversario deve almeno chiamare questa puntata aggiuntiva per rimanere attivo nella mano in questione). In caso di raise del giocatore sul bottone le possibilita’ a disposizione del giocatore di grande buio sono il fold, il call o eventualmente un ulteriore rilancio (re-raise). Nel Fixed-Limit Hold’Em l’ammontare dei rilanci e’ fisso. Pre-flop e al flop e’ possibile rilanciare per un ammontare pari al grande buio, mentre al turn ed al river il rilancio ammonta a due volte il grande buio. Per quanto l’ammontare sia fisso, in condizione di heads up non vi e’ limite al numero di rilanci che e’ possibile effettuare. I due giocatori potrebbero quindi decidere di rilanciare reciprocamente le puntate dell’avversario fino a ritrovarsi con tutte le loro chips nel piatto.
Se le puntate effettuate durante la fase di pre-flop vengono pareggiate (ovvero se il bottone/SB chiama ed il BB sceglie di fare check, se il bottone rilancia ed il BB chiama questo rilancio, oppure se una serie di rilanci termina con uno dei due giocatori che si limita al call), le chips investite dai due giocatori vengono spostate all’interno del piatto, la prima fase di gioco si conclude e viene mostrato il flop. Il flop consiste di tre carte comuni che vengono distribuite a faccia in su sul tavolo e che entrambi i giocatori possono utilizzare per ottenere il loro punto migliore. I giocatori tornano di nuovo ad agire, partendo questa volta da colui che pre-flop era il grande buio. Le sue opzioni a questo punto sono tre: fold, check (il giocatore non aggiunge chips a quelle che sono gia’ all’interno del piatto, lasciando la parola al suo avversario) e bet (il giocatore effettua una puntata aggiungendo chips a quelle gia’ presenti all’interno del piatto). Le opzioni disponibili per il secondo giocatore, a questo punto, dipendono ancora una volta da quella che e’ stata l’azione intrapresa dal suo avversario. Nel caso in cui l’avversario abbia optato per il check, il giocatore sul bottone puo’ a sua volta decidere per il fold, il check (chiudendo in questo modo la fase di gioco al flop) oppure il bet. Nel caso in cui il giocatore che era di grande buio abbia puntato, il suo avversario puo’ invece scartare la sua mano (fold), chiamare la puntata (call), oppure rilanciarla (raise). Cosi’ come nella fase pre-flop il procedimento viene reiterato fino a quando le puntate sono pareggiate o uno dei due giocatori decide di scartare la sua mano. Nella prima di queste due ipotesi si procede alla fase di gioco successiva. Il turn, ovvero una quarta carta comune, viene distribuita a faccia in su sul tavolo. Un nuovo round di puntate ha quindi luogo secondo la stessa procedura valida per il gioco al flop. Nel caso in cui le puntate si pareggino nuovamente si arriva al river, ovvero la quinta ed ultima carta comune ad essere distribuita a faccia in su sul tavolo. Ancora una volta si ha un round di puntate che segue le identiche modalita’ delineate per il gioco al flop e al turn. Nel caso in cui le puntate siano pareggiate anche al river, si procede infine allo showdown: entrambi i giocatori rivelano le proprie carte private e colui che mostra la mano migliore si aggiudica il piatto.
La mano finale di un giocatore e’ composta dalle miglior combinazione di 5 carte realizzata prendendo un qualsiasi numero di carte tra quelle private e quelle comuni. Il valore di queste mani e’ ordinato come segue (dal minore al maggiore):
- carta alta (cinque carte di valore diverso, non dello stesso seme e non disposte a scala);
- coppia (due carte con lo stesso valore);
- doppia coppia (due coppie);
- tris (tre carte con lo stesso valore);
- scala (cinque carte con valori sequenziali);
- colore (cinque carte dello stesso seme);
- full house (un tris piu’ una coppia);
- poker (quattro carte con lo stesso valore);
- scala colore (cinque carte in sequenza, tutte dello stesso seme).
Sono di seguito riportati alcuni esempi utili per chiarire come vengano calcolate queste combinazioni di cinque carte.
Giocatore 1: As, 3c
Giocatore 2: Ks, Ts
Board: 4s, Jh, Qd, 7h, 6h
Risultato: Giocatore 1 si aggiudica il piatto in quanto la sua mano di cinque carte (As, Qd, Jh, 7h, 6h – 4s e 3c non vengono conteggiati) contiene un asso come carta piu’ alta, migliore rispetto al re carta alta di Giocatore 2 (Ks, Qd, Jh, Ts, 7h – 6h e 4s non vengono conteggiati).
Giocatore 1: As, Ks
Giocatore 2: Jh, Jd
Board: 4d, 3c, Kc, 2s, Js
Risultato: Giocatore 2 vince il piatto con un tris di J (Jh, Jd, Js, Kc, 4d – 3c e 2s non vengono conteggiati), contro la coppia di K di Giocatore 1 (Ks, Kc, As, Js, 4d – 3c e 2s non vengono conteggiati).
Giocatore 1: 4s, 4d
Giocatore 2: As, Ad
Board: 2h, 6h, Kh, Qh, Ah
Risultato: Giocatore 1 e Giocatore 2 pareggiano e si spartiscono il piatto in parti uguali. Entrambi hanno infatti colore (2h, 6h, Kh, Qh, Ah – le rispettive carte private non vengono conteggiate in quanto originerebbero punti minori rispetto al colore) con le sole cinque carte comuni.
In caso di due giocatori aventi una coppia, vince il piatto il giocatore in possesso della coppia piu’ alta. Stessa cosa vale per il tris e per il poker. Per il colore si prende in considerazione la carta piu’ alta tra le cinque aventi lo stesso seme, ed eventualmente la seconda, la terza, la quarta e la quinta (ad esempio: Ah, Jh, Th, 5h, 3h vince contro Ah, Th, 9h, 5h, 3h). Per quanto riguarda la scala e la scala colore, vince il giocatore che ha quella che termina con la carta piu’ alta (ad esempio: 5h, 6d, 7d, 8c, 9s perde contro 6d, 7d, 8c, 9s, Ts). Per quanto concerne infine il full house, vince chi ha il tris piu’ alto e, in caso questo sia uguale per tutti i giocatori, chi ha la coppia piu’ alta.
E’ molto importante tenere in considerazione il fatto che una mano puo’ terminare prima che si arrivi allo showdown, nel caso in cui uno dei due giocatori effettui una puntata (pre-flop, al flop, al turn o al river) ed il suo avversario decida di non chiamarla, scartando la sua mano (come accennato in precedenza, un giocatore puo’ scartare la sua mano anche in assenza di una puntata da parte dell’avversario, ma questo tipo di giocata non assume, de facto, alcun senso). In questo caso, chi ha effettuato la puntata risulta il vincitore della mano e si aggiudica il piatto. Nel gioco reale soltanto una percentuale relativamente bassa delle mani che vengono giocate durante una partita si conclude allo showdown, rendendo in questo modo il gioco molto interessante.
Un altro aspetto da considerare e’ che, nel caso in cui un giocatore effettui una puntata ed il suo avversario non abbia chips a sufficienza per pareggiarla, quest’ultimo puo’ comunque effettuare il call spostando nel piatto tutte le sue chips (condizione di “all in”). L’ammontare puntato e che non e’ stato “coperto” ritorna immediatamente a far parte dello stack del giocatore che ha effettuato la puntata, mentre il rimanente finisce nel piatto. Entrambi i giocatori si contendono quindi il piatto risultante secondo le normali regole di gioco. Se questa situazione si verifica prima del river, entrambi i giocatori devono mostrare le proprie carte nascoste girandole a faccia in su sul tavolo. Il dealer procede quindi a distribuire tutte le carte comuni ancora mancanti sul board ed il vincitore della mano e’ decretato una volta tutte queste diventano disponibili.
Ulteriori note
- Il progetto dovra’ essere realizzato individualmente.
- Il programma dovrà essere scritto in codice ANSI C standard, al fine di garantirne il più ampio livello di portabilità possibile. Non e’ ammesso, a meno che tale possibilità non sia esplicitata nel testo d’esame o nelle FAQ pubblicate su Dolly, l’utilizzo di comandi propri del sistema operativo in uso. Il programma dovra’ essere in grado di “girare” allo stesso modo su qualsiasi piattaforma.
- Il programma dovra’ essere adeguatamente commentato. Non abbiate paura di essere eccessivamente prolissi nei vostri commenti.
- Il programma dovra’ rispettare in maniera assolutamente rigorosa le specifiche illustrare in questo documento. Qualsiasi modifica rispetto allo schema ivi delineato ed apportata in maniera arbitraria verra’ considerata un errore. Per qualsiasi dubbio o chiarimento si prega di utilizzare il forum.
- Il mazzo da gioco dovra’ essere implementato attraverso una pila (e’ indifferente se l’implementazione avviene attraverso array o lista lineare). Due apposite funzioni dovranno provvedere rispettivamente a mescolarlo (shuffling) ed a prendere una carta dalla testa (operazione di pop) ogni qualvolta cio’ sia necessario (ovvero quando vengono distribuite le starting hands o quando vengono girate sul board le carte comuni).
- Ogni giocatore inizia la partita con uno stack di 1,500 chips.
- Per rendere piu’ semplice il programma, i bui non verranno aumentati su base temporale (evitando cosi’ allo studente il compito di implementare un timer). I livelli cambieranno ogni 10 mani giocate, susseguendosi in accordo a questa sequenza (piccolo/grande buio): 10/20, 15/30, 20/40, 30/60, 40/80, 50/100, 75/150, 100/200, 150/300, 200/400, 300/600. Nel caso in cui la partita sia ancora in corso dopo dieci mani giocate con bui a 300/600, questi non incrementeranno piu’ ed il gioco proseguira’ fino ad avere un vincitore.
- Ogni qualvolta un giocatore scegliesse di foldare la propria mano nonostante la possibilita’ di effetuare un check, un messaggio di avviso deve apparire chiedendo al giocatore conferma dell’azione intrapresa.
- Al termine di ogni mano il programma deve mostrare un riepilogo che indichi le mani di cinque carte dei due giocatori (in caso di showdown) ed i rispettivi punti, con conseguente “dichiarazione” del vincitore e dell’importo vinto. Stessa cosa nel caso in cui la mano si concluda prima dello show down. In tal caso le carte private dei due giocatori non devono essere mostrate, ma il programma dovra’ comunque riportare chi e’ il vincitore e quale l’importo del piatto che si e’ aggiudicato.
- Non tutte le mani di partenza hanno lo stesso valore. Seguendo ad esempio quanto riportato da Sklansky (Hold’Em Poker for Advanced Players, 1999) possiamo classificare le mani di partenza in 8 gruppi differenti, a partire dalle migliori per arrivare a quelle con minor potenziale (la dicitura “s” accanto ad una mano sta ad indicare che le due carte sono “suited”, ovvero dello stesso seme; x indica una carta qualsiasi minore del 9):
gruppo 1: AA, KK, QQ, JJ, AKs;
gruppo 2: TT, AQs, AJs, KQs, AK;
gruppo 3: 99, JTs, QJs, KJ,s ATs, AQ;
gruppo 4: T9s, KQ, 88, QTs, 98s, J9s, AJ, KTs;
gruppo 5: 77, 87s, Q9s, T8s, KJ, QJ, JT, 76s, 97s, Axs, 65s;
gruppo 6: 66, AT, 55, 86s, KT, QT, 54s, K9s, J8s, 75s;
gruppo 7: 44, J9, 64s, T9, 53s, 33, 98, 43s, 22, Kxs, T7s, Q8s;
gruppo 8: 87, A9, Q9, 76, 42s, 32s, 96s, 85s, J8, J7s, 65, 54, 74s, K9, T8.
Sulla base di questa semplice classificazione e’ possibile elaborare una solida strategia di gioco pre-flop.
- Non e’ richiesto che la strategia di gioco post-flop sia particolarmente elaborata. In linea di massima si puo’ far si’ che il computer segua un comportamento “a soglia”: punti o rilanci soltanto quando ha punti piu’ forti rispetto ad una certa misura di riferimento (es. coppia piu’ alta sul tavolo), faccia check o fold (a una puntata dell’avversario) quando non li ha.
- Facoltativo: estremamente interessante sarebbe aggiustare dinamicamente questa soglia a seconda dell’aggressivita’ dimostrata fino a quel momento dall’avversario umano (ad esempio chiamando e rilanciando con un range di punti molto piu’ ampio contro un giocatore che punta spesso dopo il flop). Allo stesso modo, anche la strategia pre-flop potrebbe adattarsi all’avversario che si ha di fronte (ad esempio estendendo il range di mani con le quali rilanciare contro un giocatore molto chiuso e restringendo il range per chiamare un suo rilancio).
- Il bluff e’ una componente importante del poker. Di tanto in tanto il software puo’ provare a rappresentare un punto che in realta’ non ha, puntando e/o rilanciando.
- Fintanto che i bui sono ad un livello basso in confronto al proprio stack e’ possibile seguire una strategia conservativa, selezionando le migliori mani di partenza e scartando quelle piu’ problematiche. Man mano che i bui aumentano ed iniziano ad incidere in maniera significativa sul proprio stack diventa necessario prendersi qualche rischio in piu’ ed entrare in gioco con un range di mani piu’ ampio.
- Un buon giocatore di poker deve essere imprevedibile. Per rendere tale il vostro software e’ possibile impostarlo per seguire una certa strategia, ma con l’introduzione di tanto in tanto di qualche variazione casuale sul tema (ad es., in una determinata situazione: esegui l’80% delle volte quello che suggerisce la strategia, fai qualcosa di diverso il restante 20% delle volte).
- Il programma deve tenere uno storico di tutte le mani giocate, salvato in un file di testo. Il formato per descrivere ogni singola mano deve ricalcare il seguente schema (dove si ipotizzano bui a 10/20 e i due giocatori che iniziano la mano con l’identico stack di 1,500 chips):
Poker Game, Hand #N – 10/20 – Fixed Limit Hold’em
Seat 1: Human (1,500)
Seat 2: Computer (1,500)
Human posts the small blind of 10
Computer posts the big blind of 20
The button is in seat #1
*** HOLE CARDS ***
Dealt to Human [7h Ad]
Human calls 10
Computer checks
*** FLOP *** [8c 4h Ah]
Computer checks
Human bets 20
Computer calls 20
*** TURN *** [8c 4h Ah] [4c]
Computer checks
Human bets 40
Computer raises to 80
Human calls 40
*** RIVER *** [8c 4h Ah 4c] [6d]
Computer bets 40
Human calls 40
Computer shows [8s 8d]
Human shows [7h Ad]
Computer shows a full house, Eights full of Fours
Human shows two pair, Aces and Fours
Computer wins the pot (320) with a full house, Eights full of Fours
*** SUMMARY ***
Total pot 320
Board: [8c 4h Ah 4c 6d]
Seat 1: Human (button) showed [7h Ad] and lost with two pair, Aces and Fours
Seat 2: Computer showed [8s 8d] and won (320) with a full house, Eights full of Fours