Skill Factory
Lista post > Impariamo Python giocando al "Solitario del Ferroviere" - Lezione 5
Impariamo Python giocando al "Solitario del Ferroviere" - Lezione 5
Gino Visciano |
Skill Factory - 06/01/2020 22:33:30 | in Tutorials
Nella lezione precedente abbiamo completato il primo livello del "Solitario del Ferroviere", questo livello è stato creato per gli apprendisti che intendono imparare a giocare, senza grosse difficoltà. La caratteristica principale è quella che sia le carte indovinate, sia quelle non indovinate sono scoperte, in modo da rendere più facile la scelta della carta da pensare, come mostra l'immagine seguente.
In questa lezione completiamo il secondo livello del "Solitario del Ferroviere", creato per i principianti. A differenza del livello precedente, qui sia le carte indovinate, sia quelle non indovinate sono coperte, come mostra l'immagine seguente:
A cosa serve l'icona Help me!
L'icona Help me! segnala al giocatore come ottenere un aiuto per ricordare quali sono le le carte non indovinate.
Cliccando sull'icona Help me! appare la finestra seguente:
Il messaggio di aiuto indica al giocatore come vedere le carte non indovinate:
L'immagine Help me! sparisce automaticamente dopo 5 secondi. Per ottenere questo effetto, sono state utilizzate le funzioni seguenti:
# Disattiva la finestra Help me!
def help_frame_hidden():
global help_show
help_show.place_forget()
# Attiva la finestra Help me!
def help_frame_show(event):
global help_show
help_show=tk.Frame(root)
label_carta_non_indovinata_help_show=tk.Label(help_show, image=immagine_help_show)
label_carta_non_indovinata_help_show.pack()
help_show.place(x=1000,y=60)
suono(11,0.1)
# Dopo 5000 millisecondi (5 secondi) esegue la funzione help_frame_hidden
help_show.after(5000,help_frame_hidden)
Come rendere cliccabile l'icona Help me
L'icona Help me, corrisponde all'immagine seguente:
Per renderla cliccabile è stato utilizzato il codice seguente:
immagine_help=ImageTk.PhotoImage(Image.open('help.png')) # Carica l'immagine dell'icona
label_carta_non_indovinata_help=tk.Label(root, image=immagine_help) # Associa l'immagine dell'icona all'etichetta
label_carta_non_indovinata_help.place(x=1230,y=150) # Visualizza l'etichetta con l'immagine dell'icona sul piano di gioco
# La funzione bind permette di associare all'etichetta l'evento click (<button> ) per eseguire la funzione help_frame_show
label_carta_non_indovinata_help.bind("<Button>",help_frame_show)
Come consultare le carte sbagliate cliccando sul mazzo delle carte non indovinate
Per poter gestire questa funzionalità è stato applicato l'algoritmo seguente:
Inizio (Azione 1)
Mentre clicchi su una carta del mazzo
Se carte del mazzo non indivinate>1 allora
Se non è l'ultima carta del mazzo allora
Se è la prima carta allora
visualizza carta precedente
visualizza retro carta a desta
Altrimenti
visualizza carta precedente
Fine se
Fine se
Fine se
Fine Mentre
Fine
Inizio (Azione 2)
Mentre clicchi sul retro della carta a destra
Se la carte del mazzo visualizzata non è la penultima allora
Visualizza la carta precedente a quella visualizzata
Altrimenti
visualizza la prima carta del mazzo
nascondi il retro della carta a destra
Fine se
Fine Mentre
Fine
label_carta_non_indovinata.bind("<Button>",gira_carta_non_indovinata)
label_carta_non_indovinata_retro.bind("<Button>",gira_carta_non_indovinata_back)
In questo modo, quando si clicca su una carta del mazzo delle carte non indovinate, si attiva la funzione gira_carta_non_indovinata, quando si clicca sul retro, si attiva la funzione gira_carta_non_indovinata_back. Le due funzioni permettono di vedere tutte le carte del mazzo delle carte non indovinate.
# Ad ogni click gira le carte del mazzo e mostra la carta successiva
def gira_carta_non_indovinata(event):
global indice_gira_carta_non_indovinata
if len(mazzo_dx)>1 and indice_gira_carta_non_indovinata>0:
label_carta_non_indovinata_retro.place(x=1175,y=40)
indice_gira_carta_non_indovinata-=1
label_carta_non_indovinata.config(image=immagini_carte[mazzo_dx[indice_gira_carta_non_indovinata]])
label_carta_non_indovinata.place(x=945,y=40)
suono(2,0.1)
else:
suono(6,0.1)
# Ad ogni click gira le carte del mazzo e mostra la carta precedente
def gira_carta_non_indovinata_back(event):
global mazzo_dx
global indice_gira_carta_non_indovinata
if indice_gira_carta_non_indovinata<len(mazzo_dx)-2:
indice_gira_carta_non_indovinata+=1
label_carta_non_indovinata.config(image=immagini_carte[mazzo_dx[indice_gira_carta_non_indovinata]])
label_carta_non_indovinata.place(x=945,y=40)
else:
label_carta_non_indovinata_retro.place_forget()
indice_gira_carta_non_indovinata+=1
label_carta_non_indovinata.config(image=immagini_carte[mazzo_dx[indice_gira_carta_non_indovinata]])
label_carta_non_indovinata.place(x=945,y=40)
suono(1,0.1)
Come ripristinare le carte del mazzo carte non indovinate quando si gira una nuova carta dal mazzo centrale
Quando viene girata una nuova carta dal mazzo centrale, il mazzo delle carte non indovinate deve essere ripristinato, per ottenere questo risultato è stata implementata la funzione seguente:
def ripristina_carte_non_indovinate():
if len(mazzo_dx)>1:
label_carta_non_indovinata_retro.place_forget()
indice_gira_carta_non_indovinata=len(mazzo_dx)-1
label_carta_non_indovinata.config(image=immagini_carte[mazzo_dx[indice_gira_carta_non_indovinata]])
label_carta_non_indovinata.place(x=945,y=40)
Analisi del codice Python
# Solitario del ferroviere (Lezione 4)
import pygame # Importa classe pygame per gestire i suoni
import tkinter as tk # Importa classe tkinter con alias tk per gestire il pannello di gioco
import time # Importa classe time per gestire l'orologio di sistema
import random # Importa classe random che permette di ottenere gli indici casuali usati per mischiare le carte
from PIL import Image, ImageTk # Dalla libreira Pillow importa le classi Image e ImageTk per gestire le immagini del gioco
from tkinter import messagebox # Dalla libreira tkinter importa le classe messagebox usata per creare la finestra modale "GAME OVER"
mazzo_centrale=[1,2,3,4,5,6,7,8,9,10] # Lista con i valori delle carte (mazzo di carte centrale)
mazzo_sx=[] # Lista con i valori delle carte (mazzo di carte indovinate)
mazzo_dx=[] # Lista con i valori delle carte (mazzo di carte non indovinate)
immagini_carte=[] # Lista con i riferimenti delle immagini delle carte
indice_carta_pensata=0
indice_carta_girata=0
indice_gira_carta_non_indovinata=0
time1=0
time_start=0
tentativi=1
score=1000
conta_score=0
flag=True # Abilita (True) e disabilita (False) l'aggiornamento dei secondi e del punteggio
help_show=None # Riferimento della finestra Help me!
# Termina l'applicazione
def esci():
root.quit()
# Ogni 200 millisecondi aggiorna secondi, tentativi, punteggio ed orologio
def tick():
global time1
global time_start
global tentativi
global score
global conta_score
global flag
# legge ora locale del pc
if flag: # Abilita/Disabilita aggiornamento secondi e punteggio
time2 = time.strftime('%H:%M:%S')
if time2 != time1:
time1 = time2
label_clock.config(text=time2)
secondi=int(round(time.time()-time_start,0))
conta_score+=1
if conta_score>10:
score=score-1
conta_score=0
if score>0:
spazi=" "[:(10-len(str(secondi)))]
str_secondi=spazi+str(secondi)+" "
label_secondi.config(text=str_secondi)
spazi=" "[:(10-len(str(tentativi)))]
label_tentativi.config(text=spazi+str(tentativi)+" ")
spazi=" "[:(10-len(str(score)))]
label_score.config(text=spazi+str(score)+" ")
else:
label_score.config(text=" 0 ")
info=messagebox.showinfo('Fine Partita', 'GAME OVER')
esci()
# chiama se stessa (ricorsiva) ogni 200 milliseconds
label_clock.after(200, tick)
# Mischia i valori delle carte del mazzo centrale
def mischia_carte(mazzo):
temp=0
max=len(mazzo)-1
for i in range(1,100):
prima=random.randint(0,max)
seconda=random.randint(0,max)
if prima!=seconda:
temp=mazzo[prima]
mazzo[prima]=mazzo[seconda]
mazzo[seconda]=temp
# Gestisce i suoni e le durate
def suono(sound,tempo):
if sound==1:
pygame.mixer_music.load("Click.wav")
elif sound==2:
pygame.mixer_music.load("PenSound.wav")
elif sound==3:
pygame.mixer_music.load("ToggleSound.wav")
elif sound==4:
pygame.mixer_music.load("TickSound.mp3")
elif sound==5:
pygame.mixer_music.load("ToneSound.wav")
elif sound==6:
pygame.mixer_music.load("PlingSound.wav")
elif sound==7:
pygame.mixer_music.load("OvationSound.wav")
elif sound==8:
pygame.mixer_music.load("ElectronicSound.wav")
elif sound==9:
pygame.mixer_music.load("CardSound.wav")
elif sound==10:
pygame.mixer_music.load("BranchSound.wav")
elif sound==11:
pygame.mixer_music.load("smsalertSound.wav")
elif sound==12:
pygame.mixer_music.load("ComputerSound.wav")
pygame.mixer_music.play()
time.sleep(tempo)
# Carica le immagini delle carte ed aggiunge i riferimenti alla lista immagini_carte
def carica_immagini_carte():
immagini_carte=[]
immagini_carte.append(ImageTk.PhotoImage(Image.open('Carte_Napoletane_retro.png')))
immagini_carte.append(ImageTk.PhotoImage(Image.open('1coppe.png')))
immagini_carte.append(ImageTk.PhotoImage(Image.open('2coppe.png')))
immagini_carte.append(ImageTk.PhotoImage(Image.open('3coppe.png')))
immagini_carte.append(ImageTk.PhotoImage(Image.open('4coppe.png')))
immagini_carte.append(ImageTk.PhotoImage(Image.open('5coppe.png')))
immagini_carte.append(ImageTk.PhotoImage(Image.open('6coppe.png')))
immagini_carte.append(ImageTk.PhotoImage(Image.open('7coppe.png')))
immagini_carte.append(ImageTk.PhotoImage(Image.open('8coppe.png')))
immagini_carte.append(ImageTk.PhotoImage(Image.open('9coppe.png')))
immagini_carte.append(ImageTk.PhotoImage(Image.open('10coppe.png')))
return immagini_carte
# Si attiva quando si clicca sul pulsante gira, alza le carte del mazzo centrale e controlla se la carta alzata è uguale alla carta pensata
def gira():
global indice_carta_girata
global indice_carta_pensata
global indice_gira_carta_non_indovinata
global mazzo_centrale
global flag
ripristina_carte_non_indovinate()
max=len(mazzo_centrale)-1
if indice_carta_pensata==1:
carta_pensata=10
else:
carta_pensata=indice_carta_pensata-1
label_carta_girata.config(image=immagini_carte[mazzo_centrale[indice_carta_girata]])
label_carta_girata.place(x=475,y=40)
girate=" "+str(indice_carta_girata+1)+"/"+str(max+1)+" "
label_girate.config(text=girate)
label_girate.place(x=520,y=370)
if carta_pensata==mazzo_centrale[indice_carta_girata]:
mazzo_sx.append(mazzo_centrale[indice_carta_girata])
indovinate= " "+str(len(mazzo_sx))+" "
if len(mazzo_sx)==10:
indovinate=indovinate[:9]
label_indovinate.config(text=indovinate)
label_indovinate.place(x=765,y=370)
label_carta_indovinata.config(image=immagini_carte[mazzo_centrale[indice_carta_girata]])
label_carta_indovinata.place(x=710,y=40)
suono(5,0.1)
else:
mazzo_dx.append(mazzo_centrale[indice_carta_girata])
indice_gira_carta_non_indovinata=len(mazzo_dx)-1
non_indovinate= " "+str(len(mazzo_dx))+" "
if len(mazzo_dx)==10:
non_indovinate=non_indovinate[:9]
label_non_indovinate.config(text=non_indovinate)
label_non_indovinate.place(x=1000,y=370)
label_carta_non_indovinata.config(image=immagini_carte[mazzo_centrale[indice_carta_girata]])
label_carta_non_indovinata.place(x=945,y=40)
suono(3,0.1)
if indice_carta_girata<max:
indice_carta_girata=indice_carta_girata+1
else:
label_carte_da_indovinare.place_forget()
label_carta_girata.place_forget()
pulsante_gira.place_forget()
label_girate.place_forget()
indice_carta_girata=0
if(len(mazzo_dx)>0):
suono(8,0.5)
pulsante_mischia.place(x=290,y=370)
else:
suono(7,0.3)
pulsante_nuova_partita.place(x=290,y=370)
flag=False
# Si attiva quando si clicca sul pulsante cambia, permette di scegliere la carta pensata
def cambia():
global indice_carta_pensata
label_carta_pensata.config(image=immagini_carte[indice_carta_pensata])
label_carta_pensata.place(x=5,y=40)
if indice_carta_pensata<10:
indice_carta_pensata=indice_carta_pensata+1
else:
indice_carta_pensata=1
suono(4,0.1)
# Si attiva quando si clicca sul pulsante mischia, avvia tutta la procedura per mischiare le carte
def mischia():
global mazzo_centrale
global indice_carta_pensata
global tentativi
global score
suono(9,4)
tentativi=tentativi+1
score=int(score/2)
mazzo_centrale.clear()
mazzo_centrale=mazzo_dx[:]
ripristina_carte_non_indovinate()
mazzo_dx.clear()
mischia_carte(mazzo_centrale)
label_carta_girata.place_forget()
label_carta_non_indovinata.place_forget()
label_carta_pensata.config(image=immagini_carte[1])
indice_carta_pensata=2
label_carta_girata.config(image=immagini_carte[0])
label_carte_da_indovinare.place(x=245,y=40)
label_non_indovinate.config(text=" 0 ")
label_non_indovinate.place(x=1000,y=370)
girate=" 0/"+str(len(mazzo_centrale))+" "
label_girate.config(text=girate)
label_girate.place(x=520,y=370)
pulsante_gira.place(x=290,y=370)
pulsante_mischia.place_forget()
# Si attiva quando si clicca sul pulsante nuova_partita, avvia tutta la procedura per iniziare una nuova partita
def nuova_partita():
global mazzo_dx
global mazzo_sx
global mazzo_centrale
global indice_carta_pensata
global indice_carta_girata
global indice_gira_carta_non_indovinata
global tentativi
global score
global conta_score
global time_start
global flag
mazzo_centrale=[1,2,3,4,5,6,7,8,9,10]
mazzo_sx=[]
ripristina_carte_non_indovinate()
mazzo_dx=[]
indice_carta_pensata=0
indice_carta_girata=0
indice_gira_carta_non_indovinata=0
tentativi=1
score=1000
conta_score=0
flag=True
time_start=time.time()
label_carta_indovinata.place_forget()
label_carta_non_indovinata.place_forget()
label_carta_girata.place_forget()
label_carta_pensata.config(image=immagini_carte[1])
indice_carta_pensata=2
label_carta_girata.config(image=immagini_carte[0])
label_carte_da_indovinare.place(x=245,y=40)
label_indovinate.config(text=" 0 ")
label_indovinate.place(x=765,y=370)
label_non_indovinate.config(text=" 0 ")
label_non_indovinate.place(x=1000,y=370)
girate=" 0/"+str(len(mazzo_centrale))+" "
label_girate.config(text=girate)
label_girate.place(x=520,y=370)
pulsante_gira.place(x=290,y=370)
pulsante_nuova_partita.place_forget()
mischia_carte(mazzo_centrale)
suono(12,2.5)
# Si attiva quando si clicca sulla carta del mazzo carte non indovinate, mostra la carta precedente se disponibile
def gira_carta_non_indovinata(event):
global indice_gira_carta_non_indovinata
if len(mazzo_dx)>1 and indice_gira_carta_non_indovinata>0:
label_carta_non_indovinata_retro.place(x=1175,y=40)
indice_gira_carta_non_indovinata-=1
label_carta_non_indovinata.config(image=immagini_carte[mazzo_dx[indice_gira_carta_non_indovinata]])
label_carta_non_indovinata.place(x=945,y=40)
suono(2,0.1)
else:
suono(6,0.1)
# Si attiva quando si clicca sul retro di una carta del mazzo carte non indovinate, riscopre le carte girate
def gira_carta_non_indovinata_back(event):
global mazzo_dx
global indice_gira_carta_non_indovinata
if indice_gira_carta_non_indovinata<len(mazzo_dx)-2:
indice_gira_carta_non_indovinata+=1
label_carta_non_indovinata.config(image=immagini_carte[mazzo_dx[indice_gira_carta_non_indovinata]])
label_carta_non_indovinata.place(x=945,y=40)
else:
label_carta_non_indovinata_retro.place_forget()
indice_gira_carta_non_indovinata+=1
label_carta_non_indovinata.config(image=immagini_carte[mazzo_dx[indice_gira_carta_non_indovinata]])
label_carta_non_indovinata.place(x=945,y=40)
suono(1,0.1)
def ripristina_carte_non_indovinate():
if len(mazzo_dx)>1:
label_carta_non_indovinata_retro.place_forget()
indice_gira_carta_non_indovinata=len(mazzo_dx)-1
label_carta_non_indovinata.config(image=immagini_carte[mazzo_dx[indice_gira_carta_non_indovinata]])
label_carta_non_indovinata.place(x=945,y=40)
# Disattiva la finestra Help me!
def help_frame_hidden():
global help_show
help_show.place_forget()
# Attiva la finestra Help me!
def help_frame_show(event):
global help_show
help_show=tk.Frame(root)
label_carta_non_indovinata_help_show=tk.Label(help_show, image=immagine_help_show)
label_carta_non_indovinata_help_show.pack()
help_show.place(x=1000,y=60)
suono(11,0.1)
help_show.after(5000,help_frame_hidden)
# Inizia una nuova partita
def start():
global indice_carta_pensata
global indice_carta_girata
global time_start
pulsante_gira.place(x=290,y=370)
pulsante_cambia.place(x=60,y=370)
label_titolo_carta_pensata.place(x=25,y=5)
label_carta_pensata.place(x=5,y=40)
label_carte_da_indovinare.place(x=245,y=40)
label_titolo_carta_da_indovinare.place(x=230,y=5)
label_titolo_carte_indovinate.place(x=710,y=5)
label_titolo_carte_non_indovinate.place(x=920,y=5)
label_girate.place(x=520,y=370)
label_indovinate.place(x=765, y=370)
label_non_indovinate.place(x=1000, y=370)
label_clock.place(x=1300,y=5)
if time_start==0:
time_start = time.time()
label_titolo_tempo.place(x=30,y=490)
label_secondi.place(x=30,y=515)
label_tentativi.place(x=160,y=515)
label_titolo_tentativi.place(x=160,y=490)
label_titolo_score.place(x=280,y=490)
label_score.place(x=280,y=515)
pygame.init()
indice_carta_pensata=2
indice_carta_girata=0
# Preparazione pannello di gioco
root = tk.Tk()
root.wm_title('Solitario del ferroviere')
root.geometry("1400x600")
root.resizable(False, False)
immagine_help=ImageTk.PhotoImage(Image.open('help.png'))
label_carta_non_indovinata_help=tk.Label(root, image=immagine_help)
immagine_help_show=ImageTk.PhotoImage(Image.open('help_show.png'))
pulsante_gira=tk.Button(root,text="GIRA", width=10, height=2, bd = 3,command=gira, bg="teal",font=("Helvetica", 12))
pulsante_cambia=tk.Button(root,text="CAMBIA", width=10, height=2, bd = 3,command=cambia, bg="seagreen",font=("Helvetica", 12))
pulsante_mischia=tk.Button(root,text="MISCHIA", width=10, height=2, bd = 3,command=mischia, bg="mediumpurple",font=("Helvetica", 12))
pulsante_nuova_partita=tk.Button(root,text="NUOVA PARTITA", width=15, height=2, bd = 3,command=nuova_partita, bg="darkorange",font=("Helvetica", 12))
label_titolo_carta_pensata=tk.Label(root, text="CARTA PENSATA",font=("Helvetica", 14))
label_titolo_carta_da_indovinare=tk.Label(root, text="CARTE DA INDOVINARE",font=("Helvetica", 14))
label_titolo_carte_indovinate=tk.Label(root, text="CARTE INDOVINATE",font=("Helvetica", 14),fg="green")
label_titolo_carte_non_indovinate=tk.Label(root, text="CARTE NON INDOVINATE",font=("Helvetica", 14),fg="red")
label_titolo_tempo=tk.Label(root, text="TEMPO",font=("times", 12,"italic"),fg="black")
label_titolo_tentativi=tk.Label(root, text="TENTATIVI",font=("times", 12,"italic"),fg="black")
label_titolo_score=tk.Label(root, text="SCORE",font=("times", 12,"italic"),fg="black")
label_indovinate=tk.Label(root, text=" 0 ",font=("Helvetica", 25),fg="white",bg="green")
label_powered_sf=tk.Label(root, text="2020 - Powered by Skill Factory",font=("times", 14,'italic'))
label_non_indovinate=tk.Label(root, text=" 0 ",font=("Helvetica", 25),fg="white",bg="red")
label_girate=tk.Label(root, text=" 0/10 ",font=("Helvetica", 25),fg="white",bg="tomato")
label_clock = tk.Label(root, font=('arial', 16, 'italic'), bg='darkgray',fg='black')
label_secondi=tk.Label(root, font=('arial', 16, 'normal'), bg='blue',fg='white')
label_tentativi=tk.Label(root, font=('arial', 16, 'normal'), bg='orange',fg='white')
label_score=tk.Label(root, font=('arial', 16, 'normal'), bg='palevioletred',fg='white')
immagini_carte=carica_immagini_carte()
logo=ImageTk.PhotoImage(Image.open('logo_sf.png'))
label_logo=tk.Label(root, image=logo)
label_carta_pensata=tk.Label(root, image=immagini_carte[1])
label_carte_da_indovinare=tk.Label(root, image=immagini_carte[0])
label_carta_girata=tk.Label(root, image=immagini_carte[0])
label_carta_indovinata=tk.Label(root, image=immagini_carte[0])
label_carta_non_indovinata=tk.Label(root, image=immagini_carte[0])
label_carta_non_indovinata.bind("<Button>",gira_carta_non_indovinata)
label_carta_non_indovinata_retro=tk.Label(root, image=immagini_carte[0])
label_carta_non_indovinata_retro.bind("<Button>",gira_carta_non_indovinata_back)
label_powered_sf.place(x=550,y=557)
label_logo.place(x=805,y=545)
label_carta_non_indovinata_help.place(x=1230,y=150)
label_carta_non_indovinata_help.bind("<Button>",help_frame_show)
tick()
start()
mischia_carte(mazzo_centrale)
root.mainloop()
Nella prossima lezione implementeremo le funzionalità per creare il terzo livello di difficoltà del "Solitario del Ferroviere", creato per gli esperti. Per questo livello di gioco non è previsto nessun aiuto, dipende tutto dalla capacità del giocatore che deve ricordare tutte le carte indovinate e non indovinate.
Arrivederci ...
<< Lezione precedente Lezione successiva >>
Per scaricare le risorse di questa lezione clicca sul link seguente:risorse_lezione_05