量子計算機能快速求解推箱子關卡嗎?

 

作者:楊超

本文地址:http://sokoban.ws/blog/?p=3757

量子計算機常被大眾媒體描述得十分神奇,甚至有科學家也添油加醋,如 David Deutsch 的 The Fabric of Reality 一書。用量子計算機能設計出快速求解推箱子關卡的算法嗎?我在讀了David Deutsch的書后,對此問題頗感興趣。這個月,閱讀了不少相關文獻,找到了答案。答案是否定的。

首先,制造出通用的量子計算機仍然有極大的工程技術困難。

第二,再看看理論上,量子算法能干什么。最有名的量子算法就是Peter Shor的整數分解算法,這一算法使得基于大數分解比較困難的公鑰加密算法岌岌可危。Shor的算法是1994年提出(Shor因此獲得哥德爾獎Godel Prize),歷史也沒有太長。想要知道這一算法與傳統計算機算法有何不同,可讀Scott Aaronson的博文 《Shor, I’ll do it》。Scott Aaronson生于1981年,才36歲,是德州大學奧斯汀分校的教授,在理論計算機科學特別是計算復雜度理論方面有非常高的造詣。他博文中對Shor算法的核心解釋得深入淺出。關鍵是整數分解還是有某種規律,量子算法恰恰能更好地利用這一規律,一定程度上避免了暴力窮舉。

要注意的是,整數分解并非特別難的問題。在基于傳統計算機(圖靈機)的計算復雜度理論中,整數分解被認為不屬于P,但也只是比P問題略難一些,介于P和NP-Complete之間,且更靠近P。因此,量子算法能快速分解大數也只是情理之中。

知道量子算法是怎么做的,能做什么,就更好地理解量子算法不能做什么。Scott Aaronson博客的站名banner位置有這么一段話,澄清大眾對量子計算的誤解:

If you take just one piece of information from this blog: Quantum computers would not solve hard search problems instantaneously by simply trying all the possible solutions at once.

這句話翻譯過來就是:如果你想從我的博客中只學一樣東西,那就是量子計算機無法通過同時嘗試所有可能來求解困難的搜索問題。

這句話簡直是針對本文開頭的問題的完美回答。就算大規模的量子計算機制造出來了,NP完全問題也不可能有快速算法,更不用說比NP完全問題更難的推箱子(PSPACE完全問題)了。

第三,有和沒有快速算法(efficient algorithm)的分界線在哪里呢?Scott Aaronson在NP-complete Problems and Physical Reality一文(發表在2005年ACM SIGACT News)中也有深刻獨特的見解。除了量子計算,他還逐一考察了蛋白質計算等若干未來可能有物理實現的計算機模型。文章最后,他給出了如下的一條分界線:

基于圖靈機提出的P問題類也許未能很好的刻畫有快速算法問題全體。具有快速算法的問題應該更廣泛些,包含整數分解和圖同構等。這也許是一條深刻的物理規律。

 

 

發表在 推箱子, 數學, 算法, 計算機 | 留下評論

圍棋、推箱子和計算復雜度

 

本文地址:http://sokoban.ws/blog/?p=2330

作者:楊超

這個月,2016年3月,Google 的 DeepMind 團隊開發的圍棋程序 AlphaGo 在韓國首都以 4:1 戰勝世界冠軍圍棋九段李世石。早在近20年前,IBM 的國際象棋程序“深藍”就已經戰勝人類冠軍。而圍棋棋盤比較大,人們普遍認為人類對計算機程序的優勢在圍棋項目還可以保持比較長的時間。而這次 Google 團隊的勝利,證明了其實開發一個戰勝人類的下圍棋程序并沒有那么難,而是開發這樣的程序沒有太大的直接收益,哪怕是國際象棋和圍棋這樣就有悠久歷史傳統和廣泛的群眾基礎和關注度的棋類。

圍棋究竟有多難?我們拿它和推箱子來比較一下。恰好我剛剛完成了用三篇博文來介紹推箱子問題的計算復雜度:推箱子是PSPACE完全問題

為了從計算復雜度方面和推箱子問題比較,我們需要準確地定義一下什么叫圍棋問題

雖然人們常說圍棋的變化很多,但是無論變化有多少,終究是一個有限的數。所有有限步內能分出勝負的、沒有隱藏信息、也沒有運氣成分的二人棋類游戲,一定有一方有必勝策略(或者必和策略)。打個比分說,19路圍棋按照中國的貼目規則也許是先手有必勝策略。那么我們所說的圍棋問題,就是對于任意的n x n棋盤上下的圍棋,如何設計一個算法來確定究竟是先手必勝還是后手必勝?或者等價地說,先手究竟有沒有必勝策略?(即這是一個回答“是”或者“否”的問題)通常的19路棋盤圍棋是圍棋問題的一個實例。要回答這個問題,除了窮舉所有的對弈變化之外,人們暫時還沒能找到其它規律來判斷誰有必勝策略。對圍棋而言,窮舉所需要的時間隨著棋盤 n 的增大,是成指數增長的。事實上,已經有文獻證明,按日本規則,圍棋問題是EXPTIME完全問題(見[1,2],該文章作者猜測,若按中國規則,圍棋問題可能更難,成為指數空間完全問題)。也就是說,在指數時間可解的問題里面,圍棋問題是最困難的其中一個。除了圍棋,其它一些棋類問題如國際象棋、西洋跳棋(checkers)都被證明是EXPTIME完全問題。其中8×8棋盤的西洋跳棋在使用計算機花了近20年的窮舉計算后,在2007年被證明雙方都采取完美策略一定是和棋。

所以,從計算復雜度來看,包括圍棋在內的許多棋類游戲比推箱子要難一個層次。計算復雜度的幾個概念(EXPTIME、PSPACE、NP、P)的關系可用下圖表示。雖然還沒有從理論上嚴格證明,但是一般認為,從內到外,這四類問題的計算復雜度是嚴格地越來越難。

更有甚者,圍棋問題的一些子問題,如征子能否成功問題在文獻中被證明是PSPACE完全問題[3]。而圍棋殘局收官問題,則是PSPACE難的[4]。也就是說圍棋問題的某些子問題就已經和推箱子問題一樣難了。

那么,為什么比推箱子更難的圍棋都已經開發出能戰勝人類的程序,但是比圍棋還容易一些的推箱子,我們卻沒有看到優秀的推箱子求解程序能夠解出較大的、箱子數目較多的關卡呢?我想主要有以下這么一些因素。

