Истории с тегом: программизмы

Всего историй: 900

5587

SlowSort()

Я преподаю программирование в провинциальном, но таки государственном университете. Работаю шестой год, по образованию — математик-программист. Работу свою люблю и отношусь к ней ответственно. Главная цель — научить студентов писать чёткие и прямые программы. Про это и хочу рассказать.

В четвертом семестре у прикладных математиков курс «Структуры данных и алгоритмы». Язык С++, среда и интерфейс программ мне индифферентны, но чтобы не тратили лишнее время, ратую за консоль. Две группы по две пары по четвергам весь семестр.

Первое занятие у одной группы. После получасовых объяснений студент спрашивает: «А что, STL использовать нельзя?» Говорю, что нет, ибо цель как раз в том, чтобы понять, как это работает. Он оказывается самым сильным в группе, библиотеку знает, но не умеет передавать параметры в функцию по ссылке. Круто. Объясняю.

Через пару — вторая группа. «А теперь возьмите код из примеров и реализуйте через функции». Четыре девочки говорят, что не умеют с ними работать. Мысленно матерюсь, вслух зову их поближе к доске и полпары объясняю то, что они должны были усвоить в первом, на крайний случай во втором семестре. Остальная часть группы краем уха слушает. Дома изливаю яд в блоге, вопрошая, почему девочкам незнание программирования ранее спустили на тормозах. Дураки с этой специальности отчисляются на первом курсе, так что по крайней мере математику студенты понимают.

Вторая неделя. Несколько студентов сделали задачи дома и принесли сдавать. Один красавец для каждой задачи создаёт отдельный динамический массив, перемещается по нему с помощью указателей и пытается выдать творение за линейный список. Ругаюсь, пока не начинаю повторяться. Товарищ оправдывается: мол, хотел побыстрее отделаться. В итоге потратил две пары на переделывание и дописывание задач. В конце сдаёт и гордо так говорит, что сделал быструю сортировку. Разумеется, нашёл реализацию для массива, и вместо каждого упоминания размера вставил функцию определения длины списка. Объясняю, что у полученного алгоритма сложность стала больше, чем у «пузырька». Ржём уже вместе. Кстати, о «пузырьке» — надо ли говорить, что остальные студенты о других сортировках не имеют никакого понятия? Обнаруживаются ещё четверо не знающих функций, зато давешние девицы к концу занятия доделывают первую часть лабы. Правда, с моей помощью, но радость и гордость на лицах неподдельные.

Началась третья неделя. Жду, что нового принесёт четверг.

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

5585

Угу-AI

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

Перевёл бота из режима обучения в активный, собирался сам зайти с другого UIN и потестировать, но тут работа навалилась. Только к концу рабочего дня я вдруг сообразил, что в аське непривычно тихо — никто меня не тревожил аж с обеда.

Читал логи. «Много думал». Больше всего впечатлило общение с любимой: бот разговаривал с ней полтора часа и договорился о романтическом свидании завтра вечером у меня дома.

5564

Круги ада: тест пройден

Читаем ТЗ на подсистему программного учёта вагонного чего-то там, которое поступило на ревизию.

Функции и задачи, выполняемые подсистемой, должны быть выполнены вне зависимости от отказов технических средств.

Представляем, как будут проходить приёмо-сдаточные испытания. Установили систему, запустили — и хренась по тестовому стенду молотком! Потом питание отключить, провода повыдёргивать, залить сверху водой и отлакировать огнемётом. Всё ещё работает? Сдали!

5546

Параноики, приходите после второй беты

Писал конвертер на Java из файлов MDB в SQLite. Понадобилась библиотека на чистой Java, то есть не привязанная к какой-либо платформе.

Интернет большой — библиотеку я нашёл. Правда, она была в разработке, поэтому не всё ещё работало должным образом. В частности, в описании было сказано, что не реализована работа с запароленными базами, поэтому пока с такими базами можно работать, как с обычными базами без пароля.

5537

Дао тестера

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

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

5518

Вот он какой, турецкий код

Коллега, задолбавшись проектом, поехал отдыхать с женой в Турцию. Нам же позарез понадобилось реализовать дополнительную функцию в той части проекта, которую знает только он. Связываемся с ним, пытаемся разузнать, где смотреть, где документация, а он отмахивается, что долго объяснять, и вообще он на отдыхе.

Где-то через час на почту пришло письмо с куском кода. Вставили — заработало. Ошибок не было. Когда коллега вернулся, мы выяснили, что он по памяти, без компилятора, IDE, проекта и документации по API на руках написал функцию в Блокноте и отправил нам — и был премного удивлён, что всё заработало с первого раза.

