任何人都可以找到为什么我的代码中没有任何真正的答案吗?例如,我写go(7,3,l)
,我想它应该将3升水移到第二个水壶,但根据序言它是错误的。怎么了?
:- dynamic go/3.
:- dynamic cur_state/1,init/5.
:- dynamic end_state/1, final/5.
cur_state(State):-State = state(10,0,0,7,l).
end_state(State):-State = state(0,3,3,0,r).
pour(state(D1,D2,D3,n,l),move(D,C,r),state(D,C,D3,n,r)) :-
D is D1-n,
C is D2+n.
pour(state(D1,D2,D3,n,r),move(D,C,l),state(D,C,D3,n,l)) :-
D is D1-n,
C is D2.
pour(state(D1,D2,D3,n,l),move(D,C,r),state(D,D2,C,n,r)) :-
D is D1-n,
C is D3+n.
pour(state(D1,D2,D3,n,l),move(D,C,r),state(D1,D,C,n,r)) :-
D is D2-n,
C is D3+n.
pour(state(D1,D2,D3,n,r),move(D,C,l),state(D1,D,C,n,l)) :-
D is D2-n,
C is D1+n.
pour(state(D1,D2,D3,n,r),move(D,C,l),state(D1,D,c,n,l)) :-
D is D2-n,
C is D3.
pour(state(D1,D2,D3,n,l),move(D,C,r),state(C,D2,D,n,r)) :-
D is D3-n,
C is D1.
pour(state(D1,D2,D3,n,r),move(D,C,l),state(D1,C,D,n,l)) :-
D is D3-n,
C is D2+n.
pour(state(D1,D2,D3,n,r),move(D,C,l),state(C,D2,D,n,l)) :-
D is D3-n,
C is D1+n.
carry(7,0).
carry(3,0).
carry(10,0).
carry(7,0).
carry(7,3).
legal(10,X,Y):-X+Y<10.
legal(X,Y,Z):-X+Y+Z<10.
legal(X,7,Y):-X+Y=<3.
legal(X,Y,3):-X+Y=<7.
newstate(state(D1,D2,D3,n,l),state(D11,D22,D33,n1,r)):-
carry(M,C),
M=<7,C=<3,
D22 is D2+n,
D11 is D1-n,
D3 is D33,
n1 is n,
D2=<7,D1=<10,
legal(D1,D2,D3).
newstate(state(D1,D2,D3,n,r),state(D11,D22,D33,n1,l)):-
carry(M,C),
M=<10,C=<100,
D11 is D1-n,
D22 is D2,
D33 is D3,
D1=<10,
legal(D1,D2,D3).
newstate(state(D1,D2,D3,n,l),state(D11,D22,D33,n1,r)):-
carry(M,C),
M=<10,C<3,
D11 is D1-n,
D33 is D3+n,
D22 is D2,
D1=<10,D3=<3,
legal(D1,D2,D3).
newstate(state(D1,D2,D3,n,r),state(D11,D22,D33,n1,l)):-
carry(M,C),
M=<7,C=<3,
D22 is D2-n,
D33 is D1+n,
D11 is D1,
D2=<7,D1=<10,
legal(D1,D2,D3).
newstate(state(D1,D2,D3,n,l),state(D11,D22,D33,n1,r)):-
carry(M,C),
M=<7,C=0,
D22 is D2-n,
D33 is D3+n,
D11 is D1,
D2=<7,D3=<3,
legal(D1,D2,D3).
newstate(state(D1,D2,D3,n,r),state(D11,D22,D33,n1,l)):-
carry(M,C),
M=<7,C=<100,
D22 is D2-n,
D33 is D3,
D11 is D1,
D2=<7,
legal(D1,D2,D3).
newstate(state(D1,D2,D3,n,r),state(D11,D22,D33,n1,l)):-
carry(M,C),
M=<3,C=<7,
D22 is D2+n,
D33 is D3-n,
D11 is D1,
D3=<3,D2=<7,
legal(D1,D2,D3).
newstate(state(D1,D2,D3,n,r),state(D11,D22,D33,n1,l)):-
carry(M,C),
M=<3,C=<100,
D11 is D1+n,
D33 is D3-n,
D22 is D2,
D3=<3,D1=<10,
legal(D1,D2,D3).
newstate(state(D1,D2,D3,n,l),state(D11,D22,D33,n1,r)):-
carry(M,C),
M=<3,C=<100,
D33 is D3-n,
D22 is D2,
D11 is D1,
D3=<3,
legal(D1,D2,D3).
eisodos(_):- cur_state(State),write(State),nl.
init(S1,S2,S3,S4,S5):-assert(cur_state(State):-State = state(S1,S2,S3,S4,S5)),write('Arxikh:'),
write(state(S1,S2,S3,S4,S5)),retractall(init(S1,S2,S3,S4,S5)),nl.
final(S1,S2,S3,S4,S5):-assert(end_state(State):-State = state(S1,S2,S3,S4,S5)),write('Telikh:'),
write(state(S1,S2,S3,S4,S5)),retractall(init1(S1,S2,S3,S4,S5)),nl.
go(Move1,Move2,Move3):-cur_state(State),newstate(State,NextState),
pour(State,move(Move1,Move2,Move3), NextState),
retractall(cur_state(State):-State = state(_,_,_,_,_)),asserta(cur_state(NextState)),
((end_state(NextState),write('Bravo!!!!')) ;(write(' ---*Eiste sthn katastash --- :'),write(NextState))),nl.
答案 0 :(得分:3)
扩展@Mog的答案,如果你想找到最短的解决方案,我建议使用迭代加深。以下是基于@Mog发布的代码(因此解决了与OP发布的问题略有不同的相同问题)。由于我们想要描述一个列表(移动),DCG表示法很方便:
solution(Path) :- length(Path, _), phrase(path([0-3, 0-5, 8-8]), Path).
path(State) --> { equivalent(State, [0-3, 4-5, 4-8]) }.
path(State0) --> [From-To],
{ move(State0, State), State = [_-From, _-To, _] },
path(State).
equivalent(State1, State2) :- forall(member(X, State1), member(X, State2)).
move(State, [NewX-From, NewY-To|NewRest]) :-
select(X-From, State, Rest),
X \== 0,
select(Y-To, Rest, NewRest),
Fillable is To - Y,
ToFill is min(X, Fillable),
NewY is Y + ToFill,
NewX is X - ToFill.
示例查询:
?- solution(Ps).
Ps = [8-5, 5-3, 3-8, 5-3, 8-5, 5-3, 3-8] .
答案 1 :(得分:2)
正如我在评论中所说,我有点不知道如何帮助你完成当前的工作,因为它有很多错误的东西。我建议你阅读一本关于Prolog的精彩教程(例如Learn Prolog now),这样你就可以掌握语言基础知识。如果您有兴趣,这是解决问题的简单方法。如果您不希望破坏您的问题,请不要进一步阅读:](我发布的那个是关于3/5/8壶和4/4分裂)。
go(Path) :-
solve([0-3, 0-5, 8-8], [], [], Temp),
reverse(Temp, Path).
solve(State, _Visited, Path, Path) :-
equivalent(State, [0-3, 4-5, 4-8]).
solve(State, Visited, Acc, Path) :-
move(State, NewState),
NewState = [_-From, _-To|_],
forall(member(Past, Visited), \+ equivalent(Past, NewState)),
solve(NewState, [NewState|Visited], [From-To|Acc], Path).
equivalent(State1, State2) :-
forall(member(X, State1), member(X, State2)).
move(State, [NewX-From, NewY-To|NewRest]) :-
select(X-From, State, Rest),
X \== 0,
select(Y-To, Rest, NewRest),
Fillable is To - Y,
ToFill is min(X, Fillable),
NewY is Y + ToFill,
NewX is X - ToFill.
如果您在阅读有关prolog的更多信息后需要解释代码,请不要犹豫!
答案 2 :(得分:0)
首先需要纠正它的基本语法:变量必须以大写字母开头,所以例如你必须改变这个规则
pour(state(D1,D2,D3,n,l),move(D,C,r),state(D,C,D3,n,r)) :-
D is D1-n,
C is D2+n.
到
pour(state(D1,D2,D3,N,l),move(D,C,r),state(D,C,D3,N,r)) :-
D is D1-N,
C is D2+N.
和
newstate(state(D1,D2,D3,n,l),state(D11,D22,D33,n1,r)):-
carry(M,C),
M=<7,C=<3,
D22 is D2+n,
D11 is D1-n,
D3 is D33,
n1 is n,
D2=<7,D1=<10,
legal(D1,D2,D3).
到
newstate(state(D1,D2,D3,N,l),state(D11,D22,D33,N1,r)):-
carry(M,C),
M=<7,C=<3,
D22 is D2+N,
D11 is D1-N,
D3 is D33,
N1 is N,
D2=<7,D1=<10,
legal(D1,D2,D3).
您应该意识到N1仅在第一个newstate / 2过程中被赋值:然后更正该规则的其他实例。
然后你应该删除无用的动态断言:想想你的实际断言/回收用法:你需要的是在任何一步改变状态在'jugs'之间移动'water':所以你应该在进入循环时断言/收回状态/ 5,从初始状态(在启动程序中断言)到最终可接受状态,进行测试以停止循环。
但是这种基于状态变化的风格导致非常难以调试。请尝试删除altogheter动态,断言/撤消,并绕过循环中的状态。