[BTS] AI Tactics - war

glider1

Deity
Joined
May 29, 2006
Messages
2,905
Location
Where animals hop not run
This sub forum of the "Better than BTS" project is for discussing AI behaviour regarding the tactics of deploying and utilising stacks and units during or prior to war.

Examples of this are AI behaviours current and future for aspects like stack pathing, stack targets, stack divisions into sub stacks, pillaging, plundering, decoys etc etc.
 
What c++ functions are there in the code that cause AI stacks to deviate from their planned target once a border war has been declared? I've seen it change it's mind and that is good to an extent. At least in BTS there is less chance for "oscillation" to occur (where stacks stall never sure of how to proceed) than in the old days of vanilla civ4. I know that there is an individual AI for each unit and that a stack is assigned a target, but what area in the code causes stacks to change mind and pick another target in the field or even retreat?

Reason I ask is it'd be nice to see some more sophisticated behaviour of stacks like making the path to the intended target more ambigious in order to confuse the defender. I realise that is a very subtle judgement for an AI between shortest time to target verses clever tactical balking but hey maybe?

Already this type of behaviour happens by accident.....or design?
Cheers.
 
AIs have "route to" goals, and they proceed at their target directly. I think they reevaluate their goal each round?

The AI also seems poor at "can I actually win this battle" level tactics. Maybe it has gotten better, but I've seen the 313 better AI throw a stack against defenders, when it is almost certainly going to get slaughtered.

I suspect some of this is due to the really crappy "power" based estimates of stack strength.

This can feed back into strategy: losing a battle on the field, but winning economically, can be worth it.

...

There doesn't seem to be a "tactical targets" phase to the AI. That would be where the AI would find threats that it considers important, determine what resources can be deployed against those threats, and then deploy them. Or maybe that has been folded into the game since I last poked into the AI functions, and I missed it. :)

Instead, it seems to make decisions on a per-unit basis.
 
I would help with estimating the strength of a stack. I'm fairly confident that the power of stacks can be estimated somewhat accurate.

There are essentially 2 methods:

Method 1: Just do some simulation runs of the stack of units against the enemy stack of units and determine the likelihood of success based on the success in these simulation runs. The advantage of this method is that it's pretty accurate. The disadvantage might be that it could be hard to run simulation runs inside the game. Maybe the game engine just doesn't make it easy to do this.
I don't think this method will be a burden on the computer as you wouldn't have to do lots of simulation runs to get a somewhat accurate prediction of the result.

Method 2: Come up with a complicated formula encompassing collateral damage, first strikes, various promotions of the units and match ups of units to estimate the strength of the stack. The advantage of this method is that it is surely possible to enter this formula into the game and a computer could pretty quickly calculate the strength of the stack. The disadvantage is that it's pretty hard to come up with a formula that works well in all the possible match ups between 2 stacks of units. There are lots and lots of variables with all the promotions and bonuses that units can get.

I would be in favour of method 1 if someone could code simulation runs into the game. However, if this happens to be impossible, then we should be able to come up with a decent formula for the relative strength of stacks with method 2.
 
Yeah an automated test bed with two stacks facing off in various configurations and terrains, and automated result collecting and statistical analysis would be nice even if only to contrast with the predicted outcomes of "complicated" strength equations.

There is some real fun to be had with developing the behaviour of stacks during conflict. Simplified maps with nothing but opposing stacks facing off with terrain variables and line of sight variables.

Boy does it get complicated quickly though. You could sort out more sophisticated behaviours of two enemy stacks interacting I'm sure, but with the introduction of a third, and then a fourth stack, complexity scales rapidly...

The question is how to control this complexity then?
A beautiful problem!?

Sometimes I wonder if there is not a possible partial marraige between a rules based approach and a "brute force" calculation approach within controlled grid sizes. After all a chess AI is so good largely because of "sophisticated brute force" calculation. I understand that computation times would rapidly explode in civ ooh yeah.

Cheers.

PS) I would like a "Better than BTS" AI to still be playable on my two gig core duo box!
 
If the Civ4 code doesn't provide an easy way to simulate battles, it shouldn't be too hard to write our own function ... just create a copy of the battle code which creates lists of (CvUnit* pUnit, int iHealth) for each side. The extra iHealth would be initialized to the units health and used in the simulation in place of the actual health.

It would only take ~4 simulations to get a rough idea of whether it was highly likely to be a loss, as long as the code wasn't called very often it wouldn't burden the game much.
 
For heuristics, we have:
Presume we attack first with Collateral units.

Calculate roughly how much damage collateral damage units do, in terms of enemy RealPower.

Then add up a total RealPower approximation of our side, and their side.