5502

Споткнулся, упал, очнулся — буква

Кто хоть раз мучился на C# с выводом форматированного текста в майкрософтовском GDI+, знает, что для точных измерений размеров выводимого текста нужно пользоваться методом MeasureCharacterRanges, так как MeasureString даёт лишь приблизительный размер прямоугольника, в который гарантированно укладывается выводимый на экран текст. Эти пляски необходимы, если ты уже нарисовал какой-то текст на экране, а теперь надо продолжить с того же места. Предлагаемая методика, хоть и громоздка, но считает всё точно, и привыкнуть к ней можно.

Разбирая код одного сумрачного гения с сертификатом MCSE, я узрел совершенно чудный алгоритм решения той же задачи. Определяются размеры буквы W, домножаются на количество букв в выведенном тексте, а потом из полученной точки правее выведенного текста начинется перебор всех пикселей справа налево, пока не встретится пиксель, отличный по цвету от фона. Затем определяется ширина пробела, прибавляется к найденной точке — и отсюда надлежит выводить следующий блок текста. Надо ли говорить, что измеренные таким образом размеры никаких гарантий не давали, если строка с выведенным текстом оканчивалась на буквы вроде T или V, а скорость вывода текста после исправления возросла в три раза?

5498

Цифра в боксе, плюс в уме

Учусь в небезызвестной Бауманке на робототехнике. Начало второго семестра, первая в нём информатика и задание: написать на WinForm калькулятор. Пока все радостно рисовали кнопочки на форме, я решил сделать калькулятор из двух текстбоксов, вылавливая в них ключевые символы по событию Change и отправляя в нужные переменные, дабы потом посчитать. Ловила программа элементы не как-нибудь, а брала для этого из текстбокса символ по счётчику, который рос при каждом вызове этого самого Change. Да, знаю, что индусятина, но вылетела из головы команда, чтобы длину строки получить.

Как это должно было выглядеть в идеале? Пользователь пишет число, жмёт, например, плюс, прога радостно этот плюс стирает, переносит в лейбл рядышком и перебрасывает курсор в соседний текстбокс. Как всё получилось? Пользователь вводит число, жмёт плюсик и… лицезреет ошибку.

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

Ой! Пользователь нажал кнопку! Так, счётчик у нас ноль, смотрим нулевой символ… Ага, единичка. Ничего делать не буду, но счётчик плюсану. Ай! Опять кнопку нажали. Ладно, надо свои ватты отрабатывать. Счётчик — единица, и под номером один у нас… ага, плюсик. Мы его из текстбокса убираем. Вай, что это — опять событие Change! Я же и то не закончил! Ладно, справлюсь, у меня оперативки много. Что, опять проверять текстбокс? Ладно. Счётчик — единица. Что? Да нету здесь символа с таким номером! Идите вы все…

5494

Самый научный в мире скринсейвер

Давным-давно, когда «Pentium 60 МГц» звучало гордо, стоял в нашем отделе 486 DX-33 c двумя мегабайтами ОЗУ, зато с видеокартой SVGA, метром видеопамяти и математическим сопроцессором. Трудился компьютер над расчётами каких-то статистических научных данных по довольно сложным зависимостям и формулам — сейчас уж не вспомню. Программа была написана в реальном режиме x86, где для доступа к памяти за 1 МБ нужно было работать через EMS или XMS. Только в этом режиме процессора работал драйвер хитрой железяки, эти самые данные собиравший. Код был очень чудесатым: впихнуть в сегменты по 64 КБ массив на 840 — это не фунт изюма.

Нежданно-негаданно накрылся у этого монстра мегабайт оперативки. Естественно, программа перестала работать, а график сбора данных и их обработки был сорван. Институт, как и все научные учреждения страны, финансировался бедно, и несчастный мегабайт ОЗУ купить было не на что. Нормальные программисты сдались бы — но не мы.

Мы использовали… память видеоадаптера. Код даже переписывать особо не пришлось — вместо библиотеки доступа к XMS была написана библиотека доступа к видеопамяти через VESA. Размеры окна отображения — те же самые 64 КБ, только по другому адресу, который и был указан программе: «Данные искать и писать тут».

В бета-версии программы графический режим видеоадаптера при выполнении расчетов не переключался, и на экране творилась просто жуткая психоделика. Конечно, в релизе мы вставили переключение видеоадаптера в разрешение 320×240, чтобы в первых 64 КБ рисовать прогресс-бар: «Подождите, данные обрабатываются». С точки зрения наших учёных ничего не изменилось: графики с готовыми данными и интерфейс для их записи на диск мы выводили по-прежнему в честных 1024×768, и только на экране ожидания текст надписи стал покрупнее.

