[SDK] Lead from Behind

They should add this into Better AI. It would help them with one of their problems with units just piling onto the player. Making it almost impossible to defend efficiently.
 
I'll be looking into merging this into PIG Mod. Not sure where you got the inspiration for this but I and others have been saying for a while now that something needed to be done with the bestdefender code, particularly in regards to how great generals are picked as defenders. The other area of the bestdefender code which is problematic IMO is that units with many first strikes will get picked to defend in battles at very bad odds when other better units are available. Since highly promoted drill units will usually have at least 10 or 17 xp then it's likely this mod will help the problem of drill IV units dying off to units which are immune to first strikes when cheaper units are available to defend. For example, a drill IV longbow will unfortunately defend against a Flanking 2 knight (immune to first strikes) instead of an umpromoted longbow.

Haven't had a good look at your changes yet but I'll try to do that now.
 
Have had a bit of a look at the code now and I think it looks great. One thing that might help people to understand the effect of this mod is to post a couple of examples (maybe screenshots?) showing some situations where the changes will make a difference. I think many people, including myself, don't have a great understanding of the bestdefender code in the first place so some examples would really help to drive home the point of this modcomp.
 
The other area of the bestdefender code which is problematic IMO is that units with many first strikes will get picked to defend in battles at very bad odds when other better units are available. Since highly promoted drill units will usually have at least 10 or 17 xp then it's likely this mod will help the problem of drill IV units dying off to units which are immune to first strikes when cheaper units are available to defend. For example, a drill IV longbow will unfortunately defend against a Flanking 2 knight (immune to first strikes) instead of an umpromoted longbow.
I'd read some posts regarding that, so did take a look at it. I don't really see a problem with the way it's implemented though - it only factors in Defender's first strikes if the attacker is NOT immune. It also factors in Attacker's first strikes if the defender IS immune (as a positive).

In either case, it works out to a bonus to your Ranking (how good a defender you'll be) of 8%/first strike and 4%/chance of first strike. (That's based on a COMBAT_DAMAGE xml setting of 20).

In your example, assuming no other promotions, the drill IV longbow and the unpromoted longbow would be considered equally good defenders. Which then goes to the 'tie-breaker' - something called 'Unit Cycle', which I haven't looked into, but my guess is it's the order in which the units were produced. So since the drill IV longbow has probably been around longer (in order to gain all that experience), it gets picked as defender. With my mod of course, that extra experience would make it considered more valuable, hence would only be picked if the attacker was really weak.

Now, for when first strikes are factored in, whether that 8%/strike+4%/chance is reasonable or not is a judgement call. I could add a setting to allow you to adjust that ...
 
I'd read some posts regarding that, so did take a look at it. I don't really see a problem with the way it's implemented though - it only factors in Defender's first strikes if the attacker is NOT immune. It also factors in Attacker's first strikes if the defender IS immune (as a positive).

In either case, it works out to a bonus to your Ranking (how good a defender you'll be) of 8%/first strike and 4%/chance of first strike. (That's based on a COMBAT_DAMAGE xml setting of 20).

In your example, assuming no other promotions, the drill IV longbow and the unpromoted longbow would be considered equally good defenders. Which then goes to the 'tie-breaker' - something called 'Unit Cycle', which I haven't looked into, but my guess is it's the order in which the units were produced. So since the drill IV longbow has probably been around longer (in order to gain all that experience), it gets picked as defender. With my mod of course, that extra experience would make it considered more valuable, hence would only be picked if the attacker was really weak.

Now, for when first strikes are factored in, whether that 8%/strike+4%/chance is reasonable or not is a judgement call. I could add a setting to allow you to adjust that ...

Wait. Let's just be clear on something first. I'm not sure that you noticed but a D4 longbow also gets the +10% vs. mounted, so it is technically better than the unpromoted longbow at defending, but my problem is that the main utility of a D4 unit is his first strikes and defending when none of them can be used is a massive waste. I would be tempted to apply a very slight negative weight per first strike that can't be used due to the enemy being immune. Most D4 units have 4-7 or 3-6 first strikes. Because these units are usually very strong defenders against units not immune to first strikes, I think it would be preferable to have cheaper units defend against such units.

