La creazione di un progetto da zero in Visual Basic NET? Lo trovi su Opentraining.it
Corso di Visual Basic:
Quindicesima lezione - Campo Minato: algoritmi, diagrammi di flusso, l'operatore Mod, la funzione IIf, il parametro Index (a cura di Giorgio Abraini)

Ricapitolando, ora conosciamo le posizioni delle mine, e ogni pulsante sa, grazie alla proprietà tag, se nasconde una mina oppure no; ora dobbiamo scrivere le istruzioni per il gioco vero e proprio: cosa succede quando il giocatore preme un pulsante?
Quello che succede è molto semplice: se sotto il pulsante premuto si trova una mina, il gioco termina; altrimenti viene visualizzato il numero di mine circostanti quel pulsante, come mostra la figura sotto:


bisognerà quindi effettuare un controllo del genere:

If Mina(i).Tag = -1 Then
'il gioco è finito!
Else
'il gioco continua
End If

Prima di tutto, però, bisogna calcolare quante mine circondano ogni pulsante: questa operazione è opportuno farla all'inizio della partita, in modo che il calcolo sia effettuato una volta sola; quindi dobbiamo aggiornare la routine mnuNew_Click.
A questo punto dobbiamo escogitare un algoritmo semplice ed efficiente per fare questi calcoli: per chi non lo sapesse, un algoritmo è una sequenza di operazioni che permettono di ottenere un generico obiettivo; la sequenza con cui queste operazioni devono essere eseguite è determinata dal verificarsi di certe condizioni, e il controllo di queste condizioni è parte integrante dell'algoritmo.
Solitamente si usa un grafico (il cosiddetto diagramma di flusso) per descrivere un algoritmo (ovvero il flusso delle operazioni), ma qui preferisco usare un elenco numerato.
Un algoritmo per calcolare il numero di mine circostanti un pulsante potrebbe essere questo:

1) prendo in considerazione un pulsante (chiamiamolo "x");

2) prendo in considerazione tutti i pulsanti che lo circondano, uno alla volta (chiamiamo questo pulsante "y");

3) se y nasconde una mina, incremento un contatore c, altrimenti non faccio nulla;

4) esamino il pulsante successivo tra quelli che circondano x, e torno al punto 2); se ho esaminato tutti i pulsanti che circondano x, assegno x.Tag = c e reimposto c = 0 (altrimenti c si ricorderebbe dei valori relativi ad altri pulsanti);

5) esamino il pulsante successivo a x e torno al punto 1; se ho esaminato tutti i pulsanti, ho terminato l'algoritmo.

In parole povere, questo algoritmo descrive due cicli annidati tra loro: il primo esamina tutti i nostri 16 pulsanti, uno alla volta; il secondo, quello più interno, esamina tutti i pulsanti che circondano quello preso in esame dal primo ciclo; all'interno del secondo ciclo viene aggiornato il contatore delle mine.
C'è però un altro algoritmo, che mi sembra più semplice ed efficiente: visto che sappiamo che le mine sono in tutto 3, non c'è alcun bisogno di fare due cicli per andare a cercare i pulsanti che nascondono una mina; noi sappiamo dove sono le mine, e quindi ci basterà aggiornare le proprietà Tag dei pulsanti che circondano quelli che nascondono una mina.
L'algoritmo è questo:

1) inizializzo le proprietà tag di tutti i pulsanti a 0;

2) prendo in esame il pulsante con indice PosMine(i) (chiamiamolo "x"; inizialmente i = 0);

3) pongo x.tag = -1 e aggiorno le proprietà tag di tutti i pulsanti che circondano x;

4) se i = 2 termino l'algoritmo, altrimenti pongo i = i + 1 e torno al punto 2.

Tradotto in codice, questo algoritmo diventerebbe così (ovviamente va aggiunto alla routine mnuNew_Click):

Dim i As Integer 'contatore
Dim x As Integer, y As Integer 'coordinate del pulsante con la mina
Dim x1 As Integer, y1 As Integer 'coordinate dei pulsanti circostanti 'quello con la mina
For i = 0 To 15
Mina(i).Tag = 0
Next i
For i = 0 To 2
Mina(PosMine(i)).Tag = -1
x = Int(PosMine(i) / 4) 'riga in cui si trova la mina
y = PosMine(i) Mod 4 'colonna in cui si trova la mina
For x1 = IIf(x = 0, 0, x - 1) To IIf(x = 3, 3, x + 1)
For y1 = IIf(y = 0, 0, y - 1) To IIf(y = 3, 3, y + 1)
If Mina(4 * x1 + y1).Tag > -1 Then
Mina(4 * x1 + y1).Tag = Mina(4 * x1 + y1).Tag + 1
End If
Next y1
Next x1
Next i
Timer1.Enabled = True

Il primo ciclo è quello di inizializzazione; il secondo appare più complicato di quanto sia in realtà: innanzitutto viene aggiornato il Tag del pulsante con la mina, poi vengono calcolate le coordinate di questo pulsante; questa operazione è opportuna perché i pulsanti sono disposti graficamente come una matrice bidimensionale 4 x 4, mentre nel codice sono "allineati" in un vettore unidimensionale.
Prendiamo ad esempio il decimo pulsante, quello con indice 9: dato che ogni riga è di quattro elementi, per sapere su quale riga e colonna si trova bisogna sottrarre dall'indice il multiplo di 4 immediatamente precedente all'indice stesso (in questo caso 8): la differenza (9 - 8 = 1) indica la colonna, mentre questo multiplo diviso per 4 indica la riga (8 / 4 = 2).
La colonna viene ottenuta tramite l'operatore Mod, che restituisce il resto intero di una divisione: ad esempio, 9 Mod 4 = 1 perché 9 / 4 è uguale a 2 col resto di 1; ovviamente 8 Mod 4 = 0, così come 10 Mod 5, 6 Mod 2, 3 Mod 3 ecc.
Per analogia con l'indice dei pulsanti, anche le righe e le colonne le contiamo a partire da 0, quindi il pulsante con indice 9 si troverà sulla riga 2 colonna 1, ovvero il decimo pulsante si trova sulla terza riga, seconda colonna.
Ottenute le coordinate, è più semplice controllare i pulsanti che circondano la mina.
Avrete notato una nuova funzione nei cicli più interni: la funzione IIf; questa funzione è simile ad una if "concentrata": i tre argomenti indicano rispettivamente la condizione da verificare, il risultato da restituire se la condizione è vera, il risultato da restituire se la condizione è falsa; in altri termini, IIf(x=0, 0, x-1) equivale a:

If x = 0 Then
risultato = 0
Else
risultato = x - 1
End If

Questo controllo è necessario perché, se è x = 0, cioè se la mina si trova sulla prima riga, i pulsanti circostanti partono anch'essi dalla prima riga e non dalla riga precedente come avverrebbe negli altri casi, semplicemente perché non esiste una riga precedente alla prima; lo stesso dicasi per l'ultima riga

IIf(x = 3, 3, x + 1))

e per la prima e ultima colonna.
Nel ciclo più interno ho introdotto un altro controllo per verificare che il pulsante controllato NON sia quello che nasconde la mina: infatti i due cicli analizzano tutti i pulsanti che circondano la mina, compreso quello che nasconde la mina stessa, e quest'ultimo non deve essere modificato.
Per non parlare della possibilità di avere due mine adiacenti. Infine, la proprietà Tag viene aggiornata incrementando di 1 il valore della stessa proprietà.
Questo per consentire un'indicazione corretta nel caso le mine circostanti un determinato pulsante siano 2, oppure 3.
L'ultima istruzione serve per abilitare il Timer, in modo da poter misurare i secondi di gioco. Ora possiamo finalmente scrivere il codice da eseguire quando il giocatore preme un pulsante: si tratta semplicemente di controllare il valore della proprietà Tag; nella routine Mina_Click noterete la presenza del parametro Index: questo è ovviamente l'indice del pulsante premuto dall'utente, ed è stato aggiunto automaticamente da Visual Basic quando abbiamo deciso di creare la matrice di pulsanti. In questa routine dunque scriviamo:

Dim x As Integer, y As Integer 'coordinate del pulsante premuto
Dim x1 As Integer, y1 As Integer 'coordinate dei pulsanti circostanti 'quello premuto
If Mina(Index).Tag > 0 Then
Mina(Index).Caption = Mina(Index).Tag
ElseIf Mina(Index).Tag = -1 Then
For x = 0 To 2
Mina(PosMine(x)).Caption = "M"
Next x
Timer1.Enabled = False
Else 'mina(index).tag=0
x = Int(Index / 4) 'riga in cui si trova la mina
y = Index Mod 4 'colonna in cui si trova la mina
For x1 = IIf(x = 0, 0, x - 1) To IIf(x = 3, 3, x + 1)
For y1 = IIf(y = 0, 0, y - 1) To IIf(y = 3, 3, y + 1)
Mina(4 * x1 + y1).Caption = Mina(4 * x1 + y1).Tag
Next y1
Next x1
End If

Il significato di questo codice dovreste essere in grado di capirlo da soli, tenendo conto di come funziona il vero "Campo Minato". Comunque la prossima volta lo spiegherò in dettaglio



Archivio:
Lezioni Commenta questa lezione Invia la tua guida Avviso per le nuove lezioni
Proponi un argomento

Visual Basic Italia© copyright 2000 - tutti i diritti riservati
E-mail:
vbitalia@libero.it