ライフゲーム 修正版

修正してみた。

  • 指摘された点の改良
  • 無駄なループの削減
  • 世代を表示
  • 停止判定ロジックの追加
<html>
<head>
<style type="text/css">
* { margin: 0; padding: 0; }
p { padding: 10px; font-size: 200%; }
</style>
<script type="text/javascript">
lifegame = function() {
    var size = 15;      // フィールドサイズ。定数
    var field;          // フィールド
    var age = 0;        // 世代
    var stop = false;   // 停止するかどうか
    
    // フィールドの初期化
    // 初期の生きセルはランダムに生成
    var init = function() {
        field = new Array(size);
        for (var i = 0; i < size; i++) {
            field[i] = new Array(size);
            for (var j = 0; j < size; j++) {
                field[i][j] = (parseInt(Math.random() * 10) % 3 == 0) ? true : false;
            }
        }
    };
    
    // 次世代のフィールドを生成
    var createNextField = function() {
        var nextField = new Array(size);
        for (var i = 0; i < size; i++) {
            nextField[i] = new Array(size);
            for (var j = 0; j < size; j++) {
                var c = getAliveCellCount(i, j)
                nextField[i][j] = birth(i, j, c) || keep(i, j, c);
            }
        }
        return nextField;
    };
    
    // 生きてるセルのカウントアップ
    var getAliveCellCount = function(i, j) {
        var c = 0;
        for (var x = -1; x <= 1; x++) {
            if (i + x < 0 || i + x >= size) continue;
            for (var y = -1; y <= 1; y++) {
                if (j + y < 0 || j + y >= size || (x == 0 && y == 0)) continue;
                if (field[i+x][j+y] == true) c++;
            }
        }
        return c;
    };
    
    // 誕生するか?
    var birth = function(i, j, c) {
        if (field[i][j] == true) return false;
        return (c == 3) ? true : false;
    };
    
    // 維持するか?
    var keep = function(i, j, c) {
        if (field[i][j] == false) return false;
        return (c == 2 || c == 3) ? true : false;
    };
    
    // 停止判定
    // 現世代のフィールドと次世代のフィールドが完全に同一だった場合、停止とみなす
    var isStop = function(nextField) {
        if (field.length != nextField.length) return false;
        for (var i = 0; i < size; i++) {
            if (field[i].length != nextField[i].length) return false;
            for (var j = 0; j < size; j++) {
                if (field[i][j] != nextField[i][j]) return false;
            }
        }
        return true;
    }
    
    // 描画用文字列を作成
    var createDrawBuffer = function() {
        var buf = "";
        for (var i = 0; i < size; i++) {
            for (var j = 0; j < size; j++) {
                buf += field[i][j] ? "■" : "□";
            }
            buf += "<br>";
        }
        if (stop) {
            buf+= "第" + age + "世代にて停止";
        } else {
            age++;
            buf += "第" + age + "世代";
        }
        return buf;
    };
    
    // public methods
    return {
        exec : function() {
            if (typeof(field) == "undefined") {
                init();
            } else {
                var nextField = createNextField();
                if (isStop(nextField)) {
                    stop = true;
                }
                field = nextField;
            }
            document.getElementById("area").innerHTML = createDrawBuffer();
        }
    };
}();

window.onload = function(){setInterval(lifegame.exec, '1000');};
</script>
</head>
<body>
<p id="area"></p>
</body>
</html>