PDA

Ver la Versión Completa : sacar numeros al azar


edlm
22-04-2006, 22:22:30
hola, quiero saber si se puede sacar 20 numeros al azar sin que se repitan, es decir con la funcion random dentro de un for puedo obtener numeros al azar pero con frecuencia estos numero se repiten, habrá alguna forma para evitarlo o tendra que hacerse con sentecias de If, si aguien sabe de alguna forma para hacerlo agradeceria el consejo.

Gracias

alextmb
22-04-2006, 22:27:53
hola amigo yo estoy en las mismas mira a ver si entrelos dos lo sacamos o alguien nos auxilia, tengo que hacer que en 40 images, que tengo en un arreglo llamado Carta asignarles un numero al azar del uno al 20 pero solo se pueden repetir una vez mira lo que he hecho
for a:=1 to 20 do
begin
Repeat
fin:=20
Randomize;
num:=random(20)+1;
z:=true;
for c:=1 to fin do
begin
if num=Carta[c].Tag then
begin
z:=false;
fin:=0;
end
end;
Until(z=true);
Carta[a].Tag:=num;
end;


avisame que te parece

seoane
22-04-2006, 23:03:40
En un juego de cartas yo usaba este metodo para barajar. A lo mejor te sirve:


var
Baraja: array[1..40] of Integer;
i,j,k: Integer;
begin
// Colocamos todas las cartas por orden
for i:= 1 to 40 do
begin
Baraja[i]:= i;
end;
// Y ahora las barajamos
Randomize;
for i:= 1 to 40 do
begin
j:= Random(40)+1;
k:= Baraja[i];
Baraja[i]:= Baraja[j];
Baraja[j]:= k;
end;
end;

edlm
23-04-2006, 01:13:10
Alextmb, tu codigo casi no lo comprendo, ¿a ti te funciona?, analisando el de el amigo seoane ese me ha dejado una idea mas clara, debido a que talvez hacer que con un random obtengamos 20 numeros que no se repitan seria muy compicado, parece mejor la idea de desordenar un arreglo de 20 numeros para que el orden sea distinto cada vez, así como el lo hizo al barajear las cartas yo lo implementare asi si tienen algun comentario me avisan.

alextmb
23-04-2006, 01:34:22
estoy de acuerdo contigo me complique mucho la vida. Pero bueno de los errores se aprende.

edusus
23-04-2006, 20:03:59
Pienso que la solución puede ser la siguiente.

begin
randomize;
x:= random(20)+ 1;
Label (1 to 20). caption:= x;
If Tlabel. any caption has repeated number do
begin
Replace that number for another;
end;
end;

:D :D :D
No os enfadeis amigos, es una broma jajajaja

Turboleta
23-04-2006, 23:52:21
Tambien se puede podría hacer otra cosa.
1º declarar un array para contener lo números que van saliendo, sin repetir.
2º declarar una variable de tipo conjunto para poder controlar si y han salido antriormente.Poco más o menos así:

var NumOk: array [1..20] of integer;
YaUtiliados: set of Byte; // de 0..255
n, num: integer;
begin
YaUtilizados:= [] // conjunto vacío; no hay números
randomize;
for n:= 1 to 20 do
begin
Repeat
num:= random(20) + 1;
Until not (num in YaUtilizados);// se comprueba si el número ya existe en el conjunto

NumOk[n]:= num; // Si el núnero no ha sido utilizado anteriormente, se guarda en el array
YaUtilizados:= YaUtilizados + [num] // y a la vez se añade al conjunto
end;

Bueno, es posible que haya alguna incorrección, pero básicamente esta es la idea. Así no tendrías ningún número repetido.

Espero te sirva la idea.

Delphius
24-04-2006, 04:32:29
Bueno, la mejor manera de obtener números "aletorios" (y sencilla) es emplear un generador de número aleatorios por el método multiplicativo de amplitud máxima.
Yo tuve que codificar estos algoritmos... es más.. tuve algunos inconvenientes y aquí me ayudaron a solucionarlos. En ese entonces, yo había subido el código... pero creo que a causa de la pérdida de algunos datos del disco del servidor se perdió ese hilo. Le paso un zip con el código. Veanlo...

Se puede conseguir que se generen números que no se repitan en la serie (amplitud máxima) si se consigue que exista una relación de números primos entre el valor m (módulo) y el a (multiplicativo).

edusus
24-04-2006, 10:09:05
Hola Turboleta,
he copiado tu código pero lo que no encuentro la forma de hacer es ver el contenido del conjunto yautilizados. Puedes decirme como hacer? y si no te importa otra pregunta. ¿Si lo que yo quiero es obtener por ejemplo 5 números aleatorios de un conjunto del 1 al 20, cómo lo podría hacer?
Muchas gracias por tu ayuda.

roman
24-04-2006, 17:18:50
El método de Turboleta es lo que yo hubiera pensado y alguna vez hecho. Sin embargo hay que ver que la propuesta de Seoane es muy interesante al no requerir de un doble ciclo. Habrá que revisar el código que amablemente nos ofrece Delphius. Lo que no sé es si alguno de los algoritmos que pone está ya hecho para evitar repeticiones.

// Saludos

Joakin
24-04-2006, 19:54:14
Amigos , aunque no hice yo la pregunta me interesa mucho el tema.
Copié la propuesta de seoane pero lo que no sé es como ver el resultado.
Con algún showmessage(), o en una label . Y como llamo a que se vea .
Si alguien me lo pudiera explicar me gustaría mucho saberlo. Gracias.

