Пример #1
0
        public static IRacingSessionModel GetSerializedSessionInfo(this IRacingSDK racingSDK)
        {
            var sessionInfo = racingSDK.GetSessionInfo();

            if (sessionInfo == null)
            {
                return(null);
            }

            return(IRacingSessionModel.Serialize(sessionInfo));
        }
Пример #2
0
        public static Dictionary <int, int> CalculateSOFs(IRacingDataModel dataModel, IRacingSessionModel sessionModel)
        {
            if (sessionModel == null)
            {
                return(null);
            }

            if (dataModel == null)
            {
                return(null);
            }

            var drivers = sessionModel.DriverInfo.Drivers;

            var result  = new Dictionary <int, int>();
            var classes = drivers
                          .Where(x => x.IsSpectator == 0)
                          .Where(x => x.CarIsPaceCar == "0")
                          .Where(x => x.CarIsAI == "0")
                          .Select(x => x.CarClassID)
                          .GroupBy(x => x)
                          .Select(x => x.Key)
                          .ToList();

            classes.ForEach(carClass =>
            {
                var driversInClass = drivers
                                     .Where(x => x.IsSpectator == 0)
                                     .Where(x => x.CarIsPaceCar == "0")
                                     .Where(x => x.CarIsAI == "0")
                                     .Where(x => x.CarClassID == carClass).ToList();

                var fieldSize = driversInClass.Count();

                var exponentials = new List <double>();

                //Calculate exponentials
                driversInClass.ForEach(x => exponentials.Add(Math.Exp((x.IRating * -1) / _initialConstant)));

                result.Add(carClass, Convert.ToInt32(_initialConstant * Math.Log(driversInClass.Count / exponentials.Sum())));
            });

            return(result);
        }
