ラングトンのアリ
提供:kuhalaboWiki
(版間での差分)
(→参考) |
|||
| 315行: | 315行: | ||
== 参考 == | == 参考 == | ||
| − | + | [[スケーラブルアート論]] | |
[[Category:授業]] | [[Category:授業]] | ||
2020年10月30日 (金) 00:52時点における版
目次 |
Processing
平面が格子状に構成され、各マスが白または黒で塗られる。 アリは各ステップで上下左右のいずれかのマスに移動することができる。アリは以下の規則に従って移動する。
- 白いマスにアリがいた場合、90°右に方向転換し、そのマスの色を反転させ、1マス前進する。
- 黒いマスにアリがいた場合、90°左に方向転換し、そのマスの色を反転させ、1マス前進する。
この単純な規則で驚くほど複雑な動作をする。
ソース例
参考 ラングトンの蟻 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(右)
- turn rightは現在の方向に1足した値の4で割った余り。
- 初期状態 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;
}
}
