De hecho, escribí un código para hacer esto . La esencia de esto es usar estadísticas para corregir rayas desafortunadas. La forma en que puede hacer esto es hacer un seguimiento de cuántas veces se ha producido el evento y utilizarlo para sesgar el número generado por el PRNG.
En primer lugar, ¿cómo hacemos un seguimiento del porcentaje de eventos? La manera ingenua de hacer esto sería mantener todos los números generados en la memoria y promediarlos: lo que funcionaría pero es terriblemente ineficiente. Después de pensar un poco, se me ocurrió lo siguiente (que es básicamente un promedio móvil acumulativo ).
Tome las siguientes muestras de PRNG (donde procesamos si la muestra es> = 0.5):
Values: 0.1, 0.5, 0.9, 0.4, 0.8
Events: 0 , 1 , 1 , 0 , 1
Percentage: 60%
Tenga en cuenta que cada valor contribuye a 1/5 del resultado final. Miremos de otra manera:
Values: 0.1, 0.5
Events: 0 , 1
Observe que 0
contribuye al 50% del valor y 1
contribuye al 50% del valor. Tomado un poco más lejos:
Values: [0.1, 0.5], 0.9
Events: [0 , 1 ], 1
Ahora los primeros valores aportan el 66% del valor y el último 33%. Básicamente podemos destilar esto al siguiente proceso:
result = // 0 or 1 depending on the result of the event that was just generated
new_samples = samples + 1
average = (average * samples / new_samples) + (result * 1 / new_samples)
// Essentially:
average = (average * samples / new_samples) + (result / new_samples)
// You might want to limit this to, say, 100.
// Leaving it to carry on increasing can lead to unfairness
// if the game draws on forever.
samples = new_samples
Ahora necesitamos sesgar el resultado del valor muestreado del PRNG, porque vamos por un porcentaje de probabilidad aquí, las cosas son mucho más fáciles (en comparación con, por ejemplo, cantidades aleatorias de daño en un RTS). Esto va a ser difícil de explicar porque "se me ocurrió". Si el promedio es más bajo, significa que debemos aumentar las posibilidades de que ocurra el evento y viceversa. Entonces algunos ejemplos
average = 0.1
desired = 0.5
corrected_chance = 83%
average = 0.2
desired = 0.5
corrected_chance = 71%
average = 0.5
desired = 0.5
corrected_change = 50%
Ahora, lo que se me ocurrió 'es que en el primer ejemplo, el 83% era solo "0.5 de 0.6" (en otras palabras, "0.5 de 0.5 más 0.1"). En términos de eventos aleatorios, eso significa:
procced = (sample * 0.6) > 0.1
// or
procced = (sample * 0.6) <= 0.5
Entonces, para generar un evento, básicamente usarías el siguiente código:
total = average + desired
sample = rng_sample() * total // where the RNG provides a value between 0 and 1
procced = sample <= desired
Y por lo tanto, obtienes el código que puse en la esencia. Estoy bastante seguro de que todo esto se puede usar en el escenario de caso de daño aleatorio, pero no me he tomado el tiempo para resolverlo.
Descargo de responsabilidad: se trata de estadísticas nacionales, no tengo educación en el campo. Sin embargo, mis pruebas unitarias sí pasan.