Beruflich Dokumente
Kultur Dokumente
Quin es quin?
NDICE
Captulo 1: Introduccin a PVM. 3 Captulo 2: Definicin del Juego10 Captulo 3: Definicin del Problema..11 Captulo 4: Descripcin de la Solucin..12 Bibliografa.15 Anexo A: Manual de cdigo..16 Anexo B: Exclusin mutua. Algoritmo de anillos de fichas..41 Anexo C: Primitivas de PVM utilizadas43 Anexo D: Ejecucin y Salida del programa...46
Quin es quin?
Precio. As como es mucho ms barato un computador paralelo que el computador tradicional equivalente, un conjunto de ordenadores de mediana o baja potencia es muchsimo ms barato que el computador paralelo de potencia equivalente. Al igual que ocurrir con el caso del computador paralelo, van a existir factores (fundamentalmente, la lentitud de la red frente a la velocidad del bus del computador paralelo) que van a hacer de que sean necesarios ms ordenadores de pequea potencia que los tericos para igualar el rendimiento. Sin embargo, aun teniendo esto en cuenta, la solucin es mucho ms barata. 3
Quin es quin?
Adems, al no ser PVM una solucin que necesite de mquinas dedicadas (es decir, el daemon de PVM corre como un proceso ms), podemos emplear en el proceso los tiempos muertos de los procesadores de todas las mquinas de nuestra red a las que tengamos acceso. Por ello, si ya tenemos una red Unix montada, el costo de tener un supercomputador paralelo va a ser cero ya disponemos de las mquinas, no tendremos que comprar nada nuevo, y adems la biblioteca PVM es software libre, por lo que no hay que pagar para usarla Disponibilidad. Todo centro de clculo tiene un mnimo de una docena de mquinas arrumbadas en una esquina, y que nadie sabe qu hacer exactamente ya con ellas. Con esa docena que hace seis aos que ya no corren ni la ltima versin del Word para Windows, podemos instalar Linux, PVM y aadirlo al supercomputador paralelo virtual que conforma las mquinas que ya tendramos en red. Tolerancia a fallos. Si por cualquier razn falla uno de los ordenadores que conforman nuestra PVM y el programa que la usa est razonablemente bien hecho. Nuestra aplicacin puede seguir funcionando sin problemas. En un caso como el nuestro, en el que la aplicacin va a estar corriendo durante meses, es crtico que la aplicacin sea tolerante a fallos. Siempre hay alguna razn por la que alguna mquina puede fallar, y la aplicacin debe continuar haciendo los clculos con aquel hardware que contine disponible. Heterogeneidad. Podemos crear una mquina paralela virtual a partir de ordenadores de cualquier tipo. PVM nos va a abstraer la topologa de la red, la tecnologa de la red, la cantidad de memoria de cada mquina, el tipo de procesador y la forma de almacenar los datos. Este ltimo punto es de extrema importancia, ya que el principal problema que tendramos en los sockets era la programacin de rutinas de conversin de formato de datos entre todos los ordenadores de la red, puesto que la codificacin, tanto de enteros como de flotantes, puede ser distinta. Por ltimo, nos permite incluir en nuestra PVM hasta mquinas paralelas. Una mquina paralela en una PVM se puede comportar tanto como una sola mquina secuencial (caso, por ejemplo, del soporte SMP de Linux) o, como ocurre en muchas mquinas paralelas, presentarse a PVM como un conjunto de mquinas secuenciales.
Adems de estas ventajas con respecto al empleo de un supercomputador, tiene muchas otras: Portabilidad. Es probablemente la librera de paso de mensajes ms portable que existe. Paralelismo Escalable. PVM permite definir cuantos procesadores puede utilizar una aplicacin, en caso de que falten procesadores, PVM realiza el trabajo en menos procesadores, recurriendo a tcnicas de procesamiento concurrente. Tolerancia a fallos a partir de aadir o borrar procesos anfitriones (Host). Fcil de Instalar y de Usar. 4
Quin es quin?
Esquema fcil de modificar y de configurar/definir por la mquina virtual. Control arbitrario de dependencia de estructuras. La aplicacin decide: Donde y cuando producir o terminar las tareas. Cuales mquinas se agregan o se remueven desde la mquina virtual en paralelo. Cuales tareas se pueden comunicar y/o sincronizar con otras.
Puede incorporar casi cualquier computadora que funcione bajo UNIX, (Obviamente con cuenta de acceso), para incorporarla fcilmente al esquema de la mquina virtual.
Como hemos visto el uso de PVM tiene muchas ventajas, pero tambin tiene desventajas: Nos podemos olvidar del paralelismo fuertemente acoplado. Si disponemos de una red Ethernet, simplemente la red va a dejar de funcionar para todas las aplicaciones (incluida PVM) de la cantidad de colisiones que se van a producir en caso de que intentemos paralelismo fuertemente acoplado. Si disponemos de una red de tecnologa ms avanzada; es decir, ms cara (como ATM) el problema es menor, pero sigue existiendo. La segunda desventaja es que la abstraccin de la mquina virtual, la independencia del hardware y la independencia de la codificacin tienen un coste. PVM no va a ser tan rpida como son los Sockets. Sin embargo, si el grado de acoplamiento se mantiene lo suficientemente bajo, no es observable esta diferencia. Cuenta con un esquema no estandarizado.- PVM no es un estndar (como lo es MPI). Es algo deficiente en cuanto al paso de mensajes se refiere.
Quin es quin?
La primera parte es el daemon, llamado pvmd. En la versin actual de PVM -la 3-, el nombre es pvmd3. El daemon ha de estar funcionando en todas las mquinas que vayan a compartir sus recursos computacionales con la mquina paralela virtual. A diferencia de otros daemons y programas del sistema, el daemon de PVM puede ser instalado por el usuario en su directorio particular (de hecho, la instalacin por defecto es as). Esto nos va a permitir hacer supercomputacin como usuarios, sin tener que discutir con el administrador de la red que programas vamos a poder ejecutar. Una vez que un usuario (o superusuario) instal en un directorio PVM, todos los usuarios pueden hacer uso de esa instalacin con el requisito de que el directorio donde est instalada PVM sea de lectura al usuario que quiera hacer uso de ella. En muchos centros de computacin, el administrador prefiere instalar l mismo PVM; con lo que, adems de evitar que un usuario pueda borrarla sin consultar a los dems, va a permitir que todos los usuarios tengan PVM instalada por defecto; y, lo que es ms importante, nosotros como administradores podremos determinar el valor de nice (prioridad del daemon) con el que va a ser lanzado el daemon pvmd3 y as, si este valor de nice es lo suficientemente alto, permite que la mquina ejecute PVM solamente en los momentos ociosos. Este daemon pvmd3 es el responsable de la mquina virtual de por s, es decir, de que se ejecuten nuestros programas para PVM y de coordinar los mecanismos de comunicacin entre mquinas, la conversin automtica de datos y de ocultar la red al programador. Por ello, una vez que PVM est en marcha, el paralelismo es independiente de la arquitectura de la mquina, y slo depende de la arquitectura de la mquina virtual creada por PVM. Esto nos va a evitar el problema que tenamos con los Sockets ya que tenamos que hacer una rutina de codificacin y otra de decodificacin, al menos, por cada arquitectura distinta del sistema. Cada usuario, arrancar el daemon como si de un programa normal se tratase, para ejecutar el cdigo de PVM. Este programa se queda residente, realizando las funciones anteriores.
Las libreras de PVM (pvmd3)
La segunda parte es la biblioteca de desarrollo. Contiene las rutinas para operar con los procesos, transmitir mensajes entre procesadores y alterar las propiedades de la mquina virtual. Toda aplicacin se ha de enlazar a la biblioteca para poderse ejecutar despus. Tendremos tres ficheros de bibliotecas: Esta librera brinda una gran cantidad de rutinas escritas en lenguaje C. Esta rutina siempre es requerida. librera adicional que se requiere en caso de que la aplicacin escrita en PVM utilice cdigo de Fortran. librera requerida en caso de usar grupos dinmicos.
Quin es quin?
Quin es quin?
El envo de mensajes es sin bloqueo. Esto quiere decir que el que enva el mensaje no tiene que esperar a que el mensaje llegue, sino que solamente espera a que el mensaje sea puesto en la cola de mensajes. La cola de mensajes, adems, asegura que los mensajes de una misma tarea llegarn en orden entre si. Esto no es trivial, ya que empleando UDP puede que enviemos dos mensajes y que lleguen fuera de orden (UDP es un protocolo no orientado a conexin). TCP, por ser un protocolo orientado a la conexin, realiza una reordenacin de los mensajes antes de pasarlos a la capa superior, sin embargo, tiene el inconveniente que establecer las conexiones entre nodos empleando TCP supone, si tenemos n nodos, tendremos un mnimo de ($n)(n$-1) conexiones TCP activas. Provocando esto que hasta para nmeros ridculos de $n$ nos quedamos sin puertos por ste planteamiento. Establecer conexiones TCP entre procesos en lugar de entre nodos es peor todava, por las mismas razones que en el caso de los nodos. La comunicacin de las tareas con el daemon se hace empleando TCP. Esto se debe a que, al ser comunicaciones locales, la carga derivada de la apertura y cierre de un canal es muy pequeo. Adems, no vamos a tener tantas conexiones como en el caso de la conexin entre daemons, ya que las tareas no se conectan entre s ni con nada fuera del nodo, por lo que slo hablan directamente con su daemon. Esto determina que sern n conexiones TCP, que s es una cifra razonable. La recepcin de los mensajes podemos hacerla mediante primitivas con bloqueo, sin bloqueo o con un tiempo mximo de espera. PVM nos dotar de primitivas para realizar los tres tipos de recepcin. En principio nos sern ms cmodas las primitivas con bloqueo, ya que nos darn un mecanismo de sincronizacin bastante cmodo. Las de tiempo mximo de espera nos sern tiles para trabajar con ellas como si fuesen con bloqueo, mas dando soporte al hecho de que puede que el que tiene que mandarnos el mensaje se haya colgado. Por ltimo, la recepcin de mensajes mediante primitivas sin bloqueo hace de la sincronizacin un dolor de cabeza. De cualquier forma, en los tres casos anteriormente citados la misma PVM se encargar de decirnos cundo una tarea acab. Para informarnos de lo que pasa, emplea un mecanismo de eventos asncronos. PVM puede ser empleada de forma nativa como funciones en C y en C++, y como procedimientos en Fortran. Basta para ello con tomar las cabeceras necesarias (si trabajamos con C o C++); y, para los tres, enlazar con la biblioteca adecuada, que viene con la distribucin estndar. En el caso de C es libpvm3.a y en el del Fortran libfpvm3.a. Si deseamos trabajar en otros lenguajes puede ser un poco ms complejo. Si el lenguaje permite incorporar funciones nativas en lenguaje C (como es el caso, por ejemplo, de Java) no hay ningn problema; ya que podemos invocar la funcin; bien directamente si el lenguaje lo permite, bien haciendo alguna pequea rutina para adaptar el tipo de los datos, el formato de llamada a funcin o cualquiera de las restricciones que nos imponga el lenguaje que empleemos para invocar funciones en C. Hemos de destacar que toda funcin en C pvm_alguna cosa tiene como equivalente en Fortran pvmfalgunacosa, y viceversa.
Quin es quin?
El programa PVM corresponde al intrprete de comandos de nuestra mquina virtual. Algunos de los comandos ms importantes son:
add mquina: Incorpora la mquina indicada a la mquina paralela virtual. delete mquina: Elimina la mquina indicada del conjunto de mquinas asociadas a la mquina paralela virtual. Como es lgico, no podremos eliminar la mquina desde la que estamos ejecutando el intrprete de comandos. conf: Configuracin actual de la mquina paralela virtual. ps: Listado de procesos de la mquina paralela virtual. ps -a lista todos los procesos. halt: Apaga la mquina paralela virtual. Esto significa que mata todas las tareas de PVM, elimina el daemon de forma ordenada y sale del programa pvm. help: Lista los comandos del programa. Tremendamente til en los momentos de desesperacin. id: Imprime el TID de la consola. jobs: Genera un listado de los trabajos en ejecucin. kill: Mata un proceso de PVM. mstat: Muestra el estado de una mquina de las pertenecientes a PVM. pstat: Muestra el estado de un proceso de los pertenecientes a PVM. quit: Sale de la mquina paralela virtual sin apagarla. reset: Inicializa la mquina. Eso supone matar todos los procesos de PVM salvo los programas monitores en ejecucin, limpiar las colas de mensajes y las tablas internas y pasar a modo de espera todos los servidores. setenv: Lista todas las variables de entorno del sistema. sig seal tarea: Manda una seal a una tarea. spawn: Arranca una aplicacin bajo PVM. Es un comando bastante complejo cuyas opciones veremos en una seccin aparte. trace: Actualiza o visualiza la mscara de eventos traceados. alias: Define un alias predefinido, es decir, un atajo para teclear un comando. unalias: Elimina un alias predefinido. version: Imprime la versin usada de PVM.
Quin es quin?
10
Quin es quin?
11
Quin es quin?
Antes de empezar la comunicacin se produce una sincronizacin de todos los elementos del grupo, para que todos se encuentren en el mismo punto. El proceso juego enva a los jugadores los personajes, las preguntas y el jugador que comienza, esto lo hace mediante multiemisin a todos los elementos del grupo excepto a el mismo.
12
Quin es quin?
Ahora empieza el juego en s, con las preguntas de los jugadores y las respuestas del juego. Para solucionar el problema de la seccin crtica anteriormente descrito, aplicamos el algoritmo de anillo de fichas con todos los jugadores (para ver en que consiste mirar el Anexo B). La ficha la introduce el jugador que comienza (el que escogi de forma aleatoria el padre), el resto esperar su turno, es decir que le pase la ficha el jugador que le precede. El orden del anillo corresponder con el orden en que entraron en el grupo. Pero adems de pasar el turno de unos jugadores a otros, se informar al siguiente jugador de si el juego ha concluido o no. (En la figura siguiente se representa como jugador inicial al 1, sin embargo como se sabe es aleatorio)
Cuando un jugador recibe el turno, ste enva su pregunta al juego. Esta pregunta puede ser sobre una caracterstica o un personaje. Como ambos ser un nmero entero y positivo, hay que hacer algo para diferenciarlos. Para ello, cuando se pregunte por un personaje, se encriptar el mensaje, se pone negativo y se le resta 1. El jugador elegir que preguntar de la siguiente manera. Si est seguro de quien es pregunta por l. Sino, existe una probabilidad de que el jugador se arriesgue y pregunte por un personaje, en este caso el jugador elige aleatoriamente entre los personajes que no ha eliminado. Si no se arriesga, pregunta por una caracterstica, para ello elige entre las preguntas restantes. Posteriormente el juego recibe la pregunta y la procesa. Si es una pregunta sobre una caracterstica encuentra la respuesta y la enva. Si es una pregunta sobre un personaje, el juego comprueba si el jugador ha acertado o no. Si acierta es el ganador y el juego termina. Si falla el jugador es eliminado y el juego continua, a no ser que ya slo queda un jugador en este caso termina y este es el ganador. En este caso el juego enva al jugador si el juego ha acabado o no. Por ltimo el jugador recibe la respuesta. Si es a una pregunta de caractersticas, elimina los personajes que no cumplen la condicin que se saca de dicha respuesta, y tambin elimina las preguntas que ya no hacen falta hacer, ya sea por que ya han sido formuladas o porque no haga falta realizarla ya que la respuesta ya se 13
Quin es quin?
conoce de antemano, despus pasa el turno al siguiente jugador en el anillo. Si pregunt por un personaje, recibir la informacin de si el juego ha acabado o no; si acaba termina pasa el turno al siguiente, indicando que el juego ha acabado, si no acaba, igualmente pasa el turno al siguiente, pero sin indicar que el juego ha concluido. En este ltimo caso, el jugador est eliminado y su objetivo ahora ser recibir el turno y pasarlo, sin hacer nada con l, hasta que le digan que le juego ha acabado.
Tal y como se ha planteado la solucin, tenemos un modelo cliente-servidor. En el que el juego es un servidor dedicado, que espera las preguntas de los clientes, los jugadores, y las responde. Sin embargo es un servidor que en todo momento sabe quin le va a pedir servicio y por lo tanto slo espera la peticin de dicho cliente.
14
Quin es quin?
Bibliografa
Tenembaun, Andrew S. Sistemas Operativos Distribuidos. Traducido por Palmas Velasco, scar A. Revisin tcnica de Guerrero, Gabriel. Primea Edicin. Naucalpan de Jurez, Estado de Mxico. Prentice Hall Hispanoamericana, S. A. 1996. 617 p. ISBM: 968-880-627-7. Hervs Martnez, Csar. Apuntes de PVM. Servicio de Reprografa de la Universidad de Crdoba. 2004. Ercilla Gonzlez, Carmen (i12gopac). Trabajo sobre PVM: Juego en familia. 2003-2004. Milanez Santilln, Jorge Alberto. http://iio.ens.uabc.mx/~jmilanez/escolar/ sistemas_operativos/expo-5.html. Descripcin: Teora sobre PVM. Fecha de creacin: 2004-Mar-22. ltima visita realizada: 20-Dic-2004. Olea, Ismael. http://es.tldp.org/Manuales-LuCAS/doc-cluster-computadoras/ doc-cluster-computadoras-html/node44.html. Descripcin: Teora sobre PVM. Fecha de creacin: 01-Nov-1997. ltima visita realizada: 19-Dic-2004. Http://computing.ee.ethz.ch/sepp/condor-6.3.1-to.SEPP/examples/PVM/. Descripcin: Ejemplo de programa en PVM. Fecha de creacin: 01-Nov-1997. ltima visita realizada: 20-Dic-2004.
15
Quin es quin?
/* Definicin de la informacin que vamos a utilizar en el juego. Para facilitar el cmputo, se le asocian nmeros enteros */ #define HOMBRE 0 #define MUJER 1 #define RUBIO 0 #define MORENO 1 #define PELIRROJO 2 #define CASTANO 3 #define CANOSO 4 #define AZULES 0 #define VERDES 1 #define MARRONES 2 #define NEGROS 3 #define CORTO 0 #define LARGO 1 #define NO 0 #define SI 1 /* Definicin de la estructura "personaje", con todos los campo con los que vamos a caracterizar a los personajes de los que va a formar el juego */ typedef struct { char nombre[10]; int sexo; int color_pelo; int ojos; int pecas; int gafas; int long_pelo; int pendientes; int barba; } personaje; /* Nombre del personaje */ /* Sexo del personaje */ /* Color de pelo del personaje */ /* Color de ojos del personaje */ /* Si el personaje tiene pecas o no */ /* Si el personaje tiene gafas o no */ /* Longitud del pelo del personaje */ /* Si el personaje lleva pendientes o no */ /* Si el personaje tiene barba o no */
16
Quin es quin?
void crear_personajes(personaje personajes[NPERS]); void crear_preguntas(char preguntas[NPREG][50]); int obtener_respuestas(int n_pregunta); /* FUNCIN - main DESCRIPCIN - Funcin principal del motor del juego. Crea los jugadores les pasa los personajes y las preguntas que crea y el jugador que comienza. Despus espera preguntas y las responde, si le preguntan por algn personaje comprueba si ha acertado, pudiendo finalizar el juego o continuar con l. Adems va imprimiendo en un fichero con toda la informacin relativa a la partida PARMETROS - int argc, char *argv[] VALOR DEVUELTO - Nada */ main(int argc, char *argv[]) { char preguntas[NPREG][50];/* las preguntas de las que consta el juego */ personaje personajes[NPERS]; int mytid; int *tids; int info; int i; int n_jugadores; int n_personaje; int jug_actual; int n_pregunta; int per_creido; int respuesta; int terminado=0; int *jug_eliminado; /* los personajes que forman parte del juego */ /* El TID de este motor de juego */ /* puntero que apuntar al lugar donde se almacenarn los TIDs de los procesos hijos (jugadores) */ /* variable de recogida de errores */ /* variable auxiliar */ /* nmero de jugadores que van a participar */ /* nmero del personaje elegido para el juego */ /* jugador que tiene el turno */ /* nmero de la pregunta formulada */ /* personaje que un jugador cree que es el elegido */ /* respuesta a la pregunta hecha por un jugador S o NO */ /* variable para indica si el juego ha acabado o no. Se inicializa con 0 */ /* puntero que apuntar al lugar donde se almacenar un vector para ver si un jugador est jugando o est eliminado */ /* nmero de jugadores eliminados. Inicialmente es 0 */ /* lgico del fichero */ /* Obtenmos el TID del proceso*/
17
Quin es quin?
if( mytid < 0 ) { pvm_perror("ERROR: El en el identificador del motor del juego \n"); pvm_exit(); exit(0); } if(argc == 1) { /* Si no introduce el nmero de jugadores por consola habr que pedirlos por pantalla */ do{ printf("Introduce el nmero de jugadores que van a participar (2-%d): ",MAXNJUG); scanf("%s",argv[0]); /* Almacenamos el nmero de jugadores en argv[0] para despus pasarselo a los hijos*/
n_jugadores = atoi(argv[0]); if( n_jugadores < 2 || n_jugadores > MAXNJUG ) printf("ERROR: El nmero de jugadores debe estar entre 2 y %d\n",MAXNJUG); }while( n_jugadores < 2 || n_jugadores > MAXNJUG ); } else { if(argc == 2) { n_jugadores = atoi(argv[1]); if(n_jugadores < 2 || n_jugadores > MAXNJUG) { printf("ERROR: El nmero de jugadores debe estar entre 2 y %d\n",MAXNJUG); pvm_exit(); exit(0); } } else { printf("ERROR: Nmero de argumentos no vlido\n",MAXNJUG); pvm_exit(); exit(0); } } /* Creamos el grupo donde ocupar la posicin 0; si no tiene es posicin, el grupo es errneo */ if( pvm_joingroup("juego") != 0 ) { pvm_perror("ERROR: El grupo est corrupto\n"); pvm_lvgroup( " juego " ); pvm_exit(); exit(0); } /* Ya que conocemos el nmero de jugadores, reservamos memoria para el vector TIDs y el vector jug_eliminado*/ if( (tids = (int *)(malloc(sizeof(int)*n_jugadores))) == NULL ) { printf("ERROR: No se ha podido reservar memoria correctamente\n"); pvm_lvgroup( "juego" ); pvm_exit(); exit(0); } if( (jug_eliminado = (int *)(malloc(sizeof(int)*jug_eliminados))) == NULL ) { printf("ERROR: No se ha podido reservar memoria correctamente\n"); pvm_lvgroup( "juego" ); pvm_exit(); exit(0); }
18
Quin es quin?
pvm_barrier( "juego", n_jugadores+1 ); /* Sincronizamos a todos los elementos del grupo, para que la comunicacin entre el motor los jugadores sea correcta */ /* Creacin de los personajes y las preguntas de las que constar el juego */ crear_personajes(personajes); crear_preguntas(preguntas); srand ((unsigned int)time(NULL)); n_personaje = rand()%NPERS; /* Nmero aleatorio entre 0 y 31, ya que hay 32 personajes */ /* Nmero entre 1 y el nmero de jugadores que representa la posicin en el grupo del jugador que comienza */
fprintf(f,"Nmero de jugadores que participan en el juego: %d\n\n",n_jugadores); /* Obtenemos los TIDs de los jugadores en el orden en que estn en el grupo, que ser el orden en el juego, empezando por el elegido aleatoriamente */ for(i=0;i<n_jugadores;i++) { jug_eliminado[i] = 0; tids[i] = pvm_gettid("juego", i+1); fprintf(f,"Jugador %d: t%x\n",i+1,tids[i]); } fprintf(f,"\nLa mquina ha elegido a %s \n\n",personajes[n_personaje].nombre); fprintf(f,"Empieza el jugador %d\n\n",jug_actual); /* Iniciamos el buffer, empaquetamos y enviamos a los jugadores los personajes y las preguntas creados y el jugador que comenzar el juego. Este envo se har mediante multiemisin a todos los elementos del grupo excepto l */ pvm_initsend(PvmDataDefault); for(i=0;i<NPERS;i++) { pvm_pkstr(personajes[i].nombre); pvm_pkint(&personajes[i].sexo,1,1); pvm_pkint(&personajes[i].color_pelo,1,1); pvm_pkint(&personajes[i].ojos,1,1); pvm_pkint(&personajes[i].pecas,1,1); pvm_pkint(&personajes[i].gafas,1,1); pvm_pkint(&personajes[i].long_pelo,1,1); pvm_pkint(&personajes[i].pendientes,1,1); pvm_pkint(&personajes[i].barba,1,1); }
19
Quin es quin?
for(i=0;i<NPREG;i++) pvm_pkstr(preguntas[i]); pvm_pkint(&jug_actual,1,1); pvm_bcast("juego",1); jug_actual--; /* Decrementamos jug_actual, para que su valor est entre 0 y n_jugadores-1 ya que los vectores empiezan desde 0 */
printf("\nLa partida se est llevando a cabo "); /* Bucle que representa el papel de motor de juego, recibiendo preguntas y respondindolas */ while( terminado == 0 ) { /* Espera la pregunta del jugador que posee el turno en cada momento */ pvm_recv(tids[jug_actual],2); pvm_upkint(&n_pregunta,1,1); /* Si el valor que llega es positivo es una pregunta, si es negativo es un personaje encriptado y habr que comprobar si ha acertado */ /* Desencripta para obtener el nmero del personaje que el jugador cree es la solucin */
respuesta = (per_creido == n_personaje); /* Comprueba si el jugador ha acertado o no. Ser 1 si es correcto 0 si es incorrecto */ fprintf(f,"Jugador %d => Es %s?\n",jug_actual+1,personajes[per_creido].nombre); fprintf(f,"Ordenador => %s\n\n",respuesta ? "S" : "NO"); /* Si la respuesta es 1 es que el jugador ha acertado, por lo tanto es el ganador y el juego termina; si la respuesta es 0 el jugador es eliminado */ if(respuesta) { terminado = 1; fprintf(f,"*****************************************\n"); fprintf(f,"*\tGANADOR JUGADOR %d => ,jug_actual+1); fprintf(t%x\t*\n", tids[jug_actual]); fprintf(f,"*****************************************\n\n"); } else { fprintf(f,"JUGADOR %d eliminado\n\n",jug_actual+1); jug_eliminado[jug_actual]=1; jug_eliminados++; /* Al eliminar la jugador comprobamos que quedan ms de dos jugadores particando para continuar con el juego, si no fuese as el juego termina y se busca el jugador que queda, ya que este ser el ganador */
20
Quin es quin?
if( n_jugadores-1 == jug_eliminados ) { respuesta = 1; /* Ponemos respuesta a 1 para indicar al jugador que le juego ha acabado */ terminado = 1; /* Buscamos al ganador*/ i=-1; do{ i++; }while(jug_eliminado[i]==1); fprintf(f,"Han sido eliminados todos los jugadores menos uno\n"); fprintf(f,"\n*****************************************\n"); fprintf(f,"*\tGANADOR JUGADOR %d => t%x\t*\n",i+1,tids[i]); fprintf(f,"*****************************************\n\n"); } } } else { /* Obtenemos la respuesta a la pregunta formulada */ respuesta = obtener_respuesta(n_pregunta,personajes,n_personaje); fprintf(f,"Jugador %d => %s\n",jug_actual+1,preguntas[n_pregunta]); fprintf(f,"Ordenador => %s\n\n",respuesta ? "S" : "NO"); } /* Enviamos la respuesta al jugador. Si hizo una pregunta, si le enva un 1 significa que la respuesta es S y si enva un 0 es lo contrario. Si dijo un personaje se le manda si el juego ha terminado 1, o no 0 */ pvm_initsend(PvmDataDefault); pvm_pkint(&respuesta,1,1); pvm_send(tids[jug_actual],3); /* Buscamos el siguiente jugador en el orden, que siga participando */ do{ jug_actual=(jug_actual+1)%n_jugadores; }while(jug_eliminado[jug_actual]==1); } fprintf(f,"****** FIN JUEGO ******"); fclose(f); printf("\nLa partida ha sido almacenada en el fichero \"salida.txt\"\n\n"); free(tids); free(jug_eliminado); pvm_lvgroup( "juego" ); pvm_exit(); exit(0); }
21
Quin es quin?
DESCRIPCIN - Funcin que a partir del nmero de la pregunta que recibe, devuelve la respuesta a dicha pregunta consultando el personaje elegido. Devolver 0 si la respuesta es "NO" o 1 si la respuesta es "S" PARMETROS - int n_pregunta, personaje *personajes, int n_personaje VALOR DEVUELTO - int (0 1) */ int obtener_respuesta(int n_pregunta,personaje *personajes,int n_personaje) { switch (n_pregunta) { case 0: return personajes[n_personaje].sexo==HOMBRE; case 1: return personajes[n_personaje].sexo==MUJER; case 2: return personajes[n_personaje].color_pelo==RUBIO; case 3: return personajes[n_personaje].color_pelo==MORENO; case 4: return personajes[n_personaje].color_pelo==PELIRROJO; case 5: return personajes[n_personaje].color_pelo==CASTANO; case 6: return personajes[n_personaje].color_pelo==CANOSO; case 7: return personajes[n_personaje].ojos==AZULES; case 8: return personajes[n_personaje].ojos==VERDES; case 9: return personajes[n_personaje].ojos==MARRONES; case 10: return personajes[n_personaje].ojos==NEGROS; case 11: return personajes[n_personaje].pecas==SI; case 12: return personajes[n_personaje].gafas==SI; case 13: return personajes[n_personaje].long_pelo==CORTO; case 14: return personajes[n_personaje].long_pelo==LARGO; case 15: return personajes[n_personaje].pendientes==SI; case 16: return personajes[n_personaje].barba==SI; } }
22
Quin es quin?
DESCRIPCIN - Funcin que rellena el vector de estructuras que la funcin recibe, esta informacin representa los diferentes personajes que intervienen en el juego PARMETROS - personaje personajes[NPERS] VALOR DEVUELTO - Nada */ void crear_personajes(personaje personajes[NPERS]) { strcpy(personajes[0].nombre,"Mara"); personajes[0].sexo=MUJER; personajes[0].color_pelo=RUBIO; personajes[0].ojos=AZULES; personajes[0].pecas=SI; personajes[0].gafas=SI; personajes[0].long_pelo=LARGO; personajes[0].pendientes=SI; personajes[0].barba=NO; strcpy(personajes[1].nombre,"Rosa"); personajes[1].sexo=MUJER; personajes[1].color_pelo=RUBIO; personajes[1].ojos=VERDES; personajes[1].pecas=NO; personajes[1].gafas=NO; personajes[1].long_pelo=LARGO; personajes[1].pendientes=NO; personajes[1].barba=NO; strcpy(personajes[2].nombre,"Antonia"); personajes[2].sexo=MUJER; personajes[2].color_pelo=RUBIO; personajes[2].ojos=MARRONES; personajes[2].pecas=NO; personajes[2].gafas=NO; personajes[2].long_pelo=LARGO; personajes[2].pendientes=SI; personajes[2].barba=NO; strcpy(personajes[3].nombre,"Margarita"); personajes[3].sexo=MUJER; personajes[3].color_pelo=MORENO; personajes[3].ojos=NEGROS; personajes[3].pecas=NO; personajes[3].gafas=SI; personajes[3].long_pelo=LARGO; personajes[3].pendientes=NO; personajes[3].barba=NO; strcpy(personajes[4].nombre,"Violeta"); personajes[4].sexo=MUJER; personajes[4].color_pelo=MORENO; personajes[4].ojos=VERDES; personajes[4].pecas=SI; personajes[4].gafas=NO; personajes[4].long_pelo=LARGO; personajes[4].pendientes=SI; personajes[4].barba=NO; strcpy(personajes[5].nombre,"Eva"); personajes[5].sexo=MUJER; personajes[5].color_pelo=MORENO; personajes[5].ojos=MARRONES;
23
Quin es quin?
24
Quin es quin?
25
Quin es quin?
26
Quin es quin?
27
Quin es quin?
DESCRIPCIN - Funcin que rellena el vector de cadenas que la funcin recibe, esta informacin representa las diferentes preguntas que los jugadores pueden formular a lo largo del juego PARMETROS - personaje personajes[NPERS] VALOR DEVUELTO - Nada */ void crear_preguntas(char preguntas[NPREG][50]) { strcpy(preguntas[0],"Es hombre?"); strcpy(preguntas[1],"Tu personaje es mujer?"); strcpy(preguntas[2],"Tiene el pelo rubio?"); strcpy(preguntas[3],"Es moreno?"); strcpy(preguntas[4],"Tu personaje, Es pelirrojo?"); strcpy(preguntas[5],"El color de pelo es castao?"); strcpy(preguntas[6],"Tiene el pelo canoso?"); strcpy(preguntas[7],"Tiene los ojos azules?"); strcpy(preguntas[8],"El color de los ojos es verde?"); strcpy(preguntas[9],"Los ojos de tu personaje son marrones?"); strcpy(preguntas[10], "El color de ojos de tu personaje es negro?"); strcpy(preguntas[11],"Tiene pecas?"); strcpy(preguntas[12],"Lleva gafas?"); strcpy(preguntas[13],"Tu personaje tiene el pelo corto?"); strcpy(preguntas[14],"Tiene el pelo largo?"); strcpy(preguntas[15],"Lleva pendientes?"); strcpy(preguntas[16],"Tiene, tu personaje, barba?"); }
28
Quin es quin?
int eliminar_personajes(int n_pregunta, int tabla_pers[NPERS],personaje *personajes,int respuesta); int eliminar_preguntas(int tabla_pers[NPERS], personaje personajes[NPERS], int tabla_preg[NPREG], int pers_posibles); int probabilidad_arriesgarse(int pers_posibles); int pregunta_aleatoria(int preg_eliminadas, int tabla_preg[NPREG]); int personaje_aleatorio(int pers_posibles, int tabla_pers[NPERS]); /* FUNCIN - main DESCRIPCIN - Funcin principal del jugador. Intenta adivinar el persanaje secreto. Para ello espera su turno, pregunta por una caracterstica o por un personaje, recibe la respuesta y la procesa, realizando las operaciones de acuerdo con esa respuesta. PARMETROS - int argc, char *argv[] VALOR DEVUELTO - Nada */ main(int argc, char *argv[]) { personaje personajes[NPERS]; char preguntas[NPREG][50]; int ptid;
/* los personajes que forman parte del juego */ /* las preguntas de las que consta el juego */ /* TID del proceso padre */
int tabla_pers[NPERS], tabla_preg[NPREG]; /* tablas donde se indican si un personaje o una pregunta, respectivamete, est eliminado o no */ int id_grupo; int i; int n_pregunta; int respuesta; int jug_inicial; int n_jugadores; int jug_izquierda, jug_derecha; int pers_posibles=NPERS; /* la posicin del jugador dentro del grupo */ /* variale auxiliar */ /* nmero de la pregunta que formula */ /* respuesta que recibe, S o NO */ /* la posicin del jugador dentro del grupo del jugador que comienza a jugar */ /* nmero de jugadores que participan */ /* TID del personaje que est situado a la derecha y a la izquierda en el anillo que se forma */ /* nmero de personajes que no han sido eliminados y por lo tanto pueden ser el personaje secreto. Inicialmente contiene el valor de NPERS */ /* nmero del persoanje que el jugador cree que puede ser el elegido por la mquina */ /* variable para indica si el juego ha acabado o no */ /* nmero de preguntas eliminadas. Inicialmente contiene el valor 0 */ /* variable que indica si el jugador est eliminado o no*/
29
Quin es quin?
/* Obtenemos el nmero de jugadores que nos enva el motor del juego. Esta valor ser el ltimo argumento que pasa, por lo tanto estar almacenado en argv[argc-1], ya que argc es el nmero de elementos pasados y los vectores comienzan en 0 */
ptid = pvm_parent();
/* Obtenemos el TID del padre */ /* Adjuntamos al jugador al grupo. La posicin dentro del grupo ser entre 1 y n_jugadores, ya que el nmero 0 del grupo es el motor del juego*/
pvm_barrier( "juego", n_jugadores+1 ); /* Sincronizamos a todos los elementos del grupo, para que la comunicacin entre el motor y los jugadores sea correcta */ /* Recibimos del padre (motor del juego) y desempaquetamos los personajes y las preguntas del juego y el jugador que comenzar el juego*/ pvm_recv(ptid,1); for(i=0;i<NPERS;i++) { pvm_upkstr(personajes[i].nombre); pvm_upkint(&personajes[i].sexo,1,1); pvm_upkint(&personajes[i].color_pelo,1,1); pvm_upkint(&personajes[i].ojos,1,1); pvm_upkint(&personajes[i].pecas,1,1); pvm_upkint(&personajes[i].gafas,1,1); pvm_upkint(&personajes[i].long_pelo,1,1); pvm_upkint(&personajes[i].pendientes,1,1); pvm_upkint(&personajes[i].barba,1,1); tabla_pers[i]=0; /* Inicializamos todos los personajes como no eliminados */ } for(i=0;i<NPREG;i++) { pvm_upkstr(preguntas[i]); /* Probar pvm_psend */ tabla_preg[i]=0; /* Inicializamos todas las preguntas como no eliminadas */ } pvm_upkint(&jug_inicial,1,1); /* Determina los vecinos en el anillo. El anillo esta formado slo por los jugadores. Por lo tanto el vecino izquierdo del 1 es el n_jugadores y el de la derecha del n_jugadores es el 1 (ya que el 0 es le motor del juego y no forma parte del anillo) */ jug_izquierda = pvm_gettid("juego", id_grupo == 1 ? n_jugadores : id_grupo-1); jug_derecha = pvm_gettid("juego", id_grupo%n_jugadores + 1); /* Le damos el turno al jugador que ha sido elegido. El resto esperan hasta que les toque su turno, que les ser enviado por su vecino izquierdo del anillo, que es el jugador que les precede en el turno. Cuando se pasa el turno se enva una informacin "terminado", esta informacin nos indicar si el juego ha acabado o no (1 0 respectivamente) */ if( id_grupo == jug_inicial ) terminado=0; /*Inicializa "terminado" a 0 */ else { pvm_recv( jug_izquierda, 4 ); /* Espera su turno */ pvm_upkint(&terminado,1,1); /* Recibe si el juego ha acabado o no */ } srand ((unsigned int)time(NULL)+id_grupo);
30
Quin es quin?
while(terminado == 0) { if( eliminado == 1 ) { /* Como est eliminado lo nico que hace es pasar el turno al siguinte */ pvm_initsend( PvmDataDefault ); pvm_pkint(&terminado,1,1); pvm_send( jug_derecha, 4); pvm_recv( jug_izquierda, 4); pvm_upkint(&terminado,1,1); } else { /* Si el jugador no est eliminado, puede pasar a preguntar. Si slo le queda un personaje como posible preguntar por l, adems tiene una probabilidad de arriesgarse an no estando seguro de quin es, esta probabilidad aumenta cuanto menos personajes le quede como posibles. Sino hace una pregunta sobre una caracterstica */ if( pers_posibles == 1 || rand()%100 < probabilidad_arriesgarse(pers_posibles)) { /* Elegimos un personaje aleatoriamente entre los que quedan */ per_creido = personaje_aleatorio(pers_posibles,tabla_pers); per_creido = -(per_creido+1); /* Encriptamos para que el motor del juego sepa que no es una pregunta */ /* Enviamos el personaje credo al motor */ pvm_initsend( PvmDataDefault ); pvm_pkint(&per_creido,1,1); pvm_send(ptid,2); /* Recibimos la respuesta del motor. En este caso este valor nos indicar si el juego ha acabado o no */ pvm_recv(ptid,3); pvm_upkint(&respuesta,1,1); if(respuesta) terminado=1; else eliminado=1; } else { /* Elegimos una pregunta aleatoriamente entre las que quedan */ n_pregunta=pregunta_aleatoria(preg_eliminadas,tabla_preg); /* Enviamos esa pregunta al motor del juego */ pvm_initsend( PvmDataDefault ); pvm_pkint(&n_pregunta,1,1); pvm_send( ptid, 2); /* Recibimos la respuesta del motor */ pvm_recv( ptid, 3 ); pvm_upkint(&respuesta,1,1); /* Elimina los personajes y las preguntas usando la informacin obtenida en este turno */ pers_posibles -= eliminar_personajes(n_pregunta,tabla_pers,personajes,respuesta); preg_eliminadas = eliminar_preguntas(tabla_pers, personajes, tabla_preg, pers_posibles); /* Si el juego no ha acabado es porque se ha equivocado y por lo tanto se elimina al jugador */ /* Si la respuesta es S entonces el juego ha acabado*/ /* Vuelve esperar su turno */
31
Quin es quin?
/*Enviamos el turno al siguinete jugador */ pvm_initsend( PvmDataDefault ); pvm_pkint(&terminado,1,1); pvm_send( jug_derecha, 4); /* Esperamos ha recibir el turno */ pvm_recv( jug_izquierda, 4); pvm_upkint(&terminado,1,1); } } } /* Informamos al jugador de la derecha que el juego ya ha acabado, ya que si ha concluido el bucle significa que "terminado" es igual a 1 */ pvm_initsend( PvmDataDefault ); pvm_pkint(&terminado,1,1); pvm_send( jug_derecha, 4 ); /* El jugador finaliza dejando el grupo y saliendo de pvm */ pvm_lvgroup( "juego" ); pvm_exit(); exit(0); }
/* FUNCIN - probabilidad_arriesgase DESCRIPCIN - Funcin que representa una funcin de probabilidad en tanto por ciento. El parmetro de la funcin es la cantidad de personajes que no han sido eliminados, y por lo tanto pueden ser el personaje secreto, y la probabilidad es el valor que se devuelve. La probabilidad mnima es 1% (0.01), que es cuando el nmero de personajes que Quedan es menor o igual al NPERS y mayor que 16; y la mayor probabilidad es 20% (0.2), que es cuando slo quedan dos personajes posibles PARMETROS - int x VALOR DEVUELTO - int */ int probabilidad_arriesgarse(int pers_posibles) { if( pers_posibles <= NPERS && pers_posibles > 16 ) return 1; if( pers_posibles <= 16 && pers_posibles > 8 ) return 2; if( pers_posibles <= 8 && pers_posibles > 4 ) return 4; if( pers_posibles <= 4 && pers_posibles > 2 ) return 10; if( pers_posibles == 2 ) return 20; }
32
Quin es quin?
/* FUNCIN - pregunta_aleatoria DESCRIPCIN - Funcin que se encarga de de elegir una pregunta de forma aleatoria entre los preguntas que no han sido eliminadas. Devuelve el nmero de la pregunta elegida PARMETROS - int preg_eliminadas, int tabla_preg[NPREG] VALOR DEVUELTO - int */ int pregunta_aleatoria(int preg_eliminadas, int tabla_preg[NPREG]) { int i, n_pregunta; i = rand()%(NPREG-preg_eliminadas); /* Generamos un nmero aleatorio par escoger entre las preguntas restantes*/
/* Buscamos la pregunta elegida buscando la i-sima pregunta no formulada */ n_pregunta=-1; do{ n_pregunta++; if(tabla_preg[n_pregunta]==0) i--; }while( i != -1 ); return n_pregunta; }
/* FUNCIN - personaje_aleatorio DESCRIPCIN - Funcin que se encarga de de elegir un personaje aleatoriamente entre los personajes que no han sido eliminados. Devuelve el nmero de ese personaje elegido PARMETROS - int pers_posibles, int tabla_pers[NPERS] VALOR DEVUELTO - int */ int personaje_aleatorio(int pers_posibles, int tabla_pers[NPERS]) { int i, n_personaje; i = rand()%(pers_posibles); /* Generamos un nmero aleatorio para escoger entre los personajes restantes*/
/* Buscamos el personaje elegido buscando el i-simo personaje no eliminado */ n_personaje=-1; do{ n_personaje++; if(tabla_pers[n_personaje]==0) i--; }while( i != -1 ); return n_personaje; }
33
Quin es quin?
DESCRIPCIN - Funcin que se encarga de eliminar aquellos personajes que no pueden ser el personaje secreto, a partir de la respuesta que se ha dado a la pregunta formulada (ambos parmetros se pasan a la funcin). Se devuelve el nmero de personajes que se han eliminado para cada pregunta PARMETROS - int n_pregunta, int tabla_pers[NPERS],personaje personajes[NPERS],int respuesta VALOR DEVUELTO - int */ int eliminar_personajes(int n_pregunta, int tabla_pers[NPERS],personaje personajes[NPERS],int respuesta) { int i,pers_eliminados=0; /* Dependiendo de la pregunta tendremos que comprobar una caractrstica u otra de los personajes. Hacemos un recorrido por todos los personajes no eliminados y aquellos que no cumplan la condicin que se desprende de la respuesta a la pregunta formulada (que es la que cumple el personaje secreto), sern eliminados */ switch (n_pregunta) { case 0: for(i=0;i<NPERS;i++) if(tabla_pers[i]==0) if( (personajes[i].sexo==HOMBRE) != respuesta ) { tabla_pers[i]=1; pers_eliminados++; } break; case 1: for(i=0;i<NPERS;i++) if(tabla_pers[i]==0) if( (personajes[i].sexo==MUJER) != respuesta ) { tabla_pers[i]=1; pers_eliminados++; } break; case 2: for(i=0;i<NPERS;i++) if(tabla_pers[i]==0) if( (personajes[i].color_pelo==RUBIO) != respuesta ) { tabla_pers[i]=1; pers_eliminados++; } break; case 3: for(i=0;i<NPERS;i++) if(tabla_pers[i]==0) if( (personajes[i].color_pelo==MORENO) != respuesta ) { tabla_pers[i]=1; pers_eliminados++; } break;
34
Quin es quin?
case 4: for(i=0;i<NPERS;i++) if(tabla_pers[i]==0) if( (personajes[i].color_pelo==PELIRROJO) != respuesta ) { tabla_pers[i]=1; pers_eliminados++; } break; case 5: for(i=0;i<NPERS;i++) if(tabla_pers[i]==0) if( (personajes[i].color_pelo==CASTANO) != respuesta ) { tabla_pers[i]=1; pers_eliminados++; } break; case 6: for(i=0;i<NPERS;i++) if(tabla_pers[i]==0) if( (personajes[i].color_pelo==CANOSO) != respuesta ) { tabla_pers[i]=1; pers_eliminados++; } break; case 7: for(i=0;i<NPERS;i++) if(tabla_pers[i]==0) if( (personajes[i].ojos==AZULES) != respuesta ) { tabla_pers[i]=1; pers_eliminados++; } break; case 8: for(i=0;i<NPERS;i++) if(tabla_pers[i]==0) if( (personajes[i].ojos==VERDES) != respuesta ) { tabla_pers[i]=1; pers_eliminados++; } break; case 9: for(i=0;i<NPERS;i++) if(tabla_pers[i]==0) if( (personajes[i].ojos==MARRONES) != respuesta ) { tabla_pers[i]=1; pers_eliminados++; } break; case 10: for(i=0;i<NPERS;i++) if(tabla_pers[i]==0) if( (personajes[i].ojos==NEGROS) != respuesta ) { tabla_pers[i]=1; pers_eliminados++; } break;
35
Quin es quin?
case 11: for(i=0;i<NPERS;i++) if(tabla_pers[i]==0) if( (personajes[i].pecas==SI) != respuesta ) { tabla_pers[i]=1; pers_eliminados++; } break; case 12: for(i=0;i<NPERS;i++) if(tabla_pers[i]==0) if( (personajes[i].gafas==SI) != respuesta ) { tabla_pers[i]=1; pers_eliminados++; } break; case 13: for(i=0;i<NPERS;i++) if(tabla_pers[i]==0) if( (personajes[i].long_pelo==CORTO) != respuesta ) { tabla_pers[i]=1; pers_eliminados++; } break; case 14: for(i=0;i<NPERS;i++) if(tabla_pers[i]==0) if( (personajes[i].long_pelo==LARGO) != respuesta ) { tabla_pers[i]=1; pers_eliminados++; } break; case 15: for(i=0;i<NPERS;i++) if(tabla_pers[i]==0) if( (personajes[i].pendientes==SI) != respuesta ) { tabla_pers[i]=1; pers_eliminados++; } break; case 16: for(i=0;i<NPERS;i++) if(tabla_pers[i]==0) if( (personajes[i].barba==SI) != respuesta ) { tabla_pers[i]=1; pers_eliminados++; } } return pers_eliminados; }
36
Quin es quin?
DESCRIPCIN - Funcin que se encarga de eliminar aquellas preguntas que ya no hagan falta hacer para averiguar el perspnaje secreto, ya sea porque ya han sido formuladas o debido a que no hace falta plantearlas con la infomacin que se tiene a partir de los personajes no eliminados. Las preguntas eliminadas se sealan con un 1 en el vector tabla_preg. Devuelve el nmero total de preguntas eliminadas PARMETROS - int tabla_pers[NPERS], personaje personajes[NPERS], int tabla_preg[NPREG], int pers_posibles VALOR DEVUELTO - int */ int eliminar_preguntas(int tabla_pers[NPERS], personaje personajes[NPERS], int tabla_preg[NPREG], int pers_posibles) { int i; int preg_eliminadas=0; /* variables auxiliares para contar el nmero de personajes no eliminados que poseen la caracterstica que representa cada una */ int sexo=0; /* Nmero de mujeres que quedan*/ int pecas=0; /* Nmero de personajes que queda con pecas */ int gafas=0; /* Nmero de personajes que queda con gafas */ int long_pelo=0; /* Nmero de personajes que queda con pelo largo */ int barba=0; /* Nmero de personajes que queda con barba */ int pendientes=0; /* Nmero de personajes que queda con pendientes */ int rubio=0,moreno=0,pelirrojo=0,castano=0,canoso=0; /* Nmero de personajes que quedan con los diferentes colores de pelo */ int azules=0,verdes=0,marrones=0,negros=0; /* Nmero de personajes que quedan con los diferentes colores de ojos */
/* Obtenemos los valores de las variables auxiliares */ for(i=0;i<NPERS;i++) if(tabla_pers[i]==0) { sexo+=personajes[i].sexo; rubio+=personajes[i].color_pelo==RUBIO?1:0; moreno+=personajes[i].color_pelo==MORENO?1:0; pelirrojo+=personajes[i].color_pelo==PELIRROJO?1:0; castano+=personajes[i].color_pelo==CASTANO?1:0; canoso+=personajes[i].color_pelo==CANOSO?1:0; azules+=personajes[i].ojos==AZULES?1:0; verdes+=personajes[i].ojos==VERDES?1:0; marrones+=personajes[i].ojos==MARRONES?1:0; negros+=personajes[i].ojos==NEGROS?1:0; pecas+=personajes[i].pecas; gafas+=personajes[i].gafas; long_pelo+=personajes[i].long_pelo; barba+=personajes[i].barba; pendientes+=personajes[i].pendientes; } /* Si no hay mujeres o el nmero de mujeres es igual al nmero de personajes que quedan, las preguntas sobre el sexo del personaje no tienen sentido y se eliminan */ if( sexo == 0 || sexo == pers_posibles) { tabla_preg[0]=1; tabla_preg[1]=1; preg_eliminadas+=2; }
37
Quin es quin?
if( rubio == pers_posibles || moreno == pers_posibles || pelirrojo == pers_posibles || castano == pers_posibles || canoso == pers_posibles) { /* Si todos los personajes tienen el mismo color de pelo, se eliminan todas las preguntas relacionadas con el color del pelo */ tabla_preg[2]=1; tabla_preg[3]=1; tabla_preg[4]=1; tabla_preg[5]=1; tabla_preg[6]=1; preg_eliminadas+=5; } else { /* Si todos los personajes no tienen el mismo color de pelo, pero alguno de los colores de pelo no aparecen en ningn personje, se eliminan todas las preguntas relacionadas con esos colores de pelo */ if(rubio == 0) { tabla_preg[2]=1; preg_eliminadas++; } if(moreno == 0) { tabla_preg[3]=1; preg_eliminadas++; } if(pelirrojo == 0) { tabla_preg[4]=1; preg_eliminadas++; } if(castano == 0) { tabla_preg[5]=1; preg_eliminadas++; } if(canoso == 0) { tabla_preg[6]=1; preg_eliminadas++; } } if( azules == pers_posibles || verdes == pers_posibles || marrones == pers_posibles || negros == pers_posibles) { /* Si todos los personajes tienen el mismo color de ojos, se eliminan todas las preguntas relacionadas con el color de ojos */ tabla_preg[7]=1; tabla_preg[8]=1; tabla_preg[9]=1; tabla_preg[10]=1; preg_eliminadas+=4; } else { /* Si todos los personajes no tienen el mismo color de ojos, pero alguno de los colores de ojos no aparecen en ningn personje, se eliminan todas las preguntas relacionadas con esos colores de ojos */ if(azules == 0) { tabla_preg[7]=1; preg_eliminadas++; }
38
Quin es quin?
/* Si no hay personajes con pecas o el nmero de personajes con pecas es igual al nmero de personajes que quedan, la pregunta relativa a las pecas no tiene sentido y se elimina */ if( pecas == 0 || pecas == pers_posibles) { tabla_preg[11]=1; preg_eliminadas++; } /* Si no hay personajes con gafas o el nmero de personajes con gafas es igual al nmero de personajes que quedan, la pregunta sobre las gafass no tiene sentido y se elimina */ if( gafas == 0 || gafas == pers_posibles) { tabla_preg[12]=1; preg_eliminadas++; } /* Si no hay personajes con el pelo largo o el nmero de personajes con el pelo largo es igual al nmero de personajes que quedan, las preguntas relativas a la longitud del pelo no tiene sentido y se eliminan */ if( long_pelo == 0 || long_pelo == pers_posibles) { tabla_preg[14]=1; tabla_preg[15]=1; preg_eliminadas+=2; } /* Si no hay personajes con barba o el nmero de personajes con barba es igual al nmero de personajes que quedan, la pregunta sobre la barba no tiene sentido y se elimina */ if( barba == 0 || barba == pers_posibles) { tabla_preg[15]=1; preg_eliminadas++; } /* Si no hay personajes con pendientes o el nmero de personajes con pendientes es igual al nmero de personajes que quedan, la pregunta relativa a los pendientes no tiene sentido y se elimina */ if( pendientes == 0 || pendientes == pers_posibles) { tabla_preg[16]=1; preg_eliminadas++; } return preg_eliminadas; }
39
Quin es quin?
ARCHCFLAGS = -DSYSVBFUNC -DSYSVSTR -DNOGETDTBLSIZ -DSYSVSIGNAL DNOWAIT3 -DNOUNIXDOM ARCHLIB = -lnsl -lsocket -lthread PVM_ARCH = SUNMP # # Custom makefile for PVM programs. # # Set PVM_ROOT to the path where PVM includes and libraries are installed. # Set PVM_ARCH to your architecture type (SUN4, HP9K, RS6K, SGI, etc.) # Set ARCHLIB to any special libs needed on PVM_ARCH (-lrpc, -lsocket, etc.) # otherwise leave ARCHLIB blank # SDIR = .. #BDIR = $(HOME)/pvm3/bin BDIR = $(SDIR)/../bin XDIR = $(BDIR)/$(PVM_ARCH) CC = OPTIONS CFLAGS LIBS = GLIBS = F77 = FFLAGS = FLIBS = LFLAGS = gcc = -O = $(OPTIONS) -I$(PVM_ROOT)/include $(ARCHCFLAGS) -lpvm3 $(ARCHLIB) -lgpvm3 f77 -g -lfpvm3 -L$(PVM_ROOT)/lib/$(PVM_ARCH)
default: juego jugador clean: rm -f *.o juego jugador $(XDIR): - mkdir $(BDIR) - mkdir $(XDIR) juego: $(SDIR)/juego.c $(XDIR) $(CC) $(CFLAGS) -o juego $(SDIR)/juego.c $(LFLAGS) $(GLIBS) $(LIBS) mv juego $(XDIR) jugador: $(SDIR)/jugador.c $(XDIR) $(CC) $(CFLAGS) -o jugador $(SDIR)/jugador.c $(LFLAGS) $(GLIBS) $(LIBS) mv jugador $(XDIR)
40
Quin es quin?
41
Quin es quin?
El algoritmo tambin tiene problemas si falla un proceso, pero la recuperacin es ms sencilla que en los dems casos. Si pedimos un reconocimiento a cada proceso que reciba la ficha, entonces se detectar un proceso muerto si su vecino intenta darle la ficha y fracasa en el intento. En ese momento, el proceso muerto se puede eliminar del grupo y el poseedor de la ficha puede enviar sta por encima de la cabeza del proceso muerto al siguiente miembro, y as, sucesivamente, en caso necesario. Por supuesto, esto requiere que todos mantengan la configuracin actual de anillo.
42
Quin es quin?
Principales rutinas de control de procesos pvm_mytid. Se usa para que el proceso juego obtenga su TID. Llamada: mytid = pvm_ mytid(); pvm_exit. La llaman los procesos para indicar al pvmd local que el proceso est saliendo de PVM. Esta rutina no mata al proceso, el cual puede seguir realizando tareas como cualquier otro proceso UNIX. Llamada: mytid = pvm_ exit(); pvm_spawn. Lo usamos para crear los jugadores. Creamos n_jugadores copias del fichero ejecutable jugador sobre la mquina virtual, argv es un puntero al array de argumentos a jugador, con el final del array especificado por NULL. En el argumento flag ponemos un 0 para que PVM elija donde expandir los jugadores; en el argumento where es NULL, indicando que expanda las tareas por defecto; y TIDs indica la direccin de memoria donde se almacenarn los TIDs de las tareas creadas. Recogemos el nmero de tareas creada en info, para ver si se han creado todos los jugadores pedidos. Llamada: info = pvm_spawn("jugador", argv, 0, NULL, n_jugadores, tids) pvm_kill. Lo llama el proceso jugador para eliminar a los procesos jugadores, cuando se produce un error durante el juego. Le llamamos tantas veces como jugadores haya, y le pasamos el TID de cada uno. Llamada: pvm_kill(tids[i]);
Rutinas de informacin pvm_parent. Lo usan los jugadores para obtener el TID del juego. Llamada: ptid = pvm_parent();
43
Quin es quin?
pvm_perror. Lo usan los procesos para obtener informacin de los errores que se producen.
Rutinas de informacin pvm_initsend. Antes de enviar informacin limpiamos el buffer de envo. Como parmetro usamos la opcin PvmDataDefault. Llamada: pvm_initsend(PvmDataDefault);
pvm_pkint, pvm_upkint. La usan los procesos para empaquetar o desempaquetar los enteros que se pasan unos a otros. Le pasamos como argumentos, el puntero al entero que deseamos enviar o en el que deseamos recibir dicho entero; y el en resto ponemos los parmetros por defecto. Ejemplo de llamada: pvm_pkint(&personajes[i].sexo,1,1);
pvm_pkstr, pvm_upkstr. La usan los procesos para empaquetar y desempaquetar las cadenas que se desean enviar o recibir. Le pasamos como argumento el puntero a la cadena que deseamos enviar o en la que deseamos recibir dicha cadena. Ejemplo de llamada: pvm_pkstr(preguntas[i]);
pvm_sent. La usan para enviar los mensajes. En cada caso ponemos como primer parmetro el TID del proceso al que vamos a enviar el mensaje. El segundo parmetro es la etiqueta de paso de mensajes.
Ejemplo de llamada: pvm_send( jug_derecha, 4); pvm_recv. Los procesos la usan para ponerse a la espera de la llegada de un mensaje. Se produce bloqueo para sincronizarse con el envo. Como primer parmetro le pasamos el TID del proceso del que espera el envo, y como segundo la etiqueta de paso de mensajes, que deber ser igual que la del envo. Ejemplo de llamada: pvm_recv(tids[jug_actual],2);
44
Quin es quin?
pvm_joingroup. Unimos a los jugadores y al juego al grupo juegos. En la llamada del juego comprobamos que es el primer elemento del grupo. En la de los jugadores, recoge su identificador dentro del grupo. Llamadas: id_grupo= pvm_joingroup( "jugadores" ); if( pvm_joingroup("jugadores") != 0 )
pvm_barrier. Bloqueamos todos los procesos del grupo para que se sincronicen. Le pasamos el nombre del grupo y el nmero de elementos del grupo.
pvm_bcast. Lo usa el juego para enviar informacin sobre el juego a todos los elementos del grupo excepto l; es decir, a todos los jugadores. Como primer parmetro le pasamos el nombre del grupo, y como segundo la etiqueta de paso de mensajes. Llamada: pvm_bcast("jugadores",1);
pvm_gettid. La usan los procesos para obtener el TID del elemento del grupo identificado por el identificador de grupo pasado como segundo parmetro, el primeo es el nombre del grupo. Ejemplo de llamada: tids[i] = pvm_gettid("jugadores", i+1);
pvm_lvgroup. La llaman los procesos para dejar el grupo. Pasan como parmetro el nombre del grupo. Llamada: pvm_lvgroup(juego);
45
Quin es quin?
D.1. Salida
Salidas de algunas pruebas realizadas al programa (fichero salida.txt): Prueba 1 Nmero de jugadores que participan en el juego: 8 Jugador 1: t40036 Jugador 2: t40037 Jugador 3: t80029 Jugador 4: t8002b Jugador 5: t8002a Jugador 6: tc002e Jugador 7: tc0030 Jugador 8: tc002f La mquina ha elegido a Esther como personaje a adivinar Empieza el jugador 1 Jugador 1 => Tiene el pelo canoso? Ordenador => S 46
Ampliacin de Sistemas Operativos Jugador 2 => Tu personaje tiene el pelo corto? Ordenador => S Jugador 3 => Lleva gafas? Ordenador => NO Jugador 4 => Es moreno? Ordenador => NO Jugador 5 => Tu personaje es mujer? Ordenador => S Jugador 6 => Tiene el pelo canoso? Ordenador => S Jugador 7 => El color de pelo es castao? Ordenador => NO Jugador 8 => Lleva gafas? Ordenador => NO Jugador 1 => Los ojos de tu personaje son marrones? Ordenador => NO Jugador 2 => Tu personaje tiene el pelo corto? Ordenador => S Jugador 3 => Tiene el pelo largo? Ordenador => NO Jugador 4 => Tu personaje, Es pelirrojo? Ordenador => NO Jugador 5 => Tiene el pelo largo? Ordenador => NO Jugador 6 => Tu personaje es mujer? Ordenador => S Jugador 7 => Es hombre? Ordenador => NO Jugador 8 => Tiene el pelo canoso? Ordenador => S Jugador 1 => Tu personaje es mujer? Ordenador => S Jugador 2 => Tu personaje es mujer? Ordenador => S
Quin es quin?
47
Ampliacin de Sistemas Operativos Jugador 3 => Tiene el pelo rubio? Ordenador => NO Jugador 4 => Es hombre? Ordenador => NO Jugador 5 => Lleva gafas? Ordenador => NO Jugador 6 => Es Vicenta? Ordenador => NO JUGADOR 6 eliminado Jugador 7 => El color de ojos de tu personaje es negro? Ordenador => NO Jugador 8 => El color de los ojos es verde? Ordenador => S Jugador 1 => Es Esther? Ordenador => S ***************************************** * GANADOR JUGADOR 1 => t40036 * ***************************************** ****** FIN JUEGO ******
Quin es quin?
Prueba 2 Nmero de jugadores que participan en el juego: 5 Jugador 1: t40046 Jugador 2: t40047 Jugador 3: t80034 Jugador 4: t80035 Jugador 5: tc0039 La mquina ha elegido a Jorge como personaje a adivinar Empieza el jugador 4 Jugador 4 => Tiene el pelo canoso? Ordenador => NO Jugador 5 => Tiene el pelo rubio? Ordenador => NO 48
Ampliacin de Sistemas Operativos Jugador 1 => Los ojos de tu personaje son marrones? Ordenador => NO Jugador 2 => Tiene, tu personaje, barba? Ordenador => S Jugador 3 => Lleva pendientes? Ordenador => NO Jugador 4 => Tu personaje es mujer? Ordenador => NO Jugador 5 => Es hombre? Ordenador => S Jugador 1 => Tiene el pelo largo? Ordenador => S Jugador 2 => El color de ojos de tu personaje es negro? Ordenador => NO Jugador 3 => El color de ojos de tu personaje es negro? Ordenador => NO Jugador 4 => Tiene el pelo largo? Ordenador => S Jugador 5 => El color de ojos de tu personaje es negro? Ordenador => NO Jugador 1 => Tiene pecas? Ordenador => NO Jugador 2 => El color de los ojos es verde? Ordenador => NO Jugador 3 => Tiene pecas? Ordenador => NO Jugador 4 => Tu personaje tiene el pelo corto? Ordenador => NO Jugador 5 => El color de pelo es castao? Ordenador => S Jugador 1 => Tu personaje, Es pelirrojo? Ordenador => NO Jugador 2 => Tiene el pelo canoso? Ordenador => NO
Quin es quin?
49
Ampliacin de Sistemas Operativos Jugador 3 => Tu personaje es mujer? Ordenador => NO Jugador 4 => Lleva gafas? Ordenador => NO Jugador 5 => El color de los ojos es verde? Ordenador => NO Jugador 1 => Es hombre? Ordenador => S Jugador 2 => Es Jorge? Ordenador => S ***************************************** * GANADOR JUGADOR 2 => t40047 * ***************************************** ****** FIN JUEGO ******
Quin es quin?
Prueba 3 Nmero de jugadores que participan en el juego: 3 Jugador 1: t40041 Jugador 2: t80031 Jugador 3: tc0036 La mquina ha elegido a Alberto como personaje a adivinar Empieza el jugador 2 Jugador 2 => Tiene los ojos azules? Ordenador => NO Jugador 3 => Tiene el pelo rubio? Ordenador => NO Jugador 1 => Tiene, tu personaje, barba? Ordenador => NO Jugador 2 => Tiene el pelo rubio? Ordenador => NO Jugador 3 => Tu personaje es mujer? Ordenador => NO
50
Ampliacin de Sistemas Operativos Jugador 1 => Tiene pecas? Ordenador => NO Jugador 2 => Los ojos de tu personaje son marrones? Ordenador => S Jugador 3 => Tiene pecas? Ordenador => NO Jugador 1 => Tu personaje tiene el pelo corto? Ordenador => S Jugador 2 => Es moreno? Ordenador => NO Jugador 3 => Lleva gafas? Ordenador => NO Jugador 1 => Los ojos de tu personaje son marrones? Ordenador => S Jugador 2 => Tiene el pelo canoso? Ordenador => NO Jugador 3 => Lleva pendientes? Ordenador => NO Jugador 1 => Es moreno? Ordenador => NO Jugador 2 => Tiene, tu personaje, barba? Ordenador => NO Jugador 3 => El color de ojos de tu personaje es negro? Ordenador => NO Jugador 1 => Lleva gafas? Ordenador => NO Jugador 2 => Tiene, tu personaje, barba? Ordenador => NO Jugador 3 => El color de pelo es castao? Ordenador => S Jugador 1 => El color de pelo es castao? Ordenador => S Jugador 2 => Es ngela? Ordenador => NO JUGADOR 2 eliminado
Quin es quin?
51
Ampliacin de Sistemas Operativos Jugador 3 => Los ojos de tu personaje son marrones? Ordenador => S Jugador 1 => Es Alberto? Ordenador => S ***************************************** * GANADOR JUGADOR 1 => t40041 * ***************************************** ****** FIN JUEGO ******
Quin es quin?
Prueba 4 Nmero de jugadores que participan en el juego: 2 Jugador 1: t80033 Jugador 2: tc0038 La mquina ha elegido a Violeta como personaje a adivinar Empieza el jugador 2 Jugador 2 => Los ojos de tu personaje son marrones? Ordenador => NO Jugador 1 => Tu personaje, Es pelirrojo? Ordenador => NO Jugador 2 => El color de los ojos es verde? Ordenador => S Jugador 1 => El color de ojos de tu personaje es negro? Ordenador => NO Jugador 2 => Es Esther? Ordenador => NO JUGADOR 2 eliminado Han sido eliminados todos los jugadores menos uno ***************************************** * GANADOR JUGADOR 1 => t80033 * ***************************************** ****** FIN JUEGO ******
52