many fixes

This commit is contained in:
Rob Pearce 2021-02-17 21:50:31 +11:00
parent 7e3110d1c3
commit 18ad1e286c
2 changed files with 545 additions and 95 deletions

616
tak.c
View File

@ -1,4 +1,3 @@
// TODO: call tak
// TODO: trap ctrl-c
#include <ctype.h>
#include <math.h>
@ -25,7 +24,7 @@
//#define FORMAT_STACK "|[%-10s]|"
#define FORMAT_OWNER "| %s%c%c%s "
#define FORMAT_STACK "| %-10s "
#define FORMAT_AIVAL "| %s%d%s "
#define FORMAT_AIVAL "| %s%5d%s /%2d "
#define LINEPART "--------------"
#define TRUE (-1)
@ -43,8 +42,10 @@
char board[MAXW*MAXH][MAXBOARDSTRLEN];
int aivalue[MAXW*MAXH];
#define BLOCKED -12345
int aidef[MAXW*MAXH];
#define BLOCKED -999
char cmdbuf[MAX_CMD_LEN];
char aireason[MAXW*MAXH][2048];
int tilesleft[MAXPLAYERS];
int capsleft[MAXPLAYERS];
@ -56,12 +57,15 @@ int ai[MAXPLAYERS];
// for game log
char topofmove = ' ';
int flattened = FALSE;
int tak[MAXPLAYERS];
char movelog[256];
int debug = FALSE;
int xmod[]={0, 1, 0, -1}; /// nesw
int ymod[]={1, 0, -1, 0}; /// nesw
enum direction {NORTH = 0, EAST = 1, SOUTH = 2, WEST = 3};
int size=5;
@ -105,10 +109,11 @@ int setupround(void) {
capsleft[i] = startcaps;
hasroad[i] = FALSE;
roundpoints[i] = 0;
tak[i] = FALSE;
}
ai[0] = FALSE;
ai[1] = FALSE;
//ai[1] = TRUE;
//ai[1] = FALSE;
ai[1] = TRUE;
for (i=0; i<MAXPLAYERS; i++) {
roundpoints[i] = 0;
@ -188,6 +193,18 @@ char counttiles(char *stack) {
return count;
}
int getownernumxy(int x, int y) {
return getpnum(getownerxy(x,y));
}
char getownerxy(int x, int y) {
char *s;
s = board[y*w+x];
return getowner(s);
}
char getowner(char *stack) {
int pos;
if (!stack) return ' ';
@ -263,7 +280,7 @@ char *readcmd(char *cmd) {
}
printf("%s",BOLD);
if (ai[turn]) {
genaicmd(cmd, FALSE);
genaicmd(cmd, TRUE, (turnnumber == 1) ? TRUE : FALSE);
printf("%s\n",cmd);
} else {
fgets(cmd ,MAX_CMD_LEN, stdin);
@ -275,7 +292,206 @@ char *readcmd(char *cmd) {
return cmd;
}
char *genaicmd(char *cmd, int showdb) {
int rowhasmod(int sx, int sy, char mod, int who) {
int count=0;
int x;
if (!isvalidxy(sx,sy)) {
return 0;
}
for (x=0; x < w; x++) {
if (getmodxy(x,sy) == mod) {
count++;
}
}
return count;
}
int colhasmod(int sx, int sy, char mod, int who) {
int count=0;
int y;
if (!isvalidxy(sx,sy)) {
return 0;
}
for (y=0; y < h; y++) {
if (getmodxy(sx,y) == mod) {
count++;
}
}
return count;
}
int countownedinrow(int sx, int sy, int who) {
int count=0;
int x;
char *s;
if (!isvalidxy(sx,sy)) {
return 0;
}
for (x=0; x < w; x++) {
if (x != sx) {
s = board[sy*w+x];
if (getpnum(getowner(s)) == who) {
count++;
}
}
}
return count;
}
int countownedincol(int sx, int sy, int who) {
int count=0;
int y;
char *s;
if (!isvalidxy(sx,sy)) {
return 0;
}
for (y=0; y < h; y++) {
if (y != sy) {
s = board[y*w+sx];
if (getpnum(getowner(s)) == who) {
count++;
}
}
}
return count;
}
int countadjacent(int x, int y, int who) {
int count=0,d;
int newx,newy;
char *s;
if (!isvalidxy(x,y)) {
return 0;
}
for (d=0; d <=3; d++) {
newx = x + xmod[d];
newy = y + ymod[d];
//printf("* checking %d,%d for spaces owned by who=%d\n",newx,newy,who);
if (isvalidxy(newx,newy)) {
//printf("* %d,%d is valid\n",newx,newy);
s = board[newy*w+newx];
//printf("* %d,%d is owned by: %c (player %d)\n",newx,newy,getowner(s),getpnum(getowner(s)));
if (getpnum(getowner(s)) == who) {
count++;
}
}
}
return count;
}
void aiupdatetile(int x, int y) {
int multi;
int xpos,ypos;
int idx = y*w+x;
int n,a,b,c;
char temp[1024];
xytopos(x,y,&xpos,&ypos);
if (!canplacetile(turn, x, y, ' ', NULL) &&
!canmoveanyto(turn, x, y, NULL, TRUE)) {
aivalue[idx] = BLOCKED;
} else if (xywouldgivewinto(turn, x, y)) { // would make us win
modaivalue(x, y, 999, "would make us win");
modaivalue_around(x, y, 10, "would make us win"); //adjust surrounding
modaidef_around(x, y, 1);
modaidef(x, y, -999);
} else if (xywouldgivewinto(1-turn, x, y)) { // would make other player win
modaivalue(x, y, 800, "would give win to other player");
modaivalue_around(x, y, 12, "would give win to other player"); //adjust surrounding
modaidef(x, y, 10);
modaidef_around(x, y, 2);
}
// if we already own it, probably dont want to go there
if (getownernumxy(x, y) == turn) {
modaivalue(x,y, -15, "we own this space already");
} else {
n = countadjacent(x,y,turn);
// modify based on adjacent controlled locations
snprintf(temp, 1024, "we own %d adjacent cells", n);
modaivalue(x,y, n * 1, temp); // controlled by us
}
if (getownernumxy(x, y) == turn) {
multi = 1;
} else {
multi = 2;
}
n = countadjacent(x,y,1 - turn);
snprintf(temp, 1024, "other player owns %d adjacent cells", n);
modaivalue(x,y, n * multi, temp); // controlled by other player
modaidef_around(x, y, countadjacent(x,y,1 - turn) * 1);
// If we DONT own this location, consider other stones in the same row/col
if (getownernumxy(x, y) != turn) {
n = countownedinrow(x,y,turn) - rowhasmod(x,y,turn,'|'); // dont include our walls since they don't count in roads
snprintf(temp, 1024, "we own %d cells in this row", n);
modaivalue(x,y, n * 6, temp);
n = countownedincol(x,y,turn) - colhasmod(x,y,turn,'|'); // don't include our walls since they don't count in roads
snprintf(temp, 1024, "we own %d cells in this column", n);
modaivalue(x,y, n * 6, temp);
// opponent tiles in row, offset by our walls/caps
multi = 2;
a = rowhasmod(x,y,'^',turn);
multi -= a;
b = rowhasmod(x,y,'|',turn);
multi -= b;
if (getownernumxy(x, y) == ' ') { // cells noone owns are more valuable
c = 1;
multi += 1;
} else {
c=0;
}
n = countownedinrow(x,y,1-turn) - rowhasmod(x,y,'|',1 - turn); // don't include their walls
snprintf(temp, 1024, "other player has %d cells in row (we have %d caps + %d walls == %d multiplier)", n, a, b, multi);
if (multi > 0) {
modaivalue(x,y, n * multi, temp);
}
modaidef(x,y, n * 1);
// opponent tiles in col, offset by our walls/caps
multi = 2;
a = colhasmod(x,y,'^',turn);
multi -= a;
b = colhasmod(x,y,'|',turn);
multi -= b;
if (getownernumxy(x, y) == ' ') { // cells noone owns are more valuable
c = 1;
multi += 1;
} else {
c=0;
}
n = countownedincol(x,y,1-turn) - colhasmod(x,y,'|',1 - turn); // don't include their walls
snprintf(temp, 1024, "other player has %d cells in col (empty=%d, we have %d caps + %d walls == %d multiplier)", n, c, a, b, multi);
if (multi > 0) {
modaivalue(x,y, n * multi, temp);
}
modaidef(x,y, n * 1);
}
// reduce defence required for each or our caps in this row/col
a = colhasmod(x,y,'^',turn);
b = rowhasmod(x,y,'^',turn);
modaidef(x,y, (a+b) * -1);
a = colhasmod(x,y,'|',turn);
b = rowhasmod(x,y,'|',turn);
modaidef(x,y, (a+b) * -1);
}
char *genaicmd(char *cmd, int showdb, int useworst) {
int x,y,best;
int ncandidates;
int candidate[MAXW*MAXH];
@ -284,28 +500,29 @@ char *genaicmd(char *cmd, int showdb) {
for (y=0; y < h; y++) {
for (x=0; x < w; x++) {
aivalue[y*w+x] = 500;
aidef[y*w+x] = 0;
strcpy(aireason[y*w+x], "");
}
}
// 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);
}
aiupdatetile(x,y);
}
}
// determine the best priority
best = -1;
if (useworst) best=99999;
else 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 (aivalue[y*w+x] != BLOCKED) {
if (useworst) {
if (aivalue[y*w+x] < best) best = aivalue[y*w+x];
} else {
if (aivalue[y*w+x] > best) best = aivalue[y*w+x];
}
}
}
}
@ -315,7 +532,7 @@ char *genaicmd(char *cmd, int showdb) {
showaivalues(best);
}
printf("*** best value is = %d\n", best);
//printf("*** best value is = %d\n", best);
// pick randomly from the best priority
ncandidates = 0;
for (y=0; y < h; y++) {
@ -326,8 +543,7 @@ printf("*** best value is = %d\n", best);
}
}
printf("*** ncandidates = %d\n", ncandidates);
//printf("*** ncandidates = %d\n", ncandidates);
if (ncandidates == 0) {
sprintf(cmd, "\\r");
@ -339,17 +555,40 @@ printf("*** ncandidates = %d\n", ncandidates);
xytopos(xsel,ysel,&xpossel, &ypossel);
// we place a tile here or move here?
if (canmoveanyto(turn, x, y, str)) {
if (canplacetile(turn, xsel, ysel, ' ', NULL)) {
char mod = ' ';
int chance = aidef[ysel*w+xsel]*15;
// wall or cap?
if (pctchance(chance)) {
if ((capsleft[turn] > 0) &&
pctchance(chance) &&
canplacetile(turn, xsel, ysel, '^', NULL)) {
mod = '^';
} else if (canplacetile(turn, xsel, ysel, '|', NULL)) {
mod = '|';
}
}
// place
if (mod == ' ') {
sprintf(cmd, "%c%c", xpossel,ypossel);
} else {
sprintf(cmd, "%c%c%c", mod,xpossel,ypossel);
}
} else if (canmoveanyto(turn, xsel, ysel, str, TRUE)) {
// move
sprintf(cmd, "%s", str);
} else {
// place
sprintf(cmd, "%c%c", xpossel,ypossel);
}
}
return cmd;
}
int pctchance(int num) {
if (rand() % 100 < num) {
return TRUE;
}
return FALSE;
}
int xywouldgivewinto(int who, int tx, int ty) {
char board2[MAXW*MAXH][MAXBOARDSTRLEN];
int x,y,wouldwin = FALSE;
@ -373,12 +612,62 @@ void idxtoxy(int idx, int *x, int *y) {
if (y) *y = idx / w;
}
int modaivalue(int x,int y,int amt) {
int modaidef(int x,int y,int amt) {
int idx=y*w+x;
if (!isvalidxy(x,y)) {
return TRUE;
}
aidef[idx] += amt;
return FALSE;
}
int modaivalue(int x,int y,int amt, char *reason) {
char temp[512];
int idx=y*w+x;
if (!isvalidxy(x,y)) {
return TRUE;
}
if (aivalue[idx] == BLOCKED) {
return TRUE;
}
aivalue[idx] += amt;
snprintf(temp, 512, " [%s%-3d] %s\n", (amt > 0) ? "+" : "", amt, reason ? reason : "<unspecified>");
strcat(aireason[idx], temp);
return FALSE;
}
int modaivalue_around(int x,int y,int amt, char *reason) {
int newx,newy,d;
int xpos,ypos;
char localreason[1024];
if (!isvalidxy(x,y)) {
return TRUE;
}
xytopos(x,y,&xpos,&ypos);
snprintf(localreason, 1024, "(from adjacent tile %c%c): %s", xpos,ypos, reason);
for (d=0; d <=3; d++) {
newx = x + xmod[d];
newy = y + ymod[d];
modaivalue(newx, newy, amt, localreason);
}
return FALSE;
}
int modaidef_around(int x,int y,int amt) {
int newx,newy,d;
if (!isvalidxy(x,y)) {
return TRUE;
}
for (d=0; d <=3; d++) {
newx = x + xmod[d];
newy = y + ymod[d];
modaidef(newx, newy, amt);
}
return FALSE;
}
@ -421,9 +710,24 @@ int checkendgame(void) {
if (isboardfull()) {
return TRUE;
}
return FALSE;
}
void checkfortak(int who) {
int x,y;
// check for 'tak' condition
tak[who] = FALSE;
for (y=0; y < h; y++) {
for (x=0; x < w; x++) {
if (xywouldgivewinto(who, x, y)) {
tak[who] = TRUE;
}
}
}
}
int getstartcapstones(int sz) {
switch (sz) {
case 3:
@ -468,6 +772,8 @@ int nextturn(void) {
// reset game log variables?
topofmove = ' ';
flattened = FALSE;
tak[0] = FALSE;
tak[1] = FALSE;
return 0;
}
@ -535,7 +841,7 @@ int movetile(int count,char xch,char ych, char dir, char *dropstr) {
char dropping[MAXSTACK*2];
char *bpos,*newbpos,*p,*dp,*mp;
int pass;
int xmod,ymod;
int xmodamt,ymodamt;
int numtomove;
char err[256];
postoxy(xch,ych,&x, &y);
@ -577,7 +883,7 @@ int movetile(int count,char xch,char ych, char dir, char *dropstr) {
return TRUE;
}
dirtoxy(dir,&xmod,&ymod);
dirtoxy(dir,&xmodamt,&ymodamt);
numtomove = count;
// First pass: validate each step
@ -616,8 +922,8 @@ int movetile(int count,char xch,char ych, char dir, char *dropstr) {
//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;
x += xmodamt;
y += ymodamt;
// 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);
@ -777,7 +1083,8 @@ int canplacetile(int who, int x, int y, int mod, char *why) {
return TRUE;
}
int canmoveanyto(int who, int tx, int ty, char *why) {
int canmoveanyto(int who, int tx, int ty, char *why, int safe) {
int x,y;
if (!canmoveto(who, tx, ty, why)) return FALSE;
if (why) strcpy(why,"");
@ -793,8 +1100,16 @@ int canmoveanyto(int who, int tx, int ty, char *why) {
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;
if (ok) {
if (safe) {
if (!canmovefrom(who, x, y, why)) { // got somethong to move here
ok = FALSE;
}
} else {
if (!willmovefrom(who, x, y, why)) { // got somethong which is safe to move here
ok = FALSE;
}
}
}
count = counttiles(board[y*w+x]);
if (ok && (x == tx) && abs(tx - x) > count) { // distance ok?
@ -804,7 +1119,7 @@ int canmoveanyto(int who, int tx, int ty, char *why) {
ok = FALSE;
}
// can this stack get one of our color to there???
if (canmakedropstr(who, x,y,tx,ty,why)) {
if (ok && canmakedropstr(who, x,y,tx,ty,why)) {
return TRUE;
}
}
@ -819,8 +1134,6 @@ int canmakedropstr(int who, int sx, int sy, int dx, int dy, char *str) { // retu
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;
@ -880,12 +1193,14 @@ int canmakedropstr(int who, int sx, int sy, int dx, int dy, char *str) { // retu
strcat(localstr, temp);
if (str) strcpy(str,localstr);
return TRUE;
// TODO: go further to control mlre locations
// TODO: go further to control more locations
} else {
char *z;
// not there yet.
// must drop at least one
// TODO: figure out how many we can drop and
// still reach dst
// TODO: drop more than 1, prefer our color
//z = strchr(mp, getpchar(who));
@ -894,16 +1209,32 @@ int canmakedropstr(int who, int sx, int sy, int dx, int dy, char *str) { // retu
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);
int didsomething = TRUE;
char temp[10],owner;
// would dropping this amt let the
// other player win?
while (didsomething) {
didsomething = FALSE;
owner = *(z+numtodrop-1);
if (getpnum(owner) == 1-who) {
if (xywouldgivewinto(1-who, x, y)) {
if (++numtodrop >= counttiles(mp)) {
break;
}
didsomething = TRUE;
}
}
}
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 {
sprintf(temp, "%1d",numtodrop);
strcat(localstr, temp);
if (db) printf("db: ** numtodrop: %d. tiles in stack: %d (%s)\n", numtodrop, counttiles(mp), mp);
// remove dropped tiles from moving stack
mp += numtodrop;
if (db) printf("db: ** new tiles in stack: %d (%s)\n", counttiles(mp), mp);
@ -933,6 +1264,17 @@ char getdirchar(int dir) {
return '=';
}
int willmovefrom(int who, int x, int y, char *why) {
// would moving away from here make the other player win?
if (xywouldgivewinto(who, x, y)) {
if (why) sprintf(why, "Moving away would open up a win to other player");
return FALSE;
}
return canmovefrom(who, x, y, why);
}
int canmovefrom(int who, int x, int y, char *why) {
int mod;
int idx,xch,ych;
@ -943,14 +1285,18 @@ int canmovefrom(int who, int x, int y, char *why) {
mod = getmod(bpos);
if (why) strcpy(why,"");
if (turnnumber == 1) {
if (why) sprintf(why, "cant move on first setup turn.\n");
return FALSE;
}
// is there anything at the source location?
if (!strlen(bpos) ) {
sprintf(why, "empty source location\n");
if (why) 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");
if (why) sprintf(why, "not owner of source location\n");
return FALSE;
}
return TRUE;
@ -966,9 +1312,13 @@ int canmoveto(int who, int x, int y, char *why) {
mod = getmod(bpos);
if (why) strcpy(why,"");
if (turnnumber == 1) {
if (why) sprintf(why, "cant move on first setup turn.\n");
return FALSE;
}
if (mod == '^') {
// capstone?
sprintf(why, "%s capstone at %c%c\n",getpname(getowner(bpos)), xch,ych);
if (why) sprintf(why, "%s capstone at %c%c\n",getpname(getowner(bpos)), xch,ych);
return FALSE;
}
return TRUE;
@ -1003,7 +1353,7 @@ int parsecmd(char *cmd) {
winner = 1-turn;
logmove(turn, cmd, ' ');
return FALSE;
} else if (strstr(cmd, "\\w ")) { // check if loc would give us a win
} 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];
@ -1013,6 +1363,21 @@ int parsecmd(char *cmd) {
printf(" *** would %c%c give us a win? %s\n", xpos,ypos,
wouldwin ? "YES" : "no");
return TRUE;
} else if (!strcmp(cmd, "\\b")) {
showboard();
return TRUE;
} else if (strstr(cmd, "\\w ")) {
int xpos,ypos,x,y;
p = cmd + 3;
xpos = p[0];
ypos = p[1];
postoxy(xpos,ypos,&x,&y);
printf("%sAI thoughts for %s%c%c%s%s: [%s%d%s%s]\n",YELLOW,BOLD,xpos,ypos,reset,YELLOW, BOLD,aivalue[y*w+x],reset,YELLOW);
printf("%s%s\n",aireason[y*w+x],reset);
return TRUE;
} else if (!strcmp(cmd, "\\s")) {
showscores("Current");
return TRUE;
} else if (strstr(cmd, "\\m ")) { // check if we can move to loc
char temp[256];
int xpos,ypos,x,y;
@ -1020,16 +1385,30 @@ int parsecmd(char *cmd) {
xpos = p[0];
ypos = p[1];
postoxy(xpos,ypos,&x,&y);
if (canmoveanyto(turn, x, y, temp)) {
if (canmoveanyto(turn, x, y, temp, FALSE)) {
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 (strstr(cmd, "\\c ")) { // count adjacent tiles to loc
int xpos,ypos,x,y,num,i;
p = cmd + 3;
xpos = p[0];
ypos = p[1];
postoxy(xpos,ypos,&x,&y);
for (i = 0; i <= 1; i++) {
num = countadjacent(x,y,i);
printf("%c%c has %d adjacent %s%s%s controlled locations.\n",xpos,ypos,num,getpcol(i),getpname(i),reset);
}
return TRUE;
} else if (!strcmp(cmd, "\\a")) { // simlulate AI move for us, with debug info
char cmd[256];
genaicmd(cmd, TRUE);
genaicmd(cmd, TRUE, FALSE);
printf("%sAI suggested move for %s%s%s%s: %s%s%s%s\n", YELLOW, getpcol(turn),getpname(turn),reset,YELLOW,getpcol(turn), BOLD, cmd, reset);
return TRUE;
}
@ -1081,6 +1460,7 @@ int parsecmd(char *cmd) {
}
if (!err) {
checkfortak(turn);
logmove(turn, cmd, topofmove);
}
@ -1106,6 +1486,7 @@ void showaivalues(int best) {
int x,y;
char ch;
printf("\n");
printf(FORMAT_ROWHEAD, ' ');
ch = 'a';
for (x=0; x < w; x++) {
@ -1120,8 +1501,16 @@ void showaivalues(int best) {
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);
int def = aidef[y*w+x];
char *col;
if (val == best) {
col = GREEN;
} else if (val == BLOCKED) {
col = RED;
} else {
col = YELLOW;
}
printf(FORMAT_AIVAL, col, val, reset, def);
}
printf(FORMAT_ROWTAIL, ch);
printf("\n");
@ -1305,6 +1694,13 @@ void showboardbinary(int pnum) {
}
void roadlog(char *dname, int dir, int xch, int ych, int newx,int newy) {
int newxch,newych;
xytopos(newx, newy, &newxch, &newych);
fprintf(stderr,"** db: Checking %s (dir %d xm=%d,ym=%d) from %c%c (%c%c == %d,%d)\n", dname, dir, xmod[dir],ymod[dir],xch,ych,newxch,newych,newx,newy);
}
int xyvalidforroad(char (*b)[MAXBOARDSTRLEN], int who, int x, int y) {
char *cell;
cell = b[y*w+x];
@ -1316,8 +1712,6 @@ int xyvalidforroad(char (*b)[MAXBOARDSTRLEN], int who, int x, int y) {
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;
@ -1342,6 +1736,12 @@ int checkxyforroad(char (*b)[MAXBOARDSTRLEN], int who, int sx, int sy, int sd) {
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])));
// check initial cell
if (!xyvalidforroad(b, who,x,y)) {
if (db) fprintf(stderr,"** db: %c%c not valid for road - stopping\n", xch,ych);
return FALSE;
}
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;
@ -1356,56 +1756,59 @@ int checkxyforroad(char (*b)[MAXBOARDSTRLEN], int who, int sx, int sy, int sd) {
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);
// is there a valid cell to the left?
newx = x + xmod[leftdir];
newy = y + ymod[leftdir];
if (db) roadlog("left", leftdir, xch,ych,newx,newy);
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;
d = leftdir;
moved = TRUE;
} else { // turn left
newx = x + xmod[leftdir];
newy = y + ymod[leftdir];
}
if (!moved) { // forward?
newx = x + xmod[d];
newy = y + ymod[d];
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 (db) roadlog("forward", d, xch,ych,newx,newy);
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) { // right
newx = x + xmod[rightdir];
newy = y + ymod[rightdir];
if (db) roadlog("right", rightdir, xch,ych,newx,newy);
if (xyvalidforroad(b, who,newx,newy)) {
x = newx;
y = newy;
d = rightdir;
moved = TRUE;
}
}
if (!moved) { // reverse direction
if (--d < 0) d = 3;
if (--d < 0) d = 3;
newx = x + xmod[d];
newy = y + ymod[d];
if (db) roadlog("backward", d, xch,ych,newx,newy);
if (xyvalidforroad(b, who,newx,newy)) {
x = newx;
y = newy;
moved = TRUE;
}
}
if (!moved) {
if (db) fprintf(stderr,"** db: Couldn't turn around - no roads.\n");
}
if (moved) {
xytopos(x, y, &newxch, &newych);
if (db) fprintf(stderr,"** db: %c%c is owned by us, moving there.\n", newxch,newych);
xch = newxch;
ych = newych;
@ -1483,6 +1886,32 @@ int gotwinner(void) {
return FALSE;
}
void determinefinalwinner(void) {
if (gamepoints[0] > gamepoints[1]) {
winner = 0;
} else if (gamepoints[1] > gamepoints[0]) {
winner = 1;
} else {
winner = -1;
}
if (winner == -1) {
} else {
printf("%s** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **%s\n", getpcol(winner), reset);
printf("%s ***** %s%s%s is the victor! %s*****%s\n",
getpcol(winner), BOLD,getpname(winner), reset,
getpcol(winner), reset);
printf("%s** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **%s\n", getpcol(winner), reset);
}
// show totals
showscores("Final");
// TODO: bold this
printf("\n%s--- Press ENTER to end ---%s\n", BOLD, reset);
// wait for key
fgets(cmdbuf ,MAX_CMD_LEN, stdin);
}
void determinewinner(void) {
int x,y,i;
int flatstones[MAXPLAYERS];
@ -1539,17 +1968,17 @@ void determinewinner(void) {
}
// show totals
showscores();
showscores("Current");
// TODO: bold this
printf("\n%s--- Press ENTER for next round ---%s\n", BOLD, reset);
// wait for key
fgets(cmdbuf ,MAX_CMD_LEN, stdin);
}
void showscores(void) {
void showscores(char *str) {
int i;
char temp[64];
printf("Current scores:\n");
printf("%s scores:\n", str);
for (i=0; i<MAXPLAYERS; i++) {
sprintf(temp, "%s%12s%s",getpcol(i), getpname(i), reset);
printf(" %s: %s%d points%s\n", temp, getpcol(i),gamepoints[i], reset);
@ -1592,10 +2021,14 @@ void logmove(int who, char *txt, char append) {
if (flattened) {
strcat(temp, "*");
}
if (tak[who]) {
strcat(temp, "'");
}
// first player's turn?
if (who == firstturn) {
sprintf(movelog, "%s", temp);
printf("%s%s%d.%s%s %s ...%s\n", YELLOW, BOLD, turnnumber, reset, YELLOW, movelog,reset);
} else {
strcat(movelog, " ");
strcat(movelog, temp);
@ -1626,4 +2059,5 @@ int main(int argc, char *argv[]) {
}
nextround();
}
determinefinalwinner();
}

24
tak.h
View File

@ -35,22 +35,38 @@ void printbinaryline(char prefix, int num, int wantcr);
int playerhasroads(int pnum, char (*b)[]);
void updateroadstatus(void);
char *makecolorstr(char *orig, char *newstr);
void showscores(void);
void showscores(char *str);
int checkxyforroad(char (*b)[], int who, int sx, int sy, int sd);
void pickfirstplayer(void);
int xyvalidforroad(char (*b)[], int who, int x, int y);
void logmove(int who, char *txt, char append);
int normalise(char *a);
char *genaicmd(char *cmd, int showdb);
char *genaicmd(char *cmd, int showdb, int useworst);
int canplacetile(int who, int x, int y, int mod, char *why);
int canmoveto(int who, int x, int y, char *why);
void idxtoxy(int idx, int *x, int *y);
void xytopos(int x, int y, int *xch, int *ych);
int gotwinner(void);
int xywouldgivewinto(int who, int tx, int ty);
int modaivalue(int x,int y,int amt);
int modaivalue(int x,int y,int amt, char *reason);
int modaivalue_around(int x,int y,int amt, char *reason);
int modaidef(int x,int y,int amt);
int modaidef_around(int x,int y,int amt);
int canmovefrom(int who, int x, int y, char *why);
int canmoveanyto(int who, int x, int y, char *why);
int willmovefrom(int who, int x, int y, char *why);
int canmoveanyto(int who, int x, int y, char *why, int safe);
int canmakedropstr(int who, int sx, int sy, int dx, int dy, char *str);
char getdirchar(int dir);
void showaivalues(int best);
int countadjacent(int x, int y, int who);
int getpnum(int n);
int countownedinrow(int sx, int sy, int who);
int countownedincol(int sx, int sy, int who);
int pctchance(int num);
int colhasmod(int sx, int sy, char mod, int who);
int rowhasmod(int sx, int sy, char mod, int who);
void determinefinalwinner(void);
void roadlog(char *dname, int dir, int xch, int ych, int newx, int newy);
char getownerxy(int x, int y);
int getownernumxy(int x, int y);
void checkfortak(int who);