home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-06-20 | 83.1 KB | 2,313 lines |
- >From: LOGANJ@BYUVAX.BITNET
- Newsgroups: net.sources.mac
- Subject: Sources to Go program for the Macintosh
- Date: 11 Mar 86 02:13:30 GMT
- Organization: University of California at Berkeley
-
- The following text contains 1 document file and 7 files of source code for
- the Go program posted 24 Feb 86, as promised. Each source file begins with
- "/* File filename" and you will need to break the files up to compile. The
- programs were written for Megamax C.
-
- The core programs (in goprocs.c) have been through extensive testing,
- everything else is in the process of conceptualization and development.
-
- These programs are provided as a simple skeleton go program. Some code was
- removed from the 'bestmoves' routine for this posting, to keep it simple.
- Since code was removed, the following programs will not play as well as the
- executable version that was posted 24 Feb 1986.
-
- This is not to be taken as an example of great coding technique - this is a
- first effort.
-
- Known problems: The last time that I adjusted the weights in the
- move selection routine (bestmoves) to play a better game against Nemesis I
- made a mistake, so presently the executable version of the program will
- attempt an illegal move in some situations.
-
- Also, I do not have access to a Mac XL, so I can not insure that the
- program runs properly there. As far as I know, the code follows the
- toolbox interface conventions - nothing tricky there.
-
- Will this kind posting create more interest in Programs that play go?
- Or will it set the programming of go back ten years by undermining support
- for more professional efforts? Other?
-
- Thanks to those of you who have responded with problems and suggestions!
- Correspondence and gratuities of any kind (verbal, code, financial, ...)
- can be sent to:
-
- Lynn Beus & Jim Logan
- BYU Computer Science
- 232 TMCB
- Provo, Utah 84602
-
- or email: loganj@byuvax.bitnet
-
- Phone: (801) 378-3617
- ___________________________________________________________________________
-
- 26 February 1986
-
- Go Utility Programs Description
-
- Developer: James R. Logan Jr. (BYU)
- Advisor: Dr. Lynn H. Beus (BYU)
- BYU Computer Science
- 232 TMCB
- Provo, Utah 84602
- email address: loganj@byuvax.bitnet
- phone: (801) 378-3617
-
- This document describes procedures, variables, arrays, and structures
- that maintain a 1-dimensional representation of the Oriental game of Go.
- The present implementation of the programs, for lack of development
- time, has the following arbitrary limitations:
-
- - No count is maintained of the number of eyes that each army has
- (an easy thing to implement?), but only the number of individual
- liberties that each army has.
-
- - No count is maintained of the number of neighboring armies to an
- army.
-
- - The maximum allowable board size is 19 by 19 lines, or 361 positions.
-
- - The maximum allowable number of armies is 362 (compile time
- parameter).
-
- - The game board must be square.
-
- The 'who' variable in the game structure (game.who) designates black's
- or white's turn to play, and is an input parameter to some of these
- procedures. The user is required to set this variable to White or Black
- before each procedure call.
-
- All 1-dimensional representations of the Go board are defined in C as
- char [361]. The Go Programs consist of twelve main procedures. The
- calling conventions and purpose of these twelve procedures is described
- as follows:
-
- -initialize
- Initializes the specified game structure by clearing all stones from the
- various arrays and building the initial blank army. Initialize must be
- called for a newly allocated game structure. For example, to initialize
- a 5 by 5 game board the initialize routine should be called as follows:
-
- g->width = 5;
- initialize(g);
- where g is a game structure pointer previously allocated by the user.
-
- -addastone
- Adds a stone of color g.who to the specified 1-dimensional position and
- updates the specified game structure. If the specified position is
- already occupied then no update occurs. For example, to add a stone to
- position 9 the addastone routine should be called as follows:
-
- addastone(g,9);
- where g is an initialized game structure pointer.
-
- -removeastone
- Removes the specified stone and updates the specified game structure.
- If the specified stone represents an unoccupied position then no update
- occurs. For example, to remove a stone at position 9 the removeastone
- routine should be called as follows:
-
- removeastone(g,9,status);
- where g is a game structure pointer,
- and status is a movestatus (mstatus) structure.
-
- -getneighbors
- Returns the number of immediate non-blank neighbors to a position, and
- returns the 1 dimensional board position of each non-blank neighbor in a
- stone[1..4] array sorted by army number. For example, to get all
- neighboring positions (white, black, and blank) to position 9 the
- getneighbors routine should be called as follows:
-
- getneighbors(g,n,9);
- where g is a game structure pointer,
- and n is a nabor structure pointer.
-
- The next two procedures will not normally be needed by the users program,
- but they are included for completeness.
-
- -capture
- Removes the army represented by the specified stone and updates the
- appropriate data structures. If the specified stone represents a blank
- army then no update occurs. For example, to remove an army that
- contains a stone at position 9 the capture routine should be called as
- follows:
-
- capture(g,9);
- where g is a game structure pointer.
-
- -uncapture
- Uncaptures the army represented by the specified position and updates
- the appropriate data structures. If the specified postion is occupied
- then no update occurs. For example, to uncapture an army that contains
- a stone at position 9 the uncapture routine should be called as follows:
-
- uncapture(g,9,color);
- where g is a game structure pointer,
- and color is the color of the army (White or Black) being uncaptured.
- _________________________________________________________________________
-
- The following routines print the values of game structures upside down
- from the game board displayed on the screen.
-
- -moveboard
- This procedure prints the game.board array on the screen, for debugging.
- For example, to display game.board call moveboard as follows:
-
- moveboard(g);
- where g is a game structure pointer.
-
- -armyboard
- This procedure prints the game.armymen array on the screen, for debugging.
- For example, to display game.armymen call armyboard as follows:
-
- armyboard(g);
- where g is a game structure pointer.
-
- -armyinfo
- This procedure prints the game.army structure on the screen, for debugging.
- For example, to display game.army call armyinfo as follows:
-
- armyinfo(g);
- where g is a game structure pointer.
-
- linkinfo
- This procedure prints the game.armylnk array on the screen, for debugging.
- For example, to display game.armylnk call linkinfo as follows:
-
- linkinfo(g);
- where g is a game structure pointer.
-
- -pictinfo
- This procedure prints the game.cpict and game.opict arrays on the screen
- in hex, for debugging. For example, to display game.cpict and
- game.opict call pictinfo as follows:
-
- pictinfo(g);
- where g is a game structure pointer.
-
- -neighborinfo
- This procedure prints the game.neibrd array on the screen in hex, for
- debugging. For example, to display game.neibrd call neighborinfo as
- follows:
-
- neighborinfo(g);
- where g is a game structure pointer.
- ________________________________________________________________________
-
- These Go Programs use one main data structure to represent a game of Go,
- as follows:
-
- game - This structure contains some basic structures for the analysis of
- a single board position.
-
- The Game structure contains the following variables, arrays, and
- structures:
-
- who - This variable represents the color of the player making the
- current move, and is set to White for one player, and Black for the
- other player. This variable must be set before a call to the addastone
- procedure, because the addastone procedure uses this variable to set the
- board array value (stone color).
-
- avail - This variable is the next available army number in a linked list
- of army numbers. Do not change this variable.
-
- maxstone - This variable indicates the 1-dimensional size of the game
- board being used. It is computed by the initialize procedure. Do not
- change this variable.
-
- width - This variable indicates the width of the game board. The
- initialize procedure sets this variable to the maximum column number.
- Do not change this variable.
-
- movecount - This variable indicates the number of stones played in the
- game structure. This variable is cleared by the initialize procedure,
- incremented by calls to the addastone procedure, and decremented by
- calls to the removeastone and capture procedures. Do not change this
- variable.
-
- movestatus - This structure contains ko information and capture
- information based on the last stone played on the board. This structure
- should be pushed on the stack during tree searches, because it is used
- to remove a play and restore the previous game position. Do not change
- the variables in this structure.
-
- The ko position (movestatus.kospot) is set by the capture procedure to
- the 1-dimensional position of a 1-man army that was just captured. If
- no army was captured by the last move then this variable is set to -1.
- Also if the size of the captured army is greater than one then this
- variable is set to -1. The addastone procedure sets this variable to
- -1, but the addastone procedure calls the capture procedure if a capture
- is made by a move.
-
- The capture information (movestatus.captures) is set by the addastone
- procedure to reflect which of the four possible armies surrounding the
- new stone was captured. This variable type (movestatus.captures) is bit
- encoded, where the least significant 4 bits determine which direction an
- army was captured in (so that the army can be restored if the capturing
- stone is removed).
-
- debug - This BITSET variable represents various debug states. Bits 0-5
- are used in these programs, and bits 6-15 are available for any use.
-
- board - This 1-dimensional array contains the position of black and
- white stones on the Go Board. One player's stones are represented by a
- value of White, and opponent stones are represented by a value of Black.
- Do not change this array.
-
- rowbrd - This 1-dimensional array corresponds exactly to the board array
- above and indicates the 2-dimensional row number of each position. Do
- not change this array.
-
- colbrd - This 1-dimensional array corresponds exactly to the board array
- above and indicates the 2-dimensional column number of each position.
- Do not change this array.
-
- armymen - This 1-dimensional array corresponds exactly to the Board
- structure (above). Each board position in this array contains the army
- number of the army that occupies this position. The army number is used
- to access information about the army.
-
- armylnk - This 1-dimensional array corresponds exactly to the Board
- structure (above). Each position in this array contains the number of
- the next man in the army. This array is used for processing every man
- in an army, which occurs when an army is being built, when an army is
- captured, and when army neighbors need to be counted.
-
- whitepats - This 1-dimensional array corresponds exactly to the Board
- structure (above). Each position in this array contains a binary
- representation of the white stones in a 5 by 5 diamond shape around the
- position. This binary picture can be used to test for a specific
- geometic arrangement of the white player's stones around a given
- position. See the diagram below.
-
- blackpats - This 1-dimensional array corresponds exactly to the Board
- structure (above). Each position in this array contains a binary
- representation of the black stones in a 5 by 5 diamond shape around the
- position. This binary picture can be used to test for a specific
- geometic arrangement of the black player's stones around a given
- position. See the diagram below.
-
- Whitepats and blackpats (above) contain 32 bit values that represent
- stone patterns in a 5 by 5 diamond shape, centered around a given board
- position (S). Only 29 bits are actually used, 25 bits for a 5 by 5
- square and 4 bits at the center of each outside edge. The area covered
- and bits represented are as follows:
-
- Shape Bit numbers
-
- * 28
- * * * * * 5 4 3 2 1
- * * * * * 10 9 8 7 6
- * * * S * * * 27 15 14 13 12 11 26
- * * * * * 20 19 18 17 16
- * * * * * 25 24 23 22 21
- * 29
-
- neibrd - This 1-dimensional array corresponds exactly to the Board
- structure (above). The purpose of this array is to test a 1-dimensional
- position and determine if the position is on one edge or corner of the
- board. This array can also be used to test for a position on row 1, 2,
- 3, or 4 from any side of the board.
-
- army - This structure is indexed by army number, and contains
- information about each army such as size, color, first (first army man's
- board position), last (last army man's board position), fp (forward
- pointer to the next army), bp (backward pointer to the previous army),
- lib (liberties), friend (number of bordering friendly stones), enemy
- (number of bordering enemy stones), armies (number of neighboring
- non-blank armies -- not implemented yet), and rollcall (scratchpad
- variable). For blank armies the number of liberties is not used, the
- number of friendly stones is the number of neighboring white stones, and
- the number of enemy stones is the number of neighboring black stones.
- For non-blank armies the number of friendly stones is not used.
- ________________________________________________________________________
-
- The following additional data structures are used by these programs and
- also made available for convenience, as follows:
-
- neighbors - This structure contains the output of the getneighbors
- procedure: the number and position of non-blank neighbors to a
- specified 1-dimensional position, sorted by army number (which makes it
- easier to tell if different neighbors are in the same army).
-
- neighborcount - This array is used with the game.neibrd array to quickly
- determine how many valid neighboring positions there are to a given
- stone position. This array, neighborcount[0..15], merely translates a
- binary number from 0 to 15 into the number of bits that are set in that
- binary number.
-
- mstatus - This structure contains ko information and capture information
- based on the last stone played on the board.
-
- The ko position (movestatus.kospot) is set by the capture procedure to
- the 1-dimensional position of a 1-man army that was just captured. If
- no army was captured by the last move then this variable is set to -1.
- Also if the size of the captured army is greater than one then this
- variable is set to -1. The addastone procedure sets this variable to
- -1, but the addastone procedure calls the capture procedure if a capture
- is made by a move.
-
- The capture information (movestatus.captures) is set by the addastone
- procedure to reflect which of the four possible armies surrounding the
- new stone was captured. This variable is bit encoded.
- _________________________________________________________________________
-
- To use all of the above utility programs and data structures the
- following C code is necessary:
-
- #include <goprocs.h>
- #include <gomoves.h>
-
- The following C code creates/allocates a game structure called g at
- compile time (this is the responsibility of the user):
-
- game g;
-
- Black, White, and Blank are C parameters that define the only valid
- states of a board position. Black and White define the only valid
- stone colors and player designations. The following C code changes
- the designated player in the game structure pointed to by g:
-
- g->who = otherside[g->who];
-
- The following C code will walk through all armies (black,white, and blank),
- given a game structure pointer (g):
-
- int armynumber;
- armynumber = mygame.army[mygame.avail].bp; /* back pointer is first army */
- while (armynumber > 0) {
- if (mygame.army[armynumber].size > 0) {
- (* code to process each army goes here *)
- }
- armynumber = mygame.army[armynumber].bp;
- }
-
- The following C code will walk through an army, given a game structure
- pointer (g) and the position of any stone in the army (s):
-
- int stone;
- stone = g->army[g->armymen[s]].first; /* first man in army */
- while (stone >= 0) {
- (* code to process each army man goes here *)
- stone = g->armylnk[stone]; /* next man in army */
- }
-
- The following C code will obtain the positions of the neighbors to a
- given stone position (s), given a game structure pointer (g) and visit
- each of the non-blank neighboring positions in order of their army number:
-
- neighbors nabor; int n;
- getneighbors(g,&nabor,s); /* get the neighbors */
- for (n = 0; n < nabor.neis; n++) { /* go through neighbors */
- if (g->board[s] != Blank) {
- (* code to process non-blank neighbors to stone s goes here *)
- } }
- ________________________________end of document___________________________
-
- /* File goprocs.h
- Developer: James R. Logan Jr. (BYU), Advisor: Dr. Lynn H. Beus (BYU)
- email address: loganj@byuvax.bitnet
- (801) 378-3617
-
- Structures required by the go program utilities.
- This code is not machine dependent.
- */
-
- #define firstelement 0
- #define brdsize 19
- #define maxstones 362
- #define maxarmies 362
- #define White 0
- #define Black 1
- #define Blank 2
-
- typedef struct {
- int
- color, /* army color */
- size, /* army size */
- first, /* first armyman's position */
- last, /* last armyman's position */
- fp, /* forward pointer to next army */
- bp, /* backward pointer to last army */
- lib, /* number of liberties, for nonblank armies only */
- friend, /* number of neighboring White stones, for blank armies only */
- enemy, /* number of enemy stones for nonblank armies, or Black stones */
- armies, /* number of neighboring armies */
- rollcall;/* scratch pad variable */
- } armystruct;
-
- typedef struct {
- int kospot; /* valid ko position, or -1, result of last move */
- long captures; /* bit 1 is capture on the west (left)
- bit 2 is capture on the east (right)
- bit 3 is capture on the south (down)
- bit 4 is capture on the north (up) */
- } mstatus;
-
- typedef struct {
- int
- who, /* White for computer's level, Black for opponent */
- avail, /* next available army number */
- maxstone, /* size of 1-dimensional board */
- width, /* width of 1-dimensional board */
- movecount,/* number of stones played on the board */
- deadwhite,/* number of captured white stones */
- deadblack,/* number of captured black stones */
- debug; /* debug flags */
- char
- board[maxstones], /* computer = White, opponent = Black */
- rowbrd[maxstones], /* translates 1-dimension row to 2-dimension */
- colbrd[maxstones], /* translates 1-dimension col to 2-dimension */
- whitecount[maxstones],/* count of white stones in whitepats */
- blackcount[maxstones];/* count of black stones in blackpats */
- int
- armymen[maxstones], /* men of same army have same num */
- armylnk[maxstones]; /* link to next army member */
- long
- whitepats[maxstones],/* bit pattern of white stones in 5 by 5 square */
- blackpats[maxstones],/* bit pattern of black stones in 5 by 5 square */
- neibrd[maxstones]; /* n by n bit encoded valid neighbors array */
- mstatus movestatus; /* ko position and capture info */
- armystruct army[maxarmies];
- } game;
-
- typedef struct {
- int
- neis,
- stone[4],
- direction[4];
- /* bit 1 is neighbor on the west (left)
- bit 2 is capture on the east (right)
- bit 3 is capture on the south (down)
- bit 4 is capture on the north (up) */
- } neighbors;
- /* File gomoves.h
- Developer: James R. Logan Jr. (BYU), Advisor: Dr. Lynn H. Beus (BYU)
- email address: loganj@byuvax.bitnet
- (801) 378-3617
- */
-
- #define maxsons 5 /* maximum depth of alpha-beta tree */
- #define maxlevs 5 /* must be odd, maximizing level for best odds? */
-
- typedef struct {
- int s,pv; /* alpha beta stone position and board value */
- } nodestruct;
-
- typedef struct { /* children of node in alpha-beta tree */
- int nodepnt,nodecnt;
- mstatus status; /* board status resulting from stone */
- nodestruct nodes[maxsons];
- } sons;
- /* File gomain.c
- Developer: James R. Logan Jr. (BYU), Advisor: Dr. Lynn H. Beus (BYU)
- email address: loganj@byuvax.bitnet
- (801) 378-3617
-
- This procedure provides the interface between the Mac and the operator.
- This code is machine dependent.
- */
-
- #include <qd.h>
- #include <win.h>
- #include <menu.h>
- #include <event.h>
- #include <te.h>
- #include <stdio.h>
- #include <goprocs.h>
-
- #define lastmenu 5
- #define applemenu 1
- #define filemenu 256
- #define gamemenu 257
- #define playermenu 258
- #define displaymenu 259
-
- FILE *fp,*gp;
- windowptr whichwindow;
- menuhandle mymenus[lastmenu+1];
- boolean doneflag,temp;
- eventrecord myevent;
- long blinktime;
- int code,refnum;
- int themenu,theitem,
- activeplayer,blinkstate,blinkcolor,blinkstone,drawnumber,
- lookahead,play,playfile,stonestate;
-
- game mygame;
-
- extern initgame();
- extern int addastone(),moves();
- extern char coltable[19];
- extern int otherside[2];
- extern windowptr mewindow,mywindow;
-
- setupmenus() {
- int i;
- char appletitle[2];
- initmenus();
- appletitle[0] = applemark; appletitle[1] = 0;
- mymenus[1] = newmenu(applemenu, appletitle);
- addresmenu(mymenus[1], "DRVR");
- mymenus[2] = newmenu(filemenu, "Directives");
- appendmenu(mymenus[2], "Pass;Change Sides;Log to File;Play Log File;Quit");
- mymenus[3] = newmenu(gamemenu, "Game");
- appendmenu(mymenus[3], "Initialize;Begin or Resume;Pause");
- mymenus[4] = newmenu(playermenu, "Players");
- appendmenu(mymenus[4], "Computer Vs Computer;Computer Vs Human;Human Vs Human"
- );
- mymenus[5] = newmenu(displaymenu, "Display");
- appendmenu(mymenus[5],
- "Look Ahead Moves;Stone Numbers;Procedures;Stones;Stone Armies;Stone Links;S
- tone Patterns;Position Values;Army Info");
- for (i=1; i<=lastmenu; i++) insertmenu(mymenus[i], 0);
- drawmenubar();
- drawnumber = 1;
- checkitem(mymenus[5],2,1);
- lookahead = 0;
- activeplayer = 1;
- checkitem(mymenus[4],activeplayer,1);
- }
-
- docommand(themenu, theitem) int themenu, theitem; {
- char name[256];
- int i;
- switch (themenu) {
- case applemenu:
- getitem(mymenus[1], theitem, name);
- refnum = opendeskacc(name);
- break;
- case filemenu:
- switch (theitem) {
- case 1: /* pass */
- if (play == 0) {
- if ((activeplayer == 2) || (activeplayer == 3)) {
- mygame.who = otherside[mygame.who];
- if (activeplayer == 2) {
- play = 1;
- } else {
- if (mygame.who == White) printf(" White's turn ...\n");
- else printf(" Black's turn ...\n");
- }
- }
- }
- break;
- case 2: /* change sides */
- mygame.who = otherside[mygame.who];
- if (mygame.who == White) printf(" White's turn ...\n");
- else printf(" Black's turn ...\n");
- break;
- case 3:
- if (fp == NULL) {
- checkitem(mymenus[2],3,1);
- createfile();
- } else {
- checkitem(mymenus[2],3,0);
- fclose(fp); fp = NULL;
- }
- break;
- case 4:
- if (gp == 0) {
- if (activeplayer == 2) blinkoff();
- replay();
- if (gp != 0) {
- checkitem(mymenus[2],4,1);
- play = 1;
- playfile = 1;
- }
- } else {
- checkitem(mymenus[2],4,0);
- if (gp != NULL) fclose(gp); gp = NULL;
- play = 0;
- playfile = 0;
- mygame.who = otherside[mygame.who];
- if (mygame.who == White) printf(" White's turn ...\n");
- else printf(" Black's turn ...\n");
- if (activeplayer == 2) blinkon();
- }
- break;
- case 5:
- if (fp != NULL) { fclose(fp); fp = NULL; }
- if (gp != NULL) { fclose(gp); gp = NULL; }
- doneflag = 1;
- break;
- }
- break;
- case gamemenu:
- switch (theitem) {
- case 1:
- play = 0;
- if (playfile != 0) {
- checkitem(mymenus[2],4,0);
- if (gp != NULL) fclose(gp); gp = NULL;
- playfile = 0;
- }
- blinkoff();
- boardsize(&mygame);
- if (activeplayer == 1) {
- if (mygame.who == White) printf(" White's turn ...\n");
- else printf(" Black's turn ...\n");
- } else if (activeplayer == 2) {
- blinkon();
- printf(" Your turn ...\n");
- } else if (activeplayer == 3) printf(" Black's turn ...\n");
- break;
- case 2:
- if ((playfile != 0) || (activeplayer == 1)) play = 1;
- else if (activeplayer == 2) printf(" Your turn ...\n");
- else if (mygame.who == White) printf(" White's turn ...\n");
- else printf(" Black's turn ...\n");
- break;
- case 3: play = 0; break;
- }
- break;
- case playermenu:
- switch (theitem) {
- case 1:
- if (activeplayer == 2) blinkoff();
- checkitem(mymenus[4],activeplayer,0);
- activeplayer = 1;
- checkitem(mymenus[4],activeplayer,1);
- break;
- case 2:
- play = 0;
- blinkstone = -1;
- checkitem(mymenus[4],activeplayer,0);
- activeplayer = 2;
- checkitem(mymenus[4],activeplayer,1);
- break;
- case 3:
- play = 0;
- if (activeplayer == 2) blinkoff();
- checkitem(mymenus[4],activeplayer,0);
- activeplayer = 3;
- checkitem(mymenus[4],activeplayer,1);
- break;
- }
- break;
- case displaymenu:
- switch (theitem) {
- case 1:
- lookahead = 1 - lookahead;
- checkitem(mymenus[5],1,lookahead);
- break;
- case 2:
- drawnumber = 1 - drawnumber;
- checkitem(mymenus[5],2,drawnumber);
- break;
- case 3:
- if ((mygame.debug & 1) == 0) {
- mygame.debug |= 1;
- checkitem(mymenus[5],3,1);
- } else {
- mygame.debug &= ~1;
- checkitem(mymenus[5],3,0);
- }
- break;
- case 4: moveboard(&mygame); break;
- case 5: armyboard(&mygame); break;
- case 6: linkinfo(&mygame); break;
- case 7: pictinfo(&mygame); break;
- case 8: valueboard(&mygame); break;
- case 9: armyinfo(&mygame); break;
- } }
- hilitemenu(0);
- }
-
- stoneon() {
- if ((stonestate == 0) && (blinkstone >= 0))
- drawstone(&mygame,blinkstone,blinkcolor);
- stonestate = 1;
- }
-
- stoneoff() {
- if ((stonestate != 0) && (blinkstone >= 0))
- undrawstone(&mygame,blinkstone);
- stonestate = 0;
- }
-
- blinkon() {
- /* Turn on the blink'n blinker if no look ahead in progress. */
- if (lookahead == 0) {
- blinkstate = 1;
- blinktime = tickcount();
- } }
-
- blinkoff() { blinkstate = 0; stoneon(); }
-
- blink() {
- /* This procedure does the actual blinking of the last stone played */
- long now;
- if (blinkstate != 0) {
- now = tickcount();
- if (now > blinktime + 20) {
- if (stonestate != 0) stoneoff(); else stoneon();
- blinktime = now;
- } } }
-
- main() {
- /* This procedure provides the interface between the Mac and the
- operator */
- int i,s;
- extern struct qdvar { char dummy[202]; grafptr qdtheport;} qdvars;
- #define theport (qdvars.qdtheport)
-
- openresfile("clock");
- initgraf(&theport);
- initfonts();
- flushevents(everyevent, 0);
- initwindows();
- setupmenus();
- initdialogs(0L);
- initcursor();
-
- doneflag = 0; play = 0; playfile = 0; blinkstone = -1;
- mygame.debug = 0;
- mygame.width = 19;
- fp = NULL; gp = NULL;
- initgame(&mygame);
-
- do {
- systemtask();
- blink();
- temp = getnextevent(everyevent, &myevent);
- switch (myevent.what) {
- case mousedown:
- code = findwindow(&myevent.where, &whichwindow);
- switch (code) {
- case inmenubar:
- docommand(menuselect(&myevent.where)); break;
- case insyswindow:
- systemclick(&myevent, whichwindow); break;
- case indrag:
- break;
- case ingrow:
- case incontent:
- if ((play == 0) &&
- ((playfile != 0) || (activeplayer == 2) || (activeplayer == 3))) {
- if (whichwindow == mywindow) {
- blinkoff();
- setport(mywindow);
- globaltolocal(&myevent.where);
- setport(mewindow);
- /* place a stone on the board */
- s = (mygame.width - 1 - ((myevent.where.a.v - 2) / 16));
- if (s < 0) s = 0;
- if (s >= mygame.width) s = mygame.width - 1;
- s = s * mygame.width;
- i = (myevent.where.a.h - 2) / 16;
- if (i < 0) i = 0;
- if (i >= mygame.width) i = mygame.width - 1;
- s = s + i;
- s = addastone(&mygame,s);
- if (s >= 0) {
- if (mygame.who == White) printf(" White to %c,%d\n",
- coltable[mygame.colbrd[s]],mygame.rowbrd[s]);
- else printf(" Black to %c,%d\n",
- coltable[mygame.colbrd[s]],mygame.rowbrd[s]);
- if (activeplayer == 2) play = 1;
- mygame.who = otherside[mygame.who];
- if (mygame.who == White) printf(" White's turn ...\n");
- else printf(" Black's turn ...\n");
- } else {
- if (mygame.who == White) printf(" Still White's turn ...\n");
- else printf(" Still Black's turn ...\n");
- }
- }
- }
- break;
- /* goaway box is on the modify window only, so save the changes to the
- letter being modified and take down the modify window */
- case ingoaway: break;
- }
- break;
- case mouseup: break;
- case keydown:
- case autokey:
- /* draw_text((char) (255 & myevent.message)); */
- break;
- case activateevt: break;
- case updateevt:
- /* setport(mywindow);
- beginupdate(mywindow);
- endupdate(mywindow);*/
- break;
- }
- if (doneflag == 0) {
- if (gp == NULL) {
- if (playfile != 0) {
- playfile = 0;
- checkitem(mymenus[2],4,0);
- }
- if (((activeplayer == 1) || (activeplayer == 2)) && (play != 0)) {
- blinkcolor = mygame.who;
- blinkstone = moves(&mygame);
- if (mygame.who == White) printf(" White's turn ...\n");
- else printf(" Black's turn ...\n");
- if (activeplayer == 2) {
- play = 0;
- blinkon();
- } }
- } else if (play != 0) replay();
- }
- } while (doneflag == 0);
- }
- /* File go.c
- Developer: James R. Logan Jr. (BYU), Advisor: Dr. Lynn H. Beus (BYU)
- email address: loganj@byuvax.bitnet
- (801) 378-3617
-
- These routines and the routines in gomoves.c determine the strategy of
- the go program. This code is not machine dependent.
- */
-
- #include <qd.h>
- #include <pack.h>
- #include <win.h>
- #include <dialog.h>
- #include <stdio.h>
- #include <goprocs.h>
- #include <gomoves.h>
-
- extern char coltable[19];
- extern int activeplayer,blinkstone,looking,play,otherside[2];
- extern game mygame;
- extern int addastone();
- extern initialize(),removeastone(),capture(),uncapture(),
- getneighbors(),allarmies(),linkarmies(),buildarmies(),
- armymerge(),topicture(),frompicture(),moveboard(),
- armyboard(),linkinfo(),armyinfo(),pictinfo(),neighborinfo();
-
- overlay "gamestuff"
-
- #define allyweight 4
- #define blankweight 1
- #define enemyweight 2
- #define libertiesweight 1
- #define squareweight 4
-
- #define edgevalue 1
- #define openvalue 2 /* ordinary unoccupied square, not on edge */
- #define cornervalue 10
- #define connectvalue 3
- #define midneivalue 6
- #define midrowvalue 8
- #define row3value 4
- #define row5value 3
-
- pattern greypat = {0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92};
-
- rect screenrect;
- windowrecord merecord,myrecord,drecord;
- windowptr mewindow,mywindow = {0L},dummywindow;
-
- sons root[maxlevs];
-
- mstatus status;
-
- int
- init[maxstones],value[maxstones], /* initial position values */
- color,stone,nextmove,passcount,
- searchdepth = {1},searchwidth = {1},work;
-
- initgame(g) game *g; {
- int i,j,brdsze;
- char dummyscreen[20000];
- if (mywindow == 0L) {
- /* calculate the size of the window for the game board, and display */
- brdsze = 16 + 8 * (g->width - 1);
- setrect(&screenrect,351-brdsze,181-brdsze,351+brdsze,181+brdsze);
- mywindow = newwindow(&myrecord, &screenrect, "", 1, 2,
- (long)-1, 0, (long)0);
- dummywindow = newwindow(&drecord, &screenrect, "", 0, 2,
- (long)-1, 1, (long)0);
- drecord.port.portbits.baseaddr = &dummyscreen;
- setrect(&screenrect, 0, 21, 188, 340);
- mewindow = newwindow(&merecord, &screenrect, "", 1, 2,
- (long)-1, 0, (long)0);
- } else {
- disposewindow(mywindow);
- brdsze = 16 + 8 * (g->width - 1);
- setrect(&screenrect,351-brdsze,181-brdsze,351+brdsze,181+brdsze);
- mywindow = newwindow(&myrecord, &screenrect, "Go", 1, 3,
- (long)-1, 0, (long)0);
- }
- if ((g->debug & 1) != 0) { printf("Initgame: \n"); }
- setport(mywindow);
- textmode(srcxor);
- backpat(&greypat);
- setorigin(-12,0);
- brdsze = 4 + 16 * g->width;
- setrect(&screenrect,0,0,400,brdsze);
- eraserect(&screenrect);
- setport(mewindow);
- textsize(9);
- initialize(g); /* initialize the game structure for the go procs */
- g->who = Black; /* first move is black's */
- passcount = 0; /* number of consecutive passes in the game */
- blinkstone = -1; /* indicate no stone to blink yet */
- /* set the initial value of each position, first the whole board */
- for (i = firstelement; i < g->maxstone; i++) { init[i] = openvalue; }
- /* set the initial value of the edges of the board */
- j = firstelement;
- for (i = firstelement; i < g->width; i++) {
- init[j] = edgevalue; init[j+g->width-1] = edgevalue;
- init[i] = edgevalue; init[g->maxstone-g->width+i] = edgevalue;
- j = j + g->width;
- }
- /* Set the initial value for row 3 all around the board */
- if (g->width >= 7) {
- j = 2*g->width+3;
- for (i = firstelement; i < g->width-6; i++) {
- init[j] = row3value; init[g->maxstone-j-1] = row3value;
- j = j + 1; }
- j = 3*g->width+2;
- for (i = firstelement; i < g->width-6; i++) {
- init[j] = row3value; init[j+g->width-5] = row3value;
- j = j + g->width; }
- }
- /* Set the value for the middle of row 3 around the edge of the board */
- if (g->width >= 9) {
- j = (2*g->width)+(g->width/2);
- init[j] = midrowvalue;
- init[g->maxstone-1-j] = midrowvalue;
- j = ((g->width / 2) * g->width) + 2;
- init[j] = midrowvalue;
- init[g->maxstone-1-j] = midrowvalue;
- }
- /* Set the initial value for row 5 all around the board, but not in 5 corner */
- if (g->width >= 11) {
- j = 4*g->width+5;
- for (i = firstelement; i < g->width-10; i++) {
- init[j] = row5value; init[g->maxstone-j-1] = row5value;
- j = j + 1; }
- j = 5*g->width+4;
- for (i = firstelement; i < g->width-10; i++) {
- init[j] = row5value; init[j+g->width-9] = row5value;
- j = j + g->width; }
- }
- /* Set the initial value for 3 rows in from each corner */
- if (g->width >= 5) {
- init[2*g->width+2] = cornervalue;
- init[3*g->width-3] = cornervalue;
- init[g->maxstone-2*g->width-3] = cornervalue;
- init[g->maxstone-3*g->width+2] = cornervalue;
- }
- /* Set the initial value for 2 jump neighbors from mid row 3 */
- if (g->width == 19) {
- init[44] = midneivalue; init[50] = midneivalue;
- init[116] = midneivalue; init[130] = midneivalue;
- init[230] = midneivalue; init[244] = midneivalue;
- init[310] = midneivalue; init[316] = midneivalue;
- }
- init[0] = 0; init[g->width-1] = 0;
- init[g->maxstone-g->width] = 0; init[g->maxstone-1] = 0;
- if ((g->debug & 1) != 0) { printf("Initgame end.\n"); }
- }
-
- int moves(g) game *g; {
- /* This procedure receives control when the computer needs to make a move,
- and returns the 1-dimensional position selected by the computer.
- If g->who == White a move is computed for the computer, else a move is
- computed for the opponent. A legal move is always added to the board */
- int s; sons *sonsp;
- alphabeta(); /* look ahead for the best move */
- if (nextmove >= 0) {
- s = addastone(g,nextmove); /* add this move to the game board */
- if (s >= 0) {
- if (g->who == White) printf(" White to %c,%d\n",
- coltable[g->colbrd[s]],g->rowbrd[s]);
- else printf(" Black to %c,%d\n",
- coltable[g->colbrd[s]],g->rowbrd[s]);
- }
- passcount = 0;
- } else {
- s = -1;
- if (activeplayer == 1) passcount = passcount + 1;
- if (g->who == White) printf(" White passes\n");
- else printf(" Black passes\n");
- }
- g->who = otherside[g->who];
- if ((activeplayer == 1) && (passcount >= 2)) {
- play = 0;
- printf(" Play stopped after two passes!\n");
- }
- return s;
- }
-
- alphabeta() {
- /* This procedure is the top level of the alpha-beta cutoff look ahead
- procedure. Alpha and beta are initialized here. */
- int a,b,dummy; int sonsp;
- looking = 1; /* indicate look ahead in progress */
- nextmove = -1; /* default next move is a pass */
- sonsp = 0; /* point to root of tree */
- a = -9999; b = 9999; /* alpha-beta initialization */
- dummy = abcontrol (sonsp,a,b,mygame.who);
- looking = 0;
- }
-
- int abcontrol (tr,a,b,wh) int tr,a,b,wh; {
- /* This procedure performs the actual alpha-beta search. Inputs are
- tree level, Alpha, Beta, and who's move it is. The present
- implementation does not dynamically allocate the tree. */
- int ta,tb,ev,junk,r,c,v;
- if (tr >= searchdepth) { /* last level of tree? */
- ev = eval(searchdepth); /* yes, compute the position value */
- if ((mygame.debug & 0xF) != 0) {
- printf("\nabcontrol - level, node, value: %d %d %d\n",
- searchdepth-1,root[searchdepth-1].nodepnt-1,ev);
- }
- return (ev); /* return the best position value */
- } else if (wh == mygame.who) { /* for maximizing level */
- bestmoves(&mygame,tr); /* fill in the best moves */
- while ((root[tr].nodepnt < root[tr].nodecnt) && (a < b)) {
- junk = addastone(&mygame,root[tr].nodes[root[tr].nodepnt].s);
- root[tr].status = mygame.movestatus;
- root[tr].nodepnt = root[tr].nodepnt + 1;
- ta = abcontrol (tr + 1, a, b, otherside[wh]);
- if (ta > a) {
- a = ta; /* new alpha value */
- if (tr <= 0) { nextmove = root[tr].nodes[root[tr].nodepnt-1].s; }
- }
- removeastone(&mygame,root[tr].nodes[root[tr].nodepnt-1].s,root[tr].status)
- ;
- }
- return (a);
- } else { /* for minimizing level */
- bestmoves(&mygame,tr); /* fill in the best moves */
- while ((root[tr].nodepnt < root[tr].nodecnt) && (a < b)) {
- mygame.who = wh; /* change sides */
- junk = addastone(&mygame,root[tr].nodes[root[tr].nodepnt].s);
- root[tr].status = mygame.movestatus;
- mygame.who = otherside[mygame.who]; /* change sides back */
- root[tr].nodepnt = root[tr].nodepnt + 1;
- tb = abcontrol (tr + 1, a, b, otherside[wh]);
- if (tb < b) { b = tb; } /* new beta value */
- removeastone(&mygame,root[tr].nodes[root[tr].nodepnt-1].s,root[tr].status)
- ;
- }
- return (b);
- }
- }
-
- int eval(sonsp) int sonsp; {
- /* This procedure evaluates the worth of look ahead moves during the alpha
- beta search - not a well defined process. Need a lot of work here!
- The game structure fields don't seem to represent enough higher level
- (human) abstractions to play a good game yet. The evaluation here
- is based on the number of armies, eyes, and total number of liberties
- for both sides. Variables beginning with an 'a' are ally values, 'e' are
- enemy values. */
- int n,v,pv,allies,enemies,alibs,elibs,wh,tb;
- if ((mygame.debug & 1) != 0) { printf("eval: \n"); }
- pv = 0; allies = 0; enemies = 0; alibs = 0; elibs = 0;
- wh = 1;
- for (tb = 0; tb < sonsp; tb++) { /* traverse the tree */
- pv = pv + root[tb].nodes[root[tb].nodepnt-1].pv * wh;
- tb = tb + 1;
- wh = -wh; /* switch players at each level of the tree */
- }
- n = mygame.army[mygame.avail].bp; /* visit each army */
- while (n > 0) {
- if (mygame.army[n].size > 0) {
- if (mygame.army[n].color == Blank) { /* blank army is an eye? */
- if (mygame.army[n].enemy <= 0) {
- if (mygame.who == White) allies = allies + 1; /* ally eyes */
- else enemies = enemies + 1; /* enemy eyes */
- } else if (mygame.army[n].friend <= 0) {
- if (mygame.who == White) enemies = enemies + 1;/* ally eyes */
- else allies = allies + 1; /* enemy eyes */
- }
- } else if (mygame.army[n].color == mygame.who) {
- alibs = alibs + mygame.army[n].lib;
- } else {
- elibs = elibs + mygame.army[n].lib;
- }
- }
- n = mygame.army[n].bp;
- }
- v = allies * allyweight - enemies * enemyweight +
- libertiesweight * alibs - libertiesweight * elibs +
- pv * squareweight;
- if ((mygame.debug & 1) != 0) { printf("eval.\n"); }
- return (v);
- }
-
- boardsize(g) game *g; {
- /* This procedure handles the game initialization dialog */
- int the_item,item_type,value;
- handle item_handle;
- rect drect,item_box;
- char item_text[64];
- dialogptr mydialog;
- setrect(&drect,-16,28,440,200);
- copybits(&mywindow->portbits,&dummywindow->portbits,
- &drect,&drect,srccopy,(long)0);
- mydialog = getnewdialog(9507,(long) 0,(long)-1);
- getditem(mydialog,3,&item_type,&item_handle,&item_box);
- sprintf(item_text,"%d",g->width);
- setitext(item_handle,item_text);
- getditem(mydialog,4,&item_type,&item_handle,&item_box);
- sprintf(item_text,"%d",searchwidth);
- setitext(item_handle,item_text);
- getditem(mydialog,5,&item_type,&item_handle,&item_box);
- sprintf(item_text,"%d",searchdepth);
- setitext(item_handle,item_text);
- do {
- modaldialog((long) 0,&the_item);
- if (the_item == 1) {
- getditem(mydialog,3,&item_type,&item_handle,&item_box);
- getitext(item_handle,&item_text);
- sscanf(item_text,"%d",&value);
- if ((value > 2) && (value < 20)) g->width = value;
- getditem(mydialog,4,&item_type,&item_handle,&item_box);
- getitext(item_handle,&item_text);
- sscanf(item_text,"%d",&value);
- if ((value > 0) && (value <= maxsons)) searchwidth = value;
- getditem(mydialog,5,&item_type,&item_handle,&item_box);
- getitext(item_handle,&item_text);
- sscanf(item_text,"%d",&value);
- if ((value > 0) && (value <= maxlevs)) searchdepth = value;
- }
- } while ((the_item != 1) && (the_item != 2));
- closedialog(mydialog);
- copybits(&dummywindow->portbits,&mywindow->portbits,
- &drect,&drect,srccopy,(long)0);
- if (the_item == 1) initgame(g);
- }
-
- valueboard(g) game *g; {
- int i,s;
- s = 0;
- while (s < g->maxstone) {
- for (i = firstelement; i < g->width; i++) { printf("%3d",value[s]); s = s +
- 1; }
- printf("\n");
- } }
- /* File gomoves.c
- Developer: James R. Logan Jr. (BYU), Advisor: Dr. Lynn H. Beus (BYU)
- email address: loganj@byuvax.bitnet
- (801) 378-3617
-
- This routine determines the best n moves available when a move is
- being selected by the computer. This code is not machine dependent.
- */
-
- #include <goprocs.h>
- #include <gomoves.h>
-
- #define maxsons 5
- #define maxlevs 5 /* must be odd, maximizing level for best odds */
-
- #define allyweight 4
- #define blankweight 1
- #define enemyweight 2
- #define libertiesweight 1
- #define squareweight 4
-
- /* The following 32 bit values represent patterns in a 5 by 5 diamond shape,
- centered around a given board position (s). Only 29 bits are actually
- used, 25 bits for a 5 by 5 square and 4 bits at the center of each
- outside edge. The area covered and bits represented are as follows:
-
- * 28
- * * * * * 5 4 3 2 1
- * * * * * 10 9 8 7 6
- * * * S * * * 27 15 14 13 12 11 26
- * * * * * 20 19 18 17 16
- * * * * * 25 24 23 22 21
- * 29
- */
- #define square3 0x739C0L
- #define square5 0x0E8C62EL
- #define diamond5 0x477DC4L
- #define circle7 0x1F100011L
-
- #define firstmoves 17 /* number of moves before middle game */
-
- #define attackvalue 14
- #define circle7value 2
- #define edgevalue 1
- #define edgecutvalue 10
- #define edgejoinvalue 16
- #define openvalue 2 /* ordinary unoccupied square, not on edge */
- #define capturevalue 24
- #define cornervalue 10
- #define connectvalue 3
- #define cutvalue 3
- #define hitarivalue 18
- #define invadevalue 20 /* must be 4 less than capture value */
- #define midneivalue 6
-
- #define midrowvalue 8
- #define protvalue 24
- #define retreatsize 18
- #define row3value 4
- #define row5value 3
- #define square5value 1
- #define runtoedgevalue 12
- #define territoryvalue 4
-
- extern sons root[maxlevs];
- extern int
- otherside[2],
- init[maxstones],value[maxstones], /* initial position values */
- searchdepth,searchwidth;
-
- bestmoves(g,sonsp) game *g; int sonsp; {
- /* This procedure determines the best n moves available using a point
- scheme with weights for different patterns and situations. This
- routine does not explicitly check the validity of each move (bad
- moves are possible if the weights are not properly set. */
- char *enmcount,*fricount;
- int a1,a2,blankfris,blankenms,frilibs,lastus,lastthem,
- ha,pa,snapstone,snaplibs,i,n,s,s1,us,them,
- captsize,protsize,totallibs,hitarisize,hitarisave,neiarms,neienms,node;
- long fripats,enmpats,neipats;
- neighbors nabor,nextnabor;
- /* First initialize all the best moves to pass */
- if ((g->debug & 1) != 0) { printf("bestmoves: \n"); }
- root[sonsp].nodecnt = 0; root[sonsp].nodepnt = 0;
- for (node = firstelement; node < searchwidth; node++) {
- root[sonsp].nodes[node].pv = 0;
- root[sonsp].nodes[node].s = -1; /* default is to pass */
- }
- /* Evaluate each square of the board and assign a value to it */
- for (i = firstelement; i < g->maxstone; i++) {
- value[i] = 0; /* default is not blank, so no value */
- if ((g->board[i] == Blank) && (i != g->movestatus.kospot)) {
- neipats = g->neibrd[i];
- a1 = g->armymen[i]; /* blank army number */
- if (g->who == White) {
- fricount = &g->whitecount[0]; enmcount = &g->blackcount[0];
- fripats = g->whitepats[i]; enmpats = g->blackpats[i];
- blankfris = g->army[a1].friend; blankenms = g->army[a1].enemy;
- } else {
- fricount = &g->blackcount[0]; enmcount = &g->whitecount[0];
- fripats = g->blackpats[i]; enmpats = g->whitepats[i];
- blankfris = g->army[a1].enemy; blankenms = g->army[a1].friend;
- }
- getneighbors(g,&nabor,i); /* get the neighbors */
- if ((g->army[a1].size > g->maxstone-4) ||
- ((blankfris > 0) && (blankenms > 0))) {
- if ((init[i] > openvalue) &&
- (((fripats & square3) != 0) || ((enmpats & square3) != 0)) ) {
- value[i] = openvalue;
- } else {
- value[i] = init[i]; /* default value */
- }
- }
- /* territory value, more territory value for empty diamonds
- some code was removed here too */
- if (((fripats & diamond5) == 0) &&
- ((enmpats & diamond5) == 0) &&
- ((neipats & 0x0F0) == 0x0F0)) {
- value[i] = value[i] + territoryvalue;
- } else {
- us = 0; them = 0; captsize = 0; protsize = 0;
- lastus = -1; lastthem = -1; totallibs = g->army[a1].size - 1;
- frilibs = 0; hitarisize = 0; hitarisave = 0;
- neiarms = 0; neienms = 0; ha = -1; pa = -1;
- for (n = firstelement; n < nabor.neis; n++) { /* count new army neighbor
- s */
- s = nabor.stone[n]; /* neighbors row & column */
- a2 = g->armymen[s]; /* neighbor army number */
- if (g->board[s] == Blank) {
- frilibs = frilibs + 1;
- } else {
- if (g->army[a2].color == g->who) {
- frilibs = frilibs + g->army[a2].lib - 1;
- totallibs = totallibs + g->army[a2].lib - 1;
- }
- if (g->army[a2].lib == 1) {
- if (g->army[a2].color == g->who) {
- protsize = protsize + g->army[a2].size;
- pa = a2;
- } else {
- captsize = captsize + g->army[a2].size;
- }
- /* Check for hitari ...
- If the enemy can be hitari'd add in the points, if we can be hitari'd
- add in the points if we can protect against hitari without using up
- our eyes and if the blank army has more of our stones as neighbors */
- } else if (g->army[a2].lib == 2) {
- if (g->army[a2].color == otherside[g->who]) {
- hitarisize = hitarisize + g->army[a2].size;
- } else if ((g->army[a2].color == g->who) &&
- (g->army[a1].enemy > 0) && (blankfris > 1)) {
- hitarisave = hitarisave + g->army[a2].size;
- ha = a2;
- }
- }
- /* Don't count neighbors in the same amry more than once in neiarms,
- and don't count armies in trouble */
- if (g->board[s] == g->who) {
- us = us + 1;
- if (((lastus < 0) || (a2 != lastus)) &&
- (a2 != ha)) {
- neiarms = neiarms + 1;
- lastus = a2;
- }
- } else {
- them = them + 1;
- if ((lastthem < 0) || (a2 != lastthem)) {
- neienms = neienms + 1;
- lastthem = a2;
- }
- }
- }
- }
- /* This is the place! I cut lots of strategic code from here. If you want
- to improve the ability of this program to play go, this is the place to
- do it. */
-
-
- /* lower the value of a square controlled */
- if (((neipats & 0xF00) != 0xF00) && /* row 3 test */
- ((neipats & 0x0F0) == 0x0F0) &&
- (them > 0) && ((fripats & diamond5) == 0)) value[i] = 0;
- if ((us > 2) && (them <= 0)) { value[i] = 0; }
- if ((us > 1) && (neiarms < us)) { value[i] = 0; }
- if ((them > 2) && (us <= 0)) { value[i] = 0; }
- /* lower the value of a square that can be hitari'd on the next move */
- if ((us <= 0) && (them >= nabor.neis-2)) {
- value[i] = (value[i] / 2) - 1;
- }
- /* increase the value of a position that protects us from hitari, unless
- that position is already controlled by us */
- if ((hitarisave > 0) && (nabor.neis > 3) && (frilibs > 1) &&
- ((us < 3) || (them > 0))) {
- value[i] = value[i] + hitarisave + retreatsize + neiarms - us;
- }
- /* increase the value of a square that hitari's the enemy */
- if (hitarisize > 0) {
- if (frilibs > 1) {
- value[i] = value[i] + hitarisize - us;
- if (nabor.neis > 3) {
- value[i] = value[i] + hitarivalue;
- }
- } else if ((snaplibs > 0) && (snaplibs < 3)) {
- value[i] = value[i] + hitarisize + capturevalue +
- hitarivalue + neiarms + snaplibs;
- } }
- /* protect if we pick up at least 3 liberties, or 2 liberties without
- having to move on the edge of the board and without having to move
- into our eyes */
- if ((protsize > 0) && (blankfris > 1) &&
- ((frilibs > 2) || ((frilibs > 1) && (nabor.neis > 3)))) {
- value[i] = value[i] + protsize + protvalue - us;
- }
- /* don't move to the edge unless someone else is there */
- if (((fripats & square3) == 0) && (nabor.neis < 4)) { value[i] = 0; }
- /* lower the value of a square we are next to if the enemy is not near */
- if (((enmpats & square3) == 0) && ((fripats & square3) != 0)) {
- if (nabor.neis > 3) value[i] = value[i] / 2; else value[i] = 0;
- }
- /* Increase the value of moves that extend influence into unoccupied territory *
- /
- if ((g->movecount >= firstmoves) &&
- ((fripats & square3) == 0) && ((enmpats & square3) == 0)) {
- if (((fripats & square5) != 0) && ((enmpats & square5) != 0)) {
- value[i] = value[i] + square5value;
- } else if (((fripats & square5) == 0) && ((enmpats & square5) == 0)) {
- if (((fripats & circle7) != 0) && ((enmpats & circle7) != 0))
- value[i] = value[i] + circle7value;
- } }
- /* don't move to a square surrounded by enemy unless we have a capture */
- if (captsize > 0) {
- value[i] = value[i] + capturevalue + captsize;
- } else if (them >= nabor.neis) {
- value[i] = 0;
- }
- }
- /* There are three situations we move into: 1 is during the first
- moves of the game when a large blank army occupies most of the
- board; 2 is into a blank army that borders on computer and enemy
- stones; 3 is into an eye if the value high enough to indicate a
- capture or protection required, if not a KO situation. */
- if (value[i] > 0) {
- if ((i != g->movestatus.kospot) &&
- ((g->army[a1].size > g->maxstone-4) ||
- ((blankfris > 0) && (blankenms > 0)) ||
- (value[i] > invadevalue))) {
- s = i; node = firstelement;
- while ((node < searchwidth) && (s >= 0)) {
- if (value[s] > root[sonsp].nodes[node].pv) {
- root[sonsp].nodes[node].pv = value[s];
- s1 = root[sonsp].nodes[node].s; /* save the old value */
- root[sonsp].nodes[node].s = s; /* use the better value */
- s = s1; /* continue with old value */
- }
- node = node + 1;
- }
- root[sonsp].nodecnt = root[sonsp].nodecnt + 1;
- }
- }
- }
- }
- if (root[sonsp].nodecnt > searchwidth) { root[sonsp].nodecnt = searchwidth; }
- if ((g->debug & 1) != 0) { printf("bestmoves end.\n"); }
- }
- /* File goprocs.c
- Developer: James R. Logan Jr. (BYU), Advisor: Dr. Lynn H. Beus (BYU)
- BYU Computer Science
- 232 TMCB
- Provo, Utah 84602
- email address: loganj@byuvax.bitnet
- (801) 378-3617
-
- These procedures are go playing utility procedures that can be used by
- a go playing progam to do all the house keeping during a game of go.
- These procedures a based on a 1-dimensional representation of the game.
- This code is not machine dependent, except for the drawing routines at
- the end.
- */
-
- #include <qd.h>
- #include <win.h>
- #include <stdio.h>
- #include <goprocs.h>
-
- #define patwidth 5
-
- extern FILE *fp;
- extern int drawnumber,lookahead,otherside[2];
- extern windowptr mewindow,mywindow;
-
- overlay "gostuff"
-
- char coltable[19] = {'A','B','C','D','E','F','G','H','J','K','L','M','N','O','P'
- ,'Q','R','S','T'};
- int picset[29] =
- {0x50,0x41,0x40,0x42,0x60,
- 0x14,0x05,0x04,0x06,0x24,
- 0x10,0x01,0x00,0x02,0x20,
- 0x18,0x09,0x08,0x0A,0x28,
- 0x90,0x81,0x80,0x82,0xA0,
- 0x100,0x200,0x400,0x800};
- pattern whitepat = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
- pattern blackpat = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
-
- int looking,stonenumber,otherside[2],
- wrkbrd[maxstones];
-
- initialize (g) game *g; {
- /* This procedure initializes the game structure supplied by the caller */
- int i,j,r1,c1,w1,w2,w3,w4,w5,w6,w7,w8;
- if ((g->debug & 1) != 0) printf("initializing, board size %d.\n",g->width);
- /* initialize other side table */
- otherside[White] = Black; otherside[Black] = White;
- /* initialize game parameters */
- g->movecount = 0;
- g->deadwhite = 0; g->deadblack = 0;
- w1 = g->width; w2 = w1 + w1; w3 = w2 + w1; w4 = w3 + w1;
- w5 = w4 + w1; w6 = w5 + w1; w7 = w6 + 1; w8 = w7 + 1;
- g->maxstone = w1 * w1; g->movestatus.kospot = -1;
- /* initialize the neighbor board */
- for (i = firstelement; i < g->maxstone; i++) g->neibrd[i] = 0x0FFFFFFFFL;
- j = firstelement;
- for (i = firstelement; i < g->width; i++) {
- g->neibrd[j] = g->neibrd[j] & 0x0EEEEEEEEL;
- g->neibrd[j+w1-1] = g->neibrd[j+w1-1] & 0x0DDDDDDDDL;
- g->neibrd[i] = g->neibrd[i] & 0x0BBBBBBBBL;
- g->neibrd[g->maxstone-w1+i] = g->neibrd[g->maxstone-w1+i] & 0x077777777L;
- if (w1 > 1) {
- g->neibrd[j+1] = g->neibrd[j+1] & 0x0EEEEEEEFL;
- g->neibrd[j+w1-2] = g->neibrd[j+w1-2] & 0x0DDDDDDDFL;
- g->neibrd[i+w1] = g->neibrd[i+w1] & 0x0BBBBBBBFL;
- g->neibrd[g->maxstone-w2+i] = g->neibrd[g->maxstone-w2+i] & 0x07777777FL;
- }
- if (w1 > 2) {
- g->neibrd[j+2] = g->neibrd[j+2] & 0x0EEEEEEFFL;
- g->neibrd[j+w1-3] = g->neibrd[j+w1-3] & 0x0DDDDDDFFL;
- g->neibrd[i+w2] = g->neibrd[i+w2] & 0x0BBBBBBFFL;
- g->neibrd[g->maxstone-w3+i] = g->neibrd[g->maxstone-w3+i] & 0x0777777FFL;
- }
- if (w1 > 3) {
- g->neibrd[j+3] = g->neibrd[j+3] & 0x0EEEEEFFFL;
- g->neibrd[j+w1-4] = g->neibrd[j+w1-4] & 0x0DDDDDFFFL;
- g->neibrd[i+w3] = g->neibrd[i+w3] & 0x0BBBBBFFFL;
- g->neibrd[g->maxstone-w4+i] = g->neibrd[g->maxstone-w4+i] & 0x077777FFFL;
- }
- if (w1 > 4) {
- g->neibrd[j+4] = g->neibrd[j+4] & 0x0EEEEFFFFL;
- g->neibrd[j+w1-5] = g->neibrd[j+w1-5] & 0x0DDDDFFFFL;
- g->neibrd[i+w4] = g->neibrd[i+w4] & 0x0BBBBFFFFL;
- g->neibrd[g->maxstone-w5+i] = g->neibrd[g->maxstone-w5+i] & 0x07777FFFFL;
- }
- if (w1 > 5) {
- g->neibrd[j+5] = g->neibrd[j+5] & 0x0EEEFFFFFL;
- g->neibrd[j+w1-6] = g->neibrd[j+w1-6] & 0x0DDDFFFFFL;
- g->neibrd[i+w5] = g->neibrd[i+w5] & 0x0BBBFFFFFL;
- g->neibrd[g->maxstone-w6+i] = g->neibrd[g->maxstone-w6+i] & 0x0777FFFFFL;
- }
- if (w1 > 6) {
- g->neibrd[j+6] = g->neibrd[j+6] & 0x0EEFFFFFFL;
- g->neibrd[j+w1-7] = g->neibrd[j+w1-7] & 0x0DDFFFFFFL;
- g->neibrd[i+w6] = g->neibrd[i+w6] & 0x0BBFFFFFFL;
- g->neibrd[g->maxstone-w7+i] = g->neibrd[g->maxstone-w7+i] & 0x077FFFFFFL;
- }
- if (w1 > 7) {
- g->neibrd[j+7] = g->neibrd[j+7] & 0x0EFFFFFFFL;
- g->neibrd[j+w1-8] = g->neibrd[j+w1-8] & 0x0DFFFFFFFL;
- g->neibrd[i+w7] = g->neibrd[i+w7] & 0x0BFFFFFFFL;
- g->neibrd[g->maxstone-w8+i] = g->neibrd[g->maxstone-w8+i] & 0x07FFFFFFFL;
- }
- j = j + g->width;
- }
- /* initialize the row and column arrays */
- i = 0;
- r1 = 1;
- while (i < g->maxstone) {
- for (c1 = 0; c1 < g->width; c1++)
- { g->rowbrd[i] = r1; g->colbrd[i] = c1; i = i + 1; }
- r1 = r1 + 1;
- }
- for (i = firstelement; i < g->maxstone; i++) {
- g->board[i] = Blank; g->whitepats[i] = 0; g->blackpats[i] = 0;
- g->whitecount[i] = 0; g->blackcount[i] = 0;
- }
- allarmies(g); /* Create the armies */
- drawboard(g); /* display the game board */
- looking = 0; /* indicate not in look ahead now */
- stonenumber = 0;
- if ((g->debug & 1) != 0) printf("initialize end.\n");
- }
-
- int addastone(g,newstone) game *g; int newstone; {
- /* Clear the blank army for rebuilding, update any neighboring enemy
- armies directly, and do nothing for neighboring friendly armies.
- Friendly armies are merged and updated by linkarmies at the end. */
- int a1,a2,first,playedstone,n,s; neighbors nabor; mstatus oldstatus;
- playedstone = -1;
- a2 = -1;
- if ((newstone >= 0) && (newstone < g->maxstone) &&
- (newstone != g->movestatus.kospot) && (g->board[newstone] == Blank)) {
- g->movecount = g->movecount + 1;
- if (looking == 0) stonenumber = stonenumber + 1;
- oldstatus = g->movestatus; /* save the old status */
- g->board[newstone] = g->who;
- drawstone(g,newstone,g->who);
- g->movestatus.kospot = -1; /* clear the ko position */
- g->movestatus.captures = 0; /* clear captures */
- topicture(g,newstone);
- a1 = g->armymen[newstone]; /* old blank army number */
- first = g->army[a1].first; /* create link list of armies to relink */
- getneighbors(g,&nabor,newstone);
- a2 = -1;
- for (n = firstelement; n < nabor.neis; n++) {
- s = nabor.stone[n];
- if (g->board[s] != Blank) {
- a1 = g->armymen[s];
- if ((a1 != a2) && (g->army[a1].color == otherside[g->who])) {
- g->army[a1].enemy = g->army[a1].enemy + 1;
- g->army[a1].lib = g->army[a1].lib - 1;
- if (g->army[a1].lib <= 0) {
- capture(g,g->army[a1].first);
- g->movestatus.captures = g->movestatus.captures | nabor.direction[n]
- ;
- }
- }
- a2 = a1;
- } }
- linkarmies(g,first);
- /* If the added stone was illegal for lack of liberties then remove it */
- if (g->army[g->armymen[newstone]].lib <= 0) {
- if (g->who == White) printf(" Bad add by white at %c,%d\n",
- coltable[g->colbrd[newstone]],g->rowbrd[newstone]);
- else printf(" Bad add by black at %c,%d\n",
- coltable[g->colbrd[newstone]],g->rowbrd[newstone]);
- removeastone(g,newstone,g->movestatus);
- g->movestatus = oldstatus;
- if (looking == 0) stonenumber = stonenumber - 1;
- } else {
- /* If the added stone merged into another army then there is no ko spot */
- a1 = g->armymen[newstone]; /* old blank army number */
- if (g->army[a1].size > 1) g->movestatus.kospot = -1;
- if (looking == 0) {
- playedstone = newstone;
- if (fp != NULL) {
- if (g->who == White) fprintf(fp,"add w %c,%d\n",
- coltable[g->colbrd[newstone]],g->rowbrd[newstone]);
- else fprintf(fp,"add b %c,%d\n",
- coltable[g->colbrd[newstone]],g->rowbrd[newstone]);
- } } }
- } else {
- if (g->who == White) printf(" Bad add by white at %c,%d\n",
- coltable[g->colbrd[newstone]],g->rowbrd[newstone]);
- else printf(" Bad add by black at %c,%d\n",
- coltable[g->colbrd[newstone]],g->rowbrd[newstone]);
- }
- return playedstone;
- }
-
- removeastone(g,newstone,status) game *g; int newstone; mstatus status; {
- /* Clear the blank army for rebuilding, update any neighboring enemy
- armies directly, and do nothing for neighboring friendly armies.
- Friendly armies are merged and updated by linkarmies at the end. */
- int a1,a2,first,n,s,color,wh; neighbors nabor;
- if ((g->debug & 1) != 0) printf("removeastone at: %d\n",newstone);
- if ((newstone >= 0) && (newstone < g->maxstone) &&
- (g->board[newstone] != Blank)) {
- g->movecount = g->movecount - 1;
- g->movestatus = status; /* set the new board status */
- wh = g->board[newstone]; /* save the old color */
- color = otherside[wh];
- frompicture(g,newstone); /* remove stone from picture */
- g->board[newstone] = Blank;/* remove the stone */
- if (wh == White) g->deadwhite = g->deadwhite + 1;
- else g->deadblack = g->deadblack + 1;
- undrawstone(g,newstone);
- a1 = g->armymen[newstone]; /* old army number */
- first = g->army[a1].first; /* first man in army to be relinked */
- getneighbors(g,&nabor,newstone);
- a2 = 0;
- for (n = firstelement; n < nabor.neis; n++) { /* for neighbors */
- a1 = g->armymen[nabor.stone[n]];
- if ((g->army[a1].color == Blank) &&
- ((nabor.direction[n] & g->movestatus.captures) != 0)) {
- uncapture(g,nabor.stone[n],color);
- g->army[a1].lib = 1; /* set 1 liberty for the removed stone */
- } else if ((a1 != a2) && (g->army[a1].color == otherside[wh])) {
- g->army[a1].enemy = g->army[a1].enemy - 1;
- g->army[a1].lib = g->army[a1].lib + 1;
- }
- a2 = a1;
- }
- linkarmies(g,first);
- } else {
- if (g->who == White) printf(" Bad remove by white at %c,%d\n",
- coltable[g->colbrd[newstone]],g->rowbrd[newstone]);
- else printf(" Bad remove by black at %c,%d\n",
- coltable[g->colbrd[newstone]],g->rowbrd[newstone]);
- }
- if ((g->debug & 1) != 0) printf("removeastone, end.\n");
- }
-
- capture(g,s) game *g; int s; {
- /* Call this routine to remove an army that has been captured. The
- army remains intact, just changes to a blank army. Neighboring
- enemy armies have their liberties updated by buildarmies. */
- int a1,a2,s1,n,wh; neighbors nabor;
- if ((g->debug & 1) != 0) printf("capture:\n");
- if ((s >= 0) && (s < g->maxstone)) {
- a1 = g->armymen[s]; /* get the army number */
- if (g->army[a1].color != Blank) {
- if (g->army[a1].size == 1) {
- g->movestatus.kospot = g->army[a1].first;
- } else {
- g->movestatus.kospot = -1;
- }
- g->movecount = g->movecount - g->army[a1].size;
- wh = g->army[a1].color; /* save the army color */
- if (wh == White) g->deadwhite = g->deadwhite + g->army[a1].size;
- else g->deadblack = g->deadblack + g->army[a1].size;
- g->army[a1].color = Blank; /* change army color to blank */
- g->army[a1].size = 0; /* causes army to be rebuilt by buildarmies */
- s1 = g->army[a1].first; /* first man in army */
- while (s1 >= 0) {
- frompicture(g,s1); /* take out of picture */
- undrawstone(g,s1);
- g->board[s1] = Blank; /* change stone color to blank */
- /* clear the size in neighboring enemy armies so they will be rebuilt */
- getneighbors(g,&nabor,s1);
- for (n = firstelement; n < nabor.neis; n++) { /* for neighbors */
- a2 = g->armymen[nabor.stone[n]];
- if (a2 > 0) {
- if (g->army[a2].color == otherside[wh]) {
- g->army[a2].size = 0; }
- }
- }
- /* get the next man in the army */
- s1 = g->armylnk[s1]; /* row link to next army man */
- }
- buildarmies(g);
- } else {
- printf(" Bad capture at: %c,%d\n",coltable[g->colbrd[s]],g->rowbrd[s]);
- }
- } else {
- printf(" Bad capture at: %c,%d\n",coltable[g->colbrd[s]],g->rowbrd[s]);
- }
- if ((g->debug & 1) != 0) printf("capture, end.\n");
- }
-
- uncapture(g,s,wh) game *g; int s,wh; {
- /* Call this routine to uncapture an army that had been captured. The
- army remains intact, just changes to a non-blank army. Neighboring
- enemy armies have their liberties updated by buildarmies. */
- int a1,a2,s1,n; neighbors nabor;
- if ((g->debug & 1) != 0) printf("uncapture:\n");
- if ((s >= 0) && (s < g->maxstone)) {
- a1 = g->armymen[s]; /* get the army number */
- if (g->army[a1].color == Blank) {
- g->movecount = g->movecount + g->army[a1].size;
- if (wh == White) g->deadwhite = g->deadwhite - g->army[a1].size;
- else g->deadblack = g->deadblack - g->army[a1].size;
- g->army[a1].color = wh; /* change army color to non-blank */
- g->army[a1].size = 0; /* causes army to be rebuilt by buildarmies */
- s1 = g->army[a1].first; /* first man in army */
- while (s1 >= 0) {
- g->board[s1] = wh; /* change stone color to non-blank */
- drawstone(g,s1,wh);
- topicture(g,s1); /* add to picture */
- /* clear the size in neighboring enemy armies so they will be rebuilt */
- getneighbors(g,&nabor,s1);
- for (n = firstelement; n < nabor.neis; n++) { /* for neighbors */
- a2 = g->armymen[nabor.stone[n]];
- if (g->army[a2].color != wh) g->army[a2].size = 0;
- }
- /* get the next man in the army */
- s1 = g->armylnk[s1]; /* row link to next army man */
- }
- buildarmies(g);
- }
- } else {
- printf("Bad uncapture an army at: %c,%d\n",
- coltable[g->colbrd[s]],g->rowbrd[s]);
- }
- if ((g->debug & 1) != 0) printf(" uncapture, end.\n");
- }
-
- getneighbors(g,nabor,stone) game *g; neighbors *nabor; int stone; {
- int b,i,j,s;
- /* Establish the number and position of neighbors to a stone. Gather
- the stone numbers of neighboring positions into the nabor.stone
- array sorted by army number. The purpose of the sort is
- to group neighbors belonging to the same army together. */
- nabor->neis = firstelement;
- if ((g->neibrd[stone] & 1) != 0) {
- nabor->stone[firstelement] = stone - 1;
- nabor->direction[firstelement] = 1;
- nabor->neis = nabor->neis + 1; }
- if ((g->neibrd[stone] & 2) != 0) {
- nabor->stone[nabor->neis] = stone + 1;
- nabor->direction[nabor->neis] = 2;
- nabor->neis = nabor->neis + 1; }
- if ((g->neibrd[stone] & 4) != 0) {
- nabor->stone[nabor->neis] = stone - g->width;
- nabor->direction[nabor->neis] = 4;
- nabor->neis = nabor->neis + 1; }
- if ((g->neibrd[stone] & 8) != 0) {
- nabor->stone[nabor->neis] = stone + g->width;
- nabor->direction[nabor->neis] = 8;
- nabor->neis = nabor->neis + 1; }
- for (i = firstelement; i < nabor->neis-1; i++) {
- for (j = i+1; j < nabor->neis; j++) {
- if (g->armymen[nabor->stone[j]] < g->armymen[nabor->stone[i]]) {
- s = nabor->stone[j];
- nabor->stone[j] = nabor->stone[i]; nabor->stone[i] = s;
- b = nabor->direction[j];
- nabor->direction[j] = nabor->direction[i]; nabor->direction[i] = b;
- } } } }
-
- allarmies(g) game *g; {
- /* Clear all army numbers in the army array, and call build armies */
- int n,s;
- if ((g->debug & 1) != 0) printf("allarmies:\n");
- g->avail = 1; /* next available army number */
- g->army[1].bp = 0;
- for (n = firstelement; n < maxarmies; n++) {
- g->army[n].first = -1;
- g->army[n].fp = n + 1; /* initialize armies forward links */
- }
- for (s = firstelement; s < g->maxstone; s++) {
- g->armymen[s] = 0; g->armylnk[s] = s - 1;
- }
- linkarmies(g,g->maxstone-1);
- if ((g->debug & 1) != 0) printf(" allarmies.\n");
- }
-
- linkarmies(g,first) game *g; int first; {
- /* Create a 1 man army for each square. Then look at neighboring squares,
- and if any are the same color army then merge the new army into the
- neighboring army */
- int n,s,s1,s2,new,old; neighbors nabor;
- if ((g->debug & 1) != 0) printf("linkarmies:\n");
- s = first;
- old = g->armymen[s]; /* save old army number */
- while (s >= 0) {
- s1 = g->armylnk[s]; /* save link to next old army man */
- new = g->avail; /* get next available army number */
- g->avail = g->army[g->avail].fp;
- g->army[g->avail].bp = new;
- g->armymen[s] = new; /* set new army number */
- g->armylnk[s] = -1;
- g->army[new].size = 0; /* size is done by buildarmies */
- g->army[new].color = g->board[s];
- g->army[new].first = s; g->army[new].last = s;
- getneighbors(g,&nabor,s); /* get the neighbors */
- for (n = firstelement; n < nabor.neis; n++) { /* go through the neighbors *
- /
- s2 = nabor.stone[n];
- if (g->armymen[s2] != old) { armymerge(g,s2,s); }
- }
- s = s1; /* next man to be linked */
- }
- /* make old army number available */
- if (old > 0) {
- if (g->army[old].fp != g->avail) {
- if (g->army[old].bp > 0) {
- g->army[g->army[old].bp].fp = g->army[old].fp; }
- g->army[g->army[old].fp].bp = g->army[old].bp;
- g->army[g->army[g->avail].bp].fp = old;
- g->army[old].fp = g->avail;
- g->army[old].bp = g->army[g->avail].bp;
- g->army[g->avail].bp = old;
- }
- g->army[old].first = -1; g->avail = old;
- }
- buildarmies(g);
- if ((g->debug & 1) != 0) printf(" linkarmies.\n");
- }
-
- buildarmies(g) game *g; {
- /* Add up the number of computer and opponent stones that border on
- each army */
- int a1,a2,n,s,s1; neighbors nabor;
- if ((g->debug & 1) != 0) printf("buildarmies:\n");
- for (s = firstelement; s < g->maxstone; s++) wrkbrd[s] = 0;
- a1 = g->army[g->avail].bp;
- while (a1 > 0) { /* go through each active army */
- if ((g->army[a1].size <= 0) && (g->army[a1].first >= 0)) {
- g->army[a1].lib = 0;
- g->army[a1].friend = 0;
- g->army[a1].enemy = 0;
- g->army[a1].armies = 0;
- s = g->army[a1].first; /* first man in army */
- while (s >= 0) {
- g->army[a1].size = g->army[a1].size + 1;
- getneighbors(g,&nabor,s); /* get the neighbors */
- for (n = firstelement; n < nabor.neis; n++) { /* go through neighbors *
- /
- s1 = nabor.stone[n];
- if (wrkbrd[s1] != a1) {
- wrkbrd[s1] = a1; /* mark this neighbor counted */
- if (g->board[s] != Blank) {
- if (g->board[s1] == Blank) {
- g->army[a1].lib = g->army[a1].lib + 1;
- } else if (g->board[s1] != g->board[s]) {
- g->army[a1].enemy = g->army[a1].enemy + 1;
- }
- } else {
- if (g->board[s1] != Blank) {
- if (g->board[s1] == White) {
- g->army[a1].friend = g->army[a1].friend + 1;
- } else {
- g->army[a1].enemy = g->army[a1].enemy + 1;
- }
- }
- }
- }
- }
- s = g->armylnk[s]; /* link to next man */
- }
- }
- a1 = g->army[a1].bp;
- }
- if ((g->debug & 1) != 0) printf(" buildarmies.\n");
- }
-
- armymerge(g,s1,s2) game *g; int s1,s2; {
- /* Merge two armies by merging the linked lists */
- int a1,a2,i,s,s3;
- a1 = g->armymen[s1]; a2 = g->armymen[s2];
- if ((a1 > 0) && (a1 != a2) && (g->board[s1] == g->board[s2])) {
- /* Change a2 number to a1 for all the a2 armymen */
- s = g->army[a2].first; /* first man in army */
- while (s >= 0) { g->armymen[s] = a1; s = g->armylnk[s]; }
- /* Link army a2 into army a1 */
- g->armylnk[g->army[a2].last] = g->army[a1].first;
- g->army[a1].first = g->army[a2].first;
- g->army[a2].first = -1; /* delete army a2 */
- g->army[a2].size = 0;
- g->army[a1].size = 0; /* required for buildarmies */
- if (g->army[a2].fp != g->avail) {
- if (g->army[a2].bp > 0) {
- g->army[g->army[a2].bp].fp = g->army[a2].fp; }
- g->army[g->army[a2].fp].bp = g->army[a2].bp;
- g->army[g->army[g->avail].bp].fp = a2;
- g->army[a2].fp = g->avail;
- g->army[a2].bp = g->army[g->avail].bp;
- g->army[g->avail].bp = a2;
- }
- g->avail = a2;
- } }
-
- topicture(g,s) game *g; int s; {
- /* Add the specified stone to the bitmap of the stones in the 5 by 5
- diamond centered about the specified stone */
- int i,s1,s2,s3,w3; long bit,*p; char *c;
- i = - g->width - g->width - 2; bit = 1L; s1 = -1;
- if (g->who == White) { p = &g->whitepats[s]; c = &g->whitecount[s]; }
- else { p = &g->blackpats[s]; c = &g->blackcount[s]; }
- for (s2 = 0; s2 < patwidth; s2++) {
- for (s3 = 0; s3 < patwidth; s3++) {
- s1 = s1 + 1;
- if ((picset[s1] & g->neibrd[s]) == picset[s1])
- { *(p+i) = *(p+i) | bit; *(c+i) = *(c+i) + 1; }
- bit = bit + bit; i = i + 1;
- } i = i + g->width - patwidth;
- }
- w3 = g->width + g->width + g->width;
- if ((picset[25] & g->neibrd[s]) == picset[25])
- { *(p-3) = *(p-3) | 0x2000000L; *(c-3) = *(c-3) + 1; }
- if ((picset[26] & g->neibrd[s]) == picset[26])
- { *(p+3) = *(p+3) | 0x4000000L; *(c+3) = *(c+3) + 1; }
- if ((picset[27] & g->neibrd[s]) == picset[27])
- { *(p-w3) = *(p-w3) | 0x8000000L; *(c-w3) = *(c-w3) + 1; }
- if ((picset[28] & g->neibrd[s]) == picset[28])
- { *(p+w3) = *(p+w3) | 0x10000000L; *(c+w3) = *(c+w3) + 1; }
- }
-
- frompicture(g,s) game *g; int s; {
- /* Remove the specified stone from the bitmap of the stones in the 5 by 5
- diamond centered about the specified stone. */
- int i,s1,s2,s3,w3; long bit,*p; char *c;
- i = - g->width - g->width - 2; bit = 1; s1 = -1;
- if (g->who == White) { p = &g->whitepats[s]; c = &g->whitecount[s]; }
- else { p = &g->blackpats[s]; c = &g->blackcount[s]; }
- for (s2 = 0; s2 < patwidth; s2++) {
- for (s3 = 0; s3 < patwidth; s3++) {
- s1 = s1 + 1;
- if ((picset[s1] & g->neibrd[s]) == picset[s1])
- { *(p+i) = *(p+i) & ~bit; *(c+i) = *(c+i) - 1; }
- bit = bit + bit; i = i + 1;
- } i = i + g->width - patwidth;
- }
- w3 = g->width + g->width + g->width;
- if ((picset[25] & g->neibrd[s]) == picset[25])
- { *(p-3) = *(p-3) & ~0x2000000L; *(c-3) = *(c-3) - 1; }
- if ((picset[26] & g->neibrd[s]) == picset[26])
- { *(p+3) = *(p+3) & ~0x4000000L; *(c+3) = *(c+3) - 1; }
- if ((picset[27] & g->neibrd[s]) == picset[27])
- { *(p-w3) = *(p-w3) & ~0x8000000L; *(c-w3) = *(c-w3) - 1; }
- if ((picset[28] & g->neibrd[s]) == picset[28])
- { *(p+w3) = *(p+w3) & ~0x10000000L; *(c+w3) = *(c+w3) - 1; }
- }
-
- /* The following routines provide output for debugging */
-
- moveboard(g) game *g; {
- int i,s;
- s = 0;
- while (s < g->maxstone) {
- for (i = firstelement; i < g->width; i++) {
- if (g->board[s] == White) printf(" 1");
- else if (g->board[s] == Black) printf(" 2");
- else printf(" 0");
- s = s + 1;
- }
- printf("\n");
- } }
-
- armyboard(g) game *g; {
- int i,s;
- s = 0;
- while (s < g->maxstone) {
- for (i = firstelement; i < g->width; i++) { printf("%3d",g->armymen[s]); s =
- s + 1; }
- printf("\n");
- } }
-
- armyinfo(g) game *g; {
- int i,n; char qkey;
- qkey = 'g';
- printf("Total stones: %d\nAvail: %d\n",g->movecount,g->avail);
- n = 0;
- i = g->army[g->avail].bp;
- while (i > 0) { if (i > n) n = i; i = g->army[i].bp; }
- printf("Highest army number: %d\n",n);
- i = g->army[g->avail].bp;
- while ((qkey != 'q') && (i > 0)) {
- printf("Army %d\n",i);
- if (g->army[i].first >= 0) {
- printf("Color %d\nSize %d\nFirst %d\nLast %d\n",
- g->army[i].color,g->army[i].size,g->army[i].first,g->army[i].last);
- printf("FP %d\nBP %d\nLiberties %d\nFriends %d\nEnemies %d\n",
- g->army[i].fp,g->army[i].bp,g->army[i].lib,g->army[i].friend,g->army[i].
- enemy);
- }
- i = g->army[i].bp;
- printf("q return to quit, space to continue\n"); qkey = getchar();
- }
- }
-
- linkinfo(g) game *g; {
- int i,s;
- s = firstelement;
- while (s < g->maxstone) {
- for (i = firstelement; i < g->width; i++) { printf("%d ",g->armylnk[s]); s =
- s + 1; }
- printf("\n");
- }
- }
-
- pictinfo(g) game *g; {
- int i,s; char qkey;
- s = 0; qkey = 'g';
- printf("White stone patterns:\n");
- while ((s < g->maxstone) && (qkey != 'q') && (qkey != 'n')) {
- for (i = firstelement; i < g->width; i++)
- { printf(" %lx\n",g->whitepats[s]); s = s + 1; }
- printf("q return to quit, space to continue\n"); qkey = getchar();
- } printf("Black stone patterns:\n");
- s = 0;
- while ((s < g->maxstone) && (qkey != 'q')) {
- for (i = firstelement; i < g->width; i++)
- { printf(" %lx\n",g->blackpats[s]); s = s + 1; }
- printf("q return to quit, space to continue\n"); qkey = getchar();
- }
- }
-
- neighborinfo(g) game *g; {
- int i,s;
- s = 0;
- while (s < g->maxstone) {
- for (i = firstelement; i < g->width; i++)
- { printf("%4x ",g->neibrd[s]); s = s + 1; }
- printf("\n");
- }
- }
-
- drawboard(g) game *g; {
- int i,linelength; rect srect; char num[4];
- setport(mywindow);
- /* Draw the position letters and numbers */
- textsize(9);
- for (i = g->width; i > 0; i--) {
- moveto(-12,14 + 16 * (g->width - i));
- sprintf(num,"%2d", i);
- drawstring(num);
- }
- for (i = 0; i < g->width; i++) {
- moveto(7 + 16 * i,13 + 16 * g->width);
- drawchar(coltable[i]);
- }
- /* Draw the board */
- textsize(7);
- linelength = 16 * (g->width - 1);
- moveto(10,10);
- for (i = 0; i < g->width; i++) {
- line(linelength,0);
- move(-linelength,16);
- }
- moveto(10,10);
- for (i = 0; i < g->width; i++) {
- line(0,linelength);
- move(16,-linelength);
- }
- /* draw the handicap positions on a 19 X 19 board */
- if (g->width == 19) {
- /* first draw the corner handicap positions */
- setrect(&srect, 55, 55, 61, 61); filloval(&srect,&blackpat);
- setrect(&srect, 55, 247, 61, 253); filloval(&srect,&blackpat);
- setrect(&srect, 247, 55, 253, 61); filloval(&srect,&blackpat);
- setrect(&srect, 247, 247, 253, 253); filloval(&srect,&blackpat);
- /* now draw the other row 3 handicap positions */
- setrect(&srect, 55, 151, 61, 157); filloval(&srect,&blackpat);
- setrect(&srect, 151, 55, 157, 61); filloval(&srect,&blackpat);
- setrect(&srect, 247, 151, 253, 157); filloval(&srect,&blackpat);
- setrect(&srect, 151, 247, 157, 253); filloval(&srect,&blackpat);
- /* finally draw the center handicap position */
- setrect(&srect, 151, 151, 157, 157); filloval(&srect,&blackpat);
- }
- setport(mewindow);
- }
-
- drawstone(g,s,wh) game *g; int s,wh; {
- int w,x,y; rect srect; char num[8];
- if ((looking == 0) || (lookahead != 0)) {
- setport(mywindow);
- x = 10 + 16 * (s % g->width);
- y = 10 + 16 * ((g->maxstone - 1 - s) / g->width);
- setrect(&srect, x-8, y-8, x+8, y+8);
- if (wh == White) {
- filloval(&srect,&whitepat);
- } else {
- filloval(&srect,&blackpat);
- }
- if ((drawnumber != 0) && (looking == 0)) {
- sprintf(num,"%d",stonenumber);
- w = stringwidth(num) >> 1;
- moveto(x-w,y+3);
- drawstring(num);
- }
- setport(mewindow);
- }
- }
-
- undrawstone(g,s) game *g; int s; {
- int x,y; rect srect;
- if ((looking == 0) || (lookahead != 0)) {
- setport(mywindow);
- x = 10 + 16 * (s % g->width);
- y = 10 + 16 * ((g->maxstone - 1 - s) / g->width);
- setrect(&srect, x-8, y-8, x+8, y+8);
- eraseoval(&srect);
- if ((g->neibrd[s] & 1) != 0) { moveto(x,y); line(-8,0); }
- if ((g->neibrd[s] & 2) != 0) { moveto(x,y); line(8,0); }
- if ((g->neibrd[s] & 4) != 0) { moveto(x,y); line(0,8); }
- if ((g->neibrd[s] & 8) != 0) { moveto(x,y); line(0,-8); }
- /* draw the handicap positions on a 19 X 19 board */
- if (g->width == 19) {
- /* first draw the corner handicap positions */
- if (s == 60) {
- setrect(&srect, 55, 247, 61, 253); filloval(&srect,&blackpat); }
- if (s == 72) {
- setrect(&srect, 247, 247, 253, 253); filloval(&srect,&blackpat); }
- if (s == 288) {
- setrect(&srect, 55, 55, 61, 61); filloval(&srect,&blackpat); }
- if (s == 300) {
- setrect(&srect, 247, 55, 253, 61); filloval(&srect,&blackpat); }
- /* now draw the other row 3 handicap positions */
- if (s == 174) {
- setrect(&srect, 55, 151, 61, 157); filloval(&srect,&blackpat); }
- if (s == 294) {
- setrect(&srect, 151, 55, 157, 61); filloval(&srect,&blackpat); }
- if (s == 186) {
- setrect(&srect, 247, 151, 253, 157); filloval(&srect,&blackpat); }
- if (s == 66) {
- setrect(&srect, 151, 247, 157, 253); filloval(&srect,&blackpat); }
- /* finally draw the center handicap position */
- if (s == 180) {
- setrect(&srect, 151, 151, 157, 157); filloval(&srect,&blackpat); }
- }
- setport(mewindow);
- }
- }
- /* File gofile.c
- Developer: James R. Logan Jr. (BYU), Advisor: Dr. Lynn H. Beus (BYU)
- email address: loganj@byuvax.bitnet
- (801) 378-3617
-
- These routines handle the disk I/O for the go program's log file and
- replay feature. This code is not machine dependent.
- */
-
- #include <qd.h>
- #include <pack.h>
- #include <win.h>
- #include <dialog.h>
- #include <stdio.h>
- #include <goprocs.h>
-
- overlay "filestuff"
-
- char prompt[2] = {' ','\0'},origname[2] = {' ','\0'},filename[32];
- rect drect;
-
- extern FILE *fp,*gp;
- extern char coltable[19];
- extern int play;
- extern game mygame;
- extern windowptr mywindow, dummywindow;
- extern int addastone(),moves();
-
- createfile() {
- /* This procedure opens a log file for the game in progess */
- sfreply reply; point pt; char volname[30]; int i,j,tint; long tlong;
- setrect(&drect,-16,28,440,200);
- copybits(&mywindow->portbits,&dummywindow->portbits,&drect,&drect,srccopy,(lon
- g)0);
- setpt(&pt, 190, 75);
- sfputfile(&pt, &prompt[0], &origname[0], NULL, &reply);
- copybits(&dummywindow->portbits,&mywindow->portbits,&drect,&drect,srccopy,(lon
- g)0);
- if (reply.good) {
- getvinfo(reply.vrefnum, volname, &tint, &tlong);
- strcpy(filename, volname); strcat(filename, ":"); strcat(filename, reply.fna
- me);
- if (fp != NULL) fclose(fp);
- fp = fopen(filename,"w");
- } }
-
- replay() {
- /* This procedure opens a saved game and replays the game. The game file
- can be modified by an editor to change the sequence of play. The first
- letter of each line determines the function. Using log files is the
- fastest way to set up a specific board position. */
- char col,color,tline[128];
- int c,i,row,s,size,tint; long tlong;
- sfreply reply; point pt; char volname[30];
- if (gp == 0) {
- setrect(&drect,-16,28,440,200);
- copybits(&mywindow->portbits,&dummywindow->portbits,
- &drect,&drect,srccopy,(long)0);
- setpt(&pt, 186, 75);
- sfgetfile(&pt, NULL, NULL, 1, "TEXT", NULL, &reply);
- copybits(&dummywindow->portbits,&mywindow->portbits,
- &drect,&drect,srccopy,(long)0);
- if (reply.good) {
- getvinfo(reply.vrefnum, volname, &tint, &tlong);
- strcpy(filename, volname); strcat(filename, ":"); strcat(filename, reply.f
- name);
- gp = fopen(filename,"r");
- }
- } else {
- c = NULL;
- for (i=0; (i<128) && ((c = getc(gp)) != EOF) && (c != 10); i++) tline[i] = c
- ;
- tline[i] = 0;
- switch (tline[0]) {
- case 'a': case 'A':
- sscanf(tline,"%*s %c %c,%d",&color,&col,&row);
- s = position(col,row);
- if ((color == 'w') || (color == 'W')) mygame.who = White;
- else if ((color == 'b') || (color == 'B')) mygame.who = Black;
- if (s >= 0) s = addastone(&mygame,s);
- break;
- case 'b': case 'B': mygame.who = Black; break;
- case 'c': case 'C':
- sscanf(tline,"%*s %c,%d",&col,&row);
- s = position(col,row);
- if (s >= 0) capture(&mygame,s);
- break;
- case 'i': case 'I':
- sscanf(tline,"%*s %d",&size);
- if ((size > 2) && (size < 20)) {
- mygame.width = size;
- initgame(&mygame);
- }
- break;
- case 'm': case 'M': s = moves(&mygame); break;
- case 'r': case 'R':
- sscanf(tline,"%*s %c,%d",&col,&row);
- s = position(col,row);
- if (s >= 0) removeastone(&mygame,s,mygame.movestatus);
- break;
- case 'u': case 'U':
- sscanf(tline,"%*s %c,%d,%c",&col,&row,&color);
- s = position(col,row);
- if (s >= 0) {
- if ((color == 'w') || (color == 'W')) uncapture(&mygame,s,White);
- else if ((color == 'b') || (color == 'B')) uncapture(&mygame,s,Black);
-
- }
- break;
- case 'w': case 'W': mygame.who = White; break;
- default:
- }
- if (c == EOF) { fclose(gp); gp = NULL; play = 0; }
- } }
-
- int position(col,row) char col; int row; {
- /* This procedure converts from a 2-dimensional position used by the world,
- to the 1-dimensional position used in the game structures */
- int i,s;
- s = -1;
- if ((row > 0) && (row <= mygame.width)) {
- for (i = 0; i < mygame.width; i++) if (col == coltable[i]) s = i;
- if ((s >= 0) && (s < mygame.width)) s = (row - 1) * mygame.width + s;
- }
- return(s);
- }
-
-