[[lua AI fixes]]

(1) First draft of the caching system for LuaAI. (2) Added validation
variables and setters/getters in the ai contexts, to allow LuaAI cache
check the movemaps for validity
This commit is contained in:
Dmitry Kovalenko 2012-04-08 00:00:14 +00:00
parent 8a2ddc368f
commit 9ddd3d4408
6 changed files with 252 additions and 100 deletions

23
data/ai/lua/cache.lua Normal file
View file

@ -0,0 +1,23 @@
--! #textdomain wesnoth
return {
init = function(ai)
ai.cache = {}
function ai.update_cache(item, getter)
ai.cache[item] = ai[getter]()
return ai.cache[item]
end
function ai.get_cached_item(item, getter, validator)
if not ai.cache[item] or not ai[validator]() then
local result = ai.update_cache(item, getter)
return result
end
return ai.cache[item]
end
end
}

View file

@ -2,16 +2,70 @@
return {
init = function(ai)
init = function(ai)
-- Initialize the cache system for LuaAI context
local cache = wesnoth.require("ai/lua/cache.lua")
cache.init(ai)
-- Validator section
function ai.dst_src_validator()
if not ai.is_dst_src_valid() then
ai.cache["dstsrc"] = nil
return false
end
return true
end
function ai.dst_src_enemy_validator()
if not ai.is_dst_src_enemy_valid() then
ai.cache["enemy_dstsrc"] = nil
return false
end
return true
end
function ai.src_dst_validator()
if not ai.is_src_dst_valid() then
ai.cache["srcdst"] = nil
return false
end
return true
end
function ai.src_dst_enemy_validator()
if not ai.is_src_dst_enemy_valid() then
ai.cache["enemy_srcdst"] = nil
return false
end
return true
end
-- End of validator section
-- Proxy function section
function ai.get_cached_dstsrc()
return ai.get_cached_item("dstsrc", "get_dstsrc", "dst_src_validator")
end
--! ===========================
function ai.get_cached_srcdst()
return ai.get_cached_item("srcdst", "get_srcdst", "dst_src_enemy_validator")
end
function ai.get_cached_enemy_dstsrc()
return ai.get_cached_item("enemy_dstsrc", "get_enemy_dstsrc", "src_dst_validator")
end
--! say hello to player via a message
function ai.say_hello()
wesnoth.message(string.format("Hello from Lua AI which controls side %d! It's turn %d.", ai.side, wesnoth.current.turn))
end
--! ===========================
end
function ai.get_cached_enemy_srcdst()
return ai.get_cached_item("enemy_srcdst", "get_enemy_srcdst", "src_dst_enemy_validator")
end
-- End of proxy function section
end
}

View file

