Necessità di un generatore casuale prevedibile


151

Sono uno sviluppatore di giochi Web e ho un problema con i numeri casuali. Diciamo che un giocatore ha il 20% di probabilità di ottenere un colpo critico con la sua spada. Ciò significa che 1 colpo su 5 dovrebbe essere critico. Il problema è che ho ottenuto risultati molto negativi nella vita reale - a volte i giocatori ottengono 3 punti critici in 5 colpi, a volte nessuno in 15 colpi. Le battaglie sono piuttosto brevi (3-10 colpi), quindi è importante ottenere una buona distribuzione casuale.

Attualmente uso PHP mt_rand(), ma stiamo semplicemente spostando il nostro codice in C ++, quindi voglio risolvere questo problema nel nuovo motore del nostro gioco.

Non so se la soluzione sia un generatore casuale uniforme, o forse ricordare i precedenti stati casuali per forzare una corretta distribuzione.


58
C'è una probabilità dello 0,5% circa di 3 colpi critici e 2 non critici e una probabilità del 3,5% di 15 colpi non critici di fila, assumendo numeri casuali reali.
Nixuz,

10
+1 a sopra. Una caratteristica dei numeri casuali è che si ottengono valori anomali.
Preoccupato di TunbridgeWells

45
@Nixus: No, è circa il 5% di probabilità di 3 colpi critici e 2 non critici, ti stai dimenticando di moltiplicare con (5! / (3! * 2!)) = 10. Con un livello di confidenza del 95%, è non è statisticamente improbabile che si verifichino 3 colpi critici in 5 colpi.
erikkallen,

7
All'inizio ho pensato che fosse una domanda sciocca ... ancora una volta, sono umiliato dalla SO.
SergioL,

Risposte:


39

Concordo con le risposte precedenti che la casualità reale in piccole tirature di alcuni giochi è indesiderabile - sembra troppo ingiusta per alcuni casi d'uso.

Ho scritto una semplice Shuffle Bag come l'implementazione in Ruby e ho fatto alcuni test. L'implementazione ha fatto questo:

  • Se sembra ancora giusto o non abbiamo raggiunto la soglia dei tiri minimi, restituisce un colpo giusto in base alla probabilità normale.
  • Se la probabilità osservata dai lanci precedenti la fa sembrare ingiusta, restituisce un colpo "equo e solidale".

È ritenuto ingiusto in base alle probabilità al contorno. Ad esempio, per una probabilità del 20%, è possibile impostare il 10% come limite inferiore e il 40% come limite superiore.

Usando quei limiti, ho scoperto che con esecuzioni di 10 hit, il 14,2% delle volte la vera implementazione pseudocasuale ha prodotto risultati che erano fuori dai limiti . Circa l'11% delle volte, sono stati segnati 0 colpi critici in 10 tentativi. Il 3,3% delle volte, 5 o più colpi critici sono stati sbarcati su 10. Naturalmente, usando questo algoritmo (con un conteggio minimo dei tiri di 5), una quantità molto più piccola (0,03%) delle corse "Fairish" era fuori limite . Anche se l'implementazione di seguito non è adatta (si possono fare cose più intelligenti, certamente), vale la pena notare che, in particolare, gli utenti ritengono spesso che sia ingiusto con una vera soluzione pseudocasuale.

Ecco la mia carne FairishBagscritta in Ruby. L'intera implementazione e la rapida simulazione Monte Carlo sono disponibili qui (in sintesi) .

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

Aggiornamento: l' uso di questo metodo aumenta la probabilità complessiva di ottenere un colpo critico, a circa il 22% usando i limiti sopra. Puoi compensare impostando la sua probabilità "reale" un po 'più in basso. Una probabilità del 17,5% con la modifica equa produce una probabilità osservata a lungo termine di circa il 20% e mantiene le corse a breve termine corrette.


Penso che questa sia la migliore soluzione adatta alle mie esigenze. Shuffle bag menzionato nella migliore risposta a punta non è male, ma ha bisogno di molti calcoli e mi piace la soluzione più semplice che porta al bersaglio.
Pensatore

Steve Rabin ha scritto un articolo interessante sulla casualità nei giochi. In breve, il vero comportamento "casuale" in realtà non "sembra" casuale per la maggior parte delle persone e gli studi lo hanno sostenuto. Il suo articolo si chiama Filtered Randomness for AI Decisions and Game Logic e appare in "AI Game Programming Wisdom 2" (2003). Dovresti dare un'occhiata, probabilmente ti sarà utile.
Jeff Tucker,

