% Program:  family.pl.solution
% Source:   Prolog
%
% Purpose:  This is the sample program for the Prolog Lab in COMP9414.
%           It is a simple Prolog program to demonstrate how prolog works.
%           See lab.html for a full description.
%
% History:  18-Feb-1999   Original code       Barry Drake
%           30-Mar-1999   Solutions added     Barry Drake
%           05-Nov-2006   SWI Prolog          Bill Wilson
%                         Checked - let Bill W know about any further problems

% parent(Parent, Child)
%
parent(albert, jim).
parent(albert, peter).
parent(jim, brian).
parent(john, darren).
parent(peter, lee).
parent(peter, sandra).
parent(peter, james).
parent(peter, kate).
parent(peter, kyle).
parent(brian, jenny).
parent(irene, jim).
parent(irene, peter).
parent(pat, brian).
parent(pat, darren).
parent(amanda, jenny).


% female(Person)
%
female(irene).
female(pat).
female(lee).
female(sandra).
female(jenny).
female(amanda).
female(kate).

% male(Person)
%
male(albert).
male(jim).
male(peter).
male(brian).
male(john).
male(darren).
male(james).
male(kyle).


% yearOfBirth(Person, Year).
%
yearOfBirth(irene, 1923).
yearOfBirth(pat, 1954).
yearOfBirth(lee, 1970).
yearOfBirth(sandra, 1973).
yearOfBirth(jenny, 1996).
yearOfBirth(amanda, 1979).
yearOfBirth(albert, 1926).
yearOfBirth(jim, 1949).
yearOfBirth(peter, 1945).
yearOfBirth(brian, 1974).
yearOfBirth(john, 1955).
yearOfBirth(darren, 1976).
yearOfBirth(james, 1969).
yearOfBirth(kate, 1975).
yearOfBirth(kyle, 1976).



% ----------------------
%  Solutions Start Here
% ----------------------


% grandparent(Grandparent, Grandchild)
% means Grandparent is a grandparent of Grandchild
%
grandparent(Grandparent, Grandchild) :-
	parent(Grandparent, Child),
	parent(Child, Grandchild).


% older(A,B)
% means A is older than B
%
older(A,B) :- yearOfBirth(A, Y1),
              yearOfBirth(B, Y2),
              Y2 > Y1.


% siblings(A,B)
% means A and B are siblings
%
siblings(A,B) :-
    parent(X, A),       % A & B share a common parent
    parent(X,B),         %
    A \== B.             % A is different from B  (Bratko, p175)



% sibling_list(Child, Siblings)
% Siblings is a list of Child's brothers and sisters
%
sibling_list(Child, Siblings) :-
	findall(Sibling, siblings(Child, Sibling), List),
	remove_duplicates(List, Siblings).
	

% remove_duplicates(List, Result)
%
% Removes duplicate entries in a list
%
remove_duplicates([], []).

remove_duplicates([X|Rest], Result) :-
	member(X, Rest), !,
	remove_duplicates(Rest, Result).
	
remove_duplicates([X|Rest], [X|Result]) :-
	% X is not a member of Rest as
	% the above clause has a cut in it.
	remove_duplicates(Rest, Result).

	

% olderBrother(A,B)
% means A is an older brother of B
%
olderBrother(A,B) :- siblings(A, B), male(A), older(A, B).


% descendant(Person, Descendant)
% means Descendant is a descendant of Person.
%
descendant(Person, Descendant) :-
        parent(Person, Descendant).
descendant(Person, Descendant) :-
        parent(Person, Child),
        descendant(Child, Descendant).


% ancestor(Person, Ancestor)
% means Ancestor is an ancestor of Person.
%
% This is functionally equivalent to descendant(Ancestor, Person).
%
ancestor(Person, Ancestor) :-
        parent(Ancestor, Person).
ancestor(Person, Ancestor) :-
        parent(Parent, Person),
        ancestor(Parent, Ancestor).


% children(Parent, ChildList)
% ChildList is bound to a list of the children of Parent.
%
children(Parent, ChildList) :-
    findall(Child, parent(Parent,Child), ChildList).


% listCount(List, Count)
% Count is bound to the number of elements in List.
%
listCount([], 0).
listCount([_|Tail], Count) :-
    listCount(Tail, TailCount),
    Count is TailCount + 1.


% countDescendants(Person, Count)
% Count is bound to the number of descentants of Person.
%
countDescendants(Person, Count) :-
    findall(Decendant, descendant(Person,Decendant), List),
    listCount(List, Count).