Potrzeba przewidywalnego generatora losowego


151

Jestem twórcą gier internetowych i mam problem z przypadkowymi liczbami. Powiedzmy, że gracz ma 20% szans na trafienie krytyczne mieczem. Oznacza to, że 1 na 5 trafień powinno być krytyczne. Problem polega na tym, że otrzymałem bardzo złe wyniki w życiu - czasami gracze otrzymują 3 trafienia krytyczne w 5 trafieniach, czasami żaden z 15 trafień. Bitwy są raczej krótkie (3-10 trafień), więc ważne jest, aby uzyskać dobry losowy rozkład.

Obecnie używam PHP mt_rand(), ale przenosimy nasz kod do C ++, więc chcę rozwiązać ten problem w nowym silniku naszej gry.

Nie wiem, czy rozwiązaniem jest jakiś jednolity generator losowy, czy może zapamiętanie poprzednich stanów losowych, aby wymusić właściwy rozkład.


58
Istnieje około 0,5% szans na dokładnie 3 trafienia krytyczne i 2 niekrytyczne oraz 3,5% szansy na 15 niekrytycznych trafień z rzędu, zakładając prawdziwe liczby losowe.
Nixuz

10
+1 do powyżej. Jedną z cech liczb losowych jest to, że otrzymujesz wartości odstające.
ConcernedOfTunbridgeWells

45
@Nixus: Nie, to około 5% szans na 3 trafienia krytyczne i 2 niekrytyczne, zapominasz o pomnożeniu przez (5! / (3! * 2!)) = 10. Przy 95% poziomie pewności jest to statystycznie nie jest mało prawdopodobne, aby 3 trafienia krytyczne wystąpiły w 5 uderzeniach.
erikkallen

7
Na początku pomyślałem, że to głupie pytanie ... po raz kolejny jestem upokorzony przez SO.
SergioL

Odpowiedzi:


39

Zgadzam się z wcześniejszymi odpowiedziami, że prawdziwa losowość w małych seriach niektórych gier jest niepożądana - wydaje się zbyt niesprawiedliwa w niektórych przypadkach użycia.

Napisałem prostą implementację typu Shuffle Bag w Rubim i przeprowadziłem kilka testów. Wdrożenie zrobiło to:

  • Jeśli nadal wydaje się sprawiedliwy lub nie osiągnęliśmy progu minimalnych rzutów, zwraca uczciwe trafienie w oparciu o normalne prawdopodobieństwo.
  • Jeśli obserwowane prawdopodobieństwo z poprzednich rzutów sprawia, że ​​wydaje się to niesprawiedliwe, zwraca trafienie „fair-ifying”.

Jest uważane za niesprawiedliwe na podstawie prawdopodobieństw granicznych. Na przykład dla prawdopodobieństwa 20% można ustawić 10% jako dolną granicę i 40% jako górną granicę.

Korzystając z tych granic, stwierdziłem, że w przypadku serii 10 trafień w 14,2% przypadków prawdziwa implementacja pseudolosowa dała wyniki wykraczające poza te granice . W około 11% przypadków 0 trafień krytycznych padło w 10 próbach. W 3,3% przypadków padło 5 lub więcej trafień krytycznych na 10. Oczywiście, używając tego algorytmu (z minimalną liczbą rzutów 5), znacznie mniejsza liczba (0,03%) „Fairish” przebiegów była poza zakresem . Nawet jeśli poniższa implementacja jest nieodpowiednia (z pewnością można zrobić sprytniejsze rzeczy), warto zauważyć, że często Twoi użytkownicy będą czuli, że jest to niesprawiedliwe w przypadku prawdziwego pseudolosowego rozwiązania.

Oto treść mojego FairishBagnapisanego w języku Ruby. Cała implementacja i szybka symulacja Monte Carlo jest dostępna tutaj (streszczenie) .

def fire!
  hit = if @rolls >= @min_rolls && observed_probability > @unfair_high
    false
  elsif @rolls >= @min_rolls && observed_probability < @unfair_low
    true
  else
    rand <= @probability
  end
  @hits += 1 if hit
  @rolls += 1
  return hit
end

def observed_probability
  @hits.to_f / @rolls
end

Aktualizacja: Korzystanie z tej metody zwiększa ogólne prawdopodobieństwo otrzymania trafienia krytycznego do około 22% przy zastosowaniu powyższych granic. Możesz to zrównoważyć, ustawiając jego „rzeczywiste” prawdopodobieństwo nieco niższe. Prawdopodobieństwo na poziomie 17,5% z modyfikacją fairish daje obserwowane prawdopodobieństwo długoterminowe na poziomie około 20% i sprawia, że ​​przebiegi krótkoterminowe są sprawiedliwe.


Myślę, że to najlepsze rozwiązanie, które odpowiada moim potrzebom. Wymieniona w najlepiej wskazanej odpowiedzi torba Shuffle nie jest zła, ale wymaga wielu obliczeń, a ja lubię najprostsze rozwiązanie, które prowadzi do celu.
Thinker

Steve Rabin napisał ciekawy artykuł o losowości w grach. Krótko mówiąc, dla większości ludzi prawdziwe „przypadkowe” zachowanie nie wydaje się być przypadkowe, a badania potwierdziły to. Jego artykuł nosi tytuł Filtered Randomness for AI Decisions and Game Logic i ukazuje się w „AI Game Programming Wisdom 2” (2003). Powinieneś to sprawdzić, prawdopodobnie ci się przyda.
Jeff Tucker,

@IanTerrell Dobrze byłoby określić, jak duża jest próbka twoich testów, tj. Ile bitew określa te prawdopodobieństwa.

@ user677656: Jest w istocie, ale jest 100 tys.
Ian Terrell

223

Oznacza to, że 1 na 5 trafień powinno być krytyczne. Problem polega na tym, że otrzymałem bardzo złe wyniki w życiu - czasami gracze otrzymują 3 trafienia krytyczne w 5 trafieniach, czasami żaden z 15 trafień.

Potrzebujesz torby do losowania . Rozwiązuje problem prawdziwego losowego bycia zbyt losowym dla gier.

Algorytm wygląda mniej więcej tak: umieszczasz 1 krytyczne i 4 niekrytyczne trafienia w torbie. Następnie losujesz ich kolejność w torbie i wybierasz je pojedynczo. Kiedy worek jest pusty, napełniasz go ponownie tymi samymi wartościami i losujesz. W ten sposób otrzymasz średnio 1 trafienie krytyczne na 5 trafień i maksymalnie 2 trafienia krytyczne i 8 niekrytycznych z rzędu. Zwiększ liczbę przedmiotów w torbie, aby uzyskać większą losowość.

Oto przykład implementacji (w Javie) i jej przypadki testowe, które napisałem jakiś czas temu.


21
+1 za dobry pomysł bez krytyki. Skaluj torbę, aby uzyskać wyższy stopień losowości i poradzić sobie z rozbieżnościami krytycznej szansy między graczami (jeśli zmienna ofc)
TheMissingLINQ

16
Możesz mieć torbę o rozmiarze 10. Zadaj 1 trafienie plus 30% szansy na sekundę. Jeśli krytyczna szansa się zmieni, możesz po prostu wyrzucić torbę i rozpocząć nową. Zwróć uwagę, że każdy taki schemat wiąże się z ryzykiem, że jeśli ty (lub twój przeciwnik) znasz swoje prawdopodobieństwo trafienia krytycznego i rozmiar worka, możesz czasami wiedzieć na pewno, że nie otrzymasz kolejnego krytycznego trafienia przez określoną liczbę rzutów. Może to wpłynąć na taktykę.
Steve Jessop

3
Tak ... w czymś takim jak to biegasz ricks podobnie jak liczenie kart. Czy ryzykuję peona, czy podejmę wielkie zabójstwo… mały, ustalony zestaw potencjalnych wyników może zmniejszyć ryzyko straty i zwiększyć szansę na „hazard”
Matthew Whited

8
Podoba mi się pomysł tasowania w worku, ale nie sądzę, aby pasował do „ducha” gry, ponieważ prawdopodobieństwo trafienia krytycznego wynoszące 20% (co oznacza, że ​​nie możesz zrobić żadnego w 10 trafieniach) nie jest już prawdopodobieństwem. Staje się dokładnie 1 trafieniem co 5 trafień. Co więcej, przerzucenie worka, jeśli zmieni się prawdopodobieństwo trafienia krytycznego, spowoduje usterkę w grze. Jeśli moje trafienie krytyczne zostało wykonane, rzucę na siebie zaklęcie, aby wcześniej dostać kolejnego krytyka: p
Michaël Carpentier,

2
@Jonathan: nadanie torbie dużego rozmiaru, który mu nadajesz, w rzeczywistości niweczy cały pomysł na torbę: upewnienie się, że coś się wydarzy (krytyczny, który jest osiągnięty) przy akceptowalnej liczbie rzutów. Zwiększenie rozmiaru torby 50000 jest mniej więcej tym samym, co użycie generatora liczb losowych.
dstibbe

113

Nie rozumiesz, co oznacza losowość.

Który z nich jest bardziej losowy?

wprowadź opis obrazu tutaj wprowadź opis obrazu tutaj

Podczas gdy drugi wykres wygląda na bardziej równomiernie rozłożony, tym bardziej losowy jest w rzeczywistości pierwszy wykres. Ludzki umysł często widzi wzorce w przypadkowości, więc na pierwszym wykresie widzimy skupiska jako wzorce, ale tak nie jest - są po prostu częścią losowo wybranej próbki.


25
Dobre wyjaśnienie Numb3rs!
RMAAlmeida

9
Technicznie rzecz biorąc, nie można zmierzyć losowości. Obie dystrybucje wydają mi się dość arbitralne, chociaż przypuszczam, że obie zostały wygenerowane algorytmicznie. Możesz przeprowadzić szereg testów na pierwszym wykresie i określić, że prawdopodobnie pochodzi on z procesu, który umieszcza punkty zgodnie z jednorodnym rozkładem, ale nie będziesz w stanie stwierdzić, że jest on bardziej losowy. Jako kontrprzykład, możesz zrobić wykres taki jak pierwszy, używając liniowego generatora kongruencji, a następnie zrobić wykres podobny do drugiego, używając wzmocnionego szumu z diody Zenera. Spróbuj użyć słowa nieskorelowane zamiast losowego.
Dietrich Epp

8
Możesz zmierzyć prawdopodobieństwo, że wspomniany rozkład jest losowy.
ceejayoz


