#include <unistd.h>
#include <getopt.h>
#include <sys/time.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#define BLACK (0x20)
#define BLEACH(a) (a&~BLACK)
#define ISBLACK(p) (!!(p&BLACK))
#define YOF(m) (m&7)
#define XOF(m) ((m>>8)&7)
#define yOF(m) ((m>>16)&7)
#define xOF(m) ((m>>24)&7)
#define MYNAME "kermsbot"
typedef int scoretype;
class amove {
public:
unsigned x, y, X, Y;
amove() { };
inline amove(unsigned x, unsigned y, unsigned X, unsigned Y):x(x), y(y), X(X), Y(Y) { }
operator const char *() const {
static char r[5] = "xxxx";
if (!this)
return "";
r[0] = x + 'a';
r[1] = y + '1';
r[2] = X + 'a';
r[3] = Y + '1';
return r;
}
operator bool() const {
if (x) return true;
if (X) return true;
if (y) return true;
if (Y) return true;
return false;
}
};
static inline scoretype valueOf(const char c, unsigned x=0, unsigned y=0, bool black=false) {
switch (BLEACH(c)) {
case 0:
return 0;
case 'P':
switch(black) {
switch (y) { case 1: return 5; case 0: return 9; }
switch (y) { case 6: return 5; case 7: return 9; }
}
return 1;
case 'K': return 200;
case 'Q': return 9;
case 'B': return 3;
case 'R': return 5;
case 'N': return 3;
}
return 0;
}
static long long unsigned Mcount;
class Board {
public:
char board[8][8];
scoretype position[2];
amove lastmove;
const char *move_to_string(amove m) const {
static char r[50] = "";
if (!this)
return "";
r[0] = board[m.X][m.Y];
r[1] = m.x + 'a';
r[2] = m.y + '1';
r[3] = m.X + 'a';
r[4] = m.Y + '1';
r[5] = 0;
return r;
}
Board () {
int x, y, n, c;
position[0] = position[1] = 0;
for (x = 0; x < 8; x++)
for (y = 0; y < 8; y++)
board[x][y] = 0;
for (c = 2; c--;) {
for (n = 0; n < 8; n++)
board[n][c ? 6 : 1] = 'P' | (c * BLACK);
y = c ? 7 : 0;
board[0][y] = board[7][y] = 'R' | (c * BLACK);
board[1][y] = board[6][y] = 'N' | (c * BLACK);
board[2][y] = board[5][y] = 'B' | (c * BLACK);
board[3][y] = 'Q' | (c * BLACK);
board[4][y] = 'K' | (c * BLACK);
}
lastmove = { 0, 0, 0, 0};
initpos();
}
void initpos() {
int x, y;
position[0] = position[1] = 0;
for (x = 8; x--;)
for (y = 8; y--;)
position[ISBLACK(board[x][y])] +=
valueOf(board[x][y], x, y, ISBLACK(board[x][y]));
}
void show() const {
fprintf(stderr, " a b c d e f g h\n");
unsigned X = lastmove.X, Y = lastmove.Y;
for (unsigned y = 8; y-- > 0;) {
fprintf(stderr, "\033[1;m%d", y + 1);
for (unsigned x = 0; x < 8; x++)
fprintf(stderr, "\033[1;%s;%s;%sm%c ",
((X == x) && (Y == y)
&& (lastmove)) ? "7" : "27",
(((x + y) % 2) ? "40" : "47"),
board[x][y] ? (ISBLACK(board[x][y]) ? "31" : "32") :
"30", board[x][y] ? board[x][y] : ' ');
fprintf(stderr, "\033[1;m%d\n", y + 1);
}
fprintf(stderr, " a b c d e f g h\n");
fprintf(stderr, "\033[1;%sm%s \033[32m%3d:\033[31m%3d\n", ISBLACK(board[X][Y]) ? "31" : "32", move_to_string(lastmove), position[0] - 200, position[1] - 200);
}
void apply(const amove & m) {
lastmove = m;
if (!m)
return;
unsigned x = m.x, y = m.y, X = m.X, Y = m.Y;
char *src = &board[x][y], *dst = &board[X][Y];
char bleached = BLEACH(*src);
if (bleached == 'P' && x != X && !*dst) {
position[ISBLACK(board[X][y])] -=
valueOf('P', X, y, ISBLACK(board[X][y]));
board[X][y] = 0;
}
if (bleached == 'K' && x == 4)
switch (X) {
case 2: apply(amove(0, y, 3, y)); break;
case 6: apply(amove(7, y, 5, y)); break;
}
if (*dst)
position[ISBLACK(*dst)] -= valueOf(*dst, X, Y, ISBLACK(*dst));
if (bleached == 'P' && (Y == 7 || !Y)) {
*src &= BLACK;
*src |= 'Q';
position[ISBLACK(*src)] -= valueOf('P', x, y, ISBLACK(*src));
position[ISBLACK(*src)] += valueOf('Q', X, Y, ISBLACK(*src));
}
*dst = *src;
*src = 0;
}
#define OK (!((Y|X)&~7))
#define AT (board[X][Y])
#define MINE (ISBLACK(board[X][Y])==black)
#define MOVE {(moves->x=x),(moves->y=y),(moves->X=X),(moves->Y=Y);moves++;}
amove *getMovesP(unsigned x, unsigned y, amove * moves, bool black) {
const unsigned dir = black ? -1 : 1;
unsigned X = x, Y = y;
Y = y + dir; if (OK && !AT) { MOVE;
Y += dir; if (((14U + dir) % 7U) == y && OK && !AT) MOVE; }
Y = y + dir; X = x + 1; if (OK && AT && !MINE) MOVE;
X = x - 1; if (OK && AT && !MINE) MOVE;
return moves;
}
amove *getMovesN(unsigned x, unsigned y, amove * moves, bool black) {
unsigned X = x, Y = y;
X += 2; Y--; if (OK && (!AT || !MINE)) MOVE;
Y += 2; if (OK && (!AT || !MINE)) MOVE; X--; Y++;
if (OK && (!AT || !MINE)) MOVE; X -= 2;
if (OK && (!AT || !MINE)) MOVE; X--; Y--;
if (OK && (!AT || !MINE)) MOVE; Y -= 2;
if (OK && (!AT || !MINE)) MOVE; X++; Y--;
if (OK && (!AT || !MINE)) MOVE; X += 2;
if (OK && (!AT || !MINE)) MOVE;
return moves;
}
amove *getMovesB(unsigned x, unsigned y, amove * moves, bool black) {
int X, Y;
X = x - 1; Y = y - 1; while (OK) { if (AT) { if (!MINE) MOVE; break; } MOVE; --X; --Y; }
X = x + 1; Y = y - 1; while (OK) { if (AT) { if (!MINE) MOVE; break; } MOVE; ++X; --Y; }
X = x - 1; Y = y + 1; while (OK) { if (AT) { if (!MINE) MOVE; break; } MOVE; --X; ++Y; }
X = x + 1; Y = y + 1; while (OK) { if (AT) { if (!MINE) MOVE; break; } MOVE; ++X; ++Y; }
return moves;
}
amove *getMovesK(unsigned x, unsigned y, amove * moves, bool black) {
unsigned X = x, Y = y;
X++; if (OK && (!AT || !MINE)) MOVE;
Y++; if (OK && (!AT || !MINE)) MOVE;
X--; if (OK && (!AT || !MINE)) MOVE;
X--; if (OK && (!AT || !MINE)) MOVE;
Y--; if (OK && (!AT || !MINE)) MOVE;
Y--; if (OK && (!AT || !MINE)) MOVE;
X++; if (OK && (!AT || !MINE)) MOVE;
X++; if (OK && (!AT || !MINE)) MOVE;
return moves;
}
amove *getMovesR(unsigned x, unsigned y, amove * moves, bool black) {
int X, Y;
X = x - 1; Y = y; while (OK) { if (AT) { if (!MINE) MOVE; break; } MOVE; --X; }
X = x + 1; Y = y; while (OK) { if (AT) { if (!MINE) MOVE; break; } MOVE; ++X; }
X = x; Y = y - 1; while (OK) { if (AT) { if (!MINE) MOVE; break; } MOVE; --Y; }
X = x; Y = y + 1; while (OK) { if (AT) { if (!MINE) MOVE; break; } MOVE; ++Y; }
return moves;
}
amove *getMoves(amove * end, bool black) {
if (position[black] < valueOf('k', 0, 0, 0))
return end;
for (unsigned y = black ? 0 : 8; black ? (y < 8) : (y-- > 0); y += black)
for (unsigned x = 0; x < 8; x++)
if (board[x][y] && (ISBLACK(board[x][y]) == black))
switch (BLEACH(board[x][y])) { TODO
case 'P': end = getMovesP(x, y, end, black); continue;
case 'N': end = getMovesN(x, y, end, black); continue;
case 'Q':
case 'B': end = getMovesB(x, y, end, black);
if (BLEACH(board[x][y]) == 'B') continue;
case 'R': end = getMovesR(x, y, end, black); continue;
case 'K': end = getMovesK(x, y, end, black); continue;
}
return end;
};
scoretype move(bool black, unsigned minrecursionsleft, int maxrecursionsleft,int theirbestmovescore=-9999){
static int howdeepami, howdeepcount[20];
howdeepcount[howdeepami++]++;
amove myMove = { 0, 0, 0, 0 },
moves[512],
*end = getMoves(moves, black);
scoretype max = -9999;
scoretype startpos = position[black] - position[!black];
for (int pass=0;pass<2;pass++)
{
for (amove * u = moves; u < end; u++) {
scoretype newpos;
char C=board[u->X][u->Y];
if(pass==0&&C==0)continue;
if(pass==1&&C>0)continue;
if (minrecursionsleft) {
Board p(*this);
p.apply(*u);
newpos = -p.move(!black, minrecursionsleft - 1, maxrecursionsleft -1,max);
} else {
newpos = startpos + valueOf(board[u->X][u->Y], u->X, u->Y,
ISBLACK(board[u->X][u->Y]));
char c=board[u->x][u->y];
newpos += valueOf(c, u->X, u->Y, ISBLACK(c)) - valueOf(c, u->x, u->y, ISBLACK(c));
Mcount++;
}
if (newpos > max) {
max = newpos;
myMove = *u;
}
if(newpos>=-theirbestmovescore) {
goto shortcut;
}
}
}
shortcut:
if (myMove) {
apply(myMove);
}
howdeepami--;
if(!howdeepami)for (int i=0;i<9;i++) {
fprintf(stderr,"%d %d\n",i,howdeepcount[i]);
howdeepcount[i]=0;
}
return max;
}
};
int main(int argc, char **argv) {
int opt;
const char *icsopponent = NULL, *icsboard = "";
bool server=false;
int nummoves = 200, playselfdepth = -1;
int icstime = 0, icsinc = 3;
fprintf(stderr, "green is white, red is black\n");
while ((opt = getopt(argc, argv, "D:n:I:B:T:t:S")) != -1)
switch (opt) {
case 'B':
icsboard = strdup(optarg);
break;
case 'I':
icsopponent = strdup(optarg);
break;
case 'S': server = true;
case 'T': icstime = atoi(optarg); break;
case 't': icsinc = atoi(optarg); break;
case 'D': playselfdepth = atoi(optarg); break;
case 'n':
nummoves = atoi(optarg);
break;
default:
fprintf(stderr, "Usage: ./chess7 > >(./openseal freechess.org > fifo ) < fifo -I inemuri \n");
exit(EXIT_FAILURE);
}
Board & board = *new Board();
char nl;
bool black = false, ics = false;
setlinebuf(stdin);
setlinebuf(stdout);
setlinebuf(stderr);
board.show();
int msecs[2] = { 0, 0 };
int timeleft[2]={10,10};
while (1) {
struct timeval tv, tv2;
gettimeofday(&tv, NULL);
if (playselfdepth >= 0) {
scoretype max = -9999;
fprintf(stderr, "2nd player depth %d\n", playselfdepth);
max = board.move(!black, playselfdepth, playselfdepth);
if (max > -150) {
} else {
fprintf(stderr, "game over\a\n");
if (!ics)
exit(0);
}
board.show();
} else {
char x, y, X, Y, s[4000];
while (1) {
char whosturn, move[300], whiteplayer[999], blackplayer[999];
if (icsopponent) {
if (!strcmp(icsopponent, "kurushi"));
if (!strcmp(icsopponent, "inemuri"));
}
if (fgets(s, sizeof(s), stdin) == NULL)
exit(0);
fprintf(stderr, "%s", s);
if (strstr(s, "is playing a game")) {
fprintf(stdout, "obs %s\n", icsopponent);
}
if (strstr(s, "Server location: freechess.org")) {
ics = true;
fprintf(stdout,
"%s\n\nstyle 12\nset chanoff 1\nset bell 0\nset seek 0\n",MYNAME);
}
if (icsopponent
&& (strstr(s, "from observation list")
|| strstr(s, "Server location: freechess.org"))) {
fprintf(stdout, "unobs %s\nmatch %s %d %d %s\n",
icsopponent, icsopponent, icstime, icsinc,
icsboard);
msecs[0]=msecs[1]=0; }
if (strstr(s, "{Game")){
if(strstr(s,"Creat")){
msecs[0]=msecs[1]=0;
}
else if(strstr(s,MYNAME)) {
fprintf(stdout, "hist\n");
fprintf(stdout, "hist %s\n",icsopponent);
fprintf(stderr, "\a\n");
if(!server)exit(-1);
}
}
if (strstr(s, "Challenge: ")) {
fprintf(stdout, "acc\n");
board = *new Board();
msecs[0]=msecs[1]=0; }
if (sscanf
(s,
" <12> %*s %*s %*s %*s %*s %*s %*s %*s %c %*s %*s %*s %*s %*s %*s %*s %s %s %*s %*s %*s %*s %*s %d %d %*s %s %*s %*s %*s %*s",
&whosturn, whiteplayer, blackplayer, &timeleft[0],&timeleft[1],move) == 6) {
if (sscanf(move, "%*c/%c%c-%c%c", &x, &y, &X, &Y) == 4)
board.lastmove =
amove(x - 'a', y - '1', X - 'a', Y - '1');
else {
fprintf(stderr, "cant see %s\n", move);
board.lastmove = {
0, 0, 0, 0};
}
for (int x = 0; x < 8; x++)
for (int y = 0; y < 8; y++) {
char p = s[5 + y * 9 + x + (*s == '\r')];
board.board[x][7 - y] = (p == '-') ? 0 : p;
}
board.initpos();
board.show();
black = ! !strcmp(whiteplayer, MYNAME);
if (strstr(s, MYNAME) && ((whosturn == 'W') ? 0 : 1) == black)
break;
}
if (!ics && sscanf(s, "%c%c%c%c%c", &x, &y, &X, &Y, &nl) == 5
&& nl == '\n') {
x -= 'a';
X -= 'a';
y -= '1';
Y -= '1';
black = 1;
board.apply(amove(x, y, X, Y));
board.show();
break;
}
}
}
gettimeofday(&tv2, NULL);
msecs[!black] +=
((tv2.tv_sec - tv.tv_sec) * 1000 +
(tv2.tv_usec - tv.tv_usec) / 1000);
fprintf(stderr, "\033[1;32m%4ds \033[1;31m%4ds\n", msecs[0] / 1000,
msecs[1] / 1000);
gettimeofday(&tv, NULL);
amove moves[512];
#define POWFACT 1.75
int mindepth = POWFACT*log(timeleft[black]*150000) / log(sqrt((board.getMoves(moves, black) - moves) * (board.getMoves(moves, !black) - moves)))-1;
int maxdepth=mindepth;
fprintf(stderr,"estimating %lf Mmoves\n",pow(sqrt((board.getMoves(moves, black) - moves) * (board.getMoves(moves, !black) - moves)),(1.0+mindepth)/POWFACT)/1000000);
long long possiblemoves= pow(sqrt((board.getMoves(moves, black) - moves) * (board.getMoves(moves, !black) - moves)) ,(1+mindepth));
fprintf(stderr, "depth %d-%d for %d moves\n", mindepth,maxdepth,
board.getMoves(moves, black) - moves);
long long int Mcount_=Mcount;
scoretype max = board.move(black, mindepth,maxdepth);
if (max > -150) {
fprintf(stdout, "%s\n", board.move_to_string(board.lastmove) + 1);
} else {
fprintf(stdout, "resign\n");
fprintf(stderr, "game over\a\n");
if (!ics)
exit(0);
}
if (!ics)
board.show();
if (!nummoves--)
exit(0);
gettimeofday(&tv2, NULL);
msecs[black] +=
((tv2.tv_sec - tv.tv_sec) * 1000 +
(tv2.tv_usec - tv.tv_usec) / 1000);
fprintf(stderr, "\033[1;32m%4ds \033[1;31m%4ds\033[m %lldMm/s considered %5lld Mmoves of %5lld possible depth %d-%d\n",
msecs[0] / 1000, msecs[1] / 1000,
Mcount / (msecs[black] +1+
(playselfdepth >= 0 ? msecs[!black] : 0)) / 1000,( Mcount-Mcount_)/1000000, possiblemoves/1000000
,mindepth,maxdepth);
}
return 0;
};