New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Some fixes to the Experimental AI #6783
Conversation
@Alarantalara I don't know how much you are around these days, but I saw that you posted some comments recently. If you have time, you may want to have a look too, since a lot of this is your code (although I may have introduced the problem with the data leakage, I don't remember). |
data/ai/lua/ca_recruit_rushers.lua
Outdated
|
||
|
||
local function get_best_defense(unit) | ||
local terrain_archetypes = { "Wo", "Ww", "Wwr", "Ss", "Gt", "Ds", "Ft", "Hh", "Mm", "Vi", "Ch", "Uu", "At", "Qt", "^Uf", "Xt", "Tb" } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might as well update the list of terrain codes while you're copying everything.
^Uf and Tb are the same terrain but ^Uf is deprecated, so it can go. I suggest using Tt, which is what both are aliases of.
Mine rails got a special code and while it's not useful in general, there might be some value in adding it (I left it out since it's more of a functional change in the suggestion, but worth considering).
local terrain_archetypes = { "Wo", "Ww", "Wwr", "Ss", "Gt", "Ds", "Ft", "Hh", "Mm", "Vi", "Ch", "Uu", "At", "Qt", "^Uf", "Xt", "Tb" } | |
local terrain_archetypes = { "Wo", "Ww", "Wwr", "Ss", "Gt", "Ds", "Ft", "Hh", "Mm", "Vi", "Ch", "Uu", "At", "Qt", "Xt", "Tt" } |
I never stopped getting mail and even read it sometimes, but hadn't been paying much attention for awhile. I started getting more involved again about a month ago, but mostly it's just been me going over all the things that changed and realizing how out of date I am. I'm having fun poking around the new features and making my unfinished ideas work again, so it's possible I might eventually do something a bit more substantial. |
Great, good to have you back, even if only partly. I made the change to the terrain codes you suggested (including the mine rails) and added a few other changes as well. I guess I didn't wait what others have to say first after all, but they were simple enough so I just went ahead. |
This is done now, as far as I am concerned. I implemented the suggestions above, added the last task (extra_recruits) and squashed commits. I'll let this sit here for a couple days to see if there are other comments and merge it if not. |
data/ai/lua/ca_recruit_rushers.lua
Outdated
@@ -944,6 +944,11 @@ function ca_recruit_rushers:evaluation(cfg, data, filter_own) | |||
end | |||
end | |||
|
|||
recruit_data.recuit_types = wesnoth.sides[wesnoth.current.side].recruit | |||
for _,unit_type in ipairs(leader.extra_recruit) do | |||
table.insert(recruit_data.recuit_types, unit_type) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might cause duplicate entries if both wesnoth.sides[wesnoth.current.side].recruit and leader.extra_recruit contain the same unit.
Apart from slowing things down, depending on the level of randomness, it could also increase the chance that unit is selected since it gets two chances to have the highest score, not one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoops, indeed! How about now: 00e4b22
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like it
data/ai/lua/ca_recruit_rushers.lua
Outdated
@@ -944,6 +944,14 @@ function ca_recruit_rushers:evaluation(cfg, data, filter_own) | |||
end | |||
end | |||
|
|||
recruit_data.recuit_types = {} | |||
for _,unit_type in ipairs(wesnoth.sides[wesnoth.current.side].recruit) do | |||
recruit_data.recuit_types[unit_type] = true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing the R in "recruit_types" here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Funny in that I had just noticed that myself. And there was a more substantial problem also: the code setting up that table actually had to be pulled forward about 20 lines as it was sometimes needed earlier (a situation that had not happened in my previous tests). Both is fixed now.
By the way, I should have mentioned earlier that deprecating the generic recruit engine and the new parameter |
data/ai/lua/ca_recruit_rushers.lua
Outdated
-- high_level_fraction: the approximate fraction of units of level 2 or higher to be recruited | ||
-- (default = 0) | ||
-- enemy_types: array of default enemy unit types to consider if there are no enemies on the map | ||
-- and no enemy sides exist or have recruit lists |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just noticed that specifying enemy_types
as a Lua array does not work (and has never worked) if this parameter is to be supplied by an [args]
tag. We could convert it to a comma-separated list instead, but I suggest to simply drop this parameter altogether. It is an undocumented parameter and, as is obvious from the comment above, it is essentially never needed, and even in the rare scenario when that might happen, there is a default list of types provided that will be used instead. This is such a rare edge case that it does not seem worth it to me to keep this parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assigning an array of strings as a config values does do an implicit join (so it's a comma-separated list), but if you're later reading it from a config you'd need to manually split it.
Probably easier to remove it, like you said. If someone needs the AI to be able to play a scenario that doesn't have any enemies, they should probably use a different type of recruitment algorithm anyway. (Or no recruitment, just use pre-placed units.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I recall, I added it with maps like Dark Forecast in mind, where there are lots of enemies of known types, but they're all placed via scripting. Humans can play it fine after the first few games, but the AI has no way of knowing what's coming and this would help with the first round of enemies.
Of course, I never actually tried making an AI for Dark Forecast, so I never discovered the issue. I suspect I would have ended up either providing the parameter through Lua and not noticed anyway or modifiing it further to support changing spawn lists.
At any rate, unless you plan on writing a Dark Forecast AI, it seems completely reasonable to drop it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the comments. I am not planning to write an AI specifically for Dark Forecast either, so I am going to stick with dropping this for now. We can always add something (which would likely end up being more complex than this) later, either in this CA or a custom setup, if the need arises.
This removes the need for the Generic Recruit Engine and makes Recruit Rushers a "clean" candidate action. In the process, it fixes a bug of data leakage between the Experimental AIs of different sides.
While most data in recruit_data can stay persistent from turn to turn, some of recruit_data.recruit, such as enemy_types, needs to be updated each turn.
Many of the operations of the recruit rushers CA are expensive and are therefore cached. For the most part, this cache can be kept from turn to turn, but in case there are events that change, for example, the map or the recruit list, this parameter can be used to force a reset of the cache each turn.
This fixes wesnoth#4924. Note, however, that the recruit rushers CA is set up for single-leader sides and does not work with multiple leaders, so this is of limited use.
Update: I got rid of the |
The incentive for this change was the fact that there is a "data leakage" bug if several sides all use the Experimental AI recruiting. Because AI candidate actions are loaded with
wesnoth.require
, all the information set in the oldca_recruit_rushers.lua
is only loaded once and thus applied to all sides. While there are other ways of fixing this problem, I've been meaning to remove the generic recruit engine in favor of simple straight CAs for a while anyway.There is no change in behavior due to the first (refactoring) commit. The CA functions exactly as before, and
generic_recruit_engine.lua
is still there, in case some UMC uses it directly.There are, however, a couple internal parameter changes.
leader_takes_village
andmin_turn_1_recruit
were internal parameters for the interaction between the Experimental AI's castle switch and recruit rushers CAs. Now that both CAs have full access to the AI engine'sdata
variable, they are not needed any more.The one actual change is that
score_function
has now been replaced by the usualca_score
parameter. Again, this is entirely internal and there is no change of behavior. In the unlikely case that some UMC actually uses the generic recruit engine with a score function, the engine is still there, as already mentioned. And for the ExpAI itself, the behavior is exactly the same, as the score function just returned a constant value anyway.While I'm at it, I might as well also do the following as part of this PR (but I first want to see if there are any substantial objections to what I have so far):
ca_recruit_rushers.lua
appears to go through the__cfg
of the AI configuration on each call, which is very inefficient. That should be avoided.