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