The Battle for Wesnoth  1.17.0-dev
goal.cpp
Go to the documentation of this file.
1 
2 /*
3  Copyright (C) 2009 - 2018 by Yurii Chernyi <terraninfo@terraninfo.net>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 /**
17  * @file
18  */
19 
20 #include "ai/composite/goal.hpp"
21 
22 #include "ai/default/contexts.hpp"
23 #include "ai/lua/core.hpp"
24 #include "ai/lua/lua_object.hpp"
25 #include "ai/manager.hpp"
26 #include "filter_context.hpp"
27 #include "game_board.hpp"
28 #include "log.hpp"
29 #include "map/location.hpp"
30 #include "resources.hpp"
32 #include "terrain/filter.hpp"
33 #include "units/unit.hpp"
34 #include "units/map.hpp"
35 #include "units/filter.hpp"
36 
37 #include <set>
38 #include <sstream>
39 
40 namespace ai {
41 
42 static lg::log_domain log_ai_goal("ai/goal");
43 #define DBG_AI_GOAL LOG_STREAM(debug, log_ai_goal)
44 #define LOG_AI_GOAL LOG_STREAM(info, log_ai_goal)
45 #define ERR_AI_GOAL LOG_STREAM(err, log_ai_goal)
46 
47 goal::goal(readonly_context &context, const config &cfg)
48  : readonly_context_proxy(), cfg_(cfg), ok_(true)
49 {
51 }
52 
54 {
55  LOG_AI_GOAL << "side " << get_side() << " : " << " created goal with name=[" << cfg_["name"] << "]" << std::endl;
56 }
57 
58 void goal::on_create(std::shared_ptr<ai::lua_ai_context>)
59 {
60  unrecognized();
61 }
62 
64 {
65  ERR_AI_GOAL << "side " << get_side() << " : " << " tried to create goal with name=[" << cfg_["name"] << "], but the [" << cfg_["engine"] << "] engine did not recognize that type of goal. " << std::endl;
66  ok_ = false;
67 }
68 
70 {
71 }
72 
73 void goal::add_targets(std::back_insert_iterator< std::vector< target >> /*target_list*/)
74 {
75 }
76 
78 {
79  return cfg_;
80 }
81 
82 std::string goal::get_id() const
83 {
84  return cfg_["id"];
85 }
86 
87 std::string goal::get_name() const
88 {
89  return cfg_["id"];
90 }
91 
92 std::string goal::get_engine() const
93 {
94  return cfg_["engine"];
95 }
96 
97 bool goal::redeploy(const config &cfg)
98 {
99  cfg_ = cfg;
100  on_create();
101  return true;
102 }
103 
104 bool goal::ok() const
105 {
106  return ok_;
107 }
108 
109 bool goal::active() const
110 {
111  return is_active(cfg_["time_of_day"],cfg_["turns"]);
112 }
113 
115 {
116  goal::on_create();
117  if (!cfg_["engine"].empty() && cfg_["engine"] != "cpp") {
118  unrecognized();
119  value_ = 0;
120  return;
121  }
122  if (const config::attribute_value *v = cfg_.get("value")) {
123  value_ = v->to_double(0);
124  }
125 }
126 
127 void target_unit_goal::add_targets(std::back_insert_iterator< std::vector< target >> target_list)
128 {
129  if (!(this)->active()) {
130  return;
131  }
132 
133  const config &criteria = cfg_.child("criteria");
134  if (!criteria) return;
135 
136  //find the enemy leaders and explicit targets
137  const unit_filter ufilt{ vconfig(criteria) };
138  for (const unit &u : resources::gameboard->units()) {
139  if (ufilt( u )) {
140  LOG_AI_GOAL << "found explicit target unit at ... " << u.get_location() << " with value: " << value() << "\n";
141  *target_list = target(u.get_location(), value(), target::TYPE::EXPLICIT);
142  }
143  }
144 
145 }
146 
148  : goal(context,cfg)
149  , value_(0.0)
150 {
151 }
152 
154 {
155  goal::on_create();
156  if (!cfg_["engine"].empty() && cfg_["engine"] != "cpp") {
157  unrecognized();
158  value_ = 0;
159  return;
160  }
161  if (cfg_.has_attribute("value")) {
162  value_ = cfg_["value"].to_double(0);
163  }
164  const config &criteria = cfg_.child("criteria");
165  if (criteria) {
166  filter_ptr_.reset(new terrain_filter(vconfig(criteria),resources::filter_con, false));
167  }
168 }
169 
170 void target_location_goal::add_targets(std::back_insert_iterator< std::vector< target >> target_list)
171 {
172  if (!(this)->active()) {
173  return;
174  }
175 
176  if (!filter_ptr_) return;
177 
178  std::set<map_location> items;
179  filter_ptr_->get_locations(items);
180  for (const map_location &loc : items)
181  {
182  LOG_AI_GOAL << "found explicit target location ... " << loc << " with value: " << value() << std::endl;
183  *target_list = target(loc, value(), target::TYPE::EXPLICIT);
184  }
185 
186 }
187 
189  : goal(context,cfg)
190  , filter_ptr_()
191  , value_(0.0)
192 {
193 }
194 
196 {
197  goal::on_create();
198  if (!cfg_["engine"].empty() && cfg_["engine"] != "cpp") {
199  unrecognized();
200  value_ = 0;
201  return;
202  }
203  if (const config::attribute_value *v = cfg_.get("value")) {
204  value_ = v->to_double(0);
205  }
206  if (const config::attribute_value *v = cfg_.get("protect_radius")) {
207  radius_ = (*v).to_int(1);
208  }
209 
210  if (radius_<1) {
211  radius_=20;
212  }
213  const config &criteria = cfg_.child("criteria");
214  if (criteria) {
215  filter_ptr_.reset(new terrain_filter(vconfig(criteria), resources::filter_con, false));
216  }
217 
218 }
219 
220 void protect_goal::add_targets(std::back_insert_iterator< std::vector< target >> target_list)
221 {
222  std::string goal_type;
223  if (protect_unit_) {
224  goal_type = "protect_unit";
225  } else {
226  goal_type ="protect_location";
227  }
228 
229  if (!(this)->active()) {
230  LOG_AI_GOAL << "skipping " << goal_type << " goal - not active" << std::endl;
231  return;
232  }
233 
234  const config &criteria = cfg_.child("criteria");
235  if (!criteria) {
236  LOG_AI_GOAL << "skipping " << goal_type << " goal - no criteria given" << std::endl;
237  return;
238  } else {
239  DBG_AI_GOAL << "side " << get_side() << ": "<< goal_type << " goal with criteria" << std::endl << cfg_.child("criteria") << std::endl;
240  }
241 
242  unit_map &units = resources::gameboard->units();
243 
244  std::set<map_location> items;
245  if (protect_unit_) {
246  const unit_filter ufilt{ vconfig(criteria) };
247  for (const unit &u : units)
248  {
249  // 'protect_unit' can be set to any unit of any side -> exclude hidden units
250  // unless they are visible to the AI side (e.g. allies with shared vision).
251  // As is done in other parts of the AI, units under fog/shroud count as visible to the AI.
252  if (ufilt(u)
253  && (!u.invisible(u.get_location()) || u.is_visible_to_team(current_team(), false)))
254  {
255  DBG_AI_GOAL << "side " << get_side() << ": in " << goal_type << ": " << u.get_location() << " should be protected\n";
256  items.insert(u.get_location());
257  }
258  }
259  } else {
260  filter_ptr_->get_locations(items);
261  }
262  DBG_AI_GOAL << "side " << get_side() << ": searching for threats in "+goal_type+" goal" << std::endl;
263  // Look for directions to protect a specific location or specific unit.
264  for (const map_location &loc : items)
265  {
266  for (const unit &u : units)
267  {
268  int distance = distance_between(u.get_location(), loc);
269  if (current_team().is_enemy(u.side()) && distance < radius_ &&
270  !u.invisible(u.get_location()))
271  {
272  DBG_AI_GOAL << "side " << get_side() << ": in " << goal_type << ": found threat target. " << u.get_location() << " is a threat to "<< loc << '\n';
273  *target_list = target(u.get_location(),
274  value_ * static_cast<double>(radius_ - distance) /
275  radius_, target::TYPE::THREAT);
276  }
277  }
278  }
279 
280 }
281 
282 protect_goal::protect_goal(readonly_context &context, const config &cfg, bool protect_unit)
283  : goal(context,cfg)
284  , filter_ptr_()
285  , protect_unit_(protect_unit)
286  , radius_(20) //this default radius is taken from old code
287  , value_(1.0) //this default value taken from old code
288 {
289 }
290 
292  : goal(context, cfg)
293  , code_()
294  , handler_()
295 {
296  if (cfg.has_attribute("code")) {
297  code_ = cfg["code"].str();
298  }
299  else
300  {
301  ERR_AI_GOAL << "side " << get_side() << " : Error creating Lua goal (missing code= key)" << std::endl;
302  }
303 }
304 
305 void lua_goal::on_create(std::shared_ptr<ai::lua_ai_context> l_ctx)
306 {
307  handler_.reset(resources::lua_kernel->create_lua_ai_action_handler(code_.c_str(), *l_ctx));
308 }
309 
310 void lua_goal::add_targets(std::back_insert_iterator< std::vector< target >> target_list)
311 {
312  std::shared_ptr<lua_object<std::vector<target>>> l_obj = std::make_shared<lua_object<std::vector<target>>>();
313  config c(cfg_.child_or_empty("args"));
314  const config empty_cfg;
315  handler_->handle(c, empty_cfg, true, l_obj);
316  try {
317  std::vector < target > targets = *(l_obj->get());
318 
319  for (target tg : targets)
320  {
321  *target_list = tg;
322  }
323  } catch(const bad_enum_cast& e) {
324  ERR_AI_GOAL << "A Lua goal returned a target of an unknown type (\"" << e.value() << "\"; unfortunately, the engine cannot recover from this error. As a result, all targets returned by the goal have been lost.\n";
325  }
326 
327 }
328 
329 // This is defined in the source file so that it can easily access the logger
330 bool goal_factory::is_duplicate(const std::string& name)
331 {
332  if (get_list().find(name) != get_list().end()) {
333  ERR_AI_GOAL << "Error: Attempt to double-register goal " << name << std::endl;
334  return true;
335  }
336  return false;
337 }
338 
339 } //end of namespace ai
static std::unique_ptr< class sdl_event_handler > handler_
Definition: handler.cpp:61
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:414
virtual void add_targets(std::back_insert_iterator< std::vector< target >> target_list)
Definition: goal.cpp:73
virtual const unit_map & units() const override
Definition: game_board.hpp:111
This class represents a single unit of a specific type.
Definition: unit.hpp:120
virtual bool is_active(const std::string &time_of_day, const std::string &turns) const override
Definition: contexts.hpp:755
Variant for storing WML attributes.
static lg::log_domain log_ai_goal("ai/goal")
bool has_attribute(config_key_type key) const
Definition: config.cpp:207
target_location_goal(readonly_context &context, const config &cfg)
Definition: goal.cpp:188
bool active() const
Definition: goal.cpp:109
virtual std::string get_id() const
Definition: goal.cpp:82
const attribute_value * get(config_key_type key) const
Returns a pointer to the attribute with the given key or nullptr if it does not exist.
Definition: config.cpp:766
goal(readonly_context &context, const config &cfg)
Definition: goal.cpp:47
virtual void on_create()
Definition: goal.cpp:153
config cfg_
Definition: goal.hpp:65
std::shared_ptr< lua_ai_action_handler > handler_
Definition: goal.hpp:148
const std::vector< std::string > items
virtual void add_targets(std::back_insert_iterator< std::vector< target >> target_list)
Definition: goal.cpp:310
Lua object(value) wrapper implementation.
virtual void on_create()
Definition: goal.cpp:195
A small explanation about what&#39;s going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:60
virtual void on_create()
Definition: goal.cpp:53
bool ok_
Definition: goal.hpp:66
virtual std::string get_engine() const
Definition: goal.cpp:92
filter_context * filter_con
Definition: resources.cpp:23
void unrecognized()
Definition: goal.cpp:63
game_board * gameboard
Definition: resources.cpp:20
virtual void add_targets(std::back_insert_iterator< std::vector< target >> target_list)
Definition: goal.cpp:220
bool is_enemy(int n) const
Definition: team.hpp:254
Managing the AIs lifecycle - headers TODO: Refactor history handling and internal commands...
lua_goal(readonly_context &context, const config &cfg)
Definition: goal.cpp:291
const char * value() const noexcept
Definition: make_enum.hpp:112
Encapsulates the map of the game.
Definition: location.hpp:37
bool redeploy(const config &cfg)
Definition: goal.cpp:97
virtual const team & current_team() const override
Definition: contexts.hpp:454
std::shared_ptr< terrain_filter > filter_ptr_
Definition: goal.hpp:99
std::string code_
Definition: goal.hpp:147
double value() const
Definition: goal.hpp:79
Default AI contexts.
virtual side_number get_side() const override
Get the side number.
Definition: contexts.hpp:400
#define ERR_AI_GOAL
Definition: goal.cpp:45
virtual void add_targets(std::back_insert_iterator< std::vector< target >> target_list)
Definition: goal.cpp:170
virtual void add_targets(std::back_insert_iterator< std::vector< target >> target_list)
Definition: goal.cpp:127
std::size_t distance_between(const map_location &a, const map_location &b)
Function which gives the number of hexes between two tiles (i.e.
Definition: location.cpp:545
protect_goal(readonly_context &context, const config &cfg, bool protect_unit)
Definition: goal.cpp:282
virtual void on_create()
Definition: goal.cpp:114
A variable-expanding proxy for the config class.
Definition: variable.hpp:44
Standard logging facilities (interface).
target_unit_goal(readonly_context &context, const config &cfg)
Definition: goal.cpp:147
#define DBG_AI_GOAL
Definition: goal.cpp:43
bool is_duplicate(const std::string &name)
Definition: goal.cpp:330
game_lua_kernel * lua_kernel
Definition: resources.cpp:25
Container associating units to locations.
Definition: map.hpp:97
#define LOG_AI_GOAL
Definition: goal.cpp:44
#define e
bool ok() const
Definition: goal.cpp:104
const config & child_or_empty(config_key_type key) const
Returns the first child with the given key, or an empty config if there is none.
Definition: config.cpp:477
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:59
mock_char c
virtual std::string get_name() const
Definition: goal.cpp:87
virtual config to_config() const
Definition: goal.cpp:77
virtual ~goal()
Definition: goal.cpp:69
void init_readonly_context_proxy(readonly_context &target)
Definition: contexts.hpp:438