% Prolog Challenge 1 - Imaginary Friends

% Facts
child(joanne).
child(lou).
child(ralph).
child(winnie).

animal(bear).
animal(moose).
animal(seal).
animal(zebra).

adventure(circus).
adventure(band).
adventure(spaceship).
adventure(train).

solve :-
    animal(JoanneAnimal), animal(LouAnimal), animal(RalphAnimal),
    animal(WinnieAnimal),
    all_different([JoanneAnimal, LouAnimal, RalphAnimal, WinnieAnimal]),

    adventure(JoanneAdventure), adventure(LouAdventure), adventure(RalphAdventure),
    adventure(WinnieAdventure),
    all_different([JoanneAdventure, LouAdventure, RalphAdventure, WinnieAdventure]),



    Stories = [ story(joanne, JoanneAnimal, JoanneAdventure),
                story(lou, LouAnimal, LouAdventure),
                story(ralph, RalphAnimal, RalphAdventure),
                story(winnie, WinnieAnimal, WinnieAdventure) ],


    % 1. The seal wasn't created by Joanne or Lou and neither rode in a spaceship
    %    nor took a trip on a 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 isn't the grizzly bear, but it went to the circus
    \+ member(story(joanne, bear, _), Stories),
       member(story(joanne, _, circus), Stories),

    % 3. Winnie's imaginary friend is a zebra
      member(story(winnie, zebra, _), Stories),

    % 4. The grizzly bear didn't board the spaceship
    \+ member(story(_, bear, spaceship), Stories),

    tell(joanne, JoanneAnimal, JoanneAdventure),
    tell(lou, LouAnimal, LouAdventure),
    tell(ralph, RalphAnimal, RalphAdventure),
    tell(winnie, WinnieAnimal, WinnieAdventure).

tell(Author, Animal, Adventure) :- write(Author), write(' created the imaginary friend '), write(Animal),
    write(', who did the '), write(Adventure), write(' adventure.'), 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([_]).
    




