bash.im ithappens.me zadolba.li

Программизмы

13432

Fair dice roll

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

Уже более пятнадцати лет я наблюдаю пляски разработчиков игр вокруг рандомизаторов, и мне слегка несмешно временами, такое ощущение, что матчасть даже не пытались изучать:

  • if (rand(10000)==1) и прочие подобные глупости при использовании генератора с нормальным распределением.

  • Выбор по таблице добычи при помощи генератора с нормальным распределением. Если сюда добавить ещё разный шанс трофеям, то для некоторых позиций вырисовывается совсем запредельная схема.

  • Генерация энтропии на основе данных игрока/сессии/сервера. Обычно легко прослеживается и явно заметна.

  • Выборка случайного элемента из некоторой части списка для придания «большей случайности». За пределами добра и зла. В одной известной игрушке про убийство монстров это привело к тому, что можно было сутками пытаться выбить шмотку, которой просто не может выпасть в текущей сессии.

  • Скрытая манипуляция выборкой под видом случайного выбора.

  • ...и даже сочетание всего вышеперечисленного.

Самое смешное, что когда пользователи жалуются на симптомы подобных решений или вычисляют примерный алгоритм работы рандомизатора, начинается тотальное отрицание всего и вся. В крайнем случае, проверки алгоритма за пределами возможного матожидания, например: «Вот, смотрите, мы протестировали алгоритм на выборке из 300 выстрелов, всё чудесно». После этой фразы уже объяснять, что если сократить количество итераций до 30, картина меняется в корне, абсолютно бесполезно.

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

13430

Великий корейский рандом

Пишу на C# тест для детей. Первое задание — перевести маску подсети в сокращённый вид, второе — перевести маску подсети из сокращённого вида в полный, далее — вычисление адреса сети и так далее.

Прога практически дописана. И тут я замечаю, что у меня выдается одна и та же маска в первом и во втором задании, просто в разной форме записи. Ну, совпало, думаю.

Перезапускаю прогу ещё раз… маска совпадает. Ещё четыре раза — маска совпадает. Проверяю переменные — всё в порядке. Проверяю вывод данных — всё в порядке. Лезу в подпрограмму генератора маски — опять не вижу ошибок! Прямо перед отображением работы запускаю вхолостую генератор маски шесть раз — каждый раз выдаёт разные.

И тут я замечаю, что маски в первом и во втором задании больше не одинаковы. Перезапускаю программу — маски разные. Удаляю холостые запуски генератора — маски опять разные. Это всего лишь шесть раз подряд маски в первом и во втором случае совпали. Рандом — такой рандом…

13427

Неуловимый Джо

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

Вставляем в программу проверку входных бинарных данных (_fpclass) — вдруг нам NaN пришёл (или ещё какой мусор). И неожиданно для себя получаем три жирных бага в совсем других местах: зависание, некорректное отображение данных, движение времени «большими рывками».

Пара часов отладки — и становится понятно, что дело в том, что _fpclass портит режим сопроцессора. И вместо long double у нас сопроцессор считает всё как float.

Открываем сорцы. Ну странно же, когда стандартная подпрограмма из системной библиотеки не восстанавливает регистры оборудования. Гм, она восстанавливает. Угу, восстанавливает. Но с перепутанным порядком параметров в вызове _control87.

Дата написания кода — © 1998, 2000. Версия библиотеки 10.0. Как этот баг прожил 15 лет? 15 лет, Карл!

13417

Не путайте тёплое с мягким

Прихожу на сайт. Смотрю — висит объявление: «Требуется java-разработчик». А внутри чёрным по белому написано: «Требуется писатель руками на java для разработки проекта на Unity3D». Народ! Когда вы научитесь отличать Java от JavaScript? Unity3D — это популярный игровой движок с возможностью писать скрипты на C#, JavaScript и Boo (никому не нужном).

Почти что никого, никого из новичков не волнует, что написано JavaScript. И они начинают в описании проектов писать: «Язык программирования: Java». Начинают набор именно Java-программистов в команду. И самое страшное — начинают спорить, что Java и JavaScript отличаются как С++ от С, в ответ на справедливое замечание, что, мол, а название ЯП неправильное висит. Ну спорщиков-то не очень много, и они быстро сливаются под напором аргументов.

Менеджеры — это отдельный разговор. На эту тему много было сказано и ещё многое скажут, только намекну, что студии, где манагеры ищут Java-разработчиков на проект в Unity3D, можно посочувствовать.

