widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #12144
[Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
TiborB has proposed merging lp:~widelands-dev/widelands/ai_portspaces into lp:widelands.
Requested reviews:
Widelands Developers (widelands-dev)
For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/ai_portspaces/+merge/335785
AI now scans entire map for portspaces. And multiple changes to the logic, including logic of placing militarysites - they now know there is (unowned) vicinity of port spaces (or portspaces themselves)
--
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/ai_portspaces into lp:widelands.
=== modified file 'src/ai/ai_help_structs.cc'
--- src/ai/ai_help_structs.cc 2017-11-24 09:19:52 +0000
+++ src/ai/ai_help_structs.cc 2018-01-05 22:15:52 +0000
@@ -236,6 +236,7 @@
unowned_land_nearby(0),
enemy_owned_land_nearby(0U),
unowned_buildable_spots_nearby(0U),
+ unowned_portspace_vicinity_nearby(0U),
nearest_buildable_spot_nearby(0U),
near_border(false),
unowned_mines_spots_nearby(0),
=== modified file 'src/ai/ai_help_structs.h'
--- src/ai/ai_help_structs.h 2017-11-17 07:16:12 +0000
+++ src/ai/ai_help_structs.h 2018-01-05 22:15:52 +0000
@@ -316,6 +316,7 @@
uint16_t unowned_land_nearby;
uint16_t enemy_owned_land_nearby;
uint16_t unowned_buildable_spots_nearby;
+ uint16_t unowned_portspace_vicinity_nearby;
uint16_t nearest_buildable_spot_nearby;
// to identify that field is too close to border and no production building should be built there
bool near_border;
@@ -356,7 +357,7 @@
Widelands::ExtendedBool is_portspace;
bool port_nearby; // to increase priority if a port is nearby,
// especially for new colonies
- Widelands::ExtendedBool portspace_nearby; // prefer military buildings closer to the portspace
+ Widelands::ExtendedBool portspace_nearby; // special fields intended for ports
int32_t max_buildcap_nearby;
// It is not necessary to check resources (stones, fish...) too frequently as they do not change
// fast. This stores the time of the last check.
=== modified file 'src/ai/defaultai.cc'
--- src/ai/defaultai.cc 2017-12-10 21:19:02 +0000
+++ src/ai/defaultai.cc 2018-01-05 22:15:52 +0000
@@ -123,7 +123,7 @@
if (note.ownership == NoteFieldPossession::Ownership::GAINED) {
unusable_fields.push_back(note.fc);
}
- });
+ });
// Subscribe to NoteImmovables.
immovable_subscriber_ =
@@ -139,7 +139,7 @@
} else {
lose_immovable(*note.pi);
}
- });
+ });
// Subscribe to ProductionSiteOutOfResources.
outofresource_subscriber_ = Notifications::subscribe<NoteProductionSiteOutOfResources>(
@@ -150,7 +150,7 @@
out_of_resources_site(*note.ps);
- });
+ });
// Subscribe to TrainingSiteSoldierTrained.
soldiertrained_subscriber_ = Notifications::subscribe<NoteTrainingSiteSoldierTrained>(
@@ -161,46 +161,48 @@
soldier_trained(*note.ts);
- });
+ });
// Subscribe to ShipNotes.
- shipnotes_subscriber_ = Notifications::subscribe<NoteShipMessage>([this](
- const NoteShipMessage& note) {
-
- // in a short time between start and late_initialization the player
- // can get notes that can not be processed.
- // It seems that this causes no problem, at least no substantial
- if (player_ == nullptr) {
- return;
- }
- if (note.ship->get_owner()->player_number() != player_->player_number()) {
- return;
- }
-
- switch (note.message) {
-
- case NoteShipMessage::Message::kGained:
- gain_ship(*note.ship, NewShip::kBuilt);
- break;
-
- case NoteShipMessage::Message::kLost:
- for (std::deque<ShipObserver>::iterator i = allships.begin(); i != allships.end(); ++i) {
- if (i->ship == note.ship) {
- allships.erase(i);
- break;
- }
- }
- break;
-
- case NoteShipMessage::Message::kWaitingForCommand:
- for (std::deque<ShipObserver>::iterator i = allships.begin(); i != allships.end(); ++i) {
- if (i->ship == note.ship) {
- i->waiting_for_command_ = true;
- break;
- }
- }
- }
- });
+ shipnotes_subscriber_ =
+ Notifications::subscribe<NoteShipMessage>([this](const NoteShipMessage& note) {
+
+ // in a short time between start and late_initialization the player
+ // can get notes that can not be processed.
+ // It seems that this causes no problem, at least no substantial
+ if (player_ == nullptr) {
+ return;
+ }
+ if (note.ship->get_owner()->player_number() != player_->player_number()) {
+ return;
+ }
+
+ switch (note.message) {
+
+ case NoteShipMessage::Message::kGained:
+ gain_ship(*note.ship, NewShip::kBuilt);
+ break;
+
+ case NoteShipMessage::Message::kLost:
+ for (std::deque<ShipObserver>::iterator i = allships.begin(); i != allships.end();
+ ++i) {
+ if (i->ship == note.ship) {
+ allships.erase(i);
+ break;
+ }
+ }
+ break;
+
+ case NoteShipMessage::Message::kWaitingForCommand:
+ for (std::deque<ShipObserver>::iterator i = allships.begin(); i != allships.end();
+ ++i) {
+ if (i->ship == note.ship) {
+ i->waiting_for_command_ = true;
+ break;
+ }
+ }
+ }
+ });
}
DefaultAI::~DefaultAI() {
@@ -923,26 +925,6 @@
const Map& map = game().map();
- // here we generate list of all ports and their vicinity from entire map
- for (const Coords& c : map.get_port_spaces()) {
- MapRegion<Area<FCoords>> mr(map, Area<FCoords>(map.get_fcoords(c), 3));
- do {
- const int32_t hash = map.get_fcoords(*(mr.location().field)).hash();
- if (port_reserved_coords.count(hash) == 0)
- port_reserved_coords.insert(hash);
- } while (mr.advance(map));
-
- // 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));
- do {
- const int32_t hash = map.get_fcoords(*(mr_nw.location().field)).hash();
- if (port_reserved_coords.count(hash) == 0)
- port_reserved_coords.insert(hash);
- } while (mr_nw.advance(map));
- }
-
// here we scan entire map for own ships
std::set<OPtr<Ship>> found_ships;
for (int16_t y = 0; y < map.get_height(); ++y) {
@@ -990,13 +972,26 @@
if (ps_obs.bo->is(BuildingAttribute::kSpaceConsumer) &&
!ps_obs.bo->is(BuildingAttribute::kRanger)) {
MapRegion<Area<FCoords>> mr(
- map, Area<FCoords>(map.get_fcoords(ps_obs.site->get_position()), 4));
+ map, Area<FCoords>(map.get_fcoords(ps_obs.site->get_position()), 2));
do {
blocked_fields.add(mr.location(), game().get_gametime() + 20 * 60 * 1000);
} while (mr.advance(map));
}
}
+ // getting list of all fields nearby port space
+ // TODO it seems port spaces can change over time so ports_vicinity needs to be refreshed from
+ // time to time
+ for (const Coords& c : map.get_port_spaces()) {
+ MapRegion<Area<FCoords>> mr(map, Area<FCoords>(map.get_fcoords(c), 3));
+ do {
+ const uint32_t hash = mr.location().hash();
+ if (!ports_vicinity.count(hash)) {
+ ports_vicinity.insert(hash);
+ }
+ } while (mr.advance(map));
+ }
+
// printing identified basic buildings if we are in the basic economy mode
basic_economy_established = persistent_data->remaining_basic_buildings.empty();
if (!basic_economy_established) {
@@ -1214,9 +1209,12 @@
Area<FCoords>(field.coords, actual_enemy_check_area), nullptr, find_enemy_owned_walkable);
field.nearest_buildable_spot_nearby = std::numeric_limits<uint16_t>::max();
+ field.unowned_buildable_spots_nearby = 0;
+ field.unowned_portspace_vicinity_nearby = 0;
if (field.unowned_land_nearby > 0) {
std::vector<Coords> found_buildable_fields;
+ // first looking for unowned buildable spots
field.unowned_buildable_spots_nearby =
map.find_fields(Area<FCoords>(field.coords, kBuildableSpotsCheckArea),
&found_buildable_fields, find_unowned_buildable);
@@ -1227,8 +1225,16 @@
field.nearest_buildable_spot_nearby = cur_distance;
}
}
- } else {
- field.unowned_buildable_spots_nearby = 0;
+
+ // now looking for unowned_portspace_vicinity_nearby
+ MapRegion<Area<FCoords>> mr(map, Area<FCoords>(field.coords, kBuildableSpotsCheckArea));
+ do {
+
+ if (mr.location().field->get_owned_by() == 0 &&
+ ports_vicinity.count(mr.location().hash()) > 0) {
+ field.unowned_portspace_vicinity_nearby += 1;
+ }
+ } while (mr.advance(map));
}
// Is this near the border? Get rid of fields owned by ally
@@ -1276,25 +1282,17 @@
}
// identifying portspace fields
- if (field.is_portspace ==
- Widelands::ExtendedBool::kUnset) { // if we know it, no need to do it once more
- if (player_->get_buildcaps(field.coords) & BUILDCAPS_PORT) {
- field.is_portspace = ExtendedBool::kTrue;
- } else {
- field.is_portspace = ExtendedBool::kFalse;
- }
+ if (player_->get_buildcaps(field.coords) & BUILDCAPS_PORT) {
+ field.is_portspace = ExtendedBool::kTrue;
+ } else {
+ field.is_portspace = ExtendedBool::kFalse;
}
// testing for near portspaces
- if (field.portspace_nearby == Widelands::ExtendedBool::kUnset) {
+ if (ports_vicinity.count(field.coords.hash()) > 0) {
+ field.portspace_nearby = ExtendedBool::kTrue;
+ } else {
field.portspace_nearby = ExtendedBool::kFalse;
- MapRegion<Area<FCoords>> mr(map, Area<FCoords>(field.coords, 4));
- do {
- if (port_reserved_coords.count(mr.location().hash()) > 0) {
- field.portspace_nearby = ExtendedBool::kTrue;
- break;
- }
- } while (mr.advance(map));
}
// testing if a port is nearby, such field will get a priority boost
@@ -1613,29 +1611,23 @@
const uint8_t score_parts_size = 60;
int32_t score_parts[score_parts_size] = {0};
if (field.enemy_owned_land_nearby) {
- score_parts[0] = 3 *
- management_data.neuron_pool[73].get_result_safe(
- field.enemy_owned_land_nearby / 5, kAbsValue);
- score_parts[1] =
- 3 *
- management_data.neuron_pool[76].get_result_safe(field.enemy_owned_land_nearby, kAbsValue);
- score_parts[2] = 3 *
- management_data.neuron_pool[54].get_result_safe(
- field.enemy_military_presence * 2, kAbsValue);
- score_parts[3] = 3 *
- management_data.neuron_pool[61].get_result_safe(
- field.enemy_military_presence / 3, kAbsValue);
+ score_parts[0] = 3 * management_data.neuron_pool[73].get_result_safe(
+ field.enemy_owned_land_nearby / 5, kAbsValue);
+ score_parts[1] = 3 * management_data.neuron_pool[76].get_result_safe(
+ field.enemy_owned_land_nearby, kAbsValue);
+ score_parts[2] = 3 * management_data.neuron_pool[54].get_result_safe(
+ field.enemy_military_presence * 2, kAbsValue);
+ score_parts[3] = 3 * management_data.neuron_pool[61].get_result_safe(
+ field.enemy_military_presence / 3, kAbsValue);
score_parts[4] =
(!field.enemy_accessible_) ? (-100 + management_data.get_military_number_at(55)) : 0;
- score_parts[5] =
- 2 *
- management_data.neuron_pool[50].get_result_safe(field.enemy_owned_land_nearby, kAbsValue);
+ score_parts[5] = 2 * management_data.neuron_pool[50].get_result_safe(
+ field.enemy_owned_land_nearby, kAbsValue);
score_parts[6] =
field.enemy_military_sites * std::abs(management_data.get_military_number_at(67) / 2);
- score_parts[7] =
- 2 *
- management_data.neuron_pool[34].get_result_safe(field.enemy_military_sites * 2, kAbsValue);
+ score_parts[7] = 2 * management_data.neuron_pool[34].get_result_safe(
+ field.enemy_military_sites * 2, kAbsValue);
score_parts[8] = management_data.neuron_pool[56].get_result_safe(
field.enemy_military_presence * 2, kAbsValue);
@@ -1644,13 +1636,11 @@
score_parts[10] = (field.enemy_accessible_) ? management_data.get_military_number_at(80) : 0;
score_parts[11] =
- -3 *
- management_data.neuron_pool[8].get_result_safe(
- (field.military_in_constr_nearby + field.military_unstationed) * 3, kAbsValue);
+ -3 * management_data.neuron_pool[8].get_result_safe(
+ (field.military_in_constr_nearby + field.military_unstationed) * 3, kAbsValue);
score_parts[12] =
- -3 *
- management_data.neuron_pool[74].get_result_safe(
- (field.military_in_constr_nearby + field.military_unstationed) * 5, kAbsValue);
+ -3 * management_data.neuron_pool[74].get_result_safe(
+ (field.military_in_constr_nearby + field.military_unstationed) * 5, kAbsValue);
score_parts[13] = ((field.military_in_constr_nearby + field.military_unstationed) > 0) ?
-std::abs(management_data.get_military_number_at(32)) :
0;
@@ -1677,9 +1667,8 @@
std::abs(management_data.get_military_number_at(58)) :
0;
if (expansion_type.get_expansion_type() == ExpansionMode::kResources) {
- score_parts[23] = 2 *
- management_data.neuron_pool[78].get_result_safe(
- (field.unowned_mines_spots_nearby + 2) / 3, kAbsValue);
+ score_parts[23] = 2 * management_data.neuron_pool[78].get_result_safe(
+ (field.unowned_mines_spots_nearby + 2) / 3, kAbsValue);
}
score_parts[24] =
@@ -1708,22 +1697,19 @@
management_data.neuron_pool[10].get_result_safe(field.military_loneliness / 50, kAbsValue);
score_parts[30] =
- -10 *
- management_data.neuron_pool[8].get_result_safe(
- 3 * (field.military_in_constr_nearby + field.military_unstationed), kAbsValue);
+ -10 * management_data.neuron_pool[8].get_result_safe(
+ 3 * (field.military_in_constr_nearby + field.military_unstationed), kAbsValue);
score_parts[31] =
- -10 *
- management_data.neuron_pool[31].get_result_safe(
- 3 * (field.military_in_constr_nearby + field.military_unstationed), kAbsValue);
+ -10 * management_data.neuron_pool[31].get_result_safe(
+ 3 * (field.military_in_constr_nearby + field.military_unstationed), kAbsValue);
score_parts[32] = -4 * field.military_in_constr_nearby *
std::abs(management_data.get_military_number_at(82));
score_parts[33] = (field.military_in_constr_nearby > 0) ?
-5 * management_data.get_military_number_at(85) :
0;
- score_parts[34] = -1 *
- management_data.neuron_pool[4].get_result_safe(
- (field.area_military_capacity + 4) / 5, kAbsValue);
+ score_parts[34] = -1 * management_data.neuron_pool[4].get_result_safe(
+ (field.area_military_capacity + 4) / 5, kAbsValue);
score_parts[35] = 3 * management_data.get_military_number_at(133);
if (expansion_type.get_expansion_type() == ExpansionMode::kEconomy) {
@@ -1750,14 +1736,12 @@
score_parts[41] = 3 * std::abs(management_data.get_military_number_at(93));
}
- score_parts[42] =
- (field.unowned_land_nearby) ?
- management_data.neuron_pool[18].get_result_safe(field.own_non_military_nearby, kAbsValue) :
- 0;
+ score_parts[42] = (field.unowned_land_nearby) ? management_data.neuron_pool[18].get_result_safe(
+ field.own_non_military_nearby, kAbsValue) :
+ 0;
- score_parts[43] = 2 *
- management_data.neuron_pool[11].get_result_safe(
- field.unowned_buildable_spots_nearby, kAbsValue);
+ score_parts[43] = 2 * management_data.neuron_pool[11].get_result_safe(
+ field.unowned_buildable_spots_nearby, kAbsValue);
score_parts[44] =
management_data.neuron_pool[12].get_result_safe(field.unowned_mines_spots_nearby, kAbsValue);
score_parts[45] =
@@ -1767,12 +1751,10 @@
score_parts[46] =
-1 * management_data.neuron_pool[55].get_result_safe(field.ally_military_presence, kAbsValue);
- score_parts[47] =
- -1 *
- management_data.neuron_pool[53].get_result_safe(2 * field.ally_military_presence, kAbsValue);
- score_parts[48] = -2 *
- management_data.neuron_pool[4].get_result_safe(
- (field.area_military_capacity + 4) / 5, kAbsValue);
+ score_parts[47] = -1 * management_data.neuron_pool[53].get_result_safe(
+ 2 * field.ally_military_presence, kAbsValue);
+ score_parts[48] = -2 * management_data.neuron_pool[4].get_result_safe(
+ (field.area_military_capacity + 4) / 5, kAbsValue);
score_parts[49] = ((field.military_in_constr_nearby + field.military_unstationed) > 0) ?
-std::abs(management_data.get_military_number_at(81)) :
0;
@@ -1781,6 +1763,13 @@
0;
score_parts[56] =
(any_unconnected_imm) ? 2 * std::abs(management_data.get_military_number_at(23)) : 0;
+ score_parts[57] = 1 * management_data.neuron_pool[18].get_result_safe(
+ 2 * field.unowned_portspace_vicinity_nearby, kAbsValue);
+ score_parts[58] = 3 * management_data.neuron_pool[19].get_result_safe(
+ 5 * field.unowned_portspace_vicinity_nearby, kAbsValue);
+ score_parts[59] = (field.unowned_portspace_vicinity_nearby) ?
+ 10 * std::abs(management_data.get_military_number_at(31)) :
+ 0;
for (uint16_t i = 0; i < score_parts_size; i++) {
field.military_score_ += score_parts[i];
@@ -2425,13 +2414,6 @@
continue;
}
- // testing for reserved ports
- if (!bo.is(BuildingAttribute::kPort)) {
- if (port_reserved_coords.count(bf->coords.hash()) > 0) {
- continue;
- }
- }
-
if (std::rand() % 3 == 0 && bo.total_count() > 0) {
continue;
} // add randomnes and ease AI
@@ -2454,10 +2436,21 @@
int32_t prio = 0; // score of a bulding on a field
+ // testing for reserved ports
+ if (!bo.is(BuildingAttribute::kPort)) {
+ if (bf->portspace_nearby == ExtendedBool::kTrue) {
+ if (num_ports == 0) {
+ continue;
+ }
+ // If we have at least on port, we can perhaps build here something
+ // but decreasing the score to discourage it
+ prio -= 5 * std::abs(management_data.get_military_number_at(52));
+ }
+ }
+
if (bo.type == BuildingObserver::Type::kProductionsite) {
- prio = management_data.neuron_pool[44].get_result_safe(bf->military_score_ / 20) / 5;
- assert(prio >= -20 && prio <= 20);
+ prio += management_data.neuron_pool[44].get_result_safe(bf->military_score_ / 20) / 5;
// this can be only a well (as by now)
if (bo.is(BuildingAttribute::kWell)) {
@@ -2470,7 +2463,7 @@
continue;
}
- prio = bo.primary_priority;
+ prio += bo.primary_priority;
// keep wells more distant
if (bf->producers_nearby.at(bo.outputs.at(0)) > 2) {
@@ -2487,7 +2480,7 @@
} else if (bo.is(BuildingAttribute::kLumberjack)) {
- prio = bo.primary_priority;
+ prio += bo.primary_priority;
if (bo.new_building == BuildingNecessity::kForced) {
prio += 5 * std::abs(management_data.get_military_number_at(17));
@@ -2512,7 +2505,7 @@
// Quarries are generally to be built everywhere where rocks are
// no matter the need for granite, as rocks are considered an obstacle
// to expansion
- prio = 2 * bf->rocks_nearby;
+ prio += 2 * bf->rocks_nearby;
if (bf->rocks_nearby > 0 && bf->near_border) {
prio += management_data.get_military_number_at(27) / 2;
@@ -2569,9 +2562,8 @@
prio -= bf->producers_nearby.at(bo.outputs.at(0)) * 20;
prio += bf->supporters_nearby.at(bo.outputs.at(0)) * 20;
- prio +=
- -5 +
- bf->fish_nearby * (1 + std::abs(management_data.get_military_number_at(63) / 15));
+ prio += -5 + bf->fish_nearby *
+ (1 + std::abs(management_data.get_military_number_at(63) / 15));
if (resource_necessity_water_needed_) {
prio *= 3;
}
@@ -2587,8 +2579,6 @@
assert(bo.new_building == BuildingNecessity::kNeeded);
- prio = 0;
-
if (bo.total_count() == 0) {
prio += 200;
} else {
@@ -2635,9 +2625,8 @@
}
if (current_stocklevel < 40) {
- prio += 5 *
- management_data.neuron_pool[23].get_result_safe(
- (40 - current_stocklevel) / 2, kAbsValue);
+ prio += 5 * management_data.neuron_pool[23].get_result_safe(
+ (40 - current_stocklevel) / 2, kAbsValue);
}
for (auto ph : bo.production_hints) {
@@ -2648,10 +2637,14 @@
if (bf->enemy_nearby) {
prio -= 20;
}
+
+ if (bf->unowned_portspace_vicinity_nearby > 0) {
+ prio -= 500;
+ }
}
} else if (bo.is(BuildingAttribute::kRecruitment)) {
- prio = bo.primary_priority;
+ prio += bo.primary_priority;
prio -= bf->unowned_land_nearby * 2;
prio -= (bf->enemy_nearby) * 100;
prio -= (expansion_type.get_expansion_type() != ExpansionMode::kEconomy) * 100;
@@ -2684,9 +2677,8 @@
// we attempt to cluster space consumers together
prio += bf->space_consumers_nearby * 2;
// and be far from rangers
- prio += 1 -
- bf->rangers_nearby *
- std::abs(management_data.get_military_number_at(102)) / 5;
+ prio += 1 - bf->rangers_nearby *
+ std::abs(management_data.get_military_number_at(102)) / 5;
} else {
// leave some free space between them
prio -= bf->producers_nearby.at(bo.outputs.at(0)) *
@@ -2756,7 +2748,7 @@
// Consider border with exemption of some huts
if (!(bo.is(BuildingAttribute::kLumberjack) || bo.is(BuildingAttribute::kNeedsCoast) ||
bo.is(BuildingAttribute::kFisher))) {
- prio = recalc_with_border_range(*bf, prio);
+ prio += recalc_with_border_range(*bf, prio);
} else if (bf->near_border && (bo.is(BuildingAttribute::kLumberjack) ||
bo.is(BuildingAttribute::kNeedsCoast))) {
prio /= 2;
@@ -2765,12 +2757,12 @@
} // production sites done
else if (bo.type == BuildingObserver::Type::kMilitarysite) {
- assert(prio == 0);
- prio = bo.primary_priority;
+ prio += bo.primary_priority;
// Two possibilities why to construct militarysite here
if (!bf->defense_msite_allowed &&
- bf->nearest_buildable_spot_nearby < bo.desc->get_conquers() &&
+ (bf->nearest_buildable_spot_nearby < bo.desc->get_conquers() ||
+ bf->unowned_portspace_vicinity_nearby > 0) &&
(bf->military_in_constr_nearby + bf->military_unstationed) <
concurent_ms_in_constr_no_enemy) {
// it will conquer new buildable spots for buildings or mines
@@ -2811,7 +2803,7 @@
if (bf->is_portspace != ExtendedBool::kTrue && bo.is(BuildingAttribute::kPort)) {
continue;
}
- prio = bo.primary_priority;
+ prio += bo.primary_priority;
// iterating over current warehouses and testing a distance
// getting distance to nearest warehouse and adding it to a score
@@ -2849,7 +2841,7 @@
// Even if a site is forced it has kNeeded necessity now
assert(bo.primary_priority > 0 && bo.new_building == BuildingNecessity::kNeeded);
- prio = bo.primary_priority;
+ prio += bo.primary_priority;
// for spots close to a border
if (bf->near_border) {
@@ -2881,13 +2873,6 @@
continue;
}
- // testing also vicinity
- if (!bo.is(BuildingAttribute::kPort)) {
- if (port_reserved_coords.count(bf->coords.hash()) > 0) {
- continue;
- }
- }
-
// Prefer road side fields
prio += bf->preferred ? 5 : 0;
@@ -4244,28 +4229,51 @@
const uint32_t gametime) {
bo.primary_priority = 0;
- if (numof_warehouses_in_const_ > 0 ||
- bo.aimode_limit_status() != AiModeBuildings::kAnotherAllowed || !basic_economy_established) {
- bo.new_building_overdue = 0;
- bo.primary_priority = 0;
- return BuildingNecessity::kForbidden;
- }
-
+ // First there are situation when we cannot built the warehouse/port
+ // a) This is port and map is not seafaring one
if (bo.is(BuildingAttribute::kPort) && !map_allows_seafaring_) {
bo.new_building_overdue = 0;
- bo.primary_priority = 0;
- return BuildingNecessity::kForbidden;
- }
-
- bo.primary_priority = 0;
-
- // Build one warehouse for ~every 35 productionsites and mines_.
- // Militarysites are slightly important as well, to have a bigger
- // chance for a warehouses (containing waiting soldiers or wares
- // needed for soldier training) near the frontier.
- int32_t needed_count = static_cast<int32_t>(productionsites.size() + mines_.size()) /
- (40 + management_data.get_military_number_at(21) / 10) +
- 1;
+ return BuildingNecessity::kForbidden;
+ }
+
+ // b) the site is prohibited
+ if (bo.prohibited_till > gametime) {
+ bo.new_building_overdue = 0;
+ return BuildingNecessity::kForbidden;
+ }
+
+ // If this is a port and is the first bo be built
+ const bool first_port_allowed = (bo.is(BuildingAttribute::kPort) && bo.total_count() == 0);
+
+ // c) there are warehouses in construction (first port is exemption)
+ if (numof_warehouses_in_const_ > 0 && !first_port_allowed) {
+ bo.new_building_overdue = 0;
+ return BuildingNecessity::kForbidden;
+ }
+
+ // d) there is ai limit for this bulding
+ if (bo.aimode_limit_status() != AiModeBuildings::kAnotherAllowed) {
+ bo.new_building_overdue = 0;
+ return BuildingNecessity::kForbidden;
+ }
+
+ // e) basic economy not established, but first port is an exemption
+ if (!basic_economy_established && !first_port_allowed) {
+ bo.new_building_overdue = 0;
+ return BuildingNecessity::kForbidden;
+ }
+
+ // Number of needed warehouses decides if new one is needed and also
+ // converts to the score
+ int32_t needed_count = 0;
+ if (first_port_allowed) {
+ needed_count += numof_warehouses_ + numof_warehouses_in_const_ + 1;
+ } else {
+ needed_count += static_cast<int32_t>(productionsites.size() + mines_.size()) /
+ (40 + management_data.get_military_number_at(21) / 10) +
+ 1;
+ }
+
assert(needed_count >= 0 &&
needed_count <= (static_cast<uint16_t>(productionsites.size() + mines_.size()) / 10) + 2);
@@ -4275,22 +4283,27 @@
++needed_count;
}
- if (bo.is(BuildingAttribute::kPort) && (productionsites.size() + mines_.size()) > 10) {
+ // Port should always have higher score than a warehouse
+ if (bo.is(BuildingAttribute::kPort)) {
++needed_count;
}
+ // suppres a warehouse if not enough spots
+ if (spots_ < kSpotsEnough && !bo.is(BuildingAttribute::kPort)) {
+ --needed_count;
+ }
+
if (needed_count <= numof_warehouses_in_const_ + numof_warehouses_) {
bo.new_building_overdue = 0;
return BuildingNecessity::kForbidden;
}
// So now we know the warehouse here is needed.
- bo.primary_priority = 1 +
- (needed_count - numof_warehouses_in_const_ - numof_warehouses_) *
- std::abs(management_data.get_military_number_at(22));
+ bo.primary_priority = 1 + (needed_count - numof_warehouses_) *
+ std::abs(management_data.get_military_number_at(22) * 5);
++bo.new_building_overdue;
bo.primary_priority +=
- bo.new_building_overdue * std::abs(management_data.get_military_number_at(16)) / 40;
+ bo.new_building_overdue * std::abs(management_data.get_military_number_at(16)) / 10;
return BuildingNecessity::kAllowed;
}
@@ -4371,9 +4384,8 @@
// We build one trainig site per X military sites
// with some variations, of course
- int32_t target = 1 +
- static_cast<int32_t>(militarysites.size() + productionsites.size()) /
- (std::abs(management_data.get_military_number_at(113) / 2) + 1);
+ int32_t target = 1 + static_cast<int32_t>(militarysites.size() + productionsites.size()) /
+ (std::abs(management_data.get_military_number_at(113) / 2) + 1);
assert(target > 0 && target < 500);
uint16_t current_proportion = 0;
@@ -5390,6 +5402,7 @@
}
// counts buildings with the BuildingAttribute
+// Type of buildings, not individual buildings are meant
uint8_t DefaultAI::count_buildings_with_attribute(BuildingAttribute attribute) {
uint8_t count = 0;
if (tribe_ == nullptr) {
@@ -5750,15 +5763,6 @@
warehousesites.back().bo = &bo;
if (bo.is(BuildingAttribute::kPort)) {
++num_ports;
- // unblock nearby fields, might be used for other buildings...
- const Map& map = game().map();
- MapRegion<Area<FCoords>> mr(
- map, Area<FCoords>(map.get_fcoords(warehousesites.back().site->get_position()), 3));
- do {
- const int32_t hash = map.get_fcoords(*(mr.location().field)).hash();
- if (port_reserved_coords.count(hash) > 0)
- port_reserved_coords.erase(hash);
- } while (mr.advance(map));
}
}
}
=== modified file 'src/ai/defaultai.h'
--- src/ai/defaultai.h 2017-12-10 21:22:43 +0000
+++ src/ai/defaultai.h 2018-01-05 22:15:52 +0000
@@ -39,7 +39,7 @@
namespace Widelands {
struct Road;
struct Flag;
-}
+} // namespace Widelands
/**
* Default Widelands Computer Player (defaultAI)
@@ -305,10 +305,10 @@
std::deque<Widelands::FCoords> unusable_fields;
std::deque<Widelands::BuildableField*> buildable_fields;
Widelands::BlockedFields blocked_fields;
+ std::unordered_set<uint32_t> ports_vicinity;
Widelands::PlayersStrengths player_statistics;
Widelands::ManagementData management_data;
Widelands::ExpansionType expansion_type;
- std::unordered_set<uint32_t> port_reserved_coords;
std::deque<Widelands::MineableField*> mineable_fields;
std::deque<Widelands::Flag const*> new_flags;
std::deque<Widelands::Road const*> roads;
Follow ups
-
[Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
From: noreply, 2018-02-12
-
Re: [Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
From: GunChleoc, 2018-02-12
-
Re: [Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
From: TiborB, 2018-02-07
-
Re: [Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
From: GunChleoc, 2018-02-07
-
[Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
From: bunnybot, 2018-02-04
-
[Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
From: TiborB, 2018-02-03
-
Re: [Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
From: TiborB, 2018-02-03
-
Re: [Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
From: GunChleoc, 2018-02-03
-
Re: [Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
From: TiborB, 2018-02-02
-
[Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
From: bunnybot, 2018-01-31
-
Re: [Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
From: GunChleoc, 2018-01-31
-
[Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
From: bunnybot, 2018-01-31
-
Re: [Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
From: TiborB, 2018-01-30
-
Re: [Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
From: GunChleoc, 2018-01-30
-
Re: [Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
From: TiborB, 2018-01-29
-
Re: [Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
From: GunChleoc, 2018-01-29
-
Re: [Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
From: TiborB, 2018-01-28
-
Re: [Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
From: GunChleoc, 2018-01-26
-
Re: [Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
From: TiborB, 2018-01-16
-
Re: [Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
From: GunChleoc, 2018-01-16
-
Re: [Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
From: TiborB, 2018-01-16
-
Re: [Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
From: TiborB, 2018-01-16
-
Re: [Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
From: GunChleoc, 2018-01-16
-
Re: [Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
From: TiborB, 2018-01-16
-
Re: [Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
From: GunChleoc, 2018-01-16
-
[Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
From: bunnybot, 2018-01-07
-
[Merge] lp:~widelands-dev/widelands/ai_portspaces into lp:widelands
From: bunnybot, 2018-01-06