widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #12100
[Merge] lp:~widelands-dev/widelands/ai_fields_update into lp:widelands
TiborB has proposed merging lp:~widelands-dev/widelands/ai_fields_update into lp:widelands.
Requested reviews:
Widelands Developers (widelands-dev)
For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/ai_fields_update/+merge/335589
An improvement to AI's update_all_buildable_fields function, to pick few more suitable fields and update their information so that they will be usable for construct_building function.
--
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/ai_fields_update into lp:widelands.
=== modified file 'src/ai/defaultai.cc'
--- src/ai/defaultai.cc 2017-12-10 21:19:02 +0000
+++ src/ai/defaultai.cc 2017-12-25 20:58:49 +0000
@@ -1048,10 +1048,11 @@
}
/**
- * Checks ALL available buildable fields.
+ * Checks PART of available buildable fields.
*
- * this shouldn't be used often, as it might hang the game for some 100
- * milliseconds if the area the computer owns is big.
+ * this checks about 40-50 buildable fields. In big games the player can have thousends
+ * of them, so we rotate the buildable_fields container and check 40 fields, and in addition
+ * we look for medium&big fields and near border fields if needed.
*/
void DefaultAI::update_all_buildable_fields(const uint32_t gametime) {
uint16_t i = 0;
@@ -1059,35 +1060,111 @@
// To be sure we have some info about enemies we might see
update_player_stat(gametime);
+ // Generall we check fields as they are in the container, but we need also given
+ // number of "special" fields. So if given number of fields are not found within
+ // "regular" check, we must go on and look also on other fields...
+ uint8_t non_small_needed = 4;
+ uint8_t near_border_needed = 10;
+
+ const uint16_t minimal_fields_check = 35;
+
// we test 40 fields that were update more than 1 seconds ago
- while (!buildable_fields.empty() &&
- (buildable_fields.front()->field_info_expiration - kFieldInfoExpiration + 1000) <=
- gametime &&
- i < 40) {
+ while (!buildable_fields.empty() && i < std::min<uint16_t>(minimal_fields_check, buildable_fields.size())) {
BuildableField& bf = *buildable_fields.front();
- // check whether we lost ownership of the node
- if (bf.coords.field->get_owned_by() != player_number()) {
- delete &bf;
- buildable_fields.pop_front();
- continue;
- }
-
- // check whether we can still construct regular buildings on the node
- if ((player_->get_buildcaps(bf.coords) & BUILDCAPS_SIZEMASK) == 0) {
- unusable_fields.push_back(bf.coords);
- delete &bf;
- buildable_fields.pop_front();
- continue;
- }
-
- update_buildable_field(bf);
+ if ((buildable_fields.front()->field_info_expiration - kFieldInfoExpiration + 1000) <=
+ gametime) {
+
+ // check whether we lost ownership of the node
+ if (bf.coords.field->get_owned_by() != player_number()) {
+ delete &bf;
+ buildable_fields.pop_front();
+ continue;
+ }
+
+ // check whether we can still construct regular buildings on the node
+ if ((player_->get_buildcaps(bf.coords) & BUILDCAPS_SIZEMASK) == 0) {
+ unusable_fields.push_back(bf.coords);
+ delete &bf;
+ buildable_fields.pop_front();
+ continue;
+ }
+
+ update_buildable_field(bf);
+ if (non_small_needed > 0) {
+ int32_t const maxsize = player_->get_buildcaps(bf.coords) & BUILDCAPS_SIZEMASK;
+ if (maxsize > 1) {
+ non_small_needed -= 1;
+ }
+ }
+ if (near_border_needed > 0) {
+ if (bf.near_border) {
+ near_border_needed -= 1;
+ }
+ }
+ }
bf.field_info_expiration = gametime + kFieldInfoExpiration;
buildable_fields.push_back(&bf);
buildable_fields.pop_front();
i += 1;
}
+
+ // If needed we iterate once more and look for 'special' fields
+ // starting in the middle of buildable_fields to skip fileds tested lately
+ // But not doing this if the count of buildable fields is too low
+ // (no need to bother) or this is a new game (< 20 seconds)
+ if (buildable_fields.size() < minimal_fields_check * 3 || gametime < 20000) {
+ return;
+ }
+
+ for (uint32_t j = buildable_fields.size() / 2; j < buildable_fields.size(); j++) {
+ // If we dont need to iterate (anymore) ...
+ if (non_small_needed + near_border_needed == 0) {
+ break;
+ }
+
+ // Skip if the field is not ours or were updated lately
+ if (buildable_fields[j]->coords.field->get_owned_by() != player_number()) {
+ continue;
+ }
+ // We are not interested in fields where info has expired less than 20s ago
+ if (buildable_fields[j]->field_info_expiration > gametime - 20000) {
+ continue;
+ }
+
+ // Continue if field is blocked at the moment
+ if (blocked_fields.is_blocked(buildable_fields[j]->coords)) {
+ continue;
+ }
+
+ // Few constants to keep the code cleaner
+ const int32_t field_maxsize =
+ player_->get_buildcaps(buildable_fields[j]->coords) & BUILDCAPS_SIZEMASK;
+ const bool field_near_border = buildable_fields[j]->near_border;
+
+ // Let decide if we need to update and for what reason
+ const bool update_due_size = non_small_needed && field_maxsize > 1;
+ const bool update_due_border = near_border_needed && field_near_border;
+
+ if (!(update_due_size || update_due_border)) {
+ continue;
+ }
+
+ // decreasing the counters
+ if (update_due_size) {
+ assert (non_small_needed > 0);
+ non_small_needed -= 1;
+ }
+ if (update_due_border) {
+ assert (near_border_needed > 0);
+ near_border_needed -= 1;
+ }
+
+ // and finnaly update the buildable field
+ update_buildable_field(*buildable_fields[j]);
+ buildable_fields[j]->field_info_expiration = gametime + kFieldInfoExpiration;
+ }
}
/**
Follow ups