Jeu pygame fonction ex
Résolu
Bonjour,
J'ai trouvé un jeu pygame sur le net qui, lorsque l’on clique sur une case, inverse son fond et celui des cases adjacentes :
Le but du jeu est donc d'obtenir un damier dont toutes les cases sont de la même couleur.
Le problème c'est que je n'ai pas compris deux fonctions notamment la plus longue (
Voici le code:
J'ai trouvé un jeu pygame sur le net qui, lorsque l’on clique sur une case, inverse son fond et celui des cases adjacentes :
- si la case est en milieu de damier, son fond change ainsi que celui des 8 cases qui l'entourent ;
- si la case est le long d'un bord mais pas dans un coin du damier, son fond change ainsi que celui des 5 cases qui l'entourent ;
- si la case est dans un coin du damier, son fond change ainsi que celui des 3 cases qui l'entourent.
Le but du jeu est donc d'obtenir un damier dont toutes les cases sont de la même couleur.
Le problème c'est que je n'ai pas compris deux fonctions notamment la plus longue (
execute) si quelqu'un pourrait bien me les expliquer merci!
Voici le code:
import pygame
from pygame.locals import *
import numpy as np
import pickle ##pour enregistrer les solutions connues
#ATTENTION POUR TESTER LE JEU IL FAUT CLIQUER SUR START
class Le_Jeu(object):
def __init__(self, largeur=1200, hauteur=800, fps=60):
"""Initialiser pygame, fenêtre, arrière-plan, police,...
arguments par défaut
"""
pygame.init()
pygame.display.set_caption("Le jeu du casse tête")
self.largeur = largeur
self.hauteur = hauteur
self.screen = pygame.display.set_mode((self.largeur, self.hauteur), pygame.DOUBLEBUF)
self.background = pygame.Surface(self.screen.get_size()).convert()
self.background.fill((255,255,255)) # arrière plan blanc
self.clock = pygame.time.Clock()
self.fps = fps
self.playtime = 0.0
self.font = pygame.font.SysFont('mono', 24, bold=True)
self.initialMat = np.zeros((8,8)).astype(int)
# ------------- création des boutons initiaux ----------
button = self.font.render('Solve', True, (0,255,0), (0,0,128))#nous n'avons malheuresement pas réussi cette fonction qui permettrait de résoudre automatiquement le jeu
buttonRect = button.get_rect()
buttonRect.center = (500,500)
self.background.blit(button,buttonRect)
for num in range(4,9):
numButton = self.font.render(' '+ str(num) + ' ',True,(0,255,0), (0,0,128))
numButtonRect = numButton.get_rect()
numButtonRect.center = (-150 + 50*num, 500)
self.background.blit(numButton,numButtonRect)
mess = self.font.render('Choisir la taille', True, (0,0,0), (255,255,255))
messRect = mess.get_rect()
messRect.center = (150,470)
self.background.blit(mess,messRect)
randButton = self.font.render('Random', True, (0,255,0),(0,0,128))
randRect = randButton.get_rect()
randRect.center = (340,500)
self.background.blit(randButton,randRect)
setupButton = self.font.render('START', True, (0,255,255), (250,0,250))
setupRect = setupButton.get_rect()
setupRect.center = (425,500)
self.background.blit(setupButton,setupRect)
def verification(self,Mat = np.zeros((5,5))):
##Vérifie si le jeu peut être résolue
size = np.sqrt(len(Mat))
if size == 4:
verif1 = np.array([1,0,0,0, 1,1,0,0, 1,0,1,0, 0,1,1,1])
verif2 = np.array([0,0,0,1, 0,0,1,1, 0,1,0,1, 1,1,1,0])
verif3 = np.array([0,1,0,0, 1,1,1,0, 0,0,0,1, 1,1,0,1])
verif4 = np.array([0,0,1,0, 0,1,1,1, 1,0,0,0, 1,0,1,1])
if np.dot(Mat,verif1)%2>0 or np.dot(Mat,verif2)%2>0 or np.dot(Mat,verif3)%2>0 or np.dot(Mat,verif4)%2>0:
return False
else:
return True
elif size == 5:
verif1 = np.array([0,1,1,1,0, 1,0,1,0,1, 1,1,0,1,1, 1,0,1,0,1, 0,1,1,1,0])
verif2 = np.array([1,0,1,0,1, 1,0,1,0,1, 0,0,0,0,0, 1,0,1,0,1, 1,0,1,0,1])
if np.dot(Mat,verif1)%2>0 or np.dot(Mat,verif2)%2>0:
return False
else:
return True
else:
return True
JE N'AI PAS COMPRIS CELLE CI
def Choisir(self,sz = 5):
##Pas tout les puzzles ne sont solubles, alors choisir seulement un qui l'est##
randMat = np.random.randint(2,size=sz*sz)
while self.verification(Mat = randMat) == False:
randMat = np.random.randint(2,size=sz*sz)
randMat = randMat.reshape((sz,sz))
return randMat
def verif_victoire(self, flag, Mat = np.ones((5,5))):
size = len(Mat)
if flag == True:
for i in range(size):
if flag == True:
for j in range(size):
if Mat[i,j]==1:
flag = False
break
return flag
def paintInit(self, Mat = np.ones((5,5)), sM = np.zeros((5,5))):
'''peindre les cases initiales'''
size = len(Mat)
shift = size + 2
for ligne in range(size):
for col in range(size):
mycell = Cell(col=col, ligne=ligne, color=(0,255*Mat[ligne,col],255),
background=self.background)
mycell.blit(self.background)
solcell = Cell(col=col+shift, ligne=ligne, color=(255*sM[ligne,col],0,255),
background=self.background)
solcell.blit(self.background)
def paintPuz(self,Mat = np.ones((5,5))):
'''peindre le puzzle'''
size = len(Mat)
for ligne in range(size):
for col in range(size):
mycell = Cell(col=col, ligne=ligne,
color=(255*Mat[ligne,col],255*Mat[ligne,col],255*(1-Mat[ligne,col])),
background=self.background)
mycell.blit(self.background)
def paint(self,col=0, ligne=0, color=(0,0,255)):
"""mettre à jour une seule cellule"""
#------- Test de fonctions trouver sur internet --------
# pygame.draw.line(Surface, color, start, end, width)
# pygame.draw.rect(Surface, color, Rect, width=0): return Rect
#pygame.draw.rect(self.background, (0,255,0), (50,50,100,25)) # rect: (x1, y1, width, height)
# pygame.draw.circle(Surface, color, pos, radius, width=0): return Rect
# pygame.draw.polygon(Surface, color, pointlist, width=0): return Rect
# pygame.draw.arc(Surface, color, Rect, start_angle, stop_angle, width=1): return Rect
# ------------------- blitting a cell --------------
mycell = Cell(col=col,ligne=ligne,color=color,background=self.background)
mycell.blit(self.background)
def cliquable(self, ligne, col, M = np.ones((5,5)),sM = np.zeros((5,5))):
size = len(M)
shift = size + 2
if ligne>=size or col >=size:
pass
else:
for i in range(size):
for j in range(size):
if (np.abs(ligne-i)<2 and col==j) or (ligne==i and np.abs(col-j)<2):
M[i,j] = (M[i,j]+1)%2
self.paint(ligne=i,col=j,color=(0,255*M[i,j],255))
sM[ligne,col] = sM[ligne,col]+1
##peindre la cellule sur laquelle vous avez cliqué dans la solution
self.paint(col=col+shift,ligne=ligne,color=(255*(sM[ligne,col]%2),0,255))
return M, sM
def alterne(self, ligne, col, M = np.ones((5,5))):
size = len(M)
if ligne>=size or col >=size:
pass
else:
M[ligne,col] = (M[ligne,col]+1)%2 ##alterne la lumière
self.paint(ligne=ligne,col=col,color=(0,255*M[ligne,col],255))
return M
def dernière_ligne(self, M=np.ones((5,5))):
##création d'une chaîne dans la dernière colonne
size = len(M)
arr = ''
for j in range(size):
arr = arr + str(M[-1,j])
return arr
def iterate(self, i, j, step2, size):
if j<size-1:
j += 1
elif step2 == True:
j = 0
step2 = False
else:
i += 1
j = 0
if i == size-1:
step2 = True
return i, j, step2
## JE N'EST PAS COMPRIS CELLE CI
def execute(self):
"""la boucle principale"""
#matrix = self.ChooseInitBoard(sz=8)
initMat = np.zeros((8,8))
matrix = np.zeros((8,8))
size = matrix.shape[0]
solMatrix = np.zeros((size,size)) ## garder une trace des boutons enfoncés dans le travail pour résoudre
self.paintInit(Mat=matrix, sM=solMatrix)
running = True
setup = True ##False lorsque l'utilisateur a terminer l'installation
stop = False ##True lorsque le chrono doit s'arrêter
solving = False ##True lorsque le processus de résolution est en cours d'execution
step2 = False ##True pour signifier l’étape 2 du processus de résolution
errorMes = False ##True lorsque le message d’erreur est visible
finalRow = ''
attempt = '' ##tentative de solution si la solution est inconnue
while running:
ligne = -1
col = -1
pos = []
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
elif event.type == pygame.MOUSEBUTTONUP:
errorMes = False
pos = pygame.mouse.get_pos()
#print(pos)
if 5<=pos[0]%55 and 5<=pos[1]%55: ##assurez-vous que le clic n’est pas sur une limite
ligne = pos[1]//55
col = pos[0]//55
if setup == True and len(pos)>0:
if pos[1]<450: ##il pourrait être sur une cellule
matrix = self.alterne(ligne,col,matrix)
elif 485<=pos[1]<=515: ##il pourrait être sur un boutton
if 300<=pos[0]<=385: ##c'est le bouton "aléatoire"
matrix = self.Choisirlatailleinitiale(sz=size)
self.paintInit(Mat = matrix, sM = solMatrix)
elif 390<=pos[0]<=460: ##c'est le bouton "commencer"
if self.verification(Mat=matrix.reshape(matrix.size,)):
setup = False
print('Out of Setup Mode')
initMat = matrix.astype(int)
matrix = matrix.astype(int)
self.clock = pygame.time.Clock()
stop = False ##Commencer le temps
else: ##ne permettent pas à l’utilisateur de définir un modèle insoluble
errorMes = True
else: #s'assurer si on clique bien sur un nombre
for num in range(4,9):
if -170+50*num<=pos[0]<=-130+50*num:
size = num
matrix = np.zeros((num,num))
solMatrix = np.zeros((num,num))
whitescreen = pygame.draw.rect(self.background, (255,255,255), (0,0,1000,450))
self.paintInit(Mat = matrix, sM = solMatrix)
break ##peut juste cliquer sur un bouton à la fois
elif solving == False and len(pos)>0:
##n’autorise pas le clic pendant qu’il est en cours de résolution##
if 460<=pos[0]<=540 and 485<=pos[1]<=515: ##puis on clique sur le bouton résoudre
solving = True
#définir la position initiale de l’algorithme de résolution#
i=0
j=0
elif ligne>=0 and col>=0:
#print(ligne,col)
matrix, solMatrix = self.cliquable(ligne, col, matrix, solMatrix)
if solving == True:
##passer par l’étape suivante du processus de résolution##
if i == 0 and step2 == True:
if attempt[j]=='1':
matrix, solMatrix = self.cliquable(ligne=i,col=j,M=matrix, sM=solMatrix)
elif i<size-1: ##ensuite, nous exécutant la première partie de l’algorithme
##si une lumière est allumée, utilisez la ligne suivante vers le bas pour l’effacer
if matrix[i,j] == 1:
matrix, solMatrix = self.cliquable(ligne=i+1,col=j,M=matrix, sM=solMatrix)
elif i == size-1:
##lorsque vous atteignez la dernière ligne, obtenez une chaîne pour l’arrangement
temp = self.dernière_ligne(M = matrix)
if '1' in temp: ##si nous n’avons pas encore fini de résoudre
if len(finalRow) == len(temp):
diff = '' ##mesurer la différence entre la dernière ligne précédente et la nouvelle
for ch in range(len(finalRow)):
diff = diff + str((int(temp[ch]) - int(finalRow[ch]))%2)
if diff not in KnownSols:
KnownSols[diff] = attempt
## enregistrer les solutions connus ##
with open('KS.p', 'wb') as fp:
pickle.dump(KnownSols, fp, protocol=pickle.HIGHEST_PROTOCOL)
finalRow = temp
print('Dernière ligne: ', finalRow)
if finalRow in KnownSols:
attempt = KnownSols[finalRow]
else: ##choisissez une sélection aléatoire de boutons à appuyer dans la ligne supérieure
attempt = ''
while '1' not in attempt and attempt not in KnownSols.values():
attempt = ''
for i in range(size):
attempt = attempt + str(np.random.randint(0,2))
step2 = True
i=0
j=-1
print('Attempt: ', attempt)
else: ##si nous avons terminé, ajoutez les informations au dictionnaire si elles sont manquantes
résoudre = False
if finalRow not in KnownSols:
KnownSols[finalRow] = attempt
## enregistrer les solution connu##
with open('KS.p', 'wb') as fp:
pickle.dump(KnownSols, fp, protocol=pickle.HIGHEST_PROTOCOL)
i,j,step2 = self.iterate(i,j,step2,size)
if stop == False:
if self.verif_victoire(True, Mat = matrix): #checkflag == True:
print('Victoire!!')
stop = True
if self.playtime != 0: ##si le jeu a réellement commencer
setup = True
self.paintPuz(Mat = initMat)
else:
#CREATION D'UN CHRONOMETRE (perso)
milliseconds = self.clock.tick(self.fps)
self.playtime += milliseconds / 1000.0
self.draw_text("Cliques: {:6.4}{}TEMPS DE JEU: {:6.4} SECONDES".format(np.sum(solMatrix), " "*5, self.playtime))
self.draw_text("Cliques Min: {:6.3}".format(np.sum(solMatrix%2)), loc=(50,570))
self.draw_text("Cases initialement cliqué", loc=((2.7*size/2)*55,(size+0.5)*55))
if errorMes == True:
self.draw_text("Error: Modèle insoluble", loc = (50,520), color = (255,0,0))
pygame.display.flip()
self.screen.blit(self.background, (0, 0))
pygame.quit()
def draw_text(self, text,loc=(50,550), color=(0,0,0)):
"""Centrer le texte dans la fenêtre
"""
fw, fh = self.font.size(text)
surface = self.font.render(text, True, color)
self.screen.blit(surface, loc)
class Cell(object):
"""Ceci est censé être une méthode pour créer une seule cellule"""
def __init__(self, length = 50, col = 0, ligne = 0, color=(0,0,255),
background = pygame.Surface((600,600))):
self.length = length
self.x = col*55
self.y = ligne*55
self.color = color
self.surface = background
##création de l’arrière-plan de la cellule##
pygame.draw.rect(self.surface, (0,0,1), (self.x,self.y,self.length+10, self.length+10))
## création de la cellule##
pygame.draw.rect(self.surface, self.color, (self.x+5, self.y+5, self.length, self.length))
self.surface = self.surface.convert()
def blit(self,background):#dessine une image sur une autre
background.blit(self.surface, (0,0))##dessine une surface source sur cette surface
class Victoire():
"""
Documentation :
Description : La classe Victoire affiche une fenêtre popup lorsque le joueur arrive à gagner la partie
Méthodes :
-__init__() : initialisation de la fenêtre (méthode de base) : crée une popup qui nous affiche un message de victoire et le nombre de click total
Arguments :
Aucun argument nécessaire
"""
def __init__(self):
global nb_clicks
Tk().wm_withdraw() # to hide the main window
messagebox.showinfo('Bravo !' , 'Félicitations, vous avez gagné la partie avec' + str(nb_clicks) + 'clicks !' )
####
if __name__ == '__main__':
# appel avec largeur de fenêtre et fps
Le_Jeu().execute()
Configuration: Windows / Firefox 94.0
A voir également:
- Jeu pygame fonction ex
- Fonction si et - Guide
- Money manager ex - Télécharger - Bourse & Finance
- 94 jeu - Télécharger - Puzzle & Réflexion
- 94 degrés jeu - Télécharger - Divers Jeux
- Jeu zuma - Télécharger - Jeux vidéo
1 réponse
Bonjour,
La fonction
La fonction
Bon après je trouve le programme parfois peu lisible, pas toujours bien architecturé et donc pas forcément idéal pour débuter ou apprendre à bien programmer, notamment car il comporte plusieurs fautes d'orthographe ou vis-à-vis des conventions python PEP8.
Un exemple plus simple est proposé ici et c'est là qu'on voit que pygame est assez limité pour faire des boutons. Si tu prends des modules comme PyQT ou GTK, tu peux créer de "vrais" boutons et lancer du code en fonction des événements qu'ils lèvent (e.g. quand on clique dessus). Cela te permettrait d'avoir un code bien plus lisible, modulaire, et qui distingue mieux la partie interface graphique et le moteur du jeu (voir architecture MVC).
Bonne chance
La fonction
Choisirtire aléatoirement une configuration de départ (certaines cases seront noires, d'autre blanches). Mais d'après l'auteur, certaines configurations ne peuvent pas être résolues, donc plutôt que de proposer un problème insoluble au joueur, il contrôle si le puzzle peut être résolu et tire une nouvelle configuration si ça n'est pas le cas. Les détails de cette vérification sont réalisés dans la méthode
verification.
La fonction
executealors je vais expliquer en gros. Si tu veux des explications détaillées, n'hésite pas à regarder dans la documentation de
numpy/
pickle/
pygame.
- l181-193 : on initialise les différentes variables du jeu ;
- l194 : on lance la boucle qui maintient le programme ouvert (jusqu'à ce qu'il soit quitté) ;
- l198 : on réagit sur un événement pygame (e.g. le joueur a cliqué ou utilisé son clavier) ;
- l199-205 : le joueur veut quitter le jeu (il a cliqué sur la croix, appuyé sur echap, etc), on bascule la variable
running
àFalse
ce qui va sortir de la boucle amorcée l194. - l205-211 : le joueur a relâché le clic de la souris, on relève la position du curseur et on déduit la ligne et la colonne de la casée sélectionnée ;
- l212 : en gros si j'ai bien compris, il y a deux "affichages" (en fonction des valeurs de
setup
etsolving
), celui qui correspond à la configuraiton et celui qui sert à jouer ; - l212 à 237, on gère la partie configuration (les commentaires parlent d'eux mêmes). Le code est assez compliqué, mais en gros, en fonction de la position de la souris, on sait sur quoi l'utilisateur à cliqué et on réagit en conséquence (ça aurait été plus simple et plus lisibles en utilisant des vrais boutons) ;
- Bon là je passe un peu car c'est assez peu lisible et intéressant :-D
- l290: on sauve les résultats dans un fichier pickle ;
- l295-300: on vérifie si le problème est résolu ;
- l301-304: on met à jour le chronomètre ;
- l305-307: on affiche quelques statistiques ;
- l315: on est sorti de la boucle, on quitte.
Bon après je trouve le programme parfois peu lisible, pas toujours bien architecturé et donc pas forcément idéal pour débuter ou apprendre à bien programmer, notamment car il comporte plusieurs fautes d'orthographe ou vis-à-vis des conventions python PEP8.
Un exemple plus simple est proposé ici et c'est là qu'on voit que pygame est assez limité pour faire des boutons. Si tu prends des modules comme PyQT ou GTK, tu peux créer de "vrais" boutons et lancer du code en fonction des événements qu'ils lèvent (e.g. quand on clique dessus). Cela te permettrait d'avoir un code bien plus lisible, modulaire, et qui distingue mieux la partie interface graphique et le moteur du jeu (voir architecture MVC).
Bonne chance