In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

ProceduralAutomaton

ProceduralAutomaton
Procedural generated cellular automaton.
<Operation>
[N]       : Generate a next automaton.
Mouse Drag: Place R/G/B cell.
[R][G][B] : Change type of placed cell.
[C]       : Reset a field with the same rule.
/**
 * Copyright ABA ( http://wonderfl.net/user/ABA )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/s8ma
 */

// ProceduralAutomaton
//  Procedural generated cellular automaton.
//  <Operation>
//   [N]       : Generate a next automaton.
//   Mouse Drag: Place R/G/B cell.
//   [R][G][B] : Change type of placed cell.
//   [C]       : Reset a field with the same rule.
package {
    import flash.display.Sprite;
    [SWF(width="465", height="465", backgroundColor="0", frameRate="30")]
    public class Main extends Sprite {
        public function Main() { main = this; initializeFirst(); }
    }
}
// Initializer.
var seedText:TextField, messageText:TextField;
function initialize():void {
    seedText = createTextField(0, 0, 15, 300, 20, 0xffffff);
    messageText = createTextField(0, 445, 15, 300, 20, 0xffffff);
    messageText.text = "Push [N] key to generate a next automaton.";
    main.addChild(seedText); main.addChild(messageText);
    setRandomSeed((new Date).getTime());
    createNewAutomaton();
}
function createNewAutomaton():void {
    var i:int;
    do {
        automaton = new Automaton;
        automaton.initialize();
        field = new Field;
        for (i = 0; i < 32; i++) {
            field.update();
            if (!field.isChanged || !field.isChangedFromPrevPrev) break;
        }
    } while (i < 32);
    automaton.removeUnusedRules();
    field = new Field;
    ticks = 0;
    seedText.text = "Rule #" + automaton.seed;
}
// Update a field.
var ticks:int;
var placedType:int = Field.FIRE;
function update():void {
    if (ticks++ % 10 == 0) field.update();
    if (keys[82]) { keys[82] = false; placedType = Field.FIRE; }
    if (keys[71]) { keys[71] = false; placedType = Field.TREE; }
    if (keys[66]) { keys[66] = false; placedType = Field.WATER; }
    var cx:int = main.stage.mouseX / Field.CELL_PIXEL;
    var cy:int = main.stage.mouseY / Field.CELL_PIXEL;
    if (cx < 0) cx = 0; else if (cx >= Field.SIZE) cx = Field.SIZE - 1;
    if (cy < 0) cy = 0; else if (cy >= Field.SIZE) cy = Field.SIZE - 1;
    if (isMousePressed) field.cells[cx + cy * Field.SIZE] = placedType;
    if (keys[67]) { keys[67] = false; field = new Field; ticks = 0; }
    if (keys[78]) {    keys[78] = false; createNewAutomaton(); }
    field.draw();
    field.drawCell(cx, cy, placedType);
    automaton.drawRules();
}
// Field consists of cells.
var field:Field;
class Field {
    public static const BLANK:int = 0, FIRE:int = 1, TREE:int = 2, WATER:int = 3;
    public static const SIZE:int = 31, CELL_PIXEL:int = SCREEN_WIDTH / SIZE;
    public var cells:Vector.<int> = new Vector.<int>(SIZE * SIZE);
    private var rect:Rectangle = new Rectangle(0, 0, CELL_PIXEL - 1, CELL_PIXEL - 1);
    private var cellsPrev:Vector.<int> = new Vector.<int>(SIZE * SIZE);
    private var cellsPrevPrev:Vector.<int> = new Vector.<int>(SIZE * SIZE);
    private var colors:Array = [[100, 100, 50], [250, 0, 0], [50, 250, 50], [50, 50, 250]];
    public function Field() {
        for (var i:int = 0; i < SIZE; i++) {
            cells[randi(SIZE) + randi(SIZE) * SIZE] = randi(automaton.typeCount - 1) + 1;
        }
    }
    public function update():void {
        for (var i:int = 0; i < SIZE * SIZE; i++) {
            cellsPrevPrev[i] = cellsPrev[i];
            cellsPrev[i] = cells[i];
        }
        for (var x:int = 0; x < SIZE; x++) for (var y:int = 0; y < SIZE; y++) automaton.updateCell(x, y);
    }
    public function get isChanged():Boolean {
        for (var i:int = 0; i < SIZE * SIZE; i++) if (cellsPrev[i] != cells[i]) return true;
        return false;
    }
    public function get isChangedFromPrevPrev():Boolean {
        for (var i:int = 0; i < SIZE * SIZE; i++) if (cellsPrevPrev[i] != cells[i]) return true;
        return false;
    }
    public function draw():void {
        for (var x:int = 0; x < SIZE; x++) for (var y:int = 0; y < SIZE; y++) drawCell(x, y, cells[x + y * SIZE]);
    }
    public function drawCell(x:int, y:int, c:int):void {
        rect.x = x * CELL_PIXEL;
        rect.y = y * CELL_PIXEL;
        bd.fillRect(rect, getColor(c));
    }
    public function getColor(c:int):int {
        return colors[c][0] * 0x10000 + colors[c][1] * 0x100 + colors[c][2];
    }
    public function set(x:int, y:int, c:int):void {
        cells[x + y * SIZE] = c;
    }
    public function get(x:int, y:int):int {
        return cells[x + y * SIZE];
    }
    public function checkAround(cx:int, cy:int, p:int):int {
        var c:int;
        for (var ox:int = -1; ox <= 1; ox++) for (var oy:int = -1; oy <= 1; oy++) {
            if (ox == 0 && oy == 0) continue;
            var x:int = cx + ox, y:int = cy + oy;
            if (x < 0 || x >= SIZE || y < 0 || y >= SIZE) continue;
            if (cellsPrev[x + y * SIZE] == p) c++;
        }
        return c;
    }
}
// Generated automaton.
var automaton:Automaton;
class Automaton {
    public var seed:int;
    public var typeCount:int;
    public var rules:Vector.<Rule> = new Vector.<Rule>;
    public function Automaton() {
        seed = randn(int.MAX_VALUE);
        setRandomSeed(seed);
        typeCount = randi(3) + 2;
    }
    public function initialize():void {
        var types:Vector.<int> = new Vector.<int>;
        var i:int;
        for (i = 0; i < typeCount; i++) types.push(i);
        for (i = 0; i < typeCount; i++) {
            var t:int = randi(types.length);
            rules.push(new Rule(types[t]));
            types.splice(t, 1);
        }
        var rc:int = randi(3);
        for (i = 0; i < rc; i++) rules.push(new Rule(randi(typeCount)));
    }
    public function removeUnusedRules():void {
        for (var i:int = 0; i < rules.length; i++) if (!rules[i].isUsed) { rules.splice(i, 1); i--; }
    }
    public function updateCell(x:int, y:int):void {
        for (var i:int = rules.length - 1; i >= 0; i--) rules[i].updateCell(x, y);
    }
    public function drawRules():void {
        var y:int = 20;
        for each (var r:Rule in rules) {
            r.draw(10, y); y += Rule.CELL_PIXEL * 4;
        }
    }
}
// Rule for changing a cell.
class Rule {
    public static const CELL_PIXEL:int = Field.CELL_PIXEL * 0.7;
    public var centerType:int, aroundType:int, nextType:int;
    public var minAroundCount:int, maxAroundCount:int;
    public var isUsed:Boolean;
    private var rect:Rectangle = new Rectangle(0, 0, CELL_PIXEL - 1,  CELL_PIXEL - 1);
    private var rectInner:Rectangle = new Rectangle(0, 0, CELL_PIXEL - 3,  CELL_PIXEL - 3);
    private var rectBox:Rectangle = new Rectangle(0, 0, CELL_PIXEL * 3 + 1,  CELL_PIXEL * 3 + 1);
    private var rectArrow:Rectangle = new Rectangle(0, 0, CELL_PIXEL * 0.5 - 1,  CELL_PIXEL * 0.5 - 1);
    public function Rule(centerType:int) {
        this.centerType = centerType;
        aroundType = randi(automaton.typeCount);
        nextType = randi(automaton.typeCount);
        if (nextType == centerType) {
            nextType++; if (nextType >= automaton.typeCount) nextType = 0;
        }
        minAroundCount = randi(8) + 1;
        maxAroundCount = minAroundCount + randi(9 - minAroundCount);
    }
    public function updateCell(x:int, y:int):void {
        if (field.get(x, y) != centerType) return;
        var c:int = field.checkAround(x, y, aroundType);
        if (c >= minAroundCount && c <= maxAroundCount) {
            field.set(x, y, nextType);
            isUsed = true;
        }
    }
    public function draw(x:int, y:int):void {
        drawCells(x, y, centerType);
        drawArrow(x + CELL_PIXEL * 3.5, y);
        drawCells(x + CELL_PIXEL * 6, y, nextType);
    }
    private const offsets:Array = [0, 0, 1, 0, 2, 0, 0, 1, 2, 1, 0, 2, 1, 2, 2, 2];
    private function drawCells(x:int, y:int, c:int):void {
        rectBox.x = x - 1; rectBox.y = y - 1;
        bd.fillRect(rectBox, 0);
        rect.x = x + CELL_PIXEL; rect.y = y + CELL_PIXEL;
        bd.fillRect(rect, field.getColor(c));
        for (var i:int = 0; i < maxAroundCount; i++) {
            rect.x = x + offsets[i * 2] * CELL_PIXEL;
            rect.y = y + offsets[i * 2 + 1] * CELL_PIXEL;
            bd.fillRect(rect, field.getColor(aroundType));
            if (i < minAroundCount - 1) {
                rectInner.x = rect.x + 1;
                rectInner.y = rect.y + 1;
                bd.fillRect(rectInner, 0);
            }
        }
    }
    private const arrowColor:int = 0xffffff;
    private function drawArrow(x:int, y:int):void {
        for (var i:int = 0; i < 4; i++) {
            rectArrow.x = x + i * CELL_PIXEL * 0.5; rectArrow.y = y + CELL_PIXEL * 1.3;
            bd.fillRect(rectArrow, arrowColor);
            if (i == 2) {
                rectArrow.y = y + CELL_PIXEL * 0.75; bd.fillRect(rectArrow, arrowColor);
                rectArrow.y = y + CELL_PIXEL * 1.75; bd.fillRect(rectArrow, arrowColor);
            } else if (i == 1) {
                rectArrow.y = y + CELL_PIXEL * 0.4; bd.fillRect(rectArrow, arrowColor);
                rectArrow.y = y + CELL_PIXEL * 2.25; bd.fillRect(rectArrow, arrowColor);
            }
        }
    }
}
import flash.display.*;
import flash.geom.*;
import flash.events.*;
import flash.text.*;
const SCREEN_WIDTH:int = 465, SCREEN_HEIGHT:int = 465;
var main:Main, bd:BitmapData;
var isMousePressed:Boolean, keys:Vector.<Boolean> = new Vector.<Boolean>(256);
// Initialize a bitmapdata and events.
function initializeFirst():void {
    bd = new BitmapData(SCREEN_WIDTH, SCREEN_HEIGHT, false);
    bd.fillRect(bd.rect, 0);
    main.addChild(new Bitmap(bd));
    main.stage.addEventListener(MouseEvent.MOUSE_DOWN, function (e:Event):void { isMousePressed = true; });
    main.stage.addEventListener(MouseEvent.MOUSE_UP, function (e:Event):void { isMousePressed = false; });
    main.stage.addEventListener(KeyboardEvent.KEY_DOWN, function(e:KeyboardEvent):void { keys[e.keyCode] = true; } );
    initialize();
    main.addEventListener(Event.ENTER_FRAME, updateFrame);
}
// Update the frame.
function updateFrame(event:Event):void {
    bd.lock();
    bd.fillRect(bd.rect, 0);
    update();
    bd.unlock();
}
// Utility functions.
function createTextField(x:int, y:int, size:int, width:int, height:int, color:int):TextField {
    var fm:TextFormat = new TextFormat, fi:TextField = new TextField;
    fm.size = size; fm.color = color; fm.leftMargin = 0;
    fi.defaultTextFormat = fm; fi.x = x; fi.y = y; fi.width = width; fi.height = height; fi.selectable = false;
    return fi;
}
function randi(n:int):int {
    return random() * n;
}
function randn(n:int):Number {
    return random() * n;
}
var xorShiftX:int = 123456789, xorShiftY:int = 362436069, xorShiftZ:int = 521288629, xorShiftW:int = 88675123;
function setRandomSeed(v:int):void {
    var sv:int = v;
    xorShiftX = sv = 1812433253 * (sv ^ (sv >> 30));
    xorShiftY = sv = 1812433253 * (sv ^ (sv >> 30)) + 1;
    xorShiftZ = sv = 1812433253 * (sv ^ (sv >> 30)) + 2;
    xorShiftW = sv = 1812433253 * (sv ^ (sv >> 30)) + 3;
}
function random():Number {
    var t:int = xorShiftX ^ (xorShiftX << 11);
    xorShiftX = xorShiftY; xorShiftY = xorShiftZ; xorShiftZ = xorShiftW;
    xorShiftW = (xorShiftW ^ (xorShiftW >> 19)) ^ (t ^ (t >> 8));
    return Number(xorShiftW) / int.MAX_VALUE;
}