Le Jeu de la Vie de Conway
Le Jeu de la Vie de Conway est un exemple classique de la façon dont la complexité peut émerger de quelques règles simples. Imaginez une grille infinie de cellules — chacune peut être « allumée » (vivante) ou « éteinte » (morte). À chaque tour (ou « génération »), chaque cellule vérifie combien de voisins sont vivants. Si elle est trop entourée, elle meurt. Si elle est trop isolée, elle meurt aussi. Mais avec exactement trois voisins, une cellule morte prend vie.
Cet ensemble de règles simples mène à des comportements infiniment fascinants — des formations stables et des oscillateurs répétitifs aux « vaisseaux spatiaux » autopropulsés qui traversent la grille. C'est une démonstration parfaite de la façon dont la complexité peut naître de la simplicité, et c'est même Turing-complet, ce qui signifie qu'il peut théoriquement simuler tout calcul.
Exemples de motifs
Ces motifs classiques illustrent le comportement émergent du jeu. Le « Glider » démontre le mouvement à travers la grille, le « Pulsar » crée une oscillation fascinante, et le « Small Exploder » montre comment des formes simples peuvent évoluer vers des formes complexes.
L'Algorithme
Au cœur du Jeu de la Vie se trouvent quelques fonctions élégantes qui déterminent la vie et la mort dans notre univers cellulaire :
// 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;
}
// 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;
}