Tabella dei contenuti: Mostra/Chiudi
Ciao e benvenuto, Uno degli esempi di programmi python più diffusi per fare pratica è quello dell'impiccato. in questo progetto andremo quindi a scrivere il gioco dell'impiccato con il linguaggio di programmazione python.
Iniziamo subito ad analizzare il problema che dobbiamo risolvere.
Come ben sai nell'impiccato una persona deve indovinare una parola che l'avversario ha scelto(nel nostro caso sarà il computer), per farlo dovrà proporre ad ogni turno una lettera, se è presente nella parola allora verrà essa visualizzata, altrimenti il giocatore perderà una vita.
Possiamo suddividere quindi questo esercizio in 3 macro funzioni:
- Generare una parola, ovvero quella che il giocatore dovrà indovinare;
- Gestire la mossa del giocatore;
- Gestire i tentativi a disposizione del giocatore e determinare se la partita è persa o vinta.
Ottenere una parola casuale
Andiamo quindi subito a far scegliere al computer la parola che in seguito dovremo indovinare.
Per farlo potremmo banalmente assegnare una stringa ad una variabile ed utilizzarla per il nostro gioco in questo modo: parola_da_indovinare = "pluto"
.
Tuttavia così facendo, la parola sarà sempre la stessa e ne saremo a conoscenza rendendo privo di senso il gioco.
Come possiamo quindi, fare in modo che ad ogni esecuzione del programma, venga assegnata automaticamente alla nostra variabile una stringa diversa?
Beh potremmo creare una lista, ovvero una sequenza di elementi, che conterrà tutte le parole che vogliamo, e come vedremo tra poco, ottenere una parola casuale da esso ogni volta che il nostro programma verrà avviato.
Prendiamo per esempio questa lista: lista_di_parole = ["pythonpertutti", "casa", "sole", "ananas"]
, potremmo fare in modo che ad ogni avvio del nostro script, verrà assegnata una parola casuale tra quelle presenti nella lista alla nostra variabile.
La libreria random
Devi sapere che è possibile ottenere gli elementi di una lista tramite un indice che parte da 0 fino alla lunghezza della lista - 1. Quindi se per esempio volessi ottenere il secondo elemento di una lista dovrei procedere in questo modo:
lista_di_parole = ["pythonpertutti", "casa", "sole", "ananas"]
secondo_elemento = lista_di_parole[1]
print(secondo_elemento)
Ora se trovassimo il modo di poter generare in modo casuale un numero intero, compreso tra 0 e la lunghezza della nostra lista(-1), otterremo un numero che potremmo utilizzare come indice per la nostra lista e di conseguenza otterremo un elemento a caso dalla lista.
In questo caso ci viene in aiuto una libreria di Python, ovvero un insieme di funzioni già scritte e pronte all'uso. La libreria in questione si chiama random. Per importarlo scriviamo la seguente istruzione all'inizio del nostro file: import random.
La funzione Randint
Tra le numerose funzionalità che questa libreria ci offre, troviamo la funzione randint(), che ci permette appunto, dato un intervallo, di generare un numero intero casuale.
import random
lista_di_parole = ["pythonpertutti", "casa", "sole", "ananas"]
indice_casuale = random.randint(0, 3)
parola_da_indovinare = lista_di_parole[indice_casuale]
print(parola_da_indovinare)
Ecco quindi che abbiamo la possibilità di ottenere un elemento casuale all'interno di una nostra lista.
Giusto un piccolo accorgimento, come avrai notato, per ottenere il nostro indice casuale, nell'intervallo ho scritto il numero 3
(ovvero la lunghezza della nostra lista - 1); attualmente funziona correttamente, ma se la lunghezza della nostra lista dovesse cambiare, il nostro numero non sarà più affidabile. Possiamo però ottenere la lunghezza della nostra lista con una semplice funzione: len(lista)
.
Andiamo subito ad applicarlo al nostro programma:
import random
lista_di_parole = ["pythonpertutti", "casa", "sole", "ananas"]
lunghezza = len(lista_di_parole)
indice_casuale = random.randint(0, lunghezza)
parola_da_indovinare = lista_di_parole[indice_casuale]
print(parola_da_indovinare)
La funzione choice
In alternativa alla funzione randint()
, la libreria random ci offre la funzione choice()
, la quale ci restituisce direttamente un elemento casuale della nostra lista, senza preoccuparci di dover generare un indice casuale.
import random
lista_di_parole = ["pythonpertutti", "casa", "sole", "ananas"]
parola_da_indovinare = random.choice(lista_di_parole)
print(parola_da_indovinare)
Importare le parole da file di testo
Se volessimo rendere più varia e grande la nostra lista di parole da indovinare, potremmo fare in modo di prendere le parole da un file esterno, come potrebbe essere un file di testo contenente numerose parole. Creiamo per esempio un file di testo con estensione .txt
e scriviamo una parola per riga(su internet puoi trovare anche direttamente dei file di testo con numerose parole, accertati però che siano una per riga).
Con python fare tutto ciò è molto semplice, inizia quindi spostando il file che hai scaricato nella stessa cartella in cui è presente il tuo progetto.
Torniamo ora al nostro programma, vediamo subito come far aprire il nostro file di testo con il nostro linguaggio di programmazione, e leggerne il contenuto:
lista_di_parole = []
with open('nome_file.txt', 'r') as f:
for line in f:
parola = line.rstrip('\n')
lista_di_parole.append(parola)
La funzione open()
ci consente di aprire un file, come parametri vuole appunto il nome del file da aprire, e la modalità con cui farlo, ovvero se in scrittura/lettura o entrambe. In questo caso ho deciso di aprirlo solamente in modalità lettura 'r'
.
La variabile f
contiene tutte le parole del nostro file, e per andare a leggere riga per riga ho dovuto effettuare un ciclo for. Per evitare problemi ho utilizzato il metodo rstrip('\n')
per rimuovere eventuali caratteri di a capo in modo da ottenere la parola pulita.
Riordiniamo il codice
Ottimo ora che tutto il nostro codice funziona correttamente, andiamo ad organizzarlo meglio, suddividendolo in funzioni.
Per rendere il tutto più chiaro e modulare andrei a creare due funzioni: una che si occupa di caricare la nostra lista, e l'altra si occuperà di generarci la nostra parola casuale:
import random
def carica_parole():
lista_di_parole = []
with open('nome_file.txt', 'r') as f:
for line in f:
parola = line.rstrip('\n')
lista_di_parole.append(parola)
return lista_di_parole
def parola_random(lista_di_parole):
return random.choice(lista_di_parole)
lista_di_parole = carica_parole()
parola_da_indovinare = parola_random(lista_di_parole)
lettere_indovinate = ['_' for lettera in parola_da_indovinare]
print(lettere_indovinate)
Tenere traccia di ogni lettera indovinata dall'utente
Per tener traccia di ogni lettera indovinata dall'utente e poterla confrontare con la parola da indovinare in modo da determinare la vittoria o meno della partita, possiamo utilizzare una lista in questo modo:
Potremmo creare una lista di lunghezza uguale alla parola da indovinare, dove ogni elemento corrisponderà ad ogni lettera della parola.
Inizialmente tutte le lettere avranno come valore un trattino '_'
che starà ad indicare appunto le lettere ancora non indovinate. Per esempio supponendo che la nostra parola sia casa
, la nostra lista avrà inizialmente i seguenti valori ["_", "_", "_", "_"]
. In seguito, se, per esempio, l'utente dovesse inserire la lettera a
, la nostra lista diventerà così: ["_", "a", "_", "a"]
.
Ogni volta che l’utente inserirà una lettera presente nella parola, andremo ad ottenere la sua posizione(l’indice) nella parola.
Dato che la lunghezza della parola da indovinare, e la lunghezza della lista che abbiamo creato è uguale, utilizzeremo quell'indice per accedere all'elemento corrispondente della nostra lista e sostituiremo il trattino '_'
con la lettera inserita dall'utente.
Anche se non ti sembrerà chiarissimo questo ragionamento prova a seguirmi e vedrai che passo passo capirai tutto.
Creare la lista delle parole indovinate
Creiamo la nostra lista che inizialmente sarà vuota e andiamo a popolarla tanti trattini quanto è lunga la parola. Per aggiungere un elemento ad una lista basta scrivere il nome della lista.append e l’elemento tra parentesi.
lettere_indovinate = []
for lettera in parola_da_indovinare:
lettere_indovinate.append('_')
print(lettere_indovinate, parola)
Utilizzando la list comprehension possiamo riscrivere la stessa cosa in un riga:
lettere_indovinate = ['_' for lettera in parola_da_indovinare]
print(lettere_indovinate, parola)
Ottenere le lettere dall'utente
Ora che abbiamo inizializzato la nostra lista dove verranno visualizzate le parole indovinate dal nostro giocatore, andiamo ad ottenere l'input del nostro utente e verificare se la lettera inserita è presente o meno nella parola scelta dal computer!
Riprendiamo inanzitutto il codice completo fino ad ora:
import random
def carica_parole():
lista_di_parole = []
with open('nome_file.txt', 'r') as f:
for line in f:
parola = line.rstrip('\n')
lista_di_parole.append(parola)
return lista_di_parole
def parola_random(lista_di_parole):
return random.choice(lista_di_parole)
lista_di_parole = carica_parole()
parola_da_indovinare = parola_random(lista_di_parole)
lettere_indovinate = ['_' for lettera in parola_da_indovinare]
print(lettere_indovinate)
Dato che l'impiccato è un gioco a turni, non dovremmo chiedere una sola volta la lettera all'utente, bensì fino a quando il giocatore non indovinerà la parola o perderà tutte le vite a disposizione.
Per farlo dobbiamo creare un ciclo while e al suo interno chiederemo all'utente una lettera.
while True:
scelta = input("Inserisci una lettera -> ")
if scelta in parola_da_indovinare:
for i, lettera in enumerate(parola_da_indovinare):
if lettera == scelta:
lettere_indovinate[i] = lettera
else:
print("lettera non presente")
print(lettere_indovinate)
Come detto in precedenza, una volta che ho l'input dell'utente, verifico se la lettera ottenuta è presente nella parola, se lo è allora ottengo l'indice in cui si trova la lettera e sostituisco il '_'
presente nella lista lettere_indovinate
con la lettera digitata dal giocatore.
Nel caso la lettera non fosse nella parola allora andremo a togliere una vita al giocatore, momentaneamente stampa semplicemente a schermo una scritta, ma nella prossima parte di questo progetto andremo proprio a gestire tutta la parte che riguarda la vittoria e la sconfitta del giocatore.
Infine andrei a riorganizzare meglio il codice creando un altro paio di funzioni: una che si occuperà di sostiuire i '_'
con la lettera dell'utente, l'altra di visualizzare meglio la lista delle lettere indovinate:
import random
def carica_parole():
lista_di_parole = []
with open('nome_file.txt', 'r') as f:
for line in f:
parola = line.rstrip('\n')
lista_di_parole.append(parola)
return lista_di_parole
def parola_random(lista_di_parole):
return random.choice(lista_di_parole)
def visualizza_parola(lista_lettere):
print(' '.join(lettera for lettera in lista_lettere))
def aggiorna_lettere_indovinate(parola, scelta, lettere_indovinate):
for i, lettera in enumerate(parola):
if lettera == scelta:
lettere_indovinate[i] = lettera
return lettere_indovinate
lista_di_parole = carica_parole()
parola_da_indovinare = parola_random(lista_di_parole)
lettere_indovinate = ['_' for lettera in parola_da_indovinare]
visualizza_parola(lettere_indovinate)
while True:
scelta = input("Inserisci una lettera -> ")
if scelta in parola_da_indovinare:
lettere_indovinate = aggiorna_lettere_indovinate(parola_da_indovinare, scelta, lettere_indovinate)
else:
print("lettera non presente")
visualizza_parola(lettere_indovinate)
Gestire i tentativi disponibili dall'utente
Andiamo ora a vedere come creare un sistema che ci permette di controllare la vita del nostro utente.
Nell'impiccato ad ogni lettera sbagliata viene disegnato un pezzo del patibolo, fino ad arrivare ad avere il disegno completo dell'omino impiccato.
Tutto ciò possiamo farlo anche in python grazie ai generatori!
Ci basta creare un generatore che ogni volta che viene chiamato, restituisce una stringa sempre più completa del nostro patibolo:
def show_player_life():
life = """
---
"""
yield life
life = """
|----
|
|
|
|
---
"""
yield life
life = """
|----0
| |
| |
| |
| |
---
"""
yield life
life = """
|----O
| |
| /|\
| |
| |
---
"""
yield life
life = """
|----O
| |
| /|\
| |
| /|\
---
"""
yield life
life = """
|--\
| \O
| |
| /|\
| |
--- /|\
"""
yield life
Perfetto! adesso andiamo a chiamare il nostro generatore ogni volta che l'utente sbaglia una lettera.
lista_di_parole = carica_parole()
parola_da_indovinare = parola_random(lista_di_parole)
lettere_indovinate = ['_' for lettera in parola_da_indovinare]
vita_giocatore = show_player_life()
visualizza_parola(lettere_indovinate)
while True:
scelta = input("Inserisci una lettera -> ")
if scelta in parola_da_indovinare:
lettere_indovinate = aggiorna_lettere_indovinate(parola_da_indovinare, scelta, lettere_indovinate)
else:
print(next(vita_giocatore))
visualizza_parola(lettere_indovinate)
Determinare il risultato della partita
Come puoi notare ora quando arriviamo al sesto tentativo errato, il programma solleva un eccezione di tipo StopIteration
, il che è normale perché il nostro generatore ha finito elementi da iterare, perciò andiamo a gestire questo errore con un try/catch, visualizzando un messaggio di sconfitta e uscendo dal ciclo while nel caso si verificasse un errore:
try:
print(next(vita_giocatore))
except StopIteration:
print("Hai perso, la parola era: {0}".format(parola_da_indovinare))
break
Nel caso invece l'utente dovesse andare a scegliere l'ultima lettera rimanente da indovinare, dobbiamo visualizzare un messaggio di vittoria e uscire dal ciclo while, in questo modo ad esempio:
scelta = input("Inserisci una lettera -> ")
if scelta in parola_da_indovinare:
lettere_indovinate = aggiorna_lettere_indovinate(parola_da_indovinare, scelta, lettere_indovinate)
if parola_da_indovinare == ''.join(lettera for lettera in lettere_indovinate):
print("Hai vinto, complimenti! La parola è: {0}".format(parola_da_indovinare))
break
Ecco quindi il nostro bellissimo gioco dell'impiccato completamente funzionante!
Codice completo
import random
def carica_parole():
lista_di_parole = []
with open('nome_file.txt', 'r') as f:
for line in f:
parola = line.rstrip('\n')
lista_di_parole.append(parola)
return lista_di_parole
def parola_random(lista_di_parole):
return random.choice(lista_di_parole)
def visualizza_parola(lista_lettere):
print(' '.join(lettera for lettera in lista_lettere))
def aggiorna_lettere_indovinate(parola, scelta, lettere_indovinate):
for i, lettera in enumerate(parola):
if lettera == scelta:
lettere_indovinate[i] = lettera
return lettere_indovinate
def show_player_life():
life = """
---
"""
yield life
life = """
|----
|
|
|
|
---
"""
yield life
life = """
|----0
| |
| |
| |
| |
---
"""
yield life
life = """
|----O
| |
| /|\
| |
| |
---
"""
yield life
life = """
|----O
| |
| /|\
| |
| /|\
---
"""
yield life
life = """
|--\
| \O
| |
| /|\
| |
--- /|\
"""
yield life
lista_di_parole = carica_parole()
parola_da_indovinare = parola_random(lista_di_parole)
lettere_indovinate = ['_' for lettera in parola_da_indovinare]
vita_giocatore = show_player_life()
visualizza_parola(lettere_indovinate)
while True:
scelta = input("Inserisci una lettera -> ")
if scelta in parola_da_indovinare:
lettere_indovinate = aggiorna_lettere_indovinate(parola_da_indovinare, scelta, lettere_indovinate)
if parola_da_indovinare == ''.join(lettera for lettera in lettere_indovinate):
print("Hai vinto, complimenti! La parola è: {0}".format(parola_da_indovinare))
break
else:
try:
print(next(vita_giocatore))
except StopIteration:
print("Hai perso, la parola era: {0}".format(parola_da_indovinare))
break
visualizza_parola(lettere_indovinate)
Funzionalità da aggiungere
Ora tocca a te! ci sono un bel po di modifiche che potresti apportare a questo giochino. Una tra queste potrebbe essere quella di implementare un interfaccia grafica, oppure salvare in un database tutti i risultati delle partite giocate in modo da poter visualizzare statistiche varie.
Insomma, dai sfogo alla tua creatività e buona programmazione!