My basic generation functions are genqs() and gen_neutral(). gen_all() is not used in my critical search() except for mate_search() and elsewhere like UCI move validation and debug autoplay. Coming to mate_search() means the game is won so this mate_search() is very simple and would not be a drag even if "transplated" to Rybka 4! - or it might give it another 10 elo!Sven Schüle wrote:I can think of a possible reason why your original version failed. It is a common mistake, or let's call it "bad programming habit", to write big functions that serve for more than one purpose at once. In your case, your gen_all() function includes both move generation *and* move ordering, and it is also used for illegal move detection. By separating these issues you gain much more flexibility. It may turn out that the performance of perft() is much less crucial than the performance of your regular search, but nevertheless it can often be considered a design flaw to put too much functionality into one function, simply because that function becomes too specialized and is not easy to reuse at other places. Every time you want to use gen_all() you have to buy everything it includes, even if you don't like it. In your case, gen_all() was in fact not reusable for perft without accepting major drawbacks due to useless generation and ordering of irrelevant neutral moves.Chan Rasjid wrote:Sven,
You are spot on. I found it independently, but too slow.
So it could mean my ordering of neutral moves is too elaborate.Code: Select all
...
As to your new implementation, I would still consider it as kind of an "intermediate" solution since I expect that your genqs() function includes move ordering, too, which has zero meaning for perft due to absence of alpha-beta. I would separate the ordering and the generation parts for both gen_all() and genqs(). Furthermore, I still think that legality check can be done much simpler and faster than by generating all capture moves. But maybe you are currently in a situation where you want to postpone "optimizations". (Having made perft faster by a factor of >10 may indeed be more than an "optimization", in this case I think you simply use a superior algorithm.) So separating ordering from generation can be useful, using a faster legality check is kind of "optional".
For your regular search, can you explain briefly how gen_all() works? Do you generate moves piece by piece and calculate ordering data immediately when a move is generated, stopping in the middle when generating a king capture?
Sven
Code: Select all
// the basic generation functions are genqs() and gen_neutral()
// prototype
move_t validate_partialmove(move_t move, int side);
move_t *genqs_all(move_t *m, const int s, const u64 k_brAttack[]);
move_t *genqs(move_t *m, const int side, const u64 k_brAttack[]);
move_t *gen_neutral(move_t *move, const int s, const u64 k_brAttack[], int *phase, const int gen_part);
int gen_root_move(rootmove_t *rootmove, check_t *check_s, const int side);
move_t * gen_all(move_t *move, const check_t *check_s, const int side);
move_t *gen_evade_check(move_t *m, const check_t *check_s, const int s);
move_t *gen_all(move_t *move, const check_t *check_s, const int side) {
if (!check_s->type) {
// !!! ugly k_brAttack[3] - currently only used in gen_neutral for gen() brq check
u64 k_brAttack[3];
k_brAttack[0] = ROT_DIAG7(king[side^1]) | ROT_DIAG9(king[side^1]);
k_brAttack[1] = ROT_FILE(king[side^1]) | ROT_RANK(king[side^1]);
k_brAttack[2] = k_brAttack[0] | k_brAttack[1];
if ((move = genqs_all(move, side, k_brAttack)) != NULL) {
// !!! incremental full generation likely not a good idea; currently disabled
int p = PhaseNeutralStart;
move = gen_neutral(move, side, k_brAttack, &p, 0);
}else {/* invalid, capt King */
return NULL;
}
assert(*move == 0);
}else {
if (!is_sq_attacked_brq(king[side^1], side));
else {/* invalid, capt King */
return NULL;
}
move = gen_evade_check(move, check_s, side);
assert(*move == 0);
}
return move;
}
I don't know why my info says I joined CCC in March 2006. I think I joined earlier, probably 2003 and was active for a while as I had many questions. I do learn a lot here and have read and are aware of most of the basics of chess programming. I consider my current engine "mature". The only things or the thing missing, of course, is the ELO not reaching that of ROBBOLITTO, "THE CLONE ". Imagine my earlier engine (before I come here) with a full transposition table had a hard time keeping up with TSCP! I got a lot of hint's here, just as Vasik Rajlich did ??? My engine could play a 100+ games in debug auto play mode without an assert() being triggered and it is very important - I have assert()s at every corner! I think only after a program is bug free can we think about other things (there of course is another simpler route ... ). I think I can now start thinking.
Move validation has been well covered in the past here. Most of the mature programs should have settled with a choice though "micro" optimization could still be done. My current method is that used by Crafty, king capture in the next node, unless it has switched camp. Now that you mentioned about validation, I might want to re-consider validation before "making" the move. Behind my mind, I seem to see now that I have all the functions that could make it slightly better and not hard to implement. I will think a little.
My engine is bitboard. For gen_qs(), the moves includes all captures, ep and promote. The sliding pieces are the first to be generated as, in my implementation, only these can do a king capture. It ranges through the B/R/Q bitboards for the pieces. On capture of a king, it returns, otherwise it packs the move with ordering info in the same integer-32. K/N/P capture of king is done when the king moves and it is cheap to check if it counter-threat any K/N/P through pre-calculated board[64]->kMap/nMap/pMap[2 sides]. Intuitively, I think my move generation cannot be "better". The only thing is how much to put into move ordering for non-captures. I expect all programs to be as efficient in the plain move generation part.
As for perft, I want only to use the real generator as perft is meant for it. I don't want to do even the slightest editing just in case bugs might enter hiding other real bugs. I would like to compare nps with other engines - don't know if Crafty or other engines can run perft through a command line.
BTW, Sven, have you a released version of your program (if you don't have one !!!) in linux. I want programs for testing.
Rasjid