Пазл Кувшин для воды в SWI-Пролог

Я новичок AI и Пролог. Я пытался реализовать проблему 2 Water Jug в SWI Prolog. Тем не менее, мое решение возвращает global stack overflow,

Я знаю, что этот вопрос задавался в прошлом и имел многочисленные ответы / решения, так как в качестве новичка мой подход немного наивен, поэтому я хотел знать, что я делаю неправильно.

Проблема:

Есть два кувшина, один имеет емкость 4 галлона, а другой может вместить до 3 галлонов. Мне нужно 2 галлона в кувшине объемом 4 галлона, а другой должен быть пустым.

Вот код:

member(X, [X|R]).
member(X, [Y|R]) :- member(X,R).

append([X|Y], Z, [X|W]) :- append(Y,Z,W).
append([], X, X).

/*                                                                                                                                            
production rules for the water jug problem                                                                                                    
*/
maneuver(X, Y, Z):-X=:=2, Y=:=0, write('done').
maneuver(X, Y, Z):-X<4, \+ member(Z, (4,Y)), append(Z, [(4,Y)], A), write('Fill 4 gallon jug\n'), maneuver(4,Y,A).
maneuver(X, Y, Z):-Y<3, \+ member(Z, (X,3)), append(Z, [(X,3)], A), write('Fill 3 gallon jug\b'), maneuver(X,3,A).
maneuver(X, Y, Z):-X>0, \+ member(Z, (0,Y)), append(Z, [(0,Y)], A), write('Empty the 4 gallon jug\n'), maneuver(0,Y,A).
maneuver(X, Y, Z):-Y>0, \+ member(Z, (X,0)), append(Z, [(X,0)], A), write('Empty the 3 gallon jug\n'), maneuver(X,0,A).
maneuver(X, Y, Z):-X+Y>=4, Y>0, \+ member(Z, (4,Y-(4-X))), append(Z, [(4,Y-(4-X))], A), write('Pour from 3 gallon jug to 4 gallon jug\n'), ma$
maneuver(X, Y, Z):-X+Y>=3, X>0, \+ member(Z, (X-(3-Y),3)), append(Z, [(X-(3-Y),3)], A), write('Pour from 4 gallon jug to 3 gallon jug\n'), ma$
maneuver(X, Y, Z):-X+Y=<4, Y>0, \+ member(Z, (X+Y, 0)), append(Z, [(X+Y, 0)], A), write('Pour the water in the 3 gallon jug into the 4 gallon$
maneuver(X, Y, Z):-X+Y=<4, Y>0, \+ member(Z, (0, X+Y)), append(Z, [(0, X+Y)], A), write('Pour the water in the 4 gallon jug into the 3 gallon$

Вот вывод.

Fill 4 gallon jug
Fill 3 gallon juEmpty the 4 gallon jug
Fill 4 gallon jug
Empty the 4 gallon jug
Fill 4 gallon jug
Empty the 4 gallon jug
Fill 4 gallon jug
Empty the 4 gallon jug
Fill 4 gallon jug
Empty the 4 gallon jug
Fill 4 gallon jug
Empty the 4 gallon jug
Fill 4 gallon jug
Empty the 4 gallon jug
...

1 ответ

Решение

В Прологе не имеет смысла выводить действие "описание", потому что любая последовательность действий, которая потерпит неудачу, будет отменена, пытаясь таким образом найти любую доступную альтернативу. Тогда первый шаг, который я бы сделал, - это "косметический" шаг: уберите описание, которое можно вывести из двух смежных шагов решения (список Z), и добавьте аргумент "Решение" в маневр.

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

\+ member(Z, (4,Y)), append(Z, [(4,Y)], A)

сделайте подпрограмму (и исправьте ошибку, которая, я думаю, приведет к петле):

update(State, Step, Updated) :-
   \+ member(Step, State),
   append(State, [Step], Updated).

В вашем коде есть 2 ошибки, которые необходимо исправить.

  1. вы не можете напрямую писать или ссылаться на уравнения типа Y-(4-X),

например: если X=3,Y=5. Он будет рассматривать его как 5-(4-3), но не как 3. Итак, вам нужно взять дополнительные переменные, чтобы получить значение.

  1. Вам не нужно писать функцию добавления, поскольку вы добавляете только один элемент, к которому вы можете напрямую прикрепить его

Z как [(4,Y)|Z].

Модифицированный код будет таким:

member(X,[X|_]).
member(X,[Y|Z]):-member(X,Z).

move(X,Y,_):-X=:=2,Y=:=0,write('done'),!.
move(X,Y,Z):-X<4,\+member((4,Y),Z),write("fill 4 jug"),nl,move(4,Y,[(4,Y)|Z]).
move(X,Y,Z):-Y<3,\+member((X,3),Z),write("fill 3 jug"),nl,move(X,3,[(X,3)|z]).
move(X,Y,Z):-X>0,\+member((0,Y),Z),write("pour 4 jug"),nl,move(0,Y,[(0,Y)|Z]).
move(X,Y,Z):-Y>0,\+member((X,0),Z),write("pour 3 jug"),nl,move(X,0,[(X,0)|Z]).
move(X,Y,Z):-P is X+Y,P>=4,Y>0,K is 4-X,M is Y-K,\+member((4,M),Z),write("pour from 3jug to 4jug"),nl,move(4,M,[(4,M)|Z]).
move(X,Y,Z):-P is X+Y,P>=3,X>0,K is 3-Y,M is X-K,\+member((M,3),Z),write("pour from 4jug to 3jug"),nl,move(M,3,[(M,3)|Z]).
move(X,Y,Z):-K is X+Y,K<4,Y>0,\+member((K,0),Z),write("pour from 3jug to 4jug"),nl,move(K,0,[(K,0)|Z]).
move(X,Y,Z):-K is X+Y,K<3,X>0,\+member((0,K),Z),write("pour from 4jug to 3jug"),nl,move(0,K,[(0,K)|Z]).

если ввод:

move(0,0,[(0,0)]).

вывод:

fill 4 jug
fill 3 jug
pour 4 jug
pour 3 jug
fill 4 jug
pour from 4jug to 3jug
pour 3 jug
pour from 4jug to 3jug
fill 4 jug
pour from 4jug to 3jug
pour 3 jug
done
Другие вопросы по тегам