• Графическая библиотека для C++?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Судя по всему, вы про винду спрашиваете. Надо использовать всякие виндовые апи. Помимо GDI+ есть возможность работы через DirectX (c Win8) и WindowsGraphicsCapture (с Win10). С этим можно получать скриншот в текстурах. Потом можно прям на GPU их с шаблонами сравнивать, что будет на порядки быстрее работы с отдельными пикселями.
    Ответ написан
    2 комментария
  • Почему такая ошибка странная?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Похоже линкер не может найти библиотеку xbase. У вас в коде указана pragma xbase32.lib, но видимо этого не достаточно. Пропишите в ключах компилятору где искать эту xbase.

    edit: ошибка говорит, что линкер не может найти определение перегруженного метода << для вывода xb::xbString в cout.
    Ответ написан
    Комментировать
  • Алгоритм построения многоугольника из исходного квадрата и пересекающих его линий?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Для начала, надо бы уточнить условие. Ибо непясно, по какому принципу выбирается, какая из двух отсекаемых прямой половин берется в ответ.

    Картинке удовлетворяет такая интерпретация: Берется область, остекаемая прямыми, содержащая центр квадрата. Предполагаем, что прямые через центр не проходят.

    Тогда каждая прямая задает полуплоскость допустимых точек, да и сам квадрат можно задать 4-мя такими полуплосокстями и вам надо найти пересечение всех их.

    Эта задача решается за O(n log n). Задайте каждую прямую в виде ax+by+c=0. Т.ч. вектор {a,b} выпущенный с прямой, торчит в сторону полуплоскости, которую надо взять. Если вдруг не так, то надо поменять знак у всех трех коэффициентов.

    Разбейте все прямые на 2 множества, те - которые смотрят "вверх" и те, которые смотрят "вниз". Если вектор нормали имеет положительную y координату - это смотрит вверх. Вертикальные прямые можно включить, допустим, в верхнее множество.

    В каждом множестве построим ломанную, отделяющую нужную область. Это будет выпуклая область с двумя бесконечными лучами в конце.

    Потом отсортируйте все прямые по углу наклона вектора {a,b}. Это можно сделать без тригонометрии, сравнивая векторы по векторному произведению. Ну, или просто какую-нибудь функцию вроде atan2() используйте.

    Потом будем поддерживать ломанную, описывающую пересечение первых k проуплоскостей. Изначально это просто одна прямая (для первой полуплоскости). Будем хранить это как стек из прямых и рядом стек из точек пересечения. Изначально там только одна прямая и 0 точек пересечения.

    Потом добавляем полуплоскости по одной. Пока последняя вершина на ломанной не лежит в нужной полуплоскости, выбрасываем ее. Для этого убираем из обоих стеков последний элемент. Это можно проверить, просто подставив координаты точки в уравнение ax+by+c. Если даст отрицательное значение - выбрасываем.
    Если точек не осталось, или точка лежит где надо, то новую прямую надо пересечь с последней прямой. Точку пересечения и новую прямую добавляем в стек.

    В конце мы получили две ломанные, огибающие нужное пространство сверху и снизу. Надо их пересечь.
    Для этого выкинием сверхней ломанной все крайние точки, которые отсекаются последней и первой прямой в нижней ломанной. И наоборот. В конце, пересечения двух бесконечных лучей слева и справа добавляем в ответ.
    Ответ написан
    Комментировать
  • Безопасен ли сайт paimon.moe?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Проблема этой команды в том, что она отключает все системы безопасности, потом запускает скрипт из интернета по ссылке. Этот скрипт может и измениться в будущем. Т.ч. даже если оно безопасно прямо сейчас, оно может использоваться для кражи всего в любой момент.

    Код по ссылке сейчас вроде не делает ничего страшного. Он проверяет какой-то файл, вероятно, принадлежащий Геншину, берет оттуда какие-то URL адреса, делает к ним запросы, и на основе ответов выбирает какой-то url, который и выдает вам и просит вставить на paimon.moe.

    Я бы посоветовал не запускать вот ту команду, что вам дают, а использовать вот этот код, который я по ссылке проверил. Сохраните это как genshin.ps1 и запускайте потом его.

    Ну и, поскольку скрипт делает какие-то запросы к сайту геншина, вас могут теоретически забанить, ибо разработчики это могут видеть у себя на серверах.
    Add-Type -AssemblyName System.Web
    
    $logLocation = "%userprofile%\AppData\LocalLow\miHoYo\Genshin Impact\output_log.txt";
    $logLocationChina = "%userprofile%\AppData\LocalLow\miHoYo\$([char]0x539f)$([char]0x795e)\output_log.txt";
    
    $reg = $args[0]
    $apiHost = "hk4e-api-os.hoyoverse.com" 
    if ($reg -eq "china") {
      Write-Host "Using China cache location"
      $logLocation = $logLocationChina
      $apiHost = "hk4e-api.mihoyo.com"
    }
    
    $tmps = $env:TEMP + '\pm.ps1';
    if ([System.IO.File]::Exists($tmps)) {
      ri $tmps
    }
    
    $path = [System.Environment]::ExpandEnvironmentVariables($logLocation);
    if (-Not [System.IO.File]::Exists($path)) {
        Write-Host "Cannot find the log file! Make sure to open the wish history first!" -ForegroundColor Red
    
        if (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {  
            Write-Host "Do you want to try to run the script as Administrator? Press [ENTER] to continue, or any key to cancel."
            $keyInput = [Console]::ReadKey($true).Key
            if ($keyInput -ne "13") {
                return
            }
    
            $myinvocation.mycommand.definition > $tmps
    
            Start-Process powershell -Verb runAs -ArgumentList "-noexit", $tmps, $reg
            break
        }
    
        return
    }
    
    $logs = Get-Content -Path $path
    $m = $logs -match "(?m).:/.+(GenshinImpact_Data|YuanShen_Data)"
    $m[0] -match "(.:/.+(GenshinImpact_Data|YuanShen_Data))" >$null
    
    if ($matches.Length -eq 0) {
        Write-Host "Cannot find the wish history url! Make sure to open the wish history first!" -ForegroundColor Red
        return
    }
    
    $gamedir = $matches[1]
    # Thanks to @jogerj for getting the latest webchache dir
    $webcachePath = Resolve-Path "$gamedir/webCaches"
    $cacheVerPath = Get-Item (Get-ChildItem -Path $webcachePath | Sort-Object LastWriteTime -Descending | Select-Object -First 1).FullName
    $cachefile = Resolve-Path "$cacheVerPath/Cache/Cache_Data/data_2"
    $tmpfile = "$env:TEMP/ch_data_2"
    
    Copy-Item $cachefile -Destination $tmpfile
    
    function testUrl($url) {
      $ProgressPreference = 'SilentlyContinue'
      $uri = [System.UriBuilder]::New($url)
      $uri.Path = "event/gacha_info/api/getGachaLog"
      $uri.Host = $apiHost
      $uri.Fragment = ""
      $params = [System.Web.HttpUtility]::ParseQueryString($uri.Query)
      $params.Set("lang", "en");
      $params.Set("gacha_type", 301);
      $params.Set("size", "5");
      $params.Add("lang", "en-us");
      $uri.Query = $params.ToString()
      $apiUrl = $uri.Uri.AbsoluteUri
    
      $response = Invoke-WebRequest -Uri $apiUrl -ContentType "application/json" -UseBasicParsing -TimeoutSec 10 | ConvertFrom-Json
      $testResult = $response.retcode -eq 0
      return $testResult
    }
    
    $content = Get-Content -Encoding UTF8 -Raw $tmpfile
    $splitted = $content -split "1/0/"
    $found = $splitted -match "e20190909gacha-v2"
    $link = $false
    $linkFound = $false
    for ($i = $found.Length - 1; $i -ge 0; $i -= 1) {
      $t = $found[$i] -match "(https.+?game_biz=)"
      $link = $matches[0]
      Write-Host "`rChecking Link $i" -NoNewline
      $testResult = testUrl $link
      if ($testResult -eq $true) {
        $linkFound = $true
        break
      }
      Sleep 1
    }
    
    Remove-Item $tmpfile
    
    Write-Host ""
    
    if (-Not $linkFound) {
      Write-Host "Cannot find the wish history url! Make sure to open the wish history first!" -ForegroundColor Red
      return
    }
    
    $wishHistoryUrl = $link
    
    Write-Host $wishHistoryUrl
    Set-Clipboard -Value $wishHistoryUrl
    Write-Host "Link copied to clipboard, paste it back to paimon.moe" -ForegroundColor Green
    Ответ написан
  • C++: Как ускорить этот многопоточный код?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    А вы не добавляйте все в один список сразу. Пусть каждый поток использует свой список. Наверно, стоит заветси массив списков и использовать номер потока как индекс в массиве - в тот список ответ и добавляйте.

    В самом конце можно списки объединить. Последовательно. Или с критической секцией. Каждый поток должен получить первый и последний элемент списка. За две операции добавить список к глобальному и изменить последний элемент в глобальном списке. Ну, это если std::list использовать.

    Вообще, если один раз в конце собирать все ответы, то можно их и в vector в критической секции складывать. Это все займет не больше времени, чем один раз ответ вывести.
    Ответ написан
    2 комментария
  • Как реализовать побитовый сдвиг чисел, которые записаны как строки ( длинные числа хранятся в строках)?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Из комментариев понятно, что это вы так пытаетесь умножение двух длинных чисел через сдвиги реализовывать. Соответственно, у вас сдвиги тоже длинные.

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

    Основной цикл будет вроде
    for (int i = 0; i < a.length(); ++i) {
      for (int j = 0; j < b.length(); ++j) {
         c[i+j] += a[i] * b[j];
      }
    }


    В этом коде i+ - это и есть сдвиг. a[i] - это цифра на которую приходится домножать. а b[j] - это собственно само сдвигаемое и прикладываемое число.
    Ответ написан
    Комментировать
  • Как защитить программу от копирования без интернета?

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

    Активация ключа по телефону/интернету исключает лишь самый тривиальный способ "взлома" - просто копирование одной и той же лицензии по куче компьютеров без модификации исполняемых файлов.

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

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Во-первых, дополните минимум нулями слева, чтобы две строки были одинаковой длины.

    Потом генерируйте посимвольно, считая, какие значения текущая цифра может принимать. Смотрите, если где-то вы сгенерируете цифру меньше maximum, то дальше может быть вообще что угодно. Ваше сгенеренное число уже меньше максимума. Так же с минимумом. Поэтому, поддерживайте 2 флага: "сгенрированная строка уже меньше максимума" и "сгенерированная строка уже больше минимума". Каждый следующий символ не должен превосходить цифру в максимуме, если не первый флаг. Также он не должен быть меньше минимума, если не второй флаг.

    Что-то вроде этого:
    bool smaller_than_max = false;
    bool bigger_than_min = false;
    for (int i = 0; i < n; ++i) {
       int left = bigger_than_min ? '0' : minimum[i];
       int right = smaller_than_max ? '9' : maximum[i];
       answer[i] = left + rand() % (right - left + 1);
       bigger_than_min |= answer[i] > minimum[i];
       smaller_than_max |= answer[i] < maximum[i];
    }


    Edit: тут все возможные числа не будут равновероятны. Чтобы они были равновероятны придется хорошенько поизвращаться.
    Ответ написан
    Комментировать
  • Знает ли кто-то системную DLL, которая не фиксирует себя в памяти при загрузке?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Вряд ли тут какие-то хитрые методы остаться в памяти тут используются. Просто библиотека приложением итак используется. LoadLibrary лишь увеличивает счетчик использований, FreeLibrary просто уменьшает его, и ничего не загружается/выгружается. Попробуйте найти какую-то dll-ку, которая не выводится в списке в начале.
    Ответ написан
    1 комментарий
  • Как хранятся многомерные массивы в памяти?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Зависит от типа массива.
    int **a;
    // или vector<vector<int>> a;
    a[10][7];


    Тут происходит 2 разименовывания указателя. Массив в памяти хранится строчками. Каждая строка может быть где угодно. При этом дополнительно хранится массив указателей на строки (длиной с длину столбца). Поэтому такой массив занимает в памяти M*(sizeof(int*))+M*N*sizeof(int). Чуть сложнее для vector, но идея такая же.

    int a[10][3];
    a[4][5];


    Тут массив, хоть и многомерный, но фиксированного размера. Поэтому он хранится одним блоком. Компилятор знает длины всех строк и сразу вычисляет адрес конкретного элемента - сдвигаясь на (длину строки)*(номер строки)+(номер столбца). Он занимает N*M*sizeof(int).

    Сравните ассемблерный код.

    Кстати, именно поэтому вы не можете преобразовать int[4][5] к int**. И такой массив при передаче в функцию надо передавать по типу int[][5] (можно опустить количество строк. Ибо для адресации нужна лишь длина строк, но нестолбцов, но размер строки указать предется обязательно).

    arr[1][2] => *(*(arr + 1) + 2) Это действительно работает, потому что arr имеет тип int[][3] или int*[3]. Коспилятор видя arr+1, знает, что над сместится на 1 размер int[3]. * разыменовывает это, но при этом указывает на то же место. И получает просто указатель на int начало строки. Фактически тут просто меняется тип указателя с int*[3] на int*. +2 сдвигается в строке на 2 размера int.
    Ответ написан
    Комментировать
  • Как исправить ошибку Е0028 Выражение должно иметь константное значение на С?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    С вообще говоря, не умеет выделять массивы произвольного размера на стеке (вот так как у вас x локальная переменная). Ему надо знать размер массива во время компиляции. Вот про это он и ругается, n - не константа.

    Есть расширение VLA, которое есть в стандарте C99. С ним вот такие вот массивы можно заводить. Оно включено не во всех компиляторах из коробки. В некоторых его вообще, наверное, нет.
    Попробуйте передать компилятору в ключах флаг -std=c99.

    Или, выделяйте массив через malloc (не забудьте free сделать потом).

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

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Не совсем. Действительно, вы получаете в x код символа '4'. Но вы не преобразуете его в символьный. Это все еще int (скорее всего, 4-х байтный). В данном конкретном случае, это работает. Но тут вам повезло, что printf может вместо char принять int и правильно его синтерпретировать. Правильнее было бы преобразовать к char перед передачей в printf:
    printf("%c", (char)x);

    Вот тут уже действительно происходит преобразование к символьному типу char.

    Edit:
    Немного не прав был. printf надо передавать int, даже если формат "%с". Но какой-нибудь другой функции может понадобится именно char.
    Ответ написан
    5 комментариев
  • Как решить задачу, на оптимальную нагрузку курьера доставки?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Это обобщенная задача коммивояжора Multiple Traveling Salesman Problem.

    Надо будет построить граф. Взять все точки доставки и склад как вершины и каким-нибудь google maps найти расстояние и пути между каждой парой точек. Эти длины пути надо записать в ребра.

    Вообще, это очень сложная задача, как-то легко и быстро не решается. Если допустить не оптимальное решение, а что-то приблизительное, то есть эвристические аппроксимации да не точные методы вроде генетического алгоритма, метода отжига или муравьиного алгоритма (смотрите википедию для обычного коммивояжора). А так - только полный перебор с отсеченями, если у вас будет побольше точек и куръеров.

    Если у вас точек и куръеров действительно мало (не более 25 точек, не более 3 куръеров), то можно попробовать решать через динамическое программирование F(M, c1, c2, c3) - минимальная стоимость развезти товары из множества M так, что 3 куръера остаются в вершинах c1, c2 и c3. Переход - перебрать куръера и откуда он пришел из множества M. Посмотрите в википедии алгоритм для одного куръера, на трех это легко обобщается. Будет это работать за O(n^(c+1)2^n), где c - количество куръеров. n - количество вершин в графе. Сильно много куръеров или точек на карте этот алгоритм не переварит.
    Ответ написан
    Комментировать
  • Не могу понять, правильно ли я ввел формулу?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Какое значение эта формула принимает при x=1, например?

    Ну и у вас условие в бинарном поиске неправильное. Если f(a) и f(c) принимают разные значения, то корень находится между a и c. Вы же переходите к отрезку [c,b].
    Ответ написан
    2 комментария
  • Не удается открыть семафор, в чем ошибка?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    А он точно создается? Добавьте в процесс производителя вывод возвращаемого значения. Убедитесь, что семафор создан.

    Может, там, вполне NULL возвращается. И да, лучше HANDLE не сравнивать с nullptr. Это, все-таки, не указатель.
    Ответ написан
    1 комментарий
  • Почему вектор перемещения не поддается правилу треугольника при вычитании векторов?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    На графике или в тексте ошибка. Или там r-r0 должно быть в тексте, или стрелочку не в ту сторону нарисовали.
    Так бывает - в учебниках и методичках встречаются опечатки.
    Ответ написан
    Комментировать
  • Алгоритм для преобразование матрицы в треугольную?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Надо на каждой итерации искать среди оставшихся строк ту, у которой в данном столбце стоит максимальное по модулю значение. Менять местами эту строку с i-ой, потом все точно так же.

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

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    У вас полная каша в голове. Вы не понимаете, что такое перемещение, копирование.

    Вот как вы себе пердставляете перемещение int*?
    int* - это адрес в памяти. Число. Когда вы "перемещаете" img этого типа, вы перемещаете одно число. Из переменной img, в вектор.

    При этом что там лежит в памяти по адресу, равному этому числу (или на 20 сдвинутому), вообще не поменялось.

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

    Так, у вас в imgs вы не пихаете копию данных, а пихаете указатель.
    Ответ написан
    2 комментария
  • Как найти 7 неизвестных?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    У вас тут не уравнения, а неравенства. Системы неравенств часто имеют бесконечно много решений.

    Сходу очевидно, что x=y=a+b=c+d+k дает по нулям все левые части, что удовлетворяем всем неравенствам.

    Так что, берем x=y=a=c=1, b=d=k=0

    Плюс, можно менять 1 на что угодно. Можно распределять эту 1 между a и b, а так же между c, d и k. Бесконечно много решений.

    Похоже, тут проблема XY. Давайте вашу изначальную задачу - откуда вы эти неравенства взяли. Потому что их решение выглядит бесполезным. Вы что-то не то придумали, решили, что вам нужны эти неравнества, но это - тупик.
    Ответ написан
    4 комментария
  • Получение значения указателя в структуре которая является указателем?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    В чем проблема? Если бы у вас в структуре было поле типа int, как бы вы получали значение этого поля? вот точно так же, только у вас тип не int, а char*

    struct Foo {
    char* data;
    };
    
    Foo* bar;
    char* pointer = bar->data;
    Ответ написан
    Комментировать