Invalid move

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

Aleks Peshkov
Posts: 892
Joined: Sun Nov 19, 2006 9:16 pm
Location: Russia

Re: Invalid move

Post by Aleks Peshkov »

I cannot say better then Bob had said already.

Your nearest goal should be not to make another mediocre chess engine but too study and practice programming skills.
Henk
Posts: 7216
Joined: Mon May 27, 2013 10:31 am

Re: Invalid move

Post by Henk »

The only thing I learned is that using 'modern' design patterns don't work well in a chess engine for most important is efficiency. Some improvements only work if they are implemented in an efficient way.

For instance using an iterator on a bit board is much too slow. While using iterators is good programming practice.

But first task is to get most basic stuff working 100%. Problem was that I was using test positions only in last weeks. But they test too less. So I did not encounter any illegal moves.

I think there may also be problems when cleaning up hash table during search. It is code I don't trust.

But if I do not clean up hash during search then I may get an out of memory bug when doing deep analysis.
Henk
Posts: 7216
Joined: Mon May 27, 2013 10:31 am

Re: Invalid move

Post by Henk »

Sven Schüle wrote:@Henk: If skipper plays an illegal root move, as you have described, then you could track it like this:

Add debugging code only for the root node (plyCount == 0 I guess). The effort is negligible so you could leave it in for a while. So if you are at the root then go through the whole move list that you have just generated in a conservative way (not optimized for efficiency but clear and safe, and also not basing on "king capture" but on the usual legality detection mechanisms) to identify all illegal moves, and save this information as a list of booleans (legal/illegal) where the list index corresponds to the index of the move in your regular move list. This additional list could be a global array (rootMoveIsLegal[]). To do this correctly you will probably also need to find out "in a conservative way" whether the moving side is currently in check (same here: only for root node - "global variable" isInCheckAtRoot).

Then continue with the normal move loop. In the loop body you should be able to tell whether the move that you have just tried was illegal or not (in your case of a king-capture engine I would assume you can tell it by looking at the returned subtree score). Now when being in the move loop of the root node this information must match the "conservative" legal/illegal flag that you have saved in the beginning. If it doesn't match then the last subtree has returned wrong information. This could still go unnoticed in the context of playing a move in the game since it could either be a legal root move that is wrongly classified as "illegal" (then you might just miss to play a better move if this root move would be the best move), or an illegal move that does not become new best move (then it does not affect the move decision). Now you could raise an exception and maybe dump some relevant information. Play hundreds or thousands of fast games with this instrumented version to see whether you can catch the problem. Save the games automatically! If the problem occurs you now have data to reproduce it, attach the debugger and find the root cause.
Ok 'll implement something like that. The worst thing is that I have to play very many games before a similar bug is encountered.
kbhearn
Posts: 411
Joined: Thu Dec 30, 2010 4:48 am

Re: Invalid move

Post by kbhearn »

For instance using an iterator on a bit board is much too slow. While using iterators is good programming practice.
I'm quite sure one can write oneself an iterator that isn't 'much too slow'. Whether or not that's actually good programming practice since it comes down to hiding a simple task inside of a class is another matter.

Your iterator would be a forward iterator, would contain its own copy of the bitboard and an int for current value. increment operation would set it to 'end' if the bitboard is now empty or pop and remove the next significant bit otherwise. I think it might come out being slower than just handling the iteration logic directly in loops rather than being able to write them as generic iterator loops but it wouldn't be 'much too slow', all the little functions would be inlinable and perhaps the compiler would be smart enough to get rid of the waste for you.

really though - the difference between

Code: Select all

for (BBIterator iter(bb); iter != BBIterator::end; ++iter) { // BBIterator constructor makes copy for you
// *iter can now be used as sq
...
}
and

Code: Select all

while (bb) { // make copy first if you need to preserve bb
sq = bb.bsfandremove();
...
}
hardly justifies having to write a seperate iterator class to me.
Henk
Posts: 7216
Joined: Mon May 27, 2013 10:31 am

Re: Invalid move

Post by Henk »

I am using C# and I have not found an equivalent for 'inlining' methods also it has no macro facility. Probably they expect the compiler knows best.

This was the class I used before. Don't do this at home.

Code: Select all

 public class BitBoardIterator:IBitBoardIterator
    {
        UInt64 bits;
      
 
        public void Reset(UInt64 bits)
        {
            this.bits = bits;
         
           
        }

        public UInt64 Next()
        {
            while (bits != 0)
            {
                UInt64 bit = bits & (~bits + 1);
             
                bits &= bits - 1;
                return bit;
            }
            return 0;         
        }
    }
Another reason not to take much care about my code for it usually gets replaced in a few weeks. Unless it is really bad and ugly code with many bugs or with major design errors. These code lines usually stay forever.
kbhearn
Posts: 411
Joined: Thu Dec 30, 2010 4:48 am

Re: Invalid move

Post by kbhearn »

Henk wrote:I am using C# and I have not found an equivalent for 'inlining' methods also it has no macro facility. Probably they expect the compiler knows best.
Yes, well... c# is another issue not related to using iterators. You may need to avoid some features in order to get a reasonably fast program but i'm not familiar enough with it to say which. It could be the fact that you appear to derive from an interface class. It could just be that it's not designed to be compiled to efficient native code so small heavily used functions are penalised where in c++ they'd be inlined for you automagically.
jdart
Posts: 4366
Joined: Fri Mar 10, 2006 5:23 am
Location: http://www.arasanchess.org

Re: Invalid move

Post by jdart »

If my program is compiled with debug flags on it does a lot of additional checking including sanity checks for each move generated (for example, start square is non-empty or (if castling) King is on the expected square). Another useful check is to verify that if the program thinks the King is in check, the King can really be captured by the opposing side (I have some optimizations for finding check and this verifies correctness).

Running a search in debug mode slows down execution quite a bit but still it is going to hit many millions of nodes during a minute search so will exercise the code in many different positions.

So try that and then run your test suite .. and don't stop until you have zero asserts triggered.

Another very useful tool is the sanitizer flags that are now part of GCC (install the latest GCC to get these). See https://gcc.gnu.org/onlinedocs//gcc/Ins ... tions.html. These will find uninitialized variables and other programming errors.

--Jon
jdart
Posts: 4366
Joined: Fri Mar 10, 2006 5:23 am
Location: http://www.arasanchess.org

Re: Invalid move

Post by jdart »

I forgot to mention:

Implementing and checking perft (https://chessprogramming.wikispaces.com/Perft) is also an excellent way to find bugs in move generation.

--Jon