Nesting tables in LUA

Nesting tables in LUA

Discuss Lua based Spring scripts (LuaUI widgets, mission scripts, gaia scripts, mod-rules scripts, scripted keybindings, etc...)

Moderator: Moderators

Post Reply
Fil
Posts: 6
Joined: 13 Nov 2015, 11:52

Nesting tables in LUA

Post by Fil »

Hi guys,

i'm doing a project for my thesis and i'm pretty new to LUA Scripting. My problem is the following: i am trying to track unit-to-unit combat statistics, and i want to obtain a nested table structured this way:

my unit type -> enemy unit type -> distance -> and then the distance table is something like { [100] = 2, [200] = 5, etc} , where indexes 100 200 are different ranges at which my unit has killed enemy unit, and values 2, 5 counts the number of kills have been made at that distance.

The result is intended to give me a statistic on how many times a certain unit type killed that other unit type at different distances, so it is like:
- unit1 x unit2 x 100m = 3
- unit1 x unit2 x 200m = 4
- unit1 x unit4 x 100m = 2
etc

My problem is i can't figure out how to structure this table:
- is there a way to make the "distance" table different for every "my unit x enemy unit" combination? or creating a table "distance" returns always the same table so every kill made at 100m writes on the same "distance" table indipendently of my and enemy unit type?
- the process should be as automatic as possible, meaning i don't want to declare previously all unit types and enemy types as table names or indexes (i can extract "unitDefID" and "attackerDefID" from a .UnitDestroyed call in, so i would like to being able to use that values for defining table values)

Thank you in advance! :)

Fil
User avatar
smoth
Posts: 22309
Joined: 13 Jan 2005, 00:46

Re: Nesting tables in LUA

Post by smoth »

Code: Select all


table = {
childTable = {},
2ndChildTable = {
 variableA = "waffles",
 variableB = "doughnut",
}
},
does this help?
8611z
Posts: 169
Joined: 08 Jul 2015, 20:20

Re: Nesting tables in LUA

Post by 8611z »

my unit type -> enemy unit type -> distance -> and then the distance table is something like { [100] = 2, [200] = 5, etc} , where indexes 100 200 are different ranges at which my unit has killed enemy unit, and values 2, 5 counts the number of kills have been made at that distance.
Could do like this:

Code: Select all

distanceHistogram[attackerID][victimID][distanceBin] = killCount
(Such diagrams https://upload.wikimedia.org/wikipedia/ ... ogram1.png are called "histogram" and the bars/boxes (100,200,300,..) are called "bins" (as in "bucket"))


If you want to increase count of unittype "X" killed by unittype "Y" at distance "D" you would do:

Code: Select all

distanceHistogram[X][Y][D] = distanceHistogram[X][Y][D] +1
The problem is that if you make a table like

Code: Select all

distanceHistogram = {}
then no subtables exist within it, and they do not get automagically created on access.

Code: Select all

distanceHistogram[X] = bla		--this works, new entry is created and filled with value
distanceHistogram[X][Y] = bla		--this does not work
distanceHistogram[X][Y][D] = bla	--this works even less

So you can either:
1) At inintinitatlistion create those subtables fill all entries with zeros.
or
2) Create new entries as they become needed.
I think for this case (2) is better.
(There are ways to write that shorter&nice but then it explains less clear imo.)

Code: Select all

function addToHistogram (attackerID, victimID, distance)
	--decide into which "bin" this distance goes (0,100,200,300,..)
	Dbin = (math.floor(distance / 100))*100

	--if there is no table for this attacker, then create one:
	if not distanceHistogram[attackerID] then distanceHistogram[attackerID] = {} end

	--if there is no table for this type of victim of type of attacker yet, then create one:
	if not distanceHistogram[attackerID][victimID] then distanceHistogram[attackerID][victimID] = {} end

	--if there is no table for the kill-distance for this type of victim of this type attacker yet, then starting counting at zero:
	if not distanceHistogram[attackerID][victimID][Dbin] then distanceHistogram[attackerID][victimID][Dbin] = 0 end

	--now we have an entry of the killcount at this distance, of this victim, by this attacker...
	--...and can increase it by 1:
	distanceHistogram[attackerID][victimID][Dbin] = distanceHistogram[attackerID][victimID][Dbin] +1
end
To print the table in bit ugly way:

Code: Select all

function printHistogram ()
	Spring.Echo ("----printHistogram---")
	for  attackerID,a  in pairs (distanceHistogram) do
		Spring.Echo ("attacker=",unitName(attackerID))
		for victimID,v  in pairs (distanceHistogram[attackerID]) do
			Spring.Echo ("\tvictim="..unitName(victimID))
			for dBin=0,maxD, binSize do
				count = distanceHistogram[attackerID][victimID][dBin] or 0
				if count > 0 then Spring.Echo ("\t\tdBin=",dBin, "count=",count) end
			end
		end
	end
end
usage:

Code: Select all

function gadget:UnitDestroyed(unitID, unitDefID, unitTeam, attackerID, attackerDefID, attackerTeam)	--add some checks if units are valid etc
	distance = Spring.GetUnitSeparation  (attackerID, unitID) or 0
	addToHistogram (attackerDefID, unitDefID, distance)
end	

example output:

Code: Select all

 ----printHistogram---
 attacker=, Raven
 	victim=Light Laser Tower
		dBin=, 800, count=, 2
 	victim=Peewee
 		dBin=, 1000, count=, 1
 attacker=, Peewee
 	victim=Light Laser Tower
 		dBin=, 100, count=, 2
 attacker=, Light Laser Tower
 	victim=Peewee
 		dBin=, 100, count=, 1
 		dBin=, 200, count=, 3
 		dBin=, 400, count=, 5
 attacker=, Guardian
 	victim=Peewee
 		dBin=, 100, count=, 2
 		dBin=, 200, count=, 1
 		dBin=, 300, count=, 3
 		dBin=, 400, count=, 2
 		dBin=, 500, count=, 4
 		dBin=, 600, count=, 10
 		dBin=, 700, count=, 4
User avatar
FLOZi
MC: Legacy & Spring 1944 Developer
Posts: 6240
Joined: 29 Apr 2005, 01:14

Re: Nesting tables in LUA

Post by FLOZi »

Fil wrote:... nested table structured this way:

my unit type -> enemy unit type -> distance -> and then the distance table is something like { [100] = 2, [200] = 5, etc} , where indexes 100 200 are different ranges at which my unit has killed enemy unit, and values 2, 5 counts the number of kills have been made at that distance.

The result is intended to give me a statistic on how many times a certain unit type killed that other unit type at different distances, so it is like:
- unit1 x unit2 x 100m = 3
- unit1 x unit2 x 200m = 4
- unit1 x unit4 x 100m = 2
etc
...
Not sure if I interpreted correctly;

Code: Select all

statsTable = {friendlyDefID1 = {enemyDefID1 = {[100] = 2, [200] = 5, ...}, enemyDefID2 = {...}, ...}, friendlyDefID2 = {...}, ...}
This would then be accessed e.g.

Code: Select all

statsTable[friendlyUnitDefID][enemydefID][range]
Do you need help understanding how to actually build such a table in lua, also?

edit: knorke got there first :-)
Fil
Posts: 6
Joined: 13 Nov 2015, 11:52

Re: Nesting tables in LUA

Post by Fil »

Hi guys! thanks for everything, you've been so kind :)

I managed to create a

killsTable[unitDefID][attackerDefID]["distance"][distance]=kills

(- the string "distance" identifies the table section scoring kills by distance, since i'm planning to score them even by angle, etc.,
- the variable distance holds the different distance ranges like 100 200 etc)

My initial confusion was due to the fact of declaring previously the subtables (because i needed them to be created) and then nesting them, but was a plain wrong approach, having only 1 table is woooow far more easy. Btw i check for missing table sections everytime i'm scoring a new entry.

Thank you!
User avatar
Silentwings
Posts: 3720
Joined: 25 Oct 2008, 00:23

Re: Nesting tables in LUA

Post by Silentwings »

Working with subtables does often produce easier to read code though, you just have to remember that in lua all tables are accessed by reference, regardless of whether its a table or a subtable.
Post Reply

Return to “Lua Scripts”