Write a program that takes in a year and determines whether that year is a leap year in Coral - google-coral

Ex: If the input is 1712, the output is:
1712 is a leap year.
Ex: If the input is 1913, the output is:
1913 is not a leap year.
integer inputYear
inputYear = Get next input
if inputYear / 4 == 0
Put inputYear to output
Put " is a leap year." to output
elseif inputYear / 400 == 0
Put inputYear to output
Put " is a leap year." to output
elseif inputYear / 100 == 0
Put inputYear to output
Put " is a leap year." to output
else
Put inputYear to output
Put " is not a leap year." to output
I'm not wanting the answer, just help with my code. I can't figure out why the if/elseif statements aren't executing.

I can't figure out why the if/elseif statements aren't executing.
It's executing, but take 1712 as an example, 1712/4 != 0, and therefore never passes the condition for the if statement. Matter fact, it doesn't pass any of those above conditions.
What you want is modulo math: %.
FYI, check your algorithm.

Related

Parse time string to hours, minutes and seconds in Lua

I am currently working on a plugin for grandMA2 lighting control using Lua. I need the current time. The only way to get the current time is the following function:
gma.show.getvar('TIME')
which always returns the current system time, which I then store in a variable. An example return value is "12h54m47.517s".
How can I separate the hours, minutes and seconds into 3 variables?
If os.date is available (and matches gma.show.getvar('TIME')), this is trivial:
If format starts with '!', then the date is formatted in Coordinated Universal Time. After this optional character, if format is the string "*t", then date returns a table with the following fields: year, month (1–12), day (1–31), hour (0–23), min (0–59), sec (0–61, due to leap seconds), wday (weekday, 1–7, Sunday is 1), yday (day of the year, 1–366), and isdst (daylight saving flag, a boolean). This last field may be absent if the information is not available.
local time = os.date('*t')
local hour, min, sec = time.hour, time.min, time.sec
This does not provide you with a sub-second precision though.
Otherwise, parsing the time string is a typical task for tostring and string.match:
local hour, min, sec = gma.show.getvar('TIME'):match('^(%d+)h(%d+)m(%d*%.?%d*)s$')
-- This is usually not needed as Lua will just coerce strings to numbers
-- as soon as you start doing arithmetic on them;
-- it still is good practice to convert the variables to the proper type though
-- (and starts being relevant when you compare them, use them as table keys or call strict functions that check their argument types on them)
hour, min, sec = tonumber(hour), tonumber(min), tonumber(sec)
Pattern explanation:
^ and $ pattern anchors: Match the full string (and not just part of it), making the match fail if the string does not have the right format.
(%d)+h: Capture hours: One or more digits followed by a literal h
(%d)+m: Capture minutes: One or more digits followed by a literal m
(%d*%.?%d*)s: Capture seconds: Zero or more digits followed by an optional dot followed by again zero or more digits, finally ending with a literal s. I do not know the specifics of the format and whether something like .1s, 1.s or 1s is occasionally emitted, but Lua's tonumber supports all of these so there should be no issue. Note that this is slightly overly permissive: It will also match . (just a dot) and an s without any leading digits. You might want (%d+%.?%d+)s instead to force digits appearing before & after the dot.
Lets do it with string method gsub()
local ts = gma.show.getvar('TIME')
local hours = ts:gsub('h.*', '')
local mins = ts:gsub('.*%f[^h]', ''):gsub('%f[m].*', '')
local secs = ts:gsub('.*%f[^m]', ''):gsub('%f[s].*', '')
To make a Timestring i suggest string method format()
-- secs as float
timestring = ('[%s:%s:%.3f]'):format(hours, mins, secs)
-- secs not as float
timestring = ('[%s:%s:%.f]'):format(hours, mins, secs)

How do I convert Integers to Floats or doubles in Lua?

