Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: David8 en 8 Abril 2014, 15:45 pm



Título: Duda función barajar
Publicado por: David8 en 8 Abril 2014, 15:45 pm
Hola, tengo el siguiente fragmento de programa:
Código:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>

void baraja( int wMazo[][13] );
// código

int main (void)
{
   //código
   int mazo[4][13] = {0};
   srand(time(0));
   baraja(mazo);
   //código
   return EXIT_SUCCESS;
}

void baraja( int wMazo[][13] )
{
   int fila;
   int columna;
   int carta;

   for(carta=1; carta<=52; carta++){
      do{
         fila = rand() % 4;
         columna = rand() % 13;
      } while(wMazo[fila][columna] != 0);
      wMazo[fila][columna] = carta;
   }
}

No entiendo porqué se pasa wMazo[][13], es decir, porque se deja el primer corchete sin datos, ¿no debería ser wMazo[4][13] ?

Gracias.


Título: Re: Duda función barajar
Publicado por: amchacon en 8 Abril 2014, 16:02 pm
Esa funcion da problemas, es muy probable que el mazo generado tenga 2 cartas identicas.

Lo ideal esque generes el mazo ordenado y luego hagas intercambios aleatorios.

En cuanto a la pregunta, el primer corchete es opcional. Puedes ponerlo o no, el segundo corchete es necesario para que el compilador traduzca los dos [][] en uno solo.


Título: Re: Duda función barajar
Publicado por: eferion en 8 Abril 2014, 16:22 pm
Como dice amchacon, tu código genera cartas repetidas ( por mera cuestión de estadística es más probable el caso en el que mazo tiene cartas repetidas que el caso en el que todas la cartas son distintas ).

La solución a ese problema pasaría por crear primero un mazo ordenado, lo cual es fácil de generar, y después mezclarlo mediante una serie de permutaciones ( generar un par X, Y e intercambiar sus cartas ). El número de permutaciones necesarias para asegurar una mezcla adecuada variará en función del algoritmo que elijas.


Título: Re: Duda función barajar
Publicado por: rir3760 en 8 Abril 2014, 17:29 pm
No entiendo porqué se pasa wMazo[][13], es decir, porque se deja el primer corchete sin datos, ¿no debería ser wMazo[4][13]?
Puedes declararla así pero no tendrá efecto ya que en C cuando un argumento es de tipo array lo que recibe la función es la dirección en memoria de (un puntero a) su primer elemento. Si el array es de tipo "T [N]" la función recibe un puntero de tipo "T *".

Utilizando tu caso como ejemplo la función la puedes declarar en cualquiera de las dos formas:
Código
  1. void baraja( int wMazo[4][13] );
  2.  
  3. /* O tambien */
  4. void baraja( int wMazo[][13] );
Pero no importa ya que la función se procesa como si su declaración fuera (y es):
Código
  1. void baraja(int (*wMazo)[13]);

Esa funcion da problemas, es muy probable que el mazo generado tenga 2 cartas identicas.
En buen plan: lo reviso con cuidado y no veo como se pueda duplicar una carta. ¿Se me escapa algo?

Un saludo


Título: Re: Duda función barajar
Publicado por: eferion en 8 Abril 2014, 17:32 pm
Cierto. Vi los random y me cegué jejejeje.

El problema es que llegar a tardar un tiempo infinito en mezclar el mazo.... si una de las combinaciones (fila, columna) no se da hasta pasadas miles de iteraciones... pues ahí que te quedas esperando.


Título: Re: Duda función barajar
Publicado por: amchacon en 8 Abril 2014, 18:20 pm
Tienes razón Rir, que fallo más tonto :-X

De todas formas, no me gusta ese modo de barajar como ya dije. Me parece mas natural de este modo:

1º Te generas el mazo ordenado.
2º Coges dos elementos al azar y los intercambias
3º Repites el paso 2 tantas veces como creas necesario. Para un mazo tienes de sobra con 1000 iteraciones.

De hecho en C++ (que no C) puedes hacer los dos ultimos pasos en un sola función:
http://www.cplusplus.com/reference/algorithm/random_shuffle/


Título: Re: Duda función barajar
Publicado por: leosansan en 8 Abril 2014, 19:43 pm
..........................................................
El problema es que llegar a tardar un tiempo infinito en mezclar el mazo.... si una de las combinaciones (fila, columna) no se da hasta pasadas miles de iteraciones... pues ahí que te quedas esperando.

Creo que últimamente menospreciamos la potencia de proceso de nuestros PC.

Como media a mi me tarda menos de 0.020s.

