Amphibious attack AI

jkp1187

Unindicted Co-Conspirator
Joined
Aug 29, 2004
Messages
2,496
Location
Pittsburgh, Pennsylvania
(This was cross-posted in the Unofficial Patch forum, too.)

This is a save file from a current game. I'm posting this because I'm worried about the AI's ability to successfully launch a cross-sea invasion. I am using only 3.17 + Solver's 0.19.

The Hammurabi/Frederick Permanent Alliance declared war on me and launched an attack. H/F are threatening me with their navy from the northern sea. Note that they have several transports in the navy stack adjacent to Alexandria.

However, I have almost nothing in Alexandria -- a maceman, that's it. They should've just attacked immediately with whatever they had in the transports and either captured the city or burned it down. Instead, they did nothing. In subsequent turns, they just started cruising around the northern sea. They never even unloaded their army. The AI's best hope in a war against a strong human player is to take him by surprise, grab a city or two, then hopefully smash the human's counterattack stack and hope he sues for peace. Here, the AI have more or less thrown away their best chance.


http://files.filefront.com/AttackedCivBeyondSwordSave/;10880051;/fileinfo.html
 
I'm posting this because I'm worried about the AI's ability to successfully launch a cross-sea invasion.

You and everyone else. Naval invasions are one of the AI's biggest weaknesses. Even when they do land some troops or even take a city, the transports tend to go back to the homeland and twiddle their thumbs rather than forming a continuous train of reinforcements.
 
This is the first time in any AI version that I've seen such a blatant mis-use of transports. I've seen sneak attacks without transports before, but this is the first sneak attack I've seen where the AI brought transports, then didn't bother doing anything them. (Eventually they landed the large stack on my territory next to a coastal city, and it turned out that they had several marines, infantry and SAM infantry.)
 
Keep the examples coming preferably in Better Than BTS builds but anything will do. Even without coding, we should be able to replicate AI invasion behaviour in controlled world builder examples and thus hone down on the problem.

It seems that reading your thoughts, it looks like the AI has hesitated way too long even when it had a clear target. Even if you could just decrease the hesitation, you would at least get closer to the simple tactic you suggested that an AI can employ:

Take him by surprise,
Grab a city,
Smash the human's counterattack stack,
Sue for peace.

This behaviour is already fairly generic in the AI's approach if it doesn't hesitate. If it is successful, it makes the expenditure in building an invasion force worth while at least on a basic level.

I've been concentrating on Better Than BTS but if I spend the effort to upgrade stock BTS to Solver, then branch off to you link, I'll take a look at this example thanks.

Cheers.
 
Keep the examples coming preferably in Better Than BTS builds but anything will do. Even without coding, we should be able to replicate AI invasion behaviour in controlled world builder examples and thus hone down on the problem.

It seems that reading your thoughts, it looks like the AI has hesitated way too long even when it had a clear target. Even if you could just decrease the hesitation, you would at least get closer to the simple tactic you suggested that an AI can employ:

Take him by surprise,
Grab a city,
Smash the human's counterattack stack,
Sue for peace.

This behaviour is already fairly generic in the AI's approach if it doesn't hesitate. If it is successful, it makes the expenditure in building an invasion force worth while at least on a basic level.

I've been concentrating on Better Than BTS but if I spend the effort to upgrade stock BTS to Solver, then branch off to you link, I'll take a look at this example thanks.

Cheers.

Agreed. Of course, it can't always be as simple as that -- and the AI should take follow-on steps to correct (such as reinforcing newly-taken cities). But I definitely think that if the AI has gotten the idea to do a dagger-style attack on a city and it has the opportunity to make it, it really should do it. They don't necessarily have to burn down the city, even if they take it, then the human player re-takes the city the next turn, he's still lost all of his culture improvements. (And, more importantly, the human has been forced to react to the AI instead of vice-versa.)

Of course, a better idea is to just burn down the city altogether -- really, that would've been a far more advisable course for the AI in this situation. I recall a game on Monarch level played on Warlords where I made the mistake of garrisoning my coastal capital with three longbowmen well into the era of cavalry. The French declared war in a sneak attack, landed six cavalry (of course, my own cavalry and riflemen were oriented to the interior of my continent, facing off other enemies, and were out of range,) made quick work of the longbows and burned down my capital. I destroyed their cavalry, sunk some of their ships and fishing boats, and then had to admit that I couldn't proceed against them.

The AI really needs to do more hit-and-run attacks like this, I think.
 
Perhaps with more examples it will be clear what exactly the problem is with amphibious attack. In other words whether it is a "hesitation" problem when it finally comes for the fleet to pick a target, or is it a backup problem with timing errors in transport support fleets arriving or is it both?
Cheers
 
