1次元セルオートマトン

提供:kuhalaboWiki
移動: 案内, 検索

目次

openFrameworksのサンプル

Wolframのセルオートマトンの描画プログラム

シンプルに配列だけで記述

シェルピンスキーのギャスケット その1

  • 2次元配列cell[256][256]を作り、まとめて状態を更新し、描画する。
#include "ofApp.h"

static const int NUM = 256; //セルの個数
int cell[NUM][NUM];

//--------------------------------------------------------------
void ofApp::setup(){
	ofBackground(0, 0, 0); //背景色の設定
//初期状態は真ん中だけが 1 で残りはすべて 0
	for(int i = 0; i < NUM; i++){
		cell[i][0] = 0;
	}
	cell[NUM/2][0] = 1;
}

//--------------------------------------------------------------
void ofApp::update(){
//状態遷移則 1つ前と1つ後の値を足した値の1桁目(2進法の足し算 XOR)
	for(int j = 1; j < NUM; j++){ // j: 時間
		for(int i = 1; i < NUM-1; i++){ // i: 位置
			cell[i][j] = ( cell[i-1][j-1] + cell[i+1][j-1] ) % 2; //状態遷移則 %は剰余演算
		}
	}
}

//--------------------------------------------------------------
void ofApp::draw(){
	int w = 4; //セルの描画幅
	for(int i = 0; i < NUM; i++){
		for(int j = 0; j < NUM; j++){
			if( cell[i][j] > 0 ) ofSetColor(255,0,0); //セルが 1 の時の描画色
			else ofSetColor(0,0,0); //セルが 0 の時の描画色
			ofRect(i * w, j * w , w , w ); 
		}
	}
}


状態遷移則を変えてみる。
1つ前と自分の値と1つ後の値を足した値
			cell[i][j] = ( cell[i-1][j-1] + cell[i][j-1]  + cell[i+1][j-1] ) % 2;
cellの値を256で割った余りにする。
			cell[i][j] = ( cell[i-1][j-1] + cell[i+1][j-1] ) % 256;
drawを変えてみる。
1つ前と自分の値と1つ後の値を足した値
			if (cell[i][j] > 0) ofSetColor(127, cell[i][j], 0); //セルが 1 の時の描画色

クラスを使って記述

シェルピンスキーのギャスケット その2

クラスに、内部状態、状態遷移則などを定義する。

Cell.h
  • Cellクラスを設計
#pragma once
#include "ofMain.h"

class Cell {
public:
	ofPoint pos; //位置
	float width; //幅
	ofColor bcolor; //描画色
	int state; //内部状態
	int sXXX; //自分と両隣りの状態 000-111(0-7)の8通り

public:
	Cell();
	void draw();
	void update();
};


Cell.cpp
  • ルール90(01011010)の規則を記述
#include "Cell.h"

Cell::Cell(){
	width = 4;
	bcolor = ofColor(255, 0, 0);
}

void Cell::update(){
//自分と両隣りの状態に応じて次の自分の状態を決める
		switch(sXXX){
		case 0: //000
			state = 0;
			break;
		case 1: //001
			state = 1;
			break;
		case 2: //010
			state = 0;
			break;
		case 3: //011
			state = 1;
			break;
		case 4: //100
			state = 1;
			break;
		case 5: //101
			state = 0;
			break;
		case 6: //110
			state = 1;
			break;
		case 7: //111
			state = 0;
			break;
		}
}

void Cell::draw(){
	if( state ){
		ofSetColor(bcolor);
		ofRect(pos, width,width);
	}
}
ofApp.h
  • クラスの配列cellを生成。その1の通常の配列cellとの違いに注意。
#pragma once

#include "ofMain.h"
#include "Cell.h"

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 NUM = 256; //セルの個数
		Cell cell[NUM][NUM];
		
};
ofApp.cpp
//--------------------------------------------------------------
void ofApp::setup(){
	ofBackground(0, 0, 0); //背景色の設定
	//初期状態は真ん中だけが 1 で残りはすべて 0
	for(int i = 0; i < NUM; i++){
		cell[i][0].state = 0;
		cell[i][0].pos = ofPoint(i * cell[i][0].width, 0);
	}
	cell[NUM/2][0].state = 1;
}