2
Aby być uczciwym, chociaż OP może nie używać właściwych terminów, rozumie, że generator liczb losowych daje mu coś bardziej podobnego do pierwszego wykresu, kiedy chce czegoś bardziej podobnego do drugiego wykresu, ponieważ wydaje się on bardziej „sprawiedliwy” dla użytkownika.
Kip

88

Biorąc pod uwagę zachowanie, o które prosisz, myślę, że losujesz niewłaściwą zmienną.

Zamiast wybierać losowo, czy to trafienie będzie krytyczne, spróbuj losować liczbę tur do następnego trafienia krytycznego. Na przykład, po prostu wybierz liczbę od 2 do 9 za każdym razem, gdy gracz otrzyma trafienie krytyczne, a następnie daj mu następny krytyczny po upływie tylu rund. Możesz także użyć metod kostek, aby zbliżyć się do normalnego rozkładu - na przykład otrzymasz następne trafienie krytyczne w turach 2D4.

Uważam, że ta technika jest używana w grach RPG, które mają również przypadkowe spotkania na całym świecie - losujesz licznik kroków, a po tylu krokach ponownie zostajesz trafiony. Wydaje się to o wiele bardziej sprawiedliwe, ponieważ prawie nigdy nie zostajesz trafiony przez dwa spotkania z rzędu - jeśli zdarzy się to choćby raz, gracze stają się zirytowani.


Myślę, że to świetne rozwiązanie, ale co z 80% szansą?
Thinker

Lubię też czasami używać wielowymiarowych generatorów losowych. Szansa na trafienie + Szansa na moc + Szansa na trafienie krytyczne. Tak jak rzucanie kilkoma różnymi kośćmi w D&D
Matthew Whited

Podoba mi się ten pomysł i masz całkowitą rację co do licznika kroków, który był używany w finale fantasy przez bardzo długi czas, na przykład
Ed James

Problem polega na tym, że działa to tylko wtedy, gdy prawdopodobieństwo trafienia krytycznego jest mniej więcej stałe między trafieniami. Załóżmy, że w połowie bitwy gracz rzuca zaklęcie, które podwaja jego prawdopodobieństwo trafienia krytycznego. W takim razie jak dostosujesz liczbę zwojów?
Alex319

+1 Bardzo ładny, bardzo łatwo radzi sobie również z mniejszymi prawdopodobieństwami trafienia niż 20%.
Alice Purcell,

53

Najpierw zdefiniuj „właściwą” dystrybucję. Liczby losowe są, cóż, losowe - wyniki, które widzisz, są całkowicie zgodne z (pseudo) losowością.

Rozwijając to, zakładam, że chcesz mieć poczucie „sprawiedliwości”, więc użytkownik nie może przejść 100 obrotów bez sukcesu. Jeśli tak, śledziłbym liczbę niepowodzeń od ostatniego sukcesu i ważył wygenerowany wynik. Załóżmy, że chcesz, aby 1 na 5 rzutów zakończył się sukcesem. Więc losowo generujesz liczbę od 1 do 5, a jeśli jest to 5, świetnie.

Jeśli nie, zapisz awarię, a następnym razem wygeneruj liczbę od 1 do 5, ale dodaj powiedzmy floor (numFailures / 2). Więc tym razem mają szansę 1 na 5. Jeśli im się nie uda, następnym razem wygrywający przedział to 4 i 5; szansa na sukces 2 na 5. Dzięki tym wyborom, po 8 porażkach, na pewno się uda.


W związku z tym ... czy zakres liczb losowych wpłynąłby na rozkład ... np. Wybranie Random r = new Random (); r. następny (1,5) vs. r. następny (1, 1000000)% 200000
Eoin Campbell

23
+1 za zobaczenie problemu stojącego za żądaniem zamiast powiedzieć OP, że źle rozumie przypadkowość.
Boris Callens

4
Zwróć uwagę, że jeśli to zrobisz, ich ogólny odsetek sukcesów będzie większy niż 1 do 5. Sposobem na obejście tego jest (na przykład) wybranie losowo 20 różnych liczb z zakresu 1–100 i ustalenie z góry, że bądź ich krytykami. To jednak trochę więcej księgowości.
Steve Jessop

„będzie większa niż 1 na 5” - to znaczy w dłuższej perspektywie.
Steve Jessop

Możesz nieco zmniejszyć prawdopodobieństwo początkowe, tak aby ogólna proporcja została zmniejszona do 1/5. Nie wiem, o ile trzeba to zmniejszyć, ale wszystko jest ciągłe, więc musi być prawidłowa odpowiedź.
Steve Jessop

35

Co powiesz na zamianę mt_rand () na coś takiego?

Komiks XKCD (RFC 1149.5 określa 4 jako standardową liczbę losową zweryfikowaną przez IEEE).

(RFC 1149.5 określa 4 jako standardową liczbę losową zweryfikowaną przez IEEE).

Z XKCD .


Dobry, ale czy rozwiąże to problem z dystrybucją liczb losowych PO? ;-)
Arjan Einbu

