5

Let's suppose we have a maze. You start somewhere in it:

* - * - * 
    |   |
    *-here

Only a small part of the maze is generated (for example, a 10 by 10 square around you). As you move around, more of the maze is generated. Is there an algorithm that ensures that there is always a place for you to go?

For example:

 *-here  * - *
             |
             *

would not work because you have no paths.

I have a 'solution' for it, and that is to generate a finite maze, then force it to be connected to another finite maze, forming a mesh (ensuring that finite mazes are doable is easy).

Edit 1: The maze can't have a deterministic size; Parts of the map will be generated dynamically.

Edit 2: It has to generate the same maze no matter the order which you load it in (Moving up then left should generate the same maze as moving left then up)

My maze does not need to include all places

example image:enter image description here

Ruiqi Li
  • 187
  • 14
  • Try Googling maze generation disjoint sets. It ensures you always have a path to go to, no cycles and every square can be reached. – Gertjan Brouwer May 14 '20 at 22:55
  • 1
    I’m a bit confused about how you can have a maze in a grid where there’s always more to explore. What happens if you hit a dead end, for example? Or is the idea that you can never hit a dead end under any circumstance? – templatetypedef May 15 '20 at 02:19
  • *"It has to generate the same maze no matter the order which you load it in"*: how would you test that? Does this mean the maze generation is not random, but predetermined, and that you always walk around in the same virtual maze, no matter how many times you start from scratch? – trincot May 15 '20 at 05:30
  • No, i mean that given a same seed, the maze will be identical no matter what other thing effects it – Ruiqi Li Jun 12 '20 at 16:32
  • @templatetypedef no, i mean that you will never be trapped in a part of the maze. I expect dead ends, but no enclosed areas – Ruiqi Li Jun 12 '20 at 16:34
  • Think of the maze as a graph where the solver is trying find a way between two chosen nodes. Two ways I've used both begin with a "dense" graph: one with many more edges than you'd like. Then they discover an embedded tree. Various forms of grid are the simplest dense graphs, but lots of others are possible. For tree discovery, you can use a minimum spanning tree algorithm with random weights. Another way is to search depth first from the start, choosing the next out-edge randomly. Delete edges to already-visited nodes. Heuristic weighting of random numbers determines the feel of the maze. – Gene Sep 06 '21 at 19:30

4 Answers4

2

I like to generate mazes with variants of Kruskal's algorihtm:

http://weblog.jamisbuck.org/2011/1/3/maze-generation-kruskal-s-algorithm

https://mtimmerm.github.io/webStuff/maze.html

One way to think of using Kruskal's algorithm to generate mazes is:

  1. Assign a random weight to every possible wall
  2. Remove every wall if the cells on ether side of it are not connected by removing all walls of lesser weight.

If you divide the world into tiles, then you can turn this into an algorithm that you can evaluate locally as follows:

  1. Assign a random weight to every possible wall. Use a different random number generator for the walls in each tile, and seed it with the tile's coordinates.
  2. Remove every wall if the cells on either side of it are not connected by removing all walls of lesser weight in its tile and adjacent tiles.

This way, to generate any tile of the maze, you only need to consider the weights that would be assigned to walls in the 8 adjacent tiles. The procedure is just like doing the normal Kruskal's to make a 3 tile X 3 tile maze, and then cutting out the middle tile.

When you generate mazes this way, it's guaranteed that there will be a path from every place in the maze to every other place. Unlike "perfect" mazes, however, there may be more than one path between two places that are more than a tile apart. As long as your tiles are sufficiently large, though, there won't be any visible artifacts of the tiling, and it will still be difficult to find your way from one place to another.

Matt Timmermans
  • 53,709
  • 3
  • 46
  • 87
  • I just want to clarify, but: look at this https://i.stack.imgur.com/iTfx3.png – Ruiqi Li May 15 '20 at 00:24
  • yes, that's right. To generate the new tile, though, you have to consider the random wall weights in the 8 neighboring tiles. It doesn't actually matter where "you" are -- you can generate each tile individually at any time and they will all match up into a big maze – Matt Timmermans May 15 '20 at 01:08
  • I have talked with my dev team about this, and this is not what i am looking for. We want it so that we don't need the other parts of the maze to generate. our current solution works in the same way, so I want an answer that does not need the other parts of the maze to generate is, if that is possible. – Ruiqi Li May 15 '20 at 03:21
  • Well, I'm not going to repeat all the stuff I already wrote, but I hope you'll revisit it after some more research. – Matt Timmermans May 15 '20 at 03:47
