Difference between revisions of "LuaAI"

From The Battle for Wesnoth Wiki
m
(expanded)
Line 1: Line 1:
 
Good lua support for Wesnoth's AI would be cool.
 
Good lua support for Wesnoth's AI would be cool.
Adding such support is not a rocket science - just several well-defined steps.
 
  
# expose game state (readonly_context) to lua code
+
== The role and responsibilities of ai support engine ==
#expose action handlers ('move,attack,recruit,recall,stop' actions from readwrite_context) to lua code
+
AI is constructed from components.
#add a src/ai/composite/engine_lua.?pp which will take config snippets and return c++ objects which will act as wrappers to lua-based candidate actions/stages/aspects
+
AI support engines (src/ai/composite/engine_*.?pp) are stateful components in the context of the ai for the specific side, responsible with taking config snippets and translating them into c++ components.
# (optional) modify aspects code to make translation from/to lua objects less expensive
 
# (optional) somehow prohibit modification of game state via lua handlers  (prohibit calling stuff such as wesnoth.fire() from AIs)
 
  
most of the work is a proper (1).
+
[stage]
 +
  # this stage will be parsed by default cpp engine
 +
  {ANYTHING_HERE_CAN_BE_CPP_ENGINE_SPECIFIC}
 +
[/stage]
  
(4) and (5) are optional
+
[stage]
 +
  engine=cpp
 +
  # this stage will be parsed by default cpp engine
 +
  {ANYTHING_HERE_CAN_BE_CPP_ENGINE_SPECIFIC}
 +
[/stage]
  
(2) is very simple - just call a c++ function when lua function is called, translating the arguments. 'traslation via config' is already done by silene (see how wesnoth.fire works)
+
[stage]
 +
  engine=fai
 +
  # this stage will be parsed by formula ai engine
 +
  {ANYTHING_HERE_CAN_BE_FAI_ENGINE_SPECIFIC}
 +
[/stage]
  
(3) is just some wrapper stuff - it's enough to do it for stages and candidate actions
+
[stage]
 +
  engine=lua
 +
  # this stage will be parsed by lua engine
 +
  {ANYTHING_HERE_CAN_BE_LUA_ENGINE_SPECIFIC}
 +
[/stage]
  
in (1), for a base ai, it's needed to access the 1.1) our side number 1.2) game map info, 1.3) team info,  1.4) units info 1.5) scenario info such as income and time of day
+
So, I've committed a stub lua engine , src/ai/composite/engine_lua.cpp
  
future GSoCers, take notes !
+
This engine is constructed when the ai is not yet fully initialized, so, the constructor is passed two arguments: the config of the engine (if present, i.e. when loading a savegame) and the readonly_context (which provides functions to access the game state but not to modify it)
  
Ask Crab_ on irc for details.
+
At this point, ai aspects and ai goals are created. Supporting writing aspects and goals in lua is not first-priority (since they tend to have a simple config like 'target units standing on locations matching this SLF' or 'aggression=0.5' and can be written in plain WML), but, it would be interesting to have in the future (since some aspects handle calculation of interesting things like attack ratings)
 +
 
 +
When the ai is fully initialized, full ai_context is passed to the engine.
 +
Then, ai stages and their parts are parsed. At this point we're interested in parsing stages and candidate actions, so lua engine has to override those methods from engine which deal with parsing stages and candidate actions from config.
 +
 
 +
stage = stateful object in the context of the ai for the specific side, it's just a 'part of ai turn' with do_play_stage() method.
 +
candidate_action = stateful object in the context of the candidate action evaluation loop stage, it's 'evaluator+executor' pair (if THIS, than doing THAT has score SCORE)
 +
 
 +
== Exposing game state ==
 +
ai context includes functions which provide access to
 +
# current side number
 +
# unit map
 +
# game map
 +
# information about teams, villages
 +
# information about turn and time of day
 +
# scenario info such as income per turn
 +
# current values of ai aspects (aggression, attack_depth, avoid, passive_leader, passive_leader_shares_keep, leader_aggression,caution, grouping, leader_goal, leader_value, number_of_possible_recruits_to_force_recruit, recruitment_ignore_bad_combat, recruitment_ignore_bad_movement, recruitment_pattern, scout_village_targeting, simple_targeting, support_villages, village_value, villages_per_scout,...)
 +
# action handlers (more on them below)
 +
 
 +
 
 +
== Exposing action handlers ==
 +
# action handlers ('move,attack,recruit,recall,stop' actions from src/ai/actions.cpp must be made available to lua code. there are helper functions for that in ai_context. note that it's possible to check if the action is allowed before actually executing it. the code, when used in candidate_actions is usually similar to this:
 +
 
 +