Nie całkiem; Prosi o nielosowy RNG, dla którego mógłby użyć tej funkcji; ale to, czego naprawdę chce, lepiej wyjaśnia aktualna najlepsza odpowiedź ( stackoverflow.com/questions/910215/910224#910224 )
Colin Pickard

28
To jest bardziej losowe niż chce OP
Çağdaş Tekin

-1, ponieważ RFC1149 nie ma sekcji 5 (i alternatywnie nie ma 1149.5); +1 za uczciwą losowość.
greyfade

34

Mamy nadzieję, że ten artykuł Ci pomoże: http://web.archive.org/web/20090103063439/http://www.gamedev.net:80/reference/design/features/randomness/

Ta metoda generowania „liczb losowych” jest powszechna w grach RPG / MMORPG.

Problem, który rozwiązuje, jest następujący (wyciąg):

Pająk ostrza jest przy twoim gardle. Uderza i chybiasz Trafia ponownie i znowu tęsknisz. I znowu i znowu, dopóki nie zostanie z ciebie nic do trafienia. Nie żyjesz, a nad twoim trupem bawi się dwumetrowy pajęczak. Niemożliwy? Nie. Nieprawdopodobne? Tak. Ale mając wystarczającą liczbę graczy i wystarczająco dużo czasu, nieprawdopodobne staje się prawie pewne. Nie chodziło o to, że pająk ostrza był twardy, po prostu pech. Jakie to frustrujące. Wystarczy, że gracz będzie chciał rzucić palenie.


1
Słyszałem wariant tego - „jedno na milion zdarzenie ma miejsce 6000 razy w populacji świata”.
ceejayoz

19

To, czego chcesz, to nie liczby losowe, ale liczby, które wydają się przypadkowe człowiekowi. Inni już zasugerowali indywidualne algorytmy, które mogą Ci pomóc, na przykład Shuffle Bad.

Aby uzyskać dobrą szczegółową i obszerną analizę tej domeny, zobacz temat AI Game Programming Wisdom 2 . Cała książka jest warta przeczytania dla każdego twórcy gier, idea „pozornie losowych liczb” została omówiona w rozdziale:

Filtrowana losowość dla decyzji AI i logiki gry :

Streszczenie: Konwencjonalna mądrość sugeruje, że im lepszy generator liczb losowych, tym bardziej nieprzewidywalna będzie Twoja gra. Jednak według badań psychologicznych prawdziwa losowość w perspektywie krótkoterminowej często wydaje się ludziom zdecydowanie nieładna. W tym artykule pokazano, jak podejmować losowe decyzje sztucznej inteligencji i logikę gry dla graczy bardziej losowo, przy jednoczesnym zachowaniu silnej losowości statystycznej.

Może zainteresować Cię także inny rozdział:

Statystyka liczb losowych

Streszczenie: Liczby losowe są najczęściej używane przez sztuczną inteligencję i gry w ogóle. Ignorowanie ich potencjału oznacza uczynienie gry przewidywalną i nudną. Używanie ich w niewłaściwy sposób może być równie złe, jak ich ignorowanie. Zrozumienie, w jaki sposób generowane są liczby losowe, ich ograniczeń i możliwości, może usunąć wiele trudności związanych z ich używaniem w grze. Ten artykuł zawiera informacje na temat liczb losowych, ich generowania i metod oddzielania dobrych od złych.


8

Z pewnością każda generacja liczb losowych ma szansę na wyprodukowanie takich przebiegów? Nie dostaniesz wystarczająco dużego zestawu próbek w 3-10 rolkach, aby zobaczyć odpowiednie wartości procentowe.

Może to, czego chcesz, to próg miłosierdzia ... pamiętaj o ostatnich 10 rzutach, a jeśli nie mieli krytycznego trafienia, daj im freebie. Wygładź procy i strzały losowości.


8

Najlepszym rozwiązaniem może być play-testów z wieloma różnymi non systemów losowych i wybrać ten, który sprawia graczy najszczęśliwsze.

Możesz również wypróbować politykę wycofywania się dla tej samej liczby w danym spotkaniu, np. Jeśli gracz wyrzuci 1w swojej pierwszej turze, zaakceptuj ją. Aby zdobyć kolejny 1, muszą rzucić 2 1sekundy z rzędu. Aby uzyskać trzecią 1, potrzebują 3 z rzędu, w nieskończoność.


7

Niestety to, o co prosisz, to w rzeczywistości generator liczb nielosowych - ponieważ chcesz, aby poprzednie wyniki były brane pod uwagę przy określaniu następnej liczby. Obawiam się, że nie tak działają generatory liczb losowych.

Jeśli chcesz, aby 1 na 5 trafień było krytyczne, po prostu wybierz liczbę od 1 do 5 i powiedz, że to trafienie będzie krytyczne.


1
chce, aby gra była losowa, jeśli używasz ściśle generowanych liczb losowych, w niektórych przypadkach uzyskujesz wyniki „losowe koreańskie”. Są to losowe wyniki, które powodują, że gracze zbyt często denerwują się i frustrują (zapytaj dowolnego gracza z linii 2);)
Juan Techera

W konsekwencji, jeśli pierwsze trafienie jest trafieniem krytycznym, następne cztery nie będą. Brzmi to tak, jakby tego chciał OP, ale kiedy tak to wypowiadasz, brzmi to z opóźnieniem. Dostajesz za to moje UV.
belgariontheking

-1 wydaje się mylący „losowy” z „bez pamięci” - en.wikipedia.org/wiki/Memorylessness
Alice Purcell

7

