assert

Discussion of chess software programming and technical issues.

Moderators: hgm, Harvey Williamson, bob

Forum rules
This textbox is used to restore diagrams posted with the [d] tag before the upgrade.
F. Bluemers
Posts: 838
Joined: Thu Mar 09, 2006 10:21 pm
Location: Nederland
Contact:

Re: assert

Post by F. Bluemers » Mon Nov 13, 2017 1:08 pm

flok wrote:Hi,

I'm looking to improve my program.
For that I'm adding asserts all over the place to check input variables, outgoing values, and so on.
I've also added an assert that if we're in a null move, then beta == alpha + 1.
My question now is: what other things are there to check for?


regards
The last question also shows why one should not overrate assert(),you already have to now what to look for...

Anyway,you can add asserts for hashtable initialized
board is valid before and after makemove
alpha<beta
remaining depth< limit or your killer and other tables
remaining depth>=0
various checks on a move(squares in range,piece,etc)

User avatar
hgm
Posts: 22332
Joined: Fri Mar 10, 2006 9:06 am
Location: Amsterdam
Full name: H G Muller
Contact:

Re: assert

Post by hgm » Mon Nov 13, 2017 3:14 pm

Knowing what I am going to test in an assert for me is almost the same as already realizing how I calculated it wrong. I get many errors in my engines, but when I finally smoked them out, they are always in a completely unexpected place, which I never imagined could go wrong, and would never have and the idea for to test it with an assert.

When you have a lot of incrementally updated stuff, it is very advisable to also have a routine to calculate it from scratch, and compare the two.

jdart
Posts: 3510
Joined: Fri Mar 10, 2006 4:23 am
Location: http://www.arasanchess.org

Re: assert

Post by jdart » Mon Nov 13, 2017 5:59 pm

Some things I do in debug mode:

Check that all scores returned by eval or from the hash are in the range of valid values (-MATE, +MATE).

Sanity check all moves returned from the move generator or the hash., or added to the PV array I.e. a valid piece is on the start square, the dest is not a same-color piece, etc.

I have a check after each move made that the hash code after the move (updated incrementally) matches the value calculated from scratch (not incrementally)

If you have C-style arrays, do a bound check on the index before access. (Or consider using <array> if C++).

--Jon

Ras
Posts: 951
Joined: Tue Aug 30, 2016 6:19 pm
Contact:

Re: assert

Post by Ras » Mon Nov 13, 2017 11:49 pm

mar wrote:if you index local arrays out of bounds, that's your problem.
That's only one of the countless pitfalls. C has tons of undefined behaviour. Like shifting by more than a variable's width, signed integer overflow or pointer aliasing. Together with increasingly hostile compilers, you can't even rely on well-tested code.

Under Linux, GCC offers a lot of sanitizer options that are useful during testing, and I'd advise to use them.

User avatar
lucasart
Posts: 2957
Joined: Mon May 31, 2010 11:29 am
Contact:

Re: assert

Post by lucasart » Tue Nov 14, 2017 6:23 am

Harald wrote:If you want to test only parts of your code then you can do things like this:

In an header like basics.h

Code: Select all

// Which tests should be performed
#ifdef _DEBUG
#define ASSERT_BASICS&#40;c,t&#41;              &#123; if ( !&#40;c&#41; )  throw &#40;t&#41;; &#125;
#define ASSERT_PRINCIPAL_VARIATION&#40;c,t&#41; &#123; if ( !&#40;c&#41; )  throw &#40;t&#41;; &#125;
#define ASSERT_MOVE&#40;c,t&#41;                &#123; if ( !&#40;c&#41; )  throw &#40;t&#41;; &#125;
...
#else
#define ASSERT_BASICS&#40;c,t&#41;
#define ASSERT_PRINCIPAL_VARIATION&#40;c,t&#41;
#define ASSERT_MOVE&#40;c,t&#41;
...
#endif
And in a file like move.cpp

Code: Select all

void Move&#58;&#58;set&#40; ColorType color, SquareType from, SquareType to,
                PieceType piece, PieceType capture,
                PromotionType promotion
              )
