UNIVERSIDAD CARLOS III DE MADRID
PROGRAMACIÓN. GRADO EN INGENIERÍA EN TECNOLOGÍAS INDUSTRIALES
CONVOCATORIA ORDINARIA MAYO 2013. PROBLEMAS
Apellidos:______________________________________
Nombre:_______________________________________
NIA:__________________________________________
Problema 1 (3,5 puntos)
El Bingo es un juego de azar muy antiguo, y bastante popular alrededor de todo el mundo. Se juega
con un bombo que contiene 90 bolas numeradas. Cada jugador tiene un cartón con números entre
1 y 90. Un locutor va sacando las bolas del bombo y recitando los números, y los jugadores que
tienen el número en su cartón lo tachan. El ganador es el primer jugador en tachar todos los
números de su cartón (a esto se le llama "hacer bingo").
En este ejercicio se va a escribir un programa en C que permita simular una versión simplificada del
juego del Bingo.
Supondremos que pueden jugar como máximo 100 jugadores. Se debe definir un vector de
estructuras que almacene la información de cada jugador, que será:
Nombre
Edad
Cartón actual que está jugando
El cartón se representará como una matriz de 3 filas y 9 columnas que contendrá números entre el
1 y el 90. Este cartón se irá modificando a lo largo de la partida (según se vayan “tachando”
números). La siguiente tabla muestra un ejemplo de cartón:
21 51 89 82 4 1 68 29 1
19 10 35 43 68 8 2 38 90
43 6 22 30 59 57 26 1 85
Antes de comenzar la partida, se pedirá por teclado el número de jugadores (n_jugadores) que
deberá estar entre 1 y 100. Se irán leyendo de teclado el nombre y edad cada jugador. Además, se
rellenará la matriz que representa el cartón, para lo que se utilizará la siguiente función (que se
supone ya programada, por lo que solo es necesario llamarla):
void inicializaCarton (int miCarton[FILAS][COLUMNAS])
Actualizados estos datos, se comenzará la partida. Para ello, se irán leyendo por teclado números
(que simularán los que salen del bombo) y deberán estar entre 1 y 90 (para simplificar, no es
necesario controlar si un número ya ha salido anteriormente, podrán repetirse).
A partir de este número, se deberá comprobar si éste está en los cartones de los jugadores. Si fuera
así, se deberá sustituir en el cartón de ese jugador por un 0, indicando que el número está tachado.
Este proceso se repetirá hasta que un jugador obtenga bingo, es decir, todos los números de su
cartón ya hayan sido tachados. Podría darse el caso de que varios jugadores obtengan bingo en la
misma jugada.
Acabada la partida, deberá mostrarse por pantalla una clasificación de los jugadores, en función de
cuántos números tachados tenga cada uno.
1
El programa se deberá hacer OBLIGATORIAMENTE utilizando FUNCIONES y de acuerdo a los pasos
que se detallan a continuación (tener en cuenta que la función principal deberá realizarse al final):
1. Defina los tipos de datos estructurados necesarios para almacenar toda la información
del juego (0,5 puntos).
2. Implemente la función "inicializaJugadores”. Esta función recibe como parámetro el
vector con todos los jugadores y el número total de jugadores. Así, inicializará el vector
leyendo nombre y edad por teclado, e inicializando cada cartón LLAMANDO para ello a la
función "inicializaCarton" que se supone ya programada (0,5 puntos)..
3. Implemente la función "tachaNumero". Esta función recibe como parámetro un cartón y
un número, comprueba si dicho número está en el cartón, y lo tacha (lo marca con un 0).
(1 punto).
4. Implemente la función "compruebaFila". Esta función recibe como parámetro un cartón
y el número de una fila, y comprueba si dicha fila está completa (todos los números
están a 0). Devolverá un 1 si la fila está completa y un 0 en caso contrario. (1 punto).
5. Implemente la función "compruebaBingo". Esta función recibe como parámetro un
cartón y comprueba si todos sus números están a 0. Para ello, deberá llamar
OBLIGATORIAMENTE a la función compruebaFila. Si el cartón tiene todas sus casillas a 0,
la función deberá devolver un 1, en caso contrario, un 0. (1 punto).
6. Implemente la función “calculaNumerosParaBingo”. Esta función recibe como parámetro
un cartón y devuelve el número de números que faltan en dicho cartón para conseguir
un Bingo (números distintos de 0 que tiene dicho cartón) (1 punto).
7. Implemente la función “mostrarClasificacion”. Esta función recibe como parámetro el
vector de jugadores y muestra por pantalla una clasificación de dichos jugadores en
función de los números tachados. Se mostrará primero los que menos números sin
tachar tengan. (Si dos jugadores están empatados podrá mostrarse primero cualquiera
de ellos). Se mostrará un listado con el nombre del jugador y el cuántos números sin
tachar tiene. (2 puntos).
8. Escriba el programa principal teniendo en cuenta las indicaciones del juego y empleando
las funciones desarrolladas anteriormente. No es necesario volver a declarar las variables
ya declaradas en el apartado 1. (3 puntos)
2
Problema 2 (3,5 puntos)
Una ciudad tiene cuatro depósitos de agua, numerados del 1 al 4, que abastecen a cada una de sus
cuatro zonas. En cada depósito hay mecanismos para su llenado, vaciado, trasvase (paso de agua de
un depósito a otro) y medida. En un momento determinado del tiempo cada zona presenta una
demanda de agua: alta, normal o nula, que se cuantifica con las cifras 2, 1 y 0, respectivamente.
Los depósitos (de igual capacidad) pueden estar vacíos, llenos hasta la mitad o llenos por completo.
Estos estados se cuantifican con las cifras 0, 1 y 2, respectivamente. A efectos de un suministro
eficaz se mide la relación entre el contenido almacenado en un depósito y la demanda de su zona
con una variable numérica llamada necesidad, que es la diferencia entre el contenido de un
depósito y la demanda de su zona. Nótese que los valores negativos de necesidad implican que el
contenido del depósito es insuficiente para la demanda, y que los valores positivos indican buen
abastecimiento. Por ejemplo, una zona con demanda 2 (alta) cuyo depósito tiene un contenido 1
(medio) presenta una necesidad 1-2=-1 (está mal abastecida). Por otra parte, una zona con
demanda 1 (normal) cuyo depósito tiene un contenido 2 (lleno) presenta una necesidad 2-1=1 (está
bien abastecida).
Las acciones que se pueden realizar sobre un depósito son:
• Llenarlo.
• Vaciar la mitad de su contenido.
• Vaciar todo su contenido.
• Trasvasar agua a otro depósito.
Estas acciones se desarrollan de acuerdo con las siguientes condiciones:
• Un depósito no puede llenarse o recibir trasvases si está lleno.
• Un depósito no puede vaciarse o trasvasar si está vacío.
• Un depósito (donante) trasvasa a otro (receptor) el contenido que el receptor admita.
Ejemplos:
• Si un donante está medio lleno y trasvasa a un receptor vacío, éste último queda medio lleno
y el depósito donante queda vacío.
• Si un donante está lleno y trasvasa a un receptor medio lleno, el donante queda medio lleno
y el receptor queda lleno.
Se pide desarrollar el programa completo para accionar los mecanismos de los depósitos, presentar
información sobre su contenido, y asesorar al operador en sus decisiones, siguiendo los pasos que
se detallan a continuación:
a) Declarar e inicializar las estructuras para almacenar la información sobre los depósitos y las
zonas:
• Nombre del depósito (alfanumérico)
• Contenido (numérico)
• Zona (alfanumérico)
• Demanda de la zona (numérico)
• Necesidad de la zona (numérico)
b) Mostrar un menú que dé al usuario las siguientes opciones
1. Ver el contenido de todos los depósitos
2. Grabar la demanda de todas las zonas
3. Llenar un depósito.
4. Vaciar la mitad del volumen de un depósito.
5. Vaciar todo el volumen de un depósito.
3
6. Trasvasar de un depósito a otro.
7. Mostrar las acciones recomendadas
8. Salir
c) Ejecutar la acción elegida, y volver a mostrar el menú, y así sucesivamente. El programa
terminará tanto si el operador elije Salir (opción 8) como si todas las zonas están ya bien
abastecidas (la necesidad en todas las zonas es mayor o igual que 0). Antes de cerrarse, el programa
mostrará un mensaje indicando si el operador ha elegido salir o si todas las zonas están bien
abastecidas.
A continuación se da más información sobre algunas de las acciones:
1. Consultar el contenido de todos los depósitos, mostrará la información de acuerdo con el
siguiente ejemplo
Deposito 1. Norte: 2
Deposito 2. Sur: 0
Deposito 3. Este: 1
Deposito 4. Oeste: 2
2. Grabar la demanda de todas las zonas leerá por teclado el valor de la demanda en cada zona
3. Mostrar las acciones recomendadas mostrará al operador los depósitos que se recomienda
llenar, que serán aquellos que están mal abastecidos (variable necesidad con valor negativo)
Notas:
(1) El intento de realizar acciones imposibles (llenar un depósito lleno, por ejemplo), deberá
notificarse al operador. A continuación se mostrará de nuevo el menú principal.
(2) Para especificar el depósito sobre el que se realiza una acción bastará proporcionar su
número.
(3) En la resolución de este problema no es necesario usar funciones.
4
Problema 1. Depósito. Solución
#include <stdio.h>
#include <stdlib.h>
#define MAXDEP 4
/*======================================================================*
* Definir estructuras *
*======================================================================*/
struct dep {
char nombre[20]; /*nombre del deposito*/
char zona[20]; /*nombre de la zona a la que abastece*/
int estado; /*vacio=0, medio=1, lleno=2*/
int demanda; /*alta=2, baja=1, nula=0*/
int necesidad; /*positiva: bien, negativa: mal abastecida*/
};
int main(void){
int i;
int opcion;
int salir=0;
int numeroDep;
int depDa;
int depToma;
int codigoTrasvase;
int bienAbastecidas;
struct dep deposito[MAXDEP];
/*======================================================================*
* Inicializar estructuras *
*======================================================================*/
for (i=0;i<MAXDEP;i++){
strcpy(deposito[i].nombre,"");
strcpy(deposito[i].zona, "");
deposito[i].estado=0;
deposito[i].demanda=0;
deposito[i].necesidad=0;
}
/*======================================================================*
* Pedir datos *
*======================================================================*/
for(i=0;i<MAXDEP; i++){
printf ("Introduzca el nombre del deposito %d: ", i+1);
scanf ("%s", deposito[i].nombre);
printf ("Introduzca el nombre de la zona del deposito %d: ", i+1);
scanf ("%s", deposito[i].zona);
}
/*======================================================================*
* Menu *
*======================================================================*/
do {
printf ("Opciones:\n");
printf ("[1]=ver el contenido de todos los depositos\n");
printf ("[2]=grabar la demanda de todas las zonas\n");
printf ("[3]=llenar un deposito\n");
printf ("[4]=vaciar la mitad del volumen de un deposito\n");
printf ("[5]=vaciar completo\n");
printf ("[6]=trasvasar de un deposito a otro\n");
printf ("[7]=acciones recomendadas\n");
printf ("[8]=salir\n");
printf ("opcion >");
scanf("%d",&opcion);
5
switch (opcion){
case 1:{ //consulta
for (i=0;i<MAXDEP;i++){
printf("Deposito %d %s. ", i+1, deposito[i].nombre);
printf("Estado: %d\n", deposito[i].estado);
}
break;
}
case 2:{ //grabar
for(i=0;i<MAXDEP; i++){
printf ("Introduzca la demanda de la zona %s: ",
deposito[i].zona);
scanf ("%d", &deposito[i].demanda);
}
break;
}
case 3:{ /*llenar*/
printf("Deposito:");
scanf("%d", &numeroDep);
if (deposito[numeroDep-1].estado !=2){
deposito[numeroDep-1].estado=2;
} else {
printf ("el deposito está lleno\n");
}
break;
}
case 4:{ /*vaciar medio*/
printf("Deposito:");
scanf("%d", &numeroDep);
if (deposito[numeroDep-1].estado !=0){
deposito[numeroDep-1].estado --;
} else {
printf ("el deposito está vacío\n");
}
break;
}
case 5:{ /*vaciar completo*/
printf("Deposito:");
scanf("%d", &numeroDep);
if (deposito[numeroDep-1].estado !=0){
deposito[numeroDep-1].estado=0;
} else {
printf ("el deposito está vacío\n");
}
break;
}
case 6:{ /*trasvasar*/
printf("Deposito donante:");
scanf("%d", &depDa);
printf("Deposito receptor:");
scanf("%d", &depToma);
codigoTrasvase=deposito[depDa-1].estado *10 + deposito[depToma-
1].estado;
/*============================ trasvase ======================*/
switch (codigoTrasvase){
case 10:{
deposito[depDa-1].estado=0;
deposito[depToma-1].estado=1;
break;
}
case 11:{
deposito[depDa-1].estado=0;
deposito[depToma-1].estado=2;
6
break;
}
case 20:{
deposito[depDa-1].estado=0;
deposito[depToma-1].estado=2;
break;
}
case 21:{
deposito[depDa-1].estado=1;
deposito[depToma-1].estado=2;
break;
}
default: printf ("No es posible trasvasar\n");
}
/* Alternativa para el codigo del trasvase
if ((deposito[depDa-1].estado==1) &&
(deposito[depToma-1].estado==0)){
deposito[depDa-1].estado=0;
deposito[depToma-1].estado=1;
}else{
if ((deposito[depDa-1].estado==1) &&
(deposito[depToma-1].estado==1)){
deposito[depDa-1].estado=0;
deposito[depToma-1].estado=2;
}else{
if ((deposito[depDa-1].estado==2) &&
(deposito[depToma-1].estado==0)){
deposito[depDa-1].estado=0;
deposito[depToma-1].estado=2;
}else{
if ((deposito[depDa-1].estado==2) &&
(deposito[depToma-1].estado==1)){
deposito[depDa-1].estado=1;
deposito[depToma-1].estado=2;
}else{
printf("no es posible trasvasar\n");
}
}
}
}*/
/*======================= fin trasvase =========================*/
break;
}
case 7:{ /*acciones recomendadas*/
bienAbastecidas=1;
for(i=0;i<MAXDEP; i++){ /*cálculo de necesidades*/
deposito[i].necesidad=deposito[i].estado -deposito[i].demanda;
if (deposito[i].necesidad <0){
printf ("llenar deposito %d\n", i+1);
bienAbastecidas=0;
}
}
if (bienAbastecidas==1)
printf ("Todas las zonas están bien abastecidas\n");
break;
}
case 8:{
salir=1;
break;
}
default: printf ("Opcion incorrecta\n");
} /* fin gran case*/
7
/* verificación de buen abastecimiento para controlar la salida del programa*/
bienAbastecidas=1;
for(i=0;i<MAXDEP; i++){
deposito[i].necesidad=deposito[i].estado - deposito[i].demanda;
if (deposito[i].necesidad <0)
bienAbastecidas=0;
}
} while ((salir==0) && (bienAbastecidas==0)) ;
if (salir==1)
{printf ("adios, el operador ha elegido salir\n");}
else
{printf ("adios, todas las zonas estan bien abastecidas\n");}
system("PAUSE");
return (0);
}
8
Problema 2. Bingo. Solución
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FILAS 3
#define COLUMNAS 9
#define MAXJUGADORES 100
// Apartado 1. Definición de la estructura de datos
struct tipo_jugador{
char nombre[20];
int edad;
int carton[FILAS][COLUMNAS];
};
// Creamos una estructura con los datos minimos necesarios para ordenar los
jugadores
// podría también hacerse sobre la misma estructura jugadores
struct tipo_miniJugador{
int posicion;
int numParaBingo;
};
// prototipos de las funciones
void inicializaCarton(int miCarton[FILAS][COLUMNAS]);
void inicializaJugadores(struct tipo_jugador jug[], int n);
void tachaNumero(int cartonJug[FILAS][COLUMNAS], int num);
int compruebaFila(int cartonJug[FILAS][COLUMNAS], int fila);
int compruebaBingo(int cartonJug[FILAS][COLUMNAS]);
int calculaNumerosParaBingo(int cartonJug[FILAS][COLUMNAS]);
void ordenaVectorNumerosParaBingo(struct tipo_miniJugador mini_j[], int numJug);
void mostrarNumerosParaBingo(struct tipo_jugador jug[], int numJug);
// Apartado 8. Programa principal
int main(void) {
int n_jugadores;//numero de jugadores
int numBombo; //numero que sale del bombo
int i;
int JugadorConBingo=0;// flag para indicar si un jugador tiene bingo o no
int Bingo=0; // flag para terminar cuando haya algún bingo
struct tipo_jugador jugadores[MAXJUGADORES];
// int vectorNumerosParaBingo[2][MAXJUGADORES];
// leer cuantos jugadores va a haber en la partida
do{
printf("Introduzca el numero de jugadores: ");
scanf("%d",&n_jugadores);
} while ((n_jugadores>100)||(n_jugadores<0));
// inicializar los datos de los jugadores
inicializaJugadores(jugadores, n_jugadores);
/* Datos para probar. Descomentar esta parte para probar
jugadores[1].carton[0][0]=5;
jugadores[0].carton[0][0]=5;
jugadores[0].carton[0][1]=6;
*/
// partida, termina cuando hay un bingo
printf("\n Empieza la partida: \n");
9
do{
// para probar
// numAleatorio=rand();
// se lee el numbero del bombo
do{
printf("Introduzca un numero:");
scanf("%d",&numBombo);
}while ((numBombo>9)||(numBombo<0));
// se marcan los cartones
for (i=0;i<n_jugadores;i++){
tachaNumero(jugadores[i].carton,numBombo);
}
// se comprueba si hay bingo
for (i=0;i<n_jugadores;i++){
JugadorConBingo = compruebaBingo(jugadores[i].carton);
if (JugadorConBingo==1){
printf("\nEl jugador %d, %s ha hecho
Bingo\n",i,jugadores[i].nombre);
Bingo=1; //hay bingo, terminará la partida
JugadorConBingo=0; // pero el siguiente jugador podra tener bingo
o no
}
}
} while (Bingo == 0);
// Mostramos los resultados, los numeros que faltan para bingo
mostrarNumerosParaBingo(jugadores,n_jugadores);
system("PAUSE");
return 0;
}
// Funcion inicializaCarton. No se pedía en el examen, se supone ya programada
void inicializaCarton(int miCarton[FILAS][COLUMNAS]){
int i,j, numAleatorioCarton,repetido=0;
int numColumna[3];
for (i=0; i<COLUMNAS; i++){
for (j=0; j<FILAS; j++){
//Usa la función rand que genera numeros aleatorios
numAleatorioCarton = (rand()%10)+(10*i)+1;
/* para probarlo, descomentar la línea siguiente, rellena
todo con el 4
numAleatorioCarton=4; */
miCarton[j][i]=numAleatorioCarton;
}
}
}
//Apartado 2. Función inicializaJugadores
void inicializaJugadores(struct tipo_jugador jug[], int n){
int i;
for (i=0;i<n;i++){
printf("\nIntroduzca el nombre del jugador %d: \t", i);
scanf("%s",jug[i].nombre);
printf("\nIntroduzca la edad del jugador %d: \t", i);
scanf("%d",&jug[i].edad);
inicializaCarton(jug[i].carton);
}
10
}
//Apartado 3. Función marcaNumero
void tachaNumero(int cartonJug[FILAS][COLUMNAS], int num){
//num es el número a tachar en el cartón
int i,j;
for (i=0; i<FILAS; i++){
for (j=0; j<COLUMNAS; j++){
if (cartonJug[i][j]==num){
cartonJug[i][j]=0;
}
}
}
}
//Apartado 4. Comprobar fila
int compruebaFila(int cartonJug[FILAS][COLUMNAS], int fila){
int j;
int lineaHecha = 0;
int numCerosFila = 0;
// se comprueban todas las columnas de esa fila
for (j=0; j<COLUMNAS; j++){
if (cartonJug[fila][j]==0){
numCerosFila++;
}
}
if (numCerosFila==COLUMNAS){
lineaHecha=1;
}
return lineaHecha;
// devuelve 1 si la linea está completa, 0 en cas ocontrario
}
//Apartado 5. Comprobar bingo
int compruebaBingo(int cartonJug[FILAS][COLUMNAS]){
int i;
int bingoHecho = 0;
int numLinea = 0;
for (i=0;i<FILAS;i++){
numLinea = numLinea + compruebaFila(cartonJug, i);
}
if (numLinea==FILAS){
bingoHecho=1;
}
return bingoHecho;
}
//Apartado 6. Calcular números que faltan para hacer bino
int calculaNumerosParaBingo(int cartonJug[FILAS][COLUMNAS]){
int i,j;
int numFaltanTotales=0;
for (i=0;i<FILAS;i++){
for (j=0; j<COLUMNAS; j++){
if (cartonJug[i][j]!=0){
numFaltanTotales++;
}
}
}
11
return numFaltanTotales;
}
// Apartado 7. Mostrar la clasificacion (dos funciones, mostrar y ordenar)
void ordenaVectorNumerosParaBingo(struct tipo_miniJugador mini_j[], int numJug){
// ordenamos el vector en el que hemos copiado los datos
// se comparan los numeros pendientes para bingo
// pero se mueve también la posición
int i,j, aux;
for (i=1;i<=numJug-1;i++){
for (j=0;j<numJug-i;j++){
if (mini_j[j].numParaBingo > mini_j[j+1].numParaBingo){
aux=mini_j[j+1].numParaBingo;
mini_j[j+1].numParaBingo=mini_j[j].numParaBingo;
mini_j[j].numParaBingo=aux;
aux=mini_j[j+1].posicion;
mini_j[j+1].posicion=mini_j[j].posicion;
mini_j[j].posicion=aux;
}
}
}
}
void mostrarNumerosParaBingo(struct tipo_jugador jug[], int numJug){
int i;
struct tipo_miniJugador CopiaJug[MAXJUGADORES]; // copia reducida de la
estructura para ordenarla
//Pasamos los datos al vector copia, solo la posicion y cuantos numeros
faltan para bingo
for (i=0;i<numJug; i++){
CopiaJug[i].posicion = i;
CopiaJug[i].numParaBingo= calculaNumerosParaBingo(jug[i].carton);
}
// Ordenamos el vector copia en función de los numeros que faltan para bingo
ordenaVectorNumerosParaBingo(CopiaJug, numJug);
//Mostramos los resultados
printf("\n Este es el resultado de la partida: \n");
for (i=0;i<numJug; i++){
printf("\n Al Jugador %s le quedan %d numeros por tachar\n",
jug[CopiaJug[i].posicion].nombre, CopiaJug[i].numParaBingo);
}
}
12