Probes DTZ tables for distance to zero information.

        Both DTZ and WDL tables are required in order to probe for DTZ.

        Returns a positive value if the side to move is winning, ``0`` if the
        position is a draw and a negative value if the side to move is losing.
        More precisely:

        +-----+------------------+--------------------------------------------+
        | WDL | DTZ              |                                            |
        +=====+==================+============================================+
        |  -2 | -100 <= n <= -1  | Unconditional loss (assuming 50-move       |
        |     |                  | counter is zero), where a zeroing move can |
        |     |                  | be forced in -n plies.                     |
        +-----+------------------+--------------------------------------------+
        |  -1 |         n < -100 | Loss, but draw under the 50-move rule.     |
        |     |                  | A zeroing move can be forced in -n plies   |
        |     |                  | or -n - 100 plies (if a later phase is     |
        |     |                  | responsible for the blessed loss).         |
        +-----+------------------+--------------------------------------------+
        |   0 |         0        | Draw.                                      |
        +-----+------------------+--------------------------------------------+
        |   1 |   100 < n        | Win, but draw under the 50-move rule.      |
        |     |                  | A zeroing move can be forced in n plies or |
        |     |                  | n - 100 plies (if a later phase is         |
        |     |                  | responsible for the cursed win).           |
        +-----+------------------+--------------------------------------------+
        |   2 |    1 <= n <= 100 | Unconditional win (assuming 50-move        |
        |     |                  | counter is zero), where a zeroing move can |
        |     |                  | be forced in n plies.                      |
        +-----+------------------+--------------------------------------------+

        The return value can be off by one: a return value -n can mean a
        losing zeroing move in in n + 1 plies and a return value +n can mean a
        winning zeroing move in n + 1 plies.
        This is guaranteed not to happen for positions exactly on the edge of
        the 50-move rule, so that (with some care) this never impacts the
        result of practical play.

        Minmaxing the DTZ values guarantees winning a won position (and drawing
        a drawn position), because it makes progress keeping the win in hand.
        However the lines are not always the most straightforward ways to win.
        Engines like Stockfish calculate themselves, checking with DTZ, but
        only play according to DTZ if they can not manage on their own.

        >>> import chess
        >>> import chess.syzygy
        >>>
        >>> with chess.syzygy.open_tablebase("data/syzygy/regular") as tablebase:
        ...     board = chess.Board("8/2K5/4B3/3N4/8/8/4k3/8 b - - 0 1")
        ...     print(tablebase.probe_dtz(board))
        ...
        -53

        Probing is thread-safe when done with different *board* objects and
        if *board* objects are not modified during probing.

        :raises: :exc:`KeyError` (or specifically
            :exc:`chess.syzygy.MissingTableError`) if the position could not
            be found in the tablebase. Use
            :func:`~chess.syzygy.Tablebase.get_dtz()` if you prefer to get
            ``None`` instead of an exception.

            Note that probing corrupted table files is undefined behavior.

def probe_dtz(self, board: chess.Board) -> int:
        """
        Probes DTZ tables for distance to zero information.

        Both DTZ and WDL tables are required in order to probe for DTZ.

        Returns a positive value if the side to move is winning, ``0`` if the
        position is a draw and a negative value if the side to move is losing.
        More precisely:

        +-----+------------------+--------------------------------------------+
        | WDL | DTZ              |                                            |
        +=====+==================+============================================+
        |  -2 | -100 <= n <= -1  | Unconditional loss (assuming 50-move       |
        |     |                  | counter is zero), where a zeroing move can |
        |     |                  | be forced in -n plies.                     |
        +-----+------------------+--------------------------------------------+
        |  -1 |         n < -100 | Loss, but draw under the 50-move rule.     |
        |     |                  | A zeroing move can be forced in -n plies   |
        |     |                  | or -n - 100 plies (if a later phase is     |
        |     |                  | responsible for the blessed loss).         |
        +-----+------------------+--------------------------------------------+
        |   0 |         0        | Draw.                                      |
        +-----+------------------+--------------------------------------------+
        |   1 |   100 < n        | Win, but draw under the 50-move rule.      |
        |     |                  | A zeroing move can be forced in n plies or |
        |     |                  | n - 100 plies (if a later phase is         |
        |     |                  | responsible for the cursed win).           |
        +-----+------------------+--------------------------------------------+
        |   2 |    1 <= n <= 100 | Unconditional win (assuming 50-move        |
        |     |                  | counter is zero), where a zeroing move can |
        |     |                  | be forced in n plies.                      |
        +-----+------------------+--------------------------------------------+

        The return value can be off by one: a return value -n can mean a
        losing zeroing move in in n + 1 plies and a return value +n can mean a
        winning zeroing move in n + 1 plies.
        This is guaranteed not to happen for positions exactly on the edge of
        the 50-move rule, so that (with some care) this never impacts the
        result of practical play.

        Minmaxing the DTZ values guarantees winning a won position (and drawing
        a drawn position), because it makes progress keeping the win in hand.
        However the lines are not always the most straightforward ways to win.
        Engines like Stockfish calculate themselves, checking with DTZ, but
        only play according to DTZ if they can not manage on their own.

        >>> import chess
        >>> import chess.syzygy
        >>>
        >>> with chess.syzygy.open_tablebase("data/syzygy/regular") as tablebase:
        ...     board = chess.Board("8/2K5/4B3/3N4/8/8/4k3/8 b - - 0 1")
        ...     print(tablebase.probe_dtz(board))
        ...
        -53

        Probing is thread-safe when done with different *board* objects and
        if *board* objects are not modified during probing.

        :raises: :exc:`KeyError` (or specifically
            :exc:`chess.syzygy.MissingTableError`) if the position could not
            be found in the tablebase. Use
            :func:`~chess.syzygy.Tablebase.get_dtz()` if you prefer to get
            ``None`` instead of an exception.

            Note that probing corrupted table files is undefined behavior.
        """
        v = self.probe_dtz_no_ep(board)

        if not board.ep_square or self.variant.captures_compulsory:
            return v

        v1 = -3

        # Generate all en-passant moves.
        for move in board.generate_legal_ep():
            board.push(move)
            try:
                v0_plus, _ = self.probe_ab(board, -2, 2)
                v0 = -v0_plus
            finally:
                board.pop()

            if v0 > v1:
                v1 = v0

        if v1 > -3:
            v1 = WDL_TO_DTZ[v1 + 2]
            if v < -100:
                if v1 >= 0:
                    v = v1
            elif v < 0:
                if v1 >= 0 or v1 < -100:
                    v = v1
            elif v > 100:
                if v1 > 0:
                    v = v1
            elif v > 0:
                if v1 == 1:
                    v = v1
            elif v1 >= 0:
                v = v1
            else:
                if all(board.is_en_passant(move) for move in board.generate_legal_moves()):
                    v = v1

        return v