Java Avancé : Jeu de la vie

Automates Cellulaires
mardi 9 novembre 2021
par  Emmanuel Adam
popularité : 13%

Jeu de la Vie

Dans le Jeu de la Vie (proposé par Conway 1970), dans une matrice se trouvent des cellules, actives ou inactives.

Le Jeu de la vie consiste à faire évoluer sur un grille un ensemble cellules
selon les règles suivantes :

  • Si une cellule active est entourée de moins de 2 cellules :
    elle manque de contact et se désactive.
  • Si une cellule active est entourée de plus de 3 cellules : elle est en milieu surpeuplé et se désactive.
  • Si une cellule inactive est entourée de 3 cellules, alors elle s’active.
  • Dans les autres cas, la cellule garde son état.

Voici le lien pour la page wikipedia en français.

Ici http://golly.sourceforge.net/ se trouve le logiciel golly, spécialement dédié aux automates cellulaires.
Possibilité d’utiliser un monde très très étendu...

Enoncé

Créer le programme permettant le déroulement d’un jeu de la Vie.
1. Créer les classes Cellule et Matrice :

Les classes suivantes sont à définir :

  • Cellule, avec les variables
    • vivante : booléen
    • etatPrecedent : booléen qui indique si un l’état précédent de la cellule
    • Cellule[][] grille : un lien vers la matrice de cellules
    • Circle cercle : un lien vers sa représentation graphique
    • x, y les coordonnées
    • le constructeur : public Cellule(Cellule [][]grille, int x, int y, boolean vivante)
    • evoluer() qui change la valeur de la cellule par rapport à son voisinage
      On prendra un monde sphérique. ’taille’ étant la dimension de la grille carrée, la case en haut à gauche de la case (0,0) est la case (taille-1, taille-1).

  • Matrice, avec les variables
    • Cellule[][] grille, la grille au temps actuel
    • Cellule[][] grilleAncienne, la grille au temps précédent
    • double densité : pourcentage initiale de cellules actives
    • int taille : la taille de la matrice (carrée)
    • le constructeur public Matrice(int taille, double densite)
    • la fonction void init() qui cree des cellules inactives dans la grille et les recopie dans la grilleAncinne
    • la fonction initHasard() qui active densité% de cellule dans la grille et dans la grilleAncienne
    • copieGrille(), recopie grille dans ancienne grille
    • animGrille(), demande à chaque cellule d’évoluer

2. Interactivité
Ajouter des interactions :

  • l’appui sur ’p’ met en pause la simulation
  • l’appui sur ’d’ démarre la simulation
  • l’appui sur ’e’ efface tout
  • ’l’appui sur ’h’ active des cellules aléatoirement
  • un clic souris sur la zone de simulation active.desactive des cellules

3. Ralentissez la croissance :
ajouter des étapes afin de voir l’évolution des cellules au ralenti :

  • les cellules actives sont en vert clair
  • les cellules qui se désactivent et seraient désactivés au top suivant sont en vert
  • les cellules qui se réactivent et seraient actives au top suivant sont en vert sombre
  • les cellules inactives sont en vert noir.

4. Animation :
Quand une cellule change d’état, sa couleur s’estompe graduellement.
Remarque : Ceci ralenti la simulation..

Fenêtre JFX pour tester le code

On utilisera une fenêtre de type JavaFX.
En JavaFX, une application graphique se déroule sur une scène (scene) de théâtre (stage).
Sur cette scène se trouve des acteurs, les éléments graphiques.

N.B. Pour lancer cette application, il est nécessaire d’ajouter dans les options de la JVM le chemin d’accès au répertoire où vous avez installer JavaFX. Exemple :
— module-path /MONREPERTOIRE/LeRepDeJAVAFX/lib —add-modules=javafx.controls,javafx.fxml

