2017-10-17 81 views
1

我是prolog的初學者,我試圖用圖片https://i.stack.imgur.com/BechG.png中顯示的方框來解決問題。我的代碼是:如何使盒子免費,在桌子上的盒子,SWI-Prolog的情況下?

box(a). 
box(b). 
box(c). 
table(t). 
on(a,t). 
on(b,t). 
on(c,a). 
free(b). 
free(c). 

move(X,Z),free(Y):- 
    free(X), 
    free(Z), 
    on(X,Y). 

move(X,t):- 
    free(X), 
    not(on(X,t)). 

move(X,Y):- 
    free(X), 
    free(Y). 

一次只能移動一個盒子,這意味着我不能同時從表格中取出兩個盒子。當我把這個命令放到盒子裏時,我遇到了一個問題move(c,t),move(b,c),move(a,b).在SWI-Prolog中,它向我展示了它應該是真的。在所有其他選擇中,它表現真實,我認爲盒子永遠不會變得自由。

回答

1

您採取錯誤的表示。使用事實對於表示一個不可改變的世界是很好的,但是一旦你開始搜索,你想表示一個可變的世界狀態,這在邏輯變量中最好實現。這樣你就可以利用Prolog非確定性和回溯來找到一系列讓你從開始狀態到最終狀態的動作。因此, 讓我們代表數據庫中的最終狀態,然後規則來獲取變量的開始狀態和最終狀態。我們對一個州的表示是一系列(三個)on(X,Y)條款。

final(a,b). 
final(b,c). 
final(c,t). 

start(State) :- 
    findall(on(X,Y), on(X,Y), State). 
final(State) :- 
    findall(on(X,Y), final(X,Y), FinalState), 
    same_state(State, FinalState). 

same_state(State1, State2) :- 
    sort(State1, State), 
    sort(State2, State). 

現在我們必須定義自由的狀態。這很簡單:最上面的一個和表都是免費的:

free(X, State) :- 
    box(X), 
    \+ member(on(_,X), State). 
free(t, _). 

現在,我們可以定義一個舉動是從初始狀態取出一個on(X,Y)並添加一個新問題:

move(State0, move(X,New), [on(X,New)|Rest]) :- 
    select(on(X,_), State0, Rest), 
    free(X, State0), 
    free(New, State0), 
    X \== New. 

接下來,我們必須做出多重舉動。我們必須小心,不要進入一個狀態,我們之前已經看到:

moves(State, [], _Visited, State). 
moves(State0, [Move|T], Visited, State) :- 
    move(State0, Move, State1), 
    \+ (member(V, Visited), 
     same_state(State1, V) 
     ), 
    moves(State1, T, [State1|Visited], State). 

現在,我們幾乎完成:

solve(Moves) :- 
    start(State), 
    moves(State, Moves, [State], Final), 
    final(Final). 

有很多優化。我會把它留給你。最後的兩個謂詞確實顯示了搜索的整體方法:從頭開始,進行移動,避免返回到舊狀態並測試您是否找到了目標狀態。整個東西在一個文件中顯示在https://swish.swi-prolog.org/p/BenchG.pl

+0

這樣一個美麗的解決方案,這就是爲什麼我喜歡Prolog! –