public static void AddFinalsRaces(this Tournament tournament)
        {
            if (!tournament.Races.All(r => r.IsFinished()) || tournament.Groups.Any(g => g.Name == "Finals"))
            {
                return;
            }
            var finalsCars = new List<Car>();
            var scoutGroup = tournament.Groups.First(g => g.Name == "Scouts");
            var resultsByClass = ResultsByClass(tournament, scoutGroup);
            foreach (var classGroup in resultsByClass)
            {
                var firstCar = GetFirstCar(tournament, classGroup);
                if (firstCar == null)
                {
                    return;
                }
                finalsCars.Add(firstCar.Copy());
            }
            for (int i = 0; i < finalsCars.Count; i++)
            {
                finalsCars[i].Number = i + 1;
            }

            var tournamentBuilder = new TournamentBuilder("finals", "");
            var laneStats = tournament.LaneStats;
            var finalsGroup = new Group {Name = "Finals", Round = "Finals", Cars = finalsCars.ToArray()};
            var raceDef = RaceDefinitionSource.RaceDefinitions(finalsCars.Count, 1, laneStats);
            tournamentBuilder.AddGroup(finalsGroup, raceDef);
            var finalsTournament = tournamentBuilder.Build("Finals");
            tournament.AddGroupsAndRaces(finalsTournament.Groups, finalsTournament.Races);
        }
        public static void AddTiebreakerRaces(this Tournament tournament)
        {
            int byeCounter = 0;

            if (!tournament.Races.All(r => r.IsFinished()))
            {
                return;
            }
            var tiebreakerRounds = tournament.Groups.Select(g => g.Round).Where(r => r != null && r.Contains("Tie"));
            var tiebreakerRound  = 0;

            foreach (var round in tiebreakerRounds)
            {
                var thisRound = round.Split('-').Last().ToInt();
                tiebreakerRound = Math.Max(thisRound, tiebreakerRound);
            }
            var roundName = "Tie - " + (tiebreakerRound + 1);
            var laneStats = tournament.LaneStats;

            foreach (var g in tournament.Groups)
            {
                var resultsByClass = ResultsByClass(tournament, g);

                foreach (var classGroup in resultsByClass)
                {
                    var take          = g.Round == "prelim" ? 3 : 1;
                    var maxPointList  = classGroup.OrderByDescending(r => r.Points).Take(take).Select(r => r.Points).ToArray();
                    var lastMaxPoints = 0;
                    for (var i = 0; i < maxPointList.Length; i++)
                    {
                        if (lastMaxPoints == maxPointList[i])
                        {
                            continue;
                        }
                        var tiebreakerTournamentBuilder = new TournamentBuilder(tournament.Name + " - tiebreakers", "");
                        var maxPoints       = lastMaxPoints = maxPointList[i];
                        var tieBreakerPlace = CalculateTiebreakerPlace(g.Name, i + 1);
                        byeCounter = BuildTiebreakerRacesForPointLevel(tournament, classGroup.Key, classGroup, maxPoints, g, laneStats,
                                                                       byeCounter, roundName, tiebreakerTournamentBuilder, tieBreakerPlace);
                        var tiebreakerTournament = tiebreakerTournamentBuilder.Build(roundName);
                        foreach (var race in tiebreakerTournament.Races)
                        {
                            foreach (var car in race.Cars())
                            {
                                if (car.IsBye())
                                {
                                    car.Place  = 4;
                                    car.Points = 1;
                                }
                            }
                        }

                        tournament.AddGroupsAndRaces(tiebreakerTournament.Groups, tiebreakerTournament.Races);
                    }
                }
            }
        }
        public static void AddFinalsRaces(this Tournament tournament)
        {
            if (!tournament.Races.All(r => r.IsFinished()) || tournament.Groups.Any(g => g.Name == "Finals"))
            {
                return;
            }
            var finalsCars     = new List <Car>();
            var scoutGroup     = tournament.Groups.First(g => g.Name == "Scouts");
            var resultsByClass = ResultsByClass(tournament, scoutGroup);

            foreach (var classGroup in resultsByClass)
            {
                var firstCar = GetFirstCar(tournament, classGroup);
                if (firstCar == null)
                {
                    return;
                }
                finalsCars.Add(firstCar.Copy());
            }
            for (int i = 0; i < finalsCars.Count; i++)
            {
                finalsCars[i].Number = i + 1;
            }

            var tournamentBuilder = new TournamentBuilder("finals", "");
            var laneStats         = tournament.LaneStats;
            var finalsGroup       = new Group {
                Name = "Finals", Round = "Finals", Cars = finalsCars.ToArray()
            };
            var raceDef = RaceDefinitionSource.RaceDefinitions(finalsCars.Count, 1, laneStats);

            tournamentBuilder.AddGroup(finalsGroup, raceDef);
            var finalsTournament = tournamentBuilder.Build("Finals");

            tournament.AddGroupsAndRaces(finalsTournament.Groups, finalsTournament.Races);
        }
        public static void AddTiebreakerRaces(this Tournament tournament)
        {
            int byeCounter = 0;
            if (!tournament.Races.All(r => r.IsFinished()))
            {
                return;
            }
            var tiebreakerRounds = tournament.Groups.Select(g => g.Round).Where(r => r != null && r.Contains("Tiebreaker"));
            var tiebreakerRound = 0;
            foreach (var round in tiebreakerRounds)
            {
                var thisRound = round.Split('-').Last().ToInt();
                tiebreakerRound = Math.Max(thisRound, tiebreakerRound);
            }
            var roundName = "Tiebreaker-" + (tiebreakerRound + 1);
            var tiebreakerTournamentBuilder = new TournamentBuilder(tournament.Name + " - tiebreakers", "");
            var laneStats = tournament.LaneStats;
            foreach (var g in tournament.Groups)
            {
                var resultsByClass = ResultsByClass(tournament, g);

                foreach (var classGroup in resultsByClass)
                {
                    var take = g.Round == "prelim" ? 3 : 1;
                    var maxPointList = classGroup.OrderByDescending(r => r.Points).Take(take).Select(r => r.Points).Distinct().ToArray();
                    for (var i = 0; i < maxPointList.Length; i++)
                    {
                        var maxPoints = maxPointList[i];
                        byeCounter = BuildTiebreakerRacesForPointLevel(tournament, classGroup.Key, classGroup, maxPoints, g, laneStats,
                            byeCounter, roundName, tiebreakerTournamentBuilder, i + 1);
                    }
                }
            }
            var tiebreakerTournament = tiebreakerTournamentBuilder.Build(roundName);
            tournament.AddGroupsAndRaces(tiebreakerTournament.Groups, tiebreakerTournament.Races);
        }