首先,開發推箱子求解程序比開發下圍棋程序更加無利可圖。目前看到的一些求解程序基本都是個人單打獨斗編寫的,運行在個人電腦上,而且都是作為業余興趣進行的。尚未看到有軟件類企業或者研究團隊投入較大資源來開發。作為對比,Google的AlphaGo程序投入了至少20人的開發團隊,和李世石對戰時動用了上千個CPU和GPU同時計算。

其次,AlphaGo雖然戰勝了人類,但是并沒有回答我們前面所定義的圍棋問題,也就是說并不知道是否先手必勝。戰勝人類并不需要窮遍所有變化,比判斷19路圍棋誰有必勝策略稍微容易一些。而一個推箱子關卡求解程序從某種意義上必須回答出推箱子問題,一般來說,必須窮遍所有路經才能判斷一個關卡無解。而找到一個答案,除了窮舉剪枝之外也還沒有見到有人提出新的算法思路。

比較令人好奇的是,如果投入更多的人力和計算機運算資源,計算機求解推箱子能達到一個什么樣的水平呢?能解出多大的關卡?解大關卡能比人解得更快嗎?

第83期推箱子比賽,我們也借著這個機會,由麥英兄設計了一關AlphaGo關卡。這一關計算機能解出來嗎?

[參考文獻]

1.? J. M. Robson, The complexity of Go, Proc. IFIP (1983) 413-417.

2. J. M. Robson, Combinatorial games with exponential space complete decision problems, Proc. Mathematical Foundations of Computer Science, Springer-Verlag, LNCS 176, 1984, pp. 498-506

3. M. Crasmaru and J. Tromp, Ladders are PSPACE-complete, Proc. 2nd Int. Conf. Computers and Games, Springer-Verlag, LNCS 2063, 2000, pp. 241-249

4. D. Wolfe, Go Endgames Are PSPACE-Hard, More Games of No Chances, MSRI Publications, Volume 42, 2002, pp. 125-136

 

發表在 推箱子, 數學, 計算機 | 留下評論

推箱子是PSPACE完全問題

 

本文地址:http://sokoban.ws/blog/?p=2254

作者:楊超

本文是兩篇博文《 一系列具有遞歸關系和指數長度答案的推箱子關卡》《 判斷推箱子關卡是否有解的多項式空間的算法》 的續篇。這三篇博文構成推箱子與PSPACE問題三部曲。

一、什么是PSPACE完全問題(PSPACE-complete problems)

前兩篇文章已經提過,PSPACE問題指的是:相對于實例(instance)的大小,存在多項式空間算法的判斷性問題(decision problem)。

PSPACE完全問題是PSPACE問題中最困難的一類。即一個問題A能夠被稱為PSPACE完全問題,如果問題A滿足:對任何其他的PSPACE問題B,都存在一個多項式時間的方法把B的實例轉化成A的實例,使得這兩個實例在這兩個問題中有相同的答案(都是“是”或者都是“否”)。由此定義,只要能給出某個PSPACE完全問題的快速算法,那么這個算法就可以用來解決所有的PSPACE問題。

我們這里所說的推箱子問題(SOKOBAN),指的是給出一個推箱子關卡(即實例),如何判斷這個關卡是否有解。

無論從實踐到理論,都有證據表明推箱子是非常困難的。

實踐中,我們舉辦了好幾年的MF8推箱子網絡比賽,尚未見到有人或者組織能夠用計算機快速解出我們的比賽主關。

在計算復雜性理論中,推箱子問題也被證明是一個PSPACE完全問題。本文的目的就是簡單介紹一下這些證明。要證明推箱子問題(或者其他問題)是PSPACE完全問題,要論證兩個方面:

一是推箱子首先是PSPACE問題。因為存在很多問題,其難度甚至超出PSPACE的范圍,我們需要說明推箱子沒有超出這個范圍。這一點的證明較為容易,已經在三部曲的第二篇文中說過了。

二是證明推箱子是PSPACE問題里面最難的。這又有兩種常用的方法,第一種方法是按照定義,描述一種方案把任何一個PSPACE問題的實例轉化為推箱子實例。第二種方法就是,描述一種方案,把某一個已經被證明的PSPACE完全問題的每個實例轉化成推箱子的實例。

無論是用那種方法證明,其技術性都是比較高的,比較依賴于巧妙的構思。

二、PSPACE完全問題的例子

已經有許許多多的問題被證明是PSPACE完全問題。這些問題可以被用來證明其他問題也是PSPACE完全問題。這里介紹兩個比較有代表性的。

第一個是TQBF問題(True Quantified Boolean Formula)。這個問題的一個實例就是一個每個變量都帶有量詞(存在、任意)的布爾邏輯公式。公式中的每個變量只能取值“真”或者“假”。

如:(任意x)(存在y)(存在z) ((x或者y)并且z)

我們需要判斷這樣的一個公式是否總是“真”的。

第二個是LBA問題,即線性空間自動機(Linear Bounded Automata)。這個問題的一個實例是:給出一個線性空間自動機和一個輸入,該自動機是否接受該輸入。

這個問題的PSPACE完全性證明非常簡單。因此利用此問題證明推箱子問題是PSPACE完全問題,和直接用定義證明推箱子問題是PSPACE完全問題,幾乎沒有多大區別。

除此之外,推箱子和滑塊類游戲也是PSPACE完全問題的有趣例子。

三、推箱子是PSPACE完全問題

Dorit Dor和Uri Zwick在1996年寫文章[1]研究了推箱子問題的計算復雜度,但未能證明推箱子是PSPACE完全的。加拿大阿爾伯特大學的Joseph C. Culberson看到該文后,在1997年就證明了推箱子是PSPACE完全問題[2]。

Culberson的證明方法是把LBA問題的實例轉化為推箱子問題的實例。為此,他利用推箱子的規則設計了一些巧妙的局部關卡模塊。這些模塊限定了推箱子中的人為了過關,只能按照規定的路線走。把這些不同功能的模塊拼接起來,通過人的行走路徑,可以模擬圖靈機(即自動機)的運行。這樣任何一個LBA問題的實例就能轉換為一個推箱子關卡。LBA問題的實例有肯定的回答當且僅當相應的推箱子關卡有解。

