private static Car GetFirstCar(Tournament tournament, IGrouping<string, CarResult> classGroup)
 {
     var maxPoints = classGroup.Max(r => r.Points);
     var carsWithMaxPoints = classGroup.Where(r => r.Points == maxPoints).ToArray();
     if (carsWithMaxPoints.Count() == 1)
     {
         return carsWithMaxPoints.First().Car;
     }
     var tiebreakWinner = TiebreakWinner(tournament, classGroup);
     if (tiebreakWinner == null)
     {
         return null;
     }
     return tiebreakWinner;
 }
        public Tournament Build(string round = "prelim")
        {
            var races = new SortedList<double, Race>();
            var groups = new List<Group>();
            for (var groupIndex = 0; groupIndex < _groups.Count; groupIndex++)
            {
                var group = _groups[groupIndex];
                groups.Add(group.Item1);
                var carsByNumber = group.Item1.Cars.ToDictionary(c => c.Number);
                var length = group.Item2.Length;
                for (var i = 0; i < length; i++)
                {
                    var offset = (groupIndex+1)/1000.0;
                    var pctDoneBefore = ((double) i)/length + offset;
                    var pctDoneAfter = ((double) i + 1)/length - offset;
                    var pctDone = pctDoneBefore >= 0.5 ? pctDoneBefore : pctDoneAfter;
                    var raceDef = group.Item2[i];
                    var race = new Race
                    {
                        Round = round,
                        Group = group.Item1.Name,
                        Car1 = new RaceResult{Car = carsByNumber[raceDef.Lane1]},
                        Car2 = new RaceResult{Car = carsByNumber[raceDef.Lane2]},
                        Car3 = new RaceResult{Car = carsByNumber[raceDef.Lane3]},
                        Car4 = new RaceResult{Car = carsByNumber[raceDef.Lane4]},
                    };
                    races.Add(pctDone, race);
                }
            }

            var raceList = races.Values.ToArray();
            for (var i = 0; i < raceList.Length; i++)
            {
                raceList[i].RaceNumber = i + 1;
            }

            var tournament = new Tournament {Groups = groups.ToArray(), Races = raceList.ToArray(), Name = TournamentName};
            return tournament;
        }
 private static IEnumerable<IGrouping<string, CarResult>> ResultsByClass(Tournament tournament, Group g)
 {
     var racesInGroup = tournament.Races.Where(r => r.Group == g.Name).ToArray();
     var carResults = racesInGroup.SelectMany(r => new[] {r.Car1, r.Car2, r.Car3, r.Car4});
     var carResultsByCar = from r in carResults
         group r by r.Car.ID
         into _g
         select
             new CarResult(_g.First().Car, _g.Count(r => r.Place == 1), _g.Count(r => r.Place == 2),
                 _g.Count(r => r.Place == 3), _g.Count(r => r.Place == 4), _g.Count());
     var resultsByClass = from result in carResultsByCar
         group result by g.ShowClassStandings ? result.Car.Class : ""
         into _g
         select _g;
     return resultsByClass;
 }
 private static int BuildTiebreakerRacesForPointLevel(Tournament tournament, string classKey, IEnumerable<CarResult> classGroup, int maxPoints, Group g,
     LaneStat[] laneStats, int byeCounter, string roundName, TournamentBuilder tiebreakerTournamentBuilder, int tiebreakerPlace)
 {
     var carsWithMaxPoints = classGroup.Where(r => r.Points == maxPoints).ToArray();
     var baseGroup = g.ShowClassStandings ? classKey : g.Name;
     if (carsWithMaxPoints.Count() > 1 && !tournament.Groups.Any(_g => _g.TiebreakGroup == baseGroup))
     {
         int i = 1;
         var tiedCars =
             carsWithMaxPoints.Select(
                 c =>
                     new Car
                     {
                         Builder = c.Car.Builder,
                         Class = c.Car.Class,
                         ID = c.Car.ID,
                         Name = c.Car.Name,
                         Number = i++
                     }).ToList();
         var raceDef = RaceDefinitionSource.RaceDefinitions(tiedCars.Count(), 1, laneStats);
         while (tiedCars.Count() < 4)
         {
             byeCounter++;
             var carId = "BYE" + byeCounter;
             tiedCars.Add(new Car {Builder = carId, Name = carId, ID = carId, Number = i});
             i++;
         }
         var name = tiebreakerPlace == 1
             ? string.Join("-", baseGroup.Split('-').First(), roundName)
             : string.Join("-", baseGroup.Split('-').First()+":"+tiebreakerPlace, roundName);
         var tiedGroup = new Group {Name = name, Cars = tiedCars.ToArray(), Round = roundName, TiebreakGroup = baseGroup};
         tiebreakerTournamentBuilder.AddGroup(tiedGroup, raceDef);
     }
     return byeCounter;
 }
 private static Car TiebreakWinner(Tournament tournament, IGrouping<string, CarResult> classGroup)
 {
     var tiebreakCount = 1;
     while (true)
     {
         var tiebreakGroupName = string.Join("-", classGroup.Key, "Tiebreaker", tiebreakCount);
         var tiebreakGroup = tournament.Groups.FirstOrDefault(g => g.Name == tiebreakGroupName);
         if (tiebreakGroup == null)
         {
             return null;
         }
         var tiebreakResults = ResultsByClass(tournament, tiebreakGroup).First();
         var maxPoints = tiebreakResults.Max(r => r.Points);
         var carsWithMaxPoints = tiebreakResults.Where(r => r.Points == maxPoints).ToArray();
         if (carsWithMaxPoints.Count() == 1)
         {
             return carsWithMaxPoints.First().Car;
         }
         tiebreakCount++;
     }
 }
 public static void Save(this Tournament tournament)
 {
     File.WriteAllText(@"C:\Tournaments\{0}\tournament.{1}.json".FormatWith(tournament.Name, DateTime.Now.ToString("yyyyMMdd-hhmmss")), JsonConvert.SerializeObject(tournament, Formatting.Indented));
     File.WriteAllText(@"C:\Tournaments\{0}\tournament.json".FormatWith(tournament.Name), JsonConvert.SerializeObject(tournament, Formatting.Indented));
 }
 public HttpResponseMessage SaveTournament(Tournament tournament)
 {
     tournament.Update();
     tournament.Save();
     return ApiResponse.SuccessResponse(Request, tournament);
 }