Would love to get some analysis on this from the NP Math Experts such as @xjhdexter or Jay himself.
So I was mapping out some routes in the 1v1 game here against @Trucriot and noticed some EXACT same arrival times … like all the way down to 3 digits - who the heck will win (via defensive bonus) when two players travel the exact same distance and arrive at the same unoccupied star?
Except due to mathematical rounding, it’s not “quite” exact … as shown in this example game here. Game setup is a Circular Twin Ring with 24 Stats and Close Distance. I set it up with turn-based and 6 tick jumps. Weapons are locked at Level 3. I made moves that were left/right & top/down “symmetric” and I abandoned the core starts for Yellow and Cyan. Here’s what it looked like after 18 ticks:
For the Right/Left, Cyan (who started from the right) won three of the four battles against Yellow.
The Top/Down is more interesting. First, Green won against Blue in BOTH “interior” battles. HOWEVER, for the “outside” stars (i.e. the previous cores), Blue has arrived at the stars and now owns them - Green has NOT (hard to tell from the image, but look at the game which I have paused).
This is really weird because the distance is shown at 8.000 LY which should take 24 ticks … NOT 25!
Now, some of you are saying “but that would be 8.00001” … but if you use the Range Tool and go back and forth 10 times (how we used to do it in the old days before Jay added the extra decimal points!) the distance is shown as 79.999LY … so what the heck is going on?!?
Also, why did Cyan win most of their battles and Green win the interior battles? Was this due to a very slight mathematical difference? And if you had a map that truly was exact, is there any type of tie-breaker … i.e. player UID … or maybe Green gets the HULK SMASH advantage?!?
Only jay can tell you exactly as the answer depends on coding choices he made.
Decimal numbers (called floats or floating points) in computers are notorious for a lot of the issues you’ve described. The short version is that there is no way to represent precisely a normal (base 10) decimal number in binary for all decimals. You can read a longer explanation with reference to Python (which Jay has mentioned the game is built on) here:
For most cases it goes unnoticed, but tiny rounding error could crop up in edge cases. The case of green not yet arriving could be this although it’s a bit weird.
As to the victory pattern… I’d assume there’s hidden tie breaker, because you don’t usually check for equality between two floats because of the representation issues mentioned above. For instance if the code was something like (not real code):
if distance(CarrierA) < distance(CarrierB):
defender = CarrierA
defender = CarrierB
Then whatever determined which carrier was which would mean it would determine who wins tied - my money would be on the carrier uid likely driving the processing order.
All this is guessing - Jay could have written the code in a variety of ways that would deal with or cause different issues.
As a computer guy, I hear 'ya that floating point representation is not exact … and yea, you’d have to look at Jay’s code to know for sure.
That’s a GREAT programming example @Kaine with LESSTHAN/OR … since that means the corner case of EQUALS goes to CarrierB … so there would be a “hidden” advantage to the order dependence of CarrierA and CarrierB.
Yea, Green taking 25 ticks instead of 24 ticks to travel 8.000LY is clearly a sign of a bug … either in the Range Tool or the movement algorithm … since the former shows 10X trips is 79.999LY.
In many (maybe all) cases, I’ve had travel from a home star to a newly acquired homestar which is 8.0 ly or whatever round number based on settings always is needing the extra level of range even though the ruler says otherwise.
The distance between core stars is 8LY … so the starting parameters are Hyper5 and Scan6 which should just barely reach 8LY. The TOP player can jump to the two “side” cores and also see them … which is what you would expect.
However, while the BOTTOM player can jump to the two “side” cores, it can NOT see them … which is NOT what you would expect.
Just to make it more puzzling, per the original post, the TOP player takes the expected 24 ticks to reach the “side” cores … whereas the BOTTOM player takes 25 ticks.
So doing a “black box” analysis of the code that I can’t see, this suggests to me that the distance determination of Scan versus Hyper is different code … since in this case, it yields different results. There might also be something goofy with the movement algorithm (?)
Over the years, I’ve seen various people point out oddities like this … so if nothing else, this should be a good test case to debug the code to figure out what is happening in this goofy corner case.
For a start, back in the old days when bandwidth mattered I made the decision to truncate all the floats to just 2 or 3 decimal places when sending them to the client. Unnecessary these days, but reduced bandwidth to the client by quite a lot in the old days. So positions on the client are not even rounded, and different to what the server is working with. That could explain some ruler and travel time errors.
Also, yes, fairly sure I just compare the distance of that last jump for initiative, so floating point errors are going to come into play.
Anyhow, thanks for looking at this stuff, it would be nice to sort it all out one day.
@JayKyburz - Thanks for chiming in and roger on the “space” trade-off by truncating the floats to the client … so the player view is ever-so-slightly different than the server. I wonder if making that one change would address some of the oddities … and hopefully low chance of bork’ing things up!
Wow, I just saw this in action in multiple circumstances in a circular, twin-ring galaxy. Thanks to all for shedding light on the subject. Clearly the solution is for all values in NP to be displayed in binary.