后來,在2005年前后,麻省理工大學的博士生Robert A. Hearn又給出了推箱子是PSPACE完全問題的另一種的證明方法[3,4]。Hearn先定義了一種抽象游戲NCL(Nondeterministic Constraint Logic,Hearn稱之為一種計算模型)。通過把TQBF的每個實例轉化為NCL的實例,Hearn證明了NCL問題也是PSPACE完全問題。Hearn定義的這個新問題NCL問題有一個好處就是,通過它來證明包括推箱子、滑塊類在內的一些益智游戲是PSPACE完全問題,相對來說顯得比較簡單和清晰。

然后,Hearn把NCL的每個實例轉化為推箱子的實例。在這個過程中,Hearn也是設計了一些具有不同功能的推箱子局部關卡模塊。和Culberson的證明不同的是,Hearn的模塊中,主要利用推箱子規則,使得一些箱子只能要么處于目標點,要么只能偏離目標點一格,這樣完美地模擬了NCL游戲中的核心要素:0和1兩種狀態。并且,這種轉化同樣保證了NCL的實例有解當且僅當相應的推箱子實例(關卡)有解。

下圖示意兩種證明的總體思路的區別。

從實例的轉化設計的細節上,Culberson主要利用人的行走路線模擬圖靈機的運行。Hearn主要利用箱子的狀態來模擬0、1兩種狀態,轉化得到的關卡對人來說是“開放”的,可以隨時訪問任何一個箱子,不存在行走路徑的限制。兩者都用到了推箱子的某些特殊局部構造。

[參考文獻]

1. Dorit Dor, Uri Zwick. SOKOBAN and other motion planning problems. Computational Geometry 13 (1999) 215-228 (submitted in 1996)

2. Joseph C. Culberson. Sokoban is PSPACE-complete. Technical Report TR 97-02 of Dept. of Computing Science, The University of Alberta. April 1997.

3. Robert A. Hearn, Erik D. Demaine. PSPACE-completeness of sliding-block puzzles and other problems through the nondeterministic constraint logic model of computation. Theoretical Computer Science 343 (2005) 72-96.

4. Robert A. Hearn, Games, Puzzles, and Computation. PhD Thesis of MIT. June 2006.

[修改說明]

2016年4月16日,增加對Hearn方法轉換得到的關卡的特點描述。

 

發表在 推箱子, 數學 | 一條評論

sokoban.cn 網站的訪問者統計數據

 

本文地址:http://sokoban.ws/blog/?p=1758

網站訪問計數器對小網站來說是一個有趣的部件。在發現ClustrMaps提供免費的訪問統計,并按訪問者所在國家顯示在世界地圖中,便也在MF8推箱子比賽的網站sokoban.ws(后來增加了sokoban.cn域名)上添加了一個。

今年(2015年)3月底,ClustrMaps的4號服務器發生故障,丟失了少量數據。并且所有用戶必須重新注冊賬號,計數和統計都從零開始。

雖然是采取免費的服務模式,他們還是定期備份數據,并且在故障發生后的一個月內整理出備份數據供用戶存檔

下面便是從2012年9月6日至2015年3月16日這兩年半的訪問者數據。新計數器從2015年4月1日開始。

記錄到113個國家或地區的訪問數。

發表在 其他, 推箱子 | 留下評論

魔方吧推箱子比賽五周年

 

作者:楊超

本文地址:http://sokoban.ws/blog/?p=1133

隨著第57期MF8(魔方吧)推箱子比賽結束,我們這個在線的推箱子比賽足足舉辦了五周年。這是一件值得高興的事情,借這個時機總結一下這五年中比賽的發展變化。比賽能夠舉辦五年,主要原因我想是推箱子愛好者們在編關和解關中得到了樂趣。anian、stopheart、荊先生、20603、zhenying、西北天狼、laizhufu、zhouxh、風過了無痕、(捷克)P?emysl Zíka、shamying、tengxi、Many illusions等都為比賽貢獻過關卡。參加比賽的朋友就更多無法一一列出了。每期一般少則十來人,多則近三十人提交答案。參賽者來自中國、德國、法國、西班牙、保加利亞、阿魯巴、丹麥、巴西、比利時、美國、俄羅斯等十多個國家或地區。我對編關和解關參與得較少,主要負責比賽的后勤工作。關于編關解關中故事,有待其他朋友來講述,在此我說說比賽是如何辦起來的,以及這五年中比賽網站、形式和獎品等的變化。

一、比賽的由來

比賽是借助魔方吧論壇這個平臺辦起來的,所以叫MF8推箱子比賽。魔方這個上世紀80年代風靡一時的智力玩具在2006年后又開始變得越來越流行了。究其原因,很重要的一個是有個民間組織叫WCA(世界魔方協會World Cube Association)在全球各地舉辦了越來越多的魔方競速比賽。在這股潮流下,我也弄到了以前比較少見的四階五階魔方,并且于2007年夏天在MF8論壇注冊了賬號,而我注冊的賬號是sokoban。到了2009年,也跟MF8論壇的站長cube_master混了個臉熟。

2009年4月初,可能是由于老封關掉了他的推箱子論壇,MF8站長cube_master在魔方吧論壇里開增設了一個推箱子版。我馬上毛遂自薦擔任了推箱子版版主。可能是看到魔方的各種競速比賽舉辦得紅紅火火,我很自然地也想在新成立的推箱子版搞一個在線比賽。于是開版才幾天,第一期的MF8推箱子比賽就倉促開始了。

最初提交答案的方式極為麻煩。參賽者把答案加密打包在論壇回復,并站內私信把密碼發給我。我再人工驗證答案。比賽以這種很原始的方式運行了一年多,才得到改進。

前幾期的比賽關卡也是由我從現有關卡中選取或是由我隨意編的,質量不高。幸運的是,anian很快就加入比賽關卡的編排組織工作中,之后stopheart、荊先生和更多的朋友都為比賽提供了精彩的關卡,保證了比賽關卡的質量。

二、比賽網站

比賽的第一年,提交答案的方式的確很繁瑣,很不友好。到了2010年6月,我學習了一些簡單的PHP網站編程后,便利用國外的免費虛擬主機 http://sokoutil.orgfree.com 建立一個簡易的在線提交和驗證答案系統,簡化了答案提交的流程。

比賽網站建立不到半年,由于不可抗拒的原因,中國大陸無法直接訪問。于是把比賽網站整體遷移到另一國外的免費虛擬主機 http://sokoban.zzl.org 。搬家才兩個月,中國大陸又無法訪問了。一氣之下,我便從國內的互聯網服務提供商租用了虛擬主機,把網站再次遷移,從國外搬到了國內的服務器。同時依照工信部的規定,于2011年初通過了備案,成為一個合法的網站。