mt_rand () jest oparty na implementacji Mersenne Twister , co oznacza, że ​​daje jedną z najlepszych losowych dystrybucji, jakie można uzyskać.

Najwyraźniej to, czego chcesz, wcale nie jest przypadkowe, więc powinieneś zacząć od określenia dokładnie tego, czego chcesz. Prawdopodobnie zdasz sobie sprawę, że masz sprzeczne oczekiwania - że wyniki powinny być naprawdę przypadkowe i nieprzewidywalne, a jednocześnie nie powinny wykazywać lokalnych odchyleń od podanego prawdopodobieństwa - ale wtedy staje się przewidywalne. Jeśli ustawisz maksymalnie 10 bezkrytycznych z rzędu, to właśnie powiedziałeś graczom "jeśli masz 9 bez krytyków z rzędu, następny będzie krytyczny ze 100% pewnością" - możesz tak w ogóle nie przejmuj się przypadkowością.


6

Przy tak małej liczbie testów powinieneś spodziewać się takich wyników:

Prawdziwa losowość jest przewidywalna tylko w przypadku dużego zestawu, tak że całkiem możliwe jest rzucenie monetą i trafienie orzeł 3 razy z rzędu za pierwszym razem, jednak po kilku milionach rzutów otrzymasz około 50-50.


7
Chociaż nadal istnieje szansa, że ​​po kilku milionach rzutów nadal będziesz widział tylko jedną stronę monety. Chociaż jeśli to się kiedykolwiek zdarzy, prawdopodobnie siedzisz zbyt blisko nieskończonego popędu nieprawdopodobieństwa: P
Grant Peters

haha, tak, ale szansa jest tak niewiarygodnie mała, że ​​prawa matematyczne mówią, że powinieneś zobaczyć równomierny (ish) rozkład.
Ed James

6

Widzę wiele odpowiedzi sugerujących śledzenie wcześniej wygenerowanych liczb lub tasowanie wszystkich możliwych wartości.

Osobiście nie zgadzam się, że 3 trafienia krytyczne z rzędu są złe. Nie zgadzam się też, że 15 nie-krytyków z rzędu jest złych.

Rozwiązałbym ten problem, modyfikując samą szansę na trafienie krytyczne po każdej liczbie. Przykład (aby zademonstrować pomysł):

int base_chance = 20;
int current_chance = base_chance;

int hit = generate_random_number(0, 100) + 1; // anything from 1 to 100
if(hit < current_chance)//Or whatever method you use to check
{
    //crit!
    if(current_chance > base_chance)
        current_chance = base_chance; // reset the chance.
    else
        current_chance *= 0.8; // decrease the crit chance for the NEXT hit.
}
else
{
    //no crit.
    if(current_chance < base_chance)
        current_chance = base_chance; // reset the chance.
    else
        current_chance *= 1.1; // increase the crit chance for the NEXT hit.
    //raise the current_chance
}

Im dłużej nie dostaniesz trafienia krytycznego - tym większa masz szansę na trafienie krytycznej następnej akcji. Załączony przeze mnie reset jest całkowicie opcjonalny i wymagałoby przetestowania, aby stwierdzić, czy jest potrzebny, czy nie. Może być pożądane, ale nie musi, dać większe prawdopodobieństwo trafienia krytycznego za więcej niż jedną akcję z rzędu, po długim łańcuchu akcji bez krytyki.

Dorzucam tylko moje 2 centy ...


Podoba mi się takie podejście. Prawdopodobnie zrobiłbym to w inny sposób. Zacznij od niższej szansy i zwiększaj do maksimum 20% + trochę dodanego procentu, aż trafi i zresetuj ponownie do jakiejś niskiej wartości.
Matthew

5

Kilka pierwszych odpowiedzi to świetne wyjaśnienia, więc skupię się tylko na algorytmie, który daje Ci kontrolę nad prawdopodobieństwem „złej passy”, nigdy nie będąc deterministycznym. Oto, co myślę, że powinieneś zrobić:

Zamiast podawać p , parametr rozkładu Bernoulliego, który jest Twoim prawdopodobieństwem trafienia krytycznego, podaj a i b , parametry rozkładu beta, „sprzężony poprzednik” rozkładu Bernoulliego. Musisz śledzić A i B , liczbę trafień krytycznych i niekrytycznych do tej pory.

Teraz, aby określić a i b , upewnij się, że a / (a ​​+ b) = p, szansa na trafienie krytyczne. Fajne jest to, że (a + b) określa ilościowo, jak blisko chcesz, aby A / (A + B) było ogólnie p.

Robisz samplowanie w ten sposób:

niech p(x)będzie funkcją gęstości prawdopodobieństwa rozkładu beta. Jest dostępny w wielu miejscach, ale możesz go znaleźć w GSL jako gsl_ran_beta_pdf.

S = A+B+1
p_1 = p((A+1)/S)
p_2 = p(A/S)

Wybierz trafienie krytyczne, próbkując z rozkładu Bernoulliego z prawdopodobieństwem p_1 / (p_1 + p_2)

Jeśli okaże się, że liczby losowe mają zbyt wiele „złych smugi” skalować się i B , ale w granicach, jak w i b idź do nieskończoności, trzeba będzie podejście torba losowe opisane wcześniej.

Jeśli to wdrożysz, daj mi znać, jak to idzie!


5

