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.
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!
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?
- playgameoflife.com
- conwaylife.com (wiki com milhares de padrões)
- Simulações no Scilab, Python, JavaScript, etc.
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.") // =========================================

Nenhum comentário:
Postar um comentário