ラングトンのアリ
提供:kuhalaboWiki
- アリは以下の規則に従って移動する。
- 色ありのマス(1)にアリがいた場合、90°右に方向転換し、そのマスの色を反転させ、1マス前進する。
- 色なしのマス(0)にアリがいた場合、90°左に方向転換し、そのマスの色を反転させ、1マス前進する。
- ofImageを使って、アリの動いた軌跡を描画している。
- ofImageのマニュアル http://www.openframeworks.cc/documentation/graphics/ofImage.html
- アリの現在位置の色はアリごとに異なる色を設定
- アリの軌跡の色は1色に設定
- ofApp.h
#pragma once #include "ofMain.h" class Ant { // Antクラス public: int row; // アリの x座標 int col; // アリの y座標 ofColor bcolor; // アリの色 int dir; // アリの進行方向 }; class ofApp : public ofBaseApp{ public: void setup(); void update(); void draw(); void keyPressed(int key); void keyReleased(int key); void mouseMoved(int x, int y ); void mouseDragged(int x, int y, int button); void mousePressed(int x, int y, int button); 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; };
- ofApp.cpp
#include "ofApp.h" //-------------------------------------------------------------- void ofApp::setup(){ ofBackground(0, 0, 0); ofSetFrameRate(30); myImage.allocate(WIDTH, HEIGHT, OF_IMAGE_GRAYSCALE); pixels = myImage.getPixels(); for (int i = 0; i < WIDTH * HEIGHT; i++) { pixels[i] = 0; } for (int i = 0; i < WIDTH; i++) { for (int j = 0; j < HEIGHT; j++) { field[i][j] = 0; } } myImage.update(); for (int i = 0; i < ANTS_NUM; i++) { ants[i].row = int(ofRandom(WIDTH)); ants[i].col = int(ofRandom(HEIGHT)); ants[i].bcolor = ofColor(ofRandom(200,255), ofRandom(0,255), ofRandom(0,200), 255); ants[i].dir = i % 4; } } //-------------------------------------------------------------- void ofApp::update(){ for (int i = 0; i < ANTS_NUM; i++) { //アリの個体 for(int j = 0; j < DRAW_RATE; j++){ // 描画間隔 if(field[ants[i].row][ants[i].col] == 1){ //fieldに色があるとき ants[i].dir = ( ants[i].dir + 1 ) % 4; // 右に90度方向転換 field[ants[i].row][ants[i].col] = 0; pixels[ants[i].col * WIDTH + ants[i].row] = 0; } 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) { 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 ofApp::draw(){ ofSetColor(0, 0, 255); myImage.draw(0, 0, WIDTH * FIELD_RATE, HEIGHT * FIELD_RATE); // fieldの描画 for (int i = 0; i < ANTS_NUM; i++) { // antの描画 ofSetColor(ants[i].bcolor); ofRect(ants[i].row * FIELD_RATE, ants[i].col * FIELD_RATE, FIELD_RATE, FIELD_RATE); } }
アリごとに異なる軌跡色を設定
- Antくらすのプロパティに 歩いた軌跡の色である tcolorを設定
- ofImageをOF_IMAGE_COLORに設定する。
- myImageは RGBの3プレーンで構成される。
- Antクラス
class Ant { public: int row; int col; ofColor bcolor; // antの現在位置の色 ofColor tcolor; // antの軌跡の色 int dir; };
- ofApp.cpp
- アリは、色のないフィールドにいると、自分の軌跡色をmyImageにセルに設定する。
//-------------------------------------------------------------- void ofApp::setup(){ ofBackground(0, 0, 0); ofSetFrameRate(30); myImage.allocate(WIDTH, HEIGHT, OF_IMAGE_COLOR); //ofImageをカラーモードで割当 pixels = myImage.getPixels(); 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(); for (int i = 0; i < ANTS_NUM; i++) { ants[i].row = int(ofRandom(WIDTH)); ants[i].col = int(ofRandom(HEIGHT)); ants[i].bcolor = ofColor(ofRandom(0, 255), ofRandom(0, 255), ofRandom(0, 255) ); ants[i].tcolor = ofColor(ofRandom(0, 255) , ofRandom(0, 255) , ofRandom(0, 255) ); ants[i].dir = i % 4; } } //-------------------------------------------------------------- void ofApp::update(){ for (int i = 0; i < ANTS_NUM; i++) { //アリの個体 for(int j = 0; j < DRAW_RATE; j++){ // 描画間隔 if(field[ants[i].row][ants[i].col] == 1){ //fieldに色があるとき ants[i].dir = ( ants[i].dir + 1 ) % 4; field[ants[i].row][ants[i].col] = 0; pixels[ants[i].col * 3 * WIDTH + ants[i].row * 3] = 0; // R値 pixels[ants[i].col * 3 * WIDTH + ants[i].row * 3 + 1] = 0; // G値 pixels[ants[i].col * 3 * WIDTH + ants[i].row * 3 + 2] = 0; // B値 } else { //fieldに色がないとき ants[i].dir = ( ants[i].dir + 3 ) % 4; field[ants[i].row][ants[i].col] = 1; pixels[ants[i].col * 3 * WIDTH + ants[i].row * 3] = ants[i].tcolor.r; // R値 pixels[ants[i].col * 3 * WIDTH + ants[i].row * 3 + 1] = ants[i].tcolor.g; // G値 pixels[ants[i].col * 3 * WIDTH + ants[i].row * 3 + 2] = ants[i].tcolor.b; // B値 } switch(ants[i].dir) { 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 ofApp::draw(){ ofSetColor(255, 255, 255); // 描画色をリセット ofSetRectMode(OF_RECTMODE_CORNER); myImage.draw(0, 0, WIDTH * FIELD_RATE, HEIGHT * FIELD_RATE); // fieldの描画 ofSetRectMode(OF_RECTMODE_CENTER); for (int i = 0; i < ANTS_NUM; i++) {// antの描画 ofSetColor(ants[i].bcolor); ofRect(ants[i].row * FIELD_RATE, ants[i].col * FIELD_RATE, FIELD_RATE, FIELD_RATE); } }
動的配列vectorの利用
アリは、初めはいないが、マウスクリックした場所にAntインスタンスが動的に現れる。
- 動的配列(vector)は、定義時に、配列の要素数を決めなくてもよい。プログラム実行中に動的に追加や削除ができる。
従来は、予め配列数を決めて、例えば
クラス名 インスタンス名[100]
と宣言していたが、vectorでは。
vector <クラス名> インスタンス名
と宣言し、配列の個数は、動的に追加、削除できる。
今回の例では、
Ant ants[100];
とするところを
vector <Ant> ants;
とすると、アリを後から追加できる。 配列の個数(大きさは)
ants.size()
で参照できる。
インスタンスを追加するには、
ants.push_back()
を使う。
マウスクリックした位置に新しいアリを生成する部分は以下のとおり。
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に追加 }
すべての要素を削除するには、
ants.clear()
とする。
Cを押すと、アリと画面をクリアする場合
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(); } }