среда, 24 августа 2016 г.

Шифры из Gravity Falls и их "разоблачение" на Python, или "чем заняться в лесу"


Сидели мы на базе отдыха в лесу. Интернет едва ловит, трафика не очень много, за прошедшую неделю хорошо отдохнули. Захотелось чего-то интересного. Я уже начала присматриваться к кодам для Ingress (не очень удобно в лесных условиях), но тут на глаза попалась шифровка в конце одной из серий Гравити Фолз...

(Да, я знаю, что все это наверняка разгадано и описано много раз. Но мы не ищем легких путей! :))

Седьмая серия, фраза: "KZKVI QZN WRKKVI HZBH: 'ZFFTSDCJSTZWHZWFS!'".

Начинаю вспоминать шифры, и навскидку вспоминаю только шифр Цезаря. Вручную считать лень. С хорошего отдыха хочется закодить что-то мелкое. Пишу:

cipher = "KZKVI QZN WRKKVI HZBH: 'ZFFTSDCJSTZWHZWFS!'"
 
def caesars_cipher(str, shift):
    result = ''
    for letter in str:
        new_chr = letter
        if letter in string.ascii_letters:
            letter_number = ord(letter)
 
            # Эти два блока "закольцовывают" алфавит, не позволяя выйти за его пределы
            if (letter in string.ascii_uppercase and letter_number + shift > ord('Z')) or \
                (letter in string.ascii_lowercase and letter_number + shift > ord('z')):
                    letter_number -= 26
 
            if (letter in string.ascii_uppercase and letter_number + shift < ord('A')) or \
                (letter in string.ascii_lowercase and letter_number + shift < ord('a')):
                    letter_number += 26
 
            new_chr = chr(letter_number + shift)
        result += new_chr
    return result

И запускаю, сразу со всеми сдвигами:


print("Исходный шифр:")
print(cipher)
print("Варианты расшифровки:")  
for i in range(1, 26)print("Сдвиг:", i, " ",  caesars_cipher(cipher, i))

Смотрю список всех вариантов и..ничего не получаю.

Тут птичка приносит мне на крылышках, что:
а) это шифр "Атбаш";
б) во всех сериях такое есть.

Берусь кодировать Атбаш!

def bashi_code(str):
    result = ''
    for letter in str:
        new_chr = letter
        if letter in string.ascii_letters:
            if letter in string.ascii_uppercase:
                new_chr = (string.ascii_uppercase[- string.ascii_uppercase.find(letter) - 1])
            else:
                new_chr = (string.ascii_uppercase[- string.ascii_uppercase.find(letter) - 1])
        result += new_chr
    return result

С оценкой эффективности вот так у меня пока не очень. Но кое-что я подозреваю. Поэтому пишу для дальнейших тестов альтернативу:

def bashi_code_alter(str):
    result = ''
    for letter in str:
        new_chr = letter
        if letter in string.ascii_letters:
            if letter in string.ascii_uppercase:
                new_chr = chr(ord("Z") - (ord(letter) - ord('A')))
            else:
                new_chr = chr(ord("z") - (ord(letter) - ord('a')))
        result += new_chr
    return result

Пробую:

print("Исходный шифр:")
print(cipher)
print("Расшифровка:")
print(bashi_code_alter(cipher))

И - да, получаю расшифровку!
"PAPER JAM DIPPER SAYS: 'AUUGHWXQHGADSADUH!'" - "Бумажный мятый Диппер говорит: ...". Боюсь, последнее "слово" уже не расшифровывается.

Теперь у нас есть функции, расшифровывывающие коды двух видов. И, возможно, будет что-то ещё? Пишу функцию-запускалку:

def decipher(cipher):
    print("Пробуем шифр Цезаря:")
    for i in range(1, 26):
        print("Сдвиг ", i, ": ",  caesars_cipher(cipher, i))
    print("Пробуем шифр Атбаш:")
    print(bashi_code(cipher))

И-и-и..запускаю на всех фразах всех пересмотренных на тот момент серий!

# 1 серияcipher = "ZHOFRPH WR JUDYLWB IDOOV"

Расшифровка, шифр Цезарь
Сдвиг  23 (-3) :  WELCOME TO GRAVITY FALLS

# 2 серия
cipher = "QHAW ZHHN: UHWXUQ WR EXWW LVODQG"

Расшифровка, шифр Цезарь
Сдвиг  23 :  NEXT WEEK: RETURN TO BUTT ISLAND

# 3 серия
cipher = "KH'V VWLOO LQ WKH YHQWV"

Расшифровка, шифр Цезарь
Сдвиг  23 :  HE'S STILL IN THE VENTS

# 4 серия
cipher = "FDUOD, ZKB ZRQW BRX FDOO PH?"

Расшифровка, шифр Цезарь
Сдвиг  23 :  CARLA, WHY WONT YOU CALL ME?

Интернеты говорят, что это про любовь Стэна, о которой он говорит в более поздних сериях.

# 5 серия
cipher = "RQZDUGV DRVKLPD!"

Расшифровка, шифр Цезарь
Сдвиг  23 :  ONWARDS AOSHIMA!

А здесь гугл сообщает, что Aoshima - это вот эта штука:


Гравити и есть Гравити :)

# 6 серия
cipher = "PU. FDHVDULDQ ZLOO EH RXW QHAW ZHHN. PU. DWEDVK ZLOO VXEVWLWXWH."

Расшифровка, шифр Цезарь
Сдвиг  23 :  MR. CAESARIAN WILL BE OUT NEXT WEEK. MR. ATBASH WILL SUBSTITUTE.

На этом моменте почувствовала себя победителем по жизни :) Потому что - да, я начала с 7 серии и Цезаря, когда в 6 серии Цезарем же написано, что использовать дальше! :)

# 7 серия
cipher = "KZKVI QZN WRKKVI HZBH: 'ZFFTSDCJSTZWHZWFS!'"

Расшифровка, шифр Атбаш:
PAPER JAM DIPPER SAYS: 'AUUGHWXQHGADSADUH!'

Здесь я решила временно остановиться, поскольку и пересмотр Гравити пока дальше не идет. Но в коде осталась TODO-шка! Два разных варианта Атбаша! Проверим их.

# Проверка разницы по скорости выполнения двух вариантов Атбаша.
def time_test():
 import time
 
 start_time = time.clock()
 bashi_code("HELLO THERE")
 print(time.clock() - start_time, "seconds")
 
 start_time = time.clock()
 bashi_code_alter("HELLO THERE")
 print(time.clock() - start_time, "seconds")
 
# Результат:
# 4.099999999999937e-05 seconds
# 1.8999999999998185e-05 seconds 

Воть так! Я слышала где-то, что строки - ме-едленные, но занятно получить подтверждение. Впрочем, медленный вариант нам пригодится, когда мы займемся русификацией... Но это в другой раз, а я закругляюсь. Надеюсь, вам было забавно наблюдать за моей расшифровкой!

Комментариев нет:

Отправить комментарий