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

Perl/Tk でごりごり書いてみました。
  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
use strict;
use warnings;

use Tk;
use Tk::MsgBox;
use utf8;

my $w = shift || 100;
my $h = shift || $w;

my $pxsize  = 4;
my $init_pattern_subs = create_pattern_subs();
my $pattern = shift;
my $pattarn_sub = $pattern && exists $init_pattern_subs->{$pattern}
? $init_pattern_subs->{$pattern} 
: sub { 0 };

my $mw = Tk::MainWindow->new(-title => 'ラングトンの蟻');
my $control_frame = $mw->Frame;
$control_frame->pack(
  -side => 'bottom',
  -anchor => 's',
  -fill => 'x',
);
my $drawing_frame = $mw->Frame;
$drawing_frame->pack(
  -side => 'top',
  -anchor => 'n',
  -fill => 'both',
);
my $canvas = $drawing_frame->Canvas(
  -width => $w * $pxsize, -height => $h * $pxsize,
  -background => 'white',
);
my @field;
for my $x ( 0 .. $w-1 ) {
  for my $y ( 0 .. $h-1 ) {
    $field[$x][$y] = $canvas->createRectangle(
      (map{$_ * $pxsize} $x,$y,$x+1,$y+1),
      -fill => 'white'
    );
  }
}

$canvas->pack(-fill => 'both');
my $start_button = $control_frame->Button(
  -text => 'START',
  -command => \&start_proc,
  -state => 'normal',
);
$start_button->pack(-anchor => 'w', -side => 'left');
my $stop_button = $control_frame->Button(
  -text => 'STOP',
  -command => \&stop_proc,
  -state => 'disabled',
);
$stop_button->pack(-anchor => 'w', -side => 'left', -padx => 20);
my $stat = step_label(0,0,0);
my $stat_label = $control_frame->Label(
  -textvariable => \$stat
);
$stat_label->pack(-anchor => 'w', -side => 'left', -padx => 30);

Tk->MainLoop;

sub create_pattern_subs
{
  +{
    ichimatsu => sub { (($_[0]/2) ^ ($_[1]/2)) & 0x1; },
    lines => sub { ($_[0]/12) & ($_[1]/2) & 0x1; },
    random => sub { !int rand 3 },
  };
}

sub step_label
{
  sprintf '%#8d steps (%#3d, %#3d)', @_;
}

{
  my ($count,$x,$y,$d,$timer);

  sub start_proc
  {
    $stop_button->configure(-state => 'normal');
    $start_button->configure(-state => 'disabled');

    $count = 0;
    $x = int(rand($w/2) + $w/4);
    $y = int(rand($h/2) + $h/4);
    $d = int(rand(4));
    for my $x_ ( 0 .. $w-1 ) {
      for my $y_ ( 0 .. $h-1 ) {
        $canvas->itemconfigure($field[$x_][$y_],
          -fill => $pattarn_sub->($x_,$y_) ? 'black' : 'white');
      }
    }

    $timer = $mw->repeat(10, \&next_step);
  }

  sub stop_proc
  {
    $stop_button->configure(-state => 'disabled');
    $start_button->configure(-state => 'normal');

    $mw->afterCancel($timer);
  }

  sub next_step
  {
    my $bit = $canvas->itemcget($field[$x][$y], '-fill') ne 'white';
    $canvas->itemconfigure($field[$x][$y], -fill => ($bit ? 'white' : 'black'));

    $d = ($bit ? ++$d : --$d) % 4;
    if    ( $d == 0 ) { --$x; }
    elsif ( $d == 1 ) { ++$y; }
    elsif ( $d == 2 ) { ++$x; }
    elsif ( $d == 3 ) { --$y; }

    if ( $x < 0 || $x >= $w || $y < 0 || $y >= $h ) {
      stop_proc;
      my $d = $mw->MsgBox(-title => 'END', -message => 'しゅーりょー', -type => 'ok');
      $d->Show;
      return;
    }

    $stat = step_label( ++$count, $x, $y);
  }

}

Index

Feed

Other

Link

Pathtraq

loading...