суббота, 22 декабря 2012 г.

IKS + SKI: Infognition December Functional Programming Contest

В этом году thedeemon (также известный как DeeMon - "drop the "the", it's cleaner" <c>) решил устроить всем отличный подарок на Новый Год.

Конечно же речь о соревновании IDFPC-2012, которое можно охарактеризовать как квест в духе всенародно любимого Save Endo. Ну разве что попроще. Но именно квест. С несколькими этапами, спрятанными тут и там кодовыми словами и таблицей результатов online.

И нет, я совершенно не собирался участвовать. У меня жуткий цейтнот по двум другим проектам, не говоря уже о приближающихся праздниках. Даже на тусовку хаскеллистов, которую организовал thesz на прошлой неделе, выбраться не удалось. Хотя было бы неплохо уже с народом познакомиться. Короче говоря, никакой возможности участвовать в IDFPC не было. Ссылку я, конечно, Лёхе кинул. Можно даже сказать выкинул. Выкинул из головы в скайп, чтобы поскорее о ней забыть. И благополучно забыл. До пятницы.

В пятницу в районе двух в скайпе появился Лёха и с порога спросил

- 11 UTC - это 15 MSK?

И пошло-поехало. Я ответил, что да. Лёха полез на Wolfram Alpha проверять. Вольфрам показывал явную ерунду. Мы зарепортили им баг, который они не исправили до сих пор... В таком режиме и пролетел оставшийся час.

Задание было опубликовано в 15:00 и отличалось крайней лаконичностью. Всем организаторам подобных контестов надо поучиться у DeeMon'а.

Дан файл - картинка в формате bmp, - в нём зашифрован кадр из фильма. Нужно сказать, что за фильм. Еще был обещан scoreboard, куда надо будет вбивать встреченные по ходу пьесы кодовые слова. Но поначалу он не работал.

Картинку из любопытства я глянул, однако примерно минут 40 после публикации еще отбивался от Лёхиных атак и пытался заниматься делом. Но потом всё равно сдался. И здесь начинается короткая, но полная драматизма, история двух антивселенных: IKS и SKI.

Ну что ж, давайте поиграем.

CODEWORD: PLAY

Итак, джентльмены. Есть файл и с ним надо что-то делать. Поехали!
Ну, с файлом всё ясно. Говорим ему less, узнаём, что grep - это наш друг, и вот:
cat pic.bmp | grep -a "###"
### These three # signs marked the beginning of data segment as well as first comment. Grep is your friend now.
### RGB triplets in this file do not really store colors.
### Each triplet of bytes correspoding to a pixel contains values A,B,C (in this order), each a signed 8-bit integer.
### Remember that BMP stores image upside-down, so first bytes of data segment are first triplets of last row of image.
### Let X=70 and Y=79 be coordinates of current pixel. Let VX=18 and VY=26 (signed 8-bit integers) be current vector. Let CLR=0.
### Loop: take values A,B,C from triplet corresponding to current pixel in this BMP.
### Xor VX with A, VY with B and CLR with C.
### If CLR is not 0 draw a line from (X,Y) to (X+VX,Y+VY).
### Add VX to X and VY to Y, repeat the loop until A=B=C=0.
### So first visited points should be (70,79), (70,87), (64,79), (64,87)...
### Codeword: play
Когда grep на вашей стороне, вам по плечу любые проблемы. А теперь настало время заняться векторной графикой.

CODEWORD: SVG

Итак, джентльмены, нам предстоит первое содержательное задание. Оно заключается в том, чтобы реализовать интерпретатор для своеобразной разновидности Черепашки Logo. Правда вряд ли эта версия подойдёт для обучения детей программированию. Но ведь и мы уже давно не дети, верно? Приступаем!

Emacs открыт, ghci запущен, будущее предельно понятно. Самый сложный вопрос - это в каком виде рендерить картинку. И вроде бы логично бы делать bmp такого же формата и размера, как исходная картинка. Но поскольку недавно прочитан "Dive Into HTML5", то выбор падает в пользу рисования на canvas'е. Это будет иметь свои последствия: и положительные, и отрицательные.

