如何在桌子上摆放盒子的情况下让盒子免费,SWI-Prolog?

时间:2017-10-17 19:46:33

标签: prolog

我是prolog的初学者,我正试图用图片https://i.stack.imgur.com/BechG.png中所示的方框来解决问题。我的代码是:

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 个答案:

答案 0 :(得分: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

的一个文件中