hgm wrote:diep wrote:In diep i'm using an incremental attacktable. It works as follows:
int attacktable[2][64]; For side times squares.
In each integer: sign bit is not used.
bits 15..30 are giving the index numbers, in bitboard style, 1 bit
for each n, into the piecelist array.
int piecelist[2][18]; // gives square of piece.
So in that manner you can see, if you would need it what squares the attackers are on.
Then least few significant 4 bits are the number of attackers onto 1 square.
For titled players, number of attackers to a square is an important consideration in evaluating a position simply. Also in SEE it is of use.
the bits 4..29 there is a 'gnuchess 4.0' type of sense of value of a piece.
That ranges from ctlP being most significant to ctlK being least significant
Note the manner in how i do this 'ctlX' stuff is different from gnuchess 4.0
How do you do this incremental updtae? I want to do something similar in my engine HaQiKi D, but the problem I am running into is efficient removal of attacks when a piece is moved, in combination with elongation of unblocked slider attacks.
It is easy enough to keep some sort of stack containing the square number of all newly attacked squares (revealed by move generation for the moved piece) and the old attack maps of those squares. That allows for easy UnMake, without invoking move generation again. But when the piece is a slider, and one of its targets moves away later, its target might shift to some new square further along the ray. Then, when I later make a move with that slider, I cannot rely on the information on the stack with attacked squares to clear the corresponding attack bits in its former targets, as this would not contain the elongated slider move. And I cannot easily update the target square in the stack to the shifted target, as I don't know where to find the stack.
This problem seemed so nasty, that I became convinced it would be more efficient to use linked list to contain the attack info. By linking each attack in a list for the fromSquare as well as the toSquare, it is very easy to remove every move of a moved or captured piece out of its attack map (the list hanging from the toSquare), and uncouple the fromList it is part of in its entirety (for easy UnMake). Then I can easily update a cell to a new target, when a slider is unblocked. (For easy UnMake I actually replace them, keeping the toList they are in, and just taking them out of the fromList.)
But working with the doubly linked lists puts a heavy burdon on the load/store unit.
It is not so easy to get attacktables bugfree to work in an incremental manner. Considering your great analytical skills i leave it to those to figure out how to solve it. Doing attacktables incremental is a lot faster than generating them new of course.
You will realize that the 'free' thing i get from my attacktables is whether the king is under attack. So i do save out *that* system time.
Note this datastructure is not so clever for a fast beancounter, as doing attacktables incremental already is too slow. Diep gets 1 million nps single core when i would remove its eval, some more toying i managed to get it a tad faster than that (k7 2.1Ghz).
The only manner to really get to 2.5 million nps at a k7, so under 1000 cycles, was to do things in ad hoc manner.
A big problem of combining 2 searches is that a 2.5 million nps engine is less efficient thanks to lacking all the information that Diep has to its avail during search. In diep it is crucial to not search hopeless moves in qsearch.
At 2.5 mln nps you prefer to search a few hopeless moves over doing too little, your nps allows it anyway.
In diep of course the qsearch is everywhere the same. That allows better hashing. At any given depth in qsearch, the search sees and concludes the same bounds/scores so to speak.
At 2.5 mln nps what i do is 1 ply of checks and then just recaptures or interesting captures. It's total material driven in that case. No hashing at all in qsearch of course at that speed, the memory controller wouldn't be able to handle it, only hashing during main search. So that 2.5 mln nps gets limited mainly by memory controller in main search and by me reusing functionality out of diep to sooner get the program done (whereas new special dedicated code would be faster).
My basic question would be why you would want to get to work incremental attacktables considering that AFAIK not a single engine yours has a lot of chessknowledge inside its evaluation function.
You want to try to go for that?
Thanks,
Vincent