Three-fold repetition and null move Added transposition table (this was tested alone and worked as expected), three fold repetition and null move pruning in my engine and wins more games but some of them end with three fold repetition even in win positions, played against the previous version

I keep a table history to save the current state of the board before making the move, to save the current zobrist key, move, en passant and castling

In make null function I just hash the en passant if exists, switch side, hash it and increment the fiftymove counter 

To check for repetitions I do this:

int i;
for (i = 4; i &lt;= board-&gt;fiifty_move; i += 2) {
    if (board-&gt;zkey == board-&gt;history[board-&gt;ply - i].zkey) {
        return true;
    }
}


The question is when checking for repetition it will check also for null move positions, is that correct? If a null move is repeated can we take that as a move even that null move it just switching sides?

I've seen engines that has a array like: hist_rep[index++].zkey = curr_zkey; that is only to check for repetitions and the array is not filled in the make null move function

Others engines has a counter inside the repetition function to check if the position has been repeated before more than one time

for (...) {
    if (zkey[i] == curr_zkey) ++rep;
    if (rep == 2) return true;
}


What is the correct way?
No. You shouldn't count null-move in repetitions because:


Null-move is fake
Null-move artificially creates a repetition when there is none


Your implementation is correct, but you might want to exclude null-move. Let's take a look at Stockfish:


  https://github.com/official-stockfish/Stockfish/blob/master/src/position.cpp


bool Position::is_draw(int ply) const {

  if (st-&gt;rule50 &gt; 99 &amp;&amp; (!checkers() || MoveList&lt;LEGAL&gt;(*this).size()))
      return true;

  int end = std::min(st-&gt;rule50, st-&gt;pliesFromNull);

  if (end &lt; 4)
    return false;

  StateInfo* stp = st-&gt;previous-&gt;previous;
  int cnt = 0;

  for (int i = 4; i &lt;= end; i += 2)
  {
      stp = stp-&gt;previous-&gt;previous;

      // At root position ply is 1, so return a draw score if a position
      // repeats once earlier but after or at the root, or repeats twice
      // strictly before the root.
      if (   stp-&gt;key == st-&gt;key
          &amp;&amp; ++cnt + (ply - i &gt; 0) == 2)
          return true;
  }

  return false;
}


You already have st-&gt;rule50 in your code (board-&gt;fifty-move) but you don't have st-&gt;pliesFromNull.

Let's check what Stockfish author said about pilesFromNull.


  http://www.talkchess.com/forum/viewtopic.php?start=0&amp;t=35052&amp;topic_view=flat&amp;sid=46a5561bcd0c4d36796c0fbfe5158079


By Joona Kiiski (2010):

They are already excluded, note the use of st-&gt;pliesFromNull: 

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. 


You see, if the strongest engine in the world does it you have no reason for not doing it.

If you check the code carefully, the first time when you do a null-move pliesFromNull is 0.

void Position::do_null_move(StateInfo&amp; newSt) {
    ....
    st-&gt;pliesFromNull = 0;
}


later the engine increments the counter in do_move:

++st-&gt;pliesFromNull;