seoane
24-04-2006, 20:20:06
El metodo que yo explique era para barajar una supuesta baraja de cartas representada por un array. De forma que cada posicion del array corresponde al lugar que ocuparia dentro de la baraja, es decir, Baraja[1] nos diria cual es la primera carta, Baraja[2] la segunda, etc ... Aclaro esto porque creo que aunque para este fin el metodo es bastante eficiente, para otros fines, como puede ser ir sacando uno a uno numeros al azar sin saber previamente cuantos, el metodo de Turboleta puede se mas eficaz.

Aclarado esto, para poder visualizar el resultado solo tienes que recorrer el array elemento a elemento.


var
Baraja: array[1..40] of Integer;
i,j,k: Integer;
s: string;
begin
// Colocamos todas las cartas por orden
for i:= 1 to 40 do
begin
Baraja[i]:= i;
end;
// Y ahora las barajamos
Randomize;
for i:= 1 to 40 do
begin
j:= Random(40)+1;
k:= Baraja[i];
Baraja[i]:= Baraja[j];
Baraja[j]:= k;
end;
s:= IntToStr(Baraja[1]);
for i:= 2 to 40 do
s:= s + ',' + IntToStr(Baraja[i]);
ShowMessage(s);
end;

Delphius
24-04-2006, 22:04:17
La soluciòn más correcta es que se emplee el generador multiplicativo, junto con el conjunto YaUtilizados que emplea Turboleta. No se si me explico: la idea es emplear el generador, y a medida que genera... ingresarlo en el conjunto.
no sé es si alguno de los algoritmos que pone está ya hecho para evitar repeticiones
Pues no. El método es muy simple... no tiene en cuenta eso, pero una propiedad de este generador es que si se eligen cuidadosamente los valores de "m" y "a" se puede obtener una serie de números que no se repiten. Aunque también puede modificarse el código para que maneje el conjunto que emplea Turboleta.
el valor de "m" no solo da la condición de cuantos números deben generarse... sino que además, que impone el valor máximo que se permitirá. Si más no me equivoco para los interesados aquí... deberá tomar 20.
Yo probaría con (no estoy muy seguro):
m = 20
a = 7
semilla = 3

Saludos,

roman
24-04-2006, 22:13:13
Hola Carlos,

Lo que no entiendo entonces es por qué no usar el algoritmo que ya incluye Delphi en su función Random.

// Saludos

Delphius
24-04-2006, 22:24:59
Lo que no entiendo entonces es por qué no usar el algoritmo que ya incluye Delphi en su función RandomLa función Random tiene una distribución uniforme, o en términos simples: plana. Esto quiere decir que todos los números tienen igual probabilidad de salir. Lo que la convierte en una función no muy aleatoria que digamos.
El generador multiplicativo tiene una distribución casi uniforme, pero tampoco es una distribuciòn normal (forma de compana). Pero es mejor que la función random() que viene incorporada en Delphi.

Delphius
25-04-2006, 04:29:54
Cuando dije:

el valor de "m" no solo da la condición de cuantos números deben generarse... sino que además, que impone el valor máximo que se permitirá. Si más no me equivoco para los interesados aquí... deberá tomar 20

Me expresé mal, "m" sólo impone el valor máximo, y no necesariamente la serie. Lo que pasa, es que en forma "indirecta"... el valor de "m" condiciona la serie. La particularidad de este generador es que si se cumplen ciertas condiciones, (disculpen.. en este momento no tengo mis apuntes de modelo y simulación a mano y no me acuerdo de como es el corolario), se puede garantizar que en la serie de "m" elementos... no habrá ningun repetido.

Es otro punto a favor por el cual usaría este método y no la simple Random.;)
Saludos,

Joakin
25-04-2006, 08:59:36
Muchas gracias y ahora veo que modificando el segundo form (con la variable s) puedo de esas 40 pedir que solo aparte algunas al azar y sin repetirse, que es lo que me interesaba. Muy bien y gracias

Turboleta
26-04-2006, 21:01:30
Edusus, siento no haberte respondido antes. Llevo un par de días sin entrar en el foro.

Respecto al contenido del conjunto YaUtilizados no se puede ver directamente. Sí puedes saber si un número está incluido en él.

if num in YaUtilizados then ShowMessage('El número ' + IntToStr(num) + ' sí existe');

Respecto a elegir 5 numeros compredidos entre 1 y 20, te sirve el mismo algoritmo de mi post anterior cambiando el for de 1 a 20 por de 1 a 5.


Un saludo.

Turboleta
26-04-2006, 21:07:34
Edusus, con las prisas se me olvidó decirte que donde realmente puedes y debes ver los números es en el array NumOk.

Hasta otra.

silem23
31-05-2012, 16:30:11
Increible que este tema aun sigue vigente, muchas gracias a todos los que en su momento se tomaron el tiempo para responder el hilo que me ha sido de mucha ayuda saludos

Casimiro Notevi
31-05-2012, 21:50:40
Todos los hilos siguen vigentes, fíjate que es del 2006, pero no acostumbramos a cerrarlos por si surgen nuevas propuestas, ideas, etc. o como tu caso, aunque sea para agradecir de que te ha sido de ayuda.
Saludos.