← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~widelands-dev/widelands/ai-building-necessity into lp:widelands

 

TiborB has proposed merging lp:~widelands-dev/widelands/ai-building-necessity into lp:widelands.

Requested reviews:
  Widelands Developers (widelands-dev)

For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/ai-building-necessity/+merge/268548

This is another AI-only fix. I changed the algorithm for calculation if a building is needed - used by construct_building() function and also for mines when considering if a mine without resources will be enhanced or dismantled. 

AI compares outputs of a building with actual stock amounts, and if below some treshold, the building is 'needed'.
-- 
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/ai-building-necessity into lp:widelands.
=== modified file 'src/ai/ai_help_structs.h'
--- src/ai/ai_help_structs.h	2015-07-27 20:25:32 +0000
+++ src/ai/ai_help_structs.h	2015-08-19 20:40:26 +0000
@@ -393,6 +393,13 @@
 
 	int16_t production_hint_;
 
+	// information needed for decision on new building construction
+	// these should be calculated only once during one run of construct_building()
+	// function
+	Widelands::ExtendedBool output_needed_;
+	int16_t max_preciousness;
+	int16_t max_needed_preciousness_;
+
 	int32_t cnt_built_;
 	int32_t cnt_under_construction_;
 	int32_t cnt_target_;  // number of buildings as target

=== modified file 'src/ai/defaultai.cc'
--- src/ai/defaultai.cc	2015-08-03 21:18:42 +0000
+++ src/ai/defaultai.cc	2015-08-19 20:40:26 +0000
@@ -437,6 +437,9 @@
 		bo.is_port_ = bld.get_isport();
 		bo.trainingsite_type_ = TrainingSiteType::kNoTS;
 		bo.upgrade_substitutes_ = false;
+		bo.output_needed_ = ExtendedBool::kUnset;
+		bo.max_preciousness = 0;
+		bo.max_needed_preciousness_ = 0;
 
 		if (bh.renews_map_resource()) {
 			bo.production_hint_ = tribe_->safe_ware_index(bh.get_renews_map_resource());
@@ -1409,10 +1412,13 @@
 		}
 	}
 
-	// these are 3 helping variables
-	bool output_is_needed = false;
-	int16_t max_preciousness = 0;         // preciousness_ of most precious output
-	int16_t max_needed_preciousness = 0;  // preciousness_ of most precious NEEDED output
+	//Resetting output_needed_ in building observer
+	for (uint32_t j = 0; j < buildings_.size(); ++j) {
+		BuildingObserver& bo = buildings_.at(j);
+		if (bo.type == BuildingObserver::PRODUCTIONSITE || bo.type == BuildingObserver::MINE){
+			bo.output_needed_ = ExtendedBool::kUnset;
+		}
+	}
 
 	// first scan all buildable fields for regular buildings
 	for (std::list<BuildableField*>::iterator i = buildable_fields.begin();
@@ -1488,10 +1494,6 @@
 				continue;
 			}
 
-			// so we are going to seriously evaluate this building on this field,
-			// first some base info - is its output needed at all?
-			check_ware_necessity(bo, &output_is_needed, &max_preciousness, &max_needed_preciousness);
-
 			int32_t prio = 0;  // score of a bulding on a field
 
 			if (bo.type == BuildingObserver::PRODUCTIONSITE) {
@@ -1501,6 +1503,12 @@
 					continue;
 				}
 
