Unofficial BTS 3.13 patch

Some good points glider, I agree with you that in terms of effect either B or what I proposed for C make the most sense. Here's my take on how they would be different:

Current -
City X considers city Y to be close if they're within 6 or 7 squares and the closeness measure is higher if Y has a higher population. As Yakk said, for player or team 1 their closeness measure to 2 is actually the measure of how close 2's cities are to 2's cities (this is the bug). Because of this bug, player/team 3 (and all other players) will have the same closeness measure to 2 as 1 does.

Fix A -
City closeness is the same as before. For player/team 1, they would consider player 2 close if 1 has a city of any size near large cities owned by 2.

Fix B -
City closeness is the same as before. For player/team 1, they would consider player 2 close if 2 has a city of any size near large cities owned by 1.

Fix C -
The city closeness measure would be highest when X and Y both have high populations, lowest if both are small. X's closeness to Y would be the same as Y's closeness to X (unless one is owned by barbs ...). Because of this, it doesn't much matter whether summing is done like Fix A or B except in the case of barbs where I think it points to summing as in Fix B.

In terms of how these would effect other parts of the game, here's what I can see:

CvCityAI::AI_cityThreat - (determines how "threatened" a city feels, used to compute whether the city needs extra defenders nearby)
Right now, a city feels more threatened if the cities around it are larger. Since it's just city based, current performance would be unaffected by Fix A or B (which only change how CvPlayerAI and CvTeamAI are computed). Fix C would change this so that a larger city would feel more threatened by other cities than a smaller city would.

CvPlayerAI::AI_conquerCity - (decide whether to raze a conquered city)
The closeness of a conquered city to the rest of the player's empire lowers the odds that it will be razed. Again, this just uses CvCityAI::AI_playerCloseness so it is unaffected by Fix A or B. For Fix C a player would be a bit less likely to raze a large city close to small cities in their empire and a bit less hesitant to raze small cities near large cities in their empire. The change here looks to be quite small in magnitude.

CvPlayerAI::AI_getStrategyHash - (determine which strategies a player follows)
CvTeam::AI_teamCloseness used for Crush strategy, but this only checks if closeness is > 0. I believe since it's just > 0, Fixes A, B, and C will all be equivalent and different than the current bugged method which is never 0 (can't not be close to yourself). Also used for the Peace strategy which is not actually implemented, so no real effect there.

CvTeamAI::AI_startWarVal - (used to pick which other team to declare war on)
The current method effectively uses the other team's self-closeness, so a target with many large, tight cities would be more appealing than a small or spread out empire regardless of how close they are to the attacker. Any of the fixes is a significant change from the current function, definitely dwarfing any difference between the fixes. That said, fix A would cause the AI to more often pick war against a player when the AI has a city (of any size) near big cities owned by the other player. For B it would be the reverse, the AI would attack a player who has a city near large cities that it owns. C is a middle ground, where war is most likely against the player with the most large cities near the larger cities of the AI's empire.

So, as you can see Fix C affects a couple of CvCityAI functions that the others do not ... it certainly is not purely a bug fix in that regard. That said, these extra effects would not be that large really and also seem entirely reasonable to me.

The real difference between the fixes is in choosing war victims, I would say we should pick a fix based on what makes the most sense for the AI in this regard. Based on the understanding I've described here I would order them C > B > A, but I look forward to hearing what the rest of you think.
 
In the case of CvTeamAI::AI_startWarVal, wouldn't it make more sense to sum up (separately) both the old value and the new way of considering the value.
Then startWarVal has 2 numbers to pick/decide between on its action.
Obviously the best option would be to actually add more AI code that takes into account the internal personality/preferences of the AI - so they can use the number that best reflects that. But even without doing extra AI code into the startWarVal - you can sum both the old way and the new way and pick one for an action by Chance.
I'm not sure though, seems like any significant change (which some of the suggestions are) will drastically affect whether an AI can be bribed into War or how it will manage its Empire on its own.
 
