Tetris en python 2.6

Description

Un petit tetris en python.Lisez le code TetrisPythonPrincipe pour avoir une explication plus exhaustive de la méthode employée.De par la présence du module winsound ne fonctionne que sous windows, cependant lisez le début pour contourner le problème.

Source / Exemple :


################################################################################
#                                 TETRIS                                       #       
#                        en Python pour windows                                #
#           pour les autres os veuillez mettre un '#' devant les lignes        #
#                       13,252,270,354,376,380,466                             #
################################################################################

from Tkinter import *
from time import sleep
from random import randrange
from winsound import *
import pickle

#-------------------------------------------------------------------------------
def initialisation():
    """ Création du tableau de canevas 20 lignes 10 colonnes et de sa matrice
        associée.Création du panneau d'informations.Définition des pièces et de
        leurs positions."""    
    global tab_can,tab_grille,tab_couleur,coord_courante,piece,sens,tab_pieces,\
           nbr_lignes,score,label_score,niveau,label_niveau,can_piece_suivante,\
           top_five,label_topfive,tab_scores,label_noms,label_scores,\
           informations,label_lignes,reliefs,interval,couleur_fond
    #----- Canevas et matrice -------------------------------------------------
    tab_can = []
    tab_grille = []
    tab_couleur = ['wheat','LimeGreen','blue','red','dark green','SteelBlue',\
                 'DarkOrange','navy','LightGoldenrodYellow']
    for i in range(20):
        tab_can.append([[]]*10)
        tab_grille.append([[]]*10)

    grille_jeu = Frame(fen)
    for ligne in range(20):
        for colonne in range(10):
            couleur = tab_couleur[0]
            tab_can[ligne][colonne] = Canvas(grille_jeu,bg=couleur,\
                                        highlightbackground="linen",height=20,\
                                           width=20,borderwidth=1,relief=GROOVE)
            tab_can[ligne][colonne].grid(row=ligne,column=colonne)
            tab_grille[ligne][colonne] = 0
    grille_jeu.grid(row=1,column=0)
    #----- Panneau d'informations ---------------------------------------------
    informations = Frame(fen,bg='DarkCyan',width=150,height=520)

    
    frame_suivante = Frame(informations,bg='DarkRed')
    label_titre = Label(informations,text="TETRIS",
                             fg='DarkOrange',font="Century 18 normal bold",
                                                    bg='DarkCyan')
    label_titre.place(x=22,y=05,width=100,height=40)        
    can_piece_suivante = []
    for i in range(4):
        can_piece_suivante.append([[]]*4)
    for ligne in range(4):
        for colonne in range(4):
            coul = tab_couleur[8]
            can_piece_suivante[ligne][colonne] = Canvas(frame_suivante,bg=coul,\
                                highlightbackground="linen",height=15,width=15,\
                                                    borderwidth=1,relief=GROOVE)
            can_piece_suivante[ligne][colonne].grid(row=ligne,column=colonne)

    label_next = Label(informations,text="SUIVANTE",
                             fg='white',font="Century 9 normal bold",
                                                    bg='DarkCyan')
    label_next.place(x=27,y=50,width=90,height=20)        

    frame_suivante.place(x=30,y=70,width=84,height=84)

    label_score = Label(informations,text="SCORE\n0",
                             fg='white',font="Century 13 normal bold",
                                              bg='CornflowerBlue',relief=RIDGE)
    label_score.place(x=30,y=180,width=90,height=40)

    niveau = 1
    label_niveau = Label(informations,text="NIVEAU\n"+str(niveau),
                             fg='white',font="Century 13 normal bold",
                                                  bg='DarkOrange',relief=RIDGE)
    label_niveau.place(x=30,y=230,width=90,height=40)
    ligne = 0
    label_lignes = Label(informations,text="LIGNES\n"+str(ligne),
                             fg='white',font="Century 13 normal bold",
                                                    bg='SeaGreen',relief=RIDGE)
    label_lignes.place(x=30,y=280,width=90,height=40)    
    #-----
    frame_top5 = Frame(informations,bg='maroon')

    label_top5 = Label(frame_top5,text="TOP 5",fg='white',\
                       font="Century 13 normal bold",bg='maroon',anchor=N,\
                                                               relief=SUNKEN)
    label_top5.pack(expand=NO,fill=BOTH)

    label_noms = Label(frame_top5,fg='white',font="Century 11 normal bold",\
                                           bg='maroon',anchor=NW,relief=SUNKEN)
    label_noms.pack(side=LEFT)

    label_scores = Label(frame_top5,fg='white',font="Century 11 normal bold",
                                 width=6,bg='maroon',anchor=E,relief=SUNKEN)
    label_scores.pack(side=RIGHT)

    frame_top5.place(x=5,y=330,width=140,height=160)

    informations.grid(row=1,column=1)
    #-----
    label_options = Frame(fen,bg='DarkCyan',width=500,height=150)

    MODES=[("Groove",GROOVE),("Ridge",RIDGE)]
    reliefs = StringVar()
    reliefs.set(GROOVE)
    for text,mode in MODES:
        b = Radiobutton(label_options,command=maj_Grille,bg='DarkCyan',
                      activebackground='DarkCyan',text=text,variable=reliefs,
                                                                  value=mode)
        b.pack(anchor=W,side=LEFT)

    interval = IntVar()
    dims = Scale(label_options,from_=1,to=5,length=100,width=5,\
                 orient=HORIZONTAL,tickinterval=1,variable=interval,\
                 command=maj_Grille,bg='DarkCyan',label="Intervalle",\
                 activebackground='DarkCyan',troughcolor='ivory')
    dims.pack(side=LEFT,padx=10)

    couleur_fond = StringVar()
    COUL_FOND=[("Crème","wheat"),("Rosé","Thistle"),("Métal","LightSteelBlue")]    
    couleur_fond.set("wheat")
    for text,couleur in COUL_FOND:
        b = Radiobutton(label_options,command=maj_Grille,bg='DarkCyan',\
                        text=text,activebackground='DarkCyan',\
                        variable=couleur_fond,value=couleur)
        b.pack(anchor=W,side=LEFT)

    label_options.grid(row=0,column=0,columnspan=2,sticky=W+E+N+S)
    #----- Définition des pièces ----------------------------------------------#                                           
    piece1 =[[(0,1,0,0),(0,1,1,0),(0,0,1,0),(0,0,0,0)],#<-1ere position->0 1 0 0
                   [(0,0,0,0),(0,0,1,1),(0,1,1,0),(0,0,0,0)],#<-2eme     0 1 1 0 
                   [(0,1,0,0),(0,1,1,0),(0,0,1,0),(0,0,0,0)],#<-3eme     0 0 1 0 
                   [(0,0,0,0),(0,0,1,1),(0,1,1,0),(0,0,0,0)]]#<-4eme     0 0 0 0

    piece2 = [[(0,2,2,0),(0,2,2,0),(0,0,0,0),(0,0,0,0)],         # 0 2 2 0
                 [(0,2,2,0),(0,2,2,0),(0,0,0,0),(0,0,0,0)],      # 0 2 2 0
                 [(0,2,2,0),(0,2,2,0),(0,0,0,0),(0,0,0,0)],      # 0 0 0 0
                 [(0,2,2,0),(0,2,2,0),(0,0,0,0),(0,0,0,0)]]      # 0 0 0 0

    piece3 = [[(0,3,0,0),(0,3,0,0),(0,3,0,0),(0,3,0,0)],        # 0 3 0 0
                [(3,3,3,3),(0,0,0,0),(0,0,0,0),(0,0,0,0)],      # 0 3 0 0
                [(0,3,0,0),(0,3,0,0),(0,3,0,0),(0,3,0,0)],      # 0 3 0 0
                [(3,3,3,3),(0,0,0,0),(0,0,0,0),(0,0,0,0)]]      # 0 3 0 0

    piece4 = [[(0,0,4,0),(0,4,4,0),(0,4,0,0),(0,0,0,0)],        # 0 0 4 0
                 [(0,0,0,0),(0,4,4,0),(0,0,4,4),(0,0,0,0)],     # 0 4 4 0
                 [(0,0,4,0),(0,4,4,0),(0,4,0,0),(0,0,0,0)],     # 0 4 0 0
                 [(0,0,0,0),(0,4,4,0),(0,0,4,4),(0,0,0,0)]]     # 0 0 0 0

    piece5 = [[(0,5,0,0),(0,5,5,0),(0,5,0,0),(0,0,0,0)],        # 0 5 0 0
                 [(0,0,0,0),(0,0,5,0),(0,5,5,5),(0,0,0,0)],     # 0 5 5 0
                 [(0,0,0,5),(0,0,5,5),(0,0,0,5),(0,0,0,0)],     # 0 5 0 0
                 [(0,5,5,5),(0,0,5,0),(0,0,0,0),(0,0,0,0)]]     # 0 0 0 0

    piece6 = [[(0,0,6,0),(0,0,6,0),(0,6,6,0),(0,0,0,0)],        # 0 0 6 0
                 [(0,0,0,0),(0,6,6,6),(0,0,0,6),(0,0,0,0)],     # 0 0 6 0
                 [(0,6,6,0),(0,6,0,0),(0,6,0,0),(0,0,0,0)],     # 0 6 6 0
                 [(0,0,0,0),(0,6,0,0),(0,6,6,6),(0,0,0,0)]]     # 0 0 0 0

    piece7 = [[(0,7,0,0),(0,7,0,0),(0,7,7,0),(0,0,0,0)],        # 0 7 0 0
                 [(0,0,0,0),(0,0,0,7),(0,7,7,7),(0,0,0,0)],     # 0 7 0 0
                 [(0,7,7,0),(0,0,7,0),(0,0,7,0),(0,0,0,0)],     # 0 7 7 0
                 [(0,0,0,0),(0,7,7,7),(0,7,0,0),(0,0,0,0)]]     # 0 0 0 0

    tab_pieces =(piece1,piece2,piece3,piece4,piece5,piece6,piece7)
    #----- 
    fen.bind('<Right>',droite)
    fen.bind('<Left>',gauche)
    fen.bind('<Up>',tourne)
    fen.bind('<Down>',tombe)    
    fen.bind('<KeyRelease-Down>',tombe_Relache)
    #-----
    tab_scores = [["Nom001",00000],["Nom002",00000],["Nom003",00000],
                                          ["Nom004",00000],["Nom005",00000]]
    #sauve_Top()
    charge_Top()
    maj_Grille()

#-------------------------------------------------------------------------------
def sauve_Top():
    """Sauvegarde du tableau des scores"""
    f = open('top5c','w')
    pickle.dump(tab_scores,f)
    f.close()
             
#-------------------------------------------------------------------------------
def charge_Top():
    """Chargement du tableau des scores"""
    global tab_scores
    
    nom_fichier = "top5c"
    fichier = open(nom_fichier, 'r')
    tab_scores = pickle.load(fichier)
    fichier.close()
    affiche_Scores()
    
#-------------------------------------------------------------------------------
def affiche_Scores():
    """Mise à jour du tableau des scores dans la partie information"""
    noms=""
    scores=""
    for i in tab_scores:
        noms += i[0]+"\n"
        scores += str(i[1])+"\n"
    label_noms.configure(text=noms,justify=LEFT)
    label_scores.configure(text=scores,justify=RIGHT)
    
#-------------------------------------------------------------------------------
def aide():
    """Tirage au hazard d'une pièce mémorisée dans piece_suivante.
       Affichage de cette pièce dans la partie information.Lorsque la pièce
       courante ne peut plus descendre, cette pièce devient la pièce courante"""
    global piece,can_piece_suivante,piece_suivante
    
    index = randrange(0,len(tab_pieces))
    piece_suivante = tab_pieces[index]    
    for i in range(4):
        for j in range(4):
            if piece_suivante[0][i][j] == 0:
                couleur = tab_couleur[8]
            else:
                couleur = tab_couleur[piece_suivante[0][i][j]]
            can_piece_suivante[i][j].configure(bg=couleur)

