Skip to content

Commit

Permalink
CQ WPX - Improved Serial Number generation (Coded by W7SST)
Browse files Browse the repository at this point in the history
- Renamed Settings > NR Digits menu item to Serial NR
- F6FVY provided highest serial number sent by single-ops in CQ WPX 2023
- Added ability to generate serial numbers using actual distribution
- Added new menu picks: Start of Contest, Mid-Contest and End of Contest
- Add new Serial NR > Custom Range... menu pick for user-defined range
- Custom Range... specification can include leading zero (e.g. 001-250)
- Operator's sent Serial NR starts using a random number in the selected
  Mid-Contest or End of Contest modes for greater realism.
- Allow selection changes to Serial NR mode during runtime.

Set user's Serial NR with realistic value for Mid/End Contest modes.
Allow changes to Serial NR mode selection during runtime.
  • Loading branch information
w7sst committed Mar 7, 2024
1 parent 4dde587 commit 022cef5
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 11 deletions.
25 changes: 25 additions & 0 deletions Contest.pas
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,14 @@ TContest = class
procedure DropStation(id : integer); virtual; abstract;
function GetCall(id : integer) : string; virtual; abstract;
procedure GetExchange(id : integer; out station : TDxStation); virtual; abstract;
function GetRandomSerialNR: Integer; virtual;
function GetStationInfo(const ACallsign : string) : string; virtual;
function PickCallOnly : string;

