home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Carousel
/
CAROUSEL.cdr
/
mactosh
/
code
/
cshar_go.sit
< prev
next >
Wrap
Text File
|
1988-06-20
|
91KB
|
2,408 lines
18-Jun-88 14:51:33-MDT,93237;000000000000
Return-Path: <u-lchoqu%sunset@cs.utah.edu>
Received: from cs.utah.edu by SIMTEL20.ARPA with TCP; Sat, 18 Jun 88 14:49:36 MDT
Received: by cs.utah.edu (5.54/utah-2.0-cs)
id AA22730; Sat, 18 Jun 88 14:49:32 MDT
Received: by sunset.utah.edu (5.54/utah-2.0-leaf)
id AA24857; Sat, 18 Jun 88 14:49:25 MDT
Date: Sat, 18 Jun 88 14:49:25 MDT
From: u-lchoqu%sunset@cs.utah.edu (Lee Choquette)
Message-Id: <8806182049.AA24857@sunset.utah.edu>
To: rthum@simtel20.arpa
Subject: go.c.shar
#! /bin/sh
#
# This is a shell archive. Save this into a file, edit it
# and delete all lines above this comment. Then give this
# file to sh by executing the command "sh file". The files
# will be extracted into the current directory owned by
# you with default permissions.
#
# The files contained herein are:
#
# 17 README
# 12 go.c
# 5 gofile.c
# 10 gomain.c
# 11 gomoves.c
# 1 gomoves.h
# 28 goprocs.c
# 3 goprocs.h
#
echo 'Extracting README'
if test -f README; then echo 'shar: will not overwrite README'; else
sed 's/^X//' << '________This_Is_The_END________' > README
XThis directory contains 1 document file and 7 files of source code for
Xthe Go program posted 24 Feb 86, as promised. The programs were written
Xfor Megamax C.
X
XThe core programs (in goprocs.c) have been through extensive testing,
Xeverything else is in the process of conceptualization and development.
X
XThese programs are provided as a simple skeleton go program. Some code was
Xremoved from the 'bestmoves' routine for this posting, to keep it simple.
XSince code was removed, the following programs will not play as well as the
Xexecutable version that was posted 24 Feb 1986.
X
XThis is not to be taken as an example of great coding technique - this is a
Xfirst effort.
X
XKnown problems: The last time that I adjusted the weights in the
Xmove selection routine (bestmoves) to play a better game against Nemesis I
Xmade a mistake, so presently the executable version of the program will
Xattempt an illegal move in some situations.
X
XAlso, I do not have access to a Mac XL, so I can not insure that the
Xprogram runs properly there. As far as I know, the code follows the
Xtoolbox interface conventions - nothing tricky there.
X
XWill this kind posting create more interest in Programs that play go?
XOr will it set the programming of go back ten years by undermining support
Xfor more professional efforts? Other?
X
XThanks to those of you who have responded with problems and suggestions!
XCorrespondence and gratuities of any kind (verbal, code, financial, ...)
Xcan be sent to:
X
XLynn Beus & Jim Logan
XBYU Computer Science
X232 TMCB
XProvo, Utah 84602
X
Xor email: loganj@byuvax.bitnet
X
XPhone: (801) 378-3617
X___________________________________________________________________________
X
X26 February 1986
X
XGo Utility Programs Description
X
XDeveloper: James R. Logan Jr. (BYU)
XAdvisor: Dr. Lynn H. Beus (BYU)
XBYU Computer Science
X232 TMCB
XProvo, Utah 84602
Xemail address: loganj@byuvax.bitnet
Xphone: (801) 378-3617
X
XThis document describes procedures, variables, arrays, and structures
Xthat maintain a 1-dimensional representation of the Oriental game of Go.
XThe present implementation of the programs, for lack of development
Xtime, has the following arbitrary limitations:
X
X - No count is maintained of the number of eyes that each army has
X (an easy thing to implement?), but only the number of individual
X liberties that each army has.
X
X - No count is maintained of the number of neighboring armies to an
X army.
X
X - The maximum allowable board size is 19 by 19 lines, or 361 positions.
X
X - The maximum allowable number of armies is 362 (compile time
X parameter).
X
X - The game board must be square.
X
XThe 'who' variable in the game structure (game.who) designates black's
Xor white's turn to play, and is an input parameter to some of these
Xprocedures. The user is required to set this variable to White or Black
Xbefore each procedure call.
X
XAll 1-dimensional representations of the Go board are defined in C as
Xchar [361]. The Go Programs consist of twelve main procedures. The
Xcalling conventions and purpose of these twelve procedures is described
Xas follows:
X
X-initialize
XInitializes the specified game structure by clearing all stones from the
Xvarious arrays and building the initial blank army. Initialize must be
Xcalled for a newly allocated game structure. For example, to initialize
Xa 5 by 5 game board the initialize routine should be called as follows:
X
X g->width = 5;
X initialize(g);
X where g is a game structure pointer previously allocated by the user.
X
X-addastone
XAdds a stone of color g.who to the specified 1-dimensional position and
Xupdates the specified game structure. If the specified position is
Xalready occupied then no update occurs. For example, to add a stone to
Xposition 9 the addastone routine should be called as follows:
X
X addastone(g,9);
X where g is an initialized game structure pointer.
X
X-removeastone
XRemoves the specified stone and updates the specified game structure.
XIf the specified stone represents an unoccupied position then no update
Xoccurs. For example, to remove a stone at position 9 the removeastone
Xroutine should be called as follows:
X
X removeastone(g,9,status);
X where g is a game structure pointer,
X and status is a movestatus (mstatus) structure.
X
X-getneighbors
XReturns the number of immediate non-blank neighbors to a position, and
Xreturns the 1 dimensional board position of each non-blank neighbor in a
Xstone[1..4] array sorted by army number. For example, to get all
Xneighboring positions (white, black, and blank) to position 9 the
Xgetneighbors routine should be called as follows:
X
X getneighbors(g,n,9);
X where g is a game structure pointer,
X and n is a nabor structure pointer.
X
XThe next two procedures will not normally be needed by the users program,
Xbut they are included for completeness.
X
X-capture
XRemoves the army represented by the specified stone and updates the
Xappropriate data structures. If the specified stone represents a blank
Xarmy then no update occurs. For example, to remove an army that
Xcontains a stone at position 9 the capture routine should be called as
Xfollows:
X
X capture(g,9);
X where g is a game structure pointer.
X
X-uncapture
XUncaptures the army represented by the specified position and updates
Xthe appropriate data structures. If the specified postion is occupied
Xthen no update occurs. For example, to uncapture an army that contains
Xa stone at position 9 the uncapture routine should be called as follows:
X
X uncapture(g,9,color);
X where g is a game structure pointer,
X and color is the color of the army (White or Black) being uncaptured.
X_________________________________________________________________________
X
XThe following routines print the values of game structures upside down
Xfrom the game board displayed on the screen.
X
X-moveboard
XThis procedure prints the game.board array on the screen, for debugging.
XFor example, to display game.board call moveboard as follows:
X
X moveboard(g);
X where g is a game structure pointer.
X
X-armyboard
XThis procedure prints the game.armymen array on the screen, for debugging.
XFor example, to display game.armymen call armyboard as follows:
X
X armyboard(g);
X where g is a game structure pointer.
X
X-armyinfo
XThis procedure prints the game.army structure on the screen, for debugging.
XFor example, to display game.army call armyinfo as follows:
X
X armyinfo(g);
X where g is a game structure pointer.
X
Xlinkinfo
XThis procedure prints the game.armylnk array on the screen, for debugging.
XFor example, to display game.armylnk call linkinfo as follows:
X
X linkinfo(g);
X where g is a game structure pointer.
X
X-pictinfo
XThis procedure prints the game.cpict and game.opict arrays on the screen
Xin hex, for debugging. For example, to display game.cpict and
Xgame.opict call pictinfo as follows:
X
X pictinfo(g);
X where g is a game structure pointer.
X
X-neighborinfo
XThis procedure prints the game.neibrd array on the screen in hex, for
Xdebugging. For example, to display game.neibrd call neighborinfo as
Xfollows:
X
X neighborinfo(g);
X where g is a game structure pointer.
X________________________________________________________________________
X
XThese Go Programs use one main data structure to represent a game of Go,
Xas follows:
X
Xgame - This structure contains some basic structures for the analysis of
Xa single board position.
X
XThe Game structure contains the following variables, arrays, and
Xstructures:
X
Xwho - This variable represents the color of the player making the
Xcurrent move, and is set to White for one player, and Black for the
Xother player. This variable must be set before a call to the addastone
Xprocedure, because the addastone procedure uses this variable to set the
Xboard array value (stone color).
X
Xavail - This variable is the next available army number in a linked list
Xof army numbers. Do not change this variable.
X
Xmaxstone - This variable indicates the 1-dimensional size of the game
Xboard being used. It is computed by the initialize procedure. Do not
Xchange this variable.
X
Xwidth - This variable indicates the width of the game board. The
Xinitialize procedure sets this variable to the maximum column number.
XDo not change this variable.
X
Xmovecount - This variable indicates the number of stones played in the
Xgame structure. This variable is cleared by the initialize procedure,
Xincremented by calls to the addastone procedure, and decremented by
Xcalls to the removeastone and capture procedures. Do not change this
Xvariable.
X
Xmovestatus - This structure contains ko information and capture
Xinformation based on the last stone played on the board. This structure
Xshould be pushed on the stack during tree searches, because it is used
Xto remove a play and restore the previous game position. Do not change
Xthe variables in this structure.
X
XThe ko position (movestatus.kospot) is set by the capture procedure to
Xthe 1-dimensional position of a 1-man army that was just captured. If
Xno army was captured by the last move then this variable is set to -1.
XAlso if the size of the captured army is greater than one then this
Xvariable is set to -1. The addastone procedure sets this variable to
X-1, but the addastone procedure calls the capture procedure if a capture
Xis made by a move.
X
XThe capture information (movestatus.captures) is set by the addastone
Xprocedure to reflect which of the four possible armies surrounding the
Xnew stone was captured. This variable type (movestatus.captures) is bit
Xencoded, where the least significant 4 bits determine which direction an
Xarmy was captured in (so that the army can be restored if the capturing
Xstone is removed).
X
Xdebug - This BITSET variable represents various debug states. Bits 0-5
Xare used in these programs, and bits 6-15 are available for any use.
X
Xboard - This 1-dimensional array contains the position of black and
Xwhite stones on the Go Board. One player's stones are represented by a
Xvalue of White, and opponent stones are represented by a value of Black.
XDo not change this array.
X
Xrowbrd - This 1-dimensional array corresponds exactly to the board array
Xabove and indicates the 2-dimensional row number of each position. Do
Xnot change this array.
X
Xcolbrd - This 1-dimensional array corresponds exactly to the board array
Xabove and indicates the 2-dimensional column number of each position.
XDo not change this array.
X
Xarmymen - This 1-dimensional array corresponds exactly to the Board
Xstructure (above). Each board position in this array contains the army
Xnumber of the army that occupies this position. The army number is used
Xto access information about the army.
X
Xarmylnk - This 1-dimensional array corresponds exactly to the Board
Xstructure (above). Each position in this array contains the number of
Xthe next man in the army. This array is used for processing every man
Xin an army, which occurs when an army is being built, when an army is
Xcaptured, and when army neighbors need to be counted.
X
Xwhitepats - This 1-dimensional array corresponds exactly to the Board
Xstructure (above). Each position in this array contains a binary
Xrepresentation of the white stones in a 5 by 5 diamond shape around the
Xposition. This binary picture can be used to test for a specific
Xgeometic arrangement of the white player's stones around a given
Xposition. See the diagram below.
X
Xblackpats - This 1-dimensional array corresponds exactly to the Board
Xstructure (above). Each position in this array contains a binary
Xrepresentation of the black stones in a 5 by 5 diamond shape around the
Xposition. This binary picture can be used to test for a specific
Xgeometic arrangement of the black player's stones around a given
Xposition. See the diagram below.
X
XWhitepats and blackpats (above) contain 32 bit values that represent
Xstone patterns in a 5 by 5 diamond shape, centered around a given board
Xposition (S). Only 29 bits are actually used, 25 bits for a 5 by 5
Xsquare and 4 bits at the center of each outside edge. The area covered
Xand bits represented are as follows:
X
X Shape Bit numbers
X
X * 28
X * * * * * 5 4 3 2 1
X * * * * * 10 9 8 7 6
X* * * S * * * 27 15 14 13 12 11 26
X * * * * * 20 19 18 17 16
X * * * * * 25 24 23 22 21
X * 29
X
Xneibrd - This 1-dimensional array corresponds exactly to the Board
Xstructure (above). The purpose of this array is to test a 1-dimensional
Xposition and determine if the position is on one edge or corner of the
Xboard. This array can also be used to test for a position on row 1, 2,
X3, or 4 from any side of the board.
X
Xarmy - This structure is indexed by army number, and contains
Xinformation about each army such as size, color, first (first army man's
Xboard position), last (last army man's board position), fp (forward
Xpointer to the next army), bp (backward pointer to the previous army),
Xlib (liberties), friend (number of bordering friendly stones), enemy
X(number of bordering enemy stones), armies (number of neighboring
Xnon-blank armies -- not implemented yet), and rollcall (scratchpad
Xvariable). For blank armies the number of liberties is not used, the
Xnumber of friendly stones is the number of neighboring white stones, and
Xthe number of enemy stones is the number of neighboring black stones.
XFor non-blank armies the number of friendly stones is not used.
X________________________________________________________________________
X
XThe following additional data structures are used by these programs and
Xalso made available for convenience, as follows:
X
Xneighbors - This structure contains the output of the getneighbors
Xprocedure: the number and position of non-blank neighbors to a
Xspecified 1-dimensional position, sorted by army number (which makes it
Xeasier to tell if different neighbors are in the same army).
X
Xneighborcount - This array is used with the game.neibrd array to quickly
Xdetermine how many valid neighboring positions there are to a given
Xstone position. This array, neighborcount[0..15], merely translates a
Xbinary number from 0 to 15 into the number of bits that are set in that
Xbinary number.
X
Xmstatus - This structure contains ko information and capture information
Xbased on the last stone played on the board.
X
XThe ko position (movestatus.kospot) is set by the capture procedure to
Xthe 1-dimensional position of a 1-man army that was just captured. If
Xno army was captured by the last move then this variable is set to -1.
XAlso if the size of the captured army is greater than one then this
Xvariable is set to -1. The addastone procedure sets this variable to
X-1, but the addastone procedure calls the capture procedure if a capture
Xis made by a move.
X
XThe capture information (movestatus.captures) is set by the addastone
Xprocedure to reflect which of the four possible armies surrounding the
Xnew stone was captured. This variable is bit encoded.
X_________________________________________________________________________
X
XTo use all of the above utility programs and data structures the
Xfollowing C code is necessary:
X
X#include <goprocs.h>
X#include <gomoves.h>
X
XThe following C code creates/allocates a game structure called g at
Xcompile time (this is the responsibility of the user):
X
X game g;
X
XBlack, White, and Blank are C parameters that define the only valid
Xstates of a board position. Black and White define the only valid
Xstone colors and player designations. The following C code changes
Xthe designated player in the game structure pointed to by g:
X
X g->who = otherside[g->who];
X
XThe following C code will walk through all armies (black,white, and blank),
Xgiven a game structure pointer (g):
X
X int armynumber;
X armynumber = mygame.army[mygame.avail].bp; /* back pointer is first army */
X while (armynumber > 0) {
X if (mygame.army[armynumber].size > 0) {
X (* code to process each army goes here *)
X }
X armynumber = mygame.army[armynumber].bp;
X }
X
XThe following C code will walk through an army, given a game structure
Xpointer (g) and the position of any stone in the army (s):
X
X int stone;
X stone = g->army[g->armymen[s]].first; /* first man in army */
X while (stone >= 0) {
X (* code to process each army man goes here *)
X stone = g->armylnk[stone]; /* next man in army */
X }
X
XThe following C code will obtain the positions of the neighbors to a
Xgiven stone position (s), given a game structure pointer (g) and visit
Xeach of the non-blank neighboring positions in order of their army number:
X
X neighbors nabor; int n;
X getneighbors(g,&nabor,s); /* get the neighbors */
X for (n = 0; n < nabor.neis; n++) { /* go through neighbors */
X if (g->board[s] != Blank) {
X (* code to process non-blank neighbors to stone s goes here *)
X } }
________This_Is_The_END________
if test `wc -l < README` -ne 404; then
echo 'shar: README was damaged during transit'
echo ' (should have been 404 bytes)'
fi
fi ; : end of overwriting check
echo 'Extracting go.c'
if test -f go.c; then echo 'shar: will not overwrite go.c'; else
sed 's/^X//' << '________This_Is_The_END________' > go.c
X/* File go.c
X Developer: James R. Logan Jr. (BYU), Advisor: Dr. Lynn H. Beus (BYU)
X email address: loganj@byuvax.bitnet
X (801) 378-3617
X
X These routines and the routines in gomoves.c determine the strategy of
X the go program. This code is not machine dependent.
X*/
X
X#include <qd.h>
X#include <pack.h>
X#include <win.h>
X#include <dialog.h>
X#include <stdio.h>
X#include <goprocs.h>
X#include <gomoves.h>
X
Xextern char coltable[19];
Xextern int activeplayer,blinkstone,looking,play,otherside[2];
Xextern game mygame;
Xextern int addastone();
Xextern initialize(),removeastone(),capture(),uncapture(),
X getneighbors(),allarmies(),linkarmies(),buildarmies(),
X armymerge(),topicture(),frompicture(),moveboard(),
X armyboard(),linkinfo(),armyinfo(),pictinfo(),neighborinfo();
X
Xoverlay "gamestuff"
X
X#define allyweight 4
X#define blankweight 1
X#define enemyweight 2
X#define libertiesweight 1
X#define squareweight 4
X
X#define edgevalue 1
X#define openvalue 2 /* ordinary unoccupied square, not on edge */
X#define cornervalue 10
X#define connectvalue 3
X#define midneivalue 6
X#define midrowvalue 8
X#define row3value 4
X#define row5value 3
X
Xpattern greypat = {0x24,0x92,0x49,0x24,0x92,0x49,0x24,0x92};
X
Xrect screenrect;
Xwindowrecord merecord,myrecord,drecord;
Xwindowptr mewindow,mywindow = {0L},dummywindow;
X
Xsons root[maxlevs];
X
Xmstatus status;
X
Xint
X init[maxstones],value[maxstones], /* initial position values */
X color,stone,nextmove,passcount,
X searchdepth = {1},searchwidth = {1},work;
X
Xinitgame(g) game *g; {
Xint i,j,brdsze;
Xchar dummyscreen[20000];
X if (mywindow == 0L) {
X/* calculate the size of the window for the game board, and display */
X brdsze = 16 + 8 * (g->width - 1);
X setrect(&screenrect,351-brdsze,181-brdsze,351+brdsze,181+brdsze);
X mywindow = newwindow(&myrecord, &screenrect, "", 1, 2,
X (long)-1, 0, (long)0);
X dummywindow = newwindow(&drecord, &screenrect, "", 0, 2,
X (long)-1, 1, (long)0);
X drecord.port.portbits.baseaddr = &dummyscreen;
X setrect(&screenrect, 0, 21, 188, 340);
X mewindow = newwindow(&merecord, &screenrect, "", 1, 2,
X (long)-1, 0, (long)0);
X } else {
X disposewindow(mywindow);
X brdsze = 16 + 8 * (g->width - 1);
X setrect(&screenrect,351-brdsze,181-brdsze,351+brdsze,181+brdsze);
X mywindow = newwindow(&myrecord, &screenrect, "Go", 1, 3,
X (long)-1, 0, (long)0);
X }
X if ((g->debug & 1) != 0) { printf("Initgame: \n"); }
X setport(mywindow);
X textmode(srcxor);
X backpat(&greypat);
X setorigin(-12,0);
X brdsze = 4 + 16 * g->width;
X setrect(&screenrect,0,0,400,brdsze);
X eraserect(&screenrect);
X setport(mewindow);
X textsize(9);
X initialize(g); /* initialize the game structure for the go procs */
X g->who = Black; /* first move is black's */
X passcount = 0; /* number of consecutive passes in the game */
X blinkstone = -1; /* indicate no stone to blink yet */
X/* set the initial value of each position, first the whole board */
X for (i = firstelement; i < g->maxstone; i++) { init[i] = openvalue; }
X/* set the initial value of the edges of the board */
X j = firstelement;
X for (i = firstelement; i < g->width; i++) {
X init[j] = edgevalue; init[j+g->width-1] = edgevalue;
X init[i] = edgevalue; init[g->maxstone-g->width+i] = edgevalue;
X j = j + g->width;
X }
X/* Set the initial value for row 3 all around the board */
X if (g->width >= 7) {
X j = 2*g->width+3;
X for (i = firstelement; i < g->width-6; i++) {
X init[j] = row3value; init[g->maxstone-j-1] = row3value;
X j = j + 1; }
X j = 3*g->width+2;
X for (i = firstelement; i < g->width-6; i++) {
X init[j] = row3value; init[j+g->width-5] = row3value;
X j = j + g->width; }
X }
X/* Set the value for the middle of row 3 around the edge of the board */
X if (g->width >= 9) {
X j = (2*g->width)+(g->width/2);
X init[j] = midrowvalue;
X init[g->maxstone-1-j] = midrowvalue;
X j = ((g->width / 2) * g->width) + 2;
X init[j] = midrowvalue;
X init[g->maxstone-1-j] = midrowvalue;
X }
X/* Set the initial value for row 5 all around the board, but not in 5 corner */
X if (g->width >= 11) {
X j = 4*g->width+5;
X for (i = firstelement; i < g->width-10; i++) {
X init[j] = row5value; init[g->maxstone-j-1] = row5value;
X j = j + 1; }
X j = 5*g->width+4;
X for (i = firstelement; i < g->width-10; i++) {
X init[j] = row5value; init[j+g->width-9] = row5value;
X j = j + g->width; }
X }
X/* Set the initial value for 3 rows in from each corner */
X if (g->width >= 5) {
X init[2*g->width+2] = cornervalue;
X init[3*g->width-3] = cornervalue;
X init[g->maxstone-2*g->width-3] = cornervalue;
X init[g->maxstone-3*g->width+2] = cornervalue;
X }
X/* Set the initial value for 2 jump neighbors from mid row 3 */
X if (g->width == 19) {
X init[44] = midneivalue; init[50] = midneivalue;
X init[116] = midneivalue; init[130] = midneivalue;
X init[230] = midneivalue; init[244] = midneivalue;
X init[310] = midneivalue; init[316] = midneivalue;
X }
X init[0] = 0; init[g->width-1] = 0;
X init[g->maxstone-g->width] = 0; init[g->maxstone-1] = 0;
X if ((g->debug & 1) != 0) { printf("Initgame end.\n"); }
X}
X
Xint moves(g) game *g; {
X/* This procedure receives control when the computer needs to make a move,
X and returns the 1-dimensional position selected by the computer.
X If g->who == White a move is computed for the computer, else a move is
X computed for the opponent. A legal move is always added to the board */
Xint s; sons *sonsp;
X alphabeta(); /* look ahead for the best move */
X if (nextmove >= 0) {
X s = addastone(g,nextmove); /* add this move to the game board */
X if (s >= 0) {
X if (g->who == White) printf(" White to %c,%d\n",
X coltable[g->colbrd[s]],g->rowbrd[s]);
X else printf(" Black to %c,%d\n",
X coltable[g->colbrd[s]],g->rowbrd[s]);
X }
X passcount = 0;
X } else {
X s = -1;
X if (activeplayer == 1) passcount = passcount + 1;
X if (g->who == White) printf(" White passes\n");
X else printf(" Black passes\n");
X }
X g->who = otherside[g->who];
X if ((activeplayer == 1) && (passcount >= 2)) {
X play = 0;
X printf(" Play stopped after two passes!\n");
X }
X return s;
X}
X
Xalphabeta() {
X/* This procedure is the top level of the alpha-beta cutoff look ahead
X procedure. Alpha and beta are initialized here. */
Xint a,b,dummy; int sonsp;
X looking = 1; /* indicate look ahead in progress */
X nextmove = -1; /* default next move is a pass */
X sonsp = 0; /* point to root of tree */
X a = -9999; b = 9999; /* alpha-beta initialization */
X dummy = abcontrol (sonsp,a,b,mygame.who);
X looking = 0;
X}
X
Xint abcontrol (tr,a,b,wh) int tr,a,b,wh; {
X/* This procedure performs the actual alpha-beta search. Inputs are
X tree level, Alpha, Beta, and who's move it is. The present
X implementation does not dynamically allocate the tree. */
Xint ta,tb,ev,junk,r,c,v;
X if (tr >= searchdepth) { /* last level of tree? */
X ev = eval(searchdepth); /* yes, compute the position value */
X if ((mygame.debug & 0xF) != 0) {
X printf("\nabcontrol - level, node, value: %d %d %d\n",
X searchdepth-1,root[searchdepth-1].nodepnt-1,ev);
X }
X return (ev); /* return the best position value */
X } else if (wh == mygame.who) { /* for maximizing level */
X bestmoves(&mygame,tr); /* fill in the best moves */
X while ((root[tr].nodepnt < root[tr].nodecnt) && (a < b)) {
X junk = addastone(&mygame,root[tr].nodes[root[tr].nodepnt].s);
X root[tr].status = mygame.movestatus;
X root[tr].nodepnt = root[tr].nodepnt + 1;
X ta = abcontrol (tr + 1, a, b, otherside[wh]);
X if (ta > a) {
X a = ta; /* new alpha value */
X if (tr <= 0) { nextmove = root[tr].nodes[root[tr].nodepnt-1].s; }
X }
X removeastone(&mygame,root[tr].nodes[root[tr].nodepnt-1].s,root[tr].status)
X;
X }
X return (a);
X } else { /* for minimizing level */
X bestmoves(&mygame,tr); /* fill in the best moves */
X while ((root[tr].nodepnt < root[tr].nodecnt) && (a < b)) {
X mygame.who = wh; /* change sides */
X junk = addastone(&mygame,root[tr].nodes[root[tr].nodepnt].s);
X root[tr].status = mygame.movestatus;
X mygame.who = otherside[mygame.who]; /* change sides back */
X root[tr].nodepnt = root[tr].nodepnt + 1;
X tb = abcontrol (tr + 1, a, b, otherside[wh]);
X if (tb < b) { b = tb; } /* new beta value */
X removeastone(&mygame,root[tr].nodes[root[tr].nodepnt-1].s,root[tr].status)
X;
X }
X return (b);
X }
X}
X
Xint eval(sonsp) int sonsp; {
X/* This procedure evaluates the worth of look ahead moves during the alpha
X beta search - not a well defined process. Need a lot of work here!
X The game structure fields don't seem to represent enough higher level
X (human) abstractions to play a good game yet. The evaluation here
X is based on the number of armies, eyes, and total number of liberties
X for both sides. Variables beginning with an 'a' are ally values, 'e' are
X enemy values. */
Xint n,v,pv,allies,enemies,alibs,elibs,wh,tb;
X if ((mygame.debug & 1) != 0) { printf("eval: \n"); }
X pv = 0; allies = 0; enemies = 0; alibs = 0; elibs = 0;
X wh = 1;
X for (tb = 0; tb < sonsp; tb++) { /* traverse the tree */
X pv = pv + root[tb].nodes[root[tb].nodepnt-1].pv * wh;
X tb = tb + 1;
X wh = -wh; /* switch players at each level of the tree */
X }
X n = mygame.army[mygame.avail].bp; /* visit each army */
X while (n > 0) {
X if (mygame.army[n].size > 0) {
X if (mygame.army[n].color == Blank) { /* blank army is an eye? */
X if (mygame.army[n].enemy <= 0) {
X if (mygame.who == White) allies = allies + 1; /* ally eyes */
X else enemies = enemies + 1; /* enemy eyes */
X } else if (mygame.army[n].friend <= 0) {
X if (mygame.who == White) enemies = enemies + 1;/* ally eyes */
X else allies = allies + 1; /* enemy eyes */
X }
X } else if (mygame.army[n].color == mygame.who) {
X alibs = alibs + mygame.army[n].lib;
X } else {
X elibs = elibs + mygame.army[n].lib;
X }
X }
X n = mygame.army[n].bp;
X }
X v = allies * allyweight - enemies * enemyweight +
X libertiesweight * alibs - libertiesweight * elibs +
X pv * squareweight;
X if ((mygame.debug & 1) != 0) { printf("eval.\n"); }
X return (v);
X}
X
Xboardsize(g) game *g; {
X/* This procedure handles the game initialization dialog */
Xint the_item,item_type,value;
Xhandle item_handle;
Xrect drect,item_box;
Xchar item_text[64];
Xdialogptr mydialog;
X setrect(&drect,-16,28,440,200);
X copybits(&mywindow->portbits,&dummywindow->portbits,
X &drect,&drect,srccopy,(long)0);
X mydialog = getnewdialog(9507,(long) 0,(long)-1);
X getditem(mydialog,3,&item_type,&item_handle,&item_box);
X sprintf(item_text,"%d",g->width);
X setitext(item_handle,item_text);
X getditem(mydialog,4,&item_type,&item_handle,&item_box);
X sprintf(item_text,"%d",searchwidth);
X setitext(item_handle,item_text);
X getditem(mydialog,5,&item_type,&item_handle,&item_box);
X sprintf(item_text,"%d",searchdepth);
X setitext(item_handle,item_text);
X do {
X modaldialog((long) 0,&the_item);
X if (the_item == 1) {
X getditem(mydialog,3,&item_type,&item_handle,&item_box);
X getitext(item_handle,&item_text);
X sscanf(item_text,"%d",&value);
X if ((value > 2) && (value < 20)) g->width = value;
X getditem(mydialog,4,&item_type,&item_handle,&item_box);
X getitext(item_handle,&item_text);
X sscanf(item_text,"%d",&value);
X if ((value > 0) && (value <= maxsons)) searchwidth = value;
X getditem(mydialog,5,&item_type,&item_handle,&item_box);
X getitext(item_handle,&item_text);
X sscanf(item_text,"%d",&value);
X if ((value > 0) && (value <= maxlevs)) searchdepth = value;
X }
X } while ((the_item != 1) && (the_item != 2));
X closedialog(mydialog);
X copybits(&dummywindow->portbits,&mywindow->portbits,
X &drect,&drect,srccopy,(long)0);
X if (the_item == 1) initgame(g);
X}
X
Xvalueboard(g) game *g; {
Xint i,s;
X s = 0;
X while (s < g->maxstone) {
X for (i = firstelement; i < g->width; i++) { printf("%3d",value[s]); s = s +
X1; }
X printf("\n");
X} }
________This_Is_The_END________
if test `wc -l < go.c` -ne 333; then
echo 'shar: go.c was damaged during transit'
echo ' (should have been 333 bytes)'
fi
fi ; : end of overwriting check
echo 'Extracting gofile.c'
if test -f gofile.c; then echo 'shar: will not overwrite gofile.c'; else
sed 's/^X//' << '________This_Is_The_END________' > gofile.c
X/* File gofile.c
X Developer: James R. Logan Jr. (BYU), Advisor: Dr. Lynn H. Beus (BYU)
X email address: loganj@byuvax.bitnet
X (801) 378-3617
X
X These routines handle the disk I/O for the go program's log file and
X replay feature. This code is not machine dependent.
X*/
X
X#include <qd.h>
X#include <pack.h>
X#include <win.h>
X#include <dialog.h>
X#include <stdio.h>
X#include <goprocs.h>
X
Xoverlay "filestuff"
X
Xchar prompt[2] = {' ','\0'},origname[2] = {' ','\0'},filename[32];
Xrect drect;
X
Xextern FILE *fp,*gp;
Xextern char coltable[19];
Xextern int play;
Xextern game mygame;
Xextern windowptr mywindow, dummywindow;
Xextern int addastone(),moves();
X
Xcreatefile() {
X/* This procedure opens a log file for the game in progess */
Xsfreply reply; point pt; char volname[30]; int i,j,tint; long tlong;
X setrect(&drect,-16,28,440,200);
X copybits(&mywindow->portbits,&dummywindow->portbits,&drect,&drect,srccopy,(lon
Xg)0);
X setpt(&pt, 190, 75);
X sfputfile(&pt, &prompt[0], &origname[0], NULL, &reply);
X copybits(&dummywindow->portbits,&mywindow->portbits,&drect,&drect,srccopy,(lon
Xg)0);
X if (reply.good) {
X getvinfo(reply.vrefnum, volname, &tint, &tlong);
X strcpy(filename, volname); strcat(filename, ":"); strcat(filename, reply.fna
Xme);
X if (fp != NULL) fclose(fp);
X fp = fopen(filename,"w");
X} }
X
Xreplay() {
X/* This procedure opens a saved game and replays the game. The game file
X can be modified by an editor to change the sequence of play. The first
X letter of each line determines the function. Using log files is the
X fastest way to set up a specific board position. */
Xchar col,color,tline[128];
Xint c,i,row,s,size,tint; long tlong;
Xsfreply reply; point pt; char volname[30];
X if (gp == 0) {
X setrect(&drect,-16,28,440,200);
X copybits(&mywindow->portbits,&dummywindow->portbits,
X &drect,&drect,srccopy,(long)0);
X setpt(&pt, 186, 75);
X sfgetfile(&pt, NULL, NULL, 1, "TEXT", NULL, &reply);
X copybits(&dummywindow->portbits,&mywindow->portbits,
X &drect,&drect,srccopy,(long)0);
X if (reply.good) {
X getvinfo(reply.vrefnum, volname, &tint, &tlong);
X strcpy(filename, volname); strcat(filename, ":"); strcat(filename, reply.f
Xname);
X gp = fopen(filename,"r");
X }
X } else {
X c = NULL;
X for (i=0; (i<128) && ((c = getc(gp)) != EOF) && (c != 10); i++) tline[i] = c
X;
X tline[i] = 0;
X switch (tline[0]) {
X case 'a': case 'A':
X sscanf(tline,"%*s %c %c,%d",&color,&col,&row);
X s = position(col,row);
X if ((color == 'w') || (color == 'W')) mygame.who = White;
X else if ((color == 'b') || (color == 'B')) mygame.who = Black;
X if (s >= 0) s = addastone(&mygame,s);
X break;
X case 'b': case 'B': mygame.who = Black; break;
X case 'c': case 'C':
X sscanf(tline,"%*s %c,%d",&col,&row);
X s = position(col,row);
X if (s >= 0) capture(&mygame,s);
X break;
X case 'i': case 'I':
X sscanf(tline,"%*s %d",&size);
X if ((size > 2) && (size < 20)) {
X mygame.width = size;
X initgame(&mygame);
X }
X break;
X case 'm': case 'M': s = moves(&mygame); break;
X case 'r': case 'R':
X sscanf(tline,"%*s %c,%d",&col,&row);
X s = position(col,row);
X if (s >= 0) removeastone(&mygame,s,mygame.movestatus);
X break;
X case 'u': case 'U':
X sscanf(tline,"%*s %c,%d,%c",&col,&row,&color);
X s = position(col,row);
X if (s >= 0) {
X if ((color == 'w') || (color == 'W')) uncapture(&mygame,s,White);
X else if ((color == 'b') || (color == 'B')) uncapture(&mygame,s,Black);
X
X }
X break;
X case 'w': case 'W': mygame.who = White; break;
X default:
X }
X if (c == EOF) { fclose(gp); gp = NULL; play = 0; }
X} }
X
Xint position(col,row) char col; int row; {
X/* This procedure converts from a 2-dimensional position used by the world,
X to the 1-dimensional position used in the game structures */
Xint i,s;
X s = -1;
X if ((row > 0) && (row <= mygame.width)) {
X for (i = 0; i < mygame.width; i++) if (col == coltable[i]) s = i;
X if ((s >= 0) && (s < mygame.width)) s = (row - 1) * mygame.width + s;
X }
X return(s);
X}
________This_Is_The_END________
if test `wc -l < gofile.c` -ne 126; then
echo 'shar: gofile.c was damaged during transit'
echo ' (should have been 126 bytes)'
fi
fi ; : end of overwriting check
echo 'Extracting gomain.c'
if test -f gomain.c; then echo 'shar: will not overwrite gomain.c'; else
sed 's/^X//' << '________This_Is_The_END________' > gomain.c
X/* File gomain.c
X Developer: James R. Logan Jr. (BYU), Advisor: Dr. Lynn H. Beus (BYU)
X email address: loganj@byuvax.bitnet
X (801) 378-3617
X
X This procedure provides the interface between the Mac and the operator.
X This code is machine dependent.
X*/
X
X#include <qd.h>
X#include <win.h>
X#include <menu.h>
X#include <event.h>
X#include <te.h>
X#include <stdio.h>
X#include <goprocs.h>
X
X#define lastmenu 5
X#define applemenu 1
X#define filemenu 256
X#define gamemenu 257
X#define playermenu 258
X#define displaymenu 259
X
XFILE *fp,*gp;
Xwindowptr whichwindow;
Xmenuhandle mymenus[lastmenu+1];
Xboolean doneflag,temp;
Xeventrecord myevent;
Xlong blinktime;
Xint code,refnum;
Xint themenu,theitem,
X activeplayer,blinkstate,blinkcolor,blinkstone,drawnumber,
X lookahead,play,playfile,stonestate;
X
Xgame mygame;
X
Xextern initgame();
Xextern int addastone(),moves();
Xextern char coltable[19];
Xextern int otherside[2];
Xextern windowptr mewindow,mywindow;
X
Xsetupmenus() {
Xint i;
Xchar appletitle[2];
X initmenus();
X appletitle[0] = applemark; appletitle[1] = 0;
X mymenus[1] = newmenu(applemenu, appletitle);
X addresmenu(mymenus[1], "DRVR");
X mymenus[2] = newmenu(filemenu, "Directives");
X appendmenu(mymenus[2], "Pass;Change Sides;Log to File;Play Log File;Quit");
X mymenus[3] = newmenu(gamemenu, "Game");
X appendmenu(mymenus[3], "Initialize;Begin or Resume;Pause");
X mymenus[4] = newmenu(playermenu, "Players");
X appendmenu(mymenus[4], "Computer Vs Computer;Computer Vs Human;Human Vs Human"
X);
X mymenus[5] = newmenu(displaymenu, "Display");
X appendmenu(mymenus[5],
X "Look Ahead Moves;Stone Numbers;Procedures;Stones;Stone Armies;Stone Links;S
Xtone Patterns;Position Values;Army Info");
X for (i=1; i<=lastmenu; i++) insertmenu(mymenus[i], 0);
X drawmenubar();
X drawnumber = 1;
X checkitem(mymenus[5],2,1);
X lookahead = 0;
X activeplayer = 1;
X checkitem(mymenus[4],activeplayer,1);
X}
X
Xdocommand(themenu, theitem) int themenu, theitem; {
Xchar name[256];
Xint i;
X switch (themenu) {
X case applemenu:
X getitem(mymenus[1], theitem, name);
X refnum = opendeskacc(name);
X break;
X case filemenu:
X switch (theitem) {
X case 1: /* pass */
X if (play == 0) {
X if ((activeplayer == 2) || (activeplayer == 3)) {
X mygame.who = otherside[mygame.who];
X if (activeplayer == 2) {
X play = 1;
X } else {
X if (mygame.who == White) printf(" White's turn ...\n");
X else printf(" Black's turn ...\n");
X }
X }
X }
X break;
X case 2: /* change sides */
X mygame.who = otherside[mygame.who];
X if (mygame.who == White) printf(" White's turn ...\n");
X else printf(" Black's turn ...\n");
X break;
X case 3:
X if (fp == NULL) {
X checkitem(mymenus[2],3,1);
X createfile();
X } else {
X checkitem(mymenus[2],3,0);
X fclose(fp); fp = NULL;
X }
X break;
X case 4:
X if (gp == 0) {
X if (activeplayer == 2) blinkoff();
X replay();
X if (gp != 0) {
X checkitem(mymenus[2],4,1);
X play = 1;
X playfile = 1;
X }
X } else {
X checkitem(mymenus[2],4,0);
X if (gp != NULL) fclose(gp); gp = NULL;
X play = 0;
X playfile = 0;
X mygame.who = otherside[mygame.who];
X if (mygame.who == White) printf(" White's turn ...\n");
X else printf(" Black's turn ...\n");
X if (activeplayer == 2) blinkon();
X }
X break;
X case 5:
X if (fp != NULL) { fclose(fp); fp = NULL; }
X if (gp != NULL) { fclose(gp); gp = NULL; }
X doneflag = 1;
X break;
X }
X break;
X case gamemenu:
X switch (theitem) {
X case 1:
X play = 0;
X if (playfile != 0) {
X checkitem(mymenus[2],4,0);
X if (gp != NULL) fclose(gp); gp = NULL;
X playfile = 0;
X }
X blinkoff();
X boardsize(&mygame);
X if (activeplayer == 1) {
X if (mygame.who == White) printf(" White's turn ...\n");
X else printf(" Black's turn ...\n");
X } else if (activeplayer == 2) {
X blinkon();
X printf(" Your turn ...\n");
X } else if (activeplayer == 3) printf(" Black's turn ...\n");
X break;
X case 2:
X if ((playfile != 0) || (activeplayer == 1)) play = 1;
X else if (activeplayer == 2) printf(" Your turn ...\n");
X else if (mygame.who == White) printf(" White's turn ...\n");
X else printf(" Black's turn ...\n");
X break;
X case 3: play = 0; break;
X }
X break;
X case playermenu:
X switch (theitem) {
X case 1:
X if (activeplayer == 2) blinkoff();
X checkitem(mymenus[4],activeplayer,0);
X activeplayer = 1;
X checkitem(mymenus[4],activeplayer,1);
X break;
X case 2:
X play = 0;
X blinkstone = -1;
X checkitem(mymenus[4],activeplayer,0);
X activeplayer = 2;
X checkitem(mymenus[4],activeplayer,1);
X break;
X case 3:
X play = 0;
X if (activeplayer == 2) blinkoff();
X checkitem(mymenus[4],activeplayer,0);
X activeplayer = 3;
X checkitem(mymenus[4],activeplayer,1);
X break;
X }
X break;
X case displaymenu:
X switch (theitem) {
X case 1:
X lookahead = 1 - lookahead;
X checkitem(mymenus[5],1,lookahead);
X break;
X case 2:
X drawnumber = 1 - drawnumber;
X checkitem(mymenus[5],2,drawnumber);
X break;
X case 3:
X if ((mygame.debug & 1) == 0) {
X mygame.debug |= 1;
X checkitem(mymenus[5],3,1);
X } else {
X mygame.debug &= ~1;
X checkitem(mymenus[5],3,0);
X }
X break;
X case 4: moveboard(&mygame); break;
X case 5: armyboard(&mygame); break;
X case 6: linkinfo(&mygame); break;
X case 7: pictinfo(&mygame); break;
X case 8: valueboard(&mygame); break;
X case 9: armyinfo(&mygame); break;
X } }
X hilitemenu(0);
X}
X
Xstoneon() {
X if ((stonestate == 0) && (blinkstone >= 0))
X drawstone(&mygame,blinkstone,blinkcolor);
X stonestate = 1;
X}
X
Xstoneoff() {
X if ((stonestate != 0) && (blinkstone >= 0))
X undrawstone(&mygame,blinkstone);
X stonestate = 0;
X}
X
Xblinkon() {
X/* Turn on the blink'n blinker if no look ahead in progress. */
X if (lookahead == 0) {
X blinkstate = 1;
X blinktime = tickcount();
X} }
X
Xblinkoff() { blinkstate = 0; stoneon(); }
X
Xblink() {
X/* This procedure does the actual blinking of the last stone played */
Xlong now;
X if (blinkstate != 0) {
X now = tickcount();
X if (now > blinktime + 20) {
X if (stonestate != 0) stoneoff(); else stoneon();
X blinktime = now;
X} } }
X
Xmain() {
X/* This procedure provides the interface between the Mac and the
X operator */
Xint i,s;
Xextern struct qdvar { char dummy[202]; grafptr qdtheport;} qdvars;
X#define theport (qdvars.qdtheport)
X
X openresfile("clock");
X initgraf(&theport);
X initfonts();
X flushevents(everyevent, 0);
X initwindows();
X setupmenus();
X initdialogs(0L);
X initcursor();
X
X doneflag = 0; play = 0; playfile = 0; blinkstone = -1;
X mygame.debug = 0;
X mygame.width = 19;
X fp = NULL; gp = NULL;
X initgame(&mygame);
X
X do {
X systemtask();
X blink();
X temp = getnextevent(everyevent, &myevent);
X switch (myevent.what) {
X case mousedown:
X code = findwindow(&myevent.where, &whichwindow);
X switch (code) {
X case inmenubar:
X docommand(menuselect(&myevent.where)); break;
X case insyswindow:
X systemclick(&myevent, whichwindow); break;
X case indrag:
X break;
X case ingrow:
X case incontent:
X if ((play == 0) &&
X ((playfile != 0) || (activeplayer == 2) || (activeplayer == 3))) {
X if (whichwindow == mywindow) {
X blinkoff();
X setport(mywindow);
X globaltolocal(&myevent.where);
X setport(mewindow);
X/* place a stone on the board */
X s = (mygame.width - 1 - ((myevent.where.a.v - 2) / 16));
X if (s < 0) s = 0;
X if (s >= mygame.width) s = mygame.width - 1;
X s = s * mygame.width;
X i = (myevent.where.a.h - 2) / 16;
X if (i < 0) i = 0;
X if (i >= mygame.width) i = mygame.width - 1;
X s = s + i;
X s = addastone(&mygame,s);
X if (s >= 0) {
X if (mygame.who == White) printf(" White to %c,%d\n",
X coltable[mygame.colbrd[s]],mygame.rowbrd[s]);
X else printf(" Black to %c,%d\n",
X coltable[mygame.colbrd[s]],mygame.rowbrd[s]);
X if (activeplayer == 2) play = 1;
X mygame.who = otherside[mygame.who];
X if (mygame.who == White) printf(" White's turn ...\n");
X else printf(" Black's turn ...\n");
X } else {
X if (mygame.who == White) printf(" Still White's turn ...\n");
X else printf(" Still Black's turn ...\n");
X }
X }
X }
X break;
X/* goaway box is on the modify window only, so save the changes to the
X letter being modified and take down the modify window */
X case ingoaway: break;
X }
X break;
X case mouseup: break;
X case keydown:
X case autokey:
X/* draw_text((char) (255 & myevent.message)); */
X break;
X case activateevt: break;
X case updateevt:
X/* setport(mywindow);
X beginupdate(mywindow);
X endupdate(mywindow);*/
X break;
X }
X if (doneflag == 0) {
X if (gp == NULL) {
X if (playfile != 0) {
X playfile = 0;
X checkitem(mymenus[2],4,0);
X }
X if (((activeplayer == 1) || (activeplayer == 2)) && (play != 0)) {
X blinkcolor = mygame.who;
X blinkstone = moves(&mygame);
X if (mygame.who == White) printf(" White's turn ...\n");
X else printf(" Black's turn ...\n");
X if (activeplayer == 2) {
X play = 0;
X blinkon();
X } }
X } else if (play != 0) replay();
X }
X } while (doneflag == 0);
X}
________This_Is_The_END________
if test `wc -l < gomain.c` -ne 353; then
echo 'shar: gomain.c was damaged during transit'
echo ' (should have been 353 bytes)'
fi
fi ; : end of overwriting check
echo 'Extracting gomoves.c'
if test -f gomoves.c; then echo 'shar: will not overwrite gomoves.c'; else
sed 's/^X//' << '________This_Is_The_END________' > gomoves.c
X/* File gomoves.c
X Developer: James R. Logan Jr. (BYU), Advisor: Dr. Lynn H. Beus (BYU)
X email address: loganj@byuvax.bitnet
X (801) 378-3617
X
X This routine determines the best n moves available when a move is
X being selected by the computer. This code is not machine dependent.
X*/
X
X#include <goprocs.h>
X#include <gomoves.h>
X
X#define maxsons 5
X#define maxlevs 5 /* must be odd, maximizing level for best odds */
X
X#define allyweight 4
X#define blankweight 1
X#define enemyweight 2
X#define libertiesweight 1
X#define squareweight 4
X
X/* The following 32 bit values represent patterns in a 5 by 5 diamond shape,
X centered around a given board position (s). Only 29 bits are actually
X used, 25 bits for a 5 by 5 square and 4 bits at the center of each
X outside edge. The area covered and bits represented are as follows:
X
X * 28
X * * * * * 5 4 3 2 1
X * * * * * 10 9 8 7 6
X* * * S * * * 27 15 14 13 12 11 26
X * * * * * 20 19 18 17 16
X * * * * * 25 24 23 22 21
X * 29
X*/
X#define square3 0x739C0L
X#define square5 0x0E8C62EL
X#define diamond5 0x477DC4L
X#define circle7 0x1F100011L
X
X#define firstmoves 17 /* number of moves before middle game */
X
X#define attackvalue 14
X#define circle7value 2
X#define edgevalue 1
X#define edgecutvalue 10
X#define edgejoinvalue 16
X#define openvalue 2 /* ordinary unoccupied square, not on edge */
X#define capturevalue 24
X#define cornervalue 10
X#define connectvalue 3
X#define cutvalue 3
X#define hitarivalue 18
X#define invadevalue 20 /* must be 4 less than capture value */
X#define midneivalue 6
X
X#define midrowvalue 8
X#define protvalue 24
X#define retreatsize 18
X#define row3value 4
X#define row5value 3
X#define square5value 1
X#define runtoedgevalue 12
X#define territoryvalue 4
X
Xextern sons root[maxlevs];
Xextern int
X otherside[2],
X init[maxstones],value[maxstones], /* initial position values */
X searchdepth,searchwidth;
X
Xbestmoves(g,sonsp) game *g; int sonsp; {
X/* This procedure determines the best n moves available using a point
X scheme with weights for different patterns and situations. This
X routine does not explicitly check the validity of each move (bad
X moves are possible if the weights are not properly set. */
Xchar *enmcount,*fricount;
Xint a1,a2,blankfris,blankenms,frilibs,lastus,lastthem,
X ha,pa,snapstone,snaplibs,i,n,s,s1,us,them,
X captsize,protsize,totallibs,hitarisize,hitarisave,neiarms,neienms,node;
Xlong fripats,enmpats,neipats;
Xneighbors nabor,nextnabor;
X/* First initialize all the best moves to pass */
X if ((g->debug & 1) != 0) { printf("bestmoves: \n"); }
X root[sonsp].nodecnt = 0; root[sonsp].nodepnt = 0;
X for (node = firstelement; node < searchwidth; node++) {
X root[sonsp].nodes[node].pv = 0;
X root[sonsp].nodes[node].s = -1; /* default is to pass */
X }
X/* Evaluate each square of the board and assign a value to it */
X for (i = firstelement; i < g->maxstone; i++) {
X value[i] = 0; /* default is not blank, so no value */
X if ((g->board[i] == Blank) && (i != g->movestatus.kospot)) {
X neipats = g->neibrd[i];
X a1 = g->armymen[i]; /* blank army number */
X if (g->who == White) {
X fricount = &g->whitecount[0]; enmcount = &g->blackcount[0];
X fripats = g->whitepats[i]; enmpats = g->blackpats[i];
X blankfris = g->army[a1].friend; blankenms = g->army[a1].enemy;
X } else {
X fricount = &g->blackcount[0]; enmcount = &g->whitecount[0];
X fripats = g->blackpats[i]; enmpats = g->whitepats[i];
X blankfris = g->army[a1].enemy; blankenms = g->army[a1].friend;
X }
X getneighbors(g,&nabor,i); /* get the neighbors */
X if ((g->army[a1].size > g->maxstone-4) ||
X ((blankfris > 0) && (blankenms > 0))) {
X if ((init[i] > openvalue) &&
X (((fripats & square3) != 0) || ((enmpats & square3) != 0)) ) {
X value[i] = openvalue;
X } else {
X value[i] = init[i]; /* default value */
X }
X }
X/* territory value, more territory value for empty diamonds
X some code was removed here too */
X if (((fripats & diamond5) == 0) &&
X ((enmpats & diamond5) == 0) &&
X ((neipats & 0x0F0) == 0x0F0)) {
X value[i] = value[i] + territoryvalue;
X } else {
X us = 0; them = 0; captsize = 0; protsize = 0;
X lastus = -1; lastthem = -1; totallibs = g->army[a1].size - 1;
X frilibs = 0; hitarisize = 0; hitarisave = 0;
X neiarms = 0; neienms = 0; ha = -1; pa = -1;
X for (n = firstelement; n < nabor.neis; n++) { /* count new army neighbor
Xs */
X s = nabor.stone[n]; /* neighbors row & column */
X a2 = g->armymen[s]; /* neighbor army number */
X if (g->board[s] == Blank) {
X frilibs = frilibs + 1;
X } else {
X if (g->army[a2].color == g->who) {
X frilibs = frilibs + g->army[a2].lib - 1;
X totallibs = totallibs + g->army[a2].lib - 1;
X }
X if (g->army[a2].lib == 1) {
X if (g->army[a2].color == g->who) {
X protsize = protsize + g->army[a2].size;
X pa = a2;
X } else {
X captsize = captsize + g->army[a2].size;
X }
X/* Check for hitari ...
X If the enemy can be hitari'd add in the points, if we can be hitari'd
X add in the points if we can protect against hitari without using up
X our eyes and if the blank army has more of our stones as neighbors */
X } else if (g->army[a2].lib == 2) {
X if (g->army[a2].color == otherside[g->who]) {
X hitarisize = hitarisize + g->army[a2].size;
X } else if ((g->army[a2].color == g->who) &&
X (g->army[a1].enemy > 0) && (blankfris > 1)) {
X hitarisave = hitarisave + g->army[a2].size;
X ha = a2;
X }
X }
X/* Don't count neighbors in the same amry more than once in neiarms,
X and don't count armies in trouble */
X if (g->board[s] == g->who) {
X us = us + 1;
X if (((lastus < 0) || (a2 != lastus)) &&
X (a2 != ha)) {
X neiarms = neiarms + 1;
X lastus = a2;
X }
X } else {
X them = them + 1;
X if ((lastthem < 0) || (a2 != lastthem)) {
X neienms = neienms + 1;
X lastthem = a2;
X }
X }
X }
X }
X/* This is the place! I cut lots of strategic code from here. If you want
X to improve the ability of this program to play go, this is the place to
X do it. */
X
X
X/* lower the value of a square controlled */
X if (((neipats & 0xF00) != 0xF00) && /* row 3 test */
X ((neipats & 0x0F0) == 0x0F0) &&
X (them > 0) && ((fripats & diamond5) == 0)) value[i] = 0;
X if ((us > 2) && (them <= 0)) { value[i] = 0; }
X if ((us > 1) && (neiarms < us)) { value[i] = 0; }
X if ((them > 2) && (us <= 0)) { value[i] = 0; }
X/* lower the value of a square that can be hitari'd on the next move */
X if ((us <= 0) && (them >= nabor.neis-2)) {
X value[i] = (value[i] / 2) - 1;
X }
X/* increase the value of a position that protects us from hitari, unless
X that position is already controlled by us */
X if ((hitarisave > 0) && (nabor.neis > 3) && (frilibs > 1) &&
X ((us < 3) || (them > 0))) {
X value[i] = value[i] + hitarisave + retreatsize + neiarms - us;
X }
X/* increase the value of a square that hitari's the enemy */
X if (hitarisize > 0) {
X if (frilibs > 1) {
X value[i] = value[i] + hitarisize - us;
X if (nabor.neis > 3) {
X value[i] = value[i] + hitarivalue;
X }
X } else if ((snaplibs > 0) && (snaplibs < 3)) {
X value[i] = value[i] + hitarisize + capturevalue +
X hitarivalue + neiarms + snaplibs;
X } }
X/* protect if we pick up at least 3 liberties, or 2 liberties without
X having to move on the edge of the board and without having to move
X into our eyes */
X if ((protsize > 0) && (blankfris > 1) &&
X ((frilibs > 2) || ((frilibs > 1) && (nabor.neis > 3)))) {
X value[i] = value[i] + protsize + protvalue - us;
X }
X/* don't move to the edge unless someone else is there */
X if (((fripats & square3) == 0) && (nabor.neis < 4)) { value[i] = 0; }
X/* lower the value of a square we are next to if the enemy is not near */
X if (((enmpats & square3) == 0) && ((fripats & square3) != 0)) {
X if (nabor.neis > 3) value[i] = value[i] / 2; else value[i] = 0;
X }
X/* Increase the value of moves that extend influence into unoccupied territory *
X/
X if ((g->movecount >= firstmoves) &&
X ((fripats & square3) == 0) && ((enmpats & square3) == 0)) {
X if (((fripats & square5) != 0) && ((enmpats & square5) != 0)) {
X value[i] = value[i] + square5value;
X } else if (((fripats & square5) == 0) && ((enmpats & square5) == 0)) {
X if (((fripats & circle7) != 0) && ((enmpats & circle7) != 0))
X value[i] = value[i] + circle7value;
X } }
X/* don't move to a square surrounded by enemy unless we have a capture */
X if (captsize > 0) {
X value[i] = value[i] + capturevalue + captsize;
X } else if (them >= nabor.neis) {
X value[i] = 0;
X }
X }
X/* There are three situations we move into: 1 is during the first
X moves of the game when a large blank army occupies most of the
X board; 2 is into a blank army that borders on computer and enemy
X stones; 3 is into an eye if the value high enough to indicate a
X capture or protection required, if not a KO situation. */
X if (value[i] > 0) {
X if ((i != g->movestatus.kospot) &&
X ((g->army[a1].size > g->maxstone-4) ||
X ((blankfris > 0) && (blankenms > 0)) ||
X (value[i] > invadevalue))) {
X s = i; node = firstelement;
X while ((node < searchwidth) && (s >= 0)) {
X if (value[s] > root[sonsp].nodes[node].pv) {
X root[sonsp].nodes[node].pv = value[s];
X s1 = root[sonsp].nodes[node].s; /* save the old value */
X root[sonsp].nodes[node].s = s; /* use the better value */
X s = s1; /* continue with old value */
X }
X node = node + 1;
X }
X root[sonsp].nodecnt = root[sonsp].nodecnt + 1;
X }
X }
X }
X }
X if (root[sonsp].nodecnt > searchwidth) { root[sonsp].nodecnt = searchwidth; }
X if ((g->debug & 1) != 0) { printf("bestmoves end.\n"); }
X}
________This_Is_The_END________
if test `wc -l < gomoves.c` -ne 264; then
echo 'shar: gomoves.c was damaged during transit'
echo ' (should have been 264 bytes)'
fi
fi ; : end of overwriting check
echo 'Extracting gomoves.h'
if test -f gomoves.h; then echo 'shar: will not overwrite gomoves.h'; else
sed 's/^X//' << '________This_Is_The_END________' > gomoves.h
X/* File gomoves.h
X Developer: James R. Logan Jr. (BYU), Advisor: Dr. Lynn H. Beus (BYU)
X email address: loganj@byuvax.bitnet
X (801) 378-3617
X*/
X
X#define maxsons 5 /* maximum depth of alpha-beta tree */
X#define maxlevs 5 /* must be odd, maximizing level for best odds? */
X
Xtypedef struct {
X int s,pv; /* alpha beta stone position and board value */
X} nodestruct;
X
Xtypedef struct { /* children of node in alpha-beta tree */
X int nodepnt,nodecnt;
X mstatus status; /* board status resulting from stone */
X nodestruct nodes[maxsons];
X} sons;
________This_Is_The_END________
if test `wc -l < gomoves.h` -ne 18; then
echo 'shar: gomoves.h was damaged during transit'
echo ' (should have been 18 bytes)'
fi
fi ; : end of overwriting check
echo 'Extracting goprocs.c'
if test -f goprocs.c; then echo 'shar: will not overwrite goprocs.c'; else
sed 's/^X//' << '________This_Is_The_END________' > goprocs.c
X/* File goprocs.c
X Developer: James R. Logan Jr. (BYU), Advisor: Dr. Lynn H. Beus (BYU)
X BYU Computer Science
X 232 TMCB
X Provo, Utah 84602
X email address: loganj@byuvax.bitnet
X (801) 378-3617
X
X These procedures are go playing utility procedures that can be used by
X a go playing progam to do all the house keeping during a game of go.
X These procedures a based on a 1-dimensional representation of the game.
X This code is not machine dependent, except for the drawing routines at
X the end.
X*/
X
X#include <qd.h>
X#include <win.h>
X#include <stdio.h>
X#include <goprocs.h>
X
X#define patwidth 5
X
Xextern FILE *fp;
Xextern int drawnumber,lookahead,otherside[2];
Xextern windowptr mewindow,mywindow;
X
Xoverlay "gostuff"
X
Xchar coltable[19] = {'A','B','C','D','E','F','G','H','J','K','L','M','N','O','P'
X,'Q','R','S','T'};
Xint picset[29] =
X {0x50,0x41,0x40,0x42,0x60,
X 0x14,0x05,0x04,0x06,0x24,
X 0x10,0x01,0x00,0x02,0x20,
X 0x18,0x09,0x08,0x0A,0x28,
X 0x90,0x81,0x80,0x82,0xA0,
X 0x100,0x200,0x400,0x800};
Xpattern whitepat = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
Xpattern blackpat = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
X
Xint looking,stonenumber,otherside[2],
X wrkbrd[maxstones];
X
Xinitialize (g) game *g; {
X/* This procedure initializes the game structure supplied by the caller */
Xint i,j,r1,c1,w1,w2,w3,w4,w5,w6,w7,w8;
X if ((g->debug & 1) != 0) printf("initializing, board size %d.\n",g->width);
X/* initialize other side table */
X otherside[White] = Black; otherside[Black] = White;
X/* initialize game parameters */
X g->movecount = 0;
X g->deadwhite = 0; g->deadblack = 0;
X w1 = g->width; w2 = w1 + w1; w3 = w2 + w1; w4 = w3 + w1;
X w5 = w4 + w1; w6 = w5 + w1; w7 = w6 + 1; w8 = w7 + 1;
X g->maxstone = w1 * w1; g->movestatus.kospot = -1;
X/* initialize the neighbor board */
X for (i = firstelement; i < g->maxstone; i++) g->neibrd[i] = 0x0FFFFFFFFL;
X j = firstelement;
X for (i = firstelement; i < g->width; i++) {
X g->neibrd[j] = g->neibrd[j] & 0x0EEEEEEEEL;
X g->neibrd[j+w1-1] = g->neibrd[j+w1-1] & 0x0DDDDDDDDL;
X g->neibrd[i] = g->neibrd[i] & 0x0BBBBBBBBL;
X g->neibrd[g->maxstone-w1+i] = g->neibrd[g->maxstone-w1+i] & 0x077777777L;
X if (w1 > 1) {
X g->neibrd[j+1] = g->neibrd[j+1] & 0x0EEEEEEEFL;
X g->neibrd[j+w1-2] = g->neibrd[j+w1-2] & 0x0DDDDDDDFL;
X g->neibrd[i+w1] = g->neibrd[i+w1] & 0x0BBBBBBBFL;
X g->neibrd[g->maxstone-w2+i] = g->neibrd[g->maxstone-w2+i] & 0x07777777FL;
X }
X if (w1 > 2) {
X g->neibrd[j+2] = g->neibrd[j+2] & 0x0EEEEEEFFL;
X g->neibrd[j+w1-3] = g->neibrd[j+w1-3] & 0x0DDDDDDFFL;
X g->neibrd[i+w2] = g->neibrd[i+w2] & 0x0BBBBBBFFL;
X g->neibrd[g->maxstone-w3+i] = g->neibrd[g->maxstone-w3+i] & 0x0777777FFL;
X }
X if (w1 > 3) {
X g->neibrd[j+3] = g->neibrd[j+3] & 0x0EEEEEFFFL;
X g->neibrd[j+w1-4] = g->neibrd[j+w1-4] & 0x0DDDDDFFFL;
X g->neibrd[i+w3] = g->neibrd[i+w3] & 0x0BBBBBFFFL;
X g->neibrd[g->maxstone-w4+i] = g->neibrd[g->maxstone-w4+i] & 0x077777FFFL;
X }
X if (w1 > 4) {
X g->neibrd[j+4] = g->neibrd[j+4] & 0x0EEEEFFFFL;
X g->neibrd[j+w1-5] = g->neibrd[j+w1-5] & 0x0DDDDFFFFL;
X g->neibrd[i+w4] = g->neibrd[i+w4] & 0x0BBBBFFFFL;
X g->neibrd[g->maxstone-w5+i] = g->neibrd[g->maxstone-w5+i] & 0x07777FFFFL;
X }
X if (w1 > 5) {
X g->neibrd[j+5] = g->neibrd[j+5] & 0x0EEEFFFFFL;
X g->neibrd[j+w1-6] = g->neibrd[j+w1-6] & 0x0DDDFFFFFL;
X g->neibrd[i+w5] = g->neibrd[i+w5] & 0x0BBBFFFFFL;
X g->neibrd[g->maxstone-w6+i] = g->neibrd[g->maxstone-w6+i] & 0x0777FFFFFL;
X }
X if (w1 > 6) {
X g->neibrd[j+6] = g->neibrd[j+6] & 0x0EEFFFFFFL;
X g->neibrd[j+w1-7] = g->neibrd[j+w1-7] & 0x0DDFFFFFFL;
X g->neibrd[i+w6] = g->neibrd[i+w6] & 0x0BBFFFFFFL;
X g->neibrd[g->maxstone-w7+i] = g->neibrd[g->maxstone-w7+i] & 0x077FFFFFFL;
X }
X if (w1 > 7) {
X g->neibrd[j+7] = g->neibrd[j+7] & 0x0EFFFFFFFL;
X g->neibrd[j+w1-8] = g->neibrd[j+w1-8] & 0x0DFFFFFFFL;
X g->neibrd[i+w7] = g->neibrd[i+w7] & 0x0BFFFFFFFL;
X g->neibrd[g->maxstone-w8+i] = g->neibrd[g->maxstone-w8+i] & 0x07FFFFFFFL;
X }
X j = j + g->width;
X }
X/* initialize the row and column arrays */
X i = 0;
X r1 = 1;
X while (i < g->maxstone) {
X for (c1 = 0; c1 < g->width; c1++)
X { g->rowbrd[i] = r1; g->colbrd[i] = c1; i = i + 1; }
X r1 = r1 + 1;
X }
X for (i = firstelement; i < g->maxstone; i++) {
X g->board[i] = Blank; g->whitepats[i] = 0; g->blackpats[i] = 0;
X g->whitecount[i] = 0; g->blackcount[i] = 0;
X }
X allarmies(g); /* Create the armies */
X drawboard(g); /* display the game board */
X looking = 0; /* indicate not in look ahead now */
X stonenumber = 0;
X if ((g->debug & 1) != 0) printf("initialize end.\n");
X}
X
Xint addastone(g,newstone) game *g; int newstone; {
X/* Clear the blank army for rebuilding, update any neighboring enemy
X armies directly, and do nothing for neighboring friendly armies.
X Friendly armies are merged and updated by linkarmies at the end. */
Xint a1,a2,first,playedstone,n,s; neighbors nabor; mstatus oldstatus;
X playedstone = -1;
X a2 = -1;
X if ((newstone >= 0) && (newstone < g->maxstone) &&
X (newstone != g->movestatus.kospot) && (g->board[newstone] == Blank)) {
X g->movecount = g->movecount + 1;
X if (looking == 0) stonenumber = stonenumber + 1;
X oldstatus = g->movestatus; /* save the old status */
X g->board[newstone] = g->who;
X drawstone(g,newstone,g->who);
X g->movestatus.kospot = -1; /* clear the ko position */
X g->movestatus.captures = 0; /* clear captures */
X topicture(g,newstone);
X a1 = g->armymen[newstone]; /* old blank army number */
X first = g->army[a1].first; /* create link list of armies to relink */
X getneighbors(g,&nabor,newstone);
X a2 = -1;
X for (n = firstelement; n < nabor.neis; n++) {
X s = nabor.stone[n];
X if (g->board[s] != Blank) {
X a1 = g->armymen[s];
X if ((a1 != a2) && (g->army[a1].color == otherside[g->who])) {
X g->army[a1].enemy = g->army[a1].enemy + 1;
X g->army[a1].lib = g->army[a1].lib - 1;
X if (g->army[a1].lib <= 0) {
X capture(g,g->army[a1].first);
X g->movestatus.captures = g->movestatus.captures | nabor.direction[n]
X;
X }
X }
X a2 = a1;
X } }
X linkarmies(g,first);
X/* If the added stone was illegal for lack of liberties then remove it */
X if (g->army[g->armymen[newstone]].lib <= 0) {
X if (g->who == White) printf(" Bad add by white at %c,%d\n",
X coltable[g->colbrd[newstone]],g->rowbrd[newstone]);
X else printf(" Bad add by black at %c,%d\n",
X coltable[g->colbrd[newstone]],g->rowbrd[newstone]);
X removeastone(g,newstone,g->movestatus);
X g->movestatus = oldstatus;
X if (looking == 0) stonenumber = stonenumber - 1;
X } else {
X/* If the added stone merged into another army then there is no ko spot */
X a1 = g->armymen[newstone]; /* old blank army number */
X if (g->army[a1].size > 1) g->movestatus.kospot = -1;
X if (looking == 0) {
X playedstone = newstone;
X if (fp != NULL) {
X if (g->who == White) fprintf(fp,"add w %c,%d\n",
X coltable[g->colbrd[newstone]],g->rowbrd[newstone]);
X else fprintf(fp,"add b %c,%d\n",
X coltable[g->colbrd[newstone]],g->rowbrd[newstone]);
X } } }
X } else {
X if (g->who == White) printf(" Bad add by white at %c,%d\n",
X coltable[g->colbrd[newstone]],g->rowbrd[newstone]);
X else printf(" Bad add by black at %c,%d\n",
X coltable[g->colbrd[newstone]],g->rowbrd[newstone]);
X }
X return playedstone;
X}
X
Xremoveastone(g,newstone,status) game *g; int newstone; mstatus status; {
X/* Clear the blank army for rebuilding, update any neighboring enemy
X armies directly, and do nothing for neighboring friendly armies.
X Friendly armies are merged and updated by linkarmies at the end. */
Xint a1,a2,first,n,s,color,wh; neighbors nabor;
X if ((g->debug & 1) != 0) printf("removeastone at: %d\n",newstone);
X if ((newstone >= 0) && (newstone < g->maxstone) &&
X (g->board[newstone] != Blank)) {
X g->movecount = g->movecount - 1;
X g->movestatus = status; /* set the new board status */
X wh = g->board[newstone]; /* save the old color */
X color = otherside[wh];
X frompicture(g,newstone); /* remove stone from picture */
X g->board[newstone] = Blank;/* remove the stone */
X if (wh == White) g->deadwhite = g->deadwhite + 1;
X else g->deadblack = g->deadblack + 1;
X undrawstone(g,newstone);
X a1 = g->armymen[newstone]; /* old army number */
X first = g->army[a1].first; /* first man in army to be relinked */
X getneighbors(g,&nabor,newstone);
X a2 = 0;
X for (n = firstelement; n < nabor.neis; n++) { /* for neighbors */
X a1 = g->armymen[nabor.stone[n]];
X if ((g->army[a1].color == Blank) &&
X ((nabor.direction[n] & g->movestatus.captures) != 0)) {
X uncapture(g,nabor.stone[n],color);
X g->army[a1].lib = 1; /* set 1 liberty for the removed stone */
X } else if ((a1 != a2) && (g->army[a1].color == otherside[wh])) {
X g->army[a1].enemy = g->army[a1].enemy - 1;
X g->army[a1].lib = g->army[a1].lib + 1;
X }
X a2 = a1;
X }
X linkarmies(g,first);
X } else {
X if (g->who == White) printf(" Bad remove by white at %c,%d\n",
X coltable[g->colbrd[newstone]],g->rowbrd[newstone]);
X else printf(" Bad remove by black at %c,%d\n",
X coltable[g->colbrd[newstone]],g->rowbrd[newstone]);
X }
X if ((g->debug & 1) != 0) printf("removeastone, end.\n");
X}
X
Xcapture(g,s) game *g; int s; {
X/* Call this routine to remove an army that has been captured. The
X army remains intact, just changes to a blank army. Neighboring
X enemy armies have their liberties updated by buildarmies. */
Xint a1,a2,s1,n,wh; neighbors nabor;
X if ((g->debug & 1) != 0) printf("capture:\n");
X if ((s >= 0) && (s < g->maxstone)) {
X a1 = g->armymen[s]; /* get the army number */
X if (g->army[a1].color != Blank) {
X if (g->army[a1].size == 1) {
X g->movestatus.kospot = g->army[a1].first;
X } else {
X g->movestatus.kospot = -1;
X }
X g->movecount = g->movecount - g->army[a1].size;
X wh = g->army[a1].color; /* save the army color */
X if (wh == White) g->deadwhite = g->deadwhite + g->army[a1].size;
X else g->deadblack = g->deadblack + g->army[a1].size;
X g->army[a1].color = Blank; /* change army color to blank */
X g->army[a1].size = 0; /* causes army to be rebuilt by buildarmies */
X s1 = g->army[a1].first; /* first man in army */
X while (s1 >= 0) {
X frompicture(g,s1); /* take out of picture */
X undrawstone(g,s1);
X g->board[s1] = Blank; /* change stone color to blank */
X/* clear the size in neighboring enemy armies so they will be rebuilt */
X getneighbors(g,&nabor,s1);
X for (n = firstelement; n < nabor.neis; n++) { /* for neighbors */
X a2 = g->armymen[nabor.stone[n]];
X if (a2 > 0) {
X if (g->army[a2].color == otherside[wh]) {
X g->army[a2].size = 0; }
X }
X }
X/* get the next man in the army */
X s1 = g->armylnk[s1]; /* row link to next army man */
X }
X buildarmies(g);
X } else {
X printf(" Bad capture at: %c,%d\n",coltable[g->colbrd[s]],g->rowbrd[s]);
X }
X } else {
X printf(" Bad capture at: %c,%d\n",coltable[g->colbrd[s]],g->rowbrd[s]);
X }
X if ((g->debug & 1) != 0) printf("capture, end.\n");
X}
X
Xuncapture(g,s,wh) game *g; int s,wh; {
X/* Call this routine to uncapture an army that had been captured. The
X army remains intact, just changes to a non-blank army. Neighboring
X enemy armies have their liberties updated by buildarmies. */
Xint a1,a2,s1,n; neighbors nabor;
X if ((g->debug & 1) != 0) printf("uncapture:\n");
X if ((s >= 0) && (s < g->maxstone)) {
X a1 = g->armymen[s]; /* get the army number */
X if (g->army[a1].color == Blank) {
X g->movecount = g->movecount + g->army[a1].size;
X if (wh == White) g->deadwhite = g->deadwhite - g->army[a1].size;
X else g->deadblack = g->deadblack - g->army[a1].size;
X g->army[a1].color = wh; /* change army color to non-blank */
X g->army[a1].size = 0; /* causes army to be rebuilt by buildarmies */
X s1 = g->army[a1].first; /* first man in army */
X while (s1 >= 0) {
X g->board[s1] = wh; /* change stone color to non-blank */
X drawstone(g,s1,wh);
X topicture(g,s1); /* add to picture */
X/* clear the size in neighboring enemy armies so they will be rebuilt */
X getneighbors(g,&nabor,s1);
X for (n = firstelement; n < nabor.neis; n++) { /* for neighbors */
X a2 = g->armymen[nabor.stone[n]];
X if (g->army[a2].color != wh) g->army[a2].size = 0;
X }
X/* get the next man in the army */
X s1 = g->armylnk[s1]; /* row link to next army man */
X }
X buildarmies(g);
X }
X } else {
X printf("Bad uncapture an army at: %c,%d\n",
X coltable[g->colbrd[s]],g->rowbrd[s]);
X }
X if ((g->debug & 1) != 0) printf(" uncapture, end.\n");
X}
X
Xgetneighbors(g,nabor,stone) game *g; neighbors *nabor; int stone; {
Xint b,i,j,s;
X/* Establish the number and position of neighbors to a stone. Gather
X the stone numbers of neighboring positions into the nabor.stone
X array sorted by army number. The purpose of the sort is
X to group neighbors belonging to the same army together. */
X nabor->neis = firstelement;
X if ((g->neibrd[stone] & 1) != 0) {
X nabor->stone[firstelement] = stone - 1;
X nabor->direction[firstelement] = 1;
X nabor->neis = nabor->neis + 1; }
X if ((g->neibrd[stone] & 2) != 0) {
X nabor->stone[nabor->neis] = stone + 1;
X nabor->direction[nabor->neis] = 2;
X nabor->neis = nabor->neis + 1; }
X if ((g->neibrd[stone] & 4) != 0) {
X nabor->stone[nabor->neis] = stone - g->width;
X nabor->direction[nabor->neis] = 4;
X nabor->neis = nabor->neis + 1; }
X if ((g->neibrd[stone] & 8) != 0) {
X nabor->stone[nabor->neis] = stone + g->width;
X nabor->direction[nabor->neis] = 8;
X nabor->neis = nabor->neis + 1; }
X for (i = firstelement; i < nabor->neis-1; i++) {
X for (j = i+1; j < nabor->neis; j++) {
X if (g->armymen[nabor->stone[j]] < g->armymen[nabor->stone[i]]) {
X s = nabor->stone[j];
X nabor->stone[j] = nabor->stone[i]; nabor->stone[i] = s;
X b = nabor->direction[j];
X nabor->direction[j] = nabor->direction[i]; nabor->direction[i] = b;
X} } } }
X
Xallarmies(g) game *g; {
X/* Clear all army numbers in the army array, and call build armies */
Xint n,s;
X if ((g->debug & 1) != 0) printf("allarmies:\n");
X g->avail = 1; /* next available army number */
X g->army[1].bp = 0;
X for (n = firstelement; n < maxarmies; n++) {
X g->army[n].first = -1;
X g->army[n].fp = n + 1; /* initialize armies forward links */
X }
X for (s = firstelement; s < g->maxstone; s++) {
X g->armymen[s] = 0; g->armylnk[s] = s - 1;
X }
X linkarmies(g,g->maxstone-1);
X if ((g->debug & 1) != 0) printf(" allarmies.\n");
X}
X
Xlinkarmies(g,first) game *g; int first; {
X/* Create a 1 man army for each square. Then look at neighboring squares,
X and if any are the same color army then merge the new army into the
X neighboring army */
Xint n,s,s1,s2,new,old; neighbors nabor;
X if ((g->debug & 1) != 0) printf("linkarmies:\n");
X s = first;
X old = g->armymen[s]; /* save old army number */
X while (s >= 0) {
X s1 = g->armylnk[s]; /* save link to next old army man */
X new = g->avail; /* get next available army number */
X g->avail = g->army[g->avail].fp;
X g->army[g->avail].bp = new;
X g->armymen[s] = new; /* set new army number */
X g->armylnk[s] = -1;
X g->army[new].size = 0; /* size is done by buildarmies */
X g->army[new].color = g->board[s];
X g->army[new].first = s; g->army[new].last = s;
X getneighbors(g,&nabor,s); /* get the neighbors */
X for (n = firstelement; n < nabor.neis; n++) { /* go through the neighbors *
X/
X s2 = nabor.stone[n];
X if (g->armymen[s2] != old) { armymerge(g,s2,s); }
X }
X s = s1; /* next man to be linked */
X }
X/* make old army number available */
X if (old > 0) {
X if (g->army[old].fp != g->avail) {
X if (g->army[old].bp > 0) {
X g->army[g->army[old].bp].fp = g->army[old].fp; }
X g->army[g->army[old].fp].bp = g->army[old].bp;
X g->army[g->army[g->avail].bp].fp = old;
X g->army[old].fp = g->avail;
X g->army[old].bp = g->army[g->avail].bp;
X g->army[g->avail].bp = old;
X }
X g->army[old].first = -1; g->avail = old;
X }
X buildarmies(g);
X if ((g->debug & 1) != 0) printf(" linkarmies.\n");
X}
X
Xbuildarmies(g) game *g; {
X/* Add up the number of computer and opponent stones that border on
X each army */
Xint a1,a2,n,s,s1; neighbors nabor;
X if ((g->debug & 1) != 0) printf("buildarmies:\n");
X for (s = firstelement; s < g->maxstone; s++) wrkbrd[s] = 0;
X a1 = g->army[g->avail].bp;
X while (a1 > 0) { /* go through each active army */
X if ((g->army[a1].size <= 0) && (g->army[a1].first >= 0)) {
X g->army[a1].lib = 0;
X g->army[a1].friend = 0;
X g->army[a1].enemy = 0;
X g->army[a1].armies = 0;
X s = g->army[a1].first; /* first man in army */
X while (s >= 0) {
X g->army[a1].size = g->army[a1].size + 1;
X getneighbors(g,&nabor,s); /* get the neighbors */
X for (n = firstelement; n < nabor.neis; n++) { /* go through neighbors *
X/
X s1 = nabor.stone[n];
X if (wrkbrd[s1] != a1) {
X wrkbrd[s1] = a1; /* mark this neighbor counted */
X if (g->board[s] != Blank) {
X if (g->board[s1] == Blank) {
X g->army[a1].lib = g->army[a1].lib + 1;
X } else if (g->board[s1] != g->board[s]) {
X g->army[a1].enemy = g->army[a1].enemy + 1;
X }
X } else {
X if (g->board[s1] != Blank) {
X if (g->board[s1] == White) {
X g->army[a1].friend = g->army[a1].friend + 1;
X } else {
X g->army[a1].enemy = g->army[a1].enemy + 1;
X }
X }
X }
X }
X }
X s = g->armylnk[s]; /* link to next man */
X }
X }
X a1 = g->army[a1].bp;
X }
X if ((g->debug & 1) != 0) printf(" buildarmies.\n");
X}
X
Xarmymerge(g,s1,s2) game *g; int s1,s2; {
X/* Merge two armies by merging the linked lists */
Xint a1,a2,i,s,s3;
X a1 = g->armymen[s1]; a2 = g->armymen[s2];
X if ((a1 > 0) && (a1 != a2) && (g->board[s1] == g->board[s2])) {
X/* Change a2 number to a1 for all the a2 armymen */
X s = g->army[a2].first; /* first man in army */
X while (s >= 0) { g->armymen[s] = a1; s = g->armylnk[s]; }
X/* Link army a2 into army a1 */
X g->armylnk[g->army[a2].last] = g->army[a1].first;
X g->army[a1].first = g->army[a2].first;
X g->army[a2].first = -1; /* delete army a2 */
X g->army[a2].size = 0;
X g->army[a1].size = 0; /* required for buildarmies */
X if (g->army[a2].fp != g->avail) {
X if (g->army[a2].bp > 0) {
X g->army[g->army[a2].bp].fp = g->army[a2].fp; }
X g->army[g->army[a2].fp].bp = g->army[a2].bp;
X g->army[g->army[g->avail].bp].fp = a2;
X g->army[a2].fp = g->avail;
X g->army[a2].bp = g->army[g->avail].bp;
X g->army[g->avail].bp = a2;
X }
X g->avail = a2;
X} }
X
Xtopicture(g,s) game *g; int s; {
X/* Add the specified stone to the bitmap of the stones in the 5 by 5
X diamond centered about the specified stone */
Xint i,s1,s2,s3,w3; long bit,*p; char *c;
X i = - g->width - g->width - 2; bit = 1L; s1 = -1;
X if (g->who == White) { p = &g->whitepats[s]; c = &g->whitecount[s]; }
X else { p = &g->blackpats[s]; c = &g->blackcount[s]; }
X for (s2 = 0; s2 < patwidth; s2++) {
X for (s3 = 0; s3 < patwidth; s3++) {
X s1 = s1 + 1;
X if ((picset[s1] & g->neibrd[s]) == picset[s1])
X { *(p+i) = *(p+i) | bit; *(c+i) = *(c+i) + 1; }
X bit = bit + bit; i = i + 1;
X } i = i + g->width - patwidth;
X }
X w3 = g->width + g->width + g->width;
X if ((picset[25] & g->neibrd[s]) == picset[25])
X { *(p-3) = *(p-3) | 0x2000000L; *(c-3) = *(c-3) + 1; }
X if ((picset[26] & g->neibrd[s]) == picset[26])
X { *(p+3) = *(p+3) | 0x4000000L; *(c+3) = *(c+3) + 1; }
X if ((picset[27] & g->neibrd[s]) == picset[27])
X { *(p-w3) = *(p-w3) | 0x8000000L; *(c-w3) = *(c-w3) + 1; }
X if ((picset[28] & g->neibrd[s]) == picset[28])
X { *(p+w3) = *(p+w3) | 0x10000000L; *(c+w3) = *(c+w3) + 1; }
X}
X
Xfrompicture(g,s) game *g; int s; {
X/* Remove the specified stone from the bitmap of the stones in the 5 by 5
X diamond centered about the specified stone. */
Xint i,s1,s2,s3,w3; long bit,*p; char *c;
X i = - g->width - g->width - 2; bit = 1; s1 = -1;
X if (g->who == White) { p = &g->whitepats[s]; c = &g->whitecount[s]; }
X else { p = &g->blackpats[s]; c = &g->blackcount[s]; }
X for (s2 = 0; s2 < patwidth; s2++) {
X for (s3 = 0; s3 < patwidth; s3++) {
X s1 = s1 + 1;
X if ((picset[s1] & g->neibrd[s]) == picset[s1])
X { *(p+i) = *(p+i) & ~bit; *(c+i) = *(c+i) - 1; }
X bit = bit + bit; i = i + 1;
X } i = i + g->width - patwidth;
X }
X w3 = g->width + g->width + g->width;
X if ((picset[25] & g->neibrd[s]) == picset[25])
X { *(p-3) = *(p-3) & ~0x2000000L; *(c-3) = *(c-3) - 1; }
X if ((picset[26] & g->neibrd[s]) == picset[26])
X { *(p+3) = *(p+3) & ~0x4000000L; *(c+3) = *(c+3) - 1; }
X if ((picset[27] & g->neibrd[s]) == picset[27])
X { *(p-w3) = *(p-w3) & ~0x8000000L; *(c-w3) = *(c-w3) - 1; }
X if ((picset[28] & g->neibrd[s]) == picset[28])
X { *(p+w3) = *(p+w3) & ~0x10000000L; *(c+w3) = *(c+w3) - 1; }
X}
X
X/* The following routines provide output for debugging */
X
Xmoveboard(g) game *g; {
Xint i,s;
X s = 0;
X while (s < g->maxstone) {
X for (i = firstelement; i < g->width; i++) {
X if (g->board[s] == White) printf(" 1");
X else if (g->board[s] == Black) printf(" 2");
X else printf(" 0");
X s = s + 1;
X }
X printf("\n");
X} }
X
Xarmyboard(g) game *g; {
Xint i,s;
X s = 0;
X while (s < g->maxstone) {
X for (i = firstelement; i < g->width; i++) { printf("%3d",g->armymen[s]); s =
X s + 1; }
X printf("\n");
X} }
X
Xarmyinfo(g) game *g; {
Xint i,n; char qkey;
X qkey = 'g';
X printf("Total stones: %d\nAvail: %d\n",g->movecount,g->avail);
X n = 0;
X i = g->army[g->avail].bp;
X while (i > 0) { if (i > n) n = i; i = g->army[i].bp; }
X printf("Highest army number: %d\n",n);
X i = g->army[g->avail].bp;
X while ((qkey != 'q') && (i > 0)) {
X printf("Army %d\n",i);
X if (g->army[i].first >= 0) {
X printf("Color %d\nSize %d\nFirst %d\nLast %d\n",
X g->army[i].color,g->army[i].size,g->army[i].first,g->army[i].last);
X printf("FP %d\nBP %d\nLiberties %d\nFriends %d\nEnemies %d\n",
X g->army[i].fp,g->army[i].bp,g->army[i].lib,g->army[i].friend,g->army[i].
Xenemy);
X }
X i = g->army[i].bp;
X printf("q return to quit, space to continue\n"); qkey = getchar();
X }
X}
X
Xlinkinfo(g) game *g; {
Xint i,s;
X s = firstelement;
X while (s < g->maxstone) {
X for (i = firstelement; i < g->width; i++) { printf("%d ",g->armylnk[s]); s =
X s + 1; }
X printf("\n");
X }
X}
X
Xpictinfo(g) game *g; {
Xint i,s; char qkey;
X s = 0; qkey = 'g';
X printf("White stone patterns:\n");
X while ((s < g->maxstone) && (qkey != 'q') && (qkey != 'n')) {
X for (i = firstelement; i < g->width; i++)
X { printf(" %lx\n",g->whitepats[s]); s = s + 1; }
X printf("q return to quit, space to continue\n"); qkey = getchar();
X } printf("Black stone patterns:\n");
X s = 0;
X while ((s < g->maxstone) && (qkey != 'q')) {
X for (i = firstelement; i < g->width; i++)
X { printf(" %lx\n",g->blackpats[s]); s = s + 1; }
X printf("q return to quit, space to continue\n"); qkey = getchar();
X }
X}
X
Xneighborinfo(g) game *g; {
Xint i,s;
X s = 0;
X while (s < g->maxstone) {
X for (i = firstelement; i < g->width; i++)
X { printf("%4x ",g->neibrd[s]); s = s + 1; }
X printf("\n");
X }
X}
X
Xdrawboard(g) game *g; {
Xint i,linelength; rect srect; char num[4];
X setport(mywindow);
X/* Draw the position letters and numbers */
X textsize(9);
X for (i = g->width; i > 0; i--) {
X moveto(-12,14 + 16 * (g->width - i));
X sprintf(num,"%2d", i);
X drawstring(num);
X }
X for (i = 0; i < g->width; i++) {
X moveto(7 + 16 * i,13 + 16 * g->width);
X drawchar(coltable[i]);
X }
X/* Draw the board */
X textsize(7);
X linelength = 16 * (g->width - 1);
X moveto(10,10);
X for (i = 0; i < g->width; i++) {
X line(linelength,0);
X move(-linelength,16);
X }
X moveto(10,10);
X for (i = 0; i < g->width; i++) {
X line(0,linelength);
X move(16,-linelength);
X }
X/* draw the handicap positions on a 19 X 19 board */
X if (g->width == 19) {
X/* first draw the corner handicap positions */
X setrect(&srect, 55, 55, 61, 61); filloval(&srect,&blackpat);
X setrect(&srect, 55, 247, 61, 253); filloval(&srect,&blackpat);
X setrect(&srect, 247, 55, 253, 61); filloval(&srect,&blackpat);
X setrect(&srect, 247, 247, 253, 253); filloval(&srect,&blackpat);
X/* now draw the other row 3 handicap positions */
X setrect(&srect, 55, 151, 61, 157); filloval(&srect,&blackpat);
X setrect(&srect, 151, 55, 157, 61); filloval(&srect,&blackpat);
X setrect(&srect, 247, 151, 253, 157); filloval(&srect,&blackpat);
X setrect(&srect, 151, 247, 157, 253); filloval(&srect,&blackpat);
X/* finally draw the center handicap position */
X setrect(&srect, 151, 151, 157, 157); filloval(&srect,&blackpat);
X }
X setport(mewindow);
X}
X
Xdrawstone(g,s,wh) game *g; int s,wh; {
Xint w,x,y; rect srect; char num[8];
X if ((looking == 0) || (lookahead != 0)) {
X setport(mywindow);
X x = 10 + 16 * (s % g->width);
X y = 10 + 16 * ((g->maxstone - 1 - s) / g->width);
X setrect(&srect, x-8, y-8, x+8, y+8);
X if (wh == White) {
X filloval(&srect,&whitepat);
X } else {
X filloval(&srect,&blackpat);
X }
X if ((drawnumber != 0) && (looking == 0)) {
X sprintf(num,"%d",stonenumber);
X w = stringwidth(num) >> 1;
X moveto(x-w,y+3);
X drawstring(num);
X }
X setport(mewindow);
X }
X}
X
Xundrawstone(g,s) game *g; int s; {
Xint x,y; rect srect;
X if ((looking == 0) || (lookahead != 0)) {
X setport(mywindow);
X x = 10 + 16 * (s % g->width);
X y = 10 + 16 * ((g->maxstone - 1 - s) / g->width);
X setrect(&srect, x-8, y-8, x+8, y+8);
X eraseoval(&srect);
X if ((g->neibrd[s] & 1) != 0) { moveto(x,y); line(-8,0); }
X if ((g->neibrd[s] & 2) != 0) { moveto(x,y); line(8,0); }
X if ((g->neibrd[s] & 4) != 0) { moveto(x,y); line(0,8); }
X if ((g->neibrd[s] & 8) != 0) { moveto(x,y); line(0,-8); }
X/* draw the handicap positions on a 19 X 19 board */
X if (g->width == 19) {
X/* first draw the corner handicap positions */
X if (s == 60) {
X setrect(&srect, 55, 247, 61, 253); filloval(&srect,&blackpat); }
X if (s == 72) {
X setrect(&srect, 247, 247, 253, 253); filloval(&srect,&blackpat); }
X if (s == 288) {
X setrect(&srect, 55, 55, 61, 61); filloval(&srect,&blackpat); }
X if (s == 300) {
X setrect(&srect, 247, 55, 253, 61); filloval(&srect,&blackpat); }
X/* now draw the other row 3 handicap positions */
X if (s == 174) {
X setrect(&srect, 55, 151, 61, 157); filloval(&srect,&blackpat); }
X if (s == 294) {
X setrect(&srect, 151, 55, 157, 61); filloval(&srect,&blackpat); }
X if (s == 186) {
X setrect(&srect, 247, 151, 253, 157); filloval(&srect,&blackpat); }
X if (s == 66) {
X setrect(&srect, 151, 247, 157, 253); filloval(&srect,&blackpat); }
X/* finally draw the center handicap position */
X if (s == 180) {
X setrect(&srect, 151, 151, 157, 157); filloval(&srect,&blackpat); }
X }
X setport(mewindow);
X }
X}
________This_Is_The_END________
if test `wc -l < goprocs.c` -ne 727; then
echo 'shar: goprocs.c was damaged during transit'
echo ' (should have been 727 bytes)'
fi
fi ; : end of overwriting check
echo 'Extracting goprocs.h'
if test -f goprocs.h; then echo 'shar: will not overwrite goprocs.h'; else
sed 's/^X//' << '________This_Is_The_END________' > goprocs.h
X/* File goprocs.h
X Developer: James R. Logan Jr. (BYU), Advisor: Dr. Lynn H. Beus (BYU)
X email address: loganj@byuvax.bitnet
X (801) 378-3617
X
X Structures required by the go program utilities.
X This code is not machine dependent.
X*/
X
X#define firstelement 0
X#define brdsize 19
X#define maxstones 362
X#define maxarmies 362
X#define White 0
X#define Black 1
X#define Blank 2
X
Xtypedef struct {
X int
X color, /* army color */
X size, /* army size */
X first, /* first armyman's position */
X last, /* last armyman's position */
X fp, /* forward pointer to next army */
X bp, /* backward pointer to last army */
X lib, /* number of liberties, for nonblank armies only */
X friend, /* number of neighboring White stones, for blank armies only */
X enemy, /* number of enemy stones for nonblank armies, or Black stones */
X armies, /* number of neighboring armies */
X rollcall;/* scratch pad variable */
X} armystruct;
X
Xtypedef struct {
X int kospot; /* valid ko position, or -1, result of last move */
X long captures; /* bit 1 is capture on the west (left)
X bit 2 is capture on the east (right)
X bit 3 is capture on the south (down)
X bit 4 is capture on the north (up) */
X} mstatus;
X
Xtypedef struct {
X int
X who, /* White for computer's level, Black for opponent */
X avail, /* next available army number */
X maxstone, /* size of 1-dimensional board */
X width, /* width of 1-dimensional board */
X movecount,/* number of stones played on the board */
X deadwhite,/* number of captured white stones */
X deadblack,/* number of captured black stones */
X debug; /* debug flags */
X char
X board[maxstones], /* computer = White, opponent = Black */
X rowbrd[maxstones], /* translates 1-dimension row to 2-dimension */
X colbrd[maxstones], /* translates 1-dimension col to 2-dimension */
X whitecount[maxstones],/* count of white stones in whitepats */
X blackcount[maxstones];/* count of black stones in blackpats */
X int
X armymen[maxstones], /* men of same army have same num */
X armylnk[maxstones]; /* link to next army member */
X long
X whitepats[maxstones],/* bit pattern of white stones in 5 by 5 square */
X blackpats[maxstones],/* bit pattern of black stones in 5 by 5 square */
X neibrd[maxstones]; /* n by n bit encoded valid neighbors array */
X mstatus movestatus; /* ko position and capture info */
X armystruct army[maxarmies];
X} game;
X
Xtypedef struct {
X int
X neis,
X stone[4],
X direction[4];
X /* bit 1 is neighbor on the west (left)
X bit 2 is capture on the east (right)
X bit 3 is capture on the south (down)
X bit 4 is capture on the north (up) */
X} neighbors;
________This_Is_The_END________
if test `wc -l < goprocs.h` -ne 77; then
echo 'shar: goprocs.h was damaged during transit'
echo ' (should have been 77 bytes)'
fi
fi ; : end of overwriting check
exit 0