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的語法。
紅色表示水塘,不能通過。
這是結果:
好醜,還不如ASCII碼: