На этом шаге мы рассмотрим решение этой головоломки.
SEND + MORE = MONEY - это криптоарифметическая головоломка, где нужно найти такие цифры, которые, будучи подставленными вместо букв, сделают математическое утверждение верным. Каждая буква в задаче представляет одну цифру от 0 до 9. Никакие две разные буквы не могут представлять одну и ту же цифру. Если буква повторяется, это означает, что цифра в решении также повторяется.
Чтобы проще было решить эту задачку вручную, стоит выстроить слова в столбик:
SEND + MORE ------ MONEY
Задача легко решается вручную, потребуется лишь немного алгебры и интуиции. Но довольно простая компьютерная программа поможет сделать это быстрее, используя множество возможных решений. Представим SEND + MORE = MONEY как задачу с ограничениями.
from csp import Constraint, CSP from typing import Dict, List, Optional class SendMoreMoneyConstraint(Constraint[str, int]): def __init__(self, letters: List[str]) -> None: super().__init__(letters) self.letters: List[str] = letters def satisfied(self, assignment: Dict[str, int]) -> bool: # если есть повторяющиеся значения, то решение не подходит if len(set(assignment.values())) < len(assignment): return False # если все переменные назначены, проверяем, правильна ли сумма if len(assignment) == len(self.letters): s: int = assignment["S"] e: int = assignment["E"] n: int = assignment["N"] d: int = assignment["D"] m: int = assignment["M"] o: int = assignment["O"] r: int = assignment["R"] y: int = assignment["Y"] send: int = s * 1000 + e * 100 + n * 10 + d more: int = m * 1000 + o * 100 + r * 10 + e money: int = m * 10000 + o * 1000 + n * 100 + e * 10 + y return send + more == money return True # нет противоречий
Метод SendMoreMoneyConstraint satisfied() выполняет несколько действий. Во-первых, он проверяет, соответствуют ли разные буквы одинаковым цифрам. Если это так, то решение неверно и метод возвращает False. Затем метод проверяет, всем ли буквам назначены цифры. Если это так, то он проверяет, является ли формула SEND + MORE = MONEY корректной с данным присваиванием. Если да, то решение найдено и метод возвращает True. В противном случае возвращается False. Наконец, если еще не всем буквам присвоены цифры, то возвращается True. Это сделано для того, чтобы после получения частичного решения работа продолжалась.
Попробуем это запустить: if __name__ == "__main__": letters: List[str] = ["S", "E", "N", "D", "M", "O", "R", "Y"] possible_digits: Dict[str, List[int]] = {} for letter in letters: possible_digits[letter] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] possible_digits["M"] = [1] # мы не принимаем ответы, начинающиеся с 0 csp: CSP[str, int] = CSP(letters, possible_digits) csp.add_constraint(SendMoreMoneyConstraint(letters)) solution: Optional[Dict[str, int]] = csp.backtracking_search() if solution is None: print("Решение не найдено!") else: print(solution)
Вы, вероятно, заметили, что мы предварительно задали значение для буквы М. Это сделано для того, чтобы исключить ответ, в котором М соответствует 0, потому что, если подумать, ограничение не учитывает, что число не может начинаться с нуля. Но попробуйте выполнить программу без этого заранее назначенного ответа.
Решение должно выглядеть примерно так:
{'S': 9, 'E': 5, 'N': 6, 'D': 7, 'M': 1, 'O': 0, 'R': 8, 'Y': 2}
На следующем шаге мы рассмотрим размещение элементов на печатной плате.