← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~widelands-dev/widelands/ai_upgrading_reworked into lp:widelands

 

TiborB has proposed merging lp:~widelands-dev/widelands/ai_upgrading_reworked into lp:widelands.

Requested reviews:
  Widelands Developers (widelands-dev)

For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/ai_upgrading_reworked/+merge/287229

Redesigned logic of upgrading of the productionsites. AI now waits untill all wares are sent away from productionsite and then it upgrades. Also other small changes..
-- 
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/ai_upgrading_reworked into lp:widelands.
=== modified file 'src/ai/ai_help_structs.h'
--- src/ai/ai_help_structs.h	2016-02-22 08:50:04 +0000
+++ src/ai/ai_help_structs.h	2016-02-25 21:06:10 +0000
@@ -368,6 +368,8 @@
 	int32_t cnt_target;  // number of buildings as target
 	int32_t cnt_limit_by_aimode; // limit imposed by weak or normal AI mode
 
+	int32_t cnt_upgrade_pending; //number of buildings that are to be upgraded
+
 	// used to track amount of wares produced by building
 	uint32_t stocklevel;
 	uint32_t stocklevel_time;  // time when stocklevel_ was last time recalculated
@@ -388,6 +390,7 @@
 	uint32_t unoccupied_till;
 	uint8_t stats_zero;
 	uint32_t no_resources_since;
+	bool upgrade_pending;
 	BuildingObserver* bo;
 };
 

=== modified file 'src/ai/defaultai.cc'
--- src/ai/defaultai.cc	2016-02-22 08:50:04 +0000
+++ src/ai/defaultai.cc	2016-02-25 21:06:10 +0000
@@ -477,7 +477,10 @@
 	tribe_ = &player_->tribe();
 	const uint32_t gametime = game().get_gametime();
 
-	log("ComputerPlayer(%d): initializing (%u)\n", player_number(), static_cast<unsigned int>(type_));
+	log("ComputerPlayer(%d): initializing as type %u\n", player_number(), static_cast<unsigned int>(type_));
+	if (player_->team_number() > 0) {
+		log ("    ... member of team %d\n", player_->team_number());
+	}
 
 	wares.resize(game().tribes().nrwares());
 	for (DescriptionIndex i = 0; i < static_cast<DescriptionIndex>(game().tribes().nrwares()); ++i) {
@@ -508,6 +511,7 @@
 		bo.cnt_under_construction = 0;
 		bo.cnt_target = 1;  // default for everything
 		bo.cnt_limit_by_aimode = std::numeric_limits<int32_t>::max();
+		bo.cnt_upgrade_pending = 0;
 		bo.stocklevel = 0;
 		bo.stocklevel_time = 0;
 		bo.last_dismantle_time = 0;
@@ -824,7 +828,7 @@
 				//  Guard by a set - immovables might be on several nodes at once.
 				if (&imm->owner() == player_ && !found_immovables.count(imm)) {
 					found_immovables.insert(imm);
-					gain_immovable(*imm);
+					gain_immovable(*imm, true);
 				}
 			}
 		}
@@ -3114,74 +3118,130 @@
 
 	Map& map = game().map();
 
-	// first we try to upgrade
-	// Upgrading policy
-	// a) if there are two buildings and none enhanced and there are workers
-	// available, one is to be enhanced
-	// b) if there are two buildings
-	// statistics percents are decisive
-	// c) yet there are buildings that might be upgraded, even when
-	// there is no second buiding of the kind (flag upgrade_substitutes)
+	// The code here is bit complicated
+	// a) Either this site is pending for upgrade, if ready, order the upgrade
+	// b) other site of type is pending for upgrade
+	// c) if none of above, we can consider upgrade of this one
 
 	const DescriptionIndex enhancement = site.site->descr().enhancement();
-	if (connected_to_wh && enhancement != INVALID_INDEX &&
-		// if upgrade does not subsitute, we need to have two buildings at least
-		((site.bo->cnt_built - site.bo->unoccupied_count > 1 && site.bo->upgrade_extends)
-		||
-		site.bo->upgrade_substitutes) &&
-	    gametime > 45 * 60 * 1000 &&
-	    gametime > site.built_time + 20 * 60 * 1000) {
-
-		// Only enhance buildings that are allowed (scenario mode)
-		// do not do decisions too fast
-		if (player_->is_building_type_allowed(enhancement)) {
-
-			const BuildingDescr& bld = *tribe_->get_building_descr(enhancement);
-			BuildingObserver& en_bo = get_building_observer(bld.name().c_str());
-			bool doing_upgrade = false;
-
-			if (gametime - en_bo.construction_decision_time >= 10 * 60 * 1000 &&
-			    (en_bo.cnt_under_construction + en_bo.unoccupied_count) == 0) {
-
-				// don't upgrade without workers
-				if (site.site->has_workers(enhancement, game())) {
-
-					// forcing first upgrade
-					if (en_bo.total_count() == 0) {
+
+	bool considering_upgrade = enhancement != INVALID_INDEX;
+
+	// First we check for rare case when input wares are set to 0 but AI is not aware that
+	// the site is pending for upgrade - one possible cause is this is a fresly loaded game
+	if (!site.upgrade_pending) {
+		bool resseting_wares = false;
+		for (auto& queue : site.site->warequeues()) {
+			if (queue->get_max_fill() == 0) {
+				resseting_wares = true;
+				game().send_player_set_ware_max_fill(*site.site, queue->get_ware(), queue->get_max_size());
+			}
+		}
+		if (resseting_wares) {
+			log(" %d: AI: input queues resettted to max for %s (game just loaded?)\n",
+			player_number(),
+			site.bo->name);
+			return true;
+		}
+	}
+
+	if (site.upgrade_pending) {
+		// The site is in process of emptying its input queues
+		// Counting remaining wares in the site now
+		int32_t left_wares = 0;
+		for (auto& queue : site.site->warequeues()) {
+			left_wares += queue->get_filled();
+		}
+		//do nothing when some wares are left, but do not wait more then 4 minutes
+		if (site.bo->construction_decision_time + 4 * 60 * 1000 > gametime && left_wares > 0) {
+			return false;
+		}
+		assert (site.bo->cnt_upgrade_pending == 1);
+		assert(enhancement != INVALID_INDEX);
+		game().send_player_enhance_building(*site.site, enhancement);
+		considering_upgrade = false;
+		return true;
+	} else if (site.bo->cnt_upgrade_pending > 0) {
+		// some other site of this type is in pending for upgrade
+		assert (site.bo->cnt_upgrade_pending == 1);
+		return false;
+	}
+	assert (site.bo->cnt_upgrade_pending == 0);
+
+	// Of course type of productionsite must be allowed
+	if (considering_upgrade && !player_->is_building_type_allowed(enhancement)) {
+		considering_upgrade = false;
+	}
+
+	// Site must be connected to warehouse
+	if (considering_upgrade && !connected_to_wh) {
+		considering_upgrade = false;
+	}
+
+	// if upgraded building produces another wares we are willing to upgrade it sooner
+	if (considering_upgrade) {
+		if (site.bo->upgrade_extends) {
+			// if upgrade produces new outputs, we force first upgrade
+			if (gametime < site.built_time + 10 * 60 * 1000) {
+				considering_upgrade = false;
+			}
+		} else {
+			if (gametime < 45 * 60 * 1000 || gametime < site.built_time + 20 * 60 * 1000) {
+				considering_upgrade = false;
+			}
+		}
+	}
+
+	// No upgrade without proper workers
+	if (considering_upgrade && !site.site->has_workers(enhancement, game())) {
+		considering_upgrade = false;
+	}
+
+	if (considering_upgrade) {
+
+		const BuildingDescr& bld = *tribe_->get_building_descr(enhancement);
+		BuildingObserver& en_bo = get_building_observer(bld.name().c_str());
+		bool doing_upgrade = false;
+
+		// 10 minutes is a time to productions statics to settle
+		if ((en_bo.last_building_built == kNever || gametime - en_bo.last_building_built >= 10 * 60 * 1000) &&
+		    (en_bo.cnt_under_construction + en_bo.unoccupied_count) == 0) {
+
+			// forcing first upgrade
+			if (en_bo.total_count() == 0) {
+				doing_upgrade = true;
+			}
+
+			if (en_bo.total_count() == 1) {
+				if (en_bo.current_stats > 55) {
+					doing_upgrade = true;
+				}
+			}
+
+			if (en_bo.total_count() > 1) {
+				if (en_bo.current_stats > 75) {
 						doing_upgrade = true;
-					}
-
-					if (en_bo.total_count() == 1) {
-						//if the upgrade itself can be upgraded futher, we are more willing to upgrade 2nd building
-						if (en_bo.upgrade_extends || en_bo.upgrade_substitutes) {
-							if (en_bo.current_stats > 30) {
-								doing_upgrade = true;
-							}
-						} else if (en_bo.current_stats > 50) {
-							doing_upgrade = true;
-						}
-					}
-
-					if (en_bo.total_count() > 1) {
-						if (en_bo.current_stats > 80) {
-								doing_upgrade = true;
-						}
-					}
-
-					// Dont forget about limitation of number of buildings
-					if (en_bo.cnt_limit_by_aimode <= en_bo.total_count() - en_bo.unconnected_count) {
-						doing_upgrade = false;
-					}
 				}
 			}
 
-			// Enhance if enhanced building is useful
-			// additional: we dont want to lose the old building
-			if (doing_upgrade) {
-				game().send_player_enhance_building(*site.site, enhancement);
-				en_bo.construction_decision_time = gametime;
-				return true;
-			}
+			// Dont forget about limitation of number of buildings
+			if (en_bo.aimode_limit_status() != AiModeBuildings::kAnotherAllowed) {
+				doing_upgrade = false;
+			}
+		}
+
+		// Here we just restrict input wares to 0 and set flag 'upgrade_pending' to true
+		if (doing_upgrade) {
+
+			// reducing input queues
+			for (auto& queue : site.site->warequeues()) {
+				game().send_player_set_ware_max_fill(*site.site, queue->get_ware(), 0);
+			}
+			site.bo->construction_decision_time = gametime;
+			en_bo.construction_decision_time = gametime;
+			site.upgrade_pending = true;
+			site.bo->cnt_upgrade_pending += 1;
+			return true;
 		}
 	}
 
@@ -4656,9 +4716,9 @@
 }
 
 // this is called whenever we gain ownership of a PlayerImmovable
-void DefaultAI::gain_immovable(PlayerImmovable& pi) {
+void DefaultAI::gain_immovable(PlayerImmovable& pi, const bool found_on_load) {
 	if (upcast(Building, building, &pi)) {
-		gain_building(*building);
+		gain_building(*building, found_on_load);
 	} else if (upcast(Flag const, flag, &pi)) {
 		new_flags.push_back(flag);
 	} else if (upcast(Road const, road, &pi)) {
@@ -5012,7 +5072,7 @@
 }
 
 // this is called whenever we gain a new building
-void DefaultAI::gain_building(Building& b) {
+void DefaultAI::gain_building(Building& b, const bool found_on_load) {
 
 	BuildingObserver& bo = get_building_observer(b.descr().name().c_str());
 
@@ -5050,10 +5110,15 @@
 			productionsites.back().site = &dynamic_cast<ProductionSite&>(b);
 			productionsites.back().bo = &bo;
 			productionsites.back().bo->new_building_overdue = 0;
-			productionsites.back().built_time = gametime;
+			if (found_on_load && gametime > 5 * 60 * 1000) {
+				productionsites.back().built_time = gametime - 5 * 60 * 1000;
+			} else {
+				productionsites.back().built_time = gametime;
+			}
 			productionsites.back().unoccupied_till = gametime;
 			productionsites.back().stats_zero = 0;
 			productionsites.back().no_resources_since =  kNever;
+			productionsites.back().upgrade_pending = false;
 			productionsites.back().bo->unoccupied_count += 1;
 			if (bo.is_shipyard) {
 				marine_task_queue.push_back(kStopShipyard);
@@ -5175,6 +5240,10 @@
 			     i != productionsites.end();
 			     ++i)
 				if (i->site == &b) {
+					if (i->upgrade_pending) {
+						bo.cnt_upgrade_pending -= 1;
+					}
+					assert (bo.cnt_upgrade_pending == 0 || bo.cnt_upgrade_pending == 1);
 					productionsites.erase(i);
 					break;
 				}

=== modified file 'src/ai/defaultai.h'
--- src/ai/defaultai.h	2016-02-18 17:58:54 +0000
+++ src/ai/defaultai.h	2016-02-25 21:06:10 +0000
@@ -213,9 +213,9 @@
 	Widelands::EconomyObserver* get_economy_observer(Widelands::Economy&);
 	Widelands::BuildingObserver& get_building_observer(char const*);
 
-	void gain_immovable(Widelands::PlayerImmovable&);
+	void gain_immovable(Widelands::PlayerImmovable&, bool found_on_load = false);
 	void lose_immovable(const Widelands::PlayerImmovable&);
-	void gain_building(Widelands::Building&);
+	void gain_building(Widelands::Building&, bool found_on_load);
 	void lose_building(const Widelands::Building&);
 	void gain_ship(Widelands::Ship&, NewShip);
 	void check_ship_in_expedition(Widelands::ShipObserver&, uint32_t);


Follow ups