Now that I read all the discussion about the closeness function, I wonder if this is not a bug ,but a shortcut way of saying to the AI " Attack the enemy core instead of trying to catch strayed cities" ( high pop clustered cities= empire core in my book.... ), but really badly implemented. Maybe adding ( or multiplying ? :dunno: ) the today closeness with one of the corrected version ( jdog Fix C ? ) would do the trick?
 
glider1 said:
The for-loop construction using the macro GET_PLAYER (thanks Yakk) is so common in the BTS code. The design of the function:
int CvPlayerAI::AI_playerCloseness(PlayerTypes eIndex, int iMaxDistance)
would surely have been intended utilising that standardised for-loop construction. I cannot imagine that all of the coders and quality control would have opted for the option A non-standard for loop construction. It just looks "different" and would have raised questions.

Looping over your own cities ... doesn't require the GET_PLAYER macro, because the CvPlayer object already has access to the CvPlayer object. :)

GET_PLAYER is common because you are often iterating over every player, or have passed the player ID in as an argument that you want to iterate over.

...

What I find most illuminating is the Barbarian closeness code in CvCityAI:

Code:
if (pLoopCity->isBarbarian())
{
	iTempValue /= 4;
}

Ie, if the other city is a barbarian, divide closeness by 4.

This makes me think we should iterate over _our_ cities, and consider Barbarian cities to be 4 times less close than they are. (as opposed to looping over their cities, and Barbarians considering all civilizations to be 4 times less close than they are... heh)

...

The concern with adding both city sizes is that it changes the magnitude of the closeness parameter, especially in the late game with large cities.

This could cause over-commitment of defending troops. :/

...

So, I'm saying that:
Code:
for (pLoopCity = firstCity(&iLoop); pLoopCity != NULL; pLoopCity = nextCity(&iLoop))
{
	iValue += pLoopCity->AI_playerCloseness(eIndex, iMaxDistance);
}
is the right answer.

The in-game effect is that the AI tries to cherry pick large cities that are close to territory they already control.

...

