Jeu de la vie [si05] - Exercice Karine Zampieri, Stéphane Rivière, Béatrice Amerein-Soltner Unisciel algoprog Version 24 avril 2015 Table des matières 1 Jeu de la vie / pg-jeuviea1 (C++) 1 1.1 Représentation du milieu........................... 1 1.2 Affichage et initialisation du terrain..................... 3 1.3 Création de la population initiale...................... 4 1.4 Calcul de la génération suivante....................... 5 1.5 Programme principal............................. 7 1.6 Annexe : exemples de configurations initiales................ 8 2 Optionnel : Version graphique 8 2.1 Mode graphique................................ 8 2.2 Jeu de la vie.................................. 9 1 Jeu de la vie / pg-jeuviea1 (C++) Mots-Clés Simulation, Graphique, Algorithmique, Programmation, C++. Requis Axiomatique impérative. Optionnel Graphique. Cet exercice réalise le jeu de la vie de Conway qui simule le développement de cellules vivantes. Le programme demande la taille du terrain, l occupation initiale du terrain par les cellules, le nombre de générations à calculer, affiche le terrain initial puis calcule et affiche les générations suivantes du terrain. 1.1 Représentation du milieu Le développement des cellules se fait de génération en génération. Lorsque l on passe d une génération à la suivante, une cellule peut naître, continuer à vivre ou mourir. Le milieu de développement des cellules est un terrain quadrillé et chaque case du terrain est soit vide, soit occupée par une cellule (figure 1a). 1
Unisciel algoprog Jeu de la vie [si05] 2 Le terrain est donc représenté par un tableau à deux dimensions. Une case du tableau contiendra 0 si la case du terrain est vide, 1 si la case est occupée par une cellule. Définissez le type TabCellules représentant un tableau de cellules d entiers de hauteur maximale HMAX=75 et de largeur maximale LMAX=40. Définissez alors le type Terrain comme étant une structure incluant : Des entiers hauteur et largeur mémorisant les dimensions effectives du terrain. Un TabCellules cells mémorisant l état des cellules. Lorsqu on passe à la génération suivante, l évolution d une case (i, j) du terrain se fait en considérant le nombre total de cellules se trouvant dans les 8 cases voisines qui l entourent (figure 1b). Les cases situées sur le bord du terrain posent un problème : lequel? Elles n ont pas toutes les huit cellules voisines. Pour remédier simplement au problème ci-avant, le terrain utilisé sera entouré d une bordure constituée de cases toujours vides. Ainsi si w et h sont la largeur et la hauteur du terrain données par l utilisateur, le terrain sera constitué des cases (i, j) avec i variant de 0 à h + 1 et j variant de 0 à w + 1, mais le calcul de la génération suivante ne se fera que sur les cases de 1 à h et de 1 à w. Commencez par écrire une fonction evalcase(tr,ix,jx) qui renvoie la valeur (entier) de la case en (ix,jx) d un Terrain tr. De même, écrivez une procédure fixercase(tr,ix,jx,val) qui fixe la valeur val (entier) de la case en (ix,jx) d un Terrain tr. Validez vos déclarations, votre fonction et votre procédure avec la solution.
Unisciel algoprog Jeu de la vie [si05] 3 C++ @[jeuviea1a.cpp] 1.2 Affichage et initialisation du terrain Le terrain sera affiché à l écran avec des caractères : une cellule active sera affichée avec O et une cellule vide avec.. Écrivez une procédure afficherterrain(tr) qui affiche à l écran un Terrain tr. Écrivez une procédure initialisermilieu(tr) qui initialise le tableau (terrain utilisé + bordure) d un Terrain tr. Le tableau ne doit contenir que des cases vides. Soit la procédure saisirentier(n,a,b) qui demande et saisit un entier dans n jusqu à ce qu il soit dans l intervalle d entiers [a..b]. Elle affiche l invite : Entier dans [[a]..[b]]? C++ @[saisirentiera1.cpp] Écrivez une procédure saisirdimensions(tr) qui demande et saisit les dimensions (hauteur et largeur) d un Terrain tr. Affichez les invites : Hauteur du terrain? Largeur du terrain? Validez vos procédures avec la solution. C++ @[jeuviea1b.cpp] Écrivez une procédure test_init qui déclare un Terrain tr, demande ses dimensions (hauteur et largeur), l initialise et l affiche.
Unisciel algoprog Jeu de la vie [si05] 4 Testez. Validez votre procédure avec la solution. C++ @[pg-jeuviea1b.cpp] 1.3 Création de la population initiale La création de la population initiale se fait en activant des cellules sur un terrain vide. Soit la fonction dansintervalle(n,a,b) qui renvoie Vrai si un entier n est dans l intervalle [a..b] d entiers, Faux sinon. C++ @[dansintervallea1.cpp] Écrivez une procédure activercellules(tr) qui, pour un terrain tr, demande à l utilisateur les coordonnées (i, j) de chaque cellule à activer, une coordonnée de (-1,-1) indiquant que l on ne veut plus activer de cellules. Validez votre procédure avec la solution. C++ @[jeuviea1c.cpp] Copiez/collez la procédure test_init en la procédure test_placer. Complétez-la et modifiez-le de sorte qu après avoir initialisé un terrain de dimensions demandée à l utilisateur, elle demande à l utilisateur d activer des cellules en réaffichant le terrain à chaque fois.
Unisciel algoprog Jeu de la vie [si05] 5 Testez. Validez votre procédure avec la solution. C++ @[pg-jeuviea1c.cpp] 1.4 Calcul de la génération suivante Lorsque l on passe à la génération suivante, l évolution d une case (i, j) du terrain se fait en considérant le nombre total nc de cellules se trouvant dans les 8 cases voisines qui l entourent (figure 1b) : Si la case est vide et si nc = 3 : une cellule naît dans cette case. Sinon (la case est active) : Si nc > 3 : la cellule meurt étouffée. Si nc < 2 : la cellule meurt d isolement. Sinon la cellule continue à vivre. Ainsi, le terrain de la figure 2(a), génération i, évolue à la génération suivante i + 1 en le terrain de la figure 2(b) selon les règles données ci-avant.
Unisciel algoprog Jeu de la vie [si05] 6 Écrivez une fonction nvoisins(tr,ix,jx) qui calcule et renvoie le nombre de cellules actives dans le voisinage d une cellule en (ix,jx) d un Terrain tr. Écrivez une procédure copierterrain(tr,dp) qui copie un Terrain tr dans un Terrain dp. Aide simple Recopiez les champs et les cellules effectives du terrain tr. Écrivez alors une procédure generationsuivante(tr) qui, pour un Terrain tr, passe à la génération suivante. Attention : Le calcul du nombre de cellules voisines doit se faire en considérant la configuration de départ du terrain (à sauver donc dans un terrain temporaire grâce à la procédure copierterrain) et non pas la configuration en cours de modification. Enfin écrivez alors une procédure jouer(tr) qui, pour un Terrain tr, passe à la génération suivante puis affiche le nouveau terrain jusqu à ce que l utilisateur tape la touche q pour signifier qu il souhaite «quitter».
Unisciel algoprog Jeu de la vie [si05] 7 Outil C++ Après l affichage du terrain, ajoutez la ligne : cin.get(c); Cela stoppera le programme jusqu à ce que vous tapiez sur une touche (c est une variable caractère à déclarer). Validez votre fonction et vos procédures avec la solution. C++ @[jeuviea1d.cpp] 1.5 Programme principal Écrivez une procédure test_jouer qui demande la taille du terrain, l occupation initiale du terrain par les cellules, affiche le terrain initial puis calcule et affiche les générations suivantes du terrain. Testez. Validez votre procédure avec la solution. C++ @[pg-jeuviea1d.cpp]
Unisciel algoprog Jeu de la vie [si05] 8 1.6 Annexe : exemples de configurations initiales 2 Optionnel : Version graphique 2.1 Mode graphique Afin de réaliser des graphiques, [C++] Récupérez les fichiers graphics.h et winbgi.cpp, copiez-les dans le dossier contenant (le fichier cpp de) votre projet et ajoutez-les comme éléments existants dans votre projet. Ajoutez dans la partie des #include de votre programme : #include "graphics.h" Écrivez alors les procédures de jeux avec illustration graphique sous la forme suivante : void jeuxgraphiques() { opengraphsize(600,400); //... le jeu... getch(); closegraph(); } Enfin ajoutez la ligne suivante dans votre fichier projet (pour la bibliothèque graphique) : -lgdi32
Unisciel algoprog Jeu de la vie [si05] 9 Mode standard En mode standard, il y a renversement des axes : le point (0,0) se trouve dans le coin supérieur gauche. 2.2 Jeu de la vie Vous pouvez faire une version graphique avec winbgi. On choisit pour dessiner le terrain une taille de bordure et une taille de cellule. Pour une cellule active, on affiche un cercle de rayon taille/2. Définissez les constantes BORDURE de valeur 50, TAILLEC de valeur 20 et RAYONC de valeur TAILLEC/2. La case (ix,jx) est alors dans le carré de taille côté dont le point en haut à gauche a pour coordonnées (BORDURE+jx*TAILLEC,BORDURE=ix*TAILLEC). Écrivez une procédure calculerxy(x,y,ix,jx) qui, étant données les coordonnées d une cellule (ix,jx), calcule les coordonnées écran dans (x,y) (entier). Déduisez une procédure calculerlc(ix,jx,x,y) qui, étant données les coordonnées écran (x,y) (entier), calcule les coordonnées d une cellule dans (ix,jx). Écrivez alors une procédure afficherterraingr(tr) qui affiche de façon graphique le terrain : après avoir effacé le terrain, on affiche les carrés de toutes les cases puis on affiche les cases (ix,jx) qui contiennent une cellule en traçant un cercle centré en (BORDURE+jx*TAILLEC+RAYONCC,BORDURE+ix*TAILLEC+RAYONCC) de rayon côté/2. Validez vos procédures avec la solution. C++ @[jeuviea1e.cpp]
Unisciel algoprog Jeu de la vie [si05] 10 Écrivez une procédure activercellulesgr(tr) qui active graphiquement les cellules en cliquant avec la souris sur les cellules. On s arrête quand on clique hors du terrain. Outil C++ La fonction getmouse(int& x,int& y) attend un clic de souris et récupère ses coordonnées dans les entiers x et y. Écrivez une procédure jouergr(tr) équivalente à la procédure jouer(tr) qui permet de jouer en mode graphique. Validez vos procédures avec la solution. C++ @[jeuviea1f.cpp] Écrivez une procédure test_jouergr qui demande les dimensions pour le dessin, ouvre la fenêtre et organise correctement la saisie des cases et l évolution des cellules. Testez. Validez votre procédure avec la solution. C++ @[pg-jeuviea1f.cpp]