Code source de lejeu.dieu

 # -*- encoding:utf-8 -*-

from copy import deepcopy


[docs]class SuperDieu(object): """Classe optimisée permettant l'évolution des cellules.""" def __init__(self, etat, size=None, mode="infini", regle =((3, ),(2,3))): """Initialise la classe SuperDieu :param etat: Set de coordonnée des cellules vivantes :type etat: set :param size: couple de nombre définissant la largeur et la hauteur du rectangle défini au préalable :type size: tuple :param mode: mode de jeu influant sur le calcule des voisins :type mode: str :param regle: defini les règles :type regle: tuple """ self.regle = regle self.mode = mode self.size = size self.vivantes = etat self.n_voisines = {} self.mortes_actives = set() for (x,y) in self.vivantes: # Tout les vivants for (v_x, v_y) in self.coord_voisins((x,y)): # Voisins de (x,y) if not (v_x,v_y) in self.n_voisines: self.n_voisines[(v_x,v_y)] = 0 # On initialise le voisins à zéro self.n_voisines[(v_x,v_y)] += 1 # Nombres de voisins augmente de 1 for (x,y) in self.n_voisines: # Pour toutes les cellules vivantes et leur voisins if not(x,y) in self.vivantes: # Selectionne tout les voisins morts existants self.mortes_actives.add((x,y)) # Tadaa ! Nous avons tout les voisins morts !
[docs] def coord_voisins(self, c): """Calcule les coordonnées des voisins d'une cellule. :param c: Couple de coordonnées. :type c: Tuple. :return: Les voisins de c. :rtype: Set. """ voisins_infini = {(c[0]-1, c[1]-1), (c[0]-1, c[1]), (c[0]-1, c[1]+1), (c[0], c[1]-1), (c[0], c[1]+1), (c[0]+1, c[1]-1), (c[0]+1, c[1]), (c[0]+1, c[1]+1)} if self.mode == "infini": return voisins_infini if self.mode == "snake": return {(x%self.size[0], y%self.size[1]) for (x,y) in voisins_infini}
[docs] def doit_mourir(self, c): """Défini les cellules qui mourront à la prochaine génération. :param c: Couple de coordonnées. :type c: tuple :return: Doit-elle mourir ? :rtype: bool """ if c in self.n_voisines: return not (self.n_voisines[c] in self.regle[1]) else: return True
[docs] def doit_naitre(self, c): """Défini les cellules qui naîtront à la prochaine génération. :param c: Couple de coordonnées. :type c: tuple :return: Doit-elle survivre ? :rtype: bool """ return self.n_voisines[c] in self.regle[0]
[docs] def generation_suivante(self): """Applique l'algorithme d'évolution en mode ``infini``. - Calcule les coordonnées des cellules nées et mortes suivants la règle du JEU. - Met à jour ``self.n_voisines``, ``self.mortes_actives``, ``self.vivantes``. :return: Les cellules nées et mortes. :rtype: bool """ # ajoute les celulles qui vont naître au prochain tour nees = {c for c in self.mortes_actives if self.doit_naitre(c)} # ajoute les celulles qui vont mourir au prochain tour mortes = {c for c in self.vivantes if self.doit_mourir(c)} for (x,y) in nees: self.vivantes.add((x,y)) self.mortes_actives.remove((x,y)) for (v_x,v_y) in self.coord_voisins((x,y)): if not (v_x,v_y) in self.n_voisines: self.n_voisines[(v_x, v_y)] = 0 self.mortes_actives.add((v_x, v_y)) self.n_voisines[(v_x,v_y)] += 1 for (x,y) in mortes: self.vivantes.remove((x,y)) if (x,y) in self.n_voisines: if self.n_voisines[(x,y)] >= 1: self.mortes_actives.add((x,y)) for (v_x,v_y) in self.coord_voisins((x,y)): if self.n_voisines[(v_x,v_y)] == 1: if (v_x,v_y) in self.mortes_actives: self.mortes_actives.remove((v_x,v_y)) del self.n_voisines[(v_x,v_y)] else: self.n_voisines[(v_x,v_y)] -= 1 return nees, mortes
[docs]class Dieu(object): """Classe gérant la vie et la mort des cellules.""" def __init__(self, etat): """Initialise la classe Dieu. :param etat: Liste de coordonnée des cellules vivantes. :type etat: liste """ # liste de liste composée de 0 et 1 (0: cellule morte) self.etat = etat self.size = (len(etat), len(etat[0]))
[docs] def generation_suivante(self, mode='snake'): """Calcule la prochaine génération avec le bon mode assigné. """ getattr(self, 'generation_suivante_'+mode)()
[docs] def generation_suivante_snake(self): """Applique l'algorithme d'évolution en mode ``snake``. - Fait une copie de ``self.etat``. - Prends tout les voisins de chaque cellules et applique les deux règles. - Met à jour ``self.etat``. """ # nouvel_etat est une copie de l'état courant nouvel_etat = deepcopy(self.etat) for x in range(self.size[0]): for y in range(self.size[1]): # n: nombre de voisins vivant, initialisé à -self.etat[x][y] car # sinon on compterais aussi la cellule en cours dans les # boucles. n = -self.etat[x][y] for v_x in (x-1, x, x+1): for v_y in (y-1, y, y+1): # "%self.size" permet de definir un cellule situé à l'opposé # dans le cas ou la cellule est or du "carré" if self.etat[v_x % self.size[0]][v_y % self.size[1]] == 1: # le voisin est vivant n += 1 # regle 1: naissance if self.etat[x][y] == 0: if n == 3: nouvel_etat[x][y] = 1 # regle 2: mort else: if not (2 <= n <= 3): nouvel_etat[x][y] = 0 # on sauvegarde nouvel_etat dans `self.etat` self.etat = nouvel_etat
[docs] def generation_suivante_mur(self): """Applique l'algorithme d'évolution en mode ``mur``. - Fait une copie de ``self.etat``. - Prends tout les voisins de chaque cellules et applique les deux règles. - Met à jour ``self.etat``. """ # nouvel_etat est une copie de l'état courant # nouvel_etat est une copie de l'état courant nouvel_etat = deepcopy(self.etat) for x in range(self.size): for y in range(self.size): # n: nombre de voisins vivant, initialisé à -self.etat[x][y] car # sinon on compterais aussi la cellule en cours dans les # boucles. n = -self.etat[x][y] for v_x in (x-1, x, x+1): for v_y in (y-1, y, y+1): if -1 < v_x < self.size and -1 < v_y < self.size: if self.etat[v_x][v_y] == 1: # le voisin est vivant n += 1 # regle 1: naissance if self.etat[x][y] == 0: if n == 3: nouvel_etat[x][y] = 1 # regle 2: mort else: if not (2 <= n <= 3): nouvel_etat[x][y] = 0 # on sauvegarde nouvel_etat dans `self.etat` self.etat = nouvel_etat nouvel_etat = deepcopy(self.etat)
[docs] def print_etat(self): """Affiche l'etat de manière comprehensible sur la console (debug). """ for ligne in self.etat: print(" ".join(str(i) for i in ligne))