%sisters
sister(abigail).
sister(brenda).
sister(mary).
sister(paula).
sister(tara).

%months
month(february).
month(march).
month(june).
month(july).
month(december).

%weekdays
day(sunday).
day(monday).
day(wednesday).
day(friday).
day(saturday).

%concept of dates being before other dates
before(february, march).
before(march, june).
before(june, july).
before(july, december).

before(sunday, monday).
before(monday, wednesday).
before(wednesday, friday).
before(friday, saturday).

before(december, _) :- !, fail.
before(saturday, _) :- !, fail.

%distinctiness
before(Former, Later) :- Former = Later, !, fail.
%transitivity
before(Former, Later) :- before(Former, Middle), before(Middle, Later).


solve :-
    BDays = [bday(abigail, AbMonth, AbDay), bday(brenda, BrMonth, BrDay),
              bday(mary, MaMonth, MaDay), bday(paula, PaMonth, PaDay),
              bday(tara, TaMonth, TaDay)],
    
    %type restrictions
    month(AbMonth), month(BrMonth), month(MaMonth), month(PaMonth), month(TaMonth),
    all_different([AbMonth, BrMonth, MaMonth, PaMonth, TaMonth]),
    
    day(AbDay), day(BrDay), day(MaDay), day(PaDay), day(TaDay),  
    all_different([AbDay, BrDay, MaDay, PaDay, TaDay]),
    
    %rule 1: paula was born in march but not on a saturday
    %abigail's birthday was not on friday or wednesday
    member(bday(paula, march, _), BDays),
    \+member(bday(paula, _, saturday), BDays),
    \+member(bday(abigail, _, friday), BDays), 
    \+member(bday(abigail, _, wednesday), BDays),
    
    %rule 2: the girl whose birthday is on monday was born earlier in the year
    	%than Brenda and Mary
    %massive OR incoming
    \+member(bday(brenda, _, monday), BDays),
    (   (member(bday(abigail, _, monday),BDays), before(AbMonth, BrMonth), before(AbMonth, MaMonth));
    	(member(bday(paula, _, monday),BDays), before(PaMonth, BrMonth), before(PaMonth, MaMonth));
    	(member(bday(tara, _, monday),BDays), before(TaMonth, BrMonth), before(TaMonth, MaMonth))),
    
    
    %mary's covered by her bday being a weekend
    
    %rule 3: tara wasn't born in february and her birthday was on the weekend
    \+member(bday(tara, february,_), BDays),
    (   member(bday(tara, _, saturday), BDays);
    	member(bday(tara, _, sunday), BDays) ),
    
    %rule 4: mary was not born in december nor was her birthday on a weekday.
    	%the girl whose birthday was in june was born on sunday
    \+member(bday(mary, december, _), BDays),
    (   member(bday(mary, _, saturday), BDays);
    	member(bday(mary, _, sunday), BDays) ),
    member(bday(_, june, sunday), BDays),
    
    %rule 5: tara was born before brenda, whose birthday wasn't on friday.
    	%mary wasn't born in july.
    before(TaMonth, BrMonth),
    \+member(bday(brenda, _, friday), BDays),
    \+member(bday(mary, july, _), BDays),
    
    %communication
    tell(abigail, AbMonth, AbDay), 
    tell(brenda, BrMonth, BrDay),
    tell(mary, MaMonth, MaDay), 
    tell(paula, PaMonth, PaDay),
    tell(tara, TaMonth, TaDay).


tell(Sister, Month, Day) :- write(Sister), write(' was born on a '), 
    write(Day), write(' in '), write(Month), 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([_]).