-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathFamilyTree
182 lines (157 loc) · 5.62 KB
/
FamilyTree
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
class Member(object):
def __init__(self, founder):
"""
founder: string
Initializes a member.
Name is the string of name of this node,
parent is None, and no children
"""
self.name = founder
self.parent = None
self.children = []
def __str__(self):
return self.name
def add_parent(self, mother):
"""
mother: Member
Sets the parent of this node to the `mother` Member node
"""
self.parent = mother
def get_parent(self):
"""
Returns the parent Member node of this Member
"""
return self.parent
def is_parent(self, mother):
"""
mother: Member
Returns: Boolean, whether or not `mother` is the
parent of this Member
"""
return self.parent == mother
def add_child(self, child):
"""
child: Member
Adds another child Member node to this Member
"""
self.children.append(child)
def is_child(self, child):
"""
child: Member
Returns: Boolean, whether or not `child` is a
child of this Member
"""
return child in self.children
class Family(object):
def __init__(self, founder):
"""
Initialize with string of name of oldest ancestor
Keyword arguments:
founder -- string of name of oldest ancestor
"""
self.names_to_nodes = {}
self.root = Member(founder)
self.names_to_nodes[founder] = self.root
def set_children(self, mother, list_of_children):
"""
Set all children of the mother.
Keyword arguments:
mother -- mother's name as a string
list_of_children -- children names as strings
"""
# convert name to Member node (should check for validity)
mom_node = self.names_to_nodes[mother]
# add each child
for c in list_of_children:
# create Member node for a child
c_member = Member(c)
# remember its name to node mapping
self.names_to_nodes[c] = c_member
# set child's parent
c_member.add_parent(mom_node)
# set the parent's child
mom_node.add_child(c_member)
def is_parent(self, mother, kid):
"""
Returns True or False whether mother is parent of kid.
Keyword arguments:
mother -- string of mother's name
kid -- string of kid's name
"""
mom_node = self.names_to_nodes[mother]
child_node = self.names_to_nodes[kid]
return child_node.is_parent(mom_node)
def is_child(self, kid, mother):
"""
Returns True or False whether kid is child of mother.
Keyword arguments:
kid -- string of kid's name
mother -- string of mother's name
"""
mom_node = self.names_to_nodes[mother]
child_node = self.names_to_nodes[kid]
return mom_node.is_child(child_node)
def cousin(self, a, b):
"""
Returns a tuple of (the cousin type, degree removed)
Keyword arguments:
a -- string that is the name of node a
b -- string that is the name of node b
cousin type:
-1 if a and b are the same node.
-1 if either one is a direct descendant of the other
>=0 otherwise, it calculates the distance from
each node to the common ancestor. Then cousin type is
set to the smaller of the two distances, as described
in the exercises above
degrees removed:
>= 0
The absolute value of the difference between the
distance from each node to their common ancestor.
"""
child_node1 = self.names_to_nodes[a]
child_node2 = self.names_to_nodes[b]
"""check if two nodes are same"""
if a == b:
t = -1
r = 0
elif child_node1.get_parent() == child_node2.get_parent():
"""check if have same parents"""
t = 0
r = 0
elif self.is_parent(a,b) or self.is_child(a,b):
"""check for immediate parent"""
t = -1
r = 1
else:
"""add all elements till root in list"""
root1 = []
root1.append(child_node1.name)
parent_node = child_node1
while parent_node != self.root:
root1.append(parent_node.get_parent().name)
parent_node = parent_node.get_parent()
"""add all elements till root in list"""
root2 = []
root2.append(child_node2.name)
parent_node = child_node2
while parent_node != self.root:
root2.append(parent_node.get_parent().name)
parent_node = parent_node.get_parent()
rootNode = ""
check = False
for i in root1:
for j in root2:
if i == j:
rootNode = i
check = True
break
if check == True:
break
"""check if one of node is rootNode then its parent of other node"""
if a == rootNode or b == rootNode:
t = -1
else:
t = min(root1.index(rootNode)-1,root2.index(rootNode)-1)
r = abs(root1.index(rootNode) - root2.index(rootNode))
return t, r