HostedRedmine.com has moved to the Planio platform. All logins and passwords remained the same. All users will be able to login and use Redmine just as before. Read more...
Task #951985
openUsing granularity for move_fragments causes short int overflow in pathfinding functions.
0%
Description
Recently I'm challenged by issues in the movement system which, if my problems are tl;dr, go to section 2 to read about the actual bug.
Section 1. Granularity issues in Freeciv movement system.
If your ruleset has some move_fragments value setting like 6, 9, or 12, you get some strange maths phenomena artificially limiting what your ruleset can do. Let's take 9 frags for example, and a unit who has 2mp (18 frags)¶
Your road types can set their move_costs in such a way to travel the following distances:
[MOVE_COST OF ROAD IN FRAGS]: {TILE DISTANCE}
9 frags: 2 tiles (theoretic case of a road that only speeds movement on rough terrain)
6-8 frags: 3 tiles
5 frags: 4 tiles
4 frags: 5 tiles
3 frags: 6 tiles
2 frags: 9 tiles
1 frag: 18 tiles
0 frag: infinite tiles
For roads where you want distance of 2-9, you have a pretty nice spread of options. But then what happens?
10,11,12,13,14,15,16,17 are all impossible, and then the next jump from 18 is to infinity.
The jump from possible road of 9 distance to 18 distance is very similar to the granularity problems that come from, for example, Warrior A1, next best unit is A2 or DOUBLE the attack. If you're so used to this that you don't blink, imagine an Armor unit where you have to jump from A10 to A20 as the next best unit, and this is what I mean by granularity problem.
The way to solve granularity problems was solved long ago by the ancients, and it's just to increase the number-base you're working with. For example, Clubman A10, Axeman A12, Swordman A15, Horseman A20, etc.
And this is also how to solve the problem with roads. In move_frag 9 system, if my 2mp unit goes 9 tiles down road-type-A and I want to an upgraded road-type-B, I have to double the distance to 18. Then I hit a singularity problem where the next road after that is extreme imbalanced and OP: infinity. Of course, I can choose move_fragments to be a nice higher number, like a highly composite number, and I'm reinventing what the Babylonians and ancient navigators did with the base-60 or base-360, still used in time and directional measurement today!
Section 2. The overflow bug¶
This is where we start to regret someone thought he's saving 2 nanoseconds or 500 bytes, by using short int move_costs in the pathfinding.c and pftools.c. You see, we actually get less than a short int because there's a thing called
#define PF_TURN_FACTOR 65536
Now our move_fragments for move_cost, moves_left, total_mc, and so are getting multiplied by this 2-byte FACTOR which really means we're using HALF OF A SHORT INT. I will conclude quickly to say this causes int overflow and segfaults when using highly granular move_fragment systems, especially the one that my research revealed to be the most perfect one.
I unfortunately had to hack the entire move system to use long ints everywhere, to fix the segfault, but probably only needs to be done in a few places in pathfinding and pftools. However, when I tried that I must have missed a case and still got segfaults and after a day of hunting it and failing, I thought, F*** this, we have 64-bit CPU for a reason and we're gong to long int at FCW.
You can comment on it how you want but, I can make roads that go any distance from 1 to 120 without a single gap in between, and setting up a fraction reduced GCF and LCD system in client so you never see such crazy big fractions, it's child's play.
So, what will the official upstream response be to the overflow problem for rulesets wanting granularity?