-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.py
133 lines (114 loc) · 3.7 KB
/
main.py
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
import sys
from dataclasses import dataclass
from enum import Enum, auto
from typing import Iterator
from elements import dict_el
class TokenKind(Enum):
ELEM = auto()
NUM = auto()
L_BRACK = auto()
R_BRACK = auto()
@dataclass
class Token:
kind: TokenKind
val: str
def get_generic_tok_type(tok: str) -> TokenKind:
if tok.isnumeric():
return TokenKind.NUM
else:
return TokenKind.ELEM
def lex(string: str) -> list[Token]:
tokens = []
tok = ""
for index, char in enumerate(string):
if char == "(":
if tok:
tokens.append(Token(get_generic_tok_type(tok), tok))
tokens.append(Token(TokenKind.L_BRACK, "("))
tok = ""
elif char == ")":
if tok:
tokens.append(Token(get_generic_tok_type(tok), tok))
tokens.append(Token(TokenKind.R_BRACK, ")"))
tok = ""
elif char.isupper() or (char.isnumeric() and not string[index-1].isnumeric() and index > 0):
if tok:
tokens.append(Token(get_generic_tok_type(tok), tok))
tok = char
elif char.isspace():
if tok:
tokens.append(Token(get_generic_tok_type(tok), tok))
tok = ""
else:
tok += char
if tok:
tokens.append(Token(get_generic_tok_type(tok), tok))
return tokens
def add_elem(elems: list[tuple[int, str]], elem: tuple[int, str]):
elem_index = None
for index, e in enumerate(elems):
if e[1] == elem[1]:
elem_index = index
if elem_index is not None:
elems[elem_index] = (elem[0] + elems[elem_index][0], elem[1])
else:
elems.append(elem)
def parse(tokens: Iterator[Token], nested: bool = False) -> list[tuple[int, str]]:
elems: list[tuple[int, str]] = []
elem = None
elem_bracks = None
for tok in tokens:
if tok.kind == TokenKind.ELEM:
if elem:
add_elem(elems, (1, elem))
elem = tok.val
elif tok.kind == TokenKind.NUM:
if elem:
add_elem(elems, (int(tok.val), elem))
elem = None
elif elem_bracks:
for e in elem_bracks:
add_elem(elems, (e[0]*int(tok.val), e[1]))
elem_bracks = None
else:
print("Invalid position of an index")
exit(1)
elif tok.kind == TokenKind.L_BRACK:
elem_bracks = parse(tokens, nested=True)
elif tok.kind == TokenKind.R_BRACK:
if not nested:
print("Bracket wasn't matched")
exit(1)
break
else:
if nested:
print("Bracket was not closed")
exit(1)
if elem is not None:
add_elem(elems, (1, elem))
if elem_bracks is not None:
for e in elem_bracks:
add_elem(elems, e)
return elems
def get_atom_mass(elem: str) -> int:
if elem in dict_el:
return dict_el[elem]
else:
print(f"Element \"{elem}\" was not found")
exit(1)
def compute_molecular_mass(elems: list[tuple[int, str]]) -> int:
return sum(map(
lambda elem: get_atom_mass(elem[1]) * elem[0],
elems
))
def get_verbose_output(elems: list[tuple[int, str]]) -> str:
return " + ".join([f"{elem[0]} * {get_atom_mass(elem[1])}" for elem in elems]) +\
f" = {compute_molecular_mass(elems)}"
def get_output(elems: list[tuple[int, str]]) -> int | str:
return (get_verbose_output(elems) if "-v" in sys.argv
else compute_molecular_mass(elems))
def main():
while True:
print(get_output(parse(iter(lex(input())))))
if __name__ == "__main__":
main()