create account

JS Tutorial: Labyrinth Generator - Rekursive Backtracker Algorithm by snackaholic

View this thread on: hive.blogpeakd.comecency.com
· @snackaholic ·
$4.39
JS Tutorial: Labyrinth Generator - Rekursive Backtracker Algorithm
![bild2.png](https://cdn.steemitimages.com/DQmPXS8R4ebToVzLTqo7Cx6HQutRR8tesg1nsbKuuGvZn2d/bild2.png)

Hallo und herzlich willkommen zum Tutorial, welches euch zeigt, wie ihr in JavaScript eure eigenen Labyrinthe erzeugen könnt. Zur Generierung dieser werden wir auf den [Recursive Backtracker Algorithm](https://en.wikipedia.org/wiki/Maze_generation_algorithm#Recursive_backtracker) zurückgreifen.

# Der Algorithmus:

Zunächst wollen wir einmal auf den Algorithmus eingehen und ihn anschließend nachprogrammieren. Es folgt eine freie Übersetzung des unter Wikipedia referenzierten Algorithmus:

- Nehme eine zufällige Zelle und mache diese zur aktuellen Zelle. Markiere sie anschließend als besucht.
- Solange es unbesuchte Zellen gibt
  - Falls die aktuelle Zelle unbesuchte Nachbarn hat
    - Selektiere eine Zelle der Nachbarzellen per Zufall
    - Füge die aktuelle Zelle dem Stack hinzu
    - Entferne die Wand zwischen der aktuellen & selektierten Zelle
    - Mache aus der selektierten Zelle die aktuelle Zelle & markiere sie als besucht.
  - Falls der Stack nicht leer ist
    - Entferne ein Element vom Stack und mache es zur aktuellen Zelle. 
<hr>

# Vorbereitungen:

## Koordinatensystem

Wir werden unsere Zellen mit Hilfe eines Koordinatensystems abbilden. Dabei wollen wir dieses frei Dimensionieren können.

```javascript
var gridsize = 20;
var cells = [];
for (var i = 0; i < gridsize; i++) {
    for (var j = 0; j < gridsize; j++) {
        cells.push(cell(i, j));
    }
}
```

Die variable gridsize bestimmt, wie viele Zeilen(y) und Spalten(x) es gibt. Für die jeweilige Zelle wird ein Zellenobjekt im Zellenarray cells gespeichert. 

Im Codebeispiel würden aktuell 400 Zellen generiert, welche bei der Erstellung des Labyrinths berücksichtigt werden müssten.

<hr>

## Zellengenerierung

Unsere Zellen werden nach Vorgabe des Algorithmus mindestens folgende Eigenschaften besitzen:
 * Zustand, ob eine Zelle besucht worden ist oder nicht
  * Information, welche Zellwände eingerissen wurden

Weitere Informationen fügen wir der Zelle hinzu:
* Information, wie Hoch & Breit eine Zelle ist
* Schlüssel zur Objektidentifizierung

Wir generieren unsere Zellenobjekte mit Hilfe eines sogenannten [Objekkonstruktors](https://www.w3schools.com/js/js_object_constructors.asp): 

```javascript
function cell(x, y) {
    var newcell = {
        "x": x,
        "y": y,
        "wall": [true, true, true, true], // top right left bottom
        "visited": false,
        "key" : "x" + x + "y" + y
    };
    return newcell;
}
```

<hr>

# Umsetzung des Algorithmus

Nun da wir alle Vorkehrungen getroffen haben, ist es an der Reihe den Algorithmus schritt für Schritt umzusetzen.
> Nehme eine zufällige Zelle und mache diese zur aktuellen Zelle. Markiere sie anschließend als besucht.

Wir benötigen eine Funktion, welche uns ein zufälliges Element eines Arrays zurückgibt.

```javascript
// give random item from array
function randomItem(array) {
    return array[Math.floor(Math.random() * array.length)];
}
```

Nun können wir diese als besucht markieren und Sie zu unserer aktuellen Zelle machen.

```javascript
function recursiveBacktrackerMaze() {
    // make decision of initial cell
    var initialCell = randomItem(cells);
    var currentCell = initialCell;
    initialCell.visited = true;
```
<hr> 
Als nächstes müssen wir uns um folgende Anweisung kümmern:

> Solange es unbesuchte Zellen gibt

Dafür benötigen wir eine Teilmenge unseres Zellenarrays. Und zwar brauchen wir die Zellen, welche als Status" visited = false" haben. Dafür implementieren wir folgende Hilfsfunktion:

```javascript
function giveUnvisitedCells() {
    var ucells = [];
    for (var i = 0; i < cells.length; i++) {
        if (cells[i].visited == false) {
            ucells.push(cells[i]);
        }
    }
    return ucells;
}
```
<hr>

Nun da wir immer auf die unbesuchten Zellen zugreifen können, müssen wir uns laut der nächsten Anweisung auch um unbesuchte Nachbarn der Zelle kümmern.
> Falls die aktuelle Zelle unbesuchte Nachbarn hat

Dafür implementieren wir 2 Hilfsfunktionen. Zum einen erweitern wir das Zellenobjekt, sodass dieses uns seine direkten Nachbarn zurückgeben kann.
```javascript
newcell.giveNeighborKeys = function () {
        var array = [];
        // left
        if (x - 1 >= 0) {
            array.push("x" + (x - 1) + "y" + y);
        }
        // right
        if (x + 1 < gridsize) {
            array.push("x" + (x + 1) + "y" + y);
        }
        // up
        if (y - 1 >= 0) {
            array.push("x" + x + "y" + (y - 1));
        }
        // down
        if (y + 1 < gridsize) {
            array.push("x" + x + "y" + (y + 1));
        }
        return array;
    };
```
Mit Hilfe dieser Funktion wollen wir uns dann alle Zellen zurückgeben, welche nicht besucht worden sind.

```javascript
    newcell.giveUnvisitedNeighbors = function () {
        var neighbors = newcell.giveNeighborKeys();
        var unvisitedKeys = [];
        for (var i = 0; i < neighbors.length; i++) {
            var key = neighbors[i];
            if (cells[giveIndexByKey(cells, key)].visited == false) {
                unvisitedKeys.push(key);
            }
        }
        return unvisitedKeys;
    };
```

Dabei generieren wir immer die Schlüssel des zu findenden Objektes.

Um für den generierten Objektschlüssel das passende Objekt zu finden, müssen wir alle Objekte unseres Zellenarrays mit den generierten Schlüssel vergleichen. 

```javascript
function giveIndexByKey(array, key) {
    for (var i = 0; i < array.length; i++) {
        if (array[i].key == key) {
            return i;
        }
    }
    return -1;
}
```
<hr>
Der Rest des Algorithmus liegt auf der Hand: 

> Selektiere eine Zelle der Nachbarzellen per Zufall
    - Füge die aktuelle Zelle dem Stack hinzu
    - Entferne die Wand zwischen der aktuellen & selektierten Zelle
    - Mache aus der selektierten Zelle die aktuelle Zelle & markiere sie als besucht.
```javascript
var unvisitedNeighborKeys = currentCell.giveUnvisitedNeighbors();
        // Falls die aktuelle Zelle unbesuchte Nachbarn hat
        if (unvisitedNeighborKeys.length > 0) {
            // Selektiere eine Zelle der Nachbarzellen per Zufall
            var randomNeighborKey = randomItem(unvisitedNeighborKeys);
            // Füge die aktuelle Zelle dem Stack hinzu
            keysStack.push(currentCell);
            // Entferne die Wand zwischen der aktuellen & selektierten Zelle
            removeWall(currentCell, randomNeighborKey);
            // Mache aus der selektierten Zelle die aktuelle Zelle & markiere sie als besucht.
            currentCell = cells[giveIndexByKey(cells, randomNeighborKey)];
            currentCell.visited = true;
        }
```

Sollten wir aber keine Nachbarzellen haben, müssen wir auf unseren Stack zurückgreifen

>Falls der Stack nicht leer ist
Entferne ein Element vom Stack und mache es zur aktuellen Zelle.

Dadurch ergibt sich dann eine else-if Anweisung
```javascript
...
} else if (keysStack.length > 0) {
            currentCell = keysStack.pop();
}
```
Damit sind wir auch schon fertig.
<hr>

# Das Ergebnis:

Wenn wir uns nun Schritt für Schritt des Algorithmus anschauen, wird deutlich, warum dieser als "Backtracker" Algorithmus bezeichnet wird. Die aktuelle Zelle wird durch die blaue Zelle dargestellt. Die nicht besuchte Zellen sind rot. Bereits besuchte Zellen sind grün. Dadurch ergibt sich folgendes Bild: 

![animation (0).gif](https://cdn.steemitimages.com/DQmePkvY7yYYdY5TBHspPZAyvcb3bSX4N6t8uQmQwPxKmXy/animation%20(0).gif)

 Gegen Ende der Animation sieht man, wie der Algorightmus den bereits gegangenen Weg zurückgeht, bis er eine nicht besuchte Zelle findet, um diese Anschließend als besucht zu markieren. Daher auch der Name "Backtracker Algorithmus". 

<hr>

Für die Nerds unter euch hier auch nochmal ein [Fiddlelink](https://jsfiddle.net/54rbczp8/).

Vielen Dank fürs lesen, falls Ihr irgendwelche Fragen oder Verbesserungsvorschläge haben solltet, lasst es mich bitte in den Kommentaren wissen :)

Wünsche euch allen eine schöne restliche Woche!
👍  , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , and 43 others
properties (23)
authorsnackaholic
permlinkjs-tutorial-labyrinth-generator-rekursive-backtracker-algorithm
categorydeutsch
json_metadata{"tags":["deutsch","de-stem","steemstem","javascript","steemdev"],"image":["https://cdn.steemitimages.com/DQmPXS8R4ebToVzLTqo7Cx6HQutRR8tesg1nsbKuuGvZn2d/bild2.png","https://cdn.steemitimages.com/DQmePkvY7yYYdY5TBHspPZAyvcb3bSX4N6t8uQmQwPxKmXy/animation%20(0).gif"],"links":["https://en.wikipedia.org/wiki/Maze_generation_algorithm#Recursive_backtracker","https://www.w3schools.com/js/js_object_constructors.asp","https://jsfiddle.net/54rbczp8/"],"app":"steemit/0.1","format":"markdown"}
created2018-07-02 21:15:15
last_update2018-07-02 21:15:15
depth0
children5
last_payout2018-07-09 21:15:15
cashout_time1969-12-31 23:59:59
total_payout_value3.469 HBD
curator_payout_value0.920 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length8,089
author_reputation4,012,973,923,033
root_title"JS Tutorial: Labyrinth Generator - Rekursive Backtracker Algorithm"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id63,188,094
net_rshares1,874,311,547,508
author_curate_reward""
vote details (107)
@a-0-0 ·
#
# upvote for me please? https://steemit.com/news/@bible.com/2sysip
#
properties (22)
authora-0-0
permlinkre-snackaholic-js-tutorial-labyrinth-generator-rekursive-backtracker-algorithm-20180702t211550532z
categorydeutsch
json_metadata{"tags":["deutsch"],"links":["https://steemit.com/news/@bible.com/2sysip"],"app":"steemit/0.1"}
created2018-07-02 21:15:48
last_update2018-07-02 21:15:48
depth1
children0
last_payout2018-07-09 21:15:48
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length70
author_reputation-4,863,186,238,920
root_title"JS Tutorial: Labyrinth Generator - Rekursive Backtracker Algorithm"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id63,188,149
net_rshares0
@bid.bot ·
$0.02
Bid.Bot Upvote
<table>
<tr>
<td>
<center>

<p/>

![bid.bot](https://steemitimages.com/u/bid.bot/avatar/small)
</center>

</td>
<td>

##### Promotion With Minimum and Guaranteed 10% ROI!

</td>
</tr>
</table>

<table>
<tr>
<td>

##### Yeah!

<p><p/>

You just got a 19% upvote from me, courtesy of @bid.bot. I am the **All-In-One**, Upvoting and Anonymous Flagging BidBot.


</td>
<td>

##### Top Profitability

<p><p/>

I'm able to **calculate and proxy** the most **profitable bids** for the best bidbots out there, so **you don't have to!** Place your bids via <a href="https://bidbot.me">https://bidbot.me</a>.

</td>
</tr>
</table>

👍  
properties (23)
authorbid.bot
permlinkjs-tutorial-labyrinth-generator-rekursive-backtracker-algorithm-comment
categorydeutsch
json_metadata{}
created2018-07-03 16:03:24
last_update2018-07-03 16:03:24
depth1
children0
last_payout2018-07-10 16:03:24
cashout_time1969-12-31 23:59:59
total_payout_value0.015 HBD
curator_payout_value0.004 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length622
author_reputation19,745,488,675,947
root_title"JS Tutorial: Labyrinth Generator - Rekursive Backtracker Algorithm"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id63,264,589
net_rshares8,854,678,276
author_curate_reward""
vote details (1)
@resteemator ·
@resteemator is a new bot casting votes for its followers. Follow @resteemator and vote this comment to increase your chance to be voted in the future!
properties (22)
authorresteemator
permlink20180703t152005831z
categorydeutsch
json_metadata{"tags":["steem"],"app":"steemjs/test"}
created2018-07-03 15:20:06
last_update2018-07-03 15:20:06
depth1
children0
last_payout2018-07-10 15:20:06
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length151
author_reputation-248,953,111,874
root_title"JS Tutorial: Labyrinth Generator - Rekursive Backtracker Algorithm"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id63,259,317
net_rshares0
@steem-bootcamp ·
$0.04
###### Nachdem Dein Beitrag gelesen worden ist hat ein Kurator des [German-Steem-Bootcamp](https://steemit.com/@steem-bootcamp) entschieden, ihn mit einem Upvote über ein paar Cent zu belohnen  
##### Aktueller Kurator ist @greece-lover
👍  ,
properties (23)
authorsteem-bootcamp
permlinkre-snackaholic-js-tutorial-labyrinth-generator-rekursive-backtracker-algorithm-20180706t063211836z
categorydeutsch
json_metadata{"tags":["deutsch"],"users":["greece-lover"],"links":["https://steemit.com/@steem-bootcamp"],"app":"steemit/0.1"}
created2018-07-06 06:32:24
last_update2018-07-06 06:32:24
depth1
children0
last_payout2018-07-13 06:32:24
cashout_time1969-12-31 23:59:59
total_payout_value0.031 HBD
curator_payout_value0.009 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length236
author_reputation5,380,630,314,722
root_title"JS Tutorial: Labyrinth Generator - Rekursive Backtracker Algorithm"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id63,618,557
net_rshares21,666,484,760
author_curate_reward""
vote details (2)
@steemstem ·
post_voted_by
<center> https://cdn.discordapp.com/attachments/354723995037466624/463380522928963599/steemSTEM.png</center> <br><br> This post has been voted on by the steemstem curation team and voting trail.  <br> <br>There is more to SteemSTEM than just writing posts, check <a href="https://steemit.com/steemstem/@steemstem/being-a-member-of-the-steemstem-community">here</a> for some more tips on being a community member. You can also join our discord <a href="https://discord.gg/BPARaqn">here</a> to get to know the rest of the community!
👍  
properties (23)
authorsteemstem
permlinkre-js-tutorial-labyrinth-generator-rekursive-backtracker-algorithm-20180703t085822
categorydeutsch
json_metadata""
created2018-07-03 08:58:24
last_update2018-07-03 08:58:24
depth1
children0
last_payout2018-07-10 08:58:24
cashout_time1969-12-31 23:59:59
total_payout_value0.000 HBD
curator_payout_value0.000 HBD
pending_payout_value0.000 HBD
promoted0.000 HBD
body_length530
author_reputation262,017,435,115,313
root_title"JS Tutorial: Labyrinth Generator - Rekursive Backtracker Algorithm"
beneficiaries[]
max_accepted_payout1,000,000.000 HBD
percent_hbd10,000
post_id63,211,641
net_rshares7,865,201,681
author_curate_reward""
vote details (1)