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  //TODO: we will protect hidden units, by not testing for invisibility to current side
267  if (ufilt(u)) {
268  DBG_AI_GOAL << "side " << get_side() << ": in " << goal_type << ": " << u.get_location() << " should be protected\n";
269  items.insert(u.get_location());
270  }
271  }
272  } else {
273  filter_ptr_->get_locations(items);
274  }
275  DBG_AI_GOAL << "side " << get_side() << ": searching for threats in "+goal_type+" goal" << std::endl;
276  // Look for directions to protect a specific location or specific unit.
277  for (const map_location &loc : items)
278  {
279  for (const unit &u : units)
280  {
281  int distance = distance_between(u.get_location(), loc);
282  if (current_team().is_enemy(u.side()) && distance < radius_ &&
283  !u.invisible(u.get_location()))
284  {
285  DBG_AI_GOAL << "side " << get_side() << ": in " << goal_type << ": found threat target. " << u.get_location() << " is a threat to "<< loc << '\n';
286  *target_list = target(u.get_location(),
287  value_ * static_cast<double>(radius_ - distance) /
288  radius_, target::TYPE::THREAT);
289  }
290  }
291  }
292 
293 
294 }
295 
296 
297 protect_goal::protect_goal(readonly_context &context, const config &cfg, bool protect_unit)
298  : goal(context,cfg)
299  , filter_ptr_()
300  , protect_unit_(protect_unit)
301  , radius_(20) //this default radius is taken from old code
302  , value_(1.0) //this default value taken from old code
303 {
304 }
305 
307  : goal(context, cfg)
308  , code_()
309  , handler_()
310 {
311  if (cfg.has_attribute("code")) {
312  code_ = cfg["code"].str();
313  }
314  else
315  {
316  ERR_AI_GOAL << "side " << get_side() << " : Error creating Lua goal (missing code= key)" << std::endl;
317  }
318 }
319 
320 void lua_goal::on_create(std::shared_ptr<ai::lua_ai_context> l_ctx)
321 {
322  handler_.reset(resources::lua_kernel->create_lua_ai_action_handler(code_.c_str(), *l_ctx));
323 }
324 
325 void lua_goal::add_targets(std::back_insert_iterator< std::vector< target >> target_list)
326 {
327  std::shared_ptr<lua_object<std::vector<target>>> l_obj = std::make_shared<lua_object<std::vector<target>>>();
328  config c(cfg_.child_or_empty("args"));
329  handler_->handle(c, true, l_obj);
330  try {
331  std::vector < target > targets = *(l_obj->get());
332 
333  for (target tg : targets)
334  {
335  *target_list = tg;
336  }
337  } catch(const bad_enum_cast& e) {
338  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";
339  }
340 
341 }
342 
343 
344 // This is defined in the source file so that it can easily access the logger
345 bool goal_factory::is_duplicate(const std::string& name)
346 {
347  if (get_list().find(name) != get_list().end()) {
348  ERR_AI_GOAL << "Error: Attempt to double-register goal " << name << std::endl;
349  return true;
350  }
351  return false;
352 }
353 
354 
355 } //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:423
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:882
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:217
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:744
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:325
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.
lua_goal(readonly_context &context, const config &cfg)
Definition: goal.cpp:306
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:530
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:471
#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:297
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:345
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:456
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:512