fork download
  1. from __future__ import unicode_literals, division, print_function
  2. import re
  3.  
  4. def do_it(expr):
  5. elems = parse_input(expr)
  6. if elems is None: raise Exception()
  7. val1, op_chr, val2, val3 = elems
  8.  
  9. op_fn, test_fn = get_operator_fn(op_chr)
  10. precheck_fn = get_precheck_fn(val1, test_fn, val2, val3)
  11. valid_fn = get_valid_fn(val1, op_fn, val2, val3)
  12.  
  13. def assignNum(chars, nums=range(10), a_dic={}):
  14. if len(chars) <= 0:
  15. if valid_fn(a_dic):
  16. print(format_result(val1, op_chr, val2, val3, a_dic))
  17. return True
  18. return False
  19.  
  20. for i in range(len(nums)):
  21. a_dic[chars[0]] = nums[i]
  22.  
  23. if not precheck_fn(a_dic):
  24. continue
  25.  
  26. if assignNum(chars[1:], nums[0:i] + nums[i + 1:]):
  27. return True
  28.  
  29. del a_dic[chars[0]]
  30. return False
  31.  
  32. print(expr)
  33. assignNum(list(set([ch for ch in val1 + val2 + val3])))
  34.  
  35. def to_num(val, a_dic):
  36. l_val = [ch for ch in val]
  37. l_pow = [pow(10, i) for i in reversed(range(len(l_val)))]
  38. return sum([a_dic[ch] * i for ch, i in zip(l_val, l_pow)])
  39.  
  40. def get_precheck_fn(val1, test_fn, val2, val3):
  41. def precheck_fn(a_dic):
  42. try:
  43. if any([a_dic[val[0]] == 0 for val in [val1, val2, val3]]):
  44. return False
  45. except KeyError:
  46. pass
  47.  
  48. for i in range(min(len(val1), len(val2), len(val3))):
  49. try:
  50. if not test_fn(a_dic[val1[-i - 1]], a_dic[val2[-i - 1]], a_dic[val3[-i - 1]]):
  51. return False
  52. except KeyError:
  53. pass
  54.  
  55. return True
  56.  
  57. return precheck_fn
  58.  
  59. def get_valid_fn(val1, op_fn, val2, val3):
  60. def valid_fn(a_dic):
  61. return op_fn(to_num(val1, a_dic), to_num(val2, a_dic)) == to_num(val3, a_dic)
  62. return valid_fn
  63.  
  64. def get_operator_fn(op_chr):
  65. if op_chr == '+': return lambda x, y: x + y, lambda x, y, z: z in ((x + y) % 10, (x + y + 1) % 10)
  66. if op_chr == '-': return lambda x, y: x - y, lambda x, y, z: z in ((10 + x - y) % 10, (9 + x - y) % 10)
  67.  
  68. def parse_input(expr):
  69. m = re.match(r'^([A-Z]+)\s*([\+\-\*/])\s*([A-Z]+)\s*=\s*([A-Z]+)', expr)
  70. if m is not None:
  71. return m.group(1), m.group(2), m.group(3), m.group(4)
  72. return None
  73.  
  74. def format_result(val1, op, val2, val3, a_dic):
  75. vals = [''.join([str(a_dic[ch]) for ch in val]) for val in [val1, val2, val3]]
  76. return '{} {} {} = {}'.format(vals[0], op, vals[1], vals[2])
  77.  
  78. do_it('SEND + MORE = MONEY')
  79. print()
  80. do_it('WWWDOT - GOOGLE = DOTCOM')
  81.  
Success #stdin #stdout 1.51s 7736KB
stdin
Standard input is empty
stdout
SEND + MORE = MONEY
9567 + 1085 = 10652

WWWDOT - GOOGLE = DOTCOM
777589 - 188103 = 589486