Chi non conosce Tris? 🙂 Uno dei giochi più semplici, e proprio per questo ha appassionato generazioni di persone.
Il gioco si svolge su una griglia di 3 x 3 caselle e ogni giocatore segna a turno una casella con una “X” o una “O”.
L’obiettivo è posizionare tre simboli in fila, in orizzontale, in verticale o in diagonale. Il primo giocatore che riesce a raggiungere questo obiettivo vince la partita.
Ho voluto sperimentate una semplice implementazione di Tris in Python.
Esaminiamo insieme il codice per capire come funziona.
Ho creato diverse funzioni ciascuna delle quali svolge un compito specifico. In questo modo, il corpo principale del programma è costituito da un semplice ciclo che alterna le mosse del giocatore umano e del computer, e a ogni ciclo verifica se c’è un vincitore, o se sono finite le mosse disponibili.
La prima funzione initialize()
imposta un vettore board[i][j]
che conterrà i valori “X”, “O” e vuoto che descrivono le righe del tabellone di gioco e rappresentano i tre possibili stati di ogni casella: occupata dal giocatore X, occupata dal giocatore O o vuota.
Le funzioni human_move()
e computer_move()
gestiscono le mosse due due giocatori.
Per il giocatore umano, la funzione human_move()
intercetta l’evento pygame.MOUSEBUTTONUP
e legge le coordinate x, y del mouse e le converte nelle coordinate della casella (riga, colonna) del tabellone.
Quindi verifica che la casella sia libera, leggendo il contenuto del vettore board[i][j]
e se la casella è libera aggiorna il valore.
Quindi cambia giocatore e prosegue con la successiva funzione computer_move()
che a sua volta chiama la funzione find_
best
_move()
per scegliere la mossa migliore.
Come far scegliere al computer la mossa migliore
La funzione find_best_move()
la parte più interessante del programma: serve a verificare se esiste una mossa vincente che può essere eseguita nello stato di gioco corrente. Se viene trovata una mossa vincente, la funzione restituisce le coordinate e il giocatore del computer la esegue.
Se non c’è una mossa vincente, la funzione controlla se c’è una mossa che può essere fatta per bloccare la vittoria del giocatore umano. Se viene trovata una mossa bloccante, la funzione restituisce quella mossa e il giocatore del computer la esegue.
Per ottimizzare il codice, ho creato la funzione
in modo che possa cercare sia la mossa vincente sia la mossa bloccante. Vediamo come.find_
best
_move()
La tecnica che ho usato prevede di assegnare dei valori alle caselle:
- Se la casella è occupata dal giocatore umano X –> valore 3
- Se la casella è occupata dal giocatore computer O –> valore 5
- Se la casella è vuota –> valore 1
La funzione
calcola il prodotto di tutte le righe, di tutte le colonne e delle due diagonali e lo confronta con i valori che indicano una imminente mossa vincente (prioritaria) oppure bloccante (seconda scelta).find_
best
_move()
- Se ci sono due O allineate (mossa vincente), il prodotto sarà 5 x 5 = 25
- Se ci sono due X allineate (mossa bloccante), il prodotto sarà 3 x 3 x 1 = 9
Se non c’è né una mossa vincente né una mossa bloccante, la funzione genera una mossa casuale selezionando a caso una cella libera nel tabellone di gioco. La funzione restituisce questa mossa e il giocatore del computer la esegue.
Implementando queste tre fasi, la funzione computer_move()
garantisce che il giocatore del computer esegua sempre una mossa che massimizzi le sue possibilità di vittoria o che minimizzi le possibilità di vittoria del giocatore umano, se non è disponibile una mossa vincente.
La prossima sfida? Retro Coding! 😄
Fare il porting di questo Tetris sul Commodore VIC-20, i suoi soli 3 kbyte di RAM e il suo limitatissimo BASIC 2.0!