セルオートマトン
提供:kuhalaboWiki
目次 |
セルオートマトン
パスカルの三角形
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
ワイヤワールド /