// TODO: call tak // TODO: trap ctrl-c #include #include #include #include #include #include #include "tak.h" #define MAXSTACK 10 #define MAXW 8 #define MAXH 8 #define MAX_CMD_LEN 100 #define MAXPLAYERS 2 #define FORMAT_ROWHEAD "%c " #define FORMAT_ROWTAIL "| %c" #define FORMAT_COLHEAD "| %c " #define FORMAT_COLTAIL "| %c " //#define FORMAT_OWNER "| %c%c |" //#define FORMAT_STACK "|[%-10s]|" #define FORMAT_OWNER "| %s%c%c%s " #define FORMAT_STACK "| %-10s " #define FORMAT_AIVAL "| %s%d%s " #define LINEPART "--------------" #define TRUE (-1) #define FALSE (0) #define ALL (-1) #define BLACK "\e[0;30m" #define BLUE "\e[0;36m" #define RED "\e[0;31m" #define YELLOW "\e[0;33m" #define BOLD "\e[1m" //#define BLUE "\e[0;34m" #define GREEN "\e[0;32m" #define reset "\e[0m" char board[MAXW*MAXH][MAXBOARDSTRLEN]; int aivalue[MAXW*MAXH]; #define BLOCKED -12345 char cmdbuf[MAX_CMD_LEN]; int tilesleft[MAXPLAYERS]; int capsleft[MAXPLAYERS]; int hasroad[MAXPLAYERS]; int gamepoints[MAXPLAYERS]; int roundpoints[MAXPLAYERS]; int ai[MAXPLAYERS]; // for game log char topofmove = ' '; int flattened = FALSE; char movelog[256]; int debug = FALSE; enum direction {NORTH = 0, EAST = 1, SOUTH = 2, WEST = 3}; int size=5; int w=5; int h=5; int curround, numrounds; int turnnumber = 0; int firstturn = 0; // who goes first int gameover = 0; int turn = 0; int winner = -1; void init(void) { int x,y; for (y=0; y < h; y++) { for (x=0; x < w; x++) { strcpy(board[y*w+x], ""); } } } int setupround(void) { int i; int x,y; int starttiles,startcaps; for (y=0; y < h; y++) { for (x=0; x < w; x++) { strcpy(board[y*w+x], ""); } } gameover = 0; turn = firstturn; turnnumber = 1; starttiles = getstarttiles(size); startcaps = getstartcapstones(size); for (i=0; i 8) || (sz == 7)) { printf("error - board size must be between 3 and 8 (but not 7).\n"); return TRUE; } w = h = size = sz; for (i=0; i=0; pos--) { if (!ismod(stack[pos])) break; } if (pos < 0) return ' '; return stack[pos]; } int isdir(char ch) { switch (ch) { case '>': case '<': case '+': case '-': return TRUE; } return FALSE; } int ismod(char ch) { switch (ch) { case 'C': case 'k': case '^': case 'S': case 's': case '|': return TRUE; } return FALSE; } char *getdirname(int dir) { switch (dir) { case '>': return "right"; case '<': return "left"; case '+': return "up"; case '-': return "down"; } return "UNKNOWN_DIR"; } char *getmodname(int mod) { switch (mod) { case 'C': case 'k': case '^': return "capstone"; case 'S': case '|': return "standing stone"; } return "flatstone"; } char *readcmd(char *cmd) { char turntext[64]; if (turnnumber == 1) { sprintf(turntext, "SETUP: %s%s%s placing %s%s's%s initial tile", getpcol(turn),getpname(turn), reset, getpcol(1-turn),getpname(1-turn),reset); printf("R%d/%d-T%d. %s %s==> ",curround,numrounds,turnnumber, turntext, getpcol(turn)); } else { sprintf(turntext, "%s%s's%s turn", getpcol(turn),getpname(turn),reset); printf("R%d/%d-T%d. %s (%s%sstones:%s%s%d %scapstones%s%s:%d%s) %s==> ",curround,numrounds,turnnumber, turntext, getpcol(turn), BOLD, reset, getpcol(turn), tilesleft[turn], BOLD, reset,getpcol(turn),capsleft[turn],reset, getpcol(turn)); } printf("%s",BOLD); if (ai[turn]) { genaicmd(cmd, FALSE); printf("%s\n",cmd); } else { fgets(cmd ,MAX_CMD_LEN, stdin); if (cmd) { cmd[strlen(cmd)-1] = 0; } } printf("%s",reset); return cmd; } char *genaicmd(char *cmd, int showdb) { int x,y,best; int ncandidates; int candidate[MAXW*MAXH]; int sel, xsel, ysel,xpossel,ypossel; // zero all priorities for (y=0; y < h; y++) { for (x=0; x < w; x++) { aivalue[y*w+x] = 500; } } // mark anywhere we definitely cannot go for (y=0; y < h; y++) { for (x=0; x < w; x++) { int idx = y*w+x; if (!canplacetile(turn, x, y, ' ', NULL) && !canmoveanyto(turn, x, y, NULL)) { aivalue[idx] = BLOCKED; } else if (xywouldgivewinto(1-turn, x, y)) { modaivalue(x, y, 999); } } } // determine the best priority best = -1; for (y=0; y < h; y++) { for (x=0; x < w; x++) { if ((aivalue[y*w+x] != BLOCKED) && (aivalue[y*w+x] > best)) { best = aivalue[y*w+x]; } } } if (showdb) { showaivalues(best); } printf("*** best value is = %d\n", best); // pick randomly from the best priority ncandidates = 0; for (y=0; y < h; y++) { for (x=0; x < w; x++) { if (aivalue[y*w+x] == best) { candidate[ncandidates++] = y*w+x; } } } printf("*** ncandidates = %d\n", ncandidates); if (ncandidates == 0) { sprintf(cmd, "\\r"); } else { char str[256]; sel = rand() % ncandidates; idxtoxy(candidate[sel], &xsel, &ysel); xytopos(xsel,ysel,&xpossel, &ypossel); // we place a tile here or move here? if (canmoveanyto(turn, x, y, str)) { // move sprintf(cmd, "%s", str); } else { // place sprintf(cmd, "%c%c", xpossel,ypossel); } } return cmd; } int xywouldgivewinto(int who, int tx, int ty) { char board2[MAXW*MAXH][MAXBOARDSTRLEN]; int x,y,wouldwin = FALSE; // take copy of board for (y=0; y < h; y++) { for (x=0; x < w; x++) { strcpy(board2[y*w+x], board[y*w+x]); } } // force owner of given position to given player strcat(board2[ty*w+tx], getpstr(who)); if ( playerhasroads(who, board2)) { wouldwin = TRUE; } return wouldwin; } void idxtoxy(int idx, int *x, int *y) { if (x) *x = idx % w; if (y) *y = idx / w; } int modaivalue(int x,int y,int amt) { int idx=y*w+x; if (aivalue[idx] == BLOCKED) { return TRUE; } aivalue[idx] += amt; return FALSE; } int isboardfull() { int x,y; for (y=0; y < h; y++) { for (x=0; x < w; x++) { if (!counttiles(board[y*w+x])) return FALSE; } } return TRUE; } void updateroadstatus(void) { int i; // update road status for each player for (i=0; i origcount) { printf("* %s can't move %s tiles %s from %c%c - only %d there\n",getpname(turn),countstr,getdirname(dir), xch,ych,origcount); return TRUE; } dirtoxy(dir,&xmod,&ymod); numtomove = count; // First pass: validate each step for (pass=0; pass <= 1; pass++) { int remaining,numtodrop; if (pass == 1) { if (debug) printf("- %s%s%s is moving %d tiles %s from %c%c, dropping %s\n", getpcol(turn), getpname(turn), reset, count, getdirname(dir), xch, ych, strlen(dropstr) ? dropstr : "*"); } //printf("PASS %d\n",pass); postoxy(xch,ych,&x, &y); // pick up stack of tiles to move p = bpos + strlen(bpos)-1; //printf("debug: bpos is: %s\n", bpos); //printf("debug: p is: %s\n", p); if (ismod(*p)) p--; p -= (count-1) ; //printf("debug: new p is: %s\n", p); strcpy(moving, p); if (pass == 1) { // actually remove tiles from source location *p = 0; } // begin at start of drop string dp = dropstr; // start dropping from bottom of moving stack mp = moving; newxch = xch; newych = ych; while ((remaining = counttiles(mp))) { //printf("remaining in mp: %d\n",remaining);; //printf("move %s from %d,%d (%c%c)", getdirname(dir), x,y,newxch,newych); x += xmod; y += ymod; // still on the board? if (!isvalidxy(x,y)) { printf("* %s can't move %s tiles %s from %c%c - would move off board with %d tiles remaining\n",getpname(turn),countstr,getdirname(dir), xch,ych, remaining); return TRUE; } xytopos(x, y, &newxch, &newych); newpos = y*w+x; newbpos = board[newpos]; //printf("now at %d,%d (%c%c)", x,y,newxch,newych); mod = getmod(newbpos); if (!canmoveto(turn, x, y, err)) { printf("* %s can't move %s tiles %s from %c%c - %s\n",getpname(turn),countstr,getdirname(dir), xch,ych, err); return TRUE; } else if ((mod == '|') && (remaining > 1)) { // stack of > 1 moving onto standing stone printf("* %s can't move %s tiles %s from %c%c - %d tiles blocked by %s standing stone at %c%c\n",getpname(turn),countstr,getdirname(dir), xch,ych, remaining, getpname(getowner(newbpos)), newxch,newych); return TRUE; } else if ((mod == '|') && (getmod(mp) != '^')) { // non-capstone moving onto standing stone printf("* %s can't move %s tiles %s from %c%c - only capstone can move onto %s standing stone at %c%c\n",getpname(turn),countstr,getdirname(dir), xch,ych, getpname(getowner(newbpos)), newxch,newych); return TRUE; } else if ((mod == '|') && (remaining == 1) && (getmod(mp) == '^')) { // single capstone moving onto a standing stone // TODO: can yoi flatten yourbown standing stone? if (pass == 1) { if (debug) printf(" - %s%s%s capstone flattens %s%s%s standing stone at %c%c!\n",getpcol(turn),getpname(turn),reset, getpcol(getowner(newbpos)),getpname(getowner(newbpos)), reset, newxch,newych); newbpos[strlen(newbpos)-1] = 0;; flattened = TRUE; } } // drop tiles if (!dp || *dp == 0) { numtodrop = remaining; } else { numtodrop = *dp - '0'; } if (numtodrop > remaining) { printf("* %s can't move %s tiles %s from %c%c with '%s' - want to drop %d tiles at %c%c but only %d remain\n",getpname(turn),countstr,getdirname(dir), xch,ych, dropstr, numtodrop, newxch,newych, remaining); return TRUE; } // construct string of tiles to drop strncpy(dropping, mp, numtodrop); dropping[numtodrop] = 0; // retain top capstone/standingstone if (ismod(*(mp+numtodrop))) { strncat(dropping, mp+numtodrop, 1); mp++; // havk } if (pass == 1) { char colorstr[MAXSTACK*10]; // add ansi color codes makecolorstr(dropping, colorstr); if (debug) { printf(" - dropping '%s' (%d) at %c%c. remaining: '%s' (%d)\n", colorstr, numtodrop, newxch,newych, (mp+numtodrop), counttiles(mp+numtodrop)); } // actually drop tiles here strcat(newbpos, dropping); } // remove dropped tiles from moving stack mp += numtodrop; // advance to next drop count entry dp++; } } return FALSE; } void dirtoxy(char dir, int *x, int *y) { *x = 0; *y = 0; switch (dir) { case '>': *x = 1; *y = 0; break; case '<': *x = -1; *y = 0; break; case '+': *x = 0; *y = 1; break; case '-': *x = 0; *y = -1; break; } } int placetile(int who,char xch,char ych, char mod) { int pos,x,y; char *bpos; char err[256]; if (mod) mod = modprintable(mod); postoxy(xch,ych,&x, &y); pos = y*w+x; bpos = board[pos]; if (!canplacetile(who, x, y, mod, err)) { // is this space available? printf("* %s\n",err); return TRUE; } if (debug) printf("-- placing %s %s at %c%c\n", getpname(who), getmodname(mod), xch, ych); strcat(bpos, getpstr(who)); if (mod) { strncat(bpos, &mod, 1); } if (mod == '^') { capsleft[who]--; } else { tilesleft[who]--; } return FALSE; } int canplacetile(int who, int x, int y, int mod, char *why) { int idx,xch,ych; char *bpos; xytopos(x,y,&xch, &ych); idx = y*w+x; bpos = board[idx]; if (why) strcpy(why,""); // placing capstone on first turn? if (turnnumber == 1 && ((mod == '|') || (mod == '^'))) { if (why) sprintf(why,"can't place %s %s at %c%c - can only place flat tiles during setup, mod is '%c'\n",getpname(who),getmodname(mod),xch,ych,mod); return FALSE; } if ((mod == '^') && (capsleft[who] <= 0)) { if (why) sprintf(why, "can't place %s %s at %c%c - no capstones left\n",getpname(who),getmodname(mod),xch,ych); return FALSE; } if (strlen(bpos) > 0) { if (why) sprintf(why, "can't place %s %s at %c%c - not free\n",getpname(who),getmodname(mod),xch,ych); return FALSE; } return TRUE; } int canmoveanyto(int who, int tx, int ty, char *why) { int x,y; if (!canmoveto(who, tx, ty, why)) return FALSE; if (why) strcpy(why,""); // for each tile we control, see if it can move to given spot for (y=0; y < h; y++) { for (x=0; x < w; x++) { int ok = TRUE; int count; if( (x == tx) && (y == ty)) { ok = FALSE; } if (ok && (x != tx) && (y != ty)) { // same row/col ok = FALSE; } if ( ok && !canmovefrom(who, x, y, why)) { // got somethong to move here ok = FALSE; } count = counttiles(board[y*w+x]); if (ok && (x == tx) && abs(tx - x) > count) { // distance ok? ok = FALSE; } if (ok && (y == ty) && abs(ty - y) > count) { // distance ok? ok = FALSE; } // can this stack get one of our color to there??? if (canmakedropstr(who, x,y,tx,ty,why)) { return TRUE; } } } return FALSE; } int canmakedropstr(int who, int sx, int sy, int dx, int dy, char *str) { // return TRUE if we succeeded int count,maxtry,trystacksize, d; char moving[MAXSTACK*2]; char *mp; char *p; char *spos; int smod; int xmod[]={0, 1, 0, -1}; /// nesw int ymod[]={1, 0, -1, 0}; /// nesw char localstr[256]; int db = TRUE; spos=board[sy*w+sx]; smod = getmod(spos); count = counttiles(board[sy*w+sx]); if (count < 1) { return FALSE; } if (count > size) maxtry = size; else maxtry = count; // which dir? if ((sx == dx) && (sy < dy)) { d = 0; } else if ((sx == dx) && (sy > dy)) { d = 2; } else if ((sy == dy) && (sx > dx)) { d = 3; } else if ((sy == dy) && (sx < dx)) { d = 1; } else { return FALSE; } // try each stack size for (trystacksize = 1; trystacksize <= maxtry; trystacksize++) { int x,y; int stillgood = TRUE; int xch,ych; // pick up stack of tiles to move p = spos + strlen(spos)-1; if (ismod(*p)) p--; p -= (trystacksize-1) ; strcpy(moving, p); mp = moving; // max distance we can move before hitting wall/cap/edge? x = sx; y = sy; xytopos(x, y, &xch, &ych); stillgood = TRUE; sprintf(localstr, "%d%c%c%c", trystacksize,xch,ych,getdirchar(d)); while (stillgood) { // move one cell toward dst x += xmod[d]; y += ymod[d]; if (!isvalidxy(x,y) || getmodxy(x,y) == '^' || (getmodxy(x,y) == '|' && (smod != '^' || counttiles(mp) != 1)) ) { // hit a blocker - stop stillgood = FALSE; } else { // are we there yet if (x == dx && y == dy) { char temp[64]; // dump the rest here and we're done sprintf(temp, "%1d",counttiles(mp)); strcat(localstr, temp); if (str) strcpy(str,localstr); return TRUE; // TODO: go further to control mlre locations } else { char *z; // not there yet. // must drop at least one // TODO: drop more than 1, prefer our color //z = strchr(mp, getpchar(who)); // stone to drop. z = mp; // drop 1 if (z) { // if match, drop so it's on top int numtodrop = (z - moving) + 1; char temp[10]; sprintf(temp, "%1d",numtodrop); strcat(localstr, temp); if (db) printf("db: ** numtodrop: %d. tiles in stack: %d (%s)\n", numtodrop, counttiles(mp), mp); // no more tiles in moving stack?? if (numtodrop >= counttiles(mp)) { // this stack size. stillgood = FALSE; } else { // remove dropped tiles from moving stack mp += numtodrop; if (db) printf("db: ** new tiles in stack: %d (%s)\n", counttiles(mp), mp); } } else { // if not, fail this stack size. stillgood = FALSE; } } } } } return FALSE; } char getdirchar(int dir) { switch (dir) { case 1: return '>'; case 3: return '<'; case 0: return '+'; case 2: return '-'; } return '='; } int canmovefrom(int who, int x, int y, char *why) { int mod; int idx,xch,ych; char *bpos; xytopos(x,y,&xch, &ych); idx = y*w+x; bpos = board[idx]; mod = getmod(bpos); if (why) strcpy(why,""); // is there anything at the source location? if (!strlen(bpos) ) { sprintf(why, "empty source location\n"); return FALSE; } // does the other player own the source location? if (getowner(bpos) == getpchar(1 - who)) { sprintf(why, "not owner of source location\n"); return FALSE; } return TRUE; } int canmoveto(int who, int x, int y, char *why) { int mod; int idx,xch,ych; char *bpos; xytopos(x,y,&xch, &ych); idx = y*w+x; bpos = board[idx]; mod = getmod(bpos); if (why) strcpy(why,""); if (mod == '^') { // capstone? sprintf(why, "%s capstone at %c%c\n",getpname(getowner(bpos)), xch,ych); return FALSE; } return TRUE; } int isvalidxy(int x, int y) { if (x >= 0 && x < w && y >= 0 && y < w) { return TRUE; } return FALSE; } int isvalidxypos(char x, char y) { char firstx = 'a'; char lastx = 'a' + w - 1; char firsty = '1'; char lasty = '1'+h-1; if (x >= firstx && x <= lastx && y >= firsty && y <= lasty) { return TRUE; } return FALSE; } int parsecmd(char *cmd) { int err = FALSE; int mod=0; char *p=cmd; if (!p) return TRUE; if (!strcmp(cmd, "\\r")) { // resign winner = 1-turn; logmove(turn, cmd, ' '); return FALSE; } else if (strstr(cmd, "\\w ")) { // check if loc would give us a win int xpos,ypos,x,y,wouldwin; p = cmd + 3; xpos = p[0]; ypos = p[1]; postoxy(xpos,ypos,&x,&y); wouldwin = xywouldgivewinto(turn, x, y); printf(" *** would %c%c give us a win? %s\n", xpos,ypos, wouldwin ? "YES" : "no"); return TRUE; } else if (strstr(cmd, "\\m ")) { // check if we can move to loc char temp[256]; int xpos,ypos,x,y; p = cmd + 3; xpos = p[0]; ypos = p[1]; postoxy(xpos,ypos,&x,&y); if (canmoveanyto(turn, x, y, temp)) { printf(" *** %c%c is reachable: %s\n", xpos,ypos, temp); } else { printf(" *** can't move to %c%c\n", xpos,ypos); } return TRUE; } else if (!strcmp(cmd, "\\a")) { // simlulate AI move for us, with debug info char cmd[256]; genaicmd(cmd, TRUE); return TRUE; } if (ismod(p[0])) { mod = p[0]; p++; } if (strchr(p, 'q')) { gameover = TRUE; } else if (isalpha(p[0]) && isdigit(p[1]) && isdir(p[2])) { // move all tiles in direction int xpos = p[0]; int ypos = p[1]; int dir = p[2]; if (movetile(ALL,xpos,ypos,dir,p+3)) err = TRUE; } else if (isdigit(p[0]) && isalpha(p[1]) && isdigit(p[2]) && isdir(p[3]) ) { // move x tiles in direction int count = p[0] - '0'; int xpos = p[1]; int ypos = p[2]; int dir = p[3]; if (count > size) { printf("* can't move more than %d tiles\n",size); err = TRUE; } else { if (movetile(count,xpos,ypos,dir,p+4)) err = TRUE; } } else if ((strlen(p) == 2) && isalpha(p[0]) && isdigit(p[1]) ) { // place tile int xpos = p[0]; int ypos = p[1]; if (isvalidxypos(xpos,ypos)) { if (placetile((turnnumber == 1) ? (1-turn) : turn,xpos,ypos,mod)) err = TRUE; } else { printf("* invalid cell reference '%c%c'\n",xpos,ypos); err = TRUE; } } else { printf("* bad command '%s'\n",cmd); err = TRUE; } if (err && ai[turn]) { char temp[10]; printf("...ai made an error?!"); fgets(temp ,MAX_CMD_LEN, stdin); exit(1); } if (!err) { logmove(turn, cmd, topofmove); } return err; } char *makecolorstr(char *orig, char *newstr) { char *p; char *curcol; strcpy(newstr, ""); for (p = orig; *p; p++) { if (!ismod(*p)) { curcol = getpcol(getpchar(*p)); strcat(newstr, curcol); } strncat(newstr, p, 1); } strcat(newstr, reset); return newstr; } void showaivalues(int best) { int x,y; char ch; printf(FORMAT_ROWHEAD, ' '); ch = 'a'; for (x=0; x < w; x++) { printf(FORMAT_COLHEAD, ch++); } printf(FORMAT_ROWTAIL, ' '); printf("\n"); line(); ch = '1' + h - 1; for (y=h-1; y >= 0; y--) { // show ai priority values printf(FORMAT_ROWHEAD, ch); for (x=0; x < w; x++) { int val = aivalue[y*w+x]; // show owner printf(FORMAT_AIVAL, val == best ? GREEN : YELLOW, val, reset); } printf(FORMAT_ROWTAIL, ch); printf("\n"); // TODO: move this to a function // show board stack printf(FORMAT_ROWHEAD, ch); for (x=0; x < w; x++) { char *str = board[y*w+x]; // show stack if (str) { char origstr[MAXSTACK*10]; char colorstr[MAXSTACK*10]; sprintf(origstr,FORMAT_STACK, str ? str : " "); // add ansi color codes makecolorstr(origstr, colorstr); //strcpy(colorstr,origstr); printf("%s", colorstr); } else { printf(FORMAT_STACK, " "); } } printf(FORMAT_ROWTAIL, ch); ch--; printf("\n"); line(); } printf(FORMAT_ROWHEAD, ' '); ch = 'a'; for (x=0; x < w; x++) { printf(FORMAT_COLHEAD, ch++); } printf(FORMAT_ROWTAIL, ' '); printf("\n"); /* for (i=0;i= 0; y--) { /* printf(FORMAT_ROWHEAD, ch); for (x=0; x < w; x++) { char *str = board[y*w+x]; // show owner printf(FORMAT_OWNER, getpcol(getowner(str)),getowner(str), getmod(str), reset); } printf(FORMAT_ROWTAIL, ch); printf("\n"); */ printf(FORMAT_ROWHEAD, ch); for (x=0; x < w; x++) { char *str = board[y*w+x]; // show stack if (str) { char origstr[MAXSTACK*10]; char colorstr[MAXSTACK*10]; sprintf(origstr,FORMAT_STACK, str ? str : " "); // add ansi color codes makecolorstr(origstr, colorstr); //strcpy(colorstr,origstr); printf("%s", colorstr); } else { printf(FORMAT_STACK, " "); } } printf(FORMAT_ROWTAIL, ch); ch--; printf("\n"); line(); } printf(FORMAT_ROWHEAD, ' '); ch = 'a'; for (x=0; x < w; x++) { printf(FORMAT_COLHEAD, ch++); } printf(FORMAT_ROWTAIL, ' '); printf("\n"); /* for (i=0;i= 0; y--) { line[y] = 0; for (x=0; x < w; x++) { char *str = board[y*w+x]; if ((getmod(str) != '|') && getowner(str) != ' ' && (getpnum(getowner(str)) == pnum)) { int this; this = 1 << xtoleftshift(x); line[y] |= this; } } printbinaryline(ch--, line[y], TRUE); } //printbinaryline('X', vline); for (y=h-1; y >= 0; y--) { hline |= line[y]; vline &= line[y]; //printbinaryline('x', vline); } /* printf("raw:\n"); ch = '1' + h - 1; for (y=h-1; y >= 0; y--) { line[y] = 0; printf("%c - ", ch--); // show line for (x=0; x < w; x++) { char *str = board[y*w+x]; if ((getmod(str) != '|') && getowner(str) != ' ' && (getpnum(getowner(str)) == pnum)) { printf("%d",1); } else { printf("%d",0); } } printf("\n"); } */ printf("horizontal line:\n"); printbinaryline('H', hline, FALSE); printf(" - %s\n",(hline == allones) ? "YES" : ""); // all 1s = yes printf("vertical line:\n"); printbinaryline('V', vline, FALSE); printf(" - %s\n",(vline) ? "YES" : ""); // all 1s = yes } int xyvalidforroad(char (*b)[MAXBOARDSTRLEN], int who, int x, int y) { char *cell; cell = b[y*w+x]; if (isvalidxy(x,y) && (getpnum(getowner(cell)) == who) && (getmod(cell) != '|')) { return TRUE; } return FALSE; } int checkxyforroad(char (*b)[MAXBOARDSTRLEN], int who, int sx, int sy, int sd) { int xmod[]={0, 1, 0, -1}; /// nesw int ymod[]={1, 0, -1, 0}; /// nesw int x,y,newx,newy,d,xch,ych,newxch,newych; int startxch,startych; int startdir,done,turncount; int db = 0; int visited[MAXW*MAXH]; // mark everywhere as not visited for (y=0; y < h; y++) { for (x=0; x < w; x++) { visited[y*w+x] = 0; } } x=sx; y=sy; d=sd; startdir=d; xytopos(x, y, &xch, &ych); startxch = xch; startych = ych; if (db) fprintf(stderr,"** db: looking for %s roads from %c%c (owned by %c / %d)\n", getpname(who), xch,ych, getowner(b[sy*w+sx]), getpnum(getowner(b[sy*w+sx]))); if (getpnum(getowner(b[sy*w+sx])) != who) { if (db) fprintf(stderr,"** db: %s doesn't own %c%c - stopping\n", getpname(who), xch,ych); return FALSE; } done = FALSE; turncount = 0; while (!done) { int moved = FALSE; int leftdir,rightdir; // figure out where left/right is. leftdir = (d - 1); if (leftdir < 0) leftdir = 3; rightdir = (d + 1); if (rightdir >= 4) rightdir = 0; // is there a valid cell in the current dir? newx = x + xmod[d]; newy = y + ymod[d]; xytopos(newx, newy, &newxch, &newych); if (db) fprintf(stderr,"** db: Checking forward (dir %d) from %c%c (%c%c)\n", d, xch,ych,newxch,newych); if (xyvalidforroad(b, who,newx,newy)) { x = newx; y = newy; moved = TRUE; } else { // turn left newx = x + xmod[leftdir]; newy = y + ymod[leftdir]; xytopos(newx, newy, &newxch, &newych); if (db) fprintf(stderr,"** db: Checking left (dir %d) from %c%c (%c%c)\n", leftdir, xch,ych,newxch,newych); if (xyvalidforroad(b, who,newx,newy)) { x = newx; y = newy; d = leftdir; moved = TRUE; } else { // turn right newx = x + xmod[rightdir]; newy = y + ymod[rightdir]; xytopos(newx, newy, &newxch, &newych); if (db) fprintf(stderr,"** db: Checking right (dir %d) from %c%c (%c%c)\n", rightdir, xch,ych,newxch,newych); if (xyvalidforroad(b, who,newx,newy)) { x = newx; y = newy; d = rightdir; moved = TRUE; } else { // reverse direction if (--d < 0) d = 3; if (--d < 0) d = 3; if (db) fprintf(stderr,"** db: Turning around (dir %d) from %c%c (%c%c)\n", d, xch,ych,newxch,newych); if (xyvalidforroad(b, who,newx,newy)) { x = newx; y = newy; moved = TRUE; } else { if (db) fprintf(stderr,"** db: Couldn't turn around - no roads.\n"); done = TRUE; } } } } if (moved) { if (db) fprintf(stderr,"** db: %c%c is owned by us, moving there.\n", newxch,newych); xch = newxch; ych = newych; turncount = 0; // back to start? if ((x == sx) && (y == sy)) { if (db) fprintf(stderr,"** db: We're back at the start (%c%c) - no roads.\n", startxch,startych); done = TRUE; // other side? } else if ((sx == 0) && (x == w-1)) { if (db) fprintf(stderr,"** db: Horizontal w->e path from from %c%c to %c%c!\n", startxch,startych,xch,ych); return TRUE; } else if ((sx == w-1) && (x == 0)) { if (db) fprintf(stderr,"** db: Horizontal e->w path from from %c%c to %c%c!\n", startxch,startych,xch,ych); return TRUE; } else if ((sy == 0) && (y == h-1)) { if (db) fprintf(stderr,"** db: Vertical s->n path from from %c%c to %c%c!\n", startxch,startych,xch,ych); return TRUE; } else if ((sy == h-1) && (y == 0)) { if (db) fprintf(stderr,"** db: Vertical n->s path from from %c%c to %c%c!\n", startxch,startych,xch,ych); return TRUE; } } else { // didn't move? done = TRUE; } } if (db) fprintf(stderr,"** db: No roads found. Returning false.\n"); return FALSE; } int playerhasroads(int pnum, char (*b)[]) { int x,y; // check for roads from bottom to top for (x=0; x < w; x++) { if (checkxyforroad(b, pnum, x, 0, NORTH)) return TRUE; } // check for roads from left to right for (y=h-1; y >= 0; y--) { if (checkxyforroad(b, pnum, 0, y, EAST)) return TRUE; } return FALSE; } void printbinaryline(char prefix, int num, int wantcr) { int x; // show line number printf("%c - ", prefix); // show line for (x=0; x < w; x++) { if (num & (1 << xtoleftshift(x))) { printf("%d",1); } else { printf("%d",0); } } if (wantcr) printf("\n"); } void line(void) { int x; for (x=0; x < w; x++) { printf("%s", LINEPART); } printf("\n"); } int gotwinner(void) { if (winner >= 0) { return TRUE; } return FALSE; } void determinewinner(void) { int x,y,i; int flatstones[MAXPLAYERS]; int stonepoints,sizepoints; // win by roads? if (!gotwinner()) { if (hasroad[0] && hasroad[1]) { // current turn wins a tie winner = turn; } else if (hasroad[0]) { winner = 0; } else if (hasroad[1]) { winner = 1; } } if (!gotwinner()) { // count flatstones for (y=0; y < h; y++) { for (x=0; x < w; x++) { if (!getmod(board[y*w+x])) { flatstones[getpnum(getowner(board[y*w+x]))]++; } } } if (flatstones[0] > flatstones[1]) { winner = 0; } else if (flatstones[0] < flatstones[1]) { winner = 0; } else { // current turn wins a tie winner = turn; } } if (!gotwinner()) { // shouldn't be possible... winner = turn; } // only winner gets points // 1 point for every board square (size*size) // 1 point for each of their remaining tiles sizepoints = (size * size); stonepoints = tilesleft[winner]; roundpoints[winner] = sizepoints + stonepoints; printf("%s*** %s%s%s%s%s wins round %d and earns %d points (%d from board size, %d from remaining tiles)%s\n", BOLD, getpcol(winner), BOLD, getpname(winner), reset, BOLD, curround, roundpoints[winner], sizepoints, stonepoints,reset); // update totals for (i=0; i