为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

围棋程序源代码

2017-10-28 50页 doc 177KB 81阅读

用户头像

is_014457

暂无简介

举报
围棋程序源代码围棋程序源代码 #include /* #include */ #include #ifdef ADDED # define PATCHLEVEL 2 # define WALLY_OUTPUT 0 # define MGT_OUTPUT 1 # define CAT_OUTPUT 2 # define M_LETTER(x) \ ((x < 8) ? lettercol(x) : ((x == 8) ? 'i' : lettercol(x - 1))) int outputmode = WALLY...
围棋程序源代码
围棋程序源代码 #include /* #include */ #include #ifdef ADDED # define PATCHLEVEL 2 # define WALLY_OUTPUT 0 # define MGT_OUTPUT 1 # define CAT_OUTPUT 2 # define M_LETTER(x) \ ((x < 8) ? lettercol(x) : ((x == 8) ? 'i' : lettercol(x - 1))) int outputmode = WALLY_OUTPUT; #endif #define ASSERT 1 /*flag for whether assert() macros should be */ /* expanded*/ #define BIGU 10000 /*a number higher than any meaningful "urgency" */ /* or move importance*/ #define RESIGN (-2) /*codes for resigning */ #define PASS (-1) /* passing moves*/ #define BOTHPASS (-3) /*code for both sides passed, game is over*/ #define EDGE 23 /*max # intersections on the edge of a go board*/ int edge= 9; /*the number of intersections which we are using (a */ /* command line parameter)*/ #define NPLAYERS 2 /*# players (hence # copies to keep of score &c.)*/ int debugattack= 0; /*flag for printing debugging messages in attack()*/ /*Return the absolute value of i.*/ #define abs(i) ((i)>=0?(i):-(i)) /*Return TRUE if (x,y) corresponds to a point on the board.*/ #define on1board(x) (0<=(x)&&(x)color&&0==g->nliberties) { rv += g->nstones; *capx= g->x; *capy= g->y; remove(g->x, g->y); } return rv; } int colletter(letter) register int letter; /* Return the column # (0 to edge-1) which corresponds to letter. Due to perversity of tournament organizers etc., 'i' or 'I' is omitted, leading to an increase in complexity of this routine. Return (-1) on illegal input. */ { register int result; if('a'<=letter&&letter<='z') result= letter-'a'; else if('A'<=letter&&letter<='Z') result= letter-'A'; else return (-1); if(8>result) ; else if(8==result) return (-1); else --result; if(result>=edge) return (-1); else return result; } int getnb() /*Read and return the first nonblank character from the standard input.*/ { int c; do c= getchar(); while(' '==c||'\n'==c||TAB==c); return c; } int scanfcoo(x, y) int *x, *y; /* Read a coordinate from the standard input and write it to *x and *y. Like scanf, return 1 for success, 0 for failure, negative numbers for special moves, e.g. PASS and RESIGN. On any input error, the function eats input up to the next newline. */ { int xx, yy, c1, c2; /*Get first nonblank character of input, normally a letter code for a column.*/ c1= getnb(); /*Check for possible resignation (a '.' at the start of the input).*/ if('.'==c1) { while('\n'!=getchar()) /*Skip to end of line.*/ ; return RESIGN; } /*Check for possible "pass".*/ if('p'==lowercase(c1)) { c2= getchar(); if('a'!=lowercase(c2)) ungetc(c2, stdin); else { if((c2=getchar(),'s'!=lowercase(c2))||(c2=getchar(),'s'!=lowercase(c2))) { ungetc(c2, stdin); goto skipquit; } else return PASS; } } xx= colletter(c1); if(1!=scanf("%d", &yy)) { skipquit: /*Skip to the next newline and return failure.*/ while('\n'!=getchar()) ; return 0; } if(0==onboard(xx,yy-1)) /*The -1 converts between C arrays starting */ /* at 0 and human boards counting from 1.*/ goto skipquit; else { *x= xx; *y= yy-1; return 1; } } movedone() /* Do everything which must be done to complete a move after the stone is placed. */ { thegame.pla= nextp(thegame.pla); ++thegame.tur; } count(x, y, thisgroup, scratch, mark) register int x, y; register group *thisgroup; board scratch; int mark; /* Recursively group together connected stones. Three things must be done: (1) count liberties in thisgroup->nliberties, (2) count stones in thisgroup->nstones, and We set scratch[][]= mark for each point and liberty of this group, so that we only count each only once. The calling routine must see to it that scratch[][]!=mark for all points and liberties that it wants counted. */ { register int *bxy, *sxy; /*Common subexpressions to reduce array */ /* arithmetic; they point to theboard[x][y] and scratch[x][y].*/ endrecurse: assert(onboard(x,y)); assert(thisgroup->color==theboard[x][y]); assert(thisgroup->nstones>=0); assert(thisgroup->nliberties>=0); assert(mark!=scratch[x][y]); /*Set common subexpressions.*/ bxy= &(theboard[x][y]); sxy= &(scratch[x][y]); /*Count the point (x,y) and make it a member of the group.*/ ++(thisgroup->nstones); *sxy= mark; /*"Process" (x, y-1): should it be in the group, or a liberty, or */ /* nothing?*/ y= y-1; bxy -= 1; sxy -= 1; assert(&theboard[x][y]==bxy); assert(&scratch[x][y]==sxy); if(y>=0) if(thisgroup->color==*bxy) { if(*sxy!=mark) count(x, y, thisgroup, scratch, mark); } else if(EMPTY==*bxy) { if(*sxy!=mark) { *sxy=mark; ++(thisgroup->nliberties); } } /*Process (x, y+1).*/ y= y+2; bxy += 2; sxy += 2; assert(&theboard[x][y]==bxy); assert(&scratch[x][y]==sxy); if(ycolor==*bxy) { if(*sxy!=mark) count(x, y, thisgroup, scratch, mark); } else if(EMPTY==*bxy) { if(*sxy!=mark) { *sxy=mark; ++(thisgroup->nliberties); } } /*Process (x-1, y).*/ y= y-1; x= x-1; bxy -= EDGE+1; sxy -= EDGE+1; assert(&theboard[x][y]==bxy); assert(&scratch[x][y]==sxy); if(x>=0) if(thisgroup->color==*bxy) { if(*sxy!=mark) count(x, y, thisgroup, scratch, mark); } else if(EMPTY==*bxy) { if(*sxy!=mark) { *sxy=mark; ++(thisgroup->nliberties); } } /*Process (x+1, y).*/ x= x+2; bxy += 2*EDGE; sxy += 2*EDGE; assert(&theboard[x][y]==bxy); assert(&scratch[x][y]==sxy); if(xcolor==*bxy) { if(*sxy!=mark) goto endrecurse; } else if(EMPTY==*bxy) { if(*sxy!=mark) { *sxy=mark; ++(thisgroup->nliberties); } } } makegroups() /*Analyzes groupings of stones on board; sets groups[].*/ { register int x, y; /*coords of point we are now assigning to a group*/ board scratch; /*scratch for count() to use to say if a point is */ /* already counted*/ /*Clear old groups[] table and scratch[][].*/ ngroups= 0; { register int *s; for(s=scratch[0],x=0; xcolor= *bxy; thisgroup->x= x; thisgroup->y= y; thisgroup->nliberties= 0; thisgroup->nstones= 0; count(x, y, thisgroup, scratch, 1+thisgroup-groups); ++thisgroup; ++ngroups; } } } } placestone(x, y, p) int x, y, p; /* Put a stone for player p at (x,y) and remove all the captures which result. Update ko information. */ { int ncap, capx, capy; assert(onboard(x, y)); assert(BLACK==p||WHITE==p); assert(EMPTY==theboard[x][y]); theboard[x][y]= p; makegroups(); /*Group all stones and count libs.*/ ncap= capture(nextp(p), &capx, &capy);/*Remove p's opponent's dead stones.*/ thegame.kox= thegame.koy= (-1); /*Cancel any old ko.*/ if(1==ncap) /*If exactly one stone was captured, check for new ko.*/ { register int j, *ip; group g; board scratch; for(ip=(int*)scratch,j=EDGE*EDGE; j--; ) *ip++= 0; g.color= theboard[x][y]; g.nstones= 0; g.nliberties= 0; g.x= x; g.y= y; count(x, y, &g, scratch, 1); /*Count stones and libs for capturing group.*/ if(1==g.nstones && 1==g.nliberties) /*If c.g. is a single stone in atari */ { thegame.kox= capx; thegame.koy= capy; } /* then ko, so mark it.*/ } if(ncap) /*If any enemy stones were removed, */ makegroups(); /* recalculate the board.*/ ncap= capture(p, &capx, &capy);/*Remove any still-trapped stones (suicide).*/ assert(WHITE==p||0==ncap); /*Wally knows not to make suicides.*/ } sortv(p, n) group **p; int n; /* Sort the table p[] or pointers to groups in order of vulnerability, most vulnerable first. Currently this is the slow simple bubble sort we all know. */ { register int uns; /*flag that an unsorted pair was found last pass*/ register group *t, /*exchange temporary*/ **ip; /*pointer through p[]*/ register int j; /*loop index through p*/ do { uns= 0; for(j=0,ip=p; jnliberties< (*ip)->nliberties || (t->nliberties==(*ip)->nliberties && t->nstones>(*ip)->nstones) ) { uns= 1; ip[1]= *ip; *ip= t; } } } while(uns); } int subj_lib(x, y) int x, y; /* Return the subjunctive liberties of the group created by a BLACK move at x, y, that is, how many liberties would it have after the move was made? This is done shoddily, without considering the liberties created by the disappearance of any groups captured by the move. */ { board scratch; /*parameter array of flags for count()*/ group t; /*parameter group for count()*/ assert(onboard(x,y)); assert(EMPTY==theboard[x][y]); /*Make sure we can undo by restoring EMPTY.*/ theboard[x][y]= BLACK; /*Temporarily place the stone in question.*/ /*Clear scratch[][] so count() works properly.*/ { register int *s, j; for(j=EDGE*EDGE,s=(int*)scratch; j--; ) *s++= 0; } /*Make a fake group for the new stone to be part of -- this is */ /* a necessary parameter for count().*/ t.color= BLACK; t.x= x; t.y= y; t.nliberties= 0; t.nstones= 0; /*Show this little Potemkin village to the count().*/ count(x, y, &t, scratch, 1); /*Undo the temporary move (x,y).*/ theboard[x][y]= EMPTY; /*Return the result from count().*/ return t.nliberties; } pattern1(u, masks, movehere) int *u; board masks, movehere; /* A routine called by pattern() to match possible moves to tabulated patterns of specific orientation. *u gives the urgency of the best move found so far; we are to ignore moves which are inferior to this. If this move has not already been found (compare to the urgency value in movehere[]) then we set its urgency value in *u and in movehere[], and put it into the table goodmoves[]. If the move is better than any found before, we put it at the beginning of the table; otherwise we put it in at the pointer pgoodmoves. masks[][] is an array which represents the pieces on the board, translated into bit masks by lookup in flookup[]. A late-breaking modification is that only the EMPTY points which have movehere[][] set are tested, so that pattern() can be called to look for contact plays or possibly other restricted sets which make good patterns. An even later modification permits the use of movehere[][] to tell the urgency of the best move which has been made to that point. */ { register int *is, *iis;/*pointers into patterns[]; or scratch*/ register int j; /*& into a particular pattern, # points remaining*/ register int x, y; /*current position we're trying to match pattern to*/ register int xs, ys; /*position of a point from a pattern*/ int ua; /*urgency and adjustment for this move*/ int thispat; /*which pattern in the table are we currently */ /* trying to match?*/ for(is=patterns,thispat=0; PATTERN==*is; is+= 3+3*(is[1]),++thispat) { for(x=0; x edge-1-y (across a mirror plane parallel to x-axis) (2) x <-> edge-1-x ( " y-axis) (3) y <-> edge-1-y ( " x-axis) (4) x <-> y ( " the line y=x) (5) y <-> edge-1-y (across a mirror plane parallel to x-axis) (6) x <-> edge-1-x ( " y-axis) (7) y <-> edge-1-y ( " x-axis) (8) x <-> -y ( " the line y=(-x)) Draw pictures if necessary to see how this works. */ { register int x, y, t, j, *is; board scratch; /*Translate the board to flags for easy comparison with pattern table.*/ for(x=0; xnstones= 0; /*Clear these before */ g->nliberties= 0; /* passing to count, which increments them.*/ count(g->x, g->y, g, scratch, 1); /*Print out scratch[][] as 9x9 table.*/ if(debugattack) { printf("$In attack after count(), board and scratch are:\n"); for(y=edge-1; y>=0; --y) { printf("$"); for(x=0; xnliberties>=0); /*Look for the best adjacent point.*/ edist= edge*10; /*We haven't found a point near the (2.9)-th line yet.*/ for(x=0; x=ml) /* if not too suicidal*/ { register int toedge= x; /*distance to edge of board*/ if(toedge>edge-1-x) toedge= edge-1-x; if(toedge>y) toedge= y; if(toedge>edge-1-y) toedge= edge-1-y; if(debugattack) fprintf(stderr, "$Looking at %d,%d, toedge=%d, abs=%d.\n", x, y, toedge, abs(10*toedge-21)); if(abs(10*toedge-19)nstones= 0; /*Clear these before */ g->nliberties= 0; /* passing to count, which increments them.*/ count(g->x, g->y, g, scratch, 1); /*Check that there are enough liberties to find a contact play.*/ assert(g->nliberties>=0); /*Return any point which succeeds.*/ for(x=0; xcolor) { ++nf; *igt++= g; } for(j=0,g=groups,ne=0,es=igt; jcolor) { ++ne; *igt++= g; } /*Sort the tables in order of vulnerability to attack.*/ sortv(fs, nf); sortv(es, ne); /*Consider extremely urgent pattern moves.*/ if(upattern<16) { movepattern: if(debugattack) printf("$making pattern, pattern #=%d, urgency=%d.\n", patnum, upattern); x= patternx; y= patterny; goto movexy; } /*Capture the enemy!*/ while(ne && 1==(*es)->nliberties) { if(0==attack(*es, &x, &y, 0)) { if(debugattack) printf("$Capturing the enemy.\n"); goto movexy; } else /*(This case comes up if we can't capture because of ko.)*/ { ++es; --ne; } /*Go on to next most vulnerable group.*/ } if(upattern<24) goto movepattern; /*If we can't do that, then try to protect ourself. But as per Dr. Millen, */ /* don't risk everything crawling along the edge without lookahead.*/ /*However, we have a more powerful computer than the good doctor, so we */ /* can afford to check another condition: if crawling connects to a healthy */ /* group immediately (as when the program makes a pattern match with */ /* O O # */ /* . . O . */ /* ~ ~ ~ ~ */ /* where '~' is off the board, then is attacked with */ /* O O # */ /* . . O # */ /* ~ ~ ~ + */ /* it seems to make no sense to prohibit the program from defending with */ /* O O # */ /* . O O # */ /* ~ ~ ~ ~ */ /* .. so we *don't* prohibit it.*/ while(nf && 1==(*fs)->nliberties) { if(escape(*fs, &x, &y)) /*If we can't see how to escape */ { ++fs; --nf; } /* go on to next friendly group, */ else /* otherwise */ { if((0==x||edge-1==x||0==y||edge-1==y) && /* if crawling */ (2>=subj_lib(x,y)) ) /* and not connecting to strong group */ { ++fs; --nf; continue; } /* this is probably not a good move */ else /* but if not crawling or connecting to */ /* a strong group, go for it.*/ if(debugattack) printf("$Protecting a friendly group from imminent capture.\n"); goto movexy; } } if(upattern<34) goto movepattern; /*Try putting the enemy in atari.*/ while(ne && 2==(*es)->nliberties) /*For all vulnerable enemy groups */ { if(attack(*es, &x, &y, 2)) /* if we can't see how to attack */ { ne--; ++es; } /* go on to the next enemy group, */ else /* otherwise */ { if(debugattack) printf("$Putting an enemy group into atari.\n"); goto movexy; /* attack the group.*/ } } if(upattern0) fprintf(file, "(Black wins.)\n"); else fprintf(file, "(White wins.)\n"); } int ist(x, y, n, scratch) register int x, y, n; board scratch; /*This is the recursive part of isterritory().*/ { assert(onboard(x,y)); assert(EMPTY==theboard[x][y]); assert(0==scratch[x][y]); scratch[x][y]= 1; x= x+1; if(onboard(x,y)) { if(EMPTY==theboard[x][y]) { if(0==scratch[x][y] && 0==ist(x, y, n, scratch)) return 0; } else if(n==theboard[x][y]) return 0; } x= x-2; if(onboard(x,y)) { if(EMPTY==theboard[x][y]) { if(0==scratch[x][y] && 0==ist(x, y, n, scratch)) return 0; } else if(n==theboard[x][y]) return 0; } x= x+1; y= y+1; if(onboard(x,y)) { if(EMPTY==theboard[x][y]) { if(0==scratch[x][y] && 0==ist(x, y, n, scratch)) return 0; } else if(n==theboard[x][y]) return 0; } y= y-2; if(onboard(x,y)) { if(EMPTY==theboard[x][y]) { if(0==scratch[x][y] && 0==ist(x, y, n, scratch)) return 0; } else if(n==theboard[x][y]) return 0; } return 1; } int isterritory(x, y, p) register int x, y, p; /* Return TRUE if the EMPTY point x, y is to be counted as territory for player p. This is only called at the end of the game, and I see no reason why it can't be slow. I don't understand the (Ing?) fractional point rules, so I don't implement them. An empty point counts as territory only if only one player has stones adjacent to the block of empty spaces to which it belongs. */ { board scratch; assert(onboard(x,y)); assert(EMPTY==theboard[x][y]); /*Clear scratch[].*/ { register int x, y; for(x=0; xEDGE) fatal("board size out of range on input line"); edge= maybe; } else if(0==strcmp(*argv,"-even")) /*if we are to play an even game*/ evenmode= 1; #ifdef ADDED else if (strcmp(*argv, "-d") == 0) debugattack = 1; else if (strcmp(*argv, "-mgt") == 0) outputmode = MGT_OUTPUT; else if (strcmp(*argv, "-cat") == 0) outputmode = CAT_OUTPUT; #endif else #ifdef ADDED { #else { char hname[80]; #endif if(0!=ofname) fatal("duplicate filenames in command line"); ofname= *argv; ofile= fopen(ofname, "w"); if(0==ofile) fatal("unable to open output file"); #ifndef ADDED printf("What is the name of my opponent? (for the game record)\n"); gets(hname); fprintf(ofile, "%s (black) vs. %s (white)\n", progname, hname); #endif } } #ifdef ADDED if (ofile == 0) { if (outputmode != WALLY_OUTPUT) { fprintf(stderr, "%s: output file needed for -mgt or -cat\n", progname); exit(1); } } else { if (outputmode != CAT_OUTPUT) { printf("What is the name of my opponent? "); gets(hname); } switch (outputmode) { case WALLY_OUTPUT: /* should match that in #ifndef above */ fprintf(ofile, "%s (black) vs. %s (white)\n", progname, hname); break; case MGT_OUTPUT: time(&secs); fprintf(ofile, "(\n;\nGaMe[1]\nSize[%d]\nVieW[]\nBlackSpec[1]\n", edge); fprintf(ofile, "WhiteSpec[1]\nFileFormat[1]\nPLayer[]\n"); fprintf(ofile, "Comment[Black: %s\nWhite: %s\n\nDate: %s", progname, hname, ctime(&secs)); fprintf(ofile, "Size: %d x %d]\n", edge, edge); /* CAT_OUTPUT doesn't require any of this */ } } #endif if(evenmode) nhandicap[edge]= 0; /*Make a brief explanation.*/ printf("%s\n%s\n", "This program plays (poorly) the oriental game of Go, also", "known as wei-chi."); /*Play the game.*/ initgame(); do if(BLACK==thegame.pla) rvalue=mymove(); else if(WHITE==thegame.pla) rvalue=enemymove(); else panic("illegal thegame.pla in main() loop"); while(rvalue!=BOTHPASS && rvalue!=RESIGN); #ifndef ADDED if(BOTHPASS==rvalue) #endif score(); /*Close the output file.*/ if(ofile) #ifdef ADDED { if (outputmode == MGT_OUTPUT) fprintf(ofile, ")\n"); #endif if(fclose(ofile)) fatal("unable to close output file"); #ifdef ADDED } #endif exit(0); }
/
本文档为【围棋程序源代码】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索