Solving the mystery: Unit Maintenance

Status
Not open for further replies.
Nice work cww256!

Whatever is the formula it sucks..

Worker costs the same as GDR?
Free support for maximum 2 units?
only every second unit increase the support cost?
The support cost raise is not always consistent (like in turn 100, 7->8; +3gold- 9->10; +2 gold- 11->12; +3 gold (It can be rounding of course, but it suggests an overcomplicated formula)
 
Code:
Turn 1			Turn 100		Turn 200		Turn 300	
Units	Expenses	Units	Expenses	Units	Expenses	Units	Expenses
0	0		0	0		0	0		0	0
1	0		1	0		1	0		1	0
2	1		2	2		2	4		2	6
3	1		3	2		3	4		3	6
4	2		4	5		4	9		4	14
5	2		5	5		5	9		5	14
6	3		6	8		6	14		6	22
7	3		7	8		7	14		7	22
8	4		8	11		8	19		8	30
9	4		9	11		9	19		9	30
10	5		10	13		10	24		10	38
11	5		11	13		11	24		11	38
12	6		12	16		12	30		12	47
13	6		13	16		13	30		13	47
14	7		14	19		14	35		14	55
15	7		15	19		15	35		15	55
16	8		16	22		16	41		16	64
17	8		17	22		17	41		17	64
18	9		18	25		18	46		18	73
19	9		19	25		19	46		19	73
20	10		20	28		20	52		20	82
21	10		21	28		21	52		21	82
22	11		22	31		22	57		22	91
23	11		23	31		23	57		23	91
24	12		24	34		24	63		24	100
25	12		25	34		25	63		25	100
26	13		26	37		26	68		26	109
27	13		27	37		27	68		27	109
28	14		28	40		28	74		28	118
29	14		29	40		29	74		29	118
30	15		30	43		30	79		30	127


Great job!

Well, first it seems that costs are roughly linear with the number of units, with a factor of about 2.1-2.6 with every doubling of the # of units. It's not clear if the deviations are rounding issue, or truly part of the formula. But it seems inconsistent if it's intended.

For example, taking the 30 unit numbers and dividing by 15 units for the same time period, we get about 2.3. Doing so for the 10 units over 5 units cost, we get about 2.6. But there's a reason for that. Since the cost only goes up every second unit, the first number (10 units) is when the costs went up. Having 5 units did not increase cost compared to 4. So that is why we get 2.6. This effect is larger at smaller numbers.

To be consistent, we should compare when both numbers are mod 2 =1 or mod 2 = 0. So examples are 16 vs 8 units, or 20 vs 10. These cases consistently give a factor of about 2.15 for doubling the # of units. So it is consistent.

There may be some time dependence, as

The time change is more difficult as it's non linear. Dividing the cost for the same number of units across different times, it looks like the cost actually SLOWS over time.

At 30 units: 0 turns to 100 turns gives a factor of 2.87, but 100 ->200 is 1.84, and 200 -> 300 is 1.61.

That's it for now. I'll do some more analysis later.
 
Firaxis should make a big patch which ads a game option for turning on fixed maintenace prices for every unit type, because this system, if you can call it that way, is a uncontrollable exercise in frustration.
 
I simplified the system provided by cww256 in order to make a rule of thumb I could use while I play. Therefore, I ignored the pair thing (which really doesn't affect linearity) and a 3-4$/turn discount you probably get after a few more hundred turns (400+).

The maintenance per unit is constant with the unit number. It increases as a power 2 function with turn number:

Maintenance per unit = 2E-5 * turn² + 0,0077 turn + 0,5 (ugly formula)

This is not so easy to manipulate in-game, so instead you can just remember this empiric rule:

At turn 1, Maintenance per unit is 0,5$
At turn 70, Maintenance per unit is 1$
After turn 100, Maintenance per unit is about 1,4$ per every 100 turns

I guess I'll just remember the milestones:

Turn 70: 1$
Turn 140: 2$
Turn 210: 3$
Turn 280: 4$
etc.

This is super simplified, but it fits easily most of the values compiled by cww256.

EDIT: 2 graphs that show the real deal without approximations (except I chopped the odd unit number values):

civanalysis.jpg
 
of all the things to be complicated... i don't understand why unit maintenance is one of them... this unit cost blah gold per turn and that's it... maybe changes according to unit's level and area occupying... in your own empire=cheap... friendly=normal... neutral=costly... enemy=really expensive...
 
Pouf, I like this:

Turn 70: 1$
Turn 140: 2$
Turn 210: 3$
Turn 280: 4$

Good rule of thumb. Depending on the change with a patch, let's see if this adjusts, but it's a good way to take a complicated formula, but still plan ahead.
 
There's another thread with info about upcoming changes in a future patch at http://forums.civfanatics.com/showthread.php?t=391028. One of the changes is:
"Economy - Fixed bug where players could disband a single unit, and not see the economic return until disbanding 1 more".

So there really is a bug with the formula...

There is a bug, but I believe that it is unrelated to the data I produced.

The bug occurs when you disband a unit (specifically an even numbered unit) and see no change in your unit expenses. I have had this happen to me in actual games, but not in any testing with adding and removing units with the tuner.

I expect the bug is related to the act of disbanding of the unit rather than the calculation of unit costs. I guess well see when the patch comes out :).
 
of all the things to be complicated... i don't understand why unit maintenance is one of them... this unit cost blah gold per turn and that's it... maybe changes according to unit's level and area occupying... in your own empire=cheap... friendly=normal... neutral=costly... enemy=really expensive...

I agree that the formula seems complicated, although Pouf seems to have simplified it a good bit, but I have not noticed any factors involving unit level, age, location, or type in any of the testing I have done.
 
First post ;)
But I've done quite some legwork for it.
The formula form for any turn is in the form:
C = B * N ^ P
Where
C: Unit maintenance cost
B: Base coefficient
P: Power coefficient

