簡體   English   中英

JavaScript 迷宮求解算法

[英]JavaScript Maze Solver Algorithm

HTML

<div id="labirinth">
    <form style="text-align:center" name="forma1" autocomplete="on">
        <table style="margin:0 auto;">
            <tr>
                <td style="float:right;">Height:</td>
                <td><input type="text" id="height" name="height" autofocus="autofocus" maxlength="2" size="6" /></td>
            </tr>
            <tr>
                <td style="float:right;">Width:</td>
                <td><input type="text" id="width" name="width"  maxlength="2" size="6" /></td>
            </tr>
        </table>
    </form>
    <input type="button" alt="submit" onClick="datas();" value="New" style="margin-top:10px;" />
</div>
<pre id="out"></pre>

JavaScript

function datas() {

    var height = parseInt(document.getElementById("height").value);
    var width = parseInt(document.getElementById("width").value);

    document.getElementById('out').innerHTML = display(maze(height,width));
}

function maze(x,y) {
    var n=x*y-1;
    if (n<0) {alert("Bad numbers!");return;}
    var horiz=[]; 
        for (var j= 0; j<x+1; j++) horiz[j]= [];
    var verti=[]; 
        for (var j= 0; j<y+1; j++) verti[j]= [];

    var here= [Math.floor(Math.random()*x), Math.floor(Math.random()*y)];
    var path= [here];
    var unvisited= [];
    for (var j= 0; j<x+2; j++) {
        unvisited[j]= [];
        for (var k= 0; k<y+1; k++)
            unvisited[j].push(j>0 && j<x+1 && k>0 && (j != here[0]+1 || k != here[1]+1));
    }
    while (0<n) {
        var potential= [[here[0]+1, here[1]], [here[0],here[1]+1],
            [here[0]-1, here[1]], [here[0],here[1]-1]];
        var neighbors= [];
        for (var j= 0; j < 4; j++)
            if (unvisited[potential[j][0]+1][potential[j][1]+1])
                neighbors.push(potential[j]);
        if (neighbors.length) {
            n= n-1;
            next= neighbors[Math.floor(Math.random()*neighbors.length)];
            unvisited[next[0]+1][next[1]+1]= false;
            if (next[0] == here[0])
                horiz[next[0]][(next[1]+here[1]-1)/2]= true;
            else 
                verti[(next[0]+here[0]-1)/2][next[1]]= true;
            path.push(here= next);
        } else 
            here= path.pop();
    }
    return ({x: x, y: y, horiz: horiz, verti: verti});
}

function display(m) {
    var text= [];
    for (var j= 0; j<m.x*2+1; j++) {
        var line= [];
        if (0 == j%2)
            for (var k=0; k<m.y*4+1; k++)
                if (0 == k%4) 
                    line[k]= 'X';
                else
                    if (j>0 && m.verti[j/2-1][Math.floor(k/4)])
                        line[k]= ' ';
                    else
                        line[k]= 'X';
        else
            for (var k=0; k<m.y*4+1; k++)
                if (0 == k%4)
                    if (k>0 && m.horiz[(j-1)/2][k/4-1])
                        line[k]= ' ';
                    else
                        line[k]= 'X';
                else
                    line[k]= ' ';
        if (0 == j) line[1]=line[3]=' ',line[2]= '1';
        if (m.x*2-1 == j) line[4*m.y]= '2';
        text.push(line.join('')+'\r\n');

    }
    return text.join('');
}

我正在嘗試在不使用 HTML 表格單元格的情況下在 JavaScript 中創建完全工作的迷宮生成器。 現在我遇到了這個迷宮的創建求解器的問題。

問題:我的代碼需要使用哪種迷宮求解算法? 我應該從什么開始? 我不需要整個算法——我只需要關於是否可以在這個迷宮生成器中使用迷宮求解器的建議。

JSbin - http://jsbin.com/uwoyon/1

我對適用於您生成的迷宮的求解器的建議是 Dijkstra 算法。 雖然我不確定 horiz 和 verti 參數如何定義迷宮結構,但 Dijkstra 的算法可以通過從“1”旁邊的單元格開始並從那里開始構建來滿足您的情況。

它的操作方式是用每個單元格和起始單元格之間的單元格數量來標記每個單元格。 對於 3x3 迷宮,第一個單元格將是:

x 1 xxxxxxxxx
x 1         x
x   xxxxxxxxx
x           x
x   xxxxxxxxx
x           2
xxxxxxxxxxxxx

使用標記的單元格檢查是否有空的相鄰單元格(沒有被牆阻擋的單元格),將單元格值增加 1。對所有空單元格重復此過程:

x 1 xxxxxxxxx
x 1   2   3 x
x   xxxxxxxxx
x 2   3   4 x
x   xxxxxxxxx
x 3   4   5 2
xxxxxxxxxxxxx

現在從與結尾 '2' 相鄰的單元格向后工作。 這表明該解決方案的路徑長度為 5 步,因此從 5 開始,找到相鄰的 4,然后是 3,依此類推回到 1。

注意:我推薦使用隊列來標記單元格的遞歸解決方案:

1- 用“1”標記第一個單元格並將其放入隊列中。

2- 從隊列中取出單元格: - 檢查合法鄰居(未被牆阻擋的鄰居)是否未標記。 - 如果相鄰單元格未標記,則用當前單元格+1 標記它。 - 將相鄰小區添加到隊列中。 - 對所有 4 個潛在鄰居重復

3- 重復步驟 1 和 2,直到沒有更多未標記的細胞。

編輯:這是使用我建議的解算器的小提琴,它與問題中的迷宮生成器無關,所以除非被問到,否則我不會詳細介紹它是如何操作的(有點粗糙,但它的實現應該易於遵循)。

如果它是一個完美的迷宮(任何兩個單元之間只有一條路徑),那么您只需要一個遞歸牆跟隨器。 從第一個單元格開始,按照給定的順序檢查所有周圍的單元格,通常是順時針或逆時針。 如果可以輸入單元格,請輸入。 如果是結束,你就完成了。 如果不是,則遞歸。 當您檢查了所有其他 3 條路徑並且沒有一條路徑結束時,只需返回即可。 當您到達終點時,您的調用堆棧有解決方案 :) 我通常做的是為“我在這里找不到解決方案”返回“false”或為“這就是解決方案”返回“true”。

你可以在我的 github 上的迷宮算法中看到我是如何解決的:

https://github.com/mdchaney/jsmaze

如果您查看 jsmaze2.html,函數“find_depth”實際上是一個求解器。

jsmaze4.html 非常復雜,但它實際上是在使用遞歸算法構建迷宮的同時構建解決方案。 它通過跟蹤在建造過程中“進入”一個單元格時哪一堵牆被推倒來做到這一點。 由於還有其他算法,我還包括了“find_depth”,它為任何迷宮設置了入口牆。

這足以讓你開始。

非遞歸方式將為您解決迷宮。 通過遞歸(回溯算法),您可能會碰運氣。

請參閱此文件:- http://cs.stanford.edu/people/eroberts/courses/cs106b/chapters/07-backtracking-algorithms.pdf

如果這個問題會持續到周末。 我會發布一個編碼答案。

謝謝

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM