# Devo definir as bibliotecas necessárias
from random import SystemRandom
from PIL import Image, ImageDraw, ImageColor
import glob
0) Classe Célula
class Celula:
def __init__(self, estado):
self.__estado = estado
self.__vizinhos = []
self.__estadoFuturo = estado
def getEstado(self):
return self.__estado
def setEstado(self, estado):
self.__estado = estado
def setEstadoFuturo(self, estado):
self.__estadoFuturo = estado
def getEstadoFuturo(self):
return self.__estadoFuturo
# a regra de atualizacao do estado futuro será implementada nas classes filhas
def analisarVizinhos(self):
raise NotImplementedError
# depois de analisar a vizinhanca, a celula deve atualizar o seu estado atual
def atualizarEstado(self):
self.__estado = self.__estadoFuturo
# adiciona uma célula na lista de células vizinhas
def AddVizinho(self, c):
self.__vizinhos.append(c)
# retorna a lista de vizinhos da célula
def getVizinhos(self):
return self.__vizinhos
# Verificar quantos vizinhos cada celula possui
def contaVizinhos(self):
return len(self.__vizinhos)
# as cores serao definidas de acordo com as classes filhas
def getColor(self):
raise NotImplementedError
def getModelo(self):
return "Celula"
1) Modelo Jogo da Vida (GOL):
Estados possíveis: vivo - cor branca ou morto - cor preta.
Regra 1: Se uma célula viva tiver dois ou três vizinhos vivos, ela continua a viver. Caso contrário, morrerá por solidão ou superpopulação.
Regra 2: Se uma célula morta tiver exatamente três vizinhos, ela retorna a viver.
Composição de 100 interações do modelo jogo da vida

Modelo jogo da vida com 70 interações

# implementação da célula com as regras do jogo da vida (GOL)
class CelulaGOL(Celula):
def __init__(self):
# SystemRandom: uma forma mais imprevisível de gerar numeros aleatórios que Random :)
rnd = SystemRandom()
escolha = rnd.random()
if escolha > 0.5:
# Celula indica chamada do metodo (__init__) da classe pai (Celula)
Celula.__init__(self, False) # morto
else:
Celula.__init__(self, True) # vivo
# o metodo verifica o estado de vivo das células adjacentes e em outro momento
# atualizaremos o estado da celula, via método atualizarEstado()
def analisarVizinhos(self):
# Dois estados vivo(1) e morto (0)
vivos = self.getQteVizinhosEstado(True)
# Regra 1
if (self.getEstado() == True):
if (vivos == 2 or vivos == 3):
self.setEstadoFuturo(True)
# Caso contrário, morrerá por solidão ou superpopulação.
else:
self.setEstadoFuturo(False)
# Regra 2:
else:
if (vivos == 3):
self.setEstadoFuturo(True)
else:
self.setEstadoFuturo(False)
def getColor(self):
if self.getEstado() == True:
return 'black'
else:
return 'white'
# sobrescremevos o método getModelo para retornar o nome da classe de célula atual
# outra forma seria por type(self).__name__
def getModelo(self):
return "Celula da Vida"
2) Modelo Voto de Vichniac
Estados possíveis: vivo - cor branca ou morto - cor preta.
Regra 1: Considerando o estado da célula e as celulas adjacentes, se possuir cincou ou mais células vivas, ela se manterá viva.
Regra 2: Introduza um pouco de instabilidade no modelo, alternando o próximo estado quando possuir quatro ou cinco células vivas, conforme a regra 1.
Composição de 36 interações do modelo voto de vichniac

Modelo voto de Vichniac com 3 interações

Modelo voto de Vichniac com 20 interações

Modelo voto de Vichniac com 35 interações

class CelulaVichniac(Celula):
def __init__(self):
rnd = SystemRandom()
escolha = rnd.random()
if escolha > 0.5:
Celula.__init__(self, False) # morto
else:
Celula.__init__(self, True) # vivo
def analisarVizinhos(self):
vivos = self.getQteVizinhosEstado(True)
if self.getEstado() == True:
vivos = vivos + 1
if vivos <= 4:
self.setEstadoFuturo(False)
else: # vivos > 4
self.setEstadoFuturo(True)
if vivos == 4 | vivos == 5:
self.setEstadoFuturo(not self.getEstadoFuturo())
def getColor(self):
if self.getEstado() == True:
return 'black'
else:
return 'white'
def getModelo(self):
return "Celula Vichniac"
3) Modelo do Cérebro de Brian
Estados possíveis: desligado - cor branca, descansar- cor cinza e queimando - cor preta.
Regra 1: Se estiver no estado queimando, o próximo estado é descansar.
Regra 2: Se estiver descansando, o próximo estado é desligado.
Regra 3: Se estiver queimando e tiver exatamente dois vizinhos queimando, o estado se tornará queimando.
Composição de 20 interações do modelo brian brain

