widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #12888
[Merge] lp:~widelands-dev/widelands/ai_mineable_fields into lp:widelands
TiborB has proposed merging lp:~widelands-dev/widelands/ai_mineable_fields into lp:widelands.
Requested reviews:
Widelands Developers (widelands-dev)
For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/ai_mineable_fields/+merge/342006
Changes in AI - related to mining
- AI now calculates count of available mineable spots per resource
- for above it distinguishes critical ores (iron + granite if output of mine is used for building)
- fixed stupid bug with iron_ore_id which contained index of iron ore as ware, but was used as index of iron as underground resource
- few changes in GA (so some training will be needed afterwards)
--
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/ai_mineable_fields into lp:widelands.
=== modified file 'src/ai/ai_help_structs.cc'
--- src/ai/ai_help_structs.cc 2018-02-16 20:42:21 +0000
+++ src/ai/ai_help_structs.cc 2018-03-23 20:35:11 +0000
@@ -335,6 +335,52 @@
: in_construction(0), finished(0), is_critical(false), unoccupied(0) {
}
+// Reset counter for all field types
+void MineFieldsObserver::zero() {
+ for (auto& material : stat) {
+ material.second = 0;
+ }
+}
+
+// Increase counter by one for specific ore/minefield type
+void MineFieldsObserver::add(const Widelands::DescriptionIndex idx) {
+ stat[idx] += 1;
+}
+
+// Add ore into critical_ores
+void MineFieldsObserver::add_critical_ore(const Widelands::DescriptionIndex idx) {
+ critical_ores.insert(idx);
+}
+
+// Does the player has at least one mineable field with positive amount for each critical ore?
+bool MineFieldsObserver::has_critical_ore_fields() {
+ for (auto ore : critical_ores) {
+ if (get(ore) == 0) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// Returns count of fields with desired ore
+uint16_t MineFieldsObserver::get(const Widelands::DescriptionIndex idx) {
+ if (stat.count(idx) == 0) {
+ return 0;
+ }
+ return stat[idx];
+}
+
+// Count of types of mineable fields, up to 4 currently
+uint8_t MineFieldsObserver::count_types() {
+ uint16_t count = 0;
+ for (auto material : stat) {
+ if (material.second > 0) {
+ count += 1;
+ }
+ }
+ return count;
+}
+
ExpansionType::ExpansionType() {
type = ExpansionMode::kResources;
}
=== modified file 'src/ai/ai_help_structs.h'
--- src/ai/ai_help_structs.h 2018-02-16 21:04:59 +0000
+++ src/ai/ai_help_structs.h 2018-03-23 20:35:11 +0000
@@ -556,6 +556,22 @@
uint16_t unoccupied;
};
+// This struct contains count of mineable fields grouped by ore/resource type
+struct MineFieldsObserver {
+
+ void zero();
+ void add(Widelands::DescriptionIndex);
+ void add_critical_ore(Widelands::DescriptionIndex);
+ bool has_critical_ore_fields();
+ uint16_t get(Widelands::DescriptionIndex);
+ uint8_t count_types();
+
+private:
+ // This is the central information of the struct: a pair of resource and count of fields
+ std::map<Widelands::DescriptionIndex, uint16_t> stat;
+ std::set<Widelands::DescriptionIndex> critical_ores;
+};
+
constexpr int kNeuronWeightLimit = 100;
constexpr size_t kNeuronMaxPosition = 20;
constexpr size_t kSecondParentProbability = 50;
=== modified file 'src/ai/defaultai.cc'
--- src/ai/defaultai.cc 2018-03-02 07:50:34 +0000
+++ src/ai/defaultai.cc 2018-03-23 20:35:11 +0000
@@ -695,7 +695,8 @@
bo.set_is(BuildingAttribute::kSupportingProducer);
}
- iron_ore_id = tribe_->ironore();
+ iron_resource_id = game().world().get_resource("iron");
+ assert (iron_resource_id != INVALID_INDEX);
if (bo.type == BuildingObserver::Type::kMine) {
// get the resource needed by the mine
@@ -710,9 +711,10 @@
mines_per_type[bo.mines] = MineTypesObserver();
}
// Identify iron mines based on output
- if (bo.outputs[0] == iron_ore_id) {
+ if (bo.outputs[0] == tribe_->ironore()) {
bo.set_is(BuildingAttribute::kIronMine);
mines_per_type[bo.mines].is_critical = true;
+ mine_fields_stat.add_critical_ore(bo.mines);
}
}
@@ -782,8 +784,8 @@
!(ware == tribe_->rawlog() || ware == tribe_->granite())) {
bo.set_is(BuildingAttribute::kBuildingMatProducer);
if (bo.type == BuildingObserver::Type::kMine) {
- has_critical_mines = true;
mines_per_type[bo.mines].is_critical = true;
+ mine_fields_stat.add_critical_ore(bo.mines);
}
}
}
@@ -1035,9 +1037,6 @@
persistent_data->expedition_start_time = gametime;
}
- // just to be sure we have iron mines identified
- assert(iron_ore_id != INVALID_INDEX);
-
productionsites_ratio_ = management_data.get_military_number_at(86) / 10 + 12;
// Just to be initialized
@@ -1212,6 +1211,21 @@
i += 1;
}
+ // Updating overall statistics, first we flush the data and then iterate over all mine fields
+ mine_fields_stat.zero();
+ for (uint32_t j = 0; j < mineable_fields.size(); j++) {
+ if (mineable_fields[j]->coords.field->get_resources_amount() > 0) {
+ mine_fields_stat.add(mineable_fields[j]->coords.field->get_resources());
+ }
+ }
+
+ // Following asserts presume that there is 1-3 critical mines
+ if (mine_fields_stat.count_types() == 4) {
+ assert(mine_fields_stat.has_critical_ore_fields());
+ }
+ if (mine_fields_stat.count_types() == 0) {
+ assert(!mine_fields_stat.has_critical_ore_fields());
+ }
}
/**
@@ -1267,7 +1281,7 @@
FindEnemyNodeWalkable find_enemy_owned_walkable(player_, game());
FindNodeUnownedBuildable find_unowned_buildable(player_, game());
FindNodeUnownedMineable find_unowned_mines_pots(player_, game());
- FindNodeUnownedMineable find_unowned_iron_mines(player_, game(), iron_ore_id);
+ FindNodeUnownedMineable find_unowned_iron_mines(player_, game(), iron_resource_id);
FindNodeAllyOwned find_ally(player_, game(), player_number());
PlayerNumber const pn = player_->player_number();
const World& world = game().world();
@@ -1363,7 +1377,7 @@
if (field.unowned_mines_spots_nearby > 0 &&
// for performance considerations we count iron nodes only if we have less than 2 iron
// mines now...
- (mines_per_type[iron_ore_id].in_construction + mines_per_type[iron_ore_id].finished) <=
+ (mines_per_type[iron_resource_id].in_construction + mines_per_type[iron_resource_id].finished) <=
1) {
// counting iron mines, if we have less than two iron mines
field.unowned_iron_mines_nearby = map.find_fields(
@@ -1700,7 +1714,7 @@
field.inland = true;
}
- const uint8_t score_parts_size = 64;
+ const uint8_t score_parts_size = 69;
int32_t score_parts[score_parts_size] = {0};
if (field.enemy_owned_land_nearby) {
score_parts[0] = 3 *
@@ -1755,7 +1769,7 @@
(field.enemy_nearby) ? 3 * std::abs(management_data.get_military_number_at(68)) : 0;
score_parts[19] =
(field.enemy_wh_nearby) ? 3 * std::abs(management_data.get_military_number_at(132)) : 0;
- score_parts[58] = (field.enemy_wh_nearby) ?
+ score_parts[64] = (field.enemy_wh_nearby) ?
std::abs(management_data.get_military_number_at(135)) :
-std::abs(management_data.get_military_number_at(135));
@@ -1825,18 +1839,18 @@
}
if (msites_in_constr() > 0 && field.max_buildcap_nearby == BUILDCAPS_BIG &&
spots_avail.at(BUILDCAPS_BIG) <= 2) {
- score_parts[57] = -10 * std::abs(management_data.get_military_number_at(54));
+ score_parts[65] = -10 * std::abs(management_data.get_military_number_at(54));
}
}
// common inputs
- if (field.unowned_iron_mines_nearby > 0 && ((mines_per_type[iron_ore_id].in_construction +
- mines_per_type[iron_ore_id].finished) == 0)) {
+ if (field.unowned_iron_mines_nearby > 0 && ((mines_per_type[iron_resource_id].in_construction +
+ mines_per_type[iron_resource_id].finished) == 0)) {
score_parts[40] = field.unowned_iron_mines_nearby *
std::abs(management_data.get_military_number_at(92)) / 50;
}
- if (field.unowned_iron_mines_nearby && ((mines_per_type[iron_ore_id].in_construction +
- mines_per_type[iron_ore_id].finished) <= 1)) {
+ if (field.unowned_iron_mines_nearby && ((mines_per_type[iron_resource_id].in_construction +
+ mines_per_type[iron_resource_id].finished) <= 1)) {
score_parts[41] = 3 * std::abs(management_data.get_military_number_at(93));
}
@@ -1892,6 +1906,16 @@
score_parts[63] = (field.nearest_buildable_spot_nearby < 4) ?
std::abs(management_data.get_military_number_at(155) * 2) :
0;
+ // 64 and 65 are used above
+ score_parts[66] = (field.unowned_mines_spots_nearby > 0 && !mine_fields_stat.has_critical_ore_fields()) ?
+ std::abs(management_data.get_military_number_at(157)) :
+ 0;
+ score_parts[67] = (field.unowned_mines_spots_nearby > 0 && mine_fields_stat.count_types() <= 4 ) ?
+ std::abs(management_data.get_military_number_at(158)) :
+ 0;
+ score_parts[68] = (field.unowned_mines_spots_nearby == 0 && mine_fields_stat.count_types() <= 4 ) ?
+ -std::abs(management_data.get_military_number_at(159)) :
+ 0;
for (uint16_t i = 0; i < score_parts_size; i++) {
field.military_score_ += score_parts[i];
@@ -2218,6 +2242,12 @@
inputs[50] = (bakeries_count_ <= 1);
inputs[51] = (numof_psites_in_constr > 8);
inputs[52] = (numof_psites_in_constr < 8);
+ inputs[53] = (mine_fields_stat.has_critical_ore_fields());
+ inputs[54] = (!mine_fields_stat.has_critical_ore_fields());
+ inputs[55] = (mine_fields_stat.count_types() == 4);
+ inputs[56] = (mine_fields_stat.count_types() != 4);
+ inputs[57] = (mine_fields_stat.has_critical_ore_fields());
+ inputs[58] = (!mine_fields_stat.has_critical_ore_fields());
static int16_t needs_boost_economy_score = management_data.get_military_number_at(61) / 5;
needs_boost_economy_score = management_data.get_military_number_at(61) / 5;
@@ -2240,12 +2270,10 @@
}
// Finding expansion policy
- // Do we need basic resources?
- // This is a replacement for simple count of mines
- const int32_t virtual_mines = mines_.size() + mineable_fields.size() / 15;
+ // Do we need basic resources? Do we have basic mines?
const bool needs_fishers = resource_necessity_water_needed_ && fishers_count_ < 1;
- if (virtual_mines < 4 || mines_per_type[iron_ore_id].total_count() < 1 || needs_fishers) {
+ if (!mine_fields_stat.has_critical_ore_fields() || mines_per_type[iron_resource_id].total_count() < 1 || needs_fishers) {
expansion_type.set_expantion_type(ExpansionMode::kResources);
} else {
// now we must decide if we go after spots or economy boost
@@ -2976,10 +3004,6 @@
prio -= 5;
}
- // be should rather have some mines
- if (virtual_mines < 6) {
- prio -= (6 - virtual_mines) * 7;
- }
// take care about borders and enemies
if (bf->enemy_nearby) {
@@ -4402,7 +4426,7 @@
// Single _critical is a critical mine if it is the only one of its type, so it needs special
// treatment
bool single_critical = false;
- if ((site.bo->is(BuildingAttribute::kBuildingMatProducer) || site.bo->mines == iron_ore_id) &&
+ if ((site.bo->is(BuildingAttribute::kBuildingMatProducer) || site.bo->mines == iron_resource_id) &&
mines_per_type[site.bo->mines].total_count() == 1) {
single_critical = true;
}
@@ -4680,6 +4704,11 @@
bo.primary_priority += std::abs(management_data.get_military_number_at(57) / 2);
}
+ // Do we own some minefields for each critical mine
+ if (!mine_fields_stat.has_critical_ore_fields()) {
+ bo.primary_priority -= std::abs(management_data.get_military_number_at(156));
+ }
+
// We build one trainig site per X military sites
// with some variations, of course
int32_t target = 1 +
@@ -5015,17 +5044,17 @@
}
inputs[31] = (persistent_data->trees_around_cutters < 100) * 2;
inputs[32] = (persistent_data->trees_around_cutters < 200) * 2;
- inputs[33] = ((mines_per_type[iron_ore_id].in_construction +
- mines_per_type[iron_ore_id].finished) <= 1) *
- -1;
- inputs[34] = ((mines_per_type[iron_ore_id].in_construction +
- mines_per_type[iron_ore_id].finished) <= 1) *
- -1;
- inputs[35] = ((mines_per_type[iron_ore_id].in_construction +
- mines_per_type[iron_ore_id].finished) == 0) *
- -1;
- inputs[36] = ((mines_per_type[iron_ore_id].in_construction +
- mines_per_type[iron_ore_id].finished) == 0) *
+ inputs[33] = ((mines_per_type[iron_resource_id].in_construction +
+ mines_per_type[iron_resource_id].finished) <= 1) *
+ -1;
+ inputs[34] = ((mines_per_type[iron_resource_id].in_construction +
+ mines_per_type[iron_resource_id].finished) <= 1) *
+ -1;
+ inputs[35] = ((mines_per_type[iron_resource_id].in_construction +
+ mines_per_type[iron_resource_id].finished) == 0) *
+ -1;
+ inputs[36] = ((mines_per_type[iron_resource_id].in_construction +
+ mines_per_type[iron_resource_id].finished) == 0) *
-1;
inputs[37] = -1;
inputs[38] = -1;
@@ -5164,7 +5193,7 @@
int16_t tmp_score = 1;
tmp_score +=
- mines_per_type[iron_ore_id].in_construction + mines_per_type[iron_ore_id].finished;
+ mines_per_type[iron_resource_id].in_construction + mines_per_type[iron_resource_id].finished;
tmp_score += (soldier_status_ == SoldiersStatus::kBadShortage) * 2;
tmp_score += (soldier_status_ == SoldiersStatus::kShortage) * 2;
tmp_score += (gametime / 60 / 1000 - 20) / 4;
@@ -5225,7 +5254,7 @@
(mines_per_type[bo.mines].in_construction + mines_per_type[bo.mines].finished == 1) ?
2 :
0;
- inputs[5] = (bo.mines == iron_ore_id) ? 2 : 1;
+ inputs[5] = (bo.mines == iron_resource_id) ? 2 : 1;
inputs[6] = (bo.current_stats - 50) / 10;
inputs[7] = (gametime < 15 * 60 * 1000) ? -1 : 0;
inputs[8] = (gametime < 30 * 60 * 1000) ? -1 : 0;
@@ -5238,7 +5267,7 @@
(mines_per_type[bo.mines].in_construction + mines_per_type[bo.mines].finished == 1) ?
1 :
0;
- inputs[12] = (bo.mines == iron_ore_id) ? 2 : 0;
+ inputs[12] = (bo.mines == iron_resource_id) ? 2 : 0;
inputs[13] = (bo.current_stats - 50) / 10;
inputs[14] = (bo.current_stats - 50) / 10;
inputs[15] = management_data.get_military_number_at(123) / 10;
=== modified file 'src/ai/defaultai.h'
--- src/ai/defaultai.h 2018-02-20 21:11:27 +0000
+++ src/ai/defaultai.h 2018-03-23 20:35:11 +0000
@@ -287,6 +287,7 @@
Widelands::BuildingNecessity check_building_necessity(Widelands::BuildingObserver&, uint32_t);
void soldier_trained(const Widelands::TrainingSite&);
bool critical_mine_unoccupied(uint32_t);
+
SoldiersStatus soldier_status_;
int32_t vacant_mil_positions_average_;
uint16_t attackers_count_;
@@ -330,6 +331,8 @@
// it will map mined material to observer
std::map<int32_t, Widelands::MineTypesObserver> mines_per_type;
std::vector<uint32_t> spots_avail;
+ Widelands::MineFieldsObserver mine_fields_stat;
+
// used for statistics of buildings
uint32_t numof_psites_in_constr;
@@ -377,8 +380,8 @@
// buildings
bool basic_economy_established;
- // id of iron_ore to identify iron mines in mines_per_type map
- int32_t iron_ore_id = Widelands::INVALID_INDEX;
+ // id of iron as resource to identify iron mines in mines_per_type map
+ int32_t iron_resource_id = Widelands::INVALID_INDEX;
// this is a bunch of patterns that have to identify weapons and armors for input queues of
// trainingsites
@@ -398,7 +401,6 @@
std::vector<std::vector<int16_t>> AI_military_matrix;
std::vector<int16_t> AI_military_numbers;
- bool has_critical_mines = false;
uint16_t buil_material_mines_count = 0;
bool ai_training_mode_ = false;
=== modified file 'src/ai/defaultai_warfare.cc'
--- src/ai/defaultai_warfare.cc 2018-02-15 20:31:17 +0000
+++ src/ai/defaultai_warfare.cc 2018-03-23 20:35:11 +0000
@@ -322,8 +322,8 @@
inputs[27] = (ts_finished_count_ - ts_without_trainers_) * 2;
inputs[28] = general_score * 3;
inputs[29] = general_score;
- inputs[30] = ((mines_per_type[iron_ore_id].in_construction +
- mines_per_type[iron_ore_id].finished) > 0) ?
+ inputs[30] = ((mines_per_type[iron_resource_id].in_construction +
+ mines_per_type[iron_resource_id].finished) > 0) ?
1 :
-1;
inputs[31] = (player_statistics.get_player_power(pn) >
@@ -682,7 +682,7 @@
1 :
0;
inputs[2] = (mines_.size() < 3) ? -1 : 0;
- inputs[3] = (mines_per_type[iron_ore_id].total_count() == 0) ? -1 : 0;
+ inputs[3] = (mines_per_type[iron_resource_id].total_count() == 0) ? -1 : 0;
inputs[4] = (player_statistics.get_player_power(pn) * 2 >
player_statistics.get_visible_enemies_power(gametime)) ?
-1 :
@@ -1006,7 +1006,7 @@
inputs[12] = (scores[size - 1] > total_score / 3) ? -2 : 0;
inputs[13] =
(player_statistics.get_enemies_max_land() < player_statistics.get_player_land(pn)) ? -1 : 0;
- inputs[14] = (mines_per_type[iron_ore_id].total_count() == 0) ? +1 : 0;
+ inputs[14] = (mines_per_type[iron_resource_id].total_count() == 0) ? +1 : 0;
inputs[15] = (spots_ < kSpotsTooLittle) ? +1 : 0;
inputs[16] = +1;
inputs[17] = +2;
@@ -1121,11 +1121,11 @@
inputs[57] =
player_statistics.any_enemy_seen_lately(gametime) && (spots_ < kSpotsTooLittle) ? +2 : 0;
inputs[58] =
- ((mines_per_type[iron_ore_id].in_construction + mines_per_type[iron_ore_id].finished) == 0) ?
+ ((mines_per_type[iron_resource_id].in_construction + mines_per_type[iron_resource_id].finished) == 0) ?
+3 :
0;
inputs[59] =
- ((mines_per_type[iron_ore_id].in_construction + mines_per_type[iron_ore_id].finished) == 0) ?
+ ((mines_per_type[iron_resource_id].in_construction + mines_per_type[iron_resource_id].finished) == 0) ?
+1 :
0;
inputs[60] = (expansion_type.get_expansion_type() == ExpansionMode::kEconomy) ? -2 : 0;
@@ -1238,12 +1238,22 @@
inputs[114] = -10;
}
+ if (!mine_fields_stat.has_critical_ore_fields()) {
+ inputs[115] = -3;
+ inputs[116] = -6;
+ inputs[117] = -8;
+ }
+ inputs[118] = -mine_fields_stat.count_types();
+ inputs[119] = -mine_fields_stat.count_types() * 3;
+
+
for (int i = 0; i < 4 * kFNeuronBitSize; i = i + 1) {
if (inputs[i] < -35 || inputs[i] > 6) {
log("Warning check_building_necessity score on position %2d too high %2d\n", i, inputs[i]);
}
}
+
int32_t final_score = 0;
for (int i = 0; i < kFNeuronBitSize; i = i + 1) {
if (management_data.f_neuron_pool[56].get_position(i)) {
Follow ups
-
[Merge] lp:~widelands-dev/widelands/ai_mineable_fields into lp:widelands
From: noreply, 2018-03-27
-
Re: [Merge] lp:~widelands-dev/widelands/ai_mineable_fields into lp:widelands
From: TiborB, 2018-03-27
-
[Merge] lp:~widelands-dev/widelands/ai_mineable_fields into lp:widelands
From: bunnybot, 2018-03-26
-
Re: [Merge] lp:~widelands-dev/widelands/ai_mineable_fields into lp:widelands
From: TiborB, 2018-03-26
-
Re: [Merge] lp:~widelands-dev/widelands/ai_mineable_fields into lp:widelands
From: TiborB, 2018-03-26
-
[Merge] lp:~widelands-dev/widelands/ai_mineable_fields into lp:widelands
From: TiborB, 2018-03-26
-
Re: [Merge] lp:~widelands-dev/widelands/ai_mineable_fields into lp:widelands
From: GunChleoc, 2018-03-26
-
Re: [Merge] lp:~widelands-dev/widelands/ai_mineable_fields into lp:widelands
From: TiborB, 2018-03-25
-
Re: [Merge] lp:~widelands-dev/widelands/ai_mineable_fields into lp:widelands
From: GunChleoc, 2018-03-25
-
[Merge] lp:~widelands-dev/widelands/ai_mineable_fields into lp:widelands
From: bunnybot, 2018-03-24