Using function arguments to call a table

Posted by Daved on Fri 22 Apr 2011 11:36 PM — 5 posts, 25,887 views.

#0
The tables in my combat system for aetolia look like this:



limbs_list = { 
	"left leg",
	"right leg",
	"left arm",
	"right arm",
	"head",
	"torso"
} --limbs_list

limbs_default = { -- default values for all limbs
	["damage"] = 0,
	["parrying"] = false,
	["needparry"] = false,
	["triedparry"] = false,
	["lasttriedparry"] = 0,
	["lasthit"] = false,
	["restoring"] = false,
	["broken"] = false,
	["damaged"] = false,
	["mangled"] = false,
	["worst"] = false
} -- limbs_default

limb_vars = {
	"damage",
	"parrying",
	"needparry",
	"triedparry",
	"lasttriedparry",
	"lasthit",
	"restoring",
	"broken",
	"damaged",
	"mangled",
	"worst"
} -- limb_vars
	
my_limbs = {} -- initialize my limb table
	
for _, cur_limb in ipairs (limbs_list) do -- populate my limb table with limbs
	my_limbs[cur_limb] = {}
	for _, cur_var in ipairs (limb_vars) do -- populate my limb tables's limbs with variables
		my_limbs[cur_limb][cur_var] = limbs_default[cur_var] -- set all those values for each limb to their default value
	end -- for limb_vars
end -- for limbs_list

target_limbs = {} -- initialize my target's limb table
	
for _, cur_limb in ipairs (limbs_list) do -- populate my limb table with limbs
	target_limbs[cur_limb] = {}
	for _, cur_var in ipairs (limb_vars) do -- populate my limb tables's limbs with variables
		target_limbs[cur_limb][cur_var] = limbs_default[cur_var] -- set all those values for each limb to their default value
	end -- for limb_vars
end -- for limbs_list



There is a very similar structure for tables to track my and my opponent's balances, afflictions, etc.

Currently, my functions for retrieving useful values from those tables look like:


function GetLimbs(var, limb) -- returns the value of a given variable for a given limb
	return (my_limbs[limb][var])
end -- func

function GetTargetLimbs(var, limb) -- returns the value of a given variable for my target's given limb
	return (target_limbs[limb][var])
end -- func


Again a similar structure for the other types of information.

I would like a more general function, one to retrieve any value from any table, something like


function Get(who, table, key1, key2)
	return (who_table[key1][key2])
end -- func


But that syntax isn't working, most likely because
Get("my", "limbs", "left arm", "parrying") is trying to return who_table too literally, or doesn't know what to do with the string values of those two arguments (who and table) in the context of processing them as variable names.

I recognize that this could be done by combining all my tables into one super table i.e.


function Get(who, table, key1, key2)
	return (AMTS_vars[who][table][key1][key2])
end -- func

Get("my", "limbs", "left arm", "parrying") 

--would then return the value of AMTS_vars["my"]["limbs"]["left arm"]["parrying"]



But surely that's not my only recourse! Halp?

For a more illustrative and slightly simpler example of what I am trying to do, have a look here: http://pastebin.com/S07m4u69

Amended on Sat 23 Apr 2011 12:13 AM by Daved
USA #1
Daved said:

function Get(who, table, key1, key2)
	return (who_table[key1][key2])
end -- func

who, table, and who_table are three entirely separate variable names. An underscore isn't an operator, it's just a part of a name.

Also, I think your function is a little general. If you can do this...
Get("my", "limbs", "left arm", "parrying")
...then why can't you just do this?
return my_limbs["left arm"]["parrying"]


As a suggestion, why don't you do this:
local me = {
  limbs = {},
}

local target = {
  limbs = {},
}

Then you can use Get(me, "limbs", "left arm", "parrying") - notice that I'm passing the table in as the first argument, not a string. It's still a bit pointless since you can just do me.limbs["left arm"]["parrying"], but there you go.
Australia Forum Administrator #2

function Get(who, table, key1, key2)
	return (who_table[key1][key2])
end -- func


A simple modification would be simply pass down the table, eg.


function Get(t, key1, key2)
	return (t[key1][key2])
end -- func

...

Get(my_limbs, "left arm", "parrying")


