Ci eravamo lasciati con la prima parte riguardante l'argomento vettori (array), nella lezione numero 14 ma, soprattutto, vi avevo promesso che avrei continuato il discorso facendovi un esempio di come utilizzarli in una applicazione (a console) ed in particolar modo scrivendo un programmino che potevamo usare per giocare al SuperEnalotto. Bene. E' arrivato il momento di mettere mano al codice. Prima di iniziare è necessaria una piccola premessa: "Per vincere al SuperEnalotto, è necessario avere solo ed esclusivamente fortuna! Non esistono formule magiche. Il programmino che faremo è solo a scopo didattico e quindi se non si ha fortuna..." Poco tempo fa mi ero dilettato a progettare l'applicazione anche per il mio PDA (palmare con Windows Mobile 5) sempre scritta in C# e funzionava molto bene perché avevo previsto anche il gioco del Lotto. Era mia intenzione di fornire a tutti coloro che erano interessati questa piccola applicazione per PDA, ma in una fredda giornata di Gennaio il mio palmare mi ha detto addio e, in compenso, ho perso tutto il codice sorgente memorizzato sul mio PC. Non dispero di poter resuscitare il palmare e se dovessi riuscirci, vi informerò in qualche modo. Le esequie per il mio PDA sono terminate ed è ora di fare le cose un po' più serie. Come saprete il gioco del SuperEnalotto basa i suoi numeri sulle estrazioni delle prime sei ruote del lotto. Questo però ci interessa ben poco in quanto il programma dovrà "semplicemente" generare una sequenza casuale di quei sei numeri. Il problema è che questa sequenza non deve avere numeri ripetuti ovviamente, e si dovranno "estrarre" sei numeri a caso sui novanta canonici del Lotto, cioè da 1 a 90. Ma cosa c'entrano i vettori in tutto questo? E' necessario che un numero estratto non lo sia già stato, e per ogni estrazione (casuale) il controllo deve essere ripetuto fino a quando non vengono generati sei numeri differenti. L'uso di un vettore di 90 elementi, inizializzato tutto a zero, mi è stato di grande aiuto perché ad ogni estrazione vado a collocare l'estratto nel vettore nel punto esatto indicizzato dal numero stesso-1. Se e solo se la locazione puntata dall'estratto-1 risulta contenere il valore zero, allora lo inserisco nel vettore, altrimenti ne genero uno nuovo ed il controllo viene ripetuto. Tutto questo fino a quando non inserisco tutti e sei numeri estratti. Vi ricordo a tal proposito che un vettore indicizza i suoi elementi con base zero; cioè il primo elemento ha indice 0, il secondo ha indice 1, e così via. Quindi i 90 numeri all'interno del vettore vanno indicizzati da 0 a 89. ESEMPIO: Numero estratto casualmente = 35
Avrei potuto utilizzare sei variabili e controllare se ognuna di esse conteneva l'estratto, ma credo che il metodo precedente sia più veloce e con meno controlli. Qualcuno potrebbe pensare che l'uso di un vettore per tenere traccia dei 6 estratti sia esagerato. A pensarci bene, no! Il motivo è che posso tenere traccia degli estratti per ben 15 giocate. Infatti 6 x 15 = 90. Quindi se volessi giocare per 15 volte in un solo colpo, non avrò sicuramente estratti ripetuti ed ogni volta che lo farò, ho molta probabilità di non avere nessuna sestina identica alle 15 precedenti. Quest'ultima ipotesi di gioco deve essere affrontata quando verranno studiate le matrici. Questo semplice "algoritmo" l'ho inventato io, ma, se qualcuno di voi ha una idea migliore e più veloce, non esiti a farmelo sapere ne sarò felice. Finalmente, dopo le chiacchiere, si parla di C#. Per prima cosa è necessario generare un numero casuale appartenente all'insieme dei numeri del lotto, da 1 a 90. Il linguaggio mette a disposizione una classe ad hoc per fare ciò, la classe Random con la quale creeremo un oggetto che chiameremo rnd: Random rnd= new Random(); attraverso il quale abbiamo la possibilità di generare un numero casuale. L'oggetto così creato può fare utilizzo di tre metodi principali, questi:
Per il nostro programmino, faremo uso del terzo metodo il quale dovrà generare un numero casuale appartenente all'intervallo 1-90. Quindi richiameremo questo metodo in questo modo: rnd.Next(0,90); che ritorna un numero intero a 32 bit appartenente all'intervallo. L'intervallo così dichiarato non contempla però l'estremo superiore, cioè, verrà generato un numero intero da 0 a 89 che utilizzeremo per indicizzare proprio il nostro vettore per il controllo di cui sopra. Nel momento in cui si inserirà il numero nel vettore, il medesimo verrà incrementato di una unità (per avere poi gli esatti estratti da 1 a 90). L'alternativa sarebbe stata anche quella di far generare l'estratto nell'intervallo 1 a 90 per poi utilizzarlo decrementato di uno al momento dell'indicizzazione del vettore. Il vettore che utilizzeremo, dovrà contenere gli estratti e considerando che i numeri del lotto non superano la cifra 90, credo che non c'è alcun bisogno di implementare un vettore che contenga degli interi a 32 bit (ognuno dei quali occupa ben 4 byte) ma si potrebbe dichiarare un vettore di tipo byte nel seguente modo: byte[] estratti = new byte[90]; che potrà contenere interi a 8 bit (1 byte, cioè cifre da 0 a 256) con un notevole risparmio di memoria (lascio a voi il calcolo come esercizio). Una volta dichiarato il vettore, è bene azzerarlo e lo faremo con il seguente metodo: static void Azzera_vettore() { //ogni elemento del vettore //viene inizializzato a 0 for(byte i = 0; i < 90; i++) estratti[i]= 0; } Il passo successivo è un metodo che finalmente genera i 6 numeri: static void Genera() { // variabile contatore byte i = 0; // variabile che contiene l'estratto byte numero = 0; // viene generato un numero intero // che deve essere sottoposto a // casting* perché il vettore contiene // valori di tipo byte numero = (byte)rnd.Next(0,90); // ciclo che controlla l'esistenza // dell'estratto per sei volte (da 0 a 5) while (i < 6) { if (estratti[numero] == 0) { // se la locazione del vettore // puntata dall'estratto contiene // il valore 0, allora lo inserisce // nel vettore incrementato di 1 e // anch'esso deve essere sottoposto a // casting* perché l'incremento risulta // intero estratti[numero] = (byte)(numero+1); // ed incrementa il contatore i++; } // genera un nuovo numero numero = (byte)rnd.Next(0, 90); } } *Cosa significa casting? Il casting è una operazione attraverso la quale abbiamo l'opportunità di convertire il tipo di una determinata variabile in un altro. Nel metodo Genera(), si è fatto uso del casting per convertire una cifra di tipo int ritornata dal metodo rnd.Next(0,90), in un tipo byte con cui abbiamo dichiarato la variabile numero:
Una scrittura del genere effettua la conversione da un tipo int (a 32 bit) ad un tipo byte (a 8 bit). Un esempio: ... Graficamente abbiamo in memoria una situazione del genere: rappresentazione binaria del numero intero 38 della variabile numero1
di tipo int (32 bit): rappresentazione binaria della variabile numero2 di tipo
byte (8 bit): Dopo l'operazione di casting, la situazione della variabile numero2
sarà: cioè sono stati "copiati" solo i primi 8 bit della variabile intera numero1 nella seconda variabile numero2 eliminando i restanti 24 bit. Un altro esempio: ... Graficamente abbiamo in memoria una situazione del genere: rappresentazione binaria del numero intero 258 della variabile numero1
di tipo int (32 bit): rappresentazione binaria della variabile numero2 di tipo
byte (8 bit): Dopo l'operazione di casting, la situazione della variabile numero2
sarà: cioè conterrà il valore 2. Questa situazione non è ovviamente accettabile perché vengono persi dei dati. Non è stato memorizzato il valore originario, infatti i primi 8 bit della variabile numero1 rappresentano appunto il valore 2, non 258. Morale della favola: Nel nostro programmino del SuperEnalotto, non abbiamo problemi di sorta in quanto i numeri generati rientrano perfettamente nei valori possibili che una variabile di tipo byte (8 bit) può contenere (da 1 a 90). Spero di essere stato chiaro. Proseguiamo. Come ultimo metodo, ci sarà quello che visualizzerà tutti gli estratti: static void Stampa() { Console.WriteLine("Programma SuperEnalotto:\n\nGli estratti sono:\n"); for(byte i = 0; i < 90; i++) if (estratti[i] != 0) Console.Write("{0} ", estratti[i]); Console.WriteLine(); } che visualizza gli estratti in ordine crescente. Si commenta da solo (spero!). Infine il metodo Main() che altro non fa che richiamare i metodi di cui sopra; public static void Main() { Azzera_vettore(); Genera(); Stampa(); // resta in attesa fino a quando non // viene premuto il tasto Invio Console.ReadLine(); } Il codice ora è completo, e questo è il listato: using System; public class Program { // dichiarazione degli oggetti // a livello globale static Random rnd= new Random(); static byte[] estratti = new byte[90]; static void Azzera_vettore() { // ogni elemento del vettore // viene inizializzato a 0 for (byte i = 0; i < 90; i++) estratti[i] = 0; } static void Genera() {
// variabile contatore
byte i = 0;
// variabile che contiene l'estratto
byte numero = 0;
// viene generato un numero intero
// che deve essere sottoposto a
// casting perché il vettore contiene
// valori di tipo byte
numero = (byte)rnd.Next(0,90);
// ciclo che controlla l'esistenza
// dell'estratto per sei volte (da 0 a 5)
while (i < 6)
{
if (estratti[numero] == 0) {
// se la locazione del vettore
// puntata dall'estratto contiene
// il valore 0, allora lo inserisce
// nel vettore incrementato di 1 e
// anch'esso deve essere sottoposto a
// casting perché l'incremento risulta
// intero
estratti[numero] = (byte)(numero+1);
// ed incrementa il contatore
i++;
}
// genera un nuovo numero
numero = (byte)rnd.Next(0, 90);
}
}
static void Stampa()
{
Console.WriteLine("Programma SuperEnalotto:\n\nGli estratti sono:\n");
for(byte i = 0; i < 90; i++)
if (estratti[i] != 0)
Console.Write("{0} ", estratti[i]);
Console.WriteLine();
}
public static void Main() { Azzera_vettore(); Genera(); Stampa(); // resta in attesa fino a quando non // viene premuto il tasto Invio Console.ReadLine(); } Copiatelo, salvatelo con il nome di Super8.cs e compilatelo. Questo è il mio esempio: L'interfaccia è ovviamente spartana trattandosi di una applicazione a console, ma potete tranquillamente modificare il codice affinchè possa essere più possibile gradevole, e buona fortuna! Nella prossima lezione, in cui studieremo le matrici, faremo in modo di ampliare questo programmino in modo da ottenere tutte e 15 le possibili sestine in ordine di estrazione. Pagina precedente - Pagina successiva |