Ya hace un tiempo hubo una discusión acerca de cuánto tiempo se emplearía en rellenar, con el mismo método, una matriz 10x10  (http://foro.elhacker.net/programacion_cc/portafolium_set_my_name_for_the_example_yes_i_from_colombia-t390785.0.html)con números del 1 al 1000 y andaba por los 0.012s y acabó en este otro tema (http://foro.elhacker.net/buscador2-t391362.0.html;msg1856841#msg1856841).

Salu2!.


Título: Re: Duda función barajar
Publicado por: ivancea96 en 8 Abril 2014, 19:49 pm
Para barajar, yo lo que hago es ir cogiendo elementos, e ir colocándolos en un array en posiciones aleatorias.

O lo que es lo mismo, ir cogiendo elementos aleatorios, e ir introduciéndolos en el array.
Así para barajar en un tiempo finito.


Título: Re: Duda función barajar
Publicado por: amchacon en 8 Abril 2014, 20:41 pm
Para barajar, yo lo que hago es ir cogiendo elementos, e ir colocándolos en un array en posiciones aleatorias.

O lo que es lo mismo, ir cogiendo elementos aleatorios, e ir introduciéndolos en el array.
Así para barajar en un tiempo finito.
Pero estás duplicando el array así... Para eso intercambias y ya esta.

Creo que últimamente menospreciamos la potencia de proceso de nuestros PC.

Como media a mi me tarda menos de 0.020s.

Ya hace un tiempo hubo una discusión acerca de cuánto tiempo se emplearía en rellenar, con el mismo método, una matriz 10x10  (http://foro.elhacker.net/programacion_cc/portafolium_set_my_name_for_the_example_yes_i_from_colombia-t390785.0.html)con números del 1 al 1000 y andaba por los 0.012s y acabó en este otro tema (http://foro.elhacker.net/buscador2-t391362.0.html;msg1856841#msg1856841).

Salu2!.

Por supuesto, pero siempre se busca la máxima eficiencia.

Suponte un servidor de poker con millones de usuarios, dado que tienes que hacer millones de mezclas conviene perder el menor tiempo posible.

Y confiar en el "azar" no suele ser muy buena práctica. Es una buena costumbre garantizar que el algoritmo termine en tiempo finito incluso en el peor caso posible, nos ayudará a evitarnos algunos errores "oscuros".

Como curiosidad de algoritmos basados en el azar, tenemos un algoritmo de ordenación que usa una técnica similar: El bogosort (o stupidsort). Que viene a ser el siguiente:

Dado un conjunto de números desordenados:
     1º Comprobar que esten ordenados, si lo estan termina.
     2º Mezclar los numeros aleatoriamente.

Y aquí una implementación de este algoritmo en C++:

Código
  1. #include <iostream>
  2. #include <algorithm>
  3. #include <ctime>
  4. #include <iterator>
  5. using namespace std;
  6.  
  7. void bogo_sort(vector<int>&);
  8.  
  9. int main()
  10. {
  11.    vector<int> Numeros;
  12.    srand(time(NULL));
  13.    int N;
  14.  
  15.    cout<<"Introduzca numero de elementos a ordenar: ";
  16.    cin>>N;
  17.  
  18.    Numeros.resize(N);
  19.  
  20.    for (int i = 0; i < 10;i++) // 10 intentos
  21.    {
  22.        generate(Numeros.begin(),Numeros.end(),rand); // relleno el vector de numeros aleatorios
  23.  
  24.          // Muestra los numeros generados por pantalla:
  25. //        copy(Numeros.begin(),Numeros.end(), ostream_iterator<int>(cout, " "));
  26.  
  27.        time_t inicio = clock();
  28.  
  29.        bogo_sort(Numeros);
  30.  
  31.        time_t fin = clock();
  32.  
  33.        cout<<(double)(fin-inicio)/(CLOCKS_PER_SEC)<<"s en ordenar "<<N<<" elementos"<<endl;
  34.  
  35.        // muestra los numeros ordenados por pantalla
  36. //        copy(Numeros.begin(),Numeros.end(), ostream_iterator<int>(cout, " "));
  37.  
  38.       // cout<<endl;
  39.    }
  40.    return 0;
  41. }
  42.  
  43. bool enOrden(vector<int> &x) {return adjacent_find(x.begin(), x.end(), greater<int>()) == x.end();}
  44.  
  45. void bogo_sort(vector<int> &Numeros)
  46. {
  47.    while (!enOrden(Numeros))
  48.    {
  49.        random_shuffle(Numeros.begin(),Numeros.end());
  50.    }
  51. }
  52.  

Dile que genere 10 elementos. A mí los tiempos me salen muy dispares (desde 0,063 hasta 5 segundos). Eso en rangos pequeños, cuanto mayor sea el rango, mayor será la dispersión.

En resumen, trabajar basado en la suerte nos da unos programas muy impredecibles y inestables. A mí personalmente no me gusta nada ;D


Título: Re: Duda función barajar
Publicado por: ivancea96 en 8 Abril 2014, 20:43 pm
Pero estás duplicando el array así... No sé.

Creo que es obvio que se hace en un array temporal >.>


Título: Re: Duda función barajar
Publicado por: amchacon en 8 Abril 2014, 20:45 pm
Creo que es obvio que se hace en un array temporal >.>
¿Y después lo vuelves a copiar en el array original? :huh:


Título: Re: Duda función barajar
Publicado por: leosansan en 8 Abril 2014, 20:47 pm
Para barajar, yo lo que hago es ir cogiendo elementos, e ir colocándolos en un array en posiciones aleatorias.

O lo que es lo mismo, ir cogiendo elementos aleatorios, e ir introduciéndolos en el array.
Así para barajar en un tiempo finito.

Si no te he entendido mal ivancea96, la colocación en el array o.k, lo vas llenando desde cero al final, pero al tomar un elemento aleatorio puede suceder que ya lo hayas tomado, con lo que necesitarías poner un valor flag para indicar que ese elemento ya se ha tomado. En estas circunstancias estarías igual que el método que David8 y yo hemos propuesto como alternativa.

Todo esto si te he entendido bien, vete tu a saber. ;)

Yo casi me quedaría con el método de coger la lista ordenada, como sugirió amchacon, y desordenarla aleatoriamente. por intercambio aleatorio de posiciones un cierto número de veces y listo. Así tenemos controladas las iteracione a realizar.

¡¡¡¡ Saluditos! ..... !!!!


(http://st.forocoches.com/foro/images/smilies/aaaaa.gif)


Título: Re: Duda función barajar
Publicado por: ivancea96 en 8 Abril 2014, 21:03 pm
El caso, es que cada vez que coges un elemento, se reduce el próximo número máximo del rand() en 1. Si un elemento que escoges, ya ha sido cogido, se va al siguiente, así hasta que no haya sido cogido...


Título: Re: Duda función barajar
Publicado por: amchacon en 8 Abril 2014, 21:10 pm
El caso, es que cada vez que coges un elemento, se reduce el próximo número máximo del rand() en 1. Si un elemento que escoges, ya ha sido cogido, se va al siguiente, así hasta que no haya sido cogido...
¿Comor?

¿Y si cojo un elemento del principio? ¿No puede adceder a los finales?

Quiero ver una implementación ^^


Título: Re: Duda función barajar
Publicado por: ivancea96 en 8 Abril 2014, 21:21 pm
¿Si coges un elemento del principio? Ese proceso se repite N veces, siendo N el tamaño del array.

EDITO:
Quiero ver una implementación

Código
  1. template<class T>void barajar(vector<T> &v){
  2.    vector<T> t;
  3.    int r=0;
  4.    while(v.size()>0){
  5.        t.push_back(v[r=rand()%v.size()]);
  6.        v.erase(v.begin()+r);
  7.    }
  8.    v = t;
  9. }
Por ejemplo, manejando vectores.


Título: Re: Duda función barajar
Publicado por: leosansan en 8 Abril 2014, 21:51 pm
¿Comor?

¿Y si cojo un elemento del principio? ¿No puede adceder a los finales?

Quiero ver una implementación ^^

Yo también lo quiero ver.

En el método que propuse, desordenar un cierto número de veces, 10 000 en el caso que propongo, con lo que controlamos las iteraciones, una implementación simple, nada rebuscada, arroja valores por debajo de 0.02s, más cercanos al 0.015s:


Código
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<time.h>
  4. #define MAX_DESORDEN 10000
  5.  
  6.  
  7. int main (void){
  8.  int mazo[4][13] = {0};
  9.  srand((unsigned) time(NULL));
  10.  int i,j,k=0,x1,y1,x2,y2,temp;
  11.  ///puts("Mazo ordenado:\n");
  12.  for (i=0;i< 4; i++){
  13.    ///puts("\n");
  14.    for (j=0;j<13 ;j++,k++ ){
  15.      mazo[i][j]=k;
  16.      ///printf("%d  ",mazo[i][j]);
  17.    }
  18.   }
  19.  
  20.  for (i=0;i<MAX_DESORDEN;i++){
  21.    x1=rand () %4;
  22.    y1=rand () %13;
  23.    x2=rand () %4;
  24.    y2=rand () %13;
  25.    temp=mazo[x1][y1];
  26.    mazo[x1][y1]=mazo[x2][y2];
  27.    mazo[x2][y2]=temp;
  28.  }
  29.  /** activame para ver el mazo desordenado **/
  30.  /*puts("\n\nMazo desordenado:\n");
  31.   for (i=0;i< 4; i++){
  32.     puts("\n");
  33.     for (j=0;j<13 ;j++,k++ )
  34.       printf("%d  ",mazo[i][j]);
  35.    }*/
  36.   return EXIT_SUCCESS;
  37. }

Salu2!.





Título: Re: Duda función barajar
Publicado por: amchacon en 8 Abril 2014, 22:18 pm
Al parecer ya ha editado su post con la implementación... Pero la propuesta de Ivan no es una solución eficiente (intenta mezclar 10 millones de elementos, a mí me tardó 4 minutos...).

Por cierto Leo, haciendo pruebas me he dado cuenta que hay una forma un poco más sencilla de mezclar. No es necesario definirte una constante con el numero de iteraciones:
Código
  1. for (int i = 0;i < v.size(); i++)
  2.    swap(v[i],v[rand()%A.size()]);

Dicho de otra forma, recorro el array y cada posición la intercambio con otra aleatoria. De esa forma tengo la garantía de tener el array desordenado y no tengo que definir una constante "a ojo".

La función swap no es más que:
Código
  1. void swap(int &a,int &b)
  2. {
  3.    int c = a;
  4.    a = b;
  5.    b = c;
  6. }


Título: Re: Duda función barajar
Publicado por: leosansan en 8 Abril 2014, 23:24 pm
.................................).

Por cierto Leo, haciendo pruebas me he dado cuenta que hay una forma un poco más sencilla de mezclar. No es necesario definirte una constante con el numero de iteraciones:
...........................................
Dicho de otra forma, recorro el array y cada posición la intercambio con otra aleatoria. De esa forma tengo la garantía de tener el array desordenado y no tengo que definir una constante "a ojo".
......................................

Buena observación amchacon, muy buena  ;-) ;-) ;-)

