使用p5.js的迷宫求解算法

时间:2019-04-05 00:24:46

标签: html p5.js

我使用深度优先搜索-递归backtracker算法生成了一个迷宫。我也想解决,但不知道如何开始解决我的迷宫。

我正在使用p5.js创建迷宫,并想解决已经生成的迷宫。

这是我用于生成迷宫的javascript代码。如果要运行此代码,则可能需要在HTML文件中添加p5.js cdn。

var cols, rows;
var w = 40;
var grid = [];
var current;
var stack = [];
function setup() {
    createCanvas(400,400);
    cols = floor(width/w);
    rows = floor(height/w);
    frameRate(5);
    for (var j = 0; j<rows; j++){
        for (var i = 0; i < cols; i++) {
            var cell = new Cell(i,j);
            grid.push(cell);
        }
    }
    current = grid[0];
}
function draw(){
    background(51);
    for (var i = 0; i<grid.length; i++){
        grid[i].show();
    }
    current.visited = true;
    current.highlight();
    var next = current.checkNeighbours();
    if (next) {
        next.visited = true;
        stack.push(current);
        removeWalls(current,next);
        current = next;
    }
    else if(stack.length > 0){
        current = stack.pop();
    }
}
function index(i,j){
    if (i < 0 || j < 0 || i > cols-1 || j > rows-1) {
        return -1;
    }
    return i + j * cols;
}
function Cell(i,j){
    this.i = i;
    this.j = j;
    this.walls = [true,true,true,true];
    this.visited = false;
    this.checkNeighbours = function(){
        var neighbours = [];
        var top =       grid[index(i, j-1)];
        var right =     grid[index(i+1, j)];
        var bottom =    grid[index(i, j+1)];
        var left =      grid[index(i-1, j)];
        if (top && !top.visited){
            neighbours.push(top);
        }
        if (right && !right.visited){
            neighbours.push(right);
        }
        if (bottom && !bottom.visited){
            neighbours.push(bottom);
        }
        if (left && !left.visited){
            neighbours.push(left);
        }
        if (neighbours.length > 0){
            var r = floor(random(0, neighbours.length));
            return neighbours[r];
        }
        else{
            return undefined;
        }
    }
    this.highlight = function(){
        x = this.i*w;
        y = this.j*w;
        noStroke();
        fill(0,0,255,200);
        rect(x,y,w,w);
    }
    this.show = function(){
        x = this.i*w;
        y = this.j*w;
        stroke(255);
        if (this.walls[0]){
            line(x   ,y    ,x+w ,y);
        }   
        if (this.walls[1]){
            line(x+w ,y    ,x+w ,y+w);
        }
        if (this.walls[2]){
            line(x+w ,y+w  ,x   ,y+w);
        }
        if (this.walls[3]){
            line(x   ,y+w  ,x   ,y)
        }   
        if (this.visited) {
            noStroke();
            fill(255,0,255,100);
            rect(x,y,w,w);
        }
    }
}
function removeWalls(a,b){
    var x = a.i - b.i;
    if (x === 1){
        a.walls[3] = false;
        b.walls[1] = false;
    }
    else if (x === -1){
        a.walls[1] = false;
        b.walls[3] = false; 
    }
    var y = a.j - b.j;
    if (y === 1){
        a.walls[0] = false;
        b.walls[2] = false;
    }
    else if (y === -1){
        a.walls[2] = false;
        b.walls[0] = false; 
    }   
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.js"></script>

2 个答案:

答案 0 :(得分:1)

many algorithms个解决迷宫的方法。解决由recursive backtracker算法创建的迷宫的一种简单方法是在生成迷宫时跟踪解决方案。

  1. 将第一个单元格设为起始单元格并将其推入解决方案堆栈
  2. 将最后一个单元格设为目标单元格
  3. 虽然解决方案堆栈不包含目标单元格
    1. 如果未访问下一个邻居,则将其推入解决方案堆栈
    2. 如果一个单元格中没有下一个邻居,则在回溯时弹出解决方案堆栈
  4. 将目标单元格推入解决方案堆栈时,将解决方案标记为完成

调整问题代码,使其也实现我们拥有的解决方案算法:

var cols, rows;
var w = 40;
var grid = [];
var current;
var stack = [];
var solution = [];
var goal;
var solutionComplete;
function setup() {
    createCanvas(400,400);
    cols = floor(width/w);
    rows = floor(height/w);
    frameRate(5);
    for (var j = 0; j<rows; j++){
        for (var i = 0; i < cols; i++) {
            var cell = new Cell(i,j);
            grid.push(cell);
        }
    }
    current = grid[0];
    grid[grid.length - 1].goal = true;
    solution.push(grid[0]);
}
function draw(){
    background(51);
    for (var i = 0; i<grid.length; i++){
        grid[i].show();
    }
    current.visited = true;
    current.highlight();
    var next = current.checkNeighbours();
    if (next) {
        if (!next.visited){
          if (!solutionComplete){
            solution.push(next);
            if (next.goal){
              solutionComplete = true;
            }
          }
        }
        next.visited = true;
        stack.push(current);
        removeWalls(current,next);
        current = next;
    }
    else if(stack.length > 0){
        current = stack.pop();
        if (!solutionComplete){
          solution.pop();
        }
    }
    if (solutionComplete){
      for (let i = 0; i < solution.length; i++){
        solution[i].solutionCell = true;
      }
    }
}
function index(i,j){
    if (i < 0 || j < 0 || i > cols-1 || j > rows-1) {
        return -1;
    }
    return i + j * cols;
}
function Cell(i,j){
    this.i = i;
    this.j = j;
    this.walls = [true,true,true,true];
    this.visited = false;
    this.goal = false;
    this.solutionCell = false;
    this.checkNeighbours = function(){
        var neighbours = [];
        var top =       grid[index(i, j-1)];
        var right =     grid[index(i+1, j)];
        var bottom =    grid[index(i, j+1)];
        var left =      grid[index(i-1, j)];
        if (top && !top.visited){
            neighbours.push(top);
        }
        if (right && !right.visited){
            neighbours.push(right);
        }
        if (bottom && !bottom.visited){
            neighbours.push(bottom);
        }
        if (left && !left.visited){
            neighbours.push(left);
        }
        if (neighbours.length > 0){
            var r = floor(random(0, neighbours.length));
            return neighbours[r];
        }
        else{
            return undefined;
        }
    }
    this.highlight = function(){
        x = this.i*w;
        y = this.j*w;
        noStroke();
        fill(0,0,255,200);
        rect(x,y,w,w);
    }
    this.show = function(){
        x = this.i*w;
        y = this.j*w;
        stroke(255);
        if (this.walls[0]){
            line(x   ,y    ,x+w ,y);
        }   
        if (this.walls[1]){
            line(x+w ,y ,x+w ,y+w);
        }
        if (this.walls[2]){
            line(x+w ,y+w  ,x ,y+w);
        }
        if (this.walls[3]){
            line(x ,y+w ,x ,y)
        }
        if (this.goal){
            noStroke();
            fill(0,255,0,100);
            rect(x,y,w,w);
        }        
        else if (this.solutionCell){
            noStroke();
            fill(255,0,0,100);
            rect(x,y,w,w);
        }else if(this.visited) {
            noStroke();
            fill(255,0,255,100);
            rect(x,y,w,w);
        }
    }
}
function removeWalls(a,b){
    var x = a.i - b.i;
    if (x === 1){
        a.walls[3] = false;
        b.walls[1] = false;
    }
    else if (x === -1){
        a.walls[1] = false;
        b.walls[3] = false; 
    }
    var y = a.j - b.j;
    if (y === 1){
        a.walls[0] = false;
        b.walls[2] = false;
    }
    else if (y === -1){
        a.walls[2] = false;
        b.walls[0] = false; 
    }   
}
   <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.2/p5.min.js"></script>

将迷宫的生成和解决方案实现分开,这样就可以在确定解决方案之前完全生成迷宫,这并不困难,但是除非存在强制我们解决完整迷宫的限制,否则构建解决方案才有意义连同迷宫。

答案 1 :(得分:0)

很抱歉,这是非常相关的,但是编码训练 youtuber 制作了一个迷宫生成算法,但我不知道它是否使用了深度优先搜索