Применение заклинаний - Как оптимизировать урон в секунду

23

Представьте, что у нас есть волшебник, который знает несколько заклинаний. Каждое заклинание имеет 3 атрибута: урон, время охлаждения и время чтения. Довольно стандартная ролевая игра.

Время перезарядки: количество времени (t), необходимое для того, чтобы снова разыграть это заклинание. Заклинание «перезаряжается» в тот момент, когда оно начинает читать.

Время чтения: количество времени (t), которое требуется для использования заклинания. Пока волшебник читает что-то, другое заклинание не может быть наложено и не может быть отменено.

Вопрос в том, как бы вы максимизировали урон, используя различные наборы заклинаний?

Легко рассчитать максимальный урон за время применения. Но что делать в ситуациях, когда лучше подождать, чем "застрять", разыгрывая заклинание с низким уроном, когда доступно гораздо более высокое заклинание?

Например,

  1. Огненный шар: 3000 урона, время каста 3 секунды, остывание 6 секунд.

  2. Ледяная стрела: 20 урона, 4 секунды каста, 4 секунды остывания.

  3. Огненный взрыв: 3 урона, 3 секунды каста, 3 секунды остывания.

В этом случае ваш урон в секунду выше, если вы решили пойти на более низкое заклинание DPCT (огненный взрыв) вместо ледяного удара. Таким образом, мы должны рассмотреть последствия выбора заклинания. альтернативный текст

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

aaronfarr
источник
Зачем мне делать 1-3-1 в этой ситуации? Почему не 1-2-1? Почему не 1-2-3-1, который более эффективен, чем 1-3-1-X, если один только 1-3-1 не убьет цель?
@Joe Wreschnig: Спасибо, что указал на это. Была ошибка в моем примере. Упростил это сейчас до 2 случаев.
Ааронфарр
1
Жадный, как в выборе самого высокого доступного заклинания дпс, когда это возможно. Не учитывая другую логику т.е. ожидание.
Ааронфарр
1
Просто чтобы мутить воду. Рассмотрим заклинание, которое наносит ∞ урона, но разыгрывает 50 секунд. Это dps / dpct равно ∞, но его никогда не следует выбирать, если цель может быть уничтожена другими средствами менее чем за 50 секунд.
deft_code
1
Вы должны связать с боян на math.stackexchange.com/questions/10414/...
Sparr

Ответы:

23

Весь ИИ это поиск!

Когда вы попадаете в интуицию ИИ, удивительно, сколько из этого действительно ищет .

  • состояние : оставшееся время восстановления всех доступных заклинаний.
  • фитнес : общий ущерб нанесен
  • стоимость : общее время
  • ветви : любое известное заклинание. Если заклинание все еще находится в перезарядке, просто добавьте это значение к его времени чтения.
  • цель : общее здоровье цели. Целью должно быть ограниченное количество урона, поэтому в случае неизвестной цели выберите максимально возможное количество здоровья.
    В качестве альтернативы, цель может быть потрачена менее чем за 50 секунд, и поиск найдет максимальный урон, который может быть нанесен за 50 секунд.

Подключите эти параметры к поиску единой стоимости (UCS) и заранее, гарантированно оптимальный план битвы. Еще лучше, если вы можете использовать эвристику, искать с помощью A * или IDA *, и вы получите тот же ответ намного быстрее.

Еще несколько преимуществ использования UCS в том, что он может найти оптимальный порядок приведения для гораздо более сложных ситуаций, чем тот, который вы предоставили только с 3 переменными. Некоторые другие аспекты, которые можно легко добавить:

  • ущерб с течением времени
  • обновить заклинание, чтобы уменьшить время восстановления других заклинаний
  • заклинание Ускорение, заставляющее другие заклинания читать быстрее.
  • усилитель урона, заставляющий другие заклинания наносить больше урона.

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

deft_code
источник
2

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

Sparr
источник
1

Вы должны думать с точки зрения «урона на единицу времени наложения» (DPCT) - например, огненный шар с 3-секундным применением и нанесением 3000 урона будет делать 1000 DPCT.

Если вам пришлось подождать 3 секунды до восстановления заклинания, то это уменьшило бы его до 500 DPCT (3000 урона, разделенное на 6 секунд, включая ожидание)

Так что вам просто нужно определить время нанесения урона за каждое заклинание, включая оставшееся время ожидания восстановления. Выберите один с самым высоким DPCT, подождите, если необходимо, затем разыграйте его. Повторяйте, пока босс не умрет :)

bluescrn
источник
проблема в том, что DPCT может быть очень обманчивым. Скажем, к примеру, мы добавляем еще 2 заклинания к смеси Огненный шар: 3000 урона, 3 секунды применения, 6 секунд перезарядки, DPCT: 1000 Заклинание № 2: 20 урона, 4 секунды применения, 4 секунды перезарядки, DPCT: 5 Заклинание № 3: 3 урон, 3 секунды наложения, 3 секунды восстановления, DPCT: 1 (помните, время восстановления начинается с момента сотворения заклинания) Даже если заклинание № 3 имеет более низкое значение DPCT, оно приведет к увеличению DPS (1-3-1-3 .. .) чем Заклинание № 2 (1-2-1-2 ...).
Ааронфарр
1

