Polling a database with items of different priority - lua

Given a list of items that have priorities ranging between 1 and 4 where one is the most important and 4 is the least important, how can I create a system that polls a central database for updates on the list of items, but polling the higher priority items more frequently than the lower priority items?
for example:
I have items a, b, and c that have priority values 1, 2, and three respectively.
In a perfectly functioning program, item a should be polling for updates more often than b and c, and b should be polling more frequently than c.
My main issue is designing a system in which all items are still polled regularly but the highest priority are polled more frequently.
Sorry I don't have more details but I don't really have any source code or anything to build off of, I'm kinda at a blank slate right now.
Also I'm working Lua, but I'm just looking for a rough pseudo-code version of ideas, I'd like to work out the exact implementation my self. For simplicity sake, polling the database can be represented by a method call: getDatabaseInfo(itemIndex);
All answers appreciated, thank you for your time!

local items = { -- all your items are here
{name = "item #1", update_period = 1 },
{name = "item #2", update_period = 1.5}, -- updates for item#2 will happen 1.5 times less frequent than updates for item#1
{name = "item #3", update_period = 2 }, -- updates for item#3 will happen 2 times less frequent than updates for item#1
{name = "item #4", update_period = 3 }, -- updates for item#4 will happen 3 times less frequent than updates for item#1
}
local function update_one_item()
local min_ctr, itemIndex = math.huge
for idx, item in ipairs(items) do
item.current_counter = item.current_counter or 0
if item.current_counter < min_ctr then
min_ctr = item.current_counter
itemIndex = idx
end
end
for idx, item in ipairs(items) do
item.current_counter = item.current_counter - min_ctr
end
items[itemIndex].current_counter = items[itemIndex].current_counter + items[itemIndex].update_period
getDatabaseInfo(itemIndex);
print(items[itemIndex].name.." updated")
end
for _ = 1, 20 do
update_one_item()
end
Output:
item #1 updated
item #2 updated
item #3 updated
item #4 updated
item #1 updated
item #2 updated
item #1 updated
item #3 updated
item #1 updated
item #2 updated
item #4 updated
item #1 updated
item #3 updated
item #2 updated
item #1 updated
item #1 updated
item #2 updated
item #3 updated
item #4 updated
item #1 updated

Depending on how often you wish for each value to be updated, a loop like this could work.
Things with primary priority are updated every time
Things with secondary priority are updated every 2 cycles
Things with tertiary priority are updated every 3 cycles
Things with quaternary priority are updated every 4 cycles
Code:
for i = 1,math.huge do
for ii = 1,#items do do
if getPriority(ii) == 1 then
items[ii] = getDatabaseInfo(ii)
elseif i%2 == 0 and getPriority(ii) == 2 then
items[ii] = getDatabaseInfo(ii)
elseif i%3 == 0 and getPriority(ii) == 3 then
items[ii] = getDatabaseInfo(ii)
elseif i%4 == 0 and GetPriority(ii) == 4 then
items[ii] = getDatabaseInfo(ii)
end
end
sleep(interval)
end
The way this works is it does a check for if the current iteration number is divisible by 1,2,3, or 4.
One could add a 3rd nested loop which loops over all priorities, so you can have limitless amounts of priorities, but I'll leave that as an exercise to the reader :)
As noted by Piglet in the comments, you can use this shortcut to make the code more efficient:
if i % getPriority(ii) == 0 then ...

Related

Automatically create new row when checkbox is ticked in Google Sheets