There is definitely an issue with loading up reinforcements but I don't know yet why or what can be done. When a civ is launching a naval invasion (of another island/continent) is uses AREAAI_ASSAULT which should cause it to produce invaders to ship over. After the first wave the transports will return to the motherland but they seem to fill up in a trickle and don't get around to leaving usually ... my hunch is that one of two things slows the AI down:

- Once the transports leave to make their delivery, troops produced while they're away may not go to the city the transports will return to for fast pickup. I don't see any obvious coordination of this yet.
- Transports or more importantly groups of transports may wait until they are completely full again before making the second trip. If you have 4 transports waiting in a city they may wait till all 4 are full before sending reinforcements over ... this is the behavior for the initial wave which is good (large stack at once), but the AI should prioritize getting any full transport over there safely for reinforcements. I don't know if it does this or not.

As for the "hesitation" of troops in transit, I have a guess as to what might have caused it ... in CvUnitAI::AI_assaultSeaTransport there's the following:

Code:
		if (pLoopPlot->isCity())
		{
			if (iVisibleEnemyDefenders * 3 > iCargo)
			{
				iValue /= 10;
			}
			else
			{
				iValue *= iCargo;
				iValue /= std::max(1, (iVisibleEnemyDefenders * 3));
			}
		}

iVisibleEnemyDefenders would change depending on whether the transport group could see the city or not ... I'm not sure whether this function would get called multiple times as the transports move or whether they would only pick a target once. Seems like it very well could happen multiple times if the units are "woken" by passing enemy ships and the like.
 
It really does appear to be a "clock work problem". All the cogs have to work in harmony for the AI to carry off an invasion "successfully" (as defined by the criterion" JKP has established above as a base performance goal for an AI invasion).

This is obviously why the problem is quite tricky. Hopeful ways forward seem to be:
1) Reduce the hesitation when picking a final amphibious attack location by possibly limiting the number of loops through the iVisibleEnemyDefenders code.

2) Somehow get backup resupply transports to operate independently once each is full, so long as the transport has some minimum level of naval defenders to accompany it.

These are not simple problems unless!......the behaviour is correct in the code but masked by a bug. Fingers crossed.....
Cheers.
 
One way to start on the 'higher level planner', without making a huge architecture change is to have a sort of 'repository' of plans made this turn so far...

so, in one location, you can do the following...

if (blah)
- decide now is the time to set sail with all our troops
- DecisionRepository::SetAssaultState(kInitialWaveLaunched)

then at all the other places in various code, you can check for various decisions

if (DecisionRepository::GetAssaultState() == kInitialWaveLanded)
switch(DecisionRepository::GetAssaultType())
case kCaptureCity:
DecisionRepository::GetTargetCity()
case kHarrassment:
etc

In further thinking about it, you probably want to factor it a bit differently, and have a different class for different overall ideas, so just have a class for a Assault plan. There already is a very minor version of this, in that it knows it is doing an assault and what the target city is.

It doesnt know:
- the first wave has landed, so bring reinforcements faster
- the target city is too strong, so either land troops in easy to defend spots and get more troops or pick a different city
- doesnt pick target friendly cities to send reinforcements waiting for transports (the empty transports have to get there first, then it sends troops)

having an overall assault plan class would be a way to encapsulate all the decisions without having to have all the other classes have to know more about each other (playerai, unitai, etc)

-Iustus
 
Sometimes from little things, big things grow.... Yakk is kinda suggesting this "high level planning" on the "Threats/Targets/Reserves/Plans" forum as well.....

I guess it makes sense to design a first pass new planning class. The issue seems to be that it will be a "hybrid" solution to fit into an existing problem and so could suffer from all sorts of problems if it is expanded to fit all the other "planning scenarios" down the track....

Amphibious invasion is a nice example of the fundamental issues of the existing design. I wonder if it's a good idea to try both strategies:

1) Push the code to it's limit to get amphibious invasion reasonably working!

2) Ditch 1) and instead begin a new branch in the project with a "planning" class heirachy and subsequent object structures through the AI.

It'll be up to you guys with proper C++ environments to see which is the best way to go short term. Enjoy the challenge!!!
Cheers.
 
It really does appear to be a "clock work problem". All the cogs have to work in harmony for the AI to carry off an invasion "successfully" (as defined by the criterion" JKP has established above as a base performance goal for an AI invasion).

This is obviously why the problem is quite tricky. Hopeful ways forward seem to be:
1) Reduce the hesitation when picking a final amphibious attack location by possibly limiting the number of loops through the iVisibleEnemyDefenders code.

2) Somehow get backup resupply transports to operate independently once each is full, so long as the transport has some minimum level of naval defenders to accompany it.

These are not simple problems unless!......the behaviour is correct in the code but masked by a bug. Fingers crossed.....
Cheers.

Glider,

