using Nonemm.Core; using Nonemm.Core.Country; namespace Nonemm.Contests.Rules; /// The Ukrainian DX contest. A Ukrainian station sends its oblast, everyone /// else a serial number, and a contact with Ukraine is worth 10 points to a /// station outside it. The multipliers are the countries and the oblasts, each /// once per band. public sealed class UkrainianDx : Contest { public string Name => "UKRAINDX"; public string DisplayName => "Ukrainian DX"; public string CabrilloName => "UKRAINIAN-DX"; public IReadOnlyList ExchangeFieldsFor(StationInfo me) => IsUkrainian(me.CountryPrefix) ? [ new ExchangeField("Snt", ExchangeSlot.SentReport, ExchangeFieldKind.Report, IsRequired: false), new ExchangeField("Rcv", ExchangeSlot.ReceivedReport, ExchangeFieldKind.Report), new ExchangeField("Exch", ExchangeSlot.Exchange1, ExchangeFieldKind.Text) { Width = 3 }, ] : [ new ExchangeField("Snt", ExchangeSlot.SentReport, ExchangeFieldKind.Report, IsRequired: false), new ExchangeField("SntNR", ExchangeSlot.SentNumber, ExchangeFieldKind.Number, IsRequired: false), new ExchangeField("Rcv", ExchangeSlot.ReceivedReport, ExchangeFieldKind.Report), new ExchangeField("Exch", ExchangeSlot.Exchange1, ExchangeFieldKind.Text) { Width = 3 }, ]; /// A number is the serial everyone outside Ukraine sends; anything else is /// an oblast, which goes in the section column as well. public Qso FromExchange1(Qso qso, string typed) => int.TryParse(typed, out int number) ? qso with { ReceivedNumber = number, Section = "" } : qso with { ReceivedNumber = 0, Section = typed.Trim().ToUpperInvariant() }; /// N1MM's log for this contest keeps what the one box was sorted into in a /// column of its own beside the exchange. public IReadOnlyList LogFieldsFor(StationInfo me) => [ .. ExchangeFieldsFor(me), new ExchangeField("Sect", ExchangeSlot.Section, ExchangeFieldKind.Text) { Width = 5 }, ]; public IReadOnlyList MultiplierNamesFor(StationInfo me) => ["Countries", "Oblasts"]; public DupeScope DupeScope => DupeScope.PerBandAndMode; public bool HasSerialNumbers => true; public IReadOnlyList Modes => [ModeCategory.Cw, ModeCategory.Phone]; public string SentExchangeFor(StationInfo me) => IsUkrainian(me.CountryPrefix) ? me.County : "001"; /// What went out on this contact. A Ukrainian station sends the same /// oblast every time; everyone else sends a serial, so the Cabrillo file /// reads the contact's own number and not the first one. N1MM pads it to /// three digits. private string SentExchangeOn(Qso qso, StationInfo me) => IsUkrainian(me.CountryPrefix) ? me.County : $"{qso.SentNumber:000}"; public int PointsFor(QsoContext qso) { if (IsUkrainian(qso.CountryPrefix)) { return IsUkrainian(qso.Me.CountryPrefix) ? 1 : 10; } if (qso.IsSameCountry) { return 1; } return qso.IsSameContinent ? 2 : 3; } public IReadOnlyList MultipliersFor(QsoContext qso) { string band = qso.Band?.Name ?? ""; List found = []; if (qso.CountryPrefix.Length > 0) { found.Add(new Multiplier(1, qso.CountryPrefix, band)); } string oblast = qso.Qso.Section.Trim().ToUpperInvariant(); if (IsUkrainian(qso.CountryPrefix) && oblast.Length > 0) { found.Add(new Multiplier(2, oblast, band)); } return found; } public int TotalScore(ScoreTally tally, ContestEntry entry) => tally.Points * tally.TotalMultipliers; public CabrilloExchange CabrilloExchange(Qso qso, StationInfo me, ContestEntry entry) => new( [ new CabrilloField(me.Callsign, 13), new CabrilloField(qso.SentReport, 3), new CabrilloField(SentExchangeOn(qso, me), 6), ], [ new CabrilloField(qso.Call.Text, 13), new CabrilloField(qso.ReceivedReport, 3), new CabrilloField(qso.Section.Length > 0 ? qso.Section : qso.Exchange1, 6), ]); private static bool IsUkrainian(string countryPrefix) => countryPrefix == "UR"; }