GODRICH
#css애니메이션#버튼#로딩#전환효과#스크롤#대시보드#실전ui#디자인트렌드

생명게임 시뮬레이터 9가지 — 이웃 수 값으로 세대 잇기

격자가 제멋대로 움직이는 것처럼 보이지만 실제로는 세대마다 이웃 수 값 하나로 생사가 갈리고, 그 값이 쌓인 나이만큼 색이 바래며, 같은 값이 규칙표를 타고 전선처럼 신호를 옮긴다 — 아홉 가지 계산형 셀룰러 오토마타를 그 값으로 본다.

자동 재생 · 눌러서 해당 항목으로 · 전부 한 zip

기본 생사 규칙 하나를 아홉 방향으로 나눠 놓았습니다. 이웃 수로 사각 격자의 생사를 가르는 기본형에서 시작해, 그 규칙을 한 줄짜리 이진 규칙 번호로 좁히고, 고정된 발사틀로 장면을 채우고, 죽은 뒤에도 나이 값을 남기고, 손으로 직접 씨앗을 찍고, 규칙표 자체를 몇 세대마다 바꿔치기하고, 이웃을 여섯 개로 바꾸고, 상태를 네 단계로 늘려 신호를 옮기고, 마지막은 네 구역이 각자 다른 규칙표로 한 화면에서 동시에 도는 순서로 묶었습니다. 아홉 가지 모두 같은 셀룰러 오토마타 알고리즘 하나를 이웃 수 계산 방향만 바꿔 쓴 결과입니다.

규칙 하나가 어떻게 화면을 만드나 — 이웃 수 계산

이 아홉 가지 셀룰러 오토마타는 전부 칸 하나마다 이웃 수를 세고 그 수를 규칙표와 비교해 다음 세대의 생사를 정하는 같은 틀 위에 있습니다. 기본형(01)은 살아있는 칸이 이웃 2~3개(SURVIVE_MIN·SURVIVE_MAX)면 살아남고, 죽은 칸은 이웃이 정확히 3개(BIRTH_COUNT)일 때만 태어납니다 — 이 세 값만 바꿔도 격자가 성기게 흩어지는지 빽빽하게 굳는지가 갈립니다.

같은 계산을 다른 모양으로 옮긴 항목도 있습니다. 02 는 이웃을 왼쪽·자신·오른쪽 세 칸으로 줄이고 그 조합을 8비트 규칙 번호(RULE=30)의 이진수 자리와 대조해 다음 줄 상태를 정하는 1차원 판입니다. 07 은 칸을 육각형으로 어긋나게 배치해 OFF_EVEN·OFF_ODD 오프셋 표로 이웃을 정확히 여섯 개만 세고, 08 은 칸 상태를 빈칸·전선·신호머리·신호꼬리 네 단계로 늘려 전선 칸이 이웃 신호머리 수(HEAD_NEIGHBORS_MIN·MAX)에 따라 신호머리로 바뀝니다.

규칙표 값 자체를 바꾸는 항목도 있습니다. 06 은 26세대(CYCLE_GENERATIONS)마다 RULESETS 배열의 다음 규칙 세트로 통째로 갈아 끼우고, 09 는 화면을 네 구역(QUADS)으로 나눠 구역마다 다른 규칙표를 배정해 한 캔버스 안에서 네 무늬가 동시에 삽니다.

이웃 수 계산이 실제로 화면에서 얼마나 움직였는지 — 24프레임 실측

각 데모를 24프레임 캡처해 인접한 23개 구간(델타)의 픽셀 변화로 움직임을 쟀습니다. 누적면적은 프레임마다 바뀐 픽셀 비율을 더한 값이고, 강도_평균은 바뀐 픽셀의 평균 밝기 차, 움직인프레임은 23개 구간 중 실제로 뭔가 바뀐 구간 수입니다. 아홉 항목 전부 23/23 이라 캡처 구간마다 매번 무언가 바뀌었다는 뜻입니다.

항목 누적면적 강도_평균 움직인프레임
01 기본 격자 51.9% 144.5 23/23
02 규칙 스트립 53.9% 47.8 23/23
03 글라이더 건 27.6% 47.6 23/23
04 나이 잔상 55.7% 32.8 23/23
05 포인터 그리기 17.0% 146.7 23/23
06 규칙 실험실 60.3% 55.1 23/23
07 육각 격자 49.5% 55.0 23/23
08 와이어월드 26.7% 136.8 23/23
09 히어로 장면 62.4% 148.5 23/23

