|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T g
Length: 19784 (0x4d48)
Types: TextFile
Names: »goTree.pas«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
└─⟦this⟧ »EUUGD18/General/GoBoard/goTree.pas«
{---------------------------------------------------------------}
{ GoTree.Pas }
{ }
{ Go Game Tree Manager }
{ Copyright (c) 1982 by Three Rivers Computer Corp. }
{ }
{ Written: June 3, 1982 by Stoney Ballard }
{ Edit History: }
{ June 3, 1982 Started }
{ June 4, 1982 Add dead group removal }
{ June 10, 1982 Use new go file manager }
{ Nov 9, 1982 Extracted from GO.PAS }
{ Nov 15, 1982 Added tag and comment deletion }
{ Jan 5, 1983 Increased segment max sizes }
{ Jan 7, 1983 Changed File Format to have global comment }
{---------------------------------------------------------------}
module goTree;
exports
imports goCom from goCom;
imports getTimeStamp from getTimeStamp;
type
pMRec = ^moveRec;
tagStr = string[maxTagLen];
tagPtr = ^tagRec;
tagRec = record
mPtr: pMRec;
nextTag: tagPtr;
sTag: tagStr;
end;
mType = (header, move, remove, hcPlay, pass);
moveRec = packed record
mark: boolean;
flink: pMRec;
case id: mType of
header:
(lastMove: pMRec;
freePool: pMRec;
lastTag: tagPtr;
nextMRec: integer;
nextMBlock: integer;
nextTRec: integer;
nextTBlock: integer;
nextCIdx: integer;
nextCBlock: integer;
freeTags: tagPtr);
hcPlay, move, remove, pass:
(blink: pMRec;
slink: pMRec;
tag: tagPtr;
who: sType;
moveN: integer;
cmtBase: integer;
cmtLen: integer;
case {id:} mType of
hcPlay:
(hcNum: integer);
move, remove:
(mx: integer;
my: integer;
ox: integer;
oy: integer;
kx: integer;
ky: integer) )
end;
baseBlock = packed record
case boolean of
false:
(padding: array[1..512] of char);
true:
(randBool: boolean;
oldTest: pointer;
fileVersion: integer;
created: timeStamp;
rootComment: string[127])
end;
pBaseBlock = ^baseBlock;
var
treeRoot: pMRec;
stepTag: tagPtr;
hdrBlock: pBaseBlock;
exception goFNF;
exception badGoWrite;
exception badFileVersion;
procedure initGoTree;
procedure makeGoTree;
procedure readTree(nam: string);
procedure writeTree(nam: string; lm: pMRec);
function newMove(cm: pMRec): pMRec;
function delBranch(pm: pMRec): pMRec;
function hasAlts(pm: pMRec): boolean;
function isBranch(pm: pMRec): boolean;
function hasBranch(pm: pMRec): boolean;
function mergeMove(cm: pMRec): pMRec;
procedure tagMove(cm: pMRec; ts: tagStr);
function tagExists(ts: tagStr): boolean;
procedure commentMove(cm: pMRec; cs: string);
function getComment(cm: pMRec; var cs: string): boolean;
function getTag(cm: pMRec; var ts: string): boolean;
procedure delTag(tp: tagPtr);
procedure getFNameString(var fs: string);
private
imports fileSystem from fileSystem;
imports memory from memory;
imports perq_string from perq_string;
imports clock from clock;
const
curFileVersion = 1;
minTreeSize = 20;
minTagSize = 4;
minCmtSize = 4;
maxTreeSize = 255;
maxTagSize = 64;
maxCmtSize = 128;
treeSegInc = 8;
tagSegInc = 4;
cmtSegInc = 4;
type
caType = packed array[0..1] of char;
pCmtArray = ^caType;
var
mFID: FileID;
treeSeg, tagSeg, cmtSeg: integer;
trSegSize, tagSegSize, cmtSegSize: integer;
cmtArray: pCmtArray;
cmtCmpArray: array[1..1024] of pMRec;
procedure getFNameString(var fs: string);
var
ts: string;
begin { getFNameString }
fs := gameFName;
if fs <> '' then
begin
stampToString(hdrBlock^.created, ts);
fs := concat(fs, ' ');
fs := concat(fs, ts);
end;
end { getFNameString };
function isBranch(pm: pMRec): boolean;
begin { isBranch }
repeat
if pm = treeRoot then
begin
isBranch := false;
exit(isBranch);
end;
pm := pm^.blink;
until pm^.flink^.slink <> nil;
isBranch := true;
end { isBranch };
function hasBranch(pm: pMRec): boolean;
begin { hasBranch }
while pm^.flink <> nil do
if pm^.flink^.slink <> nil then
begin
hasBranch := true;
exit(hasBranch);
end
else
pm := pm^.flink;
hasBranch := false;
end { hasBranch };
procedure initSegs(trSize, tagSize, cmtSize: integer);
begin { initSegs }
if treeSeg <> -1 then
begin
changeSize(treeSeg, trSize);
changeSize(tagSeg, tagSize);
changeSize(cmtSeg, cmtSize);
end
else
begin
createSegment(treeSeg, trSize, treeSegInc, maxTreeSize);
createSegment(tagSeg, tagSize, tagSegInc, maxTagSize);
createSegment(cmtSeg, cmtSize, cmtSegInc, maxCmtSize);
end;
trSegSize := trSize;
tagSegSize := tagSize;
cmtSegSize := cmtSize;
end { initSegs };
procedure initHdrBlock;
begin { initHdrBlock }
with hdrBlock^ do
begin
oldTest := nil;
fileVersion := curFileVersion;
getTStamp(created);
rootComment := '';
end;
end { initHdrBlock };
procedure makeGoTree;
begin { makeGoTree }
initSegs(minTreeSize, minTagSize, minCmtSize);
initHdrBlock;
treeRoot := makePtr(treeSeg, 0, pMRec);
with treeRoot^ do
begin
id := header;
freePool := nil;
flink := nil;
lastTag := nil;
nextMRec := wordSize(moveRec);
nextMBlock := minTreeSize * 256;
nextTRec := 0;
nextTBlock := minTagSize * 256;
nextCIdx := 0;
nextCBlock := minCmtSize * 512;
freeTags := nil;
end;
cmtArray := makePtr(cmtSeg, 0, pCmtArray);
stepTag := nil;
end { makeGoTree };
procedure readTree(nam: string);
type
ptrHack = record
case integer of
0: (p: pMRec);
1: (pt: tagPtr);
2: (po: integer;
ps: integer);
end;
var
size, gbg, i, b: integer;
pd: pDirBlk;
ph: ptrHack;
pm: pMRec;
tm: tagPtr;
mBlks, tBlks, cBlks: integer;
begin { readTree }
initSegs(minTreeSize, minTagSize, minCmtSize);
mFID := FSLookup(nam, size, gbg);
if mFID = 0 then
raise goFNF;
FSBlkRead(mFID, 0, recast(hdrBlock, pDirBlk));
if hdrBlock^.oldTest <> nil then
begin
initHdrBlock;
b := 0;
end
else if hdrBlock^.fileVersion <> curFileVersion then
begin
makeGoTree;
raise badFileVersion;
end
else
b := 1;
pd := makePtr(treeSeg, 0, pDirBlk);
FSBlkRead(mFID, b, pd);
b := b + 1;
treeRoot := makePtr(treeSeg, 0, pMRec);
with treeRoot^ do
begin
mBlks := nextMBlock div 256;
tBlks := nextTBlock div 256;
cBlks := nextCBlock div 512;
end;
initSegs(mBlks, tBlks, cBlks);
for i := 1 to mBlks - 1 do
begin
pd := makePtr(treeSeg, i * 256, pDirBlk);
FSBlkRead(mFID, b, pd);
b := b + 1;
end;
for i := 0 to tBlks - 1 do
begin
pd := makePtr(tagSeg, i * 256, pDirBlk);
FSBlkRead(mFID, b, pd);
b := b + 1;
end;
for i := 0 to cBlks - 1 do
begin
pd := makePtr(cmtSeg, i * 256, pDirBlk);
FSBlkRead(mFID, b, pd);
b := b + 1;
end;
with treeRoot^ do
begin
if freePool <> nil then
begin
ph.p := freePool;
ph.ps := treeSeg;
freePool := ph.p;
end;
if flink <> nil then
begin
ph.p := flink;
ph.ps := treeSeg;
flink := ph.p;
end;
if lastMove <> nil then
begin
ph.p := lastMove;
ph.ps := treeSeg;
lastMove := ph.p;
end;
if lastTag <> nil then
begin
ph.pt := lastTag;
ph.ps := tagSeg;
lastTag := ph.pt;
end;
if freeTags <> nil then
begin
ph.pt := freeTags;
ph.ps := tagSeg;
freeTags := ph.pt;
end;
end;
i := wordSize(moveRec);
while i < treeRoot^.nextMRec do
begin
pm := makePtr(treeSeg, i, pMRec);
with pm^ do
begin
if flink <> nil then
begin
ph.p := flink;
ph.ps := treeSeg;
flink := ph.p;
end;
if blink <> nil then
begin
ph.p := blink;
ph.ps := treeSeg;
blink := ph.p;
end;
if slink <> nil then
begin
ph.p := slink;
ph.ps := treeSeg;
slink := ph.p;
end;
if tag <> nil then
begin
ph.pt := tag;
ph.ps := tagSeg;
tag := ph.pt;
end;
end;
i := i + wordSize(moveRec);
end;
i := 0;
while i < treeRoot^.nextTRec do
begin
tm := makePtr(tagSeg, i, tagPtr);
with tm^ do
begin
if mPtr <> nil then
begin
ph.p := mPtr;
ph.ps := treeSeg;
mPtr := ph.p;
end;
if nextTag <> nil then
begin
ph.pt := nextTag;
ph.ps := tagSeg;
nextTag := ph.pt;
end;
end;
i := i + wordSize(tagRec);
end;
stepTag := nil;
end { readTree };
procedure writeTree(nam: string; lm: pMRec);
var
pd: pDirBlk;
treeBlks, tagBlks, cmtBlks: integer;
b, i: integer;
procedure compressCmts;
var
numCmts: integer;
cp: pMRec;
procedure spanComments(m: pMRec);
begin { spanComments }
while m <> nil do
begin
if m^.cmtLen > 0 then
begin
numCmts := numCmts + 1;
cmtCmpArray[numCmts] := m;
end;
spanComments(m^.slink);
m := m^.flink;
end;
end { spanComments };
procedure sortComments;
var
i, j: integer;
t: pMRec;
begin { sortComments }
for i := 1 to numCmts - 1 do
for j := i + 1 to numCmts do
if cmtCmpArray[i]^.cmtBase > cmtCmpArray[j]^.cmtBase then
begin
t := cmtCmpArray[i];
cmtCmpArray[i] := cmtCmpArray[j];
cmtCmpArray[j] := t;
end;
end { sortComments };
procedure squeezeComments;
var
i, j, cgi, lastCB: integer;
mp: pMRec;
begin { squeezeComments }
lastCB := 0;
for i := 1 to numCmts do
begin
if cmtCmpArray[i]^.cmtBase > lastCB then
begin
cgi := cmtCmpArray[i]^.cmtBase;
for j := 0 to cmtCmpArray[i]^.cmtLen - 1 do
begin
{$R-}
cmtArray^[lastCB + j] := cmtArray^[cgi + j];
{$R=}
end;
cmtCmpArray[i]^.cmtBase := lastCB;
end;
lastCB := cmtCmpArray[i]^.cmtBase + cmtCmpArray[i]^.cmtLen;
end;
treeRoot^.nextCIdx := lastCB;
end { squeezeComments };
begin { compressCmts }
numCmts := 0;
cp := treeRoot^.flink;
if cp <> nil then
begin
spanComments(cp);
sortComments;
squeezeComments;
end;
end { compressCmts };
begin { writeTree }
mFID := FSEnter(nam);
if mFID = 0 then
raise badGoWrite
else
begin
compressCmts;
with treeRoot^ do
begin
lastMove := lm;
treeBlks := nextMBlock div 256;
tagBlks := nextTBlock div 256;
cmtBlks := nextCBlock div 512;
end;
FSBlkWrite(mFID, 0, recast(hdrBlock, pDirBlk));
b := 1;
for i := 0 to treeBlks - 1 do
begin
pd := makePtr(treeSeg, i * 256, pDirBlk);
FSBlkWrite(mFID, b, pd);
b := b + 1;
end;
for i := 0 to tagBlks - 1 do
begin
pd := makePtr(tagSeg, i * 256, pDirBlk);
FSBlkWrite(mFID, b, pd);
b := b + 1;
end;
for i := 0 to cmtBlks - 1 do
begin
pd := makePtr(cmtSeg, i * 256, pDirBlk);
FSBlkWrite(mFID, b, pd);
b := b + 1;
end;
FSClose(mFID, treeBlks + tagBlks + cmtBlks, 4096);
end;
end { writeTree };
function newMove(cm: pMRec): pMRec;
var
pm: pMRec;
begin { newMove }
with treeRoot^ do
if freePool <> nil then
begin
pm := freePool;
freePool := pm^.flink;
end
else
begin
if nextMRec + wordSize(moveRec) > nextMBlock then
begin
trSegSize := trSegSize + treeSegInc;
changeSize(treeSeg, trSegSize);
nextMBlock := nextMBlock + (treeSegInc * 256);
end;
pm := makePtr(treeSeg, nextMRec, pMRec);
nextMRec := nextMRec + wordSize(moveRec);
end;
with pm^ do
begin
flink := nil;
blink := cm;
slink := nil;
tag := nil;
cmtLen := 0;
end;
if cm^.flink <> nil then
pm^.slink := cm^.flink;
cm^.flink := pm;
newMove := pm;
end { newMove };
procedure tagMove(cm: pMRec; ts: tagStr);
var
tp: tagPtr;
begin { tagMove }
if cm^.tag <> nil then
cm^.tag^.sTag := ts
else
with treeRoot^ do
begin
if freeTags <> nil then
begin
tp := freeTags;
freeTags := tp^.nextTag;
end
else
begin
if nextTRec + wordSize(tagRec) > nextTBlock then
begin
tagSegSize := tagSegSize + tagSegInc;
changeSize(tagSeg, tagSegSize);
nextTBlock := nextTBlock + (tagSegInc * 256);
end;
tp := makePtr(tagSeg, nextTRec, tagPtr);
nextTRec := nextTRec + wordSize(tagRec);
end;
cm^.tag := tp;
with tp^ do
begin
mPtr := cm;
nextTag := lastTag;
sTag := ts;
end;
lastTag := tp;
end;
treeDirty := true;
end { tagMove };
function tagExists(ts: tagStr): boolean;
var
tp: tagPtr;
function upCmp(s1, s2: pString): boolean;
begin { upCmp }
convUpper(s1);
convUpper(s2);
upCmp := s1 = s2;
end { upCmp };
begin { tagExists }
tp := treeRoot^.lastTag;
while tp <> nil do
if upCmp(tp^.sTag, ts) then
begin
tagExists := true;
exit(tagExists);
end
else
tp := tp^.nextTag;
tagExists := false;
end { tagExists };
procedure commentMove(cm: pMRec; cs: string);
var
sl, i: integer;
begin { commentMove }
if cm = treeRoot then
hdrBlock^.rootComment := cs
else
begin
sl := length(cs);
with cm^ do
begin
cmtLen := sl;
if sl > 0 then
begin
cmtBase := treeRoot^.nextCIdx;
treeRoot^.nextCIdx := cmtBase + sl;
if cmtBase + cmtLen > treeRoot^.nextCBlock then
with treeRoot^ do
begin
cmtSegSize := cmtSegSize + cmtSegInc;
changeSize(cmtSeg, cmtSegSize);
nextCBlock := nextCBlock + (cmtSegInc * 512);
end;
for i := 0 to sl - 1 do
begin
{$R-}
cmtArray^[cmtBase + i] := cs[i + 1];
{$R=}
end;
end;
end;
end;
treeDirty := true;
end { commentMove };
function getComment(cm: pMRec; var cs: string): boolean;
var
i: integer;
begin { getComment }
if cm = treeRoot then
begin
cs := hdrBlock^.rootComment;
getComment := cs <> '';
end
else if cm^.cmtLen = 0 then
getComment := false
else
with cm^ do
begin
getComment := true;
adjust(cs, cmtLen);
for i := 1 to cmtLen do
begin
{$R-}
cs[i] := cmtArray^[cmtBase + i - 1];
{$R=}
end;
end;
end { getComment };
function getTag(cm: pMRec; var ts: string): boolean;
begin { getTag }
if cm = treeRoot then
getTag := false
else if cm^.tag = nil then
getTag := false
else
begin
ts := cm^.tag^.sTag;
getTag := true;
end;
end { getTag };
procedure delTag(tp: tagPtr);
var
ttp: tagPtr;
begin { delTag }
tp^.mPtr^.tag := nil;
tp^.mPtr := nil;
if stepTag = tp then
stepTag := nil;
ttp := treeRoot^.lastTag;
if ttp = tp then
treeRoot^.lastTag := tp^.nextTag
else
begin
while ttp^.nextTag <> tp do
ttp := ttp^.nextTag;
ttp^.nextTag := tp^.nextTag;
end;
tp^.nextTag := treeRoot^.freeTags;
treeRoot^.freeTags := tp;
end { delTag };
function delBranch(pm: pMRec): pMRec;
var
sm: pMRec;
procedure recDel(m: pMRec);
var
tp: tagPtr;
begin { recDel }
if m <> nil then
begin
recDel(m^.slink);
recDel(m^.flink);
m^.blink := nil;
m^.slink := nil;
m^.flink := treeRoot^.freePool;
treeRoot^.freePool := m;
if m^.tag <> nil then
delTag(m^.tag);
end;
end { recDel };
begin { delBranch }
if pm = treeRoot then
exit(delBranch);
while pm^.id = remove do
pm := pm^.blink;
if pm^.blink^.flink = pm then
pm^.blink^.flink := pm^.slink
else
begin
sm := pm^.blink^.flink;
while sm^.slink <> pm do
sm := sm^.slink;
sm^.slink := pm^.slink;
end;
pm^.slink := nil;
delBranch := pm^.blink;
pm^.blink := nil;
recDel(pm);
end { delBranch };
procedure delNode(pm: pMRec);
var
sm: pMRec;
begin { delNode }
if pm = treeRoot then
exit(delNode);
if pm^.blink^.flink = pm then
pm^.blink^.flink := pm^.slink
else
begin
sm := pm^.blink^.flink;
while sm^.slink <> pm do
sm := sm^.slink;
sm^.slink := pm^.slink;
end;
pm^.blink := nil;
pm^.slink := nil;
pm^.flink := treeRoot^.freePool;
treeRoot^.freePool := pm;
end { delNode };
function mergeMove(cm: pMRec): pMRec;
var
tm: pMRec;
begin { mergeMove }
tm := cm^.blink^.flink;
mergeMove := cm;
while tm <> nil do
begin
if tm <> cm then
with tm^ do
if id = cm^.id then
if id = hcPlay then
begin
mergeMove := tm;
delNode(cm);
exit(mergeMove);
end
else if id = pass then
begin
if who = cm^.who then
begin
mergeMove := tm;
delNode(cm);
exit(mergeMove);
end;
end
else if (mx = cm^.mx) and
(my = cm^.my) and
(who = cm^.who) then
begin
mergeMove := tm;
delNode(cm);
exit(mergeMove);
end;
tm := tm^.slink;
end;
treeDirty := true;
end { mergeMove };
function hasAlts(pm: pMRec): boolean;
begin { hasAlts }
while pm^.id = remove do
pm := pm^.blink;
hasAlts := pm^.blink^.flink^.slink <> nil;
end { hasAlts };
procedure initGoTree;
begin { initGoTree }
treeSeg := -1;
new(0, 256, hdrBlock);
end. { initGoTree }