Пример #3
0
        public static Dictionary <int, double> CalculateIRatingGains(IRacingDataModel dataModel, IRacingSessionModel sessionModel)
        {
            if (sessionModel == null)
            {
                return(null);
            }

            if (dataModel == null)
            {
                return(null);
            }
            var currentSessionId = dataModel.Data.SessionNum;
            var currentSession   = sessionModel.SessionInfo.Sessions.Where(x => x.SessionNum == currentSessionId).FirstOrDefault();

            if (currentSession == null)
            {
                return(null);
            }

            if (currentSession.ResultsPositions == null)
            {
                return(null);
            }

            var drivers = sessionModel.DriverInfo.Drivers;

            var result  = new Dictionary <int, double>();
            var classes = drivers
                          .Where(x => x.IsSpectator == 0)
                          .Where(x => x.CarIsPaceCar == "0")
                          .Where(x => x.CarIsAI == "0")
                          .Select(x => x.CarClassID)
                          .GroupBy(x => x)
                          .Select(x => x.Key)
                          .ToList();

            classes.ForEach(carClass =>
            {
                var driversInClass = drivers
                                     .Where(x => x.IsSpectator == 0)
                                     .Where(x => x.CarIsPaceCar == "0")
                                     .Where(x => x.CarIsAI == "0")
                                     .Where(x => x.CarClassID == carClass).ToList();

                var fieldSize = driversInClass.Count();

                var dns = currentSession.ResultsPositions
                          .Where(x => x.ReasonOutId == 1)
                          .Where(x => driversInClass.Any(y => y.CarIdx == x.CarIdx))
                          .Count();

                var exponentials  = new Dictionary <int, double>();
                var probabilities = new Dictionary <int, List <double> >();
                var expectedScore = new Dictionary <int, double>();
                var change        = new Dictionary <int, double>();
                var expectedDNS   = new Dictionary <int, double>();
                var changeDNS     = new Dictionary <int, double>();
                var fudgeFactor   = new Dictionary <int, double>();

                //Calculate exponentials
                driversInClass.ForEach(x => exponentials.Add(x.CarIdx, Math.Exp((x.IRating * -1) / _initialConstant)));

                driversInClass.ForEach(x =>
                {
                    //calculate _probabilities
                    probabilities.Add(x.CarIdx, new List <double>());
                    driversInClass.ForEach(y =>
                    {
                        probabilities[x.CarIdx].Add(
                            (1 - exponentials[x.CarIdx]) * exponentials[y.CarIdx] /
                            (
                                (1 - exponentials[y.CarIdx]) * exponentials[x.CarIdx] +
                                (1 - exponentials[x.CarIdx]) * exponentials[y.CarIdx])
                            );
                    });

                    //calculate expected score
                    expectedScore.Add(x.CarIdx, probabilities[x.CarIdx].Sum(y => y) - 0.5);
                });

                driversInClass.ForEach(x =>
                {
                    var currentPosition = currentSession.ResultsPositions.Where(y => y.CarIdx == x.CarIdx).FirstOrDefault();
                    if (currentPosition != null && currentPosition.ReasonOutId != 1)
                    {
                        fudgeFactor.Add(x.CarIdx, ((fieldSize - ((double)dns / 2)) / 2 - ((double)currentPosition.ClassPosition + 1)) / 100);
                    }
                });

                driversInClass.ForEach(x =>
                {
                    var currentPosition = currentSession.ResultsPositions.Where(y => y.CarIdx == x.CarIdx).FirstOrDefault();
                    if (currentPosition != null)
                    {
                        if (currentPosition.ReasonOutId != 1)
                        {
                            change.Add(x.CarIdx, (fieldSize - (currentPosition.ClassPosition + 1) - expectedScore[x.CarIdx] - fudgeFactor[x.CarIdx]) * 200 / (fieldSize - dns));
                        }
                    }
                });

                driversInClass.ForEach(x =>
                {
                    var currentPosition = currentSession.ResultsPositions.Where(y => y.CarIdx == x.CarIdx).FirstOrDefault();
                    if (currentPosition != null)
                    {
                        if (currentPosition.ReasonOutId == 1)
                        {
                            expectedDNS.Add(x.CarIdx, expectedScore[x.CarIdx]);
                        }
                    }
                });

                if (dns > 0)
                {
                    var sumOfChangeStarters      = change.Values.Sum(x => x);
                    var avgOfExpectedNonStarters = expectedDNS.Values.Average();
                    //based on current position calculate the change in iRating for those that did not start
                    driversInClass.ForEach(x =>
                    {
                        var currentPosition = currentSession.ResultsPositions.Where(y => y.CarIdx == x.CarIdx).FirstOrDefault();
                        if (currentPosition != null)
                        {
                            if (currentPosition.ReasonOutId == 1)
                            {
                                fudgeFactor.Add(x.CarIdx, 0);
                                changeDNS.Add(x.CarIdx, (sumOfChangeStarters / dns * expectedScore[x.CarIdx] / avgOfExpectedNonStarters) * -1);
                            }
                        }
                    });

                    foreach (var key in changeDNS.Keys)
                    {
                        change.Add(key, changeDNS[key]);
                    }
                }
                foreach (var key in change.Keys)
                {
                    result.Add(key, change[key]);
                }
            });

            return(result);
        }
        /// <summary>
        /// Calculates Gaps and Intervals for all cars and classes in the current race
        ///
        /// This uses Session Info and Data models to calculate positions on the fly rather than using
        /// the official values in the session info model. This means the Gaps and Intervals are as
        /// close to real-time as we can get based on the data passed in.
        ///
        /// </summary>
        /// <param name="dataModel"></param>
        /// <param name="sessionModel"></param>
        /// <returns></returns>
        public static List <CarGapIntervalModel> CalculateGapsAndIntervals(IRacingDataModel dataModel, IRacingSessionModel sessionModel)
        {
            if (sessionModel == null)
            {
                return(null);
            }
            if (dataModel == null)
            {
                return(null);
            }

            var results = new List <CarGapIntervalModel>();

            var trackLength = float.Parse(sessionModel.WeekendInfo.TrackLength.Replace("km", "").Replace("mi", "").Trim());

            if (sessionModel.WeekendInfo.TrackLength.Contains("km"))
            {
                trackLength *= 1000;
            }
            else
            {
                trackLength = (trackLength * (5 / 8)) * 1000;
            }



            //Get Current Session
            var currentSessionNumber = dataModel.Data.SessionNum;

            var currentSession = sessionModel.SessionInfo.Sessions
                                 .Where(x => x.SessionNum == currentSessionNumber)
                                 .FirstOrDefault();


            //All drivers ordered

            var orderedDrivers = dataModel.Data.Cars
                                 .Where(x => x.CarIdxLapDistPct != -1)
                                 .OrderByDescending(x => x.CarIdxLap)
                                 .ThenByDescending(x => x.CarIdxLapDistPct).ToList();

            //find car in first
            var leader = orderedDrivers.FirstOrDefault();

            if (leader == null)
            {
                return(results);
            }

            var leaderSession = currentSession.ResultsPositions.Where(ses => ses.CarIdx == leader.CarIdx).FirstOrDefault();
            var leaderDriver  = sessionModel.DriverInfo.Drivers.Where(ses => ses.CarIdx == leader.CarIdx).FirstOrDefault();

            var drivers = sessionModel.DriverInfo.Drivers
                          .Where(x => x.IsSpectator == 0)
                          .Where(x => x.CarIsPaceCar == "0")
                          .Where(x => x.CarIsAI == "0")
                          .ToList();

            //get the classes
            var classes = drivers
                          .Select(x => x.CarClassID)
                          .GroupBy(x => x)
                          .Select(x => x.Key)
                          .ToList();

            var classLeaders = new Dictionary <int, CarModel>();

            classes.ForEach(classId =>
            {
                var driversInClass = drivers
                                     .Where(x => x.CarClassID == classId)
                                     .Select(x => x.CarIdx)
                                     .ToList();

                classLeaders.Add(classId, orderedDrivers
                                 .Where(x => driversInClass.Any(driver => driver == x.CarIdx))
                                 .FirstOrDefault()
                                 );
            });

            var lastClassCar = new Dictionary <int, CarModel>(classLeaders);

            //create Leader result model
            results.Add(new CarGapIntervalModel
            {
                CarIdx        = leader.CarIdx,
                ClassGap      = TimeSpan.Zero,
                ClassInterval = TimeSpan.Zero,
                ClassIntervalLapDifference = 0,
                Gap      = TimeSpan.Zero,
                Interval = TimeSpan.Zero,
                IntervalLapDifference = 0
            });

            for (int i = 1; i < orderedDrivers.Count(); i++)
            {
                var car           = orderedDrivers[i];
                var carInFront    = orderedDrivers[i - 1];
                var currentDriver = drivers.Where(driver => driver.CarIdx == car.CarIdx).FirstOrDefault();

                if (currentDriver == null)
                {
                    continue;
                }

                //Create model for current car
                var carModel = new CarGapIntervalModel
                {
                    CarIdx = car.CarIdx
                };

                //Interval to Leader
                var times = BetweenCars(leader, car, trackLength);
                carModel.Interval = times.Item1;
                carModel.IntervalLapDifference = times.Item2;

                //Gap between driver in front of current car
                times        = BetweenCars(carInFront, car, trackLength);
                carModel.Gap = times.Item1;


                //grab current class leader
                CarModel currentClassLeader = null;
                if (classLeaders.ContainsKey(currentDriver.CarClassID))
                {
                    currentClassLeader = classLeaders[currentDriver.CarClassID];
                }
                if (currentClassLeader == null)
                {
                    throw new NullReferenceException("There should always be a class leader.");
                }

                //grab last class car used
                CarModel lastCarUsed = null;
                if (lastClassCar.ContainsKey(currentDriver.CarClassID))
                {
                    lastCarUsed = lastClassCar[currentDriver.CarClassID];
                }
                if (lastCarUsed == null)
                {
                    throw new NullReferenceException("There should always be a class leader.");
                }

                if (currentClassLeader.CarIdx == car.CarIdx)
                {
                    carModel.ClassGap      = TimeSpan.Zero;
                    carModel.ClassInterval = TimeSpan.Zero;
                    carModel.ClassIntervalLapDifference = 0;
                }
                else
                {
                    //Interval to Class Leader
                    times = BetweenCars(currentClassLeader, car, trackLength);
                    carModel.ClassInterval = times.Item1;
                    carModel.ClassIntervalLapDifference = times.Item2;

                    //Gap between class driver in front of current car
                    times             = BetweenCars(lastCarUsed, car, trackLength);
                    carModel.ClassGap = times.Item1;

                    lastClassCar[currentDriver.CarClassID] = car;
                }
                results.Add(carModel);
            }

            return(results);
        }
