Computer Chess Club Archives


Search

Terms

Messages

Subject: Re: Beginner's guide?

Author: Brian McKinley

Date: 11:59:19 05/14/98

Go up one level in this thread



On May 14, 1998 at 05:32:13, frank phillips wrote:

>Can anyone point me in the direction of explanations of the techniques
>used in chess programming.   Having learnt a bit of C this year and with
>the help of articles found on the Net about search algorithms managed to
>write crude connect4 and othello programs,  I would now appreciate some
>pointers to simple but thorough and complete explanations of  bitboards
>and hashtables.  Several articles I have found partially explain these
>topics but usually assume that the reader has more knowledge than I do,
>perhaps because they assume a basic programming background which I do
>not have.  The source code to Crafty (thanks Bob) is well documented but
>beyond me at the moment.  On a specific issue, I would be grateful for
>an explanation of how to get a pv out of the (alpha/beta negamax)
>search.  Everything I have tried so far based on storing the best move
>in an array pv[depth] has failed, so I seem to be missing a fundamental
>point - or am just plain stupid :-/

Figuring out how the back up the principal variation was one
of the problems that gave me trouble when I started my chess
program.  Then I realized that each value has a pv associated with
it, and that all you need to do is to back up the pv with the value.
I have tried to include some code to demonstrate this.  Notice that
AlphaBeta returns a structure containing a value and a pv instead
of just a value.  Good Luck.

// Structure to hold a pointer to a value and it's pv.
struct SResult
{
	SResult() { m_value = -INT_MAX; m_pv = 0;}
	SResult( int value, CMoveList * pv)
		{ m_value = value; m_pv = pv;}
	SResult & SResult::operator = (int i)
		{m_value = i; m_pv = 0; return *this;}
	operator int()
		{ return m_value;}
	SResult & operator - ()
		{ m_value = -m_value; return *this; };

	int m_value;
	CMoveList * m_pv;
};


// Saves the principal variation in the storage area (CMoveList)
// for the current ply.
CMoveList * CPosition::SavePrincipalVariation()
{
	int size = m_move - m_game->Position().MoveNumber();

	CMoveList & pv = *(m_plyinfo->m_pv);
	pv.Empty();

	if (size > 0)
	{
		pv.Size(size);

		SPlyInfo * plyinfo = m_plyinfo;

		for (int i = size - 1; i >= 0; i--)
		{
			pv[i] = plyinfo->m_lastmove;
			plyinfo = plyinfo->m_previous;
		}
	}

	return m_plyinfo->m_pv;
}

// This function swaps the pv at the next
// ply with the pv at this ply so that the pv
// will not be overwritten by the next move.

void CPosition::BackUpPrincipalVariation()
{
	CMoveList * pv = m_ply[m_nextplyinfo].m_pv;
	m_ply[m_nextplyinfo].m_pv = m_plyinfo->m_pv;
	m_plyinfo->m_pv = pv;
}

// Stripped down AlphaBeta to demonstrate how the pv is
// backed up with the value.

SResult CPosition::AlphaBeta( short depth, int alpha, int beta, int
positionbest)
{
	SResult best, value;
	CMove * move = 0;
	CMove bestmove;

	if (depth < 0 || GameOver())
	{
		best = Evaluate();
	}
	else
	{
		move = NextMove();
		while (move)
		{
			MakeMove(*move);

			if (best > alpha )
				alpha = best;

			value = -AlphaBeta( depth - 1, -beta, -alpha, best);
			UnMakeMove();

			if (value > best)
			{
				bestmove = *move;
				best = value;

				BackUpPrincipalVariation();

				if ( best >= beta)
					break;
			}
			move = NextMove();
		}
	}

	// Saving the pv is expensive, so only do it
	// if it will be backed up at the previous ply
	if (!best.m_pv && best < -positionbest)
	{
		best.m_pv = SavePrincipalVariation();
		if (!bestmove.IsEmpty())
			best.m_pv->Add(bestmove);
	}
	return best;
}



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.