%solution to imaginary friends logic puzzle.

%facts
friend(grizzly_bear).
friend(moose).
friend(seal).
friend(zebra).

child(joanne).
child(lou).
child(ralph).
child(winnie).

trip(circus).
trip(rock_band).
trip(spaceship).
trip(train).

%solution
solve :-
    trip(JoanneTrip), trip(LouTrip), trip(RalphTrip), trip(WinnieTrip),
    all_different([JoanneTrip, LouTrip, RalphTrip, WinnieTrip]),

    friend(JoanneFriend), friend(LouFriend), friend(RalphFriend), friend(WinnieFriend),
    all_different([JoanneFriend, LouFriend, RalphFriend, WinnieFriend]),


    Stories = [ story(joanne, JoanneTrip, JoanneFriend),
                story(lou, LouTrip, LouFriend),
                story(ralph, RalphTrip, RalphFriend),
                story(winnie, WinnieTrip, WinnieFriend) ],

%rules
%The seal(who isnt the creation of either Joanne or Lou) neither rode to the moon 
%in a spaceship nor took a trip around the world on a magic train.
(( \+member(story(joanne, _, seal), Stories),
    \+member(story(lou, _, seal), Stories),
    \+member(story(_, spaceship, seal), Stories),
    \+member(story(_, train, seal), Stories) ) ),

%Joannes imaginary friend(who isnt the grizzly bear)
%went to the circus.
(( member(story(joanne, circus, _), Stories),
    \+member(story(joanne, _, grizzly_bear), Stories) ) ),

%Winnies imaginary friend is a zebra.
(member(story(winnie, _, zebra), Stories)),

%The grizzly bear didnt board the spaceship to the moon.
\+ member(story(_, spaceship, grizzly_bear), Stories),

%display results
tell(joanne, JoanneTrip, JoanneFriend),
tell(lou, LouTrip, LouFriend),
tell(ralph, RalphTrip, RalphFriend),
tell(winnie, WinnieTrip, WinnieFriend).

tell(Who, Where, Friend) :- write(Who), write(' went to '), write(Where),
write(' with their imaginary '), write(Friend), 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([_]).