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
114 lines
3.8 KiB
C#
114 lines
3.8 KiB
C#
using Nonemm.Contests.Rules;
|
|
using Nonemm.Core;
|
|
|
|
namespace Nonemm.Contests.Tests;
|
|
|
|
/// CQ WW RTTY is scored differently from the CW and SSB running of the same
|
|
/// contest, so it gets its own tests rather than sharing them.
|
|
public class CqWorldWideRttyTests
|
|
{
|
|
private static readonly Contest Rtty = new CqWorldWide(ModeCategory.Digital);
|
|
|
|
private static ContestLog LogFor(StationInfo me) => new(Rtty, me, TestLog.CountryFile);
|
|
|
|
private static Qso Contact(string call, int zone, string stateOrProvince = "") =>
|
|
TestLog.Contact(call, mode: Modes.Rtty, zone: zone, section: stateOrProvince);
|
|
|
|
[Fact]
|
|
public void ContactInsideYourOwnCountryScoresOne()
|
|
{
|
|
ContestLog log = LogFor(TestLog.Germany);
|
|
Assert.Equal(1, log.Judge(Contact("DL9XYZ", 14)).Points);
|
|
}
|
|
|
|
[Fact]
|
|
public void SameContinentScoresTwo()
|
|
{
|
|
ContestLog log = LogFor(TestLog.Germany);
|
|
Assert.Equal(2, log.Judge(Contact("IK2XYZ", 15)).Points);
|
|
}
|
|
|
|
[Fact]
|
|
public void DifferentContinentScoresThree()
|
|
{
|
|
ContestLog log = LogFor(TestLog.Germany);
|
|
Assert.Equal(3, log.Judge(Contact("JA1XYZ", 25)).Points);
|
|
}
|
|
|
|
[Fact]
|
|
public void TheStateIsAThirdMultiplier()
|
|
{
|
|
ContestLog log = LogFor(TestLog.Germany);
|
|
Verdict verdict = log.Judge(Contact("K1ABC", 5, "CT"));
|
|
|
|
Assert.Equal(
|
|
["5", "K", "CT"],
|
|
verdict.NewMultipliers.Select(m => m.Value).ToList());
|
|
}
|
|
|
|
[Fact]
|
|
public void AStationOutsideTheUnitedStatesAndCanadaBringsNoStateMultiplier()
|
|
{
|
|
ContestLog log = LogFor(TestLog.Germany);
|
|
Verdict verdict = log.Judge(Contact("JA1XYZ", 25, "DX"));
|
|
|
|
Assert.Equal(["25", "JA"], verdict.NewMultipliers.Select(m => m.Value).ToList());
|
|
}
|
|
|
|
[Fact]
|
|
public void TheStateCountsAgainOnAnotherBand()
|
|
{
|
|
ContestLog log = LogFor(TestLog.Germany);
|
|
log.Add(Contact("K1ABC", 5, "CT"));
|
|
Verdict verdict = log.Judge(
|
|
TestLog.Contact("K2DEF", kilohertz: 7_040, mode: Modes.Rtty, zone: 5, section: "CT"));
|
|
|
|
Assert.Contains(verdict.NewMultipliers, m => m.Value == "CT");
|
|
}
|
|
|
|
[Fact]
|
|
public void TheThreeMultiplierNamesAreShown() =>
|
|
Assert.Equal(["Zones", "Countries", "States"], Rtty.MultiplierNames);
|
|
|
|
[Fact]
|
|
public void TheCabrilloNameIsTheRttyOne() => Assert.Equal("CQ-WW-RTTY", Rtty.CabrilloName);
|
|
|
|
/// A station outside the US and Canada sends DX in the state column.
|
|
[Fact]
|
|
public void TheSentExchangeCarriesTheStateOrDx()
|
|
{
|
|
Assert.Equal("14 DX", Rtty.SentExchangeFor(TestLog.Germany));
|
|
Assert.Equal("5 CT", Rtty.SentExchangeFor(TestLog.UnitedStates));
|
|
}
|
|
|
|
[Fact]
|
|
public void TheExchangeHasAStateBoxThatIsNotRequired()
|
|
{
|
|
IReadOnlyList<ExchangeField> fields = Rtty.ExchangeFieldsFor(TestLog.Germany);
|
|
|
|
Assert.Equal(3, fields.Count);
|
|
Assert.Equal(ExchangeSlot.Section, fields[2].Slot);
|
|
Assert.False(fields[2].IsRequired);
|
|
}
|
|
|
|
/// The Canadian areas this contest counts are its own list, which splits
|
|
/// Newfoundland from Labrador.
|
|
[Theory]
|
|
[InlineData("NF")]
|
|
[InlineData("LB")]
|
|
public void TheContestsOwnCanadianAreasCount(string area) =>
|
|
Assert.Contains(
|
|
LogFor(TestLog.Germany).Judge(Contact("VO1XYZ", 5, area)).NewMultipliers,
|
|
m => m.Index == 3 && m.Value == area);
|
|
|
|
/// A maritime mobile station belongs to no country. CQ WW counts it for the
|
|
/// zone alone, and the contact still scores by continent.
|
|
[Fact]
|
|
public void MaritimeMobileScoresButBringsNoCountry()
|
|
{
|
|
Verdict verdict = LogFor(TestLog.Germany).Judge(Contact("IK2XYZ/MM", 15));
|
|
Assert.Equal(2, verdict.Points);
|
|
Assert.DoesNotContain(verdict.NewMultipliers, m => m.Index == 2);
|
|
}
|
|
}
|