Gioco del Tris
Usiamo come caso di studio il gioco del tris (Tic Tac Toe, in inglese).
Creazione della board di gioco
Il tabellone di gioco (board) del tris è formato da 3 righe e 3 colonne. Possiamo rappresentarlo con una matrice 3x3.
In Python possiamo creare una matrice così:
board = [
['-','-','-'],
['-','-','-'],
['-','-','-']
]
Come vedete, nella dichiarazione della variabile non è necessario specificare la dimensione, perché viene automaticamente inferita dal valore assegnato.
Per stampare a schermo lo stato del tabellone, possiamo scrivere un doppio ciclo che va da uno a tre:
for i in range(3):
for j in range(3):
print(board[i][j], end=" ")
print()
La funzione range(n)
permette di iterare tra ed 0 e n-1; in questo caso quindi i
e j
assumeranno i valori da 0 a 2.
range(n)
può essere usato per iterare in molti altri modi, vedi qui per maggiori dettagli.
Mettiamo questo doppio ciclo all'interno di una funzione, in modo da poterlo richiamare quando ci è necessario.
# definisco la funzione
def mostra_tabellone():
for i in range(3):
for j in range(3):
print(board[i][j], end=" ")
print()
# richiamo la funzione
mostra_tabellone()
Notare come tutto quello che appartiene alla funzione è indentato al suo interno, mentre ciò che non ne fa parte non ha nessuna indentazione.
Ricordiamo anche che è buona norma che le funzioni comincino con un verbo, in quanto rappresentano delle azioni.
Richiesta di un valore in input
Per chiedere un valore in modo interattivo in input all'utente, si può usare la funzione input()
.
Ad esempio per chiedere la riga in cui inserire il proprio segno nel tabellone, potremmo scrivere:
r = input("Inserisci la riga (valori da 0 a 2): ")
Attenzione però: la funzione input()
ritorna una stringa, mentre noi vorremmo avere un intero. Per convertire da stringa ad intero, possiamo usare la funzione int()
:
r = int(input("Inserisci la riga (valori da 0 a 2): "))
Analogamente per la colonna. Complessivamente:
r = int(input("Inserisci la riga (valori da 0 a 2): "))
c = int(input("Inserisici la colonna (valori da 0 a 2): "))
Inserire i simboli nel tabellone
Per inserire il simbolo di un giocatore è sufficiente assegnare il carattere nel giusto elemento della variabile tabellone:
board[r][c] = symbol
Vogliamo ripetere questa operazione finché il tabellone non è pieno oppure finché qualcuno non ha vinto. Creiamo un ciclo viene essere eseguito 9 volte.
for idx in range(9):
mostra_tabellone()
r = int(input("Inserisci la riga (valori da 0 a 2): "))
c = int(input("Inserisici la colonna (valori da 0 a 2): "))
# aggiungere anche condizione che r,c devono essere compresi tra 0 e 2
if board[r][c]=='-':
board[r][c] = 'O'
In questo modo però stiamo assegnando sempre il simbolo 'O' , che ovviamente non è quello che vogliamo: vogliamo alternare i simboli 'X' e 'O'. Possiamo fare in modo che per idx
pari mettiamo un simbolo, e per i dispari l'altro. Per fare questo possiamo creare una lista con i due simboli, ed assegnare il simbolo in base all'indice, come di seguito.
symList = ['X','O']
for idx in range(9):
symbol = symList[idx%2]
mostra_tabellone()
print("Il tuo simbolo è: "+symbol)
r = int(input("Inserisci la riga (valori da 0 a 2): "))
c = int(input("Inserisici la colonna (valori da 0 a 2): "))
# aggiungere anche condizione che r,c devono essere compresi tra 0 e 2
if board[r][c]=='-':
board[r][c] = symbol
Abbiamo utilizzato l'operatore modulo (%
), che ritorna il resto di una divisione; siccome stiamo dividendo per due, il resto potrà essere solamente 0
o 1
, quindi non potrà mai succedere che esco fuori dall'array symList
che ha esattamente due elementi.
Con questa soluzione riusciamo ad evitare di inserire un if
. In generale è una buona regola di programmazione ridurre il numero di condizioni, sia perché di solito facilita la lettura (le condizioni sono spesso faticose da interpretare), sia perché il codice è più facile da testare. Ovviamente è solo un suggerimento da usare in base al proprio giudizio, non un obbligo.
Controllo dei valori di ingresso
È importante controllare sempre i valori di ingresso forniti dall'utente, per rendere il codice più robusto.
Per fare questo, ci serve un ciclo che chiede all'infinito i valori di input finché questi non sono corretti. Per uscire da un ciclo si usa la parola chiave break
.
# while True esegue un ciclo infinito
while True:
r = int(input("Inserisci la riga (valori da 0 a 2): "))
c = int(input("Inserisici la colonna (valori da 0 a 2): "))
# aggiungere anche condizione che r,c devono essere compresi tra 0 e 2
if board[r][c]=='-':
board[r][c] = symbol
# break esce dal ciclo
break
Controllo della condizione di vittoria
Creiamo una funzione che controlla se qualcuno ha vinto.
Vogliamo creare una funzione che ritorni False
nel caso in cui nessuno ha vinto, altrimenti il simbolo del vincitore.
Esistono diversi modi per realizzare questa funzione. Qui ne presento una, ma ce ne sono molte altre altrettanto valide, anche senza usare cicli for
.
def win(board):
# ripete il controllo per ogni giocatore
for sym in symList:
# controlla se ci sono 3 simboli uguali in una riga
for i in range(3):
if board[i].count(sym)==3:
return sym
# controlla se ci sono 3 simboli uguali in una colonna
for i in range(3):
if (board[0][i]==sym and
board[1][i]==sym and
board[2][i]==sym):
return sym
# controlla le due diagonali
if (board[0][0]==sym and
board[1][1]==sym and
board[2][2]==sym):
return sym
if (board[0][2]==sym and
board[1][1]==sym and
board[2][0]==sym):
return sym
return False
Codice finale
#!/usr/bin/env python3
print("Gioco del tic tac toe")
board = [
['-','-','-'],
['-','-','-'],
['-','-','-']
]
symList = ['X','O']
def mostra_tabellone():
for i in range(3):
for j in range(3):
print(board[i][j], end=" ")
print()
def win(board):
for sym in symList:
#check rows
for i in range(3):
if board[i].count(sym)==3:
return sym
#check columns
for i in range(3):
if (board[0][i]==sym and
board[1][i]==sym and
board[2][i]==sym):
return sym
# check diagonals
if (board[0][0]==sym and
board[1][1]==sym and
board[2][2]==sym):
return sym
if (board[0][2]==sym and
board[1][1]==sym and
board[2][0]==sym):
return sym
return False
winner=False
for idx in range(9):
symbol = symList[idx%2]
mostra_tabellone()
print("Il tuo simbolo è: "+symbol)
while True:
r = int(input("Inserisci la riga (valori da 0 a 2): "))
c = int(input("Inserisici la colonna (valori da 0 a 2): "))
# aggiungere anche condizione che r,c devono essere compresi tra 0 e 2
if board[r][c]=='-':
board[r][c] = symbol
break
winner=win()
if winner:
break
mostra_tabellone()
print("The winner is... "+winner+"!")