---evaluation---
 +
move_ = check_move_action(leader->first,keep,false);
 +
if (move_->is_ok()){
 +
    return get_score();
 +
}
 +
---later, if selected for execution---
 +
move_->execute();
 +
------
 +
Note:
 +
(1) action (or the list of actions) is usually cached between evaluation and execution
 +
(2) it is possible to check if the move is 'ok' without executing it.
 +
 
 +
P.S. it is, probably, also needed to somehow prohibit modification of game state via lua handlers (i.e. prohibit calling stuff such as wesnoth.fire() from AIs). also it's important to prevent changes of state of ai for side A by ai of side B. For start,it's probably enough to prevent only accidential changes, but, if it's possible to achieve a proper separation between lua code for different AIs, it'll be a good thing.

Revision as of 23:08, 18 January 2010

Good lua support for Wesnoth's AI would be cool.

The role and responsibilities of ai support engine

AI is constructed from components. AI support engines (src/ai/composite/engine_*.?pp) are stateful components in the context of the ai for the specific side, responsible with taking config snippets and translating them into c++ components.

[stage]
 # this stage will be parsed by default cpp engine
 {ANYTHING_HERE_CAN_BE_CPP_ENGINE_SPECIFIC}
[/stage]
[stage]
 engine=cpp
 # this stage will be parsed by default cpp engine
 {ANYTHING_HERE_CAN_BE_CPP_ENGINE_SPECIFIC}
[/stage]
[stage]
 engine=fai
 # this stage will be parsed by formula ai engine
 {ANYTHING_HERE_CAN_BE_FAI_ENGINE_SPECIFIC}
[/stage]
[stage]
 engine=lua
 # this stage will be parsed by lua engine
 {ANYTHING_HERE_CAN_BE_LUA_ENGINE_SPECIFIC}
[/stage]

So, I've committed a stub lua engine , src/ai/composite/engine_lua.cpp

This engine is constructed when the ai is not yet fully initialized, so, the constructor is passed two arguments: the config of the engine (if present, i.e. when loading a savegame) and the readonly_context (which provides functions to access the game state but not to modify it)

At this point, ai aspects and ai goals are created. Supporting writing aspects and goals in lua is not first-priority (since they tend to have a simple config like 'target units standing on locations matching this SLF' or 'aggression=0.5' and can be written in plain WML), but, it would be interesting to have in the future (since some aspects handle calculation of interesting things like attack ratings)

When the ai is fully initialized, full ai_context is passed to the engine. Then, ai stages and their parts are parsed. At this point we're interested in parsing stages and candidate actions, so lua engine has to override those methods from engine which deal with parsing stages and candidate actions from config.

stage = stateful object in the context of the ai for the specific side, it's just a 'part of ai turn' with do_play_stage() method.
candidate_action = stateful object in the context of the candidate action evaluation loop stage, it's 'evaluator+executor' pair (if THIS, than doing THAT has score SCORE)

Exposing game state

ai context includes functions which provide access to

# current side number
# unit map
# game map
# information about teams, villages
# information about turn and time of day
# scenario info such as income per turn
# current values of ai aspects (aggression, attack_depth, avoid, passive_leader, passive_leader_shares_keep, leader_aggression,caution, grouping, leader_goal, leader_value, number_of_possible_recruits_to_force_recruit, recruitment_ignore_bad_combat, recruitment_ignore_bad_movement, recruitment_pattern, scout_village_targeting, simple_targeting, support_villages, village_value, villages_per_scout,...)
# action handlers (more on them below)


Exposing action handlers

  1. action handlers ('move,attack,recruit,recall,stop' actions from src/ai/actions.cpp must be made available to lua code. there are helper functions for that in ai_context. note that it's possible to check if the action is allowed before actually executing it. the code, when used in candidate_actions is usually similar to this:

---evaluation---

move_ = check_move_action(leader->first,keep,false);
if (move_->is_ok()){
    return get_score();
}

---later, if selected for execution---

move_->execute();

Note: (1) action (or the list of actions) is usually cached between evaluation and execution (2) it is possible to check if the move is 'ok' without executing it.

P.S. it is, probably, also needed to somehow prohibit modification of game state via lua handlers (i.e. prohibit calling stuff such as wesnoth.fire() from AIs). also it's important to prevent changes of state of ai for side A by ai of side B. For start,it's probably enough to prevent only accidential changes, but, if it's possible to achieve a proper separation between lua code for different AIs, it'll be a good thing.