|
|
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: 50784 (0xc660)
Types: TextFile
Names: »goPlayUtils.pas«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
└─⟦this⟧ »EUUGD18/General/GoBoard/goPlayUtils.pas«
module goPlayUtils;
exports
imports goCom from goCom;
const
iNil = 32767; { a distinguished value like nil }
maxGroup = 512;
maxSPoint = 16;
type
intBoard = array[-2..maxPoint + 2] of array[-2..maxPoint + 2] of integer;
boolBoard = array[-2..maxPoint + 2] of array[-2..maxPoint + 2] of boolean;
point = record
px, py: integer;
end;
pointList = record
p: array[1..400] of point;
indx: integer;
end;
sPointList = record
p: array[1..maxSPoint] of point;
indx: integer;
end;
intList = record
indx: integer;
v: array[1..400] of integer;
end;
sgRec = record
w, s, sm: integer;
end;
groupRec = record
groupMark: integer;
atLevel: integer;
isLive: boolean;
isDead: boolean;
libC: integer;
numEyes: integer;
size: integer;
lx, ly: integer;
end;
var
kleim, ekstre, bord, ndbord, sGroups, threatBord: intBoard;
groupIDs, connectMap, protPoints: intBoard;
groupSeen, legal: boolBoard;
maxGroupID: integer;
pList, pList1, plist2, plist3, pPlist: pointList;
nlcGroup, aList: intList;
sList: array[1..400] of sgRec;
gList: array[0..maxGroup] of groupRec;
killFlag: boolean;
numCapt: integer;
utilPlayLevel: integer;
treeLibLim: integer;
mySType: sType;
showTrees: boolean;
sGlist: array[1..maxGroup] of integer;
depthLimit: integer;
markBoard: intBoard;
marker: integer;
function saveable(gx, gy: integer; var savex, savey: integer): boolean;
function killable(gx, gy: integer; var killx, killy: integer): boolean;
procedure initBoolBoard(var bb: boolBoard);
procedure spanGroup(x, y: integer; var libs: pointList);
function abs(i: integer): integer;
procedure intersectPlist(var p1, p2, pr: pointList);
procedure initArray(var ary: intBoard);
procedure initState;
procedure copyArray(var dAry, sAry: intBoard);
procedure steik;
procedure spread;
procedure respreicen;
procedure plei(x, y, z: integer);
procedure genState;
procedure saveState;
procedure restoreState;
function tencen(x, y: integer): integer;
procedure genConnects;
procedure initGPUtils;
procedure sortLibs;
private
imports screen from screen;
imports raster from raster;
imports goBoard from goBoard;
imports io_others from io_others;
type
playType = (rem, add, chLib, reMap);
playRec = record
gID: integer;
case kind: playType of
rem, add:
(who, xl, yl, nextGID, sNumber: integer);
chLib:
(oldLC, oldLevel: integer);
reMap:
(oldGID: integer)
end;
var
adjInAtari, adj2Libs: boolean;
intersectNum, spanNum, libMark: integer;
playStack: array[1..1024] of playRec;
playMark: integer;
newGID: integer;
tryLevel: integer;
grpMark: integer;
gMap: array[0..maxGroup] of integer;
dbStop, inGenState: boolean;
exception screwup;
procedure pause;
begin { pause }
{ if dbStop and not inGenState then
begin
while not tabswitch do;
repeat
if tabYellow then
dbStop := false;
until not tabswitch;
end; }
end { pause };
procedure sstone(w, x, y, numb: integer);
var
cx, cy: integer;
begin { sstone }
sReadCursor(cx, cy);
if w = 1 then
placeStone(mySType, x, y, 0, 0, numb)
else if mySType = white then
placeStone(black, x, y, 0, 0, numb)
else
placeStone(white, x, y, 0, 0, numb);
sSetCursor(cx, cy);
end { sstone };
procedure rstone(x, y: integer);
var
cx, cy: integer;
begin { rstone }
sReadCursor(cx, cy);
remStone(x, y);
sSetCursor(cx, cy);
end { rstone };
procedure initBoolBoard(var bb: boolBoard);
var
i, j: integer;
begin { initBoolBoard }
for i := 0 to maxPoint do
for j := 0 to maxPoint do
bb[i, j] := false;
end { initBoolBoard };
function abs(i: integer): integer;
begin { abs }
if i < 0 then
abs := -i
else
abs := i;
end { abs };
procedure sortLibs;
var
i, j, t: integer;
begin { sortLibs }
for i := 1 to maxGroupID do
sGList[i] := i;
for i := 1 to maxGroupID - 1 do
for j := i + 1 to maxGroupID do
if gList[sGlist[i]].libC > gList[sGlist[j]].libC then
begin
t := sGList[i];
sGlist[i] := sGlist[j];
sGlist[j] := t;
end;
end { sortLibs };
procedure spanGroup(x, y: integer; var libs: pointList);
var
lookFor: integer;
procedure span(x, y: integer);
begin { span }
markBoard[x, y] := marker;
if bord[x, y] = 0 then
begin
libs.indx := libs.indx + 1;
libs.p[libs.indx].px := x;
libs.p[libs.indx].py := y;
end
else if bord[x, y] = lookFor then
begin
groupSeen[x, y] := true;
if (x > 0) and (markBoard[x - 1, y] <> marker) then
span(x - 1, y);
if (y > 0) and (markBoard[x, y - 1] <> marker) then
span(x, y - 1);
if (x < maxPoint) and (markBoard[x + 1, y] <> marker) then
span(x + 1, y);
if (y < maxPoint) and (markBoard[x, y + 1] <> marker) then
span(x, y + 1);
end
else if gList[gMap[groupIDs[x, y]]].libC = 1 then
adjInAtari := true
else if (gList[gMap[groupIDs[x, y]]].libC = 2) and
(not gList[gMap[groupIDs[x, y]]].isLive) then
adj2Libs := true;
end { span };
begin { spanGroup }
marker := marker + 1;
if marker = 0 then
begin
initArray(markBoard);
marker := 1;
end;
adjInAtari := false;
adj2Libs := false;
lookFor := bord[x, y];
libs.indx := 0;
span(x, y);
end { spanGroup };
procedure sSpanGroup(x, y: integer; var libs: sPointList);
var
lookFor: integer;
procedure span(x, y: integer);
begin { span }
markBoard[x, y] := marker;
if bord[x, y] = 0 then
begin
libs.indx := libs.indx + 1;
if libs.indx <= maxSPoint then
begin
libs.p[libs.indx].px := x;
libs.p[libs.indx].py := y;
end;
end
else if bord[x, y] = lookFor then
begin
groupSeen[x, y] := true;
if (x > 0) and (markBoard[x - 1, y] <> marker) then
span(x - 1, y);
if (y > 0) and (markBoard[x, y - 1] <> marker) then
span(x, y - 1);
if (x < maxPoint) and (markBoard[x + 1, y] <> marker) then
span(x + 1, y);
if (y < maxPoint) and (markBoard[x, y + 1] <> marker) then
span(x, y + 1);
end
else if gList[gMap[groupIDs[x, y]]].libC = 1 then
adjInAtari := true
else if (gList[gMap[groupIDs[x, y]]].libC = 2) and
(not gList[gMap[groupIDs[x, y]]].isLive) then
adj2Libs := true;
end { span };
begin { sSpanGroup }
marker := marker + 1;
if marker = 0 then
begin
initArray(markBoard);
marker := 1;
end;
adjInAtari := false;
adj2Libs := false;
lookFor := bord[x, y];
libs.indx := 0;
span(x, y);
end { sSpanGroup };
procedure listAdjacents(x, y: integer; var iL: intList);
var
me, him: integer;
procedure span(x, y: integer);
begin { span }
markBoard[x, y] := marker;
if bord[x, y] = me then
begin
if (x > 0) and (markBoard[x - 1, y] <> marker) then
span(x - 1, y);
if (x < maxPoint) and (markBoard[x + 1, y] <> marker) then
span(x + 1, y);
if (y > 0) and (markBoard[x, y - 1] <> marker) then
span(x, y - 1);
if (y < maxPoint) and (markBoard[x, y + 1] <> marker) then
span(x, y + 1);
end
else if bord[x, y] = him then
if gList[gMap[groupIDs[x, y]]].groupMark <> grpMark then
begin
gList[gMap[groupIDs[x, y]]].groupMark := grpMark;
iL.indx := iL.indx + 1;
iL.v[iL.indx] := gMap[groupIDs[x, y]];
end;
end { span };
begin { listAdjacents }
grpMark := grpMark + 1;
marker := marker + 1;
if marker = 0 then
begin
initArray(markBoard);
marker := 1;
end;
iL.indx := 0;
me := bord[x, y];
him := -me;
span(x, y);
end { listAdjacents };
procedure listDiags(x, y: integer; var diags: sPointList);
var
me: integer;
procedure span(x, y: integer);
begin { span }
markBoard[x, y] := marker;
if (x > 0) and (y > 0) and
(bord[x - 1, y - 1] = 0) and
(bord[x, y - 1] <> me) and
(bord[x - 1, y] <> me) and
(markBoard[x - 1, y - 1] <> marker) then
begin
markBoard[x - 1, y - 1] := marker;
diags.indx := diags.indx + 1;
if diags.indx <= maxSPoint then
with diags.p[diags.indx] do
begin
px := x - 1;
py := y - 1;
end;
end;
if (x < maxPoint) and (y > 0) and
(bord[x + 1, y - 1] = 0) and
(bord[x, y - 1] <> me) and
(bord[x + 1, y] <> me) and
(markBoard[x + 1, y - 1] <> marker) then
begin
markBoard[x + 1, y - 1] := marker;
diags.indx := diags.indx + 1;
if diags.indx <= maxSPoint then
with diags.p[diags.indx] do
begin
px := x + 1;
py := y - 1;
end;
end;
if (x > 0) and (y < maxPoint) and
(bord[x - 1, y + 1] = 0) and
(bord[x, y + 1] <> me) and
(bord[x - 1, y] <> me) and
(markBoard[x - 1, y + 1] <> marker) then
begin
markBoard[x - 1, y + 1] := marker;
diags.indx := diags.indx + 1;
if diags.indx <= maxSPoint then
with diags.p[diags.indx] do
begin
px := x - 1;
py := y + 1;
end;
end;
if (x < maxPoint) and (y < maxPoint) and
(bord[x + 1, y + 1] = 0) and
(bord[x, y + 1] <> me) and
(bord[x + 1, y] <> me) and
(markBoard[x + 1, y + 1] <> marker) then
begin
markBoard[x + 1, y + 1] := marker;
diags.indx := diags.indx + 1;
if diags.indx <= maxSPoint then
with diags.p[diags.indx] do
begin
px := x + 1;
py := y + 1;
end;
end;
if (x > 0) and (bord[x - 1, y] = me) and
(markBoard[x - 1, y] <> marker) then
span(x - 1, y);
if (x < maxPoint) and (bord[x + 1, y] = me) and
(markBoard[x + 1, y] <> marker) then
span(x + 1, y);
if (y > 0) and (bord[x, y - 1] = me) and
(markBoard[x, y - 1] <> marker) then
span(x, y - 1);
if (y < maxPoint) and (bord[x, y + 1] = me) and
(markBoard[x, y + 1] <> marker) then
span(x, y + 1);
end { span };
begin { listDiags }
me := bord[x, y];
diags.indx := 0;
marker := marker + 1;
if marker = 0 then
begin
initArray(markBoard);
marker := 1;
end;
span(x, y);
end { listDiags };
procedure intersectPlist(var p1, p2, pr: pointList);
var
i, j, k: integer;
begin { intersectPlist }
marker := marker + 1;
if marker = 0 then
begin
initArray(markBoard);
marker := 1;
end;
pr.indx := 0;
for i := 1 to p1.indx do
with p1.p[i] do
markBoard[px, py] := marker;
j := 0;
for i := 1 to p2.indx do
with p2.p[i] do
if markBoard[px, py] = marker then
begin
j := j + 1;
pr.p[j] := p2.p[i];
end;
pr.indx := j;
end { intersectPlist };
procedure initArray(var ary: intBoard);
var
i, j: integer;
begin { initArray }
for i := 0 to maxPoint do
for j := 0 to maxPoint do
ary[i, j] := 0;
end { initArray };
procedure initState;
var
i, j: integer;
begin { initState }
for i := -2 to maxPoint + 2 do
for j := -2 to maxPoint + 2 do
begin
ekstre[i, j] := 0;
kleim[i, j] := 0;
groupIDs[i, j] := 0;
connectMap[i, j] := 0;
protPoints[i, j] := 0;
end;
end { initState };
procedure copyArray(var dAry, sAry: intBoard);
var
i, j: integer;
begin { copyArray }
for i := 0 to maxPoint do
for j := 0 to maxPoint do
dAry[i, j] := sAry[i, j];
end { copyArray };
{
generates a one-point spread in the force field array (kleim)
the spread from a single point after four calls is:
1
2 2 2
2 4 6 4 2
2 4 8 10 8 4 2
1 2 6 10 62 10 6 2 1
2 4 8 10 8 4 2
2 4 6 4 2
2 2 2
1
}
procedure steik;
var
i, j: integer;
begin { steik }
initArray(ekstre);
for i := 0 to maxPoint do
for j := 0 to maxPoint do
begin
ekstre[i, j] := ekstre[i, j] + kleim[i, j];
if kleim[i, j] > 0 then
begin
if i > 0 then
ekstre[i - 1, j] := ekstre[i - 1, j] + 1;
if j > 0 then
ekstre[i, j - 1] := ekstre[i, j - 1] + 1;
if i < maxPoint then
ekstre[i + 1, j] := ekstre[i + 1, j] + 1;
if j < maxPoint then
ekstre[i, j + 1] := ekstre[i, j + 1] + 1;
end
else if kleim[i, j] < 0 then
begin
if i > 0 then
ekstre[i - 1, j] := ekstre[i - 1, j] - 1;
if j > 0 then
ekstre[i, j - 1] := ekstre[i, j - 1] - 1;
if i < maxPoint then
ekstre[i + 1, j] := ekstre[i + 1, j] - 1;
if j < maxPoint then
ekstre[i, j + 1] := ekstre[i, j + 1] - 1;
end;
end;
copyArray(kleim, ekstre);
end { steik };
{
sets up kleim from the current board position
}
procedure spread;
var
i, j: integer;
begin { spread }
for i := 0 to maxPoint do
for j := 0 to maxPoint do
kleim[i, j] := ndbord[i, j] * 50;
steik;
steik;
steik;
steik;
end { spread };
{
gList is initialized with the size, loc, and libCount of each group
groupIDs contains the serial numbers of the groups.
}
procedure respreicen;
var
i, j, gID, libCount, gSize, who: integer;
procedure span(x, y: integer);
begin { span }
if (bord[x, y] = 0) and
(markBoard[x, y] <> marker) then { a liberty }
begin
markBoard[x, y] := marker;
libCount := libCount + 1;
end
else if (bord[x, y] = who) and
(groupIDs[x, y] = 0) then
begin
groupIDs[x, y] := gID;
gSize := gSize + 1;
if x > 0 then
span(x - 1, y);
if x < maxPoint then
span(x + 1, y);
if y > 0 then
span(x, y - 1);
if y < maxPoint then
span(x, y + 1);
end;
end { span };
begin { respreicen }
gID := 0;
for i := 0 to maxPoint do
for j := 0 to maxPoint do
groupIDs[i, j] := 0;
for i := 0 to maxPoint do
for j := 0 to maxPoint do
if (bord[i, j] <> 0) and { a stone there }
(groupIDs[i, j] = 0) then { not seen yet }
begin
marker := marker + 1;
if marker = 0 then
begin
initArray(markBoard);
marker := 1;
end;
gID := gID + 1;
libCount := 0;
gSize := 0;
who := bord[i, j];
span(i, j); { span the group, collecting info }
with gList[gID] do
begin
groupMark := 0;
atLevel := 0;
isLive := false; { we don't know yet }
isDead := false;
numEyes := -1;
size := gSize;
libC := libCount;
lx := i;
ly := j;
end;
gMap[gID] := gID; { set up identity map }
end;
maxGroupID := gID;
newGID := gID;
grpMark := 0;
end { respreicen };
{
play z at [x, y].
killFlag is set true if anything is killed.
}
procedure plei(x, y, z: integer);
var
i, me, him, myGID: integer;
isNew: boolean;
procedure killGroup(x, y: integer);
begin { killGroup }
playMark := playMark + 1;
with playStack[playMark] do
begin { record this kill }
kind := rem;
who := him;
xl := x;
yl := y;
gID := groupIDs[x, y];
sNumber := board[x, y].mNum;
if showTrees then
rstone(x, y);
end;
numCapt := numCapt + 1;
bord[x, y] := 0;
groupIDs[x, y] := 0;
if x > 0 then
begin
if bord[x - 1, y] = me then
begin
nlcGroup.indx := nlcGroup.indx + 1;
nlcGroup.v[nlcGroup.indx] := gMap[groupIDs[x - 1, y]];
end
else if bord[x - 1, y] = him then
killGroup(x - 1, y);
end;
if x < maxPoint then
begin
if bord[x + 1, y] = me then
begin
nlcGroup.indx := nlcGroup.indx + 1;
nlcGroup.v[nlcGroup.indx] := gMap[groupIDs[x + 1, y]];
end
else if bord[x + 1, y] = him then
killGroup(x + 1, y);
end;
if y > 0 then
begin
if bord[x, y - 1] = me then
begin
nlcGroup.indx := nlcGroup.indx + 1;
nlcGroup.v[nlcGroup.indx] := gMap[groupIDs[x, y - 1]];
end
else if bord[x, y - 1] = him then
killGroup(x, y - 1);
end;
if y < maxPoint then
begin
if bord[x, y + 1] = me then
begin
nlcGroup.indx := nlcGroup.indx + 1;
nlcGroup.v[nlcGroup.indx] := gMap[groupIDs[x, y + 1]];
end
else if bord[x, y + 1] = him then
killGroup(x, y + 1);
end;
end { killGroup };
procedure mergeGroup(sGID: integer);
var
i: integer;
begin { mergeGroup }
for i := 1 to newGID do
if gMap[i] = sGID then
begin
playMark := playMark + 1;
with playStack[playMark] do
begin
kind := reMap;
gID := i;
oldGID := sGID;
end;
gMap[i] := myGID;
end;
end { mergeGroup };
begin { plei }
me := z;
him := -me;
killFlag := false; { set true if something is killed }
numCapt := 0;
tryLevel := tryLevel + 1;
isNew := false;
bord[x, y] := z; { play the stone }
if (x > 0) and (bord[x - 1, y] = me) then { connect to adjacent group }
myGID := gMap[groupIDs[x - 1, y]]
else if (x < maxPoint) and (bord[x + 1, y] = me) then
myGID := gMap[groupIDs[x + 1, y]]
else if (y > 0) and (bord[x, y - 1] = me) then
myGID := gMap[groupIDs[x, y - 1]]
else if (y < maxPoint) and (bord[x, y + 1] = me) then
myGID := gMap[groupIDs[x, y + 1]]
else { nobody to connect to }
begin
newGID := newGID + 1;
isNew := true;
myGID := newGID;
with gList[myGID] do
begin
groupMark := 0;
atLevel := tryLevel;
isLive := false;
numEyes := -1;
size := -1;
lx := x;
ly := y;
end;
gMap[myGID] := myGID;
end;
groupIDs[x, y] := myGID;
playMark := playMark + 1;
with playStack[playMark] do
begin { record this move }
kind := add;
who := me;
xl := x;
yl := y;
gID := myGID;
sNumber := 0;
if isNew then
nextGID := newGID - 1
else
nextGID := newGID;
if showTrees then
sstone(me, x, y, 0);
end;
{ merge adjacent groups }
if (x > 0) and (bord[x - 1, y] = me) and
(gMap[groupIDs[x - 1, y]] <> myGID) then
mergeGroup(gMap[groupIDs[x - 1, y]]);
if (x < maxPoint) and (bord[x + 1, y] = me) and
(gMap[groupIDs[x + 1, y]] <> myGID) then
mergeGroup(gMap[groupIDs[x + 1, y]]);
if (y > 0) and (bord[x, y - 1] = me) and
(gMap[groupIDs[x, y - 1]] <> myGID) then
mergeGroup(gMap[groupIDs[x, y - 1]]);
if (y < maxPoint) and (bord[x, y + 1] = me) and
(gMap[groupIDs[x, y + 1]] <> myGID) then
mergeGroup(gMap[groupIDs[x, y + 1]]);
{ kill opposing groups, listing affected groups }
nlcGroup.indx := 1;
nlcGroup.v[1] := myGID; { init list to include me }
if (x > 0) and (bord[x - 1, y] = him) and
(gList[gMap[groupIDs[x - 1, y]]].libC = 1) then
begin
killFlag := true;
killGroup(x - 1, y);
end;
if (x < maxPoint) and (bord[x + 1, y] = him) and
(gList[gMap[groupIDs[x + 1, y]]].libC = 1) then
begin
killFlag := true;
killGroup(x + 1, y);
end;
if (y > 0) and (bord[x, y - 1] = him) and
(gList[gMap[groupIDs[x, y - 1]]].libC = 1) then
begin
killFlag := true;
killGroup(x, y - 1);
end;
if (y < maxPoint) and (bord[x, y + 1] = him) and
(gList[gMap[groupIDs[x, y + 1]]].libC = 1) then
begin
killFlag := true;
killGroup(x, y + 1);
end;
{ list groups adjacent to me }
if (x > 0) and (bord[x - 1, y] = him) then
begin
nlcGroup.indx := nlcGroup.indx + 1;
nlcGroup.v[nlcGroup.indx] := gMap[groupIDs[x - 1, y]];
end;
if (x < maxPoint) and (bord[x + 1, y] = him) then
begin
nlcGroup.indx := nlcGroup.indx + 1;
nlcGroup.v[nlcGroup.indx] := gMap[groupIDs[x + 1, y]];
end;
if (y > 0) and (bord[x, y - 1] = him) then
begin
nlcGroup.indx := nlcGroup.indx + 1;
nlcGroup.v[nlcGroup.indx] := gMap[groupIDs[x, y - 1]];
end;
if (y < maxPoint) and (bord[x, y + 1] = him) then
begin
nlcGroup.indx := nlcGroup.indx + 1;
nlcGroup.v[nlcGroup.indx] := gMap[groupIDs[x, y + 1]];
end;
{ fix liberty count for affected groups }
grpMark := grpMark + 1;
for i := 1 to nlcGroup.indx do
with gList[nlcGroup.v[i]] do
if groupMark <> grpMark then
begin
if atLevel <> tryLevel then
begin
playMark := playMark + 1;
with playStack[playMark] do
begin
kind := chLib;
gID := nlcGroup.v[i];
oldLevel := atLevel;
oldLC := libC;
end;
end;
groupMark := grpMark;
atLevel := tryLevel;
spanGroup(lx, ly, pPList);
libC := pPList.indx;
end;
end { plei };
procedure saveState;
begin { saveState };
playMark := 0;
tryLevel := 0;
newGID := maxGroupID;
end { saveState };
{
undoes a move sequence back to uMark
}
procedure undoTo(uMark: integer);
var
i: integer;
begin { undoTo }
for i := playMark downto uMark + 1 do
with playStack[i] do
if kind = rem then
begin
bord[xl, yl] := who;
groupIDs[xl, yl] := gID;
if showTrees then
sstone(who, xl, yl, sNumber);
end
else if kind = add then
begin
bord[xl, yl] := 0;
groupIDs[xl, yl] := 0;
tryLevel := tryLevel - 1;
newGID := nextGID;
if showTrees then
rstone(xl, yl);
end
else if kind = reMap then
gMap[gID] := oldGID
else { change libs of group - gID is pre-mapped }
with gList[gID] do
begin
libC := oldLC;
atLevel := oldLevel;
end;
playMark := uMark;
end { undoTo };
{
restores the state of the world after trying a move sequence
}
procedure restoreState;
var
i: integer;
begin { restoreState }
if playMark > 0 then
begin
undoTo(0);
playMark := 0;
tryLevel := 0;
end;
end { restoreState };
exception bpt;
{
returns true if the group (at x, y) is killable.
if so, returns the point to play at in killx, killy.
}
function killable(gx, gy: integer; var killx, killy: integer): boolean;
const
tryLimit = 300;
var
me, him, depth, i, j, tryCount, tl, topMark, tkMark, mark2: integer;
sChar: char;
lList, dList: sPointList;
tp: point;
libList: array[1..maxSPoint] of integer;
esc: boolean;
function mtNbrs(x, y: integer): integer;
var
n: integer;
begin { mtNbrs }
n := 0;
if (x > 0) and (bord[x - 1, y] = 0) then
n := n + 1;
if (x < maxPoint) and (bord[x + 1, y] = 0) then
n := n + 1;
if (y > 0) and (bord[x, y - 1] = 0) then
n := n + 1;
if (y < maxPoint) and (bord[x, y + 1] = 0) then
n := n + 1;
mtNbrs := n;
end { mtNbrs };
function tKillTree(tx, ty: integer): boolean;
var
tkMark: integer;
escape: boolean;
function killTree(tx, ty: integer; var escape: boolean): boolean;
label
1, 2;
var
curMark, mark2, mark3, i, j, k, tl, dStart: integer;
lList1, lList2: sPointList;
libList: array[1..maxSPoint] of integer;
tp: point;
esc: boolean;
begin { killTree }
escape := false;
tryCount := tryCount + 1;
if tryCount > tryLimit then
begin
killable := false;
undoTo(tkMark);
for i := 1 to depth - 1 do
begin
sClearChar(sChar, rXor);
end;
depth := 1;
exit(tKilltree);
end;
write(sChar);
depth := depth + 1;
curMark := playMark;
plei(tx, ty, me); { try my move }
pause;
if gList[gMap[groupIDs[tx, ty]]].libC = 0 then { I'm dead }
killTree := false
else if killFlag then { I killed something of his }
killTree := true
else if gList[gMap[groupIDs[gx, gy]]].libC > treeLibLim then { safe }
killTree := false
else
begin
sSpanGroup(gx, gy, lList1); { find his liberties }
if gList[gMap[groupIDs[tx, ty]]].libC = 1 then { he can kill me }
begin
if lList1.indx < maxSPoint then { add that option to his list }
begin
lList1.indx := lList1.indx + 1;
spanGroup(tx, ty, pList2); { find my liberty }
with lList1.p[lList1.indx] do
begin
px := pList2.p[1].px;
py := pList2.p[1].py;
end;
end
else
begin
killTree := false; { forget it }
goto 1;
end;
end;
for i := 1 to maxSPoint do { init liblist so diags can be marked }
libList[i] := -1;
if (utilPlayLevel > 4) and
(lList1.indx > 1) and
(gList[gMap[groupIDs[gx, gy]]].libC > 1) then { try diags }
begin
listDiags(gx, gy, dList);
j := 0;
i := lList1.indx;
while (j < dList.indx) and
(i < maxSPoint) do
begin
j := j + 1;
i := i + 1;
libList[i] := 0; { mark this as a diag }
with dList.p[j] do
begin
lList1.p[i].px := px;
lList1.p[i].py := py;
end;
end;
lList1.indx := i;
end;
if lList1.indx > 1 then { sort by decreasing lib count }
begin
for i := 1 to lList1.indx do
if libList[i] <> 0 then { diags are tried last }
with lList1.p[i] do
begin
mark2 := playMark;
plei(px, py, him);
libList[i] := gList[gMap[groupIDs[gx, gy]]].libC;
if (libList[i] > treeLibLim) or
((libList[i] > (depthLimit - depth)) and
(libList[i] > 2)) then
begin
escape := true;
killTree := false;
goto 1; { he can live }
end;
undoTo(mark2);
end;
for i := 1 to lList1.indx - 1 do
for j := i + 1 to lList1.indx do
if libList[i] < libList[j] then
begin
tl := libList[i];
libList[i] := libList[j];
libList[j] := tl;
tp := lList1.p[i];
lList1.p[i] := lList1.p[j];
lList1.p[j] := tp;
end;
end;
for i := 1 to lList1.indx + 1 do { try his responses }
begin
mark2 := playMark;
if i <= lList1.indx then { try his move }
with lList1.p[i] do
begin
plei(px, py, him); { play his response }
pause;
if gList[gMap[groupIDs[px, py]]].libC < 2 then
goto 2; { a bogus move }
end
else if gList[gMap[groupIDs[gx, gy]]].libC <= 1 then
begin
killTree := true; { can't tenuki if in atari }
goto 1;
end;
if gList[gMap[groupIDs[gx, gy]]].libC > treeLibLim then
begin
escape := true;
killTree := false;
goto 1;
end;
if gList[gMap[groupIDs[gx, gy]]].libC > 1 then
begin { look at my responses }
sSpanGroup(gx, gy, lList2); { list his liberties }
dStart := lList2.indx + 1;
if adjInAtari then { he wins }
begin
killTree := false;
goto 1;
end;
if (lList2.Indx > 2) and adj2Libs then { he wins }
begin
killTree := false;
goto 1;
end;
for k := 1 to maxSPoint do
libList[k] := -1;
if utilPlayLevel > 4 then { account for diagonal moves }
begin
listDiags(gx, gy, dList);
j := 0;
k := lList2.indx;
while (j < dList.indx) and
(k < maxSPoint) do
begin
j := j + 1;
k := k + 1;
libList[k] := 100;
with dList.p[j] do
begin
lList2.p[k].px := px;
lList2.p[k].py := py;
end;
end;
lList2.indx := k;
end;
if lList2.indx > 1 then { sort by increasing lib count }
begin
for k := 1 to lList2.indx do
if libList[k] <> 100 then { diags go last }
with lList2.p[k] do
begin
mark3 := playMark;
plei(px, py, me);
libList[k] := gList[gMap[groupIDs[gx, gy]]].libC;
undoTo(mark3);
end;
for k := 1 to lList2.indx - 1 do
for j := k + 1 to lList2.indx do
if libList[k] > libList[j] then
begin
tl := libList[k];
libList[k] := libList[j];
libList[j] := tl;
tp := lList2.p[k];
lList2.p[k] := lList2.p[j];
lList2.p[j] := tp;
end
else if (libList[k] = libList[j]) and
(libList[k] = 1) then
if mtNbrs(lList2.p[k].px, lList2.p[k].py) <
mtNbrs(lList2.p[j].px, lList2.p[j].py) then
begin
tl := libList[k];
libList[k] := libList[j];
libList[j] := tl;
tp := lList2.p[k];
lList2.p[k] := lList2.p[j];
lList2.p[j] := tp;
end;
end;
for j := 1 to lList2.indx do
begin
if killTree(lList2.p[j].px, lList2.p[j].py, esc) then
goto 2; { this kills him }
if esc and (j >= dStart) then
begin
killTree := false;
goto 1; { don't bother with more diags if escapes }
end;
end;
killTree := false; { none of my responses kills him }
goto 1;
end;
2:
undoTo(mark2);
end;
killTree := true; { none of his responses saves him }
end;
1:
undoTo(curMark);
sClearChar(sChar, rXor);
depth := depth - 1;
end { killTree };
begin { tKillTree }
tryCount := 0;
tkMark := playMark;
tKillTree := killTree(tx, ty, escape);
end { tKillTree };
begin { killable }
dbStop := true;
him := bord[gx, gy]; { find out who I am }
me := -him;
if me = 1 then
sChar := '>'
else
sChar := '|';
write(sChar);
depth := 1;
topMark := playMark;
sSpanGroup(gx, gy, lList); { find his liberties }
if lList.indx = 1 then
begin
killable := true;
killx := lList.p[1].px;
killy := lList.p[1].py;
end
else if lList.indx > treeLibLim then
killable := false
else if adjInAtari then
killable := false
else if (lList.indx > 2) and adj2Libs then
killable := false
else
begin
for i := 1 to maxSPoint do
libList[i] := -1;
if utilPlayLevel > 4 then { account for diagonal moves }
begin
listDiags(gx, gy, dList);
j := 0;
i := lList.indx;
while (j < dList.indx) and
(i < maxSPoint) do
begin
j := j + 1;
i := i + 1;
libList[i] := 100;
with dList.p[j] do
begin
lList.p[i].px := px;
lList.p[i].py := py;
end;
end;
lList.indx := i;
end;
if lList.indx > 1 then { sort by increasing lib count }
begin
for i := 1 to lList.indx do
if libList[i] <> 100 then { diags go last }
with lList.p[i] do
begin
mark2 := playMark;
plei(px, py, me);
libList[i] := gList[gMap[groupIDs[gx, gy]]].libC;
undoTo(mark2);
end;
for i := 1 to lList.indx - 1 do
for j := i + 1 to lList.indx do
if libList[i] > libList[j] then
begin
tl := libList[i];
libList[i] := libList[j];
libList[j] := tl;
tp := lList.p[i];
lList.p[i] := lList.p[j];
lList.p[j] := tp;
end
else if (libList[i] = libList[j]) and
(libList[i] = 1) then
if mtNbrs(lList.p[i].px, lList.p[i].py) <
mtNbrs(lList.p[j].px, lList.p[j].py) then
begin
tl := libList[i];
libList[i] := libList[j];
libList[j] := tl;
tp := lList.p[i];
lList.p[i] := lList.p[j];
lList.p[j] := tp;
end;
end;
for i := 1 to lList.indx do
begin
if legal[lList.p[i].px, lList.p[i].py] then
begin
killx := lList.p[i].px;
killy := lList.p[i].py;
if tKillTree(killx, killy) then
begin
killable := true;
sClearChar(sChar, rXor);
exit(killable);
end;
end;
end;
killable := false;
end;
sClearChar(sChar, rXor);
end { killable };
{
returns true if the group (at gx, gy) is saveable.
if so, returns the point to play at in savex, savey
}
function saveable(gx, gy: integer; var savex, savey: integer): boolean;
label
1;
var
me, him, gx1, gx2, i, j, smark, mark2, tl: integer;
sChar: char;
dList: sPointList;
tp: point;
libList: array[1..maxSPoint] of integer;
begin { saveable }
dbStop := true;
me := bord[gx, gy];
him := -me;
if me = 1 then
sChar := '|'
else
sChar := '>';
write(sChar);
spanGroup(gx, gy, pList3); { find my liberties }
if adjInAtari then { one of my options is to kill }
begin
listAdjacents(gx, gy, aList);
for i := 1 to aList.indx do
if gList[aList.v[i]].libC = 1 then
with gList[aList.v[i]] do
begin
spanGroup(lx, ly, pList1); { find it's liberty }
pList3.indx := pList3.indx + 1;
pList3.p[pList3.indx].px := pList1.p[1].px;
pList3.p[pList3.indx].py := pList1.p[1].py;
end;
end;
for i := 1 to maxSPoint do
libList[i] := -1;
if (utilPlayLevel > 4) and
(gList[gMap[groupIDs[gx, gy]]].libC > 1) then { account for diags }
begin
listDiags(gx, gy, dList);
j := 0;
i := pList3.indx;
while (j < dList.indx) and
(i < maxSPoint) do
begin
j := j + 1;
i := i + 1;
libList[i] := 100;
with dList.p[j] do
begin
pList3.p[i].px := px;
pList3.p[i].py := py;
end;
end;
pList3.indx := i;
end;
if pList3.indx > 1 then { sort by decreasing lib count }
begin
for i := 1 to pList3.indx do
if libList[i] <> 100 then
with pList3.p[i] do
begin
mark2 := playMark;
plei(px, py, me);
libList[i] := gList[gMap[groupIDs[gx, gy]]].libC;
if libList[i] > treeLibLim then { i'm safe }
begin
savex := px;
savey := py;
saveable := true;
goto 1;
end;
undoTo(mark2);
end;
for i := 1 to pList3.indx - 1 do
for j := i + 1 to pList3.indx do
if libList[i] < libList[j] then
begin
tl := libList[i];
libList[i] := libList[j];
libList[j] := tl;
tp := pList3.p[i];
pList3.p[i] := pList3.p[j];
pList3.p[j] := tp;
end;
end;
for i := 1 to pList3.indx do
begin
savex := pList3.p[i].px;
savey := pList3.p[i].py;
if legal[savex, savey] then
begin
smark := playMark;
plei(savex, savey, me);
pause;
if gList[gMap[groupIDs[savex, savey]]].libC > 1 then
if gList[gMap[groupIDs[gx, gy]]].libC > treeLibLim then
begin
saveable := true;
restoreState;
sClearChar(sChar, rXor);
exit(saveable);
end
else if gList[gMap[groupIDs[gx, gy]]].libC > 1 then
if not killable(gx, gy, gx1, gx2) then
begin
saveable := true;
restoreState;
sClearChar(sChar, rXor);
exit(saveable);
end;
undoTo(smark);
end;
end;
saveable := false;
1:
restoreState;
sClearChar(sChar, rXor);
end { saveable };
{
marks unsavable groups as dead
}
procedure markDead;
var
i, j, gx, gy: integer;
begin { markDead }
for i := 1 to maxGroupID do
with gList[i] do
if killable(lx, ly, gx, gy) then
isDead := not saveable(lx, ly, gx, gy)
else
isDead := false;
for i := 0 to maxPoint do
for j := 0 to maxPoint do
if bord[i, j] = 0 then
ndbord[i, j] := 0
else if gList[groupIDs[i, j]].isDead then
ndbord[i, j] := 0
else
ndbord[i, j] := bord[i, j];
end { markDead };
{
marks groups with two eyes as live
}
procedure markLive;
var
i, j, size, sMark: integer;
saw1, sawm1: boolean;
procedure span(x, y: integer);
begin { span }
if ndbord[x, y] = 1 then
saw1 := true
else if ndbord[x, y] = -1 then
sawm1 := true
else if sGroups[x, y] = 0 then
begin
sGroups[x, y] := sMark;
size := size + 1;
if x > 0 then
span(x - 1, y);
if x < maxPoint then
span(x + 1, y);
if y > 0 then
span(x, y - 1);
if y < maxPoint then
span(x, y + 1);
end;
end { span };
function checkLive(x, y: integer): boolean;
var
numEyes, who: integer;
procedure span(x, y: integer);
begin { span }
markBoard[x, y] := marker;
if ndbord[x, y] = 0 then
with sList[sGroups[x, y]] do
begin
if (sm <> marker) and
(w = who) then
begin
sm := marker;
if s > 6 then
exit(checkLive);
numEyes := numEyes + 1;
if numEyes > 1 then
exit(checkLive);
end;
end
else if bord[x, y] = who then
begin
if (x > 0) and
(markBoard[x - 1, y] <> marker) then
span(x - 1, y);
if (x < maxPoint) and
(markBoard[x + 1, y] <> marker) then
span(x + 1, y);
if (y > 0) and
(markBoard[x, y - 1] <> marker) then
span(x, y - 1);
if (y < maxPoint) and
(markBoard[x, y + 1] <> marker) then
span(x, y + 1);
end;
end { span };
begin { checkLive }
checkLive := true;
numEyes := 0;
who := bord[x, y];
marker := marker + 1;
span(x, y);
checkLive := false;
end { checkLive };
begin { markLive }
sMark := 0;
initArray(sGroups);
for i := 0 to maxPoint do
for j := 0 to maxPoint do
if (sGroups[i, j] = 0) and
(ndbord[i, j] = 0) then
begin
size := 0;
sMark := sMark + 1;
sawm1 := false;
saw1 := false;
span(i, j);
sList[sMark].s := size;
sList[sMark].sm := 0;
if sawm1 then
if saw1 then
sList[sMark].w := 0
else
sList[sMark].w := -1
else if saw1 then
sList[sMark].w := 1
else
sList[sMark].w := 0;
end;
for i := 1 to maxGroupID do
with gList[i] do
if not isDead then
isLive := checkLive(lx, ly);
end { markLive };
{
generates the connection map and the protected point map.
}
procedure genConnects;
var
x, y, numStones: integer;
begin { genConnects }
for x := 0 to maxPoint do
for y := 0 to maxPoint do
begin
connectMap[x, y] := 0;
protPoints[x, y] := 0;
end;
for x := 0 to maxPoint do
for y := 0 to maxPoint do
if bord[x, y] = 1 then { map connections to this stone }
begin
if x > 0 then { direct connection }
connectMap[x - 1, y] := connectMap[x - 1, y] + 1;
if x < maxPoint then
connectMap[x + 1, y] := connectMap[x + 1, y] + 1;
if y > 0 then
connectMap[x, y - 1] := connectMap[x, y - 1] + 1;
if y < maxPoint then
connectMap[x, y + 1] := connectMap[x, y + 1] + 1;
if (x > 0) and (y > 0) and { diagonal connection }
(bord[x - 1, y] = 0) and (bord[x, y - 1] = 0) then
connectMap[x - 1, y - 1] := connectMap[x - 1, y - 1] + 1;
if (x < maxPoint) and (y > 0) and
(bord[x + 1, y] = 0) and (bord[x, y - 1] = 0) then
connectMap[x + 1, y - 1] := connectMap[x + 1, y - 1] + 1;
if (x < maxPoint) and (y < maxPoint) and
(bord[x + 1, y] = 0) and (bord[x, y + 1] = 0) then
connectMap[x + 1, y + 1] := connectMap[x + 1, y + 1] + 1;
if (x > 0) and (y < maxPoint) and
(bord[x - 1, y] = 0) and (bord[x, y + 1] = 0) then
connectMap[x - 1, y + 1] := connectMap[x - 1, y + 1] + 1;
if (x > 1) and (kleim[x - 1, y] > 3) then { one point jump }
connectMap[x - 2, y] := connectMap[x - 2, y] + 1;
if (x < (maxPoint - 1)) and (kleim[x + 1, y] > 3) then
connectMap[x + 2, y] := connectMap[x + 2, y] + 1;
if (y > 1) and (kleim[x, y - 1] > 3) then
connectMap[x, y - 2] := connectMap[x, y - 2] + 1;
if (y < (maxPoint - 1)) and (kleim[x, y + 1] > 3) then
connectMap[x, y + 2] := connectMap[x, y + 2] + 1;
if (x > 1) and (y > 0) and { knight's move }
(kleim[x - 1, y] > 3) and (kleim[x - 1, y - 1] > 3) then
connectMap[x - 2, y - 1] := connectMap[x - 2, y - 1] + 1;
if (x > 0) and (y > 1) and
(kleim[x, y - 1] > 3) and (kleim[x - 1, y - 1] > 3) then
connectMap[x - 1, y - 2] := connectMap[x - 1, y - 2] + 1;
if (x < (maxPoint - 1)) and (y > 0) and
(kleim[x + 1, y] > 3) and (kleim[x + 1, y - 1] > 3) then
connectMap[x + 2, y - 1] := connectMap[x + 2, y - 1] + 1;
if (x < maxPoint) and (y > 1) and
(kleim[x, y - 1] > 3) and (kleim[x + 1, y - 1] > 3) then
connectMap[x + 1, y - 2] := connectMap[x + 1, y - 2] + 1;
if (x > 1) and (y < maxPoint) and
(kleim[x - 1, y] > 3) and (kleim[x - 1, y + 1] > 3) then
connectMap[x - 2, y + 1] := connectMap[x - 2, y + 1] + 1;
if (x > 0) and (y < (maxPoint - 1)) and
(kleim[x, y + 1] > 3) and (kleim[x - 1, y + 1] > 3) then
connectMap[x - 1, y + 2] := connectMap[x - 1, y + 2] + 1;
if (x < (maxPoint - 1)) and (y < maxPoint) and
(kleim[x + 1, y] > 3) and (kleim[x + 1, y + 1] > 3) then
connectMap[x + 2, y + 1] := connectMap[x + 2, y + 1] + 1;
if (x < maxPoint) and (y < (maxPoint - 1)) and
(kleim[x, y + 1] > 3) and (kleim[x + 1, y + 1] > 3) then
connectMap[x + 1, y + 2] := connectMap[x + 1, y + 2] + 1;
end
else if bord[x, y] = 0 then { see if protected point }
begin
numStones := 0;
if x = 0 then
numStones := numStones + 1;
if y = 0 then
numStones := numStones + 1;
if x = maxPoint then
numStones := numStones + 1;
if y = maxPoint then
numStones := numStones + 1;
if (x > 0) and (bord[x - 1, y] = 1) then
numStones := numStones + 1;
if (y > 0) and (bord[x, y - 1] = 1) then
numStones := numStones + 1;
if (x < maxPoint) and (bord[x + 1, y] = 1) then
numStones := numStones + 1;
if (y < maxPoint) and (bord[x, y + 1] = 1) then
numStones := numStones + 1;
if numStones = 4 then
protPoints[x, y] := 1
else if numStones = 3 then
begin
if (x > 0) and
((bord[x - 1, y] = 0) or
((bord[x - 1, y] = -1) and
(gList[groupIDs[x - 1, y]].libC = 1))) then
protPoints[x, y] := 1
else if (x < maxPoint) and
((bord[x + 1, y] = 0) or
((bord[x + 1, y] = -1) and
(gList[groupIDs[x + 1, y]].libC = 1))) then
protPoints[x, y] := 1
else if (y > 0) and
((bord[x, y - 1] = 0) or
((bord[x, y - 1] = -1) and
(gList[groupIDs[x, y - 1]].libC = 1))) then
protPoints[x, y] := 1
else if (y < maxPoint) and
((bord[x, y + 1] = 0) or
((bord[x, y + 1] = -1) and
(gList[groupIDs[x, y + 1]].libC = 1))) then
protPoints[x, y] := 1
end;
end;
for x := 0 to maxPoint do
for y := 0 to maxPoint do
if bord[x, y] <> 0 then
begin
connectMap[x, y] := 0;
protPoints[x, y] := 0;
end;
end { genConnects };
{
generates the whole state of the game.
}
procedure genState;
var
i, j: integer;
begin { genState }
inGenState := true;
respreicen;
markDead;
markLive;
spread;
genConnects;
inGenState := false;
end { genState };
{
generates a value for the [x, y] location that appears to get larger
for points that are saddle points in the influence graph (klein)
}
function tencen(x, y: integer): integer;
var
a, b, c, d, w, z: integer;
begin { tencen }
if kleim[x, y] > -1 then { if he does not influence this area, return 50 }
begin
tencen := 50;
exit(tencen);
end;
w := kleim[x, y]; { w <= -1 }
a := iNil;
if x > 0 then
if kleim[x - 1, y] > -1 then { if neighbor is not influenced by him }
a := kleim[x - 1, y] - w; { score is sum of his influence on central }
b := iNil; { point and my influence on this neighbor }
if y > 0 then
if kleim[x, y - 1] > -1 then
b := kleim[x, y - 1] - w;
c := iNil;
if x < maxPoint then
if kleim[x + 1, y] > -1 then
c := kleim[x + 1, y] - w;
d := iNil;
if y < maxPoint then
if kleim[x, y + 1] > -1 then
d := kleim[x, y + 1] - w;
z := a; { z := max(a, b, c, d) }
if z <> iNil then
begin
if (b <> iNil) and
(b > z) then
z := b;
end
else
z := b;
if z <> iNil then
begin
if (c <> iNil) and
(c > z) then
z := c;
end
else
z := c;
if z <> iNil then
begin
if (d <> iNil) and
(d > z) then
z := d;
end
else
z := d;
if (z <> iNil) and
((x = 0) or
(y = 0) or
(x = maxPoint) or
(y = maxPoint)) then
z := z * 2; { double z if on the edge of the board ?? }
if z <> iNil then
tencen := z
else
tencen := 50;
end { tencen };
procedure initGPUtils;
begin { initGPUtils }
initArray(markBoard);
initState;
marker := 0;
playMark := 0;
with gList[0] do
begin
isLive := false;
isDead := false;
libC := 0;
size := 0;
numEyes := 0;
lx := -1;
ly := -1;
end;
gMap[0] := 0;
dbStop := false;
inGenState := false;
end. { initGPUtils }