Skip to content

Commit

Permalink
Simplify pos_is_ok()
Browse files Browse the repository at this point in the history
Now we don't need anymore the tricky pointer to
show the failed test. Added some few tests too.

Also small rename in see_ge() while there.

No functional change

Closes #1151
  • Loading branch information
mcostalba authored and zamar committed Jun 28, 2017
1 parent 7734212 commit fa1e342
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 70 deletions.
129 changes: 61 additions & 68 deletions src/position.cpp
Expand Up @@ -381,8 +381,7 @@ void Position::set_state(StateInfo* si) const {

/// Position::set() is an overload to initialize the position object with
/// the given endgame code string like "KBPKN". It is mainly a helper to
/// get the material key out of an endgame code. Position is not playable,
/// indeed is even not guaranteed to be legal.
/// get the material key out of an endgame code.

Position& Position::set(const string& code, Color c, StateInfo* si) {

Expand All @@ -394,8 +393,8 @@ Position& Position::set(const string& code, Color c, StateInfo* si) {

std::transform(sides[c].begin(), sides[c].end(), sides[c].begin(), tolower);

string fenStr = sides[0] + char(8 - sides[0].length() + '0') + "/8/8/8/8/8/8/"
+ sides[1] + char(8 - sides[1].length() + '0') + " w - - 0 10";
string fenStr = "8/" + sides[0] + char(8 - sides[0].length() + '0') + "/8/8/8/8/"
+ sides[1] + char(8 - sides[1].length() + '0') + "/8 w - - 0 10";

return set(fenStr, false, si, nullptr);
}
Expand Down Expand Up @@ -1000,18 +999,18 @@ Key Position::key_after(Move m) const {


/// Position::see_ge (Static Exchange Evaluation Greater or Equal) tests if the
/// SEE value of move is greater or equal to the given value. We'll use an
/// SEE value of move is greater or equal to the given threshold. We'll use an
/// algorithm similar to alpha-beta pruning with a null window.

bool Position::see_ge(Move m, Value v) const {
bool Position::see_ge(Move m, Value threshold) const {

assert(is_ok(m));

// Castling moves are implemented as king capturing the rook so cannot be
// handled correctly. Simply assume the SEE value is VALUE_ZERO that is always
// correct unless in the rare case the rook ends up under attack.
if (type_of(m) == CASTLING)
return VALUE_ZERO >= v;
return VALUE_ZERO >= threshold;

Square from = from_sq(m), to = to_sq(m);
PieceType nextVictim = type_of(piece_on(from));
Expand All @@ -1030,15 +1029,15 @@ bool Position::see_ge(Move m, Value v) const {
occupied = 0;
}

if (balance < v)
if (balance < threshold)
return false;

if (nextVictim == KING)
return true;

balance -= PieceValue[MG][nextVictim];

if (balance >= v)
if (balance >= threshold)
return true;

bool relativeStm = true; // True if the opponent is to move
Expand Down Expand Up @@ -1071,7 +1070,7 @@ bool Position::see_ge(Move m, Value v) const {

relativeStm = !relativeStm;

if (relativeStm == (balance >= v))
if (relativeStm == (balance >= threshold))
return relativeStm;

stm = ~stm;
Expand Down Expand Up @@ -1146,78 +1145,72 @@ void Position::flip() {
}


/// Position::pos_is_ok() performs some consistency checks for the position object.
/// Position::pos_is_ok() performs some consistency checks for the
/// position object and raises an asserts if something wrong is detected.
/// This is meant to be helpful when debugging.

bool Position::pos_is_ok(int* failedStep) const {
bool Position::pos_is_ok() const {

const bool Fast = true; // Quick (default) or full check?

enum { Default, King, Bitboards, State, Lists, Castling };
if ( (sideToMove != WHITE && sideToMove != BLACK)
|| piece_on(square<KING>(WHITE)) != W_KING
|| piece_on(square<KING>(BLACK)) != B_KING
|| ( ep_square() != SQ_NONE
&& relative_rank(sideToMove, ep_square()) != RANK_6))
assert(0 && "pos_is_ok: Default");

for (int step = Default; step <= (Fast ? Default : Castling); step++)
{
if (failedStep)
*failedStep = step;

if (step == Default)
if ( (sideToMove != WHITE && sideToMove != BLACK)
|| piece_on(square<KING>(WHITE)) != W_KING
|| piece_on(square<KING>(BLACK)) != B_KING
|| ( ep_square() != SQ_NONE
&& relative_rank(sideToMove, ep_square()) != RANK_6))
return false;
if (Fast)
return true;

if (step == King)
if ( std::count(board, board + SQUARE_NB, W_KING) != 1
|| std::count(board, board + SQUARE_NB, B_KING) != 1
|| attackers_to(square<KING>(~sideToMove)) & pieces(sideToMove))
return false;
if ( pieceCount[W_KING] != 1
|| pieceCount[B_KING] != 1
|| attackers_to(square<KING>(~sideToMove)) & pieces(sideToMove))
assert(0 && "pos_is_ok: Kings");

if (step == Bitboards)
{
if ( (pieces(WHITE) & pieces(BLACK))
||(pieces(WHITE) | pieces(BLACK)) != pieces())
return false;
if ( (pieces(PAWN) & (Rank1BB | Rank8BB))
|| pieceCount[W_PAWN] > 8
|| pieceCount[B_PAWN] > 8)
assert(0 && "pos_is_ok: Pawns");

for (PieceType p1 = PAWN; p1 <= KING; ++p1)
for (PieceType p2 = PAWN; p2 <= KING; ++p2)
if (p1 != p2 && (pieces(p1) & pieces(p2)))
return false;
}
if ( (pieces(WHITE) & pieces(BLACK))
|| (pieces(WHITE) | pieces(BLACK)) != pieces()
|| popcount(pieces(WHITE)) > 16
|| popcount(pieces(BLACK)) > 16)
assert(0 && "pos_is_ok: Bitboards");

if (step == State)
{
StateInfo si = *st;
set_state(&si);
if (std::memcmp(&si, st, sizeof(StateInfo)))
return false;
}
for (PieceType p1 = PAWN; p1 <= KING; ++p1)
for (PieceType p2 = PAWN; p2 <= KING; ++p2)
if (p1 != p2 && (pieces(p1) & pieces(p2)))
assert(0 && "pos_is_ok: Bitboards");

if (step == Lists)
for (Piece pc : Pieces)
{
if (pieceCount[pc] != popcount(pieces(color_of(pc), type_of(pc))))
return false;
StateInfo si = *st;
set_state(&si);
if (std::memcmp(&si, st, sizeof(StateInfo)))
assert(0 && "pos_is_ok: State");

for (int i = 0; i < pieceCount[pc]; ++i)
if (board[pieceList[pc][i]] != pc || index[pieceList[pc][i]] != i)
return false;
}
for (Piece pc : Pieces)
{
if ( pieceCount[pc] != popcount(pieces(color_of(pc), type_of(pc)))
|| pieceCount[pc] != std::count(board, board + SQUARE_NB, pc))
assert(0 && "pos_is_ok: Pieces");

if (step == Castling)
for (Color c = WHITE; c <= BLACK; ++c)
for (CastlingSide s = KING_SIDE; s <= QUEEN_SIDE; s = CastlingSide(s + 1))
{
if (!can_castle(c | s))
continue;

if ( piece_on(castlingRookSquare[c | s]) != make_piece(c, ROOK)
|| castlingRightsMask[castlingRookSquare[c | s]] != (c | s)
||(castlingRightsMask[square<KING>(c)] & (c | s)) != (c | s))
return false;
}
for (int i = 0; i < pieceCount[pc]; ++i)
if (board[pieceList[pc][i]] != pc || index[pieceList[pc][i]] != i)
assert(0 && "pos_is_ok: Index");
}

for (Color c = WHITE; c <= BLACK; ++c)
for (CastlingSide s = KING_SIDE; s <= QUEEN_SIDE; s = CastlingSide(s + 1))
{
if (!can_castle(c | s))
continue;

if ( piece_on(castlingRookSquare[c | s]) != make_piece(c, ROOK)
|| castlingRightsMask[castlingRookSquare[c | s]] != (c | s)
|| (castlingRightsMask[square<KING>(c)] & (c | s)) != (c | s))
assert(0 && "pos_is_ok: Castling");
}

return true;
}
4 changes: 2 additions & 2 deletions src/position.h
Expand Up @@ -138,7 +138,7 @@ class Position {
void increment_tbHits();

// Static Exchange Evaluation
bool see_ge(Move m, Value value = VALUE_ZERO) const;
bool see_ge(Move m, Value threshold = VALUE_ZERO) const;

// Accessing hash keys
Key key() const;
Expand All @@ -161,7 +161,7 @@ class Position {
Value non_pawn_material() const;

// Position consistency check, for debugging
bool pos_is_ok(int* failedStep = nullptr) const;
bool pos_is_ok() const;
void flip();

private:
Expand Down

2 comments on commit fa1e342

@niklasf
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there still a reason for pos_is_ok() to return bool?

@mcostalba
Copy link
Author

@mcostalba mcostalba commented on fa1e342 Jul 1, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@niklasf because it is used in an assert:

assert(pos_is_ok);

Next question may be: why used in an assert if already has asserts inside?

Answer: To compile it out in release build (and do not use #ifdef)

Please sign in to comment.