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

Requested reviews:
  Widelands Developers (widelands-dev)

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

Changes to AI in regard to colonization (exploration):

- AI nows considers whether possible sea direction leads to unknown territories 
(using Player.vision() = 0) and these are preferred to normal open sea (know 
territories only)
- Logic for building ports and shipyard was tweaked to increase AI's 
willingness to build them

Main problem on confined territories with one portspace are roads (AI does not 
control them fully) and trees.
-- 
Your team Widelands Developers is requested to review the proposed merge of 
lp:~widelands-dev/widelands/ai_colonization_update into lp:widelands.
=== modified file 'src/ai/ai_help_structs.h'
--- src/ai/ai_help_structs.h	2018-02-16 20:42:21 +0000
+++ src/ai/ai_help_structs.h	2018-02-17 20:56:06 +0000
@@ -509,6 +509,7 @@
 	Widelands::Ship* ship;
 	bool waiting_for_command_ = false;
 	uint32_t last_command_time = 0;
+	bool escape_mode = false;
 
 	// direction by which the ship circumvents an island
 	// this is the last circle-island command's direction

=== modified file 'src/ai/defaultai.cc'
--- src/ai/defaultai.cc	2018-02-16 20:42:21 +0000
+++ src/ai/defaultai.cc	2018-02-17 20:56:06 +0000
@@ -2389,6 +2389,7 @@
 
 			if (bo.is(BuildingAttribute::kShipyard)) {
 				assert(bo.new_building == BuildingNecessity::kAllowed ||
+				       bo.new_building == BuildingNecessity::kNeeded ||
 				       bo.new_building == BuildingNecessity::kForbidden);
 			}
 
@@ -2761,7 +2762,6 @@
 						prio += 150;
 						assert(!bo.is(BuildingAttribute::kShipyard));
 					} else if (bo.is(BuildingAttribute::kShipyard)) {
-						assert(bo.new_building == BuildingNecessity::kAllowed);
 						if (!map_allows_seafaring_) {
 							continue;
 						}
@@ -4574,10 +4574,13 @@
 	// So now we know the warehouse here is needed.
 	bo.primary_priority =
 	   1 +
-	   (needed_count - numof_warehouses_) * std::abs(management_data.get_military_number_at(22) * 5);
+	   (needed_count - numof_warehouses_) * std::abs(management_data.get_military_number_at(22) * 20);
 	++bo.new_building_overdue;
 	bo.primary_priority +=
-	   bo.new_building_overdue * std::abs(management_data.get_military_number_at(16)) / 10;
+	   bo.new_building_overdue * std::abs(management_data.get_military_number_at(16));
+	if (bo.is(BuildingAttribute::kPort) && spots_ < kSpotsTooLittle) {
+		bo.primary_priority += std::abs(management_data.get_military_number_at(152)) * 10;
+	}
 	return BuildingNecessity::kAllowed;
 }
 