В параллельной антивселенной Лёха еще час назад заявил, что эта задача элементарно решается на MATLAB'е. Но у него до сих пор "блин, чего-то не бьётся" и никак не получаются контрольные точки (70,79), (70,87), (64,79), (64,87). Подкидываю ему пару идей и даже RGB - или, точнее, ABC - исходной точки (18,18,42), но он такой точки в MATLAB'е в упор не видит.

Через полчаса, в половину пятого, Лёха сваливает домой и просит не рассказывать ему подробности, потому что собирается еще порешать задачку... в понедельник. Смешно, ага.

Еще через 8 минут Черепашка рисует первую страницу Векторного Гипертекстового Фидонета с адресом 70:79/18.26:

А еще через минуту выясняется, что предстоит разработка интерпретатора Весьма Фон-Неймановской Виртуальной Машины (50:22/24.34):
Забавно, что программой для VVVM будет являться всё тот же многострадальный bmp.
Уже запущен скоринговый сервер, я регистрирую команду IKS и получаю первые 15 очков.

Чтобы не сойти с ума в мире декартовых черепах, вам нужны чёткие, ясные идеи.

CODEWORD: CARTESIAN

Итак, джентльмены, нам требуется найти потерянную страничку Векторного Гипертекстового Фидонета, на которую нет ссылки. Это не иголка в стоге сена, но всё же. Какие будут идеи?

Самая первая идея - это тупой перебор всех 400*200*256*256 траекторий с проверкой, что они не покидают пределов картинки и заканчиваются в "чёрных" точках (0,0,0). Но это как-то не комильфо.

Вторая идея основывается на том наблюдении, что мир Черепашки T-симметричен. Можно выпустить траектории в обратном времени из всех "чёрных" точек, которых всего несколько тысяч. Это неплохая идея, но в итоге решено всё-таки воспользоваться намёком и плясать от шрифта.

Для начала нужно понять, как именно рисуются буквы. Открываем сгенерённую html'ку в emacs'е и комментируя куски javascript-кода ищем какую-нибудь одну букву.

Первое открытие слегка обескураживает. Используемый в Векторном Гипертекстовом Фидонете шрифт хоть и единственный, но довольно хитрый. По крайней мере часть букв, например "A", не являются элементами шрифта, а состоят из нескольких различных глифов. Да и сама страничка рисуется не последовательно, буква за буквой, а в довольно хаотическом порядке. Там прорисовалась палочка, здесь появилась закорючечка, тут вылез штришок. Ну DeeMon, ну злодей...

Второе открытие более обнадёживающее. Буква "C" рисуется без отрыва пишушей части Черепашки от canvas'а. Именно паттерн буквы "C" я использую для поиска следующих страниц.

Первой такой обнаруженной страницей становится 106:15/18.0:

С буквой "C" мне повезло, конечно. Мало того, что она есть на секретной странице, так еще и является самым первым символом, с которого начинается её прорисовка. IKS героически набирает 29 очков. Кайф.

Обнаруживается и страница 173:80/88.-75 с недостающим куском спецификации VVVM. Выглядит она, правда, в лучших традициях Векторного Гипертекстового Фидонета:

Неплохо, в принципе, но надо бы что-то получше.

После непродолжительного ковыряния с буквами выясняется, что "P" и "M" тоже рисуются по-человечески. Это позволяет быстро получить 23:71/-60.-15:

Но на этом сказки кончились и начался Феерический Тупняк №1, который надолго сбил меня с истинного пути.

Как известно, с canvas'ом есть такой нюанс, что целые значения координат соответствуют не середине пиксела, а линии между соседними пикселами. Мои Черепашки рисовали по целочисленным координатами, отчего все странички слегка замылены. В этом даже есть своя эстетика, но...

Как можно видеть на картинке, символ "+" выглядит практически неотличимо от "." (или \cdot в TeX). Я даже поначалу решил, что это так и задумано. Что сложения в наборе инструкций VVVM нет, зато есть некоторый специальный оператор ".", описание которого нужно искать на неизвестных науке Тёмных Страницах Векторного Гипертекстового Фидонета...

Поэтому вместо того, чтобы заниматься интерпретатором VVVM, я решаю вычислить все глифы используемого шрифта и с их помощью найти все недостающие страницы. Фундаментальное исследование.

