public void CalcularMelhorVoltaDaCorrida(Dictionary <int, DadosCorridaPiloto> pDadosVoltaPilotos)
        {
            StringBuilder melhorVoltaDaCorrida = new StringBuilder();

            var formatString = "|{0,-35}|{1,-35}|{2,-35}|";

            melhorVoltaDaCorrida.AppendLine()
            .AppendFormat(Culture, formatString, "Código Piloto", "Nome Piloto", "Tempo da Volta")
            .AppendLine();

            String primeiraLinha = CriarLinhaFormatadoraColunasTabelas(melhorVoltaDaCorrida);

            melhorVoltaDaCorrida.Insert(0, primeiraLinha);
            melhorVoltaDaCorrida.Append(primeiraLinha).AppendLine();


            //hashmap que sera retornado. OBS é um LinkedHashMap pois ele sempre preserva a ordem de insercão
            //pilotos ordenados pelo menor tempo de volta
            var pilotosOrdenadosByMenorTempoVolta = new Dictionary <int, DadosCorridaPiloto>();

            //ordena o dicionário pelo menor tempo de volta de cada piloto
            pDadosVoltaPilotos.ToList().OrderBy(x => x.Value.MelhorVolta).ToList()
            .ForEach(x => pilotosOrdenadosByMenorTempoVolta.Add(x.Key, x.Value));

            DadosCorridaPiloto dadosMelhorPiloto = pilotosOrdenadosByMenorTempoVolta.FirstOrDefault().Value;

            int      codigoPiloto = dadosMelhorPiloto.Piloto.Codigo;
            String   nomePiloto   = dadosMelhorPiloto.Piloto.NomePiloto;
            TimeSpan melhorVolta  = dadosMelhorPiloto.MelhorVolta;

            melhorVoltaDaCorrida.AppendFormat(Culture, formatString, codigoPiloto.ToString("D3"), nomePiloto, melhorVolta.ToString(@"hh\:mm\:ss\:fff")).AppendLine();

            //acrescenta no relatorio Final título seção MELHOR VOLTA POR PILOTO
            RelatorioFinal.AppendLine().AppendLine().Append("-> [ MELHOR VOLTA DA CORRIDA ]").AppendLine().AppendLine();
            //append no relatorio Final dados sobre MELHOR VOLTA POR PILOTO
            RelatorioFinal.Append(melhorVoltaDaCorrida.ToString());
        }
        // função que calcula e faz chamadas para métodos que ajudarão a construir o relatório final
        public string CalcularResultadoCorrida(List <IVoltaCorrida> pVoltas)
        {
            // Dicionário que conterá dados relevantes de cada piloto ao final da corrida
            var dDadosPilotosCorrida = new Dictionary <int, DadosCorridaPiloto>();

            // agrupa voltas por cada piloto
            var voltasGroupedByPiloto = pVoltas.GroupBy(x => x.Piloto.Codigo);

            // para cada piloto, itere sobre suas voltas

            foreach (var voltaG in voltasGroupedByPiloto)
            {
                var voltasPiloto = voltaG.Select(volta => volta);

                var somadorVelocidades = 0.0f;

                var ultimaVolta = voltasPiloto.Last();

                //para cada volta do piloto atual
                foreach (var volta in voltasPiloto)
                {
                    if (!dDadosPilotosCorrida.ContainsKey(voltaG.Key))
                    {
                        somadorVelocidades += volta.VelocidadeMediaVolta;

                        var dadosCorrida = new DadosCorridaPiloto(volta.HoraVolta, volta.NumeroVolta, volta.TempoVolta, volta.VelocidadeMediaVolta, volta.Piloto);

                        dDadosPilotosCorrida.Add(voltaG.Key, dadosCorrida);
                    }
                    else
                    {
                        //se o piloto já esta no hashmap dados_pilotos_final_da_corrida, atualize seus dados//
                        DadosCorridaPiloto dadosPiloto = dDadosPilotosCorrida[voltaG.Key];

                        //atualiza hora da última volta
                        dadosPiloto.HoraUltimaVolta = volta.HoraVolta;
                        //atualiza número da volta
                        dadosPiloto.NumeroDeVoltasTotais = volta.NumeroVolta;
                        //atualiza velocidadeTotal
                        dadosPiloto.VelocidadeTotalCorrida = dadosPiloto.VelocidadeTotalCorrida + volta.VelocidadeMediaVolta;
                        //atualiza tempo total durante a corrida
                        dadosPiloto.TempoTotalCorrida = TimeSpanUtils.OperarTimeSpans(dadosPiloto.TempoTotalCorrida, volta.TempoVolta, ETimeSpanOperacao.Adicao);

                        //se tempo da volta atual for melhor (menor) que o anterior, atualize este valor
                        if (volta.TempoVolta < dadosPiloto.MelhorVolta)
                        {
                            dadosPiloto.MelhorVolta = volta.TempoVolta;
                        }

                        // variável que armazena a soma das velocidades de cada volta do piloto atual
                        somadorVelocidades += volta.VelocidadeMediaVolta;

                        // se for a última volta do piloto atual calcule sua Velocidade Média
                        if (volta.Equals(ultimaVolta))
                        {
                            float velocidadeMedia = somadorVelocidades / voltasPiloto.Count();
                            dadosPiloto.VelocidadeMediaCorrida = velocidadeMedia;

                            somadorVelocidades = 0.0F; // reseta somadorVelocidades
                        }

                        //atualiza dados do piloto atual no dicionário dDadosPilotosCorrida
                        dDadosPilotosCorrida[voltaG.Key] = dadosPiloto;
                    }
                }
            }

            //Dicionário com classificação final dos pilotos
            Dictionary <int, DadosCorridaPiloto> posicaoFinal = ComputarPosicaoFinalDosPilotos(dDadosPilotosCorrida);

            //gera relatório da classificação final da corrida
            CalcularClassificacaoFinalPilotos(posicaoFinal);

            //gera relatório da melhor volta de cada piloto na corrida
            CalcularMelhorVoltaDeCadaPiloto(dDadosPilotosCorrida);

            //gera relatório da melhor volta da corrida
            CalcularMelhorVoltaDaCorrida(dDadosPilotosCorrida);

            //gera relatório da velocidade média de cada piloto na corrida
            CalcularVelocidadeMediaDeCadaPiloto(dDadosPilotosCorrida);

            return(RelatorioFinal.ToString());
        }