@ -74,86 +74,6 @@ Gs^Fp , Gs^Fp , Wwf , Wwf , Mm , Rd
text="Location guarded (range = 3)"
[/label]
[event]
name=preload
first_time_only=no
[lua]
code = <<
H = wesnoth.require "lua/helper.lua"
W = H.set_wml_action_metatable {}
_ = wesnoth.textdomain "my-campaign"
-- Define your global constants here.
-- ...
ai = {}
ca_counter = 0
-- @Crab_: this preload event in my opinion should be carried out in a separate file and included in all scenarios
-- that intend to use lua, because it contains some vital code. Implementations of patrol could be kept here
-- or carried out somewhere else, depending on what we want. This counter is as simple as it is, but not protected at all
-- I think if users try to mess with it, it's they're own fault. If this needs protection we can put it in a table a protect
-- with a metatable.
H.set_wml_var_metatable(_G)
wesnoth.require("ai/lua/patrol.lua")
local ptrl = patrol_gen("Rark", {{x=14, y=7}, {x=15, y=7}, {x=15, y=8}, {x=14, y=8}}) -- need to find a solution for this
patrol_rark = ptrl.exec
patrol_bilbo = patrol_gen("Bilbo", {{x=2, y=3}, {x=3, y=2}}).exec
patrol_sally = patrol_gen("Sally", {{x=5, y=7}, {x=7, y=5}}).exec
patrol_eval_rark = ptrl.eval
-- End of patrol function // patrol_gen(ai, "Rark", {{x=14, y=7}, {x=15, y=7}, {x=15, y=8}, {x=14, y=8}})
>>
[/lua]
[/event]
[event]
name=side 2 turn 1
first_time_only=yes
[add_ai_behavior]
side=2
[filter]
name="Rark"
[/filter]
sticky=yes
loop_id=ca_loop
evaluation="return patrol_eval_rark()"
execution="patrol_rark()"
[/add_ai_behavior]
[/event]
[event]
name=side 2 turn 1
first_time_only=yes
[add_ai_behavior]
side=2
[filter]
name="Bilbo"
[/filter]
sticky=yes
loop_id=ca_loop
evaluation="return patrol_eval_rark()"
execution="patrol_bilbo()"
[/add_ai_behavior]
[/event]
[event]
name=side 2 turn 1
first_time_only=yes
[add_ai_behavior]
side=2
[filter]
name="Sally"
[/filter]
sticky=yes
loop_id=ca_loop
evaluation="return patrol_eval_rark()"
execution="patrol_sally()"
[/add_ai_behavior]
[/event]
[event]
name=side 2 turn 1
@ -329,7 +249,7 @@ Gs^Fp , Gs^Fp , Wwf , Wwf , Mm , Rd
name="lua"
code= <<
--! ==============================================================
ai = ...
local ai = ...
local my_ai = { }
@ -341,12 +261,14 @@ ai_stdlib.init(ai)
function my_ai:stage_hello()
wesnoth.message('hello from stage!')
local debug_utils = wesnoth.require "~add-ons/Wesnoth_Lua_Pack/debug_utils.lua"
local avoid = ai.get_avoid()
local leader_goal = ai.get_leader_goal()
debug_utils.dbms(avoid,false,"variable",false)
debug_utils.dbms(leader_goal,false,"variable",false)
--local mm = ai.get_dstsrc()
--wesnoth.message("type " .. type(mo))
--debug_utils.dbms(dstsrc,false,"variable",false)
--debug_utils.dbms(mo,false,"variable",false)
end
function my_ai:candidate_action_evaluation_hello()

View file

