Computer Chess Club Archives


Search

Terms

Messages

Subject: Re: Question about Gerbil

Author: Dann Corbit

Date: 15:49:08 07/11/01

Go up one level in this thread


On July 11, 2001 at 18:35:48, Dan Homan wrote:

>On July 11, 2001 at 16:37:38, Dann Corbit wrote:
>
>>On July 11, 2001 at 16:16:29, Artem Pyatakov wrote:
>>
>>>I was just in the process of making my own program hash, and I was looking at
>>>the Gerbil 01 source code for some guidance, but I noticed something strange.
>>>
>>>Does Gerbil at this point NOT hash En Passant squares?
>>>Am I correctly thinking that this information should be hashed?
>>
>>Gerbil has the smartest e.p. hashing of any program I have ever seen.  I intend
>>to brashly copy it, as soon as I find the time.
>>
>>Gerbil hashes ONLY those e.p. information points where the pawn can *actually*
>>be taken which is just plain brilliant.  It will result in a lot more hash hits
>>for no apparent penalty.
>>
>>An example of the genius of Bruce Moreland.
>
>I think this idea has been around for a while... although I might just think so
>because Bruce Moreland mentioned it somewhere else... One wrinkle is that I
>thought most programs did this in their make-move routine (which, of course,
>updates the hash signature of a position).  I am surprised that it would be a
>bigger savings to do this when actually retrieving or storing the hash entry,
>but I haven't looked at Gerbil's code yet (it is on my todo list), so I don't
>know.

Reading Bruce's code is fun.  His comments read like a novel.
That's where Bruce does it too [in makemove].  The e.p. part is variable isqEnP:

