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

⟦654ce1121⟧ TextFile

    Length: 58638 (0xe50e)
    Types: TextFile
    Names: »goPlayer.pas«

Derivation

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

TextFile

{---------------------------------------------------------------}
{ 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 }