Ok I already had forgotten why chess programming was complicated (disregarding some terrible tough bugs and the bit board stuff).hgm wrote:This is not how it is usually done. When I want to know if a move is checking in my mailbox engines, I calculate the vector from the to-Square to the opponent's King square (from the piece list), and test in a lookup table if that vector matches with one of the possible captures from the moved piece (by bitwise AND between the direction sets). If there is alignment, and the piece is a leaper, it is a check. If it was a slider, you have to scan the ray between to-Square and King.Henk wrote:I don't understand why checking KingInCheck for each move in futility pruning is not too expensive. KingInCheck means that you have to generate all or almost all moves and test if it can capture the King. This will certainly never work at depth 1.
In addition you have to test for discovered checks by scanning the ray from King in the direction of the from-Square, and test if what you hit is a slider that captures in that direction.
If you are smart, you can combine the latter task for several moves, as usually many moves share the same from-square.
It is still expensive compared to MakeMove(), but far cheaper than a full move generation.
MadChess 2.0 Development
Moderator: Ras
-
Henk
- Posts: 7251
- Joined: Mon May 27, 2013 10:31 am
Re: MadChess 2.0 Development
-
hgm
- Posts: 28458
- Joined: Fri Mar 10, 2006 10:06 am
- Location: Amsterdam
- Full name: H G Muller
Re: MadChess 2.0 Development
Well, it is as complicated as you want it to be. Fairy-Max does it in the way you describe, just playing null move and see if that returns a King-captured score. That means it can only see if a move is checking at d=2, when the daughter node still has a ply left for null move.
So you can get a long way without any complex tricks. (And for variants this actually is a plus, as the tricks typically make use of special properties of pieces that might not hold in variants. Like that the range of a move is always 1 or infinite, that a ray is traversed always in steps of one, that pieces can only be blocked along the line of sight, etc.) If Skipper does not beat Fairy-Max yet, it is not because it doesn't use any complicated tricks...
So you can get a long way without any complex tricks. (And for variants this actually is a plus, as the tricks typically make use of special properties of pieces that might not hold in variants. Like that the range of a move is always 1 or infinite, that a ray is traversed always in steps of one, that pieces can only be blocked along the line of sight, etc.) If Skipper does not beat Fairy-Max yet, it is not because it doesn't use any complicated tricks...
-
emadsen
- Posts: 441
- Joined: Thu Apr 26, 2012 1:51 am
- Location: Oak Park, IL, USA
- Full name: Erik Madsen
Re: MadChess 2.0 Development
I use a very similar technique in my engine. I play the pseudo-legal move, scan from own king in each compass direction plus knight directions, looking for enemy attackers (exposing own king to check), then scan from piece destination square (checking enemy king), then undo the move. This technique determines if the move is legal and whether it checks the enemy king.hgm wrote:This is not how it is usually done. When I want to know if a move is checking in my mailbox engines, I calculate the vector from the to-Square to the opponent's King square (from the piece list), and test in a lookup table if that vector matches with one of the possible captures from the moved piece (by bitwise AND between the direction sets). If there is alignment, and the piece is a leaper, it is a check. If it was a slider, you have to scan the ray between to-Square and King.
In addition you have to test for discovered checks by scanning the ray from King in the direction of the from-Square, and test if what you hit is a slider that captures in that direction.
If you are smart, you can combine the latter task for several moves, as usually many moves share the same from-square.
It is still expensive compared to MakeMove(), but far cheaper than a full move generation.
This is a very simple method which is sufficient for now. I know I can optimize it later by tracking slider occupancy of ranks, files, and diagonals. Such data will indicate when an attack is impossible- trading incremental updates of occupancy for avoidance of scanning some compass directions. And I can eliminate playing the move twice (once to test legality, once in search) with some kind of PlayIfLegal method. I need to give this some thought...
Erik Madsen | My C# chess engine: https://www.madchess.net