practice prim maze generation.
Log in to post a comment.
// You can find the Turtle API reference here: https://turtletoy.net/syntax
Canvas.setpenopacity(1);
// Global code will be evaluated once.
const turtle = new Turtle();
function line(x1,y1,x2,y2){turtle.penup();turtle.goto(x1,y1);turtle.pendown();turtle.goto(x2,y2);}
// masks
const L = 1;
const R = 2;
const U = 4;
const D = 8;
const IN = 16;
function opposite(direction)
{
if(direction == L)return R;
if(direction == R)return L;
if(direction == U)return D;
if(direction == D)return U;
}
// canvas parameters
let width = 200.0
let height = 200.0
let margin = 5.0
let maze_width = width - margin*2.0;
let maze_height = height - margin*2.0;
let maze_left = -maze_width*0.5;
let maze_top = -maze_height*0.5;
// maze
const num_grid = 120;
grid_size = maze_width/num_grid;
let map =new Array();
for(let y=0;y<num_grid;y++)
{
map[y]=new Array();
for(let x=0;x<num_grid;x++){
map[y][x]=0;
}
}
let front = new Set()
function valid(x,y)
{
return x>=0 && x<num_grid && y>=0 && y<num_grid
}
function inside(x,y)
{
return map[y][x] & IN;
}
function neighbors(x,y)
{
let nb = new Array();
if(valid(x-1,y) && inside(x-1,y)){nb.push([x-1,y,L]);}
if(valid(x+1,y) && inside(x+1,y)){nb.push([x+1,y,R]);}
if(valid(x,y-1) && inside(x,y-1)){nb.push([x,y-1,U]);}
if(valid(x,y+1) && inside(x,y+1)){nb.push([x,y+1,D]);}
return nb;
}
function get_xy(id){
return [Math.floor(id/num_grid),id%num_grid];
}
function id(x,y){
return x*num_grid+y;
}
function add_front(x,y){
if(valid(x,y) && !inside(x,y)){
front.add(id(x,y))
}
}
function mark(x,y)
{
map[y][x] |= IN;
add_front(x-1,y);
add_front(x+1,y);
add_front(x,y-1);
add_front(x,y+1);
}
function rand_int(max) {
return Math.floor(Math.random() * max);
}
function rand_pop(myset)
{
let items = Array.from(myset);
let it = items[rand_int(items.length)];
myset.delete(it)
return it
}
function generate_maze()
{
// random start cell
let start_x = rand_int(num_grid);
let start_y = rand_int(num_grid);
mark(start_x,start_x)
let steps = 0;
// generation loop
while(front.size)
{
// get random element from fontier
let xyid = rand_pop(front);
let xy = get_xy(xyid);
let x = xy[0],y = xy[1];
// find fontier's neighbors
nbs = neighbors(x,y);
// pick random neighbor
let nb = nbs[rand_int(nbs.length)];
let nx = nb[0], ny = nb[1];
let dir = nb[2];
// break the wall and make a way
map[y][x] |= dir;
map[ny][nx] |= opposite(dir);
steps++;
// mark the cell as inside
mark(x,y);
}
}
generate_maze();
function draw_grid(x,y)
{
let l = maze_left + grid_size*x;
let r = l + grid_size;
let t = maze_top + grid_size*y;
let b = t + grid_size;
let dir = map[y][x];
if(!(dir&L))line(l,t,l,b);
if(!(dir&U))line(l,t,r,t);
if((x==num_grid-1)&&!(dir&R))line(r,t,r,b);
if((y==num_grid-1)&&!(dir&D))line(l,b,r,b);
}
// The walk function will be called until it returns false.
function walk(i) {
let xy = get_xy(i);
let x = xy[0],y = xy[1];
draw_grid(x,y);
return i < num_grid*num_grid-1;//num_grid
}