#-------------------------------------------------------------------------------
def nouvelle_Partie():
    """A chaque nouvelle partie on réinitialise la matrice et certaines
       variables de jeu.On tire au hazard une pièce mémorisée dans
       piece_courante."""
    global piece_courante,piece_suivante,piece_suivante,niveauUp,nbr_lignes,\
           label_score,score,label_niveau,niveau,coord_courante

    barreMenu.entryconfig(1,state=DISABLED)
    for ligne in range(20):
        for colonne in range(10):
            tab_grille[ligne][colonne] = 0

    piece_courante = []
    piece_suivante = []
    niveau = 1
    label_niveau.configure(text="NIVEAU\n"+str(niveau))
    score = 0
    label_score.configure(text="SCORE\n"+str(score))    
    nbr_lignes = 0
    index = randrange(0,len(tab_pieces))
    piece_courante = tab_pieces[index]
    niveauUp = False
    PlaySound("debut.wav",SND_ASYNC)
    nouvelle_Piece(piece_courante)
    
#-------------------------------------------------------------------------------    
def nouvelle_Piece(piece_courante):
    """A chaque nouvelle pièce on réinitialise la coordonnée courante.La piece
       courante devient celle reçue en argument autrement dit la pièce suivante.
       Si son déplacement n'est pas possible la partie est finie."""    
    global coord_courante,piece,sens,vitesse_courante,vitesse,niveau,tab_scores
           
    vitesse_courante = 550 - (niveau*50)
    vitesse = vitesse_courante
    coord_courante = [0,3]
    sens = 0
    piece = piece_courante
    aide()  #<--- Tirage de la pièce suivante

    if not verif_Deplacement(0,0,0):
        PlaySound("perdu.wav",SND_ASYNC)             
        imprime_Piece(sens)
        if score > tab_scores[4][1]:
            nouveau_score()
        barreMenu.entryconfig(1,state=ACTIVE)
    else :
        imprime_Piece(sens)
        sleep(1)
        descente()

