The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
contexts.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2009 - 2025
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
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
33static 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// =======================================================================
40namespace ai {
41
42// default ai context
46
50
51// default ai context proxy
52
56
62
66
67int default_ai_context_impl::count_free_hexes_in_castle(const map_location &loc, std::set<map_location> &checked_hexes)
68{
69 int ret = 0;
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
93
95{
96 const gamemap &map_ = resources::gameboard->map();
97 const int defense = u.defense_modifier(map_.get_terrain(loc));
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(loc) && u.get_ability_bool("regenerate", loc) == false) {
106 rating += healing_value;
107 }
108
109 if(map_.is_village(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
124std::vector<target> default_ai_context_impl::find_targets(const move_map& enemy_dstsrc)
125{
126
127 log_scope2(log_ai, "finding targets...");
129 unit_map::iterator leader = units_.find_leader(get_side());
130 const gamemap &map_ = resources::gameboard->map();
131 const bool has_leader = leader != units_.end();
132
133 std::vector<target> targets;
134
135 //=== start getting targets
136
137 //if enemy units are in range of the leader, then we target the enemies who are in range.
138 if(has_leader) {
139 double threat = power_projection(leader->get_location(), enemy_dstsrc);
140 if(threat > 0.0) {
141 //find the location of enemy threats
142 std::set<map_location> threats;
143
144 for(const map_location& adj : get_adjacent_tiles(leader->get_location())) {
145 auto itors = enemy_dstsrc.equal_range(adj);
146 while(itors.first != itors.second) {
147 if(units_.count(itors.first->second)) {
148 threats.insert(itors.first->second);
149 }
150
151 ++itors.first;
152 }
153 }
154
155 assert(threats.empty() == false);
156
157 const double value = threat/static_cast<double>(threats.size());
158 for(std::set<map_location>::const_iterator i = threats.begin(); i != threats.end(); ++i) {
159 LOG_AI << "found threat target... " << *i << " with value: " << value;
160 targets.emplace_back(*i,value,ai_target::type::threat);
161 }
162 }
163 }
164
165 double corner_distance = distance_between(map_location::ZERO(), map_location(map_.w(),map_.h()));
166 double village_value = get_village_value();
167 if(has_leader && village_value > 0.0) {
168 std::map<map_location,pathfind::paths> friends_possible_moves;
169 move_map friends_srcdst, friends_dstsrc;
170 calculate_possible_moves(friends_possible_moves, friends_srcdst, friends_dstsrc, false, true);
171
172 for(const map_location& village_loc : map_.villages()) {
173 assert(map_.on_board(village_loc));
174
175 bool ally_village = false;
176 for(const team& t : resources::gameboard->teams()) {
177 if(!current_team().is_enemy(t.side()) && t.owns_village(village_loc)) {
178 ally_village = true;
179 break;
180 }
181 }
182
183 if (ally_village)
184 {
185 //Support seems to cause the AI to just 'sit around' a lot, so
186 //only turn it on if it's explicitly enabled.
188 double enemy = power_projection(village_loc, enemy_dstsrc);
189 if (enemy > 0)
190 {
191 enemy *= 1.7;
192 double our = power_projection(village_loc, friends_dstsrc);
193 double value = village_value * our / enemy;
194 add_target(target(village_loc, value, ai_target::type::support));
195 }
196 }
197 }
198 else
199 {
200 double leader_distance = distance_between(village_loc, leader->get_location());
201 double value = village_value * (1.0 - leader_distance / corner_distance);
202 LOG_AI << "found village target... " << village_loc
203 << " with value: " << value
204 << " distance: " << leader_distance;
205 targets.emplace_back(village_loc,value,ai_target::type::village);
206 }
207 }
208 }
209
210 std::vector<goal_ptr>& goals = get_goals();
211
212 //find the enemy leaders and explicit targets
214 if (get_leader_value()>0.0) {
215 for(u = units_.begin(); u != units_.end(); ++u) {
216 //is a visible enemy leader
217 if (u->can_recruit() && current_team().is_enemy(u->side())
218 && !u->invisible(u->get_location())) {
219 assert(map_.on_board(u->get_location()));
220 LOG_AI << "found enemy leader (side: " << u->side() << ") target... " << u->get_location() << " with value: " << get_leader_value();
221 targets.emplace_back(u->get_location(), get_leader_value(), ai_target::type::leader);
222 }
223 }
224
225 }
226
227 //explicit targets for this team
228 for(std::vector<goal_ptr>::iterator j = goals.begin();
229 j != goals.end(); ++j) {
230
231 if (!(*j)->active()) {
232 continue;
233 }
234 (*j)->add_targets(std::back_inserter(targets));
235
236 }
237
238 //=== end getting targets
239
240 std::vector<double> new_values;
241
242 for(std::vector<target>::iterator i = targets.begin();
243 i != targets.end(); ++i) {
244
245 new_values.push_back(i->value);
246
247 for(std::vector<target>::const_iterator j = targets.begin(); j != targets.end(); ++j) {
248 if(i->loc == j->loc) {
249 continue;
250 }
251
252 const double distance = std::abs(j->loc.x - i->loc.x) +
253 std::abs(j->loc.y - i->loc.y);
254 new_values.back() += j->value/(distance*distance);
255 }
256 }
257
258 assert(new_values.size() == targets.size());
259 for(std::size_t n = 0; n != new_values.size(); ++n) {
260 LOG_AI << "target value: " << targets[n].value << " -> " << new_values[n];
261 targets[n].value = new_values[n];
262 }
263
264 return targets;
265}
266
267const std::vector<target>& default_ai_context_impl::additional_targets() const
268{
269 return additional_targets_;
270}
271
273{
274 additional_targets_.push_back(t);
275}
276
281
286
287} //of namespace ai
static bool is_enemy(std::size_t side, std::size_t other_side)
map_location loc
Definition move.cpp:172
double t
virtual default_ai_context & get_default_ai_context()
Definition contexts.cpp:90
virtual void clear_additional_targets() const
Definition contexts.cpp:277
virtual const std::vector< target > & additional_targets() const
Definition contexts.cpp:267
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:124
virtual config to_default_ai_context_config() const
Definition contexts.cpp:282
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:272
std::vector< target > additional_targets_
Definition contexts.hpp:236
default_ai_context * target_
Definition contexts.hpp:199
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:447
virtual const std::vector< goal_ptr > & get_goals() const override
Definition contexts.hpp:628
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:494
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:673
virtual double get_village_value() const override
Definition contexts.hpp:738
virtual double get_leader_value() const override
Definition contexts.hpp:653
virtual bool get_support_villages() const override
Definition contexts.hpp:733
void init_readwrite_context_proxy(readwrite_context &target)
Definition contexts.hpp:874
virtual side_number get_side() const override
Get the side number.
Definition contexts.hpp:393
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
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 gamemap & map() const override
virtual const std::vector< team > & teams() const override
team & get_team(int i)
virtual const unit_map & units() const override
terrain_code get_terrain(const map_location &loc) const
Looks up terrain at a particular location.
Definition map.cpp:265
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:347
Encapsulates the map of the game.
Definition map.hpp:176
bool is_village(const map_location &loc) const
Definition map.cpp:60
const std::vector< map_location > & villages() const
Return a list of the locations of villages on the map.
Definition map.hpp:232
int gives_healing(const map_location &loc) const
Definition map.cpp:62
This class stores all the data for a single 'side' (in game nomenclature).
Definition team.hpp:74
bool is_enemy(int n) const
Definition team.hpp:270
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(const 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:39
static lg::log_domain log_ai("ai/general")
#define LOG_AI
Definition contexts.cpp:62
Default AI contexts.
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.
int defense_modifier(const t_translation::terrain_code &terrain, const map_location &loc) const
The unit's defense on a given terrain.
Definition unit.cpp:1777
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:584
void get_adjacent_tiles(const map_location &a, utils::span< map_location, 6 > res)
Function which, given a location, will place all adjacent locations in res.
Definition location.cpp:513
Standard logging facilities (interface).
#define log_scope2(domain, description)
Definition log.hpp:276
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
@ enemy
Belongs to a non-friendly side; normally visualised by not displaying an orb.
This module contains various pathfinding functions and utilities.
std::unique_ptr< MIX_Audio, decltype(&MIX_DestroyAudio)> value
Definition sound.cpp:139
Encapsulates the map of the game.
Definition location.hpp:46
static const map_location & ZERO()
Definition location.hpp:97
static map_location::direction n
#define i