Created
May 14, 2012 18:10
-
-
Save foota/2695432 to your computer and use it in GitHub Desktop.
Cellular Automaton
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // CellularAutomaton.as | |
| // by nox, 2010.7.9 | |
| // http://handasse.blogspot.com/ | |
| /* | |
| 1-9 : ルール設定 - セルの周りの生存セル数(0-8)に対応 | |
| : '.' 死亡, '&' 変化, '+' 誕生, '=' 維持 | |
| SPACE : 一時停止 | |
| ENTER : リセット | |
| V : メッセージ表示/非表示 | |
| Z : 初期生存セルの割合を減少 | |
| X : 初期生存セルの割合を増加 | |
| */ | |
| package { | |
| import flash.display.*; | |
| import flash.events.*; | |
| import flash.text.*; | |
| import flash.utils.*; | |
| import flash.geom.Point; | |
| [SWF (width="465", height="465", backgroundColor="0x000000", frameRate="60")] | |
| public class CellularAutomaton extends Sprite | |
| { | |
| private const R:int = 465, C:int = 465, C5:int = ((C-1) >> 5) + 1; | |
| private const RCinv:Number = 1.0 / (R * C); | |
| private const remainBits:int = ((~C + 1) & 0x1f) * R; | |
| // '.': death, '&': change, '+': birth, '=': survival | |
| private const ruleChar:Array = ['.', '&', '+', '='] | |
| private const log4inv:Number = 1.0 / Math.log(4.0); | |
| private const updateTime:uint = 500; | |
| private var bmpData:BitmapData = new BitmapData(R, C); | |
| private var cells:Array = new Array(R); | |
| private var modR:Array = new Array(R * 3); | |
| private var modC:Array = new Array(C * 3); | |
| // 0: death, 1: change, 2: birth, 3: survival | |
| private var rules:Array = [0, 0, 3, 2, 0, 0, 0, 0, 0]; // Conway's Game of Life | |
| private var rate:Number = 0.3; | |
| private var initRate:Number = rate; | |
| private var cnt:Array = new Array(R); | |
| private var ruleBits:Array = new Array(4); | |
| private var entropy:Number = 1.0; | |
| private var patterns:Array = [0, 0, 0, 0]; | |
| private var txtData:TextField = new TextField(); | |
| private var txtRules:TextField = new TextField(); | |
| private var fps:Number = 0.0; | |
| private var drawCount:uint = 0; | |
| private var prevTimer:uint = 0; | |
| private function bitcount(bits:uint):uint { | |
| bits = (bits & 0x55555555) + (bits >> 1 & 0x55555555); | |
| bits = (bits & 0x33333333) + (bits >> 2 & 0x33333333); | |
| bits = (bits & 0x0f0f0f0f) + (bits >> 4 & 0x0f0f0f0f); | |
| bits = (bits & 0x00ff00ff) + (bits >> 8 & 0x00ff00ff); | |
| return (bits & 0x0000ffff) + (bits >>16 & 0x0000ffff); | |
| } | |
| private function init():void { | |
| var i:int, j:int; | |
| for (i = 0; i < R; i++) for (j = 0; j < C5; j++) cells[i][j] = 0; | |
| for (i = 0; i < R; i++) for (j = 0; j < C; j++) | |
| if (Math.random() < initRate) cells[i][j>>5] |= 1 << (j&0x1f); | |
| } | |
| private function next():void { | |
| var i:int, j:int, x:int, y:int; | |
| for (i = 0; i < R; i++) for (j = 0; j < C; j++) cnt[i][j] = 0; | |
| for (x = 0; x < R; x++) for (y = 0; y < C; y++) | |
| if (cells[x][y>>5] & 1 << (y&0x1f)) | |
| for (i = -1; i <= 1; i++) for (j = -1; j <= 1; j++) | |
| if (i != 0 || j != 0) cnt[modR[x+i+R]][modC[y+j+C]]++; | |
| for (i = 0; i < 4; i++) patterns[i] = 0; | |
| for (x = 0; x < R; x++) { | |
| for (i = 0; i < 4; i++) for (j = 0; j < C5; j++) ruleBits[i][j] = 0; | |
| for (y = 0; y < C; y++) | |
| ruleBits[rules[cnt[x][y]]][y>>5] |= 1 << (y&0x1f); | |
| for (i = 0; i < C5; i++) { | |
| var cellBits:uint = cells[x][i]; | |
| cells[x][i] = cells[x][i] & ~ruleBits[0][i] ^ ruleBits[1][i] | ruleBits[2][i]; | |
| patterns[0] += bitcount(~cellBits & ~cells[x][i]); | |
| patterns[1] += bitcount(cellBits & ~cells[x][i]); | |
| patterns[2] += bitcount(~cellBits & cells[x][i]); | |
| patterns[3] += bitcount(cellBits & cells[x][i]); | |
| } | |
| } | |
| patterns[0] -= remainBits; | |
| entropy = 0.0; | |
| for (i = 0; i < 4; i++) { | |
| if (patterns[i] == 0) continue; | |
| var p:Number = patterns[i] * RCinv; | |
| entropy -= p * Math.log(p) * log4inv; | |
| } | |
| } | |
| private function countAlive():int { | |
| var cnt:int = 0; | |
| for (var x:int = 0; x < R; x++) | |
| for (var c:int = 0; c < C5; c++) | |
| cnt += bitcount(cells[x][c]); | |
| return cnt; | |
| } | |
| private function showData(cntAlive:uint):void { | |
| drawCount += 1; | |
| if (getTimer() - prevTimer >= updateTime) { | |
| fps = (drawCount * 1000 / (getTimer() - prevTimer) * 10 >> 0) / 10; | |
| prevTimer = getTimer(); | |
| drawCount = 0; | |
| } | |
| txtData.htmlText = "<span class='c'>FPS = " + fps + " / " + stage.frameRate | |
| + "\nN = " + cntAlive | |
| + "\nH = " + (entropy * 100000 >> 0) / 100000 + "</span>"; | |
| } | |
| private function showRules():void { | |
| var rule:String = ""; | |
| for (var i:int = 0; i < 9; i++) rule += ruleChar[rules[i]]; | |
| txtRules.htmlText = "<span class='c'>" + "[" + rule + "] " | |
| + initRate + " / " + (rate * 100000 >> 0) / 100000 + "</span>"; | |
| } | |
| private function onEnterFrame(event:Event):void { | |
| var cntAlive:uint = countAlive(); | |
| showData(cntAlive); | |
| showRules(); | |
| rate = cntAlive * RCinv; | |
| var color:uint = (rate * 0xff) << 16 | ((1.0 - rate) * 0xff) >> 0; | |
| var bgcolor:uint = (entropy * 0xff) << 8; | |
| bmpData.lock(); | |
| for (var i:int = 0; i < R; i++) { | |
| for (var j:int = 0; j < C; j++) { | |
| var bit:uint = cells[i][j>>5] >> (j&0x1f) & 1; | |
| bmpData.setPixel(i, j, bit * color + (bit ^ 1) * bgcolor); | |
| } | |
| } | |
| bmpData.unlock(); | |
| next(); | |
| } | |
| private function onKeyDown(event:KeyboardEvent):void{ | |
| if (49 <= event.keyCode && event.keyCode <= 57) { | |
| // '1'-'9' keys : set rules for number of neighbors (0-8) | |
| var idx:uint = event.keyCode - 49; | |
| rules[idx] = (rules[idx] + 1) & 0x3; | |
| } else { | |
| switch (event.keyCode) { | |
| case 32: // Space : pause | |
| if (stage.hasEventListener(Event.ENTER_FRAME)) | |
| stage.removeEventListener(Event.ENTER_FRAME, onEnterFrame); | |
| else | |
| stage.addEventListener(Event.ENTER_FRAME, onEnterFrame); | |
| break; | |
| case 86: // 'V' : show / hide messages | |
| if (stage.contains(txtData)) stage.removeChild(txtData); | |
| else stage.addChild(txtData); | |
| if (stage.contains(txtRules)) stage.removeChild(txtRules); | |
| else stage.addChild(txtRules); | |
| break; | |
| case 88: // 'X' : decrease initial rate of population | |
| initRate = (initRate * 10) >> 0; | |
| initRate = initRate + 1; | |
| initRate = (initRate > 10) ? 0.0 : initRate / 10; | |
| break; | |
| case 90: // 'Z' : increase initial rate of population | |
| initRate = (initRate * 10) >> 0; | |
| initRate = initRate - 1; | |
| initRate = (initRate < 0) ? 1.0 : initRate / 10; | |
| break; | |
| case 13: // Enter : reset | |
| init(); | |
| break; | |
| } | |
| } | |
| showRules(); | |
| }; | |
| public function CellularAutomaton() { | |
| stage.addChild(new Bitmap(bmpData)); | |
| stage.addChild(txtData); | |
| stage.addChild(txtRules); | |
| stage.addEventListener(Event.ENTER_FRAME, onEnterFrame); | |
| stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown); | |
| var i:int; | |
| for (i = 0; i < R * 3; i++) modR[i] = i % R; | |
| for (i = 0; i < C * 3; i++) modC[i] = i % C; | |
| for (i = 0; i < R; i++) { | |
| cells[i] = new Array(C5); | |
| cnt[i] = new Array(C); | |
| } | |
| for (i = 0; i < 4; i++) ruleBits[i] = new Array(C5); | |
| var styleSheet:StyleSheet = new StyleSheet(); | |
| styleSheet.setStyle(".c", {fontFamily:"_typewriter", fontSize:"16px", color:"#ffffff"}); | |
| txtData.styleSheet = txtRules.styleSheet = styleSheet; | |
| txtData.autoSize = txtRules.autoSize = TextFieldAutoSize.LEFT; | |
| txtData.y = 0; | |
| txtRules.y = stage.height - 24; | |
| prevTimer = getTimer(); | |
| init(); | |
| } | |
| } | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
http://handasse.blogspot.com/2010/07/2.html