ライフゲーム #8

Blinkerばかりで飽きたので別のパターンにしたい。
が、その前に、第0世代のDOTファイルのエッジ群をいちいち手で構成するのはさすがに面倒なので、
以前言及したように、メッシュサイズを与えるとエッジ構成を自動生成するプログラムを作成する。
その生成されたDOTに手を入れて、どのノードがalive属性付きかの情報を付加して第0世代のグラフとする。
例によってgvprで新規グラフを作成し、それにエッジ情報を加えて出力する。
文字列の扱いの容易い他のスクリプト言語等で書いた方がたぶん効率がよさそうな気もするが、
以前書いたようにGraphvizだけで閉じているので、これもこれなりの利点だろう。

gen_mesh.g
BEGIN {
  if (ARGC != 2) {
    printf(2, 'usage: gvpr -f gen_mesh.g -a "width height"\n');
    exit(0);
  }

  int w = ARGV[0], h = ARGV[1];
  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('n%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++) {
    for (x = 0; x < w; x++) {
      node_t n = gen_node(g, x, y);
      if (x < w - 1) {
        if (y > 0) gen_edge(g, n, x + 1, y - 1);
        gen_edge(g, n, x + 1, y);
        if (y < h - 1) gen_edge(g, n, x + 1, y + 1);
      }
      if (y > 0) gen_edge(g, n, x, y - 1);
    }
  }
  write(g);
}

メッシュの大きさは幅と高さをgvprの-aオプションで指定する。
処理は各ノードについて自分のx座標よりも大きいx座標のノード、
もしくは、同じx座標で小さいy座標のノードとの間にエッジを張るだけである。

gvpr -f gen_mesh.g -a "4 3" | neato -T png -o 4x3.png


pos属性などもこの時点で付加してもよかったかもしれないが、
属性の付加は後からでもできるわけで、元データは単純さを保つことにした。