View Full Version : [BTS] AI Tactics - war
glider1 Jun 22, 2008, 11:06 PM 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.
glider1 Jun 22, 2008, 11:19 PM 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.
Yakk Jun 23, 2008, 01:48 PM 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.
Roland Johansen Jun 23, 2008, 02:25 PM 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.
glider1 Jun 23, 2008, 06:28 PM 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!
jdog5000 Jun 24, 2008, 01:03 AM 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.
Yakk Jun 24, 2008, 07:31 AM 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?)
glider1 Jun 24, 2008, 05:36 PM 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.
Yakk Jun 24, 2008, 09:08 PM 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.
Lone Wolf Jun 26, 2008, 04:12 AM 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.
glider1 Jun 26, 2008, 08:14 PM 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.
mjs0 Jun 27, 2008, 08:36 AM 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.
Lone Wolf Jun 28, 2008, 04:17 AM 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.
mjs0 Jun 28, 2008, 05:55 AM 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!
Lone Wolf Jul 01, 2008, 12:22 AM 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.
glider1 Jul 01, 2008, 02:08 AM 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.
Lone Wolf Jul 01, 2008, 05:17 AM 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.
mjs0 Jul 01, 2008, 06:54 AM 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.
Iustus Jul 05, 2008, 01:30 PM 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
glider1 Jul 05, 2008, 04:51 PM Thanks for revisiting some of the thoughts from Better AI. This hopefully will prevent re-inventing a broken wheel.
Cheers.
Nor Me Jul 08, 2008, 01:31 PM Simulations would require a fair bit of code. The combat code requires real units so you'd either have to duplicate all of it or cut and paste it into new functions and have the real ones call them to do the same thing they did before. Then have fake units use that code.
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.
First strike and collateral damage aren't too hard. Just add a bit when they apply. The rock paper scissors modifiers are a bit harder. If most of my attack stack isn't spearmen, then even though half the defenders are chariots, it's not worth adding more. If I'm defending with some spearmen then I might want to add extra defence strength but no more than the total strength of attacking mounted units. If a few of them have shock and I have a war elephant, things start getting complex.
For heuristics, we have:
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?)
I pointed out in your power thread somewhere in this forum that I don't think squared is the right power. I've implemented and tested the formula I came up with. This thread is worthless without code:
int CvUnit::currEffectiveStr(const CvPlot* pPlot, const CvUnit* pAttacker, CombatDetails* pCombatDetails) const
{
int iStrength = currCombatStr(pPlot, pAttacker, pCombatDetails);
iStrength *= (5 * maxHitPoints() + 3 * currHitPoints());
iStrength /= (7 * maxHitPoints() + currHitPoints());
if (iStrength < 1)
return 0;
int iCube = iStrength;
if (iCube > MAX_INT/10000)
{
FAssert(MAX_INT/40000 > 200);
iCube = MAX_INT/10000;
}
int iGuess = 0;
int iNewGuess = 200;
//cube root
int iPass = 0;
while ((iNewGuess != iGuess) && (iNewGuess != iGuess + 1))
{
iPass++;
FAssert(iPass < 20);
iGuess = iNewGuess;
iNewGuess = iCube * 10000;
iNewGuess /= iGuess;
iNewGuess /= iGuess;
iNewGuess += 2 * iGuess;
iNewGuess /= 3;
}
return (iStrength * iGuess)/100;
}
Sorry for the spam, copy and paste is just faster than writing pretty formulae. That's a formula just using health and strength.
I don't know how sensible the 4/3 power is but it's definitely better than just adding up the strengths when the city defenders are likely to be individually stronger.
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.
It's still there. The problem, as in Better AI, is that some of the old code can also cause stacks to attack cities. But it's not hard to make those check the stack comparison code as well if a few units are involved on both sides.
With both those, the AI was much better at taking cities. It did fail sometimes, but the survivors were damaged enough for me to believe that it might have stood a decent chance if not for the RNG gods.
It was much a better judge than I am, anyway. Is there any need to put the data-crunching-challenged player at a disadvantage?
Roland Johansen Jul 08, 2008, 03:57 PM I don't know how sensible the 4/3 power is but it's definitely better than just adding up the strengths when the city defenders are likely to be individually stronger.
I've done some pretty detailed calculations on this 'problem' and the 1.3 power is pretty accurate. I wrote something down about those calculations in one of those threads about strength-power formulas (not in this subforum I think) but I don't know if I can find that thread again.
4/3 and 1.3 are close enough so 4/3 is pretty good. Squaring the strength of units in a stack before adding them is even worse than just adding the strengths of the units in the stack.
For the rest, I think the rock-paper-scissors system of civ4 makes any formula far from perfect because its hard to predict the outcome with a simple formula in all cases. That's why I would prefer simulation. But it's far from impossible to come up with a decent formula and that might be good enough. We humans can also not easily predict the outcome between two stacks of mixed units which seem closely matched in strength. It shouldn't be too hard to come up with a formula that is comparable to the human guestimates when they see a matchup between two stacks.
armand453 Jul 13, 2008, 12:29 PM I noticed that airplane prefer to bombard plot with bonus near ennemy cities, instead of bombarding these cities, even when it have a stack adjacent to the city.
Isn't it better to attack the city in this case?
Armand.
PS: I noticed that with better AI 0.21 don't know if it come from this or the original.
jdog5000 Jul 17, 2008, 03:54 PM The AI will bombard defenses in cities if there are adjacent attackers or attackers on the way. If the walls/culture are at 0, then bombers (or other units running the air attack AI when no bombers are available) do have a 1/4 chance of choosing to bombard plots instead of running airstrikes on the city.
Does this match what you're seeing?
|
|