Commit Graph
8 Commits
Author SHA1 Message Date
erikbrockoandClaude Opus 5 b5d9f1e21c Name the All Asian multiplier after what it counts
The score window and the stored Contest.Multiplier1Name row both said
"Prefixes" for an Asian entrant, which counts DXCC entities.

Contest.MultiplierNames is now MultiplierNamesFor(StationInfo me), the
same shape as ExchangeFieldsFor. Every other contest returns the same
list it did before; All Asian returns "Countries" from Asia and
"Prefixes" from everywhere else. ContestDefinitions.For takes the
station as well, because that name is written to the log for N1MM.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0157i7PiZyqBkquxS9A6FTdQ
2026-09-10 20:47:51 +00:00
erikbrockoandClaude Opus 5 bae40bb04e Show the boxes N1MM shows for each contest
The entry window had a fixed set of boxes with a Name and Comment box beside
the exchange. N1MM lays out one row of boxes per contest and nothing else, so
this does the same: general logging keeps Name and Comment, and a contest gets
the boxes it exchanges.

Two new members on `Contest` carry the cases where the boxes and the log
columns are not the same list:

- `FromExchange1` spreads what was typed in one box across the log columns.
  Where the other station sends a serial or a district code depending on where
  it is, N1MM gives it one box and sorts the value into the number, section or
  zone column from there, so the score and the Cabrillo file read it from the
  same column N1MM does.
- `LogFieldsFor` gives the log window its own column list. Sweepstakes takes
  the whole exchange in one box and logs it in four columns; `SweepstakesExchange`
  parses `72 A 74 SCV` in any order, reading from the last word back as N1MM
  does.

The sent serial is now marked as not required and space steps over it along
with the two report boxes, because nobody types the number going out.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015NZkFxHde1iifAQemFTHxf
2026-09-09 20:12:37 +00:00
erikbrockoandClaude Opus 5 3932f83147 Add the YOTA and OK/OM DX contests
Both are in the station's log and neither could be opened. The rules are
written from the published ones and checked by replaying the log.

YOTA scores a contact by the age the other operator sends: 13 points down to 10
for anyone 25 or under, whatever the continent, and 1 point or 3 for everyone
else. Every age worked on a band is a multiplier. The 2024, 2025 and 2026 logs
come out to the contact.

OK/OM DX is the first contest whose exchange differs by the other station's
country: a county from OK and OM stations, a serial number from everyone else,
in the two columns N1MM keeps them in, and `SkipsField` walks the entry window
past the box that does not apply. Points depend on which side the operator is
on, and Czechia and Slovakia count as the two countries they are. The 2023 log
comes out to the contact.

The Cabrillo exchange now gets the entry, because YOTA sends an age that only
the contest setup knows.

Two differences are left in the log, both from the .udc files the operator
used: their YOTA file only lists ages 7 to 25, so a younger operator scored as
an adult, and one OK/OM log was made with the file for stations outside OK and
OM while signing an OM call.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RoGtneMQaz4M9w7Kk49AVD
2026-08-31 09:16:44 +00:00
erikbrockoandClaude Opus 5 04568d0ca3 Read the rest of what a .udc file says, and score what N1MM scores
Two pieces of work on the scoring engine.

The .udc reader now takes N1MM's published scoring vocabulary: the full
PointsPerContact condition set, the PointsMultBy family, PowerMult, BonusPoints,
the multiplier sources and the settings that say which stations bring a
multiplier in. MultMult is a weight rather than a switch, as in N1MM's
ComputeScore. The entry categories and the sent exchange reach the rules in a
new ContestEntry, so a contest can score by the power category it is entered in
or by what this station sends.

Then every contest in a real N1MM log was scored again from these rules and
compared with the points and multiplier flags N1MM wrote. That found five bugs:
ARRL DX and IARU read the exchange from the wrong column, a stored " " was read
as a value rather than as empty, CQ WW RTTY's own Canadian area names were not
counted, a maritime mobile scored nothing, and a contact in a mode the contest
does not run scored as if it were in the contest.

