from __future__ import unicode_literals, division, print_function
import re
def do_it(expr):
elems = parse_input(expr)
if elems is None: raise Exception()
val1, op_chr, val2, val3 = elems
op_fn, test_fn = get_operator_fn(op_chr)
precheck_fn = get_precheck_fn(val1, test_fn, val2, val3)
valid_fn = get_valid_fn(val1, op_fn, val2, val3)
def assignNum(chars, nums=range(10), a_dic={}):
if len(chars) <= 0:
if valid_fn(a_dic):
print(format_result(val1, op_chr, val2, val3, a_dic))
return True
return False
for i in range(len(nums)):
a_dic[chars[0]] = nums[i]
if not precheck_fn(a_dic):
continue
if assignNum(chars[1:], nums[0:i] + nums[i + 1:]):
return True
del a_dic[chars[0]]
return False
print(expr)
assignNum(list(set([ch for ch in val1 + val2 + val3])))
def to_num(val, a_dic):
l_val = [ch for ch in val]
l_pow = [pow(10, i) for i in reversed(range(len(l_val)))]
return sum([a_dic[ch] * i for ch, i in zip(l_val, l_pow)])
def get_precheck_fn(val1, test_fn, val2, val3):
def precheck_fn(a_dic):
try:
if any([a_dic[val[0]] == 0 for val in [val1, val2, val3]]):
return False
except KeyError:
pass
for i in range(min(len(val1), len(val2), len(val3))):
try:
if not test_fn(a_dic[val1[-i - 1]], a_dic[val2[-i - 1]], a_dic[val3[-i - 1]]):
return False
except KeyError:
pass
return True
return precheck_fn
def get_valid_fn(val1, op_fn, val2, val3):
def valid_fn(a_dic):
return op_fn(to_num(val1, a_dic), to_num(val2, a_dic)) == to_num(val3, a_dic)
return valid_fn
def get_operator_fn(op_chr):
if op_chr == '+': return lambda x, y: x + y, lambda x, y, z: z in ((x + y) % 10, (x + y + 1) % 10)
if op_chr == '-': return lambda x, y: x - y, lambda x, y, z: z in ((10 + x - y) % 10, (9 + x - y) % 10)
def parse_input(expr):
m = re.match(r'^([A-Z]+)\s*([\+\-\*/])\s*([A-Z]+)\s*=\s*([A-Z]+)', expr)
if m is not None:
return m.group(1), m.group(2), m.group(3), m.group(4)
return None
def format_result(val1, op, val2, val3, a_dic):
vals = [''.join([str(a_dic[ch]) for ch in val]) for val in [val1, val2, val3]]
return '{} {} {} = {}'.format(vals[0], op, vals[1], vals[2])
do_it('SEND + MORE = MONEY')
print()
do_it('WWWDOT - GOOGLE = DOTCOM')
ZnJvbSBfX2Z1dHVyZV9fIGltcG9ydCB1bmljb2RlX2xpdGVyYWxzLCBkaXZpc2lvbiwgcHJpbnRfZnVuY3Rpb24KaW1wb3J0IHJlCgpkZWYgZG9faXQoZXhwcik6CiAgICBlbGVtcyA9IHBhcnNlX2lucHV0KGV4cHIpCiAgICBpZiBlbGVtcyBpcyBOb25lOiByYWlzZSBFeGNlcHRpb24oKQogICAgdmFsMSwgb3BfY2hyLCB2YWwyLCB2YWwzID0gZWxlbXMKICAgIAogICAgb3BfZm4sIHRlc3RfZm4gPSBnZXRfb3BlcmF0b3JfZm4ob3BfY2hyKQogICAgcHJlY2hlY2tfZm4gPSBnZXRfcHJlY2hlY2tfZm4odmFsMSwgdGVzdF9mbiwgdmFsMiwgdmFsMykKICAgIHZhbGlkX2ZuID0gZ2V0X3ZhbGlkX2ZuKHZhbDEsIG9wX2ZuLCB2YWwyLCB2YWwzKQoKICAgIGRlZiBhc3NpZ25OdW0oY2hhcnMsIG51bXM9cmFuZ2UoMTApLCBhX2RpYz17fSk6CiAgICAgICAgaWYgbGVuKGNoYXJzKSA8PSAwOgogICAgICAgICAgICBpZiB2YWxpZF9mbihhX2RpYyk6CiAgICAgICAgICAgICAgICBwcmludChmb3JtYXRfcmVzdWx0KHZhbDEsIG9wX2NociwgdmFsMiwgdmFsMywgYV9kaWMpKQogICAgICAgICAgICAgICAgcmV0dXJuIFRydWUKICAgICAgICAgICAgcmV0dXJuIEZhbHNlCgogICAgICAgIGZvciBpIGluIHJhbmdlKGxlbihudW1zKSk6CiAgICAgICAgICAgIGFfZGljW2NoYXJzWzBdXSA9IG51bXNbaV0KICAgICAgICAgICAgCiAgICAgICAgICAgIGlmIG5vdCBwcmVjaGVja19mbihhX2RpYyk6CiAgICAgICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICAKICAgICAgICAgICAgaWYgYXNzaWduTnVtKGNoYXJzWzE6XSwgbnVtc1swOmldICsgbnVtc1tpICsgMTpdKToKICAgICAgICAgICAgICAgIHJldHVybiBUcnVlCiAgICAgICAgICAgIAogICAgICAgIGRlbCBhX2RpY1tjaGFyc1swXV0KICAgICAgICByZXR1cm4gRmFsc2UKCiAgICBwcmludChleHByKQogICAgYXNzaWduTnVtKGxpc3Qoc2V0KFtjaCBmb3IgY2ggaW4gdmFsMSArIHZhbDIgKyB2YWwzXSkpKQoKZGVmIHRvX251bSh2YWwsIGFfZGljKToKICAgIGxfdmFsID0gW2NoIGZvciBjaCBpbiB2YWxdCiAgICBsX3BvdyA9IFtwb3coMTAsIGkpIGZvciBpIGluIHJldmVyc2VkKHJhbmdlKGxlbihsX3ZhbCkpKV0KICAgIHJldHVybiBzdW0oW2FfZGljW2NoXSAqIGkgZm9yIGNoLCBpIGluIHppcChsX3ZhbCwgbF9wb3cpXSkKCmRlZiBnZXRfcHJlY2hlY2tfZm4odmFsMSwgdGVzdF9mbiwgdmFsMiwgdmFsMyk6CiAgICBkZWYgcHJlY2hlY2tfZm4oYV9kaWMpOgogICAgICAgIHRyeToKICAgICAgICAgICAgaWYgYW55KFthX2RpY1t2YWxbMF1dID09IDAgZm9yIHZhbCBpbiBbdmFsMSwgdmFsMiwgdmFsM11dKToKICAgICAgICAgICAgICAgIHJldHVybiBGYWxzZQogICAgICAgIGV4Y2VwdCBLZXlFcnJvcjoKICAgICAgICAgICAgcGFzcwogICAgICAgIAogICAgICAgIGZvciBpIGluIHJhbmdlKG1pbihsZW4odmFsMSksIGxlbih2YWwyKSwgbGVuKHZhbDMpKSk6CiAgICAgICAgICAgIHRyeToKICAgICAgICAgICAgICAgIGlmIG5vdCB0ZXN0X2ZuKGFfZGljW3ZhbDFbLWkgLSAxXV0sIGFfZGljW3ZhbDJbLWkgLSAxXV0sIGFfZGljW3ZhbDNbLWkgLSAxXV0pOgogICAgICAgICAgICAgICAgICAgIHJldHVybiBGYWxzZQogICAgICAgICAgICBleGNlcHQgS2V5RXJyb3I6CiAgICAgICAgICAgICAgICBwYXNzCiAgICAgICAgICAgICAgICAKICAgICAgICByZXR1cm4gVHJ1ZQoKICAgIHJldHVybiBwcmVjaGVja19mbgoKZGVmIGdldF92YWxpZF9mbih2YWwxLCBvcF9mbiwgdmFsMiwgdmFsMyk6CiAgICBkZWYgdmFsaWRfZm4oYV9kaWMpOgogICAgICAgIHJldHVybiBvcF9mbih0b19udW0odmFsMSwgYV9kaWMpLCB0b19udW0odmFsMiwgYV9kaWMpKSA9PSB0b19udW0odmFsMywgYV9kaWMpCiAgICByZXR1cm4gdmFsaWRfZm4KCmRlZiBnZXRfb3BlcmF0b3JfZm4ob3BfY2hyKToKICAgIGlmIG9wX2NociA9PSAnKyc6IHJldHVybiBsYW1iZGEgeCwgeTogeCArIHksIGxhbWJkYSB4LCB5LCB6OiB6IGluICgoeCArIHkpICUgMTAsICh4ICsgeSArIDEpICUgMTApCiAgICBpZiBvcF9jaHIgPT0gJy0nOiByZXR1cm4gbGFtYmRhIHgsIHk6IHggLSB5LCBsYW1iZGEgeCwgeSwgejogeiBpbiAoKDEwICsgeCAtIHkpICUgMTAsICg5ICsgeCAtIHkpICUgMTApCgpkZWYgcGFyc2VfaW5wdXQoZXhwcik6CiAgICBtID0gcmUubWF0Y2gocideKFtBLVpdKylccyooW1wrXC1cKi9dKVxzKihbQS1aXSspXHMqPVxzKihbQS1aXSspJywgZXhwcikKICAgIGlmIG0gaXMgbm90IE5vbmU6CiAgICAgICAgcmV0dXJuIG0uZ3JvdXAoMSksIG0uZ3JvdXAoMiksIG0uZ3JvdXAoMyksIG0uZ3JvdXAoNCkKICAgIHJldHVybiBOb25lCgpkZWYgZm9ybWF0X3Jlc3VsdCh2YWwxLCBvcCwgdmFsMiwgdmFsMywgYV9kaWMpOgogICAgdmFscyA9IFsnJy5qb2luKFtzdHIoYV9kaWNbY2hdKSBmb3IgY2ggaW4gdmFsXSkgZm9yIHZhbCBpbiBbdmFsMSwgdmFsMiwgdmFsM11dCiAgICByZXR1cm4gJ3t9IHt9IHt9ID0ge30nLmZvcm1hdCh2YWxzWzBdLCBvcCwgdmFsc1sxXSwgdmFsc1syXSkgCgpkb19pdCgnU0VORCArIE1PUkUgPSBNT05FWScpCnByaW50KCkKZG9faXQoJ1dXV0RPVCAtIEdPT0dMRSA9IERPVENPTScpCg==