地図/創発/グリッド

隣の数え方

(N + i) % N で端を反対側へ巻くと、マス目の上下と左右がつながって、紙が筒になる。筒の口どうしもつながってドーナツ状(トーラス)になる。端のマスを特別扱いせずに済み、模様が画面の縁で途切れない。

隣の集め方には二通りある。上下左右の4マスだけ足す von と、斜めも入れて8マス足す moore。8マスのほうは二重ループで自分 (0, 0) だけ飛ばして、まわりの8マスを足す。どちらも idx でトーラスの巻きを通すので、端のマスでも8方向きっちり拾える。

// 4近傍: 上下左右だけ足す
const von = (g, x, y) => idx(g, x - 1, y) + idx(g, x + 1, y) + idx(g, x, y - 1) + idx(g, x, y + 1)

// 8近傍: 斜めも足す。自分(0,0)だけ飛ばす
const moore = (g, x, y) => {
  let sum = 0
  for (let dy = -1; dy <= 1; dy++) {
    for (let dx = -1; dx <= 1; dx++) {
      if (dx === 0 && dy === 0) continue
      sum += idx(g, x + dx, y + dy)
    }
  }
  return sum
}

中央の1マスだけ立てて、「立っている隣がひとつでもあれば自分も立つ」というルールで広げる。左は4近傍、右は8近傍。同じ初期値・同じルールで、隣の数え方だけが違う。

4近傍は中央から菱形に、8近傍は四角に育つ。grow に渡す数え方の関数を von から moore に替えただけで、波面の形が変わる。

上下左右の4マスを見る数え方が von Neumann 近傍、斜めも入れて8マス見る数え方が Moore 近傍。名前はそれぞれ John von Neumann と Edward Moore に由来する。von Neumann 近傍は1ステップで届く範囲がマンハッタン距離1の集合なので菱形に、Moore 近傍はチェビシェフ距離1の集合なので正方形に広がる。何を隣と認めるかが、そのまま拡散の波面の対称性を決める。

「自分と近傍の数から次の状態を決める関数」を差し替えると、同じ土台のまま別のものが立ち上がる。