Station location, industry location and GetCoverageRadius

Discuss the new AI features ("NoAI") introduced into OpenTTD 0.7, allowing you to implement custom AIs, and the new Game Scripts available in OpenTTD 1.2 and higher.

Moderator: OpenTTD Developers

Post Reply
marco.r
Engineer
Engineer
Posts: 37
Joined: 16 Aug 2011 01:26

Station location, industry location and GetCoverageRadius

Post by marco.r »

Greetings,
I just started playing around with the NoAI framework, but I have a few difficulties with things that
should be quite basic.

Let's say that I want to find out where I can build a station that can receive wood for a nearby sawmill.
What should I be looking for ? I tried a couple approaches but all of them failed
- Extract from the map the tiles belonging to the industry, and use GetCoverageRadius to build the
tiles where build my station (let's say a simple 1x1 truck station). Doesn't work because not all the tiles
of the sawmill accept wood (and what's more, tiles not belonging to the sawmill will produce goods. Go figure).
- Use AITile::GetCargoAcceptance/AITile::GetCargoProduction, starting from the location of the factory
and expanding while I keep finding a positive response. Problem is, this will get also production from
other factories, am I right ? What if I want production from/to _that_ factory ?
For the moment I kept the first approach, with a couple of "fixes" that make it work with the default set,
but I think there is a better solution... any idea ?

Marco

edit: ouch, wrong section, was meant to go in NoAI discussion subsection
Brumi
President
President
Posts: 921
Joined: 18 Jul 2009 17:54

Re: Station location, industry location and GetCoverageRadiu

Post by Brumi »

In most cases, this will work perfectly:

Code: Select all

tiles = AITileList_IndustryAccepting(the_sawmill, coverage_radius_of_station);
At least it will work with the default industry set.

However, there are cases when an industry accepts multiple types of cargo, but at different tiles. See http://www.tt-forums.net/viewtopic.php?p=950891#p950891.
To avoid this, you will have to filter the above tilelist afterwards by acceptance. (note that AITileList_IndustryAccepting doesn't have a cargo parameter)

Code: Select all

tiles.Valuate(AITile.GetCargoAcceptance, crg, 1, 1, coverage_radius_of_station);
tiles.RemoveBelowValue(8);
krinn
Transport Coordinator
Transport Coordinator
Posts: 342
Joined: 29 Dec 2010 19:36

Re: Station location, industry location and GetCoverageRadiu

Post by krinn »

marco.r wrote:Problem is, this will get also production from
other factories, am I right ? What if I want production from/to _that_ factory ?
For that part it's not undoable but the solve might be too tweaky while the solve won't produce really interresting results.

Say you wish to only get wood acceptance from industryA, you'll have to assign an accepting radius, then add any other industries that also accept wood within that radius*2 (because if radius of industryB touch radius of industryA you will have a shared tile with both accepting the wood)
Now that you have that, you need to remove all tiles that are shared by both, remain will be tiles not shared and own by industryA that accept wood: your goal is reach.

As you see, not undoable, just weak benefits (making sure only industryA is feed) vs a weak "bad" effect (you may feed more than just one industry, but you will get paid anyway).
Except if your goal is to feed only 1 industry to higher as much as possible its producing of another good you wish to make big money out of it (an openttdcoopAI ?) i don't think that's a good idea (because removing shared tiles = removing possible places to find a spot to build your station)
marco.r
Engineer
Engineer
Posts: 37
Joined: 16 Aug 2011 01:26

Re: Station location, industry location and GetCoverageRadiu

Post by marco.r »

krinn wrote:
marco.r wrote:Problem is, this will get also production from
other factories, am I right ? What if I want production from/to _that_ factory ?
For that part it's not undoable but the solve might be too tweaky while the solve won't produce really interresting results.

Say you wish to only get wood acceptance from industryA, you'll have to assign an accepting radius, then add any other industries that also accept wood within that radius*2 (because if radius of industryB touch radius of industryA you will have a shared tile with both accepting the wood)
Now that you have that, you need to remove all tiles that are shared by both, remain will be tiles not shared and own by industryA that accept wood: your goal is reach.

As you see, not undoable, just weak benefits (making sure only industryA is feed) vs a weak "bad" effect (you may feed more than just one industry, but you will get paid anyway).
Except if your goal is to feed only 1 industry to higher as much as possible its producing of another good you wish to make big money out of it (an openttdcoopAI ?) i don't think that's a good idea (because removing shared tiles = removing possible places to find a spot to build your station)
First of all, thanks to both for you answers.
Actually what I wanted to be sure was that I would not get also the tiles of the "area of interest" of another factory, ending up outside of the area of the original one.
But with the solution proposed it is a non-issue.

Now it works just fine. thanks again !
User avatar
skippern
Traffic Manager
Traffic Manager
Posts: 195
Joined: 30 Oct 2013 13:57

Re: Station location, industry location and GetCoverageRadiu

Post by skippern »

Reviving the thread because the topic fits my question

Trying to find a nice function to get a square ready to build a station close to an industry. The purpose is to find a square of sufficient space within the area of coverage of so I do not need to terraform or demolish anything. I am currently trying this:

Code: Select all

function MyAI::BuildStation(near, cargoid)
{
local ind_idx = AIIndustry.GetIndustryID(near);
local ind_type = AIIndustry.GetIndustryType(ind_idx);
local town_id = AITile.GetClosestTown(near);
local station_name = AITown.GetName(town_id) + " " + AIIndustryType.GetName(ind_type) + " Cargo Station";

local tile = near;

while (!AITile.IsBuildableRectangle(tile, 3, 3)) {

}

AIRail.BuildRailStation(tile, AIRail.RAILTRACK_NW_SE, 3, 3, AIStation.STATION_JOIN_ADJACENT);
local station = AIStation.GetStationID(tile);
AIBaseStation.SetName(station, station_name);

return station;
}
I have no idea what to put into the while-loop, if it fails it should return NULL, that part is understandable, I need to figure out how to move around within the coverage area until I get a rectangle I can build on
Skippern
OpenTTD Mac user
R2dical
Traffic Manager
Traffic Manager
Posts: 163
Joined: 18 Mar 2013 22:22

Re: Station location, industry location and GetCoverageRadiu

Post by R2dical »

Well if you are specifying a tile to build near to, I'd say best would be to generate a TileList of all possible tiles in your chosen radius and run through each with a for loop:

Code: Select all

	local tile_list = AITileList();
	tile_list.AddRectangle(tile - AIMap.GetTileIndex(radius, radius), tile + AIMap.GetTileIndex(radius, radius));

	tile_list.Valuate(AIBase.RandItem);    // Avoid building similar layouts all the time:)
	tile_list.Sort(AIList.SORT_BY_VALUE, AIList.SORT_DESCENDING);

	local current_tile = null;
	for(current_tile = tile_list.Begin(); !tile_list.IsEnd(); current_tile = tile_list.Next()) {
	
		if(AIRail.BuildRailStation(current_tile, AIRail.RAILTRACK_NW_SE, 3, 3, AIStation.STATION_NEW));	// Try build whole thing at once.
			break;
	}
	
	if(!AIRail.IsRailStationTile(current_tile))
		return null;	//failed to build for all tiles.
Also check out the util functions in NoCAB (or Krinn's Dictator), there is a nice method of terraforming to flatten a rectange for building.
User avatar
skippern
Traffic Manager
Traffic Manager
Posts: 195
Joined: 30 Oct 2013 13:57

Re: Station location, industry location and GetCoverageRadiu

Post by skippern »

R2dical wrote: Also check out the util functions in NoCAB (or Krinn's Dictator), there is a nice method of terraforming to flatten a rectange for building.
Dictator is a messy code :shock:
Skippern
OpenTTD Mac user
User avatar
skippern
Traffic Manager
Traffic Manager
Posts: 195
Joined: 30 Oct 2013 13:57

Re: Station location, industry location and GetCoverageRadiu

Post by skippern »

What am I doing wrong?

Code: Select all

local tile_list = AITileList();
tile_list.AddRectangle(near - AIMap.GetTileIndex(radius, radius), near + AIMap.GetTileIndex(radius, radius));
tile_list.Valuate(AIBase.RandItem);
tile_list.Sort(AIList.SORT_BY_VALUE, AIList.SORT_DESCENDING);
local i = 0; // help with debugging
local current_tile = tile_list.Begin(); // changed from null to make sure that this wasn't the problem
AILog.Info("Trying to build station ("+tile_list.Count()+")"); // tells me how many tiles is in the list, for debugging
for (current_tile = tile_list.Begin(); !tile_list.IsEnd(); current_tile = tile_list.Next()) {
   if (!AIMap.IsValidTile(current_tile)) AILog.Error("Error: False current_tile"); // produce nasty error if fails <- not printed, so tile is valid
   if (AIRail.BuildRailStation(current_tile, direction, platforms, length, AIStation.STATION_NEW)) break; // station is not built
   i++; // for debugging
   AISign.BuildSign(current_tile, station_name); // sign is not placed
}
AILog.Info("Tried "+i+" tiles, either all tiles tried or station built");
No station built, and no debugging signs placed, what happens?
Skippern
OpenTTD Mac user
R2dical
Traffic Manager
Traffic Manager
Posts: 163
Joined: 18 Mar 2013 22:22

Re: Station location, industry location and GetCoverageRadiu

Post by R2dical »

You set a rail type before doing the loop right?

This works for my AI (not gonna bother with the screenshot :tongue: ):

Code: Select all

	local build = AIExecMode();
	local near = SuperLib.Tile.GetRandomTile();
	local rail_list = AIRailTypeList();
	AIRail.SetCurrentRailType(rail_list.Begin());
	
	local tile_list = AITileList();
	tile_list.AddRectangle(near - AIMap.GetTileIndex(radius, radius), near + AIMap.GetTileIndex(radius, radius));
	tile_list.Valuate(AIBase.RandItem);
	tile_list.Sort(AIList.SORT_BY_VALUE, AIList.SORT_DESCENDING);
	local current_tile = null;
	for (current_tile = tile_list.Begin(); !tile_list.IsEnd(); current_tile = tile_list.Next()) {
	   if (AIRail.BuildRailStation(current_tile, AIRail.RAILTRACK_NW_SE, 3, 5, AIStation.STATION_NEW))
		break;
	}
In practise you may want to use the Superlib version of AddRectange, which accounts for edge of map and "wrap around" avoid clamp feature. Also looping through a tile list means you don't have to bother with IsValid.
skippern wrote:Dictator is a messy code :shock:
Really? Take a look at TeshiNet :) (not "messy" but non descriptive variables and comments...)
User avatar
skippern
Traffic Manager
Traffic Manager
Posts: 195
Joined: 30 Oct 2013 13:57

Re: Station location, industry location and GetCoverageRadiu

Post by skippern »

R2dical wrote:You set a rail type before doing the loop right?
That was it!
R2dical wrote:
skipern wrote:Dictator is a messy code :shock:
Really? Take a look at TeshiNet :) (not "messy" but non descriptive variables and comments...)

In practise you may want to use the Superlib version of AddRectange, which accounts for edge of map and "wrap around" avoid clamp feature. Also looping through a tile list means you don't have to bother with IsValid.
First need to get this rolling, than I can start looking at better solutions
Skippern
OpenTTD Mac user
Post Reply

Return to “OpenTTD AIs and Game Scripts”

Who is online

Users browsing this forum: No registered users and 20 guests