这是一个清理/简化版本(恕我直言)。
总的来说,没有太多需要优化的地方。
这是标准的深度优先搜索通过状态空间的路径。
对于广度优先搜索,需要另一种方法。
可以尝试比线性扫描(即某种哈希表)更快地查找访问状态,但是对于长度为 8 的历史记录,这真的不值得。
% The state indicates the position of: Farmer, Wolf, Goat, Cabbage
% which is always one of east ('e') or west ('w').
unsafe(state(e,w,w,_)). % Wolf and Goat are on the same border and the farmer ain't there
unsafe(state(w,e,e,_)). % Wolf and Goat are on the same border and the farmer ain't there
unsafe(state(e,_,w,w)). % Goat and Cabbage are on the same border and the farmer ain't there
unsafe(state(w,_,e,e)). % Goat and Cabbage are on the same border and the farmer ain't there
opp(e,w).
opp(w,e).
% Valid next state generation
move(state(X,X,G,C), state(Y,Y,G,C)):-
opp(X,Y),
\+ unsafe(state(Y,Y,G,C)),
format("try farmer takes wolf ~q -> ~q\n",[state(X,X,G,C), state(Y,Y,G,C)]).
move(state(X,W,X,C), state(Y,W,Y,C)):-
opp(X,Y),
\+ unsafe(state(Y,W,Y,C)),
format("try farmer takes goat ~q -> ~q\n",[state(X,W,X,C), state(Y,W,Y,C)]).
move(state(X,W,G,X), state(Y,W,G,Y)):-
opp(X,Y),
\+ unsafe(state(Y,W,G,Y)),
format("try farmer takes cabbage ~q -> ~q\n",[state(X,W,G,X), state(Y,W,G,Y)]).
move(state(X,W,G,C), state(Y,W,G,C)):-
opp(X,Y),
\+ unsafe(state(Y,W,G,C)),
format("try farmer takes self ~q -> ~q\n",[state(X,W,G,C), state(Y,W,G,C)]).
not_yet_seen(State,History) :- % will fail if member(State, History)
member(State, History),
!,
format("State ~q already seen\n",[State]),
fail.
not_yet_seen(_,_). % the replacement: success if \+ member(State, History)
path(State, State, History) :- % found a solution! (but maybe not the BEST solution)
!, % don't continue the search down this history
reverse(History,RevHistory),
maplist(term_to_atom,RevHistory,RevHistoryAtoms),
atomic_list_concat(RevHistoryAtoms, '->', OutputAtom),
length(History,L),
format("A solution of length ~d: ~q\n",[L,OutputAtom]).
path(CurState, FinalState, History) :-
move(CurState, NextState), % generate a safe next state
not_yet_seen(NextState, History), % that hasn't been seen yet
(true;(format("Backtracking from using ~q\n",[NextState]),fail)),
path(NextState, FinalState, [NextState|History]). % add it to the visited states and recurse
go(StartState, FinalState) :-
path(StartState, FinalState, [StartState]). % 3rd arg is "history"
test :-
go(state(w,w,w,w), % first everything is west
state(e,e,e,e)). % then everything is east
它找到了两个历史长度为 8 的解:
?- test.
try farmer takes goat state(w,w,w,w) -> state(e,w,e,w)
try farmer takes goat state(e,w,e,w) -> state(w,w,w,w)
State state(w,w,w,w) already seen
try farmer takes self state(e,w,e,w) -> state(w,w,e,w)
try farmer takes wolf state(w,w,e,w) -> state(e,e,e,w)
try farmer takes wolf state(e,e,e,w) -> state(w,w,e,w)
State state(w,w,e,w) already seen
try farmer takes goat state(e,e,e,w) -> state(w,e,w,w)
try farmer takes goat state(w,e,w,w) -> state(e,e,e,w)
State state(e,e,e,w) already seen
try farmer takes cabbage state(w,e,w,w) -> state(e,e,w,e)
try farmer takes wolf state(e,e,w,e) -> state(w,w,w,e)
try farmer takes wolf state(w,w,w,e) -> state(e,e,w,e)
State state(e,e,w,e) already seen
try farmer takes goat state(w,w,w,e) -> state(e,w,e,e)
try farmer takes goat state(e,w,e,e) -> state(w,w,w,e)
State state(w,w,w,e) already seen
try farmer takes cabbage state(e,w,e,e) -> state(w,w,e,w)
State state(w,w,e,w) already seen
Backtracking from using state(e,w,e,e)
Backtracking from using state(w,w,w,e)
try farmer takes cabbage state(e,e,w,e) -> state(w,e,w,w)
State state(w,e,w,w) already seen
try farmer takes self state(e,e,w,e) -> state(w,e,w,e)
try farmer takes goat state(w,e,w,e) -> state(e,e,e,e)
A solution of length 8: 'state(w,w,w,w)->state(e,w,e,w)->state(w,w,e,w)->state(e,e,e,w)->state(w,e,w,w)->state(e,e,w,e)->state(w,e,w,e)->state(e,e,e,e)'
true ;
Backtracking from using state(e,e,e,e)
try farmer takes self state(w,e,w,e) -> state(e,e,w,e)
State state(e,e,w,e) already seen
Backtracking from using state(w,e,w,e)
Backtracking from using state(e,e,w,e)
Backtracking from using state(w,e,w,w)
Backtracking from using state(e,e,e,w)
try farmer takes cabbage state(w,w,e,w) -> state(e,w,e,e)
try farmer takes goat state(e,w,e,e) -> state(w,w,w,e)
try farmer takes wolf state(w,w,w,e) -> state(e,e,w,e)
try farmer takes wolf state(e,e,w,e) -> state(w,w,w,e)
State state(w,w,w,e) already seen
try farmer takes cabbage state(e,e,w,e) -> state(w,e,w,w)
try farmer takes goat state(w,e,w,w) -> state(e,e,e,w)
try farmer takes wolf state(e,e,e,w) -> state(w,w,e,w)
State state(w,w,e,w) already seen
try farmer takes goat state(e,e,e,w) -> state(w,e,w,w)
State state(w,e,w,w) already seen
Backtracking from using state(e,e,e,w)
try farmer takes cabbage state(w,e,w,w) -> state(e,e,w,e)
State state(e,e,w,e) already seen
Backtracking from using state(w,e,w,w)
try farmer takes self state(e,e,w,e) -> state(w,e,w,e)
try farmer takes goat state(w,e,w,e) -> state(e,e,e,e)
A solution of length 8: 'state(w,w,w,w)->state(e,w,e,w)->state(w,w,e,w)->state(e,w,e,e)->state(w,w,w,e)->state(e,e,w,e)->state(w,e,w,e)->state(e,e,e,e)'
true ;
Backtracking from using state(e,e,e,e)
try farmer takes self state(w,e,w,e) -> state(e,e,w,e)
State state(e,e,w,e) already seen
Backtracking from using state(w,e,w,e)
Backtracking from using state(e,e,w,e)
try farmer takes goat state(w,w,w,e) -> state(e,w,e,e)
State state(e,w,e,e) already seen
Backtracking from using state(w,w,w,e)
try farmer takes cabbage state(e,w,e,e) -> state(w,w,e,w)
State state(w,w,e,w) already seen
Backtracking from using state(e,w,e,e)
try farmer takes self state(w,w,e,w) -> state(e,w,e,w)
State state(e,w,e,w) already seen
Backtracking from using state(w,w,e,w)
Backtracking from using state(e,w,e,w)
false.