-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patharithmetic_arranger.py
142 lines (106 loc) · 5.15 KB
/
arithmetic_arranger.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
134
135
136
137
138
139
140
141
142
import re
import sys
supported_operators: str = "+-"
max_number_of_problems: int = 5
max_digits_per_operand: int = 4
number_of_operands_per_problem: int = 2
# Suppose we only have flat problem with no parenthesis and only +, or -, the total number of elements (operands
# and operator) is as below:
number_of_operands_and_operators: int = (number_of_operands_per_problem * 2) - 1
def get_operands_and_operator(problem: str) -> list[str]:
# global number_of_operands_and_operators
elements = problem.split()
# Checking the total number of operands + operator
if len(elements) != number_of_operands_and_operators:
print("Error: \"", problem, "\" doesn't comply with",
number_of_operands_and_operators, "total number of operands and operator")
quit()
return elements
def process_problems(problems: list[str], with_answers=False) -> str:
"""
Checks if the problems are well formatted.
Returns True if the format is okay.
Returns Error message if an error found.
"""
# Make sure we don't have too many problems supplied.
if len(problems) > max_number_of_problems:
return "Error: Too many problems."
# Make sure only appropriate operators are used.
for problem in problems:
elements = get_operands_and_operator(problem)
# If we reached here then we are sure we don't have any problem with the number of element in the problems.
# We extract first_operand, operator, and second_operand.
first_operand, operator, second_operand = [elements[e] for e in range(number_of_operands_and_operators)]
# Checking the operator and making sure it's supported.
if len(operator) != 1 or operator not in supported_operators:
return "Error: Operator must be '+' or '-'."
# Extra check: make sure actually have only digits in the operands
pattern = "[0-9]+"
if re.fullmatch(pattern, first_operand) is None or re.fullmatch(pattern, second_operand) is None:
return "Error: Numbers must only contain digits."
# Making sure each operand has a max of four digits in width
if len(first_operand) > max_digits_per_operand or len(second_operand) > max_digits_per_operand:
return "Error: Numbers cannot be more than four digits."
return arrange(problems, with_answers)
def arrange(problems: list[str], with_answers=False) -> str:
"""
Sample arrangement with answers:
32 1 9999 523
+ 8 - 3801 + 9999 - 49
---- ------ ------ -----
40 -3800 19998 474
Sample arrangement WITHOUT answers:
32 3801 45 123
+ 698 - 2 + 43 + 49
----- ------ ---- -----
"""
underline_character = "-"
arrangement = ""
line_1 = "" # For first operands
line_2 = "" # For operators
line_3 = "" # For second operands
line_4 = "" # For answers (optional)
block_seperator = " "
iteration = 0
for problem in problems:
elements = get_operands_and_operator(problem)
# Add separators if iteration > 0, meaning we previously added some element,
# so we add a separator before adding new elements.
if 0 < iteration < len(problems):
line_1 += block_seperator
line_2 += block_seperator
line_3 += block_seperator
if len(line_4) > 0: # Only process line_4 (answers) if data had been added previously.
line_4 += block_seperator
first_operand, operator, second_operand = [elements[e] for e in range(number_of_operands_and_operators)]
# Determine the width of the problem arrangement which is
# the maximum length of the operands + 2 (the space and the operator)
width = max(len(first_operand), len(second_operand)) + 2
# We start the justification to the right.
formatted_first_line = str.rjust(first_operand, width)
formatted_second_line = str.rjust(second_operand, width - 1) # Minus 1 to create place for the operator
formatted_second_line = operator + formatted_second_line
formatted_third_line = str.rjust("", width, underline_character)
# Prepare the arrangement line per line
line_1 += formatted_first_line
line_2 += formatted_second_line
line_3 += formatted_third_line
# Optionally add the answer
if with_answers:
formatted_fourth_line = str.rjust(str(eval(problem)), width)
line_4 += formatted_fourth_line
iteration += 1
# Add the whole arrangement line by line.
arrangement = line_1 + "\n" + line_2 + "\n" + line_3
if with_answers:
arrangement += "\n" + line_4
return arrangement
def display_arrangement(problems: list[str], with_answers=False) -> None:
arrangement = arrange(problems, with_answers)
for line in arrangement:
for element in line:
sys.stdout.write(element)
print()
def arithmetic_arranger(problems: list[str], with_answers=False) -> str:
# First check the format and exit if syntax is incorrect.
return process_problems(problems, with_answers)