UTN – FRBA – Algoritmos y Estructura de Datos – Examen Final – 17/07/2015 Elecciones 2015 Temas evaluados: Resolución de problemas, abstracción, modularización, archivos y flujos. Contexto Usted es parte de un equipo que brinda apoyo informático a la Dirección Nacional Electoral y debe informar sobre los resultados de las Primarias Abiertas Simultaneas Obligatorias (PASO). El Centro de Cómputos que usted lidera recibe vía internet la información de las mesas escrutadas de todo el país. Su equipo debe procesar la información e informar los resultados parciales acumulados. Problema Dado un archivo con los datos de una mesa, se deben actualizar los resultados generales e informar el avance del proceso. El nombre del archivo contiene el distrito y el números de mesa. El nombre es una cadena de 10 dígitos, los primeros 4 representan el código de distrito, los siguientes 5 el número de mesa, y el décimo es un número verificador. El archivo de mesa contiene la cantidad de votos de cada fórmula presidencial, agrupadas por partido. Los partidos están ordenados alfabéticamente, al igual que las fórmulas. Cada registro tiene la forma (partido, fórmula, votos). Los primeros tres registros son especiales, tienen partido y fórmula nulos, el primero tiene los votos en blanco, el segundo los impugnados, y la cantidad de personas que no se acercaron a votar en el tercero. El archivo de resultados tiene la misma forma y cantidad de registros, pero en vez de representar cantidades de una mesa, representa el acumulado del resultado general, originalmente en cero. Recursos disponibles Las variables externas a toda función (“globales”) losResultadosGenerales, laCantidadDeMesasEscrutadasHastaAhora, y laCantidadVotosEscrutadosHastaAhora, la primera es un flujo (archivo abierto) para lectura y escritura, las últimas son enteros. La constante externa a toda función (“global”) laCantidadDeMesasTotal. La función GetMesa que dado un string con el nombre de archivo de mesa retorna el número de mesa. La función EsMesaProcesada que dado un número de mesa retorna verdadero si la mesa ya fue procesada. Recuerde que Puede usar funciones de biblioteca para resolver búsquedas. La expresión sizeof(Tipo) tiene como valor la cantidad de bytes que ocupa variables de Tipo. En C, la expresión fseek(unFlujo, n, SEEK_SET) posiciona el cursor de unFlujo a n bytes del inicio. En C++, la expresión unFlujo.seekg(n) posiciona el cursor de lectura, y unFlujo.seekp(n), el de escritura. Se pide 1. Codificar las declaraciones necesarias para el registro que se usa en ambos archivos. 2. Diagramar o codificar la función ProcesarMesa que dado el nombre de un archivo de mesa, procese ese archivo, actualice los resultados generales e informe el avance. La función debe verificar que la mesa no haya sido procesada previamente. Para la actualización, recuerde leer, posicionarse, y escribir. 3. Diagramar o codificar la función InformarAvance dada la cantidad de votos de una mesa, actualiza la cantidad de mesas escrutadas, y envía a la salida estándar el porcentaje de mesas escrutadas y el porcentaje votos obtenidos por cada formula a ese momento. UTN – FRBA – Algoritmos y Estructura de Datos – Examen Final – 31/07/2015 Recursos disponibles Las variables externas a toda función (“globales”) o losResultadosGenerales, archivo abierto o laCantidadDeMesasEscrutadasHastaAhora, int o laCantidadVotosEscrutadosHastaAhora, int La constante externa a toda función (“global”) laCantidadDeMesasTotal. La función GetMesa que dado un string con el nombre de archivo de mesa retorna el número de mesa. La función EsMesaProcesada que dado un número de mesa retorna verdadero si la mesa ya fue procesada. Recuerde que Puede usar funciones de biblioteca para resolver búsquedas. La expresión sizeof(Tipo) tiene como valor la cantidad de bytes que ocupa variables de Tipo. En C, la expresión fseek(unFlujo, n, SEEK_SET) posiciona el cursor de unFlujo a n bytes del inicio. En C++, la expresión unFlujo.seekg(n) posiciona el cursor de lectura, y unFlujo.seekp(n), el de escritura. Se pide 1. Codificar las declaraciones necesarias para el registro que se usa en ambos archivos. En C En C++ Implementando cadenas con vector de char Utilizando array de caracteres para cadena de tamaño fijo struct VotosDeFormula { char elPartido[50 + 1]; char laFormula[50 + 1]; unsigned losVotos; }; struct VotosDeFormula{ array<char,50> elPartido, laFormula; unsigned losVotos; }; UTN – FRBA – Algoritmos y Estructura de Datos – Examen Final – 31/07/2015 2. Diagramar o codificar la función ProcesarMesa que dado el nombre de un archivo de mesa, procese ese archivo, actualice los resultados generales e informe el avance. La función debe verificar que la mesa no haya sido procesada previamente. Para la actualización, recuerde leer, posicionarse, y escribir. En C void ProcesarMesa(char* nombreMesa) { VotosDeFormula formula, formulaTotal; if (esMesaProcesada(getMesa(nombreMesa))) return; FILE* archMesa = fopen(nombreMesa, "rb+"); int cantidadDeVotosTotalesMesa = 0; fseek(losResultadosGenerales, 0, SEEK_SET); fread(&formula, sizeof(formula), 1, archMesa); while (!feof(archMesa)) { fread(&formulaTotal, sizeof(formulaTotal), 1, losResultadosGenerales); formulaTotal.votos+= formula.votos; fseek(losResultadosGenerales, ftell(losResultadosGenerales – sizeof(formulaTotal), SEEK_SET); write(&formulaTotal, sizeof(formulaTotal), 1, losResultadosGenerales); cantidadDeVotosTotalesMesa+= candidato.votos; fread(&formula, sizeof(formula), 1, archMesa); } informarAvance(cantidadDeVotosTotalesMesa); fclose(archMesa); return; } En C con plantillas void procesarMesa(char* nombreMesa) { if (esMesaProcesada(getMesa(nombreMesa))) return; FILE* archMesa = fopen(nombreMesa, "rb+"); int cantidadDeVotosTotalesMesa = 0; seek<VotosDeFormula>(losResultadosGenerales, 0); VotosDeFormula formula = read<VotosDeFormula>(archMesa); while (!feof(archMesa)) { VotosDeFormula formulaTotal = read<VotosDeFormula>(losResultadosGenerales); formulaTotal.votos+= formula.votos; seek<VotosDeFormula>(losResultadosGenerales, filePos< VotosDeFormula > (losResultadosGenerales) - 1); write< VotosDeFormula >(losResultadosGenerales, candidatoTotal); cantidadDeVotosTotalesMesa+= candidato.votos; candidato = read<VotosDeFormula>(archMesa); } informarAvance(cantidadDeVotosTotalesMesa); fclose(archMesa); return; } En C ++ void ProcesarMesa(string unNombreDeArchivoDeMesa) extern stream losResultadosGenerales; // Declaración extern es innecesaria, pero clarifica unsigned elNumeroDeMesa = GetMesa(unNombreDeArchivoDeMesa); if(EsMesaYaProcesada(elNumeroDeMesa)) return; stream laMesa=AbrirArchivo(unNombreDeArchivoDeMesa); // me conecto a la mesa losResultadosGenerales.seekg(0); losResultadosGenerales.seekp(0); // incializo los cursores de losResultados VotosDeFormula unRegistroEnMesa, unRegistroEnResultados; unisgned losVotosDeLaMesa = 0; while(Read(laMesa, unRegistroEnMesa)){ Read(losResultadosGenerales, unRegistroEnResultados); // Leo y avanzo unRegistroEnResultados.losVostos += unRegistroEnResultados; // Acumulo Write(losResultadosGenerales, unRegistroEnResultados); // Escribo y avanzo losVotosDeLaMesa += unRegistroEnMesa.losVotos; } InformarAvance(votosDeLaMesa); } template<typename T> std::ostream& Write(std::ostream& out, const T& block){ return out.write(reinterpret_cast<const char*>(&block), sizeof block ); } template<typename T> std::istream& Read(std::istream& in, T& block){ return in.read( reinterpret_cast<char*>(&block), sizeof block ); } UTN – FRBA – Algoritmos y Estructura de Datos – Examen Final – 31/07/2015 3. Diagramar o codificar la función InformarAvance dada la cantidad de votos de una mesa, actualiza la cantidad de mesas escrutadas, y envía a la salida estándar el porcentaje de mesas escrutadas y el porcentaje votos obtenidos por cada formula a ese momento. En C // variables Globales FILE * losResultadosGenerales; unsigned laCantidadDeMesasEscrutadasHastaAhora; unsigned laCantidadVotosEscrutadosHastaAhora; const unsigned laCantidadDeMesasTotal = 2; void informarAvance(int cantidadDeVotosTotalesMesa) { VotosDeFormula blanco, impugnado, noVoto, formulaTotal; laCantidadDeMesasEscrutadasHastaAhora++; laCantidadVotosEscrutadosHastaAhora += cantidadDeVotosTotalesMesa; cout << "Cantidad de mesas escrutadas: " << laCantidadDeMesasEscrutadasHastaAhora * 100.0 / laCantidadDeMesasTotal << "\%" << endl; fseek(losResultadosGenerales, 0, SEEK_SEET); fread(&blanco, sizeof(blanco),1, losResultadosGenerales); cout << "Votos en blanco : " << blanco.votos * 100.0 / laCantidadVotosEscrutadosHastaAhora << "\%" << endl; fread(&impugnado, sizeof(impugnado), 1losResultadosGenerales); cout << "Votos impugnados : " << impugnado.votos * 100.0 / laCantidadVotosEscrutadosHastaAhora << "\%" << endl; fread(noVoto, sizeof(noVoto), 1,losResultadosGenerales); cout << "No votaron : " << noVoto.votos * 100.0 / laCantidadVotosEscrutadosHastaAhora << "\%" << endl; fread(&formulaTotal, sizeof(formulaTotal), 1, losResultadosGenerales); while (!feof(losResultadosGenerales)) { cout << formulaTotal.partido << " - " << formulaTotal.formula << " : " << formulaTotal.votos * 100.0 / laCantidadVotosEscrutadosHastaAhora << "\%" << endl; fread(&formulaTotal, sizeof(formulaTotal), 1, losResultadosGenerales); } } En C++ void InformarAvance(unsigned unosVotosDeMesa){ // La declaración extern no es necesaria, pero clarifica extern unsigned laCantidadDeMesasEscrutadasHastaAhora; extern unsigned laCantidadDeVotosEscrutadosHastaAhora; extern const unsigned laCantidadDeMesasTotal; ++laCantidadDeMesasEscrutadasHastaAhora; // cuento mesas laCantidadDeVotosEscrutadosHastaAhora += unosVotosDeMesa; //acumulo votos cout << "Mesas escrutadas: " << laCantidadDeMesasEscrutadasHastaAhora / laCantidadDeMesasTotal * 100; << endl; losResultadosGenerales.seekg(0); while(Read(losResultadosGenerales, unRegistroEnResultados)) cout << unRegistroEnResultados.elPartido << '\t' << unRegistroEnResultados.laFormula << '\t' << unRegistroEnResultados.losVotos / laCantidadDeVotosEscrutadosHastaAhora * 100; << endl; }