A first-pass RealPower estimate:
(1/4 of unit-type-specific +% combat bonuses) * (100%+target-square combat bonuses)^2 * (Combat Strength^2, including the combat promotions) * (HP remaining as a percentage) * (50%+HP remaining/2)
only counting units that can attack.

(Mostly, that isn't pulled out of my ass, but rather remembered from the last time I crunched the numbers. The unit-type specific % thing is out of my ass -- we could split power up into unit-type chunks, and use that to weigh our +% combat bonuses?)
 
If only calculating RealPower was as easy as in chess algorithms. Actually, the whole history of assigning power weights to the pieces in chess were devised long before AI programming and has never been altered because they are so beautifully correct and mathematically perfect. Power is simply referenced to the weakest piece on the board the pawn, regardless of the way the piece moves (diagonal/rectilinear/discontinuous).

ie) pawn = 1, knight = 3 pawns, bishop=3 pawns, rook=5 pawns, queens=9 pawns.

Incredibly over the whole history of chess in real life even humans and AI's use this power weighting automatically and readily to consider a sacrifise like rook for a bishop+2 pawns and thus achieve power equality but with tactical initiative.

The weightings have never proven innacurate. They are perfect.

In otherwords to duplicate this, the power of all units and stacks regardless of diversity are referred back to the strength of a single unpromoted warrior.
Swordsman = 6 Warriors.

If only it were that simple!

Non-linearity seems to be the complicated dragon beast in BTS. Thanks for the heuristic real power estimate Yakk. I will go look at the "shape" of the curve. It looks like it is "parabolic" which at least seems to fit the logic of that ancient power assignment in chess, which seems to imply a parabola too?
Cheers.
 
The estimate, for 100% health units with no per-type bonuses, is pretty damn close to accurate. :) It runs into problems with damaged units however.

(ie, a full-HP unit with 1000 RealPower fighting a full-HP unit with 100 RealPower will tend to lose about 100/1000 of it's HP on average -- ie, for every 10 damage it does, it takes 1 damage on average in return).

This falls apart because units that are damaged have a super-linear decrease in RealPower, which results in the damage to their RealPower being more than the 9% projected.
 
Actually, the whole history of assigning power weights to the pieces in chess were devised long before AI programming and has never been altered because they are so beautifully correct and mathematically perfect.

Well, it's not that simple. For details, see

http://www.chessvariants.com/d.betza/pieceval/index.html

But these rough estimates still work.

On-topic, sometimes I notice that siege weapons sitting in cities as a counter-stack measure often never actually suicide theselves against invading stack for collateral damage. They just sit in the city and get destroyed by attacking units, which is usually suboptimal use for siege.
 
Boy is there incentive to work on the strength equations and danger estimation:
Quote Solver Better Than BTS forum:

"Yeah, I've thought about it - my code does make ships rather easy to scare away but the Ai doesn't really have good routines for evaluating danger and relative strength of enemy stacks."

Thanks for the "reality" check on the maths of calculating chess piece strength. As per usual, there's more to it than meets the eye.

Cheers.
 
There is little point making accurate estimates of the relative strength of stacks without also improving the AI's choice of units for attack.
It is quite absurd how often I have seen horse/melee units suicide against my defenses before siege is used.
It is particularly bad with attacks from transports as each transport seems to get treated as its own mini stack with no awareness of the transport full of siege units that is last to attack. I suspect the land based attacks may suffer in the same way when two stacks arrive simultaneously at a border city.
In my last game I watched in disbelief as a decent sized stack with trebuchets settled outside my city and took 4 turns to bombard my defenses down whilst...over the course of those 4 turns at least five units threw themselves at the city which still had defenses and was full of units that were not yet collaterally damaged. (is that a real phrase?)

On-topic, sometimes I notice that siege weapons sitting in cities as a counter-stack measure often never actually suicide theselves against invading stack for collateral damage. They just sit in the city and get destroyed by attacking units, which is usually suboptimal use for siege.
Sometimes siege is the only unit in the city that will not get collateral damage when the cats/trebs/cannons are unleashed. I often keep cannons in cities to defend and do not suicide them, especially if the attackers are on a hill/in a forest.
The important thing is to ensure that the AI is making a 'conscious' decision to defend with them rather than suicide i.e. that it has considered the options rather than simply accidentally making the right decision in some cases.

On another topic, I would like to see AI stacks that are besieging a city take out resupply routes to hinder easy reinforcement of the city during the siege as well as prevent the drafting of resource-dependent units in the city.
 
Sometimes siege is the only unit in the city that will not get collateral damage when the cats/trebs/cannons are unleashed. I often keep cannons in cities to defend and do not suicide them, especially if the attackers are on a hill/in a forest.

Cannons may be useful in defence, especially against mostly-grenadier stacks (str 12=12). But Catapults and Trebuchets in Knight/Musketmen era? Not that much.'

The important thing is to ensure that the AI is making a 'conscious' decision to defend with them rather than suicide

Oh, I agree here.
 
But Catapults and Trebuchets in Knight/Musketmen era? Not that much.'
Everything is situational. If there are knights that will flank my cats/trebs then out they go without a thought, cuirassier/cavalry against cannons...same result...but if the stack does not have flanking units...

Perhaps its just the way I play and defend but I often have fairly weak but numerous defenders in cities with a number of strong defender stacks ready to move to threatened cities.

It often happens that one or two extra defenders (even weak ones that are effectively defensive suicide) can prevent the fall of a city, not by winning but simply by using up an opponents attacks, in order to stall for time just one more turn until the stack of riflemen arrives.

Cats and Trebs fit this role perfectly especially since once collateral damage has been dealt and a few rounds of combat have played out they will end up stronger than, and thus defend before, severely damaged units that are actually more expensive and valuable.

So, flanking units in the attacking stack are one key deciding factor, the other is how much siege they have brought and the potential for my own flanking units to wreak havoc. There are two considerations here...
1. If my own siege could weaken them enough to allow my flanking units a better chance at removing some of their siege then out some of them go!
2. If my own flanking units can succeed without help then I'll hold back until after my flank attacks. An attacking stack with less siege and thus less potential for collateral may then be worth suiciding against because the reduction in attack values may make my remaining defenders strong enough to win if they are not going to get a lot of collateral dealt to them in turn.

So, to sum up...I simply don't see it as a clear cut rule to always suicide siege, I really think it depends on a lot of factors!
 
Well, when the AI does not suicide the siege weapons, they are useless and just lose at >80% odds to my attacking stack.

I often have fairly weak but numerous defenders in cities with a number of strong defender stacks ready to move to threatened cities.

The AI does not.
 
Well, when the AI does not suicide the siege weapons, they are useless and just lose at >80% odds to my attacking stack.

I guess example saves of this behaviour using the Better Than BTS builds might help to forge ahead on improving it. At least with real world saves, we could begin to replicate the behaviour in controlled environments like world builder, and then start understanding and improving the AI's behaviour at the code level.

In Better Than BTS attached saves would be good any time so long as they are actually Better Than BTS save games.

Cheers.
 
I guess example saves of this behaviour using the Better Than BTS builds might help to forge ahead on improving it.

I'll try to provide them.
 
The AI does not.
True, and a good point, but maybe it should. ;)