Modelo Brian Brain com 18 interações

class CelulaBrianBrain(Celula):
def __init__(self):
random = SystemRandom()
# Dois estados queimando(2) descansando(1) e desligado(0)
Celula.__init__(self, random.randint(0, 2))
def analisarVizinhos(self):
if self.getEstado() == 2:
self.setEstadoFuturo(1)
elif self.getEstado() == 1:
self.setEstadoFuturo(0)
elif self.getEstado() == 0:
# getQteVizinhosEstado
firing = self.getQteVizinhosEstado(2)
if firing == 2:
self.setEstadoFuturo(2)
else:
# mantem do jeito que esta
self.setEstadoFuturo(self.getEstado())
# para o estado firing: cor preta,resting cor cinza e desligado: branca
def getColor(self):
if self.getEstado() == 0:
return 'white'
elif self.getEstado() == 1:
return 'gray'
elif self.getEstado() == 2:
return 'black'
def getModelo(self):
return "Celula Brian Brain"
4) Modelo de Formato de Onda
Esse modelo não utiliza um conjunto de estado discreto, por exemplo vivo ou morto.
De forma a simplificar seu comportamento utilizaremos uma escala de valores 0 a 255, a qual será apresentada graficamente em uma escala de cinza.
Regra 1: Se a média da soma dos estados das células vizinhas for 255, o próximo estado será 0.
Regra 2: Se a média da soma dos estados das células vizinhas for 0, o próximo estado será 255.
Regra 3: Caso contrário o próximo estado será a soma do estado da célula e da média dos estados das células vizinhas, menos o estado anterior.
Regra 4: O próximo estado com valor que extrapola o intervalo de 0 a 255, ficará limitado ao limite inferior (0) ou superior (255), conforme o caso.
class CelulaWave(Celula):
def __init__(self, x, y):
Celula.__init__(self, (x + y) * 14)
self.__estadoAnterior = 0
def analisarVizinhos(self):
total = 0
if self.contaVizinhos == 0:
exit
vizinhos = self.getVizinhos()
for vizinho in vizinhos:
total = total + vizinho.getEstado()
media = float(int( total / 8))
#Regra 1
if media > 255:
self.setEstadoFuturo(0)
# Regra 2
elif media == 0:
self.setEstadoFuturo(255)
else:
self.setEstadoFuturo(self.getEstado() + media)
if (self.__estadoAnterior > 0):
self.setEstadoFuturo(self.getEstadoFuturo() - self.__estadoAnterior)
if (self.getEstadoFuturo() > 255):
self.setEstadoFuturo(255)
elif self.getEstadoFuturo() < 0:
self.setEstadoFuturo(0)
self.__estadoAnterior = self.getEstado()
def getColor(self):
nivel = str(format(int(self.getEstado()), '02X'))
return '#'+ str(nivel) + str(nivel)+str(nivel)
def getModelo(self):
return "Celula Formato Onda"
Composição de 70 interações do modelo formato de onda

Modelo formato de Onda com 6 interações

Modelo formato de Onda com 26 interações

Modelo formato de Onda com 49 interações

Modelo formato de Onda com 69 interações