В общем, ценой пары ночных бдений компьютера и его оператора расчёты вернулись в колею расписания, а нашему отделу была выписана премия за оперативное решение проблемы. А для любителей медитации перед компьютером мы оставили «пасхалку»: по хитрой комбинации клавиш режим видеоадаптера переключался, и можно было полюбоваться на самый научный в мире скринсейвер.

5484

О барометре в свободном падении

Говорите, программа рассчитывает принадлежность клетки к одной или другой группе по цвету фона? Ха! Нас этим не удивить.

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

Для справки: задача важная, нужная и популярная, и решений у неё есть много. Одно из решений приведено в книге «Алгоритмы: построение и анализ» Т. Кормена, являющейся университетским учебником для большинства вузов, начиная с MIT. Но в девяностых на окраине России про Кормена ещё не знали, и пришлось выкручиваться своими силами.

Насколько я понимаю, от нас ожидалось что-то вроде алгоритма Грэхема: взять самую левую точку, которая гарантированно будет включена в эту выпуклую оболочку, построить векторы ко всем остальным точкам, выбрать из них самый правый, перейти на выбранную точку, повторить. Если уже выбраны две точки, ситуация облегчается: сумма нормированных векторов будет тем больше, чем больше они сонаправлены. Проблема только в выборе второй точки, потому что не на чем построить самый первый вектор. Но если самая первая точка — крайняя левая, то можно взять вертикальный вектор (добавить мнимую точку с той же координатой X, но с запредельным Y): все остальные точки будут гарантированно справа. Но векторы у меня вылетели из головы, а с тригонометрией и выбором самого маленького угла относительно только что построенной прямой я просто запутался. Время поджимало, и надо было сдать хоть какое-то решение. Результат поразил даже меня самого.

Итак, для получения бонусных очков надо показать всё это графически. Отлично: выводим на экран все введённые точки, между всеми ними рисуем линии. Тогда линии, составляющие выпуклую оболочку, тоже будут нарисованы. Теперь берём какую-нибудь точку, расположенную вне этой оболочки ([639, 479] кажется подходящим кандидатом) и выполняем заливку FloodFill кавайно-малиновым цветом. Заливка упрётся в линии выпуклой оболочки. Теперь ещё раз пройдёмся по всем возможным линиям, отрисовывая их уже чёрным цветом — с точки зрения пользователя линии сотрутся. На экране останется малиновый фон с чёрной кляксой посередине, а граница между ними как раз и будет внешней оболочкой. Бонусное задание выполнено.

Теперь для каждой точки найдём цвета восьми окружающих её пикселей. Если среди них окажутся малиновые, вызовем сложный комплекс проверок, призванный ответить на вопрос, является ли точка частью внешней оболочки или же просто лежит рядом с границей. Я не помню, как я обрабатывал граничные случаи, — кажется, сдвигал точку на пиксель в сторону чёрного цвета, перерисовывал и смотрел на разницу, — но в конечном итоге я находил все точки выпуклой оболочки (плюс, возможно, несколько лишних, лежащих совсем рядом с границей и не отсеянных дополнительными проверками). В конце концов я очищал экран и рисовал выпуклую оболочку набело, одной линией: мол, смотрите, завидуйте. Весь процесс занимал несколько минут.

Монстрообразная программа состояла из нескольких десятков функций с «говорящими» именами типа CheckThis и Try12. Комментариев по делу не было: мне было не до них. Переменные имели имена, в которых начал путаться я сам. Глобальные и локальные были замешаны в гремучую смесь. Времени на отладку и на доводку этого чуда до ума просто не хватило. Работает? Сдаём!

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

Дома, в спокойной обстановке, я переписал решение как надо, с векторами и определением углов. Потом, переехав в другую страну и обучаясь на факультете компьютерных наук, я обнаружил ещё несколько решений этой задачи, в том числе очень оригинальный и довольно быстрый алгоритм Чана, созданный как раз в середине девяностых. Переписанная программа заняла в несколько раз меньше места, работала не в пример быстрее и выглядела куда элегантнее. А самое обидное, что реализация этого решения (даже с учётом повторения темы «векторы» в учебнике математики) заняла меньше времени.

Какой будет мораль? А не будет никакой морали. Разве что повторение общеизвестной истины: озаботьтесь проектированием перед тем, как начать писать код.