+				// this just indicates that values must be recalculated - if this building
+				// is to be considered later on in this function
+				if (bo.output_needed_ == ExtendedBool::kUnset) {
+					check_building_necessity(bo);
+				}
+
 				// this can be only a well (as by now)
 				if (bo.mines_water_) {
 					if (bf->ground_water_ < 2) {
@@ -1624,7 +1632,7 @@
 				} else if (bo.is_fisher_) {  // fisher
 
 					// ~are fishes needed?
-					if (max_needed_preciousness == 0) {
+					if (bo.max_needed_preciousness_ == 0) {
 						continue;
 					}
 
@@ -1638,7 +1646,7 @@
 
 					// we use preciousness to allow atlanteans to build the fishers huts
 					// atlanteans have preciousness 4, other tribes 3
-					if (max_needed_preciousness < 4 && new_buildings_stop_) {
+					if (bo.max_needed_preciousness_ < 4 && new_buildings_stop_) {
 						continue;
 					}
 
@@ -1757,7 +1765,7 @@
 					// generally we allow 1 building in construction, but if
 					// preciousness of missing ware is >=10 and it is farm-like building
 					// we allow 2 in construction
-					if (max_needed_preciousness >= 10
+					if (bo.max_needed_preciousness_ >= 10
 						&& bo.inputs_.empty()
 						&& gametime > 30 * 60 * 1000) {
 						if ((bo.cnt_under_construction_ + bo.unoccupied_) > 1) {
@@ -1779,7 +1787,7 @@
 						if (!seafaring_economy) {
 							continue;
 						}
-					} else if (!output_is_needed) {
+					} else if (bo.output_needed_ == ExtendedBool::kFalse) {
 						continue;
 					} else if ((bo.cnt_built_ - bo.unconnected_) == 0 &&
 					           game().get_gametime() > 40 * 60 * 1000) {
@@ -1792,7 +1800,7 @@
 					// we check separatelly buildings with no inputs and some inputs
 					if (bo.inputs_.empty()) {
 
-						prio += max_needed_preciousness + kDefaultPrioBoost;
+						prio += bo.max_needed_preciousness_ + kDefaultPrioBoost;
 
 						if (bo.space_consumer_) {  // need to consider trees nearby
 							prio += 20 - (bf->trees_nearby_ / 3);
@@ -1827,14 +1835,14 @@
 
 					} else if (!bo.inputs_.empty()) {
 						if ((bo.total_count() - bo.unconnected_ == 0)) {
-							prio += max_needed_preciousness + kDefaultPrioBoost;
+							prio += bo.max_needed_preciousness_ + kDefaultPrioBoost;
 						}
 						if ((bo.cnt_built_ - bo.unconnected_) > 0
 							&&
 							is_productionsite_needed(bo.outputs_.size(),
 													bo.current_stats_,
 													PerfEvaluation::kForConstruction)) {
-							prio += max_needed_preciousness + kDefaultPrioBoost - 3 +
+							prio += bo.max_needed_preciousness_ + kDefaultPrioBoost - 3 +
 							        (bo.current_stats_ - 55) / 8;
 						}
 					}
@@ -2228,12 +2236,14 @@
 					continue;
 				}
 
-				// testing if building's output is needed
-				check_ware_necessity(
-				   bo, &output_is_needed, &max_preciousness, &max_needed_preciousness);
+				if (bo.output_needed_ == ExtendedBool::kUnset) {
+					check_building_necessity(bo);
+				}
 
-				if (!output_is_needed && (bo.total_count() - bo.unconnected_) > 0) {
-					continue;
+				if (bo.output_needed_ == ExtendedBool::kFalse
+					&&
+				 	(bo.total_count() - bo.unconnected_) > 0) {
+						continue;
 				}
 
 				// if current one(s) are performing badly
@@ -2298,7 +2308,7 @@
 					prio += bonus_score;
 
 					// applying max needed
-					prio += max_needed_preciousness * 3;
+					prio += bo.max_needed_preciousness_ * 3;
 
 					// prefer mines in the middle of mine fields of the
 					// same type, so we add a small bonus here
@@ -3538,14 +3548,11 @@
 		return true;
 	}
 
-	// updating statistics if needed
-	if (site.bo->stocklevel_time < game().get_gametime() - 5 * 1000) {
-		site.bo->stocklevel_ = get_stocklevel_by_hint(site.bo->production_hint_);
-		site.bo->stocklevel_time = game().get_gametime();
-	}
+	// is output needed (compare stocked materials vs target values)
+	check_building_necessity(*site.bo);
 
-	// if we have enough of mined resources on stock - do not upgrade
-	if (site.bo->stocklevel_ > 150) {
+	// if we have enough of mined materials on stock - do not upgrade (yet)
+	if (site.bo->output_needed_ == ExtendedBool::kFalse) {
 		return false;
 	}
 
@@ -3601,39 +3608,39 @@
 	return count;
 }
 
-// calculating how much an output is needed
-// 'max' is because the building can have more outputs
-void DefaultAI::check_ware_necessity(BuildingObserver& bo,
-                                     bool* output_is_needed,
-                                     int16_t* max_preciousness,
-                                     int16_t* max_needed_preciousness) {
-
-	// resetting values
-	*output_is_needed = false;
-	*max_preciousness = 0;
-	*max_needed_preciousness = 0;
-
-	for (EconomyObserver* observer : economies) {
-		// Don't check if the economy has no warehouse.
-		if (observer->economy.warehouses().empty()) {
-			continue;
-		}
-
-		for (uint32_t m = 0; m < bo.outputs_.size(); ++m) {
-			WareIndex wt(static_cast<size_t>(bo.outputs_.at(m)));
-
-			if (observer->economy.needs_ware(wt)) {
-				*output_is_needed = true;
-
-				if (wares.at(bo.outputs_.at(m)).preciousness_ > *max_needed_preciousness) {
-					*max_needed_preciousness = wares.at(bo.outputs_.at(m)).preciousness_;
-				}
-			}
-
-			if (wares.at(bo.outputs_.at(m)).preciousness_ > *max_preciousness) {
-				*max_preciousness = wares.at(bo.outputs_.at(m)).preciousness_;
-			}
-		}
+// goes over all outputs of a building and compare stocked material with
+// target values. The result is yes/no and some scores
+void DefaultAI::check_building_necessity(BuildingObserver& bo) {
+	// iterate over outputs of building, counts warehoused stock
+	// and deciding if enough
+	bo.max_preciousness = 0;
+	bo.max_needed_preciousness_ = 0;
+
+	for (uint32_t m = 0; m < bo.outputs_.size(); ++m) {
+		WareIndex wt(static_cast<size_t>(bo.outputs_.at(m)));
+
+		uint16_t target = tribe_->get_ware_descr(wt)->default_target_quantity() / 3;
+		// at least  1
+		target = std::max<uint16_t>(target, 1);
+
+		uint16_t preciousness = wares.at(bo.outputs_.at(m)).preciousness_;
+
+		if (get_warehoused_stock(wt) < target) {
+			if (bo.max_needed_preciousness_ < preciousness) {
+				bo.max_needed_preciousness_ = preciousness;
+			}
+		}
+
+		if (bo.max_preciousness < preciousness) {
+			bo.max_preciousness = preciousness;
+		}
+	}
+
+	// here we decide if the building is needed
+	if (bo.max_needed_preciousness_ > 0) {
+		bo.output_needed_ = ExtendedBool::kTrue;
+	} else {
+		bo.output_needed_ = ExtendedBool::kFalse;
 	}
 }
 

=== modified file 'src/ai/defaultai.h'
--- src/ai/defaultai.h	2015-07-27 20:25:32 +0000
+++ src/ai/defaultai.h	2015-08-19 20:40:26 +0000
@@ -169,10 +169,7 @@
 
 	void update_productionsite_stats(uint32_t);
 
-	void check_ware_necessity(BuildingObserver& bo,
-	                          bool* output_is_needed,
-	                          int16_t* max_preciousness,
-	                          int16_t* max_needed_preciousness);
+	void check_building_necessity(BuildingObserver& bo);
 
 	ScheduleTasks get_oldest_task(uint32_t);
 

=== modified file 'tribes/empire/grape/conf'
--- tribes/empire/grape/conf	2014-10-01 18:50:06 +0000
+++ tribes/empire/grape/conf	2015-08-19 20:40:26 +0000
@@ -1,7 +1,7 @@
 help=_These grapes are the base for a tasty wine. They are harvested in a vineyard and processed in a winery.
 
 default_target_quantity=20 # currently not used
-preciousness=9
+preciousness=10
 
 [idle]
 pics=grape_idle.png


Follow ups