Задать вопрос
  • Как написать структура классов платформера?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Перед нами серьёзный проект: есть и сеть, и подкачка, и поиск путей. Если вы будете писать платформер с нуля, вероятно, «лишние» компоненты вы писать не будете.
    2. Это компоненты, а не классы. Структура классов в геймплее будет более густая, а в рендеринге и физике — менее.
    Например, пишем 2D-рендеринг. Я бы делал Renderer, Tileset, TileLayer, Sprite, Particle…

    В зависимости от желания и целей, лучше воспользуйтесь чужим движком или напишите свой простенький. Куча вопросов отпадёт.
    Ответ написан
    Комментировать
  • Как понять решение задачи по нахождению всех анаграмм (рекурсия)?

    @Mercury13
    Программист на «си с крестами» и не только
    По очереди для каждого из элементов.
    1. Поставить его на последнее место.
    2. Вызвать функцию рекурсивно с длиной на 1 меньшей.

    Она, соответственно, будет по очереди ставить на ПРЕДпоследнее место каждый из оставшихся, и т.д.
    Ответ написан
  • Могли бы объяснить что такое квартиль и медианна?

    @Mercury13
    Программист на «си с крестами» и не только
    Это значит:
    Нижние 25% работ — в диапазоне 50…130.
    Следующие 25% — в диапазоне 130…150
    Ещё 25% — в диапазоне 150…170
    И верхние 25% работ — в диапазоне 170…500

    То, что среднее выше медианы, обычно свидетельствует о том, что сверху у распределения «длинный хвост». Что и видно — целых 25% работ попадают в диапазон 170…500.
    Ответ написан
    2 комментария
  • Можно ли обновлять модель в Qt по таймингу?

    @Mercury13
    Программист на «си с крестами» и не только
    Нет, так нельзя. И вообще, эти части модели вызывает элемент управления (например, QTreeView). Тем чаще, чем активнее мы работаем с данными.

    Как я понял, вы столкнулись с ситуацией: доступ к данным медленный. Значит, надо наладить кэш, чтобы rowCount, parent, index и прочие в большинстве случаев исполнялись мгновенно.

    Хорошо, задача номер два: где-то в дебрях второго потока идёт долгое обновление модели, а мы хотим её по частям отображать. Это дело сложное, и универсального ответа нет.

    Начнём с того, что синхронизировать поток и UI удобнее всего через сигналы-слоты-emit с типом соединения Qt::QueuedConnection (BlockedQueuedConnection, думаю, многовато будет). У слота будет один параметр: сколько элементов уже подгрузили.

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

    В слоте производим такую фишку: rowsAboutToBeInserted, изменяем наше дополнительное поле, rowsInserted. И так для всех элементов, у кого добавилось потомства.
    Ответ написан
    3 комментария
  • Как на 32-битной платформе в переменную типа intptr_t может влезть максимальный адрес ссылки?

    @Mercury13
    Программист на «си с крестами» и не только
    зачем нужно было вообще вводить intptr_t если есть uintptr_t, в который адрес точно влезет?

    intptr_t — разность двух адресов.

    И, более того, как в ЗНАКОВУЮ переменную типа intptr_t можно поместить 32-битный адрес памяти, если в этом числе 1 бит уходит на знак, а для данных остаётся 31 бит?

    Учите матчасть — как действует дополнительный код, почему машинные целые изображают в виде круга и почему знаковое и беззнаковое сложение выполняется одними и теми же операциями add/sub. В общем, данные записываются во все 32 бита. И в знаковый тоже.

    как может БЕЗЗНАКОВОЕ число равняться числу СО ЗНАКОМ?

    А вот сравнивать их — ошибка, и не зря большинство компиляторов выводит предупреждение. Оба надо перевести либо в unsigned, либо в signed, либо в более крупный знаковый целый тип.
    Ответ написан
    2 комментария
  • Может кто объяснить, что происходит при кликании ярлыка программы на физическом уровне?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Мышь посылает команды «Я нажата» и «Я отпущена». Считаем, что мышь USB’шная — тогда диспетчер шины 125 раз в секунду даёт мыши таймслот, и она за это время посылает 8-байтовый пакет, и в нём есть поля «сдвиг по X, сдвиг по Y, нажатые кнопки». Сама ОС ведёт счёт координатам курсора мыши. Отображение курсора мыши — это отдельная функция графического драйвера (из-за требовательности к скорости).
    2. ОС из этих команд генерирует событие «Двойной щелчок по координатам (X, Y)» и посылает текущей программе (в данном случае — оболочке Windows, explorer.exe, он же Проводник).
    3. Рабочий стол — это сильно модифицированный ListView из comctl32.dll (если я правильно назвал эту библиотеку). Впрочем, событие «двойной щелчок» обрабатывается самим Проводником, и если какой-то элемент выделен, он говорит: запусти файл, библиотека shell32.dll, функция ShellExecute с глаголом «open».
    4. Библиотека оболочки shell32.dll имеет специальную ветвь кода для запуска ярлыков. Она разбирает файл ярлыка и вызывает более низкоуровневую функцию CreateProcess.
    5. Ядро Windows делает всё, что нужно, чтобы создать процесс, завести под него отдельное «пользовательское» адресное пространство, отдельный стек вызовов, потоки ввода-вывода и т.д. Сам EXE-файл и его библиотеки становятся частью системы подкачки Windows, и если какая-то страничка сегмента кода будет выброшена, она подгружается прямо из EXE/DLL. Разрешает динамические адреса, которые становятся известны только при загрузке программы (т.н. relocations). Процесс загрузки программы — дело сложное, с ним я незнаком.
    6. Считаем, что программа GUI’шная. Тогда при загрузке, как ни странно, ничего внешне не происходит (только трещит винт, подкачивая данные в оперативную память). Сама программа говорит WinAPI: мне нужно создать такое-то окно, с такими-то кнопками в заголовке, с отображением на панели задач.
    7. Система сама посылает окну события: «Я изменяю свой размер», «Я показываюсь», «Я перерисовываюсь». Программа может перехватить эти события и сделать по ним что-то своё. Если у окна есть неклиентская часть (заголовок, рамка), показывает их сама Windows.
    8. За перерисовку клиентской части окна (то есть того, что внутри рамки) отвечает одна из нескольких подсистем Windows. Наиболее распространённая — GDI (интерфейс графических устройств), хотя всё чаще используют библиотеки аппаратного ускорения — DirectX/OpenGL/Vulkan.
    9. Как только сработали события перерисовки — внутренние Windows и пользовательские — мы видим на экране окошко!
    Ответ написан
    2 комментария
  • Правильно ли объясняется в тексте почему в 1 кб 1024 байт?

    @Mercury13
    Программист на «си с крестами» и не только
    Дело вот в чём. Возьмём магнитную память. У неё есть проволочки-ряды, проволочки-столбцы и проходящий через все сердечники провод считывания-записи. Чтобы считать ячейку, мы пускаем ток через нужный ряд и нужный столбец (сила тока подбирается так, чтобы две проволочки работали, а одна — нет). Чтобы пустить ток ровно через одну проволочку, используется такой девайс, как дешифратор: двоичный код, например, 010=2 превращает в позиционный код 00100000 (единица на 2-м месте, начиная с ноля).

    Вот у нас есть такой блок памяти. Пришёл адрес — как получить номер строки и столбца? Разделить адрес на кол-во столбцов; частное — № строки, остаток — № столбца. Для удобства столбцов должна быть степень двойки: во-первых, это полностью задействует возможности дешифратора; во-вторых, частное и остаток сводятся к тому, что часть линий адреса отводим на один дешифратор, часть на второй.

    Если у нас несколько таких блоков, из тех же соображений и строк должна быть степень двойки — так что получается, что ёмкость устройства памяти произвольного доступа (магнитной, оперативной, постоянной, флэш-) степень двойки. Количество блоков — не обязательно, и батарея чипов на SSD может содержать любое удобное количество — а ёмкость одного чипа действительно степень двойки.

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

    Вот и всё.
    Ответ написан
    Комментировать
  • Причина работы данного массива структур?

    @Mercury13
    Программист на «си с крестами» и не только
    Таков смысл «си с крестами» — «вы не платите за то, чем не пользуетесь». В данном случае: не пользуетесь авариями — не платите за них. Кстати, самый эффективный способ обработки аварий на x86 только недавно лишился патента, и я не в курсе, есть ли он в MinGW (на x64 патент обошли и он там давно был). Плюс совместимость с Си.

    Правда, мне пришлось сделать свои массивы Array1d и Fix1d именно для того, чтобы проверять границы: включено в debug и выключено в release.
    Ответ написан
    Комментировать
  • Что такое bulk-запрос?

    @Mercury13
    Программист на «си с крестами» и не только
    Это понятие никак не формализовано. Но в целом это…
    Запрос, позволяющий массово выполнить несколько сходных действий. Например, получить информацию сразу по нескольким контрагентам, со всем, что им подчинено. Залить в БД кучу информации.
    Ответ написан
    Комментировать
  • Программа для работы с тайлсетами?

    @Mercury13
    Программист на «си с крестами» и не только
    Tiled: www.mapeditor.org/. Не самая крутая, но самая известная.
    Вот ещё одна: tide.codeplex.com
    Ответ написан
    Комментировать
  • Как написать картинку кодом?

    @Mercury13
    Программист на «си с крестами» и не только
    Формат JPEG очень сложен, и КРАЙНЕ не рекомендую писать поддержку самому. Лучше пользоваться любой подходящей библиотекой. Вот, например, на Qt:
    #include <QImage>
    #include <QPainter>
    
    int main()
    {
        QImage pix(100, 100, QImage::Format_RGB888);
        pix.fill(Qt::darkBlue);
        QPainter painter(&pix);
        painter.setPen(QPen(Qt::yellow, 2.0));
        painter.drawEllipse(QPoint(50, 50), 40, 30);
        pix.save("test.jpg");
    }

    Приду домой — отыщу код на PHP, призванный уменьшать размер картинок. В общем, для любого современного языка библиотека найдётся.
    Ответ написан
    2 комментария
  • Почему в C++ нужно строить всю программу на ООП (длинный вопрос)?

    @Mercury13
    Программист на «си с крестами» и не только
    Задача ООП: 1) Локализовать изменения состояния объекта (инкапсуляция); 2) связывать разные кирпичики данных через стандартные интерфейсы (полиморфизм).

    Простейший тетрис не слишком велик, чтобы его писать на чистом ООП.
    Но представьте себе, мы начинаем налаживать настраиваемое управление джойстиком или клавиатурой. И тогда у нас появляется такой код.
    enum {
      BT_LEFT = 1,
      BT_RIGHT = 2,
      BT_ROTATE = 4,
      BT_SOFTDROP = 8,
      BT_HARDDROP = 16,
      BT_PAUSE = 32,
      BT_CONNECTED = 32768,   // бит, указывающий, что контроллер подключён
    };
    class Controller {  // интерфейс
    public:
      virtual unsigned poll() const = 0;   // сочетание битов BT_XXX
      virtual ~Controller = default;
    };

    Классы Keyboard и Joystick поддерживают интерфейс Controller, и подмена клавиатуры на джойстик и наоборот ничего не изменит.
    Вот вам полиморфизм.

    Текстовый редактор превращаем в многооконный — берём класс Editor и пристраиваем его не к программе в целом, а к MDI-окошку. Вот вам инкапсуляция — локализованное изменение состояния.

    Я как-то мучил движок Doom. Он написан в самом настоящем объектном стиле на чистом Си! Хотя и там были проблемы: сетевой код был куда хуже по качеству, чем сам движок. Писали разделённый экран, глобальную переменную netgame разделили на две, multiplayer и netgame и долго-долго правили баги, где multiplayer, где netgame (было дело, участник десматча ввёл IDKFA, это сработало и вызвало рассинхронизацию). А код пользовательского интерфейса — вообще медвежуть!
    Ответ написан
    Комментировать
  • Как мне получить нужное значение?

    @Mercury13
    Программист на «си с крестами» и не только
    ($dec >> 8) << 7 теряет нижние 8 бит и сдвигает на один вправо.
    $dec % 128 оставляет нижние 7 бит.
    Таким образом, эта конструкция выкусывает из числа 7-й бит (у младшего номер 0).
    Восстановить однозначно нельзя: надо (($res & ~0x7F) << 1) | ($res & 0x7F) и, возможно, | 0x80.
    Например: ((585 & ~0x7F) << 1) | (585 & 0x7F) | 0x80 = 1225.
    Во всех ваших четырёх примерах установить опущенный 7-й бит нужно. Он что-то значит?
    Ответ написан
    2 комментария
  • Как называется процесс чтения кода браузером?

    @Mercury13
    Программист на «си с крестами» и не только
    Parsing, разбор.
    Ответ написан
    Комментировать
  • А как реализуют всякие разархировщики файлов игр для модификаций?

    @Mercury13
    Программист на «си с крестами» и не только
    Сам я бросил ковырять игры давным-давно, и мои знания устарели. Но вот в старых играх, где упаковки ещё не было, я успешно распознавал кое-какие форматы. Но в целом задача состоит из двух: опознание формата архива и опознание формата файла в архиве.

    Архив, как правило, устроен просто (хотя разработчики могут зашифровать его, как в «Мафии»). Разжатие чаще всего делается каким-нибудь из стандартных алгоритмов типа Deflate или LZMA. В принципе, можно и игру дизассемблировать, если алгоритм необычный, но чаще всего нет нужды. Кстати, разжатие из-за того, что оно критично к скорости, не покрывают всякими там Denuvo.

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

    Для утилит используют любой доступный язык высокого уровня, чаще всего Си++.
    Ответ написан
    Комментировать
  • Как пишутся библиотеки для C++ и других ЯП?

    @Mercury13
    Программист на «си с крестами» и не только
    В 99,9% случаев — на языках высокого уровня. Как слой более низкого уровня используются три вещи.
    1. Стандартная библиотека языка.
    2. Внутреннее API ОС (WinAPI/POSIX/DOS).
    3. Чужие низкоуровневые библиотеки.

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

    Здесь под «низким уровнем» понимается «мало автоматизации», «очень тонкая прослойка между API операционной системы и нашим новым интерфейсом», «минимум управления памятью» — то есть функция, например, принимает не std::string, а указатель на нуль-терминированную строку const char*. И для написания библиотек любят языки, способные работать на низком уровне — в первую очередь Си, Си++ и Паскаль. Если нет ограничения по скорости, ассемблер не обязателен.
    Ответ написан
    1 комментарий
  • Как открыть порт на роутере? Комплексное решение?

    @Mercury13
    Программист на «си с крестами» и не только
    1. https://portforward.com/tp-link/tl-wr740n/
    www.pcwintech.com/port-forwarding-tp-link-tl-wr740...
    forum.tp-linkru.ru/viewtopic.php?t=9
    Но не забывайте, что это требует статического IP-адреса сервера, и лучше всего это сделать, прописав статическую зависимость MAC-IP. По третьей сцылке это есть.
    2. Гуглите UPnP. Посмотрите, допустим, вот. Использование UPnP C++
    3. Сам даже не знаю. Как-то само из кусочков понимание собралось. Правда, я в своё время налаживал локальные «сети» по COM- и LPT-кабелю. А потом по-чёрному резался в разные игры по интернету. Разумеется, тонкостей настройки больших сетей мне это не дало, но как ходят пакеты, примерно понимаю.
    Ответ написан
    2 комментария
  • Какие есть проблемы при работе генетических алгоритмов?

    @Mercury13
    Программист на «си с крестами» и не только
    3 = Сходимость к произвольной точке.
    4. Плохая сходимость.
    5. Не получается придумать качественную процедуру кроссинговера (её задача — поддерживать разнообразие популяции).
    Ответ написан
    Комментировать
  • Что означает "+" после регистра?

    @Mercury13
    Программист на «си с крестами» и не только
    Перед нами синтаксис ассемблера Intel.
    qword ptr [] — адрес восьмибайтовой переменной в памяти. Если конкретный — прямая адресация, если внутри какой-то регистр — косвенный.
    + — простая операция сложения.

    Перед нами косвенная адресация со смещением. То есть, берём содержимое регистра eax, прибавляем 80h, обращаемся по этому адресу и то, что получилось, загоняем в стек сопроцессора как double.

    ЗЫ. Подобный полный показ команд с ведущими нулями и без указателя 16-й системы (80h) обычно используется в дизассемблерных листингах.
    Ответ написан
    3 комментария
  • Нужно ли солить хеш длинного случайного сессионного ключа в БД?

    @Mercury13
    Программист на «си с крестами» и не только
    Для чего вообще солят хэши? Против сливов БД: если хэши ушли, по ним сложно восстановить пароли.
    • Если при подозрении на слив мы можем перегенерировать ключи или объявить их просроченными;
    • Если ключи держатся где угодно, только не в БД;
    • Если ключи настолько длинны и случайны, что сложновато будет обратить алгоритм объединёнными хакерскими силами
    — то зачем?

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