&#123;
    ASSERT_MOVE&#40; color == White || color == Black, "Error&#58; bad color in Move&#58;&#58;set&#40;)" )
    ASSERT_MOVE&#40; from >= 0 && from < 64, "Error&#58; bad from in Move&#58;&#58;set&#40;)" )
    ASSERT_MOVE&#40; to   >= 0 && to   < 64, "Error&#58; bad to in Move&#58;&#58;set&#40;)" )
    ASSERT_MOVE&#40; piece >= Pawn && piece < 8, "Error&#58; bad piece in Move&#58;&#58;set&#40;)" )
    ASSERT_MOVE&#40; capture >= NoPiece && capture != King && capture < 8, "Error&#58; bad capture in Move&#58;&#58;set&#40;)" )
    ASSERT_MOVE&#40; promotion <= PromoteToKnight, "Error&#58; bad promotion in Move&#58;&#58;set&#40;)" )
    move_ = from | &#40;to << 6&#41; | &#40;promotion << 12&#41; | &#40;piece << 14&#41; | &#40;capture << 17&#41; | &#40;color << 20&#41;;
&#125;
This is pointless. Just clutters the code for no reason.

Assert already prints the source file name and line when it fires.
Theory and practice sometimes clash. And when that happens, theory loses. Every single time.

AlvaroBegue
Posts: 884
Joined: Tue Mar 09, 2010 2:46 pm
Location: New York

Re: assert

Post by AlvaroBegue » Tue Nov 14, 2017 12:26 pm

lucasart wrote:
Harald wrote:If you want to test only parts of your code then you can do things like this:

In an header like basics.h

Code: Select all

// Which tests should be performed
#ifdef _DEBUG
#define ASSERT_BASICS&#40;c,t&#41;              &#123; if ( !&#40;c&#41; )  throw &#40;t&#41;; &#125;
#define ASSERT_PRINCIPAL_VARIATION&#40;c,t&#41; &#123; if ( !&#40;c&#41; )  throw &#40;t&#41;; &#125;
#define ASSERT_MOVE&#40;c,t&#41;                &#123; if ( !&#40;c&#41; )  throw &#40;t&#41;; &#125;
...
#else
#define ASSERT_BASICS&#40;c,t&#41;
#define ASSERT_PRINCIPAL_VARIATION&#40;c,t&#41;
#define ASSERT_MOVE&#40;c,t&#41;
...
#endif
And in a file like move.cpp

Code: Select all

void Move&#58;&#58;set&#40; ColorType color, SquareType from, SquareType to,
                PieceType piece, PieceType capture,
                PromotionType promotion
              )
&#123;
    ASSERT_MOVE&#40; color == White || color == Black, "Error&#58; bad color in Move&#58;&#58;set&#40;)" )
    ASSERT_MOVE&#40; from >= 0 && from < 64, "Error&#58; bad from in Move&#58;&#58;set&#40;)" )
    ASSERT_MOVE&#40; to   >= 0 && to   < 64, "Error&#58; bad to in Move&#58;&#58;set&#40;)" )
    ASSERT_MOVE&#40; piece >= Pawn && piece < 8, "Error&#58; bad piece in Move&#58;&#58;set&#40;)" )
    ASSERT_MOVE&#40; capture >= NoPiece && capture != King && capture < 8, "Error&#58; bad capture in Move&#58;&#58;set&#40;)" )
    ASSERT_MOVE&#40; promotion <= PromoteToKnight, "Error&#58; bad promotion in Move&#58;&#58;set&#40;)" )
    move_ = from | &#40;to << 6&#41; | &#40;promotion << 12&#41; | &#40;piece << 14&#41; | &#40;capture << 17&#41; | &#40;color << 20&#41;;
&#125;
This is pointless. Just clutters the code for no reason.

Assert already prints the source file name and line when it fires.
Those are pretty bad examples, but sometimes you do want to have a message to go with the assert. I have seen this trick used before:

Code: Select all

    assert&#40;a1 >= 0.0f && "negative values not yet supported");
When the condition is not satisfied you get a message like this:

Code: Select all

Assertion failed&#58; &#40;a1 >= 0.0f && "negative values not yet supported"), function main, file kk.cpp, line 44.

Harald
Posts: 259
Joined: Thu Mar 09, 2006 12:07 am

Re: assert

Post by Harald » Tue Nov 14, 2017 7:45 pm

This is pointless. Just clutters the code for no reason.
The point is that you can choose which portions of your program you want to debug today without making the whole program slower.

Henk
Posts: 5104
Joined: Mon May 27, 2013 8:31 am

Re: assert

Post by Henk » Tue Nov 14, 2017 8:17 pm

They also say you should avoid using primitive types. If you define a more specific type you can add more checks and make less mistakes.

Post Reply