セルオートマトン

提供:kuhalaboWiki
(版間での差分)
移動: 案内, 検索
(2次元セルオートマトン)
(2次元セルオートマトン)
293行: 293行:
 
*  e
 
*  e
 
<table border=1>
 
<table border=1>
<tr><td> </td><td>A</td><td> </td></tr>
+
<tr><td> </td><td>a</td><td> </td></tr>
<tr><td>B</td><td>C</td><td>D</td></tr>
+
<tr><td>b</td><td>c</td><td>d</td></tr>
<tr><td> </td><td>E</td><td> </td></tr>
+
<tr><td> </td><td>e</td><td> </td></tr>
 
</table>
 
</table>
  

2021年10月22日 (金) 00:30時点における版

Wikipedia

目次

パスカルの三角形

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

基本セルオートマトン(Elementary Cellular Automaton)

  • 隣接する3つのセルで次の状態が決まる。
  • セルの状態は、0,1
    1. 000 -> 0 or 1
    2. 001 -> 0 or 1
    3. 010 -> 0 or 1
    4. 011 -> 0 or 1
    5. 100 -> 0 or 1
    6. 101 -> 0 or 1
    7. 110 -> 0 or 1
    8. 111 -> 0 or 1
  • 0 or 1 が8通りあるので、合計 2の8乗=256通りのルールがある。
  • Wolframは256通りのルールをすべて調べた。

基本セルオートマトンのソース例

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桁目のみ残す)
  1. 000 -> 0
  2. 001 -> 1
  3. 010 -> 1
  4. 011 -> 0
  5. 100 -> 1
  6. 101 -> 0
  7. 110 -> 0
  8. 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
 a 
bcd
 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で六角格子を作る。

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;
}

セルオートマトン資料

セルオートマトン音楽

ワイヤワールド /

人工生命

ラングトンのアリ

レイノルズのボイド

反応拡散系

フラクタル

参考

スケーラブルアート論

個人用ツール
名前空間

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