The online racing simulator
#1 - amp88
Determining Time Gap Between Drivers
I'm having a bit of trouble determining the time gap between 2 drivers and would appreciate some help, please.

For the purposes of discussion imagine a race with 2 drivers called "A" and "B".

There are 3 distinct cases that I can see:

1. Drivers A and B are on the same lap.
2. Driver A has completed more laps than driver B but driver B is ahead of A on the track (e.g. driver A has completed 6 laps, driver B has completed 5 laps but driver B has not yet been lapped).
3. Driver A has completed more laps than driver B and driver A is ahead of driver B on the track (e.g. driver A has completed 6 laps, driver B has completed 5 laps AND has been passed by driver A on the track).

If the drivers are on the same lap (or case 2 is true and the difference in laps completed is 1) the gap should be displayed as a time whereas if cases 2 or 3 are true and the difference in laps completed is greater than 1 the gap should be displayed as a number of laps.

The problems I'm having are:

Determining whether case 2 or 3 is true if the drivers are on different laps. I think the best way is to use their current node index (from the IS_NLP packet).

Determining the time gap if case 2 is true and the laps completed difference is 1. In this case I think you would just take the split time for the last completed split of the driver behind and subtract the split time at the same point of the player ahead on their last lap.

Am I on the right lines? Am I missing something obvious? Am I going insane with these questions?
Yes, you would use the splits. I store a list of all the players, with their LapsDone and RaceTime, and update it each time they cross a split. Then I sort the list by LapsDone, or if the players are on the same lap by their RaceTimes. Then I loop through the list and subtract each players RaceTime from the time of the player in front of them. This gives you their relative times.
#3 - amp88
How do you determine who is ahead on the track? Do you just rely on split times or do you use the current node index or something else?
I use the split times, or more exactly the ETime from the split, which is the drivers total elapsed time in the race. You can sort by this and figure out what order people are in. However you also need to use the players laps done in the comparison as well, as if someone joins a race half way through they will have a lower elapsed time than the winner, even through they are actually far behind.

Let me show you the code I use in LFSPoints for determining the race finishing order. This is C# .NET, but should hopefully make sense in Java as they are so similar. We have a class which we store the player info we need, and also implements the sorting algorithm.

class Player : IComparable<Player>
{
public int LapsDone;
public long TotalElapsed;

// This method is called by the Sort comparison.
public int CompareTo(Player other)
{
// If they are on the same lap we compare by elapsed time.
if (this.LapsDone == other.LapsDone)
{
return this.TotalElapsed.CompareTo(other.TotalElapsed);
}
// Otherwise we compare by laps done.
return other.LapsDone.CompareTo(this.LapsDone);
}
}

Then you can just sort your list of players.

// Dummy list.
List<Player> players = new List<Player>();

// Sort the list, which uses the Player.CompareTo() method.
players.Sort();

foreach (Player player in players)
{
// These players are in order.
}

That's not the only way of doing it of course, but it's what I use and I think it's simple and works very well. The key obviously is using built-in List sorting mechanism, but I'm sure Java allows this, although the syntax might be different.

Anyway, hope that makes sense.
#5 - amp88
Sorry for the miscommunication. I understand your methodology (your custom comparator using the laps done then total time to rank players), but I'm trying to do something slightly different. Driver A has completed 4 laps and is in the middle of the first sector of his lap 5. Driver B has completed 3 laps and is in the middle of the first sector of his lap 4. Clearly driver A is ahead of driver B (since his laps completed is greater), but the key thing I'm trying to ascertain is whether or not driver B is a lap down on driver A. If driver A is ahead of driver B in the first sector then driver B is a lap down (so the gap is +1 lap). If driver B is ahead of driver A then driver B isn't yet a lap down (so the gap will be 1:30.00 or whatever).
Quote from amp88 :but the key thing I'm trying to ascertain is whether or not driver B is a lap down on driver A.


// 1 = 4 - 3
int lapsDown = a.LapsDone - b.LapsDone;

if (lapsDown > 0)
{
// b is a lap down
}

Sorry, obviously I don't get it. The sectors don't matter, either you've completed a lap or you haven't.
#7 - amp88
I've attached a diagram to try and help explain the situation.
Attached images
diagramifvhbfivr.gif
The problem is when a driver's lap delta is less then or equal to 1 how do you know if the one driver is physically ahead of the other driver. If the delta between the two lap counts is great then 1, then it physically does not matter where the cars are on track because they are definitely a lap or more down.