I guess it depends on the goals of the project. I would like to see the same process we saw with the original Better AI project, which is that the bonuses on higher levels are reduced over time as the AI gets smarter.

In order achieve such reductions we should be cognizant of that goal when making any decisions and teaching the AI tactics that rely on its ability to outbuild the human would be counter to that goal.
The reason I have many old defenders is because I simply cannot afford to either upgrade or replace them. If the AI's bonuses are to be reduced to level the playing field then it will be in the same bind and the factors I pointed out should come into play.

As I say, I guess it depends on the goals of the project.
 
We added some code which to check stack vs stack strengths when deciding when to attack in BetterAI, I have not looked to see what survived in BtS.

However, we backed off on using this as much as we could, because of a bigger problem.

A human player has a much better concept of when a 'losing attack' is worth doing for other reasons, the AI has no concept of this. So, if you change it so that it will never attack unless it will win, it attacks a lot less, and it is a bit more predictable. This is not to mention that you never get the satisfaction of seeing the AI smash up against your strong defenses.

One time it is better to attack than to just sit is if your offensive power (especially vs cities), is stronger than your defensive power. If you have a stack of 10 city attack 3 units outside a city, and the defender has 30 units inside the city, it still might be better to attack with them all, destroy 10 units, but then lose all your units to the counterattack, rather than just sit in place, and lose all your units to a counterattack without killing one enemy unit. Ok, if this is true, what about the middle case, where you lose all 10 units but only destroy 5 enemy units? 3 enemy units? Of course, if you have a big stack of defensive troops within range, it is probably best to move to them and attack a few turns later.

All of these factors lead to backing off the use of the str vs str calcs a bit, so as to have the AI attack even if it would lose, if it could destroy a few units. It is very likely this needs to be tweaked, but we found that throwing it out completely did not work without addressing many other issues that arrived as fallout.

Currently the AI has no way to add up the strength of several different stacks that are all within striking range of the same target. The only way this happens is to move them all to the same spot and group them together, then attack the next turn.

-Iustus
 
Top Bottom