# HG changeset patch # User Josef 'Jeff' Sipek # Date 1727352151 14400 # Thu Sep 26 08:02:31 2024 -0400 # Node ID ff9ed89a571150dc939b9cee4c31d574b6eaf5f7 # Parent 4cd363673b6c1f2bf775b77686fe2b1a415c8ee3 WIP: xlua: generalize state/county -type contests diff --git a/docs/lua-hlog-module.md b/docs/lua-hlog-module.md --- a/docs/lua-hlog-module.md +++ b/docs/lua-hlog-module.md @@ -52,6 +52,13 @@ shouldn't be counted toward the total. +hlog.contest_helper +------------------- + +### `county(...)` +TODO + + hlog.country ------------ diff --git a/xlua/CMakeLists.txt b/xlua/CMakeLists.txt --- a/xlua/CMakeLists.txt +++ b/xlua/CMakeLists.txt @@ -29,6 +29,7 @@ contests/K1USN-SST contests/NEQP contests/POTA + helper-county prompt set startup-stats diff --git a/xlua/scripts/.hgignore b/xlua/scripts/.hgignore --- a/xlua/scripts/.hgignore +++ b/xlua/scripts/.hgignore @@ -6,6 +6,7 @@ contests/K1USN-SST.{luac,c} contests/NEQP.{luac,c} contests/POTA.{luac,c} +helper-county.{luac,c} prompt.{luac,c} set.{luac,c} startup-stats.{luac,c} diff --git a/xlua/scripts/helper-county.lua b/xlua/scripts/helper-county.lua new file mode 100644 --- /dev/null +++ b/xlua/scripts/helper-county.lua @@ -0,0 +1,248 @@ +-- +-- Copyright (c) 2022-2024 Josef 'Jeff' Sipek +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy +-- of this software and associated documentation files (the "Software"), to deal +-- in the Software without restriction, including without limitation the rights +-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-- copies of the Software, and to permit persons to whom the Software is +-- furnished to do so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in +-- all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +-- SOFTWARE. +-- + +local mt = { } + +local function county(counties, state_dxccs, duphash) + local out = { } + + local tmp = hlog.set.new() + tmp:add(state_dxccs) + state_dxccs = tmp + + local county_dxccs = hlog.set.new() + local states = hlog.set.new() + local name2abbrev = { } + local abbrev2name = { } + for _, info in ipairs(counties) do + local dxcc = info[1] + local a = info[3] + local n = info[2] .. info[4] + local s = info[2] + + state_dxccs:add(dxcc) + county_dxccs:add(dxcc) + states:add(s) + + assert(name2abbrev[n] == nil) + name2abbrev[n] = a + + assert(abbrev2name[a] == nil) + abbrev2name[a] = info + end + + -- NOTE: dxcc-state is a superset of dxcc-county + out['dxcc-county'] = county_dxccs -- set of dxccs that may use counties + out['dxcc-state'] = state_dxccs -- set of dxccs that may use states + out['states-county'] = states -- set of states that use counties + out['county'] = counties -- the raw data from the user + out['n2a'] = name2abbrev -- map from to abbrev + out['a2n'] = abbrev2name -- map from abbrev to info + out['dups'] = hlog.set.new() -- set of dup hashes + + -- set up an object with the data + local obj = { + duphash = duphash, + data = out, + } + + setmetatable(obj, mt) + + return obj +end + +local function name2abbrev(self, dxcc, state, county) + local map = self.data + + -- outside of DXCCs that use states or counties + if not map['dxcc-state']:has(dxcc) and not map['dxcc-county']:has(dxcc) then + return "DX" + end + + -- inside the 'states' but outside the 'counties' area + if not map['states-county']:has(state) then + return state + end + + -- inside the 'counties' area + assert(county ~= nil) + + return map['n2a'][state .. county] +end + +local function abbrev2name(self, abbrev) + local map = self.data + + local info = map['a2n'][abbrev] + + -- inside 'counties' area: return state & county + if info ~= nil then + return info[2], info[4] + end + + -- outside 'counties' area, but inside 'states' area: return state + if abbrev ~= nil and abbrev ~= "DX" then + return abbrev, nil + end + + -- outside 'counties' and 'states' area + return nil, nil +end + +local function dxcc_use_state(self, dxcc) + if dxcc == nil then + return false + end + + return self.data['dxcc-state']:has(dxcc) +end + +local function dxcc_use_county(self, dxcc) + if dxcc == nil then + return false + end + + return self.data['dxcc-county']:has(dxcc) +end + +local function state_use_county(self, dxcc, state) + local map = self.data + + if dxcc == nil or state == nil then + return false + end + + return map['dxcc-county']:has(dxcc) and map['states-county']:has(state) +end + +local function qso_done(self, qso, tx, rx) + local map = self.data + + tx = tx ~= nil and tx or qso.additional['contest-tx'] + rx = rx ~= nil and rx or qso.additional['contest-rx'] + + map['dups']:add(self.duphash(qso, tx, rx)) +end + +-- is the passed in qso a duplicate with a previous qso? +local function is_dup(self, qso, tx, rx) + local map = self.data + + tx = tx ~= nil and tx or qso.additional['contest-tx'] + rx = rx ~= nil and rx or qso.additional['contest-rx'] + + return map['dups']:has(self.duphash(qso, tx, rx)) +end + +local function export_prep(self, id, year, qpoints, qmult, qexchange) + local function do_add_entry(tx, rx, args) + local qp = args[1] + local all = args[2] + local ops = args[3] + local points = args[4] + local mults = args[5] + local qso = args[6] + + local tx_exch, tx_exch_ok = qexchange(qso.tx, tx) + local rx_exch, rx_exch_ok = qexchange(qso.rx, rx) + + -- accumulate points + if not self:is_dup(qso, tx, rx) and tx_exch_ok and rx_exch_ok then + points[1] = points[1] + qpoints(qso, tx, rx) + end + + -- add the mult + local m = qmult(qso, tx, rx) + if m ~= nil then + mults:add(m) + end + + -- add to list of all QSOs + table.insert(all, { qso, tx_exch, rx_exch, tx_exch_ok and rx_exch_ok }) + + -- stash for future dup detection + self:qso_done(qso, tx, rx) + + -- keep track of the operators + ops:add(qso.tx.operator_call) + end + + local function add_entry(id, year, station, all, ops, points, mults, qso) + if qso.additional['contest-id'] ~= id or + qso.additional['contest-year'] ~= year then + return + end + + if qso.tx.band == nil then + print(string.format("Error: %s QSO lacks band info", qso.uuid)) + return + end + + assert(qso.tx.station_call ~= nil) + station:add(qso.tx.station_call) + + hlog.utils.each_with_each(qso.additional['contest-tx'], + qso.additional['contest-rx'], + "+", do_add_entry, + { self, all, ops, points, mults, qso }) + end + + local station = hlog.set.new() + local all = {} + local ops = hlog.set.new() + local points = { 0 } + local mults = hlog.set.new() + + for qso in hlog.index.history(true) do + add_entry(id, year, station, all, ops, points, mults, qso) + end + + if station:count_items() ~= 1 then + error(string.format("Error: more than one station callsign used: %s", + station:to_string())) + end + + station = hlog.utils.join_ipairs(station:as_array(), ",") -- should be only 1 element + points = points[1] + + return all, station, ops, points, mults +end + +local function tostring(self) + return "County{" .. self.data:tostring() .. "}" +end + +mt.__index = { + name2abbrev = name2abbrev, + abbrev2name = abbrev2name, + dxcc_use_state = dxcc_use_state, + dxcc_use_county = dxcc_use_county, + state_use_county = state_use_county, + qso_done = qso_done, + is_dup = is_dup, + export_prep = export_prep, + tostring = tostring, +} + +return { + county = county, +} diff --git a/xlua/xlua.c b/xlua/xlua.c --- a/xlua/xlua.c +++ b/xlua/xlua.c @@ -64,6 +64,12 @@ { NULL, NULL }, }; +static void xlua_pushlib_contest_helper(lua_State *L) +{ + lua_newtable(L); + xlua_merge_lua_funcs(L, "helper-county.lua"); +} + static void xlua_register(lua_State *L) { lua_newtable(L); @@ -76,6 +82,10 @@ xlua_pushlib_cabrillo(L); lua_settable(L, -3); + lua_pushliteral(L, "contest_helper"); + xlua_pushlib_contest_helper(L); + lua_settable(L, -3); + lua_pushliteral(L, "country"); xlua_pushlib_country(L); lua_settable(L, -3);