为什么我的迷宫生成器不检测是否在 p5.js 中访问了单元格?
Why is my maze generator not detecting if a cell has been visited in p5.js?
我正在尝试制作一个迷宫生成器,到目前为止几乎一切正常。我已经能够将我的位置设置为随机 pos
,然后我重复 standard()
函数。在函数中,我将 pos
添加到 posList
,然后我选择一个随机方向。接下来,我检查单元格是否已被 运行 通过所有 posList
向量反向访问过。我还没有执行回溯的代码。如果 visited = false
然后我移动到广场并执行尚未制作的 path()
功能。但是,出于某种原因,移动器只是不检测是否已访问单元格。我正在使用 p5.js。我做错了什么?
var posList = [];
var pos;
var tempo;
var boole = false;
var direc;
var mka = 0;
function setup() {
createCanvas(400, 400);
//Set up position
pos = createVector(floor(random(3)), floor(random(3)));
frameRate(1)
}
//Choose a direction
function direct(dire) {
if(dire === 0) {
return(createVector(0, -1));
} else if(dire === 1) {
return(createVector(1, 0));
} else if(dire === 2) {
return(createVector(0, 1));
} else {
return(createVector(-1, 0));
}
}
/foLo stands fo forLoop
function foLo() {
//If we have checked less than three directions and know there is a possibility for moving
if(mka < 4) {
//tempoRARY, this is what we use to see if the cell has been visited
tempo = createVector(pos.x + direct(direc).x, pos.y + direct(direc).y);
//Go through posList backwards
for(var i = posList.length - 1; i >= 0; i --) {
//If the cell has been visited or the cell is off of the screen
if(tempo === posList[i]) {
//Change the direction
direc ++;
//Roll over direction value
if(direc === 4) {
direc = 0;
}
//Re-execute on next frame
foLo();
//The cell has been visited
boole = false;
//Debugging
console.log(direc)
mka++;
} else if(tempo.x < 0 || tempo.x > 2 || tempo.y < 0 || tempo.y > 2) {
direc ++;
if(direc === 4) {
direc = 0;
}
foLo();
boole = false;
console.log(direc)
mka++;
}
}
//If it wasn't visited (Happens every time for some reason)
if(boole === true) {
//position is now the temporary value
pos = tempo;
console.log("works")
mka = 0;
}
}
}
function standard() {
//Add pos to posList
posList.push(pos);
//Random direction
direc = floor(random(4));
//Convert to vector
direct(direc);
foLo();
//Tracks pos
fill(255, 255, 0);
rect(pos.x*100+50, pos.y*100+50, 50, 50)
}
function draw() {
background(255);
fill(0);
noStroke();
//draw grid
for(var i = 0; i < 4; i ++) {
rect(i*100,0,50,350);
rect(0, i*100, 350, 50);
}
standard();
boole = true;
console.log(pos)
console.log(posList);
}
您的问题出在比较两个向量的那一行if(tempo === posList[i]) {
:这永远不会成立。
您可以使用以下代码验证(例如 setup()
):
const v1 = new p5.Vector(1, 0);
const v2 = new p5.Vector(1, 0);
const v3 = new p5.Vector(1, 1);
console.log(v1 === v2) // false
console.log(v1 === v3) // false
这是因为尽管具有相同的值 v1
和 v2
引用了两个不同的对象。
您可以使用 p5.Vector.equals
函数。该文档有以下示例:
let v1 = createVector(10.0, 20.0, 30.0);
let v2 = createVector(10.0, 20.0, 30.0);
let v3 = createVector(0.0, 0.0, 0.0);
print(v1.equals(v2)); // true
print(v1.equals(v3)); // false
这可能不会给你一个有效的算法,因为我怀疑你有其他逻辑错误(但我可能是错的,或者你稍后会调试它们)但至少这部分代码会做你期望的。
另一个解决方案是使用 Set
而不是您的职位列表。此解决方案的缺点是您必须调整代码以处理“网格外”位置情况。但是,当您想跟踪访问过的项目时,Set
通常是一个很好的解决方案,因为访问时间是恒定的。这意味着要定义一个位置是否已经被访问过,它总是需要相同的时间(你会做类似 visitedSet.has(positionToCheck)
的事情,而在你的解决方案中,你遍历一个列表,你访问过的单元格越多检查单元格是否在列表中需要更长的时间。
Set
解决方案将要求您先转换向量,然后再将它们添加到正弦集合中,我在不能简单地比较向量之前解释过。所以你可以用这样的东西检查他们的字符串表示:
const visitedCells = new Set();
const vectorToString = (v) => `${v.x},{$v.y}` // function to get the vector representation
// ...
visitedCells.add(vectorToString(oneCell)); // Mark the cell as visited
visited = visitedCells.has(vectorToString(anotherCell))
还有一个一般性的建议你应该注意你的变量和函数的名字。例如
// foLo stands fo forLoop
function foLo() {
是一个很大的味道:你的函数名称应该是描述性的,当你看到你的函数调用 foLo();
必须在函数声明旁边找到注释时,会使代码的可读性降低。您可以将其命名为 generateMaze()
,这样您无需查看功能代码就知道它在做什么。
也一样
//tempoRARY, this is what we use to see if the cell has been visited
tempo = createVector(pos.x + direct(direc).x, pos.y + direct(direc).y);
例如,您可以简单地将 tempo
重命名为 cellToVisit
。
或boole
:命名一个布尔值boole
并不能传达很多信息。
刚写代码的时候可能看起来是一些小细节,但是当你的代码有几百行或者休息几天再看的时候,你会感谢过去的你那。
我正在尝试制作一个迷宫生成器,到目前为止几乎一切正常。我已经能够将我的位置设置为随机 pos
,然后我重复 standard()
函数。在函数中,我将 pos
添加到 posList
,然后我选择一个随机方向。接下来,我检查单元格是否已被 运行 通过所有 posList
向量反向访问过。我还没有执行回溯的代码。如果 visited = false
然后我移动到广场并执行尚未制作的 path()
功能。但是,出于某种原因,移动器只是不检测是否已访问单元格。我正在使用 p5.js。我做错了什么?
var posList = [];
var pos;
var tempo;
var boole = false;
var direc;
var mka = 0;
function setup() {
createCanvas(400, 400);
//Set up position
pos = createVector(floor(random(3)), floor(random(3)));
frameRate(1)
}
//Choose a direction
function direct(dire) {
if(dire === 0) {
return(createVector(0, -1));
} else if(dire === 1) {
return(createVector(1, 0));
} else if(dire === 2) {
return(createVector(0, 1));
} else {
return(createVector(-1, 0));
}
}
/foLo stands fo forLoop
function foLo() {
//If we have checked less than three directions and know there is a possibility for moving
if(mka < 4) {
//tempoRARY, this is what we use to see if the cell has been visited
tempo = createVector(pos.x + direct(direc).x, pos.y + direct(direc).y);
//Go through posList backwards
for(var i = posList.length - 1; i >= 0; i --) {
//If the cell has been visited or the cell is off of the screen
if(tempo === posList[i]) {
//Change the direction
direc ++;
//Roll over direction value
if(direc === 4) {
direc = 0;
}
//Re-execute on next frame
foLo();
//The cell has been visited
boole = false;
//Debugging
console.log(direc)
mka++;
} else if(tempo.x < 0 || tempo.x > 2 || tempo.y < 0 || tempo.y > 2) {
direc ++;
if(direc === 4) {
direc = 0;
}
foLo();
boole = false;
console.log(direc)
mka++;
}
}
//If it wasn't visited (Happens every time for some reason)
if(boole === true) {
//position is now the temporary value
pos = tempo;
console.log("works")
mka = 0;
}
}
}
function standard() {
//Add pos to posList
posList.push(pos);
//Random direction
direc = floor(random(4));
//Convert to vector
direct(direc);
foLo();
//Tracks pos
fill(255, 255, 0);
rect(pos.x*100+50, pos.y*100+50, 50, 50)
}
function draw() {
background(255);
fill(0);
noStroke();
//draw grid
for(var i = 0; i < 4; i ++) {
rect(i*100,0,50,350);
rect(0, i*100, 350, 50);
}
standard();
boole = true;
console.log(pos)
console.log(posList);
}
您的问题出在比较两个向量的那一行if(tempo === posList[i]) {
:这永远不会成立。
您可以使用以下代码验证(例如 setup()
):
const v1 = new p5.Vector(1, 0);
const v2 = new p5.Vector(1, 0);
const v3 = new p5.Vector(1, 1);
console.log(v1 === v2) // false
console.log(v1 === v3) // false
这是因为尽管具有相同的值 v1
和 v2
引用了两个不同的对象。
您可以使用 p5.Vector.equals
函数。该文档有以下示例:
let v1 = createVector(10.0, 20.0, 30.0);
let v2 = createVector(10.0, 20.0, 30.0);
let v3 = createVector(0.0, 0.0, 0.0);
print(v1.equals(v2)); // true
print(v1.equals(v3)); // false
这可能不会给你一个有效的算法,因为我怀疑你有其他逻辑错误(但我可能是错的,或者你稍后会调试它们)但至少这部分代码会做你期望的。
另一个解决方案是使用 Set
而不是您的职位列表。此解决方案的缺点是您必须调整代码以处理“网格外”位置情况。但是,当您想跟踪访问过的项目时,Set
通常是一个很好的解决方案,因为访问时间是恒定的。这意味着要定义一个位置是否已经被访问过,它总是需要相同的时间(你会做类似 visitedSet.has(positionToCheck)
的事情,而在你的解决方案中,你遍历一个列表,你访问过的单元格越多检查单元格是否在列表中需要更长的时间。
Set
解决方案将要求您先转换向量,然后再将它们添加到正弦集合中,我在不能简单地比较向量之前解释过。所以你可以用这样的东西检查他们的字符串表示:
const visitedCells = new Set();
const vectorToString = (v) => `${v.x},{$v.y}` // function to get the vector representation
// ...
visitedCells.add(vectorToString(oneCell)); // Mark the cell as visited
visited = visitedCells.has(vectorToString(anotherCell))
还有一个一般性的建议你应该注意你的变量和函数的名字。例如
// foLo stands fo forLoop
function foLo() {
是一个很大的味道:你的函数名称应该是描述性的,当你看到你的函数调用 foLo();
必须在函数声明旁边找到注释时,会使代码的可读性降低。您可以将其命名为 generateMaze()
,这样您无需查看功能代码就知道它在做什么。
//tempoRARY, this is what we use to see if the cell has been visited
tempo = createVector(pos.x + direct(direc).x, pos.y + direct(direc).y);
例如,您可以简单地将 tempo
重命名为 cellToVisit
。
或boole
:命名一个布尔值boole
并不能传达很多信息。
刚写代码的时候可能看起来是一些小细节,但是当你的代码有几百行或者休息几天再看的时候,你会感谢过去的你那。