public override CompetitorRanks GenerateResult(int winsToClinchMatch, Competitor competitorA, Competitor competitorB)
        {
            var competitorAWins = 0;
            var competitorBWins = 0;

            while (competitorAWins < winsToClinchMatch && competitorBWins < winsToClinchMatch)
            {

                var randomRatio = Convert.ToDouble(RandomNumberGenerator.Next(0, 101)) / Convert.ToDouble(100);
                var ratingRatio = Convert.ToDouble(competitorA.TheoreticalRating) / (Convert.ToDouble(competitorA.TheoreticalRating) + Convert.ToDouble(competitorB.TheoreticalRating));

                if (randomRatio < ratingRatio)
                    competitorAWins++;
                else
                    competitorBWins++;
            }

            var ranks = new CompetitorRanks();

            if (competitorAWins > competitorBWins)
            {
                ranks.Add(competitorA, 1);
                ranks.Add(competitorB, 2);
            }
            else
            {
                ranks.Add(competitorB, 1);
                ranks.Add(competitorA, 2);
            }

            return ranks;
        }
        public override CompetitorRanks GenerateResult(MatchStrategies.MatchStrategy matchStrategy, List<Competitor> competitors)
        {
            if (competitors.Count == 1)
            {
                CompetitorRanks singleRank = new CompetitorRanks();
                singleRank.Add(competitors[0], 1);

                return singleRank;
            }

            List<Match> matches = new List<Match>();

            for (int i = 0; i < Convert.ToInt32(Math.Round(_numberOfRounds.Value)); i++)
            {
                matches.AddRange(GenerateSingleRoundResult(matchStrategy, competitors, 1.0));
            }

            // now run the partial round, if there are any
            double fractionOfPartialRound = (_numberOfRounds.Value - Math.Round(_numberOfRounds.Value));

            if (fractionOfPartialRound > 0.0)
                matches.AddRange(GenerateSingleRoundResult(matchStrategy, competitors, fractionOfPartialRound));

            Matches = matches;

            return GetTournamentRoundRanks();
        }
        private void BreakTiesByRoundRobinRanks(CompetitorRanks roundRobinRanks, CompetitorRanks finalRanks)
        {
            IEnumerable<KeyValuePair<Competitor, int>> orderedRanks = finalRanks
                .OrderBy(x => x.Value)
                .ThenBy(x => roundRobinRanks[x.Key]);

            int rank = 1;
            foreach (KeyValuePair<Competitor, int> orderedRank in orderedRanks)
            {
                finalRanks[orderedRank.Key] = rank++;
            }
        }
        private CompetitorRanks GetTournamentRoundRanks()
        {
            if (Matches.Count != 4)
                throw new ArgumentException("Collection count must be 4.", "matches");

            // assumption: the matches are in this order: matches 1 and 2 are semis,
            // match 3 is petit finals, match 4 is finals
            CompetitorRanks ranks = new CompetitorRanks();
            ranks.Add(Matches[3].Winner, 1);
            ranks.Add(Matches[3].Loser, 2);
            ranks.Add(Matches[2].Winner, 3);
            ranks.Add(Matches[2].Loser, 4);

            return ranks;
        }
        public override CompetitorRanks GenerateResult(int winsToClinchMatch, Competitor competitorA, Competitor competitorB)
        {
            var ranks = new CompetitorRanks();
            
            if (competitorA.TheoreticalRating > competitorB.TheoreticalRating)
            {
                ranks.Add(competitorA, 1);
                ranks.Add(competitorB, 2);
            }
            else
            {
                ranks.Add(competitorB, 1);
                ranks.Add(competitorA, 2);
            }

            return ranks;
        }
        public override CompetitorRanks GenerateResult(int tournamentRunSequence, MatchStrategies.MatchStrategy matchStrategy, List<Competitor> competitors)
        {
            // round robin to seed the semifinals
            TournamentRound rrTR = new TournamentRound(new RrTRS(_numberOfRoundRobinRounds), matchStrategy);
            CompetitorRanks rrRanks = rrTR.Run(competitors);

            // run single semifinal knockout round
            TournamentRound koTR = new TournamentRound(new KoTRS(_winsToClinchKnockoutMatch), matchStrategy);
            CompetitorRanks koRanks = koTR.Run(rrRanks.OrderBy(x => x.Value).Select(x => x.Key).ToList<Competitor>());

            // rank the results first by how they did in the semifinals, then by how they did in the round robin
            var untypedRanks = koRanks.OrderBy(x => x.Value).ThenBy(x => rrRanks[x.Key]);

            CompetitorRanks ranks = new CompetitorRanks();
            int i = 1;
            foreach (KeyValuePair<Competitor, int> untypedRank in untypedRanks)
            {
                ranks.Add(untypedRank.Key, i++);
            }

            return ranks;            
        }
        public void BreakTiesTest()
        {
            List<Competitor> competitors = Helpers.CompetitorListHelper.GetStandardCompetitors(8);

            CompetitorRanks roundRobinRanks = new CompetitorRanks();
            CompetitorRanks finalRanks = new CompetitorRanks();
            int i = 1;
            foreach (Competitor competitor in competitors)
            {
                roundRobinRanks.Add(competitor, i);

                if (i < 5)
                    finalRanks.Add(competitor, 5);
                else if (i < 7)
                    finalRanks.Add(competitor, 3);
                else
                    finalRanks.Add(competitor, 9-i);

                i++;
            }

            RrKoSfFiTS_Accessor target = new RrKoSfFiTS_Accessor();
            target.BreakTiesByRoundRobinRanks(roundRobinRanks, finalRanks);

            var finalRankArray = finalRanks
                .Select(x => new { x.Key.Name, x.Value })
                .OrderBy(x => x.Value)
                .ToArray();

            Assert.AreEqual("H", finalRankArray[0].Name);
            Assert.AreEqual("G", finalRankArray[1].Name);
            Assert.AreEqual("E", finalRankArray[2].Name);
            Assert.AreEqual("F", finalRankArray[3].Name);
            Assert.AreEqual("A", finalRankArray[4].Name);
            Assert.AreEqual("B", finalRankArray[5].Name);
            Assert.AreEqual("C", finalRankArray[6].Name);
            Assert.AreEqual("D", finalRankArray[7].Name);
        }
        public override CompetitorRanks GenerateResult(int tournamentRunSequence, MatchStrategies.MatchStrategy matchStrategy, List<Competitor> competitors)
        {
            if (competitors.Count % 2 != 0)
                throw new ArgumentException("Collection count must be even.", "competitors");

            // round robin to seed the semifinals
            TournamentRound rrTR = new TournamentRound(new RrTRS(_numberOfRoundRobinRounds), matchStrategy);
            CompetitorRanks rrRanks = rrTR.Run(competitors);

            List<Competitor> rankedCompetitors = rrRanks.OrderBy(x => x.Value).Select(x => x.Key).ToList<Competitor>();

            CompetitorRanks ranks = new CompetitorRanks();
            // run single knockout round for nearby competitors
            for (int i = 0; i < competitors.Count / 2; i++)
            {
                TournamentRound koTR = new TournamentRound(new KoTRS(_winsToClinchKnockoutMatch), matchStrategy);
                CompetitorRanks koRanks = koTR.Run(new List<Competitor>() { rankedCompetitors[i * 2], rankedCompetitors[(i * 2) + 1] });
                ranks.Add(koRanks.First(x => x.Value == 1).Key, (i * 2) + 1);
                ranks.Add(koRanks.First(x => x.Value == 2).Key, (i * 2) + 2);
            }

            return ranks;
        }
        private static bool BreakTieGroupByHeadToHeadMatchPoints(CompetitorRanks tieGroupRanks, List<Match> matches, int firstMatchesToExclude)
        {
            bool hasChangedRanks = false;

            // verify there are ties to break
            if (tieGroupRanks.Count() < 2)
                throw new ArgumentException("No tied competitors.");

            // verify all members of the tie group have the same number of points
            int tiedRank = 0;
            foreach (KeyValuePair<Competitor, int> tieMember in tieGroupRanks)
            {
                if (tiedRank != 0 && tiedRank != tieMember.Value)
                    throw new ArgumentException("This group contains members who are not tied with the others.");

                tiedRank = tieMember.Value;
            }

            // compare the points in the head-to-head matches first
            // find all the matches where they go head to head
            List<Match> headToHeadMatches = matches

                .Join(tieGroupRanks,

                match => match.Winner,
                tieMember => tieMember.Key,
                (match, tiedCompetitor) => match)

                .Join(tieGroupRanks,
                match => match.Loser,
                tieMember => tieMember.Key,
                (match, tiedCompetitor) => match)

                .OrderBy(x => x.RunSequence)

                .ToList<Match>();

            for (int i = 0; i < firstMatchesToExclude; i++)
            {
                if (headToHeadMatches.Count > 0)
                    headToHeadMatches.RemoveAt(0);
            }

            CompetitorPoints tiedCompetitorPoints = AccumulateMatchPoints(headToHeadMatches);

            // assign the correct competitor ranks, leaving ties where they exist
            double lastPointTotal = tiedCompetitorPoints.OrderByDescending(x => x.Value).First().Value;
            foreach (KeyValuePair<Competitor, double> tiedCompetitorPoint in tiedCompetitorPoints.OrderByDescending(x => x.Value))
            {
                if (tiedCompetitorPoint.Value < lastPointTotal)
                {
                    tiedRank++;
                    hasChangedRanks = true;
                }

                tieGroupRanks[tiedCompetitorPoint.Key] = tiedRank;

                lastPointTotal = tiedCompetitorPoint.Value;
            }

            return hasChangedRanks;
        }
        private static bool BreakTies(CompetitorRanks tournamentRoundRanks, List<Match> matches)
        {
            bool hasChangedRanks = false;

            List<int> distinctTournamentRoundRanks = tournamentRoundRanks.Values.Distinct().ToList<int>();

            foreach (int tiedRank in distinctTournamentRoundRanks)
            {
                // find all the competitors with the same points
                CompetitorRanks tieGroupRanks = new CompetitorRanks(tournamentRoundRanks
                    .Where(x => x.Value == tiedRank)
                    .ToDictionary(x => x.Key, x => x.Value));

                if (tieGroupRanks.Count() > 1)
                {
                    if (BreakTieGroupByHeadToHeadMatchPoints(tieGroupRanks, matches, 0))
                        hasChangedRanks = true;
                    else if (BreakTieGroupByHeadToHeadMatchPoints(tieGroupRanks, matches, 1))
                        hasChangedRanks = true;
                }

                // add the tie resolution results back into the overall ranks
                foreach (KeyValuePair<Competitor, int> tieGroupRank in tieGroupRanks)
                {
                    tournamentRoundRanks[tieGroupRank.Key] = tieGroupRank.Value;
                }
            }

            return hasChangedRanks;
        }
        public void BreakTiesTest_NonRandomMatches()
        {
            var competitors = Helpers.CompetitorListHelper.GetStandardCompetitors(6);

            var matches = new List<Match>
                              {
                                  (Match)new Match_Accessor {
                                          Winner = competitors[0],
                                          Loser = competitors[1],
                                          RunSequence = 1
                                      }.Target,
                                  (Match)new Match_Accessor {
                                          Winner = competitors[0],
                                          Loser = competitors[2],
                                          RunSequence = 2
                                      }.Target,
                                  (Match)new Match_Accessor {
                                          Winner = competitors[0],
                                          Loser = competitors[4],
                                          RunSequence = 3
                                      }.Target,
                                  (Match)new Match_Accessor {
                                          Winner = competitors[0],
                                          Loser = competitors[5],
                                          RunSequence = 4
                                      }.Target,
                                  (Match)new Match_Accessor
                                      {
                                          Winner = competitors[1],
                                          Loser = competitors[2],
                                          RunSequence = 5
                                      }.Target,
                                  (Match)new Match_Accessor
                                      {
                                          Winner = competitors[1],
                                          Loser = competitors[3],
                                          RunSequence = 6
                                      }.Target,
                                  (Match)new Match_Accessor
                                      {
                                          Winner = competitors[1],
                                          Loser = competitors[4],
                                          RunSequence = 7
                                      }.Target,
                                  (Match)new Match_Accessor
                                      {
                                          Winner = competitors[1],
                                          Loser = competitors[5],
                                          RunSequence = 8
                                      }.Target,
                                  (Match)new Match_Accessor
                                      {
                                          Winner = competitors[2],
                                          Loser = competitors[0],
                                          RunSequence = 9
                                      }.Target,
                                  (Match)new Match_Accessor
                                      {
                                          Winner = competitors[2],
                                          Loser = competitors[3],
                                          RunSequence = 10
                                      }.Target,
                                  (Match)new Match_Accessor
                                      {
                                          Winner = competitors[2],
                                          Loser = competitors[4],
                                          RunSequence = 11
                                      }.Target,
                                  (Match)new Match_Accessor
                                      {
                                          Winner = competitors[2],
                                          Loser = competitors[5],
                                          RunSequence = 12
                                      }.Target,
                                  (Match)new Match_Accessor
                                      {
                                          Winner = competitors[3],
                                          Loser = competitors[4],
                                          RunSequence = 13
                                      }.Target,
                                  (Match)
                                  new Match_Accessor
                                      {
                                          Winner = competitors[4],
                                          Loser = competitors[5],
                                          RunSequence = 14
                                      }.Target,
                                  (Match)new Match_Accessor
                                      {
                                          Winner = competitors[5],
                                          Loser = competitors[3],
                                          RunSequence = 15
                                      }.Target
                              };

            var tournamentRoundRanks = new CompetitorRanks
                                           {
                                               { competitors[0], 1 },
                                               { competitors[1], 2 },
                                               { competitors[2], 2 },
                                               { competitors[3], 4 },
                                               { competitors[4], 4 },
                                               { competitors[5], 4 }
                                           };

            while (RrTRS_Accessor.BreakTies(tournamentRoundRanks, matches)) { };

            Assert.AreEqual(1, tournamentRoundRanks[competitors[0]]);
            Assert.AreEqual(2, tournamentRoundRanks[competitors[1]]);
            Assert.AreEqual(3, tournamentRoundRanks[competitors[2]]);
            Assert.AreEqual(4, tournamentRoundRanks[competitors[4]]);
            Assert.AreEqual(5, tournamentRoundRanks[competitors[5]]);
            Assert.AreEqual(6, tournamentRoundRanks[competitors[3]]);
        }
        public void BreakTiesTest_ThreeWayTie()
        {
            var competitors = new List<Competitor>
                                  {
                                      new Competitor { Name = "A" },
                                      new Competitor { Name = "B" },
                                      new Competitor { Name = "C" }
                                  };

            var matches = new List<Match>();

            var matchAccessor = new Match_Accessor { Winner = competitors[0], Loser = competitors[1], RunSequence = 1 };
            matches.Add((Match)matchAccessor.Target);

            matchAccessor = new Match_Accessor { Winner = competitors[1], Loser = competitors[2], RunSequence = 2 };
            matches.Add((Match)matchAccessor.Target);

            matchAccessor = new Match_Accessor { Winner = competitors[2], Loser = competitors[0], RunSequence = 3 };
            matches.Add((Match)matchAccessor.Target);

            var tournamentRoundRanks = new CompetitorRanks
                                                       {
                                                           { competitors[0], 1 },
                                                           { competitors[1], 1 },
                                                           { competitors[2], 1 }
                                                       };

            while (RrTRS_Accessor.BreakTies(tournamentRoundRanks, matches)) { };

            Assert.IsTrue(tournamentRoundRanks[competitors[1]] < tournamentRoundRanks[competitors[2]]);
            Assert.IsTrue(tournamentRoundRanks[competitors[2]] < tournamentRoundRanks[competitors[0]]);
        }
        public void BreakTiesTest()
        {
            var competitors = Helpers.CompetitorListHelper.GetStandardCompetitors(6);

            var round = new TournamentRound(new RrTRS(), new SimpleRandomMs());
            round.Run(competitors);

            var tournamentRoundRanks = new CompetitorRanks
                                           {
                                               { competitors[0], 1 },
                                               { competitors[1], 2 },
                                               { competitors[2], 2 },
                                               { competitors[3], 4 },
                                               { competitors[4], 4 },
                                               { competitors[5], 4 }
                                           };

            RrTRS_Accessor.BreakTies(tournamentRoundRanks, round.Matches);

            Assert.IsTrue(tournamentRoundRanks[competitors[0]] < tournamentRoundRanks[competitors[1]]);
            Assert.IsTrue(tournamentRoundRanks[competitors[0]] < tournamentRoundRanks[competitors[2]]);
            Assert.IsTrue(tournamentRoundRanks[competitors[1]] < tournamentRoundRanks[competitors[3]]);
            Assert.IsTrue(tournamentRoundRanks[competitors[1]] < tournamentRoundRanks[competitors[4]]);
            Assert.IsTrue(tournamentRoundRanks[competitors[1]] < tournamentRoundRanks[competitors[5]]);
            Assert.IsTrue(tournamentRoundRanks[competitors[2]] < tournamentRoundRanks[competitors[3]]);
            Assert.IsTrue(tournamentRoundRanks[competitors[2]] < tournamentRoundRanks[competitors[4]]);
            Assert.IsTrue(tournamentRoundRanks[competitors[2]] < tournamentRoundRanks[competitors[5]]);
        }
        public override CompetitorRanks GenerateResult(int tournamentRunSequence, MatchStrategies.MatchStrategy matchStrategy, List<Competitor> competitors)
        {
            if (competitors.Count != 8)
                throw new ArgumentException("Collection count must be 8.", "competitors");

            // round robin to seed 2 separate round robins
            TournamentRound rr1 = new TournamentRound(new RrTRS(_numberOfRr1Rounds), matchStrategy);
            CompetitorRanks rr1Ranks = rr1.Run(competitors);

            List<Competitor> rrACompetitors = rr1Ranks
                .OrderBy(x => x.Value)
                .Take(4)
                .Select(x => x.Key)
                .ToList<Competitor>();

            List<Competitor> rrBCompetitors = rr1Ranks
                .OrderBy(x => x.Value)
                .Skip(4)
                .Take(4)
                .Select(x => x.Key)
                .ToList<Competitor>();

            // round robin to determine 1, 2, 3
            TournamentRound rrA = new TournamentRound(new RrTRS(_numberOfRr2Rounds), matchStrategy);
            CompetitorRanks rrARanks = rrA.Run(rrACompetitors);

            // round robin to determine 4
            TournamentRound rrB = new TournamentRound(new RrTRS(_numberOfRr2Rounds), matchStrategy);
            CompetitorRanks rrBRanks = rrB.Run(rrBCompetitors);

            // finals
            List<Competitor> finalsCompetitors = rrARanks
                .OrderBy(x => x.Value)
                .Take(2)
                .Select(x => x.Key)
                .ToList<Competitor>();

            TournamentRound finals = new TournamentRound(new KoTRS(_winsToClinchFinalMatch), matchStrategy);
            CompetitorRanks finalsRanks = finals.Run(finalsCompetitors);

            // petit finals
            List<Competitor> petitFinalsCompetitors = rrARanks
                .OrderBy(x => x.Value)
                .Skip(2)
                .Take(1)
                .Select(x => x.Key)
                .ToList<Competitor>();

            Competitor rrBWinner = rrBRanks
                .OrderBy(x => x.Value)
                .Take(1)
                .Select(x => x.Key)
                .First();

            petitFinalsCompetitors.Add(rrBWinner);

            TournamentRound petitFinals = new TournamentRound(new KoTRS(_winsToClinchPetitFinalMatch), matchStrategy);
            CompetitorRanks petitFinalsRanks = petitFinals.Run(petitFinalsCompetitors);

            // consolation round
            List<Competitor> consolationCompetitors = rrBRanks
                .OrderBy(x => x.Value)
                .Skip(1)
                .Select(x => x.Key)
                .ToList<Competitor>();

            Competitor rrALoser = rrARanks
                .OrderBy(x => x.Value)
                .Skip(3)
                .Take(1)
                .Select(x => x.Key)
                .First();

            consolationCompetitors.Add(rrALoser);

            TournamentRound consolationRound = new TournamentRound(new RrTRS(_numberOfRr3Rounds), matchStrategy);
            CompetitorRanks consolationRanks = consolationRound.Run(consolationCompetitors);

            CompetitorRanks ranks = new CompetitorRanks();
            
            int i = 1;
            foreach (var rank in finalsRanks.OrderBy(x => x.Value))
            {
                ranks.Add(rank.Key, i++);
            }

            foreach (var rank in petitFinalsRanks.OrderBy(x => x.Value))
            {
                ranks.Add(rank.Key, i++);
            }

            foreach (var rank in consolationRanks.OrderBy(x => x.Value))
            {
                ranks.Add(rank.Key, i++);
            }

            return ranks;
        }
        public void Run(List<Competitor> competitors)
        {
            RunSequence = ++_sequence;

            _competitors = competitors;

            _competitorTournamentRanks = _tournamentStrategy.GenerateResult(RunSequence.Value, _matchStrategy, competitors);

            AssignTournamentRanksToCompetitorObjects();
        }