Generador de números aleatorios de JavaScript que se puede inicializar con una semilla
La función de JavaScript Math.random() devuelve un valor aleatorio entre 0 y 1, sembrado automáticamente según la hora actual (similar a Java, creo). Sin embargo, no creo que haya forma de establecer tu propia semilla para ella.
¿Cómo puedo hacer un generador de números aleatorios al que pueda proporcionar mi propio valor de semilla, de modo que pueda hacer que produzca una secuencia repetible de números (pseudo)aleatorios?
Respuesta #1
Si no necesitas la capacidad de inicialización, simplemente usa Math.random() y construye funciones auxiliares alrededor de ella (por ejemplo, randRange(start, end)).
No estoy seguro de qué RNG estás usando, pero es mejor conocerlo y documentarlo para que estés al tanto de sus características y limitaciones.
Como dijo Starkii, Mersenne Twister es un buen PRNG, pero no es fácil de implementar. Si quieres hacerlo tú mismo, intenta implementar un LCG: es muy fácil, tiene cualidades de aleatoriedad decentes (no tan buenas como Mersenne Twister) y puedes usar algunas de las constantes populares.
EDICIÓN: considere las excelentes opciones en esta respuesta para implementaciones de RNG semillables y cortas, incluyendo una opción LCG.
function RNG(seed) {
// LCG using GCC's constants
this.m = 0x80000000; // 2**31;
this.a = 1103515245;
this.c = 12345;
this.state = seed ? seed : Math.floor(Math.random() * (this.m - 1));
}
RNG.prototype.nextInt = function() {
this.state = (this.a * this.state + this.c) % this.m;
return this.state;
}
RNG.prototype.nextFloat = function() {
// returns in range [0,1]
return this.nextInt() / (this.m - 1);
}
RNG.prototype.nextRange = function(start, end) {
// returns in range [start, end): including start, excluding end
// can't modulu nextInt because of weak randomness in lower bits
var rangeSize = end - start;
var randomUnder1 = this.nextInt() / this.m;
return start + Math.floor(randomUnder1 * rangeSize);
}
RNG.prototype.choice = function(array) {
return array[this.nextRange(0, array.length)];
}
var rng = new RNG(20);
for (var i = 0; i < 10; i++)
console.log(rng.nextRange(10, 50));
var digits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
for (var i = 0; i < 10; i++)
console.log(rng.choice(digits));Respuesta #2
Si quieres poder especificar la semilla, solo necesitas reemplazar las llamadas a getSeconds() y getMinutes(). Podrías pasar un int y usar la mitad de él módulo 60 para el valor de los segundos y la otra mitad módulo 60 para darte la otra parte.
Dicho esto, este método parece basura. Hacer una generación adecuada de números aleatorios es muy difícil. El problema obvio con esto es que la semilla del número aleatorio se basa en segundos y minutos. Adivinar la semilla y recrear tu flujo de números aleatorios solo requiere probar 3600 combinaciones diferentes de segundos y minutos. También significa que solo hay 3600 semillas posibles diferentes. Esto es corregible, pero yo sería sospechoso de este RNG desde el principio.
Si quieres usar un RNG mejor, prueba el Mersenne Twister. Es un RNG bien probado y bastante robusto, con un órbita enorme y un rendimiento excelente.
EDICIÓN: Realmente debería ser correcto y referirme a esto como un Generador de Números Pseudoaleatorios o PRNG.
&
Respuesta #3
Uso un puerto de JavaScript del Mersenne Twister: https://gist.github.com/300494. Te permite establecer la semilla manualmente. Además, como se menciona en otras respuestas, el Mersenne Twister es un PRNG realmente bueno.
