#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;
	}

};
//amove emptymove={0,0,0,0};

static inline scoretype valueOf(const char c, unsigned x=0, unsigned y=0, bool black=false) {
	switch (BLEACH(c)) {		// instead of bleach and swich, lookuptable? or both cases and no bleach?
	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;
//    return ((y-1.0)*4/3+1.0);
	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;
// run this with ./chess7 4 <> /dev/tcp/freechess.org/23 >&0
//or with timeseal
//   mknod fifo p
//./chess7 4 > >(./openseal freechess.org > fifo ) < fifo
// it used to support console, sort ofstill might, but that seems broken since i added freechess support

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 () {					// setup my board (each player has their own board.. perfectly normal..why i have no idea
		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;
		//  fprintf(stderr,"corrent pos %d and %d\n",position[0],position[1]);
		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]));
		//  fprintf(stderr,"correct pos %d and %d\n",position[0],position[1]);
	}

	void show() const {
//      fprintf(stderr,"\033[1;H");
		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;K");
			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,"\033[1;K");
		fprintf(stderr, " a b c d e f g h\n");
//      fprintf(stderr,"\033[1;K");
		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);	//fprintf(stderr,"\033[1;K");

//fprintf(stderr,"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
	}

//#define MAKEMOVE(x,y,X,Y) (((((((x)<<8)|(y))<<8)|(X))<<8)|(Y))
	void apply(const amove & m) {
		lastmove = m;			// not needed in inner loop? maybe have a imagine that is only the point part of apply but not this or the castle or the en passant since i wouldnt imagine that move anyway
		if (!m)
			return;				// pointless? never used.. yetit faster with it, weird
		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) {	// en passant
			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)
			/* if((*dst|32)=='z')
			   position[(*dst>>5)&1]-=1+2*((*dst&32)?(m&255)>3?(m&255)-3:0:(m&255)<4?4-(m&255):0);
			   else */
			position[ISBLACK(*dst)] -= valueOf(*dst, X, Y, ISBLACK(*dst));
		if (bleached == 'P' && (Y == 7 || !Y)) {	// promote pawn
			//position[(*src>>5)&1]+=((*src&32)?(m&255)>3?2:0:(m&255)<4?2:0);
			*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])		// slow
#define MINE (ISBLACK(board[X][Y])==black)
//#define MOVE (*(moves++)=((((((x<<8)+y)<<8)+X)<<8)+Y)) // slow
//#define MOVE (*(moves++)=amove(x,y,X,Y))
#define MOVE {(moves->x=x),(moves->y=y),(moves->X=X),(moves->Y=Y);moves++;}
//#define MOVE {char *c=(char*)(moves++);*(c++)=Y;*(c++)=X;*(c++)=y;*c=x; } // slow
//#define MOVE move_(moves,x,y,X,Y)
//void move_(unsigned * &moves,char x,char y,char X,char Y) {char *c=(char*)(moves++);*(c++)=Y;*(c++)=X;*(c++)=y;*c=x; } // slow

	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) {
		//for(unsigned y=0;y<4;y++)  for(unsigned z=0;z++<2;y=7-y) for(unsigned x=black*8;black?x--:x<8;black||x++) 
		if (position[black] < valueOf('k', 0, 0, 0))
			return end;			//im dead, i cant move
		for (unsigned y = black ? 0 : 8; black ? (y < 8) : (y-- > 0); y += black)
//		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 en passant and castle..note that i broke lastmove since i started reading in the whole board after not wanting to parse o-o-o, so this will be tricky to do now, even though FICS tells me, its hard to know at depth.. en passant not so much, as i could get lastmove info easily out of FICS for that..castle, hard
					case 'P': end = getMovesP(x, y, end, black); continue;
					case 'N': end = getMovesN(x, y, end, black); continue;
					case 'Q':	// add bishop plus rook
					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;
	};