I used Logitechs LUA implementation to write a simple no recoil script.
I want to fine tune the NR Variable by converting it to a double and using decimals.
Whenever I try to do this,the console puts out
[string "LuaVM"]:45: bad argument #2 to 'OutputLogMessage' (number has no integer representation) Line Number:1
And the Script stops working if decimal numbers are inserted. I don´t really know how I can do the conversion even after looking into the documents.
--General--
UP = 13 -- to increase NoRecoil strength, toggle Modify to change RapidFire strenght
DOWN = 12 -- to reduce NoRecoil strength, toggle Modify to change RapidFire strenght
--NoRecoil
NR = 4 -- distance to pull down, (default) recoil reduction
HorizontalRecoilModifier=0 -- unused, is for left right recoil
Sleep_ = 10 -- delay between pull down, less for smoother
--BINDS--
--General--
UP = 13 -- to increase NoRecoil strength, + Modify to increase RapidFireNoRecoil
DOWN = 12 -- to reduce
--NoRecoil
RC = 3 -- right click, when you press RC and LC it pulls down
LC = 1 -- Left click, key boud to shoot ingame
--FUNCTIONS--
EnablePrimaryMouseButtonEvents(true); -- to capture primary (1) klick
OutputDebugMessage("Profil Aktiv")
function NoRecoil()
repeat
MoveMouseRelative(0,NR)
Sleep(Sleep_)
until not IsMouseButtonPressed(LC)
end
--NoRecoilModify
function Add()
NR=NR+1
if (NR>10) then
NR=0
end
OutputLogMessage("NR %d\n", NR)
OutputDebugMessage("NR %d\n", NR)
end
function Reduce()
NR=NR-1
if (NR<0) then
NR=10
end
OutputLogMessage("NR %d\n", NR)
OutputDebugMessage("NR %d\n", NR)
end
--increaseAndReduce
function OnEvent(event, arg)
if (event == "MOUSE_BUTTON_PRESSED" and arg == UP) then
Add()
end
if (event == "MOUSE_BUTTON_PRESSED" and arg == DOWN) then
Reduce()
end
if IsMouseButtonPressed(RC)then
repeat
if IsMouseButtonPressed(LC) then
NoRecoil()
end
until not IsMouseButtonPressed(RC)
end
end
Please keep in mind this is my first serious attempt at understanding LUA for some shenanigans, I am currently learning Java at my Uni and this is my fourth week of actual coding.
The format placeholder %d specifically denotes an integer. Use %f or any other floating point placeholder as explained in a documentation for sprintf (the underlying implementation of string formatting in Lua), e.g.
https://man.archlinux.org/man/core/man-pages/sprintf.3.en

How do I get the first two digits from a number?

