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

    @Mercury13
    Программист на «си с крестами» и не только
    1. Что такое Container и для чего он нужен? Возможно, от этого дела удастся избавиться или заменить интерфейсом?
    2. Не должен конструктор Graph брать в параметры Parser. Наоборот, Parser функцией parse() должен возвращать Graph.
    3. Config стоит разбить на несколько частей: одна специфична для Graph, вторая для Parser. Как их объединять — зависит от того, кому какие настройки нужны.
    Ответ написан
    2 комментария
  • Есть ли разница между двумя функциями?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Будьте осторожны, перед нами динамический массив, сделанный расширением стека. Не на всех компиляторах есть, плюс стек ограничен парой мегабайт.
    Нормализацию размера лучше сделать shift %= size;
    Подпрограмма работает с локальной переменной и всё, что она делает, идёт на экран и больше никуда.
    (вообще стоит разделять обработку и вывод!)
    Время работы size.

    2. Сдвигаем на один элемент нужное количество раз. Время работы shift·size.

    3. Как за size «на месте»…
    квоПрох := НОД(shift, size)
    для i = [0..квоПрох)
      i1 := i
      tmp := a[i]
      вечный цикл
        i2 := (i1 + shift) % size
        если i2 = i
          прервать вечный цикл
        a[i1] := a[i2]    
        i1 := i2
      a[i1] := tmp
    Ответ написан
    Комментировать
  • Как создать "библиотеку" для NPC на языке C++?

    @Mercury13
    Программист на «си с крестами» и не только
    Из такого вопроса видно, что человек всё ещё нетвёрдо знает программирование, а уже пытается программить игру.
    И тут есть два варианта.

    1. Движок с нуля. Тонкая графическая прослойка наподобие SDL, оставляющая 100%-ю свободу движкописателям — это тоже «с нуля» и всячески рекомендуется даже продвинутым (не нужно писать всякие там Alt-Tab’ы и прочую дрянь, далёкую от игры). Тогда пусть начнёт с «питончика» (https://ru.wikipedia.org/wiki/Snake_(игра) ) или текстового квеста.
    А потом, когда доберётся до платформера или CRPG, он поймёт, каким образом привязать к монстру характеристики.

    Первое приближение (не слишком удобное для скриптования и подходящее для платформеров/action-RPG, но негодное в настоящих RPG) — сделать каждому компьютерному персонажу «класс» (не путать с классом ООП), включающий кол-во HP, внешний вид и прочее. А также «набор скриптов» — для поведения в диалогах, запрограммированного передвижения, превращения из «болванчика» в компьютерного врага, и т.д. Без набора скриптов он просто компьютерный враг, тупо нападающий на ПиСя.

    Если скриптовый движок чужой (тут уже не зазорно брать чужое) — вы уж смотрите, что он может и куда его впихнуть. А если хотите написать сами — лучше делайте триггеры, как в StarCraft.

    2. На чужом движке. Это уж смотрите, что движок может, какие возможности в нём «в коробке», а какие придётся дописывать своим кодом и чужими модулями. Не знаком ни с одним. Чужой движок — довольно противное дело для начинающего программиста: он автоматически формирует какую-то структуру программы, и программисту приходится не столько творить, сколько разбираться с этой структурой. С одной стороны, можно быстро написать довольно сложную игру, с другой — не так много радости «а у меня заработало».
    Ответ написан
    Комментировать
  • Как реализовать метод буквенного номера по числу?

    @Mercury13
    Программист на «си с крестами» и не только
    Вот мой действующий код на «Си с крестами». Индексы — ВНИМАНИЕ — начинаются с нуля. Сумеете перевести на Яву, и из второго оставить одни буквы? Первое действует для любой длины, второе — для длины до 3 символов, присущей Excel’ю.

    std::wstring xl::colNameW(
            size_t aIndex)
    {
        wchar_t q[21];  // more than enough even for 64-bit system :)
        wchar_t* ptr = q + 20;
        *ptr = 0;   // debug
    
        // Getting size
        size_t n = 1;
        unsigned long long pw = 26;
        while (aIndex>=pw && n<20)
        {
            aIndex -= static_cast<size_t>(pw);
            pw *= 26;
            ++n;
        }
    
        FOR_S(i, 0, n)  // макрос, означающий for (size_t i = 0; i < n; ++i)
        {
            *(--ptr) = static_cast<wchar_t>(L'A' + (aIndex % 26));
            aIndex /= 26;
        }
        return std::wstring(ptr, n);
    }
    
    namespace {
    
        bool isCap(const char* x, const char* aEnd)
        {
            return (x != aEnd && *x >= 'A' && *x <= 'Z');
        }
    
        bool isDig(const char* x, const char* aEnd)
        {
            return (x != aEnd && *x >= '0' && *x <= '9');
        }
    
    }   // anon namespace
    
    
    xl::CellCoords xl::parseCellCoords(
            const char* aStart, const char* aEnd)
    {
        enum {
            AA = 26,
            AAA = 26 + 26 * 26
        };
        xl::CellCoords r;
        // Letter
        r.col = 0;
        if (!isCap(aStart, aEnd))
            return CellCoords::bad();
        r.col = *(aStart++) - 'A';
        if (isCap(aStart, aEnd)) {
            r.col = (r.col * 26) + *(aStart++) - 'A';
            if (isCap(aStart, aEnd)) {
                r.col = AAA + (r.col * 26) + *(aStart++) - 'A';
            } else {
                r.col += AA;
            }
        }
        // Number
        r.row = 0;
        while (isDig(aStart, aEnd)) {
            size_t r0 = r.row;
            r.row = r.row * 10 + *(aStart++) - '0';
            if (r.row < r0)
                return CellCoords::bad();
        }
        if (r.row == 0 || aStart != aEnd)
            return CellCoords::bad();
        --r.row;
        return r;
    }


    Принцип действия перевода цифра → буква.
    Находим, сколько букв в нашей колонке. Допустим, три. Вычитаем из цифры номер колонки AAA (т.е. 26 + 26·26, если нумеровать с нуля, и 1 + 26 + 26·26 — если с единицы), и оставшееся переводим в 26-ичную систему счисления (A=0, B=1, C=2…).

    Принцип действия перевода буква → цифра аналогичен. Находим количество букв. Если их три, то переводим из 26-ичной системы счисления в цифру и прибавляем номер колонки AAA.
    Ответ написан
    Комментировать
  • Возникает ошибка Ошибка C4700 использована неинициализированная локальная переменная как исправить?

    @Mercury13
    Программист на «си с крестами» и не только
    #include "stdio.h"
    #include "stdlib.h"

    Лучше это писать в угловых скобках.

    double dr(double zb)
    {
        return zb = (rand() % 100) / (100 * 1.0);
    }

    Присваиваем параметру zb что-то, чтобы его похѣрить? Параметр будет жить до конца функции и НЕ ВЕРНЁТСЯ в вызвавшую программу (параметры передаются по копии).
    Кстати, параметр zb ни на что не используется: что бы вы ни передали туда снаружи, подпрограмма в этот параметр не посмотрит.

    printf("%lf", dr(double zb));
    На G++ не скомпилировалось. Ну, написал dr(0), благо параметр не используется ни на что.

    if (d == e)
    {
        printf("Win! your cash:%lf", winWay(a, b));

    C:\TestApps\ErrUninitLocal\main.cpp|30|warning: 'd' may be used uninitialized in this function [-Wmaybe-uninitialized]|
    А действительно, переменная d нигде никому не присваивается.

    И ещё одно. Я не знаю, как действует Visual C, но модификатор l для формата %f нужен для scanf, но не нужен для printf. Вот так-то всё это дело устроено.

    double a = winWay(a, b);
    }

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

    C:\TestApps\ErrUninitLocal\main.cpp|33|warning: 'a' may be used uninitialized in this function [-Wmaybe-uninitialized]|
    Тут вообще забавно работает. double a — считаем, что a определилась. = winWay(a, b) — считаем, что используется ОНА ЖЕ, а не более ранняя a. Естественно, неинициализированная.

    (аналогично с loseway)
    C:\TestApps\ErrUninitLocal\main.cpp|38|warning: 'a' may be used uninitialized in this function [-Wmaybe-uninitialized]|
    Ответ написан
    Комментировать
  • Как вернуть ссылку/указатель на элемент вектора?

    @Mercury13
    Программист на «си с крестами» и не только
    1.
    bool FindElement(const string& search, CElement*& result);

    2. CElement* FindElement(const string& search);
    Ответ написан
    1 комментарий
  • Что такое безсерверная обработка данных?

    @Mercury13
    Программист на «си с крестами» и не только
    Название странное. Это когда облачная платформа выделяет не сервер (виртуальную машину, контейнер), а какую-то функцию, и на каких серверах она работает — не важно.
    https://en.wikipedia.org/wiki/Serverless_computing
    Ответ написан
    Комментировать
  • Что такое 3D математика?

    @Mercury13
    Программист на «си с крестами» и не только
    Векторная алгебра (ну или векторная геометрия) в 3D.
    Векторы, матрицы, базисы, однородные координаты, видовые преобразования, кватернион поворота…
    Первый курс университета, покрывается курсом «Линейная алгебра и аналитическая геометрия».
    Дизайнеру не нужно.
    Ответ написан
    4 комментария
  • Нужно ли создавать интерфейсы для одного класса?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Если из класса можно вытащить какую-то абстракцию. Например, из объекта «файл» можно вытащить абстракцию «поток». Личное — объект Project реализует интерфейс Modifiable с двумя функциями: modify() и isModified().

    2. Для упрощения юнит-тестирования при условии владения.
    Предположим, у нас есть класс «класс» (школьный) и класс «ученик». Ученик знает, в каком он классе.
    В такой ситуации получается «клубок»: если надо делать ученика, то надо делать и класс.
    Этот замкнутый круг можно разорвать, сделав интерфейс ISchoolClass и унаследовав от него класс. При юнит-тестировании заменяем класс на какую-то заглушку.
    Ответ написан
    Комментировать
  • Можно ли организовать связь между QT, mySQL и Excel?

    @Mercury13
    Программист на «си с крестами» и не только
    Qt и MySQL работают отлично и очень быстро. Маленькая подсказка: помимо DLL драйвера, который надо бросить в подкаталог plugins\sqldrivers, надо положить в РАБОЧИЙ каталог программы DLL MySQL или MariaDB (зависит от сборки Qt).

    С Excel’ем сложнее, и приходится искать любую Excel-библиотеку, имеющуюся на Си++.
    Из открытых — XLNT (кроссплатформенный) и QtXlsx (привязан к системе классов Qt).
    Мы используем частично LibXL (платный, тормозной, огромный расход памяти, но QtXlsx ещё хуже, насколько я проверял), частично свой велосипед (минимум функциональности, оптимизирован под огромные XLSX — вплоть до того, что Excel берёт большую таблицу за 10 секунд, а мы за три, а LibreOffice вообще над ней размышляет минутами).

    Но это уже собственно вопрос: а что есть для Excel’я на Си++. Может, сырой XLNT довели до ума. Может, у вас нет огромных таблиц, и того, что есть, вам хватает…

    UPD. Есть разные сборки DLL MySQL, так что придётся экспрериментировать, чтобы работало не только на разработческой машине, но и у потенциального юзверя.
    Ответ написан
    Комментировать
  • Как удалить часть строки в c++?

    @Mercury13
    Программист на «си с крестами» и не только
    Так и надо, но не хватает только одного: каким-то образом обрезать строку после всего этого.
    for (…)
      s1[i] = s1[i + s2len]
    s1.resize(s1.length() - s2len);

    Не забывайте: если длина вашей строки — это strlen, то length() в цикле вызывать запрещено!

    Да, ещё вопрос: убрать ПЕРВОЕ вхождение или ВСЕ вхождения?
    Ответ написан
  • Как нарисовать на курсоре в RunTime?

    @Mercury13
    Программист на «си с крестами» и не только
    Попробуйте Brush.Color := $FF000000 or clBlue;. Велика вероятность, что механизмы работы с 32-битными изображениями тут слабоваты.
    Ответ написан
    1 комментарий
  • Как подключиться к глобальному интернету Маска?

    @Mercury13
    Программист на «си с крестами» и не только
    Потребуется специальная антенная решётка. По предварительным расчётам, она будет по размеру с коробку от пиццы. Пока выведены два спутника, она вряд ли где-то продаётся.
    И предварительная стоимость — 50$/мес — негуманная для страны, где интернет один из лучших в мире (ой, если бы ещё не роскомнадзоры и их украинские аналоги).

    (Долго вспоминал, как называется крупная спутниковая сеть голосовой связи — Iridium. Удивительно, что она ещё работает и для работы полагается именно что на Маска.)

    Нашёл.
    https://www.reddit.com/r/Starlink/comments/7zqm2c/...
    Ответ написан
    2 комментария
  • Как понимать алгоритмы?

    @Mercury13
    Программист на «си с крестами» и не только
    Есть три специфичных вида алгоритмов.
    • Математические. Из них я могу припомнить геометрические (выпуклая оболочка) и вычислительные (метод Рунге-Кутты).
    • Связанные с особыми структурами данных.
    • Параллельные.

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

    Из общего — те части математики, которые служат основополагающими принципами работы компьютеров. Теория множеств, булева алгебра, комбинаторика, теория автоматов… Также важно изучить символы Ландау и понятие «асимптотическая сложность алгоритма».

    Для параллельных важно понимать архитектуру параллельных систем.
    Ответ написан
    Комментировать
  • Как скомпилировать QWT готовым Qt 5.10 MinGW-w64 Dynamic?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    Например, можно скомпилировать прямо через Qt Creator.
    Ответ написан
    Комментировать
  • Как получить нужную точность при умножении и делении чисел типа double?

    @Mercury13
    Программист на «си с крестами» и не только
    Дело в том, что 4,2 и 4,3 невозможно представить в виде double. И система, например, сохраняет 4,3 в виде 4,2999999, которое при умножении на 10 станет 42,999999.
    Нужно убедиться, что при преобразовании double → int происходит round, а не усечение.
    Ответ написан
    2 комментария
  • Насколько отвратителен данный код?

    @Mercury13
    Программист на «си с крестами» и не только
    Главная проблема.
    const char *source = fmt::format("/tmp/{}.ini", unid).c_str();

    Объект fmt::format сразу же исчезнет, и source будет «висеть».

    Придётся писать…
    fmt::format fmSource("/tmp/{}.ini", unid);
    const char *source = fmSource.c_str();

    И так далее.
    Ответ написан
    8 комментариев
  • Почему не работает код (c)?

    @Mercury13
    Программист на «си с крестами» и не только
    https://ru.wikipedia.org/wiki/Условия_Йоды
    Аж в двух местах.

    Причём в Си не нужно ставить в сложных условиях скобки, как в Паскале, вполне покатит такое…
    if ((a >= 11 && a <= 14) || m == 0 || (m >= 5 && m <= 9))

    Но нет, вы наставили лишних скобок и заглушили ошибку.

    Также, что мне не нравится.
    Вместо 0,1,2,3 лучше использовать константы MANY/FEW/ONE/UNKNOWN.

    В case 1 символ подстановки плохо содран с доски.

    Если условие на MANY самое сложное и выполняется по остаточному принципу — почему его делаем самым первым? Лучше что-то типа…
    • 10…20 → MANY
    • 1 → ONE
    • 2…4 → FEW
    • Иначе MANY
    Ответ написан
    Комментировать
  • В чем причина некоректного отображения текста во всех браузерах?

    @Mercury13
    Программист на «си с крестами» и не только
    Что-то заглючило или в файле шрифта Arial, или в библиотеках Direct2D. И Blink, и «рыжая» используют DirectWrite, если он есть (у вас 10, он точно есть). У Edge свой шрифтовой движок. Разумеется, нужно восстановить соответствующие файлы.
    Больше грешу на шрифт Arial: всё, что вы показываете как ошибку, выведено именно этим шрифтом. Если у вас SSD, заодно проверьте его SMART.
    UPD. Может быть, не сам шрифт виноват, а кэш шрифтов. Прежде надо попробовать это. https://winaero.com/blog/rebuild-font-cache-windows-10/
    Ответ написан
  • Какой формулой определить где находится персонаж - за другим персонажем, перед, справа-слева и тд.?

    @Mercury13
    Программист на «си с крестами» и не только
    Считаем, что у нас FPS, т.е. есть некая абсолютная «горизонталь». Обычно в таких играх взгляд хранится через углы (yaw, pitch, roll).
    Взад-вперёд: знак скалярного произведения двух векторов: единичного вектора взгляда без учёта тангажа (cos(yaw), sin(yaw)) и вектора на персонажа (x1−x0, y1−y0).
    Влево-вправо: знак косого произведения той же пары векторов.
    Вверх-вниз: и так понятно.
    Все три в одних единицах, и у кого модуль больше, то и пишем: сверху, справа и т.д. Возможно, придётся сделать скидку на рост персонажей и их диаметр.

    В играх типа Descent нет верха и низа, горизонтали и вертикали. Верх и низ есть только относительно кабины нашего аппарата, а взгляд хранится в виде ортонормированной матрицы, куска этой матрицы или кватерниона.
    1) Скалярное произведение единичного 3D-вектора взгляда (обычно в таких играх хранится напрямую или считается через кватернион поворота) и 3D-вектора на персонажа.
    2) Скалярное произведение единичного вектора, который смотрит вбок (если такой есть), и вектора на персонажа. Либо смешанное произведение единичного вектора взгляда, единичного вектора макушки и вектора на персонажа.
    3) Скалярное произведение единичного вектора макушки и вектора на персонажа.

    Смешанный случай — с переменным вектором гравитации (в глобальных авиасимуляторах или играх на астероидах) — распиши сам.
    Ответ написан
    Комментировать