challenge ラングトンのアリの描画

ラングトンのアリを描画してください。ラングトンのアリは、以下のような動きをする、セル・オートマトンです。(Wikipediaより引用)
- 黒いマスにアリがいた場合、90°右に方向転換し、そのマスの色を反転させ、1マス前進する。
- 白いマスにアリがいた場合、90°左に方向転換し、そのマスの色を反転させ、1マス前進する。
詳しくはWikipedia等で調べるか、参考ページに拙作のデモがありますのでご覧下さい。
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
<head>
       <meta http-equiv="content-type" content="text/html;charset=utf-8">
       <meta http-equiv="content-script-type" content="text/javascript">
       <meta http-equiv="content-style-type" content="text/css">
       <title>ラングトンの蟻</title>
<style type="text/css">
#canvas{
       border: 1px solid #999;
       width: 300px;
       height: 300px;
}
#canvas div{
       width: 3px;
       height: 3px;
       float: left;
}
</style>
<script>
var earth = [];
var WORLD_SIZE = 100;
var lang_ant;

function Ant(){}
Ant.prototype = {
    age : 0,
    ageDisplay : undefined,
    id : undefined,
    speed: 200,
    direction: [0,-1],//向き。x y軸。最初は上に動く
    position: [60,40],//初期位置
    world: [],
    start: function(){
        var self = this;
        this.id = setInterval(function(){self.move()}, 1000/this.speed);
    },
    move: function(){
        this.ageDisplay.innerHTML = ++this.age;
        this.moveNextCell();
        var cell = this.getCellInfo();
        var color = cell.getAndToggleColor();
        this.setNextDirection(color);
    },
    moveNextCell: function(){
        this.position[0] += this.direction[0];
        this.position[1] += this.direction[1];
        if(this.position[0] < 0 || this.position[1] < 0 ||
           this.position[0] >= WORLD_SIZE || this.position[1] >= WORLD_SIZE){
            clearInterval(this.id);
            this.die();
        }
    },
    getCellInfo: function(){
        var idx = this.position[0] + this.position[1] * WORLD_SIZE;
        return this.world[idx];
    },
    setNextDirection: function(bool){//colorがfalse(白)なら右へ、true(黒)なら左へ転回
        if(bool){//黒
            var tmp = this.direction[0];
            this.direction[0] = this.direction[1];
            this.direction[1] = -tmp;
        }
        else{//白
            var tmp = this.direction[0];
            this.direction[0] = -this.direction[1];
            this.direction[1] = tmp;
        }
    },
    die: function(){
        alert('Langton\'s ant is dead.');
        throw true;
    }
};

function Cell(elm){
    this.elm = elm;
}
Cell.prototype = {
    elm: undefined,
    color: false, //colorは2値なのでbooleanで表す
    colorList: ['#FFF','#000'],
    getAndToggleColor: function(){
        this.color = !this.color;
        var i = this.color ? 1 : 0;
        this.elm.style.backgroundColor = this.colorList[i];
        return !this.color;
    }
}
window.onload = function(){
    var canvas = document.getElementById('canvas');
    var div = '<div></div>';
    var inner_canvas = "";
    for(var i=0; i< WORLD_SIZE*WORLD_SIZE; i++){
        inner_canvas += div;
    }
    canvas.innerHTML = inner_canvas;
    
    var cells = canvas.childNodes;
    for(var i=0; i<cells.length; i++){//世界の誕生
        earth[i] = new Cell(cells[i]);
    }
    lang_ant = new Ant();//蟻の誕生
    lang_ant.world = earth;//地球に降り立つ
    lang_ant.ageDisplay = document.getElementById('step');
    
    document.getElementById('run').disabled = false;
}
</script>
</head>
<body>
<p><input type="button" value="run" onclick="lang_ant.start();this.disabled=true;" id="run" disabled="disabled"> <span id="step"></span>
 <input type="button" value="stop &amp; refresh" onclick="location.reload();"></p>
<div id="canvas"></div>

Posted feedbacks - なでしこ

画面のサイズや画面端での扱いについて特に規定されていないようなので、何も考えずにサックリと書いてみた。枠まで到達しても死にません。

方向転換に関する論理計算がパッと見で分かりにくいだけで、他は分かりやすいのではないかと。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
!東=0
!南=1
!西=2
!北=3

線スタイルは`透明`
必要な 間、蟻を進めて0.01秒待つ

■ブロック
 ・{整数}W{=5}
 ・{整数}H{=5}
 ・色取得(X,Yの)~
  X*W,Y*Wを点取得
 ・プロット(X,YにCOLを)~
  塗り色はCOL
  X*W,Y*Hから(X+1)*W,(Y+1)*Hへ四角

■蟻 +ブロック
 ・{整数}向き{=2}
 ・{整数}X{=40}
 ・{整数}Y{=40}
 ・進む~
  COLとは整数=X,Yの色取得
  向き=(向き-2*(COL==白色)+5)%4
  X,Yに(COLの反転色)をプロット
  X=X-(向き==西)+(向き==東)
  Y=Y-(向き==南)+(向き==北)

●反転色(COLの)
 白色-COLを戻す

連投失礼。Wikipediaに載っていた拡張版のラングトンの蟻(色反転でなく、複数色循環)も実装してみた。まだ誰もやっていなかったかな?拡張の解釈は多分合っていると思ふ。。。

あたかも要塞のように常に左右に対称に広がっていく様子は割と面白い。(都市発展系のシミュレーションゲームのよう)

# 発展にかなり時間がかかるので、ついでに500ステップ毎に描画を反映させるようにしました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
!ブロック幅 =3
!ブロック高さ=3
!世界幅 =150
!世界高さ=120

!東=0
!南=1
!西=2
!北=3

!色数 =4
!基準色=黒色
!STEPBY=500

ルールは『RLLR』
ルールの色配列は「{基準色},{赤色},{青色},{緑色}」を`,`で区切ったもの

母艦について
 クライアントW=ブロックのW*世界幅
 クライアントH=ブロックのH*世界高
 スタイルは`枠固定`
 基準色で画面クリア

STEPとは整数

線スタイルは`透明`
必要な 間
 蟻を進める。
 もしSTEP%STEPBYが0ならば
  0.01秒待つ
  母艦は「step: {STEP}」
 STEPに1を直接足す

■ルール
 ・{配列}ルール配列
 ・テキスト ←ルール設定 デフォルト
 ・ルール設定(V)~
  Vを文字列分解して反復
   ルール配列[回数-1]=2*(対象==`R`)-1 # Rなら1、それ以外は-1
 ・{非公開}色配列

■ブロック
 ・{非公開}W{=3}
 ・{非公開}H{=3}
 ・色取得(X,Yの)~
  X*W,Y*Wを点取得
 ・プロット(X,YにCOLを)~
  塗り色はCOL
  X*W,Y*Hから(X+1)*W,(Y+1)*Hへ四角

■蟻 +ブロック
 ・{整数}向き{=0}
 ・{整数}X{=75}
 ・{整数}Y{=50}
 ・進む~
  COLとは整数=X,Yの色取得
  COLで向きを方向転換する
  COLを色循環する
  X,YにCOLをプロット
  Xに(向き==東)-(向き==西)を世界幅でMOD加算
  Yに(向き==南)-(向き==北)を世界高でMOD加算

●方向転換する({整数}COLで{参照渡し}DIRを)
 Iとは整数=ルールの色配列でCOLを配列検索
 もしIが(-1)ならばI=0
 DIRに(ルールのルール配列[I])を4でMOD加算する

●色循環する({参照渡し}COLを)
 COLORSとは配列=ルールの色配列
 Iとは整数=COLORSでCOLを配列検索
 COL=COLORS[(I+1)%色数]

# Z/CZ上でAにBを直接足す
●MOD加算({参照渡し}Aに{整数}Bを{整数}Cで)
 A=(A+B+C)%C

Index

Feed

Other

Link

Pathtraq

loading...