Herramienta de Selección Aleatoria
Herramienta de selección aleatoria justa para sorteos, elecciones y extracciones
¿Qué es un Sorteo Aleatorio?
Un selector aleatorio elige un elemento de una lista sin que una persona decida manualmente. Es útil para participación en clase, orden de intervención en reuniones, sorteos ligeros, asignación de tareas, elección de comida, dinámicas de equipo y cualquier situación donde una elección neutral visible ayuda a evitar sesgos. Esta página trabaja con una lista línea por línea, puede animar el sorteo, guardar historial local y evitar repeticiones retirando los elementos ya elegidos del grupo restante. La aleatoriedad puede hacer la selección justa en sentido estadístico, pero no valida identidades, no elimina automáticamente nombres duplicados ni aporta evidencia auditada. Para sorteos oficiales, cumplimiento, elegibilidad o premios, usa un proceso con registros y reglas.
Cómo usar
Pasos de operación
- Introduce las opciones en el cuadro de texto, una por línea
- Define el número de elementos a seleccionar
- Elige si se permiten duplicados
- Haz clic en el botón 'Iniciar sorteo'
- Consulta los resultados en el lado derecho
Consejos para sorteos justos
- Coloca un candidato por línea y elimina espacios o duplicados accidentales, salvo que los duplicados estén permitidos a propósito.
- Para sorteos públicos, define la semilla, la regla de duplicados y la regla de resorteo antes de comenzar para que el resultado sea más fácil de explicar.
Casos de uso
Principio técnico
El selector aleatorio se basa en la Web Crypto API (W3C, WHATWG), específicamente crypto.getRandomValues(typedArray), que es la única fuente de aleatoriedad criptográficamente segura expuesta en los navegadores. Internamente, el navegador llama al CSPRNG del sistema operativo: CryptGenRandom en Windows (AES-256 en modo CTR-DRBG desde Windows 10), getrandom(2) en Linux (que lee del mismo pool basado en ChaCha20 que alimenta /dev/urandom del kernel), SecRandomCopyBytes en macOS, y el equivalente en iOS, Android y BSD. La salida es adecuada para generación de claves, nonces, salts, IVs y cualquier lugar donde la previsibilidad sería un problema de seguridad. La distinción de 'grado criptográfico' importa. Math.random() en V8 usa xorshift128+ (un algoritmo rápido de baja entropía) y devuelve un float de 64 bits en [0, 1); un actor hostil que observe algunas salidas puede en principio reconstruir el estado de 128 bits y predecir cada valor futuro. Lo mismo ocurre con SpiderMonkey y JavaScriptCore. Esto hace que Math.random() no sea apto para cualquier uso donde el resultado debe ser impredecible — selección justa de un ganador, un token, una contraseña de un solo uso, una mano en un juego de cartas, una muestra de auditoría. crypto.getRandomValues(typedArray) es la única opción para esos casos. Mapear enteros uniformes de 32 bits a un índice uniforme en [0, N) sin sesgo de módulo es el segundo detalle de ingeniería que separa lo correcto de lo incorrecto. Ingenuamente, idx = randomUint32 % N es incorrecto: si N no divide 2³², los primeros 2³² mod N valores son ligeramente más probables. El algoritmo correcto es el muestreo por rechazo: calcular limit = 2³² - (2³² mod N); extraer un valor de 32 bits r; si r >= limit, extraer de nuevo; de lo contrario devolver r % N. El sesgo cae de O(N / 2³²) a cero. Para N = 2 o N potencia de 2 el módulo es exacto, pero el muestreo por rechazo es la opción segura por defecto y cuesta como máximo una reextracción en promedio (y siempre termina). El selector almacena los resultados en localStorage con una clave versionada, para que una sesión sobreviva a una recarga de página y el usuario pueda revisar el historial de sorteos. El historial no está cifrado ni firmado — es local, no sensible y fácil de borrar. Para el modo sin repeticiones, el algoritmo extrae sin reemplazo usando un barajado parcial de Fisher-Yates: en el paso k de N, intercambia el elemento k con un elemento elegido uniformemente en [k, N) y bloquea el elemento k como extraído. Esto es O(N) en tiempo, O(1) en espacio extra, y da a cada permutación la misma probabilidad, que es la garantía combinatoria correcta. (El ingenuo 'extraer N veces, rechazando repeticiones' también es correcto pero O(N²) y puede estancarse en sesiones largas.) Para selecciones ponderadas (cada opción tiene su propia probabilidad), el algoritmo estándar es el muestreo de CDF inverso con un array de suma de prefijos: construir una suma de prefijos de pesos, extraer un real uniforme en [0, total) y búsqueda binaria para el menor i tal que prefix[i] >= u. Eso es O(log N) por extracción, y la suma de prefijos se construye una vez por cambio. El método de alias (Walker-Vose) da O(1) por extracción al costo de O(N) de configuración, lo que vale la pena solo cuando N es grande y la distribución es fija.
- Fuente de aleatoriedad: crypto.getRandomValues(typedArray) — el único RNG criptográficamente seguro en navegadores, respaldado por el CSPRNG del SO (AES-256 CTR-DRBG en Windows 10+, ChaCha20 en Linux/macOS/iOS/Android).
- Math.random() es xorshift128+ en V8 (y variantes en otros motores): rápido pero predecible. Nunca usarlo para selección justa, tokens, OTPs o muestras de auditoría — solo para ruido visual, animaciones o muestreo no seguro.
- Mapeo de índice sin sesgo: muestreo por rechazo, no módulo. Calcular limit = 2³² - (2³² mod N); si el uint32 aleatorio >= limit, extraer de nuevo; si no, devolver r % N. Evita el clásico 'sesgo de módulo' donde índices de rango corto aparecen más frecuentemente.
- Extracciones sin repeticiones usan barajado parcial de Fisher-Yates en O(N) tiempo, O(1) espacio: en el paso k intercambiar elemento k con un elemento uniforme en [k, N), luego bloquear k. Cada permutación es igualmente probable.
- Selecciones ponderadas usan muestreo de CDF inverso: construir suma de prefijos de pesos una vez, extraer un real uniforme en [0, total), búsqueda binaria para el menor prefix[i] >= u. O(log N) por extracción.
- El historial de sorteos se persiste en localStorage con una clave versionada, para que una sesión sobreviva a una recarga de página. El historial es solo local y no sensible en seguridad — limpiar desde la UI al terminar.
- Fisher-Yates vs 'extraer N veces con rechazo': ambos son correctos en distribución, pero Fisher-Yates es O(N) total y O(1) memoria, mientras que el rechazo ingenuo es O(N²) en el peor caso (muchas repeticiones cerca del final de una lista larga).
- Rango y tipos de salida: getRandomValues acepta Int8Array, Uint8Array, Int16Array, Uint16Array, Int32Array, Uint32Array, BigInt64Array, BigUint64Array — y la página siempre usa Uint32Array para alimentar el paso de mapeo de índices.
Ejemplos
Sorteo sin repeticiones desde una lista de candidatos
Lista de entrada (uno por línea):
Alice
Bob
Charlie
David
Eve
Frank
Permitir duplicados: OFF Selecciones: 3
Resultado:
#1: Charlie
#2: Alice
#3: Frank
(Bob, David, Eve siguen en el grupo)
La página llama a crypto.getRandomValues() sobre un Uint32Array para generar
un entero uniforme en [0, n) en cada sorteo, donde n es el número de
candidatos restantes. Cada nombre tiene la misma probabilidad 1/n en cada
selección, y el índice elegido se fija antes de que comience la animación.Sorteo con repeticiones e historial con marca de tiempo
Lista de entrada (uno por línea):
Cara
Cruz
Permitir duplicados: ON Selecciones: 5
Resultado:
#1 (14:23:01): Cara
#2 (14:23:01): Cruz
#3 (14:23:01): Cara
#4 (14:23:01): Cara
#5 (14:23:01): Cruz
En modo con repetición la misma entrada puede ser elegida en sorteos consecutivos,
y el grupo nunca se reduce. La marca de tiempo del sorteo se añade a cada registro
para que la misma lista de candidatos pueda reutilizarse entre rondas mientras el
historial muestra exactamente cuándo ocurrió cada selección. Borra los registros
por separado de la lista de candidatos: se almacenan bajo claves distintas de
localStorage.Snippet JavaScript para la selección subyacente
// Elige un índice de [0, n) usando Web Crypto (CSPRNG)
function pickIndex(n) {
// crypto.getRandomValues da un valor uniforme de 32 bits; el módulo n
// es seguro aquí porque n es como mucho unos pocos miles para un sorteo de lista,
// y el sesgo del módulo es despreciable (2^32 / n es grande).
const buf = new Uint32Array(1);
crypto.getRandomValues(buf);
return buf[0] % n;
}
// pickIndex(6) -> p. ej. 4 (Charlie en el ejemplo anterior)
// pickIndex(2) -> 0 o 1 (Cara o Cruz)
//
// Nota: para grupos enormes donde n se aproxima a 2^32, usa muestreo por rechazo
// para eliminar el sesgo del módulo, p. ej.:
// const limit = Math.floor(0xFFFFFFFF / n) * n;
// let r; do { crypto.getRandomValues(buf); r = buf[0]; } while (r >= limit);Comprobación de equidad sobre 1.000 sorteos
Lista: ['A', 'B', 'C', 'D'] (4 entradas, proporción esperada 25,0%)
Sorteos: 1.000 Permitir duplicados: ON
Observado:
A: 247 (24,7%)
B: 256 (25,6%)
C: 248 (24,8%)
D: 249 (24,9%)
Una ejecución de 1.000 sorteos con crypto.getRandomValues debería caer dentro de
unos +/- 3 puntos porcentuales de la proporción esperada en cada entrada;
desviaciones mayores (p. ej. una entrada al 35%) suelen indicar que la
implementación llama a Math.random() o aplica mal el módulo. Para una rifa
regulada, guarda la lista fuente, la fuente de la semilla aleatoria (entropía
del navegador/SO), la marca de tiempo del sorteo y una firma de testigo:
localStorage no es un sistema de registro duradero.Preguntas frecuentes
¿La selección es realmente aleatoria?
Sí. La selección utiliza crypto.getRandomValues de la Web Crypto API, que es criptográficamente sólida. Cada opción tiene la misma probabilidad a menos que configures pesos.
¿Puede salir la misma opción dos veces seguidas?
Sí, así funciona la selección aleatoria independiente. Con 5 opciones, la probabilidad de que salgan dos iguales seguidas es 1/5 = 20 %. Si no quieres repeticiones, activa 'eliminar tras la selección', que extrae sin reposición hasta vaciar la lista.
¿Cómo se gestiona 'elegir N elementos'?
Por defecto muestrea sin reposición: cada elemento puede salir como máximo una vez por extracción de N. Activa 'con reposición' si los duplicados son aceptables (por ejemplo, asignar N tareas a una misma persona). En modo sin reposición, N no puede superar el tamaño de la lista de opciones.
¿Puedo añadir pesos para sesgar las elecciones?
Algunas versiones admiten pesos por opción (p. ej. opción A peso 3, opción B peso 1: A tiene 3 veces más probabilidades). La página normaliza los pesos a probabilidades. Sin pesos, todas las opciones tienen la misma probabilidad.
¿Por qué es más justo que elegir 'a ojo'?
Los humanos somos malos siendo aleatorios: tendemos a evitar elecciones recientes, a sobreelegir opciones llamativas y a sesgarnos inconscientemente hacia los nombres que reconocemos. Una elección por ordenador elimina ese sesgo, lo que hace que las decisiones tipo sorteo se sientan más limpias para los participantes.
¿Se guarda mi lista?
Algunas versiones la guardan en localStorage para que persista en el mismo navegador. Si cierras la pestaña o cambias de navegador, se pierde a menos que la hayas exportado. Nada se sube a un servidor.
¿Debería usarlo para loterías legales?
No. Los sorteos, loterías y rifas legales requieren procedimientos aleatorios auditables, a menudo hardware físico o RNG certificado. Una herramienta web genérica no está documentada ni auditada: úsala solo para sorteos de oficina y rifas informales.