DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T g

⟦4f70ec858⟧ TextFile

    Length: 50784 (0xc660)
    Types: TextFile
    Names: »goPlayUtils.pas«

Derivation

└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
    └─⟦this⟧ »EUUGD18/General/GoBoard/goPlayUtils.pas« 

TextFile

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 }