void VMakeMove(PCON pcon, PSTE pste, PCM pcm)
{
	PSQ	psqFrom;
	PSQ	psqTo;

	(pste + 1)->isqEnP = isqNIL;	// By default, no en-passant square.
#ifdef	NULL_MOVE
	(pste + 1)->fNull = fFALSE;		// By default, null-move is allowed.
#endif
	(pste + 1)->cf = pste->cf &		// Some castling flags might get turned
		s_argcf[pcm->isqFrom] &		//  off if I'm moving a king or rook.
		s_argcf[pcm->isqTo];
	//
	//	Initialize various values for the next ply.
	//
	(pste + 1)->plyFifty = pste->plyFifty + 1;
	(pste + 1)->hashkPc = HashkSwitch(pste->hashkPc);
	(pste + 1)->hashkPn = pste->hashkPn;
	(pste + 1)->valPcUs = pste->valPcThem;
	(pste + 1)->valPcThem = pste->valPcUs;
	(pste + 1)->valPnUs = pste->valPnThem;
	(pste + 1)->valPnThem = pste->valPnUs;
	//
	//	This section handles cleaning up a captured piece.  The nastiest stuff
	//	is in the en-passant section.
	//
	psqTo = &pcon->argsq[pcm->isqTo];
	if (pcm->cmf & cmfCAPTURE) {
		int	isqTook;

		if (pcm->cmf & cmfMAKE_ENP) {			// This is gross.
			Assert(pste->isqEnP != isqNIL);
			isqTook = pste->isqEnP +
				((pste->coUs == coWHITE) ? -filIBD : filIBD);
			pste->ppiTook = pcon->argsq[isqTook].ppi;
			Assert(pste->ppiTook != NULL);
			Assert(pste->ppiTook->pc == pcPAWN);
			Assert(pste->ppiTook->co != pste->coUs);
			pcon->argsq[isqTook].ppi = NULL;
		} else {
			isqTook = pcm->isqTo;				// This is normal.
			pste->ppiTook = psqTo->ppi;			// This field will be used
		}										//  when it's time to unmake.
		Assert(pste->ppiTook != NULL);
		pste->ppiTook->fDead = fTRUE;			// <-- Mark it dead.
		(pste + 1)->hashkPc ^=					// XOR the piece out of the
			s_arghashkPc[pste->ppiTook->pc][	//  hash key.
			pste->ppiTook->co][isqTook];
		if (pste->ppiTook->pc == pcPAWN)		// Remove a captured pawn
			(pste + 1)->hashkPn ^=				//  from the pawn hash key.
				s_arghashkPc[pcPAWN][
				pste->ppiTook->co][isqTook];
		(pste + 1)->plyFifty = 0;				// Capture resets this.
		(pste + 1)->valPcUs -=
			s_argvalPcOnly[pste->ppiTook->pc];
		(pste + 1)->valPnUs -=
			s_argvalPnOnly[pste->ppiTook->pc];
	}
 	//	The next few lines move the piece, and clear out the "from" square,
	//	modify the new hash key, and deal with the fifty-move counter if this
	//	is a pawn move.
 	//
	psqFrom = &pcon->argsq[pcm->isqFrom];
	if (psqFrom->ppi->pc == pcPAWN)
		(pste + 1)->plyFifty = 0;
	psqTo->ppi = psqFrom->ppi;
	psqFrom->ppi = NULL;
	psqTo->ppi->isq = pcm->isqTo;
	(pste + 1)->hashkPc ^= s_arghashkPc[psqTo->ppi->pc][
		pste->coUs][pcm->isqFrom];
	(pste + 1)->hashkPc ^= s_arghashkPc[psqTo->ppi->pc][
		pste->coUs][pcm->isqTo];
	if (psqTo->ppi->pc == pcPAWN) {
		(pste + 1)->hashkPn ^= s_arghashkPc[pcPAWN][pste->coUs][pcm->isqFrom];
		(pste + 1)->hashkPn ^= s_arghashkPc[pcPAWN][pste->coUs][pcm->isqTo];
	}
	//	The rest of the function handles dumb special cases like castling
	//	and promotion and setting the en-passant square behind a two-square
	//	pawn move.
	//
	if (pcm->cmf & cmfCASTLE) {
		int	isqRookFrom;
		int	isqRookTo;
		PSQ	psqRookFrom;
		PSQ	psqRookTo;
		PPI	ppiRook;

		switch (pcm->isqTo) {
		case isqC1:
			isqRookFrom = isqA1;
			isqRookTo = isqD1;
			break;
		case isqG1:
			isqRookFrom = isqH1;
			isqRookTo = isqF1;
			break;
		case isqC8:
			isqRookFrom = isqA8;
			isqRookTo = isqD8;
			break;
		default:
			Assert(fFALSE);
		case isqG8:
			isqRookFrom = isqH8;
			isqRookTo = isqF8;
			break;
		}
		psqRookFrom = &pcon->argsq[isqRookFrom];
		psqRookTo = &pcon->argsq[isqRookTo];
		ppiRook = psqRookFrom->ppi;
		Assert(ppiRook != NULL);
		ppiRook->isq = isqRookTo;
		Assert(psqRookTo->ppi == NULL);
		psqRookTo->ppi = ppiRook;
		psqRookFrom->ppi = NULL;
		(pste + 1)->hashkPc ^= s_arghashkPc[pcROOK][pste->coUs][isqRookFrom];
		(pste + 1)->hashkPc ^= s_arghashkPc[pcROOK][pste->coUs][isqRookTo];
	} else if (pcm->cmf & cmfPR_MASK) {
		int	pcTo = (int)(pcm->cmf & cmfPR_MASK);

		psqTo->ppi->pc = pcTo;
		psqTo->ppi->val = s_argvalPc[pcTo];
		(pste + 1)->valPcThem += s_argvalPcOnly[pcTo];
		(pste + 1)->valPnThem -= valPAWN;
		//
		//	Reflect the pawn's promotion in the hash key.
		//
		(pste + 1)->hashkPc ^= s_arghashkPc[pcPAWN][pste->coUs][pcm->isqTo];
		(pste + 1)->hashkPc ^= s_arghashkPc[pcTo][pste->coUs][pcm->isqTo];
		//
		//	In the pawn hash key, the pawn is just XOR'd out -- it's gone.
		//
		(pste + 1)->hashkPn ^= s_arghashkPc[pcTo][pste->coUs][pcm->isqTo];
	} else if (pcm->cmf & cmfSET_ENP) {
		int	isq;

		//	I'm only going to set the en-passant square if there is a pawn
		//	that could conceivably execute an en-passant capture.
		//
		isq = pcm->isqTo;
		if ((!((isq + 1) & 0x88)) &&
			(pcon->argsq[isq + 1].ppi != NULL) &&
			(pcon->argsq[isq + 1].ppi->pc == pcPAWN) &&
			(pcon->argsq[isq + 1].ppi->co != pste->coUs))
			(pste + 1)->isqEnP = isq + ((pste->coUs == coWHITE) ?
				-filIBD : filIBD);
		else if ((!((isq - 1) & 0x88)) &&
			(pcon->argsq[isq - 1].ppi != NULL) &&
			(pcon->argsq[isq - 1].ppi->pc == pcPAWN) &&
			(pcon->argsq[isq - 1].ppi->co != pste->coUs))
			(pste + 1)->isqEnP = isq + ((pste->coUs == coWHITE) ?
				-filIBD : filIBD);
	}
}



This page took 0 seconds to execute

Last modified: Thu, 15 Apr 21 08:11:13 -0700

Current Computer Chess Club Forums at Talkchess. This site by Sean Mintz.