Page 1 of 1

Optimizing ore searching

Posted: Sat Jun 27, 2015 10:29 am
by ThaPear
I'm looking to find all ores within a certain radius, but I need to do it quickly, as it's done quite often.

The code I'm currently using to find ores in a specific radius around a specific position is this:

Code: Select all

local results = game.findentitiesfiltered{type = "resource", area = GetBoundingBox(position, radius)}
local ores = {}
for i = #results, 1, -1 do
	local ore = results[i]
	-- No fluids.
	if game.entityprototypes[ore.name].resourcecategory == "basic-fluid"
	-- No lava.
	or game.entityprototypes[ore.name].resourcecategory == "lava-magma"
	-- No depleted resources that aren't infinite.
	or (ore.amount <= 0 and not game.entityprototypes[ore.name].infiniteresource)
	-- No trees.
	or string.find(ore.name, "tree") then
		--table.remove(results, i)
	else
		table.insert(ores, results[i])
	end
end
--return results
return ores
This causes the script to take up about 15-25 ms, as opposed to just 1 ms when doing:

Code: Select all

local results = game.findentitiesfiltered{type = "resource", area = GetBoundingBox(self.vehicle.position, radius)}
return results
As you can see, I've tried removing them from the old results and I've tried creating a new list with only the filtered entities.
The new list was slightly faster, but only 2-4 ms (on the 15-25).

Situation: There are (currently 21) entities searching for ores in a certain radius, driving there, mining, searching anew, etc..

My question is: Does anyone have suggestions on optimizing this?

Re: Optimizing ore searching

Posted: Sat Jun 27, 2015 11:20 pm
by keyboardhack
You could split it up so it only does 1 tenth of the work every tick. something like this:

Code: Select all

local dY = yEnd - yStart
local results = game.findentitiesfiltered{type = "resource", area = {{xStart, yStart + ((dY / 10) * (cycleCounter - 1))}, {xEnd, ((dY / 10) * cycleCounter)}}}
if CycleCounter > 10 then
    cycleCounter = 1
end
cycleCounter = cycleCounter + 1

--filter results
Variables
cycleCounter is a variable controlling what tenth of the field the entity(i am guessing it's an entity) it's searching in.
xStart, yStart is the top left position of the search area
xEnd, yend is the bottom right position of the search area
(hopefully the code makes sense :))

Re: Optimizing ore searching

Posted: Tue Jun 30, 2015 2:24 am
by DaveMcW
You can also divide it by the total number of entities. Each tick you pick the next entity in the list and process that one. This way performance is constant, there is only a bit of decision lag if you have a lot of them.

I believe Roboports do this already.

Re: Optimizing ore searching

Posted: Wed Jul 01, 2015 8:50 am
by jorgenRe
Okay so what i would do is rather put each orefield in a table, so have that dropoff point search around it for resources ONLY when its built, and then put what it finds in a table. Then each miner looks through that table and takes the first position in it and mines it out. When its out it goes to the table again and takes the lowest from there too :)!
Summed up:
Make dropoff point 1 time search for resources, puts the results in a table -->(Point 2:) each miner within a radius of that dropoff point will take the first position and by using: "table.remove(glob.table[dropoffStationNr], 1)" it removes the first position in the table, and then moves everything over it down! It will now have a new resource entity to mine, then when it is mined out, it will ask for another resource^(back to point 2)

Re: Optimizing ore searching

Posted: Sat Jul 04, 2015 9:36 pm
by jorgenRe
keyboardhack wrote:You could split it up so it only does 1 tenth of the work every tick. something like this:

Code: Select all

local dY = yEnd - yStart
local results = game.findentitiesfiltered{type = "resource", area = {{xStart, yStart + ((dY / 10) * (cycleCounter - 1))}, {xEnd, ((dY / 10) * cycleCounter)}}}
if CycleCounter > 10 then
    cycleCounter = 1
end
cycleCounter = cycleCounter + 1

--filter results
Variables
cycleCounter is a variable controlling what tenth of the field the entity(i am guessing it's an entity) it's searching in.
xStart, yStart is the top left position of the search area
xEnd, yend is the bottom right position of the search area
(hopefully the code makes sense :))
Hmmmm If less than 10... Makes steps of 1.... resets to 1 does: 1+1...2+1... when 9 then goes back to 1 That is 8 steps and not 10! :ugeek:

Re: Optimizing ore searching

Posted: Sat Jul 04, 2015 10:47 pm
by keyboardhack
jorgenRe wrote:
keyboardhack wrote:You could split it up so it only does 1 tenth of the work every tick. something like this:

Code: Select all

local dY = yEnd - yStart
local results = game.findentitiesfiltered{type = "resource", area = {{xStart, yStart + ((dY / 10) * (cycleCounter - 1))}, {xEnd, ((dY / 10) * cycleCounter)}}}
if CycleCounter > 10 then
    cycleCounter = 1
end
cycleCounter = cycleCounter + 1

--filter results
Variables
cycleCounter is a variable controlling what tenth of the field the entity(i am guessing it's an entity) it's searching in.
xStart, yStart is the top left position of the search area
xEnd, yend is the bottom right position of the search area
(hopefully the code makes sense :))
Hmmmm If less than 10... Makes steps of 1.... resets to 1 does: 1+1...2+1... when 9 then goes back to 1 That is 8 steps and not 10! :ugeek:
There is an error in the code but that's not it.
It begins at 1 loops up to 9. 9 is not bigger than 10 so it continiues. 10 is not bigger than 10 so it continiues. It should actually stop at 10 so this line

Code: Select all

if CycleCounter > 10 then
Should be

Code: Select all

if CycleCounter == 10 then
Now it will loop from 1 to 10 which should be correct. Ofc i haven't tested it so there could be additional bugs : P