Python實(shí)現(xiàn)迷宮自動(dòng)尋路實(shí)例
背景
我打開(kāi)手機(jī),發(fā)現(xiàn)有人在QQ空間里叫囂。
看他得意的樣子,顯然是在家里呆久了,已經(jīng)忘了天有多高。
預(yù)處理
設(shè)計(jì)一個(gè)迷宮自動(dòng)尋路算法并不難,但是對(duì)于當(dāng)下這個(gè)任務(wù)而言,第一個(gè)棘手的地方在于,如何把這個(gè)迷宮變成計(jì)算機(jī)認(rèn)識(shí)的樣子,也就是迷宮圖片的矩陣化。
圖片的大小是397×390
。先把四周的白邊裁掉,再把這幅圖中的每一個(gè)像素二值化,再根據(jù)顏色賦值,黑色用0
表示,白色用1
表示,建立一個(gè)0/1
矩陣。考慮到迷宮的邊界都是封閉的,為了防止由于圖片質(zhì)量問(wèn)題導(dǎo)致某些看上去是0
的地方其實(shí)是1
,在之后走迷宮的過(guò)程中造成一些可預(yù)知的影響,比如列表的越界等,我們?cè)侔阉臈l邊上的元素全部強(qiáng)制變成0
。這時(shí),對(duì)迷宮的預(yù)處理已經(jīng)基本完成,如果我們把1
隱藏,把所有的0
打印出來(lái),經(jīng)過(guò)放縮之后,就得到了這樣的結(jié)果:
尋路算法
得到了這個(gè)迷宮矩陣之后,我們需要找到一條從左上角到右下角的路。
印象中我與有關(guān)走迷宮的方法有過(guò)一面之緣,那是在一節(jié)算法選修課上,老師在臺(tái)上深情地講著深度優(yōu)先搜索與廣度優(yōu)先搜索,我在臺(tái)下忘我地抄著大物實(shí)驗(yàn)報(bào)告。至今,提起這兩個(gè)概念,我唯一的印象只有它倆的英文縮寫(xiě)一個(gè)是D開(kāi)頭一個(gè)是B開(kāi)頭。
不過(guò)沒(méi)關(guān)系。當(dāng)年陳刀仔他能用20塊贏到3700萬(wàn),我用for循環(huán)
搞定這個(gè)小迷宮,沒(méi)有問(wèn)題。
一般來(lái)說(shuō),迷宮的內(nèi)部是不封閉的,我從任意一個(gè)地方倒水,總能把整個(gè)迷宮填滿(mǎn)。因此,假定我們有一個(gè)小老鼠,把它放在起點(diǎn),如果它能夠保證自動(dòng)避障、不踩走過(guò)的路、遇死胡同回退,那么它總能找到終點(diǎn)。
因此,我們定義一個(gè)點(diǎn)(x,y)
,初始位置為(1,1)
,也就是邊界內(nèi)左上角的第一個(gè)點(diǎn)。
定義兩個(gè)列表,一個(gè)是path
,用來(lái)存放它最終確定下來(lái)的路徑(也就是那個(gè)最終走到終點(diǎn)的路徑)中的每一個(gè)點(diǎn);另一個(gè)是footprint
,用來(lái)存放所有它走過(guò)的地方,包括它走的錯(cuò)路。兩個(gè)列表形如[(1,1),(1,2),(2,2),......,(m,n)]
。
再定義四種動(dòng)作,分別是:向下走一步(y=y+1)
,向右走一步(x=x+1)
,向左走一步(x=x-1)
和向上走一步(y=y-1)
。我們每次讓這個(gè)點(diǎn)嘗試四種動(dòng)作,如果能走就讓它走。判斷是否不能走是看下一步的坐標(biāo)是否是墻或者是足跡。把新的點(diǎn)放進(jìn)path
和footprint
里,成為新的足跡。
確定四個(gè)動(dòng)作的優(yōu)先級(jí),即下、右、左、上
,能下則下,不能下則右,不能右則左,不能左則上。這樣它就不會(huì)在一個(gè)空地上平白無(wú)故地亂轉(zhuǎn),而是具有一定方向性地探索。
接下來(lái),讓算法具備自動(dòng)回退的能力。我們想象一個(gè)簡(jiǎn)單情景:
這個(gè)圖不準(zhǔn)確,不滿(mǎn)足本文的優(yōu)先級(jí)設(shè)定,但也足以表意
遇到這樣的死胡同,假如進(jìn)來(lái)的時(shí)候足跡把出去的路給封死了,那么這個(gè)點(diǎn)就沒(méi)辦法再出來(lái)了。一旦我們發(fā)現(xiàn)這個(gè)點(diǎn)陷入了絕境,哪里都不能走了,這時(shí)候我們就得讓它原路返回。實(shí)迷途其未遠(yuǎn),回到上一個(gè)路口也很簡(jiǎn)單,無(wú)非就是刪掉這一段路線。方法就是把path
列表里的最后一個(gè)元素逐一彈出列表,由于我們有footprint
記錄,所有它走過(guò)的地方都不能再走第二遍,所以只要這條錯(cuò)誤的路沒(méi)有完全退出去,退到哪一步都是四個(gè)方向都不能走的,因?yàn)楦浇急凰哌^(guò)了。這樣它就會(huì)一直退到我們期望的那個(gè)地方,也就是它誤入歧途的那個(gè)路口。
測(cè)試
下面,我們讓它開(kāi)始循環(huán)。只要它的坐標(biāo)不等于終點(diǎn)的坐標(biāo),我們就一直讓它不斷地探索。運(yùn)行結(jié)束后,我們得到了一條迂回的曲線,如圖(局部)。
程序成功得到了一條可以通往終點(diǎn)的路徑,但這條路徑過(guò)于冗雜,以上圖為例,所有寬度不為1
的地方都是這個(gè)點(diǎn)繞來(lái)繞去所導(dǎo)致的。因此,該路徑還有待優(yōu)化。
優(yōu)化
我們考慮如下一種簡(jiǎn)單情況:
在這條路線中,顯然4
~9
屬于沒(méi)有意義的兜圈,正確的路線應(yīng)該是從3
直接到10
。
我們的優(yōu)化方法是:如果第n步
在(x,y)
,從第n+2步
(也就是下一步的下一步),一直到最后一步,這中間只要有一步落在(x,y)
一步之遙的地方,就把從第n+1步
到這一步的所有路徑點(diǎn)都刪掉。拿上面這個(gè)例子來(lái)說(shuō),我們從第1步
開(kāi)始檢查。檢查到第3步
時(shí),我們從第5步
開(kāi)始看,一直看到第10步
發(fā)現(xiàn)10
落在3
一步就能到達(dá)的地方,這時(shí)我們把中間的4-9
全部刪掉,直接把10
接在3
的后面。
不過(guò),考慮到后面可能還會(huì)有更優(yōu)的情況,比如說(shuō)從12
開(kāi)始繼續(xù)繞,繞到20
發(fā)現(xiàn)20
剛好落在3
的上面,那我們事實(shí)上應(yīng)該直接把20
接在3
后面,12
也要丟掉,之前的方法有些缺陷。因此,為了避免這種情況,我們逆著循環(huán),對(duì)于第3步
而言,我們從第20步
往前循環(huán),一直循環(huán)到第5步
,看是否有3能直接到達(dá)的地方。這樣我們就能對(duì)這條路線進(jìn)行最大優(yōu)化了。
繪制路徑
最終,我們得到了正確而簡(jiǎn)潔的路徑,也記錄了曾經(jīng)走過(guò)的錯(cuò)路和多走的路。
根據(jù)矩陣和圖片的對(duì)應(yīng)關(guān)系,我們把圖片里對(duì)應(yīng)的像素改變顏色,其它點(diǎn)不作更改。
繪制路徑:
優(yōu)化之前:
全部足跡:
結(jié)語(yǔ)
至此,我們已經(jīng)把這個(gè)問(wèn)題解決得差不多了。整個(gè)程序在我的電腦上運(yùn)行下來(lái)大概需要三五分鐘這個(gè)樣子,畢竟是只用for循環(huán)
的暴力方法。
相關(guān)文章
關(guān)于pandas-profiling的降級(jí)之旅
這篇文章主要介紹了關(guān)于pandas-profiling的降級(jí)之旅,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11python學(xué)習(xí)筆記之調(diào)用eval函數(shù)出現(xiàn)invalid syntax錯(cuò)誤問(wèn)題
python是一門(mén)多種用途的編程語(yǔ)言,時(shí)常扮演腳本語(yǔ)言的角色。一般來(lái)說(shuō),python可以定義為面向?qū)ο蟮哪_本語(yǔ)言,這個(gè)定義把面向?qū)ο蟮闹С趾兔嫦蚰_本語(yǔ)言的角色融合在一起。很多時(shí)候,人們常常喜歡用“腳本”和不是語(yǔ)言來(lái)描述python的代碼文件。2015-10-10python實(shí)現(xiàn)感知機(jī)線性分類(lèi)模型示例代碼
這篇文章主要給大家介紹了關(guān)于python實(shí)現(xiàn)感知機(jī)線性分類(lèi)模型的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用python具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06Python使用bar繪制堆積/帶誤差棒柱形圖的實(shí)現(xiàn)
本文先講解bar參數(shù)如何使用,然后分別演示堆積柱形圖和帶誤差柱形圖畫(huà)法。具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09Python動(dòng)態(tài)創(chuàng)建類(lèi)實(shí)例詳解
這篇文章主要為大家介紹了Python動(dòng)態(tài)創(chuàng)建類(lèi)實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12python包pdfkit(wkhtmltopdf)?將HTML轉(zhuǎn)換為PDF的操作方法
pdfkit,把HTML+CSS格式的文件轉(zhuǎn)換成PDF格式文檔的一種工具。它就是html轉(zhuǎn)成pdf工具包wkhtmltopdf的Python封裝。所以,必須手動(dòng)安裝wkhtmltopdf,這篇文章主要介紹了python包pdfkit(wkhtmltopdf)將HTML轉(zhuǎn)換為PDF,需要的朋友可以參考下2022-04-04