AIs and the Art of War

I play a lot of partial games when testing. The AI is slow to expand but don't go over the city limits when that option is enabled.

Well, it should! Especially with post-Despotism, there is only 1 :mad: per extra city, which can easily be compensated and is more then worth it.
 
I'm not sure what was causing the slowdown but an attempt to debug a non-issue I didn't realize was a non-issue MAY have had something to do with that.

That slowdown comes from
Code:
int CvUnit::getExtraUnitCombatModifier(UnitCombatTypes eIndex) const
{
	FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(eIndex < GC.getNumUnitCombatInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");
	
	const UnitCombatKeyedInfo* info = findUnitCombatKeyedInfo(eIndex);

	int iBaseAmount = (info == NULL ? 0 : info->m_iExtraUnitCombatModifier);
/************************************************************************************************/
/* Afforess	                  Start		 03/1/10                       Coded By: KillMePlease   */
/*                                                                                              */
/* Great Commanders                                                                             */
/************************************************************************************************/
	if (!isCommander()) //this is not a commander
	{
		CvUnit* pCommander = getCommander();
		if (pCommander != NULL)
			return	iBaseAmount + pCommander->getExtraUnitCombatModifier(eIndex);
	}
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/
	return iBaseAmount;
}

this is called from isClearlySuperior
Code:
	for(int iJ = 0; iJ < GC.getNumUnitCombatInfos(); iJ++)
	{
		int iCombatMod = pUnit->unitCombatModifier((UnitCombatTypes)iJ);
		int iOtherCombatMod = pOtherUnit->unitCombatModifier((UnitCombatTypes)iJ);

		if ( iCombatMod > 0 )
		{
			iTotalCombatMods += iCombatMod;
		}

		if ( iOtherCombatMod > 0 )
		{
			iOtherTotalCombatMods += iOtherCombatMod;
		}
	}
alot in that save and just takes it's time. It would be possible to recode isClearlySuperior but i don't think i do that any time soon.

EDIT: Testing is showing that they are still only taking one unit with them with the 2*strength of best city defender.

This tells me that they MAY not have a city defender in the evaluation because 2*0 would = 0 and perhaps only the canDefend() check is working at all.

That was caused by:
Code:
						// safety check. (cf. conditions in AI_found)
						if (getGroup()->canDefend() || GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pMissionPlot, MISSIONAI_GUARD_CITY) > 0)
This is why they always left with one defender.


One thing I wonder though... I was wondering if it was a bad thing to have two potential brokerage calls like I had in the settle AI... maybe that was causing some serious trouble? I dunno...

That is possible and i would just try 2*strength of best city defender because they often didn't even have more then one of them before. Because of that other piece of code so everything is better even if they just get two of them now.


EDIT:

I don't make any tests until you commit those changes because it just won't work here anymore. I didn't look at the other changes you made maybe my problems are caused by something else????
 