01이웃 수 값으로 생사가 갈리는 기본 격자 오토마타

칸마다 살아있는 이웃 수를 세어 SURVIVE_MIN·SURVIVE_MAX(2~3)와 BIRTH_COUNT(3) 규칙표와 비교하고, 그 수가 규칙에 맞으면 다음 세대에 살아남거나 새로 태어나게 해 매 세대 48×30칸 전체를 Canvas 2D API 로 다시 그립니다. 로딩 화면 배경이나 화면보호기 스타일 인트로에 붙이기 좋습니다.

이웃 수 값으로 생사가 갈리는 기본 격자 오토마타
새 창에서 열기

01 · 이웃 수 값으로 생사가 갈리는 기본 격자 오토마타 — 측정 누적면적 51.899% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

SURVIVE_MINBIRTH_COUNTfillRect
  function step(){
    for (let y = 0; y < ROWS; y++){
      for (let x = 0; x < COLS; x++){
        const alive = grid[idx(x, y)] === 1;
        const n = neighborCount(x, y);
        let willLive = 0;
        if (alive){
          willLive = (n >= SURVIVE_MIN && n <= SURVIVE_MAX) ? 1 : 0;
        } else {
          willLive = (n === BIRTH_COUNT) ? 1 : 0;
        }
        next[idx(x, y)] = willLive;
      }
    }
    const tmp = grid; grid = next; next = tmp;
    generation++;
  }

02한 줄 규칙 번호 값이 다음 줄 무늬를 정하는 스트립 오토마타

한 줄짜리 칸 배열을 왼쪽·자신·오른쪽 세 칸의 조합으로 8비트 규칙 번호(RULE=30)와 대조해 다음 줄 상태를 정하고, copyWithin 으로 기존 줄을 한 칸씩 위로 밀어 올린 뒤 맨 아랫줄에 새 줄을 채워 삼각형 줄무늬가 누적됩니다. 배경 텍스처나 알고리즘 설명 삽화에 씁니다.

한 줄 규칙 번호 값이 다음 줄 무늬를 정하는 스트립 오토마타
새 창에서 열기

02 · 한 줄 규칙 번호 값이 다음 줄 무늬를 정하는 스트립 오토마타 — 측정 누적면적 53.91% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

RULEcopyWithinfillRect
  let grid = new Uint8Array(COLS * ROWS);

  function idx(x, y){ return y * COLS + x; }

  function clearGrid(){
    grid.fill(0);
  }

  function seedRow(seedX){
    grid[idx(seedX, ROWS - 1)] = 1;
  }

  function step(){
    grid.copyWithin(0, COLS, ROWS * COLS);
    const base = (ROWS - 2) * COLS;
    const outBase = (ROWS - 1) * COLS;
    for (let x = 0; x < COLS; x++){
      const l = grid[base + ((x - 1 + COLS) % COLS)];
      const m = grid[base + x];
      const r = grid[base + ((x + 1) % COLS)];
      const pattern = l * 4 + m * 2 + r;
      grid[outBase + x] = ruleBits[pattern];
    }
  }

03고정된 발사틀이 값 간격마다 이동체를 쏘아 보내는 장면 오토마타

GUN_ROWS(4·18·32행) 세 자리에 고정한 작은 세포 배열이 스스로 회복하면서 대각선으로 이동하는 작은 무리를 하나씩 밀어내고, 밀려난 무리는 화면 끝에 닿을 때까지 같은 모양을 유지한 채 이동합니다. 셀 크기를 6px 로 줄여 80×50칸을 써서 이동체가 지나갈 공간을 넉넉하게 잡았습니다.

고정된 발사틀이 값 간격마다 이동체를 쏘아 보내는 장면 오토마타
새 창에서 열기

03 · 고정된 발사틀이 값 간격마다 이동체를 쏘아 보내는 장면 오토마타 — 측정 누적면적 27.599% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

GUN_ROWSplaceGunseedGrid
  function placeGun(ox, oy, mirror){
    for (let i = 0; i < GUN_CELLS.length; i++){
      const dx = GUN_CELLS[i][0], dy = GUN_CELLS[i][1];
      const x = ox + (mirror ? (GUN_W - 1 - dx) : dx);
      const y = oy + dy;
      if (x >= 0 && x < COLS && y >= 0 && y < ROWS) grid[idx(x, y)] = 1;
    }
  }

  const GUN_ROWS = [4, 18, 32];

  function seedGrid(offset){
    grid.fill(0);
    for (let i = 0; i < GUN_ROWS.length; i++){
      placeGun(2 + offset, GUN_ROWS[i], false);
      placeGun(COLS - 2 - (GUN_W - 1) - offset, GUN_ROWS[i], true);
    }
  }

