2016-05-02 75 views
1

我試圖解決這個問題Pebble Solitaire,這是我的代碼部分:SWI-Prolog:findall/3找不到所有解決方案?

% Base case 
play(List, X) :- 
    count_pebbles(List, X). 

%%%%%%%%%%%%%% 
% JUMP RIGHT % 
%%%%%%%%%%%%%% 
    % oo-XXXXXXXXX 
    play( [111, 111, 45|Tail], X) :- 
     play([45, 45, 111|Tail], X). 

    % Xoo-XXXXXXXX 
    play( [A, 111, 111, 45|Tail], X) :- 
     play([A, 45, 45, 111|Tail], X). 

    % XXoo-XXXXXXX 
    play( [A, B, 111, 111, 45|Tail], X) :- 
     play([A, B, 45, 45, 111|Tail], X). 

    % XXXoo-XXXXXX 
    play( [A, B, C, 111, 111, 45|Tail], X) :- 
     play([A, B, C, 45, 45, 111|Tail], X). 

    % XXXXoo-XXXXX 
    play( [A, B, C, D, 111, 111, 45|Tail], X) :- 
     play([A, B, C, D, 45, 45, 111|Tail], X). 

    % XXXXXoo-XXXX 
    play( [A, B, C, D, E, 111, 111, 45|Tail], X) :- 
     play([A, B, C, D, E, 45, 45, 111|Tail], X). 

    % XXXXXXoo-XXX 
    play( [A, B, C, D, E, F, 111, 111, 45|Tail], X) :- 
     play([A, B, C, D, E, F, 45, 45, 111|Tail], X). 

    % XXXXXXXoo-XX 
    play( [A, B, C, D, E, F, G, 111, 111, 45|Tail], X) :- 
     play([A, B, C, D, E, F, G, 45, 45, 111|Tail], X). 

    % XXXXXXXXoo-X 
    play( [A, B, C, D, E, F, G, H, 111, 111, 45|Tail], X) :- 
     play([A, B, C, D, E, F, G, H, 45, 45, 111|Tail], X). 

    % XXXXXXXXXoo- 
    play( [A, B, C, D, E, F, G, H, I, 111, 111, 45], X) :- 
     play([A, B, C, D, E, F, G, H, I, 45, 45, 111], X). 


%%%%%%%%%%%%% 
% JUMP LEFT % 
%%%%%%%%%%%%% 
    % -ooXXXXXXXXX 
    play( [45, 111, 111|Tail]) :- 
     play([111, 45, 45|Tail]). 

    % X-ooXXXXXXXX 
    play( [A, 45, 111, 111|Tail]) :- 
     play([A, 111, 45, 45|Tail]). 

    % XX-ooXXXXXXX 
    play( [A, B, 45, 111, 111|Tail]) :- 
     play([A, B, 111, 45, 45|Tail]). 

    % XXX-ooXXXXXX 
    play( [A, B, C, 45, 111, 111|Tail]) :- 
     play([A, B, C, 111, 45, 45|Tail]). 

    % XXXX-ooXXXXX 
    play( [A, B, C, D, 45, 111, 111|Tail]) :- 
     play([A, B, C, D, 111, 45, 45|Tail]). 

    % XXXXX-ooXXXX 
    play( [A, B, C, D, E, 45, 111, 111|Tail]) :- 
     play([A, B, C, D, E, 111, 45, 45|Tail]). 

    % XXXXXX-ooXXX 
    play( [A, B, C, D, E, F, 45, 111, 111|Tail]) :- 
     play([A, B, C, D, E, F, 111, 45, 45|Tail]). 

    % XXXXXXX-ooXX 
    play( [A, B, C, D, E, F, G, 45, 111, 111|Tail]) :- 
     play([A, B, C, D, E, F, G, 111, 45, 45|Tail]). 

    % XXXXXXXX-ooX 
    play( [A, B, C, D, E, F, G, H, 45, 111, 111|Tail]) :- 
     play([A, B, C, D, E, F, G, H, 111, 45, 45|Tail]). 

    % XXXXXXXXX-oo 
    play( [A, B, C, D, E, F, G, H, I, 45, 111, 111]) :- 
     play([A, B, C, D, E, F, G, H, I, 111, 45, 45]). 

是啊,這是醜陋的。

但是,當我打電話findall(Value, play(Game, Value), Values),其中Game只是45和111的任何序列(例如[45,111,45,45,45,45,111,111,111,45,45,45])。 ,價值觀只與2個項目列表統一(編輯:不正確,它與更多項目統一,見評論)。

