ProcessingでLangtonのループを作ってみた
追加
ルールの引用元を記載した。(2012年4月18日)
目的
Processingというグラフィックに特化したプログラム言語で、Langtonのループを動かしてみた。
Langtonのループって
Christopher Langtonが考案したセルオートマトンによる自己複製のモデルである。
一つのセルに0-7の状態があり、この(中央にある)セルの状態とこの上下左右のセルの状態からルールを適用することによってこの中央のセルの値が変わる。
これを繰り返すことでループを増殖していく。
仕様
- 任意のキーでポーズ
- ルールが適用できなかったら初期状態にして動かす
- 状態の色
- 0: ■
- 1: □
- 2: ■
- 3: ■
- 4: ■
- 5: ■
- 6: ■
- 7: ■
- ルールはruletablerepositoryのLangtons-Loops.tableを使いました。
コードの構成
- void initCellSpace(): セルを初期化する。
- boolean nextState(): 次のセルを更新する。ここでルールの適用を行う。ルールが適用できたらtrue、そうでなければ(ルールを全部探索したら)falseを返す。
ソースコード
int rectSize = 5; int[][] space; int[][] nextSpace; ArrayList rules; boolean running = true; int count = 0; // Init state int[][] langLoop = { {0,2,2,2,2,2,2,2,2,0,0,0,0,0,0}, {2,1,7,0,1,4,0,1,4,2,0,0,0,0,0}, {2,0,2,2,2,2,2,2,0,2,0,0,0,0,0}, {2,7,2,0,0,0,0,2,1,2,0,0,0,0,0}, {2,1,2,0,0,0,0,2,1,2,0,0,0,0,0}, {2,0,2,0,0,0,0,2,1,2,0,0,0,0,0}, {2,7,2,0,0,0,0,2,1,2,0,0,0,0,0}, {2,1,2,2,2,2,2,2,1,2,2,2,2,2,0}, {2,0,7,1,0,7,1,0,7,1,1,1,1,1,2}, {0,2,2,2,2,2,2,2,2,2,2,2,2,2,0} }; void setup() { size(800, 800); colorMode(RGB, 100); int sizeX = width/rectSize; // Number of rect for x and y axis int sizeY = height/rectSize; println("X = " + sizeX); println("Y = " + sizeY); space = new int[sizeY][sizeX]; nextSpace = new int[sizeY][sizeX]; rules = new ArrayList(); // init space initCellSpace(); // load rules from a file "Langtons-Loops.table" // and add loaded rule to list BufferedReader br = createReader("Langtons-Loops.table"); String l; try { while((l = br.readLine()) != null) { // like 00000, load numeric format if(Character.isDigit(l.charAt(0))) rules.add(l); } } catch (IOException e) { e.printStackTrace(); } println("Loaded " + rules.size() + " rules."); frameRate(120); } void draw() { if(running) { if(nextState()) { //println(count); for(int i=0; i<space.length; i++) { for(int j=0; j<space[i].length; j++) { fill(stateToColor(space[i][j])); rect(j*rectSize, i*rectSize, rectSize, rectSize); } } count++; } else { initCellSpace(); count = 0; } } } // stop or run void keyPressed() { if (running) { println("Stop!"); } else { println("Play!"); } running = !running; } void initCellSpace() { for(int i=0; i<space.length; i++) { for(int j=0; j<space[i].length; j++) { space[i][j] = 0; } } // put init state on 'space' at center int offsetX = space.length/2; int offsetY = space[0].length/2; for(int i=0; i<langLoop.length; i++) { for(int j=0; j<langLoop[i].length; j++) { space[offsetY-langLoop.length/2+i][offsetX-langLoop.length/2+j] = langLoop[i][j]; } } } color stateToColor(int state) { color cl = 0; switch(state) { case 0: cl = color(0,0,0); break; case 1: cl = color(100,100,100); break; case 2: cl = color(50,50,50); break; case 3: cl = color(0,100,0); break; case 4: cl = color(0,50,50); break; case 5: cl = color(0,0,100); break; case 6: cl = color(50,0,50); break; case 7: cl = color(100,100,100); break; } return cl; } // n_states:8(0-7) // neighborhood:vonNeumann (Center, North, East, South, West) // symmetries:rotate4 boolean nextState() { for(int i=0; i<space.length; i++) { for(int j=0; j<space[i].length; j++) { // 読み込み int vN[] = new int[5]; int next = space[i][j]; vN[0] = space[i][j]; // Center vN[1] = (i == 0) ? space[space.length-1][j] : space[i-1][j]; // North 1 -> 2 -> 3 -> 4 vN[2] = (j == space[i].length-1) ? space[i][0] : space[i][j+1]; // East 2 -> 3 -> 4 -> 1 vN[3] = (i == space.length-1) ? space[0][j] : space[i+1][j]; // South 3 -> 4 -> 1 -> 2 vN[4] = (j == 0) ? space[i][space.length-1] : space[i][j-1]; // Weat 4 -> 1 -> 2 -> 3 // 比較・回転 String rule; int k; for(k=0; k<rules.size(); k++) { rule = (String)rules.get(k); // XXX: 片っ端から比較または回転する if (vN[0] == rule.charAt(0)-'0' && vN[1] == rule.charAt(1)-'0' && vN[2] == rule.charAt(2)-'0' && vN[3] == rule.charAt(3)-'0' && vN[4] == rule.charAt(4)-'0') { next = rule.charAt(5)-'0'; break; } else if (vN[0] == rule.charAt(0)-'0' && vN[1] == rule.charAt(2)-'0' && vN[2] == rule.charAt(3)-'0' && vN[3] == rule.charAt(4)-'0' && vN[4] == rule.charAt(1)-'0') { next = rule.charAt(5)-'0'; break; } else if (vN[0] == rule.charAt(0)-'0' && vN[1] == rule.charAt(3)-'0' && vN[2] == rule.charAt(4)-'0' && vN[3] == rule.charAt(1)-'0' && vN[4] == rule.charAt(2)-'0') { next = rule.charAt(5)-'0'; break; } else if (vN[0] == rule.charAt(0)-'0' && vN[1] == rule.charAt(4)-'0' && vN[2] == rule.charAt(1)-'0' && vN[3] == rule.charAt(2)-'0' && vN[4] == rule.charAt(3)-'0') { next = rule.charAt(5)-'0'; break; } } if(k == rules.size()) { return false; } else { nextSpace[i][j] = next; } } } // 全更新 for(int i=0; i<space.length; i++) { for(int j=0; j<space[i].length; j++) { space[i][j] = nextSpace[i][j]; } } return true; }
実行結果
参考文献
詳しくはこれらを読んでちょ
ラングトンの自己複製オートマトン - 人工知能に関する断創録
SELF-REPRODUCTION IN CELLULAR AUTOMATA