patternMinor
Harry Potter's Family Tree Database
Viewed 0 times
harrydatabasefamilypottertree
Problem
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
```
%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,
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,
Solution
Your
Below is the version that would work:
Some general advise:
closest_common_ancestor/3 doesn't work, for instance, closest_common_ancestor(rose, fred, X). fails to find answers, however X=arthur and X=molly are both answers.Below is the version that would work:
closest_common_ancestor(P1, P2, CCA) :-
parent(CCA, P1),
parent(CCA, P2).
closest_common_ancestor(P1, P2, CCA) :-
parent(P, P1),
closest_common_ancestor(P, P2, CCA).
closest_common_ancestor(P1, P2, CCA) :-
parent(P, P2),
closest_common_ancestor(P1, P, CCA).Some general advise:
- There's no reason not to name variables in predicates the way you described them in the documentation. In fact, I'd prefer
Person1toP1, especially in the context whereParent1could be also inferred. Also, there are some documentation tools, usually bundled with whatever version of Prolog you are using, that have certain conventions wrt documentation format. If you wanted to produce documentation that is usable for others in an automatic way, it would help to study those tools. For example, if you are usingswipl, look at http://www.swi-prolog.org/pldoc/doc_for?object=section(%27packages/pldoc.html%27) .
- Try avoiding expressing your assertions through negation. It is an art in and for itself, but once you start following this rule, you'll realize that the code you produce is more straight-forward and less verbose. It takes, however, time and effort to adopt this rule.
- Use
formatinstead ofprint,nland friends. Unless you are writing some utility code whose purpose is printing, there's no reason to clutter the code with string formatting.
Code Snippets
closest_common_ancestor(P1, P2, CCA) :-
parent(CCA, P1),
parent(CCA, P2).
closest_common_ancestor(P1, P2, CCA) :-
parent(P, P1),
closest_common_ancestor(P, P2, CCA).
closest_common_ancestor(P1, P2, CCA) :-
parent(P, P2),
closest_common_ancestor(P1, P, CCA).Context
StackExchange Code Review Q#142539, answer score: 2
Revisions (0)
No revisions yet.