Пока рефакторил/оптимизировал, поломал алгоритм аи. Игра про захват земель по определённым правилам, и визуально стало выглядеть, как будто игроки просто бесконечно стоят на месте.
Оказалось, посеял опечатку в целевой функции. По задумке, должно было оптимизировать отрыв от ближайшего соперника (свои_очки - максимум_среди_врагов).
Но в формулу попал индекс, а не значение, и они стали выбирать максимально возможный самый пакостный ход для противника, полностью жертвуя прогрессом для себя.
А поскольку так попеременно делали оба, то так и застревали до упора.
Как хранятся полосные матрицы в лапак?
Внимание вопрос: в каком порядке элементы AB лежат в памяти.
А что такое "лапак"?
Edit: спс
krian
LAPACK
Забавный баг c SDL2, на macOS вызов SDL_Init() с флагом SDL_INIT_GAMECONTROLLER может поменять локаль и сменить разделитель десятичной дроби с точки на запятую.
printf("%.2f | %s\n", 2.78, setlocale( LC_ALL, NULL)); int sdl_init_result = SDL_Init( SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER); printf( "%.2f | %s\n", 2.78, setlocale( LC_ALL, NULL));
Вывод:
2.78 | C 2,78 | ru_RU.UTF-8
Багрепортнул сюда:
https://discourse.libsdl.org/t/bug-sdl-init-with-sdl-init-gamecon… -locale/26995
Решил поэксперементировать с Vulkan. Первым делом, конечно, хотел реализовать очистку экрана цветом.
Скопипастил код с одного примера. 4 часа не мог понять, почему оно не работает. В итоге нашёл, в чём проблема:
VkImageSubresourceRange vk_image_range; std::memset(&vk_image_range, 0, sizeof( vk_image_range)); vk_image_range.aspectMask= VK_IMAGE_ASPECT_COLOR_BIT; vk_image_range.baseMipLevel= 0u; vk_image_range.levelCount= 1u; vk_image_range.baseArrayLayer= 0u; vk_image_range.levelCount= 1u;
Самое интересное, что нашёл я это не глазами, а догадавшись врубить слой валидации.
Panzerschrek[CN]
какой смысл писать эти "u"? Я бы понял если бы ты передавал их в качестве аргумента при вызове функции или параметром шаблона. Но в данном случае?
Panzerschrek[CN]
> В итоге нашёл, в чём проблема
Для незнакомых с Вулканом поясни, на какую строчку смотреть.
Aroch
> какой смысл писать эти "u"?
Привычка, чтобы потом, там где надо, не похерить типизацию.
romanshuvalov
> Для незнакомых с Вулканом поясни, на какую строчку смотреть.
Вот, даже ты не заметил. Суть в том, что я 2 раза выставляю значение одного поля levelCount. В норме там должно быть layerCount и levelCount.
// с++ if(an ) { } else if( val = an_proc( ) ) // внутри for { // }
var t = an_proc() val = 0 // если t ноль, то не будет val = t // исправление бага if an : { } elif t : { val = t // }
Panzerschrek[CN]
> Вот, даже ты не заметил
А я и не читал.
Тренировался (давно, лет 10 назад) в OpenGL на ассемблере. Споткнулся на текстурах, упорно не хотел текстурироваться полигон. Исходный код брал из OpenGL-редбука практически один-в-один, только вызовы си-шных функций заменял на invoke-макросы.
Причина оказалась в том, что в редбуке был написан вызов
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL)
который на самом деле устанавливает не плавающую переменную, а целочисленную (то есть, фактически должна быть функция glTexEnvi), но за счет автоматического приведения типов целочисленная константа GL_DECAL приводилась к плавающей величине и glTexEnvf приводила к нужному результату.
В ассемблере же
invoke glTexEnvf, GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL
все сделано было по написанному, то есть целочисленная величина в неизменном двоичном представлении была передана туда, где ожидалось двоичное представление флоата.
Выводы:
1). Не используйте старый OpenGL
2). Не доверяйте авторам всяких редбуков, они тоже могут ошибаться
3). НЕ ПИШИТЕ НА АССЕМБЛЕРЕ (сказал человек, который продолжает это делать)
Так и не понял в чем суть бага, но если делать умножение позиции на MVP в геом шейдере, то интерполяция работает криво, если полигон очень длинный и оказывается частично за пределами виюпорта.
Перенос умножения в вершиный шейдер решило проблему.
На разных видеокартах все одинаково, возможно где-то и есть объяснение этого странного поведения...
Был примерно такой код такой код:
some_cache_.insert(element); BuildElement( element);
Заменил на вот это:
some_cache_.insert(element); // Когда кеш заполнен: for( auto& element : some_cache_) BuildElement( element);
И вдруг, на каких-то сложных примерах входных данных стало проявляться недопостроение элементов. Долго думал, в чём же может быть причина.
Сегодня, после отладки принэфами обнаружил, что цикл выполняется меньшее число раз, чем количество элементов в кеше. В конце до меня допёрло в чём причина. Оказывается, что BuildElement тоже может вставлять элементы в кеш. Починил, реализовав обход по отдельной копии кеша, чтобы она не изменилась в процессе.
class A{ public: virtual ~A() {} }; class B{ public: virtual ~B( ) {} }; class C: public A, B{ public: void check( ) { A* a = static_cast<A*>( this); B* b = static_cast<B*>( this); C* c_a = dynamic_cast<C*>( a); C* c_b = dynamic_cast<C*>( b); cout << "A* > C*: "<< ( ( c_a) ? "passed" : "failed") << endl; cout << "B* > C*: "<< ( ( c_b) ? "passed" : "failed") << endl; } virtual ~C( ){} };
кто сходу ответит что будет выведено и почему? :)