Is it possible to move the for loop counter in lua? - memory

I am trying to move my i location forward and backward if a certain string arrives kind of like assembly code, is this possible using lua?
something like this:
local array = {"Hi", "Goodbye", "Cat"}
for i in pairs(array) do
if string.find(array[i], "Hi") then
move_to(3) -- so it will basically skip over "Goodbye" but I need this on a large scale so it can jump from 3 to 234 and then jump back to 1 etc etc
elseif array[i] == "Cat" then
print("Cat")
end
end
Also I cannot just make a variable to check if a jump is in progress and just ignore the other values until I am at the descried location, because then I cannot jump backwards
Thanks!

You cannot use a numeric for loop or a generic for loop with the standard iterator functions to do this. You cannot properly control their state from inside. Just use a while loop.
while notDoneCondition do
-- do stuff that may trigger the jumpCondition
if jumpCondition then
pos = jumpTarget
end
end

Related

(Lua) How do I increment a variable every time one of three if statements runs?

I'm building a moving and sensing bot in CoppelliaSim for school. CopelliaSim uses Lua for scripting. Basically every time the bot's forward sensors hit something, one of three if statements will run. I want it to count how many times any of these if statements runs, and once that count gets to a certain amount (like 20), I'll run something else, which will do the same thing (find collisions, add to the count, reach an amount, and switch back to the first).
i=0
result=sim.readProximitySensor(noseSensor) -- Read the proximity sensor
-- If we detected something, we set the backward mode:
if (result>0) then backUntilTime=sim.getSimulationTime()+3
print("Collision Detected")
i=i+1
print(i)
end
result=sim.readProximitySensor(noseSensor0) -- Read the proximity sensor
-- If we detected something, we set the backward mode:
if (result>0) then backUntilTime=sim.getSimulationTime()+3
print("Collision Detected")
i=i+1
print(i)
end
result=sim.readProximitySensor(noseSensor1) -- Read the proximity sensor
-- If we detected something, we set the backward mode:
if (result>0) then backUntilTime=sim.getSimulationTime()+3
print("Collision Detected")
i=i+1
print(i)
end
Above is the start of a function and one of the three If statements. I'm printing just to see if it actually increments. It is printing, but it is not incrementing (just 1 over and over). This bot has 3 sensors on it (an if statement for each sensor) and it adds 1 to i for the first collision and ignores the rest, even if it's from the same sensor. I feel like my problem is just some simple syntax issue with Lua that I don't know and can't find how to properly fix.
I'm happy to provide more code if this little snippet was not sufficient to answer this question.
Assuming that you have a looping function such as sysCall_actuation which is being executed per simulation step. As Joseph Sible-Reinstate Monica has already stated, you are setting your variable i back to zero every time a simulation step is executed. To achieve your goal, you would have to set your variable to 0 outside your function. There are two appropriate approaches to achieve that:
Define the variable outside any function, in the beginning of your file (or before you define any function that uses your variable e.g right before the definition of sysCall_actuation).
-- Beginning of the file.
local i = 0
..
function sysCall_actuation()
..
i = i + 1
..
end
Define your variable in sysCall_init function, which is the appropriate approach in CoppeliaSim.
function sysCall_init()
i = 0
..
end
Finally, you can use your variable in your sysCall_actuation function with basic comparison operations:
function sysCall_actuation()
..
if i > 20 then
i = 0 -- Reset 'i' so this function will not be running every step again and again.
-- Do something here.
..
end
As a side note, practice using local variables whenever you can, to keep the memory clean and avoid having ambiguous variables.

Multiple Messages & Issues Searching Lua Tables