// it seems i invented negamax on my own -- https://en.wikipedia.org/wiki/Negamax
	scoretype move(bool black, unsigned minrecursionsleft, int maxrecursionsleft,int theirbestmovescore=-9999){
		static int howdeepami, howdeepcount[20];
		howdeepcount[howdeepami++]++;
		//  if(depth>19){fprintf(stderr,"too deep\n");exit(-1);} // wth this line makes it 10% slower
//                  {fprintf(stderr,"depth %d %s\r",depth,move_to_string(lastmove));}
//char spaces[]="                                                   ",o[400];
		amove	myMove = { 0, 0, 0, 0 },
			moves[512],
			*end = getMoves(moves, black);
		scoretype max = -9999;		// if i make this -150, i never express to the other side tha ive lost, so it cant see the end of the game
//      fprintf(stderr,"\033[1;%sm%d reacting to to %s\033[1;m\n",black?"31":"32",depth, move_to_string(lastmove));  //fprintf(stderr,"\033[1;K");
		//for(amove *u=!black?moves[depth]:end;!black?(u<end):(u-- > moves[depth]);!black?u++:u) { 
//      strncpy(o,spaces,recursions);
//      fprintf(stderr,"%2d %s.                               \n",recursions,o);

		scoretype startpos = position[black] - position[!black];
		for (int pass=0;pass<2;pass++) // be hostile first, for move ordering
		{
			for (amove * u = moves; u < end; u++) {
				scoretype newpos;
				char C=board[u->X][u->Y];

				//if(wentdeeper<2&&!recursionsleft&&board[u->X][u->Y]&&BLEACH(board[u->X][u->Y])!='P'){//valueOf(board[u->X][u->Y],u->X,u->Y,ISBLACK(board[u->X][u->Y]))>1){
	/*			if(!minrecursionsleft&&maxrecursionsleft&&valueOf(board[u->X][u->Y],u->X,u->Y,ISBLACK(board[u->X][u->Y]))>1){
				//if(!minrecursionsleft&&maxrecursionsleft&&board[u->X][u->Y]){//valueOf(board[u->X][u->Y],u->X,u->Y,ISBLACK(board[u->X][u->Y]))>1){
	//wentdeeper=recursions;
	//      fprintf(stderr,"\033[1;%smgoing %2d deep at %2d for %c%s taking %c\033[1;m\r",black?"31":"32", recursions+recursionsleft,howdeepami,board[u->x][u->y], move_to_string(*u)+1,board[u->X][u->Y]);  //fprintf(stderr,"\033[1;K"); // this status output is very slow
					minrecursionsleft++;			// if my first move is going to take a piece, look a bit farther ahead
				}
	*/			//make apply just have what i need for this part so i can write different scoring logic in only the 1 place
	//			fprintf(stderr,"trying \033[%sm%s at depth %d\033[m\n", black ? "31" : "32"	, (const char*)(*u),howdeepami); 
				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 {


					// finish all slaughtering
				/*	if(maxrecursionsleft&&board[u->X][u->Y]) {
						Board p(*this);
						p.apply(*u);
	//      fprintf(stderr,"\033[1;%sm plainng through at %2d for %c%s taking %c\033[1;m\n",black?"31":"32", howdeepami,board[u->x][u->y], move_to_string(*u)+1,board[u->X][u->Y]);  //fprintf(stderr,"\033[1;K"); // this status output is very slow
						newpos = -p.move(!black, 0,maxrecursionsleft-1);
					} else 
				*/
				// bug, enpassant not recognized 
					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++;
				}
	//			fprintf(stderr,"tried \033[%sm%s for %d\033[m\n", black ? "31" : "32"	, (const char*)(*u),newpos);


				if (newpos > max) {
					max = newpos;
					myMove = *u;
	//				fprintf(stderr,"new best move \033[%sm%s for %d\033[m\n", black ? "31" : "32"	, (const char*)myMove,max);
				}
				// if this move is worse for the opponent (best for me) than something the opponent already tried, its not going to try the move that leads here, so stop trying others (this is called alpha beta pruning, which i did not come up with on my own)
	//			fprintf(stderr,"at depth %d of %d\n",howdeepami,minrecursionsleft+howdeepami);
				if(newpos>=-theirbestmovescore) {
				//	fprintf(stderr,"pruning tree with %d move against %d (%s) move at depth %d of %d\n",newpos,theirbestmovescore,move_to_string(theirbestmove)+1,howdeepami,minrecursionsleft+howdeepami);
					goto shortcut;
					}
			}
		}
		shortcut:
		if (myMove) {
			apply(myMove);
//          show();
//      fprintf(stderr,"\033[1;%sm%d i would move %s to be %d relative position\033[1;m\n",black?"31":"32" ,depth, move_to_string(lastmove), max);  //fprintf(stderr,"\033[1;K");
		}
//if(wentdeeper==recursions)wentdeeper=0;
		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) {
// getopt
	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; // dont exit at end of game
		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;
			//for(;max<-150&&d>0;d--) { // we really cant do depth zero or it'll try to move into check which is illegal, but we have to in move() to value the end of the game
			fprintf(stderr, "2nd player depth %d\n", playselfdepth);
			max = board.move(!black, playselfdepth, playselfdepth);
			//}
			if (max > -150) {
//          fprintf(stderr,"%s %d/%d now to max diff %d\n", board.move_to_string(board.lastmove)+1,board.position[0],board.position[1],max);  //fprintf(stderr,"\033[1;K");
			} 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];
