Iustus
King
I have been poking around the AI code myself, just trying to get a handle on what it does.
I found something in AI_foundValue (in CVPlayerAI.cpp), which I think could stand a change. This routine is used to evaluate locations to found a new city.
line 1527 (near the end):
this will always ignore at least one bad tile, and, I think, tend to skew quite quickly away from the firaxis default. Might I suggest the following change?
First, this is the same code, but more readable:
Now, here is the agorithm change:
it also potentially has a divide by zero, unless none of your AI variables can be zero? If they cannot be zero, you 'could' change getAIVar(n) to (getAIVar(n)-1) and do the same for getAIVar(n+1), but that might have strange implications in your mutations, as a 0 or 1 value would be quite special.
Which brings me to a more fundamental point. There are many cases where two variables are quite interlinked. For example:
This is really just one variable, but a fractional one.
Have you considered making a more fundamental change and using floating point (or fractional) numbers for your AI variables? You could do this with near zero processing cost if you wanted, by integrating math functions into the lookup, creating fuctions like:
so the above would become:
where 8687 is the old 86 value divided by the old 87 value in a floating point (or fixed) number.
The function call overhead is going to be more than the math, so you will lose no time over just doing a lookup. In fact, it may be faster, becase it is one call, instead of two.
You might want to add a flag or two to pass, to invert one or the other parameters, and to specify the order.
Anyway, it is a thought, it would allow each variable to be truely unique. Currently, I would hazard to guess that upwards of 20% of your variables are related in this way, meaning that the ratio of the two is what is important, so values of 30 and 60 for the pair is the same as 300 and 600 for the pair. This could end up wasting a lot of generations and testing.
Actually, now that I think about this, I have another solution. Replace all the divisors by some fixed number that works well with the range of AI values. So, if your AI values can range from 1 to 1000, a good divisor might be in the 50-100 range. (The higher your max AI value, the safer it is to pick a divisor).
If the divisor is constant, then only one value is changing, and you do not have to make the floating point change. In effect, you are almost using fixed point numbers. In theory, you could even use different divisors in different places, but you probably want to at least have them be multiplied by some constant (I would suggest a constant in C, rather than reading a number from XML or some other variable, just for speed). Like so:
Going this way, the inital code changes to:
-Iustus
I found something in AI_foundValue (in CVPlayerAI.cpp), which I think could stand a change. This routine is used to evaluate locations to found a new city.
line 1527 (near the end):
Code:
iValue /= (max(0, (iBadTile - (NUM_CITY_PLOTS / getAIVar(90)))) + getAIVar(91)); // TGA | AutoGenFunction | v0.02 | 24 August 2006
this will always ignore at least one bad tile, and, I think, tend to skew quite quickly away from the firaxis default. Might I suggest the following change?
First, this is the same code, but more readable:
Code:
iTempValue = iBadTile - (NUM_CITY_PLOTS / getAIVar(90));
iTempValue = max(0, iTempValue);
iTempValue += getAIVar(91)
iValue /= iTempValue;
Now, here is the agorithm change:
Code:
iTempValue = (getAIVar(n) * iBadTile) - (getAIVar(n+1) * (NUM_CITY_PLOTS / 4));
iTempValue /= max(1, getAIVar(n+2)); // can remove max if AI var cannot be zero
iTempValue = max(0, iTempValue);
iTempValue += getAIVar(91)
iValue /= iTempValue;
it also potentially has a divide by zero, unless none of your AI variables can be zero? If they cannot be zero, you 'could' change getAIVar(n) to (getAIVar(n)-1) and do the same for getAIVar(n+1), but that might have strange implications in your mutations, as a 0 or 1 value would be quite special.
Which brings me to a more fundamental point. There are many cases where two variables are quite interlinked. For example:
Code:
iValue *= getAIVar(86); // TGA | AutoGenFunction | v0.02 | 24 August 2006
iValue /= getAIVar(87); // TGA | AutoGenFunction | v0.02 | 24 August 2006
This is really just one variable, but a fractional one.
Have you considered making a more fundamental change and using floating point (or fractional) numbers for your AI variables? You could do this with near zero processing cost if you wanted, by integrating math functions into the lookup, creating fuctions like:
Code:
int addAIVar(int value, int aiVarIndex)
int multiplyByAIVar(int value, int aiVarIndex)
int divideByAIVar(int value, int aiVarIndex)
int divideAIVarBy(int value, int aiVarIndex)
so the above would become:
Code:
value = multiplyByAIVar(value, 8687);
where 8687 is the old 86 value divided by the old 87 value in a floating point (or fixed) number.
The function call overhead is going to be more than the math, so you will lose no time over just doing a lookup. In fact, it may be faster, becase it is one call, instead of two.
You might want to add a flag or two to pass, to invert one or the other parameters, and to specify the order.
Anyway, it is a thought, it would allow each variable to be truely unique. Currently, I would hazard to guess that upwards of 20% of your variables are related in this way, meaning that the ratio of the two is what is important, so values of 30 and 60 for the pair is the same as 300 and 600 for the pair. This could end up wasting a lot of generations and testing.
Actually, now that I think about this, I have another solution. Replace all the divisors by some fixed number that works well with the range of AI values. So, if your AI values can range from 1 to 1000, a good divisor might be in the 50-100 range. (The higher your max AI value, the safer it is to pick a divisor).
If the divisor is constant, then only one value is changing, and you do not have to make the floating point change. In effect, you are almost using fixed point numbers. In theory, you could even use different divisors in different places, but you probably want to at least have them be multiplied by some constant (I would suggest a constant in C, rather than reading a number from XML or some other variable, just for speed). Like so:
Code:
#define TGA_DIVISOR 100
Going this way, the inital code changes to:
Code:
iValue *= getAIVar(86); // TGA | AutoGenFunction | v0.02 | 24 August 2006
iValue /= TGA_DIVISOR; // TGA | AutoGenFunction | v0.02 | 24 August 2006
-Iustus