That slowdown comes from
Code:
int CvUnit::getExtraUnitCombatModifier(UnitCombatTypes eIndex) const
{
	FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(eIndex < GC.getNumUnitCombatInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");
	
	const UnitCombatKeyedInfo* info = findUnitCombatKeyedInfo(eIndex);

	int iBaseAmount = (info == NULL ? 0 : info->m_iExtraUnitCombatModifier);
/************************************************************************************************/
/* Afforess	                  Start		 03/1/10                       Coded By: KillMePlease   */
/*                                                                                              */
/* Great Commanders                                                                             */
/************************************************************************************************/
	if (!isCommander()) //this is not a commander
	{
		CvUnit* pCommander = getCommander();
		if (pCommander != NULL)
			return	iBaseAmount + pCommander->getExtraUnitCombatModifier(eIndex);
	}
/************************************************************************************************/
/* Afforess	                     END                                                            */
/************************************************************************************************/
	return iBaseAmount;
}

this is called from isClearlySuperior
Code:
	for(int iJ = 0; iJ < GC.getNumUnitCombatInfos(); iJ++)
	{
		int iCombatMod = pUnit->unitCombatModifier((UnitCombatTypes)iJ);
		int iOtherCombatMod = pOtherUnit->unitCombatModifier((UnitCombatTypes)iJ);

		if ( iCombatMod > 0 )
		{
			iTotalCombatMods += iCombatMod;
		}

		if ( iOtherCombatMod > 0 )
		{
			iOtherTotalCombatMods += iOtherCombatMod;
		}
	}
alot in that save and just takes it's time. It would be possible to recode isClearlySuperior but i don't think i do that any time soon.
If I'm not mistaken, that would take some seriously interesting caching right?


That was caused by:
Code:
						// safety check. (cf. conditions in AI_found)
						if (getGroup()->canDefend() || GET_PLAYER(getOwnerINLINE()).AI_plotTargetMissionAIs(pMissionPlot, MISSIONAI_GUARD_CITY) > 0)
This is why they always left with one defender.
Nope... My adjustments changed || to a && as well.




EDIT:

I don't make any tests until you commit those changes because it just won't work here anymore. I didn't look at the other changes you made maybe my problems are caused by something else????
They're already on the svn.
 
A player can, as we have mentioned, decide to not build a bunch of buildings that cost too much money, maintenance. The Ai chooses what to build depending on a program but more often than not builds a lot of those +Maintenance buildings.
This more than anything might slow the AI's expansion (can not afford another city), it's unit building (not enough units for settlers defence), and in the end it's competence.

If either the added building costs are somewhat reduced (with somewhat I am actually thinking "quite a bit") or the Ai is told to skip those unless ABSOLUTELY needed, or the building is worth the cost (those that give +:science: for instance, or gain more than one loses).
At least in the first 3 Eras, or 2 and a half eras, after that if a building costs both players and AI can usually afford it, but the Prehistory and Ancient Eras suffer a lot from this I think.

Cheers
 
Please don't remove/reduce maintenance! I'm playing a game on noble now, and I litteraly swim in gold since forever. Even with no Shrine and twice as many cities then Monarchy can support I have waaaay to much gold surplus each round.

How good is the AI in city specialization? Does it destinguish between boarder cities, realativly secure boarder cities (like a coastal city in the high north protected by ice sheets), military city, :gold: city, GP and :science: cities etc?
 
They're already on the svn.

Now they expand again my problems are gone. I saw you reverted some pushMission(MISSION_SKIP) calls from your previous changes that explains why the ContractBroker is working again. I missed that you put them in before did you try to fix infinite loops with them?

If I'm not mistaken, that would take some seriously interesting caching right?

I don't think caching is neccesary there because caching can't always be used just to fix bad or slow code.
If there are huge stacks of units isClearlySuperior could be called alot. Each time it calls the slow getExtraUnitCombatModifier function 2*GC.getNumUnitCombatInfos() times. This leads to alot getCommander() calls and more getExtraUnitCombatModifier calls. That is just slow by desing so it could be recoded to be faster. It would also be possible to use some kind of multithreading in CvSelectionGroupAI::AI_getBestGroupAttacker.

But it is possible something else causes that slowdown in that save that must be ruled out before.
 
Please don't remove/reduce maintenance! I'm playing a game on noble now, and I litteraly swim in gold since forever. Even with no Shrine and twice as many cities then Monarchy can support I have waaaay to much gold surplus each round.

I must point out that I am not finding this to be so. Even at Monarchy my income is at most 10 per turn. Having said that I rarely have to put my science below 100. In the early game changing the science by even 40% has little or no effect on the income I am getting per turn. I think the most I have seen is +1 gold a turn. All that changes at the Metals civic. As I said elsewhere I need to expand to keep from going broke.
 
Not talking about removing or reducing maintenance. Talking about reducing the added costs for having buildings, like the Graveyard's -5 gold per turn, or Sentry Post -2 gold per turn, and the -10 or more cost per turn for some wonders.

These I fear the AI might not not build enough and thus incurs too high costs and thus does not expand in a reasonable pace.
All too often a high disease AI city I take over has a Graveyard and Healer's Hut that cost more money than the relative slight decrease in Disease they give is worth. As one example. Another is City Defence buildings, both direct defence and indirect by damage chance, when a player might send up units to meet any enemy approaching instead and thus save in costs versus what an AI can (as they are not "smart" enough for that kind of tactic).

My point really being that those high costs on buildings are hindering the AI more than the Player, a lot more I would say too. A player can decide to have 2xdisease reducing units stationed in a city instead and doing more good than a Graveyard and Mausoleum and Apothecary together, for a fraction of the cost, while an AI builds them and still needs a unit to get the same effect as the player.

Cheers
 
Now they expand again my problems are gone. I saw you reverted some pushMission(MISSION_SKIP) calls from your previous changes that explains why the ContractBroker is working again. I missed that you put them in before did you try to fix infinite loops with them?
Yeah, but only in the one before this - you were showing, even before that, that there was trouble with growth. When he stated that the units stuck in the loop weren't causing the game to be stuck as a whole I realized that was a mistake to put that there.

Nevertheless, you'll see that despite the adjustments the AI is still only sending out one unit so I do think there's something of an issue with the strength of the best defender. I was finding that the AI was having trouble finding a valid buildable defender through
Code:
		if (AI_chooseUnit("min defender", UNITAI_CITY_DEFENSE))
		{
			return;
		}
which is really as basic a call as you can get.

Of course, analyzing this is hell because the unit selection process is terribly overcomplicated - there's portions I really don't see the point in for one thing. Finding the problem there is like finding a needle in a haystack.

The problem COULD be what happens when military units are built with food (such as they seem to be on some early civics.)
The 'get strength of' function leads here:

UnitTypes CvCityAI::AI_bestUnitAI(UnitAITypes eUnitAI, int& iBestValue, bool bAsync, bool bNoRand, CvUnitSelectionCriteria* criteria)

That starts getting into whether the unit should be built right now due to food.

Then, assuming the caching is working correctly, it makes a validity check on the unit's evaluation, then looks for the best evaluation among units similar, then appears to make a selection from among those that work...

The whole thing just strikes me as terribly over-engineered for this type of call.

I don't think caching is neccesary there because caching can't always be used just to fix bad or slow code.
If there are huge stacks of units isClearlySuperior could be called alot. Each time it calls the slow getExtraUnitCombatModifier function 2*GC.getNumUnitCombatInfos() times. This leads to alot getCommander() calls and more getExtraUnitCombatModifier calls. That is just slow by desing so it could be recoded to be faster. It would also be possible to use some kind of multithreading in CvSelectionGroupAI::AI_getBestGroupAttacker.

But it is possible something else causes that slowdown in that save that must be ruled out before.
Yeah, that seems... rough. The getCommander thing has never been an easy one to solve. Koshling did some caching there but it's difficult at best. Maybe there's another way to short circuit those calls if they aren't necessary to make. If there's no modifiers on a particular tag ever established in the xml, no commanders in play on that team, no commanders in the area, anything to narrow the cause to even check this.

I've been wanting to do something another mod pulled off - having support promotions that are added due to the existence of other units on the plot - but I can't figure out how to do it in such a way that it wouldn't cause a similar problem... but then again, maybe if this could be sorted out in a quick way it could also be used to establish how commanders could be restructured entirely to be much faster... Process in and out the offered modifiers when validated and invalidated so that the modifier is stored on the unit and faster to access at times like these. Working out the validation and invalidation processes would be the tricky part.
 
Yeah, but only in the one before this - you were showing, even before that, that there was trouble with growth. When he stated that the units stuck in the loop weren't causing the game to be stuck as a whole I realized that was a mistake to put that there.

Nevertheless, you'll see that despite the adjustments the AI is still only sending out one unit so I do think there's something of an issue with the strength of the best defender. I was finding that the AI was having trouble finding a valid buildable defender through
Code:
		if (AI_chooseUnit("min defender", UNITAI_CITY_DEFENSE))
		{
			return;
		}
which is really as basic a call as you can get.

Of course, analyzing this is hell because the unit selection process is terribly overcomplicated - there's portions I really don't see the point in for one thing. Finding the problem there is like finding a needle in a haystack.

The problem COULD be what happens when military units are built with food (such as they seem to be on some early civics.)
The 'get strength of' function leads here:

UnitTypes CvCityAI::AI_bestUnitAI(UnitAITypes eUnitAI, int& iBestValue, bool bAsync, bool bNoRand, CvUnitSelectionCriteria* criteria)

That starts getting into whether the unit should be built right now due to food.

Then, assuming the caching is working correctly, it makes a validity check on the unit's evaluation, then looks for the best evaluation among units similar, then appears to make a selection from among those that work...

The whole thing just strikes me as terribly over-engineered for this type of call.

If you look at this line
Code:
if (getGroup()->canDefend() && getGroup()->getStrength() > 2*GET_PLAYER(getOwnerINLINE()).strengthOfBestUnitAI(DOMAIN_LAND, UNITAI_CITY_DEFENSE))

You have getGroup()->getStrength() and 2*GET_PLAYER(getOwnerINLINE()).strengthOfBestUnitAI(DOMAIN_LAND, UNITAI_CITY_DEFENSE). they are not the same getStrength() includes promotions and other modifiers but the return value of strengthOfBestUnitAI() is very simple.
Code:
		CvUnitInfo& kUnit = GC.getUnitInfo(eBestUnit);

		return (kUnit.getCombat() + GET_TEAM(getTeam()).getUnitClassStrengthChange((UnitClassTypes)kUnit.getUnitClassType()));

So they can't be compared and i suggest to try my initial 4*GET_PLAYER(getOwnerINLINE()).strengthOfBestUnitAI(DOMAIN_LAND, UNITAI_CITY_DEFENSE). That should give them ~3 defenders in the early game.
 
Well... that does make sense.

Where would I have been going wrong when trying to enforce 2 specific city defense AI units and 2 specific city counter units?
 
I'am not sure if the ContractBroker can handle two calls in a row from the same unit if it doesn't that is a issue. I noticed some conditions where you used && instead of || that could cause problems if the wrong one is used and remember that && has a higher priority.
 
So they can't be compared and i suggest to try my initial 4*GET_PLAYER(getOwnerINLINE()).strengthOfBestUnitAI(DOMAIN_LAND, UNITAI_CITY_DEFENSE). That should give them ~3 defenders in the early game.

I think 3 defenders in early game is too low. Especially when civs have only 1 city each. You have a lot of free units.

I just downloaded the latest SVN (8186) today and started a game as Denmark. I play Deity/Nightmare and the new Education rules hit hard: I can only self-research 1 tech until progress drops to near zero beakers per turn due to education being at -100, which means I must rely on tech diffusion and the occasional tech from popping tribal villages to progress, until Education starts to increase slowly after finally researching Oral Tradition. So I am way behind in technology and city development.

I found the Turkish capital 16 squares away. After improving education I build a hunting instructions and stone tools maker then start pumping out Spiked Clubmen to hunt animals. When I have about a dozen Spiked Clubmen I send all of them to the Turkish capital, which was only defended by 1 tribal guardian and 2 slingers. It was population size 4 (while my own capital was still at 1). I lost 5 Spiked clubmen before conquering the Turkish capital.

In earlier games that would have been a major money drain but both cities have -115% maintenance which means zero gold cost. I have -90% pretribemaint autobuildings in both cities, don't know where the last -25% comes from. He must have lost the 2nd Band of Homo Sapiens he started with (AI perk for Deity difficulty) as the Turkish civ vanished after losing its capital and there are no city ruins around.
 
Until now settlers had only one unit as escort, if they have 3 now that is already an improvement. It was like this for a long time and nobody really noticed it otherwise it would have been changed years ago. Those units are just to defend the settler and as a starting point for the city defense, the city calls for more units later if they are needed. If more units are really needed we need to make another change especialy for slower gamespeeds to stop the ai from scrapping settlers too early.
 
I think 3 defenders in early game is too low. Especially when civs have only 1 city each. You have a lot of free units.

I just downloaded the latest SVN (8186) today and started a game as Denmark. I play Deity/Nightmare and the new Education rules hit hard: I can only self-research 1 tech until progress drops to near zero beakers per turn due to education being at -100, which means I must rely on tech diffusion and the occasional tech from popping tribal villages to progress, until Education starts to increase slowly after finally researching Oral Tradition. So I am way behind in technology and city development.

I found the Turkish capital 16 squares away. After improving education I build a hunting instructions and stone tools maker then start pumping out Spiked Clubmen to hunt animals. When I have about a dozen Spiked Clubmen I send all of them to the Turkish capital, which was only defended by 1 tribal guardian and 2 slingers. It was population size 4 (while my own capital was still at 1). I lost 5 Spiked clubmen before conquering the Turkish capital.

In earlier games that would have been a major money drain but both cities have -115% maintenance which means zero gold cost. I have -90% pretribemaint autobuildings in both cities, don't know where the last -25% comes from. He must have lost the 2nd Band of Homo Sapiens he started with (AI perk for Deity difficulty) as the Turkish civ vanished after losing its capital and there are no city ruins around.

1) Way to go finding ways to get around the education bind and still maintain competitiveness! Mind-blowingly difficult but not absolutely impossible, however improbable survival may be is exactly what we're going for with nightmare deity.

