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

Ruby でシンプルに書いてみました。

入力された数字の分だけどんどん世代を進めます。qが入力されたら終わりです。

  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
134
135
136
137
#
#  World.rb
#  iLangAnt
#
#  Created by 石井 大海 on 09/07/17.
#  Copyright (c) 2009 __MyCompanyName__. All rights reserved.
#

class Ant
  attr_reader :world, :x, :y, :generation

  def pos()
    return [x,y]
  end

  def initialize(world=World.new, pos_x=40, pos_y=60)
    @world = world
    @x = pos_x
    @y = pos_y
    @direction = [0, -1]
    @generation = 0
  end

  def position()
    @world.at(@x, @y)
  end

  def step()
    @x += @direction[0]
    @y += @direction[1]
    return nil unless position()
    position.toggle()
    if @world.black?(@x,@y)
      @direction = [-@direction[1], @direction[0]]
    else
      @direction = [@direction[1], -@direction[0]]
    end
    @generation += 1
  end

end

class World
  attr_reader :height, :width

  class <<self
    def define_block_delegate(mtd)
      define_method(mtd) {|x,y|
        at(x,y).__send__(mtd)
      }
    end
  end

  def initialize(height=100, width=100, wrap=true)
    @world = Array.new(height){ Array.new(width){ Block.new } }
    @height, @width = height, width
    @wrap = wrap
  end

  def at(x, y)
    unless (0...@height).include?(y) && (0...@width).include?(x)
      if @wrap
        x, y = x % width, y % height
      else
        return nil
      end
    end
    @world[y][x]
  end

  define_block_delegate :white?
  define_block_delegate :black?
  define_block_delegate :color

  def inspect()
    @world.map{|r| r.map(&:inspect).join("")}.join("\n")
  end

end

class Block
  attr_reader :state
  alias color state

  WHITE = true
  BLACK = false

  def initialize(state=WHITE)
    @state = state
  end

  def toggle
    @state = !@state
  end

  def set_white
    @state = WHITE
  end

  def set_black
    @state = BLACK
  end

  def black?
    @state
  end

  def white?
    !@state
  end

  def inspect()
    case @state
    when WHITE
      " □ "
    when BLACK
      " ■ "
    end
  end

end

if $0 == __FILE__
  w, h ,= ARGV
  w ||= h ||= 20
  wd = World.new(w, h)
  ant = Ant.new(wd, w*6/10, h*4/10)
  while (print"> ";gets)
    break if $_ =~ /^q/i
    count = 1 unless (count = $_.to_i) > 0
    count.times {
      ant.step
      p ant.generation
      p wd
    }
  end
end

 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
def ant(world_size, x_pos = world_size / 2, y_pos = world_size / 2)
  world = Array.new
  generation = 0
  direc = {}; direc[:x] = 0; direc[:y] = 1
  world_size.times{world <<  [true] * world_size}
  while true
    system "clear"
    p generation += 1
    world[x_pos][y_pos] = !world[x_pos][y_pos]
    world.each{|i|
      i.each{|k| printf("%s ",k ? : : :)}
      p ''
    }
    sleep 0.1

    if world[x_pos][y_pos] then
      direc[:x], direc[:y] = direc[:y], -direc[:x]
    else
      direc[:x], direc[:y] = -direc[:y], direc[:x]
    end
    
    x_pos = (x_pos + direc[:x]) % world_size
    y_pos = (y_pos + direc[:y]) % world_size
    
  end
end

world_size = 20
ant(world_size)

Index

Feed

Other

Link

Pathtraq

loading...