home *** CD-ROM | disk | FTP | other *** search
/ Giga Games 1 / Giga Games.iso / net / go / comp / logan.c < prev    next >
Encoding:
Text File  |  1993-06-20  |  83.1 KB  |  2,313 lines

  1. >From: LOGANJ@BYUVAX.BITNET
  2. Newsgroups: net.sources.mac
  3. Subject: Sources to Go program for the Macintosh
  4. Date: 11 Mar 86 02:13:30 GMT
  5. Organization: University of California at Berkeley
  6.  
  7. The following text contains 1 document file and 7 files of source code for
  8. the Go program posted 24 Feb 86, as promised.  Each source file begins with
  9. "/* File filename" and you will need to break the files up to compile.  The
  10. programs were written for Megamax C.
  11.  
  12. The core programs (in goprocs.c) have been through extensive testing,
  13. everything else is in the process of conceptualization and development.
  14.  
  15. These programs are provided as a simple skeleton go program.  Some code was
  16. removed from the 'bestmoves' routine for this posting, to keep it simple.
  17. Since code was removed, the following programs will not play as well as the
  18. executable version that was posted 24 Feb 1986.
  19.  
  20. This is not to be taken as an example of great coding technique - this is a
  21. first effort.
  22.  
  23. Known problems:  The last time that I adjusted the weights in the
  24. move selection routine (bestmoves) to play a better game against Nemesis I
  25. made a mistake, so presently the executable version of the program will
  26. attempt an illegal move in some situations.
  27.  
  28. Also, I do not have access to a Mac XL, so I can not insure that the
  29. program runs properly there.  As far as I know, the code follows the
  30. toolbox interface conventions - nothing tricky there.
  31.  
  32. Will this kind posting create more interest in Programs that play go?
  33. Or will it set the programming of go back ten years by undermining support
  34. for more professional efforts?  Other?
  35.  
  36. Thanks to those of you who have responded with problems and suggestions!
  37. Correspondence and gratuities of any kind (verbal, code, financial, ...)
  38. can be sent to:
  39.  
  40. Lynn Beus & Jim Logan
  41. BYU Computer Science
  42. 232 TMCB
  43. Provo, Utah  84602
  44.  
  45. or email:  loganj@byuvax.bitnet
  46.  
  47. Phone: (801) 378-3617
  48. ___________________________________________________________________________
  49.  
  50. 26 February 1986
  51.  
  52. Go Utility Programs Description
  53.  
  54. Developer:  James R. Logan Jr. (BYU)
  55. Advisor:  Dr. Lynn H. Beus (BYU)
  56. BYU Computer Science
  57. 232 TMCB
  58. Provo, Utah  84602
  59. email address:  loganj@byuvax.bitnet
  60. phone:  (801) 378-3617
  61.  
  62. This document describes procedures, variables, arrays, and structures
  63. that maintain a 1-dimensional representation of the Oriental game of Go.
  64. The present implementation of the programs, for lack of development
  65. time, has the following arbitrary limitations:
  66.  
  67.   -  No count is maintained of the number of eyes that each army has
  68.      (an easy thing to implement?),  but only the number of individual
  69.      liberties that each army has.
  70.  
  71.   -  No count is maintained of the number of neighboring armies to an
  72.      army.
  73.  
  74.   -  The maximum allowable board size is 19 by 19 lines, or 361 positions.
  75.  
  76.   -  The maximum allowable number of armies is 362 (compile time
  77.      parameter).
  78.  
  79.   -  The game board must be square.
  80.  
  81. The 'who' variable in the game structure (game.who) designates black's
  82. or white's turn to play, and is an input parameter to some of these
  83. procedures.  The user is required to set this variable to White or Black
  84. before each procedure call.
  85.  
  86. All 1-dimensional representations of the Go board are defined in C as
  87. char [361].  The Go Programs consist of twelve main procedures.  The
  88. calling conventions and purpose of these twelve procedures is described
  89. as follows:
  90.  
  91. -initialize
  92. Initializes the specified game structure by clearing all stones from the
  93. various arrays and building the initial blank army.  Initialize must be
  94. called for a newly allocated game structure.  For example, to initialize
  95. a 5 by 5 game board the initialize routine should be called as follows:
  96.  
  97.   g->width = 5;
  98.   initialize(g);
  99.   where g is a game structure pointer previously allocated by the user.
  100.  
  101. -addastone
  102. Adds a stone of color g.who to the specified 1-dimensional position and
  103. updates the specified game structure.  If the specified position is
  104. already occupied then no update occurs.  For example, to add a stone to
  105. position 9 the addastone routine should be called as follows:
  106.  
  107.   addastone(g,9);
  108.   where g is an initialized game structure pointer.
  109.  
  110. -removeastone
  111. Removes the specified stone and updates the specified game structure.
  112. If the specified stone represents an unoccupied position then no update
  113. occurs.  For example, to remove a stone at position 9 the removeastone
  114. routine should be called as follows:
  115.  
  116.   removeastone(g,9,status);
  117.   where g is a game structure pointer,
  118.   and status is a movestatus (mstatus) structure.
  119.  
  120. -getneighbors
  121. Returns the number of immediate non-blank neighbors to a position, and
  122. returns the 1 dimensional board position of each non-blank neighbor in a
  123. stone[1..4] array sorted by army number.  For example, to get all
  124. neighboring positions (white, black, and blank) to position 9 the
  125. getneighbors routine should be called as follows:
  126.  
  127.   getneighbors(g,n,9);
  128.   where g is a game structure pointer,
  129.   and n is a nabor structure pointer.
  130.  
  131. The next two procedures will not normally be needed by the users program,
  132. but they are included for completeness.
  133.  
  134. -capture
  135. Removes the army represented by the specified stone and updates the
  136. appropriate data structures.  If the specified stone represents a blank
  137. army then no update occurs.  For example, to remove an army that
  138. contains a stone at position 9 the capture routine should be called as
  139. follows:
  140.  
  141.   capture(g,9);
  142.   where g is a game structure pointer.
  143.  
  144. -uncapture
  145. Uncaptures the army represented by the specified position and updates
  146. the appropriate data structures.  If the specified postion is occupied
  147. then no update occurs.  For example, to uncapture an army that contains
  148. a stone at position 9 the uncapture routine should be called as follows:
  149.  
  150.   uncapture(g,9,color);
  151.   where g is a game structure pointer,
  152.   and color is the color of the army (White or Black) being uncaptured.
  153. _________________________________________________________________________
  154.  
  155. The following routines print the values of game structures upside down
  156. from the game board displayed on the screen.
  157.  
  158. -moveboard
  159. This procedure prints the game.board array on the screen, for debugging.
  160. For example, to display game.board call moveboard as follows:
  161.  
  162.   moveboard(g);
  163.   where g is a game structure pointer.
  164.  
  165. -armyboard
  166. This procedure prints the game.armymen array on the screen, for debugging.
  167. For example, to display game.armymen call armyboard as follows:
  168.  
  169.   armyboard(g);
  170.   where g is a game structure pointer.
  171.  
  172. -armyinfo
  173. This procedure prints the game.army structure on the screen, for debugging.
  174. For example, to display game.army call armyinfo as follows:
  175.  
  176.   armyinfo(g);
  177.   where g is a game structure pointer.
  178.  
  179. linkinfo
  180. This procedure prints the game.armylnk array on the screen, for debugging.
  181. For example, to display game.armylnk call linkinfo as follows:
  182.  
  183.   linkinfo(g);
  184.   where g is a game structure pointer.
  185.  
  186. -pictinfo
  187. This procedure prints the game.cpict and game.opict arrays on the screen
  188. in hex, for debugging.  For example, to display game.cpict and
  189. game.opict call pictinfo as follows:
  190.  
  191.   pictinfo(g);
  192.   where g is a game structure pointer.
  193.  
  194. -neighborinfo
  195. This procedure prints the game.neibrd array on the screen in hex, for
  196. debugging.  For example, to display game.neibrd call neighborinfo as
  197. follows:
  198.  
  199.   neighborinfo(g);
  200.   where g is a game structure pointer.
  201. ________________________________________________________________________
  202.  
  203. These Go Programs use one main data structure to represent a game of Go,
  204. as follows:
  205.  
  206. game - This structure contains some basic structures for the analysis of
  207. a single board position.
  208.  
  209. The Game structure contains the following variables, arrays, and
  210. structures:
  211.  
  212. who - This variable represents the color of the player making the
  213. current move, and is set to White for one player, and Black for the
  214. other player.  This variable must be set before a call to the addastone
  215. procedure, because the addastone procedure uses this variable to set the
  216. board array value (stone color).
  217.  
  218. avail - This variable is the next available army number in a linked list
  219. of army numbers. Do not change this variable.
  220.  
  221. maxstone - This variable indicates the 1-dimensional size of the game
  222. board being used.  It is computed by the initialize procedure.  Do not
  223. change this variable.
  224.  
  225. width - This variable indicates the width of the game board.  The
  226. initialize procedure sets this variable to the maximum column number.
  227. Do not change this variable.
  228.  
  229. movecount - This variable indicates the number of stones played in the
  230. game structure.  This variable is cleared by the initialize procedure,
  231. incremented by calls to the addastone procedure, and decremented by
  232. calls to the removeastone and capture procedures. Do not change this
  233. variable.
  234.  
  235. movestatus - This structure contains ko information and capture
  236. information based on the last stone played on the board.  This structure
  237. should be pushed on the stack during tree searches, because it is used
  238. to remove a play and restore the previous game position.  Do not change
  239. the variables in this structure.
  240.  
  241. The ko position (movestatus.kospot) is set by the capture procedure to
  242. the 1-dimensional position of a 1-man army that was just captured.  If
  243. no army was captured by the last move then this variable is set to -1.
  244. Also if the size of the captured army is greater than one then this
  245. variable is set to -1.  The addastone procedure sets this variable to
  246. -1, but the addastone procedure calls the capture procedure if a capture
  247. is made by a move.
  248.  
  249. The capture information (movestatus.captures) is set by the addastone
  250. procedure to reflect which of the four possible armies surrounding the
  251. new stone was captured.  This variable type (movestatus.captures) is bit
  252. encoded, where the least significant 4 bits determine which direction an
  253. army was captured in (so that the army can be restored if the capturing
  254. stone is removed).
  255.  
  256. debug - This BITSET variable represents various debug states.  Bits 0-5
  257. are used in these programs, and bits 6-15 are available for any use.
  258.  
  259. board - This 1-dimensional array contains the position of black and
  260. white stones on the Go Board.  One player's stones are represented by a
  261. value of White, and opponent stones are represented by a value of Black.
  262. Do not change this array.
  263.  
  264. rowbrd - This 1-dimensional array corresponds exactly to the board array
  265. above and indicates the 2-dimensional row number of each position.  Do
  266. not change this array.
  267.  
  268. colbrd - This 1-dimensional array corresponds exactly to the board array
  269. above and indicates the 2-dimensional column number of each position.
  270. Do not change this array.
  271.  
  272. armymen - This 1-dimensional array corresponds exactly to the Board
  273. structure (above). Each board position in this array contains the army
  274. number of the army that occupies this position.  The army number is used
  275. to access information about the army.
  276.  
  277. armylnk - This 1-dimensional array corresponds exactly to the Board
  278. structure (above). Each position in this array contains the number of
  279. the next man in the army.  This array is used for processing every man
  280. in an army, which occurs when an army is being built, when an army is
  281. captured, and when army neighbors need to be counted.
  282.  
  283. whitepats - This 1-dimensional array corresponds exactly to the Board
  284. structure (above). Each position in this array contains a binary
  285. representation of the white stones in a 5 by 5 diamond shape around the
  286. position.  This binary picture can be used to test for a specific
  287. geometic arrangement of the white player's stones around a given
  288. position.  See the diagram below.
  289.  
  290. blackpats - This 1-dimensional array corresponds exactly to the Board
  291. structure (above). Each position in this array contains a binary
  292. representation of the black stones in a 5 by 5 diamond shape around the
  293. position.  This binary picture can be used to test for a specific
  294. geometic arrangement of the black player's stones around a given
  295. position.  See the diagram below.
  296.  
  297. Whitepats and blackpats (above) contain 32 bit values that represent
  298. stone patterns in a 5 by 5 diamond shape, centered around a given board
  299. position (S).  Only 29 bits are actually used, 25 bits for a 5 by 5
  300. square and 4 bits at the center of each outside edge.  The area covered
  301. and bits represented are as follows:
  302.  
  303.     Shape              Bit numbers
  304.  
  305.       *                    28
  306.   * * * * *           5  4  3  2  1
  307.   * * * * *          10  9  8  7  6
  308. * * * S * * *     27 15 14 13 12 11 26
  309.   * * * * *          20 19 18 17 16
  310.   * * * * *          25 24 23 22 21
  311.       *                    29
  312.  
  313. neibrd - This 1-dimensional array corresponds exactly to the Board
  314. structure (above).  The purpose of this array is to test a 1-dimensional
  315. position and determine if the position is on one edge or corner of the
  316. board.  This array can also be used to test for a position on row 1, 2,
  317. 3, or 4 from any side of the board.
  318.  
  319. army - This structure is indexed by army number, and contains
  320. information about each army such as size, color, first (first army man's
  321. board position), last (last army man's board position), fp (forward
  322. pointer to the next army), bp (backward pointer to the previous army),
  323. lib (liberties), friend (number of bordering friendly stones), enemy
  324. (number of bordering enemy stones), armies (number of neighboring
  325. non-blank armies -- not implemented yet), and rollcall (scratchpad
  326. variable).  For blank armies the number of liberties is not used, the
  327. number of friendly stones is the number of neighboring white stones, and
  328. the number of enemy stones is the number of neighboring black stones.
  329. For non-blank armies the number of friendly stones is not used.
  330. ________________________________________________________________________
  331.  
  332. The following additional data structures are used by these programs and
  333. also made available for convenience, as follows:
  334.  
  335. neighbors - This structure contains the output of the getneighbors
  336. procedure:  the number and position of non-blank neighbors to a
  337. specified 1-dimensional position, sorted by army number (which makes it
  338. easier to tell if different neighbors are in the same army).
  339.  
  340. neighborcount - This array is used with the game.neibrd array to quickly
  341. determine how many valid neighboring positions there are to a given
  342. stone position.  This array, neighborcount[0..15], merely translates a
  343. binary number from 0 to 15 into the number of bits that are set in that
  344. binary number.
  345.  
  346. mstatus - This structure contains ko information and capture information
  347. based on the last stone played on the board.
  348.  
  349. The ko position (movestatus.kospot) is set by the capture procedure to
  350. the 1-dimensional position of a 1-man army that was just captured.  If
  351. no army was captured by the last move then this variable is set to -1.
  352. Also if the size of the captured army is greater than one then this
  353. variable is set to -1.  The addastone procedure sets this variable to
  354. -1, but the addastone procedure calls the capture procedure if a capture
  355. is made by a move.
  356.  
  357. The capture information (movestatus.captures) is set by the addastone
  358. procedure to reflect which of the four possible armies surrounding the
  359. new stone was captured.  This variable is bit encoded.
  360. _________________________________________________________________________
  361.  
  362. To use all of the above utility programs and data structures the
  363. following C code is necessary:
  364.  
  365. #include <goprocs.h>
  366. #include <gomoves.h>
  367.  
  368. The following C code creates/allocates a game structure called g at
  369. compile time (this is the responsibility of the user):
  370.  
  371.   game g;
  372.  
  373. Black, White, and Blank are C parameters that define the only valid
  374. states of a board position.  Black and White define the only valid
  375. stone colors and player designations.  The following C code changes
  376. the designated player in the game structure pointed to by g:
  377.  
  378.   g->who = otherside[g->who];
  379.  
  380. The following C code will walk through all armies (black,white, and blank),
  381. given a game structure pointer (g):
  382.  
  383.   int armynumber;
  384.   armynumber = mygame.army[mygame.avail].bp; /* back pointer is first army */
  385.   while (armynumber > 0) {
  386.     if (mygame.army[armynumber].size > 0) {
  387.       (* code to process each army goes here *)
  388.     }
  389.     armynumber = mygame.army[armynumber].bp;
  390.   }
  391.  
  392. The following C code will walk through an army, given a game structure
  393. pointer (g) and the position of any stone in the army (s):
  394.  
  395.   int stone;
  396.   stone = g->army[g->armymen[s]].first; /* first man in army */
  397.   while (stone >= 0) {
  398.     (* code to process each army man goes here *)
  399.     stone = g->armylnk[stone]; /* next man in army */
  400.   }
  401.  
  402. The following C code will obtain the positions of the neighbors to a
  403. given stone position (s), given a game structure pointer (g) and visit
  404. each of the non-blank neighboring positions in order of their army number:
  405.  
  406.   neighbors nabor; int n;
  407.   getneighbors(g,&nabor,s);     /* get the neighbors */
  408.   for (n = 0; n < nabor.neis; n++) {  /* go through neighbors */
  409.     if (g->board[s] != Blank) {
  410.       (* code to process non-blank neighbors to stone s goes here *)
  411.   } }
  412. ________________________________end of document___________________________
  413.  
  414. /* File goprocs.h
  415.    Developer:  James R. Logan Jr. (BYU), Advisor:  Dr. Lynn H. Beus (BYU)
  416.    email address:  loganj@byuvax.bitnet
  417.    (801) 378-3617
  418.  
  419.    Structures required by the go program utilities.
  420.    This code is not machine dependent.
  421. */
  422.  
  423. #define firstelement 0
  424. #define brdsize 19
  425. #define maxstones 362
  426. #define maxarmies 362
  427. #define White 0
  428. #define Black 1
  429. #define Blank 2
  430.  
  431. typedef struct {
  432.   int
  433.   color,   /* army color */
  434.   size,    /* army size  */
  435.   first,   /* first armyman's position */
  436.   last,    /* last armyman's position */
  437.   fp,      /* forward pointer to next army */
  438.   bp,      /* backward pointer to last army */
  439.   lib,     /* number of liberties, for nonblank armies only */
  440.   friend,  /* number of neighboring White stones, for blank armies only */
  441.   enemy,   /* number of enemy stones for nonblank armies, or Black stones */
  442.   armies,  /* number of neighboring armies */
  443.   rollcall;/* scratch pad variable */
  444. } armystruct;
  445.  
  446. typedef struct {
  447.   int kospot;    /* valid ko position, or -1, result of last move */
  448.   long captures; /* bit 1 is capture on the west (left)
  449.                     bit 2 is capture on the east (right)
  450.                     bit 3 is capture on the south (down)
  451.                     bit 4 is capture on the north (up) */
  452. } mstatus;
  453.  
  454. typedef struct {
  455.   int
  456.   who,      /* White for computer's level, Black for opponent */
  457.   avail,    /* next available army number */
  458.   maxstone, /* size of 1-dimensional board */
  459.   width,    /* width of 1-dimensional board */
  460.   movecount,/* number of stones played on the board */
  461.   deadwhite,/* number of captured white stones */
  462.   deadblack,/* number of captured black stones */
  463.   debug;    /* debug flags */
  464.   char
  465.   board[maxstones],    /* computer = White, opponent = Black */
  466.   rowbrd[maxstones],   /* translates 1-dimension row to 2-dimension */
  467.   colbrd[maxstones],   /* translates 1-dimension col to 2-dimension */
  468.   whitecount[maxstones],/* count of white stones in whitepats */
  469.   blackcount[maxstones];/* count of black stones in blackpats */
  470.   int
  471.   armymen[maxstones],  /* men of same army have same num */
  472.   armylnk[maxstones];  /* link to next army member */
  473.   long
  474.   whitepats[maxstones],/* bit pattern of white stones in 5 by 5 square */
  475.   blackpats[maxstones],/* bit pattern of black stones in 5 by 5 square */
  476.   neibrd[maxstones];   /* n by n bit encoded valid neighbors array */
  477.   mstatus movestatus;  /* ko position and capture info */
  478.   armystruct army[maxarmies];
  479. } game;
  480.  
  481. typedef struct {
  482.   int
  483.   neis,
  484.   stone[4],
  485.   direction[4];
  486.         /* bit 1 is neighbor on the west (left)
  487.            bit 2 is capture on the east (right)
  488.            bit 3 is capture on the south (down)
  489.            bit 4 is capture on the north (up) */
  490. } neighbors;
  491. /* File gomoves.h
  492.    Developer:  James R. Logan Jr. (BYU), Advisor:  Dr. Lynn H. Beus (BYU)
  493.    email address:  loganj@byuvax.bitnet
  494.    (801) 378-3617
  495. */
  496.  
  497. #define maxsons 5  /* maximum depth of alpha-beta tree */
  498. #define maxlevs 5  /* must be odd, maximizing level for best odds? */
  499.  
  500. typedef struct {
  501.   int s,pv;       /* alpha beta stone position and board value */
  502. } nodestruct;
  503.  
  504. typedef struct {  /* children of node in alpha-beta tree */
  505.   int nodepnt,nodecnt;
  506.   mstatus status; /* board status resulting from stone */
  507.   nodestruct nodes[maxsons];
  508. } sons;
  509. /* File gomain.c
  510.    Developer:  James R. Logan Jr. (BYU), Advisor:  Dr. Lynn H. Beus (BYU)
  511.    email address:  loganj@byuvax.bitnet
  512.    (801) 378-3617
  513.  
  514.    This procedure provides the interface between the Mac and the operator.
  515.    This code is machine dependent.
  516. */
  517.  
  518. #include <qd.h>
  519. #include <win.h>
  520. #include <menu.h>
  521. #include <event.h>
  522. #include <te.h>
  523. #include <stdio.h>
  524. #include <goprocs.h>
  525.  
  526. #define lastmenu 5
  527. #define applemenu 1
  528. #define filemenu 256
  529. #define gamemenu 257
  530. #define playermenu 258
  531. #define displaymenu 259
  532.  
  533. FILE *fp,*gp;
  534. windowptr whichwindow;
  535. menuhandle mymenus[lastmenu+1];
  536. boolean doneflag,temp;
  537. eventrecord myevent;
  538. long blinktime;
  539. int code,refnum;
  540. int themenu,theitem,
  541.   activeplayer,blinkstate,blinkcolor,blinkstone,drawnumber,
  542.   lookahead,play,playfile,stonestate;
  543.  
  544. game mygame;
  545.  
  546. extern initgame();
  547. extern int addastone(),moves();
  548. extern char coltable[19];
  549. extern int otherside[2];
  550. extern windowptr mewindow,mywindow;
  551.  
  552. setupmenus() {
  553. int i;
  554. char appletitle[2];
  555.   initmenus();
  556.   appletitle[0] = applemark; appletitle[1] = 0;
  557.   mymenus[1] = newmenu(applemenu, appletitle);
  558.   addresmenu(mymenus[1], "DRVR");
  559.   mymenus[2] = newmenu(filemenu, "Directives");
  560.   appendmenu(mymenus[2], "Pass;Change Sides;Log to File;Play Log File;Quit");
  561.   mymenus[3] = newmenu(gamemenu, "Game");
  562.   appendmenu(mymenus[3], "Initialize;Begin or Resume;Pause");
  563.   mymenus[4] = newmenu(playermenu, "Players");
  564.   appendmenu(mymenus[4], "Computer Vs Computer;Computer Vs Human;Human Vs Human"
  565. );
  566.   mymenus[5] = newmenu(displaymenu, "Display");
  567.   appendmenu(mymenus[5],
  568.     "Look Ahead Moves;Stone Numbers;Procedures;Stones;Stone Armies;Stone Links;S
  569. tone Patterns;Position Values;Army Info");
  570.   for (i=1; i<=lastmenu; i++) insertmenu(mymenus[i], 0);
  571.   drawmenubar();
  572.   drawnumber = 1;
  573.   checkitem(mymenus[5],2,1);
  574.   lookahead = 0;
  575.   activeplayer = 1;
  576.   checkitem(mymenus[4],activeplayer,1);
  577. }
  578.  
  579. docommand(themenu, theitem) int themenu, theitem; {
  580. char name[256];
  581. int i;
  582.   switch (themenu) {
  583.   case applemenu:
  584.     getitem(mymenus[1], theitem, name);
  585.     refnum = opendeskacc(name);
  586.     break;
  587.   case filemenu:
  588.     switch (theitem) {
  589.     case 1: /* pass */
  590.       if (play == 0) {
  591.         if ((activeplayer == 2) || (activeplayer == 3)) {
  592.           mygame.who = otherside[mygame.who];
  593.           if (activeplayer == 2) {
  594.             play = 1;
  595.           } else {
  596.             if (mygame.who == White) printf(" White's turn ...\n");
  597.             else printf(" Black's turn ...\n");
  598.           }
  599.         }
  600.       }
  601.       break;
  602.     case 2: /* change sides */
  603.       mygame.who = otherside[mygame.who];
  604.       if (mygame.who == White) printf(" White's turn ...\n");
  605.       else printf(" Black's turn ...\n");
  606.       break;
  607.     case 3:
  608.       if (fp == NULL) {
  609.         checkitem(mymenus[2],3,1);
  610.         createfile();
  611.       } else {
  612.         checkitem(mymenus[2],3,0);
  613.         fclose(fp); fp = NULL;
  614.       }
  615.       break;
  616.     case 4:
  617.       if (gp == 0) {
  618.         if (activeplayer == 2) blinkoff();
  619.         replay();
  620.         if (gp != 0) {
  621.           checkitem(mymenus[2],4,1);
  622.           play = 1;
  623.           playfile = 1;
  624.         }
  625.       } else {
  626.         checkitem(mymenus[2],4,0);
  627.         if (gp != NULL) fclose(gp); gp = NULL;
  628.         play = 0;
  629.         playfile = 0;
  630.         mygame.who = otherside[mygame.who];
  631.         if (mygame.who == White) printf(" White's turn ...\n");
  632.         else printf(" Black's turn ...\n");
  633.         if (activeplayer == 2) blinkon();
  634.       }
  635.       break;
  636.     case 5:
  637.       if (fp != NULL) { fclose(fp); fp = NULL; }
  638.       if (gp != NULL) { fclose(gp); gp = NULL; }
  639.       doneflag = 1;
  640.       break;
  641.     }
  642.     break;
  643.   case gamemenu:
  644.     switch (theitem) {
  645.     case  1:
  646.       play = 0;
  647.       if (playfile != 0) {
  648.         checkitem(mymenus[2],4,0);
  649.         if (gp != NULL) fclose(gp); gp = NULL;
  650.         playfile = 0;
  651.       }
  652.       blinkoff();
  653.       boardsize(&mygame);
  654.       if (activeplayer == 1) {
  655.         if (mygame.who == White) printf(" White's turn ...\n");
  656.         else printf(" Black's turn ...\n");
  657.       } else if (activeplayer == 2) {
  658.         blinkon();
  659.         printf(" Your turn ...\n");
  660.       } else if (activeplayer == 3) printf(" Black's turn ...\n");
  661.       break;
  662.     case  2:
  663.       if ((playfile != 0) || (activeplayer == 1)) play = 1;
  664.       else if (activeplayer == 2) printf(" Your turn ...\n");
  665.       else if (mygame.who == White) printf(" White's turn ...\n");
  666.       else printf(" Black's turn ...\n");
  667.       break;
  668.     case  3: play = 0; break;
  669.     }
  670.     break;
  671.   case playermenu:
  672.     switch (theitem) {
  673.     case  1:
  674.       if (activeplayer == 2) blinkoff();
  675.       checkitem(mymenus[4],activeplayer,0);
  676.       activeplayer = 1;
  677.       checkitem(mymenus[4],activeplayer,1);
  678.       break;
  679.     case  2:
  680.       play = 0;
  681.       blinkstone = -1;
  682.       checkitem(mymenus[4],activeplayer,0);
  683.       activeplayer = 2;
  684.       checkitem(mymenus[4],activeplayer,1);
  685.       break;
  686.     case  3:
  687.       play = 0;
  688.       if (activeplayer == 2) blinkoff();
  689.       checkitem(mymenus[4],activeplayer,0);
  690.       activeplayer = 3;
  691.       checkitem(mymenus[4],activeplayer,1);
  692.       break;
  693.     }
  694.     break;
  695.   case displaymenu:
  696.     switch (theitem) {
  697.     case  1:
  698.       lookahead = 1 - lookahead;
  699.       checkitem(mymenus[5],1,lookahead);
  700.       break;
  701.     case  2:
  702.       drawnumber = 1 - drawnumber;
  703.       checkitem(mymenus[5],2,drawnumber);
  704.       break;
  705.     case  3:
  706.       if ((mygame.debug & 1) == 0) {
  707.         mygame.debug |= 1;
  708.         checkitem(mymenus[5],3,1);
  709.       } else {
  710.         mygame.debug &= ~1;
  711.         checkitem(mymenus[5],3,0);
  712.       }
  713.       break;
  714.     case  4: moveboard(&mygame); break;
  715.     case  5: armyboard(&mygame); break;
  716.     case  6: linkinfo(&mygame); break;
  717.     case  7: pictinfo(&mygame); break;
  718.     case  8: valueboard(&mygame); break;
  719.     case  9: armyinfo(&mygame); break;
  720.   } }
  721.   hilitemenu(0);
  722. }
  723.  
  724. stoneon() {
  725.   if ((stonestate == 0) && (blinkstone >= 0))
  726.     drawstone(&mygame,blinkstone,blinkcolor);
  727.   stonestate = 1;
  728. }
  729.  
  730. stoneoff() {
  731.   if ((stonestate != 0) && (blinkstone >= 0))
  732.     undrawstone(&mygame,blinkstone);
  733.   stonestate = 0;
  734. }
  735.  
  736. blinkon() {
  737. /* Turn on the blink'n blinker if no look ahead in progress. */
  738.   if (lookahead == 0) {
  739.     blinkstate = 1;
  740.     blinktime = tickcount();
  741. } }
  742.  
  743. blinkoff() { blinkstate = 0; stoneon(); }
  744.  
  745. blink() {
  746. /* This procedure does the actual blinking of the last stone played */
  747. long now;
  748.   if (blinkstate != 0) {
  749.     now = tickcount();
  750.     if (now > blinktime + 20) {
  751.       if (stonestate != 0) stoneoff(); else stoneon();
  752.       blinktime = now;
  753. } } }
  754.  
  755. main() {
  756. /* This procedure provides the interface between the Mac and the
  757.    operator */
  758. int i,s;
  759. extern struct qdvar { char dummy[202]; grafptr qdtheport;} qdvars;
  760. #define theport (qdvars.qdtheport)
  761.  
  762.   openresfile("clock");
  763.   initgraf(&theport);
  764.   initfonts();
  765.   flushevents(everyevent, 0);
  766.   initwindows();
  767.   setupmenus();
  768.   initdialogs(0L);
  769.   initcursor();
  770.  
  771.   doneflag = 0; play = 0; playfile = 0; blinkstone = -1;
  772.   mygame.debug = 0;
  773.   mygame.width = 19;
  774.   fp = NULL; gp = NULL;
  775.   initgame(&mygame);
  776.  
  777.   do {
  778.     systemtask();
  779.     blink();
  780.     temp = getnextevent(everyevent, &myevent);
  781.     switch (myevent.what) {
  782.     case mousedown:
  783.       code = findwindow(&myevent.where, &whichwindow);
  784.       switch (code) {
  785.       case inmenubar:
  786.         docommand(menuselect(&myevent.where)); break;
  787.       case insyswindow:
  788.         systemclick(&myevent, whichwindow); break;
  789.       case indrag:
  790.         break;
  791.       case ingrow:
  792.       case incontent:
  793.         if ((play == 0) &&
  794.           ((playfile != 0) || (activeplayer == 2) || (activeplayer == 3))) {
  795.           if (whichwindow == mywindow) {
  796.             blinkoff();
  797.             setport(mywindow);
  798.             globaltolocal(&myevent.where);
  799.             setport(mewindow);
  800. /* place a stone on the board */
  801.             s = (mygame.width - 1 - ((myevent.where.a.v - 2) / 16));
  802.             if (s < 0) s = 0;
  803.             if (s >= mygame.width) s = mygame.width - 1;
  804.             s = s * mygame.width;
  805.             i = (myevent.where.a.h - 2) / 16;
  806.             if (i < 0) i = 0;
  807.             if (i >= mygame.width) i = mygame.width - 1;
  808.             s = s + i;
  809.             s = addastone(&mygame,s);
  810.             if (s >= 0) {
  811.               if (mygame.who == White) printf(" White to %c,%d\n",
  812.                 coltable[mygame.colbrd[s]],mygame.rowbrd[s]);
  813.               else printf(" Black to %c,%d\n",
  814.                 coltable[mygame.colbrd[s]],mygame.rowbrd[s]);
  815.               if (activeplayer == 2) play = 1;
  816.               mygame.who = otherside[mygame.who];
  817.               if (mygame.who == White) printf(" White's turn ...\n");
  818.               else printf(" Black's turn ...\n");
  819.             } else {
  820.               if (mygame.who == White) printf(" Still White's turn ...\n");
  821.               else printf(" Still Black's turn ...\n");
  822.             }
  823.           }
  824.         }
  825.         break;
  826. /* goaway box is on the modify window only, so save the changes to the
  827.    letter being modified and take down the modify window */
  828.       case ingoaway: break;
  829.       }
  830.       break;
  831.     case mouseup: break;
  832.     case keydown:
  833.     case autokey:
  834. /*      draw_text((char) (255 & myevent.message)); */
  835.       break;
  836.     case activateevt: break;
  837.     case updateevt:
  838. /*      setport(mywindow);
  839.       beginupdate(mywindow);
  840.       endupdate(mywindow);*/
  841.       break;
  842.     }
  843.     if (doneflag == 0) {
  844.       if (gp == NULL) {
  845.         if (playfile != 0) {
  846.           playfile = 0;
  847.           checkitem(mymenus[2],4,0);
  848.         }
  849.         if (((activeplayer == 1) || (activeplayer == 2)) && (play != 0)) {
  850.           blinkcolor = mygame.who;
  851.           blinkstone = moves(&mygame);
  852.           if (mygame.who == White) printf(" White's turn ...\n");
  853.           else printf(" Black's turn ...\n");
  854.           if (activeplayer == 2) {
  855.             play = 0;
  856.             blinkon();
  857.         } }
  858.       } else if (play != 0) replay();
  859.     }
  860.   } while (doneflag == 0);
  861. }
  862. /* File go.c
  863.    Developer:  James R. Logan Jr. (BYU), Advisor:  Dr. Lynn H. Beus (BYU)
  864.    email address:  loganj@byuvax.bitnet
  865.    (801) 378-3617
  866.  
  867.    These routines and the routines in gomoves.c determine the strategy of
  868.    the go program.  This code is not machine dependent.
  869. */
  870.  
  871. #include <qd.h>
  872. #include <pack.h>
  873. #include <win.h>
  874. #include <dialog.h>
  875. #include <stdio.h>
  876. #include <goprocs.h>
  877. #include <gomoves.h>
  878.  
  879. extern char coltable[19];
  880. extern int activeplayer,blinkstone,looking,play,otherside[2];
  881. extern game mygame;
  882. extern int addastone();
  883. extern initialize(),removeastone(),capture(),uncapture(),
  884.   getneighbors(),allarmies(),linkarmies(),buildarmies(),
  885.   armymerge(),topicture(),frompicture(),moveboard(),
  886.   armyboard(),linkinfo(),armyinfo(),pictinfo(),neighborinfo();
  887.  
  888. overlay "gamestuff"
  889.  
  890. #define allyweight 4
  891. #define blankweight 1
  892. #define enemyweight 2
  893. #define libertiesweight 1
  894. #define squareweight 4
  895.  
  896. #define edgevalue 1
  897. #define openvalue 2  /* ordinary unoccupied square, not on edge */
  898. #define cornervalue 10
  899. #define connectvalue 3
  900. #define midneivalue 6
  901. #define midrowvalue 8
  902. #define row3value 4
  903. #define row5value 3
  904.  
  905. pattern greypat = {0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92};
  906.  
  907. rect screenrect;
  908. windowrecord merecord,myrecord,drecord;
  909. windowptr mewindow,mywindow = {0L},dummywindow;
  910.  
  911. sons root[maxlevs];
  912.  
  913. mstatus status;
  914.  
  915. int
  916.   init[maxstones],value[maxstones],  /* initial position values */
  917.   color,stone,nextmove,passcount,
  918.   searchdepth = {1},searchwidth = {1},work;
  919.  
  920. initgame(g) game *g; {
  921. int i,j,brdsze;
  922. char dummyscreen[20000];
  923.   if (mywindow == 0L) {
  924. /* calculate the size of the window for the game board, and display */
  925.     brdsze = 16 + 8 * (g->width - 1);
  926.     setrect(&screenrect,351-brdsze,181-brdsze,351+brdsze,181+brdsze);
  927.     mywindow = newwindow(&myrecord, &screenrect, "", 1, 2,
  928.       (long)-1, 0, (long)0);
  929.     dummywindow = newwindow(&drecord, &screenrect, "", 0, 2,
  930.       (long)-1, 1, (long)0);
  931.     drecord.port.portbits.baseaddr = &dummyscreen;
  932.     setrect(&screenrect, 0, 21, 188, 340);
  933.     mewindow = newwindow(&merecord, &screenrect, "", 1, 2,
  934.       (long)-1, 0, (long)0);
  935.   } else {
  936.     disposewindow(mywindow);
  937.     brdsze = 16 + 8 * (g->width - 1);
  938.     setrect(&screenrect,351-brdsze,181-brdsze,351+brdsze,181+brdsze);
  939.     mywindow = newwindow(&myrecord, &screenrect, "Go", 1, 3,
  940.                      (long)-1, 0, (long)0);
  941.   }
  942.   if ((g->debug & 1) != 0) { printf("Initgame: \n"); }
  943.   setport(mywindow);
  944.   textmode(srcxor);
  945.   backpat(&greypat);
  946.   setorigin(-12,0);
  947.   brdsze = 4 + 16 * g->width;
  948.   setrect(&screenrect,0,0,400,brdsze);
  949.   eraserect(&screenrect);
  950.   setport(mewindow);
  951.   textsize(9);
  952.   initialize(g);  /* initialize the game structure for the go procs */
  953.   g->who = Black; /* first move is black's */
  954.   passcount = 0;  /* number of consecutive passes in the game */
  955.   blinkstone = -1; /* indicate no stone to blink yet */
  956. /* set the initial value of each position, first the whole board */
  957.   for (i = firstelement; i < g->maxstone; i++) { init[i] = openvalue; }
  958. /* set the initial value of the edges of the board */
  959.   j = firstelement;
  960.   for (i = firstelement; i < g->width; i++) {
  961.     init[j] = edgevalue; init[j+g->width-1] = edgevalue;
  962.     init[i] = edgevalue; init[g->maxstone-g->width+i] = edgevalue;
  963.     j = j + g->width;
  964.   }
  965. /* Set the initial value for row 3 all around the board */
  966.   if (g->width >= 7) {
  967.     j = 2*g->width+3;
  968.     for (i = firstelement; i < g->width-6; i++) {
  969.       init[j] = row3value; init[g->maxstone-j-1] = row3value;
  970.       j = j + 1; }
  971.     j = 3*g->width+2;
  972.     for (i = firstelement; i < g->width-6; i++) {
  973.       init[j] = row3value; init[j+g->width-5] = row3value;
  974.       j = j + g->width; }
  975.   }
  976. /* Set the value for the middle of row 3 around the edge of the board */
  977.   if (g->width >= 9) {
  978.     j = (2*g->width)+(g->width/2);
  979.     init[j] = midrowvalue;
  980.     init[g->maxstone-1-j] = midrowvalue;
  981.     j = ((g->width / 2) * g->width) + 2;
  982.     init[j] = midrowvalue;
  983.     init[g->maxstone-1-j] = midrowvalue;
  984.   }
  985. /* Set the initial value for row 5 all around the board, but not in 5 corner */
  986.   if (g->width >= 11) {
  987.     j = 4*g->width+5;
  988.     for (i = firstelement; i < g->width-10; i++) {
  989.       init[j] = row5value; init[g->maxstone-j-1] = row5value;
  990.       j = j + 1; }
  991.     j = 5*g->width+4;
  992.     for (i = firstelement; i < g->width-10; i++) {
  993.       init[j] = row5value; init[j+g->width-9] = row5value;
  994.       j = j + g->width; }
  995.   }
  996. /* Set the initial value for 3 rows in from each corner */
  997.   if (g->width >= 5) {
  998.     init[2*g->width+2] = cornervalue;
  999.     init[3*g->width-3] = cornervalue;
  1000.     init[g->maxstone-2*g->width-3] = cornervalue;
  1001.     init[g->maxstone-3*g->width+2] = cornervalue;
  1002.   }
  1003. /* Set the initial value for 2 jump neighbors from mid row 3 */
  1004.   if (g->width == 19) {
  1005.     init[44] = midneivalue; init[50] = midneivalue;
  1006.     init[116] = midneivalue; init[130] = midneivalue;
  1007.     init[230] = midneivalue; init[244] = midneivalue;
  1008.     init[310] = midneivalue; init[316] = midneivalue;
  1009.   }
  1010.   init[0] = 0; init[g->width-1] = 0;
  1011.   init[g->maxstone-g->width] = 0; init[g->maxstone-1] = 0;
  1012.   if ((g->debug & 1) != 0) { printf("Initgame end.\n"); }
  1013. }
  1014.  
  1015. int moves(g) game *g; {
  1016. /* This procedure receives control when the computer needs to make a move,
  1017.    and returns the 1-dimensional position selected by the computer.
  1018.    If g->who == White a move is computed for the computer, else a move is
  1019.    computed for the opponent.  A legal move is always added to the board */
  1020. int s; sons *sonsp;
  1021.   alphabeta(); /* look ahead for the best move */
  1022.   if (nextmove >= 0) {
  1023.     s = addastone(g,nextmove); /* add this move to the game board */
  1024.     if (s >= 0) {
  1025.       if (g->who == White) printf(" White to %c,%d\n",
  1026.           coltable[g->colbrd[s]],g->rowbrd[s]);
  1027.       else printf(" Black to %c,%d\n",
  1028.           coltable[g->colbrd[s]],g->rowbrd[s]);
  1029.     }
  1030.     passcount = 0;
  1031.   } else {
  1032.     s = -1;
  1033.     if (activeplayer == 1) passcount = passcount + 1;
  1034.     if (g->who == White) printf(" White passes\n");
  1035.     else printf(" Black passes\n");
  1036.   }
  1037.   g->who = otherside[g->who];
  1038.   if ((activeplayer == 1) && (passcount >= 2)) {
  1039.     play = 0;
  1040.     printf(" Play stopped after two passes!\n");
  1041.   }
  1042.   return s;
  1043. }
  1044.  
  1045. alphabeta() {
  1046. /* This procedure is the top level of the alpha-beta cutoff look ahead
  1047.    procedure.  Alpha and beta are initialized here. */
  1048. int a,b,dummy; int sonsp;
  1049.   looking = 1;   /* indicate look ahead in progress */
  1050.   nextmove = -1; /* default next move is a pass */
  1051.   sonsp = 0;     /* point to root of tree */
  1052.   a = -9999; b = 9999; /* alpha-beta initialization */
  1053.   dummy = abcontrol (sonsp,a,b,mygame.who);
  1054.   looking = 0;
  1055. }
  1056.  
  1057. int abcontrol (tr,a,b,wh) int tr,a,b,wh; {
  1058. /* This procedure performs the actual alpha-beta search.  Inputs are
  1059.    tree level, Alpha, Beta, and who's move it is.  The present
  1060.    implementation does not dynamically allocate the tree. */
  1061. int ta,tb,ev,junk,r,c,v;
  1062.   if (tr >= searchdepth) {   /* last level of tree? */
  1063.     ev = eval(searchdepth);    /* yes, compute the position value */
  1064.     if ((mygame.debug & 0xF) != 0) {
  1065.       printf("\nabcontrol - level, node, value: %d %d %d\n",
  1066.         searchdepth-1,root[searchdepth-1].nodepnt-1,ev);
  1067.     }
  1068.     return (ev);        /* return the best position value */
  1069.   } else if (wh == mygame.who) {    /* for maximizing level */
  1070.     bestmoves(&mygame,tr);   /* fill in the best moves */
  1071.     while ((root[tr].nodepnt < root[tr].nodecnt) && (a < b)) {
  1072.       junk = addastone(&mygame,root[tr].nodes[root[tr].nodepnt].s);
  1073.       root[tr].status = mygame.movestatus;
  1074.       root[tr].nodepnt = root[tr].nodepnt + 1;
  1075.       ta = abcontrol (tr + 1, a, b, otherside[wh]);
  1076.       if (ta > a) {
  1077.         a = ta; /* new alpha value */
  1078.         if (tr <= 0) { nextmove = root[tr].nodes[root[tr].nodepnt-1].s; }
  1079.       }
  1080.       removeastone(&mygame,root[tr].nodes[root[tr].nodepnt-1].s,root[tr].status)
  1081. ;
  1082.     }
  1083.     return (a);
  1084.   } else {   /* for minimizing level */
  1085.     bestmoves(&mygame,tr);   /* fill in the best moves */
  1086.     while ((root[tr].nodepnt < root[tr].nodecnt) && (a < b)) {
  1087.       mygame.who = wh;                      /* change sides */
  1088.       junk = addastone(&mygame,root[tr].nodes[root[tr].nodepnt].s);
  1089.       root[tr].status = mygame.movestatus;
  1090.       mygame.who = otherside[mygame.who];   /* change sides back */
  1091.       root[tr].nodepnt = root[tr].nodepnt + 1;
  1092.       tb = abcontrol (tr + 1, a, b, otherside[wh]);
  1093.       if (tb < b) { b = tb; } /* new beta value */
  1094.       removeastone(&mygame,root[tr].nodes[root[tr].nodepnt-1].s,root[tr].status)
  1095. ;
  1096.     }
  1097.     return (b);
  1098.   }
  1099. }
  1100.  
  1101. int eval(sonsp) int sonsp; {
  1102. /* This procedure evaluates the worth of look ahead moves during the alpha
  1103.    beta search - not a well defined process.  Need a lot of work here!
  1104.    The game structure fields don't seem to represent enough higher level
  1105.    (human) abstractions to play a good game yet.  The evaluation here
  1106.    is based on the number of armies, eyes, and total number of liberties
  1107.    for both sides.  Variables beginning with an 'a' are ally values, 'e' are
  1108.    enemy values. */
  1109. int n,v,pv,allies,enemies,alibs,elibs,wh,tb;
  1110.   if ((mygame.debug & 1) != 0) { printf("eval: \n"); }
  1111.   pv = 0; allies = 0; enemies = 0; alibs = 0; elibs = 0;
  1112.   wh = 1;
  1113.   for (tb = 0; tb < sonsp; tb++) {    /* traverse the tree */
  1114.     pv = pv + root[tb].nodes[root[tb].nodepnt-1].pv * wh;
  1115.     tb = tb + 1;
  1116.     wh = -wh;     /* switch players at each level of the tree */
  1117.   }
  1118.   n = mygame.army[mygame.avail].bp;   /* visit each army */
  1119.   while (n > 0) {
  1120.     if (mygame.army[n].size > 0) {
  1121.       if (mygame.army[n].color == Blank) {   /* blank army is an eye? */
  1122.         if (mygame.army[n].enemy <= 0) {
  1123.           if (mygame.who == White) allies = allies + 1; /* ally eyes */
  1124.           else enemies = enemies + 1;                   /* enemy eyes */
  1125.         } else if (mygame.army[n].friend <= 0) {
  1126.           if (mygame.who == White) enemies = enemies + 1;/* ally eyes */
  1127.           else allies = allies + 1;                     /* enemy eyes */
  1128.         }
  1129.       } else if (mygame.army[n].color == mygame.who) {
  1130.         alibs = alibs + mygame.army[n].lib;
  1131.       } else {
  1132.         elibs = elibs + mygame.army[n].lib;
  1133.       }
  1134.     }
  1135.     n = mygame.army[n].bp;
  1136.   }
  1137.   v = allies * allyweight - enemies * enemyweight +
  1138.        libertiesweight * alibs - libertiesweight * elibs +
  1139.        pv * squareweight;
  1140.   if ((mygame.debug & 1) != 0) { printf("eval.\n"); }
  1141.   return (v);
  1142. }
  1143.  
  1144. boardsize(g) game *g; {
  1145. /* This procedure handles the game initialization dialog */
  1146. int the_item,item_type,value;
  1147. handle item_handle;
  1148. rect drect,item_box;
  1149. char item_text[64];
  1150. dialogptr mydialog;
  1151.   setrect(&drect,-16,28,440,200);
  1152.   copybits(&mywindow->portbits,&dummywindow->portbits,
  1153.         &drect,&drect,srccopy,(long)0);
  1154.   mydialog = getnewdialog(9507,(long) 0,(long)-1);
  1155.   getditem(mydialog,3,&item_type,&item_handle,&item_box);
  1156.   sprintf(item_text,"%d",g->width);
  1157.   setitext(item_handle,item_text);
  1158.   getditem(mydialog,4,&item_type,&item_handle,&item_box);
  1159.   sprintf(item_text,"%d",searchwidth);
  1160.   setitext(item_handle,item_text);
  1161.   getditem(mydialog,5,&item_type,&item_handle,&item_box);
  1162.   sprintf(item_text,"%d",searchdepth);
  1163.   setitext(item_handle,item_text);
  1164.   do {
  1165.     modaldialog((long) 0,&the_item);
  1166.     if (the_item == 1) {
  1167.       getditem(mydialog,3,&item_type,&item_handle,&item_box);
  1168.       getitext(item_handle,&item_text);
  1169.       sscanf(item_text,"%d",&value);
  1170.       if ((value > 2) && (value < 20)) g->width = value;
  1171.       getditem(mydialog,4,&item_type,&item_handle,&item_box);
  1172.       getitext(item_handle,&item_text);
  1173.       sscanf(item_text,"%d",&value);
  1174.       if ((value > 0) && (value <= maxsons)) searchwidth = value;
  1175.       getditem(mydialog,5,&item_type,&item_handle,&item_box);
  1176.       getitext(item_handle,&item_text);
  1177.       sscanf(item_text,"%d",&value);
  1178.       if ((value > 0) && (value <= maxlevs)) searchdepth = value;
  1179.     }
  1180.   } while ((the_item != 1) && (the_item != 2));
  1181.   closedialog(mydialog);
  1182.   copybits(&dummywindow->portbits,&mywindow->portbits,
  1183.         &drect,&drect,srccopy,(long)0);
  1184.   if (the_item == 1) initgame(g);
  1185. }
  1186.  
  1187. valueboard(g) game *g; {
  1188. int i,s;
  1189.   s = 0;
  1190.   while (s < g->maxstone) {
  1191.     for (i = firstelement; i < g->width; i++) { printf("%3d",value[s]); s = s +
  1192. 1; }
  1193.     printf("\n");
  1194. } }
  1195. /* File gomoves.c
  1196.    Developer:  James R. Logan Jr. (BYU), Advisor:  Dr. Lynn H. Beus (BYU)
  1197.    email address:  loganj@byuvax.bitnet
  1198.    (801) 378-3617
  1199.  
  1200.    This routine determines the best n moves available when a move is
  1201.    being selected by the computer.  This code is not machine dependent.
  1202. */
  1203.  
  1204. #include <goprocs.h>
  1205. #include <gomoves.h>
  1206.  
  1207. #define maxsons 5
  1208. #define maxlevs 5     /* must be odd, maximizing level for best odds */
  1209.  
  1210. #define allyweight 4
  1211. #define blankweight 1
  1212. #define enemyweight 2
  1213. #define libertiesweight 1
  1214. #define squareweight 4
  1215.  
  1216. /* The following 32 bit values represent patterns in a 5 by 5 diamond shape,
  1217.    centered around a given board position (s).  Only 29 bits are actually
  1218.    used, 25 bits for a 5 by 5 square and 4 bits at the center of each
  1219.    outside edge.  The area covered and bits represented are as follows:
  1220.  
  1221.       *                    28
  1222.   * * * * *           5  4  3  2  1
  1223.   * * * * *          10  9  8  7  6
  1224. * * * S * * *     27 15 14 13 12 11 26
  1225.   * * * * *          20 19 18 17 16
  1226.   * * * * *          25 24 23 22 21
  1227.       *                    29
  1228. */
  1229. #define square3 0x739C0L
  1230. #define square5 0x0E8C62EL
  1231. #define diamond5 0x477DC4L
  1232. #define circle7 0x1F100011L
  1233.  
  1234. #define firstmoves 17 /* number of moves before middle game */
  1235.  
  1236. #define attackvalue 14
  1237. #define circle7value 2
  1238. #define edgevalue 1
  1239. #define edgecutvalue 10
  1240. #define edgejoinvalue 16
  1241. #define openvalue 2  /* ordinary unoccupied square, not on edge */
  1242. #define capturevalue 24
  1243. #define cornervalue 10
  1244. #define connectvalue 3
  1245. #define cutvalue 3
  1246. #define hitarivalue 18
  1247. #define invadevalue 20 /* must be 4 less than capture value */
  1248. #define midneivalue 6
  1249.  
  1250. #define midrowvalue 8
  1251. #define protvalue 24
  1252. #define retreatsize 18
  1253. #define row3value 4
  1254. #define row5value 3
  1255. #define square5value 1
  1256. #define runtoedgevalue 12
  1257. #define territoryvalue 4
  1258.  
  1259. extern sons root[maxlevs];
  1260. extern int
  1261.   otherside[2],
  1262.   init[maxstones],value[maxstones],  /* initial position values */
  1263.   searchdepth,searchwidth;
  1264.  
  1265. bestmoves(g,sonsp) game *g; int sonsp; {
  1266. /* This procedure determines the best n moves available using a point
  1267.    scheme with weights for different patterns and situations.  This
  1268.    routine does not explicitly check the validity of each move (bad
  1269.    moves are possible if the weights are not properly set. */
  1270. char *enmcount,*fricount;
  1271. int a1,a2,blankfris,blankenms,frilibs,lastus,lastthem,
  1272.   ha,pa,snapstone,snaplibs,i,n,s,s1,us,them,
  1273.   captsize,protsize,totallibs,hitarisize,hitarisave,neiarms,neienms,node;
  1274. long fripats,enmpats,neipats;
  1275. neighbors nabor,nextnabor;
  1276. /* First initialize all the best moves to pass */
  1277.   if ((g->debug & 1) != 0) { printf("bestmoves: \n"); }
  1278.   root[sonsp].nodecnt = 0; root[sonsp].nodepnt = 0;
  1279.   for (node = firstelement; node < searchwidth; node++) {
  1280.     root[sonsp].nodes[node].pv = 0;
  1281.     root[sonsp].nodes[node].s = -1;   /* default is to pass */
  1282.   }
  1283. /* Evaluate each square of the board and assign a value to it */
  1284.   for (i = firstelement; i < g->maxstone; i++) {
  1285.     value[i] = 0;          /* default is not blank, so no value */
  1286.     if ((g->board[i] == Blank) && (i != g->movestatus.kospot)) {
  1287.       neipats = g->neibrd[i];
  1288.       a1 = g->armymen[i];    /* blank army number */
  1289.       if (g->who == White) {
  1290.         fricount = &g->whitecount[0]; enmcount = &g->blackcount[0];
  1291.         fripats = g->whitepats[i]; enmpats = g->blackpats[i];
  1292.         blankfris = g->army[a1].friend; blankenms = g->army[a1].enemy;
  1293.       } else {
  1294.         fricount = &g->blackcount[0]; enmcount = &g->whitecount[0];
  1295.         fripats = g->blackpats[i]; enmpats = g->whitepats[i];
  1296.         blankfris = g->army[a1].enemy; blankenms = g->army[a1].friend;
  1297.       }
  1298.       getneighbors(g,&nabor,i);  /* get the neighbors */
  1299.       if ((g->army[a1].size > g->maxstone-4) ||
  1300.          ((blankfris > 0) && (blankenms > 0))) {
  1301.         if ((init[i] > openvalue) &&
  1302.           (((fripats & square3) != 0) || ((enmpats & square3) != 0)) ) {
  1303.           value[i] = openvalue;
  1304.         } else {
  1305.           value[i] = init[i];      /* default value */
  1306.         }
  1307.       }
  1308. /* territory value, more territory value for empty diamonds
  1309.    some code was removed here too */
  1310.       if (((fripats & diamond5) == 0) &&
  1311.           ((enmpats & diamond5) == 0) &&
  1312.           ((neipats & 0x0F0) == 0x0F0)) {
  1313.             value[i] = value[i] + territoryvalue;
  1314.       } else {
  1315.         us = 0; them = 0; captsize = 0; protsize = 0;
  1316.         lastus = -1; lastthem = -1; totallibs = g->army[a1].size - 1;
  1317.         frilibs = 0; hitarisize = 0; hitarisave = 0;
  1318.         neiarms = 0; neienms = 0; ha = -1; pa = -1;
  1319.         for (n = firstelement; n < nabor.neis; n++) { /* count new army neighbor
  1320. s */
  1321.           s = nabor.stone[n];              /* neighbors row & column */
  1322.           a2 = g->armymen[s];              /* neighbor army number */
  1323.           if (g->board[s] == Blank) {
  1324.             frilibs = frilibs + 1;
  1325.           } else {
  1326.             if (g->army[a2].color == g->who) {
  1327.               frilibs = frilibs + g->army[a2].lib - 1;
  1328.               totallibs = totallibs + g->army[a2].lib - 1;
  1329.             }
  1330.             if (g->army[a2].lib == 1) {
  1331.               if (g->army[a2].color == g->who) {
  1332.                 protsize = protsize + g->army[a2].size;
  1333.                 pa = a2;
  1334.               } else {
  1335.                 captsize = captsize + g->army[a2].size;
  1336.               }
  1337. /* Check for hitari ...
  1338.    If the enemy can be hitari'd add in the points, if we can be hitari'd
  1339.    add in the points if we can protect against hitari without using up
  1340.    our eyes and if the blank army has more of our stones as neighbors */
  1341.             } else if (g->army[a2].lib == 2) {
  1342.               if (g->army[a2].color == otherside[g->who]) {
  1343.                 hitarisize = hitarisize + g->army[a2].size;
  1344.               } else if ((g->army[a2].color == g->who) &&
  1345.                 (g->army[a1].enemy > 0) && (blankfris > 1)) {
  1346.                 hitarisave = hitarisave + g->army[a2].size;
  1347.                 ha = a2;
  1348.               }
  1349.             }
  1350. /* Don't count neighbors in the same amry more than once in neiarms,
  1351.    and don't count armies in trouble */
  1352.             if (g->board[s] == g->who) {
  1353.               us = us + 1;
  1354.               if (((lastus < 0) || (a2 != lastus)) &&
  1355.                    (a2 != ha)) {
  1356.                 neiarms = neiarms + 1;
  1357.                 lastus = a2;
  1358.               }
  1359.             } else {
  1360.               them = them + 1;
  1361.               if ((lastthem < 0) || (a2 != lastthem)) {
  1362.                 neienms = neienms + 1;
  1363.                 lastthem = a2;
  1364.               }
  1365.             }
  1366.           }
  1367.         }
  1368. /* This is the place!  I cut lots of strategic code from here.  If you want
  1369.    to improve the ability of this program to play go, this is the place to
  1370.    do it. */
  1371.  
  1372.  
  1373. /* lower the value of a square controlled */
  1374.         if (((neipats & 0xF00) != 0xF00) &&    /* row 3 test */
  1375.             ((neipats & 0x0F0) == 0x0F0) &&
  1376.             (them > 0) && ((fripats & diamond5) == 0)) value[i] = 0;
  1377.         if ((us > 2) && (them <= 0)) { value[i] = 0; }
  1378.         if ((us > 1) && (neiarms < us)) { value[i] = 0; }
  1379.         if ((them > 2) && (us <= 0)) { value[i] = 0; }
  1380. /* lower the value of a square that can be hitari'd on the next move */
  1381.         if ((us <= 0) && (them >= nabor.neis-2)) {
  1382.           value[i] = (value[i] / 2) - 1;
  1383.         }
  1384. /* increase the value of a position that protects us from hitari, unless
  1385.    that position is already controlled by us */
  1386.         if ((hitarisave > 0) && (nabor.neis > 3) && (frilibs > 1) &&
  1387.             ((us < 3) || (them > 0))) {
  1388.           value[i] = value[i] + hitarisave + retreatsize + neiarms - us;
  1389.         }
  1390. /* increase the value of a square that hitari's the enemy */
  1391.         if (hitarisize > 0) {
  1392.           if (frilibs > 1) {
  1393.             value[i] = value[i] + hitarisize - us;
  1394.             if (nabor.neis > 3) {
  1395.               value[i] = value[i] + hitarivalue;
  1396.             }
  1397.           } else if ((snaplibs > 0) && (snaplibs < 3)) {
  1398.               value[i] = value[i] + hitarisize + capturevalue +
  1399.                 hitarivalue + neiarms + snaplibs;
  1400.         } }
  1401. /* protect if we pick up at least 3 liberties, or 2 liberties without
  1402.    having to move on the edge of the board and without having to move
  1403.    into our eyes */
  1404.         if ((protsize > 0) && (blankfris > 1) &&
  1405.             ((frilibs > 2) || ((frilibs > 1) && (nabor.neis > 3)))) {
  1406.           value[i] = value[i] + protsize + protvalue - us;
  1407.         }
  1408. /* don't move to the edge unless someone else is there */
  1409.         if (((fripats & square3) == 0) && (nabor.neis < 4)) { value[i] = 0; }
  1410. /* lower the value of a square we are next to if the enemy is not near */
  1411.         if (((enmpats & square3) == 0) && ((fripats & square3) != 0)) {
  1412.           if (nabor.neis > 3) value[i] = value[i] / 2; else value[i] = 0;
  1413.         }
  1414. /* Increase the value of moves that extend influence into unoccupied territory *
  1415. /
  1416.         if ((g->movecount >= firstmoves) &&
  1417.             ((fripats & square3) == 0) && ((enmpats & square3) == 0)) {
  1418.           if (((fripats & square5) != 0) && ((enmpats & square5) != 0)) {
  1419.             value[i] = value[i] + square5value;
  1420.           } else if (((fripats & square5) == 0) && ((enmpats & square5) == 0)) {
  1421.             if (((fripats & circle7) != 0) && ((enmpats & circle7) != 0))
  1422.               value[i] = value[i] + circle7value;
  1423.           } }
  1424. /* don't move to a square surrounded by enemy unless we have a capture */
  1425.         if (captsize > 0) {
  1426.           value[i] = value[i] + capturevalue + captsize;
  1427.         } else if (them >= nabor.neis) {
  1428.           value[i] = 0;
  1429.         }
  1430.       }
  1431. /* There are three situations we move into:  1 is during the first
  1432.    moves of the game when a large blank army occupies most of the
  1433.    board; 2 is into a blank army that borders on computer and enemy
  1434.    stones; 3 is into an eye if the value high enough to indicate a
  1435.    capture or protection required, if not a KO situation. */
  1436.       if (value[i] > 0) {
  1437.         if ((i != g->movestatus.kospot) &&
  1438.             ((g->army[a1].size > g->maxstone-4) ||
  1439.             ((blankfris > 0) && (blankenms > 0)) ||
  1440.             (value[i] > invadevalue))) {
  1441.           s = i; node = firstelement;
  1442.           while ((node < searchwidth) && (s >= 0)) {
  1443.             if (value[s] > root[sonsp].nodes[node].pv) {
  1444.               root[sonsp].nodes[node].pv = value[s];
  1445.               s1 = root[sonsp].nodes[node].s;   /* save the old value */
  1446.               root[sonsp].nodes[node].s = s;    /* use the better value */
  1447.               s = s1;                      /* continue with old value */
  1448.             }
  1449.             node = node + 1;
  1450.           }
  1451.           root[sonsp].nodecnt = root[sonsp].nodecnt + 1;
  1452.         }
  1453.       }
  1454.     }
  1455.   }
  1456.   if (root[sonsp].nodecnt > searchwidth) { root[sonsp].nodecnt = searchwidth; }
  1457.   if ((g->debug & 1) != 0) { printf("bestmoves end.\n"); }
  1458. }
  1459. /* File goprocs.c
  1460.    Developer:  James R. Logan Jr. (BYU), Advisor:  Dr. Lynn H. Beus (BYU)
  1461.    BYU Computer Science
  1462.    232 TMCB
  1463.    Provo, Utah  84602
  1464.    email address:  loganj@byuvax.bitnet
  1465.    (801) 378-3617
  1466.  
  1467.    These procedures are go playing utility procedures that can be used by
  1468.    a go playing progam to do all the house keeping during a game of go.
  1469.    These procedures a based on a 1-dimensional representation of the game.
  1470.    This code is not machine dependent, except for the drawing routines at
  1471.    the end.
  1472. */
  1473.  
  1474. #include <qd.h>
  1475. #include <win.h>
  1476. #include <stdio.h>
  1477. #include <goprocs.h>
  1478.  
  1479. #define patwidth 5
  1480.  
  1481. extern FILE *fp;
  1482. extern int drawnumber,lookahead,otherside[2];
  1483. extern windowptr mewindow,mywindow;
  1484.  
  1485. overlay "gostuff"
  1486.  
  1487. char coltable[19] = {'A','B','C','D','E','F','G','H','J','K','L','M','N','O','P'
  1488. ,'Q','R','S','T'};
  1489. int picset[29] =
  1490.   {0x50,0x41,0x40,0x42,0x60,
  1491.    0x14,0x05,0x04,0x06,0x24,
  1492.    0x10,0x01,0x00,0x02,0x20,
  1493.    0x18,0x09,0x08,0x0A,0x28,
  1494.    0x90,0x81,0x80,0x82,0xA0,
  1495.    0x100,0x200,0x400,0x800};
  1496. pattern whitepat = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
  1497. pattern blackpat = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
  1498.  
  1499. int looking,stonenumber,otherside[2],
  1500.   wrkbrd[maxstones];
  1501.  
  1502. initialize (g) game *g; {
  1503. /* This procedure initializes the game structure supplied by the caller */
  1504. int i,j,r1,c1,w1,w2,w3,w4,w5,w6,w7,w8;
  1505.   if ((g->debug & 1) != 0) printf("initializing, board size %d.\n",g->width);
  1506. /* initialize other side table */
  1507.   otherside[White] = Black; otherside[Black] = White;
  1508. /* initialize game parameters */
  1509.   g->movecount = 0;
  1510.   g->deadwhite = 0; g->deadblack = 0;
  1511.   w1 = g->width; w2 = w1 + w1; w3 = w2 + w1; w4 = w3 + w1;
  1512.   w5 = w4 + w1; w6 = w5 + w1; w7 = w6 + 1; w8 = w7 + 1;
  1513.   g->maxstone = w1 * w1; g->movestatus.kospot = -1;
  1514. /* initialize the neighbor board */
  1515.   for (i = firstelement; i < g->maxstone; i++) g->neibrd[i] = 0x0FFFFFFFFL;
  1516.   j = firstelement;
  1517.   for (i = firstelement; i < g->width; i++) {
  1518.     g->neibrd[j] = g->neibrd[j] & 0x0EEEEEEEEL;
  1519.     g->neibrd[j+w1-1] = g->neibrd[j+w1-1] & 0x0DDDDDDDDL;
  1520.     g->neibrd[i] = g->neibrd[i] & 0x0BBBBBBBBL;
  1521.     g->neibrd[g->maxstone-w1+i] = g->neibrd[g->maxstone-w1+i] & 0x077777777L;
  1522.     if (w1 > 1) {
  1523.       g->neibrd[j+1] = g->neibrd[j+1] & 0x0EEEEEEEFL;
  1524.       g->neibrd[j+w1-2] = g->neibrd[j+w1-2] & 0x0DDDDDDDFL;
  1525.       g->neibrd[i+w1] = g->neibrd[i+w1] & 0x0BBBBBBBFL;
  1526.       g->neibrd[g->maxstone-w2+i] = g->neibrd[g->maxstone-w2+i] & 0x07777777FL;
  1527.     }
  1528.     if (w1 > 2) {
  1529.       g->neibrd[j+2] = g->neibrd[j+2] & 0x0EEEEEEFFL;
  1530.       g->neibrd[j+w1-3] = g->neibrd[j+w1-3] & 0x0DDDDDDFFL;
  1531.       g->neibrd[i+w2] = g->neibrd[i+w2] & 0x0BBBBBBFFL;
  1532.       g->neibrd[g->maxstone-w3+i] = g->neibrd[g->maxstone-w3+i] & 0x0777777FFL;
  1533.     }
  1534.     if (w1 > 3) {
  1535.       g->neibrd[j+3] = g->neibrd[j+3] & 0x0EEEEEFFFL;
  1536.       g->neibrd[j+w1-4] = g->neibrd[j+w1-4] & 0x0DDDDDFFFL;
  1537.       g->neibrd[i+w3] = g->neibrd[i+w3] & 0x0BBBBBFFFL;
  1538.       g->neibrd[g->maxstone-w4+i] = g->neibrd[g->maxstone-w4+i] & 0x077777FFFL;
  1539.     }
  1540.     if (w1 > 4) {
  1541.       g->neibrd[j+4] = g->neibrd[j+4] & 0x0EEEEFFFFL;
  1542.       g->neibrd[j+w1-5] = g->neibrd[j+w1-5] & 0x0DDDDFFFFL;
  1543.       g->neibrd[i+w4] = g->neibrd[i+w4] & 0x0BBBBFFFFL;
  1544.       g->neibrd[g->maxstone-w5+i] = g->neibrd[g->maxstone-w5+i] & 0x07777FFFFL;
  1545.     }
  1546.     if (w1 > 5) {
  1547.       g->neibrd[j+5] = g->neibrd[j+5] & 0x0EEEFFFFFL;
  1548.       g->neibrd[j+w1-6] = g->neibrd[j+w1-6] & 0x0DDDFFFFFL;
  1549.       g->neibrd[i+w5] = g->neibrd[i+w5] & 0x0BBBFFFFFL;
  1550.       g->neibrd[g->maxstone-w6+i] = g->neibrd[g->maxstone-w6+i] & 0x0777FFFFFL;
  1551.     }
  1552.     if (w1 > 6) {
  1553.       g->neibrd[j+6] = g->neibrd[j+6] & 0x0EEFFFFFFL;
  1554.       g->neibrd[j+w1-7] = g->neibrd[j+w1-7] & 0x0DDFFFFFFL;
  1555.       g->neibrd[i+w6] = g->neibrd[i+w6] & 0x0BBFFFFFFL;
  1556.       g->neibrd[g->maxstone-w7+i] = g->neibrd[g->maxstone-w7+i] & 0x077FFFFFFL;
  1557.     }
  1558.     if (w1 > 7) {
  1559.       g->neibrd[j+7] = g->neibrd[j+7] & 0x0EFFFFFFFL;
  1560.       g->neibrd[j+w1-8] = g->neibrd[j+w1-8] & 0x0DFFFFFFFL;
  1561.       g->neibrd[i+w7] = g->neibrd[i+w7] & 0x0BFFFFFFFL;
  1562.       g->neibrd[g->maxstone-w8+i] = g->neibrd[g->maxstone-w8+i] & 0x07FFFFFFFL;
  1563.     }
  1564.     j = j + g->width;
  1565.   }
  1566. /* initialize the row and column arrays */
  1567.   i = 0;
  1568.   r1 = 1;
  1569.   while (i < g->maxstone) {
  1570.     for (c1 = 0; c1 < g->width; c1++)
  1571.       { g->rowbrd[i] = r1; g->colbrd[i] = c1; i = i + 1; }
  1572.     r1 = r1 + 1;
  1573.   }
  1574.   for (i = firstelement; i < g->maxstone; i++) {
  1575.     g->board[i] = Blank; g->whitepats[i] = 0; g->blackpats[i] = 0;
  1576.     g->whitecount[i] = 0; g->blackcount[i] = 0;
  1577.   }
  1578.   allarmies(g);  /* Create the armies */
  1579.   drawboard(g);  /* display the game board */
  1580.   looking = 0;   /* indicate not in look ahead now */
  1581.   stonenumber = 0;
  1582.   if ((g->debug & 1) != 0) printf("initialize end.\n");
  1583. }
  1584.  
  1585. int addastone(g,newstone) game *g; int newstone; {
  1586. /* Clear the blank army for rebuilding, update any neighboring enemy
  1587.    armies directly, and do nothing for neighboring friendly armies.
  1588.    Friendly armies are merged and updated by linkarmies at the end. */
  1589. int a1,a2,first,playedstone,n,s; neighbors nabor; mstatus oldstatus;
  1590.   playedstone = -1;
  1591.   a2 = -1;
  1592.   if ((newstone >= 0) && (newstone < g->maxstone) &&
  1593.       (newstone != g->movestatus.kospot) && (g->board[newstone] == Blank)) {
  1594.     g->movecount = g->movecount + 1;
  1595.     if (looking == 0) stonenumber = stonenumber + 1;
  1596.     oldstatus = g->movestatus;  /* save the old status */
  1597.     g->board[newstone] = g->who;
  1598.     drawstone(g,newstone,g->who);
  1599.     g->movestatus.kospot = -1;  /* clear the ko position */
  1600.     g->movestatus.captures = 0; /* clear captures */
  1601.     topicture(g,newstone);
  1602.     a1 = g->armymen[newstone]; /* old blank army number */
  1603.     first = g->army[a1].first; /* create link list of armies to relink */
  1604.     getneighbors(g,&nabor,newstone);
  1605.     a2 = -1;
  1606.     for (n = firstelement; n < nabor.neis; n++) {
  1607.       s = nabor.stone[n];
  1608.       if (g->board[s] != Blank) {
  1609.         a1 = g->armymen[s];
  1610.         if ((a1 != a2) && (g->army[a1].color == otherside[g->who])) {
  1611.           g->army[a1].enemy = g->army[a1].enemy + 1;
  1612.           g->army[a1].lib = g->army[a1].lib - 1;
  1613.           if (g->army[a1].lib <= 0) {
  1614.             capture(g,g->army[a1].first);
  1615.             g->movestatus.captures = g->movestatus.captures | nabor.direction[n]
  1616. ;
  1617.           }
  1618.         }
  1619.         a2 = a1;
  1620.     } }
  1621.     linkarmies(g,first);
  1622. /* If the added stone was illegal for lack of liberties then remove it */
  1623.     if (g->army[g->armymen[newstone]].lib <= 0) {
  1624.       if (g->who == White) printf(" Bad add by white at %c,%d\n",
  1625.           coltable[g->colbrd[newstone]],g->rowbrd[newstone]);
  1626.       else printf(" Bad add by black at %c,%d\n",
  1627.           coltable[g->colbrd[newstone]],g->rowbrd[newstone]);
  1628.       removeastone(g,newstone,g->movestatus);
  1629.       g->movestatus = oldstatus;
  1630.       if (looking == 0) stonenumber = stonenumber - 1;
  1631.     } else {
  1632. /* If the added stone merged into another army then there is no ko spot */
  1633.       a1 = g->armymen[newstone]; /* old blank army number */
  1634.       if (g->army[a1].size > 1) g->movestatus.kospot = -1;
  1635.       if (looking == 0) {
  1636.         playedstone = newstone;
  1637.         if (fp != NULL) {
  1638.           if (g->who == White) fprintf(fp,"add w %c,%d\n",
  1639.             coltable[g->colbrd[newstone]],g->rowbrd[newstone]);
  1640.           else fprintf(fp,"add b %c,%d\n",
  1641.             coltable[g->colbrd[newstone]],g->rowbrd[newstone]);
  1642.     } } }
  1643.   } else {
  1644.     if (g->who == White) printf(" Bad add by white at %c,%d\n",
  1645.           coltable[g->colbrd[newstone]],g->rowbrd[newstone]);
  1646.     else printf(" Bad add by black at %c,%d\n",
  1647.           coltable[g->colbrd[newstone]],g->rowbrd[newstone]);
  1648.   }
  1649.   return playedstone;
  1650. }
  1651.  
  1652. removeastone(g,newstone,status) game *g; int newstone; mstatus status; {
  1653. /* Clear the blank army for rebuilding, update any neighboring enemy
  1654.    armies directly, and do nothing for neighboring friendly armies.
  1655.    Friendly armies are merged and updated by linkarmies at the end. */
  1656. int a1,a2,first,n,s,color,wh; neighbors nabor;
  1657.   if ((g->debug & 1) != 0) printf("removeastone at: %d\n",newstone);
  1658.   if ((newstone >= 0) && (newstone < g->maxstone) &&
  1659.       (g->board[newstone] != Blank)) {
  1660.     g->movecount = g->movecount - 1;
  1661.     g->movestatus = status;    /* set the new board status */
  1662.     wh = g->board[newstone];   /* save the old color */
  1663.     color = otherside[wh];
  1664.     frompicture(g,newstone);   /* remove stone from picture */
  1665.     g->board[newstone] = Blank;/* remove the stone */
  1666.     if (wh == White) g->deadwhite = g->deadwhite + 1;
  1667.     else g->deadblack = g->deadblack + 1;
  1668.     undrawstone(g,newstone);
  1669.     a1 = g->armymen[newstone]; /* old army number */
  1670.     first = g->army[a1].first; /* first man in army to be relinked */
  1671.     getneighbors(g,&nabor,newstone);
  1672.     a2 = 0;
  1673.     for (n = firstelement; n < nabor.neis; n++) { /* for neighbors */
  1674.       a1 = g->armymen[nabor.stone[n]];
  1675.       if ((g->army[a1].color == Blank) &&
  1676.           ((nabor.direction[n] & g->movestatus.captures) != 0)) {
  1677.         uncapture(g,nabor.stone[n],color);
  1678.         g->army[a1].lib = 1;   /* set 1 liberty for the removed stone */
  1679.       } else if ((a1 != a2) && (g->army[a1].color == otherside[wh])) {
  1680.         g->army[a1].enemy = g->army[a1].enemy - 1;
  1681.         g->army[a1].lib = g->army[a1].lib + 1;
  1682.       }
  1683.       a2 = a1;
  1684.     }
  1685.     linkarmies(g,first);
  1686.   } else {
  1687.     if (g->who == White) printf(" Bad remove by white at %c,%d\n",
  1688.           coltable[g->colbrd[newstone]],g->rowbrd[newstone]);
  1689.     else printf(" Bad remove by black at %c,%d\n",
  1690.           coltable[g->colbrd[newstone]],g->rowbrd[newstone]);
  1691.   }
  1692.   if ((g->debug & 1) != 0) printf("removeastone, end.\n");
  1693. }
  1694.  
  1695. capture(g,s) game *g; int s; {
  1696. /* Call this routine to remove an army that has been captured.  The
  1697.    army remains intact, just changes to a blank army.  Neighboring
  1698.    enemy armies have their liberties updated by buildarmies. */
  1699. int a1,a2,s1,n,wh; neighbors nabor;
  1700.   if ((g->debug & 1) != 0) printf("capture:\n");
  1701.   if ((s >= 0) && (s < g->maxstone)) {
  1702.     a1 = g->armymen[s];       /* get the army number */
  1703.     if (g->army[a1].color != Blank) {
  1704.       if (g->army[a1].size == 1) {
  1705.         g->movestatus.kospot = g->army[a1].first;
  1706.       } else {
  1707.         g->movestatus.kospot = -1;
  1708.       }
  1709.       g->movecount = g->movecount - g->army[a1].size;
  1710.       wh = g->army[a1].color;     /* save the army color */
  1711.       if (wh == White) g->deadwhite = g->deadwhite + g->army[a1].size;
  1712.       else g->deadblack = g->deadblack + g->army[a1].size;
  1713.       g->army[a1].color = Blank;  /* change army color to blank */
  1714.       g->army[a1].size = 0;   /* causes army to be rebuilt by buildarmies */
  1715.       s1 = g->army[a1].first; /* first man in army */
  1716.       while (s1 >= 0) {
  1717.         frompicture(g,s1);    /* take out of picture */
  1718.         undrawstone(g,s1);
  1719.         g->board[s1] = Blank;     /* change stone color to blank */
  1720. /* clear the size in neighboring enemy armies so they will be rebuilt */
  1721.         getneighbors(g,&nabor,s1);
  1722.         for (n = firstelement; n < nabor.neis; n++) {   /* for neighbors */
  1723.           a2 = g->armymen[nabor.stone[n]];
  1724.           if (a2 > 0) {
  1725.             if (g->army[a2].color == otherside[wh]) {
  1726.               g->army[a2].size = 0; }
  1727.           }
  1728.         }
  1729. /* get the next man in the army */
  1730.         s1 = g->armylnk[s1];  /* row link to next army man   */
  1731.       }
  1732.       buildarmies(g);
  1733.     } else {
  1734.       printf(" Bad capture at: %c,%d\n",coltable[g->colbrd[s]],g->rowbrd[s]);
  1735.     }
  1736.   } else {
  1737.     printf(" Bad capture at: %c,%d\n",coltable[g->colbrd[s]],g->rowbrd[s]);
  1738.   }
  1739.   if ((g->debug & 1) != 0) printf("capture, end.\n");
  1740. }
  1741.  
  1742. uncapture(g,s,wh) game *g; int s,wh; {
  1743. /* Call this routine to uncapture an army that had been captured.  The
  1744.    army remains intact, just changes to a non-blank army.  Neighboring
  1745.    enemy armies have their liberties updated by buildarmies. */
  1746. int a1,a2,s1,n; neighbors nabor;
  1747.   if ((g->debug & 1) != 0) printf("uncapture:\n");
  1748.   if ((s >= 0) && (s < g->maxstone)) {
  1749.     a1 = g->armymen[s];     /* get the army number */
  1750.     if (g->army[a1].color == Blank) {
  1751.       g->movecount = g->movecount + g->army[a1].size;
  1752.       if (wh == White) g->deadwhite = g->deadwhite - g->army[a1].size;
  1753.       else g->deadblack = g->deadblack - g->army[a1].size;
  1754.       g->army[a1].color = wh; /* change army color to non-blank */
  1755.       g->army[a1].size = 0;   /* causes army to be rebuilt by buildarmies */
  1756.       s1 = g->army[a1].first; /* first man in army */
  1757.       while (s1 >= 0) {
  1758.         g->board[s1] = wh;  /* change stone color to non-blank */
  1759.         drawstone(g,s1,wh);
  1760.         topicture(g,s1);    /* add to picture */
  1761. /* clear the size in neighboring enemy armies so they will be rebuilt */
  1762.         getneighbors(g,&nabor,s1);
  1763.         for (n = firstelement; n < nabor.neis; n++) {   /* for neighbors */
  1764.           a2 = g->armymen[nabor.stone[n]];
  1765.           if (g->army[a2].color != wh) g->army[a2].size = 0;
  1766.         }
  1767. /* get the next man in the army */
  1768.         s1 = g->armylnk[s1];  /* row link to next army man */
  1769.       }
  1770.       buildarmies(g);
  1771.     }
  1772.   } else {
  1773.     printf("Bad uncapture an army at: %c,%d\n",
  1774.       coltable[g->colbrd[s]],g->rowbrd[s]);
  1775.   }
  1776.   if ((g->debug & 1) != 0) printf(" uncapture, end.\n");
  1777. }
  1778.  
  1779. getneighbors(g,nabor,stone) game *g; neighbors *nabor; int stone; {
  1780. int b,i,j,s;
  1781. /* Establish the number and position of neighbors to a stone.  Gather
  1782.    the stone numbers of neighboring positions into the nabor.stone
  1783.    array sorted by army number.  The purpose of the sort is
  1784.    to group neighbors belonging to the same army together. */
  1785.   nabor->neis = firstelement;
  1786.   if ((g->neibrd[stone] & 1) != 0) {
  1787.     nabor->stone[firstelement] = stone - 1;
  1788.     nabor->direction[firstelement] = 1;
  1789.     nabor->neis = nabor->neis + 1; }
  1790.   if ((g->neibrd[stone] & 2) != 0) {
  1791.     nabor->stone[nabor->neis] = stone + 1;
  1792.     nabor->direction[nabor->neis] = 2;
  1793.     nabor->neis = nabor->neis + 1; }
  1794.   if ((g->neibrd[stone] & 4) != 0) {
  1795.     nabor->stone[nabor->neis] = stone - g->width;
  1796.     nabor->direction[nabor->neis] = 4;
  1797.     nabor->neis = nabor->neis + 1; }
  1798.   if ((g->neibrd[stone] & 8) != 0) {
  1799.     nabor->stone[nabor->neis] = stone + g->width;
  1800.     nabor->direction[nabor->neis] = 8;
  1801.     nabor->neis = nabor->neis + 1; }
  1802.   for (i = firstelement; i < nabor->neis-1; i++) {
  1803.     for (j = i+1; j < nabor->neis; j++) {
  1804.       if (g->armymen[nabor->stone[j]] < g->armymen[nabor->stone[i]]) {
  1805.         s = nabor->stone[j];
  1806.         nabor->stone[j] = nabor->stone[i]; nabor->stone[i] = s;
  1807.         b = nabor->direction[j];
  1808.         nabor->direction[j] = nabor->direction[i]; nabor->direction[i] = b;
  1809. } } } }
  1810.  
  1811. allarmies(g) game *g; {
  1812. /* Clear all army numbers in the army array, and call build armies */
  1813. int n,s;
  1814.   if ((g->debug & 1) != 0) printf("allarmies:\n");
  1815.   g->avail = 1;      /* next available army number */
  1816.   g->army[1].bp = 0;
  1817.   for (n = firstelement; n < maxarmies; n++) {
  1818.     g->army[n].first = -1;
  1819.     g->army[n].fp = n + 1;  /* initialize armies forward links */
  1820.   }
  1821.   for (s = firstelement; s < g->maxstone; s++) {
  1822.     g->armymen[s] = 0; g->armylnk[s] = s - 1;
  1823.   }
  1824.   linkarmies(g,g->maxstone-1);
  1825.   if ((g->debug & 1) != 0) printf(" allarmies.\n");
  1826. }
  1827.  
  1828. linkarmies(g,first) game *g; int first; {
  1829. /* Create a 1 man army for each square.  Then look at neighboring squares,
  1830.    and if any are the same color army then merge the new army into the
  1831.    neighboring army */
  1832. int n,s,s1,s2,new,old; neighbors nabor;
  1833.   if ((g->debug & 1) != 0) printf("linkarmies:\n");
  1834.   s = first;
  1835.   old = g->armymen[s];      /* save old army number */
  1836.   while (s >= 0) {
  1837.     s1 = g->armylnk[s];     /* save link to next old army man */
  1838.     new = g->avail;         /* get next available army number */
  1839.     g->avail = g->army[g->avail].fp;
  1840.     g->army[g->avail].bp = new;
  1841.     g->armymen[s] = new;    /* set new army number */
  1842.     g->armylnk[s] = -1;
  1843.     g->army[new].size = 0;  /* size is done by buildarmies */
  1844.     g->army[new].color = g->board[s];
  1845.     g->army[new].first = s; g->army[new].last = s;
  1846.     getneighbors(g,&nabor,s);     /* get the neighbors */
  1847.     for (n = firstelement; n < nabor.neis; n++) {  /* go through the neighbors *
  1848. /
  1849.       s2 = nabor.stone[n];
  1850.       if (g->armymen[s2] != old) { armymerge(g,s2,s); }
  1851.     }
  1852.     s = s1;  /* next man to be linked */
  1853.   }
  1854. /* make old army number available */
  1855.   if (old > 0) {
  1856.     if (g->army[old].fp != g->avail) {
  1857.       if (g->army[old].bp > 0) {
  1858.         g->army[g->army[old].bp].fp = g->army[old].fp; }
  1859.       g->army[g->army[old].fp].bp = g->army[old].bp;
  1860.       g->army[g->army[g->avail].bp].fp = old;
  1861.       g->army[old].fp = g->avail;
  1862.       g->army[old].bp = g->army[g->avail].bp;
  1863.       g->army[g->avail].bp = old;
  1864.     }
  1865.     g->army[old].first = -1; g->avail = old;
  1866.   }
  1867.   buildarmies(g);
  1868.   if ((g->debug & 1) != 0) printf("  linkarmies.\n");
  1869. }
  1870.  
  1871. buildarmies(g) game *g; {
  1872. /* Add up the number of computer and opponent stones that border on
  1873.    each army */
  1874. int a1,a2,n,s,s1; neighbors nabor;
  1875.   if ((g->debug & 1) != 0) printf("buildarmies:\n");
  1876.   for (s = firstelement; s < g->maxstone; s++) wrkbrd[s] = 0;
  1877.   a1 = g->army[g->avail].bp;
  1878.   while (a1 > 0) {                  /* go through each active army */
  1879.     if ((g->army[a1].size <= 0) && (g->army[a1].first >= 0)) {
  1880.       g->army[a1].lib = 0;
  1881.       g->army[a1].friend = 0;
  1882.       g->army[a1].enemy = 0;
  1883.       g->army[a1].armies = 0;
  1884.       s = g->army[a1].first;          /* first man in army */
  1885.       while (s >= 0) {
  1886.         g->army[a1].size = g->army[a1].size + 1;
  1887.         getneighbors(g,&nabor,s);     /* get the neighbors */
  1888.         for (n = firstelement; n < nabor.neis; n++) {  /* go through neighbors *
  1889. /
  1890.           s1 = nabor.stone[n];
  1891.           if (wrkbrd[s1] != a1) {
  1892.             wrkbrd[s1] = a1;        /* mark this neighbor counted */
  1893.             if (g->board[s] != Blank) {
  1894.               if (g->board[s1] == Blank) {
  1895.                 g->army[a1].lib = g->army[a1].lib + 1;
  1896.               } else if (g->board[s1] != g->board[s]) {
  1897.                 g->army[a1].enemy = g->army[a1].enemy + 1;
  1898.               }
  1899.             } else {
  1900.               if (g->board[s1] != Blank) {
  1901.                 if (g->board[s1] == White) {
  1902.                   g->army[a1].friend = g->army[a1].friend + 1;
  1903.                 } else {
  1904.                   g->army[a1].enemy = g->army[a1].enemy + 1;
  1905.                 }
  1906.               }
  1907.             }
  1908.           }
  1909.         }
  1910.         s = g->armylnk[s]; /* link to next man */
  1911.       }
  1912.     }
  1913.     a1 = g->army[a1].bp;
  1914.   }
  1915.   if ((g->debug & 1) != 0) printf("  buildarmies.\n");
  1916. }
  1917.  
  1918. armymerge(g,s1,s2) game *g; int s1,s2; {
  1919. /* Merge two armies by merging the linked lists */
  1920. int a1,a2,i,s,s3;
  1921.   a1 = g->armymen[s1]; a2 = g->armymen[s2];
  1922.   if ((a1 > 0) && (a1 != a2) && (g->board[s1] == g->board[s2])) {
  1923. /* Change a2 number to a1 for all the a2 armymen */
  1924.     s = g->army[a2].first;  /* first man in army */
  1925.     while (s >= 0) { g->armymen[s] = a1; s = g->armylnk[s]; }
  1926. /* Link army a2 into army a1 */
  1927.     g->armylnk[g->army[a2].last] = g->army[a1].first;
  1928.     g->army[a1].first = g->army[a2].first;
  1929.     g->army[a2].first = -1; /* delete army a2 */
  1930.     g->army[a2].size = 0;
  1931.     g->army[a1].size = 0;   /* required for buildarmies */
  1932.     if (g->army[a2].fp != g->avail) {
  1933.       if (g->army[a2].bp > 0) {
  1934.         g->army[g->army[a2].bp].fp = g->army[a2].fp; }
  1935.       g->army[g->army[a2].fp].bp = g->army[a2].bp;
  1936.       g->army[g->army[g->avail].bp].fp = a2;
  1937.       g->army[a2].fp = g->avail;
  1938.       g->army[a2].bp = g->army[g->avail].bp;
  1939.       g->army[g->avail].bp = a2;
  1940.     }
  1941.     g->avail = a2;
  1942. } }
  1943.  
  1944. topicture(g,s) game *g; int s; {
  1945. /* Add the specified stone to the bitmap of the stones in the 5 by 5
  1946.    diamond centered about the specified stone */
  1947. int i,s1,s2,s3,w3; long bit,*p; char *c;
  1948.   i = - g->width - g->width - 2; bit = 1L; s1 = -1;
  1949.   if (g->who == White) { p = &g->whitepats[s]; c = &g->whitecount[s]; }
  1950.   else { p = &g->blackpats[s]; c = &g->blackcount[s]; }
  1951.   for (s2 = 0; s2 < patwidth; s2++) {
  1952.     for (s3 = 0; s3 < patwidth; s3++) {
  1953.       s1 = s1 + 1;
  1954.       if ((picset[s1] & g->neibrd[s]) == picset[s1])
  1955.         { *(p+i) = *(p+i) | bit; *(c+i) = *(c+i) + 1; }
  1956.       bit = bit + bit; i = i + 1;
  1957.     } i = i + g->width - patwidth;
  1958.   }
  1959.   w3 = g->width + g->width + g->width;
  1960.   if ((picset[25] & g->neibrd[s]) == picset[25])
  1961.     { *(p-3) = *(p-3) | 0x2000000L; *(c-3) = *(c-3) + 1; }
  1962.   if ((picset[26] & g->neibrd[s]) == picset[26])
  1963.     { *(p+3) = *(p+3) | 0x4000000L; *(c+3) = *(c+3) + 1; }
  1964.   if ((picset[27] & g->neibrd[s]) == picset[27])
  1965.     { *(p-w3) = *(p-w3) | 0x8000000L; *(c-w3) = *(c-w3) + 1; }
  1966.   if ((picset[28] & g->neibrd[s]) == picset[28])
  1967.     { *(p+w3) = *(p+w3) | 0x10000000L; *(c+w3) = *(c+w3) + 1; }
  1968. }
  1969.  
  1970. frompicture(g,s) game *g; int s; {
  1971. /* Remove the specified stone from the bitmap of the stones in the 5 by 5
  1972.    diamond centered about the specified stone. */
  1973. int i,s1,s2,s3,w3; long bit,*p; char *c;
  1974.   i = - g->width - g->width - 2; bit = 1; s1 = -1;
  1975.   if (g->who == White) { p = &g->whitepats[s]; c = &g->whitecount[s]; }
  1976.   else { p = &g->blackpats[s]; c = &g->blackcount[s]; }
  1977.   for (s2 = 0; s2 < patwidth; s2++) {
  1978.     for (s3 = 0; s3 < patwidth; s3++) {
  1979.       s1 = s1 + 1;
  1980.       if ((picset[s1] & g->neibrd[s]) == picset[s1])
  1981.         { *(p+i) = *(p+i) & ~bit; *(c+i) = *(c+i) - 1; }
  1982.       bit = bit + bit; i = i + 1;
  1983.     } i = i + g->width - patwidth;
  1984.   }
  1985.   w3 = g->width + g->width + g->width;
  1986.   if ((picset[25] & g->neibrd[s]) == picset[25])
  1987.     { *(p-3) = *(p-3) & ~0x2000000L; *(c-3) = *(c-3) - 1; }
  1988.   if ((picset[26] & g->neibrd[s]) == picset[26])
  1989.     { *(p+3) = *(p+3) & ~0x4000000L; *(c+3) = *(c+3) - 1; }
  1990.   if ((picset[27] & g->neibrd[s]) == picset[27])
  1991.     { *(p-w3) = *(p-w3) & ~0x8000000L; *(c-w3) = *(c-w3) - 1; }
  1992.   if ((picset[28] & g->neibrd[s]) == picset[28])
  1993.     { *(p+w3) = *(p+w3) & ~0x10000000L; *(c+w3) = *(c+w3) - 1; }
  1994. }
  1995.  
  1996. /* The following routines provide output for debugging */
  1997.  
  1998. moveboard(g) game *g; {
  1999. int i,s;
  2000.   s = 0;
  2001.   while (s < g->maxstone) {
  2002.     for (i = firstelement; i < g->width; i++) {
  2003.       if (g->board[s] == White) printf(" 1");
  2004.       else if (g->board[s] == Black) printf(" 2");
  2005.       else printf(" 0");
  2006.       s = s + 1;
  2007.     }
  2008.     printf("\n");
  2009. } }
  2010.  
  2011. armyboard(g) game *g; {
  2012. int i,s;
  2013.   s = 0;
  2014.   while (s < g->maxstone) {
  2015.     for (i = firstelement; i < g->width; i++) { printf("%3d",g->armymen[s]); s =
  2016.  s + 1; }
  2017.     printf("\n");
  2018. } }
  2019.  
  2020. armyinfo(g) game *g; {
  2021. int i,n; char qkey;
  2022.   qkey = 'g';
  2023.   printf("Total stones: %d\nAvail: %d\n",g->movecount,g->avail);
  2024.   n = 0;
  2025.   i = g->army[g->avail].bp;
  2026.   while (i > 0) { if (i > n) n = i; i = g->army[i].bp; }
  2027.   printf("Highest army number: %d\n",n);
  2028.   i = g->army[g->avail].bp;
  2029.   while ((qkey != 'q') && (i > 0)) {
  2030.     printf("Army %d\n",i);
  2031.     if (g->army[i].first >= 0) {
  2032.       printf("Color %d\nSize %d\nFirst %d\nLast %d\n",
  2033.         g->army[i].color,g->army[i].size,g->army[i].first,g->army[i].last);
  2034.       printf("FP %d\nBP %d\nLiberties %d\nFriends %d\nEnemies %d\n",
  2035.         g->army[i].fp,g->army[i].bp,g->army[i].lib,g->army[i].friend,g->army[i].
  2036. enemy);
  2037.     }
  2038.     i = g->army[i].bp;
  2039.     printf("q return to quit, space to continue\n"); qkey = getchar();
  2040.   }
  2041. }
  2042.  
  2043. linkinfo(g) game *g; {
  2044. int i,s;
  2045.   s = firstelement;
  2046.   while (s < g->maxstone) {
  2047.     for (i = firstelement; i < g->width; i++) { printf("%d ",g->armylnk[s]); s =
  2048.  s + 1; }
  2049.     printf("\n");
  2050.   }
  2051. }
  2052.  
  2053. pictinfo(g) game *g; {
  2054. int i,s; char qkey;
  2055.   s = 0; qkey = 'g';
  2056.   printf("White stone patterns:\n");
  2057.   while ((s < g->maxstone) && (qkey != 'q') && (qkey != 'n')) {
  2058.     for (i = firstelement; i < g->width; i++)
  2059.       { printf(" %lx\n",g->whitepats[s]); s = s + 1; }
  2060.     printf("q return to quit, space to continue\n"); qkey = getchar();
  2061.   } printf("Black stone patterns:\n");
  2062.   s = 0;
  2063.   while ((s < g->maxstone) && (qkey != 'q')) {
  2064.     for (i = firstelement; i < g->width; i++)
  2065.       { printf(" %lx\n",g->blackpats[s]); s = s + 1; }
  2066.     printf("q return to quit, space to continue\n"); qkey = getchar();
  2067.   }
  2068. }
  2069.  
  2070. neighborinfo(g) game *g; {
  2071. int i,s;
  2072.   s = 0;
  2073.   while (s < g->maxstone) {
  2074.     for (i = firstelement; i < g->width; i++)
  2075.       { printf("%4x ",g->neibrd[s]); s = s + 1; }
  2076.     printf("\n");
  2077.   }
  2078. }
  2079.  
  2080. drawboard(g) game *g; {
  2081. int i,linelength; rect srect; char num[4];
  2082.   setport(mywindow);
  2083. /* Draw the position letters and numbers */
  2084.   textsize(9);
  2085.   for (i = g->width; i > 0; i--) {
  2086.     moveto(-12,14 + 16 * (g->width - i));
  2087.     sprintf(num,"%2d", i);
  2088.     drawstring(num);
  2089.   }
  2090.   for (i = 0; i < g->width; i++) {
  2091.     moveto(7 + 16 * i,13 + 16 * g->width);
  2092.     drawchar(coltable[i]);
  2093.   }
  2094. /* Draw the board */
  2095.   textsize(7);
  2096.   linelength = 16 * (g->width - 1);
  2097.   moveto(10,10);
  2098.   for (i = 0; i < g->width; i++) {
  2099.     line(linelength,0);
  2100.     move(-linelength,16);
  2101.   }
  2102.   moveto(10,10);
  2103.   for (i = 0; i < g->width; i++) {
  2104.     line(0,linelength);
  2105.     move(16,-linelength);
  2106.   }
  2107. /* draw the handicap positions on a 19 X 19 board */
  2108.   if (g->width == 19) {
  2109. /* first draw the corner handicap positions */
  2110.     setrect(&srect,  55,  55,  61,  61); filloval(&srect,&blackpat);
  2111.     setrect(&srect,  55, 247,  61, 253); filloval(&srect,&blackpat);
  2112.     setrect(&srect, 247,  55, 253,  61); filloval(&srect,&blackpat);
  2113.     setrect(&srect, 247, 247, 253, 253); filloval(&srect,&blackpat);
  2114. /* now draw the other row 3 handicap positions */
  2115.     setrect(&srect,  55, 151,  61, 157); filloval(&srect,&blackpat);
  2116.     setrect(&srect, 151,  55, 157,  61); filloval(&srect,&blackpat);
  2117.     setrect(&srect, 247, 151, 253, 157); filloval(&srect,&blackpat);
  2118.     setrect(&srect, 151, 247, 157, 253); filloval(&srect,&blackpat);
  2119. /* finally draw the center handicap position */
  2120.     setrect(&srect, 151, 151, 157, 157); filloval(&srect,&blackpat);
  2121.   }
  2122.   setport(mewindow);
  2123. }
  2124.  
  2125. drawstone(g,s,wh) game *g; int s,wh; {
  2126. int w,x,y; rect srect; char num[8];
  2127.   if ((looking == 0) || (lookahead != 0)) {
  2128.     setport(mywindow);
  2129.     x = 10 + 16 * (s % g->width);
  2130.     y = 10 + 16 * ((g->maxstone - 1 - s) / g->width);
  2131.     setrect(&srect, x-8, y-8, x+8, y+8);
  2132.     if (wh == White) {
  2133.       filloval(&srect,&whitepat);
  2134.     } else {
  2135.       filloval(&srect,&blackpat);
  2136.     }
  2137.     if ((drawnumber != 0) && (looking == 0)) {
  2138.       sprintf(num,"%d",stonenumber);
  2139.       w = stringwidth(num) >> 1;
  2140.       moveto(x-w,y+3);
  2141.       drawstring(num);
  2142.     }
  2143.     setport(mewindow);
  2144.   }
  2145. }
  2146.  
  2147. undrawstone(g,s) game *g; int s; {
  2148. int x,y; rect srect;
  2149.   if ((looking == 0) || (lookahead != 0)) {
  2150.     setport(mywindow);
  2151.     x = 10 + 16 * (s % g->width);
  2152.     y = 10 + 16 * ((g->maxstone - 1 - s) / g->width);
  2153.     setrect(&srect, x-8, y-8, x+8, y+8);
  2154.     eraseoval(&srect);
  2155.     if ((g->neibrd[s] & 1) != 0) { moveto(x,y); line(-8,0); }
  2156.     if ((g->neibrd[s] & 2) != 0) { moveto(x,y); line(8,0); }
  2157.     if ((g->neibrd[s] & 4) != 0) { moveto(x,y); line(0,8); }
  2158.     if ((g->neibrd[s] & 8) != 0) { moveto(x,y); line(0,-8); }
  2159. /* draw the handicap positions on a 19 X 19 board */
  2160.     if (g->width == 19) {
  2161. /* first draw the corner handicap positions */
  2162.       if (s == 60) {
  2163.         setrect(&srect,  55, 247,  61, 253); filloval(&srect,&blackpat); }
  2164.       if (s == 72) {
  2165.         setrect(&srect, 247, 247, 253, 253); filloval(&srect,&blackpat); }
  2166.       if (s == 288) {
  2167.         setrect(&srect,  55,  55,  61,  61); filloval(&srect,&blackpat); }
  2168.       if (s == 300) {
  2169.         setrect(&srect, 247,  55, 253,  61); filloval(&srect,&blackpat); }
  2170. /* now draw the other row 3 handicap positions */
  2171.       if (s == 174) {
  2172.         setrect(&srect,  55, 151,  61, 157); filloval(&srect,&blackpat); }
  2173.       if (s == 294) {
  2174.         setrect(&srect, 151,  55, 157,  61); filloval(&srect,&blackpat); }
  2175.       if (s == 186) {
  2176.         setrect(&srect, 247, 151, 253, 157); filloval(&srect,&blackpat); }
  2177.       if (s == 66) {
  2178.         setrect(&srect, 151, 247, 157, 253); filloval(&srect,&blackpat); }
  2179. /* finally draw the center handicap position */
  2180.       if (s == 180) {
  2181.         setrect(&srect, 151, 151, 157, 157); filloval(&srect,&blackpat); }
  2182.     }
  2183.     setport(mewindow);
  2184.   }
  2185. }
  2186. /* File gofile.c
  2187.    Developer:  James R. Logan Jr. (BYU), Advisor:  Dr. Lynn H. Beus (BYU)
  2188.    email address:  loganj@byuvax.bitnet
  2189.    (801) 378-3617
  2190.  
  2191.    These routines handle the disk I/O for the go program's log file and
  2192.    replay feature.  This code is not machine dependent.
  2193. */
  2194.  
  2195. #include <qd.h>
  2196. #include <pack.h>
  2197. #include <win.h>
  2198. #include <dialog.h>
  2199. #include <stdio.h>
  2200. #include <goprocs.h>
  2201.  
  2202. overlay "filestuff"
  2203.  
  2204. char prompt[2] = {' ','\0'},origname[2] = {' ','\0'},filename[32];
  2205. rect drect;
  2206.  
  2207. extern FILE *fp,*gp;
  2208. extern char coltable[19];
  2209. extern int play;
  2210. extern game mygame;
  2211. extern windowptr mywindow, dummywindow;
  2212. extern int addastone(),moves();
  2213.  
  2214. createfile() {
  2215. /* This procedure opens a log file for the game in progess */
  2216. sfreply reply; point pt; char volname[30]; int i,j,tint; long tlong;
  2217.   setrect(&drect,-16,28,440,200);
  2218.   copybits(&mywindow->portbits,&dummywindow->portbits,&drect,&drect,srccopy,(lon
  2219. g)0);
  2220.   setpt(&pt, 190, 75);
  2221.   sfputfile(&pt, &prompt[0], &origname[0], NULL, &reply);
  2222.   copybits(&dummywindow->portbits,&mywindow->portbits,&drect,&drect,srccopy,(lon
  2223. g)0);
  2224.   if (reply.good) {
  2225.     getvinfo(reply.vrefnum, volname, &tint, &tlong);
  2226.     strcpy(filename, volname); strcat(filename, ":"); strcat(filename, reply.fna
  2227. me);
  2228.     if (fp != NULL) fclose(fp);
  2229.     fp = fopen(filename,"w");
  2230. } }
  2231.  
  2232. replay() {
  2233. /* This procedure opens a saved game and replays the game.  The game file
  2234.    can be modified by an editor to change the sequence of play.  The first
  2235.    letter of each line determines the function.  Using log files is the
  2236.    fastest way to set up a specific board position.  */
  2237. char col,color,tline[128];
  2238. int c,i,row,s,size,tint; long tlong;
  2239. sfreply reply; point pt; char volname[30];
  2240.   if (gp == 0) {
  2241.     setrect(&drect,-16,28,440,200);
  2242.     copybits(&mywindow->portbits,&dummywindow->portbits,
  2243.           &drect,&drect,srccopy,(long)0);
  2244.     setpt(&pt, 186, 75);
  2245.     sfgetfile(&pt, NULL, NULL, 1, "TEXT", NULL, &reply);
  2246.     copybits(&dummywindow->portbits,&mywindow->portbits,
  2247.           &drect,&drect,srccopy,(long)0);
  2248.     if (reply.good) {
  2249.       getvinfo(reply.vrefnum, volname, &tint, &tlong);
  2250.       strcpy(filename, volname); strcat(filename, ":"); strcat(filename, reply.f
  2251. name);
  2252.       gp = fopen(filename,"r");
  2253.     }
  2254.   } else {
  2255.     c = NULL;
  2256.     for (i=0; (i<128) && ((c = getc(gp)) != EOF) && (c != 10); i++) tline[i] = c
  2257. ;
  2258.     tline[i] = 0;
  2259.     switch (tline[0]) {
  2260.       case 'a': case 'A':
  2261.         sscanf(tline,"%*s %c %c,%d",&color,&col,&row);
  2262.         s = position(col,row);
  2263.         if ((color == 'w') || (color == 'W')) mygame.who = White;
  2264.         else if ((color == 'b') || (color == 'B')) mygame.who = Black;
  2265.         if (s >= 0) s = addastone(&mygame,s);
  2266.         break;
  2267.       case 'b': case 'B': mygame.who = Black; break;
  2268.       case 'c': case 'C':
  2269.         sscanf(tline,"%*s %c,%d",&col,&row);
  2270.         s = position(col,row);
  2271.         if (s >= 0) capture(&mygame,s);
  2272.         break;
  2273.       case 'i': case 'I':
  2274.         sscanf(tline,"%*s %d",&size);
  2275.         if ((size > 2) && (size < 20)) {
  2276.           mygame.width = size;
  2277.           initgame(&mygame);
  2278.         }
  2279.         break;
  2280.       case 'm': case 'M': s = moves(&mygame); break;
  2281.       case 'r': case 'R':
  2282.         sscanf(tline,"%*s %c,%d",&col,&row);
  2283.         s = position(col,row);
  2284.         if (s >= 0) removeastone(&mygame,s,mygame.movestatus);
  2285.         break;
  2286.       case 'u': case 'U':
  2287.         sscanf(tline,"%*s %c,%d,%c",&col,&row,&color);
  2288.         s = position(col,row);
  2289.         if (s >= 0) {
  2290.           if ((color == 'w') || (color == 'W')) uncapture(&mygame,s,White);
  2291.           else if ((color == 'b') || (color == 'B')) uncapture(&mygame,s,Black);
  2292.  
  2293.         }
  2294.         break;
  2295.       case 'w': case 'W': mygame.who = White; break;
  2296.       default:
  2297.     }
  2298.     if (c == EOF) { fclose(gp); gp = NULL; play = 0; }
  2299. } }
  2300.  
  2301. int position(col,row) char col; int row; {
  2302. /* This procedure converts from a 2-dimensional position used by the world,
  2303.    to the 1-dimensional position used in the game structures */
  2304. int i,s;
  2305.   s = -1;
  2306.   if ((row > 0) && (row <= mygame.width)) {
  2307.     for (i = 0; i < mygame.width; i++) if (col == coltable[i]) s = i;
  2308.     if ((s >= 0) && (s < mygame.width)) s = (row - 1) * mygame.width + s;
  2309.   }
  2310.   return(s);
  2311. }
  2312.  
  2313.