ラングトンのアリ

提供:kuhalaboWiki
(版間での差分)
移動: 案内, 検索
(人工生命(ALife))
(概要)
2行: 2行:
 
[http://ja.wikipedia.org/wiki/%E3%83%A9%E3%83%B3%E3%82%B0%E3%83%88%E3%83%B3%E3%81%AE%E3%82%A2%E3%83%AA ラングトンのアリwikipedia] /  
 
[http://ja.wikipedia.org/wiki/%E3%83%A9%E3%83%B3%E3%82%B0%E3%83%88%E3%83%B3%E3%81%AE%E3%82%A2%E3%83%AA ラングトンのアリwikipedia] /  
  
平面が格子状に構成され、各マスが白または黒で塗られる。
+
*平面が格子状に構成され、各マスが白または黒で塗られる。
アリは各ステップで上下左右のいずれかのマスに移動することができる。アリは以下の規則に従って移動する。
+
*アリは各ステップで上下左右のいずれかのマスに移動することができる。アリは以下の規則に従って移動する。
 
+
 
# 白いマスにアリがいた場合、90°右に方向転換し、そのマスの色を反転させ、1マス前進する。
 
# 白いマスにアリがいた場合、90°右に方向転換し、そのマスの色を反転させ、1マス前進する。
 
# 黒いマスにアリがいた場合、90°左に方向転換し、そのマスの色を反転させ、1マス前進する。
 
# 黒いマスにアリがいた場合、90°左に方向転換し、そのマスの色を反転させ、1マス前進する。

2021年10月22日 (金) 00:42時点における版

目次

概要

ラングトンのアリwikipedia /

  • 平面が格子状に構成され、各マスが白または黒で塗られる。
  • アリは各ステップで上下左右のいずれかのマスに移動することができる。アリは以下の規則に従って移動する。
  1. 白いマスにアリがいた場合、90°右に方向転換し、そのマスの色を反転させ、1マス前進する。
  2. 黒いマスにアリがいた場合、90°左に方向転換し、そのマスの色を反転させ、1マス前進する。

Langton ant01 11.png

この単純な規則で驚くほど複雑な動作をする。

ラングトンのループ /

Processingソース例

参考 ラングトンの蟻 Processing / tado Langton's ant /

  • boolean型の変数の値は、truefalseの2値
    • この場合は、cellsの色が、黒(true)か白(false)かの2値
    •  ! 演算子は、NOT(否定)で、!(true)falseのことで !(false)trueになる。
  • 輪郭の色の指定はstroke()、塗りつぶしの色の指定は fill()
  • アリの座標は、PVector型のantで表す。
  • アリの進行方向は、ant_directionで表す。0(上),1(右),2(下),3(左)の4方向。
    • turn rightは現在の方向に1足した値の4で割った余り。
      • (ant_direction + 1) % 4; 例: 2(下)のとき、turn rightで2+1=3(左)
    • turn leftは現在の方向に3足した値の4で割った余り。
      • (ant_direction + 3) % 4; 例: 2(下)のとき、turn leftで(2+3)%4=1(右)
初期状態 initialize_cells()
0 すべて 白 :しばらく彷徨った後、行進する。
1 すべて 黒:しばらく彷徨った後、行進する。
2 中央に黒い長方形 :長方形の周囲に城壁を築く。その後、行進する。
3 ランダム :
int CELL_NUM = 100;
int CELL_SIZE = 5;

boolean[][] cells = new boolean[CELL_NUM][CELL_NUM];

PVector ant;
int ant_direction; // 0=up, 1=right, 2=down, 3=left
 
void settings() {
 size(CELL_NUM * CELL_SIZE, CELL_NUM * CELL_SIZE);
}
 
void setup(){
  // initialize cells, 0: all white, 1: all black, 2: put black rectangle, 3: random
  initialize_cells(0);
  
  // initialize ant position
  ant = new PVector(int(CELL_NUM / 2),int(CELL_NUM / 2));
  ant_direction = 0;
}

void draw(){
  // clear screen
  fill(255);
  rect(0, 0, width, height);
  
   // draw cells
   noStroke();
   fill(30);
   for(int w = 0; w < CELL_NUM; w++){
     for(int h = 0; h < CELL_NUM; h++){
       if(cells[w][h] == true){
         rect(w * CELL_SIZE, h * CELL_SIZE, CELL_SIZE, CELL_SIZE);
       }
     }
   }
  
  // draw lines
  stroke(128);
  strokeWeight(1);
  for(int i = 0; i < CELL_NUM; i++){
    line(i * CELL_SIZE, 0, i * CELL_SIZE, height);
    line(0, i * CELL_SIZE, width, i * CELL_SIZE);
  }
   
   // draw ant
   fill(255, 0, 0);
   rect(ant.x * CELL_SIZE, ant.y * CELL_SIZE, CELL_SIZE, CELL_SIZE);
   
   //act ant
   act_ant();
}

void act_ant(){
  if(cells[(int)ant.x][(int)ant.y] == true){
    ant_direction = (ant_direction + 3) % 4; // turn left
  }else {
    ant_direction = (ant_direction + 1) % 4; // turn right
  }
  cells[(int)ant.x][(int)ant.y] = !cells[(int)ant.x][(int)ant.y];
  forward_ant();
}

void forward_ant(){
  switch(ant_direction){
    case 0:
      ant.y = (ant.y - 1 + CELL_NUM) % CELL_NUM;
      break;
    case 1:
      ant.x = (ant.x + 1) % CELL_NUM;
      break;
    case 2:
      ant.y = (ant.y + 1) % CELL_NUM;
      break;
    case 3:
      ant.x = (ant.x - 1 + CELL_NUM) % CELL_NUM;
      break;
  }
}

void initialize_cells(int method){
  switch(method){
    case 0: // all white
      for(int w = 0; w < CELL_NUM; w++){
        for(int h = 0; h < CELL_NUM; h++){
          cells[w][h] = false;
        }
      }
      break;
    case 1: // all black
      for(int w = 0; w < CELL_NUM; w++){
        for(int h = 0; h < CELL_NUM; h++){
          cells[w][h] = true;
        }
      }
      break;
    case 2: // put black rectangle 
      for(int w = 0; w < CELL_NUM; w++){
        for(int h = 0; h < CELL_NUM; h++){
          cells[w][h] = false;
        }
      }
      int rect_x = 40;
      int rect_y = 20;
      for(int w = (CELL_NUM / 2) - int(rect_x / 2); w < (CELL_NUM / 2) + int(rect_x / 2); w++){
        for(int h = (CELL_NUM / 2) - int(rect_y / 2); h < (CELL_NUM / 2) + int(rect_y / 2); h++){
          cells[w][h] = true;
        }        
      }
      break;
    case 3: // random
      for(int w = 0; w < CELL_NUM; w++){
        for(int h = 0; h < CELL_NUM; h++){
          if(random(10) > 5){
            cells[w][h] = true;
          }else{
            cells[w][h] = false;
          }
        }
      }
      break;
  }
}

ラングトンのアリの拡張

多数の色を使うように拡張する。色の変化は、循環となり、アリの動きは各色ごとに右か左に向きを変えて1マス進むことになる。これを色の順に L(左)と R(右)を並べて表す。

以下のソース例
  • mod = 4で、4の剰余系(0,1,2,3)で色を表す
  • 色はHSB系で表す。H:色相、S:彩度、B:明度
    • この例では、colorMode(HSB, mod, 100, 100)として、色相(mod=)4段階、彩度100段階、明度100段階で表す。
    • 参考:色彩
  • 各色(0123)による進路「LRLR」の時、彷徨った後、行進する(通常のラングトンのアリ)。
  • 各色(0123)による進路「RLLR」の時、正方形を描きながら彷徨う。
    • 以下のソース例は「RLLR」としている。
int CELL_NUM = 100;
int CELL_SIZE = 5;

int[][] cells = new int[CELL_NUM][CELL_NUM];
int mod = 4;
PVector ant;
int ant_direction; // 0=up, 1=right, 2=down, 3=left
 
void settings() {
 size(CELL_NUM * CELL_SIZE, CELL_NUM * CELL_SIZE);
}
 
void setup(){
  
  // initialize cells, 0: all white, 1: all black, 2: put rectangle, 3:random
   colorMode(HSB, mod, 100, 100);
   initialize_cells(0);
  
  // initialize ant position
  ant = new PVector(int(CELL_NUM / 2),int(CELL_NUM / 2));
  ant_direction = 0;
}

void draw(){
  // clear screen
  fill(0,0,95);
  rect(0, 0, width, height);
  
   // draw cells
   noStroke();
   for(int w = 0; w < CELL_NUM; w++){
     for(int h = 0; h < CELL_NUM; h++){
       if(cells[w][h] > 0){
         fill(cells[w][h], 75, 75);  // セルの色
         rect(w * CELL_SIZE, h * CELL_SIZE, CELL_SIZE, CELL_SIZE);
       }
     }
   }
  
  // draw lines
  stroke(0,0,90);
  strokeWeight(1);
  for(int i = 0; i < CELL_NUM; i++){
    line(i * CELL_SIZE, 0, i * CELL_SIZE, height);
    line(0, i * CELL_SIZE, width, i * CELL_SIZE);
  }
   
   // draw ant
   fill(0, 100, 100);
   rect(ant.x * CELL_SIZE, ant.y * CELL_SIZE, CELL_SIZE, CELL_SIZE);
   
   //act ant
   act_ant();
}

void act_ant(){
  switch(cells[(int)ant.x][(int)ant.y]){
// RLLR
    case 0:
    ant_direction = (ant_direction + 1) % 4; // turn right
      break;
    case 1:
    ant_direction = (ant_direction + 3) % 4; // turn left
      break;
    case 2:
    ant_direction = (ant_direction + 3) % 4; // turn left
      break;
    case 3:
    ant_direction = (ant_direction + 1) % 4; // turn right
      break;
  }
  cells[(int)ant.x][(int)ant.y] = ( cells[(int)ant.x][(int)ant.y] + 1 ) % mod;
  forward_ant();
}

void forward_ant(){
  switch(ant_direction){
    case 0:
      ant.y = (ant.y - 1 + CELL_NUM) % CELL_NUM;
      break;
    case 1:
      ant.x = (ant.x + 1) % CELL_NUM;
      break;
    case 2:
      ant.y = (ant.y + 1) % CELL_NUM;
      break;
    case 3:
      ant.x = (ant.x - 1 + CELL_NUM) % CELL_NUM;
      break;
  }
}

void initialize_cells(int method){
  switch(method){
    case 0: // all white
      for(int w = 0; w < CELL_NUM; w++){
        for(int h = 0; h < CELL_NUM; h++){
          cells[w][h] = 0;
        }
      }
      break;
      
    case 1: // all black
      for(int w = 0; w < CELL_NUM; w++){
        for(int h = 0; h < CELL_NUM; h++){
          cells[w][h] = mod/2;
        }
      }
      break;
    
    case 2: // put black rectangle 
      for(int w = 0; w < CELL_NUM; w++){
        for(int h = 0; h < CELL_NUM; h++){
          cells[w][h] = 0;
        }
      }
      int rect_x = 40;
      int rect_y = 20;
      for(int w = (CELL_NUM / 2) - int(rect_x / 2); w < (CELL_NUM / 2) + int(rect_x / 2); w++){
        for(int h = (CELL_NUM / 2) - int(rect_y / 2); h < (CELL_NUM / 2) + int(rect_y / 2); h++){
          cells[w][h] = mod/2;
        }        
      }
      break;
            
    case 3: // random
      for(int w = 0; w < CELL_NUM; w++){
        for(int h = 0; h < CELL_NUM; h++){
            cells[w][h] = (int)random(mod);
        }
      }
      break;

  }
}


人工生命(ALife)

セルオートマトン

レイノルズのボイド

反応拡散系

フラクタル

参考

スケーラブルアート論

個人用ツール
名前空間

変種
操作
案内
ツールボックス