制作迷宮地圖和行走路線(2)
說(shuō)在前面
上節(jié)課我們介紹了“使用深度優(yōu)先搜索算法生成不含環(huán)迷宮”的方法,該程序只完成了構(gòu)造隨機(jī)迷宮圖案的功能,卻沒(méi)有記錄通道行進(jìn)路線。這樣只能通過(guò)肉眼觀察迷宮,手動(dòng)繪制從起點(diǎn)到終點(diǎn)的路線,而不能讓電腦自動(dòng)繪制行走路線。我們可以在繪制迷宮通道的同時(shí),把通道前進(jìn)的方向也記錄下來(lái),為后期遍歷迷宮做好準(zhǔn)備工作。
今天我們就在上節(jié)課代碼的基礎(chǔ)上,增加記錄迷宮路線的功能;并實(shí)現(xiàn)給定任意起點(diǎn)和終點(diǎn)坐標(biāo),讓電腦自動(dòng)繪制行走路線的功能。
第2節(jié)??????使用深度優(yōu)先搜索算法生成迷宮并尋找路徑

第1節(jié)課介紹的程序只完成了構(gòu)造隨機(jī)迷宮圖案的功能,卻沒(méi)有記錄通道行進(jìn)路線。這樣只能通過(guò)肉眼觀察迷宮,手動(dòng)繪制從起點(diǎn)到終點(diǎn)的路線,而不能讓電腦自動(dòng)繪制行走路線。我們可以在繪制迷宮通道的同時(shí),使用二維數(shù)組route記錄迷宮路線,其中route[r][c]的值是一個(gè)列表,存儲(chǔ)了與格子(r, c)連通的相鄰格子的行列下標(biāo)(i, j),有幾個(gè)格子與(r, c)相鄰且連通,route[r][c]就有幾個(gè)元素。
'''函數(shù)功能:使用深度優(yōu)先搜索來(lái)生成不含環(huán)迷宮,并記錄通道走向函數(shù)名:dfs(r, c)參數(shù)表:r,c -- 表示當(dāng)前格子在二維數(shù)組maze中的行列下標(biāo)。返回值:把二維數(shù)組maze和route當(dāng)做全局變量,直接使用畫筆繪制迷宮通道,不需要返回值。'''def dfs(r, c):# 標(biāo)記(r, c)來(lái)過(guò)maze[r][c] = 1# 走到(r, c)tt.goto(start_x+c*size, start_y-r*size)# (r, c)的上下左右位置d = [(r - 1, c), (r + 1, c), (r, c - 1), (r, c + 1)]# 打亂位置,下一個(gè)位置是隨機(jī)的random.shuffle(d)for (i, j) in d:# 選所有可以走的下一個(gè)點(diǎn),如果此點(diǎn)在范圍內(nèi)并且沒(méi)去過(guò)if 0<=iand 0<=jand maze[i][j]==0: route[r][c].append((i, j)) # 記錄與(r, c)連通的位置(i, j)route[i][j].append((r, c)) # 記錄與(i, j)連通的位置(r, c)# 遞歸去走下一個(gè)點(diǎn)dfs(i, j)# 回溯到(r, c)tt.goto(start_x+c*size, start_y-r*size)
2.使用深度優(yōu)先搜索來(lái)尋找路徑
有了二維數(shù)組route記錄的通道行進(jìn)信息,就可以給定任意起點(diǎn)和終點(diǎn)坐標(biāo),讓電腦自動(dòng)繪制行走路線。我們先將maze歸零,以便重新遍歷地圖。同時(shí)定義列表ans來(lái)存儲(chǔ)行走路徑,先將終點(diǎn)加入到ans中,之后逆序添加各個(gè)格子的行列下標(biāo)。
那么使用什么方法來(lái)遍歷地圖呢?
最容易想到的方法是模仿構(gòu)造迷宮地圖,使用深度優(yōu)先搜索算法。我們可以定義函數(shù)dfs_ans(r, c),把列表maze和ans當(dāng)做全局變量(因?yàn)榱斜硎强勺儗?duì)象,即使不聲明為global變量,仍可以修改其元素值),若從當(dāng)前格子出發(fā)能夠到達(dá)終點(diǎn),返回True,否則False。
函數(shù)遍歷與當(dāng)前格子(r, c)連通的相鄰格子route[r][c],遞歸處理通道上的每一個(gè)格子,直到終點(diǎn)。若當(dāng)前格子與終點(diǎn)連通,將當(dāng)前格子行列下標(biāo)添加到ans,并返回True,否則返回False。
'''函數(shù)功能:使用深度優(yōu)先搜索來(lái)尋找路徑函數(shù)名:dfs_ans(r, c)參數(shù)表:r,c -- 表示當(dāng)前格子在二維數(shù)組maze中的行列下標(biāo)。返回值:把列表maze和ans當(dāng)做全局變量,若從當(dāng)前格子出發(fā)能夠到達(dá)終點(diǎn),返回True,否則False。'''def dfs_ans(r, c):if r==r2 and c==c2:return Truefor (i, j) in route[r][c]:if maze[i][j] == 0: # 如果沒(méi)有去過(guò)該點(diǎn),則遞歸搜索該點(diǎn)maze[i][j] = 1 # 標(biāo)記該點(diǎn)已經(jīng)來(lái)過(guò)# 遞歸去走下一個(gè)點(diǎn)if dfs_ans(i, j): #若當(dāng)前格子與終點(diǎn)連通,將當(dāng)前格子行列下標(biāo)加入到ansans.append((r, c))return Truereturn False
3.繪制使用深度優(yōu)先搜索獲得的路徑
有了列表ans存儲(chǔ)的路徑信息,就可以繪制行走路線了。因?yàn)閍ns的元素值是采用回溯算法依次添加的,所以離終點(diǎn)越近的格子越早添加到ans中。因此我們需要逆序遍歷ans,才可以順序輸出從起點(diǎn)到終點(diǎn)的路線。我們定義函數(shù)display_ans()實(shí)現(xiàn)該功能,參考代碼如下:
'''函數(shù)功能:根據(jù)ans的值,繪制使用深度優(yōu)先搜索獲得的路徑函數(shù)名:display_ans()參數(shù)表:直接使用列表ans的元素值,不需要任何參數(shù)。返回值:直接利用畫筆繪制路線,不需要返回值。'''def display_ans():tt.speed(1)tt.pensize(size*0.5) # 路線粗細(xì)tt.color("red")tt.penup()tt.goto(start_x+ans[-1][1]*size, start_y-ans[-1][0]*size)tt.pendown()for (r, c) in ans[-2::-1]: #逆序遍歷ans,剛好可以順序輸出從起點(diǎn)到終點(diǎn)的路線tt.goto(start_x+c*size, start_y-r*size)
4.主函數(shù)部分代碼
tt.TurtleScreen._RUNNING = Truett.ht()tt.bgcolor('black')tt.color("white")tt.speed(3)w, h = 20, 20size = 30tt.pensize(size*0.8)maze = [[0] * w for i in range(h)]route = [[[] for j in range(w)] for i in range(h)] #記錄迷宮路線start_x = -w / 2 * sizestart_y = h / 2 * sizett.penup()tt.goto(start_x, start_y)tt.pendown()dfs(0, 0)r1, c1 = [int(i) for i in input("起點(diǎn)行列下標(biāo):").split()]r2, c2 = [int(i) for i in input("終點(diǎn)行列下標(biāo):").split()]maze = [[0] * w for _ in range(h)] # 將maze歸零,重新遍歷地圖maze[r1][c1] = 1ans = [(r2, c2)]dfs_ans(r1, c1)display_ans()tt.done()
代碼說(shuō)明:
與第1節(jié)課的程序相比,本節(jié)課程序在主函數(shù)中增加了一個(gè)二維數(shù)組route,用來(lái)記錄記錄迷宮路線。還增加了使用深度優(yōu)先搜索來(lái)尋找路徑的功能:先從鍵盤依次讀入起點(diǎn)行、列下標(biāo)(用空格隔開(kāi))和終點(diǎn)行、列下標(biāo),然后將maze歸零,以便重新遍歷地圖。定義列表ans,并將終點(diǎn)的行列下標(biāo)(r2, c2)作為ans的第一個(gè)元素,之后調(diào)用函數(shù)dfs_ans(),使用深度優(yōu)先搜索算法逆序添加各個(gè)格子信息到ans中。最后調(diào)用函數(shù)display_ans()繪制使用深度優(yōu)先搜索獲得的路徑。
本節(jié)課介紹的程序是使用深度優(yōu)先搜索算法來(lái)尋找路徑的,除此之外,我們還可以使用廣度優(yōu)先搜索算法來(lái)尋找路徑。請(qǐng)查閱廣度優(yōu)先搜索算法相關(guān)知識(shí),設(shè)置自定義函數(shù),實(shí)現(xiàn)給定任意起點(diǎn)和終點(diǎn)坐標(biāo),使用廣度優(yōu)先搜索算法來(lái)尋找路徑、并繪制行走路線的功能。
需要本文PPT、源代碼和課后練習(xí)答案的,可以加入“Python算法之旅”知識(shí)星球參與討論和下載文件,“Python算法之旅”知識(shí)星球匯集了數(shù)量眾多的同好,更多有趣的話題在這里討論,更多有用的資料在這里分享。
我們專注Python算法,感興趣就一起來(lái)!
相關(guān)優(yōu)秀文章:
