Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 41 additions & 21 deletions src/mission/KM_Campaigns.pas
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,11 @@ implementation
SysUtils, Math, KromUtils,
KM_GameParams,
KM_Resource, KM_ResLocales, KM_ResSprites, KM_ResTypes,
KM_Log, KM_Defaults, KM_CommonUtils, KM_FileIO;

KM_Log, KM_Defaults, KM_CommonUtils, KM_FileIO, KM_Sort
{$IFDEF FPC}
, Generics.Defaults
{$ENDIF}
;

const
CAMP_HEADER_V1 = $FEED; //Just some header to separate right progress files from wrong
Expand Down Expand Up @@ -208,28 +211,45 @@ destructor TKMCampaignsCollection.Destroy;
end;


procedure TKMCampaignsCollection.SortCampaigns;
// Return True if A is considered less (<) than B, False otherwise
function TKMCampaignComparator(constref A, B: TKMCampaign): Boolean;
var
aPrio, bPrio: Integer;
begin
// TSK goes first
if A.ShortName = 'TSK' then aPrio := 0
// TPR goes second
else if A.ShortName = 'TPR' then aPrio := 1
// Others go lexicographically sorted
else aPrio := 2;

//Return True if items should be exchanged
function Compare(A, B: TKMCampaign): Boolean;
begin
//TSK is first
if A.ShortName = 'TSK' then Result := False
else if B.ShortName = 'TSK' then Result := True
//TPR is second
else if A.ShortName = 'TPR' then Result := False
else if B.ShortName = 'TPR' then Result := True
//Others are left in existing order (alphabetical)
else Result := False;
end;
if B.ShortName = 'TSK' then bPrio := 0
else if B.ShortName = 'TPR' then bPrio := 1
else bPrio := 2;

var
I, K: Integer;
Result := (aPrio < bPrio)
or ((2 = aPrio) and (aPrio = bPrio) and (A.ShortName < B.ShortName));
end;


{$IFDEF Unix}
// Return Negative if A < B, Positive if B < A, 0 otherwise
function TKMCampaignComparatorThreeWay(constref A, B: TKMCampaign): LongInt;
begin
for I := 0 to Count - 1 do
for K := I to Count - 1 do
if Compare(Campaigns[I], Campaigns[K]) then
SwapInt(NativeUInt(fList.List[I]), NativeUInt(fList.List[K]));
if (TKMCampaignComparator(A, B)) then Result := -1
else if (TKMCampaignComparator(B, A)) then Result := +1
else Result := 0;
end;
{$ENDIF}


procedure TKMCampaignsCollection.SortCampaigns;
begin
{$IFNDEF Unix}
SelectionSort<TKMCampaign>(fList, 0, Count - 1, @TKMCampaignComparator);
{$ELSE}
fList.Sort(@TKMCampaignComparatorThreeWay);
{$ENDIF}
end;


Expand Down
40 changes: 40 additions & 0 deletions src/utils/algorithms/KM_Sort.pas
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,15 @@
{$I KaM_Remake.inc}
interface

uses
KromUtils,
Generics.Collections, Generics.Defaults;

type
TKMCompFunc = function (const aElem1, aElem2): Integer;
TKMSelectionSortCompType<T> = Function(constref A, B: T) : Boolean;

procedure SelectionSort<T>(var aList: TList<T>; idxFirst, idxLast: Integer; Comp: TKMSelectionSortCompType<T>);

procedure SortCustom(var aArr; aMinIdx, aMaxIdx, aSize: Integer; aCompFunc: TKMCompFunc);

Expand Down Expand Up @@ -63,4 +70,37 @@ procedure SortCustom(var aArr; aMinIdx, aMaxIdx, aSize: Integer; aCompFunc: TKMC
QuickSort(aMinIdx * aSize, aMaxIdx * aSize, Buf[0]);
end;

procedure SelectionSort<T>(var aList: TList<T>; idxFirst, idxLast: Integer; Comp: TKMSelectionSortCompType<T>);
var
I, K, L, J: Integer;
begin
if not (idxFirst < idxLast) then Exit;

I := idxFirst;
L := idxLast;

while I < L do
begin
J := I;
for K := J + 1 to L do
if
{$IFDEF Unix}
Comp(aList.Items[I], aList.Items[J])
{$ELSE}
Comp(aList.List[I], aList.List[J])
{$ENDIF}
then
J := K;
if (I <> J) then
begin
{$IFDEF Unix}
aList.Exchange(I, J);
{$ELSE}
SwapInt(NativeUInt(aList.List[I]), NativeUInt(aList.List[J]));
{$ENDIF}
end;
Inc(I);
end;
end;

end.