:- use_module(library(tor_clpfd)).

go1 :- search(dbs(17,wgc)).
go2 :- search(id(wgc)).
go3 :- search(lds(wgc)).

wgc :-
  initial_state(State),
  wgc(State).

wgc(State) :-
  final_state(State), !.
wgc(State) :-
  move(State,Move),
  update(State,Move,State1),
  legal(State1),
  wgc(State1).

initial_state(wgc(left, [wolf, goat, cabbage], [])).

final_state(wgc(right, [], [wolf, goat, cabbage])).

move(wgc(Bank, Left, Right),Move) :-
  ( Bank == left,
    tor_member(Move, Left)
  tor
    Bank == right,
    tor_member(Move, Right )
  tor
    Move = alone
  ).

:- tor tor_member/2.
tor_member(X,[X|_]).
tor_member(X,[_|Xs]) :- tor_member(X,Xs).

update(wgc(B,L,R), Cargo, wgc(B1, L1, R1)) :-
  update_boat(B, B1),
  update_banks(Cargo, B, L, R, L1, R1).

update_boat(left, right).
update_boat(right, left).

update_banks(alone, _B, L, R, L, R) :- !.
update_banks(Cargo, left, L, R, L1, R1) :- !,
  select(Cargo, L, L1),
  insert(Cargo, R, R1).
update_banks(Cargo, right, L, R, L1, R1) :-
  select(Cargo, R, R1),
  insert(Cargo, L, L1).

insert(X,[Y|Ys], [X,Y|Ys]) :-
  precedes(X,Y), !.
insert(X, [Y|Ys], [Y|Zs]) :-
  precedes(Y,X), !,
  insert(X,Ys,Zs).
insert(X, [], [X]).

precedes(wolf, _X).
precedes(_X, cabbage).

legal(wgc(left, _L, R)) :- \+ illegal(R).
legal(wgc(right, L, _R)) :- \+ illegal(L).

illegal(Bank) :- memberchk(wolf, Bank), memberchk(goat, Bank).
illegal(Bank) :- memberchk(goat, Bank), memberchk(cabbage, Bank).
