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
PokerHanda partire da una lista diCard(stando attenti a non cadere nell'errore di introdurre un ReferenceEscaping) -
PokerHandespone il gruppo di carte di cui sono composti solo tramite un iteratore (Utilizzare il pattern Iterator, sfruttando l'interfacciaIterabledella libreria standard) -
Definire una classe
PokerTablecon la responsabilità di creare e gestire ilDeckdella partita en(passato come parametro) giocatori assegnando 5 carte a ciascuno. -
PokerTabledeve essereIterablesullePokerHand. -
Gli oggetti
PokerHandforniscono 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'interfacciaChainedHandEvaluatorche espone un metodo che, dato un oggettoPokerHandne calcola il punteggio (HandRank) corrispondente; per ogni tipologia di punteggio che si vuole valutare, occorrerà implementare un sotto-tipo appropriato diChainedHandEvaluator. Ciascun sotto-tipo diChainedHandEvaluatorconosce 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 nellaPokerHandrestituisceTHREE_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
PokerTabledeve fornire un metodoPokerHand getHand(int i)che restituisce una copia della mano del giocatore i-esimo; -
Gli oggetti
PokerHanddevono implementare l'interfacciaComparable, ordinando lePokerHandsecondo il valore restituito dagetRank(). Non c'è bisogno di definire l'ordinamento fra mani con lo stesso punteggio. -
Aggiungere a
PokerTableun 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
PokerTabledeve fornire un metodo che restituisce un iteratore suIntegerche permetta di scorrere gli identificatori deiplayerordinati dal punteggio più alto al più basso. -
Se rimane tempo completare i valutatori lasciati in sospeso e estendere il confronto di
PokerHandin modo che risolva anche i casi di parità di ranking (vedi https://en.wikipedia.org/wiki/List_of_poker_hands)