widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #04459
Re: [Merge] lp:~widelands-dev/widelands/ai_persistent_data into lp:widelands
my turn now, see my comments to your comments...
Diff comments:
>
> === modified file 'src/ai/defaultai.cc'
> --- src/ai/defaultai.cc 2015-08-28 19:09:59 +0000
> +++ src/ai/defaultai.cc 2015-10-05 17:29:41 +0000
> @@ -690,8 +733,98 @@
> taskDue[ScheduleTasks::kUnbuildableFCheck] = 1000;
> taskDue[ScheduleTasks::kWareReview] = 15 * 60 * 1000;
> taskDue[ScheduleTasks::kPrintStats] = 30 * 60 * 1000;
> - taskDue[ScheduleTasks::kCountMilitaryVacant] = 10 * 60 * 1000;
> + taskDue[ScheduleTasks::kCountMilitaryVacant] = 1 * 60 * 1000;
> taskDue[ScheduleTasks::kCheckEnemySites] = 10 * 60 * 1000;
> +
> + // Here the AI persistent data either exists - then they are read
> + // or does not exist, then they are created and saved
> + const int16_t persistent_data_exists_ = player_->get_ai_data_int16(kPersistentData);
> +
> + // 0 implies no saved data exits yet
> + if (persistent_data_exists_ == 0) {
> + player_->set_ai_data(static_cast<int16_t>(1), kPersistentData);
> +
> + // these random values to make some small differences between players
> + // they are immediately saved
> + // these values are never changed
> + ai_personality_military_loneliness_ = std::rand() % 5 * 30 - 60;
> + player_->set_ai_data(ai_personality_military_loneliness_, kMilitLoneliness);
> +
> + ai_personality_attack_margin_ = std::max(std::rand() % 20 - 5, 0);
> + player_->set_ai_data(ai_personality_attack_margin_, kAttackMargin);
> +
> + ai_personality_wood_difference_ = std::rand() % 40 - 20;
> + player_->set_ai_data(ai_personality_wood_difference_, kWoodDiff);
> +
> + ai_productionsites_ratio_ = std::rand() % 5 + 7;
> + player_->set_ai_data(ai_productionsites_ratio_, kProdRatio);
> +
> + ai_personality_early_militarysites = std::rand() % 20 + 20;
> + player_->set_ai_data(ai_personality_early_militarysites, kEarlyMilitary);
> +
> + } else {
> + log (" %d: restoring saved AI data...\n", player_number());
> +
> +
> + // Restoring data and doing some basic check
> + ai_personality_military_loneliness_ = player_->get_ai_data_int16(kMilitLoneliness);
> + if (ai_personality_military_loneliness_ < -60 || ai_personality_military_loneliness_ > 60) {
> + log(" %d: unexpected value for ai_personality_military_loneliness_: %d\n",
> + player_number(), ai_personality_military_loneliness_);
> + }
> +
> + ai_personality_attack_margin_ = player_->get_ai_data_uint32(kAttackMargin);
> + if (ai_personality_attack_margin_ > 15) {
> + log(" %d: unexpected value for ai_personality_attack_margin_: %d\n",
> + player_number(), ai_personality_attack_margin_);
> + }
> +
> + ai_personality_wood_difference_ = player_->get_ai_data_int32(kWoodDiff);
> + if (ai_personality_wood_difference_ < -20 || ai_personality_wood_difference_ > 19) {
> + log(" %d: unexpected value for ai_personality_wood_difference_: %d\n",
> + player_number(), ai_personality_wood_difference_);
> + }
> +
> + ai_productionsites_ratio_ = player_->get_ai_data_uint32(kProdRatio);
> + if (ai_productionsites_ratio_< 5 || ai_productionsites_ratio_ > 15) {
> + log(" %d: unexpected value for ai_productionsites_ratio_: %d\n",
> + player_number(), ai_productionsites_ratio_);
> + }
> +
> + ai_personality_early_militarysites = player_->get_ai_data_uint32(kEarlyMilitary);
> + if (ai_personality_early_militarysites< 20 || ai_personality_early_militarysites > 40) {
> + log(" %d: unexpected value for ai_personality_early_msites: %d\n",
> + player_number(), ai_personality_early_militarysites);
> + }
> +
well if we have arrays m_ai_data_uint32[], m_ai_data_int32[] and m_ai_data_uint16[] I dont know how to make template function that would return value from array based on template data type....
I know template functions only in 'passively', so this one would look like this:
template <typename type> type get_ai_data(uint32_t position) {
//here based on type it would pick proper array - I dont know how to do it
return m_ai_data_???????[position];
}
Or can I pass type (int32_t, uint32_t ...) as an argument to the function, like:
get_ai_data(uint32_t position, type) {
if (type == int32_t) {
return m_ai_data_int32[position]
} else if (type == uint32_t) {
return m_ai_data_uint32[position]
} else ....
.....
....
}
this would do the trick...
> + // Now some runtime values that are generated and saved during course of game
> + last_attack_time_ = player_->get_ai_data_uint32(kLastAttack);
> +
> + last_attacked_player_ = static_cast<uint16_t>(player_->get_ai_data_int16(kAttacker));
> + if (last_attacked_player_ > 8) {
> + log(" %d: unexpected value for last_attacked_player_: %d\n",
> + player_number(), ai_personality_attack_margin_);
> + }
> +
> + colony_scan_area_ = player_->get_ai_data_uint32(kColonyScan);
> + if (colony_scan_area_ > 50) {
> + log(" %d: unexpected value for colony_scan_area_: %d\n",
> + player_number(), colony_scan_area_);
> + }
> +
> + trees_around_cutters_ = player_->get_ai_data_uint32(kTreesAround);
> +
> + least_military_score_ = player_->get_ai_data_int32(kLeastMilit);
> + if (least_military_score_< 0 || least_military_score_ > 1000) {
> + log(" %d: unexpected value for least_military_score_: %d\n",
> + player_number(), least_military_score_);
> + }
> + target_military_score_ = player_->get_ai_data_int32(kTargetMilit);
> + if (target_military_score_< least_military_score_ || target_military_score_ > 1000) {
> + log(" %d: unexpected value for target_military_score_: %d\n",
> + player_number(), target_military_score_);
> + }
> + }
> }
>
> /**
> @@ -3531,61 +3577,97 @@
> return true;
> }
>
> - // doing nothing when failed count is too low
> - if (site.no_resources_count < 4) {
> + // to avoid problems with uint underflow, we discourage considerations below
> + if (gametime < 10 * 60 * 1000) {
> return false;
> }
>
> - // dismantling when the failed count is too high
> - if (site.no_resources_count > 12) {
> - flags_to_be_removed.push_back(site.site->base_flag().get_position());
> - if (connected_to_wh) {
> - game().send_player_dismantle(*site.site);
> - } else {
> - game().send_player_bulldoze(*site.site);
> - }
> - site.bo->construction_decision_time_ = gametime;
> - return true;
> - }
> -
> - // is output needed (compare stocked materials vs target values)
> - check_building_necessity(*site.bo);
> -
> - // if we have enough of mined materials on stock - do not upgrade (yet)
> - if (site.bo->output_needed_ == ExtendedBool::kFalse) {
> + // if mine is working, doing nothing
> + if (site.no_resources_since_ > gametime - 5 * 60 * 1000) {
> return false;
> }
>
> // Check whether building is enhanceable. If yes consider an upgrade.
> const BuildingIndex enhancement = site.site->descr().enhancement();
> -
> - // if no enhancement is possible
> - if (enhancement == INVALID_INDEX) {
> - // will be destroyed when no_resource_count will overflow
> + bool has_upgrade = false;
> + if (enhancement != INVALID_INDEX) {
> + if (player_->is_building_type_allowed(enhancement)) {
> + has_upgrade = true;
> + }
> + }
> +
> + // every type of mine has minimal number of mines that are to be preserved
> + // (we will not dismantle even if there are no mineable resources left for this level of mine
> + // and output is not needed)
> + bool forcing_upgrade = false;
> + const uint16_t minimal_mines_count = (site.bo->built_mat_producer_)?2:1;
> + if (has_upgrade &&
> + mines_per_type[site.bo->mines_].total_count() <= minimal_mines_count) {
> + forcing_upgrade = true;
> + }
> +
> +
> + // dismantling a mine
> + if (!has_upgrade) { // if no upgrade, now
> + flags_to_be_removed.push_back(site.site->base_flag().get_position());
> + if (connected_to_wh) {
> + game().send_player_dismantle(*site.site);
> + } else {
> + game().send_player_bulldoze(*site.site);
> + }
> + site.bo->construction_decision_time_ = gametime;
> + return true;
> + // if having an upgrade, after half hour
> + } else if (site.no_resources_since_ < gametime - 30 * 60 * 1000 && !forcing_upgrade) {
> + flags_to_be_removed.push_back(site.site->base_flag().get_position());
> + if (connected_to_wh) {
> + game().send_player_dismantle(*site.site);
> + } else {
> + game().send_player_bulldoze(*site.site);
> + }
> + site.bo->construction_decision_time_ = gametime;
> + return true;
> + }
> +
> + // if we are here, a mine is upgradeable
> +
> + // if we don't need the output, and we have other buildings of the same type, the function returns
> + // and building will be dismantled later.
> + check_building_necessity(*site.bo, PerfEvaluation::kForDismantle, gametime);
> + if (site.bo->max_needed_preciousness_ == 0 && !forcing_upgrade) {
> return false;
> }
>
> + // again similarly, no upgrading if not connected, other parts of AI will dismantle it,
> + // or connect to a warehouse
> if (!connected_to_wh) {
> - // no enhancement possible
> + return false;
> + }
> +
> + // don't upgrade now if other mines of the same type are right now in construction
> + if (mines_per_type[site.bo->mines_].in_construction > 0) {
> return false;
> }
>
> bool changed = false;
> - if (player_->is_building_type_allowed(enhancement)) {
> - // first exclude possibility there are enhancements in construction or unoccupied_
> - const BuildingDescr& bld = *tribe_->get_building_descr(enhancement);
> - BuildingObserver& en_bo = get_building_observer(bld.name().c_str());
> -
> - // if it is too soon for enhancement and making sure there are no unoccupied mines
> - if (gametime - en_bo.construction_decision_time_ >= kBuildingMinInterval &&
> - en_bo.unoccupied_ + en_bo.cnt_under_construction_ == 0) {
> -
> - // now verify that there are enough workers
> - if (site.site->has_workers(enhancement, game())) { // enhancing
> - game().send_player_enhance_building(*site.site, enhancement);
> - en_bo.construction_decision_time_ = gametime;
> - changed = true;
> - }
> +
> + // first exclude possibility there are enhancements in construction or unoccupied_count_
> + const BuildingDescr& bld = *tribe_->get_building_descr(enhancement);
> + BuildingObserver& en_bo = get_building_observer(bld.name().c_str());
> +
> + // if it is too soon for enhancement
> + if (gametime - en_bo.construction_decision_time_ >= kBuildingMinInterval) {
> + // now verify that there are enough workers
> + if (site.site->has_workers(enhancement, game())) { // enhancing
Now I am not sure what you mean. When we consider upgrade we allways check if we have workers for target building. So I presume that this will guarantee that newly upgraded building will have enough workers.
Of course I can imagine some corner cases, f.e. two buidlings needed the same workers being built/upgraded in the same time..
> + game().send_player_enhance_building(*site.site, enhancement);
> + if (site.bo->max_needed_preciousness_ == 0) {
> + assert (mines_per_type[site.bo->mines_].total_count() <= minimal_mines_count);
> + }
> + if (mines_per_type[site.bo->mines_].total_count() > minimal_mines_count) {
> + assert(site.bo->max_needed_preciousness_ > 0);
> + }
> + en_bo.construction_decision_time_ = gametime;
> + changed = true;
> }
> }
>
--
https://code.launchpad.net/~widelands-dev/widelands/ai_persistent_data/+merge/271853
Your team Widelands Developers is subscribed to branch lp:~widelands-dev/widelands/ai_persistent_data.
References