Il codice fornito è una versione (adattata secondo le convenzioni Gradle) di parte del programma Solitaire, scritto da Martin P. Robillard.
In questo esercizio si richiede di utilizzare le classi del package
ca.mcgill.cs.stg.solitaire.cards
senza modificarle, nello spirito
dell'"Open/Closed Principle". Le classi prodotte dovranno far parte del
package it.unimi.di.sweng.lab04
.
Si vuole avere una classe PokerHand
che permetta di gestire un gruppo di
carte e una classe PokerTable
che gestisca un gruppo di giocatori rappresentato dalle rispettive PokerHand
.
In particolare sviluppare con metodologia TDD:
-
un costruttore di
PokerHand
a partire da una lista diCard
(stando attenti a non cadere nell'errore di introdurre un ReferenceEscaping) -
PokerHand
espone il gruppo di carte di cui sono composti solo tramite un iteratore (Utilizzare il pattern Iterator, sfruttando l'interfacciaIterable
della libreria standard) -
Definire una classe
PokerTable
con la responsabilità di creare e gestire ilDeck
della partita en
(passato come parametro) giocatori assegnando 5 carte a ciascuno. -
PokerTable
deve essereIterable
sullePokerHand
. -
Gli oggetti
PokerHand
forniscono un metodogetRank()
per determinare il punteggio di una mano (in caso di dubbio, le regole sono riassunte qui: https://en.wikipedia.org/wiki/List_of_poker_hands). I possibili punteggi (da sviluppare uno alla volta, nell'ordine voluto, secondo una modalità TDD) sono:
public enum HandRank {
HIGH_CARD,
ONE_PAIR,
TWO_PAIR,
THREE_OF_A_KIND,
STRAIGHT,
FLUSH,
FULL_HOUSE,
FOUR_OF_A_KIND,
STRAIGHT_FLUSH
}
- L'implementazione del metodo
getRank()
rischia di cadere nell'anti-pattern "Switch Statement". Per evitarlo, è possibile organizzare la valutazione del punteggio secondo un pattern "Chain-of-responsibility": si definisce un'interfacciaChainedHandEvaluator
che espone un metodo che, dato un oggettoPokerHand
ne calcola il punteggio (HandRank
) corrispondente; per ogni tipologia di punteggio che si vuole valutare, occorrerà implementare un sotto-tipo appropriato diChainedHandEvaluator
. Ciascun sotto-tipo diChainedHandEvaluator
conosce anche il "prossimo" valutatore (comunicato col proprio costruttore): ciò permette di costruire una catena di valutatori. Si può perciò iniziare dal valutatore del punteggio più alto (STRAIGHT_FLUSH
) che avrà come prossimo valutatore quello diFOUR_OF_A_KIND
, ecc. La logica di valutazione sarà: se il valutatore riconosce lo schema del "proprio" punteggio, restituisce il valore opportuno (p.es. se il valutatore del tris trova 3 carte dello stesso valore nellaPokerHand
restituisceTHREE_OF_A_KIND
, altrimenti richiama il prossimo valutatore, probabilmente il valutatore di doppie coppie). Non è necessario realizzare tutti i valutatori ma almeno tre a vostra scelta.
-
La classe
PokerTable
deve fornire un metodoPokerHand getHand(int i)
che restituisce una copia della mano del giocatore i-esimo; -
Gli oggetti
PokerHand
devono implementare l'interfacciaComparable
, ordinando lePokerHand
secondo il valore restituito dagetRank()
. Non c'è bisogno di definire l'ordinamento fra mani con lo stesso punteggio. -
Aggiungere a
PokerTable
un metodovoid change(int player, List<Card> toChange)
che permetta di cambiare le carte della mano del giocare numeroplayer
, con il vincolo che almeno una deve restare invariata. Si può assumere (precondizione del contratto) che le carte indicate come da cambiare facciano effettivamente parte della mano del giocatore e che almeno una carta non venga cambiata -
La classe
PokerTable
deve fornire un metodo che restituisce un iteratore suInteger
che permetta di scorrere gli identificatori deiplayer
ordinati dal punteggio più alto al più basso. -
Se rimane tempo completare i valutatori lasciati in sospeso e estendere il confronto di
PokerHand
in modo che risolva anche i casi di parità di ranking (vedi https://en.wikipedia.org/wiki/List_of_poker_hands)