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