Задать вопрос
  • Как написать что-то в консоли?

    @Mercury13
    Программист на «си с крестами» и не только
    Итак, надо вызвать прогу и повзаимодействовать с ней. Кроссплатформенность нужна?

    Если работаем на чистом WinAPI, надо пробовать перенаправление потоков ввода-вывода.

    С повышением прав не работал: если повышение не нужно, или прога изначально работает под одминком, никаких вопросов, но ведь всякое бывает…
    Ответ написан
    Комментировать
  • Как записать это выражение?

    @Mercury13
    Программист на «си с крестами» и не только
    Добавлю от себя: десятичная система счисления справа не имеет смысла: нет такого понятия, как десятичный плюс. Слева — двоичная система счисления, справа — РОДНАЯ, в которой мы проводим расчёты, будь это двоичная, десятичная, фибоначчиева или просто чёрточки на песке.

    Перед нами самое обычное определение позиционной системы счисления. Слева индекс имеет смысл (мы указываем основание), справа не имеет (мы работаем в «родной» для нас системе).

    UPD. Мы, конечно, можем написать: (123 + 456)10, что значит: все числа в скобках в десятичной системе. Только в вашем примере в скобках нет ни многозначных чисел, ни сверхдесятичных систем счисления (B16=11), чтобы это имело какой-то смысл. Цифра два — она и в Африке два: мы договорились, что она значит || независимо от системы счисления. Если, конечно, не делать из неё многозначные числа.

    Да, на языке программирования вы записали правильно, хотя чаще на компьютерах используется схема Горнера:

    ((1) * 2 + 1) * 2 + 0

    Во многих языках есть запись 0b110.
    Ответ написан
    7 комментариев
  • Как архитектурно правильно организовать классы в игре на JS. (ООП)?

    @Mercury13
    Программист на «си с крестами» и не только
    Статические методы класса как раз для оперирования с несколькими экземплярами класса?

    Статические поля и методы служат для работы с классом в целом. Примеры:
    • Есть десять объектов и новых создавать нельзя.
    • Общий для всей проги объектный пул, а второго, скорее всего, не будет.
    • Псевдоконструктор — Rect.xyxy(x1,y1,x2,y2) и Rect.xywh(x,y,w,h).
    • Функциональность никак не зависит от экземпляра объекта: calculateDamageWithCrit при условии, что генератор случайных чисел тоже статический (принадлежит библиотеке языка в целом, а не игровому миру).

    Где правильно хранить экземпляры классов врагов?

    С Wave вы, вероятно, сами запутались: это то информация о волне, то часть текущего состояния мира. Я бы всех врагов закинул в Game (правда, назвал бы объект World).

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

    Башня принадлежит игровому миру — тоже её в Game (или World).

    У башни есть массив с пулями которые она выпускает.

    Пули очень не стоит в башню — их лучше в тот же Game/World. Башню вы уничтожаете — пули тоже исчезают?

    И эта вот функция просчёта у меня просто в файле. Нужно ли её загонять в класс как метод?

    Только для красоты. Не важно, где лежит скрытая функция, если она не зависит от экземпляра (типа-статическая) и скрытая (не видна снаружи).

    Важная штука: часто в играх есть неизменная информация о врагах, башнях, пулях (TowerType, EnemyType, BulletType, WaveInfo…), и есть конкретный экземпляр (Tower, Enemy, Bullet). Иногда враги, башни и пули объединяют в один GameObj, но это уже зависит от архитектуры. Возможно и так, и этак.
    Ответ написан
    6 комментариев
  • Отличие int32_t от std::int32_t?

    @Mercury13
    Программист на «си с крестами» и не только
    Никакого. int32_t — это из Си, std::int32_t — стандартное пространство имён Си++.
    Ответ написан
    Комментировать
  • Почему появляется лишний символ при открытии файла qt C++?

    @Mercury13
    Программист на «си с крестами» и не только
    А какой код генерации этих данных? Я пока вижу, что 8 байтов длины в формате Motorola (58), после этого 58 байтов данных. Мне интересно узнать, откуда взялся qword длины, и откуда — dword 6 в начале, тоже в формате Motorola?

    UPD. Пока подозреваю, что дело в SendBufferSizeSocketOption.
    Ответ написан
  • Как происходит управление перемещением программ в пользовательском пространстве?

    @Mercury13
    Программист на «си с крестами» и не только
    Программа туда не уместится, если не предусмотрено способа разбить её пополам. Перемещение происходит, если её адрес по умолчанию чем-то не нравится: или занят, или надо утрамбовать адреса плотнее (было важно в эпоху DOS), или…

    А пока — три важных ремарки.
    1. В пользовательском пространстве у нас 2 гигабайта или больше виртуальной памяти, и она условно «пуста»: в любых адресах этой памяти можно разместить что угодно. Но если мы обратимся к отсутствующей странице, получим аварийный останов — такова уж издержка виртуальности. Сначала надо обратиться к системному менеджеру памяти, и он выдаст рабочий диапазон адресов.
    2. Программа перемещается посегментно.
    3. Есть два главных способа перемещения программы: адресация от IP и relocations.

    Адресация от IP работает, понятное дело, если исходный и целевой адрес в одном сегменте. По какому адресу ни располагай сегмент — адреса от IP менять не надо. В x86, НЯЗ, она работает в одном-единственном случае: короткие переходы (±127 байтов). Ветвления все короткие, а если нужно ветвиться далеко — ответвляется на безусловный переход, который уносит далеко-далеко.

    В x64 режим адресации от IP есть во всех обращениях к памяти, переходах и вызовах, но только на ±2Г (точно не в курсе).

    Во всех версиях x86 базовый адрес при адресации от IP — это конец текущей команды, не начало.

    Relocations — это ремарки: сегмент 1 рассчитан на базовый адрес 12. Если он другой — подкорректируй адреса 34 и 56. Независимо от метода адресации — от IP или абсолютного. Если сегмент загрузился не по штатному адресу — например, 23 — к числам по адресам 34 и 56 прибавляем разницу 11. Скажем, было 78, стало 89.

    В архитектурах с сегментной памятью (x86-16) эта самая сегментная память — также метод перемещения программы. Старый добрый COM-файл имел абсолютные адреса, но только от начала текущего сегмента — и представлял собой исключительно машинный код, загружаемый по адресу не то 128, не то 256 (вот не помню). А перемещение его по памяти сводится к установке нужных значений в сегментные регистры SS/CS/DS/ES.
    (Да, *.COM не имел вообще никакого формата, это просто куча кода и данных, которая 1:1 грузится в память.)
    Ответ написан
    4 комментария
  • Почему имя параметра может совпадать с именем члена класса?

    @Mercury13
    Программист на «си с крестами» и не только
    Это НЕ синтаксический разбор, а семантика языка.
    В большинстве случаев играет роль ближайший идентификатор. Но в инициализаторах снаружи скобок поле объекта (больше ничего там быть не может, только поле)

    #include <iostream>
    
    class Obj {
    public:
        Obj(std::string x)
            : x(std::move(x))
            // 1. Поле, больше ничего быть не может
            // 2. Параметр, как ближайший идентификатор
        {
            std::cout << '[' << x << ']' << '\n';  // Параметр, как ближайший идентификатор
        }
    private:
        std::string x;
    };
    
    int main()
    {
        Obj obj("Habr");
        return 0;
    }
    Ответ написан
  • Есть ли технические причины тому, что у ноутбука с дисплеем 360Hz есть только режим 60 Hz и 360 Hz, но нет промежуточных?

    @Mercury13
    Программист на «си с крестами» и не только
    Если заработает — программных не должно быть. Из аппаратных — только шум на определённых режимах/изображениях, но это уже вопрос качества питающей обвязки. Чаще такое бывает на настольных мониторах, чем на ноутах.
    Просто прописывают список поддерживаемых режимов — в VGA на это пустили неиспользуемый штырь, где на ноутах, не знаю. Просто лень: или совместимые 60, или максимальные 360, на что нужны промежуточные?
    Ответ написан
    5 комментариев
  • Как генерировать случайные числа в вычислительной системе?

    @Mercury13
    Программист на «си с крестами» и не только
    Итак, задача — сгенерировать случайные числа по закону Гаусса.
    Если есть Си++11, копай модуль <random>.
    Если нет, простейший способ сгенерировать — F⁻¹(ξ), для этого есть бэ-мэ качественные приближения обратного распределения Гаусса.
    Есть также более «лёгкий» способ генерировать такие числа по два сразу, гугли.
    Ответ написан
    Комментировать
  • Как вшить .mp4 файл в .exe С++?

    @Mercury13
    Программист на «си с крестами» и не только
    На данный момент вы вызываете внешний плеер, причём не важно, какой — системный ассоциированный с расширением MP4. Не забудьте, что в такой ситуации внешнего плеера уже не будет, придётся налаживать свой.

    1. ОС-зависимые ресурсы (например, ресурсы Windows). Поскольку тут у вас и так WinAPI, этот способ вполне катит.
    2. Обёртка Qt или чего-то другого над этими ресурсами: где они есть, ресурсы, а где нет, простые массивы. Использовать, если и без того используете Qt.
    3. Склеить EXE-файл с MP4. Главное — придумать способ разделить их обратно (например, добавить четыре байта длины в конце).
    4. Преобразовать MP4 в байтовый массив, вставить в какой-то CPP.
    5. Вариант 4, но более быстрый в компиляции: Использовать ожидаемую функцию Си #embed.
    Ответ написан
    Комментировать
  • Как доказать, что если множество (G \ H) ∪ {1} — подгруппа G, то либо H = {1}, либо H = G?

    @Mercury13
    Программист на «си с крестами» и не только
    Обозначим обратный через x*, так писать проще.

    Берём элемент h∈H, ≠1 и другой g∉H, ≠1. Заметим, что:
    • h*∈H, ≠1, а g*∉H, ≠1
    • gh, hg, g*h и т.д. в любых сочетаниях ≠1.

    Вариант первый. x=gh∈H. Множим справа на h*, и получаем xh* = ghh* = g. Слева штуки из H, справа нет — H не замкнута.

    Вариант второй. x=gh∉H. Множим слева на g*, и получаем g*x = g*gh = h. Слева штуки из нашей подгруппы (G \ H) ∪ {1}, справа нет. Так что подгруппа явно не замкнута.

    Для полугрупп с единицей, о которых ты пытался говорить, это НЕ ТАК. Как известно, у любой конечной полугруппы есть идемпотент — тем лучше. Пусть G = B², H={00, 10}, операция — побитовое ИЛИ, E=00. Тогда множество (G\H)∪E={00,01,11} явно замкнуто относительно ИЛИ. (Я пытался вводить ажурные B и единицу, а система стирает.)
    Ответ написан
    Комментировать
  • Преобразование шрифта?

    @Mercury13
    Программист на «си с крестами» и не только
    Вот разбор строки.
    6638d576265ed231173995.png

    Совместимая декомпозиция NFKD (а лучше совместимая композиция NFKC) конкретно тут не поможет (не меняет ни одного символа), но в других случаях может улучшить жизнь.

    Затем тебе придётся работать с визуально сходными символами, и начинать надо отсюда.
    https://util.unicode.org/UnicodeJsps/confusables.jsp

    6638d67702c6c545558246.png

    Этого тоже мало, но вот с этого начинать надо.
    Ответ написан
    Комментировать
  • Как переделать код согласно современным стандартам?

    @Mercury13
    Программист на «си с крестами» и не только
    Вы с неинициализированной памятью работаете почти правильно, но…

    Первое. Надо указать выравнивание класса.
    MyClass* arr = (MyClass*) operator new (sizeof(MyClass) * 10,
                                            std::align_val_t(alignof(MyClass)));
    . . .
    operator delete(arr, std::align_val_t(alignof(MyClass)));


    Второе. А нельзя инкапсулировать подобную работу с памятью в класс, чтобы конструктор выделял память и деструктор отдавал? Я сделал вот такое.
    #include <iostream>
    
    class MyClass {
    private:
        const int a;
    public:
        MyClass() = delete;
        MyClass(MyClass&&) = delete;
        MyClass(const MyClass&) = delete;
        MyClass(int a) : a(a) {};
        ~MyClass() = default;
        MyClass& operator=(MyClass&&) = delete;
        MyClass& operator=(const MyClass&) = delete;
        operator int() const { return a; }
    };
    
    template <class T>
    class DynArray {
    public:
        static constexpr std::align_val_t ALIGNMENT { alignof(T) };
        DynArray (size_t n)
            : maxSize(n),
              d((T*) operator new (sizeof(T) * n, ALIGNMENT )) {}
        ~DynArray() {
            std::destroy_n(d, currSize);
            operator delete(d, ALIGNMENT);
        }
        template <class... Args>
            T& add(Args&&... args);
        T& operator [] (size_t i) { return d[i]; }
        const T& operator [] (size_t i) const { return d[i]; }
    private:
        size_t currSize = 0, maxSize = 0;
        T* d;
    };
    
    template <class T> template <class... Args>
    T& DynArray<T>::add(Args&&... args)
    {
        if (currSize >= maxSize)
            throw std::logic_error("[DynArray::add] Overflow");
        auto& where = d[currSize++];
        new (&where) MyClass(std::forward<Args>(args)...);
        return where;
    }
    
    int main() {
        DynArray<MyClass> da(10);
    
        for (int i = 0; i < 10; ++i) {
            da.add(i);
        }
    
        // Что-то сделали с массивом
        for (int i = 0; i < 10; ++i) {
            std::cout << da[i] << '\n';
        }
    
        return 0;
    }


    Ну и третье — в коде есть, но забыл указать — разбирайте API неинициализированной памяти Си++17.

    ЧЕТВЁРТОЕ. Есть один класс, который не перемещает. Поскольку начиная с Си++17 весь STL внутри работает с неинициализированной памятью, получается довольно мило — но хранится ли оно непрерывно, мы никак не узнаем.
    std::deque<MyClass> dq;
        for (int i = 0; i < 10; ++i) {
            dq.emplace_back(i + 42);
        }
        // Что-то сделали с массивом
        for (int i = 0; i < 10; ++i) {
            std::cout << dq[i] << '\n';
        }
    Ответ написан
    2 комментария
  • Как установить цвет пикселю, если ранее у него не был установлен цвет?

    @Mercury13
    Программист на «си с крестами» и не только
    Я бы не советовал работать прямо через TPngImage. Но если уж решили — надо смотреть канал прозрачности. Что-то вроде:
    case picture.TransparencyMode of
    ptmNone: ; // порядок, ничего не делаем
    ptmBit: // если есть такие PNG — ну, придумайте сами, чё делать
                // Всё через тот же AlphaScanLine
      raise Exception.Create('1-bit transparency unsupported');  // вроде так? — давно не паскалил
    ptmPartial: AlphaScanline[y]^[x] := 255;
    end;


    Надо признаться, «амбаркадебра» известна яростной скупкой открытых компонентов, и я даже нарывался на известные ошибки известных открытых компонентов прямо в оболочке Delphi.
    Ответ написан
  • Почему переменная становится равна 1, если после инициализации класса она была равна 3?

    @Mercury13
    Программист на «си с крестами» и не только
    Вы используете одноимённую локальную переменную в MainProgram().
    MainProgram::m_command_file_len должно равняться нулю ЧЕМУ ПОПАЛО, потому что его никто не трогал.

    UPD. Вы ещё и неправильно используете венгерскую нотацию: префикс f, m или _, оставленный для внутренних переменных, почему-то забрался в локальную.
    Ответ написан
    1 комментарий
  • Как изменить часть файла в zip архиве?

    @Mercury13
    Программист на «си с крестами» и не только
    Возможно, но для этого надо вмешиваться как в процесс доступа к архиву, так и в процесс сжатия. Вот примерно так.
    ZEXTERN int ZEXPORT deflateParams(z_streamp strm,
                                      int level,
                                      int strategy);

    Штука в том, что ключевые байты надо держать несжатыми.

    UPD. Если хотите, чтобы не нарушать NDA, я возьму что-то общедоступное вроде Zippy и попробую написать прототип. Но только если хотите.

    UPD2. Блин, забыл про CRC! Его тоже придётся как-то пересчитывать.
    Ответ написан
    7 комментариев
  • Как определить сложность алгоритма?

    @Mercury13
    Программист на «си с крестами» и не только
    У нас два вложенных цикла, каждый порядка n.
    Значит, O(n)·O(n) = O(n²), если не докажем меньше.
    Не докажем, там обычная арифметическая прогрессия, которая что-то вроде n(n—1)/2.
    Ответ написан
    Комментировать
  • Что это за файл и синтаксис?

    @Mercury13
    Программист на «си с крестами» и не только
    Это файл местной консоли. Файл устроен на манер командного: каждая строчка — это отдельная команда для игрового интерпретатора.

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

    Вторая — самые настоящие команды консоли. Quake очень популяризовал внутреннюю консоль игры.
    Ответ написан
  • Соблюдается ли лицензионная чистота при работе с QT?

    @Mercury13
    Программист на «си с крестами» и не только
    Само понятие «открытое ПО» как раз выступает против таких ограничивалок.
    Я полагаю, какие-нибудь крючкотворцы найдут в десяти заповедях двенадцать лазеек, но в целом все открытые лицензии выступают против того, чтобы кому-то ограничивать свободу. Не бывает лицензии LGPL для правильных людей.
    Ответ написан
    Комментировать
  • Почему не существует не итерационных/точных методов для вычисления корня из числа?

    @Mercury13
    Программист на «си с крестами» и не только
    Всё крайне просто.
    Потому что, начиная с рационального числа и проводя четыре арифметических действия, +−×: , мы будем оставаться в поле рациональных чисел. А корень в большинстве случаев иррациональный.
    Мы можем получить лишь рациональное число, достаточно близкое к нашему корню.
    И все «нормальные» методы вычисления корня работают так: если ещё немного повычислять, можно получить более точный корень. То есть итерационные.

    Пример НЕитерационного метода предложили Ын, Уолш и Таролли, но более он известен по игре Quake III: придумать приближение логарифма, разделить на 2 и обратить это самое приближение. Но этот метод не масштабируем: если точности не хватает, придётся брать в руки какой-нибудь метод Ньютона и дотягивать точность. Ну или придумывать более точное приближение логарифма — исходное было всего лишь прочтением компьютерного дробного как целого числа. То есть придётся рубить его на мантиссу и порядок, порядок брать как есть, а мантиссу преобразовывать каким-то многочленом (если читать дробное как целое, то наш многочлен — банальная линейная функция, log₂(1+x)≈x).

    А лучше порядок превратить в несмещённый, поделить надвое, вернуть опять к смещённому, и остаётся только найти приближение — многочленом или таблицей — для x∈[1,4).

    Другой НЕитерационный алгоритм — банальная таблица. Каким-то раком предвычислить таблицу, а то, что в таблицу не попадает, приблизить любым доступным методом, да хоть линейной интерполяцией или многочленами Эрмита.
    Ответ написан
    Комментировать