Skip to content

Commit 370d983

Browse files
[Sync Iteration] python/wordy/10
1 parent d4ff482 commit 370d983

1 file changed

Lines changed: 103 additions & 0 deletions

File tree

solutions/python/wordy/10/wordy.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
"""
2+
Parse and evaluate simple math word problems
3+
returning the answer as an integer.
4+
5+
Handle a set of operations, in sequence.
6+
7+
Since these are verbal word problems, evaluate
8+
the expression from left-to-right, ignoring the
9+
typical order of operations.
10+
"""
11+
12+
OPERATORS: tuple = ("plus", "minus", "multiplied", "divided")
13+
REPLACEABLE: tuple = ("What", "is", "by")
14+
15+
16+
def answer(question: str) -> int:
17+
"""
18+
Evaluate a simple word-based arithmetic question from left to right.
19+
20+
:param question: The input question, e.g., "What is 5 plus 13?"
21+
:type question: str
22+
:returns: The evaluated integer result.
23+
:rtype: int
24+
:raises ValueError: If the operation is unknown or the syntax is invalid.
25+
"""
26+
new_question: list[str] = [
27+
word
28+
for word in question.replace("?", "").split()
29+
if word not in REPLACEABLE
30+
]
31+
# Reduce iteratively:
32+
# evaluate the first two-token slice and fold the result left-to-right.
33+
try:
34+
result, new_question = int(new_question[0]), new_question[1:]
35+
while new_question:
36+
_err_check(new_question)
37+
result, new_question = (
38+
_math_operation(result, new_question),
39+
new_question[2:],
40+
)
41+
except ValueError as exc:
42+
if exc.args[0] == "unknown operation":
43+
raise exc
44+
raise ValueError("syntax error") from exc
45+
except IndexError as exc:
46+
raise ValueError("syntax error") from exc
47+
48+
return result
49+
50+
51+
def _math_operation(result: int, question: list[str]) -> int:
52+
"""
53+
Compute a single binary arithmetic step for the current operator.
54+
55+
Expects the next tokens of the question to begin with the operator word
56+
(e.g. ``plus``, ``minus``, ``multiplied``, ``divided``) followed by the
57+
right-hand side operand. Division uses floor division (``//``) to comply
58+
with the exercise rules.
59+
60+
:param result: Accumulated left-hand value computed so far.
61+
:type result: int
62+
:param question: Remaining tokens starting with the operator then rhs
63+
integer, e.g. ``['plus', '4', ...]``.
64+
:type question: list[str]
65+
:returns: Accumulated result after consuming the operator and rhs.
66+
:rtype: int
67+
"""
68+
math_operator: str = question[0]
69+
operand: int = int(question[1])
70+
71+
match math_operator:
72+
case "plus":
73+
result += operand
74+
case "minus":
75+
result -= operand
76+
case "divided":
77+
result //= operand
78+
case "multiplied":
79+
result *= operand
80+
81+
return result
82+
83+
84+
def _err_check(question: list[str]) -> None:
85+
"""
86+
Validate the upcoming operator/operand tokens and raise appropriate errors.
87+
88+
:param question: Remaining tokens starting at the operator; used to detect
89+
malformed sequences (e.g., missing rhs integer).
90+
:type question: list[str]
91+
:raises ValueError: If an unknown operation is encountered or the token
92+
sequence is syntactically invalid.
93+
"""
94+
math_operator: str = question[0]
95+
# if the question contains an unknown operation.
96+
if math_operator not in OPERATORS and not math_operator.isdigit():
97+
raise ValueError("unknown operation")
98+
# if the question is malformed or invalid.
99+
if math_operator.isdigit():
100+
raise ValueError("syntax error")
101+
# if the question is malformed or invalid.
102+
if math_operator in OPERATORS and len(question) == 1:
103+
raise ValueError("syntax error")

0 commit comments

Comments
 (0)