The Battle for Wesnoth  1.15.9+dev
contexts.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  * Helper functions for the object which operates in the context of AI for specific side
17  * This is part of AI interface
18  * @file
19  */
20 
21 #include "ai/default/contexts.hpp"
22 
23 #include "game_board.hpp"
24 #include "log.hpp"
25 #include "map/map.hpp"
26 #include "resources.hpp"
27 #include "team.hpp"
28 #include "units/unit.hpp"
29 #include "ai/composite/goal.hpp"
30 #include "pathfind/pathfind.hpp"
31 
32 static lg::log_domain log_ai("ai/general");
33 #define DBG_AI LOG_STREAM(debug, log_ai)
34 #define LOG_AI LOG_STREAM(info, log_ai)
35 #define WRN_AI LOG_STREAM(warn, log_ai)
36 #define ERR_AI LOG_STREAM(err, log_ai)
37 
38 // =======================================================================
39 namespace ai {
40 
41 // default ai context
43 {
44 }
45 
47 {
48 }
49 
50 // default ai context proxy
51 
53 {
54 }
55 
57 {
58  init_readwrite_context_proxy(target);
59  target_= &target.get_default_ai_context();
60 }
61 
63 {
64 }
65 
66 int default_ai_context_impl::count_free_hexes_in_castle(const map_location &loc, std::set<map_location> &checked_hexes)
67 {
68  int ret = 0;
69  unit_map &units_ = resources::gameboard->units();
70  for(const map_location& adj : get_adjacent_tiles(loc)) {
71  if (checked_hexes.find(adj) != checked_hexes.end())
72  continue;
73  checked_hexes.insert(adj);
74  if (resources::gameboard->map().is_castle(adj)) {
75  const unit_map::const_iterator u = units_.find(adj);
76  ret += count_free_hexes_in_castle(adj, checked_hexes);
77  if (u == units_.end()
78  || (current_team().is_enemy(u->side())
79  && u->invisible(adj))
80  || ((&resources::gameboard->get_team(u->side()) == &current_team())
81  && u->movement_left() > 0)) {
82  ret += 1;
83  }
84  }
85  }
86  return ret;
87 }
88 
90  return *this;
91 }
92 
94 {
95  const gamemap &map_ = resources::gameboard->map();
96  const t_translation::terrain_code terrain = map_.get_terrain(loc);
97  const int defense = u.defense_modifier(terrain);
98  int rating = 100 - defense;
99 
100  const int healing_value = 10;
101  const int friendly_village_value = 5;
102  const int neutral_village_value = 10;
103  const int enemy_village_value = 15;
104 
105  if(map_.gives_healing(terrain) && u.get_ability_bool("regenerate", loc) == false) {
106  rating += healing_value;
107  }
108 
109  if(map_.is_village(terrain)) {
110  int owner = resources::gameboard->village_owner(loc);
111 
112  if(owner == get_side()) {
113  rating += friendly_village_value;
114  } else if(owner == 0) {
115  rating += neutral_village_value;
116  } else {
117  rating += enemy_village_value;
118  }
119  }
120 
121  return rating;
122 }
123 
124 std::vector<target> default_ai_context_impl::find_targets(const move_map& enemy_dstsrc)
125 {
126 
127  log_scope2(log_ai, "finding targets...");
128  unit_map &units_ = resources::gameboard->units();
129  unit_map::iterator leader = units_.find_leader(get_side());
130  const gamemap &map_ = resources::gameboard->map();
131  std::vector<team> teams_ = resources::gameboard->teams();
132  const bool has_leader = leader != units_.end();
133 
134  std::vector<target> targets;
135 
136  //=== start getting targets
137 
138  //if enemy units are in range of the leader, then we target the enemies who are in range.
139  if(has_leader) {
140  double threat = power_projection(leader->get_location(), enemy_dstsrc);
141  if(threat > 0.0) {
142  //find the location of enemy threats
143  std::set<map_location> threats;
144 
145  for(const map_location& adj : get_adjacent_tiles(leader->get_location())) {
146  std::pair<move_map::const_iterator,move_map::const_iterator> itors = enemy_dstsrc.equal_range(adj);
147  while(itors.first != itors.second) {
148  if(units_.count(itors.first->second)) {
149  threats.insert(itors.first->second);
150  }
151 
152  ++itors.first;
153  }
154  }
155 
156  assert(threats.empty() == false);
157 
158  const double value = threat/static_cast<double>(threats.size());
159  for(std::set<map_location>::const_iterator i = threats.begin(); i != threats.end(); ++i) {
160  LOG_AI << "found threat target... " << *i << " with value: " << value << "\n";
161  targets.emplace_back(*i,value,target::TYPE::THREAT);
162  }
163  }
164  }
165 
166  double corner_distance = distance_between(map_location::ZERO(), map_location(map_.w(),map_.h()));
167  double village_value = get_village_value();
168  if(has_leader && village_value > 0.0) {
169  std::map<map_location,pathfind::paths> friends_possible_moves;
170  move_map friends_srcdst, friends_dstsrc;
171  calculate_possible_moves(friends_possible_moves, friends_srcdst, friends_dstsrc, false, true);
172 
173  const std::vector<map_location>& villages = map_.villages();
174  for(std::vector<map_location>::const_iterator t =
175  villages.begin(); t != villages.end(); ++t) {
176 
177  assert(map_.on_board(*t));
178  bool ally_village = false;
179  for (std::size_t i = 0; i != teams_.size(); ++i)
180  {
181  if (!current_team().is_enemy(i + 1) && teams_[i].owns_village(*t)) {
182  ally_village = true;
183  break;
184  }
185  }
186 
187  if (ally_village)
188  {
189  //Support seems to cause the AI to just 'sit around' a lot, so
190  //only turn it on if it's explicitly enabled.
191  if(get_support_villages()) {
192  double enemy = power_projection(*t, enemy_dstsrc);
193  if (enemy > 0)
194  {
195  enemy *= 1.7;
196  double our = power_projection(*t, friends_dstsrc);
197  double value = village_value * our / enemy;
198  add_target(target(*t, value, target::TYPE::SUPPORT));
199  }
200  }
201  }
202  else
203  {
204  double leader_distance = distance_between(*t, leader->get_location());
205  double value = village_value * (1.0 - leader_distance / corner_distance);
206  LOG_AI << "found village target... " << *t
207  << " with value: " << value
208  << " distance: " << leader_distance << '\n';
209  targets.emplace_back(*t,value,target::TYPE::VILLAGE);
210  }
211  }
212  }
213 
214  std::vector<goal_ptr>& goals = get_goals();
215 
216  //find the enemy leaders and explicit targets
218  if (get_leader_value()>0.0) {
219  for(u = units_.begin(); u != units_.end(); ++u) {
220  //is a visible enemy leader
221  if (u->can_recruit() && current_team().is_enemy(u->side())
222  && !u->invisible(u->get_location())) {
223  assert(map_.on_board(u->get_location()));
224  LOG_AI << "found enemy leader (side: " << u->side() << ") target... " << u->get_location() << " with value: " << get_leader_value() << "\n";
225  targets.emplace_back(u->get_location(), get_leader_value(), target::TYPE::LEADER);
226  }
227  }
228 
229  }
230 
231  //explicit targets for this team
232  for(std::vector<goal_ptr>::iterator j = goals.begin();
233  j != goals.end(); ++j) {
234 
235  if (!(*j)->active()) {
236  continue;
237  }
238  (*j)->add_targets(std::back_inserter(targets));
239 
240  }
241 
242  //=== end getting targets
243 
244  std::vector<double> new_values;
245 
246  for(std::vector<target>::iterator i = targets.begin();
247  i != targets.end(); ++i) {
248 
249  new_values.push_back(i->value);
250 
251  for(std::vector<target>::const_iterator j = targets.begin(); j != targets.end(); ++j) {
252  if(i->loc == j->loc) {
253  continue;
254  }
255 
256  const double distance = std::abs(j->loc.x - i->loc.x) +
257  std::abs(j->loc.y - i->loc.y);
258  new_values.back() += j->value/(distance*distance);
259  }
260  }
261 
262  assert(new_values.size() == targets.size());
263  for(std::size_t n = 0; n != new_values.size(); ++n) {
264  LOG_AI << "target value: " << targets[n].value << " -> " << new_values[n] << "\n";
265  targets[n].value = new_values[n];
266  }
267 
268  return targets;
269 }
270 
271 const std::vector<target>& default_ai_context_impl::additional_targets() const
272 {
273  return additional_targets_;
274 }
275 
277 {
278  additional_targets_.push_back(t);
279 }
280 
282 {
283  additional_targets_.clear();
284 }
285 
287 {
288  return config();
289 }
290 
291 } //of namespace ai
virtual default_ai_context & get_default_ai_context()=0
int village_owner(const map_location &loc) const
Given the location of a village, will return the 1-based number of the team that currently owns it...
int h() const
Effective map height, in hexes.
Definition: map.hpp:124
unit_iterator end()
Definition: map.hpp:428
virtual const std::vector< team > & teams() const override
Definition: game_board.hpp:82
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
Definition: location.cpp:474
virtual const unit_map & units() const override
Definition: game_board.hpp:109
This class represents a single unit of a specific type.
Definition: unit.hpp:119
static const map_location & ZERO()
Definition: location.hpp:74
unit_iterator find_leader(int side)
Definition: map.cpp:327
virtual config to_default_ai_context_config() const
Definition: contexts.cpp:286
virtual void calculate_possible_moves(std::map< map_location, pathfind::paths > &possible_moves, move_map &srcdst, move_map &dstsrc, bool enemy, bool assume_full_movement=false, const terrain_filter *remove_destinations=nullptr) const =0
virtual const gamemap & map() const override
Definition: game_board.hpp:99
unit_iterator begin()
Definition: map.hpp:418
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Definition: translation.hpp:48
virtual bool get_support_villages() const =0
int count_free_hexes_in_castle(const map_location &loc, std::set< map_location > &checked_hexes)
Definition: contexts.cpp:66
bool on_board(const map_location &loc) const
Tell if a location is on the map.
Definition: map.cpp:382
virtual void clear_additional_targets() const
Definition: contexts.cpp:281
virtual double get_village_value() const =0
virtual std::vector< target > find_targets(const move_map &enemy_dstsrc)
Definition: contexts.cpp:124
t_translation::terrain_code get_terrain(const map_location &loc) const
Looks up terrain at a particular location.
Definition: map.cpp:314
std::multimap< map_location, map_location > move_map
The standard way in which a map of possible moves is recorded.
Definition: game_info.hpp:42
#define LOG_AI
Definition: contexts.cpp:34
int defense_modifier(const t_translation::terrain_code &terrain) const
The unit&#39;s defense on a given terrain.
Definition: unit.cpp:1596
Belongs to a non-friendly side; normally visualised by not displaying an orb.
A small explanation about what&#39;s going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:59
int gives_healing(const map_location &loc) const
Definition: map.cpp:66
default_ai_context()
Constructor.
Definition: contexts.cpp:42
virtual default_ai_context & get_default_ai_context()
Definition: contexts.cpp:89
static lg::log_domain log_ai("ai/general")
game_board * gameboard
Definition: resources.cpp:20
Encapsulates the map of the game.
Definition: map.hpp:33
virtual const std::vector< target > & additional_targets() const
Definition: contexts.cpp:271
bool is_enemy(int n) const
Definition: team.hpp:251
#define log_scope2(domain, description)
Definition: log.hpp:209
std::size_t count(const map_location &loc) const
Definition: map.hpp:413
virtual double power_projection(const map_location &loc, const move_map &dstsrc) const =0
Function which finds how much &#39;power&#39; a side can attack a certain location with.
virtual void add_target(const target &t) const
Definition: contexts.cpp:276
void init_default_ai_context_proxy(default_ai_context &target)
Definition: contexts.cpp:56
Encapsulates the map of the game.
Definition: location.hpp:37
unit_iterator find(std::size_t id)
Definition: map.cpp:309
bool get_ability_bool(const std::string &tag_name, const map_location &loc) const
Checks whether this unit currently possesses or is affected by a given ability.
Definition: abilities.cpp:144
int w() const
Effective map width, in hexes.
Definition: map.hpp:121
virtual int count_free_hexes_in_castle(const map_location &loc, std::set< map_location > &checked_hexes)=0
std::size_t i
Definition: function.cpp:933
virtual const std::vector< goal_ptr > & get_goals() const =0
virtual ~default_ai_context()
Destructor.
Definition: contexts.cpp:46
virtual const team & current_team() const =0
Default AI contexts.
virtual double get_leader_value() const =0
virtual ~default_ai_context_proxy()
Definition: contexts.cpp:52
bool is_village(const map_location &loc) const
Definition: map.cpp:64
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
double t
Definition: astarsearch.cpp:64
const std::vector< map_location > & villages() const
Return a list of the locations of villages on the map.
Definition: map.hpp:188
Standard logging facilities (interface).
virtual side_number get_side() const =0
Get the side number.
virtual int rate_terrain(const unit &u, const map_location &loc) const
Definition: contexts.cpp:93
Container associating units to locations.
Definition: map.hpp:97
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:60
static map_location::DIRECTION n
virtual ~default_ai_context_impl()
Definition: contexts.cpp:62
This module contains various pathfinding functions and utilities.
std::string::const_iterator iterator
Definition: tokenizer.hpp:24
virtual void add_target(const target &t) const =0