I have done a preliminary code review - everything just small nits. Can you 
clean up the NOCOMs too and set a commit message?

Diff comments:

> 
> === modified file 'src/ai/ai_help_structs.cc'
> --- src/ai/ai_help_structs.cc 2019-04-09 16:43:49 +0000
> +++ src/ai/ai_help_structs.cc 2019-06-14 18:11:44 +0000
> @@ -1417,4 +1303,190 @@
>       return update_time;
>  }
>  
> +FlagWarehouseDistances::FlagInfo::FlagInfo(const uint32_t gametime,
> +                                           const uint16_t dist,
> +                                           const uint32_t wh) {
> +     expiry_time = gametime + kFlagDistanceExpirationPeriod;
> +     soft_expiry_time = gametime + kFlagDistanceExpirationPeriod / 2;
> +     distance = dist;
> +     nearest_warehouse = wh;
> +     new_road_prohibited_till = 0;
> +}
> +FlagWarehouseDistances::FlagInfo::FlagInfo() {
> +     expiry_time = 0;
> +     distance = 1000;

1000 appears multiple times - please make it a constexpr

> +     new_road_prohibited_till = 0;
> +}
> +
> +// We are updating the distance info, but not all the time.
> +// Always if after soft expiration period, but
> +// if below expiration period only when the new value is lower than current 
> on
> +// In both cases new expiration times are calculated
> +bool FlagWarehouseDistances::FlagInfo::update(const uint32_t gametime,
> +                                              const uint16_t new_distance,
> +                                              const uint32_t nearest_wh) {
> +     const uint32_t new_expiry_time = gametime + 
> kFlagDistanceExpirationPeriod;
> +
> +     if (gametime > soft_expiry_time) {
> +             distance = new_distance;
> +             expiry_time = new_expiry_time;
> +             soft_expiry_time = gametime + kFlagDistanceExpirationPeriod / 2;
> +             nearest_warehouse = nearest_wh;
> +             return true;
> +     } else if (new_distance < distance || (new_distance == distance &&
> +                                            expiry_time < gametime + 
> kFlagDistanceExpirationPeriod)) {
> +             distance = new_distance;
> +             expiry_time = gametime + kFlagDistanceExpirationPeriod;
> +             nearest_warehouse = nearest_wh;
> +             return true;
> +     }
> +     return false;
> +}
> +
> +uint16_t FlagWarehouseDistances::FlagInfo::get(const uint32_t gametime, 
> uint32_t* nw) const {
> +     *nw = nearest_warehouse;
> +     if (gametime <= expiry_time) {
> +             return distance;
> +     }
> +     return 1000;
> +}
> +
> +void FlagWarehouseDistances::FlagInfo::road_built(const uint32_t gametime) {
> +     new_road_prohibited_till = gametime + 60 * 1000;
> +}
> +
> +bool FlagWarehouseDistances::FlagInfo::road_prohibited(const uint32_t 
> gametime) const {
> +     return new_road_prohibited_till > gametime;
> +}
> +
> +bool FlagWarehouseDistances::set_distance(const uint32_t flag_coords,
> +                                          const uint16_t distance,
> +                                          uint32_t const gametime,
> +                                          uint32_t const nearest_warehouse) {
> +     if (flags_map.count(flag_coords) == 0) {
> +             flags_map[flag_coords] =
> +                FlagWarehouseDistances::FlagInfo(gametime, distance, 
> nearest_warehouse);
> +             return true;
> +     }
> +     return flags_map[flag_coords].update(gametime, distance, 
> nearest_warehouse);
> +}
> +
> +uint16_t FlagWarehouseDistances::count() const {
> +     return flags_map.size();
> +}
> +
> +int16_t
> +FlagWarehouseDistances::get_distance(const uint32_t flag_coords, uint32_t 
> gametime, uint32_t* nw) {
> +     if (flags_map.count(flag_coords) == 0) {
> +             *nw = 0;
> +             return 1000;  // this is to discourage to build second road 
> from brand new flag...
> +     } else {
> +             return flags_map[flag_coords].get(gametime, nw);
> +     }
> +}
> +
> +void FlagWarehouseDistances::set_road_built(const uint32_t coords_hash, 
> const uint32_t gametime) {
> +     if (flags_map.count(coords_hash) == 1) {
> +             flags_map[coords_hash].road_built(gametime);
> +     }
> +}
> +
> +bool FlagWarehouseDistances::get_road_prohibited(const uint32_t coords_hash,
> +                                                 const uint32_t gametime) {
> +     if (flags_map.count(coords_hash) == 1) {
> +             return flags_map[coords_hash].road_prohibited(gametime);
> +     }
> +     return false;
> +}
> +
> +bool FlagWarehouseDistances::remove_old_flag(uint32_t gametime) {
> +     for (std::map<uint32_t, FlagWarehouseDistances::FlagInfo>::iterator it 
> = flags_map.begin();
> +          it != flags_map.end(); it++) {
> +             if (it->second.expiry_time + kOldFlagRemoveTime < gametime) {
> +                     it = flags_map.erase(it);
> +                     return true;
> +             }
> +     }
> +     return false;
> +}
> +
> +// Returns pointer to winning road, providing the treshold is exceeded

providing > provided that

