Skip to content

Commit

Permalink
More insufficient materials
Browse files Browse the repository at this point in the history
  • Loading branch information
PikaCat-OuO committed Mar 2, 2024
1 parent 53968f5 commit db78ce1
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 37 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ also be made available under GPL v3.
[release-badge]: https://img.shields.io/github/v/release/official-pikafish/Pikafish?style=for-the-badge&label=official%20release
[release-link]: https://github.com/official-pikafish/Pikafish/releases/latest
[rulebook-badge]: https://img.shields.io/badge/computer%20rule-20B2AA?style=for-the-badge&logo=mdbook
[rulebook-link]: https://pikafish.org/中国象棋程序竞赛规则.pdf
[rulebook-link]: https://pikafish.org/rule.pdf
[src-link]: https://github.com/official-pikafish/Pikafish/tree/master/src
[stockfish-link]: https://github.com/official-stockfish/Stockfish
[uci-link]: https://backscattering.de/chess/uci/
Expand Down
101 changes: 66 additions & 35 deletions src/position.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -966,7 +966,7 @@ Value Position::detect_chases(int d, int ply) {

// Tests whether the position may end the game by rule 60, insufficient material, draw repetition,
// perpetual check repetition or perpetual chase repetition that allows a player to claim a game result.
bool Position::rule_judge(Value& result, int ply) const {
bool Position::rule_judge(Value& result, int ply) {

// Restore rule 60 by adding back the checks
int end = std::min(st->rule60 + std::max(0, st->check10[WHITE] - 10)
Expand Down Expand Up @@ -1016,48 +1016,79 @@ bool Position::rule_judge(Value& result, int ply) const {
}
}

// 60 move rule
if (st->rule60 >= 120)
{
result = MoveList<LEGAL>(*this).size() ? VALUE_DRAW : mated_in(ply);
return true;
}

// Draw by insufficient material
if ([&] {
if (count<PAWN>() == 0)
if (count<PAWN>() == 0)
{
enum DrawLevel : int {
NO_DRAW, // There is no drawing situation exists
DIRECT_DRAW, // A draw can be directly yielded without any checks
MATE_DRAW // We need to check for mate before yielding a draw
};

int level = [&]() {
// No cannons left on the board
if (!major_material())
return DIRECT_DRAW;

// One cannon left on the board
if (major_material() == CannonValue)
{
// No attacking pieces left
if (!major_material())
return true;

// Only one cannon left on the board
if (major_material() == CannonValue)
// See which side is holding this cannon, and this side must not possess any advisors
Color cannonSide = major_material(WHITE) == CannonValue ? WHITE : BLACK;
if (count<ADVISOR>(cannonSide) == 0)
{
// No advisors left on the board
if (count<ADVISOR>() == 0)
return true;

// The side not holding the cannon can possess one advisor
// The side holding the cannon should only have cannon
if ((count<ALL_PIECES>(WHITE) == 2 && count<CANNON>(WHITE) == 1
&& count<ADVISOR>(BLACK) == 1)
|| (count<ALL_PIECES>(BLACK) == 2 && count<CANNON>(BLACK) == 1
&& count<ADVISOR>(WHITE) == 1))
return true;
}
if (count<ADVISOR>(~cannonSide) == 0)
return DIRECT_DRAW;

// Two cannons left on the board, one for each side, but no other pieces left on the board
if (count<ALL_PIECES>() == 4 && count<CANNON>(WHITE) == 1
&& count<CANNON>(BLACK) == 1)
return true;
// One advisor left on the board
if (count<ADVISOR>(~cannonSide) == 1)
return count<BISHOP>(cannonSide) == 0 ? DIRECT_DRAW : MATE_DRAW;

// Two advisors left on the board
if (count<BISHOP>(cannonSide) == 0)
return MATE_DRAW;
}
}

return false;
}())
{
result = VALUE_DRAW;
return true;
}
// Two cannons left on the board, one for each side, and no advisors left on the board
if (major_material() == CannonValue * 2 && count<ADVISOR>() == 0
&& count<CANNON>(WHITE) == 1 && count<CANNON>(BLACK) == 1)
return count<BISHOP>() == 0 ? DIRECT_DRAW : MATE_DRAW;

// 60 move rule
if (st->rule60 >= 120)
{
result = MoveList<LEGAL>(*this).size() ? VALUE_DRAW : mated_in(ply);
return true;
return NO_DRAW;
}();

if (level != NO_DRAW)
{
if (level == MATE_DRAW)
{
MoveList<LEGAL> moves(*this);
if (moves.size() == 0)
{
result = mated_in(ply);
return true;
}
for (const auto& move : moves)
{
StateInfo tempSt;
do_move(move, tempSt);
bool mate = MoveList<LEGAL>(*this).size() == 0;
undo_move(move);
if (mate)
return false;
}
}
result = VALUE_DRAW;
return true;
}
}

return false;
Expand Down
2 changes: 1 addition & 1 deletion src/position.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ class Position {
// Other properties of the position
Color side_to_move() const;
int game_ply() const;
bool rule_judge(Value& result, int ply = 0) const;
bool rule_judge(Value& result, int ply = 0);
int rule60_count() const;
uint16_t chased(Color c);
Value major_material(Color c) const;
Expand Down

0 comments on commit db78ce1

Please sign in to comment.