3) crie um CA que contenha uma matriz de células de acordo com o modelo desejado.
4) Permita ainda, criar uma imagem (.jpeg) do CA de acordo os estados de suas células, em uma simbologia gráfica (cada cor representa um estado). Indique ainda quantas interações entre as células ocorreram para chegar ao estado apresentado.
class CelularAutomata:
# metodo que cria a classe CelularAutomata, o parâmetro modelo definirá qual classe de células será utilizada
def __init__(self, modelo, linhas, colunas):
self.__linhas = linhas
self.__colunas = colunas
self.__modelo = modelo
# quantas vezes o automata celular foi atualizado
self.__interacao = 0
# criar a matriz de celulas de acordo com o modelo
if modelo == 0:
self.__matrix = [[CelulaGOL() for x in range(colunas)] for y in range(linhas)]
elif modelo == 1:
self.__matrix = [[CelulaVichniac() for x in range(colunas)] for y in range(linhas)]
# vou consolidar um pouco mais a maioria
for i in range(linhas):
for j in range(colunas):
if i >26 or i < 7:
self.__matrix[i][j].setEstado(1)
elif modelo == 2:
self.__matrix = [[CelulaBrianBrain() for x in range(colunas)] for y in range(linhas)]
elif modelo == 3:
self.__matrix = [[CelulaWave(x / self.__colunas, y/ self.__linhas) for x in range(colunas)] for y in range(linhas)]
else:
# erro sair
quit
# Referenciar os vizinhos
for i in range(linhas):
for j in range(colunas):
# Adicionar para cada celula as referencias dos oito vizinhos
if (i > 0 and j > 0):
self.__matrix[i][j].AddVizinho(self.__matrix[i - 1][j - 1])
if (i > 0):
self.__matrix[i][j].AddVizinho(self.__matrix[i - 1][j])
if (i > 0 and j < colunas - 1):
self.__matrix[i][j].AddVizinho(self.__matrix[i - 1][j + 1])
if (j > 0):
self.__matrix[i][j].AddVizinho(self.__matrix[i][j - 1])
if (j < colunas - 1):
self.__matrix[i][j].AddVizinho(self.__matrix[i][j + 1])
if (i < linhas - 1 and j > 0):
self.__matrix[i][j].AddVizinho(self.__matrix[i + 1][j - 1])
if (i < linhas - 1):
self.__matrix[i][j].AddVizinho(self.__matrix[i + 1][j])
if (i < linhas - 1 and j < colunas - 1):
self.__matrix[i][j].AddVizinho(self.__matrix[i + 1][j + 1])
# retorna a celula na posicao i,j
def getCelula(self, i, j):
return self.__matrix[i][j]
# método que processa os estados das celulas vizinhas para definir o proximo estado de cada celula
def analisaCA(self):
for i in range(self.__linhas):
for j in range(self.__colunas):
self.__matrix[i][j].analisarVizinhos()
# método que atualiza o estado de cada celula com base em seu estado futuro
def atualizaCA(self):
for i in range(self.__linhas):
for j in range(self.__colunas):
self.__matrix[i][j].atualizarEstado()
self.__interacao = self.__interacao + 1
# método que conta a quantidade de celulas que possui determinado estado
# utilizarei para parar a criacao de imagens, quanto todas as celulas estiver mortas
def contaCelulasEstado(self, estado):
qte = 0
for i in range(self.__linhas):
for j in range(self.__colunas):
if self.__matrix[i][j].getEstado() == estado:
qte = qte + 1
return qte
#verifica se há no CA celulas que permitam interacao (nao mortas)
# True - todas as células morreram
def morreu(self):
if self.__modelo != 3:
if self.contaCelulasEstado(0) == self.__linhas*self.__colunas:
return True
else:
return False
else:
soma = 0
for i in range(self.__linhas):
for j in range(self.__colunas):
soma = soma + self.__matrix[i][j].getEstado()
if soma == 0:
return True
else:
return False
def getImage(self, legenda):
# diametro do circulo a ser inserido na imagem, igual ao da referencia Generative Art.
tam = 10
img = Image.new('RGB', (tam * self.__linhas, tam * self.__colunas), color='white')
d = ImageDraw.Draw(img)
for i in range(self.__linhas):
for j in range(self.__colunas):
# o metodo ImageColor.getrgb transforma o texto em um objeto color (r,g,b)
d.ellipse((tam * i, tam * j, tam * (i + 1), tam * (j + 1)),
fill=ImageColor.getrgb(self.__matrix[i][j].getColor()), outline=(0, 0, 0))
if legenda > 0:
msg = "Modelo: " + self.__matrix[i][j].getModelo() + " interacao: " + str(self.__interacao)
# inserindo texto na imagem, posicao (1,1), cor amarela
d.text((1, 1), msg, fill=(255, 255, 0))
return img
Agora integrando tudo com método crIaImagens
# cria para o modelo de automata celular indicado por m, as imagens para interacoes pedidas
def criaImagens(diretorio, m, interacoes):
if m > 3:
print('Modelo nao previsto')
exit()
ca = CelularAutomata(m, 50, 30)
# tenho que padronizar a quantidade de digitos a ser escrita no nome do arquivo
# para ordenar
tam = len(str(interacoes))
indice = ''
for i in range(tam):
indice = indice + str(0)
ca.getImage(1).save(diretorio + 'img_' + str(m) + '_' + indice + '.jpeg')
# faca n mudancas de estado e salve a imagem de cada uma
for i in range(interacoes):
# ao analisar e atualizar, acontece uma interacao
ca.analisaCA()
ca.atualizaCA()
indice = ''
for j in range(tam - len(str(i + 1))):
indice = indice + str(0)
indice = indice + str(i + 1)
ca.getImage(1).save(diretorio + 'img_' + str(m) + '_' + indice + '.jpeg')
# se todo o CA morreu, terminar
if ca.morreu() == True: break
if __name__ != "__main__":
diretorio = '/Users/philippe/PycharmProjects/'
for m in range(4):
if m == 0:
# GOL 100 iteracoes
criaImagens(diretorio, m, 100)
elif m == 1:
# Vichniac, 166 iteracoes
criaImagens(diretorio, m, 166)
elif m == 2:
# Brian Brain, 20 iteracoes
criaImagens(diretorio, m, 20)
elif m == 3:
# Onda, 70 iteracoes
criaImagens(diretorio, m, 70)