@ -168,8 +168,12 @@ readonly_context_impl::readonly_context_impl(side_context &context, const config
leader_aggression_(),
leader_goal_(),
leader_value_(),
move_maps_enemy_valid_(false),
move_maps_enemy_valid_(false),
move_maps_valid_(false),
dst_src_valid_lua_(false),
dst_src_enemy_valid_lua_(false),
src_dst_valid_lua_(false),
src_dst_enemy_valid_lua_(false),
number_of_possible_recruits_to_force_recruit_(),
passive_leader_(),
passive_leader_shares_keep_(),
@ -816,7 +820,25 @@ int readonly_context_impl::get_villages_per_scout() const
return 0;
}
bool readonly_context_impl::is_dst_src_valid_lua() const
{
return dst_src_valid_lua_;
}
bool readonly_context_impl::is_dst_src_enemy_valid_lua() const
{
return dst_src_enemy_valid_lua_;
}
bool readonly_context_impl::is_src_dst_valid_lua() const
{
return src_dst_valid_lua_;
}
bool readonly_context_impl::is_src_dst_enemy_valid_lua() const
{
return src_dst_enemy_valid_lua_;
}
void readonly_context_impl::invalidate_defensive_position_cache() const
{
@ -840,6 +862,12 @@ void readonly_context_impl::invalidate_move_maps() const
{
move_maps_valid_ = false;
move_maps_enemy_valid_ = false;
dst_src_valid_lua_ = false;
dst_src_enemy_valid_lua_ = false;
src_dst_valid_lua_ = false;
src_dst_enemy_valid_lua_ = false;
}
@ -1100,6 +1128,25 @@ void readonly_context_impl::recalculate_move_maps_enemy() const
move_maps_enemy_valid_ = true;
}
void readonly_context_impl::set_dst_src_valid_lua()
{
dst_src_valid_lua_ = true;
}
void readonly_context_impl::set_dst_src_enemy_valid_lua()
{
dst_src_enemy_valid_lua_ = true;
}
void readonly_context_impl::set_src_dst_valid_lua()
{
src_dst_valid_lua_ = true;
}
void readonly_context_impl::set_src_dst_enemy_valid_lua()
{
src_dst_enemy_valid_lua_ = true;
}
const map_location& readonly_context_impl::suitable_keep(const map_location& leader_location, const pathfind::paths& leader_paths){
if (resources::game_map->is_keep(leader_location)) {

View file

@ -326,7 +326,14 @@ public:
virtual bool is_active(const std::string &time_of_day, const std::string &turns) const = 0;
virtual bool is_dst_src_valid_lua() const = 0;
virtual bool is_dst_src_enemy_valid_lua() const = 0;
virtual bool is_src_dst_valid_lua() const = 0;
virtual bool is_src_dst_enemy_valid_lua() const = 0;
virtual void invalidate_defensive_position_cache() const = 0;
@ -366,7 +373,12 @@ public:
virtual void recalculate_move_maps_enemy() const = 0;
virtual void set_src_dst_valid_lua() = 0;
virtual void set_src_dst_enemy_valid_lua() = 0;
virtual void set_dst_src_valid_lua() = 0;
virtual void set_dst_src_enemy_valid_lua() = 0;
/** get most suitable keep for leader - nearest free that can be reached in 1 turn, if none - return nearest occupied that can be reached in 1 turn, if none - return nearest keep, if none - return null_location */
virtual const map_location& suitable_keep( const map_location& leader_location, const pathfind::paths& leader_paths ) = 0;
@ -833,7 +845,26 @@ public:
{
return target_->is_active(time_of_day, turns);
}
virtual bool is_dst_src_valid_lua() const
{
return target_->is_dst_src_valid_lua();
}
virtual bool is_dst_src_enemy_valid_lua() const
{
return target_->is_dst_src_enemy_valid_lua();
}
virtual bool is_src_dst_valid_lua() const
{
return target_->is_src_dst_valid_lua();
}
virtual bool is_src_dst_enemy_valid_lua() const
{
return target_->is_src_dst_enemy_valid_lua();
}
virtual void invalidate_defensive_position_cache() const
{
@ -881,7 +912,26 @@ public:
{
target_->recalculate_move_maps_enemy();
}
virtual void set_dst_src_valid_lua()
{
target_->set_dst_src_valid_lua();
}
virtual void set_dst_src_enemy_valid_lua()
{
target_->set_dst_src_enemy_valid_lua();
}
virtual void set_src_dst_valid_lua()
{
target_->set_src_dst_valid_lua();
}
virtual void set_src_dst_enemy_valid_lua()
{
target_->set_src_dst_enemy_valid_lua();
}
virtual const map_location& suitable_keep( const map_location& leader_location, const pathfind::paths& leader_paths )
{
@ -1312,7 +1362,14 @@ public:
virtual bool is_active(const std::string &time_of_day, const std::string &turns) const;
virtual bool is_dst_src_valid_lua() const;
virtual bool is_dst_src_enemy_valid_lua() const;
virtual bool is_src_dst_valid_lua() const;
virtual bool is_src_dst_enemy_valid_lua() const;
virtual void invalidate_defensive_position_cache() const;
@ -1348,7 +1405,14 @@ public:
void on_create();
virtual void set_dst_src_valid_lua();
virtual void set_dst_src_enemy_valid_lua();
virtual void set_src_dst_valid_lua();
virtual void set_src_dst_enemy_valid_lua();
virtual const map_location& suitable_keep( const map_location& leader_location, const pathfind::paths& leader_paths );
@ -1390,6 +1454,10 @@ private:
aspect_type< double >::typesafe_ptr leader_value_;
mutable bool move_maps_enemy_valid_;
mutable bool move_maps_valid_;
mutable bool dst_src_valid_lua_;
mutable bool dst_src_enemy_valid_lua_;
mutable bool src_dst_valid_lua_;
mutable bool src_dst_enemy_valid_lua_;
aspect_type<double>::typesafe_ptr number_of_possible_recruits_to_force_recruit_;
aspect_type<bool>::typesafe_ptr passive_leader_;
aspect_type<bool>::typesafe_ptr passive_leader_shares_keep_;

View file

@ -546,6 +546,7 @@ static void push_move_map(lua_State *L, const move_map& m)
static int cfun_ai_get_dstsrc(lua_State *L)
{
move_map dst_src = get_readonly_context(L).get_dstsrc();
get_readonly_context(L).set_dst_src_valid_lua();
push_move_map(L, dst_src);
return 1;
}
@ -553,6 +554,7 @@ static int cfun_ai_get_dstsrc(lua_State *L)
static int cfun_ai_get_srcdst(lua_State *L)
{
move_map src_dst = get_readonly_context(L).get_srcdst();
get_readonly_context(L).set_src_dst_valid_lua();
push_move_map(L, src_dst);
return 1;
}
@ -560,6 +562,7 @@ static int cfun_ai_get_srcdst(lua_State *L)
static int cfun_ai_get_enemy_dstsrc(lua_State *L)
{
move_map enemy_dst_src = get_readonly_context(L).get_enemy_dstsrc();
get_readonly_context(L).set_dst_src_enemy_valid_lua();
push_move_map(L, enemy_dst_src);
return 1;
}
@ -567,10 +570,39 @@ static int cfun_ai_get_enemy_dstsrc(lua_State *L)
static int cfun_ai_get_enemy_srcdst(lua_State *L)
{
move_map enemy_src_dst = get_readonly_context(L).get_enemy_srcdst();
get_readonly_context(L).set_src_dst_enemy_valid_lua();
push_move_map(L, enemy_src_dst);
return 1;
}
static int cfun_ai_is_dst_src_valid(lua_State *L)
{
bool valid = get_readonly_context(L).is_dst_src_valid_lua();
lua_pushboolean(L, valid);
return 1;
}
static int cfun_ai_is_dst_src_enemy_valid(lua_State *L)
{
bool valid = get_readonly_context(L).is_dst_src_enemy_valid_lua();
lua_pushboolean(L, valid);
return 1;
}
static int cfun_ai_is_src_dst_valid(lua_State *L)
{
bool valid = get_readonly_context(L).is_src_dst_valid_lua();
lua_pushboolean(L, valid);
return 1;
}
static int cfun_ai_is_src_dst_enemy_valid(lua_State *L)
{
bool valid = get_readonly_context(L).is_src_dst_enemy_valid_lua();
lua_pushboolean(L, valid);
return 1;
}
lua_ai_context* lua_ai_context::create(lua_State *L, char const *code, ai::engine_lua *engine)
{
int res_ai = luaL_loadstring(L, code);//stack size is now 1 [ -1: ai_context]
@ -620,6 +652,12 @@ lua_ai_context* lua_ai_context::create(lua_State *L, char const *code, ai::engin
{ "get_village_value", &cfun_ai_get_village_value },
{ "get_villages_per_scout", &cfun_ai_get_villages_per_scout },
// End of aspects
// Validation/cache functions
{ "is_dst_src_valid", &cfun_ai_is_dst_src_valid },
{ "is_dst_src_enemy_valid", &cfun_ai_is_dst_src_enemy_valid },
{ "is_src_dst_valid", &cfun_ai_is_src_dst_valid },
{ "is_src_dst_enemy_valid", &cfun_ai_is_src_dst_enemy_valid },
// End of validation functions
{ "move", &cfun_ai_execute_move_partial },
{ "move_full", &cfun_ai_execute_move_full },
{ "recall", &cfun_ai_execute_recall },