一文看懂Python迷宮生成和迷宮破解算法

@本文來源於公衆號:csdn2299,喜歡可以關注公衆號 程序員學府
今天小編就爲大家分享一今天小編就爲大家分享一篇Python迷宮生成和迷宮破解算法實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧

1迷宮生成

1.隨機PRIM

思路:先讓迷宮中全都是牆,不斷從列表(最初只含有一個啓始單元格)中選取一個單元格標記爲通路,將其周圍(上下左右)未訪問過的單元格放入列表並標記爲已訪問,再隨機選取該單元格與周圍通路單元格(若有的話)之間的一面牆打通。重複以上步驟直到列表爲空,迷宮生成完畢。這種方式生成的迷宮難度高,岔口多。

效果:在這裏插入圖片描述
代碼:

import random
import numpy as np
from matplotlib import pyplot as plt
 
 
def build_twist(num_rows, num_cols): # 扭曲迷宮
    # (行座標,列座標,四面牆的有無&訪問標記)
 m = np.zeros((num_rows, num_cols, 5), dtype=np.uint8)
 r, c = 0, 0
 trace = [(r, c)]
 while trace:
  r, c = random.choice(trace)
  m[r, c, 4] = 1    # 標記爲通路
  trace.remove((r, c))
  check = []
  if c > 0:
   if m[r, c - 1, 4] == 1:
    check.append('L')
   elif m[r, c - 1, 4] == 0:
    trace.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:
    trace.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:
    trace.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:
    trace.append((r + 1, c))
    m[r + 1, c, 4] = 2
  if len(check):
   direction = random.choice(check)
   if direction == 'L': # 打通一面牆
    m[r, c, 0] = 1
    c = c - 1
    m[r, c, 2] = 1
   if direction == 'U':
    m[r, c, 1] = 1
    r = r - 1
    m[r, c, 3] = 1
   if direction == 'R':
    m[r, c, 2] = 1
    c = c + 1
    m[r, c, 0] = 1
   if direction == 'D':
    m[r, c, 3] = 1
    r = r + 1
    m[r, c, 1] = 1
 m[0, 0, 0] = 1
 m[num_rows - 1, num_cols - 1, 2] = 1
 return m

2.深度優先

思路:從起點開始隨機遊走並在前進方向兩側建立牆壁,標記走過的單元格,當無路可走(周圍無未訪問過的單元格)時重複返回上一個格子直到有新的未訪問單元格可走。最終所有單元格都被訪問過後迷宮生成完畢。這種方式生成的迷宮較爲簡單,由一條明顯但是曲折的主路徑和不多的分支路徑組成。

效果:在這裏插入圖片描述
代碼:

def build_tortuous(num_rows, num_cols): # 曲折迷宮
 m = np.zeros((num_rows, num_cols, 5), dtype=np.uint8)
 r = 0
 c = 0
 trace = [(r, c)]
 while trace:
  m[r, c, 4] = 1    # 標記爲已訪問
  check = []
  if c > 0 and m[r, c - 1, 4] == 0:
   check.append('L')
  if r > 0 and m[r - 1, c, 4] == 0:
   check.append('U')
  if c < num_cols - 1 and m[r, c + 1, 4] == 0:
   check.append('R')
  if r < num_rows - 1 and m[r + 1, c, 4] == 0:
   check.append('D')
  if len(check):
   trace.append([r, c])
   direction = random.choice(check)
   if direction == 'L':
    m[r, c, 0] = 1
    c = c - 1
    m[r, c, 2] = 1
   if direction == 'U':
    m[r, c, 1] = 1
    r = r - 1
    m[r, c, 3] = 1
   if direction == 'R':
    m[r, c, 2] = 1
    c = c + 1
    m[r, c, 0] = 1
   if direction == 'D':
    m[r, c, 3] = 1
    r = r + 1
    m[r, c, 1] = 1
  else:
   r, c = trace.pop()
 m[0, 0, 0] = 1
 m[num_rows - 1, num_cols - 1, 2] = 1
 return m

2.迷宮破解

效果:在這裏插入圖片描述
在這裏插入圖片描述

1.填坑法

思路:從起點開始,不斷隨機選擇沒牆的方向前進,當處於一個坑(除了來時的方向外三面都是牆)中時,退一步並建造一堵牆將坑封上。不斷重複以上步驟,最終就能抵達終點。

優缺點:可以處理含有環路的迷宮,但是處理時間較長還需要更多的儲存空間。

代碼:

