unit HanoiList;
interface
uses
Classes, SysUtils;
const
cSg = '
HANOI1';
type
EHanoiList =
class(
Exception);
THanoiListHeader =
packed record
cSg :
array [0..5]
of char;
dwDiscs,
dwClusterFill,
dwClusterSize,
dwClusterCount : Cardinal;
end;
THanoiList =
class(TList)
private
dwClusterSize,
// Größe eines Blockes in Byte
dwDiscs,
// Anzahl der bearbeiteten Scheiben
dwClusterFill : Cardinal;
// Zeigt auf neuen DS in letzten Block
// (log. Einheiten)
procedure AddCluster;
// fügt neuen Datenblock in die Liste ein
// -- properties --
function GetMoveCount : Int64;
protected
procedure Notify(Ptr: Pointer; Action : TListNotification);
override;
public
constructor Create(adwClusterSize, adwDiscs : Cardinal);
// adwClusterSize: siehe dwClusterSize
constructor LoadFromStream(astm : TStream);
constructor LoadFromFile(
const asFileName :
String);
procedure SaveToStream(astm : TStream);
procedure SaveToFile(
const asFileName :
String);
procedure AddMove(aiFrom, aiTo : Integer);
// Fügt neuen DS an das Ende an
// aiFrom, aiTo: Stab-bewegung (0..2 nur sinnvoll)
procedure GetMove(aiIndex : Int64;
var iFrom, iTo : Integer);
// Holt einen DS
// aiIndex: log. Position
property MoveCount : Int64
read GetMoveCount;
end;
implementation
constructor THanoiList.Create(adwClusterSize, adwDiscs : Cardinal);
begin
inherited Create;
dwClusterSize := adwClusterSize;
dwDiscs := adwDiscs;
AddCluster;
end;
constructor THanoiList.LoadFromStream(astm : TStream);
Var fHead : THanoiListHeader;
i : Integer;
pTmp : Pointer;
begin
inherited Create;
astm.
Read(fHead, SizeOf(fHead));
if not CompareMem(@fHead.cSg, PChar(cSg), 6)
then
raise EHanoiList.Create('
LoadFromStream - Datei ist ungültig (Signatur)!');
dwClusterSize := fHead.dwClusterSize;
dwDiscs := fHead.dwDiscs;
dwClusterFill := fHead.dwClusterFill;
for i := 0
to fHead.dwClusterCount - 1
do
begin
GetMem(pTmp, dwClusterSize);
astm.
Read(pTmp^, dwClusterSize);
Add(pTmp);
end;
end;
constructor THanoiList.LoadFromFile(
const asFileName :
String);
Var stm : TFileStream;
begin
stm := TFileStream.Create(asFileName, fmOpenRead);
try
LoadFromStream(stm);
finally
stm.Free;
end;
end;
procedure THanoiList.AddCluster;
Var pTemp : Pointer;
begin
dwClusterFill := 0;
GetMem(pTemp, dwClusterSize);
Add(pTemp);
end;
procedure THanoiList.AddMove(aiFrom, aiTo : Integer);
Var pCur : PByte;
bDS : Byte;
begin
if dwClusterFill >= dwClusterSize
shl 1
then
AddCluster;
if (aiFrom
in [0..2])
and (aiTo
in [0..2])
then
begin
bDS := aiFrom
or (aiTo
shl 2);
pCur := Last;
Inc(pCur, dwClusterFill
shr 1);
if (dwClusterFill
and 1) = 0
then
pCur^ :=
bDS
else
pCur^ := pCur^
or (
bDS shl 4);
Inc(dwClusterFill);
end
else
raise EHanoiList.Create('
AddMove - aiFrom oder aiTo außerhalb des zulässigen Bereichs!!!');
end;
procedure THanoiList.GetMove(aiIndex : Int64;
var iFrom, iTo : Integer);
Var pCur : PByte;
bDS : Byte;
iCluster,
iCur : Integer;
begin
// In welchem Block steht der Datensatz
iCluster := (aiIndex
shr 1)
div dwClusterSize;
if iCluster >= Count
then
raise EHanoiList.Create('
GetMove - Index außerhalb des zulässigen Bereiches!');
pCur := Items[iCluster];
iCur := aiIndex
mod (dwClusterSize
shl 1);
Inc(pCur, iCur
shr 1);
if (iCur
and 1) = 0
then
bDS := pCur^
and $F
else
bDS := pCur^
shr 4;
iTo :=
bDS shr 2;
iFrom :=
bDS and 3;
end;
procedure THanoiList.Notify(Ptr: Pointer; Action : TListNotification);
begin
if Action = lnDeleted
then
FreeMem(Ptr);
end;
function THanoiList.GetMoveCount : Int64;
begin
Result := (dwClusterSize
shl 1) * (Count - 1) + dwClusterFill;
end;
procedure THanoiList.SaveToStream(astm : TStream);
Var fHead : THanoiListHeader;
i : Integer;
begin
StrLCopy(fHead.cSg, PChar(cSg), 6);
fHead.dwClusterCount := Count;
fHead.dwDiscs := dwDiscs;
fHead.dwClusterSize := dwClusterSize;
fHead.dwClusterFill := dwClusterFill;
astm.
Write(fHead, SizeOf(fHead));
for i := 0
to Count - 1
do
astm.
Write(Items[i]^, dwClusterSize);
end;
procedure THanoiList.SaveToFile(
const asFileName :
String);
Var stm : TFileStream;
begin
stm := TFileStream.Create(asFileName, fmCreate);
try
SaveToStream(stm);
finally
stm.Free;
end;
end;
end.