Zach Wegner wrote:diep wrote:Zach Wegner wrote:Still on that anti-bitboard kick, eh Vincent?

This has nothing to do with bitboards, i just objectively report what is fastest.
Thanks,
Vincent
Well, I think you would be right about the move generator, no argument there. Deserialization of bitboards is rather tedious and doesn't interest me, though creating the attack bitboards themselves is fun to think about from a mathematical point of view. But bitboards are just so much massively simpler and easier to conceptualize for me. For mailbox or gnuchess 4.x approaches to be fast at things like eval, you need to keep around tons of little tables. For example, take the evaluation of Fruit. A lot of it is fairly simple, but looking at the pawn eval or the king safety eval in particular shows tons of stuff that's just ugly: all the pawn_file and BitGE stuff, the piece_attacks_king() function, etc. Now compare this to Strelka, where (ahem) the exact same calculations are done with bitboards. Much simpler, and much faster. Even if you look at eval_pattern() in Fruit, where mailbox would supposedly shine, the Strelka version is simpler and faster. Even if bitboards weren't faster at this sort of stuff, it would be a massive advantage just in conceptualizing it.
All I'm saying is that I think the "bitboards are slow and complicated" mode of thinking is getting more and more outdated.
Attacktables is slower in bitboards of course, in diep i'm doing it incremental.
You can mathematical prove this easily. It is best for an evaluation function to have all information within a single integer preferably, or 2 integers.
In bitboards you are doing a big diaspora of information. Fruit is a bad comparision to compare with. It is french style coding, of a programmer who seems to write some sort of Fortran type C++ code. It's easy to speedup his code and get 2x more nps than Fruit in a lossless manner.
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
Bitboards is way too slow to do this non-incremental. You need some sort of datastructure like this. If you just see the 'combine attacks' function of crafty there, that's so so slow.
If you realize all this attack info gets used throughout Diep's eval, you'll realize the necessity of incremental attacktables for Diep.
The speed of your move generator determines a lot more than just move generation. It also shows how much talent you've got as a programmer.
Fiddling with bitboards already means bitboards is too slow for what you do, besides that it loses too much time.
Setup a datastructure like i've got in diep and you hardly ever again lose time to the datastructure itself. With bitboards you're nonstop busy with it. Higher level thinking hardly happens.
We can definitely conclude nearly 10 years after Frans Morsch did do the historic statement: "Vincent, please don't post what you do inside Diep, let them all toy with bitboards; bitboards is too complicated for them, it will limit engine strengths".
I can conclude he was so so right. Like 1 person really is fast in bitboards, the rest, despite trying to make a fast beancounter (nearly all of them), doesn't even manage to get under 1000 cycles a node. Real clumsy programmers. In fact biggest limit is c++ in most codes. The guys here don't realize how much of a slow down average c++ code is compared to C code, let alone assembler.
Additionally to that, if you just create a beancounter, how do you plan to beat rybka if you have a smaller evaluation function AND get 2 to 4 times slower nps than rybka?
Note that's still better than the Go guys. I remember a few years a discussion there, where they claimed JAVA to be nearly same speed like C.
If your evaluatoin function is rather simple and tiny, you can't claim to be a good programmer if you need more than 1000 cycles a node.
I see cases of bitboard engines, where diep, having worlds largest evaluation function, nearly gets the same nps, just thanks to clumsy implemented code and c++ overhead.
Now note that i do appreciate people who write their own code, a lot more than those who just model after existing engines; we would see a posting of GCP regarding Thinker here, but so far i didn't see him post it.
Vincent