[LUA ]Making a random song picker - lua

Been trying to get a random song "I'm using fruit placeholders for now" and it always returns Orange
and I can't seem to figure out why.
math.randomseed(os.time())
local songLists = {"Apple", "Orange", "Pineapple"}
local songValue = math.random(#songLists)
local songSelected = songLists[songValue]
print(tostring(songSelected))

Lua uses PRNG (pseudorandom number generator) to calculate random number.
math.randomseed(os.time()) initalizes formula with some sort of data current time (not the best decision). os.time() gives current time with prezision of 1s, it means if you execute this code in loop within part of second you will get the same seed number (if clock not changes). The best practice is to initialize random math.randomseed(...) once application is started and with better random data as process id, os.clock(), ...
Most likely your problem is math.randomseed(...) is executed many times with the same seed data in this code or may be in anothe part of application.

Related

How to efficiently extract all values in a large master table that start with a specified string

I'm designing the UI for a Lua program, one element of which requires the user to either select an existing value from a master table or create a new value in that table.
I would normally use an IUP list with EDITBOX = "YES".
However, the number of items that the user can select may run into many hundreds or possibly thousands, and the performance when populating the list in iup (and also selecting from it) is unacceptably slow. I cannot control the number of items in the table.
My current thinking is to create a list with an editbox, but without any values. As the user types into the editbox (after perhaps 2-3 characters) the list would populate with the subset of table items that start with the characters typed. The user could then select an item from the list or keep typing to narrow the options or create a new item.
For this to work, I need to be able to create a new table with the items from the master table that start with the entered characters.
One option would be to iterate through the master table using the Penlight 'startswith' function to create the new table:
require "pl.init"
local subtable = {} --empty result table
local startstring = "xyz" -- will actually be set by the iup control
for _, v in ipairs (mastertable) do
if stringx.startswith(v, startstring) then
table.insert(subtable,v)
end
end
However, I'm worried about the performance of doing that if the master table is huge. Is there a more efficient way to code this, or a different way I could implement the UI?
There are various approaches you can take to improve the big-O performance of your prefix search, at the cost of increased code complexity; that said, given the size of your dataset (thousands of items) and the intended use (triggered by user interaction, rather than e.g. game logic that needs to run every frame), I think a simple linear search over the options is almost certainly going to be fast enough.
To test this theory, I timed the following code:
local dict = {}
for word in io.lines('/usr/share/dict/words') do
table.insert(dict, word)
end
local matched = {}
local search = "^" .. (...)
for _,word in ipairs(dict) do
if word:match(search) then
table.insert(matched, word)
end
end
print('Found '..#matched..' words.')
I used /usr/bin/time -v and tried it with both lua 5.2 and luaJIT.
Note that this is fairly pessimistic compared to your code:
no attempt made to localize library functions that are repeatedly called, or use # instead of table.insert
timing includes not just the search but also the cost of loading the dictionary into memory in the first place
string.match is almost certainly slower than stringx.startswith
dictionary contains ~100k entries rather than the "hundreds to thousands" you expect in your application
Even with all those caveats, it costs 50-100ms in lua5.2 and 30-50ms in luaJIT, over 50 runs.
If I use os.clock() to time the actual search, it consistently costs about 10ms in lua5.2 and 3-4 in luajit.
Now, this is on a fairly fast laptop (Core i7), but also non-optimized code running on a dataset 10-100x larger than you expect to process; given that, I suspect that the naïve approach of just looping over the entries calling startswith will be plenty fast for your purposes, and result in code that's significantly simpler and easier to debug.

Store machine status on Graphite time-series to later extract KPIs

having a machine which sends (not regularly) its status values 0, 1, 2, we're storing it in Graphite. Now the status means:
0 - stopped
1 - working
2 - stopped by anomaly
The requested KPIs to extract are the classical ones: how much time on status 0 or 1 or 2 in a day or a week? Before reinventing the wheel, we're looking at the best way to compute those PKIs and if in Graphite (or possible other time-series solution) there are already function which deal with summing the time where the data point value is just a condition. Clearly the time intervals to sum are not stored, it's the time elapsed between a data point and the next one.
Or should the data pre-processed to compute the time intervals and then store three data sets like: status.working, status.stopped, status.alarm and for each store when the specific "event" started and how much it lasted?
There are other KPIs, for example the number of alarms in a day. Receiving two status data points in a row both indicating status "2" is actually a single alarm condition and must count as 1.
So, is there a best way to store such data without pre-processing it? It sounds to be a common pattern but (shame on us?) we have not found this topic well explored.
Thanks.
Graphite has a number of functions that could help you here. One that stands out is the summarize() function in which you can pass an aggregation method (in this case sum) and a duration in minutes/hours/days/weeks/etc), take a look here
isNonNull is another useful function: it can be used to determine the existence of a datapoint regardless of the value.
When you say that the machie reports a value 0 to indicate it has stopped - does it actually send that value or does it report nothing? This is an important detail and will have some bearing on the end result of your solution.

Running a server with LUA and I need to trigger a function at a specific time every day

So I'm running a LUA script that executes every minute, this is controlled by software and I can't control the timing of the execution. I would like to check the time every day and trigger a function at a specific time. However, I would like to execute another script 5 minutes before that happens.
Right now I'm doing a string comparison using os.date() and parsing it to a string. It works, but the code isn't pretty and if the time changes, i have to manually change the time in two different variables, I'm pretty new to LUA so I've been having difficulty figuring out the best way to do this.
So the question is, how do I set a time variable, and compare that variable to os.date (or os.time) ?
There's no fancy way to do timers in pure Lua. What you can do to avoid os.date() strings, is to generate timestamps with preset dates, os.time accepts a key-value table to set a date:
timestamp = os.time({year=2019, month=1, day=n})
By iteratively increasing the n variable, you will receive a timestamp for every new n day after January 1st 2019. E.g.
os.date("%Y-%m-%d %H-%M-%S",os.time({year=2019,month=1,day=900})
--> 2021-06-18 12-00-00
If you can't save the day variable to keep track of (between application restarts), get the current "today" day and iterate from there:
os.date("%Y-%m-%d %H-%M-%S",
os.time({year=os.date("%Y"),month=os.date("%m"),day=os.date("%d")+n}
)
Using os.date with custom format and os.time makes your code independent of currently set date locale.
After you have determined the timestamp of the first task, offset the second actual task by five minutes secondTaskTimestamp = fistTaskTimestamp + 5*60 (or use os.time again). Your timer checker only should compare timestamps by now.
Now when you have to change the pre-configured time, you will only have to change the time-date of the first task, and the second task will be automatically offset.
Related: How do I execute a global function on a specific day at a specific time in Lua?

Real Random numbers

I am trying to get a random number of 0-20 like so
RandomRange(0, 20)
I know alot of software when using there built in function for random it will give the same random numbers each time the program is ran, thus not so random.. Does RandomRange act this way? I could not test as not near programming computer. If Answer is yes, then how can i get a Really Random number?
Thanks
http://www.delphibasics.co.uk/RTL.asp?Name=Random
http://www.delphibasics.co.uk/RTL.asp?Name=Randomize
The Randomize command will re-seed the random number generator based on the current time of day. With that, the only way you'll get the exact same sequence of "random" numbers is if you run the program at exactly the same time of day (usually measured down to fractions of a second for these kinds of purposes).
EDIT: You can also use RandSeed (http://www.delphibasics.co.uk/RTL.asp?Name=RandSeed) to select the seed yourself. This is useful if you want to test the same sequence multiple times, for debugging, or want to randomize based on some other seed than time of day.

how to use a timer in Lua

I capture data with tshark and save certain data from the packet header to process them in order to detect some incedants in the network. I saved the data in a table in my lua program (which is running in the cmd with tshark using the command (-Xlua_script:))
and now i want to process the data of each minute alone while capturing is running. It's an online processing. Firstly:Any body knows if this could be implemented?Secondly I need a timer, I don't know how to do this, and i want a way that i can take the data in the tables to process them, reset the tables to get the new data of the next minute without losing any data.
Any suggestions or ideas??
there isn't the concept of a 'timer' in lua like some other languages, where you can create one and set up an event handler and have your main program notified when the timer goes off... however you can periodically check os.clock() to determine how long its been since you've done some processing and if a minute has elapsed, go ahead and process the data.
something like this might be what you need:
lastTimeProcessed = os.clock()
function IsTimeToProcess(currentTime)
span = currentTime - lastTimeProcessed
if span >= 60 then
lastTimeProcessed = currentTime
return true
end
return false
end
while true do
if IsTimeToProcess(os.clock()) then
-- process some data here
end
-- otherwise do another round of whatever you're doing
end

Resources