2) Nice move on taking out the enemy capital that way! Outstanding display of strategery. I think you'd have caught out any unsuspecting human player that way as well. The AI could perhaps have been a little better at reacting but if it's told to have much more in defense it eats up too much production that can be used for better purposes at that early stage.

3) You pointed out we MAY have a problem with the new AI for when they have more than one settler to start the game with - they'll need to have at least enough defenders added to their starting bonus amounts to compensate for the needs the settler demands to accompany them so the don't disband. So great reporting!
 
I play Deity/Nightmare and the new Education rules hit hard: I can only self-research 1 tech until progress drops to near zero beakers per turn due to education being at -100, which means I must rely on tech diffusion and the occasional tech from popping tribal villages to progress, until Education starts to increase slowly after finally researching Oral Tradition.

The trick is to go for the Oral Tradition first and prefer commerce tiles above anything, even hammers. Its the fifth tech if you go there ASAP and there is nothing so important, not even Cave dwelling. It helps to find another civilization to get some tech difusion points, but it is still possible even without it. I'd recommend Language first to increase science a little. The education then still drops below -100 before you get there and science to 1-2 beakers, but it is still possible to get there quickly even with no traits used. Then a lot of buildings give too many education points, so it swings to 250+ :lol:
If you are lucky to have caves and river, Klassies river caves are the best build just after the start (they give commerce, not gold).

