Volta a Portugal Relatório Algoritmos e Estruturas de Dados 2º ano do Mestrado Integrado em Engenharia Informática e Computação Elementos do Grupo: João Carlos Figueiredo Rodrigues Prudêncio –070509111 – [email protected] Pedro Miguel Cerqueira da Silva – 060509002 – [email protected] José Miguel Teixeira Viana – 070509139 - [email protected] Turma: 2MIEIC5 10 de Dezembro de 2008 Índice 1. Introdução .................................................................................................................... 3 2. Descrição estruturada do problema....................................................................... 4 2.1 Pressupostos…………………………………………………………………...4 2.2 Casos de utilização……………………………………………………….......7 3. Desenho da solução………………………………………………………………........9 4. Implentação ............................................................................. …………………….. 14 5. Conclusão ............................................................................................................ ….. 16 6. Bibliografia………………………………………………………………………………17 Índice de imagens Ilustração 1 – Diagrama de casos de utilização .......................................................... 8 Ilustração 2 – Modelo de classes UML ......................................................................... 13 Ilustração 3 – Menu de inserção de chegadas a etapas……………….….…...........14 Ilustração 4 – Menu de classificação geral individual por tempos.………….….. 15 Ilustração 5 – Menu de pesquisa de eventos ...................................................... ….. 15 2 1. Introdução O trabalho prático que este relatório expõe é no âmbito da disciplina de Algoritmos e Estruturas de Dados leccionada no segundo ano do Mestrado Integrado de Engenharia Informática e Computação da Faculdade de Engenharia da Universidade do Porto. A elaboração deste relatório tem como objectivo explicitar e documentar um software desenvolvido pelos autores do mesmo, na linguagem de programação orientada por objectos C++. Desta forma, nos capítulos que se seguem será apresentada a estrutura e organização global do programa, usando, entre outros, o UML. Este trabalho prático foi dividido em duas partes, sendo que a segunda parte era a continuação do projecto iniciado. Sendo assim, este relatório irá fundamentar todas as opções usadas, e funcionalidades implementadas, tanto da primeira parte, como da segunda. Em relação aos objectivos gerais do trabalho, pretendia-se um programa que tivesse a funcionalidade de gerir a Volta a Portugal em ciclismo, exibindo todas as funcionalidades para o cálculo de classificações, gestão de etapas, gestão de equipas e ciclistas, entre outras. No próximo capítulo, será relatada estrutura global do problema assim como as interpretações e bases que nos permitiram projectar um programa, e pensar nos algoritmos que o resolvessem. A elaboração deste projecto, teve como fundamento pesquisa bibliográfica, com recorrência a livros, pesquisa na internet acerca de algoritmia e programação em específico sobre linguagem C++ e UML. É de salientar que foi usado como ambiente de desenvolvimento de programação o programa “Microsoft Visual Studio 2008”, desta forma o grupo não garante que os ficheiros sejam correctamente interpretados por outro compilador que não o que este software usa. Para a esquematização do modelo de casos de utilização, foi usado o programa “Microsoft Office Visio 2007”. Por fim, usou-se um programa para realizar o diagrama de UML denominado “Architecture Enterprise“. Considera-se portanto, que este projecto foi estimulante para a aprendizagem de programação, e da linguagem C++ em concreto, na medida em que motivou o grupo na procura de soluções para o problema proposto. Além de competências de programação, competências de trabalho de equipa e de organização de projectos foram da mesma forma estimuladas. 3 2. Descrição estruturada do problema 2.1. Pressupostos O enunciado do trabalho prático, propõe a elaboração de um sistema para gestão da Volta a Portugal em bicicleta. Considera-se portanto essencial entender toda a conjuntura deste desporto, em termos de organização das suas estruturas básicas e modelos de classificação, assim como dos elementos que têm uma participação activa no mesmo e de que maneiras é que intervêm. É portanto essencial, clarificar os pressupostos que consideramos, antes de iniciarmos o processo de estruturação do projecto, em termos de programação. Numa Volta a Portugal, existem um conjunto de equipas que participam na mesma. Uma equipa possui um conjunto de patrocinadores, para poder financiar a sua permanência na competição. É constituída por um director associativo, e por um conjunto de ciclistas. Não foi possível apurar qual o número de directores associativos que uma equipa pode ter, decidiu-se então definir que para a existência de uma equipa tem que existir um e só um director associativo que vai fazer a gestão da equipa. Sendo assim, para criar uma nova equipa na competição, é necessário referir qual o director associativo que vai assumir os cargos de gestão da mesma. Durante a competição é possível contratar outro director associativo para a equipa, mas uma equipa nunca pode ficar sem uma pessoa responsável por este cargo. Em relação aos ciclistas de uma equipa, estes são os principais intervenientes na competição. Um ciclista apenas pode existir associado a uma determinada equipa, tendo algumas características que achamos relevantes para o seu desempenho como desportista, tais como: eficácia a pedalar, altura, estilos dos quais é especialista, peso, potência a pedalar, assim como a sua capacidade aeróbia (VO2max). Note-se que consideramos que não existe limite para o número de ciclistas numa equipa. Consideramos apenas como restrição, que não podem existir nomes repetidos na competição. Iremos de seguida expor, de que medida é que estes agentes se envolvem na Volta a Portugal. Primeiro é importante referir que uma Volta a Portugal, ocorre com uma frequência anual, estando sempre associada a um ano. Uma volta de um determinado ano, é subdividida em várias etapas. Cada etapa é iniciada numa determinada data e está predefinido o número de quilómetros que o circuito dessa etapa possui, assim como o percurso que está irá tomar. Uma etapa é por sua vez subdivida, em várias locais, que podem ser ou uma meta-volante ou um prémiomontanha. Cada um destes checkpoints tem uma importância crucial para a classificação que irá ser explicada de seguida. 4 Tanto uma meta-volante como um prémio-montanha, possuem uma referência ao quilómetro que onde se encontra, ou seja, se pertencem a uma etapa que tem um circuito de 200 quilómetros, esses checkpoints terão que ter um quilómetro entre 0 e 200, garantindo assim que este se encontra dentro da etapa. Em cada meta-volante são registados os três primeiros ciclistas a chegar, e é registado o tempo a que estes chegam. São também atribuídos 5, 3 e 1 pontos pela ordem de chegada. Além disso, são atribuídas bonificações de 3, 2 e 1 minutos também pela ordem de chegada. Relativamente aos prémios-montanha, existem três tipos de categorias pelo que conseguimos apurar. Relativamente á categoria 1, não conseguimos descobrir qual era a pontuação que atribuía a um ciclista, pelo que arbitramos que seriam atribuídos 20, 16, 12, 8, 4 e 2 aos ciclistas pela sua ordem de chegada. Na categoria 2 seriam atribuídos os pontos da seguinte forma 10, 8, 6, 4, 2 e 1, e finalmente na categoria 3 seria 5, 3, 2, 1. Ainda relativamente aos checkpoints, apenas será importante guardar os tempos de chegada do ciclista em que são contabilizados os pontos. Por exemplo, num prémio-montanha de categoria 1, o sétimo ciclista a chegar, já não terá importância para a classificação, e portanto não será relevante contabilizar o tempo, nem o facto de ter chegado a esse local. Além destes locais referidos, também vai ser importante saber a ordem de chegada e o tempo que um ciclista chega no final de cada etapa. Neste caso, consideramos importante que todos os ciclistas possam cortar a meta, e portanto serão contabilizados todos os tempos. Aos primeiros três ciclistas a chegarem ao final da etapa, são atribuídas as bonificações de 10, 6 e 4 minutos respectivamente. Note-se ainda, que em cada um destes locais, não podem chegar dois ciclistas com o mesmo nome, ou seja, como seria óbvio um ciclista só pode chegar uma vez a um local. Ainda relativamente ás chegadas a um local, note-se que é importante que um ciclista não chegue primeiro ao final da etapa, e só posteriormente a uma metavolante, por exemplo. Com isto queremos dizer que, tem que haver coerência com a ordem de chegada de um ciclista em um local, e com a relação tempo/quilómetro de chegada. Apesar de parecerem situações óbvias, torna-se necessário esclarecer estas situações, porque quando se está a simular situações do mundo real através da programação, todos estes pressupostos convêm ser analisados e definidos. Após definir a estrutura de uma etapa, procede-se a explicação das classificações realizadas em cada etapa. A classificação individual por tempos é gerada a partir dos tempos alcançados por cada ciclista nessa etapa, que serão ordenados de forma crescente. Nesta classificação também são contabilizadas as 5 bonificações tanto da chegada ao final da etapa, como da chegada às metas-volante. No entanto, estas bonificações apenas são tomadas em conta aquando do cálculo da classificação individual por tempos. Para a classificação montanha, é preciso considerar os prémios-montanha existentes na etapa. A classificação montanha será portanto a soma de pontos montanha de cada ciclista. Estas pontuações serão ordenadas de forma decrescente, e portanto o ciclista que possuir mais pontos será o vencedor desta classificação. Relativamente à classificação por pontos, esta é determinada pela ordem de chegada ao fim da etapa. Para determinar esta ordem, consulta-se a classificação individual por tempos, ou seja, o ciclista que tiver menor tempo será o primeiro a chegar ao final da etapa. Serão considerados os dez primeiros a chegar, e a pontuação será atribuída da seguinte forma do primeiro para o último: 25, 20, 16, 13, 10, 8, 6, 4, 2 e 1 pontos. Existe também a classificação por equipas, que será como o nome indica ser constituída por equipas. A cada equipa soma-se então os três melhores tempos de todo o seu plantel activo de ciclistas. Posteriormente ordenam-se estes tempos de forma crescente, e a equipa que possuir um menor tempo será a vencedora desta classificação. Estes são os tipos de classificações existentes por cada etapa. Tal como já foi referido, uma volta é constituída por um conjunto de etapas. Assim, existe também uma classificação global que estará dependente da classificação de cada etapa. De seguida irá ser descrita como é calculada a classificação geral de uma volta. Existe também uma classificação individual geral por tempos, que para cada ciclista irá somar os tempos obtidos em cada uma das etapas. É nesta fase que serão contabilizadas as bonificações obtidas tanto nas metas-volante, como á chegada de cada etapa. Esta classificação irá ser ordenada de forma crescente por tempo. O ciclista com menor tempo será considerado o vencedor desta classificação e, portanto portador da camisola amarela. A classificação geral montanha, será como o nome indica obtida a partir da soma dos pontos de um ciclista em todos prémios-montanha de todas as etapas, caso tenho alcançado algum ponto de acordo com a metodologia já explicada. Estas pontuações serão ordenadas de forma decrescente, e portanto o ciclista que possuir mais pontos será o vencedor desta classificação e por conseguinte, portador da camisola azul. É também considerada a classificação geral juventude, que irá ser constituída pelos cinco melhores ciclistas da classificação geral individual por tempos, com 6 menos de vinte cinco anos de idade. O vencedor desta classificação é o portador da camisola laranja. Numa volta existe também uma classificação geral por pontos, mas esta é distinta da classificação por pontos das etapas. Assim, a classificação geral por pontos numa volta, não é mais do que para cada ciclista somar as pontuações obtidas por metas-volante assim como a sua pontuação na classificação montanha, se é que tem, para cada etapa. Note-se que o vencedor desta classificação é o portador da camisola branca. A classificação geral por equipas consiste na soma dos três melhores tempos individuais de cada equipa em todas as etapas disputadas. 2.2 Casos de utilização O diagrama de Use Case ou casos de utilização é referente a todas as acções que os intervenientes do processo de inscrição desencadeiam ou acções desencadeadas por terceiros que intervêm directamente com estes. O actor principal é o utilizador do programa. Tal como especificado no enunciado, serão considerados três tipos de utilizadores, visitante, administrador ou coordenador. O visitante apenas poderá consultar todos os dados relativamente às equipas, etapas, classificações, historial. Mas nada poderá alterar. O administrador tem as mesmas permissões para consultar toda a informação, e pode adicionalmente editar as classificações nas etapas, ou seja, adicionar tempos a um ciclista numa determinada etapa, ou uma chegada num prémio-montanha ou numa meta-volante. Pode também alterar o historial de um determinado ciclista, ou seja, adicionar ou remover prémios. Estas funcionalidades irão ser aprofundadas posteriormente. Para entrar no sistema como administrador será necessário um login e uma password, que estão guardados num ficheiro. O coordenador tem as mesmas permissões que o administrador, e adicionalmente pode alterar toda a constituição das equipas e das etapas, assim como configurar as contas dos utilizadores. Para entrar no sistema como coordenador é necessário também um login e uma password que estão armazenados num ficheiro. 7 Ilustração 2 – Diagrama de casos de utilização 8 3. Desenho da solução Neste capítulo irá ser apresentada a organização das classes e suas funções. Note que devido á elevada extensão das classes e métodos do programa elaborado comparativamente com o número de páginas proposto para o relatório, irá apenas ser apresentado um modelo global e resumido das classes. Para um conhecimento profundo acerca das mesmas apenas é possível através da análise do código fonte. A classe Trabalhador tem como objectivo guardar as informações subjacentes a qualquer trabalhador numa equipa, ou seja, nome, data de nascimento e naturalidade. Esta classe possui os métodos set e get para poder alterar os membros dados assim como todas as outras classes que irão ser apresentadas de seguida. Utilizou-se o conceito de herança de classes e polimorfismo para elaborar as classes Ciclista e DirectorAssociativo, que herdam da classe trabalhador. Estas duas classes possuem os membros de dados que foram acordados ser os mais relevantes neste caso, e herdam todas as características do Trabalhador. Note-se ainda que existe um método imprimir em todas estas três classes, permitindo usar o conceito de polimorfismo, que dependente do tipo de objecto irá invocar o respectivo método imprime. A classe Equipa irá ser a classe que armazena Ciclistas e um Director Associativo. Assim esta classe irá ter os métodos adicionaCiclista() e apagaCiclista() que como o nome indica permite manipular o plantel da equipa. De notar que nesta classe já usamos o conceito de overloading de operadores, assim em muitas outras classes. Neste caso o método operator<<() foi definido, apesar de ser uma função friend e de não pertencer á classe. Estes operador é definido na maioria das classes que irão ser apresentadas. Foram desenvolvidas outras classes que o grupo achou pertinente e com bastante usabilidade. Uma dessas classes foi a classe Data e a classe Tempo. A classe Data possui um dia, mês e ano, e possui métodos para validação de datas e para impressão dessa data em forma de um tipo de dados do tipo string. Esta classe possui o método operator<() que permite comparar datas, o que é essencial para efectuar a classificação juventude, por exemplo. A classe Tempo é bastante similar, possuindo os membros dado hora, minuto, segundo. Possui alguns operadores implementados para incrementar, decrementar, comparar tempos. Esta classe também é essencial para toda a classificação. Uma outra classe não menos importante é a classe Excepcao, que é responsável por todas as excepções que possam ocorrer durante a execução do programa. Apesar de muito simples, contendo apenas um membro dado com o nome da excepção e o operator<<() , é correntemente usada ao longo de todo o programa. 9 A classe Etapa é fulcral no desenho deste programa. Responsável por grande parte das classificações como já explicado anteriormente, armazena também objectos do tipo MetaVolante, PremioMontanha, Pontuacao, que são também classes que foram elaboradas. A classe MetaVolante possui os membros dados do nome e do quilómetro a que essa meta-volante ocorre, mas também possui um vector com os primeiros ciclistas que chegaram a essa meta-volante, ou seja um vector de objecto do tipo Pontuacao. A classe PremioMontanha é muito similar, mas é utilizada para as pontuações montanha. A partir destas três classes ira ser possível gerar todas as classificações. Vão existir vários contentores genéricos do tipo vector que conterão as diferentes classificações. A classe Pontuacao é a classe base de todas as classificações, tendo portanto um apontador para Ciclista e um Tempo. Foi definido também o operator<() que irá ser usado para todo o tipo de classificações, este dirá que uma Pontuacao será menor que outra, quando o tempo da primeira for menor que o da segunda(usando o operador da classe Tempo). Relativamente ainda á classe Etapa, cada etapa possui um objecto do tipo Eventos, que irá conter uma Binary Search Tree(BST). Esta BST conterá um conjunto de objectos do tipo PontuacaoBST, este tipo de objectos contém um apontador para uma Pontuacao, e uma membro de dados do tipo string, que conterá a descrição dessa pontuação. Basicamente, um objecto do tipo PontuacaoBST será ou uma chegada ao final da etapa, ou uma chegada a uma meta-volante ou por último, uma chegada a um prémio-montanha. Desta forma, esta BST terá a funcionalidade para pesquisar eventos que ocorreram nessa etapa. Assim recorrendo a um algoritmo de pesquisa muito eficiente das árvores binárias, consegue-se encontrar rapidamente um conjunto de pontuações pretendidas, dentro de um intervalo de tempo estipulado. Relativamente á classe Volta, esta é basicamente constituída por um conjunto de etapas, apesar de conter também o seu próprio sistema de classificações baseado nas etapas já devidamente especificado. Este classe terá então acesso a um vector de objectos do tipo apontadores para Equipa, e um de objectos do tipo apontadores para Etapa. Ao longo da elaboração do programa, houve necessidade de usar sempre apontadores em todas as estruturas. Desta forma não se está a replicar os dados, existindo apenas a informação uma vez, o restante serão apontadores para essa posição de memória. Usamos esta situação no caso dos vectores de apontadores para Ciclista na classe Equipa, assim como na classe Etapa. Existem ainda as classes Visitante, Administrativo e Coordenador, responsáveis pelo interface com o utilizador. A classe Interface é o ponto de partida para o programa, permitindo escolher como deseja entrar no sistema. Esta classe possui um 10 apontador para um objecto do tipo Historico, e sempre que o programa é iniciado ou fechado os dados são carregados e actualizados a partir dos ficheiros que se encontram na pasta do projecto. A classe Historico é portanto responsável por carregar todas as voltas, que por sua vez carregam todas as suas respectivas etapas. Relativamente aos ficheiros existem os ficheiros “equipasX.txt” e “etapasX.txt”, em que “X” deverá ter o ano dessa volta. Estes ficheiros possuem uma organização própria e necessitam de ter este nome para serem reconhecidos pelo programa. Caso não exista pelo menos um ficheiro de etapas e um de equipas o programa lançará uma excepção e não poderá ser iniciado. Note-se que apesar disso o utilizador nada tem que fazer nos ficheiros, visto que a gestão destes será da inteira responsabilidade do programa. No entanto, pensou-se que não faria sentido o programa iniciar sem ter como base estes ficheiros, que permitem o carregamento e a actualização dos dados. Existem ainda os ficheiros “Visitantes.txt”, “Administrativo.txt”, “Coordenadores.txt”. No caso dos Visitantes, possui o número de visitantes total ao programa, assim como a última visita. No caso dos restantes ficheiros, possuem as passwords dos utilizadores e também os dados da última visita desse utilizador. São estas classes que também são responsáveis por todos os menus existentes na interface gráfica do programa, fazendo também todas as validações no decorrer no mesmo. Em todos os menus, são previstas todas as opções possíveis, e as que não se enquadra no panorama possível de opções, serão rejeitadas e aparecerá uma mensagem de erro para o utilizador voltar a inserir uma opção correcta. O grupo teve o cuidado de efectuar uma interface robusta, de maneira que o programa nunca bloquear aceitando por exemplo letras quando são pedidos números. Foi ainda elaborada outra classe denominada hashHistorico, que contém uma hash_set de objectos do tipo CiclistaHistorico. Um CiclistaHistorico conterá o nome de um ciclista e um vector de objectos do tipo Premium. Um objecto Premium representará um prémio de um ciclista, ou seja, terá um ano de realização, a equipa a que esse ciclista pertence nesse ano, assim como a modalidade que esse ciclista foi vencedor. Assim, permite-se adicionar, remover e visualizar todos os prémios que um determinado ciclista venceu. É possível carregar a partir de um ficheiro uma determinada modalidade, estando onze ficheiros disponíveis para o efeito. Ao actualizar os dados no ficheiro, o programa irá actualizar todos os ficheiros, colocando o prémio no respectivo ficheiro de acordo com a modalidade. Os ficheiros terão o seguinte formato “historicoAmadores.txt” mas o utilizador não tem que se preocupar com a organização interna dos ficheiros, esta será da inteira responsabilidade do programa. 11 Relativamente às estruturas de dados usadas, foram várias de acordo com a situação pretendida. No caso da pesquisa de eventos a estrutura que achamos mais adequada foi a BST visto que tem como ordem de complexidade, para a execução da pesquisa de elementos pode ser realizada em O(log n). Usamos uma classe BST já definida, leccionado nas aulas da disciplina. No caso do histórico, o ideal é usar uma hash_set visto que pretende-se obter rapidamente os prémios de um utilizador. As tabelas de dispersão asseguram tempo médio constante para inserção, remoção e pesquisa. Isto é possível através de uma função de codificação que definimos, que é usada pela classe. Nas restantes situações foi usada a classe vector. Apesar de haver estruturas mais eficazes, pensamos não ser objectivo do trabalho alterar tudo o que já estava realizado numa primeira fase, para uma estrutura mais eficiente. Assim, o grupo resolveu manter a estrutura vector predominante no trabalho. Como algoritmo de ordenação foi usado o algoritmo InsertionSort, apesar de não ser dos algoritmos mais eficientes, pensamos que não teria grande impacto a alteração para o algoritmo mais eficiente, visto a quantidade pequena esperada nos dados do programa. 12 Ilustração 2 – Modelo de classes UML 13 4. Implementação Existem vários algoritmos que foram aplicados ao longo da realização do projecto, é difícil escolher alguns mais relevantes para incluir neste relatório. Relativamente á fase de testes do programa, desde o ínicio da elaboração deste que se procederam a sucessivos testes. Tentando adivinhar possíveis erros e falhas do programa e dos algoritmos implementados, muitos testes foram feitos. Para a realização destes testes, foram introduzidas três etapas com prémios-montanha e metas-volante, cinco equipas, cada equipa com cinco ciclistas. A partir destes dados inseriu-se chegadas aos checkpoints, analisando a classificação tanto das etapas, como a classificação geral. De seguida apresentam-se esses testes efectuados e os resultados obtidos. Ilustração 3 – Menu de inserção de chegadas a etapas A partir de dados inseridos como demonstrado na Ilustração 3, obteve-se a classificação geral demonstrado pela Ilustração 4. Devido às inúmeras classificações existentes na Volta a Portugal, é impossível demonstrar todos os testes efectuados. 14 Ilustração 4 – Menu de classificação geral individual por tempos Para testar a pesquisa de eventos, usamos os dados já inseridos e testamos várias pesquisas, com vários tempos, e conferimos se todos os resultados das pesquisas estavam coerentes. Apresentamos de seguida um desses testes. Ilustração 5 – Menu de pesquisa de eventos 15 5. Conclusão Relativamente às funcionalidades não implementadas, consideramos que não existem. Visto que consideramos que todos as funcionalidades e objectivos propostos no enunciado foram cumpridos, tanto relativo á primeira parte do trabalho, como á segunda parte. No entanto, seria possível implementar outras funcionalidades com mais tempo para a elaboração do programa. Uma das funcionalidades que pensamos em implementar seria a codificação da password nos ficheiros, de maneira que não existisse maneira de alguém descobrir a password de um determinado utilizador, ao pesquisar os ficheiros. Outras das funcionalidades que poderiam ter sido implementadas seria por exemplo permitir a elaboração de gráficos sobre a performance de um determinado ciclista, ou equipa. Analisando os dados de todas as provas de anos passados, poder-se-ia fazer o tratamento estatístico, e elaborar automaticamente um relatório acerca das probabilidades de cada equipa ou ciclista ganhar efectivamente uma determinada classificação. Poder-se-ia também ter implementado uma espécie de jogo/simulação, que permitisse gerar automaticamente as chegadas aos checkpoints de acordo com as características de cada ciclista e também dos dados estatísticos acima referidos. Possivelmente poder-se-á mesmo implementar as funcionalidades acima referidas após a conclusão da disciplina. Relativamente ao desempenho do grupo, todos os elementos do grupo contribuíram positivamente para o desenvolvimento do trabalho. Através de um bom trabalho de equipa, aproveitando os conhecimentos individuais de cada elemento do grupo, conseguiu-se alcançar os objectivos propostos inicialmente para este trabalho. 16 6. Bibliografia The C++ Programming Language , 3rd Edition / Stroustrup Addison-Wesley C++ Primer, 3rd Edition / Lippman and Lajoie Addison-Wesley http://www.cplusplus.com/doc/tutorial http://www.sgi.com/tech/stl 17