Code: Select all
void Position::do_null_move(....
// Save the current key to the history[] array, in order to be able to
// detect repetition draws.
history[gamePly] = key;
gamePly++;
Moderators: hgm, Rebel, chrisw
Code: Select all
void Position::do_null_move(....
// Save the current key to the history[] array, in order to be able to
// detect repetition draws.
history[gamePly] = key;
gamePly++;
Could you explain the reason why you exclude move sequences containing a null move from repetition detection? As far as I can see Glaurung did not contain this "pliesFromNull" code, and it seems to be new after SF 1.5.1.zamar wrote:They are already excluded, note the use of st->pliesFromNull:
// Draw by repetition?
for (int i = 4; i <= Min(Min(gamePly, st->rule50), st->pliesFromNull); i += 2)
if (history[gamePly - i] == st->key)
return true;
Code: Select all
Ke4-e5 Kd8-d7
<null> Kd7-e8
Ke5-e4 Ke8-d8
Code: Select all
(X1)
Ke4-e5 (Y1) Kd8-d7
<null> Kd7-e8 (Z1)
Ke5-e4 Ke8-d8
(X2)
<null> Kd8-d7
Ke4-e5 Kd7-e7
Ke5-e4 Ke7-d8
(X3)
Ke4-e5 (Y2) Kd8-e8 (Z2)
<null> Ke8-e7
Ke5-e4 Ke7-d8
(X4)
It is probably correct that the subtree after <passive move> becomes smaller this way, although the subtree after the second <null> is considerably larger. So at least it seems o.k. not to check for repetition after *two consecutive null moves of the same side*. But the "pliesFromNull" implementation skips more repetition draws than that, and I still doubt that this does not hurt, at least in endgames. Also a sequencehgm wrote:The null move symbolizes any quiet ot defensive move, and although such moves are nort supposed to have tactical consequences, they do make the position different.
The most detrimental effect of not considering the null move irreversible is that it is no longer possible for the side that is ahead to obtain a fail high by doing consecutive null moves for one side. After <null> <passive move> another <null> would be refuted by <reverse passive move>, which would get a draw score. So you would be forced to refute most nonsense moves after <null> by a real move, losing the reduction, where a null move would have been the logical choice.
Code: Select all
<MOVE1> <null>
<rev. MOVE1> <MOVE2>
<null> <rev. MOVE2>
Most programs simply reset fifty move rule counter when doing null move. If I remember correctly Bob said that Crafty uses this trick. The downside is that side can escape fifty move rule by doing null move which perhaps doesn't cost any elo, but is irritating in practice.hgm wrote:Crafty does not have it???
Sven Schüle wrote: It would be interesting to see game results with vs. without "pliesFromNull" implementation, or to get a statement about the test results when that feature was added.
Code: Select all
Date: Wed, 7 Oct 2009 09:03:17 +0100
Subject: Do not claim repetition after null move
Null moves can artificially create a repetition
draw where instead there is no one.
So use a second counter to reset history after
a null move.
Idea from Joona.
After 999 games at 1+0
Mod vs Orig +238 =553 -208 51.50% 514.5/999 +10 ELO
---
src/position.cpp | 8 ++++++--
src/position.h | 2 +-
2 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/src/position.cpp b/src/position.cpp
index e0e9aa3..4e9a6dc 100644
--- a/src/position.cpp
+++ b/src/position.cpp
@@ -703,7 +703,7 @@ void Position::do_move(Move m, StateInfo& newSt, Bitboard dcCandidates) {
// pointer to point to the new, ready to be updated, state.
struct ReducedStateInfo {
Key key, pawnKey, materialKey;
- int castleRights, rule50;
+ int castleRights, rule50, pliesFromNull;
Square epSquare;
Value mgValue, egValue;
Value npMaterial[2];
@@ -724,6 +724,7 @@ void Position::do_move(Move m, StateInfo& newSt, Bitboard dcCandidates) {
// Increment the 50 moves rule draw counter. Resetting it to zero in the
// case of non-reversible moves is taken care of later.
st->rule50++;
+ st->pliesFromNull++;
if (move_is_castle(m))
{
@@ -1242,6 +1243,7 @@ void Position::do_null_move(StateInfo& backupSt) {
backupSt.mgValue = st->mgValue;
backupSt.egValue = st->egValue;
backupSt.previous = st->previous;
+ backupSt.pliesFromNull = st->pliesFromNull;
st->previous = &backupSt;
// Save the current key to the history[] array, in order to be able to
@@ -1258,6 +1260,7 @@ void Position::do_null_move(StateInfo& backupSt) {
sideToMove = opposite_color(sideToMove);
st->epSquare = SQ_NONE;
st->rule50++;
+ st->pliesFromNull = 0;
gamePly++;
st->mgValue += (sideToMove == WHITE)? TempoValueMidgame : -TempoValueMidgame;
@@ -1279,6 +1282,7 @@ void Position::undo_null_move() {
st->mgValue = backupSt->mgValue;
st->egValue = backupSt->egValue;
st->previous = backupSt->previous;
+ st->pliesFromNull = backupSt->pliesFromNull;
// Update the necessary information
sideToMove = opposite_color(sideToMove);
@@ -1683,7 +1687,7 @@ bool Position::is_draw() const {
return true;
// Draw by repetition?
- for (int i = 2; i < Min(gamePly, st->rule50); i += 2)
+ for (int i = 2; i < Min(Min(gamePly, st->rule50), st->pliesFromNull); i += 2)
if (history[gamePly - i] == st->key)
return true;
diff --git a/src/position.h b/src/position.h
index 370bb1d..606c748 100644
--- a/src/position.h
+++ b/src/position.h
@@ -88,7 +88,7 @@ enum Phase {
struct StateInfo {
Key key, pawnKey, materialKey;
- int castleRights, rule50;
+ int castleRights, rule50, pliesFromNull;
Square epSquare;
Value mgValue, egValue;
Value npMaterial[2];
--
1.6.5.1.1367.gcd48
Thanks for your clarification, also to Marco for showing the exact patch and corresponding test results. Regarding Crafty, I missed that "reset 50 moves counter" trick.zamar wrote:Most programs simply reset fifty move rule counter when doing null move. If I remember correctly Bob said that Crafty uses this trick. The downside is that side can escape fifty move rule by doing null move which perhaps doesn't cost any elo, but is irritating in practice.hgm wrote:Crafty does not have it???
The problem is that side with score below zero can refute a null move with a move which simply repeats the position. Then this dummy move causing fail high can end up saved in transposition table which we really don't want to do.
Consider,
Kd7-e8 Null
Ke8-d7 Null
Kd7-e8 Null
Ke8-d7 Null
If white is down in material we don't want king shuffling cause fail high and refute null move.