All checks were successful
Deploy to birb co. production / deploy (push) Successful in 10s
74 lines
2.4 KiB
Python
74 lines
2.4 KiB
Python
# Make a calculator using Reverse Polish Notation. Use recursion.
|
|
# The Reverse Polish syntax completely removes the need for parentheses.
|
|
#
|
|
# Syntax examples:
|
|
# "3 + 2" -> ["3", "2", "+"]
|
|
# "3 * 4 + 2" -> ["3", "4", "*", "2", "+"]
|
|
# "3 * (4 + 2)" -> ["3", "4", "2", "+", "*"]
|
|
#
|
|
# Example for how to evaluate ["3", "4", "2", "+", "*"]:
|
|
# Start with "4 2 +" -> "6"
|
|
# Then "3 6 *" -> "18"
|
|
# Start with the "innermost" expression and work backwards (this is the recursion part)
|
|
#
|
|
# For help, email me@bchen.dev
|
|
|
|
# Sample solution below
|
|
|
|
# Facts:
|
|
# The last element of the list must always be an operator; otherwise there is only one element
|
|
|
|
def rpn(expression: list[str]) -> int:
|
|
operators = "+-*/"
|
|
|
|
def eval(expression: list[str]) -> tuple[int, int]:
|
|
"""
|
|
Evaluate RPN and return an index value pointing to the first token in the expression.
|
|
"""
|
|
for i in range(len(expression) - 1, -1, -1):
|
|
token = expression[i]
|
|
|
|
if token in operators:
|
|
right, right_token_index = eval(expression[:i])
|
|
|
|
# for left, we need the index of the token that comes after right
|
|
left, left_token_index = eval(expression[:right_token_index])
|
|
|
|
if token == "+":
|
|
return left + right, left_token_index
|
|
elif token == "-":
|
|
return left - right, left_token_index
|
|
elif token == "*":
|
|
return left * right, left_token_index
|
|
else:
|
|
return int(left / right), left_token_index
|
|
else:
|
|
# evaluate as a literal
|
|
literal = int(token)
|
|
return literal, i
|
|
|
|
return (0, 0)
|
|
|
|
return eval(expression)[0]
|
|
|
|
|
|
# The following test cases should pass (please copy this into your code):
|
|
tests = [
|
|
(["3", "2", "+"], 5),
|
|
(["3", "4", "*"], 12),
|
|
(["3", "4", "2", "+", "*"], 18),
|
|
([], 0),
|
|
(["50", "2", "/"], 25),
|
|
(["5", "2", "/"], 2), # for division, cast to int using int(num)
|
|
(["5", "4", "3", "-", "*"], 5),
|
|
(["5", "4", "6", "2", "10", "+", "*", "-", "-"], 73),
|
|
(["3", "2", "+", "5", "*"], 25)
|
|
]
|
|
for case in tests:
|
|
result = rpn(case[0])
|
|
expected = case[1]
|
|
if result == expected:
|
|
print(f"PASS: expected {expected}, got {result} for {case[0]}")
|
|
else:
|
|
print(f"FAIL: expected {expected}, got {result} for {case[0]}")
|