/* goat.pl * * Wolf, Goat, Cabbage Puzzle * * demonstrates searching a cyclic state space using Prolog * * demo for CS 313 Daniel Scharstein */ :- use_module(library(lists)). /* The problem: A man travels with a wolf, a goat, and a cabbage. He needs to cross a river in a boat that can at most hold himself and one of his three objects. He cannot leave the wolf alone with the goat or the goat with the cabbage, because the former would eat the latter in each case. How can the river be crossed? */ /* represent valid passenger configurations as lists: */ canBeInBoat([man]). canBeInBoat([man, wolf]). canBeInBoat([man, goat]). canBeInBoat([man, cabbage]). /* represent groups of objects on either shore as lists: */ illegal(Group) :- not(member(man, Group)), member(wolf, Group), member(goat, Group). illegal(Group) :- not(member(man, Group)), member(goat, Group), member(cabbage, Group). legal(Group) :- not(illegal(Group)). /* print all solutions */ printAll :- solve(Result), nl, /* newline */ printList(Result), fail. /* backtrack to find other solutions */ /* print each element of a list on its own line */ printList([]). printList([H|T]) :- writeln(H), printList(T). /* we will represent states using the goups on the left shore */ /* this calls the main search routine solve/5 */ solve(Result) :- /* initial values (makes it easier to read): */ Left = [man, wolf, goat, cabbage], /* group on left bank of river */ Right = [], /* group on right bank of river */ Moves = [], /* moves made so far */ States = [Left], /* states been in so far */ solve(Left, Right, Moves, States, Result). /* if left bank empty, done: return moves made in reverse order */ solve([], _, Moves, _, Result) :- reverse(Moves, Result). /* otherwise, try a move, make sure it doesn't result in a state we've been in already, and keep searching recursively */ solve(L, R, Moves, States, Result) :- makeMove(L, R, NewL, NewR, M), not(member(NewL, States)), solve(NewL, NewR, [M|Moves], [NewL|States], Result). /* comes up with a legal move */ makeMove(L, R, NewL, NewR, goRight(Passengers)) :- canBeInBoat(Passengers), remove(Passengers, L, NewL), legal(NewL), add(Passengers, R, NewR). makeMove(L, R, NewL, NewR, goLeft(Passengers)) :- canBeInBoat(Passengers), remove(Passengers, R, NewR), legal(NewR), add(Passengers, L, NewL). remove(X, L, NewL) :- mergeLists(X, NewL, L). add(X, L, NewL) :- mergeLists(X, L, NewL), /* make sure that NewL is in unique order */ mergeLists(NewL, _, [man, wolf, goat, cabbage]). mergeLists([], [], []). mergeLists([H|A], B, [H|C]) :- mergeLists(A, B, C). mergeLists(A, [H|B], [H|C]) :- mergeLists(A, B, C).