@IanTerrell Sarebbe bene dichiarare quanto è grande la dimensione del campione dei tuoi test, cioè quante battaglie per determinare quelle probabilità.

@ user677656: È in sostanza, ma sono 100k
Ian Terrell,

223

Ciò significa che 1 colpo su 5 dovrebbe essere critico. Il problema è che ho ottenuto risultati molto negativi nella vita reale - a volte i giocatori ottengono 3 punti critici in 5 colpi, a volte nessuno in 15 colpi.

Ciò di cui hai bisogno è una borsa shuffle . Risolve il problema del fatto che il vero casuale è troppo casuale per i giochi.

L'algoritmo è in questo modo: metti 1 colpi critici e 4 non critici in un sacchetto. Quindi randomizzi il loro ordine nella borsa e li prendi uno alla volta. Quando il sacchetto è vuoto, lo si riempie di nuovo con gli stessi valori e lo si randomizza. In questo modo otterrai in media 1 colpo critico per 5 colpi, e al massimo 2 colpi critici e 8 colpi non critici di fila. Aumenta il numero di oggetti nella borsa per una maggiore casualità.

Ecco un esempio di implementazione (in Java) e dei suoi casi di test che ho scritto qualche tempo fa.


21
+ 1 per una buona idea senza critiche. Scala la borsa per un più alto grado di casualità e per gestire le variazioni nelle probabilità critiche tra i giocatori (se variabile ofc)
TheMissingLINQ

16
Potresti avere una dimensione del sacchetto di 10. Metti 1 colpo, più una probabilità del 30% di un secondo. Se le possibilità critiche cambiano, potresti semplicemente buttare via la borsa e iniziarne una nuova. Nota che qualsiasi schema di questo tipo corre il rischio che se tu (o il tuo avversario) conoscete la probabilità di colpo critico e le dimensioni del sacco, a volte potete sapere con certezza che non otterrete un altro critico per un certo numero di tiri. Ciò potrebbe influire sulle tattiche.
Steve Jessop,

3
Sì ... in qualcosa del genere esegui trucchi simili al conteggio delle carte. Rischio un peon o vado avanti per la grande uccisione ... un piccolo insieme fisso di potenziali esiti può ridurre il rischio di perdita e aumentare le possibilità di essere "spacciato"
Matthew Whited,

8
Mi piace l'idea di shuffle bag ma non penso che corrisponda allo "spirito" del gioco perché la probabilità di colpo critico del 20% (il che significa che non puoi farne nessuno su 10 colpi) non è più una probabilità. Diventa esattamente 1 colpo ogni 5 colpi. Inoltre, il rilancio della borsa in caso di variazione della probabilità di colpo critico causerà un errore nel gioco. Se il mio colpo critico è stato fatto, lancerò l'incantesimo su me stesso per ottenere il prossimo critico prima: p
Michaël Carpentier,

2
@Jonathan: rendere la borsa delle grandi dimensioni che gli dai in realtà annulla l'intera idea della borsa: assicurarsi che accada qualcosa (la critica che viene raggiunta) entro un ammontare accettabile di tiri. Rendere la borsa grande 50000 è quasi la stessa cosa che usare il generatore di numeri casuali.
dstibbe,

113

Hai frainteso cosa significhi random.

Quale di questi è più casuale?

inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine

Mentre la seconda trama sembra distribuita in modo più uniforme, più casuale è in realtà la prima trama. La mente umana vede spesso schemi nella casualità, quindi vediamo i gruppi nella prima trama come schemi, ma non lo sono - fanno solo parte di un campione selezionato casualmente.


25
Buona spiegazione di Numb3rs!
RMAAlmeida,

9
Tecnicamente parlando, non puoi misurare la casualità. Entrambe le distribuzioni mi sembrano abbastanza arbitrarie, anche se la mia ipotesi è che entrambe siano state generate algoritmicamente. Puoi eseguire una serie di test sul primo grafico e determinare che è probabile che provenga da un processo che posiziona i punti secondo una distribuzione uniforme, ma non sarai in grado di concludere che è più casuale. Come controesempio, potresti creare un diagramma come il primo usando un generatore congruenziale lineare, quindi creare un diagramma come il secondo usando il rumore amplificato di un diodo zener. Prova la parola non correlata anziché casuale.
Dietrich Epp,

8
È possibile misurare la probabilità che detta distribuzione sia casuale.
Ceejayoz,


2
Ad essere onesti, sebbene OP non stia usando i termini corretti, capisce che il generatore di numeri casuali gli sta dando qualcosa di più simile al primo grafico, quando vuole qualcosa di più simile al secondo grafico perché sembra più "equo" per l'utente.
Kip

88

Dato il comportamento che stai chiedendo, penso che stai randomizzando la variabile sbagliata.

Piuttosto che randomizzare se questo colpo sarà critico, prova a randomizzare il numero di turni fino al prossimo colpo critico. Ad esempio, basta scegliere un numero compreso tra 2 e 9 ogni volta che il giocatore ottiene un critico, quindi dare loro il prossimo critico dopo che sono trascorsi molti round. Puoi anche usare i metodi dei dadi per avvicinarti a una distribuzione normale - per esempio, otterrai il tuo prossimo critico in turni 2D4.

Credo che questa tecnica venga utilizzata nei giochi di ruolo che hanno incontri casuali anche nell'overworld: randomizzi un contapassi e dopo tanti passaggi, verrai colpito di nuovo. Sembra molto più giusto perché non vieni quasi mai colpito da due incontri di fila - se ciò accade anche una volta, i giocatori diventano irritabili.


Penso che questa sia un'ottima soluzione, ma che dire dell'80% di possibilità?
Pensatore,

A volte mi piace anche usare generatori casuali multidimensionali. Probabilità di colpire + Probabilità di potenziare + Probabilità di critico. Proprio come tirare diversi dadi in D&D
Matthew Whited,

Mi piace questa idea, e hai perfettamente ragione sulla cosa del contapassi, che è stata usata nella fantasia finale per molto tempo, ad esempio
Ed James,

Un problema è che funziona solo se la probabilità di un critico è approssimativamente costante tra i colpi. Supponiamo che a metà battaglia il giocatore lanci un incantesimo che raddoppi la probabilità di un colpo critico. Quindi come si regola il numero di giri?
Alex319,

+1 Molto bello, gestisce anche meno probabilità di round to-hit del 20% molto facilmente.
Alice Purcell,

53

Innanzitutto, definire una distribuzione "corretta". I numeri casuali sono, beh, casuali: i risultati che stai vedendo sono del tutto coerenti con la (pseudo) casualità.

Espandendo su questo, suppongo che ciò che vuoi sia una sensazione di "correttezza", quindi l'utente non può fare 100 giri senza successo. In tal caso, terrei traccia del numero di guasti dall'ultimo successo e pondererei il risultato generato. Supponiamo che tu voglia 1 tiri su 5 per "riuscire". Quindi generi casualmente un numero da 1 a 5, e se è 5, ottimo.

In caso contrario, registra l'errore e la prossima volta genera un numero da 1 a 5, ma aggiungi, ad esempio, floor (numFailures / 2). Quindi, questa volta, hanno ancora una probabilità 1 su 5. Se falliscono, la prossima volta l'intervallo vincente è 4 e 5; una probabilità di successo 2 su 5. Con queste scelte, dopo 8 fallimenti, hanno sicuramente successo.


In quella nota ... l'intervallo di numeri casuali influirebbe sulla distribuzione ... ad es. Scegliendo un Casuale r = nuovo Casuale (); r.Prossimo (1,5) vs. r.Prossimo (1, 1000000)% 200000
Eoin Campbell,

23
+1 per vedere il problema dietro la richiesta invece di dire all'OP che fraintende in modo casuale.
Boris Callens,

4
Nota che se lo fai, la loro proporzione complessiva di successi sarà maggiore di 1 su 5. Un modo per aggirare il problema è (ad esempio) scegliere 20 numeri diversi a caso dall'intervallo 1..100 e predeterminare che quelli essere i loro critici. È un po 'più di contabilità, però.
Steve Jessop,

"sarà maggiore di 1 su 5" - si prevede che sarà a lungo termine, intendo.
Steve Jessop,

È possibile ridimensionare un po 'la probabilità iniziale, in modo che la proporzione complessiva sia ridotta a 1/5. Non ho capito di quanto devi ridurlo, ma tutto è continuo, quindi ci deve essere una risposta giusta.
Steve Jessop,

35

Che ne dici di sostituire mt_rand () con qualcosa del genere?

Fumetto XKCD (RFC 1149.5 specifica 4 come numero casuale verificato IEEE standard.)

(RFC 1149.5 specifica 4 come numero casuale verificato IEEE standard.)

