ラングトンのアリ

ラングトンのアリの描画 どう書く?org にインスパイヤされて、ラングトンのアリの軌跡を表示するプログラムを作ります。 ラングトンのアリ - Wikipedia を見れば分かりますが、以下のようなものです。(以下、Wikipedia からの引用)

* 黒いマスにアリがいた場合、90°右に方向転換し、そのマスの色を反転させ、1マス前進する。
* 白いマスにアリがいた場合、90°左に方向転換し、そのマスの色を反転させ、1マス前進する。

まとめて関数化すればもっとスマートになると思いますが、とりあえず作成してみたレベルのものを載せておきます。

#! /usr/local/bin/gawk -f
# langtons_ant.awk
# ラングトンのアリ
# usage: gawk -f langtons_ant.awk

BEGIN {
    srand();

    # 端末の高さと幅を取得する
    get_terminal_cmd = "stty -a";
    while (get_terminal_cmd | getline > 0) {
        if ($4 == "rows") {
            rows = $5;
            sub(/;/, "", rows);
        }
        if ($6 == "columns") {
            cols = $7;
            sub(/;/, "", cols);
        }
    }
    close(get_terminal_cmd);
    cols--;

    # 配列の初期化 (全て白)
    for (i = 1; i <= cols; i++) {
        for (j = 1; j <= rows; j++) {
            arr[i, j] = ".";
        }
    }

    # 中心に現在地点を配置する
    current_x = int(cols / 2);
    current_y = int(rows / 2);

    for (;;) {
        count++;
        if (count == 1) {
            post_x = current_x - 1;
            post_y = current_y;
        }

        if (arr[current_x, current_y] == ".") {
            if (post_x == current_x - 1) {
                new_x = current_x; new_y = current_y - 1;
            }
            if (post_x == current_x + 1) {
                new_x = current_x; new_y = current_y + 1;
            }
            if (post_y == current_y - 1) {
                new_x = current_x + 1; new_y = current_y;
            }
            if (post_y == current_y + 1) {
                new_x = current_x - 1; new_y = current_y;
            }
            arr[current_x, current_y] = "#";
            post_x = current_x;
            post_y = current_y;
            current_x = new_x;
            current_y = new_y;
        } else {
            if (post_x == current_x - 1) {
                new_x = current_x; new_y = current_y + 1;
            }
            if (post_x == current_x + 1) {
                new_x = current_x; new_y = current_y - 1;
            }
            if (post_y == current_y - 1) {
                new_x = current_x - 1; new_y = current_y;
            }
            if (post_y == current_y + 1) {
                new_x = current_x + 1; new_y = current_y;
            }
            arr[current_x, current_y] = ".";
            post_x = current_x;
            post_y = current_y;
            current_x = new_x;
            current_y = new_y;
        }

        # 50 回に 1 回表示する
        if (count % 50 == 0) {
            plot(arr, cols + 1, rows - 1);
            system("sleep 0.1");
        }

    }
}

# 指定された位置で表示する
function plot(arr, x_size, y_size,    i, j, k, len, str) {

    for (j = 1; j <= y_size; j++) {

        for (i = 1; i <= x_size; i++) {

            if (arr[i, j] == "") {
                arr[i, j] == ".";
            } else {
                len = length(arr[i, j]);
                str = arr[i, j];

                for (k = 1; k <= len; k++) {
                    arr[i + k - 1, j] = substr(str, k, 1);
                }
            }
            line = sprintf("%s%s", line, arr[i, j]);
        }

        print line;
        line = "";
    }
}

plot() 関数は以前AWK Users JP :: コンソールアナログ時計で用いたものを再利用しています。

実行してみます。 初期値に依存しますが、図形がどんどん成長して以下のようになっていきます。

...............................................................................
...............................................................................
...............................................................................
...............................................................................
..................................##.......#...................................
.................................##......#.#...................................
................................#.##..###.##...................................
................................#..#.#.#.####..................................
.................................#.#.#.#..#.#..................................
...................................#.....#.....................................
......................................###......................................
....................................###..#.....................................
................................#.#.#..#.#.#...................................
................................###....#.#..#..................................
.................................#...##..##.#..................................
..................................##......##...................................
.........................................##....................................
...............................................................................
...............................................................................
...............................................................................
...............................................................................

awk 単独だと表示能力が乏しいので、他のツールと合わせて表示させたいものです。

tag_gawk.pngtag_gawk.png