If you use fail hard you know what to check. But fail hard is slower.flok wrote:Thank you all guys but I'm more looking for things like "in situation x, check if alpha > score and score < tt val" etc.
Like: in null move, check if alpha = beta - 1 and so on.
assert
Moderators: hgm, Rebel, chrisw
-
- Posts: 7220
- Joined: Mon May 27, 2013 10:31 am
Re: assert
-
- Posts: 2559
- Joined: Fri Nov 26, 2010 2:00 pm
- Location: Czech Republic
- Full name: Martin Sedlak
Re: assert
nonsense.lucasart wrote:Undefined behaviors and subtle bugs are pervasive in C, and even more so in C++. If you're coding in a more robust language like D or C#, you shouldn't have this kind of problem.
if you index local arrays out of bounds, that's your problem.
C# is slower compared to C/C++/D, I don't see how D is more robust than C/C++ except that it zero-initializes by default (not talking about language features).
(if you think so, maybe you should switch to D/C#)
in fact, C++ is of course more "robust" than C, you can use std::array which checks bounds in debug mode and of course more.
Valgrind/DrMemory won't catch all problems, but they're pretty good.
now back to OP: asserts are nice but they also slow your code in debug mode, so too many of them probably hurts
-
- Posts: 855
- Joined: Sun May 23, 2010 1:32 pm
Re: assert
You can find a lot of assert in position.h and position.cpp of Vajolet source code. It's probably not perfect but can give you some idea
-
- Posts: 318
- Joined: Thu Mar 09, 2006 1:07 am
Re: assert
If you want to test only parts of your code then you can do things like this:
In an header like basics.h
And in a file like move.cpp
In an header like basics.h
Code: Select all
// Which tests should be performed
#ifdef _DEBUG
#define ASSERT_BASICS(c,t) { if ( !(c) ) throw (t); }
#define ASSERT_PRINCIPAL_VARIATION(c,t) { if ( !(c) ) throw (t); }
#define ASSERT_MOVE(c,t) { if ( !(c) ) throw (t); }
...
#else
#define ASSERT_BASICS(c,t)
#define ASSERT_PRINCIPAL_VARIATION(c,t)
#define ASSERT_MOVE(c,t)
...
#endif
Code: Select all
void Move::set( ColorType color, SquareType from, SquareType to,
PieceType piece, PieceType capture,
PromotionType promotion
)
{
ASSERT_MOVE( color == White || color == Black, "Error: bad color in Move::set()" )
ASSERT_MOVE( from >= 0 && from < 64, "Error: bad from in Move::set()" )
ASSERT_MOVE( to >= 0 && to < 64, "Error: bad to in Move::set()" )
ASSERT_MOVE( piece >= Pawn && piece < 8, "Error: bad piece in Move::set()" )
ASSERT_MOVE( capture >= NoPiece && capture != King && capture < 8, "Error: bad capture in Move::set()" )
ASSERT_MOVE( promotion <= PromoteToKnight, "Error: bad promotion in Move::set()" )
move_ = from | (to << 6) | (promotion << 12) | (piece << 14) | (capture << 17) | (color << 20);
}
-
- Posts: 868
- Joined: Thu Mar 09, 2006 11:21 pm
- Location: Nederland
Re: assert
The last question also shows why one should not overrate assert(),you already have to now what to look for...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
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)
-
- Posts: 27811
- Joined: Fri Mar 10, 2006 10:06 am
- Location: Amsterdam
- Full name: H G Muller
Re: assert
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.
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.
-
- Posts: 4367
- Joined: Fri Mar 10, 2006 5:23 am
- Location: http://www.arasanchess.org
Re: assert
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
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
-
- Posts: 2488
- Joined: Tue Aug 30, 2016 8:19 pm
- Full name: Rasmus Althoff
Re: assert
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.mar wrote:if you index local arrays out of bounds, that's your problem.
Under Linux, GCC offers a lot of sanitizer options that are useful during testing, and I'd advise to use them.
-
- Posts: 3232
- Joined: Mon May 31, 2010 1:29 pm
- Full name: lucasart
Re: assert
This is pointless. Just clutters the code for no reason.Harald wrote:If you want to test only parts of your code then you can do things like this:
In an header like basics.hAnd in a file like move.cppCode: Select all
// Which tests should be performed #ifdef _DEBUG #define ASSERT_BASICS(c,t) { if ( !(c) ) throw (t); } #define ASSERT_PRINCIPAL_VARIATION(c,t) { if ( !(c) ) throw (t); } #define ASSERT_MOVE(c,t) { if ( !(c) ) throw (t); } ... #else #define ASSERT_BASICS(c,t) #define ASSERT_PRINCIPAL_VARIATION(c,t) #define ASSERT_MOVE(c,t) ... #endif
Code: Select all
void Move::set( ColorType color, SquareType from, SquareType to, PieceType piece, PieceType capture, PromotionType promotion ) { ASSERT_MOVE( color == White || color == Black, "Error: bad color in Move::set()" ) ASSERT_MOVE( from >= 0 && from < 64, "Error: bad from in Move::set()" ) ASSERT_MOVE( to >= 0 && to < 64, "Error: bad to in Move::set()" ) ASSERT_MOVE( piece >= Pawn && piece < 8, "Error: bad piece in Move::set()" ) ASSERT_MOVE( capture >= NoPiece && capture != King && capture < 8, "Error: bad capture in Move::set()" ) ASSERT_MOVE( promotion <= PromoteToKnight, "Error: bad promotion in Move::set()" ) move_ = from | (to << 6) | (promotion << 12) | (piece << 14) | (capture << 17) | (color << 20); }
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.
-
- Posts: 931
- Joined: Tue Mar 09, 2010 3:46 pm
- Location: New York
- Full name: Álvaro Begué (RuyDos)
Re: assert
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:lucasart wrote:This is pointless. Just clutters the code for no reason.Harald wrote:If you want to test only parts of your code then you can do things like this:
In an header like basics.hAnd in a file like move.cppCode: Select all
// Which tests should be performed #ifdef _DEBUG #define ASSERT_BASICS(c,t) { if ( !(c) ) throw (t); } #define ASSERT_PRINCIPAL_VARIATION(c,t) { if ( !(c) ) throw (t); } #define ASSERT_MOVE(c,t) { if ( !(c) ) throw (t); } ... #else #define ASSERT_BASICS(c,t) #define ASSERT_PRINCIPAL_VARIATION(c,t) #define ASSERT_MOVE(c,t) ... #endif
Code: Select all
void Move::set( ColorType color, SquareType from, SquareType to, PieceType piece, PieceType capture, PromotionType promotion ) { ASSERT_MOVE( color == White || color == Black, "Error: bad color in Move::set()" ) ASSERT_MOVE( from >= 0 && from < 64, "Error: bad from in Move::set()" ) ASSERT_MOVE( to >= 0 && to < 64, "Error: bad to in Move::set()" ) ASSERT_MOVE( piece >= Pawn && piece < 8, "Error: bad piece in Move::set()" ) ASSERT_MOVE( capture >= NoPiece && capture != King && capture < 8, "Error: bad capture in Move::set()" ) ASSERT_MOVE( promotion <= PromoteToKnight, "Error: bad promotion in Move::set()" ) move_ = from | (to << 6) | (promotion << 12) | (piece << 14) | (capture << 17) | (color << 20); }
Assert already prints the source file name and line when it fires.
Code: Select all
assert(a1 >= 0.0f && "negative values not yet supported");
Code: Select all
Assertion failed: (a1 >= 0.0f && "negative values not yet supported"), function main, file kk.cpp, line 44.