Note that Closeness also scales linearly with distance. :) (it isn't just 20+sum of city populations). And in the early game, the "city population" factor is rather small.
 
Now that I read all the discussion about the closeness function, I wonder if this is not a bug ,but a shortcut way of saying to the AI " Attack the enemy core instead of trying to catch strayed cities" ( high pop clustered cities= empire core in my book.... ), but really badly implemented. Maybe adding ( or multiplying ? :dunno: ) the today closeness with one of the corrected version ( jdog Fix C ? ) would do the trick?

Closeness doesn't determine where to attack someone, only which player to start a war against. Once the war is started, picking a target city is a separate action (CvPlayerAI::AI_targetCityValue among others). Regardless, it's clear from other uses apart from startWarVal (in addition to the name) that it was meant as a measure of proximity. I think the strategic value of picking a war against a nearby player instead of a war against a large, packed empire is pretty clear.
 
What I find most illuminating is the Barbarian closeness code in CvCityAI:

Code:
if (pLoopCity->isBarbarian())
{
	iTempValue /= 4;
}

Ie, if the other city is a barbarian, divide closeness by 4.

This makes me think we should iterate over _our_ cities, and consider Barbarian cities to be 4 times less close than they are. (as opposed to looping over their cities, and Barbarians considering all civilizations to be 4 times less close than they are... heh)

Yes, definitely.

The concern with adding both city sizes is that it changes the magnitude of the closeness parameter, especially in the late game with large cities.

This could cause over-commitment of defending troops. :/

I disagree, the difference between 2*(pop of city1) and (pop of city1 + pop of city2) is 0 on average I believe. This doesn't mean it's the right approach, but it doesn't disrupt the expected magnitude of the parameter.

So, I'm saying that:
Code:
for (pLoopCity = firstCity(&iLoop); pLoopCity != NULL; pLoopCity = nextCity(&iLoop))
{
	iValue += pLoopCity->AI_playerCloseness(eIndex, iMaxDistance);
}
is the right answer.

The in-game effect is that the AI tries to cherry pick large cities that are close to territory they already control.

I agree that that's the way the loop was intended, the barb city bit makes it pretty conclusive. Any other changes would go beyond bug fixing and into AI modifications which is not in the scope of the unofficial patch.

That said, the difference from that small change is serious ... here's the first few steps of CvPlayerAI::AI_startWarVal:

Code:
	iValue = AI_calculatePlotWarValue(eTeam);

	iValue += (3 * AI_calculateCapitalProximity(eTeam)) / ((iValue > 0) ? 2 : 3);
	
	int iClosenessValue = AI_teamCloseness(eTeam);
	if ([B]iClosenessValue == 0[/B])
	{
		[B]iValue /= 4[/B];
	}
	iValue += iClosenessValue / 4;

(There's a bit more to this function, but this is really the meat of it)

Previously only a team with no cities would ever return a closeness value of 0, so the conditional divide by 4 would never happen (side note: this is further evidence that it's a bug and not some poorly named bit of logic). Now, any team with no cities within 6 or 7 tiles of this team's cities will get a 0 and have their value divided by 4.

One of the next steps in the function is to apply a multiplier based on attitude:

Code:
	switch (AI_getAttitude(eTeam))
	{
	case ATTITUDE_FURIOUS:
		iValue *= 16;
		break;

	case ATTITUDE_ANNOYED:
		iValue *= 8;
		break;

	case ATTITUDE_CAUTIOUS:
		iValue *= 4;
		break;

	case ATTITUDE_PLEASED:
		iValue *= 2;
		break;

	case ATTITUDE_FRIENDLY:
		iValue *= 1;
		break;

	default:
		FAssert(false);
		break;
	}

The division by 4 which we will be effectively introducing is equivalent to a change of two steps on the attitude scale ... all other things being equal, the AI will now give a higher value to a civ with any closeness value > 0 whom they're Pleased towards than they would give to a civ they're Annoyed with who is 8 tiles away!

Now this is not the only place where attitude is used in determining who to attack, there's also CvTeamAI::AI_noWarAttitudeProb which probabilistically reduces the chance of even checking AI_startWarVal for teams with which the AI has good relations (depends on leader personality). Nonetheless, the effect of closeness on AI war decisions as seemingly intended has never been tested in game ... to a large extent we're into modifying the AI territory already just by fixing the bug.
 
I'm not sure though, seems like any significant change (which some of the suggestions are) will drastically affect whether an AI can be bribed into War or how it will manage its Empire on its own.

The startWarVal is not used by diplomacy code, changes we make here will not affect bribe costs at all. Bribe costs are handled in CvTeamAI::AI_declareWarTradeVal which has its own methods of determining value and doesn't involve closeness at all. The startWarVal is only used in a section of AI_doWar which starts with the comment "if no war plans, consider starting one!" ... the effect on this picking of a new war to start is definitely significant.
 
So I wasn't delusional when I said that the AI doesn't seem to be attacking its direct neighbors any more than someone far away. And the fanbois all told me I was an idiot.

Well Duuk, find the truth for yourself is the lesson!

Preliminary results from my end is showing that this "closeness" thing is Big. Real Big! The nature of the game has transformed no question. It's too early to say about the balance of the game. I've run say three tests of A,B,C and vanilla on the same map under the same starting conditions simply swapping the DLL over before launching.

Here are my starting conditions:
18 civs on a standard temperate Pangaea map all options standard. I've deliberatly made it crowded so as to get some action happening sooner rather than later. You would expect warfare in a stressed out crowded world of civs yes?. The first 120 turns are conducted on auto-play with no human intervention.

1) Either option A, B, of C make regional warfare much more dominant in the first 120 turns of a standard game. There are more wars too and most if not all have some regional component to their declaration. The only exception to regional war declarations is when a non-neighbour civ is dragged in because of diplomatic reasons (this is not absolutely certain).

2) Vanilla is like sitting in the park watching the flowers grow! Warfare in the first 120 turns is much less likely (one short war compared to five-six). Remember that this is a crowded map!

3) Interestingly, option A and B produce the same war declarations in the first 120 turns (better triple check this because this is questionable)

