/// <summary>
        /// Gets the specified contest scores for all rounds from the file.
        /// </summary>
        /// <param name="contestId">The contest identifier.</param>
        /// <returns>Dictionary of timesheets.  Key is the round ordinal, value is an enumeration of timesheets for that round.</returns>
        public async Task <Result <ContestScoresCollection> > ReadAsync(string contestId)
        {
            if (string.IsNullOrEmpty(contestId))
            {
                return(Error <ContestScoresCollection>(null, $"{nameof(contestId)} cannot be null or empty."));
            }

            var allScores = (await GetAll <TimeSheet>()) ?? new List <TimeSheet>();

            if (allScores == null)
            {
                allScores = new List <TimeSheet>();
            }

            var scoresToReturn = allScores.Where(p => p.ContestId == contestId).GroupBy(score => score.RoundOrdinal);

            if (scoresToReturn == null)
            {
                return(Error <ContestScoresCollection>(null, new Exception($"A pilot with the id {contestId} could not be found")));
            }

            var returnObj = new ContestScoresCollection();

            foreach (var scoreGroup in scoresToReturn)
            {
                var pilotTimeSheets = new List <TimeSheet>();

                foreach (var score in scoreGroup)
                {
                    pilotTimeSheets.Add(score);
                }

                var roundOrdinal = scoreGroup.First()?.RoundOrdinal ?? 0;

                if (!returnObj.Rounds.Contains(roundOrdinal))
                {
                    returnObj.Add(new ContestRoundScoresCollection(pilotTimeSheets, roundOrdinal));
                }
            }

            return(Success(returnObj, nameof(ReadAsync)));
        }
        /// <summary>
        /// Generates the pilot scores.
        /// </summary>
        /// <param name="numberOfPilots">The number of pilots.</param>
        /// <param name="numberOfRounds">The number of rounds.</param>
        /// <param name="timeSheets">The time sheets.</param>
        /// <returns></returns>
        private Dictionary <string, PilotContestScoreCollection> GeneratePilotScores(int numberOfPilots, int numberOfRounds, ContestScoresCollection scores)
        {
            // This is really basic, we aren't testing the algo, we are testing the validation and handling of the non-algo code in this test class
            var returnCollection = new Dictionary <string, PilotContestScoreCollection>();
            var rnd = new Random();

            for (var i = 0; i < numberOfPilots; ++i)
            {
                returnCollection.Add($"pilot{i}", new PilotContestScoreCollection($"pilot{i}", rnd.Next(0, 1000)));
                for (var j = 0; j < numberOfRounds; ++j)
                {
                    returnCollection[$"pilot{i}"].Add(j, 10);
                }
            }

            return(returnCollection);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Generates the contest scores by pilot.
        /// </summary>
        /// <param name="allContestRoundScores">All contest round scores.</param>
        /// <returns></returns>
        public Dictionary <string, PilotContestScoreCollection> GenerateContestScores(ContestScoresCollection allContestRoundScores)
        {
            // Init the output collection.
            var totals = new Dictionary </*PilotId*/ string, PilotContestScoreCollection>();

            // Flatten the rounds and
            // group all of the scores by pilot id
            var pilotTimeSheets = new List <TimeSheet>();

            foreach (var round in allContestRoundScores)
            {
                pilotTimeSheets.AddRange(round.Select(r => r));
            }

            var pilotScoreGroups = pilotTimeSheets.GroupBy(pts => pts.PilotId);

            // Take each pilot and their scores and place each round score in the output collection.
            foreach (var individualPilotScoreSet in pilotScoreGroups)
            {
                foreach (var roundScore in individualPilotScoreSet)
                {
                    // Check to see if we have a pilot entry in the output collection, if not, create one.
                    if (!totals.ContainsKey(roundScore.PilotId))
                    {
                        totals.Add(roundScore.PilotId, new PilotContestScoreCollection(roundScore.PilotId,
                                                                                       individualPilotScoreSet.Sum(scores => scores.Score),
                                                                                       individualPilotScoreSet.ToDictionary(k => k.RoundOrdinal, v => v.Score)));
                    }

                    // If there are multiple scores for the same round for a pilot, only take the first
                    if (!totals[roundScore.PilotId].ContainsKey(roundScore.RoundOrdinal))
                    {
                        totals[roundScore.PilotId].Add(roundScore.RoundOrdinal, roundScore.Score);
                    }
                }
            }

            // Remove the lowest score for each, if four rounds have been completed.
            foreach (var individualPilotScoreSet in totals)
            {
                double lowestScore         = 0.0;
                int    droppedRoundOrdinal = -1;

                // Only do this if the pilot has completed 4 rounds
                if (individualPilotScoreSet.Value.Count > 4)
                {
                    // Loop through and find the lowest round score.
                    for (var i = 0; i < individualPilotScoreSet.Value.Count; ++i)
                    {
                        if (individualPilotScoreSet.Value[i] < lowestScore)
                        {
                            lowestScore         = individualPilotScoreSet.Value[i];
                            droppedRoundOrdinal = i;
                        }
                    }
                }

                // Total the score and remove the lowest if applicable.
                individualPilotScoreSet.Value.TotalScore = individualPilotScoreSet.Value.Sum(x => x.Value) - lowestScore;

                // Mark the dropped round
                individualPilotScoreSet.Value.DroppedRoundOrdinal = droppedRoundOrdinal;
            }

            // Total the scores for each round, for each pilot and put it in the last "column" / entry (int.MaxValue will be the key) for the pilot
            foreach (var pilotScoreSet in totals)
            {
            }

            return(totals);
        }
        public static ContestScoresCollection GenerateValidContestRoundScores(int numberOfPilots,
                                                                              string contestId             = "SASS August 2017",
                                                                              int numberOfRounds           = 1,
                                                                              int maxTimeGateTimeInSeconds = 120,
                                                                              bool multipleFlightGroups    = false,
                                                                              bool generateScores          = false)
        {
            var validScoresForRound = new ContestRoundScoresCollection();
            var TaskA  = new TaskA_LastFlightSevenMin();
            var result = new ContestScoresCollection();

            if (numberOfPilots == 0)
            {
                return(result);
            }
            var rnd = new Random();

            // Set up a mock task to validate and score the rounds if required.
            var mockTask = new Mock <TaskBase>();

            mockTask.Setup(x => x.ValidateTask(It.IsAny <RoundScoreBase>())).Returns(true);
            mockTask.Setup(x => x.ScoreTask(It.IsAny <RoundScoreBase>())).Returns <RoundScoreBase>(y => y.TimeGates.Sum(x => x.Time.TotalSeconds));
            var f3kRoundScoreAlgo = new RoundScoringAlgo();

            for (var i = 0; i < numberOfRounds; ++i)
            {
                // Reset

                validScoresForRound = new ContestRoundScoresCollection();

                for (var j = 0; j < numberOfPilots; ++j)
                {
                    var flightGroup = FlightGroup.A;

                    // Generate 2 flight groups
                    if (multipleFlightGroups)
                    {
                        flightGroup = (j % 2) != 0 ? FlightGroup.A : FlightGroup.B;
                    }

                    var timeGates = new List <TimeGate> {
                        new TimeGate(TimeSpan.FromSeconds(rnd.Next(45, maxTimeGateTimeInSeconds)), j, TimeGateType.Task)
                    };
                    var roundScore = new TimeSheet
                    {
                        RoundOrdinal = i,
                        TimeGates    = timeGates,
                        PilotId      = $"pilot{j}",
                        ContestId    = contestId,
                        TaskId       = TaskA.Id,
                        FlightGroup  = FlightGroup.A
                    };

                    // Generate the scores if needed.
                    if (generateScores)
                    {
                    }

                    validScoresForRound.Add(roundScore);
                }

                if (generateScores)
                {
                    f3kRoundScoreAlgo.ScoreRound(validScoresForRound, mockTask.Object);
                }

                result.Add(validScoresForRound);
            }

            return(result);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Generates the contest scores by pilot.
        /// </summary>
        /// <param name="allContestRoundScores">All contest round scores.</param>
        /// <returns></returns>
        public Dictionary <string, PilotContestScoreCollection> GenerateContestScores(ContestScoresCollection allContestRoundScores)
        {
            // Init the output collection.
            var totals = new Dictionary </*PilotId*/ string, PilotContestScoreCollection>();

            // Flatten the rounds and
            // group all of the scores by pilot id
            var pilotTimeSheets = new List <TimeSheet>();

            foreach (var round in allContestRoundScores)
            {
                pilotTimeSheets.AddRange(round.Select(r => r));
            }

            var pilotScoreGroups = pilotTimeSheets.GroupBy(pts => pts.PilotId);

            // Take each pilot and their scores and place each round score in the output collection.
            foreach (var individualPilotScoreSet in pilotScoreGroups)
            {
                foreach (var roundScore in individualPilotScoreSet)
                {
                    // Check to see if we have a pilot entry in the output collection, if not, create one.
                    if (!totals.ContainsKey(roundScore.PilotId))
                    {
                        totals.Add(roundScore.PilotId, new PilotContestScoreCollection(roundScore.PilotId,
                                                                                       individualPilotScoreSet.Sum(scores => scores.Score),
                                                                                       individualPilotScoreSet.ToDictionary(k => k.RoundOrdinal, v => v.Score)));
                    }

                    // If there are multiple scores for the same round for a pilot, only take the first
                    if (!totals[roundScore.PilotId].ContainsKey(roundScore.RoundOrdinal))
                    {
                        totals[roundScore.PilotId].Add(roundScore.RoundOrdinal, roundScore.Score);
                    }
                }
            }

            return(totals);
        }
        /// <summary>
        /// Scores a group of rounds.
        /// </summary>
        /// <param name="allRoundScores">All contest scores.</param>
        /// <returns>
        /// A collection with the PilotId as the key and a collection of scores for each round as the value.
        /// In the collection of scores, the round number is the key and the score for that round is value.
        /// The last entry (int.MaxValue) in the scores collection is the total for the set of rounds passed in.
        /// </returns>
        public Result <Dictionary <string, PilotContestScoreCollection> > GetAggregateRoundScoresForPilots(ContestScoresCollection allRoundScores)
        {
            if (allRoundScores == null || allRoundScores.Count() < 1)
            {
                return(Error <Dictionary <string, PilotContestScoreCollection> >(null, $"{nameof(allRoundScores)} cannot be null or empty"));
            }

            var result = contestScoreAggregator.GenerateContestScores(allRoundScores);

            return(Success(result, nameof(GetAggregateRoundScoresForPilots)));
        }