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

  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
115
116
117
118
119
120
121
122
123
124
125
126
127
#!/usr/bin/python
# -*- coding: utf-8 -*-
# http://ja.doukaku.org/276/

import random
import sys

EAST = 0
NORTH = 90
WEST = 180
SOUTH = 270

BLACK = (0, 0, 0)
RED = (1, 0, 0)
GREEN = (0, 1, 0)
BLUE = (0, 0, 1)


class Grid(object):

    def __init__(self, width=40, height=20):
        self._width = width
        self._height = height
        self._color = {}

    def width(self):
        return self._width

    def height(self):
        return self._height

    def color(self, position, color=None):
        if color is not None:
            self._color[tuple(position)] = color

        return self._color.get(tuple(position), BLACK)

    def view(self):
        for y in range(0, self.height()):
            for x in range(0, self.width()):
                sys.stdout.write({
                    BLACK: ' ',
                    RED: '*',
                    GREEN: '+',
                    BLUE: '@',
                    }[self.color((x, y))])
            sys.stdout.write('\n')


class Ant(object):

    def __init__(
        self,
        grid,
        color=RED,
        position=[10, 10],
        direction=EAST,
        ):

        self._grid = grid
        self._position = position
        self._direction = direction
        self._color = color

    def position(self, position=None):
        if position is not None:
            self._position = list(position)

        return self._position

    def color(self, color=None):
        if color is not None:
            self._color = color

        return self._color

    def left(self):
        self._direction = (self._direction + 90) % 360

    def right(self):
        self._direction = (self._direction - 90) % 360

    def forward(self):
        if self._direction == NORTH:
            self._position[1] -= 1
        elif self._direction == SOUTH:
            self._position[1] += 1
        elif self._direction == EAST:
            self._position[0] -= 1
        elif self._direction == WEST:
            self._position[0] += 1

        self._position[0] %= self._grid.width()
        self._position[1] %= self._grid.height()

    def step(self):
        if self._color == self._grid.color(self._position):
            self._grid.color(self._position, BLACK)
            self.left()
        else:
            self._grid.color(self._position, self._color)
            self.right()

        self.forward()


if __name__ == '__main__':

    width = int(sys.argv[1])
    height = int(sys.argv[2])
    num = int(sys.argv[3])
    iteration = int(sys.argv[4])

    grid = Grid(width=width, height=height)
    ants = []
    for i in range(0, num):
        c = (RED, GREEN, BLUE)[i % 3]
        x = int(random.random() * width)
        y = int(random.random() * height)
        ants.append(Ant(grid, color=c, position=[x, y]))

    for i in range(0, iteration):
        for ant in ants:
            ant.step()
        if i % (iteration / 10) == 0:
            sys.stdout.write('step: %d\n' % i)
            grid.view()

Python + Tkinter

  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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#!/usr/bin/python
# -*- coding: utf-8 -*-
# http://ja.doukaku.org/276/

import random
import sys
import Tkinter as Tk

DOT_SIZE = 5


class Ant(object):

    def __init__(self, grid, x, y, direction, color):
        self._grid = grid
        self.x = x
        self.y = y
        self.direction = direction
        self.color = color

    def left(self):
        self.direction = (self.direction + 90) % 360

    def right(self):
        self.direction = (self.direction - 90) % 360

    def forward(self):
        diff = {  # 0:EAST, 90:NORTH 180:SOUTH 270:WEST
            0: (1, 0),
            90: (0, -1),
            180: (-1, 0),
            270: (0, 1),
            }[self.direction]
        self.x = (self.x + diff[0]) % self._grid.width
        self.y = (self.y + diff[1]) % self._grid.height

    def is_my_color(self):
        return self.color == self._grid.get_color(self.x, self.y)

    def black(self):
        self._grid.delete_color(self.x, self.y)

    def my_color(self):
        self._grid.update_color(self.x, self.y, self.color)

    def step(self):
        if self.is_my_color():
            self.black()
            self.left()
        else:
            self.my_color()
            self.right()

        self.forward()


class Grid(Tk.Canvas):

    def __init__(self, parent, width=40, height=20):
        self.width = width
        self.height = height
        self._color = {}

        xw = DOT_SIZE * self.width
        xh = DOT_SIZE * self.height
        Tk.Canvas.__init__(self, parent, background='black', width=xw,
                           height=xh)

    def color(self, x, y):
        return self._color.get((x, y), {'id': None, 'color': 'black'})

    def get_color(self, x, y):
        return self.color(x, y)['color']

    def delete_color(self, x, y):
        old = self.color(x, y)
        if old['id'] is not None:
            self.delete(old['id'])
            del self._color[(x, y)]

    def update_color(self, x, y, color):
        old = self.color(x, y)
        if old['id'] is None:
            xx0 = x * DOT_SIZE
            xy0 = y * DOT_SIZE
            xx1 = xx0 + DOT_SIZE
            xy1 = xy0 + DOT_SIZE
            id = self.create_rectangle(xx0, xy0, xx1, xy1, fill=color,
                                       outline=color)
            self._color[(x, y)] = {'id': id, 'color': color}
        else:
            self.itemconfigure(old['id'], fill=color, outline=color)


class Frame(Tk.Frame):

    def __init__(self, width, heigth, num_ant, master=None):
        Tk.Frame.__init__(self, master)
        self.master.title('Rangton Ant')

        self._grid = Grid(self, width=width, height=height)
        self._grid.pack()

        def _rand_int(n):
            return int(random.random() * n)

        def _make_ant(i):
            c = ('red', 'yellow', 'green', 'cyan', 'blue', 'cyan',
                 'magenta', 'white')[i % 7]
            d = (0, 90, 180, 270)[_rand_int(4)]
            x = _rand_int(width)
            y = _rand_int(height)
            return Ant(self._grid, x, y, d, c)

        self._ants = map(_make_ant, range(num_ant))

        self.move()

    def move(self):
        for ant in self._ants:
            ant.step()
        self.after(1, self.move)


if __name__ == '__main__':

    width = int(sys.argv[1])
    height = int(sys.argv[2])
    num_ant = int(sys.argv[3])

    f = Frame(width, height, num_ant)
    f.pack()
    f.mainloop()

Index

Feed

Other

Link

Pathtraq

loading...