Computer Chess Club Archives


Search

Terms

Messages

Subject: Re: checks in qsearch

Author: Gerd Isenberg

Date: 15:51:53 10/29/02

Go up one level in this thread


<snip>
>>>You could go for something cheap to detect checks in qsearch
>>>and just see whether the 'to' square possibly attacks the king
>>>square, only after that call a function.
>>>
>>>if( quickchecktable[piece][63+kingsq-to]
>>> && slowcheck(piece,to,kingsq) )
>>>  check = true; ...
>>
>>In that case I may miss checks that are not done by the piece that moved.
>
>You are concerned about xray checks?
>
>In DIEP i do things like that, but i don't know many engines
>which do checks in qsearch which do them. Note that i do
>unlimited checks in the qsearch for like 32
>ply in a row or so (my stackdepth of qsearch currently is 32 ply
>i did see no reason yet to make that more).
>
>In any case, here is how i do things in qsearch, but i have to
>warn you that it's very slow if you want to get a million
>nodes a second :)
>
>Note that you see i'm using incremental attack tables too.
>
>For a number of years i could do without incremental attack tables
>by simply only using them in evaluation a lot and quite a bit less
>in move ordering.
>
>>I still have ways to improve the speed without missing checks.
>
>In case you want to do *all* checks, then you might want to use
>attacktables too.
>
>Note that i simply generate all moves in qsearch. Total move generation
>all together is like 0.6% system time anyway.
>
>Then i can do all moves from which i gamble that they are making my
>search more quiet. With big evaluation not necessarily captures and
>checks are the only moves that can modify evaluation a lot.
>
>>Note that I cannot use the difference in the squares to decide if a rook pseudo
>>attack the king because the difference between h2 and a3 is the same as the
>>difference between a3 and b3.
>
>but it's very fast to use such a small table that eliminates already the
>vaste majority.
>
>But indeed i also got rid of that primitive table and use a bigger table
>now. The primitive table works great however for programs that want to
>get a million nodes a second and extend check evasions (so we do not
>talk about qsearch here but about normal search where of course
>calling a function to detect whether you are in check is way way too
>slow).
>
>Here is some code from DIEP hoping you will have a look at it:
>
>    /* Eerst controleren op schaak */
>    if( piece != king && looprichting[piece][t][OpKing]
>     && ScanAttack(side,piece,t,OpKing) ) {
>      nt->zet |= move_checks;
>    }
>
>    /* Aftrekschaak */
>    if( (AttM[f]&(ctlB|ctlR|ctlQ)) ) {
>      if( ((AttM[f]&ctlB) && looprichting[bishop][f][OpKing]
>           && ScanXrayAttack(side,bishop,f,OpKing))
>       || ((AttM[f]&ctlR) && looprichting[rook][f][OpKing]
>           && ScanXrayAttack(side,rook,f,OpKing))
>       || ((AttM[f]&ctlQ) && looprichting[queen][f][OpKing]
>           && ScanXrayAttack(side,queen,f,OpKing)) ) {
>        int bb,bc,bd,be;
>        bb = board[t];
>        bc = color[t];
>        be = snelbord[f];
>        bd = snelbord[t];
>        snelbord[f] = 0;
>        snelbord[t] = 7;
>        board[f] = 0;
>        color[f] = neutral;
>        board[t] = 7;  /* zodat schaakje niet van het stuk zelf is */
>        color[t] = xside;
>        if( SqAttackedBySide(OpKing,side) ) {
>          nt->zet |= move_checks;
>          aftrekschaak = 1;
>     /*     #if ForwardPruning
>          nt->zet |= move_noprune;
>          #endif*/
>        }
>        board[f] = piece;
>        color[f] = side;
>        board[t] = bb;
>        color[t] = bc;
>        snelbord[f] = be;
>        snelbord[t] = bd;
>      }
>    }
>
>
>
<snip>

Hi Vincent,
nice to see some code from DIEP, interesting.

I guess the declaration for looprichting is something like this:

bool looprichting[12][64][64]; // 48KB or 40KB for [10]?

I do it with bitboards in a similar way, but use an array of function pointers
for each piece. For sliding pieces i use also currently a two dimensional array
(bitboards which makes 32KB) indexed by "to" and "king" to get a bitboard
looking for some pieces inbetween.

Due to mememory latency, i am thinking about a short direction fill, to
determine these "inter"-bitboards. May be an array of function pointers indexed
by let say (8+to-king) with dedicated functions that do directions fills with
1..7 iterations without any conditional jumps.

For "Aftrekschaak" i use bitboards for pinned pieces and covered
(remove?)checkers, I initialized simultaniously for both sides before
move-generation.
I have to look whether "from" is member of "remove checkers" bitboard and
whether the move leaves the ray.

Regards,
Gerd


// two polymorph routines
Bool CNode::IsCheckMove(UINT to, UINT piece) const	{
  return (this->*m_scIsCheckMove[piece])(to);}

Bool CNode::IsCheckMove(UINT from, UINT to, UINT piece) const	{
  return IsCheckMove(to, piece) || IsRemoveCheckMove(from, to);}

....

typedef	Bool (CNode::*PTR_ISCHECKMOVE)(UINT to) const;

CNode::PTR_ISCHECKMOVE CNode::m_scIsCheckMove[14] =
{
	KingCheckMove,
	KingCheckMove,
	WPawnCheckMove,
	BPawnCheckMove,
	BishopCheckMove,
	BishopCheckMove,
	KnightCheckMove,
	KnightCheckMove,
	RookCheckMove,
	RookCheckMove,
	KingCheckMove,
	KingCheckMove,
	QueenCheckMove,
	QueenCheckMove,
};

Bool CNode::KingCheckMove(UINT to) const
{
	to;
        ASSERT(false);
        return false;
}


Bool CNode::WPawnCheckMove(UINT to) const
{
	UINT eksq = EnemyKingSquare();
	if ( isDiagonalAdjacent(eksq, to) )
	{
		register int delta = eksq - to;
		return (delta == 7) + (delta == 9);
	}
	if (to >= 56 )
		return QueenCheckMove(to);
	return false;
}

...

Bool CNode::BishopCheckMove(UINT to) const
{
	UINT eksq = EnemyKingSquare();
	if ( isDiagonalAdjacent(eksq, to) )
		return true;
	if ( isDiagonal(eksq, to) )
		return (m_sInterBB[eksq][to] & GetPieceBB()) == 0;
	return false;
}

...



This page took 0.01 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.