1. Что такое числовой ребус?
Ребус - это зашифрованный пример, где каждая цифра заменена какой-то буквой. Одна и та же цифра в примере обязательно должна быть заменена одной и той же буквой. И наоборот - две разных цифры не могут быть заменены на одну и ту же букву.
И последнее правило: в примере, который мы хотим превратить в ребус, ни одно число не может начинаться с 0.
Примеры ребусов:
EIN + EIN + EIN + EIN = VIER (1+1+1+1 = 4, нем.);
ЛОДКА + ЛОДКА + ЛОДКА + ЛОДКА = РЕГАТА;
КНИГА + КНИГА + КНИГА = НАУКА;
SEND + MORE = MONEY (Посылайте больше денег, англ.);
КОТ + КТО = ТОК
И все их с лёгкостью будет решать наша программа!
2. Структура нашей программы
Я понимаю, что вам важен один лишь результат, поэтому вы можете сразу посмотреть в конец блога. Однако, не обижайтесь, если вы там ничего не поймёте и поэтому не сможете пользоваться. А мы продолжим.
Итак, программа должна:
Узнавать ребус;
Перебирать все возможные значения букв;
Проверить, какие из них подходят;
Выдать результаты.
Всё это довольно легко, но давайте начнём со самого сложного - перебора и проверки, так как 1-й и 4-й пункт будут занимать всего одну строчку, если знать, как осуществеляется вывод и ввод в Python. Но давайте всё по порядку.
2.1. Перебор.
Я решил использовать для перебора рекурсию. Поясню для начала, что такое рекурсия. Рекурсивная функция - это функция, которая в процессе её выполнения вызывает саму себя. Например, перебор всех ходов в шахматах - это рекурсия, потому что мы перебираем всевозможные свои ходы и для каждого своего хода заново вызываем ту же функцию оценки для следующих возможных ходов.
Вёрнемся к нашему перебору. Его структура должна выглядеть примерно так:
Функция перебор(пример):
Найти букву в примере, которую ещё не заменили на цифру;
ЕСЛИ такой буквы нету, ТО пример готов и должен проверяться, а перебор закончен ИНАЧЕ:
Для каждой цифры от 0 до 9 выполнить:
Если такая цифра уже используется в примере, она нам не подходит; взять следующию цифру;
Каждую букву в примере заменить на эту цифру;
Вызвать перебор для нового примера
А теперь перепишем это на питон:
def get_comb(s):
print(s + '\r', end='')
letter = ''
for i in s:
if (i.isalpha()): # i.isalpha() показывает, является ли буквой переменная i
letter = i
break
if (not letter):
check(s)
return # заканчивает перебор, если пример готов
for n in range(10):
n = str(n)
if (s.find(n) > -1): continue
s2 = s.replace(letter, n)
get_comb(s2)
Эта функция заменяет буквы в ребусе на числа, не пропуская ни одного варианта. Нам остаётся только написать функцию check()
, которая будет проверять пример на правильность.
2.2. Функция check()
К счастью, нам не придётся писать длинную функцию, для того чтобы расшифровать наш пример и проверить его на правильность. Ведь для питона строка "10+29=39
", это все равно что обычный набор символов, он его не поймёт.
Так вот, существует в питоне функция eval()
. Эта функция назначена как раз для вычисления примеров и равенств (ведь 10+29=39 по сути своей, не пример, а равенство).
С этой чудестной утилитой функция check()
будет занимать всего лишь 4 строчки:
def check(s):
try:
b = eval(s.replace("=", "=="))
except: return
if (b): print(s)
Эта функция проверяет, верное ли равенство мы собрали. Если там возникает ошибка (когда вначале числа стоит 0, eval()
выдаёт ошибку), то мы считаем, что равенство неверно (и правильно делаем, ведь это нарушает правила числового ребуса).
Если же равенство собрано, то мы нашли решение ребуса и можем его вывести на экран.
Итак, осталось только собрать всё вместе и добавить ввод ребуса.
3. Программа целиком.
Теперь, вот вам весь наш код:
def check(s):
try:
b = eval(s.replace("=", "=="))
except: return
if (b): print(s)
def get_comb(s):
print(s + '\r', end='')
letter = ''
for i in s:
if (i.isalpha()):
letter = i
break
if (not letter):
check(s)
return
for n in range(10):
n = str(n)
if (s.find(n) > -1): continue
s2 = s.replace(letter, n)
get_comb(s2)
s = (input("Введите ребус: ")).replace(" ", "") # убираем пробелы с ребуса
get_comb(s)
Я также застраховал этот код : вы можете вводить ребус, делая пробелы, например, вводя кто + кот = ток
вместо кто+кот=ток
.
Итак, теперь вы можете очень быстро решать ребусы и даже придумывать свои, если, конечно, вы установили Python и ваш компьютер не слишком медленный (например, у меня на компьютере некоторые ребусы занимают минуту-две времени).
Удачи!
Комментарии (13)
randomsimplenumber
30.09.2023 16:50Пара замечаний:
def check(s):
Ожидается, что функция с таким названием что то вернет ;)
n = str(n)
Фу так делать. Когда переменная иногда int, иногда str - в большом куске кода можно запутаться. В вашем случае есть готовый метод, возвращающий '0123456789' ;)
IvanStrizak
30.09.2023 16:50Из картинки...
9567 - send
1085 - more
10752 - money
Буква n из send это 6.
Буква n в money это 7.
чего не сходится....
wataru
30.09.2023 16:50eval на пользовательском вводе — это очень, очень плохая идея.
например, у меня на компьютере некоторые ребусы занимают минуту-две времени
Ну так никаких оптимизаций в переборе нет. Надо распарсить текст, выделить числа, потом с младших разрядов перебирать еще неизвестные буквы, сразу проверяя, что сумма сходится.
А так самое наивное решение
fish224 Автор
30.09.2023 16:50Ну так никаких оптимизаций в переборе нет. Надо распарсить текст, выделить числа, потом с младших разрядов перебирать еще неизвестные буквы, сразу проверяя, что сумма сходится.
Я специально не стал этого делать, потому что 2 минуты на выполнение меня вполне устраивает.
Syzd
30.09.2023 16:50Подскажите print(s + '\r', end='') в python 2.7 не работает, а в 3.7 - работает. В чем дело? Как исправить, чтобы работало всюду?
wataru
30.09.2023 16:50По-моему, никак, питон3 и питон2 — это разные языки. На совместимость там забили.
fish224 Автор
30.09.2023 16:50У меня работает в python 3.9, а в питоне 2 этот код работать не будет, потому что версии языка заметно отличаются
Syzd
30.09.2023 16:50Вообще-то будет. Вот мой вариант, который может работать в Python 2.7 с латинскими символами.
#Only for use in Python 2.6.0a2 and later from __future__ import print_function def check(s): try: b = eval(s.replace("=", "==")) except: return if (b): print(s) def get_comb(s): print(s + '\r', end='') letter = '' for i in s: if (i.isalpha()): letter = i break if (not letter): check(s) return for n in range(10): n = str(n) if (s.find(n) > -1): continue s2 = s.replace(letter, n) get_comb(s2) s = (raw_input("Enter REBUS: ")).replace(" ", "") # remove space s = s.replace("=", "==") get_comb(s)
Dimano
А почему выводит второй, неправильный результат?
Введите ребус: КНИГА + КНИГА + КНИГА = НАУКА
28375+28375+28375=85125
98765+98765+98765=85495
Dimano
Разобрался не очищается последняя попытка, которая выводится на экран
Можно в конце добавить
print(' ' * 70, end='')
У дочки в учебники математики были такие ребусы, нам их не задавали но интересно же.
Самое простое с чего можно начать это когда в одном разряде и в слагаемых и в ответе стоит одинаковая буква, вариантов в зависимости от количества слагаемых немного.