Rzucanie zaklęć - Jak zoptymalizować obrażenia na sekundę

23

Wyobraź sobie, że mamy czarodzieja znającego kilka zaklęć. Każde zaklęcie ma 3 atrybuty: Obrażenia, czas ostygnięcia i czas rzucania. Całkiem standardowe rzeczy RPG.

Czas odnowienia: czas (t) potrzebny do ponownego rzucenia tego czaru. Zaklęcie „odnawia się” w momencie rozpoczęcia rzucania.

Czas rzucania: czas (t) potrzebny do użycia zaklęcia. Podczas gdy czarodziej rzuca coś, innego czaru nie można rzucić i nie można go anulować.

Pytanie brzmi: jak zmaksymalizować obrażenia przy różnych zestawach zaklęć?

Łatwo jest obliczyć najwyższe obrażenia na czas rzucania. Ale co z sytuacjami, w których lepiej jest poczekać, a potem utknąć, rzucając zaklęcie o niskim poziomie obrażeń, gdy dostępne jest znacznie wyższe?

Na przykład,

  1. Kula ognia: 3000 obrażeń, 3 sekundy rzucania, 6 sekund ostygnięcia.

  2. Frostbolt: 20 obrażeń, 4 sekundy rzucania, 4 sekundy ostygnięcia.

  3. Fireblast: 3 obrażenia, 3 sekundy rzucania, 3 sekundy ostygnięcia.

W takim przypadku twoje obrażenia na sekundę są większe, jeśli zdecydujesz się wybrać niższe zaklęcie DPCT (podmuch ognia) zamiast zamrożenia. Musimy więc rozważyć konsekwencje wyboru zaklęcia. alternatywny tekst

W poniższym przykładzie przedstawiono przypadki „przerzucania” i „oczekiwania”. alternatywny tekst

aaronfarr
źródło
Dlaczego miałbym robić 1-3-1 w tej sytuacji? Dlaczego nie 1-2-1? Dlaczego nie 1-2-3-1, który jest bardziej wydajny niż 1-3-1-X, jeśli 1-3-1 sam nie zabije celu?
@Joe Wreschnig: Dziękujemy za zwrócenie na to uwagi. To był błąd w moim przykładzie. Uproszczono to teraz do zaledwie 2 przypadków.
aaronfarr
1
Chciwy, ponieważ w miarę możliwości wybieraj najwyższe dostępne zaklęcie DPS. Zignorowanie innej logiki tj. Czekanie.
aaronfarr
1
Po prostu mętną wodę. Rozważ zaklęcie, które zadaje does obrażeń, ale jego rzucenie zajmuje 50 sekund. Jego wartość dps / dpct wynosi ∞, ale nigdy nie należy go wybierać, jeśli cel można zabić innymi środkami w mniej niż 50 sekund.
deft_code
1
Powinieneś link do dupe na math.stackexchange.com/questions/10414/…
Sparr

Odpowiedzi:

23

Cała sztuczna inteligencja to wyszukiwanie!

Kiedy wchodzisz w sedno sztucznej inteligencji, niesamowite jest, jak wiele z tego naprawdę stanowi wyszukiwanie .

  • stan : pozostały czas odnowienia wszystkich dostępnych czarów.
  • przydatność : wyrządzone szkody ogółem
  • koszt : całkowity czas wykonania
  • gałęzie : dowolne znane zaklęcie. Jeśli zaklęcie wciąż się odnawia, po prostu dodaj tę wartość do czasu rzucania.
  • cel : całkowite zdrowie celu. Celem musi być skończona ilość obrażeń, więc w przypadku nieznanego celu wybierz możliwie największe zdrowie.
    Alternatywnie, cel można wydać mniej niż 50 sekund, a poszukiwanie znalazłoby maksymalne obrażenia, które można by zadać w 50 sekund.

Podłącz te parametry do Uniform Cost Search (UCS) i presto, co gwarantuje optymalny plan bitwy. Jeszcze lepiej, jeśli możesz wymyślić heurystykę, wyszukiwanie za pomocą A * lub IDA *, a otrzymasz tę samą odpowiedź znacznie szybciej.

