water jug in prolog

leaflyfly picture leaflyfly · Oct 3, 2011 · Viewed 10.6k times · Source

It is a water jug problem. The larger bucket holds 5, the smaller bucket holds 3. I want to get 4 in the larger bucket.

The problem is that when I run I cannot get any answer, it produces an error. It doesn't seem like an obvious error, the algorithm is simple and direct.

Could anyone help me to find what is wrong with it?

check_safe(X,Y):- X>=0,X=<3,Y>=0,Y=<5.

%empty the 3 bucket

move(state(X,Y),state(0,Y)):- X>0,check_safe(0,Y).

%empty the 5 bucket

move(state(X,Y),state(X,0)):- Y>0,check_safe(X,0).

%fill the 3 bucket

move(state(X,Y), state(3,Y)):- X<3, X>=0,check_safe(3,Y).

%fill the 5 bucket

move(state(X,Y),state(X,5)):- Y>=0, Y<5,check_safe(X,5).

%transfer from 3 to 5 until the larger bucket is full

move(state(X,Y),state(NewX,5)):- X+Y>= 5, X>0,Y>=0, NewX=X+Y-5,check_safe(NewX,5).

%transfer from 3 to 5 until the smaller bucket is empty

move(state(X,Y),state(0,NewY)):- X+Y<5, X>0,Y>=0, NewY=X+Y,check_safe(0,NewY).

%transfer from 5 to 3 until the smaller is full

move(state(X,Y),state(3,NewY)):- Y>0,X>=0,X+Y>=5, NewY=Y+X-3,check_safe(3,NewY).

%transfer from 5 to 3 until the larger is empty

move(state(X,Y),state(NewX,0)):-Y>0,X>=0, X+Y<5, NewX=Y+X,check_safe(NewX,0).


path(X,X,_,[X]).
path(X,Y,BeenStates,Path):-
    move(X,Somewhere),not(member(Somewhere,BeenStates)),
    path(Somewhere,Y,[Somewhere|BeenStates],Path2), Path = [X|Path2].


puzzle:- path(state(0,0),state(0,5),[state(0,0)],PathList),X>=0,X=<5,
    writeOut(PathList).

% Here's an easy little predicate for printing a list.
writeOut([]).
writeOut([H|T]):-write(H),nl, writeOut(T).

Answer

Enigmativity picture Enigmativity · Oct 4, 2011

You're not using "is" for the assignments.

Your puzzle\0 predicate has two unbound variables: X & Y.

And your path\4 predicates are faulty.

Try these:

path([state(X, 4)|Xs],[state(X, 4)|Xs]):- !.
path([X|Xs],Rs):-
    move(X,Y),not(member(Y,[X|Xs])),
    path([Y,X|Xs],Rs).

puzzle:- path([state(0,0)],PathList),
    write(PathList), nl, fail.

Below is my solution to this problem:

move(s(X,Y),s(Z,5)) :- Z is X - (5 - Y), Z >= 0.
move(s(X,Y),s(Z,0)) :- Z is X + Y, Z =< 3.
move(s(X,Y),s(3,Z)) :- Z is Y - (3 - X), Z >=0.
move(s(X,Y),s(0,Z)) :- Z is X + Y, Z =< 5.

move(s(0,Y),s(3,Y)).
move(s(X,0),s(X,5)).
move(s(X,Y),s(X,0)) :- Y > 0.
move(s(X,Y),s(0,Y)) :- X > 0.

moves(Xs) :- moves([s(0,0)],Xs).
moves([s(X0,Y0)|T], [s(X1,4),s(X0,Y0)|T])
    :- move(s(X0,Y0),s(X1,4)), !.
moves([s(X0,Y0)|T],Xs) :-
    move(s(X0,Y0),s(X1,Y1)), 
    not(member(s(X1,Y1),[s(X0,Y0)|T])),
    moves([s(X1,Y1),s(X0,Y0)|T],Xs).

?- moves(Xs), write(Xs), nl, fail.

I get these solutions:

[s(0,4),s(3,1),s(0,1),s(1,0),s(1,5),s(3,3),s(0,3),s(3,0),s(0,0)]
[s(3,4),s(2,5),s(2,0),s(0,2),s(3,2),s(0,5),s(1,5),s(3,3),s(0,3),s(3,0),s(0,0)]
[s(3,4),s(2,5),s(2,0),s(0,2),s(3,2),s(0,5),s(3,5),s(3,0),s(0,0)]
[s(0,4),s(3,1),s(0,1),s(1,0),s(1,5),s(3,3),s(0,3),s(3,0),s(3,2),s(0,5),s(0,0)]
[s(3,4),s(2,5),s(2,0),s(0,2),s(3,2),s(0,5),s(0,0)]
[s(0,4),s(3,1),s(0,1),s(1,0),s(1,5),s(3,3),s(0,3),s(3,0),s(3,5),s(0,5),s(0,0)]

Obviously the second to last, being the shortest, is the best.