ラングトンのアリ
提供:kuhalaboWiki
- アリは以下の規則に従って移動する。
- 黒いマスにアリがいた場合、90°右に方向転換し、そのマスの色を反転させ、1マス前進する。
- 白いマスにアリがいた場合、90°左に方向転換し、そのマスの色を反転させ、1マス前進する。
- ofImageを使って、アリの動いた軌跡と現在位置を描画している。
- ofImageのマニュアル http://www.openframeworks.cc/documentation/graphics/ofImage.html
- アリの現在位置の色はアリごとに異なる色を設定
- アリの軌跡の色は1色に設定
- ofApp.h
#pragma once #include "ofMain.h" class Ant { public: int row; int col; 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]; 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; 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; 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] = 1; } } 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]
今回の例では、
Ant ants[100]
と宣言していたが、vectorでは。
vector <クラス名> インスタンス名
今回の例では、
vector <Ant> ants
と宣言し、配列の個数は、動的に追加、削除できる。