4) Interestingly, option C is actually a middle ground between A and B producing less wars than A or B but more than vanilla.

5) When a war does happen, the result of the war is purely tactical and the outcome can vary dependant on how the AI deploys it's army. There is no weight in the outcome because of option A or B. So far from what I can see, the AI tactical battle seems reasonable and not "unbalanced". That is the big question of course. Will a human crunch the AI under option A, B or C?......So far the experiment in my mind is to test option A and B from the perspective of them being potential "bug fixes".

@Yakk - Back to option C for a moment (technically this should be discussed on another forum). Regarding late game overdefending because of how threatened a city is. How is:
pLoopCity->getPopulation() + getPopulation()
worse than:
pLoopCity->getPopulation() * 2?

It must be a distribution of values issue in the "closeness" array with more bias towards being threatened? It's got to be a small effect yes?

@Jdog
What I'm confused about with option C is this:
"Fix C would change this so that a larger city would feel more threatened by other cities than a smaller city would." This verbally translates:
pLoopCity->getPopulation() + getPopulation()
There's something wrong about this reality yes? Small cities are under greater threat? But no because big cities have more to loose from being intruded upon? Help me I'm confused.

I don't have any data capacity left this month with my ISP so I literally cannot share the three DLL's for the fanatics to test this for themselves. Could someone else do it?

Cheers.

PS) Thanks Jdog and Yakk for some excellent clarification work converting the reading of the code into human language us non-specialists can understand.
 
Code:
20 + pLoopCity->getPopulation() * 2;
D'oh! I forgot about that *2. :)

If we want to be paranoid about making nearby wars too tempting, we could reduce the divisor to /= 2?

Then again, would you as a player consider going to war with a civilization that wasn't adjacent to you that often?

There are two obvious AI improvements.

First, increase the radius we do closeness under the doWar calculation.

Second, do "transitive" war checks. If we are friendly with open borders with close civilization A, then check closeness between A and civilization B to generate a "leapfrog" war plan.

The first could be considered a bug fix (now that it is live, the "ignore civilizations more than 6 away" code might be overkill, heh), the second would be adding features. :)

Increasing MaxDistance does cause some increased computational load. Each city ends up calculating:
Code:
int iPathDistance = GC.getMap().calculatePathDistance(plot(), pLoopCity->plot());
which is an inter-city pathing calculation.
 
@Jdog
What I'm confused about with option C is this:
"Fix C would change this so that a larger city would feel more threatened by other cities than a smaller city would." This verbally translates:
pLoopCity->getPopulation() + getPopulation()
There's something wrong about this reality yes? Small cities are under greater threat? But no because big cities have more to loose from being intruded upon? Help me I'm confused.

Cool, I'm glad you're running some tests to try things out in game! That's the most important thing really.

As for city threat measures, I'm not entirely sure I understand what you're asking. Here's a breakdown of how city closeness would be different under fix C (this isn't changed by A or B, they change how the sum of city closeness is calculated for a player) ... call the two cities we're comparing X and Y:

X low pop, Y low pop:
- Current: Low closeness both ways
- Fix C: Low closeness both ways

X high pop, Y low pop:
- Current: Low closeness of Y to X, high closeness of X to Y
- Fix C: Mid closeness for both

X low pop, Y high pop:
- Current: High closeness of Y to X, low closeness of X to Y
- Fix C: Mid closeness for both

X high pop, Y high pop:
- Current: High closeness for both
- Fix C: High closeness for both

The real differences are when there is a big disparity in population between X and Y. With the current method, a big city owned by player 1 near a small outpost of player 2 doesn't feel very threatened while player 2 would consider themselves close to player 1 and thus be more likely to declare war on player 1. Fix C makes it so closeness works the same for both X and Y. This is one reason why I think C is the way to go.

