Alguien me ayuda con una duda (creo que bastante básica), sobre generación de números aleatorios? Quien está online por aquí?
Quiero hacer una función que me devuelva un número semi-random, entre 0 y 3.
Por ejemplo, cada vez que llamen a la función, haya un 50% de probabilidad que devuelva 0 o 1
Un 30% de probabilidad que devuelva 2
Un 10% de probabilidad que devuelva 3
Pudiendo dejar el % de probabilidad editable.
#2 La distribución uniforme es tu amiga.
Partes de un número 'x' random entre 0 y 1:
- x < 0.5 -> devuelves 0 o 1 (si este resultado es aleatorio pues otro random)
- 0.5 < x < 0.8 -> devuelves 2
- 0.8 < x < 1 -> devuelves 3
En tu ejemplo no cubre el 100% pero asumo que fue un fallo al ponerlo xD
Os pongo en contexto: Quiero generar un mapa, y en los espacios libres quiero generar un item:
0 = nada
1 = moneda
2 = arma
3 = enemigo
Me interesa que el mapa esté la mitad vacio o con monedas (probabilidad del 50% de sacar 0 o 1)
Y luego que hayan más armas que enemigos, pero siempre en menor cantidad que monedas.
No sé si me explico bien xd. Voy a poner vuestro ejemplo a ver como queda
[0,0,0,0,0,1,1,1,1,1,2,2,2,3,3], sacas un random (0,nºcasillas mapa) y lo extraes del array para q no se repita y a campionar
#1 ¿Supongo que algo así te valdría?
float prob = Math.random();
int ret;
if (prob < 0.5) {
float prob2 = Math.random();
if (prob2 < 0.5) ret = 0;
else ret = 1;
} else if (prob < 0.8) {
ret = 2;
} else {
ret = 3;
}
Math.random sería el típico método que devuelven un random entre [0, 1)
#7 no me gusta como eliges el 0 o 1....
if prob<0.25 {
return 0;
} else if prob<0.5 {
return 1;
} else if prob<0.8 {
return 2;
} else {
return 3
}
#8 Ya, me he ajustado lo más literal posible a lo que ha especificado, excepto en la parte en la que las probabilidades no suman un 100% jajaja
Vale, ese sistema no escala demasiado bien pero bueno... He puesto un ejemplo con 4 números y 3 probabilidades... imagina que tengo 20 números con 20 probabilidades diferentes, y que quiero ir cambiando esos valores para ver como queda el resultado. En fin, que asco xd
#5 Haz una función que:
Asigna un peso a cada uno de los elementos de la distribución, o reciba estos pesos. Por ejemplo: moneda 0.4, arma 0.2, enemigo 0.5.
Suma los pesos. Asigna a cada elemento un offset, que será la suma de los pesos de los anteriores.
Haz un random entre 0 y la suma de los pesos.
Devuelve el elemento con ese offset.
Te vale en javascript?
Realmente puedes crear números aleatorios con la distribución que te de la gana. La uniforme funciona muy bien generalmente porque la probabilidad de caer en un rango concreto (0.2 - 0.7 por ejemplo) es tamaño de dicho rango (0.5).
Si ves que no te vale puedes probar otras distribuciones, por ejemplo, imagina que quieres que las monedas tiendan a concentrarse en un punto del mapa (por el medio, por ejemplo) podrías utilizar una distribución normal:
De esta forma utilizas las coordenadas como puntos en el eje (o una bidimensional, vamos xD). El alto de la curva habla de la probabilidad del rango concreto, más alta, más probable
no dejes en manos de la probabilidad todo eso, sino te puede salir un mapa con muchisima municion para 1 enemigo
Te recomiendo que para el tema del juego no uses la "aleatoriedad" para la posición de los items, sino que juegues con las cantidades y con la distribución para hacerla a tu gusto siguiendo siempre las reglas que pones. De lo contrario, te podrían salir mapas bastante bastante malos y muy mal distribuidos. Justo lo que dice #13
#14 Quiere hacer un mapa procedular xD, si no lo hace todo aleatorio...
pero como dicen soulscx y eondev, limitaría los items por mapa, y la distribución aleatoria xD
Haz una una curva como te han dicho y listo.
Yo lo hago constantemente en el trabajo para generar funciones que dan pesos a distintos rangos.
La aleatoriedad se puede pastorear como una vaca, por eso no os preocupeis xD
#11 Hay funciones que te permiten pasar una lista de pesos y ya ella va haciendo. Si no, igual te toca hacerla, si ves que va a crecer quita los ifs xD
#11 Es que si quieres probabilidades distintas dictadas por ti es lo que hay :/
Lo de cambiar los valores, puedes definir las probabilidades por constantes y sumarlas para los if:
const float PROB_0 = 0.25;
const float PROB_1 = 0.25;
const float PROB_2 = 0.3;
if prob<PROB_0 {
return 0;
} else if prob<PROB_0+PROB_1 {
return 1;
} else if prob<PROB_0+PROB_1+PROB_3 {
return 2;
} else {
return 3
}
#11 Lo más sencillo es que generes una semilla con un array de posibles resultados y otro array de pesos relativos.
Elemento_1 {
Semillas = [hueco, moneda, enemigo, powerup, boss]
Pesos = [1, 0.3, 0.4, 0.02, 0.01]
}
Luego haces la distribución random en función de los pesos totales y relativos.
Aquí tienes una biblia de cómo se programan juegos de verdad: https://gameprogrammingpatterns.com/
#19 Ahi estás teniendo un problema, y es que estás concatenendo if así que solo puedes tener 4 resultados, el quiere escalarlo a mas, y tendría que hacer un bucle
#11 un método que le mandas un mapa del estilo {K = el numero que quieres que te devuelva, V = el % de salir}
este método lo incluyes a la hora de generar el nivel/pantalla o como lo llames, y que cuando genere el nivel recorra ese mapa.
Espero que te ayude
r = Math.random();
a = .5; // 50%
b = .3; // 30%
// c = .2; // 20%
return
r < a ? "el 1"
: r < (a + b) ? "el 2"
: "el 3";
#1
Función:
const roll = (itemWeights = {}) => {
const {weightOffsets, totalWeight} = Object.keys(itemWeights).reduce((res, itemName) => {
const itemWeight = itemWeights[itemName];
const newTotalWeight = res.totalWeight + itemWeight;
return {
weightOffsets: [...res.weightOffsets, {itemName, from: res.totalWeight, to: newTotalWeight }],
totalWeight: newTotalWeight
};
}, {weightOffsets: [], totalWeight: 0});
const r = Math.random() * totalWeight;
const offset = weightOffsets.find(offset => r >= offset.from && r < offset.to);
return offset ? offset.itemName : null;
}
Ejemplo de pesos:
const pesos = {
moneda: 0.5,
enemigo: 0.2,
dildo: 0.7
};
Llamar a la función 10 veces:
(new Array(10).fill(null)).forEach(_ => console.log(roll(pesos)));
Lo que dicen #21 y #26. Pesos relativos sobre el peso total. Él lo ha hecho con dos arrays, yo te lo he puesto con un dict/hashMap/objeto JS.
Si lo quiere hacer escalable, lo que dice #21 es la solución.
Además, puede modificar el objeto para añadir restricciones mas adelante, es decir, crear algo asi:
Hueco {
minimo: 10,
maximo: 20
}
Vale, al final he optado por los if anidados, pese a que no escalan bien. Como de momento tengo pocos items pues no es mayor problema. He dejado el código lo más limpio que he podido:
Código: https://pastebin.com/Wz5nDCpH
#24 escalado...
const porcentajes = [.5, .3, .2];
const elementos = ["el 1", "el 2", "el 3"];
const cantidad = porcentajes.length - 1;
const random = Math.random();
for (let i = 0, j = 0; i < cantidad; i++) {
j += porcentajes[i];
if (random < j) { return elementos[i]; }
}
return elementos[cantidad];