Da XKCD .


Bene, ma questo risolverà il problema di distribuzione casuale dei numeri dei PO? ;-)
Arjan Einbu,

Non proprio; Chiede un RNG non casuale, per il quale potrebbe usare questa funzione; ma ciò che vuole davvero è meglio spiegato dall'attuale risposta migliore ( stackoverflow.com/questions/910215/910224#910224 )
Colin Pickard,

28
Questo è più casuale di quanto l'OP voglia
Çağdaş Tekin,

-1 perché RFC1149 non ha sezione 5 (e in alternativa non c'è 1149.5); +1 per casualità equa.
greyfade,

34

Speriamo che questo articolo ti possa aiutare: http://web.archive.org/web/20090103063439/http://www.gamedev.net:80/reference/design/features/randomness/

Questo metodo di generazione di "numeri casuali" è comune nei giochi rpg / mmorpg.

Il problema che risolve è questo (estratto):

Un ragno a lama è alla gola. Colpisce e ti manca. Colpisce di nuovo e ti manca di nuovo. E ancora e ancora, fino a quando non ti rimane più niente da colpire. Sei morto e c'è un aracnide di due tonnellate che gongola sul tuo cadavere. Impossibile? No. Improbabile? Sì. Ma dato abbastanza giocatori e abbastanza tempo, l'improbabile diventa quasi certo. Non era che il ragno della lama fosse duro, era solo sfortuna. Che frustrante. È abbastanza per far smettere un giocatore.


1
Ne ho sentito una variante: "un evento su un milione accade 6.000 volte nella popolazione mondiale".
Ceejayoz,

19

Quello che vuoi non sono numeri casuali, ma numeri che sembrano casuali a un essere umano. Altri hanno già suggerito singoli algoritmi, che possono aiutarti, come Shuffle Bad.

Per una buona analisi dettagliata ed estesa di questo dominio vedi AI Game Programming Wisdom 2 . Vale la pena leggere l'intero libro per qualsiasi sviluppatore di giochi, l'idea di "numeri apparentemente casuali" è trattata nel capitolo:

Casualità filtrata per decisioni AI e logica di gioco :

Riassunto: la saggezza convenzionale suggerisce che migliore è il generatore di numeri casuali, più imprevedibile sarà il tuo gioco. Tuttavia, secondo gli studi di psicologia, la vera casualità a breve termine spesso sembra decisamente non casuale per l'uomo. Questo articolo mostra come rendere le decisioni casuali sull'IA e la logica di gioco più casuali per i giocatori, pur mantenendo una forte casualità statistica.

Potresti anche trovare interessante un altro capitolo:

Le statistiche dei numeri casuali

Riassunto: i numeri casuali sono utilizzati principalmente dall'intelligenza artificiale e dai giochi in generale. Ignorare il loro potenziale è rendere il gioco prevedibile e noioso. Usarli in modo errato può essere altrettanto grave che ignorarli apertamente. Comprendere come vengono generati i numeri casuali, i loro limiti e le loro capacità, può rimuovere molte difficoltà nell'utilizzarli nel gioco. Questo articolo offre informazioni su numeri casuali, la loro generazione e metodi per separare quelli buoni da quelli cattivi.


8

Sicuramente qualsiasi generazione di numeri casuali ha la possibilità di produrre tali tiri? Non otterrai un set di campioni abbastanza grande in 3-10 rotoli per vedere le percentuali appropriate.

Forse quello che vuoi è una soglia di misericordia ... ricorda gli ultimi 10 tiri, e se non hanno avuto un colpo critico, dai loro un omaggio. Appianare le imbragature e le frecce della casualità.


8

La tua soluzione migliore potrebbe essere testare il gioco con più schemi diversi non casuali e scegliere quello che rende i giocatori più felici.

Puoi anche provare una politica di back-off per lo stesso numero in un dato incontro, ad esempio, se un giocatore lancia un 1al primo turno, accettalo. Per ottenerne un altro 1devono tirare 2 1s di fila. Per ottenere un terzo 1hanno bisogno di 3 di fila, all'infinito.


7

Sfortunatamente quello che stai chiedendo è effettivamente un generatore di numeri non casuale, perché vuoi che i risultati precedenti siano presi in considerazione quando determini il numero successivo. Temo che non sia così che funzionano i generatori di numeri casuali.

Se vuoi che 1 colpo su 5 sia critico, scegli semplicemente un numero compreso tra 1 e 5 e dì che quel colpo sarà critico.


1
vuole un gioco casuale casuale, se usi rigidi numeri generati casuali in alcuni casi finisci per avere risultati "casuali coreani". Questi sono risultati casuali che fanno arrabbiare e frustrare i giocatori troppo spesso (chiedi a qualsiasi giocatore di lignaggio 2);)
Juan Techera,

Di conseguenza, se il primo colpo è un critico, i successivi quattro non lo saranno. Sembra che questo sia ciò che l'OP vuole, ma quando lo pronunci in questo modo, sembra ritardato. Ottieni il mio UV per quello.
belgariontheking,

-1 sembri confondere "random" con "memoryless" - en.wikipedia.org/wiki/Memorylessness
Alice Purcell

7

mt_rand () si basa su un'implementazione di Mersenne Twister , il che significa che produce una delle migliori distribuzioni casuali che puoi ottenere.

Apparentemente ciò che vuoi non è affatto casualità, quindi dovresti iniziare specificando esattamente cosa vuoi. Probabilmente ti renderai conto di avere aspettative contrastanti - che i risultati dovrebbero essere davvero casuali e non prevedibili, ma allo stesso tempo non dovrebbero mostrare variazioni locali rispetto alla probabilità dichiarata - ma poi diventerà prevedibile. Se imposti un massimo di 10 non-crits di seguito, allora hai appena detto ai giocatori "se hai avuto 9 non-crits di seguito, il prossimo sarà critico con certezza al 100%" - potresti beh, non preoccuparti affatto della casualità.


6

Su un numero così piccolo di test dovresti aspettarti risultati del genere:

La vera casualità è prevedibile solo su dimensioni enormi, in modo tale che è possibile lanciare una moneta e ottenere teste 3 volte di fila per la prima volta, tuttavia oltre qualche milione di lanci si arriva a circa 50-50.


7
Anche se c'è ancora la possibilità che dopo qualche milione di lanci, avrai ancora visto solo un lato della medaglia. Anche se ciò dovesse accadere, probabilmente ti siedi troppo vicino a un'infinita spinta di improbabilità: P
Grant Peters,

haha, sì ma la possibilità è così incredibilmente bassa che le leggi della matematica dicono che dovresti vedere una distribuzione uniforme (ish).
Ed James,

6

Vedo molte risposte che suggeriscono di tenere traccia dei numeri precedentemente generati o di mescolare tutti i possibili valori.

Personalmente, non sono d'accordo, il fatto che 3 crits di seguito siano cattivi. Né sono d'accordo sul fatto che 15 non-crits di fila siano cattivi.

Vorrei risolvere il problema, modificando la possibilità critica stessa, dopo ogni numero. Esempio (per dimostrare l'idea):

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
}

Più a lungo non ottieni un critico, maggiori sono le possibilità che hai per la tua prossima azione. Il ripristino che ho incluso è del tutto facoltativo e avrebbe bisogno di essere testato per capire se è necessario o meno. Può essere o meno desiderabile dare una maggiore probabilità di un critico per più di un'azione di seguito, dopo una lunga catena di azioni non critiche.

Sto solo gettando i miei 2 centesimi ...


Mi piace questo tipo di approccio. Probabilmente lo farei nell'altro modo. Inizia con una probabilità inferiore e accumula fino a un massimo del 20% + una percentuale aggiunta fino a quando non colpisce e ripristina nuovamente a un valore basso.
Matteo,

5

Le prime poche risposte sono grandi spiegazioni, quindi mi concentrerò solo su un algoritmo che ti dà il controllo sulla probabilità di "serie errate" senza diventare mai deterministico. Ecco cosa penso che dovresti fare:

Invece di specificare p , il parametro di una distribuzione di Bernoulli, che è la vostra probabilità di un colpo critico, specificare un e b , i parametri della distribuzione beta, il "coniugato prima" della distribuzione di Bernoulli. Devi tenere traccia di A e B , il numero di colpi critici e non critici finora.

Ora, per specificare un e b , in modo che a / (a + b) = p, la probabilità di un colpo critico. La cosa bella è che (a + b) quantifica quanto vuoi che A / (A + B) sia p in generale.

Fai il tuo campionamento in questo modo:

lascia che p(x)sia la funzione di densità di probabilità della distribuzione beta. È disponibile in molti luoghi, ma puoi trovarlo nella GSL come gsl_ran_beta_pdf.

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

Scegli un colpo critico campionando da una distribuzione di bernoulli con probabilità p_1 / (p_1 + p_2)