I don't have any data capacity left this month with my ISP so I literally cannot share the three DLL's for the fanatics to test this for themselves. Could someone else do it?

I'll do that this evening unless someone beats me to it.
 
This is pretty interesting, and not to rain on the parade. But Bhuric's patch attempts to fix game-breaking bugs (for the most part). This should start its own thread; fork the current patch and go from there. There hasn't been any "outside" AI work done since betterAI was incorporated into BTS.

It would also be cool, if some of the "insiders" here, could get one of the Dev's to comment on what the functionality in question was meant to be. Then you wouldn't be operating so much in the dark with guess work.

Anyways just ma 0.02
 
Code:
20 + pLoopCity->getPopulation() * 2;
D'oh! I forgot about that *2. :)

If we want to be paranoid about making nearby wars too tempting, we could reduce the divisor to /= 2?

Then again, would you as a player consider going to war with a civilization that wasn't adjacent to you that often?

There are two obvious AI improvements.

First, increase the radius we do closeness under the doWar calculation.

Second, do "transitive" war checks. If we are friendly with open borders with close civilization A, then check closeness between A and civilization B to generate a "leapfrog" war plan.

The first could be considered a bug fix (now that it is live, the "ignore civilizations more than 6 away" code might be overkill, heh), the second would be adding features. :)

Increasing MaxDistance does cause some increased computational load. Each city ends up calculating:
Code:
int iPathDistance = GC.getMap().calculatePathDistance(plot(), pLoopCity->plot());
which is an inter-city pathing calculation.

Sneaky little 2x ... don't worry, you caught my bigger confusion about reading the code earlier ;)

I was thinking the same thing about changing the divisor to be /= 2 ... one possibility would be to use 4 for the Aggresive AI setting and 2 for regular, that way on Aggressive you'll get more backstabbing to make local territory gains. One of the impressions I have is that Blake tends to program for the Aggressive AI setting and isn't too fond of having the AIs "roleplay" so much as go for the win. To me /= 2 seems like a good middle ground for regular, while on Aggressive /= 4 might be more appropriate.

Another fix in the same area of the code I think needs to be made is just after that where:

Code:
	iValue += iClosenessValue / 4;

Back when closeness was self-closeness (like last week :p ), the value for a large empire was in the hundreds. Now that it's closeness between empires, values tend to be much smaller ... from what I've seen they're often < 10 but can be up to about 40 or 50 in the mid game. Seems to me like we should remove the / 4 since the values are now much smaller. For reference typical startWarVals for the mid-game are in the 500 - 1500 range from what I've seen, but that is after all the multiplying for attitude. I plan to test this more to see what seems reasonable, but certainly the magnitude of team closeness is a lot smaller now.

I also definitely agree with your thought to increase the range for checks, 6 or 7 is actually really short because it seems that the second check on distance using:

Code:
int iPathDistance = GC.getMap().calculatePathDistance(plot(), pLoopCity->plot());

uses only cardinal directions (ie tiles that are diagonally next to each other are at a distance of 2). This second check only happens for in the same area (ie not on nearby islands). Check me on this, but certainly when stepping through CvCityAI::AI_cachePlayerCloseness it seems like this bit cuts out a lot of cities that would otherwise be considered close and certainly look like neighbors to me ... ie, in the following mini-map, calculatePathDistance() appears to put X and Y at a distance of 8:

0000Y
00000
00000
00000
X0000

There's no actual space for another city between them, they should be neighbors I think and in fact the first distance check using stepDistance() says they are with a distance of 4 (diagonals), but is later overruled by calculatePathDistance().

Frankly, instead of increasing iMaxDistance we could just remove the calculatePathDistance() check. It currently reads:

Code:
	if (getArea() == pLoopCity->getArea())
	{
		int iPathDistance = GC.getMap().[B]calculatePathDistance[/B](plot(), pLoopCity->plot());
		if (iPathDistance > 0)
		{
			iDistance = iPathDistance;
		}
		else
		{

		}
	}

