Skip to content

Commit d58d31f

Browse files
bite 136
1 parent dd1536a commit d58d31f

File tree

3 files changed

+230
-0
lines changed

3 files changed

+230
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,4 @@
2525
/21/README.md
2626
/238/README.md
2727
/149/README.md
28+
/136/README.md

136/bt.py

+151
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
"""
2+
Write a function which checks the red blood cell compatibility between donor and recipient.
3+
https://en.wikipedia.org/wiki/Blood_type#Red_blood_cell_compatibility
4+
For simplicity, the appearance of 8 basic types of blood is considered.
5+
The input of blood type can be in the form of:
6+
pre defined Bloodtype enum e.g.: Bloodtype.ZERO_NEG
7+
value of the pre-defined Bloodtype 0..7
8+
pre defined text e.g. "0-", "B+", "AB+", ...
9+
If input value is not a required type TypeError is raised.
10+
If input value is not in defined interval ValueError is raised.
11+
Keywords: enum, exception handling, multi type input
12+
"""
13+
14+
from enum import Enum
15+
16+
17+
class Bloodtype(Enum):
18+
ZERO_NEG = 0
19+
ZERO_POS = 1
20+
B_NEG = 2
21+
B_POS = 3
22+
A_NEG = 4
23+
A_POS = 5
24+
AB_NEG = 6
25+
AB_POS = 7
26+
27+
28+
blood_type_text = {
29+
"0-": Bloodtype.ZERO_NEG,
30+
"0+": Bloodtype.ZERO_POS,
31+
"B-": Bloodtype.B_NEG,
32+
"B+": Bloodtype.B_POS,
33+
"A-": Bloodtype.A_NEG,
34+
"A+": Bloodtype.A_POS,
35+
"AB-": Bloodtype.AB_NEG,
36+
"AB+": Bloodtype.AB_POS,
37+
}
38+
39+
# print(Bloodtype.A_NEG.value)
40+
# complete :
41+
42+
# print(type(Bloodtype.AB_POS.value))
43+
44+
45+
def check_bt(donor, recipient):
46+
""" Checks red blood cell compatibility based on 8 blood types
47+
Args:
48+
donor (int | str | Bloodtype): red blood cell type of the donor
49+
recipient (int | str | Bloodtype): red blood cell type of the recipient
50+
Returns:
51+
bool: True for compatability, False otherwise.
52+
"""
53+
54+
if type(donor) is int and type(recipient) is int:
55+
if donor not in [0, 1, 2, 3, 4, 5, 6, 7] or recipient not in [0, 1, 2, 3, 4, 5, 6, 7]:
56+
raise ValueError
57+
elif donor == Bloodtype.ZERO_NEG.value:
58+
return True
59+
elif donor == Bloodtype.ZERO_POS.value and recipient in [Bloodtype.AB_POS.value, Bloodtype.A_POS.value, Bloodtype.B_POS.value, Bloodtype.ZERO_POS.value]:
60+
return True
61+
elif donor == Bloodtype.B_NEG.value and recipient in [Bloodtype.AB_POS.value, Bloodtype.AB_NEG.value, Bloodtype.B_POS.value, Bloodtype.B_NEG.value]:
62+
return True
63+
elif donor == Bloodtype.B_POS.value and recipient in [Bloodtype.AB_POS.value, Bloodtype.B_POS.value]:
64+
return True
65+
elif donor == Bloodtype.A_NEG.value and recipient in [Bloodtype.AB_POS.value, Bloodtype.AB_NEG.value, Bloodtype.A_POS.value, Bloodtype.A_NEG.value]:
66+
return True
67+
elif donor == Bloodtype.A_POS.value and recipient in [Bloodtype.AB_POS.value, Bloodtype.A_POS.value]:
68+
return True
69+
elif donor == Bloodtype.AB_NEG.value and recipient in [Bloodtype.AB_POS.value, Bloodtype.AB_NEG.value]:
70+
return True
71+
elif donor == Bloodtype.AB_POS.value and recipient == Bloodtype.AB_POS.value:
72+
return True
73+
else:
74+
return False
75+
elif type(donor) is str and type(recipient) is str:
76+
if donor not in blood_type_text.keys() or recipient not in blood_type_text.keys():
77+
raise ValueError
78+
elif donor == "0-":
79+
return True
80+
elif donor == "0+" and recipient in ["AB+", "A+", "B+", "0+"]:
81+
return True
82+
elif donor == "B-" and recipient in ["AB+", "AB-", "B+", "B-"]:
83+
return True
84+
elif donor == "B+" and recipient in ["AB+", "B+"]:
85+
return True
86+
elif donor == "A-" and recipient in ["AB+", "AB-", "A+", "A-"]:
87+
return True
88+
elif donor == "A+" and recipient in ["AB+", "A+"]:
89+
return True
90+
elif donor == "AB-" and recipient in ["AB+", "AB-"]:
91+
return True
92+
elif donor == "AB+" and recipient == "AB+":
93+
return True
94+
else:
95+
return False
96+
elif type(donor) is Bloodtype and type(recipient) is Bloodtype:
97+
if donor not in blood_type_text.values() or recipient not in blood_type_text.values():
98+
raise ValueError
99+
elif donor == blood_type_text.get("0-"):
100+
return True
101+
elif donor == blood_type_text.get("0+") and recipient in [blood_type_text.get("AB+"), blood_type_text.get("A+"),
102+
blood_type_text.get("B+"), blood_type_text.get("O+")]:
103+
return True
104+
elif donor == blood_type_text.get("B-") and recipient in [blood_type_text.get("AB+"),
105+
blood_type_text.get("AB-"),
106+
blood_type_text.get("B+"),
107+
blood_type_text.get("B-")]:
108+
return True
109+
elif donor == blood_type_text.get("B+") and recipient in [blood_type_text.get("AB+"),
110+
blood_type_text.get("B+")]:
111+
return True
112+
elif donor == blood_type_text.get("A-") and recipient in [blood_type_text.get("AB+"),
113+
blood_type_text.get("AB-"),
114+
blood_type_text.get("A+"),
115+
blood_type_text.get("A-")]:
116+
return True
117+
elif donor == blood_type_text.get("A+") and recipient in [blood_type_text.get("AB+"),
118+
blood_type_text.get("A+")]:
119+
return True
120+
elif donor == blood_type_text.get("AB-") and recipient in [blood_type_text.get("AB+"),
121+
blood_type_text.get("AB-")]:
122+
return True
123+
elif donor == blood_type_text.get("AB+") and recipient == blood_type_text.get("AB+"):
124+
return True
125+
else:
126+
return False
127+
else:
128+
raise TypeError
129+
130+
# print(check_bt(7, 1))
131+
# hint
132+
133+
134+
def _particular_antigen_comp(donor: int, recipient: int) -> tuple:
135+
"""Returns a particalar antigen compatibility, where each tuple member
136+
marks a compatibility for a particular antigen (A, B, Rh-D).
137+
If tuple member is non-negative there is a compatibility.
138+
For red blood cell compatibility is required that
139+
all tuple members are non-negative (i.e. compatibility for all 3 antigens).
140+
0- bloodtype is represented as 0 ; AB+ is represented as 7; see Bloodtype enum
141+
Examples:
142+
_particular_antigen_comp(0, 7) -> (1, 1, 1) 0- can donate to AB+
143+
_particular_antigen_comp(1, 3) -> (0, 1, 0) 0+ can donate to B+
144+
_particular_antigen_comp(2, 5) -> (1, -1, 1) B+ cannot donate to A+
145+
_particular_antigen_comp(7, 0) -> (-1, -1, -1) AB+ cannot donate to 0-
146+
"""
147+
return (
148+
((recipient // 4) % 2) - ((donor // 4) % 2),
149+
((recipient // 2) % 2) - ((donor // 2) % 2),
150+
(recipient % 2) - (donor % 2),
151+
)

136/test_bt.py

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import pytest
2+
from bt import check_bt, Bloodtype
3+
4+
5+
def test_universal_donor():
6+
donor = Bloodtype.ZERO_NEG
7+
for i in range(8):
8+
recipient = Bloodtype(i)
9+
assert check_bt(donor, recipient)
10+
11+
12+
def test_universal_recipient():
13+
recipient = Bloodtype.AB_POS
14+
for i in range(8):
15+
donor = Bloodtype(i)
16+
assert check_bt(donor, recipient)
17+
18+
19+
def test_AB_POS_can_donate_to_own_group_only_numeric_input():
20+
donor = 7
21+
for i in range(7):
22+
recipient = i
23+
assert check_bt(donor, recipient) is False
24+
25+
26+
def test_ZERO_NEG_can_recieve_from_own_group_only_numeric_input():
27+
recipient = 0
28+
for i in range(1, 8):
29+
donor = i
30+
assert check_bt(donor, recipient) is False
31+
32+
33+
def test_red_blood_cell_compatibility():
34+
assert check_bt(Bloodtype.A_NEG, Bloodtype.A_NEG) # own
35+
assert check_bt(Bloodtype.B_NEG, Bloodtype.B_POS)
36+
assert check_bt(Bloodtype.A_NEG, Bloodtype.AB_NEG)
37+
38+
39+
def test_red_blood_cell_incompatibility():
40+
assert check_bt(Bloodtype.B_POS, Bloodtype.B_NEG) is False
41+
assert check_bt(Bloodtype.A_NEG, Bloodtype.B_NEG) is False
42+
assert check_bt(Bloodtype.AB_NEG, Bloodtype.B_POS) is False
43+
assert check_bt(Bloodtype.B_NEG, Bloodtype.A_POS) is False
44+
45+
46+
def test_red_blood_cell_compatibility_text_input():
47+
assert check_bt("0+", "A+")
48+
assert check_bt("0+", "B+")
49+
assert check_bt("B-", "B+")
50+
assert check_bt("A-", "AB-")
51+
52+
53+
def test_red_blood_cell_incompatibility_text_input():
54+
assert check_bt("0+", "A-") is False
55+
assert check_bt("0+", "B-") is False
56+
assert check_bt("B-", "0-") is False
57+
assert check_bt("AB-", "A+") is False
58+
59+
60+
def test_invalid_value_text_input():
61+
with pytest.raises(ValueError):
62+
check_bt("X-", "Y+")
63+
with pytest.raises(ValueError):
64+
check_bt("0", "A+")
65+
66+
67+
def test_invalid_value_numeric_input():
68+
with pytest.raises(ValueError):
69+
check_bt(8, 1)
70+
with pytest.raises(ValueError):
71+
check_bt(3, -1)
72+
73+
74+
def test_invalid_type():
75+
with pytest.raises(TypeError):
76+
check_bt(1.0, 1)
77+
with pytest.raises(TypeError):
78+
check_bt(3, ["AB", "Rh+"])

0 commit comments

Comments
 (0)