Función que devuelva numero aleatorios

AikonCWD

Alguien me ayuda con una duda (creo que bastante básica), sobre generación de números aleatorios? Quien está online por aquí?

AikonCWD

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.

1 respuesta
aren-pulid0

genera un numero aleatorio entre 1 y 10:
si es x < 5, devuelve 1
si 5 < x < 8, devuelve 2
y asi

1 respuesta
Fyn4r

#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

1 1 respuesta
AikonCWD

#3 #4 Vale, voy a intentarlo.

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

1 respuesta
Soulscx

[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
Asnarth

#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)

1 1 respuesta
n3krO

#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
}
1 respuesta
Kalgator

#1 Si es para Godot usa el randf()

con la formula de ellos

Asnarth

#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

AikonCWD

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

4 respuestas
EnderFX

#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?

Fyn4r

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

1 1 respuesta
Soulscx

no dejes en manos de la probabilidad todo eso, sino te puede salir un mapa con muchisima municion para 1 enemigo

2 respuestas
eondev

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

Kalgator

#14 Quiere hacer un mapa procedular xD, si no lo hace todo aleatorio... :new_moon_with_face:

pero como dicen soulscx y eondev, limitaría los items por mapa, y la distribución aleatoria xD

1 respuesta
HeXaN

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.

Fyn4r

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

n3krO

#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
}
1 1 respuesta
Soulscx

un juego q no sera goty

Hipnos

#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/

2 respuestas
Kalgator

#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

Soraghatsu

#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

B
r = Math.random();

a = .5; // 50%
b = .3; // 30%
// c = .2; // 20%

return 

r < a ? "el 1" 
    : r < (a + b) ? "el 2"
        : "el 3";
3
EnderFX

#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.

Ranthas

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

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:


https://imgur.com/a/N9H1CkV

Código: https://pastebin.com/Wz5nDCpH

2
Isidrus

No quiero ensuciar el hilo, pero leyéndoos me he acordado de esta tira de Dilbert.

7
B

#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];
4 2 respuestas
AikonCWD

#29 vaya crack. qué belleza de código

1