widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #12414
[Merge] lp:~widelands-dev/widelands/findpath_modification into lp:widelands
TiborB has proposed merging lp:~widelands-dev/widelands/findpath_modification into lp:widelands.
Requested reviews:
Widelands Developers (widelands-dev)
For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/findpath_modification/+merge/337103
This is mainly AI thing. First this contains extension to map::findpath function (now used only by AI) to be more sensitive about building capabilities of field where the road is going to lead. (To avoid them a bit)
Subsequently I did some changes to AI's road creating algorithm.
--
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/findpath_modification into lp:widelands.
=== modified file 'src/ai/ai_help_structs.cc'
--- src/ai/ai_help_structs.cc 2017-11-24 09:19:52 +0000
+++ src/ai/ai_help_structs.cc 2018-02-02 22:36:27 +0000
@@ -191,8 +191,15 @@
return false;
}
-NearFlag::NearFlag(const Flag& f, int32_t const c, int32_t const d)
- : flag(&f), cost(c), distance(d) {
+NearFlag::NearFlag(const Flag& f, int32_t const c)
+ : flag(&f), current_road_distance(c) {
+ to_be_checked = true;
+}
+
+NearFlag::NearFlag() {
+ flag = nullptr;
+ current_road_distance = 0;
+ to_be_checked = true;
}
EventTimeQueue::EventTimeQueue() {
@@ -870,56 +877,38 @@
return (blocked_fields_.count(coords.hash()) != 0);
}
-FlagsForRoads::Candidate::Candidate(uint32_t coords, int32_t distance, bool economy)
- : coords_hash(coords), air_distance(distance), different_economy(economy) {
+// as a policy, we just set some default value, that will be updated later on
+FlagsForRoads::Candidate::Candidate(uint32_t coords, int32_t distance, bool different_economy)
+ : coords_hash(coords), air_distance(distance) {
new_road_possible = false;
- accessed_via_roads = false;
+ new_road_length = 200;
// Values are only very rough, and are dependant on the map size
- new_road_length = 2 * Widelands::kMapDimensions.at(Widelands::kMapDimensions.size() - 1);
- current_roads_distance = 2 * (Widelands::kMapDimensions.size() - 1); // must be big enough
- reduction_score = -air_distance; // allows reasonable ordering from the start
+ current_road_length = (different_economy) ? 600 : 400; // must be big enough
}
+// Used when sorting cadidate flags from best one
bool FlagsForRoads::Candidate::operator<(const Candidate& other) const {
- if (reduction_score == other.reduction_score) {
- return coords_hash < other.coords_hash;
- } else {
- return reduction_score > other.reduction_score;
- }
+ const int32_t other_rs = other.reduction_score();
+ const int32_t this_rs = reduction_score();
+ return std::tie(other.new_road_possible, other_rs) < std::tie(new_road_possible, this_rs);
}
bool FlagsForRoads::Candidate::operator==(const Candidate& other) const {
return coords_hash == other.coords_hash;
}
-void FlagsForRoads::Candidate::calculate_score() {
- if (!new_road_possible) {
- reduction_score = kRoadNotFound - air_distance; // to have at least some ordering preserved
- } else if (different_economy) {
- reduction_score = kRoadToDifferentEconomy - air_distance - 2 * new_road_length;
- } else if (!accessed_via_roads) {
- if (air_distance + 6 > new_road_length) {
- reduction_score = kShortcutWithinSameEconomy - air_distance - 2 * new_road_length;
- } else {
- reduction_score = kRoadNotFound;
- }
- } else {
- reduction_score = current_roads_distance - 2 * new_road_length;
- }
-}
-
void FlagsForRoads::print() { // this is for debugging and development purposes
- for (auto& candidate_flag : queue) {
+ for (auto& candidate_flag : flags_queue) {
log(" %starget: %3dx%3d, saving: %5d (%3d), air distance: %3d, new road: %6d, score: %5d "
"%s\n",
- (candidate_flag.reduction_score >= min_reduction && candidate_flag.new_road_possible) ?
+ (candidate_flag.reduction_score() >= min_reduction && candidate_flag.new_road_possible) ?
"+" :
" ",
Coords::unhash(candidate_flag.coords_hash).x,
Coords::unhash(candidate_flag.coords_hash).y,
- candidate_flag.current_roads_distance - candidate_flag.new_road_length, min_reduction,
+ candidate_flag.current_road_length - candidate_flag.new_road_length, min_reduction,
candidate_flag.air_distance, candidate_flag.new_road_length,
- candidate_flag.reduction_score,
+ candidate_flag.reduction_score(),
(candidate_flag.new_road_possible) ? ", new road possible" : " ");
}
}
@@ -927,7 +916,7 @@
// Queue is ordered but some target flags are only estimations so we take such a candidate_flag
// first
bool FlagsForRoads::get_best_uncalculated(uint32_t* winner) {
- for (auto& candidate_flag : queue) {
+ for (auto& candidate_flag : flags_queue) {
if (!candidate_flag.new_road_possible) {
*winner = candidate_flag.coords_hash;
return true;
@@ -937,77 +926,57 @@
}
// Road from starting flag to this flag can be built
-void FlagsForRoads::road_possible(Widelands::Coords coords, uint32_t distance) {
- // std::set does not allow updating
- Candidate new_candidate_flag = Candidate(0, 0, false);
- for (auto candidate_flag : queue) {
- if (candidate_flag.coords_hash == coords.hash()) {
- new_candidate_flag = candidate_flag;
- assert(new_candidate_flag.coords_hash == candidate_flag.coords_hash);
- queue.erase(candidate_flag);
- break;
- }
- }
-
- new_candidate_flag.new_road_length = distance;
- new_candidate_flag.new_road_possible = true;
- new_candidate_flag.calculate_score();
- queue.insert(new_candidate_flag);
-}
-
-// Remove the flag from candidates as interconnecting road is not possible
-void FlagsForRoads::road_impossible(Widelands::Coords coords) {
- const uint32_t hash = coords.hash();
- for (auto candidate_flag : queue) {
- if (candidate_flag.coords_hash == hash) {
- queue.erase(candidate_flag);
- return;
- }
- }
-}
-
-// Updating walking distance over existing roads
-// Queue does not allow modifying its members so we erase and then eventually insert modified member
-void FlagsForRoads::set_road_distance(Widelands::Coords coords, int32_t distance) {
- const uint32_t hash = coords.hash();
- Candidate new_candidate_flag = Candidate(0, 0, false);
- bool replacing = false;
- for (auto candidate_flag : queue) {
- if (candidate_flag.coords_hash == hash) {
- assert(!candidate_flag.different_economy);
- if (distance < candidate_flag.current_roads_distance) {
- new_candidate_flag = candidate_flag;
- queue.erase(candidate_flag);
- replacing = true;
- break;
- }
- break;
- }
- }
- if (replacing) {
- new_candidate_flag.current_roads_distance = distance;
- new_candidate_flag.accessed_via_roads = true;
- new_candidate_flag.calculate_score();
- queue.insert(new_candidate_flag);
- }
-}
-
+void FlagsForRoads::road_possible(Widelands::Coords coords, const uint32_t new_road) {
+ for (auto& candidate_flag : flags_queue) {
+ if (candidate_flag.coords_hash == coords.hash()) {
+ candidate_flag.new_road_length = new_road;
+ // candidate_flag.current_roads_distance = current_road;
+ candidate_flag.new_road_possible = true;
+ candidate_flag.reduction_score();
+ return;
+ }
+ }
+ NEVER_HERE();
+}
+
+// find_reachable_fields returns duplicates so we deal with them
+bool FlagsForRoads::has_candidate(const uint32_t hash) {
+ for (auto& candidate_flag : flags_queue) {
+ if (candidate_flag.coords_hash == hash) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// Updating walking distance into flags_queue
+void FlagsForRoads::set_cur_road_distance(Widelands::Coords coords, int32_t cur_distance) {
+ for (auto& candidate_flag : flags_queue) {
+ if (candidate_flag.coords_hash == coords.hash()) {
+ candidate_flag.current_road_length = cur_distance;
+ candidate_flag.reduction_score();
+ return;
+ }
+ }
+}
+
+// Returns mostly best candidate, as a result of sorting
bool FlagsForRoads::get_winner(uint32_t* winner_hash) {
// If AI can ask for 2nd position, but there is only one viable candidate
// we return the first one of course
bool has_winner = false;
- for (auto candidate_flag : queue) {
- if (candidate_flag.reduction_score < min_reduction || !candidate_flag.new_road_possible) {
+ for (auto candidate_flag : flags_queue) {
+ if (candidate_flag.reduction_score() < min_reduction || !candidate_flag.new_road_possible) {
continue;
}
assert(candidate_flag.air_distance > 0);
- assert(candidate_flag.reduction_score >= min_reduction);
+ assert(candidate_flag.reduction_score() >= min_reduction);
assert(candidate_flag.new_road_possible);
*winner_hash = candidate_flag.coords_hash;
has_winner = true;
- if (std::rand() % 3 > 0) {
- // with probability of 2/3 we accept this flag
+ if (std::rand() % 4 > 0) {
+ // with probability of 3/4 we accept this flag
return true;
}
}
=== modified file 'src/ai/ai_help_structs.h'
--- src/ai/ai_help_structs.h 2017-11-17 07:16:12 +0000
+++ src/ai/ai_help_structs.h 2018-02-02 22:36:27 +0000
@@ -255,14 +255,14 @@
// ordering nearflags by biggest reduction
struct CompareShortening {
bool operator()(const NearFlag& a, const NearFlag& b) const {
- return (a.cost - a.distance) > (b.cost - b.distance);
+ return a.current_road_distance > b.current_road_distance;
}
};
-
- NearFlag(const Flag& f, int32_t const c, int32_t const d);
+ NearFlag();
+ NearFlag(const Flag& f, int32_t const c);
bool operator<(const NearFlag& f) const {
- return cost > f.cost;
+ return current_road_distance > f.current_road_distance;
}
bool operator==(Flag const* const f) const {
@@ -270,8 +270,8 @@
}
Flag const* flag;
- int32_t cost;
- int32_t distance;
+ bool to_be_checked;
+ uint32_t current_road_distance;
};
// FIFO like structure for pairs <gametime,id>, where id is optional
@@ -731,45 +731,44 @@
struct Candidate {
Candidate();
- Candidate(uint32_t coords, int32_t distance, bool economy);
+ Candidate(uint32_t coords, int32_t distance, bool different_economy);
uint32_t coords_hash;
int32_t new_road_length;
- int32_t current_roads_distance;
+ int32_t current_road_length;
int32_t air_distance;
- int32_t reduction_score;
- bool different_economy;
+
bool new_road_possible;
- bool accessed_via_roads;
bool operator<(const Candidate& other) const;
bool operator==(const Candidate& other) const;
- void calculate_score();
+ int32_t reduction_score() const {return current_road_length - new_road_length - (new_road_length - air_distance) / 3;};
};
int32_t min_reduction;
- // This is the core of this object - candidate flags ordered by score
- std::set<Candidate> queue;
+ // This is the core of this object - candidate flags to be ordered by air_distance
+ std::deque<Candidate> flags_queue; //NOCOM
- void add_flag(Widelands::Coords coords, int32_t air_dist, bool diff_economy) {
- queue.insert(Candidate(coords.hash(), air_dist, diff_economy));
+ void add_flag(Widelands::Coords coords, int32_t air_dist, bool different_economy) {
+ flags_queue.push_back(Candidate(coords.hash(), air_dist, different_economy));
}
uint32_t count() {
- return queue.size();
+ return flags_queue.size();
}
+ bool has_candidate(const uint32_t hash);
// This is for debugging and development purposes
void print();
// during processing we need to pick first one uprocessed flag (with best score so far)
bool get_best_uncalculated(uint32_t* winner);
// When we test candidate flag if road can be built to it, there are two possible outcomes:
- void road_possible(Widelands::Coords coords, uint32_t distance);
- void road_impossible(Widelands::Coords coords);
+ void road_possible(Widelands::Coords coords, const uint32_t new_road);
// Updating walking distance over existing roads
- void set_road_distance(Widelands::Coords coords, int32_t distance);
+ void set_cur_road_distance(Widelands::Coords coords, const int32_t cur_distance);
// Finally we query the flag that we will build a road to
bool get_winner(uint32_t* winner_hash);
+
};
// This is a struct that stores strength of players, info on teams and provides some outputs from
=== modified file 'src/ai/defaultai.cc'
--- src/ai/defaultai.cc 2018-01-30 11:44:48 +0000
+++ src/ai/defaultai.cc 2018-02-02 22:36:27 +0000
@@ -3280,7 +3280,7 @@
// Various tests to invoke building of a shortcut (new road)
if (flag.nr_of_roads() == 0 || needs_warehouse) {
- create_shortcut_road(flag, 17, 22, gametime);
+ create_shortcut_road(flag, 22, 22, gametime);
inhibit_road_building_ = gametime + 800;
} else if (!has_building && flag.nr_of_roads() == 1) {
// This is end of road without any building, we do not initiate interconnection thus
@@ -3288,7 +3288,7 @@
} else if (flag.nr_of_roads() == 1 || std::rand() % 10 == 0) {
if (spots_ > kSpotsEnough) {
// This is the normal situation
- create_shortcut_road(flag, 15, 22, gametime);
+ create_shortcut_road(flag, 18, 22, gametime);
inhibit_road_building_ = gametime + 800;
} else if (spots_ > kSpotsTooLittle) {
// We are short of spots so shortening must be significant
@@ -3301,11 +3301,11 @@
}
// a warehouse with 3 or less roads
} else if (is_warehouse && flag.nr_of_roads() <= 3) {
- create_shortcut_road(flag, 9, -10, gametime);
+ create_shortcut_road(flag, 15, -10, gametime);
inhibit_road_building_ = gametime + 400;
// and when a flag is full with wares
} else if (spots_ > kSpotsEnough && flag.current_wares() > 5) {
- create_shortcut_road(flag, 9, -5, gametime);
+ create_shortcut_road(flag, 15, -5, gametime);
inhibit_road_building_ = gametime + 400;
} else {
return false;
@@ -3335,13 +3335,13 @@
std::priority_queue<NearFlag> queue;
// only used to collect flags reachable walking over roads
std::vector<NearFlag> reachableflags;
- queue.push(NearFlag(roadstartflag, 0, 0));
+ queue.push(NearFlag(roadstartflag, 0));
uint8_t pathcounts = 0;
- uint8_t checkradius = 0;
+ uint8_t checkradius = 15;
if (spots_ > kSpotsEnough) {
- checkradius = 7;
+ checkradius = 10;
} else if (spots_ > kSpotsTooLittle) {
- checkradius = 11;
+ checkradius = 12;
} else {
checkradius = 15;
}
@@ -3395,7 +3395,7 @@
continue;
}
- queue.push(NearFlag(*endflag, 0, dist));
+ queue.push(NearFlag(*endflag, 0));
}
}
return false;
@@ -3403,6 +3403,17 @@
// trying to connect the flag to another one, be it from own economy
// or other economy
+// The procedure is:
+// - Collect all flags within checkradius into RoadCandidates, but first we dont even know if a road
+// can be built to them
+// - Walking over road network to collect info on flags that are accessible over road network
+// - Than merge info from NearFlags to RoadCandidates and consider roads to few best candidates from
+// RoadCandidates We use score named "reduction" that is basically diff between connection over
+// existing roads minus possible road from starting flag to candidate flag Of course there are two
+// special cases:
+// - the candidate flag does not belong to the same economy, so no road connection exists
+// - they are from same economy, but are connected beyond range of checkradius, so actual length of
+// connection is not known
bool DefaultAI::create_shortcut_road(const Flag& flag,
uint16_t checkradius,
int16_t min_reduction,
@@ -3490,9 +3501,11 @@
checkradius += 2;
}
+ // Now own roadfinding stuff
const Map& map = game().map();
// initializing new object of FlagsForRoads, we will push there all candidate flags
+ // First we dont even know if a road can be built there (from current flag)
Widelands::FlagsForRoads RoadCandidates(min_reduction);
FindNodeWithFlagOrRoad functor;
@@ -3532,32 +3545,41 @@
// This is a candidate, sending all necessary info to RoadCandidates
const bool different_economy = (player_immovable->get_economy() != flag.get_economy());
const int32_t air_distance = map.calc_distance(flag.get_position(), reachable_coords);
- RoadCandidates.add_flag(reachable_coords, air_distance, different_economy);
+ if (!RoadCandidates.has_candidate(reachable_coords.hash())) {
+ RoadCandidates.add_flag(reachable_coords, air_distance, different_economy);
+ }
}
}
// now we walk over roads and if field is reachable by roads, we change the distance assigned
// above
- std::priority_queue<NearFlag> queue;
- std::vector<NearFlag> nearflags; // only used to collect flags reachable walk over roads
- queue.push(NearFlag(flag, 0, 0));
+ std::map<uint32_t, NearFlag> nearflags; // only used to collect flags reachable walk over roads
+ nearflags[flag.get_position().hash()] = NearFlag(flag, 0);
// algorithm to walk on roads
- while (!queue.empty()) {
- std::vector<NearFlag>::iterator f =
- find(nearflags.begin(), nearflags.end(), queue.top().flag);
-
- if (f != nearflags.end()) {
- queue.pop();
- continue;
- }
-
- nearflags.push_back(queue.top());
- queue.pop();
- NearFlag& nf = nearflags.back();
-
+ // All nodes are marked as to_be_checked and under some conditions, the same node can be checked
+ // twice
+ while (true) {
+ // looking for a node with shortest existing road distance from starting flag and one that has
+ // to be checked
+ uint32_t start_field = std::numeric_limits<uint32_t>::max();
+ uint32_t nearest_distance = 10000;
+ for (auto item : nearflags) {
+ if (item.second.current_road_distance < nearest_distance && item.second.to_be_checked) {
+ nearest_distance = item.second.current_road_distance;
+ start_field = item.first;
+ }
+ }
+ // OK, so no node to be checked - quitting now
+ if (start_field == std::numeric_limits<uint32_t>::max()) {
+ break;
+ }
+
+ nearflags[start_field].to_be_checked = false;
+
+ // Now going over roads leading from this flag
for (uint8_t i = 1; i <= 6; ++i) {
- Road* const road = nf.flag->get_road(i);
+ Road* const road = nearflags[start_field].flag->get_road(i);
if (!road) {
continue;
@@ -3565,68 +3587,111 @@
Flag* endflag = &road->get_flag(Road::FlagStart);
- if (endflag == nf.flag) {
+ if (endflag == nearflags[start_field].flag) {
endflag = &road->get_flag(Road::FlagEnd);
}
- int32_t dist = map.calc_distance(flag.get_position(), endflag->get_position());
-
- if (dist > checkradius + 5) { // Testing bigger vicinity then checkradius....
+ uint32_t endflag_hash = endflag->get_position().hash();
+
+ int32_t dist =
+ map.calc_distance(nearflags[start_field].flag->get_position(), endflag->get_position());
+
+ if (dist > checkradius + 2) { // Testing bigger vicinity then checkradius....
continue;
}
- queue.push(NearFlag(*endflag, nf.cost + road->get_path().get_nsteps(), dist));
+ // There is few scenarios for this neighbour flag
+ if (nearflags.count(endflag_hash) == 0) {
+ // This is brand new flag
+ nearflags[endflag_hash] =
+ NearFlag(*endflag, nearflags[start_field].current_road_distance +
+ road->get_path().get_nsteps());
+ } else {
+ // Were here
+ if (nearflags[endflag_hash].current_road_distance >
+ nearflags[start_field].current_road_distance + road->get_path().get_nsteps()) {
+ // ..but this current connection is shorter than one found before
+ nearflags[endflag_hash].current_road_distance =
+ nearflags[start_field].current_road_distance + road->get_path().get_nsteps();
+ // So let re-check neighbours once more
+ nearflags[endflag_hash].to_be_checked = true;
+ }
+ }
}
}
// Sending calculated walking costs from nearflags to RoadCandidates to update info on
// Candidate flags/roads
for (auto& nf_walk : nearflags) {
- if (map.calc_distance(flag.get_position(), nf_walk.flag->get_position()) <= checkradius) {
- // nearflags contains also flags beyond the radius, so we skip these
- RoadCandidates.set_road_distance(
- nf_walk.flag->get_position(), static_cast<int32_t>(nf_walk.cost));
+ // NearFlag contains also flags beyond check radius, these are not relevent for us
+ if (RoadCandidates.has_candidate(nf_walk.second.flag->get_position().hash())) {
+ RoadCandidates.set_cur_road_distance(
+ nf_walk.second.flag->get_position(), nf_walk.second.current_road_distance);
}
}
- // We do not calculate roads to all nearby flags, ideally we investigate 4 roads, but the number
- // can be higher if a road cannot be built to considered flag. The logic is: 2 points for
- // possible
- // road, 1 for impossible, and count < 10 so in worst scenario we will calculate 10 impossible
- // roads without finding any possible
- uint32_t count = 0;
+ // Here we must consider how much are buildable fields lacking
+ // the number will be transformed to a weight passed to findpath function
+ int32_t fields_necessity = 5;
+ if (spots_ < kSpotsTooLittle) {
+ fields_necessity += 10;
+ }
+ if (map_allows_seafaring_ && num_ports == 0) {
+ fields_necessity += 10;
+ }
+ if (num_ports < 4) {
+ fields_necessity += 10;
+ }
+ if (spots_ < kSpotsEnough) {
+ fields_necessity += 5;
+ }
+ fields_necessity *= std::abs(management_data.get_military_number_at(64)) * 5;
+
+ // We need to sort these flags somehow, because we are not going to investigate all of them
+ // so sorting by air_distance (nearer flags first)
+ std::sort(std::begin(RoadCandidates.flags_queue), std::end(RoadCandidates.flags_queue),
+ [](const FlagsForRoads::Candidate& a, const FlagsForRoads::Candidate& b) {
+ // Here we are doing a kind of bucketing
+ const int32_t a_length = a.current_road_length/50;
+ const int32_t b_length = b.current_road_length/50;
+ return std::tie(b_length, a.air_distance) < std::tie(a_length, b.air_distance);
+ });
+
+ // Now we calculate roads from here to few best looking RoadCandidates....
+ uint32_t possible_roads_count = 0;
uint32_t current = 0; // hash of flag that we are going to calculate in the iteration
- while (count < 10 && RoadCandidates.get_best_uncalculated(¤t)) {
+ while (possible_roads_count < 5 && RoadCandidates.get_best_uncalculated(¤t)) {
const Widelands::Coords coords = Coords::unhash(current);
-
Path path;
// value of pathcost is not important, it just indicates, that the path can be built
- const int32_t pathcost = map.findpath(flag.get_position(), coords, 0, path, check);
+ // We send this information to RoadCandidates, with length of possible road if applicable
+ const int32_t pathcost =
+ map.findpath(flag.get_position(), coords, 0, path, check, 0, fields_necessity);
if (pathcost >= 0) {
RoadCandidates.road_possible(coords, path.get_nsteps());
- count += 2;
- } else {
- RoadCandidates.road_impossible(coords);
- count += 1;
+ possible_roads_count += 1;
}
}
- // Well and finally building the winning road
+ // re-sorting again, now by reduction score
+ std::sort(std::begin(RoadCandidates.flags_queue), std::end(RoadCandidates.flags_queue));
+
+ // Well and finally building the winning road (if any)
uint32_t winner_hash = 0;
if (RoadCandidates.get_winner(&winner_hash)) {
const Widelands::Coords target_coords = Coords::unhash(winner_hash);
Path& path = *new Path();
#ifndef NDEBUG
- const int32_t pathcost = map.findpath(flag.get_position(), target_coords, 0, path, check);
+ const int32_t pathcost =
+ map.findpath(flag.get_position(), target_coords, 0, path, check, 0, fields_necessity);
assert(pathcost >= 0);
#else
- map.findpath(flag.get_position(), target_coords, 0, path, check);
+ map.findpath(flag.get_position(), target_coords, 0, path, check, 0, fields_necessity);
#endif
game().send_player_build_road(player_number(), path);
return true;
}
-
// if all possible roads skipped
if (last_attempt_) {
Building* bld = flag.get_building();
@@ -3640,7 +3705,6 @@
game().send_player_bulldoze(*const_cast<Flag*>(&flag));
return true;
}
-
return false;
}
=== modified file 'src/logic/map.cc'
--- src/logic/map.cc 2017-12-31 18:46:49 +0000
+++ src/logic/map.cc 2018-02-02 22:36:27 +0000
@@ -1612,7 +1612,8 @@
int32_t const persist,
Path& path,
const CheckStep& checkstep,
- uint32_t const flags) const {
+ uint32_t const flags,
+ uint32_t const caps_sensitivity) const {
FCoords start;
FCoords end;
int32_t upper_cost_limit;
@@ -1695,6 +1696,15 @@
cost = curpf->real_cost + ((flags & fpBidiCost) ? calc_bidi_cost(cur, *direction) :
calc_cost(cur, *direction));
+ // If required (indicated by caps_sensitivity) we increase the path costs
+ // if the path is just crossing a field with building capabilities
+ if (caps_sensitivity > 0) {
+ int32_t buildcaps_score = neighb.field->get_caps() & BUILDCAPS_SIZEMASK;
+ buildcaps_score += (neighb.field->get_caps() & BUILDCAPS_MINE) ? 1 : 0;
+ buildcaps_score += (neighb.field->get_caps() & BUILDCAPS_PORT) ? 9 : 0;
+ cost += buildcaps_score * caps_sensitivity;
+ }
+
if (neighbpf.cycle != pathfields->cycle) {
// add to open list
neighbpf.cycle = pathfields->cycle;
=== modified file 'src/logic/map.h'
--- src/logic/map.h 2017-12-18 10:42:40 +0000
+++ src/logic/map.h 2018-02-02 22:36:27 +0000
@@ -354,7 +354,8 @@
const int32_t persist,
Path&,
const CheckStep&,
- const uint32_t flags = 0) const;
+ const uint32_t flags = 0,
+ const uint32_t caps_sensitivity = 0) const;
/**
* We can reach a field by water either if it has MOVECAPS_SWIM or if it has
Follow ups
-
[Merge] lp:~widelands-dev/widelands/findpath_modification into lp:widelands
From: noreply, 2018-02-16
-
Re: [Merge] lp:~widelands-dev/widelands/findpath_modification into lp:widelands
From: GunChleoc, 2018-02-15
-
Re: [Merge] lp:~widelands-dev/widelands/findpath_modification into lp:widelands
From: TiborB, 2018-02-15
-
Re: [Merge] lp:~widelands-dev/widelands/findpath_modification into lp:widelands
From: GunChleoc, 2018-02-15
-
Re: [Merge] lp:~widelands-dev/widelands/findpath_modification into lp:widelands
From: TiborB, 2018-02-14
-
[Merge] lp:~widelands-dev/widelands/findpath_modification into lp:widelands
From: bunnybot, 2018-02-14
-
Re: [Merge] lp:~widelands-dev/widelands/findpath_modification into lp:widelands
From: GunChleoc, 2018-02-14
-
Re: [Merge] lp:~widelands-dev/widelands/findpath_modification into lp:widelands
From: Tino, 2018-02-14
-
Re: [Merge] lp:~widelands-dev/widelands/findpath_modification into lp:widelands
From: TiborB, 2018-02-14
-
[Merge] lp:~widelands-dev/widelands/findpath_modification into lp:widelands
From: bunnybot, 2018-02-13
-
Re: [Merge] lp:~widelands-dev/widelands/findpath_modification into lp:widelands
From: TiborB, 2018-02-13
-
Re: [Merge] lp:~widelands-dev/widelands/findpath_modification into lp:widelands
From: GunChleoc, 2018-02-13
-
Re: [Merge] lp:~widelands-dev/widelands/findpath_modification into lp:widelands
From: TiborB, 2018-02-12
-
Re: [Merge] lp:~widelands-dev/widelands/findpath_modification into lp:widelands
From: GunChleoc, 2018-02-12
-
Re: [Merge] lp:~widelands-dev/widelands/findpath_modification into lp:widelands
From: TiborB, 2018-02-10
-
[Merge] lp:~widelands-dev/widelands/findpath_modification into lp:widelands
From: bunnybot, 2018-02-10
-
[Merge] lp:~widelands-dev/widelands/findpath_modification into lp:widelands
From: bunnybot, 2018-02-06
-
[Merge] lp:~widelands-dev/widelands/findpath_modification into lp:widelands
From: bunnybot, 2018-02-05
-
Re: [Merge] lp:~widelands-dev/widelands/findpath_modification into lp:widelands
From: TiborB, 2018-02-04
-
[Merge] lp:~widelands-dev/widelands/findpath_modification into lp:widelands
From: bunnybot, 2018-02-04
-
[Merge] lp:~widelands-dev/widelands/findpath_modification into lp:widelands
From: bunnybot, 2018-02-03
-
[Merge] lp:~widelands-dev/widelands/findpath_modification into lp:widelands
From: bunnybot, 2018-02-03