def solve_fill(num_rows, num_cols, m): # 填坑法
 map_arr = m.copy() # 拷貝一份迷宮來填坑
 map_arr[0, 0, 0] = 0
 map_arr[num_rows-1, num_cols-1, 2] = 0
 move_list = []
 xy_list = []
 r, c = (0, 0)
 while True:
  if (r == num_rows-1) and (c == num_cols-1):
   break
  xy_list.append((r, c))
  wall = map_arr[r, c]
  way = []
  if wall[0] == 1:
   way.append('L')
  if wall[1] == 1:
   way.append('U')
  if wall[2] == 1:
   way.append('R')
  if wall[3] == 1:
   way.append('D')
  if len(way) == 0:
   return False
  elif len(way) == 1:   # 在坑中
   go = way[0]
   move_list.append(go)
   if go == 'L':    # 填坑
    map_arr[r, c, 0] = 0
    c = c - 1
    map_arr[r, c, 2] = 0
   elif go == 'U':
    map_arr[r, c, 1] = 0
    r = r - 1
    map_arr[r, c, 3] = 0
   elif go == 'R':
    map_arr[r, c, 2] = 0
    c = c + 1
    map_arr[r, c, 0] = 0
   elif go == 'D':
    map_arr[r, c, 3] = 0
    r = r + 1
    map_arr[r, c, 1] = 0
  else:
   if len(move_list) != 0:  # 不在坑中
    come = move_list[len(move_list)-1]
    if come == 'L':
     if 'R' in way:
      way.remove('R')
    elif come == 'U':
     if 'D' in way:
      way.remove('D')
    elif come == 'R':
     if 'L' in way:
      way.remove('L')
    elif come == 'D':
     if 'U' in way:
      way.remove('U')
   go = random.choice(way)  # 隨機選一個方向走
   move_list.append(go)
   if go == 'L':
    c = c - 1
   elif go == 'U':
    r = r - 1
   elif go == 'R':
    c = c + 1
   elif go == 'D':
    r = r + 1
 r_list = xy_list.copy()    
 r_list.reverse()   # 行動座標記錄的反轉
 i = 0
 while i < len(xy_list)-1:   # 去掉重複的移動步驟
  j = (len(xy_list)-1) - r_list.index(xy_list[i])
  if i != j:    # 說明這兩個座標之間的行動步驟都是多餘的,因爲一頓移動回到了原座標
   del xy_list[i:j]
   del move_list[i:j]
   r_list = xy_list.copy()
   r_list.reverse()
  i = i + 1
 return move_list

2.回溯法

思路:遇到岔口則將岔口座標和所有可行方向壓入棧,從棧中彈出一個座標和方向,前進。不斷重複以上步驟,最終就能抵達終點。

優缺點:計算速度快,需要空間小,但無法處理含有環路的迷宮。

代碼:

def solve_backtrack(num_rows, num_cols, map_arr): # 回溯法
 move_list = ['R']
 m = 1  # 回溯點組號
 mark = []
 r, c = (0, 0)
 while True:
  if (r == num_rows-1) and (c == num_cols-1):
   break
  wall = map_arr[r, c]
  way = []
  if wall[0] == 1:
   way.append('L')
  if wall[1] == 1:
   way.append('U')
  if wall[2] == 1:
   way.append('R')
  if wall[3] == 1:
   way.append('D')
  come = move_list[len(move_list) - 1]
  if come == 'L':
   way.remove('R')
  elif come == 'U':
   way.remove('D')
  elif come == 'R':
   way.remove('L')
  elif come == 'D':
   way.remove('U')
  while way:
   mark.append((r, c, m, way.pop()))    # 記錄當前座標和可行移動方向
  if mark:
   r, c, m, go = mark.pop()
   del move_list[m:]    # 刪除回溯點之後的移動
  else:
   return False
  m = m + 1
  move_list.append(go)
  if go == 'L':
   c = c - 1
  elif go == 'U':
   r = r - 1
  elif go == 'R':
   c = c + 1
  elif go == 'D':
   r = r + 1
 del move_list[0]
 return move_list

測試

rows = int(input("Rows: "))
cols = int(input("Columns: "))
 
Map = build_twist(rows, cols)
plt.imshow(draw(rows, cols, Map), cmap='gray')
fig = plt.gcf()
fig.set_size_inches(cols/10/3, rows/10/3)
plt.gca().xaxis.set_major_locator(plt.NullLocator())
plt.gca().yaxis.set_major_locator(plt.NullLocator())
plt.subplots_adjust(top=1, bottom=0, right=1, left=0, hspace=0, wspace=0)
plt.margins(0, 0)
fig.savefig('aaa.png', format='png', transparent=True, dpi=300, pad_inches=0)
 
move = solve_backtrack(rows, cols, Map)
plt.imshow(draw_path(draw(rows, cols, Map), move), cmap='hot')
fig = plt.gcf()
fig.set_size_inches(cols/10/3, rows/10/3)
plt.gca().xaxis.set_major_locator(plt.NullLocator())
plt.gca().yaxis.set_major_locator(plt.NullLocator())
plt.subplots_adjust(top=1, bottom=0, right=1, left=0, hspace=0, wspace=0)
plt.margins(0, 0)
fig.savefig('bbb.png', format='png', transparent=True, dpi=300, pad_inches=0)

非常感謝你的閱讀
大學的時候選擇了自學python,工作了發現吃了計算機基礎不好的虧,學歷不行這是
沒辦法的事,只能後天彌補,於是在編碼之外開啓了自己的逆襲之路,不斷的學習python核心知識,深入的研習計算機基礎知識,整理好了,如果你也不甘平庸,那就與我一起在編碼之外,不斷成長吧!
其實這裏不僅有技術,更有那些技術之外的東西,比如,如何做一個精緻的程序員,而不是“屌絲”,程序員本身就是高貴的一種存在啊,難道不是嗎?[點擊加入]想做你自己想成爲高尚人,加油!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章