The empty else clause is really strange to me ... I don't think I've seen that anywhere else in the SDK. The first check for distance makes much more sense and works as it should IMO, this second one is suspect. To me, closeness should be based on how long it takes troops to move between the cities, and they can move on diagonals. I can't think of anything else in civ which works on just cardinal directions (not even fat-cross/cultural borders) ... calculatePathDistance() is only used is a couple of other places for evaluating distances in AI code, stepDistance makes 8x as many appearances. Perhaps this second check was supposed to take into account blockages by mountains or the availability of roads, but in practice it doesn't seem to do that at all. Please check this out and see what you think.

As for the leapfrog war idea, that seems like a bigger change and a bit hard to implement ... we'd need to first check whether we can easily get to the cities of the friendly team as they could be on another continent. If we were to try that out, I'd say we would want to start with Vassals first before Open borders. This new feature is definitely in the realm of a new "Beyond Better AI" mod or something like that though (which I know you're interested in Yakk and totally support as a separate experiment/development :) ).
 
CvCityAI::AI_cityThreat - (determines how "threatened" a city feels, used to compute whether the city needs extra defenders nearby)
Right now, a city feels more threatened if the cities around it are larger. Since it's just city based, current performance would be unaffected by Fix A or B (which only change how CvPlayerAI and CvTeamAI are computed). Fix C would change this so that a larger city would feel more threatened by other cities than a smaller city would.

EDIT: I have read Jdog's clarification in post 2230 so nothing more needs to be said.....
(I would love clarification on AI_cityThreat calculations on city defenders. The last sentence is important with regard to option C. I have to infer that the AI would prefer defending the bigger cities under option C. This is good and could be not good? Option-C is "better-ai" territory for sure.)

From what I see in game so far, one or other of option A or B could classify as a bug fix within this Bhruic forum. Even without changing the attitude scaling. I have not found a single case where there was a "pleased" disposition leading to a war declaration in option A. Even if it did happen in game, it's not necessarily a bug. I seem to remember playing civ4 prior to BTS and war declarations used to emerge out of "pleased" relationships. They would shock the human and were sometimes very damaging attacks. In the old days of civ4, I never encounted a war declaration from "friendly" only ever from "pleased". Therefore I am making the case that either A or B could still be thought of as a "bug fix".

That said, we do have a way forward now with a genuinely better-AI. "Big scale" testing needs to happen on this at some point. Either it would happen within Firaxis or within the context of a Better-AI mod. In that respect the only DLLS that are important for people to test at this stage are either the option A or option B dll. Which will it be?

I would love clarification on whether option A is good or option B is good. There has nothing been absolutely bullet proof solid for option A over option B either theoretically or practically. It seems to me that the option A point about barbarian/4 is not even rock solid proof. It is just circumstantial.

No-one has refuted my point about "strategy" yet. That is that option-A looks like having a much larger "tactical" component to it in the late game especially during colonisation and thus could impact detrimentally on AI behaviour late game. Option B does not seem to have this issue nearly as significantly. Without clarification, I will proceed with testing option A and B with respect to the later game although this is very slow and tedious and would be better sorted out through "logical inference".....

I'm starting to think that there might be a case for including option A AND option B as part of strategic choice threshold for the better-ai project. This would be where there is some condition placed on utilising option A or B based on "context". It was mentioned making it random for example. But in better-ai I'm sure there is a "better" way of deciding which "strategy" is best for a given civ.

For now I'm still thinking "bug fix" because there might be a genuine short cut to a better-richer game play experience straight off the bat without hundreds of hours of "beta" testing.
Cheers.
 
Calculate path distance should be calling into the DLL A* pathing module, and working out how far the real distance between the two is. A* pathing is a reasonably efficient way to work out the shortest path between two nodes.

Are you sure that calculatePathDistance sucks that much?

...

In any case, implementing the "holy crap, that was a bug" fix of "option B" (calculate closeness of each of the player's cities to each of the other player's cities, dividing by 4 if the other player is a barbarian). There will be an increased bias towards fighting locally, which is what the code is supposed to do.

Fine-tuning it is another issue entirely. At least one person has tested it, and found that it results in more closer wars between AIs, which is what it is supposed to do!
 
This is pretty interesting, and not to rain on the parade. But Bhuric's patch attempts to fix game-breaking bugs (for the most part). This should start its own thread; fork the current patch and go from there. There hasn't been any "outside" AI work done since betterAI was incorporated into BTS.

It would also be cool, if some of the "insiders" here, could get one of the Dev's to comment on what the functionality in question was meant to be. Then you wouldn't be operating so much in the dark with guess work.

Anyways just ma 0.02


Actually, this IS a bug. This explains why the AI doesn't ever have a chance at a conquest victory: Simply put, the AI doesn't understand that attacking your neighbor is better than launching an invasion across the ocean.

I've been claiming that since Vanilla 1.00 but everything thought I was crazy :D
 
glider:

In terms of A, B, and C, I am quite certain that A is what was intended. It is the logical construction of the loop where the player closeness value is the sum from their cities, the barbarian bit reinforces this.

It's not bad strategically I don't think ... attacking a player with nearby big cities means that if you succeed in capturing them the cities will be worth something. The issue you raise about colonization is potentially real though ... there's no consideration in calculating closeness for how far the player's city may be from the meat of their empire, so a distant outpost they have near big enemy cities would appear like it would lure them into transcontinental war.

However, closeness is only one of the measures used for determining the startWarVal, another is CvTeamAI::AI_calculateCapitalProximity which uses ratios of distances between capitals to weight different teams, closer being better of course. So long as the player has some closeness > 0 to a potential target with a much closer capital I think the magnitude of the capital proximity factor will trump any difference in closeness generated by the faraway outpost.

By far the biggest effect any fix will have is that closeness will actually be 0 for some players now, triggering the /= 4 in startWarVal ... actual differences between A and B in terms of startWarVal shouldn't be very big compared to this.

I created a blank test map with just two cities from different players to try things out ... the setup was:

0000Y
00000
00000
00000
X0000

When the population of X is 20 and Y is 3, under option A the closeness value generated by X was 8 and for Y was 22, logically this flips exactly when using option B. For option C, both got 15. Just for reference, the original code values would have been 35 for X and 45 for Y irrespective of where X and Y were relative to each other.

For the time being in startWarVal these closeness values are then / 4 before being added to the war value ... the contribution for city X is then either 2, 5, or 3 for A, B, and C. This fairly small difference will only matter for the startWarVal if the net effect of other factors like capital proximity, capturable resources (this would be another interesting discussion in itself), and attitude is finely balanced.

Once we agree to increase the weight of closeness since the values are smaller now it will matter more which we pick. Once we're past just fixing the bug then I maintain that C is the best way to go.



Yakk:

In the test map I just mentioned I tried to recreate the issues I'd seen with calculatePathDistance and was unable to ... it seemed to be working the way it should. I started with all grassland and it correctly returned a distance of 4, when I inserted a mountain range or body of water it correctly returned 7 (the first distance measure was still 4). Just FYI it is not affected by roads/forest, which is sensible.

I intend to check it a couple more times in real game situations (I unfortunately don't have a save for the prior experience), but unless something comes up I guess we should consider it working correctly. I did have multiple cities demonstrating this issue though ...
 
When the population of X is 20 and Y is 3, under option A the closeness value generated by X was 8 and for Y was 22, logically this flips exactly when using option B. For option C, both got 15. Just for reference, the original code values would have been 35 for X and 45 for Y irrespective of where X and Y were relative to each other.

Thanks for those numbers Jdog! Boy this does need clarity doesn't it? I've got only one "test" stream going at the moment. In my widdle world of a bit more testing, I've decided that option A or B is already a bug fix so it's easy. Just choose one or the other. Game play is improved without any serious penalty as far as I can tell. If Bhruic were around he could do that for the benefit of everyone perhaps!?....

The rest of this post is in "spoiler" because it shouldn't be in this forum :)
Spoiler :
The test stream build I am privately going to "play around with" is:
1) CvTeamAI::AI_startWarVal with:
iValue += iClosenessValue / 1

2) CvPlayerAI::AI_playerCloseness(PlayerTypes eIndex, int iMaxDistance)
Option A

