O Jogo da Vida (em inglês: Conway's Game of Life) é um dos experimentos mais famosos da história da computação e da matemática recreativa. Criado em 1970 pelo matemático britânico John Horton Conway, ele não é um jogo no sentido convencional, pois não tem jogadores, pontuação ou um objetivo claro. É na verdade um autômato celular: uma simulação que evolui sozinha a partir de regras extremamente simples.
Curiosidade: Conway manteve o jogo em segredo por meses, testando configurações até ter certeza de que era "interessante". Quando publicado na revista Scientific American (Gardner, Martin. “Mathematical Games: The fantastic combinations of John Conway’s new solitaire game ‘life’.” Scientific American, vol. 223, no. 4, p. 120–123, outubro 1970.), explodiu em popularidade e nunca mais parou!
Como funciona?
Tudo acontece em uma grade infinita de células quadradas (em simulações usamos grades finitas, como 50×50). Cada célula pode estar em dois estados:
- Viva (geralmente representada por 1 ou cor preta)
- Morta (0 ou branca)
A cada geração (passo de tempo), todas as células são atualizadas simultaneamente com base em seus 8 vizinhos. As regras são apenas estas quatro:
- Uma célula viva com menos de 2 vizinhos vivos → morre (solidão)
- Uma célula viva com 2 ou 3 vizinhos vivos → sobrevive
- Uma célula viva com mais de 3 vizinhos vivos → morre (superpopulação)
- Uma célula morta com exatamente 3 vizinhos vivos → nasce!
E só isso. Não há mais regras.
Por que é tão fascinante?
Apesar da simplicidade, surgem comportamentos incrivelmente complexos:
- Padrões estáticos: como o "bloco" (2×2) que nunca muda
- Osciladores: como o "blinker" (pisca a cada geração)
- Naves espaciais: como o famoso glider que se move diagonalmente para sempre
- Construções universais: é possível criar portas lógicas, memórias e até computadores completos dentro do jogo!
Fato impressionante: O Jogo da Vida é Turing-completo, ou seja, pode simular qualquer computador real. Teoricamente, daria para rodar Windows dentro dele!
Exemplo de padrão famoso: o Glider
Uma das menores "naves espaciais", que se move uma célula a cada 4 gerações:
// Glider (3x3) - uma das estruturas mais icônicas
glider = [0 1 0;
0 0 1;
1 1 1];
Onde ver em ação?
O Jogo da Vida não é só diversão: ele inspira estudos em biologia, inteligência artificial, complexidade e até filosofia sobre o que significa "vivo".´ E tudo isso com apenas quatro regras.
Exemplo de código Scilab:
// ===========================================
// JOGO DA VIDA DE CONWAY (Conway's Game of Life)
// Implementação básica no Scilab
// ===========================================
// Limpa tudo:
clf();
close(winsid());
// --- 1. Parâmetros e Inicialização ---
// Dimensão da grade (matriz)
linhas = 70;
colunas = 70;
// Número de gerações a serem simuladas
numGeracoes = 1000;
// Probabilidade inicial de uma célula estar viva (entre 0 e 1)
probVida = 0.25;
// Cria a grade inicial (Estado 0) preenchida com 0s (mortas) ou 1s (vivas)
// rand(linhas, colunas) gera números aleatórios uniformes entre 0 e 1.
// O teste '< probVida' transforma em matriz booleana (verdadeiro/falso).
// *1 converte a matriz booleana para números (1 para verdadeiro, 0 para falso).
rand('seed',35);
grade = (rand(linhas, colunas) < probVida)*1;
grade = zeros(linhas, colunas);
m=20;
grade(40:40+m-1,40:40+m-1) = (rand(m,m) < probVida)*1;
// 1. NAVE ESPACIAL (Glider) - 3x3 - Posição: linhas 5-7, cols 5-7
glider = [0 1 0; // Forma clássica do Glider
0 0 1;
1 1 1];
grade(5:7, 5:7) = glider;
grade(5:7, 35:37) = glider;
// 2. R-PENTOMINO - Evolui de forma interessante - 3x3 - Pos: lin 5-7, col 20-22
r_pentomino = [0 1 1;
1 1 0;
0 1 0];
grade(5:7, 20:22) = r_pentomino;
// 3. BLINKER VERTICAL (oscilador período 2) - 3x1 - Pos: lin 20-22, col 40
blinker_v = [1; 1; 1];
grid(20:22, 40) = blinker_v;
// 4. BLOCK (estático) - 2x2 - Pos: lin 25-26, col 25-26
block = [1 1;
1 1];
grade(26:27, 28:29) = block;
// 5. TOAD (oscilador período 2) - 2x4 - Pos: lin 10-11, col 30-33
toad = [0 1 1 1;
1 1 1 0];
grade(10:11, 30:33) = toad;
// 6. BEACON (bloco pulsante, período 2) - 4x4 - Pos: lin 35-38, col 10-13
beacon = [1 1 0 0;
1 1 0 0;
0 0 1 1;
0 0 1 1];
grade(35:38, 10:13) = beacon;
// Matriz LWSS (5 linhas x 4 colunas)
lwss = [0 1 1 1 1; // Linha 1 (topo)
1 0 0 0 1; // Linha 2
0 0 0 0 1; // Linha 3
1 0 0 1 0]; // Linha 4 (base)
grade(15:18, 50:54) = lwss;
// --- 2. Função para Calcular a Próxima Geração ---
// Define uma função que aplica as regras do Jogo da Vida
function novaGrade=proximaGeracao(gradeAtual)
// Obtém as dimensões da grade
[r, c] = size(gradeAtual);
// Inicializa a nova grade (todos mortos)
novaGrade = zeros(r, c);
// Loop sobre cada célula da grade
for i = 1:r
for j = 1:c
// --- A. Contagem de Vizinhos Vivos ---
// Inicializa a contagem de vizinhos
vizinhosVivos = 0;
// Loop de 3x3 em torno da célula (i, j),
// ignorando a própria célula
for di = -1:1
for dj = -1:1
// Se (di, dj) = (0, 0), é a própria célula,
// então pule.
if di == 0 & dj == 0 then
continue
end
// Coordenadas do vizinho
ni = i + di;
nj = j + dj;
// Checa se o vizinho está dentro dos limites da grade
// Usa a topologia de grade finita (não toroidal/cíclica)
if ni >= 1 & ni <= r & nj >= 1 & nj <= c then
// Adiciona o estado do vizinho (1 se vivo, 0 se morto)
vizinhosVivos = vizinhosVivos + gradeAtual(ni, nj);
end
end
end
// --- B. Aplicação das Regras (4 Regras Fundamentais) ---
// Estado atual da célula
estadoAtual = gradeAtual(i, j);
if estadoAtual == 1 then
// 1. Sobrevivência: Se viva e tem 2 ou 3 vizinhos vivos, continua viva.
if vizinhosVivos == 2 | vizinhosVivos == 3 then
novaGrade(i, j) = 1;
// 2. Subpopulação/Superpopulação: Caso contrário (0, 1, ou >3), morre.
else
novaGrade(i, j) = 0; // Morre
end
else // estadoAtual == 0 (Célula Morta)
// 3. Nascimento: Se morta e tem EXATAMENTE 3 vizinhos vivos, nasce (fica viva).
if vizinhosVivos == 3 then
novaGrade(i, j) = 1; // Nasce
// 4. Continua Morta: Caso contrário, permanece morta.
else
novaGrade(i, j) = 0; // Permanece morta
end
end
end
end
endfunction
// --- 3. Simulação e Visualização (Loop Principal) ---
disp("Iniciando Jogo da Vida...")
f = scf();
f.color_map = graycolormap(32);
uicontrol(f, ...
"style", "pushbutton", ...
"string", "Fim", ...
"units", "normalized", ...
"position", [0.88 0.05 0.1 0.06], ...
"fontsize", 14, ...
"fontweight", "bold", ...
"backgroundcolor", [0.9 0.3 0.3], ...
"foregroundcolor", [1 1 1], ...
"callback", "close(gcf()); abort;", ... // fecha a figura atual
"callback_type", 10); // permite usar comandos Scilab diretamente
W = 0;
g = 0;
while W < 1
g = g + 1;
if g>2500 then W = 2; end;
// Calcula a próxima geração
grade = proximaGeracao(grade);
// --- Visualização (Plotagem) ---
// Plota a matriz 'grade' como uma imagem
// image(grade) mostra a matriz como pixels, onde o valor (0 ou 1)
// é mapeado para uma cor.
// Usamos 'grayplot' para maior controle sobre a visualização de matrizes.
// Define os limites dos eixos
x = 1:colunas;
y = 1:linhas;
// O comando grayplot plota a matriz de dados (grade)
// O 'colmap' (mapa de cores) é definido para ter apenas duas cores:
// 0 (morto) -> Cor 1 (Branco - 'wh')
// 1 (vivo) -> Cor 2 (Preto - 'bl')
// Matplot: Plota uma matriz de valores, mapeando os valores diretamente.
// Usamos -grade para inverter a escala de cores, se necessário.
// Melhor usar 'Matplot' e definir a paleta:
// Plota a grade usando as cores definidas
// Matplot(grade) mapeia: 0 -> Cor 1 (Branco), 1 -> Cor 2 (Preto)
Matplot(32*grade);
// Configurações estéticas para parecer um autômato celular
a = gca(); // Pega a alça para os eixos atuais
a.box = "on"; // Desenha a moldura
//a.x_location = "top"; // Eixo X em cima (opcional)
//a.y_reverse = "on"; // Inverte o eixo Y para começar no canto superior esquerdo
a.x_label.text = ""; // Remove o rótulo X
a.y_label.text = ""; // Remove o rótulo Y
a.title.text = "Geração " + string(g); // Título com o número da geração
// Pausa para visualizar a animação. O 0.1 é em segundos.
sleep(0.01);
end
disp("Simulação concluída.")
// =========================================