CMU Coding Bootcamp
1from typing import List
2
3
4def getMostImportantOpIndex(parts: List[str]) -> int:
5 """Returns the index of the most important operator in the given list of parts."""
6 index = len(parts) + 1
7 higher_order_operator = 0
8
9 if "^" in parts:
10 higher_order_operator = 2
11 index = parts.index("^")
12 if "*" in parts and higher_order_operator < 2 and parts.index("*") < index:
13 higher_order_operator = 1
14 index = parts.index("*")
15 if "/" in parts and higher_order_operator < 2 and parts.index("/") < index:
16 higher_order_operator = 1
17 index = parts.index("/")
18 if "%" in parts and higher_order_operator < 2 and parts.index("%") < index:
19 higher_order_operator = 1
20 index = parts.index("%")
21 if "+" in parts and higher_order_operator < 1 and parts.index("+") < index:
22 index = parts.index("+")
23 if "-" in parts and higher_order_operator < 1 and parts.index("-") < index:
24 index = parts.index("-")
25 return index
26
27
28def runStep(a: str, sign: str, b: str) -> str:
29 """Runs a single step of the evaluation process."""
30 if sign == "+":
31 return str(int(a) + int(b))
32 elif sign == "-":
33 return str(int(a) - int(b))
34 elif sign == "*":
35 return str(int(a) * int(b))
36 elif sign == "/":
37 return str(int(a) // int(b))
38 elif sign == "%":
39 return str(int(a) % int(b))
40 elif sign == "^":
41 return str(int(a) ** int(b))
42 else:
43 raise ValueError("Invalid operator")
44
45
46def getEvalSteps(expr: str) -> str:
47 """Returns a string containing the evaluation steps of the given expression."""
48 padding = " " * (len(expr) + 1) + "= "
49
50 expr = expr.strip()
51 expr = expr.replace(" ", "")
52 expr = expr.replace("**", "^")
53 expr = expr.replace("//", "/")
54 steps = [expr]
55
56 expr_parts = []
57 cur_piece = ""
58 for c in expr:
59 if c.isdigit():
60 cur_piece += c
61 else:
62 expr_parts.append(cur_piece)
63 expr_parts.append(c)
64 cur_piece = ""
65 expr_parts.append(cur_piece)
66 while len(expr_parts) > 1:
67 next_op = getMostImportantOpIndex(expr_parts)
68 left = expr_parts.pop(next_op - 1)
69 op = expr_parts.pop(next_op - 1)
70 right = expr_parts.pop(next_op - 1)
71 val = runStep(left, op, right)
72 expr_parts.insert(next_op - 1, val)
73 steps.append("".join(expr_parts))
74 steps[0] = steps[0] + " = " + steps.pop(1)
75 steps = [step.replace("^", "**") for step in steps]
76 steps = [step.replace("/", "//") for step in steps]
77 steps = [padding + step if not i == 0 else step for i, step in enumerate(steps)]
78 final = "\n".join(steps) + "\n"
79 return final
80
81
82def testGetEvalSteps():
83 print("Testing getEvalSteps()...", end="")
84 assert (
85 getEvalSteps("2+3*4-8**3%3")
86 == """\
872+3*4-8**3%3 = 2+3*4-512%3
88 = 2+12-512%3
89 = 2+12-2
90 = 14-2
91 = 12
92"""
93 )
94 assert (
95 getEvalSteps("2**2**3+4-2//3")
96 == """\
972**2**3+4-2//3 = 4**3+4-2//3
98 = 64+4-2//3
99 = 64+4-0
100 = 68-0
101 = 68
102"""
103 )
104 assert (
105 getEvalSteps("4//2**2*8-3+2")
106 == """\
1074//2**2*8-3+2 = 4//4*8-3+2
108 = 1*8-3+2
109 = 8-3+2
110 = 5+2
111 = 7
112"""
113 )
114 assert (
115 getEvalSteps("2**4//2-3+1")
116 == """\
1172**4//2-3+1 = 16//2-3+1
118 = 8-3+1
119 = 5+1
120 = 6
121"""
122 )
123 print("Passed!")
124
125
126testGetEvalSteps()