콘웨이의 생명 게임
Conway의 라이프 게임은 몇 가지 간단한 규칙에서 복잡성이 피어나는 전형적인 예입니다. 무한한 셀 그리드를 상상해 보세요. 각 셀은 '켜짐'(살아있음) 또는 '꺼짐'(죽음) 상태입니다. 매 턴(또는 '세대')마다 모든 셀은 살아있는 이웃의 수를 확인합니다. 너무 밀집되면 죽고, 너무 고립되어도 죽습니다. 하지만 정확히 세 개의 이웃이 있으면 죽은 셀이 생명을 얻습니다.
이 간단한 규칙 세트는 끝없이 매혹적인 행동을 만들어냅니다. 안정적인 구조와 반복되는 진동자부터 그리드를 가로지르는 자기 추진 '우주선'까지 다양합니다. 이것은 단순함에서 복잡성이 어떻게 발생할 수 있는지에 대한 완벽한 시연이며, 튜링 완전하기도 합니다. 즉, 이론적으로 모든 계산을 시뮬레이션할 수 있습니다.
게임 보드 로딩 중...
패턴 예시
이 고전적인 패턴들은 게임의 창발적 행동을 보여줍니다. 'Glider'는 그리드를 가로지르는 움직임을 보여주고, 'Pulsar'는 매혹적인 진동을 만들며, 'Small Exploder'는 단순한 모양이 복잡한 형태로 어떻게 진화하는지 보여줍니다.
알고리즘
라이프 게임의 핵심에는 이 셀 우주에서 삶과 죽음을 결정하는 몇 가지 우아한 함수가 있습니다:
// 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;
}
핵심 알고리즘은 그리드의 각 셀에 Conway의 규칙을 적용합니다. 매 세대마다 모든 셀의 상태와 이웃 수를 확인하여 살아남을지, 죽을지, 또는 생명을 얻을지 결정합니다.
// 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;
}