Result is rounded down (in-game C=Floor(BN^P))

Both B and P are changing every turn. The power coefficient is changing in a linear way, the base coefficient isn't (I could not find a good fit for either quadratic, power, logarhitmic or linear function.... It could be approximated well with a higher-order polynomial, but that's cheating).

The formula for P:
P=1+p*T
Where
p: coefficient in range 2,84868526E-4<p<2,859962634E-4
T: game turn for Standard speed

(I've also took some quick data for Marathon game speed. It seems like turn 300 for Marathon corresponds to turn 100 on Standard. This was just a very fast check, so I can't give any accuracy data for this - just thought I'd put it down, in case anyone is interested.)


I could not find a good formula for B, but I can give the ranges, where it must lay:
Code:
Turn	MinBase         MaxBase
0	0,5000000000	0,5000000000
100	1,2847900738	1,3129769180
203	2,2140351563	2,2307128059
250	2,6603125000	2,7106609715
327	3,4555534668	3,4713468137
432	4,6845312500	4,6975000000
The reason for the odd Turn numbers is that I had existing savegames on those turns, so it was the least work to start from there. I took data points at 6,8,10,12,14,16,18,20,70,128,194 units. I took more data at lower numbers to help with fitting - to limit the rounding error. For turns 203 and 432 I also took a data point for 454 units, so the coefficients there are better defined.

To test the accuracy, you can use the B,P pairs below:
Code:
Turn   Base Coef  Power Coef
0      0,50000    1,00000
100    1,31000    1,03150
203    2,21800    1,05790
250    2,67000    1,07150
327    3,46200    1,09370
432    4,68500    1,12353

I hope someone can find a good function to fit B. So we could get an exact formula for any turn.
 
Giving the cubic fit for B:
B=a+b*T+c*T^2+d*T^3
Where:
a: 0,5
b: 7,8467E-3
c: 2E-6
d: 5,2317E-9
T: game turn for Standard speed

Goes with:
P=1+p*T
Where:
p: 2,859E-4
T: game turn for Standard speed

So put together - the function should match the unit maintenance cost exactly in between turns 0..432 and 0..194 units.

C=Floor[ (a+b*T+c*T^2+d*T^3)*N^(1+p*T) ]
Where:
a: 0,5
b: 7,8467E-3
c: 2E-6
d: 5,2317E-9
p: 2,859E-4
N: number of units
T: game turn for Standard speed

Using the example above - cost for 127 units in turn 265:
C=Floor [(0,5+7,8467E-3*265+2E-6*265^2+5,2317E-9*265^3)*127^(1+2,859E-4*265)]
C=Floor [2,8172*127^1,0757635]
C=Floor [2,8172*183,314]
C=Floor [516,43]
C=516

I don't think anyone wants to go calculate these things by hand.
But the gist is:
at turn 0, 1st, 1000th and 100000th unit costs exactly the same = 0,5 gold.
at any other turn, 1st unit is cheapest, every further unit is a bit more expensive,
for each passing turn, the difference between first and every further unit gets bigger.

Example : Turn: 6Units - Cost - Cost per unit // 194Units - Cost - Avg. cost per unit
T0: 3g (0,5) // 97g (0,5)
T100: 8g (1,3) // 295g (1,5)
T250: 18g (3,0) // 754g (3,9)
T432: 35g (5,8) // 1742 (9,0)

If someone finds a better fit (simpler) function for B, please share.

About the fix - it will only change the mixup where only every second unit was affecting maintenance, nothing is said about chaning the bizzare maintenance calculation....
Fireaxis really should come out clean on what the formula for unit maintenance is... I understand the logic of it, but it really shouldn't be kept away from the players. All this regression fitting I had to do should not be required :/
 
Edit: I didn't realize StPeter solved this already, making my post moot (especially since I couldn't solve it). I'll just leave it in a spoiler box. :p

Spoiler :

I'm by no means a mathematician, but I've been fiddling with Excel trying to figure this out (using cww256's values). My numbers are crazy long (20 digits) and even then I don't find them to be an acceptable fit. I'm pretty much posting this in the hopes it gives someone an idea or at least know what not to try. :lol:

I'm under the assumption that the relationship between unit maintenance and unit number in any given turn is linear (y = mx + b), while the relationship between m (also b) and a given turn is a cubic function (y = ax^3 + bx^2 + cx + d), with both m and b having different values for a, b, and c. These are big assumptions, I know.

So I have....

Unit Maintenance = m * (Unit Count) + b

where...
Unit Count = # of units, even number (round down if necessary)
m = a(Turn Count ^ 3) + b(Turn Count ^ 2) + c(Turn Count) + d
b = w(Turn Count ^ 3) + x(Turn Count ^ 2) + y(Turn Count) + z
a = 1.84774123523232 * 10^-08
b = 4.87158099588671 * 10^-06
c = 8.56277320763297 * 10^-03
d = 4.91428948032809 * 10^-01
w = -1.30350464430793 * 10^-08
x = 3.52305933497015 * 10^-05
z = 1.07274556807765 * 10^-02

So how do these crazy numbers compare to actual values provided, you may ask? You can see this screen shot to find out:

Spoiler :
attachment.php

c.turn is calculated unit maintenance for that turn, a.turn is actual unit maintenance for that turn, and d.turn is the difference between the two values. At the bottom it shows the largest difference, smallest difference, and average difference for each turn. The number on the far right is an overall average of the difference for each turn. As you can see, no issue for turn 1, semi-close for turns 100 and 200, but it's as far off as -7 gold for turn 300. Oh well, gave it my best shot.
 

Attachments

  • UM Calculations.png
    UM Calculations.png
    33.2 KB · Views: 6,757
I am 100% convinced that they did NOT use a second or third order polynomial function to modelize the unit maintenance...

Obviously you could fit any random series with a 10th order polynome but the terms won't mean anything.

I'm thinking something like

Total Maintenance Cost = (a * Unit count)^(b + c * Turn number)

With (b + c * Turn number) very close to 1.
 
I agree that the dudes likely did not use a polynomial.
However, the form
Total Maintenance Cost = (a * Unit count)^(b + c * Turn number), where a,b,c are constants, cannot fit the data. That is a fact.
Hope you can find a nicer function though.

Lemme dump some raw data for you here - hope you can work with it.

Units Turn Maintenance
6 0 3,00000
8 0 4,00000
10 0 5,00000
12 0 6,00000
14 0 7,00000
16 0 8,00000
18 0 9,00000
20 0 10,00000
70 0 35,00000
128 0 64,00000
194 0 97,00000
6 100 8,00000
8 100 11,00000
10 100 13,00000
12 100 16,00000
14 100 19,00000
16 100 22,00000
18 100 25,00000
20 100 28,00000
70 100 103,00000
128 100 192,00000
194 100 295,00000
6 203,00000 14,00000
8 203,00000 20,00000
10 203,00000 25,00000
12 203,00000 30,00000
14 203,00000 36,00000
16 203,00000 41,00000
18 203,00000 47,00000
20 203,00000 52,00000
70 203,00000 198,00000
128 203,00000 376,00000
194 203,00000 584,00000
454 203,00000 1436
6 250 18,00000
8 250 24,00000
10 250 31,00000
12 250 38,00000
14 250 45,00000
16 250 52,00000
18 250 59,00000
20 250 66,00000
70 250 253,00000
128 250 483,00000
194 250 754,00000
6 327,00000 24,00000
8 327,00000 33,00000
10 327,00000 42,00000
12 327,00000 52,00000
14 327,00000 62,00000
16 327,00000 71,00000
18 327,00000 81,00000
20 327,00000 91,00000
70 327,00000 360,00000
128 327,00000 697,00000
194 327,00000 1099,00000
6 432 35,00000
8 432 48,00000
10 432 62,00000
12 432 76,00000
14 432 90,00000
16 432 105,00000
18 432 120,00000
20 432 135,00000
70 432 554,00000
128 432 1092,00000
194 432 1742,00000
454 432 4528

Gl&Hi5! ;)
 
You guys do realise there are these params in the xml? Sorry if this has already been posted - I haven't read the entire thread

Code:
<Row Name="INITIAL_GOLD_PER_UNIT_TIMES_100">
			<Value>50</Value>
		</Row>
		<Row Name="INITIAL_FREE_OUTSIDE_UNITS">
			<Value>3</Value>
		</Row>
		<Row Name="INITIAL_OUTSIDE_UNIT_GOLD_PERCENT">
			<Value>0</Value>
		</Row>
		<Row Name="UNIT_MAINTENANCE_GAME_MULTIPLIER">
			<Value>8</Value>
		</Row>
		<Row Name="UNIT_MAINTENANCE_GAME_EXPONENT_DIVISOR">
			<Value>7</Value>
		</Row>
Is there any way you can fit those into a formula that explains the result?
 
Yup, I know about the settings. My first approach was trying to find if the values are used in some .lua, so I could avoid doing all that work. But the actual maintenance stuff seems to be done in "CvGameCoreDLLFinal Release.dll". So no luck there.
Reverse-engineering how the parameters fit into the equation atm is possible for the power part, the base coefficient part is in a :):):):) state atm, as I've just put a poly stub there to at least make the calculation possible - but it is in no way a solution.
One thing will be true even for poly though - "a" coef. of the poly is always going to be the base unit cost - a: 0,5.
Atm I've got a few other things I'd like to do, so I won't be doing this though.
 
<Row Name="UNIT_MAINTENANCE_GAME_MULTIPLIER">
<Value>8</Value>
</Row>


I changed this value to 1 and have no trouble with this issue anymore
 
Lemme dump some raw data for you here - hope you can work with it.

Gl&Hi5! ;)

The data can be fitted by c(t,n) = ((0.5 + 8/1000 t) n)^(1 + 2/7000 t)

Will give some thought to analysing this later. Cheers.
 
Status
Not open for further replies.
Back
Top Bottom