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

Schelling Segregation Model

http://mindyourdecisions.com/blog/2008/10/28/game-theory-and-racism-the-schelling-segregation-model/#.U7-oqvl_skY
http://www.youtube.com/watch?v=dnffIS2EJ30
/**
 * Copyright greentec ( http://wonderfl.net/user/greentec )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/rtoK
 */

package {
    import com.bit101.components.InputText;
    import com.bit101.components.Label;
    import com.bit101.components.NumericStepper;
    import com.bit101.components.PushButton;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.geom.Rectangle;

    public class FlashTest extends Sprite {
        
        public var colors:Array = [0xea4b35, 0x1aaf5d, 0x217fbc, 0xf3c500, 0x8f3fb0]; //0x1aaf5d];
        
        public var mainBitmap:Bitmap;
        public var mainBitmapData:BitmapData;
        
        public var cells:Vector.<Vector.<int>>;
        
        public var tile_width:int = 8;
        public var tile_height:int = 8;
        public var tileNum_X:int = 58;
        public var tileNum_Y:int = 50;
        
        public var gridSprite:Sprite;
       
        public var PRNG_gen:PM_PRNG;
        public var seed:int = Math.random() * int.MAX_VALUE;
        
        public var eraseCellNum:int = 50;
        public var raceNum:int = 3;
        
        public var emptyArr:Array = [0, tileNum_X - 1, (tileNum_Y - 1) * tileNum_X, tileNum_X * tileNum_Y - 1];
        public var dir:Array = [[ -1, -1], [ -1, 0], [ -1, 1], [0, 1], [1, 1], [1, 0], [1, -1], [0, -1]];
        public var happyNeighborNum:Array = [0, 1, 1, 2, 2, 2, 3, 3, 3];
        public var escapeTryNum:int = 5;
        
        public var _randomSeedInputText:InputText;
        public var happyLabel:Label;

        public function FlashTest() {
            // write as3 code here..
            PRNG_gen = new PM_PRNG();
            PRNG_gen.seed = seed;
            
            mainBitmapData = new BitmapData(465, 465, false, 0x292929);
            mainBitmap = new Bitmap(mainBitmapData);
            addChild(mainBitmap);
            
            var i:int, j:int;

            gridSprite = new Sprite(); //draw Line
            gridSprite.graphics.lineStyle(0, 0x7f7f7f);
           
            for (i = 0; i < tileNum_X + 1; i += 1)
            {
                gridSprite.graphics.moveTo(i * tile_width, 0);
                gridSprite.graphics.lineTo(i * tile_width, tileNum_Y * tile_height);
            }
            for (i = 0; i < tileNum_Y + 1; i += 1)
            {
                gridSprite.graphics.moveTo(0, i * tile_height);
                gridSprite.graphics.lineTo(tileNum_X * tile_width, i * tile_height);
            }
            
            addChild(gridSprite);
            
            cells = new Vector.<Vector.<int>>(tileNum_Y);
            for (i = 0; i < tileNum_Y; i += 1)
            {
                cells[i] = new Vector.<int>(tileNum_X);
                
                for (j = 0; j < tileNum_X; j += 1)
                {
                    //cells[i][j] = (i % 2 == j % 2) ? 1 : 2;
                    cells[i][j] = int(PRNG_gen.nextDouble() * raceNum) + 1;
                }
            }
            
            for (i = 0; i < emptyArr.length; i += 1)
            {
                var tx:int = emptyArr[i] % tileNum_X;
                var ty:int = emptyArr[i] / tileNum_X;
                cells[ty][tx] = 0;
            }
            
            //cells[0][0] = 0;
            //cells[0][tileNum_X - 1] = 0;
            //cells[tileNum_Y - 1][0] = 0;
            //cells[tileNum_Y - 1][tileNum_X - 1] = 0;
            
            var _randomSeedLabel:Label = new Label(this, 10, tile_height * tileNum_Y + 10, "Random Seed");
            _randomSeedInputText = new InputText(this, _randomSeedLabel.x + _randomSeedLabel.width + 5, _randomSeedLabel.y, String(seed));
            _randomSeedInputText.restrict = "0-9";
            var _randomSeedButton:PushButton = new PushButton(this, _randomSeedInputText.x + _randomSeedInputText.width + 5, _randomSeedInputText.y, "Another Seed", 
                function(e:Event):void    
                {
                    _randomSeedInputText.text = String(int(Math.random() * int.MAX_VALUE));
                }
            );
            var _resetButton:PushButton = new PushButton(this, _randomSeedButton.x + _randomSeedButton.width + 5, _randomSeedButton.y, "Reset", onReset);
            
            var _eraseRandomCellButton:PushButton = new PushButton(this, _randomSeedLabel.x, _randomSeedLabel.y + _randomSeedLabel.height + 10, "Erase Cell", eraseRandomCells);
            var _segregateButton:PushButton = new PushButton(this, _eraseRandomCellButton.x + _eraseRandomCellButton.width + 5, _eraseRandomCellButton.y, "Do One Cycle", doSegregateOnce);
            happyLabel = new Label(this, _segregateButton.x + _segregateButton.width + 5, _segregateButton.y, "");
            var _raceLabel:Label = new Label(this, happyLabel.x + 80 + 10, happyLabel.y, "Race Num : ");
            var _raceNumNumericStepper:NumericStepper = new NumericStepper(this, _raceLabel.x + 50 + 5, _raceLabel.y, 
                function(e:Event):void
                {
                    raceNum = e.target.value;
                }
            );
            _raceNumNumericStepper.minimum = 2;
            _raceNumNumericStepper.maximum = 5;
            _raceNumNumericStepper.value = raceNum;
            
            drawCell(cells);
            calcHappyPercent(cells);
       }
       
       private function isHappy(i:int, j:int, color:int):Boolean
        {
            var neighborNum:int = 0;
            var sameNeighbor:int = 0;
            var k:int;
            var tx:int, ty:int;
            
            for (k = 0; k < dir.length; k += 1)
            {
                ty = i + dir[k][0];
                tx = j + dir[k][1];
                
                if (tx >= 0 &&
                    tx <= tileNum_X - 1 &&
                    ty >= 0 &&
                    ty <= tileNum_Y - 1)
                {
                    if (cells[ty][tx] != 0)
                    {
                        neighborNum += 1;
                        if (color == cells[ty][tx])
                        {
                            sameNeighbor += 1;
                        }
                    }
                }
            }
            
            if (happyNeighborNum[neighborNum] > sameNeighbor)
            {

                return false;
            }
            else
            {
                return true;
            }
         }
        
        private function doSegregateOnce(e:Event = null):void
        {
            var i:int, j:int;
            var temp:int;
            var k:int;
            var isMoved:Boolean;
            
            for (i = 0; i < tileNum_Y; i += 1)
            {
                for (j = 0; j < tileNum_X; j += 1)
                {
                    if (isHappy(i, j, cells[i][j]) == false)
                    {
                        isMoved = false;
                        for (k = 0; k < escapeTryNum; k += 1)
                        {
                            temp = emptyArr[int(PRNG_gen.nextDouble() * emptyArr.length)];
                            
                            if (isHappy(int(temp / tileNum_X), temp % tileNum_X, cells[i][j]) == true)
                            {
                                cells[int(temp / tileNum_X)][temp % tileNum_X] = cells[i][j];
                                cells[i][j] = 0;
                                
                                emptyArr.splice(temp, 1);
                                emptyArr.push(i * tileNum_X + j);
                                isMoved = true;
                                break;
                            }
                            
                        }
                        
                        if (isMoved == false)
                        {
                            cells[i][j] = 0; //dead
                        }
                    }
                    
                }
            }
            
            drawCell(cells);
            calcHappyPercent(cells);
        }
        
        private function calcHappyPercent(cells:Vector.<Vector.<int>>):void
        {
            var happyNum:int = 0;
            var allNum:int = 0;
            var i:int, j:int;
            
            for (i = 0; i < tileNum_Y; i += 1)
            {
                for (j = 0; j < tileNum_X; j += 1)
                {
                    if (cells[i][j] > 0)
                    {
                        allNum += 1;
                        if (isHappy(i, j, cells[i][j]) == true)
                        {
                            happyNum += 1;
                        }
                    }
                }
            }
            
            
            happyLabel.text = "Happy : " + String(int(happyNum / allNum * 10000) / 100) + "%";
        }
        
        private function onReset(e:Event = null):void
        {
            var i:int, j:int;
            
            PRNG_gen.seed = parseInt(_randomSeedInputText.text);
            emptyArr = [0, tileNum_X - 1, (tileNum_Y - 1) * tileNum_X, tileNum_X * tileNum_Y - 1];
            
            cells = new Vector.<Vector.<int>>(tileNum_Y);
            for (i = 0; i < tileNum_Y; i += 1)
            {
                cells[i] = new Vector.<int>(tileNum_X);
                
                for (j = 0; j < tileNum_X; j += 1)
                {
                    //cells[i][j] = (i % 2 == j % 2) ? 1 : 2;
                    cells[i][j] = int(PRNG_gen.nextDouble() * raceNum) + 1;
                }
            }
            
            for (i = 0; i < emptyArr.length; i += 1)
            {
                var tx:int = emptyArr[i] % tileNum_X;
                var ty:int = emptyArr[i] / tileNum_X;
                cells[ty][tx] = 0;
            }
            
            drawCell(cells);
            calcHappyPercent(cells);
        }
       
        private function eraseRandomCells(e:Event = null):void
        {
            var i:int;
            emptyArr = emptyArr.concat(printRandomNumber(tileNum_X * tileNum_Y, eraseCellNum));
            var tempX:int, tempY:int;
            
            for (i = 0; i < emptyArr.length; i += 1)
            {
                tempX = emptyArr[i] % tileNum_X;
                tempY = emptyArr[i] / tileNum_X;
                
                cells[tempY][tempX] = 0;
            }
            
            drawCell(cells);
            calcHappyPercent(cells);

           
            //trace(emptyArr);
        }
        
        private function printRandomNumber(n:int, k:int) : Array
        {
            var original:Array=[];
            var result:Array=[];
            var i:int;
            var randInt:int;
            var temp:Object;
            
            for(i=0;i<n;i+=1)
            {
                original.push(i);
            }
            
            for(i=0;i<k;i+=1)
            {
                randInt = PRNG_gen.nextDouble() * (n - i) + i;
                temp = original[i];
                original[i] = original[randInt];
                original[randInt] = temp;
                result.push(original[i]);
            }
            
            return result;
        }
        
        private function drawCell(cells:Vector.<Vector.<int>>):void
        {
            mainBitmapData.fillRect(mainBitmapData.rect, 0x292929);
            
            var i:int, j:int;
           
            for (i = 0; i < tileNum_Y; i += 1)
            {
                for (j = 0; j < tileNum_X; j += 1)
                {
                    mainBitmapData.fillRect(new Rectangle(j * tile_width +1, i * tile_height + 1, tile_width - 2, tile_height - 2), colors[cells[i][j] - 1]);
                }
            }
        }
    }
}