К сожалению, участие в контесте было спонтанным и неподготовленным технически. Поэтому приходилось сильно отвлекаться на всякие домашние дела. И судя по git log, шрифт был известен мне только к 11 вечера. За эти три часа IKS скатился со 2-го на 6-ое, а потом и на 8-ое место.

Выглядит шрифт вот так:

Комбинации этих чудесных закорючек образуют буквы и цифры на страничках Векторного Гипертекстового Фидонета. Круто.

Не могу гарантировать, что это полный список глифов шрифта, но скорее всего это так. Можно заметить, что некоторые закорючки дублируются. Это означает, что на страницах Векторного Гипертекстового Фидонета они были начертаны разными способами. Не 20 способов написания слова "меч", конечно, но тоже ничего так.

Когда у вас есть алфавит, получение всех страниц Векторного Гипертекстового Фидонета - это дело техники. Для каждой точки исходной картинки (x,y) и каждого символа алфавита вычисляем все варианты (vx,vy), перебирая пары точек символа. Например для глифа "C" это даёт 400*200*56 вариантов, что очень быстро. Отбрасываем убежавшие за границу картинки траектории, отбрасываем траектории со слишком длинными линиями (скажем длиннее 15 пикселов), отбрасываем траектории, являющиеся подтраекториями более длинных и ву-ля - ни одной новой страницы. Увы.

Но унывать времени нет, настала пора поманьячиться с VVVM.

CODEWORD: MANIAC

Итак, джентльмены, на этот раз жизнь, похоже, не загадывает никаких загадок. От нас требуется взять и тупо реализовать интерпретатор VVVM по спецификации, изложенной на 4 страничках Векторного Гипертекстового Фидонета. Поехали.

Но поехать сразу не удаётся. Мои домашние злоключения еще не кончились и приходится отвлечься еще на час-полтора. За комп я возвращаюсь уже в первом часу ночи и принимаюсь лихорадочно клепать интерпретатор.

Интепретатор клепается быстро и начинает работать тоже сразу. Если не считать одного маленького, но забавного косяка. Хотя я, естественно, уже сообразил, что "." - это именно "+", но это нисколько не мешает мне считать, что ".=" - это ":=", а не "+=". В итоге как минимум полчаса на отладку инструкции 10 всё-таки убито.

Но в целом реализация интерпретатора проходит гладко и в половину третьего ночи перед моим изумлённым взором предстаёт

$ ./Main | head
Codeword: MANIAC
и еще примерно 240Мб специфического текста... Это впечатляет.

Таблица скоринга уверенно показывает 48 очков у IKS. План на завтра понятен. Всё - спать.

Когда у вас всё получается слишком легко, то вы двигаетесь вперёд с такой скоростью, что можете даже не заметить что-нибудь очень важное. Настолько важное, что это может вам стоить места в top5 и даже в top10. И тут будут бессильны даже Агенты K и J.

CODEWORD: MEN IN BLACK

Итак, джентльмены, программа для VVVM сгенерила нам впечатляющие 240Мб текстовых данных, которые из себя представляют описание задания и программы для 1048576 параллельных процессов, каждый из которых должен выполнить 7 итераций, и тогда Элли с Тотошкой возвратятся в Канзас. А для того, чтобы всё это случилось, нам предстоит плотно поработать. Приступим.

В субботу я проснулся в райне полудня и практически сразу занялся делом. Но сначала всё-таки состоялись скайп-перегоры с параллельной антивселенной, в результате которых мне удалось заинтриговать Лёху и включить его в процесс прохождения квеста. Это было совсем не сложно: "Жены нет дома, ребёнок спит..." Большим демотиватором было то, что лидеры уже завершили выступление, набрав свою сотню очков. Но за утешительные призы еще можно было побороться, да и вообще - с такой задачкой повозиться интересно.

Исходный bmp-файлик оказался ох как не прост... Вот какое описание квеста сгенерила программа для VVVM:

Imagine a system with a lot of parallel processes, each with its own program and variables. On each iteration each process runs its program once. After all of them ran their programs follows next iteration. Variables of each process keep their values between iterations. All variables are integer. Initially they are filled with arbitrary values between 0 and 255. Each process has a mailbox, can send values to other processes (put in their mailbox) and receive values by reading from its own mailbox.
Here are the programs:
Process 327438:
  send Value to process 233125,
  send Value to process 114668,
  send Value to process 113287,
  [Q,J,P,W] <- receive(4),
  T <- (Q + J + P + W + 2) / 4,
  Value <- -40 * T / 64 + 54.
