package {

import flash.display.BitmapData;

import flash.geom.Rectangle;

import flash.geom.Point;

public class MazeConstructor {

private var mazeBitmapData:BitmapData;

private var cellsX:Number;

private var cellsY:Number;

private var cellWidth:Number;

private var cellHeight:Number;

private var isRandom:Boolean = false;

private var seed:Number;

private var wallThickness:Number;

private var hasExits:Boolean;

private var maze:Array;

private var mx:Number = 0;

private var my:Number = 0;

private var nextCell:Number = 0;

private var d:Number = 0;

private var dx:Array = [ 0, 0, -1, 1 ];

private var dy:Array = [ -1, 1, 0, 0 ];

private var todo:Array = [];

private var todonum:Number = 0;

public function MazeConstructor() {}

public function initMaze($mazeBitmapData:BitmapData,$cellsX:Number,$cellsY:Number,$cellWidth:Number,$cellHeight:Number,$wallThickness:Number=1,$seed:Number=0,$hasExits:Boolean=false):void {

mazeBitmapData = $mazeBitmapData;

cellsX = $cellsX;

cellsY = $cellsY;

cellWidth = $cellWidth;

cellHeight = $cellHeight;

wallThickness = $wallThickness;

seed = $seed;

hasExits = $hasExits;

if(seed==0) isRandom = true;

createMaze();

}

private function createMaze():void {

mx = 0;

my = 0;

nextCell = 0;

d = 0;

dx = [ 0, 0, -1, 1 ];

dy = [ -1, 1, 0, 0 ];

todo = [];

todonum = 0;

maze = [];

for(mx = 0; mx < cellsX; mx++) {

maze[mx] = [];

for(my = 0; my < cellsY; my++) {

if(mx == 0 || mx == cellsX-1 || my == 0 || my == cellsY-1) {

maze[mx][my] = 32;

} else {

maze[mx][my] = 63;

}

}

}

if(isRandom==true) {

mx = (Math.floor(Math.random() * (cellsX-2)))+1;

my = (Math.floor(Math.random() * (cellsY-2)))+1;

} else {

mx = Math.floor(cellsX/2);

my = Math.floor(cellsY/2);

}

maze[mx][my] &= ~48;

for(d = 0; d < 4; d++) {

if((maze[mx + dx[d]][my + dy[d]] & 16) != 0) {

todo[todonum++] = ((mx + dx[d]) << 16) | (my + dy[d]);

maze[mx + dx[d]][my + dy[d]] &= ~16;

}

}

while(todonum > 0) {

if(isRandom==true) {

nextCell = (Math.floor(Math.random() * todonum));

} else {

seed++;

nextCell = seed % todonum;

}

mx = todo[nextCell] >> 16;

my = todo[nextCell] & 65535;

todo[nextCell] = todo[--todonum];

do{

if(isRandom==true) {

d = Math.floor(Math.random()*4);

} else {

seed++;

d = seed%4;

}

} while((maze[mx + dx[d]][my + dy[d]] & 32) != 0);

maze[mx][my] &= ~((1 << d) | 32);

maze[mx + dx[d]][my + dy[d]] &= ~(1 << (d ^ 1));

for(d = 0; d < 4; d++) {

if((maze[mx + dx[d]][my + dy[d]] & 16) != 0) {

todo[todonum++] = ((mx + dx[d]) << 16) | (my + dy[d]);

maze[mx + dx[d]][my + dy[d]] &= ~16;

}

}

}

if(hasExits==true) {

maze[1][1] &= ~1;

maze[cellsX-2][cellsY-2] &= ~2;

}

renderMaze();

}

private function renderMaze():void {

var i:int;

var j:int;

for(i = 1; i < cellsX-1; i++) {

for(j = 1; j < cellsY-1; j++) {

if((maze[j] & 1) != 0) {

mazeBitmapData.fillRect (new Rectangle(i * cellWidth, j * cellHeight, cellWidth+wallThickness, wallThickness),0xff000000);

}

if((maze[j] & 2) != 0) {

mazeBitmapData.fillRect(new Rectangle(i * cellWidth, j * cellHeight + cellHeight, cellWidth+wallThickness, wallThickness),0xff000000);

}

if((maze[j] & 4) != 0) {

mazeBitmapData.fillRect(new Rectangle(i * cellWidth, j * cellHeight, wallThickness, cellHeight+wallThickness),0xff000000);

}

if((maze[j] & 8) != 0) {

mazeBitmapData.fillRect(new Rectangle(i * cellWidth+cellWidth, j * cellHeight, wallThickness, cellHeight+wallThickness),0xff000000);

}

}

}

}

}

}