[ create a new paste ] login | about

Link: http://codepad.org/sWPDapof    [ raw code | fork ]

Python, pasted on Sep 17:
from itertools import permutations, chain
import re

def solve(problem):
    problem = re.sub('^([^=]+)=+(.*)$', r'(\1)-(\2)', problem)
    expr = compile(problem, '<string>', 'eval')
    variables = expr.co_names
    letters = [ord(x) for x in set(''.join(variables))]
    default_mapping = dict(zip(letters, [ord('5')] * len(letters)))
    varlens = [len(x) for x in variables]
    max_depth = max(varlens)
    tmp = [[x - i for x in varlens] for i in range(max_depth)]
    error_limits = [sum(int(10**(e - 1)) for e in t) for t in tmp]

    def advance(n, mapping, remaining):
        def distance(candidate):
            newmap = dict(chain(mapping.items(), candidate.items()))
            values = [int(v.translate(newmap).translate(default_mapping))
                      for v in variables]
            r = remaining
            if candidate:
                r = [d for d in remaining if d not in candidate.values()]
            env = dict(zip(variables, values))
            return abs(eval(expr, {}, env)), tuple(env.items()), newmap, r

        if n == max_depth:
            r = distance({})
            if not r[0]: yield r[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 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(dict(zip(letters, c))) for c in ps):
                    if r[0] < error_limits[n]:
                        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')))


Create a new paste based on this one


Comments: