prologwater-jug-problem

Water jug puzzle in SWI-Prolog


I am an AI and Prolog newbie. I was trying to implement the 2 Water Jug problem in SWI Prolog. However, my solution is returning a global stack overflow.

I know this question has been asked in the past and has had numerous answers/solutions, as a complete newbie my approach is a bit naive, hence I wanted to know what am I doing wrong.

Problem:

There are two jugs, one has a capacity of 4 gallons while the other can hold up to 3 gallons. I need 2 gallons in the 4 gallon jug and the other one should be empty.

Here's the code:

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$

Here's the output.

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
...

Solution

  • in Prolog, it make little sense to output the action 'description', because any sequence of actions that will fail will be undone, thus trying any available alternative. Then the first step I would take is a 'cosmetic one' : move away the description, that can be inferred from two adjacent steps of a solution (the list Z), and add a Solution argument to maneuver.

    Another important improvement: all your steps repeat the same - wrong - pattern: for instance

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

    make a 'subroutine' (and correct the mistake, that - I think - leads to the loop):

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