1

There are many, of varying complexities. A good place to start is the Wikipedia page: https://en.wikipedia.org/wiki/Maze_generation_algorithm.

Often, it'll be easier to generate the whole maze in advance and reveal it bit by bit as it is explored than to incrementally generate the maze during exploration, but take a look at the link and decide what you think.

Also, if the maze doesn't completely fill space, you might look at the way old games like hack, nethack, or rogue generate room layouts on levels. I'm sorry I don't have a reference for how that was done.

Thomas Kammeyer
  • 4,457
  • 21
  • 30
  • I don't want the maze to be of deterministic size, and it should be dynamically generated. – Ruiqi Li May 14 '20 at 20:58
  • OK, so that'll be more interesting. One possible (and addmitedly somewhat vague) suggestion: take one of the line-by-line simple algorithms and apply it to the "frontier" of the already-created maze at each step. – Thomas Kammeyer May 14 '20 at 21:10
  • I'm not sure, but will you method generate the same maze given the same seed, no matter how you move? – Ruiqi Li May 14 '20 at 21:16
  • I'm not completely certain... I think some of those algorithms are deterministic and some not but you'd have to read that section of the Wikipedia article to get those details. Even if it one of them is random, if you want it to be deterministic you might be able fix the seed based on the initial configuration, or fix the seed some other way of your choosing, to make it be deterministic. – Thomas Kammeyer May 14 '20 at 21:24
  • there are maze algorithms that are deterministic given seed, but if you move differently, it might affect how the maze is generated because you also have to consider other parts of the maze (insuring weird stuff doesn't happen) when you, for example, walk in a circle. – Ruiqi Li May 14 '20 at 21:28
0

Maybe you can use Wilson's algorithm to solve your problem. This algorithm grows the "maze" (spanning tree) by adding a loop-erased "random walk" from some point outside of the existing maze until the random walk meets the existing maze. So if you want to grow your existing maze, you could add some empty region (only nodes, no edges) to your existing graph, select one vertex from that region and run a random walk until the existing maze is met which will grow your maze.

ChrisF
  • 134,786
  • 31
  • 255
  • 325
0

Here's a suggestion of something that doesn't entirely meet your objective, but it comes close. Where it's lacking is that you also have to compute a guaranteed solution, which will override what follows. So what follows is deterministic for the rest of the maze.

The type of maze being considered uses a square grid. Each cell is a square. There are 16 types of cells. Think of each wall as a binary digit. If the wall is missing, it's a 1. If it's present, it's a 0. Using a seed calculated from the coordinates of the cell, compute a random number from 0 to 15 and assign it to the cell. Each cell now has deterministically been assigned a random number.

Neighboring cells are possibly incompatible, though. So simply use a rule to tweak the values. For every pair of adjoining cells, take the one with the lower coordinate as the truth (the other coordinate is the same, since we're talking about a square grid). Adjust the wall value of the other one to match.

That creates a maze without a guaranteed path. So simply modify it with the path from the calculated solution. Let's number the edges clockwise from the top, assigning the top to the most significant bit. I'll fill in the space with a perpendicular line to show where a path would be, rather than leaving it blank as in the question.

Example cells:

* - *
|   | 0 cell
* - *

* - *
-   | 1 cell
* - *

* - *
|   | 2 cell
* | *

* - *
-   | 3 cell
* | *

etc.

So now, suppose the cell at (5,4) as a type 6 and its neighbor to the right (6,4) is a type 12:

* - *      * | *
|   -      |   -
* | *      * - *

These conflict with each other. The one on the left wants the path. The one on the right wants a wall. This is resolved by looking at the coordinates. (5,4) < (6,4) so the left one is given precedence. It wants a path, so the other cell is modified by applying a bitwise or with 1:

* - *      * | *
|   -      -   -
* | *      * - *

So the new configuration of the cell to the right is type 13 (12 OR 1).

The two cells are then compared to the precomputed solution path and tweaked, if needed. If the precomputed solution does not pass through either of these cells, we are finished.

Victor Engel
  • 2,037
  • 2
  • 25
  • 46
  • P.S. You may want to omit type 0 cells, since they would be orphans. You can also modify your random number generator to preferentially select one kind of cell over others if you like. – Victor Engel Sep 06 '21 at 19:16
  • Also, instead of overriding at the end, it would probably be better to check if the wall under consideration is part of the precomputed path. If so, use that, else, do the logic here. No need to do all this logic if it's just going to be overridden later. – Victor Engel Sep 06 '21 at 20:48