[[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:
parent
8a2ddc368f
commit
9ddd3d4408
6 changed files with 252 additions and 100 deletions
23
data/ai/lua/cache.lua
Normal file
23
data/ai/lua/cache.lua
Normal 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
|
||||
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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 },
|
||||
|
|
Loading…
Add table
Reference in a new issue