bob wrote:...
First question is, what is your board representation? Bitboards have advantages and disadvantages. One significant advantage is in the evaluation where you can ask multiple questions by doing boolean operations on "sets" of information in one instruction. Make/Unmake is not particularly fast compared to a 0x88-like implementation because of redundant work being done (occupied squares, etc). The first place bitboards shows its versatility is when you choose to generate just captures, as here it is simply faster than 0x88. But perft doesn't do a capture-only search so it plays no part in perft.
If I were trying to write the fastest-possible perft, I would use something else. I use perft to check things after making a significant change to the move generator, or make/unmake, or the check detector.
I use a 16x10 board. , that means:
Code: Select all
I=Illegal
V=Vuota (empty)
I,I,I,I,I,I,I,I,I,I
I,I,I,I,I,I,I,I,I,I
I,I,I,I,I,I,I,I,I,I
I,I,I,I,I,I,I,I,I,I
V,V,V,V,V,V,V,V,I,I
V,V,V,V,V,V,V,V,I,I
V,V,V,V,V,V,V,V,I,I
V,V,V,V,V,V,V,V,I,I
V,V,V,V,V,V,V,V,I,I
V,V,V,V,V,V,V,V,I,I
V,V,V,V,V,V,V,V,I,I
V,V,V,V,V,V,V,V,I,I
I,I,I,I,I,I,I,I,I,I
I,I,I,I,I,I,I,I,I,I
The first 2 illegal squares lines are more than needed, one extra illegal square is enough to handle knight on a8 illegal moves (on the left top square). I don't use board indexes but directly square pointers. Its easiest to handle, in assembly, from my point of view. Despite from that, it is a common rapresentation, i think.
Maybe transposition tables used in standard search and applyed to perft can help to debug the transposition tables itself or to collect statistics? In fact, as you said, there are no usefull raison to speed up perft but it becomes interesting if the speed up one is trying can then be applyed to normal search. Using some standard search speed-up in perft can give an information about that speed-up correctness.
Coming back to check test, i test the squares to know if there are an enemy piece of the required types. I test many piece types for any square tested, depending if they are ne suqare near or more to the king. Supposing to have to test for check to a white king in e4, i test:
d5,f5 for K/Q/B/P
e5 for K/Q/R
d3,f3 for K/Q/B
e3 for K/Q
then others "e" column squares for Q/R and "5" line for Q/R and obviously the 2 diagonals for Q/B.
When i find a friend piece or an enemy piece not of desired type i stop testing on that line (column or diagonal).
At end, i test for 8 knights squares.
The test costs "only" 3 assembly instructions per square (the test is in something like an unrolled loop, in assembly - in fact i use macros to write readable code). It is very expensive because it requires testing for 16/17 squares for a just castled king with all pawns unmoved. It means about 50 instructions. If the king is in the middle of the board, it takes more inst. Generating a single moves takes me about 7/8 inst. so the cost of testing for check is about as to generate almost 7 more moves per any move played!!! Obviously making the moves takes more than generate it... so the effective cost, compared with move generation, is less important but still higher than other approach, i think.
In previous programs (Drago/Raffaela) i tested for check only at the next ply (that means not to check at all) but with Freccia i want to try to leave the check as soon as i have played the move (or a little before, if i want further optimize).