為了使比賽網站看上去更像一個正式網站,2010年底,注冊使用了域名 sokoban.ws。2012年5月后,中國互聯網信息中心(CNNIC)重新開放個人注冊.cn域名,同年11月,我們又成功注冊了 sokoban.cn 域名。

下面貼幾個不同時期的比賽網站截圖:

2010年10月

2011年11月

2012年4月

2014年3月(手機版截圖)

三、比賽形式

我們一直希望吸引到更多的朋友參加到比賽中來,為此比賽形式做過一些調整。

第三十一期設立的圍觀答案,參賽者可以提交n-1個箱子歸位的答案。到了四十三期,取消了圍觀答案,取而代之的是每期設立一主一副兩個關卡。副關較為容易,降低參賽的門檻。事實上我們的比賽一直是完全公開的,不設任何門檻,參賽者甚至不需要在比賽網站注冊賬號,就可以參賽。

四、比賽獎品

我們的比賽雖然開始得比較倉促,但從第一期起就提供了獎品。

頭兩期的獎品是我厚著臉皮向MF8論壇的一位版主“七夜”要的,七夜沒好意思直接拒絕,便贊助了兩期銘浩之魔方。后來鬼手魔方也有意贊助我們的比賽,從第三期起到第五十五期,期間除了第三十期慶祝魔方吧論壇開壇八周年由大煙頭贊助了寶石魔方,鬼手連續贊助了四年多。

從第三十四期到第四十八期,荊先生非常慷慨地贊助了幸運話費獎一年半。

比較遺憾的是目前比賽暫時沒有了贊助,若有企業有興趣贊助,我們非常歡迎。

發表在 推箱子 | 留下評論

用深度優先搜索(DFS)確定圖的割點

本文地址:http://sokoban.ws/blog/?p=1000

之前的博文《推箱子游戲的一個箱子推動路徑搜索算法 (二)》介紹了圖論中尋找割點的算法在推箱子路徑搜索中的應用。但是對用DFS尋找割點的原理說得不夠清楚明白,本文的目的是試圖進一步闡明這個算法,并把示意圖畫的更漂亮一些。

用DFS遍歷一個圖的所有頂點時,按訪問順序依次標號為1到n,稱之為DFS數。頂點v的DFS數記作D(v)。并得到一棵DFS樹(黑色邊),稱DFS樹的邊為樹邊(tree edge),其余的邊(紅色邊)稱為回頭邊(back edge)。如下圖,圖的邊都按搜索過程中向外的方向定向,得到一個有向圖。樹邊都是從DFS數小的頂點指向大的,回頭邊都是從DFS數大的頂點指向小的。

 

根據上面由深度優先搜索得到的有向圖中,可定義每個頂點的低位數(lowpoint):從該頂點出發,只用最多一條回頭邊,沿有向邊能走到的頂點中DFS數最小值。頂點v的低位數記為L(v)。

低位數取值有兩種情況:一是沒用上回頭邊,則能走到的DFS數最小的的頂點就是該點自身,對應的路是一個頂點構成的平凡的路。此時L(v)=D(v)。二是用了回頭邊,則一定是最后一條邊是回頭邊,走到一個DFS數更小的頂點。此時L(v)<=D(v)。

所以,一般地,總有L(v)<=D(v)。

有了這兩個參數,就可以確定割點了:對根節點,即DFS數為1的頂點,其為割點當且僅當在DFS樹中有兩個或以上子節點;其余所有非根節點v是割點的充分必要條件是:v存在一個子節點u(在DFS樹中的子節點)滿足u的低位數大于等于v的DFS數,即L(u)>=D(v)。

下圖標出的頂點的低位數(圈外數字,沒標圈外數字的頂點低位數和DFS數相等),綠色頂點為割點。

注:若用 DFS的深度(depth)來替代上面算法中的DFS數,并用深度來計算低位數,則算法一樣能有效地找出割點。

[參考文獻]
1. Shimon Even, Graph Algorithms (2nd Edition). Cambridge University Press. 2012. p52-54

