#include #include #include #include "common.h" char otherplayer(char player) { return player^'x'^'o'; } void printtopbottom(Boardstate *b) { long j; printf(" "); for (j=-2; jmaxx+2; j++) printf("%2ld",j+2); printf("\n"); } void printboard(Boardstate *b) { #if 0 printf("maxx=%ld maxy=%ld toplay=%c\n",b->maxx,b->maxy,b->toplay); for (long i=b->maxy-1; i>=0; i--) { for (long j=0; jmaxx; j++) printf("%2x ",b->board[i*b->maxx+j]); printf("\n"); } #endif printtopbottom(b); for (long i=b->maxy+1; i>=-2; i--) { printf("%2ld",i+2); for (long j=-2; jmaxx+2; j++) if (i>=0 && j>=0 && imaxy && jmaxx) printf(" %c",b->board[i*b->maxx+j]); else printf(" "); printf("%2ld\n",i+2); } printtopbottom(b); } /* note: order of lines in file is reversed from what is shown in printboard */ void saveboard(Boardstate *b, char *filename) { long i; FILE *f=fopen(filename,"w"); if (f==NULL) { perror(filename); exit(1); } for (i=0; imaxy; i++) { fwrite(&b->board[i*b->maxx],1,b->maxx,f); fputs("\n",f); } if (fclose(f)!=0) { perror(filename); exit(1); } } Boardstate *loadboard(char *filename) { FILE *f=fopen(filename,"r"); if (f==NULL) { perror(filename); exit(1); } Boardstate *b=malloc(sizeof(Boardstate)); b->maxx=0; b->maxy=1; b->board=malloc(1); int c; for (;;) { c=getc(f); if (c=='\n') break; if (c==EOF) { fprintf(stderr,"%s: format error (no newline)\n",filename); exit(1); } b->maxx++; b->board = realloc(b->board,b->maxx); b->board[b->maxx-1]=c; } while (1) { b->board = realloc(b->board,b->maxx*(b->maxy+1)); size_t len = fread(&b->board[b->maxx*(b->maxy)],1,b->maxx,f); if (len==0) break; b->maxy++; if (len!=b->maxx) { fprintf(stderr,"%s: format error (line too short)\n",filename); exit(1); } c=getc(f); if (c!='\n') { fprintf(stderr,"%s: format error (newline expected)\n",filename); exit(1); } } // printboard(b); /* now check the board */ long i, countx=0, counto=0; for (i=0; imaxx*b->maxy; i++) { if (b->board[i]=='x') countx++; else if (b->board[i]=='o') counto++; else if (b->board[i]!=' ') { fprintf(stderr,"wrong character %d in %s\n",b->board[i],filename); exit(1); } } if (countxcounto+1) { fprintf(stderr,"unbalanced: %ld xs, %ld os\n", countx, counto); exit(1); } b->toplay = (countx==counto)?'x':'o'; return b; } int moveok(Boardstate *b, long x, long y) { // printf("moveok(b,%ld,%ld)\n",x,y); if (x>=0 && xmaxx && y>=0 && ymaxy) if (b->board[y*b->maxx+x]!=' ') return 0; for (long x1=x-2; x1<=x+2; x1++) for (long y1=y-2; y1<=y+2; y1++) if (x1>=0 && x1maxx && y1>=0 && y1maxy) if (b->board[y1*b->maxx+x1]!=' ') return 1; return 0; } int iswin(Boardstate *b) { for (long i=0; imaxy; i++) for (long j=0; jmaxx; j++) { /* check horizontal */ for (long k=0;; k++) { if (j+k >= b->maxx) break; if (b->board[i*b->maxx+j+k] != b->toplay) break; if (k==4) return 1; } /* check vertical */ for (long k=0;; k++) { if (i+k >= b->maxy) break; if (b->board[(i+k)*b->maxx+j] != b->toplay) break; if (k==4) return 1; } /* check diagonal / */ for (long k=0;; k++) { if (j+k >= b-> maxx || i+k >= b->maxy) break; if (b->board[(i+k)*b->maxx+j+k] != b->toplay) break; if (k==4) return 1; } /* check diagonal \ */ for (long k=0;; k++) { if (j-k<0 || i+k >= b->maxy) break; if (b->board[(i+k)*b->maxx+j-k] != b->toplay) break; if (k==4) return 1; } } return 0; } /* if move outside the board, grow the board to include the move */ Boardstate *resizeboard(Boardstate *b, long *px, long *py) { long omaxx=b->maxx; long omaxy=b->maxy; if (*px>=0 && *py>=0 && *px=omaxx) { nmaxx = *px+1; } if (*py<0) { offy = -*py; *py=0; nmaxy += offy; } else if (*py>=omaxy) { nmaxy = *py+1; } char *ob=b->board; char *nb=malloc(nmaxy*nmaxx); // printf("nmaxx=%ld nmaxy=%ld\n",nmaxx,nmaxy); for (long i=0; i=omaxy || oj<0 || oj>=omaxx) { // printf("space i=%ld j=%ld oi=%ld oj=%ld\n",i,j,oi,oj); nb[i*nmaxx+j] = ' '; } else { // printf("board i=%ld j=%ld oi=%ld oj=%ld\n",i,j,oi,oj); nb[i*nmaxx+j] = ob[oi*omaxx+oj]; } } } b->maxx=nmaxx; b->maxy=nmaxy; b->board=nb; free(ob); return b; } int plyfull(Boardstate *b, long x, long y) { if (moveok(b, x, y)) { b=resizeboard(b,&x,&y); assert(x>=0 && xmaxx && y>=0 && ymaxy); b->board[y*b->maxx+x] = b->toplay; if (iswin(b)) return 1; else { b->toplay = otherplayer(b->toplay); return 0; } } else return -1; }