From 039b3fdd2d16c07be04c245534d18484578c2685 Mon Sep 17 00:00:00 2001 From: Mike Brashler Date: Tue, 8 Nov 2022 14:50:25 -0800 Subject: [PATCH 1/6] refactor - move code from Ini.FromIni to TMainForm.SetContest --- Ini.pas | 15 ++++++++------- Main.pas | 34 ++++++++++++++++++++++++++++++---- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/Ini.pas b/Ini.pas index c4b22f4..82d6320 100644 --- a/Ini.pas +++ b/Ini.pas @@ -199,9 +199,11 @@ procedure FromIni; ArrlClass := ReadString(SEC_STN, 'ArrlClass', '3A'); ArrlSection := ReadString(SEC_STN, 'ArrlSection', 'OR'); - MainForm.SetMyCall(ReadString(SEC_STN, 'Call', Call)); - MainForm.SetPitch(ReadInteger(SEC_STN, 'Pitch', 3)); - MainForm.SetBw(ReadInteger(SEC_STN, 'BandWidth', 9)); + // load station settings... + // Calls to SetMyCall, SetPitch, SetBw, etc., moved to MainForm.SetContest + Call := ReadString(SEC_STN, 'Call', Call); + MainForm.ComboBox1.ItemIndex := ReadInteger(SEC_STN, 'Pitch', 3); + MainForm.ComboBox2.ItemIndex := ReadInteger(SEC_STN, 'BandWidth', 9); HamName := ReadString(SEC_STN, 'Name', ''); CWOPSNum := ReadString(SEC_STN, 'cwopsnum', CWOPSNum); @@ -210,8 +212,8 @@ procedure FromIni; MainForm.UpdCWMinRxSpeed(ReadInteger(SEC_STN, 'CWMinRxSpeed', MinRxWpm)); MainForm.UpdNRDigits(ReadInteger(SEC_STN, 'NRDigits', NRDigits)); - MainForm.SetWpm(ReadInteger(SEC_STN, 'Wpm', Wpm)); - MainForm.SetQsk(ReadBool(SEC_STN, 'Qsk', Qsk)); + Wpm := ReadInteger(SEC_STN, 'Wpm', Wpm); + Qsk := ReadBool(SEC_STN, 'Qsk', Qsk); CallsFromKeyer := ReadBool(SEC_STN, 'CallsFromKeyer', CallsFromKeyer); GetWpmUsesGaussian := ReadBool(SEC_STN, 'GetWpmUsesGaussian', GetWpmUsesGaussian); @@ -241,8 +243,7 @@ procedure FromIni; begin V := 3; WriteInteger(SEC_SYS, 'BufSize', V); end; V := Max(1, Min(5, V)); BufSize := 64 shl V; - Tst.Filt.SamplesInInput := BufSize; - Tst.Filt2.SamplesInInput := BufSize; + // Tst.Filt{,2}.SamplesInInput: set in TContest.Create & TMainForm.SetContest V := ReadInteger(SEC_STN, 'SelfMonVolume', 0); MainForm.VolumeSlider1.Value := V / 80 + 0.75; diff --git a/Main.pas b/Main.pas index 19bf3b3..daffd57 100644 --- a/Main.pas +++ b/Main.pas @@ -446,8 +446,8 @@ procedure TMainForm.FormCreate(Sender: TObject); ListView2.Visible:= False; ListView2.Clear; - Tst := TContest.Create; - LoadCallList; + //Tst := TContest.Create; + //LoadCallList; // Adding a contest: implement a new contest-specific call history .pas file. // Adding a contest: load call history file (be sure to delete it below). @@ -871,6 +871,11 @@ procedure TMainForm.SetContest(AContestNum: TSimContest); assert(ContestDefinitions[AContestNum].T = AContestNum, 'Contest definitions are out of order'); + + // drop prior contest + if Assigned(Tst) then + FreeAndNil(Tst); + Ini.SimContest := AContestNum; Ini.ActiveContest := @ContestDefinitions[AContestNum]; SimContestCombo.ItemIndex := Ord(AContestNum); @@ -881,8 +886,29 @@ procedure TMainForm.SetContest(AContestNum: TSimContest); sbar.Font.Color := clDefault; sbar.Visible := mnuShowCallsignInfo.Checked; - // update my sent exchange types - Tst.Me.SentExchTypes := Tst.GetSentExchTypes(skMyStation, Ini.Call); + // create new contest + // how to turn this into a factory + //Tst := CreateContest(AContestNum, Ini.Call); + Tst := TContest.Create; + CallLst.LoadCallList; // loads Master.dta + // Tst.LoadCallHistory; // virtual function + + // the following will initialize simulation-specific data owned by contest. + // (this used to reside in Ini.FromIni and called while reading .INI file) + begin + SetMyCall(Ini.Call); + SetPitch(ComboBox1.ItemIndex); + SetBw(ComboBox2.ItemIndex); + SetWpm(Ini.Wpm); + SetQsk(Ini.Qsk); + + // buffer size + Tst.Filt.SamplesInInput := Ini.BufSize; + Tst.Filt2.SamplesInInput := Ini.BufSize; + + // update my sent exchange types (must be called after loading call lists?) + Tst.Me.SentExchTypes:= Tst.GetSentExchTypes(skMyStation, Ini.Call); + end; // update Exchange field labels and length settings (e.g. RST, Nr.) ConfigureExchangeFields(ActiveContest.ExchType1, ActiveContest.ExchType2); From 846e4b7d3f03f55c461a43b2fc1321954aa4e9c1 Mon Sep 17 00:00:00 2001 From: Mike Brashler Date: Thu, 10 Nov 2022 15:25:46 -0800 Subject: [PATCH 2/6] refactor - introduce TContest base class and common behaviors --- ArrlFd.pas | 47 +++++++++++++++++++++++-------------------- CWOPS.pas | 48 +++++++++++++++++++++++++++++--------------- Contest.pas | 50 ++++++++++++++++++++++++++++++++++++++++++++- CqWW.pas | 42 +++++++++++++++++++++----------------- DxStn.pas | 58 +++++++++-------------------------------------------- Ini.pas | 1 - Log.pas | 15 ++++---------- Main.pas | 52 ++++++++++++++++++++++++++--------------------- MyStn.pas | 4 ++-- NaQp.pas | 52 +++++++++++++++++++++++++++++------------------ QrmStn.pas | 3 ++- QrnStn.pas | 6 ++++-- Qsb.pas | 5 ++++- Station.pas | 4 ++-- 14 files changed, 219 insertions(+), 168 deletions(-) diff --git a/ArrlFd.pas b/ArrlFd.pas index e207118..ca3ff03 100644 --- a/ArrlFd.pas +++ b/ArrlFd.pas @@ -7,8 +7,7 @@ interface uses - Generics.Defaults, Generics.Collections, ARRL, - SysUtils, Classes, {Contnrs,} PerlRegEx, pcre; + Generics.Defaults, Generics.Collections, Contest, DxStn; type TFdCallRec = class @@ -21,22 +20,20 @@ TFdCallRec = class class function compareCall(const left, right: TFdCallRec) : integer; static; end; -TArrlFieldDay = class +TArrlFieldDay = class(TContest) private FdCallList: TObjectList; Comparer: IComparer; - procedure LoadFdHistoryFile; - public constructor Create; destructor Destroy; override; - function pickStation(): integer; - //function getcwopsid(): integer; - //function getcwopscall(id:integer): string; - //function getcwopsname(id:integer): string; - //function getcwopsnum(id:integer): integer; - function getCall(id:integer): string; // returns station callsign + procedure LoadCallHistory(const AUserCallsign : string); override; + + function PickStation(): integer; override; + function GetCall(id : integer): string; override; // returns station callsign + procedure GetExchange(id : integer; out station : TDxStation); override; + function getExch1(id:integer): string; // returns station info (e.g. 3A) function getExch2(id:integer): string; // returns section info (e.g. OR) function getClass(id:integer): string; // returns station class (e.g. 3A) @@ -44,19 +41,16 @@ TArrlFieldDay = class function getUserText(id:integer): string; // returns optional club name //function IsNum(Num: String): Boolean; function FindCallRec(out fdrec: TFdCallRec; const ACall: string): Boolean; - function GetStationInfo(const ACallsign: string) : string; + function GetStationInfo(const ACallsign: string) : string; override; end; -var - gARRLFD: TArrlFieldDay; - implementation uses - log; + SysUtils, Classes, Log, PerlRegEx, pcre, ARRL; -procedure TArrlFieldDay.LoadFdHistoryFile; +procedure TArrlFieldDay.LoadCallHistory(const AUserCallsign : string); const DelimitChar: char = ','; var @@ -70,7 +64,7 @@ procedure TArrlFieldDay.LoadFdHistoryFile; tl.StrictDelimiter := True; try - FdCallList:= TObjectList.Create; + FdCallList.Clear; slst.LoadFromFile(ParamStr(1) + 'FD_2022-004.TXT'); @@ -106,8 +100,8 @@ procedure TArrlFieldDay.LoadFdHistoryFile; constructor TArrlFieldDay.Create; begin inherited Create; + FdCallList:= TObjectList.Create; Comparer := TComparer.Construct(TFdCallRec.compareCall); - LoadFdHistoryFile; end; @@ -118,7 +112,7 @@ destructor TArrlFieldDay.Destroy; end; -function TArrlFieldDay.pickStation(): integer; +function TArrlFieldDay.PickStation(): integer; begin result := random(FdCallList.Count); end; @@ -163,7 +157,7 @@ function TArrlFieldDay.GetStationInfo(const ACallsign: string) : string; dxEntity := ''; result:= ''; - if gArrlFd.FindCallRec(fdrec, ACallsign) then + if FindCallRec(fdrec, ACallsign) then begin userText:= fdrec.UserText; @@ -184,12 +178,21 @@ function TArrlFieldDay.GetStationInfo(const ACallsign: string) : string; end; -function TArrlFieldDay.getCall(id:integer): string; // returns station callsign +// returns station callsign +function TArrlFieldDay.GetCall(id : integer): string; begin result := FdCallList.Items[id].Call; end; +procedure TArrlFieldDay.GetExchange(id : integer; out station : TDxStation); +begin + station.Exch1 := getExch1(id); + station.Exch2 := getExch2(id); + station.UserText := getUserText(id); +end; + + function TArrlFieldDay.getExch1(id:integer): string; // returns station info (e.g. 3A) begin result := FdCallList.Items[id].StnClass; diff --git a/CWOPS.pas b/CWOPS.pas index 10bb60d..10c6133 100644 --- a/CWOPS.pas +++ b/CWOPS.pas @@ -3,7 +3,7 @@ interface uses - SysUtils, Classes, Contnrs, PerlRegEx, pcre; + Classes, Contest, Contnrs, DxStn; type TCWOPSRec= class @@ -13,31 +13,33 @@ TCWOPSRec= class Number: string; end; - TCWOPS= class + TCWOPS= class(TContest) private CWOPSList: TList; - procedure LoadCWOPS; procedure Delimit(var AStringList: TStringList; const AText: string); public constructor Create; - function getcwopsid(): integer; - function getcwopscall(id:integer): string; + destructor Destroy; override; + procedure LoadCallHistory(const AUserCallsign : string); override; + + function PickStation(): integer; override; + function GetCall(id : integer): string; override; + procedure GetExchange(id : integer; out station : TDxStation); override; + function getcwopsname(id:integer): string; function getcwopsnum(id:integer): integer; - function IsNum(Num: String): Boolean; end; -var - CWOPSCWT: TCWOPS; + function IsNum(Num: String): Boolean; implementation uses - log; + SysUtils, Log; -procedure TCWOPS.LoadCWOPS; +procedure TCWOPS.LoadCallHistory(const AUserCallsign : string); var slst, tl: TStringList; i: integer; @@ -46,7 +48,7 @@ procedure TCWOPS.LoadCWOPS; slst:= TStringList.Create; tl:= TStringList.Create; try - CWOPSList:= TList.Create; + CWOPSList.Clear; slst.LoadFromFile(ParamStr(1) + 'CWOPS.LIST'); slst.Sort; @@ -81,21 +83,35 @@ procedure TCWOPS.LoadCWOPS; constructor TCWOPS.Create; begin inherited Create; - LoadCWOPS; + CWOPSList:= TList.Create; end; -function TCWOPS.getcwopsid(): integer; +destructor TCWOPS.Destroy; begin - result := random(CWOPSList.Count); + FreeAndNil(CWOPSList); + inherited; end; -function TCWOPS.getcwopscall(id:integer): string; +function TCWOPS.PickStation(): integer; +begin + result := random(CWOPSList.Count); +end; + +function TCWOPS.GetCall(id : integer): string; begin result := TCWOPSRec(CWOPSList.Items[id]).Call; end; + +procedure TCWOPS.GetExchange(id : integer; out station : TDxStation); +begin + station.OpName := getcwopsname(id); + station.NR := getcwopsnum(id); +end; + + function TCWOPS.getcwopsname(id:integer): string; begin @@ -108,7 +124,7 @@ function TCWOPS.getcwopsnum(id:integer): integer; result := strtoint(TCWOPSRec(CWOPSList.Items[id]).Number); end; -function TCWOPS.IsNum(Num: String): Boolean; +function IsNum(Num: String): Boolean; var X : Integer; begin diff --git a/Contest.pas b/Contest.pas index c7caa1d..e0d652a 100644 --- a/Contest.pas +++ b/Contest.pas @@ -29,6 +29,13 @@ TContest = class constructor Create; destructor Destroy; override; procedure Init; + procedure LoadCallHistory(const AUserCallsign : string); virtual; + + function PickStation : integer; virtual; + function GetCall(id : integer) : string; virtual; + procedure GetExchange(id : integer; out station : TDxStation); virtual; + function GetStationInfo(const ACallsign : string) : string; virtual; + function GetSentExchTypes( const AStationKind : TStationKind; const AMyCallsign : string) : TExchTypes; @@ -49,7 +56,7 @@ TContest = class implementation uses - Main; + Main, CallLst, ARRL; { TContest } @@ -105,6 +112,47 @@ procedure TContest.Init; end; +procedure TContest.LoadCallHistory(const AUserCallsign : string); +begin + assert(SimContest in [scWpx, scHst]); + if SimContest in [scWPX, scHst] then + CallLst.LoadCallList; // loads Master.dta (p/o CQ WPX Contest) +end; + + +function TContest.PickStation : integer; +begin + assert(SimContest in [scWpx, scHst], 'PickStation should be overriden'); + Result := -1; +end; + + +function TContest.GetCall(id : integer) : string; +begin + assert(SimContest in [scWpx, scHst]); + Result := CallLst.PickCall; +end; + + +procedure TContest.GetExchange(id : integer; out station : TDxStation); +begin + assert(SimContest in [scWpx, scHst]); + station.NR := station.Oper.GetNR; +end; + + +{ + GetStationInfo() returns station's DXCC information. + + Adding a contest: UpdateSbar - update status bar with station info (e.g. FD shows UserText) + Override as needed for each contest. +} +function TContest.GetStationInfo(const ACallsign : string) : string; +begin + Result := gDXCCList.Search(ACallsign); +end; + + { Return sent dynamic exchange types for the given kind-of-station and callsign. } diff --git a/CqWW.pas b/CqWW.pas index 0184662..9774ca7 100644 --- a/CqWW.pas +++ b/CqWW.pas @@ -7,8 +7,7 @@ interface uses - Generics.Defaults, Generics.Collections, - SysUtils, Classes, {Contnrs,} PerlRegEx, pcre; + Generics.Defaults, Generics.Collections, Contest, DxStn; type TCqWwCallRec = class @@ -20,35 +19,34 @@ TCqWwCallRec = class class function compareCall(const left, right: TCqWwCallRec) : integer; static; end; -TCqWw = class +TCqWw = class(TContest) private CqWwCallList: TObjectList; Comparer: IComparer; - procedure LoadHistoryFile; - public constructor Create; destructor Destroy; override; - function pickStation(): integer; - function getCall(id:integer): string; // returns station callsign + procedure LoadCallHistory(const AUserCallsign : string); override; + + function PickStation(): integer; override; + function GetCall(id:integer): string; override; // returns station callsign + procedure GetExchange(id : integer; out station : TDxStation); 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: TCqWwCallRec; const ACall: string): Boolean; - function GetStationInfo(const ACallsign: string) : string; + function GetStationInfo(const ACallsign: string) : string; override; function IsNum(Num: String): Boolean; end; -var - gCQWW: TCqWw; - implementation uses - log, ARRL; + SysUtils, Classes, log, ARRL; -procedure TCqWw.LoadHistoryFile; +procedure TCqWw.LoadCallHistory(const AUserCallsign : string); const DelimitChar: char = ','; var @@ -62,7 +60,7 @@ procedure TCqWw.LoadHistoryFile; tl.StrictDelimiter := True; try - CqWwCallList := TObjectList.Create; + CqWwCallList.Clear; slst.LoadFromFile(ParamStr(1) + 'CQWWCW.TXT'); @@ -94,8 +92,8 @@ procedure TCqWw.LoadHistoryFile; constructor TCqWw.Create; begin inherited Create; + CqWwCallList := TObjectList.Create; Comparer := TComparer.Construct(TCqWwCallRec.compareCall); - LoadHistoryFile; end; @@ -106,7 +104,7 @@ destructor TCqWw.Destroy; end; -function TCqWw.pickStation(): integer; +function TCqWw.PickStation(): integer; begin result := random(CqWwCallList.Count); end; @@ -151,7 +149,7 @@ function TCqWw.GetStationInfo(const ACallsign: string) : string; dxEntity := ''; result:= ''; - if gCQWW.FindCallRec(fdrec, ACallsign) then + if Self.FindCallRec(fdrec, ACallsign) then begin userText:= fdrec.UserText; @@ -171,12 +169,20 @@ function TCqWw.GetStationInfo(const ACallsign: string) : string; end; -function TCqWw.getCall(id:integer): string; // returns station callsign +function TCqWw.getCall(id : integer): string; // returns station callsign begin result := CqWwCallList.Items[id].Call; end; +procedure TCqWw.GetExchange(id : integer; out station : TDxStation); +begin + station.Exch2 := getExch2(station.Operid); + station.NR := StrToInt(getExch2(station.Operid)); +end; + + + function TCqWw.getExch1(id:integer): string; // returns RST (e.g. 5NN) begin result := '5NN'; diff --git a/DxStn.pas b/DxStn.pas index b0814c3..db67827 100644 --- a/DxStn.pas +++ b/DxStn.pas @@ -8,9 +8,7 @@ interface uses - SysUtils, Classes, Station, RndFunc, Dialogs, Ini, ARRLFD, NAQP, CWOPS, - CQWW, - CallLst, Qsb, DxOper, Log, SndTypes; + Station, Qsb, DxOper, SndTypes; type TDxStation = class(TStation) @@ -32,7 +30,8 @@ TDxStation = class(TStation) implementation uses - Contest; + SysUtils, Classes, RndFunc, Dialogs, + CallLst, Log, Ini, Contest; { TDxStation } @@ -41,27 +40,10 @@ constructor TDxStation.CreateStation; inherited Create(nil); HisCall := Ini.Call; - // Adding a contest: DxStation.CreateStation - load a random callsign - case SimContest of - scCwt: begin - Operid := CWOPSCWT.getcwopsid(); - MyCall := CWOPSCWT.getcwopscall(Operid); - end; - scFieldDay: begin - Operid := gARRLFD.pickStation(); - MyCall := gARRLFD.getCall(Operid); - end; - scNaQp: begin - Operid := gNAQP.pickStation(); - MyCall := gNAQP.getCall(Operid); - end; - scCQWW: begin - Operid := gCQWW.pickStation(); - MyCall := gCQWW.getCall(Operid); - end - else - MyCall := PickCall; // Pick one Callsign from Calllist - end; + + // Pick one Callsign from call history file + Operid := Tst.PickStation; + MyCall := Tst.GetCall(Operid); Oper := TDxOperator.Create; Oper.Call := MyCall; @@ -75,30 +57,8 @@ constructor TDxStation.CreateStation; SentExchTypes := Tst.GetSentExchTypes(skDxStation, MyCall); // Adding a contest: DxStation.CreateStation - get Exch1 (e.g. Name), Exch2 (e.g. NR), and optional UserText - case SimContest of - scCwt: begin - OpName := CWOPSCWT.getcwopsname(Operid); - NR := CWOPSCWT.getcwopsnum(Operid); - end; - scFieldDay: begin - Exch1 := gARRLFD.getExch1(Operid); - Exch2 := gARRLFD.getExch2(Operid); - UserText := gARRLFD.getUserText(Operid); - end; - scNaQp: begin - Exch1 := gNAQP.getExch1(Operid); - OpName := Exch1; // TODO - refactor etOpName to use Exch1 - Exch2 := gNAQP.getExch2(Operid); - UserText := gNAQP.getUserText(Operid); - end; - scCQWW: begin - Exch2 := gCQWW.getExch2(Operid); - NR := StrToInt(gCQWW.getExch2(Operid)); - end - else - NR := Oper.GetNR; - end; - //showmessage(MyCall); + // load dynamic exchange field information into this DxStation. + Tst.GetExchange(Operid, Self); if Ini.Lids and (Random < 0.03) then RST := 559 + 10 * Random(4) diff --git a/Ini.pas b/Ini.pas index 82d6320..c92987a 100644 --- a/Ini.pas +++ b/Ini.pas @@ -243,7 +243,6 @@ procedure FromIni; begin V := 3; WriteInteger(SEC_SYS, 'BufSize', V); end; V := Max(1, Min(5, V)); BufSize := 64 shl V; - // Tst.Filt{,2}.SamplesInInput: set in TContest.Create & TMainForm.SetContest V := ReadInteger(SEC_STN, 'SelfMonVolume', 0); MainForm.VolumeSlider1.Value := V / 80 + 0.75; diff --git a/Log.pas b/Log.pas index fa2613a..05bb547 100644 --- a/Log.pas +++ b/Log.pas @@ -8,9 +8,7 @@ interface uses - Windows, SysUtils, Classes, Graphics, RndFunc, Math, Controls, - StdCtrls, ExtCtrls, ARRL, ARRLFD, NAQP, PerlRegEx, pcre; - + Classes, Controls, ExtCtrls; procedure SaveQso; procedure LastQsoToScreen; @@ -68,6 +66,8 @@ THisto= class(TObject) implementation uses + Windows, SysUtils, Graphics, RndFunc, Math, + StdCtrls, PerlRegEx, pcre, Contest, Main, DxStn, DxOper, Ini, MorseKey; @@ -145,14 +145,7 @@ procedure UpdateSbar(const ACallsign: string); s: string; begin // Adding a contest: UpdateSbar - update status bar with station info (e.g. FD shows UserText) - case Ini.SimContest of - scFieldDay: - s := gArrlFd.GetStationInfo(ACallsign); - scNaQp: - s := gNAQP.GetStationInfo(ACallsign); - else - s := gDXCCList.Search(ACallsign); - end; + s := Tst.GetStationInfo(ACallsign); // '&' are suppressed in this control; replace with '&&' s:= StringReplace(s, '&', '&&', [rfReplaceAll]); diff --git a/Main.pas b/Main.pas index daffd57..51dfc41 100644 --- a/Main.pas +++ b/Main.pas @@ -352,6 +352,7 @@ TMainForm = class(TForm) private MustAdvance: boolean; + function CreateContest(AContestId : TSimContest) : TContest; procedure ConfigureExchangeFields( AExchType1: TExchange1Type; AExchType2: TExchange2Type); @@ -446,16 +447,8 @@ procedure TMainForm.FormCreate(Sender: TObject); ListView2.Visible:= False; ListView2.Clear; - //Tst := TContest.Create; - //LoadCallList; - - // Adding a contest: implement a new contest-specific call history .pas file. - // Adding a contest: load call history file (be sure to delete it below). + // load DXCC support gDXCCList := TDXCC.Create; - gARRLFD := TArrlFieldDay.Create; - gNAQP := TNcjNaQp.Create; - gCQWW := TCqWW.Create; - CWOPSCWT := TCWOPS.Create; Histo:= THisto.Create(PaintBox1); @@ -466,6 +459,7 @@ procedure TMainForm.FormCreate(Sender: TObject); Keyer.Rate := DEFAULTRATE; Keyer.BufSize := Ini.BufSize; + // create a derived TContest of the appropriate type SetContest(Ini.SimContest); end; @@ -474,16 +468,29 @@ procedure TMainForm.FormDestroy(Sender: TObject); begin ToIni; gDXCCList.Free; - gARRLFD.Free; - gNAQP.Free; - gCQWW.Free; - CWOPSCWT.Free; Histo.Free; Tst.Free; DestroyKeyer; end; +// Contest Factory - allocate a derived TContest of the appropriate type +function TMainForm.CreateContest(AContestId : TSimContest) : TContest; +begin + // Adding a contest: implement a new contest-specific call history .pas file. + Result := nil; + case AContestId of + scWpx, scHst: Result := TContest.Create; + scCwt: Result := TCWOPS.Create; + scFieldDay: Result := TArrlFieldDay.Create; + scNaQp: Result := TNcjNaQp.Create; + scCQWW: Result := TCqWW.Create; + else + assert(false); + end; +end; + + procedure TMainForm.AlSoundOut1BufAvailable(Sender: TObject); begin if AlSoundOut1.Enabled then @@ -887,14 +894,10 @@ procedure TMainForm.SetContest(AContestNum: TSimContest); sbar.Visible := mnuShowCallsignInfo.Checked; // create new contest - // how to turn this into a factory - //Tst := CreateContest(AContestNum, Ini.Call); - Tst := TContest.Create; - CallLst.LoadCallList; // loads Master.dta - // Tst.LoadCallHistory; // virtual function + Tst := CreateContest(AContestNum); // the following will initialize simulation-specific data owned by contest. - // (this used to reside in Ini.FromIni and called while reading .INI file) + // (moved here from Ini.FromIni) begin SetMyCall(Ini.Call); SetPitch(ComboBox1.ItemIndex); @@ -902,9 +905,12 @@ procedure TMainForm.SetContest(AContestNum: TSimContest); SetWpm(Ini.Wpm); SetQsk(Ini.Qsk); - // buffer size - Tst.Filt.SamplesInInput := Ini.BufSize; - Tst.Filt2.SamplesInInput := Ini.BufSize; + // buffer size - set in TContest.Create() + assert(Tst.Filt.SamplesInInput = Ini.BufSize); + assert(Tst.Filt2.SamplesInInput = Ini.BufSize); + + // load contest-specific call history file + Tst.LoadCallHistory(Ini.Call); // update my sent exchange types (must be called after loading call lists?) Tst.Me.SentExchTypes:= Tst.GetSentExchTypes(skMyStation, Ini.Call); @@ -2041,7 +2047,7 @@ procedure TMainForm.CWOPSNumberClick(Sender: TObject); if buf = '' then begin exit; end; - if CWOPSCWT.isnum(buf)=False then begin + if not CWOPS.isnum(buf) then begin exit; end; CWOPSNum := buf; diff --git a/MyStn.pas b/MyStn.pas index 03459ee..4489649 100644 --- a/MyStn.pas +++ b/MyStn.pas @@ -8,7 +8,7 @@ interface uses - SysUtils, Classes, Station, RndFunc, Ini, SndTypes, MorseKey; + Station, Classes, SndTypes; type TMyStation = class(TStation) @@ -31,7 +31,7 @@ TMyStation = class(TStation) implementation uses - Contest, Main; + SysUtils, RndFunc, Ini, MorseKey, Contest, Main; { TMyStation } diff --git a/NaQp.pas b/NaQp.pas index 4c60d2e..221e529 100644 --- a/NaQp.pas +++ b/NaQp.pas @@ -3,9 +3,7 @@ interface uses - Generics.Defaults, Generics.Collections, ARRL, - StrUtils, - SysUtils, Classes, Contnrs, PerlRegEx, pcre; + Generics.Defaults, Generics.Collections, Contest, DxStn; type TNaQpCallRec = class @@ -18,36 +16,37 @@ TNaQpCallRec = class class function compareCall(const left, right: TNaQpCallRec) : integer; static; end; -TNcjNaQp = class +TNcjNaQp = class(TContest) private NaQpCallList: TList; Comparer: IComparer; - procedure LoadHistoryFile; - public constructor Create; - function pickStation(): integer; - function getCall(id:integer): string; // returns station callsign + destructor Destroy; override; + procedure LoadCallHistory(const AUserCallsign : string); override; + + function PickStation(): integer; override; + function GetCall(id : integer): string; override; // returns station callsign + procedure GetExchange(id : integer; out station : TDxStation); override; + function getExch1(id:integer): string; // returns station info (e.g. MIKE) function getExch2(id:integer): string; // returns section info (e.g. OR) function getName(id:integer): string; // returns station op name (e.g. MIKE) function getState(id:integer): string; // returns state (e.g. OR) function getUserText(id:integer): string; // returns optional UserText function FindCallRec(out recOut: TNaQpCallRec; const ACall: string): Boolean; - function GetStationInfo(const ACallsign: string) : string; + function GetStationInfo(const ACallsign: string) : string; override; end; -var - gNAQP: TNcjNaQp; - implementation uses - log; + StrUtils, SysUtils, Classes, Contnrs, PerlRegEx, pcre, + log, ARRL; -procedure TNcjNaQp.LoadHistoryFile; +procedure TNcjNaQp.LoadCallHistory(const AUserCallsign : string); const DelimitChar: char = ','; var @@ -61,7 +60,7 @@ procedure TNcjNaQp.LoadHistoryFile; tl.StrictDelimiter := True; try - NaQpCallList:= TList.Create; + NaQpCallList.Clear; slst.LoadFromFile(ParamStr(1) + 'NAQPCW.TXT'); @@ -96,12 +95,19 @@ procedure TNcjNaQp.LoadHistoryFile; constructor TNcjNaQp.Create; begin inherited Create; + NaQpCallList := TList.Create; Comparer := TComparer.Construct(TNaQpCallRec.compareCall); - LoadHistoryFile; end; -function TNcjNaQp.pickStation(): integer; +destructor TNcjNaQp.Destroy; +begin + FreeAndNil(NaQpCallList); + inherited; +end; + + +function TNcjNaQp.PickStation(): integer; begin result := random(NaQpCallList.Count); end; @@ -142,7 +148,7 @@ function TNcjNaQp.GetStationInfo(const ACallsign: string) : string; dxEntity := ''; result:= ''; - if gNAQP.FindCallRec(rec, ACallsign) then + if FindCallRec(rec, ACallsign) then begin userText:= rec.UserText; @@ -163,12 +169,20 @@ function TNcjNaQp.GetStationInfo(const ACallsign: string) : string; end; -function TNcjNaQp.getCall(id:integer): string; // returns station callsign +function TNcjNaQp.GetCall(id : integer): string; // returns station callsign begin result := NaQpCallList.Items[id].Call; end; +procedure TNcjNaQp.GetExchange(id : integer; out station : TDxStation); +begin + station.Exch1 := getExch1(station.Operid); + station.OpName := station.Exch1; // TODO - refactor etOpName to use Exch1 + station.Exch2 := getExch2(station.Operid); + station.UserText := getUserText(station.Operid); +end; + function TNcjNaQp.getExch1(id:integer): string; // returns station info (e.g. MIKE) begin result := NaQpCallList.Items[id].Name; diff --git a/QrmStn.pas b/QrmStn.pas index c0d120a..29e3fa2 100644 --- a/QrmStn.pas +++ b/QrmStn.pas @@ -8,7 +8,7 @@ interface uses - SysUtils, Classes, Station, RndFunc, Ini, CallLst; + Station; type TQrmStation = class(TStation) @@ -22,6 +22,7 @@ TQrmStation = class(TStation) implementation uses + SysUtils, Classes, RndFunc, Ini, CallLst, Contest; constructor TQrmStation.CreateStation; diff --git a/QrnStn.pas b/QrnStn.pas index 661d425..9bbe7e1 100644 --- a/QrnStn.pas +++ b/QrnStn.pas @@ -8,8 +8,7 @@ interface uses - SysUtils, Classes, Station, RndFunc, Ini, CallLst, - Math; + Station; type TQrnStation = class(TStation) @@ -20,6 +19,9 @@ TQrnStation = class(TStation) implementation +uses + Ini, RndFunc, Math; + constructor TQrnStation.CreateStation; var i: integer; diff --git a/Qsb.pas b/Qsb.pas index 9eddc1e..b8083b8 100644 --- a/Qsb.pas +++ b/Qsb.pas @@ -8,7 +8,7 @@ interface uses - SysUtils, QuickAvg, SndTypes, RndFunc, Math, Ini; + QuickAvg, SndTypes; type TQsb = class @@ -29,6 +29,9 @@ TQsb = class implementation +uses + SysUtils, RndFunc, Math, Ini; + constructor TQsb.Create; begin diff --git a/Station.pas b/Station.pas index bc45d64..3565a65 100644 --- a/Station.pas +++ b/Station.pas @@ -8,7 +8,7 @@ interface uses - SysUtils, Classes, Math, SndTypes, Ini, MorseKey; + Classes, SndTypes, Ini; const NEVER = MAXINT; @@ -96,7 +96,7 @@ TStation = class (TCollectionItem) implementation uses - Contest; + SysUtils, Math, MorseKey, Contest; { TExchTypes } From 69fdf25ee813bfb2eea4aef02610c78c6d05e65a Mon Sep 17 00:00:00 2001 From: Mike Brashler Date: Sat, 12 Nov 2022 15:02:06 -0800 Subject: [PATCH 3/6] refactor TContest hierarchy - add TCqWpx class --- CallLst.pas | 38 +++++++++++----- Contest.pas | 26 +++++++---- CqWpx.pas | 112 ++++++++++++++++++++++++++++++++++++++++++++++ Main.pas | 9 ++-- MorseRunner.dpr | 3 +- MorseRunner.dproj | 1 + QrmStn.pas | 2 +- 7 files changed, 167 insertions(+), 24 deletions(-) create mode 100644 CqWpx.pas diff --git a/CallLst.pas b/CallLst.pas index 176338a..dfc966c 100644 --- a/CallLst.pas +++ b/CallLst.pas @@ -8,22 +8,34 @@ interface uses - SysUtils, Classes, Ini; - -procedure LoadCallList; -function PickCall: string; + Classes; + +type + // simple calllist. contains a TStringList of callsigns. + TCallList = class + protected + Calls: TStringList; + + public + constructor Create; + destructor Destroy; + procedure LoadCallList; + function PickCall : string; + end; -var - Calls: TStringList; implementation +uses + SysUtils, Ini; + function CompareCalls(Item1, Item2: Pointer): Integer; begin Result := StrComp(PChar(Item1), PChar(Item2)); end; -procedure LoadCallList; +// reads callsigns from Master.dta file +procedure TCallList.LoadCallList; const Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/'; CHRCOUNT = Length(Chars); @@ -89,7 +101,8 @@ procedure LoadCallList; end; -function PickCall: string; +// returns a single callsign +function TCallList.PickCall : string; var Idx: integer; begin @@ -106,11 +119,16 @@ function PickCall: string; end; -initialization +constructor TCallList.Create; +begin Calls := TStringList.Create; +end; -finalization +destructor TCallList.Destroy; +begin Calls.Free; +end; + end. diff --git a/Contest.pas b/Contest.pas index e0d652a..6c440fc 100644 --- a/Contest.pas +++ b/Contest.pas @@ -16,6 +16,8 @@ TContest = class private function DxCount: integer; procedure SwapFilters; + protected + constructor Create; public BlockNumber: integer; Me: TMyStation; @@ -26,7 +28,6 @@ TContest = class RitPhase: Single; FStopPressed: boolean; - constructor Create; destructor Destroy; override; procedure Init; procedure LoadCallHistory(const AUserCallsign : string); virtual; @@ -35,6 +36,7 @@ TContest = class function GetCall(id : integer) : string; virtual; procedure GetExchange(id : integer; out station : TDxStation); virtual; function GetStationInfo(const ACallsign : string) : string; virtual; + function PickCallOnly : string; function GetSentExchTypes( const AStationKind : TStationKind; @@ -114,30 +116,26 @@ procedure TContest.Init; procedure TContest.LoadCallHistory(const AUserCallsign : string); begin - assert(SimContest in [scWpx, scHst]); - if SimContest in [scWPX, scHst] then - CallLst.LoadCallList; // loads Master.dta (p/o CQ WPX Contest) end; function TContest.PickStation : integer; begin - assert(SimContest in [scWpx, scHst], 'PickStation should be overriden'); + assert(false, 'PickStation should be overriden'); Result := -1; end; function TContest.GetCall(id : integer) : string; begin - assert(SimContest in [scWpx, scHst]); - Result := CallLst.PickCall; + assert(false, 'GetCall should be overriden'); + Result := ''; end; procedure TContest.GetExchange(id : integer; out station : TDxStation); begin - assert(SimContest in [scWpx, scHst]); - station.NR := station.Oper.GetNR; + assert(false, 'PickStation should be overriden'); end; @@ -153,6 +151,16 @@ function TContest.GetStationInfo(const ACallsign : string) : string; end; +// helper function to return only a callsign (used by QrnStation) +function TContest.PickCallOnly : string; +var + id : integer; +begin + id := PickStation; + Result := GetCall(id); +end; + + { Return sent dynamic exchange types for the given kind-of-station and callsign. } diff --git a/CqWpx.pas b/CqWpx.pas new file mode 100644 index 0000000..2a3fb57 --- /dev/null +++ b/CqWpx.pas @@ -0,0 +1,112 @@ +unit CQWPX; + +{$ifdef FPC} +{$MODE Delphi} +{$endif} + +interface + +uses + Contest, CallLst, DxStn; + +type +TCqWpx = class(TContest) +private + // CQ Wpx Contest uses the global Calls variable (see CallLst.pas) + CallLst : TCallList; + +public + constructor Create; + destructor Destroy; override; + procedure LoadCallHistory(const AUserCallsign : string); override; + + function PickStation(): integer; override; + function GetCall(id:integer): string; override; // returns station callsign + procedure GetExchange(id : integer; out station : TDxStation); 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; +end; + +implementation + +uses + SysUtils, Classes, log, ARRL; + +procedure TCqWpx.LoadCallHistory(const AUserCallsign : string); +begin + CallLst.LoadCallList; +end; + + +constructor TCqWpx.Create; +begin + inherited Create; + CallLst := TCallList.Create; +end; + + +destructor TCqWpx.Destroy; +begin + CallLst.Free; + inherited; +end; + + +function TCqWpx.PickStation(): integer; +begin + Result := -1; +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). +// Format: ' - Entity/Continent' +function TCqWpx.GetStationInfo(const ACallsign: string) : string; +var + dxrec : TDXCCRec; +begin + dxrec := nil; + Result := ''; + + // find caller's Continent/Entity + if gDXCCList.FindRec(dxrec, ACallsign) then + Result := Format('%s - %s/%s', [ACallsign, dxRec.Continent, dxRec.Entity]); +end; + + +function TCqWpx.GetCall(id : integer): string; // returns station callsign +begin + Result := CallLst.PickCall; +end; + + +procedure TCqWpx.GetExchange(id : integer; out station : TDxStation); +begin + station.Exch1 := getExch1(station.Operid); // RST + station.NR := station.Oper.GetNR; // serial number +end; + + + +function TCqWpx.getExch1(id:integer): string; // returns RST (e.g. 5NN) +begin + result := '599'; +end; + + +function TCqWpx.getExch2(id:integer): string; // returns serial number (e.g. 3) +begin + Result := '1'; +end; + + +end. + + + diff --git a/Main.pas b/Main.pas index 51dfc41..a7d576c 100644 --- a/Main.pas +++ b/Main.pas @@ -16,7 +16,7 @@ interface Buttons, SndCustm, SndOut, Contest, Ini, MorseKey, CallLst, VolmSldr, VolumCtl, StdCtrls, Station, Menus, ExtCtrls, MAth, ComCtrls, Spin, SndTypes, ShellApi, jpeg, ToolWin, ImgList, Crc32, - WavFile, IniFiles, Idhttp, ARRL, ARRLFD, NAQP, CWOPS, CQWW, + WavFile, IniFiles, Idhttp, System.ImageList; const @@ -410,7 +410,10 @@ function ToStr(const val : TExchange2Type): string; overload; MainForm: TMainForm; implementation -uses TypInfo, ScoreDlg, Log, PerlRegEx; + +uses + ARRL, ARRLFD, NAQP, CWOPS, CQWW, CQWPX, + TypInfo, ScoreDlg, Log, PerlRegEx; {$R *.DFM} @@ -480,7 +483,7 @@ function TMainForm.CreateContest(AContestId : TSimContest) : TContest; // Adding a contest: implement a new contest-specific call history .pas file. Result := nil; case AContestId of - scWpx, scHst: Result := TContest.Create; + scWpx, scHst: Result := TCqWpx.Create; scCwt: Result := TCWOPS.Create; scFieldDay: Result := TArrlFieldDay.Create; scNaQp: Result := TNcjNaQp.Create; diff --git a/MorseRunner.dpr b/MorseRunner.dpr index af49ccc..eeb1734 100644 --- a/MorseRunner.dpr +++ b/MorseRunner.dpr @@ -37,7 +37,8 @@ uses ArrlFd in 'ArrlFd.pas', NaQp in 'NaQp.pas', CWOPS in 'CWOPS.pas', - CqWW in 'CqWW.pas'; + CqWW in 'CqWW.pas', + CqWpx in 'CqWpx.pas'; {$R *.RES} diff --git a/MorseRunner.dproj b/MorseRunner.dproj index 91b5ba1..9aa5598 100644 --- a/MorseRunner.dproj +++ b/MorseRunner.dproj @@ -155,6 +155,7 @@ + Cfg_2 Base diff --git a/QrmStn.pas b/QrmStn.pas index 29e3fa2..bb6343a 100644 --- a/QrmStn.pas +++ b/QrmStn.pas @@ -30,7 +30,7 @@ constructor TQrmStation.CreateStation; inherited Create(nil); Patience := 1 + Random(5); - MyCall := PickCall; + MyCall := Tst.PickCallOnly; HisCall := Ini.Call; Amplitude := 5000 + 25000 * Random; Pitch := Round(RndGaussLim(0, 300)); From 6878ab6896f616f8bf86d5a550a6046efc1fd815 Mon Sep 17 00:00:00 2001 From: Mike Brashler Date: Sat, 12 Nov 2022 23:26:39 -0800 Subject: [PATCH 4/6] add TContest.DeleteStation; used in HST mode --- ArrlFd.pas | 8 ++++++++ CWOPS.pas | 8 ++++++++ Contest.pas | 6 ++++++ CqWW.pas | 8 ++++++++ CqWpx.pas | 7 +++++++ DxStn.pas | 6 ++++++ NaQp.pas | 8 ++++++++ 7 files changed, 51 insertions(+) diff --git a/ArrlFd.pas b/ArrlFd.pas index ca3ff03..8c7396e 100644 --- a/ArrlFd.pas +++ b/ArrlFd.pas @@ -31,6 +31,7 @@ TArrlFieldDay = class(TContest) procedure LoadCallHistory(const AUserCallsign : string); override; 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; @@ -118,6 +119,13 @@ function TArrlFieldDay.PickStation(): integer; end; +procedure TArrlFieldDay.DropStation(id : integer); +begin + assert(id < FdCallList.Count); + FdCallList.Delete(id); +end; + + function TArrlFieldDay.FindCallRec(out fdrec: TFdCallRec; const ACall: string): Boolean; var rec: TFdCallRec; diff --git a/CWOPS.pas b/CWOPS.pas index 10c6133..d171ecc 100644 --- a/CWOPS.pas +++ b/CWOPS.pas @@ -24,6 +24,7 @@ TCWOPS= class(TContest) procedure LoadCallHistory(const AUserCallsign : string); override; function PickStation(): integer; override; + procedure DropStation(id : integer); override; function GetCall(id : integer): string; override; procedure GetExchange(id : integer; out station : TDxStation); override; @@ -99,6 +100,13 @@ function TCWOPS.PickStation(): integer; end; +procedure TCWOPS.DropStation(id : integer); +begin + assert(id < CWOPSList.Count); + CWOPSList.Delete(id); +end; + + function TCWOPS.GetCall(id : integer): string; begin result := TCWOPSRec(CWOPSList.Items[id]).Call; diff --git a/Contest.pas b/Contest.pas index 6c440fc..d92236e 100644 --- a/Contest.pas +++ b/Contest.pas @@ -33,6 +33,7 @@ TContest = class procedure LoadCallHistory(const AUserCallsign : string); virtual; function PickStation : integer; virtual; + procedure DropStation(id : integer); virtual; function GetCall(id : integer) : string; virtual; procedure GetExchange(id : integer; out station : TDxStation); virtual; function GetStationInfo(const ACallsign : string) : string; virtual; @@ -126,6 +127,11 @@ function TContest.PickStation : integer; end; +procedure TContest.DropStation(id : integer); +begin +end; + + function TContest.GetCall(id : integer) : string; begin assert(false, 'GetCall should be overriden'); diff --git a/CqWW.pas b/CqWW.pas index 9774ca7..7ce3610 100644 --- a/CqWW.pas +++ b/CqWW.pas @@ -30,6 +30,7 @@ TCqWw = class(TContest) procedure LoadCallHistory(const AUserCallsign : string); override; 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; @@ -110,6 +111,13 @@ function TCqWw.PickStation(): integer; end; +procedure TCqWw.DropStation(id : integer); +begin + assert(id < CqWwCallList.Count); + CqWwCallList.Delete(id); +end; + + function TCqWw.FindCallRec(out fdrec: TCqWwCallRec; const ACall: string): Boolean; var rec: TCqWwCallRec; diff --git a/CqWpx.pas b/CqWpx.pas index 2a3fb57..2226b0b 100644 --- a/CqWpx.pas +++ b/CqWpx.pas @@ -21,6 +21,7 @@ TCqWpx = class(TContest) procedure LoadCallHistory(const AUserCallsign : string); override; 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; @@ -63,6 +64,12 @@ function TCqWpx.PickStation(): integer; end; +procedure TCqWpx.DropStation(id : integer); +begin + // already deleted by GetCall +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). diff --git a/DxStn.pas b/DxStn.pas index db67827..7c0a91e 100644 --- a/DxStn.pas +++ b/DxStn.pas @@ -74,6 +74,12 @@ constructor TDxStation.CreateStation; Amplitude := 9000 + 18000 * (1 + RndUShaped); Pitch := Round(RndGaussLim(0, 300)); + if Ini.RunMode = rmHst then + begin + Tst.DropStation(Operid); + Operid := -1; + end; + //the MeSent event will follow immediately TimeOut := NEVER; State := stCopying; diff --git a/NaQp.pas b/NaQp.pas index 221e529..4e5b819 100644 --- a/NaQp.pas +++ b/NaQp.pas @@ -27,6 +27,7 @@ TNcjNaQp = class(TContest) procedure LoadCallHistory(const AUserCallsign : string); override; 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; @@ -113,6 +114,13 @@ function TNcjNaQp.PickStation(): integer; end; +procedure TNcjNaQp.DropStation(id : integer); +begin + assert(id < NaQpCallList.Count); + NaQpCallList.Delete(id); +end; + + function TNcjNaQp.FindCallRec(out recOut: TNaQpCallRec; const ACall: string): Boolean; var rec: TNaQpCallRec; From 43e18930cd8c256d3a0252e555ab8e1725c8acb8 Mon Sep 17 00:00:00 2001 From: Mike Brashler Date: Sun, 13 Nov 2022 06:24:16 -0800 Subject: [PATCH 5/6] convert several virtual methods to abstact --- CallLst.pas | 2 +- Contest.pas | 40 +++++----------------------------------- 2 files changed, 6 insertions(+), 36 deletions(-) diff --git a/CallLst.pas b/CallLst.pas index dfc966c..0fedf82 100644 --- a/CallLst.pas +++ b/CallLst.pas @@ -18,7 +18,7 @@ TCallList = class public constructor Create; - destructor Destroy; + destructor Destroy; override; procedure LoadCallList; function PickCall : string; end; diff --git a/Contest.pas b/Contest.pas index d92236e..612dd21 100644 --- a/Contest.pas +++ b/Contest.pas @@ -30,12 +30,12 @@ TContest = class destructor Destroy; override; procedure Init; - procedure LoadCallHistory(const AUserCallsign : string); virtual; + procedure LoadCallHistory(const AUserCallsign : string); virtual; abstract; - function PickStation : integer; virtual; - procedure DropStation(id : integer); virtual; - function GetCall(id : integer) : string; virtual; - procedure GetExchange(id : integer; out station : TDxStation); virtual; + function PickStation : integer; virtual; abstract; + procedure DropStation(id : integer); virtual; abstract; + function GetCall(id : integer) : string; virtual; abstract; + procedure GetExchange(id : integer; out station : TDxStation); virtual; abstract; function GetStationInfo(const ACallsign : string) : string; virtual; function PickCallOnly : string; @@ -115,36 +115,6 @@ procedure TContest.Init; end; -procedure TContest.LoadCallHistory(const AUserCallsign : string); -begin -end; - - -function TContest.PickStation : integer; -begin - assert(false, 'PickStation should be overriden'); - Result := -1; -end; - - -procedure TContest.DropStation(id : integer); -begin -end; - - -function TContest.GetCall(id : integer) : string; -begin - assert(false, 'GetCall should be overriden'); - Result := ''; -end; - - -procedure TContest.GetExchange(id : integer; out station : TDxStation); -begin - assert(false, 'PickStation should be overriden'); -end; - - { GetStationInfo() returns station's DXCC information. From df8a98dc44ac63f07bee3454614669f3793aad29 Mon Sep 17 00:00:00 2001 From: Mike Brashler Date: Tue, 15 Nov 2022 09:13:24 -0800 Subject: [PATCH 6/6] load call history files if user callsign has changed --- ArrlFd.pas | 13 +++++++++++-- CWOPS.pas | 15 +++++++++++++-- CallLst.pas | 8 ++++++++ Contest.pas | 24 +++++++++++++++++++++++- CqWW.pas | 13 +++++++++++-- CqWpx.pas | 13 +++++++++++-- Main.pas | 3 ++- NaQp.pas | 13 +++++++++++-- 8 files changed, 90 insertions(+), 12 deletions(-) diff --git a/ArrlFd.pas b/ArrlFd.pas index 8c7396e..1a6cedb 100644 --- a/ArrlFd.pas +++ b/ArrlFd.pas @@ -28,7 +28,7 @@ TArrlFieldDay = class(TContest) public constructor Create; destructor Destroy; override; - procedure LoadCallHistory(const AUserCallsign : string); override; + function LoadCallHistory(const AUserCallsign : string) : boolean; override; function PickStation(): integer; override; procedure DropStation(id : integer); override; @@ -51,7 +51,7 @@ implementation uses SysUtils, Classes, Log, PerlRegEx, pcre, ARRL; -procedure TArrlFieldDay.LoadCallHistory(const AUserCallsign : string); +function TArrlFieldDay.LoadCallHistory(const AUserCallsign : string) : boolean; const DelimitChar: char = ','; var @@ -59,6 +59,11 @@ procedure TArrlFieldDay.LoadCallHistory(const AUserCallsign : string); i: integer; rec: TFdCallRec; begin + // reload call history iff user's callsign has changed. + Result := not HasUserCallsignChanged(AUserCallsign); + if Result then + Exit; + slst:= TStringList.Create; tl:= TStringList.Create; tl.Delimiter := DelimitChar; @@ -91,6 +96,10 @@ procedure TArrlFieldDay.LoadCallHistory(const AUserCallsign : string); end; end; + // retain user's callsign after successful load + SetUserCallsign(AUserCallsign); + Result := True; + finally slst.Free; tl.Free; diff --git a/CWOPS.pas b/CWOPS.pas index d171ecc..6d7001b 100644 --- a/CWOPS.pas +++ b/CWOPS.pas @@ -21,7 +21,7 @@ TCWOPS= class(TContest) public constructor Create; destructor Destroy; override; - procedure LoadCallHistory(const AUserCallsign : string); override; + function LoadCallHistory(const AUserCallsign : string) : boolean; override; function PickStation(): integer; override; procedure DropStation(id : integer); override; @@ -40,16 +40,23 @@ implementation uses SysUtils, Log; -procedure TCWOPS.LoadCallHistory(const AUserCallsign : string); +function TCWOPS.LoadCallHistory(const AUserCallsign : string) : boolean; var slst, tl: TStringList; i: integer; CWO: TCWOPSRec; begin + // reload call history iff user's callsign has changed. + Result := not HasUserCallsignChanged(AUserCallsign); + if Result then + Exit; + slst:= TStringList.Create; tl:= TStringList.Create; + try CWOPSList.Clear; + slst.LoadFromFile(ParamStr(1) + 'CWOPS.LIST'); slst.Sort; @@ -73,6 +80,10 @@ procedure TCWOPS.LoadCallHistory(const AUserCallsign : string); end; end; + // retain user's callsign after successful load + SetUserCallsign(AUserCallsign); + Result := True; + finally slst.Free; tl.Free; diff --git a/CallLst.pas b/CallLst.pas index 0fedf82..d6e9189 100644 --- a/CallLst.pas +++ b/CallLst.pas @@ -20,6 +20,7 @@ TCallList = class constructor Create; destructor Destroy; override; procedure LoadCallList; + procedure Clear(); function PickCall : string; end; @@ -101,6 +102,12 @@ procedure TCallList.LoadCallList; end; +procedure TCallList.Clear(); +begin + Calls.Clear; +end; + + // returns a single callsign function TCallList.PickCall : string; var @@ -126,6 +133,7 @@ constructor TCallList.Create; destructor TCallList.Destroy; begin + Calls.Clear; Calls.Free; end; diff --git a/Contest.pas b/Contest.pas index 612dd21..329a410 100644 --- a/Contest.pas +++ b/Contest.pas @@ -14,10 +14,16 @@ interface type TContest = class private + UserCallsign : String; // used by LoadCallHistory() to minimize reloads + function DxCount: integer; procedure SwapFilters; + protected constructor Create; + function HasUserCallsignChanged(const AUserCallsign : String) : boolean; + procedure SetUserCallsign(const AUserCallsign : String); + public BlockNumber: integer; Me: TMyStation; @@ -30,7 +36,7 @@ TContest = class destructor Destroy; override; procedure Init; - procedure LoadCallHistory(const AUserCallsign : string); virtual; abstract; + function LoadCallHistory(const AHomeCallsign : string) : boolean; virtual; abstract; function PickStation : integer; virtual; abstract; procedure DropStation(id : integer); virtual; abstract; @@ -90,6 +96,7 @@ constructor TContest.Create; Agc.HoldSamples := 155; Agc.AgcEnabled := true; NoActivityCnt :=0; + UserCallsign := ''; Init; end; @@ -112,6 +119,21 @@ procedure TContest.Init; Me.Init; Stations.Clear; BlockNumber := 0; + UserCallsign := ''; +end; + + +{ return whether to call history file is valid based on user's callsign. } +function TContest.HasUserCallsignChanged(const AUserCallsign : string) : boolean; +begin + // user's home callsign is required to load this contest. + Result := (not AUserCallsign.IsEmpty) and (UserCallsign <> AUserCallsign); +end; + + +procedure TContest.SetUserCallsign(const AUserCallsign : String); +begin + UserCallsign := AUserCallsign; end; diff --git a/CqWW.pas b/CqWW.pas index 7ce3610..414c04e 100644 --- a/CqWW.pas +++ b/CqWW.pas @@ -27,7 +27,7 @@ TCqWw = class(TContest) public constructor Create; destructor Destroy; override; - procedure LoadCallHistory(const AUserCallsign : string); override; + function LoadCallHistory(const AUserCallsign : string) : Boolean; override; function PickStation(): integer; override; procedure DropStation(id : integer); override; @@ -47,7 +47,7 @@ implementation uses SysUtils, Classes, log, ARRL; -procedure TCqWw.LoadCallHistory(const AUserCallsign : string); +function TCqWw.LoadCallHistory(const AUserCallsign : string) : boolean; const DelimitChar: char = ','; var @@ -55,6 +55,11 @@ procedure TCqWw.LoadCallHistory(const AUserCallsign : string); i: integer; rec: TCqWwCallRec; begin + // reload call history iff user's callsign has changed. + Result := not HasUserCallsignChanged(AUserCallsign); + if Result then + Exit; + slst:= TStringList.Create; tl:= TStringList.Create; tl.Delimiter := DelimitChar; @@ -83,6 +88,10 @@ procedure TCqWw.LoadCallHistory(const AUserCallsign : string); end; end; + // retain user's callsign after successful load + SetUserCallsign(AUserCallsign); + Result := True; + finally slst.Free; tl.Free; diff --git a/CqWpx.pas b/CqWpx.pas index 2226b0b..10cf5cb 100644 --- a/CqWpx.pas +++ b/CqWpx.pas @@ -18,7 +18,7 @@ TCqWpx = class(TContest) public constructor Create; destructor Destroy; override; - procedure LoadCallHistory(const AUserCallsign : string); override; + function LoadCallHistory(const AUserCallsign : string) : boolean; override; function PickStation(): integer; override; procedure DropStation(id : integer); override; @@ -38,9 +38,18 @@ implementation uses SysUtils, Classes, log, ARRL; -procedure TCqWpx.LoadCallHistory(const AUserCallsign : string); +function TCqWpx.LoadCallHistory(const AUserCallsign : string) : boolean; begin + // reload call history iff user's callsign has changed. + Result := not HasUserCallsignChanged(AUserCallsign); + if Result then + Exit; + CallLst.LoadCallList; + + // retain user's callsign after successful load + SetUserCallsign(AUserCallsign); + Result := True; end; diff --git a/Main.pas b/Main.pas index a7d576c..a309e99 100644 --- a/Main.pas +++ b/Main.pas @@ -913,7 +913,8 @@ procedure TMainForm.SetContest(AContestNum: TSimContest); assert(Tst.Filt2.SamplesInInput = Ini.BufSize); // load contest-specific call history file - Tst.LoadCallHistory(Ini.Call); + if not Tst.LoadCallHistory(Ini.Call) then + Exit; // update my sent exchange types (must be called after loading call lists?) Tst.Me.SentExchTypes:= Tst.GetSentExchTypes(skMyStation, Ini.Call); diff --git a/NaQp.pas b/NaQp.pas index 4e5b819..79eddc6 100644 --- a/NaQp.pas +++ b/NaQp.pas @@ -24,7 +24,7 @@ TNcjNaQp = class(TContest) public constructor Create; destructor Destroy; override; - procedure LoadCallHistory(const AUserCallsign : string); override; + function LoadCallHistory(const AUserCallsign : string) : boolean; override; function PickStation(): integer; override; procedure DropStation(id : integer); override; @@ -47,7 +47,7 @@ implementation StrUtils, SysUtils, Classes, Contnrs, PerlRegEx, pcre, log, ARRL; -procedure TNcjNaQp.LoadCallHistory(const AUserCallsign : string); +function TNcjNaQp.LoadCallHistory(const AUserCallsign : string) : boolean; const DelimitChar: char = ','; var @@ -55,6 +55,11 @@ procedure TNcjNaQp.LoadCallHistory(const AUserCallsign : string); i: integer; rec: TNaQpCallRec; begin + // reload call history iff user's callsign has changed. + Result := not HasUserCallsignChanged(AUserCallsign); + if Result then + Exit; + slst:= TStringList.Create; tl:= TStringList.Create; tl.Delimiter := DelimitChar; @@ -86,6 +91,10 @@ procedure TNcjNaQp.LoadCallHistory(const AUserCallsign : string); end; end; + // retain user's callsign after successful load + SetUserCallsign(AUserCallsign); + Result := True; + finally slst.Free; tl.Free;