from itertools import permutations
import re
def solve(problem):
problem = re.sub('^([^=]+)=+(.*)$', r'(\1)-(\2)', problem)
variables = compile(problem, '<string>', 'eval').co_names
letters = [ord(x) for x in set(''.join(variables))]
default_mapping = dict(zip(letters, [ord('5')] * len(letters)))
max_depth = max(len(x) for x in variables)
def reconstruct(expr):
return re.sub(r'^\((.*?)\)-\((.*?)\)$', r'\1==\2', expr)
def advance(n, mapping, remaining):
def distance(candidate):
newmap = mapping + candidate
expr = problem.translate(dict(newmap)).translate(default_mapping)
r = remaining
if candidate:
r = [d for d in remaining if all(d != c[1] for c in candidate)]
return abs(eval(expr)), expr, newmap, r
if n == max_depth:
result = distance(())
if not result[0]:
yield reconstruct(result[1])
else:
nth = set(''.join(v[n:n+1] for v in variables))
letters = [ord(x) for x in nth if ord(x) not in dict(mapping)]
if not letters:
yield from advance(n + 1, mapping, remaining)
else:
xs = [ord(x) for x in '123456789'] if n == 0 else remaining
ps = permutations(xs, len(letters))
for r in sorted(distance(tuple(zip(letters, c))) for c in ps):
yield from advance(n + 1, r[2], r[3])
yield from advance(0, (), [ord(x) for x in '0123456789'])
print(next(solve('send + more = money')))
print(next(solve('apple + grape = cherry')))