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

forked from: Zoomed Labyrinth

トレモー法で迷路探索
Get Adobe Flash player
by fukt 19 Feb 2013
/**
 * Copyright fukt ( http://wonderfl.net/user/fukt )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/r1Zv
 */

// forked from peko's Zoomed Labyrinth
// forked from kenbu's 迷路探索 トレモー法
/**
    トレモー法で迷路探索
*/


package {
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Graphics;
    import flash.display.PixelSnapping;
    import flash.display.Sprite;
    import flash.display.StageAlign;
    import flash.display.StageScaleMode;
    import flash.events.Event;
    import flash.filters.DisplacementMapFilter;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    

    [SWF(width="465", height="465")]
    public class Labirinth extends Sprite
    {
        
        private var maze:Maze;
        private var searchMaze:TremauxSearch;
        private var bitmap:Bitmap;
        

        private const WIDTH:Number = 231;
        private const HEIGHT:Number = 231;
        private const SCALE:Number = 2;
        
        private var cursor:Sprite;
        
        private var zoomSpr:Sprite = new Sprite;
        private var zoomBmd:BitmapData = new BitmapData(256,256,false,0x808080);
        private var zoomBmp:Bitmap = new Bitmap(zoomBmd, PixelSnapping.NEVER, true);
        
        public function Labirinth() {
        
            stage.frameRate = 60;
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;
            
            var progressArray:Array = [];
            maze = new DigMaze(WIDTH,HEIGHT,progressArray);
        

            searchMaze = new TremauxSearch(maze, new Point(1,1), new Point(1, HEIGHT-2), new Array());
        
        
            var bitmapData:BitmapData = new BitmapData(WIDTH*SCALE, HEIGHT*SCALE);
            bitmap = new Bitmap(bitmapData);
            addChild(bitmap);
                
            cursor = new Sprite();
            addChild(cursor);
            var g:Graphics = cursor.graphics;
            g.beginFill(0x5500ff00ff);
            g.drawRect(0,0,SCALE,SCALE);
            g.endFill();
        
            //地図を描画
            drawMaze();
        
        
            this.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
            
            zoomBmp.x = -zoomBmp.height>>1;
            zoomBmp.y = -zoomBmp.width >>1;
            zoomSpr.addChild(zoomBmp);
            zoomSpr.alpha = 0.1;
            //addChild(zoomSpr);
            
            for (var yy:uint=0; yy<zoomBmd.height; yy++) {
                for (var xx:uint=0; xx<zoomBmd.width; xx++) {
                    var dx:Number = xx-128;
                    var dy:Number = yy-128;
                    var rr:Number = Math.sqrt(dx*dx+dy*dy);
                    
                    if(rr<127) { 
                        var R:uint = 128-(128-rr)/128*dx;
                        var G:uint = 128-(128-rr)/128*dy;
                        var B:uint = 128;
                        zoomBmd.setPixel(xx, yy,(R<<16) + (G<<8) + (B<<0));
                    }
                    
                }
            }
            
        }
        
        

        private var cnt:int = 0;
        private function enterFrameHandler(event:Event):void
        {
            var l:int = 1;
            for(var i:int = 0; i<l; i++) {
                drawSearch();
            }
            zoomSpr.x += (cursor.x-zoomSpr.x)/5;
            zoomSpr.y += (cursor.y-zoomSpr.y)/5;
            filters = [new DisplacementMapFilter(zoomBmd, new Point(zoomSpr.x-(zoomBmd.width>>1), zoomSpr.y-(zoomBmd.height>>1)),1, 2, 256, 256)]
            
            if(cnt == maze.buildProgressArray.length)
            {
                this.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
            }
        }
        
        private function drawSearch():void
        {
            if(cnt == searchMaze.buildProgressArray.length)
            {
                return;
            }
            
            var point:MazePoint = searchMaze.buildProgressArray[cnt];
            var color:Number;
            if(point.value == 2)
            {
                //一回通った
                color = 0x55c0c0c0;
            }
            else
            {
                //2回通った。
                color = 0xff0000ff;
            }
            var scale:Number = 9;
            
            var bitmapData:BitmapData = bitmap.bitmapData;
            
            rect.x = point.x * SCALE;
            rect.y = point.y * SCALE;
            rect.width = SCALE;
            rect.height = SCALE;
            
            
            bitmapData.fillRect(rect, color);

            cursor.x = point.x * SCALE;
            cursor.y = point.y * SCALE;

            
            cnt++;
        
        }
        
        
        private var rect:Rectangle = new Rectangle(0,0,0,0);
        
        private function drawMaze():void
        {
            var bitmapData:BitmapData = bitmap.bitmapData;

            maze.data.forEach(function(p:uint, i:int, arr:Array):void{
            
                var x:int = i%maze.width;
                var y:int = int(i/maze.height);
            
                
            
                var color:Number;
                if(p == 0)
                {
                    color = 0xffffffff;
                }
                else
                {
                    color = 0xff000000;
                }
                var scale:Number = 3;
                
                
                rect.x = x*SCALE;
                rect.y = y*SCALE;
                rect.width = SCALE;
                rect.height = SCALE;
                
                
                bitmapData.fillRect(rect, color);
            });
                           if(!searchMaze)
                            return;
            
            //ゴールを描画
            rect.x = searchMaze.goalPoint.x * SCALE;
            rect.y = searchMaze.goalPoint.y * SCALE;
            rect.width = SCALE;
            rect.height = SCALE;
            bitmapData.fillRect(rect, 0xffff0000);

        }
    }
}

    class Maze 
    { 
         
        public var width:uint; 
        public var height:uint; 
        public var data:Array; 
        public var buildProgressArray:Array; 
         

        public function Maze(width:uint, height:uint, buildProgressArray:Array = null) 
        { 
            this.width = width; 
            this.height = height; 
            this.buildProgressArray = buildProgressArray; 
            initialize(); 
        } 
         
        protected function initialize():void 
        { 
            data = []; 
        } 
         
         
        protected function setData(x:uint, y:uint, value:uint):void 
        {     
            //value : 1(壁) , 0(道) 
            data[x + width*y] = value; 

            if(buildProgressArray) 
            { 
                buildProgressArray.push(new MazePoint(x, y, value)); 
            } 
        } 

        public function getData(x:uint, y:uint):uint 
        { 
            return data[x + width*y]; 
        } 

    } 



    import flash.geom.Point; 
     
    class DigMaze extends Maze 
    { 
         
         

        public function DigMaze(width:uint, height:uint, buildProgressArray:Array = null,density:Number = 1) 
        { 
            super(width, height, buildProgressArray); 
             
        } 
         
        override protected function initialize():void 
        { 
            super.initialize(); 
             
            setDefWall(); 
            setWall(); 
             

        } 
         
        private var startPointArray:Array = []; 
         
        private function setDefWall():void 
        { 
            //まずすべてを壁でうめる 
            for(var y:int = 0; y< height; y++) 
            { 
                for(var x:int = 0; x< width; x++) 
                { 
                    setData(x,y,1); 
                     
                    //起点になれる座標配列を作る。 
                    if(y==0 || y == height-1 || x==0 || x == width-1) 
                    { 
                        continue; 
                    } 
                    if(x%2 == 1 && y%2 == 1) 
                    { 
                        startPointArray.push(new MazePoint(x,y,1)); 
                    } 
                     
                 
                }     
            } 
             
            //↓シャッフル・・をさせる。 
            //startPointArray. 
             
        } 
         
         
        private function setWall():void 
        { 
             
            startPointArray.forEach(function(p:MazePoint,i:int, arr:Array):void 
            { 

                if(p.value != 0) 
                { 
                    var loop:Boolean = true; 
                     
                    var x:uint = p.x; 
                    var y:uint = p.y; 
                     
                    while(loop) 
                    { 
                        var dir:String = checkRandomDicrectionCreate2Panel(x,y); 
                     

                        if(dir != "") 
                        { 
                            //塗りつぶし処理をする。と。 
                            //setData(x,y,0); 
                            switch(dir) 
                            { 
                                case TOP: 
                                    setData(x,y-1,0); 
                                    setData(x,y-2,0); 
                                    y -= 2; 
                                    break; 
                                case RIGHT: 
                                    setData(x+1,y,0); 
                                    setData(x+2,y,0); 
                                    x+=2; 
                                     
                                    break; 
                                case BOTTOM: 
                                    setData(x,y+1,0); 
                                    setData(x,y+2,0); 
                                    y +=2; 
                                    break; 
                                case LEFT: 
                                    setData(x-1,y,0); 
                                    setData(x-2,y,0); 
                                    x -=2; 
                                    break; 
                            } 
                        } 
                        else 
                        { 
                            loop = false; 
                        } 
                    } 
                } 
             
            }); 
        } 
         
        private static const TOP:String = "top"; 
        private static const RIGHT:String = "right"; 
        private static const BOTTOM:String = "bottom"; 
        private static const LEFT:String = "left"; 
         
        private function checkRandomDicrectionCreate2Panel(x:uint, y:uint):String 
        { 
            //生成できる方向をかえす 
            var enabledArray:Array = []; 
            if(getData(x-1,y) == 1 && getData(x-2,y) == 1 && x!=2) 
            { 
                //左は動ける。 
                enabledArray.push(LEFT); 
            } 
            if(getData(x,y-1) == 1 && getData(x,y-2) == 1 && y!=2) 
            { 
                //上に動ける。 
                enabledArray.push(TOP); 
            } 
            if(getData(x+1,y) == 1 && getData(x+2,y) == 1 && x!=width-2) 
            { 
                //右に動ける。 
                enabledArray.push(RIGHT); 
            } 
            if(getData(x,y+1) == 1 && getData(x,y+2) == 1 && y!=height-2) 
            { 
                //下に動ける。 
                enabledArray.push(BOTTOM); 
            } 

            if(enabledArray.length > 0) 
            { 
                return enabledArray[int(enabledArray.length*Math.random())]; 
            } 
            return ""; 
        } 
         

    } 




     class Direction
    {
        public static const TOP:String = "top";
        public static const RIGHT:String = "right";
        public static const BOTTOM:String = "bottom";
        public static const LEFT:String = "left";

    }






     
    import flash.geom.Point; 
    class MazePoint extends Point 
    { 
        public var value:int; 
        public function MazePoint(x:Number,y:Number,value:int) 
        { 
            super(x,y); 
            this.value = value; 
        } 
         
    } 



    //サーチャー
    class TremauxSearcher
    {
        
        private static const DIRECTIONS:Array = [Direction.TOP, Direction.RIGHT, Direction.BOTTOM, Direction.LEFT];

        public var direction:int;
        private var maze:Maze;
            
        
        public function TremauxSearcher(direction:uint, maze:Maze)
        {
            this.direction = direction;
            this.maze = maze;
            x = 1;
            y = 1;
        }
        
        //セッタ
        private var _x:uint;
        public function set x(value:uint):void
        {
            _oldX = _x;
            _x = value;
        }
        
        public function get x():uint
        {
            return _x;
        }
        
        private var _oldX:uint;
        public function get oldX():uint
        {
            return _oldX;
        }
        
        private var _y:uint;
        public function set y(value:uint):void
        {
            _oldY = _y;
            _y = value;
        }
        
        private var _oldY:uint;
        public function get oldY():uint
        {
            return _oldY;
        }
        
        public function get y():uint
        {
            return _y;
        }
        

        
        
        
        
        public function forword():void
        {
            //前方が道か調べる。
            
            if(isForwordWall(x,y))
            {
                //前が壁の場合。
                //右を向く
                turnRight();
                if(isForwordWall(x,y))
                {
                    //左を向く
                    turnLeft();
                    turnLeft();
                    if(isForwordWall(x,y))
                    {
                        //後を向く
                        turnLeft();    
                    }
                }
            }
            //一歩進む。
            move(1);

            

        }
        

        
        public function trunBack():void
        {
            turnRight();
            turnRight();
        }
        
        public function turnRight():void
        {
            direction++;
            if(direction == 4)
            {
                direction = 0
            }
        }
        
        public function turnLeft():void
        {
            direction--;
            if(direction == -1)
            {
                direction = 3;
            }        
        }
        
        private function move(value:int):void
        {
            switch(direction)
            {
                case 0:
                    //上向き
                    x = x;
                    y -= value;
                    break;
                case 1:
                    //右向き
                    x += value;
                    y=y;
                    break;
                case 2:
                    //下向き
                    x = x;
                    y += value;
                    break;
                case 3:
                    //左向き
                    x -= value;
                    y = y;
                    break;
            }
        }
        
        
        private function isForwordWall(posX:uint, posY:uint):Boolean
        {
            //正面が壁か否か
            switch(direction)
            {
                case 0:
                    //上向き
                    posY -= 1;
                    break;
                case 1:
                    //右向き
                    posX += 1;
                    break;
                case 2:
                    //下向き
                    posY += 1;
                    break;
                case 3:
                    //左向き
                    posX -= 1;
                    break;
            }
            //自分の前が壁か調べる。
            
            
            return (maze.data[posX + maze.width*posY] == 1);

        }
        
    }



//サーチ

    class TremauxSearch
    {
        
        //検索結果をまるごと格納。
        public var data:Array;
        
        private var searchData:Array;
        
        private var maze:Maze;
        public var startPoint:Point;
        public var goalPoint:Point;
        
        private var searcher:TremauxSearcher;
        
        //捜索過程を格納
        public var buildProgressArray:Array;
        
        
        

        public function TremauxSearch(maze:Maze, startPoint:Point, goalPoint:Point, buildProgressArray:Array = null)
        {
            this.maze = maze;
            this.startPoint = startPoint;
            this.goalPoint = goalPoint;
            this.buildProgressArray = buildProgressArray;
            
            
            
            this.initialize();
        }
        
        protected function initialize():void
        {
            searcher = new TremauxSearcher(0, maze);
            searcher.x = 1;
            searcher.y = 1;
            
            searchData = [].concat(maze.data);
            
            move();
        }
        

        protected function move():void
        {
            
            var loop:Boolean = true;
            var cnt:int = 0;
            var cntMax:int = 50000;    //たどり着けない疑いあり・・・のため。。
            //while(loop)
            while(cnt++ < cntMax )
            {
                if(!loop)
                {
                    cnt = cntMax;
                    return;
                }
                
                //移動する
                searcher.forword();
                setMark(searcher.x, searcher.y);
                

                if(isGoal(searcher.x, searcher.y))
                {
                    //ゴール。
                    loop = false;
                    //trace("ゴール");
                }
                else if(this.isDive(searcher.x, searcher.y))
                {
                    //分岐点に来た。
                    var mark:uint = getData(searcher.x, searcher.y);
                    if(mark == 2)
                    {
                        //初めて来た分岐点
                        //道を一本選んで進む。
                        loop = selectRoadAndTurn();
                    }
                    else if(mark == 3 && getData(searcher.oldX, searcher.oldY)==3)
                    {
                        //行き止まりで戻ってきた場合
                        loop = selectRoadAndTurn();
                    }
                    else
                    {
                        //来たことのある分岐点の場合は引き返す。
                        searcher.trunBack();
                    }
                    
                }
                else if(this.isDeadEnd(searcher.x, searcher.y))
                {
                    //行き止まりの場合は引き返す。
                    searcher.trunBack();
                    setMark(searcher.x, searcher.y);
                }
                

            }
            
            
        }
        
        private function isGoal(x:uint, y:uint):Boolean
        {
            return (goalPoint.x == x && goalPoint.y == y);
        }
        
        private function isDeadEnd(x:uint, y:uint):Boolean
        {
            //行き止まり
            var top:uint = getData(x,y-1);
            var right:uint = getData(x+1,y);
            var bottom:uint = getData(x,y+1);
            var left:uint = getData(x-1,y);
            var deadEndCnt:uint=0;
            if(top == 1)deadEndCnt++;
            if(right == 1)deadEndCnt++;
            if(bottom == 1)deadEndCnt++;
            if(left == 1)deadEndCnt++;
            return (deadEndCnt >= 3)
        }
        
        private function isDive(x:uint, y:uint):Boolean
        {
            //分岐点か否か

            
            var top:uint = getData(x,y-1);
            var right:uint = getData(x+1,y);
            var bottom:uint = getData(x,y+1);
            var left:uint = getData(x-1,y);
            var diveCnt:uint=0;
            if(top != 1)diveCnt++;
            if(right != 1)diveCnt++;
            if(bottom != 1)diveCnt++;
            if(left != 1)diveCnt++;
            return (diveCnt >= 3)
        }
        
        private function selectRoadAndTurn():Boolean
        {
            //道を選んで、方向を合わせておく。
            var x:uint = searcher.x;
            var y:uint = searcher.y;

            var top:uint = getData(x,y-1);
            var right:uint = getData(x+1,y);
            var bottom:uint = getData(x,y+1);
            var left:uint = getData(x-1,y);
            

            //通ったことのない道を優先させる。
            if(top == 0 && !isOldPos(x,y-1))
            {
                //上に進める
                searcher.direction = 0;
                return true;
            }
            
            if(right == 0 && !isOldPos(x+1,y))
            {
                //右に進める
                searcher.direction = 1;
                return true;
            }
            
            if(bottom == 0 && !isOldPos(x,y+1))
            {
                //下に進める
                searcher.direction = 2;
                return true;
            }
            
            if(left == 0 && !isOldPos(x-1,y))
            {
                //左に進める
                searcher.direction = 3;
                return true;
            }
            
            if(top == 2 && !isOldPos(x,y-1))
            {
                //上に進める
                searcher.direction = 0;
                return true;
            }
            
            if(right == 2 && !isOldPos(x+1,y))
            {
                //右に進める
                searcher.direction = 1;
                return true;
            }
            
            if(bottom == 2 && !isOldPos(x,y+1))
            {
                //下に進める
                searcher.direction = 2;
                return true;
            }
            
            if(left == 2 && !isOldPos(x-1,y))
            {
                //左に進める
                searcher.direction = 3;
                return true;
            }            
            
            return false;

        }
        
        private function isOldPos(x:uint, y:uint):Boolean
        {
            return(searcher.oldX == x && searcher.oldY == y);
        }
        
        public function getData(x:uint, y:uint):uint
        {
            return searchData[x + maze.width*y];
        }
                
        protected function setMark(x:uint, y:uint):void
        {
            var d:uint = searchData[x + maze.width*y];
            var value:uint;
            if(d == 0)
            {
                value = 2;
                searchData[x + maze.width*y] = value;
            }
            else if(d == 2)
            {
                value = 3;
                searchData[x + maze.width*y] = value;
            }
            
            if(buildProgressArray)
            {
                buildProgressArray.push(new MazePoint(x,y,value));
            }
            
        }


    }