×Закрыть

Вызов на Python-игры (часть 3)

Продолжение. Начало тут.

Внимание! Прежде чем читать дальше, я настоятельно рекомендую всем попытаться справиться с задачами самостоятельно. Опыт и полученное вами удовольствие будут несравненно выше.

Уровень 10

На 10 уровне нам предлагается найти длину 30 члена очень непонятной последовательности, первые несколько членов которой выдаются при щелчке на картинке.
После изучения последовательности и некоторого поиска в Интернет, я выяснил что последовательность эта называется «числа Морриса» и генерируется очень интересным методом.

В качестве начального значения берется чисто 1.
На каждом следующем шаге последовательность подряд идущих одинаковых цифр заменяется на их количество и саму цифру. То есть второй шаг будет 11 (одна единица). Дальше последовательность будет прогрессировать следующим образом:

  • 3 шаг: 21, две единицы
  • 4 шаг: 1211, одна двойка, одна единица
  • 5 шаг: 111221, одна единица, одна двойка, две единицы
И так далее.

Теперь дело осталось за малым — закодировать этот алгоритм. У меня, после недолгих размышлений вышла такая программа.

 

# счетчик
cnt = 1
# таблица последовательностей
# -1 используется как "стоповый" элемент
val = [1, -1]
# счетчик цифр
cc = 1

while cntval[num+1]:
cur.append(cc)
cur.append(val[num])
cc = 1
else:
# иначе просто увеличиваем счетчик
cc = cc +1
val = cur
val.append(-1)
cnt = cnt + 1
print cnt, val

# Выводим длину без последнего элемента "-1"
print len(val)-1
В «эталонных» ответах нашелся более краткий вариант решения, построенный на регулярных выражениях. Я приведу его без комментариев.

 

import re
def describe(s):
return "".join([str(len(m.group(0))) + m.group(1)
for m in re.finditer(r"(d)1*", s)])
s = "1"
for dummy in range(30):
s = describe(s)
print len(s)
После выполнения программы, мы получаем число 5808, которое и служит пропуском на следующий уровень.

Уровень 11

Уровень встречает нас необычной картинкой. Рассмотрев ее внимательней в любом редакторе, становится ясно, что она наполовину состоит из черных точек. Заголовок страницы, гласящий «чет нечет» «завершил» начатое дело. Стало понятно что надо оставить от картинки пикселы то ли с четными то ли с нечетными координатами. Так получилось, что я угадал с первого раза что нужны четные.

 

