迷宫生成算法-Prim最小生成树

算法思想

1.Start with a grid full of walls.
2.Pick a cell, mark it as part of the maze. Add the walls of the cell to the wall list.
3.While there are walls in the list:
    1.Pick a random wall from the list. If only one of the two cells that the wall divides is visited, then:
        2.Make the wall a passage and mark the unvisited cell as part of the maze.
        3.Add the neighboring walls of the cell to the wall list.
    2.Remove the wall from the list.
 
1.让迷宫全是墙.
2.选一个单元格作为迷宫的通路,然后把它的邻墙放入列表
3.当列表里还有墙时
    1.从列表里随机选一个墙,如果这面墙分隔的两个单元格只有一个单元格被访问过
        1.那就从列表里移除这面墙,即把墙打通,让未访问的单元格成为迷宫的通路
        2.把这个格子的墙加入列表
    2.如果墙两面的单元格都已经被访问过,那就从列表里移除这面墙

在操作过程中,如果把墙放到列表中,比较复杂,维基里面提到了改进策略:

Although the classical Prim's algorithm keeps a list of edges, for maze generation we could instead maintain a list of adjacent cells. If the randomly chosen cell has multiple edges that connect it to the existing maze, select one of these edges at random. This will tend to branch slightly more than the edge-based version above.

解释一下就是:我们可以维护一个迷宫单元格的列表,而不是边的列表。在这个迷宫单元格列表里面存放了未访问的单元格,我们在单元格列表中随机挑选一个单元格,如果这个单元格有多面墙联系着已存在的迷宫通路,我们就随机选择一面墙打通。这会比基于边的版本分支稍微多一点。

相对于深度优先的算法,Prim随机算法不是优先选择最近选中的单元格,而是随机的从所有的列表中的单元格进行选择,新加入的单元格和旧加入的单元格同样概率会被选择,新加入的单元格没有有优先权。因此其分支更多,生成的迷宫更复杂,难度更大,也更自然。生成的迷宫如图所示:

 

代码

 

import random
import numpy as np
from matplotlib import pyplot as plt
import matplotlib.cm as cm
 
num_rows = int(input("Rows: ")) # number of rows
num_cols = int(input("Columns: ")) # number of columns
 
# The array M is going to hold the array information for each cell.
# The first four coordinates tell if walls exist on those sides 
# and the fifth indicates if the cell has been visited in the search.
# M(LEFT, UP, RIGHT, DOWN, CHECK_IF_VISITED)
M = np.zeros((num_rows,num_cols,5), dtype=np.uint8)
 
# The array image is going to be the output image to display
image = np.zeros((num_rows*10,num_cols*10), dtype=np.uint8)
 
# Set starting row and column
r = 0
c = 0
history = [(r,c)] # The history is the stack of visited locations
 
# Trace a path though the cells of the maze and open walls along the path.
# We do this with a while loop, repeating the loop until there is no history, 
# which would mean we backtracked to the initial start.
while history: 
    #random choose a candidata cell from the cell set histroy
    r,c = random.choice(history)
    M[r,c,4] = 1 # designate this location as visited
    history.remove((r,c))
    check = []
    # If the randomly chosen cell has multiple edges 
    # that connect it to the existing maze, 
    if c > 0:
        if M[r,c-1,4] == 1:
            check.append('L')
        elif M[r,c-1,4] == 0:
            history.append((r,c-1))
            M[r,c-1,4] = 2
    if r > 0:
        if M[r-1,c,4] == 1: 
            check.append('U') 
        elif M[r-1,c,4] == 0:
            history.append((r-1,c))
            M[r-1,c,4] = 2
    if c < num_cols-1:
        if M[r,c+1,4] == 1: 
            check.append('R')
        elif M[r,c+1,4] == 0:
            history.append((r,c+1))
            M[r,c+1,4] = 2 
    if r < num_rows-1:
        if M[r+1,c,4] == 1: 
            check.append('D') 
        elif  M[r+1,c,4] == 0:
            history.append((r+1,c))
            M[r+1,c,4] = 2
 
    # select one of these edges at random.
    if len(check):
        move_direction = random.choice(check)
        if move_direction == 'L':
            M[r,c,0] = 1
            c = c-1
            M[r,c,2] = 1
        if move_direction == 'U':
            M[r,c,1] = 1
            r = r-1
            M[r,c,3] = 1
        if move_direction == 'R':
            M[r,c,2] = 1
            c = c+1
            M[r,c,0] = 1
        if move_direction == 'D':
            M[r,c,3] = 1
            r = r+1
            M[r,c,1] = 1
         
# Open the walls at the start and finish
M[0,0,0] = 1
M[num_rows-1,num_cols-1,2] = 1
    
# Generate the image for display
for row in range(0,num_rows):
    for col in range(0,num_cols):
        cell_data = M[row,col]
        for i in range(10*row+2,10*row+8):
            image[i,range(10*col+2,10*col+8)] = 255
        if cell_data[0] == 1: 
            image[range(10*row+2,10*row+8),10*col] = 255
            image[range(10*row+2,10*row+8),10*col+1] = 255
        if cell_data[1] == 1: 
            image[10*row,range(10*col+2,10*col+8)] = 255
            image[10*row+1,range(10*col+2,10*col+8)] = 255
        if cell_data[2] == 1: 
            image[range(10*row+2,10*row+8),10*col+9] = 255
            image[range(10*row+2,10*row+8),10*col+8] = 255
        if cell_data[3] == 1: 
            image[10*row+9,range(10*col+2,10*col+8)] = 255
            image[10*row+8,range(10*col+2,10*col+8)] = 255
        
 
# Display the image
plt.imshow(image, cmap = cm.Greys_r, interpolation='none')
plt.show()

 

posted @ 2020-09-23 21:01  tao10203  阅读(140)  评论(0)    收藏  举报