docs/n1mm-interop.md has the check and what still differs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RoGtneMQaz4M9w7Kk49AVD
2026-08-31 08:33:40 +00:00
erikbrockoandClaude Opus 5 ff46cb00ed Put N1MM's status bar along the bottom of the entry window
Three parts, as N1MM has them: what just happened on the left, the contacts
and multipliers in the middle, the score on the right.

The left says where the call being typed is from, in N1MM's own shape:
OM: EU -> Slovak Republic, Zn 15. The zone is the one the contest counts in, so
Contest.UsesItuZones answers that the way N1MM's ZoneType does, and IARU
overrides it. A message from something the operator just did stands there until
the next keystroke.

The middle is N1MM's breakdown: the contacts and then one number per multiplier
the contest counts, separated by slashes, and No Score before the first
contact. Points are not in it, because they are not in N1MM's; the score window
has them.

Those numbers were in the line at the top of the window, which now carries the
contest name alone, and the country was in the bar under the callsign box,
which now says only what working the call would bring. Neither is said twice.

Looked at under Xvfb: the country line for OM3KFF and then G4AB, 10/7/8 and
300 beside them, and a Mark message standing in the left until the next
keystroke.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RoGtneMQaz4M9w7Kk49AVD
2026-08-30 22:46:13 +00:00
erikbrockoandClaude Opus 5 da9884ebf5 Open a log N1MM wrote
Three things stopped it.

A contest is keyed by ContestNR, not by ContestID. ContestID is only the
ContestInstance table's primary key; DXLOG.ContestNR refers to ContestNR, which
is what N1MM's SQLWhereString matches on. The two agree in a fresh log and
drift apart in one that has been used for a while, so we were reading one
contest's header with another contest's contacts. In a real log of 56284
contacts, joining on ContestID disagreed with the contact's own ContestName
52029 times; joining on ContestNR disagreed 109 times.

N1MM names a contest per mode: CQWWCW, CQWWSSB, CQWWRTTY, never plain CQWW.
Our contests now use those names, and N1mmContestNames turns one back into a
contest and a mode when a log is opened. The name carries the mode, so it beats
the ModeCategory column. Plain CQWW still opens, because older versions wrote
it that way.

The log columns were sized by counting characters, which was too narrow for the
headers: those are drawn in the theme's font, not the grid's monospace. The
grid sizes them now, with the character count as a floor so a column of short
values does not collapse.

Bandmap spots now age from when they arrived rather than from the time written
in them. A node with a wrong clock, or one replaying its backlog on connect,
emptied the bandmap as fast as it filled it.

Checked by opening a real 56284-contact N1MM log under Xvfb and reading the
contest and contacts back.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 16:27:35 +00:00
ErikandClaude Opus 5 d96cbe146b Write what N1MM needs before it will open a log
Checked by opening a log this program wrote in N1MM 1.0.11031. Three things it
rejected:

- a log naming a contest with no row in the Contest table throws "No current
  row" in Contest.FromRow, so the definition row is written whenever a contest
  is opened;
- an empty overlay category is answered with "Invalid Overlay Category:", so an
  entry with no overlay now says "N/A", and the dialog offers N1MM's list;
- the sent exchange omits the report, which is what N1MM's own contest dialog
  asks for.

With those three fixed N1MM opens the log and shows the contacts.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 11:15:48 +00:00
ErikandClaude Opus 5 ef631f1dc4 Add the rest of the major contests, .udc files and the registry
ARRL DX, IARU HF, Sweepstakes, RTTY Roundup, NAQP and general logging join
CQ WW and CQ WPX. The Cabrillo QSO line is now built column by column by the
contest, because Sweepstakes puts the callsign after the serial number where
everyone else puts it first.

User-defined contests read the subset of N1MM's .udc settings that covers the
exchange, the dupe rule, points and up to three multipliers.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 10:35:28 +00:00