bool FInitHashe(PCON pcon)
{
    if( hashBuffer ) {
        free( hashBuffer );
        hashBuffer = 0;
    }
    s_chashdMac = 15;
    int cbMaxHash = uciHash.get_spin();

    if( cbMaxHash <= 0 || cbMaxHash > 1024 )
        cbMaxHash = 32;
    cbMaxHash *= 1024*1024;
    chashdMax = 1;
    for (;;) {
        if (chashdMax * 2 * (int)sizeof(HASHD) > cbMaxHash)
            break;
        chashdMax *= 2;
    }
    VPrSendComment("%d Kbytes main hash memory (%d entries)", chashdMax * sizeof(HASHD) / 1024, chashdMax);
    Assert( sizeof(HASHD) == 16 );
    hashBuffer = (RGHASHD) malloc( 64 + chashdMax * sizeof(HASHD));
    if ( hashBuffer == NULL) {
        VPrSendComment("Can't allocate hash memory: %d bytes",
                       chashdMax * sizeof(HASHD));
        return false;
    }
    s_rghashd = (RGHASHD) ((U64(hashBuffer)+63) & (~63));
    s_chashdMac = ((chashdMax / BUCKET_SIZE) - 1) * BUCKET_SIZE;
    stats.Hsize = chashdMax;
    VClearHashe();
    return true;
}
Exemple #2
0
void VPrRating(void * pv, int eloUs, int eloThem)
{
	PCON pcon = pv;

	VPrSendComment("My rating is %ld; opponent's rating is %ld.",
		eloUs, eloThem);
}
Exemple #3
0
void VPrBanner(void)
{
	int	i;

	for (i = 0; c_argszHelp[i] != NULL; i++)
		VPrSendComment(c_argszHelp[i]);
}
void VAssertFailed(const char * szMod, int iLine)
{
	VPrSendComment("Assert Failed: %s+%d\n", szMod, iLine);
#ifdef _MSC_VER
	_asm	{
		int 3
	}
#else
    asm ("int $3\n\t");

#endif
//	exit(1);
    int x = 0;
}
EvalCache::EvalCache(int _numEntries) {
    VPrSendComment("%d Kbytes eval cache memory (%d entries)", _numEntries * sizeof(EvalCacheEntry) / 1024, _numEntries);
    numEntries = _numEntries;
    // TODO : alignment, sizeof(EvalCacheEntry)
    cache = new EvalCacheEntry[ numEntries ];
}
Exemple #6
0
BOOL FGenBook(PCON pcon, char * szFile, int cbMaxBook, int bdm)
{
	FILE * pfI;
	int	cLine;
	BOOL	f;
	CM	argcmPrev[256];
	BOOL argfAvoid[256];
	int	cplyPrev;
	BOOL	fResult;
	int	cbn = 0;

	//	The book stuff is not high performance, so I'm going to use all the
	//	book memory specified by the user, rather than trying to break it
	//	down to the next lower power of two.  I'll use at least one node.
	//
	s_cbnMax = cbMaxBook / sizeof(BN);
	if (s_cbnMax < 1)
		s_cbnMax = 1;
	//
	//	Allocate the memory and open the file.  This is not cleaned up if I
	//	leave this routine early, because it's assumed that the program is
	//	immediately ending.
	//
	if ((s_rgbn = malloc(s_cbnMax * sizeof(BN))) == NULL) {
		VPrSendComment("Can't allocate book memory: %d bytes",
			s_cbnMax * sizeof(BN));
		return fFALSE;
	}
	memset(s_rgbn, 0, s_cbnMax * sizeof(BN));
	if ((pfI = fopen(szFile, "r")) == NULL) {
		VPrSendComment("Can't open book: \"%s\"", szFile);
		return fFALSE;
	}
	//	Eat the file.  This loop is kind of complicated.
	//
	cplyPrev = 0;
	fResult = fTRUE;
	for (cLine = 0;;) {
		char	aszBuf[512];
		char	aszOut[512];
		char *	szOut = aszOut;
		char *	argsz[256];
		int	csz;
		PSTE	pste = pcon->argste;
		int	isz;
		int	i;
		BOOL	fFollowing;
		int	cply;

		//	Get a line from the file.
		//
		if (fgets(aszBuf, sizeof(aszBuf), pfI) != aszBuf)	// Opening name.
			break;
		cLine++;
		VStrip(aszBuf);
		if ((aszBuf[0] == '/') ||		// Ignore some probable comment lines.
			(aszBuf[0] == '#') ||
			(aszBuf[0] == '*') ||
			(aszBuf[0] == ';') ||				
			(aszBuf[0] == '\0')) {
			if (bdm != bdmNONE)
				printf("%s\n", aszBuf);
			continue;
		}
		//	Set up the board.
		//
		f = FInitCon(pcon, s_aszFenDefault);
		Assert(f);
		//
		//	Break the line up.
		//
		csz = CszVectorizeBookLine(aszBuf, argsz);
		isz = cply = 0;
		//
		//	Look at the first string and see if it's a move number.  If it's
		//	a move number other than one, it's assumed that the moves between
		//	one and there are taken from the previous line.  "cply" is set to
		//	the proper ply value based upon the move number (0 is white's
		//	first move, 1 is black's first, 2 is white's second, etc.).
		//
		//	If the move number is "1.", it's assumed to be a white move.  If
		//	there are extra dots appended (as in "1.." or "1..."), it's
		//	assumed that black is on the move.
		//
		if ((isz < csz) && (isdigit(argsz[isz][0]))) {
			int	cmov;

			cmov = 0;
			for (i = 0; argsz[isz][i]; i++)
				if (isdigit(argsz[isz][i]))
					cmov = cmov * 10 + argsz[isz][i] - '0';
				else
					break;
			cply = (cmov - 1) * 2;
			if ((argsz[isz][i++] == '.') && (argsz[isz][i] == '.'))
				cply++;
			isz++;
		} else
			cply = 0;
		//
		//	If white is to move, check the next string for "...", which
		//	indicates that it's black's move.
		//
		//	The deal here is that I'm trapping the case "1. ..." and marking
		//	it as black to move.
		//
		if ((isz < csz) && (!(cply & 1)))
			if (!strcmp(argsz[isz], "...")) {
				cply++;
				isz++;
			}
		//
		//	If I set this up to start other than on move 1 for white, I have
		//	to have enough previous context lying around from the previous
		//	line.  I gap is not allowed.
		//
		if (cplyPrev < cply) {
			VBookError(szFile, cLine, "Discontiguous opening line");
			fResult = fFALSE;
			goto lblDone;
		}
		//	Skip over any previous context.  If I'm outputting in "full" mode,
		//	write this stuff to stdout.  If I'm outputting in "compact" mode,
		//	I'm going to emit a couple of spaces per ply, so it indents in an
		//	attractive way.
		//
		for (i = 0; i < cply; i++) {
			char	aszMov[32];
			BOOL	f;

			if (bdm == bdmFULL) {
				char	aszSan[32];
				SAN	san;

				VGenLegalMoves(pcon, pste);
				VCmToSan(pcon, pste, &argcmPrev[i], &san);
				VSanToSz(&san, aszSan);
				if (!(i & 1))
					szOut += sprintf(szOut, "%d. ", i / 2 + 1);
				szOut += sprintf(szOut, "%s", aszSan);
				if (argfAvoid[i])
					*szOut++ = '?';
				*szOut++ = ' ';
			} else if (bdm != bdmNONE)
				szOut += sprintf(szOut, "  ");
			VCmToSz(&argcmPrev[i], aszMov);
			f = FAdvance(pcon, aszMov);
			Assert(f);
		}
		//	I'm going to take care of the new stuff now.
		//
		fFollowing = fTRUE;
		for (; isz < csz; isz++) {
			char	aszSan[32];
			char	aszMov[32];
			int	j;
			PCM	pcm;
			CM	cm;
			SAN	san;

			if (atoi(argsz[isz]))		// Skip move numbers.
				continue;
			if (argsz[isz][0] == '(')	// Variation name starts with "(" and
				break;					//  is last arg.  The vectorize
										//  routine used in here handles "("
										//  specially, so this works.
			//
			//	If the move some even number of plies back was a "?" move,
			//	this is a "?" move, too, otherwise it isn't.
			//
			if (cply < 2)	// Too close to the start to have a move before.
				argfAvoid[cply] = fFALSE;
			else
				argfAvoid[cply] = argfAvoid[cply - 2];
			//
			//	Look for an explicit "?", which marks this as a move to avoid.
			//
			for (j = 0; argsz[isz][j]; j++)
				if (argsz[isz][j] == '?') {
					argsz[isz][j] = '\0';
					argfAvoid[cply] = fTRUE;
					break;
				}
			//
			//	Find the move in the list of legal moves, essentially
			//	converting from SAN to internal format.
			//
			VGenLegalMoves(pcon, pste);
			pcm = pste->pcmFirst;
			for (; pcm < (pste + 1)->pcmFirst; pcm++) {
				VCmToSan(pcon, pste, pcm, &san);
				VSanToSz(&san, aszSan);
				if (!strcmp(aszSan, argsz[isz]))
					break;
			}
			if (pcm >= (pste + 1)->pcmFirst) {
				sprintf(aszBuf, "Illegal move for %s, token %d on line",
					(pste->coUs == coWHITE) ? "white" : "black", isz + 1);
				VBookError(szFile, cLine, aszBuf);
				fResult = fFALSE;
				goto lblDone;
			}
			cm = *pcm;
			//
			//	Output the move if necssary.  This is some tricky and nasty
			//	code, depending upon what mode I'm in, what I've already
			//	outputed on this line, and whether the book I'm reading in
			//	is "full" or "compact".
			//
			if (bdm != bdmNONE) {
				if (fFollowing)
					if ((cplyPrev <= cply) || (memcmp(&cm,
						&argcmPrev[cply], sizeof(CM)))) {
						if ((cply & 1) && (bdm == bdmCOMPACT))
							szOut += sprintf(szOut, "%d. ... ", cply / 2 + 1);
						fFollowing = fFALSE;
					} else if (bdm == bdmCOMPACT)
						szOut += sprintf(szOut, "  ");
				if ((!fFollowing) || (bdm == bdmFULL)) {
					if (!(cply & 1))
						szOut += sprintf(szOut, "%d. ", cply / 2 + 1);
					szOut += sprintf(szOut, "%s", aszSan);
					if (argfAvoid[cply])
						*szOut++ = '?';
					*szOut++ = ' ';
				}
			}
			//	Make the move on the internal board.
			//
			VCmToSz(&cm, aszMov);
			f = FAdvance(pcon, aszMov);
			Assert(f);
			//
			//	Hash it unless it is a "?" move.  This is how "avoid" moves
			//	are handled -- they are simply not hashed in the book file.
			//
			//	What this means of course is that every instance of the
			//	position after this move is made must be marked with a "?",
			//	or it's like none of them are.
			//
			//	With a "compact" book, this isn't a problem, unless there are
			//	transpositions.
			//
			if (!argfAvoid[cply]) {
				HASHK	hashkFull = HashkFull(pcon, pste);

				//	Note that the previous line generates moves, which is
				//	annoying.
				//
				//	I'm hashing the "full" keys, so the en-passant and
				//	castling don't cause problems.
				//
				if (FHashBn(hashkFull))
					if (++cbn >= s_cbnMax * 3 / 4) {
						VBookError(szFile, cLine, "Book memory full");
						fResult = fFALSE;
						goto lblDone;
					}
			}
			//	Remember the move in the "last line" array, which will be used
			//	to diff the next line against this one.
			//
			argcmPrev[cply++] = cm;
		}
		//	Record the length of the current line.
		//
		cplyPrev = cply;
		//
		//	Deal with the variation name field at the end of the line, which
		//	means just printing it out if I'm in dump mode.
		//
		if (bdm != bdmNONE) {
			if (isz < csz) {		// <-- "isz < csz" if I found a "(".
				//
				//	I'm going to print the line in 128 characters, followed by
				//	the variation name.  This is pretty wide, but lots of
				//	lines are longer than 80 characters.
				//
				while (szOut - aszOut < 128)
					*szOut++ = ' ';
				szOut += sprintf(szOut, "%s", argsz[isz]);
			}
			*szOut = '\0';
			VStrip(szOut);
			printf("%s\n", aszOut);
		}
	}
	if (bdm == bdmNONE)
		VPrSendComment("%d book positions", cbn);
	else
		fResult = fFALSE;	// If I dumped this book, I'm going to exit the
lblDone:					//  program after this returns.
	fclose(pfI);
	return fResult;
}
Exemple #7
0
void VBookError(char * szFile, int cLine, char * sz)
{
	VPrSendComment("Book error (%s, line %d) : %s.", szFile, cLine, sz);
}
Exemple #8
0
void VPrIcs(void * pv, char * szIcs)
{
	PCON pcon = pv;

	VPrSendComment("I am playing on: %s", szIcs);
}
Exemple #9
0
void VPrOpponentName(void * pv, char * szName)
{
	PCON pcon = pv;
	
	VPrSendComment("Opponent is: %s", szName);
}
Exemple #10
0
void VPrOpponentComputer(void * pv)
{
	PCON pcon = pv;

	VPrSendComment("Opponent is a computer.");
}
void VThink(PCON pcon, TM tmUs, TM tmThem)
{
	Assert(pcon->smode == smodeIDLE);
    //VPrSendComment("entering VThink\n");
	if (pcon->fLowPriority)
		VLowPriority();
    if( uciHash.has_changed() )
        FInitHashe(pcon);
    if( uciBookName.has_changed() )
        book_open( uciBookName.get_string() );
    if( uciUseEGBB.has_changed() || uciEGBBDir.has_changed() )
        prepareEGBB();
	//
	//	Set up time-out, and remind myself that I'm not dead.
	//
	pcon->ss.tmUs = tmUs;
	pcon->ss.tmThem = tmThem;
	pcon->fAbort = false;
	pcon->smode = (tmUs == tmANALYZE) ? smodeANALYZE : smodeTHINK;
	//
	//	This loop is going to execute at least once.  It might execute for the
	//	whole game, if the program continuously ponders correctly.
	//

	char	aszMove[32];
	char	aszPonder[32];
    aszMove[0] = aszPonder[0] = '\0';
	for (;;) {
		char	aszSanHint[32];
		SAN	sanHint;
		CM	cm;
		bool	f;

        //VPrSendComment("for (;;) mode=%d\n", pcon->smode);
        stats.raz();
        razKillers();
        History.raz();
        CounterMoves.raz();
        initMVVLVA( pcon );

		pcon->fTimeout = false;	    	// I'm not timed out yet.
		pcon->ss.tmStart = TmNow();		// Record when I started.
		if (pcon->smode ==				// If I'm pondering, I don't set the
			smodeTHINK)					//  time control stuff.  This will be
			VSetTime(pcon);				//  handled at the point it's clear
										//  that I picked the correct move.

        bool keepPV = false;
        if (pcon->smode ==smodeTHINK) {
//            printf("# mode is THINK\n");
            if( pcon->gc.argcm > 0 ) {
                CM lastMove = pcon->gc.argcm[pcon->gc.ccm - 1];
                char	asz[16];
                CmToSz(&lastMove, asz);
                if( lastMove == lastPV[2] ) {
                    for(int i = 0; i < csteMAX; i++)
                        lastPV[i] = lastPV[i+2];
                    keepPV = true;
                }
            }
        }
        PSTE	pste = &pcon->argste[0];
        pste->ccmPv = 0;
        if( !keepPV ) {
            // Clear the PV
            VSetPv(pcon);
        }

//        VSetRepHash(pcon);				// Pump game history into rep hash.
        if (pcon->smode == smodeTHINK)
            VDrawCheck(pcon);			// Try to claim appropriate 50-move
										//  and 3x rep draws before examining
										//  moves.
        //
        //	During the first 20 moves of the game I will try to find a book
        //	move.  If I find one I will play it.
        //
        if ((pcon->smode == smodeTHINK) && (uciOwnBook.get_check()) &&
            (pcon->gc.ccm < 40) && (book_find_move(pcon, &cm, true))) {
            char	asz[16];

            CmToSz(&cm, asz);	// Make book move.
            bool f = FAdvance(pcon, asz);
            Assert(f);
            VPrSendMove(asz, "");// I am not going to bother checking for draws
					            //  and mates that occur while in book.  If by
					            //  weird chance one of these happens, if
					            //  we're hooked up to the chess server, the
					            //  server might call it.
            break;
        }
        //	Increment sequence number.  The transposition hash system will
        //	overwrite nodes from old searches, and this is how it knows that
        //	this is a new search, rather than just more of the old one.
        //
        VIncrementHashSeq();
        //
        //	Search the position via iterative deepening.
        //
        pcon->ss.nodes = 0;			// Global node counter.
        pcon->ss.nodesNext = 2000;	// Time (in nodes) of next callback to
							        //  interface.
        if( pcon->tc.nodes )
            pcon->ss.nodesNext = pcon->tc.nodes;

        pcon->ss.tbhits = 0;

        pste->evaluated  = false;
        int staticVal = ValEval(pcon, pste, -20000, 20000);

        pste->plyRem = 0;
        pcon->ss.plyDepth = 0 + 1;

        pcon->ss.lastVal = staticVal;
        int oldVal = pcon->ss.lastVal;
//        pcon->ss.tmExtend = false;
        pcon->ss.easyMove = false;
//        pcon->ss.dontStop = false;
        pcon->ss.dontStopPrev = false;
        pcon->ss.canStop = false;

        pcon->ss.currBestMove = CM(0,0);
        int prevDepthVal = valMIN;
        int val = 0;
        int Alpha = valMIN;			// Initial window is wide open.
        int Beta = valMAX;
        for (int i = 0; i < plyMAX; i++)  {
            // TODO : re enable aspiration window !
            pcon->ss.plyMaxDepth = 0;
            pste->plyRem = i;
            pcon->ss.plyDepth = i + 1;
            pcon->ss.failed = false;
            pcon->ss.scoreDropped = false;
            pcon->ss.rootHasChanged = false;

            VPrSendUciDepth( pcon->ss );

            val = ValSearchRoot(pcon, pste, Alpha, Beta);

            if( pcon->ss.lastVal > oldVal )
                oldVal = pcon->ss.lastVal;
            else
                oldVal = (pcon->ss.lastVal + oldVal)/2;
            if( val > pcon->ss.lastVal || (pcon->ss.plyDepth <= 3))
                pcon->ss.lastVal = val;
            else
                pcon->ss.lastVal = (pcon->ss.lastVal + val)/2;
//            pcon->ss.lastVal = val;

/*            if( pcon->ss.dontStopPrev ) {
                printf("# dontStopPrev is set, delta = %d \n", val - oldVal);
                if( val - oldVal >= -35 ) {
                    printf("# reseting dontStopPrev to false\n");
                    pcon->ss.dontStopPrev = false;
                }
            }*/

//            pcon->ss.dontStop = pcon->ss.scoreDropped;
//            pcon->ss.canStop = (pcon->ss.plyDepth >=5) && 
//                !pcon->ss.scoreDropped && !pcon->ss.dontStopPrev; // && !pcon->ss.rootHasChanged;
            pcon->ss.canStop = (pcon->ss.plyDepth >=1) && 
                !pcon->ss.scoreDropped;// && !pcon->ss.dontStopPrev; // && !pcon->ss.rootHasChanged;
            printf("# scoreDropped=%d rootChanged=%d stopPrev=%d => canStop=%d\n", 
                pcon->ss.scoreDropped, pcon->ss.rootHasChanged, pcon->ss.dontStopPrev, pcon->ss.canStop);
//            pcon->ss.dontStopPrev = pcon->ss.dontStop;
            pcon->ss.dontStopPrev = pcon->ss.scoreDropped;

            // Initialize the PV with the result of the previous search
            VSetPv(pcon);
            if (pcon->fAbort || pcon->fTimeout)
                break;
            //
            //	This checks for a result outside the window, and if it finds
            //	one it re-searches with the window wide open.
            //
			if ((val <= Alpha) || (val >= Beta)) {
				if (val <= Alpha)	// Record a fail-low (fail-high is
										//  handled inside "ValSearch").
					//
					//	This function needs the root moves generated, and they
					//	are, because "ValSearch" does it.
					//
					VDumpPv(pcon, pcon->ss.plyDepth, val, prsaFAIL_LOW);
				val = ValSearchRoot(pcon, pste, valMIN, valMAX);
                // Initialize the PV with the result of the previous search
			    VSetPv(pcon);
				if (pcon->fAbort)
					break;
				if (pcon->fTimeout)
					break;
			}

//            VIncrementHashSeq();

            pcon->ss.prsa = prsaNORMAL;
            pcon->ss.val = val;
            //
            //	Mated now or this move mates, drop out of here.
            //
            if ((pcon->ss.val == valMATE - 1) || (pcon->ss.val == -valMATE))
                break;
            // found a mate in n, no need to iterate
            if( (val == prevDepthVal) && (val > /*50*100*/(valMATE - 500) ) && (pcon->smode != smodeANALYZE) )
                break;
            prevDepthVal = val;
            // stop thinking if there is only one move, no need to let the other guy
            // think longer
            if( pcon->ss.ccmLegalMoves == 1 ) {
                // we can still look a bit so we have a PV set for the next move
                if( i >= 5 && (pcon->smode == smodeTHINK))
                    break;
            }
            if( (pcon->smode == smodeTHINK) ) {
                int usedTime = TmNow() - pcon->ss.tmStart;
                int remaingingTime = pcon->ss.tmEnd  - TmNow();
                if( pcon->ss.canStop && !pcon->ss.rootHasChanged && (usedTime > remaingingTime) ) {
                    VPrSendComment("time : used=%d remaining =%d\n", usedTime, remaingingTime);
                    break;
                }
            }
#if 0
            if( (pcon->smode == smodeTHINK) ) {
                int usedTime = TmNow() - pcon->ss.tmStart;
                int remaingingTime = pcon->ss.tmEnd  + pcon->ss.tmExtra / 9  - TmNow();
                const int bf = int(1.9f * 32); // kind of branching factor
                if( (!pcon->ss.failed) && (usedTime * bf) / 32 > remaingingTime ) {
                    VPrSendComment("time : used=%d remaining =%d\n", usedTime, remaingingTime);
                    break;
                }
            }
#endif
            //
            //	Depth-restricted search.  Check for "timeout", meaning target
            //	depth met.
            //
            if (((pcon->smode == smodeTHINK) || (pcon->smode == smodePONDER)) 
                && (pcon->tc.plyDepth > 0) &&
                (pcon->ss.plyDepth >= pcon->tc.plyDepth))
                break;
            //
            //	Set up for next iteration, which will use a window centered
            //	around the current position value.
            //
//			Alpha = val - 50;
//			Beta = val + 50;
        }

        //	If abort or doing pondering, I'm done, because I don't need to
        //	make any moves or set up the next search.
        //
        //	NOTE: None of the stuff below happens in analysis mode, because
        //	the next line exits the routine!  This means that results won't
        //	be posted (draws, mates, etc.) if the game is in analysis mode,
        //	which seems to be the right thing to do according to Tim Mann,
        //	circa 26-Apr-2001 on the Yahoo chess engines mailing list.
        //
#ifdef _DEBUG
        stats.report();
#endif
        //
        //	If there is a move in the first element of the PV, I can make it.
        //	I don't make it now, because I want to look at the second element
        //	of the PV for a pondering move, and if I execute the first move,
        //	it will destroy the PV.
        //
        aszMove[0] = aszPonder[0] = '\0';
        if (pste->ccmPv >= 1)
            CmToSz(&pste->argcmPv[0], aszMove);
        CM	cmHint;
        if ((pste->ccmPv >= 2)) {
            CmToSz(&pste->argcmPv[1], aszPonder);
            cmHint = pste->argcmPv[1];
        }
        // this line was moved down for uci support
        // TODO : check this
        if ((pcon->fAbort) || (pcon->smode != smodeTHINK))
            break;

        //	As of this point, I have move to make in "aszMove", move to ponder
        //	in "aszPonder".  If I can't move, or I can't ponder, these strings
        //	are nulled out.
        //
        //	Check to see if I'm mated or stalemated, which will be the case
        //	if I can't move.
        //
        if (aszMove[0] == '\0') {
			if ((!pcon->fTimeout) && (pcon->ss.val == -valMATE)) {
				VMates(pste->side ^ 1);
				break;
			}
			VStalemate(pste->side);
			break;
		}
        //VPrSendComment("advancing my move=%s\n", aszMove);
        f = FAdvance(pcon, aszMove);
        Assert(f);
        //
        //	Deal with draw offers right before the move is sent to the
        //	interface.  This boolean is set when the opponent offers a draw.
        //	It is cleared when the interface tells us to set up a new
        //	position, and when the engine makes a move.
        //
        //	If this boolean is not cleared at the appropriate time, it's not
        //	critically bad, because all that will happen is that the program
        //	will offer an unsolicited draw in a position it thinks is drawn.
        //
        //	The engine will execute its planned move after trying to agree to
        //	the draw, in case something goes wrong with the draw offer.
        //
        //	If the interface can't handle this, there could be problems.
        //
        //	This code is before the resignation code in order to catch the
        //	one-in-a-million case where the opponent offers a draw before the
        //	engine can resign.
        //
        if (pcon->fDrawOffered) {
            if (FAcceptDraw(pcon, pste))
                VPrOfferDraw();
            pcon->fDrawOffered = false;
        }
        //	Check to see if I should resign, and do so if necessary.  The move
        //	the engine is planning to make is not executed in this case, in
        //	order to avoid the unattractive <move made> <resigns> sequence.
        //
        //	If the interface doesn't listen to the resignation, the program
        //	simply won't move.
        //
        else if (FCheckResign(pcon, pste))
            break;
        //	Inform the interface that we have a move.
        //
        if( ! pcon->isUCI ) 
            VPrSendMove(aszMove, aszPonder);
        //
        //	The score from the last search might indicate that this is mate.
        //
        if ((!pcon->fTimeout) && (val == valMATE - 1)) {
            VMates(pste->side ^ 1);	// This is backwards because we already
            break;					//  moved on the internal board.
        }
        //	Check for 50-move or 3x repetition draws.
        //
        VDrawCheck(pcon);
        //
        //	Check to see if I stalemated my opponent, and report the result as
        //	appropriate.
        //
        if (FStalemated(pcon))
            VStalemate(pste->side ^ 1);
        //
        //	If the PV contained at least two moves, and the "fPonder" boolean
        //	is set, the second one is sitting in "aszPonder".
        //
        //	If there is no move, we're done, and we're going to drop out of
        //	the bottom of this routine and leave.
        //
        //	If there was a move, I'm going to set our state to "smodePONDER",
        //	remember the move that we are pondering on, execute the move on
        //	the board, and loop around to the top of this think loop and start
        //	thinking again.
        //
        //	Later, if the the interface passes in the move that we are
        //	pondering on, the state info will be dummied up so the program
        //	thinks it's doing a normal search.  If the wrong move is passed in
        //	(the opponent made a move we didn't expect), we'll abort the
        //	search, undo the last move, exit this routine, and be called again
        //	and told to think.
        //
        //	So we get into this routine when we're told to think about
        //	something, and we stay in here until we fail to predict the
        //	opponent's move.
        //

        if (aszPonder[0] == '\0' || !pcon->fPonder )
            break;

        //
        //	Get the algebraic so I can send a hint move.  The Winboard
        //	interface will stick this at the beginning of the PV it displays
        //	while we are pondering.
        //
        bGenMoves(pcon,	pcon->argste);
        CmToSan(pcon, pcon->argste, &cmHint, &sanHint);
        SanToSz(&sanHint, aszSanHint);
        strcpy(pcon->aszPonder, aszPonder);
//        VPrSendComment("potential ponder move(2)=%s\n", aszSanHint);
        //
        //	Execute the move.  I'm now one move ahead of the game, which is
        //	tricky.  After that, send the hint move.
        //
//        VPrSendComment("ok let's advance for the ponder move %s\n", aszPonder);
        f = FAdvance(pcon, aszPonder);
        Assert(f);
        if (pcon->fPost)
            VPrSendHint(aszSanHint);
        VPrSendComment("switching to ponder mode, previous mode was=%d\n", pcon->smode);
        pcon->smode = smodePONDER;
    }
    //	Inform the interface that we have a move.
    //
    if( pcon->isUCI ) {
        VPrSendUciNodeCount(true, pcon->ss );
        VPrSendMove(aszMove, aszPonder);
    }
    //	If I broke out, and I'm in ponder mode, back up the search and pretend
    //	that I never pondered.  I could do some sneaky stuff having to do with
    //	remembering the move that would have been made if the pondered search
    //	had been converted into a normal search soon enough, but this would be
    //	annoying to do and it's kind of rare and pointless.
    //
    stats.report2();
    //VPrSendComment("end of VThink mode is %d\n", pcon->smode );
    if (pcon->smode == smodePONDER)
        VUndoMove(pcon);
    pcon->smode = smodeIDLE;
}