Пример #5
0
 public void GetSerializedSession()
 {
     session = sdk.GetSerializedSessionInfo();
     Assert.NotNull(session);
 }
Пример #6
0
        private static void Loop()
        {
            int lastUpdate = -1;

            while (true)
            {
                var currentlyConnected = sdk.IsConnected();

                // Check if we can find the sim
                if (currentlyConnected)
                {
                    int       attempts    = 0;
                    const int maxAttempts = 99;

                    object sessionnum = TryGetSessionNum();
                    while (sessionnum == null && attempts <= maxAttempts)
                    {
                        attempts++;
                        sessionnum = TryGetSessionNum();
                    }
                    if (attempts >= maxAttempts)
                    {
                        System.Console.WriteLine("Session num too many attempts");
                        continue;
                    }

                    // Parse out your own driver Id
                    if (DriverId == -1)
                    {
                        _DriverId = (int)sdk.GetData("PlayerCarIdx");
                    }

                    var data = sdk.GetSerializedData();

                    // Raise the TelemetryUpdated event and pass along the lap info and session time
                    //var telArgs = new TelemetryUpdatedEventArgs(new TelemetryInfo(sdk), time);
                    // this.RaiseEvent(OnTelemetryUpdated, telArgs);

                    // Is the session info updated?
                    int newUpdate = sdk.Header.SessionInfoUpdate;
                    if (newUpdate != lastUpdate)
                    {
                        lastUpdate = newUpdate;
                        _session   = sdk.GetSerializedSessionInfo();
                    }

                    if (data != null && _session != null)
                    {
                        Console.SetCursorPosition(0, 0);


                        foreach (var car in data.Data.Cars.OrderByDescending(x => x.CarIdxLap).ThenByDescending(x => x.CarIdxLapDistPct))
                        {
                            var currentData = _session.DriverInfo.Drivers.Where(y => y.CarIdx == car.CarIdx).FirstOrDefault();
                            if (currentData != null && car.CarIdxEstTime != 0)
                            {
                                Console.WriteLine($"{currentData.CarNumber}\t{string.Format("{0:0.00}", car.CarIdxEstTime)}\t{string.Format("{0:0.00}", car.CarIdxLapDistPct * 100)}");
                            }
                        }
                    }

                    Thread.Sleep(15);
                }
                else
                {
                    Thread.Sleep(1000);
                }
            }
        }
        public static List <CarRelativeModel> CalculateRelatives(IRacingDataModel dataModel, IRacingSessionModel sessionModel)
        {
            if (sessionModel == null)
            {
                return(null);
            }
            if (dataModel == null)
            {
                return(null);
            }

            var orderedDrivers = dataModel.Data.Cars
                                 .Where(x => x.CarIdxLapDistPct != -1)
                                 .OrderByDescending(x => x.CarIdxLapDistPct).ToList();

            var relatives = new List <CarRelativeModel>();

            var currentCar = sessionModel.DriverInfo.Drivers.FirstOrDefault(x => x.CarIdx == dataModel.Data.PlayerCarIdx);

            if (currentCar == null || currentCar.IsSpectator != 0)
            {
                currentCar = sessionModel.DriverInfo.Drivers.FirstOrDefault(x => x.CarIdx == dataModel.Data.CamCarIdx);
            }
            if (currentCar == null || currentCar.IsSpectator != 0)
            {
                currentCar = sessionModel.DriverInfo.Drivers.FirstOrDefault(x => x.CarIsPaceCar == "0" && x.CarIsAI == "0");
            }
            var currentCarData = dataModel.Data.Cars.FirstOrDefault(x => x.CarIdx == currentCar.CarIdx);

            for (var carIdx = 0; carIdx < dataModel.Data.Cars.Count(); carIdx++)
            {
                var car = dataModel.Data.Cars[carIdx];

                if (car.CarIdx == currentCar.CarIdx)
                {
                    relatives.Add(new CarRelativeModel
                    {
                        CarIdx   = car.CarIdx,
                        Ahead    = TimeSpan.FromSeconds(0),
                        Behind   = TimeSpan.FromSeconds(0),
                        Lap      = car.CarIdxLap,
                        Selected = true,
                        Position = carIdx + 1
                    });
                    continue;
                }

                if (car.CarIdxLapDistPct > currentCarData.CarIdxLapDistPct)
                {
                    //time remaining for car (ahead) to finish the lap they are on
                    var remainingThisLap = currentCarData.CarIdxLastLapTime * (1 - car.CarIdxLapDistPct);

                    relatives.Add(new CarRelativeModel
                    {
                        CarIdx = car.CarIdx,
                        Ahead  = TimeSpan.FromSeconds(car.CarIdxEstTime - currentCarData.CarIdxEstTime),
                        //the time the currentCar is into the lap + the remaining time for the car (ahead)
                        Behind   = TimeSpan.FromSeconds(currentCarData.CarIdxEstTime + remainingThisLap),
                        Lap      = car.CarIdxLap,
                        Selected = false,
                        Position = carIdx + 1
                    });
                }

                if (car.CarIdxLapDistPct < currentCarData.CarIdxLapDistPct)
                {
                    //time remaining for currentCar to finish the lap they are on
                    var remainingThisLap = car.CarIdxLastLapTime * (1 - currentCarData.CarIdxLapDistPct);
                    relatives.Add(new CarRelativeModel
                    {
                        CarIdx = car.CarIdx,
                        //the time for the currentCar to finish the lap + the time the car behind is into their current lap.
                        Ahead    = TimeSpan.FromSeconds(remainingThisLap + car.CarIdxEstTime),
                        Behind   = TimeSpan.FromSeconds(currentCarData.CarIdxEstTime - car.CarIdxEstTime),
                        Lap      = car.CarIdxLap,
                        Selected = false,
                        Position = carIdx + 1
                    });
                }
            }

            return(relatives);
        }