|
Documenting scripts with AI June 19, 2025 07:25AM |
Admin Registered: 10 years ago Posts: 895 |
|
Re: Documenting scripts with AI June 19, 2025 07:25AM |
Admin Registered: 10 years ago Posts: 895 |
local args={...}
conf = args[1].config
local filter = {}
filter.country = conf.country
filter.region = conf.region
filter.county = conf.county
filter.minVisitDate = conf.minVisitDate
filter.maxVisitDate = conf.maxVisitDate
filter.minHiddenDate = conf.minHiddenDate
filter.maxHiddenDate = conf.maxHiddenDate
filter.types = conf.types
filter.sizes = conf.sizes
filter.difficulties = conf.difficulties
filter.terrains = conf.terrains
local mincaches = 1
if (not (conf.mincaches == nil)) and tonumber(conf.mincaches)>0 then
mincaches = tonumber(conf.mincaches)
end
local minage = 1
if (not (conf.minage == nil)) and tonumber(conf.minage)>=0 then
minage = tonumber(conf.minage)
end
local maxage = 999
if (not (conf.maxage == nil)) and tonumber(conf.maxage)>=0 then
maxage = tonumber(conf.maxage)
end
local mintotal = 1
if (not (conf.mintotal == nil)) and tonumber(conf.mintotal)>0 then
mintotal = tonumber(conf.mintotal)
end
local mindifferentages = 1
if (conf.mindifferentages ~= nil) and tonumber(conf.mindifferentages)>0 then
mindifferentages = tonumber(conf.mindifferentages)
end
uniquedates = false
if conf.uniquedates ~= nil and conf.uniquedates=="YES" then
uniquedates = true
end
local showall = false
if (not (conf.showall == nil)) and conf.showall=="YES" then
showall = true
end
profileName = args[1]['profileName']
profileId = PGC.ProfileName2Id(profileName)
local cachesfound = 0
local totalage = 0
local differentages = 0
local datelog = {}
local resultText = ""
local htmlBlob = ""
local meets
local countsperage = {}
local logperdate = {}
local caches
myFinds = PGC.GetFinds( profileId, { fields = { 'gccode', 'cache_name', 'hidden', 'visitdate' }, filter=filter, order = 'OLDESTFIRST' } )
if #myFinds>0 then
local lastyear = tonumber(string.sub(myFinds[#myFinds].visitdate,1,4));
for age=1,lastyear-2000 do
countsperage[age] = 0
end
end
local qualified = {}
for n,v in ipairs(myFinds) do
local birthdate = string.sub(v.hidden,6)
if birthdate == string.sub(v.visitdate,6) then
local age = tonumber(string.sub(v.visitdate,1,4))-tonumber(string.sub(v.hidden,1,4))
if age >= minage and age <= maxage then
if uniquedates then
if datelog[birthdate] ~= nil then
-- Project-GC has changed this from %d to %d+ to include multidigit ages
local prevage = tonumber(string.match(datelog[birthdate]," %(age (%d+)%)$"))
if prevage < age then
totalage = totalage - prevage
cachesfound = cachesfound - 1
countsperage[prevage] = countsperage[prevage] - 1
if countsperage[prevage] <= 0 then differentages = differentages - 1 end
else
age = 0
end
end
if age > 0 then
datelog[birthdate] = "[" .. v.gccode .. "](http://coord.info/" .. v.gccode .. ") " .. v.cache_name .. ", hidden " .. string.sub(v.hidden,1,4) .. " found " .. string.sub(v.visitdate,1,4) .. " (age " .. age .. ")"
end
end
end
if age >= minage and age <= maxage then
table.insert (qualified, v)
cachesfound = cachesfound + 1
totalage = totalage + age
if countsperage[age] == 0 then
differentages = differentages + 1
end
countsperage[age] = countsperage[age] + 1
if showall or (mincaches>mindifferentages) or (countsperage[age] == 1) or (mintotal>mindifferentages) then
resultText = resultText .. birthdate .. " [" .. v.gccode .. "](http://coord.info/" .. v.gccode .. ") " .. v.cache_name .. ", hidden " .. string.sub(v.hidden,1,4) .. " found " .. string.sub(v.visitdate,1,4) .. " (age " .. age .. ")\n"
end
meets = (totalage >= mintotal) and (cachesfound >= mincaches) and (differentages >= mindifferentages)
if meets and not showall then break end
end
end
end
if meets and uniquedates then
resultText = ""
local a = {}
for n in pairs(datelog) do table.insert(a, n) end
table.sort(a)
for i,n in ipairs(a) do
resultText = resultText .. n .. " " .. datelog[n] .. "\n"
end
end
if not meets then
if cachesfound == 0 then
htmlBlob = "You have not found any qualifying cache."
elseif cachesfound < mincaches then
htmlBlob = "You have only found " .. cachesfound .. " of the " .. mincaches .. " caches required."
elseif differentages < mindifferentages then
htmlBlob = "You have only found caches with " .. differentages .. " different ages ("
local printcomma = false
for age,count in ipairs(countsperage) do
if count > 0 then
if printcomma then htmlBlob = htmlBlob .. "," end
htmlBlob = htmlBlob .. age
printcomma = true
end
end
htmlBlob = htmlBlob .. "), but you need " .. mindifferentages .. "."
elseif totalage < mintotal then
htmlBlob = "The total age of the birthday caches you found is only " .. totalage .. ", but you need at least " .. mintotal .. "."
else
htmlBlob = ""
end
if #qualified > 0 then
htmlBlob = htmlBlob .. "\n<TABLE><TR><TH>GCcode</TH><TH>Hidden</TH><TH>Found</TH></TR>\n"
local loga = {}
for _,v in ipairs(qualified) do
table.insert (loga, "<TR><TD><A href=http://coord.info/"..v.gccode..">"..v.gccode.."</A></TD><TD>"..v.hidden.."</TD><TD>"..v.visitdate.."</TD><TR>")
end
htmlBlob = htmlBlob .. table.concat (loga, "\n") .. "\n</TABLE>"
end
end
return { ok = meets, log = resultText, html = htmlBlob }
|
Re: Documenting scripts with AI June 19, 2025 07:25AM |
Admin Registered: 10 years ago Posts: 895 |
--[[
Geocaching Birthday Geocache Challenge Checker
This script validates whether a geocacher has completed a "birthday geocache" challenge.
A birthday geocache is one where the geocache was found on the same month/day it was hidden,
but in a different year (hence the "age" calculation).
The checker supports:
- Finding a minimum number of birthday geocaches
- Achieving a minimum total "age" (sum of all geocache ages)
- Finding geocaches with a minimum number of different ages
- Optionally requiring unique dates (only one geocache per birth date)
Example: A geocache hidden on 2010-05-15 and found on 2015-05-15 has an "age" of 5 years.
]]
--[[
Changelog:
2025-06-19: Documented scripts with several comments.
2025-06-19: Rewrote script into a two pass procedure. This was done to make sure that the
"You have only found X of the Y..." actually matched the number of items in the list.
2025-06-19: Return `html = false` when not used, not an empty string.
]]
-- Get input arguments and configuration
local args = {...}
conf = args[1].config
-- Initialize filter object for geocache search
local filter = {}
filter.country = conf.country
filter.region = conf.region
filter.county = conf.county
filter.minVisitDate = conf.minVisitDate
filter.maxVisitDate = conf.maxVisitDate
filter.minHiddenDate = conf.minHiddenDate
filter.maxHiddenDate = conf.maxHiddenDate
filter.types = conf.types
filter.sizes = conf.sizes
filter.difficulties = conf.difficulties
filter.terrains = conf.terrains
-- Parse configuration parameters with defaults
-- Minimum number of birthday geocaches required (default: 1)
local mincaches = 1
if (not (conf.mincaches == nil)) and tonumber(conf.mincaches) > 0 then
mincaches = tonumber(conf.mincaches)
end
PGC.print("mincaches: ", mincaches, "\n")
-- Minimum age of geocaches (years between hidden and found dates, default: 1)
local minage = 1
if (not (conf.minage == nil)) and tonumber(conf.minage) >= 0 then
minage = tonumber(conf.minage)
end
PGC.print("minage: ", minage, "\n")
-- Maximum age of geocaches (default: 999 years)
local maxage = 999
if (not (conf.maxage == nil)) and tonumber(conf.maxage) >= 0 then
maxage = tonumber(conf.maxage)
end
PGC.print("maxage: ", maxage, "\n")
-- Minimum total age (sum of all geocache ages, default: 1)
local mintotal = 1
if (not (conf.mintotal == nil)) and tonumber(conf.mintotal) > 0 then
mintotal = tonumber(conf.mintotal)
end
PGC.print("mintotal: ", mintotal, "\n")
-- Minimum number of different ages required (default: 1)
local mindifferentages = 1
if (conf.mindifferentages ~= nil) and tonumber(conf.mindifferentages) > 0 then
mindifferentages = tonumber(conf.mindifferentages)
end
PGC.print("mindifferentages: ", mindifferentages, "\n")
-- Whether to enforce unique dates (only one geocache per birth date)
uniquedates = false
if conf.uniquedates ~= nil and conf.uniquedates == "YES" then
uniquedates = true
end
PGC.print("uniquedates: ", uniquedates, "\n")
-- Whether to show all qualifying geocaches or stop when requirements are met
local showall = false
if (not (conf.showall == nil)) and conf.showall == "YES" then
showall = true
end
PGC.print("showall: ", showall, "\n")
-- Get profile information
profileName = args[1]['profileName']
profileId = PGC.ProfileName2Id(profileName)
-- Retrieve user's geocache finds from backend
myFinds = PGC.GetFinds(profileId, {
fields = { 'gccode', 'cache_name', 'hidden', 'visitdate' },
filter = filter,
order = 'OLDESTFIRST'
})
-- PASS 1: Determine best geocache for each birth date
local bestPerBirthdate = {}
for n, v in ipairs(myFinds) do
-- Extract birth date (month-day) from hidden date
local birthdate = string.sub(v.hidden, 6)
-- Check if geocache was found on its "birthday" (same month-day)
if birthdate == string.sub(v.visitdate, 6) then
-- Calculate geocache age (years between hidden and found)
local age = tonumber(string.sub(v.visitdate, 1, 4)) - tonumber(string.sub(v.hidden, 1, 4))
-- Check if age is within acceptable range
if age >= minage and age <= maxage then
-- If uniquedates is enabled, only keep the oldest geocache for each birth date
if uniquedates then
if bestPerBirthdate[birthdate] == nil or age > bestPerBirthdate[birthdate].age then
PGC.print("Adding " .. v.gccode .. " for birthdate " .. birthdate .. ", replacing potential duplicates", "\n")
bestPerBirthdate[birthdate] = {
geocache = v,
age = age
}
end
else
-- If uniquedates is disabled, keep all qualifying geocaches
if bestPerBirthdate[birthdate] == nil then
bestPerBirthdate[birthdate] = {}
end
PGC.print("Adding " .. v.gccode .. " for birthdate " .. birthdate, "\n")
table.insert(bestPerBirthdate[birthdate], {
geocache = v,
age = age
})
end
end
end
end
--PGC.print("Pass 1 complete - bestPerBirthdate:", bestPerBirthdate)
-- PASS 2: Build results from the clean data
local qualified = {}
local cachesfound = 0
local totalage = 0
local differentages = 0
local countsperage = {}
local resultText = ""
-- Initialize age counters
if #myFinds > 0 then
local lastyear = tonumber(string.sub(myFinds[#myFinds].visitdate, 1, 4));
PGC.print("Initializing countsperage from age 1 to " .. (lastyear - 2000), "\n")
for age = 1, lastyear - 2000 do
countsperage[age] = 0
end
end
-- Sort birth dates for consistent output (oldest hidden dates first)
local sortedEntries = {}
for birthdate, entry in pairs(bestPerBirthdate) do
if uniquedates then
table.insert(sortedEntries, {birthdate = birthdate, entry = entry})
else
for _, subentry in ipairs(entry) do
table.insert(sortedEntries, {birthdate = birthdate, entry = subentry})
end
end
end
-- Sort by hidden date (oldest first)
table.sort(sortedEntries, function(a, b)
return a.entry.geocache.hidden < b.entry.geocache.hidden
end)
-- Process each entry in sorted order
for _, sortedEntry in ipairs(sortedEntries) do
local birthdate = sortedEntry.birthdate
local entry = sortedEntry.entry
local v = entry.geocache
local age = entry.age
table.insert(qualified, v)
cachesfound = cachesfound + 1
totalage = totalage + age
if countsperage[age] == 0 then
differentages = differentages + 1
end
countsperage[age] = countsperage[age] + 1
-- Add to result text
if showall or (mincaches > mindifferentages) or (countsperage[age] == 1) or (mintotal > mindifferentages) then
resultText = resultText .. birthdate .. " [" .. v.gccode .. "](http://coord.info/" .. v.gccode .. ") " ..
v.cache_name .. ", hidden " .. string.sub(v.hidden, 1, 4) ..
" found " .. string.sub(v.visitdate, 1, 4) .. " (age " .. age .. ")\n"
end
-- Check if all requirements are now met
local meets = (totalage >= mintotal) and (cachesfound >= mincaches) and (differentages >= mindifferentages)
-- Stop processing if requirements are met and not showing all
if meets and not showall then
break
end
end
-- Check final requirements
local meets = (totalage >= mintotal) and (cachesfound >= mincaches) and (differentages >= mindifferentages)
-- Generate failure message if requirements not met
local htmlBlob = false
if not meets then
htmlBlob = ""
if cachesfound == 0 then
htmlBlob = "You have not found any qualifying geocache."
elseif cachesfound < mincaches then
htmlBlob = "You have only found " .. cachesfound .. " of the " .. mincaches .. " geocaches required."
elseif differentages < mindifferentages then
htmlBlob = "You have only found geocaches with " .. differentages .. " different ages ("
local printcomma = false
for age, count in ipairs(countsperage) do
if count > 0 then
if printcomma then
htmlBlob = htmlBlob .. ","
end
htmlBlob = htmlBlob .. age
printcomma = true
end
end
htmlBlob = htmlBlob .. "), but you need " .. mindifferentages .. "."
elseif totalage < mintotal then
htmlBlob = "The total age of the birthday geocaches you found is only " .. totalage ..
", but you need at least " .. mintotal .. "."
else
htmlBlob = ""
end
-- Add table of qualifying geocaches even if requirements not fully met
if #qualified > 0 then
htmlBlob = htmlBlob .. "\n<TABLE><TR><TH>GCcode</TH><TH>Hidden</TH><TH>Found</TH></TR>\n"
local loga = {}
for _, v in ipairs(qualified) do
table.insert(loga, "<TR><TD><A href=http://coord.info/" .. v.gccode .. ">" ..
v.gccode .. "</A></TD><TD>" .. v.hidden .. "</TD><TD>" ..
v.visitdate .. "</TD><TR>")
end
htmlBlob = htmlBlob .. table.concat(loga, "\n") .. "\n</TABLE>"
end
end
-- Return results
return {
ok = meets, -- Boolean: whether challenge is completed
log = resultText, -- Formatted log text
html = htmlBlob -- HTML formatted results
}