Jeu de la vie, TP n°11

Version finale

Le menu doit maintenant vraiment donner la possibilité de dessiner la configuration initiale.
vie05.py [Cacher les numéros de ligne]
  1. # -*- coding: utf-8 -*-
  2. import random,curses
  3. ##############################################
  4. ####    CALCUL DE LA TAILLE DE L'ÉCRAN    ####
  5. ##############################################
  6. def tailleecran() :
  7.     nblgn,nbcol=ecran.getmaxyx()                   # nombre de lignes et de colonnes
  8.     nblgn,nbcol=nblgn-haut-bas,nbcol-gauche-droite # ajuster avec les marges
  9.     return nblgn,nbcol
  10. #####################################
  11. ####    CREATION DES TABLEAUX    ####
  12. #####################################
  13. def creation() :
  14.     global tableau
  15.     for l in range(0,nblgn) :               # pour chaque ligne
  16.         tableau.append([vide]*nbcol)        # créer la ligne
  17.         prochaine.append([vide]*nbcol)      # créer la ligne
  18. #####################################
  19. ####    REMPLISSAGE ALÉATOIRE    ####
  20. #####################################
  21. def remplissage_aleatoire() :
  22.     global tableau
  23.     proportion=random.random()              # proportion espace/étoile
  24.     for l in range(0,nblgn) :               # pour chaque ligne
  25.         for c in range(0,nbcol) :           # pour chaque colonne
  26.             if random.random()<proportion : # si tirage aléatoire dans la bonne proportion
  27.                 tableau[l][c]=vide          # ajouter un espace
  28.             else :                          # sinon
  29.                 tableau[l][c]=plein         # ajouter une étoile
  30. #####################################
  31. ####    REMPLISSAGE À LA MAIN    ####
  32. #####################################
  33. def remplissage_dessine() :
  34.     global tableau
  35.     ligne,colonne=1,1              # positions verticale et horizontale initiale
  36.     unetouche=0                    # pour pouvoir entrer dans la boucle
  37.     while unetouche!=ord("q") :    # tant que pas appuyé sur Q
  38.         if (unetouche==curses.KEY_RIGHT) and (colonne<nbcol) :# à droite
  39.             colonne+=1
  40.         elif (unetouche==curses.KEY_LEFT) and (colonne>0) :   # à gauche ,
  41.             colonne-=1
  42.         elif (unetouche==curses.KEY_UP) and (ligne>0) :       # en haut
  43.             ligne-=1
  44.         elif (unetouche==curses.KEY_DOWN) and (ligne<nblgn) : # en bas
  45.             ligne+=1
  46.         elif unetouche==ord(" ") : # barre d'espace
  47.             if tableau[ligne][colonne]==vide :  #  -> change d'état
  48.                 tableau[ligne][colonne]=plein
  49.             else :
  50.                 tableau[ligne][colonne]=vide
  51.         ecran.clear()              # effacer l'écran
  52.         affichage(True)            # affichage de l'espace complet
  53.         ecran.addch(ligne+haut,colonne+gauche,tableau[ligne][colonne],INVERSE)  # curseur
  54.         unetouche=ecran.getch()    # attente d'une frappe clavier
  55. ##############################################
  56. ####    PREMIER REMPLISSAGE DU TABLEAU    ####
  57. ##############################################
  58. def remplissage() :
  59.     choisir=[ord(" ")]                             # liste des touches pour sortir
  60.     liste=["hasard","dessin de la configuration"]  # liste des messages
  61.     l0,c0=4,4                                      # décalages horizontal et vertical
  62.     # message d'invite
  63.     ecran.addstr(l0-1,c0,"Faites votre choix, puis appuyez sur \"espace\" :")
  64.     # calcul de longueur maximale
  65.     l=0
  66.     for i in range(0,len(liste)) :
  67.         if len(liste[i])>l :
  68.             l=len(liste[i])
  69.     # égalisation des longueurs des message
  70.     for i in range(0,len(liste)) :
  71.         while len(liste[i])<l :
  72.             liste[i]+=" "
  73.     choix=0                                    # initialisation du choix
  74.     k=0                                        # touche tapée
  75.     while k not in choisir :                   # TQ pas appuyé sur une touche de sortie
  76.         if k==curses.KEY_DOWN :                # descendre
  77.             choix=(choix+1) % len(liste)
  78.         elif k==curses.KEY_UP :                # monter
  79.             choix=(choix-1) % len(liste)
  80.         # afficher les messages
  81.         for i in range(0,len(liste)) :
  82.             if i==choix :                      # le choix actuellement sélectionné
  83.                 ecran.addstr(l0+i,c0+2," "+liste[i]+" ",INVERSE)
  84.             else :                             # un autre choix
  85.                 ecran.addstr(l0+i,c0+2," "+liste[i]+" ",NORMAL)
  86.         k=ecran.getch()                        # attendre frappe au clavier
  87.     if choix==0:
  88.         remplissage_aleatoire()
  89.     elif choix==1:
  90.         remplissage_dessine()
  91. #################################################
  92. ####    CALCUL DE LA PROCHAINE GÉNÉRATION    ####
  93. #################################################
  94. def generation() :
  95.     global tableau,prochaine,generations
  96.     for l in range(0,nblgn) :               # pour chaque ligne
  97.         for c in range(0,nbcol) :           # pour chaque colonne
  98.             n=voisins(l,c)                  # nombres de voisiuns de la case
  99.             #  si (case vivante avec 2 voisins) ou si 3 voisins
  100.             if (n==2 and tableau[l][c]==plein) or (n==3) :
  101.                 prochaine[l][c]=plein       # case vivante à la prochaine génération
  102.             else :
  103.                 prochaine[l][c]=vide        # case vide à la prochaine génération
  104.     for l in range(0,nblgn) :               # pour chaque ligne
  105.         for c in range(0,nbcol) :           # pour chaque colonne
  106.             tableau[l][c]=prochaine[l][c]   # recopier la nouvelle génération
  107.     generations+=1                          # une génération de plus
  108. #########################
  109. ####    AFFICHAGE    ####
  110. #########################
  111. def affichage(creation=False) :
  112.     global nblgn,nbcol,tableau,prochaine
  113.     exnblgn,exnbcol=nblgn,nbcol                    # sauvegarde de la taille ancienne
  114.     nblgn,nbcol=tailleecran()                      # calcul de la taille de l'écran
  115.     if (exnblgn,exnbcol)!=(nblgn,nbcol) :          # si le monde a changé de taille
  116.         ## sauvegarde du monde actuel ##
  117.         for l in range(0,exnblgn) :                # pour chaque ligne
  118.             for c in range(0,exnbcol) :            # pour chaque colonne
  119.                 prochaine[l][c]=tableau[l][c]      # recopier la nouvelle génération
  120.         ## re-création du monde à la bonne taille ##
  121.         tableau=[]                                 # tableau vide
  122.         for l in range(0,nblgn) :                  # pour chaque ligne
  123.             tableau.append([vide]*nbcol)           # créer la ligne
  124.         ## recopie des données sauvegardées ##
  125.         for l in range(0,min(nblgn,exnblgn)) :     # pour chaque ligne
  126.             for c in range(0,min(nbcol,exnbcol)) : # pour chaque colonne
  127.                 tableau[l][c]=prochaine[l][c]      # recopier la nouvelle génération
  128.         ## re-création du tableau "prochaine" à la bonne taille ##
  129.         prochaine=[]                               # tableau vide
  130.         for l in range(0,nblgn) :                  # pour chaque ligne
  131.             prochaine.append([vide]*nbcol)         # créer la ligne
  132.         ecran.clear()                              # effacer les restes
  133.     for l in range(0,nblgn) :                      # pour chaque ligne
  134.         for c in range(0,nbcol) :                  # pour chaque colonne
  135.             ecran.addstr(l+haut,c+gauche,tableau[l][c]) # case correspondante
  136.     if creation :
  137.         debutmessage="Déplacements avec le curseur. Sélectionner avec espace. "
  138.     else :
  139.         debutmessage=str(generations)+"° génération. " # affiche le n° de génération
  140.     ecran.addstr(nblgn+haut,gauche,debutmessage)
  141.     ecran.addstr(str(nbcol)+"x"+str(nblgn))        # affiche la taille du monde
  142.     ou=""                                          # entre les choix (vide pour le 1er)
  143.     sortir=""                                      # message à afficher
  144.     for q in sortie :                              # pour toutes les touches de sortie
  145.         sortir=sortir+ou+"« "+chr(q)+" »"          # ajouter la touche
  146.         ou=" ou "                                  # entre les choix ("ou" à partir du 2°)
  147.     ecran.addstr(". Pour sortir, appuyer sur "+sortir+".") # afficher le message
  148. ###################################
  149. ####    COMPTER LES VOISINS    ####
  150. ###################################
  151. def voisins(l,c) :
  152.     lavant,lapres,cavant,capres=l-1,l+1,c-1,c+1   # les bornes d'exploration
  153.     if lavant<0 : lavant=nblgn-1                  # pour la ligne du haut
  154.     if lapres>=nblgn : lapres=0                   # pour la ligne du bas
  155.     if cavant<0 : cavant=nbcol-1                  # pour la colonne de gauche
  156.     if capres>=nbcol : capres=0                   # pour la colonne de droite
  157.     nbre=0                                        # initialisation du compteur
  158.     for ll in [lavant,l,lapres] :                 # pour les 3 lignes entourant la case
  159.         for cc in [cavant,c,capres] :             # pour les 3 colonnes entourant la case
  160.             # pour chaque case occupée qui n'est pas la case elle-même
  161.             if (ll!=l or cc!=c) and tableau[ll][cc]==plein :
  162.                 nbre+=1                           # ajouter 1 au compteur
  163.     return nbre                                   # retourner la valeur du compteur
  164. ####################################
  165. ####    ATTENTE ET FERMETURE    ####
  166. ####################################
  167. def finir() :
  168.     curses.endwin()             # revenir à la console
  169. ###############################
  170. ####    INITIALISATIONS    ####
  171. ###############################
  172. ecran=curses.initscr()                # créer l'écran graphique
  173. ecran.nodelay(1)                      # getch() non bloquant
  174. curses.curs_set(False)                # pas d'affichage du curseur
  175. ecran.keypad(True)                    # codage des touches de fonctions en 1 octet
  176. curses.start_color()                  # utilisation des couleurs
  177. # premier jeu de couleur pour l'affichage normal
  178. curses.init_pair(1,curses.COLOR_WHITE,curses.COLOR_BLACK)
  179. NORMAL=curses.color_pair(1)+curses.A_BOLD
  180. # deuxième jeu de couleur pour l'affichage inversé
  181. curses.init_pair(2,curses.COLOR_BLACK,curses.COLOR_WHITE)
  182. INVERSE=curses.color_pair(2)+curses.A_BOLD
  183. gauche,droite,haut,bas=1,1, 1,2       # décalages horizontaux et verticaux
  184. nblgn,nbcol=tailleecran()             # calcul de la taille de l'écran
  185. sortie=[ord('q'),ord('Q')]            # touches pour finir
  186. tableau=[]                            # création du tableau vide
  187. prochaine=[]                          # création du tableau pour la prochaine génération
  188. plein="*"                             # contenu d'une case pleine
  189. vide=" "                              # contenu d'une case vide
  190. generations=0                         # nombre de générations
  191. ##################################
  192. ####    CORPS DU PROGRAMME    ####
  193. ##################################
  194. creation()                      # création des tableaux
  195. remplissage()                   # remplissage initial du tableau
  196. k=0                             # initialisation pour rentrer dans la boucle
  197. while k not in sortie :         # TQ on n'a pas appuyé sur une touche pour sortir
  198.     affichage()                 # affichage de la génération courante
  199.     generation()                # calcul de la génération suivante
  200.     k=ecran.getch()             # récupérér la touche sur laquelle on a appuyé
  201. finir()                         # sortir de l'écran graphique
Dernière modification : 25/8/2016