3) CvCityAI::AI_cachePlayerCloseness(int iMaxDistance)
Option C

4) There was some other point you had with Yakk regarding modifying CvCityAI::AI_cachePlayerCloseness(int iMaxDistance) beyond just option C but I didn't understand that. It was to do with the aggressive setting.

From doing a little bit more mucking around I think that the numbers you have crunched show that the extra divide by 4 in AI_startWarVal does seem excessive now as you have said. I think I'm noticing that on other map types not Pangaea, the AI's could do with more weight towards player closeness by reducing or eliminating the divide by four.

Also, if I go with the option A for loop construction, then to balance that I need your idea of option C so that colonisation war plans might not be overly spurious.

That's the guess! It's fun anyway.

Cheers!
 
JDogg said:
It's not bad strategically I don't think ... attacking a player with nearby big cities means that if you succeed in capturing them the cities will be worth something. The issue you raise about colonization is potentially real though ... there's no consideration in calculating closeness for how far the player's city may be from the meat of their empire, so a distant outpost they have near big enemy cities would appear like it would lure them into transcontinental war.

That's an edge condition. Note that a single outpost will probably not trigger a huge closeness -- while a long border with someone will.

In the test map I just mentioned I tried to recreate the issues I'd seen with calculatePathDistance and was unable to ... it seemed to be working the way it should. I started with all grassland and it correctly returned a distance of 4, when I inserted a mountain range or body of water it correctly returned 7 (the first distance measure was still 4). Just FYI it is not affected by roads/forest, which is sensible.