Just to follow up, eventually H/F unloaded their army on a square immediately adjacent to one of my coastal cities. They actually had quite a few marines in the stack, along with Infantry. If they'd had that in the transports to begin with, they probably could've burned down at least two of my (comparatively unprotected) cities, or seized and invested at least one of them (hopefully reinforcing with follow-on forces). Of course, by the time they'd landed, I had built up a sufficient force that was able to take them down in just one turn.

I will upload the save file shortly. I want to play at least three games from start to finish using the 'normal' version, and am currently involved in a new game, but will try Better AI next.
 
I will upload the save file shortly. I want to play at least three games from start to finish using the 'normal' version, and am currently involved in a new game, but will try Better AI next.

Good idea to compare behaviour with base. We need more examples definetly. I'm still a little confused about amphibious landing behaviour in terms of exactly what the problem is. I wonder if anyone else has sharpened it down so that at least there might be a >50% that we can improve amphibious landing without adding another layer onto the AI. It sure would be nice to have something in the hands now rather than later!

Cheers.
 
The higher level planner for putting cities and units into assault groups is definitely an awesome idea, if it can be done well it will be a huge leap forward for the civ AI.

Back to smaller (and certainly sooner) steps for a moment ...

I've found a section of the city production AI which could be improved to send more reinforcements/second waves when the AI engaging in transcontinental war.

CvCityAI::AI_chooseProduction() handles production decisions for AI cities. When the AI is only at war with players who have no cities on the same island/continent as the city that's making production decisions, the AI will be running AREAAI_ASSAULT (or one of two variants of this) which has several effects on unit build decisions. In particular, in the middle of the very long chooseProduction function there's a special section just for handling assault scenarios. It's flow goes like this:

Code:
if( have many more transports than escort ships )
    1/2 time build an escort ship

if( have many more transports than attack ships )
    if( best attack ship can bombard )
        1/2 time build attack ship

if( more attack land units in area than transport capacity )
    always build a transport ship

if( any not full carriers )
    always build a carrier plane

if( have 4x more transports than carriers )
    always build a carrier

if( any not full missile carriers )
    always build a missile

Notice something missing there? There's no handling for building invasion troops, not even some fraction of the time. After this section of code there is no further piece where the AI would emphasize building invasion troops over other potential priorities ... there are several checks for building troops if the AI is in and land war, but not if it's attacking someone overseas. Because of this, the AI cities feel no particular need to fill up any transports that may be sitting waiting for troops.

Somewhere in the above flow we should insert code to build more invaders ... it should only apply to cities in the AI's primary area or if there are any not full transports waiting in the area (sea assault transports will almost always return to the primary area, potentially ignoring idle stacks stranded on islands ... but that's a separate discussion). My sense is that even in these situations the AI should only choose a military unit some fraction of the time, 1/2 or a 1/3 or something.

The first question then is where to insert the land troops clause ... should carriers and missiles take top priority? Or should the AI prioritize troops for idle transports?

The second question is should there be any new conditionals on the production of fighters/carriers/missiles ... right now they're built 100% of the time the code reaches this point when there's a need, regardless of how fast the city can build them. One thing that might help would be to introduce a chance (ie only build 1/2 time or less) for some of these units if the city has no airport or other experience boost ... that way the need would more likely be filled by cities which would give the units experience. This same idea of probabilistically shifting production to cities with experience giving buildings/great people could be extended to a few other sections of production code where the AI is picking units it may not desperately need.
 
I was directed here by jkp1187. I'm sorry, I can't contribute to code solutions, but if you could make the AI able to actually launch naval invasions that would have been great. Alright, keep up the good work guys :)
 
I agree with you for the second question, indeed it will give unit of better quality and won't fill the iMaxUnitSpending with "useless units".

I have a code question too on :
Code:
GC.getGame().getSorenRandNum(2, "AI train escort sea") == 0

Did this function return 0 or 1 ?
I didn't understood very well how it works :crazyeye:
Thanx.

Armand.
 
I agree with you for the second question, indeed it will give unit of better quality and won't fill the iMaxUnitSpending with "useless units".

I have a code question too on :
Code:
GC.getGame().getSorenRandNum(2, "AI train escort sea") == 0

Did this function return 0 or 1 ?
I didn't understood very well how it works :crazyeye:
Thanx.

Armand.

the "2" is saying generate a random number either in the range 0-1

getSorenRandNum(100, "blah") would return a number in the range 0-99

-Iustus
 
Thanx ;) I better understand now.
So in getSorenRandNum(100, "blah") the "blah" in fact is the seed of the random generator I think?
 
Man, I have a great game up until I conquer my enemies on my own continent. Then it's just a cakewalk and not so enjoyable because my enemies overseas don't attack me. =( Then it's straight up to corporations and by that time my biggest opponent is outproduced 5 to 1. :/

Man, I would love you guys if you could actually pull this off.

I guess I just have to play land maps in the meantime. :/
 
Back
Top Bottom