根據我的理解,當我調用findall/3時,它會在基本情況謂詞中找到一個解(它只計算鵝卵石的數量並用X統一它),然後從20中的任何一個其他遊戲謂詞,然後只是...停下來?

我需要它繼續前進,直到找到所有解決方案。爲什麼在2種解決方案之後停止?我怎樣才能讓它繼續下去?

+0

剛剛意識到它並不總是與2個項目統一,它有時會發現更多。 – Mossmyr

+0

我發現錯誤:所有的「JUMP RIGHT」謂詞都是play/2,所有「JUMP LEFT」謂詞都是play/1 <。<「 – Mossmyr

回答

3

你的程序有幾個問題。你找到了一個。還有更多!

1mo作爲慣例,省略屬於同一謂詞的子句之間的空行。這有助於避免這種意外問題。

2do另一個有用的約定是避免使用ASCII碼。而是使用字符(長度爲一個原子),象這樣:

[45,111,45,45,45,45,111,111,111,45,45,45] % your example 

[-,o,-,-,-,-,o,o,o,-,-,-] % using chars 

"-o----ooo---" % :- set_prolog_flag(double_quotes, chars). 

注意,指令set_prolog_flag(double_quotes, chars)隻影響雙引號"strings"被讀取的方式。它還裏噴出的實際字符的答案替換:

?- L = "-o--". 
L = [-,o,-,-]. 

要獲得同樣緊湊的答案用use_module(library(double_quotes))! (首先剛纔下載double_quotes.pl爲SWI到相同的目錄中的Prolog文件說):

?- use_module(double_quotes). 
true. 

?- L = "-o--". 
L = "-o--". 

3tio這是一個改寫:一是分割你的謂語play/2爲單一移動。將遞歸與其他代碼混合通常非常麻煩。想象一下,遞歸謂詞不會終止!無論如何,在同一時間太多了。這是我的承擔:

:- set_prolog_flag(double_quotes,chars). 

move(Xs0, Xs) :- 
    phrase((seq(Prefix), localmove) , Xs0, Xs1), 
    phrase( seq(Prefix),    Xs, Xs1). 

localmove, "o--" --> "-oo". 
localmove, "-oo" --> "oo-". 

seq([]) --> []. 
seq([E|Es]) --> [E], seq(Es). 

?- move("-o----ooo---",S). 
S = "-o---o--o---" ; 
S = "-o----o-oo--" ; 
false. 

所以現在,我們只有一個舉動。接下來,我們需要按順序進行多個動作。爲了確保我們不會進入週期,我將使用另一個例子中定義的closure0/3

?- S0 = "-o----ooo---", closure0(move, S0,S). 
    S0 = "-o----ooo---", S = S0 
; S0 = "-o----ooo---", S = "-o---o--o---" 
; S0 = "-o----ooo---", S = "-o----o-oo--" 
; S0 = "-o----ooo---", S = "-o----oo----" 
... 

這些是許多中間步驟。會有無限多或無限多?會有周期嗎?我們可以在所有的答案盯着,還是讓Prolog的做羣衆的思想爲我們:

?- S0 = "-o----ooo---", move(S0,S1), closure0(move, S1,S0). 
%      one move ahead, more moves, ^^ and back 
false. 

此操作失敗,從而沒有循環回到原來的狀態。我們可以證明這一般嗎?對於所有可能的長度?截至N = 9,我失敗了預期:

?- length(S0,9), move(S0,S1), closure0(move,S1,S0). 
false. 

讓我重複這個:在這裏,Prolog的證明,9洞全部可能主板不具備週期。當然有一個更簡單的說法:一步移除卵石,另一步移動鵝卵石到右側。但最後一個查詢的觀點是:Prolog證明通過考慮所有可能的立即

+0

Beautifly done。1mo)True。2do)True,但謂詞I當程序運行時用於用戶輸入輸出ASCII碼,將它們轉換回字符似乎是縮減的3tio)這裏的代碼有一些我不熟悉的語法,我必須仔細研究它。 SWI-Prolog 6.6.4中的小程序給了我「錯誤:超出全局堆棧」 – Mossmyr

+0

是的,我將'move(「 - o ---- ooo ---」,S).'上面的代碼複製到一個文件「test.pl」,運行'$ prolog test.pl'並編譯,然後調用'move(「 - o ---- ooo ---」,S).'。 – Mossmyr

+1

對!請重試! – false

相關問題