Voici un exemple de code pour l’Application :

  1. import javafx.animation.KeyFrame;
  2. import javafx.animation.Timeline;
  3. import javafx.application.Application;
  4. import javafx.scene.Group;
  5. import javafx.scene.Scene;
  6. import javafx.scene.paint.Color;
  7. import javafx.scene.shape.Circle;
  8. import javafx.stage.Stage;
  9. import javafx.util.Duration;
  10.  
  11. public class JfxAnimVie extends Application {
  12.     /**matrice liee a cet objet graphique*/
  13.     Matrice matrice;
  14.     /**elements graphiques représentant les cellules*/
  15.     public static Circle[][] circles;
  16.     /**taille d'une cellule en pixel*/
  17.     int espace = 10;
  18.     /**taille de la matrice*/
  19.     private int taille;
  20.     /**nombre de celluls initialement actives*/
  21.     private double densite;
  22.     /**délai en ms entre chaque évolution*/
  23.     private int tempo;
  24.  
  25.     @Override
  26.     public void start(Stage primaryStage) {
  27.         taille = 200;
  28.         densite = 0.2;
  29.         tempo = 100;
  30.         construireScenePourJeuDeLaVie( primaryStage);
  31.     }
  32.  
  33.     void construireScenePourJeuDeLaVie(Stage primaryStage) {
  34.         int largeur = 800;
  35.         int hauteur = 900;
  36.         espace = 4;
  37.         //definir la scene principale
  38.         Group root = new Group();
  39.         Scene scene = new Scene(root, largeur, hauteur, Color.BLACK);
  40.         primaryStage.setTitle("Life...");
  41.         primaryStage.setScene(scene);
  42.         //definir les acteurs
  43.         matrice = new Matrice(taille, densite);
  44.         matrice.init();
  45.         matrice.initHasard();
  46.         //definir les costumes
  47.         JfxAnimVie.circles = new Circle[taille][taille];
  48.         //habiller les acteurs
  49.         dessinMatrice( root);
  50.  
  51.         //afficher le theatre
  52.         primaryStage.show();
  53.         //-----lancer le timer pour faire vivre la matrice
  54.         Timeline littleCycle = new Timeline(new KeyFrame(Duration.millis(tempo), event-> { matrice.copieGrille(); matrice.animGrille(); }
  55.         ));
  56.    littleCycle.setCycleCount(Timeline.INDEFINITE);
  57.    littleCycle.play();
  58. }
  59.  
  60.     /** creation des cellules et de leurs habits  */
  61.     void dessinMatrice(Group root) {
  62.         Cellule[][] grille = matrice.getGrille();
  63.         int rayon = espace/2;
  64.         for(int i=0; i<taille; i++)
  65.             for(int j=0; j<taille; j++) {
  66.                 Cellule cell = grille[i][j];
  67.                 circles[i][j] = new Circle(i*espace+rayon, j*espace+rayon, rayon);
  68.                 cell.setCercle(circles[i][j]);
  69.                 if (cell.isVivante()) circles[i][j].setFill(Color.ANTIQUEWHITE);
  70.                 else circles[i][j].setFill(Color.DARKSLATEGRAY);
  71.                 root.getChildren().add(circles[i][j]);
  72.             }
  73.     }
  74.  
  75.     public static void main(String[] args) { launch(args);}
  76. }

Version courte mais complète

