5
5
from number_factory import NumberFactory
6
6
7
7
8
+ class ExpressionResolverException (Exception ):
9
+ def __init__ (
10
+ self ,
11
+ message : str = "Expression resolver exception" ,
12
+ expression : Expression | None = None ,
13
+ ):
14
+ super ().__init__ (f"{ message } (expression={ expression } )" )
15
+
16
+
17
+ class ExpressionResolverNotResolvable (ExpressionResolverException ):
18
+ def __init__ (
19
+ self ,
20
+ message : str = "Expression is not resolvable" ,
21
+ expression : Expression | None = None ,
22
+ ):
23
+ super ().__init__ (message , expression = expression )
24
+
25
+
26
+ class ExpressionResolverMaybeNotResolvable (ExpressionResolverException ):
27
+ def __init__ (
28
+ self ,
29
+ message : str = "Expression is maybe not resolvable" ,
30
+ expression : Expression | None = None ,
31
+ ):
32
+ super ().__init__ (message , expression = expression )
33
+
34
+
8
35
class ExpressionResolver :
9
36
def __init__ (self , validator : ExpressionValidator , number_factory : NumberFactory ):
10
37
self ._validator = validator
@@ -22,11 +49,28 @@ def _fix_result(self, expression: Expression):
22
49
expression .operand2 = self ._number_factory .fix (expression .operand2 )
23
50
expression .result = self ._number_factory .fix (expression .result )
24
51
25
- def _resolve_result_is_none (self , expression : Expression ) -> Expression | None :
52
+ def _next_operator (self , expression : Expression ) -> list [Operator ]:
53
+ if expression .operand1 is None or expression .operand2 is None :
54
+ yield random .choice (Operator .get_operators_without_eq ())
55
+ operators = Operator .get_operators_without_eq ()
56
+ random .shuffle (operators )
57
+ for operator in operators :
58
+ yield operator
59
+
60
+ def _resolve_result_is_none (self , expression : Expression ) -> Expression :
61
+ start = time .time ()
62
+ operators = self ._next_operator (expression )
26
63
while True :
27
64
exp_result = expression .clone ()
28
65
if exp_result .operator is None :
29
- exp_result .operator = random .choice (Operator .get_operators_without_eq ())
66
+ try :
67
+ exp_result .operator = next (operators )
68
+ except StopIteration :
69
+ raise ExpressionResolverNotResolvable (expression = expression )
70
+ if exp_result .operator == Operator .DIV and NumberFactory .is_zero (
71
+ exp_result .operand2
72
+ ):
73
+ continue
30
74
if exp_result .operand1 is None :
31
75
exp_result .operand1 = self ._number_factory .next ()
32
76
if exp_result .operand2 is None :
@@ -51,11 +95,14 @@ def _resolve_result_is_none(self, expression: Expression) -> Expression | None:
51
95
self ._check_result (expression , exp_result )
52
96
if not self ._validator .validate (exp_result ):
53
97
# TODO time or count limit
98
+ if time .time () - start > 1.0 :
99
+ raise ExpressionResolverMaybeNotResolvable (expression = expression )
54
100
continue
55
101
self ._fly_back (exp_result )
56
102
return exp_result
57
103
58
- def _resolve_result_is_available (self , expression : Expression ) -> Expression | None :
104
+ def _resolve_result_is_available (self , expression : Expression ) -> Expression :
105
+ start = time .time ()
59
106
while True :
60
107
exp_calc = expression .clone ()
61
108
exp_result = expression .clone ()
@@ -90,6 +137,12 @@ def _resolve_result_is_available(self, expression: Expression) -> Expression | N
90
137
# a * ? = c -> c / a = b
91
138
# ? * b = c -> c / b = a
92
139
exp_calc .operator = Operator .DIV
140
+ if not_has_operands :
141
+ exp_result .operand1 = exp_calc .operand1 = self ._number_factory .next (
142
+ dividable_by = exp_result .result ,
143
+ zero_allowed = False ,
144
+ )
145
+ print (exp_calc )
93
146
elif operator == Operator .DIV :
94
147
# a / b = c
95
148
if not_has_operands :
@@ -109,20 +162,31 @@ def _resolve_result_is_available(self, expression: Expression) -> Expression | N
109
162
else :
110
163
raise RuntimeError (f"Invalid operator: { operator } " )
111
164
if exp_result .operand1 is None :
165
+ if ExpressionResolver .is_zero_division (
166
+ exp_calc .operator , exp_calc .operand2
167
+ ):
168
+ continue
112
169
exp_result .operand1 = self ._number_factory .fix (
113
170
eval (f"{ exp_calc .result } { exp_calc .operator } { exp_calc .operand2 } " )
114
171
)
115
172
elif exp_result .operand2 is None :
173
+ if ExpressionResolver .is_zero_division (
174
+ exp_calc .operator , exp_calc .operand1
175
+ ):
176
+ continue
116
177
exp_result .operand2 = self ._number_factory .fix (
117
178
eval (f"{ exp_calc .result } { exp_calc .operator } { exp_calc .operand1 } " )
118
179
)
119
180
else :
120
- raise ValueError (f"Operator resolver not supported ({ expression } )" )
181
+ raise ExpressionResolverException (
182
+ "Operator resolver mode not supported" , expression = expression
183
+ )
121
184
self ._check_result (expression , exp_result )
122
185
123
- # print("expression:", expression, "exp_result:", exp_result)
124
186
if not self ._validator .validate (exp_result ):
125
187
# TODO time or count limit
188
+ if time .time () - start > 1.0 :
189
+ raise ExpressionResolverMaybeNotResolvable (expression = expression )
126
190
continue
127
191
self ._fly_back (exp_result )
128
192
return exp_result
@@ -152,3 +216,7 @@ def _check_result(self, expression: Expression, result: Expression):
152
216
if expression .operator is not None :
153
217
if expression .operator != result .operator :
154
218
raise RuntimeError (f"Invalid operator: { expression } -> { result } " )
219
+
220
+ @staticmethod
221
+ def is_zero_division (operator : Operator , operand2 : float ) -> bool :
222
+ return operator == Operator .DIV and NumberFactory .is_zero (operand2 )
0 commit comments