wesnoth icon indicating copy to clipboard operation
wesnoth copied to clipboard

C++ modify "grouping" to improve Ai ?

Open Quandalf opened this issue 8 months ago • 4 comments

Describe the desired feature

Image [Long post]

Ai is very good in choosing targets for attacks by single units. This can also also be easily adjusted via aggression and caution. The one reason why Ai still poses little challenge in many scenarios is: It doesn't know how to group units effectively. And move them towards the enemy. This is very obvious on large maps. https://forums.wesnoth.org/viewtopic.php?t=1578 https://forums.wesnoth.org/viewtopic.php?t=1703 Long ago grouping was introduced. Grouping is s string that affects the Move-to-Targets CA by rating a score for tiles to move-to on the way to the unit's goal(s).

"Move to targets CA evaluates potential targets and moves units toward them. The evaluation takes into account how valuable the targets are (depending on [goal] value=), how easy the AI's units can get there, how exposed to attacks they will be etc. Targets are villages, enemy leaders and enemy units that pose a threat to the AI leader - as well as anything defined in [goal]. Targets only apply to the move-to-targets CA. If a target is within range of the AI's unit(s) on the current turn, other CAs, such as combat, healing or villages are executed first. Thus, a target is specifically not an attack target, but a move target.

(From RCA wiki: https://wiki.wesnoth.org/RCA_AI#The_Candidate_Actions_.28CAs.29_of_the_main_loop_Stage_in_the_RCA_AI)

So grouping affects which tiles units choose on their way to their [goal]. Once a goal is in reach, other CAs take over. Especially if enemy units are a threat to the leader or with a simple enemy-side-goal like this - combat CA takes over.

		[goal]
			[criteria]
				side=2
			[/criteria]
			value=4
		[/goal]

In testing I found that easy to observe: defensive groups "crawl" up to each other - until a point when everybody just attacks.

I say all this to emphasize that grouping does not affect the actual battle, i.e. when units are in range to strike, they attack just the same and choose the same targets as without grouping. It affects how - in which formation and how fast - they get there. Which in turn ofc affects the battle by creating a local numerical strength through previous grouping.

There are two C++ hardcoded grouping settings: grouping=offensive - which is default - and grouping=defensive. There's also grouping=no.

Image

https://wiki.wesnoth.org/AiWML#List_of_AI_Aspects

Both of these settings are not helping Ai to effectively form dangerous attack groups especially on larger maps. They are like extreme ends of the spectrum.

Grouping=offensive has only a very loose unit cohesion and little battle-value.

  • It encourages units to move towards their goals.
  • It establishes a 'group center' with a slight penalty for distance.
  • It allows units to space out more than a turn's move from one another.

This leaves them helpless against tighter player unit groupings of 2-3 or more units within less than half a turn from each other - which is kind of standard behaviour for player units (only except single scouts). This (easily generated) local numerical superiority leads to high Kill/Death ratios for players. Since Ai knows how to effectively attack and deal damage on a single unit basis, it is able to inflict great damage to player troops - if not locally outnumbered. Which often happens due to no real offensive grouping for Ai.

So grouping offensive is basically focused on allowing Ai to reach villages quickly, without total scattering in all directions. Since it is the default grouping, you encounter it most of the time you play against Ai.

Grouping=defensive on the other hand has very tight unit cohesion but great reluctance to move anywhere.

  • It strongly penalizes moves to more than 2 tiles away from a friendly unit.
  • It requires a high power ratio of 1.5 (modified by caution) to advance towards goals.
  • It de-values targets that are far away.

This leads to Ai extremely clustering units, normally right next to one another and also being extremely reluctant to move towards enemies. When does a 1.5 HP local superiority ever happen? For holding chokepoints there are micro-Ais now. What purpose does this grouping setting actually have? It is by itself specialized for a campaign scenario where the player is Persia's Xerxes and the Ai is Leonidas' "300", guarding the pass of Thermopylae. Looking thru campaign scenario files, its main use seems to be in combination with time_of_day to create a rhythm in Ai advancement and the main function here is not the benevolent effect of the group itself, but the reluctance to advance at unfavourable times of day.

Image

Another aspect of grouping is that it cannot sensibly and deceicively be influenced by aggression or caution without having undesirable side effects - like suicidal attacks or no retreating for healing.

In my extensive testing on a large map (ca 120x120) offensive grouping scatters Ai's troops quickly. After the initial village-grabbing it is pretty much useless battle-wise and leads to Ai sending out its units from recruiting in a string-of-pearls - just for them to be slaughtered one-by-one at the line of contact. While defensive grouping leads to massive attacks of concentrated Ai forces that never arrive at their target destination. Mostly Ai builds up troops and parades them in its front yard - waiting for the battlefield to clear, so it can move in with a great HP superiority. I saw a Ai unit grouping needing over 60 turns to reach their high priority goal at the diagonal corner of the map - when the actual travel distance for their slowest units was less than 30 turns to that goal. So they are really slow and reluctant, even when already close to the enemy leader surrounded by only few troops. If two such tight battle formations happen to meet each other tho - the ensuing battle is glorious and deceicive.

Just some impressions from my testing with grouping=defensive and different goals and values on a large map.

Image

You see overly tight groups (that sometimes contain the majority of a side's total units), parading in front of its own castle gates, tight battle formations meeting each other (if they make it that far) and reluctance to enter the enemy's castle. The often resulting "Phalanx" formation has little use in most cases, since as long as there is enough room it makes little sense to not occupy it and if the space is limited units get pushed together anyway.

A slight modification of the defensive grouping's overly and immoderate grouping tightness might be a good idea since it serves little purpose - besides hiding at the wrong time of day (for which the power ratio is mainly responsible). Just allow one more tile of distance between friendly units. Even the offensive grouping might need a little do-over - limiting the maximum spread of the group around 1-3 tiles to tighten its groups a bit to make it more battle-effective - while still upholding the fast village-grabbing.

In many scenarios it seems to me a combined "hybrid" grouping would be needed for Ai to be effective and more dangerous for players to face in battle.

What would that look like? The ideal distance for unit groups - facing enemies - is certainly around 2 tiles: The 1 tile in between them still blocks enemies from moving in and it allows groups to cover larger territory and be quick in its movement. So ideally tiles farther than 3 away from friendly units should be penalized heavily to keep overall group cohesion. Tiles directly next to or exactly 3 tiles away from friendlies should be slightly penalized - only overriden by favourable terrain ratings - to ensure sensible spacing. This way I imagine Ai groups would effectively position themselves and form battle lines along good terrain. This would be similar in local strength to defensive grouping formations, yet more open and flexible and not as exaggeratedly tight. The power ratio on the other hand - our HP versus their HP in a certain radius - should be between 0.5-1 - subject to testing. This would enable Ai groups to move boldly, reach goals quickly. Good positioning and formation help even outnumbered Ai groups to hold positions longer until other bold Ai reinforcement groups arrive to back them up. This ratio should be relative close to suicidal to balance goal-reaching & group-positioning, but would need to be tested. These two factors should be combined with a great emphasis on terrain - like the player has - to adjust Ai group's movement to the map's landscape and to prevent it from walking into simple traps. This focus on terrain - via a multiplier I suppose - should just be strong enough for Ai to position groups along favourable terrain lines, but not so strong that they don't dare cross a flat plane of grass or snow anymore, if it's in the way of their goal.

Combining these factors - strong group cohesion, strong urge to reach goals and strong favour for terrain - should make Ai's offensive groups be effective on the battlefield on any map size, especially on larger and largest maps on which atm it really doesn't shine.

grouping=hybrid? grouping=effective? grouping=attack? So this is a feature request. Obviously I am no programmer and am struggeling myself trying to build a custom CA with Formula AI that leads to better grouping. I just did a lot of Ai observing and testing. I would be willing to test - if that is possible - if anyone was interested in maybe implementing a third grouping in some way (or even modify the existing grouping settings, which probably is a bit of a sacrilege). I understand if no one is really enthusiastic about doing something like this out of the blue - I am thinking however that is has the greatest potential in making Ais more dangerous to players in Wesnoth.

Playing myself and observing other players on youtube I find that a main strategy against Ai is to linger with several units on good terrain - just 1 tile outside of Ai unit's reach and effectively waiting until Ai in the next turn closes the distance like a blind dog - often enough ending up on bad terrain - basically just walking into the trap, only to be attacked by several player units at once the next turn. This sometimes borders on an exploit. A effective unit grouping combining cohesion with purpose and awareness of terrain can counter this tactic and lead to challenging positioning competiton along the given terrain - before the first attack between two groups even started and would greatly increase the strategic depth of Wesnoth, this great game.

This is just a long observation by a small map editor. I don't know how possible or realistic a third "middle" grouping in the C++ code is or how much reluctance exists to editing the already existing grouping settings. I also know that the main Ai guy quit a while ago. But I still think improving Ai grouping is really worthwhile and can improve PvAi gameplay, modding and scenario creation a lot. Many thanks. Appreciative for any reply that goes beyond the 'not-gonna-happen' I expect.

Quandalf avatar Apr 25 '25 13:04 Quandalf

Okay - I dug a little into the source files and grouping seems to be different than how it was described to me originally. In src/ai/default/ca_move_to_targets.cpp is the logic that describes how defensive and offensive groups move to targets.

If I understand that correctly defensive groups consider the entire route as dangerous while offensive groups only check reachable hexes. This makes defensive groups much more hesitant to move anywhere. Also - if(our_strength > 0.5 + get_caution() - is the power ratio (1+ caution) if I'm correct. In move_group is a best_defense check which might be modified to emphasize terrain.

So there is the power ratio, the reluctance to move (over long distances) bc "too dangerous" and the terrain check. I don't know where the difference in unit group cohesion between offensive and defensive group comes from yet?

Are there other files that define this? Does it all depend on the "route too dangerous/ not too dangerous" check plus the power ratio 0.5 + caution check? If too dangerous and power ratio fails Ai doesn't move the group and rallies units at a safe hex - which ofc leads to units pulling together. I'll do some more testing with negative caution values. I have done that but maybe not extensively enough.

Quandalf avatar Apr 25 '25 19:04 Quandalf

If somebody wants to test this on a large map - use a pattern of offensive and defensive grouping attached to the ToD cycle.

I.e. for a 6-phased cycle assign to your AI side 3 phases to grouping=offensive and 3 to grouping=defensive in a intermittend rhythm. Kinda like this

        [side]
		controller="ai"
		side=x
		[ai]
			grouping=defensive
                 [/ai]
                 [ai]
                         time_of_day=morning,dusk,second_watch
                         grouping=offensive			
                 [/ai]	
	[/side]

and you'll see the difference that makes for AI unit movement in groups Much more effective, esp over long distances. Maybe assign a high-value goal too - to get them moving.

It's the closest we come to a makeshift "hybrid grouping" - which combines the strengths of both grouping types.

Quandalf avatar Apr 27 '25 21:04 Quandalf

I think it would help if you partition your post in at least two sections:

  1. Summary of the current state
  2. Your improvement suggestions based on the current state

We do not currently have anyone specifically working on the AI so changes are unlikely to be forthcoming unless someone that is probably not a current regular contributor takes on the effort.

Also my guess is that future efforts are likely to be less in the context of the C++ AI and more in the context of Lua AI(s) like the micro AIs. (Not to say that we would reject changes to the C++ AI.)

soliton- avatar Apr 28 '25 09:04 soliton-

I would summarize it as follows.

Current state: grouping can only be set to no, offensive, and defensive, which are very different. This allows only very coarse adjustments to the AI's grouping behaviour.

Desired state: either adding new intermediate settings (with values TBD), or exposing the variables the grouping aspect tweaks, so they can be adjusted from WML.

In the latter case, grouping might become a boolean, with offensive and defensive becoming presets.

AI0867 avatar Apr 28 '25 09:04 AI0867