Swi Prolog - Реализация программы кувшин с водой со списками

Извините за ранее, впервые за публикацию в этом, пытаясь заставить этот список повторяться через каждое из действий, сохраняя его посещенные элементы списка, а затем проверять рекурсию, если элемент не находится в списке, состояние которого будет изменено. Мне нужно выяснить, почему это работает не так, как ожидалось, кажется, что результаты 7,0, 0,0, 0,4 и 7,4, и проверка, кажется, показывает те же 4 результата в одном прогоне этой программы, случайным образом выплевывая одно из них, является неправильным порядком действий, так как я знаю, что вы должны перейти из самого тяжелого условия, чтобы соответствовать, цель состоит в том, чтобы заполнить это с помощью вызова решения (состояние (0,0)). Затем вы должны получить 5 в кувшине в конце вызова и распечатать список, который показывает путь, который он использовал, и затем найти другое решение, поскольку может быть только два, где есть 5L в кувшине 7L.

action(state(L,R), P, state(7,R)) :- 
    L < 4, 
    not(lists:member(state(7,R),P)), 
    print(state(7,R)).
action(state(L,R), P, state(L,4)) :- 
    R < 4, 
    not(lists:member(state(L,4),P)), 
    print(state(L,4)).
action(state(L,R), P, state(0,R)) :- 
    L > 0, 
    not(lists:member(state(0,R),P)), 
    print(state(0,R)).
action(state(L,R), P, state(L,0)) :- 
    R > 0, 
    not(lists:member(state(L,0),P)), 
    print(state(L,0)).
action(state(L,R), P, state(7,C)) :- 
    not(lists:member(state(7,C),P)), 
    C is L + R -7,  
    C > 7,   
    print(state(7,C)).
action(state(L,R), P, state(C,4)) :- 
    not(lists:member(state(C,4),P)), 
    C is L + R -4, 
    C > 4, 
    print(state(C,4)).
action(state(L,R), P, state(0,C)) :- 
    not(lists:member(state(0,C),P)), 
    C is L + R, 
    C @=< 4, 
    print(state(0,C)).
action(state(L,R), P, state(C,0)) :- 
    not(lists:member(state(C,0),P)), 
    C is L + R, 
    C @=< 7, 
    print(state(C,0)).

solve(X) :- 
    reachedgoal(X,[],A).

reachedgoal(state(5,_),L,L).
reachedgoal(State1,P,L) :- 
    action(State1,P,State2),   
    not(lists:member(State2,P)), 
    reachedgoal(State2,[State1|P],L).

1 ответ

Решение

Было несколько небольших логических ошибок, и нет смысла проверять наличие повторяющихся действий, прежде чем вычислять значения.

solve(X) :-
  reachedgoal(X,[],_).

reachedgoal(state(5,_),L,L).
reachedgoal(State1,P,L) :-
  action(State1,P,State2),
  \+ member(State2,P),
  reachedgoal(State2,[State1|P],L).

action(state(_L,R),P,state(7,R)) :- % fill left jug (7l)
  \+ member(state(7,R),P),
  print(state(7,R)),nl.
action(state(L,_R),P,state(L,4)) :- % fill right jug (4l)
  \+ member(state(L,4),P),
  print(state(L,4)),nl.

action(state(_L,R),P,state(0,R)) :- % empty left jug
  \+ member(state(0,R),P),
  print(state(0,R)),nl.
action(state(L,_R),P,state(L,0)) :- % empty right jug
  \+ member(state(L,0),P),
  print(state(L,0)),nl.

action(state(L,R),P,state(7,C)) :- % from right jug to left jug until left full
  C is L + R - 7,
  C > 0, C =< 4,
  \+ member(state(7,C),P),
  print(state(7,C)),nl.
action(state(L,R),P,state(C,4)) :- % from left jug to right jug until right full
  C is L + R - 4,
  C > 0, C =< 7,
  \+ member(state(C,4),P),
  print(state(C,4)),nl.

action(state(L,R),P,state(0,C)) :- % from left jug to right jug until left empty
  C is L + R,
  C =< 4,
  \+ member(state(0,C),P),
  print(state(0,C)),nl.
action(state(L,R),P,state(C,0)) :- % from right jug to left jug until right empty
  C is L + R,
  C =< 7,
  \+ member(state(C,0),P),
  print(state(C,0)),nl.

Это производит:

| ?- solve(state(0,0)).
state(7,0)
state(7,0)
state(7,4)
state(7,4)
state(0,4)
state(0,4)
state(4,0)
state(4,4)
state(4,4)
state(7,1)
state(7,1)
state(0,1)
state(0,1)
state(1,0)
state(1,4)
state(1,4)
state(5,0)
yes

Дублирование происходит из-за недостаточных условий в действиях (см. Ниже).

Проверка на дублированное состояние в каждом из действий расточительна, как вы также проверяете его в reachedgoal/3и приятнее и чище просто напечатать список в конце.

solve :-
  solve(state(0,0),RevStates), reverse(RevStates,States),
  write(States), nl.

solve(X,States) :-
  reachedgoal(X,[],States).

reachedgoal(state(5,_),L,L).
reachedgoal(State1,P,L) :-
  action(State1,State2),
  \+ member(State2,P),
  reachedgoal(State2,[State1|P],L).

action(state(L,R),state(7,R)) :- % fill left jug (7l)
  L < 7.
action(state(L,R),state(L,4)) :- % fill right jug (4l)
  R < 4.
action(state(L,R),state(0,R)) :- % empty left jug
  L > 0.
action(state(L,R),state(L,0)) :- % empty right jug
  R > 0.
action(state(L,R),state(7,C)) :- % from right jug to left jug until left full
  R > 0, L < 7,
  C is L + R - 7, C > 0, C =< 4.
action(state(L,R),state(C,4)) :- % from left jug to right jug until right full
  L > 0, R < 4,
  C is L + R - 4, C > 0, C =< 7.
action(state(L,R),state(0,C)) :- % from left jug to right jug until left empty
  L > 0, C is L + R, C =< 4.
action(state(L,R),state(C,0)) :- % from right jug to left jug until right empty
  R > 0, C is L + R, C =< 7.

Теперь нет дубликатов:

| ?- solve.
[state(0,0),state(7,0),state(7,4),state(0,4),state(4,0),state(4,4),state(7,1),state(0,1),state(1,0),state(1,4)]
yes
Другие вопросы по тегам