ラングトンのアリ

提供:kuhalaboWiki
(版間での差分)
移動: 案内, 検索
(概要)
 
(1人の利用者による、間の17版が非表示)
1行: 1行:
*アリは以下の規則に従って移動する。
+
== 概要 ==
** 色ありのマス(1)にアリがいた場合、90°右に方向転換し、そのマスの色を反転させ、1マス前進する。
+
[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] /
** 色なしのマス(0)にアリがいた場合、90°左に方向転換し、そのマスの色を反転させ、1マス前進する。
+
  
* ofImageを使って、アリの動いた軌跡を描画している。
+
*平面が格子状に構成され、各マスが白または黒で塗られる。
** ofImageのマニュアル http://www.openframeworks.cc/documentation/graphics/ofImage.html
+
*アリは各ステップで上下左右のいずれかのマスに移動することができる。アリは以下の規則に従って移動する。
** 教科書の3-2-7 「画像ファイルを扱う」(p172)
+
# 白いマスにアリがいた場合、90°右に方向転換し、そのマスの色を反転させ、1マス前進する。
** アリの現在位置の色はアリごとに異なる色を設定
+
# 黒いマスにアリがいた場合、90°左に方向転換し、そのマスの色を反転させ、1マス前進する。
** アリの軌跡の色は1色に設定
+
[[ファイル:Langton ant01 11.png]]
  
;ofApp.h
+
この単純な規則で驚くほど複雑な動作をする。
* ofApp.hの中にAntクラスを記述している。
+
*[https://upload.wikimedia.org/wikipedia/commons/0/09/LangtonsAntAnimated.gif 200ステップまでの動き]
* Antクラスにはプロパティだけで、メソッドがない。
+
<pre>
+
#pragma once
+
  
#include "ofMain.h"
+
[http://ja.wikipedia.org/wiki/%E3%83%A9%E3%83%B3%E3%82%B0%E3%83%88%E3%83%B3%E3%81%AE%E3%83%AB%E3%83%BC%E3%83%97 ラングトンのループ] /
  
class Ant {  // Antクラス
+
== Processingソース例 ==
public:
+
int row; // アリの x座標
+
int col; // アリの y座標
+
ofColor bcolor; // アリの色
+
int dir; // アリの進行方向
+
};
+
  
class ofApp : public ofBaseApp{
+
参考 [http://aa-debdeb.hatenablog.com/entry/2014/12/10/154241 ラングトンの蟻 Processing] / [https://gist.github.com/tado/6603347  tado Langton's ant] /
  
public:
+
* boolean型の変数の値は、'''true'''(真) か '''false'''(偽)の2値
void setup();
+
**この場合は、cellsの色が、黒(true)か白(false)かの2値
void update();
+
** ''' ! ''' 演算子は、NOT(否定)で、'''!(true)'''は'''false'''のことで '''!(false)'''は'''true'''になる。
void draw();
+
* 輪郭の色の指定は'''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(右)
  
void keyPressed(int key);
+
;初期状態 initialize_cells()
void keyReleased(int key);
+
:0 すべて 白 :しばらく彷徨った後、行進する。
void mouseMoved(int x, int y );
+
:1 すべて 黒:しばらく彷徨った後、行進する。
void mouseDragged(int x, int y, int button);
+
:2 中央に黒い長方形 :長方形の周囲に城壁を築く。その後、行進する。
void mousePressed(int x, int y, int button);
+
:3 ランダム :
void mouseReleased(int x, int y, int button);
+
void windowResized(int w, int h);
+
void dragEvent(ofDragInfo dragInfo);
+
void gotMessage(ofMessage msg);
+
  
static const int FIELD_RATE = 4; // マス目の大きさ
 
static const int DRAW_RATE = 10; // 描画を間引く間隔
 
 
static const int WIDTH = 1024 / FIELD_RATE;
 
static const int HEIGHT = 768 / FIELD_RATE;
 
 
int field[WIDTH][HEIGHT]; // アリが動くマス目 色あり 1 色なし 0
 
 
static const int ANTS_NUM = 3; // アリの数
 
Ant ants[ANTS_NUM];
 
 
ofImage myImage;  //マス目(アリの歩いた跡)の描画用
 
unsigned char * pixels;
 
};
 
</pre>
 
 
;ofApp.cpp
 
 
<pre>
 
<pre>
#include "ofApp.h"
+
int CELL_NUM = 100;
 +
int CELL_SIZE = 5;
  
//--------------------------------------------------------------
+
boolean[][] cells = new boolean[CELL_NUM][CELL_NUM];
void ofApp::setup(){
+
ofBackground(0, 0, 0);
+
ofSetFrameRate(30);
+
  
myImage.allocate(WIDTH, HEIGHT, OF_IMAGE_GRAYSCALE); //
+
PVector ant;
pixels = myImage.getPixels();
+
int ant_direction; // 0=up, 1=right, 2=down, 3=left
for (int i = 0; i < WIDTH * HEIGHT; i++) {
+
pixels[i] = 0;
+
void settings() {
}
+
size(CELL_NUM * CELL_SIZE, CELL_NUM * CELL_SIZE);
for (int i = 0; i < WIDTH; i++) {
+
}
for (int j = 0; j < HEIGHT; j++) {
+
field[i][j] = 0;
+
void setup(){
}
+
  // initialize cells, 0: all white, 1: all black, 2: put black rectangle, 3: random
}
+
  initialize_cells(0);
myImage.update();
+
 
 +
  // initialize ant position
 +
  ant = new PVector(int(CELL_NUM / 2),int(CELL_NUM / 2));
 +
  ant_direction = 0;
 +
}
  
for (int i = 0; i < ANTS_NUM; i++) {
+
void draw(){
ants[i].row = int(ofRandom(WIDTH));
+
  // clear screen
ants[i].col = int(ofRandom(HEIGHT));
+
  fill(255);
ants[i].bcolor = ofColor(ofRandom(200,255), ofRandom(0,255), ofRandom(0,200), 255);
+
  rect(0, 0, width, height);
ants[i].dir = i % 4;
+
 
}
+
  // 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(){
void ofApp::update(){
+
  if(cells[(int)ant.x][(int)ant.y] == true){
for (int i = 0; i < ANTS_NUM; i++) { //アリの個体
+
    ant_direction = (ant_direction + 3) % 4; // turn left
for(int j = 0; j < DRAW_RATE; j++){ // 描画間隔
+
  }else {
if(field[ants[i].row][ants[i].col] == 1){ //fieldに色があるとき
+
    ant_direction = (ant_direction + 1) % 4; // turn right
ants[i].dir = ( ants[i].dir + 1 ) % 4; // 右に90度方向転換
+
  }
field[ants[i].row][ants[i].col] = 0;
+
  cells[(int)ant.x][(int)ant.y] = !cells[(int)ant.x][(int)ant.y];
pixels[ants[i].col * WIDTH + ants[i].row] = 0;
+
  forward_ant();
} else { //fieldに色がないとき
+
}
ants[i].dir = ( ants[i].dir + 3 ) % 4; // 左に90度方向転換
+
field[ants[i].row][ants[i].col] = 1;
+
pixels[ants[i].col * WIDTH + ants[i].row] = 255;
+
}
+
  
switch(ants[i].dir)
+
void forward_ant(){
{
+
  switch(ant_direction){
case 0: // 東(X軸の正)へ進む
+
    case 0:
ants[i].row += 1;
+
      ant.y = (ant.y - 1 + CELL_NUM) % CELL_NUM;
break;
+
      break;
case 1: // 南(Y軸の正)へ進む
+
    case 1:
ants[i].col += 1;
+
      ant.x = (ant.x + 1) % CELL_NUM;
break;
+
      break;
case 2: // 西(X軸の負)へ進む
+
    case 2:
ants[i].row -= 1;
+
      ant.y = (ant.y + 1) % CELL_NUM;
break;
+
      break;
case 3: // 北(Y軸の負)へ進む
+
    case 3:
ants[i].col -= 1;
+
      ant.x = (ant.x - 1 + CELL_NUM) % CELL_NUM;
break;
+
      break;
}
+
  }
ants[i].row = (ants[i].row + WIDTH) % WIDTH; // X方向境界処理
+
ants[i].col = (ants[i].col + HEIGHT) % HEIGHT; // Y方向境界処理
+
}
+
}
+
myImage.update();
+
 
}
 
}
  
//--------------------------------------------------------------
+
void initialize_cells(int method){
void ofApp::draw(){
+
  switch(method){
ofSetColor(0, 0, 255);
+
    case 0: // all white
myImage.draw(0, 0, WIDTH * FIELD_RATE, HEIGHT * FIELD_RATE); // fieldの描画
+
      for(int w = 0; w < CELL_NUM; w++){
for (int i = 0; i < ANTS_NUM; i++) { // antの描画
+
        for(int h = 0; h < CELL_NUM; h++){
ofSetColor(ants[i].bcolor);
+
          cells[w][h] = false;
ofRect(ants[i].row * FIELD_RATE, ants[i].col * FIELD_RATE, FIELD_RATE, FIELD_RATE);
+
        }
}
+
      }
 +
      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;
 +
  }
 
}
 
}
 
</pre>
 
</pre>
  
== アリごとに異なる軌跡色を設定 ==
+
== ラングトンのアリの拡張 ==
* Antクラスのプロパティに 歩いた軌跡の色である '''tcolor'''を設定
+
* ofImageを'''OF_IMAGE_COLOR'''に設定する。
+
** myImageは RGBの3プレーンで構成される。
+
  
;Antクラス
+
多数の色を使うように拡張する。色の変化は、循環となり、アリの動きは各色ごとに右か左に向きを変えて1マス進むことになる。これを色の順に L(左)と R(右)を並べて表す。
<pre>
+
class Ant {
+
public:
+
int row;
+
int col;
+
ofColor bcolor; // antの現在位置の色
+
ofColor tcolor;  // antの軌跡の色
+
int dir;
+
  
};
+
;以下のソース例
</pre>
+
* mod = 4で、4の剰余系(0,1,2,3)で色を表す
 +
* 色はHSB系で表す。H:色相、S:彩度、B:明度
 +
** この例では、'''colorMode(HSB, mod, 100, 100)'''として、色相(mod=)4段階、彩度100段階、明度100段階で表す。
 +
** 参考:[http://r-dimension.xsrv.jp/classes_j/color_system/ 色彩]
 +
* 各色(0123)による進路「LRLR」の時、彷徨った後、行進する(通常のラングトンのアリ)。
 +
* 各色(0123)による進路「RLLR」の時、正方形を描きながら彷徨う。
 +
**以下のソース例は「RLLR」としている。
  
; ofApp.cpp
 
* アリは、色のないフィールドにいると、自分の軌跡色をmyImageにセルに設定する。
 
 
<pre>
 
<pre>
//--------------------------------------------------------------
+
int CELL_NUM = 100;
void ofApp::setup(){
+
int CELL_SIZE = 5;
ofBackground(0, 0, 0);
+
ofSetFrameRate(30);
+
  
myImage.allocate(WIDTH, HEIGHT, OF_IMAGE_COLOR); //ofImageをカラーモードで割当
+
int[][] cells = new int[CELL_NUM][CELL_NUM];
pixels = myImage.getPixels();
+
int mod = 4;
for (int i = 0; i < WIDTH * HEIGHT * 3 ; i++) { //RGB 3 planeのピクセル
+
PVector ant;
pixels[i] = 0;
+
int ant_direction; // 0=up, 1=right, 2=down, 3=left
}
+
for (int i = 0; i < WIDTH; i++) {
+
void settings() {
for (int j = 0; j < HEIGHT; j++) {
+
size(CELL_NUM * CELL_SIZE, CELL_NUM * CELL_SIZE);
field[i][j] = 0;
+
}
}
+
}
+
void setup(){
myImage.update();
+
 
 +
  // 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;
 +
}
  
for (int i = 0; i < ANTS_NUM; i++) {
+
void draw(){
ants[i].row = int(ofRandom(WIDTH));
+
  // clear screen
ants[i].col = int(ofRandom(HEIGHT));
+
  fill(0,0,95);
ants[i].bcolor = ofColor(ofRandom(0, 255), ofRandom(0, 255), ofRandom(0, 255) );
+
  rect(0, 0, width, height);
ants[i].tcolor = ofColor(ofRandom(0, 255) , ofRandom(0, 255) , ofRandom(0, 255) );
+
 
ants[i].dir = i % 4;
+
  // 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(){
void ofApp::update(){
+
  switch(cells[(int)ant.x][(int)ant.y]){
for (int i = 0; i < ANTS_NUM; i++) { //アリの個体
+
// RLLR
for(int j = 0; j < DRAW_RATE; j++){ // 描画間隔
+
    case 0:
if(field[ants[i].row][ants[i].col] == 1){ //fieldに色があるとき
+
    ant_direction = (ant_direction + 1) % 4; // turn right
ants[i].dir = ( ants[i].dir + 1 ) % 4;
+
      break;
field[ants[i].row][ants[i].col] = 0;
+
    case 1:
pixels[ants[i].col * 3 * WIDTH + ants[i].row * 3] = 0; // R値
+
    ant_direction = (ant_direction + 3) % 4; // turn left
pixels[ants[i].col * 3 * WIDTH + ants[i].row * 3 + 1] = 0; // G値
+
      break;
pixels[ants[i].col * 3 * WIDTH + ants[i].row * 3 + 2] = 0; // B値
+
    case 2:
} else { //fieldに色がないとき
+
    ant_direction = (ant_direction + 3) % 4; // turn left
ants[i].dir = ( ants[i].dir + 3 ) % 4;
+
      break;
field[ants[i].row][ants[i].col] = 1;
+
    case 3:
pixels[ants[i].col * 3 * WIDTH + ants[i].row * 3] = ants[i].tcolor.r; // R値
+
    ant_direction = (ant_direction + 1) % 4; // turn right
pixels[ants[i].col * 3 * WIDTH + ants[i].row * 3 + 1] = ants[i].tcolor.g; // G値
+
      break;
pixels[ants[i].col * 3 * WIDTH + ants[i].row * 3 + 2] = ants[i].tcolor.b; // B値
+
  }
}
+
  cells[(int)ant.x][(int)ant.y] = ( cells[(int)ant.x][(int)ant.y] + 1 ) % mod;
switch(ants[i].dir)
+
  forward_ant();
{
+
case 0:  // 東(X軸の正)へ進む
+
ants[i].row += 1;
+
break;
+
case 1: // 南(Y軸の正)へ進む
+
ants[i].col += 1;
+
break;
+
case 2:  // 西(X軸の負)へ進む
+
ants[i].row -= 1;
+
break;
+
case 3:  // 北(Y軸の負)へ進む
+
ants[i].col -= 1;
+
break;
+
}
+
ants[i].row = (ants[i].row + WIDTH) % WIDTH; // X方向境界処理
+
ants[i].col = (ants[i].col + HEIGHT) % HEIGHT; // Y方向境界処理
+
}
+
}
+
myImage.update();
+
 
}
 
}
  
//--------------------------------------------------------------
+
void forward_ant(){
void ofApp::draw(){
+
  switch(ant_direction){
ofSetColor(255, 255, 255); // 描画色をリセット
+
    case 0:
ofSetRectMode(OF_RECTMODE_CORNER);
+
      ant.y = (ant.y - 1 + CELL_NUM) % CELL_NUM;
myImage.draw(0, 0, WIDTH * FIELD_RATE, HEIGHT * FIELD_RATE); // fieldの描画
+
      break;
ofSetRectMode(OF_RECTMODE_CENTER);
+
    case 1:
for (int i = 0; i < ANTS_NUM; i++) {// antの描画
+
      ant.x = (ant.x + 1) % CELL_NUM;
ofSetColor(ants[i].bcolor);
+
      break;
ofRect(ants[i].row * FIELD_RATE, ants[i].col * FIELD_RATE, FIELD_RATE, FIELD_RATE);
+
    case 2:
}
+
      ant.y = (ant.y + 1) % CELL_NUM;
 +
      break;
 +
    case 3:
 +
      ant.x = (ant.x - 1 + CELL_NUM) % CELL_NUM;
 +
      break;
 +
  }
 
}
 
}
</pre>
 
  
== 動的配列vectorの利用 ==
+
void initialize_cells(int method){
アリは、初めはいないが、マウスクリックした場所にAntインスタンスが動的に現れる。
+
  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;
  
*動的配列(vector)は、定義時に、配列の要素数を決めなくてもよい。プログラム実行中に動的に追加や削除ができる。
+
  }
従来は、予め配列数を決めて、例えば
+
}
 
+
<pre>
+
クラス名 インスタンス名[100]
+
 
</pre>
 
</pre>
と宣言していたが、vectorでは。
 
  
<pre>
 
vector <クラス名> インスタンス名
 
</pre>
 
と宣言し、配列の個数は、動的に追加、削除できる。
 
  
今回の例では、
 
<pre>
 
Ant ants[100];
 
</pre>
 
とするところを
 
<pre>
 
vector <Ant> ants;
 
</pre>
 
とすると、アリを後から追加できる。
 
配列の個数(大きさは)
 
<pre>
 
ants.size()
 
</pre>
 
で参照できる。
 
  
インスタンスを追加するには、
+
== 人工生命(ALife) ==
<pre>
+
ants.push_back()
+
</pre>
+
を使う。
+
  
マウスクリックした位置に新しいアリを生成する部分は以下のとおり。
+
[[セルオートマトン]]
<pre>
+
oid ofApp::mouseReleased(int x, int y, int button){
+
Ant a; //新しくアリのインスタンスを作成
+
a.row = mouseX * WIDTH / ofGetWidth(); //マウスの位置に配置
+
a.col = mouseY * HEIGHT / ofGetHeight();
+
a.bcolor = ofColor(ofRandom(0, 255), ofRandom(0, 255), ofRandom(0, 255) ); //色をランダムに選ぶ
+
a.tcolor = ofColor(ofRandom(0, 255) , ofRandom(0, 255) , ofRandom(0, 255) );
+
a.dir = mouseX % 4; //方向を決める
+
ants.push_back(a); // 生成したaをantsに追加
+
}
+
</pre>
+
  
すべての要素を削除するには、
+
[[レイノルズのボイド]]
<pre>
+
ants.clear()
+
</pre>
+
とする。
+
  
Cを押すと、アリと画面をクリアする場合
+
[[反応拡散系]]
<pre>
+
 
void ofApp::keyReleased(int key){
+
[[フラクタル]]
if( key == 'C'){
+
ants.clear();
+
for (int i = 0; i < WIDTH * HEIGHT * 3 ; i++) { //RGB 3 planeのピクセル
+
pixels[i] = 0;
+
}
+
for (int i = 0; i < WIDTH; i++) {
+
for (int j = 0; j < HEIGHT; j++) {
+
field[i][j] = 0;
+
}
+
}
+
myImage.update();
+
}
+
}
+
</pre>
+
  
 
== 参考 ==
 
== 参考 ==
[[ジェネラティブアート論]]
+
[[スケーラブルアート論]]
  
 
[[Category:授業]]
 
[[Category:授業]]

2021年11月4日 (木) 21:25時点における最新版

目次

[編集] 概要

ラングトンのアリwikipedia /

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

Langton ant01 11.png

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

ラングトンのループ /

[編集] Processingソース例

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

  • boolean型の変数の値は、true(真) か false(偽)の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)

セルオートマトン

レイノルズのボイド

反応拡散系

フラクタル

[編集] 参考

スケーラブルアート論

個人用ツール
名前空間

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