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.
Help with Debugging My Chess Engine
Moderators: hgm, Rebel, chrisw
-
- Posts: 855
- Joined: Sun May 23, 2010 1:32 pm
Re: Help with Debugging My Chess Engine
lot's of people will be gald to help, if you explain your problem
you are welcome
you are welcome
-
- 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
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!
To do so, implement perft and compare what you get to known results.
Let us know if you find any problems there.
Good luck!
-
- 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
Hi Pranav,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.
you can be sure that there will be someone who can help you, as soon as we know more about your problem.
-
- Posts: 12540
- Joined: Wed Mar 08, 2006 8:57 pm
- Location: Redmond, WA USA
Re: Help with Debugging My Chess Engine
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.
But sharing ideas is an even greater virtue. We have another word for this. It is called teaching.
-
- Posts: 53
- Joined: Mon Sep 19, 2016 6:51 am
Re: Help with Debugging My Chess Engine
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
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
-
- Posts: 27790
- Joined: Fri Mar 10, 2006 10:06 am
- Location: Amsterdam
- Full name: H G Muller
Re: Help with Debugging My Chess Engine
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.
-
- Posts: 793
- Joined: Sun Aug 03, 2014 4:48 am
- Location: London, UK
Re: Help with Debugging My Chess Engine
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.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.
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.
Use a debugger.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.
"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.
It's best to store castling permissions before making moves.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.
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.
-
- Posts: 53
- Joined: Mon Sep 19, 2016 6:51 am
Re: Help with Debugging My Chess Engine
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.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 that, but I am getting a host of weird messages that I am unable to understand.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.
------------------------------------------------
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.
-
- Posts: 53
- Joined: Mon Sep 19, 2016 6:51 am
Re: Help with Debugging My Chess Engine
I got it. It will require some bit manipulation. Or I can use something like vector < array<bool, 4> > for the 4 castling rights.