Commit 62e7d090 authored by Temujin's avatar Temujin

finished relationship method

parent 9541f220
"""Family Tree project for CSCI 30.""" """Family Tree project for CSCI 30."""
""" """
TODO:
Find a way to get isolated nodes.
Problems to consider -- Problems to consider --
What to do if not rooted?
Multiple roots?
What if the file describes two separate trees at once?
Handling value errors. Handling value errors.
Incest and cycles:
> Adding someone already in the tree as a child
Problems taken care of(?) --
Adding child to someone who already has two children.
Questions: Questions:
Is there only one root?
Total nodes of the tree? Total nodes of the tree?
11 generations = 2^11 - 1 11 generations = 2^11 - 1
...@@ -30,8 +17,6 @@ Tree setup procedure: ...@@ -30,8 +17,6 @@ Tree setup procedure:
4 Set the generations 4 Set the generations
5 run precompute method 5 run precompute method
6 done 6 done
""" """
...@@ -47,6 +32,12 @@ class FamilyTree: ...@@ -47,6 +32,12 @@ class FamilyTree:
value = a Person object, acting as the node value = a Person object, acting as the node
""" """
ordinal = ["first", "second", "third", "fourth", "fifth",
"sixth", "seventh", "eighth", "ninth", "tenth"]
times = ["once", "twice", "thrice", "four times", "five times",
"six times", "seven times", "eight times", "nine times",
"ten times"]
def __init__(self): def __init__(self):
"""Initialize the family tree.""" """Initialize the family tree."""
self.family_tree = dict() self.family_tree = dict()
...@@ -106,9 +97,9 @@ class FamilyTree: ...@@ -106,9 +97,9 @@ class FamilyTree:
return descendants return descendants
def precompute(self): def precompute(self):
"""Do the precomputations required to find LCA and degree. """Do the precomputations necessary to find LCA and degree.
DFS from root. DFS from root. (todo)
Along the way, set the generations (levels) Along the way, set the generations (levels)
and fill up the arrays for the lca query (TODO) and fill up the arrays for the lca query (TODO)
...@@ -137,6 +128,8 @@ class FamilyTree: ...@@ -137,6 +128,8 @@ class FamilyTree:
S = name of person in starting node. S = name of person in starting node.
*funcs = the operations to be done on the node *funcs = the operations to be done on the node
#TODO FIX THIS
""" """
visited = [] visited = []
current_node = self.family_tree[s] current_node = self.family_tree[s]
...@@ -154,7 +147,7 @@ class FamilyTree: ...@@ -154,7 +147,7 @@ class FamilyTree:
visited.append(rc.get_name()) visited.append(rc.get_name())
self.dfs(rc.get_name(), *funcs) self.dfs(rc.get_name(), *funcs)
def lca(self, name1, name2): def find_lca(self, name1, name2):
"""Find the lowest common ancestor of two nodes. """Find the lowest common ancestor of two nodes.
TODO: when one is the ancestor of the other TODO: when one is the ancestor of the other
...@@ -183,7 +176,7 @@ class FamilyTree: ...@@ -183,7 +176,7 @@ class FamilyTree:
p1 = p1.get_parent() p1 = p1.get_parent()
p2 = p2.get_parent() p2 = p2.get_parent()
return p1.get_name() return p1
def fast_lca(self, a, b): def fast_lca(self, a, b):
"""Find the lca fast. """Find the lca fast.
...@@ -192,10 +185,12 @@ class FamilyTree: ...@@ -192,10 +185,12 @@ class FamilyTree:
""" """
return return
def degree(self, p1, p2): def get_degree(self, p1, p2, lca):
"""Find the degree between two cousins.""" """Find the degree between two people."""
l_ancestor = self.lca(p1, p2) distance_p1 = lca.get_generation() - p1.get_generation()
return min([self.lca(p1, l_ancestor), self.lca(p2, l_ancestor)]) distance_p2 = lca.get_generation() - p2.get_generation()
deg = min[distance_p1 - 1, distance_p2 - 1]
return deg
def relationship(self, p1, p2): def relationship(self, p1, p2):
"""Determine the relationship between two distinct people in the tree. """Determine the relationship between two distinct people in the tree.
...@@ -203,8 +198,79 @@ class FamilyTree: ...@@ -203,8 +198,79 @@ class FamilyTree:
Input: Two people p1 and p2, where p1 != p2 Input: Two people p1 and p2, where p1 != p2
Output: The relationship between p1 and p2, from the perspective of p1 Output: The relationship between p1 and p2, from the perspective of p1
""" """
lca = self.find_lca(p1.get_name(), p2.get_name())
d1 = p1.get_generation() - lca.get_generation()
d2 = p2.get_generation() - lca.get_generation()
nearest = min([d1, d2])
furthest = max([d1, d2])
if nearest >= 2:
degree = nearest - 1
removal = abs(d1-d2)
if removal == 0:
return self.ORDINAL(degree) + "cousin"
else:
return self.ORDINAL(degree) + "cousin " + self.TIMES(removal) + "removed"
elif nearest == 1:
if furthest == 1:
if p2.sex is True:
return "brother"
else:
return "sister"
elif furthest == 2:
return self.TERM("nibling", d1, d2, p2.sex)
else:
return self.GREAT(furthest) + "grand" + self.TERM("nibling", d1, d2, p2.sex)
elif nearest == 0:
## TODO: PARENT RELATIONSHIP
if furthest == 1:
return self.TERM("child", d1, d2, p2.sex)
else:
return self.GREAT(furthest) + "grand" + self.TERM("child", d1, d2, p2.sex)
pass pass
def ORDINAL(self, n):
"""Return the index in the ordinal table."""
return self.ordinal[n]
def TIMES(self, n):
"""Return the index in the times table."""
return self.times[n]
def great(self, n):
"""Return a string of n 'greats' separated by - ."""
return "-".join(["great"]*n)
def TERM(self, kind, d1, d2, sex):
"""Return the term."""
assert (d1 != d2)
if kind == "child":
if d1 < d2:
if sex is True:
return "son"
else:
return "daughter"
else:
if sex is True:
return "father"
else:
return "mother"
elif kind == "nibling":
if d1 < d2:
if sex is True:
return "nephew"
else:
return "niece"
else:
if sex is True:
return "uncle"
else:
return "aunt"
class Person: class Person:
"""The nodes of the family tree. """The nodes of the family tree.
...@@ -325,8 +391,12 @@ def main(): ...@@ -325,8 +391,12 @@ def main():
ftree.precompute() ftree.precompute()
for key, node in ftree.family_tree.items(): for key, node in ftree.family_tree.items():
print("{}: {}".format(node, node.get_generation())) print("{}: {}".format(node, node.get_generation()))
print("The lca of {} and {} is {}".format(D, C, ftree.lca("D", "C"))) print("The lca of {} and {} is {}".format(D, C, ftree.find_lca("D", "C")))
print("The lca of {} and {} is {}".format(B, D, ftree.lca("B", "D"))) print("The lca of {} and {} is {}".format(B, D, ftree.find_lca("B", "D")))
print("The lca of {} and {} is {}".format(A, B, ftree.find_lca("A", "B")))
print("relationship (A, B): {}".format(ftree.relationship(A, B)))
print("relationship (B, C): {}".format(ftree.relationship(B, C)))
if __name__ == "__main__": if __name__ == "__main__":
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment