Little improvement of the pathfinding:

...now prefers using empty hexes

This lowers the frequency of blocked units when doing multi-turn moves
(on homogeneous terrains, because MP cost and defense have priority)
and also help a little fog exploration (since you can't stop on friends)
Was a one-liner but did some cleaning and comments.
This commit is contained in:
Ali El Gariani 2008-04-18 22:23:01 +00:00
parent a123b7c821
commit 3f180a0d1d
3 changed files with 31 additions and 23 deletions

View File

@ -26,7 +26,8 @@ Version 1.5.0-svn:
* new history feature for entering searches, chat messages, commands, and * new history feature for entering searches, chat messages, commands, and
AI formulas AI formulas
* optional cancelling of unit orders in load-game dialog (patch #1024) * optional cancelling of unit orders in load-game dialog (patch #1024)
* smarter pathfinding: if same MP cost, prefer terrains with better defense. * smarter pathfinding: if same MP cost, prefer terrains with better defense
and empty hexes (less frequent multi-turn moves blocked by a friend)
* language and i18n: * language and i18n:
* new translation: Croatian * new translation: Croatian
* updated translations: Chinese, Czech, Danish, Dutch, Finnish, French, * updated translations: Chinese, Czech, Danish, Dutch, Finnish, French,

View File

@ -18,7 +18,8 @@ Version 1.5.0-svn:
* Merged 4p A New Land by Bob_the_Mighty * Merged 4p A New Land by Bob_the_Mighty
* User interface: * User interface:
* Smarter pathfinding: if same MP cost, prefer terrains with better defense. * Smarter pathfinding: if same MP cost, prefer terrains with better defense
and empty hexes (less frequent multi-turn moves blocked by a friend)
Version 1.4: Version 1.4:
* Language and translations * Language and translations

View File

@ -292,15 +292,8 @@ double shortest_path_calculator::cost(const gamemap::location& /*src*/,const gam
{ {
assert(map_.on_board(loc)); assert(map_.on_board(loc));
// The location is not valid // loc is shrouded, consider it impassable
// 1. if the loc is shrouded, or // NOTE: This is why AI must avoid to use shroud
// 2. if moving in it costs more than the total movement of the unit, or
// 3. if there is a visible enemy on the hex, or
// 4. if the unit is not a skirmisher and there is a visible enemy
// with a ZoC on an adjacent hex in the middle of the route
// #4 is a bad criteria! It should be that moving into a ZOC
// uses up the rest of your moves
if (viewing_team_.shrouded(loc)) if (viewing_team_.shrouded(loc))
return getNoPathValue(); return getNoPathValue();
@ -308,16 +301,28 @@ double shortest_path_calculator::cost(const gamemap::location& /*src*/,const gam
int const base_cost = unit_.movement_cost(terrain); int const base_cost = unit_.movement_cost(terrain);
// Pathfinding heuristic: the cost must be at least 1 // Pathfinding heuristic: the cost must be at least 1
VALIDATE(base_cost >= 1, _("Terrain with a movement cost less than 1 encountered.")); VALIDATE(base_cost >= 1, _("Terrain with a movement cost less than 1 encountered."));
// costs more than the total movement of the unit, impassbale
if (total_movement_ < base_cost) if (total_movement_ < base_cost)
return getNoPathValue(); return getNoPathValue();
unit_map::const_iterator unit_map::const_iterator
enemy_unit = find_visible_unit(units_, loc, map_, teams_, viewing_team_), other_unit = find_visible_unit(units_, loc, map_, teams_, viewing_team_);
units_end = units_.end();
if (enemy_unit != units_end && teams_[unit_.side()-1].is_enemy(enemy_unit->second.side()))
return getNoPathValue();
// We can't traverse visible enemy and we also prefer empty hexes
// (less blocking in multi-turn moves and better when exploring fog,
// because we can't stop on a friend)
int other_unit_subcost = 0;
if (other_unit != units_.end()) {
if (teams_[unit_.side()-1].is_enemy(other_unit->second.side()))
return getNoPathValue();
else
// This value will be used with the defense_subcost (see below)
// The 1 here means: consider occupied hex as a -1% defense
// (less important than 10% defense because friends may move)
other_unit_subcost = 1;
}
// Compute how many movement points are left in the game turn // Compute how many movement points are left in the game turn
// needed to reach the previous hex. // needed to reach the previous hex.
// total_movement_ is not zero, thanks to the pathfinding heuristic // total_movement_ is not zero, thanks to the pathfinding heuristic
@ -344,14 +349,15 @@ double shortest_path_calculator::cost(const gamemap::location& /*src*/,const gam
move_cost += need_new_turn ? total_movement_ : remaining_movement; move_cost += need_new_turn ? total_movement_ : remaining_movement;
} }
// we add a tiny cost based on terrain defense, so the pathfinding // We will add a tiny cost based on terrain defense, so the pathfinding
// prefer good terrains between 2 with the same MP cost // will prefer good terrains between 2 with the same MP cost
// we divide defense by 100 * 100, because defense it's 100-based // Keep in mind that defense_modifier is inverted (= 100 - defense%)
// and we don't want any impact on move cost for less then 100-steps path const int defense_subcost = unit_.defense_modifier(terrain);
// (even ~200 since mean defense is around ~50%)
const double defense_cost = unit_.defense_modifier(terrain) / 10000.0;
return move_cost + defense_cost; // We divide subcosts by 100 * 100, because defense is 100-based and
// we don't want any impact on move cost for less then 100-steps path
// (even ~200 since mean defense is around ~50%)
return move_cost + (defense_subcost + other_unit_subcost) / 10000.0;
} }
emergency_path_calculator::emergency_path_calculator(const unit& u, const gamemap& map) emergency_path_calculator::emergency_path_calculator(const unit& u, const gamemap& map)