Faster maze generation for acmaze

master
The Dod 2022-01-15 14:48:17 +02:00
parent 3606267aec
commit d61d3e2cea
3 changed files with 44 additions and 24 deletions

View File

@ -5665,8 +5665,8 @@
{ "id": "acmaze", { "id": "acmaze",
"name": "AccelaMaze", "name": "AccelaMaze",
"shortName":"AccelaMaze", "shortName":"AccelaMaze",
"version":"0.01", "version":"0.02",
"description": "Tilt the watch to roll a ball through a maze", "description": "Tilt the watch to roll a ball through a maze.",
"icon": "app.png", "icon": "app.png",
"tags": "game", "tags": "game",
"supports" : ["BANGLEJS2"], "supports" : ["BANGLEJS2"],

View File

@ -1 +1,2 @@
0.01: New App! 0.01: New App!
0.02: Faster maze generation

View File

@ -35,21 +35,56 @@ function Maze(n) {
this.walls[cell] = WALL_RIGHT|WALL_DOWN; this.walls[cell] = WALL_RIGHT|WALL_DOWN;
this.groups[cell] = cell; this.groups[cell] = cell;
} }
// Candidates of walls to break when digging the maze.
// If candidate failed (breaking it would create a loop),
// it would never succeed, so no need to retry it.
let candidates_down = [],
candidates_right = [];
for (let r=0 ; r<n; r++) {
for (let c=0; c<n; c++) {
let cell = n*r+c;
if (r<(n-1)) { // Don't break wall down for bottom row.
candidates_down.push(cell);
}
if (c<(n-1)) { // Don't break wall right for rightmost column.
candidates_right.push(cell);
}
}
}
let from_group, to_group; let from_group, to_group;
let ngroups = n*n; let ngroups = n*n;
while (--ngroups) { while (--ngroups) {
// Abort if BTN1 pressed [grace period for menu] // Abort if BTN1 pressed [grace period for menu]
// (for some reason setWatch() fails inside constructor) // (for some reason setWatch() fails inside constructor)
if (ngroups<n*n-4 && digitalRead(BTN1)) { if (ngroups<n*n-16 && digitalRead(BTN1)) {
aborting = true; aborting = true;
return; return;
} }
from_group = to_group = -1; from_group = to_group = -1;
while (from_group<0) { while (from_group<0) {
if (Math.random()<0.5) { // try to break a wall right let trying_down = false;
let r = Math.floor(Math.random()*n); if (Math.random()<0.5 || !candidates_right.length) {
let c = Math.floor(Math.random()*(n-1)); trying_down = true;
let cell = r*n+c; }
let candidates = trying_down ? candidates_down : candidates_right;
candidate_index = Math.floor(Math.random()*candidates.length),
cell = candidates.splice(candidate_index, 1)[0],
r = Math.floor(cell/n),
c = cell%n;
if (trying_down) { // try to break a wall down
if (this.groups[cell]!=this.groups[cell+n]) {
this.walls[cell] &= ~WALL_DOWN;
g.clearRect(
this.margin+c*this.wall_length+1,
this.margin+(r+1)*this.wall_length,
this.margin+(c+1)*this.wall_length-1,
this.margin+(r+1)*this.wall_length
);
g.flip(); // show progress.
from_group = this.groups[cell];
to_group = this.groups[cell+n];
}
} else { // try to break a wall right
if (this.groups[cell]!=this.groups[cell+1]) { if (this.groups[cell]!=this.groups[cell+1]) {
this.walls[cell] &= ~WALL_RIGHT; this.walls[cell] &= ~WALL_RIGHT;
g.clearRect( g.clearRect(
@ -62,21 +97,6 @@ function Maze(n) {
from_group = this.groups[cell]; from_group = this.groups[cell];
to_group = this.groups[cell+1]; to_group = this.groups[cell+1];
} }
} else { // try to break a wall down
let r = Math.floor(Math.random()*(n-1));
let c = Math.floor(Math.random()*n);
let cell = r*n+c;
if (this.groups[cell]!=this.groups[cell+n]) {
this.walls[cell] &= ~WALL_DOWN;
g.clearRect(
this.margin+c*this.wall_length+1,
this.margin+(r+1)*this.wall_length,
this.margin+(c+1)*this.wall_length-1,
this.margin+(r+1)*this.wall_length
);
from_group = this.groups[cell];
to_group = this.groups[cell+n];
}
} }
} }
for (let cell = 0; cell<n*n; cell++) { for (let cell = 0; cell<n*n; cell++) {
@ -253,7 +273,6 @@ let maze_interval = setInterval(
function() { function() {
if (maze) { if (maze) {
if (digitalRead(BTN1) || maze.status==STATUS_ABORTED) { if (digitalRead(BTN1) || maze.status==STATUS_ABORTED) {
console.log(`aborting ${start_time}`);
maze = null; maze = null;
start_time = duration = 0; start_time = duration = 0;
aborting = false; aborting = false;
@ -270,7 +289,7 @@ let maze_interval = setInterval(
duration = Date.now()-start_time; duration = Date.now()-start_time;
g.setFontAlign(0,0).setColor(g.theme.fg); g.setFontAlign(0,0).setColor(g.theme.fg);
g.setFont("Vector",18); g.setFont("Vector",18);
g.drawString(`Solved in\n ${timeToText(duration)} \nClick to play again`, g.getWidth()/2, g.getHeight()/2, true); g.drawString(`Solved ${maze.n}X${maze.n} in\n ${timeToText(duration)} \nClick to play again`, g.getWidth()/2, g.getHeight()/2, true);
} }
} }
}, 25); }, 25);