セルオートマトン
提供:kuhalaboWiki
(版間での差分)
(ページの作成:「== セルオートマトン == [https://ja.wikipedia.org/wiki/%E3%82%BB%E3%83%AB%E3%83%BB%E3%82%AA%E3%83%BC%E3%83%88%E3%83%9E%E3%83%88%E3%83%B3 Wikipedia] === パス...」) |
(→セルオートマトン資料) |
||
| 574行: | 574行: | ||
* Life Game Orchestra : [http://www.kuhalabo.net/~kuha/nime/lifegorch/ Doccument] / [https://youtu.be/QV2C_nILzZE YouTube] | * Life Game Orchestra : [http://www.kuhalabo.net/~kuha/nime/lifegorch/ Doccument] / [https://youtu.be/QV2C_nILzZE YouTube] | ||
| − | |||
[http://ja.wikipedia.org/wiki/%E3%83%AF%E3%82%A4%E3%83%A4%E3%83%AF%E3%83%BC%E3%83%AB%E3%83%89 ワイヤワールド] / | [http://ja.wikipedia.org/wiki/%E3%83%AF%E3%82%A4%E3%83%A4%E3%83%AF%E3%83%BC%E3%83%AB%E3%83%89 ワイヤワールド] / | ||
| + | |||
| + | == 参考 == | ||
| + | [[スケーラブルアート論]] | ||
| + | |||
| + | |||
| + | [[Category:授業]] | ||
2020年10月30日 (金) 00:52時点における版
目次 |
セルオートマトン
パスカルの三角形
http://www.xn--u9jtgqbzf1fn77phnzag74e.jp/pascul-nature.html
- 数字を書くプログラム
- textSize() 文字の大きさを決める。
- text(txt,x ,y) txtという文字列を(x,y)に書く。
- splice(配列a,値v, 場所i) 配列aに値vを場所i(先頭からi番目)に挿入します。
int num = 8; //計算する世代数の上限
int[] state = {1}; //初期状態
int gen = 0; //世代
void setup(){
size(500, 500);
}
void draw(){
if(gen < num){
drawNumber(gen); //数字を書く
updateState(); //状態を更新する
}
}
void drawNumber(float y){
float scalar = (float) width / num; // 数字の大きさ
float x = (width - state.length * scalar) * 0.5; // 数字を書く位置のx座標
y *= scalar;
fill(0);
for (int i = 0; i < state.length; i++){
textSize(scalar * 0.5);
text(state[i], x + scalar * 0.5, y + scalar * 0.5);
x += scalar; // 数字を書く位置をx座標方向にずらす
}
}
void updateState(){
int[] BOUNDARY = {0}; //境界値(文字がない所)を0とする
int[] nextState = new int[state.length + 1]; // 次の世代の状態
state = splice(state, BOUNDARY, 0); // 配列の最初に境界値を加える
state = splice(state, BOUNDARY, state.length); // 配列の最後に境界値を加える
for (int i = 0; i < state.length - 1; i++){
nextState[i] = transition(i); // 次世代の状態の計算
}
state = nextState; // 状態を更新
gen++; //世代を1つ増やす
}
int transition(int i){
int nextC = state[i + 1] + state[i]; //パスカルの法則に従った計算
return nextC;
}
- 数値をmodで標記
- mod 割り算のあまり。
- 0,1のパスカルの三角形の遷移ルール
- (0+0) % 2 -> 0
- (0+1) % 2 -> 1
- (1+0) % 2 -> 1
- (1+1) % 2 -> 0
int num = 250;
int mod = 2;
int[] state = {1};
int gen = 0;
void setup(){
size(500, 500);
colorMode(HSB, 1);
background(0, 0, 1);
}
void draw(){
if (gen < num){
drawCell(gen);
updateState();
}
}
void drawCell(float y){
float scalar = (float) width / num; // セルの大きさ
float x = (width - state.length * scalar) * 0.5; // セルのx座標
y *= scalar;
noStroke();
for (int i = 0; i < state.length; i++){
fill(state[i] * 1.0 / mod, state[i] * 1.0 / mod, 1); //色相にセルの状態を割り当て
rect(x, y, scalar, scalar); // セルの描画
x += scalar; // x座標方向にセルをずらす
}
}
void updateState(){
int[] BOUNDARY = {0};
int[] nextState = new int[state.length + 1]; // 次の行の配列
state = splice(state, BOUNDARY, 0); // 配列stateの最初に{0,0}を加える
state = splice(state, BOUNDARY, state.length); // 配列stateの最後に{0,0}を加える
for (int i = 0; i < state.length - 1; i++){
nextState[i] = transition(i); // 次世代のセルの状態の計算
}
state = nextState; // セルの状態を更新
gen++;
}
int transition(int i){
int nextC = (state[i + 1] + state[i]) % mod; // 遷移規則
return nextC;
}
- セルピンスキーのギャスケット
- 0,1のパスカルの三角形の遷移ルール
- 隣接する2つのセルで次の状態が決まる。
- 00 -> 0 or 1
- 01 -> 0 or 1
- 10 -> 0 or 1
- 11 -> 0 or 1
基本セルオートマトン
- 隣接する3つのセルで次の状態が決まる。
- セルの状態は、0,1
- 000 -> 0 or 1
- 001 -> 0 or 1
- 010 -> 0 or 1
- 011 -> 0 or 1
- 100 -> 0 or 1
- 101 -> 0 or 1
- 110 -> 0 or 1
- 111 -> 0 or 1
- 0 or 1 が8通りあるので、合計 2の8乗=256通りのルールがある。
- Wolframは256通りのルールをすべて調べた。
- Elementary Cellular Automaton, Wolfram Math World
- 全て0の00000000(ルール0)から全て1の11111111(ルール255)まで
基本セルオートマトンのソース例
- c(t+1,i) = c(t,i-1) + c(t,i) + c(t,i+1) の例
- 0+0=0, 0+1=0+1=1, 1+1=0 (2進数では10だが、1桁目のみ残す)
- 000 -> 0
- 001 -> 1
- 010 -> 1
- 011 -> 0
- 100 -> 1
- 101 -> 0
- 110 -> 0
- 111 -> 1
int num = 250; //表示する世代数
int mod = 2; //法とする数
int[] state = {1}; //初期状態
int gen = 0;
void setup(){
size(1000, 500);
colorMode(HSB, 1);
background(0, 0, 1);
}
void draw(){
if (gen < num){
drawCell(gen);
updateState();
}
}
void mouseClicked(){
gen = 0;
state = new int[]{1}; //初期状態
mod = int(random(2, 20));
println(mod);
background(0, 0, 1);
}
void drawCell(float y){
float scalar = width * 0.5 / num; // セルの大きさ
float x = (width - state.length * scalar) * 0.5; // セルのx座標
y *= scalar;
noStroke();
for (int i = 0; i < state.length; i++){
fill(state[i] * 1.0 / mod, state[i] * 1.0 / mod, 1); //色相にセルの状態を割り当て
rect(x, y, scalar, scalar); // セルの描画
x += scalar; // x座標方向にセルをずらす
}
}
void updateState(){
int[] BOUNDARY = {0, 0};
int[] nextState = new int[state.length + 2]; // 次の世代の状態
state = splice(state, BOUNDARY, 0); // 配列の最初に境界値を加える
state = splice(state, BOUNDARY, state.length); // 配列の最後に境界値を加える
for (int i = 1; i < state.length - 1; i++){
nextState[i-1] = transition(state[i - 1], state[i], state[i + 1]); // 次世代のセルの状態の計算
}
state = nextState; // セルの状態を更新
gen++; //世代を1つ増やす
}
int transition(int a, int b, int c){
int d = a + b + c; //遷移ルールに従って計算
d = d % mod;
return d;
}
- 遷移ルールに確率的要素を入れる
int transition(int a, int b, int c){
int d;
if (random(1) < 0.999){
d = a + b + c; //99.9%の確率でこのルールを選択
} else {
d = a + c; //0.1%の確率でこのルールを選択
}
d = d % mod;
return d;
}
- マウスクリックするたびに、遷移ルールを変えて描画
int num = 250; //表示する世代数
int mod = 2; //法とする数
int[] state = {1}; //初期状態
int[] rule = {0, 0, 0, 1, 1, 1, 1, 0}; // rule 30 (0011110)
float gen = 0;
void setup(){
size(1000, 500);
colorMode(HSB, 1);
}
void draw(){
if (gen < num){
drawCell(gen);
updateState();
}
}
void mouseClicked(){
gen = 0;
state = new int[]{1}; //初期状態
rule = new int[8];
int ruleInt = 0;
for (int i = 0; i < 8; i++){
rule[i] = int(random(2));
ruleInt += rule[i] * int(pow(2, 7 - i));
}
println(ruleInt);
background(0, 0, 1);
}
void drawCell(float y){
float scalar = width * 0.5 / num; // セルの大きさ
float x = (width - state.length * scalar) * 0.5; // セルのx座標
y *= scalar;
noStroke();
for (int i = 0; i < state.length; i++){
fill(0, 0, 1 - state[i]); //色相にセルの状態を割り当て
rect(x, y, scalar, scalar); // セルの描画
x += scalar; // x座標方向にセルをずらす
}
}
//8個の01要素からなる配列ruleに対して,遷移ルールを決定する
int transition(int a, int b, int c){
int d;
//abcを10進数に置き換える
int ruleInt = int(a * pow(2, 2) + b * pow(2, 1) + c * pow(2, 0));
d = rule[7 - ruleInt];
return d;
}
void updateState(){
int[] BOUNDARY = {0, 0};
int[] nextState = new int[state.length + 2]; // 次の行の配列
state = splice(state, BOUNDARY, 0); // 配列stateの最初に{0,0}を加える
state = splice(state, BOUNDARY, state.length); // 配列stateの最後に{0,0}を加える
for (int i = 1; i < state.length - 1; i++){
nextState[i-1] = transition(state[i - 1], state[i], state[i + 1]); // 次世代のセルの状態の計算
}
state = nextState; // セルの状態を更新
gen++;
}
2次元セルオートマトン
- 正方格子
- 遷移ルールの例
- a
- b c d
- e
next c = a+b+c+d+e mod n
int num = 250; // 行と列の長さ
int mod = 4; // 法とする数
int[][] state = new int[num][num]; // セルの状態を表す行列
void setup(){
size(500, 500);
colorMode(HSB, 1);
initialize(); // 初期化する
frameRate(2); // 0.5秒ごとに遷移
}
void draw(){
drawCell();
updateState();
}
void initialize(){
for (int i = 0; i < num; i++){
for (int j = 0; j < num; j++){
if (i == num / 2 && j == num / 2){
state[i][j] = 1; // 真ん中の成分のみ1
} else {
state[i][j] = 0;
}
}
}
}
void updateState(){
int[][] nextState = new int[num][num]; // 次世代の状態
for (int i = 0; i < num; i++){
for (int j = 0; j < num; j++){
nextState[i][j] = transition(i, j); // 遷移
}
}
state = nextState; //更新
}
int transition(int i, int j){
int nextC;
nextC = state[(i - 1 + num) % num][j] //上のセル
+ state[i][(j - 1 + num) % num] //左のセル
+ state[i][j] //中央のセル
+ state[i][(j + 1) % num] //右のセル
+ state[(i + 1) % num][j]; //下のセル
nextC = nextC % mod;
return nextC;
}
void drawCell(){
float scalar = (float) height / num; // セルのサイズ
float y = 0; // セルのy座標
float x;
for (int i = 0; i < num; i++){
x = 0; // セルのx座標
for (int j = 0; j < num; j++){
noStroke();
fill(state[i][j] * 1.0 / mod, state[i][j] * 1.0 / mod, 1); // セルの色
rect(x, y, scalar, scalar);
x += scalar;
}
y += scalar;
}
}
ライフゲーム
- 遷移ルール
- セルの状態は、生(1)か死(0)か
- セルが1の場合
- 自分の周りに1が2個か3個の場合、1
- それ以外の場合、0
- セルが0の場合
- 自分の周りに1が3個の場合、1
- それ以外の場合、0
- 初期化
- ランダムに生と死を配置
- num = 50;
- mod = 1;
- frameRate(4);
void initialize(){
float r;
for (int i = 0; i < num; i++){
for (int j = 0; j < num; j++){
r = random(100);
if ( r > 85 ){
state[i][j] = 1;
} else {
state[i][j] = 0;
}
}
}
}
- 遷移ルール
int transition(int i, int j){
int aroundC;
int nextC = 0;
aroundC =
state[(i - 1 + num) % num][j] //上のセル
+ state[(i - 1 + num) % num][(j - 1 + num) % num] //上のセル
+ state[(i - 1 + num) % num][(j + 1) % num] //上のセル
+ state[i][(j - 1 + num) % num] //左のセル
+ state[i][(j + 1) % num] //右のセル
+ state[(i + 1) % num][(j - 1 + num) % num] //下のセル
+ state[(i + 1) % num][j] //下のセル
+ state[(i + 1) % num][(j + 1) % num]; //下のセル
if(state[i][j] == 1){
if(aroundC == 2 || aroundC == 3) {
nextC = 1;
}
else{
nextC = 0;
}
}
if(state[i][j] == 0){
if(aroundC == 3) {
nextC = 1;
}
else{
nextC = 0;
}
}
return nextC;
}
void drawCell(){
float scalar = (float) height / num; // セルのサイズ
float y = 0; // セルのy座標
float x;
for (int i = 0; i < num; i++){
x = 0; // セルのx座標
for (int j = 0; j < num; j++){
noStroke();
fill(state[i][j] * 1.0, state[i][j] * 1.0, 1); // セルの色
rect(x, y, scalar, scalar);
x += scalar;
}
y += scalar;
}
}
正六角形セルオートマトン
- 六角格子
ベクトルPVectorクラスを使った図形描画PShapeで六角格子を作る。
- beginShape()とendShape()の間にvertex()で頂点を並べて、図形を描く。vertexについて解説
- createShape()で図形を作成して、再利用する。
PVector[][] lattice;
PShape tile;
PVector[] base = new PVector[2]; //格子を張るベクトル
int num = 100; //描画する格子の行数
float scalar;
int[][] state = new int[num][num]; //セルの状態を表す行列
int mod = 10; //法とする数
void setup(){
size(600, 800);
colorMode(HSB, 1);
scalar = height * 1.0 / num; //ウィンドウと格子の行数から格子の大きさを決定
initialize(); // 初期状態
makeHexVector(); //六角格子を張るベクトルの生成
makeLattice(); //格子点ベクトルを生成
makeHex(); //正六角形タイルを生成
drawTiling(); //タイリングを描画
frameRate(2);
}
void draw(){
background(0, 0, 1);
int[][] nextState = new int[num][num]; //次世代の行列
for (int i = 0; i < num; i++){
for (int j = 0; j < num; j++){
nextState[i][j] = transition(i, j); //遷移
}
}
state = nextState; //状態を更新
drawTiling();
}
void initialize(){
for (int i = 0; i < num; i++){
for (int j = 0; j < num; j++){
if (i == num / 2 && j == num / 2){
state[i][j] = 1; // 中央の成分のみ1
} else {
state[i][j] = 0;
}
}
}
}
//六角格子を張るベクトルを作る。
//円周上の時計回りに90度(PI/2)と30度(PI/6)に点を取ってベクトルを作る。
void makeHexVector(){
base[0] = PVector.fromAngle(PI/2);
base[1] = PVector.fromAngle(PI/6);
}
//ウィンドウ内に収まるように格子点の配列latticeを定める。
//ウィンドウからはみ出た格子点は%(余り)演算でウィンドウ上部に戻す。
void makeLattice(){
lattice = new PVector[num][num];
for (int i = 0; i < num; i++){
for (int j = 0; j < num; j++){
PVector v = PVector.mult(base[0], i * scalar);
v.add(PVector.mult(base[1], j * scalar));
lattice[i][j] = new PVector(v.x, v.y % height);
}
}
}
//fromAngleで60度(PI/3)刻みで正6角形の格子を作る
//
void makeHex(){
tile = createShape();
tile.beginShape();
tile.noStroke();
for (int i = 0; i < 6; i++){
PVector v = PVector.fromAngle(2 * PI * i / 6);
v.mult(scalar / sqrt(3));
tile.vertex(v.x, v.y);
}
tile.endShape(CLOSE);
}
//makeHex関数で作った正6角形の格子に沿って配置する。
void drawTiling(){
for (int i = 0; i < num; i++){
for (int j = 0; j < num; j++){
tile.resetMatrix();
tile.translate(lattice[i][j].x, lattice[i][j].y); //タイルの位置を指定
setTileColor(tile, i, j);
shape(tile); //タイルを描画
}
}
}
void setTileColor(PShape t, int i, int j){
t.setFill(color(state[i][j] * 1.0 / mod, state[i][j] * 1.0 / mod, 1));
}
int transition(int i, int j){
int d;
d = state[i][j] //中央のセル
+ state[(i - 1 + num) % num][j] //上のセル
+ state[(i - 1 + num) % num][(j + 1) % num] //右上のセル
+ state[i][(j + 1) % num] //右下のセル
+ state[(i + 1) % num][j] //下のセル
+ state[(i + 1) % num][(j - 1 + num) % num] //左下のセル
+ state[i][(j - 1 + num) % num]; //左上のセル
d = d % mod;
return d;
}
セルオートマトン資料
- ライフゲームのWindowsソフト /
- Cellular Automata explorer
- Wolfram Math World Game of Life
- HashLife
- http://golly.sourceforge.net/
- セルオートマトン音楽
- WolframTones
- Life Game Orchestra : Doccument / YouTube
ワイヤワールド /