Page 1 of 1

Station location, industry location and GetCoverageRadius

Posted: 17 Aug 2011 01:27
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

Re: Station location, industry location and GetCoverageRadiu

Posted: 17 Aug 2011 07:58
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);

Re: Station location, industry location and GetCoverageRadiu

Posted: 17 Aug 2011 10:04
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)

Re: Station location, industry location and GetCoverageRadiu

Posted: 17 Aug 2011 13:29
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 !

Re: Station location, industry location and GetCoverageRadiu

Posted: 23 Jan 2014 23:12
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

Re: Station location, industry location and GetCoverageRadiu

Posted: 23 Jan 2014 23:36
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.

Re: Station location, industry location and GetCoverageRadiu

Posted: 24 Jan 2014 11:28
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:

Re: Station location, industry location and GetCoverageRadiu

Posted: 24 Jan 2014 14:41
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?

Re: Station location, industry location and GetCoverageRadiu

Posted: 24 Jan 2014 15:13
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...)

Re: Station location, industry location and GetCoverageRadiu

Posted: 24 Jan 2014 15:31
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