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.