//                  "fjjvh"//  700, beaten at 1 6 (d=4) 
				if (icsopponent) {
// must be registered: callipygian mscp speckengine sidonia 
					if (!strcmp(icsopponent, "kurushi"));// { icsboard = "wild 2"; }			// 1671 only plays wild, i always win
					if (!strcmp(icsopponent, "inemuri"));// { icstime = 9; icsinc = 0; }			//"inemuri" // 0/[1-6] i win as white, lose as black, he must have a big book,  .. oh its the same game when im wwhite regardless of time setting?^Z/its
				}
//          "marquisce" // 1750 always beats me
				//"griffyjr"  // 1870 i lost at 1 6 (d=4) 
//              "IFDThor" // 1877 beat me 1/6/d=log(mostly 4, some 5)
//"kitteneitor" // 1847
//              "griffyjr"  // 2070 i lost at 1 2 d3.. slaughters me
				//"DBPPuppetMaster"  // 2200, not beaten
//          "Giuchess" //   checkmatted him 1600 3 0 ( he doesnt do inc, and start must be 3 or less)  at d=4  to log(6m)
//          "Giuchess" //   2000 lightning rating 2 0  he beat, with the same settings as i beat him with more time...odd

				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};	// bug, cant see castling, but only used for display anyway
					}
					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)	// its my turn
						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);
//      for(;max<-150&&d>0;d--) { // we really cant do depth zero or it'll try to move into check which is illegal
		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;

//if(mindepth<4)mindepth=4;
		int maxdepth=mindepth;//log(timeleft[black]*400000) / log(sqrt((board.getMoves(moves, black) - moves) * (board.getMoves(moves, !black) - moves)));	// this should take into account how many pieces are ready to kill, but that isnt known until after the fact
		//replace this with logic that just collapses all takeable moves, rather than the full set of possibilities
		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));

//		if(maxdepth<=mindepth)maxdepth=mindepth+1;
		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);
		//+(3-((board.position[black]-valueOf('k'))/10)));// }
		if (max > -150) { // bug, what if the board has lots of queens.. i should compute king differently, like what if im using relative strength (ratio) instead of difference
//          fprintf(stderr,"%s %d/%d now to max diff %d\n", board.move_to_string(board.lastmove)+1,board.position[0],board.position[1],max);  //fprintf(stderr,"\033[1;K");
			fprintf(stdout, "%s\n", board.move_to_string(board.lastmove) + 1);	//fprintf(stderr,"\033[1;K");
		} 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;
};