Dodatkowymi zaletami korzystania z LUW jest to, że może znaleźć optymalną kolejność rzutowania dla znacznie bardziej skomplikowanych sytuacji niż ta, w której podano tylko 3 zmienne. Niektóre inne aspekty, które można łatwo dodać:

  • uszkodzenia z biegiem czasu
  • Odśwież zaklęcie, aby skrócić czas odnowienia innych zaklęć
  • pośpiesz się, powodując, że inne czary rzucają się szybciej.
  • wzmacniacz obrażeń powodujący, że inne czary zadają większe obrażenia.

LUW nie jest wszechmocny. Nie może modelować korzyści zaklęć ochronnych. W tym celu musisz uaktualnić do wyszukiwania alfa-beta lub minimax.
Również nie radzi sobie zbyt dobrze z obszarami afektu i walkami grupowymi. LUW można dostosować, aby zapewnić rozsądne rozwiązania w takich sytuacjach, nie ma gwarancji znalezienia optymalnego rozwiązania.

deft_code
źródło
2

Jest to specjalistyczny problem optymalizacji kombinatorycznej. Wraz ze wzrostem liczby zaklęć znacznie wzrasta trudność w znalezieniu optymalnej kombinacji / wzoru zaklęć. Heurystyka podobna do tej stosowanej w przypadku problemu plecakowego byłaby cenna w rozwiązaniu tego problemu.

Sparr
źródło
1

Musisz pomyśleć w kategoriach „obrażeń na jednostkę czasu rzucania” (DPCT) - na przykład kula ognia z 3-sekundowym rzuceniem i zadaniem 3000 obrażeń spowodowałaby 1000 DPCT.

Jeśli musiałbyś poczekać 3 sekundy na odnowienie przed rzuceniem go, zmniejszyłoby to do 500 DPCT (3000 obrażeń podzielonych przez 6 sekund łącznie, łącznie z oczekiwaniem)

Musisz więc tylko określić czas uszkodzenia każdego czaru, łącznie z pozostałym czasem oczekiwania na odnowienie. Wybierz ten z najwyższym DPCT, poczekaj w razie potrzeby, a następnie rzuć. Powtarzaj, dopóki szef nie umrze :)

bluescrn
źródło
problemem jest to, że DPCT może być bardzo mylące. Powiedzmy na przykład, że dodajemy 2 kolejne zaklęcia do mieszanki Ognista Kula: 3000 obrażeń, 3 sekundy rzutu, 6 sekund czasu odnowienia, DPCT: 1000 Zaklęcie nr 2: 20 obrażeń, 4 sekundy rzutu, 4 sekundy czasu odnowienia, DPCT: 5 Zaklęcie # 3: 3 obrażenia, 3 sekundy rzucania, 3 sekundy czasu odnowienia, DPCT: 1 (pamiętaj, że czas odnowienia rozpoczyna się w momencie rzucenia czaru). Mimo że czar nr 3 ma niższy DPCT, spowoduje wyższy DPS (1-3-1-3 .. .) niż Zaklęcie nr 2 (1-2-1-2 ...).
aaronfarr
1

Korzystając z tego przykładu, prawdopodobnie chciałbyś, aby dwa zaklęcia były bardziej skuteczne, ale być może dałyby ci inną przewagę. Krótki czas rzucania (lub brak czasu rzucania w tym przypadku) byłby bardzo przydatny, więc może być warto użyć, nawet jeśli zadaje mniej obrażeń i wymaga dłuższego użycia.

Zawsze możesz narzucić inny element równaniu. Punkty Many / Magiczne mogą służyć temu celowi, pozwalając graczowi ustalić, czy użycie tych punktów jest warte korzyści.

Ogólnie jednak, jak powiedział bluescrn, DPCT (lub DPS, jak jest nazywany w wielu grach, które są wysoce dostrojone i omawiane przez graczy szukających najlepszego miksu) jest naprawdę głównym elementem, który chcesz zbalansować, szczególnie jeśli masz jakieś drzewka technologii / umiejętności, które umożliwiają różnym graczom postęp z różnymi umiejętnościami, ale z możliwością zadawania podobnych obrażeń na danej pozycji w grze.

Jeff Gray
źródło
0

Zrozumiałem ten algorytm, który działa dobrze dla moich celów.

