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 - OCaml

F# 1.9.6.16 で作成しました。
初期状態の背景色を白黒選択可能にしました。
アリの初期状態の向きはランダムにしています。
 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
open System
open System.Windows.Forms
open System.Drawing

let size = 300
let (white, black) = (-1, 1)
let dirTable = [|(1, 0); (0, 1); (-1, 0); (0, -1)|]
let dirTextTable = [|"右"; "下"; "左"; "上"|]

type Langton'sAntForm() as this =
    inherit Form()
    [<DefaultValue>]
    val mutable ant : int -> int[,] -> Async<unit>
    let bitmap = new Bitmap(size, size)
    let picture = new PictureBox(Image = bitmap, Size = new Size(size, size), Location = new Point(0, 30))
    let button = new Button(Size = new Size(50, 30), Location = new Point(0, 0), Text = "Start")
    let checkbox = new CheckBox(Size = new Size(70, 30), Location = new Point(60, 0), Text = "黒背景")
    let labelDir = new Label(Size = new Size(80, 30), Location = new Point(140, 0), TextAlign = ContentAlignment.MiddleLeft)
    let labelStep = new Label(Size = new Size(60, 30), Location = new Point(230, 0), TextAlign = ContentAlignment.MiddleLeft)
    do this.Controls.AddRange([|(picture :> Control); (button :> Control); (checkbox :> Control); (labelDir :> Control); (labelStep :> Control)|])
    do this.Text <- "ラングトンのアリ"
    do this.ClientSize <- new Size(size, size + 30)
    do this.FormBorderStyle <- FormBorderStyle.Fixed3D
    do this.MaximizeBox <- false
    do button.Click.Add(fun _ ->
        let dir = (new Random()).Next(4)
        labelDir.Text <- "初期方向:" ^ dirTextTable.[dir]
        let (place, color) = if checkbox.Checked then (black, Color.Black) else (white, Color.White)
        [for x in 0..(size - 1) -> [for y in 0..(size - 1) -> (x, y)]] |> List.concat
        |> List.iter(fun (x, y) -> bitmap.SetPixel(x, y, color))
        Array2D.create size size place |> this.Ant dir |> Async.Start
        button.Enabled <- false)
    
    member this.Ant with get() = this.ant and set(value) = this.ant <- value
    member this.Print (x, y) place step =
        try
            if this.InvokeRequired then
                this.Invoke(new MethodInvoker(fun () ->
                    bitmap.SetPixel(x, y, if place = white then Color.White else Color.Black)
                    labelStep.Text <- string step
                    this.Refresh()))
                |> ignore
        with
        | :? ObjectDisposedException -> ()

let rec loop step (x, y) dir (field : int[,]) (form : Langton'sAntForm) =
    let rotate dir place = (dir + place + 4) % 4
    let turnover = ( * ) -1
    let move (x, y) dir =
        let (dx, dy) = dirTable.[dir] in (x + dx, y + dy)
    let (|InField|OutOfField|) (x, y) =
        if 0 <= x && x < size && 0 <= y && y < size then InField else OutOfField

    match (x, y) with
    | OutOfField -> ()
    | InField ->
        let newDir = rotate dir field.[x, y]
        field.[x, y] <- turnover field.[x, y]
        form.Print (x, y) field.[x, y] step
        loop (step + 1) (move (x, y) newDir) newDir field form

[<STAThread()>]
do
    use form = new Langton'sAntForm()
    form.Ant <- fun dir field -> async { loop 1 (size / 2, size / 2) dir field form }
    Application.EnableVisualStyles()
    Application.Run(form) |> ignore

Index

Feed

Other

Link

Pathtraq

loading...