迷宮問題python實現(靠右手摸牆)


大家好,我是小鴨醬,博客地址為:http://www.cnblogs.com/xiaoyajiang

這是大二時候的數學模型畢業課程設計,我選擇了自己研究盲人穿越迷宮的問題。當然后來再在網上查了這個問題研究比較成熟了,但是自己研究出來了也是小有成果的。

當時是用C++實現的,而且用了不必要的遞歸來進行。

現簡化為簡單的循環,並使用python實現了。

以下進行我自己設計算法的思路設計,最后附上現在的python源碼

 

@”表示牆,“·”表示迷宮中可行路線上的空格,走過的路線用“X”表示。本問題只研究12×12規模且只有一個入口和一個出口(迷宮也許會不通)的迷宮。如何從入口走到出口?

算法分析

問題一, 迷宮構造   

首先,我用二維字符型數組來表示迷宮的牆和可行路

其次,可由系統產生01的隨機數來控制每一個位置產生牆的概率,當然,如果要使概率可變動,那也無非是傳遞一個值而已。為使問題簡單化,我將產生牆的概率設置為30%

第三,將第一行和最后一行全部設置為牆,第一列和最后一列均只有一個可行路。

問題二, 穿越方式

分析 

這類問題解決的方法應該很多,但就我現在掌握的以及現在的靈感,我只能想到蠻力的辦法。

解決

一直沿着穿越者的右手邊的牆壁走,如若此迷宮是通的,那一定能找到出口!

用遞歸的辦法,我只需要研究當前的位置到下一步的過程就可以了。

問題三, 方向控制

分析

1、我設置的是二維數組,其動態必須通過數組的下標來控制

2、對於穿越者來說,他的方向只有前后左右,人在其中必定是不知道自己的坐標的

3、有了方向才不能迷失,這對於我們的穿越者也同樣如此,每一次作的決策就是選擇方向,即向左轉90°還是不轉還是向右轉90°,這里規定穿越者一次只能選擇其中一種,向左轉和向右轉的次數從最開始就累計,且一次向左轉和一次向右轉可抵消為不轉

4、由於迷宮是隨機構造的,所以也有可能出現類似漩渦一樣的路徑,所以累計的向左轉或者向右轉的次數也有可能超過3次,即在空間存在轉的角度超過360°,那么就需要研究同一方向上的轉動次數的規律。

解決

根據以上分析,需要將做決策時穿越者的狀態,具體的說就是穿越者面向的方向,用坐標絕對位置來表示出來。

規定初始位置人的朝向是坐標方位向右用sum=0表示;

每一次穿越者向自己的左邊轉一次,sum就減1

每一次穿越者向自己的右邊轉一次,sum就加1

將同一方向上的數字進行研究,可以發現其內在的規律:

絕對向右的數字有…-12,-8,-4,0,4,8,12=4n

絕對向上的數字有…-13,-9,-5,-1,3,7,11=4n-1

絕對向左的數字有…-14,-10,-6,-2,2,6,10=4n-2

據對向下的數字有…-11,-7,-3,1,5,9,13=4n+1

由上觀察,我發現余數sum%4與方向是對應的,就是說余數可以作為方向的判斷標志,根據C++%的定義和用法,發現余數與被除數的符號一致,所以這樣每個方向上有兩個余數(絕對向右的除外,因為其余數為0),且它們都區別於其他方向上的余數。

這樣容易得出——

設人的當前坐標為a[i][j]

sum%4=0時,人絕對向右,此時若向前走一步,則為a[i][j+1]

sum%4= 3 or -1 時,人絕對向上,此時若向前走一步,則為a[i-1][j]

sum%4= -3 or 1 時,人絕對向下,此時若向前走一步,則為a[i+1][j]

sum%4= -2 or 2 時,人絕對向左,此時若向前走一步,則為a[i][j-1]

問題四,決策分析

過程決策

分析1

假設前面的路都沒有走過

這是核心問題。

這里分析時假定此時人的當前絕對方位是面向右的。

1、 當前穿越者位置特征分析

      可以肯定,當前位置特征必定是穿越者的右邊是一堵牆

2、 

穿越者前

1、 前面環境分析

       根據排列組合知識可知,有4種情況,即

 

      1                  2                   3                      4

      X·               X@                 X @                    X·

  @@               @@                 @·                   @·

人前有路,路右有牆 人前有牆,牆右有牆 人前有牆,牆右有路 人前有路,路右有路

解決1

根據分析,決策可分為三類,即將23合並

 1                     2                              3

      X·               X @        X @                   X·

   @@               @@        @·                   @·

針對以上3種情況,可有與之相對應的3種決策

對於1,前進一步

對於2,向左轉

對於3,前進一步,向右轉,前進一步

這樣,可以看到經過這樣的決策,可使得人的右面是牆,便可重復進行上面的決策,遞歸便有作用了。整個穿越過程,便是以上過程的循環。

分析2與解決2

    如果前面的路走過,即前方有“X”,將其與“.”一同看待處理。

 

問題五,決策分析

邊界決策

分析

根據問題四,可對過程進行決策,但對於遞歸問題,還有關鍵的一點就是邊界分析決策。可以注意到,此問題由於是隨機產生的迷宮,所以存在不通路的情況,也就是可能會走回出發點。雖然結果也許我們認為是不同的,但是對於數組來說,都是越界。

解決

每一次都對其進行越界判斷。如果下一步的坐標經判斷是越界的,就不再需要進行問題四的操作了,就可以直接輸出二維數組了,我們的問題也就解決了!

 

python實現如下:

 1 #!usr/bin/python
 2 #Filename: maze.py
 3 import random
 4 a = [['#']*12 for i in range(12)]
 5 turn = [[0,1],[1,0],[0,-1],[-1,0]]#right,down,left,up; turn[i+1] means you turn right
 6 for i in range(1,11):
 7     for j in range(1,11):
 8         if random.random() > 0.3:#the wall is generated with the prosibility of 0.3
 9             a[i][j] = ' '
10 a[1][1] = a[10][11] = a[10][10] = ' '#the maze is generated completely
11 raw = 1#current raw number
12 column = 0#current column number
13 face = 0#0 means right, 1 means down, 2 means left, 3 means up 
14 a[raw][column] = 'X'
15 while column < 11:
16     if face == 3:
17         r_face = 0
18     else:
19         r_face = face + 1
20     if face == 0:
21         l_face = 3
22     else:
23         l_face = face - 1
24     ft_r = raw + turn[face][0]
25     ft_c = column + turn[face][1]
26     ftrt_r = ft_r + turn[r_face][0]
27     ftrt_c = ft_c + turn[r_face][1]
28     if a[ft_r][ft_c] == '#':
29         face = l_face
30     elif a[ftrt_r][ftrt_c] == '#':
31         raw = ft_r
32         column = ft_c
33         a[raw][column] = 'X'
34     else:
35         raw = ftrt_r
36         column = ftrt_c
37         a[ft_r][ft_c] = a[raw][column] = 'X'
38         face = r_face
39     if column == 0:
40         print "The maze is death!\n"
41         break
42 for i in range(0,12):
43     for j in range(0,12):
44         print a[i][j],' ',
45     print '\n'

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM