Last active
April 8, 2017 12:08
-
-
Save vyach-vasiliev/6b6ce4616b3f518fceea17f671ab9f00 to your computer and use it in GitHub Desktop.
Get combinations of expressions for number N
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import re, json, collections, math, itertools | |
def get_comb_exp_for_number_v32_clean(for_number, numbers, wo_dupl=False, more=False, debug=False): | |
""" v3.2 Clean version | |
wo_dupl - Returns right expressions without duplicates (9.*2./1.-8. = 2.*9./1.-8.) | |
more - Returns detailed statistics | |
debug - Returns right expressions and print detailed statistics | |
""" | |
def iter_expressions(numbers, operations): | |
''' Iterator. Formating numbers and operations to expression: [1,2,3,4] and [+,-,/] -> 1.+2.-3./4. ''' | |
for n in numbers: | |
for o in operations: | |
yield '{x[0]}.{y[0]}{x[1]}.{y[1]}{x[2]}.{y[2]}{x[3]}.'.format(x=n, y=o) | |
def get_expressions(numbers, operations): | |
''' Formating numbers and operations to expression: [1,2,3,4] and [+,-,/] -> 1.+2.-3./4. ''' | |
return ['{x[0]}.{y[0]}{x[1]}.{y[1]}{x[2]}.{y[2]}{x[3]}.'.format(x=n, y=o) for n in numbers for o in operations] | |
def format_expression(exp): | |
''' Adding round brackets: 2.*9.-1.*8. -> (2.*9.-1.)*8., 8.+2.*1.-9. -> (8.+2.)*1.-9. ''' | |
for_rb_re = re.compile(r'(((\d\.)[*/])?(\d\.[+-]){1,}\d\.(?=[*/]))') | |
if for_rb_re.match(exp): | |
return for_rb_re.sub(r'(\1)', exp) | |
return exp | |
def clear_duplicates(exp_arr): | |
dupl_arr_re = [ | |
re.compile(r'(?<![\*/-])(\d\.[+]){1,}\d\.'), | |
re.compile(r'(?<![\*/+])(\d\.[-]){1,}\d\.'), | |
re.compile(r'(?<![+-/])((\d\.\/1\.|\d\.)[\*]){1,}\d\.'), | |
re.compile(r'(?<![+\-\*])(((?<=/)1\.|[2-9]\.)[/]){1,}\d\.'), | |
] | |
msk_same_type = re.compile('([023456789]|(?<!(\*|/))1)') | |
exp_remove_arr = [] | |
pseudo_good_arr = [] # Here not all positive expressions, but only a part | |
for exp in exp_arr: | |
if exp in exp_remove_arr: | |
continue | |
for item_re in dupl_arr_re: | |
_same_type = item_re.search(exp) | |
if _same_type: | |
same_type = _same_type.group(0) | |
numbers_str = ''.join([x[0] for x in msk_same_type.findall(same_type)]) | |
if len(set(numbers_str)) <= 1: # '22', '2.-2.+3.-3.', '{}.-{}.+3.-3.' | |
continue | |
exp_mask = msk_same_type.sub(r"{}", same_type) | |
exp_mask = exp[:_same_type.start(0)] + exp_mask + exp[_same_type.start(0) + len(same_type):] # '(2.*9.-8.)*1.', '2.*9.', '{}.*{}.' -> '({}.*{}.-8.)*1.' | |
numbers_permut = list(set(itertools.permutations(numbers_str, len(numbers_str)))) | |
for i, item in enumerate(numbers_permut): | |
if exp in exp_remove_arr: | |
continue | |
if i == 0: | |
w = exp_mask.format(*list(item)) | |
pseudo_good_arr.append(w) | |
if i > 0: # here must be check of user mask (+-+) | |
w = exp_mask.format(*list(item)) | |
if len(set(numbers_str)) <= 2 and not w in pseudo_good_arr: | |
exp_remove_arr.append(w) | |
elif len(set(numbers_str)) > 2: | |
exp_remove_arr.append(w) | |
exp_arr = set(exp_arr) - set(exp_remove_arr) # remove b from a | |
return exp_arr | |
if isinstance(numbers, list) or isinstance(numbers, tuple): numbers = ''.join(numbers) | |
right_expressions_arr = [] | |
numbers_arr = list(itertools.permutations(numbers, 4)) | |
operations_arr = list(itertools.product('+-/*', repeat=3)) | |
expressions_arr = list(set(get_expressions(numbers_arr, operations_arr))) | |
expressions_arr_format = [format_expression(exp) for exp in expressions_arr] | |
if wo_dupl and len(list(set(numbers))) > 1: expressions_arr_format = clear_duplicates(expressions_arr_format) | |
for exp in expressions_arr_format: | |
nbf = eval(exp, {'__builtins__': None}) # calculating | |
if float(for_number) == float(nbf): | |
right_expressions_arr.append(exp) | |
all_expressions_count = len(expressions_arr) | |
right_expressions = list(set(right_expressions_arr)) | |
right_comb_numbers = [re.sub("\D", "", i) for i in set(right_expressions_arr)] # 1234 | |
right_comb_operations = [re.sub("\w\.", "", i) for i in set(right_expressions_arr)] # +-*/ | |
more_result = { | |
'all_expressions': all_expressions_count, | |
'right_expressions': right_expressions, | |
'right_comb_numbers': right_comb_numbers, | |
'right_comb_operations': right_comb_operations, | |
'right_expression_count': len(right_expressions), | |
'wrond_expressions_count': all_expressions_count - len(right_expressions), | |
} | |
if debug: | |
print(json.dumps(more_result, indent=2)) | |
if not more: | |
return right_expressions | |
else: | |
return more_result | |
# if __name__ == '__main__': | |
# a = '1294' # 21 exps wo=False, 12 exps wo=True | |
# a = '3211' # 5exps wo=False, 2 exps wo=True | |
a = '1829' # (5, ['1.*2.*9.-8.', '2./1.*9.-8.', '2.*9./1.-8.', '(2.*9.-8.)/1.', '(2.*9.-8.)*1.']) | |
# a = '2829' # nothing | |
# a = '2233' # (3, ['2.*2.+3.+3.', '(3.+3.)*2.-2.', '3.+2.+3.+2.']) | |
# a = '5555' # (7, ['5.+5.+5.-5.', '(5.+5.)*5./5.', '(5.+5.)/5.*5.', '5./5.*5.+5.', '5.+5.-5.+5.', '5.-5.+5.+5.', '5.*5./5.+5.']) | |
a = '2222' # (2, ['(2.+2.)*2.+2.', '2.*2.*2.+2.']) | |
#res = get_comb_exp_for_number_v32_clean(10, a, wo_dupl=False, debug=False) | |
res = get_comb_exp_for_number_v32_clean(10, a, wo_dupl=True, debug=False) | |
print('Goted operations: {}\n{}'.format(len(res), res)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment