I made a maze generation command line tool before. It uses a form of Growing Tree (prim's). And its link is here.
I tried to rewrite it in JS. Using HTML5 canvas. I checked the code line by line. Almost all lines are identical.
Python one fills image buffer entirely, JS doesn't fill its canvas. I tried to debug several times. Couldn't find a difference.
Here is the Python Version.
from PIL import Image
from random import choice, randrange
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument('WIDTH', type=int)
parser.add_argument('HEIGHT', type=int)
parser.add_argument('OUTPUT', type=str)
args = parser.parse_args()
WIDTH = args.WIDTH + (args.WIDTH + 1) % 2
HEIGHT = args.HEIGHT + (args.HEIGHT + 1) % 2
OUTPUT = args.OUTPUT
def checked(p):
return 0 < p[0] < WIDTH and 0 < p[1] < HEIGHT
def mid_point(p1, p2):
return (p1[0]+p2[0])/2, (p1[1]+p2[1])/2
current_point = (1, 1)
visited = {current_point: 1}
active = [current_point]
mapper = {}
while active:
left = (current_point[0] - 2, current_point[1])
right = (current_point[0] + 2, current_point[1])
up = (current_point[0], current_point[1] + 2)
down = (current_point[0], current_point[1] - 2)
neighbours = [n for n in (left, right, up, down)
if checked(n) and n not in visited]
if not neighbours:
index = randrange(0, len(active))
current_point = active[index]
active.pop(index)
else:
picked = choice(neighbours)
visited[picked] = 1
active.append(picked)
m = mid_point(current_point, picked)
mapper[m] = 1
mapper[current_point] = 1
mapper[picked] = 1
current_point = picked
data = []
for h in range(HEIGHT):
for w in range(WIDTH):
data.append(int((w, h) in mapper))
img = Image.new('1', size=(WIDTH, HEIGHT), color=0)
img.putdata(data)
img.save(OUTPUT, format='png')
Here is the JS Version.
canvas = document.getElementById('lab');
WIDTH = canvas.width;
HEIGHT = canvas.height;
ctx = canvas.getContext('2d');
ctx.imageSmoothingEnabled = false;
function drawPixel (x, y, r, g, b, a) {
var imgIndex = (x + y * WIDTH) * 4;
imagedata.data[imgIndex + 0] = r;
imagedata.data[imgIndex + 1] = g;
imagedata.data[imgIndex + 2] = b;
imagedata.data[imgIndex + 3] = a;
}
function checked(p){
return (0 < p[0] && p[0]< WIDTH) && (0 < p[1] && p[1] < HEIGHT);
}
function midPoint(p0, p1) {
return [Math.floor((p0[0] + p1[0]) / 2),
Math.floor((p0[1] + p1[1]) / 2)];
}
currentPoint = [1, 1];
visited = {}
visited[currentPoint] = true;
active = [currentPoint]
mapper = {}
while(active.length > 0) {
left = [currentPoint[0] - 2, currentPoint[1]];
right = [currentPoint[0] +2, currentPoint[1]];
up = [currentPoint[0], currentPoint[1] + 2];
down = [currentPoint[0], currentPoint[1] -2];
let neighbourCandidates = [left, right, up, down];
let neighbours = []
for (var i = 0; i < neighbourCandidates.length; i++) {
if(checked(neighbourCandidates[i]) && !visited[neighbourCandidates[i]]) {
neighbours.push(neighbourCandidates[i]);
}
}
if(neighbours.length == 0) {
index = Math.floor(Math.random() * active.length);
currentPoint = active[index];
active.pop(index);
} else {
index = Math.floor(Math.random() * neighbours.length);
picked = neighbours[index];
visited[picked] = 1;
active.push(picked);
m = midPoint(currentPoint, picked);
mapper[m] = 1;
mapper[currentPoint] = 1;
mapper[picked] = 1;
currentPoint = picked;
}
}
imagedata = ctx.getImageData(0, 0, WIDTH, HEIGHT);
for (var h = 0; h < HEIGHT; h++) {
for (var w = 0; w < WIDTH; w++) {
if(mapper[[w, h]]){
drawPixel(w, h, 255, 255, 255, 255);
}
}
}
ctx.putImageData(imagedata, 0, 0);
Just create an HTML document with a canvas that has id lab
and import the file.
I couldn't find the reason of different behaviour. Any guesses?