Vous trouvez ci-dessous un petit code complet permettant l’exécution du jeu de la Vie en Java FX, en 1 seule classe.

  1. import javafx.animation.KeyFrame;
  2. import javafx.animation.Timeline;
  3. import javafx.application.Application;
  4. import javafx.scene.Group;
  5. import javafx.scene.Scene;
  6. import javafx.scene.paint.Color;
  7. import javafx.scene.shape.Circle;
  8. import javafx.stage.Stage;
  9. import javafx.util.Duration;
  10.  
  11.  
  12. public class QuickLife extends Application {
  13.     /**
  14.      * matrice representant l'ETAT des cellules
  15.      */
  16.     byte[][] matrice;
  17.     /**
  18.      * copie de la matrice representant l'ETAT des cellules
  19.      */
  20.     byte[][] matriceCopie;
  21.     /**
  22.      * objets graphiques représentant les cellules
  23.      */
  24.     public Circle[][] circles;
  25.  
  26.     /**
  27.      * taille d'une cellule en pixel
  28.      */
  29.     int espace = 7;
  30.     /**
  31.      * longueur de la matrice (en nombre de cellules sur une rangée)
  32.      */
  33.     private int taille;
  34.     /**
  35.      * densite de cellules actives au départ
  36.      */
  37.     double densite;
  38.  
  39.     /**
  40.      * délai en ms entre chaque évolution
  41.      */
  42.     private int tempo;
  43.  
  44.  
  45.     /**
  46.      * lancement de l'application
  47.      */
  48.     public void start(Stage primaryStage) {
  49.         taille = 60;
  50.         tempo = 10;
  51.         espace = 10;
  52.         densite = 0.4;
  53.         construireScenePourJeuDeLaVie(primaryStage);
  54.     }
  55.  
  56.     void construireScenePourJeuDeLaVie(Stage primaryStage) {
  57.         int largeur = (taille + 1) * (espace + 1);
  58.         int hauteur = (taille + 1) * (espace + 1);
  59.         //definir la troupe
  60.         Group root = new Group();
  61.         //definir la scene principale
  62.         Scene scene = new Scene(root, largeur, hauteur, Color.BLACK);
  63.         primaryStage.setTitle("Life...");
  64.         primaryStage.setScene(scene);
  65.  
  66.         //creation et initialisation des cellules
  67.         matrice = new byte[taille][taille];
  68.         matriceCopie = new byte[taille][taille];
  69.         initMatrice(densite);
  70.         copie(matrice, matriceCopie);
  71.  
  72.         //definir les acteurs (representation des cellules
  73.         circles = new Circle[taille][taille];
  74.         creationTroupe(root);
  75.  
  76.         //afficher le theatre
  77.         primaryStage.show();
  78.  
  79.  
  80.         //-----lancer le timer pour faire vivre la matrice
  81.         Timeline littleCycle = new Timeline(new KeyFrame(Duration.millis(tempo),
  82.                 event -> {
  83.                     //à chaque top, lancer une evolution
  84.                     evoluerMatrice();
  85.                     //puis effectuer une copie de la matrice
  86.                     copie(matrice, matriceCopie);
  87.                 }));
  88.         //animation en boucle
  89.         littleCycle.setCycleCount(Timeline.INDEFINITE);
  90.         littleCycle.play();
  91.     }
  92.  
  93.  
  94.     /**
  95.      * copie le contenu de matrice dans matriceCopie
  96.      *
  97.      * @param matrice      matrice d'origine
  98.      * @param matriceCopie matrice de destination
  99.      */
  100.     void copie(byte[][] matrice, byte[][] matriceCopie) {
  101.         for (int i = 0; i < taille; i++)
  102.             System.arraycopy(matrice[i], 0, matriceCopie[i], 0, taille);
  103.     }
  104.  
  105.     /**
  106.      * initialise les cellules à active (1) ou non (0)
  107.      * en fonction de la densite d'activation (entre 0 et 1)
  108.      *
  109.      * @param densite densite de cellule à activer, entre entre 0(aucune cellule active) et 1(toutes cellules actives)
  110.      */
  111.     void initMatrice(double densite) {
  112.         for (int i = 0; i < taille; i++)
  113.             for (int j = 0; j < taille; j++)
  114.                 if (Math.random() < densite)
  115.                     matrice[i][j] = 1;
  116.     }
  117.  
  118.     /**
  119.      * creation des cercles et de leurs couleurs en fonction de l'etat de leur cellule (cellule située aux même coordonnées (i,j))
  120.      *
  121.      * @param root ensemble des acteurs de la scène dans lequel les cercles seront ajoutés
  122.      */
  123.     void creationTroupe(Group root) {
  124.         int rayon = espace / 2;
  125.         for (int i = 0; i < taille; i++)
  126.             for (int j = 0; j < taille; j++) {
  127.                 circles[i][j] = new Circle((i + .5) * espace, (j + .5) * espace, rayon);
  128.                 if (matrice[i][j] == 1) circles[i][j].setFill(Color.LIGHTGREEN);
  129.                 else circles[i][j].setFill(Color.DARKSLATEGRAY);
  130.                 root.getChildren().add(circles[i][j]);
  131.             }
  132.     }
  133.  
  134.     /**
  135.      * evolution d'une cellule par rapport aux voisines/
  136.      * Met à jour les valeurs dans matrice à partir des valeurs dans matriceCopie.
  137.      *
  138.      * @param x no de colonne de la cellule qui doit evoluer
  139.      * @param y no de ligne de la cellule qui doit evoluer
  140.      */
  141.     void evoluer(int x, int y) {
  142.         int nbVoisinesActives = 0;
  143.         for (int i = -1; i <= 1; i++)
  144.             for (int j = -1; j <= 1; j++) {
  145.                 if (i == 0 && j == 0) continue;
  146.                 int xx = ((x + j) + taille) % taille;
  147.                 int yy = ((y + i) + taille) % taille;
  148.                 nbVoisinesActives = nbVoisinesActives + matriceCopie[yy][xx];
  149.             }
  150.         if (matriceCopie[y][x] == 1) {
  151.             if (nbVoisinesActives > 3 || nbVoisinesActives < 2) {
  152.                 matrice[y][x] = 0;
  153.                 circles[y][x].setFill(Color.DARKSLATEGRAY);
  154.             }
  155.         } else {
  156.             if (nbVoisinesActives == 3) {
  157.                 matrice[y][x] = 1;
  158.                 circles[y][x].setFill(Color.LIGHTGREEN);
  159.             }
  160.         }
  161.     }
  162.  
  163.     /**
  164.      * evolution de l'ensemble de la matrice
  165.      */
  166.     void evoluerMatrice() {
  167.         for (int x = 0; x < taille; x++)
  168.             for (int y = 0; y < taille; y++)
  169.                 evoluer(x, y);
  170.     }
  171.  
  172.     /**
  173.      * lancement du prog
  174.      */
  175.     public static void main(String[] args) {
  176.         launch(args);
  177.     }
  178. }


Navigation

Mots-clés de l’article