I decided not to conquer the only known neighbour early, I'd lose those TD points from him and a lot of production ;)

He must have lost the 2nd Band of Homo Sapiens he started with (AI perk for Deity difficulty) as the Turkish civ vanished after losing its capital and there are no city ruins around.

Unfortunately most AI civs lose them currently. In my present game all 4 known civilizations have one city only. Maybe barbarians ate them (I use Barbarian World, barbs are bigger threat than AI so far). Or the AI is not helped by the No traits settings I am enjoying...

Speaking about barbs, haven't the recent changes influenced their behavior as well? I liked their occasional invasions and it was some nice fight for survival as they got numbers and better units too. Now there are two size 3 barb cities pretty close, one has 25 stone macemen (this formidable force prevents me from going anywhere), plenty of other units and they just sit next to a city. I'll wait for elephants or horsemen ;)

I have -90% pretribemaint autobuildings in both cities, don't know where the last -25% comes from.

Maybe it is the -25% for all cities on home continent from Anarchism. That reminds me: I always thought the combined total of -115% for the first two cities is too much. A distant conquered city costs nothing, crime doesn't matter there until Chiefdom (:confused:), building costs don't matter...

-90% would be enough, it would still serve the purpose and maintenance for a distant city would cost a little, but affordable, money.
 