...
Run 7 iterations. Now Value variables of processes are intensities of pixels of a 1024x1024 bitmap filled rowwise.
Нет, я понимаю, конечно, что DeeMon профессионально занимается алгоритмами обработки изображений, но всё равно - чертовски круто.

Ладно, что тут у нас? Насколько хватает глаз, все программы выглядят типовым образом. Но насколько типовым? И как тут правильно действовать? Может преобразовать все программы в хаскель? Синтаксис подходящий, потом останется только в правильной монаде всё это запустить параллельно. Можно, конечно, попытаться реализовать честный парсер и интерпретатор этого Эрланга. Вроде 7 итераций для миллиона с небольшим процессов - это вполне обозримо. Еще можно попытаться понять, как именно устроена этот итерационная конструкция, раз она сходится при любых начальных данных.

Поразмыслив, останавливаюсь на варианте с честным интерпретатором Эрланга, поскольку он выглядит наиболее предсказуемым.

Вооружившись Parsec'ом, уже через час я получаю приемлемый парсер для описания одного процесса и пытаюсь его натравить на весь файл. И тут меня ждёт засада..

Я ожидал чего угодно: того, что можно send не только Value, но и другие переменные, что не будут парситься выражения, что... но случилось гораздо более неприятное. Ко мне пришёл cabal hell. С Parcec'ом ко мне приехали новые bytestring'и, отчего перестал работать ghci, а значит прощай REPL и здравствуй "Edit-Compile-Run". С учётом того, что 240Мб парсились у меня порядка 2 минут, всё это было очень печально. Когда уже выпустят новую платформу?

Второй более прозаической проблемой стала память. Выделенных 32-битному процессу 4Gb памяти не хватало и он валился. Пришлось перейти на ленивые ByteString и основательно поработать над структурами данных. Основные инструменты: Ctrl-W и Ctrl-K, BangPatterns, "!" и прагма {-# UNPACK #-}. В финальной версии процессу стало хватать 500-600Mb для парсинга и исполнения программ. Правда мне еще пришлось увеличивать размер стэка до 16 мегов, что как бы намекает, что какой-то space leak где-то всё-таки остался. Ну, не суть.

Как только проблема с ограничением по памяти была снята, парсер сразу замечательно заработал и можно было приступать к интерпретатору.

Поначалу мне кажется, что тут не может быть никаких трудностей - запускай себе процессы один за другим и будет тебе счастье. Но счастья не происходит. Первый же запущенный процесс ломается на пустом mailbox'е. Ну конечно, по спецификации они же работают параллельно, значит функция receive просто должна подождать, пока в mailbox'е будет требуемое количество данных. Мне такой Эрланг реализовывать совершенно не улыбается. Поэтому решено сжульничать. Я делаю предположение, что процессы образуют ациклический граф и достаточно этот граф отсортировать топологически, чтобы узнать правильный порядок запуска. Но быстро выясняется, что в результате топологической сортировки наверх выплывает Process 0, у которого всё-таки есть [Q,T,A,J] <- receive(4). Хм... Что же делать?

Спасение находится в классическом методе преодоления пропасти в два прыжка. На каждой из 7 итераций все процессы сначала выполняют все свои инструкции send, а уж потом - все остальные свои инструкции. Конечно, мне приходится удостовериться, что это корректно. Заодно я проверяю и узнаю много других замечательных фактов: что все формулы типовые и определяются парой коэффициентов, что процессы получают ровно по 4 значения в mailbox, что порядок значений в mailbox'е не важен, как и имена переменных, и что сохранять между итерациями можно только значение Value.

И вот наступает счастливый момент первого запуска и на диске образуется файл с названием result.bmp, в котором зелёная компонента имеет значение искомых переменных Value. С замиранием сердца я его открываю и вижу мешанину из зелёных пикселов всех мастей и оттенков. Мда, беда.

Ну что тут делать? Надо искать ошибку. И чего я только не предпринимал. И менял типы данных с Int32 на Word8, и делал отладочную печать для отдельных пикселов, и выводил их цвета в csv'шку, и сравнивал эти csv'шки для разных начальных значений переменных от 0 до 255... И каждый раз это минимум 2 минуты на запуск.

Постепенно у меня растёт уверенность, что интерпетатор работает правильно, а ошибка в чём-то другом. Потеряв на эту долбанную отладку уже 4 часа времени, я в сотый раз перечитываю задание квеста и до меня доходит, в чём дело. А дело в было в Феерическом Тупняке №2.

Я выводил пикселы в файл не в порядке нумерации процессов, а в порядке их следования в файле. Мне почему-то казалось, что порядок следования в файле имеет какое-то значение.

В итоге, в 20:30 уже основательно испохабленный (в основном переводом с Int32 на Word8) интерпретатор генерит мне вот такое нечто:

Честно говоря, я не сразу понял, о чём тут речь. Но потом разглядел двух мужиков в костюмах и тёмных очках и подумал, что речь может идти о Матрице. Но скоринговый сервер был с этим не согласен. Пришлось подумать еще чуть-чуть.

Честно говоря, когда я смотрел недавно третью часть MiB, то плевался и зевал весь фильм. Однако ж, пригодилось. Так бы ни за что не догадался...

А тем временем в параллельной антивселенной жизнь в субботу развивалась своим чередом. Отчаявшись найти байты (18,18,42) в MATLAB'е, Лёха решил попытать счастья с C#. Однако в итоге наступил на те же грабли. Искомые значения RGB не встречалась нигде в загруженной картинке. Тогда Лёха сменил тактику и стал работать с файлом как с BLOB'ом, а не как с bmp-изображением. Это принесло свои плоды и команда SKI стала стремительно подниматься по турнирной таблице.

Поиск неизвестных страниц Векторного Гипертекстового Фидонета Лёха осуществлял через символ "N", т.к. в нём было всего три линии. Отсечение траекторий выходящих за границы картинки, отсечение траекторий со слишком длинными линиями - всё как в лучших домах. Впрочем, одно know-how всё же было. Для навигации между сгенерированными изображениями Лёха прикрутил графический интерфейс с горизонтальным слайдером. Я видел скриншоты - это сурово :-)