04세대 나이 값만큼 색이 바래는 잔상 오토마타

칸마다 살아있는 연속 세대 수를 나이 값(age, 최대 AGE_CAP=10)으로 따로 세어 그 값이 클수록 진한 색을 칠하고, 칸이 죽은 뒤에도 나이 값을 TRAIL_DECAY(1)만큼 세대마다 낮춰가며 몇 세대 동안 옅은 잔상을 남깁니다. 히트맵 스타일 대시보드 배경에 어울립니다.

세대 나이 값만큼 색이 바래는 잔상 오토마타
새 창에서 열기

04 · 세대 나이 값만큼 색이 바래는 잔상 오토마타 — 측정 누적면적 55.72% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

TRAIL_DECAYAGE_CAPTRAIL_HIGH
  function step(){
    for (let y = 0; y < ROWS; y++){
      for (let x = 0; x < COLS; x++){
        const i = idx(x, y);
        const wasAlive = alive[i] === 1;
        const n = neighborCount(x, y);
        let willLive = 0;
        if (wasAlive){
          willLive = (n >= SURVIVE_MIN && n <= SURVIVE_MAX) ? 1 : 0;
        } else {
          willLive = (n === BIRTH_COUNT) ? 1 : 0;
        }
        nextAlive[i] = willLive;
      }
    }
    for (let i = 0; i < alive.length; i++){
      if (nextAlive[i]){
        age[i] = Math.min(AGE_CAP, age[i] + 1);
      } else {
        age[i] = Math.max(0, age[i] - TRAIL_DECAY);
      }
    }
    const tmp = alive; alive = nextAlive; nextAlive = tmp;
  }

05커서 좌표 값으로 칸을 직접 켜고 끄는 그리기 오토마타

포인터가 격자 위를 지나는 동안 pointerdown·pointermove 좌표를 cellFromEvent 로 칸 번호로 바꿔 그 칸을 강제로 켜고, 손을 떼면(pointerup) 그려둔 배치 그대로 규칙표에 따라 세대가 자동으로 진행됩니다. 패턴을 직접 그려보는 교육용 체험판에 맞습니다.

커서 좌표 값으로 칸을 직접 켜고 끄는 그리기 오토마타
새 창에서 열기

05 · 커서 좌표 값으로 칸을 직접 켜고 끄는 그리기 오토마타 — 측정 누적면적 16.988% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