Still, even when the enemy is not immune to first strikes, the way first strikes are factored in is a bit ridiculous in some situations. The worst example I've seen was cooked up by DanF5771 here.

Before that, the worst example I'd seen was in my post three above that one.

In its current implementation, the main problem is usually with damaged units that have first strikes. Because of the way first strikes affect the ranking these units end up high on the list when they shouldn't be. Perhaps a solution would be to reduce the boost per first strike in a way proportional to the damage the defender has. After all, a units hitpower is reduced when it's damaged so the first strikes really are of lesser value anyway. But let me just say I don't really understand the bestdefender code all that well.
 
I'm not sure that you noticed but a D4 longbow also gets the +10% vs. mounted, so it is technically better than the unpromoted longbow at defending, but my problem is that the main utility of a D4 unit is his first strikes and defending when none of them can be used is a massive waste. I would be tempted to apply a very slight negative weight per first strike that can't be used due to the enemy being immune.
You're right, I'd forgotten about the +10% vs mounted. I'm a bit torn on applying a negative adjustment though - while I agree that if a D4 unit can't use their first strikes, it's a big waste, it's also true that they must have gained a lot of experience (to get that D4). And that experience (with my mod) would already make them less likely to defend. So does it need a double adjustment?

And if I'm going to apply a negative for that, shouldn't I also apply a negative for other bonuses/promotions that don't apply? Like say +50% vs Melee when the attacker is Mounted? Or even +25% City attack? While it may make sense, I'm not sure how easy it'll be to factor it all in - but I will look into it.

In its current implementation, the main problem is usually with damaged units that have first strikes. Because of the way first strikes affect the ranking these units end up high on the list when they shouldn't be. Perhaps a solution would be to reduce the boost per first strike in a way proportional to the damage the defender has. After all, a units hitpower is reduced when it's damaged so the first strikes really are of lesser value anyway.
Very true - I agree the Ranking adjustments for First Strikes should take into account the actual damage that could be done, instead of just the XML setting.

I also need to correct my last post - following the links you gave, and reading the post by DanF5771 made my double-check my own calculation, and sure enough I had it wrong. It's +16%/first strike+8%/chance of first strike (double what I had said). While I thought 8%/4% seemed reasonable, I have to agree that 16%/8% sounds excessive.

What I also hadn't considered (until looking at his example) is that having first strikes and being immune to your targets first strikes has this applied twice (i.e: In that example, it was 3-6 first strikes, which works out to 72% - and same for the attacker. But it's applied as Ranking * 1.72 * 1.72 (or Ranking * 2.9584). I think at most it should be additive (72%+72% or Ranking * 2.44)).

Anyway, I'll give it some thought, look at the code, and see what I come up with.
 
It's great to hear you are looking into it!

I agree that it doesn't quite feel right to go and apply a negative effect to unusable first strikes because you could then ask the question where do you draw the line? Other 50% bonuses etc.? But do keep in mind that it's not quite as bad as that because first strikes, like combat promotions, are very general promotions and work against every unit class. Also, units with large specific bonuses (e.g. spearmen) tend to have lower strengths so they are rarely picked as a best defender when that bonus is not in effect unless they really are almost the only unit left on the tile.

Anyway, I haven't tested any of your changes yet but I too would hope the experience modifier to the code will help to prevent highly promoted drill units from defending when there are cheaper units that could perform almost the equivalent job.

I'll PM RJ to see if he can offer his opinion on the matter.:)
 
I agree that it doesn't quite feel right to go and apply a negative effect to unusable first strikes because you could then ask the question where do you draw the line? Other 50% bonuses etc.? But do keep in mind that it's not quite as bad as that because first strikes, like combat promotions, are very general promotions and work against every unit class. Also, units with large specific bonuses (e.g. spearmen) tend to have lower strengths so they are rarely picked as a best defender when that bonus is not in effect unless they really are almost the only unit left on the tile.

I disagree. The function's name and purpose is to, literally, pick the best defender. You don't need to apply a negative effect to first strikes, just make them not factor into the best defender choices when the attacker is immune to first strikes. After all, why shouldn't it always pick the best defender? The promotions that benefit certain unit classes shouldn't even take effect in the decision for best defender unless it affects the unit that's attacking. Otherwise, it wouldn't be the best defender.
 