> +FlagCandidates::Candidate* FlagCandidates::get_winner(const int16_t 
> treshold) {
> +     if (flags_.empty()) {
> +             return nullptr;
> +     }
> +     sort();
> +     if (flags_[0].score() < treshold) {
> +             return nullptr;
> +     }
> +     if (!flags_[0].is_buildable()) {
> +             return nullptr;
> +     }
> +     return &flags_[0];
> +}
> +
> +FlagCandidates::Candidate::Candidate(
> +   const uint32_t ch, bool de, uint16_t start_f_dist, uint16_t 
> act_dist_to_wh, uint16_t air_dst) {
> +     coords_hash = ch;
> +     different_economy = de;
> +     start_flag_dist_to_wh = start_f_dist;
> +     flag_to_flag_road_distance = 0;
> +     possible_road_distance = 1000;
> +     cand_flag_distance_to_wh = act_dist_to_wh;
> +     air_distance = air_dst;
> +}
> +
> +int16_t FlagCandidates::Candidate::score() const {  // NOCOM
> +     return different_economy * 2000 + (start_flag_dist_to_wh - 
> cand_flag_distance_to_wh) +
> +            (flag_to_flag_road_distance - 2 * possible_road_distance);
> +}
> +
> +bool FlagCandidates::set_road_possible(const uint32_t coords_hash, const 
> uint16_t steps) {
> +     for (auto& item : flags_) {
> +             if (item.coords_hash == coords_hash) {
> +                     item.possible_road_distance = steps;
> +                     return true;
> +             }
> +     }
> +     printf("ERROR [set_road_possible] - no such flag\n");  // NOCOM
> +     return false;
> +}
> +
> +bool FlagCandidates::set_cur_road_distance(const uint32_t coords, uint16_t 
> dist) {
> +     for (auto& item : flags_) {
> +             if (item.coords_hash == coords) {
> +                     item.flag_to_flag_road_distance = dist;
> +                     return true;
> +             }
> +     }
> +     return false;
> +}
> +void FlagCandidates::sort() {
> +     std::sort(flags_.begin(), flags_.end());
> +}
> +
> +void FlagCandidates::sort_by_air_distance() {
> +     std::sort(flags_.begin(), flags_.end(),
> +               [](const FlagCandidates::Candidate& lf, const 
> FlagCandidates::Candidate& rf) {
> +                       return lf.air_distance < rf.air_distance;
> +               });
> +}
> +
> +void FlagCandidates::add_flag(const uint32_t coords,
> +                              const bool different_economy,
> +                              const uint16_t act_dist_to_wh,
> +                              const uint16_t air_distance) {
> +     flags_.push_back(
> +        Candidate(coords, different_economy, start_flag_dist_to_wh, 
> act_dist_to_wh, air_distance));
> +}
> +
> +bool FlagCandidates::has_candidate(const uint32_t coords_hash) {
> +     for (auto& item : flags_) {
> +             if (item.coords_hash == coords_hash) {
> +                     return true;
> +             }
> +     }
> +     return false;
> +}
> +
>  }  // namespace Widelands
> 
> === modified file 'src/ai/ai_help_structs.h'
> --- src/ai/ai_help_structs.h  2019-05-25 08:20:22 +0000
> +++ src/ai/ai_help_structs.h  2019-06-14 18:11:44 +0000
> @@ -122,6 +123,11 @@
>  // TODO(tiborb): this should be replaced by command line switch
>  constexpr int kFNeuronBitSize = 32;
>  constexpr int kMutationRatePosition = 42;
> +// This is expiration time for distance from a flag to neares warehouse

neares -> nearest

> +constexpr int kFlagDistanceExpirationPeriod = 120 * 1000;
> +// If the distance of flag-warehouse was not updated for this time, we 
> presume that the flag
> +// does not exist anymore and remove it
> +constexpr int kOldFlagRemoveTime = 5 * 60 * 1000;
>  
>  constexpr uint32_t kNever = std::numeric_limits<uint32_t>::max();
>  
> 
> === modified file 'src/ai/defaultai.cc'
> --- src/ai/defaultai.cc       2019-05-26 11:39:41 +0000
> +++ src/ai/defaultai.cc       2019-06-14 18:11:44 +0000
> @@ -3422,6 +3429,76 @@
>       return true;
>  }
>  
> +
> +// Re-calculating warehouse to flag distances
> +void DefaultAI::check_flag_distances(const uint32_t gametime) {
> +     for (WarehouseSiteObserver& wh_obs : warehousesites) {
> +             // wh_obs.flag_distances_last_update = gametime; NOCOM
> +             uint16_t checked_flags = 0;
> +             const uint32_t this_wh_hash = 
> wh_obs.site->get_position().hash();
> +             uint32_t highest_distance_set = 0;
> +
> +             std::queue<Widelands::Flag*>
> +                remaining_flags;  // only used to collect flags reachable 
> walk over roads
> +             remaining_flags.push(&wh_obs.site->base_flag());
> +             // const bool distance_set =

Dead comment

> +             flag_warehouse_distance.set_distance(
> +                wh_obs.site->base_flag().get_position().hash(), 0, gametime, 
> this_wh_hash);
> +             uint32_t tmp_wh;
> +             assert(flag_warehouse_distance.get_distance(
> +                       wh_obs.site->base_flag().get_position().hash(), 
> gametime, &tmp_wh) == 0);
> +
> +             // Algorithm to walk on roads
> +             // All nodes are marked as to_be_checked == true first and once 
> the node is checked it is
> +             // changed to false. Under some conditions, the same node can 
> be checked twice, the
> +             // to_be_checked can be set back to true. Because less hoops 
> (fewer flag-to-flag roads) does
> +             // not always mean shortest road.
> +             while (!remaining_flags.empty()) {
> +                     checked_flags += 1;

++checked_flags;

> +                     // looking for a node with shortest existing road 
> distance from starting flag and one that
> +                     // has to be checked Now going over roads leading from 
> this flag
> +                     const uint16_t current_flag_distance = 
> flag_warehouse_distance.get_distance(
> +                        remaining_flags.front()->get_position().hash(), 
> gametime, &tmp_wh);
> +                     for (uint8_t i = 1; i <= 6; ++i) {
> +                             Road* const road = 
> remaining_flags.front()->get_road(i);
> +
> +                             if (!road) {
> +                                     continue;
> +                             }
> +
> +                             Flag* endflag = 
> &road->get_flag(Road::FlagStart);
> +
> +                             if (endflag == remaining_flags.front()) {
> +                                     endflag = 
> &road->get_flag(Road::FlagEnd);
> +                             }
> +                             const uint16_t steps_count = 
> road->get_path().get_nsteps();
> +
> +                             // Calculated distance can be used or ignored 
> if f.e. longer than via other route
> +                             bool const updated = 
> flag_warehouse_distance.set_distance(
> +                                endflag->get_position().hash(), 
> current_flag_distance + steps_count, gametime,
> +                                this_wh_hash);
> +
> +                             if (highest_distance_set < 
> current_flag_distance + steps_count) {
> +                                     highest_distance_set = 
> current_flag_distance + steps_count;
> +                             }
> +
> +                             if (updated) {
> +                                     remaining_flags.push(endflag);
> +                             }
> +                     }
> +                     remaining_flags.pop();
> +             }
> +
> +             printf(
> +                "%d: Checked flags: %3d, highest distance: %5d, warehouses: 
> %lu, time: %d s\n",  // NOCOM
> +                player_number(), checked_flags, highest_distance_set, 
> warehousesites.size(),
> +                gametime / 1000);
> +     }
> +
> +     // Now let do some lazy prunning - remove the flags that were not 
> updated for long

prunning -> pruning

> +     flag_warehouse_distance.remove_old_flag(gametime);
> +}
> +
>  // Here we pick about 25 roads and investigate them. If it is a dead end we 
> dismantle it
>  bool DefaultAI::dismantle_dead_ends() {
>       bool road_dismantled = false;
> @@ -3538,50 +3615,36 @@
>       }
>  
>       bool is_warehouse = false;
> -     bool has_building = false;
>       if (Building* b = flag.get_building()) {
> -             has_building = true;
>               BuildingObserver& bo = 
> get_building_observer(b->descr().name().c_str());
>               if (bo.type == BuildingObserver::Type::kWarehouse) {
>                       is_warehouse = true;
>               }
>       }
> +     const uint32_t flag_coords_hash = flag.get_position().hash();
>  
> -     // is connected to a warehouse?
> +     if (flag_warehouse_distance.get_road_prohibited(flag_coords_hash, 
> gametime)) {return false;}
>       const bool needs_warehouse = flag.get_economy()->warehouses().empty();
>  
> -     if (!has_building && flag.nr_of_roads() == 1) {
> -             return false;
> -     } else if (is_warehouse && flag.nr_of_roads() <= 3) {
> -             // Do nothing
> -     } else if (needs_warehouse) {
> -             // Do nothing
> -     } else if (flag.current_wares() > 5) {
> -             // Do nothing
> -     } else if (has_building && std::rand() % 3 == 0) {
> -             // Do nothing
> -     } else if (std::rand() % 10 == 0) {
> -             // Do nothing
> -     } else {
> -             return false;
> -     }
> -
> -     int16_t expected_shortcut = 27;
> -     if (has_building) {
> -             expected_shortcut -= 3;
> -     }
> -     expected_shortcut -= flag.current_wares() * 3;
> -     if (is_warehouse) {
> -             expected_shortcut -= 10;
> -     }
> -     if (std::rand() % 5 == 0) {
> -             expected_shortcut -= 10;
> -     }
> -     expected_shortcut -= 2 * flag.nr_of_roads();
> -
> -     create_shortcut_road(flag, 14, expected_shortcut, gametime);
> -
> -     return true;
> +     uint32_t tmp_wh; // NOCOM
> +
> +     // when deciding if we attempt to build a road from here we use 
> probability NOCOM
> +     uint16_t probability_score = 0;
> +     if (flag.nr_of_roads() == 1) {probability_score += 20;}
> +     if (is_warehouse && flag.nr_of_roads() <= 3) {probability_score += 20;}
> +     probability_score += flag.current_wares() * 5;
> +     if (needs_warehouse) {probability_score += 500;}
> +     if (std::rand() % 10 == 0)

