?-op(100,yfx,':'). /* define : as a left-associative operator */ /* The major predicate is solve(Current_state, Goal_state, Traversed_path, Solution_path). where Traversed_path is a list of pourings made so far. */ solve(Goal, Goal, Path, Path). /* If the current state is the goal state, then output the path to the 4th argument */ solve(Current, Goal, Path, Solution) :- edge(Step, Current, New), /* move across river */ not(marked(solve(New, Goal, _, _))), /* Graph search requires checking whether we've searched this node before */ solve(New, Goal, Path:Step, Solution). /* depth-first search. */ edge(goLeft(M,C, W:X:left), U:V:right, W:X:left) :- digit(M), digit(C), M+C>0, M+C<3, W is U+M, X is V+C, safe(W,X). edge(goRight(M,C, W:X:right), U:V:left, W:X:right) :- digit(M), digit(C), M+C>0, M+C<3, W is U-M, X is V-C, safe(W,X). safe(X,Y) :- X>=0, Y>=0, X=<3, Y=<3, (X>=Y ; X=:=0), (3-X>=3-Y ; 3-X=:=0). digit(0). digit(1). digit(2). not(X) :- \+(X). /*Check whether a node was already searched. The rule marked(X) :- asserta((marked(X):- !)), fail. causes a node to be marked if it was not marked before, and fails. The next time it checks this node, it will succeed since that node had been asserted to be marked. Reset_marked permits the depth-first search to be done several times. */ reset_marked :- retractall(marked(_)), asserta( (marked(X) :- asserta((marked(X):- !)), fail) ). missCann(Z) :- reset_marked, solve(3:3:left,0:0:right,start,Z). ?-missCann(W), print(W), nl, fail.