[文中的圖使用http://draw.io制作]

發表在 數學, 算法 | 留下評論

推箱子游戲的一個箱子推動路徑搜索算法 (二)

作者:楊超

本文地址:http://sokoban.ws/blog/?p=843

在博文《推箱子游戲的一個箱子推動路徑搜索算法》中,我介紹了推箱子游戲如何用鼠標雙擊或拖放來進行推箱子操作。我知道的大概有十多個甚至二十多個推箱子軟件都實現了這一功能。最近,anian告訴我,他通過用20603兄的《一箭十萬》關卡測試了多個推箱子軟件,發現《YSokoban》的速度最快,點擊箱子,瞬間程序就給出了所有能被推到的格子的提示。而我編寫的《SokoPlayer HTML5》則需要約2秒。經過和anian兄的討論,我們改進了算法,大幅度提高的效率,使得《SokoPlayer HTML5》也能瞬間給出提示(約3毫秒)。下面簡單介紹一下我們如何作出改進的。

在一個箱子推動路徑搜索過程中,要反復判斷人是否能從箱子的一側自由移動(即不推動箱子情況下)到箱子的另一側。這個不難判斷,用簡單的廣度和深度優先搜索都能在線性時間內得到答案。但是箱子推動過程中,箱子位置在變化,要在不同的位置都作出判斷。假設涉及到的格子有n個,每判斷一次要O(n)時間,但箱子最多也可能出現在n個不同的格子,要做n次這樣的判斷,所以總的時間復雜度是O(n^2)。當關卡比較大時,如《一箭十萬》是50×50的關卡,不算墻體,格子也上千,導致計算時間比較長。

后來,我們發現判斷各種位置下人能否從箱子一側自由移動到另一側,可以用一個線性時間算法完成。這可以用圖論里的割點(Cut Vertex)和塊(Block)的理論和算法來幫助我們。舉一個具體的例子來說明什么是割點和塊。割點把關卡區域分割成不連通的小區域,稱為塊。下圖關卡中,黃色格子為割點,共有10個塊,分別用數字1到10標記。

我們若能把推箱子地圖所對應的圖中的割點和塊全部標記出來,那么回答人能否從一側移動到另一側就很簡單了。可以用這兩步來判斷:(1)先看箱子是否在一個 割點上。若不是割點,則人一定能從箱子一側移動到任意的另一側。若是割點,則還要進行第2步判斷。(2)看該箱子這兩側的格子是否屬于同一個塊。若是,則 能移動。否則不行。

如上圖中,若箱子在割點G6位置,人能從箱子左側(F6)移動到上側(G5),因為屬于同一個塊3號。但不能從左側(F6)移動到右側(H6)。又若箱子在H4位置,由于H4不是割點,人可以從一側移動到任意的另一側。

標記圖的所有割點和塊,有一個線性時間算法。這是一個基于深度優先搜索(Depth First Search)的算法。在深度優先搜索過程中,對每個結點記錄兩個參數。一個是結點的深度depth,另一個是結點的低位數(low point)。一個結點v的低位數是這樣計算的,取下面三者的最小值:(a)v自身的深度,(b)v的所有鄰點(DFS樹中的父結點除外)的深度,(c)DFS樹中v的所有子結點的低位數。

在實現中,通常用遞歸函數來進行深度優先搜索,于是計算低位數可以這樣處理。每發現一個新結點v時,把低位數初始為該結點的深度(即a)。對v的每個鄰點,若是父結點,不管;若是父結點以外的已訪問結點,且若該結點的深度較當前的低位數小,重新賦值v的低位數為該結點的深度(即b);若是未訪問結點,那么找到了一個子結點,于是遞歸調用搜索函數進行下一層搜索,返回時,若該子結點的低位數較小,則用它的更新v的低位數(即c)。

下面兩幅圖給出了一個例子,給出其DFS樹(紅色邊),每個結點的深度和低位數。括號內為低位數,黃色結點為割點。

有了深度和低位數,如何判斷割點和塊呢?

對于割點,判斷條件很簡單,若結點v有某一個子結點的低位數大于等于v的深度,則v是割點。

搜索的根結點比較特殊,它是割點的條件是在DFS樹中有至少兩個子結點。

對于塊的標記可以按如下方法實現。首先注意到割點同時屬于多個塊,其他點則恰屬于一個塊。在深度搜索過程中,每從一個子結點返回,并且由子結點判斷出其父結點v是割點時,就意味著找到一個新的塊了。此時,把v及其所有子孫都標記為同一個塊。標記之后,在DFS樹中,把v的所有子孫刪掉,但保留v。這樣v的子孫就不會被重復標記。而v是割點,還可能屬于另外一個塊。

以上文的圖為例。2(2)是個割點,從子結點3(2)返回是能判斷出來,同時能發現一個塊。而從子結點3(3)返回時也發現2(2)是割點,于是2(2)在另外一個塊中也被標記了。

[后兩個圖用LibreOffice Draw制作]

2013年12月22日補充:關于尋找割點算法,可參看用深度優先搜索(DFS)確定圖的割點

發表在 推箱子, 算法 | 一條評論

判斷推箱子關卡是否有解的多項式空間的算法

作者:楊超

本文地址:http://sokoban.ws/blog/?p=630

之前寫過一篇博文介紹了一系列具有遞歸關系和指數長度答案的推箱子關卡。本文給出判斷推箱子關卡是否有解的多項式空間的算法。這兩篇博文結合起來,可以對計算復雜性理論里面的PSPACE問題的概念有比較直觀的理解。推箱子游戲是一個非常好的PSPACE問題的例子。

一、P, NP和PSPACE

先定義推箱子問題。本文中說的推箱子問題,是指如下的一個判斷性的問題:給出一個推箱子關卡,這個關卡是否有解?注意這里只判斷是否有解,也就是說只要回答“是“或“否“,如果回答“是“,也不需要給出一個具體可行的lurd答案。

判斷一個推箱子關卡是否有解,是一個PSPACE完全(PSPACE-complete)問題。PSPACE-complete問題是計算復雜性理論里面的一個術語。PSPACE-complete 所討論的是推箱子問題的空間復雜度。簡單地說,空間就可以理解為計算機的內存。我們假設一個推箱子關卡寬度為w,高度為h,則我們稱這個推箱子關卡的大小為n=w*h。顯然,一個關卡越大,我們用程序去計算關卡是否可解時,需要的內存就越多。PSPACE-complete 有兩層意思。第一層意思是推箱子問題存在多項式空間的算法,也就是說存在一個算法A,這個算法對大小為n的推箱子關卡,最多使用$ n^k $(k是某一個與關卡無關的常數)的大小的內存就能回答出這個關卡是否可解。當然,所用的時間沒有限定。第二層意思是推箱子問題是所有多項式空間可解的問題里面最難的一類。PSPACE表示所有多項式空間可解問題的全體,PSPACE-complete是PSPACE 的一個子集,是里面最難的那些問題的全體。這里“最難“是有嚴格的數學定義的,在此我們直觀地認為從空間復雜度考慮最難就可以了。

計算復雜性理論的完整的理論體系建立于20世紀的70年代(1970年代)。而推箱子最早被證明是PSPACE-complete問題是在上世紀90年代末。就像我們前面解釋的那樣,證明推箱子問題是PSPACE-complete問題有兩個要點。一是要說明推箱子是多項式空間可解的。二就是說明推箱子問題是多項式可空間可解問題里面最難的。其中第一點比較容易,本文的目的是給出一個判斷推箱子關卡是否有解的多項式空間的算法。注意,這個算法只是理論上有意義,不適宜用來實際求解。在實踐中,大多推箱子求解程序使用大量的內存,往往是隨推箱子關卡大小呈指數增長。

在具體討論算法之前,先說些題外話。前些年,媒體曾熱炒過“龐加萊猜想”,這是Clay數學研究所(Clay Mathematics Institute)于2000年懸賞100萬美元的七個尚未解決的數學問題之一,每個100萬美元。其中“龐加萊猜想”最近已經被解決了。2010年,這個百萬大獎授予俄羅斯數學家佩雷爾曼(Grigoriy Perelman)。但佩雷爾曼拒絕接受這個獎項和獎金。 在其他六個尚未解決的價值百萬美元的問題中,有一個是屬于理論計算機科學里面的問題,更具體地說是關于計算復雜性理論的問題:即 P vs NP問題。

我們用P來表示所有能用多項式時間(注意是時間,不是空間,區別于PSPACE)算法解決的判斷問題全體。用NP表示所有所有能用“非確定性(Non-deterministic)”多項式時間算法的判斷問題全體。可以證明,任何一個P問題都一定是NP問題,也就是說P是NP的子集。但是現在尚未確定的是,究竟P是NP的真子集,還是P=NP?這就是所謂的P vs NP問題,七個百萬問題之一。

P和 NP都是從時間復雜度上考慮的,而PSPACE是從空間復雜度上考慮的。大家很自然會問,有沒有NPSPACE問題?也就是說是否有“非確定性“多項式空間算法問題的全體呢?有的。但是作為著名的Savitch定理的一個推論,可以證明PSPACE=NPSPACE。即兩者實際上是同一個集合,因此一般只提PSPACE。

Savitch定理是由Walter Savitch 于1970年證明的。我搜索了一下他的主頁,發現他主頁(http://cseweb.ucsd.edu/users/savitch/) 上照片似乎是在中國照的,大家可以去看看。這里提到Savitch定理的一個重要原因是下面介紹的算法是基于Savitch定理(參看[1])的證明設計的。


(圖片來自Walter Savitch的個人主頁)

可以證明,凡NP問題都是PSPACE問題,NP是PSPACE的子集。那么究竟NP是PSPACE的真子集,還是NP=PSPACE?這也是一個懸而未決的問題。多數數學家和理論計算機學家都傾向于認為P,NP和PSPACE三者,前一個都是后一個的真子集,也就是可用下圖示意:

二、判斷推箱子關卡是否有解的多項式空間的算法

下面開始討論算法。

我們知道一個大小為n的關卡,實際有效的格子實際上是小于n的,但我們不妨設就是n。每個格子要么是箱子,要么是人,要么什么也沒有,所以所能形成的不同的局面不會超過$ 3^n $種(事實上$ 3^n $高估了所有可能的局面數,但從數量級上是基本一致的),其中有一個局面是初始局面,有一個是目標局面。所以,如果一個關卡是可解的,一定在$ 3^n $步內解出來,如果$ 3^n $步內不可解,這個關卡就是不可解了。并且我們也知道存在關卡,其解法的步數和關卡大小n是成指數函數關系,在博文《一系列具有遞歸關系和指數長度答案的推箱子關卡》中已經給出了例子。

一種直觀的想法是用深度優先搜索(Depth-First Search)去窮盡所有$ 3^n $步以內的解法。但是這種算法需要用到一個后入先出的隊列,這個隊列的長度在極端情況下有可能是n的指數函數,這就超出了只用到關于n的多項式大小的空間的限制,就不是一個多項式空間算法了。

于是我們考慮一個基于二分法的遞歸算法去解決這個問題。

定義Savitch算法如下(姑且稱之為Savitch算法吧,因為它是基于Savitch定理的證明,但文獻中我沒有看到有這樣提法的)。

Savitch(c1,c2,t)
輸入:初始局面c1,目標局面c2, 步數 t? (初始局面和目標局面均為大小為n的關卡)
輸出:若能在t步內由局面c1變換到局面c2,返回“是“,否則返回“否“

1,若t==1,能直接判斷,返回“是“或者“否“。
        1.1若c1==c2,返回“是“
        1.2若c1!=c2,但能一步從c1變到c2,返回“是“
        1.3其他情況,返回“否“
2,若t>1執行下面步驟。
3,對每個所有可能的中間局面cm
        3.1遞歸調用 Savitch(c1,cm, [t/2])
        3.2遞歸調用Savitch(cm,c2, [t/2]),(若t為奇數時,3.2調用Savitch(cm,c2,[t/2]+1) )
        3.3若3.1和3.2均返回“是“,則直接返回“是“
4,若遍歷了所有中間局面cm,3.3都沒有返回,則返回“否“

對于一個大小為n的推箱子關卡,我們這樣調用算法Savitch(c1,c2, $? 3^n $),則返回值就是我們想要的答案。下面說明一下算法只用了多項式空間。

每一層迭代,我們需要分配新的內存空間給c1,c2,t和cm,所以用的的空間不超過4n。那么最多迭代多少次呢?每迭代一次,步長除以2,所以最多經過 $ \log_2 3^n = (\log_2 3) n $次迭代,步長小于1,直接返回。所以,任一時刻,算法所用到的空間不會超過 $ (\log_2 3) n \cdot 4 n = (4\log_2 3) n^2$,這是關于n的一個2次多項式。所以這是一個多項式空間算法。

注:算法第3步遍歷所有中間局面cm時,可按照局面的某種自然的字典排序去遍歷,幾乎不需要額外空間。

【參考文獻】

[1] Sipser, Michael (1997), “Section 8.1: Savitch’s Theorem”, Introduction to the Theory of Computation, PWS Publishing, pp. 279–281

寫于2011年1月,2012年8月26日修改

發表在 推箱子, 數學 | 留下評論

一系列具有遞歸關系和指數長度答案的推箱子關卡

作者:楊超

本文地址:http://sokoban.ws/blog/?p=430

推箱子的其中一個很重要的魅力來源于推箱子求解問題在計算復雜性理論里是一個 PSPACE 完全問題。在這里不對什么是 PSPACE 完全問題作出解釋,但是推箱子的一部分美妙之處可以認為正是來源于它的計算復雜度達到了 PSPACE 完全問題的級別。具體表現就是可以設計出很多不同模式的關卡,而且我們目前所涉及到的模式只是一小部分,還有很廣闊的空間等待我們去探索。另外一個表現就是存在一系列具有指數長度答案(相對與關卡的大小)的關卡,這一類關卡就是推箱子關卡眾多模式里面非常有趣的一類,也是本文要討論的對象。

2009年6月8日,我曾在魔方吧論壇發貼子介紹了一類指數長度答案的關卡。無獨有偶,約一個月后的2009年7月5日,Matrix67的一片博客文章也介紹了這一關卡。我的貼子和 Matrix67 的博文介紹的關卡都是基于2000年國外的一個關于推箱子問題的解答

對這個關卡的具體分析這里就不再重復了,簡單的說它就是由一個個的“房間”構成,上圖是三個房間的情況。要過關,最左側一個房間要進入2次,但要進入左一房間1次,就要進入左二房間2次,所以左二房間一共要進入4次。同理,左三房間就要進入8次。一般的,若有n個房間的話,第n個要進入2^n次,于是答案長度便成指數增長了。

這個關卡設計巧妙,讓人感受到推箱子的美。下面我們要介紹一個更美的更簡潔緊湊,但同樣也是具有指數長度的答案的系列關卡。

這個更漂亮的系列關卡也是在推箱子玩家里面流傳了很長時間了,有很多變化形式,其中最經典的可能是如下圖所示。

這是???? Aymeric du Peloux 2001年設計的 Picokosmos 第17關。David Holland 在2002年曾分析過這個關卡。Dries De Clercq 在這個基礎上作了名為 Fibo 系列的變形關卡。上圖所示的經典形式不只是一個關卡,而是一系列關卡,關卡可以縱向任意伸長(同時箱子也增加),只要保持箱子總數是偶數個就行了(奇數的時候關卡無解)。若用n表示箱子的數目,隨著n增大,答案步數以n的指數函數增長。

沒有玩過這一關的朋友可以點擊此鏈接在線玩。先提前警告,雖然只有8個箱子,要解出來不太容易。

我是2009年在魔方吧發了前面提到的貼子之后,才注意到這個關卡,當時沒有看到 David Holland 的分析文章,獨立地研究了這一系列關卡的步數。下一節將簡要的介紹一下我的計算方法。

上一節提到,這一系列關卡只對偶數個箱子有解。為了便于建立遞推關系,我對箱子位置作了以下微妙調整,使得對奇數也有效。主要有兩處改動:一是最下方一個箱子連同目標移動了一格;二是最上方一側的箱子移下一格(哪一側由奇偶性確定)。如下面所示,分別是4到8個箱子的情形(注意本節的圖和上一節的圖左右反了)。

本關在線游戲鏈接

本關在線游戲鏈接

設 n 個箱子的上述關卡的最佳答案需要用 M(n) 步移動,P(n)步推動過關。可以得到下面的遞推關系:

M(n)= M(n-1)+M(n-2)+n +12,????? n 是奇數
M(n)= M(n-1)+M(n-2)+n+10,?????? n 是偶數

P(n)= P(n-1)+P(n-2)+8 .

要得到上面的遞推關系,需要觀察出這系列關卡的過關規律,下面以n=7 為奇數的時候推導以上公式。

首先觀察到這樣一個現象:過關時,箱子把關卡分割成左右兩側不相通的區域。以最佳答案過關時,人是停留在右側區域,如下圖所示的位置。

要想人最后留著左側區域也是可以做到的,但是就是要多用2步移動,推動步數不變,最后位置如下。我們這里述而不證的這一觀察到的結束位置的規律是必須親自解過這一系列關卡才能有體會。如果你還沒來得及解關,下面的遞推關系就會徹底地揭示了求解的秘密了。

下面開始推導遞推關系了。根據實踐規律,當 n=7 個箱子時,前6步必須是 ldDDRU (6步移動,4步推動)。這6步之后,關卡變成下圖。

————(1)

此時,若忽略最上面兩個箱子,關卡實際上就是 n=5 個箱子的情形。利用 n=5 的時候的解法,可以走到下圖的狀態。

————(2)

從狀態(1)到狀態(2),基本相當于解一個 n=5 個箱子的關卡,但由于人最后是停在左側區域,根據前面提到的觀察規律,中間需要移動 M(5) + 2 步和推動 P(5) 步。

接下來的步驟必須是 uuuuurrDDLU (移動11步,推動4步)。一般地,則是移動 n+4 步,推動還是4步。經過這11步,得到狀態(3)。

————(3)

從狀態(3)開始,直到最后過關,相當于解一個 n=6 個箱子的關卡,因為最上方的箱子保持不動。所以余下共移動 M(6) 步,推動 P(6) 步。

經過上面以 n=7 為例的分析,我們得到奇數時的遞推關系:

M(n)=6+M(n-2)+2+n+4+M(n-1)=M(n-1)+M(n-2)+n+12
P(n)=4+P(n-2)+4+P(n-1)=P(n-1)+P(n-2)+8.

偶數的時候原理一樣,具體的推導過程在此就省略了。

有了遞推公式,和 n=4,5 時最佳步數,我們很容易就可以計算出下面的通項公式。

M(n)=(-1)^(n+1)? + (9+sqrt(5)) * a^n + (9-sqrt(5)) * b^n – n -14 ,
P(n)=( (10+4*sqrt(5))/5 ) * a^n +? ( (10-4*sqrt(5))/5 ) * b^n? – 8,
其中 a=(1+sqrt(5))/2 , b=(1-sqrt(5))/2.

下面用 MathJax 顯示一下上述兩個通項公式。

$ M(n)=(-1)^{n+1} + (9+\sqrt{5})\cdot\Big({\frac{1+\sqrt{5}}{2}}\Big)^n + (9-\sqrt{5})\cdot\Big({\frac{1-\sqrt{5}}{2}}\Big)^n-n-14 $ ,

$ P(n)={\frac {10+4\sqrt{5}}{5} } \cdot \Big({\frac{1+\sqrt{5}}{2}}\Big)^n + {\frac {10-4\sqrt{5}}{5} }\cdot\Big({\frac{1-\sqrt{5}}{2}}\Big)^n-8 $ .

從通項公式中,我們可以看出,無論是移動還是推動,答案都是具有指數長度的。

常系數線性遞推關系的求解是比較經典的數學理論了,中學數學競賽常常有這方面的題目,在高等數學里亦有不少應用。這一系列關卡結構緊湊渾然天成,卻又蘊含如此典型的遞推關系,實在是令人意想不到,堪稱常系數線性遞推關系的求解最有趣的應用之一。

第四節7個箱子關卡的最佳答案(306移動,102推動),答案格式說明請參看xsb和lurd格式簡介:

ldDDRUldDDRUdddlUluRurrrddLLUdrruulDlddlUluRuuurrDDLUrdrddLLUlldR
drUrruulDuullDDRUdddlUluRurrrddLLUdrruulDlddlUluRuuuuurrDDLUrdDDL
UrdrddLLUlldRdrUrruulDuullDDRUdddlUluRurrrddLLUlldRdrUrruulDuuuul
lDDRUldDDRUdddlUluRurrrddLLUdrruulDlddlUluRuuurrDDLUdrrddLLUlldRd
rUrruulDuullDDRUdddlUluRurrrddLLUlldRdrUrruulD

GIF動畫演示答案(GIF動畫用YSokoban,irfanview和gifsicle制作,可參看制作推箱子GIF動畫教程):

還是這一關,人最后停止在左側區域的答案(308移動,102推動),移動多了2步,最后十來步稍微有區別:

ldDDRUldDDRUdddlUluRurrrddLLUdrruulDlddlUluRuuurrDDLUrdrddLLUlldR
drUrruulDuullDDRUdddlUluRurrrddLLUdrruulDlddlUluRuuuuurrDDLUrdDDL
UrdrddLLUlldRdrUrruulDuullDDRUdddlUluRurrrddLLUlldRdrUrruulDuuuul
lDDRUldDDRUdddlUluRurrrddLLUdrruulDlddlUluRuuurrDDLUdrrddLLUlldRd
rUrruulDuullDDRUdddlUluRurrrddLLUdrruulDlddlUluR

發表在 推箱子, 數學 | 留下評論

推箱子游戲的一個箱子推動路徑搜索算法

作者:楊超

地址:http://sokoban.ws/blog/?p=298

推箱子自1981年誕生至今,已經超過30年了。推箱子軟件的功能也有了很大的改進。從剛開始的只能用鍵盤一步一步的移動,到上世紀90年代后期起,用電腦輔助搜索一個箱子的推動路徑,從而實現用鼠標兩次點擊(或是拖放)就能實現一個箱子的任意推動。可以說,電腦輔助路徑搜索,已經成為推箱子軟件的一個標準功能,使得人們從繁瑣的逐步操作中解放出來,在更大一些的關卡中探尋更多的挑戰和樂趣。

一個箱子的推動路徑搜索并不是一個很難的算法,用最基本的廣度優先搜索算法(Breadth-first search),就可以很快地找到一個推動數最少(但此時移動步數不一定最少)的路徑。我2002年春寫《Final Sokoban》第一次實現了這個算法,2004年寫《M2 Sokoban》又實現了一次。這兩次都是用C++或C在Windows平臺下寫的。2010年后寫Java Applet《SokoPlayer》,用C寫Linux下的《USokoban》和用Javascript寫《SokoPlayer HTML5》,都實現過這個算法。下面簡單說一下這個算法的要點。

首先,必須明確搜索的一個結點是什么。我們是考慮選中一個箱子后,不推其他箱子的前提下,把選中的箱子推到一個目的地。于是,在推動這個箱子的過程中,其他箱子可以視為墻體。又我們以推動一步為基本的單位來搜索,不以移動一步來搜索。所以搜索的一個結點由兩個要素確定:一是箱子的位置,二是人相對于箱子的方向。這是因為箱子可以把人隔在關卡中不同的區域。

以下面這個簡單的關卡為例:

(圖一)

可以點擊下面鏈接玩這一關。

http://sokoban.ws/sokoplayer/?w=4&h=9&lvl=HHHH|H__H|H__H|H__H|H__H|HH$H|_HaH|_H.H|_HHH

這一關的按廣度優先搜索得到的樹如下:

在上述搜索樹中我們看到,結點a 和結點 f 的箱子位置是一樣的,但是由于人的位置不同,所以是兩個不同的結點。一般地,當前要推動的箱子最多把關卡隔為四個不同區域(即上下左右,在程序中可以用0,1,2,3或其他常數表示)。所以若關卡大小不超過n*n,則搜索總的結點不超過 4n*n 個。

廣度優先搜索通常要用到一個先入先出(First-in first-out)的隊列(Queue)來保存搜索過程中的結點。根據前面的分析,每個結點只需保存箱子位置和人相對于箱子的位置。如,結點a可記為[(C, 6) 下],其中(C, 6)是圖一中箱子標尺坐標,“下”表示人相對于箱子的位置。這樣,一個結點在搜索隊列中用2到3個字節便可以保存。

其次,搜索過程中,結點可能重復出現,我們必須記住哪些結點前面已經訪問過了,只把新的結點添加到搜索隊列中。比如上面例子中,結點 e 箱子有向上和向下推兩種可能。向上推得到新結點g;向下推得到的本質上是結點c,這個在前面已經出現,所以忽略不要。

幸好,我們已經分析過了,總結點不超過4n*n個,我們可以用一個4n*n個單元的數組來記錄結點是否已經訪問過。初始時,數組全為0,每遇到一個新結點,它在數組上對應的位置改為1,表示訪問過了。于是,搜索中,我們每推一步得到一個結點,只需查看該數組的相應位置是0還是1,快速判斷這個結點是否新結點。

比如,結點c我們可以記為[(C,4)下]。我們確認它是一個新結點加入隊尾時,把[(C,4)下]對應的位置標記為1。注意,同時我們把[(C,4)左]和[(C,4)上]也標記為1,因為這三者本質上是同一個結點。在具體的算法實現上,我們檢查一下人能否從箱子下方在不推動任何箱子的前提下,自由地移動到箱子的其他方向。

有了以上的分析,我們可以把總的算法描述如下(假設關卡不超過80 x 80):

(1)初始化準備:建立搜索隊列q,把初始結點入隊。用數組t[80][80][4] 來記錄結點是否訪問過,初始化為全為o,然后把數組t中與初始結點對應的位置和與之等價的位置標記為1。

(2) 主循環:根據隊列是否為空,分別執行操作(2.1)或(2.2)

(2.1) 若隊列非空,讓隊頭結點出隊。從此結點出發,分別嘗試向上下左右推動箱子一格。(如:看是否能向左推動,就是看人能否自由的移動到箱子右側一格,且箱子左側一格為空) 若能推動,檢查得到的結點是否新結點。

若是,加入搜索隊列q的隊尾。并在t中把這一新結點標記為1,同時把與之本質上一樣的結點也標記為1。若同時還是目標結點,跳出循環,執行第(3)步。

若不是新結點,什么都不用做。

上下左右都嘗試過后,回到第(2)繼續。

(2.2)若隊列為空,全部可能結點搜索完畢。到目標結點的路徑不存在,返回。

(3) 路徑找到。從目標結點出發,回溯 lurd 路徑。為了回溯路徑,在前面的搜索過程中,實際上還需要保存額外信息,如每個新結點的前繼結點是哪個一個等等。

上面是需要返回目標結點的路徑的算法流程。若不需要回溯路徑,如只搜索哪些格子是能夠推到的,算法只需作相應調整:不保存前繼結點的信息,且第(2.1)步不跳出循環,直到隊列為空算法停止,等等。

通過以上的算法分析,我們看到,箱子的路徑搜索算法同時還要用到人自由移動的路徑搜索的算法作為幫助函數來實現。

實踐表明,因為問題本身的計算復雜度不高,即便是算法的具體實現不是特別好(如具體實現中,本可避免的大數組的復制操作太多),程序的表現也非常不錯。比如,我用瀏覽器解釋執行的 Javascript 語言編寫的《SokoPlayer HTML5》,執行效率應該說比C之類的編譯型語言差很多,但是對于80 x 50的超大型關卡,路徑搜索也就是幾秒的時間,絕大多數情況下是瞬間完成搜索。

發表在 推箱子, 編程 | 一條評論