//--------------------------------------------------------------
void ofApp::update(){
	for(int j = 1; j < NUM; j++){
		for(int i = 0; i < NUM; i++){
			int iP = (i - 1 + NUM ) % NUM;
			int iN = (i + 1 + NUM ) % NUM;
                        // 自分と両隣りの状態の2進数000-111を10進数0-7に変換
			cell[i][j].sXXX = cell[iP][j-1].state * 4 + cell[i][j-1].state * 2 + cell[iN][j-1].state;
			cell[i][j].update();
			cell[i][j].pos = ofPoint(i * cell[i][j].width, j * cell[i][j].width); //セルの描画位置を指定
		}
	}
}

//--------------------------------------------------------------
void ofApp::draw(){

	for(int i = 0; i < NUM; i++){
		for(int j = 0; j < NUM; j++){
			cell[i][j].draw();
		}
	}
}

256種のルールのセルオートマトン

  • 256種類のルール全てのセルオートマトンを順番に表示する。
Cell.h
#pragma once
#include "ofMain.h"

class Cell {
public:
	ofPoint pos; //位置
	float width; //幅
	ofColor bcolor; //描画色
	int state; //内部状態
	int sXXX; //次の状態 000-111の8通り
	int rX8; //ルール 8bit 256通り

public:
	Cell();
	void draw();
	void update();
};
Cell.cpp
#include "Cell.h"

Cell::Cell(){
	width = 4;
	bcolor = ofColor(255, 0, 0);
}

void Cell::update(){
                //自分の次の状態00000000-11111111の256通りを10進数から2進数に変換
		switch(sXXX){
		case 0: //000
			state =  rX8 % 2;
			break;
		case 1: //001
			state = ( rX8 % 4) / 2;
			break;
		case 2: //010
			state = ( rX8 % 8) / 4;
			break;
		case 3: //011
			state = ( rX8 % 16) / 8;
			break;
		case 4: //100
			state = ( rX8 % 32) / 16;
			break;
		case 5: //101
			state = ( rX8 % 64 ) / 32;
			break;
		case 6: //110
			state = ( rX8 % 128 ) / 64;
			break;
		case 7: //111
			state = rX8 / 128;
			break;
		}
}

void Cell::draw(){
	if( state ){
		ofSetColor(bcolor);
		ofRect(pos, width,width);
	}
	else
	{
		ofSetColor(ofColor(0, 0, 0));
		ofRect(pos, width,width);
	}
}
10進数から2進数の変換
10進数 n を2進数に変換した時の2^kの位の値は ( n % 2^(k+1) ) / 2^k で表せる。
ofApp.h
#pragma once

#include "ofMain.h"
#include "Cell.h"

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 NUM = 256; //セルの個数
		Cell cell[NUM][NUM];
		int r; //ルール番号 0-255の10進値
};
ofApp.cpp
#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){
	ofBackground(0, 0, 0); //背景色の設定
	ofSetFrameRate(2); //フレームレイト設定
	r = 0; //ルール番号の初期値

	//初期状態は真ん中だけが 1 で残りはすべて 0
	for(int i = 0; i < NUM; i++){
		cell[i][0].state = 0;
		cell[i][0].pos = ofPoint(i * cell[i][0].width, 0);
	}
	cell[NUM/2][0].state = 1;

}

//--------------------------------------------------------------
void ofApp::update(){
	r = ( r + 1 ) % 256; //ルール番号を1つ増やす。256になったら0に戻す
	for(int j = 1; j < NUM; j++){
		for(int i = 0; i < NUM; i++){
			cell[i][j].rX8 = r;
			int iP = (i - 1 + NUM ) % NUM;
			int iN = (i + 1 + NUM ) % NUM;
			cell[i][j].sXXX = cell[iP][j-1].state * 4 + cell[i][j-1].state * 2 + cell[iN][j-1].state;
			cell[i][j].update();
			cell[i][j].pos = ofPoint(i * cell[i][j].width, j * cell[i][j].width);
			cell[i][j].bcolor = ofColor(255-r, i, j); //模様にグラデーションをつける
		}
	}
}

//--------------------------------------------------------------
void ofApp::draw(){
	for(int i = 0; i < NUM; i++){
		for(int j = 0; j < NUM; j++){
			cell[i][j].draw();
		}
	}
	// ルール番号の表示
	ofSetColor(ofColor::white);
	ofDrawBitmapString("rule: " + ofToString(r), 10, 20);
}

参考

ジェネラティブアート論

個人用ツール
名前空間

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