edutecnica

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.