Skillbook Logo
foto profilo

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

 
Per poter implemantare questo algoritmo, prima di tutto bisogna associare l'evento click alle etichette seguenti: 

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

 



 

Share Button
TOP