Cartón de Bingo en C.

Iniciado por zkraven, 7 Febrero 2018, 14:48 PM

0 Miembros y 1 Visitante están viendo este tema.

zkraven

Hola, estoy intentando hacer un cartón de Bingo de 3x9. En los cuales los numeros deben ir ordenados por decenas y en cada linea debe de haber 4 huecos. Por ahora llevo lo siguiente de código, lo cual genera una matriz con numeros aleatorios. Mi problema es que no se insertar los huecos en blanco y tampoco se como evitar repetir un numero aleatorio. Espero que tengaís soluciones:


#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

int numero_aleatorio();

int main(){
    SetConsoleOutputCP(1252);
    srand(time(NULL));

    int matriz[3][9];
    int filas;
    int columnas;

    printf("Este es su Cartón de Bingo: \n");
    printf("\n");

    for(filas=0;filas<3;filas++)
    {
     
        for(columnas=0;columnas<9;columnas++)
        {
            switch (columnas)
            {
                case 0:

                    matriz[filas][columnas] = 1 + rand() % (10 + 1 - 1);


                    break;
                case 1:
                    matriz[filas][columnas] = 11 + rand() % (20 + 1 - 11);

                    break;
                case 2:
                    matriz[filas][columnas] = 21 + rand() % (30 + 1 - 21);

                    break;
                case 3:
                    matriz[filas][columnas] = 31 + rand() % (40 + 1 - 31);

                    break;
                case 4:
                    matriz[filas][columnas] = 41 + rand() % (50 + 1 - 41);

                    break;
                case 5:
                    matriz[filas][columnas] = 51 + rand() % (60 + 1 - 51);

                    break;
                case 6:
                    matriz[filas][columnas] = 61 + rand() % (70 + 1 - 61);

                    break;
                case 7:
                    matriz[filas][columnas] = 71 + rand() % (80 + 1 - 71);

                    break;
                case 8:
                    matriz[filas][columnas] = 81 + rand() % (90 + 1 - 81);

                    break;

            }//final del switch
            }
         



            printf("[ %i ]", matriz[filas][columnas]);
        }
      printf("\n");
    }




También me gustaría saber algún consejo para que el aspecto gráfico al ejecutarlo en consola se mejore y no solamente sea una matriz llena de números.

MAFUS

#1
Para sacar números aleatorios no repetidos del 0 al 9 se me ha ocurrido la siguiente solución, basada en las variables estáticas de una función (conservan el mismo valor de llamada a llamada pero solo pueden accederse desde el interior de la función misma):

