← Blog

Gra w życie Conwaya

Gra w życie Conwaya to klasyczny przykład tego, jak złożoność może wyłonić się z zaledwie kilku prostych reguł. Wyobraź sobie nieskończoną siatkę komórek — każda może być „włączona" (żywa) lub „wyłączona" (martwa). W każdej turze (lub „generacji") każda komórka sprawdza, ilu sąsiadów jest żywych. Jeśli jest zbyt zatłoczona, umiera. Jeśli jest zbyt samotna, również umiera. Ale przy dokładnie trzech sąsiadach martwa komórka ożywa.

Ten prosty zestaw reguł prowadzi do nieskończenie fascynujących zachowań — od stabilnych formacji i powtarzających się oscylatorów, po samopropagujące się „statki kosmiczne" przemierzające siatkę. To doskonała demonstracja tego, jak złożoność może wyłonić się z prostoty, a gra jest nawet Turing-zupełna, co oznacza, że teoretycznie może symulować dowolne obliczenia.

Jak to działa

Ładowanie planszy gry...

Przykłady wzorców

Te klasyczne wzorce pokazują emergentne zachowanie Gry. „Glider" demonstruje ruch po siatce, „Pulsar" tworzy hipnotyzującą oscylację, a „Small Exploder" pokazuje, jak proste kształty mogą ewoluować w złożone formy.

Algorytm

U podstaw Gry w życie leży zaledwie kilka eleganckich funkcji, które decydują o życiu i śmierci w naszym komórkowym wszechświecie:

// The core algorithm that determines life and death
function computeNextGeneration(currentGrid) {
  const newGrid = createEmptyGrid(rows, cols);

  for (let r = 0; r < rows; r++) {
    for (let c = 0; c < cols; c++) {
      const neighbors = countNeighbors(currentGrid, r, c);
      const cellState = currentGrid[r][c];

      // Apply Conway's rules of life
      if (cellState === 1) {
        // Live cell survives if it has 2 or 3 neighbors
        newGrid[r][c] = (neighbors === 2 || neighbors === 3) ? 1 : 0;
      } else {
        // Dead cell springs to life if it has exactly 3 neighbors
        newGrid[r][c] = (neighbors === 3) ? 1 : 0;
      }
    }
  }
  return newGrid;
}
Podstawowy algorytm stosuje reguły Conwaya do każdej komórki w siatce. Dla każdej generacji sprawdza stan każdej komórki i liczbę jej sąsiadów, aby określić, czy żyje, umiera, czy ożywa.
// Count live neighbors for each cell
function countNeighbors(g, row, col) {
  let count = 0;
  for (let i = 0; i < 8; i++) {
    const nr = row + NEIGHBOR_OFFSETS[i * 2];
    const nc = col + NEIGHBOR_OFFSETS[i * 2 + 1];
    if (nr >= 0 && nr < rows && nc >= 0 && nc < cols) {
      count += g[nr][nc];
    }
  }
  return count;
}
Zobacz Regułę 110 Wolframa →
Jak to działa

Zaznacz dowolny obszar, aby utworzyć skupiska komórek, lub zaznacz i przeciągnij, aby narysować żywe ścieżki. Naciśnij Play, aby obserwować ewolucję swojego dzieła, lub użyj Krok naprzód, aby przejść o jedną generację. Użyj Losuj dla chaosu lub Wyczyść, aby zacząć od nowa.

Zasady

Każda komórka w każdej generacji podlega czterem prostym zasadom:

  • Wyludnienie: Żywa komórka z mniej niż 2 sąsiadami umiera
  • Przetrwanie: Żywa komórka z 2 lub 3 sąsiadami przeżywa
  • Przeludnienie: Żywa komórka z więcej niż 3 sąsiadami umiera
  • Reprodukcja: Martwa komórka z dokładnie 3 sąsiadami ożywa
Sterowanie
  • Play/Pauza: Uruchom lub zatrzymaj symulację
  • Krok naprzód: Przejdź o jedną generację
  • Prędkość: Dostosuj szybkość zmiany generacji
  • Powiększenie: Zmień rozmiar siatki (tylko gdy zatrzymane)
Przykłady wzorców

Wypróbuj gotowe wzorce, aby zobaczyć różne zachowania:

  • Szybowiec: Wzorzec poruszający się po przekątnej siatki
  • Pulsar: Duży wzorzec oscylujący z okresem 3 generacji
  • Mały eksploder: Wzorzec rozszerzający się chaotycznie na zewnątrz