/*
 * Copyright (c) 2009 Michael Baczynski, http://www.polygonal.de
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/**
 * Implementation of the Park Miller (1988) "minimal standard" linear 
 * congruential pseudo-random number generator.
 * 
 * For a full explanation visit: http://www.firstpr.com.au/dsp/rand31/
 * 
 * The generator uses a modulus constant (m) of 2^31 - 1 which is a
 * Mersenne Prime number and a full-period-multiplier of 16807.
 * Output is a 31 bit unsigned integer. The range of values output is
 * 1 to 2,147,483,646 (2^31-1) and the seed must be in this range too.
 * 
 * David G. Carta's optimisation which needs only 32 bit integer math,
 * and no division is actually *slower* in flash (both AS2 & AS3) so
 * it's better to use the double-precision floating point version.
 * 
 * @author Michael Baczynski, www.polygonal.de
 */
Class
{
    class PM_PRNG
    {
        /**
         * set seed with a 31 bit unsigned integer
         * between 1 and 0X7FFFFFFE inclusive. don't use 0!
         */
        public var seed:uint;
        
        public function PM_PRNG()
        {
            seed = 1;
        }

       
        /**
         * provides the next pseudorandom number
         * as an unsigned integer (31 bits)
         */
        public function nextInt():uint
        {
            return gen();
        }
        
        /**
         * provides the next pseudorandom number
         * as a float between nearly 0 and nearly 1.0.
         */
        public function nextDouble():Number
        {
           return (gen() / 2147483647);
        }
       
        /**
         * provides the next pseudorandom number
         * as an unsigned integer (31 bits) betweeen
         * a given range.
         */
        public function nextIntRange(min:Number, max:Number):uint
        {
            min -= .4999;
            max += .4999;
            return Math.round(min + ((max - min) * nextDouble()));
        }
        
        /**
         * provides the next pseudorandom number
         * as a float between a given range.
         */
        public function nextDoubleRange(min:Number, max:Number):Number
        {
            return min + ((max - min) * nextDouble());
        }

       

       /**
         * generator:
         * new-value = (old-value * 16807) mod (2^31 - 1)
         */
        private function gen():uint
        {
            //integer version 1, for max int 2^46 - 1 or larger.
            return seed = (seed * 16807) % 2147483647;
            

           /**
            * integer version 2, for max int 2^31 - 1 (slowest)
            */
           //var test:int = 16807 * (seed % 127773 >> 0) - 2836 * (seed / 127773 >> 0);
           //return seed = (test > 0 ? test : test + 2147483647);
           
           /**
             * david g. carta's optimisation is 15% slower than integer version 1
             */
            //var hi:uint = 16807 * (seed >> 16);
            //var lo:uint = 16807 * (seed & 0xFFFF) + ((hi & 0x7FFF) << 16) + (hi >> 15);
            //return seed = (lo > 0x7FFFFFFF ? lo - 0x7FFFFFFF : lo);
        }
    }
}