#-------------------------------------------------------------------------------
def nouveau_score():
    """Appelée lorsque le score du joueur actuel dépasse le 5ème du tableau des
       scores."""
    global nom,tab_scores,entree,fen2

    nom = "new"
    fen2 = Toplevel(bg='Maroon')
    fen2.iconbitmap("Tetris_icone.ico")
    fen2.geometry(pos)
    fen2.wait_visibility()
    fen2.grab_set()
    fen2.transient(fen)
    fen2.focus_force()
    lbl = Label(fen2,text="Félicitations ! Vous faites partie du TOP5\n\
    Veuillez saisir votre nom svp(6caractères max):",fg='White',bg='maroon'\
                                                                    ,width=60)
    lbl.pack()
    entree = Entry(fen2,width=30)
    entree.bind('<Return>',recup_nom)
    entree.pack()
    fen.wait_window(fen2) #Attente de la destruction de fen2 avant de poursuivre
    new = [nom,score]
    tab_scores.append(new)
    tab_scores_range = sorted(tab_scores, key=lambda tab_scores: tab_scores[1],
                                                                   reverse=TRUE)
    tab_scores = tab_scores_range[:]
    del tab_scores[-1]
    affiche_Scores()
    sauve_Top()

#-------------------------------------------------------------------------------
def recup_nom(event):
    """Récupération des 6 premières lettres du widget entree."""
    global nom,fen2

    saisie = entree.get()
    nom = saisie[:6]
    fen2.destroy()
    
#-------------------------------------------------------------------------------
def imprime_Piece(sens):
    """On imprime la pièce dans la matrice par rapport à sa coordonnée
       courante."""
    for i in range(4):
        for j in range(len(piece)):
            if piece[sens][i][j] == 0:
                continue                
            tab_grille[coord_courante[0]+i][coord_courante[1]+j] =\
                                                            piece[sens][i][j]
    maj_Grille()

#-------------------------------------------------------------------------------
def tombe(event):
    """Touche BAS appuyée : augmentation de la vitesse."""
    global vitesse

    vitesse = 10