Таская туда-сюда слайдер, Лёха обнаружил недостающую страницу спецификации, но проворонил cartesian.

А настящая засада ждала его на квесте с VVVM. Он быстро реализовал интерпретатор и тот даже стал что-то печатать, но явно не целиком. Процесс доходил до фразы про "7 итераций" и дальше происходило деление на ноль и на этом всё заканчивалось.

С интерпретатором VVVM Лёха прошёл примерно те же круги ада, какие проходил я в то же самое время с Эрлангом: пробовал знаковые и беззнаковые типы, дебажил так и эдак, запускал разными способами... Даже научился "вышибать её из цикла", что бы это ни значило.

В итоге, всеми правдами и неправдами он получил-таки все куски спецификации и даже набрал 58 очков. Но работающего интерпретатора в субботу так и не получил, что почему-то помешало ему двигаться дальше. Странно. Не похоже на Лёху. Подумаешь, неполная спецификация и деление на ноль.

Если всё, что вам мешает, это Бороды Уодлера - применяйте бритву Хаттона. Народная мудрость.

CODEWORD: WADLER

Итак, джентльмены, квест пройден, но мы не досчитались 24 очков. Мы где-то что-то упустили и нам предстоит это исправить. За работу.

После получения названия фильма у меня образовалось 76 очков и я стал изучать скоринговую таблицу. С лидерами давно было всё понятно, но пролезть в top5 было еще совершенно реально. Я решил немного проветрить мозг после Эрланга и попробовать провернуть это дело.

И тут начинается история Феерического Тупняка №3, который по праву можно считать Великим Феерическим Тупняком.

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

Нехитрые наблюдения над таблицей скоринга подсказывают, что мне не известно, скорее всего, одно-единственное кодовое слово стоимостью 24 очка. Чуть более хитрые наблюдения говорят, что это слово становится известно некоторым участникам, которые еще не нашли maniac'а. Мою уверенность, что слово спрятано в первом квесте усиливает тот факт, что Лёха всё еще борется с интерпретатором VVVM, в котором он явно где-то жёстко накосячил, но имеет 58 очков. Это значит, что он идёт другим путём. Он не знает cartesian, но знает что-то другое.