import Image
# загружаем рисунок
im = Image.open("cave.jpg")
# создаем рисунок-"назначение"
res = Image.new('RGB', (im.size[0]//2, im.size[1]//2))

for x in range(im.size[0]):
for y in range(im.size[1]):
# сохраняем точки
res.putpixel((x//2, y//2), im.getpixel((x, y)))

#показываем что получилось
res.show()
Второе решение было найдено случайно. Если файл открыть в программе просмотра картинок типа IrfanView и уменьшить вполовину — рисунок отчетливо проступает. Это натолкнуло на второй вариант решения с использованием трансформаций библиотеки PIL.

 

import Image, ImageEnhance
inp = Image.open('cave.jpg')

# уменьшение рисунка в 2 раза
outp = inp.transform((inp.size[0]//2, inp.size[1]//2),
Image.AFFINE, (2,0,0,0,2,0))

# увеличиваем яркость
outp = ImageEnhance.Brightness(outp).enhance(8)
outp.show()
На получившемся рисунке можно легко рассмотреть искомое слово, которое и приводит нас на следующий уровень.

Уровень 12
На этом уровне нас встречает картинка с раздачей карт с цифрой 5 на рубашке. Причем картинка очень «полосатая», что натолкнуло сначала на мысль что надо что-то с ней сделать. Проковырявшись где-то с час, я ощутил безрезультатность этого направления.
Посмотрев исходник страницы, я увидел что картинка называется evil1, чисто наугад, поставив цифру 2 я убедился в том, что в наличии имеются и 2 и 3 картинки. С evil4 все было намного интересней, несмотря на что 3 картинка говорила об отсутствии продолжения, я решил попробовать номер 4, вместо картинки я получил текстовую надпись о том что «Берт-зло!». Проверив адрес «http://www.pythonchallenge.com/pc/return/bert.html», я убедился что Берт-таки просто воплощение зла. Я не смотрел Маппет-шоу ни разу, поэтому не знаю, кто такой этот Берт, но информация отложилась, и как видно не зря.

Картинка evil2.jpg дала еще одну подсказку, и я стал обладателем еще одного файла evil2.gfx.

Посмотрев его в HEX-редакторе, можно увидеть, что он на самом деле состоит из нескольких графических файлов. На эту мысль натолкнула «разбитая» сигнатура JFIF.
Число файлов нашлось тоже легко — не зря на первой картинке на картах было число 5.
Дело оставалось за малым — программой. Она, как водится, получилась небольшой.

 

# открываем файл источник
inf = open('evil2.gfx', 'rb').read()

cnt = 1
# массив результатов
res = ["", "", "", "", ""]
for char in inf:
res[cnt % 5] = res[cnt % 5] + char
cnt = cnt + 1

cnt = 1
# выводим в файлы
for zzz in res:
outf = open('test%s' % cnt, 'wb')
outf.write(zzz)
outf.close()
cnt = cnt + 1
Дело за малым — просмотрев файлы, дать им осмысленные имена.
В итоге мы получили 5 картинок. Одна из них правда не полная, но ее отлично можно просмотреть, например, FireFox-ом.

Слово на одной из картинок зачеркнуто. Остальные легко складываются в пароль на следующий уровень.
Почитав эталонные решения, я узнал что оператор получения срезов может оказывается иметь еще 3 параметр, который все сильно упрощал (как многого я не знаю). :-)

 

f=open("evil2.gfx").read()

for i in range(5):
open("image"+str(i)+".dat", "w").write(f[i::5])
Уровень 13.

На этом уровне нам предлагают позвонить тому самому злу. Картинка с телефоном имеет ссылку на кнопке 5 (имитируя вызов справочной). Последовав по этой ссылке, мы получаем XML-страницу очень знакомого содержания. Да-да-да, именно XML-RPC это то, что нам нужно.

В моем случае задача усложнялась тем что я нахожусь за прокси-сервером, поэтому потратив 3 минуты на поиски в Google, я нашел способ работать с XML-RPC через прокси-сервер. Для этого необходимо создать класс-прослойку, наследуемый от xmlrpclib.Transport, но умеющий работать через прокси.

После соединения с сервером и изучения предоставляемых им методов с помощью вызовов system.listMethods( ) и system.methodSignature(name), стало понятно что за предоставление справок отвечает вызов phone(name). Ну а кто у нас зло — мы помним еще с предыдущего уровня.

Вот и программка:

 

import xmlrpclib, httplib

class ProxiedTransport(xmlrpclib.Transport):
def set_proxy(self, proxy):
self.proxy = proxy
def make_connection(self, host):
self.realhost = host
h = httplib.HTTP(self.proxy)
return h
def send_request(self, connection, handler, request_body):
connection.putrequest("POST", '<a title="Linkification: http://%s%s" class="linkification-ext" href="http://%s%s/">http://%s%s</a>' % (self.realhost, handler))
def send_host(self, connection, host):
connection.putheader('Host', self.realhost)

p = ProxiedTransport()
p.set_proxy('127.0.0.1:3128')
server = xmlrpclib.Server('<a title="Linkification: http://www.pythonchallenge.com/pc/phonebook.php" class="linkification-ext" href="http://www.pythonchallenge.com/pc/phonebook.php">http://www.pythonchallenge.com/pc/phonebook.php</a>', transport=p)
print server.phone('Bert')
Она и дает нам адрес следующего уровня.

Уровень 14.

На этом уровне мы видим рисунок булочки, и какую-то странную картинку размеров 100×100 пикселей. Сохранив ее, и открыв в программе просмотра, мы видим, что на само-то деле ее размер — 10000×1 пиксель. Что очень соответствует названию «wire» («проволока») по-русски.
Теперь становится понятна и картинка с булочкой, и подсказка в исходнике страницы. Нам нужно «смотать» проволоку, уложив ее в квадрат 100×100 по спирали.

Уяснив задачу, принимаемся за ее решение.

 

import Image

# открываем исходный рисунок
src = Image.open('wire.png')
# создаем новый
dest = Image.new('RGB', (100, 100))

# задаем начальные координаты
x, y = (-1, 0);

counter = 1;
d = 1;
i = 100;

while(i>=0):
# горизонтальный проход
for j in xrange(i, 0, -1):
x += d
dest.putpixel((x, y), src.getpixel((counter - 1, 0)))
counter += 1

i -= 1
# вертикальный проход
for j in xrange(i, 0, -1):
y += d
dest.putpixel((x, y), src.getpixel((counter - 1, 0)))
counter += 1

# смена направления
d *= -1;

dest.show()
После выполнения этой программы, мы получаем портрет очаровательного кота, который дает нам пол ключа к следующему уровню (www.pythonchallenge.com/pc/return/cat.html). Рассмотрев его покрупнее и узнав его имя, мы можем переходить на следующий уровень.

Продолжение следует.

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті.

👍НравитсяПонравилось0
В избранноеВ избранном0
Подписаться на автора
LinkedIn

Похожие статьи



Нет комментариев

Подписаться на комментарииОтписаться от комментариев Комментарии могут оставлять только пользователи с подтвержденными аккаунтами.

Подписаться на комментарии