@@ -5510,10 +5513,20 @@
 			}
 
 		} else if (bo.is(BuildingAttribute::kShipyard)) {
-			if (bo.total_count() > 0 ||
-			    site_needed_for_economy == BasicEconomyBuildingStatus::kDiscouraged) {
+			if (bo.total_count() > 0 || (!basic_economy_established &&
+			    site_needed_for_economy == BasicEconomyBuildingStatus::kDiscouraged) || !map_allows_seafaring_) {
 				return BuildingNecessity::kForbidden;
 			}
+			bo.primary_priority = 0;
+			if (num_ports > 0) {
+				bo.primary_priority += std::abs(management_data.get_military_number_at(150) * 3);
+			}
+			if (spots_ < kSpotsTooLittle) {
+				bo.primary_priority += std::abs(management_data.get_military_number_at(151) * 3);
+			}
+			if (bo.primary_priority > 0) {
+				return BuildingNecessity::kNeeded;
+			}
 			return BuildingNecessity::kAllowed;
 		} else if (bo.max_needed_preciousness == 0) {
 			return BuildingNecessity::kNotNeeded;

=== modified file 'src/ai/defaultai.h'
--- src/ai/defaultai.h	2018-02-16 20:42:21 +0000
+++ src/ai/defaultai.h	2018-02-17 20:56:06 +0000
@@ -271,6 +271,7 @@
 	uint8_t spot_scoring(Widelands::Coords candidate_spot);
 	bool marine_main_decisions();
 	bool check_ships(uint32_t);
+	bool attempt_escape(Widelands::ShipObserver& so);
 
 	// finding and owner
 	Widelands::PlayerNumber get_land_owner(const Widelands::Map&, uint32_t);

=== modified file 'src/ai/defaultai_seafaring.cc'
--- src/ai/defaultai_seafaring.cc	2018-01-03 20:24:57 +0000
+++ src/ai/defaultai_seafaring.cc	2018-02-17 20:56:06 +0000
@@ -179,8 +179,10 @@
 	FleetStatus enough_ships = FleetStatus::kDoNothing;
 	if (ports_count > 0 && shipyards_count > 0 && idle_shipyard_stocked) {
 
-		// we always need at least one ship in transport mode
-		if (!ship_free) {
+		if (!basic_economy_established) {
+			enough_ships = FleetStatus::kEnoughShips;
+			// we always need at least one ship in transport mode
+		} else if (!ship_free) {
 			enough_ships = FleetStatus::kNeedShip;
 
 			// we want at least as many free ships as we have ports
@@ -223,7 +225,7 @@
 
 	// starting an expedition? if yes, find a port and order it to start an expedition
 	if (ports_count > 0 && expeditions_in_progress == 0 && expeditions_in_prep == 0 &&
-	    persistent_data->no_more_expeditions == kFalse && ship_free) {
+	    persistent_data->no_more_expeditions == kFalse && ship_free && basic_economy_established) {
 
 		// we need to find a port
 		for (const WarehouseSiteObserver& wh_obs : warehousesites) {
@@ -291,6 +293,12 @@
 			// if ship is waiting for command
 			if (so.waiting_for_command_) {
 				expedition_management(so);
+
+				// Sometimes we look for other direction even if ship is still scouting,
+				// escape mode here indicates that we are going over known ports
+			} else if (so.escape_mode &&
+			           so.ship->get_ship_state() == Widelands::Ship::ShipStates::kExpeditionScouting) {
+				attempt_escape(so);
 			}
 
 			// Checking utilization
@@ -439,13 +447,14 @@
 
 	const int32_t gametime = game().get_gametime();
 	PlayerNumber const pn = player_->player_number();
-	// probability for island exploration repetition
-	const int repeat_island_prob = 20;
 
 	// second we put current spot into expedition visited_spots
 	bool first_time_here = expedition_visited_spots.count(so.ship->get_position().hash()) == 0;
 	if (first_time_here) {
 		expedition_visited_spots.insert(so.ship->get_position().hash());
+		so.escape_mode = false;
+	} else {
+		so.escape_mode = true;
 	}
 
 	// if we have a port-space we can build a Port or continue exploring
@@ -470,16 +479,10 @@
 	}
 
 	// 2. Go on with expedition
-	// we were not here before
-	// OR we might randomly repeat island exploration
-	if (first_time_here || game().logic_rand() % 100 < repeat_island_prob) {
-		if (first_time_here) {
-			log("%d: %s at %3dx%3d: explore uphold, visited first time\n", pn,
-			    so.ship->get_shipname().c_str(), so.ship->get_position().x, so.ship->get_position().y);
-		} else {
-			log("%d: %s at %3dx%3d: explore uphold, visited before\n", pn,
-			    so.ship->get_shipname().c_str(), so.ship->get_position().x, so.ship->get_position().y);
-		}
+	// 2a) Ship is first time here
+	if (first_time_here) {
+		log("%d: %s at %3dx%3d: explore uphold, visited first time\n", pn,
+		    so.ship->get_shipname().c_str(), so.ship->get_position().x, so.ship->get_position().y);
 
 		// Determine direction of island circle movement
 		// Note: if the ship doesn't own an island-explore-direction it is in inter-island exploration
@@ -496,44 +499,13 @@
 		// send the ship to circle island
 		game().send_player_ship_explore_island(*so.ship, so.island_circ_direction);
 
-		// we head for open sea again
+		// 2b) We were here before, let try break for open sea
 	} else {
-		// determine swimmable directions
-		const Map& map = game().map();
-		std::vector<Direction> possible_directions;
-		for (Direction dir = FIRST_DIRECTION; dir <= LAST_DIRECTION; ++dir) {
-			// testing distance of 8 fields
-			// this would say there is an 'open sea' there
-			Widelands::FCoords tmp_fcoords = map.get_fcoords(so.ship->get_position());
-			for (int8_t i = 0; i < 8; ++i) {
-				tmp_fcoords = map.get_neighbour(tmp_fcoords, dir);
-				if (tmp_fcoords.field->nodecaps() & MOVECAPS_SWIM) {
-					if (i == 7) {
-						possible_directions.push_back(dir);
-					}
-				} else {
-					break;
-				}
-			}
-		}
-
-		// we test if there is open sea
-		if (possible_directions.empty()) {
-			// 2.A No there is no open sea
-			// TODO(toptopple): we should implement a 'rescue' procedure like 'sail for x fields and
-			// wait-state'
+		if (!attempt_escape(so)) {  // return true if the ship was sent to open sea
+			// otherwise we continue circumventing the island
 			game().send_player_ship_explore_island(*so.ship, so.island_circ_direction);
 			log("%d: %s: in JAMMING spot, continue circumvention, dir=%u\n", pn,
 			    so.ship->get_shipname().c_str(), static_cast<uint32_t>(so.island_circ_direction));
-
-		} else {
-			// 2.B Yes, pick one of available directions
-			const Direction direction =
-			   possible_directions.at(game().logic_rand() % possible_directions.size());
-			game().send_player_ship_scouting_direction(*so.ship, static_cast<WalkingDir>(direction));
-
-			log("%d: %s: exploration - breaking for free sea, dir=%u\n", pn,
-			    so.ship->get_shipname().c_str(), direction);
 		}
 	}
 
@@ -541,3 +513,67 @@
 	so.waiting_for_command_ = false;
 	return;
 }
+
+// Here we investigate possibility to go for open see, preferably to unexplored territories
+bool DefaultAI::attempt_escape(ShipObserver& so) {
+
+	const Map& map = game().map();
+	PlayerNumber const pn = player_->player_number();
+
+	// Determine swimmable directions first:
+	// This vector contains directions that lead to unexplored sea
+	static std::vector<Direction> new_teritory_directions;
+	new_teritory_directions.clear();
+	new_teritory_directions.reserve(6);
+	// This one contains any directions with open sea (superset of above one)
+	static std::vector<Direction> possible_directions;
+	possible_directions.clear();
+	possible_directions.reserve(6);
+	for (Direction dir = FIRST_DIRECTION; dir <= LAST_DIRECTION; ++dir) {
+		// testing distance of 30 fields (or as long as the sea goes, and untill
+		// unknown territory is reached)
+		Coords tmp_coords = so.ship->get_position();
+
+		for (int8_t i = 0; i < 30; ++i) {
+			map.get_neighbour(tmp_coords, dir, &tmp_coords);
+			if (!(map.get_fcoords(tmp_coords).field->nodecaps() & MOVECAPS_SWIM)) {
+				break;
+			}
+			if (i == 5) {
+				// If open sea goes at least  fields from the ship this is considerd a
+				// candidate, but worse then directions in new_teritory_directions
+				// Of course this direction can be inserted also into new_teritory_directions
+				// below
+				possible_directions.push_back(dir);
+			}
+			if (player_->vision(map.get_index(tmp_coords, map.get_width())) == 0) {
+				// So this field was never seen before, the direction is inserted into
+				// new_teritory_directions, and searching in this direction quits here
+				new_teritory_directions.push_back(dir);
+				break;
+			}
+		}
+	}
+
+	assert(possible_directions.size() >= new_teritory_directions.size());
+
+	// If only open sea (no unexplored sea) is found, we dont divert ship always
+	if (new_teritory_directions.empty() and game().logic_rand() % 100 < 80) {
+		return false;
+	}
+
+	if (!possible_directions.empty() || !new_teritory_directions.empty()) {
+		const Direction direction =
+		   !new_teritory_directions.empty() ?
+		      new_teritory_directions.at(game().logic_rand() % new_teritory_directions.size()) :
+		      possible_directions.at(game().logic_rand() % possible_directions.size());
+		game().send_player_ship_scouting_direction(*so.ship, static_cast<WalkingDir>(direction));
+
+		log("%d: %s: exploration - breaking for %s sea, dir=%u\n", pn,
+		    so.ship->get_shipname().c_str(), !new_teritory_directions.empty() ? "unexplored" : "free",
+		    direction);
+		so.escape_mode = false;
+		return true;  // we were successfull
+	}
+	return false;
+}

_______________________________________________
Mailing list: https://launchpad.net/~widelands-dev
Post to     : widelands-dev@lists.launchpad.net
Unsubscribe : https://launchpad.net/~widelands-dev
More help   : https://help.launchpad.net/ListHelp

Reply via email to