Esercizio 9
Crea la classe carta da gioco, poi crea la classe mazzo di carte e poi crea la classe mano di carte.
La scrittura di un codice che descriva la struttura di un mazzo di carte passa inevitabilmente dalla preventiva definizione del tipo di dato: carta (C). Il seguente codice introduce la classe C (carta) e istanzia un vettore di 52 carte con quattro semi: quadri, cuori, fiori e picche. Le carte di ciascun seme hanno un valore che va da 1 (asso) a 10 e poi ci sono le tre figure :fante (11) regina (12) e re (13).
class provaMazzo1 {
public static void main(String[] args) {
C[] T = new C[52];
int i = 0;
for (int s=0;s<= 3;s++)
for (int v=1; v<=13;v++){
T[i] = new C(v, s);
i++;
}
for(i=0;i<T.length;i++) System.out.println(T[i]);
}//______main
}//____classe
class C {
private int valore;
private int seme;
public static final String[] V={"", "asso", "2", "3", "4", "5", "6", "7",
"8", "9", "10", "fante", "regina", "re"};
public static final String[] S={"quadri","cuori","fiori","picche"};
C(int v, int s) {//Costruttore
this.valore = v; this.seme = s; }
public int getV(){return valore;}//metodi get
public int getS(){return seme;}
public String toString() {
String st = V[this.valore] + " di " + S[this.seme];
return st; }
}//C
L'indice del vettore varia da 0 a 51 inclusi ed ogni carta è dotata di
una coppia di coordinate che ne identificano il valore ed il seme C(v,
s). Ogni carta può poi essere rappresentata dal metodo toString()
che fa uso di due vettori di stringhe costanti String[]
V e String[] S.
Per come viene caricato il vettore, nessuna carta può avere una coordinata
valore = 0 quindi il primo elemento del vettore String[]
V esiste ma non verrà mai usato: viene dunque posto a stringa nulla
"".
I sistema di decodifica è facilmente intuibile: viene mandata in output
la stringa che ha lo stesso indice della coordinata del valore e del seme
corrispondente.
In un certo senso abbiamo già creato un oggetto "mazzo di carte" (l'array
T[] è di fatto un oggetto) non abbiamo invece scritto
una classe per l'oggetto "mazzo di carte".
Per questo scriviamo la classe mazzo di carte (MZ)
class MZ {
private C[] T;
//costruttore standard mazzo di 52 carte.
MZ() {
this.T = new C[52];
int i = 0;
for (int s=0;s<= 3;s++)
for (int v=1; v<=13;v++){
this.T[i] = new C(v, s);
i++;
}
}//MZ
Di fatto, la classe contiene il vettore di 52 carte T[
] come attributo; il suo caricamento avviene nel costruttore della
classe invece che nel main().
Si capisce che dopo aver istanziato un oggetto di classe MZ
avremo un bel mazzo di carte ordinato, ma nella realtà prima di giocare
bisogna dargli una bella mescolata.
Quindi aggiungiamo i metodi scambia() e mescola() per mischiare le carte
casualmente e poi aggiungiamo anche un metodo toString()
per stampare il mazzo mischiato.
Il risultato sarà il seguente:
class provaMazzo2 {
public static void main(String[] args) {
MZ mz=new MZ();
mz.mescola();
System.out.println(mz);
}//______main
}//______class
class C {
//...come sopra
}//C
class MZ {
private C[] T;
//costruttore standard mazzo di 52 carte.
MZ() {
this.T = new C[52];
int i = 0;
for (int s=0;s<= 3;s++)
for (int v=1; v<=13;v++){
this.T[i] = new C(v, s);
i++;
}
}//costruttore
//Stampa le carte del mazzo.
public String toString() {
String st="";
for (int i=0;i<this.T.length; i++)
st+=this.T[i]+"\n";
return st;
}
//Scambia le carte tra gli indici i e j.
public void scambia(int i, int j) {
C x; x=this.T[i];
this.T[i]=this.T[j];
this.T[j]=x;
}//scambia
//mescola casualmente
public void mescola() {
for (int i = this.T.length-1; i>0; i--){
int j=(int)(Math.random()*(i+1));
this.scambia(i,j);
}//for
}//mescola
}//MZ
Dopo aver scritto la classe per definire un mazzo di carte, il problema
ci chiede di scrivere la classe "mano di carte" .
Ci immaginiamo che la mano di carte debba essere estratta dal mazzo e che
dopo l'estrazione (ovviamente) le carte della mano non siano più presenti
nel mazzo (altrimenti si tratterebbe di un mazzo truccato).
Descrivere questi fatti ci impone di riconsiderare la struttura dell'intero
programma.
Di fatto, il mazzo mescolato in condizioni iniziali, la mano di carte estratta
ed il mazzo di carte rimanenti, sono dei generici insiemi di carte.
Per definire il comportamento di questi insiemi di carte possiamo concepire
una classe CC (collezione di carte) dalla quale poter
derivare una classe più specializzata come il mazzo da gioco iniziale. Infatti
solo il mazzo di carte iniziale ha una dimensione ben definita (52) da esso
vengono estratte le varie mani di carte ed il mazzo restante che viene collocato
sul tavolo.
Per gestire questi insiemi di carte a dimensione variabile è consigliabile
introdurre un arraylist di oggetti carta perché sappiamo che l'arraylist
è già dotato di sue funzioni autonome come add()
e remove() che permettono di inserire e rimuovere
carte da una posizione specifica oppure dalla cima della pila di carte.
Nel codice sorgente si notano all'interno della classe CC
il metodo estra() per spostare n carte da un insieme
all'altro .
Basterà dunque istanziare un generico mazzo di carte di classe MZ
per poi generare tutti i sottoinsiemi di carte che sono necessari tramite
il comando
mz.estra(n);
la classe genitrice CC provvederà a definire un oggetto
costituito da n carte tramite il costruttore
CC() {this.T = new ArrayList<C>();}
componendo l'arraylist T, rappresentativo l'insieme
di n carte.
import java.util.ArrayList;
class provaMazzo3 {
public static void main(String[] args) {
MZ mz= new MZ();
mz.mescola();//mescola il mazzo
CC ma= new CC();
mz.estra(ma, 5);
//ho estratto 5 carte dal mazzo mz
//e le ho messe nella mano "ma"
System.out.println("mazzo:"+ mz.dim()+" carte");
System.out.print(mz);
System.out.println("mano:"+ ma.dim()+" carte");
System.out.print(ma);
}//main
}//class
class CC {
private ArrayList <C> T;
//costruttore insieme vuoto di n carte
CC() {this.T = new ArrayList<C>();}
//aggiunge una carta all'insieme
public void addCarta(C c) {T.add(c);}
//rimuove la carta di indice i
public C popCarta(int i){return T.remove(i);}
//rimuove l'ultima carta
public C popCarta(){
int i = dim() - 1;
return popCarta(i);
}
//restituisce il numero di carte
public int dim() {return T.size();}
//restituisce vero se l'insieme è vuoto, falso
altrimenti
public boolean vuota(){return T.size() == 0;}
//muove n carte dall'insieme this all'inseme
that
public void estra(CC that, int n) {
for (int i = 0; i < n; i++) {
C c = popCarta();
that.addCarta(c);
}
}
//ritorna la carta di indice specificato
public C getC(int i){return T.get(i);}
//ritorna l'ultima carta
public C ultima() { int i = dim() - 1; return T.get(i); }
//scambia due carte di indice i e j
public void scambia(int i, int j) {
C c = T.get(i);
T.set(i, T.get(j));
T.set(j, c);
}
//permuta due carte casualmente
public void mescola() {
for (int i=dim()-1; i>0; i--){
int j=(int)(Math.random()*(i+1));
this.scambia(i,j);
}//for
}//mescola
public String toString() {
String st="";
for(int i=0;i<dim();i++) st+=T.get(i)+"\n";
return st; }
}//CC
class MZ extends CC{
MZ() {
for (int seme = 0; seme <= 3; seme++) {
for (int valore= 1; valore<= 13; valore++) {
addCarta(new C(valore, seme));
}//for valore
}//for seme
}//fine costruttore
}//MZ
class C {
//...come sopra
}//C
Come si vede il mazzo di 52 carte, viene considerato un caso specifico
dell'inisieme di carte CC.
Quest'ultima classe è stata sufficientemente dotata di opportuni
metodi per poter generare ed operare su sottoinsiemi del mazzo iniziale.
Andrebbe completata con ulteriori metodi che possano comparare tra loro
le varie carte, oppure riconoscerne
eventuali combinazioni.