Ah. It is a really naive A*! It probably just exists just in case you have mountain-walls (or other equivilent) that seriously change the topology of the game.

Spoiler :
glider said:
4) There was some other point you had with Yakk regarding modifying CvCityAI::AI_cachePlayerCloseness(int iMaxDistance) beyond just option C but I didn't understand that. It was to do with the aggressive setting.

The idea is, leave the iValue += iClosenessValue/4; for most settings. On aggressive AI settings, ramp it up to /2 or /1. Make aggressive AIs attack nearby people with a higher degree of preference than "normal" AIs.

Another good idea would be to boost the "closeness range" value from the default of 6. Don't change the default value, but instead in the war calculation pass in a value larger than it. It will have some CPU overhead.

(Sadly, the pathing A* code cannot be told "I want a path at most X units long", which would make the CPU overhead much lower due to pruning. Silly developers.)


Is there a sourceforge project for this, and how to we propose code changes? I'm rolling these changes into my hand-written mod, but it ... really isn't a mere unofficial patch. :)
 
Yeah, we should start our own thread or sub-forum here I guess plus a Sourceforge project ...

Spoiler :

The idea is, leave the iValue += iClosenessValue/4; for most settings. On aggressive AI settings, ramp it up to /2 or /1. Make aggressive AIs attack nearby people with a higher degree of preference than "normal" AIs.

I thought we'd remove the / 4 when adding closeness for everyone. The Aggressive v Normal change in startWarVal was for the /= 4 when closeness returns 0:

Code:
if (iClosenessValue == 0)
	{
		iValue /= 4;
	}
	iValue += iClosenessValue / 4;

would become

Code:
if (iClosenessValue == 0)
	{
		iValue /= ((GC.getGameINLINE().isOption(GAMEOPTION_AGGRESSIVE_AI) ? 4 : 2);
	}
	iValue += iClosenessValue;

or something along those lines.

 
Top Bottom