Используя ваш пример, вы, вероятно, захотите, чтобы два заклинания были эффективнее, но, возможно, дадут вам другое преимущество. Было бы очень полезно иметь короткое время чтения (или вообще никакого времени чтения), поэтому его стоит использовать, даже если оно наносит меньше урона и требует больше времени для повторного использования.

Вы всегда можете ввести другой элемент в уравнение. Мана / Магические Очки могут служить этой цели, позволяя игроку определить, стоит ли использовать эти очки.

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

Джефф Грей
источник
0

Выяснил этот алгоритм, который хорошо работает для моих целей.

Люди подняли некоторые замечательные моменты. Задание конечных параметров цели позволило бы нормальным алгоритмам поиска делать свое дело. то есть. нанести оптимальный урон за t секунд, нанести х повреждений за оптимальное время.

Мой алгоритм просто возвращает последовательность заклинаний с самым высоким DPS. Это быстрый алгоритм, так как он сокращает размер набора, который вы пересекаете, не требует знания других методов дерева поиска.

Первый шаг - определить заклинание с наибольшим уроном за время применения. Это заклинание становится базовым заклинанием, так как оно гарантирует самый высокий урон в секунду. Это значит, что вы всегда должны использовать это заклинание, если выполнены следующие 2 условия: 1) Базовое заклинание доступно (не на перезарядке). 2) В данный момент вы не разыгрываете заклинание.

Таким образом, это становится вопросом заполнения других заклинаний, пока заклинание базовой линии находится в режиме восстановления. Между (время каста) и (время восстановления - время каста). Однако может произойти некоторое наложение (правило 2 выше ложно).

Затем становится вопросом повторения всех не базовых заклинаний, чтобы найти все последовательности заклинаний, которые не нарушают 2 правила.

Для заклинаний, которые ДЕЙСТВИТЕЛЬНО перекрываются, вы должны оштрафовать их за потенциальный урон, который могло нанести базовое заклинание (вплоть до его максимального урона).

Взять, к примеру, 2 заклинания

1: 300 урона, 3 сек. Время перезарядки, 10 сек.

2: 290 урона, 3 сек. Время перезарядки, 3 сек.

Наибольший урон наносится в последовательности 1 - 2 - 2 - 2. Это приводит к наложению на 2 секунды на потенциальный бросок # 1. Тем не менее, это все еще полезно, так как, если вы не разыграете третье заклинание (т.е. 1 - 2 - 2), вы нанесете 880 урона с запасом в 1 секунду. Если вы разыгрываете дополнительное заклинание # 2, вы будете делать 1170 - 2 секунды из # 1, что составляет 200. Таким образом, 970 урона - это ваш относительный урон.

aaronfarr
источник
-2

Вы могли бы сделать простой случай переключателя стиля "уровня безопасности".

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

Предполагая, что ваше время сделано в целых числах блоков -

// after casting spell
int remainingTime = (coolDown - castTime);
switch(spellJustCast)
{
  // assuming the cast method will have some input validation for whether the spell
  // is off cooldown or not, pass the time as a parameter
  case 3 : castSpell1(remainingTime);
           castSpell2(remainingTime);
           break;
  case 1 : castSpell2(remainingTime);
           castSpell3(remainingTime);
           break;
  case 2 : castSpell1(remainingTime);
           castSpell3(remainingTime);
           break;
  default: System.out.println("Debug!");
           break;
}

Некоторые вызовы методов излишни из-за вашего времени заклинаний, но всегда есть место для обновлений таким образом.

Редактировать: Я только что понял, вам нужно будет сбросить оставшееся время после сотворения нового заклинания, вероятно, лучше всего сделать его атрибутом / полем класса и установить его из вызова в методах castSpell.

kymully
источник
Я действительно понятия не имею, чего вы пытаетесь достичь, но ни у одного современного игрового движка нет таких функций, как castSpell1 и castSpell2.
1
@Joe Wreschnig Я имел в виду, что они были его собственными методами в его классах игры, это только абстрактный пример, а не детальный.
Кимуллы
1
Да, это не так, как заклинания работают в современных движках. Есть одна функция castSpell, которая принимает объект, чьи поля считываются из файла. Такое заявление о переключении было бы невозможно поддерживать в любом реальном движке, и требуется какой-то алгоритм планирования.
@ Джо Рэшниг, я понимаю. Я просто давал способ решить проблему. Этот пример написан на Java, не предназначен для движка или конкретной платформы. Но если это не может быть реализовано, как вы говорите, мой ответ недействителен.
Кимуллы