I have a dataset of jobs for a gardening company.
status # ID Date Name Frequency
☐ 4 340 09/06/20 Jack Once Off
☐ 1 543 22/05/20 Sarah Weekly
☐ 3 121 01/05/20 Emily Fortnightly
☐ 3 577 11/06/20 Peter Once Off
When a booking is complete I want to check the box in the first column which will then create a new row with the following conditions
row is created only for jobs that are "weekly" or "fortnighly". Once off jobs wont create a row when the box is checked
The date in the new row is a week or a fortnight in the future of the original row depending on its frequency value
The job # goes up by one from the original row #
The ID, name and frequency rows remain the same
For example if I ticked the checkbox for the 3rd row it would create a new row like this:
☐ 4 121 15/05/20 Emily Fortnightly
Is this possible? Thanks!
Your goal is possible by using a custom script. You can try creating a bound script in your spreadsheet file and copy/paste this sample script below:
[updated]
SCRIPT:
function onEdit() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getActiveSheet();
var checkbox = sheet.getActiveRange().getValue();
var selectedRow = sheet.getActiveRange().getRow();
var selectedFreq = sheet.getRange(selectedRow, 6).getValue();
//Run if selected cell has a checkbox and ticked
while(checkbox == true){
addValues(selectedRow, sheet, selectedFreq);
break;
}
}
//Function to process values based on frequency
function addValues(selectedRow, sheet, selectedFreq){
var number = sheet.getRange(selectedRow,2).getValue();
var date = new Date(sheet.getRange(selectedRow,4).getValue());
if(selectedFreq == "Fortnightly"){
//Insert a new row after the ticked checkbox, setup a new date with 14 days (or 2 weeks), increments the # with 1 & the rest of the data are copied
var newDate = new Date(date.setDate(date.getDate()+14));
sheet.appendRow(["",number+1,sheet.getRange(selectedRow,3).getValue(),newDate,sheet.getRange(selectedRow,5).getValue(),sheet.getRange(selectedRow,6).getValue()]);
sheet.getRange("G"+selectedRow+":S"+selectedRow).copyTo(sheet.getRange("G"+sheet.getLastRow()+":S"+selectedRow)); //If you want to copy the rest of the columns, e.g. from range G:S
sheet.getRange(sheet.getLastRow(),1).insertCheckboxes();
sheet.getRange(sheet.getLastRow(),4).setValue(sheet.getRange(sheet.getLastRow(),4).getValue()).setNumberFormat("dd/MM/yy");
}
if(selectedFreq == "Weekly"){
//Insert a new row after the ticked checkbox, setup a new date with 7 days (1 week), increments the # with 1 & the rest of the data are copied
var newDate = new Date(date.setDate(date.getDate()+7));
sheet.appendRow(["",number+1,sheet.getRange(selectedRow,3).getValue(),newDate,sheet.getRange(selectedRow,5).getValue(),sheet.getRange(selectedRow,6).getValue()]);
sheet.getRange("G"+selectedRow+":S"+selectedRow).copyTo(sheet.getRange("G"+sheet.getLastRow()+":S"+selectedRow)); //If you want to copy the rest of the columns, e.g. from range G:S
sheet.getRange(sheet.getLastRow(),1).insertCheckboxes();
sheet.getRange(sheet.getLastRow(),4).setValue(sheet.getRange(sheet.getLastRow(),4).getValue()).setNumberFormat("dd/MM/yy");
}
}
[updated]
SAMPLE RESULT:
Sample sheet with data
Once script has been saved, ticked some check box on the sheet and new rows were automatically added at the bottom if frequency contains either "Fortnightly" or "Weekly":

Get value at index in table

Is it possible for me to cycle this table asynchronously without really checking state? I would like to be able to do something colors[count % 6] or similar where I don't need to check explicitly which state (count) I'm at.
colors = {
red = {max.R,0,0},
green = {0,max.G,0},
blue = {0,0,max.B},
purple = {max.R,0,max.B},
pink = {max.R,0.1*max.G,0.8*max.B},
yellow = {max.R*0.95,max.G*0.64,0.5*max.B}
}
I have a timer callback where I want to go through the table one color at a time , but to do so currently I have to do it like if count == 0 then setColor(colors.red) ...
One way is to use another index table:
local index = {"red", "green", "blue", "purple", "pink", "yellow"}
Then you can use colors[index[count % 6 + 1]]. The downside is, if the keys of colors are modified, index needs to be updated manually.

Decide different outcomes of team position by score

