The AI Craziness Thread

Skyre Noktis

Warlord
Joined
Apr 28, 2009
Messages
271
Some observations and constructive criticism...

1. AI treasury management is insane

When I first started doing AI testing, I noticed that AI research rates all took a nosedive shortly after turn 200 (normal speed). At first I thought they must have been crashing their economy somehow (too many units?), but that turned out not to be the case. Even the bigger empires could research at around 40-50% and still turn in a net profit.

After some digging around, I found the source of the problems: AI_getGoldTreasury in CvPlayerAI.cpp. This function tells the AI to save up gold for trading with other empires -- rather a lot of gold, as it turns out. In my game, Jonas, with ten cities, felt like he needed a stash of 1,000 gold at all times. If it ever fell below this number, he turned down research to zero and waited for it to go up again.

I see what this is supposed to do in theory, but it all it does in practice is cripple the AI's research:

1. The amount of gold saved is excessive. You simply don't need that much. If you're buying techs for gold (rather than swapping them for other techs), you might as well just research them yourself.

2. There aren't any checks to see if you've discovered Trade or Currency yet, anyway.

3. Removing this (and the money being saved up for random events, which also doesn't really help the AI in practice) resulted in AI civs being in a much stronger position, technologically, by turn 300 (again, normal speed).

As I said, I understand what it's supposed to do and how it's supposed to help, but the current implementation is horribly broken and hurts the AI a lot.

2. Stack attacking could be better

Actually, there are tons of ways this one could be improved. Two things stuck out at me on first glance:

While there is the AI_stackAttackCity function in CvUnitAI, which works as it should, comparing one stack to another to see if it's worth attacking, there's also AI_cityAttack, which just compares the best attacker against the best defender and ignores everything else in both stacks. This doesn't seem sensible at all. AI_anyAttack works the same way, but for units in the field.

AI_compareStacks is pretty simplistic in general, actually. It could do with accounting for collateral damage, for example. On that note, CvUnitAI::AI_sacrificeValue could also do with giving units that 'explode' (i.e. Pyre Zombies) a higher value.

3. The way the AI chooses when to go to war is silly

Well, we knew it sub-optimal. I had no idea how bad it was until I checked the code.

The algorithm is completely backwards. The AI decides whether it wants to go to war (mostly at random) and *then* it picks the victim. Surely it should be determining the juiciest target first and then deciding whether it's worth going to war based on relative power ratios and how attractive the victim's lands are? That would make sense.

Ideally, an aggressive leader with double the power of his/her nearest neighbour would have no qualms whatsoever about declaring a 'max war' on them immediately and conquering their sorry empire. Why should they? They shouldn't be kept at bay by the random number generator when there's no good reason not to fight.


.....................................................................

That's all for now. More stuff as I spot it.
 
1. The gold for events is also used for other things, like Doviello upgrading their units melee units.

I added some code so the AI will only save up Gold when they can actually trade a tech.
Spoiler :
Code:
	//save up some gold for only trading
	if (bTrading)
	{
	    if (!GC.getGameINLINE().isOption(GAMEOPTION_NO_TECH_TRADING))
	    {
	        bool bValid=false;
	        TeamTypes eTeam;
	        int iNeededGold;

            for (int iI = 0; iI < MAX_CIV_PLAYERS; iI++)
            {
                if (getID() != iI && GET_PLAYER((PlayerTypes)iI).isAlive())
                {
                    eTeam=GET_PLAYER((PlayerTypes)iI).getTeam();
                    if (eTeam!=NO_TEAM && GET_TEAM(getTeam()).isHasMet(eTeam))
                    {
                        if (GET_TEAM(eTeam).isGoldTrading() || GET_TEAM(getTeam()).isGoldTrading())
                        {
                            if (GET_TEAM(eTeam).isTechTrading() || GET_TEAM(getTeam()).isTechTrading())
                            {
                                if(AI_getAttitude((PlayerTypes)iI) >= ATTITUDE_PLEASED)
                                {
                                    //does a tech to trade exist?
       								for (int iJ = 0; iJ < GC.getNumTechInfos(); iJ++)
                                    {
                                        if (GET_TEAM(getTeam()).AI_techTrade((TechTypes)iJ, GET_PLAYER((PlayerTypes)iI).getTeam()) == NO_DENIAL)
                                        {
                                            iNeededGold=GC.getTechInfo((TechTypes)iJ).getResearchCost();
                                            bValid=true;
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            if(bValid)
            {
                iGold += iNeededGold;
            }
	    }
	}

2. AI_cityAttack / AI_anyAttack is used by barbs.

AI patrols /defensive stacks typically use something like this

Code:
												int iOurStrength=getGroup()->AI_GroupPower(pLoopPlot,false);
												int iTheirStrength=GET_PLAYER(getOwnerINLINE()).AI_getEnemyPlotStrength(pLoopPlot,0,true,false);
												if (iOurStrength>(iTheirStrength*1.2))
												{
													iValue = getGroup()->AI_attackOdds(pLoopPlot, true);

													if (iValue>10)
													{
This checks both for the overall odds and the odds of the best attacker.

Conquest stacks only rarely calculate attack odds.

3.
yes, this is really messed up. I agree, not every war decision should be based on randomness. How about giving every team an array of Warvalues vs. the other teams? Warvalue could include number of cities valuable for conquest, power ratio, current war of own team/target team, flavor/attitude value.
 
3. The way the AI chooses when to go to war is silly

Well, we knew it sub-optimal. I had no idea how bad it was until I checked the code.

The algorithm is completely backwards. The AI decides whether it wants to go to war (mostly at random) and *then* it picks the victim. Surely it should be determining the juiciest target first and then deciding whether it's worth going to war based on relative power ratios and how attractive the victim's lands are? That would make sense.

Ideally, an aggressive leader with double the power of his/her nearest neighbour would have no qualms whatsoever about declaring a 'max war' on them immediately and conquering their sorry empire. Why should they? They shouldn't be kept at bay by the random number generator when there's no good reason not to fight.


.....................................................................

That's all for now. More stuff as I spot it.

That's very true. Especially when you see what amounts of troops the AI has I always try to keep myself on par (at least to certain degree) crippling a significant amount of my economical power. But if the AI anyway does not attack though it could easily win why should I even care? I prefer being obliged to tech for defensive techs earlier or even to be obliged to decrease my beloved Immortal difficulty level to seeing the AI's military strong without it attacking anyone. It has not to be me. Epic Wars between the AIs and AI trying to win a conquest victory - my dream since CIV4 came out.
 
I've been playing with this a fair bit today. It's easy enough to get some (reasonably) sensible decisions out of the AI, but getting it to actually fight is another matter. What happens most of the time is that it sets its war plan (e.g. to WARPLAN_TOTAL) and then sits around and doesn't actually do anything. Usually, it never gets as far as actually declaring war because it never attacks.

I wonder if this is simply because all the civs build far too many defensive units and too few offensive units. If there are no weak points to attack, it's not going to be able to do anything.

While I certainly don't want everything overrun by barbarians within the first 100 turns, I do think the current AI is far too cautious as a whole, which makes it a lot less fun.
 
The AIs do need to be more aggressive. Right now I worry about barbs not AIs. I do think some of it may be them being more afraid of the barbs then the player.
 
They seem very afraid of everything. They end up with 6+ permanent defenders per city by the mid-game and little else to speak of. They won't attempt any attack at all if they're not in 'conquest mode', even if they're the ones who decided to go to war.
 
Something GreyFox and I have been discussing is almost relevant here.... :lol:

Currently, due to his Project I need to move my LeaderStatus file from BasicInfos to CivilizationInfos (All it does currently is do away with the 'Minor' and 'Emergent' traits, and let me display it in the scoreboard) as we need to add some tags to it. Which is impossible in BasicInfos.

While talking about it, though, we realized that essentially I'll be making a LeaderClass file... Which got us thinking about other uses for it, obviously, but more importantly, other files that would be useful for leaders.

The big one we've talked about is PersonalityInfos. Rather than have all the personality tags scattered throughout the leaderhead, and generally only subtly tweaked from leader to leader for each civ, why not have a set of 'standard' personalities set in a different file, and loaded via one line? It would make adding leaders far simpler, as you could reuse a personality, and it would also make tweaking these personalities a bit easier as you'd have it all in one place. And obviously, there's no real reason you couldn't have a 1:1 Leader to Personality ratio.

Think it would be a good idea?
 
I've been playing with this a fair bit today. It's easy enough to get some (reasonably) sensible decisions out of the AI, but getting it to actually fight is another matter. What happens most of the time is that it sets its war plan (e.g. to WARPLAN_TOTAL) and then sits around and doesn't actually do anything. Usually, it never gets as far as actually declaring war because it never attacks.

I wonder if this is simply because all the civs build far too many defensive units and too few offensive units. If there are no weak points to attack, it's not going to be able to do anything.

While I certainly don't want everything overrun by barbarians within the first 100 turns, I do think the current AI is far too cautious as a whole, which makes it a lot less fun.

You can make an AI go into conquestmode by using
void CvPlayer::startConquestMode(). All Warplans do is to select the war target and only an AI in ConquestMode will actually declare a war (unless it is scripted).

I think early wars are pretty useless for most AI civs. Your target has most likely 7+ defenders in a target city and there are usually better ways to expand. Clan, Doviello and Sheaim are set to enter conquest mode early, also a few Leaders like Tasunke or Alexis. In a recent game I was attacked about turn 160 by Doviello with 30+ Beastmen/sons of arsena and lots of wolf packs. I don't find the AI too cautious, I think it often just picks the wrong targets when in Conquestmode or misses opportunities for a 2 vs. 1 war.

@Valkrionn
depends what you want to use your new class for and how much time it saves you. For the personalities I preferred to define default values in the DLL and remove all tags with default values from the XML.
 
Not as important as the issues above, but since this is an AI thread I'll post a little glitch I've observed. Almost every time a barbarian unit moves up to my city or unit, it spends exactly 1 turn doing nothing, then attacks or moves away on the following turn. I don't think it's waiting for reinforcements (or if it is, then it is always changing its mind on the next turn before the situation improves). It's been pretty reliable in my last two games. Several times the AI would have had certain success if it had attacked when it could have (my unit was wounded, or city defended by one weak unit) and much worse on the next turn when it actually attacks.
 
I've noticed that too...

turn 1 : pit beast moves next to my city
turn 2 : pit beast does nothing
turn 3 : pit beast pillages improvement on the tile it's sitting on

why it "wasted" a turn, I do not know :lol:
 
You can make an AI go into conquestmode by using
void CvPlayer::startConquestMode(). All Warplans do is to select the war target and only an AI in ConquestMode will actually declare a war (unless it is scripted).
Thanks for the clarification. This seems to be the main problem with the existing diplomacy logic, then, as the only place 'startConquestMode' ever seems to be called is in the Python.

Your target has most likely 7+ defenders in a target city and there are usually better ways to expand.
Agreed. This is what I mean by 'too cautious'. If you have 7 defenders in a city early on, you'll had to make other sacrifices to get that many, whether it's at the expense of your economy or of building an offensive army. As a human player, I'd rather see aggressive conquerors and economic powerhouses than boring turtle civs who pose little threat but are nigh on impossible to conquer.
 
1. The gold for events is also used for other things, like Doviello upgrading their units melee units.

I added some code so the AI will only save up Gold when they can actually trade a tech.
Spoiler :
Code:
	//save up some gold for only trading
	if (bTrading)
	{
	    if (!GC.getGameINLINE().isOption(GAMEOPTION_NO_TECH_TRADING))
	    {
	        bool bValid=false;
	        TeamTypes eTeam;
	        int iNeededGold;

            for (int iI = 0; iI < MAX_CIV_PLAYERS; iI++)
            {
                if (getID() != iI && GET_PLAYER((PlayerTypes)iI).isAlive())
                {
                    eTeam=GET_PLAYER((PlayerTypes)iI).getTeam();
                    if (eTeam!=NO_TEAM && GET_TEAM(getTeam()).isHasMet(eTeam))
                    {
                        if (GET_TEAM(eTeam).isGoldTrading() || GET_TEAM(getTeam()).isGoldTrading())
                        {
                            if (GET_TEAM(eTeam).isTechTrading() || GET_TEAM(getTeam()).isTechTrading())
                            {
                                if(AI_getAttitude((PlayerTypes)iI) >= ATTITUDE_PLEASED)
                                {
                                    //does a tech to trade exist?
       								for (int iJ = 0; iJ < GC.getNumTechInfos(); iJ++)
                                    {
                                        if (GET_TEAM(getTeam()).AI_techTrade((TechTypes)iJ, GET_PLAYER((PlayerTypes)iI).getTeam()) == NO_DENIAL)
                                        {
                                            iNeededGold=GC.getTechInfo((TechTypes)iJ).getResearchCost();
                                            bValid=true;
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            if(bValid)
            {
                iGold += iNeededGold;
            }
	    }
	}

Excuse my ignorance, but am I correct in thinking that you make AI save up for the first tradable tech it comes across for each civ it can trade with? I assume that the order of techs in TechTypes is such that it works ok?
 
@Gekko
I have no idea either but in the new Barb AI this doesn't happen anymore

@Skyre
The AI simply needs these units to reliable deal with barbs and animals. 3 permanent defenders +1patrol unit per city isn't that much. I tried lower defense values in the past but it simply didn't work.

going into conquestmode is in cveventmanager.py. I made conquestmode overwrite the warplan decisions to keep the AI from starting early wars it cannot win and help some civs beeline their key techs.

@Marksman
yes, this is how it works. The AI simply tries to buy off any techs it can get from friendly civs. Usually the AI has some techs itself, so the trade is tech1+gold vs. tech2, which is a win-win situation
 
@Skyre
The AI simply needs these units to reliable deal with barbs and animals. 3 permanent defenders +1patrol unit per city isn't that much. I tried lower defense values in the past but it simply didn't work.
But 3 permanent defenders + 1 patrol unit does not equal 7 defenders(???).

Also, what difficulty setting are you playing/testing on? I'm curious. I tend to run Autoplay (AI vs. AI) games on Noble, and the AI is definitely being severely bogged down by all the defensive units it feels it has to build there. With the production bonuses from higher levels, it's not going to be such a big deal.

If there hasn't been extensive testing at lower difficulty settings, it needs to be done, especially as these AI changes will eventually filter down to base FfH where there are a lot of novice players.

going into conquestmode is in cveventmanager.py. I made conquestmode overwrite the warplan decisions to keep the AI from starting early wars it cannot win and help some civs beeline their key techs.
The hardcoding seems very inappropriate to me. Even if the AIs are rock solid defensively, there should be nothing stopping them from invading a weak human.

That and there's no guarantee a leader with an early conquest mode trigger is going to be in a position to enter a war at the time, in which case they're just wasting production (and maintenance costs) on units they can't or won't use. When naval AI gets improved and continents/islands maps become more widely played, this will be especially important.
 
You could lower barbarian city attack strength. Like an opposite city raider.
This way they would stay dangerous when roaming around and pillaging, but wouldnt conquer less defended cities so easily.
 
I tend to play with all the barb/animal/dragon challenges on with increasing difficulty as well (starting at prince).

Eventhough I find that a rare few civs do die to barbs early on, the barb invasion and later the pirate invasion and dragon hassling are very hard to deal with and a sensible defense is necessary for the AI. 3 defenders + 1 patrol per city makes sense to me.

When it comes to wars, I have seen on some occasions combined arms but more often than not a simple stack of single type units (melee, or melee+recon, rarely melee+arcane - but this depends on the civ). When it comes to starting wars and then carrying out with wars, I don't have major complaints. In comparison to other mods, WildMana AI is very very good.
 
You could lower barbarian city attack strength. Like an opposite city raider.
This way they would stay dangerous when roaming around and pillaging, but wouldnt conquer less defended cities so easily.

The penalty vs cities is a good one.
 
I think since so much scripting is used for war declaration it would be interesting if the AI was made to attempt to stop foes from obtaining various victory conditions.

Say if one nation obtains 40% of land and population, all nations not on friendly terms with that nation would turn on them to prevent a domination victory. Same idea with cultural victory. 2 cities at legendary status.. time to do something about it.

It would be fun to code in a full blown world war if you near the time victory as well :goodjob:
 
Back
Top Bottom