Although I agree also with Twisol.
#3
Thanks folks, your answers helped me realise a fundamental flaw between how I wanted to organize my variables this time around and what I was doing. What I was trying to do is have all my variables be referenced by a numerically indexed nested table. I was indexing the subtables with strings!

I searched the forums for a bit to discover some method to index my tables in this manner and came across the table.insert function.

Playing with this function a bit I found I could create such a table by using table.insert in an innermost table -> outermost table order:


iAfflictions = {}
iHerbs = {}
iBloodroot = {}
iParalysis = {}
iState = {
	false
}
iTried = {
	false
}
function IndexAffTable()
	table.insert(iParalysis, iState)
	table.insert(iParalysis, iTried)
	table.insert(iBloodroot, iParalysis)
	table.insert(iHerbs, iBloodroot)
	table.insert(iAfflictions, iHerbs)
end


compare to defining tables like so:


dAfflictions = {
	dHerbs = {
		dBloodroot = {
			dParalysis = {
				dState = {
					false
				}, -- state
				dTried = {
					false
				}, -- tried
			}, --paralysis
		}, --bloodroot
	}, -- herbs
} --afflictions


When I tprint(iAfflictions) I get

1:
  1:
    1:
      1:
        1=false
      2:
        1=false


compared to tprint(dAfflictions)

"dHerbs":
  "dBloodroot":
    "dParalysis":
      "dState":
        1=false
      "dTried":
        1=false


However, the function I'm using - IndexAffTable() is rather clumsy in structure and not easily generalized to other tables. What I seem to need is a mechanism to convert strings to objects so that I can store the names of subtables to be indexed in an intermediary table and have an ipairs loop to table.insert the subtables into each other. Any advice?

EDIT: For the sake of clarity, I'm trying to construct something more like this:


iAffCure = {
	"iHerb",
	"iSalve"
}

iAffHerb = {
	"iBloodroot",
	"iGoldenseal"
}

iAffBR = {
	"iParalysis",
	"iSlickness"
}

iAffGS = {
	"iStupidity",
	"iImpatience"
}

iAffVars = {
		"iState",
		"iTried",
		"iLastTried"
} -- affliction_variables

iState = {
	false
}
iTried = {
	false
}
iLastTried = {
	[1] = 0
}

iAfflictions = {}
iHerb = {}
iBloodroot = {}
iGoldenseal = {}


function LoopIndexAffTable()
	for a, b in ipairs (iAffCure) do
		if (b == "iHerb") then
			for c, d in ipairs (iAffHerb) do
				if (d == "iBloodroot") then
					for e, f in ipairs (iAffBR) do
						for g,h in ipairs (iAffVars) do
							table.insert(f, h)
						end -- for iAffVars
						table.insert(d, f)
					end -- for iAffBR
				elseif (d == "iGoldenseal") then
					for e, f in ipairs (iAffGS) do
						for g, h in ipairs (iAffVars) do
							table.insert(f, h)
						end -- for iAffvars
						table.insert(d, f)
					end -- for iAffGS
				end -- if d ==
				table.insert(b, d)
			end -- for iAffHerb
		end -- if b==
		table.insert(iAfflictions, b)
	end -- for iAffCure
end -- func


But of course that doesn't work because the indexed values of all of those tables are strings, and table.insert doesn't want to use strings.

Ideally looking for something that works more broadly, like

function IndexSubTables(tbl, stbl)
	for a, b in ipairs (stbl) do
		for c, d in ipairs (b) do
			for e, f in ipairs (d) do
				for g,h in ipairs (f) do
					table.insert(f, h)
				end -- for g,h
				table.insert(d, f)
			end -- for e,f
			table.insert(b, d)
		end -- for c, d
		table.insert(tbl, b)
	end -- a, b
end -- func
Amended on Sat 23 Apr 2011 07:57 AM by Daved
Australia Forum Administrator #4
I think it's too complicated.

There's nothing wrong with using string table keys. It's too roundabout IMO to have numeric keys, and then iterate through it to find a matching name. That's what string keys are for.

The only time I would use numeric keys was when I cared about the order (eg. cure X before Y) and you can do that by having a second table (a sequence table) but still keep your main data in a table keyed by name.

I think there is a fair bit about it here:

Template:post=6074
Please see the forum thread: http://gammon.com.au/forum/?id=6074.