В голове звенит тревожный звоночек, что вряд ли два дополнительных кодовых слова будут спрятаны в одном квесте, но я отключаю этот аларм и возвращаюсь к исходной картинке. Какие с ней варианты?

Есть вариант, что в Векторном Гипертекстовом Фидонете есть еще какая-то неизвестная страница. Построенная другим шрифтом, скажем. Есть вариант, что кодовое слово написано прямо в файле, как play, но каким-нибудь более хитрым образом, например по вертикали. Есть вариант... да море вариантов. И я начинаю их по очереди один за другим проверять, постепенно подбираясь к своей основной гипотезе.

Дело в том, что еще при первом поверхностном знакомстве с картинкой, мне показалось, что на ней есть Watermark или какое-то другое скрытое изображение. От DeeMon этого можно было ожидать. И исключив несколько более простых схем, к ночи я плотно приступаю к Стеганографии. Чего я только не пробую, какие только алгоритмы не применяю... Читаю википедию и тематические статьи. Никак.

Но самое интересное заключается в том, что мне кажется, будто я просто вижу это слово на картинке. Я даже поинтересовался у Лёхи в скайпе, не 6 ли букв в этом слове и не заканчивается ли оно на "ER". Оказывается, что всё так и есть. Ну вот как тут было поверить в случайное совпадение? Я не поверил.

Но разглядеть первые 4 буквы никак не удавалось. От отчаяния я даже попробовал повбивать просто рандомные слова, типа "cipher" или "header". Но скоринговый сервер уверенно говорил, что эти слова никуда не годятся. В середине первого ночи я понял, что моё слово заканчивается то ли на "DER", то ли на "LER". Чёрт возьми, я до сих пор не знаю, глюки ли это были или?..

Upd. DeeMon развеял все сомнения. Глюки, это были глюки...

Короче говоря, наутро я проснулся совершенно разбитый, демотивированный и с больной головой. И ни единой идеи. Даже хотел забросить это дело. Но как тут забросишь, когда первое же сообщение, которое приходит с утра в скайп выглядит так: "Скажи, у тебя в машине знаковые или беззнаковые слова?" И я опять возвращаюсь к Стеганографии...

Я опять пробую по кругу все вчерашние идеи и проверяю пару новых, включая то, не является ли эта картинка стереограммой :-) Никакого толку. К трём часам дня я уже в полном отчаянии и ужасно уставший. Да еще Лёха троллит по скайпу: "А как только ты узнаешь, где твои 24 очка, немедленно напьешься с горя :)))" На себя бы посмотрел! Если бы я не подсказал про буферизацию, то до сих пор бы небось с 58 очками сидел :-)

В параллельной антивселенной тем временем действительно продолжается неравный бой с интерпретатором VVVM. Чтобы исключить любые возможные глюки .NET'а Лёха переписывает реализацию интерпретатора на C. Но это ему не помогает. Программа печатает код для миллиона с копейками процессов и валится с делением на ноль либо зацикливается - в зависимости от выбранных типов данных.

На прямой вопрос, каким образом она у меня завершалась, я искренне отвечаю, что ломалась на какой-то несуществующей инструкции. И это была чистая правда. Мне в тот момент и в голову не пришло, насколько сильно я запутываю Лёху таким ответом. Это только потом я сообразил, что в ленивом языке деление на ноль не является такой уж проблемой, из-за которой следует прервать выполнение программы.

К часу дня Лёха в отчаянии просит прислать ему исходник моего интерпретатора и сверяет побайтово со своим. Но даже это ему не помогает... Наконец в половину второго я предположил

- может у тебя какая-нибудь буферизация вывода
и ты просто не видишь последний кусок напечатанный?
И получил долгожданный ответ
- $@$@%#$^@%@%$$@^@$&@$^@%$@#$%@$%@$%~!!!!!!!!!!!!!!!!
- Я ДЯТЕЛ!!!!!!
- ДЯТЕЛДЯТЕЛДЯТЕЛ!!!!
Ну, слава богу, я уж боялся, что не дождусь. Восемь часов отладки прекрасно работающего с первого раза кода. Почти так же круто, как мой Феерический Тупняк №3.