Jeśli chcesz mieć dystrybucję, która zniechęca do powtarzania wartości, możesz użyć prostego algorytmu odrzucania powtórzeń.

na przykład

int GetRand(int nSize)
{
    return 1 + (::rand() % nSize);
}
int GetDice()
{
    static int nPrevious=-1;
    while (1) {
        int nValue = GetRand(6);
        // only allow repeat 5% of the time
        if (nValue==nPrevious && GetRand(100)<95)
            continue;
        nPrevious = nValue;
        return nValue;
    }
}

Ten kod odrzuca powtarzające się wartości w 95% przypadków, co sprawia, że ​​powtórzenia są mało prawdopodobne, ale nie niemożliwe. Statystycznie jest to trochę brzydkie, ale prawdopodobnie przyniesie oczekiwane rezultaty. Oczywiście nie zapobiegnie to dystrybucji takiej jak „5 4 5 4 5”. Możesz stać się bardziej wyszukany i odrzucić przedostatniego (powiedzmy) 60% przypadków, a trzeciego od końca (powiedzmy) 30%.

Nie polecam tego jako dobrego projektu gry. Po prostu sugeruję, jak osiągnąć to, czego chcesz.


Niektóre wartości w mojej grze, takie jak trafienie krytyczne, nie mogą mieć więcej niż 50% szansy, więc w ogóle blokuję powtarzanie, ale to obniża szansę zdarzenia o kilka procent.
Thinker

4

Nie jest do końca jasne, czego chcesz. Możliwe jest utworzenie takiej funkcji, że przy pierwszych 5 jej wywołaniach zwraca liczby 1-5 w losowej kolejności.

Ale to nie jest przypadkowe. Gracz będzie wiedział, że w następnych 5 atakach otrzyma dokładnie jedną 5. Może to być jednak to, czego chcesz, aw takim przypadku po prostu musisz to samemu zakodować. (utwórz tablicę zawierającą liczby, a następnie przetasuj je)

Alternatywnie możesz nadal stosować swoje obecne podejście i założyć, że obecne wyniki są spowodowane złym generatorem losowym. Pamiętaj, że nie ma nic złego w aktualnych numerach. Wartości losowe są losowe. czasami otrzymujesz 2, 3 lub 8 tej samej wartości z rzędu. Ponieważ są przypadkowe. Dobry generator liczb losowych gwarantuje tylko, że średnio wszystkie liczby będą zwracane równie często.

Oczywiście, jeśli korzystałeś ze złego generatora losowego, może to wypaczyć wyniki, a jeśli tak, po prostu przełączenie na lepszy generator losowy powinno rozwiązać problem. (Sprawdź bibliotekę Boost.Random, aby uzyskać lepsze generatory)

