|
|
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: 58638 (0xe50e)
Types: TextFile
Names: »goPlayer.pas«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
└─⟦this⟧ »EUUGD18/General/GoBoard/goPlayer.pas«
{---------------------------------------------------------------}
{ GoPlayer.Pas }
{ }
{ Go Move Generator }
{ Copyright (c) 1983 by Three Rivers Computer Corp. }
{ }
{ Written: January 17, 1983 by Stoney Ballard }
{ Edit History: }
{---------------------------------------------------------------}
module goPlayer;
exports
imports goCom from goCom;
{ returns true if a move was generated, false for a pass }
function playMove(who: sType; var xLoc, yLoc: integer): boolean;
procedure showPlayState(who: sType);
procedure initGoPlayer;
var
playReason: string;
playLevel: integer;
maxPlayLevel: integer;
private
imports goPlayUtils from goPlayUtils;
imports popUp from popUp;
imports goBoard from goBoard;
imports perq_string from perq_string;
imports io_others from io_others;
var
saveNLibs: boolean;
stateMenu: pNameDesc;
exception broken;
procedure blek(var moveX, moveY: integer);
label
1; { done }
var
x, y: integer;
dapList1, dapList2, dapList3: pointList;
{
Checks out a move.
If my stone is not killable then true.
}
function safeMove(x, y: integer): boolean;
var
gbx, gby: integer;
begin { safeMove }
plei(x, y, 1); { try playing at point }
if killFlag then { I shouldn't kill if lookForKill didn't }
safeMove := false
else if gList[groupIDs[x, y]].libC < 2 then
begin { if it is in atari or dead }
safeMove := false; { reject it }
end
else if gList[groupIDs[x, y]].libC <= treeLibLim then { see if killable }
if playLevel > 0 then
safeMove := not killable(x, y, gbx, gby)
else
safeMove := true
else
safeMove := true;
restoreState;
end { safeMove };
function heCanCut(x, y: integer): boolean;
var
gx, gy: integer;
begin { heCanCut }
if playLevel > 3 then
begin
plei(x, y, -1); { try his cut }
heCanCut := not killable(x, y, gx, gy);
restoreState;
end
else
heCanCut := true;
end { heCanCut };
{
Plays on a corner point if possible
returns true if so
}
function takeCorner(var x, y: integer): boolean;
var
field, i: integer;
{
checks a point for no influence and no neighbors
sets up return vars and exits takeCorner if ok
}
procedure checkPos(tx, ty, field: integer);
var
ok: boolean;
begin { checkPos }
ok := (((field = 0) and (kleim[tx, ty] = 0)) or { if in field limits }
((field > 0) and
(kleim[tx, ty] >= 0) and (kleim[tx, ty] <= field)) or
((field < 0) and
(kleim[tx, ty] <= 0) and (kleim[tx, ty] >= field))) and
(bord[tx - 1, ty] = 0) and { and no neighbors }
(bord[tx + 1, ty] = 0) and
(bord[tx, ty - 1] = 0) and
(bord[tx, ty + 1] = 0);
if ok then
begin
x := tx;
y := ty;
takeCorner := true;
exit(takeCorner);
end;
end { checkPos };
begin { takeCorner }
playReason := 'takeCorner';
i := maxPoint - 3;
field := -1;
repeat
if field = -1 then
field := 0
else if field = 0 then
field := 4
else
field := -4;
checkPos(2, 3, field);
checkPos(3, 2, field);
checkPos(2, i, field);
checkPos(3, i + 1, field);
checkPos(i, i + 1, field);
checkPos(i + 1, i, field);
checkPos(i, 2, field);
checkPos(i + 1, 3, field);
checkPos(2, 4, field);
checkPos(4, 2, field);
checkPos(2, i - 1, field);
checkPos(4, i + 1, field);
checkPos(i - 1, i + 1, field);
checkPos(i + 1, i - 1, field);
checkPos(i + 1, 4, field);
checkPos(i - 1, 2, field);
until field = -4;
takeCorner := false;
end { takeCorner };
{
first phase of 3-line extentions
}
function extend(var x, y: integer): boolean;
var
i: integer;
begin { extend }
playReason := 'extend';
for i := 2 to maxPoint - 2 do { look along a three line }
if (kleim[2, i] = 0) and
(bord[1, i] = 0) and
(bord[3, i] = 0) and
(bord[2, i - 1] = 0) and
(bord[2, i + 1] = 0) then
begin
x := 2; { return the first point that there's nothing around }
y := i;
extend := true;
exit(extend);
end;
for i := 2 to maxPoint - 2 do { another 3-line extention }
if (kleim[i, maxPoint - 2] = 0) and
(bord[i - 1, maxPoint - 2] = 0) and
(bord[i + 1, maxPoint - 2] = 0) and
(bord[i, maxPoint - 1] = 0) and
(bord[i, maxPoint - 3] = 0) then
begin
x := i;
y := maxPoint - 2;
extend := true;
exit(extend);
end;
for i := maxPoint - 2 downto 2 do { another 3-line extention }
if (kleim[maxPoint - 2, i] = 0) and
(bord[maxPoint - 1, i] = 0) and
(bord[maxPoint - 3, i] = 0) and
(bord[maxPoint - 2, i - 1] = 0) and
(bord[maxPoint - 2, i + 1] = 0) then
begin
x := maxPoint - 2;
y := i;
extend := true;
exit(extend);
end;
for i := maxPoint - 2 downto 2 do { another 3-line extention }
if (kleim[i, 2] = 0) and
(bord[i - 1, 2] = 0) and
(bord[i + 1, 2] = 0) and
(bord[i, 1] = 0) and
(bord[i, 3] = 0) then
begin
x := i;
y := 2;
extend := true;
exit(extend);
end;
extend := false;
end { extend };
{
second phase of extentions - plays in my lowest influence spots on
the 3-lines, so long as they are not touching anything
}
function extend2(var x, y: integer): boolean;
var
i, rekrd, veliu: integer;
begin { extend2 }
playReason := 'extend2';
rekrd := iNil;
x := iNil;
y := iNil;
for i := 3 to maxPoint - 3 do { scan a 3-line }
if legal[2, i] then { if there is nobody there }
begin
veliu := kleim[2, i]; { get influence }
if (veliu < 7) and { a reasonable hole in my wall }
(veliu > -5) and { or a reasonable gap in his }
(bord[2, i + 1] = 0) and { not in contact with any stones }
(bord[2, i - 1] = 0) then
if (rekrd <> iNil) and
(veliu < rekrd) then
begin
rekrd := veliu; { rekrd gets the smallest value }
x := 2; { that was seen along all the 3-lines }
y := i; { x and y save that location }
end
else if rekrd = iNil then
begin
rekrd := veliu;
x := 2;
y := i;
end;
end;
for i := 3 to maxPoint - 3 do
if legal[i, 2] then
begin
veliu := kleim[i, 2];
if (veliu < 7) and
(veliu > -5) and
(bord[i + 1, 2] = 0) and
(bord[i - 1, 2] = 0) then
if (rekrd <> iNil) and
(veliu < rekrd) then
begin
rekrd := veliu;
x := i;
y := 2;
end
else if rekrd = iNil then
begin
rekrd := veliu;
x := i;
y := 2;
end;
end;
for i := maxPoint - 3 downto 3 do
if legal[maxPoint - 2, i] then
begin
veliu := kleim[maxPoint - 2, i];
if (veliu < 7) and
(veliu > -5) and
(bord[maxPoint - 2, i + 1] = 0) and
(bord[maxPoint - 2, i - 1] = 0) then
if (rekrd <> iNil) and
(veliu < rekrd) then
begin
rekrd := veliu;
x := maxPoint - 2;
y := i;
end
else if rekrd = iNil then
begin
rekrd := veliu;
x := maxPoint - 2;
y := i;
end;
end;
for i := maxPoint - 3 downto 3 do
if legal[i, maxPoint - 2] then
begin
veliu := kleim[i, maxPoint - 2];
if (veliu < 7) and
(veliu > -5) and
(bord[i + 1, maxPoint - 2] = 0) and
(bord[i - 1, maxPoint - 2] = 0) then
if (rekrd <> iNil) and
(veliu < rekrd) then
begin
rekrd := veliu;
x := i;
y := maxPoint - 2;
end
else if rekrd = iNil then
begin
rekrd := veliu;
x := i;
y := maxPoint - 2;
end;
end;
extend2 := x <> iNil;
end { extend2 };
{
connects against enemy cuts
}
function connectCut(var x, y: integer): boolean;
var
i, j, nap, gid, infl: integer;
begin { connectCut }
playreason := 'connectCut';
connectCut := true;
for i := 0 to maxPoint do
for j := 0 to maxPoint do
if legal[i, j] and
(protPoints[i, j] = 0) then { not a protected point }
begin
nap := 0; { how many of my stones am I adjacent to? }
if (i > 0) and (bord[i - 1, j] = 1) then
begin
nap := nap + 1;
pList.p[nap].px := i - 1;
pList.p[nap].py := j;
end;
if (j > 0) and (bord[i, j - 1] = 1) then
begin
nap := nap + 1;
pList.p[nap].px := i;
pList.p[nap].py := j - 1;
end;
if (i < maxPoint) and (bord[i + 1, j] = 1) then
begin
nap := nap + 1;
pList.p[nap].px := i + 1;
pList.p[nap].py := j;
end;
if (j < maxPoint) and (bord[i, j + 1] = 1) then
begin
nap := nap + 1;
pList.p[nap].px := i;
pList.p[nap].py := j + 1;
end;
if nap = 1 then { possible knight's or 2-point extention }
with pList.p[1] do
begin
gid := groupIDs[px, py];
if (i > 0) and (i < maxPoint) and
(ndbord[i - 1, j] = 1) and
(ndbord[i + 1, j] = 0) then { contact on left }
begin
if ((j > 0) and (ndbord[i, j - 1] = -1) and
(ndbord[i + 1, j - 1] = 1) and
(gid <> groupIDs[i + 1, j - 1])) or
((j < maxPoint) and (ndbord[i, j + 1] = -1) and
(ndbord[i + 1, j + 1] = 1) and
(gid <> groupIDs[i + 1, j + 1])) or
((((j > 0) and (ndbord[i, j - 1] = -1)) or
((j < maxPoint) and (ndbord[i, j + 1] = -1))) and
(i < (maxPoint - 1)) and
(ndbord[i + 2, j] = 1) and
(gid <> groupIDs[i + 2, j])) then
begin
x := i;
y := j;
if safeMove(x, y) then
exit(connectCut);
end;
end
else if (i < maxPoint) and (i > 0) and
(ndbord[i + 1, j] = 1) and
(ndbord[i - 1, j] = 0) then { r }
begin
if ((j > 0) and (ndbord[i, j - 1] = -1) and
(ndbord[i - 1, j - 1] = 1) and
(gid <> groupIDs[i - 1, j - 1])) or
((j < maxPoint) and (ndbord[i, j + 1] = -1) and
(ndbord[i - 1, j + 1] = 1) and
(gid <> groupIDs[i - 1, j + 1])) or
((((j > 0) and (ndbord[i, j - 1] = -1)) or
((j < maxPoint) and (ndbord[i, j + 1] = -1))) and
(i > 1) and
(ndbord[i - 2, j] = 1) and
(gid <> groupIDs[i - 2, j])) then
begin
x := i;
y := j;
if safeMove(x, y) then
exit(connectCut);
end;
end
else if (j > 0) and (j < maxPoint) and
(ndbord[i, j - 1] = 1) and
(ndbord[i, j + 1] = 0) then { top }
begin
if ((i > 0) and (ndbord[i - 1, j] = -1) and
(ndbord[i - 1, j + 1] = 1) and
(gid <> groupIDs[i - 1, j + 1])) or
((i < maxPoint) and (ndbord[i + 1, j] = -1) and
(ndbord[i + 1, j + 1] = 1) and
(gid <> groupIDs[i + 1, j + 1])) or
((((i > 0) and (ndbord[i - 1, j] = -1)) or
((i < maxPoint) and (ndbord[i + 1, j] = -1))) and
(j < (maxPoint - 1)) and
(ndbord[i, j + 2] = 1) and
(gid <> groupIDs[i, j + 2])) then
begin
x := i;
y := j;
if safeMove(x, y) then
exit(connectCut);
end;
end
else if (j > 0) and (j < maxPoint) and
(ndbord[i, j + 1] = 1) and
(ndbord[i, j - 1] = 0) then { bottom }
begin
if ((i > 0) and (ndbord[i - 1, j] = -1) and
(ndbord[i - 1, j - 1] = 1) and
(gid <> groupIDs[i - 1, j - 1])) or
((i < maxPoint) and (ndbord[i + 1, j] = -1) and
(ndbord[i + 1, j - 1] = 1) and
(gid <> groupIDs[i + 1, j - 1])) or
((((i > 0) and (ndbord[i - 1, j] = -1)) or
((i < maxPoint) and (ndbord[i + 1, j] = -1))) and
(j > 1) and
(ndbord[i, j - 2] = 1) and
(gid <> groupIDs[i, j - 2])) then
begin
x := i;
y := j;
if safeMove(x, y) then
exit(connectCut);
end;
end;
end
else if nap = 2 then { diagonal or 1-point extention }
begin
if groupIDs[pList.p[1].px, pList.p[1].py] <>
groupIDs[pList.p[2].px, pList.p[2].py] then
begin
if (pList.p[1].px <> pList.p[2].px) and
(pList.p[1].py <> pList.p[2].py) then { diag }
begin
spanGroup(pList.p[1].px,
pList.p[1].py, pList1);
spanGroup(pList.p[2].px,
pList.p[2].py, pList2);
intersectPlist(pList1, pList2, pList3);
if pList3.indx = 1 then
if (i > 0) and (ndbord[i - 1, j] = -1) or
(i < maxPoint) and (ndbord[i + 1, j] = -1) or
(j > 0) and (ndbord[i, j - 1] = -1) or
(j < maxPoint) and (ndbord[i, j + 1] = -1) then
begin { must make direct connection }
x := i;
y := j;
if heCanCut(x, y) then
if safeMove(x, y) then
exit(connectCut);
end
else if heCanCut(i, j) then
begin { protect point if possible }
infl := 1000;
if (i > 0) and legal[i - 1, j] and
((i = 1) or (ndbord[i - 2, j] = 0)) and
((j = 0) or (ndbord[i - 1, j - 1] = 0)) and
((j = maxPoint) or
(ndbord[i - 1, j + 1] = 0)) then
if safeMove(i - 1, j) then
if kleim[i - 1, j] < infl then
begin
x := i - 1;
y := j;
infl := kleim[i - 1, j];
end;
if (j > 0) and legal[i, j - 1] and
((j = 1) or (ndbord[i, j - 2] = 0)) and
((i = 0) or (ndbord[i - 1, j - 1] = 0)) and
((i = maxPoint) or
(ndbord[i + 1, j - 1] = 0)) then
if safeMove(i, j - 1) then
if kleim[i, j - 1] < infl then
begin
x := i;
y := j - 1;
infl := kleim[i, j - 1];
end;
if (i < maxPoint) and legal[i + 1, j] and
((i = (maxPoint - 1)) or
(ndbord[i + 2, j] = 0)) and
((j = 0) or (ndbord[i + 1, j - 1] = 0)) and
((j = maxPoint) or
(ndbord[i + 1, j + 1] = 0)) then
if safeMove(i + 1, j) then
if kleim[i + 1, j] < infl then
begin
x := i + 1;
y := j;
infl := kleim[i + 1, j];
end;
if (j < maxPoint) and legal[i, j + 1] and
((j = (maxPoint - 1)) or
(ndbord[i, j + 2] = 0)) and
((i = 0) or (ndbord[i - 1, j + 1] = 0)) and
((i = maxPoint) or
(ndbord[i + 1, j + 1] = 0)) then
if safeMove(i, j + 1) then
if kleim[i, j + 1] < infl then
begin
x := i;
y := j + 1;
infl := kleim[i, j + 1];
end;
if infl < 1000 then
exit(connectCut);
x := i; { direct connection }
y := j;
if safeMove(x, y) then
exit(connectCut);
end;
end
else { 1-point extension, only protect if threatened }
begin
if (i > 0) and (ndbord[i - 1, j] = -1) or
(j > 0) and (ndbord[i, j - 1] = -1) or
(i < maxPoint) and (ndbord[i + 1, j] = -1) or
(j < maxPoint) and (ndbord[i, j + 1] = -1) then
begin
x := i;
y := j;
if heCanCut(x, y) then
if safeMove(x, y) then
exit(connectCut);
end;
end;
end;
end
else if nap = 3 then { unprotected, but me on 3 sides }
begin
if (groupIDs[pList.p[1].px, pList.p[1].py] <>
groupIDs[pList.p[2].px, pList.p[2].py]) or
(groupIDs[pList.p[1].px, pList.p[1].py] <>
groupIDs[pList.p[3].px, pList.p[3].py]) or
(groupIDs[pList.p[3].px, pList.p[3].py] <>
groupIDs[pList.p[2].px, pList.p[2].py]) then
begin
spanGroup(pList.p[1].px, pList.p[1].py, pList1);
spanGroup(pList.p[2].px, pList.p[2].py, pList2);
intersectPlist(pList1, pList2, pList3);
spanGroup(pList.p[3].px, pList.p[3].py, pList2);
intersectPlist(pList2, pList3, pList1);
if pList1.indx = 1 then { a common connect point }
if heCanCut(i, j) then
if safeMove(i, j) then
begin
x := i;
y := j;
exit(connectCut);
end;
end;
end;
end;
connectCut := false;
end { connectCut };
{
cuts the enemy
}
function cutHim(var x, y: integer): boolean;
var
i, j, nap, gid: integer;
begin { cutHim }
playreason := 'cutHim';
cutHim := true;
for i := 0 to maxPoint do
for j := 0 to maxPoint do
if legal[i, j] then
begin
nap := 0; { how many of his stones am I adjacent to? }
if (i > 0) and (ndbord[i - 1, j] = -1) then
begin
nap := nap + 1;
pList.p[nap].px := i - 1;
pList.p[nap].py := j;
end;
if (j > 0) and (ndbord[i, j - 1] = -1) then
begin
nap := nap + 1;
pList.p[nap].px := i;
pList.p[nap].py := j - 1;
end;
if (i < maxPoint) and (ndbord[i + 1, j] = -1) then
begin
nap := nap + 1;
pList.p[nap].px := i + 1;
pList.p[nap].py := j;
end;
if (j < maxPoint) and (ndbord[i, j + 1] = -1) then
begin
nap := nap + 1;
pList.p[nap].px := i;
pList.p[nap].py := j + 1;
end;
if nap = 1 then { possible knight's or 2-point extention }
with pList.p[1] do
begin
gid := groupIDs[px, py];
if (i > 0) and (i < maxPoint) and
(ndbord[i - 1, j] = -1) and
(connectMap[i, j] > 0) then { contact on left }
begin
if ((j > 0) and
(ndbord[i + 1, j - 1] = -1) and
(gid <> groupIDs[i + 1, j - 1])) or
((j < maxPoint) and
(ndbord[i + 1, j + 1] = -1) and
(gid <> groupIDs[i + 1, j + 1])) or
((i < (maxPoint - 1)) and
(ndbord[i + 1, j] = 0) and
(ndbord[i + 2, j] = -1) and
(gid <> groupIDs[i + 2, j])) then
begin
x := i;
y := j;
if safeMove(x, y) then
exit(cutHim);
end;
end
else if (i < maxPoint) and (i > 0) and
(ndbord[i + 1, j] = -1) and
(connectMap[i, j] > 0) then { r }
begin
if ((j > 0) and
(ndbord[i - 1, j - 1] = -1) and
(gid <> groupIDs[i - 1, j - 1])) or
((j < maxPoint) and
(ndbord[i - 1, j + 1] = -1) and
(gid <> groupIDs[i - 1, j + 1])) or
((i > 1) and
(ndbord[i - 1, j] = 0) and
(ndbord[i - 2, j] = -1) and
(gid <> groupIDs[i - 2, j])) then
begin
x := i;
y := j;
if safeMove(x, y) then
exit(cutHim);
end;
end
else if (j > 0) and (j < maxPoint) and
(ndbord[i, j - 1] = -1) and
(connectMap[i, j] > 0) then { top }
begin
if ((i > 0) and
(ndbord[i - 1, j + 1] = -1) and
(gid <> groupIDs[i - 1, j + 1])) or
((i < maxPoint) and
(ndbord[i + 1, j + 1] = -1) and
(gid <> groupIDs[i + 1, j + 1])) or
((j < (maxPoint - 1)) and
(ndbord[i, j + 1] = 0) and
(ndbord[i, j + 2] = -1) and
(gid <> groupIDs[i, j + 2])) then
begin
x := i;
y := j;
if safeMove(x, y) then
exit(cutHim);
end;
end
else if (j > 0) and (j < maxPoint) and
(ndbord[i, j + 1] = -1) and
(connectMap[i, j] > 0) then { bottom }
begin
if ((i > 0) and
(ndbord[i - 1, j - 1] = -1) and
(gid <> groupIDs[i - 1, j - 1])) or
((i < maxPoint) and
(ndbord[i + 1, j - 1] = -1) and
(gid <> groupIDs[i + 1, j - 1])) or
((j > 1) and
(ndbord[i, j - 1] = 0) and
(ndbord[i, j - 2] = -1) and
(gid <> groupIDs[i, j - 2])) then
begin
x := i;
y := j;
if safeMove(x, y) then
exit(cutHim);
end;
end;
end
else if nap = 2 then { diagonal or 1-point extention }
begin
if groupIDs[pList.p[1].px, pList.p[1].py] <>
groupIDs[pList.p[2].px, pList.p[2].py] then
begin
if (pList.p[1].px <> pList.p[2].px) and
(pList.p[1].py <> pList.p[2].py) then { diag }
begin
spanGroup(pList.p[1].px,
pList.p[1].py, pList1);
spanGroup(pList.p[2].px,
pList.p[2].py, pList2);
intersectPlist(pList1, pList2, pList3);
if pList3.indx = 1 then
begin
x := i;
y := j;
if safeMove(x, y) then
exit(cutHim);
end;
end
else { 1-point extension, only cut if connected }
begin
if connectMap[i, j] > 0 then
begin
x := i;
y := j;
if safeMove(x, y) then
exit(cutHim);
end;
end;
end;
end
else if nap = 3 then { unprotected, but him on 3 sides }
begin
if (groupIDs[pList.p[1].px, pList.p[1].py] <>
groupIDs[pList.p[2].px, pList.p[2].py]) or
(groupIDs[pList.p[1].px, pList.p[1].py] <>
groupIDs[pList.p[3].px, pList.p[3].py]) or
(groupIDs[pList.p[3].px, pList.p[3].py] <>
groupIDs[pList.p[2].px, pList.p[2].py]) then
begin
spanGroup(pList.p[1].px, pList.p[1].py, pList1);
spanGroup(pList.p[2].px, pList.p[2].py, pList2);
intersectPlist(pList1, pList2, pList3);
spanGroup(pList.p[3].px, pList.p[3].py, pList2);
intersectPlist(pList2, pList3, pList1);
if pList1.indx = 1 then { a common connect point }
if safeMove(i, j) then
begin
x := i;
y := j;
exit(cutHim);
end;
end;
end;
end;
cutHim := false;
end { cutHim };
{
blocks enemy cuts thru 1-point extensions
}
function blockCut(var x, y: integer): boolean;
var
i, j: integer;
begin { blockCut }
playReason := 'blockCut';
blockCut := true;
for i := 0 to maxPoint do
for j := 0 to maxPoint do
if legal[i, j] then
begin
if (i > 0) and (j > 0) and (j < maxPoint) then
begin
if (ndbord[i - 1, j] = -1) and
(ndbord[i - 1, j - 1] = 1) and
(ndbord[i - 1, j + 1] = 1) and
(groupIDs[i - 1, j - 1] <> groupIDs[i - 1, j + 1]) then
begin
x := i;
y := j;
if heCanCut(x, y) then
if safeMove(x, y) then
exit(blockCut);
end;
end;
if (i < maxPoint) and (j > 0) and (j < maxPoint) then
begin
if (ndbord[i + 1, j] = -1) and
(ndbord[i + 1, j - 1] = 1) and
(ndbord[i + 1, j + 1] = 1) and
(groupIDs[i + 1, j - 1] <> groupIDs[i + 1, j + 1]) then
begin
x := i;
y := j;
if heCanCut(x, y) then
if safeMove(x, y) then
exit(blockCut);
end;
end;
if (j > 0) and (i > 0) and (i < maxPoint) then
begin
if (ndbord[i, j - 1] = -1) and
(ndbord[i - 1, j - 1] = 1) and
(ndbord[i + 1, j - 1] = 1) and
(groupIDs[i - 1, j - 1] <> groupIDs[i + 1, j - 1]) then
begin
x := i;
y := j;
if heCanCut(x, y) then
if safeMove(x, y) then
exit(blockCut);
end;
end;
if (j < maxPoint) and (i > 0) and (i < maxPoint) then
begin
if (ndbord[i, j + 1] = -1) and
(ndbord[i - 1, j + 1] = 1) and
(ndbord[i + 1, j + 1] = 1) and
(groupIDs[i - 1, j + 1] <> groupIDs[i + 1, j + 1]) then
begin
x := i;
y := j;
if heCanCut(x, y) then
if safeMove(x, y) then
exit(blockCut);
end;
end;
end;
blockCut := false;
end { blockCut };
{
drops to the edge of the board if threatened
}
function dropToEdge(var x, y: integer): boolean;
var
i: integer;
begin { dropToEdge }
dropToEdge := true;
playReason := 'dropToEdge';
for i := 1 to maxPoint - 1 do
begin
if legal[1, i] then
if (ndbord[2, i] = 1) and
(ndbord[0, i] = 0) and
(ndbord[1, i - 1] < 1) and
(ndbord[1, i + 1] < 1) and
((ndbord[2, i - 1] = -1) or
(ndbord[2, i + 1] = -1) or
(ndbord[1, i - 1] = -1) or
(ndbord[1, i + 1] = -1)) then
begin
x := 1;
y := i;
if safeMove(x, y) then
exit(dropToEdge);
end;
if legal[maxPoint - 1, i] then
if (ndbord[maxPoint - 2, i] = 1) and
(ndbord[maxPoint, i] = 0) and
(ndbord[maxPoint - 1, i - 1] < 1) and
(ndbord[maxPoint - 1, i + 1] < 1) and
((ndbord[maxPoint - 2, i - 1] = -1) or
(ndbord[maxPoint - 2, i + 1] = -1) or
(ndbord[maxPoint - 1, i - 1] = -1) or
(ndbord[maxPoint - 1, i + 1] = -1)) then
begin
x := maxPoint - 1;
y := i;
if safeMove(x, y) then
exit(dropToEdge);
end;
if legal[i, 1] then
if (ndbord[i, 2] = 1) and
(ndbord[i, 0] = 0) and
(ndbord[i - 1, 1] < 1) and
(ndbord[i + 1, 1] < 1) and
((ndbord[i - 1, 2] = -1) or
(ndbord[i + 1, 2] = -1) or
(ndbord[i - 1, 1] = -1) or
(ndbord[i + 1, 1] = -1)) then
begin
x := i;
y := 1;
if safeMove(x, y) then
exit(dropToEdge);
end;
if legal[i, maxPoint - 1] then
if (ndbord[i, maxPoint - 2] = 1) and
(ndbord[i, maxPoint] = 0) and
(ndbord[i - 1, maxPoint - 1] < 1) and
(ndbord[i + 1, maxPoint - 1] < 1) and
((ndbord[i - 1, maxPoint - 2] = -1) or
(ndbord[i + 1, maxPoint - 2] = -1) or
(ndbord[i - 1, maxPoint - 1] = -1) or
(ndbord[i + 1, maxPoint - 1] = -1)) then
begin
x := i;
y := maxPoint - 1;
if safeMove(x, y) then
exit(dropToEdge);
end;
if legal[0, i] then
if (ndbord[1, i] = 1) and
(ndbord[0, i - 1] < 1) and
(ndbord[0, i + 1] < 1) and
(((ndbord[1, i - 1] = -1) and
(ndbord[1, i + 1] = -1)) or
(ndbord[0, i - 1] = -1) or
(ndbord[0, i + 1] = -1)) then
begin
x := 0;
y := i;
if safeMove(x, y) then
exit(dropToEdge);
end;
if legal[maxPoint, i] then
if (ndbord[maxPoint - 1, i] = 1) and
(ndbord[maxPoint, i - 1] < 1) and
(ndbord[maxPoint, i + 1] < 1) and
(((ndbord[maxPoint - 1, i - 1] = -1) and
(ndbord[maxPoint - 1, i + 1] = -1)) or
(ndbord[maxPoint, i - 1] = -1) or
(ndbord[maxPoint, i + 1] = -1)) then
begin
x := maxPoint;
y := i;
if safeMove(x, y) then
exit(dropToEdge);
end;
if legal[i, 0] then
if (ndbord[i, 1] = 1) and
(ndbord[i - 1, 0] < 1) and
(ndbord[i + 1, 0] < 1) and
(((ndbord[i - 1, 1] = -1) and
(ndbord[i + 1, 1] = -1)) or
(ndbord[i - 1, 0] = -1) or
(ndbord[i + 1, 0] = -1)) then
begin
x := i;
y := 0;
if safeMove(x, y) then
exit(dropToEdge);
end;
if legal[i, maxPoint] then
if (ndbord[i, maxPoint - 1] = 1) and
(ndbord[i - 1, maxPoint] < 1) and
(ndbord[i + 1, maxPoint] < 1) and
(((ndbord[i - 1, maxPoint - 1] = -1) and
(ndbord[i + 1, maxPoint - 1] = -1)) or
(ndbord[i - 1, maxPoint] = -1) or
(ndbord[i + 1, maxPoint] = -1)) then
begin
x := i;
y := maxPoint;
if safeMove(x, y) then
exit(dropToEdge);
end;
end;
dropToEdge := false;
end { dropToEdge };
{
Plays a move that requires a response on the opponent's part
}
function threaten(var x, y: integer): boolean;
var
i, j, gx, gy, tNum: integer;
begin { threaten }
playReason := 'threaten';
initArray(threatBord);
for i := 1 to maxGroupID do
with gList[i] do
if (not isLive) and
(ndBord[lx, ly] = -1) then
begin
spanGroup(lx, ly, pList);
for j := 1 to pList.indx do
with pList.p[j] do
if legal[px, py] then
begin
plei(px, py, 1);
if gList[groupIDs[px, py]].libC > 1 then
if killable(lx, ly, gx, gy) then
threatBord[px, py] := threatBord[px, py] + 1;
restoreState;
end;
end;
tNum := 0;
for i := 0 to maxPoint do
for j := 0 to maxPoint do
if (threatBord[i, j] > tNum) and
((threatBord[i, j] > 1) or
(connectMap[i, j] > 0)) then
begin
tNum := threatBord[i, j];
x := i;
y := j;
end;
threaten := tNum > 0;
end { threaten };
{
Extends walls in a connected fashion.
Finds the lowest influence (mine) point that is connected to one
of my groups.
Only looks in the center of the board.
}
function extendWall(var x, y: integer): boolean;
var
infl, i, j: integer;
begin { extendWall }
playReason := 'extendWall';
x := iNil;
y := iNil;
infl := 11;
for i := 2 to maxPoint - 2 do
for j := 2 to maxPoint - 2 do
if legal[i, j] then
if connectMap[i, j] > 0 then
if (kleim[i, j] < infl) and
(ndbord[i - 1, j] < 1) and
(ndbord[i + 1, j] < 1) and
(ndbord[i, j - 1] < 1) and
(ndbord[i, j + 1] < 1) and
((kleim[i - 1, j] < 0) or
(kleim[i + 1, j] < 0) or
(kleim[i, j - 1] < 0) or
(kleim[i, j + 1] < 0)) then
if safeMove(i, j) then
begin
infl := kleim[i, j];
x := i;
y := j;
end;
extendWall := x <> iNil;
end { extendWall };
{
Pushes walls in a tightly connected fashion.
Finds the lowest influence (mine) point that is connected to one
of my groups.
}
function pushWall(var x, y: integer): boolean;
var
infl, i, j, na: integer;
begin { pushWall }
playReason := 'pushWall';
x := iNil;
y := iNil;
infl := 11;
for i := 0 to maxPoint do
for j := 0 to maxPoint do
if legal[i, j] then
if connectMap[i, j] > 0 then
if (kleim[i, j] < infl) and
(((i > 0) and (ndbord[i - 1, j] = 1)) or
((i < maxPoint) and (ndbord[i + 1, j] = 1)) or
((j > 0) and (ndbord[i, j - 1] = 1)) or
((j < maxPoint) and (ndbord[i, j + 1] = 1)) or
((i > 0) and (j > 0) and (ndbord[i - 1, j - 1] = 1)) or
((i < maxPoint) and (j > 0) and (ndbord[i + 1, j - 1] = 1)) or
((i > 0) and (j < maxPoint) and (ndbord[i - 1, j + 1] = 1)) or
((i < maxPoint) and (j < maxPoint) and
(ndbord[i + 1, j + 1] = 1))) and
(((i > 0) and (kleim[i - 1, j] < 0)) or
((i < maxPoint) and (kleim[i + 1, j] < 0)) or
((j > 0) and (kleim[i, j - 1] < 0)) or
((j < maxPoint) and (kleim[i, j + 1] < 0))) then
begin
na := 0;
if (i > 0) and (ndbord[i - 1, j] <> 0) then
na := na + 1;
if (i < maxPoint) and (ndbord[i + 1, j] <> 0) then
na := na + 1;
if (j > 0) and (ndbord[i, j - 1] <> 0) then
na := na + 1;
if (j < maxPoint) and (ndbord[i, j + 1] <> 0) then
na := na + 1;
if na < 3 then
if safeMove(i, j) then
begin
infl := kleim[i, j];
x := i;
y := j;
end;
end;
pushWall := x <> iNil;
end { pushWall };
{
check to see if I can kill anything
}
function lookForKill(var x, y: integer): boolean;
var
i: integer;
begin { lookForKill }
playReason := 'lookForKill';
lookForKill := true;
for i := 1 to maxGroupID do { scan the group list }
with gList[i] do
if (libC = 1) and
(ndbord[lx, ly] = -1) then
begin { we found a live enemy group with one liberty }
spanGroup(lx, ly, pList); { find the liberty }
x := pList.p[1].px;
y := pList.p[1].py;
if legal[x, y] then
exit(lookForKill);
end;
lookForKill := false;
end { lookForKill };
{
check to see if I can save anything in atari
}
function lookForSave(var x, y: integer): boolean;
var
i: integer;
begin { lookForSave }
playReason := 'lookForSave';
lookForSave := true;
for i := 1 to maxGroupID do { scan the group list }
with gList[i] do
if (libC = 1) and
(ndbord[lx, ly] = 1) then
begin
if saveable(lx, ly, x, y) then { see if I can save it }
exit(lookForSave);
end;
lookForSave := false;
end { lookForSave };
{
check to see if I can save anything with n libs
}
function lookForSaveN(var x, y: integer): boolean;
var
i: integer;
begin { lookForSaveN }
if saveNLibs then
begin
playReason := 'lookForSaveN';
lookForSaveN := true;
for i := 1 to maxGroupID do { scan the group list }
with gList[i] do
if (libC > 1) and
(libC <= treeLibLim) and
(ndbord[lx, ly] = 1) then
begin
if killable(lx, ly, x, y) then
if saveable(lx, ly, x, y) then { see if I can save it }
exit(lookForSaveN);
end;
end;
lookForSaveN := false;
end { lookForSaveN };
{
check to see if I can attack one of his groups
}
function lookForAttack(var x, y: integer): boolean;
var
tx, ty, i: integer;
begin { lookForAttack }
playReason := 'lookForAttack';
lookForAttack := true;
for i := 1 to maxGroupID do { scan the group list }
with gList[i] do
if (not isLive) and
(libC > 1) and
(libC <= (treeLibLim + 1)) and
(ndbord[lx, ly] = -1) then
begin
if killable(lx, ly, tx, ty) then { can we kill it? }
begin
x := tx; { yep - do so }
y := ty;
exit(lookForAttack);
end;
end;
lookForAttack := false;
end { lookForAttack };
{
check to see if I can attack one of his groups
uses limited depth search so that it can work on larger lib counts
}
function findAttack2(var x, y: integer): boolean;
var
tx, ty, i, otll: integer;
begin { findAttack2 }
if playLevel < 7 then
begin
findAttack2 := false;
exit(findAttack2);
end;
playReason := 'findAttack2';
findAttack2 := true;
depthLimit := 8;
otll := treeLibLim;
for i := 1 to maxGroupID do { scan the group list }
with gList[i] do
if (not isLive) and
(ndBord[lx, ly] = -1) and
(libC > 1) then
begin
treeLibLim := 6;
if killable(lx, ly, tx, ty) then { can we kill it? }
begin
x := tx; { yep - do so }
y := ty;
exit(findAttack2);
end;
treeLibLim := otll;
end;
findAttack2 := false;
depthLimit := 100;
end { findAttack2 };
function doubleAtari(var x, y: integer): boolean;
var
i, j: integer;
begin { doubleAtari }
playReason := 'doubleAtari';
doubleAtari := true;
for i := 1 to maxGroupID - 1 do
with gList[i] do
if (libC = 2) and
(ndbord[lx, ly] = -1) then { found an atariable group of his }
begin
spanGroup(lx, ly, dapList1);
for j := i + 1 to maxGroupID do
with gList[j] do
if (libC = 2) and
(ndbord[lx, ly] = -1) then
begin
spanGroup(lx, ly, dapList2);
intersectPlist(dapList1, dapList2, dapList3);
if dapList3.indx > 0 then
with dapList3.p[1] do
if legal[px, py] then
begin
plei(px, py, 1);
if gList[groupIDs[px, py]].libC > 1 then
begin
x := px;
y := py;
restoreState;
exit(doubleAtari);
end;
restoreState;
end;
end;
end;
doubleAtari := false;
end { doubleAtari };
{
ataris a group just for the hell of it
}
function atariAnyway(var x, y: integer): boolean;
var
i: integer;
begin { atariAnyway }
playReason := 'atariAnyway';
atariAnyway := true;
for i := 1 to maxGroupID do { scan the group list }
with gList[i] do
if (libC = 2) and
(ndbord[lx, ly] = -1) then
begin
spanGroup(lx, ly, pList);
with pList.p[1] do
if legal[px, py] and
((connectMap[px, py] > 0) or
((px > 0) and (connectMap[px - 1, py] > 0)) or
((px < maxPoint) and (connectMap[px + 1, py] > 0)) or
((py > 0) and (connectMap[px, py - 1] > 0)) or
((py < maxPoint) and (connectMap[px, py + 1] > 0))) then
if safeMove(px, py) then
begin
x := px;
y := py;
exit(atariAnyway);
end;
with pList.p[2] do
if legal[px, py] and
((connectMap[px, py] > 0) or
((px > 0) and (connectMap[px - 1, py] > 0)) or
((px < maxPoint) and (connectMap[px + 1, py] > 0)) or
((py > 0) and (connectMap[px, py - 1] > 0)) or
((py < maxPoint) and (connectMap[px, py + 1] > 0))) then
if safeMove(px, py) then
begin
x := px;
y := py;
exit(atariAnyway);
end;
end;
atariAnyway := false;
end { atariAnyway };
{
undercuts his groups
}
function underCut(var x, y: integer): boolean;
var
i, j: integer;
begin { underCut }
playReason := 'underCut';
underCut := true;
for i := 1 to maxPoint - 1 do
begin
if legal[0, i] then
begin
if ndbord[1, i] = -1 then
if safeMove(0, i) then
begin
x := 0;
y := i;
exit(underCut);
end;
end;
if legal[maxPoint, i] then
begin
if ndbord[maxPoint - 1, i] = -1 then
if safeMove(maxPoint, i) then
begin
x := maxPoint;
y := i;
exit(underCut);
end;
end;
if legal[i, 0] then
begin
if ndbord[i, 1] = -1 then
if safeMove(i, 0) then
begin
x := i;
y := 0;
exit(underCut);
end;
end;
if legal[i, maxPoint] then
begin
if ndbord[i, maxPoint - 1] = -1 then
if safeMove(i, maxPoint) then
begin
x := i;
y := maxPoint;
exit(underCut);
end;
end;
end;
underCut := false;
end { underCut };
{
reduces the liberty count of one of his groups
}
function reduceHisLiberties(var x, y: integer): boolean;
var
i, j: integer;
begin { reduceHisLiberties }
playReason := 'reduceHisLiberties';
reduceHisLiberties := true;
sortLibs;
for i := 1 to maxGroupID do
with gList[sGList[i]] do
if (not isLive) and
(libC > 2) and
(ndbord[lx, ly] = -1) then
begin
spanGroup(lx, ly, pList);
for j := 1 to pList.indx do
with pList.p[j] do
if legal[px, py] and
(connectMap[px, py] > 0) then
if safeMove(px, py) then
begin
x := px;
y := py;
exit(reduceHisLiberties);
end;
end;
reduceHisLiberties := false;
end { reduceHisLiberties };
{
connects a group to the edge
}
function dropToEdge2(var x, y: integer): boolean;
var
i: integer;
begin { dropToEdge2 }
playReason := 'dropToEdge2';
dropToEdge2 := true;
for i := 1 to maxPoint - 1 do
begin
if legal[i, 0] then
begin
if (ndbord[i, 1] = 1) and
((ndbord[i - 1, 0] < 1) or
(groupIDs[i - 1, 0] <> groupIDs[i, 1])) and
((ndbord[i + 1, 0] < 1) or
(groupIDs[i + 1, 0] <> groupIDs[i, 1])) and
((ndbord[i - 1, 1] = -1) or
(ndbord[i + 1, 1] = -1)) then
begin
x := i;
y := 0;
if safeMove(x, y) then
exit(dropToEdge2);
end;
end;
if legal[0, i] then
begin
if (ndbord[1, i] = 1) and
((ndbord[0, i - 1] < 1) or
(groupIDs[0, i - 1] <> groupIDs[1, i])) and
((ndbord[0, i + 1] < 1) or
(groupIDs[0, i + 1] <> groupIDs[1, i])) and
((ndbord[1, i - 1] = -1) or
(ndbord[1, i + 1] = -1)) then
begin
x := 0;
y := i;
if safeMove(x, y) then
exit(dropToEdge2);
end;
end;
if legal[i, maxPoint] then
begin
if (ndbord[i, maxPoint - 1] = 1) and
((ndbord[i - 1, maxPoint] < 1) or
(groupIDs[i - 1, maxPoint] <> groupIDs[i, maxPoint - 1])) and
((ndbord[i + 1, maxPoint] < 1) or
(groupIDs[i + 1, maxPoint] <> groupIDs[i, maxPoint - 1])) and
((ndbord[i - 1, maxPoint - 1] = -1) or
(ndbord[i + 1, maxPoint - 1] = -1)) then
begin
x := i;
y := maxPoint;
if safeMove(x, y) then
exit(dropToEdge2);
end;
end;
if legal[maxPoint, i] then
begin
if (ndbord[maxPoint - 1, i] = 1) and
((ndbord[maxPoint, i - 1] < 1) or
(groupIDs[maxPoint, i - 1] <> groupIDs[maxPoint - 1, i])) and
((ndbord[maxPoint, i + 1] < 1) or
(groupIDs[maxPoint, i + 1] <> groupIDs[maxPoint - 1, i])) and
((ndbord[maxPoint - 1, i - 1] = -1) or
(ndbord[maxPoint - 1, i + 1] = -1)) then
begin
x := maxPoint;
y := i;
if safeMove(x, y) then
exit(dropToEdge2);
end;
end;
end;
dropToEdge2 := false;
end { dropToEdge2 };
begin { blek }
saveState; { save state of the world }
if takeCorner(x, y) then
goto 1;
if lookForSave(x, y) then
goto 1;
if lookForSaveN(x, y) then
goto 1;
if extend(x, y) then { check for possible 3-line extentions }
goto 1;
if lookForKill(x, y) then
goto 1;
if doubleAtari(x, y) then
goto 1;
if lookForAttack(x, y) then
goto 1;
if threaten(x, y) then
goto 1;
if extend2(x, y) then
goto 1;
if connectCut(x, y) then
goto 1;
if blockCut(x, y) then
goto 1;
if cutHim(x, y) then
goto 1;
if extendWall(x, y) then
goto 1;
if findAttack2(x, y) then
goto 1;
if atariAnyway(x, y) then
goto 1;
if underCut(x, y) then
goto 1;
if dropToEdge(x, y) then
goto 1;
if pushWall(x, y) then
goto 1;
if reduceHisLiberties(x, y) then
goto 1;
if dropToEdge2(x, y) then
goto 1;
moveX := iNil; { pass }
moveY := iNil;
exit(blek);
1: { done }
moveX := x;
moveY := y;
end { blek };
procedure genBord(who: sType);
var
i, j: integer;
noMoves: boolean;
begin { genBord }
utilPlayLevel := playLevel;
showTrees := debug;
depthLimit := 100;
mySType := who;
if playLevel < 2 then
treeLibLim := 2
else
treeLibLim := 3;
noMoves := true;
for i := 0 to maxPoint do
for j := 0 to maxPoint do
if board[i, j].val = who then
begin
bord[i, j] := 1;
legal[i, j] := false;
noMoves := false;
end
else if board[i, j].val = empty then
begin
bord[i, j] := 0;
legal[i, j] := true;
end
else
begin
bord[i, j] := -1;
legal[i, j] := false;
noMoves := false;
end;
if koX >= 0 then
legal[koX, koY] := false;
if noMoves then
initState
else
genState;
end { genBord };
function playMove(who: sType; var xLoc, yLoc: integer): boolean;
var
i, j: integer;
noMoves: boolean;
begin { playMove }
saveNLibs := playLevel > 2;
genBord(who);
blek(xLoc, yLoc);
playMove := xLoc <> iNil;
end { playMove };
procedure showPlayState(who: sType);
var
res: resres;
shown: boolean;
cx, cy: integer;
handler outside;
begin { outside }
write(''); {control-G}
if shown then
refreshBoard;
exit(showPlayState);
end { outside };
procedure showIntBord(ib: intBoard);
var
i, j: integer;
s: string;
begin { showIntBord }
for i := 0 to maxPoint do
for j := 0 to maxPoint do
if ib[i, j] <> 0 then
begin
s := intToStr(ib[i, j]);
putBString(i, j, s);
end;
end { showIntBord };
procedure showGroupState(sn: integer);
var
g: integer;
s: string;
procedure span(x, y: integer);
begin { span }
markBoard[x, y] := marker;
putBString(x, y, s);
if (x > 0) and
(groupIDs[x - 1, y] = g) and
(markBoard[x - 1, y] <> marker) then
span(x - 1, y);
if (x < maxPoint) and
(groupIDs[x + 1, y] = g) and
(markBoard[x + 1, y] <> marker) then
span(x + 1, y);
if (y > 0) and
(groupIDs[x, y - 1] = g) and
(markBoard[x, y - 1] <> marker) then
span(x, y - 1);
if (y < maxPoint) and
(groupIDs[x, y + 1] = g) and
(markBoard[x, y + 1] <> marker) then
span(x, y + 1);
end { span };
begin { showGroupState }
marker := marker + 1;
if marker = 0 then
begin
initArray(markBoard);
marker := 1;
end;
if sn < 3 then
s := '*';
for g := 1 to maxGroupID do
with gList[g] do
begin
case sn of
1: { isLive }
if isLive then
span(lx, ly);
2: { isDead }
if isDead then
span(lx, ly);
3: { libertyCount }
begin
s := intToStr(libC);
span(lx, ly);
end;
end; { case }
end;
end { showGroupState };
begin { showPlayState }
genBord(who);
shown := false;
cx := tabRelX;
cy := tabRelY;
repeat
menu(stateMenu, false, 1, 11, cx, cy, -1, res);
if shown then
refreshBoard;
case res^.indices[1] of
1: { bord }
showIntBord(bord);
2: { ndBord }
showIntBord(ndBord);
3: { kleim }
showIntBord(kleim);
4: { sGroups }
showIntBord(sGroups);
5: { groupIDs }
showIntBord(groupIDs);
6: { connectMap }
showIntBord(connectMap);
7: { protPoints }
showIntBord(protPoints);
8: { isLive }
showGroupState(1);
9: { isDead }
showGroupState(2);
10: { libC }
showGroupState(3);
11: { done }
exit(showPlayState);
end; { case }
shown := true;
destroyRes(res);
until false;
end { showPlayState };
procedure initGoPlayer;
begin { initGoPlayer }
initGPUtils;
maxPlayLevel := 7;
allocNameDesc(11, 0, stateMenu);
with stateMenu^ do
begin
header := 'State to Display?';
{$R-}
commands[1] := 'Bord';
commands[2] := 'NdBord';
commands[3] := 'Influence';
commands[4] := 'Space Groups';
commands[5] := 'Group IDs';
commands[6] := 'Connect Map';
commands[7] := 'Protected Points';
commands[8] := 'Live Groups';
commands[9] := 'Dead Groups';
commands[10] := 'Liberty Counts';
commands[11] := 'Done';
{$R=}
end;
end. { initGoPlayer }