Add {}

> +     probability_score += 
> flag_warehouse_distance.get_distance(flag_coords_hash, gametime, &tmp_wh);
> +
> +     if (std::rand() % 200 < probability_score) {
> +             const bool action_taken = create_shortcut_road(flag, 14, 
> gametime);
> +             if (!action_taken) {printf ("failed to build a road\n");}

printf -> log

> +             return true;
> +     }
> +     printf ("not trying to build a road\n");

printf -> log

> +     return false;
> +
>  }
>  
>  // This function takes a road (road is smallest section of roads with two 
> flags on the ends)
> @@ -3756,318 +3819,343 @@
>  // connection is not known
>  bool DefaultAI::create_shortcut_road(const Flag& flag,
>                                       uint16_t checkradius,
> -                                     int16_t min_reduction,
>                                       uint32_t gametime) {
>  
> -     // Increasing the failed_connection_tries counter
> -     // At the same time it indicates a time an economy is without a 
> warehouse
> -     EconomyObserver* eco = get_economy_observer(flag.economy());
> -     // if we passed grace time this will be last attempt and if it fails
> -     // building is destroyes
> -     bool last_attempt_ = false;
> -
> -     // this should not happen, but if the economy has a warehouse and a 
> dismantle
> -     // grace time set, we must 'zero' the dismantle grace time
> -     if (!flag.get_economy()->warehouses().empty() &&
> -         eco->dismantle_grace_time != std::numeric_limits<uint32_t>::max()) {
> -             eco->dismantle_grace_time = 
> std::numeric_limits<uint32_t>::max();
> -     }
> -
> -     // first we deal with situations when this is economy with no warehouses
> -     // and this is a flag belonging to a building/constructionsite
> -     // such economy must get dismantle grace time (if not set yet)
> -     // end sometimes extended checkradius
> -     if (flag.get_economy()->warehouses().empty() && flag.get_building()) {
> -
> -             // occupied military buildings get special treatment
> -             // (extended grace time + longer radius)
> -             bool occupied_military_ = false;
> -             Building* b = flag.get_building();
> -             if (upcast(MilitarySite, militb, b)) {
> -                     if 
> (militb->soldier_control()->stationed_soldiers().size() > 0) {
> -                             occupied_military_ = true;
> -                     }
> -             }
> -
> -             // check if we are within grace time, if not or gracetime unset 
> we need to do something
> -             // if we are within gracetime we do nothing (this loop is 
> skipped)
> -
> -             // if grace time is not set, this is probably first time 
> without a warehouse and we must set
> -             // it
> -             if (eco->dismantle_grace_time == 
> std::numeric_limits<uint32_t>::max()) {
> -
> -                     // constructionsites
> -                     if (upcast(ConstructionSite const, constructionsite, 
> flag.get_building())) {
> -                             BuildingObserver& bo =
> -                                
> get_building_observer(constructionsite->building().name().c_str());
> -                             // first very special case - a port (in the 
> phase of constructionsite)
> -                             // this might be a new colonization port
> -                             if (bo.is(BuildingAttribute::kPort)) {
> -                                     eco->dismantle_grace_time = gametime + 
> 60 * 60 * 1000;  // one hour should be enough
> -                             } else {  // other constructionsites, usually 
> new (standalone) constructionsites
> -                                     eco->dismantle_grace_time =
> -                                        gametime + 30 * 1000 +            // 
> very shot time is enough
> -                                        (eco->flags.size() * 30 * 1000);  // 
> + 30 seconds for every flag in economy
> -                             }
> -
> -                             // buildings
> -                     } else {
> -
> -                             if (occupied_military_) {
> -                                     eco->dismantle_grace_time =
> -                                        (gametime + 90 * 60 * 1000) + 
> (eco->flags.size() * 20 * 1000);
> -
> -                             } else {  // for other normal buildings
> -                                     eco->dismantle_grace_time =
> -                                        gametime + (45 * 60 * 1000) + 
> (eco->flags.size() * 20 * 1000);
> -                             }
> -                     }
> -
> -                     // we have passed grace_time - it is time to dismantle
> -             } else if (eco->dismantle_grace_time <= gametime) {
> -                     last_attempt_ = true;
> -                     // we increase a check radius in last attempt
> -                     checkradius += 2;
> -             }
> -
> -             // and bonus for occupied military buildings:
> -             if (occupied_military_) {
> -                     checkradius += 4;
> -             }
> -
> -             // and generally increase radius for unconnected buildings
> -             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;
> -     CheckStepRoadAI check(player_, MOVECAPS_WALK, true);
> -
> -     // get all flags within radius
> -     std::vector<Coords> reachable;
> -     map.find_reachable_fields(
> -        Area<FCoords>(map.get_fcoords(flag.get_position()), checkradius), 
> &reachable, check, functor);
> -
> -     for (const Coords& reachable_coords : reachable) {
> -
> -             // ignore starting flag, of course
> -             if (reachable_coords == flag.get_position()) {
> -                     continue;
> -             }
> -
> -             // first make sure there is an immovable (should be, but still)
> -             if (upcast(PlayerImmovable const, player_immovable, 
> map[reachable_coords].get_immovable())) {
> -
> -                     // if it is the road, make a flag there
> -                     if (dynamic_cast<const 
> Road*>(map[reachable_coords].get_immovable())) {
> -                             game().send_player_build_flag(player_number(), 
> reachable_coords);
> -                     }
> -
> -                     // do not go on if it is not a flag
> -                     if (!dynamic_cast<const 
> Flag*>(map[reachable_coords].get_immovable())) {
> -                             continue;
> -                     }
> -
> -                     // testing if a flag/road's economy has a warehouse, if 
> not we are not
> -                     // interested to connect to it
> -                     if (player_immovable->economy().warehouses().size() == 
> 0) {
> -                             continue;
> -                     }
> -
> -                     // 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);
> -                     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::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
> -     // All nodes are marked as to_be_checked == true first and once the 
> node is checked it is changed
> -     // to false. Under some conditions, the same node can be checked twice, 
> the to_be_checked can
> -     // be set back to true. Because less hoops (fewer flag-to-flag roads) 
> does not always mean
> -     // shortest
> -     // road.
> -     for (;;) {
> -             // 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, we failed to find a NearFlag where to_be_checked == 
> true, so quitting the loop 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 = 
> nearflags[start_field].flag->get_road(i);
> -
> -                     if (!road) {
> -                             continue;
> -                     }
> -
> -                     Flag* endflag = &road->get_flag(Road::FlagStart);
> -
> -                     if (endflag == nearflags[start_field].flag) {
> -                             endflag = &road->get_flag(Road::FlagEnd);
> -                     }
> -
> -                     const uint32_t endflag_hash = 
> endflag->get_position().hash();
> -
> -                     const int32_t dist = 
> map.calc_distance(flag.get_position(), endflag->get_position());
> -
> -                     if (dist > checkradius + 2) {  //  Testing bigger 
> vicinity then checkradius....
> -                             continue;
> -                     }
> -
> -                     // 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 {
> -                             // We know about this flag already
> -                             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) {
> -             // 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);
> -             }
> -     }
> -
> -     // 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 = 0;
> -     if (spots_ < kSpotsTooLittle) {
> -             fields_necessity += 10;
> -     }
> -     if (map_allows_seafaring_ && num_ports == 0) {
> -             fields_necessity += 10;
> -     }
> -     if (num_ports < 4) {
> -             fields_necessity += 5;
> -     }
> -     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 first by current road length (that might contain fake 
> values for flags that were
> -     // not reached over roads) and secondary 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 (possible_roads_count < 5 && 
> RoadCandidates.get_best_uncalculated(&current)) {
> -             const Widelands::Coords coords = Coords::unhash(current);
> -             Path path;
> -
> -             // value of pathcost is not important, it just indicates, that 
> the path can be built
> -             // 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());
> -                     possible_roads_count += 1;
> -             }
> -     }
> -
> -     // re-sorting again, now by reduction score (custom operator specified 
> in .h file)
> -     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();
> +    // Increasing the failed_connection_tries counter
> +    // At the same time it indicates a time an economy is without a warehouse
> +    EconomyObserver* eco = get_economy_observer(flag.economy());
> +    // if we passed grace time this will be last attempt and if it fails
> +    // building is destroyes
> +    bool last_attempt_ = false;
> +
> +    // this should not happen, but if the economy has a warehouse and a 
> dismantle
> +    // grace time set, we must 'zero' the dismantle grace time
> +    if (!flag.get_economy()->warehouses().empty() &&
> +        eco->dismantle_grace_time != std::numeric_limits<uint32_t>::max()) {
> +        eco->dismantle_grace_time = std::numeric_limits<uint32_t>::max();
> +    }
> +
> +    // first we deal with situations when this is economy with no warehouses
> +    // and this is a flag belonging to a building/constructionsite
> +    // such economy must get dismantle grace time (if not set yet)
> +    // end sometimes extended checkradius
> +    if (flag.get_economy()->warehouses().empty() && flag.get_building()) {
> +
> +        // occupied military buildings get special treatment
> +        // (extended grace time + longer radius)
> +        bool occupied_military_ = false;
> +        Building* b = flag.get_building();
> +        if (upcast(MilitarySite, militb, b)) {
> +            if (militb->soldier_control()->stationed_soldiers().size() > 0) {
> +                occupied_military_ = true;
> +            }
> +        }
> +
> +        // check if we are within grace time, if not or gracetime unset we 
> need to do something
> +        // if we are within gracetime we do nothing (this loop is skipped)
> +
> +        // if grace time is not set, this is probably first time without a 
> warehouse and we must set
> +        // it
> +        if (eco->dismantle_grace_time == 
> std::numeric_limits<uint32_t>::max()) {

We have std::numeric_limits<uint32_t>::max() 3 times, use a constexpr?

> +
> +            // constructionsites
> +            if (upcast(ConstructionSite const, constructionsite, 
> flag.get_building())) {
> +                BuildingObserver& bo =
> +                   
> get_building_observer(constructionsite->building().name().c_str());
> +                // first very special case - a port (in the phase of 
> constructionsite)
> +                // this might be a new colonization port
> +                if (bo.is(BuildingAttribute::kPort)) {
> +                    eco->dismantle_grace_time = gametime + 60 * 60 * 1000;  
> // one hour should be enough
> +                } else {  // other constructionsites, usually new 
> (standalone) constructionsites
> +                    eco->dismantle_grace_time =
> +                       gametime + 30 * 1000 +            // very shot time 
> is enough
> +                       (eco->flags.size() * 30 * 1000);  // + 30 seconds for 
> every flag in economy
> +                }
> +
> +                // buildings
> +            } else {
> +
> +                if (occupied_military_) {
> +                    eco->dismantle_grace_time =
> +                       (gametime + 90 * 60 * 1000) + (eco->flags.size() * 20 
> * 1000);
> +
> +                } else {  // for other normal buildings
> +                    eco->dismantle_grace_time =
> +                       gametime + (45 * 60 * 1000) + (eco->flags.size() * 20 
> * 1000);
> +                }
> +            }
> +
> +            // we have passed grace_time - it is time to dismantle
> +        } else if (eco->dismantle_grace_time <= gametime) {
> +            last_attempt_ = true;
> +            // we increase a check radius in last attempt
> +            checkradius += 2;
> +        }
> +
> +        // and bonus for occupied military buildings:
> +        if (occupied_military_) {
> +            checkradius += 4;
> +        }
> +
> +        // and generally increase radius for unconnected buildings
> +        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)
> +    // Adding also distance of this flag to nearest wh
> +    uint32_t tmp_wh; // This information is not used, but we need it
> +    const uint32_t current_flag_dist_to_wh = flag_warehouse_distance.
> +            get_distance(flag.get_position().hash(), gametime, &tmp_wh);
> +
> +    FlagCandidates flag_candidates(current_flag_dist_to_wh);
> +
> +    FindNodeWithFlagOrRoad functor;
> +    CheckStepRoadAI check(player_, MOVECAPS_WALK, true);
> +
> +    // get all flags within radius
> +    std::vector<Coords> reachable;
> +    map.find_reachable_fields(
> +       Area<FCoords>(map.get_fcoords(flag.get_position()), checkradius), 
> &reachable, check, functor);
> +
> +    for (const Coords& reachable_coords : reachable) {
> +
> +        // ignore starting flag, of course
> +        if (reachable_coords == flag.get_position()) {
> +            continue;
> +        }
> +
> +        const uint32_t reachable_coords_hash = reachable_coords.hash();
> +
> +        // first make sure there is an immovable (should be, but still)
> +        if (upcast(PlayerImmovable const, player_immovable, 
> map[reachable_coords].get_immovable())) {
> +
> +            // if it is the road, make a flag there
> +            if (dynamic_cast<const 
> Road*>(map[reachable_coords].get_immovable())) {
> +                game().send_player_build_flag(player_number(), 
> reachable_coords);
> +            }
> +
> +            // do not go on if it is not a flag
> +            if (!dynamic_cast<const 
> Flag*>(map[reachable_coords].get_immovable())) {
> +                continue;
> +            }
> +
> +            // testing if a flag/road's economy has a warehouse, if not we 
> are not
> +            // interested to connect to it
> +            if (player_immovable->economy().warehouses().size() == 0) {
> +                continue;
> +            }
> +
> +            // This is a candidate, sending all necessary info to 
> RoadCandidates
> +            const bool different_economy = (player_immovable->get_economy() 
> != flag.get_economy());
> +                     const uint16_t air_distance = 
> map.calc_distance(flag.get_position(), reachable_coords);
> +
> +            if (!flag_candidates.has_candidate(reachable_coords_hash) && 
> !flag_warehouse_distance.get_road_prohibited(reachable_coords_hash, 
> gametime)) {
> +                flag_candidates.add_flag(reachable_coords_hash, 
> different_economy,
> +                flag_warehouse_distance.get_distance(reachable_coords_hash, 
> gametime, &tmp_wh), air_distance);
> +            }
> +        }
> +    }
> +
> +    // now we walk over roads and if field is reachable by roads, we change 
> the distance assigned
> +    // above
> +    std::map<uint32_t, NearFlag> nearflags;  // only used to collect flags 
> reachable walk over roads
> +    nearflags[flag.get_position().hash()] = NearFlag(&flag, 0);
> +
> +    collect_nearflags(nearflags, flag, checkradius);
> +
> +
> +
> +    // Sending calculated walking costs from nearflags to RoadCandidates to 
> update info on
> +    // Candidate flags/roads
> +    for (auto& nf_walk : nearflags) {
> +             const uint32_t nf_hash = 
> nf_walk.second.flag->get_position().hash();
> +        // NearFlag contains also flags beyond check radius, these are not 
> relevent for us
> +        if (flag_candidates.has_candidate(nf_hash)) {
> +            flag_candidates.set_cur_road_distance(
> +               nf_hash, nf_walk.second.current_road_distance);
> +        }
> +    }
> +
> +    // 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 = 0;
> +    if (spots_ < kSpotsTooLittle) {
> +        fields_necessity += 10;
> +    }
> +    if (map_allows_seafaring_ && num_ports == 0) {
> +        fields_necessity += 10;
> +    }
> +    if (num_ports < 4) {
> +        fields_necessity += 5;
> +    }
> +    if (spots_ < kSpotsEnough) {
> +        fields_necessity += 5;
> +    }
> +
> +    fields_necessity *= std::abs(management_data.get_military_number_at(64)) 
> * 5;
> +
> +    // Now we calculate roads from here to few best looking 
> RoadCandidates....
> +    flag_candidates.sort_by_air_distance();
> +    uint32_t possible_roads_count = 0;
> +    for (const auto &flag_candidate : flag_candidates.flags()){
> +        if (possible_roads_count > 10) {break;}
> +        const Widelands::Coords coords = 
> Coords::unhash(flag_candidate.coords_hash);
> +        Path path;
> +
> +        // value of pathcost is not important, it just indicates, that the 
> path can be built
> +        // 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) {
> +            flag_candidates.set_road_possible(flag_candidate.coords_hash, 
> path.get_nsteps());
> +            possible_roads_count += 1;
> +        }
> +    }
> +
> +    // re-sorting again now by default by a score
> +    flag_candidates.sort();
> +
> +
> +    // Well and finally building the winning road (if any)
> +    const int32_t winner_min_score = (spots_ < kSpotsTooLittle) ? 50 : 25;
> +
> +    FlagCandidates::Candidate* winner = 
> flag_candidates.get_winner(winner_min_score);
> +    if (winner) {
> +        const Widelands::Coords target_coords = 
> Coords::unhash(winner->coords_hash);
> +        printf("Winner to connect to %3dx%3d: ",flag.get_position(). 
> x,flag.get_position().y); //without new line
> +        winner->print();
> +
> +             // This is to prohibit the flag for some time but with 
> exemption of warehouse
> +             if (flag_warehouse_distance.get_distance(winner->coords_hash, 
> gametime, &tmp_wh) > 0) {
> +                     
> flag_warehouse_distance.set_road_built(winner->coords_hash, gametime);
> +             }
> +             // and we stright away set distance of future flag
> +             
> flag_warehouse_distance.set_distance(flag.get_position().hash(), 
> winner->start_flag_dist_to_wh + winner->possible_road_distance,
> +             gametime, 0); // faking the warehouse
> +
> +        Path& path = *new Path();
>  #ifndef NDEBUG
> -             const int32_t pathcost =
> -                map.findpath(flag.get_position(), target_coords, 0, path, 
> check, 0, fields_necessity);
> -             assert(pathcost >= 0);
> +        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, 0, fields_necessity);
> +        map.findpath(flag.get_position(), target_coords, 0, path, check, 0, 
> fields_necessity);
>  #endif
> -             game().send_player_build_road(player_number(), path);
> -             return true;
> -     }
> -     // We can't build a road so let's block the vicinity as an indication 
> this area is not
> -     // connectible
> -     // Usually we block for 2 minutes, but if it is a last attempt we block 
> for 10 minutes
> -     // Note: we block the vicinity only if this economy (usually a sole 
> flag with a building) is not
> -     // connected to a warehouse
> -     if (flag.get_economy()->warehouses().empty()) {
> -
> -             // blocking only if latest block was less then 60 seconds ago 
> or it is last attempt
> -             if (eco->fields_block_last_time + 60000 < gametime || 
> last_attempt_) {
> -                     eco->fields_block_last_time = gametime;
> -
> -                     const uint32_t block_time = last_attempt_ ? 10 * 60 * 
> 1000 : 2 * 60 * 1000;
> -
> -                     FindNodeAcceptAll buildable_functor;
> -                     CheckStepOwnTerritory check_own(player_, MOVECAPS_WALK, 
> true);
> -
> -                     // get all flags within radius
> -                     std::vector<Coords> reachable_to_block;
> -                     
> map.find_reachable_fields(Area<FCoords>(map.get_fcoords(flag.get_position()), 
> checkradius),
> -                                               &reachable_to_block, 
> check_own, buildable_functor);
> -
> -                     for (auto coords : reachable_to_block) {
> -                             blocked_fields.add(coords, 
> game().get_gametime() + block_time);
> -                     }
> -             }
> -
> -             // If it last attempt we also destroy the flag (with a building 
> if any attached)
> -             if (last_attempt_) {
> -                     remove_from_dqueue<Widelands::Flag>(eco->flags, &flag);
> -                     game().send_player_bulldoze(*const_cast<Flag*>(&flag));
> -                     dead_ends_check_ = true;
> -                     return true;
> -             }
> -     }
> -     return false;
> +        game().send_player_build_road(player_number(), path);
> +        return true;
> +    }
> +    // We can't build a road so let's block the vicinity as an indication 
> this area is not
> +    // connectible
> +    // Usually we block for 2 minutes, but if it is a last attempt we block 
> for 10 minutes
> +    // Note: we block the vicinity only if this economy (usually a sole flag 
> with a building) is not
> +    // connected to a warehouse
> +    if (flag.get_economy()->warehouses().empty()) {
> +
> +        // blocking only if latest block was less then 60 seconds ago or it 
> is last attempt
> +        if (eco->fields_block_last_time + 60000 < gametime || last_attempt_) 
> {

We have 60 * 1000 a lot - put it in a constexpr?

> +            eco->fields_block_last_time = gametime;
> +
> +            const uint32_t block_time = last_attempt_ ? 10 * 60 * 1000 : 2 * 
> 60 * 1000;
> +
> +            FindNodeAcceptAll buildable_functor;
> +            CheckStepOwnTerritory check_own(player_, MOVECAPS_WALK, true);
> +
> +            // get all flags within radius
> +            std::vector<Coords> reachable_to_block;
> +            
> map.find_reachable_fields(Area<FCoords>(map.get_fcoords(flag.get_position()), 
> checkradius),
> +                                      &reachable_to_block, check_own, 
> buildable_functor);
> +
> +            for (auto coords : reachable_to_block) {
> +                blocked_fields.add(coords, game().get_gametime() + 
> block_time);
> +            }
> +        }
> +
> +        // If it last attempt we also destroy the flag (with a building if 
> any attached)
> +        if (last_attempt_) {
> +            remove_from_dqueue<Widelands::Flag>(eco->flags, &flag);
> +            game().send_player_bulldoze(*const_cast<Flag*>(&flag));
> +            dead_ends_check_ = true;
> +            return true;
> +        }
> +    }
> +    return false;
> +}
> +
> +void DefaultAI::collect_nearflags(std::map<uint32_t, NearFlag> &nearflags, 
> const Flag& flag, const uint16_t checkradius) {
> +    // Algorithm to walk on roads
> +    // All nodes are marked as to_be_checked == true first and once the node 
> is checked it is changed
> +    // to false. Under some conditions, the same node can be checked twice, 
> the to_be_checked can
> +    // be set back to true. Because less hoops (fewer flag-to-flag roads) 
> does not always mean
> +    // shortest
> +    // road.
> +
> +     const Map& map = game().map();
> +
> +    for (;;) {
> +        // 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, we failed to find a NearFlag where to_be_checked == true, so 
> quitting the loop 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 = nearflags[start_field].flag->get_road(i);
> +
> +            if (!road) {
> +                continue;
> +            }
> +
> +            Flag* endflag = &road->get_flag(Road::FlagStart);
> +
> +            if (endflag == nearflags[start_field].flag) {
> +                endflag = &road->get_flag(Road::FlagEnd);
> +            }
> +
> +            const uint32_t endflag_hash = endflag->get_position().hash();
> +
> +            const int32_t dist = map.calc_distance(flag.get_position(), 
> endflag->get_position());
> +
> +            if (dist > checkradius + 2) {  //  Testing bigger vicinity then 
> checkradius....
> +                continue;
> +            }
> +
> +            // There is few scenarios for this neighbour flag
> +            if (nearflags.count(endflag_hash) == 0) {
> +                // This is brand new flag
> +                // calculating diff how much closer we will get to the flag
> +                nearflags[endflag_hash] =
> +                   NearFlag(endflag, 
> nearflags[start_field].current_road_distance +
> +                                        road->get_path().get_nsteps());
> +            } else {
> +                // We know about this flag already
> +                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;
> +                }
> +            }
> +        }
> +    }
> +
>  }
>  
>  /**
> 
> === added file 'src/ai/test/test_ai.cc'
> --- src/ai/test/test_ai.cc    1970-01-01 00:00:00 +0000
> +++ src/ai/test/test_ai.cc    2019-06-14 18:11:44 +0000
> @@ -0,0 +1,240 @@
> +/*
> + * Copyright (C) 2007-2019 by the Widelands Development Team
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  
> 02110-1301, USA.
> + *
> + */
> +
> +#include <exception>
> +
> +#include <boost/test/unit_test.hpp>
> +
> +#ifdef _WIN32
> +#include "base/log.h"
> +#endif
> +#include "ai/ai_help_structs.h"
> +
> +// Triggered by BOOST_AUTO_TEST_CASE
> +CLANG_DIAG_OFF("-Wdisabled-macro-expansion")
> +
> +namespace Widelands {  // Needed?
> +class World;
> +}  // namespace Widelands
> +
> +using namespace Widelands;
> +
> +BOOST_AUTO_TEST_SUITE(ai)
> +
> +BOOST_AUTO_TEST_CASE(flag_distance_soft_expiry) {
> +     FlagWarehouseDistances fw;
> +     uint32_t tmp_wh;
> +     BOOST_CHECK_EQUAL(fw.get_distance(0, 0, &tmp_wh), 1000);
> +     // set_distance(const uint32_t flag_coords, const uint16_t distance,

Clean up dead comments?

> +     //      uint32_t const gametime, uint32_t const nearest_warehouse)
> +     BOOST_CHECK_EQUAL(fw.set_distance(1, 2, 0, 3), true);
> +     // get_distance(const uint32_t flag_coords, uint32_t gametime, 
> uint32_t* nw)
> +     BOOST_CHECK_EQUAL(fw.get_distance(1, 2, &tmp_wh), 2);  // distance now 2
> +     BOOST_CHECK_EQUAL(tmp_wh, 3);
> +
> +     // setting longer distance below soft_expiry time
> +     BOOST_CHECK_EQUAL(fw.set_distance(1, 3, kFlagDistanceExpirationPeriod / 
> 3, 4), false);
> +     // distance to 3 not updated
> +     BOOST_CHECK_EQUAL(fw.get_distance(1, kFlagDistanceExpirationPeriod / 3, 
> &tmp_wh), 2);
> +     BOOST_CHECK_EQUAL(tmp_wh, 3);
> +
> +     // now setting after soft expiry
> +     BOOST_CHECK_EQUAL(
> +        fw.set_distance(1, 1, kFlagDistanceExpirationPeriod / 3, 6), true);  
> // distance set to 1
> +     BOOST_CHECK_EQUAL(fw.get_distance(1, kFlagDistanceExpirationPeriod / 3, 
> &tmp_wh), 1);
> +     BOOST_CHECK_EQUAL(tmp_wh, 6);
> +}
> +BOOST_AUTO_TEST_CASE(flag_distance_below_expiry)
> +/* Compare with void free_test_function() */
> +{
> +     FlagWarehouseDistances fw;
> +     uint32_t tmp_wh;
> +     // set_distance(const uint32_t flag_coords, const uint16_t distance,
> +     //      uint32_t const gametime, uint32_t const nearest_warehouse)
> +     BOOST_CHECK_EQUAL(fw.set_distance(1, 2, 0, 3), true);
> +     // get_distance(const uint32_t flag_coords, uint32_t gametime, 
> uint32_t* nw)
> +
> +     // setting longer distance after soft but below expiry time
> +     BOOST_CHECK_EQUAL(fw.set_distance(1, 3, kFlagDistanceExpirationPeriod * 
> 2 / 3, 5), true);
> +     BOOST_CHECK_EQUAL(fw.get_distance(1, kFlagDistanceExpirationPeriod * 2 
> / 3, &tmp_wh), 3);
> +     BOOST_CHECK_EQUAL(tmp_wh, 5);
> +}
> +
> +BOOST_AUTO_TEST_CASE(flag_distance_after_expiry)
> +/* Compare with void free_test_function() */
> +{
> +     FlagWarehouseDistances fw;
> +     uint32_t tmp_wh;
> +     // set_distance(const uint32_t flag_coords, const uint16_t distance,
> +     //      uint32_t const gametime, uint32_t const nearest_warehouse)
> +     BOOST_CHECK_EQUAL(fw.set_distance(1, 2, 0, 3), true);
> +     // get_distance(const uint32_t flag_coords, uint32_t gametime, 
> uint32_t* nw)
> +
> +     // setting longer distance below expiry time
> +     BOOST_CHECK_EQUAL(fw.set_distance(1, 3, 2 * 
> kFlagDistanceExpirationPeriod, 5), true);
> +     BOOST_CHECK_EQUAL(fw.get_distance(1, 3, &tmp_wh), 3);
> +     BOOST_CHECK_EQUAL(tmp_wh, 5);
> +}
> +
> +BOOST_AUTO_TEST_CASE(flag_distance_expiration_extension)
> +/* setting the same distance restart the expiry_period */
> +{
> +     FlagWarehouseDistances fw;
> +     uint32_t tmp_wh;
> +     BOOST_CHECK_EQUAL(fw.set_distance(1, 2, 0, 3), true);
> +     BOOST_CHECK_EQUAL(
> +        fw.set_distance(1, 2, 0, 3), false);  // cannot reset the same 
> distance in the same time
> +     // get_distance(const uint32_t flag_coords, uint32_t gametime, 
> uint32_t* nw)
> +
> +     // Now we are after expiration time
> +     BOOST_CHECK_EQUAL(fw.get_distance(1, kFlagDistanceExpirationPeriod + 3, 
> &tmp_wh), 1000);
> +
> +     // setting distance 2 time shortly one after another
> +     // set_distance(const uint32_t flag_coords, const uint16_t distance,
> +     //      uint32_t const gametime, uint32_t const nearest_warehouse)
> +     BOOST_CHECK_EQUAL(fw.set_distance(1, 2, kFlagDistanceExpirationPeriod + 
> 3, 5), true);
> +     BOOST_CHECK_EQUAL(fw.set_distance(1, 2, kFlagDistanceExpirationPeriod + 
> 10, 5), true);
> +     // current expiry_time should be 2*kFlagDistanceExpirationPeriod + 10
> +     BOOST_CHECK_EQUAL(fw.get_distance(1, 2 * kFlagDistanceExpirationPeriod, 
> &tmp_wh), 2);
> +     BOOST_CHECK_EQUAL(tmp_wh, 5);
> +     BOOST_CHECK_EQUAL(fw.get_distance(1, 2 * kFlagDistanceExpirationPeriod 
> + 15, &tmp_wh), 1000);
> +}
> +
> +BOOST_AUTO_TEST_CASE(flag_distance_road_builtexpiration_extension)
> +/* setting the same distance restart the expiry_period */
> +{
> +     FlagWarehouseDistances fw;
> +     // uint32_t tmp_wh;
> +     // No road built on fresh flag
> +     BOOST_CHECK_EQUAL(fw.get_road_prohibited(1, 1), false);
> +     // get_distance(const uint32_t flag_coords, uint32_t gametime, 
> uint32_t* nw)
> +
> +     // setting road we dont know about
> +     fw.set_road_built(1, 0);
> +     BOOST_CHECK_EQUAL(fw.get_road_prohibited(1, 1), false);
> +
> +     // let fw knows about it
> +     fw.set_distance(1, 2, 0, 3);
> +     fw.set_road_built(1, 0);
> +     BOOST_CHECK_EQUAL(fw.get_road_prohibited(1, 1), true);
> +     BOOST_CHECK_EQUAL(fw.get_road_prohibited(1, 59999), true);
> +     BOOST_CHECK_EQUAL(fw.get_road_prohibited(1, 60001), false);
> +
> +     BOOST_CHECK_EQUAL(fw.get_road_prohibited(2, 60001), false);
> +}
> +
> +BOOST_AUTO_TEST_CASE(flag_distance_old_removal)
> +/* setting the same distance restart the expiry_period */
> +{
> +     FlagWarehouseDistances fw;
> +     fw.set_distance(1, 2, 0, 3);
> +     BOOST_CHECK_EQUAL(fw.count(), 1);
> +     BOOST_CHECK_EQUAL(fw.remove_old_flag(kOldFlagRemoveTime + 
> kFlagDistanceExpirationPeriod), false);
> +     BOOST_CHECK_EQUAL(fw.count(), 1);
> +     BOOST_CHECK_EQUAL(
> +        fw.remove_old_flag(kOldFlagRemoveTime + 
> kFlagDistanceExpirationPeriod + 2), true);
> +     BOOST_CHECK_EQUAL(fw.count(), 0);
> +}
> +
> +BOOST_AUTO_TEST_CASE(new_flag_road_not_prohibited)
> +/* setting the same distance restart the expiry_period */
> +{
> +     FlagWarehouseDistances fw;
> +     // let fw knows about it
> +     BOOST_CHECK_EQUAL(fw.count(), 0);
> +     fw.set_distance(1, 2, 0, 3);
> +     BOOST_CHECK_EQUAL(fw.count(), 1);
> +     BOOST_CHECK_EQUAL(fw.get_road_prohibited(1, 1), false);
> +}
> +
> +BOOST_AUTO_TEST_CASE(flag_candidate_init)
> +/* setting the same distance restart the expiry_period */
> +{
> +     FlagCandidates fc = FlagCandidates(10);
> +     BOOST_CHECK_EQUAL(fc.count(), 0);
> +}
> +
> +BOOST_AUTO_TEST_CASE(flag_candidate_winner_score) {
> +     const uint16_t kCurFlDistToWh = 3;
> +     const uint16_t kStartFlagToWh = 10;
> +
> +     const uint16_t kPosRoadDist = 5;
> +     const uint16_t kCurRoadDistFlToFl = 17;
> +
> +     const uint32_t kTestedCoords = 11;
> +
> +     FlagCandidates fc = FlagCandidates(kStartFlagToWh);
> +
> +     // coord, different economy, distance to wh
> +     fc.add_flag(kTestedCoords, false, kCurFlDistToWh, 1);
> +     // setting coords, dist
> +     BOOST_CHECK_EQUAL(fc.set_cur_road_distance(kTestedCoords, 
> kCurRoadDistFlToFl), true);
> +     BOOST_CHECK_EQUAL(
> +        fc.set_cur_road_distance(1, 5), false);    // we cannot set distance 
> to unknown flag
> +     BOOST_CHECK_EQUAL(fc.get_winner(), nullptr);  // road not possible
> +     // set length of possible road
> +     BOOST_CHECK_EQUAL(fc.set_road_possible(kTestedCoords, kPosRoadDist), 
> true);
> +     BOOST_VERIFY(fc.get_winner());
> +     BOOST_CHECK_EQUAL(fc.get_winner()->start_flag_dist_to_wh, 
> kStartFlagToWh);
> +     BOOST_CHECK_EQUAL(fc.get_winner()->cand_flag_distance_to_wh, 
> kCurFlDistToWh);
> +     BOOST_CHECK_EQUAL(fc.get_winner()->flag_to_flag_road_distance, 
> kCurRoadDistFlToFl);
> +     BOOST_CHECK_EQUAL(fc.get_winner()->possible_road_distance, 
> kPosRoadDist);
> +     BOOST_CHECK_EQUAL(fc.get_winner()->coords_hash, kTestedCoords);
> +     BOOST_CHECK_EQUAL(fc.get_winner()->different_economy, false);
> +
> +     BOOST_CHECK_EQUAL(fc.get_winner()->score(),
> +                       +(kStartFlagToWh - kCurFlDistToWh) + 
> (kCurRoadDistFlToFl - 2 * kPosRoadDist));
> +}
> +BOOST_AUTO_TEST_CASE(flag_candidates_sorting) {
> +     FlagCandidates fc = FlagCandidates(10);
> +
> +     fc.add_flag(0, false, 10, 1);
> +     fc.add_flag(1, false, 10, 1);
> +     fc.add_flag(2, false, 10, 1);
> +     BOOST_CHECK_EQUAL(fc.set_cur_road_distance(0, 5), true);
> +     BOOST_CHECK_EQUAL(fc.set_cur_road_distance(1, 5), true);
> +     BOOST_CHECK_EQUAL(fc.set_cur_road_distance(2, 5), true);
> +     BOOST_CHECK_EQUAL(fc.set_road_possible(0, 4), true);
> +     BOOST_CHECK_EQUAL(fc.set_road_possible(1, 2), true);
> +     BOOST_CHECK_EQUAL(fc.set_road_possible(2, 3), true);
> +     BOOST_CHECK_EQUAL(fc.get_winner()->coords_hash, 1);  // sorted done 
> automatically
> +     BOOST_CHECK_EQUAL(fc.count(), 3);
> +}
> +
> +BOOST_AUTO_TEST_CASE(flag_sort_by_air_distance) {
> +     FlagCandidates fc = FlagCandidates(10);
> +
> +     fc.add_flag(0, false, 10, 4);
> +     fc.add_flag(1, false, 10, 1);
> +     fc.add_flag(2, false, 10, 2);
> +     fc.sort_by_air_distance();
> +     BOOST_CHECK_EQUAL(fc.flags()[0].air_distance, 1);
> +}
> +
> +BOOST_AUTO_TEST_CASE(flag_has_candidate) {
> +     FlagCandidates fc = FlagCandidates(10);
> +
> +     fc.add_flag(0, false, 10, 4);
> +     fc.add_flag(1, false, 10, 1);
> +     fc.add_flag(2, false, 10, 2);
> +     BOOST_CHECK_EQUAL(fc.has_candidate(1), true);
> +     BOOST_CHECK_EQUAL(fc.has_candidate(3), false);
> +}
> +
> +BOOST_AUTO_TEST_SUITE_END()


-- 
https://code.launchpad.net/~widelands-dev/widelands/ai_flag_warehouse_distance/+merge/368544
Your team Widelands Developers is subscribed to branch 
lp:~widelands-dev/widelands/ai_flag_warehouse_distance.

_______________________________________________
Mailing list: https://launchpad.net/~widelands-dev
Post to     : widelands-dev@lists.launchpad.net
Unsubscribe : https://launchpad.net/~widelands-dev
More help   : https://help.launchpad.net/ListHelp

Reply via email to