Looks like a good solution to me :) I have added a bunch of small nits with the comments function.
Diff comments: > === modified file 'src/ai/defaultai.cc' > --- src/ai/defaultai.cc 2015-02-16 20:23:15 +0000 > +++ src/ai/defaultai.cc 2015-03-04 20:14:13 +0000 > @@ -50,12 +50,6 @@ > #include "logic/world/world.h" > #include "profile/profile.h" > > -// Building of new military buildings can be restricted > -constexpr int kPushExpansion = 1; > -constexpr int kResourcesOrDefense = 2; > -constexpr int kDefenseOnly = 3; > -constexpr int kNoNewMilitary = 4; > - > // following is in miliseconds (widelands counts time in ms) > constexpr int kFieldUpdateInterval = 2000; > constexpr int kIdleMineUpdateInterval = 22000; > @@ -65,7 +59,7 @@ > constexpr int kMinBFCheckInterval = 5 * 1000; > constexpr int kShipCheckInterval = 5 * 1000; > constexpr int kMarineDecisionInterval = 20 * 1000; > -constexpr int kTrainingSitesCheckInterval = 30 * 1000; > +constexpr int kTrainingSitesCheckInterval = 5 * 60 * 1000; > > // this is intended for map developers, by default should be off > constexpr bool kPrintStats = false; > @@ -85,28 +79,16 @@ > DefaultAI::DefaultAI(Game& ggame, PlayerNumber const pid, uint8_t const t) > : ComputerPlayer(ggame, pid), > type_(t), > - m_buildable_changed(true), > - m_mineable_changed(true), > + // m_buildable_changed(true), > + // m_mineable_changed(true), > player_(nullptr), Remove > tribe_(nullptr), > num_constructionsites_(0), > num_milit_constructionsites(0), > num_prod_constructionsites(0), > num_ports(0), > - next_road_due_(2000), > - next_stats_update_due_(30000), > - next_construction_due_(1000), > + next_ai_think_(0), > next_mine_construction_due_(0), > - next_productionsite_check_due_(0), > - next_mine_check_due_(0), > - next_militarysite_check_due_(0), > - next_ship_check_due(30 * 1000), > - next_marine_decisions_due(30 * 1000), > - next_attack_consideration_due_(300000), > - next_trainingsites_check_due_(15 * 60 * 1000), > - next_bf_check_due_(1000), > - next_wares_review_due_(15 * 60 * 1000), > - next_statistics_report_(30 * 60 * 1000), > inhibit_road_building_(0), > time_of_last_construction_(0), > enemy_last_seen_(-2 * 60 * 1000), > @@ -202,7 +184,7 @@ > } > } > break; > - default: > + default: > ; > } > }); > @@ -238,111 +220,79 @@ > > const int32_t gametime = game().get_gametime(); > > - if (m_buildable_changed || next_bf_check_due_ < gametime) { > - // update statistics about buildable fields > + if (next_ai_think_ > gametime) { > + return; > + } > + > + // AI now thinks twice in a seccond, if the game engine allows this > + // if too busy, the period can be many seconds. > + next_ai_think_ = gametime + 500; > + ScheduleTasks DueTask = ScheduleTasks::kIdle; > + DueTask = get_oldest_task(gametime); > + schedStat[static_cast<uint32_t>(DueTask)] += 1; > + > + // now AI runs a job selected above to be performed in this turn > + // (only one but some of them needs to run check_economies() to > + // guarantee consistency) > + // job names are selfexplanatory > + if (DueTask == ScheduleTasks::kBFCheck) { > update_all_buildable_fields(gametime); > - next_bf_check_due_ = gametime + kMinBFCheckInterval; > - } > - > - m_buildable_changed = false; > - > - // perpetually tries to improve roads > - if (next_road_due_ <= gametime) { > - next_road_due_ = gametime + 1000; > - > - if (improve_roads(gametime)) { > - m_buildable_changed = true; > + taskDue[ScheduleTasks::kBFCheck] = gametime + > kMinBFCheckInterval; > + } else if (DueTask == ScheduleTasks::kRoadCheck) { The code would be easier to read if you renamed BF to BuildableFields > + if (check_economies()) { // is a must > return; > - } > - } else { > - // only go on, after defaultAI tried to improve roads. > - return; > - } > - > - // NOTE Because of the check above, the following parts of think() are > used > - // NOTE only once every second at maximum. This increases performance > and as > - // NOTE human player_s can not even react that fast, it should not be a > - // NOTE disadvantage for the defaultAI. > - // This must be checked every time as changes of bobs in AI area aren't > - // handled by the AI itself. > - update_all_not_buildable_fields(); > - > - // considering attack > - if (next_attack_consideration_due_ <= gametime) { > + }; > + taskDue[ScheduleTasks::kRoadCheck] = gametime + 400; > + improve_roads(gametime); > + } else if (DueTask == ScheduleTasks::kUnbuildableFCheck) { > + taskDue[ScheduleTasks::kUnbuildableFCheck] = gametime + 4000; > + update_all_not_buildable_fields(); > + } else if (DueTask == ScheduleTasks::kConsiderAttack) { > consider_attack(gametime); > - } > - > - // check if anything in the economies changed. > - // This needs to be done before new buildings are placed, to ensure > that no > - // empty economy is left. > - if (check_economies()) { > - return; > - } > - > - // Before thinking about a new construction, update current stats, to > have > - // a better view on current economy. > - if (next_stats_update_due_ <= gametime) { > + } else if (DueTask == ScheduleTasks::kCheckEconomies) { > + check_economies(); > + taskDue[ScheduleTasks::kCheckEconomies] = gametime + 8000; > + } else if (DueTask == ScheduleTasks::kProductionsitesStats) { > update_productionsite_stats(gametime); > - } > - > - // Now try to build something if possible > - if (next_construction_due_ <= gametime) { > - next_construction_due_ = gametime + 2000; > - > + } else if (DueTask == ScheduleTasks::kConstructBuilding) { > + if (check_economies()) { // economies must be consistent > + return; > + } > + taskDue[ScheduleTasks::kConstructBuilding] = gametime + 6000; > if (construct_building(gametime)) { > time_of_last_construction_ = gametime; > - m_buildable_changed = true; > - return; > - } > - } > - > - // verify that our production sites are doing well > - if (check_productionsites(gametime)) { > - return; > - } > - > - if (check_ships(gametime)) { > - return; > - } > - > - if (marine_main_decisions(gametime)) { > - return; > - } > - > - // Check the mines and consider upgrading or destroying one > - if (check_mines_(gametime)) { > - return; > - } > - > - // consider whether a change of the soldier capacity of some > militarysites > - // would make sense. > - if (check_militarysites(gametime)) { > - return; > - } > - > - if (check_trainingsites(gametime)) { > - return; > - } > - > - // improve existing roads! > - // main part of this improvment is creation 'shortcut roads' > - // this includes also connection of new buildings > - if (improve_roads(gametime)) { > - m_buildable_changed = true; > - m_mineable_changed = true; > - return; > - } > - > - // once in 15 minutes we increase(or decrease) targets for wares > - if (next_wares_review_due_ <= gametime) { > - next_wares_review_due_ = gametime + 15 * 60 * 1000; > + } > + } else if (DueTask == ScheduleTasks::kCheckProductionsites) { > + if (check_economies()) { // economies must be consistent > + return; > + } > + check_productionsites(gametime); > + taskDue[ScheduleTasks::kCheckProductionsites] = gametime + 5000; > + } else if (DueTask == ScheduleTasks::kCheckShips) { > + check_ships(gametime); > + } else if (DueTask == ScheduleTasks::KMarineDecisions) { > + marine_main_decisions(gametime); > + } else if (DueTask == ScheduleTasks::kCheckMines) { > + if (check_economies()) { // economies must be consistent > + return; > + } > + taskDue[ScheduleTasks::kCheckMines] = gametime + 7000; // 7 > seconds is enough > + check_mines_(gametime); > + } else if (DueTask == ScheduleTasks::kCheckMilitarysites) { > + check_militarysites(gametime); > + } else if (DueTask == ScheduleTasks::kCheckTrainingsites) { > + check_trainingsites(gametime); > + } else if (DueTask == ScheduleTasks::kWareReview) { > + if (check_economies()) { // economies must be consistent > + return; > + } > + taskDue[ScheduleTasks::kWareReview] = gametime + 15 * 60 * 1000; > review_wares_targets(gametime); > - } > - > - // print statistics > - if (kPrintStats && next_statistics_report_ <= gametime) { > - print_stats(); > - next_statistics_report_ += 60 * 60 * 1000; > + } else if (DueTask == ScheduleTasks::kprintStats) { > + if (check_economies()) { // economies must be consistent > + return; > + } > + print_stats(gametime); > } > } > > @@ -500,13 +450,6 @@ > } > } > > - num_constructionsites_ = 0; > - num_milit_constructionsites = 0; > - num_prod_constructionsites = 0; > - next_construction_due_ = 0; > - next_road_due_ = 1000; > - next_productionsite_check_due_ = 0; > - inhibit_road_building_ = 0; > // atlanteans they consider water as a resource > // (together with mines, stones and wood) > if (tribe_->name() == "atlanteans") { > @@ -524,7 +467,7 @@ > port_reserved_coords.insert(hash); > } while (mr.advance(map)); > > - //the same for NW neighbour of a field > + // the same for NW neighbour of a field > Coords c_nw; > map.get_tln(c, &c_nw); > MapRegion<Area<FCoords>> mr_nw(map, > Area<FCoords>(map.get_fcoords(c_nw), 3)); > @@ -593,6 +536,22 @@ > } while (mr.advance(map)); > } > } > + > + taskDue[ScheduleTasks::kConstructBuilding] = 0; > + taskDue[ScheduleTasks::kRoadCheck] = 1000; > + taskDue[ScheduleTasks::kCheckProductionsites] = 15 * 1000; > + taskDue[ScheduleTasks::kProductionsitesStats] = 30000; > + taskDue[ScheduleTasks::kCheckMines] = 30 * 1000; > + taskDue[ScheduleTasks::kCheckMilitarysites] = 0; > + taskDue[ScheduleTasks::kCheckShips] = 30 * 1000; > + taskDue[ScheduleTasks::kCheckEconomies] = 1000; > + taskDue[ScheduleTasks::KMarineDecisions] = 30 * 1000; > + taskDue[ScheduleTasks::kConsiderAttack] = 300000; > + taskDue[ScheduleTasks::kCheckTrainingsites] = 15 * 60 * 1000; > + taskDue[ScheduleTasks::kBFCheck] = 1000; > + taskDue[ScheduleTasks::kUnbuildableFCheck] = 1000; > + taskDue[ScheduleTasks::kWareReview] = 15 * 60 * 1000; > + taskDue[ScheduleTasks::kprintStats] = 30 * 60 * 1000; > } kPrintStats - capital P > > /** > @@ -606,7 +565,7 @@ > uint16_t i = 0; > > while (!buildable_fields.empty() && > buildable_fields.front()->next_update_due_ <= gametime && > - i < 25) { > + i < 40) { > BuildableField& bf = *buildable_fields.front(); > > // check whether we lost ownership of the node > @@ -753,7 +712,7 @@ > } > } > > - //testing for near porspaces > + // testing for near porspaces > if (field.portspace_nearby_ == Widelands::ExtendedBool::kUnset) { > field.portspace_nearby_ = ExtendedBool::kFalse; > MapRegion<Area<FCoords>> mr(map, Area<FCoords>(field.coords, > 2)); > @@ -1012,7 +971,7 @@ > /// Updates the production and MINE sites statistics needed for construction > decision. > void DefaultAI::update_productionsite_stats(int32_t const gametime) { > // Updating the stats every 10 seconds should be enough > - next_stats_update_due_ = gametime + 10000; > + taskDue[ScheduleTasks::kProductionsitesStats] = gametime + 10000; > uint16_t fishers_count = 0; // used for atlanteans only > > // Reset statistics for all buildings > @@ -1115,7 +1074,7 @@ > > // here we possible stop building of new buildings > new_buildings_stop_ = false; > - uint8_t expansion_mode = kResourcesOrDefense; > + MilitaryStrategy expansion_mode = MilitaryStrategy::kResourcesOrDefense; > > // there are many reasons why to stop building production buildings > // (note there are numerous exceptions) > @@ -1146,13 +1105,15 @@ > const uint32_t treshold = militarysites.size() / 40 + 2; > > if (unstationed_milit_buildings_ + num_milit_constructionsites > 3 * > treshold) { > - expansion_mode = kNoNewMilitary; > + expansion_mode = MilitaryStrategy::kNoNewMilitary; > } else if (unstationed_milit_buildings_ + num_milit_constructionsites > > 2 * treshold) { > - expansion_mode = kDefenseOnly; > + expansion_mode = MilitaryStrategy::kDefenseOnly; > + } else if (unstationed_milit_buildings_ + num_milit_constructionsites > >= treshold - 1) { > + expansion_mode = MilitaryStrategy::kResourcesOrDefense; > } else if (unstationed_milit_buildings_ + num_milit_constructionsites > >= 1) { > - expansion_mode = kResourcesOrDefense; > + expansion_mode = MilitaryStrategy::kExpansion; > } else { > - expansion_mode = kPushExpansion; > + expansion_mode = MilitaryStrategy::kPushExpansion; > } > > // we must consider need for mines > @@ -1163,9 +1124,9 @@ > if (virtual_mines <= 7) { > resource_necessity_mines_ = std::numeric_limits<uint8_t>::max(); > } else if (virtual_mines > 19) { > - resource_necessity_mines_ = 0; > + resource_necessity_mines_ = 50; > } else { > - const uint32_t tmp = ((18 - virtual_mines) * 255) / 12; > + const uint32_t tmp = (24 - virtual_mines) * 10; > resource_necessity_mines_ = tmp; > } > > @@ -1246,7 +1207,7 @@ > ++i) { > BuildableField* const bf = *i; > > - if (bf->next_update_due_ < gametime - 8000) { > + if (bf->next_update_due_ < gametime - 10000) { > continue; > } > > @@ -1518,7 +1479,7 @@ > } > // we can go above target if > there is shortage of logs on stock > else if (bo.total_count() >= > bo.cnt_target_ && > - bo.stocklevel_ > 40 + > productionsites.size() * 5) { > + bo.stocklevel_ > 40 + > productionsites.size() * 2) { > continue; > } > > @@ -1679,11 +1640,18 @@ > continue; > } > > - if (expansion_mode == kNoNewMilitary) { > - continue; > - } > - > - if (expansion_mode == kDefenseOnly && > !bf->enemy_nearby_) { > + if (expansion_mode == > MilitaryStrategy::kNoNewMilitary) { > + continue; > + } > + > + if (expansion_mode == > MilitaryStrategy::kDefenseOnly && !bf->enemy_nearby_) { > + continue; > + } > + > + if (expansion_mode == > MilitaryStrategy::kResourcesOrDefense && > + !(bf->unowned_mines_pots_nearby_ || > bf->stones_nearby_ || bf->water_nearby_ || > + (bf->distant_water_ && > resource_necessity_water_needed_) || > + bf->enemy_nearby_)) { > continue; > } > > @@ -1694,19 +1662,25 @@ > (bo.mountain_conqueror_ || > bo.expansion_type_)) { > ; > } // it is ok, go on > - else if (bf->unowned_land_nearby_ && > bo.expansion_type_ && > - num_milit_constructionsites <= 1) { > - ; // we allow big buildings now > - } else if (bf->unowned_land_nearby_ && > - bo.expansion_type_) { // decreasing > probability for big buidlings > + else if (bo.expansion_type_) { > if (bo.desc->get_size() == 2 && > gametime % 2 >= 1) { > continue; > } > if (bo.desc->get_size() == 3 && > gametime % 3 >= 1) { > continue; > - } > + }; > } > - // it is ok, go on > + //; // we allow big buildings now > + //} else if (bf->unowned_land_nearby_ && > + // bo.expansion_type_) { // decreasing > probability for big buidlings > + // if (bo.desc->get_size() == 2 && gametime % 2 > >= 1) { > + // continue; > + //} > + // if (bo.desc->get_size() == 3 && gametime % 3 > >= 1) { > + // continue; > + //} > + //} > + //// it is ok, go on > else { Remove > continue; > } // the building is not suitable for situation > @@ -1719,22 +1693,22 @@ > > // a boost to prevent an expansion halt > int32_t local_boost = 0; > - if (expansion_mode == kPushExpansion) { > + if (expansion_mode == > MilitaryStrategy::kPushExpansion) { > local_boost = 200; > } > > - prio = (bf->unowned_land_nearby_ * 2 * > resource_necessity_territory_ / 255 + > - bf->unowned_mines_pots_nearby_ * > resource_necessity_mines_ / 255 + > + prio = ((bf->unowned_land_nearby_ * 2 * > resource_necessity_territory_) / 255 + > + (bf->unowned_mines_pots_nearby_ * > resource_necessity_mines_) / 255 + > bf->stones_nearby_ / 2 + > bf->military_loneliness_ / 10 - 60 + local_boost + > - bf->water_nearby_ * > resource_necessity_water_ / 255); > + (bf->water_nearby_ * > resource_necessity_water_) / 255); > > // special bonus due to remote water for > atlanteans > if (resource_necessity_water_needed_) > - prio += bf->distant_water_ * > resource_necessity_water_ / 255; > + prio += (bf->distant_water_ * > resource_necessity_water_) / 255; > > - //special bonus if a portspace is close > + // special bonus if a portspace is close > if (bf->portspace_nearby_ == > ExtendedBool::kTrue) { > - if (num_ports == 0){ > + if (num_ports == 0) { > prio += 25; > } else { > prio += 5; > @@ -2044,9 +2018,6 @@ > // set the type of update that is needed > if (mine) { > next_mine_construction_due_ = gametime + > kBusyMineUpdateInterval; > - > - } else { > - m_buildable_changed = true; > } > > return true; > @@ -2093,7 +2064,7 @@ > roads.pop_front(); > > // occasionaly we test if the road can be dismounted > - if (gametime % 25 == 0) { > + if (gametime % 5 == 0) { > const Road& road = *roads.front(); > if (dispensable_road_test(*const_cast<Road*>(&road))) { > > game().send_player_bulldoze(*const_cast<Road*>(&road)); > @@ -2134,14 +2105,25 @@ > return true; > } > > + bool is_warehouse = false; > + if (Building* b = flag.get_building()) { > + BuildingObserver& bo = > get_building_observer(b->descr().name().c_str()); > + if (bo.type == BuildingObserver::WAREHOUSE) { > + is_warehouse = true; > + } > + } > + > // if this is end flag (or sole building) or just randomly > - if (flag.nr_of_roads() <= 1 || gametime % 200 == 0) { > - create_shortcut_road(flag, 13, 20, gametime); > + if (flag.nr_of_roads() <= 1 || gametime % 10 == 0) { > + create_shortcut_road(flag, 11, 20, gametime); > inhibit_road_building_ = gametime + 800; > - } > - // this is when a flag is full > - else if (flag.current_wares() > 6 && gametime % 10 == 0) { > - create_shortcut_road(flag, 9, 0, gametime); > + // a warehouse with 3 or less roads > + } else if (is_warehouse && flag.nr_of_roads() <= 3) { > + create_shortcut_road(flag, 9, -1, gametime); > + inhibit_road_building_ = gametime + 400; > + // and when a flag is full with wares > + } else if (flag.current_wares() > 5) { > + create_shortcut_road(flag, 9, -2, gametime); > inhibit_road_building_ = gametime + 400; > } > > @@ -2227,7 +2209,7 @@ > // or other economy > bool DefaultAI::create_shortcut_road(const Flag& flag, > uint16_t checkradius, > - uint16_t minred, > + int16_t minred, > int32_t gametime) { What does "minred" mean? I don't think you mean the color red? > > // Increasing the failed_connection_tries counter > @@ -2246,15 +2228,27 @@ > > // 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->stationed_soldiers().size() > 0) { > + occupied_military_ = true; > + } > + } > + > // if we are within grace time, it is OK, just go on > if (eco->dismantle_grace_time_ > gametime && > eco->dismantle_grace_time_ != > std::numeric_limits<int32_t>::max()) { > ; > > - // if grace time is not set, this is probably first time > without a warehouse and we must > - // set it > + // if grace time is not set, this is probably first > time without a warehouse and we must > + // set it > } else if (eco->dismantle_grace_time_ == > std::numeric_limits<int32_t>::max()) { > > // constructionsites > @@ -2267,27 +2261,16 @@ > 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 > + gametime + 30 * 1000 + // > very shot time is enough > (eco->flags.size() * 30 * 1000); // > + 30 seconds for every flag in economy > } > > - // buildings > + // buildings > } else { > > - //occupied military buildings get special > treatment > - //(extended grace time) > - bool occupied_military_ = false; > - Building* b = flag.get_building(); > - if (upcast(MilitarySite, militb, b)) { > - if (militb->stationed_soldiers().size() > > 0) { > - occupied_military_ = true; > - } > - } > - > if (occupied_military_) { > eco->dismantle_grace_time_ = > (gametime + 20 * 60 * 1000) + > (eco->flags.size() * 20 * 1000); > - checkradius += 3; > > } else { // for other normal buildings > eco->dismantle_grace_time_ = > @@ -2298,9 +2281,17 @@ > // we have passed grace_time - it is time to dismantle > } else { > last_attempt_ = true; > - //we increase a check radius in last attempt > + // we increase a check radius in last attempt > checkradius += 2; > } > + > + // and bon us for occupied military buildings: > + if (occupied_military_) { bon us -> bonus > + checkradius += 4; > + } > + > + // and generally increase radius for unconnected buildings > + checkradius += 2; > } > > Map& map = game().map(); > @@ -2552,12 +2543,10 @@ > * \returns true, if something was changed. > */ > bool DefaultAI::check_productionsites(int32_t gametime) { > - if ((next_productionsite_check_due_ > gametime) || > productionsites.empty()) { > + if (productionsites.empty()) { > return false; > } > > - next_productionsite_check_due_ = gametime + 4000; > - > bool changed = false; > // Reorder and set new values; - better now because there are multiple > returns in the function > productionsites.push_back(productionsites.front()); > @@ -2831,7 +2820,7 @@ > > // logs can be stored also in productionsites, they are counted > as on stock > // but are no available for random production site > - int16_t score = site.bo->stocklevel_ - productionsites.size() * > 5; > + int16_t score = site.bo->stocklevel_ - productionsites.size() * > 2; > > if (score > 200 && site.bo->cnt_built_ > site.bo->cnt_target_) { > > @@ -2859,16 +2848,18 @@ > // and makes two decisions: > // - build a ship > // - start preparation for expedition > -bool DefaultAI::marine_main_decisions(uint32_t const gametime) { > - if (gametime < next_marine_decisions_due) { > +bool DefaultAI::marine_main_decisions(int32_t const gametime) { > + if (gametime < taskDue[ScheduleTasks::KMarineDecisions]) { Although we generally prefer int over uint, the gametime we get from SDL is a uint32_t. So, we should try to stick with that. I know it is inconsistent across the code, we have a bug open to clean this up. > return false; > } > - next_marine_decisions_due = gametime + kMarineDecisionInterval; > > if (!seafaring_economy) { > + taskDue[ScheduleTasks::KMarineDecisions] = > std::numeric_limits<int32_t>::max(); > return false; uint32_t - see comment above > } > > + taskDue[ScheduleTasks::KMarineDecisions] = gametime + > kMarineDecisionInterval; > + > // getting some base statistics > player_ = game().get_player(player_number()); > uint16_t ports_count = 0; > @@ -2918,7 +2909,7 @@ > } > } > > - enum class FleetStatus : uint8_t {kNeedShip = 0, kEnoughShips = 1, > kDoNothing = 2 }; > + enum class FleetStatus : uint8_t {kNeedShip = 0, kEnoughShips = 1, > kDoNothing = 2}; > > // now we must compare ports vs ships to decide if new ship is needed > or new expedition can start > FleetStatus enough_ships = FleetStatus::kDoNothing; > @@ -2969,17 +2960,18 @@ > } > > // This identifies ships that are waiting for command > -bool DefaultAI::check_ships(uint32_t const gametime) { > - if (gametime < next_ship_check_due) { > +bool DefaultAI::check_ships(int32_t const gametime) { > + if (gametime < taskDue[ScheduleTasks::kCheckShips]) { uint32_t - see comment above > return false; > } > > - next_ship_check_due = gametime + kShipCheckInterval; > - > if (!seafaring_economy) { > + taskDue[ScheduleTasks::kCheckShips] = > std::numeric_limits<int32_t>::max(); > return false; uint32_t - see comment above > } > > + bool action_taken = false; > + > if (!allships.empty()) { > // iterating over ships and executing what is needed > for (std::list<ShipObserver>::iterator i = allships.begin(); i > != allships.end(); ++i) { > @@ -3001,6 +2993,7 @@ > // if ships is waiting for command > if (i->waiting_for_command_) { > expedition_management(*i); > + action_taken = true; > } > } > } > @@ -3036,6 +3029,12 @@ > marineTaskQueue_.pop_back(); > } > > + if (action_taken) { > + taskDue[ScheduleTasks::kCheckShips] = gametime + > kShipCheckInterval; > + } else { > + taskDue[ScheduleTasks::kCheckShips] = gametime + 3 * > kShipCheckInterval; > + } > + > return true; > } > > @@ -3046,10 +3045,10 @@ > * \returns true, if something was changed. > */ > bool DefaultAI::check_mines_(int32_t const gametime) { > - if ((next_mine_check_due_ > gametime) || mines_.empty()) > + if (mines_.empty()) { > return false; > + } > > - next_mine_check_due_ = gametime + 7000; // 7 seconds is enough > // Reorder and set new values; - due to returns within the function > mines_.push_back(mines_.front()); > mines_.pop_front(); > @@ -3172,6 +3171,18 @@ > } > } > > +// very primitive function - it sets thisTask to dueTask, if its due time is > +// older then due time of current dueTask > +// void DefaultAI::scheduler_review(int32_t* next_check_due_, > +// int32_t* oldestTaskTime, > +// ScheduleTasks* dueTask, > +// ScheduleTasks thisTask) { > +// if (*next_check_due_ < *oldestTaskTime) { > +//*oldestTaskTime = *next_check_due_; > +//*dueTask = thisTask; > +//} > +//} > + Remove > // counts produced output on stock > // if multiple outputs, it returns lowest value > uint32_t DefaultAI::get_stocklevel(BuildingObserver& bo) { > @@ -3229,13 +3240,13 @@ > // this function only manipulates with trainingsites' inputs priority > // decreases it when too many unoccupied military buildings > bool DefaultAI::check_trainingsites(int32_t gametime) { > - if (next_trainingsites_check_due_ > gametime) { > + if (taskDue[ScheduleTasks::kCheckTrainingsites] > gametime) { > return false; > } > if (!trainingsites.empty()) { > - next_trainingsites_check_due_ = gametime + > kTrainingSitesCheckInterval; > + taskDue[ScheduleTasks::kCheckTrainingsites] = gametime + > kTrainingSitesCheckInterval; > } else { > - next_trainingsites_check_due_ = gametime + 3 * > kTrainingSitesCheckInterval; > + taskDue[ScheduleTasks::kCheckTrainingsites] = gametime + 5 * > kTrainingSitesCheckInterval; > } > > uint8_t new_priority = DEFAULT_PRIORITY; > @@ -3265,12 +3276,12 @@ > * \returns true if something was changed > */ > bool DefaultAI::check_militarysites(int32_t gametime) { > - if (next_militarysite_check_due_ > gametime) { > + if (taskDue[ScheduleTasks::kCheckMilitarysites] > gametime) { > return false; > } > > // just to be sure the value is reset > - next_militarysite_check_due_ = gametime + 4 * 1000; // 4 seconds is > really fine > + taskDue[ScheduleTasks::kCheckMilitarysites] = gametime + 4 * 1000; // > 4 seconds is really fine > // even if there are no finished & attended military sites, probably > there are ones just in > // construction > unstationed_milit_buildings_ = 0; > @@ -3385,7 +3396,7 @@ > // reorder:; > militarysites.push_back(militarysites.front()); > militarysites.pop_front(); > - next_militarysite_check_due_ = gametime + 5 * 1000; // 10 seconds is > really fine > + taskDue[ScheduleTasks::kCheckMilitarysites] = gametime + 5 * 1000; // > 10 seconds is really fine > return changed; > } > > @@ -3833,7 +3844,7 @@ > } > > // Let defaultAI try to directly connect the constructionsite > - next_road_due_ = game().get_gametime(); > + taskDue[ScheduleTasks::kRoadCheck] = game().get_gametime(); > } else { > ++bo.cnt_built_; > > @@ -3989,9 +4000,6 @@ > } > } > } > - > - m_buildable_changed = true; > - m_mineable_changed = true; > } > > // Checks that supply line exists for given building. > @@ -4043,7 +4051,7 @@ > > // Only useable, if it owns at least one militarysite > if (militarysites.empty()) { > - next_attack_consideration_due_ = next_attack_waittime_ * 1000 + > gametime; > + taskDue[ScheduleTasks::kConsiderAttack] = next_attack_waittime_ > * 1000 + gametime; > return false; > } > > @@ -4092,7 +4100,7 @@ > if (current_margin < needed_margin) { // no attacking! > last_attack_target_.x = std::numeric_limits<uint16_t>::max(); > last_attack_target_.y = std::numeric_limits<uint16_t>::max(); > - next_attack_consideration_due_ = next_attack_waittime_ * 1000 + > gametime; > + taskDue[ScheduleTasks::kConsiderAttack] = next_attack_waittime_ > * 1000 + gametime; > return false; > } > > @@ -4131,7 +4139,7 @@ > > // if we cannot attack anybody, terminating... > if (!any_attackable) { > - next_attack_consideration_due_ = next_attack_waittime_ * 1000 + > gametime; > + taskDue[ScheduleTasks::kConsiderAttack] = next_attack_waittime_ > * 1000 + gametime; > last_attack_target_.x = std::numeric_limits<uint16_t>::max(); > last_attack_target_.y = std::numeric_limits<uint16_t>::max(); > return false; > @@ -4245,7 +4253,7 @@ > > game().send_player_enemyflagaction(best_wh_target->base_flag(), > pn, attackers); > last_attack_target_ = best_wh_target->get_position(); > - next_attack_consideration_due_ = (gametime % 10 + 10) * 1000 + > gametime; > + taskDue[ScheduleTasks::kConsiderAttack] = (gametime % 10 + 10) > * 1000 + gametime; > next_attack_waittime_ = 10; > return true; > > @@ -4261,11 +4269,11 @@ > > game().send_player_enemyflagaction(best_ms_target->base_flag(), > pn, attackers); > last_attack_target_ = best_ms_target->get_position(); > - next_attack_consideration_due_ = (gametime % 10 + 10) * 1000 + > gametime; > + taskDue[ScheduleTasks::kConsiderAttack] = (gametime % 10 + 10) > * 1000 + gametime; > next_attack_waittime_ = 10; > return true; > } else { > - next_attack_consideration_due_ = next_attack_waittime_ * 1000 + > gametime; > + taskDue[ScheduleTasks::kConsiderAttack] = next_attack_waittime_ > * 1000 + gametime; > last_attack_target_.x = std::numeric_limits<uint16_t>::max(); > last_attack_target_.y = std::numeric_limits<uint16_t>::max(); > return false; > @@ -4300,13 +4308,36 @@ > } > } > > +// run over dueTasks map and returns task with lower duetime > +DefaultAI::ScheduleTasks DefaultAI::get_oldest_task(int32_t const gametime) { > + > + int32_t oldestTaskTime = gametime; // we are looking for > jobs due before now > + ScheduleTasks DueTask = ScheduleTasks::kIdle; // default > + taskDue[ScheduleTasks::kIdle] = gametime; > + > + for (std::map<ScheduleTasks, int32_t>::iterator it = taskDue.begin(); > it != taskDue.end(); > + ++it) { uint32_t - see comment above. Also, a range-based for loop would be a lot easier to read: for (std::pair<ScheduleTasks, int32_t> task : taskDue) { > + if (it->second < oldestTaskTime) { > + oldestTaskTime = it->second; > + DueTask = it->first; > + } > + } > + return DueTask; > +} > + > // This prints some basic statistics during a game to the command line - > // missing materials and counts of different types of buildings. > // The main purpose of this is when a game creator needs to finetune a map > // and needs to know what resourcess are missing for which player and so on. > // By default it is off (see kPrintStats) > // TODO(tiborb ?): - it would be nice to have this activated by a command > line switch > -void DefaultAI::print_stats() { > +void DefaultAI::print_stats(int32_t const gametime) { > + uint32_t - see comment above. > + if (!kPrintStats) { > + taskDue[ScheduleTasks::kprintStats] = > std::numeric_limits<int32_t>::max(); > + return; uint32_t - see comment above. > + } > + taskDue[ScheduleTasks::kprintStats] = gametime + 30 * 60 * 1000; > > PlayerNumber const pn = player_number(); > > > === modified file 'src/ai/defaultai.h' > --- src/ai/defaultai.h 2015-02-16 21:19:59 +0000 > +++ src/ai/defaultai.h 2015-03-04 20:14:13 +0000 > @@ -78,8 +78,33 @@ > DEFENSIVE = 0, > }; > > - enum class WalkSearch : uint8_t {kAnyPlayer, kOtherPlayers }; > - enum class NewShip : uint8_t {kBuilt, kFoundOnLoad }; > + enum class WalkSearch : uint8_t {kAnyPlayer, kOtherPlayers}; > + enum class NewShip : uint8_t {kBuilt, kFoundOnLoad}; > + enum class ScheduleTasks : uint8_t { > + kBFCheck, > + kRoadCheck, > + kUnbuildableFCheck, > + kConsiderAttack, > + kCheckEconomies, > + kProductionsitesStats, > + kConstructBuilding, > + kCheckProductionsites, > + kCheckShips, > + KMarineDecisions, > + kCheckMines, > + kWareReview, > + kprintStats, > + kIdle, > + kCheckMilitarysites, > + kCheckTrainingsites > + }; > + enum class MilitaryStrategy : uint8_t { > + kNoNewMilitary, > + kDefenseOnly, > + kResourcesOrDefense, > + kExpansion, > + kPushExpansion > + }; > > /// Implementation for Aggressive > struct AggressiveImpl : public ComputerPlayer::Implementation { > @@ -136,6 +161,13 @@ > int16_t* max_preciousness, > int16_t* max_needed_preciousness); > > + // void scheduler_review(int32_t* next_check_due_, > + // int32_t* oldestTaskTime, > + // ScheduleTasks* DueTask, > + // ScheduleTasks thisTask); > + Remove > + ScheduleTasks get_oldest_task(int32_t); > + uint32_t - see comment above. > bool construct_building(int32_t); > > uint32_t coords_hash(Widelands::Coords coords) { > @@ -156,7 +188,7 @@ > bool improve_roads(int32_t); > bool create_shortcut_road(const Widelands::Flag&, > uint16_t maxcheckradius, > - uint16_t minred, > + int16_t minred, > const int32_t gametime); > // trying to identify roads that might be removed > bool dispensable_road_test(Widelands::Road&); > @@ -165,14 +197,13 @@ > bool check_trainingsites(int32_t); > bool check_mines_(int32_t); > bool check_militarysites(int32_t); > - bool marine_main_decisions(uint32_t); > - bool check_ships(uint32_t); > - void print_stats(); > + bool marine_main_decisions(int32_t); > + bool check_ships(int32_t); > + void print_stats(int32_t); > uint32_t get_stocklevel_by_hint(size_t); all uint32_t - see comment above. > uint32_t get_stocklevel(BuildingObserver&); > uint32_t get_warehoused_stock(Widelands::WareIndex wt); > uint32_t get_stocklevel(Widelands::WareIndex); // count all direct > outputs_ > - void check_helpersites(int32_t); > void review_wares_targets(int32_t); > > // sometimes scanning an area in radius gives inappropriate results, so > this is to verify that > @@ -213,8 +244,8 @@ > // Variables of default AI > uint8_t type_; > > - bool m_buildable_changed; > - bool m_mineable_changed; > + // collect statistics on how many times which job was run > + uint32_t schedStat[20] = {0}; > > Widelands::Player* player_; > Widelands::TribeDescr const* tribe_; > @@ -240,23 +271,12 @@ > std::list<WarehouseSiteObserver> warehousesites; > std::list<TrainingSiteObserver> trainingsites; > std::list<ShipObserver> allships; > + std::map<ScheduleTasks, int32_t> taskDue; > uint32_t - see comment above. > std::vector<WareObserver> wares; > > - int32_t next_road_due_; > - int32_t next_stats_update_due_; > - int32_t next_construction_due_; > + int32_t next_ai_think_; > int32_t next_mine_construction_due_; > - int32_t next_productionsite_check_due_; > - int32_t next_mine_check_due_; > - int32_t next_militarysite_check_due_; > - uint32_t next_ship_check_due; > - uint32_t next_marine_decisions_due; > - int32_t next_attack_consideration_due_; > - int32_t next_trainingsites_check_due_; > - int32_t next_bf_check_due_; > - int32_t next_wares_review_due_; > - int32_t next_statistics_report_; > int32_t inhibit_road_building_; > int32_t time_of_last_construction_; > int32_t enemy_last_seen_; > @@ -288,7 +308,7 @@ > // it decreases with failed scans > int32_t spots_; // sum of buildable fields > > - enum {kReprioritize, kStopShipyard, kStapShipyard }; > + enum {kReprioritize, kStopShipyard, kStapShipyard}; > > std::vector<int16_t> marineTaskQueue_; > > -- https://code.launchpad.net/~widelands-dev/widelands/ai-scheduler/+merge/251327 Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/ai-scheduler into lp:widelands. _______________________________________________ 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