Se si scopre che i numeri casuali hanno troppi "cattivi striature", scalare una e B , ma al limite, come un e b andare all'infinito, si avrà l'approccio sacchetto casuale descritto in precedenza.

Se lo implementate, per favore fatemi sapere come va!


5

Se si desidera una distribuzione che scoraggi i valori di ripetizione, è possibile utilizzare un semplice algoritmo di rifiuto della ripetizione.

per esempio

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

Questo codice rifiuta i valori di ripetizione il 95% delle volte, rendendo le ripetizioni improbabili ma non impossibili. Statisticamente è un po 'brutto, ma probabilmente produrrà i risultati desiderati. Naturalmente, non impedirà una distribuzione come "5 4 5 4 5". Potresti diventare più fantasioso e rifiutare il secondo ultimo (diciamo) il 60% delle volte e il terzo ultimo (diciamo) il 30%.

Non sto raccomandando questo come un buon design del gioco. Semplicemente suggerendo come ottenere ciò che vuoi.


Alcuni valori nel mio gioco come il colpo critico non possono avere più del 50% di probabilità, quindi sto bloccando la ripetizione, ma questo riduce la possibilità di eventi per alcune percentuali.
Pensatore,

4

Non è davvero chiaro quello che vuoi. È possibile creare una funzione in modo tale che le prime 5 volte che la si chiama, restituisca i numeri 1-5 in un ordine casuale.

Ma non è davvero casuale. Il giocatore saprà che otterrà esattamente un 5 nei prossimi 5 attacchi. Potrebbe essere quello che vuoi, e in quel caso, devi semplicemente codificarlo da solo. (crea un array contenente i numeri e poi mescolali)

In alternativa, puoi continuare a utilizzare il tuo approccio attuale e supporre che i tuoi risultati attuali siano dovuti a un cattivo generatore casuale. Nota che nulla può essere sbagliato con i tuoi numeri attuali. I valori casuali sono casuali. a volte ottieni 2, 3 o 8 dello stesso valore in una riga. Perché sono casuali. Un buon generatore casuale garantisce che in media tutti i numeri verranno restituiti allo stesso modo spesso.

Naturalmente, se hai utilizzato un generatore casuale errato, ciò potrebbe aver distorto i risultati e, in tal caso, il semplice passaggio a un generatore casuale migliore dovrebbe risolvere il problema. (Controlla la libreria Boost.Random per generatori migliori)

In alternativa, potresti ricordare gli ultimi N valori restituiti dalla tua funzione casuale e pesare il risultato con quelli. (un semplice esempio potrebbe essere "per ogni occorrenza del nuovo risultato, c'è una probabilità del 50% di scartare il valore e ottenerne uno nuovo"

Se dovessi indovinare, direi che restare nella casualità "reale" è la soluzione migliore. Assicurati di utilizzare un buon generatore casuale, quindi continua nel modo in cui lo stai facendo ora.


In realtà, la funzione che sta usando è la stessa del miglior RNG nella libreria boost.
Michael Borgwardt,

MT non è il "migliore", per ultimo ho controllato. È bello, semplice e veloce, ma non produce la migliore distribuzione. Ad ogni modo, prendi un milione di numeri casuali e controlla la distribuzione. Scopri se la tua funzione casuale ti dà effettivamente una distribuzione uniforme o meno. In caso contrario, trova un generatore migliore. In tal caso, o succhialo e accetta la fila occasionale di crits, o imbroglia e rende i risultati meno casuali e più prevedibili.
jalf

4

È possibile creare un elenco contenente i numeri da 1 a 5 e ordinarli per casualità. Quindi basta scorrere l'elenco che hai creato. Hai la garanzia di incontrare ogni numero almeno una volta ... Quando hai finito con i primi 5, basta creare altri 5 numeri ...


4

Consiglio un sistema di percentuale progressivo come Blizzard utilizza: http://www.shacknews.com/onearticle.x/57886

Generalmente si lancia un RNG quindi lo si confronta con un valore per determinare se ha esito positivo o meno. Potrebbe apparire come:

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

Tutto quello che devi fare è aggiungere un aumento progressivo delle probabilità di base ...

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

Se ne hai bisogno per essere più fantasioso è abbastanza facile aggiungerne di più. Puoi limitare la quantità che progressiveChance può ottenere per evitare una probabilità critica del 100% o ripristinarla su determinati eventi. Puoi anche avere un aumento progressivo dihance in quantità minori ogni incremento con qualcosa come progressiveChance + = (1 - progressiveChance) * SCALE dove SCALE <1.


4

Bene, se sei un po 'in matematica, probabilmente puoi provare la distribuzione esponenziale

Ad esempio, se lambda = 0,5, il valore atteso è 2 (vai a leggere l'articolo!), Significa che molto probabilmente colpirai / crit / qualunque sia il 2 ° turno (come 50%, eh?). Ma con una tale distribuzione di probabilità, ti perderai sicuramente (o farai l'opposto di qualsiasi cosa) al 0 ° turno (quello, in cui l'evento si era già verificato e il turno_contro era stato resettato), ha circa il 40% di probabilità di colpire il turno successivo, circa il 65% possibilità di farlo 2 ° (successivo dopo successivo) turno, circa l'80% per colpire 3 ° e così via.

Lo scopo di quella distribuzione è se uno ha il 50% di probabilità di colpo e perde 3 volte di seguito, otterrà un colpo sicuro (beh, oltre l'80% di probabilità e aumenta ogni turno successivo). Porta a risultati più "equi", mantenendo invariata la probabilità del 50% in eccesso.

Prendendo la tua probabilità del 20% di crit, hai

  • 17% al primo turno critico
  • 32% al 2 ° turno critico, se non si verifica alcun critico in tutti i precedenti.
  • 45% al ​​terzo turno del critico, se non si verifica alcun critico in tutti i precedenti.
  • 54% al 4 ° turno critico, se non si verifica alcun critico in tutti i precedenti.
  • ...
  • 80% all'ottava volta del critico, se non si verifica alcun critico in tutti i precedenti.

È ancora circa lo 0,2% (contro quei 5%) possibilità di 3 crits + 2 non-crits in 5 turni conseguenti. E c'è una probabilità del 14% di 4 non-crits conseguenti, 5% di 5, 1,5% per 6, 0,3% per 7, 0,07% per 8 non-crits conseguenti. Scommetto che è "più equo" del 41%, 32%, 26%, 21% e 16%.

Spero che non ti annoi ancora a morte.


questo è abbastanza simile alla mia soluzione, tranne per il fatto che "ricorda" solo il tempo trascorso dall'ultimo colpo critico. Con questa soluzione, una stringa di 4 hit critici è uguale a una stringa di 1 hit critici per quanto riguarda le probabilità sul futuro. Quindi, se i colpi critici sono buoni, questa soluzione limita il rischio al ribasso, ma non il lato positivo. La mia soluzione riguarda entrambi.
Neil G,

È ovvio che diverse soluzioni hanno i loro vantaggi. Questo si concentra sul mantenere pulita la casualità dal punto di vista scientifico. Ciò non significa che sia in qualche modo migliore di una shuffle bag o di qualsiasi altra cosa. È solo una soluzione che sembra valere la pena provare.
Dark

3

Che ne dici di fare in modo che la possibilità di critico dipenda dagli ultimi attacchi N. Uno schema semplice è una specie di catena markov: http://en.wikipedia.org/wiki/Markov_chain ma il codice è comunque molto semplice.


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;

Ovviamente devi fare i tuoi calcoli perché la possibilità di un critico è inferiore alla possibilità di un critico una volta che sai che è stato abbastanza turni dall'ultimo


Ottieni la maggior parte dell'effetto semplicemente prendendo in considerazione l'ultimo attacco. Sia P la frequenza dei colpi osservata, R la frequenza dei colpi dopo un fallimento e R / 2 la frequenza dei colpi dopo un colpo. Per definizione, in qualsiasi momento hai quindi la possibilità di colpire P = P * R + (1-P) * (R / 2). Questo significa P = R / (2-R)
MSalters,

2

OPERAZIONE,

Praticamente, se vuoi che sia giusto, non sarà casuale.

Il problema del tuo gioco è l'effettiva durata della partita. Più lunga è la partita, minore sarà la casualità che vedrai (i crits tenderanno ad essere del 20%) e si avvicinerà ai tuoi valori previsti.

Hai due opzioni, pre-calcola gli attacchi in base ai tiri precedenti. Il che ti farà ottenere un critico ogni 5 attacchi (basato sul tuo 20%), ma puoi fare l'ordine in modo casuale.

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

Questo è lo schema che desideri. Quindi fatelo scegliere casualmente da quell'elenco, fino a quando è vuoto, lo ricreano.

Questo è uno schema che ho creato per il mio gioco, funziona abbastanza bene, per quello che voglio che faccia.

la tua seconda opzione, sarebbe, aumentare la possibilità di crit, probabilmente vedrai un numero più pari alla fine di tutti gli attacchi (supponendo che le tue partite finiscano piuttosto rapidamente). Meno probabilità%, più RNG hai.


2

Stai osservando una distribuzione lineare, quando probabilmente desideri una distribuzione normale.

Se ricordi di aver giocato a D&D in gioventù, ti è stato chiesto di tirare più dadi n, quindi sommare i risultati.

Ad esempio, tirare 4 dadi a 6 facce è diverso dal tirare 1 dado a 24 facce.


2

City of Heroes ha in realtà un meccanico chiamato "streakbreaker" che risolve esattamente questo problema. Il modo in cui funziona è che dopo una serie di miss di una lunghezza correlata alla probabilità di colpire più bassa nella stringa, il prossimo attacco è garantito per essere un colpo. Ad esempio, se perdi un attacco con oltre il 90% per colpire il caso, il tuo prossimo attacco colpirà automaticamente, ma se la tua probabilità di colpire è inferiore come il 60%, dovrai avere più missioni consecutive per innescare lo "streakbreaker" (I non conosco i numeri esatti)



0

Che ne dici di ponderare il valore?

Ad esempio, se hai una probabilità del 20% di un colpo critico, genera un numero compreso tra 1 e 5 con un numero che rappresenta un colpo critico o un numero compreso tra 1 e 100 con 20 numeri che sono un colpo critico.

Ma finché lavori con numeri casuali o pseudocasuali, non c'è modo di evitare potenzialmente i risultati che stai vedendo. È la natura della casualità.


E perché dovrebbe fare la differenza? Esiste esattamente la stessa probabilità di ottenere un valore critico per entrambi i gruppi di numeri.
Samjudson,

Esattamente. Sto solo presentando due opzioni per lui per il suo esempio del 20%. Sebbene 100 probabilmente funzionerebbe meglio se si ha a che fare con percentuali di numeri interi, poiché si dovrebbe solo simulare un "dado", se si desidera pensarlo in quel modo.
Thomas Owens,

Le opzioni che stai presentando sono esattamente ciò che sta già facendo.
Ceejayoz,

2
Non per quello che vuole. Vuole un generatore di numeri non casuale, anche se pensa che sia chiamato generatore di numeri casuali.
Ceejayoz,

0

Reazione su: "Il problema è che ho ottenuto risultati molto negativi nella vita reale - a volte i giocatori ottengono 3 punti critici in 5 colpi, a volte nessuno in 15 colpi".

Hai una possibilità tra il 3 e il 4% di non ottenere nulla in 15 colpi ...


Quando hai 3500 giocatori online che combattono 10000 battaglie in un minuto, il problema che si verifica nel 3% delle battaglie è un problema molto comune.
Pensatore

Inoltre, la sfortuna che si verifica nel 3% delle battaglie è ancora solo sfortuna.
MSalters,

0

Proporrei il seguente "die rimandato a caso":

  • Mantenere due array, uno ( in-array) inizialmente riempito con i valori da 0 a n-1, l'altro ( out-array) vuoto
  • Quando viene richiesto un risultato:
    • restituisce un valore casuale da tutti i valori definiti inin-array
    • sposta questo valore da in-arrayaout-array
    • spostare uno casuali (oltre tutti gli elementi, tra cui l'! indefinita) da elemento out-arraynuovo inin-array

Questa ha la proprietà che sarà "reagire" più lentamente il grande n è. Ad esempio, se vuoi una probabilità del 20%, impostare n su 5 e colpire su uno 0 è "meno casuale" rispetto all'impostazione n su 10 e colpire su uno 0 o 1 e renderlo da 0 a 199 su 1000 sarà quasi indistinguibile dalla vera casualità su un piccolo campione. Dovrai adattare n alle dimensioni del tuo campione.


0

Pre-calcola un colpo critico casuale per ogni giocatore.

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

0

Penso che forse stai usando la funzione di distribuzione casuale sbagliata. Probabilmente non vuoi una distribuzione uniforme sui numeri. Prova invece una distribuzione normale in modo che i colpi critici diventino più rari rispetto ai colpi "normali".

Lavoro con Java, quindi non sono sicuro di dove puoi trovare qualcosa per C ++ che ti dia numeri casuali con una distribuzione normale, ma ci deve essere qualcosa là fuori.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.