I need to make a code that tells you the century when you give the year. I have this:
local kata = {}
function kata.century(number)
if number%100 == 0 then >I need to get the first two numbers
return
else
return number/100 + 1
end
end
return kata
I basically need a line that gives me the first two numbers of the year for years like "1700" and "2000"
so I can divide them by 100 and add 1.
(i'm a beginner btw)
In Lua 5.3+, use number//100.
For earlier versions, use math.floor(number/100).
According to the Gregorian calendar, 1 CE was the first year of the 1st Century CE. Since a century is a period of 100 years, this means that the first year of any century in the common era ends with a 1; thus 2000 was the last year of the 20th Century, and 2001 was the first year of the 21st Century.
Finding the century from the first two digits of the year alone will not work for this strictly correct method of identification. Taking the first two digits of 2000, and adding 1 would yield the 21st Century. But, instead of using math.floor to truncate the result of division by 10, one can use math.ceil to get the smallest integer greater than the result of the division.
function century (year)
return math.ceil(year / 100)
end
This century function gives the correct century given a year in the common era:
> century(1)
1
> century(100)
1
> century(101)
2
> century(2000)
20
> century(2001)
21
There is a convention in popular usage that centuries should be numbered based on shared digits instead of the Gregorian calendar. In this usage all years beginning with 20 are in the 21st Century, making 2000 the first year of the 21st Century. Since there is no year 0 in the Gregorian calendar, this means that the 1st Century (from 1 CE to 99 CE under this convention) spans 99 years, but all other centuries in the common era span 100 years (e.g., 100 CE to 199 CE). Finding the century from the year using this convention can be done by dividing the year by 100 and taking the floor of the result.
If the goal is to match popular expectations and follow the general popular misunderstanding of numbering centuries, use the floor method. But, if the goal is to get correct and consistent numbering of centuries based on the Gregorian calendar, use the ceiling method.

Calculating ISIN checksum

HI I know there have been may question about this here but I wasn't able to find a detailed enough answer, Wikipedia has two examples of ISIN and how is their checksum calculated.
The part of calculation that I'm struggling with is
Multiply the group containing the rightmost character
The way I understand this statement is:
Iterate through each character from right to left
once you stumble upon a character rather than digit record its position
if the position is an even number double all numeric values in even position
if the position is an odd number double all numeric values in odd position
My understanding has to be wrong because there are at least two problems:
Every ISIN starts with two character country code so position of rightmost character is always the first character
If you omit the first two characters then there is no explanation as to what to do with ISINs that are made up of all numbers (except for first two characters)
Note
isin.org contains even less information on verifying ISINs, they even use the same example as Wikipedia.
I agree with you; the definition on Wikipedia is not the clearest I have seen.
There's a piece of text just before the two examples that explains when one or the other algorithm should be used:
Since the NSIN element can be any alpha numeric sequence (9 characters), an odd number of letters will result in an even number of digits and an even number of letters will result in an odd number of digits. For an odd number of digits, the approach in the first example is used. For an even number of digits, the approach in the second example is used
The NSIN is identical to the ISIN, excluding the first two letters and the last digit; so if the ISIN is US0378331005 the NSIN is 037833100.
So, if you want to verify the checksum digit of US0378331005, you'll have to use the "first algorithm" because there are 9 digits in the NSIN. Conversely, if you want to check AU0000XVGZA3 you're going to use the "second algorithm" because the NSIN contains 4 digits.
As to the "first" and "second" algorithms, they're identical, with the only exception that in the former you'll multiply by 2 the group of odd digits, whereas in the latter you'll multiply by 2 the group of even digits.
Now, the good news is, you can get away without this overcomplicated algorithm.
You can, instead:
Take the ISIN except the last digit (which you'll want to verify)
Convert all letters to numbers, so to obtain a list of digits
Reverse the list of digits
All the digits in an odd position are doubled and their digits summed again if the result is >= 10
All the digits in an even position are taken as they are
Sum all the digits, take the modulo, subtract the result from 0 and take the absolute value
The only tricky step is #4. Let's clarify it with a mini-example.
Suppose the digits in an odd position are 4, 0, 7.
You'll double them and get: 8, 0, 14.
8 is not >= 10, so we take it as it is. Ditto for 0. 14 is >= 10, so we sum its digits again: 1+4=5.
The result of step #4 in this mini-example is, therefore: 8, 0, 5.
A minimal, working implementation in Python could look like this:
import string
isin = 'US4581401001'
def digit_sum(n):
return (n // 10) + (n % 10)
alphabet = {letter: value for (value, letter) in
enumerate(''.join(str(n) for n in range(10)) + string.ascii_uppercase)}
isin_to_digits = ''.join(str(d) for d in (alphabet[v] for v in isin[:-1]))
isin_sum = 0
for (i, c) in enumerate(reversed(isin_to_digits), 1):
if i % 2 == 1:
isin_sum += digit_sum(2*int(c))
else:
isin_sum += int(c)
checksum_digit = abs(- isin_sum % 10)
assert int(isin[-1]) == checksum_digit
Or, more crammed, just for functional fun:
checksum_digit = abs( - sum(digit_sum(2*int(c)) if i % 2 == 1 else int(c)
for (i, c) in enumerate(
reversed(''.join(str(d) for d in (alphabet[v] for v in isin[:-1]))), 1)) % 10)

How to find if range is contained in an array of ranges?

Example
business_hours['monday'] = [800..1200, 1300..1700]
business_hours['tuesday'] = [900..1100, 1300..1700]
...
I then have a bunch of events which occupy some of these intervals, for example
event = { start_at: somedatetime, end_at: somedatetime }
Iterating over events from a certain date to a certain date, I create another array
busy_hours['monday'] = [800..830, 1400..1415]
...
Now my challenges are
Creating an available_hours array that contains business_hours minus busy_hours
available_hours = business_hours - busy_hours
Given a certain duration say 30 minutes, find which time slots are available in available_hours. In the examples above, such a method would return
available_slots['monday'] = [830..900, 845..915, 900..930, and so on]
Not that it checks available_hours in increments of 15 minutes for slots of specified duration.
Thanks for the help!
I think this is a job for bit fields. Unfortunately this solution will rely on magic numbers, conversions helpers and a fair bit of binary logic, so it won't be pretty. But it will work and be very efficient.
This is how I'd approach the problem:
Atomize your days into reasonable time intervals. I'll follow your example and treat each 15 minute block of time as considered one time chunk (mostly because it keeps the example simple). Then represent your availability per hour as a hex digit.
Example:
0xF = 0x1111 => available for the whole hour.
0xC = 0x1100 => available for the first half of the hour.
String 24 of these together together to represent a day. Or fewer if you can be sure that no events will occur outside of the range. The example continues assuming 24 hours.
From this point on I've split long Hex numbers into words for legibility
Assuming the day goes from 00:00 to 23:59 business_hours['monday'] = 0x0000 0000 FFFF 0FFF F000 0000
To get busy_hours you store events in a similar format, and just & them all together.
Exmample:
event_a = 0x0000 0000 00F0 0000 0000 0000 # 10:00 - 11:00
event_b = 0x0000 0000 0000 07F8 0000 0000 # 13:15 - 15:15
busy_hours = event_a & event_b
From busy_hours and business_hours you can get available hours:
available_hours = business_hours & (busy_hours ^ 0xFFFF FFFF FFFF FFFF FFFF FFFF)
The xor(^) essentialy translates busy_hours into not_busy_hours. Anding (&) not_busy_hours with business_hours gives us the available times for the day.
This scheme also makes it simple to compare available hours for many people.
all_available_hours = person_a_available_hours & person_b_available_hours & person_c_available_hours
Then to find a time slot that fits into available hours. You need to do something like this:
Convert your length of time into a similar hex digit to the an hour where the ones represent all time chunks of that hour the time slot will cover. Next right shift the digit so there's no trailing 0's.
Examples are better than explanations:
0x1 => 15 minutes, 0x3 => half hour, 0x7 => 45 minutes, 0xF => full hour, ... 0xFF => 2 hours, etc.
Once you've done that you do this:
acceptable_times =[]
(0 .. 24 * 4 - (#of time chunks time slot)).each do |i|
acceptable_times.unshift(time_slot_in_hex) if available_hours & (time_slot_in_hex << i) == time_slot_in_hex << i
end
The high end of the range is a bit of a mess. So lets look a bit more at it. We don't want to shift too many times or else we'll could start getting false positives at the early end of the spectrum.
24 * 4 24 hours in the day, with each represented by 4 bits.
- (#of time chunks in time slot) Subtract 1 check for each 15 minutes in the time slot we're looking for. This value can be found by (Math.log(time_slot_in_hex)/Math.log(2)).floor + 1
Which starts at the end of the day, checking each time slot, moving earlier by a time chunk (15 minutes in this example) on each iteration. If the time slot is available it's added to the start of acceptable times. So when the process finishes acceptable_times is sorted in order of occurrence.
The cool thing is this implementation allows for time slots that incorporate so that your attendee can have a busy period in their day that bisects the time slot you're looking for with a break, where they might be otherwise busy.
It's up to you to write helper functions that translate between an array of ranges (ie: [800..1200, 1300..1700]) and the hex representation. The best way to do that is to encapsulate the behaviour in an object and use custom accessor methods. And then use the same objects to represent days, events, busy hours, etc. The only thing that's not built into this scheme is how to schedule events so that they can span the boundary of days.
To answer your question's title, find if a range of arrays contains a range:
ary = [800..1200, 1300..1700]
test = 800..830
p ary.any? {|rng| rng.include?(test.first) and rng.include?(test.last)}
# => true
test = 1245..1330
p ary.any? {|rng| rng.include?(test.first) and rng.include?(test.last)}
# => false
which could be written as
class Range
def include_range?(r)
self.include?(r.first) and self.include?(r.last)
end
end
Okay, I don't have time to write up a full solution, but the problem does not seem too difficult to me. I hacked together the following primitive methods you can use to help in constructing your solution (You may want to subclass Range rather than monkey patching, but this will give you the idea):
class Range
def contains(range)
first <= range.first || last >= range.last
end
def -(range)
out = []
unless range.first <= first && range.last >= last
out << Range.new(first, range.first) if range.first > first
out << Range.new(range.last, last) if range.last < last
end
out
end
end
You can iterate over business hours and find the one that contains the event like so:
event_range = event.start_time..event.end_time
matching_range = business_hours.find{|r| r.contains(event_range)}
You can construct the new array like this (pseudocode, not tested):
available_hours = business_hours.dup
available_hours.delete(matching_range)
available_hours += matching_range - event_range
That should be a pretty reusable approach. Of course you'll need something totally different for the next part of your question, but this is all I have time for :)

Resources