【发布时间】:2018-02-25 09:35:15
【问题描述】:
我为此做了很多搜索,并找到了很多生成迷宫的帮助,但我有一个非常具体的要求,我尝试过的所有循环都失败了。
我创建了一个编辑器,我可以在其中绘制我需要的东西,但是生成器会有很大帮助,但它失败了。
要求:
给定一个由 DIV 元素组成的方形网格(不小于 10x10 且不大于 60x60),我需要一条穿过和环绕网格的连接路径,该路径在除开始/结束时之外的任何点都不会触及自身。 所有路径方格之间必须始终至少有一个空白方格(只要路径不与自身接触,任何数量的空白都可以)。 不能有死胡同和环路(路径会自行交叉的地方)。
这有点像一个反向迷宫 - 我不需要填满整个网格,事实上我对路径周围的大量空间没有任何问题。沿着类似于大富翁棋盘游戏的思路可能更容易想到这一点,其中棋盘周围的路径徘徊而不是绕过边缘。我实际上被困在一个足够的描述中,因此称之为反向迷宫。
我尝试过的事情:
很多很多过于复杂的循环。 Iv 不是很接近,问题也是性能之一。 大量代码旨在生成迷宫。其中一些确实非常好,但它们都生成了一个典型的迷宫,这根本不是我真正需要的,而且事实证明,调整代码比在循环中编写一组疯狂的循环更棘手。
任何想法都会有所帮助。谢谢。
更新代码
好的,我已将 KIKO 的 PHP 代码翻译成 Javascript,但在某处我犯了一个我无法追查的简单错误:该代码工作并生成正确尺寸的表格并生成通过它的路径。
但是,在函数“isWithinGrid”中,我必须从表格的宽度和高度中减去 1,否则整个事情都会失败,如果我这样做,代码将工作并创建通过表格减去的路径一个单元格将被错误地着色,尽管它显然是路径的一部分。
请注意,有时路径会被破坏或接触到自身。我毫不怀疑是一些小问题导致了这一切,但目前这是我想出的最好的,任何进一步的帮助将不胜感激。
class Grid{
constructor(width,height){
this.width = width;
this.height = height;
this.cells = [];
for(var x=0; x < this.width; x++){
var tmparray = [];
for(var y=0; y < this.height; y++){
tmparray.push(false);
}
this.cells.push(tmparray);
}
}
isWithinGrid(x,y){
return (x >= 0) && (x <= this.width-1) && (y >= 0) && (y <= this.height-1);
}
isWithinPath(x,y){
return this.isWithinGrid(x,y) && this.cells[x][y];
}
setCellInPath(x,y,boolean){
this.cells[x][y] = boolean;
return this;
}
drawHorizontalLine(x1,x2,y){
for(var x=x1; x < x2; x++){
this.setCellInPath(x,y,true);
}
return this;
}
drawVerticalLine(x,y1,y2){
for(var y=y1; y < y2; y++){
this.setCellInPath(x,y,true);
}
return this;
}
drawSquare(){
var left = Math.round(this.width/5);
var right = Math.round(4*this.width/5);
var top = Math.round(this.height/5);
var bottom = Math.round(4*this.height/5);
this.drawHorizontalLine(left,right,top)
.drawHorizontalLine(left,right,bottom)
.drawVerticalLine(left,top,bottom)
.drawVerticalLine(right,top,bottom);
return this;
}
moveCell(x,y,dx,dy){
this.setCellInPath(x,y,false);
this.setCellInPath(x+dx,y+dy,true);
}
canMoveCell(x,y,dx,dy){
return this.isWithinPath(x,y) &&
this.isWithinGrid(x+dx,y+dy) &&
!this.isWithinPath(x+dx,y+dy) &&
!this.isWithinPath(x+2*dx,y+2*dy) &&
!this.isWithinPath(x+dy+dx,y+dx+dy)
!this.isWithinPath(x-dy+dx,y-dx+dy);
}
tryToDistortOnce(x,y,dx,dy){
if (!this.canMoveCell(x,y,dx,dy)) return false;
if (!this.canMoveCell(x+dy,y+dx,dx,dy)) return false;
if (!this.canMoveCell(x-dy,y-dx,dx,dy)) return false;
this.moveCell(x,y,dx,dy);
this.setCellInPath(x+dy+dx,y+dx+dy,true);
this.setCellInPath(x-dy+dx,y-dx+dy,true);
return true;
}
distortOnce(){
var x=0, y=0, dx=0, dy=0;
do {
x = Math.floor(Math.random() * this.width) + 1;
y = Math.floor(Math.random() * this.height) + 1;
} while (!this.isWithinPath(x,y));
switch (Math.floor(Math.random() * 4) + 1){
case 1: dx = -1; dy = 0; break;
case 2: dx = +1; dy = 0; break;
case 3: dx = 0; dy = +1; break;
case 4: dx = 0; dy = -1; break;
}
if (this.tryToDistortOnce(x,y,dx,dy)){
do {
x += dx;
y += dy;
} while (this.tryToDistortOnce(x,y,dx,dy));
return true;
}
return false;
}
distortPath(numberOfDistortions = 10){
for(var counter=1; counter < numberOfDistortions; counter++){
var tries = 0;
while (!this.distortOnce() && (tries < this.width+this.height)){ tries++; }
}
return this;
}
renderGrid(){
var str = '<table class="TSTTAB">';
for(var y=0; y < this.width; y++){
for(var x=0; x < this.height; x++){
str += '<td'+(this.cells[y][x] ? ' class="path">' : '>');
}
str += '</tr>';
}
str += '</table>';
document.getElementById('cont').innerHTML =str;
return this;
}
}
var Testgrid = new Grid(20,20);
Testgrid.drawSquare().distortPath(10).renderGrid();
.TSTTAB{background-color:#7F7F7F;border-collapse:collapse;}
.TSTTAB td{ width:20px; height: 20px; border: 1px solid #000;background-color: #E5E5E5; }
.TSTTAB td.path { background-color: #44F; }
<div id='cont'></div>
【问题讨论】:
-
分享你的代码。
-
理念:从起点开始,随机移动。如果你被卡住了,就原路返回。
-
@connexo 我认为它没有用,因为这是一个算法问题。
-
我不明白你的问题。什么是“空白方块”?
-
在这种情况下,我认为一种算法开始一条路径并随机移动,然后在卡住时回溯,可能需要很长时间并且相当不成功。我会使用另一种方法:选择在其间绘制直接路径的起点和终点。从路径中选择一个随机正方形并将其沿随机方向拖动,同时保持路径连接,直到它不能再进一步。这样,您可以根据需要尽可能多地或尽可能少地扭曲路径。我知道,魔鬼在细节中,但也许这会给你新的灵感?
标签: algorithm