Help with Debugging My Chess Engine

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

Post by universecoder »

Hello, everyone!
A few months ago I got interested in chess programming and I built my first chess engine. A very, very basic one, it generated only pseudo-legal moves; no castling, no enPassant at all. It used only NegaMax search(no alpha beta pruning and the likes). This time, I am building an improved chess engine( although I still simply use piece lists and the standard 120 entry board array). Right now, I have run into some kind of roadblock and unable to proceed further with my project. I believe that there must be a lot of expert chess programmers on this forum, so I asked here. I want some help in debugging my engine. Can anyone help? I'll soon reveal the source code and describe the exact problems if anyone is willing to help! Thanks in advance.
elcabesa
Posts: 855
Joined: Sun May 23, 2010 1:32 pm

Re: Help with Debugging My Chess Engine

Post by elcabesa »

lot's of people will be gald to help, if you explain your problem :)

you are welcome :)
AlvaroBegue
Posts: 931
Joined: Tue Mar 09, 2010 3:46 pm
Location: New York
Full name: Álvaro Begué (RuyDos)

Re: Help with Debugging My Chess Engine

Post by AlvaroBegue »

The first thing I would do is making sure that your basic functions work: move generation, making a move on the board, undoing the effects of a move on the board (if you have a function that does that).

To do so, implement perft and compare what you get to known results.

Let us know if you find any problems there.

Good luck!
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

Post by Sven »

universecoder wrote:Hello, everyone!
A few months ago I got interested in chess programming and I built my first chess engine. A very, very basic one, it generated only pseudo-legal moves; no castling, no enPassant at all. It used only NegaMax search(no alpha beta pruning and the likes). This time, I am building an improved chess engine( although I still simply use piece lists and the standard 120 entry board array). Right now, I have run into some kind of roadblock and unable to proceed further with my project. I believe that there must be a lot of expert chess programmers on this forum, so I asked here. I want some help in debugging my engine. Can anyone help? I'll soon reveal the source code and describe the exact problems if anyone is willing to help! Thanks in advance.
Hi Pranav,

you can be sure that there will be someone who can help you, as soon as we know more about your problem.
Dann Corbit
Posts: 12538
Joined: Wed Mar 08, 2006 8:57 pm
Location: Redmond, WA USA

Re: Help with Debugging My Chess Engine

Post by Dann Corbit »

If your source is from github or some other public source, just post a link and people will tell you what is broken and how to fix it.
Taking ideas is not a vice, it is a virtue. We have another word for this. It is called learning.
But sharing ideas is an even greater virtue. We have another word for this. It is called teaching.
universecoder
Posts: 53
Joined: Mon Sep 19, 2016 6:51 am

Re: Help with Debugging My Chess Engine

Post by universecoder »

I would like to thank everyone for showing interest. I'll now describe my chess engine's organization along with the problems I am facing and then I'll post the Github link. So here's it:

I have programmed it in C++(some features from C++11 are required as well).
The engine consists of the following files currently:

1. data.hpp - Contains several enumerations and some macros along with the declaration of some variables to enhance the readability of the program later. Also includes other standard header files.

2. move.hpp - It contains the declaration of the class Move.

3. move,cpp - Contains the definitions of methods in the move class. They are as follows: - Move(from, to) for normal/capture moves for any piece, Move(from) if it is enPassant(this is checked internally) and move(isCastle, castle), where isCastle is a boolean and the integer castle decides if it is king side or queen side castle. There is also a function to print the move and another one to initialize a move via a string. The printing and initializing functions are not complete right now, but they work just fine.
Also there is a function Move(from, to, PromotedPiece) for pawn promotion.

4. chessboard.hpp - Contains the declaration of the class chessboard

5. chessboard.cpp - It has the following functions:

initEmptyBoard() - It initializes an empty board
setUpDebugging() - Certain variables which make coding and printing easier
initHash() - Initializes the hashlist
fenSetup() - Loads a fen position onto the board
initPieceList() - Initializes the piece list after the fen setup is done
initUniqueKey() - Initializes the hash key.
playMove() - Play a move on the board and update the required variables
undoMove() - Undo a move on the board and update the required variables
printBoard() - This prints several variables and the board on the screen, and this helped me a lot with debugging purposes.
isSquareSafe() and isSquareAttacked() - As the names suggest
isMoveValid() - Records the side of the current king. Plays a move. Sees if square of the king is safe. If safe, then validity = true, else false. Undo the move and then return the validity.
addMove() - Checks if the move is valid and if it is so, then adds the move to the vector moveList.

6. moveGen.cpp - Contains the member function chessboard::generateAllMoves() which generates all pseudolegal moves for the current side, addMove() is used, so the vector moveList finally contains only legal moves.

7 . main.cpp - Currently only used for some tests

8. The Makefile

Now for my problems:

A) The unique keys generated when I play moves from the start to get to the fen position and when I directly load the fen position are different. Eg. I load the fen position for 1. e2e4 and I play the move e2e4 on the starting position, the uniqueKeys generated are different.

However, playing and undoing moves on the same board generates the same keys, so I believe the functions playMove() and undoMove() are right.

