XP\levelup Formula help request

Tlalynet

Emperor
Joined
Aug 24, 2007
Messages
1,048
I want to set the normal Levelup thresholds to 1/3/6/10/15/21/28/36/45/55 ect... (XP to previous level+level) but I'm drawing a blank as to what formula would accomplish it. Since XP to levelup is generated on the fly and there is no XP table to call I know I need some kind of algorithm. Perhaps there isn't a simple way to do it, but I wanted to ask here because I can't help but feel like I'm overlooking the obvious.
 
The calculation for this is done in the Python code, in the CvGameUtils.py file.
Look for the function getExperienceNeeded().
If you know a bit of Python it should be easy to modify.
 
I think that the OP requested the actual algorithm. I only wish I wasn't so completely useless at math! :p
 
you can code is recursiv

Code:
int ExperienceNeeded(int Level)
{
    if(Level<=0)
    {
        return 0;
    }
    else if(Level==1)
    {
        return 1;
    }

    return Level+ExperienceNeeded(Level-1);
}
 
I think that the OP requested the actual algorithm.


OOps, sorry :blush:

you can code is recursiv

Code:
int ExperienceNeeded(int Level)
{
    if(Level<=0)
    {
        return 0;
    }
    else if(Level==1)
    {
        return 1;
    }

    return Level+ExperienceNeeded(Level-1);
}

But the current formula is already in Python... unless you specifically want to do it in the SDK.

And anyway, there's no need to use recursion.

Don't use recursion, especially in Python, for a function which is called as often (for every unit at least once a turn).

For starters, you could use a list with the values you want (just create a list with 20 values. It should be enough. You don't have to calculate it on the fly.

But you can:
The differences sequence is an arithmetic sequence:

PHP:
  2   3   4    5     6
1   3   6   10   15   21

So the n'th element in your sequenceis the first element (1) + the sum of the first (n-1) elements in the differences sequence, which is given by:
f47ba2948d0dd572fd084dfe621a6924.png


So you can use this function:
Code:
def experienceNeeded(nLevel):
	if (nLevel <= 0):
		return 0
	
	# 1 is because this is the level for the first level.
	a1 = 1
	# 2 is the first difference
	b1 = 2
	# The difference of the differences sequence
	d = 1
	return int(a1 + ((nLevel-1) / 2.) * (2 * b1 + (nLevel-2) * d ) )

Or translate it to C++ if you prefer.
 
OMG I think me top just blew off just looking at that crazy math! :eek2:
 
Thanks Sephi, thats a functional way of doing what I wanted and along the lines of what I was thinking, but I agree with Asaf

Don't use recursion, especially in Python, for a function which is called as often

If it can be avoided.

Now lets see,

The back half of the formula simplifies to 2+iLevel in this case. So I got the line:

iExperienceNeeded = (((iLevel-1)/2)+1) * (2 + iLevel)

Sadly, while this formula works in reality like this

1*3=3
1.5*4=6
2*5=10
2.5*6=15
3*7=21
3.5*8=28
ect.

It works in python like this

1*3=3
1*4=4
2*5=10
2*6=12
3*7=21
3*8=24
ect.

It took me about half an hour to figure out what the problem with the wonky numbers was. Dang rounding.

My solution was to multiply the level by 10, then divide by 10 at the end, so

iExperienceNeeded = ((((iLevel-1)*10)/2)+1) * (2 + iLevel)/10

Which was almost right, but I left an obvious error in the code

iExperienceNeeded = ((((iLevel-1)*10)/2)+10) * (2 + iLevel)/10

Accomplishes the task perfectly.

Thank you very much Asaf, and thanks to you too Sephi, (I may plug this into wildmana for kicks sometime, but it would be imbalanced.)

If anyone has a better solution to the rounding problem than multiplying by ten and dividing by ten each time let me know, but its functional and not very wasteful even on a larger map, so its good enough for now.

Now to tweak the XP giving things in the game to suit this.
 
You can convert a calculation into floating point by using a float as one of the operands - thus avoiding integer rounding. Then wrap the whole thing into a int() function to get a integer output.

Rounding to the nearest integer can be achieved by adding 0.5 to any floating point value prior to converting it into a integer. Rounding up can similarly be achieved by adding 0.99.
 
iExperienceNeeded = (((iLevel-1)/2)+1) * (2 + iLevel)

Sadly, while this formula works in reality like this

1*3=3
1.5*4=6
2*5=10
2.5*6=15
3*7=21
3.5*8=28
ect.

It works in python like this

1*3=3
1*4=4
2*5=10
2*6=12
3*7=21
3*8=24
ect.

It took me about half an hour to figure out what the problem with the wonky numbers was. Dang rounding.

You didn't use the code as given.

You left out the "." after the 2 and then surrounding int() function, which would have given you this:
Code:
iExperienceNeeded = int((((iLevel-1)/2.)+1) * (2 + iLevel))
This should give you the expected results.

The "2." instead of "2" makes the entire thing use floating point math. The int() then converts it back to an integer. That way the rounding is done after everything else, especially the multiplication.
 
It works in python like this

1*3=3
1*4=4
2*5=10
2*6=12
3*7=21
3*8=24
ect.

You didn't use the code as given.

You left out the "." after the 2 and then surrounding int() function, which would have given you this:
Code:
iExperienceNeeded = int((((iLevel-1)/2.)+1) * (2 + iLevel))
This should give you the expected results.

The "2." instead of "2" makes the entire thing use floating point math. The int() then converts it back to an integer. That way the rounding is done after everything else, especially the multiplication.

:yup: What God-Emperor said.
 
Its true, I never did use the code as given, but translated the equation over into what I needed so I wouldn't define nLevel and the other variables. I thought there may be a purpose to the ., but the first time I put the code in action it killed the user interface so I cut out anything that looked like it may be extra, including the extra decimal point.

Thank you very much Baldyr, God-Emporer, and Asaf, I got a bit of python knowledge and a new formula out of this. I doubt there can be any improvement on God Emperors code so I'm just going to copy it if you don't mind.
 
Actually, isn't the Int() pointless in this case? The end result will never need rounding.
 
Since iExperiencedNeeded is a integer variable it should point to a integer value and not a floating point value. And I suspect you're gonna use the variable as a parameter in some method sooner or later, and I doubt it accepts a float.

In short: You should use int(). Integer rounding is just a side-effect of the conversion from float to int.
 
Back
Top Bottom