The answered I would think would be there physical location on the track (via their NodeLap data and use of their position in the race) if the lap delta is less then or equal to 1.
#9 - amp88
Quote from Dygear :The problem is when a driver's lap delta is less then or equal to 1 how do you know if the one driver is physically ahead of the other driver. If the delta between the two lap counts is great then 1, then it physically does not matter where the cars are on track because they are definitely a lap or more down.

The answered I would think would be there physical location on the track (via their NodeLap data and use of their position in the race) if the lap delta is less then or equal to 1.

The same problem exists if the difference in laps completed is greater than 1. If driver A had completed 7 laps instead of 5 in the above image the difference would either be 2 or 3 laps depending on where the cars were.

I was just hoping maybe someone had done something similar before so they could give me some pointers or their algorithm.
Oh, so you want a real time update on this then! With each update on car position then you would have to do this check. So the code you do use will be called at (REFRESHRATE * MAX_CLIENTS) And If I remember correctly the engine allows for an update every 50 ms, and there can be 32 cars in a race at one time ... (1 / 0.050) * 32 = 640 Times a Second! God, I hope what ever code you use scales well!

Ok, so let's get down to basics on this. How does you and me know if one car is ahead of another, what data must we obtain for each instance to make sure the result is correct!

If one car is on the same lap as another car, I know which car is ahead by it's position on track.
For example, if car A is has completed more of the lap then car B, then car A is ahead of car B and visa versa.

If one car is on a different lap as another car I know which car is ahead by the fact that one car has completed more laps then the other.
For example, if car A has completed more laps then car B, then car A is ahead of car B and visa versa.

If one car is on a different lap as another car, how do I know how many laps exactly these two cars are away from each other?
The only way I can think of doing this is to calculate total distance traveled from the start of the race. For example, the start line is 0 up to the maximum nodelaps of that track. So $Distance = ($NodeCount * $LapsDone) + $CurrentNode. Now to find out how many laps a car is behind another you could use there total distance divided by the node count of the track your on. ($A->Distance / $B->Distance) / $NodeCount = LapsDelta;

There are all intagers: $Distance, $NodeCount, $LapsDone, $CurrentNode, $A->Distance, $B->Distance;
However the LapsDelta will be a float, so you will have to round down to get the amount of whole laps between two cars.
Quote from Dygear :Oh, so you want a real time update on this then! With each update on car position then you would have to do this check. So the code you do use will be called at (REFRESHRATE * MAX_CLIENTS) And If I remember correctly the engine allows for an update every 50 ms, and there can be 32 cars in a race at one time ... (1 / 0.050) * 32 = 640 Times a Second! God, I hope what ever code you use scales well!

Thankfully I'm only updating the displayed difference at a set rate. I'm using 2 seconds at the moment but that can easily be changed. I've attached a screenshot to give a bit more information about what I'm trying to do (in the Gap (Ahead) and Gap (Leader) columns).

Quote from Dygear :Ok, so let's get down to basics on this. How does you and me know if one car is ahead of another, what data must we obtain for each instance to make sure the result is correct!

Yes! That's what I'd like to do.

OK, from the start:

LFS tells us the race positions (1st, 2nd, 3rd etc) and the current track position (the node of the track they're on) of all the drivers in the race in the Node and Lap packet (IS_NLP).
The number of laps the driver has completed can be determined from various sources (IS_NLP, IS_LAP, IS_PIT etc).
A record can be kept of each of the driver's split times (IS_SPX).

The goal is to display the gap between drivers. If the drivers are a lap or more apart the gap should be displayed as a number of laps (e.g. +1 lap, +3 laps). If the drivers are a lap or less apart the gap should be displayed as a time difference. This time difference should be measured using the last split time the player behind has completed and comparing that with the last split the player ahead did at the same split on their last lap. However, the difficult thing for me at the moment comes in the cases I talked about above (determining the number of laps difference by taking into account the position on the track of the drivers). If the difference in laps completed is 1 and the driver who has done more laps is ahead of the driver who has done less laps then the gap should be represented as +1 lap. If the difference in laps completed is 1 BUT the driver who has done more laps is behind the driver who has done less laps then the gap should be represented as a time.
Attached images
lfstimes0.4.1A.png
Quote from Dygear :The only way I can think of doing this is to calculate total distance traveled from the start of the race. For example, the start line is 0 up to the maximum nodelaps of that track. So $Distance = ($NodeCount * $LapsDone) + $CurrentNode. Now to find out how many laps a car is behind another you could use there total distance divided by the node count of the track your on. ($A->Distance / $B->Distance) / $NodeCount = LapsDelta;

However the LapsDelta will be a float, so you will have to round down to get the amount of whole laps between two cars.

Use the code found in the quote. If the LapsDelta is 0 then you have to find the time between the two cars. I would agree the use of ETime from the most up-to-date LAP/SPX packet, as described by DarkTimes here, would be the best bet but only to find the time behind another driver, not it's current place.
Quote from Dygear :Use the code found in the quote. If the LapsDelta is 0 then you have to find the time between the two cars. I would agree the use of ETime from the most up-to-date LAP/SPX packet, as described by DarkTimes here, would be the best bet but only to find the time behind another driver, not it's current place.

Thanks, I hadn't seen the edit you made to the post above my last post until you posted now. Much appreciated.
#14 - mobu
Because you're using the split times for calculating the gaps you could use the event that a sector is finished by a racer to update the gaps to the other racers. By storing at which lap and race time a sector is finished for all racers you can easily determine when racers have been lapped: If racer A has not lapped racer B, racer B will update sector splits before racer A, i.e. the lap counter for that sector is updated for racer B before racer A. If racer B has been lapped by racer A, racer A will update sector split before racer B. If difference in lap count of a sector split is 0 gap should be calculated as time diff by comparing the race times stored for that sector; if it is greater than 0, gap should be calculated as lap diff by comparing the laps stored for that sector.

I have no insim programming experience, so I might be handicapped by lack of knowledge. But it works in my head

/Morten

EDIT: My answer seems to have come a little to late...
Quote from mobu :/Morten

Morten, while your proposal would work, it is not what he is asking for. Amp wants to know when one driver laps another the second it happens, he does not want to have to wait for the next sector to get this information and if they have not lapped each other how many seconds are they away from each other. Again, this is where your system would shine, so he could implament both and get the efficency of your system when they are not a lap down, but the accurcy of my system when they are!
#16 - mobu
Quote from Dygear :Morten, while your proposal would work, it is not what he is asking for. Amp wants to know when one driver laps another the second it happens, he does not want to have to wait for the next sector to get this information and if they have not lapped each other how many seconds are they away from each other. Again, this is where your system would shine, so he could implament both and get the efficency of your system when they are not a lap down, but the accurcy of my system when they are!

Oh, I hadn't understood it as he wanted to know when one driver laps another instantly. I just thought he used a timer based update because it was easier than an event driven update.

The combination sounds like the perfect solution
/Morten
Here is another approach with resource hogging (or however you call it)

Save the time each 10 tracknodes and then simply subtract the times from each other at a specific node ^^

public override void setNode(int lap, int node)
{
myLap = lap;
myNode = node;
if (node % 10 == 0)
{
nodeTimes[string.Format("lap{0:0}node{1:0}", lap, node)] = DateTime.Now;
}
}

public override bool hasNodeTime(int lap, int node)
{
return nodeTimes.ContainsKey(string.Format("lap{0:0}node{1:0}", lap, node));
}

public override DateTime getNodeTime(int lap, int node)
{
if (hasNodeTime(lap, node))
{
return (DateTime)nodeTimes[string.Format("lap{0:0}node{1:0}", lap, node)];
}
else
{
return new DateTime(0);
}
}

// Distance
if (playerF.hasNodeTime(((RaceDriver)bean.Player).lap, ((RaceDriver)bean.Player).node) && bean.Player.hasNodeTime(((RaceDriver)bean.Player).lap, ((RaceDriver)bean.Player).node))
{
DateTime playerT = bean.Player.getNodeTime(((RaceDriver)bean.Player).lap, ((RaceDriver)bean.Player).node);
DateTime playerFT = playerF.getNodeTime(((RaceDriver)bean.Player).lap, ((RaceDriver)bean.Player).node);
TimeSpan dist = playerT.Subtract(playerFT);
this.lcdDistF.Text = string.Format("{0:00}:{1:00}:{2:000}", dist.Minutes, dist.Seconds, dist.Milliseconds);
}

With playerF being the "front" one and players are sorted by race positions.

That's from the Live for G15 app.

FGED GREDG RDFGDR GSFDG