一百行Ruby寫個A*

A* in Ruby

Ruby quiz的第98題讓寫一個A*尋路程序。Daniel Martin提供了一個不到兩百行的解答。如果簡化一下,完全可以在一百行以內實現。

 

 

在Daniel的程序裏,do_quiz_solution()是個外殼,它做三件事:找到起止點的座標(@start和@goal),把puzzle解析成數值矩陣(存在@terrain中),把puzzle轉換成沒有空格的規範形式存進instr以便後面利用它把路徑打印出來。

核心的部分是do_find_path()。這裏需要用到優先隊列PriorityQueue。優先隊列的元素也是一個複合結構:[優先級, [當前考察的點, 到達該點的最佳路徑, 目前花費的代價]]。

 

 

下面來看看如何實現優先隊列:

優先隊列可以看成一個半序的容器,它每次拋出優先級最低(或最高)的元素。優先隊列一般是用堆(一種滿足特定規則的完全二叉樹)來實現的,但這裏因爲優先隊列不是重點,Daniel利用Ruby內置的sort函數實現了一個簡單,而且性能不咋地的優先隊列。

@list是個數組。每次在add新元素時,會把優先級信息也一併記錄下來。另外,爲了區分相同優先級的元素,add()還會悄悄把該元素是第幾個加入隊列的元素也寫進去,即

 

然後sort!,保證數組按優先級進行排列。

接着來看看估價函數,它用來評估當前所在的位置到目標點的儘可能大的下界(最好比實際代價小)。在這裏,由於允許走斜線,只需考慮當前點與目標點橫縱座標差的最大值即可。

 

還有一個輔助函數spotfrom(),用來生成當前點周圍沒訪問過的鄰居。

 

最後,我們來看看它是怎麼把雜亂的字符串規整成標準形式的,以及又是如何依據規範字符地圖生成二位數值矩陣的。

逐行分析輸入的字符串:

  • 遇到由純空白符構成的行(/^/s*$/)就跳過;
  • 替換掉所有非.@~X*^符號; ;
  • 逐字分析
根據題設在數值矩陣的相應位置寫入相應的代價 

題目裏有個測試地圖。我想把結果用圖的形式顯示出來,對Ruby 這方面的庫又不熟,只好用Python了(需要用到matplotlib)。

 

P.S. 果然不習慣Python的語法。

large test map

紅色表示水塘,不能通過。

這是結果:

large test map solution

好醜,還不如ASCII碼:

 

發佈了72 篇原創文章 · 獲贊 3 · 訪問量 24萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章