I sometimes make small games in Lua, and often have to implement a 2D array as a grid or a board. When I want to check the cells surrounding a particular cell I usually give the 2D array a metatable so that when grid[outOfBoundsNum] is indexed it returns an empty table instead of an error:
setmetatable(grid, {
__index =
function(t, key)
if not table[key] then
return {}
else
return table[key]
end
end})
So when grid[outOfBoundsNum][anything] is called, it returns nil. Then, to check surrounding cells I do something like this :
for k, v in ipairs(neighbours) do
local cell = grid[v[1][v[2]]
if cell then -- check if this is actually within the 2D array
if cell == 1 then
-- do something
elseif cell == 2 then
-- do something else
...
end
end
This works, but it seems awkward to me. Is there a nicer or better way of doing it?
You don't need the metatable.
for k, v in ipairs(neighbours) do
local cell = grid[v[1]] and grid[v[1]][v[2]]
if cell == 1 then
-- do something
elseif cell == 2 then
-- do something else
...
end
end
Should do the job. It is a relatively common lua idiom to use logical and and or in expressions to act like the ternary operator in C.
So this line is equivalent to:
local cell = nil
if grid[v[1]]~=nil then
cell = grid[v[1]][v[2]]
end
You could write a forEachNeighbor() function which would take the grid, a position and a function and then call it with each existing neighborfield, i.e. encapsule the loop and the outer if in your second snippet in a function, you would use like:
forEachNeighbor(grid, position, function(cell)
if cell == 1 then
-- do something
elseif cell == 2 then
-- do something else
...
end)
Also, you could provide an at() function which would take a grid position as one parameter and return the corresponding field or nil, so that grid[v[1]][v[2]] becomes at(grid, v). This could also be implemented in addition to or instead of the __index metamethod.
For the __index metamethod itself: First, you probably meant t instead of table and rawget(t, key) instead of t[key] (which would cause infinite recursion).
But as lhf pointed out, the check is altogether unnecessary, because __index is only called when the key is not present in t. So you could just write:
__index = function(t, key)
return {}
end
One last remark:
I sometimes make small games in Lua, and often have to implement a 2D array
Why don't you implement it once and reuse it in other games? That's what modules are for!
Related
Here's the loop:
array={0x, 0y, 1x, 1y}
for i, v in ipairs(array) do
if (i%2)==0 then
array[i]=v+valuex
else
array[i]=v+valuey
end
end
What i think it should do is cycle through the array and add either the variable 'valuex' if the position of the array variable is pair and 'valuey' if it's not: array[i] is the position, and I add 'valuex/y' to its 'v' value, but in the end nothing end up happening.
In the other hand, this code works, and it's what i'm trying to make the loop achieve:
0x=0x+valuex
1x=1x+valuex
0y=0y+valuey
1y=1y+valuey
I really can't get my hand on the reason the loop doesn't do that, but in the same time, you've guessed it, i'm a beginner in lua and in programming in general so i'd appreciate if you could lend me a hand.
Thanks.
Assuming, as you state in a comment, that 0x et. al. are in fact variables, your code was never going to work.
Variables are not values; they're variables. Variables store values, but they are not themselves values.
When you created your array, you copied the values inside of those variables into the array. Those array entries are modified, but there is no association between the array entries and where they got their values from.
If you want to manipulate the variables themselves, then they would have to be part of some table (perhaps the global table), the array indices would have to be the string names of those values, and your modifying function would have to use v to access the variable from the table. Assuming your "0x" variables are entries in the global table, the code would look something like this:
array={"0x", "0y", "1x", "1y"} --Storing string names of the variables.
for i, v in ipairs(array) do
if (i % 2) == 0 then
_G[v] = _G[v] + valuex
else
_G[v] = _G[v] + valuey
end
end
I am using Lua v5.2.2 within a C application (embedded environment/MCU).
I need to expose some "parameters" in Lua, that for reading and writing you need to directly access the hardware (thus a C call is needed). I am looking however for other means to implement this than using plain old getters and setters.
I am mostly exploring the meta-programming power of Lua, but also I believe I can create a simpler interface for the user.
What I want to achieve is behaviour like the following:
my_param = createParameter{name="hw_param1", type="number", min=0, max=100}
my_param = 5
result = my_param + 3
On the first line a new parameter is created. This is a call towards a C function. Userdata is pushed to stack with a properly initialized struct. The hardware is also initialized as needed. A new table is returned.
On the second line an assignment is done to the parameter object. I want this to call a C function with a single argument (that of the assignment), so the value can be stored to the hardware registers.
On the third line the parameter is read. I again need a call towards a C function that will get the value of the parameter from the hardware registers, and that will return the result.
Note that the actual value of this parameter may change outside the scope of Lua, so reading the value once during initialization is not correct. The C function must be called each time to get the actual value. Similarly writing to the value must cause an immediate write to the hardware.
How can I accomplish this? Specifically can I alter the metatable of the parameter to achieve lines 2 and 3? (I am aware of how to implement line 1).
Also is it necessary to return a table from the constructor? May I, for example, return a primitive Lua type (e.g. a number) that will behave like above?
Yes, you can modify the metatable metamethods.
Line 2 would completely change the variable's value that it holds.
However, if you were to set a field in the parameter object like: my_param.x = n, the __newindex metamethod would get invoked; which you could overwrite the metamethod to behave as you would like. In your case you would make it set the parameter's field and update it with a C function call.
Regarding line 3, same principle applies, instead this time you would just use the __add metamethod, and manipulate the object when __add is invoked.
http://lua-users.org/wiki/MetamethodsTutorial
This isn't exactly what you're asking for, but it's close:
function createParameter(t)
param = {}
param.data = t
backingTable = {}
metatable = {}
function metatable.__index(t, k)
-- You can intercept the value here if you
-- want and pass it on to your C fuction.
return backingTable[k]
end
function metatable.__newindex(t, k, v)
-- You can intercept the value here if you
-- want and pass it on to your C fuction.
backingTable[k] = v
end
setmetatable(param, metatable)
return param
end
--------------------------------------------------------
my_param = createParameter{name="hw_param1", type="number", min=0, max=100}
my_param.value = 5
result = my_param.value + 3
print(result) -- prints 8
print(my_param.data.name) -- prints hw_param1
You might be able to do something tricky by assigning a metatable to the global table _G, but I think that would be kind of tricky to get set up right and could lead to unexpected outcomes.
Edit:
If you really hate having to have a level of indirection, and you really want to be able to set it directly, here's how you can do it by setting the global table.
globalMetatable = {}
globalParamNames = {}
globalParams = {}
function globalMetatable.__index(t, k)
if globalParamNames[k] then
-- You can intercept the value here if you
-- want and pass it on to your C fuction.
print("Read from param " .. k)
return globalParams[k]
else
rawget(_G, k)
end
end
function globalMetatable.__newindex(t, k, v)
if globalParamNames[k] then
-- You can intercept the value here if you
-- want and pass it on to your C fuction.
print("Wrote to param " .. k)
globalParams[k] = v
else
rawset(_G, k, v)
end
end
setmetatable(_G, globalMetatable)
function createParameter(t)
globalParamNames[t.varname] = true
end
--------------------------------------------------------
createParameter{varname="my_param", name="hw_param1", type="number", min=0, max=100}
my_param = 5
result = my_param + 3
print(result) -- prints 8
print(my_param) -- prints 5
I want to iterate through array in a precondition.
But It seems precondition part doesn't allow use of "from" and "across" syntax.
Is there a way to iterate through array in precondition?
insert_last (s: STRING)
require
new_is_longer_than_prevs:
-- here I want to iterate through array "arr" and if length of s is longer than all other previously stored string values in array
do
arr.force (s, arr.upper + 1)
end
The version suggested in the other reply works in most cases (it assumes the lower index of the array is 1). However, the across loop can be used directly on the array rather than on its index range:
new_is_longer_than_prevs:
across arr as c all s.count > c.item.count end
This version works for any lower index and is slightly more efficient at run-time.
You can use 'across ... as ... all ... end' or 'across ... as ... some ... end' in precondition and postcondition. The 'all' version is used to valid if a condition is True for every iteration and the 'some' version is used to valid if the condition is True for at least one iteration. You can use some thing like this in your code:
insert_last (s: STRING)
require
new_is_longer_than_prevs:
across arr.lower |..| arr.upper as la_index all s.count > arr[la_index.item].count end
do
arr.force (s, arr.upper + 1)
end
I have a variable as follows
local armies = {
[1] = "ARMY_1",
[2] = "ARMY_3",
[3] = "ARMY_6",
[4] = "ARMY_7",
}
Now I want to do an action for each value. What is the best way to loop over the values? The typical thing I'm finding on the internet is this:
for i, armyName in pairs(armies) do
doStuffWithArmyName(armyName)
end
I don't like that as it results in an unused variable i. The following approach avoids that and is what I am currently using:
for i in pairs(armies) do
doStuffWithArmyName(armies[i])
end
However this is still not as readable and simple as I'd like, since this is iterating over the keys and then getting the value using the key (rather imperatively). Another boon I have with both approaches is that pairs is needed. The value being looped over here is one I have control over, and I'd prefer that it can be looped over as easily as possible.
Is there a better way to do such a loop if I only care about the values? Is there a way to address the concerns I listed?
I'm using Lua 5.0 (and am quite new to the language)
The idiomatic way to iterate over an array is:
for _, armyName in ipairs(armies) do
doStuffWithArmyName(armyName)
end
Note that:
Use ipairs over pairs for arrays
If the key isn't what you are interested, use _ as placeholder.
If, for some reason, that _ placeholder still concerns you, make your own iterator. Programming in Lua provides it as an example:
function values(t)
local i = 0
return function() i = i + 1; return t[i] end
end
Usage:
for v in values(armies) do
print(v)
end
I've embedded Lua into my C application, and am trying to figure out why a table created in my C code via:
lua_createtable(L, 0, numObjects);
and returned to Lua, will produce a result of zero when I call the following:
print("Num entries", table.getn(data))
(Where "data" is the table created by lua_createtable above)
There's clearly data in the table, as I can walk over each entry (string : userdata) pair via:
for key, val in pairs(data) do
...
end
But why does table.getn(data) return zero? Do I need to insert something into the meta of the table when I create it with lua_createtable? I've been looking at examples of lua_createtable use, and I haven't seen this done anywhere....
table.getn (which you shouldn't be using in Lua 5.1+. Use the length operator #) returns the number of elements in the array part of the table.
The array part is every key that starts with the number 1 and increases up until the first value that is nil (not present). If all of your keys are strings, then the size of the array part of your table is 0.
Although it's a costly (O(n) vs O(1) for simple lists), you can also add a method to count the elements of your map :
>> function table.map_length(t)
local c = 0
for k,v in pairs(t) do
c = c+1
end
return c
end
>> a = {spam="data1",egg='data2'}
>> table.map_length(a)
2
If you have such requirements, and if your environment allows you to do so think about using penlight that provides that kind of features and much more.
the # operator (and table.getn) effectivly return the size of the array section (though when you have a holey table the semantics are more complex)
It does not count anything in the hash part of the table (eg, string keys)
for k,v in pairs(tbl) do count = count + 1 end