ライフゲーム #28

gen_mesh.gが生成するグラフには端がある。そのため、前回のような現象も起きる。
とはいえ無限の広がりをもったグラフは難しいので、
グラフの上端と下端、右端と左端のノードを繋いでトーラス面にするプログラムを作ってみる。

gen_torus.g
BEGIN {
  if (ARGC != 1) {
    printf(2, 'usage: gvpr -f gen_torus.g -a width,height [-o outfile]\n');
    exit(0);
  }

  int w = xOf(ARGV[0]), h = yOf(ARGV[0]);
  if (w < 1 || h < 1) {
    printf(2, 'error: width and height must be positive integer: %d,%d\n', w, h);
    exit(0);
  }

  node_t gen_node(graph_t g, int x, int y) {
    return node(g, sprintf('%d,%d', x, y));
  }

  void gen_edge(graph_t g, node_t n, int x, int y) {
    edge_sg(g, n, gen_node(g, x, y), '');
  }

  graph_t g = graph('', 'U');
  int x, y;
  for (y = 0; y < h; y++) {
    int yp = (y + 1) % h;
    for (x = 0; x < w; x++) {
      int xp = (x + 1) % w;
      node_t n = gen_node(g, x, y);
      gen_edge(g, n, xp, y == 0 ? h - 1 : y - 1);
      gen_edge(g, n, xp, y);
      gen_edge(g, n, xp, yp);
      gen_edge(g, n, x, yp);
    }
  }
  write(g);
}

幅や高さを法とする剰余で表される座標系について隣接するノード全てにエッジを張ればいいだけなので、
ある意味、gen_mesh.gよりもシンプルに書ける。
ただ、この書き方では問題があって、全てのノードの次数を強制的に8にするため、
幅や高さが2以下の場合は、同じノード間に2本以上のエッジが張られてしまう。
例えば、

gvpr -f gen_torus.g -a 2,2 | neato -T png -o 2x2.png


のように。
用途上、幅や高さをそれほど小さくすることはないと思うので、
問題点は覚えておきつつとりあえずこのままにしておこう。