Je suis débutant et je me suis mis comme défi de créer un Game of Life avec des fonctionnalité de base.
J'ai créer la majeur partie du programme mais il reste un problème.
Le moteur du jeu qui dois mettre à jour un tableau avec les rêgle de Conway ne fonctionne pas et met à jour n'importe comment.
J'ai essayer de chercher sur internet mais aucunne solution répond à ma question.
# Pour l'interface graphique
from tkinter import *
import random
#Dimension matrice
width = 50
height = 50
# Taille pixels à l'écran (en pixels)
size_pix = 12
#Tableaux des pixels en 2D
matrix = [[0 for i in range(width)] for j in range(height)]
matrix2 = [[0 for i in range(width)] for j in range(height)]
# Couleurs
colors = ["white", "blue"]
# gestion de la pause (par defaut, le jeu est en pause)
pause = True
# vitesse de la simulation
speed = 100
# dernière pixel modifier (pour éviter de faire clignoter le pixel quand on clique dessus)
last_click = [0, 0]
# nombre de pas de la simulation
steps = 0
#-------------------------Espace pour le moteur du jeu-------------------------
def Display(matrix):
# on met à jour le nombre de pas
label_step.config(text="Steps: " + str(steps))
# en éfface tout les pixels
Canvas.delete(ALL)
# et on les retraces
for i in range(height):
for j in range(width):
#Si la case est vivante (1), on dessine un carré noir
if matrix[i][j] == 1:
Canvas.create_rectangle(j * size_pix + 2, i * size_pix + 2, (j + 1) * size_pix + 2, (i + 1) * size_pix + 2, fill=colors[1], outline="black")
#Si la case est morte (0), on dessine un carré blanc
else:
Canvas.create_rectangle(j * size_pix + 2, i * size_pix + 2, (j + 1) * size_pix + 2, (i + 1) * size_pix + 2, fill=colors[0], outline="black")
def Break():
global pause
pause = not pause
#on relance le moteur du jeu
if not pause:
Engine(False)
def Step():
global pause
if pause:
pause = False
Engine(True)
def Reset():
global matrix, matrix2, width, height
matrix = [[0 for i in range(width)] for j in range(height)]
matrix2 = matrix.copy()
Display(matrix)
def RandomFill():
global matrix, matrix2, width, height
for i in range(height):
for j in range(width):
matrix[i][j] = random.randint(0, 1)
matrix2 = matrix.copy()
Display(matrix)
# fonction pour ajouter une cellule
def addCell(event):
global last_click
pos_x = int(event.x / size_pix)
pos_y = int(event.y / size_pix)
# on évite les débordements
if pos_x >= 0 and pos_x < width and pos_y >= 0 and pos_y < height:
if last_click != [pos_x, pos_y]:
if matrix[pos_y][pos_x] == 0:
matrix[pos_y][pos_x] = 1
else:
matrix[pos_y][pos_x] = 0
Display(matrix)
last_click = [pos_x, pos_y]
def Foreach(matrix, x, y):
global width, height
sum = 0
# on va partire du principe que comme la taille de la matrice est de 50x50,
# on ne va pas cosidére que le monde est torique (tu entre d'un coté et tu sort de l'autre)
for i in range(x - 1, x + 2):
for j in range(y - 1, y + 2):
# on évite les débordements
if i >= 0 and i < width and j >= 0 and j < height:
# on évite de faire la somme de la case sur laquelle on est
if not (i == x and j == y):
sum += matrix[j][i]
return sum
def Engine(step = False):
global matrix, matrix2, width, height, speed, pause, steps
# si on est en pause, on ne fait rien
if not pause:
steps += 1
for i in range(height):
for j in range(width):
sum = Foreach(matrix, j, i)
if sum == 3:
matrix2[i][j] = 1
elif sum == 2:
matrix2[i][j] = matrix[i][j]
elif sum < 2 or sum > 3:
matrix2[i][j] = 0
matrix = matrix2.copy()
Display(matrix)
# appele de la fonction Engine après un certain temps (fonction TKinter)
# si on dois faire un pas on ne rappelle pas la fonction Engine et on met en pause
if step:
pause = True
else:
window.after(speed, Engine)
#--------------------------Espace interface graphique--------------------------
window = Tk()
# Tire de la fenêtre
window.title("Game of Life")
# Taille de la fenêtre (x, y)
window.size = (width * size_pix + 51, height * size_pix + 51)
# Couleur de la fenêtre (format hexadécimal pour plus de couleur)
window.configure(background="#e4e4e4")
#Décalage de 2 pour la bordure des pixels s'affiche bien
Canvas = Canvas(window, bg="white", height=height * size_pix + 1, width=width * size_pix + 1)
Canvas.pack(padx=5, pady=5)
#--------------------------Espace gestion des événements--------------------------
# clic/drag gauche
Canvas.bind("<Button-1>", addCell)
Canvas.bind("<B1-Motion>", addCell)
bouton_break = Button(window, text="Break", command=Break)
bouton_break.pack(side=LEFT, padx=5, pady=5)
bouton_step = Button(window, text="Step", command=Step)
bouton_step.pack(side=LEFT, padx=5, pady=5)
label_step = Label(window, text="Steps : 0")
label_step.pack(side=LEFT, padx=5, pady=5)
bouton_reset = Button(window, text="Reset", command=Reset)
bouton_reset.pack(side=LEFT, padx=5, pady=5)
bouton_random = Button(window, text="Random", command=RandomFill)
bouton_random.pack(side=LEFT, padx=5, pady=5)
bouton_qui = Button(window, text="Quit", command=quit)
bouton_qui.pack(side=RIGHT, padx=5, pady=5)
# fonction pricipale du programme
def main():
# appele de la fonction Display pour afficher la matrice
Display(matrix)
# appele de la fonction Engine pour lancer le moteur du jeu
Engine(False)
# Démmarage du jeu
main()
#boucle principale
window.mainloop()
J'ai trouvé ceci en français: https://fr.wikipedia.org/wiki/Jeu_de_la_vie Je n'ai pas eu le courage de regarder ton code ... Il faut fonctionner avec deux grilles, l'ancienne et la nouvelle. Le plus compliqué en général est de tester tous les voisins. compte = 0 for x, y in ((-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)): if 0 <= i+x < len(grille) and 0 <= j+y < len(grille[0]): compte += grille[i+x][j+y] # je suppose 1 pour les vivants et 0 pour les morts # on teste compte et on modifie dans la nouvelle grille
J'utiliserais deepcopy au lieu de copy
Méthode de paresseux pour modifier dans la nouvelle grille: grille2[i][j] = {0: {3: 1}, 1: {2: 1, 3: 1}}[grille[i][j]].get(compte, 0)
edit: Si on ramène sur la ligne suivante la définition de chaque ligne, on peut mettre tout sur une seule ligne. On peut redéfinir la matrice avec une seule ligne, et pas besoin d'une seconde matrice. Le processus peut boucler indéfiniment si on se retrouve avec des îlots du genre: 1 1 1 1 - voisins=((-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)) compte=sum(grille[i+x][j+y] for x, y in voisins if 0<=i+x<height and 0<=j+y<width) update={0: {3: 1}, 1: {2: 1, 3: 1}}[grille[i][j]].get(compte, 0) grille = [[update for j in range(width)] for i in range(height)] - height=4 width=4 grille = [[1 for j in range(width)] for i in range(height)] grille = [[{0: {3: 1}, 1: {2: 1, 3: 1}}[grille[i][j]].get(sum(grille[i+x][j+y] for x, y in ((-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)) if 0<=i+x<height and 0<=j+y<width), 0) for j in range(width)] for i in range(height)] print(grille)
Voici ce que ça donne, et c'est ce à quoi on s'attend: [[1, 0, 0, 1], [0, 0, 0, 0], [0, 0, 0, 0], [1, 0, 0, 1]]
Par contre, utiliser deux grilles a un avantage.
Si les grilles sont identiques, on peut s'arrêter car on est dans un processus infini.
On peut également alterner indéfiniment entre les deux configurations suivantes: 0100 0110 | 010 000 0110 1000 | 010 111 0110 0001 | 010 000
0010 0110 |
Autre configurations qui se répètent (en incluant leurs rotations): 010 0110 110 110 101 1001 101 101 010 0110 010 011
Dans certains cas, des configurations qui se répètent ou alternent peuvent se trouver à proximité. Il peut en résulter des cycles de configurations. Par exemple, on peut passer de la configuration A à la configuration B, puis de B à C, et de C à A, et on recommence. Je n'ai pas analysé de tells cycles. En conclusion, il n'est pas suffisant de vérifier si deux grilles successives sont identiques. Il faut se fixer une limite d'itérations, ce qui n'est pas évident à évaluer.
- Edité par PierrotLeFou 6 janvier 2022 à 5:28:48
Le Tout est souvent plus grand que la somme de ses parties.
Le Tout est souvent plus grand que la somme de ses parties.