Skill Factory
Tutte le categorie
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
Impariamo Python giocando al "Solitario del Ferroviere" - Lezione 4
Gino Visciano |
Skill Factory - 01/01/2020 21:44:25 | in Tutorials
Nella quarta lezione creiamo il primo livello del "Solitario del Ferroviere" con cui realmente potete iniziare a giocare, con questo livello di difficoltà è più semplice giocare perché le carte indovinate e quelle non indovinate sono scoperte, in modo da rendere più facile la scelta della carta da pensare, come mostra l'immagine seguente.
Il pulsante cambia, come abbiamo visto nella prima lezione, permette di scegliere la carta da pensare, mentre il pulsante gira, come abbiamo visto nella seconda lezione e nella terza lezione permette di girare le carte del mazzo. Quando la carta pensata è uguale alla carta girata, l'immagine small della carta indovinata viene aggiunta in corrispondenza del cerchio verde, altrimenti viene aggiunta in corrispondenza del cerchio rosso.
Quando le carte da girare finiscono, se ci sono carte non indovinate, è possibie mischiare e riprendere il gioco, come mostra l'immagine seguente.
Il gioco finisce quando s'indovinano tutte le carte, in quel caso è possibile iniziare una nuova partita, come mostra l'immagine seguente.
Col passare del tempo i punti diminuiscono ed ogni volta che le carte vengono mischiate il punteggio si dimezza. Se il punteggio arriva a 0 senza aver completato il solitario, appare la finestra modale (modale=impedisce qualunque operazione e permette solo di uscire), "GAME OVER" che indica la fine del gioco, come mostra l'immagine seguente.
Come aggiornare il punteggio
Il punteggio (score) all'inizio del gioco vale 1000, questo valore si decrementa di uno ogni 10 secondi e viene dimezzato ogni volta che si mischiano le carte.
Per gestire l'aggiornamento del punteggio è stata utilizzata la funzione tick() che viene eseguita ogni 200 millisecondi:
# chiama la funzione tick ogni 200 millisecondi
label_clock.after(200, tick)
Per decrementare il punteggio ogni 10 secondi si usa la variabile conta_score. Questa variabile s'incrementa di uno, ogni volta che viene eseguita la funzione tick(), quando diventa uguale a 50, significa che sono trascorsi 10 secondi (1 secondo=5 x 200 millisecondi => 10 secondi/200 millisecondi = 50) e viene decrementato il punteggio di uno, come mostra il blocco di codice segunte, inserito nella funzione tick():
conta_score+=1
if conta_score>50:
score=score-1
conta_score=0
Per dimezzare il punteggio ogni volta che le carte vengono mischiate, è stata inserita l'istruzione score=int(score/2) nella funzione mischia(), come mostra il blocco di codice seguente:
def mischia():
...
global tentativi
global score
tentativi=tentativi+1
score=int(score/2)
...
Come visualizzzare le carte small indovinate e non indovinate
La visualizzazione delle carte small indovinate oppure non indovinate serve per rendere il livello di difficolta del solitario più semplice, perché è più facile scegliere la carta da pensare.
Per caricare le carte small abbiamo usato la funzione carica_immagini_carte_small(), che aggiunge i riferimenti delle immagini nella lista immagini_carte_small e restituisce il riferimento della lista creata.
def carica_immagini_carte_small():
immagini_carte_small=[]
immagini_carte_small.append(ImageTk.PhotoImage(Image.open('1coppe_small.png')))
immagini_carte_small.append(ImageTk.PhotoImage(Image.open('2coppe_small.png')))
immagini_carte_small.append(ImageTk.PhotoImage(Image.open('3coppe_small.png')))
immagini_carte_small.append(ImageTk.PhotoImage(Image.open('4coppe_small.png')))
immagini_carte_small.append(ImageTk.PhotoImage(Image.open('5coppe_small.png')))
immagini_carte_small.append(ImageTk.PhotoImage(Image.open('6coppe_small.png')))
immagini_carte_small.append(ImageTk.PhotoImage(Image.open('7coppe_small.png')))
immagini_carte_small.append(ImageTk.PhotoImage(Image.open('8coppe_small.png')))
immagini_carte_small.append(ImageTk.PhotoImage(Image.open('9coppe_small.png')))
immagini_carte_small.append(ImageTk.PhotoImage(Image.open('10coppe_small.png')))
return immagini_carte_small
Per visualizzare le immagini small, ogni volta che si gira una carta, viene creata un'etichetta label_img_carta_indovinata se la carta è stata indovinata, altrimenti label_img_carta_non_indovinata, se la carta non è stata indovinata.
Le etichette usate per visualizzare le carte small sul piano di gioco, si trovano ad una distanza di 50 Pixel, l'una dall'altra. La posizione corrente viene indicata dalle variabili offset_indovinate ed offset_non_indovinate, come mostral'immagine seguente:
Il blocco di codice seguente, incluso nella funzione gira(), mostra come sono gestite le carte small:
if carta_pensata==mazzo_carte[indice_carta_girata]:
label_img_carta_indovinata=tk.Label(root, image=immagini_carte_small[mazzo_carte[indice_carta_girata]-1])
label_img_carta_indovinata.place(x=820+offset_indovinate,y=60)
offset_indovinate=offset_indovinate+50
indovinate=indovinate+1
label_indovinate.config(text=str(indovinate))
label_indovinate.place(x=820,y=65)
label_carte_small_si.append(label_img_carta_indovinata)
suono(5,0.1)
else:
label_img_carta_non_indovinata=tk.Label(root, image=immagini_carte_small[mazzo_carte[indice_carta_girata]-1])
label_img_carta_non_indovinata.place(x=820+offset_non_indovinate,y=153)
offset_non_indovinate=offset_non_indovinate+50
non_indovinate=non_indovinate+1
mazzo_carte_non_indovinate.append(mazzo_carte[indice_carta_girata])
label_non_indovinate.config(text=str(non_indovinate))
label_non_indovinate.place(x=820,y=158)
label_carte_small_no.append(label_img_carta_non_indovinata)
Le liste label_carte_small_si e label_carte_small_no, servono per memorizzare i riferimenti di tutte le etichette che contengono carte smll, in modo da poter essere cancellate quando è necessario, utilizzando i blocchi di codice seguenti:
# Elimina dal piano di gioco tutte le etichete che contengono carte small indovinate
for i in range(0,10):
label_carte_small_si[i].place_forget() # Cancella l'etichetta corrispondente al riferimento corrente della lista
label_carte_small_si.clear() # Cancella dalla lista tutti i riferimenti alle etchette che contengono carte small indovinate
# Elimina dal piano di gioco tutte le etichete che contengono carte small non indovinate
for i in range(0,len(mazzo_carte)):
label_carte_small_no[i].place_forget() # Cancella l'etichetta corrispondente al riferimento corrente della lista
label_carte_small_no.clear() # Cancella dalla lista tutti i riferimenti alle etchette che contengono carte small non indovinate
Come rimescolare le carte non indovinate e riprendere il gioco
Quando le carte del mazzo centrale vengono girate tutte, se ci sono ancora carte non indovinate occore rimescolarle per riprendere il gioco, questa operazione viene svolta dalla funzione mischia().
Prima di tutto bisogna svuotare la lista mazzo_carte, che contiene i valori delle 10 carte da gioco iniziali, il comando seguente esegue questa operazione:
mazzo_carte.clear()
Successivamente bisogna caricare i valori delle carte non indovinate nella lista mazzo_carte, e svuotare la lista che contiene i valori delle carte non indovinate, come mostrano le istruzioni seguenti:
mazzo_carte=mazzo_carte_non_indovinate[:]
mazzo_carte_non_indovinate.clear()
Il blocco di codice seguente mostra le istruzioni fondamentali della funzione mischia() per mescolare le carte non indovinate e riprendere il gioco:
def mischia():
global mazzo_carte
global mazzo_carte_non_indovinate
global non_indovinate
global offset_non_indovinate
global label_carte_small_no
...
mazzo_carte.clear()
mazzo_carte=mazzo_carte_non_indovinate[:]
mazzo_carte_non_indovinate.clear()
non_indovinate=0
offset_non_indovinate=50
# Elimina dal piano di gioco il pulsante mischia
pulsante_mischia.place_forget()
suono(9,4)
# Elimina dal piano di gioco tutte le etichete che contengono carte small non indovinate
for i in range(0,len(mazzo_carte)):
label_carte_small_no[i].place_forget()
label_carte_small_no.clear()
start() # Riavvia il gioco
Come iniziare una nuova partita oppure visualizzare la finestra modale "GAME OVER" per interrompere il gioco
Quando le carte vengono indovinate tutte, se il punteggio è maggiore di zero è possibile iniziare una nuova partita,
In qualunque momento il punteggio diventa zero, appare la finestra modale "GAME OVER" e bisogna interrompere il gioco.
Il primo caso (nuova partita) si controlla attraverso il codice seguente, inserito nella funzione gira():
# Se l'indice della carta girata e minore del del massimo consentito, incrementa l'indice di uno, altrimenti mischia oppure inizia una nuova partita
if indice_carta_girata<len(mazzo_carte)-1:
indice_carta_girata=indice_carta_girata+1
suono(3,0.1)
else:
pulsante_gira.place_forget()
label_girate.place_forget()
label_mazzo_di_carte.place_forget()
label_carta_girata.place_forget()
# Se ci sono ancora carte da indovinare mischia
if indovinate<10:
pulsante_mischia.place(x=295,y=370)
suono(8,0.1)
# Se non ci sono carte da indovinare inizia una nuova partita
else:
pulsante_nuova_partita.place(x=270,y=370)
suono(7,0.1)
flag=False
La variabile flag a false blocca l'aggiornamento dei secondi e del punteggio.
Per gestire il secondo caso (GAME OVER) occorre verificare se il punteggio diventa uguale a zero, questo è possibile solo quando viene aggiornato il punteggio all'interno della funzione tick(), come mostra blocco di codice seguente:
conta_score+=1
# Se conta_score>50 aggiorna il punteggio
if conta_score>50:
score=score-1
conta_score=0
# Se score>0 aggiorna le etichette dei secondi, dei tentativi e del punteggio
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)+" ")
# Se score==0 visualizza la finestra modale GAME OVER ed interrompe il gioco
else:
label_score.config(text=" 0 ")
flag=False
messagebox.showinfo('Fine Partita', 'GAME OVER')
esci() # Esegue funzione esci()
# Interrompe il gioco
def esci():
root.quit()
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_carte=[1,2,3,4,5,6,7,8,9,10] # Contiene i valori della 10 carte da gioco
mazzo_carte_non_indovinate=[] # Contiene i valori delle carte non indovinate
immagini_carte=[] # Contiene i riferimenti delle immagini della 10 carte da gioco
immagini_carte_small=[] # Contiene i riferimenti delle immagini della 10 carte da gioco small
label_carte_small_no=[]
label_carte_small_si=[]
indice_carta_pensata=0
indice_carta_girata=2
indovinate=0
non_indovinate=0
carta_pensata=1
time1=0 # Questa variabile viene usata per il calcolo dei secondi trascorsi
time_start=0 # Questa variabile viene usata per il calcolo dei secondi trascorsi
tentativi=1 # Questa variabile viene usata per contare quante volte vengono mischiate le carte
offset_indovinate=50 # Questa variabile viene usata per posizionare le carte small indovinate sul pannello di gioco
offset_non_indovinate=50 # Questa variabile viene usata per posizionare le carte small non indovinate sul pannello di gioco
score=1000 # Questa variabile contiene il punteggio
conta_score=0 # Questa variabile viene usata per decrementare di uno il punteggio ogni 10 secondi
flag=True # Questa variabile viene usata per interrompere l'aggiornamento dei secondi e del punteggio (nuova partita/game over)
# Questa funzione interrompe il gioco
def esci():
root.quit()
# Questa funzione viene eseguita ogni 200 millisecondi ed aggiorna il contenuto di tutte le etichette del pannello di gioco
def tick():
global time1
global time_start
global tentativi
global score
global conta_score
global flag
# legge ora locale del pc
time2 = time.strftime('%H:%M:%S')
if time2 != time1:
time1 = time2
label_clock.config(text=time2) # Aggiorna l'orologio in alto a destra del pannello di gioco
if flag: # Se flag==true vengono aggiornati i secondi ed il punteggio, altrimenti viene aggiornato solo l'orologio
secondi=int(time.time()-time_start) # Calcola i secondi trascorsi
spazi=" "[:(10-len(str(secondi)))] # Qunatità di spazi usati per impaginare i secondi ed i tentativi
str_secondi=spazi+str(secondi)+" "
label_secondi.config(text=str_secondi)
spazi=" "[:(10-len(str(tentativi)))]
label_tentativi.config(text=spazi+str(tentativi)+" ")
conta_score+=1
if conta_score>50: # Quando conta_score è ugluale a 50 sono passati 10 secondi e bisogna decrementare di uno il punteggio
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 ")
flag=False # Disattiva l'aggiornamento dei secondi e del punteggio
messagebox.showinfo('Fine Partita', 'GAME OVER') # Visualizza la finestra modale "GAME OVER"
esci() # Esce dal gioco
# chiama la funzione tick ogni 200 millisecondi
label_clock.after(200, tick)
# Questa funzione viene eseguita per mischiare le carte
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
def suono(sound,tempo):
if sound==1:
pygame.mixer_music.load("TickSound.mp3")
elif sound==2:
pygame.mixer_music.load("ElectronicSound.wav")
elif sound==3:
pygame.mixer_music.load("ToggleSound.wav")
elif sound==4:
pygame.mixer_music.load("ToneSound.wav")
elif sound==5:
pygame.mixer_music.load("OvationSound.wav")
elif sound==6:
pygame.mixer_music.load("ElectronicSound.wav")
elif sound==7:
pygame.mixer_music.load("CardSound.wav")
elif sound==8:
pygame.mixer_music.load("ComputerSound.wav")
pygame.mixer_music.play()
time.sleep(tempo)
# Questa funzione viene eseguita per caricare le immagini delle 10 carte da gioco
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
# Questa funzione viene eseguita per caricare le immagini small delle 10 carte da gioco
def carica_immagini_carte_small():
immagini_carte_small=[]
immagini_carte_small.append(ImageTk.PhotoImage(Image.open('1coppe_small.png')))
immagini_carte_small.append(ImageTk.PhotoImage(Image.open('2coppe_small.png')))
immagini_carte_small.append(ImageTk.PhotoImage(Image.open('3coppe_small.png')))
immagini_carte_small.append(ImageTk.PhotoImage(Image.open('4coppe_small.png')))
immagini_carte_small.append(ImageTk.PhotoImage(Image.open('5coppe_small.png')))
immagini_carte_small.append(ImageTk.PhotoImage(Image.open('6coppe_small.png')))
immagini_carte_small.append(ImageTk.PhotoImage(Image.open('7coppe_small.png')))
immagini_carte_small.append(ImageTk.PhotoImage(Image.open('8coppe_small.png')))
immagini_carte_small.append(ImageTk.PhotoImage(Image.open('9coppe_small.png')))
immagini_carte_small.append(ImageTk.PhotoImage(Image.open('10coppe_small.png')))
return immagini_carte_small
# Questa funzione permette di scegliere la carta pensata
def cambia():
global indice_carta_pensata
global carta_pensata
carta_pensata=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(1,0.1)
# Questa funzione viene eseguita per girare le carte e verificare se la carta pensata è uguale alla carta girata
def gira():
global indice_carta_girata
global flag
global mazzo_carte
global carta_pensata
global indovinate
global non_indovinate
global offset_indovinate
global offset_non_indovinate
global label_carte_small_no
global label_carte_small_si
label_carta_girata.config(image=immagini_carte[mazzo_carte[indice_carta_girata]])
label_carta_girata.place(x=455,y=40)
girate=" "+str(indice_carta_girata+1)+"/"+str(len(mazzo_carte))+" "
label_girate.config(text=girate)
label_girate.place(x=500,y=370)
if carta_pensata==mazzo_carte[indice_carta_girata]:
label_img_carta_indovinata=tk.Label(root, image=immagini_carte_small[mazzo_carte[indice_carta_girata]-1])
label_img_carta_indovinata.place(x=820+offset_indovinate,y=60)
offset_indovinate=offset_indovinate+50
indovinate=indovinate+1
label_indovinate.config(text=str(indovinate))
label_indovinate.place(x=820,y=65)
label_carte_small_si.append(label_img_carta_indovinata)
suono(4,0.1)
else:
label_img_carta_non_indovinata=tk.Label(root, image=immagini_carte_small[mazzo_carte[indice_carta_girata]-1])
label_img_carta_non_indovinata.place(x=820+offset_non_indovinate,y=153)
offset_non_indovinate=offset_non_indovinate+50
non_indovinate=non_indovinate+1
mazzo_carte_non_indovinate.append(mazzo_carte[indice_carta_girata])
label_non_indovinate.config(text=str(non_indovinate))
label_non_indovinate.place(x=820,y=158)
label_carte_small_no.append(label_img_carta_non_indovinata)
if indice_carta_girata<len(mazzo_carte)-1:
indice_carta_girata=indice_carta_girata+1
suono(3,0.1)
else:
pulsante_gira.place_forget()
label_girate.place_forget()
label_mazzo_di_carte.place_forget()
label_carta_girata.place_forget()
if indovinate<10:
pulsante_mischia.place(x=295,y=370)
suono(6,0.1)
else:
pulsante_nuova_partita.place(x=270,y=370)
suono(5,0.1)
flag=False
# Questa funzione viene eseguita quando si clicca sul pulsante mischia, gestisce tutte le operazioni richieste quando si mischiano le carte non indovinate
def mischia():
global mazzo_carte
global mazzo_carte_non_indovinate
global non_indovinate
global offset_non_indovinate
global label_carte_small_no
global tentativi
global score
tentativi=tentativi+1
score=int(score/2)
mazzo_carte.clear()
mazzo_carte=mazzo_carte_non_indovinate[:]
mazzo_carte_non_indovinate.clear()
non_indovinate=0
offset_non_indovinate=50
pulsante_mischia.place_forget()
suono(7,4)
for i in range(0,len(mazzo_carte)):
label_carte_small_no[i].place_forget()
label_carte_small_no.clear()
start()
# Questa funzione viene eseguita quando si clicca sul pulsante nuova partita, gestisce tutte le operazioni necessarie per iniziare una nuova partita
def nuova_partita():
global mazzo_carte
global mazzo_carte_non_indovinate
global indovinate
global non_indovinate
global offset_indovinate
global offset_non_indovinate
global label_carte_small_si
global tentativi
global score
global conta_score
global time_start
global flag
mazzo_carte=[1,2,3,4,5,6,7,8,9,10]
mazzo_carte_non_indovinate.clear()
flag=True
indovinate=0
offset_indovinate=50
non_indovinate=0
offset_non_indovinate=50
tentativi=1
score=1000
conta_score=0
time_start=0
label_carta_girata.place_forget()
pulsante_nuova_partita.place_forget()
suono(8,2.5)
for i in range(0,10):
label_carte_small_si[i].place_forget()
label_carte_small_si.clear()
start()
# Questa funzione viene eseguita per inizializzare il pannello di gioco e per gestire tutte le oprazioni richieste quando inizia una nuova partita
def start():
global indice_carta_pensata
global carta_pensata
global indice_carta_girata
global non_indovinate
global mazzo_carte
global time_start
if time_start==0:
time_start = time.time()
label_clock.place(x=1300,y=5)
pulsante_cambia.place(x=60,y=370)
label_titolo_carta_pensata.place(x=25,y=5)
label_carta_pensata.config(image=immagini_carte[1])
label_carta_pensata.place(x=5,y=40)
label_titolo_mazzo_di_carte.place(x=260,y=5)
label_mazzo_di_carte.place(x=240,y=40)
pulsante_gira.place(x=285,y=370)
label_girate.config(text=" 0/"+str(len(mazzo_carte))+" ")
label_girate.place(x=500,y=370)
label_img_indovinate.place(x=750,y=60)
label_indovinate.config(text=str(indovinate))
label_indovinate.place(x=820,y=65)
label_img_non_indovinate.place(x=750,y=150)
label_non_indovinate.config(text=str(non_indovinate))
label_non_indovinate.place(x=820,y=158)
label_titolo_tempo.place(x=35,y=455)
label_secondi.place(x=30,y=515)
label_tentativi.place(x=160,y=515)
label_titolo_tentativi.place(x=153,y=455)
label_secondi.place(x=30,y=480)
label_tentativi.place(x=160,y=480)
label_titolo_score.place(x=280,y=455)
label_score.place(x=280,y=480)
pygame.init()
indice_carta_pensata=2
carta_pensata=1
indice_carta_girata=0
mischia_carte(mazzo_carte)
# Preparazione pannello di gioco
root = tk.Tk()
root.wm_title('Solitario del ferroviere')
root.geometry("1400x600")
root.resizable(False, False)
immagine_indovinate=ImageTk.PhotoImage(Image.open('verde.png'))
immagine_non_indovinate=ImageTk.PhotoImage(Image.open('rosso.png'))
label_titolo_carta_pensata=tk.Label(root, text="CARTA PENSATA",font=("Helvetica", 14))
label_titolo_mazzo_di_carte=tk.Label(root, text="MAZZO DI CARTE",font=("Helvetica", 14))
pulsante_cambia=tk.Button(root,text="CAMBIA", width=10, height=2, bd = 3,command=cambia, bg="seagreen",font=("Helvetica", 12))
pulsante_gira=tk.Button(root,text="GIRA", width=10, height=2, bd = 3,command=gira, bg="teal",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_girate=tk.Label(root, text=" 0/10 ",font=("Helvetica", 25),fg="white",bg="tomato")
label_img_indovinate=tk.Label(root, image=immagine_indovinate)
label_indovinate=tk.Label(root, text=str(indovinate),font=("Helvetica", 24))
label_non_indovinate=tk.Label(root, text=str(non_indovinate),font=("Helvetica", 24))
label_img_non_indovinate=tk.Label(root, image=immagine_non_indovinate)
label_clock = tk.Label(root, font=('arial', 14, 'italic'), bg='darkgray',fg='black')
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_secondi=tk.Label(root, font=('arial', 14, 'normal'), bg='blue',fg='white')
label_tentativi=tk.Label(root, font=('arial', 14, 'normal'), bg='orange',fg='white')
label_titolo_score=tk.Label(root, text="SCORE",font=("times", 12,"italic"),fg="black")
label_score=tk.Label(root, font=('arial', 16, 'normal'), bg='palevioletred',fg='white')
logo=ImageTk.PhotoImage(Image.open('logo_sf.png'))
label_logo=tk.Label(root, image=logo)
label_powered_sf=tk.Label(root, text="2020 - Powered by Skill Factory",font=("times", 14,'italic'))
label_powered_sf.place(x=550,y=557)
label_logo.place(x=805,y=545)
immagini_carte=carica_immagini_carte()
label_carta_pensata=tk.Label(root, image=immagini_carte[1])
label_mazzo_di_carte=tk.Label(root, image=immagini_carte[0])
label_carta_girata=tk.Label(root, image=immagini_carte[0])
immagini_carte_small=carica_immagini_carte_small()
label_sinistra=tk.Label(root, image=immagini_carte_small[0])
label_destra=tk.Label(root, image=immagini_carte_small[0])
start()
tick()
root.mainloop()
Nella prossima lezione implementeremo le funzionalità per creare il secondo livello di difficoltà del "Solitario del Ferroviere".
Arrivederci ...
<< Lezione precedente Lezione successiva >>
Per scaricare le risorse di questa lezione clicca sul link seguente:risorse_lezione_04
Impariamo Python giocando al "Solitario del Ferroviere" - Lezione 3
Gino Visciano |
Skill Factory - 27/12/2019 09:24:31 | in Tutorials
Nella prima lezione abbiamo descritto le regole per giocare al "Solitario del ferroviere" ed implementato la funzionalità per scegliere la carta da pensare, nella seconda lezione abbiamo implementato la funzionalità che permette di creare il mazzo di carte e girare le carte.
In questa nuova lezione implementeremo le seguenti funzionalità:
1) mischiare le carte
2) visualizzare l'ora ed il tempo trascorso
3) visualizzare il numero di volte che si mischiano le carte: tentativi
Come mischiare le carte
Per mischiare le carte è necessario invertire diverse volete, in modo casuale, i valori delle carte nella lista mazzo_carte, in questo modo cambiano anche le posizioni delle immagini associate alle carte, come mostra l'esempio seguente:
L'esempio prevede 6 iterazioni (loop), con inversione casuale di due valori nella lista mazzo_carte. Questo lavoro produce il risultato seguente:
mazzo_carte=[1,2,3,4,5,6,7,8,9,10] => mazzo_carte=[6,4,5,2,7,1,9,10,3,8]
Associando ai valori della lista mazzo_carte le rispettive immagini si ottiene:
6 4 5 2 7 1 9 10 3 8
La funzione Python seguente inverte 99 volte, in modo casuale, due valori della lista mazzo_carte:
Come visualizzare l'ora e misurare il tempo in secondi
In Python per ottenre l'ora del sistema occorre importare la classe time ed usare la funzione strftime(...), come mostra l'esempio seguente:
# Che ora è?
import time
orario=time.strftime('%H:%M:%S')
print (orario)
>>>15:10:20
Per ottenere l'ora di sistema in un frame, potete utilizzare l'esempio seguente:
# Che ora è?
import time
import tkinter as tk
orario=time.strftime('%H:%M:%S')
root = tk.Tk()
root.wm_title('Orologio')
root.resizable(False, False)
label_orologio=tk.Label(root, text=orario,font=("Helvetica", 20))
label_orologio.pack()
root.mainloop()
Per trasformare la visualizzazione dell'ora di sistema in un vero orologio, dovete aggiornare ogni secondo l'etichetta label_orologio, con l'ora corrente, utilizzando la funzione after(...) come mostra l'esempio seguente:
# Orologio
import time
import tkinter as tk
# Questa funzione aggiorna ogni secondo l'ora visualizzata nell'etichetta label_orologio, utilizzando la finzione after(ogni_milliscondi, esegui_funzione)
def aggiorna_orario():
orario=time.strftime('%H:%M:%S')
label_orologio.config(text=orario)
label_orologio.pack()
label_orologio.after(1000,aggiorna_orario)
root = tk.Tk()
root.wm_title('Orologio')
root.resizable(False, False)
label_orologio=tk.Label(root, text="",font=("Helvetica", 20))
aggiorna_orario()
root.mainloop()
Possiamo usare l'esempio dell'orologio per visualizzare anche i secondi trascorsi, utilizzando la funzione time(), che restituisce l'ora di sistema in secondi:
# Orologio con secondi
import time
import tkinter as tk
# Questa funzione aggiorna ogni secondo l'ora visualizzata nell'etichetta label_orologio ed i secondi trascorsi nell'etichetta label_secondi, utilizzando la finzione after(ogni_milliscondi, esegui_funzione)
def aggiorna_orario():
global time_inizio
orario=time.strftime('%H:%M:%S')
time_fine=time.time()
secondi=int(time_fine-time_inizio)
label_orologio.config(text=orario)
label_secondi.config(text=secondi)
label_orologio.pack()
label_secondi.pack()
label_orologio.after(1000,aggiorna_orario)
root = tk.Tk()
root.wm_title('Orologio')
root.resizable(False, False)
label_orologio=tk.Label(root, text="",font=("Helvetica", 20))
label_secondi=tk.Label(root, text="",font=("Helvetica", 20))
time_inizio=time.time()
aggiorna_orario()
root.mainloop()
Come visualizzare il numero di volte che si mischiano le carte
Per visualizzare il numero di volte che si mischiano le carte, dovete usare un contatore che s'incrementa ogni volta che le carte vengono mischiate. Il contatore deve essere inserito nella funzione mischia_carte(mazzo), come mostra l'esempio seguete:
tentativi=tentativi+1,
tentativi è una variabile globale, che s'incrementa di uno ogni volta che vengono mischiate le carte.
Per visualizzare i tentativi sul pannello di gioco, dovete creare un'etichetta e gestirla come mostra il codice seguente:
# Dichiarazione dell'etichetta per visualizzare il titolo del contatore
label_titolo_tentativi=tk.Label(root, text="TENTATIVI",font=("times", 12,"italic"),fg="black")
# Dichiarazione dell'etichetta per visualizzare il valore del contatore
label_tentativi=tk.Label(root, font=('arial', 14, 'normal'), bg='orange',fg='white')
# Formattazione della stringa da associare all'etichetta che visualizza i tentativi
spazi=" "[:(10-len(str(tentativi)))] # Imposta il numero di spazi da aggiungere a sinistra del valore del contatore, per ottenere sempre una stringa di 10 caratteri
# Assegna la stringa di 10 caratteri all'etichetta per vusializzare i tentativi
label_tentativi.config(text=spazi+str(tentativi)+" ")
# Posiziana e visualizza le etichette sul pannello di gioco
label_titolo_tentativi.place(x=153,y=455)
label_tentativi.place(x=160,y=515)
Per vedere dove deve essere posizionato il codice Python descritto in questa sezione, consultate la sezione Analisi del codice Python.
L'immagine seguente mostra come si presenta il pannello di gioco, dopo il posizionamento di tutte le etichette create.
Analisi del codice Python
# Solitario del ferroviere (Lezione 3)
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
mazzo_carte=[1,2,3,4,5,6,7,8,9,10] # Lista con i valori delle carte
immagini_carte=[] # Lista che contiene le immagini delle carte
indice_carta_girata=0
time1='' # Questa variabile viene usata per il calcolo dei secondi trascorsi
time_start='' # Questa variabile viene usata per il calcolo dei secondi trascorsi
tentativi=0 # Questa variabile viene usata per contare quante volte vengono mischiate le carte
# Questa funzione viene eseguita ogni 200 millisecondi ed aggiorna il contenuto di tutte le etichette del pannello di gioco
def tick():
global time1
global time_start
global tentativi
# legge ora locale del pc
time2 = time.strftime('%H:%M:%S')
if time2 != time1:
time1 = time2
# Etichetta con orologio in alto a destra del pannello di gioco
label_clock.config(text=time2)
secondi=int(time.time()-time_start)
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)+" ")
# La funzione after avvia la funzione tick ogni 200 millisecondi
label_clock.after(200, tick)
# Questa funzione permette di mischiare le carte, l'argomento mazzo, è un riferimento, contiene l'indirizzo (posizione in memoria) della lista mazzo_carte
def mischia_carte(mazzo):
global tentativi
tentativi=tentativi+1 # Questa variabile viene ha il ruolo di contatore, conta quante volte le carte vengono mischiate
temp=0
max=len(mazzo)-1 # Questa variabile indica l'indice massimo che punta all'ultimo valore contenuto nella liata mazzo_carte
for i in range(1,100):
prima=random.randint(0,max) # Questa variabile indica il primo indice casuale che punta al valore da invertire per mischiare le carte
seconda=random.randint(0,max) # Questa variabile indica il secondo indice casuale che punta al valore da invertire per mischiare le carte
if prima!=seconda:
# SWAP, inverte la posizione dei valori nella lista mazzo_carte
temp=mazzo[prima]
mazzo[prima]=mazzo[seconda]
mazzo[seconda]=temp
# Questa funzione permette di scegliere il suona da emettere (sound) e la durata (tempo)
def suono(sound,tempo):
if sound==1:
pygame.mixer_music.load("TickSound.mp3")
elif sound==2:
pygame.mixer_music.load("ElectronicSound.wav")
else:
pygame.mixer_music.load("ComputerSound.wav")
pygame.mixer_music.play() # Emette il suono richiesto
time.sleep(tempo) # Pausa
# Questa funzione carica nella lista immagini_carte le immagini delle 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
# Questa funzione permette di girare le carte
def gira():
global indice_carta_girata
global mazzo_carte
global flag
label_carta_girata.config(image=immagini_carte[mazzo_carte[indice_carta_girata]])
label_carta_girata.place(x=240,y=40)
girate=" "+str(indice_carta_girata+1)+"/10 "
label_girate.config(text=girate)
label_girate.place(x=285,y=370)
if indice_carta_girata<9:
indice_carta_girata=indice_carta_girata+1
suono(1,0.1)
else:
pulsante_gira.place_forget()
label_girate.place_forget()
indice_carta_girata=0
label_mazzo_di_carte.place_forget()
pulsante_nuova_partita.place(x=270,y=370)
suono(2,0.1)
# Questa funzione si attiva quando si clicca sul pulsante_nuova_partita, permette di mischiare le carte e riprendere il gioco
def nuova_partita():
global indice_carta_girata
label_carta_girata.place_forget()
pulsante_nuova_partita.place_forget()
suono(3,2.5)
label_girate.config(text=" 0/10 ")
start()
# Questa funzione permette di inizializzare il pannello di gioco
def start():
global indice_carta_girata
global mazzo_carte
global time_start
time_start = time.time() # Legge l'ora di sistema espressa in secondi
label_clock.place(x=360,y=5)
label_titolo_mazzo_di_carte.place(x=45,y=5)
label_mazzo_di_carte.place(x=25,y=40)
pulsante_gira.place(x=70,y=370)
label_girate.place(x=285,y=370)
label_titolo_tempo.place(x=35,y=455)
label_secondi.place(x=30,y=515)
label_tentativi.place(x=160,y=515)
label_titolo_tentativi.place(x=153,y=455)
label_secondi.place(x=30,y=480)
label_tentativi.place(x=160,y=480)
tick() # Esegue la funzione tick() che aggiorna il contenuto di tutte le etichette del pannello di gioco
pygame.init() # Inizializza le funzionalità pygame per la gestione dei suoni
indice_carta_girata=0
mischia_carte(mazzo_carte) # Mischia i valori della lista mazzo_carte
# Inizializzazione ed impostazione caratteristiche pannello di gioco
root = tk.Tk()
root.wm_title('Solitario del ferroviere')
root.geometry("460x520")
root.resizable(False, False)
label_titolo_mazzo_di_carte=tk.Label(root, text="MAZZO DI CARTE",font=("Helvetica", 14))
pulsante_gira=tk.Button(root,text="GIRA", width=10, height=2, bd = 3,command=gira, bg="green",font=("Helvetica", 12))
pulsante_nuova_partita=tk.Button(root,text="NUOVA PARTITA", width=15, height=2, bd = 3,command=nuova_partita, bg="orange",font=("Helvetica", 12))
label_girate=tk.Label(root, text=" 0/10 ",font=("Helvetica", 25),fg="white",bg="orange")
label_clock = tk.Label(root, font=('arial', 14, 'italic'), bg='gray',fg='black')
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_secondi=tk.Label(root, font=('arial', 14, 'normal'), bg='blue',fg='white')
label_tentativi=tk.Label(root, font=('arial', 14, 'normal'), bg='orange',fg='white')
immagini_carte=carica_immagini_carte()
label_mazzo_di_carte=tk.Label(root, image=immagini_carte[0])
label_carta_girata=tk.Label(root, image=immagini_carte[0])
start() # Inizializza il pannello di gioco
root.mainloop()
Nella prossima lezione implementeremo la funzionalità per controllare se la carta pensata e uguale alla carta girata dal mazzo, in questo modo già potrete iniziare a giocare.
Arrivederci ...
<< Lezione precedente Lezione successiva >>
Per scaricare le risorse di questa lezione clicca sul link seguente:risorse_lezione_03
Impariamo Python giocando al "Solitario del Ferroviere" - Lezione 2
Gino Visciano |
Skill Factory - 21/12/2019 10:02:13 | in Tutorials
Come creare il mazzo di carte
Nella lezione precedente abbiamo descritto le regole del gioco per giocare al "Solitario del ferroviere" ed implementato la funzionalità per scegliere la carta da pensare.
In questa seconda lezione implementeremo la funzionalità che permette di girare le carte del mazzo.
Per iniziare serve il mazzo di carte, per crearlo abbiamo usato la lista mazzo_carte a cui sono stati aggiunti i valori delle 10 carte da gioco, come mostra il comando seguente:
mazzo_carte=[1,2,3,4,5,6,7,8,9,10]
Successivamente, per associare i valori delle carte alle ripsettive immagini, abbiamo usato come indice della lista immagini_carte, i valori della lista mazzo_carte, come mostra il comando seguente:
immagini_carte[mazzo_carte[indice_carta_girata]]
Ad esempio, se indice_carta_girata è uguale a 4, il valore corrispondente alla carta da visualizzare è 5, come mostra l'esempio seguente:
mazzo_carte=[1,2,3,4,5,6,7,8,9,10]
Utilizzando il valore ottenuto come indice della lista immagini_carte, che contiene le immagini delle carte da gioco, si ottine la carta da gioco corrispondente:
Per visualizzare le carte da gioco sul pannello di gioco, abbiamo usato le etichette seguenti:
label_mazzo_di_carte=tk.Label(root, image=immagini_carte[0])
label_carta_girata=tk.Label(root, image=immagini_carte[0])
Per cambiare l'immagine associata all'etichetta label_carta_girata, abbiamo usato la funzione config(...), come mostra il comando seguente :
label_carta_girata.config(image=immagini_carte[mazzo_carte[indice_carta_girata]])
Come girare le carte mazzo
Per girare le carte del mazzo, è sufficiente incrementare ogni volta di uno la variabile indice_carta_girata, naturalmente la variabile deve essere azzerata ogni volta che il suo valore va oltre il limite massimo consentito, per evitare che venga generato l'errore:
IndexError: list index out of range
Per gestire questa funzionalità abbiamo creato il pulsante gira associato alla funzione gira(), come mostra il comando seguente:
pulsante_gira=tk.Button(root,text="GIRA", width=10, height=2, bd = 3,command=gira, bg="green",font=("Helvetica", 12))
Ogni volta che si clicca sul pulsante gira, la funzione gira() incrementa di 1 la variabile indice_carta_girata, in questo modo, di volta in volta, vengono visualizzate tutte le carte del mazzo, come mostra l'immagine seguente:
Quando la variabile indice_carta_girata diventa uguale a 8, la funzione gira(), gestisce le seguenti attività:
1) visualizza il dieci di coppe
2) elimina dal pannello di gioco, l'ultima carta del mazzo
3) elimina dal pannello di gioco il pulsante gira
4) permette di iniziare una nuova partitta, visualizzando il pulsante nuova partita.
L'immagine seguente mostra il pannello di gioco quando la variabile indice_carta_girata diventa uguale ad 8.
Cliccando sul pulsante nuova partita, viene eseguita la funzione nuova_partita(), che svolge le attività necessarie per riprendere il gioco.
Analisi del codice Python
# Solitario del ferroviere (Lezione 2)
import pygame # Importo la libreria pygame per gestire i suoni
import tkinter as tk # Importo la libreria tkinter con alias (abbreviazione) tk, per gestire il pannello su cui giocare
import time #Importo la libreria time per gestire il tempo attraverso l'orologio di sistema
from PIL import Image, ImageTk # Importo da PIL le librerie per gestire le immagini
from tkinter import messagebox # Importo da tkinter la libreria per gestire una finestra modale per gestire la fine del programma (game over)
# Lista per gestire il mazzo di carte
mazzo_carte=[1,2,3,4,5,6,7,8,9,10]
# Lista in cui caricare i riferimenti alle immagini delle carte
immagini_carte=[]
# Indice che punta al valore della carta girata
indice_carta_girata=0
# Questa funzione gestisce i suoni, sound permette di scegliere il suono, tempo indica pa pausa richiesta dopo il suono
def suono(sound,tempo):
if sound==1:
pygame.mixer_music.load("TickSound.mp3")
elif sound==2:
pygame.mixer_music.load("ElectronicSound.wav")
else:
pygame.mixer_music.load("ComputerSound.wav")
pygame.mixer_music.play()
time.sleep(tempo)
# Questa funzione permette di aggiungere le immagini del gioco nella 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
# Questa funzione permette di girare le carte del mazzo
def gira():
global indice_carta_girata
global mazzo_carte
global flag
# Visualizza la carta girata
label_carta_girata.config(image=immagini_carte[mazzo_carte[indice_carta_girata]])
label_carta_girata.place(x=240,y=40)
girate=" "+str(indice_carta_girata+1)+"/10 "
label_girate.config(text=girate)
label_girate.place(x=285,y=370)
if indice_carta_girata<9:
indice_carta_girata=indice_carta_girata+1
suono(1,0.1)
else:
# Questo blocco gestisce le attività richieste quando finiscono le carte del mazzo
pulsante_gira.place_forget()
label_girate.place_forget()
indice_carta_girata=0
label_mazzo_di_carte.place_forget()
pulsante_nuova_partita.place(x=270,y=370)
suono(2,0.1)
# Questa funzione avvia una nuova partita
def nuova_partita():
global indice_carta_girata
label_carta_girata.place_forget()
pulsante_nuova_partita.place_forget()
suono(3,2.5)
label_girate.config(text=" 0/10 ")
start()
# Questa funzione inizializza il pannello di gioco
def start():
global indice_carta_girata
label_titolo_mazzo_di_carte.place(x=45,y=5)
label_mazzo_di_carte.place(x=25,y=40)
pulsante_gira.place(x=70,y=370)
label_girate.place(x=285,y=370)
pygame.init()
indice_carta_girata=0
# Preparazione dei componenti del pannello di gioco
root = tk.Tk()
root.wm_title('Solitario del ferroviere')
root.geometry("460x450")
root.resizable(False, False)
label_titolo_mazzo_di_carte=tk.Label(root, text="MAZZO DI CARTE",font=("Helvetica", 14))
pulsante_gira=tk.Button(root,text="GIRA", width=10, height=2, bd = 3,command=gira, bg="green",font=("Helvetica", 12))
pulsante_nuova_partita=tk.Button(root,text="NUOVA PARTITA", width=15, height=2, bd = 3,command=nuova_partita, bg="orange",font=("Helvetica", 12))
label_girate=tk.Label(root, text=" 0/10 ",font=("Helvetica", 25),fg="white",bg="orange")
immagini_carte=carica_immagini_carte()
label_mazzo_di_carte=tk.Label(root, image=immagini_carte[0])
label_carta_girata=tk.Label(root, image=immagini_carte[0])
start()
root.mainloop()
Nella prossima lezione implementeremo la funzione per mischiare le carte del mazzo centrale.
Arrivederci ...
<< Lezione precedente Lezione successiva >>
Per scaricare le risorse di questa lezione clicca sul link seguente:risorse_lezione_02
Impariamo a programmare in Python, giocando al "Solitario del Ferroviere" - Lezione 1
Gino Visciano |
Skill Factory - 18/12/2019 20:28:16 | in Tutorials
Regole del gioco
Il Solitario del Ferroviere è un passatempo che si può giocare con le carte napoletane, le regole del gioco sono le seguenti:
1) Mischiare le carte e metterle al centro;
2) Pensare ad una carta del mazzo;
3) Alzare una carta dal mazzo;
4) Se la carta alzata è uguale a quella pensata, mettere la carta a sinistra, altrimenti metterla a destra;
5) Continuare a giocare mentre ci sono carte nel mazzo centrale;
6) Quando le carte del mazzo centrale finiscono, mentre ci sono carte a destra (carte non indovinate), mischiare le carte, metterle al centro e ricominciare a giocare.
Per semplificare la realizzazione del gioco con Python, utilizzeremo solo 10 carte napoletane , come mostra l'immagine seguente:
Il Diagramma di Flusso segunte descrive l'Algoritmo per giocare al Solitario del Ferroviere:
La pseudo-codifica seguente descrive meglio le strutture logiche dell'Algoritmo per giocare al Solitario del Ferroviere, soprattutto perché permette di riconoscere i cicli che spesso nei Diagrammi di Flusso vengono confusi con le selezioni.
#Algoritmo in pseudo-codifica, per giocare al solitario del ferroviere
Inizio
Inizio Mentre
Mischia le carte e mettile al centro
Inizio Mentre
Pensa ad una carta
Alza una carta
Se carta pensata==carta alzata allora
Metti la carta a sinistra
Altrimenti
Metti la carta a destra
Fine Se
Mentre carte al centro !=0
Mentre carte a destra !=0
Fine
In questa prima lezione implementeremo la funzione Python che permette di scegliere la carta pensata, come mostra l'immagine seguente:
Cosa serve per iniziare
Per iniziare dovete installare Python (almeno la versione 3.8), per scrivere il codice, vi suggerisco di usare come ide (integrated development environment ) Visual Studio Code.
Usando la guida seguente potete installare sia Python che Visual Studio Code: guida_installazione.
Inoltre dovete installare le seguenti librerie Python:
- pygame
- pillow
- time
con i comandi seguenti:
pip install pygame
pip install Pillow
pip install time
Se il comando pip non è installato, procedete nel modo seguente:
1) Scaricate il file get-pip.py;
2) Eseguite il comando: python get-pip.py.
Cosa dovete sapere
a=10 # Variabile intera
b=2.5 # Variabile Decimale
nome='Mario' # Variabile Stringa
flag=True # Variabile Booleana
Le liste sono insiemi dinamici di valori, per dichiarare una lista si usa la sintassi seguente:
valori=[10,20,30] # Lista di valori di tipo intero
nominativi=['Mario','Clara','Paolo','Roberta'] # Lista di valori di tipo Stringa
elenco=[] # Lista di valori vuota non ancora tipizzata
Per aggiungere un elemento ad una lista si usa il metodo append, come mostra l'esempio seguente:
elencoValori=[] # Lista di valori vuota non ancora tipizzata
# Aggiungo tre valori alla lista
elencoValori.append(10)
elencoValori.append(20)
elencoValori.append(30)
# Ciclo usato per visualizzare il contenuto della lista, i assume ad ogni ripetizione i valori seguenti: 0,1 e 2
for i in range(0,3):
print(elencoValori[i])
L'esempio seguente, si differenzia da quello precedente, perchè per visualizzare il contenuto della lista usa un foreach.
Questa struttura di programmazione permette di leggere il contenuto di una lista senza usare l'indice dell'elemento da visualizzare, perché automaticamente ad ogni iterazione (loop) legge il valore seguente e lo assegna alla variabile del ciclo.
elencoValori=[] # Lista di valori vuota non ancora tipizzata
# Aggiungo tre valori alla lista
elencoValori.append(10)
elencoValori.append(20)
elencoValori.append(30)
# Ciclo foreach, ad ogni ripetizione ad a viene assegnato un valore della lista elencoValori
for a in elencoValori:
print(a)
Analisi del codice Python
import pygame # Importo la libreria pygame per gestire i suoni
import tkinter as tk # Importo la libreria tkinter con alias (abbreviazione) tk, per gestire il pannello su cui giocare
from PIL import Image, ImageTk # Importo da PIL le librerie per gestire le immagini
from tkinter import messagebox # Importo da tkinter la libreria per gestire una finestra modale per gestire la fine del programma (game over)
import time #Importo la libreria time per gestire il tempo attraverso l'orologio di sistema
indice_carta_pensata=0
flag=True
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
# Questa funzione incrementa la variabile indice_carta_pensata, per cambiare la carta visualizzata, viene eseguite ogni volta che si esegue un click sul pulsante cambia
def cambia():
# indica che la variabile indice_carta_pensata è una variabile globale, creata all'esterno della funzione
global indice_carta_pensata
# Imposta l'immagine della carta corrente
label_carta_pensata.config(image=immagini_carte[indice_carta_pensata])
# Visualizza la carta corrente alla posizione indicata
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
# Emette un suono ed imposta una pausa 0.1 secondi
pygame.mixer_music.load("TickSound.mp3")
pygame.mixer_music.play()
time.sleep(0.1)
# Questa funzione inizializza il pannello di gioco
def start():
global indice_carta_pensata
# Visualizza il pulsante cambia, che ad ogni click esegue la funzione cambia()
pulsante_cambia.place(x=60,y=370)
label_titolo_carta_pensata.place(x=25,y=5)
label_carta_pensata.place(x=5,y=40)
# Inizializza la gestione dei suoni
pygame.init()
indice_carta_pensata=2
# Crea il pannello di gioco
root = tk.Tk()
root.wm_title('Solitario del ferroviere') # Imposta il titolo del pannello di gioco
root.geometry("215x450") # Imposta le dimensioni del pannello di gioco
root.resizable(False, False) # Disabilità il ridimensionamento del pannello di gioco
# Preparazione pulsanti ed etichette, l'attributo commad permette di indicare la funzione eseguita quando si clicca sul pulsante
pulsante_cambia=tk.Button(root,text="CAMBIA", width=10, height=2, bd = 3,command=cambia, bg="green",font=("Helvetica", 12))
label_titolo_carta_pensata=tk.Label(root, text="CARTA PENSATA",font=("Helvetica", 14))
# Prepara il vettore con i riferimenti alle immagini delle carte
immagini_carte=carica_immagini_carte()
# Carica nell'etichetta la prima carta del mazzo
label_carta_pensata=tk.Label(root, image=immagini_carte[1])
# Inizializza l'applicazione e visualizza l'etichetta ed il bottone cambia
start()
root.mainloop() # Rende il pannello di gioco interattivo
Nella prossima lezione implementeremo la funzione per girare le carte del mazzo centrale.
Arrivederci ...
Per scaricare le risorse di questa lezione clicca sul link seguente: risorse_lezione_01
Resto a casa a fare formazione ...
Anche durante il lockdown non ci siamo mai fermati, erogando oltre 3000 ore di formazione e laboratorio in Smart-Learning/Working. Grazie al nostro impegno, durante il periodo di emergenza COVID, 50 giovani programmatori hanno iniziato un tirocinio formativo presso un nostro Job partner IT, con l'opportunità di essere assunti a settembre 2020.
Tutto quello che ti serve per diventare programmatore te lo insegniamo noi!
Vuoi partecipare ad una "Skill Factory"? Invia il tuo CV a recruiting@skillfactory.it, ti contatteremo per verificare se hai i prerequisiti richiesti.
Non cerchiamo talenti o esperti d'Informatica, ma giovani seri e volenterosi, predisposti a risolvere problemi logici.
Sei un programmatore esperto?
Pensi che la tua esperienza possa essere utile agli utenti della nostra community?
Cosa aspetti, conttattaci! Puoi diventare un nostro "Competence partner" e dare valore alla tua esperienza ...
mail: sid@skillfactory.it
Per far parte della nostra community registrati su www.skillbook.it.
T U T O R I A L S S U G G E R I T I
- TypeScript
- Impariamo Python giocando al "Solitario del ferroviere"
- Impariamo a programmare con JavaScript
- Laboratori di Logica di programmazione in C
- Introduzione alla Logica degli oggetti
- Ricominciamo ... dal Linguaggio SQL
- APP Mania
- Come sviluppare un Sito con Wordpress
- Excel delle meraviglie
EDUCATIONAL GAMING BOOK (EGB) "H2O"
Nell'era dello SMART LEARNING e di PYTHON i libri non si scrivono, ma si sviluppano, in questo modo chi studia, può sperimentare ed apprendere contemporaneamente; un libro con queste caratteristiche lo possiamo definire un Educational Gaming Book (EGB).
"H2O" è un EGB che descrive tutte le caratteristiche dell'acqua, la sostanza formata da molecole di H2O, che attraverso il suo ciclo di vita garantisce la sopravvivenza di tutti gli esseri viventi del Pianeta.
L'obiettivo dell'EGB è quello di far conoscere ai giovani le proprietà dell'acqua, sotto molti aspetti uniche, per sensibilizzarli a salvaguardare un bene comune e raro, indispensabile per la vita.
Per il DOWNLOAD di "H2O" clicca qui.