public static IRacingSessionModel GetSerializedSessionInfo(this IRacingSDK racingSDK) { var sessionInfo = racingSDK.GetSessionInfo(); if (sessionInfo == null) { return(null); } return(IRacingSessionModel.Serialize(sessionInfo)); }
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); }
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); }
public void GetSerializedSession() { session = sdk.GetSerializedSessionInfo(); Assert.NotNull(session); }
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); }