Особое умиление вызывают «правильные» парни, которые в резюме, указывая свои знания, помимо разных языков, на которых писали хелловорлд в пятом классе, пишут также JavaScript (подразумевая, что использовали его в Unity3D). Чувак! Ты можешь сколь много времени писать на «JavaScript» в юнити, но в реальном вебе подели свои знания на ноль, поскольку, честно говоря, яваскрипт в юнити обладает рядом специфичных свойств, которых в тру JavaScript никогда не было и нет.

Даже на Bitbucket’е при указании языка программирования можно выбрать UnityScript, что означает JavaScript в Unity3D.

Возможно, это самая важная причина, почему народ, пишущий на UnityScript, потом бросает его в пользу куда более мощного С#.

Суть этой истории в том, что яваскрипт в юнити суть кака или, «выражаясь», неудачное решение.

13390

Тревожные звоночки

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

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

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

И чего, собственно, были вызовы?

Но, определённо, были же.

И зачем вообще их было отслеживать?

Да и глупо бы вышло. Странноватое ещё понятие — «пропущенные вызовы функции».

Спустя секунды приходит осознание…

13379

Один на всех и все на одного

Серверная — склад — база эникейщиков. Входит сотрудник.

— Здрасте, у нас там проблема. Я там пишу всем макросы на визуальном басике. У некоторых не работают. Гляньте.

Никто в «визуальном» не разбирается, но храбро идём к проблемным машинам. Беглый осмотр ничего подозрительного не выявил. Сравнение настроек также не показало отклонений. Рапортуем: настройки стандартные, запретов нет, проблема под капотом макросов. «Клиент» приходит снова:

— Проблема не в макросах: у других-то работает!

— Согласны, мистика, но из-за макроса переустанавливать систему мы не будем. Но если админ одобрит, переустановим хоть всем.

Все идём к админу: вот, так и так.

— Ошибку гуглили?

— Нет, не моё это дело, я только пишу.

— Ясно. Наши сотрудники провели осмотр и ничего не обнаружили. Проблема в макросе.

— Нет же, у других работает. Пусть ваши мальчики загуглят и исправят.

— Отладка VBS вне их рабочих обязанностей.

— И что мы будем делать?

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

Никто так и не уволился. Зато обогатился знаниями об отличиях 32 и 64-битных систем и стандартных путей разных версий Офиса.

13338

Икебана из костылей

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

А вот вторая мысль была реалистичнее: строили всегда как умели и как хотели, а до наших дней дошло то, что дошло. И тут осенило. А как надо строить, чтоб на века? Вот пирамида. Устойчивей некуда. Её можно было и целиком из песочка насыпать. Или навалить тёплой и мягкой субстанции в тех же габаритах. И ничего — стояло бы совсем как живое. Вот Парфенон — крыша на подпорках, политкорректно именуемых колоннами. Нотр-Дам тоже весь в подпорках и костылях, именуемых контрфорсами. Мда. А вот модульные универсальные решения типа хрущоб разваливаются на глазах.

Вывод для программистов довольно мрачный. Вы можете писать красивые модульные и универсальные решения, но в веках будут жить и достанутся потомкам только бесформенные кучи дерьма и икебаны из костылей…

13333

Самопроизвольное индоизвержение

А я теперь официально признаюсь быдлокодером.

Дело в том, что мне приспичило написать обёртку на Go для сишного API Eggdrop. Всё было хорошо до тех пор, пока я не попытался реализовать подобие Tcl-функции bind для C-функций. Полдня я потратил на исследование исходников, так как всемогущий поисковик мне не помог, но не нашёл ничего, кроме функций добавления и бинда Tcl-функций. В результате у меня получился такой механизм: генерируется имя вида eapi:bind_xxx, затем под этим именем добавляется привязываемая функция, затем получившаяся Tcl-функция привязывается как обычно. Возвращаемым значением этого монстра является номер бинда (то самое xxx в названии функции).

Простите меня, оно само.

13305

Руки на высоте плеч

Найдено в коде одного проекта. В stdafx.h:

#ifndef handsOutOfShoulders 
  #define handsOutOfAss 
#endif

Далее, в about:

#ifdef handsOutOfShoulders 
  /* нормальные реквизиты фирмы */
#else
  #ifdef handsOutOfAss 
    message = std::wstring(L"У нас появился долборукий
    дятел, разваливший сборку, и я не отвечаю
    за работоспособность программы");
  #else
    message = std::wstring(L"БЛ&$Ь!!! ПОКАЖИТЕ МНЕ,
    КАК ОНО РАБОТАЕТ!!!");
  #endif
#endif