% Solution to the It's a Tie logic puzzle.

% Facts

kid(joanne).
kid(lou).
kid(ralph).
kid(winnie).

friend(bear).
friend(moose).
friend(seal).
friend(zebra).

adventure(circus).
adventure(band).
adventure(spaceship).
adventure(train).


solve :-
    friend(JoanneFriend), friend(LouFriend), friend(RalphFriend), friend(WinnieFriend),
    all_different([JoanneFriend, LouFriend, RalphFriend, WinnieFriend]),

    adventure(JoanneAdventure), adventure(LouAdventure), adventure(RalphAdventure), adventure(WinnieAdventure),
    all_different([JoanneAdventure, LouAdventure, RalphAdventure, WinnieAdventure]),

    Stories = [ story(joanne, JoanneFriend, JoanneAdventure),
              story(lou, LouFriend, LouAdventure),
              story(ralph, RalphFriend, RalphAdventure),
              story(winnie, WinnieFriend, WinnieAdventure) ],

    % 1. The seal (who isn't 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(_, seal, spaceship), Stories),
    \+ member(story(_, seal, train), Stories),

    % 2. Joanne's imaginary friend (who ins't the grizzly bear) when to the circus.
    member(story(joanne, _, circus), Stories),
    \+ member(story(joanne, bear, _), Stories),

    % 3. Winnie's imaginary friend is a zebra.
    member(story(winnie, zebra, _), Stories),

    % 4. The grizzly bear didn't board the spaceship to the moon.
    \+ member(story(_, bear, spaceship), Stories),

    tell(joanne, JoanneFriend, JoanneAdventure),
    tell(lou, LouFriend, LouAdventure),
    tell(ralph, RalphFriend, RalphAdventure),
    tell(winnie, WinnieFriend, WinnieAdventure).

tell(Kid, Friend, Story) :- write(Kid), write(' wrote the '), write(Story),
    write(' story with the '), 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([_]).