#-------------------------------------------------------------------------------
def tombe_Relache(event):
    """Touche BAS relachée : la vitesse prend sa valeur déterminée par le
       niveau."""
    global vitesse,vitesse_courante

    vitesse = vitesse_courante
    
#-------------------------------------------------------------------------------
def tourne(event):
    """Touche HAUT : si c'est possible la pièce tourne."""
    global sens
    
    efface_Piece()
    if verif_Deplacement(0,0,1):
        PlaySound("pieceTournee.wav",SND_ASYNC)        
        sens += 1
        if sens == 4:
            sens = 0
        imprime_Piece(sens)
    else:
        imprime_Piece(sens)

#-------------------------------------------------------------------------------    
def descente():
    """Appelée dès la mise en place d'une nouvelle pièce, cette méthode est
       chargée de la faire descendre ligne par ligne si c'est possible.Sinon
       on appelle nouvelle_Piece avec piece_suivante en parametre."""
    global piece_suivante,niveauUp,vitesse

    efface_Piece()
    if verif_Deplacement(1,0,0):
        coord_courante[0] += 1
        imprime_Piece(sens)
        fen.after(vitesse,descente)

    else :
        PlaySound("pieceTombee.wav",SND_ASYNC)
        imprime_Piece(sens)
        verif_Ligne()
        if niveauUp:
            PlaySound("niveauUp.wav",SND_ASYNC)  
            for i in range (5):
                fen.after(100,anim_Level('red'))
                fen.update()
                fen.after(100,anim_Level('DarkOrange'))
                fen.update()
            label_niveau.configure(text="NIVEAU\n"+str(niveau))
            niveauUp = False
        nouvelle_Piece(piece_suivante)
        
#-------------------------------------------------------------------------------
def anim_Level(coul):
    """Petite animation quand le niveau monte."""
    label_niveau.configure(bg=coul)
        
#-------------------------------------------------------------------------------
def gauche(event):
    """Touche GAUCHE : si c'est possible la pièce se déplace d'une colonne
       vers la gauche."""
    efface_Piece()
    if verif_Deplacement(0,-1,0):
        coord_courante[1] -=1
        imprime_Piece(sens)
    else:
        imprime_Piece(sens)
    return

#-------------------------------------------------------------------------------
def droite(event):
    """Touche DROITE : si c'est possible la pièce se déplace d'une colonne
       vers la droite."""
    efface_Piece()
    if verif_Deplacement(0,1,0):
        coord_courante[1] += 1
        imprime_Piece(sens)
    else:
        imprime_Piece(sens)
    return

#-------------------------------------------------------------------------------
def efface_Piece():
    """On efface la pièce de la matrice par rapport à sa coordonnée courante."""
    for i in range(4):
        for j in range(4):
            if piece[sens][i][j] == 0:
                continue
            tab_grille[coord_courante[0]+i][coord_courante[1]+j] = 0

#-------------------------------------------------------------------------------            
def verif_Deplacement(dx,dy,pivot):
    """Appelée avant chaque déplacement, cette méthode vérifie si la pièce ne
       débordera pas de la matrice.Si c'est la cas on renvoit un déplacement non
       possible à la méthode appelante.Si non, on test si elle ne chevauchera
       pas des blocs déja présent."""
    rotation = sens + pivot
    if rotation == 4:
        rotation = 0
    for i in range(4):
        for j in range(4):
            if coord_courante[1]+(dy+j) > 9 or coord_courante[1]+(dy+j) < 0 or\
                                                   coord_courante[0]+(dx+i) >19:
                if piece[rotation][i][j] != 0:
                    return False
                else:
                    continue
            if (piece[rotation][i][j] * tab_grille[coord_courante[0]+(dx+i)]\
                                                [coord_courante[1]+j+dy]) != 0:
                return False
    return True