autoSeedpointermoveSURVIVE_MIN
  function cellFromEvent(e){
    const rect = cvEl.getBoundingClientRect();
    const px = (e.clientX - rect.left) * (W / rect.width);
    const py = (e.clientY - rect.top) * (H / rect.height);
    const cx = Math.max(0, Math.min(COLS - 1, Math.floor(px / CELL)));
    const cy = Math.max(0, Math.min(ROWS - 1, Math.floor(py / CELL)));
    return [cx, cy];
  }

  function paintAt(e){
    const c = cellFromEvent(e);
    grid[idx(c[0], c[1])] = 1;
    render();
  }

  function onPointerDown(e){
    human();
    isDrawing = true;
    paused = true;
    updateAria();
    paintAt(e);
  }

  function onPointerMove(e){
    if (!isDrawing) return;

06규칙표 값을 바꿔 무늬가 달라지는 규칙 실험 오토마타

생존·탄생 조건을 담은 RULESETS 배열(Life·HighLife·Seeds·Replicator 네 세트) 값을 CYCLE_GENERATIONS(26세대)마다 통째로 바꿔치고, 그때마다 seedSame() 이 같은 시작 배치(baseSeedSnapshot)를 다시 채워 넣어 규칙표 값만 다르게 같은 씨앗이 서로 다른 무늬로 갈라지는 걸 비교할 수 있습니다. 알고리즘 비교 설명 섹션에 붙이기 좋습니다.

규칙표 값을 바꿔 무늬가 달라지는 규칙 실험 오토마타
새 창에서 열기

06 · 규칙표 값을 바꿔 무늬가 달라지는 규칙 실험 오토마타 — 측정 누적면적 60.251% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

RULESETSCYCLE_GENERATIONSbaseSeedSnapshot
  function step(){
    const rule = RULESETS[ruleIndex];
    for (let y = 0; y < ROWS; y++){
      for (let x = 0; x < COLS; x++){
        const alive = grid[idx(x, y)] === 1;
        const n = neighborCount(x, y);
        const willLive = alive ? rule.survive.indexOf(n) !== -1 : rule.born.indexOf(n) !== -1;
        next[idx(x, y)] = willLive ? 1 : 0;
      }
    }
    const tmp = grid; grid = next; next = tmp;
    genCount++;
    if (genCount >= CYCLE_GENERATIONS){
      genCount = 0;
      ruleIndex = (ruleIndex + 1) % RULESETS.length;
      seedSame();
    }
  }

07육각 이웃 수 값으로 갈라지는 벌집 격자 오토마타

칸을 사각형이 아니라 육각형으로 어긋나게 배치해 OFF_EVEN·OFF_ODD 오프셋 표로 이웃을 정확히 여섯 개만 갖게 하고, 그 여섯 이웃 중 살아있는 수 값을 규칙표와 비교해 사각 격자와는 다른 방향으로 무늬가 퍼집니다. 18×9칸의 굵은 육각 셀로 보드게임 스타일 배경에 씁니다.

육각 이웃 수 값으로 갈라지는 벌집 격자 오토마타
새 창에서 열기

07 · 육각 이웃 수 값으로 갈라지는 벌집 격자 오토마타 — 측정 누적면적 49.486% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

OFF_EVENOFF_ODDhexPath
  const OFF_EVEN = [[-1,-1],[-1,0],[0,-1],[0,1],[1,-1],[1,0]];
  const OFF_ODD  = [[-1,0],[-1,1],[0,-1],[0,1],[1,0],[1,1]];

  function seedGrid(){
    for (let i = 0; i < grid.length; i++) grid[i] = rnd() < 0.33 ? 1 : 0;
  }

  function neighborCount(x, y){
    const offs = (x & 1) ? OFF_ODD : OFF_EVEN;
    let n = 0;
    for (let i = 0; i < 6; i++){
      const nx = x + offs[i][0], ny = y + offs[i][1];
      if (nx < 0 || ny < 0 || nx >= COLS || ny >= ROWS) continue;
      n += grid[idx(nx, ny)];
    }
    return n;
  }

08네 단계 값이 전선을 타고 도는 신호 회로 오토마타

칸마다 빈칸·전선·신호머리·신호꼬리 네 단계 상태 값을 갖게 하고, 전선 칸은 이웃한 신호머리 수가 HEAD_NEIGHBORS_MIN(1)~HEAD_NEIGHBORS_MAX(2) 범위일 때만 다음 세대에 신호머리로 바뀌어 미리 그려둔 전선 모양을 따라 신호가 한 방향으로 흐릅니다. 논리 회로 개념을 설명하는 교육 자료에 맞습니다.

네 단계 값이 전선을 타고 도는 신호 회로 오토마타
새 창에서 열기

08 · 네 단계 값이 전선을 타고 도는 신호 회로 오토마타 — 측정 누적면적 26.672% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

HEAD_NEIGHBORS_MAXbuildCircuitneighborHeadCount
  function step(){
    for (let y = 0; y < ROWS; y++){
      for (let x = 0; x < COLS; x++){
        const i = idx(x, y);
        const s = grid[i];
        let ns = s;
        if (s === WIRE){
          const hc = neighborHeadCount(x, y);
          if (hc >= HEAD_NEIGHBORS_MIN && hc <= HEAD_NEIGHBORS_MAX) ns = HEAD;
        } else if (s === HEAD){
          ns = TAIL;
        } else if (s === TAIL){
          ns = WIRE;
        }
        next[i] = ns;
      }
    }
    const tmp = grid; grid = next; next = tmp;
  }

09여러 규칙 값이 한 화면에서 동시에 도는 히어로 장면 오토마타

화면을 QUADS 네 구역으로 나눠 구역마다 RULESETS 의 다른 규칙표 값을 배정하고, 세대마다 각 구역이 neighborCountInQuad 로 자기 구역 경계 안에서만 이웃을 세어 인접 구역의 값이 서로 넘보지 않게 계산을 분리해 한 캔버스에 네 무늬가 동시에 삽니다. 랜딩 페이지 히어로 배경이나 포트폴리오 인트로 장면에 쓰기 좋습니다.

여러 규칙 값이 한 화면에서 동시에 도는 히어로 장면 오토마타
새 창에서 열기

09 · 여러 규칙 값이 한 화면에서 동시에 도는 히어로 장면 오토마타 — 측정 누적면적 62.378% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · 비밀번호 보기

RULESETSQUADSneighborCountInQuad
  function step(){
    for (let qi = 0; qi < 4; qi++){
      const q = QUADS[qi];
      const rule = RULESETS[qi];
      for (let y = q.y0; y <= q.y1; y++){
        for (let x = q.x0; x <= q.x1; x++){
          const alive = grid[idx(x, y)] === 1;
          const n = neighborCountInQuad(x, y, q);
          const willLive = alive ? rule.survive.indexOf(n) !== -1 : rule.born.indexOf(n) !== -1;
          next[idx(x, y)] = willLive ? 1 : 0;
        }
      }
    }
    const tmp = grid; grid = next; next = tmp;
  }

이 아홉 개를 실제로 어디에 붙이는가

관리자 대시보드 로딩 화면에는 01 기본 격자가 잘 맞습니다. 데이터를 기다리는 동안 화면이 완전히 멈춰 있지 않다는 인상을 주면서도, 이웃 수 계산만으로 돌아가 무거운 라이브러리 없이 붙일 수 있기 때문입니다.

작업 이력이나 로그를 보여주는 화면에는 04 나이 잔상이 어울립니다. 최근 세대일수록 진한 색, 오래된 세대일수록 옅은 색으로 남아 시간 순서를 굳이 숫자로 적지 않아도 눈으로 읽히기 때문입니다.

교육용 시뮬레이터나 워크숍 자료에는 05 포인터 그리기가 어울립니다. 손으로 직접 씨앗을 찍어보고 손을 떼는 순간부터 같은 규칙표가 자동으로 이어받아 진행하는 과정을 그대로 보여주기 때문입니다.

생명게임 시뮬레이터는 어디서 더 볼 수 있나?

이 편과 가장 가까운 자리는 html5 canvas 애니메이션 9종 — 물방울·블랙홀 특수효과 입니다. 그 편은 스넬 굴절·원근 투영 같은 연속 물리 계산으로 화면을 그리는 반면, 이 편의 아홉 개는 칸 하나하나가 살았는지 죽었는지 이산적인 값만 갖고 세대 단위로 갱신됩니다.

튜링 패턴 시뮬레이션 9종 — 라이브러리 없이 두 물질의 반응 격자만으로 도 격자 계산이라는 점은 같지만, 그 편은 두 물질의 농도 값이 실수로 매끄럽게 퍼지고 섞이는 반응-확산 방정식을 씁니다. 이 편은 칸이 오직 정수 상태(생·사, 08 처럼 네 단계) 사이를 규칙표대로 건너뛸 뿐 중간값이 없습니다.

낙하 물질을 다루는 폴링 샌드(falling sand simulator) 9종 — 모래·물·불 셀 오토마타 도 칸 단위 셀 오토마타지만, 아래로 떨어지거나 옆으로 흐르는 중력 방향 규칙이 중심입니다. 이 편의 아홉 개는 중력 방향이 없고 이웃 수 값 하나로만 생사·상태를 결정합니다.

셀룰러 오토마타를 진행률 부품 하나로 좁혀 쓴 예도 있습니다. 로딩 화면 채움 효과를 다룬 편의 09번 항목은 "이웃 3개 이상이면 태어나고 한 번 살면 계속 산다"는 규칙 하나만 고정해 두고 살아있는 칸의 비율을 진행률 퍼센트로 바꿔 쓰지만, 여기 아홉 개는 진행률이 아니라 규칙표·나이·좌표·상태 단계 같은 값 자체를 화면 장면으로 보여주는 데 씁니다.

어디서 깨지는가 — 접근성·reduced-motion·성능

아홉 개 원본을 직접 열어봐야 어디서 깨지는지 실감이 나는데, 그 zip 은 비밀번호 p9w3yqnr 로 잠겨 있어 아래 함정을 먼저 읽고 여는 걸 권합니다.

08 와이어월드는 HEAD_NEIGHBORS_MIN(1)과 HEAD_NEIGHBORS_MAX(2) 두 값 사이에서만 전선이 신호머리로 바뀝니다. 상한 값을 하한보다 낮게 두면(예: MAX 를 0 으로) 조건 hc >= 1 && hc <= 0 이 항상 거짓이 되어 전선 칸이 영원히 신호머리로 바뀌지 못하고 회로 전체가 깨진 채 멈춥니다 — 두 상수는 항상 MIN ≤ MAX 순서를 지켜야 합니다.

01·04·06·09 의 SURVIVE_MIN·SURVIVE_MAX 도 같은 함정이 있습니다. 최소값을 최대값보다 크게 두면 n >= SURVIVE_MIN && n <= SURVIVE_MAX 조건이 항상 거짓이 되어 어떤 칸도 살아남지 못하고 다음 세대에 격자가 통째로 비어버립니다.

아홉 개 모두 prefers-reduced-motion 이 참이면 requestAnimationFrame 루프를 아예 시작하지 않습니다. 평소에는 화면에 있는 동안 자동으로 세대가 진행되지만, reduce 환경에서는 씨앗을 심은 정지 세대 한 장만 그리고 멈춰 있다가, 클릭이나 Enter·스페이스바를 누르면 그 순간 render() 를 한 번만 더 불러 입력 직후의 세대만 보여줍니다. 05 는 클릭 대신 pointerdown·pointermove·pointerup 으로 씨앗을 찍고, 나머지 여덟 개는 click과 keydown으로 멈추거나 다시 진행합니다. 창 크기가 바뀌면(resize) 아홉 개 전부 다시 계산하지 않고 같은 격자를 render() 로만 다시 그립니다.

변형 세 가지와 접근성

값 하나만 바꿔도 아홉 개 중 하나의 인상이 달라집니다.

항목 값 변경 느낌
01 기본 격자 SURVIVE_MIN 2 → 1 생존 하한 값을 2 에서 1 로 낮추면 이웃이 하나만 살아있어도 죽지 않아, 기본형보다 칸이 훨씬 오래 남고 격자가 성기게 흩어지는 대신 빽빽하게 굳는 쪽으로 갈립니다.
04 나이 잔상 TRAIL_DECAY 1 → 2 감쇠 값을 1 에서 2 로 올리면 죽은 칸의 나이 값이 세대마다 두 배로 줄어, 잔상이 기본형의 절반 정도 길이로 짧게 옅어지고 사라집니다.
08 와이어월드 HEAD_NEIGHBORS_MAX 2 → 1 허용 상한 값을 2 에서 1 로 좁히면 이웃 신호머리가 정확히 하나일 때만 전선이 신호머리로 바뀌어, 두 신호가 만나는 분기점에서는 조건을 못 채워 신호가 기본형보다 더 자주 끊깁니다.

셀룰러 오토마타 아홉 개의 HTML·SCSS·JS 원본은 아래 카드에서 한 번에 받을 수 있습니다.

생명게임 시뮬레이터를 실제로 쓰기 전에 자주 묻는 것

콘웨이의 생명게임 규칙 말고 다른 규칙표도 넣을 수 있나요?

네, RULESETS 배열에 born·survive 배열을 가진 객체를 추가하면 06 규칙 실험실과 09 히어로 장면 양쪽에서 그대로 씁니다. born·survive 안 숫자는 이웃 수(0~8, 07 육각형은 0~6) 범위를 벗어나지 않게만 넣으면 됩니다.

격자 크기(COLS·ROWS)를 키우면 프레임이 떨어지나요?

대부분 CELL=10(48×30칸) 기준이라 여유가 있지만, 08 와이어월드처럼 매 프레임 neighborHeadCount 로 이웃 8칸을 다시 세는 항목부터 칸 수를 늘리면 계산량이 칸 수만큼 곱해집니다. CELL 값을 줄이기 전에 코드 위쪽 W·H·CELL 상수만 바꿔보고 먼저 확인하는 걸 권합니다.

아홉 개 항목의 색이나 캔버스 크기를 바꿀 수 있나요?

네, 색 상수와 W·H 값은 전부 파일 위쪽에 모여 있어 값만 바꾸면 됩니다. 다만 03 글라이더 건은 CELL=6(80×50칸)으로 다른 항목보다 격자가 촘촘해 GUN_ROWS 행 값도 캔버스 높이에 맞춰 같이 조정해야 발사틀이 화면 밖으로 밀려나지 않습니다.

압축 비밀번호를 입력하세요

비밀번호는 이 글 본문 안에 있습니다. 읽다 보면 나옵니다.