diff --git a/2026-08-28_10-22.png b/2026-08-28_10-22.png new file mode 100644 index 0000000..1738db7 Binary files /dev/null and b/2026-08-28_10-22.png differ diff --git a/2026-08-28_12-45.png b/2026-08-28_12-45.png new file mode 100644 index 0000000..c7fca37 Binary files /dev/null and b/2026-08-28_12-45.png differ diff --git a/2026-08-28_13-41.png b/2026-08-28_13-41.png new file mode 100644 index 0000000..6e50e09 Binary files /dev/null and b/2026-08-28_13-41.png differ diff --git a/digital-20260902-220047.log b/digital-20260902-220047.log new file mode 100644 index 0000000..359e471 --- /dev/null +++ b/digital-20260902-220047.log @@ -0,0 +1,118 @@ + 683 ms > open RTTY Engine 1 "Z:\\home\\erik\\cs2server\\claude\\nonemm_again\\src\\Nonemm.App\\bin\\Debug\\net10.0\\mmtty\\mmtty.exe" -r -Z + 910 ms < ready + 1346 ms < mark 1420 + 1346 ms < space 1590 + 1346 ms < switch 74765 + 1346 ms < view 80 + 1347 ms < connected Ver1.70 + 1347 ms < mark 1420 + 1347 ms < space 1590 + 1347 ms < switch 74765 + 1347 ms < view 80 + 1347 ms < tx 0 + 2158 ms < rx 65 + 2359 ms < rx 75 + 2758 ms < rx 86 + 2758 ms < rx 81 + 3558 ms < rx 86 + 4158 ms < rx 71 + 4158 ms < rx 86 + 4358 ms < rx 81 + 4558 ms < rx 73 + 5958 ms < rx 40 + 6159 ms < rx 59 + 6759 ms < rx 47 + 6958 ms < rx 47 + 7157 ms < rx 36 + 7357 ms < rx 49 + 7758 ms < rx 59 + 8158 ms < rx 71 + 8758 ms < rx 88 + 8958 ms < rx 86 + 9358 ms < rx 81 + 9358 ms < rx 65 + 10158 ms < rx 88 + 10358 ms < rx 71 + 10558 ms < rx 70 + 11358 ms < rx 74 + 11358 ms < rx 81 + 11758 ms < rx 86 + 12358 ms < rx 67 + 12758 ms < rx 81 + 13558 ms < rx 88 + 13758 ms < rx 67 + 14158 ms < rx 34 + 14558 ms < rx 81 + 14758 ms < rx 85 + 15758 ms < rx 55 + 15958 ms < rx 104 + 16758 ms < rx 88 + 17358 ms < rx 80 + 17758 ms < rx 81 + 18158 ms < rx 85 + 18358 ms < rx 85 + 18558 ms < rx 76 + 18958 ms < rx 66 + 19758 ms < rx 87 + 20091 ms > key 1 + 20092 ms < tx 1 + 20092 ms > ptt 1 + 20093 ms > send C + 20094 ms > send Q + 20295 ms > send + 20353 ms < tx 0 + 20354 ms > key 1 + 20354 ms < tx 1 + 20445 ms > send C + 20596 ms > send Q + 20796 ms > send + 20947 ms > send D + 20958 ms < rx 67 + 21097 ms > send E + 21158 ms < rx 81 + 21298 ms > send + 21357 ms < rx 32 + 21447 ms > send O + 21558 ms < rx 68 + 21598 ms > send M + 21747 ms > send 2 + 21758 ms < rx 69 + 21948 ms > send L + 21958 ms < rx 32 + 22098 ms > send T + 22158 ms < rx 79 + 22249 ms > send + 22358 ms < rx 77 + 22449 ms > send O + 22558 ms < rx 50 + 22599 ms > send M + 22750 ms > send 2 + 22900 ms > send L + 22958 ms < rx 76 + 22958 ms < rx 84 + 23101 ms > send T + 23158 ms < rx 32 + 23251 ms > send + 23358 ms < rx 79 + 23401 ms > send C + 23558 ms < rx 77 + 23602 ms > send Q + 23752 ms > send + 23757 ms < rx 50 + 23901 ms > send K + 24102 ms > send \r + 24157 ms < rx 76 + 24358 ms < rx 84 + 24558 ms < rx 32 + 24758 ms < rx 67 + 24958 ms < rx 81 + 24958 ms < rx 32 + 25158 ms < rx 75 + 25358 ms < rx 13 + 29757 ms > ptt 0 + 29757 ms > ptt 0 + 29819 ms < tx 0 + 30958 ms < rx 85 + 31158 ms < rx 13 + 31958 ms < rx 81 + 32358 ms < rx 75 diff --git a/digital-20260902-220539.log b/digital-20260902-220539.log new file mode 100644 index 0000000..eb08e58 --- /dev/null +++ b/digital-20260902-220539.log @@ -0,0 +1,91 @@ + 741 ms > open RTTY Engine 1 "Z:\\home\\erik\\cs2server\\claude\\nonemm_again\\src\\Nonemm.App\\bin\\Debug\\net10.0\\mmtty\\mmtty.exe" -r -Z + 997 ms < ready + 1440 ms < mark 1420 + 1440 ms < space 1590 + 1440 ms < switch 74765 + 1440 ms < view 80 + 1441 ms < connected Ver1.70 + 1441 ms < mark 1420 + 1441 ms < space 1590 + 1441 ms < switch 74765 + 1441 ms < view 80 + 1441 ms < tx 0 + 2252 ms < rx 66 + 2450 ms < rx 75 + 3050 ms < rx 83 + 3450 ms < rx 75 + 3850 ms < rx 85 + 4050 ms < rx 75 + 4249 ms < rx 67 + 4449 ms < rx 86 + 4559 ms > key 1 + 4559 ms < tx 1 + 4561 ms > send C + 4561 ms > send Q + 4762 ms > send + 4912 ms > send C + 5063 ms > send Q + 5249 ms < rx 67 + 5264 ms > send + 5414 ms > send D + 5449 ms < rx 81 + 5565 ms > send E + 5649 ms < rx 32 + 5649 ms < rx 67 + 5715 ms > send + 5849 ms < rx 81 + 5915 ms > send O + 6049 ms < rx 32 + 6065 ms > send M + 6216 ms > send 2 + 6249 ms < rx 68 + 6416 ms > send L + 6449 ms < rx 69 + 6449 ms < rx 32 + 6567 ms > send T + 6649 ms < rx 79 + 6717 ms > send + 6849 ms < rx 77 + 6918 ms > send O + 7049 ms < rx 50 + 7068 ms > send M + 7219 ms > send 2 + 7369 ms > send L + 7449 ms < rx 76 + 7569 ms > send T + 7649 ms < rx 84 + 7719 ms > send + 7849 ms < rx 32 + 7869 ms > send C + 8049 ms < rx 79 + 8070 ms > send Q + 8220 ms > send + 8249 ms < rx 77 + 8370 ms > send K + 8450 ms < rx 50 + 8521 ms > send \r + 8522 ms > ptt 1 + 8849 ms < rx 76 + 9049 ms < rx 84 + 9249 ms < rx 32 + 9449 ms < rx 67 + 9449 ms < rx 81 + 9649 ms < rx 32 + 9849 ms < rx 75 + 10023 ms > ptt 0 + 10023 ms < rx 13 + 10145 ms < tx 0 + 10850 ms < rx 33 + 11049 ms < rx 56 + 12249 ms < rx 87 + 12249 ms < rx 78 + 12449 ms < rx 71 + 12650 ms < rx 81 + 13049 ms < rx 83 + 13249 ms < rx 72 + 13449 ms < rx 85 + 13650 ms < rx 79 + 14249 ms < rx 66 + 14449 ms < rx 66 + 14649 ms < rx 88 + 14649 ms < rx 82 diff --git a/digital-20260902-221237.log b/digital-20260902-221237.log new file mode 100644 index 0000000..160aca0 --- /dev/null +++ b/digital-20260902-221237.log @@ -0,0 +1,260 @@ + 815 ms > open RTTY Engine 1 "Z:\\home\\erik\\cs2server\\claude\\nonemm_again\\src\\Nonemm.App\\bin\\Debug\\net10.0\\mmtty\\mmtty.exe" -r -Z + 1150 ms < ready + 1608 ms < mark 1420 + 1608 ms < space 1590 + 1608 ms < switch 74765 + 1608 ms < view 80 + 1608 ms < connected Ver1.70 + 1608 ms < mark 1420 + 1608 ms < space 1590 + 1608 ms < switch 74765 + 1608 ms < view 80 + 1608 ms < tx 0 + 3025 ms < rx 89 + 4026 ms < rx 80 + 4226 ms < rx 88 + 4426 ms < rx 81 + 4426 ms < rx 71 + 4626 ms < rx 74 + 4826 ms < rx 84 + 5625 ms < rx 87 + 5648 ms > key 1 + 5649 ms < tx 1 + 5650 ms < buffer 0 + 5650 ms > post 4 67 + 5650 ms > post 4 81 + 5851 ms < buffer 1 + 5851 ms > post 4 32 + 6000 ms > post 4 67 + 6026 ms < rx 67 + 6051 ms < buffer 2 + 6151 ms > post 4 81 + 6226 ms < rx 81 + 6352 ms > post 4 32 + 6425 ms < rx 32 + 6453 ms < buffer 1 + 6503 ms > post 4 68 + 6625 ms < rx 67 + 6654 ms > post 4 69 + 6825 ms < rx 81 + 6856 ms > post 4 32 + 7007 ms > post 4 79 + 7025 ms < rx 32 + 7057 ms < buffer 2 + 7158 ms > post 4 77 + 7226 ms < rx 68 + 7308 ms > post 4 50 + 7426 ms < rx 69 + 7426 ms < rx 32 + 7509 ms > post 4 76 + 7626 ms < rx 79 + 7660 ms > post 4 84 + 7660 ms < buffer 3 + 7810 ms > post 4 32 + 7825 ms < rx 77 + 7860 ms < buffer 4 + 7961 ms > post 4 79 + 8026 ms < rx 50 + 8161 ms > post 4 77 + 8312 ms > post 4 50 + 8426 ms < rx 76 + 8463 ms > post 4 76 + 8463 ms < buffer 5 + 8626 ms < rx 84 + 8664 ms > post 4 84 + 8664 ms < buffer 6 + 8814 ms > post 4 32 + 8825 ms < rx 32 + 8826 ms < rx 79 + 8965 ms > post 4 67 + 9026 ms < rx 77 + 9165 ms > post 4 81 + 9316 ms > post 4 32 + 9425 ms < rx 50 + 9465 ms > post 4 75 + 9465 ms < buffer 5 + 9616 ms > post 4 13 + 9617 ms > ptt 1 + 9667 ms < buffer 6 + 9825 ms < rx 76 + 9867 ms < buffer 5 + 10026 ms < rx 84 + 10068 ms < buffer 4 + 10225 ms < rx 32 + 10225 ms < rx 67 + 10268 ms < buffer 2 + 10426 ms < rx 81 + 10469 ms < buffer 1 + 10625 ms < rx 32 + 10670 ms < buffer 0 + 10825 ms < rx 75 + 11026 ms < rx 13 + 11119 ms > ptt 0 + 11549 ms < tx 0 + 12026 ms < rx 75 + 12026 ms < rx 65 + 13026 ms < rx 66 + 13626 ms < rx 86 + 13826 ms < rx 81 + 14228 ms < rx 86 + 14228 ms < rx 87 + 15225 ms < rx 89 + 16026 ms < rx 86 + 16426 ms < rx 89 + 17026 ms < rx 76 + 17443 ms > key 1 + 17444 ms < tx 1 + 17445 ms > post 4 67 + 17445 ms > post 4 65 + 17646 ms > post 4 76 + 17646 ms < buffer 2 + 17797 ms > post 4 76 + 17847 ms < buffer 3 + 17947 ms > post 4 63 + 18026 ms < rx 67 + 18048 ms < buffer 4 + 18148 ms > post 4 32 + 18226 ms < rx 65 + 18298 ms > post 4 67 + 18425 ms < rx 76 + 18449 ms > post 4 65 + 18626 ms < rx 76 + 18649 ms > post 4 76 + 18800 ms > post 4 76 + 18850 ms < buffer 5 + 18951 ms > post 4 63 + 19026 ms < rx 63 + 19026 ms < rx 32 + 19051 ms < buffer 6 + 19101 ms > post 4 32 + 19251 ms < buffer 5 + 19302 ms > post 4 68 + 19425 ms < rx 67 + 19452 ms > post 4 69 + 19452 ms < buffer 6 + 19603 ms > post 4 32 + 19625 ms < rx 65 + 19653 ms < buffer 7 + 19804 ms > post 4 79 + 19825 ms < rx 76 + 19954 ms > post 4 77 + 20026 ms < rx 76 + 20105 ms > post 4 50 + 20225 ms < rx 63 + 20255 ms > post 4 76 + 20425 ms < rx 32 + 20457 ms > post 4 84 + 20457 ms < buffer 8 + 20607 ms > post 4 32 + 20657 ms < buffer 9 + 20757 ms > post 4 75 + 20826 ms < rx 68 + 20826 ms < rx 69 + 20958 ms > post 4 13 + 20958 ms > ptt 1 + 21026 ms < rx 32 + 21225 ms < rx 79 + 21258 ms < buffer 8 + 21426 ms < rx 77 + 21459 ms < buffer 6 + 21625 ms < rx 50 + 21659 ms < buffer 5 + 21861 ms < buffer 4 + 22026 ms < rx 76 + 22062 ms < buffer 3 + 22225 ms < rx 84 + 22263 ms < buffer 1 + 22425 ms < rx 32 + 22458 ms > ptt 0 + 22462 ms < buffer 0 + 22479 ms < rx 75 + 22581 ms < tx 0 + 23826 ms < rx 78 + 24226 ms < rx 67 + 24426 ms < rx 81 + 25026 ms < rx 88 + 25426 ms < rx 82 + 25626 ms < rx 77 + 25826 ms < rx 75 + 26225 ms < rx 83 + 26426 ms < rx 66 + 26625 ms < rx 88 + 26828 ms < rx 75 + 27280 ms > key 1 + 27280 ms > post 4 67 + 27280 ms > post 4 81 + 27281 ms < tx 1 + 27432 ms < buffer 3 + 27481 ms > post 4 32 + 27632 ms > post 4 67 + 27632 ms < buffer 2 + 27782 ms > post 4 81 + 27826 ms < rx 67 + 27833 ms < buffer 3 + 27984 ms > post 4 32 + 28026 ms < rx 81 + 28135 ms > post 4 68 + 28226 ms < rx 32 + 28235 ms < buffer 2 + 28285 ms > post 4 69 + 28426 ms < rx 67 + 28436 ms > post 4 32 + 28626 ms < rx 81 + 28636 ms > post 4 79 + 28787 ms > post 4 77 + 28825 ms < rx 32 + 28837 ms < buffer 3 + 28937 ms > post 4 50 + 29026 ms < rx 68 + 29038 ms < buffer 4 + 29138 ms > post 4 76 + 29225 ms < rx 69 + 29225 ms < rx 32 + 29288 ms > post 4 84 + 29427 ms < rx 79 + 29439 ms > post 4 32 + 29626 ms < rx 77 + 29639 ms > post 4 79 + 29790 ms > post 4 77 + 29826 ms < rx 50 + 29842 ms < buffer 5 + 29941 ms > post 4 50 + 30041 ms < buffer 6 + 30090 ms > post 4 76 + 30226 ms < rx 76 + 30241 ms < buffer 7 + 30291 ms > post 4 84 + 30426 ms < rx 84 + 30441 ms > post 4 32 + 30592 ms > post 4 67 + 30625 ms < rx 32 + 30626 ms < rx 79 + 30793 ms > post 4 81 + 30827 ms < rx 77 + 30943 ms > post 4 32 + 31094 ms > post 4 75 + 31226 ms < rx 50 + 31244 ms > post 4 13 + 31245 ms < buffer 6 + 31245 ms > ptt 1 + 31626 ms < rx 76 + 31646 ms < buffer 5 + 31826 ms < rx 84 + 31826 ms < rx 32 + 31847 ms < buffer 4 + 32026 ms < rx 67 + 32047 ms < buffer 2 + 32227 ms < rx 81 + 32248 ms < buffer 1 + 32425 ms < rx 32 + 32449 ms < buffer 0 + 32625 ms < rx 75 + 32745 ms > ptt 0 + 32745 ms < rx 13 + 32786 ms < tx 0 + 33425 ms < rx 90 + 33826 ms < rx 81 + 34226 ms < rx 75 + 34425 ms < rx 67 + 34825 ms < rx 78 + 35025 ms < rx 77 diff --git a/digital-20260902-234239.log b/digital-20260902-234239.log new file mode 100644 index 0000000..66dd56f --- /dev/null +++ b/digital-20260902-234239.log @@ -0,0 +1,133 @@ + 1093 ms > open RTTY Engine 1 "Z:\\home\\erik\\cs2server\\claude\\nonemm_again\\src\\Nonemm.App\\bin\\Debug\\net10.0\\mmtty\\mmtty.exe" -r -Z + 1636 ms < ready + 1993 ms < mark 1420 + 1994 ms < space 1590 + 1994 ms < switch 74765 + 1994 ms < view 80 + 1994 ms < connected Ver1.70 + 1994 ms < mark 1420 + 1994 ms < space 1590 + 1994 ms < switch 74765 + 1994 ms < view 80 + 1994 ms < tx 0 + 2859 ms < rx 78 + 2859 ms < rx 81 + 3659 ms < rx 75 + 3659 ms < rx 87 + 3859 ms < rx 69 + 4459 ms < rx 87 + 4658 ms < rx 81 + 4859 ms < rx 89 + 5059 ms < rx 82 + 5859 ms < rx 76 + 5859 ms < rx 32 + 5954 ms > key 1 + 5954 ms < tx 1 + 5955 ms < buffer 0 + 5955 ms > send Q CQ DE OM2LT OM2LT CQ K\r + 5955 ms > post 4 67 + 6106 ms < buffer 31 + 6157 ms > ptt 1 + 6308 ms < buffer 29 + 6508 ms < buffer 28 + 6658 ms < rx 81 + 6659 ms < buffer 27 + 6859 ms < rx 32 + 6859 ms < buffer 26 + 7058 ms < rx 67 + 7058 ms < rx 81 + 7060 ms < buffer 25 + 7259 ms < rx 32 + 7260 ms < buffer 24 + 7459 ms < rx 68 + 7461 ms < buffer 22 + 7659 ms < rx 69 + 7661 ms < buffer 21 + 7822 ms > key 0 + 7822 ms < rx 32 + 7822 ms < rx 79 + 7943 ms < tx 0 + 7962 ms < buffer 0 + 8659 ms < rx 78 + 8659 ms < rx 70 + 9248 ms > key 1 + 9248 ms > send CQ CQ DE OM2LT OM2LT CQ K\r + 9249 ms < tx 1 + 9314 ms < buffer 31 + 9349 ms > ptt 1 + 9464 ms < buffer 29 + 9658 ms < rx 67 + 9665 ms < buffer 27 + 9859 ms < rx 81 + 9865 ms < buffer 26 + 10058 ms < rx 32 + 10058 ms < rx 67 + 10066 ms < buffer 25 + 10259 ms < rx 81 + 10266 ms < buffer 24 + 10459 ms < rx 32 + 10466 ms < buffer 23 + 10659 ms < rx 68 + 10667 ms < buffer 22 + 10859 ms < rx 69 + 10867 ms < buffer 20 + 11014 ms > key 0 + 11014 ms < rx 32 + 11075 ms < tx 0 + 11118 ms < buffer 0 + 11459 ms < rx 83 + 11659 ms < rx 87 + 11965 ms > key 1 + 11966 ms < tx 1 + 11966 ms > send W3ZGD DE OM2LT 599 15 599 15 K\r + 12071 ms < buffer 41 + 12117 ms > ptt 1 + 12271 ms < buffer 39 + 12472 ms < buffer 38 + 12659 ms < rx 87 + 12672 ms < buffer 37 + 12873 ms < buffer 36 + 13059 ms < rx 51 + 13073 ms < buffer 35 + 13258 ms < rx 90 + 13274 ms < buffer 33 + 13458 ms < rx 71 + 13476 ms < buffer 32 + 13659 ms < rx 68 + 13676 ms < buffer 31 + 13782 ms > key 0 + 13782 ms < rx 32 + 13844 ms < tx 0 + 13877 ms < buffer 0 + 14059 ms < rx 86 + 14259 ms < rx 76 + 14659 ms < rx 32 + 14859 ms < rx 50 + 14859 ms < rx 52 + 15059 ms < rx 46 + 15459 ms < rx 104 + 15620 ms > key 1 + 15621 ms < tx 1 + 15621 ms > send W3ZGD TU DE OM2LT QRZ\r + 15733 ms < buffer 27 + 15772 ms > ptt 1 + 15883 ms < buffer 26 + 16084 ms < buffer 25 + 16259 ms < rx 87 + 16284 ms < buffer 24 + 16485 ms < buffer 23 + 16659 ms < rx 51 + 16685 ms < buffer 21 + 16859 ms < rx 90 + 16885 ms < buffer 20 + 17059 ms < rx 71 + 17086 ms < buffer 19 + 17259 ms < rx 68 + 17286 ms < buffer 18 + 17437 ms > key 0 + 17437 ms < rx 32 + 17518 ms < tx 0 + 17537 ms < buffer 0 + 18459 ms < rx 40 + 18659 ms < rx 56 + 18859 ms < rx 63 diff --git a/docs/scoring-audit-2026-09-06.md b/docs/scoring-audit-2026-09-06.md index 62075f8..ef6ce3f 100644 --- a/docs/scoring-audit-2026-09-06.md +++ b/docs/scoring-audit-2026-09-06.md @@ -36,6 +36,8 @@ Notable examples: all six WAE RTTY instances matched every compared field. Field 4. **P1 — All Asian implements the wrong rules for Asian entrants.** [AllAsian.cs](../src/Nonemm.Contests/Rules/AllAsian.cs), lines 37 and 46, multiplies every Asian entrant's band points by three and always uses WPX prefixes. Reproductions: JA-to-JA on 20M scored 3 instead of 0; JA-to-UA9 scored 3 instead of 1; JA-to-K1 produced prefix `K1` instead of country `K`. Asian entrants count DXCC entities, same-entity QSOs do not score, and the threefold factor applies to non-Asian contacts. Both the local N1MM `CAA` implementation and the [2026 JARL rules](https://www.jarl.org/English/4_Library/A-4-3_Contests/aadx_eng.html) distinguish these cases. The existing tests only cover a non-Asian entrant. + **Fixed 2026-09-10.** `AllAsian` now asks which side the entrant is on. An Asian entrant cannot work its own country, is paid the band table once for Asia and three times for everywhere else, and counts DXCC entities; everybody else works Asia only and counts WPX prefixes. Maritime mobiles follow the published rule, which N1MM gets half right: a station at sea makes a valid contact with Asian stations alone, pays the Asian rate wherever it is, and never brings a multiplier. `AllAsianTests` covers both entrant sides, all four point values and every band. One cosmetic gap is left: the score window heads the column "Prefixes" for an Asian entrant as well, because `Contest.MultiplierNames` is not asked which station is entering. + 5. **P1 — BARTG HF and Sprint are merged into one incompatible definition.** [BartgSprint.cs](../src/Nonemm.Contests/Rules/BartgSprint.cs) uses report, serial and time, and countries/areas per band, but advertises `BARTGRTTYS` and `BARTG-SPRINT`. [N1mmContestNames.cs](../src/Nonemm.Contests/N1mmContestNames.cs) also maps `BARTGSRTTY` to this class. N1MM has separate `CBARTGSpring` and `CBARTGSprint` classes. The January Sprint exchanges a serial only and counts countries/areas once across bands, as specified in the [BARTG Sprint rules](https://bartg.org.uk/wp-content/uploads/2025/05/bartg-sprint-rules-2025-v3.pdf). Split the definitions and preserve each one's identity, exchange, multiplier scope and export format. Agreement on the supplied March HF log does not validate Sprint support. 6. **P2 — ARRL 10M uses the wrong state multiplier list.** [Arrl10Metre.cs](../src/Nonemm.Contests/Rules/Arrl10Metre.cs), line 49, uses the ARRL DX list. A Mexican `JAL` exchange became country multiplier `XE`; another Mexican state would therefore not add its own multiplier. The code also lacks the contest's maritime ITU-region multiplier treatment, and its send-state decision omits Alaska and Hawaii. Use the actual 10M rules and [ARRL's 32 Mexican multipliers](https://contests.arrl.org/contestmultipliers.php?a=xe), rather than sharing the ARRL DX eligibility list. diff --git a/src/Nonemm.Contests/Rules/AllAsian.cs b/src/Nonemm.Contests/Rules/AllAsian.cs index 680e448..7ca7fc4 100644 --- a/src/Nonemm.Contests/Rules/AllAsian.cs +++ b/src/Nonemm.Contests/Rules/AllAsian.cs @@ -2,10 +2,11 @@ using Nonemm.Core; namespace Nonemm.Contests.Rules; -/// The JARL All Asian DX contest. Only contacts with Asia count for a station -/// outside it. The exchange is the operator's age, the points go by band, and -/// each prefix worked counts once per band. An Asian station scores three -/// times what a station outside Asia scores for the same contact. +/// The JARL All Asian DX contest. It is two contests in one. A station +/// outside Asia works Asia only, and counts the WPX prefix of each Asian +/// station once per band. An Asian station works everybody except its own +/// country, counts countries instead of prefixes, and is paid three times the +/// band value for a contact outside Asia. public sealed class AllAsian : Contest { private readonly ModeCategory mode; @@ -41,13 +42,23 @@ public sealed class AllAsian : Contest { return 0; } - return PointsOn(qso.Band) * (qso.Me.Continent == "AS" ? 3 : 1); + bool treble = qso.Me.Continent == "AS" + && qso.Continent != "AS" + && !qso.Qso.Call.IsMaritimeMobile; + return PointsOn(qso.Band) * (treble ? 3 : 1); } - public IReadOnlyList MultipliersFor(QsoContext qso) => - IsWorkable(qso) && qso.Qso.Call.WpxPrefix() is { } prefix - ? [new Multiplier(1, prefix, qso.Band?.Name ?? "")] - : []; + public IReadOnlyList MultipliersFor(QsoContext qso) + { + if (!IsWorkable(qso) || qso.Qso.Call.IsMaritimeMobile) + { + return []; + } + string? value = qso.Me.Continent == "AS" ? qso.CountryPrefix : qso.Qso.Call.WpxPrefix(); + return string.IsNullOrEmpty(value) + ? [] + : [new Multiplier(1, value, qso.Band?.Name ?? "")]; + } public int TotalScore(ScoreTally tally, ContestEntry entry) => tally.Points * tally.TotalMultipliers; @@ -65,11 +76,17 @@ public sealed class AllAsian : Contest new CabrilloField(qso.Exchange1, 3), ]); - /// One side of every contact has to be in Asia. + /// An Asian station works anybody outside its own country. Everybody else + /// works Asia only, and a maritime mobile is not one of them: a station at + /// sea makes a valid contact with an Asian station alone. public bool IsWorkable(QsoContext qso) => - qso.Continent == "AS" || qso.Me.Continent == "AS"; + qso.Me.Continent == "AS" + ? !qso.IsSameCountry + : qso.Continent == "AS" && !qso.Qso.Call.IsMaritimeMobile; - /// 160 metres is worth 3, 80 and 10 metres 2, and every other band 1. + /// 160 metres is worth 3, 80 and 10 metres 2, and every other band 1. An + /// Asian entrant works from the same table and trebles it outside Asia, + /// except for a maritime mobile, which pays the Asian rate wherever it is. private static int PointsOn(Band? band) => band?.Name switch { "160M" => 3, diff --git a/tests/Nonemm.Contests.Tests/AllAsianTests.cs b/tests/Nonemm.Contests.Tests/AllAsianTests.cs new file mode 100644 index 0000000..9fb614b --- /dev/null +++ b/tests/Nonemm.Contests.Tests/AllAsianTests.cs @@ -0,0 +1,91 @@ +using Nonemm.Contests.Rules; +using Nonemm.Core; + +namespace Nonemm.Contests.Tests; + +/// All Asian is two contests in one class: an entrant outside Asia works Asia +/// for prefixes, and an Asian entrant works everybody else for countries and +/// three times the points. +public class AllAsianTests +{ + private static ContestLog LogFor(StationInfo me) => + new(new AllAsian(ModeCategory.Phone), me, TestLog.CountryFile); + + private static Qso Contact(string call, double kilohertz = 14_150) => + TestLog.Contact(call, kilohertz, mode: Modes.Usb, exchange: "46"); + + /// An Asian entrant scores the band table for another Asian station. + [Theory] + [InlineData(14_150, 1)] + [InlineData(7_050, 1)] + [InlineData(3_650, 2)] + [InlineData(28_450, 2)] + [InlineData(1_830, 3)] + public void AsianEntrantScoresAsiaAtFaceValue(double kilohertz, int expected) => + Assert.Equal( + expected, + LogFor(TestLog.Japan).Judge(Contact("UA9XYZ", kilohertz)).Points); + + /// Outside Asia is where an Asian entrant earns three times as much. + [Theory] + [InlineData(14_150, 3)] + [InlineData(3_650, 6)] + [InlineData(28_450, 6)] + [InlineData(1_830, 9)] + public void AsianEntrantScoresTrebleOutsideAsia(double kilohertz, int expected) => + Assert.Equal( + expected, + LogFor(TestLog.Japan).Judge(Contact("DL9XYZ", kilohertz)).Points); + + /// Two stations in the same country cannot work each other. + [Fact] + public void AsianEntrantCannotWorkItsOwnCountry() + { + Verdict verdict = LogFor(TestLog.Japan).Judge(Contact("JA1XYZ")); + Assert.Equal(0, verdict.Points); + Assert.Empty(verdict.NewMultipliers); + } + + /// An Asian entrant counts countries, not WPX prefixes. + [Fact] + public void AsianEntrantCountsCountries() => + Assert.Equal( + ["K"], + LogFor(TestLog.Japan).Judge(Contact("K1ABC")).NewMultipliers.Select(m => m.Value)); + + /// An entrant outside Asia counts the WPX prefixes of the Asian stations. + [Fact] + public void OutsideEntrantCountsPrefixes() => + Assert.Equal( + ["JA1"], + LogFor(TestLog.Germany).Judge(Contact("JA1XYZ")).NewMultipliers.Select(m => m.Value)); + + /// A maritime mobile is worth nothing to an entrant outside Asia, and + /// brings no multiplier to anybody. + [Fact] + public void MaritimeMobileScoresNothingOutsideAsia() + { + Verdict verdict = LogFor(TestLog.Germany).Judge(Contact("JA1XYZ/MM")); + Assert.Equal(0, verdict.Points); + Assert.Empty(verdict.NewMultipliers); + } + + /// A station at sea pays an Asian entrant the Asian rate, not three times + /// it, and never brings a multiplier. + [Fact] + public void MaritimeMobilePaysAnAsianEntrantTheAsianRate() + { + Verdict verdict = LogFor(TestLog.Japan).Judge(Contact("DL9XYZ/MM")); + Assert.Equal(1, verdict.Points); + Assert.Empty(verdict.NewMultipliers); + } + + /// An entrant outside Asia may only work Asia. + [Fact] + public void OutsideEntrantCannotWorkOutsideAsia() + { + Verdict verdict = LogFor(TestLog.Germany).Judge(Contact("IK2XYZ")); + Assert.Equal(0, verdict.Points); + Assert.Empty(verdict.NewMultipliers); + } +} diff --git a/tests/Nonemm.Contests.Tests/TestLog.cs b/tests/Nonemm.Contests.Tests/TestLog.cs index e9fd9fb..729488e 100644 --- a/tests/Nonemm.Contests.Tests/TestLog.cs +++ b/tests/Nonemm.Contests.Tests/TestLog.cs @@ -60,6 +60,15 @@ public static class TestLog ArrlSection = "CT", }; + public static readonly StationInfo Japan = new() + { + Callsign = "JA1ABC", + CqZone = 25, + ItuZone = 45, + Continent = "AS", + CountryPrefix = "JA", + }; + public static readonly StationInfo Slovakia = new() { Callsign = "OM5M",