I am attempting to make a Lua script for an online community I am a part of, I am having a problem when I attempt to search through a table array I believe. It doesn't detect the results I want.
The way it is supposed to work is that when someone types /gps [streetname] it will search the table at the top, detect the matching streetname & the coordinates and then set a waypoint to that relevant position.
At the moment it works when there is just one entry in the table, but when I put more, it will provide the error message for any non-matching streets & then the waypoint set message for the matching streets. I've Googled and don't appear to be able to find anything to help.
Any help would be appreciated.
waypoint = {
{404.08, -920.23, 'sinnerstreet', 'Sinner Street'},
{360.85, -956.46, 'atleestreet', 'Atlee Street'},
{500.48, -956.80, 'littlebighornavenue', 'Little Bighorn Avenue'},
}
RegisterCommand('gps', function(source, args, rawCommand)
for k,v in pairs(waypoint) do
x, y, streetname, displayname = table.unpack(v)
results = ""
if args[1] == nil then
if IsWaypointActive() then
SetWaypointOff()
TriggerEvent('chatMessage', '^1^*GPS Navigation: ^r^7Your GPS system has been reset.')
return end
elseif args[2] == nil and args[3] == nil then
results = args[1]
elseif args[2] ~= nil and args[3] == nil then
results = args[1] .. args[2]
else
results = args[1] .. args[2] .. args[3]
end
results = string.lower(results) -- This convertes the args into lower case
end
-- This locates the streetname and sets a waypoint to it for the player
if string.find(streetname, results) then
SetNewWaypoint(x, y)
TriggerEvent('chatMessage', '^1^*GPS Navigation: ^r^7Your waypoint to ^1' .. displayname .. '^r^7 has been set.')
else
TriggerEvent('chatMessage', '^1^*GPS Navigation: ^r^7There has been an error with your street name, please try again.')
end
end)
TriggerEvent('chat:addSuggestion', '/gps', 'This creates a waypoint to your designated street. ^*USE: /gps [streetname]')
To be honest, your code makes little to no sense, and it's probably because you're not using all the nice stuff Lua has to offer.
{404.08, -920.23, 'sinnerstreet', 'Sinner Street'},
You're storing redundant data there. The third value is really just the fourth one with spaces removed and all lowercase.
'sinnerstreet' == ('Sinner Street'):gsub("[^%l]", ""):lower()
In english: take "Sinner Street", globally (meaning in the entire string) substitute everything that is not a lowercase (%l) letter with nothing (""), then make the result of that lowercase. What you get is "sinnerstreet".
x, y, streetname, displayname = table.unpack(v)
Using globals there, that's not good. Globals are the devil. Don't use them.
Then, a few lines further down:
SetNewWaypoint(x, y)
Think about it for a moment. You set x and y in each iteration of your for loop. After the loop is done, they always contain the coordinates of the last waypoint you iterated over. I doubt that's what you want. Use local; it forces you to think what you want the scope of your variables to be, which will help you spot this kind of problem.
elseif args[2] ~= nil and args[3] == nil then
results = args[1] .. args[2]
Unless you specifically want to limit it to 3 arguments, which I doubt, you can also use table.concat to concatenate all the values in a sequence (read: array)
results = string.lower( table.concat(args) )
The thing that puzzles me is why you do this in a loop. For every waypoint, you set result to the same value, which is all the arguments concatenated and converted to lower case.
now what though? You check if result (what the user searched for) contains streetname, which, as we have previously found out, contains the name of the last waypoint in the list.
Using tables for searching
Lua has tables, one of if not the most powerful general-purpose data structure in programming.
local map = {}
for _,waypoint in ipairs(waypoints) do
map[waypoint[3]:lower()] = waypoint
end
This will get you something that looks about like this:
local map = {
sinnerstreet = {404.08, -920.23, 'sinnerstreet', 'Sinner Street'},
atleestreet = {360.85, -956.46, 'atleestreet', 'Atlee Street'},
littlebighornavenue ={500.48, -956.80, 'littlebighornavenue', 'Little Bighorn Avenue'},
}
and if you want to know if a street exists, you can just do this:
if map['atleestreet'] then
print(map.atleestreet[4])
end
if treats everything that isn't false or nil as truthy, so you can just write `map['atleestreet'] in the condition
my_table['text'] can be written as my_table.text
Looking up string indices in a table is pretty fast because of how it's implemented.
Conclusion
Try thinking your code through. If necessary, go through it line by line, writing down what values the variables hold in each moment. If you've been at it for a while, get some rest first or do something else for a while.
Then set your variables to local wherever possible (read: everywhere), figure out what needs to be inside and outside the loop and try again.
Remarks
Instead of if something == nil you can just write if not something, and if something ~= nil just if something
Apologies
Sorry for the long wall of text and using spaces inside brackets, but I wanted things to be specially easy to understand.

What is the paramater equivilant to?

