Что не так с моей программой пролога для решения 3 кувшинов с водой? - PullRequest
2 голосов
/ 05 января 2012

Может кто-нибудь узнать, почему у меня не может быть никаких истинных ответов с моим «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 ]

3 голосов
/ 06 января 2012

Расширяя ответ @ 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] .
2 голосов
/ 06 января 2012

Ну, как я уже сказал в своем комментарии, я вроде бы не знаю, как помочь вам с вашей текущей работой, поскольку в ней так много неправильных вещей. Я бы посоветовал вам прочитать хороший учебник по Прологу (например, Изучите Пролог сейчас ), чтобы вы могли освоить основы языка. Вот простой способ решить вашу проблему, если вы заинтересованы. Если вы не хотите, чтобы ваша проблема была испорчена, просто не читайте дальше:] (я написал о кувшинах 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.

Если вам нужны пояснения по коду после того, как вы прочли немного больше о прологе, не стесняйтесь!

0 голосов
/ 06 января 2012

Первое, что вам нужно исправить, это его основной синтаксис: переменные должны начинаться с заглавной буквы, поэтому, например, вы должны изменить это правило

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: вам нужно изменить состояние , перемещая «воду» между «кувшинами» на любом этапе: так что вам следует состояние assert / retract / 5 во время цикла в go из исходного состояния (подтвердите это при запуске программы) в конечное приемлемое состояние, которое будет проверено в go для остановки цикла.

Но этот стиль, основанный на изменении состояния, приводит к очень трудной отладке. Вместо этого попробуйте удалить динамический altogheter, assert / retractall и передать состояние в цикле.

...