B) the isMoveValid function does not work as intended, It goes into some sort of infinite loop, unable to figure out why. This problem bugs me the most. So right now I have commented out the line if ( isMoveValid(move) ) in my addMove function. So right now I am only adding pseudo-legal moves to the moveList vector.

C) I am unable to figure to reset the castle permissions in undoMove(). I tried using a count of the no. of times the king/rook move, but it turned out to be ugly. I think I will have to store the castle permissions in a vector containing the castle history.

Sorry for any grammatical mistakes I might have made, I wrote this in a hurry.
Thanks, and here's the link to the code I've uploaded on Github(there is no licensing so it has the standard licensing by default).

https://github.com/universecoder/Chess-Engine
User avatar
hgm
Posts: 27788
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: Help with Debugging My Chess Engine

Post by hgm »

One way to remember castling rights is to pack four flags in one variable, (one for each castling), and keep a 'spoiler' board of such variables that for each square contains which flags should be reset when that square occurs as from-square or to-square. You then just remember the old value of the rights variable, and restore it when you undo the move. Only the King and Rook squares would spoil castlings.
matthewlai
Posts: 793
Joined: Sun Aug 03, 2014 4:48 am
Location: London, UK

Re: Help with Debugging My Chess Engine

Post by matthewlai »

universecoder wrote: A) The unique keys generated when I play moves from the start to get to the fen position and when I directly load the fen position are different. Eg. I load the fen position for 1. e2e4 and I play the move e2e4 on the starting position, the uniqueKeys generated are different.

However, playing and undoing moves on the same board generates the same keys, so I believe the functions playMove() and undoMove() are right.
You are initializing the zobrist keys with each instantiation of chessboard, so each chessboard has a different set of keys. Since keys don't really need to be per-board, it's probably better to have them either in a separate class/struct (as most other engines do), or have them as static members of chessboard and only initialize them once.

If you need to have the same zobrist keys between different runs of your program (for example, if you store hashes in opening books), you can use std::uniform_int_distribution<uint64_t> with std::mt19937_64 with a fixed seed.

In general there's no reason to use rand() in C++. C++11's pseudo-random number generation support is much more powerful than C's archaic rand() and srand().

Not sure if this actually your problem, but sorry I don't have time to go through your make/unmake functions right now. In general though, if it's something like this, you can probably just print out each operation on the hash in playMove() and see if there's anything unexpected.
B) the isMoveValid function does not work as intended, It goes into some sort of infinite loop, unable to figure out why. This problem bugs me the most. So right now I have commented out the line if ( isMoveValid(move) ) in my addMove function. So right now I am only adding pseudo-legal moves to the moveList vector.
Use a debugger.
"g++ -g ..."
"gdb ./testEngine"
"r[enter]"

Wait till it gets stuck, press Ctrl-C.

It will tell you exactly where it's getting stuck in.
C) I am unable to figure to reset the castle permissions in undoMove(). I tried using a count of the no. of times the king/rook move, but it turned out to be ugly. I think I will have to store the castle permissions in a vector containing the castle history.
It's best to store castling permissions before making moves.

Otherwise you'll run into weird corner cases like the rook being captured before moving, etc. Figuring all those things out (correctly) will be slower than just storing and restoring permissions.
Disclosure: I work for DeepMind on the AlphaZero project, but everything I say here is personal opinion and does not reflect the views of DeepMind / Alphabet.
universecoder
Posts: 53
Joined: Mon Sep 19, 2016 6:51 am

Re: Help with Debugging My Chess Engine

Post by universecoder »

You are initializing the zobrist keys with each instantiation of chessboard, so each chessboard has a different set of keys. Since keys don't really need to be per-board, it's probably better to have them either in a separate class/struct (as most other engines do), or have them as static members of chessboard and only initialize them once.
I did what you suggested(declared them as static and then initialized them), but I still have a problem, the generated keys are still different.
Use a debugger.
"g++ -g ..."
"gdb ./testEngine"
"r[enter]"

Wait till it gets stuck, press Ctrl-C.

It will tell you exactly where it's getting stuck in.
I did that, but I am getting a host of weird messages that I am unable to understand.

------------------------------------------------

0x0000000000407186 in std::__detail::_Insert_base<int, int, std::allocator<int>, std::__detail::_Identity, std::equal_to<int>, std::hash<int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, true, true> >::insert(int const&) ()

--------------------------------------------------

0x000000000040ae35 in std::_Hashtable<int, int, std::allocator<int>, std::__detail::_Identity, std::equal_to<int>, std::hash<int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, true, true> >::_M_remove_bucket_begin(unsigned long, std::__detail::_Hash_node<int, false>*, unsigned long) ()
--------------------------------------------------

Program received signal SIGINT, Interrupt.
0x0000000000409ff2 in std::allocator<int>::~allocator() ()
--------------------------------------------------

And yes, I'll make the castling work.
universecoder
Posts: 53
Joined: Mon Sep 19, 2016 6:51 am

Re: Help with Debugging My Chess Engine

Post by universecoder »

I got it. It will require some bit manipulation. Or I can use something like vector < array<bool, 4> > for the 4 castling rights.