По чьей-то ссылке наткнулся на очередной сайт с загадками вида "вычисли URL следующей страницы". При ближайшем рассмотрении оказалось, что головоломка рассчитана на программистов и предполагает использование Python-а.
Just for fun я попробовал сделать ее на Haskell. И вот что получилось...
(Помимо нижеследующего текста у меня также сохранился screencast самого процесса решения, правда - с английскими комментариями. Любопытствующие кликают сюда. Как-нибудь на днях напишу о том, как был сделан screencast - оказалось, что процесс далеко не такой тривиальный, как я думал)
Дальше задачи становится гораздо более python-specific (например, прохождение следующего уровня начинается с того, что нужно десериализовать из файла (при помощи модуля pickle) питоновский список), и я пока обломался их решать.
Just for fun я попробовал сделать ее на Haskell. И вот что получилось...
(Помимо нижеследующего текста у меня также сохранился screencast самого процесса решения, правда - с английскими комментариями. Любопытствующие кликают сюда. Как-нибудь на днях напишу о том, как был сделан screencast - оказалось, что процесс далеко не такой тривиальный, как я думал)
module Main where import Data.Char import Data.List import Network.HTTP import Network.URI import Network.Browser import Data.Maybe main = print "Doing pythonchallenge.com in Haskell :)" --------------- -- Уровень 0 -- ch0 = print $ 2^38 -- Результат: -- *Main> ch1 -- 274877906944 --------------- -- Уровень 1 -- ch1_text = "g fmnc wms bgblr rpylqjyrc gr zw fylb. rfyrq ufyr amknsrcpq ypc dmp. bmgle gr gl zw fylb gq glcddgagclr ylb rfyr'q ufw rfgq rcvr gq qm jmle. sqgle qrpgle.kyicrpylq() gq pcamkkclbcb. lmu ynnjw ml rfc spj." -- Судя по картинке, прилагающейся к тексту задания, это - простой циклический подстановочный шифр с шагом 2. -- Проще говоря, каждая буква сдвинута по алфавиту на две позиции назад. -- Будем декодировать при помощи словаря подстановок: dict = zip ['a'..'z'] (drop 2 $ cycle ['a'..'z']) -- Получаем список пар: -- *Main> take 10 dict -- [('a','c'),('b','d'),('c','e'),('d','f'),('e','g'),('f','h'),('g','i'),('h','j'),('i','k'),('j','l')] -- *Main> lookup 'o' dict -- Just 'q' -- *Main> lookup ' ' dict -- Nothing -- В исходном тексте есть не только буквы, но и точки-запятые, пробелы и т.п. Их декодировать не надо. -- Сделаем свой аналог 'lookup' для этих целей: translate c = case lookup c dict of Nothing -> c Just t -> t -- Собственно, результат: ch1 = map translate ch1_text -- *Main> ch1 -- "i hope you didnt translate it by hand. thats what computers are for. doing it in by hand is inefficient and -- that's why this text is so long. using string.maketrans() is recommended. now apply on the url." -- *Main> map translate "map" -- "ocr" --------------- -- Уровень 2 -- -- В длинном-длинном тексте, который можно увидеть, сделав 'View page source', надо найти "редкие буквы". -- Поначалу я думал, что надо посчитать, какие символы входят в текст реже всего и вывести их, но похоже, -- что задачка значительно проще: буквы (а не спец. символы) в этом тексте действительно выстречаются крайне -- редко. И надо найти и вывести именно их. ch2 = do txt <- readFile "ch2_text.in" return $ filter isAlpha txt -- *Main> ch2 -- "equality" --------------- -- Уровень 3 -- -- В длинном-длинном тексте необходимо найти все прописные буквы, окруженные с двух сторон ровно тремя строчными. -- Очевидно, что это задачка на использование regexp-ов. Исключительно хохмы ради я решил ее без регекспов :) -- Для начала разбиваем текст на последовательности, состоящие из букв одного регистра: sameRegister x y = isLower x == isLower y tokenize = groupBy sameRegister -- *Main> tokenize "AAAAbbbCCdEfffGhIjjj" -- ["AAAA","bbb","CC","d","E","fff","G","h","I","jjj"] -- Разбиваем поток токенов на тройки: triplicate lst = zip3 lst (drop 1 lst) (drop 2 lst) -- *Main> triplicate $ tokenize "AAAAbbbCCdE" -- [("AAAA","bbb","CC"),("bbb","CC","d"),("CC","d","E")] -- Эта функция проверяет, попадает ли конкретная тройка под условия задачи. guardedLetter (tok1, tok2, tok3) = and [ all isUpper tok1, length tok1 == 3 , all isUpper tok3, length tok3 == 3 , all isLower tok2, length tok2 == 1] -- *Main> guardedLetter ("AAA","b","CCC") -- True -- *Main> guardedLetter ("aaa","B","ccc") -- False -- Функция-helper, извлекающая средний элемент из тройки extractLetter (_,l,_) = l -- Складываем все вместе: ch3 = do txt <- readFile "ch3_text.in" return $ concatMap extractLetter $ filter guardedLetter $ triplicate $ tokenize txt -- *Main> ch3 -- "linkedlist" --------------- -- Уровень 4 -- -- Дан URL, оканчивающийся числом. Страница, адресованная данным URL-ом, содержит в теле другое число. -- Подставив это число в URL, получаем адрес следующей страницы такой же структуры и т.п. -- Задача - пройти эту цепочку до конца и не задолбаться :) -- Я до сих пор почти не пользовался модулями Network.*, поэтому наверняка мой код можно переписать в 5 раз короче :) -- Эта функция вытягивает страницу с указаным адресом и возращает ее тело в виде строки. slurpPage address = do (Right result) <- simpleHTTP $ defaultGETRequest $ fromJust $ parseURI address return $ rspBody result -- Берем число-параметр, вытаскиваем соотв. страницу, вынимаем из нее ключ, возвращаем его. getNextKey key = do let base = "http://www.pythonchallenge.com/pc/def/linkedlist.php?nothing=" txt <- slurpPage $ base ++ key return $ last $ words txt -- Берем начальное число-параметр, идем по цепочке страниц до тех пор, пока можем вытаскивать -- из тела страницы следующее число. loopTheLoop key = do next_k <- getNextKey key case (all isDigit next_k) of True -> do putStrLn (key ++ " -> " ++ next_k) loopTheLoop next_k False -> return next_k -- Результат: "peak"
Дальше задачи становится гораздо более python-specific (например, прохождение следующего уровня начинается с того, что нужно десериализовать из файла (при помощи модуля pickle) питоновский список), и я пока обломался их решать.
(no subject)
Date: 2007-03-02 06:52 am (UTC)Начинаю думать о том, что надо бы изучить Haskell...
(no subject)
Date: 2007-03-02 07:39 am (UTC)(no subject)
Date: 2007-03-02 01:02 pm (UTC)Re: список
Date: 2007-03-02 02:47 pm (UTC)(no subject)
Date: 2007-03-02 08:24 am (UTC)(no subject)
Date: 2007-03-02 08:46 am (UTC)не могу вдуплить, что делать дальше с leak help :-/
(no subject)
Date: 2007-03-02 09:09 am (UTC)(no subject)
Date: 2007-03-02 08:50 am (UTC)Уровень 1: , выскакивает калькулятор, 2^38
Уровень 2: Хаскель, однострочник с явным разбором двух левых случаев (лень было оптимизировать): \x -> if x `elem` ['a'..'x'] then succ $ succ x else if x == 'y' then 'a' else if x == 'z' then 'b' else x
Уровень 3: Загружаем текст в emacs, регэкспом выкидываем всё, что не буква.
Уровень 4: Загружаем текст в emacs, регэкспом помечаем тегами всё, что удовлетворяет критерию, другим регэкспом удаляем всё, что вне тегов, третьим - заменяем каждое вхождение на соотв. букву.
Уровень 5: bash:
Пояснения (чтобы в man не заглядывать): "-q" - подавить вывод диагностических сообщений (нафиг они мне), "-O -" - выдавать документы на стандартный вывод, "-o" - выводить только проматчившуюся часть. В двух случаях облома меняем в этой строке начальное значение a и продолжаем. В конце - смотрим последнюю найденную страницу в браузере.
(no subject)
Date: 2007-03-02 08:52 am (UTC)Re: Reply to your comment...
Date: 2007-03-02 09:41 am (UTC)Уровень с лишними цифрами обнаружился один. На несколько строк мне насрать.
(no subject)
Date: 2007-03-02 10:09 am (UTC)Уровень 2: caesar
Уровень 3: tr
Уровень 4: sed
Уровень 5: sh+wget+sed
(no subject)
Date: 2007-03-02 10:20 am (UTC)(no subject)
Date: 2007-03-02 10:23 am (UTC)Мысль для меня слишком глубока. А кто мешает подправить выражение в sed или bc?
Re: Reply to your comment...
Date: 2007-03-02 10:33 am (UTC)(no subject)
Date: 2007-03-02 11:42 am (UTC)Re: Reply to your comment...
Date: 2007-03-02 12:41 pm (UTC)(no subject)
Date: 2007-03-03 06:37 pm (UTC)(no subject)
Date: 2007-03-04 09:25 am (UTC)Черт, затягивающая штука. Дошел уже до 20-го уровня ...
(no subject)
Date: 2007-03-04 10:22 am (UTC)С картинкой ещё прикольнее, вечером буду думать. :-)
(no subject)
Date: 2007-03-04 06:30 pm (UTC)А сам пока только на 16м.
(no subject)
Date: 2007-03-05 07:38 am (UTC)(no subject)
Date: 2007-03-05 09:56 pm (UTC)Вот только что вошёл на 18й и сил на сегодня больше нет.
18й пройду, наверное, очень быстро, вроде, простой, но если там далее типа 17го...
PS: называется: доагадайся, как я потерял авторизационную куку lj :-)
(no subject)
Date: 2007-03-06 07:47 pm (UTC)Мы с женой уже на 27-ом :)
(no subject)
Date: 2007-03-06 07:58 pm (UTC)Вообще же задачи очень неровные. Например, 18 (разница в картинках) и 19 (.wav) я прошёл очень быстро и не применяя программирования. 19 вообще издевательство, просто mplayerу параметры подобрал минут за 5 :)
Сейчас на 20м, LiveHTTP Headers от firefox помог понять, где найти private property, но сегодня уже реализовывать идеи не буду.
(no subject)
Date: 2007-03-07 09:53 pm (UTC)(no subject)
Date: 2007-03-20 09:34 pm (UTC)Мы дошли до 29-го и опять застряли.
(no subject)
Date: 2007-03-20 10:12 pm (UTC)(no subject)
Date: 2007-03-21 09:04 pm (UTC)Посказывать не буду, но с этого места начинается "реальная жесть"(тм). По крайней мере, для меня.
(no subject)
Date: 2007-03-06 08:01 pm (UTC)(no subject)
Date: 2007-03-20 09:35 pm (UTC)(no subject)
Date: 2007-03-02 02:01 pm (UTC)рядовой задолбалсявсе сделать на Haskell :)Получив в процессе какой-то фан. Speed run с использованием самых оптимальных инструментов - тоже интересно, но это другой способ подхода к снаряду.
(no subject)
Date: 2007-03-02 09:14 am (UTC)(no subject)
Date: 2007-03-02 01:58 pm (UTC)(no subject)
Date: 2007-03-02 12:11 pm (UTC)(no subject)
Date: 2007-03-02 01:58 pm (UTC)(no subject)
Date: 2007-03-02 02:32 pm (UTC)(no subject)
Date: 2007-03-02 04:59 pm (UTC)(no subject)
Date: 2007-03-03 04:22 pm (UTC)(no subject)
Date: 2007-03-04 09:24 am (UTC)Учтем на будущее ...
(no subject)
Date: 2007-05-17 06:28 pm (UTC)