В День 4 я был очень рад стандартной библиотеке, которую раньше не использовал в Python. Вот первая часть головоломки:
С помощью быстрого Google я выяснил, что Python предоставляет стандартную библиотеку для хэширования, которая называется hashlib
. Она содержит множество стандартных алгоритмов хэширования, таких как SHA1, SHA224, SHA256, SHA384, SHA512 и, конечно, MD5.
Ввод строки в модуль и получение шестнадцатеричного значения из него не так просты, как хотелось бы, но документация довольно понятна. Сначала строка должна быть преобразована в байтовый объект (s.encode()
), прежде чем ее можно будет передать в md5()
. Затем возвращаемое значение должно быть преобразовано в шестнадцатеричное с помощью функции hexdigest()
.
В качестве функции я выбрал solve()
, потому что ее можно использовать для решения любого количества ведущих нулей. Помните, всегда думайте о том, что вас ждет во второй части!
import hashlib
def solve(key, zeroes):
n = 1
prefix = zeroes * '0'
while True:
s = key + str(n)
h = hashlib.md5(s.encode()).hexdigest()[:zeroes]
if h == prefix:
return n
n += 1
print(solve('yzbqklnj', 5))
Я не был в восторге от while True
, но не видел альтернативы, кроме установки произвольно высокой верхней границы. Я видел код типа for i in range(1, 1000000)
и даже for i in itertools.count()
в мегатреде, который не казался намного лучше. Хорошая вещь в решении головоломок — знать, что решение есть, поэтому вы знаете, что в какой-то момент выйдете из цикла.
Код решил задачу для пяти ведущих нулей примерно за 0.8 с, что больше связано с реализацией hashlib
, чем с тем, что я делал, что по сути является грубой силой.
Часть 2 была самым коротким расширением на данный момент, и одним из самых коротких, которые я когда-либо видел:
Теперь найдите такое, которое начинается с шести нулей.
Наличие универсальной функции solve()
означало, что написать часть 2 было так же просто, как изменить один символ:
print(solve('yzbqklnj', 6))
Это работает немного медленнее, но я ожидал этого и был вполне доволен тем, что решение было найдено менее чем за 30 секунд.
А настоящие программисты Python?
Большинство Pythonistas решили эту задачу примерно так же, как и я, но есть пара решений, которые используют многопоточность, чтобы распределить грубую силу на несколько CPU. Я никогда раньше не занимался многопоточностью, так что, возможно, мне стоит обратить на это внимание.
Всего за четыре дня я понял, что есть несколько областей стандартного Python, на освоение которых мне нужно потратить некоторое время, иначе я буду продолжать решать головоломки, как будто я все еще пишу на Basic:
- zip()
- наборы
- многопоточность
- итераторы