int aleatorio(int reinicio) {
    // Esta función necesita stdlib.h para funcionar
    static int array[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    int retval;
    int i, z;

    if(reinicio == 0) { // Se ha optado por reiniciar a 0, así dando la posición 0 del array del llamador, la primera
                        // se reiniciará para poder iterar normalmente. En las demás trabajar de forma normal
        for(i=0; i<10; ++i)
            array[i] = i;
    }

    i = z = rand()%10; // Obtiene una posición del array interno
    while((retval = array[i]) == -1) { // Si dicha posición ya ha sido usada (cambiada a 0)
        ++i;                          // seguir buscando las siguientes hasta encontrar un valor distinto a 0.
        if(i>9)                       // Por supuesto si superamos el nueve
            i=0;                      // Hay que reiniciar a 0
        if(i == z) // Si se ha dado una vuelta completa
            break; // salir del bucle. retval valdrá -1, dando a entender que no hay más números a elegir.
    }
    array[i] = -1; // Una vez encontrado un número válido se marca como usado con el -1;

    return retval; // Retornamos el valor encontrado.
}


El resto del programa se puede basar sobre esto:
Puedes crear una matriz de 10 x 10 donde las decenas y a cada fila usar dicho iterador para las decenas del número, de la misma forma a cada columna podrás usar la función (que devolverá 0 a 9) sumando 1 para que vayan de 1 a 10.
También puedes usar la función para, una vez rellena una fila con números aleatorios conseguir 4 posiciones que se llevarán a 0, para marcar un hueco.
Finalmente puedes usar la función para tomar 3 filas aleatorias de la matriz y crear el cartón.
Por ejemplo, la aplicación en la que he basado dicha función ofrece esta salida:
100  ---  099  092  ---  095  ---  093  094  ---
044  ---  ---  045  042  ---  046  049  ---  050
063  067  ---  ---  071  062  068  ---  065  066





Actualizado el código para eliminar un bucle eterno que se podría producir al pedir un número aleatorio cuando ya se hubieran usado todos.

PalitroqueZ

Citartampoco se como evitar repetir un numero aleatorio.

y te falta resolver el otro problema, evitar repetir cartones , me explico

si para el uso que le vas a dar, necesitas generar series verticales u horizontales, en una tirada de cartones de por ejemplo 10 cartones, no pueden haber 2 cartones cuya primera columna vertical tenga numeros repetidos (sin importar el orden en que se encuentren).

por eso digo, que debes establecer cuales serán los criterios para el uso que le vas a dar a los cartones, para que luegos de generados, debes crear una o varias funciones en donde se compruebe que no hay columnas, filas, diagonales, o incluso cartones full repetidos.

a menos claro, que quien le vaya a dar uso, no le importe que salgan mas de un ganador.

"La Economía planificada lleva de un modo gradual pero seguro a la economía dirigida, a la economía autoritaria y al totalitarismo" Ludwig Erhard

Serapis

Para no repetir números, hay que usar el algoritmo del sombrero, (Fisher-Yates-Durstenfeld)...


Me autocito de otro hilo (solo cambia la cantidad de valores que se usan, alli 9 aquí ¿100?).

Cita de: NEBIRE en 26 Enero 2018, 15:52 PM
Los números aleatorios debes elegirlos entre el rango 1-8... así no te saldrá nunca el 9.

Para evitar que los números salgan repetidos una y otra vez, procede de esta manera:

Primero se meten en la 'bolsa' los números que se van a rifar:

Array de enteros = funcion RellenarArray(entero cantidad, entero Inicio)
    entero k
    array de enteros Ar

    bucle para k desde Inicio a (Cantidad + Inicio)
        Ar(k) = k 
    fin bucle
fin funcion


Y luego se barajan, así el reparto es aleatorio:

funcion Barajar(Array de enteros Ar, entero Cantidad)
    entero i, j, k

    Bucle para k desde cantidad-1 hasta 1 retrocediendo
        j = random(ente 0 y k)

        i = Ar(j)
        Ar(j) = Ar(k)
        Ar(k) = i
fin bucle



Con cada nueva partida, tu harás dos llamadas, antes que nada:

   Ar = Rellenararray(8, 1)
   Barajar(Ar, 8)
   //....colocar en sus casillas




Si como apunta Palitroquez, no quieres repetir cartones, es más de lo mismo...

zkraven

Y en cuanto a los huecos, como ingreso un espacio aleatorio en blanco (en total 4 por linea) dentro de la matriz?
Algun consejo para mejorar la apariencia tras ejecutarlo en la consola?

MAFUS

elige 4 posiciones aleatorias y conviertes en 0

zkraven

Pero no deben ser siempre las mismas posiciones las que estén vacías

Serapis

#7
Es lo mismo.

Si tu cartón tiene 10 elementos por fila, llenas un array de 0 a 9, los desordenas y los 5 primeros que sean vacíos y los 5 siguientes con valor... o viceversa...


   entero i, j, k, cantidad

   cantidad =10

    // rellenar el array
   bucle para k desde 0 a  cantidad-1
       carton(k) = k
   fin bucle

    // Barajar el array
   Bucle para k desde cantidad-1 hasta 1 retrocediendo
       j = random(ente 0 y k)

       i = Ar(j)
       carton(j) = carton(k)
       carton(k) = i
   fin bucle
   
    // Verificar cuales quedan libres y cuales ocupadas
   bucle para k desde 0 a  cantidad-1
       Si (carton(k) < 5) luego
           //casilla libre: poner a 0, dibujar algo (el bombo del bingo por ejemplo)
       Sino
           //casilla ocupada: meter aquí el valor que toque. dibujar el número, etc...
       Fin si
   fin bucle

MAFUS

Generas una línea con tu función de generar números aleatorios no repetidos.
5 3 7 1 10 8 2 6 4 9

Y ahora, con la misma función generas cuatro aleatorios más y los usas como índice:
línea[fila][aleatorio(i)] = 0;
Siendo i un iterador de 0 a 3, ambos inclusive, en un bucle.

Serapis

#9
No es preciso enviar un mensaje personal para estas cosas... pués para eso está precisamente el foro, y así cualquier respuesta sirve para todos.
Los mensajes privados son para cosas que no concierne a nadie más...

Cita de: zkraven en 10 Febrero 2018, 12:09 PM
Hola NEBIRE, sigo teniendo dudas con la función de generar huecos; podrías ayudarme a incluirla en este código:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

int filas, columnas; // iteradores

void generar(int matriz[3][9]);
void imprimir(int matriz[3][9]);
void huecos(int matriz[3][9]);

int main()
{
   SetConsoleOutputCP(1252);
   srand(time(NULL));

   int matriz[3][9];

   printf("Este es su Cartón de Bingo: \n");
   printf("\n");
   generar(matriz);
   huecos(matriz);
   imprimir(matriz);
 {
   int opcion;
   do
   {
       printf( "\n   Si desea cambiar su cartón pulse 1: \n");
       printf( "\n   Si le ha gustado su cartón y no desea cambiarlo pulse 2: ");
       scanf( "%d", &opcion );
       switch ( opcion )
       {
           case 1: generar(matriz);
                   imprimir(matriz);
                   printf("\n Suerte con su juego\n");
                   break;
           case 2: printf("\nSuerte con su juego\n");
                   break;
        }
   } while ( opcion !=2 );
}
}

void generar(int matriz[3][9])
{
   for(columnas=0;columnas<9;columnas++)
   {
   do{
       for(filas=0;filas<3;filas++)
       {
           switch (columnas)
           {
               case 0:
                   matriz[filas][columnas] = 1 + rand() % (10 + 1 - 1);
                   break;
               case 1:
                   matriz[filas][columnas] = 11 + rand() % (20 + 1 - 11);
                   break;
               case 2:
                   matriz[filas][columnas] = 21 + rand() % (30 + 1 - 21);
                   break;
               case 3:
                   matriz[filas][columnas] = 31 + rand() % (40 + 1 - 31);
                   break;
               case 4:
                   matriz[filas][columnas] = 41 + rand() % (50 + 1 - 41);
                   break;
               case 5:
                   matriz[filas][columnas] = 51 + rand() % (60 + 1 - 51);
                   break;
               case 6:
                   matriz[filas][columnas] = 61 + rand() % (70 + 1 - 61);
                   break;
               case 7:
                   matriz[filas][columnas] = 71 + rand() % (80 + 1 - 71);
                   break;
               case 8:
                   matriz[filas][columnas] = 81 + rand() % (90 + 1 - 81);
                   break;
               }//final del switch
           }
       }while((matriz[0][columnas]== matriz[1][columnas]) ||
              (matriz[0][columnas]==matriz[2][columnas]) ||
              (matriz[1][columnas]== matriz[2][columnas])||
              (matriz[0][columnas]>matriz[1][columnas])||
              (matriz[1][columnas]>matriz[2][columnas]));
   }
}

void imprimir(int matriz[3][9])
{
   for(filas=0;filas<3;filas++)
   {
       for(columnas=0;columnas<9;columnas++)
       {
           if (columnas == 0 && matriz[filas][0]!=10)
               printf("[  %i ]", matriz[filas][columnas]);
           else
               printf("[ %i ]", matriz[filas][columnas]);
       }
       printf("\n");}
}
void huecos(int matriz[3][9])
{
        do{
           generar(matriz);
        }while();
   }



En el siguiente hilo di una amplia respuesta a otro usuario que preguntaba por un bingo:
https://foro.elhacker.net/buscador2-t472516.0.html;msg2134435#msg2134435

Si bien algunos detalles no quedaron concretados (como tampoco haces tú). Antes de responderte con más precisión sobre el tema es preciso concretar detalles...  de otro modo uno refiere cosas genéricas, que luego resulta más difícil adaptar al caso específico que uno precisa.

Por ejemplo, yo recuerdo en mis tiempos de discotecas (allá a mediados de los 80s), se puso de moda que con la entrada a la discoteca, de regalo, te daban un cartón de bingo (válido para un sorteo, esa noche en el propio local), y a veces, por superar cierto valor en las consumiciones, te daban otro, luego de medianoche en adelante paraban la música un rato y se sorteaba el bingo... recuerdo que aquellos cartones eran de 80 bolas, eran 4 líneas con 5 valores, luego cantar bingo exigía acertar 20 bolas. Sin embargo duraba mucho tiempo y al parecer las consumiciones se 'congelaban' mientras todo el mundo estaba atento al trascurrir del bingo... así que pronto cambiaron a cartones de 90 bolas, con solo 3 líneas asi solo se requerían 15 bolas para alcanzar el bingo. Aunque hay más tamaños de cartones, éste de 90 bolas es el más habitual, así que conviene aclarar los detalles de como es...

Bolas: 90
Lineas: 3
Valores por linea: 9, de los cuales 4 son 'huecos'.
Cantar linea: 5 bolas en línea
Cantar bingo: 15 bolas (3lineas x 5bolas).

Más detalles:
El cartón se reparte en columnas, cada columna acoge a los valores de una decena, así es fácil hallar el valor recién extraído del bombo.
Además, el cartón está 'equilibrado', es decir tiene bolas en todas las decenas. Para que se cumpla esto, ninguna columna debe tener 3 bolas...
Mirándolo bien entonces hay 3 columnas con solo 1 valor y 6 columnas con 2 valores.

Los cartones tienes valores comenzando en 1 y acaban en 90, esto implica que los valores acabados en 0, están en la columna anterior de la decena de la que forma parte... en las explicaciones subsiguientes, en cambio he optado por valores en el rango 0-89 y así, los valores 0,10,20,30...80 están en la misma columna que el resto de valores de la decena.

Otro detalle, es que para que el juego sea equitativo con todos, no puede haber más bolas de un valor que otro en los cartones, esto implica que todas las bolas de un bingo, deben ser alojadas en sendos cartones... así el bingo de 80 bolas se ajusta en 4 cartones (20bolas por cartón x 4cartones = las 80 bolas del bingo).
... y de igual modo para éste: 90bolas de bingo / 15bolas por cartón = 6 cartones...
Es decir las 90 bolas deben repartirse en 6 cartones, y para generar más cartones siempre deben ser de 6 en 6... luego eso que tienes en tu código de 'te gusta este cartón?'... no vale... los jugadores/apostantes/bingueros, no pueden elegir cartón, al menos no debe elegirse un cartón creado al efecto, si no en todo caso, entre los generados (igual que un jugador real, no podría elegir ningún cartón que físicamente no existe, y los que existen, han sido generados siempre en secuencias de 6 en 6...)

Y por último, los cartones deben estar bien proporcionados, con un reparto de valores equilibrado. Al caso, de cada decena debe existir valores. Los jugadores se  quejarían de situaciones similares a éstas:
-- 31 32 -- 33 -- 34 35 --  (números consecutivos)
ó una como esta, (en este caso perfectamente válida)
-- 27 -- 47 67 -- -- 87 17  (números con la misma terminación)
Incluso una línea que sin ser consecutivos tuvieran varios de la misma decena alguien se quejaría:
-- -- 43 -- 48 -- 40 42 45  (todos en la misma decena)
Tampoco se libran situaciones como esta:
03 -- 06 -- -- 09 -- 85 -- 87  (unos muy bajos y otros muy altos).
Esto aunque fuera mejor, quedaría feo:
-- -- -- -- 15 31 55 62 84 (todos los huecos juntos por un lado y los valores por otro).

Se puede considerar dos formas de abordarlo, simple o complejo, según ignoremos ciertas condiciones expresadas más arriba.
Ignoro si todo esto es una tarea escolar, para la Universidad o si es algo más 'profesional', si es un trabajo para la 'Uni', quizás sea mejor obviar muchas cosas, y simplemente repartir las bolas entre los cartones sin molestarse en las otras consideraciones (obviamos mantener no más de 2 valores por decena y para 3 decenas solo 1 valor, además de constatar ordenadas las bolas en el cartón, etc...).

Si es un tarea de la 'Uni', posiblemente sea suficiente la forma simple: repartir los números entre los cartones y alojar los huecos, sin entrar a valorar más consideraciones. Por tanto voy a considerar este útimo caso, como el tuyo, y el pseudocódigo que sigue se ajusta a esto, si luego resulta que es para un trabajo más profesional, pués avisa... es un poco más complejo, pero tampoco excesivamente, aunque si lleva más texto explicativo, para terminar de comprenderlo todo bien...



----------------------------------------
Tu primer trabajo, por tanto es barajar las 90 bolas y repartirlas entre los 6 cartones. Al caso, tras barajar el array él mismo basta inicialmente para contener los 6 cartones en crudo, considerando que cada cartón empieza en los índices múltiplos de 15 ... (cartón 1ª índices del 0 al 14, 2ª índices del 15 al 29, etc... cada 15 se alojan en un nuevo cartón).
El pseudocódigo para esto, ya te lo puse más arriba, copio y pego:


Array de bytes = funcion CrearYRellenarArray(byte cantidad)
   byte k
   array de bytes Bolas(0 a cantidad-1)

   bucle para k desde 0 a cantidad-1
       Bolas(k) = k  
   fin bucle
 
   devolver Bolas
fin funcion


//Y luego se barajan, así el reparto es aleatorio:

funcion Barajar(Array de bytes Bolas, byte Cantidad)
   byte i, j
   entero k

   Bucle para k desde cantidad-1 hasta 1 retrocediendo
       i = random(ente 0 y k)

       j = Bolas(i)
       Bolas(i) = Bolas(k)
       Bolas(k) = j
   fin bucle
fin funcion



He obviado ordenar los valores de cada cartón, porque aquí la forma (simple del bingo) seguida aquí, los desordena de nuevo... al final si lo deseas puedes ordenar los valores de cada línea... a medida que se crea la línea

La 2ª tarea es generar los cartones. Una función invoca en bucle a otra que mete los huecos en cada línea de 1 cartón

// esta función manda meter los números de cada 'cartón' del array bolas en el array de cartón definitivo, con sus respectivos huecos.

// o un array de arrays...
coleccion de arrays = funcion Crear6Cartones(array de bytes Bolas, byte cantidad)
   byte k
   array de bytes carton
   //coleccion  col = nueva coleccion


   bucle para k desde 0 a 5 // 6 cartones
       carton =  MeterHuecos(bolas, k, )
       //col.Add(carton)
       llamada a ImprimirEnPantalla (carton)  ' si solo se ha de probar, que funciona bien, no es preciso devolver una colección, podría bastar con pasarlo por pantalla...
   fin bucle
   
   //devolver col
fin funcion


La 3ª tarea  finalmente es generar un array individual para cada cartón. con sus 27 casillas (3 líneas de 9) generando los huecos...

Para ello primero se crea un array con los 27 elementos que ha de tener.
Se considera subdividido en 3 series de 9, en cada serie de ellas introduce al comienzo, 5 valores procedentes del array bolas, luego se añaden detrás los 4 'huecos' (con valor 255) ... y se baraja esa línea, así quedan repartidos los valores y los huecos...

Array de bytes = Funcion MeterHuecos(array de bytes Bolas, entero NumeroCarton)
   array de bytes Carton(0 a 26)
   byte i, j, n, indice, ix, v
   entero k

   indice = (NumeroCarton * 15)    // indice en el array donde comienza este cartón...
   i = 0

   bucle para j desde 1 a 3  // 3 líneas
       // en este bucle metemos 5 valores en una línea.
       bucle para k desde indice a (indice + 4)
           carton(n) = Bolas(k)
           n +=1
       fin bucle
       indice = k

       // metemos los 4 huecos (valor 255)
       bucle para n desde n a n+3
           carton(n) = 255  
       fin bucle
     
       // Resta barajar esta línea del cartón, que es lo que hace el siguiente bucle:
       bucle para k desde n-1 hasta i+1 retrocediendo  
           ix= random(entre i y k)  // OJO: entre i y k, no entre 0 y k

           v = carton(k)
           carton(k) = carton(ix)
           carton(ix) = v
       fin bucle

       i = n      
   fin bucle  
 
   devolver carton
fin funcion


Solo resta las llamadas a cada función...

funcion Main()
   array de bytes Bolas
   // coleccion col

   Bolas = CrearYRellenarArray(90)
   llamada a Barajar(Bolas, 90)
   
   llamada a Crear6Cartones(Bolas, 90) ' y los imprime, para ver le resultado de cada uno.
   // coleccion = Crear6Cartones(Bolas, 90)
fin funcion


...y listo, es plenamente funcional... cuando lo pases a código... como está escrito de un plumazo, quizás precise alguna pequeña corrección...

La función ImprimirEnPantalla(array de bytes Carton) queda a tu esfuerzo, no creo que tengas problemas (solo recuerda que los huecos contiene valor 255, imprime 2 espacios, o 2 guiones y para valores menores de 10, añade un 0 delante, para cuadrar bien las líneas).

Este método, puede ser suficienbtemente válido para una tarea de estudiante , ya que lo que se persigue es cumplir una funcionalidad, y que el alumno se esfuerce en entender y ser capaz de darle solución, pero no es válido para usar de forma real, los cartones resultantes podrían tener situaciones por las que un jugador tendría 'quejas', tal como te señalaba más arriba...
Si necesitas algo más 'profesional' avisa y me extiendo en los detalles de la 'forma compleja'... no lo es tanto, pero ciertamente tiene más trabajo que esto...

Aquí un resultado al ejectuarlo... Nota como siendo la forma simple, aparecen los fallos descritos al comienzo: columnas con 3 valores, o con 3 huecos, más de 3 valores seguidos, valores desordenados, más de 2 valores de la misma decena, valores de algunas decenas ausentes, etc...
Sin embargo cada línea contiene 5 valores y 4 huecos y los 6 cartones contienen todas las bolas de la 0 a la 89.

--  --  29  15  --  10  77  --  02  
----------------------------------------
75  70  84  --  --  --  07  46  --  
----------------------------------------
--  21  --  76  45  --  24  22  --  
----------------------------------------


06  42  --  87  18  --  --  23  --  
----------------------------------------
--  43  62  31  --  --  --  13  33  
----------------------------------------
53  --  --  --  --  73  71  08  61  
----------------------------------------


09  --  --  88  --  59  --  20  38  
----------------------------------------
82  14  --  --  --  --  35  41  69  
----------------------------------------
--  --  44  --  83  11  74  80  --  
----------------------------------------


--  --  05  26  --  --  58  00  78  
----------------------------------------
37  --  27  55  54  --  --  12  --  
----------------------------------------
49  34  --  56  --  --  51  --  48  
----------------------------------------


--  19  81  40  --  --  17  --  16  
----------------------------------------
79  30  39  --  --  36  --  --  52  
----------------------------------------
72  85  --  --  --  04  68  --  64  
----------------------------------------


--  28  --  --  32  67  --  60  03  
----------------------------------------
--  57  65  --  --  --  01  66  89  
----------------------------------------
--  63  50  86  --  47  --  --  25  
----------------------------------------

La banca para sacar las bolas usa las dos primeras funciones, esto es, crea el array y lo rellena y luego lo baraja...
Una tercera función sería un bucle que va 'cantando' las bolas que señala el bucle... el bucle va recorriendo dicho array barajado...