Computercraft function that returns an array, use first element for boolean - lua

Edited for more details:
I'm trying to have a turtle that is sitting in front of a sapling wait for it to grow before cutting it down. It compares the log to the item in front until it matches. The system I'm currently using works, but I was hoping there was a slightly more minimal way to write it.
checkTarget = {
forward = function(tgt)
check = {turtle.inspect()} --creates table with first as boolean, second as information table
local rtn = {false, check[2]}
if type(tgt) == "table" then
for k, v in pairs(tgt) do
if check[2].name == v then
rtn = {true, v}
break
end
end
elseif tgt == nil then
return check[1]
elseif check[2].name == tgt then
rtn[1] = true
end
return rtn
end,--continued
This takes an argument, either a string or an array of strings, to compare against. When it checks the block in front it saves the detailed information to the second element in rtn and the first to a default of false. If the string matches the checked block's name, then it changes rtn[1] to true and returns all of it, which is the table at the bottom when doing checkTarget.forward("minecraft:log").
My question was, I am currently making a disposable variable to store the array that is returned from checkTarget, and then calling the variable's first element to get if it's true or not. I was hoping there was a way to include it in the if statement without the disposable variable (tempV)
repeat
local tempV = fox.checkTarget.forward("minecraft:log")
if tempV[1] then
cut()
fox.goTo({x = 0, y = 0, z = 0})
fox.face(0)
end
tempV = fox.checkTarget.forward("minecraft:log")
until not run
{
false,
{
state = {
stage = 0,
type = "birch",
},
name = "minecraft:sapling",
metadata = 2
}
}

Instead of
local tempV = fox.checkTarget.forward("minecraft:log")
if tempV[1] then
end
You can do
if fox.checkTarget.forward("minecraft:log")[1] then
end
and then calling the variable's first element to get if it's true or
not.
With tempV[1] you're not calling the first element, you're indexing it.
To call something you have to use the call operator () which doesn't make sense as a boolean is not callable.

Related

For/while loop with an f-string

How do I correctly perform a for-loop that returns as a f-string (like in Python.)
For example,
for i=10, 1, -1 do
test = string.gsub('checkbox[val = "a"]','a', i)
return test
end
Returns
checkbox[v10l = "10"]
However, I was expecting:
checkbox[val = "1"]
checkbox[val = "2"]
..
..
checkbox[val = "10"]
I'm honestly not sure what are you trying to do here. Lua has no supports for f-strings and you're trying to return multiple times from function?
This is probably the closest to what you want:
for i=1, 10 do
print(string.format('checkbox[val = "%d"]', i))
end
You're doing the following:
Running for loop from 10 to 1, in opposite direction of what you want.
Replacing all occurrences of string a in checkbox[val = "a"] with loop variable, giving you resulting string and assigning that to (global, which is not good) variable test.
Returning string you just got, thus exiting loop and function that contains loop.
If you're trying to pass multiple values from loop to the outside world, you can do one of the following:
Add them into table and return it:
local tab = {}
for i=1, 10 do
tab[i] = string.format('checkbox[val = "%d"]', i)
end
return tab
Accept callback, so caller passes in a function to call on each value:
function example(cb)
for i=1, 10 do
cb(string.format('checkbox[val = "%d"]', i))
end
end
example(print) -- Here, we pass `print` as a callback, but it's usually your own function
Choose whatever better suits your particular interface.

How to pass a table key in a function for use in a for loop?

For some reason it doesn't appear to work to pass in a table key as a function argument, what is the trick to do this?
I'm trying to wrap the for loop iteration technique in vanilla Lua into a function that has three arguments: (1) the table to iterate, (2) the table_key to check each time, and (3) the value to find. If a match is found, return it, otherwise return nil.
function table_find_match(table, table_key, match_value)
for i=1, #table do
local this = table[i]
if this[table_key] == match_value then
return this[table_key]
end
end
return nil
end
local table_example = {
{
key_example = "string_value_1"
},
{
key_example = "string_value_2"
}
}
local result = table_find_match(table_example, key_example, "string_value_1")
print(result)
Found a solution, if I pass in the table key as a string it works, such as
table_find_match(table_example, "key_example", "string_value_1")
but I really dislike having to convert it into a string, if anyone knows any other workaround to this please share
If you pass it like table_find_match(table_example, key_example, "string_value_1")
the key_example is now considered as a (nil) variable if not defined before executing, so it has to be like
local key_example = "key_example"
local result = table_find_match(table_example, key_example, "string_value_1")
print(result)

Re-initialize table without losing references

I'd like to re-initialize a table without losing references to it.
What I want to achieve is defining tables in files, and when a file is changed (with a text editor) the file is reloaded, changing the table. Of course this doesn't change the table but creates a new instance, old references will still point to the old table.
Any suggestions?
EDIT: I want to elaborate on what I want to achieve. An example with game characters and weapons. I want to modify the weapons.lua and so affect the characters.
-- weapons.lua
sword = { damage = 3 }
-- characters.lua
character = { weapon = sword }
Adding a level of indirection (putting "sword" inside "weapons") like suggested by JWT doesn't help, unless I split character into { weaponTable = weapons, weaponKey = "sword" } but I don't see this as an option.
Anchor everything that needs to survive in the global environment. Nesting is fine, and this doesn't have to be your primary reference. (You can still local things, but make sure to initialize those local variables from the global environment and update the global if you change the local.)
To initialize the global values, say
foo = foo or value -- if foo is always true-ish
bar = (bar == nil) and value or bar -- if bar may be `false`
To initialize or update tables, you can
foo = foo or { }
foo.bar = foo.bar or 23
foo.baz = foo.baz or 42
-- and so on...
but that's kinda icky, so maybe say
function reinit( new, old ) -- (re)initialize one level, prefer old
if old == nil then return new end
if type( old ) ~= "table" then return old end
for k, v in pairs( new ) do
if old[k] == nil then old[k] = v end
end
return old
end
function reset( new, old ) -- (re)initialize one level, prefer new
if old == nil then return new end
if type( old ) ~= "table" then return new end
for k, v in pairs( new ) do old[k] = v end
return old
end
and then just
foo = reinit( { bar = 23, baz = 42 }, foo ) -- only setting if not defined
-- or
foo = reset( { bar = 23, baz = 42 }, foo ) -- always overriding given fields
or maybe make it even more fancy and say
function traverse( t, path )
local here, last, lastk, created = t
-- follow path of several keys starting from t, creating tables as needed
for k in path:gmatch "[^.]+" do
k = tonumber( k ) or k -- convert all-number keys to integer (for arrays)
local next = here[k]
if not next then
next, created = { }, true
here[k] = next
else
created = false
end
lastk, last, here = k, here, next
end
return here, last, lastk, created
end
function repopulate( path, value, update )
update = update or reinit -- pass 'reset' as 'update' for the other behavior
-- or something entirely different if that's what you need
local here, last, lastk, created = traverse( _G, path )
if type( value ) == "table" then
update( value, here )
else
if created then last[lastk] = nil end -- created one level too much
update( { [lastk] = value }, last )
end
end
and then (with arbitrary nesting)
-- No need to create 'state' first if it doesn't exist yet!
-- (If it exists, it will get updated, otherwise it's created)
repopulate( "state.player.weapon", { kind = "sword", damage = 11 } )
-- Do keep in mind that generally update order is relevant -- you may want to
-- give a newly created player a default inventory, but you may not want to
-- "refill" the player's inventory on every reload. So generally `repopulate`
-- with the parent and all child nodes for from-scratch creation, then
-- `repopulate` the child nodes that need to be checked & potentially updated
-- as well.
-- (So here you'd probably repopulate `state.player` first and then
-- `state.player.weapon` or other fields only if they should be updated anyway.)
-- e.g.:
repopulate( "state.player", {
x = 0, y = 0, hp = 100, mp = 100, level = 0, -- and so on
weapon = { kind = "sword", damage = 11 }, -- etc. etc.
} )
-- on reload always force a sword-kind weapon, leave rest (damage, ...) as-is
repopulate( "state.player.weapon", { kind = "sword" }, reset )
-- or alternatively: only if player has no weapon, give them a sword
repopulate( "state.player.weapon", { kind = "sword", damage = 3 } )
And you can go further, add metamethods to hide some of that shuffling, define different update policies, ... – you've seen some of the possibilities, now go and build your own version that fits your style and your code.
(While you're free to use the above code in any way, please note that it was written ad-hoc in the browser. I did some testing, fixed some glitches, and it seems to work now, but don't be surprised if there's still one or two bugs hiding in there. So play with this, change it, break it (and see how/why it breaks), adapt and extend it, ... – but unless you completely understand what it does and can fix any bugs, I strongly suggest you write your own version, or just stick to the basics. You probably don't need everything that this does, and you're likely to need other things that this doesn't do. As this is a central part of the reloading/live-coding infrastructure and everything has to be adapted to be reload-compatible, any mismatch between your tooling and what you actually need will result in a lot of pain everywhere in your code. So if you need something like this, put in a day or two to make it work the way you need it to, or you will regret it.)
(Free bonus warning: If you do OOP, you'll probably have to store and retrieve your classes instead of creating them every time, otherwise old objects from previous iterations will miss code updates and still run their old methods. I've forgotten about that more than just a couple of times and wasted several hours pondering "why isn't it fixed now?!?" after repeatedly re-loading code... So remember to anchor your metatables, anchor your classes!)
You could nest the tables in another table.
Before:
local a = { 1, 2, 3 }
local b = { 7, 8, 9 }
print(a[2] + b[2]) -- #=> 10
After:
local lookup = {
a = { 1, 2, 3 },
b = { 7, 8, 9 }
}
print(lookup.a[2] + lookup.b[2]) -- #=> 10
Then you can fully replace (or just update) a table in the lookup table and any dependent statements will use that updated value:
lookup.a = { 100, 50, 0 }
print(lookup.a[2] + lookup.b[2]) -- #=> 58
I don't know if it's exactly what you needed (As an ID is necessary) but I hope it will fit your needs.
meta = {
tables = {},
__call = function(arg, t)
for k, v in pairs(t) do
arg[k] = v
end
end,
__bnot = function(arg)
return arg.__key
end,
__newindex = function(arg, key, val)
meta.tables[arg.__key][key] = val
end,
__index = function(arg, key)
return meta.tables[arg.__key][key]
end
}
function RefTable(arg)
local newtable = {}
if arg ~= nil then
newtable.__key = arg
setmetatable(newtable, meta)
if meta.tables[arg] == nil then
meta.tables[arg] = {}
end
else
error("RefTable can't have nil key")
end
return newtable
end
-- Using the RefTable
sword = RefTable("Sword")
sword({damage = 3})
sword.cooldown = 10
character = {sword = sword}
print("base", sword.damage, sword.cooldown)
print("embed", character.sword.damage, character.sword.cooldown)
sword = RefTable("Sword")
sword({damage = 8, cooldown = 50})
print("embed2", character.sword.damage, character.sword.cooldown)
print(sword.__key, sword.cooldown)
ref = RefTable("Sword")
ref.cooldown = 1000
print(sword.cooldown)

Accessing the key in the value (right side) of a table key affectation in Lua

The goal is to match a key of a table with a value depending of the key.
example = { ["dummy"] = this .. " example" }
print example.dummy -- print "dummy example"
Where this is the keyword to refer to the key. Is there any way to do that in Lua?
There is no way to do this directly.
You could do some preprocessing:
example = { ["dummy"] = "{THIS} example" }
for k,v in pairs(example) do
example[k]=v:gsub("{THIS}",k)
end
print(example.dummy)
It's not possible to have as clean an expression as:
t = { foo = this .. ' bar' }
because this would always be expressed without relation to the key or the table. That is, you can't capture an expression as the value of a table entry.
What is possible is implementing some level of indirection using metatables and functions, but it's hardly pretty. Here we do fetch-time evaluation. You could also recompute the results.
local function indirect_table ()
local uptable = {}
return setmetatable({}, {
__index = function (self, key)
local value = uptable[key]
return type(value) == 'function' and uptable[key](key) or value
end,
__newindex = function (self, key, value)
uptable[key] = value
--[[precompute, with no need for an uptable, or __index:
`rawset(self, key, value(key)`]]
end
})
end
local tab = indirect_table()
tab.foo = function (key) return key .. 'bar' end
print(tab.foo) --> 'foobar'
Note: this example uses a closure, but you can implement this kind of pattern using getmetatable as well.
Personally, I'd abstract this into an indirection pattern that allows arbitrary keys and values, and their actions to be specified. I figure this kind of pattern would mostly be used programatically, rather than by hand, where the results of key values are dependent on the inputs received. Again, not pretty, but a little more robust (optional actions).
local function I (_, value) return value end
local K = setmetatable({
__call = function (actor, key)
return actor.action(key, actor.value)
end
}, {
__call = function (K, value, action)
return setmetatable({ value = value, action = action or I }, K)
end
})
local T = setmetatable({
__newindex = function (self, key, value)
if getmetatable(value) == K then
value = value(key)
end
rawset(self, key, value)
end
}, {
__call = function (T, o)
return setmetatable(o or {}, T)
end
})
Simple use:
local function concat (left, right) return left .. right end
local t = T {}
t.foo = K('bar', concat) -- with a common action
t.zar = K({}, unknown_action) -- without action (`nil`)
t.qux = 'qaz' -- standard
print(t.foo, t.zar, t.qux)
This is strange metaprogramming. I'd double-check the reasoning for needing such an approach. Perhaps you're falling into an XY Problem trap? Really feels like a solution to a problem that doesn't need to exist in the first place.

How to get variables that not declared yet but will declared soon?

How can I get variables that not declared yet?
Here are simple example:
a = b
b = 123
What I want from these 2 lines is a << 123. But obv it doesn't work.
I know the easy way to get the answer a = 123 is cut 1st line and paste it to lower than 2nd line.
But I'm in some problem. I need some function like 'WillDeclaredVar()' that I can use in like this:
a = WillDeclaredVar(b)
sheepCount = 123
b = sheepCount
print(a)
so I can get the answer '123'.
Or there are any built-in functions that will allows me to do similar thing?
===
I think the link given by timrau is not telling my case. the key point is how to get Variables 'that not declared yet'.
===
Adding actual Code:
triggerCount = 0 -- Counting number of 'Trigger' function
local Trigger = function (t)
triggerCount = triggerCount + 1
return Trigger (t)
end
-- following Triggers are same as while statement.
-- following Triggers doing: Add 1 MarineCount until get 64000 MarineCount
Trigger { -- Here the Trigger function. Now triggerCount = 1.
players = {P1}
actions = {
SetDeaths(P1, Add, 1, "Terran Marine")
},
flag = {preserved},
}
Portal(LoopStart);
-- function Portal(VariableName) returns VariableName = triggerCount. So LoopStart = 1.
Trigger { -- Now triggerCount = 2.
players = {P1}
actions = {
LinkList(LoopEnd, LoopStart);
-- function LinkList(From, To) changes 'From' Trigger's next pointer to the 'To' Trigger.
-- But now the problem happens. Because 'LoopEnd' is not declared yet.
},
flag = {preserved},
}
Trigger { -- Now triggerCount = 3.
players = {P1}
conditions = {
Deaths(P1, Exactly, 64000, "Terran Marine");
}
actions = {
_LinkList(LoopEnd);
-- Reset LoopEnd's next pointer(= LoopEscape) if MarineCount hits 64000
},
flag = {preserved},
}
Portal(LoopEnd); -- LoopEnd = 3.
Changing Order of Triggers will break the Trigger logic(while statement).
All i want is get easy to coding. To put in bluntly, I don't need to solve this problem(get undeclared var). I can imagine a few ways to avoid it. But if i using these ways then the coding work will be very complicated and the difficulty of coding will increases greatly. The difficulty made me stop coding in recent months.
How can I get variables that not declared yet?
Short of time travel, you can't.
Your example code doesn't explain the motivation for the question, because this:
a = WillDeclaredVar(b)
sheepCount = 123
b = sheepCount
print(a)
Can trivially be rearranged into this:
sheepCount = 123
b = sheepCount
a = WillDeclaredVar(b)
print(a)
It would be easier to answer your question if you showed the actual problem you're trying to solve (to avoid an XY problem).
However, as stated there are few things we can note.
First, you need to distinguish between declaring a variable and giving it a value. In Lua you can say:
local b
To declare b as a local variable, which presumably will make a slot for it in the stack frame and let you bind closures to it, before you give it a value. However, the line:
a = WillDeclaredVar(b)
Will pass WillDeclaredVar the value that b currently has, and there's no way for a to change retroactively as a result of b being assigned a new value. That's simply not going to happen, ever. Neither a nor WillDeclaredVar are even aware that b exists, they are receive the value it contains at the point of call.
You could however bind the variable b to a closure which will fetch b's current value when needed.
-- declare b before giving it a value, aka "forward reference"
local b
a = function() return b end
sheepCount = 123
b = sheepCount
print(a()) -- call a to get b's current value
Another way to do that would be to make b a global variable, which is really just a key into your environment table, so you could say:
a = WillDeclaredVar('b')
And have a be some object that can fetch the current value of __ENV['b'] when required.
However, neither of these will support this syntax:
print(a)
a needs to be a function, something that looks up the value of b when needed rather than simply holding a previously computed value. You could do it in this particular instance (i.e. a needs to be convertable to a string), by creating a proxy object that implements __tostring.
function WillDeclaredVar(variableName)
local proxy = { environment = _ENV or _G, variableName = variableName }
return setmetatable(proxy, {
__tostring = function(proxy)
return proxy.environment[proxy.variableName]
end
})
end
-- a will compute a value based on the current value of b when needed
a = WillDeclaredVar('b')
sheepCount = 123
b = sheepCount
print(a)
Output:
123
To make var1 be a reference for var2 write var1 = ReferenceF or var2 (please note a space inside "ReferenceFor"!)
do
local values, references, reference_flag = {}, {}
setmetatable(_G, {
__index = function (_, name)
if name == 'ReferenceF' then
reference_flag = true
elseif reference_flag then
reference_flag = false
return {[references] = name}
elseif references[name] then
return _G[references[name]]
else
return values[name]
end
end,
__newindex = function (_, name, val)
if type(val) == 'table' and val[references] then
references[name] = val[references]
else
values[name] = val
end
end
})
end
a = ReferenceF or b -- a is Reference For b
b = ReferenceF or c -- b is Reference For c
sheepCount = 123
c = sheepCount
print(a, b, c) --> 123 123 123

Resources