As an assignment for a class, I have made a small Harry Potter family tree in Prolog. It compiles into a self-contained executable that can be run straight from the command line on Linux machines. This is my second ever program in Prolog, so I am still learning. My background is in imperative languages, so I am probably doing things and formatting my code in a not very "Prolog-ish" manner.
Main
:- [pft].
print_query_true(Q) :-
forall(Q, writeln(true:Q)).
print_query_false(Q) :-
forall(\+ Q, (writeln(false:Q), nl)).
get_input :-
writeln('Enter "1." to run a query or "9." to exit:'),
read(I),
(
I = 1 -> run_query;
I = 9 -> writeln('Goodbye'), halt;
writeln('Invalid input!')
).
run_query :-
writeln('Enter your query, followed by a period (.):'),
read(I),
nl,
print_query_true(I),
print_query_false(I),
nl.
main :- repeat, get_input, fail.
PFT
%male(X)
male(fleamont).
male(james).
male(harry).
male(albus).
male(james_ii).
male(arthur).
male(bill).
male(charlie).
male(percy).
male(george).
male(fred).
male(ron).
male(hugo).
male(mr_granger).
%female(X)
female(euphemia).
female(lily).
female(ginny).
female(lily_ii).
female(molly).
female(mrs_granger).
female(hermione).
female(rose).
%parent(Parent, Child)
parent(fleamont, james).
parent(euphemia, james).
parent(james, harry).
parent(lily, harry).
parent(harry, albus).
parent(harry, james_ii).
parent(harry, lily_ii).
parent(ginny, albus).
parent(ginny, james_ii).
parent(ginny, lily_ii).
parent(arthur, bill).
parent(arthur, charlie).
parent(arthur, percy).
parent(arthur, fred).
parent(arthur, george).
parent(arthur, ron).
parent(arthur, ginny).
parent(molly, bill).
parent(molly, charlie).
parent(molly, percy).
parent(molly, fred).
parent(molly, george).
parent(molly, ron).
parent(molly, ginny).
parent(ron, rose).
parent(ron, hugo).
parent(hermione, rose).
parent(hermione, hugo).
parent(mr_granger, hermione).
parent(mrs_granger, hermione).
%married(Husband, Wife)
married(fleamont, euphemia).
married(james, lily).
married(harry, ginny).
married(arthur, molly).
married(ron, hermione).
married(mr_granger, mrs_granger).
%spouse(X, Y)
spouse(X,Y) :- married(X, Y); married(Y, X).
%father(Father, Child)
father(F, C) :- parent(F, C), male(F).
%mother(Mother, Child)
mother(M, C) :- parent(M, C), female(M).
%brother(Brother, Person In Question)
brother(B, PIQ) :- male(B), sibling(B, PIQ).
%sister(Sister, Person In Question)
sister(S, PIQ) :- female(S), sibling(S, PIQ).
%child(Child, Parent)
child(C, P) :- parent(P, C).
%son(Son, Parent)
son(S, P) :- child(S, P), male(S).
%daughter(Daughter, Parent)
daughter(D, P) :- child(D, P), female(D).
%grandchild(Grandchild, Grandparent)
grandchild(GC, GP) :- child(GC, P), child(P, GP).
%grandson(Grandson, Grandparent)
grandson(GS, GP) :- grandchild(GS, GP), male(GS).
%granddaughter(Granddaughter, Grandparent)
granddaughter(GD, GP) :- grandchild(GD, GP), female(GD).
%sibling(X, Y)
sibling(X, Y) :- parent(P, X), parent(P, Y), X \= Y.
%grandparent(Grandparent, Grandchild)
grandparent(GP, GC) :- grandchild(GC, GP).
%grandfather(Grandfather, Grandchild)
grandfather(GF, GC) :- male(GF), grandparent(GF, GC).
%grandmother(Grandmother, Grandchild)
grandmother(GM, GC) :- female(GM), grandparent(GM, GC).
%brother_in_law(Spouses Brother, Person In Question)
brother-in-law(SB, PIQ) :- brother(SB, Spouse), spouse(PIQ, Spouse).
%sister_in_law(Spouses Sister, Person In Question)
sister-in-law(SS, PIQ) :- sister(SS, Spouse), spouse(PIQ, Spouse).
%aunt(Aunt, Person In Question)
aunt(A, PIQ) :- sister(A, P), parent(P, PIQ).
%uncle(Uncle, Person In Question)
uncle(U, PIQ) :- brother(U, P), parent(P, PIQ).
%niece(Niece, Person In Question)
niece(N, PIQ) :- daughter(N, P), sibling(P, PIQ).
%nephew(Nephew, Person In Question)
nephew(N, PIQ) :- son(N, P), sibling(P, PIQ).
%descendant(Descendant, Ancestor)
descendant(D, A) :- parent(A, D).
descendant(D, A) :- parent(P, D), descendant(P, A).
%ancestor(Ancestor, Descendant)
ancestor(A, D) :- descendant(D, A).
%closest_common_ancestor(Person1, Person2, Closest Common Ancestor)
closest_common_ancestor(P1, P2, CCA) :-
ancestor(CCA, P1),
ancestor(CCA, P2),
forall(child(C, CCA), (not(ancestor(C, P1)), not(ancestor(C, P2)))),
P1 \= P2.
%write_descendant_chain(Descendant, Ancestor)
write_descendant_chain(D, A) :-
(
child(D, A) -> write_child(D, A);
child(D, P),
descendant(P, A),
write_child(D, P),
write_descendant_chain(P, A)
).
%write_child(Child, Parent).
write_child(C, P) :-
child(C, P),
write(C),
write(' is a child of '),
write(P),
nl.