so, does the AI now expand in your games or not? I tried a game with more usual settings, except for Barbarian World (and I don't want to leave this, its funny and challenging). Traits are on (i.e. all options untouched). I'm a little behind, all others are around sedentary lifestyle. But I have 3 cities comfortably, can build a 4th one while just two AIs have 2 cities. All others have one. Some have a lot of space around, capital size 6 yet they are doing nothing.

Looks to me like they are waiting for Settlers and ignoring Tribes... The best AI founded a second city after first discovering SL.
 
so, does the AI now expand in your games or not?

On nightmare/deity most AIs waste their 2nd Band of Homo Sapiens. Later some AIs do expand a little (most are covered by fog of war so I don't see much), others just sit in their capital and do little. After a while this leads to lots of barbarian cities on the map that eventually become new minor civs (I have the option turned on). The AI is somewhat competent at conquering these new civs, and what I can see this becomes the main way of AI expansion.
 
The AI seems very fond of accepting minor civs as vassals though, instead of conquering them. Not sure if that is a good strategy. These small vassals tend to stay behind in tech.
 
In my game (also deity / nightmare) the AI is just doing fine - best of the known ones has 14 cities by now and they are ranked as the 3rd biggest (I have 7 and am 6th or 7th). However, I haven't really seen barbarians - only one Neanderthal so far, and lots of animals.

I also wanted to mention that the AI sens troops to my new founded boarder / bottle neck) city. By the time they arrived, I constructed walls and stuff there. The AI brought an Arsonist that kept Range Bombarding me and 8 Battering Rams. These did nothing. When the AI considered my defense low enought, the Major was assassinated so my city starts a revolte, purging all defenses. Then they attacked.
I think this was a pretty good strategy, but after they were crushed by my forces, only a hand full Llama Riders survived (barely) and two fully healed Archers as well. But they didn't move (the one step) out of my boarders to heal, so my defenses kept damaging them and my top defender could take them out one by one. That was weird.
 
Back
Top Bottom