1
1
import random
2
- import time
3
2
4
3
from expression import Expression , ExpressionValidator , Operator
5
4
from number_factory import NumberFactory
5
+ from number_helper import number_is_zero , number_is_equal
6
6
7
7
8
8
class ExpressionResolverException (Exception ):
@@ -40,7 +40,7 @@ class ExpressionResolver:
40
40
def __init__ (self , validator : ExpressionValidator , number_factory : NumberFactory ):
41
41
self ._validator = validator
42
42
self ._number_factory = number_factory
43
- self ._maximum_resolve_time_sec = 0.1
43
+ self ._resolve_maximum_loop_count = 8
44
44
45
45
def _fly_back (self , base : Expression , result : Expression ):
46
46
if base .operand1 is None :
@@ -56,24 +56,26 @@ def _fix_result(self, expression: Expression):
56
56
expression .result = self ._number_factory .fix (expression .result )
57
57
58
58
def _next_operator (self , expression : Expression ) -> list [Operator ]:
59
+ operators_allowed = Operator .get_operators_without_eq ()
60
+ if number_is_zero (expression .operand2 ):
61
+ # ? ? 0 = c
62
+ operators_allowed .remove (Operator .DIV )
59
63
if expression .operand1 is None or expression .operand2 is None :
60
- yield random .choice (Operator .get_operators_without_eq ())
61
- operators = Operator .get_operators_without_eq ()
62
- random .shuffle (operators )
63
- for operator in operators :
64
+ yield random .choice (operators_allowed )
65
+ random .shuffle (operators_allowed )
66
+ for operator in operators_allowed :
64
67
yield operator
65
68
66
69
def _resolve_result_is_none (self , expression : Expression ) -> Expression :
67
- start = time .time ()
68
70
operators = self ._next_operator (expression )
69
- while time . time () - start < self ._maximum_resolve_time_sec :
71
+ for _ in range ( self ._resolve_maximum_loop_count ) :
70
72
exp_result = expression .clone ()
71
73
if exp_result .operator is None :
72
74
try :
73
75
exp_result .operator = next (operators )
74
76
except StopIteration :
75
77
raise ExpressionResolverNotResolvable (expression = expression )
76
- if exp_result .operator == Operator .DIV and NumberFactory . is_zero (
78
+ if exp_result .operator == Operator .DIV and number_is_zero (
77
79
exp_result .operand2
78
80
):
79
81
continue
@@ -104,22 +106,20 @@ def _resolve_result_is_none(self, expression: Expression) -> Expression:
104
106
)
105
107
else :
106
108
exp_result .operand2 = self ._number_factory .next ()
107
- exp_result .result = self ._number_factory .fix (
108
- eval (
109
- f"{ exp_result .operand1 } { exp_result .operator } { exp_result .operand2 } "
110
- )
109
+ exp_result .result = eval (
110
+ f"{ exp_result .operand1 } { exp_result .operator } { exp_result .operand2 } "
111
111
)
112
112
self ._fix_result (exp_result )
113
- self ._check_result (expression , exp_result )
113
+ if not expression .is_match (exp_result ):
114
+ raise RuntimeError (f"Result is not match: { expression } vs { exp_result } " )
114
115
if not self ._validator .validate (exp_result ):
115
- # TODO time or count limit
116
116
continue
117
117
self ._fly_back (expression , exp_result )
118
118
return exp_result
119
119
120
- time_diff = time .time () - start
121
120
raise ExpressionResolverMaybeNotResolvable (
122
- message = f"Too slow: { time_diff :.1f} s" , expression = expression
121
+ message = f"Try count is reached ({ self ._resolve_maximum_loop_count } )" ,
122
+ expression = expression ,
123
123
)
124
124
125
125
def _resolve_only_operator_missing (self , expression : Expression ) -> Expression :
@@ -135,29 +135,28 @@ def _resolve_only_operator_missing(self, expression: Expression) -> Expression:
135
135
operators = Operator .get_operators_without_eq ()
136
136
random .shuffle (operators )
137
137
for operator in operators :
138
- if operator == Operator .DIV and NumberFactory . is_zero (expression .operand2 ):
138
+ if operator == Operator .DIV and number_is_zero (expression .operand2 ):
139
139
# zero division
140
140
continue
141
141
exp_result = expression .clone ()
142
142
exp_result .operator = operator
143
- exp_result .result = self ._number_factory .fix (
144
- eval (
145
- f"{ exp_result .operand1 } { exp_result .operator } { exp_result .operand2 } "
146
- )
143
+ exp_result .result = eval (
144
+ f"{ exp_result .operand1 } { exp_result .operator } { exp_result .operand2 } "
147
145
)
148
- if not NumberFactory .is_equal (exp_result .result , expression .result ):
146
+
147
+ if not number_is_equal (exp_result .result , expression .result ):
149
148
continue
150
149
self ._fix_result (exp_result )
151
- self ._check_result (expression , exp_result )
150
+ if not expression .is_match (exp_result ):
151
+ raise RuntimeError (f"Result is not match: { expression } vs { exp_result } " )
152
152
if not self ._validator .validate (exp_result ):
153
153
continue
154
154
self ._fly_back (expression , exp_result )
155
155
return exp_result
156
156
raise ExpressionResolverNotResolvable (expression = expression )
157
157
158
158
def _resolve_result_is_available (self , expression : Expression ) -> Expression :
159
- start = time .time ()
160
- while time .time () - start < self ._maximum_resolve_time_sec :
159
+ for _ in range (self ._resolve_maximum_loop_count ):
161
160
exp_calc = expression .clone ()
162
161
exp_result = expression .clone ()
163
162
exp_result .result = expression .result
@@ -241,47 +240,27 @@ def _resolve_result_is_available(self, expression: Expression) -> Expression:
241
240
)
242
241
else :
243
242
raise RuntimeError ("Invalid state: only one operand is missing" )
244
- self ._check_result (expression , exp_result )
245
243
244
+ if not expression .is_match (exp_result ):
245
+ raise RuntimeError (f"Result is not match: { expression } vs { exp_result } " )
246
246
if not self ._validator .validate (exp_result ):
247
247
# TODO time or count limit
248
248
continue
249
249
self ._fly_back (expression , exp_result )
250
250
return exp_result
251
251
252
- time_diff = time .time () - start
253
252
raise ExpressionResolverMaybeNotResolvable (
254
- message = f"Too slow: { time_diff :.1f} s" , expression = expression
253
+ message = f"Try count is reached ({ self ._resolve_maximum_loop_count } )" ,
254
+ expression = expression ,
255
255
)
256
256
257
257
def resolve (self , expression : Expression ) -> Expression | None :
258
- start_time = time .time ()
259
- try :
260
- if expression .result is None :
261
- return self ._resolve_result_is_none (expression )
262
- if expression .operand1 is not None and expression .operand2 is not None :
263
- return self ._resolve_only_operator_missing (expression )
264
- return self ._resolve_result_is_available (expression )
265
- finally :
266
- end_time = time .time ()
267
- diff = end_time - start_time
268
- if diff > 0.01 :
269
- print (f"ExpressionResolver.resolve: { diff :.2f} seconds" )
270
-
271
- def _check_result (self , expression : Expression , result : Expression ):
272
- if expression .operand1 is not None :
273
- if not NumberFactory .is_equal (expression .operand1 , result .operand1 ):
274
- raise RuntimeError (f"Invalid operand1: { expression } -> { result } " )
275
- if expression .operand2 is not None :
276
- if not NumberFactory .is_equal (expression .operand2 , result .operand2 ):
277
- raise RuntimeError (f"Invalid operand2: { expression } -> { result } " )
278
- if expression .result is not None :
279
- if not NumberFactory .is_equal (expression .result , result .result ):
280
- raise RuntimeError (f"Invalid result: { expression } -> { result } " )
281
- if expression .operator is not None :
282
- if expression .operator != result .operator :
283
- raise RuntimeError (f"Invalid operator: { expression } -> { result } " )
258
+ if expression .result is None :
259
+ return self ._resolve_result_is_none (expression )
260
+ if expression .operand1 is not None and expression .operand2 is not None :
261
+ return self ._resolve_only_operator_missing (expression )
262
+ return self ._resolve_result_is_available (expression )
284
263
285
264
@staticmethod
286
265
def is_zero_division (operator : Operator , operand2 : float ) -> bool :
287
- return operator == Operator .DIV and NumberFactory . is_zero (operand2 )
266
+ return operator == Operator .DIV and number_is_zero (operand2 )
0 commit comments