(svn r10098) -Codechange: bilbo cared about the performance of the AI with respect to the airport placement, so he rewrote the aircraft handling of the AI; now it can actually make lots of money again :)
authorrubidium
Mon, 11 Jun 2007 14:23:04 +0000
changeset 7354 4108080dce70
parent 7353 716c6dd9322a
child 7355 8fd37a636f6d
(svn r10098) -Codechange: bilbo cared about the performance of the AI with respect to the airport placement, so he rewrote the aircraft handling of the AI; now it can actually make lots of money again :)
src/ai/default/default.cpp
src/table/ai_rail.h
--- a/src/ai/default/default.cpp	Mon Jun 11 14:00:16 2007 +0000
+++ b/src/ai/default/default.cpp	Mon Jun 11 14:23:04 2007 +0000
@@ -622,7 +622,6 @@
 	int dist;
 	uint same_station = 0;
 
-	// Make sure distance to closest station is < 37 pixels.
 	from_tile = GET_TOWN_OR_INDUSTRY_TILE(fr->from);
 	to_tile = GET_TOWN_OR_INDUSTRY_TILE(fr->to);
 
@@ -646,7 +645,19 @@
 		return false;
 	}
 
-	if (dist != 0xFFFF && dist > 37) return false;
+	/* Requiring distance to nearest station to be always under 37 tiles may be suboptimal,
+	 * Especially for longer aircraft routes that start and end pretty at any arbitrary place on map
+	 * While it may be nice for AI to cluster their creations together, hardcoded limit is not ideal.
+	 * If AI will randomly start on some isolated spot, it will never get out of there.
+	 * AI will have chance of randomly rejecting routes further than 37 tiles from their network,
+	 * so there will be some attempt to cluster the network together */
+
+	/* Random value between 37 and 292. Low values are exponentially more likely
+	 * With 50% chance the value will be under 52 tiles */
+	int min_distance = 36 + 1 << (Random() % 9); // 0..8
+
+	/* Make sure distance to closest station is < min_distance tiles. */
+	if (dist != 0xFFFF && dist > min_distance) return false;
 
 	if (p->ai.route_type_mask != 0 &&
 			!(p->ai.route_type_mask & bitmask) &&
@@ -1371,15 +1382,55 @@
 	FoundRoute fr;
 	int i;
 
+	/* Get aircraft that would be bought for this route
+	 * (probably, as conditions may change before the route is fully built,
+	 * like running out of money and having to select different aircraft, etc ...) */
+	EngineID veh = AiChooseAircraftToBuild(p->player_money, p->ai.build_kind != 0 ? 0 : AIR_CTOL);
+
+	/* No aircraft buildable mean no aircraft route */
+	if (veh == INVALID_ENGINE) return;
+
+	const AircraftVehicleInfo *avi = AircraftVehInfo(veh);
+
+	/* For passengers, "optimal" number of days in transit is about 80 to 100
+	 * Calculate "maximum optimal number of squares" from speed for 80 days
+	 * 20 days should be enough for takeoff, land, taxi, etc ...
+	 *
+	 * "A vehicle traveling at 100kph will cross 5.6 tiles per day" ->
+	 * Since in table aircraft speeds are in "real km/h", this should be accurate
+	 * We get max_squares = avi->max_speed * 5.6 / 100.0 * 80 */
+	int max_squares = avi->max_speed * 448 / 100;
+
+	/* For example this will be 10456 tiles for 2334 km/h aircrafts with realistic aircraft speeds
+	 * and 836 with "unrealistic" speeds, much more than the original 95 squares limit
+	 *
+	 * Size of the map, if not rectangular, it is the larger dimension of it
+	 */
+	int map_size = max(MapSizeX(), MapSizeY());
+
+	/* Minimum distance between airports is half of map size, clamped between 1% and 20% of optimum.
+	 * May prevent building plane routes at all on small maps, but they will be ineffective there, so
+	 * it is feature, not a bug.
+	 * On smaller distances, buses or trains are usually more effective approach anyway.
+	 * Additional safeguard is needing at least 20 squares,
+	 * which may trigger in highly unusual configurations */
+	int min_squares = max(20, max(max_squares / 100, min(max_squares / 5, map_size / 2)));
+
+	/* Should not happen, unless aircraft with real speed under approx. 5 km/h is selected.
+	 * No such exist, unless using some NewGRF with ballons, zeppelins or similar
+	 * slow-moving stuff. In that case, bail out, it is faster to walk by foot anyway :). */
+	if (max_squares < min_squares) return;
+
 	i = 60;
 	for (;;) {
+
 		// look for one from the subsidy list
 		AiFindSubsidyPassengerRoute(&fr);
-		if (IS_INT_INSIDE(fr.distance, 0, 95 + 1)) break;
+		if (IS_INT_INSIDE(fr.distance, min_squares, max_squares + 1)) break;
 
 		// try a random one
 		AiFindRandomPassengerRoute(&fr);
-		if (IS_INT_INSIDE(fr.distance, 0, 95 + 1)) break;
+		if (IS_INT_INSIDE(fr.distance, min_squares, max_squares + 1)) break;
 
 		// only test 60 times
 		if (--i == 0) return;
@@ -1408,7 +1459,19 @@
 	p->ai.build_kind = 0;
 	p->ai.num_build_rec = 2;
 	p->ai.num_loco_to_build = 1;
-	p->ai.num_want_fullload = 1;
+	/* Using full load always may not be the best.
+	 * Pick random value and rely on selling the vehicle & route
+	 * afterwards if the choice was utterly wrong (or maybe altering the value if AI is improved)
+	 * When traffic is very low or very assymetric, is is better not to full load
+	 * When traffic is high, full/non-full make no difference
+	 * It should be better to run with aircraft only one way full 6 times per year,
+	 * rather than two way full 1 times.
+	 * Practical experiments with AI show that the non-full-load aircrafts are usually
+	 * those that survive
+	 * Also, non-full load is more resistant against starving (by building better stations
+	 * or using exclusive rights)
+	 */
+	p->ai.num_want_fullload = CHANCE16(1, 5); // 20% chance
 //	p->ai.loco_id = INVALID_VEHICLE;
 	p->ai.order_list_blocks[0] = 0;
 	p->ai.order_list_blocks[1] = 1;
--- a/src/table/ai_rail.h	Mon Jun 11 14:00:16 2007 +0000
+++ b/src/table/ai_rail.h	Mon Jun 11 14:23:04 2007 +0000
@@ -567,8 +567,32 @@
 	{1, 0, {0, 0}}
 };
 
+static const AiDefaultBlockData _airportdata_ai_3[] = {
+	MKAIR(3, 0, 0),
+	{1, 0, {0, 0}},
+};
+
+static const AiDefaultBlockData _airportdata_ai_4[] = {
+	MKAIR(4, 0, 0),
+	{1, 0, {0, 0}},
+};
+
+static const AiDefaultBlockData _airportdata_ai_5[] = {
+	MKAIR(5, 0, 0),
+	{1, 0, {0, 0}},
+};
+
+static const AiDefaultBlockData _airportdata_ai_7[] = {
+	MKAIR(7, 0, 0),
+	{1, 0, {0, 0}}
+};
+
 static const AiDefaultBlockData * const _airport_default_block_data[] = {
+	_airportdata_ai_7, // intercontinental airport
+	_airportdata_ai_4, // international airport
+	_airportdata_ai_3, // metropolitan airport
 	_airportdata_ai_0, // city airport
+	_airportdata_ai_5, // commuter airport
 	_airportdata_ai_1, // country airport
 	NULL
 };