Outils pour utilisateurs

Outils du site


nsi:tds:jeux:jeu_de_la_vie

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
Prochaine révision
Révision précédente
nsi:tds:jeux:jeu_de_la_vie [2024/12/11 19:47] – [Stockage de la grille] goupillwikinsi:tds:jeux:jeu_de_la_vie [2024/12/29 18:42] (Version actuelle) goupillwiki
Ligne 28: Ligne 28:
 {{ vie_3.png?direct&400 |}} {{ vie_3.png?direct&400 |}}
  
-===== L'interface graphique ===== +===== Les fichiers de départ =====
- +
-On peut utiliser [[nsi:modules:tkinter:start|Tkinter]]. +
- +
-Voici les éléments dont vous pourriez avoir besoin : +
- +
-==== Initialisation de la fenêtre graphique ====+
  
 <code python> <code python>
-from tkinter import * bibliothèque graphique+module life.py
  
-# on convient de dimensions : 
 WIDTH = 80          # La grille de jeu a 80 cellules de large WIDTH = 80          # La grille de jeu a 80 cellules de large
 HEIGHT = 60         # et 60 de haut HEIGHT = 60         # et 60 de haut
Ligne 46: Ligne 39:
 DEAD_COLOR = '#fff' # cellule morte est blanche DEAD_COLOR = '#fff' # cellule morte est blanche
  
-root = Tk()        # création de la fenêtre Tkinter +def create_new_cell(canvas, line:int, col:int, coul:str): 
-root.title("Life") # on attribue un titre à la fenêtre +    """
- +
-# création de la zone de dessin - canvas +
-canvas = Canvas(rootwidth = WIDTH*CELL_SIZE, height = HEIGHT*CELL_SIZE, bd=0, bg="white"+
-canvas.pack() # insertion de la zone de dessin dans la fenêtre +
-</code> +
- +
-==== Créer une cellule ==== +
- +
-La fenêtre graphique est vide. Le mieux est de créer des carrés qui resteront les mêmes tout du long de l'animation mais qui changeront de couleurs. Chaque carré représente une cellule pouvant être vivante ou morte. +
- +
-<code python> +
-def create_new_cell(line:int, col:int, coul:str): +
-    '''+
     Crée une nouvelle cellule dans la zone de dessin,     Crée une nouvelle cellule dans la zone de dessin,
     à la ligne line et colonne col, de couleur coul     à la ligne line et colonne col, de couleur coul
     la fonction renvoie un identifiant de l'objet graphique créé     la fonction renvoie un identifiant de l'objet graphique créé
-    '''+    """
     x = col * CELL_SIZE     x = col * CELL_SIZE
     y = line * CELL_SIZE     y = line * CELL_SIZE
     return canvas.create_rectangle(x, y, x + CELL_SIZE, y + CELL_SIZE, fill=coul)     return canvas.create_rectangle(x, y, x + CELL_SIZE, y + CELL_SIZE, fill=coul)
-</code> 
  
-==== Changer la couleur d'une cellule déjà créée ==== +def change_cell_coul(canvas, cell_id:int, new_coul:str): 
- +    """
-Lors de la création d'une cellule, on a pu récupérer un identifiant -- c'est un entier -- qu'il faut conserver car cet identifiant nous permettra d'atteindre la cellule et de demander son changement de couleur. +
- +
-Dans la fonction, ''canvas'' est pris comme variable globale. C'est un choix légitime car il n'y aura jamais qu'une fenêtre graphique active dans notre programme. Si on trouve que ce n'est pas assez propre, on peut toujours ajouter le ''canvas'' en argument de la fonction. +
- +
-<code python> +
-def change_cell_coul(cell_id:int, new_coul:str): +
-    '''+
     pour une cellule dont l'identifiant est fourni,     pour une cellule dont l'identifiant est fourni,
     on impose une nouvelle couleur     on impose une nouvelle couleur
-    '''+    """
     canvas.itemconfig(cell_id, fill=new_coul)     canvas.itemconfig(cell_id, fill=new_coul)
-</code> 
  
-==== Animation ====+def make_grids(canvas): 
 +    """ 
 +    crée et renvoie deux grilles 
 +    une grille cells contenant les identifiants des cellules graphiques 
 +    une grille vivants contenant l'état de vie de chaque cellule (True ou False) 
 +    """ 
 +    # à faire
  
-Le jeu de la vie est plus intéressant s'il bouge un peu !+def vivant(vivants, line, col) -> bool: 
 +    """ 
 +    renvoie True si la cellule à la position demandée est vivante 
 +    si position hors cadre, renvoie False 
 +    """ 
 +    # à faire
  
-Tkinter permet un mécanisme de réactualisation de l'affichage. Pour cela on définit une fonction chargée de réactualiser l'affichage et qui est rappelée périodiquement, par exemple toutes les secondes. 
  
-Dans notre casla fonction de réactualisation doit se charger d'examiner la grille de jeu et de définir quelles cellules doivent naître (passer de morte à vivanteou mourir.+def voisins_vivants(vivantsline, col) -> int: 
 +    """ 
 +    renvoie le nombre de voisins vivants pour la position demandée 
 +    """ 
 +    # à faire 
 +     
 +def has_to_die(vivants, line, col) -> bool: 
 +    """ 
 +    renvoie True si la cellule à la position demandée est vivante et doit mourir 
 +    """ 
 +    # à faire 
 +     
 + 
 +def has_to_born(vivants, line, col) -> bool: 
 +    """ 
 +    renvoie True si la cellule à la position demandée est morte et doit naître 
 +    """ 
 +    # à faire 
 + 
 +def set_alive(canvas, vivants, cells, line, col): 
 +    """ 
 +    met à l'état vivant la cellule demandée 
 +    c'est à dire : modifie vivants et l'état de la cellule graphique correspondante 
 +    """ 
 +    # à faire 
 +     
 +def set_dead(canvas, vivants, cells, line, col): 
 +    """ 
 +    met à l'état mort la cellule demandée 
 +    c'est à dire : modifie vivants et l'état de la cellule graphique correspondante 
 +    """ 
 +    # à faire 
 +     
 +def cycle(canvas, vivants, cells)
 +    """ 
 +    exécute un cycle de jeu de la vie 
 +    """ 
 +    # à faire 
 +</code> 
  
 <code python> <code python>
 +# main.py
 +
 +from tkinter import * # bibliothèque graphique
 +from life import make_grids, cycle
 +
 +# init fenêtre tkinter
 +root = Tk()        # création de la fenêtre Tkinter
 +root.title("Life") # on attribue un titre à la fenêtre
 +
 +# création de la zone de dessin - canvas
 +canvas = Canvas(root, width = WIDTH*CELL_SIZE, height = HEIGHT*CELL_SIZE, bd=0, bg="white")
 +canvas.pack() # insertion de la zone de dessin dans la fenêtre
 +
 def reactualisation(): def reactualisation():
-    # à vous de faire... +    cycle(canvas, vivants, cells)
-    +
     # pour que la réactualisation se relance 1s plus tard, la fonction se termine par :     # pour que la réactualisation se relance 1s plus tard, la fonction se termine par :
     root.after(1000, reactualisation)     root.after(1000, reactualisation)
 +
 +
 +cells, vivants = make_grid(canvas)
  
 # et en fin de script, on amorce en programmant une première # et en fin de script, on amorce en programmant une première
 # réactualisation # réactualisation
-root.after(0, reactualisation)+root.after(1000, reactualisation)
 # et on lance la boucle qui maintient l'affichage de la fenêtre # et on lance la boucle qui maintient l'affichage de la fenêtre
 root.mainloop() root.mainloop()
-</Code>+</code>
  
-===== Stockage de la grille =====+===== L'interface graphique =====
  
-D'une part, nous devons stocker l'état de chaque cellule (vivante ou morte) et d'autre part, pour assurer l'affichage, nous devons stoker l'identifiant du carré représentant la cellule sur le canvas.+On peut utiliser [[nsi:modules:tkinter:start|Tkinter]].
  
-Nos cellules sont réparties sur une grilleOn va stocker nos données dans un tableauNous avons deux approches possibles :+Le fenêtre elle-même est désignée par ''root''. À l'intérieur de cette fenêtre, on crée une zone de dessin qui s'appelle ''canvas''C'est surtout avec elle que l'on va travailler.
  
-<code python> +On souhaite créer des carrés qui changent de couleurs. Ces carrés sont dessinés grâce aux fonctions de ''canvas''Vous trouvez cela dans la fonction ''%%create_new_cell%%''Cette fonction se contente de renvoyer un identifiantsimple nombre entierqui permettra ensuite de retrouver le carré et de changer sa couleur.
-# tableau de tableaux, soit un tableau en 2D +
-# exemple pour l'information sur l'état : +
-vivantes = [ [False, False, False, ..., False],    # prévoir 80 colonnes comme indiqué plus haut +
-             [False, True,  False, ..., True ], +
-             ... +
-             [False, False, True,  ..., True ] ],  # et prévoir 60 lignes+
  
-# True pour une cellule vivante, False pour une morte +Quand on veut changer la couleur, on utilise ''%%change_cell_coul%%''
-# pour atteindre la cellule de ligne 13 et colonne 5 + 
-vivantes[13][5] +Il est important dans ce programme de traiter à part l'information disant si une cellule est vivante ou morte et l'objet graphique représentant cette cellule. En effet, on pourrait très bien se contenter de travailler sur les objets graphiques. On pourrait utiliser ''canvas'' pour savoir si tel carré est bleu ou blanc, ce qui nous permettrait de savoir si la cellule correspondante est vivante ou morte. Mais cela serait moins lisible et prendrait plus de temps d'exécution. Pour que le jeu de la vie fonctionne bien, il faut être plus économe en temps d'exécution. 
-la cellule en haut à gauche est à la ligne 0 et colonne 0 + 
-</code>+Tout au long du programme, nous aurons donc deux grilles : 
 +  * une grille ''vivants'' qui ne contient que des ''True'' et des ''False''. Son contenu change en fonction de l'évolution du jeu. 
 +  * une grille ''cells'' contenant les identifiants des objets graphiques. Cette grille ne change pas car les objets graphiques sont toujours les mêmes. Ils se contentent de changer de couleur. 
 + 
 +===== grilles =====
  
-Le choix de tableau 2D ci-dessus peut sembler s'imposer puisque la grille de jeu est elle-même en 2D. Mais il est parfois plus simple de passer par un tableau 1D :+==== création des grilles ==== 
 +Bien que le jeu soit à deux dimensions, je propose d'utiliser des grilles à une seule dimension car c'est plus facile à utiliser.
  
 <code python> <code python>
-# tableau 1D +vivants = [ False, False, False, ..., False,    # prévoir 80 colonnes comme indiqué plus haut
-# exemple pour l'information sur l'état : +
-vivantes = [ False, False, False, ..., False,    # prévoir 80 colonnes comme indiqué plus haut+
              False, True,  False, ..., True ,              False, True,  False, ..., True ,
              ...              ...
Ligne 143: Ligne 175:
 </code> </code>
  
-À vous de choisirÀ mon avis, la grille 1D vaut mieux.+La fonction ''%%make_grids%%'' doit créer simultanément la grille ''cells'' et la grille ''vivants''. Vous pouvez créer une grille aléatoirement en mettant à vivant ou à mort au hasard. Chaque fois que vous ajoutez un élément dans ''vivants'' il faut ajouter l'élément correspondant dans ''cells''Je vous rappelle que la création d'une cellule passe par ''%%create_new_cell%%''.
  
-<WRAP box>Solution possible en [[nsi:langages:processing:solutions:jeu_de_la_vie|Processing]].</WRAP>+==== lecture de la grille ====
  
 +On va vouloir savoir si la cellule à une certaine ligne et une certaine colonne est vivante. Pour cela on doit définir :
 +
 +<code python>
 +def vivant(vivants, line, col) -> bool:
 +    """
 +    renvoie True si la cellule à la position demandée est vivante
 +    si position hors cadre, renvoie False
 +    """
 +    # à faire
 +</code>
 +
 +
 +Comme ''vivants'' est un tableau où toutes les valeurs sont mises à la suite les unes des autres, il faut déterminer l'indice de l'élément recherché. J'ai déjà dit plus haut que si je demande la ligne 13 et la colonne 5, il faut demander ''%%vivants[ligne*WIDTH + colonne]%%''. À vous de généraliser.
 +
 +Remarquez qu'il sera plus commode de pouvoir donner des positions hors grille (vous verrez un peu plus loin pourquoi). Donc dans le cas où la position demandée ne correspond pas à une ligne valide ou une colonne valide, il faut renvoyer ''False''.
 +
 +==== voisins vivants ====
 +
 +Nous parlons ici de la fonction ''%%voisins_vivants%%'' qui pour une position donnée doit renvoyer le nombre de voisins vivants. Pour cela il suffit de faire la somme des valeurs voisines de la position considérée.
 +
 +Par exemple, si je demande ligne 13, colonne 5, je vais faire la somme des positions (12,4), (12,5), (12,6), (13,4), (13,6), (14,4), (14,5), (14,6).
 +
 +Ces positions contiennent des booléens mais si on demande une somme, les ''True'' seront convertis en ''1'' et la somme reviendra à compter le nombre de vivants.
 +
 +Ce qui vient d'être dit peut poser problème : on va se voir obliger de faire beaucoup de tests quand on est au bord. Par exemple, si j'interroge la position (2,0) *c'est à dire ligne 2 colonne 0*, il n'y a que 5 voisins au lieu de 8 : (1,0), (1,1), (2,1), (3,0), (3,1). En effet, la position (2,-1) n'existe pas. Mais si je décide que les positions hors cadre sont mortes alors rien ne m'empêche d'interroger la position (2,-1) qui sera considérée comme morte.
 +
 +Voilà pourquoi on a fait ce choix pour la fonction ''vivant''. Cela nous permet de ne pas trop nous préoccuper des bords.
 +
 +==== Changement d'état ====
 +
 +Deux fonctions permettent de changer l'état des grilles : ''%%set_alive%%'' et ''%%set_dead%%''.
 +
 +Ces fonctions doivent modifier l'état de ''vivants''. Il s'agit de modifier la grille pour mettre ''True'' ou ''False'' à l'endroit désiré.
 +
 +Elles doivent aussi modifier l'affichage. Il faut lire l'identifiant désiré dans ''cells'' afin de changer la couleur de la cellule avec ''%%change_cell_coul%%''.
 +
 +===== Évolution =====
 +
 +Je vous propose une approche qui n'est pas trop gourmande en temps de façon à obtenir une animation satisfaisante.
 +
 +La fonction ''cycle'' décide de l'évolution. Il faudra :
 +  * préparer une liste ''%%to_die%%'' des cellules devant mourir et une liste ''%%to_born%%'' des cellules devant naître. Ces listes sont vides initialement.
 +  * parcourir chaque cellule. Grâce aux fonctions ''%%has_to_born%%'' et ''%%has_to_die%%'' décider du destin de cette cellule.
 +  * Quand toutes les cellules ont été lues, passer à la modification des cellules :
 +    * mettre à l'état mort chaque cellule de ''%%to_die%%''
 +    * mettre à l'état vivant chaque cellule de ''%%to_born%%''
 +
 +<WRAP box>Solution possible en [[nsi:langages:processing:solutions:jeu_de_la_vie|Processing]].</WRAP>
nsi/tds/jeux/jeu_de_la_vie.1733942835.txt.gz · Dernière modification : de goupillwiki