The Battle for Wesnoth  1.15.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 
53 
54 
56 {
57  LOG_AI_GOAL << "side " << get_side() << " : " << " created goal with name=[" << cfg_["name"] << "]" << std::endl;
58 }
59 
60 void goal::on_create(std::shared_ptr<ai::lua_ai_context>)
61 {
62  unrecognized();
63 }
64 
66 {
67  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;
68  ok_ = false;
69 }
70 
71 
73 {
74 }
75 
76 
77 void goal::add_targets(std::back_insert_iterator< std::vector< target >> /*target_list*/)
78 {
79 }
80 
81 
82 
84 {
85  return cfg_;
86 }
87 
88 std::string goal::get_id() const
89 {
90  return cfg_["id"];
91 }
92 
93 std::string goal::get_name() const
94 {
95  return cfg_["id"];
96 }
97 
98 std::string goal::get_engine() const
99 {
100  return cfg_["engine"];
101 }
102 
103 
104 bool goal::redeploy(const config &cfg)
105 {
106  cfg_ = cfg;
107  on_create();
108  return true;
109 }
110 
111 
112 bool goal::ok() const
113 {
114  return ok_;
115 }
116 
117 
118 bool goal::active() const
119 {
120  return is_active(cfg_["time_of_day"],cfg_["turns"]);
121 }
122 
123 
125 {
126  goal::on_create();
127  if (!cfg_["engine"].empty() && cfg_["engine"] != "cpp") {
128  unrecognized();
129  value_ = 0;
130  return;
131  }
132  if (const config::attribute_value *v = cfg_.get("value")) {
133  value_ = v->to_double(0);
134  }
135 }
136 
137 void target_unit_goal::add_targets(std::back_insert_iterator< std::vector< target >> target_list)
138 {
139  if (!(this)->active()) {
140  return;
141  }
142 
143  const config &criteria = cfg_.child("criteria");
144  if (!criteria) return;
145 
146  //find the enemy leaders and explicit targets
147  const unit_filter ufilt{ vconfig(criteria) };
148  for (const unit &u : resources::gameboard->units()) {
149  if (ufilt( u )) {
150  LOG_AI_GOAL << "found explicit target unit at ... " << u.get_location() << " with value: " << value() << "\n";
151  *target_list = target(u.get_location(), value(), target::TYPE::EXPLICIT);
152  }
153  }
154 
155 
156 }
157 
158 
160  : goal(context,cfg)
161  , value_(0.0)
162 {
163 }
164 
165 
167 {
168  goal::on_create();
169  if (!cfg_["engine"].empty() && cfg_["engine"] != "cpp") {
170  unrecognized();
171  value_ = 0;
172  return;
173  }
174  if (cfg_.has_attribute("value")) {
175  value_ = cfg_["value"].to_double(0);
176  }
177  const config &criteria = cfg_.child("criteria");
178  if (criteria) {
179  filter_ptr_.reset(new terrain_filter(vconfig(criteria),resources::filter_con));
180  }
181 }
182 
183 void target_location_goal::add_targets(std::back_insert_iterator< std::vector< target >> target_list)
184 {
185  if (!(this)->active()) {
186  return;
187  }
188 
189  if (!filter_ptr_) return;
190 
191  std::set<map_location> items;
192  filter_ptr_->get_locations(items);
193  for (const map_location &loc : items)
194  {
195  LOG_AI_GOAL << "found explicit target location ... " << loc << " with value: " << value() << std::endl;
196  *target_list = target(loc, value(), target::TYPE::EXPLICIT);
197  }
198 
199 }
200 
202  : goal(context,cfg)
203  , filter_ptr_()
204  , value_(0.0)
205 {
206 }
207 
208 
209 
211 {
212  goal::on_create();
213  if (!cfg_["engine"].empty() && cfg_["engine"] != "cpp") {
214  unrecognized();
215  value_ = 0;
216  return;
217  }
218  if (const config::attribute_value *v = cfg_.get("value")) {
219  value_ = v->to_double(0);
220  }
221  if (const config::attribute_value *v = cfg_.get("protect_radius")) {
222  radius_ = (*v).to_int(1);
223  }
224 
225  if (radius_<1) {
226  radius_=20;
227  }
228  const config &criteria = cfg_.child("criteria");
229  if (criteria) {
230  filter_ptr_.reset(new terrain_filter(vconfig(criteria),resources::filter_con));
231  }
232 
233 
234 }
235 
236 
237 void protect_goal::add_targets(std::back_insert_iterator< std::vector< target >> target_list)
238 {
239  std::string goal_type;
240  if (protect_unit_) {
241  goal_type = "protect_unit";
242  } else {
243  goal_type ="protect_location";
244  }
245 
246  if (!(this)->active()) {
247  LOG_AI_GOAL << "skipping " << goal_type << " goal - not active" << std::endl;
248  return;
249  }
250 
251  const config &criteria = cfg_.child("criteria");
252  if (!criteria) {
253  LOG_AI_GOAL << "skipping " << goal_type << " goal - no criteria given" << std::endl;
254  return;
255  } else {
256  DBG_AI_GOAL << "side " << get_side() << ": "<< goal_type << " goal with criteria" << std::endl << cfg_.child("criteria") << std::endl;
257  }
258 
259  unit_map &units = resources::gameboard->units();
260 
261  std::set<map_location> items;
262  if (protect_unit_) {
263  const unit_filter ufilt{ vconfig(criteria) };
264  for (const unit &u : units)
265  {
266  // 'protect_unit' can be set to any unit of any side -> exclude hidden units
267  // unless they are visible to the AI side (e.g. allies with shared vision).
268  // As is done in other parts of the AI, units under fog/shroud count as visible to the AI.
269  if (ufilt(u)
270  && (!u.invisible(u.get_location()) || u.is_visible_to_team(current_team(), false)))
271  {
272  DBG_AI_GOAL << "side " << get_side() << ": in " << goal_type << ": " << u.get_location() << " should be protected\n";
273  items.insert(u.get_location());
274  }
275  }
276  } else {
277  filter_ptr_->get_locations(items);
278  }
279  DBG_AI_GOAL << "side " << get_side() << ": searching for threats in "+goal_type+" goal" << std::endl;
280  // Look for directions to protect a specific location or specific unit.
281  for (const map_location &loc : items)
282  {
283  for (const unit &u : units)
284  {
285  int distance = distance_between(u.get_location(), loc);
286  if (current_team().is_enemy(u.side()) && distance < radius_ &&
287  !u.invisible(u.get_location()))
288  {
289  DBG_AI_GOAL << "side " << get_side() << ": in " << goal_type << ": found threat target. " << u.get_location() << " is a threat to "<< loc << '\n';
290  *target_list = target(u.get_location(),
291  value_ * static_cast<double>(radius_ - distance) /
292  radius_, target::TYPE::THREAT);
293  }
294  }
295  }
296 
297 
298 }
299 
300 
301 protect_goal::protect_goal(readonly_context &context, const config &cfg, bool protect_unit)
302  : goal(context,cfg)
303  , filter_ptr_()
304  , protect_unit_(protect_unit)
305  , radius_(20) //this default radius is taken from old code
306  , value_(1.0) //this default value taken from old code
307 {
308 }
309 
311  : goal(context, cfg)
312  , code_()
313  , handler_()
314 {
315  if (cfg.has_attribute("code")) {
316  code_ = cfg["code"].str();
317  }
318  else
319  {
320  ERR_AI_GOAL << "side " << get_side() << " : Error creating Lua goal (missing code= key)" << std::endl;
321  }
322 }
323 
324 void lua_goal::on_create(std::shared_ptr<ai::lua_ai_context> l_ctx)
325 {
326  handler_.reset(resources::lua_kernel->create_lua_ai_action_handler(code_.c_str(), *l_ctx));
327 }
328 
329 void lua_goal::add_targets(std::back_insert_iterator< std::vector< target >> target_list)
330 {
331  std::shared_ptr<lua_object<std::vector<target>>> l_obj = std::make_shared<lua_object<std::vector<target>>>();
332  config c(cfg_.child_or_empty("args"));
333  handler_->handle(c, true, l_obj);
334  try {
335  std::vector < target > targets = *(l_obj->get());
336 
337  for (target tg : targets)
338  {
339  *target_list = tg;
340  }
341  } catch(const bad_enum_cast& e) {
342  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";
343  }
344 
345 }
346 
347 
348 // This is defined in the source file so that it can easily access the logger
349 bool goal_factory::is_duplicate(const std::string& name)
350 {
351  if (get_list().find(name) != get_list().end()) {
352  ERR_AI_GOAL << "Error: Attempt to double-register goal " << name << std::endl;
353  return true;
354  }
355  return false;
356 }
357 
358 
359 } //end of namespace ai
static std::unique_ptr< class sdl_event_handler > handler_
Definition: handler.cpp:62
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:420
virtual void add_targets(std::back_insert_iterator< std::vector< target >> target_list)
Definition: goal.cpp:77
virtual const unit_map & units() const override
Definition: game_board.hpp:114
This class represents a single unit of a specific type.
Definition: unit.hpp:99
virtual bool is_active(const std::string &time_of_day, const std::string &turns) const override
Definition: contexts.hpp:864
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:213
target_location_goal(readonly_context &context, const config &cfg)
Definition: goal.cpp:201
bool active() const
Definition: goal.cpp:118
virtual std::string get_id() const
Definition: goal.cpp:88
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:742
goal(readonly_context &context, const config &cfg)
Definition: goal.cpp:47
virtual void on_create()
Definition: goal.cpp:166
config cfg_
Definition: goal.hpp:72
std::shared_ptr< lua_ai_action_handler > handler_
Definition: goal.hpp:166
const std::vector< std::string > items
virtual void add_targets(std::back_insert_iterator< std::vector< target >> target_list)
Definition: goal.cpp:329
Lua object(value) wrapper implementation.
virtual void on_create()
Definition: goal.cpp:210
static const char * name(const std::vector< SDL_Joystick *> &joysticks, const std::size_t index)
Definition: joystick.cpp:48
A small explanation about what&#39;s going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:58
virtual void on_create()
Definition: goal.cpp:55
bool ok_
Definition: goal.hpp:73
virtual std::string get_engine() const
Definition: goal.cpp:98
filter_context * filter_con
Definition: resources.cpp:23
void unrecognized()
Definition: goal.cpp:65
game_board * gameboard
Definition: resources.cpp:20
virtual void add_targets(std::back_insert_iterator< std::vector< target >> target_list)
Definition: goal.cpp:237
bool is_enemy(int n) const
Definition: team.hpp:243
Managing the AIs lifecycle - headers TODO: Refactor history handling and internal commands...
lua_goal(readonly_context &context, const config &cfg)
Definition: goal.cpp:310
const char * value() const noexcept
Definition: make_enum.hpp:114
Encapsulates the map of the game.
Definition: location.hpp:42
bool redeploy(const config &cfg)
Definition: goal.cpp:104
virtual const team & current_team() const override
Definition: contexts.hpp:524
std::shared_ptr< terrain_filter > filter_ptr_
Definition: goal.hpp:112
std::string code_
Definition: goal.hpp:165
double value() const
Definition: goal.hpp:89
Default AI contexts.
virtual side_number get_side() const override
Get the side number.
Definition: contexts.hpp:465
#define ERR_AI_GOAL
Definition: goal.cpp:45
virtual void add_targets(std::back_insert_iterator< std::vector< target >> target_list)
Definition: goal.cpp:183
virtual void add_targets(std::back_insert_iterator< std::vector< target >> target_list)
Definition: goal.cpp:137
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:600
protect_goal(readonly_context &context, const config &cfg, bool protect_unit)
Definition: goal.cpp:301
bool find(E event, F functor)
Tests whether an event handler is available.
virtual void on_create()
Definition: goal.cpp:124
A variable-expanding proxy for the config class.
Definition: variable.hpp:42
Standard logging facilities (interface).
target_unit_goal(readonly_context &context, const config &cfg)
Definition: goal.cpp:159
#define DBG_AI_GOAL
Definition: goal.cpp:43
bool is_duplicate(const std::string &name)
Definition: goal.cpp:349
game_lua_kernel * lua_kernel
Definition: resources.cpp:25
Container associating units to locations.
Definition: map.hpp:99
#define LOG_AI_GOAL
Definition: goal.cpp:44
#define e
bool ok() const
Definition: goal.cpp:112
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:453
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:92
mock_char c
virtual std::string get_name() const
Definition: goal.cpp:93
virtual config to_config() const
Definition: goal.cpp:83
virtual ~goal()
Definition: goal.cpp:72
void init_readonly_context_proxy(readonly_context &target)
Definition: contexts.hpp:506