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