I don't know if this is the right place to ask such a question but I hope so! I'm developing a game for fun where you have different teams who get points for each kick they can do in volley with a football. When the game is over I'm counting the score of each team and sort them by the best score.
So say:
team 1 = 9 points
team 2 = 7 points
team 3 = 20 points
Then I've sorted it by the best one, so the positions are:
team 3 = 20 points
team 1 = 9 points
team 2 = 7 points
Then I print it on the screen and say like "Team 3 comes on first place with 20 points". "Team 1...second", "team 2 .....third".
The problem is when some of the teams get the same score. So say it ends up like this:
team 1 = 9 points
team 2 = 9 points
team 3 = 20 points
In such case I want it to print like: "Team 3 comes on first place with 20 points", "Team 1 and Team 2 comes on second place with 9 points each".
Here is the problem, I've been thinking and thinking but I can't come up with a smart solution of how to make the code consider a shared first/second/third place.
Here is my current code that doesn't take account of that:
for var i = 0; i < teamScoreArray.count; ++i { //sorted array by best score first
var tmpTeam:Team = teamScoreArray[i]
if i == 0{
firstPlacelbl.text = "On first place comes \(tmpTeam.teamName) with \(tmpTeam.teamScore) points"
}
if i == 1{
secondPlacelbl.text = "On second place comes \(tmpTeam.teamName) with \(tmpTeam.teamScore) points"
}
if i == 2{
thirdPlacelbl.text = "On third place comes \(tmpTeam.teamName) with \(tmpTeam.teamScore) points"
}
if i == 3{
fourthPlacelbl.text = "On fourth place comes \(tmpTeam.teamName) with \(tmpTeam.teamScore) points"
}
prevScore = tmpTeam.teamScore
}
Does anyone have any idea of how to make this?
Thank you in advance!
Increase the rank only when the score in the current iteration differs from the previous one:
var rank = 0
var previousScore = 0
for team in teamScoreArray {
if team.teamScore != previousScore {
rank += 1
}
println("Rank \(rank): \(team.teamName)")
previousScore = team.teamScore
}

Corona SDK: Having Single and Double Tap Events on One Object

I'm trying to have a different amount of force applied to an object when the screen is tapped a different amount of times ( only once and twice ).
I'm not sure what I'm doing wrong. Here is the code:
local function moveUp(event)
if event.numTaps > 1 then
jumper:applyForce( 0, 250, jumper.x, jumper.y )
elseif event.numTaps < 1 then
jumper:applyForce( 0, 0, jumper.x, jumper.y )
else
jumper:applyForce( 0, 200, jumper.x, jumper.y )
end
end
-- start game
createPlayScreen( )
system.setTapDelay( 2 )
Runtime:addEventListener("tap", moveUp)
I've tried moving the Runtime:addEventListener into the function. I've also tried have the event.numTaps == 2 and event.numTaps == 1, but to no avail.
The issue is that the TapDelay refuses to wait for the second tap.
Any and all help is greatly appreciated
P.S. I have the seconds set to two for testing purposes, but once I find that this works, I will be lowering the time to like 0.3 or something
There are several issues with the strategy you are using. For one, it is not scalable (to more than two taps). But ok, maybe you are 100% sure you will never ever need more than 2 taps. The next problem is that event.numTaps can only be 1 or 2, yet your listener tests for < 1! This can never happen. The next problem is that when you tap twice, at least in the simulator (did not test on device) you get two events: one for the first tap with numTaps = 1, and another for 2nd tap with numTaps = 2. In other words, the Corona engine does not wait before emitting a one-tap event to know if a second tap event occurs within some time range. So you get two tap events for a two-tap event, there is no way of knowing in the handler whether you should "wait" to see if another tap might occur within an allowable delay to constitute a "two-tap" event instead.
What you will have to do is create your own N-tap event generator. Whenever a tap occurs, check if your timer has been started. If so, increase the tap count and reset the timer. If not, start the timer that expires some short delay later. If no other tap occurs in that delay, the count you have saved is your tap number. Reset the counter if your timer expires. I have created some functions that do this and I have put them all in a table "object":
local tapEvents = {
measureInterTapTime = false, -- set to true to measure how fast you can tap!
onTapHandler = nil, -- set this to your handler
-- implementation details
tapTimer = nil,
tapCounter = 0,
tapEventTime = 0,
doneTap = function(self, event)
self.tapTimer = nil
if self.onTapHandler then
self.onTapHandler(self.tapCounter)
end
self.tapCounter = 0
self.tapEventTime = 0
end,
-- end implementation details
tap = function(self, event)
self.tapCounter = self.tapCounter + 1
if self.tapTimer ~= nil then
timer.cancel(self.tapTimer)
self.tapTimer = nil
end
local delayMS = 250
self.tapTimer = timer.performWithDelay(delayMS, function(e) self:doneTap(e) end, 1)
-- check how much time between taps, for interest:
if self.measureInterTapTime then
if self.tapEventTime ~= 0 then
local interTapTime = system.getTimer() - self.tapEventTime
print("Time (ms) between taps:", interTapTime)
end
self.tapEventTime = system.getTimer()
end
end,
}
tapEvents.onTapHandler = function(tapCounter)
print(tapCounter .. "-tap event")
end
-- because tapEvents contains a 'tap' function, will get called automatically with self:
Runtime:addEventListener('tap', tapEvents)
This captures N-tap events without limit!! I have included a flag you can set to true if you want to print out the ms delay between single taps so you can determine what the optimum delay should be (you don't want delay to be too short or you might inadvertently break an N tap into two smaller events; you don't want it to be too long either, or user will have to noticeably wait to indicate "end of my multitap").
Tap events must be added to a display object, not to the Runtime.
If you have a display object jumper for example, use:
jumper:addEventListener("tap", moveUp)
More documentation here: http://docs.coronalabs.com/api/event/tap/index.html