I disagree. The function's name and purpose is to, literally, pick the best defender. You don't need to apply a negative effect to first strikes, just make them not factor into the best defender choices when the attacker is immune to first strikes. After all, why shouldn't it always pick the best defender? The promotions that benefit certain unit classes shouldn't even take effect in the decision for best defender unless it affects the unit that's attacking. Otherwise, it wouldn't be the best defender.
Ah ... but 'Best' for this battle? Or 'Best' in the larger picture? Sometimes the 'Best' unit to defend is the one you can most afford to lose - so that your stronger units can live to fight another day - maybe when the odds are more in their favor.

Anyway, thinking about it some more, I do agree with NOT applying negative adjustments for bonuses/promotions that don't apply. I think that's really factored in already - whether in weaker strength or more experience (hence more valuable).

What I am planning to do is actually something mentioned in that post by DanF5771 - replace the entire Ranking calculation with the actual combat odds. That way, we can be sure first strikes will get factored in appropriately, since it's using the actual chance of winning the battle. I'll still leave my 'more valuable' check in (with flags of course, so if someone just wants the combat odds change they could do that), but I'll need to consider how best to apply it.

The bad news though is my laptop just crashed :( so I have no dev environment at the moment - it may be a few days (or more ...) before I can work on this.
 
Great job on this mod Uncutdragon. It's actually not my cup of tea as I think the game of civilisation should have a combat model based around stacks of units fighting stacks of units where the individual unit is fairly meaningless (maybe civ5). So I don't quite like the focus that civ4 put on high experience 'super units'. But since the developers chose that path in civ4 and since it takes a lot of effort from the player to create such super units, it's fairly logical that players want to preserve these units in offence and defence. The approach you took accomplishes that goal flawlessly. Now the game automatically only lets 'super units' fight the defensive battles that human players would have chosen them to fight on offence. I do think it will help the human a little as the human player is more likely to focus on preserving strong units.

The issue raised by PeaceOfMind of some errors related to how the game basically (before your adjustment) creates the ranking of units especially related to first strike units is a good one. From what I've read about it in previous threads (where some code was posted in the thread IIRC), the strength of the first strikes is regularly overestimated. I also read that it was NOT possible to just use the combat odds because that would mean that when two 150 unit stacks meet, the calculation to choose the best attacker would be humongous. For each attacker, the combat odds against each defender have to be calculated resulting in 22500 applications of the combat odds calculation for choosing the first attacker and first defenders and similar numbers of applications of the combat odds calculation for the second and third and further attackers and defenders (although some of those match ups could be cached from the first matchup). The combat odds calculation is not that bad for smaller numbers but likely becomes an issue for such large numbers.

(I know that 150 unit stacks aren't typical, but I've seen them in huge map games in the late game and the game still has to work in such instances.)

So I guess an improvement of the basic ranking code where first strikes are valued better is needed. If you could tell the posters in this thread more about whether promotion effects that don't improve the combat odds still count in the ranking and how strong the first strike promotions count (8/16% right) in those calculations, then we might be able to help you to improve the basic ranking formula (before your adjustment).

My very basic approach for valuing the first strike promotions would be to make its effects on ranking multiplicative with other effects instead of additive. A unit with huge defensive bonuses will do far more damage per first strike and will far more easily hit per first strike than a unit without such bonuses.

So something like basic ranking defender = base strength * (defender bonuses that apply against attacker - attacker bonuses that apply against defender) * (first strike effect if attacker not immune).
The base strength is the strength of the unit where effects of reduced hitpoints are already applied. The factor of defender and attacker bonuses is similar to how they are applied in the combat formula (as in the combat explained article, 1+x/100 as defender has x% net bonus against attacker and 1/(1+y/100) when the attacker has a y% net bonus versus the defender). The first strike effect could then be something like 1 + 0.08*#first strikes + 0.04*#first strike chances. Something like that.

edit: the first strike effect could also work against the defender of course when the attacker has more first strikes. So then it has to take the inverse form: 1/(1+0.08*#first strikes + 0.04*#first strike chances).
 
I disagree. The function's name and purpose is to, literally, pick the best defender. You don't need to apply a negative effect to first strikes, just make them not factor into the best defender choices when the attacker is immune to first strikes. After all, why shouldn't it always pick the best defender? The promotions that benefit certain unit classes shouldn't even take effect in the decision for best defender unless it affects the unit that's attacking. Otherwise, it wouldn't be the best defender.

Do you not realise the very simple assumption you are making? You are assuming the best defender is necessarily the one with highest survival odds. In fact, associating 'best' with this measure is arbitrary and it would not be hard to argue there are other measures that are equally reasonable. Already it does not account for the fact a transport ship (like a galleon) can be loaded with valuable units. If two units are roughly equally good as defenders but one costs 100:hammers: and the other costs 10:hammers: I think it would be entirely reasonable to call the "best" defender the cheaper one. Personally my idea of a best defender is one that is most suited to defending in that particular instance in that it will be one of the most likely to survive but also one of the least costly to lose.

Ah ... but 'Best' for this battle? Or 'Best' in the larger picture? Sometimes the 'Best' unit to defend is the one you can most afford to lose - so that your stronger units can live to fight another day - maybe when the odds are more in their favor.

Anyway, thinking about it some more, I do agree with NOT applying negative adjustments for bonuses/promotions that don't apply. I think that's really factored in already - whether in weaker strength or more experience (hence more valuable).

What I am planning to do is actually something mentioned in that post by DanF5771 - replace the entire Ranking calculation with the actual combat odds. That way, we can be sure first strikes will get factored in appropriately, since it's using the actual chance of winning the battle. I'll still leave my 'more valuable' check in (with flags of course, so if someone just wants the combat odds change they could do that), but I'll need to consider how best to apply it.

The bad news though is my laptop just crashed :( so I have no dev environment at the moment - it may be a few days (or more ...) before I can work on this.

I second the concern raised by Roland (one I would have raised if he had not done already!:p) that you would need to give very careful consideration to a drastic change to the bestdefender code that made it much more computationally expensive. Seeing you're a proficient C++ programmer I'm sure you'd have methods for finding the time complexities of each algorithm, and I'm pretty sure the actual combat odds takes a good deal more layers to compute.

I could even postulate that the bestdefender code was intentionally left separate from the combat odds because of this difference in complexity, but I can doubt that at the same time because this code was written before the combat odds code by Deep0, to my knowledge.

I think what this means for us and this mod is that we will have to live with a rough approximation to combat odds that is provided by the bestdefender code but just try to tweak it based on our greatest complaints. Adjusting it for making GGs less likely to defend as well as high experience units etc. is a good idea IMO. Adjusting it for first strikes is a bit less urgent and trickier IMO. We don't have the luxury of using the exactly correct code for odds.
 
You're both right - I hadn't really looked at the combatOdds before, but now that I do, it would take quite a bit longer to run.

The real problem with First Strikes, is the affect varies according to the difference in strength. If you're equally strong, the affect is 13.6% (so not that far off the 16% currently used). If you're a bit stronger though, the affect goes up - if you're a bit weaker, the affect goes down (considerably! even at 90% of attacker's strength, you're FS is only worth an extra 8.3%).

I calculated some real odds and looked at the affect a FS has on them - then just played around with formula's until I found something that gave me a reasonable estimate. This is what I came up with:

(((Dstr / (Dstr + max(Dstr,Astr)) * 2) ^ 5) * 0.136)

(Dstr = Defender's strength, Astr = Attacker's strength, result is the impact of a Defender's first strike)

Some real numbers, so you can see how it works. Assuming Attacker strength of 10, both units in full health, and Defender has 1 FS. Below are the odds without the FS, odds with the FS, then my estimate (applying above formula to the odds without FS)

Code:
Defender Strength    Odds without FS   Odds with FS     Estimated odds
5                        991                  987              973
8                        751                  700              694
10                       500                  432              432
12                       272                  219              235
15                       99                   73               85
20                       9                     5                7

In the code of course, I'll be applying the formula to the Ranking (not the odds), but the affect is the same. Also, I simply look at how many more FS's a unit has, treating chances as 1/2 a FS (has a small impact on odds, but not a lot).

e.g: Defender has 4-7 FS's, Attacker has 2-3 (taking immunity into account of course)
Treated as Defender 5.5, Attacker 2.5
Treated as Defender 3, Attacker none
 
You're both right - I hadn't really looked at the combatOdds before, but now that I do, it would take quite a bit longer to run.

The real problem with First Strikes, is the affect varies according to the difference in strength. If you're equally strong, the affect is 13.6% (so not that far off the 16% currently used). If you're a bit stronger though, the affect goes up - if you're a bit weaker, the affect goes down (considerably! even at 90% of attacker's strength, you're FS is only worth an extra 8.3%).

You have to be careful with this kind of analysis as there is a huge effect of the discrete mechanics of the combat odds. For instance, a unit of strength 10.01 has odds of 62,36% to beat a strength 10 unit, while a strength 10 unit has 50% odds (no first strikes). This of course doesn't mean that a 0.01% jump in strength will in general have an effect of 2*12.36%.
These effects are less prominent with first strikes but still exist.

(((Dstr / (Dstr + max(Dstr + Astr)) * 2) ^ 5) * 0.136)

What do you mean with max(Dstr + Astr)? The maximum of a single value (Dstr + Astr) is that same value. Did some part of the formula get lost?

In the code of course, I'll be applying the formula to the Ranking (not the odds), but the affect is the same. Also, I simply look at how many more FS's a unit has, treating chances as 1/2 a FS (has a small impact on odds, but not a lot).

e.g: Defender has 4-7 FS's, Attacker has 2-3 (taking immunity into account of course)
Treated as Defender 5.5, Attacker 2.5
Treated as Defender 3, Attacker none

Your multiplier looks good for low power defenders but not so great for high power ones. But it's hard to just think up a formula that does what you want, so it's quite an accomplishment to find a reasonable one out of nothing.

Is the ranking based on the combat odds? Are the multipliers from other promotions also based on the effect that these promotions have on the combat odds? Is the effect of a combat 1 promotion on the combat odds similar to the effect of a combat 1 promotion on the ranking? If the ranking has little to do with the effect of these promotions on combat odds, then a multiplier based on the effect of first strikes on the odds won't work well compared to the effects of other promotions.

It's impossible for me to see whether your approach works well or not if I can't compare it to the rest of the ranking formula and I have no knowledge of how that looks. I would like to help but can't do that without the details of the ranking calculations.
 
You have to be careful with this kind of analysis as there is a huge effect of the discrete mechanics of the combat odds. For instance, a unit of strength 10.01 has odds of 62,36% to beat a strength 10 unit, while a strength 10 unit has 50% odds (no first strikes). This of course doesn't mean that a 0.01% jump in strength will in general have an effect of 2*12.36%.
These effects are less prominent with first strikes but still exist.
You're right, I am going to have to look at this further. Rather than looking how much a FS increases the odds, I need to look at how much I need to increase the strength by to get an equivalent affect ...
What do you mean with max(Dstr + Astr)?
Sorry - that should've been max(Dstr,Astr).

Is the ranking based on the combat odds? Are the multipliers from other promotions also based on the effect that these promotions have on the combat odds? Is the effect of a combat 1 promotion on the combat odds similar to the effect of a combat 1 promotion on the ranking? If the ranking has little to do with the effect of these promotions on combat odds, then a multiplier based on the effect of first strikes on the odds won't work well compared to the effects of other promotions.
The Ranking is pretty much just the Defender's current strength. That's taking into account any damage, fortification bonuses, Defender unit bonuses/promotions, Attacker unit bonuses/promotions (as a negative). It's the same calculation used when actually resolving combat (as well as computing the odds).

It does do some manipulation to the Ranking after that:

If it's a 'World Class' unit, it cuts the ranking in half (I have a flag to remove this, since the basic intent of it is taken care of in my 'more valuable' calculation). The fact that this exists actually shows that they had at least the idea of protecting more valuable units, but just implemented with very limited scope. (In fact, there are NO world class units in BtS, so it doesn't actually apply at all).

It also reduce the ranking if the unit is carrying other units. That's based on (Asset Value of unit) / (Asset value of unit + sum(Asset value of carried units))

And other than that there's just the First Strikes adjustment that we're looking at now. That's basically if defender has FS's and attacker is NOT immune, then increase Ranking by 16%/FS+8%/chanceFS. And if attacker has FS's and defender IS immune, increase Ranking again (another multiplication) by 16%/FS+8%/chanceFS.

Anyway, I'll play with it some more ...
 
just a thought, and it's probably a little arbitrary...but what if a units free strikes were simply discounted from working out the best defender if health is less than say 80%?
 
Sorry - that should've been max(Dstr,Astr).

Maybe I should have guessed that. It would have been the most logical typing error.


The Ranking is pretty much just the Defender's current strength. That's taking into account any damage, fortification bonuses, Defender unit bonuses/promotions, Attacker unit bonuses/promotions (as a negative). It's the same calculation used when actually resolving combat (as well as computing the odds).

You could try a formula of the form:

ranking = strength * (1 + 0.06 * # first strikes + 0.03 * # first strike odds) and see how the combat odds of a unit with first strikes compares to the combat odds of units that get a similar ranking due to a higher base strength without first strikes. You seem to be good at fitting formulas. The 0.06 and 0.03 will likely have to be changed a bit.

I guess it will be hard to get a very good fitting formula because of the huge jumps in odds when a single hit more or less decides the battle and small changes in strength can cause large jumps in odds. A fit that works well on average will probably be the best that can be done. If you have some software that can draw some graphs of the odds with higher strength or higher number of first strikes, then you could compare the odds better.

Maybe PieceofMind can do some significant number of comparisons with his combat calculator.

It does do some manipulation to the Ranking after that:

If it's a 'World Class' unit, it cuts the ranking in half (I have a flag to remove this, since the basic intent of it is taken care of in my 'more valuable' calculation). The fact that this exists actually shows that they had at least the idea of protecting more valuable units, but just implemented with very limited scope. (In fact, there are NO world class units in BtS, so it doesn't actually apply at all).

You're right that it does suggest that the designers had similar thoughts as you have.

It also reduce the ranking if the unit is carrying other units. That's based on (Asset Value of unit) / (Asset value of unit + sum(Asset value of carried units))

I've heard about that one. I think you should leave that one in. It's very important in making transport units not the stack defenders.

And other than that there's just the First Strikes adjustment that we're looking at now. That's basically if defender has FS's and attacker is NOT immune, then increase Ranking by 16%/FS+8%/chanceFS.

Such large jumps in ranking due to first strikes don't compare well to similar jumps in ranking due to strength. The combat odds would be improved a lot more due to such an increase in strength.

And if attacker has FS's and defender IS immune, increase Ranking again (another multiplication) by 16%/FS+8%/chanceFS.

Wouldn't it make more sense to reduce the ranking of defenders (by the inverse of the factor which would be used if the defender had the first strikes) who aren't immune to the first strikes of the attacker while not changing the ranking of a defender that is immune. That would also work when the attacker has more first strikes than the defender. The left over first strikes would reduce the ranking of the defender.
 
This of course doesn't mean that a 0.01% jump in strength will in general have an effect of 2*12.36%.
These effects are less prominent with first strikes but still exist.
You're right the effect is less prominent. Adding or removing first strikes cannot cause the well-known "jump points" like other combat modifiers can. Really this should make it easier to take into account the effect of first strikes.

The Ranking is pretty much just the Defender's current strength. That's taking into account any damage, fortification bonuses, Defender unit bonuses/promotions, Attacker unit bonuses/promotions (as a negative). It's the same calculation used when actually resolving combat (as well as computing the odds).

I fear there may be a problem here. I noticed you said it takes damage into account. How exactly? I would expect a mistake they have made is to assume the rank of a defender is proportional to its health (out of 100). This would be problematic because a unit that is half health is worse than a full health unit that is half the strength. When you couple this with first strikes it has the effect of making injured first strikers still look fairly strong when in fact they are very weak.

I'm not very good at coming up with appropriate formulae but the reduction in ranking of a unit should probably depend on something closer to the square of its damage rather than a linear factor. The reason it is not just linear is that a unit's firepower is reduced when it is damaged as well.

Maybe PieceofMind can do some significant number of comparisons with his combat calculator.
I don't have that program set up at the moment but if necessary I could dig a bit to find it. I had set it up at the time so that it could output combat odds as a function of one of the variables (e.g. number of first strikes or HP of the attacker), with everything else held constant. It might be useful if we want to look fairly quantitatively at how first strikes affect combat odds in a range of circumstances.
 
Back
Top Bottom