1次元セルオートマトン

提供:kuhalaboWiki
(版間での差分)
移動: 案内, 検索
(256のルールを記述)
 
(1人の利用者による、間の29版が非表示)
1行: 1行:
 +
== openFrameworksのサンプル ==
 +
 
Wolframのセルオートマトンの描画プログラム
 
Wolframのセルオートマトンの描画プログラム
  
== シェルピンスキーのガスケット ==
+
== シンプルに配列だけで記述 ==
=== シンプルに配列だけで記述 ===
+
=== シェルピンスキーのギャスケット その1 ===
 +
* 2次元配列cell[256][256]を作り、まとめて状態を更新し、描画する。
 
<pre>
 
<pre>
 
#include "ofApp.h"
 
#include "ofApp.h"
22行: 25行:
 
void ofApp::update(){
 
void ofApp::update(){
 
//状態遷移則 1つ前と1つ後の値を足した値の1桁目(2進法の足し算 XOR)
 
//状態遷移則 1つ前と1つ後の値を足した値の1桁目(2進法の足し算 XOR)
for(int j = 1; j < NUM; j++){
+
for(int j = 1; j < NUM; j++){ // j: 時間
for(int i = 1; i < NUM-1; i++){
+
for(int i = 1; i < NUM-1; i++){ // i: 位置
cell[i][j] = ( cell[i-1][j-1] + cell[i+1][j-1] ) % 2;
+
cell[i][j] = ( cell[i-1][j-1] + cell[i+1][j-1] ) % 2; //状態遷移則 %は剰余演算
 
}
 
}
 
}
 
}
42行: 45行:
 
</pre>
 
</pre>
  
=== クラスを使って記述 ===
+
 
* Cellクラスを設計
+
;状態遷移則を変えてみる。
*ルール30(01011010)の規則を記述
+
:1つ前と自分の値と1つ後の値を足した値
 +
<pre>
 +
cell[i][j] = ( cell[i-1][j-1] + cell[i][j-1]  + cell[i+1][j-1] ) % 2;
 +
</pre>
 +
 
 +
:cellの値を256で割った余りにする。
 +
<pre>
 +
cell[i][j] = ( cell[i-1][j-1] + cell[i+1][j-1] ) % 256;
 +
</pre>
 +
 
 +
;drawを変えてみる。
 +
:1つ前と自分の値と1つ後の値を足した値
 +
<pre>
 +
if (cell[i][j] > 0) ofSetColor(127, cell[i][j], 0); //セルが 1 の時の描画色
 +
</pre>
 +
 
 +
== クラスを使って記述 ==
 +
=== シェルピンスキーのギャスケット その2 ===
 +
クラスに、内部状態、状態遷移則などを定義する。
  
 
;Cell.h
 
;Cell.h
 +
* Cellクラスを設計
 
<pre>
 
<pre>
 
#pragma once
 
#pragma once
57行: 79行:
 
ofColor bcolor; //描画色
 
ofColor bcolor; //描画色
 
int state; //内部状態
 
int state; //内部状態
int sXXX; //次の状態 000-111の8通り
+
int sXXX; //自分と両隣りの状態 000-111(0-7)の8通り
  
 
public:
 
public:
65行: 87行:
 
};
 
};
 
</pre>
 
</pre>
 +
 +
  
 
;Cell.cpp
 
;Cell.cpp
 +
*ルール90(01011010)の規則を記述
 
<pre>
 
<pre>
 
#include "Cell.h"
 
#include "Cell.h"
  
 
Cell::Cell(){
 
Cell::Cell(){
pos = ofPoint(0, 0);
 
 
width = 4;
 
width = 4;
state = 0;
+
bcolor = ofColor(255, 0, 0);
bcolor = ofColor(255, 0, 0, 100);
+
 
}
 
}
  
 
void Cell::update(){
 
void Cell::update(){
 +
//自分と両隣りの状態に応じて次の自分の状態を決める
 
switch(sXXX){
 
switch(sXXX){
 
case 0: //000
 
case 0: //000
115行: 139行:
  
 
;ofApp.h
 
;ofApp.h
 +
* クラスの配列cellを生成。その1の通常の配列cellとの違いに注意。
 
<pre>
 
<pre>
 
#pragma once
 
#pragma once
120行: 145行:
 
#include "ofMain.h"
 
#include "ofMain.h"
 
#include "Cell.h"
 
#include "Cell.h"
 
  
 
class ofApp : public ofBaseApp{
 
class ofApp : public ofBaseApp{
164行: 188行:
 
int iP = (i - 1 + NUM ) % NUM;
 
int iP = (i - 1 + NUM ) % NUM;
 
int iN = (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].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].update();
cell[i][j].pos = ofPoint(i * cell[i][j].width, j * cell[i][j].width);
+
cell[i][j].pos = ofPoint(i * cell[i][j].width, j * cell[i][j].width); //セルの描画位置を指定
 
+
 
}
 
}
 
}
 
}
182行: 206行:
 
}
 
}
 
</pre>
 
</pre>
=== 256のルールを記述 ===
+
 
* 256のルールのセルオートマトンを順番に表示する。
+
== 256種のルールのセルオートマトン ==
 +
* 256種類のルール全てのセルオートマトンを順番に表示する。
  
 
;Cell.h
 
;Cell.h
211行: 236行:
  
 
Cell::Cell(){
 
Cell::Cell(){
pos = ofPoint(0, 0);
 
 
width = 4;
 
width = 4;
state = 0;
 
 
bcolor = ofColor(255, 0, 0);
 
bcolor = ofColor(255, 0, 0);
 
}
 
}
  
 
void Cell::update(){
 
void Cell::update(){
 +
                //自分の次の状態00000000-11111111の256通りを10進数から2進数に変換
 
switch(sXXX){
 
switch(sXXX){
 
case 0: //000
 
case 0: //000
258行: 282行:
 
}
 
}
 
</pre>
 
</pre>
 +
 +
;10進数から2進数の変換
 +
:10進数 n を2進数に変換した時の2^kの位の値は ( n % 2^(k+1) ) / 2^k で表せる。
  
 
;ofApp.h
 
;ofApp.h
285行: 312行:
 
static const int NUM = 256; //セルの個数
 
static const int NUM = 256; //セルの個数
 
Cell cell[NUM][NUM];
 
Cell cell[NUM][NUM];
int r; //ルール番号
+
int r; //ルール番号 0-255の10進値
 
};
 
};
 
</pre>
 
</pre>
297行: 324行:
 
ofBackground(0, 0, 0); //背景色の設定
 
ofBackground(0, 0, 0); //背景色の設定
 
ofSetFrameRate(2); //フレームレイト設定
 
ofSetFrameRate(2); //フレームレイト設定
r = 0;
+
r = 0; //ルール番号の初期値
  
 
//初期状態は真ん中だけが 1 で残りはすべて 0
 
//初期状態は真ん中だけが 1 で残りはすべて 0
 
for(int i = 0; i < NUM; i++){
 
for(int i = 0; i < NUM; i++){
 
cell[i][0].state = 0;
 
cell[i][0].state = 0;
cell[i][0].rX8 = 0;
 
 
cell[i][0].pos = ofPoint(i * cell[i][0].width, 0);
 
cell[i][0].pos = ofPoint(i * cell[i][0].width, 0);
 
}
 
}
311行: 337行:
 
//--------------------------------------------------------------
 
//--------------------------------------------------------------
 
void ofApp::update(){
 
void ofApp::update(){
 +
r = ( r + 1 ) % 256; //ルール番号を1つ増やす。256になったら0に戻す
 
for(int j = 1; j < NUM; j++){
 
for(int j = 1; j < NUM; j++){
 
for(int i = 0; i < NUM; i++){
 
for(int i = 0; i < NUM; i++){
319行: 346行:
 
cell[i][j].update();
 
cell[i][j].update();
 
cell[i][j].pos = ofPoint(i * cell[i][j].width, j * cell[i][j].width);
 
cell[i][j].pos = ofPoint(i * cell[i][j].width, j * cell[i][j].width);
cell[i][j].bcolor = ofColor(r, i, j); //模様にグラデーションをつける
+
cell[i][j].bcolor = ofColor(255-r, i, j); //模様にグラデーションをつける
 
}
 
}
 
}
 
}
334行: 361行:
 
ofSetColor(ofColor::white);
 
ofSetColor(ofColor::white);
 
ofDrawBitmapString("rule: " + ofToString(r), 10, 20);
 
ofDrawBitmapString("rule: " + ofToString(r), 10, 20);
r = ( r + 1 ) % 256;
 
 
}
 
}
 
</pre>
 
</pre>

2020年10月31日 (土) 00:22時点における最新版

目次

[編集] 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);
}

[編集] 参考

ジェネラティブアート論

個人用ツール
名前空間

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