function OnSetMyCall(const AUserCallsign : string; out err : string) : boolean; virtual;
function OnContestPrepareToStart(const AUserCallsign: string;
const ASentExchange : string) : Boolean; virtual;
procedure SerialNrModeChanged; virtual;
function IsFarnsworthAllowed : Boolean;
function GetSentExchTypes(
const AStationKind : TStationKind;
Expand Down Expand Up @@ -169,6 +171,15 @@ function TContest.IsFarnsworthAllowed : Boolean;
end;


{
Return a random serial number for the currently selected Serial NR mode
(a menu pick).
}
function TContest.GetRandomSerialNR: Integer;
begin
Result := Ini.SerialNRSettings[Ini.SerialNR].GetNR;
end;


{
GetStationInfo() returns station's DXCC information.
Expand Down Expand Up @@ -243,6 +254,20 @@ function TContest.OnContestPrepareToStart(const AUserCallsign: string;
end;


{
Called after
- 'Setup | Serial NR' menu pick
- 'Setup | Serial NR | Custom Range...' menu pick/modification
The base class implementation does nothing. Other derived classes can
update cached information based on the serial NR menu pick (e.g. CQ WPX).
}
procedure TContest.SerialNrModeChanged;
begin
assert(RunMode <> rmStop);
end;


{
Return sent dynamic exchange types for the given kind-of-station and callsign.
AStationKind represents either the user's station (representing current
Expand Down
53 changes: 47 additions & 6 deletions CqWpx.pas
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ TCqWpx = class(TContest)
PrevSerialNRType : TSerialNRTypes;
PrevRangeStr : String;

procedure InitSerialNRGen;
function GetNR(const station : TDxStation) : integer;

public
Expand All @@ -30,32 +29,58 @@ TCqWpx = class(TContest)
function OnContestPrepareToStart(const AUserCallsign: string;
const ASentExchange : string) : Boolean; override;
function LoadCallHistory(const AUserCallsign : string) : boolean; override;
procedure SerialNrModeChanged; override;
procedure InitSerialNRGen;

function PickStation(): integer; override;
procedure DropStation(id : integer); override;
function GetCall(id:integer): string; override; // returns station callsign
procedure GetExchange(id : integer; out station : TDxStation); override;
function GetRandomSerialNR: Integer; override;

function getExch1(id:integer): string; // returns RST (e.g. 5NN)
function getExch2(id:integer): string; // returns section info (e.g. 3)
{function getZone(id:integer): string; // returns CQZone (e.g. 3)
function FindCallRec(out fdrec: TCqWpxCallRec; const ACall: string): Boolean;
}
function GetStationInfo(const ACallsign: string) : string; override;
function ExtractMultiplier(Qso: PQso) : string; override;
end;

implementation

uses
SysUtils, Generics.Defaults, System.Math, {Ini,} Classes, ARRL;
SysUtils, Generics.Defaults, System.Math,
Main, // for SetMySerialNR
Classes, ARRL;

function TCqWpx.OnContestPrepareToStart(const AUserCallsign: string;
const ASentExchange : string) : Boolean;
begin
// Refresh Serial NR Generator before calling OnContestPrepareToStart
InitSerialNRGen;

Result := inherited OnContestPrepareToStart(AUserCallsign, ASentExchange);

// reload My Serial Number at start of contest. This allows Mid-Contest and
// End of Contest modes to set Tst.Me.NR with a realistic random number.
if Result then
MainForm.SetMySerialNR;
end;


{
Overriden for the CQ WPX Contest to allow regeneration of the SerialNRGen
tables (based on new Ini.SerialNR setting).
Called after
- 'Setup | Serial NR' menu pick
- 'Setup | Serial NR | Custom Range...' menu pick/modification
This can be called during a Run if the user selects a different
Serial NR distribution (e.g. Mid-Contest, End of Contest, etc.).
}
procedure TCqWpx.SerialNrModeChanged;
begin
assert(RunMode <> rmStop);
InitSerialNRGen;
end;


Expand All @@ -77,6 +102,8 @@ constructor TCqWpx.Create;
inherited Create;
CallLst := TCallList.Create;
SerialNRGen := TSerialNRGen.Create;

InitSerialNRGen;
end;


Expand Down Expand Up @@ -228,6 +255,12 @@ procedure TCqWpx.DropStation(id : integer);
end;


function TCqWpx.GetRandomSerialNR: Integer;
begin
Result := Self.SerialNRGen.GetNR;
end;


// return status bar information string from DXCC data file.
// the callsign, Entity and Continent are returned.
// this string is used in MainForm.sbar.Caption (status bar).
Expand Down Expand Up @@ -271,12 +304,19 @@ procedure TCqWpx.GetExchange(id : integer; out station : TDxStation);
end;


{
Returns the serial number for a DX Station being worked.
For HST or Start-of-Contest serial NR modes, the serial number is based
on elapsed time and operator skill. For Mid-Contest and End-of-Contest
modes, the serial number returned will follow a distribution similar to
the a WPX Contest. See SerNRGen for more information.
}
function TCqWpx.GetNR(const station : TDxStation) : integer;
begin
if (RunMode = rmHST) or (Ini.SerialNR = snStartContest) then
Result := station.Oper.GetNR // Result = f(elapsed time, operator skill)
else
Result := SerialNRGen.GetNR;
Result := GetRandomSerialNR; // follows WPX distribution of serial NRs
end;


Expand All @@ -291,6 +331,7 @@ function TCqWpx.getExch2(id:integer): string; // returns serial number (e.g.
Result := '1';
end;


end.


Expand Down
11 changes: 11 additions & 0 deletions Ini.pas
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ TSerialNRSettings = record
procedure Init(const Range: string; AMin, AMax: integer);
function IsValid : boolean;
function ParseSerialNR(const ValueStr : string; var Err : string) : Boolean;
function GetNR : integer;
end;

PSerialNRSettings = ^TSerialNRSettings;
Expand Down Expand Up @@ -514,6 +515,16 @@ function TSerialNRSettings.IsValid: Boolean;
end;


function TSerialNRSettings.GetNR : integer;
begin
assert(IsValid);
if IsValid then
Result := MinVal + Random(MaxVal - MinVal)
else
Result := 1;
end;


function TSerialNRSettings.ParseSerialNR(
const ValueStr : string;
var Err : string) : Boolean;
Expand Down
28 changes: 23 additions & 5 deletions Main.pas
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,7 @@ TMainForm = class(TForm)
procedure Advance;
procedure SetContest(AContestNum: TSimContest);
procedure SetMyExchange(const AExchange: string);
procedure SetMySerialNR;
procedure SetQsk(Value: boolean);
procedure SetWpm(AWpm : integer);
procedure SetMyCall(ACall: string);
Expand Down Expand Up @@ -1181,6 +1182,13 @@ procedure TMainForm.UpdateTitleBar;
end;


procedure TMainForm.SetMySerialNR;
begin
assert(Tst.Me.SentExchTypes.Exch2 = etSerialNr);
SetMyExch2(Tst.Me.SentExchTypes.Exch2, Ini.UserExchange2[SimContest]);
end;


procedure TMainForm.SetMyCall(ACall: string);
var
err : string;
Expand Down Expand Up @@ -1310,16 +1318,23 @@ procedure TMainForm.SetMyExch1(const AExchType: TExchange1Type;
procedure TMainForm.SetMyExch2(const AExchType: TExchange2Type;
const Avalue: string);
begin
assert(RunMode = rmStop);
// Adding a contest: setup contest-specific exchange field 2
case AExchType of
etSerialNr:
begin
var S : String := Avalue.Replace('T', '0', [rfReplaceAll])
.Replace('O', '0', [rfReplaceAll])
.Replace('N', '9', [rfReplaceAll]);
Ini.UserExchange2[SimContest] := Avalue;
if not IsNum(Avalue) or (RunMode = rmHst) then
Tst.Me.Nr := 1
if SimContest = scHST then
Tst.Me.NR := 1
else if S.Contains('#') and (SerialNR in [snMidContest, snEndContest]) then
Tst.Me.NR := 1 + (Tst.GetRandomSerialNR div 10) * 10
else if IsNum(S) then
Tst.Me.Nr := S.ToInteger
else
Tst.Me.Nr := StrToInt(Avalue);

Tst.Me.Nr := 1;
if BDebugExchSettings then Edit3.Text := IntToStr(Tst.Me.Nr); // testing only
end;
etGenericField, etNaQpExch2, etNaQpNonNaExch2:
Expand Down Expand Up @@ -2344,12 +2359,15 @@ procedure TMainForm.UpdSerialNR(V: integer);
if not Ini.SerialNRSettings[snt].IsValid then
snt := snStartContest;

//Ini.NRDigits := nrd;
Ini.SerialNR := snt;
SerialNRSet1.Checked := snt = snStartContest;
SerialNRSet2.Checked := snt = snMidContest;
SerialNRSet3.Checked := snt = snEndContest;
SerialNRCustomRange.Checked := snt = snCustomRange;

// update contest-specific settings/caches (e.g. SerialNR Generator for CQ Wpx)
if not (RunMode in [rmStop, rmHST]) then
Tst.SerialNrModeChanged;
end;


Expand Down

0 comments on commit 022cef5

Please sign in to comment.