Ludzie przynieśli kilka świetnych punktów. Podanie ostatecznych parametrów celu pozwoliłoby normalnym algorytmom wyszukiwania robić swoje. to znaczy. zadaj optymalne obrażenia w t sekund, zadaj x obrażeń w optymalnym czasie.

Mój algorytm po prostu zwraca sekwencję zaklęć o najwyższym DPS. Jest to szybki algorytm, ponieważ zmniejsza rozmiar zestawu, przez który przechodzisz, nie wymaga znajomości innych technik drzewa wyszukiwania.

Pierwszym krokiem jest zidentyfikowanie zaklęcia o największej wartości obrażeń na czas rzucania. Zaklęcie to staje się zaklęciem „podstawowym”, ponieważ gwarantuje najwyższe obrażenia na sekundę. Oznacza to, że zawsze powinieneś rzucić to zaklęcie, jeśli spełnione są następujące 2 warunki: 1) Zaklęcie bazowe jest dostępne (nie przy odnawianiu). 2) Obecnie nie rzucasz czaru.

Zatem staje się to kwestią wypełniania innych zaklęć, gdy zaklęcie podstawowe jest odnawiane. Pomiędzy (czas rzucania) a (czas odnowienia - czas rzucania). Jednak może wystąpić pewne nakładanie się (powyższa reguła 2 jest fałszywa).

Następnie staje się kwestią rekurencji przez wszystkie zaklęcia nie bazowe, aby znaleźć wszystkie sekwencje zaklęć, które nie naruszają 2 zasad.

W przypadku zaklęć, które nakładają się na siebie, należy je ukarać za potencjalne obrażenia, które mogło spowodować zaklęcie podstawowe (do maksymalnych obrażeń).

Weźmy na przykład 2 zaklęcia

1: 300 obrażeń, czas rzucania 3 s, czas odnowienia 10 s

2: 290 obrażeń, czas rzucania 3 s, czas odnowienia 3 s

Najwięcej obrażeń pochodzi z sekwencji 1–2–2–2, co powoduje nakładanie się 2 sekund na potencjalny rzut nr 1. Jest to jednak nadal korzystne, ponieważ jeśli nie rzucisz trzeciego zaklęcia (tj. 1–2–2), zadasz 880 obrażeń na 1 sekundę, aby zaoszczędzić. Jeśli rzucisz dodatkowe zaklęcie # 2, wykonasz 1170 - 2 sekundy z # 1, czyli 200. Zatem 970 obrażeń to obrażenia względne.

aaronfarr
źródło
-2

Możesz zrobić prostą obudowę przełącznika w stylu „poziomu bezpieczeństwa”.

To jest tuż poza moją głową, więc strzeżcie się błędów logicznych wykraczających poza poziom myślenia mojego zmęczonego stanu, ale mam nadzieję, że to pomoże wam zacząć.

Zakładając, że Twój czas jest wykonywany w liczbach całkowitych bloku -

// 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;
}

Niektóre wywołania metod są niepotrzebne z powodu twoich czasów zaklęć, ale w ten sposób zawsze jest miejsce na aktualizacje.

Edycja: Właśnie zdałem sobie sprawę, że będziesz musiał zresetować pozostały czas po rzuceniu nowego zaklęcia, prawdopodobnie najlepiej, aby uczynić go atrybutem klasy / polem i ustawić go z wywołania w ramach metod castSpell.

kymully
źródło
Naprawdę nie mam pojęcia, co chcesz tutaj osiągnąć, ale żaden nowoczesny silnik gry nie ma funkcji takich jak castSpell1 i castSpell2.
1
@Joe Wreschnig Miałem na myśli ich własne metody w niestandardowych klasach gier, to tylko abstrakcyjny przykład, a nie szczegółowy.
kymully,
1
Racja, nie tak działają czary w nowoczesnych silnikach. Jest jedna funkcja castSpell, która pobiera obiekt, którego pola są odczytywane z pliku. Taka instrukcja zmiany byłaby niemożliwa do utrzymania w prawdziwym silniku i wymagany jest pewien algorytm planowania.
@Joe Wreschnig Rozumiem. Podałem tylko sposób rozwiązania problemu. Ten przykład jest napisany w języku Java, nieprzeznaczony dla silnika ani konkretnego frameworka. Ale jeśli nie można go wdrożyć, jak mówisz, moja odpowiedź jest nieważna.
Kymully,