The Battle for Wesnoth  1.15.12+dev
component.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2018 by Yurii Chernyi <terraninfo@terraninfo.net>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 /**
16  * Composite AI component
17  * @file
18  */
19 
21 #include "ai/composite/engine.hpp"
23 #include "config.hpp"
24 #include "log.hpp"
25 #include "units/unit.hpp"
26 
27 #include "ai/formula/ai.hpp"
28 
29 #include <boost/regex.hpp>
30 
31 namespace pathfind {
32 
33 struct pathfind;
34 
35 } //of namespace pathfind
36 
37 namespace ai {
38 
39 static lg::log_domain log_ai_component("ai/component");
40 #define DBG_AI_COMPONENT LOG_STREAM(debug, log_ai_component)
41 #define LOG_AI_COMPONENT LOG_STREAM(info, log_ai_component)
42 #define ERR_AI_COMPONENT LOG_STREAM(err, log_ai_component)
43 
44 /*
45 [modify_ai]
46  path = "stage[fallback]
47  action = "change"
48  [stage]...[/stage]
49 [/modify_ai]
50 
51 [modify_ai]
52  component = "aspect[avoid].facet[zzz]"
53  action = "change"
54  [facet]...[/facet]
55 [/modify_ai]
56 
57 [modify_ai]
58  path = "aspect[aggression].facet[zzzz]
59  action = "delete"
60 [/modify_ai]
61 
62 [modify_ai]
63  component = "aspect[aggression].facet"
64  action = "add"
65  [facet]...[/facet]
66 [/modify_ai]
67 */
68 
70 {
71  std::map<std::string, property_handler_ptr>::iterator i = property_handlers_.find(child.property);
72  if (i!=property_handlers_.end()) {
73  return i->second->handle_get(child);
74  }
75  return nullptr;
76 }
77 
78 bool component::add_child(const path_element &child, const config &cfg)
79 {
80  std::map<std::string, property_handler_ptr>::iterator i = property_handlers_.find(child.property);
81  if (i!=property_handlers_.end()) {
82  return i->second->handle_add(child,cfg);
83  }
84  return false;
85 }
86 
87 bool component::change_child(const path_element &child, const config &cfg)
88 {
89  std::map<std::string, property_handler_ptr>::iterator i = property_handlers_.find(child.property);
90  if (i!=property_handlers_.end()) {
91  return i->second->handle_change(child,cfg);
92  }
93  return false;
94 }
95 
96 bool component::delete_child(const path_element &child)
97 {
98  std::map<std::string, property_handler_ptr>::iterator i = property_handlers_.find(child.property);
99  if (i!=property_handlers_.end()) {
100  return i->second->handle_delete(child);
101  }
102  return false;
103 }
104 
105 std::vector<component*> component::get_children(const std::string &type)
106 {
107  property_handler_map::iterator i = property_handlers_.find(type);
108  if (i!=property_handlers_.end()) {
109  return i->second->handle_get_children();
110  }
111 
112  return std::vector<component*>();
113 }
114 
115 std::vector<std::string> component::get_children_types()
116 {
117  std::vector<std::string> types;
118  for (property_handler_map::value_type &ph : property_handlers_) {
119  types.push_back(ph.first);
120  }
121  return types;
122 }
123 
124 property_handler_map& component::property_handlers()
125 {
126  return property_handlers_;
127 }
128 
129 static component *find_component(component *root, const std::string &path, path_element &tail)
130 {
131  if (root==nullptr) {
132  return nullptr;
133  }
134 
135  //match path elements in [modify_ai] tag
136  boost::regex re(R"""(([^\.^\[]+)(\[(\d*)\]|\[([^\]]+)\]|()))""");
137  const int sub_matches[] {1,3,4};
138  boost::sregex_token_iterator i(path.begin(), path.end(), re, sub_matches);
139  boost::sregex_token_iterator j;
140 
141  component *c = root;
142 
143  std::vector< path_element > elements;
144  while(i != j)
145  {
146  path_element pe;
147  pe.property = *i++;
148  std::string position = *i++;
149  pe.id = *i++;
150  if (position.empty()) {
151  pe.position = -2;
152  } else {
153  try {
154  pe.position = std::stoi(position);
155  } catch (const std::invalid_argument&) {
156  pe.position = -2;
157  }
158  }
159  //DBG_AI_COMPONENT << "adding path element: "<< pe << std::endl;
160  elements.push_back(pe);
161  }
162  if (elements.size()<1) {
163  return nullptr;
164  }
165 
166  std::vector< path_element >::iterator k_max = elements.end()-1;
167  for (std::vector< path_element >::iterator k = elements.begin(); k!=k_max; ++k) {
168  //not last
169  c = c->get_child(*k);
170  if (c==nullptr) {
171  return nullptr;
172  }
173  }
174 
175  tail = *k_max;
176  return c;
177 
178 }
179 
180 bool component_manager::add_component(component *root, const std::string &path, const config &cfg)
181 {
182  path_element tail;
183  component *c = find_component(root,path,tail);
184  if (c==nullptr) {
185  return false;
186  }
187  const config &ch = cfg.child(tail.property);
188  if (!ch) {
189  return false;
190  }
191  return c->add_child(tail, ch);
192 
193 }
194 
195 bool component_manager::change_component(component *root, const std::string &path, const config &cfg)
196 {
197  path_element tail;
198  component *c = find_component(root,path,tail);
199  if (c==nullptr) {
200  return false;
201  }
202  const config &ch = cfg.child(tail.property);
203  if (!ch) {
204  return false;
205  }
206  return c->change_child(tail,ch);
207 }
208 
209 bool component_manager::delete_component(component *root, const std::string &path)
210 {
211  path_element tail;
212  component *c = find_component(root,path,tail);
213  if (c==nullptr) {
214  return false;
215  }
216  return c->delete_child(tail);
217 }
218 
219 static void print_component(component *root, const std::string &type, std::stringstream &s, int offset)
220 {
221  std::stringstream offset_ss;
222  for (int i=0;i<offset;++i) {
223  offset_ss<<" ";
224  }
225  const std::string &offset_str = offset_ss.str();
226 
227  const std::vector<std::string> &t_list = root->get_children_types();
228 
229  s << offset_str << type<<"["<<root->get_id() <<"] "<<root->get_engine()<<" "<<root->get_name()<< std::endl;
230 
231  for (std::string t : t_list) {
232  std::vector<component*> c_list = root->get_children(t);
233  for (component *c : c_list) {
234  print_component(c,t,s,offset+1);
235  }
236  }
237 }
238 
239 std::string component_manager::print_component_tree(component *root, const std::string &path)
240 {
241  path_element tail;
242  component *c;
243  if (!path.empty()) {
244  c = find_component(root,path,tail);
245  if (c==nullptr) {
246  ERR_AI_COMPONENT << "unable to find component" <<std::endl;
247  return "";
248  }
249  } else {
250  c = root;
251  }
252  std::stringstream s;
253  print_component(c, "", s, 0);
254  return s.str();
255 }
256 
257 component* component_manager::get_component(component *root, const std::string &path)
258 {
259  if(!path.empty()) {
260  path_element tail;
261  return find_component(root, path, tail);
262  }
263  return nullptr;
264 }
265 
266 } //end of namespace ai
267 
268 std::ostream &operator<<(std::ostream &o, const ai::path_element &e)
269 {
270  o << "property["<<e.property<<"] id["<<e.id <<"] position["<<e.position<<"]"<<std::endl;
271  return o;
272 }
Defines formula ai.
virtual std::string get_id() const =0
virtual bool change_child(const path_element &child, const config &cfg)
Definition: component.cpp:87
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 std::vector< component * > get_children(const std::string &type)
Definition: component.cpp:105
AI Support engine - creating specific ai components from config.
Definitions for the interface to Wesnoth Markup Language (WML).
virtual bool add_child(const path_element &child, const config &cfg)
Definition: component.cpp:78
static component * find_component(component *root, const std::string &path, path_element &tail)
Definition: component.cpp:129
A small explanation about what&#39;s going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:59
static void print_component(component *root, const std::string &type, std::stringstream &s, int offset)
Definition: component.cpp:219
virtual std::string get_engine() const =0
A component of the AI framework.
std::ostream & operator<<(std::ostream &o, const ai::path_element &e)
Definition: component.cpp:268
virtual component * get_child(const path_element &child)
Definition: component.cpp:69
std::string path
Definition: game_config.cpp:38
std::string property
Definition: component.hpp:41
std::string id
Definition: component.hpp:42
virtual std::string get_name() const =0
static lg::log_domain log_ai_component("ai/component")
virtual bool delete_child(const path_element &child)
Definition: component.cpp:96
std::size_t i
Definition: function.cpp:940
static map_location::DIRECTION s
const config & get_child(const std::string &key)
Definition: general.cpp:213
virtual std::vector< std::string > get_children_types()
Definition: component.cpp:115
Composite AI component.
double t
Definition: astarsearch.cpp:64
std::map< std::string, property_handler_ptr > property_handler_map
Definition: component.hpp:48
#define ERR_AI_COMPONENT
Definition: component.cpp:42
Standard logging facilities (interface).
#define e
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:59
mock_char c
std::string::const_iterator iterator
Definition: tokenizer.hpp:24