% Solution to the Imaginary Friends logic puzzle.

% Facts
friend(bear).
friend(moose).
friend(seal).
friend(zebra).

kid(joanne).
kid(lou).
kid(ralph).
kid(winnie).

adventure(circus).
adventure(band).
adventure(spaceship).
adventure(train).


solve :-
    adventure(JoanneAdventure), adventure(LouAdventure), adventure(RalphAdventure),
    adventure(WinnieAdventure),
    all_different([JoanneAdventure, LouAdventure, RalphAdventure, WinnieAdventure]),

    friend(JoanneFriend), friend(LouFriend), friend(RalphFriend), friend(WinnieFriend),
    all_different([bearFriend, mooseFriend, sealFriend, zebraFriend]),



    Story = [ story(joanne, JoanneAdventure, JoanneFriend),
              story(lou, LouAdventure, LouFriend),
              story(ralph, RalphAdventure, RalphFriend),
              story(winnie, WinnieAdventure, WinnieFriend) ],



    % 1. The seal (isnt a creation of Joanne or Lou),
    %		neither rode on a spacship nor rode on a train
    (   (   \+ member(story(joanne, _, seal), Story),
    \+ member(story(lou, _, seal), Story));
    (   \+ member(story(_, spaceship, seal), Story),
    \+ member(story(_, train, seal), Story))),


    % 2. Joannes friend, who isnt a bear, went to the circus
    \+ member(story(joanne, _, bear), Story),
    member(story(joanne, circus, _), Story),

    % 3. Winnie's friend is a zebra
    member(story(winnie, _, zebra), Story),

    % 4. The Bear didnt go to the moon on the spaceship
    \+ member(story(_, spaceship, bear), Story),

	tell(joanne, JoanneAdventure, JoanneFriend),
	tell(lou, LouAdventure, LouFriend),
	tell(ralph, RalphAdventure, RalphFriend),
	tell(winnie, WinnieAdventure, WinnieFriend).

tell(Author, Trip, Them) :- write('Little '), write(Author), write(' went on a trip with '), write(Them),
    write(' on a '), write(Trip), write('.'), nl.

% If the head of the list is in the tail, fail.
all_different([Head|Tail]) :- member(Head, Tail), !, fail.
% Otherwise, check the tail of the list.
all_different([_|Tail]) :- all_different(Tail).
% If there's only one thing in the list, it's fine.
all_different([_]).
