Что не так с моей программой пролога для решения 3 кувшинов с водой?
Может кто-нибудь узнать, почему у меня не может быть никаких истинных ответов с моим "go" в этом коде? Например, я пишу 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.
3 ответа
Первое, что вам нужно исправить, это основной синтаксис: переменные должны начинаться с заглавной буквы, поэтому, например, вы должны изменить это правило
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: затем исправьте другие экземпляры этого правила.
Затем вы должны удалить бесполезные динамические утверждения: подумайте о вашем фактическом использовании assert/retractall: вам нужно изменить состояние, перемещая "water" между "jugs" на любом шаге: так что вы должны утверждать / убирать состояние /5 во время цикла в перейти из исходного состояния (утвердить это при запуске программы) в конечное приемлемое состояние, которое будет проверено при переходе к остановке цикла.
Но этот стиль, основанный на изменении состояния, приводит к очень сложной отладке. Вместо этого попробуйте удалить динамический altogheter, assert/retractall и передать состояние в цикле.
Продолжая ответ @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] .
Ну, как я уже сказал в своем комментарии, я бы не знал, как помочь вам с вашей текущей работой, поскольку в ней так много неправильных вещей. Я бы посоветовал вам прочитать хороший учебник о Прологе (например, сейчас изучать Пролог), чтобы вы могли освоить основы языка. Вот простой способ решить вашу проблему, если вы заинтересованы. Если вы не хотите, чтобы ваша проблема была испорчена, просто не читайте дальше: ] (тот, который я выложил, о кувшинах 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.
Если вам нужны пояснения по коду после того, как вы прочли немного больше о прологе, не стесняйтесь!