...Pero me sentiría más tranquilo barajando un par de veces más para evitar las posibles coincidencias de i con el valor obtenido del rand y que existan cartas que acaben quedándose en las mismas posiciones :laugh:

Ya sólo nos queda ponerlo en práctica echándonos unas partiditas de póker ;)

Hay que ver la soluciones, cada vez más optimizadas, que nos salen cuando nos dejan......

Mi adaptación al C de tu idea:


Código
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<time.h>
  4.  
  5. int main (void){
  6.  int mazo[52] = {0};
  7.  srand((unsigned) time(NULL));
  8.  int j,x,temp;
  9.  ///puts("Mazo ordenado:\n");
  10.    for (j=0;j<52 ;j++)
  11.      mazo[j]=j;
  12.    for (j=0;j<52 ;j++){
  13.    x=rand () % 52;
  14.    temp=mazo[j];
  15.    mazo[j]=mazo[x];
  16.    mazo[x]=temp;
  17.  }
  18.  puts("\n\nMazo desordenado:");
  19.    for (j=0;j<52 ;j++ ){
  20.      if (j%13==0)
  21.        puts("\n");
  22.      printf("%d  ",mazo[j]);
  23.    }
  24.   putchar ('\n');
  25.   return EXIT_SUCCESS;
  26. }


Citar


Mazo desordenado:


18  35  24  31  36  46  21  25  37  34  40  23  51

0  47  6  16  7  44  9  22  12  20  33  3  17

50  39  42  13  1  10  27  26  11  29  2  43  45

14  32  48  49  4  8  28  15  38  19  41  5  30



¡¡¡¡ Saluditos! ..... !!!!


(http://st.forocoches.com/foro/images/smilies/aaaaa.gif)

 



Título: Re: Duda función barajar
Publicado por: Eternal Idol en 9 Abril 2014, 02:00 am
Ya hace un tiempo hubo una discusión acerca de cuánto tiempo se emplearía en rellenar, con el mismo método, una matriz 10x10  (http://foro.elhacker.net/programacion_cc/portafolium_set_my_name_for_the_example_yes_i_from_colombia-t390785.0.html)con números del 1 al 1000 y andaba por los 0.012s y acabó en este otro tema (http://foro.elhacker.net/buscador2-t391362.0.html;msg1856841#msg1856841).

Acabo ahi despues de que le hicieran la tarea y borrara toda huella para poder presentarla tranquilo  :rolleyes: