# Farmer, Wolf, Goat and Cabbage

A classic problem from Artificial Intelligence: Structures and strategies for complex problem solving by George F. Luger and William A. Stubblefield.

A farmer wishes to transfer (by boat) a wolf, a goat, and a cabbage from the left bank of a river to the right bank. If left unsupervised, the wolf will eat the goat and the goat will eat the cabbage, but nothing will happen as long as the farmer is near.
Beside the farmer there is only room for one item in the boat.

This is a way to solve the problem in Visual Prolog:

```implement main

domains
bank = start; target.
state = s(bank Farmer, bank Wolf, bank Goat, bank Cabbage).

constants
initState : state = s(start, start, start, start).
goalState : state = s(target, target, target, target).

domains
cargo = alone; wolf; goat; cabbage.
move = m(cargo Cargo, bank After).

class predicates
solve : (state InitState) -> move* MoveList determ.
clauses
solve(Init) = MoveList :-
MoveList = solve1(Init, [Init]),
!.

class predicates
solve1 : (state S1, state* PreviousStates) -> move* MoveList nondeterm.
clauses
solve1(goalState, _PreviousStates) = [] :- % solved
!.
solve1(S1, PreviousStates) = [Move | MoveList] :-
% make one step
Move = move_nd(S1, S2),
% avoid illegal states
not(illegalState(S2)),
% avoid states that we have already been in
not(list::isMember(S2, PreviousStates)),
% solve the rest
MoveList = solve1(S2, [S2|PreviousStates]).

class predicates
move_nd : (state Before, state After [out]) -> move Move multi.
clauses
move_nd(s(A, X, Y, Z), s(B, X, Y, Z)) = m(alone, B) :- % sail alone
B = oppositeBank(A).
move_nd(s(A, A, X, Y), s(B, B, X, Y)) = m(wolf, B) :- % sail with wolf
B = oppositeBank(A).
move_nd(s(A, X, A, Y), s(B, X, B, Y)) = m(goat, B) :- % sail with goat
B = oppositeBank(A).
move_nd(s(A, X, Y, A), s(B, X, Y, B)) = m(cabbage, B) :- % sail with cabbage
B = oppositeBank(A).

class predicates
oppositeBank : (bank Bank) -> bank Opposite.
clauses
oppositeBank(start) = target.
oppositeBank(target) = start.

class predicates
illegalState : (state State) determ.
clauses
illegalState(s(A, B, B, _)) :- % wolf and goat opposite farmer
B = oppositeBank(A),
!.
illegalState(s(A, _, B, B)) :- % goat and cabbage opposite farmer
B = oppositeBank(A).

clauses
run():-
console::init(),
if MoveList = solve(initState) then
foreach m(A,B) = list::getMember_nd(MoveList) do
stdio::writef("Sail % to %\n", A, B)
end foreach
else
stdio::write("No solution")
end if.

end implement main```