Help with Debugging My Chess Engine - 2

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

universecoder
Posts: 53
Joined: Mon Sep 19, 2016 6:51 am

Help with Debugging My Chess Engine - 2

Post by universecoder »

So, I managed to fix the following:

1. The hash function, now it generates the same hash if we go to the same positions after playing moves or directly load the fen.

2. The castle and enPassant move restoration

3. Also the "loop"

Note that I will change some things(such as use the C++11 random number generator) soon enough.

In the process of doing this, I broke the hashing of uniqueKey somewhere in undoMove(). Also, it was working perfectly until I used a new method to restore the enPassant squares. i.e. after step 2 "castle and ep moves"

Any suggestions?
https://github.com/universecoder/Chess-Engine
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: Help with Debugging My Chess Engine - 2

Post by Sven »

universecoder wrote:In the process of doing this, I broke the hashing of uniqueKey somewhere in undoMove(). Also, it was working perfectly until I used a new method to restore the enPassant squares. i.e. after step 2 "castle and ep moves"

Any suggestions?
Yes. Look at these lines in undoMove():

Code: Select all

	if ( whiteCastlePerms[0] == true ) uniqueKey ^= whiteCastleHash[0];
	if ( whiteCastlePerms[1] == true ) uniqueKey ^= blackCastleHash[1];
	if ( blackCastlePerms[0] == true ) uniqueKey ^= whiteCastleHash[0];
	if ( blackCastlePerms[1] == true ) uniqueKey ^= blackCastleHash[1];
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: Help with Debugging My Chess Engine - 2

Post by Sven »

Sven Schüle wrote:
universecoder wrote:In the process of doing this, I broke the hashing of uniqueKey somewhere in undoMove(). Also, it was working perfectly until I used a new method to restore the enPassant squares. i.e. after step 2 "castle and ep moves"

Any suggestions?
Yes. Look at these lines in undoMove():

Code: Select all

	if ( whiteCastlePerms[0] == true ) uniqueKey ^= whiteCastleHash[0];
	if ( whiteCastlePerms[1] == true ) uniqueKey ^= blackCastleHash[1];
	if ( blackCastlePerms[0] == true ) uniqueKey ^= whiteCastleHash[0];
	if ( blackCastlePerms[1] == true ) uniqueKey ^= blackCastleHash[1];
In general you also need to be careful when mixing the "push-pop" method with the "make-unmake" method. You do the former for castling rights and en passant square(s) of the board, and you do the latter for the hash key. So you need to update the hash key if castling rights or en passant square(s) are changed, in playMove() as well as undoMove(). I'm not sure whether you are doing this correctly in the current version.

Problem 1: playMove() does not update the hash key related to any castling right changes.

Problem 2: undoMove() always updates the hash key related to one of the four castling rights if that castling right is set after unmaking the move, even if it was already set before unmaking. So you change the hash key even if the given castling right did not change.

Problem 3: I do not understand the semantics of your two en passant squares. What does enPassantSquare[black] mean exactly in a position where it is White's turn?
- In the initial opening position the opponent's en passant square is empty.
- After making a move the opponent's en passant square is empty since you clear it near the end of playMove().
- After unmaking a move the opponent's en passant square is empty since you restore its previous value, and that was empty.
So the opponent's en passant square is always empty, am I right? If that is the case then it should have zero influence on the hash key (and can also be removed).

Problem 4: undoMove() always updates the hash key related to the en passant square of the moving side if it is set after unmaking the move, similar to problem 2.
universecoder
Posts: 53
Joined: Mon Sep 19, 2016 6:51 am

Re: Help with Debugging My Chess Engine - 2

Post by universecoder »

Problem 1: playMove() does not update the hash key related to any castling right changes.
Yes it does, towards the end of playMove() there are if else statements which check things related to kings and rooks reset the castling rights if the conditions are met.
Problem 2: undoMove() always updates the hash key related to one of the four castling rights if that castling right is set after unmaking the move, even if it was already set before unmaking. So you change the hash key even if the given castling right did not change.
Thanks! I will change it!
Problem 4: undoMove() always updates the hash key related to the en passant square of the moving side if it is set after unmaking the move, similar to problem 2.
Same as above.

As for problem 3 you mentioned, I imagined that enPassantSquare[white] is the enPassantSquare at which white can make a capture. Similarly for black. I couldn't understand which state of the board should contain the enPassant Square, the ply in which the pawn moves two squares ahead or the next ply? I am going to change this soon, I believe.
universecoder
Posts: 53
Joined: Mon Sep 19, 2016 6:51 am

Re: Help with Debugging My Chess Engine - 2

Post by universecoder »

I am confused so as how to do this. In undoMove(), do I do

Code: Select all

if ( castleList[plies][0] != whiteCastlePerms[0] ) {
	whiteCastlePerms[0] = castleList[plies][0];
	uniqueKey ^= whiteCastleHash[0];
}
OR

Code: Select all

if ( castleList[plies][0] != castleList[plies-1][0] ) {
	whiteCastlePerms[0] = castleList[plies][0];
	uniqueKey ^= whiteCastleHash[0];
}
User avatar
Evert
Posts: 2929
Joined: Sat Jan 22, 2011 12:42 am
Location: NL

Re: Help with Debugging My Chess Engine - 2

Post by Evert »

A move by itself does not give you enough information to decide if unmaking it will restore castling rights.
By far the easiest way to handle this is to copy the hash key before making the move, and restoring it afterwards when you unmake the move.
universecoder
Posts: 53
Joined: Mon Sep 19, 2016 6:51 am

Re: Help with Debugging My Chess Engine - 2

Post by universecoder »

Right, but what do you think of the comment I made just now, I mean the two if statements?
universecoder
Posts: 53
Joined: Mon Sep 19, 2016 6:51 am

Re: Help with Debugging My Chess Engine - 2

Post by universecoder »

What steps should I take if my perft tests are wrong?

The updated code is on github.

For node 3 it shows 9104 instead of 8902.

https://github.com/universecoder/Chess-Engine
The master branch.
elcabesa
Posts: 855
Joined: Sun May 23, 2010 1:32 pm

Re: Help with Debugging My Chess Engine - 2

Post by elcabesa »

you can debug your perft comparing the result with the results of stockfish perft.
if you look at the output of stockfish perft it print a counter for each move.
following the moves that give you different movecount you can understand where your movegen fail
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: Help with Debugging My Chess Engine - 2

Post by Sven »

universecoder wrote:I am confused so as how to do this. In undoMove(), do I do

Code: Select all

if ( castleList[plies][0] != whiteCastlePerms[0] ) {
	whiteCastlePerms[0] = castleList[plies][0];
	uniqueKey ^= whiteCastleHash[0];
}
OR

Code: Select all

if ( castleList[plies][0] != castleList[plies-1][0] ) {
	whiteCastlePerms[0] = castleList[plies][0];
	uniqueKey ^= whiteCastleHash[0];
}
In undoMove(), if you have saved state information before making the move then you have to restore that information unconditionally. My previous statement regarding "updating ... only if ... has changed" was valid for incrementally updating the hash key, in both playMove() and undoMove(). Since you are now doing it the much better way by also saving and restoring the hash key any incremental hash key update now only appears in playMove(). Please note that "problem 1" regarding hash key update related to castling rights is still unsolved (you only do it for castling moves but in the large if-else block at the end of playMove() you only update the castling rights themselves, not the hash key). And undoMove() needs to be corrected regarding the unconditional restoring of castling rights and en passant square (you do it right already for the hash key).