function onTouch(part)
local human = part.Parent:findFirstChild("Humanoid")
if (human == nil) then
return
end
human.Health = human.Health - 10
end
script.Parent.Touched:connect(onTouch)
I'm new to coding in lua, and it is my first time using functions. I want to know what the "part" is equal to so that I can find out how to set up the human variable
local human = part.Parent:findFirstChild("Humanoid")
without using the "part," like what can I plug in so that works without even setting up part, because I want to do something with it in a loop:
local burnaffect = false
--local a = 0
function onTouch(part)
local human = part.Parent:findFirstChild("Humanoid")
if (human == nil and burnaffect == false) then
return
end
a = 0
burnaffect = true
end
script.Parent.Touched:connect(onTouch)
while burnaffect == true do
local part = --????
local human = part.Parent:findFirstChild("Humanoid")
human.Health = human.Health - 10
end
The code may seem confusing but I'm fairly new so I don't know what is best yet.
It looks like what you're trying to do is have a player "set on fire" when they touch a certain brick. The code below does exactly this, and I'll explain it line by line afterwards.
function onTouch(part)
local human = part.Parent:findFirstChild("Humanoid")
if (human == nil) then
return
end
local fire = Instance.new("Fire", part)
while (human.Health > 0) do
human.Health = human.Health - 10
wait(0.1)
end
end
script.Parent.Touched:connect(onTouch)
So, I'll start going through this.
function onTouch(part)
We need to define the function first and give it a name so that we can reference it in the Touched event later. The part parameter is the Part object that touched the script.Parent object and caused the Touched event to fire. So, ROBLOX will automatically call this function whenever something touches your script.Parent and automatically input the Part that touched it as that first parameter, part.
local human = part.Parent:findFirstChild("Humanoid")
This will get the Parent of the Part that touched the block (because if a player is touching the block, it isn't going to give us the Character, it's going to give us an Arm or a Leg in the part variable, because that's the actual Part that touched it, so we need to get that part's Parent. Then, once we have the Parent, we want to get the Humanoid object inside of the Character. Then, we put that Humanoid object inside of the human variable (if we could find one, otherwise we put nil into that human variable).
if (human == nil) then
We want to check if human is nil (which would mean we couldn't find a Humanoid object in the line before this one, which means whatever touched this isn't a real Character, so we'll want to return (which means stop running the function immediately).
local fire = Instance.new("Fire", part)
This line isn't necessary, I added it because I thought if you wanted to simulate burning, this would help. You can leave it out if you'd like. It will create a new Instance of type Fire, and places it inside of the part. That is to say, if a player's Leg touches this part, a Fire will be put inside of that leg, which will make it appear to ignite in flames.
while (human.Health > 0) do
We want to keep looping until the player dies (has a human.Health value of 0 or less) so we tell the loop to keep going while human.Health is greater than 0.
human.Health = human.Health - 10
We'll deincrement the human.Health value by 10, and then wait(0.1), which will cause the script to wait for 1/10 of a second (you can change this to a different number, but it is important to keep it as if you remove it, the loop will run extremely fast and kill the player immediately. If you want this to happen, you can remove the wait, but if you wanted to kill the player immediately, you could just set human.Health = 0 in the first place.
If you have any questions, feel free to ask! Hope this answered your question.
I remember when I used to use Lua for Roblox. The part is the part in the game that gets touched. You need to reference it so you can find the humanoid object it belongs to or lack of so your code can tell if it is a humanoid that touched it or not. Let me know if you have any further questions.

Fast implementation of queues in Lua?

I am making a game using Lua and I need to use Breadth-first search to implement a fast path-finding algorithm which finds the shortest path between the enemy AI and the player.
I will have up to 3 enemies using this algorithm at once and map is a 2-dimensional tile-based maze. I have already implemented collision detection so now all that is left to do is get a way for the enemies to find the shortest path to the player in a way that can be done quickly and and preferably about 80-90 times per second per enemy.
When I previously implemented breadth-first search, I used a queue in C++. From what I have read about Lua, stack implementations using tables are very efficient since the elements don't need to be shifted after push() (AKA table.insert) and pop() (table.remove) operations. However, I have theorized that queues with large sizes can be very inefficient in Lua, because if you want to insert/remove something from index 1 of a table, all other elements in the table must be shifted either upward or downward in the table.
Thus, I would like to ask some simple questions for those experienced in Lua. What is the simplest and/or fastest implementation of a queue in this language? Is it even possible to have a fast queue in Lua or is it just generally accepted that Lua will always be forced to "shift" all elements for a queue operation such as pop() or append()?
EDIT: I understand that the underlying implementation of "shifting elements" in Lua tables is written in C and is therefore quite optimized. I just would like to know if I have any better options for queues before I begin to write a simple table implementation.
A fast implementation of queue(actually double queue) in Lua is done by the book Programming in Lua:
List = {}
function List.new ()
return {first = 0, last = -1}
end
It can insert or remove an element at both ends in constant time, the key is to store both first and last.
function List.pushleft (list, value)
local first = list.first - 1
list.first = first
list[first] = value
end
function List.pushright (list, value)
local last = list.last + 1
list.last = last
list[last] = value
end
function List.popleft (list)
local first = list.first
if first > list.last then error("list is empty") end
local value = list[first]
list[first] = nil -- to allow garbage collection
list.first = first + 1
return value
end
function List.popright (list)
local last = list.last
if list.first > last then error("list is empty") end
local value = list[last]
list[last] = nil -- to allow garbage collection
list.last = last - 1
return value
end

Evaluating a math string in Corona Lua

I would like to evaluate a math string in my corona app. Right now I'm focusing on the trig functions, so let's let the example be the most difficult we're likely to face:
local expr = "2sin(4pi+2)+7"
My goal is for this to somehow be (either) evaluated as is with maybe a pi --> math.pi switch, or to even break it up. The breaking up would be much more difficult, however, since it COULD be as complicated a above, but could also just be sin(1).
So I would prefer to stay as close to the python eval(expr) function as possible, but if that can't happen, I am flexible.
The simplest way would be to replace sin with math.sin (pi with math.pi and so on), add missing multiplications signs, and run it through loadstring, but loadstring is not available in Corona environment.
This means you will need to write your own parser for these expressions. I found a discussion on Corona forums that may help you as a starting point: here, with some details and a demo here
This should do the trick, it is able to use the lua math functions without putting 'math.function' so just sqrt(100) works fine. I threw this together because I have seen this question asked way too many times. Hopes this helps :)
If you have any questions feel free to contact me at rayaman99#gmail.com
function evaluate(cmd,v) -- this uses recursion to solve math equations
--[[ We break it into pieces and solve tiny pieces at a time then put them back together
Example of whats going on
Lets say we have "5+5+5+5+5"
First we get this:
5+5+5+5 + 5
5+5+5 + 5
5+5 + 5
5 + 5
Take all the single 5's and do their opperation which is addition in this case and get 25 as our answer
if you want to visually see this with a custom expression, uncomment the code below that says '--print(l,o,r)'
]]
v=v or 0
local count=0
local function helper(o,v,r)-- a local helper function to speed things up and keep the code smaller
if type(v)=="string" then
if v:find("%D") then
v=tonumber(math[v]) or tonumber(_G[v]) -- This section allows global variables and variables from math to be used feel free to add your own enviroments
end
end
if type(r)=="string" then
if r:find("%D") then
r=tonumber(math[r]) or tonumber(_G[r]) -- A mirror from above but this affects the other side of the equation
-- Think about it as '5+a' and 'a+5' This mirror allows me to tackle both sides of the expression
end
end
local r=tonumber(r) or 0
if o=="+" then -- where we handle different math opperators
return r+v
elseif o=="-" then
return r-v
elseif o=="/" then
return r/v
elseif o=="*" then
return r*v
elseif o=="^" then
return r^v
end
end
for i,v in pairs(math) do
cmd=cmd:gsub(i.."(%b())",function(a)
a=a:sub(2,-2)
if a:sub(1,1)=="-" then
a="0"..a
end
return v(evaluate(a))
end)
end
cmd=cmd:gsub("%b()",function(a)
return evaluate(a:sub(2,-2))
end)
for l,o,r in cmd:gmatch("(.*)([%+%^%-%*/])(.*)") do -- iteration this breaks the expression into managable parts, when adding pieces into
--print(":",l,o,r) -- uncomment this to see how it does its thing
count=count+1 -- keep track for certain conditions
if l:find("[%+%^%-%*/]") then -- if I find that the lefthand side of the expression contains lets keep breaking it apart
v=helper(o,r,evaluate(l,v))-- evaluate again and do the helper function
else
if count==1 then
v=helper(o,r,l) -- Case where an expression contains one mathematical opperator
end
end
end
if count==0 then return (tonumber(cmd) or tonumber(math[cmd]) or tonumber(_G[cmd])) end
-- you can add your own enviroments as well... I use math and _G
return v
end
a=5
print(evaluate("2+2+2*2")) -- This still has work when it comes to pemdas; however, the use parentheses can order things!
print(evaluate("2+2+(2*2)"))-- <-- As seen here
print(evaluate("sqrt(100)"))
print(evaluate("sqrt(100)+abs(-100)"))
print(evaluate("sqrt(100+44)"))
print(evaluate("sqrt(100+44)/2"))
print(evaluate("5^2"))
print(evaluate("a")) -- that we stored above
print(evaluate("pi")) -- math.pi
print(evaluate("pi*2")) -- math.pi

Resources