Skillbook Logo
foto profilo

Skill Factory

Lista post > Impariamo Python giocando al "Solitario del Ferroviere" - Lezione 3

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

 



 

Share Button
TOP