Alternatywnie możesz zapamiętać ostatnie N wartości zwróconych przez funkcję losową i zważyć wynik przez nie. (prosty przykład brzmiałby: „dla każdego wystąpienia nowego wyniku istnieje 50% szansa, że ​​powinniśmy odrzucić wartość i uzyskać nową”

Gdybym miał zgadywać, powiedziałbym, że najlepszym rozwiązaniem jest trzymanie się „rzeczywistej” losowości. Upewnij się, że używasz dobrego generatora losowego, a następnie kontynuuj tak, jak robisz to teraz.


W rzeczywistości funkcja, której używa, jest taka sama, jak w przypadku najlepszego RNG w bibliotece boost.
Michael Borgwardt

MT nie jest „najlepszy”, ostatnio sprawdzałem. Jest ładny, prosty i szybki, ale nie zapewnia najlepszej dystrybucji. W każdym razie weź milion losowych liczb i sprawdź rozkład. Dowiedz się, czy funkcja losowa faktycznie zapewnia równomierny rozkład, czy nie. Jeśli nie, znajdź lepszy generator. Jeśli tak się stanie, albo wciągnij go i zaakceptuj sporadyczny rząd krytyków, albo oszukuj i spraw, by wyniki były mniej przypadkowe i bardziej przewidywalne.
jalf

4

Możesz utworzyć listę zawierającą liczby od 1 do 5 i posortować je według losowości. Następnie przejrzyj utworzoną listę. Masz gwarancję, że trafisz na każdy numer przynajmniej raz ... Kiedy skończysz z pierwszą piątką, po prostu utwórz kolejne 5 liczb ...


4

Polecam progresywny system procentowy, jakiego używa Blizzard: http://www.shacknews.com/onearticle.x/57886

Generalnie rzucasz RNG, a następnie porównujesz go z wartością, aby określić, czy się powiedzie, czy nie. To może wyglądać tak:

if ( randNumber <= .2 ) {
   //Critical
} else {
   //Normal
}

Wszystko, co musisz zrobić, to dodać stopniowe zwiększanie podstawowej szansy ...

if (randNumber <= .2 + progressiveChance ) {
   progressiveChance = 0;
   //Critical
} else {
   progressiveChance += CHANCE_MODIFIER;
   //Normal hit
}

Jeśli chcesz, aby był bardziej fantazyjny, możesz łatwo dodać więcej. Możesz ograniczyć kwotę, jaką progressiveChance może uzyskać, aby uniknąć stuprocentowej krytycznej szansy lub zresetować ją w niektórych wydarzeniach. Możesz również uzyskać progresywny wzrost szansy w mniejszych ilościach przy każdym wzmocnieniu z czymś w rodzaju progressiveChance + = (1 - progressiveChance) * SCALE, gdzie SCALE <1.


4

Cóż, jeśli trochę interesujesz się matematyką, prawdopodobnie możesz wypróbować rozkład wykładniczy

Na przykład, jeśli lambda = 0,5, oczekiwana wartość to 2 (przeczytaj ten artykuł!), Oznacza, że ​​najprawdopodobniej będziesz uderzać / krytyka / cokolwiek co 2 turę (np. 50%, co?). Ale przy takim rozkładzie prawdopodobieństwa na pewno spudłujesz (lub zrobisz odwrotnie niż cokolwiek) na 0-tej turze (tej, w której zdarzenie już miało miejsce, a turn_counter został zresetowany), masz około 40% szans na trafienie w następnej turze, około 65% szansa na zrobienie tego w drugiej turze (następna po następnej), około 80% na trafienie w trzecią i tak dalej.

Głównym celem tej dystrybucji jest to, że jeśli ktoś ma 50% szansy na trafienie i nie trafi 3 razy z rzędu, to na pewno (no cóż, ponad 80% szansy i zwiększa się ona z każdą kolejną turą) trafi. Prowadzi to do bardziej „uczciwych” wyników, zachowując ponad 50% szans na niezmienionym poziomie.

Korzystając z 20% szans na trafienie krytyczne, masz

  • 17% na trafienie krytyczne w pierwszej turze
  • 32% na trafienie krytyczne w drugiej turze, jeśli we wszystkich poprzednich nie pojawiło się trafienie krytyczne.
  • 45% na trafienie krytyczne w 3 turze, jeśli we wszystkich poprzednich nie pojawiło się trafienie krytyczne.
  • 54% do trafienia krytycznego w czwartej turze, jeśli we wszystkich poprzednich nie pojawiło się trafienie krytyczne.
  • ...
  • 80% do trafienia krytycznego w ósmej turze, jeśli we wszystkich poprzednich nie pojawiło się trafienie krytyczne.

Nadal wynosi około 0,2% (w porównaniu do tych 5%) szans na 3 trafienia krytyczne + 2 trafienia niekrytyczne w 5 kolejnych turach. I jest 14% szans na 4 następujące po sobie odpowiedzi niekrytyczne, 5% z 5, 1,5% na 6, 0,3% na 7, 0,07% na 8 kolejnych niekrytycznych. Założę się, że to „sprawiedliwsze” niż 41%, 32%, 26%, 21% i 16%.

Mam nadzieję, że nadal się nie nudzisz.


jest to dość podobne do mojego rozwiązania, z tym wyjątkiem, że „pamięta” tylko czas od ostatniego trafienia krytycznego. W ramach tego rozwiązania ciąg 4 trafień krytycznych jest taki sam, jak ciąg 1 trafienia krytycznego, jeśli chodzi o prawdopodobieństwa dotyczące przyszłości. Tak więc, jeśli trafienia krytyczne są dobre, to rozwiązanie ogranicza ryzyko spadku, ale nie korzyści. Moje rozwiązanie dotyczy obu.
Neil G

To oczywiste, że różne rozwiązania mają swoje zalety. Ten koncentruje się na utrzymaniu losowości w czystości z naukowego punktu widzenia. To nie znaczy, że jest lepszy niż shuffle bag czy cokolwiek innego. To tylko rozwiązanie, które wydaje się warte wypróbowania.
Ciemny

3

A co z uzależnieniem szansy na trafienie krytyczne od ostatnich ataków N. Jednym prostym schematem jest pewnego rodzaju łańcuch markov: http://en.wikipedia.org/wiki/Markov_chain, ale kod i tak jest bardzo prosty.


IF turns_since_last_critical < M THEN 
   critial = false
   turns_since_last_critical++;
ELSE
   critial = IsCritical(chance);
   IF Critial THEN
       turns_since_last_critica = 0;
   ELSE
       turns_since_last_critica++;
   END IF;
END IF;

Oczywiście musisz zrobić swoje obliczenia matematyczne, ponieważ szansa na trafienie krytyczne jest niższa niż szansa na trafienie krytyczne, gdy wiesz, że minęło wystarczająco dużo tur od ostatniego


Większość efektu osiągniesz, biorąc pod uwagę ostatni atak. Niech P będzie obserwowanym współczynnikiem trafień, R współczynnikiem trafień po chybieniu, a R / 2 współczynnikiem trafień po trafieniu. Z definicji w dowolnym momencie masz szansę trafić P = P * R + (1-P) * (R / 2). Oznacza to, że P = R / (2-R)
MSalters

2

OP,

Prawie, jeśli chcesz, aby było sprawiedliwe, nie będzie to przypadkowe.

Problemem twojej gry jest faktyczna długość meczu. Im dłuższe jest dopasowanie, tym mniej losowości zobaczysz (krytyki będą wynosić 20%) i zbliży się do zamierzonych wartości.

Masz dwie opcje, wstępnie oblicz ataki na podstawie poprzednich rzutów. Które otrzymasz jednego trafienia krytycznego co 5 ataków (w oparciu o twoje 20%), ale możesz ustawić losową kolejność, w jakiej występuje.

listOfFollowingAttacks = {Hit, Hit, Hit, Miss, Crit};

To jest wzór, którego chcesz. Więc niech wybierze losowo z tej listy, dopóki nie będzie pusta, utworzą ją ponownie.

To wzór, który stworzyłem dla mojej gry, działa całkiem nieźle, do tego, co chcę.

twoją drugą opcją byłoby zwiększenie szansy na trafienie krytyczne, prawdopodobnie zobaczysz bardziej równą liczbę na końcu wszystkich ataków (zakładając, że twoje mecze kończą się dość szybko). Im mniej% szans, tym więcej RNG dostaniesz.


2

Patrzysz na rozkład liniowy, kiedy prawdopodobnie chcesz mieć rozkład normalny.

Jeśli pamiętasz, że w młodości grałeś w D&D, zostałeś poproszony o rzucenie wieloma n-stronnymi kostkami, a następnie zsumuj wyniki.

Na przykład rzut 4 x 6-stronną kostką różni się od rzutu 1 x 24-ścienną kostką.


2

City of Heroes ma w rzeczywistości mechanikę zwaną „streakbreakerem”, która rozwiązuje dokładnie ten problem. Sposób, w jaki to działa, polega na tym, że po serii chybień o długości odpowiadającej najniższemu prawdopodobieństwu trafienia w ciągu, następny atak jest gwarantowany jako trafienie. Na przykład, jeśli przegapisz atak z ponad 90% szansą na trafienie, twój następny atak zostanie automatycznie trafiony, ale jeśli twoja szansa na trafienie jest niższa, np. 60%, będziesz musiał mieć kilka następujących po sobie chybień, aby wywołać "przełamacz serii" (I nie znam dokładnych liczb)



0

A co z ważeniem wartości?

Na przykład, jeśli masz 20% szans na trafienie krytyczne, wygeneruj liczbę od 1 do 5, gdzie jedna liczba oznacza trafienie krytyczne, lub liczbę od 1 do 100, gdzie 20 oznacza trafienie krytyczne.

Ale dopóki pracujesz z liczbami losowymi lub pseudolosowymi, nie ma sposobu, aby potencjalnie uniknąć wyników, które obecnie widzisz. Taka jest natura losowości.


I dlaczego miałoby to coś zmienić? Istnieje dokładnie taka sama szansa na uzyskanie trafienia krytycznego dla obu zestawów liczb.
samjudson

Dokładnie. Przedstawiam mu tylko dwie opcje dla jego przykładu 20%. Chociaż 100 prawdopodobnie działałoby lepiej, gdybyś miał do czynienia z procentami całkowitymi, ponieważ wystarczyłoby zasymulować tylko jedną „kostkę”, jeśli chcesz o tym myśleć w ten sposób.
Thomas Owens

Opcje, które prezentujesz, są dokładnie tym, co już robi.
ceejayoz

2
Nie za to, czego chce. Chce mieć nielosowy generator liczb, nawet jeśli uważa, że ​​nazywa się to generatorem liczb losowych.
ceejayoz

0

Reakcja na: „Problem polega na tym, że otrzymałem bardzo złe wyniki w prawdziwym życiu - czasami gracze otrzymują 3 trafienia krytyczne w 5 trafieniach, czasami żaden z 15 trafień”.

Masz szansę gdzieś między 3 a 4% nie uzyskać nic w 15 trafieniach ...


Kiedy masz 3500 graczy online walczących w 10000 bitew w ciągu minuty, problem występujący w 3% bitew jest bardzo częstym problemem.
Thinker

Z drugiej strony pech, który pojawia się w 3% bitew, to nadal po prostu pech.
MSalters

0

Proponuję następującą „losowo opóźnioną kość odrzucenia”:

  • Utrzymuj dwie tablice, jedną ( in-array) początkowo wypełnioną wartościami od 0 do n-1, a drugą ( out-array) pustą
  • Gdy żądany jest wynik:
    • zwraca losową wartość ze wszystkich zdefiniowanych wartości win-array
    • przenieś tę wartość z in-arraydoout-array
    • przenieś jeden losowy (po wszystkich elementach, w tym niezdefiniowany!) element z out-arraypowrotem doin-array

Ma to tę właściwość, że będzie „reagować” wolniej, im większe będzie n . Na przykład, jeśli chcesz mieć 20% szansy, ustawienie n na 5 i trafienie na 0 jest „mniej losowe” niż ustawienie n na 10 i trafienie na 0 lub 1, co spowoduje, że 0 do 199 z 1000 będzie prawie nie do odróżnienia od prawdziwej losowości na małej próbce. Będziesz musiał dostosować n do rozmiaru próbki.


0

Oblicz wstępnie losowe trafienie krytyczne dla każdego gracza.

// OBJECT
//...
// OnAttack()
//...
c_h = c_h -1;
if ( c_h == 0 ) {
 // Yes, critical hit!
 c_h = random(5) + 1 // for the next time
 // ...
}

0

Myślę, że być może używasz złej funkcji dystrybucji losowej. Prawdopodobnie nie chcesz równego podziału liczb. Zamiast tego wypróbuj normalną dystrybucję, aby trafienia krytyczne stały się rzadsze niż „zwykłe” trafienia.

Pracuję z Javą, więc nie jestem pewien, gdzie można znaleźć coś dla C ++, które daje losowe liczby z normalną dystrybucją, ale coś tam musi być.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.