CDaley11 wrote:Thanks for your suggestions. As for the depth you are all worrying about, it is supposed to be like that. I am not decreasing the depth until it gets to zero, I am increasing it until it reaches the targeted depth. Also, it doesn't allow two null moves in a row. The problem actually was the beta and alpha being switched. Thank you for helping me out.
This bug should have been spotted by an assert(). I strongly advise you to use assert() wherever relevant. It makes your code
1/ self-documenting
2/ self-debugging
For example, the beginning of my search() function looks like this:
Code: Select all
assert(depth >= 0);
assert(alpha < beta && (is_pv || alpha+1 == beta));
if (depth <= 0)
return quiesce(...)
assert(depth >= 1);
In parciaular "assert(alpha < beta && (is_pv || alpha+1 == beta));" would have spotted the bug immediately, as well as many more potential bugs (like wrong node type passed to child when using PVS).
And even in plain and simple code, that looks straight forward, assert() are good. I cannot stress this enough, but let's take a fictitious example:
Code: Select all
if (piece == PAWN) {
...
} else if (piece == KNIGHT) {
...
} else if (piece is slider) {
...
} else {
assert(piece == KING); // what else could it be
...
}
This may seem like a trivial case, where the assert() is unnecessary pedantic code, but it's important for several reasons:
- self-documenting: what if the "..." are quite large and the whole code occupies several screen pages. Then when you are looking at the "else" portion, it is not self-obvious.
- self-debugging: OK initially you write code, and test it, and it works. And later on, you modify it, and screw things up. For example you remove the pawn case, because it becomes unnecessary. But you forgot that the else will then be called if it's a pawn, even though that code was written and tested with piece == KING in mind!
- another funny example. Suppose you write piece = PAWN instead of piece == PAWN, by accident (and let's assume the int value of PAWN is zero). You've introduced a deadly bug, and if you don't have an assert() your code may silently produce buggy results. Badly coded chess engines are full of silent bugs, and then they wonder why they can't exceed 2000 elo even though they have all the search techniques and eval stuff in there.
It's really by reading the source code of Fruit 2.1 back in 2004 that I changed my coding style, and understood the power and beauty of self-debugging & self-documenting code.
assert() and unit tests have saved my life countless times, and DiscoCheck would just be a buggy piece of crap without them.