#-------------------------------------------------------------------------------
def verif_Ligne():
    """Quand une pièce est posée on verifie par récursivité en partant du bas
       la ou les lignes contigues complètes."""
    global memoire,compt,nbr_lignes,score,label_score,niveau,label_niveau,\
                                                    label_lignes,niveauUp

    bonus = 0
    points = 0
    memoire =[]
    for i in range(19,-1,-1):
        ligne_complete = True
        for j in range(10):
            if tab_grille[i][j] == 0:
                ligne_complete = False
                if memoire != []:
                    PlaySound("ligneComplete3.wav",SND_ASYNC)
                    compt = 0
                    if animation_Ligne(i+1,memoire):
                        sleep(0.5)
                        for k in range(len(memoire)):
                            points += ((i+1)+k)*10
                            del tab_grille[(i+1)+k]
                            tab_grille[0:0]=0,0,0,0,0,0,0,0,0,0
                        maj_Grille()
                        score += points*bonus
                        label_score.configure(text="SCORE\n"+str(score))
                        label_lignes.configure(text="LIGNES\n"+str(nbr_lignes))                        
                    verif_Ligne()

        if ligne_complete:
            memoire.append(tab_grille[i])
            bonus += 1
            nbr_lignes += 1
            if nbr_lignes%20 == 0:
                niveau += 1
                niveauUp = True

#-------------------------------------------------------------------------------
def animation_Ligne(index,ligne):
    """Petite animation de la ou les lignes contigues complétées."""
    global compt,memoire

    if compt%2 == 0:
        ligne = 0,0,0,0,0,0,0,0,0,0 *len(ligne)
    else:
        ligne = memoire[:]

    for i in range(len(ligne)):
        tab_grille[index+i] = ligne[i]    
    maj_Grille()
    compt += 1
    if compt == 6:
        return True
    sleep(0.2)
    animation_Ligne(index,ligne)

    return True

#-------------------------------------------------------------------------------    
def maj_Grille(x=1):
    """Mise a jour des canevas en fonction des options et des couleurs
       référencées par les valeurs de la matrice."""
    tab_interval = [(20,20,1),(18,18,2),(16,16,3),(14,14,4),(12,12,5)]
    tab_couleur[0] = couleur_fond.get()
    for ligne in range(20):
        for colonne in range(10):
            couleur = tab_couleur[tab_grille[ligne][colonne]]
            tab_can[ligne][colonne].configure(bg=couleur,relief=reliefs.get(),
                width=tab_interval[interval.get()-1][0],
                 height=tab_interval[interval.get()-1][1],
                 borderwidth=tab_interval[interval.get()-1][2])

    fen.update()

def a_Propos():
    fen3 = Toplevel(bg='Maroon')
    fen3.resizable(0,0)
    fen3.iconbitmap("Tetris_icone.ico")
    fen3.geometry(pos)
    fen3.wait_visibility()
    fen3.grab_set()
    fen3.transient(fen)
    fen3.focus_force()
    lbl = Label(fen3,text="Calcul des points:\n\
La grille contenant 20 lignes,une ligne complète vaut en points sa position\
dans la grille.\nLorsque des lignes sont contigües, on additionne leure\
position et on multiplie la somme\npar le nombre de lignes se juxtaposant",\
                fg='White',bg='maroon',width=70,justify=LEFT,anchor=W)
    lbl.pack()
fen = Tk()
fen.title("Tetris")
fen.iconbitmap("Tetris_icone.ico")
fen.resizable(0,0)
barreMenu = Menu(fen)
options = Menu(barreMenu)
barreMenu.add_cascade(label="Jeu",menu=options,state=ACTIVE)
options.add_command(label = "Nouvelle Partie",command=nouvelle_Partie)
options.add_command(label = "Quitter",command=fen.destroy)
info = Menu(barreMenu)
barreMenu.add_cascade(label="?",menu=info,state=ACTIVE)
info.add_command(label="Calcul des points",command=a_Propos)
fen.config(menu=barreMenu)
print fen.winfo_screenwidth()
print fen.winfo_screenheight()
initialisation()
print fen.geometry()
hauteur = fen.winfo_height()
largeur = fen.winfo_width()
fen.winfo_screenwidth()
pos_x = str(((fen.winfo_screenwidth()-largeur)/2)-100)
pos_y = str(((fen.winfo_screenheight()-hauteur)/2)-100)
fen.winfo_width()
pos = '+' + pos_x + '+' + pos_y
fen.geometry(pos)
fen.mainloop()

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.