How to reveal string one letter at a time?

I'm learning from a book, and this is the assignment question i'm working on:
Create an app that asks for the users name and then displays the name down the side of the screen, one letter at a time.
Clarify what i'm trying trying to do: Have users name fade in one at a time vertically. Example: Adam "A" would appear after 1 second , "d" would appear after 3 seconds under the displayed A, "a" would appear after 5 seconds under the displayed d, "m" would appear after 7 seconds under the displayed a. The visuals would have a sort of domino effect.When they appear they would stay displayed on screen.
So far i'm able to get the user's name and display it side ways. Have it fade it in within 2 seconds. I'm stuck on how to get the letters to fade in one letter at a time.
function submit ()
print( "connect" )
userName = userNameField.text
display_userName = display.newText( userName, display.contentWidth-20, display.contentHeight/2 )
display_userName.rotation = 90
display_userName.alpha = 0
userNameField: removeSelf( )
greeting:removeSelf( )
submitButton:removeSelf( )
transition.fadeIn( display_userName, {time = 2000} )
Please let me know if you need to see more of my code.
You can do it in a simple way as below:
local myString = "Adam" -- Create your string
local positionCount = 0 -- initialize a variable to determine letter position
local function displayData()
positionCount = positionCount + 1
if(positionCount<=string.len(myString))then
-- if positionCount is less than or equal to letters in 'myString'
local letter = string.sub(myString, positionCount, positionCount) -- get the current letter
local letterLabel = display.newText(letter,20,20*positionCount,nil,20) -- place the letter
letterLabel.alpha = 0;
-- display the label and update the function after the completion of transition
transition.to(letterLabel,{time=1000,alpha=1,onComplete=displayData})
end
end
displayData()
Keep Coding.................... :)
Here is the code snippet for storing every character in a table.
Initialise a variable:
check =0;
Here splitWord is an table to store each character of string. and variable "yourStringForOneLetter" is your string variable for splitting. "string.sub" will split string into words using for loop.
if(check==wordSize) then
check=1
end
local wordSize = string.len(yourStringForOneLetter)
splitWord = {}
for i=check, check do
splitWord[i] = string.sub(yourStringForOneLetter, i, i)
check= check +1;
end

Resources