А выяснилось вот что. В случае C#, несмотря на то, что выходной файл был обёрнут в using, Лёха, видя исключение на тему "division by zero", воспринимал это как ошибку и срубал процесс средствами дебаггера. В случае с классическим C без диезов всё было еще проще - деление на ноль сразу приводило к завершению процесса. В обоих случаях никакого flush не происходило...

А вот с Эрлангом Лёха расправился невероятно быстро. Предположив, что все формулы стандартного вида и применив тот же хак с преодолением пропасти в два прыжка, уже через полтора часа он получил 86 очков и обошёл меня в таблице результатов. Круто.

У меня же Феерический Тупняк №3 был в самом разгаре. В половине четвёртого я решаю "сверить часы" с Лёхой - проговорить явно те вещи, которые мы с ним оба знаем. И начинаю перечислять всякие очевидные факты: известные обоим кодовые слова, их стоимость и тому подобные вещи. И когда в ответ на какой-то простой и "очевидный" мне вопрос Лёха уклончиво заявляет, что "пойдёт с ребёнком гулять", в голове звенит уже не звоночек, а колокол. Какого чёрта я вожусь с первым квестом?! Что там со вторым, который я проскочил на всех парах? О боже! Не может ли там быть еще одной программы для VVVM?! Omg!

По-моему, Лёха еще даже собраться не успел, когда я прислал ему следующее:

for i in {33..240000} ; do echo $i; ./Main $i 2>/dev/null | head ; done;
33
34
Codeword: 35
36
Codeword: Wadler
О, Великие Боги Самуи! Вы даже не можете себе представить, в каком расстройстве я был. Сгоряча даже заявил
- блин, и на это я убил столько времени?
- это кодовое слово для криворуких программеров,
которые сразу не могут нормальный интерпретатор
реализовать и поэтому пробуют его с разных точек запускать
Но, если честно, то своя логика есть. В каждом квесте повторялся паттерн "сделай интерпретатор и запусти его на всех входах". Можно было и сообразить... А так - 11-ое место.

К этому моменту самые шустрые команды уже успели опубликовать свои отчёты и я углубился в их чтение. У меня, вот, на написание этого поста практически неделя ушла, а они по горячим следам успевают. Молодцы. Выяснилось, хотя я это и сам подозревал, что картинку можно построить и более качественную. На разные варианты художеств, включая правильные - без артефактов, - можно полюбоваться в отчёте _winnie и комментах к нему.

Вернувшись через два часа с прогулки, Лёха фактически мгновенно получил свои недостающие 14 очков. По состоянию scoreboard'а он без труда выяснил, что кодовое слово спрятано в первом квесте. Естественно, сразу сообразил, что есть неизвестная ему страница, и наверное дождаться не мог, когда можно будет вернуться за комп :-) Поиск недостающей страницы он осуществлял через "скобочку от E", что дало ему около 400 картинок на слайдере. Среди них попалась и искомая - не до конца отрисованная, но вполне читаемая.

Всё, у SKI и IKS по 100 очков. Пора закругляться.

Annihilation

Итак, джентьмены, время подводить итоги.

После того, как мы оба завершили выступление, мы почти час трепались по скайпу: делились впечатлениями, восстанавливали хронологию - в общем синхронизировали состояние антивселенных SKI и IKS и сколлапсировали их обратно как смогли.

Основной вывод: если участвовать, то всё-таки командой. Думаю, что дополнительных аргументов тут не требуется. И касается это не только соревнований и программирования.

DeeMon'у респектище.

Результаты.

Кухня

Отчёты других участников в комментариях к заданию.

Всё. Всех с наступающим!

3 комментария:

  1. Достойное выступление и первоклассное описание! Читается на одном дыхании.

    ОтветитьУдалить
  2. Спасибо :-)
    Сам-то когда уже с нами зарубишься?

    ОтветитьУдалить
  3. Вау, Вольфрам прислал письмо, что они починили баг с часовыми поясами. Я впечатлён.

    ОтветитьУдалить